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:
parent
2dcf1450b2
commit
2f1d97e7bb
2 changed files with 25 additions and 4 deletions
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
Loading…
Reference in a new issue