@utilfirst/eslint-plugin 0.2.0 → 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/LICENSE +3 -2
- package/README.md +23 -23
- package/dist/index.js +141 -110
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -22,8 +22,9 @@ SOFTWARE.
|
|
|
22
22
|
|
|
23
23
|
Third-party notices
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
Portions of this software are adapted from anti-slop
|
|
26
|
+
(https://github.com/dmmulroy/anti-slop) and are used under the following
|
|
27
|
+
license:
|
|
27
28
|
|
|
28
29
|
MIT License
|
|
29
30
|
|
package/README.md
CHANGED
|
@@ -109,29 +109,29 @@ export default [
|
|
|
109
109
|
|
|
110
110
|
[`docs/rules.md`](./docs/rules.md) explains the policy boundary and expected replacement for every rule. The implementations and colocated tests remain the executable behavior owners.
|
|
111
111
|
|
|
112
|
-
| Rule | Description
|
|
113
|
-
| --------------------------------------------------------------------------------------- |
|
|
114
|
-
| [`consistent-blank-lines`](./docs/rules/consistent-blank-lines.md) |
|
|
115
|
-
| [`no-chained-type-assertions`](./docs/rules.md#type-evidence) | Reject chained TypeScript assertions
|
|
116
|
-
| [`no-conditional-undefined-properties`](./docs/rules.md#object-and-api-construction) | Reject conditional undefined object properties
|
|
117
|
-
| [`no-enum-declarations`](./docs/rules.md#object-and-api-construction) | Reject repository-owned enums other than ambient declarations
|
|
118
|
-
| [`no-known-value-widening`](./docs/rules.md#type-evidence) | Reject known values widened into broad target types
|
|
119
|
-
| [`no-module-mocking`](./docs/rules.md#ownership-and-tests) | Reject Vitest and Jest mocking of repository-owned modules
|
|
120
|
-
| [`no-object-parameters`](./docs/rules.md#boundary-contracts) | Reject `object` function parameters
|
|
121
|
-
| [`no-positional-boolean-parameters`](./docs/rules.md#object-and-api-construction) | Reject positional boolean flags on named functions and methods
|
|
122
|
-
| [`no-reflect-apply`](./docs/rules.md#object-and-api-construction) | Reject `Reflect.apply`
|
|
123
|
-
| [`no-reflect-get`](./docs/rules.md#object-and-api-construction) | Reject `Reflect.get`
|
|
124
|
-
| [`no-unknown-parameters`](./docs/rules.md#boundary-contracts) | Keep explicit `unknown` parameters at decoding boundaries
|
|
125
|
-
| [`no-unknown-returns`](./docs/rules.md#boundary-contracts) | Reject `unknown` return contracts
|
|
126
|
-
| [`no-unknown-type-aliases`](./docs/rules.md#boundary-contracts) | Reject type aliases that resolve to `unknown`
|
|
127
|
-
| [`no-unsafe-dictionary-type`](./docs/rules.md#boundary-contracts) | Reject dictionary contracts with broad value types
|
|
128
|
-
| [`no-unhandled-detached-promises`](./docs/rules.md#async-errors) | Require rejection handling on `void`-marked detached call chains
|
|
129
|
-
| [`no-widen-then-assert`](./docs/rules.md#type-evidence) | Reject const flows that widen a known value before narrowing it
|
|
130
|
-
| [`prefer-options-parameter`](./docs/rules.md#object-and-api-construction) | Require options objects for named functions and methods with three or more inputs
|
|
131
|
-
| [`prefer-switch-discriminator-chain`](./docs/rules.md#object-and-api-construction) | Require a switch for four or more equality branches on one discriminator
|
|
132
|
-
| [`prefer-top-level-function-declarations`](./docs/rules.md#object-and-api-construction) | Require declarations for direct top-level function bindings and default exports
|
|
133
|
-
| [`require-lint-suppression-reason`](./docs/rules.md#lint-policy) | Require a forcing reason on lint disable directives
|
|
134
|
-
| [`require-safety-comment-for-type-assertion`](./docs/rules.md#type-evidence) | Require one `SAFETY:` comment for each outermost non-const assertion
|
|
112
|
+
| Rule | Description |
|
|
113
|
+
| --------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
114
|
+
| [`consistent-blank-lines`](./docs/rules/consistent-blank-lines.md) | Apply tight, separate, or preserved gaps between statements and JSX children |
|
|
115
|
+
| [`no-chained-type-assertions`](./docs/rules.md#type-evidence) | Reject chained TypeScript assertions |
|
|
116
|
+
| [`no-conditional-undefined-properties`](./docs/rules.md#object-and-api-construction) | Reject conditional undefined object properties |
|
|
117
|
+
| [`no-enum-declarations`](./docs/rules.md#object-and-api-construction) | Reject repository-owned enums other than ambient declarations |
|
|
118
|
+
| [`no-known-value-widening`](./docs/rules.md#type-evidence) | Reject known values widened into broad target types |
|
|
119
|
+
| [`no-module-mocking`](./docs/rules.md#ownership-and-tests) | Reject Vitest and Jest mocking of repository-owned modules |
|
|
120
|
+
| [`no-object-parameters`](./docs/rules.md#boundary-contracts) | Reject `object` function parameters |
|
|
121
|
+
| [`no-positional-boolean-parameters`](./docs/rules.md#object-and-api-construction) | Reject positional boolean flags on named functions and methods |
|
|
122
|
+
| [`no-reflect-apply`](./docs/rules.md#object-and-api-construction) | Reject `Reflect.apply` |
|
|
123
|
+
| [`no-reflect-get`](./docs/rules.md#object-and-api-construction) | Reject `Reflect.get` |
|
|
124
|
+
| [`no-unknown-parameters`](./docs/rules.md#boundary-contracts) | Keep explicit `unknown` parameters at decoding boundaries |
|
|
125
|
+
| [`no-unknown-returns`](./docs/rules.md#boundary-contracts) | Reject `unknown` return contracts |
|
|
126
|
+
| [`no-unknown-type-aliases`](./docs/rules.md#boundary-contracts) | Reject type aliases that resolve to `unknown` |
|
|
127
|
+
| [`no-unsafe-dictionary-type`](./docs/rules.md#boundary-contracts) | Reject dictionary contracts with broad value types |
|
|
128
|
+
| [`no-unhandled-detached-promises`](./docs/rules.md#async-errors) | Require rejection handling on `void`-marked detached call chains |
|
|
129
|
+
| [`no-widen-then-assert`](./docs/rules.md#type-evidence) | Reject const flows that widen a known value before narrowing it |
|
|
130
|
+
| [`prefer-options-parameter`](./docs/rules.md#object-and-api-construction) | Require options objects for named functions and methods with three or more inputs |
|
|
131
|
+
| [`prefer-switch-discriminator-chain`](./docs/rules.md#object-and-api-construction) | Require a switch for four or more equality branches on one discriminator |
|
|
132
|
+
| [`prefer-top-level-function-declarations`](./docs/rules.md#object-and-api-construction) | Require declarations for direct top-level function bindings and default exports |
|
|
133
|
+
| [`require-lint-suppression-reason`](./docs/rules.md#lint-policy) | Require a forcing reason on lint disable directives |
|
|
134
|
+
| [`require-safety-comment-for-type-assertion`](./docs/rules.md#type-evidence) | Require one `SAFETY:` comment for each outermost non-const assertion |
|
|
135
135
|
|
|
136
136
|
## Attribution
|
|
137
137
|
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
|
|
5
5
|
//#region package.json
|
|
6
|
-
var version = "0.
|
|
6
|
+
var version = "0.3.0";
|
|
7
7
|
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/rules/consistent-blank-lines.ts
|
|
@@ -24,14 +24,8 @@ const IMPORT_SPECIFIER_TYPES = new Set([
|
|
|
24
24
|
AST_NODE_TYPES.ImportDefaultSpecifier,
|
|
25
25
|
AST_NODE_TYPES.ImportNamespaceSpecifier
|
|
26
26
|
]);
|
|
27
|
-
const OPAQUE_BODY_TYPES = new Set([
|
|
28
|
-
|
|
29
|
-
AST_NODE_TYPES.ClassDeclaration,
|
|
30
|
-
AST_NODE_TYPES.ClassExpression
|
|
31
|
-
]);
|
|
32
|
-
const FLOW_PREV_TYPES = new Set([AST_NODE_TYPES.ExpressionStatement, AST_NODE_TYPES.IfStatement]);
|
|
33
|
-
const FLOW_NEXT_TYPES = new Set([
|
|
34
|
-
AST_NODE_TYPES.ExpressionStatement,
|
|
27
|
+
const OPAQUE_BODY_TYPES = new Set([AST_NODE_TYPES.FunctionDeclaration, AST_NODE_TYPES.ClassDeclaration]);
|
|
28
|
+
const EXPRESSION_CONTINUATION_TYPES = new Set([
|
|
35
29
|
AST_NODE_TYPES.IfStatement,
|
|
36
30
|
AST_NODE_TYPES.ReturnStatement,
|
|
37
31
|
AST_NODE_TYPES.ThrowStatement,
|
|
@@ -43,6 +37,7 @@ const HEAVY_NEXT_TYPES = new Set([
|
|
|
43
37
|
AST_NODE_TYPES.FunctionDeclaration,
|
|
44
38
|
AST_NODE_TYPES.ClassDeclaration,
|
|
45
39
|
AST_NODE_TYPES.TSInterfaceDeclaration,
|
|
40
|
+
AST_NODE_TYPES.TSDeclareFunction,
|
|
46
41
|
AST_NODE_TYPES.ReturnStatement,
|
|
47
42
|
AST_NODE_TYPES.ThrowStatement
|
|
48
43
|
]);
|
|
@@ -59,34 +54,42 @@ const consistentBlankLines = {
|
|
|
59
54
|
meta: {
|
|
60
55
|
type: "layout",
|
|
61
56
|
docs: {
|
|
62
|
-
description: "
|
|
57
|
+
description: "Apply explicit gap policies between adjacent statement-list and JSXChild items.",
|
|
63
58
|
url: "https://github.com/utilfirst/utilfirst-eslint-plugin/blob/main/docs/rules/consistent-blank-lines.md"
|
|
64
59
|
},
|
|
65
60
|
fixable: "whitespace",
|
|
66
61
|
defaultOptions: [],
|
|
67
62
|
schema: [],
|
|
68
63
|
messages: {
|
|
69
|
-
extra: "Unexpected blank line between items that
|
|
70
|
-
missing: "Expected
|
|
64
|
+
extra: "Unexpected blank line between items that require a tight gap.",
|
|
65
|
+
missing: "Expected one blank line between items that require separation."
|
|
71
66
|
}
|
|
72
67
|
},
|
|
73
68
|
create(context) {
|
|
74
69
|
const sourceCode = context.sourceCode;
|
|
70
|
+
const lineBreak = sourceCode.text.includes("\r\n") ? "\r\n" : "\n";
|
|
75
71
|
function checkBlock(statements) {
|
|
76
72
|
for (let i = 0; i < statements.length - 1; i++) {
|
|
77
73
|
const prev = statements[i];
|
|
78
74
|
const next = statements[i + 1];
|
|
79
|
-
if (prev && next)
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
if (prev && next) {
|
|
76
|
+
const { effectiveEnd, leadingComments } = partitionStatementComments({
|
|
77
|
+
comments: sourceCode.getCommentsBefore(next),
|
|
78
|
+
prev
|
|
79
|
+
});
|
|
80
|
+
checkPair({
|
|
81
|
+
effectiveEnd,
|
|
82
|
+
effectiveStart: leadingComments[0] ?? next,
|
|
82
83
|
next,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
policy: statementGapPolicy({
|
|
85
|
+
leadingComments,
|
|
86
|
+
next,
|
|
87
|
+
prev,
|
|
88
|
+
sourceCode
|
|
89
|
+
}),
|
|
90
|
+
prev
|
|
91
|
+
});
|
|
92
|
+
}
|
|
90
93
|
}
|
|
91
94
|
}
|
|
92
95
|
function checkJsxChildren(children) {
|
|
@@ -111,28 +114,36 @@ const consistentBlankLines = {
|
|
|
111
114
|
const { node: prev } = prevSibling;
|
|
112
115
|
const { leading, node: next } = nextSibling;
|
|
113
116
|
checkPair({
|
|
117
|
+
effectiveEnd: prev,
|
|
114
118
|
effectiveStart: leading[0] ?? next,
|
|
115
|
-
|
|
119
|
+
next,
|
|
120
|
+
policy: jsxGapPolicy({
|
|
116
121
|
leading,
|
|
117
122
|
next,
|
|
118
123
|
prev
|
|
119
124
|
}),
|
|
120
|
-
|
|
121
|
-
prev,
|
|
122
|
-
shouldPreserveExtra: () => false
|
|
125
|
+
prev
|
|
123
126
|
});
|
|
124
127
|
}
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
|
-
function checkPair({
|
|
128
|
-
|
|
130
|
+
function checkPair({ effectiveEnd, effectiveStart, next, policy, prev }) {
|
|
131
|
+
if (policy === "preserve") return;
|
|
132
|
+
const prevEndLine = effectiveEnd.loc.end.line;
|
|
129
133
|
const nextStartLine = effectiveStart.loc.start.line;
|
|
130
|
-
if (nextStartLine
|
|
131
|
-
|
|
134
|
+
if (nextStartLine === prevEndLine) {
|
|
135
|
+
if (policy === "tight") return;
|
|
136
|
+
const indentation = indentationOf(prev, sourceCode);
|
|
137
|
+
context.report({
|
|
138
|
+
node: next,
|
|
139
|
+
messageId: "missing",
|
|
140
|
+
fix: (fixer) => fixer.replaceTextRange([effectiveEnd.range[1], effectiveStart.range[0]], `${lineBreak}${lineBreak}${indentation}`)
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
132
144
|
const paddingCount = nextStartLine - prevEndLine - 1;
|
|
133
|
-
const targetPadding =
|
|
145
|
+
const targetPadding = policy === "separate" ? 1 : 0;
|
|
134
146
|
if (paddingCount === targetPadding) return;
|
|
135
|
-
if (paddingCount > targetPadding && shouldPreserveExtra()) return;
|
|
136
147
|
context.report({
|
|
137
148
|
node: next,
|
|
138
149
|
messageId: paddingCount < targetPadding ? "missing" : "extra",
|
|
@@ -145,7 +156,7 @@ const consistentBlankLines = {
|
|
|
145
156
|
line: nextStartLine,
|
|
146
157
|
column: 0
|
|
147
158
|
});
|
|
148
|
-
return fixer.replaceTextRange([start, end],
|
|
159
|
+
return fixer.replaceTextRange([start, end], lineBreak.repeat(targetPadding));
|
|
149
160
|
}
|
|
150
161
|
});
|
|
151
162
|
}
|
|
@@ -171,25 +182,61 @@ const consistentBlankLines = {
|
|
|
171
182
|
};
|
|
172
183
|
}
|
|
173
184
|
};
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
function partitionStatementComments({ comments, prev }) {
|
|
186
|
+
let effectiveEnd = prev;
|
|
187
|
+
let leadingIndex = 0;
|
|
188
|
+
while (true) {
|
|
189
|
+
const comment = comments[leadingIndex];
|
|
190
|
+
if (!comment || comment.loc.start.line !== effectiveEnd.loc.end.line) break;
|
|
191
|
+
effectiveEnd = comment;
|
|
192
|
+
leadingIndex++;
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
effectiveEnd,
|
|
196
|
+
leadingComments: comments.slice(leadingIndex)
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function indentationOf(node, sourceCode) {
|
|
200
|
+
const lineStart = sourceCode.getIndexFromLoc({
|
|
201
|
+
line: node.loc.start.line,
|
|
202
|
+
column: 0
|
|
203
|
+
});
|
|
204
|
+
const linePrefix = sourceCode.text.slice(lineStart, node.range[0]);
|
|
205
|
+
return /^[\t ]*/u.exec(linePrefix)?.[0] ?? "";
|
|
206
|
+
}
|
|
207
|
+
function statementGapPolicy({ leadingComments, next, prev, sourceCode }) {
|
|
208
|
+
if (itemsSpanMultipleLines(leadingComments)) return "separate";
|
|
209
|
+
const prevHook = hookStatementOf(prev);
|
|
210
|
+
const nextHook = hookStatementOf(next);
|
|
211
|
+
if (prevHook || nextHook) return prevHook?.kind === "variable" && nextHook?.kind === "variable" && declarationsHaveSameShell({
|
|
212
|
+
next,
|
|
213
|
+
prev
|
|
214
|
+
}) ? "tight" : "separate";
|
|
215
|
+
if (isImportPair(prev, next) || isReExport(prev) && isReExport(next) || isExpressionStatementPair(prev, next)) return "preserve";
|
|
216
|
+
if (sharesNameFlow({
|
|
179
217
|
next,
|
|
180
218
|
prev,
|
|
181
|
-
|
|
182
|
-
})
|
|
183
|
-
return sharesNameFlow({
|
|
219
|
+
sourceCode
|
|
220
|
+
}) || statementsRequireTightGap({
|
|
184
221
|
next,
|
|
185
222
|
prev,
|
|
186
223
|
sourceCode
|
|
187
|
-
})
|
|
224
|
+
})) return "tight";
|
|
225
|
+
return "separate";
|
|
188
226
|
}
|
|
189
|
-
function
|
|
190
|
-
|
|
191
|
-
if (
|
|
192
|
-
return
|
|
227
|
+
function hookStatementOf(stmt) {
|
|
228
|
+
const declaration = unwrapExport(stmt);
|
|
229
|
+
if (declaration.type === AST_NODE_TYPES.VariableDeclaration && declaration.declarations.length === 1 && isHookCall(declaration.declarations[0].init)) return { kind: "variable" };
|
|
230
|
+
if (declaration.type === AST_NODE_TYPES.ExpressionStatement && isHookCall(declaration.expression)) return { kind: "expression" };
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
function declarationsHaveSameShell({ next, prev }) {
|
|
234
|
+
const previousDeclaration = unwrapExport(prev);
|
|
235
|
+
const nextDeclaration = unwrapExport(next);
|
|
236
|
+
return previousDeclaration.type === AST_NODE_TYPES.VariableDeclaration && nextDeclaration.type === AST_NODE_TYPES.VariableDeclaration && isExported(prev) === isExported(next) && !isMultiLine(prev) && !isMultiLine(next) && previousDeclaration.declarations.length === 1 && nextDeclaration.declarations.length === 1;
|
|
237
|
+
}
|
|
238
|
+
function isExported(stmt) {
|
|
239
|
+
return stmt.type === AST_NODE_TYPES.ExportNamedDeclaration || stmt.type === AST_NODE_TYPES.ExportDefaultDeclaration;
|
|
193
240
|
}
|
|
194
241
|
function sharesNameFlow({ next, prev, sourceCode }) {
|
|
195
242
|
if (isMultiLine(prev)) return false;
|
|
@@ -205,21 +252,17 @@ function sharesNameFlow({ next, prev, sourceCode }) {
|
|
|
205
252
|
function isHookCall(node) {
|
|
206
253
|
return node?.type === AST_NODE_TYPES.CallExpression && node.callee.type === AST_NODE_TYPES.Identifier && /^use[A-Z]/u.test(node.callee.name);
|
|
207
254
|
}
|
|
208
|
-
function
|
|
209
|
-
if (isImportPair(prev, next)) return true;
|
|
210
|
-
if (isReExport(prev) && isReExport(next)) return true;
|
|
255
|
+
function statementsRequireTightGap({ next, prev, sourceCode }) {
|
|
211
256
|
if (isMatchingVarDeclPair({
|
|
212
257
|
next,
|
|
213
|
-
prev
|
|
258
|
+
prev,
|
|
259
|
+
sourceCode
|
|
214
260
|
})) return true;
|
|
215
261
|
if (isMatchingTypeAliasPair(prev, next)) return true;
|
|
216
|
-
if (
|
|
262
|
+
if (prev.type === AST_NODE_TYPES.IfStatement && next.type === AST_NODE_TYPES.IfStatement) return !(isGuardIf(prev) && !isGuardIf(next));
|
|
263
|
+
if (prev.type === AST_NODE_TYPES.ExpressionStatement && EXPRESSION_CONTINUATION_TYPES.has(next.type)) {
|
|
217
264
|
if (HEAVY_NEXT_TYPES.has(next.type) && isMultiLine(next)) return false;
|
|
218
|
-
|
|
219
|
-
if (next.type !== AST_NODE_TYPES.IfStatement) return false;
|
|
220
|
-
if (isGuardIf(prev) && !isGuardIf(next)) return false;
|
|
221
|
-
} else if (next.type === AST_NODE_TYPES.IfStatement && isGuardIf(next)) return false;
|
|
222
|
-
return true;
|
|
265
|
+
return !(next.type === AST_NODE_TYPES.IfStatement && isGuardIf(next));
|
|
223
266
|
}
|
|
224
267
|
return false;
|
|
225
268
|
}
|
|
@@ -232,56 +275,47 @@ function isExpressionStatementPair(prev, next) {
|
|
|
232
275
|
function isReExport(stmt) {
|
|
233
276
|
return stmt.type === AST_NODE_TYPES.ExportNamedDeclaration && stmt.source !== null || stmt.type === AST_NODE_TYPES.ExportAllDeclaration;
|
|
234
277
|
}
|
|
235
|
-
function isMatchingVarDeclPair({ next, prev,
|
|
278
|
+
function isMatchingVarDeclPair({ next, prev, sourceCode }) {
|
|
236
279
|
const previousDeclaration = unwrapExport(prev);
|
|
237
280
|
const nextDeclaration = unwrapExport(next);
|
|
238
281
|
if (previousDeclaration.type !== AST_NODE_TYPES.VariableDeclaration || nextDeclaration.type !== AST_NODE_TYPES.VariableDeclaration) return false;
|
|
239
282
|
if (!isConstOrLet(previousDeclaration) || !isConstOrLet(nextDeclaration)) return false;
|
|
240
283
|
if (isMultiLine(prev) || isMultiLine(next)) return false;
|
|
241
284
|
if (previousDeclaration.declarations.length !== 1 || nextDeclaration.declarations.length !== 1) return false;
|
|
242
|
-
if (
|
|
243
|
-
|
|
285
|
+
if (!initializersBelongTogether({
|
|
286
|
+
nextInit: nextDeclaration.declarations[0].init,
|
|
287
|
+
prevInit: previousDeclaration.declarations[0].init,
|
|
288
|
+
sourceCode
|
|
289
|
+
})) return false;
|
|
290
|
+
return isExported(prev) === isExported(next);
|
|
244
291
|
}
|
|
245
292
|
function isMatchingTypeAliasPair(prev, next) {
|
|
246
293
|
const previousDeclaration = unwrapExport(prev);
|
|
247
294
|
const nextDeclaration = unwrapExport(next);
|
|
248
295
|
if (previousDeclaration.type !== AST_NODE_TYPES.TSTypeAliasDeclaration || nextDeclaration.type !== AST_NODE_TYPES.TSTypeAliasDeclaration) return false;
|
|
249
296
|
if (isMultiLine(prev) || isMultiLine(next)) return false;
|
|
250
|
-
return prev
|
|
297
|
+
return isExported(prev) === isExported(next);
|
|
251
298
|
}
|
|
252
299
|
function unwrapExport(stmt) {
|
|
253
300
|
if (stmt.type === AST_NODE_TYPES.ExportNamedDeclaration && stmt.declaration) return stmt.declaration;
|
|
301
|
+
if (stmt.type === AST_NODE_TYPES.ExportDefaultDeclaration) return stmt.declaration;
|
|
254
302
|
return stmt;
|
|
255
303
|
}
|
|
256
304
|
function isConstOrLet(decl) {
|
|
257
305
|
return decl.kind === "const" || decl.kind === "let";
|
|
258
306
|
}
|
|
259
|
-
function initializersBelongTogether(prevInit,
|
|
260
|
-
const
|
|
261
|
-
const
|
|
262
|
-
if (
|
|
263
|
-
if (
|
|
307
|
+
function initializersBelongTogether({ nextInit, prevInit, sourceCode }) {
|
|
308
|
+
const previousCallIdentity = callIdentityOf(prevInit, sourceCode);
|
|
309
|
+
const nextCallIdentity = callIdentityOf(nextInit, sourceCode);
|
|
310
|
+
if (previousCallIdentity !== null && nextCallIdentity !== null) return previousCallIdentity === nextCallIdentity;
|
|
311
|
+
if (previousCallIdentity !== null || nextCallIdentity !== null) return false;
|
|
264
312
|
return true;
|
|
265
313
|
}
|
|
266
|
-
function
|
|
314
|
+
function callIdentityOf(expr, sourceCode) {
|
|
267
315
|
if (!expr) return null;
|
|
268
|
-
|
|
269
|
-
return null;
|
|
270
|
-
}
|
|
271
|
-
function calleesEqual(a, b) {
|
|
272
|
-
if (!a || a.type !== b?.type) return false;
|
|
273
|
-
if (a.type === AST_NODE_TYPES.Identifier && b.type === AST_NODE_TYPES.Identifier) return a.name === b.name;
|
|
274
|
-
if (a.type === AST_NODE_TYPES.ThisExpression) return true;
|
|
275
|
-
if (a.type === AST_NODE_TYPES.MemberExpression && b.type === AST_NODE_TYPES.MemberExpression) {
|
|
276
|
-
if (a.computed !== b.computed) return false;
|
|
277
|
-
if (!calleesEqual(a.object, b.object)) return false;
|
|
278
|
-
if (!a.computed && a.property.type === AST_NODE_TYPES.Identifier && b.property.type === AST_NODE_TYPES.Identifier) return a.property.name === b.property.name;
|
|
279
|
-
if (a.computed && a.property.type === AST_NODE_TYPES.Identifier && b.property.type === AST_NODE_TYPES.Identifier) return a.property.name === b.property.name;
|
|
280
|
-
if (a.computed && a.property.type === AST_NODE_TYPES.Literal && b.property.type === AST_NODE_TYPES.Literal) return a.property.value === b.property.value;
|
|
281
|
-
return false;
|
|
282
|
-
}
|
|
283
|
-
if (a.type === AST_NODE_TYPES.CallExpression && b.type === AST_NODE_TYPES.CallExpression) return calleesEqual(a.callee, b.callee);
|
|
284
|
-
return false;
|
|
316
|
+
const call = expr.type === AST_NODE_TYPES.ChainExpression ? expr.expression : expr;
|
|
317
|
+
if (call.type !== AST_NODE_TYPES.CallExpression) return null;
|
|
318
|
+
return `${call.optional ? "optional" : "direct"}:${sourceCode.getText(call.callee)}`;
|
|
285
319
|
}
|
|
286
320
|
function isGuardIf(stmt) {
|
|
287
321
|
return stmt.type === AST_NODE_TYPES.IfStatement && blockAlwaysTerminates(stmt.consequent);
|
|
@@ -311,6 +345,7 @@ function collectIntroducedOrAssignedNames(stmt) {
|
|
|
311
345
|
else if (s.type === AST_NODE_TYPES.FunctionDeclaration && s.id) set.add(s.id.name);
|
|
312
346
|
else if (s.type === AST_NODE_TYPES.ClassDeclaration && s.id) set.add(s.id.name);
|
|
313
347
|
else if (s.type === AST_NODE_TYPES.TSInterfaceDeclaration) set.add(s.id.name);
|
|
348
|
+
else if (s.type === AST_NODE_TYPES.TSDeclareFunction && s.id) set.add(s.id.name);
|
|
314
349
|
else if (s.type === AST_NODE_TYPES.ExpressionStatement) {
|
|
315
350
|
const expr = s.expression;
|
|
316
351
|
if (expr.type === AST_NODE_TYPES.AssignmentExpression) collectAssignmentRoots(expr.left, set);
|
|
@@ -405,11 +440,17 @@ function isInSubtree(node, root) {
|
|
|
405
440
|
}
|
|
406
441
|
function isDeclarationOrPropertyKey(idNode) {
|
|
407
442
|
const parent = idNode.parent;
|
|
443
|
+
if (parent.type === AST_NODE_TYPES.LabeledStatement && parent.label === idNode || (parent.type === AST_NODE_TYPES.BreakStatement || parent.type === AST_NODE_TYPES.ContinueStatement) && parent.label === idNode) return true;
|
|
408
444
|
if (parent.type === AST_NODE_TYPES.VariableDeclarator && parent.id === idNode) return true;
|
|
409
445
|
if (FN_DECL_TYPES.has(parent.type) && "id" in parent && parent.id === idNode) return true;
|
|
410
446
|
if ((parent.type === AST_NODE_TYPES.ClassDeclaration || parent.type === AST_NODE_TYPES.ClassExpression) && parent.id === idNode) return true;
|
|
411
447
|
if (parent.type === AST_NODE_TYPES.MemberExpression && parent.property === idNode && !parent.computed) return true;
|
|
412
448
|
if (IMPORT_SPECIFIER_TYPES.has(parent.type) && "local" in parent && parent.local === idNode) return true;
|
|
449
|
+
if (parent.type === AST_NODE_TYPES.ImportSpecifier) return true;
|
|
450
|
+
if (parent.type === AST_NODE_TYPES.ExportSpecifier && parent.exported === idNode && parent.local !== idNode) return true;
|
|
451
|
+
if (parent.type === AST_NODE_TYPES.MetaProperty) return true;
|
|
452
|
+
if (parent.type === AST_NODE_TYPES.TSQualifiedName && parent.right === idNode) return true;
|
|
453
|
+
if ((parent.type === AST_NODE_TYPES.MethodDefinition || parent.type === AST_NODE_TYPES.PropertyDefinition || parent.type === AST_NODE_TYPES.AccessorProperty || parent.type === AST_NODE_TYPES.TSMethodSignature || parent.type === AST_NODE_TYPES.TSPropertySignature) && parent.key === idNode && !parent.computed) return true;
|
|
413
454
|
if (parent.type === AST_NODE_TYPES.Property && parent.key === idNode && !parent.computed && !parent.shorthand) return true;
|
|
414
455
|
if (isInBindingPosition(idNode)) return true;
|
|
415
456
|
return false;
|
|
@@ -443,35 +484,26 @@ function isInBindingPosition(idNode) {
|
|
|
443
484
|
}
|
|
444
485
|
return false;
|
|
445
486
|
}
|
|
446
|
-
function
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
if (siblingsIncludeLiteralText(next)) return true;
|
|
451
|
-
return !(isMultiLine(prev) || isMultiLine(next));
|
|
487
|
+
function jsxGapPolicy({ leading, next, prev }) {
|
|
488
|
+
if (itemsSpanMultipleLines(leading)) return "separate";
|
|
489
|
+
if (isLiteralTextChild(prev) || isLiteralTextChild(next)) return "tight";
|
|
490
|
+
return isMultiLine(prev) || isMultiLine(next) ? "separate" : "tight";
|
|
452
491
|
}
|
|
453
492
|
function isCommentOnlyContainer(child) {
|
|
454
493
|
return child.type === AST_NODE_TYPES.JSXExpressionContainer && child.expression.type === AST_NODE_TYPES.JSXEmptyExpression;
|
|
455
494
|
}
|
|
456
|
-
function
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
for (const sibling of parent.children) {
|
|
460
|
-
if (sibling.type === AST_NODE_TYPES.JSXText && sibling.value.trim() !== "") return true;
|
|
461
|
-
if (sibling.type === AST_NODE_TYPES.JSXExpressionContainer && expressionYieldsStringLiteral(sibling.expression)) return true;
|
|
462
|
-
}
|
|
463
|
-
return false;
|
|
495
|
+
function isLiteralTextChild(child) {
|
|
496
|
+
if (child.type === AST_NODE_TYPES.JSXText) return child.value.trim() !== "";
|
|
497
|
+
return child.type === AST_NODE_TYPES.JSXExpressionContainer && expressionProducesTextOrNothing(child.expression);
|
|
464
498
|
}
|
|
465
|
-
function
|
|
466
|
-
if (expr.type === AST_NODE_TYPES.Literal) return
|
|
499
|
+
function expressionProducesTextOrNothing(expr) {
|
|
500
|
+
if (expr.type === AST_NODE_TYPES.Literal) return typeof expr.value === "string";
|
|
467
501
|
if (expr.type === AST_NODE_TYPES.TemplateLiteral) return true;
|
|
468
|
-
if (expr.type === AST_NODE_TYPES.
|
|
469
|
-
if (expr.type === AST_NODE_TYPES.
|
|
502
|
+
if (expr.type === AST_NODE_TYPES.TSAsExpression || expr.type === AST_NODE_TYPES.TSTypeAssertion || expr.type === AST_NODE_TYPES.TSNonNullExpression || expr.type === AST_NODE_TYPES.TSSatisfiesExpression) return expressionProducesTextOrNothing(expr.expression);
|
|
503
|
+
if (expr.type === AST_NODE_TYPES.LogicalExpression && expr.operator === "&&") return expressionProducesTextOrNothing(expr.right);
|
|
504
|
+
if (expr.type === AST_NODE_TYPES.ConditionalExpression) return expressionProducesTextOrNothing(expr.consequent) && expressionProducesTextOrNothing(expr.alternate);
|
|
470
505
|
return false;
|
|
471
506
|
}
|
|
472
|
-
function isString$2(value) {
|
|
473
|
-
return typeof value === "string";
|
|
474
|
-
}
|
|
475
507
|
function isNode(value) {
|
|
476
508
|
return value !== null && typeof value === "object" && "type" in value && typeof value.type === "string";
|
|
477
509
|
}
|
|
@@ -492,12 +524,11 @@ function walk(node, fn) {
|
|
|
492
524
|
function isMultiLine(node) {
|
|
493
525
|
return node.loc.start.line !== node.loc.end.line;
|
|
494
526
|
}
|
|
495
|
-
function
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
return Boolean(first && last && last.loc.end.line > first.loc.start.line);
|
|
527
|
+
function itemsSpanMultipleLines(items) {
|
|
528
|
+
const first = items[0];
|
|
529
|
+
const last = items.at(-1);
|
|
530
|
+
if (!first || !last) return false;
|
|
531
|
+
return last.loc.end.line > first.loc.start.line;
|
|
501
532
|
}
|
|
502
533
|
|
|
503
534
|
//#endregion
|