@eslint/shell 0.0.0-stage → 0.1.2
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/LICENSE +201 -0
- package/README.md +167 -2
- package/dist/index.d.ts +79 -0
- package/dist/index.js +74 -0
- package/dist/languages/shell-language.d.ts +36 -0
- package/dist/languages/shell-language.js +72 -0
- package/dist/languages/shell-source-code.d.ts +55 -0
- package/dist/languages/shell-source-code.js +184 -0
- package/dist/parser/parse.d.ts +32 -0
- package/dist/parser/parse.js +758 -0
- package/dist/rules/no-backticks.d.ts +8 -0
- package/dist/rules/no-backticks.js +46 -0
- package/dist/rules/no-expansions-in-single-quotes.d.ts +8 -0
- package/dist/rules/no-expansions-in-single-quotes.js +42 -0
- package/dist/rules/no-ls-iteration.d.ts +8 -0
- package/dist/rules/no-ls-iteration.js +42 -0
- package/dist/rules/no-unquoted-expansions.d.ts +9 -0
- package/dist/rules/no-unquoted-expansions.js +91 -0
- package/dist/rules/no-unused-vars.d.ts +11 -0
- package/dist/rules/no-unused-vars.js +382 -0
- package/dist/rules/no-useless-cat.d.ts +8 -0
- package/dist/rules/no-useless-cat.js +76 -0
- package/dist/rules/no-useless-echo.d.ts +8 -0
- package/dist/rules/no-useless-echo.js +42 -0
- package/dist/rules/no-variables-in-printf-format.d.ts +8 -0
- package/dist/rules/no-variables-in-printf-format.js +60 -0
- package/dist/rules/require-cd-guard.d.ts +8 -0
- package/dist/rules/require-cd-guard.js +74 -0
- package/dist/rules/require-read-r.d.ts +8 -0
- package/dist/rules/require-read-r.js +83 -0
- package/dist/rules/utils.d.ts +35 -0
- package/dist/rules/utils.js +100 -0
- package/dist/types.d.ts +343 -0
- package/dist/types.js +7 -0
- package/dist/visitor-keys.d.ts +5 -0
- package/dist/visitor-keys.js +59 -0
- package/package.json +75 -4
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Type definitions for the shell ESTree-style syntax tree and
|
|
3
|
+
* for rules operating on it. See docs/syntax-tree.md for the full
|
|
4
|
+
* documentation of the tree format.
|
|
5
|
+
* @author Claude Opus 5.5
|
|
6
|
+
*/
|
|
7
|
+
import type { CustomRuleDefinitionType, CustomRuleTypeDefinitions, CustomRuleVisitorWithExit } from "@eslint/plugin-kit";
|
|
8
|
+
import type { ShellSourceCode } from "./languages/shell-source-code.js";
|
|
9
|
+
/**
|
|
10
|
+
* Every node carries `start` and `end` character offsets into the source
|
|
11
|
+
* text (0-based, `end` exclusive). Nodes deliberately do not carry `range`
|
|
12
|
+
* or `loc` properties; use `sourceCode.getRange(node)` and
|
|
13
|
+
* `sourceCode.getLoc(node)` instead.
|
|
14
|
+
*/
|
|
15
|
+
export interface ShellNodeBase {
|
|
16
|
+
type: string;
|
|
17
|
+
start: number;
|
|
18
|
+
end: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Properties shared by every node that can appear in a statement position.
|
|
22
|
+
*/
|
|
23
|
+
export interface StatementBase extends ShellNodeBase {
|
|
24
|
+
redirects: RedirectNode[];
|
|
25
|
+
negated: boolean;
|
|
26
|
+
background: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface ProgramNode extends ShellNodeBase {
|
|
29
|
+
type: "Program";
|
|
30
|
+
body: StatementNode[];
|
|
31
|
+
comments: CommentNode[];
|
|
32
|
+
}
|
|
33
|
+
export interface CommentNode extends ShellNodeBase {
|
|
34
|
+
type: "Comment";
|
|
35
|
+
/** The comment text without the leading `#`. */
|
|
36
|
+
text: string;
|
|
37
|
+
}
|
|
38
|
+
export interface CommandNode extends StatementBase {
|
|
39
|
+
type: "Command";
|
|
40
|
+
assignments: VariableAssignmentNode[];
|
|
41
|
+
name: WordNode | null;
|
|
42
|
+
arguments: WordNode[];
|
|
43
|
+
}
|
|
44
|
+
export interface PipelineNode extends StatementBase {
|
|
45
|
+
type: "Pipeline";
|
|
46
|
+
commands: StatementNode[];
|
|
47
|
+
/** Operator between `commands[i]` and `commands[i + 1]` (`|` or `|&`). */
|
|
48
|
+
operators: ("|" | "|&")[];
|
|
49
|
+
}
|
|
50
|
+
export interface LogicalExpressionNode extends StatementBase {
|
|
51
|
+
type: "LogicalExpression";
|
|
52
|
+
operator: "&&" | "||";
|
|
53
|
+
left: StatementNode;
|
|
54
|
+
right: StatementNode;
|
|
55
|
+
}
|
|
56
|
+
export interface SubshellNode extends StatementBase {
|
|
57
|
+
type: "Subshell";
|
|
58
|
+
body: StatementNode[];
|
|
59
|
+
}
|
|
60
|
+
export interface BlockStatementNode extends StatementBase {
|
|
61
|
+
type: "BlockStatement";
|
|
62
|
+
body: StatementNode[];
|
|
63
|
+
}
|
|
64
|
+
export interface IfStatementNode extends StatementBase {
|
|
65
|
+
type: "IfStatement";
|
|
66
|
+
test: StatementNode[];
|
|
67
|
+
consequent: StatementNode[];
|
|
68
|
+
alternate: IfStatementNode | ElseClauseNode | null;
|
|
69
|
+
}
|
|
70
|
+
export interface ElseClauseNode extends ShellNodeBase {
|
|
71
|
+
type: "ElseClause";
|
|
72
|
+
body: StatementNode[];
|
|
73
|
+
}
|
|
74
|
+
export interface WhileStatementNode extends StatementBase {
|
|
75
|
+
type: "WhileStatement";
|
|
76
|
+
test: StatementNode[];
|
|
77
|
+
body: StatementNode[];
|
|
78
|
+
}
|
|
79
|
+
export interface UntilStatementNode extends StatementBase {
|
|
80
|
+
type: "UntilStatement";
|
|
81
|
+
test: StatementNode[];
|
|
82
|
+
body: StatementNode[];
|
|
83
|
+
}
|
|
84
|
+
export interface ForStatementNode extends StatementBase {
|
|
85
|
+
type: "ForStatement";
|
|
86
|
+
variable: IdentifierNode | null;
|
|
87
|
+
words: WordNode[];
|
|
88
|
+
body: StatementNode[];
|
|
89
|
+
/** `true` for `select name in ...` loops. */
|
|
90
|
+
select: boolean;
|
|
91
|
+
}
|
|
92
|
+
export interface ArithmeticForStatementNode extends StatementBase {
|
|
93
|
+
type: "ArithmeticForStatement";
|
|
94
|
+
init: ArithmeticExpressionNode | null;
|
|
95
|
+
test: ArithmeticExpressionNode | null;
|
|
96
|
+
update: ArithmeticExpressionNode | null;
|
|
97
|
+
body: StatementNode[];
|
|
98
|
+
}
|
|
99
|
+
export interface CaseStatementNode extends StatementBase {
|
|
100
|
+
type: "CaseStatement";
|
|
101
|
+
discriminant: WordNode;
|
|
102
|
+
cases: CaseClauseNode[];
|
|
103
|
+
}
|
|
104
|
+
export interface CaseClauseNode extends ShellNodeBase {
|
|
105
|
+
type: "CaseClause";
|
|
106
|
+
patterns: WordNode[];
|
|
107
|
+
body: StatementNode[];
|
|
108
|
+
/** `;;`, `;&`, `;;&`, `;|` (mksh), or `null` when omitted before `esac`. */
|
|
109
|
+
terminator: string | null;
|
|
110
|
+
}
|
|
111
|
+
export interface FunctionDeclarationNode extends StatementBase {
|
|
112
|
+
type: "FunctionDeclaration";
|
|
113
|
+
id: IdentifierNode;
|
|
114
|
+
body: StatementNode;
|
|
115
|
+
}
|
|
116
|
+
export interface TestCommandNode extends StatementBase {
|
|
117
|
+
type: "TestCommand";
|
|
118
|
+
expression: TestExpressionNode;
|
|
119
|
+
}
|
|
120
|
+
export interface ArithmeticCommandNode extends StatementBase {
|
|
121
|
+
type: "ArithmeticCommand";
|
|
122
|
+
expression: ArithmeticExpressionNode | null;
|
|
123
|
+
}
|
|
124
|
+
export interface DeclarationCommandNode extends StatementBase {
|
|
125
|
+
type: "DeclarationCommand";
|
|
126
|
+
/** `declare`, `local`, `export`, `readonly`, `typeset`, or `nameref`. */
|
|
127
|
+
kind: string;
|
|
128
|
+
arguments: (VariableAssignmentNode | WordNode)[];
|
|
129
|
+
}
|
|
130
|
+
export interface TimeCommandNode extends StatementBase {
|
|
131
|
+
type: "TimeCommand";
|
|
132
|
+
posix: boolean;
|
|
133
|
+
body: StatementNode | null;
|
|
134
|
+
}
|
|
135
|
+
export interface CoprocCommandNode extends StatementBase {
|
|
136
|
+
type: "CoprocCommand";
|
|
137
|
+
name: WordNode | null;
|
|
138
|
+
body: StatementNode | null;
|
|
139
|
+
}
|
|
140
|
+
export interface LetCommandNode extends StatementBase {
|
|
141
|
+
type: "LetCommand";
|
|
142
|
+
expressions: ArithmeticExpressionNode[];
|
|
143
|
+
}
|
|
144
|
+
export type StatementNode = CommandNode | PipelineNode | LogicalExpressionNode | SubshellNode | BlockStatementNode | IfStatementNode | WhileStatementNode | UntilStatementNode | ForStatementNode | ArithmeticForStatementNode | CaseStatementNode | FunctionDeclarationNode | TestCommandNode | ArithmeticCommandNode | DeclarationCommandNode | TimeCommandNode | CoprocCommandNode | LetCommandNode;
|
|
145
|
+
export interface WordNode extends ShellNodeBase {
|
|
146
|
+
type: "Word";
|
|
147
|
+
parts: WordPartNode[];
|
|
148
|
+
}
|
|
149
|
+
export interface LiteralNode extends ShellNodeBase {
|
|
150
|
+
type: "Literal";
|
|
151
|
+
value: string;
|
|
152
|
+
}
|
|
153
|
+
export interface SingleQuotedStringNode extends ShellNodeBase {
|
|
154
|
+
type: "SingleQuotedString";
|
|
155
|
+
/** The text between the quotes. */
|
|
156
|
+
value: string;
|
|
157
|
+
/** `true` for `$'...'` strings. */
|
|
158
|
+
dollar: boolean;
|
|
159
|
+
}
|
|
160
|
+
export interface DoubleQuotedStringNode extends ShellNodeBase {
|
|
161
|
+
type: "DoubleQuotedString";
|
|
162
|
+
parts: WordPartNode[];
|
|
163
|
+
/** `true` for `$"..."` strings. */
|
|
164
|
+
dollar: boolean;
|
|
165
|
+
}
|
|
166
|
+
export interface ParameterExpansionNode extends ShellNodeBase {
|
|
167
|
+
type: "ParameterExpansion";
|
|
168
|
+
/** The parameter name (`foo`, `1`, `@`, `?`, ...). */
|
|
169
|
+
name: string;
|
|
170
|
+
/** `true` for `${foo}`, `false` for `$foo`. */
|
|
171
|
+
braced: boolean;
|
|
172
|
+
/** `true` for `${!ref}` indirection. */
|
|
173
|
+
indirect: boolean;
|
|
174
|
+
/** `true` for `${#foo}`. */
|
|
175
|
+
lengthOf: boolean;
|
|
176
|
+
/** Subscript for `${arr[i]}`. */
|
|
177
|
+
index: ArithmeticExpressionNode | null;
|
|
178
|
+
/**
|
|
179
|
+
* The expansion operator as written in the source (`:-`, `:=`, `##`,
|
|
180
|
+
* `%`, `/`, `//`, `:` for slices, `*`/`@` for `${!prefix*}`, ...), or
|
|
181
|
+
* `null` when the expansion has no operator.
|
|
182
|
+
*/
|
|
183
|
+
operator: string | null;
|
|
184
|
+
/** Operand of `operator` (e.g. the default in `${x:-default}`). */
|
|
185
|
+
word: WordNode | null;
|
|
186
|
+
/** Replacement word for `${x/pattern/replacement}`. */
|
|
187
|
+
replacement: WordNode | null;
|
|
188
|
+
/** Offset expression for `${x:offset:length}`. */
|
|
189
|
+
sliceOffset: ArithmeticExpressionNode | null;
|
|
190
|
+
/** Length expression for `${x:offset:length}`. */
|
|
191
|
+
sliceLength: ArithmeticExpressionNode | null;
|
|
192
|
+
}
|
|
193
|
+
export interface CommandSubstitutionNode extends ShellNodeBase {
|
|
194
|
+
type: "CommandSubstitution";
|
|
195
|
+
body: StatementNode[];
|
|
196
|
+
/** `true` when written with backquotes instead of `$(...)`. */
|
|
197
|
+
backquotes: boolean;
|
|
198
|
+
}
|
|
199
|
+
export interface ProcessSubstitutionNode extends ShellNodeBase {
|
|
200
|
+
type: "ProcessSubstitution";
|
|
201
|
+
operator: "<(" | ">(";
|
|
202
|
+
body: StatementNode[];
|
|
203
|
+
}
|
|
204
|
+
export interface ArithmeticExpansionNode extends ShellNodeBase {
|
|
205
|
+
type: "ArithmeticExpansion";
|
|
206
|
+
expression: ArithmeticExpressionNode | null;
|
|
207
|
+
}
|
|
208
|
+
export interface ExtendedGlobNode extends ShellNodeBase {
|
|
209
|
+
type: "ExtendedGlob";
|
|
210
|
+
operator: "@(" | "*(" | "+(" | "?(" | "!(";
|
|
211
|
+
pattern: string;
|
|
212
|
+
}
|
|
213
|
+
export type WordPartNode = LiteralNode | SingleQuotedStringNode | DoubleQuotedStringNode | ParameterExpansionNode | CommandSubstitutionNode | ProcessSubstitutionNode | ArithmeticExpansionNode | ExtendedGlobNode;
|
|
214
|
+
export interface VariableAssignmentNode extends ShellNodeBase {
|
|
215
|
+
type: "VariableAssignment";
|
|
216
|
+
name: IdentifierNode | null;
|
|
217
|
+
/** Subscript for `arr[i]=value`. */
|
|
218
|
+
index: ArithmeticExpressionNode | null;
|
|
219
|
+
value: WordNode | null;
|
|
220
|
+
array: ArrayExpressionNode | null;
|
|
221
|
+
/** `true` for `+=`. */
|
|
222
|
+
append: boolean;
|
|
223
|
+
}
|
|
224
|
+
export interface ArrayExpressionNode extends ShellNodeBase {
|
|
225
|
+
type: "ArrayExpression";
|
|
226
|
+
elements: ArrayElementNode[];
|
|
227
|
+
}
|
|
228
|
+
export interface ArrayElementNode extends ShellNodeBase {
|
|
229
|
+
type: "ArrayElement";
|
|
230
|
+
index: ArithmeticExpressionNode | null;
|
|
231
|
+
value: WordNode | null;
|
|
232
|
+
}
|
|
233
|
+
export interface IdentifierNode extends ShellNodeBase {
|
|
234
|
+
type: "Identifier";
|
|
235
|
+
name: string;
|
|
236
|
+
}
|
|
237
|
+
export interface RedirectNode extends ShellNodeBase {
|
|
238
|
+
type: "Redirect";
|
|
239
|
+
/** `<`, `>`, `>>`, `<<`, `<<-`, `<<<`, `<&`, `>&`, `&>`, `&>>`, `<>`, `>|`. */
|
|
240
|
+
operator: string;
|
|
241
|
+
/** File descriptor for `2>err`, or `null`. */
|
|
242
|
+
fd: number | null;
|
|
243
|
+
/** Redirect target (the heredoc delimiter for `<<`). */
|
|
244
|
+
target: WordNode | null;
|
|
245
|
+
/** Heredoc body for `<<` and `<<-`. */
|
|
246
|
+
heredoc: WordNode | null;
|
|
247
|
+
}
|
|
248
|
+
export interface BinaryArithmeticNode extends ShellNodeBase {
|
|
249
|
+
type: "BinaryArithmetic";
|
|
250
|
+
operator: string;
|
|
251
|
+
left: ArithmeticExpressionNode;
|
|
252
|
+
right: ArithmeticExpressionNode;
|
|
253
|
+
}
|
|
254
|
+
export interface UnaryArithmeticNode extends ShellNodeBase {
|
|
255
|
+
type: "UnaryArithmetic";
|
|
256
|
+
operator: string;
|
|
257
|
+
prefix: boolean;
|
|
258
|
+
argument: ArithmeticExpressionNode;
|
|
259
|
+
}
|
|
260
|
+
export interface ParenthesizedArithmeticNode extends ShellNodeBase {
|
|
261
|
+
type: "ParenthesizedArithmetic";
|
|
262
|
+
expression: ArithmeticExpressionNode;
|
|
263
|
+
}
|
|
264
|
+
export type ArithmeticExpressionNode = BinaryArithmeticNode | UnaryArithmeticNode | ParenthesizedArithmeticNode | WordNode;
|
|
265
|
+
export interface BinaryTestNode extends ShellNodeBase {
|
|
266
|
+
type: "BinaryTest";
|
|
267
|
+
operator: string;
|
|
268
|
+
left: TestExpressionNode;
|
|
269
|
+
right: TestExpressionNode;
|
|
270
|
+
}
|
|
271
|
+
export interface UnaryTestNode extends ShellNodeBase {
|
|
272
|
+
type: "UnaryTest";
|
|
273
|
+
operator: string;
|
|
274
|
+
argument: TestExpressionNode;
|
|
275
|
+
}
|
|
276
|
+
export interface ParenthesizedTestNode extends ShellNodeBase {
|
|
277
|
+
type: "ParenthesizedTest";
|
|
278
|
+
expression: TestExpressionNode;
|
|
279
|
+
}
|
|
280
|
+
export type TestExpressionNode = BinaryTestNode | UnaryTestNode | ParenthesizedTestNode | WordNode;
|
|
281
|
+
export type ShellNode = ProgramNode | CommentNode | StatementNode | ElseClauseNode | CaseClauseNode | WordNode | WordPartNode | VariableAssignmentNode | ArrayExpressionNode | ArrayElementNode | IdentifierNode | RedirectNode | BinaryArithmeticNode | UnaryArithmeticNode | ParenthesizedArithmeticNode | BinaryTestNode | UnaryTestNode | ParenthesizedTestNode;
|
|
282
|
+
export type ShellVariant = "bash" | "posix" | "mksh";
|
|
283
|
+
/**
|
|
284
|
+
* Language options. There are none yet: the shell dialect is chosen by the
|
|
285
|
+
* language (`shell/bash`, `shell/posix`, or `shell/mksh`).
|
|
286
|
+
*/
|
|
287
|
+
export interface ShellLanguageOptions {
|
|
288
|
+
[key: string]: unknown;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Visitor object for shell rules. Keys are node types, optionally with an
|
|
292
|
+
* `:exit` suffix.
|
|
293
|
+
*/
|
|
294
|
+
export type ShellRuleVisitor = CustomRuleVisitorWithExit<{
|
|
295
|
+
Program?(node: ProgramNode): void;
|
|
296
|
+
Command?(node: CommandNode): void;
|
|
297
|
+
Pipeline?(node: PipelineNode): void;
|
|
298
|
+
LogicalExpression?(node: LogicalExpressionNode): void;
|
|
299
|
+
Subshell?(node: SubshellNode): void;
|
|
300
|
+
BlockStatement?(node: BlockStatementNode): void;
|
|
301
|
+
IfStatement?(node: IfStatementNode): void;
|
|
302
|
+
ElseClause?(node: ElseClauseNode): void;
|
|
303
|
+
WhileStatement?(node: WhileStatementNode): void;
|
|
304
|
+
UntilStatement?(node: UntilStatementNode): void;
|
|
305
|
+
ForStatement?(node: ForStatementNode): void;
|
|
306
|
+
ArithmeticForStatement?(node: ArithmeticForStatementNode): void;
|
|
307
|
+
CaseStatement?(node: CaseStatementNode): void;
|
|
308
|
+
CaseClause?(node: CaseClauseNode): void;
|
|
309
|
+
FunctionDeclaration?(node: FunctionDeclarationNode): void;
|
|
310
|
+
TestCommand?(node: TestCommandNode): void;
|
|
311
|
+
ArithmeticCommand?(node: ArithmeticCommandNode): void;
|
|
312
|
+
DeclarationCommand?(node: DeclarationCommandNode): void;
|
|
313
|
+
TimeCommand?(node: TimeCommandNode): void;
|
|
314
|
+
CoprocCommand?(node: CoprocCommandNode): void;
|
|
315
|
+
LetCommand?(node: LetCommandNode): void;
|
|
316
|
+
Word?(node: WordNode): void;
|
|
317
|
+
Literal?(node: LiteralNode): void;
|
|
318
|
+
SingleQuotedString?(node: SingleQuotedStringNode): void;
|
|
319
|
+
DoubleQuotedString?(node: DoubleQuotedStringNode): void;
|
|
320
|
+
ParameterExpansion?(node: ParameterExpansionNode): void;
|
|
321
|
+
CommandSubstitution?(node: CommandSubstitutionNode): void;
|
|
322
|
+
ProcessSubstitution?(node: ProcessSubstitutionNode): void;
|
|
323
|
+
ArithmeticExpansion?(node: ArithmeticExpansionNode): void;
|
|
324
|
+
ExtendedGlob?(node: ExtendedGlobNode): void;
|
|
325
|
+
VariableAssignment?(node: VariableAssignmentNode): void;
|
|
326
|
+
ArrayExpression?(node: ArrayExpressionNode): void;
|
|
327
|
+
ArrayElement?(node: ArrayElementNode): void;
|
|
328
|
+
Identifier?(node: IdentifierNode): void;
|
|
329
|
+
Redirect?(node: RedirectNode): void;
|
|
330
|
+
BinaryArithmetic?(node: BinaryArithmeticNode): void;
|
|
331
|
+
UnaryArithmetic?(node: UnaryArithmeticNode): void;
|
|
332
|
+
ParenthesizedArithmetic?(node: ParenthesizedArithmeticNode): void;
|
|
333
|
+
BinaryTest?(node: BinaryTestNode): void;
|
|
334
|
+
UnaryTest?(node: UnaryTestNode): void;
|
|
335
|
+
ParenthesizedTest?(node: ParenthesizedTestNode): void;
|
|
336
|
+
}>;
|
|
337
|
+
export type ShellRuleDefinitionTypeOptions = {
|
|
338
|
+
LangOptions: ShellLanguageOptions;
|
|
339
|
+
Code: ShellSourceCode;
|
|
340
|
+
Visitor: ShellRuleVisitor;
|
|
341
|
+
Node: ShellNode;
|
|
342
|
+
};
|
|
343
|
+
export type ShellRuleDefinition<Options extends Partial<CustomRuleTypeDefinitions> = object> = CustomRuleDefinitionType<ShellRuleDefinitionTypeOptions, Options>;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Visitor keys describing the traversal order of the shell
|
|
3
|
+
* syntax tree. Keys are listed in source order.
|
|
4
|
+
*/
|
|
5
|
+
export const visitorKeys = Object.freeze({
|
|
6
|
+
Program: ["body"],
|
|
7
|
+
Comment: [],
|
|
8
|
+
// Statements
|
|
9
|
+
Command: ["assignments", "name", "arguments", "redirects"],
|
|
10
|
+
Pipeline: ["commands", "redirects"],
|
|
11
|
+
LogicalExpression: ["left", "right", "redirects"],
|
|
12
|
+
Subshell: ["body", "redirects"],
|
|
13
|
+
BlockStatement: ["body", "redirects"],
|
|
14
|
+
IfStatement: ["test", "consequent", "alternate", "redirects"],
|
|
15
|
+
ElseClause: ["body"],
|
|
16
|
+
WhileStatement: ["test", "body", "redirects"],
|
|
17
|
+
UntilStatement: ["test", "body", "redirects"],
|
|
18
|
+
ForStatement: ["variable", "words", "body", "redirects"],
|
|
19
|
+
ArithmeticForStatement: ["init", "test", "update", "body", "redirects"],
|
|
20
|
+
CaseStatement: ["discriminant", "cases", "redirects"],
|
|
21
|
+
CaseClause: ["patterns", "body"],
|
|
22
|
+
FunctionDeclaration: ["id", "body", "redirects"],
|
|
23
|
+
TestCommand: ["expression", "redirects"],
|
|
24
|
+
ArithmeticCommand: ["expression", "redirects"],
|
|
25
|
+
DeclarationCommand: ["arguments", "redirects"],
|
|
26
|
+
TimeCommand: ["body", "redirects"],
|
|
27
|
+
CoprocCommand: ["name", "body", "redirects"],
|
|
28
|
+
LetCommand: ["expressions", "redirects"],
|
|
29
|
+
// Words and word parts
|
|
30
|
+
Word: ["parts"],
|
|
31
|
+
Literal: [],
|
|
32
|
+
SingleQuotedString: [],
|
|
33
|
+
DoubleQuotedString: ["parts"],
|
|
34
|
+
ParameterExpansion: [
|
|
35
|
+
"index",
|
|
36
|
+
"word",
|
|
37
|
+
"replacement",
|
|
38
|
+
"sliceOffset",
|
|
39
|
+
"sliceLength",
|
|
40
|
+
],
|
|
41
|
+
CommandSubstitution: ["body"],
|
|
42
|
+
ProcessSubstitution: ["body"],
|
|
43
|
+
ArithmeticExpansion: ["expression"],
|
|
44
|
+
ExtendedGlob: [],
|
|
45
|
+
// Assignments, identifiers, redirects
|
|
46
|
+
VariableAssignment: ["name", "index", "value", "array"],
|
|
47
|
+
ArrayExpression: ["elements"],
|
|
48
|
+
ArrayElement: ["index", "value"],
|
|
49
|
+
Identifier: [],
|
|
50
|
+
Redirect: ["target", "heredoc"],
|
|
51
|
+
// Arithmetic expressions
|
|
52
|
+
BinaryArithmetic: ["left", "right"],
|
|
53
|
+
UnaryArithmetic: ["argument"],
|
|
54
|
+
ParenthesizedArithmetic: ["expression"],
|
|
55
|
+
// Test expressions
|
|
56
|
+
BinaryTest: ["left", "right"],
|
|
57
|
+
UnaryTest: ["argument"],
|
|
58
|
+
ParenthesizedTest: ["expression"],
|
|
59
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,77 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint/shell",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Shell language plugin for ESLint",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/eslint/shell.git"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"eslint",
|
|
29
|
+
"eslint-plugin",
|
|
30
|
+
"bash",
|
|
31
|
+
"shell",
|
|
32
|
+
"shellcheck",
|
|
33
|
+
"linting"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": "^20.19.0 || ^22.13.0 || >=24"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc -p tsconfig.build.json",
|
|
40
|
+
"lint": "eslint .",
|
|
41
|
+
"fmt": "prettier --write .",
|
|
42
|
+
"fmt:check": "prettier --check .",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"test:watch": "vitest",
|
|
45
|
+
"test:coverage": "vitest run --coverage"
|
|
46
|
+
},
|
|
47
|
+
"gitHooks": {
|
|
48
|
+
"pre-commit": "lint-staged"
|
|
49
|
+
},
|
|
50
|
+
"lint-staged": {
|
|
51
|
+
"*.{js,ts}": [
|
|
52
|
+
"prettier --write",
|
|
53
|
+
"eslint --fix"
|
|
54
|
+
],
|
|
55
|
+
"*.{json,md,yml,yaml}": [
|
|
56
|
+
"prettier --write"
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"dependencies": {
|
|
60
|
+
"@eslint/core": "^1.2.1",
|
|
61
|
+
"@eslint/plugin-kit": "^0.7.3",
|
|
62
|
+
"mvdan-sh": "^0.10.1"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@eslint/js": "^10.0.1",
|
|
66
|
+
"@types/node": "~20.19.0",
|
|
67
|
+
"@vitest/coverage-v8": "^4.1.10",
|
|
68
|
+
"eslint": "^10.8.1",
|
|
69
|
+
"eslint-plugin-eslint-plugin": "^7.6.2",
|
|
70
|
+
"lint-staged": "^16.4.0",
|
|
71
|
+
"prettier": "^3.9.6",
|
|
72
|
+
"typescript": "^6.0.3",
|
|
73
|
+
"typescript-eslint": "^8.67.0",
|
|
74
|
+
"vitest": "^4.1.10",
|
|
75
|
+
"yorkie": "^2.0.0"
|
|
76
|
+
}
|
|
77
|
+
}
|