test: find the imports of the builds with the compiler's scanner
The test that compares the imports of dist/ with "dependencies" matched a regular expression against the whole
file. tsc keeps comments in its output, so a usage line in a doc comment (import { ActionMapping } from
"alex2node") counted as an import and failed the commit gate with a message about dependencies.
ts.preProcessFile lists the imports instead. Stripping comments with two more expressions was tried first and
reads strings wrong: in `"src/*.ts"; require("real-one"); "*/"` it drops the require, and it never saw
import("lazy-one"); the scanner returns both. The declarations are scanned too: a .d.ts that imports a package the
consumer does not get breaks the consumer's type check.
Checked in a scratch copy: a doc comment and a string with an import in them pass; require("left-pad") in
dist/cjs, an aedes import in a declaration and an unused declared dependency each fail. npm test: 30 pass in
8.9-10.0 s.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
d96c6b8372
commit
128ca35c2a
1 changed files with 9 additions and 5 deletions
|
|
@ -8,6 +8,7 @@ const os = require("node:os");
|
||||||
const path = require("node:path");
|
const path = require("node:path");
|
||||||
const { builtinModules } = require("node:module");
|
const { builtinModules } = require("node:module");
|
||||||
const { spawnSync } = require("node:child_process");
|
const { spawnSync } = require("node:child_process");
|
||||||
|
const ts = require("typescript");
|
||||||
const pkg = require("alex2node/package.json");
|
const pkg = require("alex2node/package.json");
|
||||||
|
|
||||||
const ROOT = path.join(__dirname, "..");
|
const ROOT = path.join(__dirname, "..");
|
||||||
|
|
@ -53,14 +54,17 @@ test("each build has its own declarations, and \"exports\" names them before the
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("the builds import Node built-ins and the declared dependencies, nothing else", () => {
|
test("the builds and their declarations import Node built-ins and the declared dependencies, nothing else", () => {
|
||||||
// "mqtt/lib/x" and "@scope/name/x" belong to the packages "mqtt" and "@scope/name"
|
// "mqtt/lib/x" and "@scope/name/x" belong to the packages "mqtt" and "@scope/name"
|
||||||
const packageOf = (specifier) => specifier.split("/").slice(0, specifier.startsWith("@") ? 2 : 1).join("/");
|
const packageOf = (specifier) => specifier.split("/").slice(0, specifier.startsWith("@") ? 2 : 1).join("/");
|
||||||
const imported = new Set();
|
const imported = new Set();
|
||||||
for (const file of files(DIST).filter((f) => f.endsWith(".js"))) {
|
for (const file of files(DIST).filter((f) => /\.(js|ts)$/.test(f))) {
|
||||||
const source = fs.readFileSync(path.join(DIST, file), "utf8");
|
// Read with the compiler's scanner: tsc keeps comments in its output, and an import in a usage example or in
|
||||||
for (const [, specifier] of source.matchAll(/(?:\brequire\(|\bfrom\s+|\bimport\s+)"([^".][^"]*)"/g)) {
|
// a string is not an import.
|
||||||
if (!builtinModules.includes(specifier.replace(/^node:/, ""))) imported.add(packageOf(specifier));
|
const { importedFiles } = ts.preProcessFile(fs.readFileSync(path.join(DIST, file), "utf8"), true, true);
|
||||||
|
for (const { fileName: specifier } of importedFiles) {
|
||||||
|
if (specifier.startsWith(".") || builtinModules.includes(specifier.replace(/^node:/, ""))) continue;
|
||||||
|
imported.add(packageOf(specifier));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert.deepEqual([...imported].sort(), Object.keys(pkg.dependencies).sort());
|
assert.deepEqual([...imported].sort(), Object.keys(pkg.dependencies).sort());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue