@nielspeter/eess 0.1.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 (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/dist/ansi.d.ts +7 -0
  4. package/dist/ansi.d.ts.map +1 -0
  5. package/dist/ansi.js +16 -0
  6. package/dist/ansi.js.map +1 -0
  7. package/dist/apply-fixes.d.ts +25 -0
  8. package/dist/apply-fixes.d.ts.map +1 -0
  9. package/dist/apply-fixes.js +52 -0
  10. package/dist/apply-fixes.js.map +1 -0
  11. package/dist/baseline-generator.d.ts +18 -0
  12. package/dist/baseline-generator.d.ts.map +1 -0
  13. package/dist/baseline-generator.js +29 -0
  14. package/dist/baseline-generator.js.map +1 -0
  15. package/dist/baseline.d.ts +83 -0
  16. package/dist/baseline.d.ts.map +1 -0
  17. package/dist/baseline.js +115 -0
  18. package/dist/baseline.js.map +1 -0
  19. package/dist/check-options.d.ts +47 -0
  20. package/dist/check-options.d.ts.map +1 -0
  21. package/dist/check-options.js +2 -0
  22. package/dist/check-options.js.map +1 -0
  23. package/dist/code-frame.d.ts +17 -0
  24. package/dist/code-frame.d.ts.map +1 -0
  25. package/dist/code-frame.js +32 -0
  26. package/dist/code-frame.js.map +1 -0
  27. package/dist/combinators.d.ts +55 -0
  28. package/dist/combinators.d.ts.map +1 -0
  29. package/dist/combinators.js +43 -0
  30. package/dist/combinators.js.map +1 -0
  31. package/dist/condition.d.ts +56 -0
  32. package/dist/condition.d.ts.map +1 -0
  33. package/dist/condition.js +2 -0
  34. package/dist/condition.js.map +1 -0
  35. package/dist/correspondence.d.ts +78 -0
  36. package/dist/correspondence.d.ts.map +1 -0
  37. package/dist/correspondence.js +127 -0
  38. package/dist/correspondence.js.map +1 -0
  39. package/dist/define.d.ts +41 -0
  40. package/dist/define.d.ts.map +1 -0
  41. package/dist/define.js +42 -0
  42. package/dist/define.js.map +1 -0
  43. package/dist/diff-aware.d.ts +37 -0
  44. package/dist/diff-aware.d.ts.map +1 -0
  45. package/dist/diff-aware.js +69 -0
  46. package/dist/diff-aware.js.map +1 -0
  47. package/dist/environment.d.ts +14 -0
  48. package/dist/environment.d.ts.map +1 -0
  49. package/dist/environment.js +20 -0
  50. package/dist/environment.js.map +1 -0
  51. package/dist/errors.d.ts +14 -0
  52. package/dist/errors.d.ts.map +1 -0
  53. package/dist/errors.js +21 -0
  54. package/dist/errors.js.map +1 -0
  55. package/dist/exclusion-comments.d.ts +52 -0
  56. package/dist/exclusion-comments.d.ts.map +1 -0
  57. package/dist/exclusion-comments.js +183 -0
  58. package/dist/exclusion-comments.js.map +1 -0
  59. package/dist/execute-rule.d.ts +31 -0
  60. package/dist/execute-rule.d.ts.map +1 -0
  61. package/dist/execute-rule.js +119 -0
  62. package/dist/execute-rule.js.map +1 -0
  63. package/dist/format-github.d.ts +25 -0
  64. package/dist/format-github.d.ts.map +1 -0
  65. package/dist/format-github.js +44 -0
  66. package/dist/format-github.js.map +1 -0
  67. package/dist/format-json.d.ts +12 -0
  68. package/dist/format-json.d.ts.map +1 -0
  69. package/dist/format-json.js +30 -0
  70. package/dist/format-json.js.map +1 -0
  71. package/dist/format.d.ts +25 -0
  72. package/dist/format.d.ts.map +1 -0
  73. package/dist/format.js +66 -0
  74. package/dist/format.js.map +1 -0
  75. package/dist/index.d.ts +42 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +40 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/matching.d.ts +31 -0
  80. package/dist/matching.d.ts.map +1 -0
  81. package/dist/matching.js +64 -0
  82. package/dist/matching.js.map +1 -0
  83. package/dist/predicate.d.ts +11 -0
  84. package/dist/predicate.d.ts.map +1 -0
  85. package/dist/predicate.js +2 -0
  86. package/dist/predicate.js.map +1 -0
  87. package/dist/preset-dispatch.d.ts +46 -0
  88. package/dist/preset-dispatch.d.ts.map +1 -0
  89. package/dist/preset-dispatch.js +48 -0
  90. package/dist/preset-dispatch.js.map +1 -0
  91. package/dist/report.d.ts +38 -0
  92. package/dist/report.d.ts.map +1 -0
  93. package/dist/report.js +45 -0
  94. package/dist/report.js.map +1 -0
  95. package/dist/rule-builder.d.ts +188 -0
  96. package/dist/rule-builder.d.ts.map +1 -0
  97. package/dist/rule-builder.js +323 -0
  98. package/dist/rule-builder.js.map +1 -0
  99. package/dist/rule-description.d.ts +12 -0
  100. package/dist/rule-description.d.ts.map +1 -0
  101. package/dist/rule-description.js +2 -0
  102. package/dist/rule-description.js.map +1 -0
  103. package/dist/rule-metadata.d.ts +17 -0
  104. package/dist/rule-metadata.d.ts.map +1 -0
  105. package/dist/rule-metadata.js +2 -0
  106. package/dist/rule-metadata.js.map +1 -0
  107. package/dist/silent-exclusion.d.ts +38 -0
  108. package/dist/silent-exclusion.d.ts.map +1 -0
  109. package/dist/silent-exclusion.js +30 -0
  110. package/dist/silent-exclusion.js.map +1 -0
  111. package/dist/terminal-builder.d.ts +83 -0
  112. package/dist/terminal-builder.d.ts.map +1 -0
  113. package/dist/terminal-builder.js +134 -0
  114. package/dist/terminal-builder.js.map +1 -0
  115. package/dist/violation.d.ts +51 -0
  116. package/dist/violation.d.ts.map +1 -0
  117. package/dist/violation.js +2 -0
  118. package/dist/violation.js.map +1 -0
  119. package/package.json +40 -0
@@ -0,0 +1,42 @@
1
+ export type { Predicate } from './predicate.js';
2
+ export type { Condition, ConditionContext } from './condition.js';
3
+ export { not, and, or } from './combinators.js';
4
+ export type { Matcher } from './combinators.js';
5
+ export type { ArchViolation, ArchFix } from './violation.js';
6
+ export { applyFixes } from './apply-fixes.js';
7
+ export type { ApplyResult } from './apply-fixes.js';
8
+ export { RuleBuilder } from './rule-builder.js';
9
+ export { TerminalBuilder } from './terminal-builder.js';
10
+ export { ArchRuleError } from './errors.js';
11
+ export type { RuleMetadata } from './rule-metadata.js';
12
+ export type { RuleDescription } from './rule-description.js';
13
+ export { generateCodeFrame } from './code-frame.js';
14
+ export type { CodeFrameOptions } from './code-frame.js';
15
+ export { formatViolations, formatViolationsPlain } from './format.js';
16
+ export type { FormatOptions } from './format.js';
17
+ export { formatViolationsJson } from './format-json.js';
18
+ export { formatViolationsGitHub } from './format-github.js';
19
+ export type { CheckOptions, OutputFormat, BaselineFilter, DiffFilterLike } from './check-options.js';
20
+ export { detectFormat, isCI } from './environment.js';
21
+ export { definePredicate, defineCondition } from './define.js';
22
+ export { dispatchRule, validateOverrides, throwIfViolations } from './preset-dispatch.js';
23
+ export { reportViolations, finishPreset } from './report.js';
24
+ export type { ReportMode, ReportOptions, PresetReportOptions } from './report.js';
25
+ export type { RuleSeverity, PresetBaseOptions } from './preset-dispatch.js';
26
+ export { matchSelections } from './matching.js';
27
+ export type { Pair, MatchResult, MatchOptions } from './matching.js';
28
+ export { correspondence, CorrespondenceBuilder } from './correspondence.js';
29
+ export type { Selection, ElementInfo, Direction, RelationSpec, CorrespondenceOptions, KeyBy, } from './correspondence.js';
30
+ export { applyFilters } from './execute-rule.js';
31
+ export { escapeGitHub } from './format-github.js';
32
+ export { hashViolation } from './baseline.js';
33
+ export { bold, red, dim, yellow, cyan, gray } from './ansi.js';
34
+ export { parseExclusionComments, isExcludedByComment } from './exclusion-comments.js';
35
+ export type { ExclusionComment, ExclusionWarning, ParseResult } from './exclusion-comments.js';
36
+ export { silent } from './silent-exclusion.js';
37
+ export type { SilentExclusion } from './silent-exclusion.js';
38
+ export { withBaseline, generateBaseline, Baseline } from './baseline.js';
39
+ export type { BaselineEntry, BaselineFile } from './baseline.js';
40
+ export { collectViolations } from './baseline-generator.js';
41
+ export { diffAware, DiffFilter } from './diff-aware.js';
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ // @nielspeter/eess — the dialect-independent kernel.
2
+ //
3
+ // RuleBuilder<T, P>, Predicate<T>, Condition<T>, the violation model, baseline
4
+ // and diff-aware machinery, exclusions, formatters, and the definePredicate /
5
+ // defineCondition extension points. Nothing here depends on ts-morph or any
6
+ // dialect-specific parser.
7
+ export { not, and, or } from './combinators.js';
8
+ export { applyFixes } from './apply-fixes.js';
9
+ // Rule builder, terminal builder, error
10
+ export { RuleBuilder } from './rule-builder.js';
11
+ export { TerminalBuilder } from './terminal-builder.js';
12
+ export { ArchRuleError } from './errors.js';
13
+ // Code frame & formatting
14
+ export { generateCodeFrame } from './code-frame.js';
15
+ export { formatViolations, formatViolationsPlain } from './format.js';
16
+ export { formatViolationsJson } from './format-json.js';
17
+ export { formatViolationsGitHub } from './format-github.js';
18
+ export { detectFormat, isCI } from './environment.js';
19
+ // Custom predicate/condition factories
20
+ export { definePredicate, defineCondition } from './define.js';
21
+ // Preset dispatch — generic per-rule severity/override infrastructure for presets
22
+ export { dispatchRule, validateOverrides, throwIfViolations } from './preset-dispatch.js';
23
+ export { reportViolations, finishPreset } from './report.js';
24
+ // Matching engine — shared by correspondence() and eess-ts's crossLayer
25
+ export { matchSelections } from './matching.js';
26
+ // Cross-validation — bind two element Selections and assert they correspond
27
+ export { correspondence, CorrespondenceBuilder } from './correspondence.js';
28
+ // Lower-level building blocks (used by dialects and covered by kernel tests)
29
+ export { applyFilters } from './execute-rule.js';
30
+ export { escapeGitHub } from './format-github.js';
31
+ export { hashViolation } from './baseline.js';
32
+ export { bold, red, dim, yellow, cyan, gray } from './ansi.js';
33
+ // Exclusions
34
+ export { parseExclusionComments, isExcludedByComment } from './exclusion-comments.js';
35
+ export { silent } from './silent-exclusion.js';
36
+ // Baseline & diff-aware
37
+ export { withBaseline, generateBaseline, Baseline } from './baseline.js';
38
+ export { collectViolations } from './baseline-generator.js';
39
+ export { diffAware, DiffFilter } from './diff-aware.js';
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,2BAA2B;AAK3B,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAA;AAK/C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAG7C,wCAAwC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAI3C,0BAA0B;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAEnD,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAErE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAI3D,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAErD,uCAAuC;AACvC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE9D,kFAAkF;AAClF,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACzF,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAI5D,wEAAwE;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAG/C,4EAA4E;AAC5E,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAU3E,6EAA6E;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAE9D,aAAa;AACb,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AAErF,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAG9C,wBAAwB;AACxB,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The single matching engine shared by `correspondence()` and `eess-ts`'s
3
+ * `crossLayer` — "given two element sets and how to match them, which pairs
4
+ * form and which elements are left unmatched." Extracting this removes the
5
+ * duplicate pair-matching implementations the two builders used to carry.
6
+ */
7
+ export interface Pair<L, R> {
8
+ readonly left: L;
9
+ readonly right: R;
10
+ }
11
+ export interface MatchResult<L, R> {
12
+ /** Every matched (left, right) pair. */
13
+ readonly pairs: Pair<L, R>[];
14
+ /** Left elements with no matching right. */
15
+ readonly leftUnmatched: L[];
16
+ /** Right elements with no matching left. */
17
+ readonly rightUnmatched: R[];
18
+ /** Left elements that matched more than one right (ambiguous correspondence). */
19
+ readonly leftAmbiguous: L[];
20
+ }
21
+ export interface MatchOptions<L, R> {
22
+ /** Arbitrary predicate — O(n×m) Cartesian matching. */
23
+ readonly matchBy?: (left: L, right: R) => boolean;
24
+ /** Join key per left element — O(n+m) indexed matching (with `rightKey`). */
25
+ readonly leftKey?: (element: L) => string;
26
+ /** Join key per right element. */
27
+ readonly rightKey?: (element: R) => string;
28
+ }
29
+ /** Match two element sets by key (fast) or predicate (fallback). */
30
+ export declare function matchSelections<L, R>(left: readonly L[], right: readonly R[], opts: MatchOptions<L, R>): MatchResult<L, R>;
31
+ //# sourceMappingURL=matching.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matching.d.ts","sourceRoot":"","sources":["../src/matching.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,IAAI,CAAC,CAAC,EAAE,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;IAChB,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAClB;AAED,MAAM,WAAW,WAAW,CAAC,CAAC,EAAE,CAAC;IAC/B,wCAAwC;IACxC,QAAQ,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;IAC5B,4CAA4C;IAC5C,QAAQ,CAAC,aAAa,EAAE,CAAC,EAAE,CAAA;IAC3B,4CAA4C;IAC5C,QAAQ,CAAC,cAAc,EAAE,CAAC,EAAE,CAAA;IAC5B,iFAAiF;IACjF,QAAQ,CAAC,aAAa,EAAE,CAAC,EAAE,CAAA;CAC5B;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,EAAE,CAAC;IAChC,uDAAuD;IACvD,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAA;IACjD,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,CAAA;IACzC,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,MAAM,CAAA;CAC3C;AAaD,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,CAAC,EAClC,IAAI,EAAE,SAAS,CAAC,EAAE,EAClB,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,IAAI,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GACvB,WAAW,CAAC,CAAC,EAAE,CAAC,CAAC,CA4CnB"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * The single matching engine shared by `correspondence()` and `eess-ts`'s
3
+ * `crossLayer` — "given two element sets and how to match them, which pairs
4
+ * form and which elements are left unmatched." Extracting this removes the
5
+ * duplicate pair-matching implementations the two builders used to carry.
6
+ */
7
+ function indexByKey(elements, key) {
8
+ const map = new Map();
9
+ for (const el of elements) {
10
+ const k = key(el);
11
+ const list = map.get(k);
12
+ if (list)
13
+ list.push(el);
14
+ else
15
+ map.set(k, [el]);
16
+ }
17
+ return map;
18
+ }
19
+ /** Match two element sets by key (fast) or predicate (fallback). */
20
+ export function matchSelections(left, right, opts) {
21
+ if (opts.matchBy) {
22
+ const matchBy = opts.matchBy;
23
+ const pairs = [];
24
+ const matchedLeft = new Set();
25
+ const matchedRight = new Set();
26
+ const leftMatchCount = new Map();
27
+ for (const l of left) {
28
+ for (const r of right) {
29
+ if (matchBy(l, r)) {
30
+ pairs.push({ left: l, right: r });
31
+ matchedLeft.add(l);
32
+ matchedRight.add(r);
33
+ leftMatchCount.set(l, (leftMatchCount.get(l) ?? 0) + 1);
34
+ }
35
+ }
36
+ }
37
+ return {
38
+ pairs,
39
+ leftUnmatched: left.filter((l) => !matchedLeft.has(l)),
40
+ rightUnmatched: right.filter((r) => !matchedRight.has(r)),
41
+ leftAmbiguous: left.filter((l) => (leftMatchCount.get(l) ?? 0) > 1),
42
+ };
43
+ }
44
+ const leftKey = opts.leftKey;
45
+ const rightKey = opts.rightKey;
46
+ if (!leftKey || !rightKey) {
47
+ throw new TypeError('matchSelections requires either matchBy or both leftKey and rightKey');
48
+ }
49
+ const rightByKey = indexByKey(right, rightKey);
50
+ const leftByKey = indexByKey(left, leftKey);
51
+ const pairs = [];
52
+ for (const l of left) {
53
+ for (const r of rightByKey.get(leftKey(l)) ?? []) {
54
+ pairs.push({ left: l, right: r });
55
+ }
56
+ }
57
+ return {
58
+ pairs,
59
+ leftUnmatched: left.filter((l) => (rightByKey.get(leftKey(l))?.length ?? 0) === 0),
60
+ rightUnmatched: right.filter((r) => (leftByKey.get(rightKey(r))?.length ?? 0) === 0),
61
+ leftAmbiguous: left.filter((l) => (rightByKey.get(leftKey(l))?.length ?? 0) > 1),
62
+ };
63
+ }
64
+ //# sourceMappingURL=matching.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"matching.js","sourceRoot":"","sources":["../src/matching.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * A predicate that tests whether an architectural element matches a condition.
3
+ * Used in `.that()` clauses to filter elements before rule evaluation.
4
+ */
5
+ export interface Predicate<T> {
6
+ /** Human-readable description for violation messages, e.g. "have name matching /^parse/" */
7
+ readonly description: string;
8
+ /** Returns true if the element matches this predicate. */
9
+ test(element: T): boolean;
10
+ }
11
+ //# sourceMappingURL=predicate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predicate.d.ts","sourceRoot":"","sources":["../src/predicate.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B,4FAA4F;IAC5F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,0DAA0D;IAC1D,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,OAAO,CAAA;CAC1B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=predicate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predicate.js","sourceRoot":"","sources":["../src/predicate.ts"],"names":[],"mappings":""}
@@ -0,0 +1,46 @@
1
+ import type { ArchViolation } from './violation.js';
2
+ import type { RuleMetadata } from './rule-metadata.js';
3
+ import { type PresetReportOptions } from './report.js';
4
+ /** Per-rule severity within a preset. */
5
+ export type RuleSeverity = 'error' | 'warn' | 'off';
6
+ /**
7
+ * Base options every preset accepts: per-rule severity overrides, plus the
8
+ * reporting controls (`report` / `format`) from ADR-008 — so every preset that
9
+ * extends this can `{ report: 'return' }` without its own plumbing.
10
+ */
11
+ export interface PresetBaseOptions extends PresetReportOptions {
12
+ overrides?: Record<string, RuleSeverity>;
13
+ }
14
+ /**
15
+ * Anything with `.rule()` and `.violations()` — works with both
16
+ * `RuleBuilder<T, P>` and `TerminalBuilder` hierarchies, across all dialects.
17
+ */
18
+ interface Dispatchable {
19
+ rule(m: RuleMetadata): {
20
+ violations(): ArchViolation[];
21
+ };
22
+ violations(): ArchViolation[];
23
+ }
24
+ /**
25
+ * Dispatch a single rule within a preset.
26
+ *
27
+ * - `'off'`: skip entirely
28
+ * - `'warn'`: log violations to stderr, do not collect for aggregated throw
29
+ * - `'error'`: collect violations for aggregated throw
30
+ */
31
+ export declare function dispatchRule(builder: Dispatchable, ruleId: string, defaultSeverity: RuleSeverity, overrides: Record<string, RuleSeverity> | undefined): ArchViolation[];
32
+ /**
33
+ * Validate override keys against known rule IDs. Warns for unrecognized keys
34
+ * (likely typos).
35
+ */
36
+ export declare function validateOverrides(overrides: Record<string, RuleSeverity> | undefined, knownIds: string[]): void;
37
+ /**
38
+ * Emit (stderr text) and throw a single `ArchRuleError` with all aggregated
39
+ * violations, if any. Kept for backward compatibility; it is now `finishPreset`
40
+ * in the default `throw` mode. New presets take `PresetReportOptions` and call
41
+ * `finishPreset` so a caller can opt into `report: 'return'` / `--format json`
42
+ * (plan 0070).
43
+ */
44
+ export declare function throwIfViolations(violations: ArchViolation[]): void;
45
+ export {};
46
+ //# sourceMappingURL=preset-dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset-dispatch.d.ts","sourceRoot":"","sources":["../src/preset-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,EAAgB,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAEpE,yCAAyC;AACzC,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAA;AAEnD;;;;GAIG;AACH,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;CACzC;AAED;;;GAGG;AACH,UAAU,YAAY;IACpB,IAAI,CAAC,CAAC,EAAE,YAAY,GAAG;QAAE,UAAU,IAAI,aAAa,EAAE,CAAA;KAAE,CAAA;IACxD,UAAU,IAAI,aAAa,EAAE,CAAA;CAC9B;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,YAAY,EAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,SAAS,GAClD,aAAa,EAAE,CAcjB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,SAAS,EACnD,QAAQ,EAAE,MAAM,EAAE,GACjB,IAAI,CAWN;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,aAAa,EAAE,GAAG,IAAI,CAEnE"}
@@ -0,0 +1,48 @@
1
+ import { formatViolations } from './format.js';
2
+ import { finishPreset } from './report.js';
3
+ /**
4
+ * Dispatch a single rule within a preset.
5
+ *
6
+ * - `'off'`: skip entirely
7
+ * - `'warn'`: log violations to stderr, do not collect for aggregated throw
8
+ * - `'error'`: collect violations for aggregated throw
9
+ */
10
+ export function dispatchRule(builder, ruleId, defaultSeverity, overrides) {
11
+ const effective = overrides?.[ruleId] ?? defaultSeverity;
12
+ if (effective === 'off')
13
+ return [];
14
+ const violations = builder.rule({ id: ruleId }).violations();
15
+ if (effective === 'warn') {
16
+ if (violations.length > 0) {
17
+ console.warn(formatViolations(violations));
18
+ }
19
+ return [];
20
+ }
21
+ return violations;
22
+ }
23
+ /**
24
+ * Validate override keys against known rule IDs. Warns for unrecognized keys
25
+ * (likely typos).
26
+ */
27
+ export function validateOverrides(overrides, knownIds) {
28
+ if (!overrides)
29
+ return;
30
+ const knownSet = new Set(knownIds);
31
+ for (const key of Object.keys(overrides)) {
32
+ if (!knownSet.has(key)) {
33
+ console.warn(`[eess] Override key '${key}' does not match any rule in this preset. ` +
34
+ `Available rules: ${knownIds.join(', ')}`);
35
+ }
36
+ }
37
+ }
38
+ /**
39
+ * Emit (stderr text) and throw a single `ArchRuleError` with all aggregated
40
+ * violations, if any. Kept for backward compatibility; it is now `finishPreset`
41
+ * in the default `throw` mode. New presets take `PresetReportOptions` and call
42
+ * `finishPreset` so a caller can opt into `report: 'return'` / `--format json`
43
+ * (plan 0070).
44
+ */
45
+ export function throwIfViolations(violations) {
46
+ finishPreset(violations, { report: 'throw' });
47
+ }
48
+ //# sourceMappingURL=preset-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset-dispatch.js","sourceRoot":"","sources":["../src/preset-dispatch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,YAAY,EAA4B,MAAM,aAAa,CAAA;AAuBpE;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAqB,EACrB,MAAc,EACd,eAA6B,EAC7B,SAAmD;IAEnD,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC,MAAM,CAAC,IAAI,eAAe,CAAA;IACxD,IAAI,SAAS,KAAK,KAAK;QAAE,OAAO,EAAE,CAAA;IAElC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,UAAU,EAAE,CAAA;IAE5D,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAA;QAC5C,CAAC;QACD,OAAO,EAAE,CAAA;IACX,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,OAAO,CAAC,IAAI,CACV,wBAAwB,GAAG,4CAA4C;gBACrE,oBAAoB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5C,CAAA;QACH,CAAC;IACH,CAAC;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,38 @@
1
+ import type { ArchViolation } from './violation.js';
2
+ import type { OutputFormat } from './check-options.js';
3
+ /**
4
+ * How a preset delivers its violations (plan 0070, ADR-008):
5
+ * - `throw` (default) — emit, then throw `ArchRuleError` (today's behavior)
6
+ * - `return` — return the violations, emit nothing (the caller owns reporting)
7
+ * - `warn` — emit as a report, but do not throw
8
+ */
9
+ export type ReportMode = 'throw' | 'return' | 'warn';
10
+ /** Emission options shared by the reporter and the preset finisher. */
11
+ export interface ReportOptions {
12
+ /** Output format. Default `terminal` (rich text to stderr). */
13
+ readonly format?: OutputFormat;
14
+ /** Rationale threaded into the emitted output. */
15
+ readonly reason?: string;
16
+ }
17
+ /** Reporting controls a preset accepts, on top of its own options. */
18
+ export interface PresetReportOptions extends ReportOptions {
19
+ /** Delivery mode. Default `throw`. */
20
+ readonly report?: ReportMode;
21
+ }
22
+ /**
23
+ * The single place that knows how to *emit* violations — text (stderr), JSON,
24
+ * or GitHub annotations (stdout). No throw, no filtering, no control flow: just
25
+ * emission. `executeCheck` (the `.check()` path) and `finishPreset` (the preset
26
+ * path) both delegate here, so the two reporting paths can no longer diverge
27
+ * (plan 0070). Emits nothing for an empty set.
28
+ */
29
+ export declare function reportViolations(violations: ArchViolation[], options?: ReportOptions): void;
30
+ /**
31
+ * Finish a preset: deliver its aggregated violations per the requested mode
32
+ * (plan 0070). `throw` (default) emits then throws — backward-compatible with
33
+ * `throwIfViolations`; `return` hands the violations back untouched (the caller
34
+ * owns emission and control flow); `warn` emits without throwing. Always
35
+ * returns the violations, so a caller can inspect them regardless of mode.
36
+ */
37
+ export declare function finishPreset(violations: ArchViolation[], options?: PresetReportOptions): ArchViolation[];
38
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +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;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,aAAa,EAAE,EAAE,OAAO,GAAE,aAAkB,GAAG,IAAI,CAY/F;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,aAAa,EAAE,EAC3B,OAAO,GAAE,mBAAwB,GAChC,aAAa,EAAE,CAQjB"}
package/dist/report.js ADDED
@@ -0,0 +1,45 @@
1
+ import { ArchRuleError } from './errors.js';
2
+ import { formatViolations } from './format.js';
3
+ import { formatViolationsJson } from './format-json.js';
4
+ import { formatViolationsGitHub } from './format-github.js';
5
+ /**
6
+ * The single place that knows how to *emit* violations — text (stderr), JSON,
7
+ * or GitHub annotations (stdout). No throw, no filtering, no control flow: just
8
+ * emission. `executeCheck` (the `.check()` path) and `finishPreset` (the preset
9
+ * path) both delegate here, so the two reporting paths can no longer diverge
10
+ * (plan 0070). Emits nothing for an empty set.
11
+ */
12
+ export function reportViolations(violations, options = {}) {
13
+ if (violations.length === 0)
14
+ return;
15
+ const format = options.format ?? 'terminal';
16
+ if (format === 'json') {
17
+ process.stdout.write(formatViolationsJson(violations, options.reason) + '\n');
18
+ }
19
+ else if (format === 'github') {
20
+ process.stdout.write(formatViolationsGitHub(violations, 'error') + '\n');
21
+ }
22
+ else {
23
+ // Rich text to stderr — test runners show the plain-text Error message,
24
+ // while stderr carries the colorized Why/Fix/Docs output.
25
+ process.stderr.write(formatViolations(violations, options.reason) + '\n');
26
+ }
27
+ }
28
+ /**
29
+ * Finish a preset: deliver its aggregated violations per the requested mode
30
+ * (plan 0070). `throw` (default) emits then throws — backward-compatible with
31
+ * `throwIfViolations`; `return` hands the violations back untouched (the caller
32
+ * owns emission and control flow); `warn` emits without throwing. Always
33
+ * returns the violations, so a caller can inspect them regardless of mode.
34
+ */
35
+ export function finishPreset(violations, options = {}) {
36
+ const mode = options.report ?? 'throw';
37
+ if (mode === 'return')
38
+ return violations;
39
+ reportViolations(violations, options);
40
+ if (mode === 'throw' && violations.length > 0) {
41
+ throw new ArchRuleError(violations, options.reason);
42
+ }
43
+ return violations;
44
+ }
45
+ //# sourceMappingURL=report.js.map
@@ -0,0 +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"}
@@ -0,0 +1,188 @@
1
+ import type { Predicate } from './predicate.js';
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
+ import type { RuleDescription } from './rule-description.js';
7
+ import type { SilentExclusion } from './silent-exclusion.js';
8
+ import type { Selection, ElementInfo } from './correspondence.js';
9
+ /**
10
+ * Abstract base class for all rule builders.
11
+ *
12
+ * Concrete entry points (plans 0007+) extend this and:
13
+ * 1. Implement `getElements()` to return the elements to check
14
+ * 2. Add predicate methods that call `addPredicate()`
15
+ * 3. Add condition methods that call `addCondition()`
16
+ *
17
+ * The builder accumulates predicates and conditions. Nothing executes
18
+ * until a terminal method (`.check()`, `.warn()`, `.severity()`) is called.
19
+ */
20
+ export declare abstract class RuleBuilder<T, P = unknown> {
21
+ protected readonly project: P;
22
+ protected _predicates: Predicate<T>[];
23
+ protected _conditions: Condition<T>[];
24
+ protected _reason?: string;
25
+ protected _metadata?: RuleMetadata;
26
+ protected _exclusions: (string | RegExp)[];
27
+ protected _silentIndices: Set<number>;
28
+ protected _phase: 'predicate' | 'condition';
29
+ constructor(project: P);
30
+ /**
31
+ * Begin the predicate phase. Returns `this` for chaining.
32
+ * Purely a readability marker — `.that().haveNameMatching(...)` reads like English.
33
+ * Explicitly resets phase to 'predicate' — defensive against `.should().that()` misuse.
34
+ */
35
+ that(): this;
36
+ /**
37
+ * Add another predicate (AND). Returns `this` for chaining.
38
+ * `.that().extend('Base').and().resideInFolder('src/repos/**')` means both must match.
39
+ */
40
+ and(): this;
41
+ /**
42
+ * Begin the condition phase. Returns a forked builder for named selection safety.
43
+ * Creates a fresh builder with the same predicates but empty conditions.
44
+ * Sets phase to 'condition' so dual-use methods dispatch correctly.
45
+ */
46
+ should(): this;
47
+ /**
48
+ * Add another condition that must ALSO pass (AND).
49
+ * `.should().notContain(call('x')).andShould().notContain(call('y'))` means both must hold.
50
+ */
51
+ andShould(): this;
52
+ /**
53
+ * Plug in a custom predicate or condition.
54
+ *
55
+ * After `.that()` — pass a `Predicate<T>` to filter elements.
56
+ * After `.should()` — pass a `Condition<T>` to assert against filtered elements.
57
+ *
58
+ * Dispatch is structural: if the object has a `test` method it is treated
59
+ * as a predicate; if it has `evaluate` it is treated as a condition.
60
+ */
61
+ 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
+ /**
107
+ * Return the predicate-filtered elements as a labelled `Selection<T>` for
108
+ * cross-validation (`correspondence()`). The set is exactly the elements this
109
+ * rule would evaluate — the same filtering `.check()` applies.
110
+ *
111
+ * @param opts.label - human-readable name of this side ("diagram class")
112
+ * @param opts.identify - map an element to its message metadata (name/file/line)
113
+ */
114
+ select(opts: {
115
+ label: string;
116
+ identify: (element: T) => ElementInfo;
117
+ }): Selection<T>;
118
+ /**
119
+ * Return a structured description of this rule without executing it.
120
+ * Used by the `explain` CLI subcommand.
121
+ */
122
+ describeRule(): RuleDescription;
123
+ /**
124
+ * Execute the rule and return violations after exclusion filtering.
125
+ * Does not throw — use for programmatic access (presets, aggregation).
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.
131
+ *
132
+ * @param options - Optional baseline and diff filtering
133
+ */
134
+ check(options?: CheckOptions): void;
135
+ /**
136
+ * Execute the rule and log violations to stderr. Does not throw.
137
+ * Use for rules that should warn but not fail CI.
138
+ *
139
+ * @param options - Optional baseline and diff filtering
140
+ */
141
+ warn(options?: CheckOptions): void;
142
+ /**
143
+ * Execute the rule with the given severity.
144
+ * `.severity('error')` is equivalent to `.check()`.
145
+ * `.severity('warn')` is equivalent to `.warn()`.
146
+ */
147
+ severity(level: 'error' | 'warn'): void;
148
+ /**
149
+ * Register a predicate. Called by concrete builder methods like
150
+ * `.haveNameMatching()`, `.extend()`, etc.
151
+ */
152
+ protected addPredicate(predicate: Predicate<T>): this;
153
+ /**
154
+ * Register a condition. Called by concrete builder methods like
155
+ * `.notContain()`, `.notExist()`, etc.
156
+ */
157
+ protected addCondition(condition: Condition<T>): this;
158
+ /**
159
+ * Subclasses implement this to return the elements to check.
160
+ * Called lazily during `.check()` / `.warn()`.
161
+ */
162
+ protected abstract getElements(): T[];
163
+ /**
164
+ * Create a fork of this builder with the same predicates but empty conditions.
165
+ * Used by `.should()` to support named selections without mutation.
166
+ *
167
+ * Subclasses with additional constructor args MUST override this method.
168
+ */
169
+ protected fork(): this;
170
+ /**
171
+ * Build the rule description from predicates and conditions.
172
+ */
173
+ private buildRuleDescription;
174
+ /**
175
+ * Execute the full pipeline: filter elements with predicates,
176
+ * evaluate conditions, return violations.
177
+ */
178
+ private evaluate;
179
+ /**
180
+ * Build the `ConditionContext` passed to each condition.
181
+ *
182
+ * Subclasses with builder-specific context fields (e.g. `CallRuleBuilder`'s
183
+ * `_identifyByArgument`) override this to extend the base context.
184
+ * Call `super.buildConditionContext()` and spread the result.
185
+ */
186
+ protected buildConditionContext(): ConditionContext;
187
+ }
188
+ //# sourceMappingURL=rule-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-builder.d.ts","sourceRoot":"","sources":["../src/rule-builder.ts"],"names":[],"mappings":"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"}