@nielspeter/eess 0.2.2 → 0.5.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 +97 -4
- 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-generator.d.ts +9 -0
- package/dist/baseline-generator.d.ts.map +1 -1
- package/dist/baseline-generator.js +9 -0
- package/dist/baseline-generator.js.map +1 -1
- 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 +80 -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/cli-config.d.ts +59 -0
- package/dist/cli-config.d.ts.map +1 -0
- package/dist/cli-config.js +84 -0
- package/dist/cli-config.js.map +1 -0
- package/dist/collect-result.d.ts +94 -0
- package/dist/collect-result.d.ts.map +1 -0
- package/dist/collect-result.js +142 -0
- package/dist/collect-result.js.map +1 -0
- package/dist/combinators.d.ts +14 -0
- package/dist/combinators.d.ts.map +1 -1
- package/dist/combinators.js +53 -16
- package/dist/combinators.js.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 +43 -0
- package/dist/condition.d.ts.map +1 -1
- package/dist/condition.js +48 -1
- package/dist/condition.js.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 +57 -5
- package/dist/correspondence.d.ts.map +1 -1
- package/dist/correspondence.js +74 -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 +101 -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 -1
- package/dist/diff-aware.d.ts.map +1 -1
- package/dist/diff-aware.js +39 -9
- 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/emitter-findings.d.ts +167 -0
- package/dist/emitter-findings.d.ts.map +1 -0
- package/dist/emitter-findings.js +237 -0
- package/dist/emitter-findings.js.map +1 -0
- package/dist/errors.d.ts +73 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +93 -0
- package/dist/errors.js.map +1 -1
- package/dist/exclusion-comments.d.ts +36 -1
- package/dist/exclusion-comments.d.ts.map +1 -1
- package/dist/exclusion-comments.js +185 -37
- package/dist/exclusion-comments.js.map +1 -1
- package/dist/execute-rule.d.ts +11 -1
- package/dist/execute-rule.d.ts.map +1 -1
- package/dist/execute-rule.js +220 -11
- package/dist/execute-rule.js.map +1 -1
- package/dist/file-walk.d.ts +22 -0
- package/dist/file-walk.d.ts.map +1 -0
- package/dist/file-walk.js +51 -0
- package/dist/file-walk.js.map +1 -0
- 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 +96 -1
- package/dist/format-json.d.ts.map +1 -1
- package/dist/format-json.js +94 -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 +41 -19
- 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 +18 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -10
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +55 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +92 -0
- package/dist/internal.js.map +1 -0
- package/dist/mask-non-comment.d.ts +49 -0
- package/dist/mask-non-comment.d.ts.map +1 -0
- package/dist/mask-non-comment.js +261 -0
- package/dist/mask-non-comment.js.map +1 -0
- 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 +85 -0
- package/dist/owns-empty-discovery.js.map +1 -0
- package/dist/path-suffix.d.ts +57 -0
- package/dist/path-suffix.d.ts.map +1 -0
- package/dist/path-suffix.js +73 -0
- package/dist/path-suffix.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 +45 -0
- package/dist/predicate.d.ts.map +1 -1
- package/dist/predicate.js +20 -1
- package/dist/predicate.js.map +1 -1
- package/dist/preset-dispatch.d.ts +6 -15
- package/dist/preset-dispatch.d.ts.map +1 -1
- package/dist/preset-dispatch.js +35 -17
- 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 +42 -12
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +190 -14
- package/dist/report.js.map +1 -1
- package/dist/rule-builder-like.d.ts +17 -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 +124 -84
- package/dist/rule-builder.d.ts.map +1 -1
- package/dist/rule-builder.js +230 -181
- package/dist/rule-builder.js.map +1 -1
- package/dist/rule-description.d.ts +83 -1
- package/dist/rule-description.d.ts.map +1 -1
- package/dist/rule-description.js +75 -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 +45 -0
- package/dist/selection-memo.d.ts.map +1 -0
- package/dist/selection-memo.js +66 -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/silent-exclusion.d.ts +12 -0
- package/dist/silent-exclusion.d.ts.map +1 -1
- package/dist/silent-exclusion.js +22 -0
- package/dist/silent-exclusion.js.map +1 -1
- 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 +224 -10
- package/dist/terminal-builder.d.ts.map +1 -1
- package/dist/terminal-builder.js +336 -46
- 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 +49 -0
- package/dist/vacuity-findings.d.ts.map +1 -0
- package/dist/vacuity-findings.js +94 -0
- package/dist/vacuity-findings.js.map +1 -0
- package/dist/violation.d.ts +173 -4
- package/dist/violation.d.ts.map +1 -1
- package/dist/violation.js +262 -1
- package/dist/violation.js.map +1 -1
- package/dist/watch.d.ts +71 -0
- package/dist/watch.d.ts.map +1 -0
- package/dist/watch.js +129 -0
- package/dist/watch.js.map +1 -0
- package/package.json +6 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What diff-aware mode suppressed, said out loud.
|
|
3
|
+
*
|
|
4
|
+
* Plan 0071's first instrument. `--changed` (and `check({ diff })`) filter
|
|
5
|
+
* **reporting**, not evaluation — so a run with every finding suppressed is
|
|
6
|
+
* indistinguishable from a clean run: exit 0, no output, `total: 0`. That is
|
|
7
|
+
* the false green ADR-008 exists to prevent, and it is worse here than
|
|
8
|
+
* elsewhere because the reader chose the flag and then forgot it: CI configures
|
|
9
|
+
* `--changed` once and every subsequent run reads as clean.
|
|
10
|
+
*
|
|
11
|
+
* **The count is derived by the caller, never self-reported.** Each call site
|
|
12
|
+
* computes `before.length - after.length` around its own `filterToChanged`
|
|
13
|
+
* call. `DiffFilter` could keep that tally itself, and it deliberately does
|
|
14
|
+
* not: `CheckOptions.diff` is a structural interface (`DiffFilterLike`), so a
|
|
15
|
+
* consumer can pass any object with a `filterToChanged` method, and a filter
|
|
16
|
+
* that under-reports its own suppression would produce exactly the silence
|
|
17
|
+
* this module exists to break. Caller-side subtraction is a differently-derived
|
|
18
|
+
* value (ADR-009 rule 5) and it works for filters we did not write.
|
|
19
|
+
*
|
|
20
|
+
* **Two surfaces, because only one of them can count.**
|
|
21
|
+
*
|
|
22
|
+
* | surface | disclosure |
|
|
23
|
+
* | ---------------------------------------- | -------------------- |
|
|
24
|
+
* | CLI `check --changed` | `suppressionNotice` |
|
|
25
|
+
* | `checkAll([...])` | `suppressionNotice` |
|
|
26
|
+
* | `.check({ diff })` / `.warn({ diff })` | `activeNotice`, once |
|
|
27
|
+
*
|
|
28
|
+
* The first two filter once over every collected violation, so they know the
|
|
29
|
+
* whole number. The per-rule terminals do not: `filterToChanged` is called
|
|
30
|
+
* once per rule (`execute-rule.ts`), and a diff-aware suite with 79 rules
|
|
31
|
+
* would print 79 lines — on the channel v0.26.0 made unconditionally visible.
|
|
32
|
+
* There is no per-run aggregation point on that path, so those terminals state
|
|
33
|
+
* the **configuration** instead, once per process. A configuration statement
|
|
34
|
+
* cannot be wrong; a per-rule count presented as a run total would be.
|
|
35
|
+
*
|
|
36
|
+
* A `process.on('exit')` flush was considered and rejected: it would let the
|
|
37
|
+
* per-rule path print one complete total, but a library that installs an exit
|
|
38
|
+
* hook to deliver a correctness-relevant message has made that message
|
|
39
|
+
* dependent on stderr surviving process teardown — untestable in the shape the
|
|
40
|
+
* rest of this project asserts (a real child `vitest run`, bug 0024) without
|
|
41
|
+
* asserting a race. Stating the configuration is weaker and honest.
|
|
42
|
+
*/
|
|
43
|
+
/** Prefix shared with the rest of the library's stderr output. */
|
|
44
|
+
const TAG = '[eess]';
|
|
45
|
+
/**
|
|
46
|
+
* One line naming what was suppressed, or `undefined` when nothing was.
|
|
47
|
+
*
|
|
48
|
+
* `undefined` rather than an empty string so a call site cannot print a blank
|
|
49
|
+
* line by forgetting to check — the two callers both feed this straight into
|
|
50
|
+
* `writeStderr`.
|
|
51
|
+
*
|
|
52
|
+
* @param suppressed - `before.length - after.length`, computed by the caller.
|
|
53
|
+
* @param changedFiles - How many files the filter considered changed, when the
|
|
54
|
+
* filter exposes it. A user-supplied `DiffFilterLike` need not, in which case
|
|
55
|
+
* the sentence drops that clause rather than guessing.
|
|
56
|
+
* @param baseBranch - The branch diffed against, when known.
|
|
57
|
+
*/
|
|
58
|
+
export function suppressionNotice(suppressed, changedFiles, baseBranch) {
|
|
59
|
+
if (suppressed <= 0)
|
|
60
|
+
return undefined;
|
|
61
|
+
const findings = suppressed === 1 ? 'finding' : 'findings';
|
|
62
|
+
// A negative size is `DiffFilter`'s "git was unavailable" sentinel. That path
|
|
63
|
+
// filters nothing, so `suppressed` is 0 and we never reach here — but the
|
|
64
|
+
// guard is cheap and keeps the sentinel from ever reaching a user's screen.
|
|
65
|
+
const scope = changedFiles !== undefined && changedFiles >= 0
|
|
66
|
+
? ` outside the ${String(changedFiles)} changed ${changedFiles === 1 ? 'file' : 'files'}`
|
|
67
|
+
: ' outside the changed files';
|
|
68
|
+
const since = baseBranch === undefined ? '' : ` (diffed against '${baseBranch}')`;
|
|
69
|
+
return (`${TAG} Diff-aware mode suppressed ${String(suppressed)} ${findings}${scope}${since}. ` +
|
|
70
|
+
`Those findings are real and still present — this run did not check them. ` +
|
|
71
|
+
`Re-run without diff-aware mode to see every finding.`);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Whether {@link activeNotice} has already spoken in this process.
|
|
75
|
+
*
|
|
76
|
+
* Module-scoped rather than per-`DiffFilter`, because the documented pattern
|
|
77
|
+
* constructs a filter **inline per rule** — `.check({ diff: diffAware('main') })`
|
|
78
|
+
* in `docs/core-concepts.md:333` and `docs/what-to-check.md:515` — so
|
|
79
|
+
* per-instance state would still produce one line per rule.
|
|
80
|
+
*/
|
|
81
|
+
let noticed = false;
|
|
82
|
+
/**
|
|
83
|
+
* State that diff-aware filtering is on, once per process. Returns `undefined`
|
|
84
|
+
* on every call after the first, and whenever nothing was suppressed.
|
|
85
|
+
*
|
|
86
|
+
* Keyed on a call that actually suppressed something: a diff-aware run whose
|
|
87
|
+
* findings all happen to be in changed files has hidden nothing, and a notice
|
|
88
|
+
* there would train the reader to skip the line that matters.
|
|
89
|
+
*/
|
|
90
|
+
export function activeNotice(suppressed, changedFiles, baseBranch) {
|
|
91
|
+
if (suppressed <= 0 || noticed)
|
|
92
|
+
return undefined;
|
|
93
|
+
noticed = true;
|
|
94
|
+
const scope = changedFiles !== undefined && changedFiles >= 0
|
|
95
|
+
? `the ${String(changedFiles)} ${changedFiles === 1 ? 'file' : 'files'} changed`
|
|
96
|
+
: 'the files changed';
|
|
97
|
+
const since = baseBranch === undefined ? '' : ` since '${baseBranch}'`;
|
|
98
|
+
return (`${TAG} Diff-aware mode is active: this run reports only findings in ${scope}${since}. ` +
|
|
99
|
+
`Findings in unchanged files are suppressed and will not appear, however many there are. ` +
|
|
100
|
+
`Remove \`diff\` from the check options to see every finding.`);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Forget that {@link activeNotice} has spoken. **Tests only** — a suite
|
|
104
|
+
* asserting the once-per-process contract has to observe the first call, and
|
|
105
|
+
* whichever earlier test filtered first would otherwise have consumed it.
|
|
106
|
+
*/
|
|
107
|
+
export function resetDiffDisclosureForTests() {
|
|
108
|
+
noticed = false;
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=diff-disclosure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff-disclosure.js","sourceRoot":"","sources":["../src/diff-disclosure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,kEAAkE;AAClE,MAAM,GAAG,GAAG,QAAQ,CAAA;AAEpB;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAC/B,UAAkB,EAClB,YAAqB,EACrB,UAAmB;IAEnB,IAAI,UAAU,IAAI,CAAC;QAAE,OAAO,SAAS,CAAA;IAErC,MAAM,QAAQ,GAAG,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAA;IAC1D,8EAA8E;IAC9E,0EAA0E;IAC1E,4EAA4E;IAC5E,MAAM,KAAK,GACT,YAAY,KAAK,SAAS,IAAI,YAAY,IAAI,CAAC;QAC7C,CAAC,CAAC,gBAAgB,MAAM,CAAC,YAAY,CAAC,YAAY,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE;QACzF,CAAC,CAAC,4BAA4B,CAAA;IAClC,MAAM,KAAK,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,qBAAqB,UAAU,IAAI,CAAA;IAEjF,OAAO,CACL,GAAG,GAAG,+BAA+B,MAAM,CAAC,UAAU,CAAC,IAAI,QAAQ,GAAG,KAAK,GAAG,KAAK,IAAI;QACvF,2EAA2E;QAC3E,sDAAsD,CACvD,CAAA;AACH,CAAC;AAED;;;;;;;GAOG;AACH,IAAI,OAAO,GAAG,KAAK,CAAA;AAEnB;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,UAAkB,EAClB,YAAqB,EACrB,UAAmB;IAEnB,IAAI,UAAU,IAAI,CAAC,IAAI,OAAO;QAAE,OAAO,SAAS,CAAA;IAChD,OAAO,GAAG,IAAI,CAAA;IAEd,MAAM,KAAK,GACT,YAAY,KAAK,SAAS,IAAI,YAAY,IAAI,CAAC;QAC7C,CAAC,CAAC,OAAO,MAAM,CAAC,YAAY,CAAC,IAAI,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,UAAU;QAChF,CAAC,CAAC,mBAAmB,CAAA;IACzB,MAAM,KAAK,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,UAAU,GAAG,CAAA;IAEtE,OAAO,CACL,GAAG,GAAG,iEAAiE,KAAK,GAAG,KAAK,IAAI;QACxF,0FAA0F;QAC1F,8DAA8D,CAC/D,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B;IACzC,OAAO,GAAG,KAAK,CAAA;AACjB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the filesystem says about a glob that the compiler's file set does
|
|
3
|
+
* not — the shape of the data, not how to build it.
|
|
4
|
+
*
|
|
5
|
+
* `OnDisk`/`DiskSet` are pure: a materialized `DiskSet` is just a closure
|
|
6
|
+
* over already-walked filesystem data, so the type stays in the kernel.
|
|
7
|
+
* Walking a real project's filesystem needs Node's `fs`/`path` and the
|
|
8
|
+
* dialect's own project type to find the root, so the MATERIALIZER lives in
|
|
9
|
+
* that dialect (e.g. `packages/ts/src/core/disk-set.ts`'s `diskSet()`).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* What the filesystem knows that the compiler's file set does not.
|
|
13
|
+
*
|
|
14
|
+
* Distinguishes "your glob is misspelled" from "your glob is fine and your
|
|
15
|
+
* tsconfig scope excludes it" — the cheapest wrong action an agent can take
|
|
16
|
+
* on a dead-glob finding, and the common case in a real monorepo where a
|
|
17
|
+
* build-output or docs directory sits outside the loaded project.
|
|
18
|
+
*/
|
|
19
|
+
export type OnDisk = 'holds-typescript' | 'no-typescript' | 'absent' | 'not-determined';
|
|
20
|
+
/**
|
|
21
|
+
* What the filesystem knows that the compiler's file set does not.
|
|
22
|
+
*/
|
|
23
|
+
export interface DiskSet {
|
|
24
|
+
/** Classify a glob by what exists on disk under the paths it matches. */
|
|
25
|
+
classify(glob: string): OnDisk;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=disk-set.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disk-set.d.ts","sourceRoot":"","sources":["../src/disk-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,GAAG,kBAAkB,GAAG,eAAe,GAAG,QAAQ,GAAG,gBAAgB,CAAA;AAEvF;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAC/B"}
|
package/dist/disk-set.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the filesystem says about a glob that the compiler's file set does
|
|
3
|
+
* not — the shape of the data, not how to build it.
|
|
4
|
+
*
|
|
5
|
+
* `OnDisk`/`DiskSet` are pure: a materialized `DiskSet` is just a closure
|
|
6
|
+
* over already-walked filesystem data, so the type stays in the kernel.
|
|
7
|
+
* Walking a real project's filesystem needs Node's `fs`/`path` and the
|
|
8
|
+
* dialect's own project type to find the root, so the MATERIALIZER lives in
|
|
9
|
+
* that dialect (e.g. `packages/ts/src/core/disk-set.ts`'s `diskSet()`).
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=disk-set.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disk-set.js","sourceRoot":"","sources":["../src/disk-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How much evidence an allowlist condition actually had — bug 0015.
|
|
3
|
+
*
|
|
4
|
+
* The `only*` family constrains **edges**, not subjects. Each iterates a
|
|
5
|
+
* subject's imports (or importers) and reports one violation per edge outside
|
|
6
|
+
* the allowlist, so a subject with **zero edges has nothing to violate and
|
|
7
|
+
* passes**, however broken the allowlist. Measured: one file with no imports,
|
|
8
|
+
* `onlyImportFrom('**\/nowhere/**')` → 1 subject selected, 0 violations.
|
|
9
|
+
*
|
|
10
|
+
* The shape it fails on is the target case, not an edge case: in a layered
|
|
11
|
+
* architecture the innermost layer is the one an allowlist protects and is
|
|
12
|
+
* characteristically the layer with the fewest outbound imports.
|
|
13
|
+
*
|
|
14
|
+
* ## Why this reports rather than fails
|
|
15
|
+
*
|
|
16
|
+
* [ts-archunit Bug 0015](https://github.com/nielspeter/ts-archunit/blob/main/bugs/fixed/0015-allowlist-conditions-pass-vacuously-on-edgeless-subjects.md)
|
|
17
|
+
* refuted failing, per-subject and per-rule, on measurement:
|
|
18
|
+
*
|
|
19
|
+
* - **Per-subject has no statable remedy.** 14 of this repo's `src/` files have
|
|
20
|
+
* zero static imports and 10 are pure leaf modules. `tarjan.ts` is a
|
|
21
|
+
* dependency-free algorithm — the ideal innermost-layer citizen — and would
|
|
22
|
+
* fail at error severity. The remedies available are: add an import (harmful),
|
|
23
|
+
* exclude a working rule, narrow the selector, or delete the rule. None
|
|
24
|
+
* improves anything, because **for the `only*` family zero edges is maximal
|
|
25
|
+
* compliance**, not absent evidence. That fails ADR-009 rule 2.
|
|
26
|
+
* - **Per-rule multiplies.** Six boundaries and one dependency-free shared file
|
|
27
|
+
* make `strictBoundaries` emit 13 rules, **12** with subjects and zero edges.
|
|
28
|
+
* - **`ignoreTypeImports` inverts it.** Counting edges after the filter means a
|
|
29
|
+
* layer whose only dependency is `import type` counts zero and fires on the
|
|
30
|
+
* best possible outcome — under the option the docs recommend for layers.
|
|
31
|
+
*
|
|
32
|
+
* So the remedy is genuinely optional and the reader must judge it, which under
|
|
33
|
+
* ADR-009 rule 1 is a disclosure, not a failure. This module is the disclosure.
|
|
34
|
+
*
|
|
35
|
+
* ## Why module state rather than a field on `ConditionContext`
|
|
36
|
+
*
|
|
37
|
+
* `ConditionContext` is a **public exported type** backing the documented
|
|
38
|
+
* `defineCondition()`, and bug 0015 records that extending `Condition<T>` for
|
|
39
|
+
* this was one reason the failing design could not ship. `diff-disclosure.ts`
|
|
40
|
+
* established the pattern for a run-scoped notice that conditions produce and
|
|
41
|
+
* the CLI consumes; this follows it, including the test reset.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Why a rule tested no edges. The three are not interchangeable, and saying the
|
|
45
|
+
* wrong one is an ADR-009 rule 2 defect — a stated cause that is wrong for the
|
|
46
|
+
* input.
|
|
47
|
+
*
|
|
48
|
+
* The first version of this module printed "correct for a genuinely
|
|
49
|
+
* dependency-free module" for all three. Measured, that is false for two of
|
|
50
|
+
* them: a subject whose imports were filtered by `ignoreTypeImports` **has**
|
|
51
|
+
* dependencies, and a reader who opens the folder finds them and concludes the
|
|
52
|
+
* tool is broken; and a rule whose allowlist matched no import is pointing at
|
|
53
|
+
* the interesting case — the glob may be a typo — which that sentence hides.
|
|
54
|
+
*/
|
|
55
|
+
export type UntestedReason =
|
|
56
|
+
/** The subjects have no edges of any kind. Usually correct, and the layered case. */
|
|
57
|
+
'no-edges'
|
|
58
|
+
/** Edges existed, and every one was filtered out before the check saw it. */
|
|
59
|
+
| 'all-filtered'
|
|
60
|
+
/** Edges existed, and none of them matched the allowlist glob. */
|
|
61
|
+
| 'none-matched';
|
|
62
|
+
/** One rule's evidence: how many subjects it saw and how many edges it tested. */
|
|
63
|
+
export interface EdgeCoverage {
|
|
64
|
+
readonly rule: string;
|
|
65
|
+
readonly subjects: number;
|
|
66
|
+
readonly edges: number;
|
|
67
|
+
readonly reason: UntestedReason;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Record what a condition had to work with.
|
|
71
|
+
*
|
|
72
|
+
* Keyed on the rule description, and **accumulated** rather than overwritten:
|
|
73
|
+
* one rule can evaluate its condition more than once (a `.check()` after a
|
|
74
|
+
* `.violations()`, or the same description in two files), and taking the last
|
|
75
|
+
* write would report the smaller run.
|
|
76
|
+
*/
|
|
77
|
+
export declare function recordEdgeCoverage(rule: string, subjects: number, edges: number, reason?: UntestedReason): void;
|
|
78
|
+
/**
|
|
79
|
+
* Rules that had subjects and tested no edges — the vacuous passes.
|
|
80
|
+
*
|
|
81
|
+
* A rule with **no subjects** is deliberately excluded: that is an empty
|
|
82
|
+
* selector, which is `.expectNonEmpty()`'s business and plan 0067's, and
|
|
83
|
+
* reporting it here would give one fault two owners.
|
|
84
|
+
*/
|
|
85
|
+
export declare function untestedRules(): readonly EdgeCoverage[];
|
|
86
|
+
/**
|
|
87
|
+
* The disclosure, or `undefined` when every allowlist was exercised.
|
|
88
|
+
*
|
|
89
|
+
* Names the rules rather than counting them (ADR-009 rule 4): "3 rules tested
|
|
90
|
+
* nothing" sends the reader to grep, and the whole point is that they must
|
|
91
|
+
* judge whether an edge-free population is correct here.
|
|
92
|
+
*/
|
|
93
|
+
export declare function edgeCoverageNotice(): string | undefined;
|
|
94
|
+
/** Drop the tally. The CLI resets per run; tests reset per case. */
|
|
95
|
+
export declare function resetEdgeCoverage(): void;
|
|
96
|
+
//# sourceMappingURL=edge-coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-coverage.d.ts","sourceRoot":"","sources":["../src/edge-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,cAAc;AACxB,qFAAqF;AACnF,UAAU;AACZ,6EAA6E;GAC3E,cAAc;AAChB,kEAAkE;GAChE,cAAc,CAAA;AAElB,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAChC;AAID;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,MAAM,GAAE,cAA2B,GAClC,IAAI,CAeN;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,IAAI,SAAS,YAAY,EAAE,CAEvD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CA0BvD;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,IAAI,IAAI,CAExC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How much evidence an allowlist condition actually had — bug 0015.
|
|
3
|
+
*
|
|
4
|
+
* The `only*` family constrains **edges**, not subjects. Each iterates a
|
|
5
|
+
* subject's imports (or importers) and reports one violation per edge outside
|
|
6
|
+
* the allowlist, so a subject with **zero edges has nothing to violate and
|
|
7
|
+
* passes**, however broken the allowlist. Measured: one file with no imports,
|
|
8
|
+
* `onlyImportFrom('**\/nowhere/**')` → 1 subject selected, 0 violations.
|
|
9
|
+
*
|
|
10
|
+
* The shape it fails on is the target case, not an edge case: in a layered
|
|
11
|
+
* architecture the innermost layer is the one an allowlist protects and is
|
|
12
|
+
* characteristically the layer with the fewest outbound imports.
|
|
13
|
+
*
|
|
14
|
+
* ## Why this reports rather than fails
|
|
15
|
+
*
|
|
16
|
+
* [ts-archunit Bug 0015](https://github.com/nielspeter/ts-archunit/blob/main/bugs/fixed/0015-allowlist-conditions-pass-vacuously-on-edgeless-subjects.md)
|
|
17
|
+
* refuted failing, per-subject and per-rule, on measurement:
|
|
18
|
+
*
|
|
19
|
+
* - **Per-subject has no statable remedy.** 14 of this repo's `src/` files have
|
|
20
|
+
* zero static imports and 10 are pure leaf modules. `tarjan.ts` is a
|
|
21
|
+
* dependency-free algorithm — the ideal innermost-layer citizen — and would
|
|
22
|
+
* fail at error severity. The remedies available are: add an import (harmful),
|
|
23
|
+
* exclude a working rule, narrow the selector, or delete the rule. None
|
|
24
|
+
* improves anything, because **for the `only*` family zero edges is maximal
|
|
25
|
+
* compliance**, not absent evidence. That fails ADR-009 rule 2.
|
|
26
|
+
* - **Per-rule multiplies.** Six boundaries and one dependency-free shared file
|
|
27
|
+
* make `strictBoundaries` emit 13 rules, **12** with subjects and zero edges.
|
|
28
|
+
* - **`ignoreTypeImports` inverts it.** Counting edges after the filter means a
|
|
29
|
+
* layer whose only dependency is `import type` counts zero and fires on the
|
|
30
|
+
* best possible outcome — under the option the docs recommend for layers.
|
|
31
|
+
*
|
|
32
|
+
* So the remedy is genuinely optional and the reader must judge it, which under
|
|
33
|
+
* ADR-009 rule 1 is a disclosure, not a failure. This module is the disclosure.
|
|
34
|
+
*
|
|
35
|
+
* ## Why module state rather than a field on `ConditionContext`
|
|
36
|
+
*
|
|
37
|
+
* `ConditionContext` is a **public exported type** backing the documented
|
|
38
|
+
* `defineCondition()`, and bug 0015 records that extending `Condition<T>` for
|
|
39
|
+
* this was one reason the failing design could not ship. `diff-disclosure.ts`
|
|
40
|
+
* established the pattern for a run-scoped notice that conditions produce and
|
|
41
|
+
* the CLI consumes; this follows it, including the test reset.
|
|
42
|
+
*/
|
|
43
|
+
const coverage = new Map();
|
|
44
|
+
/**
|
|
45
|
+
* Record what a condition had to work with.
|
|
46
|
+
*
|
|
47
|
+
* Keyed on the rule description, and **accumulated** rather than overwritten:
|
|
48
|
+
* one rule can evaluate its condition more than once (a `.check()` after a
|
|
49
|
+
* `.violations()`, or the same description in two files), and taking the last
|
|
50
|
+
* write would report the smaller run.
|
|
51
|
+
*/
|
|
52
|
+
export function recordEdgeCoverage(rule, subjects, edges, reason = 'no-edges') {
|
|
53
|
+
const prior = coverage.get(rule);
|
|
54
|
+
// The MINIMUM edge count, not the maximum. Two evaluations of the same rule
|
|
55
|
+
// description — the same preset over two projects, or the same chain written
|
|
56
|
+
// twice — merge on this key, and taking the max let a run that tested edges
|
|
57
|
+
// erase a run that tested none. Measured: the vacuous run vanished from the
|
|
58
|
+
// report. For a disclosure OF vacuity the conservative direction is to keep
|
|
59
|
+
// the smaller evidence; over-disclosing costs a footnote, under-disclosing is
|
|
60
|
+
// the silent pass this module exists to surface.
|
|
61
|
+
coverage.set(rule, {
|
|
62
|
+
rule,
|
|
63
|
+
subjects: Math.max(prior?.subjects ?? 0, subjects),
|
|
64
|
+
edges: prior === undefined ? edges : Math.min(prior.edges, edges),
|
|
65
|
+
reason: prior !== undefined && prior.edges <= edges ? prior.reason : reason,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Rules that had subjects and tested no edges — the vacuous passes.
|
|
70
|
+
*
|
|
71
|
+
* A rule with **no subjects** is deliberately excluded: that is an empty
|
|
72
|
+
* selector, which is `.expectNonEmpty()`'s business and plan 0067's, and
|
|
73
|
+
* reporting it here would give one fault two owners.
|
|
74
|
+
*/
|
|
75
|
+
export function untestedRules() {
|
|
76
|
+
return [...coverage.values()].filter((c) => c.subjects > 0 && c.edges === 0);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The disclosure, or `undefined` when every allowlist was exercised.
|
|
80
|
+
*
|
|
81
|
+
* Names the rules rather than counting them (ADR-009 rule 4): "3 rules tested
|
|
82
|
+
* nothing" sends the reader to grep, and the whole point is that they must
|
|
83
|
+
* judge whether an edge-free population is correct here.
|
|
84
|
+
*/
|
|
85
|
+
export function edgeCoverageNotice() {
|
|
86
|
+
const untested = untestedRules();
|
|
87
|
+
if (untested.length === 0)
|
|
88
|
+
return undefined;
|
|
89
|
+
const because = {
|
|
90
|
+
'no-edges': 'those subjects have no imports at all, which is correct for a dependency-free module and ' +
|
|
91
|
+
'means the rule certified nothing otherwise',
|
|
92
|
+
'all-filtered': 'those subjects DO have imports — every one was excluded by `ignoreTypeImports` before the ' +
|
|
93
|
+
'check saw it, so the allowlist was never consulted',
|
|
94
|
+
'none-matched': 'those subjects have imports, and none matched the allowlist glob — so either nothing is ' +
|
|
95
|
+
'in scope by design, or the glob is wrong',
|
|
96
|
+
};
|
|
97
|
+
const lines = untested.map((c) => ` - ${c.rule}\n ${String(c.subjects)} subject${c.subjects === 1 ? '' : 's'}, 0 edges tested — ${because[c.reason]}.`);
|
|
98
|
+
const count = untested.length;
|
|
99
|
+
return (`[eess] ${String(count)} allowlist rule${count === 1 ? '' : 's'} passed without ` +
|
|
100
|
+
`testing a single edge:\n${lines.join('\n')}\n` +
|
|
101
|
+
` An allowlist constrains edges, so a subject with none cannot violate it. Only you can ` +
|
|
102
|
+
`tell an intended shape from a rule that certified nothing.`);
|
|
103
|
+
}
|
|
104
|
+
/** Drop the tally. The CLI resets per run; tests reset per case. */
|
|
105
|
+
export function resetEdgeCoverage() {
|
|
106
|
+
coverage.clear();
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=edge-coverage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-coverage.js","sourceRoot":"","sources":["../src/edge-coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AA8BH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAwB,CAAA;AAEhD;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAY,EACZ,QAAgB,EAChB,KAAa,EACb,SAAyB,UAAU;IAEnC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChC,4EAA4E;IAC5E,6EAA6E;IAC7E,4EAA4E;IAC5E,4EAA4E;IAC5E,4EAA4E;IAC5E,8EAA8E;IAC9E,iDAAiD;IACjD,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE;QACjB,IAAI;QACJ,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,IAAI,CAAC,EAAE,QAAQ,CAAC;QAClD,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC;QACjE,MAAM,EAAE,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;KAC5E,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,CAAA;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAA;IAChC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAE3C,MAAM,OAAO,GAAmC;QAC9C,UAAU,EACR,2FAA2F;YAC3F,4CAA4C;QAC9C,cAAc,EACZ,4FAA4F;YAC5F,oDAAoD;QACtD,cAAc,EACZ,0FAA0F;YAC1F,0CAA0C;KAC7C,CAAA;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CACxB,CAAC,CAAC,EAAE,EAAE,CACJ,OAAO,CAAC,CAAC,IAAI,SAAS,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,sBAAsB,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAC3H,CAAA;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAA;IAC7B,OAAO,CACL,UAAU,MAAM,CAAC,KAAK,CAAC,kBAAkB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,kBAAkB;QACjF,2BAA2B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;QAC/C,0FAA0F;QAC1F,4DAA4D,CAC7D,CAAA;AACH,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,iBAAiB;IAC/B,QAAQ,CAAC,KAAK,EAAE,CAAA;AAClB,CAAC"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { ArchViolation } from './violation.js';
|
|
2
|
+
/**
|
|
3
|
+
* The emitter's own configuration findings — [ADR-014](../../../adr/014-the-emitter-refuses-a-verdict-without-evidence.md).
|
|
4
|
+
*
|
|
5
|
+
* **Why these are not in `vacuity-findings.ts`.** Every finding there is built by
|
|
6
|
+
* `configFinding(facts, message)`, which reads its `ruleId` from
|
|
7
|
+
* `facts.describeRule()`. At the emitter there is no rule to describe: the value
|
|
8
|
+
* arrived from a preset, a loop, or a hand-assembled array, and the whole point
|
|
9
|
+
* of ADR-014 is that the emitter must speak about values it did not mint.
|
|
10
|
+
*
|
|
11
|
+
* That is not a stylistic difference, it is bug 0190's cause. The kernel's
|
|
12
|
+
* previous preset finding took `(presetName, optionsHint)` and carried **no
|
|
13
|
+
* `ruleId`**, so nothing could assert on it and no non-vacuity fixture could key
|
|
14
|
+
* on it — a finding no test could name is a finding no one can prove fires. It
|
|
15
|
+
* had no call site and was deleted rather than wired (plan 0235 Phase 0). These
|
|
16
|
+
* two carry **hardcoded, stable ids**, and they are the first hardcoded rule ids
|
|
17
|
+
* in the kernel for exactly that reason.
|
|
18
|
+
*
|
|
19
|
+
* **Why two and not one.** ADR-014 §4 separates them, and the remedies differ:
|
|
20
|
+
*
|
|
21
|
+
* - `emitter/no-receipt` — the value carried no evidence field at all. A shape
|
|
22
|
+
* defect. The remedy ("hand over what the pipeline minted") is real on every
|
|
23
|
+
* path, including one where the run was perfectly healthy.
|
|
24
|
+
* - `emitter/pass-without-evidence` — the value carried evidence, and it says
|
|
25
|
+
* zero examined with zero violations and no declaration. A vacuous pass. The
|
|
26
|
+
* remedy is about the selection, not the shape.
|
|
27
|
+
*
|
|
28
|
+
* Folding them into one id would make the fixture for either satisfiable by the
|
|
29
|
+
* other, which is the discrimination failure `check:nonvacuity` exists to catch.
|
|
30
|
+
*
|
|
31
|
+
* **What the kernel may say.** ADR-014 §4 is explicit that the kernel "never
|
|
32
|
+
* names a preset's options at a seam that may not be a preset": a preset that
|
|
33
|
+
* constructed zero rules owns its own remedy and names it before handing over.
|
|
34
|
+
* So these messages speak only about the value and the loop that produced it —
|
|
35
|
+
* the vocabulary any hand-assembler can act on.
|
|
36
|
+
*
|
|
37
|
+
* **`expectEmpty` is not an exception to that, it is the reason for the rule's
|
|
38
|
+
* shape.** It lives on the KERNEL's own `PresetReportOptions`, so naming it
|
|
39
|
+
* names this package's surface rather than a dialect's — and a product review
|
|
40
|
+
* found the vacuous-pass message, the one most likely to red an adopter's
|
|
41
|
+
* build, told them to "declare the set legitimately empty" without saying how.
|
|
42
|
+
* A remedy an author cannot act on is ADR-009 rule 2's failure, and it sends
|
|
43
|
+
* them to the one escape the message forbids in its next clause.
|
|
44
|
+
*/
|
|
45
|
+
/** The value handed to an emitter carried no evidence field at all. */
|
|
46
|
+
export declare const EMITTER_NO_RECEIPT = "emitter/no-receipt";
|
|
47
|
+
/** Zero examined, zero violations, no declaration — a pass built from nothing. */
|
|
48
|
+
export declare const EMITTER_PASS_WITHOUT_EVIDENCE = "emitter/pass-without-evidence";
|
|
49
|
+
/**
|
|
50
|
+
* A declaration that has expired: declared empty, then examined something.
|
|
51
|
+
*
|
|
52
|
+
* **This is what makes a declaration legitimate at all.** ADR-010 §3 admits
|
|
53
|
+
* `.expectEmpty()` precisely because it "fails the day it stops being true" —
|
|
54
|
+
* a claim that can never be contradicted is not an assertion, and the whole
|
|
55
|
+
* 2026-09-05 amendment to ADR-014 §3 turns on that property. Without this
|
|
56
|
+
* finding the emitter would accept a declaration nothing can ever falsify,
|
|
57
|
+
* which is the shape that amendment refused for `overrides: 'off'`.
|
|
58
|
+
*/
|
|
59
|
+
export declare const EMITTER_EXPIRED_DECLARATION = "emitter/expired-declaration";
|
|
60
|
+
/**
|
|
61
|
+
* A receipt that claims it never ran, and carries evidence that it did.
|
|
62
|
+
*
|
|
63
|
+
* **The falsifier `notRun` was shipped without.** `declaredEmpty` has one — the
|
|
64
|
+
* expiry above — and that property is the entire reason ADR-010 §3 admits a
|
|
65
|
+
* declaration at all. `notRun` suppresses too: it is the one condition that
|
|
66
|
+
* excludes a member from `mergeCollectResults`'s dead-member filter, so a zero
|
|
67
|
+
* marked `notRun` is a zero the merge will not complain about. A suppressor with
|
|
68
|
+
* no contradiction is exactly the shape ADR-014 §3's amendment refuses, and
|
|
69
|
+
* shipping one inside the change that establishes the rule is the defect an
|
|
70
|
+
* enforcement review caught here.
|
|
71
|
+
*
|
|
72
|
+
* A rule that never ran examined nothing and found nothing. Both halves are
|
|
73
|
+
* checked, because either alone is a lie the other does not cover: `examined > 0`
|
|
74
|
+
* is a denominator that could not exist, and a violation is a finding that could
|
|
75
|
+
* not have been produced.
|
|
76
|
+
*/
|
|
77
|
+
export declare const EMITTER_CONTRADICTORY_EVIDENCE = "emitter/contradictory-evidence";
|
|
78
|
+
/**
|
|
79
|
+
* The verdict's own source loaded nothing — ADR-014 §4.
|
|
80
|
+
*
|
|
81
|
+
* Distinct from `emitter/pass-without-evidence`, and the distinction is the
|
|
82
|
+
* point: a zero-examined verdict *may* be legitimate if the caller declares the
|
|
83
|
+
* emptiness, but an empty SOURCE may not. §4 states the precedence — "an empty
|
|
84
|
+
* source (`sourceEmpty`) outranks any declaration and names the source" — and
|
|
85
|
+
* ADR-010 §3 carries the same rule at the terminal as a `gated` row.
|
|
86
|
+
*
|
|
87
|
+
* The gate honoured `declaredEmpty` before it ever looked at `sourceEmpty`, so a
|
|
88
|
+
* hand-assembled receipt setting both passed silently: the escape hatch the
|
|
89
|
+
* comment beside that branch said this ADR had closed. Measured before the fix,
|
|
90
|
+
* `finishPreset(collectResult([], { examined: 0, sourceEmpty: true, declaredEmpty: true }))`
|
|
91
|
+
* returned green.
|
|
92
|
+
*/
|
|
93
|
+
export declare const EMITTER_SOURCE_EMPTY = "emitter/source-empty";
|
|
94
|
+
/**
|
|
95
|
+
* Every id this module can produce.
|
|
96
|
+
*
|
|
97
|
+
* One list, because there were two: `report.ts` had a four-way `||` and
|
|
98
|
+
* `dedupe-config-findings.ts` grew a second `Set` of the same four. Both are
|
|
99
|
+
* private, neither knew about the other, and a fifth id added to one and not the
|
|
100
|
+
* other silently reintroduces the defect the second was written to fix — N
|
|
101
|
+
* distinct dead builders collapsing into one finding annotated "they are one
|
|
102
|
+
* edit". The argument for naming the constants rather than testing an `emitter/`
|
|
103
|
+
* prefix only holds if there is ONE place to add the next one.
|
|
104
|
+
*
|
|
105
|
+
* Internal: exported for the kernel's own consumers, not on the root surface.
|
|
106
|
+
*/
|
|
107
|
+
export declare const EMITTER_IDS: ReadonlySet<string>;
|
|
108
|
+
/** Is this one of the emitter's own findings, as opposed to a caller's? */
|
|
109
|
+
export declare function isEmitterFinding(violation: {
|
|
110
|
+
ruleId?: string;
|
|
111
|
+
rule?: string;
|
|
112
|
+
}): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* The source loaded nothing, so no declaration can rescue the verdict.
|
|
115
|
+
*
|
|
116
|
+
* Names the SOURCE, per ADR-014 §4, and says so explicitly — the remedy is to
|
|
117
|
+
* fix the project or glob, never to declare the emptiness, and a reader told to
|
|
118
|
+
* "declare it" here would be sent to the one thing that cannot work. The
|
|
119
|
+
* terminal's `zeroLoadedSourceViolation` says the same thing in the same words;
|
|
120
|
+
* this is its emitter-seam sibling, for a receipt with no rule facts to carry.
|
|
121
|
+
*/
|
|
122
|
+
export declare function sourceEmptyViolation(): ArchViolation;
|
|
123
|
+
/**
|
|
124
|
+
* A value reached an emitter with no evidence at all — a bare array, or an
|
|
125
|
+
* object with no `examined`.
|
|
126
|
+
*
|
|
127
|
+
* This fires even when the run was healthy and found real violations, because
|
|
128
|
+
* the defect is that the verdict cannot be checked, not that it is wrong. That
|
|
129
|
+
* is deliberate: a shape that *sometimes* carries evidence is a shape nobody can
|
|
130
|
+
* rely on, and the one path where it matters most is the path where the loop
|
|
131
|
+
* examined nothing.
|
|
132
|
+
*/
|
|
133
|
+
export declare function noReceiptViolation(): ArchViolation;
|
|
134
|
+
/**
|
|
135
|
+
* A pass with evidence that proves nothing: zero examined, zero violations, no
|
|
136
|
+
* declaration.
|
|
137
|
+
*
|
|
138
|
+
* The remedy names the selection, never a preset's options — ADR-014 §4.
|
|
139
|
+
*/
|
|
140
|
+
export declare function passWithoutEvidenceViolation(): ArchViolation;
|
|
141
|
+
/**
|
|
142
|
+
* The declaration was true when written and is not true now.
|
|
143
|
+
*
|
|
144
|
+
* The mirror of the terminal's own `expiredExpectEmptyViolation`, at the seam a
|
|
145
|
+
* preset's declaration reaches (ADR-014 §3). The number IS the finding, so it
|
|
146
|
+
* is named.
|
|
147
|
+
*/
|
|
148
|
+
export declare function expiredDeclarationViolation(examined: number): ArchViolation;
|
|
149
|
+
/**
|
|
150
|
+
* `notRun` beside evidence of a run.
|
|
151
|
+
*
|
|
152
|
+
* The mirror of {@link expiredDeclarationViolation} for the third state. The
|
|
153
|
+
* numbers ARE the finding, so both are named: a caller debugging this needs to
|
|
154
|
+
* know which half contradicted the flag.
|
|
155
|
+
*/
|
|
156
|
+
/**
|
|
157
|
+
* A flag that quiets a zero, contradicted by the receipt's own evidence.
|
|
158
|
+
*
|
|
159
|
+
* **The flag is a parameter because the message names it.** It was hardcoded to
|
|
160
|
+
* `notRun`, and once `sourceEmpty` became contradictable too, a receipt claiming
|
|
161
|
+
* an empty source beside real evidence was told to "drop the notRun flag" — a
|
|
162
|
+
* flag nobody had set, and a remedy that cannot be applied. Four reviewers
|
|
163
|
+
* measured that on this branch's own headline scenario. ADR-009 rule 2: the
|
|
164
|
+
* finding names its cause, and the remedy remediates.
|
|
165
|
+
*/
|
|
166
|
+
export declare function contradictoryEvidenceViolation(examined: number, violations: number, flag?: 'notRun' | 'sourceEmpty'): ArchViolation;
|
|
167
|
+
//# sourceMappingURL=emitter-findings.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter-findings.d.ts","sourceRoot":"","sources":["../src/emitter-findings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAGnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,uEAAuE;AACvE,eAAO,MAAM,kBAAkB,uBAAuB,CAAA;AAEtD,kFAAkF;AAClF,eAAO,MAAM,6BAA6B,kCAAkC,CAAA;AAE5E;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,gCAAgC,CAAA;AAExE;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,8BAA8B,mCAAmC,CAAA;AAE9E;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,yBAAyB,CAAA;AAE1D;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,MAAM,CAM1C,CAAA;AAEF,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,SAAS,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAEvF;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,aAAa,CASpD;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAkBlD;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,IAAI,aAAa,CAU5D;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAO3E;AAED;;;;;;GAMG;AACH;;;;;;;;;GASG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,QAAQ,GAAG,aAAwB,GACxC,aAAa,CAqBf"}
|