Files
qinglong/scripts/ql3-edge-import-audit.cjs

119 lines
3.5 KiB
JavaScript

#!/usr/bin/env node
require('ts-node/register/transpile-only');
const fs = require('node:fs');
const path = require('node:path');
const ROOT_FORBIDDEN_PACKAGES = Object.freeze([
'@qinglong/cluster-control',
'@qinglong/cluster-postgres',
'@qinglong/worker-runtime',
'@types/pg',
'drizzle-kit',
'drizzle-orm',
'pg',
'pg-native',
]);
const ROOT_DEPENDENCY_SECTIONS = Object.freeze([
'dependencies',
'devDependencies',
'optionalDependencies',
'peerDependencies',
]);
const IMPORT_TARGETS = Object.freeze([
'../back/runtime/domain/deploymentProfile',
'../back/runtime/adapters/legacy/bootstrapDefaultManualPrimaryRuntime',
'../back/runtime/application/headlessWorkerRuntime',
]);
const FORBIDDEN_IMPORT_PATTERNS = Object.freeze([
{
name: 'postgresql migration implementation',
pattern: /\/back\/migrations\/postgresql\//,
},
{ name: 'pg', pattern: /\/node_modules\/pg\// },
{ name: 'pg-native', pattern: /\/node_modules\/pg-native\// },
{ name: 'drizzle-orm', pattern: /\/node_modules\/drizzle-orm\// },
{ name: 'drizzle-kit', pattern: /\/node_modules\/drizzle-kit\// },
{
name: 'cluster package',
pattern:
/\/(?:packages\/ql3-cluster-(?:control|postgres)|node_modules\/@qinglong\/cluster-(?:control|postgres))(?:\/|$)/,
},
{
name: 'worker runtime package',
pattern:
/\/(?:packages\/ql3-worker-runtime|node_modules\/@qinglong\/worker-runtime)(?:\/|$)/,
},
]);
function normalizeModulePath(value) {
return value.split(path.sep).join('/');
}
function findForbiddenRootDependencies(manifest) {
const findings = [];
for (const section of ROOT_DEPENDENCY_SECTIONS) {
const dependencies = manifest[section] || {};
for (const packageName of ROOT_FORBIDDEN_PACKAGES) {
if (Object.prototype.hasOwnProperty.call(dependencies, packageName)) {
findings.push({ packageName, section });
}
}
}
return findings;
}
function findForbiddenImports(modulePaths) {
const findings = [];
for (const modulePath of modulePaths) {
for (const forbidden of FORBIDDEN_IMPORT_PATTERNS) {
if (forbidden.pattern.test(modulePath)) {
findings.push({ category: forbidden.name, modulePath });
}
}
}
return findings;
}
function main() {
const root = path.resolve(__dirname, '..');
const manifestPath = path.join(root, 'package.json');
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
const forbiddenRootDependencies = findForbiddenRootDependencies(manifest);
process.env.QL_DEPLOYMENT_PROFILE = 'edge';
const baselineModules = new Set(Object.keys(require.cache));
for (const target of IMPORT_TARGETS) require(target);
const importedModules = Object.keys(require.cache)
.filter((modulePath) => !baselineModules.has(modulePath))
.map(normalizeModulePath)
.sort();
const forbiddenImports = findForbiddenImports(importedModules);
const report = {
schemaVersion: 1,
profile: process.env.QL_DEPLOYMENT_PROFILE,
importTargets: IMPORT_TARGETS,
importedModuleCount: importedModules.length,
forbiddenRootDependencies,
forbiddenImports,
compatible:
forbiddenRootDependencies.length === 0 && forbiddenImports.length === 0,
};
process.stdout.write(`${JSON.stringify(report)}\n`);
if (!report.compatible) process.exitCode = 1;
}
if (require.main === module) {
try {
main();
} catch (error) {
process.stderr.write(
`${error instanceof Error ? error.message : String(error)}\n`,
);
process.exitCode = 1;
}
}
module.exports = { findForbiddenImports, findForbiddenRootDependencies };