@nielspeter/eess 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/README.md +3 -3
  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.d.ts +69 -4
  7. package/dist/baseline.d.ts.map +1 -1
  8. package/dist/baseline.js +119 -13
  9. package/dist/baseline.js.map +1 -1
  10. package/dist/cache-registry.d.ts +14 -0
  11. package/dist/cache-registry.d.ts.map +1 -0
  12. package/dist/cache-registry.js +37 -0
  13. package/dist/cache-registry.js.map +1 -0
  14. package/dist/cardinality.d.ts +35 -0
  15. package/dist/cardinality.d.ts.map +1 -0
  16. package/dist/cardinality.js +65 -0
  17. package/dist/cardinality.js.map +1 -0
  18. package/dist/check-options.d.ts +14 -0
  19. package/dist/check-options.d.ts.map +1 -1
  20. package/dist/comment-suppression.d.ts +60 -0
  21. package/dist/comment-suppression.d.ts.map +1 -0
  22. package/dist/comment-suppression.js +89 -0
  23. package/dist/comment-suppression.js.map +1 -0
  24. package/dist/condition.d.ts +6 -0
  25. package/dist/condition.d.ts.map +1 -1
  26. package/dist/correspondence-core.d.ts +35 -0
  27. package/dist/correspondence-core.d.ts.map +1 -0
  28. package/dist/correspondence-core.js +38 -0
  29. package/dist/correspondence-core.js.map +1 -0
  30. package/dist/correspondence.d.ts +27 -5
  31. package/dist/correspondence.d.ts.map +1 -1
  32. package/dist/correspondence.js +39 -5
  33. package/dist/correspondence.js.map +1 -1
  34. package/dist/dedupe-config-findings.d.ts +56 -0
  35. package/dist/dedupe-config-findings.d.ts.map +1 -0
  36. package/dist/dedupe-config-findings.js +74 -0
  37. package/dist/dedupe-config-findings.js.map +1 -0
  38. package/dist/define.d.ts +44 -2
  39. package/dist/define.d.ts.map +1 -1
  40. package/dist/define.js +45 -4
  41. package/dist/define.js.map +1 -1
  42. package/dist/diff-aware.d.ts +8 -0
  43. package/dist/diff-aware.d.ts.map +1 -1
  44. package/dist/diff-aware.js +11 -2
  45. package/dist/diff-aware.js.map +1 -1
  46. package/dist/diff-disclosure.d.ts +72 -0
  47. package/dist/diff-disclosure.d.ts.map +1 -0
  48. package/dist/diff-disclosure.js +110 -0
  49. package/dist/diff-disclosure.js.map +1 -0
  50. package/dist/disk-set.d.ts +27 -0
  51. package/dist/disk-set.d.ts.map +1 -0
  52. package/dist/disk-set.js +12 -0
  53. package/dist/disk-set.js.map +1 -0
  54. package/dist/edge-coverage.d.ts +96 -0
  55. package/dist/edge-coverage.d.ts.map +1 -0
  56. package/dist/edge-coverage.js +108 -0
  57. package/dist/edge-coverage.js.map +1 -0
  58. package/dist/errors.d.ts +25 -0
  59. package/dist/errors.d.ts.map +1 -1
  60. package/dist/errors.js +32 -0
  61. package/dist/errors.js.map +1 -1
  62. package/dist/execute-rule.d.ts +2 -1
  63. package/dist/execute-rule.d.ts.map +1 -1
  64. package/dist/execute-rule.js +38 -6
  65. package/dist/execute-rule.js.map +1 -1
  66. package/dist/format-github.d.ts.map +1 -1
  67. package/dist/format-github.js +37 -5
  68. package/dist/format-github.js.map +1 -1
  69. package/dist/format-json.d.ts +83 -1
  70. package/dist/format-json.d.ts.map +1 -1
  71. package/dist/format-json.js +70 -9
  72. package/dist/format-json.js.map +1 -1
  73. package/dist/format.d.ts +4 -2
  74. package/dist/format.d.ts.map +1 -1
  75. package/dist/format.js +41 -19
  76. package/dist/format.js.map +1 -1
  77. package/dist/glob-site.d.ts +232 -0
  78. package/dist/glob-site.d.ts.map +1 -0
  79. package/dist/glob-site.js +156 -0
  80. package/dist/glob-site.js.map +1 -0
  81. package/dist/identity-root.d.ts +55 -0
  82. package/dist/identity-root.d.ts.map +1 -0
  83. package/dist/identity-root.js +170 -0
  84. package/dist/identity-root.js.map +1 -0
  85. package/dist/index.d.ts +41 -3
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +33 -3
  88. package/dist/index.js.map +1 -1
  89. package/dist/owns-empty-discovery.d.ts +5 -0
  90. package/dist/owns-empty-discovery.d.ts.map +1 -0
  91. package/dist/owns-empty-discovery.js +77 -0
  92. package/dist/owns-empty-discovery.js.map +1 -0
  93. package/dist/path-universe.d.ts +44 -0
  94. package/dist/path-universe.d.ts.map +1 -0
  95. package/dist/path-universe.js +21 -0
  96. package/dist/path-universe.js.map +1 -0
  97. package/dist/predicate.d.ts +33 -0
  98. package/dist/predicate.d.ts.map +1 -1
  99. package/dist/preset-dispatch.d.ts +19 -0
  100. package/dist/preset-dispatch.d.ts.map +1 -1
  101. package/dist/preset-dispatch.js +43 -3
  102. package/dist/preset-dispatch.js.map +1 -1
  103. package/dist/project-relative.d.ts +25 -0
  104. package/dist/project-relative.d.ts.map +1 -0
  105. package/dist/project-relative.js +54 -0
  106. package/dist/project-relative.js.map +1 -0
  107. package/dist/report.d.ts +11 -5
  108. package/dist/report.d.ts.map +1 -1
  109. package/dist/report.js +17 -0
  110. package/dist/report.js.map +1 -1
  111. package/dist/rule-builder-like.d.ts +11 -0
  112. package/dist/rule-builder-like.d.ts.map +1 -0
  113. package/dist/rule-builder-like.js +2 -0
  114. package/dist/rule-builder-like.js.map +1 -0
  115. package/dist/rule-builder.d.ts +109 -84
  116. package/dist/rule-builder.d.ts.map +1 -1
  117. package/dist/rule-builder.js +202 -158
  118. package/dist/rule-builder.js.map +1 -1
  119. package/dist/rule-description.d.ts +33 -1
  120. package/dist/rule-description.d.ts.map +1 -1
  121. package/dist/rule-description.js +17 -1
  122. package/dist/rule-description.js.map +1 -1
  123. package/dist/rule-metadata.d.ts +20 -3
  124. package/dist/rule-metadata.d.ts.map +1 -1
  125. package/dist/selection-memo.d.ts +47 -0
  126. package/dist/selection-memo.d.ts.map +1 -0
  127. package/dist/selection-memo.js +68 -0
  128. package/dist/selection-memo.js.map +1 -0
  129. package/dist/shallow-clone.d.ts +20 -0
  130. package/dist/shallow-clone.d.ts.map +1 -0
  131. package/dist/shallow-clone.js +27 -0
  132. package/dist/shallow-clone.js.map +1 -0
  133. package/dist/stderr.d.ts +16 -0
  134. package/dist/stderr.d.ts.map +1 -0
  135. package/dist/stderr.js +73 -0
  136. package/dist/stderr.js.map +1 -0
  137. package/dist/terminal-builder.d.ts +209 -9
  138. package/dist/terminal-builder.d.ts.map +1 -1
  139. package/dist/terminal-builder.js +264 -20
  140. package/dist/terminal-builder.js.map +1 -1
  141. package/dist/type-guards.d.ts +38 -0
  142. package/dist/type-guards.d.ts.map +1 -0
  143. package/dist/type-guards.js +42 -0
  144. package/dist/type-guards.js.map +1 -0
  145. package/dist/unsuppressable.d.ts +54 -0
  146. package/dist/unsuppressable.d.ts.map +1 -0
  147. package/dist/unsuppressable.js +76 -0
  148. package/dist/unsuppressable.js.map +1 -0
  149. package/dist/vacuity-findings.d.ts +55 -0
  150. package/dist/vacuity-findings.d.ts.map +1 -0
  151. package/dist/vacuity-findings.js +124 -0
  152. package/dist/vacuity-findings.js.map +1 -0
  153. package/dist/violation.d.ts +152 -4
  154. package/dist/violation.d.ts.map +1 -1
  155. package/dist/violation.js +262 -1
  156. package/dist/violation.js.map +1 -1
  157. package/package.json +1 -1
