chore(deps): treat line comments as trivia too in the import scan

From Copilot's fifth pass of #1962. `TRIVIA` covered block comments but not
`//`, despite the contract right above it saying a comment is legal wherever
whitespace is — so `import(// lazy\n"pkg")`, `require(// lazy\n"pkg")`, and
`from // reason\n"pkg"` were stepped over, and such a package would never
enter the candidate set. Same silent-miss direction as the block-comment gap.

Both comment syntaxes are now covered. The line-comment branch runs to
end-of-line only; the newline itself is matched by TRIVIA's `\s` branch.
Regression test added alongside the block-comment one.

The derived set is unchanged at 18 real names — widening trivia does not
admit prose, since a specifier must still follow immediately and
`packageNameOf` rejects anything not shaped like one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HDdo1rNRVQnVRRdsqSrvG3
This commit is contained in:
cliffhall 2026-08-10 21:13:56 -04:00
commit 2f1d97e7bb
2 changed files with 25 additions and 4 deletions

View file

@ -132,10 +132,12 @@ export function packageNameOf(specifier) {
// name would silently widen the set.
//
// Whitespace between tokens is really *trivia*: TypeScript allows a comment
// anywhere whitespace is legal, so `import(/* webpackIgnore: true */ "pkg")`
// and `from /* why */ "pkg"` are valid and must still be seen (Copilot,
// #1962). `TRIVIA` stands in for `\s*` at every such position.
const TRIVIA = String.raw`(?:\s|/\*[\s\S]*?\*/)*`;
// anywhere whitespace is legal, so `import(/* webpackIgnore: true */ "pkg")`,
// `from /* why */ "pkg"`, and the line-comment forms (`import(// lazy\n"pkg")`)
// are all valid and must still be seen (Copilot, #1962). `TRIVIA` stands in for
// `\s*` at every such position and covers both comment syntaxes. A line comment
// runs to end-of-line only — the newline itself is matched by the `\s` branch.
const TRIVIA = String.raw`(?:\s|/\*[\s\S]*?\*/|//[^\n]*)*`;
const SPECIFIER_FORMS = [
// import … from "x" / export … from "x"
new RegExp(String.raw`\bfrom${TRIVIA}["']([^"']+)["']`, "g"),

View file

@ -118,6 +118,25 @@ test("importedPackageNames: comment trivia between tokens (Copilot, #1962)", ()
]);
});
test("importedPackageNames: line-comment trivia, not just block (Copilot, #1962)", () => {
// `//` runs to end-of-line and is legal in every position a block comment is,
// so these are valid imports too. The newline is matched by TRIVIA's `\\s`
// branch rather than by the line-comment branch.
const source = [
"import { a } from // reason",
' "express";',
"const b = await import(// lazy",
' "undici");',
"const c = require(// lazy",
' "yaml");',
].join("\n");
assert.deepEqual([...importedPackageNames(source)].sort(), [
"express",
"undici",
"yaml",
]);
});
test("importedPackageNames: the three specifier forms that introduce types", () => {
const source = `
import { z } from "zod/v4";