@eslint-sh/eslint-plugin 0.6.0 → 0.8.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 (147) hide show
  1. package/README.md +19 -8
  2. package/dist/command-harvest/builtins/bash.d.ts +1 -1
  3. package/dist/command-harvest/builtins/bash.js +1 -1
  4. package/dist/command-harvest/builtins/bats.d.ts +2 -0
  5. package/dist/command-harvest/builtins/bats.js +3 -0
  6. package/dist/command-harvest/wrapper-table.d.ts +3 -19
  7. package/dist/command-harvest/wrapper-table.js +8 -38
  8. package/dist/configs/bash-3-2.d.ts +7 -6
  9. package/dist/configs/bash-3-2.js +5 -3
  10. package/dist/configs/posix-portable.d.ts +1 -1
  11. package/dist/configs/posix-portable.js +1 -0
  12. package/dist/declaration-conventions/read-declared-commands.d.ts +2 -2
  13. package/dist/declaration-conventions/read-declared-commands.js +2 -2
  14. package/dist/eslint-plugin-syntax.d.ts +4 -0
  15. package/dist/eslint-plugin.d.ts +86 -40
  16. package/dist/index.d.ts +5 -2
  17. package/dist/index.js +4 -2
  18. package/dist/language/shell-language-options.d.ts +18 -15
  19. package/dist/language/shell-language-options.js +33 -26
  20. package/dist/language/shell-language.d.ts +10 -9
  21. package/dist/language/shell-language.js +18 -35
  22. package/dist/language/shell-source-code.d.ts +17 -9
  23. package/dist/language/shell-source-code.js +53 -12
  24. package/dist/rules/bash-variable-semantics.d.ts +22 -0
  25. package/dist/rules/bash-variable-semantics.js +41 -0
  26. package/dist/rules/compat/create-compat-rule.js +1 -1
  27. package/dist/rules/compat/declaration-options.d.ts +2 -2
  28. package/dist/rules/compat/declaration-options.js +5 -2
  29. package/dist/rules/compat/no-append-all-redirect.js +1 -1
  30. package/dist/rules/compat/no-associative-arrays.js +2 -2
  31. package/dist/rules/compat/no-brace-sequence-padding-step.d.ts +15 -0
  32. package/dist/rules/compat/no-brace-sequence-padding-step.js +287 -0
  33. package/dist/rules/compat/no-case-attributes.js +3 -3
  34. package/dist/rules/compat/no-case-fallthrough.js +2 -2
  35. package/dist/rules/compat/no-case-modification.js +2 -2
  36. package/dist/rules/compat/no-coproc.js +1 -1
  37. package/dist/rules/compat/no-declare-g.js +3 -3
  38. package/dist/rules/compat/no-double-bracket.js +2 -2
  39. package/dist/rules/compat/no-epoch-variables.js +2 -2
  40. package/dist/rules/compat/no-fd-variable.js +1 -1
  41. package/dist/rules/compat/no-globstar.js +1 -1
  42. package/dist/rules/compat/no-lastpipe-semantics.js +2 -2
  43. package/dist/rules/compat/no-let.js +2 -1
  44. package/dist/rules/compat/no-mapfile.js +4 -2
  45. package/dist/rules/compat/no-nameref.js +3 -3
  46. package/dist/rules/compat/no-negative-array-index.js +39 -9
  47. package/dist/rules/compat/no-nounset-empty-array.js +15 -4
  48. package/dist/rules/compat/no-parameter-transformation.js +2 -2
  49. package/dist/rules/compat/no-pipe-all.js +1 -1
  50. package/dist/rules/compat/no-printf-time-format.js +4 -2
  51. package/dist/rules/compat/no-source.js +2 -1
  52. package/dist/rules/compat/no-test-v.js +4 -2
  53. package/dist/rules/compat/no-unicode-escape.js +2 -2
  54. package/dist/rules/compat/no-wait-n.js +4 -2
  55. package/dist/rules/compat/nounset-array-proof.d.ts +8 -0
  56. package/dist/rules/compat/nounset-array-proof.js +563 -0
  57. package/dist/rules/compat/posix-absent-command.d.ts +7 -8
  58. package/dist/rules/compat/posix-absent-command.js +17 -15
  59. package/dist/rules/compat/shopt-options.js +3 -1
  60. package/dist/rules/compat/version-gates.d.ts +10 -10
  61. package/dist/rules/compat/version-gates.js +21 -13
  62. package/dist/rules/create-wrapper-rule.js +12 -7
  63. package/dist/rules/index.js +2 -0
  64. package/dist/rules/no-dynamic-invocation.d.ts +0 -8
  65. package/dist/rules/no-dynamic-invocation.js +7 -15
  66. package/dist/rules/no-eval.js +3 -1
  67. package/dist/rules/no-masked-exit-status.js +15 -8
  68. package/dist/rules/no-secret-env-reads.d.ts +4 -3
  69. package/dist/rules/no-secret-env-reads.js +37 -14
  70. package/dist/rules/no-secret-flags.d.ts +2 -1
  71. package/dist/rules/no-secret-flags.js +7 -8
  72. package/dist/rules/no-unchecked-cd.js +3 -1
  73. package/dist/rules/no-undeclared-commands.d.ts +1 -15
  74. package/dist/rules/no-undeclared-commands.js +3 -15
  75. package/dist/rules/no-unused-declarations.d.ts +1 -18
  76. package/dist/rules/no-unused-declarations.js +9 -34
  77. package/dist/rules/prefer-local.js +4 -3
  78. package/dist/rules/quote-expansions.js +3 -28
  79. package/dist/rules/require-network-wrapper.d.ts +2 -17
  80. package/dist/rules/require-network-wrapper.js +33 -4
  81. package/dist/rules/require-tty-guard.js +30 -1
  82. package/dist/rules/resolve-declaration-convention.d.ts +5 -6
  83. package/dist/rules/resolve-declaration-convention.js +5 -6
  84. package/dist/rules/resolve-network-wrapper.d.ts +19 -0
  85. package/dist/rules/resolve-network-wrapper.js +57 -26
  86. package/dist/rules/resolve-transparent-wrappers.d.ts +43 -0
  87. package/dist/rules/resolve-transparent-wrappers.js +98 -0
  88. package/dist/rules/set-options.d.ts +2 -1
  89. package/dist/rules/set-options.js +17 -5
  90. package/dist/rules/shebang-interpreter.js +4 -2
  91. package/dist/rules/transparent-wrappers.d.ts +4 -3
  92. package/dist/rules/transparent-wrappers.js +5 -4
  93. package/dist/rules/user-pattern.d.ts +5 -3
  94. package/dist/rules/user-pattern.js +6 -4
  95. package/dist/syntax/index.d.ts +4 -0
  96. package/dist/syntax/index.js +4 -0
  97. package/docs/compat.md +90 -34
  98. package/docs/custom-rule-tutorial.md +9 -3
  99. package/docs/examples/no-listed-commands-rule.ts +2 -2
  100. package/docs/rules/README.md +38 -5
  101. package/docs/rules/_template.md +2 -2
  102. package/docs/rules/compat/no-append-all-redirect.md +12 -12
  103. package/docs/rules/compat/no-associative-arrays.md +14 -14
  104. package/docs/rules/compat/no-brace-sequence-padding-step.md +90 -0
  105. package/docs/rules/compat/no-case-attributes.md +13 -13
  106. package/docs/rules/compat/no-case-fallthrough.md +12 -12
  107. package/docs/rules/compat/no-case-modification.md +11 -11
  108. package/docs/rules/compat/no-coproc.md +13 -13
  109. package/docs/rules/compat/no-declare-g.md +13 -13
  110. package/docs/rules/compat/no-double-bracket.md +2 -2
  111. package/docs/rules/compat/no-epoch-variables.md +13 -13
  112. package/docs/rules/compat/no-fd-variable.md +12 -12
  113. package/docs/rules/compat/no-globstar.md +13 -13
  114. package/docs/rules/compat/no-lastpipe-semantics.md +13 -13
  115. package/docs/rules/compat/no-let.md +2 -2
  116. package/docs/rules/compat/no-mapfile.md +16 -16
  117. package/docs/rules/compat/no-nameref.md +13 -13
  118. package/docs/rules/compat/no-negative-array-index.md +14 -14
  119. package/docs/rules/compat/no-nounset-empty-array.md +72 -17
  120. package/docs/rules/compat/no-parameter-transformation.md +19 -19
  121. package/docs/rules/compat/no-pipe-all.md +13 -13
  122. package/docs/rules/compat/no-printf-time-format.md +13 -13
  123. package/docs/rules/compat/no-source.md +2 -2
  124. package/docs/rules/compat/no-test-v.md +12 -12
  125. package/docs/rules/compat/no-unicode-escape.md +13 -13
  126. package/docs/rules/compat/no-wait-n.md +13 -13
  127. package/docs/rules/no-dynamic-invocation.md +17 -12
  128. package/docs/rules/no-eval.md +6 -1
  129. package/docs/rules/no-masked-exit-status.md +4 -0
  130. package/docs/rules/no-secret-env-reads.md +34 -3
  131. package/docs/rules/no-secret-flags.md +19 -2
  132. package/docs/rules/no-unchecked-cd.md +9 -2
  133. package/docs/rules/no-undeclared-commands.md +16 -15
  134. package/docs/rules/no-unused-declarations.md +17 -20
  135. package/docs/rules/prefer-local.md +20 -2
  136. package/docs/rules/quote-expansions.md +8 -5
  137. package/docs/rules/require-network-wrapper.md +22 -17
  138. package/docs/rules/require-shebang.md +10 -4
  139. package/docs/rules/require-strict-mode.md +6 -0
  140. package/docs/rules/require-tty-guard.md +4 -1
  141. package/docs/shellcheck.md +10 -5
  142. package/docs/transparent-wrappers.md +97 -0
  143. package/docs/untrusted-code.md +440 -0
  144. package/docs/wrapper-rules.md +9 -0
  145. package/package.json +2 -2
  146. package/dist/language/end-of-input-marker.d.ts +0 -29
  147. package/dist/language/end-of-input-marker.js +0 -88
