@nielspeter/eess 0.4.0 → 0.5.1

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 (125) hide show
  1. package/README.md +94 -1
  2. package/dist/baseline-generator.d.ts +9 -0
  3. package/dist/baseline-generator.d.ts.map +1 -1
  4. package/dist/baseline-generator.js +9 -0
  5. package/dist/baseline-generator.js.map +1 -1
  6. package/dist/baseline.d.ts +1 -1
  7. package/dist/cardinality.d.ts.map +1 -1
  8. package/dist/cardinality.js +20 -5
  9. package/dist/cardinality.js.map +1 -1
  10. package/dist/cli-config.d.ts +106 -0
  11. package/dist/cli-config.d.ts.map +1 -0
  12. package/dist/cli-config.js +231 -0
  13. package/dist/cli-config.js.map +1 -0
  14. package/dist/collect-result.d.ts +94 -0
  15. package/dist/collect-result.d.ts.map +1 -0
  16. package/dist/collect-result.js +142 -0
  17. package/dist/collect-result.js.map +1 -0
  18. package/dist/combinators.d.ts +14 -0
  19. package/dist/combinators.d.ts.map +1 -1
  20. package/dist/combinators.js +53 -16
  21. package/dist/combinators.js.map +1 -1
  22. package/dist/condition.d.ts +37 -0
  23. package/dist/condition.d.ts.map +1 -1
  24. package/dist/condition.js +48 -1
  25. package/dist/condition.js.map +1 -1
  26. package/dist/correspondence.d.ts +30 -0
  27. package/dist/correspondence.d.ts.map +1 -1
  28. package/dist/correspondence.js +36 -1
  29. package/dist/correspondence.js.map +1 -1
  30. package/dist/dedupe-config-findings.d.ts.map +1 -1
  31. package/dist/dedupe-config-findings.js +27 -0
  32. package/dist/dedupe-config-findings.js.map +1 -1
  33. package/dist/diff-aware.d.ts +8 -9
  34. package/dist/diff-aware.d.ts.map +1 -1
  35. package/dist/diff-aware.js +38 -17
  36. package/dist/diff-aware.js.map +1 -1
  37. package/dist/emitter-findings.d.ts +167 -0
  38. package/dist/emitter-findings.d.ts.map +1 -0
  39. package/dist/emitter-findings.js +237 -0
  40. package/dist/emitter-findings.js.map +1 -0
  41. package/dist/errors.d.ts +48 -0
  42. package/dist/errors.d.ts.map +1 -1
  43. package/dist/errors.js +61 -0
  44. package/dist/errors.js.map +1 -1
  45. package/dist/exclusion-comments.d.ts +36 -1
  46. package/dist/exclusion-comments.d.ts.map +1 -1
  47. package/dist/exclusion-comments.js +185 -37
  48. package/dist/exclusion-comments.js.map +1 -1
  49. package/dist/execute-rule.d.ts +12 -3
  50. package/dist/execute-rule.d.ts.map +1 -1
  51. package/dist/execute-rule.js +184 -7
  52. package/dist/execute-rule.js.map +1 -1
  53. package/dist/file-walk.d.ts +22 -0
  54. package/dist/file-walk.d.ts.map +1 -0
  55. package/dist/file-walk.js +51 -0
  56. package/dist/file-walk.js.map +1 -0
  57. package/dist/format-json.d.ts +13 -0
  58. package/dist/format-json.d.ts.map +1 -1
  59. package/dist/format-json.js +24 -0
  60. package/dist/format-json.js.map +1 -1
  61. package/dist/index.d.ts +14 -46
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +13 -41
  64. package/dist/index.js.map +1 -1
  65. package/dist/internal.d.ts +55 -0
  66. package/dist/internal.d.ts.map +1 -0
  67. package/dist/internal.js +92 -0
  68. package/dist/internal.js.map +1 -0
  69. package/dist/mask-non-comment.d.ts +49 -0
  70. package/dist/mask-non-comment.d.ts.map +1 -0
  71. package/dist/mask-non-comment.js +261 -0
  72. package/dist/mask-non-comment.js.map +1 -0
  73. package/dist/owns-empty-discovery.d.ts.map +1 -1
  74. package/dist/owns-empty-discovery.js +12 -4
  75. package/dist/owns-empty-discovery.js.map +1 -1
  76. package/dist/path-suffix.d.ts +57 -0
  77. package/dist/path-suffix.d.ts.map +1 -0
  78. package/dist/path-suffix.js +73 -0
  79. package/dist/path-suffix.js.map +1 -0
  80. package/dist/predicate.d.ts +12 -0
  81. package/dist/predicate.d.ts.map +1 -1
  82. package/dist/predicate.js +20 -1
  83. package/dist/predicate.js.map +1 -1
  84. package/dist/preset-dispatch.d.ts +6 -34
  85. package/dist/preset-dispatch.d.ts.map +1 -1
  86. package/dist/preset-dispatch.js +30 -52
  87. package/dist/preset-dispatch.js.map +1 -1
  88. package/dist/report.d.ts +31 -7
  89. package/dist/report.d.ts.map +1 -1
  90. package/dist/report.js +174 -15
  91. package/dist/report.js.map +1 -1
  92. package/dist/rule-builder-like.d.ts +8 -2
  93. package/dist/rule-builder-like.d.ts.map +1 -1
  94. package/dist/rule-builder.d.ts +15 -0
  95. package/dist/rule-builder.d.ts.map +1 -1
  96. package/dist/rule-builder.js +41 -36
  97. package/dist/rule-builder.js.map +1 -1
  98. package/dist/rule-description.d.ts +50 -0
  99. package/dist/rule-description.d.ts.map +1 -1
  100. package/dist/rule-description.js +58 -0
  101. package/dist/rule-description.js.map +1 -1
  102. package/dist/selection-memo.d.ts +1 -3
  103. package/dist/selection-memo.d.ts.map +1 -1
  104. package/dist/selection-memo.js +1 -3
  105. package/dist/selection-memo.js.map +1 -1
  106. package/dist/silent-exclusion.d.ts +12 -0
  107. package/dist/silent-exclusion.d.ts.map +1 -1
  108. package/dist/silent-exclusion.js +22 -0
  109. package/dist/silent-exclusion.js.map +1 -1
  110. package/dist/terminal-builder.d.ts +29 -15
  111. package/dist/terminal-builder.d.ts.map +1 -1
  112. package/dist/terminal-builder.js +97 -51
  113. package/dist/terminal-builder.js.map +1 -1
  114. package/dist/vacuity-findings.d.ts +0 -6
  115. package/dist/vacuity-findings.d.ts.map +1 -1
  116. package/dist/vacuity-findings.js +27 -57
  117. package/dist/vacuity-findings.js.map +1 -1
  118. package/dist/violation.d.ts +22 -1
  119. package/dist/violation.d.ts.map +1 -1
  120. package/dist/violation.js.map +1 -1
  121. package/dist/watch.d.ts +71 -0
  122. package/dist/watch.d.ts.map +1 -0
  123. package/dist/watch.js +129 -0
  124. package/dist/watch.js.map +1 -0
  125. package/package.json +6 -1
