[GH-ISSUE #2599] fix(browser): source-map evidence omits literal template imports #916

Closed
opened 2026-10-15 18:29:33 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 13, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2599

Summary

A source map containing import(`./dep.js`) in an original source is included successfully, but its module dependency list omits the literal dynamic import. The equivalent quoted-string import is represented.

Steps to reproduce

Save the following controlled-fetch test as src/browser/template-import.probe.test.ts and run npm run test:focused -- src/browser/template-import.probe.test.ts. It exercises approved source-map fetching without a browser or external request and asserts the current result alongside two controls.

import { expect, it } from 'vitest';
import { fetchWebSourceMaps } from './WebSourceMapFetcher.js';
import { analyzeWebBundleInputSchema } from '../domain/webBundleAnalysis.js';
import { collectWebModuleImports } from '../domain/webModuleImports.js';
it('distinguishes literal template imports from computed imports', async () => {
 const origin='https://app.example.test', url=origin+'/app.js.map';
 const input=analyzeWebBundleInputSchema.parse({cdp_endpoint:'http://127.0.0.1:9222',target_id:'page',allowed_origins:[origin],fetch_source_maps:true});
 for(const [source,actualEdges,canonicalSpecifier] of [
 ['import(`./dep.js`);',0,'./dep.js'],
 ['import("./dep.js");',1,'./dep.js'],
 ['import(`./dep.${name}.js`);',0,null],
 ] as const) {
   const result=await fetchWebSourceMaps([{scriptKey:'script',declaredUrl:url,fetchUrl:url}],input,undefined,{fetch:async()=>new Response(JSON.stringify({version:3,names:[],sources:['main.ts'],sourcesContent:[source],mappings:'AAAA'}))});
   const item=result.items[0];
   expect(item?.status).toBe('included');
   if(item?.status!=='included') throw new Error('map not included');
   expect(item.original_module_edges).toHaveLength(actualEdges);
   if(actualEdges) expect(item.original_module_edges[0]).toMatchObject({kind:'dynamic_import',specifier:'./dep.js',resolved_source:origin+'/dep.js'});
   expect(item.original_sources[0]?.artifact?.text).toBe(source);
   expect(item.mappings).toHaveLength(1);
   expect(collectWebModuleImports(source).imports[0]?.specifier).toBe(canonicalSpecifier);
 }
});

Expected behavior

A no-substitution template import has a known specifier and should yield the same dynamic dependency as the equivalent quoted string. Keep the original text and mappings. A computed template must not invent a literal edge.

Actual behavior

The probe observed status: included, unchanged original text and one mapping for all three inputs. The literal template produced no edge; its quoted-string equivalent produced the dynamic edge for ./dep.js. The canonical extractor identified ./dep.js for both literals. The computed-template control produced no literal edge.

Evidence

  • Expected source: src/domain/webModuleImports.ts:34-38,88-89 treats a zero-expression template as a literal dynamic import; AGENTS.md, Architecture and Cleanup, assigns parsed facts to their owner.
  • Failure source: src/browser/WebSourceMapFetcher.ts:1047-1048 accepts only a string literal dynamic-import source, and src/browser/WebSourceMapFetcher.ts:744-779 records only recognized dependencies.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Restoration check

Both literal forms must yield one dynamic edge with specifier ./dep.js and the same resolved source. The computed form must yield no literal edge. Preserve source text and mapping rows for every control.

Runtime or environment

Source revision 8b181716aca2cb467be499cba226abfb5ae19141, Node v26.10.0, npm 11.19.1, Vitest 5.0.3, and the installed lockfile dependencies.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The included map silently omits a statically known module dependency, making its dependency list incomplete while other evidence stays usable.
  • Workaround status: available
  • Workaround basis: The probe confirms the original expression remains in the retained artifact, allowing an analyst to recover this dependency manually.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2599 ## Summary A source map containing ``import(`./dep.js`)`` in an original source is included successfully, but its module dependency list omits the literal dynamic import. The equivalent quoted-string import is represented. ## Steps to reproduce Save the following controlled-fetch test as `src/browser/template-import.probe.test.ts` and run `npm run test:focused -- src/browser/template-import.probe.test.ts`. It exercises approved source-map fetching without a browser or external request and asserts the current result alongside two controls. ```ts import { expect, it } from 'vitest'; import { fetchWebSourceMaps } from './WebSourceMapFetcher.js'; import { analyzeWebBundleInputSchema } from '../domain/webBundleAnalysis.js'; import { collectWebModuleImports } from '../domain/webModuleImports.js'; it('distinguishes literal template imports from computed imports', async () => { const origin='https://app.example.test', url=origin+'/app.js.map'; const input=analyzeWebBundleInputSchema.parse({cdp_endpoint:'http://127.0.0.1:9222',target_id:'page',allowed_origins:[origin],fetch_source_maps:true}); for(const [source,actualEdges,canonicalSpecifier] of [ ['import(`./dep.js`);',0,'./dep.js'], ['import("./dep.js");',1,'./dep.js'], ['import(`./dep.${name}.js`);',0,null], ] as const) { const result=await fetchWebSourceMaps([{scriptKey:'script',declaredUrl:url,fetchUrl:url}],input,undefined,{fetch:async()=>new Response(JSON.stringify({version:3,names:[],sources:['main.ts'],sourcesContent:[source],mappings:'AAAA'}))}); const item=result.items[0]; expect(item?.status).toBe('included'); if(item?.status!=='included') throw new Error('map not included'); expect(item.original_module_edges).toHaveLength(actualEdges); if(actualEdges) expect(item.original_module_edges[0]).toMatchObject({kind:'dynamic_import',specifier:'./dep.js',resolved_source:origin+'/dep.js'}); expect(item.original_sources[0]?.artifact?.text).toBe(source); expect(item.mappings).toHaveLength(1); expect(collectWebModuleImports(source).imports[0]?.specifier).toBe(canonicalSpecifier); } }); ``` ## Expected behavior A no-substitution template import has a known specifier and should yield the same dynamic dependency as the equivalent quoted string. Keep the original text and mappings. A computed template must not invent a literal edge. ## Actual behavior The probe observed `status: included`, unchanged original text and one mapping for all three inputs. The literal template produced no edge; its quoted-string equivalent produced the dynamic edge for `./dep.js`. The canonical extractor identified `./dep.js` for both literals. The computed-template control produced no literal edge. ## Evidence - Expected source: `src/domain/webModuleImports.ts:34-38,88-89` treats a zero-expression template as a literal dynamic import; `AGENTS.md`, Architecture and Cleanup, assigns parsed facts to their owner. - Failure source: `src/browser/WebSourceMapFetcher.ts:1047-1048` accepts only a string literal dynamic-import source, and `src/browser/WebSourceMapFetcher.ts:744-779` records only recognized dependencies. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete ## Restoration check Both literal forms must yield one dynamic edge with specifier `./dep.js` and the same resolved source. The computed form must yield no literal edge. Preserve source text and mapping rows for every control. ## Runtime or environment Source revision `8b181716aca2cb467be499cba226abfb5ae19141`, Node v26.10.0, npm 11.19.1, Vitest 5.0.3, and the installed lockfile dependencies. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The included map silently omits a statically known module dependency, making its dependency list incomplete while other evidence stays usable. - Workaround status: available - Workaround basis: The probe confirms the original expression remains in the retained artifact, allowing an analyst to recover this dependency manually.
bsakaguchi 2026-10-15 18:29:33 +00:00
  • closed this issue
  • added the
    bug
    label
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#916
No description provided.