mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 11:13:21 +00:00
test(architecture): ratchet top-level layer direction and mutual imports (#10584)
* test(architecture): ratchet top-level layer direction and mutual imports Declare a layer for every top-level src/ directory and root source file (domain, contracts, foundation, providers, application, composition, adapters) in scripts/lib/module-layers.mjs. verify:module-boundaries now also builds the production import graph between those units and compares it with a counted baseline: 45 unit pairs import a higher layer (248 imports) and 23 unit pairs import each other. A new upward pair, more imports on a recorded pair, a new mutual import, or an undeclared unit fails; shrinkage is reported so the baseline can be lowered. * fix(architecture): enforce layers for isolated units
This commit is contained in:
1 parent
351c2f4a03
commit
8c052bdec5
8 files changed
+472
-9
No files matched your search
@@ -3,11 +3,18 @@ import { readdir, readFile } from "node:fs/promises";
|
||||
import { join, resolve } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
import { inspectModuleBoundaries } from "./lib/module-boundaries.mjs";
|
||||
import {
|
||||
inspectResolvedModuleBoundaries,
|
||||
resolveModuleImports,
|
||||
} from "./lib/module-boundaries.mjs";
|
||||
import { compareLayerBaseline, layerGraphFacts } from "./lib/module-layers.mjs";
|
||||
|
||||
const execute = promisify(execFile);
|
||||
const root = process.cwd();
|
||||
const selected = process.argv.slice(2);
|
||||
const printLayerBaseline = process.argv.includes("--print-layer-baseline");
|
||||
const selected = process.argv
|
||||
.slice(2)
|
||||
.filter((argument) => argument !== "--print-layer-baseline");
|
||||
for (const file of selected)
|
||||
if (!file.endsWith(".ts"))
|
||||
throw new TypeError(`Expected an exact TypeScript source file: ${file}`);
|
||||
@@ -51,6 +58,8 @@ const enumerateSourceFiles = async () => {
|
||||
const files = await enumerateSourceFiles();
|
||||
|
||||
let checked = 0;
|
||||
const resolvedImports = [];
|
||||
const checkedFiles = [];
|
||||
for (const file of new Set(files.filter((path) => path.endsWith(".ts")))) {
|
||||
let source;
|
||||
try {
|
||||
@@ -64,8 +73,11 @@ for (const file of new Set(files.filter((path) => path.endsWith(".ts")))) {
|
||||
throw cause;
|
||||
}
|
||||
checked += 1;
|
||||
checkedFiles.push(file.replaceAll("\\", "/"));
|
||||
try {
|
||||
for (const violation of inspectModuleBoundaries(file, source, root)) {
|
||||
const imports = resolveModuleImports(file, source, root);
|
||||
resolvedImports.push(...imports);
|
||||
for (const violation of inspectResolvedModuleBoundaries(imports)) {
|
||||
console.error(
|
||||
`${violation.file}:${violation.line}: ${violation.boundary}: ${violation.specifier} resolves to ${violation.target}`,
|
||||
);
|
||||
@@ -76,5 +88,26 @@ for (const file of new Set(files.filter((path) => path.endsWith(".ts")))) {
|
||||
process.exitCode = 1;
|
||||
}
|
||||
}
|
||||
// Unit layering and cycles are whole-graph facts; a file selection cannot
|
||||
// establish them.
|
||||
if (selected.length === 0) {
|
||||
const baselinePath = resolve(root, "scripts/lib/module-layers.baseline.json");
|
||||
const baseline = JSON.parse(await readFile(baselinePath, "utf8"));
|
||||
const facts = layerGraphFacts(resolvedImports, checkedFiles);
|
||||
if (printLayerBaseline) {
|
||||
console.log(
|
||||
JSON.stringify({ upward: facts.upward, cycles: facts.cycles }, null, 2),
|
||||
);
|
||||
}
|
||||
const { failures, lowerable } = compareLayerBaseline(facts, baseline);
|
||||
for (const failure of failures) {
|
||||
console.error(`module layers: ${failure}`);
|
||||
process.exitCode = 1;
|
||||
}
|
||||
if (lowerable.length > 0)
|
||||
console.log(
|
||||
`Module layer baseline can be lowered in scripts/lib/module-layers.baseline.json:\n ${lowerable.join("\n ")}`,
|
||||
);
|
||||
}
|
||||
if (process.exitCode !== 1)
|
||||
console.log(`Checked resolved module boundaries in ${checked} source files.`);
|
||||
Reference in new issue
Block a user