package/dist/errors.js CHANGED
@@ -18,4 +18,36 @@ export class ArchRuleError extends Error {
18
18
  return this.#violations;
19
19
  }
20
20
  }
21
+ /**
22
+ * Is this an `ArchRuleError` — including one thrown by a DIFFERENT copy of this
23
+ * module?
24
+ *
25
+ * `instanceof` is an identity check, and a rule file does not necessarily load
26
+ * through the same module registry as the CLI that loads it. `load-rules.ts`
27
+ * uses jiti (bug 0074: a `.ts` rule file must load inside a `"type": "commonjs"`
28
+ * consumer project), and jiti keeps its own registry — so the `ArchRuleError`
29
+ * a self-executing rule file throws is a different class object from this one
30
+ * and `instanceof` is FALSE for an error that is, in every way that matters,
31
+ * an ArchRuleError.
32
+ *
33
+ * Measured: that made `check.ts` skip `ruleFileTruncated()`, so a rule file
34
+ * whose first rule threw reported the finding and said nothing about the rules
35
+ * after it that never ran — a silent gap in a red run, which is bug 0029
36
+ * reopened by the loader. The same hazard exists for any consumer with two
37
+ * copies of eess-ts on disk (a nested `node_modules`), where the loader is
38
+ * irrelevant.
39
+ *
40
+ * Structural, therefore: the `name` this class stamps in its constructor plus
41
+ * the `violations` array that is its whole reason to exist. Both are part of the
42
+ * documented public shape (`ArchViolation[]` on a thrown error), so matching on
43
+ * them is matching on the contract rather than on a coincidence.
44
+ */
45
+ export function isArchRuleError(error) {
46
+ if (error instanceof ArchRuleError)
47
+ return true;
48
+ return (error instanceof Error &&
49
+ error.name === 'ArchRuleError' &&
50
+ 'violations' in error &&
51
+ Array.isArray(error.violations));
52
+ }
21
53
  //# sourceMappingURL=errors.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,WAAW,CAAiB;IAErC,YAAY,UAA2B,EAAE,MAAe;QACtD,MAAM,OAAO,GAAG,yBAAyB,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAA;QAClH,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAC/C,KAAK,CAAC,GAAG,OAAO,GAAG,UAAU,EAAE,CAAC,CAAA;QAChC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;QAC3B,IAAI,CAAC,WAAW,GAAG,UAAU,CAAA;IAC/B,CAAC;IAED,4DAA4D;IAC5D,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAA;IACzB,CAAC;CACF"}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,WAAW,CAAiB;IAErC,YAAY,UAA2B,EAAE,MAAe;QACtD,MAAM,OAAO,GAAG,yBAAyB,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAA;QAClH,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QAC/C,KAAK,CAAC,GAAG,OAAO,GAAG,UAAU,EAAE,CAAC,CAAA;QAChC,IAAI,CAAC,IAAI,GAAG,eAAe,CAAA;QAC3B,IAAI,CAAC,WAAW,GAAG,UAAU,CAAA;IAC/B,CAAC;IAED,4DAA4D;IAC5D,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,WAAW,CAAA;IACzB,CAAC;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,KAAK,YAAY,aAAa;QAAE,OAAO,IAAI,CAAA;IAC/C,OAAO,CACL,KAAK,YAAY,KAAK;QACtB,KAAK,CAAC,IAAI,KAAK,eAAe;QAC9B,YAAY,IAAI,KAAK;QACrB,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAChC,CAAA;AACH,CAAC"}
