chore(deps): match CommonJS and template-literal imports in the shared-source scan

From the suppressed comment on Copilot's second pass of #1962. Under-
approximating is the dangerous direction here: a package the scan misses
never enters the candidate set, so its skew passes the guard silently.

Three forms went unmatched. `import x = require("pkg")` and a bare
`require("pkg")` are the ordinary import syntax in `.cts` — which the
previous commit just admitted to the scan, so leaving them out would have
been an inconsistency introduced by that widening. A dynamic import carrying
import attributes (`import("pkg", { with: … })`) was missed because the
pattern required the closing paren. A static template literal
(`import(\`pkg\`)`) was missed for want of a backtick in the quote class.

Backticks are accepted only in the *call* forms. A `from` clause requires a
string literal, so allowing them there would buy nothing while reopening the
prose hazard the anchored specifier pattern closes: inline code in comments
is written with backticks throughout this codebase, and admitting it inflated
the derived set from 18 names to 41 with prose fragments (`tools`,
`connect()`, `messages`). Inert today, since a name absent from every
lockfile contributes nothing — but a prose word colliding with a real package
name would silently widen the set. Pinned with a regression test.

The real set is unchanged at 18, so these forms add no package today; they
close the syntax against the one that arrives later.

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 20:47:09 -04:00
commit 47e0ee059a
2 changed files with 51 additions and 5 deletions

View file

@ -101,12 +101,25 @@ export function packageNameOf(specifier) {
return name;
}
// `from "x"` (import and re-export), a side-effect `import "x"`, and a dynamic
// `import("x")`. Only these three forms introduce a dependency's *types*.
// Every form that can introduce a dependency's *types* (Copilot, #1962).
// `import x = require("pkg")` and a bare `require("pkg")` matter because the
// shared trees may hold `.cts` sources, where that is the ordinary import
// syntax; and neither call form requires the closing paren, so an import
// attributes argument (`import("pkg", { with: … })`) can't hide the specifier.
//
// Backticks are accepted ONLY in the call forms, where a static template
// literal is legal. A `from` clause requires a string literal, so allowing
// backticks there would buy nothing while reopening the prose hazard the
// anchored specifier pattern exists to close — inline code in a comment is
// written with backticks throughout this codebase, and "…derived from
// `tools`…" would otherwise enter the candidate set as a package named
// `tools`. Inert today, but a prose word that collides with a real package
// name would silently widen the set.
const SPECIFIER_FORMS = [
/\bfrom\s*["']([^"']+)["']/g,
/\bimport\s+["']([^"']+)["']/g,
/\bimport\s*\(\s*["']([^"']+)["']\s*\)/g,
/\bfrom\s*["']([^"']+)["']/g, // import … from "x" / export … from "x"
/\bimport\s+["']([^"']+)["']/g, // side-effect import "x"
/\bimport\s*\(\s*["'`]([^"'`]+)["'`]/g, // dynamic import("x"[, opts])
/\brequire\s*\(\s*["'`]([^"'`]+)["'`]/g, // import x = require("x"), require("x")
];
/**

View file

@ -79,6 +79,26 @@ test("packageNameOf: non-packages are rejected", () => {
assert.equal(packageNameOf(undefined), null);
});
test("importedPackageNames: CommonJS and awkward dynamic-import forms (Copilot, #1962)", () => {
// Under-approximating is the dangerous direction: a package the scan misses
// never enters the candidate set, so its skew passes the guard silently.
// `.cts` sources in the shared trees use `import x = require(…)` as ordinary
// syntax, and a dynamic import may carry import attributes or a static
// template literal — none of which the original three patterns matched.
const source = `
import express = require("express");
const yaml = require("yaml");
const a = await import("undici", { with: { type: "json" } });
const b = await import(\`jose\`);
`;
assert.deepEqual([...importedPackageNames(source)].sort(), [
"express",
"jose",
"undici",
"yaml",
]);
});
test("importedPackageNames: the three specifier forms that introduce types", () => {
const source = `
import { z } from "zod/v4";
@ -109,6 +129,19 @@ test("importedPackageNames: prose after `from` is not an import", () => {
assert.deepEqual([...importedPackageNames(source)], ["zod"]);
});
test("importedPackageNames: a backticked `from` in prose is not an import", () => {
// Backticks are legal in the *call* forms (a static template literal) but
// never after `from`, which requires a string literal. Accepting them there
// would sweep in inline code from comments — this codebase writes it with
// backticks throughout — and a prose word colliding with a real package name
// would silently widen the candidate set.
const source = `
/** The excluded set derived from \\\`tools\\\`, keyed off \\\`express\\\`-style paths. */
import { z } from "zod";
`;
assert.deepEqual([...importedPackageNames(source)], ["zod"]);
});
test("topLevelLockVersions: nested duplicates are ignored", () => {
// A nested `node_modules/a/node_modules/b` is npm resolving a transitive
// conflict *inside* one install — routine, and not the cross-install skew