@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.
Files changed (209) hide show
  1. package/README.md +97 -4
  2. package/dist/assertion-advice.d.ts +26 -0
  3. package/dist/assertion-advice.d.ts.map +1 -0
  4. package/dist/assertion-advice.js +29 -0
  5. package/dist/assertion-advice.js.map +1 -0
  6. package/dist/baseline-generator.d.ts +9 -0
  7. package/dist/baseline-generator.d.ts.map +1 -1
  8. package/dist/baseline-generator.js +9 -0
  9. package/dist/baseline-generator.js.map +1 -1
  10. package/dist/baseline.d.ts +69 -4
  11. package/dist/baseline.d.ts.map +1 -1
  12. package/dist/baseline.js +119 -13
  13. package/dist/baseline.js.map +1 -1
  14. package/dist/cache-registry.d.ts +14 -0
  15. package/dist/cache-registry.d.ts.map +1 -0
  16. package/dist/cache-registry.js +37 -0
  17. package/dist/cache-registry.js.map +1 -0
  18. package/dist/cardinality.d.ts +35 -0
  19. package/dist/cardinality.d.ts.map +1 -0
  20. package/dist/cardinality.js +80 -0
  21. package/dist/cardinality.js.map +1 -0
  22. package/dist/check-options.d.ts +14 -0
  23. package/dist/check-options.d.ts.map +1 -1
  24. package/dist/cli-config.d.ts +59 -0
  25. package/dist/cli-config.d.ts.map +1 -0
  26. package/dist/cli-config.js +84 -0
  27. package/dist/cli-config.js.map +1 -0
  28. package/dist/collect-result.d.ts +94 -0
  29. package/dist/collect-result.d.ts.map +1 -0
  30. package/dist/collect-result.js +142 -0
  31. package/dist/collect-result.js.map +1 -0
  32. package/dist/combinators.d.ts +14 -0
  33. package/dist/combinators.d.ts.map +1 -1
  34. package/dist/combinators.js +53 -16
  35. package/dist/combinators.js.map +1 -1
  36. package/dist/comment-suppression.d.ts +60 -0
  37. package/dist/comment-suppression.d.ts.map +1 -0
  38. package/dist/comment-suppression.js +89 -0
  39. package/dist/comment-suppression.js.map +1 -0
  40. package/dist/condition.d.ts +43 -0
  41. package/dist/condition.d.ts.map +1 -1
  42. package/dist/condition.js +48 -1
  43. package/dist/condition.js.map +1 -1
  44. package/dist/correspondence-core.d.ts +35 -0
  45. package/dist/correspondence-core.d.ts.map +1 -0
  46. package/dist/correspondence-core.js +38 -0
  47. package/dist/correspondence-core.js.map +1 -0
  48. package/dist/correspondence.d.ts +57 -5
  49. package/dist/correspondence.d.ts.map +1 -1
  50. package/dist/correspondence.js +74 -5
  51. package/dist/correspondence.js.map +1 -1
  52. package/dist/dedupe-config-findings.d.ts +56 -0
  53. package/dist/dedupe-config-findings.d.ts.map +1 -0
  54. package/dist/dedupe-config-findings.js +101 -0
  55. package/dist/dedupe-config-findings.js.map +1 -0
  56. package/dist/define.d.ts +44 -2
  57. package/dist/define.d.ts.map +1 -1
  58. package/dist/define.js +45 -4
  59. package/dist/define.js.map +1 -1
  60. package/dist/diff-aware.d.ts +8 -1
  61. package/dist/diff-aware.d.ts.map +1 -1
  62. package/dist/diff-aware.js +39 -9
  63. package/dist/diff-aware.js.map +1 -1
  64. package/dist/diff-disclosure.d.ts +72 -0
  65. package/dist/diff-disclosure.d.ts.map +1 -0
  66. package/dist/diff-disclosure.js +110 -0
  67. package/dist/diff-disclosure.js.map +1 -0
  68. package/dist/disk-set.d.ts +27 -0
  69. package/dist/disk-set.d.ts.map +1 -0
  70. package/dist/disk-set.js +12 -0
  71. package/dist/disk-set.js.map +1 -0
  72. package/dist/edge-coverage.d.ts +96 -0
  73. package/dist/edge-coverage.d.ts.map +1 -0
  74. package/dist/edge-coverage.js +108 -0
  75. package/dist/edge-coverage.js.map +1 -0
  76. package/dist/emitter-findings.d.ts +167 -0
  77. package/dist/emitter-findings.d.ts.map +1 -0
  78. package/dist/emitter-findings.js +237 -0
  79. package/dist/emitter-findings.js.map +1 -0
  80. package/dist/errors.d.ts +73 -0
  81. package/dist/errors.d.ts.map +1 -1
  82. package/dist/errors.js +93 -0
  83. package/dist/errors.js.map +1 -1
  84. package/dist/exclusion-comments.d.ts +36 -1
  85. package/dist/exclusion-comments.d.ts.map +1 -1
  86. package/dist/exclusion-comments.js +185 -37
  87. package/dist/exclusion-comments.js.map +1 -1
  88. package/dist/execute-rule.d.ts +11 -1
  89. package/dist/execute-rule.d.ts.map +1 -1
  90. package/dist/execute-rule.js +220 -11
  91. package/dist/execute-rule.js.map +1 -1
  92. package/dist/file-walk.d.ts +22 -0
  93. package/dist/file-walk.d.ts.map +1 -0
  94. package/dist/file-walk.js +51 -0
  95. package/dist/file-walk.js.map +1 -0
  96. package/dist/format-github.d.ts.map +1 -1
  97. package/dist/format-github.js +37 -5
  98. package/dist/format-github.js.map +1 -1
  99. package/dist/format-json.d.ts +96 -1
  100. package/dist/format-json.d.ts.map +1 -1
  101. package/dist/format-json.js +94 -9
  102. package/dist/format-json.js.map +1 -1
  103. package/dist/format.d.ts +4 -2
  104. package/dist/format.d.ts.map +1 -1
  105. package/dist/format.js +41 -19
  106. package/dist/format.js.map +1 -1
  107. package/dist/glob-site.d.ts +232 -0
  108. package/dist/glob-site.d.ts.map +1 -0
  109. package/dist/glob-site.js +156 -0
  110. package/dist/glob-site.js.map +1 -0
  111. package/dist/identity-root.d.ts +55 -0
  112. package/dist/identity-root.d.ts.map +1 -0
  113. package/dist/identity-root.js +170 -0
  114. package/dist/identity-root.js.map +1 -0
  115. package/dist/index.d.ts +18 -12
  116. package/dist/index.d.ts.map +1 -1
  117. package/dist/index.js +12 -10
  118. package/dist/index.js.map +1 -1
  119. package/dist/internal.d.ts +55 -0
  120. package/dist/internal.d.ts.map +1 -0
  121. package/dist/internal.js +92 -0
  122. package/dist/internal.js.map +1 -0
  123. package/dist/mask-non-comment.d.ts +49 -0
  124. package/dist/mask-non-comment.d.ts.map +1 -0
  125. package/dist/mask-non-comment.js +261 -0
  126. package/dist/mask-non-comment.js.map +1 -0
  127. package/dist/owns-empty-discovery.d.ts +5 -0
  128. package/dist/owns-empty-discovery.d.ts.map +1 -0
  129. package/dist/owns-empty-discovery.js +85 -0
  130. package/dist/owns-empty-discovery.js.map +1 -0
  131. package/dist/path-suffix.d.ts +57 -0
  132. package/dist/path-suffix.d.ts.map +1 -0
  133. package/dist/path-suffix.js +73 -0
  134. package/dist/path-suffix.js.map +1 -0
  135. package/dist/path-universe.d.ts +44 -0
  136. package/dist/path-universe.d.ts.map +1 -0
  137. package/dist/path-universe.js +21 -0
  138. package/dist/path-universe.js.map +1 -0
  139. package/dist/predicate.d.ts +45 -0
  140. package/dist/predicate.d.ts.map +1 -1
  141. package/dist/predicate.js +20 -1
  142. package/dist/predicate.js.map +1 -1
  143. package/dist/preset-dispatch.d.ts +6 -15
  144. package/dist/preset-dispatch.d.ts.map +1 -1
  145. package/dist/preset-dispatch.js +35 -17
  146. package/dist/preset-dispatch.js.map +1 -1
  147. package/dist/project-relative.d.ts +25 -0
  148. package/dist/project-relative.d.ts.map +1 -0
  149. package/dist/project-relative.js +54 -0
  150. package/dist/project-relative.js.map +1 -0
  151. package/dist/report.d.ts +42 -12
  152. package/dist/report.d.ts.map +1 -1
  153. package/dist/report.js +190 -14
  154. package/dist/report.js.map +1 -1
  155. package/dist/rule-builder-like.d.ts +17 -0
  156. package/dist/rule-builder-like.d.ts.map +1 -0
  157. package/dist/rule-builder-like.js +2 -0
  158. package/dist/rule-builder-like.js.map +1 -0
  159. package/dist/rule-builder.d.ts +124 -84
  160. package/dist/rule-builder.d.ts.map +1 -1
  161. package/dist/rule-builder.js +230 -181
  162. package/dist/rule-builder.js.map +1 -1
  163. package/dist/rule-description.d.ts +83 -1
  164. package/dist/rule-description.d.ts.map +1 -1
  165. package/dist/rule-description.js +75 -1
  166. package/dist/rule-description.js.map +1 -1
  167. package/dist/rule-metadata.d.ts +20 -3
  168. package/dist/rule-metadata.d.ts.map +1 -1
  169. package/dist/selection-memo.d.ts +45 -0
  170. package/dist/selection-memo.d.ts.map +1 -0
  171. package/dist/selection-memo.js +66 -0
  172. package/dist/selection-memo.js.map +1 -0
  173. package/dist/shallow-clone.d.ts +20 -0
  174. package/dist/shallow-clone.d.ts.map +1 -0
  175. package/dist/shallow-clone.js +27 -0
  176. package/dist/shallow-clone.js.map +1 -0
  177. package/dist/silent-exclusion.d.ts +12 -0
  178. package/dist/silent-exclusion.d.ts.map +1 -1
  179. package/dist/silent-exclusion.js +22 -0
  180. package/dist/silent-exclusion.js.map +1 -1
  181. package/dist/stderr.d.ts +16 -0
  182. package/dist/stderr.d.ts.map +1 -0
  183. package/dist/stderr.js +73 -0
  184. package/dist/stderr.js.map +1 -0
  185. package/dist/terminal-builder.d.ts +224 -10
  186. package/dist/terminal-builder.d.ts.map +1 -1
  187. package/dist/terminal-builder.js +336 -46
  188. package/dist/terminal-builder.js.map +1 -1
  189. package/dist/type-guards.d.ts +38 -0
  190. package/dist/type-guards.d.ts.map +1 -0
  191. package/dist/type-guards.js +42 -0
  192. package/dist/type-guards.js.map +1 -0
  193. package/dist/unsuppressable.d.ts +54 -0
  194. package/dist/unsuppressable.d.ts.map +1 -0
  195. package/dist/unsuppressable.js +76 -0
  196. package/dist/unsuppressable.js.map +1 -0
  197. package/dist/vacuity-findings.d.ts +49 -0
  198. package/dist/vacuity-findings.d.ts.map +1 -0
  199. package/dist/vacuity-findings.js +94 -0
  200. package/dist/vacuity-findings.js.map +1 -0
  201. package/dist/violation.d.ts +173 -4
  202. package/dist/violation.d.ts.map +1 -1
  203. package/dist/violation.js +262 -1
  204. package/dist/violation.js.map +1 -1
  205. package/dist/watch.d.ts +71 -0
  206. package/dist/watch.d.ts.map +1 -0
  207. package/dist/watch.js +129 -0
  208. package/dist/watch.js.map +1 -0
  209. package/package.json +6 -1