@@ -6,7 +6,7 @@ import type { RuleMetadata } from './rule-metadata.js';
6
6
  * Shared across all builder types (RuleBuilder, SliceRuleBuilder,
7
7
  * SchemaRuleBuilder, ResolverRuleBuilder, PairFinalBuilder, SmellBuilder).
8
8
  */
9
- export interface ExecuteRuleContext {
9
+ interface ExecuteRuleContext {
10
10
  reason?: string;
11
11
  metadata?: RuleMetadata;
12
12
  exclusions?: (string | RegExp)[];
@@ -33,4 +33,5 @@ export declare function executeCheck(violations: ArchViolation[], ctx: ExecuteRu
33
33
  * Execute the terminal "warn" action: apply options, format, log to stderr.
34
34
  */
35
35
  export declare function executeWarn(violations: ArchViolation[], ctx: ExecuteRuleContext, options?: CheckOptions): void;
36
+ export {};
36
37
  //# sourceMappingURL=execute-rule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"execute-rule.d.ts","sourceRoot":"","sources":["../src/execute-rule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAQtD;;;;GAIG;AAEH,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,UAAU,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAA;IAChC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAC5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,aAAa,EAAE,EAC3B,GAAG,EAAE,kBAAkB,GACtB,aAAa,EAAE,CAoGjB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,aAAa,EAAE,EAC3B,GAAG,EAAE,kBAAkB,EACvB,OAAO,CAAC,EAAE,YAAY,GACrB,IAAI,CAeN;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,aAAa,EAAE,EAC3B,GAAG,EAAE,kBAAkB,EACvB,OAAO,CAAC,EAAE,YAAY,GACrB,IAAI,CAmBN"}
1
+ {"version":3,"file":"execute-rule.d.ts","sourceRoot":"","sources":["../src/execute-rule.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAWtD;;;;GAIG;AACH,UAAU,kBAAkB;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,YAAY,CAAA;IACvB,UAAU,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAA;IAChC,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;CAC5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,aAAa,EAAE,EAC3B,GAAG,EAAE,kBAAkB,GACtB,aAAa,EAAE,CA8GjB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,aAAa,EAAE,EAC3B,GAAG,EAAE,kBAAkB,EACvB,OAAO,CAAC,EAAE,YAAY,GACrB,IAAI,CAkBN;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,UAAU,EAAE,aAAa,EAAE,EAC3B,GAAG,EAAE,kBAAkB,EACvB,OAAO,CAAC,EAAE,YAAY,GACrB,IAAI,CA8BN"}
@@ -1,10 +1,14 @@
1
1
  import fs from 'node:fs';
2
+ import { severityFor } from './violation.js';
2
3
  import { ArchRuleError } from './errors.js';
3
4
  import { formatViolations } from './format.js';
4
5
  import { formatViolationsJson } from './format-json.js';
5
6
  import { formatViolationsGitHub } from './format-github.js';
6
7
  import { reportViolations } from './report.js';
7
8
  import { parseExclusionComments, isExcludedByComment } from './exclusion-comments.js';
9
+ import { writeStderr } from './stderr.js';
10
+ import { activeNotice } from './diff-disclosure.js';
11
+ import { recordCommentSuppression } from './comment-suppression.js';
8
12
  /**
9
13
  * Stamp rule metadata onto violations and apply the rule's exclusions.
10
14
  *
@@ -19,11 +23,16 @@ import { parseExclusionComments, isExcludedByComment } from './exclusion-comment
19
23
  */
20
24
  export function applyFilters(violations, ctx) {
21
25
  let result = violations;
22
- // Apply .excluding() chain exclusions
26
+ // Apply .excluding() chain exclusions — never against a bypassFilters
27
+ // (ADR-010 configuration) finding: it reports the rule's own instrument is
28
+ // broken, not a fault in what was examined, so an exclusion aimed at the
29
+ // latter cannot correctly suppress the former.
23
30
  const exclusions = ctx.exclusions ?? [];
24
31
  if (exclusions.length > 0) {
25
32
  const matchedPatterns = new Set();
26
33
  result = result.filter((v) => {
34
+ if (v.bypassFilters === true)
35
+ return true;
27
36
  // Match against element, file, or message — so that custom conditions
28
37
  // using createViolation() can be excluded by file path or message content,
29
38
  // not just by element name (which may be a generic AST node kind).
@@ -41,7 +50,7 @@ export function applyFilters(violations, ctx) {
41
50
  const silentIndices = ctx.silentIndices ?? new Set();
42
51
  exclusions.forEach((pattern, index) => {
43
52
  if (!matchedPatterns.has(index) && !silentIndices.has(index)) {
44
- console.warn(`[eess] Unused exclusion '${String(pattern)}' in rule '${ruleId}'. ` +
53
+ writeStderr(`[eess] Unused exclusion '${String(pattern)}' in rule '${ruleId}'. ` +
45
54
  `It matched zero violations — it may be stale after a rename.`);
46
55
  }
47
56
  });
@@ -94,7 +103,7 @@ export function applyFilters(violations, ctx) {
94
103
  const sourceText = fs.readFileSync(filePath, 'utf-8');
95
104
  const parseResult = parseExclusionComments(sourceText, filePath);
96
105
  for (const warning of parseResult.warnings) {
97
- console.warn(`[eess] ${warning.message}`);
106
+ writeStderr(`[eess] ${warning.message}`);
98
107
  }
99
108
  return parseResult.exclusions;
100
109
  }
@@ -107,7 +116,15 @@ export function applyFilters(violations, ctx) {
107
116
  }
108
117
  });
109
118
  if (allComments.length > 0) {
110
- result = result.filter((v) => !isExcludedByComment(v, allComments));
119
+ const ruleId = ctx.metadata.id;
120
+ result = result.filter((v) => {
121
+ if (v.bypassFilters === true)
122
+ return true;
123
+ const excluded = isExcludedByComment(v, allComments);
124
+ if (excluded)
125
+ recordCommentSuppression(ruleId, v.file);
126
+ return !excluded;
127
+ });
111
128
  }
112
129
  }
113
130
  return result;
@@ -121,7 +138,11 @@ export function executeCheck(violations, ctx, options) {
121
138
  filtered = options.baseline.filterNew(filtered);
122
139
  }
123
140
  if (options?.diff) {
141
+ const before = filtered.length;
124
142
  filtered = options.diff.filterToChanged(filtered);
143
+ const notice = activeNotice(before - filtered.length);
144
+ if (notice !== undefined)
145
+ writeStderr(`${notice}\n`);
125
146
  }
126
147
  if (filtered.length > 0) {
127
148
  // One emitter for both paths (plan 0070) — text/json/github, then throw.
@@ -138,18 +159,29 @@ export function executeWarn(violations, ctx, options) {
138
159
  filtered = options.baseline.filterNew(filtered);
139
160
  }
140
161
  if (options?.diff) {
162
+ const before = filtered.length;
141
163
  filtered = options.diff.filterToChanged(filtered);
164
+ const notice = activeNotice(before - filtered.length);
165
+ if (notice !== undefined)
166
+ writeStderr(`${notice}\n`);
142
167
  }
143
168
  if (filtered.length > 0) {
144
169
  if (options?.format === 'json') {
145
- console.warn(formatViolationsJson(filtered, ctx.reason));
170
+ writeStderr(formatViolationsJson(filtered, ctx.reason));
146
171
  }
147
172
  else if (options?.format === 'github') {
148
173
  process.stdout.write(formatViolationsGitHub(filtered, 'warning') + '\n');
149
174
  }
150
175
  else {
151
- console.warn(formatViolations(filtered, ctx.reason));
176
+ writeStderr(formatViolations(filtered, ctx.reason));
152
177
  }
153
178
  }
179
+ // `bypassFilters` outranks `.warn()` (see `severityFor`) — a config finding
180
+ // whose own text promises "not by .warn()" must still fail the build even
181
+ // though the rest of this rule's findings are legitimately warn-only.
182
+ const escalated = filtered.filter((v) => severityFor(v, 'warn') === 'error');
183
+ if (escalated.length > 0) {
184
+ throw new ArchRuleError(escalated, ctx.reason);
185
+ }
154
186
  }
155
187
  //# sourceMappingURL=execute-rule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"execute-rule.js","sourceRoot":"","sources":["../src/execute-rule.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"execute-rule.js","sourceRoot":"","sources":["../src/execute-rule.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"format-github.d.ts","sourceRoot":"","sources":["../src/format-github.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,aAAa,EAAE,EAC3B,QAAQ,GAAE,OAAO,GAAG,SAAmB,GACtC,MAAM,CAiBR;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD"}
1
+ {"version":3,"file":"format-github.d.ts","sourceRoot":"","sources":["../src/format-github.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAGnD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,aAAa,EAAE,EAC3B,QAAQ,GAAE,OAAO,GAAG,SAAmB,GACtC,MAAM,CAuCR;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjD"}
@@ -1,4 +1,5 @@
1
1
  import path from 'node:path';
2
+ import { remedyRepeatsMessage } from './violation.js';
2
3
  /**
3
4
  * Format violations as GitHub Actions annotation commands.
4
5
  *
@@ -20,17 +21,38 @@ export function formatViolationsGitHub(violations, severity = 'error') {
20
21
  const cwd = process.cwd();
21
22
  return violations
22
23
  .map((v) => {
23
- const relativePath = path.relative(cwd, v.file);
24
+ // Escaped as a PROPERTY: the runner splits the property list on commas,
25
+ // and a path containing one truncates the annotation onto a file that
26
+ // does not exist (measured). Same treatment as `title` two lines down.
27
+ const relativePath = escapeGitHubProperty(path.relative(cwd, v.file));
24
28
  const title = v.ruleId
25
29
  ? `Architecture Violation: ${v.ruleId}`
26
30
  : `Architecture Violation: ${v.rule}`;
27
31
  let message = v.because ? `${v.message} (${v.because})` : v.message;
28
- if (v.suggestion)
29
- message += `. Fix: ${v.suggestion}`;
32
+ // The annotation body opens with `message`, so a remedy identical to it is
33
+ // already there — see `remedyRepeatsMessage`.
34
+ //
35
+ // `join` rather than a bare `'. '`: this format is the one that
36
+ // concatenates the parts into a single line, and a message already ending
37
+ // in punctuation got a second period — `…(reading 'config').. Fix: …`,
38
+ // measured on the real CLI once a producer wrote a well-punctuated
39
+ // message. The rich and plain formats put `Fix:` on its own line and never
40
+ // had the problem.
41
+ const join = (text) => (/[.!?]$/.test(text) ? ' ' : '. ');
42
+ if (v.suggestion && !remedyRepeatsMessage(v))
43
+ message += `${join(message)}Fix: ${v.suggestion}`;
30
44
  if (v.docs)
31
- message += `. Docs: ${v.docs}`;
45
+ message += `${join(message)}Docs: ${v.docs}`;
32
46
  // GitHub annotation format: ::level file=path,line=N,title=T::message
33
- return `::${severity} file=${relativePath},line=${String(v.line)},title=${escapeGitHub(title)}::${escapeGitHub(message)}`;
47
+ //
48
+ // A configuration finding has no source location (file '', line 0), and
49
+ // `::error file=,line=0` is not a valid annotation — GitHub drops or
50
+ // misplaces it. Emit a run-level annotation instead, which renders on
51
+ // the workflow summary (plan 0070).
52
+ if (v.file === '') {
53
+ return `::${severity} title=${escapeGitHubProperty(title)}::${escapeGitHub(message)}`;
54
+ }
55
+ return `::${severity} file=${relativePath},line=${String(v.line)},title=${escapeGitHubProperty(title)}::${escapeGitHub(message)}`;
34
56
  })
35
57
  .join('\n');
36
58
  }
@@ -41,4 +63,14 @@ export function formatViolationsGitHub(violations, severity = 'error') {
41
63
  export function escapeGitHub(text) {
42
64
  return text.replace(/%/g, '%25').replace(/\r/g, '%0D').replace(/\n/g, '%0A');
43
65
  }
66
+ /**
67
+ * Property values (e.g. `title=`) additionally need `,` and `:` escaped —
68
+ * the workflow-command parser splits the property list on commas, and rule
69
+ * descriptions legitimately contain both (`{a,b}` globs, prose). The
70
+ * run-level annotation for locationless findings made `title` the sole
71
+ * identity carrier, which is what surfaced this.
72
+ */
73
+ function escapeGitHubProperty(text) {
74
+ return escapeGitHub(text).replace(/,/g, '%2C').replace(/:/g, '%3A');
75
+ }
44
76
  //# sourceMappingURL=format-github.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"format-github.js","sourceRoot":"","sources":["../src/format-github.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAG5B;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAA2B,EAC3B,WAAgC,OAAO;IAEvC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEzB,OAAO,UAAU;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;QAC/C,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM;YACpB,CAAC,CAAC,2BAA2B,CAAC,CAAC,MAAM,EAAE;YACvC,CAAC,CAAC,2BAA2B,CAAC,CAAC,IAAI,EAAE,CAAA;QACvC,IAAI,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;QACnE,IAAI,CAAC,CAAC,UAAU;YAAE,OAAO,IAAI,UAAU,CAAC,CAAC,UAAU,EAAE,CAAA;QACrD,IAAI,CAAC,CAAC,IAAI;YAAE,OAAO,IAAI,WAAW,CAAC,CAAC,IAAI,EAAE,CAAA;QAE1C,sEAAsE;QACtE,OAAO,KAAK,QAAQ,SAAS,YAAY,SAAS,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,YAAY,CAAC,KAAK,CAAC,KAAK,YAAY,CAAC,OAAO,CAAC,EAAE,CAAA;IAC3H,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AAC9E,CAAC"}
1
+ {"version":3,"file":"format-github.js","sourceRoot":"","sources":["../src/format-github.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAA2B,EAC3B,WAAgC,OAAO;IAEvC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAA;IAEzB,OAAO,UAAU;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,wEAAwE;QACxE,sEAAsE;QACtE,uEAAuE;QACvE,MAAM,YAAY,GAAG,oBAAoB,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;QACrE,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM;YACpB,CAAC,CAAC,2BAA2B,CAAC,CAAC,MAAM,EAAE;YACvC,CAAC,CAAC,2BAA2B,CAAC,CAAC,IAAI,EAAE,CAAA;QACvC,IAAI,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;QACnE,2EAA2E;QAC3E,8CAA8C;QAC9C,EAAE;QACF,gEAAgE;QAChE,0EAA0E;QAC1E,uEAAuE;QACvE,mEAAmE;QACnE,2EAA2E;QAC3E,mBAAmB;QACnB,MAAM,IAAI,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACzE,IAAI,CAAC,CAAC,UAAU,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC1C,OAAO,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,UAAU,EAAE,CAAA;QACnD,IAAI,CAAC,CAAC,IAAI;YAAE,OAAO,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,CAAA;QAExD,sEAAsE;QACtE,EAAE;QACF,wEAAwE;QACxE,qEAAqE;QACrE,sEAAsE;QACtE,oCAAoC;QACpC,IAAI,CAAC,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC;YAClB,OAAO,KAAK,QAAQ,UAAU,oBAAoB,CAAC,KAAK,CAAC,KAAK,YAAY,CAAC,OAAO,CAAC,EAAE,CAAA;QACvF,CAAC;QACD,OAAO,KAAK,QAAQ,SAAS,YAAY,SAAS,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,oBAAoB,CAAC,KAAK,CAAC,KAAK,YAAY,CAAC,OAAO,CAAC,EAAE,CAAA;IACnI,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;AAC9E,CAAC;AAED;;;;;;GAMG;AACH,SAAS,oBAAoB,CAAC,IAAY;IACxC,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AACrE,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import type { ArchViolation } from './violation.js';
2
+ import type { EdgeCoverage } from './edge-coverage.js';
2
3
  /**
3
4
  * Format violations as a JSON string.
4
5
  *
@@ -8,5 +9,86 @@ import type { ArchViolation } from './violation.js';
8
9
  * const violations = collectViolations(rule1, rule2)
9
10
  * console.log(formatViolationsJson(violations))
10
11
  */
11
- export declare function formatViolationsJson(violations: ArchViolation[], reason?: string): string;
12
+ /**
13
+ * The `check --format json` document, as a type.
14
+ *
15
+ * Exported because it is a **contract**, and an unexported contract is one a
16
+ * consumer can only discover by breaking. Without it a TypeScript consumer gets
17
+ * a runtime failure where they could have had a red build — and our own tests
18
+ * had to hand-roll the shape and cast through `unknown`, which is the kind of
19
+ * ADR-005 exemption that should not be needed against our own output.
20
+ *
21
+ * Changing these types is changing the agent contract. Treat a field removal or
22
+ * a narrowed union as breaking.
23
+ */
24
+ export interface ArchJsonViolation {
25
+ readonly rule: string;
26
+ readonly ruleId: string | null;
27
+ readonly severity: 'error' | 'warn';
28
+ readonly element: string;
29
+ /**
30
+ * The source file, or `null` when the finding has no location.
31
+ *
32
+ * For `kind: 'configuration'` this is the **rule file** that declared the
33
+ * rule — not the code under test — because the CLI attributes findings to
34
+ * their origin before rendering. It is `null` only for findings produced
35
+ * after that step. Never use it to detect a configuration finding; use `kind`.
36
+ */
37
+ readonly file: string | null;
38
+ /** `null` when there is no location; `1` on an attributed file means the file, not a position. */
39
+ readonly line: number | null;
40
+ /**
41
+ * What kind of finding this is, and therefore what to do about it.
42
+ *
43
+ * `'violation'` — the code is wrong. `'configuration'` — the **rule**
44
+ * enforces nothing, so editing the code cannot clear it.
45
+ *
46
+ * A consumer should treat an **unrecognised** value as `'violation'`: that
47
+ * keeps widening this union non-breaking, and configuration findings today
48
+ * already span four distinct remedies (a rule that matched nothing, a rule
49
+ * file that could not be evaluated, rules after a failure that never ran, and
50
+ * a stale baseline) which may earn their own names later.
51
+ */
52
+ readonly kind: 'violation' | 'configuration';
53
+ readonly message: string;
54
+ readonly because: string | null;
55
+ readonly suggestion: string | null;
56
+ readonly docs: string | null;
57
+ readonly codeFrame: string | null;
58
+ readonly measured: number | null;
59
+ }
60
+ /** One finding removed by an inline `// eess-exclude` comment. */
61
+ export interface ArchJsonSuppression {
62
+ readonly ruleId: string;
63
+ readonly file: string;
64
+ }
65
+ /** An allowlist rule that had subjects but tested no edges. */
66
+ export interface ArchJsonUntestedAllowlist {
67
+ readonly rule: string;
68
+ readonly subjects: number;
69
+ readonly edges: number;
70
+ }
71
+ /** The whole document emitted by `check --format json`. */
72
+ export interface ArchJsonReport {
73
+ readonly summary: {
74
+ readonly total: number;
75
+ readonly errors: number;
76
+ readonly warnings: number;
77
+ readonly reason: string | null;
78
+ };
79
+ readonly untestedAllowlists: readonly ArchJsonUntestedAllowlist[];
80
+ readonly commentSuppressed: readonly ArchJsonSuppression[];
81
+ readonly violations: readonly ArchJsonViolation[];
82
+ }
83
+ export declare function formatViolationsJson(violations: ArchViolation[], reason?: string,
84
+ /**
85
+ * Allowlist rules that tested no edges (bug 0015).
86
+ *
87
+ * **Passed in, not read from module state.** The first cut called
88
+ * `untestedRules()` here, which made a documented pure formatter impure: a
89
+ * per-rule JSON document in a vitest suite named rules from every earlier
90
+ * rule in the process, because nothing resets between them. Same input,
91
+ * different output depending on history.
92
+ */
93
+ untested?: readonly EdgeCoverage[]): string;
12
94
  //# sourceMappingURL=format-json.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format-json.d.ts","sourceRoot":"","sources":["../src/format-json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,aAAa,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAmBzF"}
1
+ {"version":3,"file":"format-json.d.ts","sourceRoot":"","sources":["../src/format-json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGtD;;;;;;;;GAQG;AACH;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAA;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB;;;;;;;OAOG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,kGAAkG;IAClG,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,eAAe,CAAA;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAED,kEAAkE;AAClE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,+DAA+D;AAC/D,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CACvB;AAED,2DAA2D;AAC3D,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE;QAChB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;QACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;QACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;QACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;KAC/B,CAAA;IACD,QAAQ,CAAC,kBAAkB,EAAE,SAAS,yBAAyB,EAAE,CAAA;IACjE,QAAQ,CAAC,iBAAiB,EAAE,SAAS,mBAAmB,EAAE,CAAA;IAC1D,QAAQ,CAAC,UAAU,EAAE,SAAS,iBAAiB,EAAE,CAAA;CAClD;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,aAAa,EAAE,EAC3B,MAAM,CAAC,EAAE,MAAM;AACf;;;;;;;;GAQG;AACH,QAAQ,GAAE,SAAS,YAAY,EAAO,GACrC,MAAM,CA8ER"}
@@ -1,28 +1,89 @@
1
+ import { commentSuppressions } from './comment-suppression.js';
2
+ export function formatViolationsJson(violations, reason,
1
3
  /**
2
- * Format violations as a JSON string.
4
+ * Allowlist rules that tested no edges (bug 0015).
3
5
  *
4
- * Useful for CI pipelines, custom dashboards, or piping to other tools.
5
- *
6
- * @example
7
- * const violations = collectViolations(rule1, rule2)
8
- * console.log(formatViolationsJson(violations))
6
+ * **Passed in, not read from module state.** The first cut called
7
+ * `untestedRules()` here, which made a documented pure formatter impure: a
8
+ * per-rule JSON document in a vitest suite named rules from every earlier
9
+ * rule in the process, because nothing resets between them. Same input,
10
+ * different output depending on history.
9
11
  */
10
- export function formatViolationsJson(violations, reason) {
12
+ untested = []) {
13
+ const errors = violations.filter((v) => (v.severity ?? 'error') === 'error').length;
11
14
  const output = {
12
15
  summary: {
13
16
  total: violations.length,
17
+ errors,
18
+ warnings: violations.length - errors,
14
19
  reason: reason ?? null,
15
20
  },
21
+ // Bug 0015: an allowlist constrains edges, so a subject with none passes
22
+ // whatever the allowlist says. Reported rather than failed — for the `only*`
23
+ // family zero edges is maximal compliance, and only the reader can tell a
24
+ // dependency-free module from a rule that certified nothing. Always present
25
+ // (an empty array, not omitted) so a consumer can distinguish "none" from
26
+ // "this version does not report it".
27
+ untestedAllowlists: untested.map((c) => ({
28
+ rule: c.rule,
29
+ subjects: c.subjects,
30
+ edges: c.edges,
31
+ })),
32
+ // What inline `// eess-exclude` comments removed from this report.
33
+ // Structural rather than prose, for the same reason `untestedAllowlists` is:
34
+ // the agent reading this document needs identities it can act on, not a
35
+ // sentence to grep. Always present — an empty array, not omitted — so a
36
+ // consumer can tell "nothing was suppressed" from "this version does not
37
+ // report it".
38
+ //
39
+ // Every other filter in the pipeline discloses itself; this one did not,
40
+ // which after bug 0041 made it the widest silent filter we ship.
41
+ commentSuppressed: commentSuppressions().map((c) => ({
42
+ ruleId: c.ruleId,
43
+ file: c.file,
44
+ })),
16
45
  violations: violations.map((v) => ({
17
46
  rule: v.rule,
18
47
  ruleId: v.ruleId ?? null,
48
+ severity: v.severity ?? 'error',
19
49
  element: v.element,
20
- file: v.file,
21
- line: v.line,
50
+ // `null`, not `''`/`1`, when there is no source location. A configuration
51
+ // finding reports that a RULE enforces nothing; it has no line, and saying
52
+ // `"file": "", "line": 1` states one that looks real (bug 0047). A human
53
+ // skims past it; an agent may open it or anchor an edit to it.
54
+ //
55
+ // `null` rather than omission, and consistent with the rest of this
56
+ // document — `ruleId`, `because`, `suggestion`, `docs` and `measured` all
57
+ // null when absent, so a consumer already handles the idiom here.
58
+ file: v.file === '' ? null : v.file,
59
+ line: v.file === '' ? null : v.line,
60
+ // What kind of finding this is, which drives what the reader should DO:
61
+ // `'violation'` — the code is wrong, edit the named file;
62
+ // `'configuration'` — the RULE enforces nothing, so editing the code
63
+ // cannot clear it. This distinction was absent from the payload entirely,
64
+ // so an agent could not tell them apart by any field.
65
+ //
66
+ // A string rather than a boolean, decided deliberately. There are twelve
67
+ // configuration-finding producers with materially different causes — an
68
+ // empty selector, a dead glob, a rule with no condition, a preset that
69
+ // discovered nothing — and someone will want to distinguish them. A
70
+ // boolean leaves nowhere to put that; adding a second overlapping field
71
+ // later is worse than one field with room in it. This is the agent
72
+ // contract, so the cost of the wrong shape is permanent.
73
+ //
74
+ // Not named after `bypassFilters`: the consumer cares what the finding
75
+ // IS, not which of our filters it happens to survive.
76
+ kind: v.bypassFilters === true ? 'configuration' : 'violation',
22
77
  message: v.message,
23
78
  because: v.because ?? null,
24
79
  suggestion: v.suggestion ?? null,
25
80
  docs: v.docs ?? null,
81
+ codeFrame: v.codeFrame ?? null,
82
+ // Bug 0012's measurement, on the wire. Without it the ratchet is
83
+ // machine-readable only inside the baseline file, and a dashboard wanting
84
+ // the number has to regex it back out of the message — which is the
85
+ // fragility bug 0012 was filed about.
86
+ measured: v.measured ?? null,
26
87
  })),
27
88
  };
28
89
  return JSON.stringify(output, null, 2);
@@ -1 +1 @@
1
- {"version":3,"file":"format-json.js","sourceRoot":"","sources":["../src/format-json.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAA2B,EAAE,MAAe;IAC/E,MAAM,MAAM,GAAG;QACb,OAAO,EAAE;YACP,KAAK,EAAE,UAAU,CAAC,MAAM;YACxB,MAAM,EAAE,MAAM,IAAI,IAAI;SACvB;QACD,UAAU,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACjC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI;YACxB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI;YAC1B,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI;YAChC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI;SACrB,CAAC,CAAC;KACJ,CAAA;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;AACxC,CAAC"}
1
+ {"version":3,"file":"format-json.js","sourceRoot":"","sources":["../src/format-json.ts"],"names":[],"mappings":"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"}
package/dist/format.d.ts CHANGED
@@ -18,8 +18,10 @@ export declare function formatViolations(violations: ArchViolation[], reason?: s
18
18
  /**
19
19
  * Format violations into a plain-text string (no ANSI codes).
20
20
  *
21
- * Used by ArchRuleError.message — error messages should be plain text
22
- * since they may be captured by test runners, serialized, or logged to files.
21
+ * Public export, for callers that aggregate violations themselves and need
22
+ * output free of ANSI codes — serialized, logged to a file, or embedded in
23
+ * another tool's report. `ArchRuleError.message` is a one-line summary and does
24
+ * not use this; the run's detail is written by `writeReport`.
23
25
  */
24
26
  export declare function formatViolationsPlain(violations: ArchViolation[], reason?: string): string;
25
27
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAInD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AA0CD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,aAAa,EAAE,EAC3B,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAYR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,aAAa,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAkB1F"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAKnD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAoDD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,aAAa,EAAE,EAC3B,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAYR;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,aAAa,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CA2B1F"}
package/dist/format.js CHANGED
@@ -1,28 +1,39 @@
1
+ import { remedyRepeatsMessage } from './violation.js';
1
2
  import { bold, red, cyan, dim } from './ansi.js';
2
3
  import path from 'node:path';
3
4
  /** Format a single violation into a rich terminal section. */
4
5
  function formatSingleViolation(v, index, total, cwd, showCodeFrames, reason) {
5
6
  const counter = bold(red(`Architecture Violation [${String(index + 1)} of ${String(total)}]`));
6
7
  const ruleLine = ` ${dim('Rule:')} ${v.rule}`;
7
- const relativePath = path.relative(cwd, v.file);
8
- const locationRef = cyan(relativePath + ':' + String(v.line));
9
- const location = ` ${locationRef} ${dim('—')} ${v.element}`;
8
+ // `message` is printed for BOTH shapes, and it used to be printed for neither
9
+ // — a located violation rendered only `file:line — element`, so the one
10
+ // sentence saying what is actually wrong was dropped from the default surface
11
+ // for every ordinary violation. Nothing failed when this was fixed, because
12
+ // nothing pinned it either way; `formatViolationsPlain` had always printed it,
13
+ // so the two formatters disagreed about what a violation IS.
14
+ //
15
+ // A config-level finding has no source location: `path.relative(cwd, '')`
16
+ // renders as the cwd and ':0' is noise, so it gets the message alone.
17
+ const location = v.file
18
+ ? ` ${v.message}\n ${cyan(path.relative(cwd, v.file) + ':' + String(v.line))} ${dim('—')} ${v.element}`
19
+ : ` ${v.message}`;
10
20
  const codeLine = showCodeFrames && v.codeFrame ? `\n${v.codeFrame}` : '';
11
21
  const whyText = v.because ?? reason;
12
22
  const whyLine = whyText ? ` ${dim('Why:')} ${whyText}` : '';
13
- const fixLine = v.suggestion ? ` ${dim('Fix:')} ${v.suggestion}` : '';
23
+ // Suppressed whenever the `location` slot above already printed this exact
24
+ // text, which is now BOTH shapes — see the note there. It used to be
25
+ // `!v.file && remedyRepeatsMessage(v)`, and that asymmetry was load-bearing
26
+ // and pinned, because a located violation did not render `message` at all: its
27
+ // `Fix:` line was the remedy's only appearance. Rendering `message` for both
28
+ // shapes removed the premise, and the `!v.file` half became a defect —
29
+ // measured, two occurrences of the remedy for a located finding whose
30
+ // suggestion is its message.
31
+ //
32
+ // So do not "restore" the asymmetry from the old comment: check whether this
33
+ // formatter still prints `message` for a located violation first.
34
+ const fixLine = v.suggestion && !remedyRepeatsMessage(v) ? ` ${dim('Fix:')} ${v.suggestion}` : '';
14
35
  const docsLine = v.docs ? ` ${dim('Docs:')} ${v.docs}` : '';
15
- // The message is the finding itself. It was omitted here for years, which is
16
- // survivable for a one-sided rule — `element` plus the rule description plus a
17
- // code frame usually carry the meaning — and not survivable for a two-sided
18
- // one, where `message` is the ONLY place the correspondence states which side
19
- // drifted. Measured before adding: `check:spec` rendered a ghost ADR row as
20
- // `Rule: correspondence / CLAUDE.md:24 — 099 / Why: …` and never said what was
21
- // wrong. Rendered in full, not just the first line: `correspondence()` folds
22
- // its per-side `suggest` remedy onto a continuation line, so truncating here
23
- // is what made that remedy invisible.
24
- const messageLine = ` ${dim('What:')} ${v.message.split('\n').join('\n ')}`;
25
- const parts = [counter, '', ruleLine, '', location, messageLine];
36
+ const parts = [counter, '', ruleLine, '', location];
26
37
  if (codeLine)
27
38
  parts.push(codeLine);
28
39
  if (whyLine)
@@ -51,8 +62,10 @@ export function formatViolations(violations, reason, options) {
51
62
  /**
52
63
  * Format violations into a plain-text string (no ANSI codes).
53
64
  *
54
- * Used by ArchRuleError.message — error messages should be plain text
55
- * since they may be captured by test runners, serialized, or logged to files.
65
+ * Public export, for callers that aggregate violations themselves and need
66
+ * output free of ANSI codes — serialized, logged to a file, or embedded in
67
+ * another tool's report. `ArchRuleError.message` is a one-line summary and does
68
+ * not use this; the run's detail is written by `writeReport`.
56
69
  */
57
70
  export function formatViolationsPlain(violations, reason) {
58
71
  if (violations.length === 0)
@@ -61,12 +74,21 @@ export function formatViolationsPlain(violations, reason) {
61
74
  const reasonLine = reason ? `\nReason: ${reason}` : '';
62
75
  const details = violations
63
76
  .map((v, i) => {
77
+ // A configuration finding has no source location — it reports that a RULE
78
+ // enforces nothing, not that a line is wrong — so it carries `file: ''`
79
+ // and a `line` that means nothing. Rendering it produced a bare `(:1)`
80
+ // (bug 0047). The rich formatter and the GitHub formatter
81
+ // (`format-github.ts:58`) both already special-case this; plain and JSON
82
+ // were the two that did not.
83
+ const where = v.file === '' ? '' : ` (${v.file}:${String(v.line)})`;
64
84
  const parts = [
65
- ` [${String(i + 1)}/${String(violations.length)}] ${v.element}: ${v.message} (${v.file}:${String(v.line)})`,
85
+ ` [${String(i + 1)}/${String(violations.length)}] ${v.element}: ${v.message}${where}`,
66
86
  ];
67
87
  if (v.codeFrame)
68
88
  parts.push(v.codeFrame);
69
- if (v.suggestion)
89
+ // This format always renders `message`, so a remedy identical to it is
90
+ // already shown — see `remedyRepeatsMessage`.
91
+ if (v.suggestion && !remedyRepeatsMessage(v))
70
92
  parts.push(` Fix: ${v.suggestion}`);
71
93
  return parts.join('\n');
72
94
  })