@eslint-sh/eslint-plugin 0.1.1 → 0.3.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 +4 -0
- package/dist/eslint-plugin.d.ts +15 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/language/shell-language.js +3 -3
- package/dist/language/shell-language.js.map +1 -1
- package/docs/custom-rule-tutorial.md +23 -12
- package/docs/examples/eslint.config.mjs +1 -1
- package/docs/examples/{no-rm-rf-rule.js → no-rm-rf-rule.mjs} +9 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -42,6 +42,10 @@ ShellLanguage }, rules: {} }`. `meta.version` always matches this package's `pac
|
|
|
42
42
|
prefix directive/inline-config comments must start with — e.g. the default `"eslint"` recognizes
|
|
43
43
|
`# eslint-disable-next-line ...`; consumers who already overload `# eslint-*` comments for
|
|
44
44
|
something else can configure a different prefix (e.g. `directivePrefix: 'shellcheck-sh'`).
|
|
45
|
+
- `resolveWord` — re-export of `sh-ast`'s word-resolution helper, so a project that installs only
|
|
46
|
+
this package can write custom rules that resolve static shell words (e.g. the `no-rm-rf` example
|
|
47
|
+
in the [custom-rule tutorial](./docs/custom-rule-tutorial.md)) without a separate `sh-ast`
|
|
48
|
+
install.
|
|
45
49
|
|
|
46
50
|
Parse failures surface as fatal lint messages at mvdan/sh's real reported position (never a 1:1
|
|
47
51
|
placeholder) — see `ShParseError` in `sh-ast`.
|
package/dist/eslint-plugin.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { FileProblem } from '@eslint/core';
|
|
|
4
4
|
import type { Language } from '@eslint/core';
|
|
5
5
|
import type { OkParseResult } from '@eslint/core';
|
|
6
6
|
import type { ParseResult } from '@eslint/core';
|
|
7
|
+
import { resolveWord as resolveWord_2 } from 'sh-ast/analyze';
|
|
7
8
|
import type { RulesConfig } from '@eslint/core';
|
|
8
9
|
import type { ShellDialect } from 'sh-ast';
|
|
9
10
|
import type { ShFile } from 'sh-ast';
|
|
@@ -62,6 +63,20 @@ export declare interface NormalizedShellLanguageOptions extends Record<string, u
|
|
|
62
63
|
toJSON(): ShellLanguageOptionsJSON;
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Re-exported from `sh-ast/analyze` so a project that installs only
|
|
68
|
+
* `@eslint-sh/eslint-plugin` can write custom rules that resolve static
|
|
69
|
+
* shell words (e.g. `docs/custom-rule-tutorial.md`'s `no-rm-rf` example)
|
|
70
|
+
* without a separate `sh-ast` install or relying on npm hoisting to make
|
|
71
|
+
* `sh-ast` resolvable from the consumer's own `node_modules`. Declared
|
|
72
|
+
* locally (instead of a bare re-export statement) so API Extractor
|
|
73
|
+
* attaches this doc comment and its public release tag to the committed
|
|
74
|
+
* api-report instead of emitting it as an untagged export.
|
|
75
|
+
*
|
|
76
|
+
* @public
|
|
77
|
+
*/
|
|
78
|
+
export declare const resolveWord: typeof resolveWord_2;
|
|
79
|
+
|
|
65
80
|
/**
|
|
66
81
|
* `ShellLanguage` — the `@eslint/core` `Language` implementation for shell
|
|
67
82
|
* scripts (design/ARCHITECTURE.md, "SourceCode and Language objects";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
|
+
import { resolveWord as shAstResolveWord } from 'sh-ast/analyze';
|
|
1
2
|
import { ShellLanguage } from './language/shell-language.js';
|
|
2
3
|
export { ShellLanguage } from './language/shell-language.js';
|
|
3
4
|
export { ShellSourceCode } from './language/shell-source-code.js';
|
|
4
5
|
export type { NormalizedShellLanguageOptions, ShellLanguageOptions, ShellLanguageOptionsJSON, } from './language/shell-language-options.js';
|
|
6
|
+
/**
|
|
7
|
+
* Re-exported from `sh-ast/analyze` so a project that installs only
|
|
8
|
+
* `@eslint-sh/eslint-plugin` can write custom rules that resolve static
|
|
9
|
+
* shell words (e.g. `docs/custom-rule-tutorial.md`'s `no-rm-rf` example)
|
|
10
|
+
* without a separate `sh-ast` install or relying on npm hoisting to make
|
|
11
|
+
* `sh-ast` resolvable from the consumer's own `node_modules`. Declared
|
|
12
|
+
* locally (instead of a bare re-export statement) so API Extractor
|
|
13
|
+
* attaches this doc comment and its public release tag to the committed
|
|
14
|
+
* api-report instead of emitting it as an untagged export.
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export declare const resolveWord: typeof shAstResolveWord;
|
|
5
19
|
/**
|
|
6
20
|
* The `@eslint-sh/eslint-plugin` plugin object (design/PACKAGES.md,
|
|
7
21
|
* `@eslint-sh/eslint-plugin`): `languages.sh` provides `ShellLanguage` /
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,YAAY,EACV,8BAA8B,EAC9B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,sCAAsC,CAAC;AAE9C;;;;;;;;;;;;;;;;GAgBG;;;;;;;;;;;;AACH,wBAUmB"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,IAAI,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAG7D,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,YAAY,EACV,8BAA8B,EAC9B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,sCAAsC,CAAC;AAE9C;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,WAAW,yBAAmB,CAAC;AAE5C;;;;;;;;;;;;;;;;GAgBG;;;;;;;;;;;;AACH,wBAUmB"}
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
|
+
import { resolveWord as shAstResolveWord } from 'sh-ast/analyze';
|
|
1
2
|
import { ShellLanguage } from './language/shell-language.js';
|
|
2
3
|
import { readPackageVersion } from './version.js';
|
|
3
4
|
export { ShellLanguage } from './language/shell-language.js';
|
|
4
5
|
export { ShellSourceCode } from './language/shell-source-code.js';
|
|
6
|
+
/**
|
|
7
|
+
* Re-exported from `sh-ast/analyze` so a project that installs only
|
|
8
|
+
* `@eslint-sh/eslint-plugin` can write custom rules that resolve static
|
|
9
|
+
* shell words (e.g. `docs/custom-rule-tutorial.md`'s `no-rm-rf` example)
|
|
10
|
+
* without a separate `sh-ast` install or relying on npm hoisting to make
|
|
11
|
+
* `sh-ast` resolvable from the consumer's own `node_modules`. Declared
|
|
12
|
+
* locally (instead of a bare re-export statement) so API Extractor
|
|
13
|
+
* attaches this doc comment and its public release tag to the committed
|
|
14
|
+
* api-report instead of emitting it as an untagged export.
|
|
15
|
+
*
|
|
16
|
+
* @public
|
|
17
|
+
*/
|
|
18
|
+
export const resolveWord = shAstResolveWord;
|
|
5
19
|
/**
|
|
6
20
|
* The `@eslint-sh/eslint-plugin` plugin object (design/PACKAGES.md,
|
|
7
21
|
* `@eslint-sh/eslint-plugin`): `languages.sh` provides `ShellLanguage` /
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAOlE;;;;;;;;;;;;;;;;GAgBG;AACH,eAAe;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,kBAAkB,EAAE;QAC7B,SAAS,EAAE,IAAI;KAChB;IACD,SAAS,EAAE;QACT,EAAE,EAAE,IAAI,aAAa,EAAE;KACxB;IACD,KAAK,EAAE,EAAE;CACO,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,IAAI,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAOlE;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,gBAAgB,CAAC;AAE5C;;;;;;;;;;;;;;;;GAgBG;AACH,eAAe;IACb,IAAI,EAAE;QACJ,IAAI,EAAE,0BAA0B;QAChC,OAAO,EAAE,kBAAkB,EAAE;QAC7B,SAAS,EAAE,IAAI;KAChB;IACD,SAAS,EAAE;QACT,EAAE,EAAE,IAAI,aAAa,EAAE;KACxB;IACD,KAAK,EAAE,EAAE;CACO,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ShAstError, ShParseError, parseSync, visitorKeys as shellVisitorKeys } from 'sh-ast';
|
|
2
2
|
import { matchesSelectorClass as matchesShellSelectorClass } from './selector-classes.js';
|
|
3
3
|
import { ShellSourceCode } from './shell-source-code.js';
|
|
4
4
|
import { normalizeShellLanguageOptions, validateShellLanguageOptions, } from './shell-language-options.js';
|
|
@@ -63,7 +63,7 @@ function stripPositionPrefix(message, filename) {
|
|
|
63
63
|
*
|
|
64
64
|
* Any other error reaching here (`ShInvalidDialectError` — unreachable in
|
|
65
65
|
* practice, since `validateLanguageOptions` rejects a bad dialect before
|
|
66
|
-
* ESLint ever calls `parse()`; or `
|
|
66
|
+
* ESLint ever calls `parse()`; or `ShInternalError` — a shim contract
|
|
67
67
|
* violation) has no real source position to report, so `1:1` is used as an
|
|
68
68
|
* explicit, honest fallback for the "no position available" case — not a
|
|
69
69
|
* stand-in for an actual parse error's position.
|
|
@@ -76,7 +76,7 @@ function toFileError(error) {
|
|
|
76
76
|
column: error.column,
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
-
const message = error instanceof
|
|
79
|
+
const message = error instanceof ShAstError || error instanceof Error ? error.message : String(error);
|
|
80
80
|
return { message, line: 1, column: 1 };
|
|
81
81
|
}
|
|
82
82
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-language.js","sourceRoot":"","sources":["../../src/language/shell-language.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"shell-language.js","sourceRoot":"","sources":["../../src/language/shell-language.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,11 +7,16 @@ wiring — `plugins`, `rules`, `language` — needed to run it.
|
|
|
7
7
|
|
|
8
8
|
Every code block on this page is the literal, shipped file it names — not a paraphrase — and both
|
|
9
9
|
files are executed verbatim in CI (`test/custom-rule-tutorial.test.ts` imports
|
|
10
|
-
[`examples/no-rm-rf-rule.
|
|
10
|
+
[`examples/no-rm-rf-rule.mjs`](./examples/no-rm-rf-rule.mjs) and
|
|
11
11
|
[`examples/eslint.config.mjs`](./examples/eslint.config.mjs) directly and runs them through a real
|
|
12
12
|
`eslint` `Linter.verify()`): the rule fires on a fixture script and does not fire on a clean one,
|
|
13
13
|
so this tutorial cannot silently drift from working code. Both example files ship with this
|
|
14
|
-
package (`docs/examples/`), so you can copy them into your own project as-is.
|
|
14
|
+
package (`docs/examples/`), so you can copy them into your own project as-is. Both use the `.mjs`
|
|
15
|
+
extension deliberately: they are ES modules (`import`/`export`), and a default `npm init -y`
|
|
16
|
+
project is CommonJS, so a plain `.js` extension would make Node — and ESLint's own config
|
|
17
|
+
loader — try to parse them as CommonJS and fail with `SyntaxError: Cannot use import statement
|
|
18
|
+
outside a module`. `.mjs` marks each file as an ES module regardless of the surrounding project's
|
|
19
|
+
`"type"` field.
|
|
15
20
|
|
|
16
21
|
## 1. Pick a selector from the cookbook
|
|
17
22
|
|
|
@@ -22,9 +27,9 @@ flag?) the same way a hand-written rule narrows any other selector-first ESLint
|
|
|
22
27
|
|
|
23
28
|
## 2. Write the rule module
|
|
24
29
|
|
|
25
|
-
`docs/examples/no-rm-rf-rule.
|
|
30
|
+
`docs/examples/no-rm-rf-rule.mjs`:
|
|
26
31
|
|
|
27
|
-
```
|
|
32
|
+
```mjs
|
|
28
33
|
/**
|
|
29
34
|
* The complete "flag `rm -rf`" custom rule from the custom-rule tutorial
|
|
30
35
|
* (`../custom-rule-tutorial.md`). Plain, directly-runnable JavaScript (no
|
|
@@ -41,18 +46,23 @@ flag?) the same way a hand-written rule narrows any other selector-first ESLint
|
|
|
41
46
|
* here the selector does the node-type narrowing, `create()` only does the
|
|
42
47
|
* domain-specific check).
|
|
43
48
|
*
|
|
44
|
-
* Flag words are resolved with
|
|
45
|
-
*
|
|
49
|
+
* Flag words are resolved with `@eslint-sh/eslint-plugin`'s re-exported
|
|
50
|
+
* `resolveWord` (originally from `sh-ast/analyze`) rather than a
|
|
51
|
+
* hand-rolled scan: a word is only ever treated as the literal text
|
|
46
52
|
* `-rf`/`-fr` when it is *statically* that string (bare or quoted literal
|
|
47
53
|
* concatenations); a word containing a `ParamExp`/`CmdSubst`/`ArithmExp`/
|
|
48
54
|
* `ProcSubst` resolves to `null` ("unknown") rather than being silently
|
|
49
55
|
* erased into a static match or a static non-match — the same static-word
|
|
50
|
-
* contract `design/PACKAGES.md` documents for `resolveWordText`.
|
|
56
|
+
* contract `design/PACKAGES.md` documents for `resolveWordText`. Importing
|
|
57
|
+
* it from the plugin package (rather than `sh-ast/analyze` directly) means
|
|
58
|
+
* a project that installs only `@eslint-sh/eslint-plugin` has everything
|
|
59
|
+
* this rule needs, with no separate `sh-ast` install or npm-hoisting
|
|
60
|
+
* reliance.
|
|
51
61
|
*
|
|
52
62
|
* @see ../custom-rule-tutorial.md — the tutorial this rule backs
|
|
53
63
|
* @see ../selectors.md — the `:command` launch class
|
|
54
64
|
*/
|
|
55
|
-
import { resolveWord } from 'sh-
|
|
65
|
+
import { resolveWord } from '@eslint-sh/eslint-plugin';
|
|
56
66
|
|
|
57
67
|
const noRmRf = {
|
|
58
68
|
meta: {
|
|
@@ -107,8 +117,9 @@ A few things worth calling out:
|
|
|
107
117
|
classes](./selectors.md#the-six-launch-classes) — not a bare node-type name. ESLint's
|
|
108
118
|
`esquery`-based rule-listener matching (via `ShellLanguage.matchesSelectorClass`) treats it
|
|
109
119
|
exactly like any other selector key such as `CallExpr` or `CallExpr[args.0.parts.0.value='jq']`.
|
|
110
|
-
- `resolveWord(arg, { context: 'command-argument' })` — from
|
|
111
|
-
to ask "is this word statically the string X":
|
|
120
|
+
- `resolveWord(arg, { context: 'command-argument' })` — re-exported from `@eslint-sh/eslint-plugin`
|
|
121
|
+
(originally `sh-ast/analyze`) — is the correct way to ask "is this word statically the string X":
|
|
122
|
+
it returns `{ static: true, text }` for a bare or
|
|
112
123
|
quoted literal (`rm`, `'r'm`, `"-rf"` all resolve), and `{ static: false, reason }` the moment any
|
|
113
124
|
part of the word depends on a `ParamExp`/`CmdSubst`/`ArithmExp`/`ProcSubst` — never inventing a
|
|
114
125
|
value for a dynamic word.
|
|
@@ -121,7 +132,7 @@ A few things worth calling out:
|
|
|
121
132
|
|
|
122
133
|
`docs/examples/eslint.config.mjs`:
|
|
123
134
|
|
|
124
|
-
```
|
|
135
|
+
```mjs
|
|
125
136
|
// eslint.config.mjs
|
|
126
137
|
//
|
|
127
138
|
// The custom-rule tutorial's exact flat-config wiring
|
|
@@ -130,7 +141,7 @@ A few things worth calling out:
|
|
|
130
141
|
// `eslint` `Linter.verify()` — not a reconstruction of this shape — so the
|
|
131
142
|
// documented wiring is genuinely tested.
|
|
132
143
|
import sh from '@eslint-sh/eslint-plugin'; // or the umbrella: import sh from 'eslint-sh'
|
|
133
|
-
import noRmRf from './no-rm-rf-rule.
|
|
144
|
+
import noRmRf from './no-rm-rf-rule.mjs';
|
|
134
145
|
|
|
135
146
|
export default [
|
|
136
147
|
{
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// `eslint` `Linter.verify()` — not a reconstruction of this shape — so the
|
|
7
7
|
// documented wiring is genuinely tested.
|
|
8
8
|
import sh from '@eslint-sh/eslint-plugin'; // or the umbrella: import sh from 'eslint-sh'
|
|
9
|
-
import noRmRf from './no-rm-rf-rule.
|
|
9
|
+
import noRmRf from './no-rm-rf-rule.mjs';
|
|
10
10
|
|
|
11
11
|
export default [
|
|
12
12
|
{
|
|
@@ -14,18 +14,23 @@
|
|
|
14
14
|
* here the selector does the node-type narrowing, `create()` only does the
|
|
15
15
|
* domain-specific check).
|
|
16
16
|
*
|
|
17
|
-
* Flag words are resolved with
|
|
18
|
-
*
|
|
17
|
+
* Flag words are resolved with `@eslint-sh/eslint-plugin`'s re-exported
|
|
18
|
+
* `resolveWord` (originally from `sh-ast/analyze`) rather than a
|
|
19
|
+
* hand-rolled scan: a word is only ever treated as the literal text
|
|
19
20
|
* `-rf`/`-fr` when it is *statically* that string (bare or quoted literal
|
|
20
21
|
* concatenations); a word containing a `ParamExp`/`CmdSubst`/`ArithmExp`/
|
|
21
22
|
* `ProcSubst` resolves to `null` ("unknown") rather than being silently
|
|
22
23
|
* erased into a static match or a static non-match — the same static-word
|
|
23
|
-
* contract `design/PACKAGES.md` documents for `resolveWordText`.
|
|
24
|
+
* contract `design/PACKAGES.md` documents for `resolveWordText`. Importing
|
|
25
|
+
* it from the plugin package (rather than `sh-ast/analyze` directly) means
|
|
26
|
+
* a project that installs only `@eslint-sh/eslint-plugin` has everything
|
|
27
|
+
* this rule needs, with no separate `sh-ast` install or npm-hoisting
|
|
28
|
+
* reliance.
|
|
24
29
|
*
|
|
25
30
|
* @see ../custom-rule-tutorial.md — the tutorial this rule backs
|
|
26
31
|
* @see ../selectors.md — the `:command` launch class
|
|
27
32
|
*/
|
|
28
|
-
import { resolveWord } from 'sh-
|
|
33
|
+
import { resolveWord } from '@eslint-sh/eslint-plugin';
|
|
29
34
|
|
|
30
35
|
const noRmRf = {
|
|
31
36
|
meta: {
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-sh/eslint-plugin",
|
|
3
3
|
"description": "Shell script parsing and syntax-error reporting for ESLint, with custom-rule authoring over a typed shell AST, backed by sh-ast.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"author": "Mike North <michael.l.north@gmail.com>",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@eslint/core": "^1.2.1",
|
|
8
8
|
"@eslint/plugin-kit": "^0.7.2",
|
|
9
|
-
"sh-ast": "^0.
|
|
9
|
+
"sh-ast": "^0.3.0"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"eslint": "^10.7.0"
|