56 lines
2.1 KiB
JavaScript
56 lines
2.1 KiB
JavaScript
import { readFile } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { fail, pass, repositoryRoot } from './lib.mjs';
|
|
|
|
const expected = {
|
|
node: '24.17.0',
|
|
pnpm: '11.9.0',
|
|
};
|
|
const packageJson = JSON.parse(await readFile(path.join(repositoryRoot, 'package.json'), 'utf8'));
|
|
const lockfile = await readFile(path.join(repositoryRoot, 'pnpm-lock.yaml'), 'utf8');
|
|
const nodeVersion = (await readFile(path.join(repositoryRoot, '.node-version'), 'utf8')).trim();
|
|
const nvmVersion = (await readFile(path.join(repositoryRoot, '.nvmrc'), 'utf8')).trim();
|
|
const errors = [];
|
|
|
|
if (packageJson.packageManager !== `pnpm@${expected.pnpm}`) {
|
|
errors.push(`packageManager must be pnpm@${expected.pnpm}.`);
|
|
}
|
|
if (packageJson.engines?.node !== expected.node) {
|
|
errors.push(`package.json engines.node must be ${expected.node}.`);
|
|
}
|
|
if (packageJson.engines?.pnpm !== expected.pnpm) {
|
|
errors.push(`package.json engines.pnpm must be ${expected.pnpm}.`);
|
|
}
|
|
if (nodeVersion !== expected.node || nvmVersion !== expected.node) {
|
|
errors.push('.node-version and .nvmrc must match the approved Node.js runtime.');
|
|
}
|
|
|
|
const directDependencies = {
|
|
...(packageJson.dependencies ?? {}),
|
|
...(packageJson.devDependencies ?? {}),
|
|
};
|
|
const exactVersion = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
for (const [name, version] of Object.entries(directDependencies)) {
|
|
if (typeof version !== 'string' || !exactVersion.test(version)) {
|
|
errors.push(`${name} must use an exact direct version, received ${String(version)}.`);
|
|
continue;
|
|
}
|
|
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
const escapedVersion = version.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
const lockSpecifier = new RegExp(
|
|
`(?:^|\\n)\\s{6}['\"]?${escapedName}['\"]?:\\n\\s{8}specifier: ${escapedVersion}(?:\\n|$)`,
|
|
);
|
|
if (!lockSpecifier.test(lockfile)) {
|
|
errors.push(
|
|
`${name}@${version} is not represented by an exact importer specifier in pnpm-lock.yaml.`,
|
|
);
|
|
}
|
|
}
|
|
|
|
if (errors.length) fail(errors);
|
|
else {
|
|
pass(
|
|
`Pinned Node ${expected.node}, pnpm ${expected.pnpm}, and ${Object.keys(directDependencies).length} exact direct dependency versions match the lockfile.`,
|
|
);
|
|
}
|