@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
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Resolve a cited path against a set of repo-relative paths.
3
+ *
4
+ * Two dialects had written this independently — `eess-md`'s `uniqueSuffix()`
5
+ * for `path:line` code pointers, and `eess-crossvalidate`'s `resolveFeature`
6
+ * for `.feature` citations. Same algorithm, same three-way answer, and after
7
+ * bug 0254 the same remedy text; bug 0257 is that duplication.
8
+ *
9
+ * **Why the kernel.** It is pure string work over a list of paths: no
10
+ * `ArchProject`, no ts-morph, nothing dialect-shaped. That is exactly
11
+ * `path-universe.ts`'s argument for living here, and
12
+ * [ADR-013](../../../adr/013-the-kernel-takes-the-fact-not-the-project.md)'s
13
+ * test is satisfied — the kernel takes the *fact* (a list of paths), not the
14
+ * project that produced it. It is family plumbing rather than public API, so it
15
+ * is exported from `internal.ts` (ADR-011).
16
+ *
17
+ * **What it deliberately does not decide.** Whether a `none` is broken, whether
18
+ * an `ambiguous` fails or warns, whether to consult external roots, what the
19
+ * message says — all of that is the caller's policy and differs between the two
20
+ * dialects for good reasons. This answers one question: *which path did they
21
+ * mean?*
22
+ */
23
+ /**
24
+ * Prepare a path set for repeated suffix lookups.
25
+ *
26
+ * Indexed by last segment, because the corpora this runs over resolve hundreds
27
+ * of citations against thousands of paths and a linear scan per citation was
28
+ * measurable in `eess-md`. The index is the reason this takes the whole set up
29
+ * front rather than being a plain two-argument function.
30
+ */
31
+ export function pathSuffixIndex(paths) {
32
+ // Deduplicated on entry, not assumed deduplicated. `all` was always a `Set`,
33
+ // but the per-segment lists used to push every element of the iterable — so a
34
+ // path appearing twice came back as `{ kind: 'ambiguous', files: [x, x] }`:
35
+ // one file reported as ambiguous with itself. Unreachable through today's two
36
+ // callers (both hand it a set or a filesystem walk), which is exactly why it
37
+ // would have waited for the third — the parameter is an `Iterable<string>`
38
+ // and nothing in the type says the caller must have deduplicated. Found by
39
+ // differential fuzzing across 20,000 cases; it was the only class of
40
+ // disagreement with the implementations this replaced.
41
+ const all = new Set(paths);
42
+ const byLastSegment = new Map();
43
+ for (const rel of all) {
44
+ const seg = rel.slice(rel.lastIndexOf('/') + 1);
45
+ const list = byLastSegment.get(seg);
46
+ if (list)
47
+ list.push(rel);
48
+ else
49
+ byLastSegment.set(seg, [rel]);
50
+ }
51
+ return {
52
+ resolve(wanted) {
53
+ // Exact first, and it wins outright. A citation that IS a real path is not
54
+ // ambiguous just because some longer path happens to end the same way —
55
+ // both dialects had this precedence already, and getting it backwards
56
+ // would turn correct citations into findings.
57
+ if (all.has(wanted))
58
+ return { kind: 'exact', file: wanted };
59
+ const seg = wanted.slice(wanted.lastIndexOf('/') + 1);
60
+ // Narrow by last segment, then confirm the FULL suffix on a `/` boundary:
61
+ // `x.ts` must not match `prefix-x.ts`, and `a/x.ts` must not match
62
+ // `b/aa/x.ts`.
63
+ const matches = (byLastSegment.get(seg) ?? []).filter((f) => f.endsWith('/' + wanted));
64
+ const only = matches[0];
65
+ if (matches.length === 1 && only !== undefined)
66
+ return { kind: 'unique', file: only };
67
+ if (matches.length > 1)
68
+ return { kind: 'ambiguous', files: matches };
69
+ return { kind: 'none' };
70
+ },
71
+ };
72
+ }
73
+ //# sourceMappingURL=path-suffix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-suffix.js","sourceRoot":"","sources":["../src/path-suffix.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAkBH;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,KAAuB;IACrD,6EAA6E;IAC7E,8EAA8E;IAC9E,4EAA4E;IAC5E,8EAA8E;IAC9E,6EAA6E;IAC7E,2EAA2E;IAC3E,2EAA2E;IAC3E,qEAAqE;IACrE,uDAAuD;IACvD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAS,KAAK,CAAC,CAAA;IAClC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAoB,CAAA;IACjD,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QAC/C,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACnC,IAAI,IAAI;YAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;;YACnB,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;IACpC,CAAC;IAED,OAAO;QACL,OAAO,CAAC,MAAc;YACpB,2EAA2E;YAC3E,wEAAwE;YACxE,sEAAsE;YACtE,8CAA8C;YAC9C,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;YAE3D,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;YACrD,0EAA0E;YAC1E,mEAAmE;YACnE,eAAe;YACf,MAAM,OAAO,GAAG,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAA;YACtF,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;YACvB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA;YACrF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;YACpE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;QACzB,CAAC;KACF,CAAA;AACH,CAAC"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Every path a glob could legitimately match in a project — the shape of the
3
+ * data, not how to build it.
4
+ *
5
+ * `PathUniverse` and `viewsFor` are pure: given the materialized string
6
+ * arrays, they need no `ArchProject`/ts-morph and stay in the kernel. Only
7
+ * the MATERIALIZER — walking a real project's source files into this shape —
8
+ * needs the dialect's own project type, and lives in that dialect (e.g.
9
+ * `packages/ts/src/core/path-universe.ts`'s `pathUniverse()`).
10
+ */
11
+ export interface PathUniverse {
12
+ /** Absolute paths of every file in the project. */
13
+ readonly filePaths: readonly string[];
14
+ /**
15
+ * Immediate parent directories only.
16
+ *
17
+ * Not all ancestors. A directory-matching predicate typically tests
18
+ * `filePath.substring(0, filePath.lastIndexOf('/'))` — the immediate
19
+ * parent and nothing else — so an all-ancestors set is not a harmless
20
+ * over-approximation, it is a false green: many ancestors are no file's
21
+ * direct parent, so a glob naming one of those can never select anything
22
+ * while an all-ancestors universe would call it satisfiable.
23
+ */
24
+ readonly parentDirs: readonly string[];
25
+ /** `filePaths` relative to the tsconfig directory, for message wording. */
26
+ readonly tsconfigRelativeFilePaths: readonly string[];
27
+ /** `parentDirs` relative to the tsconfig directory, for message wording. */
28
+ readonly tsconfigRelativeParentDirs: readonly string[];
29
+ }
30
+ /**
31
+ * The views a glob of this kind is matched against.
32
+ *
33
+ * Satisfiability is taken against the **union** — a glob is unsatisfiable
34
+ * only when nothing in any view matches it. That is deliberately generous,
35
+ * so that a wrong `base` cannot make a glob look unmatched by accident. It
36
+ * does NOT make `base` message-only: the anchor check in `syntacticFault`
37
+ * consults it directly, and an unanchored `base: 'absolute'` glob is dead
38
+ * regardless of what any view holds — see `GlobBase`.
39
+ *
40
+ * `import-target`, `specifier` and `literal` are not path kinds and have no
41
+ * views, so they can never be found unsatisfiable here.
42
+ */
43
+ export declare function viewsFor(universe: PathUniverse, kind: 'file-path' | 'parent-dir' | 'import-target' | 'specifier' | 'literal'): readonly (readonly string[])[];
44
+ //# sourceMappingURL=path-universe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-universe.d.ts","sourceRoot":"","sources":["../src/path-universe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,WAAW,YAAY;IAC3B,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAA;IACrC;;;;;;;;;OASG;IACH,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,2EAA2E;IAC3E,QAAQ,CAAC,yBAAyB,EAAE,SAAS,MAAM,EAAE,CAAA;IACrD,4EAA4E;IAC5E,QAAQ,CAAC,0BAA0B,EAAE,SAAS,MAAM,EAAE,CAAA;CACvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,WAAW,GAAG,YAAY,GAAG,eAAe,GAAG,WAAW,GAAG,SAAS,GAC3E,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAIhC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The views a glob of this kind is matched against.
3
+ *
4
+ * Satisfiability is taken against the **union** — a glob is unsatisfiable
5
+ * only when nothing in any view matches it. That is deliberately generous,
6
+ * so that a wrong `base` cannot make a glob look unmatched by accident. It
7
+ * does NOT make `base` message-only: the anchor check in `syntacticFault`
8
+ * consults it directly, and an unanchored `base: 'absolute'` glob is dead
9
+ * regardless of what any view holds — see `GlobBase`.
10
+ *
11
+ * `import-target`, `specifier` and `literal` are not path kinds and have no
12
+ * views, so they can never be found unsatisfiable here.
13
+ */
14
+ export function viewsFor(universe, kind) {
15
+ if (kind === 'file-path')
16
+ return [universe.filePaths, universe.tsconfigRelativeFilePaths];
17
+ if (kind === 'parent-dir')
18
+ return [universe.parentDirs, universe.tsconfigRelativeParentDirs];
19
+ return [];
20
+ }
21
+ //# sourceMappingURL=path-universe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-universe.js","sourceRoot":"","sources":["../src/path-universe.ts"],"names":[],"mappings":"AA8BA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,QAAQ,CACtB,QAAsB,EACtB,IAA4E;IAE5E,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,yBAAyB,CAAC,CAAA;IACzF,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,CAAC,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,0BAA0B,CAAC,CAAA;IAC5F,OAAO,EAAE,CAAA;AACX,CAAC"}
@@ -1,3 +1,4 @@
1
+ import type { DeclaredGlobs } from './glob-site.js';
1
2
  /**
2
3
  * A predicate that tests whether an architectural element matches a condition.
3
4
  * Used in `.that()` clauses to filter elements before rule evaluation.
@@ -7,5 +8,49 @@ export interface Predicate<T> {
7
8
  readonly description: string;
8
9
  /** Returns true if the element matches this predicate. */
