Summary
extract-import-map.mjs drops every paths alias from a tsconfig.json that contains both JSONC comments and glob patterns. Since that combination is ordinary, affected projects get an import map containing only relative imports, with no indication that anything was lost beyond one stderr line.
Why it happens
parseTsConfigText strips comments with a regex that does not honor string literals. The code comments acknowledge this ("The strip is naive (it doesn't honor string contents), so we fall back to the raw text on failure"), but the raw-text fallback cannot save this case — a tsconfig with comments is by definition one that fails a raw JSON.parse.
tsconfig aliases and include globs legitimately contain the comment delimiters:
The /* inside "@/*" opens a spurious block comment, and the */ inside "**/*.ts" closes it. Everything between is deleted:
Stripped parse fails → raw parse fails → parseTsConfigText returns null → all aliases from that config are dropped.
Trigger conditions
Both must hold, and both are ordinary:
- the tsconfig has any
// or /* */ comment, and
- it has a
paths alias containing * plus an include/exclude glob ("**/*.ts" is the create-next-app default)
Reproduction
The tsconfig above, plus src/app.ts importing @/lib/thing and src/lib/thing.ts exporting it:
$ node extract-import-map.mjs input.json output.json
Warning: extract-import-map: tsconfig.json at <path> failed to parse
— path aliases from this config will not be applied — relative imports unaffected
importMap["src/app.ts"] comes back []. Removing the comment alone makes it resolve.
Impact
Measured on a Next.js project whose tsconfig.json carried a three-line // comment explaining an allowImportingTsExtensions decision, alongside the stock "@/*": ["./src/*"] and "include": ["**/*.ts", "**/*.tsx"]:
|
files with imports |
import edges |
| before |
19 |
39 |
| after |
44 |
103 |
62% of the project's import graph was discarded. All 66 @/… imports in the source resolved to nothing.
Why the test suite never caught it
Every existing tsconfig test in test_extract_import_map.test.mjs builds its config with JSON.stringify(...), which cannot produce a comment. The bug is invisible to comment-free fixtures.
A fix is proposed in #627, with three tests written as literal text rather than JSON.stringify (line comment + globs, block comment + globs, and a // inside a string value as a guard on the fix itself).
Summary
extract-import-map.mjsdrops everypathsalias from atsconfig.jsonthat contains both JSONC comments and glob patterns. Since that combination is ordinary, affected projects get an import map containing only relative imports, with no indication that anything was lost beyond one stderr line.Why it happens
parseTsConfigTextstrips comments with a regex that does not honor string literals. The code comments acknowledge this ("The strip is naive (it doesn't honor string contents), so we fall back to the raw text on failure"), but the raw-text fallback cannot save this case — a tsconfig with comments is by definition one that fails a rawJSON.parse.tsconfig aliases and include globs legitimately contain the comment delimiters:
{ "compilerOptions": { // any comment at all "paths": { "@/*": ["./src/*"] } }, "include": ["**/*.ts"] }The
/*inside"@/*"opens a spurious block comment, and the*/inside"**/*.ts"closes it. Everything between is deleted:Stripped parse fails → raw parse fails →
parseTsConfigTextreturnsnull→ all aliases from that config are dropped.Trigger conditions
Both must hold, and both are ordinary:
//or/* */comment, andpathsalias containing*plus aninclude/excludeglob ("**/*.ts"is the create-next-app default)Reproduction
The tsconfig above, plus
src/app.tsimporting@/lib/thingandsrc/lib/thing.tsexporting it:importMap["src/app.ts"]comes back[]. Removing the comment alone makes it resolve.Impact
Measured on a Next.js project whose
tsconfig.jsoncarried a three-line//comment explaining anallowImportingTsExtensionsdecision, alongside the stock"@/*": ["./src/*"]and"include": ["**/*.ts", "**/*.tsx"]:62% of the project's import graph was discarded. All 66
@/…imports in the source resolved to nothing.Why the test suite never caught it
Every existing tsconfig test in
test_extract_import_map.test.mjsbuilds its config withJSON.stringify(...), which cannot produce a comment. The bug is invisible to comment-free fixtures.A fix is proposed in #627, with three tests written as literal text rather than
JSON.stringify(line comment + globs, block comment + globs, and a//inside a string value as a guard on the fix itself).