@taskless/cli 0.10.2 → 0.11.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 +65 -195
- package/assets/reference.json +213 -0
- package/dist/binary-DSACXL6n.js +107 -0
- package/dist/index.js +14470 -17446
- package/dist/layout/index.d.ts +31 -0
- package/dist/layout.js +43 -0
- package/dist/node/runtimes/index.d.ts +102 -0
- package/dist/node/runtimes.js +10 -0
- package/dist/prompts/index.d.ts +103 -0
- package/dist/prompts/recipes.d.ts +114 -0
- package/dist/prompts.js +53 -0
- package/dist/recipes-w68swLg4.js +2662 -0
- package/dist/rules/ast-grep-binary.d.ts +26 -0
- package/dist/rules/capabilities.d.ts +351 -0
- package/dist/rules/constraints.d.ts +132 -0
- package/dist/rules/layout.d.ts +152 -0
- package/dist/rules/platform-binary.d.ts +113 -0
- package/dist/rules/vale/binary.d.ts +35 -0
- package/dist/schemas/index.d.ts +93 -0
- package/dist/schemas/rules-create.d.ts +19 -0
- package/dist/schemas/rules-improve.d.ts +22 -0
- package/dist/schemas/rules-verify.d.ts +67 -0
- package/dist/schemas/verify-test.d.ts +22 -0
- package/dist/schemas-OhdGAhu_.js +4512 -0
- package/dist/schemas.js +65 -0
- package/dist/types/errors.d.ts +20 -0
- package/dist/util/invocation.d.ts +42 -0
- package/dist/verify-test-BaZPwJqC.js +34 -0
- package/package.json +46 -16
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PlatformBinarySpec } from "./platform-binary";
|
|
2
|
+
/**
|
|
3
|
+
* ast-grep's per-platform packaging, as the shared resolver understands it.
|
|
4
|
+
*
|
|
5
|
+
* `toolchainSuffix: true` is what produces `@ast-grep/cli-linux-x64-gnu` and
|
|
6
|
+
* `-win32-x64-msvc`. The Vale packages set it false; see
|
|
7
|
+
* {@link PlatformBinarySpec} for why that distinction is load-bearing.
|
|
8
|
+
*
|
|
9
|
+
* Both `ast-grep` and `sg` are listed because the wrapper declares them as bin
|
|
10
|
+
* entries for the same target, so either may be what got linked. `ast-grep`
|
|
11
|
+
* leads because it is the name the platform package ships the binary under; the
|
|
12
|
+
* resolver reverses the list at the link-based tiers, so `sg` is still tried
|
|
13
|
+
* first there and named in the PATH advice, as it was before the shared
|
|
14
|
+
* resolver existed.
|
|
15
|
+
*
|
|
16
|
+
* ## Why this sits in its own module rather than in `scan.ts`
|
|
17
|
+
*
|
|
18
|
+
* The spec is data: five fields describing how a package is named and how the
|
|
19
|
+
* binary identifies itself. `scan.ts` is the scanner — it reaches
|
|
20
|
+
* `rules/engines.ts`, and through it `node:fs/promises` and the CLI's error
|
|
21
|
+
* type. `@taskless/cli/node/runtimes` publishes this spec so a consumer can
|
|
22
|
+
* resolve the same binary the CLI executes, and a consumer that wants a path
|
|
23
|
+
* has no business loading a scanner to get one. Vale's spec is already a leaf
|
|
24
|
+
* for the same reason: `rules/vale/binary.ts` imports nothing but the resolver.
|
|
25
|
+
*/
|
|
26
|
+
export declare const AST_GREP_BINARY: PlatformBinarySpec;
|
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the two local engines can actually read.
|
|
3
|
+
*
|
|
4
|
+
* PURE DATA, DELIBERATELY. This module is imported by `src/prompts/recipes.ts`,
|
|
5
|
+
* which is a Worker-safe library surface — no citty, no telemetry, no
|
|
6
|
+
* filesystem, no network — and `assert-prompts-graph` in `vite.config.ts`
|
|
7
|
+
* fails the build if the prompts chunk's graph reaches a host capability. So
|
|
8
|
+
* nothing here may read `package.json`, spawn a binary, or import a node
|
|
9
|
+
* builtin. The values are transcribed once, here, and pinned by tests that do
|
|
10
|
+
* spawn the binaries.
|
|
11
|
+
*
|
|
12
|
+
* THE BINARIES ARE THE ONLY AUTHORITY, and neither of them can be asked at
|
|
13
|
+
* render time:
|
|
14
|
+
*
|
|
15
|
+
* - `src/generated/ast-grep-rule-schema.json` types `$defs.Language` as a bare
|
|
16
|
+
* string with no enum — its only hint is an `example` reading `"typescript"`,
|
|
17
|
+
* which is not even the canonical spelling — so the vendored schema cannot
|
|
18
|
+
* answer the question. `verify` answers it from the constants below instead
|
|
19
|
+
* (see `validateLanguage` in `verify.ts`).
|
|
20
|
+
* - `detect --json` reports the *repository's* languages in a different
|
|
21
|
+
* vocabulary — `C++` where ast-grep says `Cpp` — and says nothing about what
|
|
22
|
+
* an engine can parse.
|
|
23
|
+
* - Vale self-reports nothing at all. Its reach was measured by probing the
|
|
24
|
+
* shipped binary, which is why the Vale constants below carry a probe-shaped
|
|
25
|
+
* contract test rather than a parsed capability listing.
|
|
26
|
+
*
|
|
27
|
+
* BUMPING AN ENGINE IS A ONE-FILE EDIT. Change the version constant and the
|
|
28
|
+
* list beside it; `test/ast-grep-vendor-contract.test.ts` and
|
|
29
|
+
* `test/vale-vendor-contract.test.ts` fail until the two agree, which is the
|
|
30
|
+
* whole point of transcribing rather than describing. See taskless/cli#151 for
|
|
31
|
+
* the routing miss this exists to prevent: two GitHub Actions workflow rules
|
|
32
|
+
* were escalated to `runtime` because nothing said ast-grep parses YAML.
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* The ast-grep release pinned in `packages/cli/package.json`, both for
|
|
36
|
+
* `@ast-grep/cli` and for every `@ast-grep/cli-<platform>` optional dependency.
|
|
37
|
+
*
|
|
38
|
+
* Pinned against the binary by `test/ast-grep-vendor-contract.test.ts`
|
|
39
|
+
* ("engine capabilities" → "reports the pinned version").
|
|
40
|
+
*/
|
|
41
|
+
export declare const AST_GREP_VERSION = "0.45.2";
|
|
42
|
+
/**
|
|
43
|
+
* Every language ast-grep can parse, verbatim from
|
|
44
|
+
* `sg run -h` → `Supported languages are: [...]` at
|
|
45
|
+
* {@link AST_GREP_VERSION}.
|
|
46
|
+
*
|
|
47
|
+
* SPELLINGS ARE ast-grep's, NOT ours and not `detect`'s. `Cpp`, `CSharp`,
|
|
48
|
+
* `JavaScript`, `Tsx` — a rule's `language:` field is handed to ast-grep
|
|
49
|
+
* unchanged, so the binary has the final opinion. MEASURED at 0.45.2: it
|
|
50
|
+
* accepts more than this list — case variants and a fixed set of extension
|
|
51
|
+
* aliases, both enumerated in {@link AST_GREP_LANGUAGE_ALIASES} — so an
|
|
52
|
+
* off-list spelling is not on its own an error. The two real failures are a
|
|
53
|
+
* name ast-grep does not know at all (`C#`), which aborts config parsing so
|
|
54
|
+
* every rule goes unreported, and a valid name for the wrong parser
|
|
55
|
+
* (`TypeScript` over `.tsx`), which reports nothing and reads as a clean
|
|
56
|
+
* codebase. `verify` catches both; see `verify.ts`.
|
|
57
|
+
*
|
|
58
|
+
* Pinned by set-equality against the binary in
|
|
59
|
+
* `test/ast-grep-vendor-contract.test.ts`, so a version bump that adds or drops
|
|
60
|
+
* a language fails there rather than silently narrowing what the router
|
|
61
|
+
* believes is buildable locally.
|
|
62
|
+
*/
|
|
63
|
+
export declare const AST_GREP_LANGUAGES: readonly ["Bash", "C", "Cpp", "CSharp", "Css", "Dart", "Elixir", "Go", "Haskell", "Hcl", "Html", "Java", "JavaScript", "Json", "Kotlin", "Lua", "Markdown", "Nix", "Php", "Python", "Ruby", "Rust", "Scala", "Solidity", "Swift", "Tsx", "TypeScript", "Yaml"];
|
|
64
|
+
/** One of the spellings {@link AST_GREP_LANGUAGES} lists, canonically cased. */
|
|
65
|
+
export type AstGrepLanguage = (typeof AST_GREP_LANGUAGES)[number];
|
|
66
|
+
/**
|
|
67
|
+
* The spellings ast-grep also accepts that are not on the canonical list,
|
|
68
|
+
* mapped to the language each resolves to.
|
|
69
|
+
*
|
|
70
|
+
* Keys are lowercase because ast-grep's own matching is case-insensitive:
|
|
71
|
+
* `TYPESCRIPT`, `Cs` and `GOLANG` all resolve at 0.45.2. That makes the whole
|
|
72
|
+
* accepted vocabulary "the canonical list plus these, compared lowercased",
|
|
73
|
+
* which is what {@link resolveAstGrepLanguage} implements.
|
|
74
|
+
*
|
|
75
|
+
* Every value here was probed through a real config, because that is the only
|
|
76
|
+
* thing a rule file is ever fed to. That is deliberate: `sg run --lang` is a
|
|
77
|
+
* SEPARATE vocabulary and cannot stand in for this one. MEASURED at 0.45.2,
|
|
78
|
+
* the two agree on `C++` and `cxx` (both accepted) and on `C#` (both
|
|
79
|
+
* rejected), but `--lang` rejects with clap's own `is not supported!` before
|
|
80
|
+
* a rule is ever read, so it exercises a different code path and is not
|
|
81
|
+
* evidence about `language:`. At 0.41.0 they diverged outright: `--lang C++`
|
|
82
|
+
* was rejected while `language: C++` parsed. Nothing here probes `--lang`.
|
|
83
|
+
*
|
|
84
|
+
* THIS IS THE ONE LIST HERE THE BINARY CANNOT BE ASKED TO ENUMERATE. `sg run
|
|
85
|
+
* -h` prints the canonical list, so `AST_GREP_LANGUAGES` above is checked by
|
|
86
|
+
* set-equality against it; nothing prints the aliases. Each entry is instead
|
|
87
|
+
* pinned by *probing*, in the "language aliases" suite of
|
|
88
|
+
* `test/ast-grep-vendor-contract.test.ts`: every key is fed to the binary in a
|
|
89
|
+
* config and the resolution is read back out of the scan stream's own
|
|
90
|
+
* `language` field — ast-grep reports the canonical name it settled on, so the
|
|
91
|
+
* mapping is the binary's answer rather than ours. The same suite feeds a
|
|
92
|
+
* sweep of near-misses (`h`, `mjs`, `sh`, `tf`, `csx`) and asserts they are
|
|
93
|
+
* rejected, so a bump that ADDS an alias fails there too.
|
|
94
|
+
*
|
|
95
|
+
* Whitespace is not folded, deliberately: `language: "ts "` is rejected by the
|
|
96
|
+
* binary, so accepting it here would pass a rule that cannot run.
|
|
97
|
+
*/
|
|
98
|
+
export declare const AST_GREP_LANGUAGE_ALIASES: Readonly<Record<string, AstGrepLanguage>>;
|
|
99
|
+
/**
|
|
100
|
+
* The language ast-grep would parse `spelling` as, or `undefined` if it would
|
|
101
|
+
* reject the config outright.
|
|
102
|
+
*
|
|
103
|
+
* `undefined` is the fatal case, not a stylistic one: an unrecognized name
|
|
104
|
+
* fails `SgLang` deserialization, which aborts parsing of the single config
|
|
105
|
+
* Taskless assembles for the run — so every *other* sg rule goes unreported
|
|
106
|
+
* with it.
|
|
107
|
+
*/
|
|
108
|
+
export declare function resolveAstGrepLanguage(spelling: string): AstGrepLanguage | undefined;
|
|
109
|
+
/**
|
|
110
|
+
* The `.ts` / `.tsx` split — the one pair of ast-grep languages that share a
|
|
111
|
+
* family and read disjoint file extensions.
|
|
112
|
+
*
|
|
113
|
+
* MEASURED at 0.45.2: a `TypeScript` rule over a `.tsx` tree exits zero having
|
|
114
|
+
* matched nothing, and a `Tsx` rule scans `.tsx` only. That is the quiet
|
|
115
|
+
* failure of the two, because "no findings" is exactly what a clean codebase
|
|
116
|
+
* looks like. Pinned by "treats Tsx and TypeScript as different parsers, not
|
|
117
|
+
* aliases" in `test/ast-grep-vendor-contract.test.ts`.
|
|
118
|
+
*
|
|
119
|
+
* Kept to this pair deliberately. Every other language's extensions would be a
|
|
120
|
+
* second vendored table with no measured backing, and the trap only exists
|
|
121
|
+
* where two languages look like spellings of one thing.
|
|
122
|
+
*/
|
|
123
|
+
export declare const AST_GREP_TSX_SPLIT: Readonly<Partial<Record<AstGrepLanguage, string>>>;
|
|
124
|
+
/**
|
|
125
|
+
* The Vale release carried by the `@taskless/vale-<platform>` packages pinned
|
|
126
|
+
* in `packages/cli/package.json`. Their npm versions append a build stamp,
|
|
127
|
+
* `<valeVersion>-<yyyymmddhhmmss>`, minted per publish by
|
|
128
|
+
* `.github/workflows/release-vale.yml`; this is the version Vale itself
|
|
129
|
+
* reports.
|
|
130
|
+
*
|
|
131
|
+
* The SHAPE rather than an example, deliberately. A literal stamp here has to
|
|
132
|
+
* be hand-carried on every bump, and it has gone one release out of date twice
|
|
133
|
+
* now, which is worse than no example: it reads as the current pin and is not
|
|
134
|
+
* one. The real value lives in `packages/cli/package.json`, where a reader can
|
|
135
|
+
* see all six at once and cannot be told a stale one.
|
|
136
|
+
*
|
|
137
|
+
* Pinned against the binary by `test/vale-vendor-contract.test.ts`
|
|
138
|
+
* ("engine capabilities" → "reports the pinned version").
|
|
139
|
+
*/
|
|
140
|
+
export declare const VALE_VERSION = "3.20.0";
|
|
141
|
+
/**
|
|
142
|
+
* Which tier Vale routes an extension to.
|
|
143
|
+
*
|
|
144
|
+
* `converter:<program>` carries the program's own name in the tier, so one
|
|
145
|
+
* table row states both the tier and the thing a user would install. The name
|
|
146
|
+
* is the one Vale prints in its `E100` text, because that is the string a
|
|
147
|
+
* reader will search for.
|
|
148
|
+
*/
|
|
149
|
+
export type ValeFormatTier =
|
|
150
|
+
/** Parsed in-process: the document is prose, its own syntax is skipped. */
|
|
151
|
+
"markup"
|
|
152
|
+
/** Parsed in-process: comment text is linted, the code body is invisible. */
|
|
153
|
+
| "comment"
|
|
154
|
+
/** No parser: the whole file is linted as one block of prose. */
|
|
155
|
+
| "plaintext"
|
|
156
|
+
/** Vale shells out to a program the `@taskless/vale-*` packages do not ship. */
|
|
157
|
+
| `converter:${string}`;
|
|
158
|
+
/**
|
|
159
|
+
* EVERY MEASURED VALE EXTENSION, AND ITS TIER. THE ONLY TABLE.
|
|
160
|
+
*
|
|
161
|
+
* Adding an extension is one line here; every list, glob, notice and test below
|
|
162
|
+
* derives from this record, so there is no second place to keep in step. Two
|
|
163
|
+
* branches once measured this independently and produced two tables that
|
|
164
|
+
* disagreed about six extensions — that is what this single record exists to
|
|
165
|
+
* make impossible.
|
|
166
|
+
*
|
|
167
|
+
* MEASURED, NOT DOCUMENTED, AND MEASURED BY A DISCRIMINATING PROBE. Ordinary
|
|
168
|
+
* prose fires in all three readable tiers, so it can never separate them. Each
|
|
169
|
+
* tier is pinned by the property only that tier has, in
|
|
170
|
+
* `test/vale-vendor-contract.test.ts`:
|
|
171
|
+
*
|
|
172
|
+
* - **markup** — a construct only a real parser skips yields ZERO (a fenced
|
|
173
|
+
* code block, an Org `#` line, an HTML comment).
|
|
174
|
+
* - **comment** — the token in a comment yields one finding and the same token
|
|
175
|
+
* on a bare non-comment line yields ZERO. A type that fires on both is the
|
|
176
|
+
* plaintext fallback wearing a code extension.
|
|
177
|
+
* - **plaintext** — a bare line yields a finding. Listed only where the tier is
|
|
178
|
+
* surprising: `.tex`, `.mkd` and `.mkdn` all look like markup and are not.
|
|
179
|
+
* Everything unnamed lands here too, which is why this tier does not need to
|
|
180
|
+
* be exhaustive.
|
|
181
|
+
* - **converter** — a non-zero exit whose output carries `E100` and the
|
|
182
|
+
* program's name.
|
|
183
|
+
*
|
|
184
|
+
* Measured spellings, not families. `.mdown` is native Markdown and `.mkd` and
|
|
185
|
+
* `.mkdn` are not; `.asc` is a third AsciiDoc spelling that crashes exactly
|
|
186
|
+
* like `.adoc`; `.ditamap` is plaintext while `.dita` needs `dita`. Case is
|
|
187
|
+
* part of the key — `.r` and `.R` were both measured, `.PY` was measured and is
|
|
188
|
+
* not comment-aware. Add a row only after probing it; the contract test refuses
|
|
189
|
+
* to take one on faith.
|
|
190
|
+
*
|
|
191
|
+
* A VERSION BUMP INVALIDATES THIS TABLE — RE-MEASURE THE WHOLE OF IT. The tiers
|
|
192
|
+
* are a property of {@link VALE_VERSION}'s binary, and the dangerous direction
|
|
193
|
+
* is a format Vale *learns*: an extension missing from this table is read as
|
|
194
|
+
* plain text today, but the moment Vale routes it to a converter the same
|
|
195
|
+
* omission is a crash that takes down every Vale rule in the run.
|
|
196
|
+
*
|
|
197
|
+
* NOTHING MOVED ACROSS 3.19.0 → 3.20.0, AND THE SECOND HALF OF THAT CLAIM IS
|
|
198
|
+
* THE ONE THAT COST SOMETHING. Every row below was re-probed against the
|
|
199
|
+
* 3.20.0 binary and none of them moved, which this table can report. It cannot
|
|
200
|
+
* report a format Vale *learned*, so that direction was checked at the source
|
|
201
|
+
* instead: the v3.19.0...v3.20.0 tree adds no `internal/lint/<format>.go` and
|
|
202
|
+
* no `internal/lint/code/<lang>.go`, and every existing one of those files
|
|
203
|
+
* changes by a single import line from the org rename. No format was learned,
|
|
204
|
+
* so there is no new row to add. Do that check on the next bump too — a green
|
|
205
|
+
* table is silence about the dangerous direction, not evidence against it.
|
|
206
|
+
*
|
|
207
|
+
* THE TABLE ALSO HELD ACROSS 3.18.0 → 3.19.0, AND THAT IS NOT THE SAME AS THE
|
|
208
|
+
* BUMP BEING FREE. Every row below was re-probed against the 3.19.0 binary and
|
|
209
|
+
* not one of them moved. What moved was a format Vale *learned*, which is
|
|
210
|
+
* precisely the case a table of existing rows cannot report: `.ex` and `.exs`
|
|
211
|
+
* gained comment and doc-attribute extraction, so they left the unnamed
|
|
212
|
+
* plaintext fallback for the `comment` tier and are new rows below.
|
|
213
|
+
*
|
|
214
|
+
* Read that direction carefully, because it is a narrowing rather than a gain.
|
|
215
|
+
* On 3.18.0 an Elixir file was linted as one block of prose, so a rule matching
|
|
216
|
+
* `[*.ex]` fired on identifiers and string literals as readily as on comments.
|
|
217
|
+
* On 3.19.0 the code body is invisible and only comments and `@doc` attributes
|
|
218
|
+
* are read. Findings disappear, no error is raised, and nothing but a re-probe
|
|
219
|
+
* would have told us. A format Vale learns is never a no-op: the benign version
|
|
220
|
+
* of it is this one, and the dangerous version is a converter (see `.typ`).
|
|
221
|
+
*
|
|
222
|
+
* `.mdx` stayed `markup` and changed underneath the tier: a JSX element's
|
|
223
|
+
* children are now read as the Markdown they are, so a Vale rule covers prose
|
|
224
|
+
* inside `<Steps>` or `<Aside>` that it previously skipped, and those children
|
|
225
|
+
* carry the element name as a `text.class.<name>` scope. The tier is the wrong
|
|
226
|
+
* instrument for that kind of change — it says a parser exists, not what the
|
|
227
|
+
* parser sees — which is the second reason a bump needs more than this table.
|
|
228
|
+
*
|
|
229
|
+
* The 3.17.1 → 3.18.0 bump is what the dangerous case looks like in practice.
|
|
230
|
+
* Every row was re-probed against the 3.18.0 binary then too, and eight moved,
|
|
231
|
+
* in three different directions — which is why "re-measure" is not boilerplate:
|
|
232
|
+
*
|
|
233
|
+
* - `.mdx` gained a native parser: `converter:mdx2vast` → `markup`. It is
|
|
234
|
+
* supported now, and `[*.{md,mdx}]` is a legitimate matcher again.
|
|
235
|
+
* - `.typ` gained a parser that shells out to `typst2vast`
|
|
236
|
+
* (https://docs.vale.sh/formats/typst): `plaintext` →
|
|
237
|
+
* `converter:typst2vast`. That is the dangerous direction — 3.17.1 read it as
|
|
238
|
+
* prose, and the same row on 3.18.0 crashes the run. It stays unsupported
|
|
239
|
+
* permanently, since we do not support formats needing an external program.
|
|
240
|
+
* - `.rmd` gained a real Markdown parser, so it left the "looks like markup and
|
|
241
|
+
* is not" list above: `plaintext` → `markup`.
|
|
242
|
+
* - `.qml` and `.scss` gained parsers that see their comments: `plaintext` →
|
|
243
|
+
* `comment`. Vale's docs had claimed both for years; on 3.17.1 the claim was
|
|
244
|
+
* measurably false and on 3.18.0 it is true.
|
|
245
|
+
* - `.qmd` (Quarto) and `.myst` (MyST) measured as `markup`, and `.qdoc` as
|
|
246
|
+
* `comment` — QDoc documentation lives in a doc-comment block, so it is
|
|
247
|
+
* comment extraction rather than the markup tier a first reading of the
|
|
248
|
+
* release notes suggests, and probing it with bare prose reads as no support
|
|
249
|
+
* at all. All three are new rows, none of them reachable on 3.17.1.
|
|
250
|
+
*
|
|
251
|
+
* PHP also changed without the release notes saying so: comment extraction now
|
|
252
|
+
* needs a real `<?php` tag, where 3.17.1 linted a bare `//` comment without
|
|
253
|
+
* one. The tier did not move, but the probe had to. Re-probe every row on the
|
|
254
|
+
* next bump, by the discriminating property and by each language's own comment
|
|
255
|
+
* syntax — a wrong delimiter reads exactly like absent support.
|
|
256
|
+
*/
|
|
257
|
+
export declare const VALE_FORMAT_TIERS: Readonly<Record<string, ValeFormatTier>>;
|
|
258
|
+
/**
|
|
259
|
+
* Extensions Vale parses as markup: the whole document is prose, and the
|
|
260
|
+
* format's own non-prose constructs are excluded.
|
|
261
|
+
*
|
|
262
|
+
* The HTML entries carry a consequence worth stating to an author: prose
|
|
263
|
+
* outside an element is not linted, so a bare sentence in a `.html` file yields
|
|
264
|
+
* nothing.
|
|
265
|
+
*/
|
|
266
|
+
export declare const VALE_MARKUP_EXTENSIONS: readonly string[];
|
|
267
|
+
/**
|
|
268
|
+
* Extensions where Vale lints **comment text only** and ignores the code body.
|
|
269
|
+
*/
|
|
270
|
+
export declare const VALE_COMMENT_EXTENSIONS: readonly string[];
|
|
271
|
+
/**
|
|
272
|
+
* Extensions measured into the plaintext fallback whose spelling suggests
|
|
273
|
+
* otherwise.
|
|
274
|
+
*
|
|
275
|
+
* Not exhaustive and not meant to be — every unnamed extension is plaintext
|
|
276
|
+
* too. These are the ones an author would reasonably assume were parsed, so
|
|
277
|
+
* they are worth naming in a recipe rather than leaving to "everything else".
|
|
278
|
+
*/
|
|
279
|
+
export declare const VALE_PLAINTEXT_EXTENSIONS: readonly string[];
|
|
280
|
+
/**
|
|
281
|
+
* The converter each converter-dependent extension needs, keyed by extension.
|
|
282
|
+
*
|
|
283
|
+
* The lookup `rules/vale/formats.ts` uses to name a converter in the skip
|
|
284
|
+
* notice. Keys are lowercase because every measured converter format is; a
|
|
285
|
+
* caller comparing an extension off the filesystem must lowercase it first, or
|
|
286
|
+
* `README.RST` becomes a crash on case-insensitive platforms only.
|
|
287
|
+
*/
|
|
288
|
+
export declare const VALE_CONVERTER_BY_EXTENSION: Readonly<Record<string, string>>;
|
|
289
|
+
/** A format Vale supports upstream but cannot read without an external tool. */
|
|
290
|
+
export interface ValeConverterFormat {
|
|
291
|
+
/** Extensions Vale routes through this converter. */
|
|
292
|
+
extensions: readonly string[];
|
|
293
|
+
/** The executable or artifact Vale looks for, named in its own E100 text. */
|
|
294
|
+
converter: string;
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* Formats that fail rather than lint, because Vale shells out to a converter
|
|
298
|
+
* this CLI does not ship.
|
|
299
|
+
*
|
|
300
|
+
* SAY THIS ACCURATELY: Vale supports these formats. What is missing is the
|
|
301
|
+
* external program it delegates the parse to. The failure is environmental, and
|
|
302
|
+
* describing it as "Vale does not support reStructuredText" sends an author
|
|
303
|
+
* looking for the wrong fix.
|
|
304
|
+
*
|
|
305
|
+
* The blast radius is what makes this worth surfacing at routing time rather
|
|
306
|
+
* than at authoring time: Vale exits 2 with an `E100` runtime error and
|
|
307
|
+
* abandons the run, and `--no-exit` does not suppress it. One `.typ` file
|
|
308
|
+
* caught by a rule's glob takes down the entire Vale pass, including every
|
|
309
|
+
* other rule and every other file — so `[*.{md,typ}]` is not a slightly wider
|
|
310
|
+
* matcher than `[*.md]`, it is a broken one. (`[*.{md,mdx}]` was that example
|
|
311
|
+
* until 3.18.0 gave MDX a native parser — the membership of this tier is a
|
|
312
|
+
* property of {@link VALE_VERSION}, and so is the worked example.)
|
|
313
|
+
*/
|
|
314
|
+
export declare const VALE_CONVERTER_DEPENDENT: readonly ValeConverterFormat[];
|
|
315
|
+
/**
|
|
316
|
+
* Vale's checker tag per converter-dependent extension, from the `E100` text.
|
|
317
|
+
*
|
|
318
|
+
* This is the host-independent half of the failure. The prose after the tag is
|
|
319
|
+
* not: `.xml` reports `xsltproc not found` where the program is absent and
|
|
320
|
+
* `no XSLT transform provided` where it is present, and the two are split by
|
|
321
|
+
* platform — macOS ships `/usr/bin/xsltproc`, the Linux CI image does not. A
|
|
322
|
+
* contract test that matched on the program name therefore passed locally and
|
|
323
|
+
* failed in CI, which is how this list came to exist.
|
|
324
|
+
*
|
|
325
|
+
* `.xml` is also the one entry whose converter is not sufficient on its own. An
|
|
326
|
+
* XSLT transform is document-specific, so there is no default to ship and
|
|
327
|
+
* installing `xsltproc` does not make `.xml` lintable — unlike `asciidoctor`,
|
|
328
|
+
* which genuinely fixes `.adoc`. That is why its `converter` names the
|
|
329
|
+
* stylesheet as well as the program.
|
|
330
|
+
*/
|
|
331
|
+
export declare const VALE_CONVERTER_CHECKERS: Readonly<Record<string, string>>;
|
|
332
|
+
/** Every converter-dependent extension, flattened. */
|
|
333
|
+
export declare const VALE_CONVERTER_DEPENDENT_EXTENSIONS: readonly string[];
|
|
334
|
+
/** `Bash, C, Cpp, …` — the ast-grep language list as recipe prose. */
|
|
335
|
+
export declare function astGrepLanguageList(): string;
|
|
336
|
+
/** `.htm, .html, …` — Vale's markup extensions as recipe prose. */
|
|
337
|
+
export declare function valeMarkupList(): string;
|
|
338
|
+
/** `.c, .c++, …` — Vale's comment-only extensions as recipe prose. */
|
|
339
|
+
export declare function valeCommentList(): string;
|
|
340
|
+
/**
|
|
341
|
+
* `.mkd, .mkdn, …` — the plaintext extensions worth naming, as recipe prose.
|
|
342
|
+
*
|
|
343
|
+
* Rendered rather than written into the recipe because the surprising cases are
|
|
344
|
+
* exactly the ones a hand-written list gets wrong.
|
|
345
|
+
*/
|
|
346
|
+
export declare function valePlaintextList(): string;
|
|
347
|
+
/**
|
|
348
|
+
* `.rst (needs rst2html), …` — Vale's converter-dependent formats as recipe
|
|
349
|
+
* prose, each naming the tool whose absence is the actual failure.
|
|
350
|
+
*/
|
|
351
|
+
export declare function valeConverterList(): string;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import type { EngineName } from "./layout";
|
|
2
|
+
/**
|
|
3
|
+
* What `verify` enforces beyond the engine's own schema.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this exists
|
|
6
|
+
*
|
|
7
|
+
* A rule the engine executes correctly can still be refused. Those refusals are
|
|
8
|
+
* deliberate, but they are OURS, and a generator that never reads our recipes
|
|
9
|
+
* cannot know them. Published in the conformance corpus so an external eval can
|
|
10
|
+
* tell "your rule is wrong about the subject" from "your rule broke a house
|
|
11
|
+
* rule it was never told about" — two findings that want completely different
|
|
12
|
+
* responses.
|
|
13
|
+
*
|
|
14
|
+
* ## Why every entry has a test that triggers it
|
|
15
|
+
*
|
|
16
|
+
* A hand-maintained list of what code does goes stale, and this is not
|
|
17
|
+
* hypothetical: `create-sg-rule.md` told agents for months that
|
|
18
|
+
* "`verify` never reads `language`", which stopped being true when
|
|
19
|
+
* `validateLanguage` landed. Nothing failed, because prose has no test.
|
|
20
|
+
*
|
|
21
|
+
* `test/constraints.test.ts` builds a rule that violates each entry and
|
|
22
|
+
* asserts `verify` rejects it, keyed on `id`. An entry describing a check that
|
|
23
|
+
* no longer fires fails the suite; a check with no entry is invisible to that
|
|
24
|
+
* test and is the gap this list is trying to close, so add one when you add a
|
|
25
|
+
* check.
|
|
26
|
+
*/
|
|
27
|
+
export interface RuleConstraint {
|
|
28
|
+
/** Stable key. Consumers branch on this; renaming is breaking. */
|
|
29
|
+
id: string;
|
|
30
|
+
engine: EngineName;
|
|
31
|
+
/**
|
|
32
|
+
* Which command refuses the rule.
|
|
33
|
+
*
|
|
34
|
+
* Load-bearing for a consumer's eval ORDER, not a detail. A `verify`
|
|
35
|
+
* constraint is decided from the files alone and can be checked before
|
|
36
|
+
* anything runs; a `test` constraint needs the fixtures to execute. Running
|
|
37
|
+
* the cross-comparison before `verify` passes measures the wrong thing, and
|
|
38
|
+
* treating a `test`-time refusal as a `verify` gap sends someone to the wrong
|
|
39
|
+
* layer.
|
|
40
|
+
*
|
|
41
|
+
* The split is not always where it looks. `verify` requires that a test FILE
|
|
42
|
+
* exists, by filename; whether that file is attributed to this rule is
|
|
43
|
+
* decided later, from the `id:` inside it.
|
|
44
|
+
*/
|
|
45
|
+
enforcedBy: "verify" | "test";
|
|
46
|
+
/** One line, for a report that lists several. */
|
|
47
|
+
summary: string;
|
|
48
|
+
/** Why it exists, so a reader can tell a house rule from a bug. */
|
|
49
|
+
rationale: string;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* One constraint a rule broke, paired with the message that reports it.
|
|
53
|
+
*
|
|
54
|
+
* Emitted alongside `errors` rather than replacing it. A consumer mapping a
|
|
55
|
+
* rejection back to the rationale we already wrote had only our wording to
|
|
56
|
+
* match on, and wording is not a contract: rephrasing an error message is not
|
|
57
|
+
* a breaking change, so a text match rots without anything reporting it.
|
|
58
|
+
*
|
|
59
|
+
* The message is repeated rather than joined to `errors` by index. An index
|
|
60
|
+
* join is a contract nobody can see, and it breaks the first time either side
|
|
61
|
+
* filters or reorders. Repeating the string lets a consumer ignore `errors`
|
|
62
|
+
* entirely.
|
|
63
|
+
*/
|
|
64
|
+
export interface RuleViolation {
|
|
65
|
+
constraintId: RuleConstraintId;
|
|
66
|
+
message: string;
|
|
67
|
+
}
|
|
68
|
+
export declare const RULE_CONSTRAINTS: readonly [{
|
|
69
|
+
readonly id: "sg-id-matches-directory";
|
|
70
|
+
readonly engine: "sg";
|
|
71
|
+
readonly enforcedBy: "verify";
|
|
72
|
+
readonly summary: "A rule's `id:` must equal the directory it lives in.";
|
|
73
|
+
readonly rationale: "The directory name is the rule id: it is what `check` and `test` address, and what a person types to delete a rule. ast-grep registers the rule under the id in its body. With the two apart, `test` cannot find the rule at all, and `check` does run it but reports findings under a name no directory has, so nobody can locate what produced them.";
|
|
74
|
+
}, {
|
|
75
|
+
readonly id: "sg-regex-needs-kind";
|
|
76
|
+
readonly engine: "sg";
|
|
77
|
+
readonly enforcedBy: "verify";
|
|
78
|
+
readonly summary: "A `regex` needs a sibling `kind`, in `rule`, `constraints` and `utils`.";
|
|
79
|
+
readonly rationale: "A regex match with no kind to anchor it is ambiguous and slow: it is applied to every node rather than to the one shape the author meant. ast-grep accepts it, so the engine is not the thing that will tell you.";
|
|
80
|
+
}, {
|
|
81
|
+
readonly id: "sg-language-accepted";
|
|
82
|
+
readonly engine: "sg";
|
|
83
|
+
readonly enforcedBy: "verify";
|
|
84
|
+
readonly summary: "`language:` must be a spelling ast-grep itself uses; a resolvable but non-canonical one is a notice.";
|
|
85
|
+
readonly rationale: "An unrecognized name aborts config parsing, which takes every other sg rule in the project down with it and reports nothing. That is the loudest possible failure with the quietest possible symptom: a clean report.";
|
|
86
|
+
}, {
|
|
87
|
+
readonly id: "sg-files-globs-parse";
|
|
88
|
+
readonly engine: "sg";
|
|
89
|
+
readonly enforcedBy: "verify";
|
|
90
|
+
readonly summary: "`files:` globs must not name `.tsx` under TypeScript, or `.ts` under Tsx.";
|
|
91
|
+
readonly rationale: "A glob naming an extension the language cannot parse matches nothing, so the rule reports a clean codebase rather than an error. Only the TypeScript/Tsx pair is checked, and deliberately so: they are separate parsers rather than aliases, which is the one language/extension mismatch decidable from the rule file alone. No other extension is compared against `language`, so this is narrower than it first reads.";
|
|
92
|
+
}, {
|
|
93
|
+
readonly id: "sg-required-fields";
|
|
94
|
+
readonly engine: "sg";
|
|
95
|
+
readonly enforcedBy: "verify";
|
|
96
|
+
readonly summary: "`id`, `language`, `severity`, `message` and `rule` are required.";
|
|
97
|
+
readonly rationale: "ast-grep needs fewer of these than we do. The extras are what make a finding actionable and a rule addressable once it is on disk.";
|
|
98
|
+
}, {
|
|
99
|
+
readonly id: "sg-test-file-required";
|
|
100
|
+
readonly engine: "sg";
|
|
101
|
+
readonly enforcedBy: "verify";
|
|
102
|
+
readonly summary: "A rule must ship at least one test file under `.tests/`.";
|
|
103
|
+
readonly rationale: "A rule with no fixtures has shown neither that it fires nor that it stays quiet. `verify` requires the file; `test` requires the cases inside it to cover both.";
|
|
104
|
+
}, {
|
|
105
|
+
readonly id: "sg-fixture-id-matches-rule";
|
|
106
|
+
readonly engine: "sg";
|
|
107
|
+
readonly enforcedBy: "test";
|
|
108
|
+
readonly summary: "A test file's own `id:` must equal the rule id.";
|
|
109
|
+
readonly rationale: "Fixtures are attributed by the id inside the file, not by its name. A fixture carrying another rule's id is silently not counted, so a rule that ships one reads as a rule that shipped none. `verify` passes, because the FILE is there; `test` is where it bites.";
|
|
110
|
+
}];
|
|
111
|
+
/**
|
|
112
|
+
* The id of a constraint this CLI publishes.
|
|
113
|
+
*
|
|
114
|
+
* Derived from the list rather than declared beside it, so a violation can only
|
|
115
|
+
* name a constraint that is actually published. Attributing a rejection to an
|
|
116
|
+
* id no consumer can look up would be worse than attributing nothing.
|
|
117
|
+
*/
|
|
118
|
+
export type RuleConstraintId = (typeof RULE_CONSTRAINTS)[number]["id"];
|
|
119
|
+
/**
|
|
120
|
+
* Record an attributable failure in both places at once.
|
|
121
|
+
*
|
|
122
|
+
* `errors` stays the complete list and `violations` the attributable subset, so
|
|
123
|
+
* a consumer reading only `errors` sees exactly what it saw before this
|
|
124
|
+
* existed. Written through one call because two arrays maintained separately is
|
|
125
|
+
* how the message in one comes to differ from the message in the other.
|
|
126
|
+
*/
|
|
127
|
+
export declare function violate(target: {
|
|
128
|
+
errors: string[];
|
|
129
|
+
violations: RuleViolation[];
|
|
130
|
+
}, constraintId: RuleConstraintId, message: string): void;
|
|
131
|
+
/** Constraints for one engine. */
|
|
132
|
+
export declare function constraintsFor(engine: EngineName): readonly RuleConstraint[];
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The rule layout table — the single description of what a rule is made of and
|
|
3
|
+
* where its files go, for every engine.
|
|
4
|
+
*
|
|
5
|
+
* SPLIT OUT OF `engines.ts` SO IT CAN BE PUBLISHED. This module holds data and
|
|
6
|
+
* nothing else: no filesystem, no network, no command tree. `engines.ts` keeps
|
|
7
|
+
* the helpers that join these values to a `cwd`, because those import
|
|
8
|
+
* `node:fs/promises` and a Worker cannot load them.
|
|
9
|
+
*
|
|
10
|
+
* The split exists because the Cloud Generator builds rule payloads against
|
|
11
|
+
* this table. While it lived only in prose, the same layout was described in
|
|
12
|
+
* seven stale code comments and in `cli-runtime-rule-execution`'s own spec text,
|
|
13
|
+
* all naming a path two migrations had already moved — and one of those stale
|
|
14
|
+
* comments put the wrong layout into a cross-team design document. A shape
|
|
15
|
+
* described in prose drifts in every place it is described, including the one
|
|
16
|
+
* that is supposed to be authoritative. Published as data, it cannot.
|
|
17
|
+
*
|
|
18
|
+
* Re-exported for consumers as `@taskless/cli/layout` (see `src/layout/`).
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Engines this CLI knows. The directory name under `.taskless/rules/` **is**
|
|
22
|
+
* the engine: dispatch reads the path and never parses a rule file to decide
|
|
23
|
+
* who owns it.
|
|
24
|
+
*/
|
|
25
|
+
export declare const ENGINES: readonly ["sg", "vale", "runtime"];
|
|
26
|
+
export type EngineName = (typeof ENGINES)[number];
|
|
27
|
+
/**
|
|
28
|
+
* How a rule's fixtures group into cases.
|
|
29
|
+
*
|
|
30
|
+
* Stated here rather than left implicit in each engine's fixture reader, which
|
|
31
|
+
* is where it lived: `runtime/fixtures.ts` rejects a loose file because a case
|
|
32
|
+
* is a directory, `vale/verify.ts` rejects a nested directory because a case is
|
|
33
|
+
* a document, and `verify.ts` counts ast-grep's own `valid:`/`invalid:` keys.
|
|
34
|
+
* The fact was recoverable only by reading three rejections, so every consumer
|
|
35
|
+
* transcribed it — which is what published this table in the first place.
|
|
36
|
+
*
|
|
37
|
+
* Each value is pinned beside the rejection that implements it, rather than in
|
|
38
|
+
* a test of its own: `runtime-fixtures.test.ts` asserts `case-directories`
|
|
39
|
+
* where it proves a loose file is refused, `vale-verify.test.ts` asserts
|
|
40
|
+
* `case-documents` where it proves a nested directory is refused, and
|
|
41
|
+
* `reference.test.ts` asserts `ast-grep-test` publishes no cases. A reader
|
|
42
|
+
* changing a reader's mind about its layout meets the declaration in the same
|
|
43
|
+
* test, which a separate file would not have achieved.
|
|
44
|
+
*/
|
|
45
|
+
export type FixtureLayout =
|
|
46
|
+
/** A case is a directory under `pass/` or `fail/`, handed to the check as its root. */
|
|
47
|
+
"case-directories"
|
|
48
|
+
/** A case is one document under `pass/` or `fail/`. */
|
|
49
|
+
| "case-documents"
|
|
50
|
+
/** Not a directory layout: `valid:`/`invalid:` keys inside one ast-grep test file. */
|
|
51
|
+
| "ast-grep-test";
|
|
52
|
+
/** How a rule reaches execution, or `null` when this CLI has no executor yet. */
|
|
53
|
+
export type EngineExecutor = "ast-grep" | "vale-runner" | "runtime-harness" | null;
|
|
54
|
+
export interface EngineLayout {
|
|
55
|
+
engine: EngineName;
|
|
56
|
+
/**
|
|
57
|
+
* The file inside a rule directory that *is* the rule, as a function of the
|
|
58
|
+
* rule id. `sg` and `vale` name it after the rule; `runtime` always calls it
|
|
59
|
+
* `check.ts`, because the rule is a program rather than a document.
|
|
60
|
+
*/
|
|
61
|
+
ruleFile: (ruleId: string) => string;
|
|
62
|
+
/**
|
|
63
|
+
* The engine's per-rule config file, or `undefined` where the engine has
|
|
64
|
+
* nothing to put in one.
|
|
65
|
+
*
|
|
66
|
+
* Only Vale has one, and not for symmetry: Vale cannot express a rule's scope
|
|
67
|
+
* inside the style file — measured, it rejects unknown keys with `E201` — so
|
|
68
|
+
* scope needs somewhere else to live. ast-grep carries `files`/`ignores`
|
|
69
|
+
* inside the rule itself, so an `sg` per-rule config would be a file every
|
|
70
|
+
* author creates, no author fills, and every reader learns to ignore.
|
|
71
|
+
*/
|
|
72
|
+
ruleConfigFile: string | undefined;
|
|
73
|
+
/** Subdirectory holding ast-grep capture rules, for engines that use them. */
|
|
74
|
+
capturesDirectory: string | undefined;
|
|
75
|
+
/** How this engine's fixtures group into cases. See {@link FixtureLayout}. */
|
|
76
|
+
fixtureLayout: FixtureLayout;
|
|
77
|
+
executor: EngineExecutor;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Everything defining a rule lives in one directory,
|
|
81
|
+
* `.taskless/rules/<engine>/<id>/`, the same shape for every engine. A rule is
|
|
82
|
+
* therefore one path — which is what lets `verify` and `test` take a path
|
|
83
|
+
* instead of an id, and what makes deleting a rule an `rm -rf` of one thing.
|
|
84
|
+
*/
|
|
85
|
+
export declare const RULES_DIRECTORY = "rules";
|
|
86
|
+
/**
|
|
87
|
+
* The directory the whole tree hangs off, relative to the project root.
|
|
88
|
+
*
|
|
89
|
+
* Here rather than beside its callers because the conformance corpus publishes
|
|
90
|
+
* `.taskless/rules/<engine>/<id>/` as a path a consumer can act on, and a
|
|
91
|
+
* published path needs one value to be generated from.
|
|
92
|
+
*
|
|
93
|
+
* It is not yet the only copy. The literal appears in about fifteen places
|
|
94
|
+
* behind four constants that do not know about each other — `CANONICAL_DIR` in
|
|
95
|
+
* `install/install.ts` and `install/canonical.ts`, `TASKLESS_DIR` in
|
|
96
|
+
* `install/state.ts`, `TASKLESS_DIRECTORY` in `rules/scan.ts` and
|
|
97
|
+
* `rules/vale/formats.ts`. `rulesRoot` reads this one, so what the corpus
|
|
98
|
+
* publishes is what the rule commands resolve. Converging the rest is a
|
|
99
|
+
* tidy-up, and doing it inside a contract change would hide the contract
|
|
100
|
+
* change inside a rename.
|
|
101
|
+
*/
|
|
102
|
+
export declare const TASKLESS_DIRECTORY = ".taskless";
|
|
103
|
+
/**
|
|
104
|
+
* A rule's tests, relative to its rule directory. **The dot is load-bearing.**
|
|
105
|
+
*
|
|
106
|
+
* ast-grep's `ruleDirs` recurses and parses every `.yml` beneath it as a rule,
|
|
107
|
+
* so a plain `tests/` directory inside a rule directory fails the entire scan
|
|
108
|
+
* with `Fail to parse yaml as RuleConfig: missing field 'language'`. Measured
|
|
109
|
+
* against ast-grep 0.41.0: `tests/` and `__tests__/` both hard-fail,
|
|
110
|
+
* a dot-directory is skipped by rule discovery, and `sg test` still reads it
|
|
111
|
+
* when `testDir` names it.
|
|
112
|
+
*
|
|
113
|
+
* That is undocumented behavior, and three things make depending on it
|
|
114
|
+
* acceptable. The failure is loud — a parse error naming the file, never a test
|
|
115
|
+
* silently reinterpreted as a rule. `ast-grep-vendor-contract.test.ts` pins it
|
|
116
|
+
* alongside the rest of ast-grep's observed behavior, so it is
|
|
117
|
+
* checked on every run rather than remembered. And the binary is pinned to an
|
|
118
|
+
* exact version, so it cannot change without a deliberate bump, which is
|
|
119
|
+
* exactly where that test fires.
|
|
120
|
+
*
|
|
121
|
+
* If it ever does break, the recorded fallback is to materialize a rules-only
|
|
122
|
+
* tree for ast-grep and point `ruleDirs` at that (design D2).
|
|
123
|
+
*/
|
|
124
|
+
export declare const RULE_TESTS_DIRECTORY = ".tests";
|
|
125
|
+
export declare const ENGINE_LAYOUTS: {
|
|
126
|
+
sg: {
|
|
127
|
+
engine: "sg";
|
|
128
|
+
ruleFile: (ruleId: string) => string;
|
|
129
|
+
ruleConfigFile: undefined;
|
|
130
|
+
capturesDirectory: undefined;
|
|
131
|
+
fixtureLayout: "ast-grep-test";
|
|
132
|
+
executor: "ast-grep";
|
|
133
|
+
};
|
|
134
|
+
vale: {
|
|
135
|
+
engine: "vale";
|
|
136
|
+
ruleFile: (ruleId: string) => string;
|
|
137
|
+
ruleConfigFile: string;
|
|
138
|
+
capturesDirectory: undefined;
|
|
139
|
+
fixtureLayout: "case-documents";
|
|
140
|
+
executor: "vale-runner";
|
|
141
|
+
};
|
|
142
|
+
runtime: {
|
|
143
|
+
engine: "runtime";
|
|
144
|
+
ruleFile: () => string;
|
|
145
|
+
ruleConfigFile: undefined;
|
|
146
|
+
capturesDirectory: string;
|
|
147
|
+
fixtureLayout: "case-directories";
|
|
148
|
+
executor: "runtime-harness";
|
|
149
|
+
};
|
|
150
|
+
};
|
|
151
|
+
/** Whether `value` names an engine this CLI knows. */
|
|
152
|
+
export declare function isKnownEngine(value: string): value is EngineName;
|