From f32cb8355c4dc234be4e002262d370b8f2a4a6f4 Mon Sep 17 00:00:00 2001 From: carlos-alm Date: Sat, 6 Jun 2026 03:01:55 -0600 Subject: [PATCH 1/2] test(extractor): verify exported arrow function funcStack tracking in extractSpreadForOfWalk (#1354) Add regression tests confirming that `export const f = (arr) => { for (const x of arr) x(); }` correctly pushes `f` onto the funcStack so for-of bindings record the right enclosing caller. The recursive walk visits `variable_declarator` regardless of whether it is nested under a plain `lexical_declaration` or an `export_statement`, so the gap reported in the PR #1331 review was already closed by commit a6c5d2d. These tests document and gate that behavior. Closes #1354 --- tests/parsers/javascript.test.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/parsers/javascript.test.ts b/tests/parsers/javascript.test.ts index 1cb8ad5d..3ab9fbaf 100644 --- a/tests/parsers/javascript.test.ts +++ b/tests/parsers/javascript.test.ts @@ -908,4 +908,27 @@ describe('JavaScript parser', () => { ); }); }); + + describe('Phase 8.3e: extractSpreadForOfWalk — exported arrow function funcStack (#1354)', () => { + it('tracks plain const arrow function on funcStack for for-of loop', () => { + const symbols = parseJS(`const f = (arr) => { for (const x of arr) x(); };`); + expect(symbols.forOfBindings).toContainEqual( + expect.objectContaining({ enclosingFunc: 'f' }), + ); + }); + + it('tracks exported const arrow function on funcStack for for-of loop', () => { + const symbols = parseJS(`export const f = (arr) => { for (const x of arr) x(); };`); + expect(symbols.forOfBindings).toContainEqual( + expect.objectContaining({ enclosingFunc: 'f' }), + ); + }); + + it('records correct varName and sourceName for exported arrow for-of', () => { + const symbols = parseJS(`export const process = (items) => { for (const cb of items) cb(); };`); + expect(symbols.forOfBindings).toContainEqual( + expect.objectContaining({ varName: 'cb', sourceName: 'items', enclosingFunc: 'process' }), + ); + }); + }); }); From f01c33938d2595cafed04e0b0196ba96e0907f80 Mon Sep 17 00:00:00 2001 From: carlos-alm Date: Sat, 6 Jun 2026 03:42:41 -0600 Subject: [PATCH 2/2] fix: remove duplicate paramBindings in SerializedExtractorOutput and rename process test identifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The merge at 3c164f2 introduced a second `paramBindings` field (using the top-level ParamBinding import) alongside the existing inline-import form at line 68, causing TS2300 duplicate-identifier errors that broke every CI job. Removed the duplicate and the now-unused ParamBinding top-level import. Also renamed the `process` arrow-function identifier in the Phase 8.3e test to `handleItems` — `process` is a Node.js global and its presence in the test obscures that the test is solely about the export-wrapping code path. --- src/domain/wasm-worker-protocol.ts | 2 -- tests/parsers/javascript.test.ts | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/domain/wasm-worker-protocol.ts b/src/domain/wasm-worker-protocol.ts index 43a6041f..95208660 100644 --- a/src/domain/wasm-worker-protocol.ts +++ b/src/domain/wasm-worker-protocol.ts @@ -19,7 +19,6 @@ import type { Export, Import, LanguageId, - ParamBinding, TypeMapEntry, } from '../types.js'; @@ -75,7 +74,6 @@ export interface SerializedExtractorOutput { newExpressions?: readonly string[]; returnTypeMap?: Array<[string, TypeMapEntry]>; callAssignments?: CallAssignment[]; - paramBindings?: ParamBinding[]; } export interface WorkerParseResponseOk { diff --git a/tests/parsers/javascript.test.ts b/tests/parsers/javascript.test.ts index 3ab9fbaf..1411f42d 100644 --- a/tests/parsers/javascript.test.ts +++ b/tests/parsers/javascript.test.ts @@ -912,22 +912,24 @@ describe('JavaScript parser', () => { describe('Phase 8.3e: extractSpreadForOfWalk — exported arrow function funcStack (#1354)', () => { it('tracks plain const arrow function on funcStack for for-of loop', () => { const symbols = parseJS(`const f = (arr) => { for (const x of arr) x(); };`); - expect(symbols.forOfBindings).toContainEqual( - expect.objectContaining({ enclosingFunc: 'f' }), - ); + expect(symbols.forOfBindings).toContainEqual(expect.objectContaining({ enclosingFunc: 'f' })); }); it('tracks exported const arrow function on funcStack for for-of loop', () => { const symbols = parseJS(`export const f = (arr) => { for (const x of arr) x(); };`); - expect(symbols.forOfBindings).toContainEqual( - expect.objectContaining({ enclosingFunc: 'f' }), - ); + expect(symbols.forOfBindings).toContainEqual(expect.objectContaining({ enclosingFunc: 'f' })); }); it('records correct varName and sourceName for exported arrow for-of', () => { - const symbols = parseJS(`export const process = (items) => { for (const cb of items) cb(); };`); + const symbols = parseJS( + `export const handleItems = (items) => { for (const cb of items) cb(); };`, + ); expect(symbols.forOfBindings).toContainEqual( - expect.objectContaining({ varName: 'cb', sourceName: 'items', enclosingFunc: 'process' }), + expect.objectContaining({ + varName: 'cb', + sourceName: 'items', + enclosingFunc: 'handleItems', + }), ); }); });