@eslint-sh/eslint-plugin 0.7.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 (141) hide show
  1. package/README.md +14 -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 +4 -3
  10. package/dist/configs/posix-portable.d.ts +1 -1
  11. package/dist/declaration-conventions/read-declared-commands.d.ts +2 -2
  12. package/dist/declaration-conventions/read-declared-commands.js +2 -2
  13. package/dist/eslint-plugin-syntax.d.ts +4 -0
  14. package/dist/eslint-plugin.d.ts +86 -40
  15. package/dist/index.d.ts +5 -2
  16. package/dist/index.js +4 -2
  17. package/dist/language/shell-language-options.d.ts +18 -15
  18. package/dist/language/shell-language-options.js +33 -26
  19. package/dist/language/shell-language.d.ts +10 -9
  20. package/dist/language/shell-language.js +18 -35
  21. package/dist/language/shell-source-code.d.ts +17 -9
  22. package/dist/language/shell-source-code.js +53 -12
  23. package/dist/rules/bash-variable-semantics.d.ts +22 -0
  24. package/dist/rules/bash-variable-semantics.js +41 -0
  25. package/dist/rules/compat/create-compat-rule.js +1 -1
  26. package/dist/rules/compat/declaration-options.d.ts +2 -2
  27. package/dist/rules/compat/declaration-options.js +5 -2
  28. package/dist/rules/compat/no-append-all-redirect.js +1 -1
  29. package/dist/rules/compat/no-associative-arrays.js +2 -2
  30. package/dist/rules/compat/no-brace-sequence-padding-step.js +4 -4
  31. package/dist/rules/compat/no-case-attributes.js +3 -3
  32. package/dist/rules/compat/no-case-fallthrough.js +2 -2
  33. package/dist/rules/compat/no-case-modification.js +2 -2
  34. package/dist/rules/compat/no-coproc.js +1 -1
  35. package/dist/rules/compat/no-declare-g.js +3 -3
  36. package/dist/rules/compat/no-double-bracket.js +2 -2
  37. package/dist/rules/compat/no-epoch-variables.js +2 -2
  38. package/dist/rules/compat/no-fd-variable.js +1 -1
  39. package/dist/rules/compat/no-globstar.js +1 -1
  40. package/dist/rules/compat/no-lastpipe-semantics.js +2 -2
  41. package/dist/rules/compat/no-let.js +2 -1
  42. package/dist/rules/compat/no-mapfile.js +4 -2
  43. package/dist/rules/compat/no-nameref.js +3 -3
  44. package/dist/rules/compat/no-negative-array-index.js +39 -9
  45. package/dist/rules/compat/no-nounset-empty-array.js +15 -4
  46. package/dist/rules/compat/no-parameter-transformation.js +2 -2
  47. package/dist/rules/compat/no-pipe-all.js +1 -1
  48. package/dist/rules/compat/no-printf-time-format.js +4 -2
  49. package/dist/rules/compat/no-source.js +2 -1
  50. package/dist/rules/compat/no-test-v.js +4 -2
  51. package/dist/rules/compat/no-unicode-escape.js +2 -2
  52. package/dist/rules/compat/no-wait-n.js +4 -2
  53. package/dist/rules/compat/nounset-array-proof.d.ts +8 -0
  54. package/dist/rules/compat/nounset-array-proof.js +563 -0
  55. package/dist/rules/compat/posix-absent-command.d.ts +7 -8
  56. package/dist/rules/compat/posix-absent-command.js +17 -15
  57. package/dist/rules/compat/shopt-options.js +3 -1
  58. package/dist/rules/compat/version-gates.d.ts +9 -9
  59. package/dist/rules/compat/version-gates.js +13 -13
  60. package/dist/rules/create-wrapper-rule.js +12 -7
  61. package/dist/rules/no-dynamic-invocation.d.ts +0 -8
  62. package/dist/rules/no-dynamic-invocation.js +7 -15
  63. package/dist/rules/no-eval.js +3 -1
  64. package/dist/rules/no-masked-exit-status.js +15 -8
  65. package/dist/rules/no-secret-env-reads.d.ts +4 -3
  66. package/dist/rules/no-secret-env-reads.js +37 -14
  67. package/dist/rules/no-secret-flags.d.ts +2 -1
  68. package/dist/rules/no-secret-flags.js +7 -8
  69. package/dist/rules/no-unchecked-cd.js +3 -1
  70. package/dist/rules/no-undeclared-commands.d.ts +1 -15
  71. package/dist/rules/no-undeclared-commands.js +3 -15
  72. package/dist/rules/no-unused-declarations.d.ts +1 -18
  73. package/dist/rules/no-unused-declarations.js +9 -34
  74. package/dist/rules/prefer-local.js +4 -3
  75. package/dist/rules/quote-expansions.js +3 -28
  76. package/dist/rules/require-network-wrapper.d.ts +2 -17
  77. package/dist/rules/require-network-wrapper.js +33 -4
  78. package/dist/rules/resolve-declaration-convention.d.ts +5 -6
  79. package/dist/rules/resolve-declaration-convention.js +5 -6
  80. package/dist/rules/resolve-network-wrapper.d.ts +19 -0
  81. package/dist/rules/resolve-network-wrapper.js +57 -26
  82. package/dist/rules/resolve-transparent-wrappers.d.ts +43 -0
  83. package/dist/rules/resolve-transparent-wrappers.js +98 -0
  84. package/dist/rules/set-options.d.ts +2 -1
  85. package/dist/rules/set-options.js +17 -5
  86. package/dist/rules/shebang-interpreter.js +4 -2
  87. package/dist/rules/transparent-wrappers.d.ts +4 -3
  88. package/dist/rules/transparent-wrappers.js +5 -4
  89. package/dist/rules/user-pattern.d.ts +5 -3
  90. package/dist/rules/user-pattern.js +6 -4
  91. package/dist/syntax/index.d.ts +4 -0
  92. package/dist/syntax/index.js +4 -0
  93. package/docs/compat.md +76 -27
  94. package/docs/custom-rule-tutorial.md +9 -3
  95. package/docs/examples/no-listed-commands-rule.ts +2 -2
  96. package/docs/rules/README.md +36 -4
  97. package/docs/rules/_template.md +2 -2
  98. package/docs/rules/compat/no-append-all-redirect.md +12 -12
  99. package/docs/rules/compat/no-associative-arrays.md +14 -14
  100. package/docs/rules/compat/no-brace-sequence-padding-step.md +12 -12
  101. package/docs/rules/compat/no-case-attributes.md +13 -13
  102. package/docs/rules/compat/no-case-fallthrough.md +12 -12
  103. package/docs/rules/compat/no-case-modification.md +11 -11
  104. package/docs/rules/compat/no-coproc.md +13 -13
  105. package/docs/rules/compat/no-declare-g.md +13 -13
  106. package/docs/rules/compat/no-double-bracket.md +2 -2
  107. package/docs/rules/compat/no-epoch-variables.md +13 -13
  108. package/docs/rules/compat/no-fd-variable.md +12 -12
  109. package/docs/rules/compat/no-globstar.md +13 -13
  110. package/docs/rules/compat/no-lastpipe-semantics.md +13 -13
  111. package/docs/rules/compat/no-let.md +2 -2
  112. package/docs/rules/compat/no-mapfile.md +16 -16
  113. package/docs/rules/compat/no-nameref.md +13 -13
  114. package/docs/rules/compat/no-negative-array-index.md +14 -14
  115. package/docs/rules/compat/no-nounset-empty-array.md +72 -17
  116. package/docs/rules/compat/no-parameter-transformation.md +19 -19
  117. package/docs/rules/compat/no-pipe-all.md +13 -13
  118. package/docs/rules/compat/no-printf-time-format.md +13 -13
  119. package/docs/rules/compat/no-source.md +2 -2
  120. package/docs/rules/compat/no-test-v.md +12 -12
  121. package/docs/rules/compat/no-unicode-escape.md +13 -13
  122. package/docs/rules/compat/no-wait-n.md +13 -13
  123. package/docs/rules/no-dynamic-invocation.md +17 -12
  124. package/docs/rules/no-eval.md +6 -1
  125. package/docs/rules/no-masked-exit-status.md +4 -0
  126. package/docs/rules/no-secret-env-reads.md +34 -3
  127. package/docs/rules/no-secret-flags.md +19 -2
  128. package/docs/rules/no-unchecked-cd.md +9 -2
  129. package/docs/rules/no-undeclared-commands.md +16 -15
  130. package/docs/rules/no-unused-declarations.md +17 -20
  131. package/docs/rules/prefer-local.md +20 -2
  132. package/docs/rules/quote-expansions.md +8 -5
  133. package/docs/rules/require-network-wrapper.md +22 -17
  134. package/docs/rules/require-shebang.md +10 -4
  135. package/docs/rules/require-strict-mode.md +6 -0
  136. package/docs/shellcheck.md +9 -5
  137. package/docs/transparent-wrappers.md +97 -0
  138. package/docs/wrapper-rules.md +9 -0
  139. package/package.json +2 -2
  140. package/dist/language/end-of-input-marker.d.ts +0 -29
  141. package/dist/language/end-of-input-marker.js +0 -88
