@sarj/eslint-plugin 15.17.9 → 15.17.10

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/index.js CHANGED
@@ -2406,7 +2406,7 @@ var no_duplicate_lifecycle_refresh_listeners_default = createRule({
2406
2406
  VariableDeclarator(node) {
2407
2407
  if (node.id.type !== AST_NODE_TYPES9.Identifier) return;
2408
2408
  const variable = ASTUtils3.findVariable(context.sourceCode.getScope(node.id), node.id.name);
2409
- if (variable === null) return;
2409
+ if (variable === null || variable.references.some((reference) => reference.isWrite() && !reference.init)) return;
2410
2410
  if (node.init?.type === AST_NODE_TYPES9.ArrowFunctionExpression || node.init?.type === AST_NODE_TYPES9.FunctionExpression) {
2411
2411
  functionCallbacks.set(node.init, variable);
2412
2412
  }
@@ -2417,7 +2417,7 @@ var no_duplicate_lifecycle_refresh_listeners_default = createRule({
2417
2417
  FunctionDeclaration(node) {
2418
2418
  if (node.id === null) return;
2419
2419
  const variable = ASTUtils3.findVariable(context.sourceCode.getScope(node.id), node.id.name);
2420
- if (variable !== null) functionCallbacks.set(node, variable);
2420
+ if (variable !== null && !variable.references.some((reference) => reference.isWrite() && !reference.init)) functionCallbacks.set(node, variable);
2421
2421
  },
2422
2422
  CallExpression(node) {
2423
2423
  const item = registration(context.sourceCode, node);
@@ -4434,105 +4434,9 @@ import * as ts from "typescript";
4434
4434
  import {
4435
4435
  AST_NODE_TYPES as AST_NODE_TYPES16
4436
4436
  } from "@typescript-eslint/utils";
4437
- function symbolAt(services, checker, node) {
4438
- return checker.getSymbolAtLocation(services.esTreeNodeToTSNodeMap.get(node));
4439
- }
4440
- function sameSymbol(left, right) {
4441
- return left !== void 0 && right !== void 0 && left === right;
4442
- }
4443
- function enclosingClass(node) {
4444
- let current = node.parent;
4445
- while (current !== void 0) {
4446
- if (current.type === AST_NODE_TYPES16.ClassDeclaration || current.type === AST_NODE_TYPES16.ClassExpression) {
4447
- return current;
4448
- }
4449
- current = current.parent;
4450
- }
4451
- return null;
4452
- }
4453
4437
  function memberName2(member) {
4454
4438
  return !member.computed && member.key.type === AST_NODE_TYPES16.Identifier ? member.key.name : null;
4455
4439
  }
4456
- function privateMemberFixes(context, services, owner, members, removePrivateKeyword) {
4457
- const first = members[0];
4458
- const name = first === void 0 ? null : memberName2(first);
4459
- if (first === void 0 || name === null || members.some((member) => member.static || member.decorators.length > 0)) {
4460
- return void 0;
4461
- }
4462
- if (owner.body.body.some((member) => {
4463
- if (member.type !== AST_NODE_TYPES16.MethodDefinition && member.type !== AST_NODE_TYPES16.PropertyDefinition && member.type !== AST_NODE_TYPES16.AccessorProperty) return false;
4464
- return member.key.type === AST_NODE_TYPES16.PrivateIdentifier && member.key.name === name;
4465
- })) return void 0;
4466
- const selectedMembers = new Set(members);
4467
- if (owner.body.body.some((member) => {
4468
- if (member.type !== AST_NODE_TYPES16.MethodDefinition && member.type !== AST_NODE_TYPES16.PropertyDefinition && member.type !== AST_NODE_TYPES16.AccessorProperty) return false;
4469
- return memberName2(member) === name && !selectedMembers.has(member);
4470
- })) return void 0;
4471
- const checker = services.program.getTypeChecker();
4472
- const symbols = members.map((member) => symbolAt(services, checker, member.key)).filter(
4473
- (symbol) => symbol !== void 0
4474
- );
4475
- if (symbols.length === 0) return void 0;
4476
- const references = [];
4477
- let unsafe = false;
4478
- walk(context.sourceCode.ast, context.sourceCode.visitorKeys, (node) => {
4479
- if (node.type === AST_NODE_TYPES16.Literal && node.value === name) {
4480
- unsafe = true;
4481
- return;
4482
- }
4483
- if (node.type !== AST_NODE_TYPES16.MemberExpression) return;
4484
- const propertyName6 = node.property.type === AST_NODE_TYPES16.Identifier || node.property.type === AST_NODE_TYPES16.PrivateIdentifier ? node.property.name : node.property.type === AST_NODE_TYPES16.Literal && typeof node.property.value === "string" ? node.property.value : null;
4485
- if (propertyName6 !== name) return;
4486
- const propertySymbol = symbolAt(services, checker, node.property);
4487
- if (node.computed || node.property.type !== AST_NODE_TYPES16.Identifier || node.object.type !== AST_NODE_TYPES16.ThisExpression || enclosingClass(node) !== owner || !symbols.some((symbol) => sameSymbol(symbol, propertySymbol))) {
4488
- unsafe = true;
4489
- return;
4490
- }
4491
- references.push(node);
4492
- });
4493
- if (unsafe) return void 0;
4494
- const privateKeywordRanges = /* @__PURE__ */ new Map();
4495
- if (removePrivateKeyword) {
4496
- const comments = context.sourceCode.getAllComments();
4497
- for (const member of members) {
4498
- const keyword = context.sourceCode.getTokens(member).find((token) => token.value === "private");
4499
- const next = keyword === void 0 ? void 0 : context.sourceCode.getTokenAfter(keyword);
4500
- if (keyword === void 0 || next === null || next === void 0) return void 0;
4501
- if (comments.some((comment) => comment.range[0] >= keyword.range[1] && comment.range[1] <= next.range[0])) {
4502
- return void 0;
4503
- }
4504
- privateKeywordRanges.set(member, [keyword.range[0], next.range[0]]);
4505
- }
4506
- }
4507
- return (fixer) => {
4508
- const fixes = [];
4509
- for (const member of members) {
4510
- fixes.push(fixer.replaceText(member.key, `#${name}`));
4511
- if (removePrivateKeyword) {
4512
- const range = privateKeywordRanges.get(member);
4513
- if (range === void 0) return [];
4514
- fixes.push(fixer.removeRange(range));
4515
- }
4516
- }
4517
- for (const reference of references) fixes.push(fixer.replaceText(reference.property, `#${name}`));
4518
- return fixes;
4519
- };
4520
- }
4521
- function walk(node, visitorKeys, visit) {
4522
- visit(node);
4523
- for (const key of visitorKeys[node.type] ?? []) {
4524
- const child = node[key];
4525
- if (Array.isArray(child)) {
4526
- for (const item of child) {
4527
- if (typeof item === "object" && item !== null && "type" in item) {
4528
- walk(item, visitorKeys, visit);
4529
- }
4530
- }
4531
- } else if (typeof child === "object" && child !== null && "type" in child) {
4532
- walk(child, visitorKeys, visit);
4533
- }
4534
- }
4535
- }
4536
4440
  function convertibleMemberName(member) {
4537
4441
  if (member.type !== AST_NODE_TYPES16.MethodDefinition && member.type !== AST_NODE_TYPES16.PropertyDefinition && member.type !== AST_NODE_TYPES16.AccessorProperty) return null;
4538
4442
  return memberName2(member);
@@ -5337,9 +5241,9 @@ var NO_GENERIC_SINGLE_EXPORT_MODULE_DOCUMENTATION = {
5337
5241
  rationale: "A generic filename hides the sole exported responsibility and makes navigation less descriptive.",
5338
5242
  remediation: "Choose a responsibility-bearing module name or colocate the export with its domain.",
5339
5243
  category: "maintainability",
5340
- limitations: ["Only configured generic stems with exactly one public runtime export are reported."],
5244
+ limitations: ["Only the fixed generic-stem vocabulary with exactly one public runtime export is checked; exported destructuring patterns are excluded rather than undercounted."],
5341
5245
  examples: [
5342
- { id: "responsibility-named-module", title: "Name the module after its export", outcome: "no-match", files: [{ path: "src/order-parser.ts", source: "export function parseOrder() { return {}; }" }], focusPath: "src/order-parser.ts", expectedCount: 0, public: true },
5246
+ { id: "responsibility-named-module", title: "Name the module after its export", outcome: "no-match", files: [{ path: "src/parse-order.ts", source: "export function parseOrder() { return {}; }" }], focusPath: "src/parse-order.ts", expectedCount: 0, public: true },
5343
5247
  { id: "generic-module-name", title: "Do not hide one export in a generic module", outcome: "match", files: [{ path: "src/utils.ts", source: "export function parseOrder() { return {}; }" }], focusPath: "src/utils.ts", expectedCount: 1, public: true }
5344
5248
  ]
5345
5249
  };
@@ -5400,6 +5304,7 @@ function runtimeExports(program) {
5400
5304
  }
5401
5305
  if (statement.declaration !== null) {
5402
5306
  const declaration = statement.declaration;
5307
+ if (declaration.type === AST_NODE_TYPES22.VariableDeclaration && declaration.declarations.some((item) => item.id.type !== AST_NODE_TYPES22.Identifier)) ambiguous = true;
5403
5308
  exports.push(...declaredNames(declaration).map((name) => ({ key: name, name, node: declaration })));
5404
5309
  }
5405
5310
  for (const specifier of statement.specifiers) {
@@ -5558,7 +5463,7 @@ var no_offset_pagination_default = createRule({
5558
5463
  });
5559
5464
 
5560
5465
  // src/rules/no-positional-tuple-return.ts
5561
- import { AST_NODE_TYPES as AST_NODE_TYPES23 } from "@typescript-eslint/utils";
5466
+ import { AST_NODE_TYPES as AST_NODE_TYPES23, ASTUtils as ASTUtils9 } from "@typescript-eslint/utils";
5562
5467
  var NO_POSITIONAL_TUPLE_RETURN_DOCUMENTATION = {
5563
5468
  summary: "Disallow returning a multi-field tuple from a named function; return a named object so call sites cannot mismatch slots.",
5564
5469
  rationale: "Tuple fields are identified only by position, so reordering can preserve types while changing meaning.",
@@ -5588,7 +5493,7 @@ function tupleReturnType(node, aliases, resolving = /* @__PURE__ */ new Set()) {
5588
5493
  return argument === void 0 ? null : tupleReturnType(argument, aliases, resolving);
5589
5494
  }
5590
5495
  if (node.type === AST_NODE_TYPES23.TSTypeReference && node.typeName.type === AST_NODE_TYPES23.Identifier && !resolving.has(node.typeName.name)) {
5591
- const target = aliases.get(node.typeName.name);
5496
+ const target = aliases.get(node.typeName);
5592
5497
  if (target !== void 0) return tupleReturnType(target, aliases, /* @__PURE__ */ new Set([...resolving, node.typeName.name]));
5593
5498
  }
5594
5499
  if (node.type === AST_NODE_TYPES23.TSTypeOperator && node.operator === "readonly") {
@@ -5680,20 +5585,27 @@ function exportedTypeNames(program) {
5680
5585
  }
5681
5586
  return names;
5682
5587
  }
5683
- function typeAliases(program) {
5588
+ function typeAliases(sourceCode) {
5684
5589
  const aliases = /* @__PURE__ */ new Map();
5685
- for (const statement of program.body) {
5590
+ for (const statement of sourceCode.ast.body) {
5686
5591
  const declaration = statement.type === AST_NODE_TYPES23.ExportNamedDeclaration ? statement.declaration : statement;
5687
5592
  if (declaration?.type === AST_NODE_TYPES23.TSTypeAliasDeclaration) {
5688
- aliases.set(declaration.id.name, declaration.typeAnnotation);
5593
+ aliases.set(declaration.id.name, declaration);
5689
5594
  }
5690
5595
  }
5691
- return aliases;
5596
+ return {
5597
+ get(identifier) {
5598
+ const declaration = aliases.get(identifier.name);
5599
+ if (declaration === void 0) return void 0;
5600
+ const binding = ASTUtils9.findVariable(sourceCode.getScope(identifier), identifier.name);
5601
+ return binding?.defs.length === 1 && binding.defs[0]?.node === declaration ? declaration.typeAnnotation : void 0;
5602
+ }
5603
+ };
5692
5604
  }
5693
5605
  function callableReturnType(node, aliases, resolving = /* @__PURE__ */ new Set()) {
5694
5606
  if (node.type === AST_NODE_TYPES23.TSFunctionType) return node.returnType?.typeAnnotation ?? null;
5695
5607
  if (node.type === AST_NODE_TYPES23.TSTypeReference && node.typeName.type === AST_NODE_TYPES23.Identifier && !resolving.has(node.typeName.name)) {
5696
- const target = aliases.get(node.typeName.name);
5608
+ const target = aliases.get(node.typeName);
5697
5609
  if (target !== void 0) {
5698
5610
  return callableReturnType(target, aliases, /* @__PURE__ */ new Set([...resolving, node.typeName.name]));
5699
5611
  }
@@ -5822,7 +5734,7 @@ var no_positional_tuple_return_default = createRule({
5822
5734
  context.sourceCode.ast,
5823
5735
  exportedTypeNames(context.sourceCode.ast)
5824
5736
  );
5825
- const aliases = typeAliases(context.sourceCode.ast);
5737
+ const aliases = typeAliases(context.sourceCode);
5826
5738
  const reportedFunctions = /* @__PURE__ */ new WeakSet();
5827
5739
  const functionStack = [];
5828
5740
  const report2 = (annotation, name) => {
@@ -5986,7 +5898,7 @@ var no_production_browser_source_maps_default = createRule({
5986
5898
  });
5987
5899
 
5988
5900
  // src/rules/no-raw-env.ts
5989
- import { ASTUtils as ASTUtils9 } from "@typescript-eslint/utils";
5901
+ import { ASTUtils as ASTUtils10 } from "@typescript-eslint/utils";
5990
5902
  var NO_RAW_ENV_DOCUMENTATION = {
5991
5903
  summary: "Disallow direct `process.env` and `import.meta.env` reads outside validated boundaries.",
5992
5904
  rationale: "Raw environment reads are untyped and defer invalid configuration failures until use.",
@@ -6068,7 +5980,7 @@ var no_raw_env_default = createRule({
6068
5980
  },
6069
5981
  MemberExpression(node) {
6070
5982
  if (isProcessEnv(node) && node.object.type === "Identifier") {
6071
- const binding = ASTUtils9.findVariable(context.sourceCode.getScope(node), node.object.name);
5983
+ const binding = ASTUtils10.findVariable(context.sourceCode.getScope(node), node.object.name);
6072
5984
  if (binding !== null && binding.defs.length > 0 && !binding.defs.every((definition) => definition.type === "ImportBinding" && definition.parent.type === "ImportDeclaration" && ["node:process", "process"].includes(definition.parent.source.value) && ["ImportDefaultSpecifier", "ImportNamespaceSpecifier"].includes(definition.node.type))) return;
6073
5985
  }
6074
5986
  if ((isProcessEnv(node) || isImportMetaEnv(node)) && !isExemptVariableAccess(node) && !isWriteTarget(node) && !isWholeEnvSpread(node)) {
@@ -6084,7 +5996,7 @@ var no_raw_env_default = createRule({
6084
5996
  });
6085
5997
 
6086
5998
  // src/rules/no-raw-fetch-outside-clients.ts
6087
- import { AST_NODE_TYPES as AST_NODE_TYPES24, ASTUtils as ASTUtils10 } from "@typescript-eslint/utils";
5999
+ import { AST_NODE_TYPES as AST_NODE_TYPES24, ASTUtils as ASTUtils11 } from "@typescript-eslint/utils";
6088
6000
  var NO_RAW_FETCH_OUTSIDE_CLIENTS_DOCUMENTATION = {
6089
6001
  summary: "Disallow calling the global `fetch` outside the client layer; route outbound HTTP through a client module that owns retry, timeout and status handling.",
6090
6002
  rationale: "Scattered fetch calls bypass shared transport policy and are harder to stub and observe consistently.",
@@ -6272,7 +6184,7 @@ var no_raw_fetch_outside_clients_default = createRule({
6272
6184
  internalApiPrefixes.push(`${options.basePath}/api`);
6273
6185
  }
6274
6186
  function resolvesToGlobal(identifier) {
6275
- const variable = ASTUtils10.findVariable(
6187
+ const variable = ASTUtils11.findVariable(
6276
6188
  context.sourceCode.getScope(identifier),
6277
6189
  identifier.name
6278
6190
  );
@@ -6281,7 +6193,7 @@ var no_raw_fetch_outside_clients_default = createRule({
6281
6193
  function resolveNode2(node) {
6282
6194
  if (node === void 0) return null;
6283
6195
  if (node.type !== AST_NODE_TYPES24.Identifier) return node;
6284
- const variable = ASTUtils10.findVariable(
6196
+ const variable = ASTUtils11.findVariable(
6285
6197
  context.sourceCode.getScope(node),
6286
6198
  node.name
6287
6199
  );
@@ -6360,13 +6272,13 @@ var no_raw_fetch_outside_clients_default = createRule({
6360
6272
  });
6361
6273
 
6362
6274
  // src/rules/no-restricted-library-load.ts
6363
- import { AST_NODE_TYPES as AST_NODE_TYPES25, ASTUtils as ASTUtils11 } from "@typescript-eslint/utils";
6275
+ import { AST_NODE_TYPES as AST_NODE_TYPES25, ASTUtils as ASTUtils12 } from "@typescript-eslint/utils";
6364
6276
  var NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION = {
6365
- summary: "Apply a configured library-replacement policy to literal dynamic imports, CommonJS loads, and TypeScript import-equals declarations.",
6366
- rationale: "Runtime module loads can bypass the replacement policy enforced for static imports.",
6367
- remediation: "Load the configured replacement library instead of the restricted module.",
6277
+ summary: "Apply configured library restrictions to literal runtime loads and CommonJS resolution references.",
6278
+ rationale: "Dynamic imports, CommonJS loads, and package resolution checks can bypass library restrictions enforced for static imports.",
6279
+ remediation: "Use the configured replacement for the runtime dependency reference; resolution checks do not themselves load a module.",
6368
6280
  category: "architecture",
6369
- limitations: ["Only literal dynamic imports, unshadowed CommonJS loads, and TypeScript import-equals declarations are checked."],
6281
+ limitations: ["Only literal dynamic imports, unshadowed CommonJS loads/resolution calls, and runtime TypeScript import-equals declarations are checked; erased type imports are excluded. A configured restriction list is required."],
6370
6282
  examples: [
6371
6283
  { id: "static-import", title: "Static imports remain the static-import rule's responsibility", outcome: "no-match", files: [{ path: "src/client.ts", source: "import axios from 'axios';" }], focusPath: "src/client.ts", expectedCount: 0, public: true },
6372
6284
  { id: "runtime-load", title: "Do not load a restricted library at runtime", outcome: "match", files: [{ path: "src/client.ts", source: "const client = require('axios');" }], focusPath: "src/client.ts", expectedCount: 1, public: true }
@@ -6384,7 +6296,7 @@ var no_restricted_library_load_default = createRule({
6384
6296
  meta: {
6385
6297
  type: "problem",
6386
6298
  docs: {
6387
- description: "Apply a configured library-replacement policy to literal dynamic imports, CommonJS loads, and TypeScript import-equals declarations."
6299
+ description: NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION.summary
6388
6300
  },
6389
6301
  schema: [
6390
6302
  {
@@ -6410,7 +6322,7 @@ var no_restricted_library_load_default = createRule({
6410
6322
  }
6411
6323
  ],
6412
6324
  messages: {
6413
- restrictedLibraryLoad: "{{id}}: Replace runtime loading of {{module}} with {{replacement}}.{{note}}"
6325
+ restrictedLibraryLoad: "{{id}}: Replace this runtime dependency reference to {{module}} with {{replacement}}.{{note}}"
6414
6326
  }
6415
6327
  },
6416
6328
  defaultOptions: [{ libraries: [] }],
@@ -6433,7 +6345,7 @@ var no_restricted_library_load_default = createRule({
6433
6345
  });
6434
6346
  }
6435
6347
  function isUnshadowedRequire(node) {
6436
- const variable = ASTUtils11.findVariable(
6348
+ const variable = ASTUtils12.findVariable(
6437
6349
  context.sourceCode.getScope(node),
6438
6350
  node.name
6439
6351
  );
@@ -6456,6 +6368,7 @@ var no_restricted_library_load_default = createRule({
6456
6368
  if (source !== null) report2(node.arguments[0], source);
6457
6369
  },
6458
6370
  TSImportEqualsDeclaration(node) {
6371
+ if (node.importKind === "type") return;
6459
6372
  if (node.moduleReference.type !== AST_NODE_TYPES25.TSExternalModuleReference) return;
6460
6373
  const source = literalModule(node.moduleReference.expression);
6461
6374
  if (source !== null) report2(node.moduleReference.expression, source);
@@ -6465,7 +6378,7 @@ var no_restricted_library_load_default = createRule({
6465
6378
  });
6466
6379
 
6467
6380
  // src/rules/no-router-refresh-polling.ts
6468
- import { AST_NODE_TYPES as AST_NODE_TYPES26, ASTUtils as ASTUtils12 } from "@typescript-eslint/utils";
6381
+ import { AST_NODE_TYPES as AST_NODE_TYPES26, ASTUtils as ASTUtils13 } from "@typescript-eslint/utils";
6469
6382
  var NO_ROUTER_REFRESH_POLLING_DOCUMENTATION = {
6470
6383
  summary: "Do not poll by calling a Next.js router's refresh method from a timer.",
6471
6384
  rationale: "A route refresh refetches and rerenders the whole route on every tick instead of loading the named resource that changed.",
@@ -6495,7 +6408,7 @@ function isIntervalCallee(sourceCode, node) {
6495
6408
  return node.type === AST_NODE_TYPES26.Identifier && node.name === "setInterval" && isUnshadowedGlobal2(sourceCode, node) || node.type === AST_NODE_TYPES26.MemberExpression && !node.computed && node.object.type === AST_NODE_TYPES26.Identifier && (node.object.name === "window" || node.object.name === "globalThis") && isUnshadowedGlobal2(sourceCode, node.object) && node.property.type === AST_NODE_TYPES26.Identifier && node.property.name === "setInterval";
6496
6409
  }
6497
6410
  function isUnshadowedGlobal2(sourceCode, node) {
6498
- const variable = ASTUtils12.findVariable(sourceCode.getScope(node), node.name);
6411
+ const variable = ASTUtils13.findVariable(sourceCode.getScope(node), node.name);
6499
6412
  return variable === null || variable.defs.length === 0;
6500
6413
  }
6501
6414
  var no_router_refresh_polling_default = createRule({
@@ -6518,21 +6431,21 @@ var no_router_refresh_polling_default = createRule({
6518
6431
  if (node.source.value !== "next/navigation") return;
6519
6432
  for (const specifier of node.specifiers) {
6520
6433
  if (specifier.type === AST_NODE_TYPES26.ImportSpecifier && importedName4(specifier) === "useRouter") {
6521
- const variable = ASTUtils12.findVariable(context.sourceCode.getScope(specifier.local), specifier.local.name);
6434
+ const variable = ASTUtils13.findVariable(context.sourceCode.getScope(specifier.local), specifier.local.name);
6522
6435
  if (variable !== null) routerHooks.add(variable);
6523
6436
  }
6524
6437
  }
6525
6438
  },
6526
6439
  VariableDeclarator(node) {
6527
6440
  if (node.id.type === AST_NODE_TYPES26.Identifier && node.init?.type === AST_NODE_TYPES26.CallExpression && node.init.callee.type === AST_NODE_TYPES26.Identifier) {
6528
- const hook = ASTUtils12.findVariable(context.sourceCode.getScope(node.init.callee), node.init.callee.name);
6529
- const router = ASTUtils12.findVariable(context.sourceCode.getScope(node.id), node.id.name);
6441
+ const hook = ASTUtils13.findVariable(context.sourceCode.getScope(node.init.callee), node.init.callee.name);
6442
+ const router = ASTUtils13.findVariable(context.sourceCode.getScope(node.id), node.id.name);
6530
6443
  if (hook !== null && router !== null && routerHooks.has(hook)) routers.add(router);
6531
6444
  }
6532
6445
  },
6533
6446
  CallExpression(node) {
6534
6447
  if (node.callee.type !== AST_NODE_TYPES26.MemberExpression || node.callee.computed || node.callee.object.type !== AST_NODE_TYPES26.Identifier || node.callee.property.type !== AST_NODE_TYPES26.Identifier || node.callee.property.name !== "refresh") return;
6535
- const router = ASTUtils12.findVariable(
6448
+ const router = ASTUtils13.findVariable(
6536
6449
  context.sourceCode.getScope(node.callee.object),
6537
6450
  node.callee.object.name
6538
6451
  );
@@ -7590,13 +7503,13 @@ var no_select_star_default = createRule({
7590
7503
  });
7591
7504
 
7592
7505
  // src/rules/no-sentinel-return-on-catch.ts
7593
- import { AST_NODE_TYPES as AST_NODE_TYPES30 } from "@typescript-eslint/utils";
7506
+ import { AST_NODE_TYPES as AST_NODE_TYPES30, ASTUtils as ASTUtils14 } from "@typescript-eslint/utils";
7594
7507
  var NO_SENTINEL_RETURN_ON_CATCH_DOCUMENTATION = {
7595
7508
  summary: "Disallow swallowing a caught error by returning an empty sentinel unless the error is handled or the sentinel is part of the function contract.",
7596
7509
  rationale: "An unreported fallback makes operational failure indistinguishable from a legitimate empty result.",
7597
7510
  remediation: "Rethrow, report the error before returning, or model expected absence with an explicit predicate, safe-parse, or result contract.",
7598
7511
  category: "correctness",
7599
- limitations: ["Recognized predicate, safe-parse, normal-path sentinel, deliberate parse, generated-client, and configured logging patterns are excluded."],
7512
+ limitations: ["Recognized predicate, safe-parse, normal-path sentinel, deliberate parse, generated-client, and configured logging patterns are excluded. Locally shadowed undefined bindings are not treated as sentinels; recognized handling patterns are not a proof that every control-flow path handles the error."],
7600
7513
  examples: [
7601
7514
  { id: "reported-fallback", title: "Report an error before returning a fallback", outcome: "no-match", files: [{ path: "src/load.ts", source: "function load() { try { return read(); } catch (error) { logger.warn('load failed', error); return null; } }" }], focusPath: "src/load.ts", expectedCount: 0, public: true },
7602
7515
  { id: "silent-fallback", title: "Do not turn an unreported error into absence", outcome: "match", files: [{ path: "src/load.ts", source: "function load() { try { return read(); } catch { return null; } }" }], focusPath: "src/load.ts", expectedCount: 1, public: true }
@@ -8011,6 +7924,8 @@ var no_sentinel_return_on_catch_default = createRule({
8011
7924
  if (!isSentinelArgument(last.argument)) {
8012
7925
  return;
8013
7926
  }
7927
+ const returned = unwrapSentinelExpression(last.argument);
7928
+ if (returned?.type === AST_NODE_TYPES30.Identifier && returned.name === "undefined" && (ASTUtils14.findVariable(context.sourceCode.getScope(returned), returned.name)?.defs.length ?? 0) > 0) return;
8014
7929
  if (containsThrow(node.body)) {
8015
7930
  return;
8016
7931
  }
@@ -8460,12 +8375,13 @@ var no_storage_in_stateless_modules_default = createRule({
8460
8375
  // src/rules/no-string-concat-in-loop.ts
8461
8376
  import "@typescript-eslint/utils";
8462
8377
  var NO_STRING_CONCAT_IN_LOOP_DOCUMENTATION = {
8463
- summary: "Disallow O(n^2) string building via `+=` on a string variable inside a loop; push parts to an array and `join` instead.",
8378
+ summary: "Prefer collecting string fragments over repeatedly accumulating a growing string inside a loop.",
8464
8379
  rationale: "Repeatedly rebuilding a growing string can copy all prior content on each iteration, making total work grow quadratically.",
8465
- remediation: "Collect each fragment in an array, then join the fragments after the loop.",
8380
+ remediation: "Consider collecting fragments and joining once; preserve intermediate observations and coercion timing, and measure hot paths.",
8466
8381
  category: "performance",
8467
8382
  limitations: [
8468
- "Only local identifiers initialized with a string or template literal and accumulated in a loop body are inspected."
8383
+ "Only local identifiers initialized with a string or template literal and accumulated in a loop body are inspected.",
8384
+ "Deferred function bodies are excluded except recognized direct forEach callbacks. Syntax does not establish engine-specific string allocation complexity."
8469
8385
  ],
8470
8386
  examples: [
8471
8387
  {
@@ -8583,6 +8499,7 @@ function enclosingLoop(node) {
8583
8499
  if ((parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression") && parent.parent.type === "CallExpression" && parent.parent.arguments[0] === parent && parent.parent.callee.type === "MemberExpression" && !parent.parent.callee.computed && parent.parent.callee.property.type === "Identifier" && parent.parent.callee.property.name === "forEach") {
8584
8500
  return parent.parent;
8585
8501
  }
8502
+ if (parent.type === "ArrowFunctionExpression" || parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") return null;
8586
8503
  if (LOOP_NODE_TYPES.has(parent.type)) {
8587
8504
  const loop = parent;
8588
8505
  if (loop.body === child) {
@@ -8594,6 +8511,19 @@ function enclosingLoop(node) {
8594
8511
  }
8595
8512
  return null;
8596
8513
  }
8514
+ function immediatelyExitsLoop(node, loop) {
8515
+ if (!LOOP_NODE_TYPES.has(loop.type) || node.parent.type !== "ExpressionStatement") return false;
8516
+ const statement = node.parent;
8517
+ const block = statement.parent;
8518
+ if (block.type !== "BlockStatement") return false;
8519
+ const next = block.body[block.body.indexOf(statement) + 1];
8520
+ if (next?.type !== "BreakStatement" && next?.type !== "ReturnStatement" && next?.type !== "ThrowStatement") return false;
8521
+ if (next.type === "BreakStatement" && next.label !== null) return false;
8522
+ for (let current = block; current !== void 0 && current !== loop; current = current.parent) {
8523
+ if (current.type === "TryStatement" || next.type === "BreakStatement" && current.type === "SwitchStatement") return false;
8524
+ }
8525
+ return true;
8526
+ }
8597
8527
  function isSmallStaticForLoop(node) {
8598
8528
  if (node.type !== "ForStatement" || node.init?.type !== "VariableDeclaration" || node.init.declarations.length !== 1 || node.test?.type !== "BinaryExpression" || node.test.operator !== "<" && node.test.operator !== "<=" || node.update?.type !== "UpdateExpression" || node.update.operator !== "++") {
8599
8529
  return false;
@@ -8632,12 +8562,12 @@ var no_string_concat_in_loop_default = createRule({
8632
8562
  meta: {
8633
8563
  type: "suggestion",
8634
8564
  docs: {
8635
- description: "Disallow O(n^2) string building via `+=` on a string variable inside a loop; push parts to an array and `join` instead."
8565
+ description: NO_STRING_CONCAT_IN_LOOP_DOCUMENTATION.summary
8636
8566
  },
8637
8567
  schema: [],
8638
8568
  messages: {
8639
- noStringConcatInLoop: 'Avoid building a string with `+=` inside a loop \u2014 this is O(n^2). Push the parts onto an array and use `arr.join("")` after the loop.',
8640
- noStringReduce: "Avoid concatenating a growing string in `reduce` \u2014 this is O(n^2). Map the fragments and join them once instead."
8569
+ noStringConcatInLoop: "This loop repeatedly accumulates a growing string. Consider collecting fragments and joining once; preserve coercion timing and intermediate reads, and measure performance-sensitive paths.",
8570
+ noStringReduce: "This reduce repeatedly accumulates a growing string. Consider mapping fragments and joining once if coercion timing and intermediate observations are unchanged."
8641
8571
  }
8642
8572
  },
8643
8573
  defaultOptions: [],
@@ -8664,6 +8594,7 @@ var no_string_concat_in_loop_default = createRule({
8664
8594
  if (loop === null) {
8665
8595
  return;
8666
8596
  }
8597
+ if (immediatelyExitsLoop(node, loop)) return;
8667
8598
  if (isSmallStaticForLoop(loop)) {
8668
8599
  return;
8669
8600
  }
@@ -10037,7 +9968,7 @@ var no_unnecessary_use_client_default = createRule({
10037
9968
  // src/rules/no-unsafe-mock-casting.ts
10038
9969
  import {
10039
9970
  AST_NODE_TYPES as AST_NODE_TYPES40,
10040
- ASTUtils as ASTUtils13
9971
+ ASTUtils as ASTUtils15
10041
9972
  } from "@typescript-eslint/utils";
10042
9973
  var MOCK_TYPE_NAMES = /* @__PURE__ */ new Set([
10043
9974
  "Mock",
@@ -10103,7 +10034,7 @@ var no_unsafe_mock_casting_default = createRule({
10103
10034
  const directBindings = /* @__PURE__ */ new Set();
10104
10035
  const namespaceBindings = /* @__PURE__ */ new Set();
10105
10036
  function resolve2(identifier) {
10106
- return ASTUtils13.findVariable(
10037
+ return ASTUtils15.findVariable(
10107
10038
  context.sourceCode.getScope(identifier),
10108
10039
  identifier.name
10109
10040
  );
@@ -10153,7 +10084,7 @@ var no_unsafe_mock_casting_default = createRule({
10153
10084
  import {
10154
10085
  ESLintUtils as ESLintUtils3,
10155
10086
  AST_NODE_TYPES as AST_NODE_TYPES41,
10156
- ASTUtils as ASTUtils14
10087
+ ASTUtils as ASTUtils16
10157
10088
  } from "@typescript-eslint/utils";
10158
10089
  import * as ts2 from "typescript";
10159
10090
  var NO_ZOD_NATIVE_ENUM_DOCUMENTATION = {
@@ -10263,7 +10194,7 @@ var no_zod_native_enum_default = createRule({
10263
10194
  const zodImportedBindings = /* @__PURE__ */ new Map();
10264
10195
  const zodNamespaceBindings = /* @__PURE__ */ new Set();
10265
10196
  function resolvedBinding(identifier) {
10266
- return ASTUtils14.findVariable(
10197
+ return ASTUtils16.findVariable(
10267
10198
  sourceCode.getScope(identifier),
10268
10199
  identifier.name
10269
10200
  );
@@ -10329,7 +10260,7 @@ var no_zod_native_enum_default = createRule({
10329
10260
  });
10330
10261
 
10331
10262
  // src/rules/test-loops-over-literal-cases.ts
10332
- import { AST_NODE_TYPES as AST_NODE_TYPES42, ASTUtils as ASTUtils15 } from "@typescript-eslint/utils";
10263
+ import { AST_NODE_TYPES as AST_NODE_TYPES42, ASTUtils as ASTUtils17 } from "@typescript-eslint/utils";
10333
10264
  var TEST_LOOPS_OVER_LITERAL_CASES_DOCUMENTATION = {
10334
10265
  summary: "Disallow assertions over an inline literal case loop in a test; parameterization reports and names every case independently.",
10335
10266
  rationale: "A loop is reported as one test, so failures hide the individual case name and may stop later cases from running.",
@@ -10492,7 +10423,7 @@ var test_loops_over_literal_cases_default = createRule({
10492
10423
  return {};
10493
10424
  }
10494
10425
  const isFrameworkIdentifier = (identifier, modules) => {
10495
- const variable = ASTUtils15.findVariable(context.sourceCode.getScope(identifier), identifier.name);
10426
+ const variable = ASTUtils17.findVariable(context.sourceCode.getScope(identifier), identifier.name);
10496
10427
  if (variable === null || variable.defs.length === 0) return true;
10497
10428
  return variable.defs.some((definition) => {
10498
10429
  let current = definition.node;
@@ -10740,13 +10671,12 @@ import {
10740
10671
  var PREFER_ECMASCRIPT_PRIVATE_MEMBERS_DOCUMENTATION = {
10741
10672
  summary: "Prefer ECMAScript `#private` class members over TypeScript-only `private` members.",
10742
10673
  rationale: "ECMAScript private names enforce encapsulation at runtime instead of erasing the boundary during compilation.",
10743
- remediation: "Replace the TypeScript `private` modifier and all proven same-class references with an ECMAScript private name.",
10674
+ remediation: "Review reflection, instance escape and framework contracts before replacing TypeScript privacy with ECMAScript private names and updating references.",
10744
10675
  category: "maintainability",
10745
- autofix: "safe",
10676
+ autofix: "none",
10746
10677
  limitations: [
10747
10678
  "Ambient, abstract, computed, decorated, override, parameter-property, and generated declarations are excluded.",
10748
- "A fix is offered only for an undecorated, unexported class declaration with no references outside its body and when type information proves every use is a direct `this.name` access inside that class.",
10749
- "Overloads, modifier-adjacent comments, reflection, and any potentially cross-file or escaping class remain report-only."
10679
+ "Migration is report-only: type information cannot prove that instances or constructors never escape through this, or that reflection and framework serialization do not observe ordinary private properties."
10750
10680
  ],
10751
10681
  references: ["https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_elements"],
10752
10682
  examples: [
@@ -10766,19 +10696,11 @@ var PREFER_ECMASCRIPT_PRIVATE_MEMBERS_DOCUMENTATION = {
10766
10696
  files: [{ path: "src/vault.ts", source: "class Vault { private read() { return 1; } open() { return this.read(); } }" }],
10767
10697
  focusPath: "src/vault.ts",
10768
10698
  expectedCount: 1,
10769
- public: true,
10770
- fixedFiles: [{ path: "src/vault.ts", source: "class Vault { #read() { return 1; } open() { return this.#read(); } }" }]
10699
+ public: true
10771
10700
  }
10772
10701
  ]
10773
10702
  };
10774
- function reportClass2(context, services, owner) {
10775
- const parent = owner.parent;
10776
- const directlyExported = parent.type === AST_NODE_TYPES45.ExportNamedDeclaration || parent.type === AST_NODE_TYPES45.ExportDefaultDeclaration;
10777
- const locallyClosed = !directlyExported && owner.decorators.length === 0 && owner.type === AST_NODE_TYPES45.ClassDeclaration && context.sourceCode.getDeclaredVariables(owner).every(
10778
- (variable) => variable.references.every(
10779
- (reference) => reference.identifier.range[0] >= owner.range[0] && reference.identifier.range[1] <= owner.range[1]
10780
- )
10781
- );
10703
+ function reportClass2(context, owner) {
10782
10704
  const groups = /* @__PURE__ */ new Map();
10783
10705
  for (const member of owner.body.body) {
10784
10706
  if (!isConvertible(member)) continue;
@@ -10791,18 +10713,10 @@ function reportClass2(context, services, owner) {
10791
10713
  for (const [name, members] of groups) {
10792
10714
  const first = members[0];
10793
10715
  if (first === void 0) continue;
10794
- const fix = locallyClosed ? privateMemberFixes(
10795
- context,
10796
- services,
10797
- owner,
10798
- members,
10799
- true
10800
- ) : void 0;
10801
10716
  context.report({
10802
10717
  node: first.key,
10803
10718
  messageId: "preferEcmascriptPrivate",
10804
- data: { name },
10805
- ...fix === void 0 ? {} : { fix }
10719
+ data: { name }
10806
10720
  });
10807
10721
  }
10808
10722
  }
@@ -10816,7 +10730,6 @@ var prefer_ecmascript_private_members_default = createRule({
10816
10730
  meta: {
10817
10731
  type: "suggestion",
10818
10732
  docs: { description: "Prefer ECMAScript `#private` class members over TypeScript-only `private` members." },
10819
- fixable: "code",
10820
10733
  schema: [],
10821
10734
  messages: {
10822
10735
  preferEcmascriptPrivate: "TypeScript `private {{name}}` is erased at runtime; use the ECMAScript private name `#{{name}}`."
@@ -10833,8 +10746,8 @@ var prefer_ecmascript_private_members_default = createRule({
10833
10746
  }
10834
10747
  if (services === null) return {};
10835
10748
  return {
10836
- ClassDeclaration: (node) => reportClass2(context, services, node),
10837
- ClassExpression: (node) => reportClass2(context, services, node)
10749
+ ClassDeclaration: (node) => reportClass2(context, node),
10750
+ ClassExpression: (node) => reportClass2(context, node)
10838
10751
  };
10839
10752
  }
10840
10753
  });
@@ -10844,10 +10757,10 @@ import "@typescript-eslint/utils";
10844
10757
  import { AST_NODE_TYPES as AST_NODE_TYPES46 } from "@typescript-eslint/utils";
10845
10758
  var PREFER_DISCRIMINATED_UNION_DOCUMENTATION = {
10846
10759
  summary: "Flag flat result objects with a required positive boolean status and optional success/failure payloads.",
10847
- rationale: "A boolean status plus optional branch data permits contradictory and incomplete states.",
10848
- remediation: "Represent each result branch as a discriminated union member with its required payload.",
10760
+ rationale: "When success and failure are mutually exclusive outcomes, a boolean plus optional branch data permits contradictory and incomplete states.",
10761
+ remediation: "If the outcomes are mutually exclusive, represent each branch as a discriminated union member with its required payload.",
10849
10762
  category: "correctness",
10850
- limitations: ["Only local object shapes with recognized positive status and payload names are inspected."],
10763
+ limitations: ["Only local object shapes with recognized non-computed status and payload names are inspected. Names do not prove that partial-success outcomes are forbidden; review the domain before changing its representation."],
10851
10764
  examples: [
10852
10765
  { id: "explicit-result-branches", title: "Use explicit result branches", outcome: "no-match", files: [{ path: "src/result.ts", source: "type Result = { ok: true; data: string } | { ok: false; error: string };" }], focusPath: "src/result.ts", expectedCount: 0, public: true },
10853
10766
  { id: "optional-result-payloads", title: "Do not make both result payloads optional", outcome: "match", files: [{ path: "src/result.ts", source: "type Result = { ok: boolean; data?: string; error?: string };" }], focusPath: "src/result.ts", expectedCount: 1, public: true }
@@ -10911,7 +10824,7 @@ function looksLikeMutuallyExclusiveState(typeLiteral) {
10911
10824
  return statusMemberCount === REQUIRED_STATUS_MEMBER_COUNT && hasFailurePayload && (hasSuccessPayload || !hasUnrecognizedMember);
10912
10825
  }
10913
10826
  function getMemberName(member) {
10914
- if (member.type !== AST_NODE_TYPES46.TSPropertySignature) {
10827
+ if (member.type !== AST_NODE_TYPES46.TSPropertySignature || member.computed) {
10915
10828
  return null;
10916
10829
  }
10917
10830
  const { key } = member;
@@ -10947,7 +10860,7 @@ var prefer_discriminated_union_default = createRule({
10947
10860
  },
10948
10861
  schema: [],
10949
10862
  messages: {
10950
- preferDiscriminatedUnion: "This object type uses a boolean status flag alongside several optional fields, which lets illegal states be representable. Model it as a `z.discriminatedUnion` / discriminated union (e.g. `{ ok: true; data: T } | { ok: false; error: E }`) to make illegal states unrepresentable."
10863
+ preferDiscriminatedUnion: "This object type combines a boolean status with optional payloads. If success and failure are mutually exclusive, consider a discriminated union such as `{ ok: true; data: T } | { ok: false; error: E }`."
10951
10864
  }
10952
10865
  },
10953
10866
  defaultOptions: [],
@@ -10987,7 +10900,7 @@ var prefer_discriminated_union_default = createRule({
10987
10900
  });
10988
10901
 
10989
10902
  // src/rules/prefer-input-group-search.ts
10990
- import { AST_NODE_TYPES as AST_NODE_TYPES47, ASTUtils as ASTUtils16 } from "@typescript-eslint/utils";
10903
+ import { AST_NODE_TYPES as AST_NODE_TYPES47, ASTUtils as ASTUtils18 } from "@typescript-eslint/utils";
10991
10904
  var PREFER_INPUT_GROUP_SEARCH_DOCUMENTATION = {
10992
10905
  summary: "Require search icons and shared Input controls in the same visual wrapper to use InputGroup.",
10993
10906
  rationale: "The shared compound control provides consistent spacing, focus behavior, and accessible composition.",
@@ -11111,7 +11024,7 @@ var prefer_input_group_search_default = createRule({
11111
11024
  JSXOpeningElement(node) {
11112
11025
  const name = elementName(node);
11113
11026
  if (name === null) return;
11114
- const binding = ASTUtils16.findVariable(context.sourceCode.getScope(node), name);
11027
+ const binding = ASTUtils18.findVariable(context.sourceCode.getScope(node), name);
11115
11028
  if (binding?.defs.length !== 1 || binding.defs[0]?.node.type !== AST_NODE_TYPES47.ImportSpecifier || binding.defs[0].node.importKind === "type") return;
11116
11029
  const occurrence = {
11117
11030
  ancestors: context.sourceCode.getAncestors(node),
@@ -11151,7 +11064,7 @@ var prefer_input_group_search_default = createRule({
11151
11064
 
11152
11065
  // src/rules/prefer-millisecond-control-duration-schema.ts
11153
11066
  import {
11154
- ASTUtils as ASTUtils17,
11067
+ ASTUtils as ASTUtils19,
11155
11068
  AST_NODE_TYPES as AST_NODE_TYPES48
11156
11069
  } from "@typescript-eslint/utils";
11157
11070
  var PREFER_MILLISECOND_CONTROL_DURATION_SCHEMA_DOCUMENTATION = {
@@ -11220,7 +11133,7 @@ var prefer_millisecond_control_duration_schema_default = createRule({
11220
11133
  const zodNamespaces = /* @__PURE__ */ new Set();
11221
11134
  const objectFactories = /* @__PURE__ */ new Set();
11222
11135
  function binding(identifier) {
11223
- return ASTUtils17.findVariable(context.sourceCode.getScope(identifier), identifier.name);
11136
+ return ASTUtils19.findVariable(context.sourceCode.getScope(identifier), identifier.name);
11224
11137
  }
11225
11138
  function record(target, identifier) {
11226
11139
  const variable = binding(identifier);
@@ -11267,7 +11180,7 @@ var prefer_millisecond_control_duration_schema_default = createRule({
11267
11180
  });
11268
11181
 
11269
11182
  // src/rules/prefer-immutable-module-constant.ts
11270
- import { AST_NODE_TYPES as AST_NODE_TYPES49, ASTUtils as ASTUtils18 } from "@typescript-eslint/utils";
11183
+ import { AST_NODE_TYPES as AST_NODE_TYPES49, ASTUtils as ASTUtils20 } from "@typescript-eslint/utils";
11271
11184
  var PREFER_IMMUTABLE_MODULE_CONSTANT_DOCUMENTATION = {
11272
11185
  summary: "Require module-level constant collections to expose readonly state.",
11273
11186
  rationale: "A const binding prevents reassignment but does not stop callers from mutating its array, object, Set, or Map contents.",
@@ -11420,7 +11333,7 @@ var prefer_immutable_module_constant_default = createRule({
11420
11333
  create(context) {
11421
11334
  const sourceCode = context.sourceCode;
11422
11335
  const isUnshadowedGlobal3 = (identifier) => {
11423
- const variable = ASTUtils18.findVariable(sourceCode.getScope(identifier), identifier.name);
11336
+ const variable = ASTUtils20.findVariable(sourceCode.getScope(identifier), identifier.name);
11424
11337
  return variable === null || variable.defs.length === 0;
11425
11338
  };
11426
11339
  if (JAVASCRIPT_FILE_RE.test(context.filename) || isTestFile(context.filename) || isGeneratedFile(context.filename, sourceCode.getText())) {
@@ -12579,7 +12492,7 @@ var prefer_module_level_schema_default = createRule({
12579
12492
  // src/rules/prefer-module-level-refined-schema.ts
12580
12493
  import {
12581
12494
  AST_NODE_TYPES as AST_NODE_TYPES53,
12582
- ASTUtils as ASTUtils19
12495
+ ASTUtils as ASTUtils21
12583
12496
  } from "@typescript-eslint/utils";
12584
12497
  var BENCHMARK_PATH_RE = /(^|[/\\])(?:benchmarks?|bench)[/\\]/;
12585
12498
  var FACTORIES = /* @__PURE__ */ new Set([
@@ -12850,7 +12763,7 @@ var prefer_module_level_refined_schema_default = createRule({
12850
12763
  return {};
12851
12764
  const zodBindings = /* @__PURE__ */ new Set();
12852
12765
  function resolvedBinding(identifier) {
12853
- return ASTUtils19.findVariable(
12766
+ return ASTUtils21.findVariable(
12854
12767
  context.sourceCode.getScope(identifier),
12855
12768
  identifier.name
12856
12769
  );
@@ -12951,7 +12864,7 @@ var prefer_module_level_refined_schema_default = createRule({
12951
12864
  // src/rules/prefer-multi-value-zod-literal.ts
12952
12865
  import {
12953
12866
  AST_NODE_TYPES as AST_NODE_TYPES54,
12954
- ASTUtils as ASTUtils20
12867
+ ASTUtils as ASTUtils22
12955
12868
  } from "@typescript-eslint/utils";
12956
12869
  var PREFER_MULTI_VALUE_ZOD_LITERAL_DOCUMENTATION = {
12957
12870
  summary: "Use the Zod 4 multi-value literal API instead of a union of literal schemas.",
@@ -12998,7 +12911,7 @@ function isStaticPrimitive(node, context) {
12998
12911
  if (node.type === AST_NODE_TYPES54.TemplateLiteral && node.expressions.length === 0)
12999
12912
  return true;
13000
12913
  if (node.type === AST_NODE_TYPES54.Identifier && node.name === "undefined") {
13001
- const binding = ASTUtils20.findVariable(
12914
+ const binding = ASTUtils22.findVariable(
13002
12915
  context.sourceCode.getScope(node),
13003
12916
  node.name
13004
12917
  );
@@ -13035,7 +12948,7 @@ var prefer_multi_value_zod_literal_default = createRule({
13035
12948
  const zodBindings = /* @__PURE__ */ new Set();
13036
12949
  const zod4Bindings = /* @__PURE__ */ new Set();
13037
12950
  function resolvedBinding(identifier) {
13038
- return ASTUtils20.findVariable(
12951
+ return ASTUtils22.findVariable(
13039
12952
  context.sourceCode.getScope(identifier),
13040
12953
  identifier.name
13041
12954
  );
@@ -13106,7 +13019,7 @@ function isLiteralUnion(node) {
13106
13019
  function exportedContract(node) {
13107
13020
  let current = node;
13108
13021
  while (current !== void 0) {
13109
- if (current.type === AST_NODE_TYPES55.ExportNamedDeclaration) return true;
13022
+ if (current.type === AST_NODE_TYPES55.TSTypeAliasDeclaration || current.type === AST_NODE_TYPES55.TSInterfaceDeclaration) return current.parent.type === AST_NODE_TYPES55.ExportNamedDeclaration;
13110
13023
  if (current.type === AST_NODE_TYPES55.Program) return false;
13111
13024
  current = current.parent ?? void 0;
13112
13025
  }
@@ -13197,14 +13110,14 @@ var prefer_named_complex_return_type_default = createRule({
13197
13110
  });
13198
13111
 
13199
13112
  // src/rules/prefer-native-random-uuid.ts
13200
- import { AST_NODE_TYPES as AST_NODE_TYPES57, ASTUtils as ASTUtils21 } from "@typescript-eslint/utils";
13113
+ import { AST_NODE_TYPES as AST_NODE_TYPES57, ASTUtils as ASTUtils23 } from "@typescript-eslint/utils";
13201
13114
  var PREFER_NATIVE_RANDOM_UUID_DOCUMENTATION = {
13202
13115
  summary: "Prefer `globalThis.crypto.randomUUID()` over resolved zero-argument UUID v4 bindings from the `uuid` package.",
13203
13116
  rationale: "The platform implementation avoids an unnecessary dependency for standard random UUID generation.",
13204
13117
  remediation: "Call `globalThis.crypto.randomUUID()` and remove the unused `uuid` v4 import when possible.",
13205
13118
  category: "maintainability",
13206
13119
  autofix: "suggestion",
13207
- limitations: ["Only resolved zero-argument UUID v4 calls are reported; customized and other UUID versions are excluded."],
13120
+ limitations: ["Only resolved zero-argument UUID v4 calls are reported; customized and other UUID versions are excluded. Suggestions require unshadowed globalThis and comment-free calls; verify native randomUUID availability in the deployment runtime."],
13208
13121
  examples: [
13209
13122
  { id: "native-random-uuid", title: "Use the platform UUID generator", outcome: "no-match", files: [{ path: "src/id.ts", source: "const id = globalThis.crypto.randomUUID();" }], focusPath: "src/id.ts", expectedCount: 0, public: true },
13210
13123
  { id: "uuid-v4-package", title: "Do not call uuid v4 without options", outcome: "match", files: [{ path: "src/id.ts", source: "import { v4 } from 'uuid'; const id = v4();" }], focusPath: "src/id.ts", expectedCount: 1, public: true }
@@ -13224,7 +13137,7 @@ var prefer_native_random_uuid_default = createRule({
13224
13137
  hasSuggestions: true,
13225
13138
  schema: [],
13226
13139
  messages: {
13227
- preferNative: "Use the Node 22 native `globalThis.crypto.randomUUID()` instead of the `uuid` package for UUID v4.",
13140
+ preferNative: "Where supported by the deployment runtime, prefer native `globalThis.crypto.randomUUID()` over the `uuid` package for UUID v4.",
13228
13141
  replaceWithNative: "Replace this UUID v4 call with the native implementation."
13229
13142
  }
13230
13143
  },
@@ -13233,22 +13146,24 @@ var prefer_native_random_uuid_default = createRule({
13233
13146
  const directBindings = /* @__PURE__ */ new Set();
13234
13147
  const namespaceBindings = /* @__PURE__ */ new Set();
13235
13148
  function resolve2(identifier) {
13236
- return ASTUtils21.findVariable(context.sourceCode.getScope(identifier), identifier.name);
13149
+ return ASTUtils23.findVariable(context.sourceCode.getScope(identifier), identifier.name);
13237
13150
  }
13238
13151
  function record(identifier, destination) {
13239
13152
  const variable = resolve2(identifier);
13240
13153
  if (variable !== null) destination.add(variable);
13241
13154
  }
13242
13155
  function report2(node) {
13156
+ const globalBinding = ASTUtils23.findVariable(context.sourceCode.getScope(node), "globalThis");
13157
+ const canSuggest = (globalBinding?.defs.length ?? 0) === 0 && context.sourceCode.getCommentsInside(node).length === 0;
13243
13158
  context.report({
13244
13159
  node,
13245
13160
  messageId: "preferNative",
13246
- suggest: [
13161
+ suggest: canSuggest ? [
13247
13162
  {
13248
13163
  messageId: "replaceWithNative",
13249
13164
  fix: (fixer) => fixer.replaceText(node, "globalThis.crypto.randomUUID()")
13250
13165
  }
13251
- ]
13166
+ ] : []
13252
13167
  });
13253
13168
  }
13254
13169
  return {
@@ -13296,7 +13211,7 @@ var prefer_native_random_uuid_default = createRule({
13296
13211
  });
13297
13212
 
13298
13213
  // src/rules/prefer-node-crypto-hash.ts
13299
- import { AST_NODE_TYPES as AST_NODE_TYPES58, ASTUtils as ASTUtils22 } from "@typescript-eslint/utils";
13214
+ import { AST_NODE_TYPES as AST_NODE_TYPES58, ASTUtils as ASTUtils24 } from "@typescript-eslint/utils";
13300
13215
  var PREFER_NODE_CRYPTO_HASH_DOCUMENTATION = {
13301
13216
  summary: "Prefer the modern one-shot node:crypto hash API when streaming state is unnecessary.",
13302
13217
  rationale: "A createHash-update-digest chain allocates mutable streaming state for a single in-memory value; Node's built-in hash function expresses the one-shot operation directly and can use its optimized fast path.",
@@ -13352,7 +13267,7 @@ var prefer_node_crypto_hash_default = createRule({
13352
13267
  const directBindings = /* @__PURE__ */ new Set();
13353
13268
  const namespaceBindings = /* @__PURE__ */ new Set();
13354
13269
  function resolve2(identifier) {
13355
- return ASTUtils22.findVariable(
13270
+ return ASTUtils24.findVariable(
13356
13271
  context.sourceCode.getScope(identifier),
13357
13272
  identifier.name
13358
13273
  );
@@ -13539,7 +13454,7 @@ var prefer_node_fs_promises_default = createRule({
13539
13454
  });
13540
13455
 
13541
13456
  // src/rules/prefer-non-nullable-collection.ts
13542
- import { AST_NODE_TYPES as AST_NODE_TYPES60, ASTUtils as ASTUtils23 } from "@typescript-eslint/utils";
13457
+ import { AST_NODE_TYPES as AST_NODE_TYPES60, ASTUtils as ASTUtils25 } from "@typescript-eslint/utils";
13543
13458
  var PREFER_NON_NULLABLE_COLLECTION_DOCUMENTATION = {
13544
13459
  summary: "Suggest non-null arrays only when local control flow proves the nullish state is equivalent to an empty collection.",
13545
13460
  rationale: "A redundant nullish collection state spreads defaults and guards through consumers without carrying information.",
@@ -13669,14 +13584,14 @@ function directlyCoalesced(node) {
13669
13584
  return parent?.type === AST_NODE_TYPES60.LogicalExpression && parent.left === node && (parent.operator === "??" || parent.operator === "||") && emptyArray(parent.right);
13670
13585
  }
13671
13586
  function identifierIsOnlyCoalesced(context, binding, fn) {
13672
- const variable = ASTUtils23.findVariable(context.sourceCode.getScope(binding), binding.name);
13587
+ const variable = ASTUtils25.findVariable(context.sourceCode.getScope(binding), binding.name);
13673
13588
  if (variable === null || variable.references.length === 0) return false;
13674
13589
  return variable.references.every(
13675
13590
  (reference) => belongsToFunction(reference.identifier, fn) && directlyCoalesced(reference.identifier)
13676
13591
  );
13677
13592
  }
13678
13593
  function memberIsOnlyCoalesced(context, object, property, fn) {
13679
- const variable = ASTUtils23.findVariable(context.sourceCode.getScope(object), object.name);
13594
+ const variable = ASTUtils25.findVariable(context.sourceCode.getScope(object), object.name);
13680
13595
  if (variable === null) return false;
13681
13596
  const accesses = variable.references.flatMap((reference) => {
13682
13597
  if (!belongsToFunction(reference.identifier, fn)) return [null];
@@ -13786,7 +13701,7 @@ var prefer_non_nullable_collection_default = createRule({
13786
13701
  // src/rules/prefer-nullish-filter-predicate.ts
13787
13702
  import {
13788
13703
  AST_NODE_TYPES as AST_NODE_TYPES61,
13789
- ASTUtils as ASTUtils24,
13704
+ ASTUtils as ASTUtils26,
13790
13705
  ESLintUtils as ESLintUtils5
13791
13706
  } from "@typescript-eslint/utils";
13792
13707
  import ts3 from "typescript";
@@ -13832,7 +13747,7 @@ var PREFER_NULLISH_FILTER_PREDICATE_DOCUMENTATION = {
13832
13747
  ]
13833
13748
  };
13834
13749
  function isUnshadowedBoolean(node, context) {
13835
- const variable = ASTUtils24.findVariable(context.sourceCode.getScope(node), node.name);
13750
+ const variable = ASTUtils26.findVariable(context.sourceCode.getScope(node), node.name);
13836
13751
  return variable === null || variable.defs.length === 0;
13837
13752
  }
13838
13753
  function isBuiltinArrayFilter(node, services) {
@@ -13891,7 +13806,7 @@ function isProvablyTruthy(type, checker) {
13891
13806
  }
13892
13807
  function availableParameterName(node, context) {
13893
13808
  for (const name of ["value", "item", "element", "candidate"]) {
13894
- if (ASTUtils24.findVariable(context.sourceCode.getScope(node), name) === null) return name;
13809
+ if (ASTUtils26.findVariable(context.sourceCode.getScope(node), name) === null) return name;
13895
13810
  }
13896
13811
  return null;
13897
13812
  }
@@ -13945,7 +13860,7 @@ var prefer_nullish_filter_predicate_default = createRule({
13945
13860
 
13946
13861
  // src/rules/prefer-await-in-async-return.ts
13947
13862
  import {
13948
- ASTUtils as ASTUtils25,
13863
+ ASTUtils as ASTUtils27,
13949
13864
  ESLintUtils as ESLintUtils6,
13950
13865
  AST_NODE_TYPES as AST_NODE_TYPES62
13951
13866
  } from "@typescript-eslint/utils";
@@ -14059,13 +13974,13 @@ var prefer_await_in_async_return_default = createRule({
14059
13974
  if (services === null) return {};
14060
13975
  const frameworkLoaders = /* @__PURE__ */ new Set();
14061
13976
  const rememberFrameworkLoader = (identifier) => {
14062
- const variable = ASTUtils25.findVariable(context.sourceCode.getScope(identifier), identifier.name);
13977
+ const variable = ASTUtils27.findVariable(context.sourceCode.getScope(identifier), identifier.name);
14063
13978
  if (variable !== null) frameworkLoaders.add(variable);
14064
13979
  };
14065
13980
  const isFrameworkLoaderCallback = (owner) => {
14066
13981
  const parent = owner.parent;
14067
13982
  if (parent.type !== AST_NODE_TYPES62.CallExpression || parent.arguments[0] !== owner || parent.callee.type !== AST_NODE_TYPES62.Identifier) return false;
14068
- const variable = ASTUtils25.findVariable(context.sourceCode.getScope(parent.callee), parent.callee.name);
13983
+ const variable = ASTUtils27.findVariable(context.sourceCode.getScope(parent.callee), parent.callee.name);
14069
13984
  return variable !== null && frameworkLoaders.has(variable);
14070
13985
  };
14071
13986
  return {
@@ -14691,6 +14606,7 @@ var PREFER_SWITCH_FOR_REPEATED_EQUALITY_DOCUMENTATION = {
14691
14606
  category: "maintainability",
14692
14607
  limitations: [
14693
14608
  "Only direct if/else-if chains with at least three strict-equality tests are reported.",
14609
+ "The discriminant must be a bare identifier; calls, getters, indexed reads and other repeatedly evaluated expressions are excluded. Review case-value effects, selector mutation, branch scoping, and break/continue targets when converting manually; this is not an equivalence proof.",
14694
14610
  "Case values may be literals, enum-like member references, or upper-case named constants; dynamic expressions are excluded.",
14695
14611
  "The rule deliberately ignores compound predicates, loose equality, ranges, and chains that compare different discriminants."
14696
14612
  ],
@@ -14704,7 +14620,8 @@ function discriminantText(sourceCode, test) {
14704
14620
  const leftIsCase = isCaseValue(test.left);
14705
14621
  const rightIsCase = isCaseValue(test.right);
14706
14622
  if (leftIsCase === rightIsCase) return null;
14707
- return sourceCode.getText(leftIsCase ? test.right : test.left);
14623
+ const discriminant = leftIsCase ? test.right : test.left;
14624
+ return discriminant.type === AST_NODE_TYPES65.Identifier ? sourceCode.getText(discriminant) : null;
14708
14625
  }
14709
14626
  function isCaseValue(node) {
14710
14627
  if (node.type === AST_NODE_TYPES65.Literal) return true;
@@ -15294,7 +15211,7 @@ var prefer_semantic_colors_default = createRule({
15294
15211
  });
15295
15212
 
15296
15213
  // src/rules/prefer-server-actions.ts
15297
- import { ASTUtils as ASTUtils26 } from "@typescript-eslint/utils";
15214
+ import { ASTUtils as ASTUtils28 } from "@typescript-eslint/utils";
15298
15215
  var PREFER_SERVER_ACTIONS_DOCUMENTATION = {
15299
15216
  summary: "Prefer Next.js Server Actions over same-origin API mutations.",
15300
15217
  rationale: "Server Actions can remove a hand-written internal API wrapper while retaining typed application calls. Client invocations still cross a network and serialization boundary.",
@@ -15326,7 +15243,7 @@ function resolvesToGlobalFetch(context, identifier) {
15326
15243
  function resolveNode(node, context) {
15327
15244
  if (!node) return null;
15328
15245
  if (node.type !== "Identifier") return node;
15329
- const variable = ASTUtils26.findVariable(getScope(context, node), node.name);
15246
+ const variable = ASTUtils28.findVariable(getScope(context, node), node.name);
15330
15247
  const definition = variable?.defs.length === 1 ? variable.defs[0] : void 0;
15331
15248
  if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || variable?.references.some((reference) => reference.isWrite() && reference.init !== true)) return node;
15332
15249
  if (definition.node.init.type === "ObjectExpression" && variable?.references.some((reference) => reference.identifier !== node && reference.init !== true)) return node;
@@ -15335,7 +15252,7 @@ function resolveNode(node, context) {
15335
15252
  function isAxiosClient(node, context, seen = /* @__PURE__ */ new Set()) {
15336
15253
  if (node.type !== "Identifier" || seen.has(node)) return false;
15337
15254
  seen.add(node);
15338
- const variable = ASTUtils26.findVariable(getScope(context, node), node.name);
15255
+ const variable = ASTUtils28.findVariable(getScope(context, node), node.name);
15339
15256
  const definition = variable?.defs.length === 1 ? variable.defs[0] : void 0;
15340
15257
  if (definition === void 0 || variable?.references.some((reference) => reference.isWrite() && reference.init !== true)) return false;
15341
15258
  if (variable?.references.some((reference) => {
@@ -15804,7 +15721,7 @@ var prefer_whole_object_assertion_default = createRule({
15804
15721
  });
15805
15722
 
15806
15723
  // src/rules/repeated-static-call-cases.ts
15807
- import { AST_NODE_TYPES as AST_NODE_TYPES68, ASTUtils as ASTUtils27 } from "@typescript-eslint/utils";
15724
+ import { AST_NODE_TYPES as AST_NODE_TYPES68, ASTUtils as ASTUtils29 } from "@typescript-eslint/utils";
15808
15725
  var REPEATED_STATIC_CALL_CASES_DOCUMENTATION = {
15809
15726
  summary: "Report three or more consecutive literal call assertions that should be independently named test cases.",
15810
15727
  rationale: "Copy-pasted cases obscure the input table and stop later cases from being reported after the first failure.",
@@ -15830,7 +15747,7 @@ function staticMemberName5(node) {
15830
15747
  return null;
15831
15748
  }
15832
15749
  function importedName6(identifier, context, modules) {
15833
- const variable = ASTUtils27.findVariable(context.sourceCode.getScope(identifier), identifier.name);
15750
+ const variable = ASTUtils29.findVariable(context.sourceCode.getScope(identifier), identifier.name);
15834
15751
  if (variable === null || variable.defs.length === 0) return identifier.name;
15835
15752
  for (const definition of variable.defs) {
15836
15753
  if (definition.node.type !== AST_NODE_TYPES68.ImportSpecifier) continue;
@@ -15993,6 +15910,11 @@ var PREFER_ZOD_INFER_DOCUMENTATION = {
15993
15910
  rationale: "A derived type stays synchronized when the runtime schema changes.",
15994
15911
  remediation: "Replace the hand-written twin with `z.infer<typeof Schema>`.",
15995
15912
  category: "correctness",
15913
+ limitations: [
15914
+ "Only module-level const schemas and module-level type declarations are paired; local declarations are excluded rather than matched by spelling across scopes.",
15915
+ "By default every field must positively agree; collection, nested-object and referenced-schema equivalence is not inferred from outer syntax alone.",
15916
+ "This is a bounded syntactic comparison, not general type equivalence. Review schema input versus output, interface augmentation, and separately evolving domain contracts before replacing a declaration."
15917
+ ],
15996
15918
  examples: [
15997
15919
  { id: "inferred-type", title: "Infer the schema type", outcome: "no-match", files: [{ path: "src/user.ts", source: 'import { z } from "zod"; const UserSchema = z.object({ id: z.string() }); type User = z.infer<typeof UserSchema>;' }], focusPath: "src/user.ts", expectedCount: 0, public: true },
15998
15920
  { id: "handwritten-twin", title: "Do not duplicate the schema shape", outcome: "match", files: [{ path: "src/user.ts", source: 'import { z } from "zod"; const UserSchema = z.object({ id: z.string() }); interface User { id: string }' }], focusPath: "src/user.ts", expectedCount: 1, public: true }
@@ -16172,6 +16094,10 @@ function sameDomain(left, right) {
16172
16094
  function isExportedDeclaration(node) {
16173
16095
  return node.parent?.type === AST_NODE_TYPES69.ExportNamedDeclaration;
16174
16096
  }
16097
+ function isModuleLevelDeclaration(node) {
16098
+ const parent = node.parent;
16099
+ return parent?.type === AST_NODE_TYPES69.Program || parent?.type === AST_NODE_TYPES69.ExportNamedDeclaration && parent.parent.type === AST_NODE_TYPES69.Program;
16100
+ }
16175
16101
  function isModuleLevelConst(node) {
16176
16102
  const declaration = node.parent;
16177
16103
  if (declaration.type !== AST_NODE_TYPES69.VariableDeclaration || declaration.kind !== "const") {
@@ -16222,6 +16148,9 @@ function leafAgrees(field, annotation) {
16222
16148
  return annotationDomain !== null && sameDomain(field.domain, annotationDomain);
16223
16149
  }
16224
16150
  const { leaf } = field;
16151
+ if (leaf !== null && ["array", "tuple", "object", "strictObject", "looseObject", "record", "map", "set", "promise", "intersection"].includes(leaf)) {
16152
+ return false;
16153
+ }
16225
16154
  if (leaf === null || annotation === null) {
16226
16155
  return null;
16227
16156
  }
@@ -16514,7 +16443,6 @@ var prefer_zod_infer_default = createRule({
16514
16443
  if (fields.size !== members.size) {
16515
16444
  return false;
16516
16445
  }
16517
- let agreements = 0;
16518
16446
  for (const [name, field] of fields) {
16519
16447
  const member = members.get(name);
16520
16448
  if (member === void 0) {
@@ -16533,14 +16461,11 @@ var prefer_zod_infer_default = createRule({
16533
16461
  return false;
16534
16462
  }
16535
16463
  const agrees = leafAgrees(field, member.annotation);
16536
- if (agrees === false) {
16464
+ if (agrees !== true) {
16537
16465
  return false;
16538
16466
  }
16539
- if (agrees === true) {
16540
- agreements += 1;
16541
- }
16542
16467
  }
16543
- return agreements > 0;
16468
+ return true;
16544
16469
  }
16545
16470
  return {
16546
16471
  Program(node) {
@@ -16554,7 +16479,7 @@ var prefer_zod_infer_default = createRule({
16554
16479
  recordZodImport(node);
16555
16480
  },
16556
16481
  VariableDeclarator(node) {
16557
- if (node.id.type !== AST_NODE_TYPES69.Identifier || node.init == null) {
16482
+ if (node.id.type !== AST_NODE_TYPES69.Identifier || node.init == null || !isModuleLevelConst(node)) {
16558
16483
  return;
16559
16484
  }
16560
16485
  const fields = schemaFields(node.init);
@@ -16587,6 +16512,7 @@ var prefer_zod_infer_default = createRule({
16587
16512
  }
16588
16513
  },
16589
16514
  TSInterfaceDeclaration(node) {
16515
+ if (!isModuleLevelDeclaration(node)) return;
16590
16516
  if (node.typeParameters !== void 0 || (node.extends?.length ?? 0) > 0) {
16591
16517
  return;
16592
16518
  }
@@ -16602,6 +16528,7 @@ var prefer_zod_infer_default = createRule({
16602
16528
  );
16603
16529
  },
16604
16530
  TSTypeAliasDeclaration(node) {
16531
+ if (!isModuleLevelDeclaration(node)) return;
16605
16532
  const schemaName = inferredSchemaName(node.typeAnnotation);
16606
16533
  if (schemaName !== null) {
16607
16534
  inferredAliases.push({
@@ -16719,6 +16646,7 @@ var REQUIRE_ASSERT_NEVER_DOCUMENTATION = {
16719
16646
  rationale: "An empty default silently accepts new union members instead of making the compiler identify the missing case.",
16720
16647
  remediation: "Call `assertNever` with the discriminant in the exhaustive switch default.",
16721
16648
  category: "correctness",
16649
+ limitations: ["Requires type information and singleton case values covering the current union. The helper must accept never to provide a compile-time check; its spelling alone is not a proof of that contract. Review the desired runtime behavior for unexpected external values."],
16722
16650
  examples: [
16723
16651
  { id: "assert-never-default", title: "Make the default exhaustive", outcome: "no-match", files: [{ path: "src/render.ts", source: "declare const kind: 'a' | 'b';\nswitch (kind) { case 'a': break; case 'b': break; default: assertNever(kind); }" }], focusPath: "src/render.ts", expectedCount: 0, public: true },
16724
16652
  { id: "empty-default", title: "Do not leave an exhaustive default empty", outcome: "match", files: [{ path: "src/render.ts", source: "declare const kind: 'a' | 'b';\nswitch (kind) { case 'a': break; case 'b': break; default: }" }], focusPath: "src/render.ts", expectedCount: 1, public: true }
@@ -16775,11 +16703,9 @@ function isExhaustiveFiniteSwitch(node, services) {
16775
16703
  if (caseNode.test === null) continue;
16776
16704
  const test = services.esTreeNodeToTSNodeMap.get(caseNode.test);
16777
16705
  const testType = checker.getTypeAtLocation(test);
16778
- const alternatives = testType.isUnion() ? testType.types : [testType];
16779
- for (const alternative of alternatives) {
16780
- const key = finiteTypeKey(alternative, checker);
16781
- if (key !== null) handled.add(key);
16782
- }
16706
+ if (testType.isUnion()) continue;
16707
+ const key = finiteTypeKey(testType, checker);
16708
+ if (key !== null) handled.add(key);
16783
16709
  }
16784
16710
  return [...expected].every((key) => handled.has(key));
16785
16711
  }
@@ -16831,7 +16757,7 @@ var require_assert_never_default = createRule({
16831
16757
  });
16832
16758
 
16833
16759
  // src/rules/require-fetch-timeout.ts
16834
- import { AST_NODE_TYPES as AST_NODE_TYPES71, ASTUtils as ASTUtils28 } from "@typescript-eslint/utils";
16760
+ import { AST_NODE_TYPES as AST_NODE_TYPES71, ASTUtils as ASTUtils30 } from "@typescript-eslint/utils";
16835
16761
  var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
16836
16762
  summary: "Require an explicit abort signal on locally analyzable global fetch calls.",
16837
16763
  rationale: "An unbounded request can occupy work indefinitely when an upstream stalls.",
@@ -16913,7 +16839,7 @@ var require_fetch_timeout_default = createRule({
16913
16839
  }
16914
16840
  function resolvesToGlobal(identifier) {
16915
16841
  const scope = context.sourceCode.getScope(identifier);
16916
- const variable = ASTUtils28.findVariable(scope, identifier.name);
16842
+ const variable = ASTUtils30.findVariable(scope, identifier.name);
16917
16843
  return variable === null || variable.defs.length === 0;
16918
16844
  }
16919
16845
  function isGlobalFetchCall2(callee) {
@@ -16923,7 +16849,7 @@ var require_fetch_timeout_default = createRule({
16923
16849
  return callee.type === AST_NODE_TYPES71.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES71.Identifier && callee.property.name === "fetch" && callee.object.type === AST_NODE_TYPES71.Identifier && GLOBAL_OBJECTS2.has(callee.object.name) && resolvesToGlobal(callee.object);
16924
16850
  }
16925
16851
  function localConstInitProvablyLacksSignal(identifier) {
16926
- const variable = ASTUtils28.findVariable(
16852
+ const variable = ASTUtils30.findVariable(
16927
16853
  context.sourceCode.getScope(identifier),
16928
16854
  identifier.name
16929
16855
  );
@@ -16945,7 +16871,7 @@ var require_fetch_timeout_default = createRule({
16945
16871
  function isForwardedRequest(argument) {
16946
16872
  let value = argument;
16947
16873
  if (value.type === AST_NODE_TYPES71.Identifier) {
16948
- const binding = ASTUtils28.findVariable(context.sourceCode.getScope(value), value.name);
16874
+ const binding = ASTUtils30.findVariable(context.sourceCode.getScope(value), value.name);
16949
16875
  const definition = binding?.defs.length === 1 ? binding.defs[0] : void 0;
16950
16876
  if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || binding?.references.some((reference) => reference.isWrite() && reference.init !== true)) return false;
16951
16877
  value = definition.node.init;
@@ -17434,15 +17360,14 @@ var publicMethodNames = (body2, functionAliases) => {
17434
17360
  if (member.static || member.accessibility === "private" || member.accessibility === "protected") continue;
17435
17361
  if (member.key.type === AST_NODE_TYPES73.PrivateIdentifier) continue;
17436
17362
  if (member.value?.type !== AST_NODE_TYPES73.ArrowFunctionExpression && member.value?.type !== AST_NODE_TYPES73.FunctionExpression && member.typeAnnotation?.typeAnnotation.type !== AST_NODE_TYPES73.TSFunctionType && !(member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES73.TSTypeReference && member.typeAnnotation.typeAnnotation.typeName.type === AST_NODE_TYPES73.Identifier && functionAliases.has(member.typeAnnotation.typeAnnotation.typeName.name))) continue;
17437
- names.push(member.key.type === AST_NODE_TYPES73.Identifier ? member.key.name : "\u2026");
17363
+ names.push(declaredMemberName(member) ?? "\u2026");
17438
17364
  continue;
17439
17365
  }
17440
17366
  if (member.type !== AST_NODE_TYPES73.MethodDefinition) continue;
17441
17367
  if (member.kind !== "method" || member.static) continue;
17442
17368
  if (member.accessibility === "private" || member.accessibility === "protected") continue;
17443
17369
  if (member.key.type === AST_NODE_TYPES73.PrivateIdentifier) continue;
17444
- if (member.key.type === AST_NODE_TYPES73.Identifier) names.push(member.key.name);
17445
- else names.push("\u2026");
17370
+ names.push(declaredMemberName(member) ?? "\u2026");
17446
17371
  }
17447
17372
  return names;
17448
17373
  };
@@ -17483,6 +17408,11 @@ function localClassAbstractness(program) {
17483
17408
  }
17484
17409
  return classes;
17485
17410
  }
17411
+ function declaredMemberName(member) {
17412
+ if (!member.computed && member.key.type === AST_NODE_TYPES73.Identifier) return member.key.name;
17413
+ if (member.key.type === AST_NODE_TYPES73.Literal && typeof member.key.value === "string") return member.key.value;
17414
+ return null;
17415
+ }
17486
17416
  function localInterfaceSurfaces(program) {
17487
17417
  const interfaces = /* @__PURE__ */ new Map();
17488
17418
  const parents = /* @__PURE__ */ new Map();
@@ -17505,14 +17435,15 @@ function localInterfaceSurfaces(program) {
17505
17435
  if (part.type !== AST_NODE_TYPES73.TSTypeLiteral) continue;
17506
17436
  for (const member of part.members) {
17507
17437
  if (member.type !== AST_NODE_TYPES73.TSMethodSignature && member.type !== AST_NODE_TYPES73.TSPropertySignature) continue;
17508
- if (member.computed || member.key.type !== AST_NODE_TYPES73.Identifier) continue;
17438
+ const name = declaredMemberName(member);
17439
+ if (name === null) continue;
17509
17440
  if (member.type === AST_NODE_TYPES73.TSMethodSignature) {
17510
- callables2.add(member.key.name);
17441
+ callables2.add(name);
17511
17442
  continue;
17512
17443
  }
17513
17444
  if (member.type !== AST_NODE_TYPES73.TSPropertySignature) continue;
17514
17445
  const annotation = member.typeAnnotation?.typeAnnotation;
17515
- if (annotation?.type === AST_NODE_TYPES73.TSFunctionType || annotation?.type === AST_NODE_TYPES73.TSTypeReference && annotation.typeName.type === AST_NODE_TYPES73.Identifier && functionAliases.has(annotation.typeName.name)) callables2.add(member.key.name);
17446
+ if (annotation?.type === AST_NODE_TYPES73.TSFunctionType || annotation?.type === AST_NODE_TYPES73.TSTypeReference && annotation.typeName.type === AST_NODE_TYPES73.Identifier && functionAliases.has(annotation.typeName.name)) callables2.add(name);
17516
17447
  }
17517
17448
  }
17518
17449
  interfaces.set(declaration.id.name, callables2);
@@ -17523,8 +17454,9 @@ function localInterfaceSurfaces(program) {
17523
17454
  const callables = interfaces.get(declaration.id.name) ?? /* @__PURE__ */ new Set();
17524
17455
  for (const member of declaration.body.body) {
17525
17456
  if (member.type !== AST_NODE_TYPES73.TSMethodSignature && member.type !== AST_NODE_TYPES73.TSPropertySignature) continue;
17526
- if (member.computed || member.key.type !== AST_NODE_TYPES73.Identifier) continue;
17527
- if (member.type === AST_NODE_TYPES73.TSMethodSignature || member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES73.TSFunctionType || member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES73.TSTypeReference && member.typeAnnotation.typeAnnotation.typeName.type === AST_NODE_TYPES73.Identifier && functionAliases.has(member.typeAnnotation.typeAnnotation.typeName.name)) callables.add(member.key.name);
17457
+ const name = declaredMemberName(member);
17458
+ if (name === null) continue;
17459
+ if (member.type === AST_NODE_TYPES73.TSMethodSignature || member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES73.TSFunctionType || member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES73.TSTypeReference && member.typeAnnotation.typeAnnotation.typeName.type === AST_NODE_TYPES73.Identifier && functionAliases.has(member.typeAnnotation.typeAnnotation.typeName.name)) callables.add(name);
17528
17460
  }
17529
17461
  interfaces.set(declaration.id.name, callables);
17530
17462
  parents.set(
@@ -18022,7 +17954,7 @@ var require_static_next_matcher_default = createRule({
18022
17954
  });
18023
17955
 
18024
17956
  // src/rules/require-use-form-default-values.ts
18025
- import { ASTUtils as ASTUtils29 } from "@typescript-eslint/utils";
17957
+ import { ASTUtils as ASTUtils31 } from "@typescript-eslint/utils";
18026
17958
  var REQUIRE_USE_FORM_DEFAULT_VALUES_DOCUMENTATION = {
18027
17959
  summary: "react-hook-form useForm call without explicit initial or reactive values",
18028
17960
  rationale: "Without an explicit initial value, fields can change from uncontrolled to controlled as data arrives, reset behavior becomes ambiguous, and the form's initial shape no longer documents the values users can edit.",
@@ -18076,13 +18008,13 @@ var require_use_form_default_values_default = createRule({
18076
18008
  if (node.source.value !== "react-hook-form") return;
18077
18009
  for (const specifier of node.specifiers) {
18078
18010
  if (specifier.type !== "ImportSpecifier" || (specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value) !== "useForm") continue;
18079
- const variable = ASTUtils29.findVariable(context.sourceCode.getScope(specifier.local), specifier.local.name);
18011
+ const variable = ASTUtils31.findVariable(context.sourceCode.getScope(specifier.local), specifier.local.name);
18080
18012
  if (variable) importedHooks.add(variable);
18081
18013
  }
18082
18014
  },
18083
18015
  CallExpression(node) {
18084
18016
  if (node.callee.type !== "Identifier") return;
18085
- const variable = ASTUtils29.findVariable(context.sourceCode.getScope(node.callee), node.callee.name);
18017
+ const variable = ASTUtils31.findVariable(context.sourceCode.getScope(node.callee), node.callee.name);
18086
18018
  const options = node.arguments[0];
18087
18019
  if (!variable || !importedHooks.has(variable) || options !== void 0 && options.type !== "ObjectExpression" || hasInitializationOrUnknownOptions(options)) return;
18088
18020
  context.report({ node, messageId: "requireUseFormDefaultValues" });
@@ -18161,7 +18093,7 @@ var require_use_server_in_actions_file_default = createRule({
18161
18093
  // src/rules/require-zod-form-validation.ts
18162
18094
  import {
18163
18095
  AST_NODE_TYPES as AST_NODE_TYPES76,
18164
- ASTUtils as ASTUtils30
18096
+ ASTUtils as ASTUtils32
18165
18097
  } from "@typescript-eslint/utils";
18166
18098
  var REQUIRE_ZOD_FORM_VALIDATION_DOCUMENTATION = {
18167
18099
  summary: "Require Zod validation (`Schema.parse(...)` / `Schema.safeParse(...)`) when reading values out of a `FormData` object.",
@@ -18229,7 +18161,7 @@ var require_zod_form_validation_default = createRule({
18229
18161
  return {};
18230
18162
  }
18231
18163
  const zodBindings = /* @__PURE__ */ new Set();
18232
- const resolvedBinding = (identifier) => ASTUtils30.findVariable(
18164
+ const resolvedBinding = (identifier) => ASTUtils32.findVariable(
18233
18165
  context.sourceCode.getScope(identifier),
18234
18166
  identifier.name
18235
18167
  );
@@ -18526,7 +18458,7 @@ var store_insert_requires_on_conflict_default = createRule({
18526
18458
  });
18527
18459
 
18528
18460
  // src/rules/stepdown.ts
18529
- import { AST_NODE_TYPES as AST_NODE_TYPES77, ASTUtils as ASTUtils31 } from "@typescript-eslint/utils";
18461
+ import { AST_NODE_TYPES as AST_NODE_TYPES77, ASTUtils as ASTUtils33 } from "@typescript-eslint/utils";
18530
18462
  var STEPDOWN_DOCUMENTATION = {
18531
18463
  summary: "Place a private helper below its sole direct same-scope caller.",
18532
18464
  rationale: "Caller-first ordering lets a reader follow the main flow before descending into implementation details.",
@@ -18731,7 +18663,7 @@ function methodName(node) {
18731
18663
  return !node.computed && node.key.type === AST_NODE_TYPES77.Identifier ? node.key.name : null;
18732
18664
  }
18733
18665
  function referencedMethod(context, node, classVariables) {
18734
- const objectVariable = node.object.type === AST_NODE_TYPES77.Identifier ? ASTUtils31.findVariable(context.sourceCode.getScope(node.object), node.object.name) : null;
18666
+ const objectVariable = node.object.type === AST_NODE_TYPES77.Identifier ? ASTUtils33.findVariable(context.sourceCode.getScope(node.object), node.object.name) : null;
18735
18667
  const isClassReference = objectVariable !== null && classVariables.has(objectVariable);
18736
18668
  if (node.object.type !== AST_NODE_TYPES77.ThisExpression && !isClassReference) return null;
18737
18669
  if (node.property.type === AST_NODE_TYPES77.PrivateIdentifier) return `#${node.property.name}`;
@@ -18743,15 +18675,15 @@ function referencedPropertyName(node) {
18743
18675
  if (!node.computed && node.property.type === AST_NODE_TYPES77.Identifier) return node.property.name;
18744
18676
  return node.computed && node.property.type === AST_NODE_TYPES77.Literal && typeof node.property.value === "string" ? node.property.value : null;
18745
18677
  }
18746
- function walk2(node, visitorKeys, visit, nestedFunction = false) {
18678
+ function walk(node, visitorKeys, visit, nestedFunction = false) {
18747
18679
  visit(node, nestedFunction);
18748
18680
  const nested = nestedFunction || isFunction(node);
18749
18681
  for (const key of visitorKeys[node.type] ?? []) {
18750
18682
  const child = node[key];
18751
18683
  if (Array.isArray(child)) {
18752
- for (const item of child) if (typeof item === "object" && item !== null && "type" in item) walk2(item, visitorKeys, visit, nested);
18684
+ for (const item of child) if (typeof item === "object" && item !== null && "type" in item) walk(item, visitorKeys, visit, nested);
18753
18685
  } else if (typeof child === "object" && child !== null && "type" in child) {
18754
- walk2(child, visitorKeys, visit, nested);
18686
+ walk(child, visitorKeys, visit, nested);
18755
18687
  }
18756
18688
  }
18757
18689
  }
@@ -18784,11 +18716,11 @@ function classScope(context, node, computedReferenceNames) {
18784
18716
  const pinned = /* @__PURE__ */ new Set();
18785
18717
  const classVariables = /* @__PURE__ */ new Set();
18786
18718
  if (node.id !== null) {
18787
- const internal = ASTUtils31.findVariable(context.sourceCode.getScope(node), node.id.name);
18719
+ const internal = ASTUtils33.findVariable(context.sourceCode.getScope(node), node.id.name);
18788
18720
  if (internal !== null) classVariables.add(internal);
18789
18721
  }
18790
18722
  if (node.type === AST_NODE_TYPES77.ClassExpression && node.parent.type === AST_NODE_TYPES77.VariableDeclarator && node.parent.id.type === AST_NODE_TYPES77.Identifier) {
18791
- const outer = ASTUtils31.findVariable(context.sourceCode.getScope(node.parent), node.parent.id.name);
18723
+ const outer = ASTUtils33.findVariable(context.sourceCode.getScope(node.parent), node.parent.id.name);
18792
18724
  if (outer !== null) classVariables.add(outer);
18793
18725
  }
18794
18726
  for (const method of methods) {
@@ -18799,7 +18731,7 @@ function classScope(context, node, computedReferenceNames) {
18799
18731
  const parameterDecoratorNodes = /* @__PURE__ */ new Set();
18800
18732
  for (const parameter of method.value.params) {
18801
18733
  for (const decorator of parameter.decorators) {
18802
- walk2(decorator, context.sourceCode.visitorKeys, (current) => parameterDecoratorNodes.add(current));
18734
+ walk(decorator, context.sourceCode.visitorKeys, (current) => parameterDecoratorNodes.add(current));
18803
18735
  }
18804
18736
  }
18805
18737
  const thisValue = (value) => {
@@ -18824,17 +18756,17 @@ function classScope(context, node, computedReferenceNames) {
18824
18756
  return;
18825
18757
  }
18826
18758
  if (binding.type !== AST_NODE_TYPES77.Identifier) return;
18827
- const variable = ASTUtils31.findVariable(context.sourceCode.getScope(binding), binding.name);
18759
+ const variable = ASTUtils33.findVariable(context.sourceCode.getScope(binding), binding.name);
18828
18760
  if (variable !== null) {
18829
18761
  methodClassVariables.add(variable);
18830
18762
  methodAliases.add(variable);
18831
18763
  }
18832
18764
  };
18833
18765
  for (const parameter of method.value.params) {
18834
- walk2(parameter, context.sourceCode.visitorKeys, collectAlias);
18766
+ walk(parameter, context.sourceCode.visitorKeys, collectAlias);
18835
18767
  }
18836
18768
  for (const statement of method.value.body.body) {
18837
- walk2(statement, context.sourceCode.visitorKeys, collectAlias);
18769
+ walk(statement, context.sourceCode.visitorKeys, collectAlias);
18838
18770
  }
18839
18771
  const visitCall = (current, nestedFunction) => {
18840
18772
  if (current.type === AST_NODE_TYPES77.VariableDeclarator && current.id.type === AST_NODE_TYPES77.ObjectPattern && thisValue(current.init)) {
@@ -18854,7 +18786,7 @@ function classScope(context, node, computedReferenceNames) {
18854
18786
  return;
18855
18787
  }
18856
18788
  if (!privateNames.has(target)) return;
18857
- const objectVariable = current.object.type === AST_NODE_TYPES77.Identifier ? ASTUtils31.findVariable(context.sourceCode.getScope(current.object), current.object.name) : null;
18789
+ const objectVariable = current.object.type === AST_NODE_TYPES77.Identifier ? ASTUtils33.findVariable(context.sourceCode.getScope(current.object), current.object.name) : null;
18858
18790
  if (objectVariable !== null && methodAliases.has(objectVariable)) {
18859
18791
  pinned.add(target);
18860
18792
  return;
@@ -18868,19 +18800,19 @@ function classScope(context, node, computedReferenceNames) {
18868
18800
  calls.set(caller, callees);
18869
18801
  };
18870
18802
  for (const decorator of method.decorators) {
18871
- walk2(decorator, context.sourceCode.visitorKeys, visitCall, true);
18803
+ walk(decorator, context.sourceCode.visitorKeys, visitCall, true);
18872
18804
  }
18873
- if (method.computed) walk2(method.key, context.sourceCode.visitorKeys, visitCall, true);
18805
+ if (method.computed) walk(method.key, context.sourceCode.visitorKeys, visitCall, true);
18874
18806
  for (const parameter of method.value.params) {
18875
- walk2(parameter, context.sourceCode.visitorKeys, visitCall);
18807
+ walk(parameter, context.sourceCode.visitorKeys, visitCall);
18876
18808
  }
18877
18809
  for (const statement of method.value.body.body) {
18878
- walk2(statement, context.sourceCode.visitorKeys, visitCall);
18810
+ walk(statement, context.sourceCode.visitorKeys, visitCall);
18879
18811
  }
18880
18812
  }
18881
18813
  for (const member of node.body.body) {
18882
18814
  if (member.type === AST_NODE_TYPES77.MethodDefinition || member.type === AST_NODE_TYPES77.TSAbstractMethodDefinition) continue;
18883
- walk2(member, context.sourceCode.visitorKeys, (current) => {
18815
+ walk(member, context.sourceCode.visitorKeys, (current) => {
18884
18816
  if (current.type !== AST_NODE_TYPES77.MemberExpression) return;
18885
18817
  const target = referencedMethod(context, current, classVariables);
18886
18818
  const possibleTarget = target ?? referencedPropertyName(current);
@@ -18970,7 +18902,7 @@ var stepdown_default = createRule({
18970
18902
  "Program:exit": (program) => {
18971
18903
  moduleScope(context, program);
18972
18904
  const computedReferenceNames = /* @__PURE__ */ new Set();
18973
- walk2(program, context.sourceCode.visitorKeys, (node) => {
18905
+ walk(program, context.sourceCode.visitorKeys, (node) => {
18974
18906
  if (node.type === AST_NODE_TYPES77.MemberExpression && node.computed && node.property.type === AST_NODE_TYPES77.Literal && typeof node.property.value === "string") computedReferenceNames.add(node.property.value);
18975
18907
  });
18976
18908
  for (const node of classes) classScope(context, node, computedReferenceNames);
@@ -19441,7 +19373,7 @@ var iac_source_coupled_test_default = createSourceCoupledRule(
19441
19373
  // src/rules/require-pascal-case-zod-schema-name.ts
19442
19374
  import {
19443
19375
  AST_NODE_TYPES as AST_NODE_TYPES80,
19444
- ASTUtils as ASTUtils32
19376
+ ASTUtils as ASTUtils34
19445
19377
  } from "@typescript-eslint/utils";
19446
19378
  var REQUIRE_PASCAL_CASE_ZOD_SCHEMA_NAME_DOCUMENTATION = {
19447
19379
  summary: "Require confirmed module-level Zod schema contracts to use PascalCase with a `Schema` suffix.",
@@ -19642,7 +19574,7 @@ var require_pascal_case_zod_schema_name_default = createRule({
19642
19574
  const zodBindings = /* @__PURE__ */ new Set();
19643
19575
  const schemaBindings = /* @__PURE__ */ new Set();
19644
19576
  function resolvedBinding(identifier) {
19645
- return ASTUtils32.findVariable(
19577
+ return ASTUtils34.findVariable(
19646
19578
  context.sourceCode.getScope(identifier),
19647
19579
  identifier.name
19648
19580
  );
@@ -19887,7 +19819,7 @@ var RULES = {
19887
19819
  };
19888
19820
  var meta = {
19889
19821
  name: "@sarj/eslint-plugin",
19890
- version: "15.17.9"
19822
+ version: "15.17.10"
19891
19823
  };
19892
19824
  var APPLICATION_ONLY_RULES = [];
19893
19825
  var LIBRARY_IMPORT_POLICY = ["error", {