Found while implementing #11487 (PR to follow) — measured on origin/main at 402113d57, not reasoned.
#11487 fixed PATH_LITERAL (scripts/check-cross-package-test-inputs.mjs) so a backtick argument containing ${ is treated as unreadable — no name, depth preserved — instead of being walked as one ordinary descent. NEW_URL_LITERAL, three lines above it, has the identical character class ([^'"]*) and the identical blind spot, in a structurally different call path (new URL(rel, import.meta.url)seeds, notresolve/join` arguments), and #11487's fix does not touch it — deliberately out of scope there.
What is measured
constNEW_URL_LITERAL=/^new\s+URL\(\s*(['"`])([^'"`]*)\1\s*,\s*import\.meta\.url\s*,?\s*\)$/;
matches an interpolating template the same way PATH_LITERAL did:
node-e '
constNEW_URL_LITERAL=/^new\s+URL\(\s*([\x27"\x60])([^\x27"\x60]*)\1\s*,\s*import\.meta\.url\s*,?\s*\)$/;console.log("new URL(`${someVar}`, import.meta.url)".match(NEW_URL_LITERAL));
'
# =>matches,capturingcontent"${someVar}"The captured content is fed straight into walkLiteral(hereDepth, url[2], dirSegs) (no intervening "can I read this" branch — that branch only exists inside pathExpression()'s resolve/join argument loop, which NEW_URL_LITERAL does not go through). ${someVar} is walked as one ordinary path segment, so:
Unlike the PATH_LITERAL call site, an unmatched NEW_URL_LITERAL does not fall into an explicit "cannot read, keep depth" branch — pathExpression() just returns undefined for the whole new URL(...) expression (the same outcome as any other unrecognised seed shape, already accepted and self-tested at "does NOT flag a read argument that is an unrecognised expression"). So the fix shape is likely the same narrowing (reject a backtick literal containing ${), but the consequence of matching a template today is not "wrong depth kept" so much as "the whole seed is silently misread instead of being silently unrecognised" — worth its own triage read rather than assuming #11487's exact disposition applies unchanged.
Why this is a finding rather than a defect card
No test in the tree spells a new URL() seed with interpolation today (a search for NEW_URL_LITERAL returns exactly the two lines above), so nothing is currently mis-verdicted — this is a property of the detector, not an outage, same as #11487 was.
Refs: #11487 (the PATH_LITERAL fix this is the sibling of, same file, same character-class shape) · #9763 (the reconstruction that introduced the RESOLVED half and walkLiteral).
Generated by Claude Code
Found while implementing #11487 (PR to follow) — measured on
origin/mainat402113d57, not reasoned.#11487 fixed
PATH_LITERAL(scripts/check-cross-package-test-inputs.mjs) so a backtick argument containing${is treated as unreadable — no name, depth preserved — instead of being walked as one ordinary descent.NEW_URL_LITERAL, three lines above it, has the identical character class ([^'"]*) and the identical blind spot, in a structurally different call path (new URL(rel, import.meta.url)seeds, notresolve/join` arguments), and #11487's fix does not touch it — deliberately out of scope there.What is measured
matches an interpolating template the same way
PATH_LITERALdid:The captured content is fed straight into
walkLiteral(hereDepth, url[2], dirSegs)(no intervening "can I read this" branch — that branch only exists insidepathExpression()'sresolve/joinargument loop, whichNEW_URL_LITERALdoes not go through).${someVar}is walked as one ordinary path segment, so:new URL(\${someVar}`, import.meta.url)athereDepth = 1currently resolves to depth2` (a normal descent) instead of being rejected as unrecognised.`../../${someVar}`would have its..segments walked correctly and its interpolation walked as one ordinary segment in the middle — the same "biased upward, can hide an escape" shape finding: check-cross-package-test-inputs counts a template-literal argument as ONE descent, so it is LESS safe than an argument the scan cannot fold #11487 described forPATH_LITERAL, just reached throughnew URL()instead ofjoin()/resolve().fileSegssupplied, the same call can push the literal text${someVar}onto the roster'ssegsarray (a fabricated NAME), the same risk finding: check-cross-package-test-inputs counts a template-literal argument as ONE descent, so it is LESS safe than an argument the scan cannot fold #11487's Zone 2.3 discussion raised forPATH_LITERAL— there it turned out to be caught byfindEscapingPackages()'s downstreamstatSync(...).isFile()filter; whether that filter also catches this shape was not re-verified here.Unlike the
PATH_LITERALcall site, an unmatchedNEW_URL_LITERALdoes not fall into an explicit "cannot read, keep depth" branch —pathExpression()just returnsundefinedfor the wholenew URL(...)expression (the same outcome as any other unrecognised seed shape, already accepted and self-tested at "does NOT flag a read argument that is an unrecognised expression"). So the fix shape is likely the same narrowing (reject a backtick literal containing${), but the consequence of matching a template today is not "wrong depth kept" so much as "the whole seed is silently misread instead of being silently unrecognised" — worth its own triage read rather than assuming #11487's exact disposition applies unchanged.Why this is a finding rather than a defect card
No test in the tree spells a
new URL()seed with interpolation today (a search forNEW_URL_LITERALreturns exactly the two lines above), so nothing is currently mis-verdicted — this is a property of the detector, not an outage, same as #11487 was.Refs: #11487 (the
PATH_LITERALfix this is the sibling of, same file, same character-class shape) · #9763 (the reconstruction that introduced the RESOLVED half andwalkLiteral).Generated by Claude Code