@@ -1,6 +1,6 @@
1
1
  # `sh/compat/no-parameter-transformation`
2
2
 
3
- Disallow the parameter transformations `${v@op}` in scripts whose target shell lacks the
3
+ Disallow the parameter transformations `${v@op}` in scripts that must support a shell lacking the
4
4
  operator: `@Q`, `@E`, `@P`, `@A` and `@a` need Bash 4.4, `@U`, `@u`, `@L` and `@K` need Bash 5.1,
5
5
  and `@k` needs Bash 5.2. POSIX sh has none of them.
6
6
 
@@ -12,14 +12,14 @@ and `@k` needs Bash 5.2. POSIX sh has none of them.
12
12
 
13
13
  Bash 4.4 added the first transformations (Bash NEWS for 4.4), Bash 5.1 the case operators and `@K`, and Bash 5.2 `@k`. A release that lacks the operator fails with `${v@Q}: bad substitution` at the moment the word is expanded. The boundary of each operator was checked against real shells; see [Evidence](../../compat.md#evidence).
14
14
 
15
- The rule reads every parameter expansion whose operator is `@` followed by one of the ten letters. It reports when the file's target lacks that letter's release; the report is on the whole expansion. A target of Bash 5.0, for example, gets reports for `@U` but not for `@Q`. An `@` inside another expansion's word (`${v:-@Q}`) and text in single quotes are not expansions and are not reported.
15
+ The rule reads every parameter expansion whose operator is `@` followed by one of the ten letters. It reports when the minimum Bash version the file must support predates that letter's release; the report is on the whole expansion. A file that must support Bash 5.0, for example, gets reports for `@U` but not for `@Q`. An `@` inside another expansion's word (`${v:-@Q}`) and text in single quotes are not expansions and are not reported.
16
16
 
17
- The message names a portable alternative where one exists for the target:
17
+ The message names an alternative that works on the shells the file must support:
18
18
 
19
- - `@Q`: `printf '%q' "$v"`. It quotes differently (`a\ b` instead of `'a b'`), but `eval` reads it back as the same value. Not offered for a POSIX target, whose `printf` has no `%q`.
19
+ - `@Q`: `printf '%q' "$v"`. It quotes differently (`a\ b` instead of `'a b'`), but `eval` reads it back as the same value. Not offered for a file that must support POSIX sh, whose `printf` has no `%q`.
20
20
  - `@E`: `printf '%b' "$v"`.
21
- - `@A`: `declare -p v`. It prints the declaration rather than expanding to it, so capture it (`s=$(declare -p v)`) and `eval "$s"` to re-create the variable. Not offered for a POSIX target.
22
- - `@U`, `@u`, `@L`: the Bash 4.0 case expansions `"${v^^}"`, `"${v^}"`, `"${v,,}"` for a target from 4.0 to 5.0, or a `tr` conversion for an older Bash.
21
+ - `@A`: `declare -p v`. It prints the declaration rather than expanding to it, so capture it (`s=$(declare -p v)`) and `eval "$s"` to re-create the variable. Not offered for a file that must support POSIX sh.
22
+ - `@U`, `@u`, `@L`: the Bash 4.0 case expansions `"${v^^}"`, `"${v^}"`, `"${v,,}"` when the minimum supported Bash is from 4.0 to 5.0, or a `tr` conversion for an older Bash.
23
23
  - `@P`, `@a`, `@K`, `@k`: no equivalent expansion; the message says so.
24
24
 
25
25
  Under `dialect: "posix"` the parser itself rejects `${v@op}`, so a POSIX file that uses it fails to parse and this rule does not run on it.
@@ -27,18 +27,18 @@ Under `dialect: "posix"` the parser itself rejects `${v@op}`, so a POSIX file th
27
27
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
28
28
  described in [version compatibility](../../compat.md):
29
29
 
30
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
31
- - `dialect: "bash"` (the default) or `"bats"`: reports an operator when `shellVersion` is older than its release.
30
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
31
+ - `dialect: "bash"` (the default) or `"bats"`: reports an operator when `minBashVersion` is older than its release.
32
32
  - `dialect: "mksh"` or `"zsh"`: never reports.
33
33
 
34
34
  ## Options
35
35
 
36
- This rule has no options. Set the target through `languageOptions`:
36
+ This rule has no options. Set the required support through `languageOptions`:
37
37
 
38
38
  ```js
39
39
  // eslint.config.js
40
40
  {
41
- languageOptions: { dialect: 'bash', shellVersion: '3.2' },
41
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
42
42
  rules: {
43
43
  'sh/compat/no-parameter-transformation': 'error',
44
44
  },
@@ -49,9 +49,9 @@ This rule has no options. Set the target through `languageOptions`:
49
49
 
50
50
  ### Incorrect
51
51
 
52
- With `shellVersion: "3.2"`:
52
+ With `minBashVersion: "3.2"`:
53
53
 
54
- <!-- example: {"dialect": "bash", "shellVersion": "3.2", "findings": 3} -->
54
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 3} -->
55
55
 
56
56
  ```sh
57
57
  log "running ${cmd@Q}"
@@ -59,9 +59,9 @@ upper=${name@U}
59
59
  printf '%s\n' "${args[@]@K}"
60
60
  ```
61
61
 
62
- With `shellVersion: "5.0"`, only the case operator reports:
62
+ With `minBashVersion: "5.0"`, only the case operator reports:
63
63
 
64
- <!-- example: {"dialect": "bash", "shellVersion": "5.0", "findings": 1} -->
64
+ <!-- example: {"dialect": "bash", "minBashVersion": "5.0", "findings": 1} -->
65
65
 
66
66
  ```sh
67
67
  log "running ${cmd@Q}"
@@ -70,25 +70,25 @@ upper=${name@U}
70
70
 
71
71
  ### Correct
72
72
 
73
- With `shellVersion: "3.2"`:
73
+ With `minBashVersion: "3.2"`:
74
74
 
75
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
75
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
76
76
 
77
77
  ```sh
78
78
  log "running $(printf '%q' "$cmd")"
79
79
  upper=$(printf '%s' "$name" | tr '[:lower:]' '[:upper:]')
80
80
  ```
81
81
 
82
- With `shellVersion: "5.2"` or newer, or with no `shellVersion`, every transformation is fine.
82
+ With `minBashVersion: "5.2"` or newer, or with no `minBashVersion`, every transformation is fine.
83
83
 
84
84
  ## When not to use it
85
85
 
86
86
  Turn the rule off when your scripts never run on a Bash older than the operators they use, or
87
- leave `shellVersion` unset, which makes the rule report nothing.
87
+ leave `minBashVersion` unset, which makes the rule report nothing.
88
88
 
89
89
  ## Relationship to shellcheck
90
90
 
91
91
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
92
92
  layer. Run shellcheck beside it.
93
93
 
94
- shellcheck 0.11.0 reports nothing for `${v@U}`, `${v@Q}` or `${v@a}` under either `-s sh` or `-s bash` (a variable that is never assigned still draws its unrelated SC2154). So shellcheck gives no finding for these expansions in a POSIX sh script or in a Bash target older than the operator's release. This rule exists for those targets.
94
+ shellcheck 0.11.0 reports nothing for `${v@U}`, `${v@Q}` or `${v@a}` under either `-s sh` or `-s bash` (a variable that is never assigned still draws its unrelated SC2154). So shellcheck gives no finding for these expansions in a POSIX sh script or in a script that must support a Bash older than the operator's release. This rule exists for those targets.
@@ -1,6 +1,6 @@
1
1
  # `sh/compat/no-pipe-all`
2
2
 
3
- Disallow the `|&` pipe, shorthand for `2>&1 |`, in scripts whose target shell lacks it: Bash older
3
+ Disallow the `|&` pipe, shorthand for `2>&1 |`, in scripts that must support a shell lacking it: Bash older
4
4
  than 4.0, including the Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
5
5
 
6
6
  | Configs | Fixable | Languages |
@@ -20,15 +20,15 @@ Under `dialect: "posix"` the parser itself rejects `|&`, so a POSIX file that us
20
20
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
21
21
  described in [version compatibility](../../compat.md):
22
22
 
23
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
24
- - `dialect: "bash"` (the default) or `"bats"`: reports when `shellVersion` is older than `4.0`.
23
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
24
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.0`.
25
25
  - `dialect: "mksh"` or `"zsh"`: never reports (in zsh, `|&` is a different operator).
26
26
 
27
27
  ### Suggestion
28
28
 
29
29
  A suggestion rewrites the operator:
30
30
 
31
- <!-- transform: {"kind": "suggestion", "dialect": "bash", "shellVersion": "3.2"} -->
31
+ <!-- transform: {"kind": "suggestion", "dialect": "bash", "minBashVersion": "3.2"} -->
32
32
  ```sh
33
33
  make |& tee build.log
34
34
  # becomes
@@ -37,12 +37,12 @@ make 2>&1 | tee build.log
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-pipe-all': 'error',
48
48
  },