9
10
  test(element: T): boolean;
11
+ /**
12
+ * The path globs this predicate matches against, if any.
13
+ *
14
+ * Declaring them lets the builder answer "can this rule ever have subjects?"
15
+ * without running it (plan 0069). Optional: a predicate that matches on
16
+ * something other than a path — a name, a decorator, a type — declares
17
+ * nothing and is treated as opaque, which is never a fault.
18
+ *
19
+ * Leaves are `DeclaredGlob`, so a predicate cannot claim a `position`; the
20
+ * builder stamps that on according to where the predicate was registered.
21
+ */
22
+ readonly globs?: DeclaredGlobs;
23
+ /**
24
+ * What to call this predicate's globs in a **configuration finding**, when
25
+ * the call the user made is not the call the predicate makes.
26
+ *
27
+ * Plan 0074, the second consequence of 0069's appendix item 4: presets must
28
+ * thread the option name into the site's origin (`shared: "…"`, not
29
+ * `resideInFolder("…")`), or the message names a call the user never made.
30
+ *
31
+ * A preset option is one name that expands to several predicates —
32
+ * `shared: ['…']` becomes `atPath()`, which is `or(resideInFile,
33
+ * resideInFolder)`. Measured before this existed, the finding read "This
34
+ * rule's selector reside in file matching … or reside in folder matching …
35
+ * can never match anything", naming two calls the author never wrote and
36
+ * omitting the option they did.
37
+ *
38
+ * Deliberately **not** `description`, which is overloaded: that renders the
39
+ * human-readable rule text, and rewriting it would change every violation
40
+ * message the preset produces, not just the configuration finding.
41
+ */
42
+ readonly originLabel?: string;
10
43
  }
