mirror of
https://gh-proxy.org/https://github.com/klinsmaya/portal-template-default.git
synced 2026-11-11 02:27:17 +08:00
106 lines
3.7 KiB
JavaScript
106 lines
3.7 KiB
JavaScript
#!/usr/bin/env node
|
|
// Build verification runs `pnpm format:check '!.github/**'` over the whole
|
|
// application, so one badly formatted file at its root fails the first round
|
|
// of every build task. Run the same check in factory CI, before a change lands,
|
|
// without installing the application: only the Prettier and shared config
|
|
// versions its lockfile pins, in a temporary directory.
|
|
import { execFileSync } from 'node:child_process';
|
|
import {
|
|
copyFileSync,
|
|
existsSync,
|
|
mkdtempSync,
|
|
readFileSync,
|
|
rmSync,
|
|
writeFileSync,
|
|
} from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import process from 'node:process';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
export const FORMAT_ARGS = ['.', '--check', '!.github/**'];
|
|
const CONFIG_PACKAGE = '@nocobase/dev-config';
|
|
|
|
// The version pnpm resolved for a direct dependency of the root importer.
|
|
export function lockedVersion(lockfile, name) {
|
|
const importer = /^importers:\n\n {2}\.:\n([\s\S]*?)(?=^ {2}\S|^\S)/m.exec(
|
|
lockfile,
|
|
)?.[1];
|
|
const key = name.startsWith('@') ? `'${name}'` : name;
|
|
const entry = importer?.match(
|
|
new RegExp(
|
|
`^ {6}${key.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&')}:\\n {8}specifier: .*\\n {8}version: ([^\\s(]+)`,
|
|
'm',
|
|
),
|
|
);
|
|
if (!entry) throw new Error(`pnpm-lock.yaml does not pin ${name}`);
|
|
return entry[1];
|
|
}
|
|
|
|
export function checkApplicationFormat(root) {
|
|
const manifest = JSON.parse(readFileSync(path.join(root, 'package.json')));
|
|
if (manifest.prettier !== `${CONFIG_PACKAGE}/prettier`)
|
|
throw new Error(
|
|
`Expected package.json to use ${CONFIG_PACKAGE}/prettier; update this check with the application.`,
|
|
);
|
|
if (manifest.scripts?.['format:check'] !== 'prettier . --check')
|
|
throw new Error(
|
|
'Expected format:check to be "prettier . --check"; update this check with the application.',
|
|
);
|
|
const lockfile = readFileSync(path.join(root, 'pnpm-lock.yaml'), 'utf8');
|
|
const packages = ['prettier', CONFIG_PACKAGE].map(
|
|
(name) => `${name}@${lockedVersion(lockfile, name)}`,
|
|
);
|
|
const tools = mkdtempSync(path.join(os.tmpdir(), 'factory-format-'));
|
|
try {
|
|
writeFileSync(path.join(tools, 'package.json'), '{"private":true}\n');
|
|
// The application's registry settings resolve @nocobase packages.
|
|
if (existsSync(path.join(root, '.npmrc')))
|
|
copyFileSync(path.join(root, '.npmrc'), path.join(tools, '.npmrc'));
|
|
execFileSync(
|
|
'npm',
|
|
[
|
|
'install',
|
|
'--no-audit',
|
|
'--no-fund',
|
|
'--no-package-lock',
|
|
'--ignore-scripts',
|
|
'--legacy-peer-deps',
|
|
...packages,
|
|
],
|
|
{ cwd: tools, stdio: ['ignore', 'ignore', 'inherit'] },
|
|
);
|
|
// Same shared config package.json names, resolved from the tool directory.
|
|
writeFileSync(
|
|
path.join(tools, 'prettier.config.mjs'),
|
|
`export { default } from '${CONFIG_PACKAGE}/prettier';\n`,
|
|
);
|
|
console.log(`Checking application formatting with ${packages.join(', ')}`);
|
|
execFileSync(
|
|
path.join(tools, 'node_modules/.bin/prettier'),
|
|
[...FORMAT_ARGS, '--config', path.join(tools, 'prettier.config.mjs')],
|
|
{ cwd: root, stdio: 'inherit' },
|
|
);
|
|
} finally {
|
|
rmSync(tools, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
if (
|
|
process.argv[1] &&
|
|
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
) {
|
|
const root = path.resolve(process.argv[2] ?? '.');
|
|
try {
|
|
checkApplicationFormat(root);
|
|
} catch (error) {
|
|
// Prettier already listed the files; do not bury them under a stack trace.
|
|
console.error(
|
|
error.status
|
|
? 'Application formatting differs from what build verification accepts. Run Prettier on the files above.'
|
|
: error.message,
|
|
);
|
|
process.exit(1);
|
|
}
|
|
}
|