@@ -53,28 +53,28 @@ 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": 1} -->
58
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 1} -->
59
59
  ```sh
60
60
  make |& tee build.log
61
61
  ```
62
62
 
63
63
  ### Correct
64
64
 
65
- With `shellVersion: "3.2"`:
65
+ With `minBashVersion: "3.2"`:
66
66
 
67
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
67
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
68
68
  ```sh
69
69
  make 2>&1 | tee build.log
70
70
  make || echo "failed |& retried"
71
71
  ```
72
72
 
73
- With `shellVersion: "4.0"` or newer, or with no `shellVersion`, `|&` is fine.
73
+ With `minBashVersion: "4.0"` or newer, or with no `minBashVersion`, `|&` is fine.
74
74
 
75
75
  ## When not to use it
76
76
 
77
- Turn the rule off when your scripts never run on Bash older than 4.0, or leave `shellVersion`
77
+ Turn the rule off when your scripts never run on Bash older than 4.0, or leave `minBashVersion`
78
78
  unset, which makes the rule report nothing.
79
79
 
80
80
  ## Relationship to shellcheck
@@ -82,4 +82,4 @@ unset, which makes the rule report nothing.
82
82
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
83
83
  layer. Run shellcheck beside it.
84
84
 
85
- shellcheck reports `|&` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `|&` for a Bash 3.2 target. This rule exists for that target.
85
+ shellcheck reports `|&` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `|&` for a script that must support Bash 3.2. This rule checks that support requirement.
@@ -1,6 +1,6 @@
1
1
  # `sh/compat/no-printf-time-format`
