diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..bfa354a --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,60 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Overview + +Advanced Debug Mode is an Obsidian plugin that enhances the debugging experience: it toggles Obsidian's built-in debug mode (keeping inline source maps), preserves long (and async) stack traces, manages `debug`-library namespaces from the UI, surfaces DevTools (via `eruda`) on mobile, and lets you temporarily disable Obsidian's long-running-task timeouts. It is built on `obsidian-dev-utils`. + +## Commands + +| Task | Command | +|-------------------|----------------------------| +| TypeScript check | `npm run build:compile` | +| Build | `npm run build` | +| Dev (watch) | `npm run dev` | +| Lint | `npm run lint` | +| Lint (fix) | `npm run lint:fix` | +| Format | `npm run format` | +| Format (check) | `npm run format:check` | +| Spellcheck | `npm run spellcheck` | +| Markdown lint | `npm run lint:md` | +| Markdown lint fix | `npm run lint:md:fix` | +| Unit tests | `npm test` | +| Coverage | `npm run test:coverage` | +| Integration tests | `npm run test:integration` | +| Commit (wizard) | `npm run commit` | + +## Architecture + +- **Root config files** are thin re-exports — actual logic lives in `scripts/` (`eslint.config.mts` → `scripts/eslint-config.ts`, etc.). +- **`src/`** — plugin source: + - `main.ts` — Obsidian entry point (imports the stylesheet, default-exports `Plugin`) + - `plugin.ts` — `Plugin extends PluginBase`; `onloadImpl` wires up all child components (settings, settings tab, DevTools, command handler, long-running tasks, error stack-trace limit, long stack traces) + - `plugin-settings.ts` — `PluginSettings` data class with the plugin's setting defaults + - `plugin-settings-component.ts` — `PluginSettingsComponentBase` subclass that loads/saves settings + - `plugin-settings-tab.ts` — settings UI tab (`displayLegacy`) for debug mode, mobile emulation, debug namespaces, long/async stack traces, stack-trace limit, and task timeouts + - `debug-mode.ts` — `DebugMode`: read/toggle Obsidian's debug mode via `app.debugMode` + - `emulate-mobile-mode.ts` — `EmulateMobileMode`: read/toggle desktop mobile-emulation via `app.emulateMobile` + - `dev-tools-component.ts` — `DevToolsComponent`: initializes `eruda` DevTools (mobile) and toggles its entry button + - `error-stack-trace-limit-component.ts` — saves and restores `Error.stackTraceLimit` across load/unload + - `long-running-tasks-component.ts` — coordinates the two `FileSystemAdapter` patches and reloads them on settings change + - `multi-weak-map.ts` — `MultiWeakMap`: multi-key map mixing `Map`/`WeakMap` storage per key type + - `types.ts` — shared generic-function types (`GenericFunctionWithOriginalFn`, etc.) + - `command-handlers/toggle-dev-tools-button-command.ts` — `GlobalCommandHandler` to toggle the DevTools button + - `long-stack-traces/long-stack-traces-component.ts` — cross-platform entry; lazy-loads the desktop component and reloads on settings change + - `long-stack-traces/long-stack-traces-desktop-component.ts` — desktop core: patches `Error` (and child error classes), timers, microtasks, and `Promise` methods to inject long stack-trace frames + - `long-stack-traces/async-long-stack-traces-desktop-component.ts` — `async_hooks`-based async stack-trace capture (desktop only) + - `long-stack-traces/event-listener.ts` — `isEventListenerObject` type guard + - `long-stack-traces/event-handlers-map.ts` — `MultiWeakMap` mapping `(target, type, handler)` to wrapped handlers + - `patches/add-long-stack-traces-patch-component.ts` — `MonkeyAroundComponent` that wraps handler args so each invocation records a stack frame + - `patches/event-target-remove-event-listener-patch-component.ts` — patches `removeEventListener` to remove the wrapped handler + - `patches/file-system-adapter-queue-patch-component.ts` — patches `FileSystemAdapter.queue` to log timed-out task details + - `patches/file-system-adapter-things-happening-patch-component.ts` — patches `thingsHappening` to disable the long-running-task timeout + - `styles/` — `main.scss` (plugin styles) and `scss.d.ts` (SCSS module type declaration) + - `test-helpers/setup.ts` — unit-test setup +- **`main` field** points to `src/main.ts` (Obsidian plugin source entry; built artifact is `dist/build/main.js`, not published to npm). + +## Known Issues + +None. diff --git a/package.json b/package.json index 1e5c0ef..606bcc5 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "test:integration": "jiti scripts/test-integration.ts", "test:integration:android": "jiti scripts/test-integration-android.ts", "test:integration:desktop": "jiti scripts/test-integration-desktop.ts", + "test:integration:desktop:performance": "jiti scripts/test-integration-desktop-performance.ts", "test:integration:no-app": "jiti scripts/test-integration-no-app.ts", "test:watch": "jiti scripts/test-watch.ts", "version": "jiti scripts/version.ts" diff --git a/scripts/test-integration-desktop-performance.ts b/scripts/test-integration-desktop-performance.ts new file mode 100644 index 0000000..7d4da55 --- /dev/null +++ b/scripts/test-integration-desktop-performance.ts @@ -0,0 +1,8 @@ +import { wrapCliTask } from 'obsidian-dev-utils/script-utils/cli-utils'; +import { test } from 'obsidian-dev-utils/script-utils/test-runners/vitest'; + +await wrapCliTask(() => + test({ + projects: ['integration-tests:desktop-performance'] + }) +); diff --git a/scripts/vitest-config.ts b/scripts/vitest-config.ts index 3da7b57..55f8b5a 100644 --- a/scripts/vitest-config.ts +++ b/scripts/vitest-config.ts @@ -3,6 +3,7 @@ import { defineConfig } from 'vitest/config'; const SHARED_EXCLUDE = ['node_modules', 'dist']; const BIG_TIMEOUT_IN_MILLISECONDS = 30_000; const ANDROID_TIMEOUT_IN_MILLISECONDS = 60_000; +const PERFORMANCE_TIMEOUT_IN_MILLISECONDS = 600_000; const HOOK_TIMEOUT_MULTIPLIER = 4; export const config = defineConfig({ @@ -67,6 +68,17 @@ export const config = defineConfig({ testTimeout: BIG_TIMEOUT_IN_MILLISECONDS } }, + { + test: { + environment: 'node', + fileParallelism: false, + globalSetup: ['obsidian-integration-testing/vitest-global-setup'], + hookTimeout: PERFORMANCE_TIMEOUT_IN_MILLISECONDS, + include: ['src/**/*.desktop-performance.integration.test.ts'], + name: 'integration-tests:desktop-performance', + testTimeout: PERFORMANCE_TIMEOUT_IN_MILLISECONDS + } + }, { test: { environment: 'node',