--- model: mimo-v2-pro --- # Plan: `ask262Debug` Module for engine262 ## Overview Runtime execution tracker that records which ECMAScript spec sections are entered during execution. The Babel transform auto-injects `ask262Debug.mark()` at the start of every function body with URL comments — developer writes nothing. All metadata (sectionId, file, line) resolved at build time. ## Files to Change | File | Action | |------|--------| | `engine262/src/ask262-debug.mts` | **CREATE** — the module | | `engine262/src/index.mts` | **MODIFY** — add re-export | | `engine262/tsconfig.base.json` | **MODIFY** — add `#self/ask262Debug` path | | `engine262/package.json` | **MODIFY** — add `#self/ask262Debug` import | | `engine262/scripts/rollup.config.mts` | **MODIFY** — extend `resolve-self` plugin | | `engine262/scripts/transform.mts` | **MODIFY** — auto-inject `mark()` into function bodies | ## 1. `scripts/transform.mts` — Enhance the Babel plugin ### 1a. Refactor `addSectionFromComments` to also inject `mark()` into body Current behavior: sets `FuncName.section = 'url'` after the declaration. New behavior: also injects `ask262Debug.mark(["sec-..."], "file.mts", lineNumber)` as the first statement inside the function body. ```typescript function addSectionFromComments(path, getName) { if (!path.node.leadingComments) return; const sectionIds = []; let url = ''; for (const c of path.node.leadingComments) { for (const line of c.value.split('\n')) { const matches = line.match(/#(sec-[a-zA-Z0-9._%-]+)/g); if (matches) { sectionIds.push(...matches.map(m => m.substring(1))); if (!url) { const section = line.split(' ').find(l => l.includes('#sec')); url = section.includes('https') ? section : `https://tc39.es/ecma262/${section}`; } } } } if (sectionIds.length === 0) return; const name = getName(); // 1. Keep existing .section (backward compat) path.insertAfter(template.ast(`${name}.section = '${url}';`)); // 2. Inject mark() at start of function body const body = path.node.body; if (body?.type === 'BlockStatement') { const relativeFile = getRelativeFilePath(state); const line = path.node.loc?.start.line ?? 0; const markCall = template.ast( 'ask262Debug.mark(SECTION_IDS, FILE, LINE);' .replace('SECTION_IDS', JSON.stringify(sectionIds)) .replace('FILE', JSON.stringify(relativeFile)) .replace('LINE', String(line)) ); body.body.unshift(markCall); } } ``` ### 1b. Add visitors for all function-like nodes ```typescript FunctionDeclaration(path) { addSectionFromComments(path, () => path.node.id!.name); }, ClassMethod(path) { addSectionFromComments(path, () => (path.node.key as t.Identifier).name); }, ObjectMethod(path) { addSectionFromComments(path, () => (path.node.key as t.Identifier).name); }, // Existing visitors (VariableDeclaration, ExportNamedDeclaration) unchanged ``` ### 1c. Multi-section support Functions with multiple URL comments get all section IDs as an array: ```typescript /** https://tc39.es/ecma262/#sec-array.prototype.every */ /** https://tc39.es/ecma262/#sec-%typedarray%.prototype.every */ function* ArrayProto_every(args) { ... } // Transform injects: function* ArrayProto_every(args) { ask262Debug.mark(["sec-array.prototype.every", "sec-%typedarray%.prototype.every"], "intrinsics/ArrayPrototypeShared.mts", 173); ... } ``` ## 2. `engine262/package.json` — Add subpath import ```json "#self/ask262Debug": "./src/ask262-debug.mts" ``` ## 3. `engine262/tsconfig.base.json` — Add path mapping ```json "#self/ask262Debug": ["./src/ask262-debug.mts"] ``` ## 4. `scripts/rollup.config.mts` — Extend resolve-self plugin Change from exact `#self` match to prefix `#self/` match in both builds: ```typescript resolveId(source, _importer, _options) { if (source === '#self' || source.startsWith('#self/')) { return { id: './engine262.mjs' } as any; // inspector build } return undefined; }, ``` Add similar plugin to main engine262 build (which currently lacks one): ```typescript { name: 'resolve-self', resolveId(source) { if (source === '#self' || source.startsWith('#self/')) return { id: '#self' }; }, }, ``` ## 5. `engine262/src/index.mts` — Add re-export ```typescript export { default as ask262Debug, type MarkData } from './ask262-debug.mts'; ``` ## 6. `engine262/src/ask262-debug.mts` — The module Pure data collection. No stack parsing, no `node:` imports, no decorators. ```typescript export interface MarkData { readonly sectionIds: string[]; readonly fileRelativePath: string; readonly lineNumber: number; readonly important: boolean; } class Ask262Debug { marks: MarkData[] = []; private _importantStack = false; mark(sectionIds: string[], file: string, line: number) { this.marks.push({ sectionIds, fileRelativePath: file, lineNumber: line, important: this._importantStack, }); } startImportant() { this._importantStack = true; } stopImportant() { this._importantStack = false; } } const ask262Debug = new Ask262Debug(); export default ask262Debug; ``` ### Developer writes Nothing. The transform auto-injects `mark()` into every function body with URL comments. ### What the transform produces ```typescript // Original: /** https://tc39.es/ecma262/#sec-proxycreate */ export function ProxyCreate(target, handler) { // ... } // Transformed: export function ProxyCreate(target, handler) { ask262Debug.mark(["sec-proxycreate"], "abstract-ops/proxy-objects.mts", 540); // ... } ProxyCreate.section = 'https://tc39.es/ecma262/#sec-proxycreate'; ``` ## Key Design Decisions | Decision | Choice | Rationale | |----------|--------|-----------| | Module name | `#self/ask262Debug` | Follows existing `#self` pattern | | Export style | Singleton class, default export | `ask262Debug.marks` access | | `MarkData` type | Named export | Users can type-annotate | | All metadata | From transform (build time) | No runtime stack parsing, no `node:` imports | | `mark()` injection | Auto-injected at start of function body | Developer writes nothing | | Multi-section | Array of section IDs per function | Functions can implement multiple spec sections | | `markLine()` | Removed | `mark()` covers all cases | | `.section` | Kept (backward compat) | Used by test262-intrinsics | | `important` | Stubbed with boolean flag | `startImportant()`/`stopImportant()` | | Function types | FunctionDeclaration + ClassMethod + ObjectMethod | Covers all URL comment patterns | ## Verification 1. `cd engine262 && npx tsc -b .` — types compile 2. `cd engine262 && npm run lint` — no ESLint violations 3. Verify transform output: check that functions with URL comments have `ask262Debug.mark(...)` injected at start of body 4. Verify multi-section: check `ArrayProto_every` gets both section IDs 5. Run `npm run build:engine` — rollup resolves `#self/ask262Debug` correctly 6. Inspect `ask262Debug.marks` after running a test to verify marks are populated with correct data