2
2
 
3
- Disallow `printf`'s `%(fmt)T` date format in scripts whose target shell lacks it: Bash older than
3
+ Disallow `printf`'s `%(fmt)T` date format in scripts that must support a shell lacking it: Bash older than
4
4
  4.2, including the Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
5
5
 
6
6
  | Configs | Fixable | Languages |
@@ -18,19 +18,19 @@ The portable alternative for the current time is `date '+fmt'`, which takes the
18
18
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
19
19
  described in [version compatibility](../../compat.md):
20
20
 
21
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
22
- - `dialect: "bash"` (the default) or `"bats"`: reports when `shellVersion` is older than `4.2`.
23
- - `dialect: "posix"`: reports at any `shellVersion`; dash's `printf` has no `%(fmt)T`.
21
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
22
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.2`.
23
+ - `dialect: "posix"`: reports regardless of Bash releases; dash's `printf` has no `%(fmt)T`.
24
24
  - `dialect: "mksh"` or `"zsh"`: never reports.
25
25
 
26
26
  ## Options
27
27
 
28
- This rule has no options. Set the target through `languageOptions`:
28
+ This rule has no options. Set the required support through `languageOptions`:
29
29
 
30
30
  ```js
31
31
  // eslint.config.js
32
32
  {
33
- languageOptions: { dialect: 'bash', shellVersion: '3.2' },
33
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
34
34
  rules: {
35
35
  'sh/compat/no-printf-time-format': 'error',
36
36
  },
@@ -41,9 +41,9 @@ This rule has no options. Set the target through `languageOptions`:
41
41
 
42
42
  ### Incorrect
43
43
 
44
- With `shellVersion: "3.2"`:
44
+ With `minBashVersion: "3.2"`:
45
45
 
46
- <!-- example: {"dialect": "bash", "shellVersion": "3.2", "findings": 2} -->
46
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 2} -->
47
47
  ```sh
48
48
  printf '%(%Y-%m-%d)T\n' -1
49
49
  printf -v stamp '[%(%H:%M:%S)T]' -1
@@ -51,20 +51,20 @@ printf -v stamp '[%(%H:%M:%S)T]' -1
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
  date '+%Y-%m-%d'
59
59
  stamp="[$(date '+%H:%M:%S')]"
60
60
  printf '100%%(of it)T\n'
61
61
  ```
