@krizaka/config 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -58
- package/bin/krizaka-ratchet.mjs +4 -1
- package/conformance/account-baseline.js +116 -0
- package/dependency-cruiser.cjs +24 -72
- package/eslint/plugin.js +5 -1
- package/eslint/rules.js +112 -20
- package/eslint/stack.js +18 -6
- package/package.json +19 -25
- package/patterns.js +212 -29
- package/ratchet/ratchet.js +42 -29
- package/bin/krizaka-known-violations.mjs +0 -35
- package/covered-domains.cjs +0 -50
- package/covered-domains.json +0 -40
- package/ratchet/known-violations.js +0 -116
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
// The known violations of dependency-cruiser, held so that they only shrink (krizaka-ui#612). An app that adopts the
|
|
2
|
-
// import rules late records what it already breaks in `.dependency-cruiser-known-violations.json` (the format of
|
|
3
|
-
// `depcruise-baseline`, read by `depcruise --ignore-known`); this module compares that file with a real run:
|
|
4
|
-
// - a violation that is not recorded is new: refused (`depcruise --ignore-known` refuses it as well);
|
|
5
|
-
// - a recorded violation that is gone is a gain: `update` removes it, `check` refuses to leave it recorded, so the
|
|
6
|
-
// file cannot hide a regression later;
|
|
7
|
-
// - `update` never adds a line. `init` writes the file once, when it does not exist (the adoption pull request).
|
|
8
|
-
import { spawnSync } from "node:child_process";
|
|
9
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
10
|
-
import { dirname, join, resolve } from "node:path";
|
|
11
|
-
import { fileURLToPath } from "node:url";
|
|
12
|
-
|
|
13
|
-
export const KNOWN_FILE = ".dependency-cruiser-known-violations.json";
|
|
14
|
-
export const CONFIG_FILE = ".dependency-cruiser.cjs";
|
|
15
|
-
|
|
16
|
-
/** @typedef {{ type?: string, from: string, to: string, rule: { name: string, severity?: string }, cycle?: { name: string }[] }} Violation */
|
|
17
|
-
|
|
18
|
-
/** The identity of a violation, as depcruise matches it: the rule, the two ends, and the cycle's modules. @param {Violation} v */
|
|
19
|
-
export const keyOf = (v) => [v.rule.name, v.from, v.to, ...(v.cycle ?? []).map((step) => step.name)].join("\u0000");
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Compare the recorded violations with the current ones.
|
|
23
|
-
* @param {Violation[]} known
|
|
24
|
-
* @param {Violation[]} current
|
|
25
|
-
*/
|
|
26
|
-
export function compare(known, current) {
|
|
27
|
-
const knownKeys = new Set(known.map(keyOf));
|
|
28
|
-
const currentKeys = new Set(current.map(keyOf));
|
|
29
|
-
return {
|
|
30
|
-
added: current.filter((v) => !knownKeys.has(keyOf(v))),
|
|
31
|
-
gone: known.filter((v) => !currentKeys.has(keyOf(v))),
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** What `update` writes: the recorded violations that still happen. Never a new one. @param {Violation[]} known @param {Violation[]} current */
|
|
36
|
-
export const shrink = (known, current) => known.filter((v) => current.some((c) => keyOf(c) === keyOf(v)));
|
|
37
|
-
|
|
38
|
-
/** @param {Violation} v */
|
|
39
|
-
const describe = (v) => `${v.rule.name}: ${v.from} -> ${v.to}${v.cycle ? ` (cycle: ${v.cycle.map((step) => step.name).join(" -> ")})` : ""}`;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* The app's own dependency-cruiser first (its version is the one `depcruise` runs), then the one this package depends on.
|
|
43
|
-
* dependency-cruiser is ESM-only and hides its bin from `exports`: walk up `node_modules` from the app, then resolve the entry.
|
|
44
|
-
* @param {string} cwd
|
|
45
|
-
*/
|
|
46
|
-
function resolveDepcruise(cwd) {
|
|
47
|
-
const bin = (/** @type {string} */ root) => join(root, "bin", "dependency-cruiser.mjs");
|
|
48
|
-
for (let dir = resolve(cwd); ; dir = dirname(dir)) {
|
|
49
|
-
const candidate = bin(join(dir, "node_modules", "dependency-cruiser"));
|
|
50
|
-
if (existsSync(candidate)) return candidate;
|
|
51
|
-
if (dirname(dir) === dir) break;
|
|
52
|
-
}
|
|
53
|
-
let root = dirname(fileURLToPath(import.meta.resolve("dependency-cruiser")));
|
|
54
|
-
while (!existsSync(bin(root)) && dirname(root) !== root) root = dirname(root);
|
|
55
|
-
if (existsSync(bin(root))) return bin(root);
|
|
56
|
-
throw new Error("dependency-cruiser is not installed here: add it to the devDependencies.");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Run dependency-cruiser without the known file and read every violation (the `baseline` report).
|
|
61
|
-
* @param {{ cwd: string, config: string, targets: string[] }} options
|
|
62
|
-
* @returns {Violation[]}
|
|
63
|
-
*/
|
|
64
|
-
export function currentViolations({ cwd, config, targets }) {
|
|
65
|
-
const bin = resolveDepcruise(cwd);
|
|
66
|
-
const run = spawnSync(process.execPath, [bin, ...targets, "--config", config, "--output-type", "baseline"], {
|
|
67
|
-
cwd,
|
|
68
|
-
encoding: "utf8",
|
|
69
|
-
maxBuffer: 256 * 1024 * 1024,
|
|
70
|
-
});
|
|
71
|
-
try {
|
|
72
|
-
return JSON.parse(run.stdout);
|
|
73
|
-
} catch {
|
|
74
|
-
throw new Error(`dependency-cruiser failed:\n${run.stderr || run.stdout}`);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** @param {string} file @returns {Violation[]} */
|
|
79
|
-
const readKnown = (file) => JSON.parse(readFileSync(file, "utf8"));
|
|
80
|
-
/** @param {string} file @param {Violation[]} violations */
|
|
81
|
-
const writeKnown = (file, violations) => writeFileSync(file, `${JSON.stringify(violations, null, 2)}\n`);
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* `check` | `update` | `init`. Returns the exit code and the lines to print.
|
|
85
|
-
* @param {"check" | "update" | "init"} command
|
|
86
|
-
* @param {{ cwd?: string, config?: string, known?: string, targets: string[] }} options
|
|
87
|
-
* @returns {{ code: number, lines: string[] }}
|
|
88
|
-
*/
|
|
89
|
-
export function runKnownViolations(command, { cwd = process.cwd(), config = CONFIG_FILE, known = KNOWN_FILE, targets }) {
|
|
90
|
-
const file = resolve(cwd, known);
|
|
91
|
-
const current = currentViolations({ cwd, config, targets });
|
|
92
|
-
if (command === "init") {
|
|
93
|
-
if (existsSync(file)) return { code: 1, lines: [`${known} exists: the baseline is written once. Use "update" to lower it.`] };
|
|
94
|
-
writeKnown(file, current);
|
|
95
|
-
return { code: 0, lines: [`${known}: ${current.length} known violations recorded. They only go down.`] };
|
|
96
|
-
}
|
|
97
|
-
const recorded = existsSync(file) ? readKnown(file) : [];
|
|
98
|
-
const { added, gone } = compare(recorded, current);
|
|
99
|
-
if (command === "update") {
|
|
100
|
-
writeKnown(file, shrink(recorded, current));
|
|
101
|
-
const lines = [`${known}: ${recorded.length} -> ${recorded.length - gone.length} known violations.`];
|
|
102
|
-
if (added.length > 0) {
|
|
103
|
-
lines.push(`${added.length} new violation(s) are NOT recorded (the baseline never grows). Fix them:`, ...added.map((v) => ` ${describe(v)}`));
|
|
104
|
-
return { code: 1, lines };
|
|
105
|
-
}
|
|
106
|
-
return { code: 0, lines };
|
|
107
|
-
}
|
|
108
|
-
const lines = [
|
|
109
|
-
...added.map((v) => `new: ${describe(v)}`),
|
|
110
|
-
...gone.map((v) => `fixed but still recorded: ${describe(v)}`),
|
|
111
|
-
];
|
|
112
|
-
if (added.length > 0) lines.push("A new violation is never recorded: fix it (missing function? add it to the Krizaka package first).");
|
|
113
|
-
if (gone.length > 0) lines.push(`Lock the gain: krizaka-known-violations update (${gone.length} fewer).`);
|
|
114
|
-
if (lines.length === 0) lines.push(`${known}: ${recorded.length} known violations, none new, none fixed.`);
|
|
115
|
-
return { code: added.length + gone.length > 0 ? 1 : 0, lines };
|
|
116
|
-
}
|