@@ -1,3 +1,4 @@
1
+ import { combineGlobs, negateGlobs } from './glob-site.js';
1
2
  export function not(input) {
2
3
  if (typeof input === 'function') {
3
4
  return (value) => !input(value);
@@ -5,39 +6,75 @@ export function not(input) {
5
6
  return {
6
7
  description: `not (${input.description})`,
7
8
  test: (element) => !input.test(element),
9
+ // Negation-normal-form push-down: `op` inverts as well as `polarity`.
10
+ // `not(unsatisfiable)` selects everything, so a negated site is
11
+ // over-selection rather than vacuity and can never be a fault — but a
12
+ // `not` nested inside the subtree flips it back, which is why this cannot
13
+ // just flip polarity. See `negateGlobs`.
14
+ globs: input.globs && negateGlobs(input.globs),
8
15
  };
9
16
  }
10
- function assertHomogeneous(inputs) {
17
+ /**
18
+ * Every input to `and()`/`or()` must be the same kind.
19
+ *
20
+ * `eess-ts` carried a byte-identical copy — `no-copy-paste` reported it at
21
+ * 100%, with only the noun in the message differing — so the noun is now the
22
+ * parameter and the check has one owner.
23
+ *
24
+ * A `TypeError` and not a filtered result: mixing an object predicate with a
25
+ * matcher function silently drops one kind (the implementations below filter
26
+ * by `typeof`), so a rule composed that way would narrow by half of what its
27
+ * author wrote and pass on the rest. Refusing at composition time is the only
28
+ * point where the mistake is still visible.
29
+ */
30
+ export function assertHomogeneous(inputs, matcherNoun = 'Matcher') {
11
31
  if (inputs.length === 0)
12
32
  return;
13
33
  const firstIsFunction = typeof inputs[0] === 'function';
14
34
  if (inputs.some((i) => (typeof i === 'function') !== firstIsFunction)) {
15
- throw new TypeError('Cannot mix Predicate objects and Matcher functions in and()/or()');
35
+ throw new TypeError(`Cannot mix Predicate objects and ${matcherNoun} functions in and()/or()`);
16
36
  }
17
37
  }
18
38
  export function and(...inputs) {
19
- assertHomogeneous(inputs);
20
- if (typeof inputs[0] === 'function') {
21
- const matchers = inputs.filter((input) => typeof input === 'function');
22
- const fn = (value) => matchers.every((m) => m(value));
23
- return fn;
24
- }
25
- const predicates = inputs.filter((input) => typeof input !== 'function');
26
- return {
27
- description: predicates.map((p) => p.description).join(' and '),
28
- test: (element) => predicates.every((p) => p.test(element)),
29
- };
39
+ return combine(inputs, 'all');
30
40
  }
31
41
  export function or(...inputs) {
42
+ return combine(inputs, 'any');
43
+ }
44
+ /**
45
+ * The body `and()` and `or()` share, with the quantifier as its one parameter.
46
+ *
47
+ * They were the same fifteen lines twice — `no-copy-paste` reported them at
48
+ * 98%, across both packages — but the reason to share them is that **three
49
+ * choices have to agree and nothing was making them**:
50
+ *
51
+ * | `op` | quantifier | joined with | glob node |
52
+ * | ------- | ---------- | ----------- | --------- |
53
+ * | `'all'` | `every` | `' and '` | `'all'` |
54
+ * | `'any'` | `some` | `' or '` | `'any'` |
55
+ *
56
+ * A conjunction selects nothing as soon as ONE input does; a disjunction only
57
+ * when EVERY input does. Pairing `some` with a `'all'` glob node — one edit
58
+ * away, in two files, when they were written out separately — reports a live
59
+ * selector as dead, which is a configuration finding against a rule that is
60
+ * fine. Deriving all three from `op` is what makes that unreachable.
61
+ *
62
+ * Inputs that declare no globs become retained opaque children rather than
63
+ * being dropped: dropping them is what would red `or(deadGlob, byName)`.
64
+ */
65
+ function combine(inputs, op) {
32
66
  assertHomogeneous(inputs);
67
+ const holds = (xs, f) => op === 'all' ? xs.every(f) : xs.some(f);
33
68
  if (typeof inputs[0] === 'function') {
34
69
  const matchers = inputs.filter((input) => typeof input === 'function');
35
- return (value) => matchers.some((m) => m(value));
70
+ const fn = (value) => holds(matchers, (m) => m(value));
71
+ return fn;
36
72
  }
37
73
  const predicates = inputs.filter((input) => typeof input !== 'function');
38
74
  return {
39
- description: predicates.map((p) => p.description).join(' or '),
40
- test: (element) => predicates.some((p) => p.test(element)),
75
+ description: predicates.map((p) => p.description).join(op === 'all' ? ' and ' : ' or '),
76
+ test: (element) => holds(predicates, (p) => p.test(element)),
77
+ globs: combineGlobs(op, predicates.map((p) => p.globs)),
41
78
  };
42
79
  }
43
80
  //# sourceMappingURL=combinators.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"combinators.js","sourceRoot":"","sources":["../src/combinators.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"combinators.js","sourceRoot":"","sources":["../src/combinators.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * What inline exclusion comments suppressed, said out loud.
3
+ *
4
+ * Every other filter in the pipeline discloses itself: `.excluding()` warns on
5
+ * a pattern that matched nothing (`execute-rule.ts`), diff-aware has
6
+ * `suppressionNotice`, the baseline has `unmatchedBaselineFinding`. The inline
7
+ * comment filter dropped violations and returned no count — and after
8
+ * [ts-archunit bug 0041](https://github.com/nielspeter/ts-archunit/blob/main/bugs/fixed/0041-an-exclusion-comment-is-a-no-op-for-most-conditions.md)
9
+ * made comments work for every condition family, it became the **widest** filter
10
+ * in the pipeline and the only silent one.
11
+ *
12
+ * `diff-disclosure.ts` states the principle this module inherits: *a run with
13
+ * every finding suppressed is indistinguishable from a clean run.* That is the
14
+ * false green ADR-008 exists to prevent, and it is worse here than for
15
+ * `--changed`, because a comment is written once and then read by nobody. The
16
+ * flag at least appears in the CI invocation.
17
+ *
18
+ * ## Identities, not a total (ADR-009 rule 4)
19
+ *
20
+ * The notice names **which rule in which file**, not just how many. A count is a
21
+ * snapshot: it moves when anything moves and tells the reader nothing about what
22
+ * to look at. `arch/no-cycles in src/legacy/gateway.ts` is an identity — it
23
+ * survives a renumbering and it is greppable.
24
+ *
25
+ * Capped, and the cap is disclosed rather than silent: a suite with hundreds of
26
+ * exemptions should not print hundreds of lines on every green run, but
27
+ * "and 47 more" is a very different statement from printing 3 and implying that
28
+ * is all of them.
29
+ *
30
+ * ## Why module state
31
+ *
32
+ * `applyFilters` runs once per rule and has no view of the run. This is the same
33
+ * shape `edge-coverage.ts` uses for the same reason: accumulate per rule, reset
34
+ * at the run boundary, render once. The two aggregating surfaces — CLI `check`
35
+ * and `checkAll` — both already call a reset and read a notice, so this hooks
36
+ * into a pattern that exists rather than inventing one.
37
+ *
38
+ * The per-rule terminals (`.check()` / `.warn()` on a single rule) have no run
39
+ * boundary, so they do not render it. Same honest limitation `diff-disclosure`
40
+ * documents and for the same reason: a per-rule count presented as a run total
41
+ * would be wrong, and 79 lines on a 79-rule suite is not disclosure.
42
+ */
43
+ /** Start a run. Both aggregating surfaces call this before evaluating. */
44
+ export declare function resetCommentSuppression(): void;
45
+ /** Record that a comment suppressed a finding. Called from `applyFilters`. */
46
+ export declare function recordCommentSuppression(ruleId: string, file: string): void;
47
+ /** Every suppression recorded this run, for `--format json`. */
48
+ export declare function commentSuppressions(): readonly {
49
+ ruleId: string;
50
+ file: string;
51
+ }[];
52
+ /**
53
+ * One or more lines naming what inline comments suppressed, or `undefined` when
54
+ * nothing was.
55
+ *
56
+ * `undefined` rather than `''` so a caller cannot print a blank line by
57
+ * forgetting to check — both call sites feed this straight to `writeStderr`.
58
+ */
59
+ export declare function commentSuppressionNotice(): string | undefined;
60
+ //# sourceMappingURL=comment-suppression.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment-suppression.d.ts","sourceRoot":"","sources":["../src/comment-suppression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAaH,0EAA0E;AAC1E,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAED,8EAA8E;AAC9E,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAE3E;AAED,gEAAgE;AAChE,wBAAgB,mBAAmB,IAAI,SAAS;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAEjF;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,GAAG,SAAS,CA0B7D"}
@@ -0,0 +1,89 @@
1
+ /**
2
+ * What inline exclusion comments suppressed, said out loud.
3
+ *
4
+ * Every other filter in the pipeline discloses itself: `.excluding()` warns on
5
+ * a pattern that matched nothing (`execute-rule.ts`), diff-aware has
6
+ * `suppressionNotice`, the baseline has `unmatchedBaselineFinding`. The inline
7
+ * comment filter dropped violations and returned no count — and after
8
+ * [ts-archunit bug 0041](https://github.com/nielspeter/ts-archunit/blob/main/bugs/fixed/0041-an-exclusion-comment-is-a-no-op-for-most-conditions.md)
9
+ * made comments work for every condition family, it became the **widest** filter
10
+ * in the pipeline and the only silent one.
11
+ *
12
+ * `diff-disclosure.ts` states the principle this module inherits: *a run with
13
+ * every finding suppressed is indistinguishable from a clean run.* That is the
14
+ * false green ADR-008 exists to prevent, and it is worse here than for
15
+ * `--changed`, because a comment is written once and then read by nobody. The
16
+ * flag at least appears in the CI invocation.
17
+ *
18
+ * ## Identities, not a total (ADR-009 rule 4)
19
+ *
20
+ * The notice names **which rule in which file**, not just how many. A count is a
21
+ * snapshot: it moves when anything moves and tells the reader nothing about what
22
+ * to look at. `arch/no-cycles in src/legacy/gateway.ts` is an identity — it
23
+ * survives a renumbering and it is greppable.
24
+ *
25
+ * Capped, and the cap is disclosed rather than silent: a suite with hundreds of
26
+ * exemptions should not print hundreds of lines on every green run, but
27
+ * "and 47 more" is a very different statement from printing 3 and implying that
28
+ * is all of them.
29
+ *
30
+ * ## Why module state
31
+ *
32
+ * `applyFilters` runs once per rule and has no view of the run. This is the same
33
+ * shape `edge-coverage.ts` uses for the same reason: accumulate per rule, reset
34
+ * at the run boundary, render once. The two aggregating surfaces — CLI `check`
35
+ * and `checkAll` — both already call a reset and read a notice, so this hooks
36
+ * into a pattern that exists rather than inventing one.
37
+ *
38
+ * The per-rule terminals (`.check()` / `.warn()` on a single rule) have no run
39
+ * boundary, so they do not render it. Same honest limitation `diff-disclosure`
40
+ * documents and for the same reason: a per-rule count presented as a run total
41
+ * would be wrong, and 79 lines on a 79-rule suite is not disclosure.
42
+ */
43
+ let suppressions = [];
44
+ /** How many identities the notice lists before summarising the remainder. */
45
+ const LISTED = 5;
46
+ /** Start a run. Both aggregating surfaces call this before evaluating. */
47
+ export function resetCommentSuppression() {
48
+ suppressions = [];
49
+ }
50
+ /** Record that a comment suppressed a finding. Called from `applyFilters`. */
51
+ export function recordCommentSuppression(ruleId, file) {
52
+ suppressions.push({ ruleId, file });
53
+ }
54
+ /** Every suppression recorded this run, for `--format json`. */
55
+ export function commentSuppressions() {
56
+ return suppressions;
57
+ }
58
+ /**
59
+ * One or more lines naming what inline comments suppressed, or `undefined` when
60
+ * nothing was.
61
+ *
62
+ * `undefined` rather than `''` so a caller cannot print a blank line by
63
+ * forgetting to check — both call sites feed this straight to `writeStderr`.
64
+ */
65
+ export function commentSuppressionNotice() {
66
+ if (suppressions.length === 0)
67
+ return undefined;
68
+ const total = suppressions.length;
69
+ const findings = total === 1 ? 'finding' : 'findings';
70
+ const head = `[eess] ${String(total)} ${findings} suppressed by inline ` +
71
+ `// eess-exclude comments. They are exemptions, not passes:`;
72
+ // Deduplicate by identity so one rule silenced ten times in one file reads as
73
+ // one line with a count, rather than ten lines that look like ten problems.
74
+ const byIdentity = new Map();
75
+ for (const s of suppressions) {
76
+ const key = `${s.ruleId} in ${s.file === '' ? '(no file)' : s.file}`;
77
+ byIdentity.set(key, (byIdentity.get(key) ?? 0) + 1);
78
+ }
79
+ const entries = [...byIdentity.entries()];
80
+ const shown = entries.slice(0, LISTED);
81
+ const lines = shown.map(([key, n]) => ` - ${key}${n > 1 ? ` (${String(n)}×)` : ''}`);
82
+ // The cap is stated. A silent truncation reads as "that is all of them", which
83
+ // is the same lie as no disclosure at all.
84
+ if (entries.length > LISTED) {
85
+ lines.push(` - …and ${String(entries.length - LISTED)} more`);
86
+ }
87
+ return [head, ...lines].join('\n');
88
+ }
89
+ //# sourceMappingURL=comment-suppression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment-suppression.js","sourceRoot":"","sources":["../src/comment-suppression.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAQH,IAAI,YAAY,GAAkB,EAAE,CAAA;AAEpC,6EAA6E;AAC7E,MAAM,MAAM,GAAG,CAAC,CAAA;AAEhB,0EAA0E;AAC1E,MAAM,UAAU,uBAAuB;IACrC,YAAY,GAAG,EAAE,CAAA;AACnB,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,wBAAwB,CAAC,MAAc,EAAE,IAAY;IACnE,YAAY,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;AACrC,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,mBAAmB;IACjC,OAAO,YAAY,CAAA;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB;IACtC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAE/C,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAA;IACjC,MAAM,QAAQ,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAA;IACrD,MAAM,IAAI,GACR,UAAU,MAAM,CAAC,KAAK,CAAC,IAAI,QAAQ,wBAAwB;QAC3D,4DAA4D,CAAA;IAE9D,8EAA8E;IAC9E,4EAA4E;IAC5E,MAAM,UAAU,GAAG,IAAI,GAAG,EAAkB,CAAA;IAC5C,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,MAAM,OAAO,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QACpE,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IACrD,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAA;IACzC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACrF,+EAA+E;IAC/E,2CAA2C;IAC3C,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,YAAY,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;IAChE,CAAC;IACD,OAAO,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpC,CAAC"}
@@ -1,4 +1,7 @@
1
1
  import type { ArchViolation } from './violation.js';
2
+ import { type CollectResult } from './collect-result.js';
3
+ import type { DeclaredGlobs } from './glob-site.js';
4
+ import type { RuleMetadata } from './rule-metadata.js';
2
5
  /**
3
6
  * Context passed to conditions during evaluation.
4
7
  *
@@ -32,6 +35,25 @@ export interface ConditionContext {
32
35
  */
33
36
  identifyByArgument?: number;
34
37
  }
38
+ /**
39
+ * The context a condition receives, projected from what the rule declared.
40
+ *
41
+ * Four of the five fields are read off `RuleMetadata` identically everywhere;
42
+ * only `rule` — the assembled English sentence — differs, because the kernel's
43
+ * `RuleBuilder` builds it from its own lists and `eess-ts`'s builds it from a
44
+ * `DeclaredRule`. The two bodies were 93% similar with that as the sole varying
45
+ * axis.
46
+ *
47
+ * Worth one owner beyond the duplicate count: this context is what a violation
48
+ * message is written from, so a field silently absent on one side of the family
49
+ * produces findings that name their rule in one dialect and not the other —
50
+ * exactly the "a violation must be actionable" clause of ADR-009.
51
+ */
52
+ export declare function conditionContextFrom(opts: {
53
+ metadata: RuleMetadata | undefined;
54
+ reason: string | undefined;
55
+ rule: string;
56
+ }): ConditionContext;
35
57
  /**
36
58
  * A condition that evaluates filtered elements and returns violations.
37
59
  *
@@ -52,5 +74,26 @@ export interface Condition<T> {
52
74
  * @returns Violations for elements that don't satisfy the condition
53
75
  */
54
76
  evaluate(elements: T[], context: ConditionContext): ArchViolation[];
77
+ /**
78
+ * The path globs this condition matches against, if any. See
79
+ * `Predicate.globs` — same contract, stamped with `position: 'condition'`.
80
+ */
81
+ readonly globs?: DeclaredGlobs;
55
82
  }
83
+ /**
84
+ * Run every condition over the selected elements, carrying the evidence.
85
+ *
86
+ * `examined` is the count the conditions were actually HANDED — not the
87
+ * pre-predicate population — and that distinction is the reason this is shared
88
+ * rather than written per builder. `graphql/resolver-rule-builder.ts` records
89
+ * what happened when two sibling builders derived it separately: one counted
90
+ * pre-predicate and the other post, and a chain whose `.that()` selected nothing
91
+ * reported 14 units examined, handed its conditions 0, and passed green with
92
+ * `diagnose()` silent. That is the fail-open cell ADR-009 exists to close.
93
+ *
94
+ * The zero-element early exit is stated rather than implied by an empty
95
+ * violation list (plan 0098): a receipt with `examined: 0` is the
96
+ * zero-evidence case, and ADR-010 wants it said out loud.
97
+ */
98
+ export declare function evaluateConditions<T>(elements: T[], conditions: readonly Condition<T>[], context: ConditionContext): CollectResult;
56
99
  //# sourceMappingURL=condition.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../src/condition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;;;;;;;;OAaG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAE5B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,aAAa,EAAE,CAAA;CACpE"}
1
+ {"version":3,"file":"condition.d.ts","sourceRoot":"","sources":["../src/condition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,qBAAqB,CAAA;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAA;IACZ,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;;;;;;;;;OAaG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAC5B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,QAAQ,EAAE,YAAY,GAAG,SAAS,CAAA;IAClC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,gBAAgB,CAQnB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAE5B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,gBAAgB,GAAG,aAAa,EAAE,CAAA;IAEnE;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAA;CAC/B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,QAAQ,EAAE,CAAC,EAAE,EACb,UAAU,EAAE,SAAS,SAAS,CAAC,CAAC,CAAC,EAAE,EACnC,OAAO,EAAE,gBAAgB,GACxB,aAAa,CAOf"}
package/dist/condition.js CHANGED
@@ -1,2 +1,49 @@
1
- export {};
1
+ import { collectResult } from './collect-result.js';
2
+ /**
3
+ * The context a condition receives, projected from what the rule declared.
4
+ *
5
+ * Four of the five fields are read off `RuleMetadata` identically everywhere;
6
+ * only `rule` — the assembled English sentence — differs, because the kernel's
7
+ * `RuleBuilder` builds it from its own lists and `eess-ts`'s builds it from a
8
+ * `DeclaredRule`. The two bodies were 93% similar with that as the sole varying
9
+ * axis.
10
+ *
11
+ * Worth one owner beyond the duplicate count: this context is what a violation
12
+ * message is written from, so a field silently absent on one side of the family
13
+ * produces findings that name their rule in one dialect and not the other —
14
+ * exactly the "a violation must be actionable" clause of ADR-009.
15
+ */
16
+ export function conditionContextFrom(opts) {
17
+ return {
18
+ rule: opts.rule,
19
+ because: opts.reason,
20
+ ruleId: opts.metadata?.id,
21
+ suggestion: opts.metadata?.suggestion,
22
+ docs: opts.metadata?.docs,
23
+ };
24
+ }
25
+ /**
26
+ * Run every condition over the selected elements, carrying the evidence.
27
+ *
28
+ * `examined` is the count the conditions were actually HANDED — not the
29
+ * pre-predicate population — and that distinction is the reason this is shared
30
+ * rather than written per builder. `graphql/resolver-rule-builder.ts` records
31
+ * what happened when two sibling builders derived it separately: one counted
32
+ * pre-predicate and the other post, and a chain whose `.that()` selected nothing
33
+ * reported 14 units examined, handed its conditions 0, and passed green with
34
+ * `diagnose()` silent. That is the fail-open cell ADR-009 exists to close.
35
+ *
36
+ * The zero-element early exit is stated rather than implied by an empty
37
+ * violation list (plan 0098): a receipt with `examined: 0` is the
38
+ * zero-evidence case, and ADR-010 wants it said out loud.
39
+ */
40
+ export function evaluateConditions(elements, conditions, context) {
41
+ if (elements.length === 0)
42
+ return collectResult([], { examined: 0 });
43
+ const violations = [];
44
+ for (const condition of conditions) {
45
+ violations.push(...condition.evaluate(elements, context));
46
+ }
47
+ return collectResult(violations, { examined: elements.length });
48
+ }
2
49
  //# sourceMappingURL=condition.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"condition.js","sourceRoot":"","sources":["../src/condition.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"condition.js","sourceRoot":"","sources":["../src/condition.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAsCvE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAIpC;IACC,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,CAAC,MAAM;QACpB,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,EAAE;QACzB,UAAU,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU;QACrC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI;KAC1B,CAAA;AACH,CAAC;AA+BD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAa,EACb,UAAmC,EACnC,OAAyB;IAEzB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,aAAa,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAA;IACpE,MAAM,UAAU,GAAoB,EAAE,CAAA;IACtC,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,UAAU,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAA;IAC3D,CAAC;IACD,OAAO,aAAa,CAAC,UAAU,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAA;AACjE,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * F2 — the shared set-difference + non-vacuity core.
3
+ *
4
+ * Pure and engine-neutral: it compares two key sets by **identity** and reports
5
+ * the asymmetric differences plus emptiness. It never counts and never decides
6
+ * policy — the caller chooses which differences are violations (coverage /
7
+ * orphans / bijection) and how to treat an empty side (non-vacuity).
8
+ *
9
+ * Both `correspondence()` (plan 0064+/proposal 017) and `crossLayer`'s
10
+ * existence check (`haveMatchingCounterpart`) build on this one function, so
11
+ * the two "every X has a matching Y" engines can never drift — and neither can
12
+ * silently green on an empty side (ADR-008).
13
+ */
14
+ /** The identity comparison of two key sets. No counts — sets of keys. */
15
+ export interface CorrespondenceResult {
16
+ /** Side-A keys with no match in side B — coverage gaps. */
17
+ readonly missing: readonly string[];
18
+ /** Side-B keys with no match in side A — orphans. */
19
+ readonly orphans: readonly string[];
20
+ /** True when side A contributed zero keys (non-vacuity signal). */
21
+ readonly aEmpty: boolean;
22
+ /** True when side B contributed zero keys (non-vacuity signal). */
23
+ readonly bEmpty: boolean;
24
+ }
25
+ /**
26
+ * Compare two key sets by identity.
27
+ *
28
+ * `missing` = A \ B (every A-key must have a B match for coverage).
29
+ * `orphans` = B \ A (every B-key must have an A source for no-orphans).
30
+ * Bijection holds iff both are empty. Duplicate keys within a side collapse
31
+ * (set semantics); order of `missing`/`orphans` follows first appearance in
32
+ * the respective input for stable, readable output.
33
+ */
34
+ export declare function setCorrespondence(aKeys: Iterable<string>, bKeys: Iterable<string>): CorrespondenceResult;
35
+ //# sourceMappingURL=correspondence-core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correspondence-core.d.ts","sourceRoot":"","sources":["../src/correspondence-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,yEAAyE;AACzE,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,qDAAqD;IACrD,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;IACxB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAA;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,EACvB,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GACtB,oBAAoB,CAetB"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * F2 — the shared set-difference + non-vacuity core.
3
+ *
4
+ * Pure and engine-neutral: it compares two key sets by **identity** and reports
5
+ * the asymmetric differences plus emptiness. It never counts and never decides
6
+ * policy — the caller chooses which differences are violations (coverage /
7
+ * orphans / bijection) and how to treat an empty side (non-vacuity).
8
+ *
9
+ * Both `correspondence()` (plan 0064+/proposal 017) and `crossLayer`'s
10
+ * existence check (`haveMatchingCounterpart`) build on this one function, so
11
+ * the two "every X has a matching Y" engines can never drift — and neither can
12
+ * silently green on an empty side (ADR-008).
13
+ */
14
+ /**
15
+ * Compare two key sets by identity.
16
+ *
17
+ * `missing` = A \ B (every A-key must have a B match for coverage).
18
+ * `orphans` = B \ A (every B-key must have an A source for no-orphans).
19
+ * Bijection holds iff both are empty. Duplicate keys within a side collapse
20
+ * (set semantics); order of `missing`/`orphans` follows first appearance in
21
+ * the respective input for stable, readable output.
22
+ */
23
+ export function setCorrespondence(aKeys, bKeys) {
24
+ const a = new Set(aKeys);
25
+ const b = new Set(bKeys);
26
+ const missing = [];
27
+ for (const key of a) {
28
+ if (!b.has(key))
29
+ missing.push(key);
30
+ }
31
+ const orphans = [];
32
+ for (const key of b) {
33
+ if (!a.has(key))
34
+ orphans.push(key);
35
+ }
36
+ return { missing, orphans, aEmpty: a.size === 0, bEmpty: b.size === 0 };
37
+ }
38
+ //# sourceMappingURL=correspondence-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correspondence-core.js","sourceRoot":"","sources":["../src/correspondence-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAcH;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAuB,EACvB,KAAuB;IAEvB,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IACxB,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;IAExB,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;QACpB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACpC,CAAC;IAED,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,KAAK,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;QACpB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACpC,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,CAAA;AACzE,CAAC"}
@@ -1,5 +1,5 @@
1
- import type { ArchViolation } from './violation.js';
2
- import { TerminalBuilder } from './terminal-builder.js';
1
+ import type { Predicate } from './predicate.js';
2
+ import { TerminalBuilder, type CollectResult } from './terminal-builder.js';
3
3
  /** How to identify an element for a two-sided violation message. */
4
4
  export interface ElementInfo {
5
5
  readonly name: string;
@@ -65,14 +65,66 @@ export declare class CorrespondenceBuilder<L, R> extends TerminalBuilder {
65
65
  should(): this;
66
66
  /** Chain another correspondence check (AND). */
67
67
  andShould(): this;
68
- /** Every element on the named side(s) has a counterpart on the other. */
68
+ /**
69
+ * Every element on the named side(s) has a counterpart on the other. An
70
+ * absence assertion — "no element lacks a counterpart" — so it's marked
71
+ * cardinality-exempt (see `assertsCardinality()`).
72
+ */
69
73
  beComplete(opts?: {
70
74
  direction?: Direction;
71
75
  }): this;
72
- /** Related endpoints on one side have matching relations on the other. */
76
+ /**
77
+ * Related endpoints on one side have matching relations on the other. Also
78
+ * an absence assertion — "no matched pair disagrees" — cardinality-exempt
79
+ * for the same reason `beComplete()` is.
80
+ */
73
81
  preserveRelations(spec: RelationSpec<L, R>): this;
74
- protected collectViolations(): ArchViolation[];
82
+ protected collectViolations(): CollectResult;
83
+ /**
84
+ * ADR-010: mirrors `RuleBuilder.assertsCardinality()` — per-check, not a
85
+ * blanket class-wide exemption. `beComplete()`/`preserveRelations()` mark
86
+ * the function they push via `marksAssertsCardinality()`, the same
87
+ * unforgeable registry `.notExist()` uses, because both are absence
88
+ * assertions ("no element lacks a counterpart", "no matched pair
89
+ * disagrees") that can never produce a violation from an empty side — an
90
+ * empty selection here is the correctly computed input (e.g. release-gate's
91
+ * "no packages changed this diff" on a clean tree), not a broken instrument.
92
+ * `.every()`, not `.some()`, for the same reason `RuleBuilder` uses it: a
93
+ * future check type that isn't an absence assertion must not silently
94
+ * inherit this exemption just because it's chained alongside one that is.
95
+ * An empty `_checks` list is not exempt — nothing was asserted yet.
96
+ */
97
+ protected assertsCardinality(): boolean;
75
98
  }
76
99
  /** Bind two selections into a correspondence. */
77
100
  export declare function correspondence<L, R>(opts: CorrespondenceOptions<L, R>): CorrespondenceBuilder<L, R>;
101
+ /**
102
+ * The elements a rule's predicates admit, as a `Selection`.
103
+ *
104
+ * A free function over the elements and the predicates rather than a method,
105
+ * for the same reason as `recordExclusions`: the two builders that need it sit
106
+ * in incompatible hierarchies — `eess-ts` has three levels where the kernel has
107
+ * two — so there is no common base to hold it. The two copies were
108
+ * byte-identical.
109
+ */
110
+ export declare function selectMatching<T>(elements: readonly T[], predicates: readonly Predicate<T>[], opts: {
111
+ label: string;
112
+ identify: (element: T) => ElementInfo;
113
+ }): Selection<T>;
114
+ /**
115
+ * The elements every predicate admits.
116
+ *
117
+ * The same conjunction as `selectMatching`, without a `Selection` around it —
118
+ * split out because `eess-ts`'s two GraphQL builders want the ARRAY, to memoise
119
+ * it as the one set both `check()` and `diagnose()` read (plan 0096). They each
120
+ * carried this filter inline, byte for byte, which `no-copy-paste` reported at
121
+ * 100%; folding them onto `selectMatching` was not open, since a `Selection`
122
+ * carries a label and an `identify` neither of them has at that point.
123
+ *
124
+ * Sharing it with `selectMatching` matters beyond the duplicate count: "the
125
+ * elements a rule selected" must be ONE answer, or a builder's `.select()` side
126
+ * and its condition side can disagree about which elements the predicates
127
+ * admitted — the divergence ADR-010 exists to make impossible.
128
+ */
129
+ export declare function matchingElements<T>(elements: readonly T[], predicates: readonly Predicate<T>[]): T[];
78
130
  //# sourceMappingURL=correspondence.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"correspondence.d.ts","sourceRoot":"","sources":["../src/correspondence.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"correspondence.d.ts","sourceRoot":"","sources":["../src/correspondence.ts"],"names":[],"mappings":"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"}