tools/rules/purity.rule.ts
tools/rules/purity.rule.ts is a file in Coordination Surface. 64 lines of code and 11 definitions.
import type { RuleContext, RuleDeclaration, RuleResult } from "../core/types/rule.types.ts";
import type { Finding } from "../core/types/segment.types.ts";
import { LEAF_FOLDERS } from "../core/constants/layer.constants.ts";
import { localImports } from "../core/analyzers/graph.analyzer.ts";
import { surfacePrefix } from "../../config/surface.config.ts";
const CONFIG_ROOT = ((): string => {
const prefix = surfacePrefix();
return prefix.length === 0 ? "config/" : `${prefix}/config/`;
})();
const DECIDE =
"a leaf is the innermost tier and imports only leaves, which is what keeps the dependency graph acyclic " +
"at its base and stops domain vocabulary reaching the tier every other tier depends on. An import " +
"climbing OUT of the leaf tier inverts that: the leaf now needs what needs it, so nothing can be read " +
"or replaced without reading the layer above it. Move the shared value DOWN into a leaf, or move the " +
"importing module UP out of the leaf tier — never satisfy it by widening what counts as a leaf";
const inLeafTier = function inLeafTier(path: string): boolean {
return LEAF_FOLDERS.some((folder) => path.startsWith(folder));
};
const climbsOut = function climbsOut(imported: string): boolean {
return !inLeafTier(imported) && !imported.startsWith(CONFIG_ROOT);
};
const leafFinding = function leafFinding(path: string, imported: string): Finding {
return {
actual: imported,
expected: null,
healed: false,
line: 1,
locus: imported,
path,
remediation: { action: "none", decide: DECIDE, deterministic: false, from: path, target: path, to: null },
rule: "purity/leafClimbsOut",
stack: [
{ check: "tier", resolved: "leaf" },
{ check: "importedTier", resolved: "above" },
],
};
};
export const rule: RuleDeclaration = {
check(context: RuleContext): RuleResult {
const known = new Set(context.paths);
const reached = context.paths.filter(inLeafTier);
const findings = reached.flatMap((path) =>
localImports(path, context.read(path), known)
.filter(climbsOut)
.map((imported) => leafFinding(path, imported)),
);
return {
derivations: {
leafFolders: [...LEAF_FOLDERS],
reached,
skippedAsOutsideLeafTier: context.paths.filter((path) => !inLeafTier(path)),
},
findings,
healed: [],
};
},
extensions: [".ts"],
heals: false,
invariant:
"a module in the leaf tier imports only from the leaf tier or from the parameter surface beneath it, which depends on nothing in the tree and so cannot close a cycle",
jurisdiction: "all",
kinds: ["leafClimbsOut"],
stage: "structure",
};