@timmo001/oxlint-rules 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,18 +6,10 @@ function defineConfig(config) {
6
6
  // src/effect/index.ts
7
7
  import { eslintCompatPlugin } from "@oxlint/plugins";
8
8
 
9
- // src/effect/rules/no-try-catch-in-effect-generators.ts
9
+ // src/effect/rules/no-raw-gh.ts
10
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
- }
11
+
12
+ // src/shared/ast.ts
21
13
  function nearestEnclosingFunction(node) {
22
14
  let current = node.parent;
23
15
  while (current) {
@@ -33,6 +25,83 @@ function staticMemberName(node) {
33
25
  return null;
34
26
  return node.property.type === "Identifier" ? node.property.name : null;
35
27
  }
28
+
29
+ // vendor/anti-slop/src/shared/scope.ts
30
+ function resolveVariable(sourceCode, identifier) {
31
+ let scope = sourceCode.getScope(identifier);
32
+ while (scope !== null) {
33
+ const variable = scope.set.get(identifier.name);
34
+ if (variable !== undefined)
35
+ return variable;
36
+ scope = scope.upper;
37
+ }
38
+ return null;
39
+ }
40
+ // src/effect/rules/no-raw-gh.ts
41
+ var PACKAGE = "@timmo001/effect-gh";
42
+ var rawMethods = new Set(["execute", "json", "stream"]);
43
+ function isEffectGhImport(sourceCode, identifier, name) {
44
+ return resolveVariable(sourceCode, identifier)?.defs.some((definition) => {
45
+ if (definition.type !== "ImportBinding" || definition.parent?.type !== "ImportDeclaration" || definition.parent.source.value !== PACKAGE || definition.node.type !== "ImportSpecifier") {
46
+ return false;
47
+ }
48
+ const imported = definition.node.imported;
49
+ return (imported.type === "Identifier" ? imported.name : imported.value) === name;
50
+ }) ?? false;
51
+ }
52
+ function isYieldGh(sourceCode, node) {
53
+ return node?.type === "YieldExpression" && node.delegate && node.argument?.type === "Identifier" && isEffectGhImport(sourceCode, node.argument, "Gh");
54
+ }
55
+ function isGhBinding(sourceCode, identifier) {
56
+ return resolveVariable(sourceCode, identifier)?.defs.some((definition) => definition.type === "Variable" && definition.node.type === "VariableDeclarator" && isYieldGh(sourceCode, definition.node.init)) ?? false;
57
+ }
58
+ function isGhArgument(node) {
59
+ if (node?.type === "Literal")
60
+ return node.value === "gh";
61
+ if (node?.type !== "ArrayExpression")
62
+ return false;
63
+ const first = node.elements[0];
64
+ return first?.type === "Literal" && first.value === "gh";
65
+ }
66
+ var noRawGhRule = defineRule({
67
+ meta: {
68
+ type: "problem",
69
+ docs: {
70
+ description: "Use @timmo001/effect-gh typed operations instead of the raw Gh methods, Api.raw, or spawning gh directly."
71
+ },
72
+ messages: {
73
+ rawGh: "Use a typed effect-gh operation instead of `Gh.{{method}}` with raw argv. Add one to effect-gh if the command has none.",
74
+ rawApi: "Use `Api.json`, `Api.pages`, `Api.empty`, `Api.text` or `Api.headers` instead of `Api.raw`, so the response is typed.",
75
+ spawnGh: "Run gh through a typed @timmo001/effect-gh operation instead of spawning it directly."
76
+ }
77
+ },
78
+ create(context) {
79
+ return {
80
+ CallExpression(node) {
81
+ const callee = node.callee;
82
+ const method = staticMemberName(callee);
83
+ if (callee.type === "MemberExpression" && method !== null) {
84
+ const object = callee.object;
85
+ if (rawMethods.has(method) && (isYieldGh(context.sourceCode, object) || object.type === "Identifier" && isGhBinding(context.sourceCode, object))) {
86
+ context.report({ node, messageId: "rawGh", data: { method } });
87
+ return;
88
+ }
89
+ if (method === "raw" && object.type === "Identifier" && isEffectGhImport(context.sourceCode, object, "Api")) {
90
+ context.report({ node, messageId: "rawApi" });
91
+ return;
92
+ }
93
+ }
94
+ if (isGhArgument(node.arguments[0]))
95
+ context.report({ node, messageId: "spawnGh" });
96
+ }
97
+ };
98
+ }
99
+ });
100
+
101
+ // src/effect/rules/no-try-catch-in-effect-generators.ts
102
+ import { defineRule as defineRule2 } from "@oxlint/plugins";
103
+
104
+ // src/shared/effect.ts
36
105
  function isEffectImport(sourceCode, identifier, namespace) {
37
106
  const variable = resolveVariable(sourceCode, identifier);
38
107
  return variable?.defs.some((definition) => {
@@ -60,6 +129,11 @@ function isEffectMethod(sourceCode, node, method) {
60
129
  }
61
130
  return isEffectImport(sourceCode, object.object, true);
62
131
  }
132
+ function importsEffect(program) {
133
+ return program.body.some((statement) => statement.type === "ImportDeclaration" && statement.importKind !== "type" && (statement.source.value === "effect" || statement.source.value.startsWith("effect/") || statement.source.value.startsWith("@effect/")));
134
+ }
135
+
136
+ // src/effect/rules/no-try-catch-in-effect-generators.ts
63
137
  function isDirectArgument(owner, call) {
64
138
  return call.arguments.some((argument) => argument === owner);
65
139
  }
@@ -73,7 +147,7 @@ function isRecognisedEffectGenerator(sourceCode, owner) {
73
147
  const factoryCall = parent.callee;
74
148
  return factoryCall.type === "CallExpression" && isEffectMethod(sourceCode, factoryCall.callee, "fn");
75
149
  }
76
- var noTryCatchInEffectGeneratorsRule = defineRule({
150
+ var noTryCatchInEffectGeneratorsRule = defineRule2({
77
151
  meta: {
78
152
  type: "problem",
79
153
  docs: {
@@ -98,11 +172,86 @@ var noTryCatchInEffectGeneratorsRule = defineRule({
98
172
  }
99
173
  });
100
174
 
175
+ // src/effect/rules/prefer-platform-services.ts
176
+ import { defineRule as defineRule3 } from "@oxlint/plugins";
177
+ var moduleServices = new Map([
178
+ ["child_process", "childProcess"],
179
+ ["fs", "fileSystem"],
180
+ ["fs/promises", "fileSystem"]
181
+ ]);
182
+ var bunServices = new Map([
183
+ ["$", "childProcess"],
184
+ ["file", "fileSystem"],
185
+ ["spawn", "childProcess"],
186
+ ["spawnSync", "childProcess"],
187
+ ["write", "fileSystem"]
188
+ ]);
189
+ var preferPlatformServicesRule = defineRule3({
190
+ meta: {
191
+ type: "suggestion",
192
+ docs: {
193
+ description: "Prefer Effect's ChildProcessSpawner and FileSystem services over Node or Bun process and file system APIs in modules that use Effect."
194
+ },
195
+ messages: {
196
+ childProcess: "Use Effect's `ChildProcessSpawner` service (`effect/process`) instead of `{{api}}`, so scope cleanup, interruption, and test layers apply.",
197
+ fileSystem: "Use Effect's `FileSystem` service instead of `{{api}}`, so failures stay typed and tests can provide a layer."
198
+ }
199
+ },
200
+ create(context) {
201
+ let enabled = false;
202
+ return {
203
+ Program(node) {
204
+ enabled = importsEffect(node);
205
+ },
206
+ ImportDeclaration(node) {
207
+ if (!enabled || node.importKind === "type")
208
+ return;
209
+ const source = node.source.value;
210
+ const service = moduleServices.get(source.replace(/^node:/u, ""));
211
+ if (service) {
212
+ context.report({ node, messageId: service, data: { api: source } });
213
+ return;
214
+ }
215
+ if (source !== "bun")
216
+ return;
217
+ for (const specifier of node.specifiers) {
218
+ if (specifier.type !== "ImportSpecifier" || specifier.importKind === "type") {
219
+ continue;
220
+ }
221
+ const imported = specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value;
222
+ const bunService = bunServices.get(imported);
223
+ if (bunService) {
224
+ context.report({
225
+ node: specifier,
226
+ messageId: bunService,
227
+ data: { api: `Bun.${imported}` }
228
+ });
229
+ }
230
+ }
231
+ },
232
+ MemberExpression(node) {
233
+ const name = staticMemberName(node);
234
+ const service = name ? bunServices.get(name) : undefined;
235
+ if (!enabled || !service || node.object.type !== "Identifier" || node.object.name !== "Bun" || (resolveVariable(context.sourceCode, node.object)?.defs.length ?? 0) > 0) {
236
+ return;
237
+ }
238
+ context.report({
239
+ node,
240
+ messageId: service,
241
+ data: { api: `Bun.${name}` }
242
+ });
243
+ }
244
+ };
245
+ }
246
+ });
247
+
101
248
  // src/effect/index.ts
102
249
  var timmoEffectPlugin = eslintCompatPlugin({
103
250
  meta: { name: "timmo-effect" },
104
251
  rules: {
105
- "no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule
252
+ "no-raw-gh": noRawGhRule,
253
+ "no-try-catch-in-effect-generators": noTryCatchInEffectGeneratorsRule,
254
+ "prefer-platform-services": preferPlatformServicesRule
106
255
  }
107
256
  });
108
257
  var effect_default = timmoEffectPlugin;
@@ -111,7 +260,7 @@ var effect_default = timmoEffectPlugin;
111
260
  import { eslintCompatPlugin as eslintCompatPlugin2 } from "@oxlint/plugins";
112
261
 
113
262
  // vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts
114
- import { defineRule as defineRule2 } from "@oxlint/plugins";
263
+ import { defineRule as defineRule4 } from "@oxlint/plugins";
115
264
 
116
265
  // vendor/anti-slop/src/effect/shared/tagged-values.ts
117
266
  var equalityOperators = new Set(["==", "===", "!=", "!=="]);
@@ -158,7 +307,7 @@ var isMatchPatternObject = (node) => {
158
307
  };
159
308
 
160
309
  // vendor/anti-slop/src/effect/rules/no-manual-effect-error-tag.ts
161
- var noManualEffectErrorTagRule = defineRule2({
310
+ var noManualEffectErrorTagRule = defineRule4({
162
311
  meta: {
163
312
  type: "problem",
164
313
  docs: {
@@ -195,8 +344,8 @@ var noManualEffectErrorTagRule = defineRule2({
195
344
  });
196
345
 
197
346
  // vendor/anti-slop/src/effect/rules/no-manual-tag-comparison.ts
198
- import { defineRule as defineRule3 } from "@oxlint/plugins";
199
- var noManualTagComparisonRule = defineRule3({
347
+ import { defineRule as defineRule5 } from "@oxlint/plugins";
348
+ var noManualTagComparisonRule = defineRule5({
200
349
  meta: {
201
350
  type: "problem",
202
351
  docs: {
@@ -226,8 +375,8 @@ var noManualTagComparisonRule = defineRule3({
226
375
  });
227
376
 
228
377
  // vendor/anti-slop/src/effect/rules/no-manual-tagged-construction.ts
229
- import { defineRule as defineRule4 } from "@oxlint/plugins";
230
- var noManualTaggedConstructionRule = defineRule4({
378
+ import { defineRule as defineRule6 } from "@oxlint/plugins";
379
+ var noManualTaggedConstructionRule = defineRule6({
231
380
  meta: {
232
381
  type: "problem",
233
382
  docs: {
@@ -252,7 +401,7 @@ var noManualTaggedConstructionRule = defineRule4({
252
401
  });
253
402
 
254
403
  // vendor/anti-slop/src/effect/rules/no-service-constructor-imports.ts
255
- import { defineRule as defineRule5 } from "@oxlint/plugins";
404
+ import { defineRule as defineRule7 } from "@oxlint/plugins";
256
405
  var SERVICE_CONSTRUCTOR_NAME = /^make[A-Z]/u;
257
406
  var TEST_FILE = /\.(?:test|spec)\.[cm]?[jt]sx?$/u;
258
407
  function isProjectLocalImport(source) {
@@ -263,7 +412,7 @@ function getImportedName(specifier) {
263
412
  return specifier.imported.name;
264
413
  return specifier.imported.value;
265
414
  }
266
- var noServiceConstructorImportsRule = defineRule5({
415
+ var noServiceConstructorImportsRule = defineRule7({
267
416
  meta: {
268
417
  type: "problem",
269
418
  docs: {
@@ -297,9 +446,9 @@ var noServiceConstructorImportsRule = defineRule5({
297
446
  });
298
447
 
299
448
  // vendor/anti-slop/src/effect/rules/prefer-effect-match.ts
300
- import { defineRule as defineRule6 } from "@oxlint/plugins";
449
+ import { defineRule as defineRule8 } from "@oxlint/plugins";
301
450
  var equalityOperators2 = new Set(["==", "===", "!=", "!=="]);
302
- var preferEffectMatchRule = defineRule6({
451
+ var preferEffectMatchRule = defineRule8({
303
452
  meta: {
304
453
  type: "problem",
305
454
  docs: {
@@ -365,7 +514,7 @@ function enablePluginRules(namespace, plugin) {
365
514
  import { eslintCompatPlugin as eslintCompatPlugin3 } from "@oxlint/plugins";
366
515
 
367
516
  // vendor/anti-slop/src/rules/no-array-filter-map.ts
368
- import { defineRule as defineRule7 } from "@oxlint/plugins";
517
+ import { defineRule as defineRule9 } from "@oxlint/plugins";
369
518
 
370
519
  // vendor/anti-slop/src/shared/array-method.ts
371
520
  function unwrapArrayExpression(node) {
@@ -440,7 +589,7 @@ function isKnownArrayExpression(sourceCode, node, visited = new Set) {
440
589
  }
441
590
 
442
591
  // vendor/anti-slop/src/rules/no-array-filter-map.ts
443
- var noArrayFilterMapRule = defineRule7({
592
+ var noArrayFilterMapRule = defineRule9({
444
593
  meta: {
445
594
  type: "suggestion",
446
595
  docs: { description: "Disallow adjacent array filter/map passes in favor of lazy iterator helpers or a single transformation." },
@@ -469,7 +618,7 @@ var noArrayFilterMapRule = defineRule7({
469
618
  });
470
619
 
471
620
  // vendor/anti-slop/src/rules/no-reduce-accumulator-copy.ts
472
- import { defineRule as defineRule8 } from "@oxlint/plugins";
621
+ import { defineRule as defineRule10 } from "@oxlint/plugins";
473
622
  function enclosingReducer(node) {
474
623
  let parent = node.parent;
475
624
  while (parent !== null) {
@@ -519,7 +668,7 @@ function isGlobalCopyOwner(sourceCode, node, name) {
519
668
  const variable = resolveArrayBinding(sourceCode, node);
520
669
  return variable === null || variable.defs.length === 0;
521
670
  }
522
- var noReduceAccumulatorCopyRule = defineRule8({
671
+ var noReduceAccumulatorCopyRule = defineRule10({
523
672
  meta: {
524
673
  type: "problem",
525
674
  docs: { description: "Disallow copying growing reducer accumulators with Object.assign, Array.from, or array copy methods." },
@@ -560,7 +709,7 @@ var noReduceAccumulatorCopyRule = defineRule8({
560
709
  });
561
710
 
562
711
  // vendor/anti-slop/src/rules/no-chained-type-assertions.ts
563
- import { defineRule as defineRule9 } from "@oxlint/plugins";
712
+ import { defineRule as defineRule11 } from "@oxlint/plugins";
564
713
  function isTypeAssertionExpression(node) {
565
714
  return node.type === "TSAsExpression" || node.type === "TSTypeAssertion";
566
715
  }
@@ -595,7 +744,7 @@ function isForbiddenAssertionChain(node) {
595
744
  }
596
745
  return assertionCount > 1 && hasNonConstAssertion;
597
746
  }
598
- var noChainedTypeAssertionsRule = defineRule9({
747
+ var noChainedTypeAssertionsRule = defineRule11({
599
748
  meta: {
600
749
  type: "problem",
601
750
  docs: {
@@ -619,7 +768,7 @@ var noChainedTypeAssertionsRule = defineRule9({
619
768
  });
620
769
 
621
770
  // vendor/anti-slop/src/rules/no-conditional-empty-object-spread.ts
622
- import { defineRule as defineRule10 } from "@oxlint/plugins";
771
+ import { defineRule as defineRule12 } from "@oxlint/plugins";
623
772
  function unwrapParentheses(node) {
624
773
  let current = node;
625
774
  while (current.type === "ParenthesizedExpression") {
@@ -634,7 +783,7 @@ function isConditionalEmptyObjectSpread(node) {
634
783
  const conditional = unwrapParentheses(node);
635
784
  return conditional.type === "ConditionalExpression" && (isEmptyObjectExpression(conditional.consequent) || isEmptyObjectExpression(conditional.alternate));
636
785
  }
637
- var noConditionalEmptyObjectSpreadRule = defineRule10({
786
+ var noConditionalEmptyObjectSpreadRule = defineRule12({
638
787
  meta: {
639
788
  type: "suggestion",
640
789
  docs: {
@@ -658,7 +807,7 @@ var noConditionalEmptyObjectSpreadRule = defineRule10({
658
807
  });
659
808
 
660
809
  // vendor/anti-slop/src/rules/no-known-value-widening.ts
661
- import { defineRule as defineRule11 } from "@oxlint/plugins";
810
+ import { defineRule as defineRule13 } from "@oxlint/plugins";
662
811
 
663
812
  // vendor/anti-slop/src/shared/lexical-type-parameters.ts
664
813
  function isNode(value) {
@@ -1187,18 +1336,6 @@ function functionParameterBindingName(parameter, sourceCode) {
1187
1336
  return annotationStart === undefined ? sourceText : sourceText.slice(0, annotationStart - parameter.start).trimEnd();
1188
1337
  }
1189
1338
 
1190
- // vendor/anti-slop/src/shared/scope.ts
1191
- function resolveVariable2(sourceCode, identifier) {
1192
- let scope = sourceCode.getScope(identifier);
1193
- while (scope !== null) {
1194
- const variable = scope.set.get(identifier.name);
1195
- if (variable !== undefined)
1196
- return variable;
1197
- scope = scope.upper;
1198
- }
1199
- return null;
1200
- }
1201
-
1202
1339
  // vendor/anti-slop/src/rules/no-known-value-widening.ts
1203
1340
  function unwrapExpression(expression) {
1204
1341
  let current = expression;
@@ -1222,7 +1359,7 @@ function hasKnownEvidence(sourceCode, expression, visitedVariables = new Set) {
1222
1359
  const unwrapped = unwrapExpression(expression);
1223
1360
  if (unwrapped.type !== "Identifier")
1224
1361
  return false;
1225
- const variable = resolveVariable2(sourceCode, unwrapped);
1362
+ const variable = resolveVariable(sourceCode, unwrapped);
1226
1363
  if (variable === null || visitedVariables.has(variable))
1227
1364
  return false;
1228
1365
  const declarator = variableDeclarator(variable);
@@ -1241,7 +1378,7 @@ function localFunctionForCall(sourceCode, callee) {
1241
1378
  return unwrapped;
1242
1379
  if (unwrapped.type !== "Identifier")
1243
1380
  return null;
1244
- const variable = resolveVariable2(sourceCode, unwrapped);
1381
+ const variable = resolveVariable(sourceCode, unwrapped);
1245
1382
  if (variable === null || variable.defs.length !== 1)
1246
1383
  return null;
1247
1384
  const [definition] = variable.defs;
@@ -1294,7 +1431,7 @@ function hasKnownCallArgumentEvidence(sourceCode, expression, environment, visit
1294
1431
  }
1295
1432
  if (expression.type !== "Identifier")
1296
1433
  return isKnownEvidenceExpression(expression);
1297
- const variable = resolveVariable2(sourceCode, expression);
1434
+ const variable = resolveVariable(sourceCode, expression);
1298
1435
  if (variable === null || visitedVariables.has(variable))
1299
1436
  return false;
1300
1437
  const annotation = variableTypeAnnotation(sourceCode, variable);
@@ -1359,7 +1496,7 @@ function isDictionaryAccumulatorTarget(destination) {
1359
1496
  function hasParentAssertion(node) {
1360
1497
  return node.parent?.type === "TSAsExpression" || node.parent?.type === "TSTypeAssertion";
1361
1498
  }
1362
- var noKnownValueWideningRule = defineRule11({
1499
+ var noKnownValueWideningRule = defineRule13({
1363
1500
  meta: {
1364
1501
  type: "problem",
1365
1502
  docs: {
@@ -1408,7 +1545,7 @@ var noKnownValueWideningRule = defineRule11({
1408
1545
  AssignmentExpression(node) {
1409
1546
  if (node.operator !== "=" || node.left.type !== "Identifier")
1410
1547
  return;
1411
- const variable = resolveVariable2(context.sourceCode, node.left);
1548
+ const variable = resolveVariable(context.sourceCode, node.left);
1412
1549
  if (variable === null)
1413
1550
  return;
1414
1551
  const declarator = variableDeclarator(variable);
@@ -1472,7 +1609,7 @@ var noKnownValueWideningRule = defineRule11({
1472
1609
  });
1473
1610
 
1474
1611
  // vendor/anti-slop/src/rules/no-module-mocking.ts
1475
- import { defineRule as defineRule12 } from "@oxlint/plugins";
1612
+ import { defineRule as defineRule14 } from "@oxlint/plugins";
1476
1613
  var moduleMockMethods = new Set(["doMock", "mock", "unstable_mockModule"]);
1477
1614
  function importedName(node) {
1478
1615
  if (node.type !== "ImportSpecifier")
@@ -1485,7 +1622,7 @@ function isTestFrameworkObject(sourceCode, expression) {
1485
1622
  if ((expression.name === "vi" || expression.name === "jest") && sourceCode.isGlobalReference(expression)) {
1486
1623
  return true;
1487
1624
  }
1488
- const variable = resolveVariable2(sourceCode, expression);
1625
+ const variable = resolveVariable(sourceCode, expression);
1489
1626
  if (variable === null || variable.defs.length === 0) {
1490
1627
  return expression.name === "vi" || expression.name === "jest";
1491
1628
  }
@@ -1507,7 +1644,7 @@ function moduleMockCall(sourceCode, callee) {
1507
1644
  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;
1508
1645
  return method !== null && moduleMockMethods.has(method);
1509
1646
  }
1510
- var noModuleMockingRule = defineRule12({
1647
+ var noModuleMockingRule = defineRule14({
1511
1648
  meta: {
1512
1649
  type: "problem",
1513
1650
  docs: {
@@ -1531,8 +1668,8 @@ var noModuleMockingRule = defineRule12({
1531
1668
  });
1532
1669
 
1533
1670
  // vendor/anti-slop/src/rules/no-object-parameters.ts
1534
- import { defineRule as defineRule13 } from "@oxlint/plugins";
1535
- var noObjectParametersRule = defineRule13({
1671
+ import { defineRule as defineRule15 } from "@oxlint/plugins";
1672
+ var noObjectParametersRule = defineRule15({
1536
1673
  meta: {
1537
1674
  type: "problem",
1538
1675
  docs: {
@@ -1585,7 +1722,7 @@ var noObjectParametersRule = defineRule13({
1585
1722
  });
1586
1723
 
1587
1724
  // vendor/anti-slop/src/rules/no-reflect-apply.ts
1588
- import { defineRule as defineRule14 } from "@oxlint/plugins";
1725
+ import { defineRule as defineRule16 } from "@oxlint/plugins";
1589
1726
 
1590
1727
  // vendor/anti-slop/src/shared/reflect-method.ts
1591
1728
  function isGlobalReflect(sourceCode, expression) {
@@ -1593,7 +1730,7 @@ function isGlobalReflect(sourceCode, expression) {
1593
1730
  return false;
1594
1731
  if (sourceCode.isGlobalReference(expression))
1595
1732
  return true;
1596
- const variable = resolveVariable2(sourceCode, expression);
1733
+ const variable = resolveVariable(sourceCode, expression);
1597
1734
  return variable === null || variable.defs.length === 0;
1598
1735
  }
1599
1736
  function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
@@ -1606,7 +1743,7 @@ function isGlobalReflectMethodCall(sourceCode, callee, methodName) {
1606
1743
  }
1607
1744
 
1608
1745
  // vendor/anti-slop/src/rules/no-reflect-apply.ts
1609
- var noReflectApplyRule = defineRule14({
1746
+ var noReflectApplyRule = defineRule16({
1610
1747
  meta: {
1611
1748
  type: "problem",
1612
1749
  docs: {
@@ -1630,8 +1767,8 @@ var noReflectApplyRule = defineRule14({
1630
1767
  });
1631
1768
 
1632
1769
  // vendor/anti-slop/src/rules/no-reflect-get.ts
1633
- import { defineRule as defineRule15 } from "@oxlint/plugins";
1634
- var noReflectGetRule = defineRule15({
1770
+ import { defineRule as defineRule17 } from "@oxlint/plugins";
1771
+ var noReflectGetRule = defineRule17({
1635
1772
  meta: {
1636
1773
  type: "problem",
1637
1774
  docs: {
@@ -1655,7 +1792,7 @@ var noReflectGetRule = defineRule15({
1655
1792
  });
1656
1793
 
1657
1794
  // vendor/anti-slop/src/rules/no-runtime-typeof.ts
1658
- import { defineRule as defineRule16 } from "@oxlint/plugins";
1795
+ import { defineRule as defineRule18 } from "@oxlint/plugins";
1659
1796
  function isRuntimeFunction(node) {
1660
1797
  return node.type === "ArrowFunctionExpression" || node.type === "FunctionDeclaration" || node.type === "FunctionExpression";
1661
1798
  }
@@ -1678,7 +1815,7 @@ function isExistenceProbe(node) {
1678
1815
  const other = parent.left === node ? parent.right : parent.left;
1679
1816
  return other.type === "Literal" && other.value === "undefined";
1680
1817
  }
1681
- var noRuntimeTypeofRule = defineRule16({
1818
+ var noRuntimeTypeofRule = defineRule18({
1682
1819
  meta: {
1683
1820
  type: "problem",
1684
1821
  docs: {
@@ -1712,7 +1849,7 @@ var noRuntimeTypeofRule = defineRule16({
1712
1849
  });
1713
1850
 
1714
1851
  // vendor/anti-slop/src/rules/no-shape-in-symbol-names.ts
1715
- import { defineRule as defineRule17 } from "@oxlint/plugins";
1852
+ import { defineRule as defineRule19 } from "@oxlint/plugins";
1716
1853
  var FORBIDDEN_SYMBOL_NAME = "shape";
1717
1854
  function containsForbiddenSymbolName(name) {
1718
1855
  return name.toLowerCase().includes(FORBIDDEN_SYMBOL_NAME);
@@ -1723,7 +1860,7 @@ function isBorrowedMemberName(node) {
1723
1860
  return false;
1724
1861
  return parent.property === node && parent.computed === false;
1725
1862
  }
1726
- var noForbiddenTermInSymbolNamesRule = defineRule17({
1863
+ var noForbiddenTermInSymbolNamesRule = defineRule19({
1727
1864
  meta: {
1728
1865
  type: "problem",
1729
1866
  docs: {
@@ -1752,12 +1889,12 @@ var noForbiddenTermInSymbolNamesRule = defineRule17({
1752
1889
  });
1753
1890
 
1754
1891
  // vendor/anti-slop/src/rules/no-unknown-parameters.ts
1755
- import { defineRule as defineRule18 } from "@oxlint/plugins";
1892
+ import { defineRule as defineRule20 } from "@oxlint/plugins";
1756
1893
  function isTypePredicateSubject(owner, parameterName) {
1757
1894
  const predicate = owner.returnType?.typeAnnotation;
1758
1895
  return predicate?.type === "TSTypePredicate" && predicate.parameterName.type === "Identifier" && predicate.parameterName.name === parameterName;
1759
1896
  }
1760
- var noUnknownParametersRule = defineRule18({
1897
+ var noUnknownParametersRule = defineRule20({
1761
1898
  meta: {
1762
1899
  type: "problem",
1763
1900
  docs: {
@@ -1801,8 +1938,8 @@ var noUnknownParametersRule = defineRule18({
1801
1938
  });
1802
1939
 
1803
1940
  // vendor/anti-slop/src/rules/no-unknown-returns.ts
1804
- import { defineRule as defineRule19 } from "@oxlint/plugins";
1805
- var noUnknownReturnsRule = defineRule19({
1941
+ import { defineRule as defineRule21 } from "@oxlint/plugins";
1942
+ var noUnknownReturnsRule = defineRule21({
1806
1943
  meta: {
1807
1944
  type: "problem",
1808
1945
  docs: {
@@ -1855,8 +1992,8 @@ var noUnknownReturnsRule = defineRule19({
1855
1992
  });
1856
1993
 
1857
1994
  // vendor/anti-slop/src/rules/no-unknown-type-aliases.ts
1858
- import { defineRule as defineRule20 } from "@oxlint/plugins";
1859
- var noUnknownTypeAliasesRule = defineRule20({
1995
+ import { defineRule as defineRule22 } from "@oxlint/plugins";
1996
+ var noUnknownTypeAliasesRule = defineRule22({
1860
1997
  meta: {
1861
1998
  type: "problem",
1862
1999
  docs: {
@@ -1894,7 +2031,7 @@ var noUnknownTypeAliasesRule = defineRule20({
1894
2031
  });
1895
2032
 
1896
2033
  // vendor/anti-slop/src/rules/no-unsafe-dictionary-type.ts
1897
- import { defineRule as defineRule21 } from "@oxlint/plugins";
2034
+ import { defineRule as defineRule23 } from "@oxlint/plugins";
1898
2035
  var typeNodeKinds = new Set([
1899
2036
  "JSDocNonNullableType",
1900
2037
  "JSDocNullableType",
@@ -1981,7 +2118,7 @@ function shouldReportType(node, environment) {
1981
2118
  }
1982
2119
  return true;
1983
2120
  }
1984
- var noUnsafeDictionaryTypeRule = defineRule21({
2121
+ var noUnsafeDictionaryTypeRule = defineRule23({
1985
2122
  meta: {
1986
2123
  type: "problem",
1987
2124
  docs: {
@@ -2023,7 +2160,7 @@ var noUnsafeDictionaryTypeRule = defineRule21({
2023
2160
  });
2024
2161
 
2025
2162
  // vendor/anti-slop/src/rules/no-widen-then-assert.ts
2026
- import { defineRule as defineRule22 } from "@oxlint/plugins";
2163
+ import { defineRule as defineRule24 } from "@oxlint/plugins";
2027
2164
  var functionBoundaryTypes = new Set([
2028
2165
  "ArrowFunctionExpression",
2029
2166
  "FunctionDeclaration",
@@ -2219,7 +2356,7 @@ function assertionIsNarrower(sourceText, broadKind, evidence, assertedType) {
2219
2356
  return isDefinitelyObjectType(assertedType);
2220
2357
  return isDefinitelyNarrowerRecordType(assertedType);
2221
2358
  }
2222
- var noWidenThenAssertRule = defineRule22({
2359
+ var noWidenThenAssertRule = defineRule24({
2223
2360
  meta: {
2224
2361
  type: "problem",
2225
2362
  docs: {
@@ -2781,7 +2918,7 @@ var requireReadableSpacingRule = {
2781
2918
  };
2782
2919
 
2783
2920
  // vendor/anti-slop/src/rules/require-safety-comment-for-type-assertion.ts
2784
- import { defineRule as defineRule23 } from "@oxlint/plugins";
2921
+ import { defineRule as defineRule25 } from "@oxlint/plugins";
2785
2922
  var DEFAULT_SAFETY_MARKERS = ["SAFETY"];
2786
2923
  var commentOwnerKinds = new Set([
2787
2924
  "ExpressionStatement",
@@ -2824,7 +2961,7 @@ function hasSafetyComment(sourceCode, node, pattern) {
2824
2961
  current = current.parent;
2825
2962
  }
2826
2963
  }
2827
- var requireSafetyCommentForTypeAssertionRule = defineRule23({
2964
+ var requireSafetyCommentForTypeAssertionRule = defineRule25({
2828
2965
  meta: {
2829
2966
  type: "problem",
2830
2967
  docs: {
@@ -2901,42 +3038,277 @@ var src_default = antiSlopPlugin;
2901
3038
  // src/generic/index.ts
2902
3039
  import { eslintCompatPlugin as eslintCompatPlugin4 } from "@oxlint/plugins";
2903
3040
 
2904
- // src/generic/rules/prefer-event-parameter-type.ts
2905
- import { defineRule as defineRule24 } from "@oxlint/plugins";
2906
- function nearestEnclosingFunction2(node) {
2907
- let current = node.parent;
2908
- while (current) {
2909
- if (current.type === "FunctionDeclaration" || current.type === "FunctionExpression" || current.type === "ArrowFunctionExpression") {
2910
- return current;
3041
+ // src/generic/rules/no-explicit-inferable-type-predicate.ts
3042
+ import { defineRule as defineRule26 } from "@oxlint/plugins";
3043
+ function isNamed(node, name) {
3044
+ return node.type === "Identifier" && node.name === name;
3045
+ }
3046
+ function isNullish(node) {
3047
+ return node.type === "Literal" && node.value === null || isNamed(node, "undefined");
3048
+ }
3049
+ function isNullishExclusion(node, name) {
3050
+ return node.type === "BinaryExpression" && (node.operator === "!==" || node.operator === "!=") && (isNamed(node.left, name) && isNullish(node.right) || isNullish(node.left) && isNamed(node.right, name));
3051
+ }
3052
+ function isTypeofCheck(node, name) {
3053
+ if (node.type !== "BinaryExpression" || node.operator !== "===" && node.operator !== "==") {
3054
+ return false;
3055
+ }
3056
+ const isTypeof = (side) => side.type === "UnaryExpression" && side.operator === "typeof" && isNamed(side.argument, name);
3057
+ const isLiteral = (side) => side.type === "Literal";
3058
+ return isTypeof(node.left) && isLiteral(node.right) || isLiteral(node.left) && isTypeof(node.right);
3059
+ }
3060
+ function isInferableCheck(node, name) {
3061
+ if (node.type === "LogicalExpression") {
3062
+ return node.operator === "&&" && isNullishExclusion(node.left, name) && isNullishExclusion(node.right, name);
3063
+ }
3064
+ return isNullishExclusion(node, name) || isTypeofCheck(node, name) || node.type === "BinaryExpression" && node.operator === "instanceof" && isNamed(node.left, name);
3065
+ }
3066
+ function returnedExpression(owner) {
3067
+ const body = owner.body;
3068
+ if (!body)
3069
+ return null;
3070
+ if (body.type !== "BlockStatement")
3071
+ return body;
3072
+ const [statement] = body.body;
3073
+ return body.body.length === 1 && statement?.type === "ReturnStatement" ? statement.argument : null;
3074
+ }
3075
+ function isPublicSignature(owner) {
3076
+ const parent = owner.parent;
3077
+ if (parent.type === "MethodDefinition" || parent.type === "ExportNamedDeclaration" || parent.type === "ExportDefaultDeclaration") {
3078
+ return true;
3079
+ }
3080
+ return parent.type === "VariableDeclarator" && parent.parent.parent?.type === "ExportNamedDeclaration";
3081
+ }
3082
+ var noExplicitInferableTypePredicateRule = defineRule26({
3083
+ meta: {
3084
+ type: "suggestion",
3085
+ docs: {
3086
+ description: "Disallow explicit type predicates on simple null, typeof, or instanceof checks that TypeScript 5.5+ infers."
3087
+ },
3088
+ messages: {
3089
+ removeTypePredicate: "TypeScript infers the type predicate for `{{parameter}}` from this check, while an explicit predicate is never checked against the body. Remove the annotation and rely on the inferred predicate."
2911
3090
  }
2912
- current = current.parent;
3091
+ },
3092
+ create(context) {
3093
+ const check = (owner) => {
3094
+ const annotation = owner.returnType?.typeAnnotation;
3095
+ if (annotation?.type !== "TSTypePredicate" || annotation.asserts || annotation.parameterName.type !== "Identifier" || isPublicSignature(owner)) {
3096
+ return;
3097
+ }
3098
+ const parameter = annotation.parameterName.name;
3099
+ const expression = returnedExpression(owner);
3100
+ if (!owner.params.some((param) => isNamed(param, parameter)) || !expression || !isInferableCheck(expression, parameter)) {
3101
+ return;
3102
+ }
3103
+ context.report({
3104
+ node: annotation,
3105
+ messageId: "removeTypePredicate",
3106
+ data: { parameter }
3107
+ });
3108
+ };
3109
+ return {
3110
+ ArrowFunctionExpression: check,
3111
+ FunctionDeclaration: check,
3112
+ FunctionExpression: check
3113
+ };
3114
+ }
3115
+ });
3116
+
3117
+ // src/generic/rules/no-unchecked-query-selector-type.ts
3118
+ import { defineRule as defineRule27 } from "@oxlint/plugins";
3119
+
3120
+ // src/shared/json.ts
3121
+ function jsonObject(value) {
3122
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
3123
+ }
3124
+
3125
+ // src/shared/lit.ts
3126
+ var renderRoots = new Set(["renderRoot", "shadowRoot"]);
3127
+ function litElementBaseClasses(settings) {
3128
+ const configured = jsonObject(settings.lit)?.elementBaseClasses;
3129
+ return new Set([
3130
+ "LitElement",
3131
+ ...Array.isArray(configured) ? configured.map(String) : []
3132
+ ]);
3133
+ }
3134
+ function isWrapperExpression(node) {
3135
+ return node?.type === "ChainExpression" || node?.type === "ParenthesizedExpression" || node?.type === "TSAsExpression" || node?.type === "TSNonNullExpression" || node?.type === "TSSatisfiesExpression" || node?.type === "TSTypeAssertion";
3136
+ }
3137
+ function unwrapExpression2(node) {
3138
+ let current = node;
3139
+ while (isWrapperExpression(current))
3140
+ current = current.expression;
3141
+ return current;
3142
+ }
3143
+ function extendsLitBase(node, bases) {
3144
+ if (node.type === "Identifier")
3145
+ return bases.has(node.name);
3146
+ return node.type === "CallExpression" && node.arguments.some((argument) => extendsLitBase(argument, bases));
3147
+ }
3148
+ function isLitClass(node, bases) {
3149
+ const hasCustomElementDecorator = node.decorators.some((decorator) => decorator.expression.type === "CallExpression" && decorator.expression.callee.type === "Identifier" && decorator.expression.callee.name === "customElement");
3150
+ return hasCustomElementDecorator || node.superClass !== null && extendsLitBase(node.superClass, bases);
3151
+ }
3152
+ function classOfBody(body) {
3153
+ const owner = body.parent;
3154
+ return owner?.type === "ClassDeclaration" || owner?.type === "ClassExpression" ? owner : null;
3155
+ }
3156
+ function thisClass(node) {
3157
+ let current = node;
3158
+ while (current.parent) {
3159
+ const parent = current.parent;
3160
+ if (parent.type === "FunctionDeclaration" || parent.type === "FunctionExpression") {
3161
+ const owner = parent.parent;
3162
+ return (owner?.type === "MethodDefinition" || owner?.type === "TSAbstractMethodDefinition") && !owner.static && owner.value === parent ? classOfBody(owner.parent) : null;
3163
+ }
3164
+ if ((parent.type === "PropertyDefinition" || parent.type === "AccessorProperty") && parent.value === current) {
3165
+ return parent.static ? null : classOfBody(parent.parent);
3166
+ }
3167
+ if (parent.type === "StaticBlock" || parent.type === "ClassBody" || parent.type === "Program") {
3168
+ return null;
3169
+ }
3170
+ current = parent;
2913
3171
  }
2914
3172
  return null;
2915
3173
  }
2916
- function assertedEventParameter(node) {
2917
- const expression = node.expression;
2918
- if (expression.type !== "MemberExpression" || expression.computed || expression.object.type !== "Identifier" || expression.property.type !== "Identifier" || expression.property.name !== "currentTarget" && expression.property.name !== "target") {
3174
+ function isStaticSelector(node) {
3175
+ return node?.type === "Literal" || node?.type === "TemplateLiteral" && node.expressions.length === 0;
3176
+ }
3177
+ function renderRootQuery(node, bases) {
3178
+ const method = staticMemberName(node.callee);
3179
+ if (method !== "querySelector" && method !== "querySelectorAll" || node.callee.type !== "MemberExpression" || !isStaticSelector(node.arguments[0])) {
2919
3180
  return null;
2920
3181
  }
2921
- const parameterName = expression.object.name;
2922
- const property = expression.property.name;
2923
- const owner = nearestEnclosingFunction2(node);
2924
- if (!owner?.params.some((parameter) => parameter.type === "Identifier" && parameter.name === parameterName)) {
3182
+ const receiver = unwrapExpression2(node.callee.object);
3183
+ const root = staticMemberName(receiver);
3184
+ if (!root || !renderRoots.has(root) || receiver.type !== "MemberExpression" || receiver.object.type !== "ThisExpression") {
3185
+ return null;
3186
+ }
3187
+ const owner = thisClass(receiver.object);
3188
+ return owner && isLitClass(owner, bases) ? { method, root } : null;
3189
+ }
3190
+ function isAssignedMethod(name) {
3191
+ return name === "assignedElements" || name === "assignedNodes";
3192
+ }
3193
+ function feedsAssignedCall(node) {
3194
+ let current = node;
3195
+ while (isWrapperExpression(current.parent))
3196
+ current = current.parent;
3197
+ const member = current.parent;
3198
+ return member?.type === "MemberExpression" && member.object === current && isAssignedMethod(staticMemberName(member));
3199
+ }
3200
+ function litQueryDecoratorCall(node, bases) {
3201
+ const method = staticMemberName(node.callee);
3202
+ if (!isAssignedMethod(method)) {
3203
+ return feedsAssignedCall(node) ? null : renderRootQuery(node, bases);
3204
+ }
3205
+ if (node.callee.type !== "MemberExpression")
3206
+ return null;
3207
+ const inner = unwrapExpression2(node.callee.object);
3208
+ if (inner.type !== "CallExpression")
3209
+ return null;
3210
+ const query = renderRootQuery(inner, bases);
3211
+ return query?.method === "querySelector" ? { method, root: query.root } : null;
3212
+ }
3213
+ function isLitRenderRootQuery(node, bases) {
3214
+ return renderRootQuery(node, bases) !== null;
3215
+ }
3216
+
3217
+ // src/generic/rules/no-unchecked-query-selector-type.ts
3218
+ var queryMethods = new Set(["closest", "querySelector", "querySelectorAll"]);
3219
+ var noUncheckedQuerySelectorTypeRule = defineRule27({
3220
+ meta: {
3221
+ type: "problem",
3222
+ docs: {
3223
+ description: "Disallow type arguments on `querySelector`, `querySelectorAll`, and `closest`, which cast the result without checking it."
3224
+ },
3225
+ messages: {
3226
+ checkQueryResult: "`{{method}}<T>` casts the result without checking it. Check it with `instanceof`, use a checked lookup helper, or query a tag name so TypeScript infers the element type."
3227
+ }
3228
+ },
3229
+ create(context) {
3230
+ const bases = litElementBaseClasses(context.settings);
3231
+ return {
3232
+ CallExpression(node) {
3233
+ const method = staticMemberName(node.callee);
3234
+ if (!node.typeArguments || !method || !queryMethods.has(method) || isLitRenderRootQuery(node, bases)) {
3235
+ return;
3236
+ }
3237
+ context.report({
3238
+ node: node.typeArguments,
3239
+ messageId: "checkQueryResult",
3240
+ data: { method }
3241
+ });
3242
+ }
3243
+ };
3244
+ }
3245
+ });
3246
+
3247
+ // src/generic/rules/no-untyped-custom-event.ts
3248
+ import { defineRule as defineRule28 } from "@oxlint/plugins";
3249
+ var noUntypedCustomEventRule = defineRule28({
3250
+ meta: {
3251
+ type: "problem",
3252
+ docs: {
3253
+ description: "Disallow `CustomEvent` type references without a detail type, which leave `detail` as `any`."
3254
+ },
3255
+ messages: {
3256
+ typeCustomEventDetail: "`CustomEvent` without a type argument leaves `detail` as `any`. Reuse the project's typed event helper if one fits, or add one, instead of a bare `CustomEvent`."
3257
+ }
3258
+ },
3259
+ create(context) {
3260
+ return {
3261
+ TSTypeReference(node) {
3262
+ if (node.typeName.type !== "Identifier" || node.typeName.name !== "CustomEvent" || node.typeArguments) {
3263
+ return;
3264
+ }
3265
+ context.report({ node, messageId: "typeCustomEventDetail" });
3266
+ }
3267
+ };
3268
+ }
3269
+ });
3270
+
3271
+ // src/generic/rules/prefer-event-parameter-type.ts
3272
+ import { defineRule as defineRule29 } from "@oxlint/plugins";
3273
+ function staticMemberPath(node) {
3274
+ const path = [];
3275
+ let current = node.type === "ChainExpression" ? node.expression : node;
3276
+ while (current.type === "MemberExpression") {
3277
+ if (current.computed || current.property.type !== "Identifier") {
3278
+ return null;
3279
+ }
3280
+ path.unshift(current.property.name);
3281
+ current = current.object;
3282
+ }
3283
+ return current.type === "Identifier" && path.length > 0 ? { root: current.name, path } : null;
3284
+ }
3285
+ function isEventMemberPath(path) {
3286
+ const [first] = path;
3287
+ if (first === "detail")
3288
+ return true;
3289
+ return path.length === 1 && (first === "currentTarget" || first === "target");
3290
+ }
3291
+ function assertedEventParameter(node) {
3292
+ const member = staticMemberPath(node.expression);
3293
+ if (!member || !isEventMemberPath(member.path))
3294
+ return null;
3295
+ const owner = nearestEnclosingFunction(node);
3296
+ if (!owner?.params.some((parameter) => parameter.type === "Identifier" && parameter.name === member.root)) {
2925
3297
  return null;
2926
3298
  }
2927
3299
  return {
2928
- parameter: parameterName,
2929
- property
3300
+ parameter: member.root,
3301
+ property: member.path.join(".")
2930
3302
  };
2931
3303
  }
2932
- var preferEventParameterTypeRule = defineRule24({
3304
+ var preferEventParameterTypeRule = defineRule29({
2933
3305
  meta: {
2934
3306
  type: "suggestion",
2935
3307
  docs: {
2936
- description: "Prefer typing event target properties in the handler parameter instead of asserting them at use sites."
3308
+ description: "Prefer typing event target and detail properties in the handler parameter instead of asserting them at use sites."
2937
3309
  },
2938
3310
  messages: {
2939
- typeEventParameter: "Type `{{parameter}}.{{property}}` in the function signature instead of asserting it at the use site."
3311
+ typeEventParameter: "Type `{{parameter}}.{{property}}` in the function signature instead of asserting it at the use site. Reuse the project's typed event helper if one fits, or add one."
2940
3312
  }
2941
3313
  },
2942
3314
  create(context) {
@@ -2957,9 +3329,69 @@ var preferEventParameterTypeRule = defineRule24({
2957
3329
  }
2958
3330
  });
2959
3331
 
3332
+ // src/generic/rules/prefer-lit-query-decorators.ts
3333
+ import { defineRule as defineRule30 } from "@oxlint/plugins";
3334
+ var messageIds = {
3335
+ assignedElements: "preferQueryAssignedElements",
3336
+ assignedNodes: "preferQueryAssignedNodes",
3337
+ querySelector: "preferQuery",
3338
+ querySelectorAll: "preferQueryAll"
3339
+ };
3340
+ var preferLitQueryDecoratorsRule = defineRule30({
3341
+ meta: {
3342
+ type: "suggestion",
3343
+ docs: {
3344
+ description: "Require Lit query decorators instead of static render-root queries in Lit elements."
3345
+ },
3346
+ schema: [
3347
+ {
3348
+ type: "object",
3349
+ properties: {
3350
+ querySelector: { type: "boolean" },
3351
+ querySelectorAll: { type: "boolean" },
3352
+ assignedElements: { type: "boolean" },
3353
+ assignedNodes: { type: "boolean" }
3354
+ },
3355
+ additionalProperties: false
3356
+ }
3357
+ ],
3358
+ defaultOptions: [
3359
+ {
3360
+ querySelector: true,
3361
+ querySelectorAll: true,
3362
+ assignedElements: true,
3363
+ assignedNodes: true
3364
+ }
3365
+ ],
3366
+ messages: {
3367
+ preferQuery: "Use the @query decorator instead of this.{{root}}.querySelector().",
3368
+ preferQueryAll: "Use the @queryAll decorator instead of this.{{root}}.querySelectorAll().",
3369
+ preferQueryAssignedElements: "Use the @queryAssignedElements decorator instead of this.{{root}}.querySelector().assignedElements().",
3370
+ preferQueryAssignedNodes: "Use the @queryAssignedNodes decorator instead of this.{{root}}.querySelector().assignedNodes()."
3371
+ }
3372
+ },
3373
+ create(context) {
3374
+ const bases = litElementBaseClasses(context.settings);
3375
+ const options = jsonObject(context.options[0]);
3376
+ const disabled = new Set(options ? Object.keys(options).filter((method) => options[method] === false) : []);
3377
+ return {
3378
+ CallExpression(node) {
3379
+ const query = litQueryDecoratorCall(node, bases);
3380
+ if (!query || disabled.has(query.method))
3381
+ return;
3382
+ context.report({
3383
+ node,
3384
+ messageId: messageIds[query.method],
3385
+ data: { root: query.root }
3386
+ });
3387
+ }
3388
+ };
3389
+ }
3390
+ });
3391
+
2960
3392
  // src/generic/rules/prefer-types-over-assertions.ts
2961
- import { defineRule as defineRule25 } from "@oxlint/plugins";
2962
- var preferTypesOverAssertionsRule = defineRule25({
3393
+ import { defineRule as defineRule31 } from "@oxlint/plugins";
3394
+ var preferTypesOverAssertionsRule = defineRule31({
2963
3395
  meta: {
2964
3396
  type: "problem",
2965
3397
  docs: {
@@ -2971,7 +3403,7 @@ var preferTypesOverAssertionsRule = defineRule25({
2971
3403
  },
2972
3404
  create(context) {
2973
3405
  const checkAssertion = (node) => {
2974
- if (node.typeAnnotation.type === "TSTypeReference" && node.typeAnnotation.typeName.type === "Identifier" && node.typeAnnotation.typeName.name === "const") {
3406
+ if (node.typeAnnotation.type === "TSTypeReference" && node.typeAnnotation.typeName.type === "Identifier" && node.typeAnnotation.typeName.name === "const" || assertedEventParameter(node)) {
2975
3407
  return;
2976
3408
  }
2977
3409
  context.report({ node, messageId: "avoidAssertion" });
@@ -2987,7 +3419,11 @@ var preferTypesOverAssertionsRule = defineRule25({
2987
3419
  var timmoPlugin = eslintCompatPlugin4({
2988
3420
  meta: { name: "timmo" },
2989
3421
  rules: {
3422
+ "no-explicit-inferable-type-predicate": noExplicitInferableTypePredicateRule,
3423
+ "no-unchecked-query-selector-type": noUncheckedQuerySelectorTypeRule,
3424
+ "no-untyped-custom-event": noUntypedCustomEventRule,
2990
3425
  "prefer-event-parameter-type": preferEventParameterTypeRule,
3426
+ "prefer-lit-query-decorators": preferLitQueryDecoratorsRule,
2991
3427
  "prefer-types-over-assertions": preferTypesOverAssertionsRule
2992
3428
  }
2993
3429
  });
@@ -3005,7 +3441,11 @@ var recommended = defineConfig({
3005
3441
  rules: {
3006
3442
  ...enablePluginRules("anti-slop", src_default),
3007
3443
  ...enablePluginRules("timmo", generic_default),
3008
- "anti-slop/require-safety-comment-for-type-assertion": "off"
3444
+ "anti-slop/require-safety-comment-for-type-assertion": "off",
3445
+ "typescript/no-non-null-assertion": "error",
3446
+ "typescript/no-unnecessary-type-arguments": "error",
3447
+ "typescript/no-unnecessary-type-assertion": "error",
3448
+ "typescript/no-unnecessary-type-parameters": "error"
3009
3449
  }
3010
3450
  });
3011
3451
  var recommended_default = recommended;