eslint-sh 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -11
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -10,6 +10,9 @@ here regardless of which of the two packages you install.
|
|
|
10
10
|
|
|
11
11
|
## Installation
|
|
12
12
|
|
|
13
|
+
Requires `eslint@^10` as a peer dependency (already listed as a peer in `eslint-sh`'s
|
|
14
|
+
`package.json`, so a compatible `eslint` install satisfies it automatically):
|
|
15
|
+
|
|
13
16
|
```sh
|
|
14
17
|
npm install --save-dev eslint-sh
|
|
15
18
|
```
|
|
@@ -34,23 +37,109 @@ export default defineConfig([
|
|
|
34
37
|
]);
|
|
35
38
|
```
|
|
36
39
|
|
|
40
|
+
`languageOptions` is entirely optional — omitting it is equivalent to
|
|
41
|
+
`languageOptions: { dialect: 'bash' }`, since `dialect` defaults to `"bash"` (see the
|
|
42
|
+
`languageOptions` reference table below). This README's own [custom-rule tutorial](https://github.com/mike-north/eslint-sh/blob/main/packages/eslint-plugin/docs/custom-rule-tutorial.md)
|
|
43
|
+
config omits `languageOptions` for exactly that reason — it targets bash, the default, so
|
|
44
|
+
there's nothing to override; add it explicitly (as above) when you need a non-default
|
|
45
|
+
`dialect`, a `shellVersion` hint, or a custom `directivePrefix`.
|
|
46
|
+
|
|
37
47
|
## `languageOptions` reference
|
|
38
48
|
|
|
39
|
-
| Option | Allowed values | Default | Effect
|
|
40
|
-
| ----------------- | ----------------------------------------------------------------------- | ---------- |
|
|
41
|
-
| `dialect` | `"bash"`, `"posix"`, `"mksh"`, `"bats"`, `"zsh"` | `"bash"` | Selects which shell grammar the parser accepts
|
|
42
|
-
| `shellVersion` | A numeric `MAJOR` or `MAJOR.MINOR` string, e.g. `"5"` or `"3.2"` | unset | Reserved for the rule layer (e.g. a future bash-3.2 compatibility check); has no effect on parsing today since no rules ship yet.
|
|
43
|
-
| `directivePrefix` | Lowercase, hyphen-separated words, e.g. `"eslint"` or `"shellcheck-sh"` | `"eslint"` | The prefix directive/inline-config comments must start with — e.g. the default recognizes `# eslint-disable-next-line ...`.
|
|
49
|
+
| Option | Allowed values | Default | Effect |
|
|
50
|
+
| ----------------- | ----------------------------------------------------------------------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
51
|
+
| `dialect` | `"bash"`, `"posix"`, `"mksh"`, `"bats"`, `"zsh"` | `"bash"` | Selects which shell grammar the parser accepts. Enforcement is partial: some non-dialect constructs are rejected (e.g. bash array literals under `posix`), but others (e.g. `[[ ... ]]`, `let`) are accepted as ordinary commands — see the [per-dialect enforcement table](https://github.com/mike-north/sh-ast/blob/main/packages/sh-ast/README.md#dialect-enforcement). |
|
|
52
|
+
| `shellVersion` | A numeric `MAJOR` or `MAJOR.MINOR` string, e.g. `"5"` or `"3.2"` | unset | Reserved for the rule layer (e.g. a future bash-3.2 compatibility check); has no effect on parsing today since no rules ship yet. |
|
|
53
|
+
| `directivePrefix` | Lowercase, hyphen-separated words, e.g. `"eslint"` or `"shellcheck-sh"` | `"eslint"` | The prefix directive/inline-config comments must start with — e.g. the default recognizes `# eslint-disable-next-line ...`. |
|
|
44
54
|
|
|
45
55
|
## Troubleshooting
|
|
46
56
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
Every worked example below (config, script, and error output) is extracted straight out of this
|
|
58
|
+
file and run through a real `eslint` `Linter` in CI — see
|
|
59
|
+
`packages/eslint-plugin/test/troubleshooting-examples.test.ts` — so these examples can't drift
|
|
60
|
+
from what the plugin actually does.
|
|
61
|
+
|
|
62
|
+
- **Getting `Parsing error: Unexpected token` or `Unexpected key "dialect"` on shell files.**
|
|
63
|
+
Both errors mean the config object is missing `language: 'sh/sh'` — without it, ESLint doesn't
|
|
64
|
+
route the file through this plugin's language at all, even if `plugins: { sh }` and
|
|
65
|
+
`files` are set correctly. There are two ways this shows up, depending on whether
|
|
66
|
+
`languageOptions` is also present:
|
|
67
|
+
- **No `languageOptions` set:** ESLint falls back to its default JS parser on the shell file,
|
|
68
|
+
which fails on shell syntax with no mention of eslint-sh at all. Given this config:
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
export default [{ files: ['**/*.sh'], plugins: { sh } }];
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
linting this script:
|
|
75
|
+
|
|
76
|
+
```sh
|
|
77
|
+
if [[ "$1" == "foo" ]]; then echo matched; fi
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
produces:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
Parsing error: Unexpected token [
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- **`languageOptions` is set (e.g. `{ dialect: 'bash' }`) but `language` is not:** ESLint
|
|
87
|
+
validates `languageOptions` against its own built-in JS language schema (since no shell
|
|
88
|
+
`language` was selected to own that key), which doesn't recognize `dialect`. Given this
|
|
89
|
+
config:
|
|
90
|
+
|
|
91
|
+
```js
|
|
92
|
+
export default [{ files: ['**/*.sh'], plugins: { sh }, languageOptions: { dialect: 'bash' } }];
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
linting the same script:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
if [[ "$1" == "foo" ]]; then echo matched; fi
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
throws:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
TypeError: Key "languageOptions": Unexpected key "dialect" found.
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The fix for both is the same one-line addition: set `language: 'sh/sh'` alongside
|
|
108
|
+
`plugins: { sh }` in the config object.
|
|
109
|
+
|
|
50
110
|
- **A script I believe is valid reports a parse error.** The parser is dialect-sensitive: a
|
|
51
|
-
construct that's valid in one shell grammar
|
|
52
|
-
|
|
53
|
-
|
|
111
|
+
construct that's valid in one shell grammar may be rejected in another. Given this config:
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
export default [
|
|
115
|
+
{
|
|
116
|
+
files: ['**/*.sh'],
|
|
117
|
+
plugins: { sh },
|
|
118
|
+
language: 'sh/sh',
|
|
119
|
+
languageOptions: { dialect: 'posix' },
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
linting this script (a bash array literal):
|
|
125
|
+
|
|
126
|
+
```sh
|
|
127
|
+
arr=(1 2 3)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
produces:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
Parsing error: arrays are a bash/mksh/zsh feature; tried parsing as posix
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Set `languageOptions.dialect` to match the shell the script is actually written for. Note that
|
|
137
|
+
dialect enforcement is partial by design: some bash-isms — notably `[[ ... ]]` and `let` — are
|
|
138
|
+
not parse errors under `dialect: 'posix'`; they silently parse as ordinary commands instead, so
|
|
139
|
+
a clean `posix` run does not by itself prove a script is POSIX-compliant. See the
|
|
140
|
+
[per-dialect construct enforcement audit](https://github.com/mike-north/sh-ast/blob/main/packages/sh-ast/README.md#dialect-enforcement)
|
|
141
|
+
in `sh-ast` for the full accept/reject matrix and rationale.
|
|
142
|
+
|
|
54
143
|
- **Setting `shellVersion` doesn't change anything.** That's expected today — see the
|
|
55
144
|
`languageOptions` reference table above: `shellVersion` is reserved for a future rule layer and
|
|
56
145
|
has no effect on parsing while no lint rules ship.
|
|
@@ -60,6 +149,17 @@ export default defineConfig([
|
|
|
60
149
|
you've registered a custom rule and the directive still isn't recognized, check
|
|
61
150
|
`languageOptions.directivePrefix` — it must match the prefix your comment uses (the default
|
|
62
151
|
`"eslint"` only recognizes `# eslint-disable-next-line ...`, not a custom prefix).
|
|
152
|
+
- **A disable directive's rule id doesn't match anything I've registered.** An unknown rule id in
|
|
153
|
+
a disable comment (e.g. `# eslint-disable-next-line sh/typo-d-rule`) is a lint-time error, not a
|
|
154
|
+
silent no-op: ESLint reports `Definition for rule '<rule-id>' was not found.` at the directive's
|
|
155
|
+
location. Double-check the rule id against the name you registered it under (the `plugins`
|
|
156
|
+
namespace plus the rule key, e.g. `sh/your-rule`).
|
|
157
|
+
- **`TypeError: Key "language": Could not find "..." in plugin "sh".`** A typo in the
|
|
158
|
+
`language` value (e.g. `language: 'sh/shell'` instead of the registered `language: 'sh/sh'`).
|
|
159
|
+
This error is thrown by ESLint core itself (`Config`'s constructor), before any of this
|
|
160
|
+
plugin's own code runs, and does not currently enumerate the plugin's actually-registered
|
|
161
|
+
language ids in its message (current ESLint 10.x behavior). This plugin registers exactly one
|
|
162
|
+
language: `sh` (selected as `language: 'sh/sh'`).
|
|
63
163
|
|
|
64
164
|
## Status
|
|
65
165
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import sh from '@eslint-sh/eslint-plugin';
|
|
2
2
|
/**
|
|
3
|
-
* `eslint-sh` — the unscoped umbrella package
|
|
4
|
-
*
|
|
3
|
+
* `eslint-sh` — the unscoped umbrella package. Re-exports
|
|
4
|
+
* `@eslint-sh/eslint-plugin`'s plugin object
|
|
5
5
|
* unchanged as this package's default export, so `import sh from
|
|
6
6
|
* "eslint-sh"` and `import sh from "@eslint-sh/eslint-plugin"` are
|
|
7
7
|
* equivalent.
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import sh from '@eslint-sh/eslint-plugin';
|
|
2
2
|
/**
|
|
3
|
-
* `eslint-sh` — the unscoped umbrella package
|
|
4
|
-
*
|
|
3
|
+
* `eslint-sh` — the unscoped umbrella package. Re-exports
|
|
4
|
+
* `@eslint-sh/eslint-plugin`'s plugin object
|
|
5
5
|
* unchanged as this package's default export, so `import sh from
|
|
6
6
|
* "eslint-sh"` and `import sh from "@eslint-sh/eslint-plugin"` are
|
|
7
7
|
* equivalent.
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-sh",
|
|
3
3
|
"description": "Shell script parsing and syntax-error reporting for ESLint, with custom-rule authoring over a typed shell AST",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.4.0",
|
|
5
5
|
"author": "Mike North <michael.l.north@gmail.com>",
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@eslint-sh/eslint-plugin": "0.
|
|
7
|
+
"@eslint-sh/eslint-plugin": "0.4.0"
|
|
8
8
|
},
|
|
9
9
|
"devDependencies": {
|
|
10
10
|
"eslint": "^10.7.0"
|
|
@@ -53,6 +53,11 @@
|
|
|
53
53
|
},
|
|
54
54
|
"type": "module",
|
|
55
55
|
"types": "./dist/eslint-sh.d.ts",
|
|
56
|
+
"repository": {
|
|
57
|
+
"type": "git",
|
|
58
|
+
"url": "git+https://github.com/mike-north/eslint-sh.git",
|
|
59
|
+
"directory": "packages/eslint-sh"
|
|
60
|
+
},
|
|
56
61
|
"scripts": {
|
|
57
62
|
"build": "tsc -p tsconfig.json",
|
|
58
63
|
"check": "concurrently -n lint,types,api-report \"pnpm run check:lint-ts\" \"pnpm run check:typecheck\" \"pnpm run check:api-report\"",
|