@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.
@@ -1,8 +1,373 @@
1
- // vendor/anti-slop/src/index.ts
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
- // vendor/anti-slop/src/rules/no-chained-type-assertions.ts
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 = defineRule({
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 defineRule2 } from "@oxlint/plugins";
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 = defineRule2({
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 defineRule3 } from "@oxlint/plugins";
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 substitutions2 = aliasSubstitution(alias, unwrapped, new Map);
507
- const resolved2 = substitutions2 === null ? null : classifyAliasBroadTarget(alias.typeAnnotation, environment, substitutions2, new Set([name]));
508
- return resolved2?.kind === "open dictionary" ? { kind: "generic container" } : null;
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 resolveVariable(sourceCode, identifier) {
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 = resolveVariable(sourceCode, unwrapped);
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 = resolveVariable(sourceCode, unwrapped);
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 = resolveVariable(sourceCode, expression);
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 = defineRule3({
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 = resolveVariable(context.sourceCode, node.left);
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 defineRule4 } from "@oxlint/plugins";
1280
+ import { defineRule as defineRule8 } from "@oxlint/plugins";
916
1281
  var moduleMockMethods = new Set(["doMock", "mock", "unstable_mockModule"]);
917
- function resolveVariable2(sourceCode, identifier) {
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 = resolveVariable2(sourceCode, expression);
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 = defineRule4({
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 defineRule5 } from "@oxlint/plugins";
985
- var noObjectParametersRule = defineRule5({
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 defineRule6 } from "@oxlint/plugins";
1403
+ import { defineRule as defineRule10 } from "@oxlint/plugins";
1039
1404
 
1040
1405
  // vendor/anti-slop/src/shared/reflect-method.ts
1041
- function resolveVariable3(sourceCode, identifier) {
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 = resolveVariable3(sourceCode, expression);
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 = defineRule6({
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 defineRule7 } from "@oxlint/plugins";
1094
- var noReflectGetRule = defineRule7({
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 defineRule8 } from "@oxlint/plugins";
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 = defineRule8({
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 defineRule9 } from "@oxlint/plugins";
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 = defineRule9({
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 defineRule10 } from "@oxlint/plugins";
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 = defineRule10({
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 defineRule11 } from "@oxlint/plugins";
1265
- var noUnknownReturnsRule = defineRule11({
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 defineRule12 } from "@oxlint/plugins";
1319
- var noUnknownTypeAliasesRule = defineRule12({
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 defineRule13 } from "@oxlint/plugins";
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 = defineRule13({
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 defineRule14 } from "@oxlint/plugins";
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 = defineRule14({
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 defineRule15 } from "@oxlint/plugins";
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 = defineRule15({
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 = eslintCompatPlugin({
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 eslintCompatPlugin2 } from "@oxlint/plugins";
2204
+ import { eslintCompatPlugin as eslintCompatPlugin4 } from "@oxlint/plugins";
1838
2205
 
1839
2206
  // src/generic/rules/prefer-event-parameter-type.ts
1840
- import { defineRule as defineRule16 } from "@oxlint/plugins";
1841
- function nearestEnclosingFunction(node) {
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 = nearestEnclosingFunction(node);
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 = defineRule16({
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 = eslintCompatPlugin2({
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],