62
62
 
63
- With `shellVersion: "4.2"` or newer, or with no `shellVersion`, `%(fmt)T` is fine.
63
+ With `minBashVersion: "4.2"` or newer, or with no `minBashVersion`, `%(fmt)T` is fine.
64
64
 
65
65
  ## When not to use it
66
66
 
67
- Turn the rule off when your scripts never run on Bash older than 4.2, or leave `shellVersion`
67
+ Turn the rule off when your scripts never run on Bash older than 4.2, or leave `minBashVersion`
68
68
  unset, which makes the rule report nothing.
69
69
 
70
70
  ## Relationship to shellcheck
@@ -72,4 +72,4 @@ unset, which makes the rule report nothing.
72
72
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
73
73
  layer. Run shellcheck beside it.
74
74
 
75
- shellcheck 0.11.0 reports nothing for `printf "%(%s)T\n" -1` under either `-s sh` or `-s bash`. So shellcheck gives no finding for `%(fmt)T` in a POSIX sh script or in a Bash 3.2 target. This rule exists for both.
75
+ shellcheck 0.11.0 reports nothing for `printf "%(%s)T\n" -1` under either `-s sh` or `-s bash`. So shellcheck gives no finding for `%(fmt)T` in a POSIX sh script or in a script that must support Bash 3.2. This rule exists for both.
@@ -47,12 +47,12 @@ if [ -r ./lib.sh ]; then . ./lib.sh; else echo fallback; fi
47
47
 
48
48
  This is a POSIX-only gate. Every Bash has `source`, so whether the rule reports depends only on `dialect`, as described in [version compatibility](../../compat.md):
49
49
 
50
- - `dialect: "posix"`: reports at any `shellVersion`.
50
+ - `dialect: "posix"`: reports regardless of Bash releases.
51
51
  - `dialect: "bash"` (the default), `"bats"`, `"mksh"` or `"zsh"`: never reports.
52
52
 
53
53
  ## Options
54
54
 
55
- This rule has no options. Set the target through `languageOptions`:
55
+ This rule has no options. Set the required support through `languageOptions`:
56
56
 
57
57
  ```js
58
58
  // eslint.config.js
@@ -24,19 +24,19 @@ The portable alternative is `[ -n "${name+set}" ]`. `${name+set}` expands to `se
24
24
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
25
25
  described in [version compatibility](../../compat.md):
26
26
 
27
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
28
- - `dialect: "bash"` (the default) or `"bats"`: reports when `shellVersion` is older than `4.2`.
29
- - `dialect: "posix"`: reports `test -v` and `[ -v ]` at any `shellVersion`; dash has no `-v` test.
27
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
28
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.2`.
29
+ - `dialect: "posix"`: reports `test -v` and `[ -v ]` regardless of Bash releases; dash has no `-v` test.
30
30
  - `dialect: "mksh"` or `"zsh"`: never reports.
31
31
 
32
32
  ## Options
33
33
 
34
- This rule has no options. Set the target through `languageOptions`:
34
+ This rule has no options. Set the required support through `languageOptions`:
35
35
 
36
36
  ```js
37
37
  // eslint.config.js
