@eslint-sh/eslint-plugin 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +12 -4
  2. package/dist/eslint-plugin.d.ts +95 -57
  3. package/dist/index.d.ts +12 -12
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +10 -12
  6. package/dist/index.js.map +1 -1
  7. package/dist/language/selector-classes.d.ts +6 -10
  8. package/dist/language/selector-classes.d.ts.map +1 -1
  9. package/dist/language/selector-classes.js +6 -9
  10. package/dist/language/selector-classes.js.map +1 -1
  11. package/dist/language/shell-language-options.d.ts +9 -11
  12. package/dist/language/shell-language-options.d.ts.map +1 -1
  13. package/dist/language/shell-language-options.js +7 -11
  14. package/dist/language/shell-language-options.js.map +1 -1
  15. package/dist/language/shell-language.d.ts +10 -12
  16. package/dist/language/shell-language.d.ts.map +1 -1
  17. package/dist/language/shell-language.js +45 -79
  18. package/dist/language/shell-language.js.map +1 -1
  19. package/dist/language/shell-source-code.d.ts +10 -19
  20. package/dist/language/shell-source-code.d.ts.map +1 -1
  21. package/dist/language/shell-source-code.js +165 -62
  22. package/dist/language/shell-source-code.js.map +1 -1
  23. package/dist/language/source-coordinates.d.ts +23 -0
  24. package/dist/language/source-coordinates.d.ts.map +1 -0
  25. package/dist/language/source-coordinates.js +58 -0
  26. package/dist/language/source-coordinates.js.map +1 -0
  27. package/dist/language/syntax-view.d.ts +60 -0
  28. package/dist/language/syntax-view.d.ts.map +1 -0
  29. package/dist/language/syntax-view.js +164 -0
  30. package/dist/language/syntax-view.js.map +1 -0
  31. package/dist/language/word-resolution.d.ts +11 -0
  32. package/dist/language/word-resolution.d.ts.map +1 -0
  33. package/dist/language/word-resolution.js +18 -0
  34. package/dist/language/word-resolution.js.map +1 -0
  35. package/docs/custom-rule-tutorial.md +23 -12
  36. package/docs/examples/eslint.config.mjs +1 -1
  37. package/docs/examples/{no-rm-rf-rule.js → no-rm-rf-rule.mjs} +9 -4
  38. package/docs/selectors.md +9 -0
  39. package/package.json +9 -3
package/README.md CHANGED
@@ -27,14 +27,14 @@ suppress it: for a rule you've configured as `sh/your-rule`,
27
27
  - `plugin` (default export) — `{ meta: { name, version, namespace: "sh" }, languages: { sh:
28
28
  ShellLanguage }, rules: {} }`. `meta.version` always matches this package's `package.json`.
29
29
  - `ShellLanguage` — the `@eslint/core` `Language` implementation: `fileType: "text"`,
30
- `lineStart`/`columnStart: 1`, `nodeTypeKey: "type"`, the bridge's generated `visitorKeys`,
30
+ `lineStart`/`columnStart: 1`, `nodeTypeKey: "type"`, the consumer's schema-derived `visitorKeys`,
31
31
  `validateLanguageOptions`/`normalizeLanguageOptions` for the
32
32
  `{dialect, shellVersion, directivePrefix}` schema, `parse`/`createSourceCode`, and
33
33
  `matchesSelectorClass` for the six launch esquery selector classes (`:command`, `:loop`,
34
34
  `:conditional`, `:expansion`, `:quoted`, `:function` — see the
35
35
  [selector cookbook](./docs/selectors.md)).
36
36
  - `ShellSourceCode` — extends `@eslint/plugin-kit`'s `TextSourceCodeBase`; implements `traverse()`
37
- (driven by the bridge's `visitorKeys`, yielding two-phase `VisitNodeStep`s), `getParent()`, and
37
+ (driven by the consumer's `visitorKeys`, yielding two-phase `VisitNodeStep`s), `getParent()`, and
38
38
  the disable-directive surface (`getDisableDirectives()`, `getInlineConfigNodes()`,
39
39
  `applyInlineConfig()`).
40
40
  - `ShellLanguageOptions` / `NormalizedShellLanguageOptions` / `ShellLanguageOptionsJSON` — the
@@ -42,9 +42,17 @@ ShellLanguage }, rules: {} }`. `meta.version` always matches this package's `pac
42
42
  prefix directive/inline-config comments must start with — e.g. the default `"eslint"` recognizes
43
43
  `# eslint-disable-next-line ...`; consumers who already overload `# eslint-*` comments for
44
44
  something else can configure a different prefix (e.g. `directivePrefix: 'shellcheck-sh'`).
45
+ - `ShellNode` / `ShellFile` / `ShellComment` / `ShellPosition` — the plugin's lint view: lowercase
46
+ fields, UTF-16 ranges, and one-based UTF-16 locations, independent of the raw parser syntax.
47
+ Locations come from one parse-time position snapshot and remain bound to that original source;
48
+ projecting the view does not run live bounds operations on every syntax subtree.
49
+ - `resolveWord` — adapts a parsed lint Word to `sh-ast`'s word-resolution helper, so a project that installs only
50
+ this package can write custom rules that resolve static shell words (e.g. the `no-rm-rf` example
51
+ in the [custom-rule tutorial](./docs/custom-rule-tutorial.md)) without a separate `sh-ast`
52
+ install. Fabricated nodes are rejected because they have no original syntax association.
45
53
 
46
- Parse failures surface as fatal lint messages at mvdan/sh's real reported position (never a 1:1
47
- placeholder) — see `ShParseError` in `sh-ast`.
54
+ Syntax failures surface as fatal lint messages at mvdan/sh's reported byte offset, converted to
55
+ the source's UTF-16 location. Failures without a valid syntax position use a 1:1 fallback.
48
56
 
49
57
  ## Writing your own rules
50
58
 