package/README.md CHANGED
@@ -12,6 +12,90 @@ This package is the engine every eess dialect runs on. It knows nothing about Ty
12
12
  - Baseline mode, diff-aware filtering, exclusions, and the terminal/GitHub/JSON formatters
13
13
  - `definePredicate` / `defineCondition` — extension points for advanced users
14
14
 
15
+ ## Two entry points
16
+
17
+ `@nielspeter/eess` publishes two:
18
+
19
+ | Specifier | What it is |
20
+ | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
21
+ | `@nielspeter/eess` | The public API. Everything below is documented here, and a change to it is a versioned change. |
22
+ | `@nielspeter/eess/internal` | Family plumbing the sibling dialects share — cache registries, stderr guards, suppression counters, identity hashing, glob-tree internals. Not API. |
23
+
24
+ You want the root. `/internal` exists so the dialects can share one engine without
25
+ each name they touch becoming a public commitment; it is published because npm has
26
+ no way to ship a package-private module, not because it is for you. Nothing there is
27
+ documented, and no dialect re-exports it _as its own API_. Two names — `DiskSet`
28
+ and `OnDisk` — are also on `@nielspeter/eess-ts`'s root, where they are eess-ts's
29
+ own types that happen to share a name; that is the whole of the overlap.
30
+
31
+ Breaking something here is still a versioned change and still needs a changeset
32
+ (ADR-011 clause 4). What you are not owed is migration guidance, because it is not
33
+ API. See
34
+ [ADR-011](https://github.com/nielspeter/eess/blob/main/adr/011-the-kernels-public-api-is-explicit.md).
35
+
36
+ If a symbol you used disappeared from the root, it moved here — the import path is
37
+ the only change.
38
+
39
+ ## Kernel API reference
40
+
41
+ The fluent surface (`RuleBuilder`, `Predicate`, `Condition`, the combinators, the
42
+ formatters) is covered in the [docs site](https://nielspeter.github.io/eess/). This
43
+ section covers the supporting types you will meet in signatures.
44
+
45
+ ### Reporting and severity
46
+
47
+ A preset never emits on its own — the caller owns emission (ADR-008).
48
+
49
+ - **`ReportMode`** — `'throw' | 'return' | 'warn'`. What a finisher does with findings: raise an `ArchRuleError`, hand them back, or print them as advisory and continue.
50
+ - **`ReportOptions`** — the emission controls: `format` (terminal/json/github) and `reason`, the rationale threaded into the output.
51
+ - **`RuleSeverity`** — `'error' | 'warn' | 'off'`, the value of a per-rule override.
52
+ - **`PresetBaseOptions`** — what every preset accepts: an `overrides` map of rule id → `RuleSeverity`, plus the reporting controls. Extend it when you write a preset so `{ report: 'return' }` works without your own plumbing.
53
+ - **`RuleBuilderLike`** — the one-method shape (`violations()`) a preset needs from anything it dispatches, so a preset is not coupled to a dialect's builder class.
54
+ - **`Dispatchable`** — what `dispatchRule` accepts: a builder that can produce violations _and_ name itself, so the dispatcher can apply a per-rule override to it. Strictly more than `RuleBuilderLike`; that one is the narrower shape used where only the findings matter.
55
+ - **`isArchRuleError(err)`** — use this instead of `instanceof ArchRuleError` when catching. `instanceof` compares class identity, so it returns `false` whenever two copies of the package are on disk — a nested `node_modules`, or a rule file loaded through a separate module registry. The check is structural (the stamped `name` plus the `violations` array), so it survives that. The thrown shape itself — `violations: ArchViolation[]` — is public either way.
56
+ - **`ArchConfigError`** / **`isArchConfigError(err)`** — thrown when a _rule_ is misconfigured (bad arguments to a condition, a malformed rule file), as opposed to `ArchRuleError`, which means the _architecture_ is wrong. Two different faults with two different audiences: one tells a rule author they mistyped something, the other tells a team their code drifted. Carries `subject` — the condition, predicate or file at fault — so a caller can route the failure without parsing the message. `isArchConfigError` is structural for the same two-copies-on-disk reason as `isArchRuleError`.
57
+ - **`ArchFix`** — a machine-applicable edit on a violation: `file`, a `[start, end)` character span, and the `replacement` text. This is what `--fix` applies.
58
+
59
+ ### The JSON report
60
+
61
+ `--format json` emits an **`ArchJsonReport`**: a `summary` (`total`, `errors`, `warnings`, `reason`), then **`ArchJsonViolation`** entries, plus **`ArchJsonSuppression`** for findings silenced by an `eess-exclude` comment and **`ArchJsonUntestedAllowlist`** for allowlists nothing exercised. Import these to type a tool that consumes eess output rather than re-declaring the shape.
62
+
63
+ ### Filtering a run
64
+
65
+ - **`BaselineFilter`** — decides whether an already-accepted finding is suppressed by the baseline file.
66
+ - **`DiffFilterLike`** — decides whether a finding falls inside the changed region, for `--changed` runs.
67
+
68
+ Both are interfaces so a host can supply its own; the kernel ships implementations.
69
+
70
+ ### Correspondence
71
+
72
+ `correspondence()` binds two `Selection`s and checks they agree in both directions.
73
+
74
+ - **`CorrespondenceOptions`** — its argument: the `left` and `right` selections, a join strategy, and optional per-side `suggest` callbacks for the two-sided message.
75
+ - **`KeyBy`** — the fast join: a key extracted per element, giving an O(n+m) match. Prefer it. The fallback `matchBy` predicate is O(n×m).
76
+ - **`RelationSpec`** — what `preserveRelations()` takes: how to read edges from each side, so the check covers relationships and not just membership.
77
+ - **`ElementInfo`** — the `name` / `file` / `line` a dialect reports for one element, which is what the message and the violation's location are built from.
78
+
79
+ ### Declaring globs (for custom predicates)
80
+
81
+ A predicate written with `definePredicate` should declare the globs it matches on.
82
+ Without that it is opaque, so a vacuity diagnosis cannot tell "matched nothing
83
+ because the glob is dead" from "matched nothing because nothing was there" — and
84
+ any `or()` containing it becomes undiagnosable too.
85
+
86
+ - **`globNode(leaf)`** — wrap a single declared glob into a tree. The common case.
87
+ - **`globAnyOf(globs, kind, base?)`** — declare several alternatives at once.
88
+ - **`DeclaredGlob`** — one glob with its `kind` and `base`. **`GlobKind`** is what the glob matches against (`'file-path' | 'parent-dir' | 'import-target' | 'specifier' | 'literal'`) and **`GlobBase`** is what it is resolved against (`'absolute' | 'tsconfig-relative' | 'normalized'`).
89
+ - **`GlobTree<L>`** — the `and`/`any` tree the declarations form; **`DeclaredGlobs`** is that tree over `DeclaredGlob`, and **`GlobLeaf<L>`** is one position in it.
90
+ - **`OpaqueGlob`** — the explicit "this branch cannot be described" marker. Honest, and it is what keeps an undeclared predicate from silently reading as a dead one.
91
+ - **`GlobSite`** — a declared glob plus where it was written; **`GlobPosition`** is that where (`'selector' | 'discovery' | 'condition' | 'exclusion'`), which is what lets a diagnosis point at the glob you actually got wrong.
92
+ - **`GlobNode`** — the tree over `GlobSite`, i.e. a fully-stamped declaration ready to diagnose.
93
+
94
+ ### Coverage evidence
95
+
96
+ - **`EdgeCoverage`** — one rule's evidence: how many `subjects` it saw, how many `edges` it actually tested, and a `reason` when that number is zero.
97
+ - **`UntestedReason`** — why zero: `'no-edges'` (nothing to test, usually correct), `'all-filtered'` (edges existed and every one was filtered out), `'none-matched'` (edges existed and none matched the allowlist). The distinction is the point — a rule that tested nothing should say which of the three it was, per ADR-010.
98
+
15
99
  ## Who uses it
16
100
 
17
101
  You normally don't install this directly — you install a dialect:
@@ -19,7 +103,16 @@ You normally don't install this directly — you install a dialect:
19
103
  - [`@nielspeter/eess-ts`](https://www.npmjs.com/package/@nielspeter/eess-ts) — TypeScript
20
104
  - [`@nielspeter/eess-mermaid`](https://www.npmjs.com/package/@nielspeter/eess-mermaid) — Mermaid class diagrams
21
105
 
22
- Install `@nielspeter/eess` directly only when authoring a new dialect or a cross-dialect tool on top of the kernel.
106
+ Install `@nielspeter/eess` directly only when authoring a new dialect or a cross-dialect
107
+ tool on top of the kernel.
108
+
109
+ **If that is you, `/internal` is your surface, not a wall.** The two sentences above look
110
+ like they contradict each other — "not for you", then "install it if you are writing a
111
+ dialect" — so to be explicit: a dialect author is exactly who `/internal` exists for, and
112
+ the five in this repo import from it. What the root alone gives you is the rule-authoring
113
+ vocabulary, not the engine. Nothing there is documented and it changes without migration
114
+ notes, so treat it as a contract you re-check on each kernel bump; if you are building a
115
+ dialect you intend to publish, open an issue and we will work out what belongs on the root.
23
116
 
24
117
  ## License
25
118
 
@@ -5,6 +5,15 @@ import type { ArchViolation } from './violation.js';
5
5
  * Used to generate a baseline: run all rules, collect violations,
6
6
  * write them to a baseline file.
7
7
  *
8
+ * **This bypasses the evidence gate, deliberately and knowingly** — see ADR-014
9
+ * and proposal 011 ask C. Prefer a dialect's `baseline` command, which gates per
10
+ * rule file and refuses a builder that certified nothing.
11
+ *
12
+ * **Not the same function as `eess-ts`'s `collectViolations`.** This one takes
13
+ * builders with a throwing `check()` and harvests the `ArchRuleError`; the
14
+ * dialect's takes builders with a non-throwing `violations()`. Same name, same
15
+ * `@example`, different contract.
16
+ *
8
17
  * @example
9
18
  * const violations = collectViolations(
10
19
  * classes(p).that().extend('Base').should().notContain(call('parseInt')),
@@ -1 +1 @@
1
- {"version":3,"file":"baseline-generator.d.ts","sourceRoot":"","sources":["../src/baseline-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAGnD;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC,GAAG,aAAa,EAAE,CAc5F"}
1
+ {"version":3,"file":"baseline-generator.d.ts","sourceRoot":"","sources":["../src/baseline-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAGnD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,QAAQ,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC,GAAG,aAAa,EAAE,CAc5F"}
@@ -5,6 +5,15 @@ import { ArchRuleError } from './errors.js';
5
5
  * Used to generate a baseline: run all rules, collect violations,
6
6
  * write them to a baseline file.
7
7
  *
8
+ * **This bypasses the evidence gate, deliberately and knowingly** — see ADR-014
9
+ * and proposal 011 ask C. Prefer a dialect's `baseline` command, which gates per
10
+ * rule file and refuses a builder that certified nothing.
11
+ *
12
+ * **Not the same function as `eess-ts`'s `collectViolations`.** This one takes
13
+ * builders with a throwing `check()` and harvests the `ArchRuleError`; the
14
+ * dialect's takes builders with a non-throwing `violations()`. Same name, same
15
+ * `@example`, different contract.
16
+ *
8
17
  * @example
9
18
  * const violations = collectViolations(
10
19
  * classes(p).that().extend('Base').should().notContain(call('parseInt')),
@@ -1 +1 @@
1
- {"version":3,"file":"baseline-generator.js","sourceRoot":"","sources":["../src/baseline-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,QAAsC;IACzE,MAAM,aAAa,GAAoB,EAAE,CAAA;IAEzC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,OAAO,CAAC,KAAK,EAAE,CAAA;QACjB,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;gBACnC,aAAa,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,CAAA;YACzC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAA;AACtB,CAAC"}
1
+ {"version":3,"file":"baseline-generator.js","sourceRoot":"","sources":["../src/baseline-generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAG,QAAsC;IACzE,MAAM,aAAa,GAAoB,EAAE,CAAA;IAEzC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC;YACH,OAAO,CAAC,KAAK,EAAE,CAAA;QACjB,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;gBACnC,aAAa,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,UAAU,CAAC,CAAA;YACzC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,aAAa,CAAA;AACtB,CAAC"}
@@ -26,7 +26,7 @@ export interface BaselineEntry {
26
26
  /**
27
27
  * What {@link measured} counts — `code-lines`, `methods`, `complexity`.
28
28
  *
29
- * Written since [bug 0171](../../../work/bugs/0171-a-metric-unit-change-silently-loosens-every-baselined-ratchet.md).
29
+ * Written since [bug 0171](../../../work/bugs/fixed/0171-a-metric-unit-change-silently-loosens-every-baselined-ratchet.md).
30
30
  * An accepted ceiling is a number IN A UNIT, and comparing across a change of
31
31
  * unit does not measure a regression — it moves the bar. Absent on entries
32
32
  * written before stamping, which {@link Baseline.isKnown} treats as "unknown
@@ -1 +1 @@
1
- {"version":3,"file":"cardinality.d.ts","sourceRoot":"","sources":["../src/cardinality.ts"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,CAGzE;AAED,yDAAyD;AACzD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE7D"}
1
+ {"version":3,"file":"cardinality.d.ts","sourceRoot":"","sources":["../src/cardinality.ts"],"names":[],"mappings":"AAyCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,CAGzE;AAED,yDAAyD;AACzD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE7D"}
@@ -16,11 +16,26 @@
16
16
  * empty-selection gate on any rule, permanently and invisibly. That is
17
17
  * `.allowEmpty()` wearing a different hat.
18
18
  *
19
- * This symbol is **not** re-exported from `src/index.ts`, and `package.json`'s
20
- * `exports` map has no wildcard subpath, so a consumer cannot import it to
21
- * name the key. The escape hatch users *do* get is `.expectEmpty()`, which is
22
- * an assertion that fails when the selection stops being empty — not a
23
- * silencer.
19
+ * **What actually stops a consumer doing this: not enough.** Say it plainly,
20
+ * because two earlier versions of this comment did not.
21
+ *
22
+ * The `WeakSet` below defends the KEY — membership cannot be read off an object,
23
+ * copied, or forged. It does not defend the CALL. Anyone holding
24
+ * `marksAssertsCardinality` can mark any condition, and it is reachable from
25
+ * `@nielspeter/eess/internal`. The first rationale here ("the exports map has no
26
+ * wildcard subpath") stopped being true when ADR-011 added the subpath; the
27
+ * second ("the `WeakSet` is the real defence") was simply wrong about which half
28
+ * it guards, and was written in the same branch that added the subpath.
29
+ *
30
+ * The honest position: this is narrower than it was — on `main` the marker was
31
+ * exported from the kernel ROOT and re-exported by eess-ts's root, so it sat on
32
+ * two published surfaces; it is now on one, named `/internal`, which no dialect
33
+ * re-exports. It is not closed. Closing it means validating at the registration
34
+ * site (accept only conditions from a sanctioned constructor), which is a design
35
+ * change, not a comment.
36
+ *
37
+ * The escape hatch users are *meant* to have is `.expectEmpty()` — an assertion
38
+ * that fails when the selection stops being empty, not a silencer.
24
39
  */
25
40
  const CARDINALITY_ASSERTERS = new WeakSet();
26
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"cardinality.js","sourceRoot":"","sources":["../src/cardinality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,qBAAqB,GAAG,IAAI,OAAO,EAAU,CAAA;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,uBAAuB,CAAmB,SAAY;IACpE,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACpC,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAClD,OAAO,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;AAC7C,CAAC"}
1
+ {"version":3,"file":"cardinality.js","sourceRoot":"","sources":["../src/cardinality.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,MAAM,qBAAqB,GAAG,IAAI,OAAO,EAAU,CAAA;AAEnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,uBAAuB,CAAmB,SAAY;IACpE,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACpC,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,kBAAkB,CAAC,SAAiB;IAClD,OAAO,qBAAqB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;AAC7C,CAAC"}
@@ -0,0 +1,106 @@
1
+ import type { OutputFormat } from './check-options.js';
2
+ /**
3
+ * The parts of dialect CLI config handling that are the same everywhere.
4
+ *
5
+ * **Split along the kernel's existing seam, not behind a new injection point.**
6
+ * `PathUniverse` sets the pattern: the kernel takes materialized data and the
7
+ * dialect does the I/O. Here the pure halves are finding the config file and
8
+ * validating what a loaded module claims — both were byte-identical between
9
+ * `eess-ts` and `eess-mermaid` (`findConfigFile` scored 100%). The impure half,
10
+ * actually importing the file, stays in each dialect because it needs `jiti`,
11
+ * which the kernel cannot depend on.
12
+ *
13
+ * That left one genuinely shared subtlety in the impure half —
14
+ * {@link isModuleFormatRefusal} — so it lived here too: pure, and the part that
15
+ * is easy to get dangerously wrong.
16
+ *
17
+ * **That description is no longer complete, and saying so is the point.** Bug
18
+ * 0223 added two more members of the same family, and one of them —
19
+ * {@link enableTypeScriptSpecifierResolution} — is NOT pure: it registers a
20
+ * resolve hook on the host process, permanently. The substitution it performs is
21
+ * a fact about the language rule files are WRITTEN in, which is TypeScript for
22
+ * every dialect, so the kernel is the right owner. But "the impure half stays in
23
+ * each dialect" is now true of importing and false of resolving, and an
24
+ * architecture review called the three of them module-loading policy sitting in
25
+ * a config-discovery file. Splitting them into their own kernel module is the
26
+ * open half of that finding; the header no longer claims otherwise in the
27
+ * meantime.
28
+ */
29
+ /** Config fields every dialect CLI understands. A dialect may add its own. */
30
+ export interface SharedCliConfig {
31
+ rules?: string[];
32
+ format?: OutputFormat | 'auto';
33
+ watchDirs?: string[];
34
+ }
35
+ /** The first of `filenames` that exists in the working directory. */
36
+ export declare function findConfigFile(filenames: readonly string[]): string | undefined;
37
+ /**
38
+ * The shared config a loaded module claims, validated.
39
+ *
40
+ * Everything is checked rather than trusted: a config file is arbitrary user
41
+ * code and its default export can be any shape at all. An unrecognised `format`
42
+ * is dropped rather than passed through, so a typo falls back to the default
43
+ * instead of reaching a formatter that has no case for it.
44
+ */
45
+ export declare function extractSharedConfig(mod: unknown): SharedCliConfig;
46
+ /**
47
+ * Did Node refuse this file for its MODULE FORMAT, rather than for anything the
48
+ * file does?
49
+ *
50
+ * Narrow on purpose. A broad `catch` that fell back to a transpiling loader on
51
+ * any error would re-execute a rule file that had already run — doubling its
52
+ * output — and would hide a genuine syntax error behind a second,
53
+ * differently-worded failure.
54
+ *
55
+ * The condition it detects is bug 0074: the CONSUMER project is
56
+ * `"type": "commonjs"` (what `npm init -y` writes) and the config or rule file
57
+ * uses ESM syntax.
58
+ */
59
+ export declare function isModuleFormatRefusal(error: unknown): boolean;
60
+ /**
61
+ * Did Node fail to resolve a specifier that TypeScript requires be written that
62
+ * way — a `./sibling.js` whose file on disk is `./sibling.ts`?
63
+ *
64
+ * Narrow for the same reason {@link isModuleFormatRefusal} is, and narrower
65
+ * still: it answers yes only when the TypeScript source is ACTUALLY on disk. A
66
+ * genuinely missing module is still a genuinely missing module, reported the way
67
+ * it always was, and nothing is retried on its behalf.
68
+ *
69
+ * This is bug 0223, reported by a consuming project. `"type": "module"` plus the
70
+ * `.js` specifier is not an exotic combination — it is the one TypeScript
71
+ * mandates for ESM, so every project that splits its rules across files reaches
72
+ * it on the first attempt. The failure is `ERR_MODULE_NOT_FOUND` rather than a
73
+ * `SyntaxError`, which is why the format-refusal predicate above cannot see it.
74
+ */
75
+ export declare function isTypeScriptSpecifierMiss(error: unknown): boolean;
76
+ /**
77
+ * Teach this process's loader the substitution, so `./sibling.js` resolves to
78
+ * `./sibling.ts` when that is the file that exists.
79
+ *
80
+ * **`registerHooks`, deliberately, and not a transpiling loader.** The hook is
81
+ * synchronous and in-thread, so a rule file still loads into THIS module
82
+ * registry. That is the invariant plan 0165 and bug 0029 paid for and the reason
83
+ * the alternative fix was rejected: a second registry makes
84
+ * `instanceof ArchRuleError` false and sets `callerAggregatesReports` on one
85
+ * copy while it is read on the other, printing every configuration finding
86
+ * twice. Resolution is the only thing being changed here; execution is
87
+ * untouched.
88
+ *
89
+ * The hook rewrites nothing unless the emitted path is absent AND the
90
+ * TypeScript source is present, so a real `.js` file beside a `.ts` of the same
91
+ * name always wins, and a specifier naming neither is left alone to fail as it
92
+ * would have.
93
+ */
94
+ export declare function enableTypeScriptSpecifierResolution(): void;
95
+ /**
96
+ * Refuse a run that named no rule files, saying where to name them.
97
+ *
98
+ * Sets `process.exitCode` rather than throwing: the caller is a CLI entry point
99
+ * that still wants to return normally. Returns whether the run may proceed.
100
+ *
101
+ * `configName` is the dialect's own config filename, because "set them in
102
+ * config" is not an instruction — the two copies of this differed in exactly
103
+ * that word, one naming the file and one not.
104
+ */
105
+ export declare function requireRuleFiles(ruleFiles: readonly string[], configName: string): boolean;
106
+ //# sourceMappingURL=cli-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-config.d.ts","sourceRoot":"","sources":["../src/cli-config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGtD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,8EAA8E;AAC9E,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;IAChB,MAAM,CAAC,EAAE,YAAY,GAAG,MAAM,CAAA;IAC9B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAID,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAO/E;AAOD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,CAiBjE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAM7D;AAiDD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKjE;AAYD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mCAAmC,IAAI,IAAI,CA6C1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAO1F"}
@@ -0,0 +1,231 @@
1
+ import path from 'node:path';
2
+ import fs from 'node:fs';
3
+ import { registerHooks } from 'node:module';
4
+ import { isRecord } from './type-guards.js';
5
+ const FORMATS = new Set(['terminal', 'json', 'github', 'auto']);
6
+ /** The first of `filenames` that exists in the working directory. */
7
+ export function findConfigFile(filenames) {
8
+ const cwd = process.cwd();
9
+ for (const name of filenames) {
10
+ const candidate = path.join(cwd, name);
11
+ if (fs.existsSync(candidate))
12
+ return candidate;
13
+ }
14
+ return undefined;
15
+ }
16
+ /** Strings from an unknown array, dropping anything that is not one. */
17
+ function stringsOf(value) {
18
+ return Array.isArray(value) ? value.filter((v) => typeof v === 'string') : undefined;
19
+ }
20
+ /**
21
+ * The shared config a loaded module claims, validated.
22
+ *
23
+ * Everything is checked rather than trusted: a config file is arbitrary user
24
+ * code and its default export can be any shape at all. An unrecognised `format`
25
+ * is dropped rather than passed through, so a typo falls back to the default
26
+ * instead of reaching a formatter that has no case for it.
27
+ */
28
+ export function extractSharedConfig(mod) {
29
+ if (!isRecord(mod) || !('default' in mod))
30
+ return {};
31
+ const defaultExport = mod.default;
32
+ if (!isRecord(defaultExport))
33
+ return {};
34
+ const config = {};
35
+ const format = defaultExport['format'];
36
+ if (typeof format === 'string' && FORMATS.has(format)) {
37
+ // Narrowed by the set above; the cast-free form is this re-check.
38
+ config.format =
39
+ format === 'terminal' || format === 'json' || format === 'github' ? format : 'auto';
40
+ }
41
+ const rules = stringsOf(defaultExport['rules']);
42
+ if (rules)
43
+ config.rules = rules;
44
+ const watchDirs = stringsOf(defaultExport['watchDirs']);
45
+ if (watchDirs)
46
+ config.watchDirs = watchDirs;
47
+ return config;
48
+ }
49
+ /**
50
+ * Did Node refuse this file for its MODULE FORMAT, rather than for anything the
51
+ * file does?
52
+ *
53
+ * Narrow on purpose. A broad `catch` that fell back to a transpiling loader on
54
+ * any error would re-execute a rule file that had already run — doubling its
55
+ * output — and would hide a genuine syntax error behind a second,
56
+ * differently-worded failure.
57
+ *
58
+ * The condition it detects is bug 0074: the CONSUMER project is
59
+ * `"type": "commonjs"` (what `npm init -y` writes) and the config or rule file
60
+ * uses ESM syntax.
61
+ */
62
+ export function isModuleFormatRefusal(error) {
63
+ if (!(error instanceof SyntaxError))
64
+ return false;
65
+ return (error.message.includes('Cannot use import statement outside a module') ||
66
+ error.message.includes("Unexpected token 'export'"));
67
+ }
68
+ /**
69
+ * The extension substitutions TypeScript performs and Node does not.
70
+ *
71
+ * Under `nodenext`, TypeScript REQUIRES a relative import to name the emitted
72
+ * `.js` file even when the file on disk is `.ts`. Node performs no such
73
+ * substitution, so the specifier that `tsc` demands is the one Node cannot
74
+ * resolve.
75
+ */
76
+ const TS_SPECIFIER_SUBSTITUTIONS = new Map([
77
+ ['.js', ['.ts', '.tsx']],
78
+ ['.jsx', ['.tsx']],
79
+ ['.mjs', ['.mts']],
80
+ ['.cjs', ['.cts']],
81
+ ]);
82
+ /**
83
+ * Is this URL a TypeScript source file — the only kind that writes `.js` for `.ts`?
84
+ *
85
+ * Reads the PATH, not the href. Watch mode cache-busts by appending `?t=<now>`
86
+ * to the entry url, so an href check answers no for exactly the rule file being
87
+ * re-run — measured, and it disabled the substitution in watch mode entirely
88
+ * while every non-watch test stayed green.
89
+ */
90
+ function isTypeScriptSource(url) {
91
+ let pathname;
92
+ try {
93
+ pathname = new URL(url).pathname;
94
+ }
95
+ catch (error) {
96
+ void error;
97
+ return false;
98
+ }
99
+ return ['.ts', '.tsx', '.mts', '.cts'].some((ext) => pathname.endsWith(ext));
100
+ }
101
+ /** The TypeScript file a JS-family URL stands for, if one is on disk. */
102
+ function typeScriptSourceFor(url) {
103
+ for (const [emitted, sources] of TS_SPECIFIER_SUBSTITUTIONS) {
104
+ if (!url.endsWith(emitted))
105
+ continue;
106
+ const stem = url.slice(0, -emitted.length);
107
+ for (const source of sources) {
108
+ const candidate = `${stem}${source}`;
109
+ if (fs.existsSync(new URL(candidate)))
110
+ return candidate;
111
+ }
112
+ }
113
+ return undefined;
114
+ }
115
+ /**
116
+ * Did Node fail to resolve a specifier that TypeScript requires be written that
117
+ * way — a `./sibling.js` whose file on disk is `./sibling.ts`?
118
+ *
119
+ * Narrow for the same reason {@link isModuleFormatRefusal} is, and narrower
120
+ * still: it answers yes only when the TypeScript source is ACTUALLY on disk. A
121
+ * genuinely missing module is still a genuinely missing module, reported the way
122
+ * it always was, and nothing is retried on its behalf.
123
+ *
124
+ * This is bug 0223, reported by a consuming project. `"type": "module"` plus the
125
+ * `.js` specifier is not an exotic combination — it is the one TypeScript
126
+ * mandates for ESM, so every project that splits its rules across files reaches
127
+ * it on the first attempt. The failure is `ERR_MODULE_NOT_FOUND` rather than a
128
+ * `SyntaxError`, which is why the format-refusal predicate above cannot see it.
129
+ */
130
+ export function isTypeScriptSpecifierMiss(error) {
131
+ if (!isRecord(error))
132
+ return false;
133
+ if (error['code'] !== 'ERR_MODULE_NOT_FOUND')
134
+ return false;
135
+ const url = error['url'];
136
+ return typeof url === 'string' && typeScriptSourceFor(url) !== undefined;
137
+ }
138
+ /**
139
+ * Registered at most once per MODULE REGISTRY, which is usually per process.
140
+ *
141
+ * This is module state, so a second registry — the very hazard the loaders that
142
+ * call this exist to avoid — would hold a second flag and register a second
143
+ * hook. Harmless, since the hook is idempotent in effect, but the distinction is
144
+ * worth stating in the one file whose surrounding prose is about registries.
145
+ */
146
+ let specifierResolutionEnabled = false;
147
+ /**
148
+ * Teach this process's loader the substitution, so `./sibling.js` resolves to
149
+ * `./sibling.ts` when that is the file that exists.
150
+ *
151
+ * **`registerHooks`, deliberately, and not a transpiling loader.** The hook is
152
+ * synchronous and in-thread, so a rule file still loads into THIS module
153
+ * registry. That is the invariant plan 0165 and bug 0029 paid for and the reason
154
+ * the alternative fix was rejected: a second registry makes
155
+ * `instanceof ArchRuleError` false and sets `callerAggregatesReports` on one
156
+ * copy while it is read on the other, printing every configuration finding
157
+ * twice. Resolution is the only thing being changed here; execution is
158
+ * untouched.
159
+ *
160
+ * The hook rewrites nothing unless the emitted path is absent AND the
161
+ * TypeScript source is present, so a real `.js` file beside a `.ts` of the same
162
+ * name always wins, and a specifier naming neither is left alone to fail as it
163
+ * would have.
164
+ */
165
+ export function enableTypeScriptSpecifierResolution() {
166
+ if (specifierResolutionEnabled)
167
+ return;
168
+ specifierResolutionEnabled = true;
169
+ registerHooks({
170
+ resolve(specifier, context, nextResolve) {
171
+ if (!specifier.startsWith('./') && !specifier.startsWith('../')) {
172
+ return nextResolve(specifier, context);
173
+ }
174
+ const parentURL = context.parentURL;
175
+ // Only a TypeScript file writes the specifier TypeScript mandates. Without
176
+ // this the hook rewrites for every relative specifier in the process,
177
+ // including from inside `node_modules` — so a dependency shipping source
178
+ // beside a stale build directory would get its `.ts` loaded through
179
+ // strip-only mode instead of the resolution error it expects.
180
+ if (parentURL === undefined || !isTypeScriptSource(parentURL)) {
181
+ return nextResolve(specifier, context);
182
+ }
183
+ // A non-hierarchical parent (`data:`, `node:`) makes this throw
184
+ // ERR_INVALID_URL, which inside a resolve hook would convert Node's own
185
+ // diagnostic into a TypeError attributed to us.
186
+ let emitted;
187
+ try {
188
+ emitted = new URL(specifier, parentURL);
189
+ }
190
+ catch (error) {
191
+ void error;
192
+ return nextResolve(specifier, context);
193
+ }
194
+ if (emitted.protocol !== 'file:' || fs.existsSync(emitted)) {
195
+ return nextResolve(specifier, context);
196
+ }
197
+ const source = typeScriptSourceFor(emitted.href);
198
+ if (source === undefined)
199
+ return nextResolve(specifier, context);
200
+ // Carry the parent's query onto the rewrite. Watch mode busts Node's
201
+ // module cache by appending `?t=<now>` to the ENTRY url only; a statically
202
+ // imported sibling keys on its own url, which carries no query, so it is
203
+ // evaluated once and reused for the life of the session. Measured: edit a
204
+ // shared glob in the sibling and the re-run reports green computed from
205
+ // the code you just replaced, with no signal. Propagating the query makes
206
+ // the whole graph fresh, and is a no-op outside watch because there is no
207
+ // query to carry.
208
+ const rewritten = new URL(source);
209
+ rewritten.search = new URL(parentURL).search;
210
+ return nextResolve(rewritten.href, context);
211
+ },
212
+ });
213
+ }
214
+ /**
215
+ * Refuse a run that named no rule files, saying where to name them.
216
+ *
217
+ * Sets `process.exitCode` rather than throwing: the caller is a CLI entry point
218
+ * that still wants to return normally. Returns whether the run may proceed.
219
+ *
220
+ * `configName` is the dialect's own config filename, because "set them in
221
+ * config" is not an instruction — the two copies of this differed in exactly
222
+ * that word, one naming the file and one not.
223
+ */
224
+ export function requireRuleFiles(ruleFiles, configName) {
225
+ if (ruleFiles.length > 0)
226
+ return true;
227
+ console.error(`Error: No rule files specified. Pass rule files as arguments or set them in ${configName}.`);
228
+ process.exitCode = 1;
229
+ return false;
230
+ }
231
+ //# sourceMappingURL=cli-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-config.js","sourceRoot":"","sources":["../src/cli-config.ts"],"names":[],"mappings":"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"}