@eslint-sh/eslint-plugin 0.3.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 (38) hide show
  1. package/README.md +10 -6
  2. package/dist/eslint-plugin.d.ts +91 -68
  3. package/dist/index.d.ts +12 -26
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +10 -26
  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 +4 -4
  36. package/docs/examples/no-rm-rf-rule.mjs +2 -2
  37. package/docs/selectors.md +9 -0
  38. package/package.json +9 -3
@@ -1,12 +1,11 @@
1
- import type { ShFile, ShNode } from 'sh-ast';
2
1
  import type { File, Language, OkParseResult, ParseResult } from '@eslint/core';
3
2
  import { ShellSourceCode } from './shell-source-code.js';
3
+ import type { ShellFile, ShellNode } from './syntax-view.js';
4
4
  import { type NormalizedShellLanguageOptions, type ShellLanguageOptions } from './shell-language-options.js';
5
5
  /**
6
6
  * `ShellLanguage` — the `@eslint/core` `Language` implementation for shell
7
- * scripts (design/ARCHITECTURE.md, "SourceCode and Language objects";
8
- * design/PACKAGES.md, `@eslint-sh/eslint-plugin`). Registered by the plugin
9
- * as `languages.sh`, so consumers select it via `language: "sh/sh"`.
7
+ * scripts. Registered by the plugin as `languages.sh`, so consumers select
8
+ * it via `language: "sh/sh"`.
10
9
  *
11
10
  * Implements `matchesSelectorClass` (the six launch esquery selector
12
11
  * classes — see `./selector-classes.js`), so rules and end users can write
@@ -49,23 +48,22 @@ export declare class ShellLanguage implements Language {
49
48
  * needed there, but `:loop :command` is) match a whole family of node
50
49
  * types instead of one literal type name. Delegates to
51
50
  * `./selector-classes.js`'s `SELECTOR_CLASS_NODE_TYPES` table for the six
52
- * launch classes (design/ARCHITECTURE.md, "SourceCode and Language
53
- * objects"); `ancestry` is unused today because none of the six launch
51
+ * launch classes; `ancestry` is unused today because none of the six launch
54
52
  * classes need ancestor context, but the parameter is accepted to match
55
53
  * `Language.matchesSelectorClass`'s signature exactly.
56
54
  */
57
- matchesSelectorClass(className: string, node: ShNode, _ancestry: ShNode[]): boolean;
55
+ matchesSelectorClass(className: string, node: ShellNode, _ancestry: ShellNode[]): boolean;
58
56
  /**
59
57
  * Parses `file.body` (guaranteed to be a `string`, since `fileType` is
60
- * `"text"`) via `sh-ast`'s `parseSync`, mapping the result to
58
+ * `"text"`) with one synchronous parse and its original-position snapshot,
59
+ * mapping the result to
61
60
  * the `{ok: true, ast}` / `{ok: false, errors}` shape `Language.parse` is
62
61
  * required to return. Never throws — parse failures are reported as
63
- * fatal lint messages, per the `Language` contract
64
- * (design/ARCHITECTURE.md, "Parse errors and dialects").
62
+ * fatal lint messages, per the `Language` contract.
65
63
  */
66
64
  parse(file: File, context: {
67
65
  languageOptions: ShellLanguageOptions;
68
- }): ParseResult<ShFile>;
66
+ }): ParseResult<ShellFile>;
69
67
  /**
70
68
  * Creates the `ShellSourceCode` ESLint uses to run rules against `ast`.
71
69
  * `context.languageOptions` is ESLint's already-normalized copy (see
@@ -77,7 +75,7 @@ export declare class ShellLanguage implements Language {
77
75
  * direct construction (e.g. tests that skip the `Language` normalization
78
76
  * step), mirroring `parse()`'s `dialect` default above.
79
77
  */
