@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,92 @@
1
+ // @nielspeter/eess/internal — family plumbing (ADR-011).
2
+ //
3
+ // NOT public API. These symbols exist so the sibling dialects can share the
4
+ // kernel's engine without each reimplementing it; a consumer writing rules never
5
+ // names them, and nothing here is taught by `docs/` or a package README.
6
+ //
7
+ // The boundary is enforced on this side of the line only: a dialect may import
8
+ // from here, and its barrel must never re-export what it finds. It cannot be
9
+ // enforced on the consumer's side — a subpath export is published and resolvable
10
+ // by anyone, which ADR-011's Enforcement table records as `manual` rather than
11
+ // pretending otherwise.
12
+ //
13
+ // Moving a symbol OUT of here and onto the root is additive. Moving one IN is a
14
+ // breaking change and needs a changeset that says so.
15
+ export { DECLARE_INSTEAD } from './unsuppressable.js';
16
+ export { UNSUPPRESSABLE } from './unsuppressable.js';
17
+ export { UNSUPPRESSABLE_MECHANISMS } from './unsuppressable.js';
18
+ export { applyFilters } from './execute-rule.js';
19
+ export { applyFixes } from './apply-fixes.js';
20
+ export { assertionLessViolation } from './terminal-builder.js';
21
+ export { bold, red, dim, yellow, cyan, gray } from './ansi.js';
22
+ export { byCodepoint, severityFor, remedyRepeatsMessage } from './violation.js';
23
+ export { dedupeConfigFindings } from './dedupe-config-findings.js';
24
+ // The emitter's own findings, for a dialect door that must tell "this receipt
25
+ // carried no evidence" apart from "this rule matched nothing". They are
26
+ // different faults with different remedies, and a door that refuses on the
27
+ // second is a false positive — measured: one dead preset glob blocked every fix
28
+ // in a run. Internal, not root: an adopter has no reason to mint or classify an
29
+ // emitter finding, which is proposal 009's subject.
30
+ export { isEmitterFinding, EMITTER_IDS } from './emitter-findings.js';
31
+ export { disambiguateIdentities } from './violation.js';
32
+ export { discoverIdentityRoot, normalizeIdentityText } from './identity-root.js';
33
+ export { escapeGitHub } from './format-github.js';
34
+ export { hashViolation } from './baseline.js';
35
+ export { identityCollisions } from './violation.js';
36
+ export { isAnchored, isProjectRelative } from './project-relative.js';
37
+ export { isDescribable } from './rule-description.js';
38
+ export { isFaultPosition, countDeclaredGlobs, isGlobNode, isOpaqueGlob, stampGlobs, negateGlobs, combineGlobs, } from './glob-site.js';
39
+ export { isRecord, isNullaryCallable } from './type-guards.js';
40
+ export { isSilent } from './silent-exclusion.js';
41
+ export { marksAssertsCardinality } from './cardinality.js';
42
+ export { marksOwnEmptyDiscovery, ownsEmptyDiscovery } from './owns-empty-discovery.js';
43
+ export { matchSelections } from './matching.js';
44
+ export { recordEdgeCoverage, untestedRules, edgeCoverageNotice, resetEdgeCoverage, } from './edge-coverage.js';
45
+ export { registerCacheReset, clearRegisteredCaches } from './cache-registry.js';
46
+ export { resetCommentSuppression, recordCommentSuppression, commentSuppressions, commentSuppressionNotice, } from './comment-suppression.js';
47
+ export { resetIdentityCollisions } from './violation.js';
48
+ export { resetStderrGuardForTests } from './stderr.js';
49
+ export { selectionMemo } from './selection-memo.js';
50
+ export { shallowClone } from './shallow-clone.js';
51
+ export { subjectOf } from './violation.js';
52
+ export { suppressionNotice, activeNotice, resetDiffDisclosureForTests } from './diff-disclosure.js';
53
+ export { toPortablePath } from './identity-root.js';
54
+ export { viewsFor } from './path-universe.js';
55
+ // Bug 0257: one suffix resolver, called by eess-md and eess-crossvalidate.
56
+ export { pathSuffixIndex } from './path-suffix.js';
57
+ export { violationsEmittedCount } from './report.js';
58
+ export { writeStderr } from './stderr.js';
59
+ // Watch-mode scheduling and the watch loop, shared by every dialect CLI. Family
60
+ // plumbing rather than public API (ADR-011): a consumer writing rules never
61
+ // calls this; a dialect's `--watch` does. Unified here because the two copies
62
+ // drifted and one of them kept a bug the other had fixed — see `watch.ts`.
63
+ export { RunScheduler, watchAndRerun } from './watch.js';
64
+ // The dialect-independent halves of CLI config handling — finding the file,
65
+ // validating what a loaded module claims, and classifying Node's module-format
66
+ // refusal. Family plumbing (ADR-011): a consumer writing rules never calls
67
+ // these; every dialect's CLI does, and did so from its own copy until now.
68
+ export { findConfigFile, extractSharedConfig, isModuleFormatRefusal, requireRuleFiles, } from './cli-config.js';
69
+ // Recursive file discovery for the dialects that read a directory tree rather
70
+ // than a TypeScript project (`eess-md`, `eess-crossvalidate`). Each carried its
71
+ // own copy at 99% similarity.
72
+ export { walkFiles, toPosix } from './file-walk.js';
73
+ // The globs a rule declares, stamped with their origin. Family plumbing — a
74
+ // dialect's own rule-declaration layer calls it; a consumer writing rules does not.
75
+ export { declaredGlobsOf } from './rule-builder.js';
76
+ // Recording exclusion patterns into a builder's state. Family plumbing: the
77
+ // dialects' builders call it, a consumer writing rules does not.
78
+ export { recordExclusions } from './silent-exclusion.js';
79
+ // Applying a rule's predicates to its elements. Family plumbing: the dialects'
80
+ // builders call it, a consumer writing rules does not.
81
+ export { selectMatching, matchingElements } from './correspondence.js';
82
+ // Recording a predicate on a builder, diagnosing one that arrived after
83
+ // `.should()`. Family plumbing.
84
+ export { recordPredicate } from './predicate.js';
85
+ // Running a rule's conditions over its selected elements, carrying the evidence
86
+ // count ADR-010 requires. Family plumbing: dialect builders call it.
87
+ export { evaluateConditions, conditionContextFrom } from './condition.js';
88
+ // Assembling a rule's English description from what it declared. Family
89
+ // plumbing: every dialect builder renders one, a consumer does not.
90
+ export { ruleDescriptionOf, ruleDescriptionFrom } from './rule-description.js';
91
+ export { assertHomogeneous } from './combinators.js';
92
+ //# sourceMappingURL=internal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.js","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Blank every span a directive must NOT be read from, preserving length and
3
+ * lines so reported positions are unchanged.
4
+ *
5
+ * Bug 0154: `parseExclusionComments` scanned raw source line by line with a bare
6
+ * regex, so text that merely LOOKED like `// eess-exclude …` — inside a string,
7
+ * a template literal, or a block comment describing the grammar — was parsed as
8
+ * a real waiver and silently suppressed a genuine finding on the next line. That
9
+ * is a suppression nobody wrote, which is the worst direction a suppression
10
+ * system can fail in.
11
+ *
12
+ * **Text-only, deliberately.** The kernel cannot import ts-morph (ADR-002/007
13
+ * confine it to `eess-ts`), so this is a hand-rolled single-pass scanner rather
14
+ * than an AST walk. The failure direction is what makes that acceptable: a
15
+ * mis-lex can only ever *hide* a directive — a waiver stops working, loudly, and
16
+ * the violation it was hiding comes back — never invent one.
17
+ *
18
+ * Line comments are deliberately NOT blanked: they are the thing being looked
19
+ * for. Everything else that can contain `//` is.
20
+ */
21
+ /**
22
+ * Blank strings, template literals, regex literals and block comments.
23
+ *
24
+ * @param sourceText the raw file text
25
+ * @returns text of identical length and line structure, with those spans spaced out
26
+ */
27
+ export declare function maskNonCommentSpans(sourceText: string): string;
28
+ /**
29
+ * The markdown answer to the question `maskNonCommentSpans` asks of code.
30
+ *
31
+ * A `.md` file has no string or template literals, so running the JS/TS lexer
32
+ * over one is a category error — and a costly one, because markdown is
33
+ * backtick-dense: a single unbalanced backtick in prose opened a "template
34
+ * literal" that swallowed the rest of the file, silencing every real directive
35
+ * after it. Fail-closed, so no invented suppression, but a waiver that stops
36
+ * working for a reason nobody can see is its own defect.
37
+ *
38
+ * What markdown DOES have is code spans, and they mean the same thing a string
39
+ * literal means in code: this is an example of the grammar, not an instance of
40
+ * it. Fenced blocks (``` or ~~~) and inline spans are blanked; prose is left
41
+ * alone. Length- and line-preserving, so reported positions do not move.
42
+ *
43
+ * An unterminated fence blanks to end-of-file. That is the fail-closed
44
+ * direction: text under a fence that was opened and never closed is more likely
45
+ * an example than a waiver, and the cost is a directive that does not apply
46
+ * rather than one that applies where nobody asked.
47
+ */
48
+ export declare function maskMarkdownCodeSpans(sourceText: string): string;
49
+ //# sourceMappingURL=mask-non-comment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mask-non-comment.d.ts","sourceRoot":"","sources":["../src/mask-non-comment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAkCH;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAyF9D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAyChE"}
@@ -0,0 +1,261 @@
1
+ /**
2
+ * Blank every span a directive must NOT be read from, preserving length and
3
+ * lines so reported positions are unchanged.
4
+ *
5
+ * Bug 0154: `parseExclusionComments` scanned raw source line by line with a bare
6
+ * regex, so text that merely LOOKED like `// eess-exclude …` — inside a string,
7
+ * a template literal, or a block comment describing the grammar — was parsed as
8
+ * a real waiver and silently suppressed a genuine finding on the next line. That
9
+ * is a suppression nobody wrote, which is the worst direction a suppression
10
+ * system can fail in.
11
+ *
12
+ * **Text-only, deliberately.** The kernel cannot import ts-morph (ADR-002/007
13
+ * confine it to `eess-ts`), so this is a hand-rolled single-pass scanner rather
14
+ * than an AST walk. The failure direction is what makes that acceptable: a
15
+ * mis-lex can only ever *hide* a directive — a waiver stops working, loudly, and
16
+ * the violation it was hiding comes back — never invent one.
17
+ *
18
+ * Line comments are deliberately NOT blanked: they are the thing being looked
19
+ * for. Everything else that can contain `//` is.
20
+ */
21
+ /** Replace a span with spaces, keeping newlines so line numbers do not move. */
22
+ function blank(text, start, end) {
23
+ let out = '';
24
+ for (let i = start; i < end; i++) {
25
+ out += text[i] === '\n' ? '\n' : ' ';
26
+ }
27
+ return out;
28
+ }
29
+ /**
30
+ * A `/` here starts a regex literal rather than dividing.
31
+ *
32
+ * Decided by the previous significant character: after a value (identifier,
33
+ * literal, `)`, `]`) a `/` divides; after an operator, `(`, `,`, `=` or nothing
34
+ * it opens a regex. Getting this wrong is safe in one direction only — treating
35
+ * a division as a regex blanks source that could then hide a directive, so the
36
+ * bias is toward NOT opening a regex when unsure.
37
+ */
38
+ function opensRegex(text, at) {
39
+ let i = at - 1;
40
+ while (i >= 0) {
41
+ const c = text[i];
42
+ if (c === undefined)
43
+ return true;
44
+ if (c === ' ' || c === '\t' || c === '\r' || c === '\n') {
45
+ i -= 1;
46
+ continue;
47
+ }
48
+ return !/[A-Za-z0-9_$)\]]/.test(c);
49
+ }
50
+ return true;
51
+ }
52
+ /**
53
+ * Blank strings, template literals, regex literals and block comments.
54
+ *
55
+ * @param sourceText the raw file text
56
+ * @returns text of identical length and line structure, with those spans spaced out
57
+ */
58
+ export function maskNonCommentSpans(sourceText) {
59
+ let out = '';
60
+ let i = 0;
61
+ const n = sourceText.length;
62
+ while (i < n) {
63
+ const c = sourceText[i];
64
+ const next = sourceText[i + 1];
65
+ // Line comment — left intact; this is what the directive parser reads.
66
+ if (c === '/' && next === '/') {
67
+ const end = sourceText.indexOf('\n', i);
68
+ const stop = end === -1 ? n : end;
69
+ out += sourceText.slice(i, stop);
70
+ i = stop;
71
+ continue;
72
+ }
73
+ // Block comment — blanked. A grammar description inside JSDoc is prose.
74
+ if (c === '/' && next === '*') {
75
+ const close = sourceText.indexOf('*/', i + 2);
76
+ const stop = close === -1 ? n : close + 2;
77
+ out += blank(sourceText, i, stop);
78
+ i = stop;
79
+ continue;
80
+ }
81
+ // String or template literal — blanked whole, interpolations included. A
82
+ // `${…}` may itself contain a quote, so scanning it as code would need a
83
+ // nesting stack for no benefit: nothing inside a template is a directive.
84
+ if (c === '"' || c === "'" || c === '`') {
85
+ const quote = c;
86
+ let j = i + 1;
87
+ while (j < n) {
88
+ const d = sourceText[j];
89
+ if (d === '\\') {
90
+ j += 2;
91
+ continue;
92
+ }
93
+ if (d === quote) {
94
+ j += 1;
95
+ break;
96
+ }
97
+ // An unterminated single- or double-quoted string ends at the newline;
98
+ // a template legitimately spans lines.
99
+ if (d === '\n' && quote !== '`')
100
+ break;
101
+ j += 1;
102
+ }
103
+ out += blank(sourceText, i, j);
104
+ i = j;
105
+ continue;
106
+ }
107
+ // Regex literal — blanked. `/…\/…/` can contain `//`.
108
+ if (c === '/' && opensRegex(sourceText, i)) {
109
+ let j = i + 1;
110
+ let inClass = false;
111
+ let closed = false;
112
+ while (j < n) {
113
+ const d = sourceText[j];
114
+ if (d === '\\') {
115
+ j += 2;
116
+ continue;
117
+ }
118
+ if (d === '\n')
119
+ break;
120
+ if (d === '[')
121
+ inClass = true;
122
+ else if (d === ']')
123
+ inClass = false;
124
+ else if (d === '/' && !inClass) {
125
+ j += 1;
126
+ closed = true;
127
+ break;
128
+ }
129
+ j += 1;
130
+ }
131
+ // Only blank when it really closed on the same line; an unterminated
132
+ // `/` was division after all, and blanking to end-of-line could hide a
133
+ // trailing directive.
134
+ if (closed) {
135
+ out += blank(sourceText, i, j);
136
+ i = j;
137
+ continue;
138
+ }
139
+ }
140
+ out += c;
141
+ i += 1;
142
+ }
143
+ return out;
144
+ }
145
+ /**
146
+ * The markdown answer to the question `maskNonCommentSpans` asks of code.
147
+ *
148
+ * A `.md` file has no string or template literals, so running the JS/TS lexer
149
+ * over one is a category error — and a costly one, because markdown is
150
+ * backtick-dense: a single unbalanced backtick in prose opened a "template
151
+ * literal" that swallowed the rest of the file, silencing every real directive
152
+ * after it. Fail-closed, so no invented suppression, but a waiver that stops
153
+ * working for a reason nobody can see is its own defect.
154
+ *
155
+ * What markdown DOES have is code spans, and they mean the same thing a string
156
+ * literal means in code: this is an example of the grammar, not an instance of
157
+ * it. Fenced blocks (``` or ~~~) and inline spans are blanked; prose is left
158
+ * alone. Length- and line-preserving, so reported positions do not move.
159
+ *
160
+ * An unterminated fence blanks to end-of-file. That is the fail-closed
161
+ * direction: text under a fence that was opened and never closed is more likely
162
+ * an example than a waiver, and the cost is a directive that does not apply
163
+ * rather than one that applies where nobody asked.
164
+ */
165
+ export function maskMarkdownCodeSpans(sourceText) {
166
+ const lines = sourceText.split('\n');
167
+ const out = [];
168
+ let fenceChar;
169
+ let fenceLength = 0;
170
+ for (const line of lines) {
171
+ const opener = /^\s*(`{3,}|~{3,})/.exec(line);
172
+ const marker = opener === null ? undefined : opener[1];
173
+ if (fenceChar !== undefined) {
174
+ // Inside a fence: blank everything, the closing marker line included.
175
+ out.push(' '.repeat(line.length));
176
+ if (marker !== undefined && marker.charAt(0) === fenceChar && marker.length >= fenceLength) {
177
+ fenceChar = undefined;
178
+ fenceLength = 0;
179
+ }
180
+ continue;
181
+ }
182
+ if (marker !== undefined) {
183
+ fenceChar = marker.charAt(0);
184
+ fenceLength = marker.length;
185
+ out.push(' '.repeat(line.length));
186
+ continue;
187
+ }
188
+ // Markdown's THIRD code construct: a 4-space (or tab) indented block. Missed
189
+ // by the first version, which handled fences and inline spans only — so an
190
+ // indented example of a directive was read as a live waiver. Deliberately
191
+ // over-broad (a wrapped list item indents too): over-masking hides a
192
+ // directive, which is loud; under-masking invents one, which is silent.
193
+ if (/^(?: {4}|\t)/.test(line)) {
194
+ out.push(' '.repeat(line.length));
195
+ continue;
196
+ }
197
+ // Outside a fence: blank BALANCED inline spans only. An odd backtick is
198
+ // prose, and treating it as an opener is exactly the bug this replaces.
199
+ out.push(blankInlineCodeSpans(line));
200
+ }
201
+ return out.join('\n');
202
+ }
203
+ /**
204
+ * Blank code spans on one line, matching backtick RUNS the way CommonMark does:
205
+ * an opening run of N backticks is closed by the next run of exactly N.
206
+ *
207
+ * The first version paired backticks one at a time, which left the contents of
208
+ * any run of two or more exposed — so a directive inside ``…`` survived masking
209
+ * and was read as a live waiver. That is a suppression nobody wrote, the one
210
+ * direction this whole module exists to prevent (bug 0154), reintroduced by the
211
+ * fix for it. Multi-tick runs are not exotic here: they are the repo's own
212
+ * convention for code containing a backtick.
213
+ *
214
+ * An unclosed run is left as ordinary text, so a stray tick in prose still
215
+ * cannot swallow the rest of the line.
216
+ */
217
+ function blankInlineCodeSpans(line) {
218
+ const runs = [];
219
+ let i = 0;
220
+ while (i < line.length) {
221
+ if (line.charAt(i) !== '`') {
222
+ i += 1;
223
+ continue;
224
+ }
225
+ const start = i;
226
+ while (i < line.length && line.charAt(i) === '`')
227
+ i += 1;
228
+ runs.push({ start, length: i - start });
229
+ }
230
+ if (runs.length < 2)
231
+ return line;
232
+ let out = line;
233
+ let openIndex = 0;
234
+ while (openIndex < runs.length) {
235
+ const open = runs[openIndex];
236
+ if (open === undefined)
237
+ break;
238
+ let closeIndex = -1;
239
+ for (let j = openIndex + 1; j < runs.length; j++) {
240
+ const candidate = runs[j];
241
+ if (candidate !== undefined && candidate.length === open.length) {
242
+ closeIndex = j;
243
+ break;
244
+ }
245
+ }
246
+ if (closeIndex === -1) {
247
+ // No matching close: this run is prose, not a delimiter.
248
+ openIndex += 1;
249
+ continue;
250
+ }
251
+ const close = runs[closeIndex];
252
+ if (close === undefined)
253
+ break;
254
+ const from = open.start;
255
+ const to = close.start + close.length;
256
+ out = out.slice(0, from) + ' '.repeat(to - from) + out.slice(to);
257
+ openIndex = closeIndex + 1;
258
+ }
259
+ return out;
260
+ }
261
+ //# sourceMappingURL=mask-non-comment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mask-non-comment.js","sourceRoot":"","sources":["../src/mask-non-comment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Declare that this condition reports an empty discovery population itself. */
2
+ export declare function marksOwnEmptyDiscovery<T extends object>(condition: T): T;
3
+ /** Does this condition report an empty discovery population itself? */
4
+ export declare function ownsEmptyDiscovery(condition: object): boolean;
5
+ //# sourceMappingURL=owns-empty-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owns-empty-discovery.d.ts","sourceRoot":"","sources":["../src/owns-empty-discovery.ts"],"names":[],"mappings":"AAoEA,gFAAgF;AAChF,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,CAGxE;AAED,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE7D"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * A condition that diagnoses its own empty discovery population.
3
+ *
4
+ * [ts-archunit Plan 0081](https://github.com/nielspeter/ts-archunit/blob/main/plans/completed/0081-a-condition-declares-discovery-ownership.md). The
5
+ * dead-glob gate can see that a `.layer()` or `.inFolder()` glob matched nothing,
6
+ * but it short-circuits **before** the condition runs, so where a condition
7
+ * produces a better finding — one that names the dead layer, with a remedy
8
+ * pointing at the call the reader must edit — the gate would replace it with a
9
+ * generic message. This symbol is how a condition says "leave it to me".
10
+ *
11
+ * ## Why per condition, and not per builder
12
+ *
13
+ * It was per builder, and the granularity was load-bearing rather than cosmetic.
14
+ * At v0.45.0 `PairFinalBuilder` returned `true` unconditionally while its own
15
+ * docstring claimed *"All three now produce a finding naming the layer"* — and
16
+ * that claim was false: `haveMatchingCounterpart` checked for empty layers inside
17
+ * its pair loop, so a dead **final** layer produced no configuration finding at
18
+ * all. The coarse declaration suppressed the gate for exactly the case its
19
+ * declared owner did not handle, and the result was silence where the truth was
20
+ * one dead glob
21
+ * ([ts-archunit bug 0040](https://github.com/nielspeter/ts-archunit/blob/main/bugs/fixed/0040-a-crosslayer-rule-reports-nothing-when-its-layer-resolves-nothing.md)).
22
+ *
23
+ * v0.45.1 fixed the condition, so the blanket claim became true again. It would
24
+ * have gone false again the moment a fourth condition reached that builder,
25
+ * because nothing forced the new condition to say anything. Now the claim is not
26
+ * a claim: the builder reads the tag off the condition it was given.
27
+ *
28
+ * **An untagged condition does not own it, so the gate covers it.** That default
29
+ * is the load-bearing half — under it, v0.45.0's hole would have degraded to a
30
+ * generic message rather than silence, and a generic message is recoverable. An
31
+ * agent reading "this glob matched nothing" fixes the glob; silence sends it to
32
+ * write files into a layer that will never match.
33
+ *
34
+ * ## Unreachable by construction — a registry, not a property
35
+ *
36
+ * The first version was a `unique symbol` keyed onto the condition object, copying
37
+ * `ASSERTS_CARDINALITY`. Review broke it in two lines:
38
+ *
39
+ * ```ts
40
+ * const stolen = Object.getOwnPropertySymbols(haveMatchingCounterpart())[0]
41
+ * const mine: PairCondition = { description: 'x', evaluate: () => [], [stolen]: true }
42
+ * ```
43
+ *
44
+ * Measured: **0 configuration findings** on a dead layer. `PairCondition` is a
45
+ * public type and all three condition factories are public exports, so the symbol
46
+ * was readable off any shipped condition — the one-line silent opt-out this file
47
+ * claimed could not exist, reachable through documented API.
48
+ *
49
+ * The `ASSERTS_CARDINALITY` precedent is stronger than the copy was, and that is
50
+ * why copying it was not enough: `defineCondition` is its *sanctioned constructor*,
51
+ * and a test asserts that constructor emits no own symbols. `PairCondition` has no
52
+ * sanctioned constructor, so there is nothing to make the analogous guarantee.
53
+ *
54
+ * A module-level `WeakSet` closes that hole for the KEY: membership is not a
55
+ * property of the object, so it cannot be read off one, copied, or forged.
56
+ *
57
+ * It does not close it for the CALL, and the clause that used to say so — "a
58
+ * caller would need this module's binding, and it is not exported" — was already
59
+ * false when it was written: `marksOwnEmptyDiscovery` was exported from the
60
+ * kernel root. It now sits behind `@nielspeter/eess/internal`, which is narrower
61
+ * and still reachable. See `cardinality.ts` for the same limitation stated in
62
+ * full; the two markers share it.
63
+ *
64
+ * `WeakSet` rather than `Set` so a condition is not retained after its rule is
65
+ * discarded.
66
+ */
67
+ const OWNERS = new WeakSet();
68
+ /** Declare that this condition reports an empty discovery population itself. */
69
+ export function marksOwnEmptyDiscovery(condition) {
70
+ OWNERS.add(condition);
71
+ return condition;
72
+ }
73
+ /** Does this condition report an empty discovery population itself? */
74
+ export function ownsEmptyDiscovery(condition) {
75
+ return OWNERS.has(condition);
76
+ }
77
+ /*
78
+ * Not every builder needs this. `SliceRuleBuilder` declares ownership at the
79
+ * BUILDER level and correctly so: its reason — `assignedFrom` fanning out one glob
80
+ * tree per entry, where a single dead entry among populated siblings is a
81
+ * legitimate project shape — is identical for every condition reachable through
82
+ * it. Registry membership is for the case where ownership varies by condition,
83
+ * which is what made a blanket declaration wrong for cross-layer.
84
+ */
85
+ //# sourceMappingURL=owns-empty-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owns-empty-discovery.js","sourceRoot":"","sources":["../src/owns-empty-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AACH,MAAM,MAAM,GAAG,IAAI,OAAO,EAAU,CAAA;AAEpC,gFAAgF;AAChF,MAAM,UAAU,sBAAsB,CAAmB,SAAY;IACnE,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACrB,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAClD,OAAO,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;AAC9B,CAAC;AAED;;;;;;;GAOG"}
@@ -0,0 +1,57 @@
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
+ /** How a cited path resolves against a set of repo-relative paths. */
24
+ export type PathSuffixMatch =
25
+ /** The citation IS a repo-relative path. Wins outright, even if the same tail also matches elsewhere. */
26
+ {
27
+ readonly kind: 'exact';
28
+ readonly file: string;
29
+ }
30
+ /** Exactly one path ends with the citation on a `/` boundary. */
31
+ | {
32
+ readonly kind: 'unique';
33
+ readonly file: string;
34
+ }
35
+ /** Several do, so the citation names none of them. Candidates in index order. */
36
+ | {
37
+ readonly kind: 'ambiguous';
38
+ readonly files: readonly string[];
39
+ }
40
+ /** Nothing matches. */
41
+ | {
42
+ readonly kind: 'none';
43
+ };
44
+ /** A prepared path set. Build once, resolve many. Duplicate inputs collapse. */
45
+ export interface PathSuffixIndex {
46
+ resolve(wanted: string): PathSuffixMatch;
47
+ }
48
+ /**
49
+ * Prepare a path set for repeated suffix lookups.
50
+ *
51
+ * Indexed by last segment, because the corpora this runs over resolve hundreds
52
+ * of citations against thousands of paths and a linear scan per citation was
53
+ * measurable in `eess-md`. The index is the reason this takes the whole set up
54
+ * front rather than being a plain two-argument function.
55
+ */
56
+ export declare function pathSuffixIndex(paths: Iterable<string>): PathSuffixIndex;
57
+ //# sourceMappingURL=path-suffix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-suffix.d.ts","sourceRoot":"","sources":["../src/path-suffix.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,sEAAsE;AACtE,MAAM,MAAM,eAAe;AACzB,yGAAyG;AACvG;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACnD,iEAAiE;GAC/D;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE;AACpD,iFAAiF;GAC/E;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE;AACnE,uBAAuB;GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAE7B,gFAAgF;AAChF,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,CAAA;CACzC;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,eAAe,CAsCxE"}