import { readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import semver from 'semver';
const repositoryRoot = dirname(fileURLToPath(new URL('../package.json', import.meta.url)));
function readManifest(path) {
return JSON.parse(readFileSync(path, 'utf8'));
}
function fail(headline, problems) {
console.error([headline, ...problems.map((problem) => `- ${problem}`)].join('\n'));
process.exit(1);
}
const rootManifest = readManifest(join(repositoryRoot, 'package.json'));
const rootRange = rootManifest.engines?.node;
const rootMinimum = rootRange ? semver.minVersion(rootRange) : null;
if (!rootRange || rootMinimum === null) {
fail('The root Node engine contract is invalid:', [
`package.json engines.node must be a valid semver range, got ${JSON.stringify(rootRange)}.`,
]);
}
const failures = [];
let constrainedDependencies = 0;
for (const dependency of Object.keys(rootManifest.dependencies ?? {}).sort()) {
const manifestPath = join(
repositoryRoot,
'node_modules',
...dependency.split('/'),
'package.json',
);
let manifest;
try {
manifest = readManifest(manifestPath);
} catch (error) {
failures.push(
`cannot read installed manifest for ${dependency} at ${manifestPath}: ${String(error)}. ` +
'Run pnpm install before this check.',
);
continue;
}
const dependencyRange = manifest.engines?.node;
if (!dependencyRange) continue;
constrainedDependencies += 1;
const dependencyMinimum = semver.minVersion(dependencyRange);
if (dependencyMinimum === null) {
failures.push(
`${dependency} declares an invalid engines.node range: ${JSON.stringify(dependencyRange)}.`,
);
continue;
}
if (semver.lt(rootMinimum, dependencyMinimum)) {
failures.push(
`root engines.node ${JSON.stringify(rootRange)} starts at ${rootMinimum.version}, below ` +
`${dependency}@${manifest.version} engines.node ${JSON.stringify(dependencyRange)} ` +
`(minimum ${dependencyMinimum.version}).`,
);
}
}
if (failures.length > 0) {
fail('The root Node engine minimum is below its direct production dependencies:', failures);
}
console.log(
`Node engine contract passed: root minimum ${rootMinimum.version} satisfies ` +
`${constrainedDependencies} engine-constrained direct production dependencies.`,
);