@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.
- package/README.md +19 -8
- package/dist/command-harvest/builtins/bash.d.ts +1 -1
- package/dist/command-harvest/builtins/bash.js +1 -1
- package/dist/command-harvest/builtins/bats.d.ts +2 -0
- package/dist/command-harvest/builtins/bats.js +3 -0
- package/dist/command-harvest/wrapper-table.d.ts +3 -19
- package/dist/command-harvest/wrapper-table.js +8 -38
- package/dist/configs/bash-3-2.d.ts +7 -6
- package/dist/configs/bash-3-2.js +5 -3
- package/dist/configs/posix-portable.d.ts +1 -1
- package/dist/configs/posix-portable.js +1 -0
- package/dist/declaration-conventions/read-declared-commands.d.ts +2 -2
- package/dist/declaration-conventions/read-declared-commands.js +2 -2
- package/dist/eslint-plugin-syntax.d.ts +4 -0
- package/dist/eslint-plugin.d.ts +86 -40
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -2
- package/dist/language/shell-language-options.d.ts +18 -15
- package/dist/language/shell-language-options.js +33 -26
- package/dist/language/shell-language.d.ts +10 -9
- package/dist/language/shell-language.js +18 -35
- package/dist/language/shell-source-code.d.ts +17 -9
- package/dist/language/shell-source-code.js +53 -12
- package/dist/rules/bash-variable-semantics.d.ts +22 -0
- package/dist/rules/bash-variable-semantics.js +41 -0
- package/dist/rules/compat/create-compat-rule.js +1 -1
- package/dist/rules/compat/declaration-options.d.ts +2 -2
- package/dist/rules/compat/declaration-options.js +5 -2
- package/dist/rules/compat/no-append-all-redirect.js +1 -1
- package/dist/rules/compat/no-associative-arrays.js +2 -2
- package/dist/rules/compat/no-brace-sequence-padding-step.d.ts +15 -0
- package/dist/rules/compat/no-brace-sequence-padding-step.js +287 -0
- package/dist/rules/compat/no-case-attributes.js +3 -3
- package/dist/rules/compat/no-case-fallthrough.js +2 -2
- package/dist/rules/compat/no-case-modification.js +2 -2
- package/dist/rules/compat/no-coproc.js +1 -1
- package/dist/rules/compat/no-declare-g.js +3 -3
- package/dist/rules/compat/no-double-bracket.js +2 -2
- package/dist/rules/compat/no-epoch-variables.js +2 -2
- package/dist/rules/compat/no-fd-variable.js +1 -1
- package/dist/rules/compat/no-globstar.js +1 -1
- package/dist/rules/compat/no-lastpipe-semantics.js +2 -2
- package/dist/rules/compat/no-let.js +2 -1
- package/dist/rules/compat/no-mapfile.js +4 -2
- package/dist/rules/compat/no-nameref.js +3 -3
- package/dist/rules/compat/no-negative-array-index.js +39 -9
- package/dist/rules/compat/no-nounset-empty-array.js +15 -4
- package/dist/rules/compat/no-parameter-transformation.js +2 -2
- package/dist/rules/compat/no-pipe-all.js +1 -1
- package/dist/rules/compat/no-printf-time-format.js +4 -2
- package/dist/rules/compat/no-source.js +2 -1
- package/dist/rules/compat/no-test-v.js +4 -2
- package/dist/rules/compat/no-unicode-escape.js +2 -2
- package/dist/rules/compat/no-wait-n.js +4 -2
- package/dist/rules/compat/nounset-array-proof.d.ts +8 -0
- package/dist/rules/compat/nounset-array-proof.js +563 -0
- package/dist/rules/compat/posix-absent-command.d.ts +7 -8
- package/dist/rules/compat/posix-absent-command.js +17 -15
- package/dist/rules/compat/shopt-options.js +3 -1
- package/dist/rules/compat/version-gates.d.ts +10 -10
- package/dist/rules/compat/version-gates.js +21 -13
- package/dist/rules/create-wrapper-rule.js +12 -7
- package/dist/rules/index.js +2 -0
- package/dist/rules/no-dynamic-invocation.d.ts +0 -8
- package/dist/rules/no-dynamic-invocation.js +7 -15
- package/dist/rules/no-eval.js +3 -1
- package/dist/rules/no-masked-exit-status.js +15 -8
- package/dist/rules/no-secret-env-reads.d.ts +4 -3
- package/dist/rules/no-secret-env-reads.js +37 -14
- package/dist/rules/no-secret-flags.d.ts +2 -1
- package/dist/rules/no-secret-flags.js +7 -8
- package/dist/rules/no-unchecked-cd.js +3 -1
- package/dist/rules/no-undeclared-commands.d.ts +1 -15
- package/dist/rules/no-undeclared-commands.js +3 -15
- package/dist/rules/no-unused-declarations.d.ts +1 -18
- package/dist/rules/no-unused-declarations.js +9 -34
- package/dist/rules/prefer-local.js +4 -3
- package/dist/rules/quote-expansions.js +3 -28
- package/dist/rules/require-network-wrapper.d.ts +2 -17
- package/dist/rules/require-network-wrapper.js +33 -4
- package/dist/rules/require-tty-guard.js +30 -1
- package/dist/rules/resolve-declaration-convention.d.ts +5 -6
- package/dist/rules/resolve-declaration-convention.js +5 -6
- package/dist/rules/resolve-network-wrapper.d.ts +19 -0
- package/dist/rules/resolve-network-wrapper.js +57 -26
- package/dist/rules/resolve-transparent-wrappers.d.ts +43 -0
- package/dist/rules/resolve-transparent-wrappers.js +98 -0
- package/dist/rules/set-options.d.ts +2 -1
- package/dist/rules/set-options.js +17 -5
- package/dist/rules/shebang-interpreter.js +4 -2
- package/dist/rules/transparent-wrappers.d.ts +4 -3
- package/dist/rules/transparent-wrappers.js +5 -4
- package/dist/rules/user-pattern.d.ts +5 -3
- package/dist/rules/user-pattern.js +6 -4
- package/dist/syntax/index.d.ts +4 -0
- package/dist/syntax/index.js +4 -0
- package/docs/compat.md +90 -34
- package/docs/custom-rule-tutorial.md +9 -3
- package/docs/examples/no-listed-commands-rule.ts +2 -2
- package/docs/rules/README.md +38 -5
- package/docs/rules/_template.md +2 -2
- package/docs/rules/compat/no-append-all-redirect.md +12 -12
- package/docs/rules/compat/no-associative-arrays.md +14 -14
- package/docs/rules/compat/no-brace-sequence-padding-step.md +90 -0
- package/docs/rules/compat/no-case-attributes.md +13 -13
- package/docs/rules/compat/no-case-fallthrough.md +12 -12
- package/docs/rules/compat/no-case-modification.md +11 -11
- package/docs/rules/compat/no-coproc.md +13 -13
- package/docs/rules/compat/no-declare-g.md +13 -13
- package/docs/rules/compat/no-double-bracket.md +2 -2
- package/docs/rules/compat/no-epoch-variables.md +13 -13
- package/docs/rules/compat/no-fd-variable.md +12 -12
- package/docs/rules/compat/no-globstar.md +13 -13
- package/docs/rules/compat/no-lastpipe-semantics.md +13 -13
- package/docs/rules/compat/no-let.md +2 -2
- package/docs/rules/compat/no-mapfile.md +16 -16
- package/docs/rules/compat/no-nameref.md +13 -13
- package/docs/rules/compat/no-negative-array-index.md +14 -14
- package/docs/rules/compat/no-nounset-empty-array.md +72 -17
- package/docs/rules/compat/no-parameter-transformation.md +19 -19
- package/docs/rules/compat/no-pipe-all.md +13 -13
- package/docs/rules/compat/no-printf-time-format.md +13 -13
- package/docs/rules/compat/no-source.md +2 -2
- package/docs/rules/compat/no-test-v.md +12 -12
- package/docs/rules/compat/no-unicode-escape.md +13 -13
- package/docs/rules/compat/no-wait-n.md +13 -13
- package/docs/rules/no-dynamic-invocation.md +17 -12
- package/docs/rules/no-eval.md +6 -1
- package/docs/rules/no-masked-exit-status.md +4 -0
- package/docs/rules/no-secret-env-reads.md +34 -3
- package/docs/rules/no-secret-flags.md +19 -2
- package/docs/rules/no-unchecked-cd.md +9 -2
- package/docs/rules/no-undeclared-commands.md +16 -15
- package/docs/rules/no-unused-declarations.md +17 -20
- package/docs/rules/prefer-local.md +20 -2
- package/docs/rules/quote-expansions.md +8 -5
- package/docs/rules/require-network-wrapper.md +22 -17
- package/docs/rules/require-shebang.md +10 -4
- package/docs/rules/require-strict-mode.md +6 -0
- package/docs/rules/require-tty-guard.md +4 -1
- package/docs/shellcheck.md +10 -5
- package/docs/transparent-wrappers.md +97 -0
- package/docs/untrusted-code.md +440 -0
- package/docs/wrapper-rules.md +9 -0
- package/package.json +2 -2
- package/dist/language/end-of-input-marker.d.ts +0 -29
- package/dist/language/end-of-input-marker.js +0 -88
package/docs/rules/README.md
CHANGED
|
@@ -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) | `
|
|
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.
|
|
63
|
-
`dialect`. They report nothing when `
|
|
64
|
-
and the `posix-portable` preset sets `dialect: "posix"
|
|
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.
|
package/docs/rules/_template.md
CHANGED
|
@@ -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`, `
|
|
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`, `
|
|
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
|
-
- `
|
|
25
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
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", "
|
|
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
|
|
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',
|
|
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 `
|
|
57
|
+
With `minBashVersion: "3.2"`:
|
|
58
58
|
|
|
59
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
66
|
+
With `minBashVersion: "3.2"`:
|
|
67
67
|
|
|
68
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
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 `
|
|
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
|
|
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
|
|
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
|
-
- `
|
|
21
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
22
|
-
- `dialect: "posix"`: reports
|
|
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
|
|
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',
|
|
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 `
|
|
56
|
+
With `minBashVersion: "3.2"`:
|
|
57
57
|
|
|
58
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
68
|
+
With `minBashVersion: "3.2"`:
|
|
69
69
|
|
|
70
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
78
|
+
With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`:
|
|
79
79
|
|
|
80
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
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
|
|
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
|
|
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
|
-
- `
|
|
23
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
24
|
-
- `dialect: "posix"`: reports
|
|
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
|
|
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',
|
|
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 `
|
|
45
|
+
With `minBashVersion: "3.2"`:
|
|
46
46
|
|
|
47
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
58
|
+
With `minBashVersion: "3.2"`:
|
|
59
59
|
|
|
60
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
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 `
|
|
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
|
|
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
|
|
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
|
-
- `
|
|
25
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
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
|
|
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',
|
|
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 `
|
|
46
|
+
With `minBashVersion: "3.2"`:
|
|
47
47
|
|
|
48
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
62
|
+
With `minBashVersion: "3.2"`:
|
|
63
63
|
|
|
64
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
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 `
|
|
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
|
|
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
|
-
- `
|
|
21
|
-
- `dialect: "bash"` (the default) or `"bats"`: reports when `
|
|
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
|
|
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',
|
|
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 `
|
|
43
|
+
With `minBashVersion: "3.2"`:
|
|
44
44
|
|
|
45
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
54
|
+
With `minBashVersion: "3.2"`:
|
|
55
55
|
|
|
56
|
-
<!-- example: {"dialect": "bash", "
|
|
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 `
|
|
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
|
-
`
|
|
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
|
|
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.
|