@eslint-sh/eslint-plugin 0.4.0 β†’ 0.6.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 (256) hide show
  1. package/README.md +223 -17
  2. package/dist/command-harvest/builtins/bash.d.ts +36 -0
  3. package/dist/command-harvest/builtins/bash.js +98 -0
  4. package/dist/command-harvest/builtins/bats.d.ts +45 -0
  5. package/dist/command-harvest/builtins/bats.js +33 -0
  6. package/dist/command-harvest/builtins/index.d.ts +18 -0
  7. package/dist/command-harvest/builtins/index.js +39 -0
  8. package/dist/command-harvest/builtins/posix.d.ts +51 -0
  9. package/dist/command-harvest/builtins/posix.js +93 -0
  10. package/dist/command-harvest/harvest-commands.d.ts +66 -0
  11. package/dist/command-harvest/harvest-commands.js +97 -0
  12. package/dist/command-harvest/wrapper-table.d.ts +24 -0
  13. package/dist/command-harvest/wrapper-table.js +49 -0
  14. package/dist/configs/agent-authored.d.ts +41 -0
  15. package/dist/configs/agent-authored.js +33 -0
  16. package/dist/configs/bash-3-2.d.ts +28 -0
  17. package/dist/configs/bash-3-2.js +50 -0
  18. package/dist/configs/posix-portable.d.ts +40 -0
  19. package/dist/configs/posix-portable.js +52 -0
  20. package/dist/configs/recommended.d.ts +52 -0
  21. package/dist/configs/recommended.js +34 -0
  22. package/dist/declaration-conventions/comment-pragma.d.ts +33 -0
  23. package/dist/declaration-conventions/comment-pragma.js +153 -0
  24. package/dist/declaration-conventions/declaration-convention.d.ts +189 -0
  25. package/dist/declaration-conventions/declaration-convention.js +1 -0
  26. package/dist/declaration-conventions/read-declared-commands.d.ts +70 -0
  27. package/dist/declaration-conventions/read-declared-commands.js +128 -0
  28. package/dist/eslint-plugin-syntax-analyze.d.ts +23 -0
  29. package/dist/eslint-plugin-syntax.d.ts +27 -0
  30. package/dist/eslint-plugin.d.ts +1211 -52
  31. package/dist/index.d.ts +56 -8
  32. package/dist/index.js +53 -6
  33. package/dist/language/command-resolution.d.ts +124 -0
  34. package/dist/language/command-resolution.js +120 -0
  35. package/dist/language/end-of-input-marker.d.ts +29 -0
  36. package/dist/language/end-of-input-marker.js +88 -0
  37. package/dist/language/line-breaks.d.ts +18 -0
  38. package/dist/language/line-breaks.js +22 -0
  39. package/dist/language/lint-view-types.d.ts +104 -0
  40. package/dist/language/lint-view-types.js +1 -0
  41. package/dist/language/non-shell-file-guard.d.ts +35 -0
  42. package/dist/language/non-shell-file-guard.js +59 -0
  43. package/dist/language/selector-classes.d.ts +0 -1
  44. package/dist/language/selector-classes.js +0 -1
  45. package/dist/language/shell-language-options.d.ts +7 -1
  46. package/dist/language/shell-language-options.js +4 -4
  47. package/dist/language/shell-language.d.ts +10 -2
  48. package/dist/language/shell-language.js +59 -8
  49. package/dist/language/shell-source-code.d.ts +342 -5
  50. package/dist/language/shell-source-code.js +559 -30
  51. package/dist/language/source-coordinates.d.ts +13 -2
  52. package/dist/language/source-coordinates.js +68 -14
  53. package/dist/language/syntax-view.d.ts +60 -39
  54. package/dist/language/syntax-view.js +200 -45
  55. package/dist/language/word-resolution.d.ts +4 -3
  56. package/dist/language/word-resolution.js +4 -3
  57. package/dist/rules/compat/create-compat-rule.d.ts +59 -0
  58. package/dist/rules/compat/create-compat-rule.js +65 -0
  59. package/dist/rules/compat/declaration-options.d.ts +19 -0
  60. package/dist/rules/compat/declaration-options.js +110 -0
  61. package/dist/rules/compat/no-append-all-redirect.d.ts +13 -0
  62. package/dist/rules/compat/no-append-all-redirect.js +73 -0
  63. package/dist/rules/compat/no-associative-arrays.d.ts +12 -0
  64. package/dist/rules/compat/no-associative-arrays.js +39 -0
  65. package/dist/rules/compat/no-case-attributes.d.ts +12 -0
  66. package/dist/rules/compat/no-case-attributes.js +63 -0
  67. package/dist/rules/compat/no-case-fallthrough.d.ts +12 -0
  68. package/dist/rules/compat/no-case-fallthrough.js +67 -0
  69. package/dist/rules/compat/no-case-modification.d.ts +35 -0
  70. package/dist/rules/compat/no-case-modification.js +86 -0
  71. package/dist/rules/compat/no-coproc.d.ts +12 -0
  72. package/dist/rules/compat/no-coproc.js +47 -0
  73. package/dist/rules/compat/no-declare-g.d.ts +12 -0
  74. package/dist/rules/compat/no-declare-g.js +59 -0
  75. package/dist/rules/compat/no-double-bracket.d.ts +12 -0
  76. package/dist/rules/compat/no-double-bracket.js +52 -0
  77. package/dist/rules/compat/no-epoch-variables.d.ts +12 -0
  78. package/dist/rules/compat/no-epoch-variables.js +57 -0
  79. package/dist/rules/compat/no-fd-variable.d.ts +12 -0
  80. package/dist/rules/compat/no-fd-variable.js +48 -0
  81. package/dist/rules/compat/no-globstar.d.ts +12 -0
  82. package/dist/rules/compat/no-globstar.js +39 -0
  83. package/dist/rules/compat/no-lastpipe-semantics.d.ts +12 -0
  84. package/dist/rules/compat/no-lastpipe-semantics.js +53 -0
  85. package/dist/rules/compat/no-let.d.ts +12 -0
  86. package/dist/rules/compat/no-let.js +62 -0
  87. package/dist/rules/compat/no-mapfile.d.ts +13 -0
  88. package/dist/rules/compat/no-mapfile.js +122 -0
  89. package/dist/rules/compat/no-nameref.d.ts +12 -0
  90. package/dist/rules/compat/no-nameref.js +44 -0
  91. package/dist/rules/compat/no-negative-array-index.d.ts +13 -0
  92. package/dist/rules/compat/no-negative-array-index.js +123 -0
  93. package/dist/rules/compat/no-nounset-empty-array.d.ts +13 -0
  94. package/dist/rules/compat/no-nounset-empty-array.js +158 -0
  95. package/dist/rules/compat/no-parameter-transformation.d.ts +13 -0
  96. package/dist/rules/compat/no-parameter-transformation.js +123 -0
  97. package/dist/rules/compat/no-pipe-all.d.ts +13 -0
  98. package/dist/rules/compat/no-pipe-all.js +68 -0
  99. package/dist/rules/compat/no-printf-time-format.d.ts +12 -0
  100. package/dist/rules/compat/no-printf-time-format.js +99 -0
  101. package/dist/rules/compat/no-source.d.ts +13 -0
  102. package/dist/rules/compat/no-source.js +103 -0
  103. package/dist/rules/compat/no-test-v.d.ts +12 -0
  104. package/dist/rules/compat/no-test-v.js +280 -0
  105. package/dist/rules/compat/no-unicode-escape.d.ts +14 -0
  106. package/dist/rules/compat/no-unicode-escape.js +120 -0
  107. package/dist/rules/compat/no-wait-n.d.ts +12 -0
  108. package/dist/rules/compat/no-wait-n.js +73 -0
  109. package/dist/rules/compat/operator-range.d.ts +10 -0
  110. package/dist/rules/compat/operator-range.js +15 -0
  111. package/dist/rules/compat/posix-absent-command.d.ts +12 -0
  112. package/dist/rules/compat/posix-absent-command.js +134 -0
  113. package/dist/rules/compat/shopt-options.d.ts +9 -0
  114. package/dist/rules/compat/shopt-options.js +63 -0
  115. package/dist/rules/compat/version-gates.d.ts +76 -0
  116. package/dist/rules/compat/version-gates.js +197 -0
  117. package/dist/rules/create-rule.d.ts +91 -0
  118. package/dist/rules/create-rule.js +51 -0
  119. package/dist/rules/create-wrapper-rule.d.ts +166 -0
  120. package/dist/rules/create-wrapper-rule.js +407 -0
  121. package/dist/rules/define-shell-rule.d.ts +184 -0
  122. package/dist/rules/define-shell-rule.js +56 -0
  123. package/dist/rules/index.d.ts +26 -0
  124. package/dist/rules/index.js +88 -0
  125. package/dist/rules/max-script-complexity.d.ts +28 -0
  126. package/dist/rules/max-script-complexity.js +130 -0
  127. package/dist/rules/no-dynamic-invocation.d.ts +35 -0
  128. package/dist/rules/no-dynamic-invocation.js +117 -0
  129. package/dist/rules/no-eval.d.ts +13 -0
  130. package/dist/rules/no-eval.js +89 -0
  131. package/dist/rules/no-masked-exit-status.d.ts +21 -0
  132. package/dist/rules/no-masked-exit-status.js +667 -0
  133. package/dist/rules/no-secret-env-reads.d.ts +24 -0
  134. package/dist/rules/no-secret-env-reads.js +133 -0
  135. package/dist/rules/no-secret-flags.d.ts +32 -0
  136. package/dist/rules/no-secret-flags.js +162 -0
  137. package/dist/rules/no-unchecked-cd.d.ts +44 -0
  138. package/dist/rules/no-unchecked-cd.js +250 -0
  139. package/dist/rules/no-undeclared-commands.d.ts +20 -0
  140. package/dist/rules/no-undeclared-commands.js +115 -0
  141. package/dist/rules/no-unused-declarations.d.ts +23 -0
  142. package/dist/rules/no-unused-declarations.js +259 -0
  143. package/dist/rules/prefer-local.d.ts +16 -0
  144. package/dist/rules/prefer-local.js +249 -0
  145. package/dist/rules/quote-expansions.d.ts +13 -0
  146. package/dist/rules/quote-expansions.js +229 -0
  147. package/dist/rules/require-network-wrapper.d.ts +40 -0
  148. package/dist/rules/require-network-wrapper.js +244 -0
  149. package/dist/rules/require-shebang.d.ts +29 -0
  150. package/dist/rules/require-shebang.js +101 -0
  151. package/dist/rules/require-strict-mode.d.ts +52 -0
  152. package/dist/rules/require-strict-mode.js +177 -0
  153. package/dist/rules/require-tty-guard.d.ts +13 -0
  154. package/dist/rules/require-tty-guard.js +289 -0
  155. package/dist/rules/resolve-declaration-convention.d.ts +96 -0
  156. package/dist/rules/resolve-declaration-convention.js +109 -0
  157. package/dist/rules/resolve-network-wrapper.d.ts +19 -0
  158. package/dist/rules/resolve-network-wrapper.js +116 -0
  159. package/dist/rules/set-options.d.ts +109 -0
  160. package/dist/rules/set-options.js +201 -0
  161. package/dist/rules/shebang-interpreter.d.ts +18 -0
  162. package/dist/rules/shebang-interpreter.js +81 -0
  163. package/dist/rules/shebang-matches-dialect.d.ts +12 -0
  164. package/dist/rules/shebang-matches-dialect.js +69 -0
  165. package/dist/rules/transparent-wrappers.d.ts +52 -0
  166. package/dist/rules/transparent-wrappers.js +99 -0
  167. package/dist/rules/user-pattern.d.ts +63 -0
  168. package/dist/rules/user-pattern.js +184 -0
  169. package/dist/syntax/analyze.d.ts +19 -0
  170. package/dist/syntax/analyze.js +21 -0
  171. package/dist/syntax/index.d.ts +23 -0
  172. package/dist/syntax/index.js +25 -0
  173. package/dist/version.d.ts +0 -1
  174. package/dist/version.js +0 -1
  175. package/docs/compat.md +347 -0
  176. package/docs/custom-rule-tutorial.md +780 -34
  177. package/docs/declaration-conventions.md +478 -0
  178. package/docs/examples/audit-wrapper-pack.mjs +15 -0
  179. package/docs/examples/dep-line-convention.mjs +22 -0
  180. package/docs/examples/eslint.config.mjs +3 -2
  181. package/docs/examples/no-and-or-as-if-rule.mjs +61 -0
  182. package/docs/examples/no-backticks-rule-tester.mjs +106 -0
  183. package/docs/examples/no-backticks-rule.mjs +60 -0
  184. package/docs/examples/no-curl-in-functions-rule.mjs +53 -0
  185. package/docs/examples/no-function-keyword-rule.mjs +59 -0
  186. package/docs/examples/no-listed-commands-rule.ts +63 -0
  187. package/docs/examples/no-rm-rf-rule.mjs +26 -15
  188. package/docs/examples/no-unquoted-rm-variable-rule.ts +54 -0
  189. package/docs/examples/sidecar-convention.mjs +38 -0
  190. package/docs/examples/sidecar-snapshot-convention.mjs +26 -0
  191. package/docs/examples/sorted-declarations-rule.mjs +52 -0
  192. package/docs/reading-nodes.md +159 -0
  193. package/docs/rules/README.md +78 -0
  194. package/docs/rules/_template.md +83 -0
  195. package/docs/rules/compat/no-append-all-redirect.md +87 -0
  196. package/docs/rules/compat/no-associative-arrays.md +95 -0
  197. package/docs/rules/compat/no-case-attributes.md +82 -0
  198. package/docs/rules/compat/no-case-fallthrough.md +90 -0
  199. package/docs/rules/compat/no-case-modification.md +74 -0
  200. package/docs/rules/compat/no-coproc.md +76 -0
  201. package/docs/rules/compat/no-declare-g.md +80 -0
  202. package/docs/rules/compat/no-double-bracket.md +72 -0
  203. package/docs/rules/compat/no-epoch-variables.md +79 -0
  204. package/docs/rules/compat/no-fd-variable.md +78 -0
  205. package/docs/rules/compat/no-globstar.md +74 -0
  206. package/docs/rules/compat/no-lastpipe-semantics.md +73 -0
  207. package/docs/rules/compat/no-let.md +78 -0
  208. package/docs/rules/compat/no-mapfile.md +118 -0
  209. package/docs/rules/compat/no-nameref.md +81 -0
  210. package/docs/rules/compat/no-negative-array-index.md +87 -0
  211. package/docs/rules/compat/no-nounset-empty-array.md +103 -0
  212. package/docs/rules/compat/no-parameter-transformation.md +94 -0
  213. package/docs/rules/compat/no-pipe-all.md +85 -0
  214. package/docs/rules/compat/no-printf-time-format.md +75 -0
  215. package/docs/rules/compat/no-source.md +98 -0
  216. package/docs/rules/compat/no-test-v.md +82 -0
  217. package/docs/rules/compat/no-unicode-escape.md +91 -0
  218. package/docs/rules/compat/no-wait-n.md +85 -0
  219. package/docs/rules/max-script-complexity.md +109 -0
  220. package/docs/rules/no-dynamic-invocation.md +139 -0
  221. package/docs/rules/no-eval.md +106 -0
  222. package/docs/rules/no-masked-exit-status.md +239 -0
  223. package/docs/rules/no-secret-env-reads.md +173 -0
  224. package/docs/rules/no-secret-flags.md +169 -0
  225. package/docs/rules/no-unchecked-cd.md +146 -0
  226. package/docs/rules/no-undeclared-commands.md +141 -0
  227. package/docs/rules/no-unused-declarations.md +216 -0
  228. package/docs/rules/prefer-local.md +221 -0
  229. package/docs/rules/quote-expansions.md +157 -0
  230. package/docs/rules/require-network-wrapper.md +171 -0
  231. package/docs/rules/require-shebang.md +157 -0
  232. package/docs/rules/require-strict-mode.md +253 -0
  233. package/docs/rules/require-tty-guard.md +128 -0
  234. package/docs/rules/shebang-matches-dialect.md +120 -0
  235. package/docs/selectors.md +2 -2
  236. package/docs/shellcheck.md +86 -0
  237. package/docs/wrapper-rules.md +206 -0
  238. package/package.json +26 -20
  239. package/dist/index.d.ts.map +0 -1
  240. package/dist/index.js.map +0 -1
  241. package/dist/language/selector-classes.d.ts.map +0 -1
  242. package/dist/language/selector-classes.js.map +0 -1
  243. package/dist/language/shell-language-options.d.ts.map +0 -1
  244. package/dist/language/shell-language-options.js.map +0 -1
  245. package/dist/language/shell-language.d.ts.map +0 -1
  246. package/dist/language/shell-language.js.map +0 -1
  247. package/dist/language/shell-source-code.d.ts.map +0 -1
  248. package/dist/language/shell-source-code.js.map +0 -1
  249. package/dist/language/source-coordinates.d.ts.map +0 -1
  250. package/dist/language/source-coordinates.js.map +0 -1
  251. package/dist/language/syntax-view.d.ts.map +0 -1
  252. package/dist/language/syntax-view.js.map +0 -1
  253. package/dist/language/word-resolution.d.ts.map +0 -1
  254. package/dist/language/word-resolution.js.map +0 -1
  255. package/dist/version.d.ts.map +0 -1
  256. package/dist/version.js.map +0 -1