@@ -4,31 +4,26 @@ import type { FileProblem } from '@eslint/core';
4
4
  import type { Language } from '@eslint/core';
5
5
  import type { OkParseResult } from '@eslint/core';
6
6
  import type { ParseResult } from '@eslint/core';
7
+ import type { ResolveWordOptions } from 'sh-ast/analyze';
7
8
  import type { RulesConfig } from '@eslint/core';
8
- import type { ShellDialect } from 'sh-ast';
9
- import type { ShFile } from 'sh-ast';
10
- import type { ShNode } from 'sh-ast';
11
- import type { ShNodes } from 'sh-ast';
12
9
  import type { SourceLocation } from '@eslint/core';
13
10
  import { TextSourceCodeBase } from '@eslint/plugin-kit';
14
11
  import type { TraversalStep } from '@eslint/core';
12
+ import type { WordResolution } from 'sh-ast/analyze';
15
13
 
16
14
  /**
17
- * The `@eslint-sh/eslint-plugin` plugin object (design/PACKAGES.md,
18
- * `@eslint-sh/eslint-plugin`): `languages.sh` provides `ShellLanguage` /
19
- * `ShellSourceCode` (design/ARCHITECTURE.md, "SourceCode and Language
20
- * objects"), selected in a flat config via `language: "sh/sh"`
21
- * (`namespace: "sh"`). `meta.version` is read from this package's own
22
- * `package.json` at runtime — never hardcoded (see `version.ts`).
15
+ * The `@eslint-sh/eslint-plugin` plugin object: `languages.sh` provides
16
+ * `ShellLanguage` / `ShellSourceCode`, selected in a flat config via
17
+ * `language: "sh/sh"` (`namespace: "sh"`). `meta.version` is read from this
18
+ * package's own `package.json` at runtime — never hardcoded (see
19
+ * `version.ts`).
23
20
  *
24
- * `rules` is empty at this milestone (M2 — `ShellLanguage`/`ShellSourceCode`
25
- * core, plus the six launch esquery selector classes); rules and shared
26
- * `configs` are Milestone 3 (design/MILESTONES.md). Adding them later is
27
- * additive, not a breaking change to this object's shape.
21
+ * The empty `rules` registry lets consumers supply their own rules while
22
+ * sharing parsing, selectors, source coordinates, and directive semantics.
28
23
  *
29
24
  * Re-exported, unchanged, as the default export of the `eslint-sh` umbrella
30
- * package (design/PACKAGES.md's Naming decision): importing this package or
31
- * the umbrella package both yield the same plugin object.
25
+ * package: importing this package or the umbrella package both yield the
26
+ * same plugin object.
32
27
  */
33
28
  declare const _default: {
34
29
  meta: {
@@ -62,11 +57,39 @@ export declare interface NormalizedShellLanguageOptions extends Record<string, u
62
57
  toJSON(): ShellLanguageOptionsJSON;
63
58
  }
64
59
 
60
+ /**
61
+ * Resolves a parsed lint Word using the upstream-shaped syntax associated with it.
62
+ * The view supplies locations and selector fields; sh-ast/analyze owns the word
63
+ * interpretation. Fabricated or synthetic view nodes have no source syntax and
64
+ * are rejected instead of being treated as known or unknown shell values.
65
+ * @public
66
+ */
67
+ export declare function resolveWord(word: ShellNode, options?: ResolveWordOptions): WordResolution;
68
+
69
+ /** Directive processing uses the comment text without its leading shell hash. @public */
70
+ export declare interface ShellComment extends ShellNode {
71
+ /** Comment discriminator used by directive collection. */
72
+ readonly type: 'Comment';
73
+ /** Decoded comment content after the leading hash, preserving its whitespace. */
74
+ readonly text: string;
75
+ }
76
+
77
+ /** Owns ESLint configuration labels and validates their consumer-facing meaning before parsing. */
78
+ /** The dialect labels understood by ESLint configuration, mapped to upstream numeric variants when parsing. @public */
79
+ export declare type ShellDialect = 'bash' | 'posix' | 'mksh' | 'bats' | 'zsh';
80
+
81
+ /** The lint root has a statement collection even when upstream represents it as nil. @public */
82
+ export declare interface ShellFile extends ShellNode {
83
+ /** Root discriminator retained for selectors. */
84
+ readonly type: 'File';
85
+ /** Top-level statements in source order; nil upstream slices become an empty view. */
86
+ readonly stmts: readonly ShellNode[];
87
+ }
88
+
65
89
  /**
66
90
  * `ShellLanguage` — the `@eslint/core` `Language` implementation for shell
67
- * scripts (design/ARCHITECTURE.md, "SourceCode and Language objects";
68
- * design/PACKAGES.md, `@eslint-sh/eslint-plugin`). Registered by the plugin
69
- * as `languages.sh`, so consumers select it via `language: "sh/sh"`.
91
+ * scripts. Registered by the plugin as `languages.sh`, so consumers select
92
+ * it via `language: "sh/sh"`.
70
93
  *
71
94
  * Implements `matchesSelectorClass` (the six launch esquery selector
72
95
  * classes — see `./selector-classes.js`), so rules and end users can write
@@ -109,23 +132,22 @@ export declare class ShellLanguage implements Language {
109
132
  * needed there, but `:loop :command` is) match a whole family of node
110
133
  * types instead of one literal type name. Delegates to
111
134
  * `./selector-classes.js`'s `SELECTOR_CLASS_NODE_TYPES` table for the six
112
- * launch classes (design/ARCHITECTURE.md, "SourceCode and Language
113
- * objects"); `ancestry` is unused today because none of the six launch
135
+ * launch classes; `ancestry` is unused today because none of the six launch
114
136
  * classes need ancestor context, but the parameter is accepted to match
115
137
  * `Language.matchesSelectorClass`'s signature exactly.
116
138
  */
117
- matchesSelectorClass(className: string, node: ShNode, _ancestry: ShNode[]): boolean;
139
+ matchesSelectorClass(className: string, node: ShellNode, _ancestry: ShellNode[]): boolean;
118
140
  /**
119
141
  * Parses `file.body` (guaranteed to be a `string`, since `fileType` is
120
- * `"text"`) via `sh-ast`'s `parseSync`, mapping the result to
142
+ * `"text"`) with one synchronous parse and its original-position snapshot,
143
+ * mapping the result to
121
144
  * the `{ok: true, ast}` / `{ok: false, errors}` shape `Language.parse` is
122
145
  * required to return. Never throws — parse failures are reported as
123
- * fatal lint messages, per the `Language` contract
124
- * (design/ARCHITECTURE.md, "Parse errors and dialects").
146
+ * fatal lint messages, per the `Language` contract.
125
147
  */
126
148
  parse(file: File_2, context: {
127
149
  languageOptions: ShellLanguageOptions;
128
- }): ParseResult<ShFile>;
150
+ }): ParseResult<ShellFile>;
129
151
  /**
130
152
  * Creates the `ShellSourceCode` ESLint uses to run rules against `ast`.
131
153
  * `context.languageOptions` is ESLint's already-normalized copy (see
@@ -137,18 +159,16 @@ export declare class ShellLanguage implements Language {
137
159
  * direct construction (e.g. tests that skip the `Language` normalization
138
160
  * step), mirroring `parse()`'s `dialect` default above.
139
161
  */