44
+ /**
45
+ * Record a predicate on a builder, noting it if it arrived after `.should()`.
46
+ *
47
+ * A free function for the same reason as `recordExclusions` and
48
+ * `selectMatching`: the two builders sit in incompatible hierarchies, so there
49
+ * is no common base to hold a method. The copies were 94% similar and differed
50
+ * only in comment wording and braces — no behaviour.
51
+ *
52
+ * `phase` is read, never written: recording a misplaced predicate is a
53
+ * diagnosis, not a state change.
54
+ */
55
+ export declare function recordPredicate<T>(predicate: Predicate<T>, predicates: Predicate<T>[], misplaced: string[], phase: string): void;
11
56
  //# sourceMappingURL=predicate.d.ts.map
@@ -1 +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"}
1
+ {"version":3,"file":"predicate.d.ts","sourceRoot":"","sources":["../src/predicate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAEnD;;;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;IACzB;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAA;IAE9B;;;;;;;;;;;;;;;;;;OAkBG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAC/B,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,EACvB,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,EAC1B,SAAS,EAAE,MAAM,EAAE,EACnB,KAAK,EAAE,MAAM,GACZ,IAAI,CAON"}
package/dist/predicate.js CHANGED
@@ -1,2 +1,21 @@
1
- export {};
1
+ /**
2
+ * Record a predicate on a builder, noting it if it arrived after `.should()`.
3
+ *
4
+ * A free function for the same reason as `recordExclusions` and
5
+ * `selectMatching`: the two builders sit in incompatible hierarchies, so there
6
+ * is no common base to hold a method. The copies were 94% similar and differed
7
+ * only in comment wording and braces — no behaviour.
8
+ *
9
+ * `phase` is read, never written: recording a misplaced predicate is a
10
+ * diagnosis, not a state change.
11
+ */
12
+ export function recordPredicate(predicate, predicates, misplaced, phase) {
13
+ predicates.push(predicate);
14
+ // Bug 0155 state 2: a predicate-only method used after `.should()`. Dual-use
15
+ // methods dispatch to conditions in that phase and never reach here, so this is
16
+ // a filter written where an assertion was meant — the one state whose fix is
17
+ // "move it before .should()", not "add a condition".
18
+ if (phase === 'condition')
19
+ misplaced.push(predicate.description);
20
+ }
2
21
  //# sourceMappingURL=predicate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"predicate.js","sourceRoot":"","sources":["../src/predicate.ts"],"names":[],"mappings":""}
1
+ {"version":3,"file":"predicate.js","sourceRoot":"","sources":["../src/predicate.ts"],"names":[],"mappings":"AA8CA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAuB,EACvB,UAA0B,EAC1B,SAAmB,EACnB,KAAa;IAEb,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;IAC1B,6EAA6E;IAC7E,gFAAgF;IAChF,6EAA6E;IAC7E,qDAAqD;IACrD,IAAI,KAAK,KAAK,WAAW;QAAE,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;AAClE,CAAC"}
@@ -1,4 +1,4 @@
1
- import type { ArchViolation } from './violation.js';
1
+ import { type CollectResult } from './collect-result.js';
2
2
  import type { RuleMetadata } from './rule-metadata.js';
3
3
  import { type PresetReportOptions } from './report.js';
4
4
  /** Per-rule severity within a preset. */
@@ -15,11 +15,11 @@ export interface PresetBaseOptions extends PresetReportOptions {
15
15
  * Anything with `.rule()` and `.violations()` — works with both
16
16
  * `RuleBuilder<T, P>` and `TerminalBuilder` hierarchies, across all dialects.
17
17
  */
18
- interface Dispatchable {
18
+ export interface Dispatchable {
19
19
  rule(m: RuleMetadata): {
20
- violations(): ArchViolation[];
20
+ violations(): CollectResult;
21
21
  };
22
- violations(): ArchViolation[];
22
+ violations(): CollectResult;
23
23
  }
24
24
  /**
25
25
  * Dispatch a single rule within a preset.
@@ -30,19 +30,10 @@ interface Dispatchable {
30
30
  */
31
31
  export declare function dispatchRule(builder: Dispatchable, rule: string | (RuleMetadata & {
32
32
  id: string;
33
- }), defaultSeverity: RuleSeverity, overrides: Record<string, RuleSeverity> | undefined): ArchViolation[];
33
+ }), defaultSeverity: RuleSeverity, overrides: Record<string, RuleSeverity> | undefined): CollectResult;
34
34
  /**
35
35
  * Validate override keys against known rule IDs. Warns for unrecognized keys
36
36
  * (likely typos).
37
37
  */
