@timmo001/oxlint-rules 0.3.0 → 0.3.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/README.md +2 -1
- package/THIRD_PARTY_NOTICES.md +9 -0
- package/dist/cli.js +978 -83
- package/dist/configs/recommended-effect.js +1207 -312
- package/dist/configs/recommended.js +772 -70
- package/dist/upstream/anti-slop.js +765 -63
- package/dist/upstream/effect.js +196 -3
- package/package.json +5 -5
- package/vendor/anti-slop/src/effect/index.ts +8 -0
- package/vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts +52 -0
- package/vendor/anti-slop/src/effect/rules/no-manual-tag-comparison.ts +45 -0
- package/vendor/anti-slop/src/effect/rules/no-manual-tagged-construction.ts +37 -0
- package/vendor/anti-slop/src/effect/rules/prefer-effect-match.ts +54 -0
- package/vendor/anti-slop/src/effect/shared/tagged-values.ts +97 -0
- package/vendor/anti-slop/src/index.ts +6 -0
- package/vendor/anti-slop/src/rules/no-array-filter-map.ts +28 -0
- package/vendor/anti-slop/src/rules/no-known-value-widening.ts +2 -14
- package/vendor/anti-slop/src/rules/no-module-mocking.ts +3 -14
- package/vendor/anti-slop/src/rules/no-reduce-accumulator-copy.ts +109 -0
- package/vendor/anti-slop/src/rules/require-readable-spacing.ts +47 -0
- package/vendor/anti-slop/src/shared/array-method.ts +94 -0
- package/vendor/anti-slop/src/shared/reflect-method.ts +2 -13
- package/vendor/anti-slop/src/shared/scope.ts +15 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/LICENSE +22 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/UPSTREAM.md +28 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-ast.ts +51 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-between-statements.ts +906 -0
- package/vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-options.d.ts +87 -0
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,213 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { resolve as resolve2 } from "node:path";
|
|
5
|
+
|
|
6
|
+
// node_modules/oxlint/dist/index.js
|
|
7
|
+
function defineConfig(config) {
|
|
8
|
+
return config;
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
// vendor/anti-slop/src/index.ts
|
|
4
12
|
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
5
13
|
|
|
6
|
-
// vendor/anti-slop/src/rules/no-
|
|
14
|
+
// vendor/anti-slop/src/rules/no-array-filter-map.ts
|
|
7
15
|
import { defineRule } from "@oxlint/plugins";
|
|
16
|
+
|
|
17
|
+
// vendor/anti-slop/src/shared/array-method.ts
|
|
18
|
+
function unwrapArrayExpression(node) {
|
|
19
|
+
while (node.type === "ParenthesizedExpression" || node.type === "ChainExpression" || node.type === "TSAsExpression" || node.type === "TSTypeAssertion" || node.type === "TSNonNullExpression" || node.type === "TSSatisfiesExpression") {
|
|
20
|
+
node = node.expression;
|
|
21
|
+
}
|
|
22
|
+
return node;
|
|
23
|
+
}
|
|
24
|
+
function resolveArrayBinding(sourceCode, node) {
|
|
25
|
+
node = unwrapArrayExpression(node);
|
|
26
|
+
if (node.type !== "Identifier")
|
|
27
|
+
return null;
|
|
28
|
+
let scope = sourceCode.getScope(node);
|
|
29
|
+
while (scope !== null) {
|
|
30
|
+
const variable = scope.set.get(node.name);
|
|
31
|
+
if (variable !== undefined)
|
|
32
|
+
return variable;
|
|
33
|
+
scope = scope.upper;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
function arrayMethodTarget(node) {
|
|
38
|
+
node = unwrapArrayExpression(node);
|
|
39
|
+
if (node.type !== "MemberExpression")
|
|
40
|
+
return null;
|
|
41
|
+
const property = node.property;
|
|
42
|
+
if (!node.computed && property.type === "Identifier") {
|
|
43
|
+
return { name: property.name, object: node.object };
|
|
44
|
+
}
|
|
45
|
+
if (node.computed && property.type === "Literal" && typeof property.value === "string") {
|
|
46
|
+
return { name: property.value, object: node.object };
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
function isArrayAnnotation(type) {
|
|
51
|
+
if (type.type === "TSArrayType" || type.type === "TSTupleType")
|
|
52
|
+
return true;
|
|
53
|
+
if (type.type === "TSParenthesizedType")
|
|
54
|
+
return isArrayAnnotation(type.typeAnnotation);
|
|
55
|
+
if (type.type === "TSTypeOperator" && type.operator === "readonly") {
|
|
56
|
+
return isArrayAnnotation(type.typeAnnotation);
|
|
57
|
+
}
|
|
58
|
+
return type.type === "TSTypeReference" && type.typeName.type === "Identifier" && (type.typeName.name === "Array" || type.typeName.name === "ReadonlyArray");
|
|
59
|
+
}
|
|
60
|
+
function isKnownArrayExpression(sourceCode, node, visited = new Set) {
|
|
61
|
+
node = unwrapArrayExpression(node);
|
|
62
|
+
if (node.type === "ArrayExpression")
|
|
63
|
+
return true;
|
|
64
|
+
if (node.type === "CallExpression") {
|
|
65
|
+
const method = arrayMethodTarget(node.callee);
|
|
66
|
+
return method !== null && ["map", "filter", "flatMap", "slice", "concat", "toSorted", "toReversed", "toSpliced"].includes(method.name) && isKnownArrayExpression(sourceCode, method.object, visited);
|
|
67
|
+
}
|
|
68
|
+
if (node.type !== "Identifier")
|
|
69
|
+
return false;
|
|
70
|
+
const variable = resolveArrayBinding(sourceCode, node);
|
|
71
|
+
if (variable === null || visited.has(variable))
|
|
72
|
+
return false;
|
|
73
|
+
visited.add(variable);
|
|
74
|
+
if (variable.references.some((reference) => reference.isWrite() && !reference.init))
|
|
75
|
+
return false;
|
|
76
|
+
for (const identifier of variable.identifiers) {
|
|
77
|
+
const annotation = identifier.typeAnnotation?.typeAnnotation;
|
|
78
|
+
if (annotation !== undefined)
|
|
79
|
+
return isArrayAnnotation(annotation);
|
|
80
|
+
}
|
|
81
|
+
for (const definition of variable.defs) {
|
|
82
|
+
if (definition.type === "Variable" && definition.node.type === "VariableDeclarator" && definition.node.id.type === "Identifier" && definition.node.init !== null && definition.node.parent.type === "VariableDeclaration" && definition.node.parent.kind === "const") {
|
|
83
|
+
return isKnownArrayExpression(sourceCode, definition.node.init, visited);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// vendor/anti-slop/src/rules/no-array-filter-map.ts
|
|
90
|
+
var noArrayFilterMapRule = defineRule({
|
|
91
|
+
meta: {
|
|
92
|
+
type: "suggestion",
|
|
93
|
+
docs: { description: "Disallow adjacent array filter/map passes in favor of lazy iterator helpers or a single transformation." },
|
|
94
|
+
messages: {
|
|
95
|
+
arrayFilterMap: "Avoid consecutive array `{{first}}` and `{{second}}` passes. Prefer `.values().{{first}}(...).{{second}}(...).toArray()` where iterator helpers are supported, or a single `flatMap`/mutating reducer. Preserve callback ordering, indexes, and filtering semantics."
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
createOnce(context) {
|
|
99
|
+
return {
|
|
100
|
+
CallExpression(node) {
|
|
101
|
+
const outer = arrayMethodTarget(node.callee);
|
|
102
|
+
if (outer === null || outer.name !== "map" && outer.name !== "filter")
|
|
103
|
+
return;
|
|
104
|
+
const innerCall = unwrapArrayExpression(outer.object);
|
|
105
|
+
if (innerCall.type !== "CallExpression")
|
|
106
|
+
return;
|
|
107
|
+
const inner = arrayMethodTarget(innerCall.callee);
|
|
108
|
+
if (inner === null || inner.name !== (outer.name === "map" ? "filter" : "map"))
|
|
109
|
+
return;
|
|
110
|
+
if (!isKnownArrayExpression(context.sourceCode, inner.object))
|
|
111
|
+
return;
|
|
112
|
+
context.report({ node, messageId: "arrayFilterMap", data: { first: inner.name, second: outer.name } });
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// vendor/anti-slop/src/rules/no-reduce-accumulator-copy.ts
|
|
119
|
+
import { defineRule as defineRule2 } from "@oxlint/plugins";
|
|
120
|
+
function enclosingReducer(node) {
|
|
121
|
+
let parent = node.parent;
|
|
122
|
+
while (parent !== null) {
|
|
123
|
+
if (parent.type === "FunctionDeclaration")
|
|
124
|
+
return null;
|
|
125
|
+
if (parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression") {
|
|
126
|
+
const callback = parent;
|
|
127
|
+
let owner = callback.parent;
|
|
128
|
+
while (owner !== null && unwrapArrayExpression(owner) === callback)
|
|
129
|
+
owner = owner.parent;
|
|
130
|
+
if (owner?.type !== "CallExpression")
|
|
131
|
+
return null;
|
|
132
|
+
const method = arrayMethodTarget(owner.callee);
|
|
133
|
+
const firstArgument = owner.arguments[0];
|
|
134
|
+
if (method === null || method.name !== "reduce" && method.name !== "reduceRight" || owner.arguments.length > 2 || firstArgument === undefined || unwrapArrayExpression(firstArgument) !== callback)
|
|
135
|
+
return null;
|
|
136
|
+
const firstParameter = callback.params[0];
|
|
137
|
+
const accumulator = firstParameter?.type === "AssignmentPattern" ? firstParameter.left : firstParameter;
|
|
138
|
+
if (accumulator?.type !== "Identifier")
|
|
139
|
+
return null;
|
|
140
|
+
return { callback, accumulator, initialValue: owner.arguments[1] };
|
|
141
|
+
}
|
|
142
|
+
parent = parent.parent;
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
function referencesAccumulator(sourceCode, node, accumulator, visited = new Set) {
|
|
147
|
+
const variable = resolveArrayBinding(sourceCode, node);
|
|
148
|
+
if (variable === null || visited.has(variable))
|
|
149
|
+
return false;
|
|
150
|
+
if (variable === accumulator)
|
|
151
|
+
return true;
|
|
152
|
+
visited.add(variable);
|
|
153
|
+
if (variable.references.some((reference) => reference.isWrite() && !reference.init))
|
|
154
|
+
return false;
|
|
155
|
+
for (const definition of variable.defs) {
|
|
156
|
+
if (definition.type === "Variable" && definition.node.type === "VariableDeclarator" && definition.node.id.type === "Identifier" && definition.node.init !== null && definition.node.parent.type === "VariableDeclaration" && definition.node.parent.kind === "const") {
|
|
157
|
+
return referencesAccumulator(sourceCode, definition.node.init, accumulator, visited);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
function isGlobalCopyOwner(sourceCode, node, name) {
|
|
163
|
+
node = unwrapArrayExpression(node);
|
|
164
|
+
if (node.type !== "Identifier" || node.name !== name)
|
|
165
|
+
return false;
|
|
166
|
+
const variable = resolveArrayBinding(sourceCode, node);
|
|
167
|
+
return variable === null || variable.defs.length === 0;
|
|
168
|
+
}
|
|
169
|
+
var noReduceAccumulatorCopyRule = defineRule2({
|
|
170
|
+
meta: {
|
|
171
|
+
type: "problem",
|
|
172
|
+
docs: { description: "Disallow copying growing reducer accumulators with Object.assign, Array.from, or array copy methods." },
|
|
173
|
+
messages: {
|
|
174
|
+
accumulatorCopy: "Do not copy the reducer accumulator on every iteration; growing copies can cause quadratic work. Mutate a fresh, locally owned accumulator and return it, or use an iterator pipeline/flatMap."
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
createOnce(context) {
|
|
178
|
+
return {
|
|
179
|
+
CallExpression(node) {
|
|
180
|
+
const method = arrayMethodTarget(node.callee);
|
|
181
|
+
if (method === null)
|
|
182
|
+
return;
|
|
183
|
+
const reducer = enclosingReducer(node);
|
|
184
|
+
if (reducer === null)
|
|
185
|
+
return;
|
|
186
|
+
const accumulator = context.sourceCode.getDeclaredVariables(reducer.callback).find((variable) => variable.identifiers.some((identifier) => identifier.start === reducer.accumulator.start));
|
|
187
|
+
if (accumulator === undefined)
|
|
188
|
+
return;
|
|
189
|
+
const isAccumulator = (expression) => referencesAccumulator(context.sourceCode, expression, accumulator);
|
|
190
|
+
let copiesAccumulator = false;
|
|
191
|
+
if (method.name === "assign" && isGlobalCopyOwner(context.sourceCode, method.object, "Object")) {
|
|
192
|
+
const target = node.arguments[0];
|
|
193
|
+
copiesAccumulator = target !== undefined && unwrapArrayExpression(target).type === "ObjectExpression" && node.arguments.slice(1).some(isAccumulator);
|
|
194
|
+
} else if (method.name === "from" && isGlobalCopyOwner(context.sourceCode, method.object, "Array")) {
|
|
195
|
+
const source = node.arguments[0];
|
|
196
|
+
copiesAccumulator = source !== undefined && isAccumulator(source);
|
|
197
|
+
} else if (["concat", "slice", "toSpliced", "toSorted", "toReversed", "with"].includes(method.name)) {
|
|
198
|
+
const initialValue = reducer.initialValue;
|
|
199
|
+
const arrayAccumulator = initialValue !== undefined && isKnownArrayExpression(context.sourceCode, initialValue);
|
|
200
|
+
copiesAccumulator = arrayAccumulator && isAccumulator(method.object);
|
|
201
|
+
}
|
|
202
|
+
if (copiesAccumulator)
|
|
203
|
+
context.report({ node, messageId: "accumulatorCopy" });
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// vendor/anti-slop/src/rules/no-chained-type-assertions.ts
|
|
210
|
+
import { defineRule as defineRule3 } from "@oxlint/plugins";
|
|
8
211
|
function isTypeAssertionExpression(node) {
|
|
9
212
|
return node.type === "TSAsExpression" || node.type === "TSTypeAssertion";
|
|
10
213
|
}
|
|
@@ -39,7 +242,7 @@ function isForbiddenAssertionChain(node) {
|
|
|
39
242
|
}
|
|
40
243
|
return assertionCount > 1 && hasNonConstAssertion;
|
|
41
244
|
}
|
|
42
|
-
var noChainedTypeAssertionsRule =
|
|
245
|
+
var noChainedTypeAssertionsRule = defineRule3({
|
|
43
246
|
meta: {
|
|
44
247
|
type: "problem",
|
|
45
248
|
docs: {
|
|
@@ -63,7 +266,7 @@ var noChainedTypeAssertionsRule = defineRule({
|
|
|
63
266
|
});
|
|
64
267
|
|
|
65
268
|
// vendor/anti-slop/src/rules/no-conditional-empty-object-spread.ts
|
|
66
|
-
import { defineRule as
|
|
269
|
+
import { defineRule as defineRule4 } from "@oxlint/plugins";
|
|
67
270
|
function unwrapParentheses(node) {
|
|
68
271
|
let current = node;
|
|
69
272
|
while (current.type === "ParenthesizedExpression") {
|
|
@@ -78,7 +281,7 @@ function isConditionalEmptyObjectSpread(node) {
|
|
|
78
281
|
const conditional = unwrapParentheses(node);
|
|
79
282
|
return conditional.type === "ConditionalExpression" && (isEmptyObjectExpression(conditional.consequent) || isEmptyObjectExpression(conditional.alternate));
|
|
80
283
|
}
|
|
81
|
-
var noConditionalEmptyObjectSpreadRule =
|
|
284
|
+
var noConditionalEmptyObjectSpreadRule = defineRule4({
|
|
82
285
|
meta: {
|
|
83
286
|
type: "suggestion",
|
|
84
287
|
docs: {
|
|
@@ -102,7 +305,7 @@ var noConditionalEmptyObjectSpreadRule = defineRule2({
|
|
|
102
305
|
});
|
|
103
306
|
|
|
104
307
|
// vendor/anti-slop/src/rules/no-known-value-widening.ts
|
|
105
|
-
import { defineRule as
|
|
308
|
+
import { defineRule as defineRule5 } from "@oxlint/plugins";
|
|
106
309
|
|
|
107
310
|
// vendor/anti-slop/src/shared/lexical-type-parameters.ts
|
|
108
311
|
function isNode(value) {
|
|
@@ -505,9 +708,9 @@ function classifyWideningTarget(type, environment) {
|
|
|
505
708
|
if (alias === null)
|
|
506
709
|
return null;
|
|
507
710
|
if ((alias.typeParameters?.params.length ?? 0) > 0) {
|
|
508
|
-
const
|
|
509
|
-
const
|
|
510
|
-
return
|
|
711
|
+
const substitutions = aliasSubstitution(alias, unwrapped, new Map);
|
|
712
|
+
const resolved = substitutions === null ? null : classifyAliasBroadTarget(alias.typeAnnotation, environment, substitutions, new Set([name]));
|
|
713
|
+
return resolved?.kind === "open dictionary" ? { kind: "generic container" } : null;
|
|
511
714
|
}
|
|
512
715
|
const substitutions = aliasSubstitution(alias, unwrapped, new Map);
|
|
513
716
|
if (substitutions === null)
|
|
@@ -631,14 +834,7 @@ function functionParameterBindingName(parameter, sourceCode) {
|
|
|
631
834
|
return annotationStart === undefined ? sourceText : sourceText.slice(0, annotationStart - parameter.start).trimEnd();
|
|
632
835
|
}
|
|
633
836
|
|
|
634
|
-
// vendor/anti-slop/src/
|
|
635
|
-
function unwrapExpression(expression) {
|
|
636
|
-
let current = expression;
|
|
637
|
-
while (current.type === "ParenthesizedExpression" || current.type === "TSAsExpression" || current.type === "TSSatisfiesExpression" || current.type === "TSTypeAssertion" || current.type === "TSNonNullExpression") {
|
|
638
|
-
current = current.expression;
|
|
639
|
-
}
|
|
640
|
-
return current;
|
|
641
|
-
}
|
|
837
|
+
// vendor/anti-slop/src/shared/scope.ts
|
|
642
838
|
function resolveVariable(sourceCode, identifier) {
|
|
643
839
|
let scope = sourceCode.getScope(identifier);
|
|
644
840
|
while (scope !== null) {
|
|
@@ -649,6 +845,15 @@ function resolveVariable(sourceCode, identifier) {
|
|
|
649
845
|
}
|
|
650
846
|
return null;
|
|
651
847
|
}
|
|
848
|
+
|
|
849
|
+
// vendor/anti-slop/src/rules/no-known-value-widening.ts
|
|
850
|
+
function unwrapExpression(expression) {
|
|
851
|
+
let current = expression;
|
|
852
|
+
while (current.type === "ParenthesizedExpression" || current.type === "TSAsExpression" || current.type === "TSSatisfiesExpression" || current.type === "TSTypeAssertion" || current.type === "TSNonNullExpression") {
|
|
853
|
+
current = current.expression;
|
|
854
|
+
}
|
|
855
|
+
return current;
|
|
856
|
+
}
|
|
652
857
|
function variableDeclarator(variable) {
|
|
653
858
|
if (variable.defs.length !== 1)
|
|
654
859
|
return null;
|
|
@@ -801,7 +1006,7 @@ function isDictionaryAccumulatorTarget(destination) {
|
|
|
801
1006
|
function hasParentAssertion(node) {
|
|
802
1007
|
return node.parent?.type === "TSAsExpression" || node.parent?.type === "TSTypeAssertion";
|
|
803
1008
|
}
|
|
804
|
-
var noKnownValueWideningRule =
|
|
1009
|
+
var noKnownValueWideningRule = defineRule5({
|
|
805
1010
|
meta: {
|
|
806
1011
|
type: "problem",
|
|
807
1012
|
docs: {
|
|
@@ -914,18 +1119,8 @@ var noKnownValueWideningRule = defineRule3({
|
|
|
914
1119
|
});
|
|
915
1120
|
|
|
916
1121
|
// vendor/anti-slop/src/rules/no-module-mocking.ts
|
|
917
|
-
import { defineRule as
|
|
1122
|
+
import { defineRule as defineRule6 } from "@oxlint/plugins";
|
|
918
1123
|
var moduleMockMethods = new Set(["doMock", "mock", "unstable_mockModule"]);
|
|
919
|
-
function resolveVariable2(sourceCode, identifier) {
|
|
920
|
-
let scope = sourceCode.getScope(identifier);
|
|
921
|
-
while (scope !== null) {
|
|
922
|
-
const variable = scope.set.get(identifier.name);
|
|
923
|
-
if (variable !== undefined)
|
|
924
|
-
return variable;
|
|
925
|
-
scope = scope.upper;
|
|
926
|
-
}
|
|
927
|
-
return null;
|
|
928
|
-
}
|
|
929
1124
|
function importedName(node) {
|
|
930
1125
|
if (node.type !== "ImportSpecifier")
|
|
931
1126
|
return null;
|
|
@@ -937,7 +1132,7 @@ function isTestFrameworkObject(sourceCode, expression) {
|
|
|
937
1132
|
if ((expression.name === "vi" || expression.name === "jest") && sourceCode.isGlobalReference(expression)) {
|
|
938
1133
|
return true;
|
|
939
1134
|
}
|
|
940
|
-
const variable =
|
|
1135
|
+
const variable = resolveVariable(sourceCode, expression);
|
|
941
1136
|
if (variable === null || variable.defs.length === 0) {
|
|
942
1137
|
return expression.name === "vi" || expression.name === "jest";
|
|
943
1138
|
}
|
|
@@ -959,7 +1154,7 @@ function moduleMockCall(sourceCode, callee) {
|
|
|
959
1154
|
const method = callee.computed ? property.type === "Literal" && (property.value === "doMock" || property.value === "mock" || property.value === "unstable_mockModule") ? property.value : null : property.type === "Identifier" ? property.name : null;
|
|
960
1155
|
return method !== null && moduleMockMethods.has(method);
|
|
961
1156
|
}
|
|
962
|
-
var noModuleMockingRule =
|
|
1157
|
+
var noModuleMockingRule = defineRule6({
|
|
963
1158
|
meta: {
|
|
964
1159
|
type: "problem",
|
|
965
1160
|
docs: {
|
|
@@ -983,8 +1178,8 @@ var noModuleMockingRule = defineRule4({
|
|
|
983
1178
|
});
|
|
984
1179
|
|
|
985
1180
|
// vendor/anti-slop/src/rules/no-object-parameters.ts
|
|
986
|
-
import { defineRule as
|
|
987
|
-
var noObjectParametersRule =
|
|
1181
|
+
import { defineRule as defineRule7 } from "@oxlint/plugins";
|
|
1182
|
+
var noObjectParametersRule = defineRule7({
|
|
988
1183
|
meta: {
|
|
989
1184
|
type: "problem",
|
|
990
1185
|
docs: {
|
|
@@ -1037,25 +1232,15 @@ var noObjectParametersRule = defineRule5({
|
|
|
1037
1232
|
});
|
|
1038
1233
|
|
|
1039
1234
|
// vendor/anti-slop/src/rules/no-reflect-apply.ts
|
|
1040
|
-
import { defineRule as
|
|
1235
|
+
import { defineRule as defineRule8 } from "@oxlint/plugins";
|
|
1041
1236
|
|
|
1042
1237
|
// vendor/anti-slop/src/shared/reflect-method.ts
|
|
1043
|
-
function resolveVariable3(sourceCode, identifier) {
|
|
1044
|
-
let scope = sourceCode.getScope(identifier);
|
|
1045
|
-
while (scope !== null) {
|
|
1046
|
-
const variable = scope.set.get(identifier.name);
|
|
1047
|
-
if (variable !== undefined)
|
|
1048
|
-
return variable;
|
|
1049
|
-
scope = scope.upper;
|
|
1050
|
-
}
|
|
1051
|
-
return null;
|
|
1052
|
-
}
|
|
1053
1238
|
function isGlobalReflect(sourceCode, expression) {
|
|
1054
1239
|
if (expression.type !== "Identifier" || expression.name !== "Reflect")
|
|
1055
1240
|
return false;
|
|
1056
1241
|
if (sourceCode.isGlobalReference(expression))
|
|
1057
1242
|
return true;
|
|
1058
|
-
const variable =
|
|
1243
|
+
const variable = resolveVariable(sourceCode, expression);
|
|
1059
1244
|
return variable === null || variable.defs.length === 0;
|
|
1060
1245
|
}
|
|
1061
1246
|
function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
|
|
@@ -1068,7 +1253,7 @@ function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
|
|
|
1068
1253
|
}
|
|
1069
1254
|
|
|
1070
1255
|
// vendor/anti-slop/src/rules/no-reflect-apply.ts
|
|
1071
|
-
var noReflectApplyRule =
|
|
1256
|
+
var noReflectApplyRule = defineRule8({
|
|
1072
1257
|
meta: {
|
|
1073
1258
|
type: "problem",
|
|
1074
1259
|
docs: {
|
|
@@ -1092,8 +1277,8 @@ var noReflectApplyRule = defineRule6({
|
|
|
1092
1277
|
});
|
|
1093
1278
|
|
|
1094
1279
|
// vendor/anti-slop/src/rules/no-reflect-get.ts
|
|
1095
|
-
import { defineRule as
|
|
1096
|
-
var noReflectGetRule =
|
|
1280
|
+
import { defineRule as defineRule9 } from "@oxlint/plugins";
|
|
1281
|
+
var noReflectGetRule = defineRule9({
|
|
1097
1282
|
meta: {
|
|
1098
1283
|
type: "problem",
|
|
1099
1284
|
docs: {
|
|
@@ -1117,7 +1302,7 @@ var noReflectGetRule = defineRule7({
|
|
|
1117
1302
|
});
|
|
1118
1303
|
|
|
1119
1304
|
// vendor/anti-slop/src/rules/no-runtime-typeof.ts
|
|
1120
|
-
import { defineRule as
|
|
1305
|
+
import { defineRule as defineRule10 } from "@oxlint/plugins";
|
|
1121
1306
|
function isRuntimeFunction(node) {
|
|
1122
1307
|
return node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression";
|
|
1123
1308
|
}
|
|
@@ -1140,7 +1325,7 @@ function isExistenceProbe(node) {
|
|
|
1140
1325
|
const other = parent.left === node ? parent.right : parent.left;
|
|
1141
1326
|
return other.type === "Literal" && other.value === "undefined";
|
|
1142
1327
|
}
|
|
1143
|
-
var noRuntimeTypeofRule =
|
|
1328
|
+
var noRuntimeTypeofRule = defineRule10({
|
|
1144
1329
|
meta: {
|
|
1145
1330
|
type: "problem",
|
|
1146
1331
|
docs: {
|
|
@@ -1174,7 +1359,7 @@ var noRuntimeTypeofRule = defineRule8({
|
|
|
1174
1359
|
});
|
|
1175
1360
|
|
|
1176
1361
|
// vendor/anti-slop/src/rules/no-shape-in-symbol-names.ts
|
|
1177
|
-
import { defineRule as
|
|
1362
|
+
import { defineRule as defineRule11 } from "@oxlint/plugins";
|
|
1178
1363
|
var FORBIDDEN_SYMBOL_NAME = "shape";
|
|
1179
1364
|
function containsForbiddenSymbolName(name) {
|
|
1180
1365
|
return name.toLowerCase().includes(FORBIDDEN_SYMBOL_NAME);
|
|
@@ -1185,7 +1370,7 @@ function isBorrowedMemberName(node) {
|
|
|
1185
1370
|
return false;
|
|
1186
1371
|
return parent.property === node && parent.computed === false;
|
|
1187
1372
|
}
|
|
1188
|
-
var noForbiddenTermInSymbolNamesRule =
|
|
1373
|
+
var noForbiddenTermInSymbolNamesRule = defineRule11({
|
|
1189
1374
|
meta: {
|
|
1190
1375
|
type: "problem",
|
|
1191
1376
|
docs: {
|
|
@@ -1214,12 +1399,12 @@ var noForbiddenTermInSymbolNamesRule = defineRule9({
|
|
|
1214
1399
|
});
|
|
1215
1400
|
|
|
1216
1401
|
// vendor/anti-slop/src/rules/no-unknown-parameters.ts
|
|
1217
|
-
import { defineRule as
|
|
1402
|
+
import { defineRule as defineRule12 } from "@oxlint/plugins";
|
|
1218
1403
|
function isTypePredicateSubject(owner, parameterName) {
|
|
1219
1404
|
const predicate = owner.returnType?.typeAnnotation;
|
|
1220
1405
|
return predicate?.type === "TSTypePredicate" && predicate.parameterName.type === "Identifier" && predicate.parameterName.name === parameterName;
|
|
1221
1406
|
}
|
|
1222
|
-
var noUnknownParametersRule =
|
|
1407
|
+
var noUnknownParametersRule = defineRule12({
|
|
1223
1408
|
meta: {
|
|
1224
1409
|
type: "problem",
|
|
1225
1410
|
docs: {
|
|
@@ -1263,8 +1448,8 @@ var noUnknownParametersRule = defineRule10({
|
|
|
1263
1448
|
});
|
|
1264
1449
|
|
|
1265
1450
|
// vendor/anti-slop/src/rules/no-unknown-returns.ts
|
|
1266
|
-
import { defineRule as
|
|
1267
|
-
var noUnknownReturnsRule =
|
|
1451
|
+
import { defineRule as defineRule13 } from "@oxlint/plugins";
|
|
1452
|
+
var noUnknownReturnsRule = defineRule13({
|
|
1268
1453
|
meta: {
|
|
1269
1454
|
type: "problem",
|
|
1270
1455
|
docs: {
|
|
@@ -1317,8 +1502,8 @@ var noUnknownReturnsRule = defineRule11({
|
|
|
1317
1502
|
});
|
|
1318
1503
|
|
|
1319
1504
|
// vendor/anti-slop/src/rules/no-unknown-type-aliases.ts
|
|
1320
|
-
import { defineRule as
|
|
1321
|
-
var noUnknownTypeAliasesRule =
|
|
1505
|
+
import { defineRule as defineRule14 } from "@oxlint/plugins";
|
|
1506
|
+
var noUnknownTypeAliasesRule = defineRule14({
|
|
1322
1507
|
meta: {
|
|
1323
1508
|
type: "problem",
|
|
1324
1509
|
docs: {
|
|
@@ -1356,7 +1541,7 @@ var noUnknownTypeAliasesRule = defineRule12({
|
|
|
1356
1541
|
});
|
|
1357
1542
|
|
|
1358
1543
|
// vendor/anti-slop/src/rules/no-unsafe-dictionary-type.ts
|
|
1359
|
-
import { defineRule as
|
|
1544
|
+
import { defineRule as defineRule15 } from "@oxlint/plugins";
|
|
1360
1545
|
var typeNodeKinds = new Set([
|
|
1361
1546
|
"JSDocNonNullableType",
|
|
1362
1547
|
"JSDocNullableType",
|
|
@@ -1443,7 +1628,7 @@ function shouldReportType(node, environment) {
|
|
|
1443
1628
|
}
|
|
1444
1629
|
return true;
|
|
1445
1630
|
}
|
|
1446
|
-
var noUnsafeDictionaryTypeRule =
|
|
1631
|
+
var noUnsafeDictionaryTypeRule = defineRule15({
|
|
1447
1632
|
meta: {
|
|
1448
1633
|
type: "problem",
|
|
1449
1634
|
docs: {
|
|
@@ -1485,7 +1670,7 @@ var noUnsafeDictionaryTypeRule = defineRule13({
|
|
|
1485
1670
|
});
|
|
1486
1671
|
|
|
1487
1672
|
// vendor/anti-slop/src/rules/no-widen-then-assert.ts
|
|
1488
|
-
import { defineRule as
|
|
1673
|
+
import { defineRule as defineRule16 } from "@oxlint/plugins";
|
|
1489
1674
|
var functionBoundaryTypes = new Set([
|
|
1490
1675
|
"ArrowFunctionExpression",
|
|
1491
1676
|
"FunctionDeclaration",
|
|
@@ -1681,7 +1866,7 @@ function assertionIsNarrower(sourceText, broadKind, evidence, assertedType) {
|
|
|
1681
1866
|
return isDefinitelyObjectType(assertedType);
|
|
1682
1867
|
return isDefinitelyNarrowerRecordType(assertedType);
|
|
1683
1868
|
}
|
|
1684
|
-
var noWidenThenAssertRule =
|
|
1869
|
+
var noWidenThenAssertRule = defineRule16({
|
|
1685
1870
|
meta: {
|
|
1686
1871
|
type: "problem",
|
|
1687
1872
|
docs: {
|
|
@@ -1720,8 +1905,530 @@ var noWidenThenAssertRule = defineRule14({
|
|
|
1720
1905
|
}
|
|
1721
1906
|
});
|
|
1722
1907
|
|
|
1908
|
+
// vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-ast.ts
|
|
1909
|
+
var LINEBREAKS = new Set([`\r
|
|
1910
|
+
`, "\r", `
|
|
1911
|
+
`, "\u2028", "\u2029"]);
|
|
1912
|
+
var isClosingBraceToken = (token) => token.type === "Punctuator" && token.value === "}";
|
|
1913
|
+
var isSemicolonToken = (token) => token.type === "Punctuator" && token.value === ";";
|
|
1914
|
+
var isNotSemicolonToken = (token) => !isSemicolonToken(token);
|
|
1915
|
+
var isTokenOnSameLine = (left, right) => left.loc.end.line === right.loc.start.line;
|
|
1916
|
+
var isFunction = (node) => node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression";
|
|
1917
|
+
var isSingleLine = (node) => node.loc.start.line === node.loc.end.line;
|
|
1918
|
+
var skipChainExpression = (node) => node.type === "ChainExpression" ? node.expression : node;
|
|
1919
|
+
var isTopLevelExpressionStatement = (node) => node.type === "ExpressionStatement" && (node.parent.type === "Program" || node.parent.type === "BlockStatement" && isFunction(node.parent.parent));
|
|
1920
|
+
function isParenthesized(node, sourceCode) {
|
|
1921
|
+
const before = sourceCode.getTokenBefore(node);
|
|
1922
|
+
const after = sourceCode.getTokenAfter(node);
|
|
1923
|
+
return before?.value === "(" && after?.value === ")";
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
// vendor/anti-slop/src/vendor/eslint-stylistic/padding-line-between-statements.ts
|
|
1927
|
+
var CJS_EXPORT = /^(?:module\s*\.\s*)?exports(?:\s*\.|\s*\[|$)/u;
|
|
1928
|
+
var CJS_IMPORT = /^require\(/u;
|
|
1929
|
+
var LT = `[${Array.from(LINEBREAKS).join("")}]`;
|
|
1930
|
+
var PADDING_LINE_SEQUENCE = new RegExp(String.raw`^(\s*?${LT})\s*${LT}(\s*;?)$`, "u");
|
|
1931
|
+
function isSelectorOption(option) {
|
|
1932
|
+
return typeof option === "object" && !Array.isArray(option);
|
|
1933
|
+
}
|
|
1934
|
+
function newKeywordTester(type, keyword) {
|
|
1935
|
+
return {
|
|
1936
|
+
test(node, sourceCode) {
|
|
1937
|
+
const isSameKeyword = sourceCode.getFirstToken(node)?.value === keyword;
|
|
1938
|
+
const isSameType = Array.isArray(type) ? type.includes(node.type) : type === node.type;
|
|
1939
|
+
return isSameKeyword && isSameType;
|
|
1940
|
+
}
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
function newNodeTypeTester(type) {
|
|
1944
|
+
return {
|
|
1945
|
+
test: (node) => node.type === type
|
|
1946
|
+
};
|
|
1947
|
+
}
|
|
1948
|
+
function isIIFEStatement(node) {
|
|
1949
|
+
if (node.type === "ExpressionStatement") {
|
|
1950
|
+
let expression = skipChainExpression(node.expression);
|
|
1951
|
+
if (expression.type === "UnaryExpression")
|
|
1952
|
+
expression = skipChainExpression(expression.argument);
|
|
1953
|
+
if (expression.type === "CallExpression") {
|
|
1954
|
+
let node = expression.callee;
|
|
1955
|
+
while (node.type === "SequenceExpression") {
|
|
1956
|
+
const lastExpression = node.expressions.at(-1);
|
|
1957
|
+
if (lastExpression === undefined)
|
|
1958
|
+
throw new Error("Padding rule invariant: sequence expression is empty");
|
|
1959
|
+
node = lastExpression;
|
|
1960
|
+
}
|
|
1961
|
+
return isFunction(node);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
return false;
|
|
1965
|
+
}
|
|
1966
|
+
function isCJSRequire(node) {
|
|
1967
|
+
if (node.type === "VariableDeclaration") {
|
|
1968
|
+
const declaration = node.declarations[0];
|
|
1969
|
+
if (declaration?.init) {
|
|
1970
|
+
let call = declaration?.init;
|
|
1971
|
+
while (call.type === "MemberExpression")
|
|
1972
|
+
call = call.object;
|
|
1973
|
+
if (call.type === "CallExpression" && call.callee.type === "Identifier") {
|
|
1974
|
+
return call.callee.name === "require";
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
return false;
|
|
1979
|
+
}
|
|
1980
|
+
function isBlockLikeStatement(node, sourceCode) {
|
|
1981
|
+
if (node.type === "DoWhileStatement" && node.body.type === "BlockStatement") {
|
|
1982
|
+
return true;
|
|
1983
|
+
}
|
|
1984
|
+
if (isIIFEStatement(node))
|
|
1985
|
+
return true;
|
|
1986
|
+
const lastToken = sourceCode.getLastToken(node, isNotSemicolonToken);
|
|
1987
|
+
const belongingNode = lastToken && isClosingBraceToken(lastToken) ? sourceCode.getNodeByRangeIndex(lastToken.range[0]) : null;
|
|
1988
|
+
return !!belongingNode && (belongingNode.type === "BlockStatement" || belongingNode.type === "SwitchStatement");
|
|
1989
|
+
}
|
|
1990
|
+
function isDirective(node, sourceCode) {
|
|
1991
|
+
return isTopLevelExpressionStatement(node) && node.expression.type === "Literal" && typeof node.expression.value === "string" && !isParenthesized(node.expression, sourceCode);
|
|
1992
|
+
}
|
|
1993
|
+
function isDirectivePrologue(node, sourceCode) {
|
|
1994
|
+
if (isDirective(node, sourceCode) && node.parent && "body" in node.parent && Array.isArray(node.parent.body)) {
|
|
1995
|
+
for (const sibling of node.parent.body) {
|
|
1996
|
+
if (sibling === node)
|
|
1997
|
+
break;
|
|
1998
|
+
if (!isDirective(sibling, sourceCode))
|
|
1999
|
+
return false;
|
|
2000
|
+
}
|
|
2001
|
+
return true;
|
|
2002
|
+
}
|
|
2003
|
+
return false;
|
|
2004
|
+
}
|
|
2005
|
+
function isCJSExport(node) {
|
|
2006
|
+
if (node.type === "ExpressionStatement") {
|
|
2007
|
+
const expression = node.expression;
|
|
2008
|
+
if (expression.type === "AssignmentExpression") {
|
|
2009
|
+
let left = expression.left;
|
|
2010
|
+
if (left.type === "MemberExpression") {
|
|
2011
|
+
while (left.object.type === "MemberExpression")
|
|
2012
|
+
left = left.object;
|
|
2013
|
+
return left.object.type === "Identifier" && (left.object.name === "exports" || left.object.name === "module" && left.property.type === "Identifier" && left.property.name === "exports");
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
return false;
|
|
2018
|
+
}
|
|
2019
|
+
function isExpression(node, sourceCode) {
|
|
2020
|
+
return node.type === "ExpressionStatement" && !isDirectivePrologue(node, sourceCode);
|
|
2021
|
+
}
|
|
2022
|
+
function getActualLastToken(node, sourceCode) {
|
|
2023
|
+
const semiToken = sourceCode.getLastToken(node);
|
|
2024
|
+
const prevToken = sourceCode.getTokenBefore(semiToken);
|
|
2025
|
+
const nextToken = sourceCode.getTokenAfter(semiToken);
|
|
2026
|
+
const isSemicolonLessStyle = prevToken && nextToken && prevToken.range[0] >= node.range[0] && isSemicolonToken(semiToken) && !isTokenOnSameLine(prevToken, semiToken) && isTokenOnSameLine(semiToken, nextToken);
|
|
2027
|
+
return isSemicolonLessStyle ? prevToken : semiToken;
|
|
2028
|
+
}
|
|
2029
|
+
function replacerToRemovePaddingLines(_, trailingSpaces, indentSpaces) {
|
|
2030
|
+
return trailingSpaces + indentSpaces;
|
|
2031
|
+
}
|
|
2032
|
+
function getReportLoc(node, sourceCode) {
|
|
2033
|
+
if (isSingleLine(node))
|
|
2034
|
+
return node.loc;
|
|
2035
|
+
const line = node.loc.start.line;
|
|
2036
|
+
const sourceLine = sourceCode.lines[line - 1];
|
|
2037
|
+
if (sourceLine === undefined)
|
|
2038
|
+
throw new Error("Padding rule invariant: statement source line is missing");
|
|
2039
|
+
return {
|
|
2040
|
+
start: node.loc.start,
|
|
2041
|
+
end: {
|
|
2042
|
+
line,
|
|
2043
|
+
column: sourceLine.length
|
|
2044
|
+
}
|
|
2045
|
+
};
|
|
2046
|
+
}
|
|
2047
|
+
function verifyForAny() {}
|
|
2048
|
+
function verifyForNever(context, _, nextNode, paddingLines) {
|
|
2049
|
+
if (paddingLines.length === 0)
|
|
2050
|
+
return;
|
|
2051
|
+
context.report({
|
|
2052
|
+
node: nextNode,
|
|
2053
|
+
messageId: "unexpectedBlankLine",
|
|
2054
|
+
loc: getReportLoc(nextNode, context.sourceCode),
|
|
2055
|
+
fix(fixer) {
|
|
2056
|
+
if (paddingLines.length >= 2)
|
|
2057
|
+
return null;
|
|
2058
|
+
const paddingPair = paddingLines[0];
|
|
2059
|
+
if (paddingPair === undefined)
|
|
2060
|
+
throw new Error("Padding rule invariant: reported padding pair is missing");
|
|
2061
|
+
const [prevToken, nextToken] = paddingPair;
|
|
2062
|
+
const start = prevToken.range[1];
|
|
2063
|
+
const end = nextToken.range[0];
|
|
2064
|
+
const text = context.sourceCode.text.slice(start, end).replace(PADDING_LINE_SEQUENCE, replacerToRemovePaddingLines);
|
|
2065
|
+
return fixer.replaceTextRange([start, end], text);
|
|
2066
|
+
}
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
function verifyForAlways(context, prevNode, nextNode, paddingLines) {
|
|
2070
|
+
if (paddingLines.length > 0)
|
|
2071
|
+
return;
|
|
2072
|
+
context.report({
|
|
2073
|
+
node: nextNode,
|
|
2074
|
+
messageId: "expectedBlankLine",
|
|
2075
|
+
loc: getReportLoc(nextNode, context.sourceCode),
|
|
2076
|
+
fix(fixer) {
|
|
2077
|
+
const sourceCode = context.sourceCode;
|
|
2078
|
+
let prevToken = getActualLastToken(prevNode, sourceCode);
|
|
2079
|
+
const nextToken = sourceCode.getFirstTokenBetween(prevToken, nextNode, {
|
|
2080
|
+
includeComments: true,
|
|
2081
|
+
filter(token) {
|
|
2082
|
+
if (isTokenOnSameLine(prevToken, token)) {
|
|
2083
|
+
prevToken = token;
|
|
2084
|
+
return false;
|
|
2085
|
+
}
|
|
2086
|
+
return true;
|
|
2087
|
+
}
|
|
2088
|
+
}) || nextNode;
|
|
2089
|
+
const insertText = isTokenOnSameLine(prevToken, nextToken) ? `
|
|
2090
|
+
|
|
2091
|
+
` : `
|
|
2092
|
+
`;
|
|
2093
|
+
return fixer.insertTextAfter(prevToken, insertText);
|
|
2094
|
+
}
|
|
2095
|
+
});
|
|
2096
|
+
}
|
|
2097
|
+
var PaddingTypes = {
|
|
2098
|
+
any: { verify: verifyForAny },
|
|
2099
|
+
never: { verify: verifyForNever },
|
|
2100
|
+
always: { verify: verifyForAlways }
|
|
2101
|
+
};
|
|
2102
|
+
var MaybeMultilineStatementType = {
|
|
2103
|
+
"block-like": { test: isBlockLikeStatement },
|
|
2104
|
+
expression: { test: isExpression },
|
|
2105
|
+
return: newKeywordTester("ReturnStatement", "return"),
|
|
2106
|
+
export: newKeywordTester([
|
|
2107
|
+
"ExportAllDeclaration",
|
|
2108
|
+
"ExportDefaultDeclaration",
|
|
2109
|
+
"ExportNamedDeclaration"
|
|
2110
|
+
], "export"),
|
|
2111
|
+
var: newKeywordTester("VariableDeclaration", "var"),
|
|
2112
|
+
let: newKeywordTester("VariableDeclaration", "let"),
|
|
2113
|
+
const: newKeywordTester("VariableDeclaration", "const"),
|
|
2114
|
+
using: {
|
|
2115
|
+
test: (node) => node.type === "VariableDeclaration" && (node.kind === "using" || node.kind === "await using")
|
|
2116
|
+
},
|
|
2117
|
+
type: newKeywordTester("TSTypeAliasDeclaration", "type")
|
|
2118
|
+
};
|
|
2119
|
+
var StatementTypes = {
|
|
2120
|
+
"*": { test: () => true },
|
|
2121
|
+
exports: { test: isCJSExport },
|
|
2122
|
+
require: { test: isCJSRequire },
|
|
2123
|
+
directive: { test: isDirectivePrologue },
|
|
2124
|
+
iife: { test: isIIFEStatement },
|
|
2125
|
+
block: newNodeTypeTester("BlockStatement"),
|
|
2126
|
+
empty: newNodeTypeTester("EmptyStatement"),
|
|
2127
|
+
function: newNodeTypeTester("FunctionDeclaration"),
|
|
2128
|
+
"ts-method": newNodeTypeTester("TSMethodSignature"),
|
|
2129
|
+
break: newKeywordTester("BreakStatement", "break"),
|
|
2130
|
+
case: newKeywordTester("SwitchCase", "case"),
|
|
2131
|
+
class: newKeywordTester("ClassDeclaration", "class"),
|
|
2132
|
+
continue: newKeywordTester("ContinueStatement", "continue"),
|
|
2133
|
+
debugger: newKeywordTester("DebuggerStatement", "debugger"),
|
|
2134
|
+
default: newKeywordTester(["SwitchCase", "ExportDefaultDeclaration"], "default"),
|
|
2135
|
+
do: newKeywordTester("DoWhileStatement", "do"),
|
|
2136
|
+
for: newKeywordTester([
|
|
2137
|
+
"ForStatement",
|
|
2138
|
+
"ForInStatement",
|
|
2139
|
+
"ForOfStatement"
|
|
2140
|
+
], "for"),
|
|
2141
|
+
if: newKeywordTester("IfStatement", "if"),
|
|
2142
|
+
import: newKeywordTester("ImportDeclaration", "import"),
|
|
2143
|
+
switch: newKeywordTester("SwitchStatement", "switch"),
|
|
2144
|
+
throw: newKeywordTester("ThrowStatement", "throw"),
|
|
2145
|
+
try: newKeywordTester("TryStatement", "try"),
|
|
2146
|
+
while: newKeywordTester(["WhileStatement", "DoWhileStatement"], "while"),
|
|
2147
|
+
with: newKeywordTester("WithStatement", "with"),
|
|
2148
|
+
"cjs-export": {
|
|
2149
|
+
test: (node, sourceCode) => node.type === "ExpressionStatement" && node.expression.type === "AssignmentExpression" && CJS_EXPORT.test(sourceCode.getText(node.expression.left))
|
|
2150
|
+
},
|
|
2151
|
+
"cjs-import": {
|
|
2152
|
+
test: (node, sourceCode) => node.type === "VariableDeclaration" && node.declarations.length > 0 && node.declarations[0]?.init != null && CJS_IMPORT.test(sourceCode.getText(node.declarations[0].init))
|
|
2153
|
+
},
|
|
2154
|
+
enum: newKeywordTester("TSEnumDeclaration", "enum"),
|
|
2155
|
+
interface: newKeywordTester("TSInterfaceDeclaration", "interface"),
|
|
2156
|
+
"function-overload": newNodeTypeTester("TSDeclareFunction"),
|
|
2157
|
+
...Object.fromEntries(Object.entries(MaybeMultilineStatementType).flatMap(([key, value]) => [
|
|
2158
|
+
[key, value],
|
|
2159
|
+
[
|
|
2160
|
+
`singleline-${key}`,
|
|
2161
|
+
{
|
|
2162
|
+
...value,
|
|
2163
|
+
test: (node, sourceCode) => value.test(node, sourceCode) && isSingleLine(node)
|
|
2164
|
+
}
|
|
2165
|
+
],
|
|
2166
|
+
[
|
|
2167
|
+
`multiline-${key}`,
|
|
2168
|
+
{
|
|
2169
|
+
...value,
|
|
2170
|
+
test: (node, sourceCode) => value.test(node, sourceCode) && !isSingleLine(node)
|
|
2171
|
+
}
|
|
2172
|
+
]
|
|
2173
|
+
]))
|
|
2174
|
+
};
|
|
2175
|
+
function createPaddingLineRule(options) {
|
|
2176
|
+
return {
|
|
2177
|
+
meta: {
|
|
2178
|
+
type: "layout",
|
|
2179
|
+
docs: {
|
|
2180
|
+
description: "Require or disallow padding lines between statements"
|
|
2181
|
+
},
|
|
2182
|
+
fixable: "whitespace",
|
|
2183
|
+
hasSuggestions: false,
|
|
2184
|
+
schema: {
|
|
2185
|
+
$defs: {
|
|
2186
|
+
paddingType: {
|
|
2187
|
+
type: "string",
|
|
2188
|
+
enum: Object.keys(PaddingTypes)
|
|
2189
|
+
},
|
|
2190
|
+
statementType: {
|
|
2191
|
+
type: "string",
|
|
2192
|
+
enum: Object.keys(StatementTypes)
|
|
2193
|
+
},
|
|
2194
|
+
selectorOption: {
|
|
2195
|
+
type: "object",
|
|
2196
|
+
properties: {
|
|
2197
|
+
selector: {
|
|
2198
|
+
type: "string"
|
|
2199
|
+
},
|
|
2200
|
+
lineMode: {
|
|
2201
|
+
type: "string",
|
|
2202
|
+
enum: ["any", "singleline", "multiline"]
|
|
2203
|
+
}
|
|
2204
|
+
},
|
|
2205
|
+
required: ["selector"],
|
|
2206
|
+
additionalProperties: false
|
|
2207
|
+
},
|
|
2208
|
+
statementMatcher: {
|
|
2209
|
+
anyOf: [
|
|
2210
|
+
{ $ref: "#/$defs/statementType" },
|
|
2211
|
+
{ $ref: "#/$defs/selectorOption" }
|
|
2212
|
+
]
|
|
2213
|
+
},
|
|
2214
|
+
statementOption: {
|
|
2215
|
+
anyOf: [
|
|
2216
|
+
{ $ref: "#/$defs/statementMatcher" },
|
|
2217
|
+
{
|
|
2218
|
+
type: "array",
|
|
2219
|
+
items: { $ref: "#/$defs/statementMatcher" },
|
|
2220
|
+
minItems: 1,
|
|
2221
|
+
uniqueItems: true,
|
|
2222
|
+
additionalItems: false
|
|
2223
|
+
}
|
|
2224
|
+
]
|
|
2225
|
+
}
|
|
2226
|
+
},
|
|
2227
|
+
type: "array",
|
|
2228
|
+
additionalItems: false,
|
|
2229
|
+
items: {
|
|
2230
|
+
type: "object",
|
|
2231
|
+
properties: {
|
|
2232
|
+
blankLine: { $ref: "#/$defs/paddingType" },
|
|
2233
|
+
prev: { $ref: "#/$defs/statementOption" },
|
|
2234
|
+
next: { $ref: "#/$defs/statementOption" }
|
|
2235
|
+
},
|
|
2236
|
+
additionalProperties: false,
|
|
2237
|
+
required: ["blankLine", "prev", "next"]
|
|
2238
|
+
}
|
|
2239
|
+
},
|
|
2240
|
+
messages: {
|
|
2241
|
+
unexpectedBlankLine: "Unexpected blank line before this statement.",
|
|
2242
|
+
expectedBlankLine: "Expected blank line before this statement."
|
|
2243
|
+
}
|
|
2244
|
+
},
|
|
2245
|
+
create(context) {
|
|
2246
|
+
const sourceCode = context.sourceCode;
|
|
2247
|
+
const selectorMatchedNodes = new Map;
|
|
2248
|
+
const pendingPairs = [];
|
|
2249
|
+
function collectSelectorOption(option) {
|
|
2250
|
+
if (Array.isArray(option)) {
|
|
2251
|
+
for (const item of option)
|
|
2252
|
+
collectSelectorOption(item);
|
|
2253
|
+
return;
|
|
2254
|
+
}
|
|
2255
|
+
if (!isSelectorOption(option))
|
|
2256
|
+
return;
|
|
2257
|
+
selectorMatchedNodes.set(option.selector, new Set);
|
|
2258
|
+
}
|
|
2259
|
+
for (const configure of options) {
|
|
2260
|
+
collectSelectorOption(configure.prev);
|
|
2261
|
+
collectSelectorOption(configure.next);
|
|
2262
|
+
}
|
|
2263
|
+
let scopeInfo = null;
|
|
2264
|
+
function enterScope() {
|
|
2265
|
+
scopeInfo = {
|
|
2266
|
+
upper: scopeInfo,
|
|
2267
|
+
prevNode: null
|
|
2268
|
+
};
|
|
2269
|
+
}
|
|
2270
|
+
function exitScope() {
|
|
2271
|
+
if (scopeInfo)
|
|
2272
|
+
scopeInfo = scopeInfo.upper;
|
|
2273
|
+
}
|
|
2274
|
+
function match(node, type) {
|
|
2275
|
+
let innerStatementNode = node;
|
|
2276
|
+
while (innerStatementNode.type === "LabeledStatement")
|
|
2277
|
+
innerStatementNode = innerStatementNode.body;
|
|
2278
|
+
if (Array.isArray(type))
|
|
2279
|
+
return type.some(match.bind(null, innerStatementNode));
|
|
2280
|
+
if (isSelectorOption(type)) {
|
|
2281
|
+
const matchedNodes = selectorMatchedNodes.get(type.selector);
|
|
2282
|
+
if (!matchedNodes?.has(innerStatementNode))
|
|
2283
|
+
return false;
|
|
2284
|
+
const lineMode = type.lineMode;
|
|
2285
|
+
if (lineMode === "singleline")
|
|
2286
|
+
return isSingleLine(innerStatementNode);
|
|
2287
|
+
else if (lineMode === "multiline")
|
|
2288
|
+
return !isSingleLine(innerStatementNode);
|
|
2289
|
+
return true;
|
|
2290
|
+
} else {
|
|
2291
|
+
const statementType = StatementTypes[type];
|
|
2292
|
+
if (statementType === undefined)
|
|
2293
|
+
throw new Error(`Padding rule invariant: unsupported statement type ${type}`);
|
|
2294
|
+
return statementType.test(innerStatementNode, sourceCode);
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
function getPaddingType(prevNode, nextNode) {
|
|
2298
|
+
for (let i = options.length - 1;i >= 0; --i) {
|
|
2299
|
+
const configure = options[i];
|
|
2300
|
+
if (configure === undefined)
|
|
2301
|
+
throw new Error("Padding rule invariant: configuration entry is missing");
|
|
2302
|
+
if (match(prevNode, configure.prev) && match(nextNode, configure.next)) {
|
|
2303
|
+
return PaddingTypes[configure.blankLine];
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
return PaddingTypes.any;
|
|
2307
|
+
}
|
|
2308
|
+
function getPaddingLineSequences(prevNode, nextNode) {
|
|
2309
|
+
const pairs = [];
|
|
2310
|
+
let prevToken = getActualLastToken(prevNode, sourceCode);
|
|
2311
|
+
if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) {
|
|
2312
|
+
do {
|
|
2313
|
+
const token = sourceCode.getTokenAfter(prevToken, {
|
|
2314
|
+
includeComments: true
|
|
2315
|
+
});
|
|
2316
|
+
if (token.loc.start.line - prevToken.loc.end.line >= 2)
|
|
2317
|
+
pairs.push([prevToken, token]);
|
|
2318
|
+
prevToken = token;
|
|
2319
|
+
} while (prevToken.range[0] < nextNode.range[0]);
|
|
2320
|
+
}
|
|
2321
|
+
return pairs;
|
|
2322
|
+
}
|
|
2323
|
+
function verify(node) {
|
|
2324
|
+
if (!node.parent || ![
|
|
2325
|
+
"BlockStatement",
|
|
2326
|
+
"Program",
|
|
2327
|
+
"StaticBlock",
|
|
2328
|
+
"SwitchCase",
|
|
2329
|
+
"SwitchStatement",
|
|
2330
|
+
"TSInterfaceBody",
|
|
2331
|
+
"TSModuleBlock",
|
|
2332
|
+
"TSTypeLiteral"
|
|
2333
|
+
].includes(node.parent.type)) {
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
const prevNode = scopeInfo.prevNode;
|
|
2337
|
+
if (prevNode)
|
|
2338
|
+
pendingPairs.push({ prevNode, nextNode: node });
|
|
2339
|
+
scopeInfo.prevNode = node;
|
|
2340
|
+
}
|
|
2341
|
+
function verifyPendingPairs() {
|
|
2342
|
+
for (const { prevNode, nextNode } of pendingPairs) {
|
|
2343
|
+
const type = getPaddingType(prevNode, nextNode);
|
|
2344
|
+
const paddingLines = getPaddingLineSequences(prevNode, nextNode);
|
|
2345
|
+
type.verify(context, prevNode, nextNode, paddingLines);
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
function verifyThenEnterScope(node) {
|
|
2349
|
+
verify(node);
|
|
2350
|
+
enterScope();
|
|
2351
|
+
}
|
|
2352
|
+
const selectorMatchListeners = Object.fromEntries(Array.from(selectorMatchedNodes.keys(), (selector) => [
|
|
2353
|
+
selector,
|
|
2354
|
+
(node) => {
|
|
2355
|
+
selectorMatchedNodes.get(selector)?.add(node);
|
|
2356
|
+
}
|
|
2357
|
+
]));
|
|
2358
|
+
return {
|
|
2359
|
+
Program: enterScope,
|
|
2360
|
+
"Program:exit": () => {
|
|
2361
|
+
verifyPendingPairs();
|
|
2362
|
+
exitScope();
|
|
2363
|
+
},
|
|
2364
|
+
BlockStatement: enterScope,
|
|
2365
|
+
"BlockStatement:exit": exitScope,
|
|
2366
|
+
SwitchStatement: enterScope,
|
|
2367
|
+
"SwitchStatement:exit": exitScope,
|
|
2368
|
+
SwitchCase: verifyThenEnterScope,
|
|
2369
|
+
"SwitchCase:exit": exitScope,
|
|
2370
|
+
StaticBlock: enterScope,
|
|
2371
|
+
"StaticBlock:exit": exitScope,
|
|
2372
|
+
TSInterfaceBody: enterScope,
|
|
2373
|
+
"TSInterfaceBody:exit": exitScope,
|
|
2374
|
+
TSModuleBlock: enterScope,
|
|
2375
|
+
"TSModuleBlock:exit": exitScope,
|
|
2376
|
+
TSTypeLiteral: enterScope,
|
|
2377
|
+
"TSTypeLiteral:exit": exitScope,
|
|
2378
|
+
TSDeclareFunction: verifyThenEnterScope,
|
|
2379
|
+
"TSDeclareFunction:exit": exitScope,
|
|
2380
|
+
TSMethodSignature: verifyThenEnterScope,
|
|
2381
|
+
"TSMethodSignature:exit": exitScope,
|
|
2382
|
+
":statement": verify,
|
|
2383
|
+
...selectorMatchListeners
|
|
2384
|
+
};
|
|
2385
|
+
}
|
|
2386
|
+
};
|
|
2387
|
+
}
|
|
2388
|
+
|
|
2389
|
+
// vendor/anti-slop/src/rules/require-readable-spacing.ts
|
|
2390
|
+
var paddingRule = createPaddingLineRule([
|
|
2391
|
+
{ blankLine: "always", prev: "import", next: "*" },
|
|
2392
|
+
{ blankLine: "always", prev: "*", next: { selector: "Program > :not(ImportDeclaration)" } },
|
|
2393
|
+
{ blankLine: "always", prev: { selector: "Program > :not(ImportDeclaration)" }, next: "*" },
|
|
2394
|
+
{ blankLine: "always", prev: "*", next: ["function", "class", "interface", "type"] },
|
|
2395
|
+
{ blankLine: "always", prev: ["function", "class", "interface", "type"], next: "*" },
|
|
2396
|
+
{
|
|
2397
|
+
blankLine: "always",
|
|
2398
|
+
prev: "*",
|
|
2399
|
+
next: ["multiline-const", "multiline-let", "multiline-var", "multiline-using"]
|
|
2400
|
+
},
|
|
2401
|
+
{
|
|
2402
|
+
blankLine: "always",
|
|
2403
|
+
prev: ["multiline-const", "multiline-let", "multiline-var", "multiline-using"],
|
|
2404
|
+
next: "*"
|
|
2405
|
+
},
|
|
2406
|
+
{ blankLine: "always", prev: "*", next: ["return", "if", "switch", "try", "for", "while", "do"] },
|
|
2407
|
+
{ blankLine: "always", prev: "block-like", next: "*" },
|
|
2408
|
+
{ blankLine: "any", prev: "import", next: "import" },
|
|
2409
|
+
{
|
|
2410
|
+
blankLine: "any",
|
|
2411
|
+
prev: {
|
|
2412
|
+
selector: ':matches(TSDeclareFunction, ExportNamedDeclaration[declaration.type="TSDeclareFunction"])'
|
|
2413
|
+
},
|
|
2414
|
+
next: {
|
|
2415
|
+
selector: ':matches(TSDeclareFunction, FunctionDeclaration, ExportNamedDeclaration[declaration.type="TSDeclareFunction"], ExportNamedDeclaration[declaration.type="FunctionDeclaration"])'
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
]);
|
|
2419
|
+
var requireReadableSpacingRule = {
|
|
2420
|
+
...paddingRule,
|
|
2421
|
+
meta: {
|
|
2422
|
+
...paddingRule.meta,
|
|
2423
|
+
docs: {
|
|
2424
|
+
description: "Require readable spacing between declarations and logical statement groups."
|
|
2425
|
+
},
|
|
2426
|
+
schema: []
|
|
2427
|
+
}
|
|
2428
|
+
};
|
|
2429
|
+
|
|
1723
2430
|
// vendor/anti-slop/src/rules/require-safety-comment-for-type-assertion.ts
|
|
1724
|
-
import { defineRule as
|
|
2431
|
+
import { defineRule as defineRule17 } from "@oxlint/plugins";
|
|
1725
2432
|
var DEFAULT_SAFETY_MARKERS = ["SAFETY"];
|
|
1726
2433
|
var commentOwnerKinds = new Set([
|
|
1727
2434
|
"ExpressionStatement",
|
|
@@ -1764,7 +2471,7 @@ function hasSafetyComment(sourceCode, node, pattern) {
|
|
|
1764
2471
|
current = current.parent;
|
|
1765
2472
|
}
|
|
1766
2473
|
}
|
|
1767
|
-
var requireSafetyCommentForTypeAssertionRule =
|
|
2474
|
+
var requireSafetyCommentForTypeAssertionRule = defineRule17({
|
|
1768
2475
|
meta: {
|
|
1769
2476
|
type: "problem",
|
|
1770
2477
|
docs: {
|
|
@@ -1817,6 +2524,8 @@ var requireSafetyCommentForTypeAssertionRule = defineRule15({
|
|
|
1817
2524
|
var antiSlopPlugin = eslintCompatPlugin({
|
|
1818
2525
|
meta: { name: "anti-slop" },
|
|
1819
2526
|
rules: {
|
|
2527
|
+
"no-array-filter-map": noArrayFilterMapRule,
|
|
2528
|
+
"no-reduce-accumulator-copy": noReduceAccumulatorCopyRule,
|
|
1820
2529
|
"no-chained-type-assertions": noChainedTypeAssertionsRule,
|
|
1821
2530
|
"no-conditional-empty-object-spread": noConditionalEmptyObjectSpreadRule,
|
|
1822
2531
|
"no-known-value-widening": noKnownValueWideningRule,
|
|
@@ -1831,6 +2540,7 @@ var antiSlopPlugin = eslintCompatPlugin({
|
|
|
1831
2540
|
"no-unknown-returns": noUnknownReturnsRule,
|
|
1832
2541
|
"no-unknown-type-aliases": noUnknownTypeAliasesRule,
|
|
1833
2542
|
"no-widen-then-assert": noWidenThenAssertRule,
|
|
2543
|
+
"require-readable-spacing": requireReadableSpacingRule,
|
|
1834
2544
|
"require-safety-comment-for-type-assertion": requireSafetyCommentForTypeAssertionRule
|
|
1835
2545
|
}
|
|
1836
2546
|
});
|
|
@@ -1839,7 +2549,7 @@ var src_default = antiSlopPlugin;
|
|
|
1839
2549
|
import { eslintCompatPlugin as eslintCompatPlugin2 } from "@oxlint/plugins";
|
|
1840
2550
|
|
|
1841
2551
|
// src/generic/rules/prefer-event-parameter-type.ts
|
|
1842
|
-
import { defineRule as
|
|
2552
|
+
import { defineRule as defineRule18 } from "@oxlint/plugins";
|
|
1843
2553
|
function nearestEnclosingFunction(node) {
|
|
1844
2554
|
let current = node.parent;
|
|
1845
2555
|
while (current) {
|
|
@@ -1866,7 +2576,7 @@ function assertedEventParameter(node) {
|
|
|
1866
2576
|
property
|
|
1867
2577
|
};
|
|
1868
2578
|
}
|
|
1869
|
-
var preferEventParameterTypeRule =
|
|
2579
|
+
var preferEventParameterTypeRule = defineRule18({
|
|
1870
2580
|
meta: {
|
|
1871
2581
|
type: "suggestion",
|
|
1872
2582
|
docs: {
|
|
@@ -1903,11 +2613,6 @@ var timmoPlugin = eslintCompatPlugin2({
|
|
|
1903
2613
|
});
|
|
1904
2614
|
var generic_default = timmoPlugin;
|
|
1905
2615
|
|
|
1906
|
-
// node_modules/oxlint/dist/index.js
|
|
1907
|
-
function defineConfig(config) {
|
|
1908
|
-
return config;
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
2616
|
// src/configs/enable-plugin-rules.ts
|
|
1912
2617
|
function enablePluginRules(namespace, plugin) {
|
|
1913
2618
|
return Object.fromEntries(Object.keys(plugin.rules).sort().map((rule) => [`${namespace}/${rule}`, "error"]));
|
|
@@ -1933,8 +2638,8 @@ var recommended_default = recommended;
|
|
|
1933
2638
|
import { eslintCompatPlugin as eslintCompatPlugin3 } from "@oxlint/plugins";
|
|
1934
2639
|
|
|
1935
2640
|
// src/effect/rules/no-try-catch-in-effect-generators.ts
|
|
1936
|
-
import { defineRule as
|
|
1937
|
-
function
|
|
2641
|
+
import { defineRule as defineRule19 } from "@oxlint/plugins";
|
|
2642
|
+
function resolveVariable2(sourceCode, identifier) {
|
|
1938
2643
|
let scope = sourceCode.getScope(identifier);
|
|
1939
2644
|
while (scope) {
|
|
1940
2645
|
const variable = scope.set.get(identifier.name);
|
|
@@ -1960,7 +2665,7 @@ function staticMemberName(node) {
|
|
|
1960
2665
|
return node.property.type === "Identifier" ? node.property.name : null;
|
|
1961
2666
|
}
|
|
1962
2667
|
function isEffectImport(sourceCode, identifier, namespace) {
|
|
1963
|
-
const variable =
|
|
2668
|
+
const variable = resolveVariable2(sourceCode, identifier);
|
|
1964
2669
|
return variable?.defs.some((definition) => {
|
|
1965
2670
|
if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration" || definition.parent.source.value !== "effect") {
|
|
1966
2671
|
return false;
|
|
@@ -1999,7 +2704,7 @@ function isRecognisedEffectGenerator(sourceCode, owner) {
|
|
|
1999
2704
|
const factoryCall = parent.callee;
|
|
2000
2705
|
return factoryCall.type === "CallExpression" && isEffectMethod(sourceCode, factoryCall.callee, "fn");
|
|
2001
2706
|
}
|
|
2002
|
-
var noTryCatchInEffectGeneratorsRule =
|
|
2707
|
+
var noTryCatchInEffectGeneratorsRule = defineRule19({
|
|
2003
2708
|
meta: {
|
|
2004
2709
|
type: "problem",
|
|
2005
2710
|
docs: {
|
|
@@ -2036,8 +2741,149 @@ var effect_default = timmoEffectPlugin;
|
|
|
2036
2741
|
// vendor/anti-slop/src/effect/index.ts
|
|
2037
2742
|
import { eslintCompatPlugin as eslintCompatPlugin4 } from "@oxlint/plugins";
|
|
2038
2743
|
|
|
2744
|
+
// vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts
|
|
2745
|
+
import { defineRule as defineRule20 } from "@oxlint/plugins";
|
|
2746
|
+
|
|
2747
|
+
// vendor/anti-slop/src/effect/shared/tagged-values.ts
|
|
2748
|
+
var equalityOperators = new Set(["==", "===", "!=", "!=="]);
|
|
2749
|
+
var broadEffectCatchMethods = new Set(["catch", "catchAll", "catchIf"]);
|
|
2750
|
+
var isStringLiteral = (node) => node?.type === "Literal" && typeof node.value === "string";
|
|
2751
|
+
var isTagMember = (node) => node?.type === "MemberExpression" && (!node.computed && node.property.type === "Identifier" && node.property.name === "_tag" || node.computed && isStringLiteral(node.property) && node.property.value === "_tag");
|
|
2752
|
+
var tagMemberFromComparison = (node) => {
|
|
2753
|
+
if (!equalityOperators.has(node.operator))
|
|
2754
|
+
return;
|
|
2755
|
+
if (isTagMember(node.left) && isStringLiteral(node.right))
|
|
2756
|
+
return node.left;
|
|
2757
|
+
if (isTagMember(node.right) && isStringLiteral(node.left))
|
|
2758
|
+
return node.right;
|
|
2759
|
+
return;
|
|
2760
|
+
};
|
|
2761
|
+
var isBroadEffectCatchCall = (node) => node?.type === "CallExpression" && node.callee.type === "MemberExpression" && node.callee.object.type === "Identifier" && node.callee.object.name === "Effect" && !node.callee.computed && node.callee.property.type === "Identifier" && broadEffectCatchMethods.has(node.callee.property.name);
|
|
2762
|
+
var isInsideBroadEffectHandler = (node) => {
|
|
2763
|
+
let current = node.parent;
|
|
2764
|
+
while (current !== null && current !== undefined) {
|
|
2765
|
+
if (current.type === "ArrowFunctionExpression" || current.type === "FunctionExpression") {
|
|
2766
|
+
return isBroadEffectCatchCall(current.parent) && current.parent.arguments.includes(current);
|
|
2767
|
+
}
|
|
2768
|
+
current = current.parent;
|
|
2769
|
+
}
|
|
2770
|
+
return false;
|
|
2771
|
+
};
|
|
2772
|
+
var isReasonTagMember = (node) => node.object.type === "MemberExpression" && (!node.object.computed && node.object.property.type === "Identifier" && node.object.property.name === "reason" || node.object.computed && isStringLiteral(node.object.property) && node.object.property.value === "reason");
|
|
2773
|
+
var propertyName = (property) => {
|
|
2774
|
+
if (!property.computed && property.key.type === "Identifier") {
|
|
2775
|
+
return property.key.name;
|
|
2776
|
+
}
|
|
2777
|
+
if (property.key.type === "Literal" && typeof property.key.value === "string") {
|
|
2778
|
+
return property.key.value;
|
|
2779
|
+
}
|
|
2780
|
+
return;
|
|
2781
|
+
};
|
|
2782
|
+
var isMatchPatternObject = (node) => {
|
|
2783
|
+
const call = node.parent;
|
|
2784
|
+
if (call?.type !== "CallExpression" || !call.arguments.includes(node)) {
|
|
2785
|
+
return false;
|
|
2786
|
+
}
|
|
2787
|
+
const callee = call.callee;
|
|
2788
|
+
return callee.type === "MemberExpression" && callee.object.type === "Identifier" && callee.object.name === "Match" && !callee.computed && callee.property.type === "Identifier" && (callee.property.name === "when" || callee.property.name === "not");
|
|
2789
|
+
};
|
|
2790
|
+
|
|
2791
|
+
// vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts
|
|
2792
|
+
var noManualEffectErrorTagRule = defineRule20({
|
|
2793
|
+
meta: {
|
|
2794
|
+
type: "problem",
|
|
2795
|
+
docs: {
|
|
2796
|
+
description: "Use Effect tagged error handlers instead of manually branching on `_tag` in a catch handler."
|
|
2797
|
+
},
|
|
2798
|
+
messages: {
|
|
2799
|
+
tag: "Use Effect.catchTag or Effect.catchTags instead of manually discriminating a tagged error in a broad Effect catch handler.",
|
|
2800
|
+
reason: "Use Effect.catchReason or Effect.catchReasons instead of manually discriminating a tagged `reason` in a broad Effect catch handler."
|
|
2801
|
+
}
|
|
2802
|
+
},
|
|
2803
|
+
createOnce(context) {
|
|
2804
|
+
return {
|
|
2805
|
+
BinaryExpression(node) {
|
|
2806
|
+
const tagMember = tagMemberFromComparison(node);
|
|
2807
|
+
if (tagMember === undefined || !isInsideBroadEffectHandler(node)) {
|
|
2808
|
+
return;
|
|
2809
|
+
}
|
|
2810
|
+
context.report({
|
|
2811
|
+
node,
|
|
2812
|
+
messageId: isReasonTagMember(tagMember) ? "reason" : "tag"
|
|
2813
|
+
});
|
|
2814
|
+
},
|
|
2815
|
+
SwitchStatement(node) {
|
|
2816
|
+
if (!isTagMember(node.discriminant) || !isInsideBroadEffectHandler(node)) {
|
|
2817
|
+
return;
|
|
2818
|
+
}
|
|
2819
|
+
context.report({
|
|
2820
|
+
node,
|
|
2821
|
+
messageId: isReasonTagMember(node.discriminant) ? "reason" : "tag"
|
|
2822
|
+
});
|
|
2823
|
+
}
|
|
2824
|
+
};
|
|
2825
|
+
}
|
|
2826
|
+
});
|
|
2827
|
+
|
|
2828
|
+
// vendor/anti-slop/src/effect/rules/no-manual-tag-comparison.ts
|
|
2829
|
+
import { defineRule as defineRule21 } from "@oxlint/plugins";
|
|
2830
|
+
var noManualTagComparisonRule = defineRule21({
|
|
2831
|
+
meta: {
|
|
2832
|
+
type: "problem",
|
|
2833
|
+
docs: {
|
|
2834
|
+
description: "Use Effect Match or Predicate helpers instead of manually branching on `_tag`."
|
|
2835
|
+
},
|
|
2836
|
+
messages: {
|
|
2837
|
+
manualComparison: "Use Match.tag/Match.tags for tagged-value branching, or Predicate.isTagged for a simple reusable predicate.",
|
|
2838
|
+
manualSwitch: "Use Match.value(value).pipe(Match.tag/Match.tags/Match.tagsExhaustive) or the tagged enum `$match` helper instead of switching on `_tag`."
|
|
2839
|
+
}
|
|
2840
|
+
},
|
|
2841
|
+
createOnce(context) {
|
|
2842
|
+
return {
|
|
2843
|
+
BinaryExpression(node) {
|
|
2844
|
+
if (tagMemberFromComparison(node) === undefined || isInsideBroadEffectHandler(node)) {
|
|
2845
|
+
return;
|
|
2846
|
+
}
|
|
2847
|
+
context.report({ node, messageId: "manualComparison" });
|
|
2848
|
+
},
|
|
2849
|
+
SwitchStatement(node) {
|
|
2850
|
+
if (!isTagMember(node.discriminant) || isInsideBroadEffectHandler(node)) {
|
|
2851
|
+
return;
|
|
2852
|
+
}
|
|
2853
|
+
context.report({ node, messageId: "manualSwitch" });
|
|
2854
|
+
}
|
|
2855
|
+
};
|
|
2856
|
+
}
|
|
2857
|
+
});
|
|
2858
|
+
|
|
2859
|
+
// vendor/anti-slop/src/effect/rules/no-manual-tagged-construction.ts
|
|
2860
|
+
import { defineRule as defineRule22 } from "@oxlint/plugins";
|
|
2861
|
+
var noManualTaggedConstructionRule = defineRule22({
|
|
2862
|
+
meta: {
|
|
2863
|
+
type: "problem",
|
|
2864
|
+
docs: {
|
|
2865
|
+
description: "Construct tagged values with their existing Effect constructor instead of writing `_tag` manually."
|
|
2866
|
+
},
|
|
2867
|
+
messages: {
|
|
2868
|
+
manualConstruction: "Use the existing Schema tagged `.make`, tagged class/error constructor, or Data.taggedEnum variant constructor instead of writing a literal `_tag` object."
|
|
2869
|
+
}
|
|
2870
|
+
},
|
|
2871
|
+
createOnce(context) {
|
|
2872
|
+
return {
|
|
2873
|
+
ObjectExpression(node) {
|
|
2874
|
+
if (isMatchPatternObject(node))
|
|
2875
|
+
return;
|
|
2876
|
+
const tag = node.properties.find((property) => property.type === "Property" && propertyName(property) === "_tag" && isStringLiteral(property.value));
|
|
2877
|
+
if (tag !== undefined) {
|
|
2878
|
+
context.report({ node: tag, messageId: "manualConstruction" });
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
};
|
|
2882
|
+
}
|
|
2883
|
+
});
|
|
2884
|
+
|
|
2039
2885
|
// vendor/anti-slop/src/effect/rules/no-service-constructor-imports.ts
|
|
2040
|
-
import { defineRule as
|
|
2886
|
+
import { defineRule as defineRule23 } from "@oxlint/plugins";
|
|
2041
2887
|
var SERVICE_CONSTRUCTOR_NAME = /^make[A-Z]/u;
|
|
2042
2888
|
var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/u;
|
|
2043
2889
|
function isProjectLocalImport(source) {
|
|
@@ -2048,7 +2894,7 @@ function getImportedName(specifier) {
|
|
|
2048
2894
|
return specifier.imported.name;
|
|
2049
2895
|
return specifier.imported.value;
|
|
2050
2896
|
}
|
|
2051
|
-
var noServiceConstructorImportsRule =
|
|
2897
|
+
var noServiceConstructorImportsRule = defineRule23({
|
|
2052
2898
|
meta: {
|
|
2053
2899
|
type: "problem",
|
|
2054
2900
|
docs: {
|
|
@@ -2067,13 +2913,13 @@ var noServiceConstructorImportsRule = defineRule18({
|
|
|
2067
2913
|
for (const specifier of node.specifiers) {
|
|
2068
2914
|
if (specifier.type !== "ImportSpecifier")
|
|
2069
2915
|
continue;
|
|
2070
|
-
const
|
|
2071
|
-
if (!SERVICE_CONSTRUCTOR_NAME.test(
|
|
2916
|
+
const importedName = getImportedName(specifier);
|
|
2917
|
+
if (!SERVICE_CONSTRUCTOR_NAME.test(importedName))
|
|
2072
2918
|
continue;
|
|
2073
2919
|
context.report({
|
|
2074
2920
|
node: specifier,
|
|
2075
2921
|
messageId: "serviceConstructorImport",
|
|
2076
|
-
data: { name:
|
|
2922
|
+
data: { name: importedName }
|
|
2077
2923
|
});
|
|
2078
2924
|
}
|
|
2079
2925
|
}
|
|
@@ -2081,11 +2927,63 @@ var noServiceConstructorImportsRule = defineRule18({
|
|
|
2081
2927
|
}
|
|
2082
2928
|
});
|
|
2083
2929
|
|
|
2930
|
+
// vendor/anti-slop/src/effect/rules/prefer-effect-match.ts
|
|
2931
|
+
import { defineRule as defineRule24 } from "@oxlint/plugins";
|
|
2932
|
+
var equalityOperators2 = new Set(["==", "===", "!=", "!=="]);
|
|
2933
|
+
var preferEffectMatchRule = defineRule24({
|
|
2934
|
+
meta: {
|
|
2935
|
+
type: "problem",
|
|
2936
|
+
docs: {
|
|
2937
|
+
description: "Use Match from Effect for chained literal ternaries over the same value."
|
|
2938
|
+
},
|
|
2939
|
+
messages: {
|
|
2940
|
+
preferMatch: "Use Match from Effect instead of a chained literal ternary."
|
|
2941
|
+
}
|
|
2942
|
+
},
|
|
2943
|
+
createOnce(context) {
|
|
2944
|
+
const isLiteral = (node) => node.type === "Literal" || node.type === "TemplateLiteral" && node.expressions.length === 0;
|
|
2945
|
+
const comparedValue = (node) => {
|
|
2946
|
+
if (node.type !== "BinaryExpression" || !equalityOperators2.has(node.operator)) {
|
|
2947
|
+
return;
|
|
2948
|
+
}
|
|
2949
|
+
if (isLiteral(node.left))
|
|
2950
|
+
return context.sourceCode.getText(node.right);
|
|
2951
|
+
if (isLiteral(node.right))
|
|
2952
|
+
return context.sourceCode.getText(node.left);
|
|
2953
|
+
return;
|
|
2954
|
+
};
|
|
2955
|
+
return {
|
|
2956
|
+
ConditionalExpression(node) {
|
|
2957
|
+
if (node.parent?.type === "ConditionalExpression")
|
|
2958
|
+
return;
|
|
2959
|
+
const value = comparedValue(node.test);
|
|
2960
|
+
if (value === undefined)
|
|
2961
|
+
return;
|
|
2962
|
+
let alternate = node.alternate;
|
|
2963
|
+
let literalChecks = 1;
|
|
2964
|
+
while (alternate.type === "ConditionalExpression") {
|
|
2965
|
+
if (comparedValue(alternate.test) !== value)
|
|
2966
|
+
return;
|
|
2967
|
+
literalChecks += 1;
|
|
2968
|
+
alternate = alternate.alternate;
|
|
2969
|
+
}
|
|
2970
|
+
if (literalChecks > 1) {
|
|
2971
|
+
context.report({ node, messageId: "preferMatch" });
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
};
|
|
2975
|
+
}
|
|
2976
|
+
});
|
|
2977
|
+
|
|
2084
2978
|
// vendor/anti-slop/src/effect/index.ts
|
|
2085
2979
|
var antiSlopEffectPlugin = eslintCompatPlugin4({
|
|
2086
2980
|
meta: { name: "anti-slop-effect" },
|
|
2087
2981
|
rules: {
|
|
2088
|
-
"no-
|
|
2982
|
+
"no-manual-effect-error-tag": noManualEffectErrorTagRule,
|
|
2983
|
+
"no-manual-tag-comparison": noManualTagComparisonRule,
|
|
2984
|
+
"no-manual-tagged-construction": noManualTaggedConstructionRule,
|
|
2985
|
+
"no-service-constructor-imports": noServiceConstructorImportsRule,
|
|
2986
|
+
"prefer-effect-match": preferEffectMatchRule
|
|
2089
2987
|
}
|
|
2090
2988
|
});
|
|
2091
2989
|
var effect_default2 = antiSlopEffectPlugin;
|
|
@@ -2106,9 +3004,6 @@ var recommendedEffect = defineConfig({
|
|
|
2106
3004
|
});
|
|
2107
3005
|
var recommended_effect_default = recommendedEffect;
|
|
2108
3006
|
|
|
2109
|
-
// src/cli.ts
|
|
2110
|
-
import { resolve as resolve2 } from "node:path";
|
|
2111
|
-
|
|
2112
3007
|
// src/install/copy.ts
|
|
2113
3008
|
import { cp, mkdir, readdir, rm } from "node:fs/promises";
|
|
2114
3009
|
import { dirname, join, relative, resolve, sep } from "node:path";
|