38
38
  {
39
- languageOptions: { dialect: 'bash', shellVersion: '3.2' },
39
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
40
40
  rules: {
41
41
  'sh/compat/no-test-v': 'error',
42
42
  },
@@ -47,9 +47,9 @@ This rule has no options. Set the target through `languageOptions`:
47
47
 
48
48
  ### Incorrect
49
49
 
50
- With `shellVersion: "3.2"`:
50
+ With `minBashVersion: "3.2"`:
51
51
 
52
- <!-- example: {"dialect": "bash", "shellVersion": "3.2", "findings": 3} -->
52
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 3} -->
53
53
  ```sh
54
54
  if [[ -v CI ]]; then echo ci; fi
55
55
  if test -v HOME; then echo home; fi
@@ -58,20 +58,20 @@ if test -v HOME; then echo home; fi
58
58
 
59
59
  ### Correct
60
60
 
61
- With `shellVersion: "3.2"`:
61
+ With `minBashVersion: "3.2"`:
62
62
 
63
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
63
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
64
64
  ```sh
65
65
  if [ -n "${CI+set}" ]; then echo ci; fi
66
66
  [ "$flag" = -v ] && verbose=1
67
67
  grep -v '^#' config
68
68
  ```
69
69
 
70
- With `shellVersion: "4.2"` or newer, or with no `shellVersion`, the `-v` test is fine.
70
+ With `minBashVersion: "4.2"` or newer, or with no `minBashVersion`, the `-v` test is 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.2, or leave `shellVersion`
74
+ Turn the rule off when your scripts never run on Bash older than 4.2, 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
- shellcheck reports `[[` and `test -v` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `[[ -v x ]]` for a Bash 3.2 target. This rule exists for that target.
82
+ shellcheck reports `[[` and `test -v` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `[[ -v x ]]` for a script that must support Bash 3.2. This rule checks that support requirement.
@@ -27,18 +27,18 @@ Under `dialect: "posix"` the parser reads `$'…'` as a literal `$` followed by
27
27
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
28
28
  described in [version compatibility](../../compat.md):
29
29
 
30
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
31
- - `dialect: "bash"` (the default) or `"bats"`: reports an escape when `shellVersion` is older than its release (4.2, or 4.3 for U+0080 to U+00FF).
30
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
31
+ - `dialect: "bash"` (the default) or `"bats"`: reports an escape when `minBashVersion` is older than its release (4.2, or 4.3 for U+0080 to U+00FF).
32
32
  - `dialect: "mksh"` or `"zsh"`: never reports.
33
33
 
34
34
  ## Options
35
35
 
36
- This rule has no options. Set the target through `languageOptions`:
36
+ This rule has no options. Set the required support through `languageOptions`:
37
37
 
38
38
  ```js
39
39
  // eslint.config.js
40
40
  {
41
- languageOptions: { dialect: 'bash', shellVersion: '3.2' },
41
+ languageOptions: { dialect: 'bash', minBashVersion: '3.2' },
42
42
  rules: {
43
43
  'sh/compat/no-unicode-escape': 'error',
44
44
  },
@@ -49,17 +49,17 @@ This rule has no options. Set the target through `languageOptions`:
49
49
 
50
50
  ### Incorrect
51
51
 
52
- With `shellVersion: "3.2"`:
52
+ With `minBashVersion: "3.2"`:
53
53
 
54
- <!-- example: {"dialect": "bash", "shellVersion": "3.2", "findings": 2} -->
54
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 2} -->
55
55
  ```sh
56
56
  ok=$'\u2713'
57
57
  printf '%s\n' $'caf\u00e9'
58
58
  ```
59
59
 
60
- With `shellVersion: "4.2"`, only the Latin-1 range reports:
60
+ With `minBashVersion: "4.2"`, only the Latin-1 range reports:
61
61
 
62
- <!-- example: {"dialect": "bash", "shellVersion": "4.2", "findings": 1} -->
62
+ <!-- example: {"dialect": "bash", "minBashVersion": "4.2", "findings": 1} -->
63
63
  ```sh
64
64
  ok=$'\u2713'
65
65
  printf '%s\n' $'caf\u00e9'
@@ -67,20 +67,20 @@ printf '%s\n' $'caf\u00e9'
67
67
 
68
68
  ### Correct
69
69
 
70
- With `shellVersion: "3.2"`:
70
+ With `minBashVersion: "3.2"`:
71
71
 
72
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
72
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
73
73
  ```sh
74
74
  ok=$'\342\234\223'
75
75
  printf '%s\n' $'caf\303\251'
76
76
  echo '\u00e9 is written literally here'
77
77
  ```
78
78
 
79
- With `shellVersion: "4.3"` or newer, or with no `shellVersion`, every escape is fine.
79
+ With `minBashVersion: "4.3"` or newer, or with no `minBashVersion`, every escape is fine.
80
80
 
81
81
  ## When not to use it
82
82
 
83
- Turn the rule off when your scripts never run on Bash older than 4.3, or leave `shellVersion`
83
+ Turn the rule off when your scripts never run on Bash older than 4.3, or leave `minBashVersion`
84
84
  unset, which makes the rule report nothing.
85
85
 
86
86
  ## Relationship to shellcheck
@@ -88,4 +88,4 @@ unset, which makes the rule report nothing.
88
88
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
89
89
  layer. Run shellcheck beside it.
90
90
 
91
- shellcheck reports `$'…'` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report a `\u` escape for a Bash 3.2 or 4.2 target. This rule exists for that target.
91
+ shellcheck reports `$'…'` only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report a `\u` escape for a script that must support Bash 3.2 or 4.2. This rule checks that support requirement.
@@ -1,6 +1,6 @@
1
1
  # `sh/compat/no-wait-n`
2
2
 
3
- Disallow `wait -n` in scripts whose target shell lacks it: Bash older than 4.3, including the
3
+ Disallow `wait -n` in scripts that must support a shell lacking it: Bash older than 4.3, including the
4
4
  Bash 3.2 that macOS ships as `/bin/bash`, and POSIX sh.
5
5
 
6
6
  | Configs | Fixable | Languages |
@@ -20,19 +20,19 @@ The portable alternative is to wait for one job at a time by its PID: keep each
20
20
  This is a version-compat rule. Whether it reports depends only on `languageOptions`, as
21
21
  described in [version compatibility](../../compat.md):
22
22
 
23
- - `shellVersion` unset: never reports. An unset version means the newest Bash.
24
- - `dialect: "bash"` (the default) or `"bats"`: reports when `shellVersion` is older than `4.3`.
25
- - `dialect: "posix"`: reports at any `shellVersion`; POSIX `wait` has no options.
23
+ - `minBashVersion` unset: no Bash version constraint, so no report under `bash` or `bats`.
24
+ - `dialect: "bash"` (the default) or `"bats"`: reports when `minBashVersion` is older than `4.3`.
25
+ - `dialect: "posix"`: reports regardless of Bash releases; POSIX `wait` has no options.
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-wait-n': '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": 1} -->
48
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2", "findings": 1} -->
49
49
  ```sh
50
50
  for job in a b c d; do
51
51
  run "$job" &
@@ -56,9 +56,9 @@ wait
56
56
 
57
57
  ### Correct
58
58
 
59
- With `shellVersion: "3.2"`:
59
+ With `minBashVersion: "3.2"`:
60
60
 
61
- <!-- example: {"dialect": "bash", "shellVersion": "3.2"} -->
61
+ <!-- example: {"dialect": "bash", "minBashVersion": "3.2"} -->
62
62
  ```sh
63
63
  pids=
64
64
  for job in a b c d; do
@@ -70,11 +70,11 @@ for pid in $pids; do
70
70
  done
71
71
  ```
72
72
 
73
- With `shellVersion: "4.3"` or newer, or with no `shellVersion`, `wait -n` is fine.
73
+ With `minBashVersion: "4.3"` or newer, or with no `minBashVersion`, `wait -n` is fine.
74
74
 
75
75
  ## When not to use it
76
76
 
77
- Turn the rule off when your scripts never run on Bash older than 4.3, or leave `shellVersion`
77
+ Turn the rule off when your scripts never run on Bash older than 4.3, or leave `minBashVersion`
78
78
  unset, which makes the rule report nothing.
79
79
 
80
80
  ## Relationship to shellcheck
@@ -82,4 +82,4 @@ unset, which makes the rule report nothing.
82
82
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
83
83
  layer. Run shellcheck beside it.
84
84
 
85
- shellcheck reports `wait` options only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `wait -n` for a Bash 4.2 target. This rule exists for that target.
85
+ shellcheck reports `wait` options only for a script it treats as POSIX `sh` (its SC3xxx portability checks). It does not know which Bash release a script must run on, so it cannot report `wait -n` for a script that must support Bash 4.2. This rule checks that support requirement.
@@ -30,7 +30,8 @@ wrappers_: commands that run the word after them. `time ls` runs `ls`, and
30
30
  `bash ./build.sh` runs `./build.sh`. `bash -c STRING`, including a one-letter cluster such as
31
31
  `bash -lc STRING`, runs an embedded string. `bash -s` and a bare `bash` read commands from
32
32
  standard input, so the shell itself is the command.
33
- - Any names you add with `allowWrappers`.
33
+ - Project wrappers declared in `settings: { sh: { transparentWrappers: ['with-retry'] } }`,
34
+ and the shared network wrapper. See [shared transparent wrappers](../transparent-wrappers.md).
34
35
 
35
36
  A command then reports in one of two ways:
36
37
 
@@ -45,8 +46,9 @@ A command then reports in one of two ways:
45
46
 
46
47
  The rule is syntactic by design. It doesn't track values, so `cmd=ls; "$cmd"` reports. Aliases
47
48
  need no handling: non-interactive shells don't expand them, so an alias name is an ordinary
48
- static command word. Wrapper names match exactly, so `/bin/bash -c …` is a static command named
49
- `/bin/bash`, not a shell wrapper.
49
+ static command word. Utility wrappers match absolute paths by basename, so `/bin/bash -c …` runs an
50
+ embedded command. Configured utility wrappers also match relative paths; builtin specs
51
+ require exact names.
50
52
 
51
53
  It does not depend on `languageOptions`.
52
54
 
@@ -56,18 +58,20 @@ It does not depend on `languageOptions`.
56
58
  `dynamicInvocation` inside a function with one of these names, at any nesting depth, does not
57
59
  report. The same command outside that function still reports. `embeddedCommand` still reports
58
60
  inside these functions. Each use of the dispatcher stays visible at its call sites.
59
- - `allowWrappers` (`string[]`, default `[]`): extra transparent wrappers, added to the built-in
60
- list above. The word after one is checked as the command that runs. An added wrapper has no
61
- known options, so a flag right after it (`with-retry -n 3 curl`) makes the command unknown and
62
- reports. A name already in the built-in list keeps its built-in option handling.
61
+ Project wrapper facts belong in shared settings, with no rule override. The former
62
+ `allowWrappers` option is rejected. It added checks rather than suppressing them:
63
+ move its list to shared settings to preserve those checks across all wrapper-following
64
+ rules. Use `allowInFunctions` or a justified ESLint disable comment for an actual allowance.
65
+ See [migration](../transparent-wrappers.md#migration).
63
66
 
64
67
  ```js
65
68
  // eslint.config.js
66
69
  {
70
+ settings: { sh: { transparentWrappers: ['with-retry'] } },
67
71
  rules: {
68
72
  'sh/no-dynamic-invocation': [
69
73
  'error',
70
- { allowInFunctions: ['dispatch'], allowWrappers: ['with-retry'] },
74
+ { allowInFunctions: ['dispatch'] },
71
75
  ],
72
76
  },
73
77
  }
@@ -91,9 +95,9 @@ bash -c "$script" # embeddedCommand: a string of shell code
91
95
  sh -c 'make test' # embeddedCommand, even for a literal string
92
96
  ```
93
97
 
94
- With `{ allowWrappers: ['with-retry'] }`:
98
+ With `settings: { sh: { transparentWrappers: ['with-retry'] } }`:
95
99
 
96
- <!-- example: {"options": {"allowWrappers": ["with-retry"]}, "findings": 1, "messageIds": ["dynamicInvocation"]} -->
100
+ <!-- example: {"settings": {"sh": {"transparentWrappers": ["with-retry"]}}, "findings": 1, "messageIds": ["dynamicInvocation"]} -->
97
101
  ```sh
98
102
  with-retry "$c" # the wrapped command is dynamic
99
103
  ```
@@ -110,9 +114,10 @@ alias ll='ls -l'
110
114
  ll # an alias name is a static command word
111
115
  ```
112
116
 
113
- With `{ allowInFunctions: ['dispatch'], allowWrappers: ['with-retry'] }`:
117
+ With `{ allowInFunctions: ['dispatch'] }` and
118
+ `settings: { sh: { transparentWrappers: ['with-retry'] } }`:
114
119
 
115
- <!-- example: {"options": {"allowInFunctions": ["dispatch"], "allowWrappers": ["with-retry"]}} -->
120
+ <!-- example: {"options": {"allowInFunctions": ["dispatch"]}, "settings": {"sh": {"transparentWrappers": ["with-retry"]}}} -->
116
121
  ```sh
117
122
  dispatch() {
118
123
  "$@" # allowed inside the dispatcher
@@ -7,6 +7,10 @@ of code a script runs can be reviewed before it runs.
7
7
  | ------- | ------------ | --------- |
8
8
  | `recommended`, `agent-authored` | not fixable | `sh/sh` |
9
9
 
10
+ Project wrapper facts are shared through
11
+ `settings: { sh: { transparentWrappers: ['with-retry'] } }`. This rule follows
12
+ those wrappers and the shared network wrapper; see [shared transparent wrappers](../transparent-wrappers.md).
13
+
10
14
  ## Rule details
11
15
 
12
16
  A script you can review is a script whose code is all in front of you. Two constructs defeat
@@ -98,7 +102,8 @@ still report.
98
102
  eslint-sh is a convention and contract linter: a policy layer, where shellcheck is the gotcha
99
103
  layer. Run shellcheck beside it.
100
104
 
101
- This rule is one of eslint-sh's two deliberate overlaps with shellcheck. shellcheck flags
105
+ This rule is one of eslint-sh's
106
+ [deliberate overlaps with shellcheck](../shellcheck.md#deliberate-overlaps). shellcheck flags
102
107
  `eval` only in specific misuse patterns, such as SC2294 (`eval` on an array negates the benefit
103
108
  of arrays), and flags `source` of a non-constant path as SC1090 because shellcheck cannot follow
104
109
  it. Both treat these as hazards to work around. This rule treats them as a policy: code that
@@ -6,6 +6,10 @@ Disallow `local`, `declare`, `typeset`, `export` and `readonly` with a value tak
6
6
  | ---------------- | ----------------------------------------- | --------- |
7
7
  | `agent-authored` | suggestions (split into two statements) | `sh/sh` |
8
8
 
9
+ Project wrapper facts are shared through
10
+ `settings: { sh: { transparentWrappers: ['with-retry'] } }`. This rule follows
11
+ those wrappers and the shared network wrapper; see [shared transparent wrappers](../transparent-wrappers.md).
12
+
9
13
  ## Rule details
10
14
 
11
15
  `local x=$(cmd)` runs `cmd`, then runs `local`, and the statement's exit status is the status of