38
- export declare function validateOverrides(overrides: Record<string, RuleSeverity> | undefined, knownIds: string[]): void;
39
- /**
40
- * Emit (stderr text) and throw a single `ArchRuleError` with all aggregated
41
- * violations, if any. Kept for backward compatibility; it is now `finishPreset`
42
- * in the default `throw` mode. New presets take `PresetReportOptions` and call
43
- * `finishPreset` so a caller can opt into `report: 'return'` / `--format json`
44
- * (plan 0070).
45
- */
46
- export declare function throwIfViolations(violations: ArchViolation[]): void;
47
- export {};
38
+ export declare function validateOverrides(overrides: Partial<Record<string, RuleSeverity>> | undefined, knownIds: readonly string[]): void;
48
39
  //# sourceMappingURL=preset-dispatch.d.ts.map
@@ -1 +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,IAAI,EAAE,MAAM,GAAG,CAAC,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9C,eAAe,EAAE,YAAY,EAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,SAAS,GAClD,aAAa,EAAE,CAmBjB;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"}
1
+ {"version":3,"file":"preset-dispatch.d.ts","sourceRoot":"","sources":["../src/preset-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAiB,MAAM,qBAAqB,CAAA;AAEvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEtD,OAAO,EAAE,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAA;AAGtD,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,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,CAAC,EAAE,YAAY,GAAG;QAAE,UAAU,IAAI,aAAa,CAAA;KAAE,CAAA;IACtD,UAAU,IAAI,aAAa,CAAA;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,YAAY,EACrB,IAAI,EAAE,MAAM,GAAG,CAAC,YAAY,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC,EAC9C,eAAe,EAAE,YAAY,EAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,SAAS,GAClD,aAAa,CA2Cf;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAM/B,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,GAAG,SAAS,EAC5D,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,IAAI,CAWN"}
@@ -1,5 +1,7 @@
1
+ import { collectResult } from './collect-result.js';
2
+ import { severityFor } from './violation.js';
1
3
  import { formatViolations } from './format.js';
2
- import { finishPreset } from './report.js';
4
+ import { writeStderr } from './stderr.js';
3
5
  /**
4
6
  * Dispatch a single rule within a preset.
5
7
  *
@@ -14,14 +16,34 @@ export function dispatchRule(builder, rule, defaultSeverity, overrides) {
14
16
  // agent`, not just the id.
15
17
  const meta = typeof rule === 'string' ? { id: rule } : rule;
16
18
  const effective = overrides?.[meta.id] ?? defaultSeverity;
17
- if (effective === 'off')
18
- return [];
19
+ if (effective === 'off') {
20
+ // A real, measured zero — and deliberately NOT `declaredEmpty`.
21
+ //
22
+ // ADR-014 §3, amended 2026-09-05: a declaration is one a caller MADE over a
23
+ // live instrument, never one eess infers from a configuration.
24
+ // `overrides: { id: 'off' }` is an instruction, and it is byte-identical
25
+ // whether the author meant "I have scoped this out" or "I turned this off to
26
+ // stop a finding" — eess is not positioned to tell those apart, so by
27
+ // ADR-013's rule it must not decide. Marking it declared here would mint,
28
+ // on the author's behalf, exactly the declaration `declaredEmptyFindings`
29
+ // refuses to let them write ("'off' deleted the rule, so the declaration
30
+ // about it is dead").
31
+ //
32
+ // The consequence is deliberate: a preset with every rule off sums to zero
33
+ // examined with no declaration, and the emitter reports it (bug 0261).
34
+ return collectResult([], { examined: 0, notRun: true });
35
+ }
19
36
  const violations = builder.rule(meta).violations();
20
37
  if (effective === 'warn') {
21
38
  if (violations.length > 0) {
22
- console.warn(formatViolations(violations));
39
+ writeStderr(formatViolations(violations));
23
40
  }
24
- return [];
41
+ // `bypassFilters` outranks a per-rule `overrides: { id: 'warn' }` — see
42
+ // `severityFor`. A config finding — a zero-examined rule, or a preset that
43
+ // constructed nothing — is `UNSUPPRESSABLE` by its own text; silently
44
+ // dropping it here just because its OWN rule was downgraded is exactly the
45
+ // suppression path that text promises does not exist.
46
+ return collectResult(violations.filter((v) => severityFor(v, 'warn') === 'error'), { examined: violations.examined });
25
47
  }
26
48
  return violations;
27
49
  }
@@ -29,25 +51,21 @@ export function dispatchRule(builder, rule, defaultSeverity, overrides) {
29
51
  * Validate override keys against known rule IDs. Warns for unrecognized keys
30
52
  * (likely typos).
31
53
  */
32
- export function validateOverrides(overrides, knownIds) {
54
+ export function validateOverrides(
55
+ // `Partial<Record<...>>` and `readonly`, widened from the narrower shapes this
56
+ // signature had, so `eess-ts`'s byte-identical copy could be deleted rather
57
+ // than kept for its types. Both are strictly more permissive: `Partial` admits
58
+ // an explicit `undefined` value, `readonly` admits a frozen list. No caller
59
+ // loses anything.
60
+ overrides, knownIds) {
33
61
  if (!overrides)
34
62
  return;
35
63
  const knownSet = new Set(knownIds);
36
64
  for (const key of Object.keys(overrides)) {
37
65
  if (!knownSet.has(key)) {
38
- console.warn(`[eess] Override key '${key}' does not match any rule in this preset. ` +
66
+ writeStderr(`[eess] Override key '${key}' does not match any rule in this preset. ` +
39
67
  `Available rules: ${knownIds.join(', ')}`);
40
68
  }
41
69
  }
42
70
  }
43
- /**
44
- * Emit (stderr text) and throw a single `ArchRuleError` with all aggregated
45
- * violations, if any. Kept for backward compatibility; it is now `finishPreset`
46
- * in the default `throw` mode. New presets take `PresetReportOptions` and call
47
- * `finishPreset` so a caller can opt into `report: 'return'` / `--format json`
48
- * (plan 0070).
49
- */
50
- export function throwIfViolations(violations) {
51
- finishPreset(violations, { report: 'throw' });
52
- }
53
71
  //# sourceMappingURL=preset-dispatch.js.map
@@ -1 +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,IAA8C,EAC9C,eAA6B,EAC7B,SAAmD;IAEnD,8EAA8E;IAC9E,gFAAgF;IAChF,6EAA6E;IAC7E,2BAA2B;IAC3B,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAC3D,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,eAAe,CAAA;IACzD,IAAI,SAAS,KAAK,KAAK;QAAE,OAAO,EAAE,CAAA;IAElC,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAA;IAElD,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,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"}
1
+ {"version":3,"file":"preset-dispatch.js","sourceRoot":"","sources":["../src/preset-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,aAAa,EAAE,MAAM,qBAAqB,CAAA;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAuBzC;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAqB,EACrB,IAA8C,EAC9C,eAA6B,EAC7B,SAAmD;IAEnD,8EAA8E;IAC9E,gFAAgF;IAChF,6EAA6E;IAC7E,2BAA2B;IAC3B,MAAM,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;IAC3D,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,eAAe,CAAA;IACzD,IAAI,SAAS,KAAK,KAAK,EAAE,CAAC;QACxB,gEAAgE;QAChE,EAAE;QACF,4EAA4E;QAC5E,+DAA+D;QAC/D,yEAAyE;QACzE,6EAA6E;QAC7E,sEAAsE;QACtE,0EAA0E;QAC1E,0EAA0E;QAC1E,yEAAyE;QACzE,sBAAsB;QACtB,EAAE;QACF,2EAA2E;QAC3E,uEAAuE;QACvE,OAAO,aAAa,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,CAAA;IAElD,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QACzB,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,WAAW,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAA;QAC3C,CAAC;QACD,wEAAwE;QACxE,2EAA2E;QAC3E,sEAAsE;QACtE,2EAA2E;QAC3E,sDAAsD;QACtD,OAAO,aAAa,CAClB,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,EAC5D,EAAE,QAAQ,EAAE,UAAU,CAAC,QAAQ,EAAE,CAClC,CAAA;IACH,CAAC;IAED,OAAO,UAAU,CAAA;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB;AAC/B,+EAA+E;AAC/E,4EAA4E;AAC5E,+EAA+E;AAC/E,4EAA4E;AAC5E,kBAAkB;AAClB,SAA4D,EAC5D,QAA2B;IAE3B,IAAI,CAAC,SAAS;QAAE,OAAM;IACtB,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAA;IAClC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,WAAW,CACT,wBAAwB,GAAG,4CAA4C;gBACrE,oBAAoB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5C,CAAA;QACH,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Whether a glob can already match an absolute path.
3
+ *
4
+ * Extracted from ts-archunit's larger `project-relative.ts`, most of which
5
+ * (`rootOf`/`relativeToRoot`, workspace multi-root awareness) needs
6
+ * `ArchProject`/ts-morph and stays deferred — this one predicate is pure
7
+ * string syntax with no dependency on either, and `glob-diagnosis.ts` needs
8
+ * it to be kernel-eligible at all, so it gets its own small home here rather
9
+ * than waiting on the ts-morph-blocked half of the file it came from.
10
+ *
11
+ * Covers POSIX-absolute and Windows drive-absolute globs as well as an
12
+ * explicit globstar.
13
+ */
14
+ export declare function isAnchored(glob: string): boolean;
15
+ /**
16
+ * Does this glob name a location relative to the project root?
17
+ *
18
+ * Only an **unanchored, relative** glob is normalized. `'**\/x'` is explicitly
19
+ * "anywhere" and must keep meaning that; `'/abs/x'` is already absolute. So
20
+ * this is the same population `syntacticFault` calls `unanchored`, which is
21
+ * what makes the two consistent: a glob stops being reported dead for being
22
+ * unanchored exactly when it starts working.
23
+ */
24
+ export declare function isProjectRelative(glob: string): boolean;
25
+ //# sourceMappingURL=project-relative.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-relative.d.ts","sourceRoot":"","sources":["../src/project-relative.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAyBvD"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Whether a glob can already match an absolute path.
3
+ *
4
+ * Extracted from ts-archunit's larger `project-relative.ts`, most of which
5
+ * (`rootOf`/`relativeToRoot`, workspace multi-root awareness) needs
6
+ * `ArchProject`/ts-morph and stays deferred — this one predicate is pure
7
+ * string syntax with no dependency on either, and `glob-diagnosis.ts` needs
8
+ * it to be kernel-eligible at all, so it gets its own small home here rather
9
+ * than waiting on the ts-morph-blocked half of the file it came from.
10
+ *
11
+ * Covers POSIX-absolute and Windows drive-absolute globs as well as an
12
+ * explicit globstar.
13
+ */
14
+ export function isAnchored(glob) {
15
+ return glob.startsWith('**/') || glob.startsWith('/') || /^[A-Za-z]:\//.test(glob);
16
+ }
17
+ /**
18
+ * Does this glob name a location relative to the project root?
19
+ *
20
+ * Only an **unanchored, relative** glob is normalized. `'**\/x'` is explicitly
21
+ * "anywhere" and must keep meaning that; `'/abs/x'` is already absolute. So
22
+ * this is the same population `syntacticFault` calls `unanchored`, which is
23
+ * what makes the two consistent: a glob stops being reported dead for being
24
+ * unanchored exactly when it starts working.
25
+ */
26
+ export function isProjectRelative(glob) {
27
+ // A `./` segment is excluded, and that exclusion is load-bearing rather than
28
+ // fussy. `syntacticFault` reports `dot-segment` for a `./` anywhere in a
29
+ // glob, so normalizing one would make the rule MATCH at runtime while the
30
+ // gate still reported it dead — two derivations disagreeing about the same
31
+ // glob, which is the failure this project spends most of its guards on.
32
+ //
33
+ // `./` is a mistake in both worlds — it never occurs in an absolute path and
34
+ // it says nothing extra in a relative one — so the honest fix is to leave it
35
+ // failing, with advice that says to remove it.
36
+ // `..` is not relative-to-the-root in any usable sense: containment returns
37
+ // `undefined` for anything above the root, deliberately, so a `../`
38
+ // glob would normalize to nothing and be reported dead with three false
39
+ // causes. Excluded alongside `./` — both are mistakes in both readings.
40
+ if (/(?:^|\/)\.\.?\//.test(glob))
41
+ return false;
42
+ // Derived from `isAnchored`, not restated — two lists that disagree is the
43
+ // failure this file spends most of its guards on. `isAnchored` covers `/x`,
44
+ // `**/x` and a drive-absolute `C:/x`.
45
+ if (isAnchored(glob))
46
+ return false;
47
+ // `*/x/**` is deliberately NOT normalized, even though it is unanchored.
48
+ // Normalizing it would make it match, which sounds like an improvement until
49
+ // you notice it is the LAST reachable `unanchored` fault for a path glob —
50
+ // the anchor advice would become unreachable. Left failing, with a remedy
51
+ // that works: `'**/x/**'`.
52
+ return !glob.startsWith('*/');
53
+ }
54
+ //# sourceMappingURL=project-relative.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-relative.js","sourceRoot":"","sources":["../src/project-relative.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACpF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,6EAA6E;IAC7E,yEAAyE;IACzE,0EAA0E;IAC1E,2EAA2E;IAC3E,wEAAwE;IACxE,EAAE;IACF,6EAA6E;IAC7E,6EAA6E;IAC7E,+CAA+C;IAC/C,4EAA4E;IAC5E,oEAAoE;IACpE,wEAAwE;IACxE,wEAAwE;IACxE,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAC9C,2EAA2E;IAC3E,4EAA4E;IAC5E,sCAAsC;IACtC,IAAI,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAA;IAClC,yEAAyE;IACzE,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,2BAA2B;IAC3B,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;AAC/B,CAAC"}
package/dist/report.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ArchViolation } from './violation.js';
1
+ import { type CollectResult } from './collect-result.js';
2
2
  import type { OutputFormat } from './check-options.js';
3
3
  /**
4
4
  * How a preset delivers its violations (plan 0070, ADR-008):
@@ -18,21 +18,51 @@ export interface ReportOptions {
18
18
  export interface PresetReportOptions extends ReportOptions {
19
19
  /** Delivery mode. Default `throw`. */
20
20
  readonly report?: ReportMode;
21
+ /**
22
+ * Declare that this preset's subject legitimately does not exist here —
23
+ * [ADR-010](../../../adr/010-a-pass-is-constructed-from-evidence.md) §3.
24
+ *
25
+ * **On the shared options type, not on six preset interfaces**, because
26
+ * ADR-010 §3's second clause is about presets as a class: "A preset user does
27
+ * not hold the builder; if a preset option cannot carry the user's
28
+ * empty-declaration to the mint, their only reachable remedy is disabling the
29
+ * option — deleting coverage permanently (ADR-009 rule 1's trained-suppression
30
+ * dynamic, reproduced by this ADR's own gate if unaddressed)." A preset that
31
+ * examines nothing and cannot be told so leaves its user exactly one exit, and
32
+ * it is the wrong one.
33
+ *
34
+ * **It expires**, which is the only reason it is admissible at all: declare
35
+ * this and then examine something, and the emitter reports
36
+ * `emitter/expired-declaration`. A claim nothing can contradict is not an
37
+ * assertion — the property ADR-014 §3's 2026-09-05 amendment turns on when it
38
+ * refuses to infer a declaration from `overrides: 'off'`.
39
+ *
40
+ * Use it for a corpus with no ER diagrams, a suite with no exemptions, a
41
+ * project that genuinely has none of this preset's subject. Do not use it to
42
+ * quiet a preset whose glob is wrong: the day the glob is fixed, this reddens.
43
+ */
44
+ readonly expectEmpty?: boolean;
21
45
  }
22
46
  /**
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.
47
+ * How many violations this module has actually WRITTEN, ever.
48
+ *
49
+ * Read as a delta by a caller that aggregates reporting, to answer one question it
50
+ * cannot otherwise answer: *did something emit while I was loading that module?*
51
+ *
52
+ * The alternative a caller might reach for — counting the writes it SUPPRESSED and
53
+ * inferring "then nothing was written" — is a double negative and is unsound: a
54
+ * module that suppresses one terminal and leaks through another satisfies it while
55
+ * leaking. Measured on `eess-ts`, which shipped that inference and fell into
56
+ * exactly that case. Count emissions, not silences.
28
57
  */
29
- export declare function reportViolations(violations: ArchViolation[], options?: ReportOptions): void;
58
+ export declare function violationsEmittedCount(): number;
59
+ export declare function reportViolations(violations: CollectResult, options?: ReportOptions): CollectResult;
30
60
  /**
31
61
  * 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.
62
+ * (plan 0070). `throw` (default) emits then throws; `return` hands the
63
+ * violations back untouched (the caller owns emission and control flow);
64
+ * `warn` emits without throwing. Always returns the violations, so a caller can
65
+ * inspect them regardless of mode.
36
66
  */
37
- export declare function finishPreset(violations: ArchViolation[], options?: PresetReportOptions): ArchViolation[];
67
+ export declare function finishPreset(violations: CollectResult, options?: PresetReportOptions): CollectResult;
38
68
  //# sourceMappingURL=report.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAMtD;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;AAEpD,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAA;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,sEAAsE;AACtE,MAAM,WAAW,mBAAoB,SAAQ,aAAa;IACxD,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,UAAU,CAAA;CAC7B;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"}
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,aAAa,EAA8B,MAAM,qBAAqB,CAAA;AAUpF,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;IAE5B;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAC/B;AAWD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AA6HD,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,aAAa,EACzB,OAAO,GAAE,aAAkB,GAC1B,aAAa,CAqBf;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,UAAU,EAAE,aAAa,EACzB,OAAO,GAAE,mBAAwB,GAChC,aAAa,CAoCf"}