140
- createSourceCode(file: File_2, parseResult: OkParseResult<ShFile>, context: {
162
+ createSourceCode(file: File_2, parseResult: OkParseResult<ShellFile>, context: {
141
163
  languageOptions: ShellLanguageOptions;
142
164
  }): ShellSourceCode;
143
165
  }
144
166
 
145
167
  /**
146
- * `languageOptions` accepted by {@link ShellLanguage} (design/PACKAGES.md's
147
- * `languageOptions` schema): `dialect` selects mvdan/sh's `LangVariant` by
148
- * string name (default `"bash"`); `shellVersion` is consumed by the
149
- * rule layer (e.g. the bash-3.2 compatibility pack), never by the parser
150
- * itself (see design/ARCHITECTURE.md, "A verified nuance worth stating
151
- * loudly").
168
+ * `languageOptions` accepted by {@link ShellLanguage}: `dialect` selects
169
+ * mvdan/sh's `LangVariant` through a consumer-owned mapping (default `"bash"`); `shellVersion`
170
+ * is consumed by the rule layer (e.g. the bash-3.2 compatibility pack),
171
+ * never by the parser itself.
152
172
  *
153
173
  * Extends `Record<string, unknown>` (rather than a bare interface) so this
154
174
  * type satisfies the `@eslint/core` package's `LanguageOptions` bound
@@ -167,8 +187,7 @@ export declare interface ShellLanguageOptions extends Record<string, unknown> {
167
187
  * default `"eslint"` recognizes `# eslint-disable-next-line ...` and
168
188
  * `# eslint <rule-config>`. Consumers who embed shell-linting inside a
169
189
  * larger toolchain that already overloads `#eslint-*` comments for
170
- * something else can configure a different prefix (design/ARCHITECTURE.md,
171
- * "SourceCode and Language objects").
190
+ * something else can configure a different prefix.
172
191
  * @defaultValue `"eslint"`
173
192
  */
174
193
  readonly directivePrefix?: string;
@@ -197,13 +216,40 @@ export declare interface ShellLanguageOptionsJSON {
197
216
  readonly shellVersion?: string;
198
217
  }
199
218
 
219
+ /**
220
+ * A node in the consumer's lint view. Scalar/child fields use lowercase upstream
221
+ * spellings; syntax fidelity belongs to the associated upstream tree. Auxiliary
222
+ * view nodes may have spans derived from children and are not upstream Nodes.
223
+ * @public
224
+ */
225
+ export declare interface ShellNode {
226
+ /** Original syntax kind retained as the discriminator for lint selectors. */
227
+ readonly type: string;
228
+ /** Half-open UTF-16 span used to slice source and place fixes. */
229
+ readonly range: readonly [number, number];
230
+ /** Source-derived endpoints for ESLint diagnostics. */
231
+ readonly loc: {
232
+ readonly start: ShellPosition;
233
+ readonly end: ShellPosition;
234
+ };
235
+ /** Lowercase syntax fields containing consumer children or decoded scalar values. */
236
+ readonly [field: string]: unknown;
237
+ }
238
+
239
+ /** An ESLint location counts UTF-16 units, with both line and column starting at one. @public */
240
+ export declare interface ShellPosition {
241
+ /** One-based source line, with CRLF treated as one line break. */
242
+ readonly line: number;
243
+ /** One-based UTF-16 column; tabs and grapheme widths are not expanded. */
244
+ readonly column: number;
245
+ }
246
+
200
247
  /**
201
248
  * `ShellSourceCode` — the `SourceCode` object ESLint uses to work with a
202
- * parsed shell file (design/ARCHITECTURE.md, "SourceCode and Language
203
- * objects"). Extends `@eslint/plugin-kit`'s `TextSourceCodeBase`, which
249
+ * parsed shell file. Extends `@eslint/plugin-kit`'s `TextSourceCodeBase`, which
204
250
  * already implements `getLoc`/`getRange`/`getText`/`lines` (both by reading
205
251
  * the normalized node's own `loc`/`range` fields — see
206
- * `sh-ast`'s "Normalized node shape"), `getLocFromIndex`, and
252
+ * the consumer's source-view contract), `getLocFromIndex`, and
207
253
  * `getIndexFromLoc`; this class adds the two members the base class
208
254
  * deliberately leaves unimplemented: `traverse()` (base throws "Not
209
255
  * implemented") and `getParent()` (base throws "Not implemented", and
@@ -215,7 +261,7 @@ export declare interface ShellLanguageOptionsJSON {
215
261
  * (`<prefix>-disable`, `<prefix>-enable`, `<prefix>-disable-line`,
216
262
  * `<prefix>-disable-next-line`) plus whole-file inline rule config
217
263
  * (bare `<prefix> <rule-config>`), sourced from `Comment` nodes gathered via
218
- * `sh-ast`'s structural `walk()` and parsed with
264
+ * the consumer's `walkShell()` and parsed with
219
265
  * `@eslint/plugin-kit`'s `ConfigCommentParser` — the same building blocks
220
266
  * `@eslint/json`'s `JSONSourceCode` uses, generalized so the `<prefix>` is
221
267
  * configurable (default `"eslint"`; see `ShellLanguageOptions.directivePrefix`)
@@ -229,14 +275,14 @@ export declare interface ShellLanguageOptionsJSON {
229
275
  */
230
276
  export declare class ShellSourceCode extends TextSourceCodeBase<{
231
277
  LangOptions: ShellLanguageOptions;
232
- RootNode: ShFile;
233
- SyntaxElementWithLoc: ShNode;
234
- ConfigNode: ShNodes.ShCommentNode;
278
+ RootNode: ShellFile;
279
+ SyntaxElementWithLoc: ShellNode;
280
+ ConfigNode: ShellComment;
235
281
  }> {
236
282
  #private;
237
283
  constructor(options: {
238
284
  text: string;
239
- ast: ShFile;
285
+ ast: ShellFile;
240
286
  directivePrefix?: string;
241
287
  });
242
288
  /**
@@ -246,19 +292,11 @@ export declare class ShellSourceCode extends TextSourceCodeBase<{
246
292
  * so in practice the map is always populated by the time a rule observes
247
293
  * it.
248
294
  */
249
- getParent(node: ShNode): ShNode | undefined;
295
+ getParent(node: ShellNode): ShellNode | undefined;
250
296
  /**
251
- * Traverses the AST pre-order, yielding a `VisitNodeStep` on node enter
252
- * (`phase: 1`) and another on node exit (`phase: 2`) for every node —
253
- * exactly the two-phase shape `@eslint/json`/`@eslint/css` produce, which
254
- * is what lets rule listeners use `NodeType` and `NodeType:exit` esquery
255
- * selectors. Children are discovered via `sh-ast`'s generated,
256
- * frozen `visitorKeys` table (per node `type`) — **not** structurally
257
- * (contrast `sh-ast`'s own `walk()`, which deliberately walks
258
- * structurally so its correctness never depends on that table) — because
259
- * ESLint's traversal contract is defined in terms of a language's
260
- * declared `visitorKeys`, and this class's whole job is to honor that
261
- * contract for shell ASTs.
297
+ * Produces the enter/exit steps ESLint uses for selectors and ancestor lookup.
298
+ * Child keys describe the consumer view, including its auxiliary records.
299
+ * This callback protocol is ESLint's, independent of upstream syntax.Walk.
262
300
  */
263
301
  traverse(): Iterable<TraversalStep>;
264
302
  /**
@@ -269,7 +307,7 @@ export declare class ShellSourceCode extends TextSourceCodeBase<{
269
307
  * effect" when `linterOptions.noInlineConfig` is set — see
270
308
  * `eslint`'s `lib/linter/linter.js`, the `warnInlineConfig` branch).
271
309
  */
272
- getInlineConfigNodes(): ShNodes.ShCommentNode[];
310
+ getInlineConfigNodes(): ShellComment[];
273
311
  /**
274
312
  * Returns the disable/enable directives found among
275
313
  * {@link ShellSourceCode.getInlineConfigNodes}'s comments, recognizing all four forms —
@@ -301,7 +339,7 @@ export declare class ShellSourceCode extends TextSourceCodeBase<{
301
339
  * calling this method — and `getDisableDirectives`, together, since both
302
340
  * are gated by the same flag in `eslint`'s own `linter.js` — and instead
303
341
  * calls `getInlineConfigNodes` to emit a "has no effect" warning per
304
- * comment; see design/ARCHITECTURE.md, "SourceCode and Language objects").
342
+ * comment).
305
343
  */
306
344
  applyInlineConfig(): {
307
345
  configs: {
package/dist/index.d.ts CHANGED
@@ -2,22 +2,22 @@ import { ShellLanguage } from './language/shell-language.js';
2
2
  export { ShellLanguage } from './language/shell-language.js';
3
3
  export { ShellSourceCode } from './language/shell-source-code.js';
4
4
  export type { NormalizedShellLanguageOptions, ShellLanguageOptions, ShellLanguageOptionsJSON, } from './language/shell-language-options.js';
5
+ export { resolveWord } from './language/word-resolution.js';
6
+ export type { ShellFile, ShellNode, ShellComment, ShellPosition } from './language/syntax-view.js';
7
+ export type { ShellDialect } from './language/shell-language-options.js';
5
8
  /**
6
- * The `@eslint-sh/eslint-plugin` plugin object (design/PACKAGES.md,
7
- * `@eslint-sh/eslint-plugin`): `languages.sh` provides `ShellLanguage` /
8
- * `ShellSourceCode` (design/ARCHITECTURE.md, "SourceCode and Language
9
- * objects"), selected in a flat config via `language: "sh/sh"`
10
- * (`namespace: "sh"`). `meta.version` is read from this package's own
11
- * `package.json` at runtime — never hardcoded (see `version.ts`).
9
+ * The `@eslint-sh/eslint-plugin` plugin object: `languages.sh` provides
10
+ * `ShellLanguage` / `ShellSourceCode`, selected in a flat config via
11
+ * `language: "sh/sh"` (`namespace: "sh"`). `meta.version` is read from this
12
+ * package's own `package.json` at runtime — never hardcoded (see
13
+ * `version.ts`).
12
14
  *
13
- * `rules` is empty at this milestone (M2 — `ShellLanguage`/`ShellSourceCode`
14
- * core, plus the six launch esquery selector classes); rules and shared
15
- * `configs` are Milestone 3 (design/MILESTONES.md). Adding them later is
16
- * additive, not a breaking change to this object's shape.
15
+ * The empty `rules` registry lets consumers supply their own rules while
16
+ * sharing parsing, selectors, source coordinates, and directive semantics.
17
17
  *
18
18
  * Re-exported, unchanged, as the default export of the `eslint-sh` umbrella
19
- * package (design/PACKAGES.md's Naming decision): importing this package or
20
- * the umbrella package both yield the same plugin object.
19
+ * package: importing this package or the umbrella package both yield the
20
+ * same plugin object.
21
21
  */
22
22
  declare const _default: {
23
23
  meta: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,YAAY,EACV,8BAA8B,EAC9B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,sCAAsC,CAAC;AAE9C;;;;;;;;;;;;;;;;GAgBG;;;;;;;;;;;;AACH,wBAUmB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,YAAY,EACV,8BAA8B,EAC9B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AACnG,YAAY,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEzE;;;;;;;;;;;;;GAaG;;;;;;;;;;;;AACH,wBAUmB"}
package/dist/index.js CHANGED
@@ -2,22 +2,20 @@ import { ShellLanguage } from './language/shell-language.js';
2
2
  import { readPackageVersion } from './version.js';
3
3
  export { ShellLanguage } from './language/shell-language.js';
4
4
  export { ShellSourceCode } from './language/shell-source-code.js';
5
+ export { resolveWord } from './language/word-resolution.js';
5
6
  /**
6
- * The `@eslint-sh/eslint-plugin` plugin object (design/PACKAGES.md,
7
- * `@eslint-sh/eslint-plugin`): `languages.sh` provides `ShellLanguage` /
8
- * `ShellSourceCode` (design/ARCHITECTURE.md, "SourceCode and Language
9
- * objects"), selected in a flat config via `language: "sh/sh"`
10
- * (`namespace: "sh"`). `meta.version` is read from this package's own
11
- * `package.json` at runtime — never hardcoded (see `version.ts`).
7
+ * The `@eslint-sh/eslint-plugin` plugin object: `languages.sh` provides
8
+ * `ShellLanguage` / `ShellSourceCode`, selected in a flat config via
9
+ * `language: "sh/sh"` (`namespace: "sh"`). `meta.version` is read from this
10
+ * package's own `package.json` at runtime — never hardcoded (see
11
+ * `version.ts`).
12
12
  *
13
- * `rules` is empty at this milestone (M2 — `ShellLanguage`/`ShellSourceCode`
14
- * core, plus the six launch esquery selector classes); rules and shared
15
- * `configs` are Milestone 3 (design/MILESTONES.md). Adding them later is
16
- * additive, not a breaking change to this object's shape.
13
+ * The empty `rules` registry lets consumers supply their own rules while
14
+ * sharing parsing, selectors, source coordinates, and directive semantics.
17
15
  *
18
16
  * Re-exported, unchanged, as the default export of the `eslint-sh` umbrella
19
- * package (design/PACKAGES.md's Naming decision): importing this package or
20
- * the umbrella package both yield the same plugin object.
17
+ * package: importing this package or the umbrella package both yield the
18
+ * same plugin object.
21
19
  */
22
20
  export default {
23
21
  meta: {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAOlE;;;;;;;;;;;;;;;;GAgBG;AACH,eAAe;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,kBAAkB,EAAE;QAC7B,SAAS,EAAE,IAAI;KAChB;IACD,SAAS,EAAE;QACT,EAAE,EAAE,IAAI,aAAa,EAAE;KACxB;IACD,KAAK,EAAE,EAAE;CACO,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAOlE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAI5D;;;;;;;;;;;;;GAaG;AACH,eAAe;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,kBAAkB,EAAE;QAC7B,SAAS,EAAE,IAAI;KAChB;IACD,SAAS,EAAE;QACT,EAAE,EAAE,IAAI,aAAa,EAAE;KACxB;IACD,KAAK,EAAE,EAAE;CACO,CAAC"}
@@ -1,8 +1,7 @@
1
- import type { ShNode } from 'sh-ast';
1
+ import type { ShellNode as ShNode } from './syntax-view.js';
2
2
  /**
3
3
  * The six launch esquery selector classes `ShellLanguage.matchesSelectorClass`
4
- * implements (design/ARCHITECTURE.md, "SourceCode and Language objects";
5
- * the issue that introduced this module). Keys are the *bare* class name —
4
+ * implements. Keys are the *bare* class name —
6
5
  * esquery strips the leading `:` before invoking a language's
7
6
  * `matchesSelectorClass` (confirmed against `esquery`'s own `case 'class'`
8
7
  * matcher, which calls `options.matchClass(selector.name, node, ancestry)`
@@ -10,18 +9,15 @@ import type { ShNode } from 'sh-ast';
10
9
  * `:command` calls this table with `"command"`, not `":command"`.
11
10
  *
12
11
  * `:loop` intentionally matches only `ForClause` and `WhileClause` — the
13
- * two loop *statement* nodes, exactly as the bridge's generated schema
14
- * names them (`packages/bridge/generated/visitor-keys.js`), even though
15
- * design/ARCHITECTURE.md's prose shorthand says "For/While". `CStyleLoop`
12
+ * two loop *statement* nodes in the upstream syntax schema. `CStyleLoop`
16
13
  * is deliberately excluded from `:loop`: it is `ForClause.loop`'s nested
17
- * C-style arithmetic header (`init`/`cond`/`post` — see
18
- * `packages/bridge/generated/node-types.d.ts`'s `ShCStyleLoopNode`), not a
14
+ * C-style arithmetic header (`init`/`cond`/`post`), not a
19
15
  * loop statement in its own right. A `for ((i=0;i<3;i++))` loop's outer
20
16
  * node is still `ForClause`, so `:loop` already reaches every C-style loop
21
17
  * without needing to include `CStyleLoop` itself.
22
18
  *
23
- * `as const satisfies Record<string, readonly ShNodes.ShNodeTypeName[]>`
24
- * pins every listed node type to a real member of the bridge's generated
19
+ * `as const satisfies Record<string, readonly Node['Type'][]>`
20
+ * pins every listed node type to a real member of the parser's generated
25
21
  * type union — a typo or a since-renamed node type here is a compile error,
26
22
  * not a silent no-op match.
27
23
  *
@@ -1 +1 @@
1
- {"version":3,"file":"selector-classes.d.ts","sourceRoot":"","sources":["../../src/language/selector-classes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,QAAQ,CAAC;AAE9C;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,yBAAyB;;;;;;;CAOgC,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,yBAAyB,CAAC;AASvE;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7E"}
1
+ {"version":3,"file":"selector-classes.d.ts","sourceRoot":"","sources":["../../src/language/selector-classes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,IAAI,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE5D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,yBAAyB;;;;;;;CAOsB,CAAC;AAE7D;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,MAAM,OAAO,yBAAyB,CAAC;AAUvE;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE7E"}
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * The six launch esquery selector classes `ShellLanguage.matchesSelectorClass`
3
- * implements (design/ARCHITECTURE.md, "SourceCode and Language objects";
4
- * the issue that introduced this module). Keys are the *bare* class name —
3
+ * implements. Keys are the *bare* class name —
5
4
  * esquery strips the leading `:` before invoking a language's
6
5
  * `matchesSelectorClass` (confirmed against `esquery`'s own `case 'class'`
7
6
  * matcher, which calls `options.matchClass(selector.name, node, ancestry)`
@@ -9,18 +8,15 @@
9
8
  * `:command` calls this table with `"command"`, not `":command"`.
10
9
  *
11
10
  * `:loop` intentionally matches only `ForClause` and `WhileClause` — the
12
- * two loop *statement* nodes, exactly as the bridge's generated schema
13
- * names them (`packages/bridge/generated/visitor-keys.js`), even though
14
- * design/ARCHITECTURE.md's prose shorthand says "For/While". `CStyleLoop`
11
+ * two loop *statement* nodes in the upstream syntax schema. `CStyleLoop`
15
12
  * is deliberately excluded from `:loop`: it is `ForClause.loop`'s nested
16
- * C-style arithmetic header (`init`/`cond`/`post` — see
17
- * `packages/bridge/generated/node-types.d.ts`'s `ShCStyleLoopNode`), not a
13
+ * C-style arithmetic header (`init`/`cond`/`post`), not a
18
14
  * loop statement in its own right. A `for ((i=0;i<3;i++))` loop's outer
19
15
  * node is still `ForClause`, so `:loop` already reaches every C-style loop
20
16
  * without needing to include `CStyleLoop` itself.
21
17
  *
22
- * `as const satisfies Record<string, readonly ShNodes.ShNodeTypeName[]>`
23
- * pins every listed node type to a real member of the bridge's generated
18
+ * `as const satisfies Record<string, readonly Node['Type'][]>`
19
+ * pins every listed node type to a real member of the parser's generated
24
20
  * type union — a typo or a since-renamed node type here is a compile error,
25
21
  * not a silent no-op match.
26
22
  *
@@ -34,6 +30,7 @@ export const SELECTOR_CLASS_NODE_TYPES = {
34
30
  quoted: ['SglQuoted', 'DblQuoted'],
35
31
  function: ['FuncDecl'],
36
32
  };
33
+ /** Membership is independent of syntax field values or source positions. */
37
34
  const nodeTypesByClassName = new Map(Object.entries(SELECTOR_CLASS_NODE_TYPES).map(([className, nodeTypes]) => [
38
35
  className,
39
36
  new Set(nodeTypes),
@@ -1 +1 @@
1
- {"version":3,"file":"selector-classes.js","sourceRoot":"","sources":["../../src/language/selector-classes.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,IAAI,EAAE,CAAC,WAAW,EAAE,aAAa,CAAC;IAClC,WAAW,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC;IACvC,SAAS,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,CAAC;IAC7D,MAAM,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,EAAE,CAAC,UAAU,CAAC;CAC8C,CAAC;AAUvE,MAAM,oBAAoB,GAA6C,IAAI,GAAG,CAC5E,MAAM,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC;IACxE,SAAS;IACT,IAAI,GAAG,CAAS,SAAS,CAAC;CAC3B,CAAC,CACH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,IAAY;IAClE,OAAO,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC;AACtE,CAAC"}
1
+ {"version":3,"file":"selector-classes.js","sourceRoot":"","sources":["../../src/language/selector-classes.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,IAAI,EAAE,CAAC,WAAW,EAAE,aAAa,CAAC;IAClC,WAAW,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC;IACvC,SAAS,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,CAAC;IAC7D,MAAM,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,EAAE,CAAC,UAAU,CAAC;CACoC,CAAC;AAU7D,4EAA4E;AAC5E,MAAM,oBAAoB,GAA6C,IAAI,GAAG,CAC5E,MAAM,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC;IACxE,SAAS;IACT,IAAI,GAAG,CAAS,SAAS,CAAC;CAC3B,CAAC,CACH,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,IAAY;IAClE,OAAO,oBAAoB,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC;AACtE,CAAC"}
@@ -1,11 +1,11 @@
1
- import type { ShellDialect } from 'sh-ast';
1
+ /** Owns ESLint configuration labels and validates their consumer-facing meaning before parsing. */
2
+ /** The dialect labels understood by ESLint configuration, mapped to upstream numeric variants when parsing. @public */
3
+ export type ShellDialect = 'bash' | 'posix' | 'mksh' | 'bats' | 'zsh';
2
4
  /**
3
- * `languageOptions` accepted by {@link ShellLanguage} (design/PACKAGES.md's
4
- * `languageOptions` schema): `dialect` selects mvdan/sh's `LangVariant` by
5
- * string name (default `"bash"`); `shellVersion` is consumed by the
6
- * rule layer (e.g. the bash-3.2 compatibility pack), never by the parser
7
- * itself (see design/ARCHITECTURE.md, "A verified nuance worth stating
8
- * loudly").
5
+ * `languageOptions` accepted by {@link ShellLanguage}: `dialect` selects
6
+ * mvdan/sh's `LangVariant` through a consumer-owned mapping (default `"bash"`); `shellVersion`
7
+ * is consumed by the rule layer (e.g. the bash-3.2 compatibility pack),
8
+ * never by the parser itself.
9
9
  *
10
10
  * Extends `Record<string, unknown>` (rather than a bare interface) so this
11
11
  * type satisfies the `@eslint/core` package's `LanguageOptions` bound
@@ -24,8 +24,7 @@ export interface ShellLanguageOptions extends Record<string, unknown> {
24
24
  * default `"eslint"` recognizes `# eslint-disable-next-line ...` and
25
25
  * `# eslint <rule-config>`. Consumers who embed shell-linting inside a
26
26
  * larger toolchain that already overloads `#eslint-*` comments for
27
- * something else can configure a different prefix (design/ARCHITECTURE.md,
28
- * "SourceCode and Language objects").
27
+ * something else can configure a different prefix.
29
28
  * @defaultValue `"eslint"`
30
29
  */
31
30
  readonly directivePrefix?: string;
@@ -79,8 +78,7 @@ export interface NormalizedShellLanguageOptions extends Record<string, unknown>
79
78
  * nonexistent version like `'99.99'` is accepted — shape is validated, not
80
79
  * membership in a known-versions list), or when `directivePrefix` is present
81
80
  * but not a valid directive-comment label (see {@link DIRECTIVE_PREFIX_PATTERN}).
82
- * Unknown keys are silently ignored, per the ESLint `Language` contract
83
- * (design/ARCHITECTURE.md's `languageOptions` schema comment).
81
+ * Unknown keys are silently ignored, per the ESLint `Language` contract.
84
82
  *
85
83
  * The parameter is treated as `Record<string, unknown>` internally (rather
86
84
  * than trusting {@link ShellLanguageOptions}'s declared field types) because
@@ -1 +1 @@
1
- {"version":3,"file":"shell-language-options.d.ts","sourceRoot":"","sources":["../../src/language/shell-language-options.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AA4D3C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,oBAAqB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACnE,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;;;;;OAQG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,8BAA+B,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7E,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,IAAI,wBAAwB,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,4BAA4B,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CA8B3F;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvC,8BAA8B,CAkBhC"}
1
+ {"version":3,"file":"shell-language-options.d.ts","sourceRoot":"","sources":["../../src/language/shell-language-options.ts"],"names":[],"mappings":"AAAA,mGAAmG;AACnG,uHAAuH;AACvH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAyDtE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,oBAAqB,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACnE,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAE/B;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,8BAA+B,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC7E,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,MAAM,IAAI,wBAAwB,CAAC;CACpC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,4BAA4B,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CA8B3F;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACvC,8BAA8B,CAkBhC"}
@@ -1,22 +1,18 @@
1
1
  /**
2
2
  * The full set of dialects {@link ShellLanguage.validateLanguageOptions}
3
3
  * accepts, in the order surfaced by its error message. Mirrors
4
- * `sh-ast`'s `SUPPORTED_SHELL_DIALECTS` (see
5
- * design/ARCHITECTURE.md, "Parse errors and dialects", and
6
- * design/PACKAGES.md's `languageOptions` schema) — kept as an independent
7
- * constant here (rather than imported) because the bridge does not export
8
- * its internal list; both lists are exercised by tests that pin the same
9
- * five dialect names.
4
+ * the consumer's configuration labels; the syntax interface itself accepts
5
+ * upstream numeric constants rather than these configuration strings.
10
6
  */
11
7
  const SUPPORTED_SHELL_DIALECTS = ['bash', 'posix', 'mksh', 'bats', 'zsh'];
8
+ /** Narrows configuration labels without treating arbitrary strings as parser variants. */
12
9
  function isShellDialect(value) {
13
10
  return (typeof value === 'string' && SUPPORTED_SHELL_DIALECTS.includes(value));
14
11
  }
15
12
  /**
16
13
  * Default for {@link ShellLanguageOptions.directivePrefix} — the
17
- * ESLint-conventional spelling (design/ARCHITECTURE.md, "SourceCode and
18
- * Language objects": "The directive prefix is configurable but defaults to
19
- * the ESLint-conventional spelling").
14
+ * ESLint-conventional spelling. The directive prefix is configurable but
15
+ * defaults to the ESLint-conventional spelling.
20
16
  */
21
17
  const DEFAULT_DIRECTIVE_PREFIX = 'eslint';
22
18
  /**
@@ -29,6 +25,7 @@ const DEFAULT_DIRECTIVE_PREFIX = 'eslint';
29
25
  * is a strict improvement.
30
26
  */
31
27
  const DIRECTIVE_PREFIX_PATTERN = /^[a-z]+(?:-[a-z]+)*$/u;
28
+ /** Requires a label that the directive parser can recognize once a command suffix is appended. */
32
29
  function isValidDirectivePrefix(value) {
33
30
  return typeof value === 'string' && DIRECTIVE_PREFIX_PATTERN.test(value);
34
31
  }
@@ -56,8 +53,7 @@ function isValidShellVersionShape(value) {
56
53
  * nonexistent version like `'99.99'` is accepted — shape is validated, not
57
54
  * membership in a known-versions list), or when `directivePrefix` is present
58
55
  * but not a valid directive-comment label (see {@link DIRECTIVE_PREFIX_PATTERN}).
59
- * Unknown keys are silently ignored, per the ESLint `Language` contract
60
- * (design/ARCHITECTURE.md's `languageOptions` schema comment).
56
+ * Unknown keys are silently ignored, per the ESLint `Language` contract.
61
57
  *
62
58
  * The parameter is treated as `Record<string, unknown>` internally (rather
63
59
  * than trusting {@link ShellLanguageOptions}'s declared field types) because
@@ -1 +1 @@
1
- {"version":3,"file":"shell-language-options.js","sourceRoot":"","sources":["../../src/language/shell-language-options.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,wBAAwB,GAA4B,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAEnG,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ,IAAK,wBAA8C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC7F,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,wBAAwB,GAAG,QAAQ,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,wBAAwB,GAAG,uBAAuB,CAAC;AAEzD,SAAS,sBAAsB,CAAC,KAAc;IAC5C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAEjD,SAAS,wBAAwB,CAAC,KAAa;IAC7C,OAAO,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3C,CAAC;AA6ED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,4BAA4B,CAAC,eAAwC;IACnF,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,GAAG,eAAe,CAAC;IACnE,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,SAAS,CACjB,oEAAoE,wBAAwB,CAAC,IAAI,CAC/F,IAAI,CACL,cAAc,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAC1C,CAAC;IACJ,CAAC;IACD,IAAI,YAAY,KAAK,SAAS,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;QACnE,MAAM,IAAI,SAAS,CACjB,kGAAkG,IAAI,CAAC,SAAS,CAC9G,YAAY,CACb,GAAG,CACL,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,CAAC,wBAAwB,CAAC,YAAY,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,SAAS,CACjB,yHAAyH,IAAI,CAAC,SAAS,CACrI,YAAY,CACb,GAAG,CACL,CAAC;IACJ,CAAC;IACD,IAAI,eAAe,KAAK,SAAS,IAAI,CAAC,sBAAsB,CAAC,eAAe,CAAC,EAAE,CAAC;QAC9E,MAAM,IAAI,SAAS,CACjB,8JAA8J,IAAI,CAAC,SAAS,CAC1K,eAAe,CAChB,GAAG,CACL,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,6BAA6B,CAC3C,eAAwC;IAExC,MAAM,OAAO,GAAI,eAAe,CAAC,OAAoC,IAAI,MAAM,CAAC;IAChF,MAAM,eAAe,GAClB,eAAe,CAAC,eAAsC,IAAI,wBAAwB,CAAC;IACtF,MAAM,YAAY,GAAG,eAAe,CAAC,YAAkC,CAAC;IACxE,OAAO;QACL,OAAO;QACP,eAAe;QACf,mEAAmE;QACnE,wEAAwE;QACxE,+DAA+D;QAC/D,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;QACvD,MAAM;YACJ,OAAO,YAAY,KAAK,SAAS;gBAC/B,CAAC,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE;gBAC9B,CAAC,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;QACjD,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"shell-language-options.js","sourceRoot":"","sources":["../../src/language/shell-language-options.ts"],"names":[],"mappings":"AAIA;;;;;GAKG;AACH,MAAM,wBAAwB,GAA4B,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAEnG,0FAA0F;AAC1F,SAAS,cAAc,CAAC,KAAc;IACpC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ,IAAK,wBAA8C,CAAC,QAAQ,CAAC,KAAK,CAAC,CAC7F,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,wBAAwB,GAAG,QAAQ,CAAC;AAE1C;;;;;;;;GAQG;AACH,MAAM,wBAAwB,GAAG,uBAAuB,CAAC;AAEzD,kGAAkG;AAClG,SAAS,sBAAsB,CAAC,KAAc;IAC5C,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,qBAAqB,GAAG,kBAAkB,CAAC;AAEjD,SAAS,wBAAwB,CAAC,KAAa;IAC7C,OAAO,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC3C,CAAC;AA0ED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,4BAA4B,CAAC,eAAwC;IACnF,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,GAAG,eAAe,CAAC;IACnE,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,SAAS,CACjB,oEAAoE,wBAAwB,CAAC,IAAI,CAC/F,IAAI,CACL,cAAc,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAC1C,CAAC;IACJ,CAAC;IACD,IAAI,YAAY,KAAK,SAAS,IAAI,OAAO,YAAY,KAAK,QAAQ,EAAE,CAAC;QACnE,MAAM,IAAI,SAAS,CACjB,kGAAkG,IAAI,CAAC,SAAS,CAC9G,YAAY,CACb,GAAG,CACL,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,CAAC,wBAAwB,CAAC,YAAY,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,SAAS,CACjB,yHAAyH,IAAI,CAAC,SAAS,CACrI,YAAY,CACb,GAAG,CACL,CAAC;IACJ,CAAC;IACD,IAAI,eAAe,KAAK,SAAS,IAAI,CAAC,sBAAsB,CAAC,eAAe,CAAC,EAAE,CAAC;QAC9E,MAAM,IAAI,SAAS,CACjB,8JAA8J,IAAI,CAAC,SAAS,CAC1K,eAAe,CAChB,GAAG,CACL,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,6BAA6B,CAC3C,eAAwC;IAExC,MAAM,OAAO,GAAI,eAAe,CAAC,OAAoC,IAAI,MAAM,CAAC;IAChF,MAAM,eAAe,GAClB,eAAe,CAAC,eAAsC,IAAI,wBAAwB,CAAC;IACtF,MAAM,YAAY,GAAG,eAAe,CAAC,YAAkC,CAAC;IACxE,OAAO;QACL,OAAO;QACP,eAAe;QACf,mEAAmE;QACnE,wEAAwE;QACxE,+DAA+D;QAC/D,GAAG,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC;QACvD,MAAM;YACJ,OAAO,YAAY,KAAK,SAAS;gBAC/B,CAAC,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE;gBAC9B,CAAC,CAAC,EAAE,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC;QACjD,CAAC;KACF,CAAC;AACJ,CAAC"}