@sarj/eslint-plugin 16.6.0 → 16.8.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.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "@sarj/eslint-plugin",
4
- version: "16.6.0",
4
+ version: "16.8.0",
5
5
  packageManager: "npm@12.1.0",
6
6
  description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
7
7
  type: "module",
@@ -419,8 +419,9 @@ function commentLineEnd(sourceText, start) {
419
419
  }
420
420
 
421
421
  // src/rules/require-explicit-contract-implementation.ts
422
+ var ESCAPED_CLASSES = /* @__PURE__ */ new WeakMap();
422
423
  var REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION = {
423
- defaultLevel: "warning",
424
+ defaultLevel: "error",
424
425
  summary: "Require nominal inheritance when an injected abstract class is rejected by an instanceof guard.",
425
426
  rationale: "A structurally assignable fake can still fail a constructor's nominal runtime guard. Pure structural interfaces do not require an implements clause.",
426
427
  remediation: "Use an implementation inheriting the existing abstract class, or remove the nominal guard if the boundary is intentionally structural.",
@@ -428,8 +429,8 @@ var REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION = {
428
429
  autofix: "none",
429
430
  limitations: [
430
431
  "Requires direct construction of both owned consumer and collaborator classes, with a first-statement consumer constructor guard rejecting the exact parameter with if (!(parameter instanceof Contract)) throw.",
431
- "The contract must resolve to an abstract class without decorators, unresolved ancestors, or custom computed static members in its resolved hierarchy.",
432
- "Structural interfaces, non-rejecting branches, reassignment before the guard, casts, unresolved heritage, dynamic factories, explicit implementation constructors or initializers, modules referencing prototype-mutator members or assigning prototypes, and third-party classes are excluded."
432
+ "The contract must resolve to an abstract class without decorators, static blocks, unresolved ancestors, or custom computed static members in its resolved hierarchy. Escaped class constructors are checked across every owned module in the typed program.",
433
+ "Structural interfaces, non-rejecting branches, reassignment before the guard, casts, unresolved heritage, dynamic factories, implementation static blocks, explicit implementation constructors or initializers, involved modules referencing prototype-mutator members or assigning prototypes, escaped class constructors, and third-party classes are excluded."
433
434
  ],
434
435
  examples: [
435
436
  {
@@ -452,6 +453,115 @@ var REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION = {
452
453
  }
453
454
  ]
454
455
  };
456
+ function hasPrototypeMutation(source) {
457
+ function visit(node) {
458
+ const member = memberName(node);
459
+ if (member === "setPrototypeOf" || member === "__proto__" || member === "hasInstance") return true;
460
+ if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment && memberName(node.left) === "prototype") return true;
461
+ return ts.forEachChild(node, visit);
462
+ }
463
+ return visit(source) === true;
464
+ }
465
+ function memberName(node) {
466
+ if (ts.isPropertyAccessExpression(node)) return node.name.text;
467
+ if (ts.isElementAccessExpression(node) && ts.isStringLiteralLike(node.argumentExpression)) return node.argumentExpression.text;
468
+ return null;
469
+ }
470
+ function ownedSource(source) {
471
+ return !source.isDeclarationFile && !/(?:^|[/\\])(?:node_modules|vendor|vendored|generated|dist)(?:[/\\])/u.test(source.fileName) && !isGeneratedFile(source.fileName, source.text);
472
+ }
473
+ function escapedClasses(program, checker) {
474
+ const cached = ESCAPED_CLASSES.get(program);
475
+ if (cached !== void 0) return cached;
476
+ const escaped = /* @__PURE__ */ new Set();
477
+ const namespaceValues = /* @__PURE__ */ new Map();
478
+ function visit(node) {
479
+ if (ts.isTypeNode(node) || ts.isImportDeclaration(node)) return;
480
+ if (ts.isIdentifier(node) || ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) {
481
+ recordEscapedReference(checker, node, escaped, namespaceValues);
482
+ }
483
+ ts.forEachChild(node, visit);
484
+ }
485
+ for (const source of program.getSourceFiles()) if (ownedSource(source)) visit(source);
486
+ ESCAPED_CLASSES.set(program, escaped);
487
+ return escaped;
488
+ }
489
+ function recordEscapedReference(checker, node, escaped, namespaceValues) {
490
+ const symbol = canonicalSymbol(checker, node);
491
+ if (symbol !== void 0) {
492
+ let values = namespaceValues.get(symbol);
493
+ if (values === void 0) {
494
+ values = ownedClassValues(checker, symbol);
495
+ namespaceValues.set(symbol, values);
496
+ }
497
+ if (!namespacePrefix(symbol, node) && !safeClassReference(node)) for (const value of values) escaped.add(value);
498
+ }
499
+ if (ts.isElementAccessExpression(node) && !safeClassReference(node)) {
500
+ const receiver = canonicalSymbol(checker, node.expression) ?? checker.getTypeAtLocation(node.expression).getSymbol();
501
+ if (receiver !== void 0) for (const value of ownedClassValues(checker, receiver)) escaped.add(value);
502
+ }
503
+ }
504
+ function ownedClassValues(checker, original, seen = /* @__PURE__ */ new Set()) {
505
+ const symbol = original.flags & ts.SymbolFlags.Alias ? checker.getAliasedSymbol(original) : original;
506
+ const values = /* @__PURE__ */ new Set();
507
+ if (seen.has(symbol)) return values;
508
+ seen.add(symbol);
509
+ if (symbol.declarations?.some((declaration) => ts.isClassDeclaration(declaration) && ownedSource(declaration.getSourceFile()))) values.add(symbol);
510
+ if (symbol.declarations?.some((declaration) => (ts.isSourceFile(declaration) || ts.isModuleDeclaration(declaration)) && ownedSource(declaration.getSourceFile()))) {
511
+ for (const exported of checker.getExportsOfModule(symbol)) {
512
+ for (const value of ownedClassValues(checker, exported, seen)) values.add(value);
513
+ }
514
+ }
515
+ return values;
516
+ }
517
+ function safeClassReference(node) {
518
+ let reference = ts.isPropertyAccessExpression(node.parent) && node.parent.name === node ? node.parent : node;
519
+ while (ts.isParenthesizedExpression(reference.parent)) reference = reference.parent;
520
+ const parent = reference.parent;
521
+ return ts.isClassDeclaration(parent) && parent.name === reference || ts.isNewExpression(parent) && parent.expression === reference || ts.isExpressionWithTypeArguments(parent) && parent.expression === reference || ts.isBinaryExpression(parent) && parent.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword && parent.right === reference;
522
+ }
523
+ function namespacePrefix(symbol, node) {
524
+ const parent = node.parent;
525
+ const memberCall = (ts.isPropertyAccessExpression(parent) || ts.isElementAccessExpression(parent)) && ts.isCallExpression(parent.parent) && parent.parent.expression === parent;
526
+ return !symbol.declarations?.some(ts.isClassDeclaration) && (ts.isPropertyAccessExpression(parent) || ts.isElementAccessExpression(parent)) && parent.expression === node && !memberCall;
527
+ }
528
+ function closedNominalBoundary(program, checker, call, consumer, missing) {
529
+ const { implementation, contractSymbol } = missing;
530
+ const implementationSymbol = implementation.name === void 0 ? void 0 : canonicalSymbol(checker, implementation.name);
531
+ const consumerSymbol = consumer.name === void 0 ? void 0 : canonicalSymbol(checker, consumer.name);
532
+ if (implementationSymbol === void 0 || consumerSymbol === void 0) return false;
533
+ const contract = contractSymbol.declarations?.find(ts.isClassDeclaration);
534
+ if (contract === void 0) return false;
535
+ const targets = /* @__PURE__ */ new Set([consumerSymbol, ...classHierarchySymbols(checker, contract), ...classHierarchySymbols(checker, implementation)]);
536
+ const sources = /* @__PURE__ */ new Set([call.getSourceFile(), consumer.getSourceFile(), implementation.getSourceFile(), ...contractSymbol.declarations?.map((item) => item.getSourceFile()) ?? []]);
537
+ return ![...sources].some(hasPrototypeMutation) && ![...targets].some((target) => escapedClasses(program, checker).has(target));
538
+ }
539
+ function classHierarchySymbols(checker, declaration, seen = /* @__PURE__ */ new Set()) {
540
+ const symbol = declaration.name === void 0 ? void 0 : canonicalSymbol(checker, declaration.name);
541
+ if (symbol === void 0 || seen.has(symbol)) return seen;
542
+ seen.add(symbol);
543
+ for (const clause of declaration.heritageClauses ?? []) {
544
+ if (clause.token !== ts.SyntaxKind.ExtendsKeyword) continue;
545
+ for (const parent of clause.types) {
546
+ const ancestor = canonicalSymbol(checker, parent.expression)?.declarations?.find(ts.isClassDeclaration);
547
+ if (ancestor !== void 0) classHierarchySymbols(checker, ancestor, seen);
548
+ }
549
+ }
550
+ return seen;
551
+ }
552
+ function missingImplementation(checker, signature, parameter, call, argument) {
553
+ const parameterType = checker.getTypeOfSymbolAtLocation(parameter, call);
554
+ const contractType = behavioralContract(checker, parameterType);
555
+ if (contractType === null) return null;
556
+ const contractSymbol = contractType.getSymbol();
557
+ if (contractSymbol === void 0 || !hasNominalRejectionGuard(checker, signature, parameter, contractSymbol)) return null;
558
+ const actualType = checker.getTypeAtLocation(argument);
559
+ if (!checker.isTypeAssignableTo(actualType, contractType)) return null;
560
+ const implementation = ownedClass(checker, argument);
561
+ if (implementation === null) return null;
562
+ if (nominallyInherits(checker, implementation, contractSymbol, /* @__PURE__ */ new Set()) !== false) return null;
563
+ return { implementation, contractSymbol };
564
+ }
455
565
  function behavioralContract(checker, type) {
456
566
  if (type.isUnion()) {
457
567
  const substantive = type.types.filter((member) => (member.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) === 0);
@@ -476,23 +586,9 @@ function ownedClass(checker, expression) {
476
586
  if (declaration === void 0 || declaration !== constructed || declaration.getSourceFile().isDeclarationFile || /(?:^|[/\\])(?:node_modules|vendor|generated)(?:[/\\])/u.test(declaration.getSourceFile().fileName)) return null;
477
587
  return declaration;
478
588
  }
479
- function memberName(node) {
480
- if (ts.isPropertyAccessExpression(node)) return node.name.text;
481
- if (ts.isElementAccessExpression(node) && ts.isStringLiteralLike(node.argumentExpression)) return node.argumentExpression.text;
482
- return null;
483
- }
484
- function hasPrototypeMutation(source) {
485
- function visit(node) {
486
- const member = memberName(node);
487
- if (member === "setPrototypeOf" || member === "__proto__" || member === "hasInstance") return true;
488
- if (ts.isBinaryExpression(node) && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment && memberName(node.left) === "prototype") return true;
489
- return ts.forEachChild(node, visit);
490
- }
491
- return visit(source) === true;
492
- }
493
589
  function nominallyInherits(checker, declaration, target, seen) {
494
590
  if (ts.canHaveDecorators(declaration) && ts.getDecorators(declaration)?.length) return null;
495
- if (hasPrototypeMutation(declaration.getSourceFile()) || declaration.members.some((member) => ts.isConstructorDeclaration(member) || ts.isPropertyDeclaration(member) && member.initializer !== void 0)) return null;
591
+ if (hasPrototypeMutation(declaration.getSourceFile()) || declaration.members.some((member) => ts.isConstructorDeclaration(member) || ts.isClassStaticBlockDeclaration(member) || ts.isPropertyDeclaration(member) && member.initializer !== void 0)) return null;
496
592
  const symbol = declaration.name === void 0 ? void 0 : canonicalSymbol(checker, declaration.name);
497
593
  if (symbol !== void 0) {
498
594
  if (seen.has(symbol)) return null;
@@ -507,10 +603,6 @@ function nominallyInherits(checker, declaration, target, seen) {
507
603
  const inherited = parentSymbol.declarations?.find(ts.isClassDeclaration);
508
604
  return inherited === void 0 ? null : nominallyInherits(checker, inherited, target, new Set(seen));
509
605
  }
510
- function canonicalSymbol(checker, node) {
511
- const symbol = checker.getSymbolAtLocation(node);
512
- return symbol === void 0 ? void 0 : (symbol.flags & ts.SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(symbol) : symbol;
513
- }
514
606
  function hasNominalRejectionGuard(checker, signature, parameter, contract) {
515
607
  const declaration = signature.getDeclaration();
516
608
  if (declaration === void 0 || !ts.isConstructorDeclaration(declaration)) return false;
@@ -535,7 +627,7 @@ function alwaysThrows(statement) {
535
627
  return ts.isThrowStatement(statement) || ts.isBlock(statement) && statement.statements.length === 1 && ts.isThrowStatement(statement.statements[0]);
536
628
  }
537
629
  function hasOrdinaryInstanceCheck(checker, declaration, seen) {
538
- if (seen.has(declaration) || ts.getDecorators(declaration)?.length || hasPrototypeMutation(declaration.getSourceFile())) return false;
630
+ if (seen.has(declaration) || ts.getDecorators(declaration)?.length || hasPrototypeMutation(declaration.getSourceFile()) || declaration.members.some(ts.isClassStaticBlockDeclaration)) return false;
539
631
  seen.add(declaration);
540
632
  if (declaration.members.some((member) => member.name !== void 0 && ts.isComputedPropertyName(member.name) && ts.canHaveModifiers(member) && ts.getModifiers(member)?.some((modifier) => modifier.kind === ts.SyntaxKind.StaticKeyword))) return false;
541
633
  for (const clause of declaration.heritageClauses ?? []) {
@@ -547,6 +639,10 @@ function hasOrdinaryInstanceCheck(checker, declaration, seen) {
547
639
  }
548
640
  return true;
549
641
  }
642
+ function canonicalSymbol(checker, node) {
643
+ const symbol = checker.getSymbolAtLocation(node);
644
+ return symbol === void 0 ? void 0 : (symbol.flags & ts.SymbolFlags.Alias) !== 0 ? checker.getAliasedSymbol(symbol) : symbol;
645
+ }
550
646
  var require_explicit_contract_implementation_default = createRule({
551
647
  name: "require-explicit-contract-implementation",
552
648
  documentation: REQUIRE_EXPLICIT_CONTRACT_IMPLEMENTATION_DOCUMENTATION,
@@ -576,22 +672,13 @@ var require_explicit_contract_implementation_default = createRule({
576
672
  if (argument.type !== AST_NODE_TYPES.NewExpression) continue;
577
673
  const parameter = parameters[index];
578
674
  if (parameter === void 0) continue;
579
- const parameterType = checker.getTypeOfSymbolAtLocation(parameter, tsNode);
580
- const contractType = behavioralContract(checker, parameterType);
581
- if (contractType === null) continue;
582
- const contractSymbol = contractType.getSymbol();
583
- if (contractSymbol === void 0 || !hasNominalRejectionGuard(checker, signature, parameter, contractSymbol)) continue;
584
675
  const tsArgument = services.esTreeNodeToTSNodeMap.get(argument);
585
- const actualType = checker.getTypeAtLocation(tsArgument);
586
- if (!checker.isTypeAssignableTo(actualType, contractType)) continue;
587
- const implementation = ownedClass(checker, tsArgument);
588
- if (implementation === null) continue;
589
- const relationship = nominallyInherits(checker, implementation, contractSymbol, /* @__PURE__ */ new Set());
590
- if (relationship !== false) continue;
676
+ const missing = missingImplementation(checker, signature, parameter, tsNode, tsArgument);
677
+ if (missing === null || !closedNominalBoundary(services.program, checker, tsNode, consumer, missing)) continue;
591
678
  context.report({
592
679
  node: argument,
593
680
  messageId: "declareActualContract",
594
- data: { implementation: implementation.name?.text ?? "class", contract: contractSymbol.getName() }
681
+ data: { implementation: missing.implementation.name?.text ?? "class", contract: missing.contractSymbol.getName() }
595
682
  });
596
683
  }
597
684
  }
@@ -1431,7 +1518,7 @@ function abstractContractOperations(node, functionAliases) {
1431
1518
 
1432
1519
  // src/rules/require-explicit-service-contract.ts
1433
1520
  var REQUIRE_EXPLICIT_SERVICE_CONTRACT_DOCUMENTATION = {
1434
- defaultLevel: "warning",
1521
+ defaultLevel: "error",
1435
1522
  summary: "Require explicit contracts for classes that invoke retained collaborators.",
1436
1523
  rationale: "A one-operation service can orchestrate a collaborator without declaring the contract that callers consume and implementations and fakes satisfy.",
1437
1524
  remediation: "Explicitly implement a focused interface or extend an abstract class covering the service operations. Export the contract only when its consumers need it.",
@@ -7440,7 +7527,7 @@ import {
7440
7527
  } from "@typescript-eslint/utils";
7441
7528
  import ts6 from "typescript";
7442
7529
  var NO_JSON_STRINGIFY_OBJECT_EQUALITY_DOCUMENTATION = {
7443
- defaultLevel: "warning",
7530
+ defaultLevel: "error",
7444
7531
  summary: "Do not use JSON serialization as structural object equality.",
7445
7532
  rationale: "JSON text equality depends on property insertion order and serialization behavior, so semantically equal objects can compare unequal and distinct values can collapse together.",
7446
7533
  remediation: "Compare an explicit domain projection structurally, or use a reviewed canonical serializer when JSON semantics are required.",
@@ -12674,7 +12761,7 @@ var TEST_MODULES = /* @__PURE__ */ new Set(["vitest", "@jest/globals", "bun:test
12674
12761
  var TEST_NAMES2 = /* @__PURE__ */ new Set(["it", "test"]);
12675
12762
  var MODIFIERS = /* @__PURE__ */ new Set(["only", "skip", "concurrent", "fails", "failing", "todo"]);
12676
12763
  var NO_DUPLICATE_TEST_CASE_DOCUMENTATION = {
12677
- defaultLevel: "warning",
12764
+ defaultLevel: "error",
12678
12765
  summary: "Report repeated literal rows in framework test.each or it.each tables.",
12679
12766
  rationale: "Identical rows repeat the same inputs and expected values without exposing a distinct case. Accidental duplicates consume test time and hide a missing boundary vector.",
12680
12767
  remediation: "Remove the accidental duplicate or replace it with the intended distinct boundary. Preserve intentional repeated or stateful scenarios with a local explanation; do not delete their coverage automatically.",
@@ -17552,7 +17639,7 @@ var OPERATIONAL_ROLES = /* @__PURE__ */ new Set([
17552
17639
  ]);
17553
17640
  var MAX_ALIAS_DEPTH = 16;
17554
17641
  var PREFER_NOMINAL_ID_TYPES_DOCUMENTATION = {
17555
- defaultLevel: "warning",
17642
+ defaultLevel: "error",
17556
17643
  summary: "Distinguish identifier roles sharing primitive types at callable boundaries.",
17557
17644
  rationale: "Two identifier roles represented by the same primitive accept each other's values, so swapped arguments survive type checking. Transparent aliases do not prevent this.",
17558
17645
  remediation: "Introduce distinct branded identifier types at a validated domain boundary and use them in the callable contract. Keep wire representations primitive until validation; suppress a required external signature locally with a reason.",
@@ -17717,14 +17804,14 @@ var prefer_named_callback_domain_default = createRule({
17717
17804
  // src/rules/prefer-named-complex-return-type.ts
17718
17805
  import { AST_NODE_TYPES as AST_NODE_TYPES86 } from "@typescript-eslint/utils";
17719
17806
  var PREFER_NAMED_COMPLEX_RETURN_TYPE_DOCUMENTATION = {
17720
- defaultLevel: "warning",
17807
+ defaultLevel: "error",
17721
17808
  summary: "Prefer a named contract for structurally complex function return types.",
17722
17809
  rationale: "A large inline return annotation hides a reusable domain concept and makes signatures difficult to scan.",
17723
17810
  remediation: "Name the complex nested shape while preserving its generic wrappers and type parameters; reference the named contract from the return annotation.",
17724
17811
  category: "maintainability",
17725
17812
  limitations: [
17726
17813
  "Only explicit object types with at least three members and unions with at least three object variants are reported.",
17727
- "Any single-argument generic wrapper is traversed to find nested shapes, not assumed semantically transparent. Inferred return types are outside this rule; extraction is manual and must preserve locally bound type parameters."
17814
+ "Any single-argument generic wrapper is traversed to find nested shapes, not assumed semantically transparent. Inferred return types are outside this rule; extraction is manual and must preserve locally bound type parameters with generic named contracts. Types depending on polymorphic this or a local value query are excluded."
17728
17815
  ],
17729
17816
  examples: [
17730
17817
  { id: "named-result", title: "Name a multi-state result", outcome: "no-match", files: [{ path: "src/queue.ts", source: "type ClaimResult = { state: 'idle' } | { state: 'waiting'; retryAt: number } | { state: 'claimed'; id: string }; export function claim(): ClaimResult { return { state: 'idle' }; }" }], focusPath: "src/queue.ts", expectedCount: 0, public: true },
@@ -17740,10 +17827,13 @@ function unwrap4(node) {
17740
17827
  }
17741
17828
  function report(context, node) {
17742
17829
  const annotation = node.returnType?.typeAnnotation;
17743
- if (annotation !== void 0 && isComplex(annotation)) {
17830
+ if (annotation !== void 0 && isComplex(annotation) && !hasValueDependency(annotation)) {
17744
17831
  context.report({ node: annotation, messageId: "nameComplexReturnType" });
17745
17832
  }
17746
17833
  }
17834
+ function hasValueDependency(node) {
17835
+ return node.type === AST_NODE_TYPES86.TSThisType || node.type === AST_NODE_TYPES86.TSTypeQuery || forEachOwnAstChild(node, hasValueDependency);
17836
+ }
17747
17837
  function isComplex(node) {
17748
17838
  const type = unwrap4(node);
17749
17839
  if (type.type === AST_NODE_TYPES86.TSTypeLiteral) return type.members.length >= 3;
@@ -19397,22 +19487,22 @@ var prefer_shared_zod_enum_default = createRule({
19397
19487
  });
19398
19488
 
19399
19489
  // src/rules/prefer-switch-for-repeated-equality.ts
19400
- import { AST_NODE_TYPES as AST_NODE_TYPES95 } from "@typescript-eslint/utils";
19490
+ import { AST_NODE_TYPES as AST_NODE_TYPES95, ASTUtils as ASTUtils57 } from "@typescript-eslint/utils";
19401
19491
  var PREFER_SWITCH_FOR_REPEATED_EQUALITY_DOCUMENTATION = {
19402
- defaultLevel: "warning",
19492
+ defaultLevel: "error",
19403
19493
  summary: "Prefer switch over long if/else-if chains that compare one value for strict equality.",
19404
19494
  rationale: "A switch makes finite dispatch cases visually uniform and easier to extend without duplicating the discriminant.",
19405
19495
  remediation: "Replace three or more strict-equality branches over the same discriminant with a switch; keep if statements for ranges, guards, and heterogeneous predicates.",
19406
19496
  category: "maintainability",
19407
19497
  limitations: [
19408
19498
  "Only direct if/else-if chains with at least three strict-equality tests are reported.",
19409
- "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.",
19410
- "Case values may be literals, enum-like member references, or upper-case named constants; dynamic expressions are excluded.",
19499
+ "The discriminant must be a resolved lexical variable or parameter; unresolved globals, calls, getters, and indexed reads are excluded. Preserve branch scopes and break/continue targets when converting manually; no autofix is offered.",
19500
+ "Case values must be primitive literals. Member references and named constants are excluded because evaluating them can observe getters or mutate the selector. Generated sources are excluded.",
19411
19501
  "The rule deliberately ignores compound predicates, loose equality, ranges, and chains that compare different discriminants."
19412
19502
  ],
19413
19503
  examples: [
19414
19504
  { id: "switch-dispatch", title: "Make finite dispatch explicit", outcome: "no-match", files: [{ path: "src/render.ts", source: "switch (kind) { case 'a': return a(); case 'b': return b(); case 'c': return c(); default: return fallback(); }" }], focusPath: "src/render.ts", expectedCount: 0, public: true },
19415
- { id: "repeated-equality", title: "Avoid repeating the discriminant", outcome: "match", files: [{ path: "src/render.ts", source: "if (kind === 'a') return a(); else if (kind === 'b') return b(); else if (kind === 'c') return c();" }], focusPath: "src/render.ts", expectedCount: 1, public: true },
19505
+ { id: "repeated-equality", title: "Avoid repeating the discriminant", outcome: "match", files: [{ path: "src/render.ts", source: "function render(kind: string) { if (kind === 'a') return a(); else if (kind === 'b') return b(); else if (kind === 'c') return c(); }" }], focusPath: "src/render.ts", expectedCount: 1, public: true },
19416
19506
  { id: "escaped-middle", scenarioId: "native-discriminant", title: "Use native identifier identity", outcome: "match", files: [{ path: "src/dispatch.ts", source: `function probe(kind){if(kind==='a')return 1;else if(\\u006bind==='b')return 2;else if(kind==='c')return 3;return 0;}
19417
19507
  console.log(JSON.stringify(["a","b","c","d"].map(probe)));` }], focusPath: "src/dispatch.ts", expectedCount: 1, public: true },
19418
19508
  { id: "different-discriminants", scenarioId: "native-discriminant", title: "Use native identifier identity", outcome: "no-match", files: [{ path: "src/dispatch.ts", source: `function probe(kind){const other="other";if(kind==='a')return 1;else if(other==='b')return 2;else if(kind==='c')return 3;return 0;}
@@ -19428,10 +19518,7 @@ function discriminantName(test) {
19428
19518
  return discriminant.type === AST_NODE_TYPES95.Identifier ? discriminant.name : null;
19429
19519
  }
19430
19520
  function isCaseValue(node) {
19431
- if (node.type === AST_NODE_TYPES95.Literal) return true;
19432
- if (node.type === AST_NODE_TYPES95.Identifier) return /^[A-Z][A-Z0-9_]*$/u.test(node.name);
19433
- if (node.type !== AST_NODE_TYPES95.MemberExpression || node.computed) return false;
19434
- return node.property.type === AST_NODE_TYPES95.Identifier && (node.object.type === AST_NODE_TYPES95.Identifier || isCaseValue(node.object));
19521
+ return node.type === AST_NODE_TYPES95.Literal && !("regex" in node);
19435
19522
  }
19436
19523
  var prefer_switch_for_repeated_equality_default = createRule({
19437
19524
  name: "prefer-switch-for-repeated-equality",
@@ -19446,11 +19533,16 @@ var prefer_switch_for_repeated_equality_default = createRule({
19446
19533
  },
19447
19534
  defaultOptions: [],
19448
19535
  create(context) {
19536
+ if (isGeneratedFile(context.filename, context.sourceCode.text)) return {};
19449
19537
  return {
19450
19538
  IfStatement(node) {
19451
19539
  if (node.parent.type === AST_NODE_TYPES95.IfStatement && node.parent.alternate === node) return;
19452
19540
  const first = discriminantName(node.test);
19453
19541
  if (first === null) return;
19542
+ const binding = ASTUtils57.findVariable(context.sourceCode.getScope(node), first);
19543
+ if (binding === null || binding.defs.length !== 1 || binding.scope.type === "global") return;
19544
+ const [definition] = binding.defs;
19545
+ if (definition?.type !== "Parameter" && definition?.type !== "Variable") return;
19454
19546
  let count = 1;
19455
19547
  let current = node.alternate;
19456
19548
  while (current?.type === AST_NODE_TYPES95.IfStatement) {
@@ -19994,7 +20086,7 @@ function packageWorkspaceGlobs(parsed) {
19994
20086
  }
19995
20087
 
19996
20088
  // src/rules/prefer-server-actions.ts
19997
- import { ASTUtils as ASTUtils57 } from "@typescript-eslint/utils";
20089
+ import { ASTUtils as ASTUtils58 } from "@typescript-eslint/utils";
19998
20090
  var PREFER_SERVER_ACTIONS_DOCUMENTATION = {
19999
20091
  summary: "Prefer Next.js Server Actions over same-origin API mutations.",
20000
20092
  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.",
@@ -20027,7 +20119,7 @@ function resolveNode(node, context) {
20027
20119
  node = node == null ? node : unwrapExpression(node);
20028
20120
  if (!node) return null;
20029
20121
  if (node.type !== "Identifier") return node;
20030
- const variable = ASTUtils57.findVariable(getScope(context, node), node.name);
20122
+ const variable = ASTUtils58.findVariable(getScope(context, node), node.name);
20031
20123
  const definition = variable?.defs.length === 1 ? variable.defs[0] : void 0;
20032
20124
  if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || variable?.references.some((reference) => reference.isWrite() && reference.init !== true)) return node;
20033
20125
  if (definition.node.init.type === "ObjectExpression" && variable?.references.some((reference) => reference.identifier !== node && reference.init !== true)) return node;
@@ -20036,7 +20128,7 @@ function resolveNode(node, context) {
20036
20128
  function isAxiosClient(node, context, seen = /* @__PURE__ */ new Set()) {
20037
20129
  if (node.type !== "Identifier" || seen.has(node)) return false;
20038
20130
  seen.add(node);
20039
- const variable = ASTUtils57.findVariable(getScope(context, node), node.name);
20131
+ const variable = ASTUtils58.findVariable(getScope(context, node), node.name);
20040
20132
  const definition = variable?.defs.length === 1 ? variable.defs[0] : void 0;
20041
20133
  if (definition === void 0 || variable?.references.some((reference) => reference.isWrite() && reference.init !== true)) return false;
20042
20134
  if (variable?.references.some((reference) => {
@@ -20120,10 +20212,10 @@ function isFunctionArgument(node, context) {
20120
20212
  }
20121
20213
  function getPropertyNode(objNode, propName2) {
20122
20214
  if (!objNode || objNode.type !== "ObjectExpression") return null;
20123
- if (objNode.properties.some((property) => property.type === "SpreadElement" || ASTUtils57.getPropertyName(property) === null)) return null;
20215
+ if (objNode.properties.some((property) => property.type === "SpreadElement" || ASTUtils58.getPropertyName(property) === null)) return null;
20124
20216
  for (const prop of [...objNode.properties].reverse()) {
20125
20217
  if (prop.type !== "Property") continue;
20126
- const keyName = ASTUtils57.getPropertyName(prop);
20218
+ const keyName = ASTUtils58.getPropertyName(prop);
20127
20219
  if (keyName === propName2) {
20128
20220
  if (prop.value.type === "AssignmentPattern" || prop.value.type === "ArrayPattern" || prop.value.type === "ObjectPattern") {
20129
20221
  return null;
@@ -20247,7 +20339,7 @@ var prefer_server_actions_default = createRule({
20247
20339
  });
20248
20340
 
20249
20341
  // src/rules/prefer-whole-object-assertion.ts
20250
- import { AST_NODE_TYPES as AST_NODE_TYPES97, ASTUtils as ASTUtils58 } from "@typescript-eslint/utils";
20342
+ import { AST_NODE_TYPES as AST_NODE_TYPES97, ASTUtils as ASTUtils59 } from "@typescript-eslint/utils";
20251
20343
  var MERGEABLE_MATCHERS = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual"]);
20252
20344
  var SYNTHETIC_LITERAL_MATCHERS = /* @__PURE__ */ new Map([
20253
20345
  ["toBeNull", "null"]
@@ -20312,7 +20404,7 @@ function propertyAccess(node) {
20312
20404
  const path = [];
20313
20405
  let current = node;
20314
20406
  while (current.type === AST_NODE_TYPES97.MemberExpression && !current.optional) {
20315
- const name = ASTUtils58.getPropertyName(current);
20407
+ const name = ASTUtils59.getPropertyName(current);
20316
20408
  if (name === null || COLLECTION_PROPERTIES.has(name) || LITERAL_KEY_HAZARDS.has(name)) return null;
20317
20409
  path.unshift(name);
20318
20410
  current = unwrapExpression(current.object);
@@ -20459,7 +20551,7 @@ var prefer_whole_object_assertion_default = createRule({
20459
20551
  const callee = unwrapExpression(call.callee);
20460
20552
  const calleeReceiver = callee.type === AST_NODE_TYPES97.MemberExpression ? unwrapExpression(callee.object) : callee;
20461
20553
  if (callee.type !== AST_NODE_TYPES97.MemberExpression) return null;
20462
- const matcher = ASTUtils58.getPropertyName(callee);
20554
+ const matcher = ASTUtils59.getPropertyName(callee);
20463
20555
  if (matcher === null) return null;
20464
20556
  const expectCall = calleeReceiver;
20465
20557
  const expectCallee = expectCall.type === AST_NODE_TYPES97.CallExpression ? unwrapExpression(expectCall.callee) : null;
@@ -20489,7 +20581,7 @@ var prefer_whole_object_assertion_default = createRule({
20489
20581
  return assertionExpectation(statement, call, receiver, key, matcher);
20490
20582
  }
20491
20583
  function isTestExpect(callee) {
20492
- const variable = ASTUtils58.findVariable(sourceCode.getScope(callee), callee.name);
20584
+ const variable = ASTUtils59.findVariable(sourceCode.getScope(callee), callee.name);
20493
20585
  if (variable !== null && variable.defs.some((definition) => {
20494
20586
  if (definition.node.type !== AST_NODE_TYPES97.ImportSpecifier) return true;
20495
20587
  const declaration = definition.node.parent;
@@ -20532,7 +20624,7 @@ var prefer_whole_object_assertion_default = createRule({
20532
20624
  });
20533
20625
 
20534
20626
  // src/rules/repeated-static-call-cases.ts
20535
- import { AST_NODE_TYPES as AST_NODE_TYPES98, ASTUtils as ASTUtils59 } from "@typescript-eslint/utils";
20627
+ import { AST_NODE_TYPES as AST_NODE_TYPES98, ASTUtils as ASTUtils60 } from "@typescript-eslint/utils";
20536
20628
  var REPEATED_STATIC_CALL_CASES_DOCUMENTATION = {
20537
20629
  summary: "Review three or more consecutive static-input call assertions as potential named cases.",
20538
20630
  rationale: "Copy-pasted cases obscure the input table, and a thrown assertion can stop later cases from being reported.",
@@ -20553,7 +20645,7 @@ var EXPECT_MODIFIERS = /* @__PURE__ */ new Set(["not", "rejects", "resolves"]);
20553
20645
  var SNAPSHOT_MATCHERS = /snapshot/iu;
20554
20646
  var MIN_CASES2 = 3;
20555
20647
  function importedName6(identifier, context, modules) {
20556
- const variable = ASTUtils59.findVariable(context.sourceCode.getScope(identifier), identifier.name);
20648
+ const variable = ASTUtils60.findVariable(context.sourceCode.getScope(identifier), identifier.name);
20557
20649
  if (variable === null || variable.defs.length === 0) return identifier.name;
20558
20650
  for (const definition of variable.defs) {
20559
20651
  if (definition.node.type !== AST_NODE_TYPES98.ImportSpecifier) continue;
@@ -20575,7 +20667,7 @@ function testRoot2(callee) {
20575
20667
  callee = unwrapExpression(callee);
20576
20668
  if (callee.type === AST_NODE_TYPES98.Identifier) return callee;
20577
20669
  if (callee.type !== AST_NODE_TYPES98.MemberExpression) return null;
20578
- const modifier = ASTUtils59.getPropertyName(callee);
20670
+ const modifier = ASTUtils60.getPropertyName(callee);
20579
20671
  return modifier !== null && TEST_MODIFIERS5.has(modifier) ? testRoot2(callee.object) : null;
20580
20672
  }
20581
20673
  function isStatic(input) {
@@ -20621,8 +20713,8 @@ function assertionShape(statement, context, callback) {
20621
20713
  const matcherCall = unwrapExpression(statement.expression);
20622
20714
  if (matcherCall.type !== AST_NODE_TYPES98.CallExpression) return null;
20623
20715
  const matcherCallee = unwrapExpression(matcherCall.callee);
20624
- if (matcherCallee.type !== AST_NODE_TYPES98.MemberExpression || ASTUtils59.getPropertyName(matcherCallee) === null || matcherCall.arguments.length !== 1) return null;
20625
- const matcher = ASTUtils59.getPropertyName(matcherCallee) ?? "";
20716
+ if (matcherCallee.type !== AST_NODE_TYPES98.MemberExpression || ASTUtils60.getPropertyName(matcherCallee) === null || matcherCall.arguments.length !== 1) return null;
20717
+ const matcher = ASTUtils60.getPropertyName(matcherCallee) ?? "";
20626
20718
  if (SNAPSHOT_MATCHERS.test(matcher)) return null;
20627
20719
  const chain = expectCallFromMatcher(matcherCallee);
20628
20720
  const expectCallee = chain === null ? null : unwrapExpression(chain.call.callee);
@@ -20632,7 +20724,7 @@ function assertionShape(statement, context, callback) {
20632
20724
  const observedCallee = observed?.type === AST_NODE_TYPES98.CallExpression ? unwrapExpression(observed.callee) : null;
20633
20725
  if (observed?.type !== AST_NODE_TYPES98.CallExpression || observedCallee?.type !== AST_NODE_TYPES98.Identifier || observed.arguments.length === 0 || observed.arguments.some((arg) => arg.type === AST_NODE_TYPES98.SpreadElement || !isStatic(arg)) || expected?.type === AST_NODE_TYPES98.SpreadElement || expected === void 0 || !isStatic(expected)) return null;
20634
20726
  const skeleton = `${observedCallee.name}/${observed.arguments.map((item) => staticShape(item)).join(",")}/${chain.modifiers.join(".")}/${matcher}/${staticShape(expected)}`;
20635
- const binding = ASTUtils59.findVariable(context.sourceCode.getScope(observedCallee), observedCallee.name);
20727
+ const binding = ASTUtils60.findVariable(context.sourceCode.getScope(observedCallee), observedCallee.name);
20636
20728
  if (binding?.defs.some(
20637
20729
  (definition) => definition.node.range[0] >= callback.range[0] && definition.node.range[1] <= callback.range[1]
20638
20730
  )) return null;
@@ -20643,7 +20735,7 @@ function expectCallFromMatcher(node) {
20643
20735
  const modifiers = [];
20644
20736
  let receiver = node.object;
20645
20737
  while (receiver.type === AST_NODE_TYPES98.MemberExpression) {
20646
- const modifier = ASTUtils59.getPropertyName(receiver);
20738
+ const modifier = ASTUtils60.getPropertyName(receiver);
20647
20739
  if (modifier === null || !EXPECT_MODIFIERS.has(modifier)) return null;
20648
20740
  modifiers.unshift(modifier);
20649
20741
  receiver = receiver.object;
@@ -20719,7 +20811,7 @@ var repeated_static_call_cases_default = createRule({
20719
20811
  });
20720
20812
 
20721
20813
  // src/rules/prefer-zod-infer.ts
20722
- import { ASTUtils as ASTUtils60, AST_NODE_TYPES as AST_NODE_TYPES99 } from "@typescript-eslint/utils";
20814
+ import { ASTUtils as ASTUtils61, AST_NODE_TYPES as AST_NODE_TYPES99 } from "@typescript-eslint/utils";
20723
20815
  var PREFER_ZOD_INFER_DOCUMENTATION = {
20724
20816
  summary: "Derive a type from its Zod schema with `z.infer` instead of hand-writing a twin declaration beside it.",
20725
20817
  rationale: "A derived type stays synchronized when the runtime schema changes.",
@@ -21037,7 +21129,7 @@ function twinCallChain(node, zodNamespaces) {
21037
21129
  while (current.type === AST_NODE_TYPES99.CallExpression) {
21038
21130
  const callee = unwrapExpression(current.callee);
21039
21131
  const calleeReceiver = callee.type === AST_NODE_TYPES99.MemberExpression ? unwrapExpression(callee.object) : callee;
21040
- if (callee.type !== AST_NODE_TYPES99.MemberExpression || ASTUtils60.getPropertyName(callee) === null) {
21132
+ if (callee.type !== AST_NODE_TYPES99.MemberExpression || ASTUtils61.getPropertyName(callee) === null) {
21041
21133
  return null;
21042
21134
  }
21043
21135
  chain.push(current);
@@ -21050,7 +21142,7 @@ function twinCallChain(node, zodNamespaces) {
21050
21142
  }
21051
21143
  function twinMethodName(call) {
21052
21144
  const callee = unwrapExpression(call.callee);
21053
- return callee.type === AST_NODE_TYPES99.MemberExpression && ASTUtils60.getPropertyName(callee) !== null ? ASTUtils60.getPropertyName(callee) ?? "" : "";
21145
+ return callee.type === AST_NODE_TYPES99.MemberExpression && ASTUtils61.getPropertyName(callee) !== null ? ASTUtils61.getPropertyName(callee) ?? "" : "";
21054
21146
  }
21055
21147
  function twinSchemaFields(initializer, zodNamespaces) {
21056
21148
  const chain = twinCallChain(initializer, zodNamespaces);
@@ -21065,7 +21157,7 @@ function twinSchemaFields(initializer, zodNamespaces) {
21065
21157
  const fields = /* @__PURE__ */ new Map();
21066
21158
  for (const property of shape.properties) {
21067
21159
  if (property.type !== AST_NODE_TYPES99.Property) return null;
21068
- const name = ASTUtils60.getPropertyName(property);
21160
+ const name = ASTUtils61.getPropertyName(property);
21069
21161
  if (name === null) return null;
21070
21162
  fields.set(name, twinSchemaField(property.value, zodNamespaces));
21071
21163
  }
@@ -21079,16 +21171,16 @@ function twinSchemaField(node, zodNamespaces) {
21079
21171
  while (current.type === AST_NODE_TYPES99.CallExpression) {
21080
21172
  const callee = unwrapExpression(current.callee);
21081
21173
  const calleeReceiver = callee.type === AST_NODE_TYPES99.MemberExpression ? unwrapExpression(callee.object) : callee;
21082
- if (callee.type !== AST_NODE_TYPES99.MemberExpression || ASTUtils60.getPropertyName(callee) === null) {
21174
+ if (callee.type !== AST_NODE_TYPES99.MemberExpression || ASTUtils61.getPropertyName(callee) === null) {
21083
21175
  break;
21084
21176
  }
21085
21177
  const receiver = calleeReceiver;
21086
21178
  if (receiver.type === AST_NODE_TYPES99.Identifier && zodNamespaces.has(receiver.name)) {
21087
- leaf = ASTUtils60.getPropertyName(callee) ?? "";
21179
+ leaf = ASTUtils61.getPropertyName(callee) ?? "";
21088
21180
  leafCall = current;
21089
21181
  break;
21090
21182
  }
21091
- modifiers.push(ASTUtils60.getPropertyName(callee) ?? "");
21183
+ modifiers.push(ASTUtils61.getPropertyName(callee) ?? "");
21092
21184
  current = receiver;
21093
21185
  }
21094
21186
  return {
@@ -21291,7 +21383,7 @@ var prefer_zod_infer_default = createRule({
21291
21383
  },
21292
21384
  /** Records `XSchema.transform(...)` and equivalent module-level reshaping. */
21293
21385
  "MemberExpression"(node) {
21294
- if (node.object.type === AST_NODE_TYPES99.Identifier && ASTUtils60.getPropertyName(node) !== null && isPreferZodInferModuleReshaper(ASTUtils60.getPropertyName(node) ?? "")) {
21386
+ if (node.object.type === AST_NODE_TYPES99.Identifier && ASTUtils61.getPropertyName(node) !== null && isPreferZodInferModuleReshaper(ASTUtils61.getPropertyName(node) ?? "")) {
21295
21387
  reshapedSchemaNames.add(node.object.name);
21296
21388
  }
21297
21389
  },
@@ -21448,7 +21540,7 @@ function staticFieldName(key) {
21448
21540
  }
21449
21541
 
21450
21542
  // src/rules/named-child-schema-type.ts
21451
- import { AST_NODE_TYPES as AST_NODE_TYPES100, ASTUtils as ASTUtils61 } from "@typescript-eslint/utils";
21543
+ import { AST_NODE_TYPES as AST_NODE_TYPES100, ASTUtils as ASTUtils62 } from "@typescript-eslint/utils";
21452
21544
  var UNRESOLVED_TYPE_NODES = /* @__PURE__ */ new Set([
21453
21545
  AST_NODE_TYPES100.TSTypeQuery,
21454
21546
  AST_NODE_TYPES100.TSImportType,
@@ -21457,17 +21549,17 @@ var UNRESOLVED_TYPE_NODES = /* @__PURE__ */ new Set([
21457
21549
  AST_NODE_TYPES100.TSUnknownKeyword
21458
21550
  ]);
21459
21551
  var NAMED_CHILD_SCHEMA_TYPE_DOCUMENTATION = {
21460
- defaultLevel: "warning",
21552
+ defaultLevel: "error",
21461
21553
  summary: "Reference a named Zod record child's complete schema type instead of repeating its explicit annotation.",
21462
21554
  rationale: "Repeating a child schema's generic contract creates a second maintained declaration even though the record already uses that child at runtime.",
21463
- remediation: "Replace only the matching record type argument with `typeof ChildSchema`; retain the outer annotation required by isolatedDeclarations and every runtime schema operation.",
21555
+ remediation: "Replace only the matching record type argument with `typeof ChildSchema`, or share one explicit named schema type alias between child and record to retain an independently named public contract. Keep the outer annotation required by isolatedDeclarations and every runtime schema operation.",
21464
21556
  category: "maintainability",
21465
21557
  autofix: "none",
21466
21558
  limitations: [
21467
21559
  "Only direct module-level const z.record calls with two arguments, a ZodRecord annotation, and an earlier local const child with a complete explicit Zod type are inspected.",
21468
21560
  "The entire generic child annotation must match token for token; input/output, defaults, transforms, readonly modifiers and brands are never compared by output shape alone.",
21469
21561
  "Bare leaf types, broad ZodType constraints, type queries, imported or unqualified type references, annotation cycles, comments on the repeated argument, mutable bindings and generated files are excluded.",
21470
- "Import aliases and namespace imports resolve through scope bindings. Independent public contract pins require review; this warning does not remove annotations or change runtime validation."
21562
+ "Import aliases and namespace imports resolve through scope bindings. Independent public contract pins can use one shared named type alias or an exact reasoned suppression; runtime validation and outer annotations are preserved."
21471
21563
  ],
21472
21564
  examples: [
21473
21565
  { id: "named-child", title: "Reference the named child contract", outcome: "no-match", files: [{ path: "src/record.ts", source: 'import { z } from "zod"; const KeySchema: z.ZodEnum<{ a: "a"; b: "b" }> = z.enum(["a", "b"]); export const RecordSchema: z.ZodRecord<typeof KeySchema, z.ZodString> = z.record(KeySchema, z.string());' }], focusPath: "src/record.ts", expectedCount: 0, public: true },
@@ -21486,14 +21578,14 @@ var named_child_schema_type_default = createRule({
21486
21578
  type: "suggestion",
21487
21579
  docs: { description: NAMED_CHILD_SCHEMA_TYPE_DOCUMENTATION.summary },
21488
21580
  schema: [],
21489
- messages: { namedChildType: "Use `typeof {{name}}` for this exact child contract; keep the outer schema annotation and runtime operations." }
21581
+ messages: { namedChildType: "Use `typeof {{name}}` or one shared named type alias for this exact child contract; keep the outer schema annotation and runtime operations." }
21490
21582
  },
21491
21583
  defaultOptions: [],
21492
21584
  create(context) {
21493
21585
  const source = context.sourceCode;
21494
21586
  if (isGeneratedFile(context.filename, source.text)) return {};
21495
21587
  const namespaces = /* @__PURE__ */ new Set();
21496
- const bindingOf = (node) => ASTUtils61.findVariable(source.getScope(node), node.name);
21588
+ const bindingOf = (node) => ASTUtils62.findVariable(source.getScope(node), node.name);
21497
21589
  function namespaceOf(type) {
21498
21590
  if (type.typeName.type !== AST_NODE_TYPES100.TSQualifiedName || type.typeName.left.type !== AST_NODE_TYPES100.Identifier) return null;
21499
21591
  const binding = bindingOf(type.typeName.left);
@@ -21537,7 +21629,7 @@ var named_child_schema_type_default = createRule({
21537
21629
  VariableDeclarator(node) {
21538
21630
  if (!isModuleConst(node) || node.id.type !== AST_NODE_TYPES100.Identifier || node.init?.type !== AST_NODE_TYPES100.CallExpression) return;
21539
21631
  const call = node.init;
21540
- if (call.arguments.length !== 2 || call.callee.type !== AST_NODE_TYPES100.MemberExpression || call.callee.object.type !== AST_NODE_TYPES100.Identifier || ASTUtils61.getPropertyName(call.callee) !== "record") return;
21632
+ if (call.arguments.length !== 2 || call.callee.type !== AST_NODE_TYPES100.MemberExpression || call.callee.object.type !== AST_NODE_TYPES100.Identifier || ASTUtils62.getPropertyName(call.callee) !== "record") return;
21541
21633
  const annotation = node.id.typeAnnotation?.typeAnnotation;
21542
21634
  if (annotation?.type !== AST_NODE_TYPES100.TSTypeReference || annotation.typeName.type !== AST_NODE_TYPES100.TSQualifiedName || annotation.typeName.right.name !== "ZodRecord") return;
21543
21635
  const namespace = namespaceOf(annotation);
@@ -21553,7 +21645,7 @@ var named_child_schema_type_default = createRule({
21553
21645
 
21554
21646
  // src/rules/prefer-zod-parse-output-type.ts
21555
21647
  import {
21556
- ASTUtils as ASTUtils62,
21648
+ ASTUtils as ASTUtils63,
21557
21649
  AST_NODE_TYPES as AST_NODE_TYPES101,
21558
21650
  ESLintUtils as ESLintUtils14
21559
21651
  } from "@typescript-eslint/utils";
@@ -21623,11 +21715,11 @@ function isLocalZodObjectSchema(node, namespaces) {
21623
21715
  while (current.type === AST_NODE_TYPES101.CallExpression) {
21624
21716
  const callee = unwrapExpression(current.callee);
21625
21717
  const calleeReceiver = callee.type === AST_NODE_TYPES101.MemberExpression ? unwrapExpression(callee.object) : callee;
21626
- if (callee.type !== AST_NODE_TYPES101.MemberExpression || ASTUtils62.getPropertyName(callee) === null) {
21718
+ if (callee.type !== AST_NODE_TYPES101.MemberExpression || ASTUtils63.getPropertyName(callee) === null) {
21627
21719
  return false;
21628
21720
  }
21629
21721
  if (calleeReceiver.type === AST_NODE_TYPES101.Identifier) {
21630
- return namespaces.has(calleeReceiver.name) && ((ASTUtils62.getPropertyName(callee) ?? "") === "object" || (ASTUtils62.getPropertyName(callee) ?? "") === "strictObject");
21722
+ return namespaces.has(calleeReceiver.name) && ((ASTUtils63.getPropertyName(callee) ?? "") === "object" || (ASTUtils63.getPropertyName(callee) ?? "") === "strictObject");
21631
21723
  }
21632
21724
  current = calleeReceiver;
21633
21725
  }
@@ -21636,10 +21728,10 @@ function isLocalZodObjectSchema(node, namespaces) {
21636
21728
  function zodParseCall(node) {
21637
21729
  const callee = unwrapExpression(node.callee);
21638
21730
  const calleeReceiver = callee.type === AST_NODE_TYPES101.MemberExpression ? unwrapExpression(callee.object) : callee;
21639
- if (callee.type !== AST_NODE_TYPES101.MemberExpression || calleeReceiver.type !== AST_NODE_TYPES101.Identifier || ASTUtils62.getPropertyName(callee) === null) {
21731
+ if (callee.type !== AST_NODE_TYPES101.MemberExpression || calleeReceiver.type !== AST_NODE_TYPES101.Identifier || ASTUtils63.getPropertyName(callee) === null) {
21640
21732
  return null;
21641
21733
  }
21642
- const method = ASTUtils62.getPropertyName(callee);
21734
+ const method = ASTUtils63.getPropertyName(callee);
21643
21735
  if (method !== "parse" && method !== "safeParse") return null;
21644
21736
  return {
21645
21737
  call: node,
@@ -21681,7 +21773,7 @@ function localParseReturnCandidates(node, sourceCode) {
21681
21773
  for (const reference of variable.references) {
21682
21774
  const identifier = reference.identifier;
21683
21775
  const parent = identifier.parent;
21684
- const output = parsed.method === "parse" ? identifier : parent.type === AST_NODE_TYPES101.MemberExpression && parent.object === identifier && ASTUtils62.getPropertyName(parent) !== null && (ASTUtils62.getPropertyName(parent) ?? "") === "data" ? parent : null;
21776
+ const output = parsed.method === "parse" ? identifier : parent.type === AST_NODE_TYPES101.MemberExpression && parent.object === identifier && ASTUtils63.getPropertyName(parent) !== null && (ASTUtils63.getPropertyName(parent) ?? "") === "data" ? parent : null;
21685
21777
  if (output === null) continue;
21686
21778
  const candidate2 = returnedOutputCandidate(parsed, output);
21687
21779
  if (candidate2 !== null) candidates.push(candidate2);
@@ -22064,7 +22156,7 @@ var require_assert_never_default = createRule({
22064
22156
  });
22065
22157
 
22066
22158
  // src/rules/require-fetch-timeout.ts
22067
- import { AST_NODE_TYPES as AST_NODE_TYPES103, ASTUtils as ASTUtils63 } from "@typescript-eslint/utils";
22159
+ import { AST_NODE_TYPES as AST_NODE_TYPES103, ASTUtils as ASTUtils64 } from "@typescript-eslint/utils";
22068
22160
  var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
22069
22161
  summary: "Require an explicit abort signal on locally analyzable global fetch calls.",
22070
22162
  rationale: "An unbounded request can occupy work indefinitely when an upstream stalls.",
@@ -22148,7 +22240,7 @@ var require_fetch_timeout_default = createRule({
22148
22240
  }
22149
22241
  function resolvesToGlobal(identifier) {
22150
22242
  const scope = context.sourceCode.getScope(identifier);
22151
- const variable = ASTUtils63.findVariable(scope, identifier.name);
22243
+ const variable = ASTUtils64.findVariable(scope, identifier.name);
22152
22244
  return variable === null || variable.defs.length === 0;
22153
22245
  }
22154
22246
  function isGlobalFetchCall2(callee) {
@@ -22158,7 +22250,7 @@ var require_fetch_timeout_default = createRule({
22158
22250
  return callee.type === AST_NODE_TYPES103.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES103.Identifier && callee.property.name === "fetch" && callee.object.type === AST_NODE_TYPES103.Identifier && GLOBAL_OBJECTS2.has(callee.object.name) && resolvesToGlobal(callee.object);
22159
22251
  }
22160
22252
  function localConstInitProvablyLacksSignal(identifier) {
22161
- const variable = ASTUtils63.findVariable(
22253
+ const variable = ASTUtils64.findVariable(
22162
22254
  context.sourceCode.getScope(identifier),
22163
22255
  identifier.name
22164
22256
  );
@@ -22180,7 +22272,7 @@ var require_fetch_timeout_default = createRule({
22180
22272
  function isForwardedRequest(argument) {
22181
22273
  let value = argument;
22182
22274
  if (value.type === AST_NODE_TYPES103.Identifier) {
22183
- const binding = ASTUtils63.findVariable(context.sourceCode.getScope(value), value.name);
22275
+ const binding = ASTUtils64.findVariable(context.sourceCode.getScope(value), value.name);
22184
22276
  const definition = binding?.defs.length === 1 ? binding.defs[0] : void 0;
22185
22277
  if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || binding?.references.some((reference) => reference.isWrite() && reference.init !== true)) return false;
22186
22278
  value = definition.node.init;
@@ -22208,15 +22300,15 @@ var require_fetch_timeout_default = createRule({
22208
22300
  // src/rules/require-interface-for-exported-class.ts
22209
22301
  import { AST_NODE_TYPES as AST_NODE_TYPES104 } from "@typescript-eslint/utils";
22210
22302
  var REQUIRE_INTERFACE_FOR_EXPORTED_CLASS_DOCUMENTATION = {
22211
- defaultLevel: "warning",
22303
+ defaultLevel: "error",
22212
22304
  summary: "Require exported concrete classes with public behavior to declare a contract.",
22213
22305
  rationale: "An explicit contract names the intended public capability separately from implementation details. TypeScript already supports structural compatibility; this is an architecture policy, not a prerequisite for substitution.",
22214
22306
  remediation: "Declare a focused interface and add an implements clause, or inherit from an intentional base contract.",
22215
22307
  category: "architecture",
22216
22308
  limitations: [
22217
22309
  "JavaScript files are excluded because implements is TypeScript syntax; imported framework base contracts still require manual policy review.",
22218
- "An exported injected service may also receive require-port-for-service: its service-boundary error and this general exported-contract warning intentionally enforce distinct policy scopes.",
22219
- "The warning-stage rule checks module-level class declarations and direct class-expression values exported directly, through local export specifiers, or through a default identifier; re-exports and expressions wrapped in other calls require review.",
22310
+ "An exported injected service may also receive require-port-for-service: the two diagnostics intentionally enforce distinct service-boundary and general exported-contract policy scopes.",
22311
+ "The rule checks module-level class declarations and direct class-expression values exported directly, through local export specifiers, or through a default identifier; re-exports and expressions wrapped in other calls require review.",
22220
22312
  "An extends clause satisfies the contract only when its target is a locally declared abstract class; imported base-class contracts require an explicit implements clause.",
22221
22313
  "Static factories and data-only classes without public instance methods are outside the contract requirement."
22222
22314
  ],
@@ -22355,7 +22447,7 @@ function exportedClasses(program, classes) {
22355
22447
  }
22356
22448
 
22357
22449
  // src/rules/require-sql-access-class.ts
22358
- import { AST_NODE_TYPES as AST_NODE_TYPES105, ASTUtils as ASTUtils64 } from "@typescript-eslint/utils";
22450
+ import { AST_NODE_TYPES as AST_NODE_TYPES105, ASTUtils as ASTUtils65 } from "@typescript-eslint/utils";
22359
22451
  var DIRECT_EXECUTION_METHODS = /* @__PURE__ */ new Set([
22360
22452
  "all",
22361
22453
  "batch",
@@ -22462,7 +22554,7 @@ function databaseReceiver(node) {
22462
22554
  if (node.type === AST_NODE_TYPES105.Identifier)
22463
22555
  return DATABASE_NAMES.test(node.name);
22464
22556
  if (node.type !== AST_NODE_TYPES105.MemberExpression) return false;
22465
- const name = ASTUtils64.getPropertyName(node);
22557
+ const name = ASTUtils65.getPropertyName(node);
22466
22558
  return name === "DB" || name !== null && DATABASE_NAMES.test(name);
22467
22559
  }
22468
22560
  function databaseRootMember(node) {
@@ -22480,7 +22572,7 @@ function databaseRootMember(node) {
22480
22572
  }
22481
22573
  if (current.type === AST_NODE_TYPES105.MemberExpression) {
22482
22574
  if (current.object.type === AST_NODE_TYPES105.ThisExpression)
22483
- return ASTUtils64.getPropertyName(current);
22575
+ return ASTUtils65.getPropertyName(current);
22484
22576
  current = current.object;
22485
22577
  continue;
22486
22578
  }
@@ -22501,7 +22593,7 @@ function expressionHasDatabaseMarker(node) {
22501
22593
  continue;
22502
22594
  }
22503
22595
  if (current.type === AST_NODE_TYPES105.MemberExpression) {
22504
- const name = ASTUtils64.getPropertyName(current);
22596
+ const name = ASTUtils65.getPropertyName(current);
22505
22597
  if (name === "DB" || name !== null && DATABASE_NAMES.test(name))
22506
22598
  return true;
22507
22599
  current = current.object;
@@ -22520,7 +22612,7 @@ function expressionCallsBuilder(node) {
22520
22612
  }
22521
22613
  if (current.type === AST_NODE_TYPES105.CallExpression) {
22522
22614
  if (current.callee.type !== AST_NODE_TYPES105.MemberExpression) return false;
22523
- const name = ASTUtils64.getPropertyName(current.callee);
22615
+ const name = ASTUtils65.getPropertyName(current.callee);
22524
22616
  if (name !== null && BUILDER_METHODS.has(name)) return true;
22525
22617
  current = current.callee.object;
22526
22618
  continue;
@@ -22571,7 +22663,7 @@ function thisRootMember(node) {
22571
22663
  let current = node;
22572
22664
  let root = null;
22573
22665
  while (current.type === AST_NODE_TYPES105.MemberExpression) {
22574
- const name = ASTUtils64.getPropertyName(current);
22666
+ const name = ASTUtils65.getPropertyName(current);
22575
22667
  if (name === null) return null;
22576
22668
  root = name;
22577
22669
  current = current.object;
@@ -22615,19 +22707,19 @@ var require_sql_access_class_default = createRule({
22615
22707
  if (seen.has(node)) return false;
22616
22708
  seen.add(node);
22617
22709
  if (node.type === AST_NODE_TYPES105.Identifier) {
22618
- const binding = ASTUtils64.findVariable(context.sourceCode.getScope(node), node.name);
22710
+ const binding = ASTUtils65.findVariable(context.sourceCode.getScope(node), node.name);
22619
22711
  if (binding?.defs.length !== 1 || binding.references.some((reference) => reference.isWrite() && reference.init !== true)) return false;
22620
22712
  const definition = binding.defs[0];
22621
22713
  return definition?.type === "Variable" && definition.node.init !== null && knownNonDatabase(definition.node.init, seen);
22622
22714
  }
22623
- return node.type === AST_NODE_TYPES105.NewExpression && unwrappedNodeCallee?.type === AST_NODE_TYPES105.Identifier && ["Map", "WeakMap", "URLSearchParams"].includes(unwrappedNodeCallee.name) && (ASTUtils64.findVariable(context.sourceCode.getScope(unwrappedNodeCallee), unwrappedNodeCallee.name)?.defs.length ?? 0) === 0;
22715
+ return node.type === AST_NODE_TYPES105.NewExpression && unwrappedNodeCallee?.type === AST_NODE_TYPES105.Identifier && ["Map", "WeakMap", "URLSearchParams"].includes(unwrappedNodeCallee.name) && (ASTUtils65.findVariable(context.sourceCode.getScope(unwrappedNodeCallee), unwrappedNodeCallee.name)?.defs.length ?? 0) === 0;
22624
22716
  }
22625
22717
  return {
22626
22718
  CallExpression(node) {
22627
22719
  const unwrappedNodeCallee = unwrapExpression(node.callee);
22628
22720
  if (unwrappedNodeCallee.type !== AST_NODE_TYPES105.MemberExpression)
22629
22721
  return;
22630
- const method = ASTUtils64.getPropertyName(unwrappedNodeCallee);
22722
+ const method = ASTUtils65.getPropertyName(unwrappedNodeCallee);
22631
22723
  if (knownNonDatabase(unwrappedNodeCallee.object)) return;
22632
22724
  if (method === null || !isDatabaseOperation(method, unwrappedNodeCallee.object))
22633
22725
  return;
@@ -22727,7 +22819,7 @@ var require_static_next_matcher_default = createRule({
22727
22819
  });
22728
22820
 
22729
22821
  // src/rules/require-use-form-default-values.ts
22730
- import { AST_NODE_TYPES as AST_NODE_TYPES107, ASTUtils as ASTUtils65 } from "@typescript-eslint/utils";
22822
+ import { AST_NODE_TYPES as AST_NODE_TYPES107, ASTUtils as ASTUtils66 } from "@typescript-eslint/utils";
22731
22823
  var REQUIRE_USE_FORM_DEFAULT_VALUES_DOCUMENTATION = {
22732
22824
  summary: "Require explicit form-level initialization or a field default for directly bound Controller fields.",
22733
22825
  rationale: "React Hook Form exposes form-level defaultValues/values and field-level defaultValue as its explicit initialization mechanisms. A directly bound controlled field should not omit both mechanisms.",
@@ -22778,7 +22870,7 @@ var require_use_form_default_values_default = createRule({
22778
22870
  const imported = /* @__PURE__ */ new Map();
22779
22871
  const uninitializedForms = /* @__PURE__ */ new Set();
22780
22872
  const uninitializedControls = /* @__PURE__ */ new Set();
22781
- const bindingNamed = (node, name) => ASTUtils65.findVariable(context.sourceCode.getScope(node), name);
22873
+ const bindingNamed = (node, name) => ASTUtils66.findVariable(context.sourceCode.getScope(node), name);
22782
22874
  const bindingOf = (node) => bindingNamed(node, node.name);
22783
22875
  const stable = (variable) => !variable.references.some((reference) => reference.isWrite() && reference.init !== true);
22784
22876
  const importedKind = (node) => {
@@ -22824,7 +22916,7 @@ var require_use_form_default_values_default = createRule({
22824
22916
  const variable = bindingOf(node);
22825
22917
  return variable !== null && stable(variable) && uninitializedControls.has(variable);
22826
22918
  }
22827
- return node.type === AST_NODE_TYPES107.MemberExpression && ASTUtils65.getPropertyName(node) !== null && (ASTUtils65.getPropertyName(node) ?? "") === "control" && isUninitializedForm(node.object);
22919
+ return node.type === AST_NODE_TYPES107.MemberExpression && ASTUtils66.getPropertyName(node) !== null && (ASTUtils66.getPropertyName(node) ?? "") === "control" && isUninitializedForm(node.object);
22828
22920
  };
22829
22921
  const fieldOptionsNeedDefault = (node) => {
22830
22922
  if (node?.type !== AST_NODE_TYPES107.ObjectExpression) return false;
@@ -22880,7 +22972,7 @@ var require_use_form_default_values_default = createRule({
22880
22972
  trackDestructuredControl(node.id);
22881
22973
  return;
22882
22974
  }
22883
- if (node.id.type === AST_NODE_TYPES107.Identifier && node.init.type === AST_NODE_TYPES107.MemberExpression && ASTUtils65.getPropertyName(node.init) !== null && (ASTUtils65.getPropertyName(node.init) ?? "") === "control" && isUninitializedForm(node.init.object)) {
22975
+ if (node.id.type === AST_NODE_TYPES107.Identifier && node.init.type === AST_NODE_TYPES107.MemberExpression && ASTUtils66.getPropertyName(node.init) !== null && (ASTUtils66.getPropertyName(node.init) ?? "") === "control" && isUninitializedForm(node.init.object)) {
22884
22976
  const variable = bindingOf(node.id);
22885
22977
  if (variable !== null) uninitializedControls.add(variable);
22886
22978
  }
@@ -22973,7 +23065,7 @@ var require_use_server_in_actions_file_default = createRule({
22973
23065
  // src/rules/require-zod-form-validation.ts
22974
23066
  import {
22975
23067
  AST_NODE_TYPES as AST_NODE_TYPES108,
22976
- ASTUtils as ASTUtils66
23068
+ ASTUtils as ASTUtils67
22977
23069
  } from "@typescript-eslint/utils";
22978
23070
  var REQUIRE_ZOD_FORM_VALIDATION_DOCUMENTATION = {
22979
23071
  summary: "Require Zod validation (`Schema.parse(...)` / `Schema.safeParse(...)`) when reading values out of a `FormData` object.",
@@ -23021,7 +23113,7 @@ var isFormDataMethodCall = (node) => {
23021
23113
  }
23022
23114
  if (current.type !== AST_NODE_TYPES108.CallExpression) return false;
23023
23115
  const callee = unwrapExpression(current.callee);
23024
- return callee.type === AST_NODE_TYPES108.MemberExpression && ASTUtils66.getPropertyName(callee) === "formData";
23116
+ return callee.type === AST_NODE_TYPES108.MemberExpression && ASTUtils67.getPropertyName(callee) === "formData";
23025
23117
  };
23026
23118
  var require_zod_form_validation_default = createRule({
23027
23119
  name: "require-zod-form-validation",
@@ -23042,7 +23134,7 @@ var require_zod_form_validation_default = createRule({
23042
23134
  return {};
23043
23135
  }
23044
23136
  const zodBindings = /* @__PURE__ */ new Set();
23045
- const resolvedBinding = (identifier) => ASTUtils66.findVariable(
23137
+ const resolvedBinding = (identifier) => ASTUtils67.findVariable(
23046
23138
  context.sourceCode.getScope(identifier),
23047
23139
  identifier.name
23048
23140
  );
@@ -23050,7 +23142,7 @@ var require_zod_form_validation_default = createRule({
23050
23142
  const callee = unwrapExpression(node.callee);
23051
23143
  const calleeReceiver = callee.type === AST_NODE_TYPES108.MemberExpression ? unwrapExpression(callee.object) : callee;
23052
23144
  if (callee.type !== AST_NODE_TYPES108.MemberExpression) return false;
23053
- if (ASTUtils66.getPropertyName(callee) === null || !FORM_VALUE_METHODS.has(ASTUtils66.getPropertyName(callee) ?? "")) {
23145
+ if (ASTUtils67.getPropertyName(callee) === null || !FORM_VALUE_METHODS.has(ASTUtils67.getPropertyName(callee) ?? "")) {
23054
23146
  return false;
23055
23147
  }
23056
23148
  return isFormSourceIdentifier(calleeReceiver);
@@ -23081,7 +23173,7 @@ var require_zod_form_validation_default = createRule({
23081
23173
  parent = parent.parent;
23082
23174
  continue;
23083
23175
  }
23084
- if (parent.type === AST_NODE_TYPES108.CallExpression && parent.callee.type === AST_NODE_TYPES108.MemberExpression && parent.callee.object.type === AST_NODE_TYPES108.Identifier && parent.callee.object.name === "Object" && ASTUtils66.getPropertyName(parent.callee) === "fromEntries" && (resolvedBinding(parent.callee.object)?.defs.length ?? 0) === 0) {
23176
+ if (parent.type === AST_NODE_TYPES108.CallExpression && parent.callee.type === AST_NODE_TYPES108.MemberExpression && parent.callee.object.type === AST_NODE_TYPES108.Identifier && parent.callee.object.name === "Object" && ASTUtils67.getPropertyName(parent.callee) === "fromEntries" && (resolvedBinding(parent.callee.object)?.defs.length ?? 0) === 0) {
23085
23177
  parent = parent.parent;
23086
23178
  continue;
23087
23179
  }
@@ -23094,7 +23186,7 @@ var require_zod_form_validation_default = createRule({
23094
23186
  if (node.type !== AST_NODE_TYPES108.CallExpression) return false;
23095
23187
  const callee = unwrapExpression(node.callee);
23096
23188
  const calleeReceiver = callee.type === AST_NODE_TYPES108.MemberExpression ? unwrapExpression(callee.object) : callee;
23097
- if (callee.type !== AST_NODE_TYPES108.MemberExpression || ASTUtils66.getPropertyName(callee) === null || !ZOD_PARSE_METHODS.has(ASTUtils66.getPropertyName(callee) ?? "")) {
23189
+ if (callee.type !== AST_NODE_TYPES108.MemberExpression || ASTUtils67.getPropertyName(callee) === null || !ZOD_PARSE_METHODS.has(ASTUtils67.getPropertyName(callee) ?? "")) {
23098
23190
  return false;
23099
23191
  }
23100
23192
  const root = zodReceiverRoot(calleeReceiver);
@@ -23180,7 +23272,7 @@ var require_zod_form_validation_default = createRule({
23180
23272
  };
23181
23273
  const zodParseMethod = (call) => {
23182
23274
  const callee = unwrapExpression(call.callee);
23183
- return callee.type === AST_NODE_TYPES108.MemberExpression && ASTUtils66.getPropertyName(callee) !== null ? ASTUtils66.getPropertyName(callee) ?? "" : null;
23275
+ return callee.type === AST_NODE_TYPES108.MemberExpression && ASTUtils67.getPropertyName(callee) !== null ? ASTUtils67.getPropertyName(callee) ?? "" : null;
23184
23276
  };
23185
23277
  const isSafePrevalidationInspection = (identifier) => {
23186
23278
  const parent = identifier.parent;
@@ -23356,7 +23448,7 @@ function expressionCallableName(current) {
23356
23448
  }
23357
23449
 
23358
23450
  // src/rules/stepdown.ts
23359
- import { AST_NODE_TYPES as AST_NODE_TYPES109, ASTUtils as ASTUtils67 } from "@typescript-eslint/utils";
23451
+ import { AST_NODE_TYPES as AST_NODE_TYPES109, ASTUtils as ASTUtils68 } from "@typescript-eslint/utils";
23360
23452
  var STEPDOWN_DOCUMENTATION = {
23361
23453
  summary: "Place a private helper below its sole direct same-scope caller.",
23362
23454
  rationale: "Caller-first ordering lets a reader follow the main flow before descending into implementation details.",
@@ -23656,7 +23748,7 @@ function receiverOrigin(context, object, receivers) {
23656
23748
  while (true) {
23657
23749
  const unwrapped = unwrapExpression4(current);
23658
23750
  if (unwrapped.type !== AST_NODE_TYPES109.Identifier) return unwrapped;
23659
- const variable = ASTUtils67.findVariable(context.sourceCode.getScope(unwrapped), unwrapped.name);
23751
+ const variable = ASTUtils68.findVariable(context.sourceCode.getScope(unwrapped), unwrapped.name);
23660
23752
  if (variable === null) return null;
23661
23753
  const known = receivers.get(variable);
23662
23754
  if (known !== void 0) return known;
@@ -23837,11 +23929,11 @@ function classScope(context, node, computedReferences) {
23837
23929
  function classReceiverBindings(context, node) {
23838
23930
  const classReceivers = /* @__PURE__ */ new Map();
23839
23931
  if (node.id !== null) {
23840
- const internal = ASTUtils67.findVariable(context.sourceCode.getScope(node), node.id.name);
23932
+ const internal = ASTUtils68.findVariable(context.sourceCode.getScope(node), node.id.name);
23841
23933
  if (internal !== null && stableVariable(internal)) classReceivers.set(internal, true);
23842
23934
  }
23843
23935
  if (node.type === AST_NODE_TYPES109.ClassExpression && node.parent.type === AST_NODE_TYPES109.VariableDeclarator && node.parent.id.type === AST_NODE_TYPES109.Identifier && node.parent.parent.type === AST_NODE_TYPES109.VariableDeclaration && node.parent.parent.kind === "const") {
23844
- const outer = ASTUtils67.findVariable(context.sourceCode.getScope(node.parent), node.parent.id.name);
23936
+ const outer = ASTUtils68.findVariable(context.sourceCode.getScope(node.parent), node.parent.id.name);
23845
23937
  if (outer !== null && stableVariable(outer)) classReceivers.set(outer, true);
23846
23938
  }
23847
23939
  return classReceivers;
@@ -23927,7 +24019,7 @@ function classMethodCounts(body2, methods) {
23927
24019
  }
23928
24020
 
23929
24021
  // src/rules/source-coupled-test.ts
23930
- import { AST_NODE_TYPES as AST_NODE_TYPES110, ASTUtils as ASTUtils68 } from "@typescript-eslint/utils";
24022
+ import { AST_NODE_TYPES as AST_NODE_TYPES110, ASTUtils as ASTUtils69 } from "@typescript-eslint/utils";
23931
24023
  var GENERAL_SOURCE_SUFFIX_RE = /\.(?:bash|sh|ya?ml|jsonc?|toml|py|[cm]?[jt]s)$/iu;
23932
24024
  var FS_MODULES = /* @__PURE__ */ new Set(["fs", "node:fs", "fs/promises", "node:fs/promises"]);
23933
24025
  var FS_READERS = /* @__PURE__ */ new Set(["readFile", "readFileSync"]);
@@ -24044,7 +24136,7 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
24044
24136
  const scopes = [newScope()];
24045
24137
  const reportedOrigins = /* @__PURE__ */ new Set();
24046
24138
  const currentScope = () => scopes.at(-1) ?? scopes[0];
24047
- const bindingOf = (node) => ASTUtils68.findVariable(context.sourceCode.getScope(node), node.name);
24139
+ const bindingOf = (node) => ASTUtils69.findVariable(context.sourceCode.getScope(node), node.name);
24048
24140
  const assertionKind = (node) => {
24049
24141
  const binding = bindingOf(node);
24050
24142
  if (binding === null || binding.defs.length === 0) {
@@ -24097,7 +24189,7 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
24097
24189
  return visible("fsReaders", callee) && sourcePath(current.arguments[0]);
24098
24190
  }
24099
24191
  if (callee.type !== AST_NODE_TYPES110.MemberExpression) return false;
24100
- const name2 = ASTUtils68.getPropertyName(callee);
24192
+ const name2 = ASTUtils69.getPropertyName(callee);
24101
24193
  const object = unwrap6(calleeReceiver);
24102
24194
  return name2 !== null && FS_READERS.has(name2) && object.type === AST_NODE_TYPES110.Identifier && visible("fsObjects", object) && sourcePath(current.arguments[0]);
24103
24195
  };
@@ -24106,12 +24198,12 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
24106
24198
  if (current.type === AST_NODE_TYPES110.Identifier) return visibleRawOrigins(current);
24107
24199
  if (rawRead(current)) return /* @__PURE__ */ new Set([`${current.range[0]}:${current.range[1]}`]);
24108
24200
  if (current.type === AST_NODE_TYPES110.BinaryExpression && current.operator === "+") return /* @__PURE__ */ new Set([...rawOrigins(current.left), ...rawOrigins(current.right)]);
24109
- if (current.type === AST_NODE_TYPES110.MemberExpression && ASTUtils68.getPropertyName(current) === "length") return rawOrigins(current.object);
24201
+ if (current.type === AST_NODE_TYPES110.MemberExpression && ASTUtils69.getPropertyName(current) === "length") return rawOrigins(current.object);
24110
24202
  if (current.type !== AST_NODE_TYPES110.CallExpression) return /* @__PURE__ */ new Set();
24111
24203
  const callee = unwrap6(current.callee);
24112
24204
  const calleeReceiver = callee.type === AST_NODE_TYPES110.MemberExpression ? unwrapExpression(callee.object) : callee;
24113
24205
  if (callee.type !== AST_NODE_TYPES110.MemberExpression) return /* @__PURE__ */ new Set();
24114
- const name2 = ASTUtils68.getPropertyName(callee);
24206
+ const name2 = ASTUtils69.getPropertyName(callee);
24115
24207
  return name2 !== null && TEXT_TRANSFORMS.has(name2) ? rawOrigins(calleeReceiver) : /* @__PURE__ */ new Set();
24116
24208
  };
24117
24209
  const evidenceOrigins = (node) => {
@@ -24124,7 +24216,7 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
24124
24216
  const callee = unwrap6(current.callee);
24125
24217
  const calleeReceiver = callee.type === AST_NODE_TYPES110.MemberExpression ? unwrapExpression(callee.object) : callee;
24126
24218
  if (callee.type !== AST_NODE_TYPES110.MemberExpression) return /* @__PURE__ */ new Set();
24127
- const name2 = ASTUtils68.getPropertyName(callee);
24219
+ const name2 = ASTUtils69.getPropertyName(callee);
24128
24220
  if (name2 !== null && TEXT_PREDICATES.has(name2)) return rawOrigins(calleeReceiver);
24129
24221
  if (name2 !== null && REGEXP_PREDICATES.has(name2)) return new Set(current.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES110.SpreadElement ? [] : [...rawOrigins(argument)]));
24130
24222
  return /* @__PURE__ */ new Set();
@@ -24136,10 +24228,10 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
24136
24228
  return new Set(node.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES110.SpreadElement ? [] : [...evidenceOrigins(argument)]));
24137
24229
  }
24138
24230
  if (callee.type !== AST_NODE_TYPES110.MemberExpression) return /* @__PURE__ */ new Set();
24139
- const matcher = ASTUtils68.getPropertyName(callee);
24231
+ const matcher = ASTUtils69.getPropertyName(callee);
24140
24232
  if (matcher === null) return /* @__PURE__ */ new Set();
24141
24233
  let receiver = unwrap6(calleeReceiver);
24142
- while (receiver.type === AST_NODE_TYPES110.MemberExpression && EXPECT_MODIFIERS2.has(ASTUtils68.getPropertyName(receiver) ?? "")) receiver = unwrap6(receiver.object);
24234
+ while (receiver.type === AST_NODE_TYPES110.MemberExpression && EXPECT_MODIFIERS2.has(ASTUtils69.getPropertyName(receiver) ?? "")) receiver = unwrap6(receiver.object);
24143
24235
  const expectCallee = receiver.type === AST_NODE_TYPES110.CallExpression ? unwrapExpression(receiver.callee) : null;
24144
24236
  if (receiver.type === AST_NODE_TYPES110.CallExpression && expectCallee?.type === AST_NODE_TYPES110.Identifier && assertionKind(expectCallee) === "expect") {
24145
24237
  if (!EXPECT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
@@ -24422,7 +24514,7 @@ var iac_source_coupled_test_default = createSourceCoupledRule(
24422
24514
  // src/rules/require-pascal-case-zod-schema-name.ts
24423
24515
  import {
24424
24516
  AST_NODE_TYPES as AST_NODE_TYPES112,
24425
- ASTUtils as ASTUtils69
24517
+ ASTUtils as ASTUtils70
24426
24518
  } from "@typescript-eslint/utils";
24427
24519
  var REQUIRE_PASCAL_CASE_ZOD_SCHEMA_NAME_DOCUMENTATION = {
24428
24520
  summary: "Require confirmed module-level Zod schema contracts to use PascalCase with a `Schema` suffix.",
@@ -24555,7 +24647,7 @@ var SCHEMA_RETURNING_METHODS = /* @__PURE__ */ new Set([
24555
24647
  "superRefine",
24556
24648
  "transform"
24557
24649
  ]);
24558
- var terminalMethodName = (callee) => ASTUtils69.getPropertyName(callee) !== null ? ASTUtils69.getPropertyName(callee) ?? "" : null;
24650
+ var terminalMethodName = (callee) => ASTUtils70.getPropertyName(callee) !== null ? ASTUtils70.getPropertyName(callee) ?? "" : null;
24559
24651
  var calleeChainRoot2 = (node) => {
24560
24652
  let current = node;
24561
24653
  for (; ; ) {
@@ -24580,8 +24672,8 @@ var chainMemberNames2 = (node) => {
24580
24672
  for (; ; ) {
24581
24673
  current = unwrapExpression(current);
24582
24674
  if (current.type === AST_NODE_TYPES112.MemberExpression) {
24583
- if (ASTUtils69.getPropertyName(current) === null) return [];
24584
- names.push(ASTUtils69.getPropertyName(current) ?? "");
24675
+ if (ASTUtils70.getPropertyName(current) === null) return [];
24676
+ names.push(ASTUtils70.getPropertyName(current) ?? "");
24585
24677
  current = current.object;
24586
24678
  continue;
24587
24679
  }
@@ -24618,7 +24710,7 @@ var require_pascal_case_zod_schema_name_default = createRule({
24618
24710
  const zodBindings = /* @__PURE__ */ new Set();
24619
24711
  const schemaBindings = /* @__PURE__ */ new Set();
24620
24712
  function resolvedBinding(identifier) {
24621
- return ASTUtils69.findVariable(
24713
+ return ASTUtils70.findVariable(
24622
24714
  context.sourceCode.getScope(identifier),
24623
24715
  identifier.name
24624
24716
  );
@@ -24899,30 +24991,21 @@ var LIBRARY_IMPORT_POLICY = ["error", {
24899
24991
  }];
24900
24992
  var ADVISORY_RULES = [
24901
24993
  "@sarj/excessive-commentary",
24902
- "@sarj/named-child-schema-type",
24903
24994
  "@sarj/no-bespoke-api-case-conversion",
24904
- "@sarj/no-duplicate-test-case",
24905
- "@sarj/no-json-stringify-object-equality",
24906
24995
  "@sarj/no-restated-comment",
24907
24996
  "@sarj/no-restated-jsdoc",
24908
24997
  "@sarj/prefer-millisecond-control-duration-schema",
24909
24998
  "@sarj/prefer-module-level-refined-schema",
24910
24999
  "@sarj/prefer-multi-value-zod-literal",
24911
- "@sarj/prefer-named-complex-return-type",
24912
25000
  "@sarj/prefer-node-crypto-hash",
24913
25001
  "@sarj/prefer-node-fs-promises",
24914
- "@sarj/prefer-nominal-id-types",
24915
25002
  "@sarj/prefer-shared-zod-enum",
24916
- "@sarj/prefer-switch-for-repeated-equality",
24917
25003
  "@sarj/prefer-whole-object-assertion",
24918
25004
  "@sarj/require-camelcase-properties",
24919
- "@sarj/require-explicit-contract-implementation",
24920
- "@sarj/require-explicit-service-contract",
24921
- "@sarj/require-interface-for-exported-class",
24922
25005
  "@sarj/require-sql-access-class"
24923
25006
  ];
24924
25007
  var RECOMMENDED_RULES = {
24925
- "@sarj/named-child-schema-type": "warn",
25008
+ "@sarj/named-child-schema-type": "error",
24926
25009
  "@sarj/no-conditional-empty-object-spread": "error",
24927
25010
  "@sarj/prefer-typed-reflection": "error",
24928
25011
  "@sarj/no-broad-return-type": "error",
@@ -24960,7 +25043,7 @@ var RECOMMENDED_RULES = {
24960
25043
  "@sarj/no-bare-return-from-test-catch": "error",
24961
25044
  "@sarj/no-bespoke-api-case-conversion": "warn",
24962
25045
  "@sarj/no-detached-global-fetch": "error",
24963
- "@sarj/no-json-stringify-object-equality": "warn",
25046
+ "@sarj/no-json-stringify-object-equality": "error",
24964
25047
  "@sarj/no-dangerously-allow-svg": "error",
24965
25048
  "@sarj/no-duplicate-lifecycle-refresh-listeners": "error",
24966
25049
  "@sarj/no-long-comment": "error",
@@ -24982,7 +25065,7 @@ var RECOMMENDED_RULES = {
24982
25065
  "@sarj/no-sleep-in-test-body": "error",
24983
25066
  "@sarj/no-string-concat-in-loop": "error",
24984
25067
  "@sarj/no-tautological-expect": "error",
24985
- "@sarj/no-duplicate-test-case": "warn",
25068
+ "@sarj/no-duplicate-test-case": "error",
24986
25069
  "@sarj/no-typed-doc-sections": "error",
24987
25070
  "@sarj/no-trailing-value-narration": "error",
24988
25071
  "@sarj/no-declaration-comment-wall": "error",
@@ -25005,8 +25088,8 @@ var RECOMMENDED_RULES = {
25005
25088
  "@sarj/prefer-module-level-refined-schema": "warn",
25006
25089
  "@sarj/prefer-multi-value-zod-literal": ["warn", { zodMajorVersion: 4 }],
25007
25090
  "@sarj/prefer-named-callback-domain": "error",
25008
- "@sarj/prefer-nominal-id-types": "warn",
25009
- "@sarj/prefer-named-complex-return-type": "warn",
25091
+ "@sarj/prefer-nominal-id-types": "error",
25092
+ "@sarj/prefer-named-complex-return-type": "error",
25010
25093
  "@sarj/prefer-node-crypto-hash": "warn",
25011
25094
  "@sarj/prefer-node-fs-promises": "warn",
25012
25095
  "@sarj/prefer-non-nullable-collection": "error",
@@ -25014,7 +25097,7 @@ var RECOMMENDED_RULES = {
25014
25097
  "@sarj/prefer-await-in-async-return": "error",
25015
25098
  "@sarj/prefer-schema-for-api-payload": "error",
25016
25099
  "@sarj/prefer-shared-zod-enum": "warn",
25017
- "@sarj/prefer-switch-for-repeated-equality": "warn",
25100
+ "@sarj/prefer-switch-for-repeated-equality": "error",
25018
25101
  "@sarj/prefer-semantic-colors": ["error", { requireSemanticTokens: true }],
25019
25102
  "@sarj/prefer-server-actions": "error",
25020
25103
  "@sarj/prefer-whole-object-assertion": "warn",
@@ -25023,9 +25106,9 @@ var RECOMMENDED_RULES = {
25023
25106
  "@sarj/prefer-zod-parse-output-type": "error",
25024
25107
  "@sarj/require-assert-never": "error",
25025
25108
  "@sarj/require-fetch-timeout": "error",
25026
- "@sarj/require-explicit-contract-implementation": "warn",
25027
- "@sarj/require-explicit-service-contract": "warn",
25028
- "@sarj/require-interface-for-exported-class": "warn",
25109
+ "@sarj/require-explicit-contract-implementation": "error",
25110
+ "@sarj/require-explicit-service-contract": "error",
25111
+ "@sarj/require-interface-for-exported-class": "error",
25029
25112
  "@sarj/require-port-for-service": "error",
25030
25113
  "@sarj/require-sql-access-class": "warn",
25031
25114
  "@sarj/require-static-next-matcher": "error",
@@ -25040,7 +25123,7 @@ var RECOMMENDED_RULES = {
25040
25123
  "@sarj/require-pascal-case-zod-schema-name": "error"
25041
25124
  };
25042
25125
  var STRICT_RULES = {
25043
- "@sarj/named-child-schema-type": "warn",
25126
+ "@sarj/named-child-schema-type": "error",
25044
25127
  "@sarj/no-conditional-empty-object-spread": "error",
25045
25128
  "@sarj/prefer-typed-reflection": "error",
25046
25129
  "@sarj/no-broad-return-type": "error",
@@ -25079,7 +25162,7 @@ var STRICT_RULES = {
25079
25162
  "@sarj/no-bare-return-from-test-catch": "error",
25080
25163
  "@sarj/no-bespoke-api-case-conversion": "warn",
25081
25164
  "@sarj/no-detached-global-fetch": "error",
25082
- "@sarj/no-json-stringify-object-equality": "warn",
25165
+ "@sarj/no-json-stringify-object-equality": "error",
25083
25166
  "@sarj/no-dangerously-allow-svg": "error",
25084
25167
  "@sarj/no-duplicate-lifecycle-refresh-listeners": "error",
25085
25168
  "@sarj/no-long-comment": "error",
@@ -25104,7 +25187,7 @@ var STRICT_RULES = {
25104
25187
  "@sarj/no-storage-in-stateless-modules": "error",
25105
25188
  "@sarj/no-string-concat-in-loop": "error",
25106
25189
  "@sarj/no-tautological-expect": "error",
25107
- "@sarj/no-duplicate-test-case": "warn",
25190
+ "@sarj/no-duplicate-test-case": "error",
25108
25191
  "@sarj/no-typed-doc-sections": "error",
25109
25192
  "@sarj/no-trailing-value-narration": "error",
25110
25193
  "@sarj/no-declaration-comment-wall": "error",
@@ -25127,8 +25210,8 @@ var STRICT_RULES = {
25127
25210
  "@sarj/prefer-module-level-refined-schema": "warn",
25128
25211
  "@sarj/prefer-multi-value-zod-literal": ["warn", { zodMajorVersion: 4 }],
25129
25212
  "@sarj/prefer-named-callback-domain": "error",
25130
- "@sarj/prefer-nominal-id-types": "warn",
25131
- "@sarj/prefer-named-complex-return-type": "warn",
25213
+ "@sarj/prefer-nominal-id-types": "error",
25214
+ "@sarj/prefer-named-complex-return-type": "error",
25132
25215
  "@sarj/prefer-node-crypto-hash": "warn",
25133
25216
  "@sarj/prefer-node-fs-promises": "warn",
25134
25217
  "@sarj/prefer-non-nullable-collection": "error",
@@ -25136,7 +25219,7 @@ var STRICT_RULES = {
25136
25219
  "@sarj/prefer-await-in-async-return": "error",
25137
25220
  "@sarj/prefer-schema-for-api-payload": "error",
25138
25221
  "@sarj/prefer-shared-zod-enum": "warn",
25139
- "@sarj/prefer-switch-for-repeated-equality": "warn",
25222
+ "@sarj/prefer-switch-for-repeated-equality": "error",
25140
25223
  "@sarj/prefer-semantic-colors": ["error", { requireSemanticTokens: true }],
25141
25224
  "@sarj/prefer-server-actions": "error",
25142
25225
  "@sarj/prefer-whole-object-assertion": "warn",
@@ -25145,9 +25228,9 @@ var STRICT_RULES = {
25145
25228
  "@sarj/prefer-zod-parse-output-type": "error",
25146
25229
  "@sarj/require-assert-never": "error",
25147
25230
  "@sarj/require-fetch-timeout": "error",
25148
- "@sarj/require-explicit-contract-implementation": "warn",
25149
- "@sarj/require-explicit-service-contract": "warn",
25150
- "@sarj/require-interface-for-exported-class": "warn",
25231
+ "@sarj/require-explicit-contract-implementation": "error",
25232
+ "@sarj/require-explicit-service-contract": "error",
25233
+ "@sarj/require-interface-for-exported-class": "error",
25151
25234
  "@sarj/require-port-for-service": "error",
25152
25235
  "@sarj/require-sql-access-class": "warn",
25153
25236
  "@sarj/require-static-next-matcher": "error",