@@ -12,6 +12,7 @@ See the [canonical quickstart](https://github.com/mike-north/eslint-sh/blob/main
12
12
  | ---- | ------- | ------- | ----------- | ------- |
13
13
  | [`sh/compat/no-append-all-redirect`](./compat/no-append-all-redirect.md) | `bash-3.2`, `posix-portable` | No | Yes | Disallow the `&>>` redirection when the target shell lacks it, suggesting `>> file 2>&1`. |
14
14
  | [`sh/compat/no-associative-arrays`](./compat/no-associative-arrays.md) | `bash-3.2`, `posix-portable` | No | No | Disallow `declare -A` / `typeset -A` when the target shell lacks associative arrays. |
15
+ | [`sh/compat/no-brace-sequence-padding-step`](./compat/no-brace-sequence-padding-step.md) | `bash-3.2`, `posix-portable` | No | No | Disallow zero-padded (`{01..10}`) and stepped (`{1..10..2}`) brace sequences when the target shell lacks them, pointing at a counting loop. |
15
16
  | [`sh/compat/no-case-attributes`](./compat/no-case-attributes.md) | `bash-3.2`, `posix-portable` | No | No | Disallow `declare -l` / `declare -u` (and `typeset`, `local`) when the target shell lacks them, pointing at `tr`. |
16
17
  | [`sh/compat/no-case-fallthrough`](./compat/no-case-fallthrough.md) | `bash-3.2`, `posix-portable` | No | No | Disallow the `case` terminators `;&` and `;;&` when the target shell lacks them. |
17
18
  | [`sh/compat/no-case-modification`](./compat/no-case-modification.md) | `bash-3.2`, `posix-portable` | No | No | Disallow `${v^^}`, `${v,,}` and variants when the target shell lacks them, pointing at `tr`. |
@@ -26,7 +27,7 @@ See the [canonical quickstart](https://github.com/mike-north/eslint-sh/blob/main
26
27
  | [`sh/compat/no-mapfile`](./compat/no-mapfile.md) | `bash-3.2`, `posix-portable` | No | Yes | Disallow `mapfile` / `readarray` when the target shell lacks them, suggesting a read loop. |
27
28
  | [`sh/compat/no-nameref`](./compat/no-nameref.md) | `bash-3.2`, `posix-portable` | No | No | Disallow namerefs (`declare -n`, `local -n`) when the target shell lacks them. |
28
29
  | [`sh/compat/no-negative-array-index`](./compat/no-negative-array-index.md) | `bash-3.2`, `posix-portable` | No | Yes | Disallow negative array subscripts when the target shell lacks them, suggesting a length-based index. |
29
- | [`sh/compat/no-nounset-empty-array`](./compat/no-nounset-empty-array.md) | `bash-3.2`, `posix-portable` | No | Yes | Disallow whole-array expansions under `set -u` when the target shell aborts on an empty array, suggesting a guarded form. |
30
+ | [`sh/compat/no-nounset-empty-array`](./compat/no-nounset-empty-array.md) | `posix-portable` | No | Yes | Disallow whole-array expansions under `set -u` when the target shell aborts on an empty array, suggesting a guarded form. |
30
31
  | [`sh/compat/no-parameter-transformation`](./compat/no-parameter-transformation.md) | `bash-3.2`, `posix-portable` | No | No | Disallow `${v@op}` transformations when the target shell lacks the operator. |
31
32
  | [`sh/compat/no-pipe-all`](./compat/no-pipe-all.md) | `bash-3.2`, `posix-portable` | No | Yes | Disallow the stderr-merging pipe (pipe-ampersand) when the target shell lacks it, suggesting an explicit `2>&1` before the pipe. |
32
33
  | [`sh/compat/no-printf-time-format`](./compat/no-printf-time-format.md) | `bash-3.2`, `posix-portable` | No | No | Disallow `printf`'s `%(fmt)T` date format when the target shell lacks it. |
@@ -58,10 +59,12 @@ offer editor suggestions, which you apply one at a time from your editor; the Au
58
59
  describes edits available through `eslint --fix`. `quote-expansions` suggests quoting instead of
59
60
  fixing because only the script's author knows whether the splitting was intended.
60
61
 
61
- The version-gated `compat/*` rules (`compat/no-append-all-redirect`, `compat/no-associative-arrays`, `compat/no-case-attributes`, `compat/no-case-fallthrough`, `compat/no-case-modification`, `compat/no-coproc`, `compat/no-declare-g`, `compat/no-epoch-variables`, `compat/no-fd-variable`, `compat/no-globstar`, `compat/no-lastpipe-semantics`, `compat/no-mapfile`, `compat/no-nameref`, `compat/no-negative-array-index`, `compat/no-nounset-empty-array`, `compat/no-parameter-transformation`, `compat/no-pipe-all`, `compat/no-printf-time-format`, `compat/no-test-v`, `compat/no-unicode-escape`, `compat/no-wait-n`) report
62
- shell features that your target shell lacks, as set by `languageOptions.shellVersion` and
63
- `dialect`. They report nothing when `shellVersion` is unset, so the `bash-3.2` preset sets it to `3.2`
64
- and the `posix-portable` preset sets `dialect: "posix"`; each enables all of them.
62
+ The version-gated `compat/*` rules (`compat/no-append-all-redirect`, `compat/no-associative-arrays`, `compat/no-brace-sequence-padding-step`, `compat/no-case-attributes`, `compat/no-case-fallthrough`, `compat/no-case-modification`, `compat/no-coproc`, `compat/no-declare-g`, `compat/no-epoch-variables`, `compat/no-fd-variable`, `compat/no-globstar`, `compat/no-lastpipe-semantics`, `compat/no-mapfile`, `compat/no-nameref`, `compat/no-negative-array-index`, `compat/no-nounset-empty-array`, `compat/no-parameter-transformation`, `compat/no-pipe-all`, `compat/no-printf-time-format`, `compat/no-test-v`, `compat/no-unicode-escape`, `compat/no-wait-n`) report
63
+ shell features that your target shell lacks, as set by `languageOptions.minBashVersion` and
64
+ `dialect`. They report nothing when `minBashVersion` is unset, so the `bash-3.2` preset sets it to `3.2`
65
+ and the `posix-portable` preset sets `dialect: "posix"`. `bash-3.2` enables all except
66
+ `compat/no-nounset-empty-array`, which is opt-in for scripts using `set -u` on Bash below 4.4
67
+ with arrays that can really be empty; `posix-portable` retains all of them.
65
68
  See [version compatibility](../compat.md). `compat/*` means target gates only; `shebang-matches-dialect`
66
69
  compares the file with your config whatever the target, so it lives outside that namespace. `posix-portable` also enables
67
70
  `shebang-matches-dialect`, `require-strict-mode` (as `set -eu`) and the POSIX-only gates
@@ -76,3 +79,33 @@ To run these rules beside shellcheck, see [shellcheck](../shellcheck.md).
76
79
  `require-network-wrapper` reports nothing until you set its `wrapper` option (see
77
80
  [wrapper rules](../wrapper-rules.md)). Each linked rule page documents its options, limitations,
78
81
  and relationship to shellcheck.
82
+
83
+ ## Regular-expression options
84
+
85
+ Every regular-expression source in a rule option is compiled with JavaScript's `u` flag
86
+ (Unicode). `sh/no-secret-flags` also uses `i`, preserving case-insensitive matching for
87
+ both default and custom patterns. `sh/no-secret-env-reads` and `sh/prefer-local` match
88
+ case-sensitively. The original name and pattern are used without lower-casing either.
89
+ Thus `patterns: ['token']` catches `--TOKEN` in `no-secret-flags`, but does not catch
90
+ `$GITHUB_TOKEN` in `no-secret-env-reads`. `allowPattern: '^g_'` exempts `g_cache`, but not
91
+ `G_cache`, in `prefer-local`. Sources are strings, without `/` delimiters or flag suffixes;
92
+ write `\\p{Lu}` in a JavaScript string to match an uppercase Unicode letter.
93
+
94
+ The shared compiler validates syntax with these actual flags, then applies the
95
+ [pattern-safety guard](./no-secret-flags.md#patterns-run-against-script-controlled-text).
96
+ All regex syntax errors, including `(`, fail when the enabled rule first runs on a file.
97
+ The error names the rule, option (including the array index) and pattern; ESLint reports
98
+ "Occurred while linting <file>" and exits with status 2.
99
+
100
+ Config resolution does not compile regex sources: `--print-config` will not catch any regex syntax errors.
101
+ The schemas still check option types and array lengths, but deliberately omit the `regex`
102
+ format. ESLint validates that format without flags, which would reject Unicode-valid sources
103
+ such as `^[\u{41}-\u{5A}]+$` (an uppercase-letter range under `u`). Keeping compilation in the
104
+ rule allows these sources and gives every syntax error the same first-rule-run timing.
105
+
106
+ Migration: sources accepted without `u` may now fail, including identity escapes such as
107
+ `\-` outside a character class, `\q` (also invalid inside `[\q]`), and incomplete quantifiers
108
+ such as `a{,5}`. Use `-`, `q` or `a\\{,5\\}` respectively in JavaScript strings for those
109
+ literal characters. An escaped hyphen **inside** a class (`[\-]`, written `'[\\-]'` in a
110
+ JavaScript string) remains valid. Unicode property escapes (`\p{Lu}`) and code point escapes
111
+ (`\u{1F510}`) now have their Unicode meaning in every regex option.
@@ -15,7 +15,7 @@
15
15
  `{"options": {"maxNesting": 2}, "dialect": "bash"}`, then the usual closing. See any
16
16
  existing page, e.g. `max-script-complexity.md`, for the exact spelling.
17
17
 
18
- Keys: `options` (the rule's options value), `dialect`, `shellVersion`, `convention`
18
+ Keys: `options` (the rule's options value), `dialect`, `minBashVersion`, `convention`
19
19
  (`"commentPragma"`) and `filename`. Under `### Incorrect` you may also state what the prose
20
20
  claims exactly: `findings` (a count), `messageIds` (in report order), `output` (the source
21
21
  after autofix) and `suggestionOutputs`. A typo in the annotation fails the test.
@@ -38,7 +38,7 @@
38
38
 
39
39
  <Why this policy matters for shell scripts, and exactly what the rule reports. Say which
40
40
  node types or constructs it inspects and which it deliberately ignores. If the rule depends on
41
- `languageOptions` (`dialect`, `shellVersion`), say how.>
41
+ `languageOptions` (`dialect`, `minBashVersion`), say how.>
42
42
 
43
43
  ## Options
44
44
 
@@ -21,15 +21,15 @@ Under `dialect: "posix"` the parser itself rejects `&>>`, so a POSIX file that u
21
21
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
22
22
  described in [version compatibility](../../compat.md):
23
23
 
24
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
25
- - `dialect: "bash"` (the default) or `"bats"`: reports when `shellVersion` is older than `4.0`.
24
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
25
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.0`.
26
26
  - `dialect: "mksh"` or `"zsh"`: never reports.
27
27
 
28
28
  ### Suggestion
29
29
 
30
30
  A suggestion rewrites the redirection:
31
31
 
32
- <!-- transform: {"kind": "suggestion", "dialect": "bash", "shellVersion": "3.2"} -->
32
+ <!-- transform: {"kind": "suggestion", "dialect": "bash", "minBashVersion": "3.2"} -->
33
33
  ```sh
34
34
  build &>> build.log
35
35
  # becomes
@@ -38,12 +38,12 @@ build >> build.log 2>&1
38
38
 
39
39
  ## Options
40
40
 
41
- This rule has no options. Set the target through `languageOptions`:
41
+ This rule has no options. Set the required support through `languageOptions`:
42
42
 
43
43
  ```js
44
44
  // eslint.config.js
45
45
  {
46
- languageOptions: { dialect: 'bash', shellVersion: '3.2' },
46
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
47
47
  rules: {
48
48
  'sh/compat/no-append-all-redirect': 'error',
49
49
  },
@@ -54,29 +54,29 @@ This rule has no options. Set the target through `languageOptions`:
54
54
 
55
55
  ### Incorrect
56
56
 
57
- With `shellVersion: "3.2"`:
57
+ With `minBashVersion: "3.2"`:
58
58
 
59
- <!-- example: {"dialect": "bash", "shellVersion": "3.2", "findings": 1} -->
59
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 1} -->
60
60
  ```sh
61
61
  build &>> build.log
62
62
  ```
63
63
 
64
64
  ### Correct
65
65
 
66
- With `shellVersion: "3.2"`:
66
+ With `minBashVersion: "3.2"`:
67
67
 
68
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
68
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
69
69
  ```sh
70
70
  build >> build.log 2>&1
71
71
  build &> build.log
72
72
  echo "use &>> on Bash 4"
73
73
  ```
74
74
 
75
- With `shellVersion: "4.0"` or newer, or with no `shellVersion`, `&>>` is fine.
75
+ With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`, `&>>` is fine.
76
76
 
77
77
  ## When not to use it
78
78
 
79
- Turn the rule off when your scripts never run on Bash older than 4.0, or leave `shellVersion`
79
+ Turn the rule off when your scripts never run on Bash older than 4.0, or leave `minBashVersion`
80
80
  unset, which makes the rule report nothing.
81
81
 
82
82
  ## Relationship to shellcheck
@@ -84,4 +84,4 @@ unset, which makes the rule report nothing.
84
84
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
85
85
  layer. Run shellcheck beside it.
86
86
 
87
- shellcheck 0.11.0 reports nothing for `cmd &>> log` under either `-s sh` or `-s bash`. (`cmd &> log` is different: it reports SC3020 under `-s sh`.) So shellcheck gives no finding for `&>>` in a POSIX sh script or in a Bash 3.2 target. This rule exists for both.
87
+ shellcheck 0.11.0 reports nothing for `cmd &>> log` under either `-s sh` or `-s bash`. (`cmd &> log` is different: it reports SC3020 under `-s sh`.) So shellcheck gives no finding for `&>>` in a POSIX sh script or in a script that must support Bash 3.2. This rule exists for both.
@@ -1,6 +1,6 @@
1
1
  # `sh/compat/no-associative-arrays`
2
2
 
3
- Disallow associative arrays (`declare -A`, `typeset -A`) in scripts whose target shell lacks
3
+ Disallow associative arrays (`declare -A`, `typeset -A`) in scripts that must support a shell lacking
4
4
  them: Bash older than 4.0, including the Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
5
5
 
6
6
  | Configs | Fixable | Languages |
@@ -17,9 +17,9 @@ return the wrong values without an error.
17
17
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
18
18
  described in [version compatibility](../../compat.md):
19
19
 
20
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
21
- - `dialect: "bash"` (the default) or `"bats"`: reports when `shellVersion` is older than `4.0`.
22
- - `dialect: "posix"`: reports at any `shellVersion`, because POSIX sh has no arrays.
20
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
21
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.0`.
22
+ - `dialect: "posix"`: reports regardless of Bash releases, because POSIX sh has no arrays.
23
23
  - `dialect: "mksh"` or `"zsh"`: never reports.
24
24
 
25
25
  The rule reads the options of every `declare` and `typeset` command, up to the first operand,
@@ -37,12 +37,12 @@ The rule deliberately ignores:
37
37
 
38
38
  ## Options
39
39
 
40
- This rule has no options. Set the target through `languageOptions`:
40
+ This rule has no options. Set the required support through `languageOptions`:
41
41
 
42
42
  ```js
43
43
  // eslint.config.js
44
44
  {
45
- languageOptions: { dialect: 'bash', shellVersion: '3.2' },
45
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
46
46
  rules: {
47
47
  'sh/compat/no-associative-arrays': 'error',
48
48
  },
@@ -53,9 +53,9 @@ This rule has no options. Set the target through `languageOptions`:
53
53
 
54
54
  ### Incorrect
55
55
 
56
- With `shellVersion: "3.2"`:
56
+ With `minBashVersion: "3.2"`:
57
57
 
58
- <!-- example: {"dialect": "bash", "shellVersion": "3.2", "findings": 4} -->
58
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 4} -->
59
59
  ```sh
60
60
  declare -A ports # associative arrays need Bash 4.0
61
61
  typeset -A ports # the same declaration through typeset
@@ -65,9 +65,9 @@ builtin declare -A ports # reached through the builtin wrapper
65
65
 
66
66
  ### Correct
67
67
 
68
- With `shellVersion: "3.2"`:
68
+ With `minBashVersion: "3.2"`:
69
69
 
70
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
70
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
71
71
  ```sh
72
72
  # Keep the mapping as JSON and look keys up with jq.
73
73
  port=$(jq -r --arg k "$service" '.[$k]' ports.json)
@@ -75,16 +75,16 @@ port=$(jq -r --arg k "$service" '.[$k]' ports.json)
75
75
  declare -a hosts # indexed arrays exist in Bash 3.2
76
76
  ```
77
77
 
78
- With `shellVersion: "4.0"` or newer, or with no `shellVersion`:
78
+ With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`:
79
79
 
80
- <!-- example: {"dialect": "bash", "shellVersion": "4.0"} -->
80
+ <!-- example: {"dialect": "bash", "minBashVersion": "4.0"} -->
81
81
  ```sh
82
82
  declare -A ports
83
83
  ```
84
84
 
85
85
  ## When not to use it
86
86
 
87
- Turn the rule off when your scripts never run on Bash older than 4.0, or leave `shellVersion`
87
+ Turn the rule off when your scripts never run on Bash older than 4.0, or leave `minBashVersion`
88
88
  unset, which makes the rule report nothing.
89
89
 
90
90
  ## Relationship to shellcheck
@@ -92,4 +92,4 @@ unset, which makes the rule report nothing.
92
92
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
93
93
  layer. Run shellcheck beside it.
94
94
 
95
- shellcheck 0.11.0 reports the command, not the option: under `-s sh`, `declare -A` draws SC3044 (`declare` is undefined in POSIX sh), and `local -A` draws SC3043. Under `-s bash` it reports nothing. It has no way to target a Bash version, so it reports nothing for `declare -A` in a script that must run on Bash 3.2. This rule exists for that target.
95
+ shellcheck 0.11.0 reports the command, not the option: under `-s sh`, `declare -A` draws SC3044 (`declare` is undefined in POSIX sh), and `local -A` draws SC3043. Under `-s bash` it reports nothing. It has no way to check support for a minimum Bash version, so it reports nothing for `declare -A` in a script that must run on Bash 3.2. This rule checks that support requirement.
@@ -0,0 +1,90 @@
1
+ # `sh/compat/no-brace-sequence-padding-step`
2
+
3
+ Disallow zero-padded (`{01..10}`) and stepped (`{1..10..2}`, `{a..e..2}`) brace sequences in scripts
4
+ whose target shell lacks them: Bash older than 4.0, including the Bash 3.2 that macOS ships as
5
+ `/bin/bash`, and POSIX sh.
6
+
7
+ | Configs | Fixable | Languages |
8
+ | ---------------------------- | ----------- | --------- |
9
+ | `bash-3.2`, `posix-portable` | not fixable | `sh/sh` |
10
+
11
+ ## Rule details
12
+
13
+ Both forms arrived in Bash 4.0, and neither fails on Bash 3.2, which is what makes them easy to miss. On Bash 3.2.57, `echo {01..03} {1..9..4}` prints `1 2 3 {1..9..4}` and exits 0: the padding is dropped and the stepped sequence stays as a literal word. The script carries on with different words. POSIX does not specify brace expansion, so what a POSIX target does with these words depends on the shell: dash prints `{01..03} {1..9..4}`, macOS's `/bin/sh` prints `1 2 3` for `{01..03}`, and Bash 5.3 under `--posix` prints `01 02 03`. A plain `{1..3}` is as shell-dependent, but this rule reports only the two forms Bash 4.0 added.
14
+
15
+ The parser keeps a brace sequence as literal text inside a word, so the rule reads the literal text of the words the shell brace-expands. It reports a `{…}` that holds nothing but a sequence:
16
+
17
+ - two integer endpoints (an optional sign and digits) or two single ASCII letters, with an optional third `..` field that is an integer step. A step makes the sequence stepped, for numbers and letters alike, and the step may be `0` or negative.
18
+ - integer endpoints are padded when either has more than one digit and starts with `0` after an optional `-`: `{01..10}`, `{1..03}`, `{-01..1}`, `{00..10}`. A lone `0` (`{0..3}`) and `{-0..2}` are not padded, and neither is a `+01` endpoint, which Bash 5.3 expands without padding, as Bash 3.2 does.
19
+
20
+ Everything else is left alone, because it is the same on every Bash or is not a sequence at all: `{1..3}`, `{a..c}`, a descending `{3..1}`, a comma list (`{01,02}`, `{01..03,x}`), mixed endpoints (`{a..5..2}`), multi-character endpoints, a variable endpoint (`{01..$n}`, which the shell never expands), and a malformed one (`{01..}`, `{1..9..x}`, spaces inside). Quoting and escaping are honoured: `"{01..10}"`, `'{01..10}'`, `$'{01..10}'`, `\{01..10}` and `{01..10\}` are plain text.
21
+
22
+ Only code the parser sees is read: a sequence inside a quoted string that is run later (`eval '...'`, `trap '...'`) is not seen. A sequence is read where the shell brace-expands: command words and arguments, `for` and `select` lists, the elements of an array literal without an index (`a=({01..03})`), and the operands of `declare`, `local`, `export` and `readonly` (also the value in `declare d={01..03}`). It is not read where the shell does no brace expansion: a plain assignment (`a={01..03}`), a `case` subject or pattern, the operands of `[[ ]]`, here-strings and here-documents, parameter-expansion words (`${v:-{01..03}}`), and a keyed array element (`a=([5]={01..03})`). A redirection target (`: > out{01..01}`) is read only when the sequence provably yields one word. With several words the target is an "ambiguous redirect" error on Bash 5.3 (and for a padded sequence on 3.2 too), so the script is broken on every Bash that has the feature and there is nothing to port. With one word the shells disagree silently: `out{01..01}` writes `out1` on Bash 3.2.57 and `out01` on 5.3.9, and `out{1..3..5}` writes a file literally named `out{1..3..5}` on 3.2.57 and `out1` on 5.3.9. A sequence is always static text, so its length is always known; a target that also holds another brace group (`out{01..01}{a,b}`) is not read, because the product cannot be counted here, so a redirect target with more than one brace group is skipped. The same selection applies under `dialect: "posix"`, although the system `dash` creates a literal file such as `out{01..02}` for any of them without an error: a several-word target is still a sequence that no Bash accepts. A here-string or here-document word is never read. A descriptor duplication whose whole target is a one-word sequence is read only where the shells differ (checked on 3.2.57 and 5.3.9). A padded non-negative number names the same descriptor on both (`>&{01..01}`, `2>&{02..02}`, `<&{00..00}`, and `>&{-00..-00}`, which is 0), so it is not reported. A negative number in a descriptor position (`2>&{-01..-01}`, `<&{-01..-01}`, `3>&{-01..-01}`) is an "ambiguous redirect" error on both, so it is not reported either. A stepped sequence still differs (`>&{1..3..5}`, `3>&{1..3..5}` and `<&{0..0..2}` are an error or a literal word on 3.2.57 and descriptor 1 or 0 on 5.3.9), and a bare `>&` with a negative number writes a file named `-1` on 3.2.57 and `-01` on 5.3.9, as does `&>{-01..-01}`, so those are reported. The report is on the whole word, once per word, for the first sequence in it.
23
+
24
+ Numbers are bounded the way Bash 5.3 bounds them, because a word outside the bounds stays literal on every Bash and nothing differs: each endpoint and the distance between them must fit a signed 64-bit integer, and so must the step's magnitude (a step of `-9223372036854775808` is not a step). Leading zeros do not count towards the value, so `{1..00000000000000000003}` is a sequence. `{1..3..999999999999999999999}`, `{1..99999999999999999999}` and `{-1..9223372036854775807..9223372036854775807}` are not reported. These bounds were measured on Bash 5.3.9 and 3.2.57 only; the 4.x releases' bounds were not measured.
25
+
26
+ The portable alternative is to count in a loop and format with `printf`, for example `i=1; while [ "$i" -le 3 ]; do printf '%02d\n' "$i"; i=$((i + 1)); done` for a padded sequence, or `i=1; while [ "$i" -le 9 ]; do echo "$i"; i=$((i + 4)); done` for a stepped one. Both run on Bash 3.2 and on dash.
27
+
28
+ This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
29
+ described in [version compatibility](../../compat.md):
30
+
31
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
32
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.0`.
33
+ - `dialect: "posix"`: reports regardless of Bash releases, because POSIX does not specify brace expansion.
34
+ - `dialect: "mksh"` or `"zsh"`: never reports.
35
+
36
+ ## Options
37
+
38
+ This rule has no options. Set the required support through `languageOptions`:
39
+
40
+ ```js
41
+ // eslint.config.js
42
+ {
43
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
44
+ rules: {
45
+ 'sh/compat/no-brace-sequence-padding-step': 'error',
46
+ },
47
+ }
48
+ ```
49
+
50
+ ## Examples
51
+
52
+ ### Incorrect
53
+
54
+ With `minBashVersion: "3.2"`:
55
+
56
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 3} -->
57
+
58
+ ```sh
59
+ for n in {01..12}; do echo "report-$n"; done
60
+ echo {1..9..4}
61
+ cp backup{a..e..2}.tar /tmp
62
+ ```
63
+
64
+ ### Correct
65
+
66
+ With `minBashVersion: "3.2"`:
67
+
68
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
69
+
70
+ ```sh
71
+ n=1
72
+ while [ "$n" -le 12 ]; do printf 'report-%02d\n' "$n"; n=$((n + 1)); done
73
+ echo {1..3} {a..c}
74
+ echo '{01..12}'
75
+ a={01..03}
76
+ ```
77
+
78
+ With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`, both forms are fine.
79
+
80
+ ## When not to use it
81
+
82
+ Turn the rule off when your scripts never run on Bash older than 4.0, or leave `minBashVersion`
83
+ unset, which makes the rule report nothing.
84
+
85
+ ## Relationship to shellcheck
86
+
87
+ eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
88
+ layer. Run shellcheck beside it.
89
+
90
+ shellcheck 0.11.0 reports SC3009 (brace expansion is undefined in POSIX sh) under `-s sh` for every brace expansion, a plain `{1..3}` and `{a,b}` included. Under `-s bash` it reports nothing for these sequences. It does not know which Bash release a script must run on, so it cannot report the padded and stepped forms for a script that must support Bash 3.2. This rule checks that support requirement.
@@ -1,7 +1,7 @@
1
1
  # `sh/compat/no-case-attributes`
2
2
 
3
3
  Disallow the case-converting attributes `declare -l` and `declare -u` (also through `typeset` and
4
- `local`) in scripts whose target shell lacks them: Bash older than 4.0, including the Bash 3.2
4
+ `local`) in scripts that must support a shell lacking them: Bash older than 4.0, including the Bash 3.2
5
5
  that macOS ships as `/bin/bash`, and POSIX sh.
6
6
 
7
7
  | Configs | Fixable | Languages |
@@ -19,19 +19,19 @@ The portable alternative is to convert the value when it is assigned, with `tr`:
19
19
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
20
20
  described in [version compatibility](../../compat.md):
21
21
 
22
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
23
- - `dialect: "bash"` (the default) or `"bats"`: reports when `shellVersion` is older than `4.0`.
24
- - `dialect: "posix"`: reports at any `shellVersion`, because POSIX sh has no `declare`.
22
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
23
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.0`.
24
+ - `dialect: "posix"`: reports regardless of Bash releases, because POSIX sh has no `declare`.
25
25
  - `dialect: "mksh"` or `"zsh"`: never reports.
26
26
 
27
27
  ## Options
28
28
 
29
- This rule has no options. Set the target through `languageOptions`:
29
+ This rule has no options. Set the required support through `languageOptions`:
30
30
 
31
31
  ```js
32
32
  // eslint.config.js
33
33
  {
34
- languageOptions: { dialect: 'bash', shellVersion: '3.2' },
34
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
35
35
  rules: {
36
36
  'sh/compat/no-case-attributes': 'error',
37
37
  },
@@ -42,9 +42,9 @@ This rule has no options. Set the target through `languageOptions`:
42
42
 
43
43
  ### Incorrect
44
44
 
45
- With `shellVersion: "3.2"`:
45
+ With `minBashVersion: "3.2"`:
46
46
 
47
- <!-- example: {"dialect": "bash", "shellVersion": "3.2", "findings": 2} -->
47
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 2} -->
48
48
 
49
49
  ```sh
50
50
  declare -l answer=$1
@@ -55,9 +55,9 @@ f() {
55
55
 
56
56
  ### Correct
57
57
 
58
- With `shellVersion: "3.2"`:
58
+ With `minBashVersion: "3.2"`:
59
59
 
60
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
60
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
61
61
 
62
62
  ```sh
63
63
  answer=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]')
@@ -67,11 +67,11 @@ f() {
67
67
  }
68
68
  ```
69
69
 
70
- With `shellVersion: "4.0"` or newer, or with no `shellVersion`, the attributes are fine.
70
+ With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`, the attributes are fine.
71
71
 
72
72
  ## When not to use it
73
73
 
74
- Turn the rule off when your scripts never run on Bash older than 4.0, or leave `shellVersion`
74
+ Turn the rule off when your scripts never run on Bash older than 4.0, or leave `minBashVersion`
75
75
  unset, which makes the rule report nothing.
76
76
 
77
77
  ## Relationship to shellcheck
@@ -79,4 +79,4 @@ unset, which makes the rule report nothing.
79
79
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
80
80
  layer. Run shellcheck beside it.
81
81
 
82
- Under `-s sh`, shellcheck 0.11.0 reports the command, not the option: `declare -l` and `declare -u` draw SC3044 (`declare` is undefined in POSIX sh), and `local -l` and `local -u` draw SC3043. Under `-s bash` it reports nothing for these options. It does not know which Bash release a script must run on, so it reports nothing for `declare -l` in a Bash 3.2 target. This rule exists for that target.
82
+ Under `-s sh`, shellcheck 0.11.0 reports the command, not the option: `declare -l` and `declare -u` draw SC3044 (`declare` is undefined in POSIX sh), and `local -l` and `local -u` draw SC3043. Under `-s bash` it reports nothing for these options. It does not know which Bash release a script must run on, so it reports nothing for `declare -l` in a script that must support Bash 3.2. This rule checks that support requirement.
@@ -1,7 +1,7 @@
1
1
  # `sh/compat/no-case-fallthrough`
2
2
 
3
3
  Disallow the `case` terminators `;&` (run the next branch without testing its pattern) and `;;&`
4
- (go on testing the next patterns) in scripts whose target shell lacks them: Bash older than 4.0,
4
+ (go on testing the next patterns) in scripts that must support a shell lacking them: Bash older than 4.0,
5
5
  including the Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
6
6
 
7
7
  | Configs | Fixable | Languages |
@@ -21,18 +21,18 @@ Under `dialect: "posix"` the parser itself rejects both terminators, so a POSIX
21
21
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
22
22
  described in [version compatibility](../../compat.md):
23
23
 
24
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
25
- - `dialect: "bash"` (the default) or `"bats"`: reports when `shellVersion` is older than `4.0`.
24
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
25
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.0`.
26
26
  - `dialect: "mksh"` or `"zsh"`: never reports.
27
27
 
28
28
  ## Options
29
29
 
30
- This rule has no options. Set the target through `languageOptions`:
30
+ This rule has no options. Set the required support through `languageOptions`:
31
31
 
32
32
  ```js
33
33
  // eslint.config.js
34
34
  {
35
- languageOptions: { dialect: 'bash', shellVersion: '3.2' },
35
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
36
36
  rules: {
37
37
  'sh/compat/no-case-fallthrough': 'error',
38
38
  },
@@ -43,9 +43,9 @@ This rule has no options. Set the target through `languageOptions`:
43
43
 
44
44
  ### Incorrect
45
45
 
46
- With `shellVersion: "3.2"`:
46
+ With `minBashVersion: "3.2"`:
47
47
 
48
- <!-- example: {"dialect": "bash", "shellVersion": "3.2", "findings": 2} -->
48
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 2} -->
49
49
  ```sh
50
50
  case $level in
51
51
  debug) verbose=1 ;&
@@ -59,9 +59,9 @@ esac
59
59
 
60
60
  ### Correct
61
61
 
62
- With `shellVersion: "3.2"`:
62
+ With `minBashVersion: "3.2"`:
63
63
 
64
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
64
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
65
65
  ```sh
66
66
  case $level in
67
67
  debug) verbose=1; log=1 ;;
@@ -75,11 +75,11 @@ case $file in
75
75
  esac
76
76
  ```
77
77
 
78
- With `shellVersion: "4.0"` or newer, or with no `shellVersion`, both terminators are fine.
78
+ With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`, both terminators are fine.
79
79
 
80
80
  ## When not to use it
81
81
 
82
- Turn the rule off when your scripts never run on Bash older than 4.0, or leave `shellVersion`
82
+ Turn the rule off when your scripts never run on Bash older than 4.0, or leave `minBashVersion`
83
83
  unset, which makes the rule report nothing.
84
84
 
85
85
  ## Relationship to shellcheck
@@ -87,4 +87,4 @@ unset, which makes the rule report nothing.
87
87
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
88
88
  layer. Run shellcheck beside it.
89
89
 
90
- Under `-s sh`, shellcheck 0.11.0 reports `;&` and `;;&` as an error, SC2127 ("To use cases with ;&, specify #!/usr/bin/env bash or ksh", or the `;;&` equivalent naming bash), not as one of its SC3xxx portability checks. It reports the same SC2127 under `-s dash`, reports `;;&` (but not `;&`) under `-s ksh`, and reports nothing under `-s bash`. It does not know which Bash release a script must run on, so it reports nothing for either operator in a Bash 3.2 target. This rule exists for that target.
90
+ Under `-s sh`, shellcheck 0.11.0 reports `;&` and `;;&` as an error, SC2127 ("To use cases with ;&, specify #!/usr/bin/env bash or ksh", or the `;;&` equivalent naming bash), not as one of its SC3xxx portability checks. It reports the same SC2127 under `-s dash`, reports `;;&` (but not `;&`) under `-s ksh`, and reports nothing under `-s bash`. It does not know which Bash release a script must run on, so it reports nothing for either operator in a script that must support Bash 3.2. This rule checks that support requirement.
@@ -17,19 +17,19 @@ The report is on the whole expansion, with or without a trailing pattern (`${v^^
17
17
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
18
18
  described in [version compatibility](../../compat.md):
19
19
 
20
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
21
- - `dialect: "bash"` (the default) or `"bats"`: reports when `shellVersion` is older than `4.0`.
20
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
21
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.0`.
22
22
  - `dialect: "posix"`: reports nothing in practice for this syntax, because the POSIX parser rejects it with a parse error before any rule runs.
23
23
  - `dialect: "mksh"` or `"zsh"`: never reports.
24
24
 
25
25
  ## Options
26
26
 
27
- This rule has no options. Set the target through `languageOptions`:
27
+ This rule has no options. Set the required support through `languageOptions`:
28
28
 
29
29
  ```js
30
30
  // eslint.config.js
31
31
  {
32
- languageOptions: { dialect: 'bash', shellVersion: '3.2' },
32
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
33
33
  rules: {
34
34
  'sh/compat/no-case-modification': 'error',
35
35
  },
@@ -40,9 +40,9 @@ This rule has no options. Set the target through `languageOptions`:
40
40
 
41
41
  ### Incorrect
42
42
 
43
- With `shellVersion: "3.2"`:
43
+ With `minBashVersion: "3.2"`:
44
44
 
45
- <!-- example: {"dialect": "bash", "shellVersion": "3.2", "findings": 3} -->
45
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 3} -->
46
46
  ```sh
47
47
  name=${input,,} # lowercase every character
48
48
  title=${word^} # uppercase the first character
@@ -51,24 +51,24 @@ flag=${arg^^[a-z]} # with a pattern
51
51
 
52
52
  ### Correct
53
53
 
54
- With `shellVersion: "3.2"`:
54
+ With `minBashVersion: "3.2"`:
55
55
 
56
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
56
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
57
57
  ```sh
58
58
  name=$(printf '%s' "$input" | tr '[:upper:]' '[:lower:]')
59
59
  title=$(printf '%s' "${word%"${word#?}"}" | tr '[:lower:]' '[:upper:]')"${word#?}"
60
60
  ```
61
61
 
62
- With `shellVersion: "4.0"` or newer, or with no `shellVersion`, the original forms are fine.
62
+ With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`, the original forms are fine.
63
63
 
64
64
  ## When not to use it
65
65
 
66
66
  Turn the rule off when your scripts never run on Bash older than 4.0, or leave
67
- `shellVersion` unset, which makes the rule report nothing.
67
+ `minBashVersion` unset, which makes the rule report nothing.
68
68
 
69
69
  ## Relationship to shellcheck
70
70
 
71
71
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
72
72
  layer. Run shellcheck beside it.
73
73
 
74
- shellcheck reports case-modifying expansions in scripts it treats as POSIX sh (SC3059), but it cannot target a Bash version, so it cannot report `${v,,}` in a script that must run on Bash 3.2. This rule exists for that target.
74
+ shellcheck reports case-modifying expansions in scripts it treats as POSIX sh (SC3059), but it cannot check support for a minimum Bash version, so it cannot report `${v,,}` in a script that must run on Bash 3.2. This rule checks that support requirement.