@nielspeter/eess 0.2.1 → 0.4.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 +3 -3
- package/dist/assertion-advice.d.ts +26 -0
- package/dist/assertion-advice.d.ts.map +1 -0
- package/dist/assertion-advice.js +29 -0
- package/dist/assertion-advice.js.map +1 -0
- package/dist/baseline.d.ts +69 -4
- package/dist/baseline.d.ts.map +1 -1
- package/dist/baseline.js +119 -13
- package/dist/baseline.js.map +1 -1
- package/dist/cache-registry.d.ts +14 -0
- package/dist/cache-registry.d.ts.map +1 -0
- package/dist/cache-registry.js +37 -0
- package/dist/cache-registry.js.map +1 -0
- package/dist/cardinality.d.ts +35 -0
- package/dist/cardinality.d.ts.map +1 -0
- package/dist/cardinality.js +65 -0
- package/dist/cardinality.js.map +1 -0
- package/dist/check-options.d.ts +14 -0
- package/dist/check-options.d.ts.map +1 -1
- package/dist/comment-suppression.d.ts +60 -0
- package/dist/comment-suppression.d.ts.map +1 -0
- package/dist/comment-suppression.js +89 -0
- package/dist/comment-suppression.js.map +1 -0
- package/dist/condition.d.ts +6 -0
- package/dist/condition.d.ts.map +1 -1
- package/dist/correspondence-core.d.ts +35 -0
- package/dist/correspondence-core.d.ts.map +1 -0
- package/dist/correspondence-core.js +38 -0
- package/dist/correspondence-core.js.map +1 -0
- package/dist/correspondence.d.ts +27 -5
- package/dist/correspondence.d.ts.map +1 -1
- package/dist/correspondence.js +39 -5
- package/dist/correspondence.js.map +1 -1
- package/dist/dedupe-config-findings.d.ts +56 -0
- package/dist/dedupe-config-findings.d.ts.map +1 -0
- package/dist/dedupe-config-findings.js +74 -0
- package/dist/dedupe-config-findings.js.map +1 -0
- package/dist/define.d.ts +44 -2
- package/dist/define.d.ts.map +1 -1
- package/dist/define.js +45 -4
- package/dist/define.js.map +1 -1
- package/dist/diff-aware.d.ts +8 -0
- package/dist/diff-aware.d.ts.map +1 -1
- package/dist/diff-aware.js +11 -2
- package/dist/diff-aware.js.map +1 -1
- package/dist/diff-disclosure.d.ts +72 -0
- package/dist/diff-disclosure.d.ts.map +1 -0
- package/dist/diff-disclosure.js +110 -0
- package/dist/diff-disclosure.js.map +1 -0
- package/dist/disk-set.d.ts +27 -0
- package/dist/disk-set.d.ts.map +1 -0
- package/dist/disk-set.js +12 -0
- package/dist/disk-set.js.map +1 -0
- package/dist/edge-coverage.d.ts +96 -0
- package/dist/edge-coverage.d.ts.map +1 -0
- package/dist/edge-coverage.js +108 -0
- package/dist/edge-coverage.js.map +1 -0
- package/dist/errors.d.ts +25 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +32 -0
- package/dist/errors.js.map +1 -1
- package/dist/execute-rule.d.ts +11 -5
- package/dist/execute-rule.d.ts.map +1 -1
- package/dist/execute-rule.js +87 -19
- package/dist/execute-rule.js.map +1 -1
- package/dist/format-github.d.ts.map +1 -1
- package/dist/format-github.js +37 -5
- package/dist/format-github.js.map +1 -1
- package/dist/format-json.d.ts +83 -1
- package/dist/format-json.d.ts.map +1 -1
- package/dist/format-json.js +70 -9
- package/dist/format-json.js.map +1 -1
- package/dist/format.d.ts +4 -2
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +40 -8
- package/dist/format.js.map +1 -1
- package/dist/glob-site.d.ts +232 -0
- package/dist/glob-site.d.ts.map +1 -0
- package/dist/glob-site.js +156 -0
- package/dist/glob-site.js.map +1 -0
- package/dist/identity-root.d.ts +55 -0
- package/dist/identity-root.d.ts.map +1 -0
- package/dist/identity-root.js +170 -0
- package/dist/identity-root.js.map +1 -0
- package/dist/index.d.ts +41 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +33 -3
- package/dist/index.js.map +1 -1
- package/dist/owns-empty-discovery.d.ts +5 -0
- package/dist/owns-empty-discovery.d.ts.map +1 -0
- package/dist/owns-empty-discovery.js +77 -0
- package/dist/owns-empty-discovery.js.map +1 -0
- package/dist/path-universe.d.ts +44 -0
- package/dist/path-universe.d.ts.map +1 -0
- package/dist/path-universe.js +21 -0
- package/dist/path-universe.js.map +1 -0
- package/dist/predicate.d.ts +33 -0
- package/dist/predicate.d.ts.map +1 -1
- package/dist/preset-dispatch.d.ts +19 -0
- package/dist/preset-dispatch.d.ts.map +1 -1
- package/dist/preset-dispatch.js +43 -3
- package/dist/preset-dispatch.js.map +1 -1
- package/dist/project-relative.d.ts +25 -0
- package/dist/project-relative.d.ts.map +1 -0
- package/dist/project-relative.js +54 -0
- package/dist/project-relative.js.map +1 -0
- package/dist/report.d.ts +11 -5
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +17 -0
- package/dist/report.js.map +1 -1
- package/dist/rule-builder-like.d.ts +11 -0
- package/dist/rule-builder-like.d.ts.map +1 -0
- package/dist/rule-builder-like.js +2 -0
- package/dist/rule-builder-like.js.map +1 -0
- package/dist/rule-builder.d.ts +109 -84
- package/dist/rule-builder.d.ts.map +1 -1
- package/dist/rule-builder.js +202 -158
- package/dist/rule-builder.js.map +1 -1
- package/dist/rule-description.d.ts +33 -1
- package/dist/rule-description.d.ts.map +1 -1
- package/dist/rule-description.js +17 -1
- package/dist/rule-description.js.map +1 -1
- package/dist/rule-metadata.d.ts +20 -3
- package/dist/rule-metadata.d.ts.map +1 -1
- package/dist/selection-memo.d.ts +47 -0
- package/dist/selection-memo.d.ts.map +1 -0
- package/dist/selection-memo.js +68 -0
- package/dist/selection-memo.js.map +1 -0
- package/dist/shallow-clone.d.ts +20 -0
- package/dist/shallow-clone.d.ts.map +1 -0
- package/dist/shallow-clone.js +27 -0
- package/dist/shallow-clone.js.map +1 -0
- package/dist/stderr.d.ts +16 -0
- package/dist/stderr.d.ts.map +1 -0
- package/dist/stderr.js +73 -0
- package/dist/stderr.js.map +1 -0
- package/dist/terminal-builder.d.ts +209 -9
- package/dist/terminal-builder.d.ts.map +1 -1
- package/dist/terminal-builder.js +264 -20
- package/dist/terminal-builder.js.map +1 -1
- package/dist/type-guards.d.ts +38 -0
- package/dist/type-guards.d.ts.map +1 -0
- package/dist/type-guards.js +42 -0
- package/dist/type-guards.js.map +1 -0
- package/dist/unsuppressable.d.ts +54 -0
- package/dist/unsuppressable.d.ts.map +1 -0
- package/dist/unsuppressable.js +76 -0
- package/dist/unsuppressable.js.map +1 -0
- package/dist/vacuity-findings.d.ts +55 -0
- package/dist/vacuity-findings.d.ts.map +1 -0
- package/dist/vacuity-findings.js +124 -0
- package/dist/vacuity-findings.js.map +1 -0
- package/dist/violation.d.ts +152 -4
- package/dist/violation.d.ts.map +1 -1
- package/dist/violation.js +262 -1
- package/dist/violation.js.map +1 -1
- package/package.json +1 -1
package/dist/preset-dispatch.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
import { severityFor } from './violation.js';
|
|
1
2
|
import { formatViolations } from './format.js';
|
|
2
3
|
import { finishPreset } from './report.js';
|
|
4
|
+
import { writeStderr } from './stderr.js';
|
|
5
|
+
import { UNSUPPRESSABLE } from './unsuppressable.js';
|
|
3
6
|
/**
|
|
4
7
|
* Dispatch a single rule within a preset.
|
|
5
8
|
*
|
|
@@ -19,9 +22,14 @@ export function dispatchRule(builder, rule, defaultSeverity, overrides) {
|
|
|
19
22
|
const violations = builder.rule(meta).violations();
|
|
20
23
|
if (effective === 'warn') {
|
|
21
24
|
if (violations.length > 0) {
|
|
22
|
-
|
|
25
|
+
writeStderr(formatViolations(violations));
|
|
23
26
|
}
|
|
24
|
-
|
|
27
|
+
// `bypassFilters` outranks a per-rule `overrides: { id: 'warn' }` — see
|
|
28
|
+
// `severityFor`. A config finding like `presetConstructsNothingViolation`
|
|
29
|
+
// is `UNSUPPRESSABLE` by its own text; silently dropping it here just
|
|
30
|
+
// because its OWN rule was downgraded is exactly the suppression path
|
|
31
|
+
// that text promises does not exist.
|
|
32
|
+
return violations.filter((v) => severityFor(v, 'warn') === 'error');
|
|
25
33
|
}
|
|
26
34
|
return violations;
|
|
27
35
|
}
|
|
@@ -35,11 +43,43 @@ export function validateOverrides(overrides, knownIds) {
|
|
|
35
43
|
const knownSet = new Set(knownIds);
|
|
36
44
|
for (const key of Object.keys(overrides)) {
|
|
37
45
|
if (!knownSet.has(key)) {
|
|
38
|
-
|
|
46
|
+
writeStderr(`[eess] Override key '${key}' does not match any rule in this preset. ` +
|
|
39
47
|
`Available rules: ${knownIds.join(', ')}`);
|
|
40
48
|
}
|
|
41
49
|
}
|
|
42
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* A configuration finding for a preset call that constructed **zero** rules —
|
|
53
|
+
* every optional capability was left off, or a required discovery pattern
|
|
54
|
+
* (a folder glob, a repositories glob) matched nothing, so the call checked
|
|
55
|
+
* nothing and would otherwise pass silently. The vacuity matrix
|
|
56
|
+
* (`scripts/vacuity-matrix.mjs`) is what proves a preset needs this: it
|
|
57
|
+
* probes every published preset at its minimal type-correct call, and a
|
|
58
|
+
* preset reaching `fail-open` there is exactly this shape.
|
|
59
|
+
*
|
|
60
|
+
* Unsuppressable (ADR-010) for the same reason a zero-examined rule is: the
|
|
61
|
+
* caller's mistake is in how the preset was configured, not in the code the
|
|
62
|
+
* preset would have checked, and `.excluding()`/a baseline/`--changed` all
|
|
63
|
+
* aim at the latter.
|
|
64
|
+
*
|
|
65
|
+
* @param presetName - The preset's own name, e.g. `'agentGuardrails'`.
|
|
66
|
+
* @param optionsHint - The option names that would enable a rule, for the
|
|
67
|
+
* remedy — e.g. `'noGenericErrors, noStubs, noEmptyBodies'`.
|
|
68
|
+
*/
|
|
69
|
+
export function presetConstructsNothingViolation(presetName, optionsHint) {
|
|
70
|
+
const message = `${presetName}(...) constructed zero rules at this call — no capability of this ` +
|
|
71
|
+
`preset was enabled, or a discovery pattern matched nothing, so it checks nothing ` +
|
|
72
|
+
`and passes silently. Enable at least one option (${optionsHint}), or remove the call.`;
|
|
73
|
+
return {
|
|
74
|
+
rule: presetName,
|
|
75
|
+
element: presetName,
|
|
76
|
+
file: '',
|
|
77
|
+
line: 0,
|
|
78
|
+
message,
|
|
79
|
+
suggestion: `${message} ${UNSUPPRESSABLE}`,
|
|
80
|
+
bypassFilters: true,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
43
83
|
/**
|
|
44
84
|
* Emit (stderr text) and throw a single `ArchRuleError` with all aggregated
|
|
45
85
|
* violations, if any. Kept for backward compatibility; it is now `finishPreset`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preset-dispatch.js","sourceRoot":"","sources":["../src/preset-dispatch.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"preset-dispatch.js","sourceRoot":"","sources":["../src/preset-dispatch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,YAAY,EAA4B,MAAM,aAAa,CAAA;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAuBpD;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAqB,EACrB,IAA8C,EAC9C,eAA6B,EAC7B,SAAmD;IAEnD,8EAA8E;IAC9E,gFAAgF;IAChF,6EAA6E;IAC7E,2BAA2B;IAC3B,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAC3D,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,eAAe,CAAA;IACzD,IAAI,SAAS,KAAK,KAAK;QAAE,OAAO,EAAE,CAAA;IAElC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAA;IAElD,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,WAAW,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAA;QAC3C,CAAC;QACD,wEAAwE;QACxE,0EAA0E;QAC1E,sEAAsE;QACtE,sEAAsE;QACtE,qCAAqC;QACrC,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,CAAA;IACrE,CAAC;IAED,OAAO,UAAU,CAAA;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAAmD,EACnD,QAAkB;IAElB,IAAI,CAAC,SAAS;QAAE,OAAM;IACtB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAA;IAClC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,WAAW,CACT,wBAAwB,GAAG,4CAA4C;gBACrE,oBAAoB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5C,CAAA;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,gCAAgC,CAC9C,UAAkB,EAClB,WAAmB;IAEnB,MAAM,OAAO,GACX,GAAG,UAAU,oEAAoE;QACjF,mFAAmF;QACnF,oDAAoD,WAAW,wBAAwB,CAAA;IACzF,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,UAAU;QACnB,IAAI,EAAE,EAAE;QACR,IAAI,EAAE,CAAC;QACP,OAAO;QACP,UAAU,EAAE,GAAG,OAAO,IAAI,cAAc,EAAE;QAC1C,aAAa,EAAE,IAAI;KACpB,CAAA;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAA2B;IAC3D,YAAY,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;AAC/C,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a glob can already match an absolute path.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from ts-archunit's larger `project-relative.ts`, most of which
|
|
5
|
+
* (`rootOf`/`relativeToRoot`, workspace multi-root awareness) needs
|
|
6
|
+
* `ArchProject`/ts-morph and stays deferred — this one predicate is pure
|
|
7
|
+
* string syntax with no dependency on either, and `glob-diagnosis.ts` needs
|
|
8
|
+
* it to be kernel-eligible at all, so it gets its own small home here rather
|
|
9
|
+
* than waiting on the ts-morph-blocked half of the file it came from.
|
|
10
|
+
*
|
|
11
|
+
* Covers POSIX-absolute and Windows drive-absolute globs as well as an
|
|
12
|
+
* explicit globstar.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isAnchored(glob: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Does this glob name a location relative to the project root?
|
|
17
|
+
*
|
|
18
|
+
* Only an **unanchored, relative** glob is normalized. `'**\/x'` is explicitly
|
|
19
|
+
* "anywhere" and must keep meaning that; `'/abs/x'` is already absolute. So
|
|
20
|
+
* this is the same population `syntacticFault` calls `unanchored`, which is
|
|
21
|
+
* what makes the two consistent: a glob stops being reported dead for being
|
|
22
|
+
* unanchored exactly when it starts working.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isProjectRelative(glob: string): boolean;
|
|
25
|
+
//# sourceMappingURL=project-relative.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-relative.d.ts","sourceRoot":"","sources":["../src/project-relative.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAyBvD"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a glob can already match an absolute path.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from ts-archunit's larger `project-relative.ts`, most of which
|
|
5
|
+
* (`rootOf`/`relativeToRoot`, workspace multi-root awareness) needs
|
|
6
|
+
* `ArchProject`/ts-morph and stays deferred — this one predicate is pure
|
|
7
|
+
* string syntax with no dependency on either, and `glob-diagnosis.ts` needs
|
|
8
|
+
* it to be kernel-eligible at all, so it gets its own small home here rather
|
|
9
|
+
* than waiting on the ts-morph-blocked half of the file it came from.
|
|
10
|
+
*
|
|
11
|
+
* Covers POSIX-absolute and Windows drive-absolute globs as well as an
|
|
12
|
+
* explicit globstar.
|
|
13
|
+
*/
|
|
14
|
+
export function isAnchored(glob) {
|
|
15
|
+
return glob.startsWith('**/') || glob.startsWith('/') || /^[A-Za-z]:\//.test(glob);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Does this glob name a location relative to the project root?
|
|
19
|
+
*
|
|
20
|
+
* Only an **unanchored, relative** glob is normalized. `'**\/x'` is explicitly
|
|
21
|
+
* "anywhere" and must keep meaning that; `'/abs/x'` is already absolute. So
|
|
22
|
+
* this is the same population `syntacticFault` calls `unanchored`, which is
|
|
23
|
+
* what makes the two consistent: a glob stops being reported dead for being
|
|
24
|
+
* unanchored exactly when it starts working.
|
|
25
|
+
*/
|
|
26
|
+
export function isProjectRelative(glob) {
|
|
27
|
+
// A `./` segment is excluded, and that exclusion is load-bearing rather than
|
|
28
|
+
// fussy. `syntacticFault` reports `dot-segment` for a `./` anywhere in a
|
|
29
|
+
// glob, so normalizing one would make the rule MATCH at runtime while the
|
|
30
|
+
// gate still reported it dead — two derivations disagreeing about the same
|
|
31
|
+
// glob, which is the failure this project spends most of its guards on.
|
|
32
|
+
//
|
|
33
|
+
// `./` is a mistake in both worlds — it never occurs in an absolute path and
|
|
34
|
+
// it says nothing extra in a relative one — so the honest fix is to leave it
|
|
35
|
+
// failing, with advice that says to remove it.
|
|
36
|
+
// `..` is not relative-to-the-root in any usable sense: containment returns
|
|
37
|
+
// `undefined` for anything above the root, deliberately, so a `../`
|
|
38
|
+
// glob would normalize to nothing and be reported dead with three false
|
|
39
|
+
// causes. Excluded alongside `./` — both are mistakes in both readings.
|
|
40
|
+
if (/(?:^|\/)\.\.?\//.test(glob))
|
|
41
|
+
return false;
|
|
42
|
+
// Derived from `isAnchored`, not restated — two lists that disagree is the
|
|
43
|
+
// failure this file spends most of its guards on. `isAnchored` covers `/x`,
|
|
44
|
+
// `**/x` and a drive-absolute `C:/x`.
|
|
45
|
+
if (isAnchored(glob))
|
|
46
|
+
return false;
|
|
47
|
+
// `*/x/**` is deliberately NOT normalized, even though it is unanchored.
|
|
48
|
+
// Normalizing it would make it match, which sounds like an improvement until
|
|
49
|
+
// you notice it is the LAST reachable `unanchored` fault for a path glob —
|
|
50
|
+
// the anchor advice would become unreachable. Left failing, with a remedy
|
|
51
|
+
// that works: `'**/x/**'`.
|
|
52
|
+
return !glob.startsWith('*/');
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=project-relative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-relative.js","sourceRoot":"","sources":["../src/project-relative.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,6EAA6E;IAC7E,yEAAyE;IACzE,0EAA0E;IAC1E,2EAA2E;IAC3E,wEAAwE;IACxE,EAAE;IACF,6EAA6E;IAC7E,6EAA6E;IAC7E,+CAA+C;IAC/C,4EAA4E;IAC5E,oEAAoE;IACpE,wEAAwE;IACxE,wEAAwE;IACxE,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAC9C,2EAA2E;IAC3E,4EAA4E;IAC5E,sCAAsC;IACtC,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAClC,yEAAyE;IACzE,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,2BAA2B;IAC3B,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;AAC/B,CAAC"}
|
package/dist/report.d.ts
CHANGED
|
@@ -20,12 +20,18 @@ export interface PresetReportOptions extends ReportOptions {
|
|
|
20
20
|
readonly report?: ReportMode;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
23
|
+
* How many violations this module has actually WRITTEN, ever.
|
|
24
|
+
*
|
|
25
|
+
* Read as a delta by a caller that aggregates reporting, to answer one question it
|
|
26
|
+
* cannot otherwise answer: *did something emit while I was loading that module?*
|
|
27
|
+
*
|
|
28
|
+
* The alternative a caller might reach for — counting the writes it SUPPRESSED and
|
|
29
|
+
* inferring "then nothing was written" — is a double negative and is unsound: a
|
|
30
|
+
* module that suppresses one terminal and leaks through another satisfies it while
|
|
31
|
+
* leaking. Measured on `eess-ts`, which shipped that inference and fell into
|
|
32
|
+
* exactly that case. Count emissions, not silences.
|
|
28
33
|
*/
|
|
34
|
+
export declare function violationsEmittedCount(): number;
|
|
29
35
|
export declare function reportViolations(violations: ArchViolation[], options?: ReportOptions): void;
|
|
30
36
|
/**
|
|
31
37
|
* Finish a preset: deliver its aggregated violations per the requested mode
|
package/dist/report.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAMtD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEpD,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAA;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,sEAAsE;AACtE,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAC7B;
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAMtD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEpD,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAA;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,sEAAsE;AACtE,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAC7B;AAWD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,aAAa,EAAE,EAAE,OAAO,GAAE,aAAkB,GAAG,IAAI,CAa/F;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,aAAa,EAAE,EAC3B,OAAO,GAAE,mBAAwB,GAChC,aAAa,EAAE,CAQjB"}
|
package/dist/report.js
CHANGED
|
@@ -9,9 +9,26 @@ import { formatViolationsGitHub } from './format-github.js';
|
|
|
9
9
|
* path) both delegate here, so the two reporting paths can no longer diverge
|
|
10
10
|
* (plan 0070). Emits nothing for an empty set.
|
|
11
11
|
*/
|
|
12
|
+
let violationsEmitted = 0;
|
|
13
|
+
/**
|
|
14
|
+
* How many violations this module has actually WRITTEN, ever.
|
|
15
|
+
*
|
|
16
|
+
* Read as a delta by a caller that aggregates reporting, to answer one question it
|
|
17
|
+
* cannot otherwise answer: *did something emit while I was loading that module?*
|
|
18
|
+
*
|
|
19
|
+
* The alternative a caller might reach for — counting the writes it SUPPRESSED and
|
|
20
|
+
* inferring "then nothing was written" — is a double negative and is unsound: a
|
|
21
|
+
* module that suppresses one terminal and leaks through another satisfies it while
|
|
22
|
+
* leaking. Measured on `eess-ts`, which shipped that inference and fell into
|
|
23
|
+
* exactly that case. Count emissions, not silences.
|
|
24
|
+
*/
|
|
25
|
+
export function violationsEmittedCount() {
|
|
26
|
+
return violationsEmitted;
|
|
27
|
+
}
|
|
12
28
|
export function reportViolations(violations, options = {}) {
|
|
13
29
|
if (violations.length === 0)
|
|
14
30
|
return;
|
|
31
|
+
violationsEmitted += violations.length;
|
|
15
32
|
const format = options.format ?? 'terminal';
|
|
16
33
|
if (format === 'json') {
|
|
17
34
|
process.stdout.write(formatViolationsJson(violations, options.reason) + '\n');
|
package/dist/report.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAwB3D;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAA2B,EAAE,UAAyB,EAAE;IACvF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IACnC,MAAM,MAAM,GAAiB,OAAO,CAAC,MAAM,IAAI,UAAU,CAAA;IACzD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAA;IAC/E,CAAC;SAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;IAC1E,CAAC;SAAM,CAAC;QACN,wEAAwE;QACxE,0DAA0D;QAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAA;IAC3E,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,UAA2B,EAC3B,UAA+B,EAAE;IAEjC,MAAM,IAAI,GAAe,OAAO,CAAC,MAAM,IAAI,OAAO,CAAA;IAClD,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAA;IACxC,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;IACrC,IAAI,IAAI,KAAK,OAAO,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IACrD,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC"}
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAwB3D;;;;;;GAMG;AACH,IAAI,iBAAiB,GAAG,CAAC,CAAA;AAEzB;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,iBAAiB,CAAA;AAC1B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAA2B,EAAE,UAAyB,EAAE;IACvF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAM;IACnC,iBAAiB,IAAI,UAAU,CAAC,MAAM,CAAA;IACtC,MAAM,MAAM,GAAiB,OAAO,CAAC,MAAM,IAAI,UAAU,CAAA;IACzD,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAA;IAC/E,CAAC;SAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,UAAU,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;IAC1E,CAAC;SAAM,CAAC;QACN,wEAAwE;QACxE,0DAA0D;QAC1D,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAA;IAC3E,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,UAA2B,EAC3B,UAA+B,EAAE;IAEjC,MAAM,IAAI,GAAe,OAAO,CAAC,MAAM,IAAI,OAAO,CAAA;IAClD,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAA;IACxC,gBAAgB,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;IACrC,IAAI,IAAI,KAAK,OAAO,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,aAAa,CAAC,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;IACrD,CAAC;IACD,OAAO,UAAU,CAAA;AACnB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ArchViolation } from './violation.js';
|
|
2
|
+
/**
|
|
3
|
+
* Minimal shape the CLI runner and presets collect violations from: anything
|
|
4
|
+
* exposing a non-throwing, severity-stamped `.violations()`. Lives in core (not
|
|
5
|
+
* `cli/`) so presets can return `RuleBuilderLike[]` without depending on CLI
|
|
6
|
+
* infrastructure.
|
|
7
|
+
*/
|
|
8
|
+
export interface RuleBuilderLike {
|
|
9
|
+
violations: () => ArchViolation[];
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=rule-builder-like.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-builder-like.d.ts","sourceRoot":"","sources":["../src/rule-builder-like.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,aAAa,EAAE,CAAA;CAClC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-builder-like.js","sourceRoot":"","sources":["../src/rule-builder-like.ts"],"names":[],"mappings":""}
|
package/dist/rule-builder.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { Predicate } from './predicate.js';
|
|
2
2
|
import type { Condition, ConditionContext } from './condition.js';
|
|
3
|
-
import type { ArchViolation } from './violation.js';
|
|
4
|
-
import type { CheckOptions } from './check-options.js';
|
|
5
|
-
import type { RuleMetadata } from './rule-metadata.js';
|
|
6
3
|
import type { RuleDescription } from './rule-description.js';
|
|
7
|
-
import type { SilentExclusion } from './silent-exclusion.js';
|
|
8
4
|
import type { Selection, ElementInfo } from './correspondence.js';
|
|
5
|
+
import type { GlobNode } from './glob-site.js';
|
|
6
|
+
import { TerminalBuilder, type CollectResult } from './terminal-builder.js';
|
|
9
7
|
/**
|
|
10
8
|
* Abstract base class for all rule builders.
|
|
11
9
|
*
|
|
@@ -15,20 +13,35 @@ import type { Selection, ElementInfo } from './correspondence.js';
|
|
|
15
13
|
* 3. Add condition methods that call `addCondition()`
|
|
16
14
|
*
|
|
17
15
|
* The builder accumulates predicates and conditions. Nothing executes
|
|
18
|
-
* until a terminal method (`.check()`, `.warn()`, `.severity()`) is called
|
|
16
|
+
* until a terminal method (`.check()`, `.warn()`, `.severity()`) is called —
|
|
17
|
+
* inherited from {@link TerminalBuilder} (plan 0088 Phase 4), which also
|
|
18
|
+
* supplies `because`/`rule`/`excluding`/`violations`/`expectEmpty`/
|
|
19
|
+
* `expectNonEmpty` and the ADR-010 evidence gate. `RuleBuilder` keeps its own
|
|
20
|
+
* `<T, P>` two-param generic — `P` is the dialect's project type, kept
|
|
21
|
+
* separate from `TerminalBuilder` (which has no project concept, since
|
|
22
|
+
* `correspondence()`, `SmellBuilder`, and the graphql builders don't share a
|
|
23
|
+
* uniform notion of "one project") — every builder across all five dialects
|
|
24
|
+
* depends on this exact two-param signature, so it is not replaced by the
|
|
25
|
+
* fold, only extended.
|
|
19
26
|
*/
|
|
20
|
-
export declare abstract class RuleBuilder<T, P = unknown> {
|
|
27
|
+
export declare abstract class RuleBuilder<T, P = unknown> extends TerminalBuilder {
|
|
21
28
|
protected readonly project: P;
|
|
22
29
|
protected _predicates: Predicate<T>[];
|
|
23
30
|
protected _conditions: Condition<T>[];
|
|
24
|
-
protected _reason?: string;
|
|
25
|
-
protected _metadata?: RuleMetadata;
|
|
26
|
-
protected _exclusions: (string | RegExp)[];
|
|
27
|
-
protected _silentIndices: Set<number>;
|
|
28
31
|
protected _phase: 'predicate' | 'condition';
|
|
32
|
+
/** Whether `.should()` was ever reached — bug 0155 state 3/4 vs state 1. */
|
|
33
|
+
protected _reachedShould: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Descriptions of predicate-only methods used AFTER `.should()` — bug 0155
|
|
36
|
+
* state 2. A dual-use method dispatches to a condition in that phase and
|
|
37
|
+
* never lands here, so anything recorded is genuinely a filter written where
|
|
38
|
+
* an assertion was meant.
|
|
39
|
+
*/
|
|
40
|
+
protected _misplaced: string[];
|
|
29
41
|
constructor(project: P);
|
|
30
42
|
/**
|
|
31
|
-
* Begin the predicate phase. Returns
|
|
43
|
+
* Begin the predicate phase. Returns a COPY — a held selection is never
|
|
44
|
+
* edited by narrowing it (see `TerminalBuilder.copy()`).
|
|
32
45
|
* Purely a readability marker — `.that().haveNameMatching(...)` reads like English.
|
|
33
46
|
* Explicitly resets phase to 'predicate' — defensive against `.should().that()` misuse.
|
|
34
47
|
*/
|
|
@@ -59,50 +72,6 @@ export declare abstract class RuleBuilder<T, P = unknown> {
|
|
|
59
72
|
* as a predicate; if it has `evaluate` it is treated as a condition.
|
|
60
73
|
*/
|
|
61
74
|
satisfy(custom: Predicate<T> | Condition<T>): this;
|
|
62
|
-
/**
|
|
63
|
-
* Attach a human-readable rationale to the rule.
|
|
64
|
-
* Included in violation messages when `.check()` throws.
|
|
65
|
-
*/
|
|
66
|
-
because(reason: string): this;
|
|
67
|
-
/**
|
|
68
|
-
* Attach rich metadata to the rule.
|
|
69
|
-
* Provides educational context in violation output: why, how to fix, docs link.
|
|
70
|
-
*
|
|
71
|
-
* If `metadata.because` is set, it also sets the reason (same as `.because()`).
|
|
72
|
-
*/
|
|
73
|
-
rule(metadata: RuleMetadata): this;
|
|
74
|
-
/**
|
|
75
|
-
* Exclude specific violations from reporting by matching against
|
|
76
|
-
* the violation's `element`, `file`, or `message` fields.
|
|
77
|
-
*
|
|
78
|
-
* Matched violations are silently suppressed. Use for permanent,
|
|
79
|
-
* intentional exceptions — not for temporary violations (use baseline for those).
|
|
80
|
-
*
|
|
81
|
-
* Patterns are matched against all three fields. Prefer anchored regexes
|
|
82
|
-
* or full string matches over short substrings, especially for `message`
|
|
83
|
-
* matching, to avoid accidentally suppressing unrelated violations whose
|
|
84
|
-
* messages happen to contain the same text.
|
|
85
|
-
*
|
|
86
|
-
* Emits a warning if an exclusion matches zero violations — so renamed
|
|
87
|
-
* or deleted exceptions don't silently stay in the rule.
|
|
88
|
-
*
|
|
89
|
-
* For narrowing a rule's scope at the predicate phase (so the rule never
|
|
90
|
-
* evaluates the excluded element), use `satisfy(not(<predicate>))` instead.
|
|
91
|
-
* See the "Excluding a file from a rule's scope" recipe in docs/recipes.md.
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* // Exclude by element name (fully qualified)
|
|
95
|
-
* .excluding('Asset.getImageUrl')
|
|
96
|
-
*
|
|
97
|
-
* @example
|
|
98
|
-
* // Exclude by file path (regex anchored to suffix)
|
|
99
|
-
* .excluding(/repositories\/index\.ts$/)
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* // Multiple exclusions, mixed forms
|
|
103
|
-
* .excluding('Asset.getImageUrl', /\/legacy\//, /generated/)
|
|
104
|
-
*/
|
|
105
|
-
excluding(...patterns: (string | RegExp | SilentExclusion)[]): this;
|
|
106
75
|
/**
|
|
107
76
|
* Return the predicate-filtered elements as a labelled `Selection<T>` for
|
|
108
77
|
* cross-validation (`correspondence()`). The set is exactly the elements this
|
|
@@ -121,38 +90,61 @@ export declare abstract class RuleBuilder<T, P = unknown> {
|
|
|
121
90
|
*/
|
|
122
91
|
describeRule(): RuleDescription;
|
|
123
92
|
/**
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
|
|
127
|
-
violations(): ArchViolation[];
|
|
128
|
-
/**
|
|
129
|
-
* Execute the rule and throw `ArchRuleError` if any violations are found.
|
|
130
|
-
* This is the primary terminal method — use in test assertions.
|
|
93
|
+
* ADR-010: is this rule's assertion satisfied by an empty selection, as a
|
|
94
|
+
* property of what its conditions assert (`.notExist()`) rather than a
|
|
95
|
+
* caller's `.expectEmpty()` declaration?
|
|
131
96
|
*
|
|
132
|
-
*
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
*
|
|
137
|
-
*
|
|
97
|
+
* `.every()`, not `.some()` — `.andShould()` ANDs, so a rule reading
|
|
98
|
+
* `.should().notExist().andShould().beExported()` still asserts something
|
|
99
|
+
* about subjects that exist, and exempting it on the strength of the one
|
|
100
|
+
* cardinality condition would silence the other. An empty condition list is
|
|
101
|
+
* NOT exempt: `[].every()` is vacuously `true`, and a rule with zero
|
|
102
|
+
* conditions is the assertion-less case `collectViolations()` now reports as
|
|
103
|
+
* a configuration finding (bug 0155; it used to be an unreachable stderr
|
|
104
|
+
* warning, which this comment named until that fix landed) — this override
|
|
105
|
+
* must not paper over it by also declaring it cardinality-satisfied.
|
|
138
106
|
*
|
|
139
|
-
*
|
|
107
|
+
* **Load-bearing:** for a DEAD selector this early return is the only thing
|
|
108
|
+
* between an assertion-less rule and a silent pass (the gate runs after the
|
|
109
|
+
* zero-examined branch). Pinned in `assertion-less-rules.test.ts`.
|
|
140
110
|
*/
|
|
141
|
-
warn(options?: CheckOptions): void;
|
|
142
111
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
*
|
|
146
|
-
|
|
147
|
-
|
|
112
|
+
* Does this rule assert anything at all? — bug 0155.
|
|
113
|
+
*
|
|
114
|
+
* Conditions alone are not enough: a predicate-only method written *after*
|
|
115
|
+
* `.should()` silently shrank the set the conditions run over, possibly to
|
|
116
|
+
* empty, in which case they hold vacuously. That rule asserts nothing
|
|
117
|
+
* meaningful even though `_conditions` is non-empty.
|
|
118
|
+
*/
|
|
119
|
+
protected assertsSomething(): boolean;
|
|
120
|
+
protected assertionAdvice(): string;
|
|
121
|
+
protected assertsCardinality(): boolean;
|
|
122
|
+
/**
|
|
123
|
+
* ADR-010 part 3: did this rule's own underlying source (the project, a
|
|
124
|
+
* diagram, an SDL string — whatever `P` loads) produce nothing at all,
|
|
125
|
+
* before `getElements()`'s own domain-specific extraction or any
|
|
126
|
+
* predicate ran? Default `false` — the kernel has no way to know, since
|
|
127
|
+
* `P` is opaque here. A dialect's concrete builder, which knows `P`'s real
|
|
128
|
+
* shape (e.g. `ArchProject`), overrides this to check its own project's
|
|
129
|
+
* file count directly — never `getElements().length`, which conflates "the
|
|
130
|
+
* source is empty" with "this domain legitimately has nothing in a
|
|
131
|
+
* healthy project" (e.g. zero JSX elements in a backend-only codebase).
|
|
132
|
+
*/
|
|
133
|
+
protected sourceEmpty(): boolean;
|
|
134
|
+
/** Declared globs, position derived from `_phase`. Pure — no `P` needed. */
|
|
135
|
+
globs(): readonly GlobNode[];
|
|
136
|
+
/** This rule's own project, for `diagnose()`/`doctor` outside `.check()`. */
|
|
137
|
+
getProject(): P;
|
|
138
|
+
/** A `globs()` tree diagnosably dead, when zero examined — same shape as `sourceEmpty()`. */
|
|
139
|
+
protected deadGlobDiagnosis(): string | undefined;
|
|
148
140
|
/**
|
|
149
141
|
* Register a predicate. Called by concrete builder methods like
|
|
150
|
-
* `.haveNameMatching()`, `.extend()`, etc.
|
|
142
|
+
* `.haveNameMatching()`, `.extend()`, etc. Returns a COPY — see `copy()`.
|
|
151
143
|
*/
|
|
152
144
|
protected addPredicate(predicate: Predicate<T>): this;
|
|
153
145
|
/**
|
|
154
146
|
* Register a condition. Called by concrete builder methods like
|
|
155
|
-
* `.notContain()`, `.notExist()`, etc.
|
|
147
|
+
* `.notContain()`, `.notExist()`, etc. Returns a COPY — see `copy()`.
|
|
156
148
|
*/
|
|
157
149
|
protected addCondition(condition: Condition<T>): this;
|
|
158
150
|
/**
|
|
@@ -161,10 +153,31 @@ export declare abstract class RuleBuilder<T, P = unknown> {
|
|
|
161
153
|
*/
|
|
162
154
|
protected abstract getElements(): T[];
|
|
163
155
|
/**
|
|
164
|
-
*
|
|
165
|
-
*
|
|
156
|
+
* An independent copy, carrying **both** predicates and conditions.
|
|
157
|
+
* Extends `TerminalBuilder.copy()` with the fields this class adds.
|
|
166
158
|
*
|
|
167
|
-
* Subclasses with additional
|
|
159
|
+
* Subclasses with additional mutable-reference fields of their own (arrays,
|
|
160
|
+
* sets, maps a chain method pushes onto) MUST override this and call
|
|
161
|
+
* `super.copy()` first, the same reason `TerminalBuilder.copy()`'s own
|
|
162
|
+
* docstring gives — `Object.assign` shallow-copies a field, it does not
|
|
163
|
+
* give it independent identity.
|
|
164
|
+
*/
|
|
165
|
+
protected copy(): this;
|
|
166
|
+
/**
|
|
167
|
+
* A fork of this builder, carrying BOTH lists. Used by `.should()` to support
|
|
168
|
+
* named selections without mutation.
|
|
169
|
+
*
|
|
170
|
+
* **Nothing here clears the conditions** (bug 0156). It used to, and a second
|
|
171
|
+
* `.should()` therefore silently discarded the first assertion — a rule that
|
|
172
|
+
* asserted something turned into one that asserted less, by a chain method.
|
|
173
|
+
* `.should().X().should().Y()` now accumulates exactly as `.andShould()` does.
|
|
174
|
+
*
|
|
175
|
+
* Ported from `packages/ts/src/core/rule-builder.ts`, where the engine copy
|
|
176
|
+
* landed the fix and left the kernel behind. Found by the architect review of
|
|
177
|
+
* PR #72: `eess-md`, `eess-mermaid` and `eess-gherkin` all extend THIS class,
|
|
178
|
+
* so they carried the defect — and `check:corpus`, `check:ledger` and
|
|
179
|
+
* `check:diagram` are md/mermaid gates, meaning this repo's own corpus
|
|
180
|
+
* enforcement ran on the broken copy.
|
|
168
181
|
*/
|
|
169
182
|
protected fork(): this;
|
|
170
183
|
/**
|
|
@@ -172,10 +185,22 @@ export declare abstract class RuleBuilder<T, P = unknown> {
|
|
|
172
185
|
*/
|
|
173
186
|
private buildRuleDescription;
|
|
174
187
|
/**
|
|
175
|
-
* Execute the full pipeline: filter elements with predicates,
|
|
176
|
-
*
|
|
177
|
-
|
|
178
|
-
|
|
188
|
+
* Execute the full pipeline: filter elements with predicates, evaluate
|
|
189
|
+
* conditions, return violations plus the ADR-010 evidence — the
|
|
190
|
+
* post-predicate subject count, whatever it is. `TerminalBuilder.check()` /
|
|
191
|
+
* `.warn()` / `.violations()` decide what a zero count means (a
|
|
192
|
+
* configuration finding, unless `.expectEmpty()` was declared); this method
|
|
193
|
+
* only reports the count, never interprets it.
|
|
194
|
+
*
|
|
195
|
+
* `sourceEmpty` (ADR-010 part 3) is deliberately not `allElements.length
|
|
196
|
+
* === 0` — a domain's own `getElements()` legitimately returning nothing in
|
|
197
|
+
* a healthy, fully-loaded project (e.g. zero JSX elements in a
|
|
198
|
+
* backend-only codebase) is not brokenness, and conflating the two broke
|
|
199
|
+
* `.notExist()`'s cardinality exemption for exactly that case. Subclasses
|
|
200
|
+
* that can answer "did my underlying source load anything at all" override
|
|
201
|
+
* `sourceEmpty()`; the default assumes it did.
|
|
202
|
+
*/
|
|
203
|
+
protected collectViolations(): CollectResult;
|
|
179
204
|
/**
|
|
180
205
|
* Build the `ConditionContext` passed to each condition.
|
|
181
206
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rule-builder.d.ts","sourceRoot":"","sources":["../src/rule-builder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rule-builder.d.ts","sourceRoot":"","sources":["../src/rule-builder.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AAEjE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACjE,OAAO,KAAK,EAAgB,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE5D,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAA0B,MAAM,uBAAuB,CAAA;AA6CnG;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,8BAAsB,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,CAAE,SAAQ,eAAe;IAc3D,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;IAbzC,SAAS,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAK;IAC1C,SAAS,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAK;IAC1C,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,WAAW,CAAc;IACzD,4EAA4E;IAC5E,SAAS,CAAC,cAAc,UAAQ;IAChC;;;;;OAKG;IACH,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,CAAK;gBAEJ,OAAO,EAAE,CAAC;IAMzC;;;;;OAKG;IACH,IAAI,IAAI,IAAI;IAMZ;;;OAGG;IACH,GAAG,IAAI,IAAI;IAIX;;;;OAIG;IACH,MAAM,IAAI,IAAI;IAOd;;;OAGG;IACH,SAAS,IAAI,IAAI;IAIjB;;;;;;;;OAQG;IACH,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAelD;;;;;;;OAOG;IACH,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,WAAW,CAAA;KAAE,GAAG,SAAS,CAAC,CAAC,CAAC;IAOpF;;;OAGG;IACH,YAAY,IAAI,eAAe;IAW/B;;;;;;;;;;;;;;;;;;OAkBG;IACH;;;;;;;OAOG;IACH,SAAS,CAAC,gBAAgB,IAAI,OAAO;IAIrC,SAAS,CAAC,eAAe,IAAI,MAAM;cAQhB,kBAAkB,IAAI,OAAO;IAKhD;;;;;;;;;;OAUG;IACH,SAAS,CAAC,WAAW,IAAI,OAAO;IAIhC,4EAA4E;IAC5E,KAAK,IAAI,SAAS,QAAQ,EAAE;IAI5B,6EAA6E;IAC7E,UAAU,IAAI,CAAC;IAIf,6FAA6F;IAC7F,SAAS,CAAC,iBAAiB,IAAI,MAAM,GAAG,SAAS;IAMjD;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAWrD;;;OAGG;IACH,SAAS,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAMrD;;;OAGG;IACH,SAAS,CAAC,QAAQ,CAAC,WAAW,IAAI,CAAC,EAAE;IAErC;;;;;;;;;OASG;cACgB,IAAI,IAAI,IAAI;IAQ/B;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,IAAI,IAAI,IAAI;IAQtB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAS5B;;;;;;;;;;;;;;;OAeG;IACH,SAAS,CAAC,iBAAiB,IAAI,aAAa;IAuC5C;;;;;;OAMG;IACH,SAAS,CAAC,qBAAqB,IAAI,gBAAgB;CASpD"}
|