@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.
- package/README.md +94 -1
- package/dist/baseline-generator.d.ts +9 -0
- package/dist/baseline-generator.d.ts.map +1 -1
- package/dist/baseline-generator.js +9 -0
- package/dist/baseline-generator.js.map +1 -1
- package/dist/baseline.d.ts +1 -1
- package/dist/cardinality.d.ts.map +1 -1
- package/dist/cardinality.js +20 -5
- package/dist/cardinality.js.map +1 -1
- package/dist/cli-config.d.ts +106 -0
- package/dist/cli-config.d.ts.map +1 -0
- package/dist/cli-config.js +231 -0
- package/dist/cli-config.js.map +1 -0
- package/dist/collect-result.d.ts +94 -0
- package/dist/collect-result.d.ts.map +1 -0
- package/dist/collect-result.js +142 -0
- package/dist/collect-result.js.map +1 -0
- package/dist/combinators.d.ts +14 -0
- package/dist/combinators.d.ts.map +1 -1
- package/dist/combinators.js +53 -16
- package/dist/combinators.js.map +1 -1
- package/dist/condition.d.ts +37 -0
- package/dist/condition.d.ts.map +1 -1
- package/dist/condition.js +48 -1
- package/dist/condition.js.map +1 -1
- package/dist/correspondence.d.ts +30 -0
- package/dist/correspondence.d.ts.map +1 -1
- package/dist/correspondence.js +36 -1
- package/dist/correspondence.js.map +1 -1
- package/dist/dedupe-config-findings.d.ts.map +1 -1
- package/dist/dedupe-config-findings.js +27 -0
- package/dist/dedupe-config-findings.js.map +1 -1
- package/dist/diff-aware.d.ts +8 -9
- package/dist/diff-aware.d.ts.map +1 -1
- package/dist/diff-aware.js +38 -17
- package/dist/diff-aware.js.map +1 -1
- package/dist/emitter-findings.d.ts +167 -0
- package/dist/emitter-findings.d.ts.map +1 -0
- package/dist/emitter-findings.js +237 -0
- package/dist/emitter-findings.js.map +1 -0
- package/dist/errors.d.ts +48 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +61 -0
- package/dist/errors.js.map +1 -1
- package/dist/exclusion-comments.d.ts +36 -1
- package/dist/exclusion-comments.d.ts.map +1 -1
- package/dist/exclusion-comments.js +185 -37
- package/dist/exclusion-comments.js.map +1 -1
- package/dist/execute-rule.d.ts +12 -3
- package/dist/execute-rule.d.ts.map +1 -1
- package/dist/execute-rule.js +184 -7
- package/dist/execute-rule.js.map +1 -1
- package/dist/file-walk.d.ts +22 -0
- package/dist/file-walk.d.ts.map +1 -0
- package/dist/file-walk.js +51 -0
- package/dist/file-walk.js.map +1 -0
- package/dist/format-json.d.ts +13 -0
- package/dist/format-json.d.ts.map +1 -1
- package/dist/format-json.js +24 -0
- package/dist/format-json.js.map +1 -1
- package/dist/index.d.ts +14 -46
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -41
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +55 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +92 -0
- package/dist/internal.js.map +1 -0
- package/dist/mask-non-comment.d.ts +49 -0
- package/dist/mask-non-comment.d.ts.map +1 -0
- package/dist/mask-non-comment.js +261 -0
- package/dist/mask-non-comment.js.map +1 -0
- package/dist/owns-empty-discovery.d.ts.map +1 -1
- package/dist/owns-empty-discovery.js +12 -4
- package/dist/owns-empty-discovery.js.map +1 -1
- package/dist/path-suffix.d.ts +57 -0
- package/dist/path-suffix.d.ts.map +1 -0
- package/dist/path-suffix.js +73 -0
- package/dist/path-suffix.js.map +1 -0
- package/dist/predicate.d.ts +12 -0
- package/dist/predicate.d.ts.map +1 -1
- package/dist/predicate.js +20 -1
- package/dist/predicate.js.map +1 -1
- package/dist/preset-dispatch.d.ts +6 -34
- package/dist/preset-dispatch.d.ts.map +1 -1
- package/dist/preset-dispatch.js +30 -52
- package/dist/preset-dispatch.js.map +1 -1
- package/dist/report.d.ts +31 -7
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +174 -15
- package/dist/report.js.map +1 -1
- package/dist/rule-builder-like.d.ts +8 -2
- package/dist/rule-builder-like.d.ts.map +1 -1
- package/dist/rule-builder.d.ts +15 -0
- package/dist/rule-builder.d.ts.map +1 -1
- package/dist/rule-builder.js +41 -36
- package/dist/rule-builder.js.map +1 -1
- package/dist/rule-description.d.ts +50 -0
- package/dist/rule-description.d.ts.map +1 -1
- package/dist/rule-description.js +58 -0
- package/dist/rule-description.js.map +1 -1
- package/dist/selection-memo.d.ts +1 -3
- package/dist/selection-memo.d.ts.map +1 -1
- package/dist/selection-memo.js +1 -3
- package/dist/selection-memo.js.map +1 -1
- package/dist/silent-exclusion.d.ts +12 -0
- package/dist/silent-exclusion.d.ts.map +1 -1
- package/dist/silent-exclusion.js +22 -0
- package/dist/silent-exclusion.js.map +1 -1
- package/dist/terminal-builder.d.ts +29 -15
- package/dist/terminal-builder.d.ts.map +1 -1
- package/dist/terminal-builder.js +97 -51
- package/dist/terminal-builder.js.map +1 -1
- package/dist/vacuity-findings.d.ts +0 -6
- package/dist/vacuity-findings.d.ts.map +1 -1
- package/dist/vacuity-findings.js +27 -57
- package/dist/vacuity-findings.js.map +1 -1
- package/dist/violation.d.ts +22 -1
- package/dist/violation.d.ts.map +1 -1
- package/dist/violation.js.map +1 -1
- package/dist/watch.d.ts +71 -0
- package/dist/watch.d.ts.map +1 -0
- package/dist/watch.js +129 -0
- package/dist/watch.js.map +1 -0
- 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
|
|
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
|
|
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
|
|
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"}
|
package/dist/baseline.d.ts
CHANGED
|
@@ -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":"
|
|
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"}
|
package/dist/cardinality.js
CHANGED
|
@@ -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
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
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
|
/**
|
package/dist/cardinality.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cardinality.js","sourceRoot":"","sources":["../src/cardinality.ts"],"names":[],"mappings":"AAAA
|
|
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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"}
|