@@ -1,7 +1,10 @@
1
1
  import { TextSourceCodeBase } from '@eslint/plugin-kit';
2
- import type { ShellFile as ShFile, ShellNode as ShNode, ShellComment } from './syntax-view.js';
2
+ import type { ShellFile as ShFile, ShellNode as ShNode, ShellNodeOf, ShellComment } from './syntax-view.js';
3
3
  import type { Directive as IDirective, FileProblem, RulesConfig, SourceLocation, TraversalStep } from '@eslint/core';
4
- import type { ShellLanguageOptions } from './shell-language-options.js';
4
+ import type { Node as SyntaxNode, PrintOptions, SyntaxPos } from 'sh-ast';
5
+ import type { Argv0Resolution, ResolveArgv0Options, ResolveWordOptions } from 'sh-ast/analyze';
6
+ import type { ShellDialect, ShellLanguageOptions } from './shell-language-options.js';
7
+ import type { ShellCommandSite } from './command-resolution.js';
5
8
  /**
6
9
  * `ShellSourceCode` β€” the `SourceCode` object ESLint uses to work with a
7
10
  * parsed shell file. Extends `@eslint/plugin-kit`'s `TextSourceCodeBase`, which
@@ -18,8 +21,8 @@ import type { ShellLanguageOptions } from './shell-language-options.js';
18
21
  * `applyInlineConfig`) recognizes all four disable-comment forms
19
22
  * (`<prefix>-disable`, `<prefix>-enable`, `<prefix>-disable-line`,
20
23
  * `<prefix>-disable-next-line`) plus whole-file inline rule config
21
- * (bare `<prefix> <rule-config>`), sourced from `Comment` nodes gathered via
22
- * the consumer's `walkShell()` and parsed with
24
+ * (bare `<prefix> <rule-config>`), sourced from the tree's `Comment` nodes
25
+ * and parsed with
23
26
  * `@eslint/plugin-kit`'s `ConfigCommentParser` β€” the same building blocks
24
27
  * `@eslint/json`'s `JSONSourceCode` uses, generalized so the `<prefix>` is
25
28
  * configurable (default `"eslint"`; see `ShellLanguageOptions.directivePrefix`)
@@ -29,6 +32,24 @@ import type { ShellLanguageOptions } from './shell-language-options.js';
29
32
  * classes) is implemented on `ShellLanguage` β€” see `shell-language.ts` and
30
33
  * `selector-classes.ts`.
31
34
  *
35
+ * Rule-author helpers (`resolveWordText`, `getCommandName`,
36
+ * `resolveInvokedCommand`, `getCommandSites`) answer "is this word statically
37
+ * the string `jq`?", "which command does this invocation run?", and "which
38
+ * commands does this file run, and where?" by delegating to
39
+ * `sh-ast/analyze`. They never reinterpret words themselves, so every rule
40
+ * gets the same answer for the same syntax. `dialect` and `shellVersion`
41
+ * expose the file's normalized language options.
42
+ *
43
+ * Syntax access (`getSyntax`, `getViewNode`, `getIndexFromSyntaxPos`,
44
+ * `getLocFromSyntaxPos`) reaches behind the lint view to the sh-ast records
45
+ * this file was parsed into: from a view node to its record and back, and
46
+ * from a record's byte positions (such as `BinaryCmd.OpPos`, which the view
47
+ * leaves out) to ESLint coordinates in this file's text.
48
+ *
49
+ * Printed fixes (`getEditableSyntax`, `getPrintedReplacement`) edit an
50
+ * independent copy of a view node's record and print it with sh-ast's
51
+ * printer, returning the source range and text for `fixer.replaceTextRange`.
52
+ *
32
53
  * @public
33
54
  */