80
- createSourceCode(file: File, parseResult: OkParseResult<ShFile>, context: {
78
+ createSourceCode(file: File, parseResult: OkParseResult<ShellFile>, context: {
81
79
  languageOptions: ShellLanguageOptions;
82
80
  }): ShellSourceCode;
83
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"shell-language.d.ts","sourceRoot":"","sources":["../../src/language/shell-language.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAgB,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC3D,OAAO,KAAK,EAAE,IAAI,EAAa,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE1F,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAGL,KAAK,8BAA8B,EACnC,KAAK,oBAAoB,EAC1B,MAAM,6BAA6B,CAAC;AAsFrC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAc,YAAW,QAAQ;IAC5C,QAAQ,CAAC,QAAQ,EAAG,MAAM,CAAU;IACpC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAU;IAChC,QAAQ,CAAC,WAAW,EAAG,CAAC,CAAU;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAU;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAA2B;IACzE,QAAQ,CAAC,sBAAsB,EAAE,oBAAoB,CAAuB;IAE5E;;;;;;;;OAQG;IACH,uBAAuB,CAAC,eAAe,EAAE,oBAAoB,GAAG,IAAI;IAIpE;;;;;;OAMG;IACH,wBAAwB,CAAC,eAAe,EAAE,oBAAoB,GAAG,8BAA8B;IAI/F;;;;;;;;;;OAUG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO;IAInF;;;;;;;OAOG;IACH,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAAE,eAAe,EAAE,oBAAoB,CAAA;KAAE,GAAG,WAAW,CAAC,MAAM,CAAC;IAY1F;;;;;;;;;;OAUG;IACH,gBAAgB,CACd,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,EAClC,OAAO,EAAE;QAAE,eAAe,EAAE,oBAAoB,CAAA;KAAE,GACjD,eAAe;CAOnB"}
1
+ {"version":3,"file":"shell-language.d.ts","sourceRoot":"","sources":["../../src/language/shell-language.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,IAAI,EAAa,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE1F,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAGL,KAAK,8BAA8B,EAEnC,KAAK,oBAAoB,EAC1B,MAAM,6BAA6B,CAAC;AA+CrC;;;;;;;;;;;;;;GAcG;AACH,qBAAa,aAAc,YAAW,QAAQ;IAC5C,QAAQ,CAAC,QAAQ,EAAG,MAAM,CAAU;IACpC,QAAQ,CAAC,SAAS,EAAG,CAAC,CAAU;IAChC,QAAQ,CAAC,WAAW,EAAG,CAAC,CAAU;IAClC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAU;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAA2B;IACzE,QAAQ,CAAC,sBAAsB,EAAE,oBAAoB,CAAuB;IAE5E;;;;;;;;OAQG;IACH,uBAAuB,CAAC,eAAe,EAAE,oBAAoB,GAAG,IAAI;IAIpE;;;;;;OAMG;IACH,wBAAwB,CAAC,eAAe,EAAE,oBAAoB,GAAG,8BAA8B;IAI/F;;;;;;;;;OASG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,OAAO;IAIzF;;;;;;;OAOG;IACH,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAAE,eAAe,EAAE,oBAAoB,CAAA;KAAE,GAAG,WAAW,CAAC,SAAS,CAAC;IAiB7F;;;;;;;;;;OAUG;IACH,gBAAgB,CACd,IAAI,EAAE,IAAI,EACV,WAAW,EAAE,aAAa,CAAC,SAAS,CAAC,EACrC,OAAO,EAAE;QAAE,eAAe,EAAE,oBAAoB,CAAA;KAAE,GACjD,eAAe;CAOnB"}
@@ -1,89 +1,51 @@
1
- import { ShAstError, ShParseError, parseSync, visitorKeys as shellVisitorKeys } from 'sh-ast';
1
+ /** Adapts upstream parsing and diagnostics to ESLint's synchronous Language contract. */
2
+ import { LangBash, LangBats, LangError, LangMirBSDKorn, LangPOSIX, LangZsh, ParseError, parseWithPositionsSync, } from 'sh-ast';
2
3
  import { matchesSelectorClass as matchesShellSelectorClass } from './selector-classes.js';
3
4
  import { ShellSourceCode } from './shell-source-code.js';
5
+ import { SourceCoordinates } from './source-coordinates.js';
6
+ import { adaptSyntaxFile, shellVisitorKeys } from './syntax-view.js';
4
7
  import { normalizeShellLanguageOptions, validateShellLanguageOptions, } from './shell-language-options.js';
5
- /**
6
- * `sh-ast`'s `visitorKeys` is deep-frozen and typed with
7
- * `readonly string[]` arrays (a shared, immutable table safe to hand to any
8
- * number of consumers). `@eslint/core`'s `Language.visitorKeys` types this
9
- * property as mutable `Record<string, string[]>` for historical reasons,
10
- * even though ESLint itself only ever reads it. Rather than cast away the
11
- * mismatch, build one genuinely mutable (if still logically frozen-in-spirit)
12
- * copy at module load — a one-time, small-object cost.
13
- */
8
+ /** Configuration labels map to exact upstream constants; no shell-version policy is added to parsing. */
9
+ const DIALECT_VARIANTS = {
10
+ bash: LangBash,
11
+ posix: LangPOSIX,
12
+ mksh: LangMirBSDKorn,
13
+ bats: LangBats,
14
+ zsh: LangZsh,
15
+ };
16
+ /** ESLint declares mutable visitor arrays; give it its own copy of the shared consumer relationships. */
14
17
  const mutableShellVisitorKeys = Object.fromEntries(Object.entries(shellVisitorKeys).map(([type, keys]) => [type, [...keys]]));
15
18
  /**
16
- * Escapes every regex-special character in `value` so it can be embedded
17
- * literally inside a `RegExp` source string. Used by
18
- * {@link stripPositionPrefix} to build a filename-specific prefix pattern
19
- * without the filename's own characters (e.g. `.` in `b.sh`, or any
20
- * sandbox-path characters) being interpreted as regex metacharacters.
21
- */
22
- function escapeRegExp(value) {
23
- return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
24
- }
25
- /**
26
- * Strips mvdan/sh's own `<filename>:<line>:<col>: ` prefix from a
27
- * `ShParseError.message`, if present. mvdan/sh's `.message` is its own
28
- * formatted error string (`sh-ast`'s `parse.ts` passes
29
- * `result.parseError.message` to `ShParseError` verbatim — see that file's
30
- * doc comment), which already embeds the same `filename:line:col` ESLint's
31
- * own fatal-message header prints from `FileError.line`/`.column` — see
32
- * issue #36. Left un-stripped, ESLint's console formatter (and any other
33
- * consumer that reads `message.message`) shows the position twice and
34
- * exposes the sandbox-absolute `file.path` a second time inside the message
35
- * body.
36
- *
37
- * Only strips a prefix that names *this exact* `filename` (escaped, so the
38
- * filename's own characters can't be misread as regex syntax), matched
39
- * against `\d+:\d+` for line/column — mvdan/sh's message uses its own raw
40
- * byte column, which is not always numerically identical to
41
- * `ShParseError.column` (UTF-16-converted; see `ShParseErrorInfo.column`'s
42
- * doc comment). A message that doesn't start with that exact prefix (e.g.
43
- * mvdan/sh changes its format, or `filename` doesn't appear verbatim) is
44
- * returned unchanged rather than mangled.
19
+ * Strip the exact upstream filename/position prefix ESLint renders separately.
20
+ * Upstream formats saturated line/column components as `?`; the source byte
21
+ * offset can still provide an exact UTF-16 location independently of that text.
45
22
  */
46
23
  function stripPositionPrefix(message, filename) {
47
- const prefixPattern = new RegExp(`^${escapeRegExp(filename)}:\\d+:\\d+:\\s*`);
48
- return message.replace(prefixPattern, '');
24
+ const escaped = filename.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
25
+ return message.replace(new RegExp(`^${escaped}:(?:\\d+|\\?):(?:\\d+|\\?):\\s*`), '');
49
26
  }
50
- /**
51
- * Converts a caught `parseSync` failure into the `FileError` ESLint expects
52
- * from a `NotOkParseResult`. A `ShParseError` carries mvdan/sh's *real*
53
- * reported position (`.line`/`.column`, already UTF-16 — see
54
- * `sh-ast`'s `ShParseError` doc comment) and is used verbatim;
55
- * this is the fix for the retired spike's known flaw (`spike/language.mjs`
56
- * hardcoded `{ line: 1, column: 1 }` for every parse failure, discarding the
57
- * position mvdan/sh actually reported). The message text has its duplicated
58
- * `filename:line:col:` prefix stripped (see {@link stripPositionPrefix}) —
59
- * ESLint already renders that position from `.line`/`.column` in its own
60
- * fatal-message header, so embedding it again in the message body is both
61
- * noisy and, for absolute `file.path` values, an unwanted disclosure of the
62
- * sandbox-absolute path (issue #36).
63
- *
64
- * Any other error reaching here (`ShInvalidDialectError` — unreachable in
65
- * practice, since `validateLanguageOptions` rejects a bad dialect before
66
- * ESLint ever calls `parse()`; or `ShInternalError` — a shim contract
67
- * violation) has no real source position to report, so `1:1` is used as an
68
- * explicit, honest fallback for the "no position available" case — not a
69
- * stand-in for an actual parse error's position.
70
- */
71
- function toFileError(error) {
72
- if (error instanceof ShParseError) {
27
+ /** Preserve actual syntax positions while converting byte offsets into this source's UTF-16 diagnostics. */
28
+ function toFileError(error, source) {
29
+ if (error instanceof ParseError || error instanceof LangError) {
30
+ const filename = typeof error.Filename === 'string'
31
+ ? error.Filename
32
+ : new TextDecoder('utf-8', { fatal: true }).decode(error.Filename);
33
+ const location = error.Pos.IsValid && !error.Pos.IsRecovered
34
+ ? new SourceCoordinates(source).fromByteOffset(error.Pos.Offset)
35
+ : { line: 1, column: 1 };
73
36
  return {
74
- message: stripPositionPrefix(error.message, error.filename),
75
- line: error.line,
76
- column: error.column,
37
+ message: stripPositionPrefix(error.message, filename),
38
+ line: location.line,
39
+ column: location.column,
77
40
  };
78
41
  }
79
- const message = error instanceof ShAstError || error instanceof Error ? error.message : String(error);
80
- return { message, line: 1, column: 1 };
42
+ // Bridge/input failures carry no asserted syntax position. The fallback is an ESLint presentation policy.
43
+ return { message: error instanceof Error ? error.message : String(error), line: 1, column: 1 };
81
44
  }
82
45
  /**
83
46
  * `ShellLanguage` — the `@eslint/core` `Language` implementation for shell
84
- * scripts (design/ARCHITECTURE.md, "SourceCode and Language objects";
85
- * design/PACKAGES.md, `@eslint-sh/eslint-plugin`). Registered by the plugin
86
- * as `languages.sh`, so consumers select it via `language: "sh/sh"`.
47
+ * scripts. Registered by the plugin as `languages.sh`, so consumers select
48
+ * it via `language: "sh/sh"`.
87
49
  *
88
50
  * Implements `matchesSelectorClass` (the six launch esquery selector
89
51
  * classes — see `./selector-classes.js`), so rules and end users can write
@@ -130,8 +92,7 @@ export class ShellLanguage {
130
92
  * needed there, but `:loop :command` is) match a whole family of node
131
93
  * types instead of one literal type name. Delegates to
132
94
  * `./selector-classes.js`'s `SELECTOR_CLASS_NODE_TYPES` table for the six
133
- * launch classes (design/ARCHITECTURE.md, "SourceCode and Language
134
- * objects"); `ancestry` is unused today because none of the six launch
95
+ * launch classes; `ancestry` is unused today because none of the six launch
135
96
  * classes need ancestor context, but the parameter is accepted to match
136
97
  * `Language.matchesSelectorClass`'s signature exactly.
137
98
  */
@@ -140,21 +101,26 @@ export class ShellLanguage {
140
101
  }
141
102
  /**
142
103
  * Parses `file.body` (guaranteed to be a `string`, since `fileType` is
143
- * `"text"`) via `sh-ast`'s `parseSync`, mapping the result to
104
+ * `"text"`) with one synchronous parse and its original-position snapshot,
105
+ * mapping the result to
144
106
  * the `{ok: true, ast}` / `{ok: false, errors}` shape `Language.parse` is
145
107
  * required to return. Never throws — parse failures are reported as
146
- * fatal lint messages, per the `Language` contract
147
- * (design/ARCHITECTURE.md, "Parse errors and dialects").
108
+ * fatal lint messages, per the `Language` contract.
148
109
  */
149
110
  parse(file, context) {
150
111
  const text = file.body;
151
112
  const dialect = context.languageOptions.dialect ?? 'bash';
152
113
  try {
153
- const ast = parseSync(text, { dialect, filename: file.path });
114
+ const parsed = parseWithPositionsSync(text, {
115
+ Variant: DIALECT_VARIANTS[dialect],
116
+ Filename: file.path,
117
+ KeepComments: true,
118
+ });
119
+ const ast = adaptSyntaxFile(parsed.File, text, parsed.Positions);
154
120
  return { ok: true, ast };
155
121
  }
156
122
  catch (error) {
157
- return { ok: false, errors: [toFileError(error)] };
123
+ return { ok: false, errors: [toFileError(error, text)] };
158
124
  }
159
125
  }
160
126
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"shell-language.js","sourceRoot":"","sources":["../../src/language/shell-language.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shell-language.js","sourceRoot":"","sources":["../../src/language/shell-language.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,13 @@
1
1
  import { TextSourceCodeBase } from '@eslint/plugin-kit';
2
- import type { ShFile, ShNode, ShNodes } from 'sh-ast';
2
+ import type { ShellFile as ShFile, ShellNode as ShNode, ShellComment } from './syntax-view.js';
3
3
  import type { Directive as IDirective, FileProblem, RulesConfig, SourceLocation, TraversalStep } from '@eslint/core';
4
4
  import type { ShellLanguageOptions } from './shell-language-options.js';
5
5
  /**
6
6
  * `ShellSourceCode` — the `SourceCode` object ESLint uses to work with a
7
- * parsed shell file (design/ARCHITECTURE.md, "SourceCode and Language
8
- * objects"). Extends `@eslint/plugin-kit`'s `TextSourceCodeBase`, which
7
+ * parsed shell file. Extends `@eslint/plugin-kit`'s `TextSourceCodeBase`, which
9
8
  * already implements `getLoc`/`getRange`/`getText`/`lines` (both by reading
10
9
  * the normalized node's own `loc`/`range` fields — see
11
- * `sh-ast`'s "Normalized node shape"), `getLocFromIndex`, and
10
+ * the consumer's source-view contract), `getLocFromIndex`, and
12
11
  * `getIndexFromLoc`; this class adds the two members the base class
13
12
  * deliberately leaves unimplemented: `traverse()` (base throws "Not
14
13
  * implemented") and `getParent()` (base throws "Not implemented", and
@@ -20,7 +19,7 @@ import type { ShellLanguageOptions } from './shell-language-options.js';
20
19
  * (`<prefix>-disable`, `<prefix>-enable`, `<prefix>-disable-line`,
21
20
  * `<prefix>-disable-next-line`) plus whole-file inline rule config
22
21
  * (bare `<prefix> <rule-config>`), sourced from `Comment` nodes gathered via
23
- * `sh-ast`'s structural `walk()` and parsed with
22
+ * the consumer's `walkShell()` and parsed with
24
23
  * `@eslint/plugin-kit`'s `ConfigCommentParser` — the same building blocks
25
24
  * `@eslint/json`'s `JSONSourceCode` uses, generalized so the `<prefix>` is
26
25
  * configurable (default `"eslint"`; see `ShellLanguageOptions.directivePrefix`)
@@ -36,7 +35,7 @@ export declare class ShellSourceCode extends TextSourceCodeBase<{
36
35
  LangOptions: ShellLanguageOptions;
37
36
  RootNode: ShFile;
38
37
  SyntaxElementWithLoc: ShNode;
39
- ConfigNode: ShNodes.ShCommentNode;
38
+ ConfigNode: ShellComment;
40
39
  }> {
41
40
  #private;
42
41
  constructor(options: {
@@ -53,17 +52,9 @@ export declare class ShellSourceCode extends TextSourceCodeBase<{
53
52
  */
54
53
  getParent(node: ShNode): ShNode | undefined;
55
54
  /**
56
- * Traverses the AST pre-order, yielding a `VisitNodeStep` on node enter
57
- * (`phase: 1`) and another on node exit (`phase: 2`) for every node —
58
- * exactly the two-phase shape `@eslint/json`/`@eslint/css` produce, which
59
- * is what lets rule listeners use `NodeType` and `NodeType:exit` esquery
60
- * selectors. Children are discovered via `sh-ast`'s generated,
61
- * frozen `visitorKeys` table (per node `type`) — **not** structurally
62
- * (contrast `sh-ast`'s own `walk()`, which deliberately walks
63
- * structurally so its correctness never depends on that table) — because
64
- * ESLint's traversal contract is defined in terms of a language's
65
- * declared `visitorKeys`, and this class's whole job is to honor that
66
- * contract for shell ASTs.
55
+ * Produces the enter/exit steps ESLint uses for selectors and ancestor lookup.
56
+ * Child keys describe the consumer view, including its auxiliary records.
57
+ * This callback protocol is ESLint's, independent of upstream syntax.Walk.
67
58
  */
68
59
  traverse(): Iterable<TraversalStep>;
69
60
  /**
@@ -74,7 +65,7 @@ export declare class ShellSourceCode extends TextSourceCodeBase<{
74
65
  * effect" when `linterOptions.noInlineConfig` is set — see
75
66
  * `eslint`'s `lib/linter/linter.js`, the `warnInlineConfig` branch).
76
67
  */
77
- getInlineConfigNodes(): ShNodes.ShCommentNode[];
68
+ getInlineConfigNodes(): ShellComment[];
78
69
  /**
79
70
  * Returns the disable/enable directives found among
80
71
  * {@link ShellSourceCode.getInlineConfigNodes}'s comments, recognizing all four forms —
@@ -106,7 +97,7 @@ export declare class ShellSourceCode extends TextSourceCodeBase<{
106
97
  * calling this method — and `getDisableDirectives`, together, since both
107
98
  * are gated by the same flag in `eslint`'s own `linter.js` — and instead
108
99
  * calls `getInlineConfigNodes` to emit a "has no effect" warning per
109
- * comment; see design/ARCHITECTURE.md, "SourceCode and Language objects").
100
+ * comment).
110
101
  */
111
102
  applyInlineConfig(): {
112
103
  configs: {
@@ -1 +1 @@
1
- {"version":3,"file":"shell-source-code.d.ts","sourceRoot":"","sources":["../../src/language/shell-source-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,EAEnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,KAAK,EACV,SAAS,IAAI,UAAU,EAEvB,WAAW,EACX,WAAW,EACX,cAAc,EACd,aAAa,EACd,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAuExE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,eAAgB,SAAQ,kBAAkB,CAAC;IACtD,WAAW,EAAE,oBAAoB,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,UAAU,EAAE,OAAO,CAAC,aAAa,CAAC;CACnC,CAAC;;gBAwDY,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE;IAU5E;;;;;;OAMG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3C;;;;;;;;;;;;OAYG;IACH,QAAQ,IAAI,QAAQ,CAAC,aAAa,CAAC;IAoEnC;;;;;;;OAOG;IACH,oBAAoB,IAAI,OAAO,CAAC,aAAa,EAAE;IAO/C;;;;;;;;;;;;;;;;OAgBG;IACH,oBAAoB,IAAI;QAAE,UAAU,EAAE,UAAU,EAAE,CAAC;QAAC,QAAQ,EAAE,WAAW,EAAE,CAAA;KAAE;IA0B7E;;;;;;;;;;;OAWG;IACH,iBAAiB,IAAI;QACnB,OAAO,EAAE;YAAE,MAAM,EAAE;gBAAE,KAAK,EAAE,WAAW,CAAA;aAAE,CAAC;YAAC,GAAG,EAAE,cAAc,CAAA;SAAE,EAAE,CAAC;QACnE,QAAQ,EAAE,WAAW,EAAE,CAAC;KACzB;CAqBF"}
1
+ {"version":3,"file":"shell-source-code.d.ts","sourceRoot":"","sources":["../../src/language/shell-source-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,kBAAkB,EAEnB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAAE,SAAS,IAAI,MAAM,EAAE,SAAS,IAAI,MAAM,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC/F,OAAO,KAAK,EACV,SAAS,IAAI,UAAU,EAEvB,WAAW,EACX,WAAW,EACX,cAAc,EACd,aAAa,EACd,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AA+MxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,qBAAa,eAAgB,SAAQ,kBAAkB,CAAC;IACtD,WAAW,EAAE,oBAAoB,CAAC;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,UAAU,EAAE,YAAY,CAAC;CAC1B,CAAC;;gBAkDY,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE;IAU5E;;;;;;OAMG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3C;;;;OAIG;IACH,QAAQ,IAAI,QAAQ,CAAC,aAAa,CAAC;IAuDnC;;;;;;;OAOG;IACH,oBAAoB,IAAI,YAAY,EAAE;IAOtC;;;;;;;;;;;;;;;;OAgBG;IACH,oBAAoB,IAAI;QAAE,UAAU,EAAE,UAAU,EAAE,CAAC;QAAC,QAAQ,EAAE,WAAW,EAAE,CAAA;KAAE;IA0B7E;;;;;;;;;;;OAWG;IACH,iBAAiB,IAAI;QACnB,OAAO,EAAE;YAAE,MAAM,EAAE;gBAAE,KAAK,EAAE,WAAW,CAAA;aAAE,CAAC;YAAC,GAAG,EAAE,cAAc,CAAA;SAAE,EAAE,CAAC;QACnE,QAAQ,EAAE,WAAW,EAAE,CAAC;KACzB;CAqBF"}