@timmo001/oxlint-rules 0.3.0 → 0.3.1
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/dist/cli.js +247 -50
- package/dist/configs/recommended-effect.js +417 -220
- package/dist/configs/recommended.js +237 -40
- package/dist/upstream/anti-slop.js +230 -33
- package/package.json +5 -5
- package/vendor/anti-slop/src/index.ts +4 -0
- package/vendor/anti-slop/src/rules/no-array-filter-map.ts +28 -0
- package/vendor/anti-slop/src/rules/no-reduce-accumulator-copy.ts +109 -0
- package/vendor/anti-slop/src/shared/array-method.ts +94 -0
|
@@ -1,8 +1,373 @@
|
|
|
1
|
-
//
|
|
1
|
+
// node_modules/oxlint/dist/index.js
|
|
2
|
+
function defineConfig(config) {
|
|
3
|
+
return config;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// src/effect/index.ts
|
|
2
7
|
import { eslintCompatPlugin } from "@oxlint/plugins";
|
|
3
8
|
|
|
4
|
-
//
|
|
9
|
+
// src/effect/rules/no-try-catch-in-effect-generators.ts
|
|
5
10
|
import { defineRule } from "@oxlint/plugins";
|
|
11
|
+
function resolveVariable(sourceCode, identifier) {
|
|
12
|
+
let scope = sourceCode.getScope(identifier);
|
|
13
|
+
while (scope) {
|
|
14
|
+
const variable = scope.set.get(identifier.name);
|
|
15
|
+
if (variable)
|
|
16
|
+
return variable;
|
|
17
|
+
scope = scope.upper;
|
|
18
|
+
}
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
function nearestEnclosingFunction(node) {
|
|
22
|
+
let current = node.parent;
|
|
23
|
+
while (current) {
|
|
24
|
+
if (current.type === "FunctionDeclaration" || current.type === "FunctionExpression" || current.type === "ArrowFunctionExpression") {
|
|
25
|
+
return current;
|
|
26
|
+
}
|
|
27
|
+
current = current.parent;
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function staticMemberName(node) {
|
|
32
|
+
if (node.type !== "MemberExpression" || node.computed)
|
|
33
|
+
return null;
|
|
34
|
+
return node.property.type === "Identifier" ? node.property.name : null;
|
|
35
|
+
}
|
|
36
|
+
function isEffectImport(sourceCode, identifier, namespace) {
|
|
37
|
+
const variable = resolveVariable(sourceCode, identifier);
|
|
38
|
+
return variable?.defs.some((definition) => {
|
|
39
|
+
if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration" || definition.parent.source.value !== "effect") {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
if (namespace)
|
|
43
|
+
return definition.node.type === "ImportNamespaceSpecifier";
|
|
44
|
+
if (definition.node.type !== "ImportSpecifier")
|
|
45
|
+
return false;
|
|
46
|
+
const imported = definition.node.imported;
|
|
47
|
+
return (imported.type === "Identifier" ? imported.name : imported.value) === "Effect";
|
|
48
|
+
}) ?? false;
|
|
49
|
+
}
|
|
50
|
+
function isEffectMethod(sourceCode, node, method) {
|
|
51
|
+
if (staticMemberName(node) !== method || node.type !== "MemberExpression") {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const object = node.object;
|
|
55
|
+
if (object.type === "Identifier") {
|
|
56
|
+
return isEffectImport(sourceCode, object, false);
|
|
57
|
+
}
|
|
58
|
+
if (staticMemberName(object) !== "Effect" || object.type !== "MemberExpression" || object.object.type !== "Identifier") {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
return isEffectImport(sourceCode, object.object, true);
|
|
62
|
+
}
|
|
63
|
+
function isDirectArgument(owner, call) {
|
|
64
|
+
return call.arguments.some((argument) => argument === owner);
|
|
65
|
+
}
|
|
66
|
+
function isRecognisedEffectGenerator(sourceCode, owner) {
|
|
67
|
+
const parent = owner.parent;
|
|
68
|
+
if (parent.type !== "CallExpression" || !isDirectArgument(owner, parent)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
if (isEffectMethod(sourceCode, parent.callee, "gen"))
|
|
72
|
+
return true;
|
|
73
|
+
const factoryCall = parent.callee;
|
|
74
|
+
return factoryCall.type === "CallExpression" && isEffectMethod(sourceCode, factoryCall.callee, "fn");
|
|
75
|
+
}
|
|
76
|
+
var noTryCatchInEffectGeneratorsRule = defineRule({
|
|
77
|
+
meta: {
|
|
78
|
+
type: "problem",
|
|
79
|
+
docs: {
|
|
80
|
+
description: "Disallow synchronous try/catch owned by recognised Effect generator callbacks."
|
|
81
|
+
},
|
|
82
|
+
messages: {
|
|
83
|
+
useEffectErrorChannel: "Keep expected failures in the Effect error channel. Use Effect.try for synchronous throwing work, Effect.tryPromise for asynchronous throwing work, Effect-returning schema APIs for decoding, and Effect recovery combinators for recovery."
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
create(context) {
|
|
87
|
+
return {
|
|
88
|
+
TryStatement(node) {
|
|
89
|
+
if (!node.handler)
|
|
90
|
+
return;
|
|
91
|
+
const owner = nearestEnclosingFunction(node);
|
|
92
|
+
if (!owner?.generator || !isRecognisedEffectGenerator(context.sourceCode, owner)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
context.report({ node, messageId: "useEffectErrorChannel" });
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// src/effect/index.ts
|
|
102
|
+
var timmoEffectPlugin = eslintCompatPlugin({
|
|
103
|
+
meta: { name: "timmo-effect" },
|
|
104
|
+
rules: {
|
|
105
|
+
"no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
var effect_default = timmoEffectPlugin;
|
|
109
|
+
|
|
110
|
+
// vendor/anti-slop/src/effect/index.ts
|
|
111
|
+
import { eslintCompatPlugin as eslintCompatPlugin2 } from "@oxlint/plugins";
|
|
112
|
+
|
|
113
|
+
// vendor/anti-slop/src/effect/rules/no-service-constructor-imports.ts
|
|
114
|
+
import { defineRule as defineRule2 } from "@oxlint/plugins";
|
|
115
|
+
var SERVICE_CONSTRUCTOR_NAME = /^make[A-Z]/u;
|
|
116
|
+
var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/u;
|
|
117
|
+
function isProjectLocalImport(source) {
|
|
118
|
+
return source.startsWith("./") || source.startsWith("../");
|
|
119
|
+
}
|
|
120
|
+
function getImportedName(specifier) {
|
|
121
|
+
if (specifier.imported.type === "Identifier")
|
|
122
|
+
return specifier.imported.name;
|
|
123
|
+
return specifier.imported.value;
|
|
124
|
+
}
|
|
125
|
+
var noServiceConstructorImportsRule = defineRule2({
|
|
126
|
+
meta: {
|
|
127
|
+
type: "problem",
|
|
128
|
+
docs: {
|
|
129
|
+
description: "Disallow project-local make<CapabilityName> imports outside test and spec files."
|
|
130
|
+
},
|
|
131
|
+
messages: {
|
|
132
|
+
serviceConstructorImport: 'Do not import Effect service constructor "{{name}}" into runtime code. Import the owning Layer, yield the contextual service, and allow its requirements to propagate to the composition root.'
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
create(context) {
|
|
136
|
+
const isTestFile = TEST_FILE.test(context.filename.replaceAll("\\", "/"));
|
|
137
|
+
return {
|
|
138
|
+
ImportDeclaration(node) {
|
|
139
|
+
if (isTestFile || !isProjectLocalImport(node.source.value))
|
|
140
|
+
return;
|
|
141
|
+
for (const specifier of node.specifiers) {
|
|
142
|
+
if (specifier.type !== "ImportSpecifier")
|
|
143
|
+
continue;
|
|
144
|
+
const importedName = getImportedName(specifier);
|
|
145
|
+
if (!SERVICE_CONSTRUCTOR_NAME.test(importedName))
|
|
146
|
+
continue;
|
|
147
|
+
context.report({
|
|
148
|
+
node: specifier,
|
|
149
|
+
messageId: "serviceConstructorImport",
|
|
150
|
+
data: { name: importedName }
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// vendor/anti-slop/src/effect/index.ts
|
|
159
|
+
var antiSlopEffectPlugin = eslintCompatPlugin2({
|
|
160
|
+
meta: { name: "anti-slop-effect" },
|
|
161
|
+
rules: {
|
|
162
|
+
"no-service-constructor-imports": noServiceConstructorImportsRule
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
var effect_default2 = antiSlopEffectPlugin;
|
|
166
|
+
// src/configs/enable-plugin-rules.ts
|
|
167
|
+
function enablePluginRules(namespace, plugin) {
|
|
168
|
+
return Object.fromEntries(Object.keys(plugin.rules).sort().map((rule) => [`${namespace}/${rule}`, "error"]));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// vendor/anti-slop/src/index.ts
|
|
172
|
+
import { eslintCompatPlugin as eslintCompatPlugin3 } from "@oxlint/plugins";
|
|
173
|
+
|
|
174
|
+
// vendor/anti-slop/src/rules/no-array-filter-map.ts
|
|
175
|
+
import { defineRule as defineRule3 } from "@oxlint/plugins";
|
|
176
|
+
|
|
177
|
+
// vendor/anti-slop/src/shared/array-method.ts
|
|
178
|
+
function unwrapArrayExpression(node) {
|
|
179
|
+
while (node.type === "ParenthesizedExpression" || node.type === "ChainExpression" || node.type === "TSAsExpression" || node.type === "TSTypeAssertion" || node.type === "TSNonNullExpression" || node.type === "TSSatisfiesExpression") {
|
|
180
|
+
node = node.expression;
|
|
181
|
+
}
|
|
182
|
+
return node;
|
|
183
|
+
}
|
|
184
|
+
function resolveArrayBinding(sourceCode, node) {
|
|
185
|
+
node = unwrapArrayExpression(node);
|
|
186
|
+
if (node.type !== "Identifier")
|
|
187
|
+
return null;
|
|
188
|
+
let scope = sourceCode.getScope(node);
|
|
189
|
+
while (scope !== null) {
|
|
190
|
+
const variable = scope.set.get(node.name);
|
|
191
|
+
if (variable !== undefined)
|
|
192
|
+
return variable;
|
|
193
|
+
scope = scope.upper;
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
function arrayMethodTarget(node) {
|
|
198
|
+
node = unwrapArrayExpression(node);
|
|
199
|
+
if (node.type !== "MemberExpression")
|
|
200
|
+
return null;
|
|
201
|
+
const property = node.property;
|
|
202
|
+
if (!node.computed && property.type === "Identifier") {
|
|
203
|
+
return { name: property.name, object: node.object };
|
|
204
|
+
}
|
|
205
|
+
if (node.computed && property.type === "Literal" && typeof property.value === "string") {
|
|
206
|
+
return { name: property.value, object: node.object };
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
function isArrayAnnotation(type) {
|
|
211
|
+
if (type.type === "TSArrayType" || type.type === "TSTupleType")
|
|
212
|
+
return true;
|
|
213
|
+
if (type.type === "TSParenthesizedType")
|
|
214
|
+
return isArrayAnnotation(type.typeAnnotation);
|
|
215
|
+
if (type.type === "TSTypeOperator" && type.operator === "readonly") {
|
|
216
|
+
return isArrayAnnotation(type.typeAnnotation);
|
|
217
|
+
}
|
|
218
|
+
return type.type === "TSTypeReference" && type.typeName.type === "Identifier" && (type.typeName.name === "Array" || type.typeName.name === "ReadonlyArray");
|
|
219
|
+
}
|
|
220
|
+
function isKnownArrayExpression(sourceCode, node, visited = new Set) {
|
|
221
|
+
node = unwrapArrayExpression(node);
|
|
222
|
+
if (node.type === "ArrayExpression")
|
|
223
|
+
return true;
|
|
224
|
+
if (node.type === "CallExpression") {
|
|
225
|
+
const method = arrayMethodTarget(node.callee);
|
|
226
|
+
return method !== null && ["map", "filter", "flatMap", "slice", "concat", "toSorted", "toReversed", "toSpliced"].includes(method.name) && isKnownArrayExpression(sourceCode, method.object, visited);
|
|
227
|
+
}
|
|
228
|
+
if (node.type !== "Identifier")
|
|
229
|
+
return false;
|
|
230
|
+
const variable = resolveArrayBinding(sourceCode, node);
|
|
231
|
+
if (variable === null || visited.has(variable))
|
|
232
|
+
return false;
|
|
233
|
+
visited.add(variable);
|
|
234
|
+
if (variable.references.some((reference) => reference.isWrite() && !reference.init))
|
|
235
|
+
return false;
|
|
236
|
+
for (const identifier of variable.identifiers) {
|
|
237
|
+
const annotation = identifier.typeAnnotation?.typeAnnotation;
|
|
238
|
+
if (annotation !== undefined)
|
|
239
|
+
return isArrayAnnotation(annotation);
|
|
240
|
+
}
|
|
241
|
+
for (const definition of variable.defs) {
|
|
242
|
+
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") {
|
|
243
|
+
return isKnownArrayExpression(sourceCode, definition.node.init, visited);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// vendor/anti-slop/src/rules/no-array-filter-map.ts
|
|
250
|
+
var noArrayFilterMapRule = defineRule3({
|
|
251
|
+
meta: {
|
|
252
|
+
type: "suggestion",
|
|
253
|
+
docs: { description: "Disallow adjacent array filter/map passes in favor of lazy iterator helpers or a single transformation." },
|
|
254
|
+
messages: {
|
|
255
|
+
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."
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
createOnce(context) {
|
|
259
|
+
return {
|
|
260
|
+
CallExpression(node) {
|
|
261
|
+
const outer = arrayMethodTarget(node.callee);
|
|
262
|
+
if (outer === null || outer.name !== "map" && outer.name !== "filter")
|
|
263
|
+
return;
|
|
264
|
+
const innerCall = unwrapArrayExpression(outer.object);
|
|
265
|
+
if (innerCall.type !== "CallExpression")
|
|
266
|
+
return;
|
|
267
|
+
const inner = arrayMethodTarget(innerCall.callee);
|
|
268
|
+
if (inner === null || inner.name !== (outer.name === "map" ? "filter" : "map"))
|
|
269
|
+
return;
|
|
270
|
+
if (!isKnownArrayExpression(context.sourceCode, inner.object))
|
|
271
|
+
return;
|
|
272
|
+
context.report({ node, messageId: "arrayFilterMap", data: { first: inner.name, second: outer.name } });
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// vendor/anti-slop/src/rules/no-reduce-accumulator-copy.ts
|
|
279
|
+
import { defineRule as defineRule4 } from "@oxlint/plugins";
|
|
280
|
+
function enclosingReducer(node) {
|
|
281
|
+
let parent = node.parent;
|
|
282
|
+
while (parent !== null) {
|
|
283
|
+
if (parent.type === "FunctionDeclaration")
|
|
284
|
+
return null;
|
|
285
|
+
if (parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression") {
|
|
286
|
+
const callback = parent;
|
|
287
|
+
let owner = callback.parent;
|
|
288
|
+
while (owner !== null && unwrapArrayExpression(owner) === callback)
|
|
289
|
+
owner = owner.parent;
|
|
290
|
+
if (owner?.type !== "CallExpression")
|
|
291
|
+
return null;
|
|
292
|
+
const method = arrayMethodTarget(owner.callee);
|
|
293
|
+
const firstArgument = owner.arguments[0];
|
|
294
|
+
if (method === null || method.name !== "reduce" && method.name !== "reduceRight" || owner.arguments.length > 2 || firstArgument === undefined || unwrapArrayExpression(firstArgument) !== callback)
|
|
295
|
+
return null;
|
|
296
|
+
const firstParameter = callback.params[0];
|
|
297
|
+
const accumulator = firstParameter?.type === "AssignmentPattern" ? firstParameter.left : firstParameter;
|
|
298
|
+
if (accumulator?.type !== "Identifier")
|
|
299
|
+
return null;
|
|
300
|
+
return { callback, accumulator, initialValue: owner.arguments[1] };
|
|
301
|
+
}
|
|
302
|
+
parent = parent.parent;
|
|
303
|
+
}
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
function referencesAccumulator(sourceCode, node, accumulator, visited = new Set) {
|
|
307
|
+
const variable = resolveArrayBinding(sourceCode, node);
|
|
308
|
+
if (variable === null || visited.has(variable))
|
|
309
|
+
return false;
|
|
310
|
+
if (variable === accumulator)
|
|
311
|
+
return true;
|
|
312
|
+
visited.add(variable);
|
|
313
|
+
if (variable.references.some((reference) => reference.isWrite() && !reference.init))
|
|
314
|
+
return false;
|
|
315
|
+
for (const definition of variable.defs) {
|
|
316
|
+
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") {
|
|
317
|
+
return referencesAccumulator(sourceCode, definition.node.init, accumulator, visited);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
function isGlobalCopyOwner(sourceCode, node, name) {
|
|
323
|
+
node = unwrapArrayExpression(node);
|
|
324
|
+
if (node.type !== "Identifier" || node.name !== name)
|
|
325
|
+
return false;
|
|
326
|
+
const variable = resolveArrayBinding(sourceCode, node);
|
|
327
|
+
return variable === null || variable.defs.length === 0;
|
|
328
|
+
}
|
|
329
|
+
var noReduceAccumulatorCopyRule = defineRule4({
|
|
330
|
+
meta: {
|
|
331
|
+
type: "problem",
|
|
332
|
+
docs: { description: "Disallow copying growing reducer accumulators with Object.assign, Array.from, or array copy methods." },
|
|
333
|
+
messages: {
|
|
334
|
+
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."
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
createOnce(context) {
|
|
338
|
+
return {
|
|
339
|
+
CallExpression(node) {
|
|
340
|
+
const method = arrayMethodTarget(node.callee);
|
|
341
|
+
if (method === null)
|
|
342
|
+
return;
|
|
343
|
+
const reducer = enclosingReducer(node);
|
|
344
|
+
if (reducer === null)
|
|
345
|
+
return;
|
|
346
|
+
const accumulator = context.sourceCode.getDeclaredVariables(reducer.callback).find((variable) => variable.identifiers.some((identifier) => identifier.start === reducer.accumulator.start));
|
|
347
|
+
if (accumulator === undefined)
|
|
348
|
+
return;
|
|
349
|
+
const isAccumulator = (expression) => referencesAccumulator(context.sourceCode, expression, accumulator);
|
|
350
|
+
let copiesAccumulator = false;
|
|
351
|
+
if (method.name === "assign" && isGlobalCopyOwner(context.sourceCode, method.object, "Object")) {
|
|
352
|
+
const target = node.arguments[0];
|
|
353
|
+
copiesAccumulator = target !== undefined && unwrapArrayExpression(target).type === "ObjectExpression" && node.arguments.slice(1).some(isAccumulator);
|
|
354
|
+
} else if (method.name === "from" && isGlobalCopyOwner(context.sourceCode, method.object, "Array")) {
|
|
355
|
+
const source = node.arguments[0];
|
|
356
|
+
copiesAccumulator = source !== undefined && isAccumulator(source);
|
|
357
|
+
} else if (["concat", "slice", "toSpliced", "toSorted", "toReversed", "with"].includes(method.name)) {
|
|
358
|
+
const initialValue = reducer.initialValue;
|
|
359
|
+
const arrayAccumulator = initialValue !== undefined && isKnownArrayExpression(context.sourceCode, initialValue);
|
|
360
|
+
copiesAccumulator = arrayAccumulator && isAccumulator(method.object);
|
|
361
|
+
}
|
|
362
|
+
if (copiesAccumulator)
|
|
363
|
+
context.report({ node, messageId: "accumulatorCopy" });
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// vendor/anti-slop/src/rules/no-chained-type-assertions.ts
|
|
370
|
+
import { defineRule as defineRule5 } from "@oxlint/plugins";
|
|
6
371
|
function isTypeAssertionExpression(node) {
|
|
7
372
|
return node.type === "TSAsExpression" || node.type === "TSTypeAssertion";
|
|
8
373
|
}
|
|
@@ -37,7 +402,7 @@ function isForbiddenAssertionChain(node) {
|
|
|
37
402
|
}
|
|
38
403
|
return assertionCount > 1 && hasNonConstAssertion;
|
|
39
404
|
}
|
|
40
|
-
var noChainedTypeAssertionsRule =
|
|
405
|
+
var noChainedTypeAssertionsRule = defineRule5({
|
|
41
406
|
meta: {
|
|
42
407
|
type: "problem",
|
|
43
408
|
docs: {
|
|
@@ -61,7 +426,7 @@ var noChainedTypeAssertionsRule = defineRule({
|
|
|
61
426
|
});
|
|
62
427
|
|
|
63
428
|
// vendor/anti-slop/src/rules/no-conditional-empty-object-spread.ts
|
|
64
|
-
import { defineRule as
|
|
429
|
+
import { defineRule as defineRule6 } from "@oxlint/plugins";
|
|
65
430
|
function unwrapParentheses(node) {
|
|
66
431
|
let current = node;
|
|
67
432
|
while (current.type === "ParenthesizedExpression") {
|
|
@@ -76,7 +441,7 @@ function isConditionalEmptyObjectSpread(node) {
|
|
|
76
441
|
const conditional = unwrapParentheses(node);
|
|
77
442
|
return conditional.type === "ConditionalExpression" && (isEmptyObjectExpression(conditional.consequent) || isEmptyObjectExpression(conditional.alternate));
|
|
78
443
|
}
|
|
79
|
-
var noConditionalEmptyObjectSpreadRule =
|
|
444
|
+
var noConditionalEmptyObjectSpreadRule = defineRule6({
|
|
80
445
|
meta: {
|
|
81
446
|
type: "suggestion",
|
|
82
447
|
docs: {
|
|
@@ -100,7 +465,7 @@ var noConditionalEmptyObjectSpreadRule = defineRule2({
|
|
|
100
465
|
});
|
|
101
466
|
|
|
102
467
|
// vendor/anti-slop/src/rules/no-known-value-widening.ts
|
|
103
|
-
import { defineRule as
|
|
468
|
+
import { defineRule as defineRule7 } from "@oxlint/plugins";
|
|
104
469
|
|
|
105
470
|
// vendor/anti-slop/src/shared/lexical-type-parameters.ts
|
|
106
471
|
function isNode(value) {
|
|
@@ -503,9 +868,9 @@ function classifyWideningTarget(type, environment) {
|
|
|
503
868
|
if (alias === null)
|
|
504
869
|
return null;
|
|
505
870
|
if ((alias.typeParameters?.params.length ?? 0) > 0) {
|
|
506
|
-
const
|
|
507
|
-
const
|
|
508
|
-
return
|
|
871
|
+
const substitutions = aliasSubstitution(alias, unwrapped, new Map);
|
|
872
|
+
const resolved = substitutions === null ? null : classifyAliasBroadTarget(alias.typeAnnotation, environment, substitutions, new Set([name]));
|
|
873
|
+
return resolved?.kind === "open dictionary" ? { kind: "generic container" } : null;
|
|
509
874
|
}
|
|
510
875
|
const substitutions = aliasSubstitution(alias, unwrapped, new Map);
|
|
511
876
|
if (substitutions === null)
|
|
@@ -637,7 +1002,7 @@ function unwrapExpression(expression) {
|
|
|
637
1002
|
}
|
|
638
1003
|
return current;
|
|
639
1004
|
}
|
|
640
|
-
function
|
|
1005
|
+
function resolveVariable2(sourceCode, identifier) {
|
|
641
1006
|
let scope = sourceCode.getScope(identifier);
|
|
642
1007
|
while (scope !== null) {
|
|
643
1008
|
const variable = scope.set.get(identifier.name);
|
|
@@ -662,7 +1027,7 @@ function hasKnownEvidence(sourceCode, expression, visitedVariables = new Set) {
|
|
|
662
1027
|
const unwrapped = unwrapExpression(expression);
|
|
663
1028
|
if (unwrapped.type !== "Identifier")
|
|
664
1029
|
return false;
|
|
665
|
-
const variable =
|
|
1030
|
+
const variable = resolveVariable2(sourceCode, unwrapped);
|
|
666
1031
|
if (variable === null || visitedVariables.has(variable))
|
|
667
1032
|
return false;
|
|
668
1033
|
const declarator = variableDeclarator(variable);
|
|
@@ -681,7 +1046,7 @@ function localFunctionForCall(sourceCode, callee) {
|
|
|
681
1046
|
return unwrapped;
|
|
682
1047
|
if (unwrapped.type !== "Identifier")
|
|
683
1048
|
return null;
|
|
684
|
-
const variable =
|
|
1049
|
+
const variable = resolveVariable2(sourceCode, unwrapped);
|
|
685
1050
|
if (variable === null || variable.defs.length !== 1)
|
|
686
1051
|
return null;
|
|
687
1052
|
const [definition] = variable.defs;
|
|
@@ -734,7 +1099,7 @@ function hasKnownCallArgumentEvidence(sourceCode, expression, environment, visit
|
|
|
734
1099
|
}
|
|
735
1100
|
if (expression.type !== "Identifier")
|
|
736
1101
|
return isKnownEvidenceExpression(expression);
|
|
737
|
-
const variable =
|
|
1102
|
+
const variable = resolveVariable2(sourceCode, expression);
|
|
738
1103
|
if (variable === null || visitedVariables.has(variable))
|
|
739
1104
|
return false;
|
|
740
1105
|
const annotation = variableTypeAnnotation(sourceCode, variable);
|
|
@@ -799,7 +1164,7 @@ function isDictionaryAccumulatorTarget(destination) {
|
|
|
799
1164
|
function hasParentAssertion(node) {
|
|
800
1165
|
return node.parent?.type === "TSAsExpression" || node.parent?.type === "TSTypeAssertion";
|
|
801
1166
|
}
|
|
802
|
-
var noKnownValueWideningRule =
|
|
1167
|
+
var noKnownValueWideningRule = defineRule7({
|
|
803
1168
|
meta: {
|
|
804
1169
|
type: "problem",
|
|
805
1170
|
docs: {
|
|
@@ -848,7 +1213,7 @@ var noKnownValueWideningRule = defineRule3({
|
|
|
848
1213
|
AssignmentExpression(node) {
|
|
849
1214
|
if (node.operator !== "=" || node.left.type !== "Identifier")
|
|
850
1215
|
return;
|
|
851
|
-
const variable =
|
|
1216
|
+
const variable = resolveVariable2(context.sourceCode, node.left);
|
|
852
1217
|
if (variable === null)
|
|
853
1218
|
return;
|
|
854
1219
|
const declarator = variableDeclarator(variable);
|
|
@@ -912,9 +1277,9 @@ var noKnownValueWideningRule = defineRule3({
|
|
|
912
1277
|
});
|
|
913
1278
|
|
|
914
1279
|
// vendor/anti-slop/src/rules/no-module-mocking.ts
|
|
915
|
-
import { defineRule as
|
|
1280
|
+
import { defineRule as defineRule8 } from "@oxlint/plugins";
|
|
916
1281
|
var moduleMockMethods = new Set(["doMock", "mock", "unstable_mockModule"]);
|
|
917
|
-
function
|
|
1282
|
+
function resolveVariable3(sourceCode, identifier) {
|
|
918
1283
|
let scope = sourceCode.getScope(identifier);
|
|
919
1284
|
while (scope !== null) {
|
|
920
1285
|
const variable = scope.set.get(identifier.name);
|
|
@@ -935,7 +1300,7 @@ function isTestFrameworkObject(sourceCode, expression) {
|
|
|
935
1300
|
if ((expression.name === "vi" || expression.name === "jest") && sourceCode.isGlobalReference(expression)) {
|
|
936
1301
|
return true;
|
|
937
1302
|
}
|
|
938
|
-
const variable =
|
|
1303
|
+
const variable = resolveVariable3(sourceCode, expression);
|
|
939
1304
|
if (variable === null || variable.defs.length === 0) {
|
|
940
1305
|
return expression.name === "vi" || expression.name === "jest";
|
|
941
1306
|
}
|
|
@@ -957,7 +1322,7 @@ function moduleMockCall(sourceCode, callee) {
|
|
|
957
1322
|
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;
|
|
958
1323
|
return method !== null && moduleMockMethods.has(method);
|
|
959
1324
|
}
|
|
960
|
-
var noModuleMockingRule =
|
|
1325
|
+
var noModuleMockingRule = defineRule8({
|
|
961
1326
|
meta: {
|
|
962
1327
|
type: "problem",
|
|
963
1328
|
docs: {
|
|
@@ -981,8 +1346,8 @@ var noModuleMockingRule = defineRule4({
|
|
|
981
1346
|
});
|
|
982
1347
|
|
|
983
1348
|
// vendor/anti-slop/src/rules/no-object-parameters.ts
|
|
984
|
-
import { defineRule as
|
|
985
|
-
var noObjectParametersRule =
|
|
1349
|
+
import { defineRule as defineRule9 } from "@oxlint/plugins";
|
|
1350
|
+
var noObjectParametersRule = defineRule9({
|
|
986
1351
|
meta: {
|
|
987
1352
|
type: "problem",
|
|
988
1353
|
docs: {
|
|
@@ -1035,10 +1400,10 @@ var noObjectParametersRule = defineRule5({
|
|
|
1035
1400
|
});
|
|
1036
1401
|
|
|
1037
1402
|
// vendor/anti-slop/src/rules/no-reflect-apply.ts
|
|
1038
|
-
import { defineRule as
|
|
1403
|
+
import { defineRule as defineRule10 } from "@oxlint/plugins";
|
|
1039
1404
|
|
|
1040
1405
|
// vendor/anti-slop/src/shared/reflect-method.ts
|
|
1041
|
-
function
|
|
1406
|
+
function resolveVariable4(sourceCode, identifier) {
|
|
1042
1407
|
let scope = sourceCode.getScope(identifier);
|
|
1043
1408
|
while (scope !== null) {
|
|
1044
1409
|
const variable = scope.set.get(identifier.name);
|
|
@@ -1053,7 +1418,7 @@ function isGlobalReflect(sourceCode, expression) {
|
|
|
1053
1418
|
return false;
|
|
1054
1419
|
if (sourceCode.isGlobalReference(expression))
|
|
1055
1420
|
return true;
|
|
1056
|
-
const variable =
|
|
1421
|
+
const variable = resolveVariable4(sourceCode, expression);
|
|
1057
1422
|
return variable === null || variable.defs.length === 0;
|
|
1058
1423
|
}
|
|
1059
1424
|
function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
|
|
@@ -1066,7 +1431,7 @@ function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
|
|
|
1066
1431
|
}
|
|
1067
1432
|
|
|
1068
1433
|
// vendor/anti-slop/src/rules/no-reflect-apply.ts
|
|
1069
|
-
var noReflectApplyRule =
|
|
1434
|
+
var noReflectApplyRule = defineRule10({
|
|
1070
1435
|
meta: {
|
|
1071
1436
|
type: "problem",
|
|
1072
1437
|
docs: {
|
|
@@ -1090,8 +1455,8 @@ var noReflectApplyRule = defineRule6({
|
|
|
1090
1455
|
});
|
|
1091
1456
|
|
|
1092
1457
|
// vendor/anti-slop/src/rules/no-reflect-get.ts
|
|
1093
|
-
import { defineRule as
|
|
1094
|
-
var noReflectGetRule =
|
|
1458
|
+
import { defineRule as defineRule11 } from "@oxlint/plugins";
|
|
1459
|
+
var noReflectGetRule = defineRule11({
|
|
1095
1460
|
meta: {
|
|
1096
1461
|
type: "problem",
|
|
1097
1462
|
docs: {
|
|
@@ -1115,7 +1480,7 @@ var noReflectGetRule = defineRule7({
|
|
|
1115
1480
|
});
|
|
1116
1481
|
|
|
1117
1482
|
// vendor/anti-slop/src/rules/no-runtime-typeof.ts
|
|
1118
|
-
import { defineRule as
|
|
1483
|
+
import { defineRule as defineRule12 } from "@oxlint/plugins";
|
|
1119
1484
|
function isRuntimeFunction(node) {
|
|
1120
1485
|
return node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression";
|
|
1121
1486
|
}
|
|
@@ -1138,7 +1503,7 @@ function isExistenceProbe(node) {
|
|
|
1138
1503
|
const other = parent.left === node ? parent.right : parent.left;
|
|
1139
1504
|
return other.type === "Literal" && other.value === "undefined";
|
|
1140
1505
|
}
|
|
1141
|
-
var noRuntimeTypeofRule =
|
|
1506
|
+
var noRuntimeTypeofRule = defineRule12({
|
|
1142
1507
|
meta: {
|
|
1143
1508
|
type: "problem",
|
|
1144
1509
|
docs: {
|
|
@@ -1172,7 +1537,7 @@ var noRuntimeTypeofRule = defineRule8({
|
|
|
1172
1537
|
});
|
|
1173
1538
|
|
|
1174
1539
|
// vendor/anti-slop/src/rules/no-shape-in-symbol-names.ts
|
|
1175
|
-
import { defineRule as
|
|
1540
|
+
import { defineRule as defineRule13 } from "@oxlint/plugins";
|
|
1176
1541
|
var FORBIDDEN_SYMBOL_NAME = "shape";
|
|
1177
1542
|
function containsForbiddenSymbolName(name) {
|
|
1178
1543
|
return name.toLowerCase().includes(FORBIDDEN_SYMBOL_NAME);
|
|
@@ -1183,7 +1548,7 @@ function isBorrowedMemberName(node) {
|
|
|
1183
1548
|
return false;
|
|
1184
1549
|
return parent.property === node && parent.computed === false;
|
|
1185
1550
|
}
|
|
1186
|
-
var noForbiddenTermInSymbolNamesRule =
|
|
1551
|
+
var noForbiddenTermInSymbolNamesRule = defineRule13({
|
|
1187
1552
|
meta: {
|
|
1188
1553
|
type: "problem",
|
|
1189
1554
|
docs: {
|
|
@@ -1212,12 +1577,12 @@ var noForbiddenTermInSymbolNamesRule = defineRule9({
|
|
|
1212
1577
|
});
|
|
1213
1578
|
|
|
1214
1579
|
// vendor/anti-slop/src/rules/no-unknown-parameters.ts
|
|
1215
|
-
import { defineRule as
|
|
1580
|
+
import { defineRule as defineRule14 } from "@oxlint/plugins";
|
|
1216
1581
|
function isTypePredicateSubject(owner, parameterName) {
|
|
1217
1582
|
const predicate = owner.returnType?.typeAnnotation;
|
|
1218
1583
|
return predicate?.type === "TSTypePredicate" && predicate.parameterName.type === "Identifier" && predicate.parameterName.name === parameterName;
|
|
1219
1584
|
}
|
|
1220
|
-
var noUnknownParametersRule =
|
|
1585
|
+
var noUnknownParametersRule = defineRule14({
|
|
1221
1586
|
meta: {
|
|
1222
1587
|
type: "problem",
|
|
1223
1588
|
docs: {
|
|
@@ -1261,8 +1626,8 @@ var noUnknownParametersRule = defineRule10({
|
|
|
1261
1626
|
});
|
|
1262
1627
|
|
|
1263
1628
|
// vendor/anti-slop/src/rules/no-unknown-returns.ts
|
|
1264
|
-
import { defineRule as
|
|
1265
|
-
var noUnknownReturnsRule =
|
|
1629
|
+
import { defineRule as defineRule15 } from "@oxlint/plugins";
|
|
1630
|
+
var noUnknownReturnsRule = defineRule15({
|
|
1266
1631
|
meta: {
|
|
1267
1632
|
type: "problem",
|
|
1268
1633
|
docs: {
|
|
@@ -1315,8 +1680,8 @@ var noUnknownReturnsRule = defineRule11({
|
|
|
1315
1680
|
});
|
|
1316
1681
|
|
|
1317
1682
|
// vendor/anti-slop/src/rules/no-unknown-type-aliases.ts
|
|
1318
|
-
import { defineRule as
|
|
1319
|
-
var noUnknownTypeAliasesRule =
|
|
1683
|
+
import { defineRule as defineRule16 } from "@oxlint/plugins";
|
|
1684
|
+
var noUnknownTypeAliasesRule = defineRule16({
|
|
1320
1685
|
meta: {
|
|
1321
1686
|
type: "problem",
|
|
1322
1687
|
docs: {
|
|
@@ -1354,7 +1719,7 @@ var noUnknownTypeAliasesRule = defineRule12({
|
|
|
1354
1719
|
});
|
|
1355
1720
|
|
|
1356
1721
|
// vendor/anti-slop/src/rules/no-unsafe-dictionary-type.ts
|
|
1357
|
-
import { defineRule as
|
|
1722
|
+
import { defineRule as defineRule17 } from "@oxlint/plugins";
|
|
1358
1723
|
var typeNodeKinds = new Set([
|
|
1359
1724
|
"JSDocNonNullableType",
|
|
1360
1725
|
"JSDocNullableType",
|
|
@@ -1441,7 +1806,7 @@ function shouldReportType(node, environment) {
|
|
|
1441
1806
|
}
|
|
1442
1807
|
return true;
|
|
1443
1808
|
}
|
|
1444
|
-
var noUnsafeDictionaryTypeRule =
|
|
1809
|
+
var noUnsafeDictionaryTypeRule = defineRule17({
|
|
1445
1810
|
meta: {
|
|
1446
1811
|
type: "problem",
|
|
1447
1812
|
docs: {
|
|
@@ -1483,7 +1848,7 @@ var noUnsafeDictionaryTypeRule = defineRule13({
|
|
|
1483
1848
|
});
|
|
1484
1849
|
|
|
1485
1850
|
// vendor/anti-slop/src/rules/no-widen-then-assert.ts
|
|
1486
|
-
import { defineRule as
|
|
1851
|
+
import { defineRule as defineRule18 } from "@oxlint/plugins";
|
|
1487
1852
|
var functionBoundaryTypes = new Set([
|
|
1488
1853
|
"ArrowFunctionExpression",
|
|
1489
1854
|
"FunctionDeclaration",
|
|
@@ -1679,7 +2044,7 @@ function assertionIsNarrower(sourceText, broadKind, evidence, assertedType) {
|
|
|
1679
2044
|
return isDefinitelyObjectType(assertedType);
|
|
1680
2045
|
return isDefinitelyNarrowerRecordType(assertedType);
|
|
1681
2046
|
}
|
|
1682
|
-
var noWidenThenAssertRule =
|
|
2047
|
+
var noWidenThenAssertRule = defineRule18({
|
|
1683
2048
|
meta: {
|
|
1684
2049
|
type: "problem",
|
|
1685
2050
|
docs: {
|
|
@@ -1719,7 +2084,7 @@ var noWidenThenAssertRule = defineRule14({
|
|
|
1719
2084
|
});
|
|
1720
2085
|
|
|
1721
2086
|
// vendor/anti-slop/src/rules/require-safety-comment-for-type-assertion.ts
|
|
1722
|
-
import { defineRule as
|
|
2087
|
+
import { defineRule as defineRule19 } from "@oxlint/plugins";
|
|
1723
2088
|
var DEFAULT_SAFETY_MARKERS = ["SAFETY"];
|
|
1724
2089
|
var commentOwnerKinds = new Set([
|
|
1725
2090
|
"ExpressionStatement",
|
|
@@ -1762,7 +2127,7 @@ function hasSafetyComment(sourceCode, node, pattern) {
|
|
|
1762
2127
|
current = current.parent;
|
|
1763
2128
|
}
|
|
1764
2129
|
}
|
|
1765
|
-
var requireSafetyCommentForTypeAssertionRule =
|
|
2130
|
+
var requireSafetyCommentForTypeAssertionRule = defineRule19({
|
|
1766
2131
|
meta: {
|
|
1767
2132
|
type: "problem",
|
|
1768
2133
|
docs: {
|
|
@@ -1812,9 +2177,11 @@ var requireSafetyCommentForTypeAssertionRule = defineRule15({
|
|
|
1812
2177
|
});
|
|
1813
2178
|
|
|
1814
2179
|
// vendor/anti-slop/src/index.ts
|
|
1815
|
-
var antiSlopPlugin =
|
|
2180
|
+
var antiSlopPlugin = eslintCompatPlugin3({
|
|
1816
2181
|
meta: { name: "anti-slop" },
|
|
1817
2182
|
rules: {
|
|
2183
|
+
"no-array-filter-map": noArrayFilterMapRule,
|
|
2184
|
+
"no-reduce-accumulator-copy": noReduceAccumulatorCopyRule,
|
|
1818
2185
|
"no-chained-type-assertions": noChainedTypeAssertionsRule,
|
|
1819
2186
|
"no-conditional-empty-object-spread": noConditionalEmptyObjectSpreadRule,
|
|
1820
2187
|
"no-known-value-widening": noKnownValueWideningRule,
|
|
@@ -1834,11 +2201,11 @@ var antiSlopPlugin = eslintCompatPlugin({
|
|
|
1834
2201
|
});
|
|
1835
2202
|
var src_default = antiSlopPlugin;
|
|
1836
2203
|
// src/generic/index.ts
|
|
1837
|
-
import { eslintCompatPlugin as
|
|
2204
|
+
import { eslintCompatPlugin as eslintCompatPlugin4 } from "@oxlint/plugins";
|
|
1838
2205
|
|
|
1839
2206
|
// src/generic/rules/prefer-event-parameter-type.ts
|
|
1840
|
-
import { defineRule as
|
|
1841
|
-
function
|
|
2207
|
+
import { defineRule as defineRule20 } from "@oxlint/plugins";
|
|
2208
|
+
function nearestEnclosingFunction2(node) {
|
|
1842
2209
|
let current = node.parent;
|
|
1843
2210
|
while (current) {
|
|
1844
2211
|
if (current.type === "FunctionDeclaration" || current.type === "FunctionExpression" || current.type === "ArrowFunctionExpression") {
|
|
@@ -1855,7 +2222,7 @@ function assertedEventParameter(node) {
|
|
|
1855
2222
|
}
|
|
1856
2223
|
const parameterName = expression.object.name;
|
|
1857
2224
|
const property = expression.property.name;
|
|
1858
|
-
const owner =
|
|
2225
|
+
const owner = nearestEnclosingFunction2(node);
|
|
1859
2226
|
if (!owner?.params.some((parameter) => parameter.type === "Identifier" && parameter.name === parameterName)) {
|
|
1860
2227
|
return null;
|
|
1861
2228
|
}
|
|
@@ -1864,7 +2231,7 @@ function assertedEventParameter(node) {
|
|
|
1864
2231
|
property
|
|
1865
2232
|
};
|
|
1866
2233
|
}
|
|
1867
|
-
var preferEventParameterTypeRule =
|
|
2234
|
+
var preferEventParameterTypeRule = defineRule20({
|
|
1868
2235
|
meta: {
|
|
1869
2236
|
type: "suggestion",
|
|
1870
2237
|
docs: {
|
|
@@ -1893,7 +2260,7 @@ var preferEventParameterTypeRule = defineRule16({
|
|
|
1893
2260
|
});
|
|
1894
2261
|
|
|
1895
2262
|
// src/generic/index.ts
|
|
1896
|
-
var timmoPlugin =
|
|
2263
|
+
var timmoPlugin = eslintCompatPlugin4({
|
|
1897
2264
|
meta: { name: "timmo" },
|
|
1898
2265
|
rules: {
|
|
1899
2266
|
"prefer-event-parameter-type": preferEventParameterTypeRule
|
|
@@ -1901,16 +2268,6 @@ var timmoPlugin = eslintCompatPlugin2({
|
|
|
1901
2268
|
});
|
|
1902
2269
|
var generic_default = timmoPlugin;
|
|
1903
2270
|
|
|
1904
|
-
// node_modules/oxlint/dist/index.js
|
|
1905
|
-
function defineConfig(config) {
|
|
1906
|
-
return config;
|
|
1907
|
-
}
|
|
1908
|
-
|
|
1909
|
-
// src/configs/enable-plugin-rules.ts
|
|
1910
|
-
function enablePluginRules(namespace, plugin) {
|
|
1911
|
-
return Object.fromEntries(Object.keys(plugin.rules).sort().map((rule) => [`${namespace}/${rule}`, "error"]));
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
2271
|
// src/configs/recommended.ts
|
|
1915
2272
|
var recommended = defineConfig({
|
|
1916
2273
|
jsPlugins: [
|
|
@@ -1927,166 +2284,6 @@ var recommended = defineConfig({
|
|
|
1927
2284
|
});
|
|
1928
2285
|
var recommended_default = recommended;
|
|
1929
2286
|
|
|
1930
|
-
// src/effect/index.ts
|
|
1931
|
-
import { eslintCompatPlugin as eslintCompatPlugin3 } from "@oxlint/plugins";
|
|
1932
|
-
|
|
1933
|
-
// src/effect/rules/no-try-catch-in-effect-generators.ts
|
|
1934
|
-
import { defineRule as defineRule17 } from "@oxlint/plugins";
|
|
1935
|
-
function resolveVariable4(sourceCode, identifier) {
|
|
1936
|
-
let scope = sourceCode.getScope(identifier);
|
|
1937
|
-
while (scope) {
|
|
1938
|
-
const variable = scope.set.get(identifier.name);
|
|
1939
|
-
if (variable)
|
|
1940
|
-
return variable;
|
|
1941
|
-
scope = scope.upper;
|
|
1942
|
-
}
|
|
1943
|
-
return null;
|
|
1944
|
-
}
|
|
1945
|
-
function nearestEnclosingFunction2(node) {
|
|
1946
|
-
let current = node.parent;
|
|
1947
|
-
while (current) {
|
|
1948
|
-
if (current.type === "FunctionDeclaration" || current.type === "FunctionExpression" || current.type === "ArrowFunctionExpression") {
|
|
1949
|
-
return current;
|
|
1950
|
-
}
|
|
1951
|
-
current = current.parent;
|
|
1952
|
-
}
|
|
1953
|
-
return null;
|
|
1954
|
-
}
|
|
1955
|
-
function staticMemberName(node) {
|
|
1956
|
-
if (node.type !== "MemberExpression" || node.computed)
|
|
1957
|
-
return null;
|
|
1958
|
-
return node.property.type === "Identifier" ? node.property.name : null;
|
|
1959
|
-
}
|
|
1960
|
-
function isEffectImport(sourceCode, identifier, namespace) {
|
|
1961
|
-
const variable = resolveVariable4(sourceCode, identifier);
|
|
1962
|
-
return variable?.defs.some((definition) => {
|
|
1963
|
-
if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration" || definition.parent.source.value !== "effect") {
|
|
1964
|
-
return false;
|
|
1965
|
-
}
|
|
1966
|
-
if (namespace)
|
|
1967
|
-
return definition.node.type === "ImportNamespaceSpecifier";
|
|
1968
|
-
if (definition.node.type !== "ImportSpecifier")
|
|
1969
|
-
return false;
|
|
1970
|
-
const imported = definition.node.imported;
|
|
1971
|
-
return (imported.type === "Identifier" ? imported.name : imported.value) === "Effect";
|
|
1972
|
-
}) ?? false;
|
|
1973
|
-
}
|
|
1974
|
-
function isEffectMethod(sourceCode, node, method) {
|
|
1975
|
-
if (staticMemberName(node) !== method || node.type !== "MemberExpression") {
|
|
1976
|
-
return false;
|
|
1977
|
-
}
|
|
1978
|
-
const object = node.object;
|
|
1979
|
-
if (object.type === "Identifier") {
|
|
1980
|
-
return isEffectImport(sourceCode, object, false);
|
|
1981
|
-
}
|
|
1982
|
-
if (staticMemberName(object) !== "Effect" || object.type !== "MemberExpression" || object.object.type !== "Identifier") {
|
|
1983
|
-
return false;
|
|
1984
|
-
}
|
|
1985
|
-
return isEffectImport(sourceCode, object.object, true);
|
|
1986
|
-
}
|
|
1987
|
-
function isDirectArgument(owner, call) {
|
|
1988
|
-
return call.arguments.some((argument) => argument === owner);
|
|
1989
|
-
}
|
|
1990
|
-
function isRecognisedEffectGenerator(sourceCode, owner) {
|
|
1991
|
-
const parent = owner.parent;
|
|
1992
|
-
if (parent.type !== "CallExpression" || !isDirectArgument(owner, parent)) {
|
|
1993
|
-
return false;
|
|
1994
|
-
}
|
|
1995
|
-
if (isEffectMethod(sourceCode, parent.callee, "gen"))
|
|
1996
|
-
return true;
|
|
1997
|
-
const factoryCall = parent.callee;
|
|
1998
|
-
return factoryCall.type === "CallExpression" && isEffectMethod(sourceCode, factoryCall.callee, "fn");
|
|
1999
|
-
}
|
|
2000
|
-
var noTryCatchInEffectGeneratorsRule = defineRule17({
|
|
2001
|
-
meta: {
|
|
2002
|
-
type: "problem",
|
|
2003
|
-
docs: {
|
|
2004
|
-
description: "Disallow synchronous try/catch owned by recognised Effect generator callbacks."
|
|
2005
|
-
},
|
|
2006
|
-
messages: {
|
|
2007
|
-
useEffectErrorChannel: "Keep expected failures in the Effect error channel. Use Effect.try for synchronous throwing work, Effect.tryPromise for asynchronous throwing work, Effect-returning schema APIs for decoding, and Effect recovery combinators for recovery."
|
|
2008
|
-
}
|
|
2009
|
-
},
|
|
2010
|
-
create(context) {
|
|
2011
|
-
return {
|
|
2012
|
-
TryStatement(node) {
|
|
2013
|
-
if (!node.handler)
|
|
2014
|
-
return;
|
|
2015
|
-
const owner = nearestEnclosingFunction2(node);
|
|
2016
|
-
if (!owner?.generator || !isRecognisedEffectGenerator(context.sourceCode, owner)) {
|
|
2017
|
-
return;
|
|
2018
|
-
}
|
|
2019
|
-
context.report({ node, messageId: "useEffectErrorChannel" });
|
|
2020
|
-
}
|
|
2021
|
-
};
|
|
2022
|
-
}
|
|
2023
|
-
});
|
|
2024
|
-
|
|
2025
|
-
// src/effect/index.ts
|
|
2026
|
-
var timmoEffectPlugin = eslintCompatPlugin3({
|
|
2027
|
-
meta: { name: "timmo-effect" },
|
|
2028
|
-
rules: {
|
|
2029
|
-
"no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule
|
|
2030
|
-
}
|
|
2031
|
-
});
|
|
2032
|
-
var effect_default = timmoEffectPlugin;
|
|
2033
|
-
|
|
2034
|
-
// vendor/anti-slop/src/effect/index.ts
|
|
2035
|
-
import { eslintCompatPlugin as eslintCompatPlugin4 } from "@oxlint/plugins";
|
|
2036
|
-
|
|
2037
|
-
// vendor/anti-slop/src/effect/rules/no-service-constructor-imports.ts
|
|
2038
|
-
import { defineRule as defineRule18 } from "@oxlint/plugins";
|
|
2039
|
-
var SERVICE_CONSTRUCTOR_NAME = /^make[A-Z]/u;
|
|
2040
|
-
var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/u;
|
|
2041
|
-
function isProjectLocalImport(source) {
|
|
2042
|
-
return source.startsWith("./") || source.startsWith("../");
|
|
2043
|
-
}
|
|
2044
|
-
function getImportedName(specifier) {
|
|
2045
|
-
if (specifier.imported.type === "Identifier")
|
|
2046
|
-
return specifier.imported.name;
|
|
2047
|
-
return specifier.imported.value;
|
|
2048
|
-
}
|
|
2049
|
-
var noServiceConstructorImportsRule = defineRule18({
|
|
2050
|
-
meta: {
|
|
2051
|
-
type: "problem",
|
|
2052
|
-
docs: {
|
|
2053
|
-
description: "Disallow project-local make<CapabilityName> imports outside test and spec files."
|
|
2054
|
-
},
|
|
2055
|
-
messages: {
|
|
2056
|
-
serviceConstructorImport: 'Do not import Effect service constructor "{{name}}" into runtime code. Import the owning Layer, yield the contextual service, and allow its requirements to propagate to the composition root.'
|
|
2057
|
-
}
|
|
2058
|
-
},
|
|
2059
|
-
create(context) {
|
|
2060
|
-
const isTestFile = TEST_FILE.test(context.filename.replaceAll("\\", "/"));
|
|
2061
|
-
return {
|
|
2062
|
-
ImportDeclaration(node) {
|
|
2063
|
-
if (isTestFile || !isProjectLocalImport(node.source.value))
|
|
2064
|
-
return;
|
|
2065
|
-
for (const specifier of node.specifiers) {
|
|
2066
|
-
if (specifier.type !== "ImportSpecifier")
|
|
2067
|
-
continue;
|
|
2068
|
-
const importedName2 = getImportedName(specifier);
|
|
2069
|
-
if (!SERVICE_CONSTRUCTOR_NAME.test(importedName2))
|
|
2070
|
-
continue;
|
|
2071
|
-
context.report({
|
|
2072
|
-
node: specifier,
|
|
2073
|
-
messageId: "serviceConstructorImport",
|
|
2074
|
-
data: { name: importedName2 }
|
|
2075
|
-
});
|
|
2076
|
-
}
|
|
2077
|
-
}
|
|
2078
|
-
};
|
|
2079
|
-
}
|
|
2080
|
-
});
|
|
2081
|
-
|
|
2082
|
-
// vendor/anti-slop/src/effect/index.ts
|
|
2083
|
-
var antiSlopEffectPlugin = eslintCompatPlugin4({
|
|
2084
|
-
meta: { name: "anti-slop-effect" },
|
|
2085
|
-
rules: {
|
|
2086
|
-
"no-service-constructor-imports": noServiceConstructorImportsRule
|
|
2087
|
-
}
|
|
2088
|
-
});
|
|
2089
|
-
var effect_default2 = antiSlopEffectPlugin;
|
|
2090
2287
|
// src/configs/recommended-effect.ts
|
|
2091
2288
|
var recommendedEffect = defineConfig({
|
|
2092
2289
|
extends: [recommended_default],
|