34
55
  export declare class ShellSourceCode extends TextSourceCodeBase<{
@@ -42,7 +63,324 @@ export declare class ShellSourceCode extends TextSourceCodeBase<{
42
63
  text: string;
43
64
  ast: ShFile;
44
65
  directivePrefix?: string;
66
+ dialect?: ShellDialect;
67
+ shellVersion?: string;
45
68
  });
69
+ /**
70
+ * The shell dialect this file was parsed as: the normalized
71
+ * `languageOptions.dialect`, which defaults to `"bash"` when the config
72
+ * leaves it unset. Rules use it to gate dialect-specific checks.
73
+ */
74
+ get dialect(): ShellDialect;
75
+ /**
76
+ * The configured `languageOptions.shellVersion` (a `MAJOR[.MINOR]` string
77
+ * such as `"3.2"`), or `undefined` when the config does not set one. The
78
+ * parser never reads it; it exists for rules that gate on shell version.
79
+ */
80
+ get shellVersion(): string | undefined;
81
+ /**
82
+ * The one-based location of a UTF-16 `index` in this file's text, where
83
+ * `index` may be anywhere from 0 to `text.length`. CRLF counts as one line
84
+ * break.
85
+ *
86
+ * Overrides the base class, which measures every index from the root
87
+ * node's own start and so assumes the root spans the whole text. A shell
88
+ * file's root starts at its first statement or comment, so the base answer
89
+ * was shifted by any leading blank lines or indentation.
90
+ *
91
+ * @throws TypeError when `index` is not a number.
92
+ * @throws RangeError when `index` is not an integer from 0 to `text.length`.
93
+ */
94
+ getLocFromIndex(index: number): {
95
+ line: number;
96
+ column: number;
97
+ };
98
+ /**
99
+ * The UTF-16 index of a one-based `loc` in this file's text: the inverse of
100
+ * {@link ShellSourceCode.getLocFromIndex}. The column may name any position
101
+ * on its line up to and including the line break.
102
+ *
103
+ * Overrides the base class for the same reason as `getLocFromIndex`.
104
+ *
105
+ * @throws TypeError when `loc` is not an object with numeric `line` and `column`.
106
+ * @throws RangeError when `loc` is not inside the text.
107
+ */
108
+ getIndexFromLoc(loc: {
109
+ line: number;
110
+ column: number;
111
+ }): number;
112
+ /**
113
+ * Returns the literal text of `word` when `sh-ast/analyze`'s `resolveWord`
114
+ * reports it static, or `null` otherwise.
115
+ *
116
+ * Delegates to `resolveWord` (through this package's `resolveWord` export),
117
+ * which alone defines what "static" means: a word is static iff
118
+ * `resolveWord` reports `static: true`. Its non-static reasons are
119
+ * `expansion`, `tilde`, `glob`, `brace`, `locale`, and `unsupported`.
120
+ * Call the root `resolveWord` export instead when the reason matters.
121
+ *
122
+ * `options` is forwarded to `resolveWord` unchanged. When it is omitted, the
123
+ * word's grammar position picks the tilde context: a word in a `CallExpr`'s
124
+ * `args` uses `{ context: 'command-argument' }`, the context
125
+ * `enumerateCommands` uses for argv, so `resolveWordText(callExpr.args[0])`
126
+ * equals `getCommandName(callExpr)`. Any other word uses `resolveWord`'s
127
+ * conservative default, which also treats a `~` after an unquoted `:` as a
128
+ * tilde expansion, as assignment values do.
129
+ *
130
+ * @param word - A parsed `Word` node from this file's lint tree.
131
+ * @param options - Forwarded to `resolveWord` unchanged when supplied.
132
+ * @returns The resolved text, or `null` when the word is not static.
133
+ * @throws TypeError when `word` is not a parsed shell `Word`.
134
+ */
135
+ resolveWordText(word: ShellNodeOf<'Word'>, options?: ResolveWordOptions): string | null;
136
+ /**
137
+ * Returns the static text of `callExpr`'s command word (`argv[0]`) as
138
+ * written, or `null` when that word is dynamic or absent. Transparent
139
+ * wrappers are **not** followed: `sudo rm x` yields `"sudo"`. Use
140
+ * {@link ShellSourceCode.resolveInvokedCommand} for the command a wrapper
141
+ * chain actually runs.
142
+ *
143
+ * Delegates to `sh-ast/analyze`: the answer is the `argv0` resolution of the
144
+ * `CommandSite` that `enumerateCommands` reports for this `CallExpr` in this
145
+ * file. Leading `VAR=val` assignments are not part of argv, so
146
+ * `FOO=1 jq .` yields `"jq"`. An assignment-only statement (`FOO=1`) has no
147
+ * argv0 and no `CommandSite`, and yields `null`.
148
+ *
149
+ * @param callExpr - A parsed `CallExpr` node from this file's lint tree.
150
+ * @returns The command word's static text, or `null`.
151
+ * @throws TypeError when `callExpr` is not a parsed shell `CallExpr`.
152
+ * @throws `ShAnalyzeMaxDepthError` (from `sh-ast/analyze`) when this file's
153
+ * nesting exceeds analysis's recursion guard; see
154
+ * {@link ShellSourceCode.resolveInvokedCommand}.
155
+ */
156
+ getCommandName(callExpr: ShellNodeOf<'CallExpr'>): string | null;
157
+ /**
158
+ * Follows `callExpr`'s argv0 through transparent wrappers (`env`, `sudo`,
159
+ * `nohup`, `exec`, …) and returns `sh-ast/analyze`'s full `resolveArgv0`
160
+ * result, or `null` for a `CallExpr` that has no `CommandSite` (an
161
+ * assignment-only statement such as `FOO=1`).
162
+ *
163
+ * Delegates to `resolveArgv0` with the `CommandSite` that `enumerateCommands`
164
+ * reports for this `CallExpr` in this file, so it inherits that function's
165
+ * guarantee that an unknowable word is never guessed through. Read the
166
+ * effective command's name as
167
+ * `res.effective.static ? res.effective.text : null`.
168
+ * `sudo -u x "$prog"` and `exec "$@"` have a non-static `effective` with
169
+ * reason `expansion`; `env -S '…'` has reason `embedded-command`; `chain`
170
+ * lists every word resolved along the way, outermost wrapper first, and
171
+ * `chainIndices` gives each entry's position in the command's `argv` (as
172
+ * {@link ShellSourceCode.getCommandSites} reports it). When `effective` is
173
+ * static, the effective command's arguments are
174
+ * `argv.slice(chainIndices.at(-1)! + 1)`: every entry after the effective
175
+ * command's own index.
176
+ *
177
+ * Enumeration runs once per file, the first time any command helper is
178
+ * called. If the file's nesting exceeds `enumerateCommands`'s recursion
179
+ * guard, its `ShAnalyzeMaxDepthError` propagates unchanged and ESLint
180
+ * reports the rule as crashed for that file. That fails closed: a partial
181
+ * index would silently omit real commands.
182
+ *
183
+ * @param callExpr - A parsed `CallExpr` node from this file's lint tree.
184
+ * @param options - Forwarded to `resolveArgv0` unchanged.
185
+ * `transparentWrappers` replaces `sh-ast/analyze`'s
186
+ * `DEFAULT_TRANSPARENT_WRAPPERS`; spread the defaults into the array to
187
+ * extend them instead.
188
+ * @returns The resolution, or `null` when `callExpr` invokes no command.
189
+ * @throws TypeError when `callExpr` is not a parsed shell `CallExpr`.
190
+ * @throws `ShAnalyzeMaxDepthError` (from `sh-ast/analyze`) when this file's
191
+ * nesting exceeds analysis's recursion guard.
192
+ * @throws `ShAnalyzeInvalidWrapperSpecError` (from `sh-ast/analyze`) when
193
+ * `options.transparentWrappers` contains a malformed entry.
194
+ */
195
+ resolveInvokedCommand(callExpr: ShellNodeOf<'CallExpr'>, options?: ResolveArgv0Options): Argv0Resolution | null;
196
+ /**
197
+ * Returns every command invocation in this file, one entry per
198
+ * `sh-ast/analyze` `CommandSite`, in source order. Use it when a rule needs
199
+ * the whole file's commands with their structural context, such as every
200
+ * command inside a function or inside `$(…)`, instead of visiting
201
+ * `CallExpr` nodes one by one.
202
+ *
203
+ * The data comes from `sh-ast/analyze`'s `enumerateCommands`: facts about
204
+ * how each command is reached and what its words resolve to, never a
205
+ * verdict. Each entry's `context`, `argv0`, and `argv` are analysis's own
206
+ * values, unchanged; `context` lists frames outermost first, as in sh-ast.
207
+ * Each entry's `node` is the `CallExpr` view node (`===` the node ESLint
208
+ * passes to a `CallExpr` visitor), so it can be passed to
209
+ * `context.report()`.
210
+ *
211
+ * An assignment-only statement (`FOO=1`) runs no command and has no entry,
212
+ * although a command substitution in its value (`FOO=$(date)`) does.
213
+ *
214
+ * Enumeration runs at most once per file, shared with
215
+ * {@link ShellSourceCode.getCommandName} and
216
+ * {@link ShellSourceCode.resolveInvokedCommand}, and every call returns the
217
+ * same array. Because every rule shares it, the array and everything in each
218
+ * entry except `node` are deeply frozen (see `ShellCommandSite`): no rule can
219
+ * change what another rule reads. If the file's nesting exceeds `enumerateCommands`'s
220
+ * recursion guard, its `ShAnalyzeMaxDepthError` propagates unchanged, as it
221
+ * does for those helpers: a partial list would silently omit real commands.
222
+ *
223
+ * @returns This file's command sites, in source order.
224
+ * @throws `ShAnalyzeMaxDepthError` (from `sh-ast/analyze`) when this file's
225
+ * nesting exceeds analysis's recursion guard.
226
+ */
227
+ getCommandSites(): readonly ShellCommandSite[];
228
+ /**
229
+ * Returns the sh-ast record `node` was projected from: this file's original
230
+ * parse of `node`, with every field the lint view leaves out, including
231
+ * named token positions such as `BinaryCmd.OpPos`, `Stmt.Semicolon` and
232
+ * `Redirect.OpPos`. Pass those positions to
233
+ * {@link ShellSourceCode.getIndexFromSyntaxPos} or
234
+ * {@link ShellSourceCode.getLocFromSyntaxPos} to report on them, or pass the
235
+ * record to an `sh-ast/analyze` function.
236
+ *
237
+ * The returned record is read-only by contract. It is the language's
238
+ * original parse, shared by every rule and helper linting this file, and
239
+ * mutating it is unsupported: helpers such as
240
+ * {@link ShellSourceCode.resolveWordText} read the same record and would see
241
+ * the edit. It is not frozen, so a write does not throw. Make edits on an
242
+ * editable copy from {@link ShellSourceCode.getEditableSyntax} instead.
243
+ *
244
+ * @param node - A view node from this file's lint tree.
245
+ * @returns The original sh-ast record, or `undefined` when `node` has none
246
+ * in this file: an auxiliary view (a record whose type is not an sh-ast
247
+ * `Node`, such as the `Slice` of `${x:1:2}`), a view node from another
248
+ * file's tree, or an
249
+ * object that did not come from the parser.
250
+ */
251
+ getSyntax(node: ShNode): SyntaxNode | undefined;
252
+ /**
253
+ * Returns the lint view node projected from `syntax`: the inverse of
254
+ * {@link ShellSourceCode.getSyntax}. The result is the same object (`===`)
255
+ * ESLint passes to rule visitors, so it can be passed to
256
+ * `context.report()`. Use it to come back to the view after navigating the
257
+ * original records, for example from a `Stmt` record's `Cmd`.
258
+ *
259
+ * Lookup is by object identity, so only the parser's own records match.
260
+ * sh-ast's `walk` passes its callback a fresh copy of each comment stored
261
+ * on a `Stmt`, `CaseItem` or `ArrayElem`, as Go's `syntax.Walk` does, so
262
+ * those `Comment` copies have no view node. Read the stored comment from
263
+ * the record's `Comments` array instead.
264
+ *
265
+ * @param syntax - An sh-ast `Node` record from this file's original parse.
266
+ * @returns The view node, or `undefined` for any other record, including a
267
+ * copy of one of this file's records (such as a `structuredClone`) and a
268
+ * record from another parse.
269
+ */
270
+ getViewNode(syntax: SyntaxNode): ShNode | undefined;
271
+ /**
272
+ * Returns an independent, editable deep copy of the sh-ast record `node`
273
+ * was parsed from: the first half of a printed fix. Edit the copy, then pass
274
+ * it to {@link ShellSourceCode.getPrintedReplacement}.
275
+ *
276
+ * The copy is `structuredClone` of the record
277
+ * {@link ShellSourceCode.getSyntax} returns. sh-ast documents and tests
278
+ * ordinary `structuredClone` as the supported way to make an independent
279
+ * editable copy of a syntax subtree (sh-ast 0.7.0 README, "Editing and
280
+ * printing"), so no second parse is involved. The copy owns its records,
281
+ * arrays, positions and byte buffers. Editing it leaves this file's original
282
+ * syntax, its lint view, its cached traversal and the answers of view-aware
283
+ * helpers such as `resolveWord` and
284
+ * {@link ShellSourceCode.resolveWordText} unchanged. Each call returns a new
285
+ * copy.
286
+ *
287
+ * The copy's position fields keep their original values, and the copy has
288
+ * no view node: {@link ShellSourceCode.getViewNode},
289
+ * {@link ShellSourceCode.getIndexFromSyntaxPos} and the parse's position
290
+ * snapshot describe the original source, not the edit. Keep `node` to know
291
+ * which source range the fix replaces.
292
+ *
293
+ * @param node - A view node from this file's lint tree.
294
+ * @returns A deep copy of `node`'s original sh-ast record.
295
+ * @throws TypeError when `node` has no original record in this file: an
296
+ * auxiliary view (such as the `Slice` of `${x:1:2}`), a view node of another
297
+ * file, or an object that did not come from the parser.
298
+ */
299
+ getEditableSyntax(node: ShNode): SyntaxNode;
300
+ /**
301
+ * Prints `edited` with sh-ast's `printSync` and pairs the text with the
302
+ * source range it replaces, so a printed fix is
303
+ * `fix: (fixer) => fixer.replaceTextRange(r.range, r.text)`. `edited` is
304
+ * usually a copy from {@link ShellSourceCode.getEditableSyntax} of `node`
305
+ * or of one of its ancestors.
306
+ *
307
+ * The range is `node.range`, except that a `File` root replaces the whole
308
+ * text (`[0, text.length]`) whatever `node` is, which allows whole-file
309
+ * regeneration. `options` is passed to `printSync` unchanged.
310
+ *
311
+ * The printer formats; it does not replay the source. Its output starts at
312
+ * column 0 and indents nested lines with upstream's indentation (tabs by
313
+ * default, `Indent` spaces when `options.Indent` is set). Replacing a
314
+ * multi-line root nested inside other code, such as an `if` statement in a
315
+ * function body, therefore keeps the shell meaning but may change the
316
+ * formatting of its lines. Use a `Word` or `WordPart` root for a surgical
317
+ * fix that leaves the surrounding source as written.
318
+ *
319
+ * A `Stmt` root is adjusted so its text matches `node.range`. A statement's
320
+ * own leading and trailing comments lie outside its range, so they are not
321
+ * printed (the copy passed in is not modified). When `node` is a statement
322
+ * whose range ends in its `;` or `&` terminator, upstream prints the
323
+ * statement without a `;`, so a `;` is appended unless the edited statement
324
+ * prints its own `&`, `|&` or disown operator. Without this, replacing `a`
325
+ * in `a; b` would produce `a b`.
326
+ *
327
+ * @param node - A view node from this file's lint tree: the node the fix
328
+ * replaces.
329
+ * @param edited - The record to print: a `File`, `Stmt`, `Word`, `Assign`,
330
+ * `Command` or `WordPart`.
331
+ * @param options - Forwarded to `printSync` unchanged.
332
+ * @returns The range to replace and the printed text to put there.
333
+ * @throws TypeError when `node` has no original record in this file (see
334
+ * {@link ShellSourceCode.getEditableSyntax}), when `edited` is not a
335
+ * printable root (the message names its type), or when the printer's output
336
+ * is not valid UTF-8. Non-UTF-8 output comes back from `printSync` as a
337
+ * `Uint8Array` and is never decoded lossily into a fix.
338
+ * @throws `PrintError` or `PrintPanicError` (from sh-ast) when upstream's
339
+ * printer fails for `edited` or `options`.
340
+ */
341
+ getPrintedReplacement(node: ShNode, edited: SyntaxNode, options?: PrintOptions): {
342
+ range: [number, number];
343
+ text: string;
344
+ };
345
+ /**
346
+ * Converts a byte position from this file's original parse into the
347
+ * UTF-16 index ESLint uses for `range` and `text.slice`. sh-ast positions
348
+ * count UTF-8 bytes, so a raw `Offset` is wrong for any source with
349
+ * non-ASCII text before it. For example, in `echo πŸŽ‰ && echo δΈ­ζ–‡`,
350
+ * `getIndexFromSyntaxPos(binaryCmd.OpPos)` is the index where `&&` starts.
351
+ *
352
+ * The conversion is only correct for positions of this file's original
353
+ * parse, as read from {@link ShellSourceCode.getSyntax}'s records. The live
354
+ * positions of an edited or copied tree describe that edit, not this
355
+ * source.
356
+ *
357
+ * @param pos - A `SyntaxPos` from one of this file's original records.
358
+ * @returns The UTF-16 index of `pos` in this file's text.
359
+ * @throws RangeError when `pos` is invalid (`IsValid === false`), recovered
360
+ * (`IsRecovered === true`), or overflowed (`OffsetOverflow === true`), or
361
+ * when its offset is not a UTF-8 character boundary of this source. Such a
362
+ * position is never rounded to a nearby boundary.
363
+ * @throws TypeError when `pos` is not a `SyntaxPos`, or when this source
364
+ * code's tree was not built by this language's parser.
365
+ */
366
+ getIndexFromSyntaxPos(pos: SyntaxPos): number;
367
+ /**
368
+ * Converts a byte position from this file's original parse into a one-based
369
+ * ESLint location, the shape `context.report({ loc })` takes. The column
370
+ * counts UTF-16 code units, not bytes, and CRLF counts as one line break.
371
+ * Same contract as {@link ShellSourceCode.getIndexFromSyntaxPos}.
372
+ *
373
+ * @param pos - A `SyntaxPos` from one of this file's original records.
374
+ * @returns The one-based line and UTF-16 column of `pos`.
375
+ * @throws RangeError when `pos` is invalid, recovered, or overflowed, or
376
+ * when its offset is not a UTF-8 character boundary of this source.
377
+ * @throws TypeError when `pos` is not a `SyntaxPos`, or when this source
378
+ * code's tree was not built by this language's parser.
379
+ */
380
+ getLocFromSyntaxPos(pos: SyntaxPos): {
381
+ line: number;
382
+ column: number;
383
+ };
46
384
  /**
47
385
  * Returns the parent of `node`, or `undefined` for the root `File` node
48
386
  * (or any node visited before `traverse()` has run once). ESLint always
@@ -109,4 +447,3 @@ export declare class ShellSourceCode extends TextSourceCodeBase<{
109
447
  problems: FileProblem[];
110
448
  };
111
449
  }
112
- //# sourceMappingURL=shell-source-code.d.ts.map