Skip to content

Commit 3f7c152

Browse files
committed
fix(scripts): substitute every wildcard in a resolved target
CodeQL js/incomplete-sanitization, two instances, both correct. `String.replace('*', x)` fills only the first occurrence. Node's `exports` resolver uses a global regex, so a target carrying more than one `*` — e.g. `"./src/*/index-*.ts"` — gets every occurrence substituted. Replacing only the first leaves a literal `*` in the path, so `probe()` finds nothing and the audit reports a perfectly valid subpath as missing. TypeScript `paths` allows at most one `*`, so the tsconfig branch was already correct in practice; it changes for consistency and because nothing enforces that assumption. Not a suppression — the resolver now matches Node's behaviour. 37,438 specifiers still resolve clean.
1 parent 93c5686 commit 3f7c152

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

scripts/check-import-specifiers.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,14 @@ interface PathRule {
131131
prefix: string
132132
suffix: string
133133
wildcard: boolean
134-
/** Absolute targets; `*` is retained verbatim and substituted at match time. */
134+
/**
135+
* Absolute targets; `*` is retained verbatim and substituted at match time.
136+
*
137+
* Substituted with `replaceAll`, not `replace`: Node's own `exports` resolver uses a
138+
* global regex, so a target carrying more than one `*` gets every occurrence filled.
139+
* Replacing only the first would leave a literal `*` in the path and report a valid
140+
* subpath as missing.
141+
*/
135142
targets: string[]
136143
}
137144

@@ -195,7 +202,7 @@ function resolveViaPaths(spec: string, importer: string): string | null | undefi
195202
if (suffix && !spec.endsWith(suffix)) continue
196203
const middle = spec.slice(prefix.length, suffix ? spec.length - suffix.length : undefined)
197204
for (const t of targets) {
198-
const hit = probe(t.replace('*', middle))
205+
const hit = probe(t.replaceAll('*', middle))
199206
if (hit) return hit
200207
}
201208
return null
@@ -266,7 +273,7 @@ function resolveSpecifier(spec: string, importer: string): Outcome | null {
266273
const tail = pattern.slice(star + 1)
267274
if (!key.startsWith(head) || !key.endsWith(tail)) continue
268275
const middle = key.slice(head.length, key.length - tail.length)
269-
if (probe(target.replace('*', middle))) return { ok: true }
276+
if (probe(target.replaceAll('*', middle))) return { ok: true }
270277
return { ok: false, reason: `${pkg}'s '${pattern}' export has no file for '${key}'` }
271278
}
272279

0 commit comments

Comments
 (0)