@sarj/eslint-plugin 15.17.16 → 15.17.18

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
@@ -3,32 +3,32 @@ var LIBRARY_POLICY = [
3
3
  {
4
4
  "id": "LIB101",
5
5
  "module": "request",
6
- "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
7
- "replacement": "ky"
6
+ "note": "Use the platform-native fetch API; review errors, timeouts, retries, and response parsing during migration.",
7
+ "replacement": "native fetch"
8
8
  },
9
9
  {
10
10
  "id": "LIB101",
11
11
  "module": "node-fetch",
12
- "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
13
- "replacement": "ky"
12
+ "note": "Use the platform-native fetch API; review errors, timeouts, retries, and response parsing during migration.",
13
+ "replacement": "native fetch"
14
14
  },
15
15
  {
16
16
  "id": "LIB101",
17
17
  "module": "cross-fetch",
18
- "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
19
- "replacement": "ky"
18
+ "note": "Use the platform-native fetch API; review errors, timeouts, retries, and response parsing during migration.",
19
+ "replacement": "native fetch"
20
20
  },
21
21
  {
22
22
  "id": "LIB101",
23
23
  "module": "isomorphic-fetch",
24
- "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
25
- "replacement": "ky"
24
+ "note": "Use the platform-native fetch API; review errors, timeouts, retries, and response parsing during migration.",
25
+ "replacement": "native fetch"
26
26
  },
27
27
  {
28
28
  "id": "LIB101",
29
29
  "module": "axios",
30
- "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
31
- "replacement": "ky"
30
+ "note": "Use the platform-native fetch API; review errors, timeouts, retries, and response parsing during migration.",
31
+ "replacement": "native fetch"
32
32
  },
33
33
  {
34
34
  "id": "LIB102",
@@ -2507,12 +2507,12 @@ function exportedNextConfigProperty(sourceCode, path) {
2507
2507
  // src/rules/no-dangerously-allow-svg.ts
2508
2508
  var NEXT_CONFIG_RE = /(?:^|\/)next\.config\.[cm]?[jt]s$/;
2509
2509
  var NO_DANGEROUSLY_ALLOW_SVG_DOCUMENTATION = {
2510
- summary: "Next.js image configuration enables unsanitized SVG rendering",
2510
+ summary: "Next.js image configuration enables SVG rendering without the required response hardening",
2511
2511
  rationale: "SVG files can contain scripts and other active content; enabling dangerouslyAllowSVG makes the image optimizer serve that content from the application origin.",
2512
- remediation: "Keep dangerouslyAllowSVG disabled. If SVG delivery is unavoidable, use a separately reviewed asset path with restrictive Content-Disposition and Content-Security-Policy headers.",
2512
+ remediation: "Keep dangerouslyAllowSVG disabled. If SVG optimization is required, retain attachment disposition and set the image Content-Security-Policy to `script-src 'none'; sandbox;`.",
2513
2513
  category: "security",
2514
2514
  limitations: [
2515
- "Only a literal true in the effective images property of a directly exported object, unescaped const alias, or isolated module.exports object is reported. Wrappers, factories, spreads, computed keys and mutations are not inferred."
2515
+ "Only literal effective properties of a directly exported object, unescaped const alias, or isolated module.exports object are analyzed. Wrappers, factories, spreads, computed keys, dynamic policies and mutations are not inferred."
2516
2516
  ],
2517
2517
  examples: [
2518
2518
  {
@@ -2535,6 +2535,19 @@ var NO_DANGEROUSLY_ALLOW_SVG_DOCUMENTATION = {
2535
2535
  }
2536
2536
  ]
2537
2537
  };
2538
+ function literalString(node) {
2539
+ if (node?.value.type === "Literal" && typeof node.value.value === "string") return node.value.value;
2540
+ if (node?.value.type === "TemplateLiteral" && node.value.expressions.length === 0) return node.value.quasis[0]?.value.cooked ?? null;
2541
+ return null;
2542
+ }
2543
+ function hasHardenedSvgPolicy(policy) {
2544
+ const directives = policy.split(";").map((part) => part.trim().split(/\s+/u).filter(Boolean)).filter((parts) => parts.length > 0);
2545
+ const scriptSources = directives.filter(([name]) => name?.toLowerCase() === "script-src");
2546
+ const sandboxes = directives.filter(([name]) => name?.toLowerCase() === "sandbox");
2547
+ const scriptSource = scriptSources[0];
2548
+ const sandbox = sandboxes[0];
2549
+ return scriptSources.length === 1 && sandboxes.length === 1 && scriptSource?.length === 2 && scriptSource[1]?.toLowerCase() === "'none'" && sandbox?.length === 1;
2550
+ }
2538
2551
  var no_dangerously_allow_svg_default = createRule({
2539
2552
  name: "no-dangerously-allow-svg",
2540
2553
  documentation: NO_DANGEROUSLY_ALLOW_SVG_DOCUMENTATION,
@@ -2543,7 +2556,7 @@ var no_dangerously_allow_svg_default = createRule({
2543
2556
  docs: { description: NO_DANGEROUSLY_ALLOW_SVG_DOCUMENTATION.summary },
2544
2557
  schema: [],
2545
2558
  messages: {
2546
- noDangerouslyAllowSvg: "Do not enable dangerouslyAllowSVG. SVG can carry active content served from the application origin."
2559
+ noDangerouslyAllowSvg: "Do not enable dangerouslyAllowSVG without a script-blocking sandbox policy and attachment disposition. SVG can carry active content served from the application origin."
2547
2560
  }
2548
2561
  },
2549
2562
  defaultOptions: [],
@@ -2553,6 +2566,12 @@ var no_dangerously_allow_svg_default = createRule({
2553
2566
  "Program:exit"() {
2554
2567
  const node = exportedNextConfigProperty(context.sourceCode, ["images", "dangerouslyAllowSVG"]);
2555
2568
  if (node !== null && node.value.type === "Literal" && node.value.value === true) {
2569
+ const disposition = exportedNextConfigProperty(context.sourceCode, ["images", "contentDispositionType"]);
2570
+ const policy = literalString(
2571
+ exportedNextConfigProperty(context.sourceCode, ["images", "contentSecurityPolicy"])
2572
+ );
2573
+ const attachmentDisposition = disposition === null || literalString(disposition) === "attachment";
2574
+ if (attachmentDisposition && policy !== null && hasHardenedSvgPolicy(policy)) return;
2556
2575
  context.report({ node, messageId: "noDangerouslyAllowSvg" });
2557
2576
  }
2558
2577
  }
@@ -3671,12 +3690,41 @@ var no_hand_rolled_sleep_default = createRule({
3671
3690
 
3672
3691
  // src/rules/no-hand-rolled-spinner.ts
3673
3692
  import { AST_NODE_TYPES as AST_NODE_TYPES14 } from "@typescript-eslint/utils";
3693
+
3694
+ // src/rules/_tailwind.ts
3695
+ var tailwindVariantPrefix = (token) => {
3696
+ let bracketDepth = 0;
3697
+ let parenthesisDepth = 0;
3698
+ let escaped = false;
3699
+ let end = 0;
3700
+ for (let index = 0; index < token.length; index += 1) {
3701
+ const character = token[index];
3702
+ if (escaped) {
3703
+ escaped = false;
3704
+ continue;
3705
+ }
3706
+ if (character === "\\") {
3707
+ escaped = true;
3708
+ continue;
3709
+ }
3710
+ if (character === "[") bracketDepth += 1;
3711
+ else if (character === "]") bracketDepth = Math.max(0, bracketDepth - 1);
3712
+ else if (character === "(") parenthesisDepth += 1;
3713
+ else if (character === ")") parenthesisDepth = Math.max(0, parenthesisDepth - 1);
3714
+ else if (character === ":" && bracketDepth === 0 && parenthesisDepth === 0) end = index + 1;
3715
+ }
3716
+ return token.slice(0, end);
3717
+ };
3718
+ var tailwindBase = (token) => token.slice(tailwindVariantPrefix(token).length).replace(/^!/, "");
3719
+ var classTokens = (value) => value.split(/\s+/).filter(Boolean);
3720
+
3721
+ // src/rules/no-hand-rolled-spinner.ts
3674
3722
  var NO_HAND_ROLLED_SPINNER_DOCUMENTATION = {
3675
3723
  summary: "Disallow intrinsic elements styled as Tailwind border-ring spinners outside the design-system implementation.",
3676
3724
  rationale: "One-off loading indicators duplicate a shared primitive and let accessibility and styling diverge.",
3677
3725
  remediation: "Render the design-system Spinner component instead.",
3678
3726
  category: "maintainability",
3679
- limitations: ["Only effective static className values on div and span elements are inspected; a later spread makes the value unknown. Tests, stories, generated files, and the design-system implementation are excluded."],
3727
+ limitations: ["Only effective static className values on div and span elements are inspected; Tailwind utilities are combined only when they are unprefixed or share one exact variant context, while a later spread makes the value unknown. Tests, stories, generated files, and the design-system implementation are excluded."],
3680
3728
  examples: [
3681
3729
  { id: "design-system-spinner", title: "Use the shared spinner", outcome: "no-match", files: [{ path: "src/loading-state.tsx", source: '<Spinner className="size-4" />' }], focusPath: "src/loading-state.tsx", expectedCount: 0, public: true },
3682
3730
  { id: "border-ring-spinner", title: "Do not rebuild a spinner", outcome: "match", files: [{ path: "src/loading-state.tsx", source: '<div className="size-4 animate-spin rounded-full border-2 border-t-transparent" />' }], focusPath: "src/loading-state.tsx", expectedCount: 1, public: true }
@@ -3702,6 +3750,10 @@ function isContrastingEdge(token) {
3702
3750
  const match = DIRECTIONAL_BORDER.exec(token);
3703
3751
  return match?.[2] !== void 0 && !isBorderWidthValue(match[2]);
3704
3752
  }
3753
+ function hasSpinnerInVariant(classes, variant) {
3754
+ const effective = classes.filter((entry) => entry.variant === "" || entry.variant === variant).map((entry) => entry.base);
3755
+ return effective.includes("animate-spin") && effective.includes("rounded-full") && effective.some(isBorderWidth) && effective.some(isContrastingEdge);
3756
+ }
3705
3757
  function staticClassName(attribute) {
3706
3758
  const value = attribute.value;
3707
3759
  if (value?.type === AST_NODE_TYPES14.Literal && typeof value.value === "string") {
@@ -3744,8 +3796,12 @@ var no_hand_rolled_spinner_default = createRule({
3744
3796
  if (classNameAttribute?.type !== AST_NODE_TYPES14.JSXAttribute) return;
3745
3797
  const className = staticClassName(classNameAttribute);
3746
3798
  if (className === null) return;
3747
- const classes = className.split(/\s+/u);
3748
- if (classes.includes("animate-spin") && classes.includes("rounded-full") && classes.some(isBorderWidth) && classes.some(isContrastingEdge)) {
3799
+ const classes = className.split(/\s+/u).filter(Boolean).map((token) => ({
3800
+ base: tailwindBase(token),
3801
+ variant: tailwindVariantPrefix(token)
3802
+ }));
3803
+ const variants = new Set(classes.map((entry) => entry.variant));
3804
+ if ([...variants].some((variant) => hasSpinnerInVariant(classes, variant))) {
3749
3805
  context.report({ node, messageId: "handRolledSpinner" });
3750
3806
  }
3751
3807
  }
@@ -3986,33 +4042,36 @@ var no_insecure_random_id_default = createRule({
3986
4042
  });
3987
4043
 
3988
4044
  // src/rules/no-detached-global-fetch.ts
3989
- import { AST_NODE_TYPES as AST_NODE_TYPES15, ASTUtils as ASTUtils7 } from "@typescript-eslint/utils";
4045
+ import {
4046
+ AST_NODE_TYPES as AST_NODE_TYPES15,
4047
+ ASTUtils as ASTUtils7
4048
+ } from "@typescript-eslint/utils";
3990
4049
  var NO_DETACHED_GLOBAL_FETCH_DOCUMENTATION = {
3991
- summary: "Preserve the receiver when the ambient global fetch is used as a value.",
3992
- rationale: "Some host runtimes expose fetch as a receiver-sensitive callable, so storing or passing the bare function can fail only after deployment.",
3993
- remediation: "Forward through `(input, init) => globalThis.fetch(input, init)` or bind the callable to its global receiver.",
4050
+ summary: "Keep the ambient global fetch receiver-safe when storing or explicitly rebinding it.",
4051
+ rationale: "Calling a raw ambient fetch through a class or object property supplies that object as `this`; receiver-sensitive hosts can reject that invocation only after deployment.",
4052
+ remediation: "Store a forwarding wrapper such as `(input, init) => fetch(input, init)`, or bind the callable to a compatible global or undefined receiver before storing it.",
3994
4053
  category: "correctness",
3995
4054
  autofix: "none",
3996
4055
  limitations: [
3997
- "The rule recognizes the unshadowed ambient fetch, globalThis.fetch, self.fetch, and window.fetch syntactically.",
3998
- "Direct calls, explicit receiver binding or invocation, tests, scripts, generated files, and locally defined fetch implementations are excluded.",
3999
- "The rule does not follow aliases or prove which JavaScript host executes a file."
4056
+ "The rule follows stable local variables and defaulted parameters from an unshadowed ambient fetch or globalThis/self/window fetch into direct class, object, or member storage.",
4057
+ "Bare local aliases, callback arguments, returns, direct calls, compatible global or undefined bind/call/apply receivers, tests, scripts, generated files, and locally defined fetch implementations are excluded.",
4058
+ "Interprocedural aliases, mutable aliases, collection storage, and host identity remain manual review boundaries."
4000
4059
  ],
4001
4060
  examples: [
4002
4061
  {
4003
4062
  id: "forwarded-global-fetch",
4004
- title: "Forward through the global receiver",
4063
+ title: "Store a receiver-safe forwarding wrapper",
4005
4064
  outcome: "no-match",
4006
- files: [{ path: "src/client.ts", source: "const request = (input: RequestInfo | URL, init?: RequestInit) => globalThis.fetch(input, init);" }],
4065
+ files: [{ path: "src/client.ts", source: "class Client { readonly request = (input: RequestInfo | URL, init?: RequestInit) => fetch(input, init); }" }],
4007
4066
  focusPath: "src/client.ts",
4008
4067
  expectedCount: 0,
4009
4068
  public: true
4010
4069
  },
4011
4070
  {
4012
- id: "detached-global-fetch",
4013
- title: "Do not detach the ambient fetch",
4071
+ id: "receiver-unsafe-global-fetch",
4072
+ title: "Do not store raw ambient fetch as an object method",
4014
4073
  outcome: "match",
4015
- files: [{ path: "src/client.ts", source: "class Client { constructor(private readonly request: typeof fetch = fetch) {} }" }],
4074
+ files: [{ path: "src/client.ts", source: "class Client { readonly request = fetch; }" }],
4016
4075
  focusPath: "src/client.ts",
4017
4076
  expectedCount: 1,
4018
4077
  public: true
@@ -4020,85 +4079,131 @@ var NO_DETACHED_GLOBAL_FETCH_DOCUMENTATION = {
4020
4079
  ]
4021
4080
  };
4022
4081
  var GLOBAL_RECEIVERS = /* @__PURE__ */ new Set(["globalThis", "self", "window"]);
4023
- var RECEIVER_METHODS = /* @__PURE__ */ new Set(["apply", "bind", "call"]);
4082
+ var EXPLICIT_RECEIVER_METHODS = /* @__PURE__ */ new Set(["apply", "bind", "call"]);
4083
+ var STORAGE_ASSIGNMENT_OPERATORS = /* @__PURE__ */ new Set(["=", "&&=", "??=", "||="]);
4084
+ function unwrapExpression(node) {
4085
+ let current = node;
4086
+ while (current.type === AST_NODE_TYPES15.ChainExpression || current.type === AST_NODE_TYPES15.TSAsExpression || current.type === AST_NODE_TYPES15.TSNonNullExpression || current.type === AST_NODE_TYPES15.TSTypeAssertion) {
4087
+ current = current.expression;
4088
+ }
4089
+ return current;
4090
+ }
4024
4091
  var no_detached_global_fetch_default = createRule({
4025
4092
  name: "no-detached-global-fetch",
4026
4093
  documentation: NO_DETACHED_GLOBAL_FETCH_DOCUMENTATION,
4027
4094
  meta: {
4028
4095
  type: "problem",
4029
- docs: { description: "Preserve the receiver when the ambient global fetch is used as a value." },
4096
+ docs: { description: NO_DETACHED_GLOBAL_FETCH_DOCUMENTATION.summary },
4030
4097
  schema: [],
4031
4098
  messages: {
4032
- detachedGlobalFetch: "The ambient global `fetch` is being detached from its receiver. Forward through `globalThis.fetch(...)` or bind it to the global receiver."
4099
+ detachedGlobalFetch: "Raw ambient `fetch` becomes receiver-unsafe when stored or rebound this way. Store a forwarding wrapper or bind it to a compatible global or undefined receiver."
4033
4100
  }
4034
4101
  },
4035
4102
  defaultOptions: [],
4036
4103
  create(context) {
4037
4104
  const sourceCode = context.sourceCode;
4038
- if (isTestFile(context.filename) || isScriptFile(context.filename) || isGeneratedFile(context.filename, sourceCode.text)) {
4039
- return {};
4105
+ if (isTestFile(context.filename) || isScriptFile(context.filename) || isGeneratedFile(context.filename, sourceCode.text)) return {};
4106
+ const aliases = /* @__PURE__ */ new Set();
4107
+ function bindingOf(identifier) {
4108
+ return ASTUtils7.findVariable(sourceCode.getScope(identifier), identifier.name);
4040
4109
  }
4041
4110
  function resolvesToGlobal(identifier) {
4042
- const variable = ASTUtils7.findVariable(sourceCode.getScope(identifier), identifier.name);
4111
+ const variable = bindingOf(identifier);
4043
4112
  return variable === null || variable.defs.length === 0;
4044
4113
  }
4045
4114
  function isGlobalReceiver(node) {
4046
4115
  return node.type === AST_NODE_TYPES15.Identifier && GLOBAL_RECEIVERS.has(node.name) && resolvesToGlobal(node);
4047
4116
  }
4048
- function isTypePosition(node) {
4049
- let parent = node.parent;
4050
- while (parent !== void 0) {
4051
- if (parent.type === AST_NODE_TYPES15.TSTypeQuery) return true;
4052
- if (!parent.type.startsWith("TS")) return false;
4053
- parent = parent.parent;
4054
- }
4055
- return false;
4117
+ function isStableAlias(variable) {
4118
+ return !variable.references.some(
4119
+ (reference) => reference.isWrite() && reference.init !== true
4120
+ );
4056
4121
  }
4057
- function receiverOf(node) {
4058
- if (node.type === AST_NODE_TYPES15.Identifier) return null;
4059
- return isGlobalReceiver(node.object) ? node.object : null;
4122
+ function recordAlias(identifier) {
4123
+ const variable = bindingOf(identifier);
4124
+ if (variable !== null && isStableAlias(variable)) aliases.add(variable);
4060
4125
  }
4061
- function isDirectCall(node) {
4062
- return node.parent.type === AST_NODE_TYPES15.CallExpression && node.parent.callee === node;
4126
+ function isGlobalFetchMember(node) {
4127
+ if (!isGlobalReceiver(node.object)) return false;
4128
+ if (!node.computed) {
4129
+ return node.property.type === AST_NODE_TYPES15.Identifier && node.property.name === "fetch";
4130
+ }
4131
+ return node.property.type === AST_NODE_TYPES15.Literal && node.property.value === "fetch";
4063
4132
  }
4064
- function isSafeExplicitReceiverUse(node) {
4065
- const member = node.parent;
4066
- if (member.type !== AST_NODE_TYPES15.MemberExpression || member.object !== node || member.computed || member.property.type !== AST_NODE_TYPES15.Identifier || !RECEIVER_METHODS.has(member.property.name)) {
4067
- return false;
4133
+ function staticMemberName9(node) {
4134
+ if (!node.computed) {
4135
+ return node.property.type === AST_NODE_TYPES15.Identifier ? node.property.name : null;
4068
4136
  }
4069
- const invocation = member.parent;
4070
- if (invocation.type !== AST_NODE_TYPES15.CallExpression || invocation.callee !== member) {
4071
- return false;
4137
+ return node.property.type === AST_NODE_TYPES15.Literal && typeof node.property.value === "string" ? node.property.value : null;
4138
+ }
4139
+ function mayBeRawFetch(node) {
4140
+ const expression = unwrapExpression(node);
4141
+ if (expression.type === AST_NODE_TYPES15.Identifier) {
4142
+ if (expression.name === "fetch" && resolvesToGlobal(expression)) return true;
4143
+ const variable = bindingOf(expression);
4144
+ return variable !== null && aliases.has(variable) && isStableAlias(variable);
4072
4145
  }
4073
- const receiver = invocation.arguments[0];
4074
- if (receiver === void 0 || receiver.type === AST_NODE_TYPES15.SpreadElement) return false;
4075
- if (node.type === AST_NODE_TYPES15.MemberExpression) {
4076
- const original = receiverOf(node);
4077
- return original !== null && receiver.type === AST_NODE_TYPES15.Identifier && receiver.name === original.name;
4146
+ if (expression.type === AST_NODE_TYPES15.MemberExpression) {
4147
+ return isGlobalFetchMember(expression);
4078
4148
  }
4079
- return isGlobalReceiver(receiver);
4149
+ if (expression.type === AST_NODE_TYPES15.LogicalExpression) {
4150
+ return expression.operator === "&&" ? mayBeRawFetch(expression.right) : mayBeRawFetch(expression.left) || mayBeRawFetch(expression.right);
4151
+ }
4152
+ if (expression.type === AST_NODE_TYPES15.ConditionalExpression) {
4153
+ return mayBeRawFetch(expression.consequent) || mayBeRawFetch(expression.alternate);
4154
+ }
4155
+ if (expression.type === AST_NODE_TYPES15.SequenceExpression) {
4156
+ const last = expression.expressions.at(-1);
4157
+ return last !== void 0 && mayBeRawFetch(last);
4158
+ }
4159
+ return false;
4160
+ }
4161
+ function recordAliasFromValue(identifier, value) {
4162
+ if (mayBeRawFetch(value)) recordAlias(identifier);
4163
+ }
4164
+ function reportStored(node) {
4165
+ if (mayBeRawFetch(node)) context.report({ node, messageId: "detachedGlobalFetch" });
4080
4166
  }
4081
- function reportIfDetached(node) {
4082
- if (isTypePosition(node) || isDirectCall(node) || isSafeExplicitReceiverUse(node)) return;
4083
- context.report({ node, messageId: "detachedGlobalFetch" });
4167
+ function isCompatibleReceiver(node) {
4168
+ if (node === void 0 || node.type === AST_NODE_TYPES15.SpreadElement) return false;
4169
+ if (node.type !== AST_NODE_TYPES15.Identifier || !resolvesToGlobal(node)) return false;
4170
+ return GLOBAL_RECEIVERS.has(node.name) || node.name === "undefined";
4084
4171
  }
4085
4172
  return {
4086
- Identifier(node) {
4087
- if (node.name !== "fetch" || !resolvesToGlobal(node)) return;
4088
- const parent = node.parent;
4089
- if (parent.type === AST_NODE_TYPES15.MemberExpression && parent.property === node) {
4090
- return;
4091
- }
4092
- if (parent.type === AST_NODE_TYPES15.Property && parent.key === node && !parent.computed && !parent.shorthand) {
4093
- return;
4173
+ AssignmentExpression(node) {
4174
+ if (STORAGE_ASSIGNMENT_OPERATORS.has(node.operator) && node.left.type === AST_NODE_TYPES15.MemberExpression) {
4175
+ reportStored(node.right);
4094
4176
  }
4095
- reportIfDetached(node);
4096
4177
  },
4097
- "MemberExpression[computed=false]"(node) {
4098
- if (node.property.type !== AST_NODE_TYPES15.Identifier || node.property.name !== "fetch" || !isGlobalReceiver(node.object)) {
4178
+ AssignmentPattern(node) {
4179
+ if (node.left.type !== AST_NODE_TYPES15.Identifier) return;
4180
+ recordAliasFromValue(node.left, node.right);
4181
+ if (node.parent.type === AST_NODE_TYPES15.TSParameterProperty) reportStored(node.right);
4182
+ },
4183
+ CallExpression(node) {
4184
+ const callee = unwrapExpression(node.callee);
4185
+ if (callee.type !== AST_NODE_TYPES15.MemberExpression || !EXPLICIT_RECEIVER_METHODS.has(staticMemberName9(callee) ?? "") || !mayBeRawFetch(callee.object) || isCompatibleReceiver(node.arguments[0])) return;
4186
+ context.report({ node: callee.object, messageId: "detachedGlobalFetch" });
4187
+ },
4188
+ Property(node) {
4189
+ if (node.parent.type === AST_NODE_TYPES15.ObjectPattern || node.method || node.value.type === AST_NODE_TYPES15.AssignmentPattern || node.value.type === AST_NODE_TYPES15.TSEmptyBodyFunctionExpression) return;
4190
+ reportStored(node.value);
4191
+ },
4192
+ PropertyDefinition(node) {
4193
+ if (node.value !== null) reportStored(node.value);
4194
+ },
4195
+ VariableDeclarator(node) {
4196
+ if (node.init === null) return;
4197
+ if (node.id.type === AST_NODE_TYPES15.Identifier) {
4198
+ recordAliasFromValue(node.id, node.init);
4099
4199
  return;
4100
4200
  }
4101
- reportIfDetached(node);
4201
+ if (node.id.type !== AST_NODE_TYPES15.ObjectPattern || !isGlobalReceiver(unwrapExpression(node.init))) return;
4202
+ for (const property of node.id.properties) {
4203
+ if (property.type !== AST_NODE_TYPES15.Property || property.computed || property.key.type !== AST_NODE_TYPES15.Identifier || property.key.name !== "fetch") continue;
4204
+ const value = property.value.type === AST_NODE_TYPES15.AssignmentPattern ? property.value.left : property.value;
4205
+ if (value.type === AST_NODE_TYPES15.Identifier) recordAlias(value);
4206
+ }
4102
4207
  }
4103
4208
  };
4104
4209
  }
@@ -4364,7 +4469,7 @@ var NO_JSON_STRINGIFY_OBJECT_EQUALITY_DOCUMENTATION = {
4364
4469
  };
4365
4470
  var EQUALITY_OPERATORS = /* @__PURE__ */ new Set(["!=", "!==", "==", "==="]);
4366
4471
  var PRIMITIVE_FLAGS = ts.TypeFlags.BigIntLike | ts.TypeFlags.BooleanLike | ts.TypeFlags.ESSymbolLike | ts.TypeFlags.Never | ts.TypeFlags.Null | ts.TypeFlags.NumberLike | ts.TypeFlags.StringLike | ts.TypeFlags.Undefined | ts.TypeFlags.Void;
4367
- function unwrapExpression(node) {
4472
+ function unwrapExpression2(node) {
4368
4473
  let current = node;
4369
4474
  while (current.type === AST_NODE_TYPES16.ChainExpression || current.type === AST_NODE_TYPES16.TSAsExpression || current.type === AST_NODE_TYPES16.TSNonNullExpression || current.type === AST_NODE_TYPES16.TSTypeAssertion) {
4370
4475
  current = current.expression;
@@ -4372,10 +4477,10 @@ function unwrapExpression(node) {
4372
4477
  return current;
4373
4478
  }
4374
4479
  function jsonStringifyArgument(node, sourceCode) {
4375
- const expression = unwrapExpression(node);
4480
+ const expression = unwrapExpression2(node);
4376
4481
  if (expression.type !== AST_NODE_TYPES16.CallExpression) return null;
4377
4482
  const { callee } = expression;
4378
- if (callee.type !== AST_NODE_TYPES16.MemberExpression || callee.computed || callee.object.type !== AST_NODE_TYPES16.Identifier || callee.object.name !== "JSON" || callee.property.type !== AST_NODE_TYPES16.Identifier || callee.property.name !== "stringify") {
4483
+ if (callee.type !== AST_NODE_TYPES16.MemberExpression || callee.object.type !== AST_NODE_TYPES16.Identifier || callee.object.name !== "JSON" || (!callee.computed ? callee.property.type !== AST_NODE_TYPES16.Identifier || callee.property.name !== "stringify" : callee.property.type !== AST_NODE_TYPES16.Literal || callee.property.value !== "stringify")) {
4379
4484
  return null;
4380
4485
  }
4381
4486
  const variable = ASTUtils9.findVariable(sourceCode.getScope(callee.object), "JSON");
@@ -4403,7 +4508,7 @@ function typeMayContainObject(type, checker) {
4403
4508
  return true;
4404
4509
  }
4405
4510
  function syntaxMayContainObject(node) {
4406
- const expression = unwrapExpression(node);
4511
+ const expression = unwrapExpression2(node);
4407
4512
  if (expression.type === AST_NODE_TYPES16.ObjectExpression) return true;
4408
4513
  if (expression.type !== AST_NODE_TYPES16.ArrayExpression) return null;
4409
4514
  for (const element of expression.elements) {
@@ -5043,7 +5148,7 @@ var INTERFACE_CONTRACT_MEMBERS_PRIVATE_DOCUMENTATION = {
5043
5148
  category: "architecture",
5044
5149
  autofix: "none",
5045
5150
  limitations: [
5046
- "Only concrete classes with an explicit `implements` clause are checked; constructors and static members are excluded.",
5151
+ "Only concrete classes with an explicit `implements` clause are checked; constructors, static members, protected extension hooks, and overrides are excluded.",
5047
5152
  "Inherited interface members are resolved by TypeScript. Computed names are excluded because their contract identity is not stable syntax.",
5048
5153
  "The rule abstains for the whole class when TypeScript cannot resolve any implemented contract, avoiding false positives for missing or unavailable package declarations.",
5049
5154
  "The rule is report-only because a public member can have consumers in another source file; the developer must choose whether to extend the interface or privatize it.",
@@ -5095,7 +5200,7 @@ function reportClass(context, services, owner) {
5095
5200
  }
5096
5201
  }
5097
5202
  function candidate(member) {
5098
- return member.type === AST_NODE_TYPES20.MethodDefinition && member.kind !== "constructor" && !member.static && !member.computed && member.key.type === AST_NODE_TYPES20.Identifier && member.value.body !== null;
5203
+ return member.type === AST_NODE_TYPES20.MethodDefinition && member.kind !== "constructor" && !member.static && member.accessibility !== "protected" && !member.override && !member.computed && member.key.type === AST_NODE_TYPES20.Identifier && member.value.body !== null;
5099
5204
  }
5100
5205
  function interfaceNames(services, owner) {
5101
5206
  const tsOwner = services.esTreeNodeToTSNodeMap.get(owner);
@@ -5453,7 +5558,7 @@ var NO_BARE_RETURN_FROM_TEST_CATCH_DOCUMENTATION = {
5453
5558
  remediation: "Rethrow the error, assert on it, or use the runner's explicit skip mechanism when the capability is optional.",
5454
5559
  category: "testing",
5455
5560
  filePatterns: ["**/*.test.*", "**/*.spec.*", "**/tests/**", "**/__tests__/**"],
5456
- limitations: ["Only bare returns owned by a direct supported test callback and followed lexically by a framework assertion are reported."],
5561
+ limitations: ["Only bare returns owned by a direct supported test callback and followed lexically by a framework assertion are reported. A runner skip suppresses the finding only when it is an unconditional earlier statement in the return's block."],
5457
5562
  examples: [
5458
5563
  { id: "rethrow", title: "Preserve the failure", outcome: "no-match", files: [{ path: "src/codec.test.ts", source: "test('decodes', () => { try { decode(); } catch (error) { throw error; } expect(result()).toBe('ok'); });" }], focusPath: "src/codec.test.ts", expectedCount: 0, public: true },
5459
5564
  { id: "bare-return", title: "Do not silently pass", outcome: "match", files: [{ path: "src/codec.test.ts", source: "test('decodes', () => { try { decode(); } catch { return; } expect(result()).toBe('ok'); });" }], focusPath: "src/codec.test.ts", expectedCount: 1, public: true }
@@ -5474,10 +5579,11 @@ function importedName4(identifier, context, modules) {
5474
5579
  const variable = ASTUtils11.findVariable(context.sourceCode.getScope(identifier), identifier.name);
5475
5580
  if (variable === null || variable.defs.length === 0) return identifier.name;
5476
5581
  for (const definition of variable.defs) {
5477
- if (definition.node.type !== AST_NODE_TYPES22.ImportSpecifier) continue;
5582
+ if (definition.node.type !== AST_NODE_TYPES22.ImportSpecifier && definition.node.type !== AST_NODE_TYPES22.ImportDefaultSpecifier && definition.node.type !== AST_NODE_TYPES22.ImportNamespaceSpecifier) continue;
5478
5583
  const declaration = definition.node.parent;
5479
5584
  if (declaration.type !== AST_NODE_TYPES22.ImportDeclaration || typeof declaration.source.value !== "string" || !modules.has(declaration.source.value)) continue;
5480
5585
  if (declaration.source.value === "node:assert" || declaration.source.value === "node:assert/strict") return "assert";
5586
+ if (definition.node.type !== AST_NODE_TYPES22.ImportSpecifier) continue;
5481
5587
  const imported = definition.node.imported;
5482
5588
  return imported.type === AST_NODE_TYPES22.Identifier ? imported.name : String(imported.value);
5483
5589
  }
@@ -5529,6 +5635,13 @@ function isExplicitSkip(node, context) {
5529
5635
  const root = rootIdentifier2(node.callee.object);
5530
5636
  return root !== null && TEST_NAMES.has(importedName4(root, context, TEST_MODULES2) ?? "");
5531
5637
  }
5638
+ function hasDominatingExplicitSkip(node, context) {
5639
+ const block = node.parent;
5640
+ if (block?.type !== AST_NODE_TYPES22.BlockStatement) return false;
5641
+ return block.body.some(
5642
+ (candidate2) => candidate2.range[1] <= node.range[0] && candidate2.type === AST_NODE_TYPES22.ExpressionStatement && isExplicitSkip(candidate2.expression, context)
5643
+ );
5644
+ }
5532
5645
  var no_bare_return_from_test_catch_default = createRule({
5533
5646
  name: "no-bare-return-from-test-catch",
5534
5647
  documentation: NO_BARE_RETURN_FROM_TEST_CATCH_DOCUMENTATION,
@@ -5554,11 +5667,12 @@ var no_bare_return_from_test_catch_default = createRule({
5554
5667
  }
5555
5668
  if (current === null || current === void 0) break;
5556
5669
  }
5557
- if (catchClause === null || catchClause.parent.finalizer !== null) return;
5670
+ if (catchClause === null) return;
5558
5671
  const parameter = catchClause.param;
5559
- if (parameter?.type === AST_NODE_TYPES22.Identifier && node.parent === catchClause.body) {
5672
+ const returnBlock = node.parent;
5673
+ if (parameter?.type === AST_NODE_TYPES22.Identifier && returnBlock?.type === AST_NODE_TYPES22.BlockStatement) {
5560
5674
  const errorBinding = ASTUtils11.findVariable(context.sourceCode.getScope(parameter), parameter.name);
5561
- const assertedError = catchClause.body.body.some((statement) => {
5675
+ const assertedError = returnBlock.body.some((statement) => {
5562
5676
  if (statement.range[1] >= node.range[0] || statement.type !== AST_NODE_TYPES22.ExpressionStatement) return false;
5563
5677
  const expression = statement.expression;
5564
5678
  if (expression.type !== AST_NODE_TYPES22.CallExpression || !isAssertion(expression, context)) return false;
@@ -5572,7 +5686,7 @@ var no_bare_return_from_test_catch_default = createRule({
5572
5686
  });
5573
5687
  if (assertedError) return;
5574
5688
  }
5575
- if (walkOwnScope(catchClause.body, (current) => current.type === AST_NODE_TYPES22.ThrowStatement || isExplicitSkip(current, context))) return;
5689
+ if (hasDominatingExplicitSkip(node, context)) return;
5576
5690
  if (!walkOwnScope(owner.body, (current) => current.range[0] > node.range[1] && isAssertion(current, context))) return;
5577
5691
  context.report({ node, messageId: "bareReturnFromTestCatch" });
5578
5692
  }
@@ -5810,7 +5924,8 @@ var no_long_comment_default = createRule({
5810
5924
  });
5811
5925
 
5812
5926
  // src/rules/no-vague-suppression-description.ts
5813
- var DIRECTIVE_WITH_DESCRIPTION_RE = /^(?:eslint-(?:disable|disable-next-line|disable-line)\b[^:\n]*?|@ts-expect-error\b)\s*(?::|--)\s*(.+?)\s*$/iu;
5927
+ var ESLINT_DIRECTIVE_WITH_DESCRIPTION_RE = /^eslint-(?:disable|disable-next-line|disable-line)\b[^:\n]*?\s*(?::|--)\s*(.+?)\s*$/iu;
5928
+ var TS_EXPECT_ERROR_WITH_DESCRIPTION_RE = /^@ts-expect-error\b(?:(?:\s*(?::|--)\s*)|\s+)(.+?)\s*$/iu;
5814
5929
  var VAGUE_RE = /^(?:needed|required|intentional(?:ly)?|ignore(?:d)?|false positive|type error|typescript|to satisfy (?:the )?(?:linter|typescript|type checker))\.?$/iu;
5815
5930
  var NO_VAGUE_SUPPRESSION_DESCRIPTION_DOCUMENTATION = {
5816
5931
  summary: "Require suppression descriptions to name the concrete mismatch or invariant instead of a generic non-reason.",
@@ -5853,6 +5968,9 @@ var NO_VAGUE_SUPPRESSION_DESCRIPTION_DOCUMENTATION = {
5853
5968
  }
5854
5969
  ]
5855
5970
  };
5971
+ function suppressionDescription(text) {
5972
+ return (ESLINT_DIRECTIVE_WITH_DESCRIPTION_RE.exec(text)?.[1] ?? TS_EXPECT_ERROR_WITH_DESCRIPTION_RE.exec(text)?.[1])?.trim();
5973
+ }
5856
5974
  var no_vague_suppression_description_default = createRule({
5857
5975
  name: "no-vague-suppression-description",
5858
5976
  documentation: NO_VAGUE_SUPPRESSION_DESCRIPTION_DOCUMENTATION,
@@ -5875,7 +5993,7 @@ var no_vague_suppression_description_default = createRule({
5875
5993
  Program() {
5876
5994
  for (const comment of context.sourceCode.getAllComments()) {
5877
5995
  const text = comment.value.trim();
5878
- const description = DIRECTIVE_WITH_DESCRIPTION_RE.exec(text)?.[1]?.trim();
5996
+ const description = suppressionDescription(text);
5879
5997
  if (description === void 0 || !VAGUE_RE.test(description)) continue;
5880
5998
  context.report({
5881
5999
  loc: comment.loc,
@@ -6939,12 +7057,24 @@ var NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION = {
6939
7057
  { 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 }
6940
7058
  ]
6941
7059
  };
6942
- function literalModule(node) {
6943
- return node?.type === AST_NODE_TYPES28.Literal && typeof node.value === "string" ? node.value : null;
7060
+ function staticModule(node) {
7061
+ if (node?.type === AST_NODE_TYPES28.Literal && typeof node.value === "string") {
7062
+ return node.value;
7063
+ }
7064
+ if (node?.type === AST_NODE_TYPES28.TemplateLiteral && node.expressions.length === 0) {
7065
+ return node.quasis[0]?.value.cooked ?? null;
7066
+ }
7067
+ return null;
6944
7068
  }
6945
7069
  function matchesModule(source, module) {
6946
7070
  return source === module || source.startsWith(`${module}/`);
6947
7071
  }
7072
+ function staticMemberName4(node) {
7073
+ if (!node.computed && node.property.type === AST_NODE_TYPES28.Identifier) {
7074
+ return node.property.name;
7075
+ }
7076
+ return node.computed && node.property.type === AST_NODE_TYPES28.Literal && typeof node.property.value === "string" ? node.property.value : null;
7077
+ }
6948
7078
  var no_restricted_library_load_default = createRule({
6949
7079
  name: "no-restricted-library-load",
6950
7080
  documentation: NO_RESTRICTED_LIBRARY_LOAD_DOCUMENTATION,
@@ -7008,24 +7138,24 @@ var no_restricted_library_load_default = createRule({
7008
7138
  }
7009
7139
  return {
7010
7140
  ImportExpression(node) {
7011
- const source = literalModule(node.source);
7141
+ const source = staticModule(node.source);
7012
7142
  if (source !== null) report2(node.source, source);
7013
7143
  },
7014
7144
  CallExpression(node) {
7015
7145
  let requireIdentifier = null;
7016
7146
  if (node.callee.type === AST_NODE_TYPES28.Identifier && node.callee.name === "require") {
7017
7147
  requireIdentifier = node.callee;
7018
- } else if (node.callee.type === AST_NODE_TYPES28.MemberExpression && !node.callee.computed && node.callee.object.type === AST_NODE_TYPES28.Identifier && node.callee.object.name === "require" && node.callee.property.type === AST_NODE_TYPES28.Identifier && node.callee.property.name === "resolve") {
7148
+ } else if (node.callee.type === AST_NODE_TYPES28.MemberExpression && node.callee.object.type === AST_NODE_TYPES28.Identifier && node.callee.object.name === "require" && staticMemberName4(node.callee) === "resolve") {
7019
7149
  requireIdentifier = node.callee.object;
7020
7150
  }
7021
7151
  if (requireIdentifier === null || !isUnshadowedRequire(requireIdentifier)) return;
7022
- const source = literalModule(node.arguments[0]);
7152
+ const source = staticModule(node.arguments[0]);
7023
7153
  if (source !== null) report2(node.arguments[0], source);
7024
7154
  },
7025
7155
  TSImportEqualsDeclaration(node) {
7026
7156
  if (node.importKind === "type") return;
7027
7157
  if (node.moduleReference.type !== AST_NODE_TYPES28.TSExternalModuleReference) return;
7028
- const source = literalModule(node.moduleReference.expression);
7158
+ const source = staticModule(node.moduleReference.expression);
7029
7159
  if (source !== null) report2(node.moduleReference.expression, source);
7030
7160
  }
7031
7161
  };
@@ -11072,7 +11202,7 @@ function rootIdentifier3(callee) {
11072
11202
  if (callee.type === AST_NODE_TYPES45.TaggedTemplateExpression) return rootIdentifier3(callee.tag);
11073
11203
  return null;
11074
11204
  }
11075
- function staticMemberName4(member) {
11205
+ function staticMemberName5(member) {
11076
11206
  if (!member.computed && member.property.type === AST_NODE_TYPES45.Identifier) return member.property.name;
11077
11207
  if (member.computed && member.property.type === AST_NODE_TYPES45.Literal && typeof member.property.value === "string") {
11078
11208
  return member.property.value;
@@ -11087,7 +11217,7 @@ function isTestBody2(node, isFrameworkTest) {
11087
11217
  function isTestCaller(callee) {
11088
11218
  if (callee.type === AST_NODE_TYPES45.Identifier) return TEST_CALLERS3.has(callee.name);
11089
11219
  if (callee.type !== AST_NODE_TYPES45.MemberExpression) return false;
11090
- const member = staticMemberName4(callee);
11220
+ const member = staticMemberName5(callee);
11091
11221
  return member !== null && TEST_MODIFIERS3.has(member) && isTestCaller(callee.object);
11092
11222
  }
11093
11223
  function nearestEnclosingFunction2(node) {
@@ -11168,7 +11298,7 @@ function opensSubtest(node, callbackParameters) {
11168
11298
  return false;
11169
11299
  }
11170
11300
  const callee = node.callee;
11171
- return callee.type === AST_NODE_TYPES45.MemberExpression && staticMemberName4(callee) === "test" && callee.object.type === AST_NODE_TYPES45.Identifier && callbackParameters.has(callee.object.name) && node.arguments.some(
11301
+ return callee.type === AST_NODE_TYPES45.MemberExpression && staticMemberName5(callee) === "test" && callee.object.type === AST_NODE_TYPES45.Identifier && callbackParameters.has(callee.object.name) && node.arguments.some(
11172
11302
  (argument) => argument.type !== AST_NODE_TYPES45.SpreadElement && FUNCTION_TYPES6.has(argument.type)
11173
11303
  );
11174
11304
  }
@@ -11218,7 +11348,7 @@ var test_loops_over_literal_cases_default = createRule({
11218
11348
  for (let current = node; current !== void 0 && current !== enclosing; current = current.parent) {
11219
11349
  if (current.parent?.type === AST_NODE_TYPES45.BlockStatement && current.parent.body.at(-1) !== current) return;
11220
11350
  }
11221
- const cases = unwrapExpression2(node.right);
11351
+ const cases = unwrapExpression3(node.right);
11222
11352
  const callbackParameters = new Set(
11223
11353
  enclosing.params.flatMap((parameter) => parameter.type === AST_NODE_TYPES45.Identifier ? [parameter.name] : [])
11224
11354
  );
@@ -11246,9 +11376,9 @@ var test_loops_over_literal_cases_default = createRule({
11246
11376
  };
11247
11377
  }
11248
11378
  });
11249
- function unwrapExpression2(node) {
11379
+ function unwrapExpression3(node) {
11250
11380
  if (node.type === AST_NODE_TYPES45.TSAsExpression || node.type === AST_NODE_TYPES45.TSTypeAssertion || node.type === AST_NODE_TYPES45.TSSatisfiesExpression || node.type === AST_NODE_TYPES45.TSNonNullExpression) {
11251
- return unwrapExpression2(node.expression);
11381
+ return unwrapExpression3(node.expression);
11252
11382
  }
11253
11383
  return node;
11254
11384
  }
@@ -12041,14 +12171,14 @@ function isAsConst(node, sourceText) {
12041
12171
  if (node.type !== AST_NODE_TYPES52.TSAsExpression) return false;
12042
12172
  return sourceText(node.typeAnnotation).trim() === "const";
12043
12173
  }
12044
- function unwrapExpression3(node) {
12174
+ function unwrapExpression4(node) {
12045
12175
  if (node.type === AST_NODE_TYPES52.TSAsExpression || node.type === AST_NODE_TYPES52.TSSatisfiesExpression || node.type === AST_NODE_TYPES52.TSNonNullExpression) {
12046
- return unwrapExpression3(node.expression);
12176
+ return unwrapExpression4(node.expression);
12047
12177
  }
12048
12178
  return node;
12049
12179
  }
12050
12180
  function isObjectFreeze(node, isUnshadowedGlobal3) {
12051
- const inner = unwrapExpression3(node);
12181
+ const inner = unwrapExpression4(node);
12052
12182
  if (inner.type === AST_NODE_TYPES52.CallExpression && inner.callee.type === AST_NODE_TYPES52.MemberExpression && !inner.callee.computed && inner.callee.object.type === AST_NODE_TYPES52.Identifier && inner.callee.object.name === "Object" && isUnshadowedGlobal3(inner.callee.object) && inner.callee.property.type === AST_NODE_TYPES52.Identifier && inner.callee.property.name === "freeze" && inner.arguments.length === 1) {
12053
12183
  const argument = inner.arguments[0];
12054
12184
  return argument !== void 0 && argument.type !== AST_NODE_TYPES52.SpreadElement && collectionKind(argument, isUnshadowedGlobal3) === "literal";
@@ -12056,7 +12186,7 @@ function isObjectFreeze(node, isUnshadowedGlobal3) {
12056
12186
  return false;
12057
12187
  }
12058
12188
  function collectionKind(node, isUnshadowedGlobal3) {
12059
- const inner = unwrapExpression3(node);
12189
+ const inner = unwrapExpression4(node);
12060
12190
  if (inner.type === AST_NODE_TYPES52.CallExpression && inner.callee.type === AST_NODE_TYPES52.MemberExpression && !inner.callee.computed && inner.callee.object.type === AST_NODE_TYPES52.Identifier && inner.callee.object.name === "Object" && isUnshadowedGlobal3(inner.callee.object) && inner.callee.property.type === AST_NODE_TYPES52.Identifier && inner.callee.property.name === "freeze" && inner.arguments.length === 1 && inner.arguments[0] !== void 0 && inner.arguments[0].type !== AST_NODE_TYPES52.SpreadElement) {
12061
12191
  return collectionKind(inner.arguments[0], isUnshadowedGlobal3);
12062
12192
  }
@@ -15497,17 +15627,18 @@ var prefer_schema_for_api_payload_default = createRule({
15497
15627
  // src/rules/prefer-shared-zod-enum.ts
15498
15628
  import { AST_NODE_TYPES as AST_NODE_TYPES67, ASTUtils as ASTUtils38 } from "@typescript-eslint/utils";
15499
15629
  var PREFER_SHARED_ZOD_ENUM_DOCUMENTATION = {
15500
- summary: "Give literal Zod enum domains one reusable module-level schema.",
15501
- rationale: "Inline or repeated literal domains hide a reusable contract and allow equivalent fields to drift independently.",
15630
+ summary: "Give repeated literal Zod enum domains one reusable module-level schema.",
15631
+ rationale: "Repeated literal domains hide a shared contract and allow equivalent fields to drift independently.",
15502
15632
  remediation: "Declare a module-level named Zod enum schema and reuse it at each field or contract site.",
15503
15633
  category: "maintainability",
15504
- limitations: ["Only direct z.enum calls with string-literal arrays are inspected; computed domains require review. Equal values do not prove a shared business domain: retain local schemas when ownership, error customization, or future evolution differs, and review initialization order before extraction."],
15634
+ limitations: ["Only two or more exact, same-order direct z.enum calls with string-literal arrays and no customization argument in one module are inspected; one-off, computed, and customized domains require review. Equal values do not prove a shared business domain: retain local schemas when ownership or future evolution differs, and review initialization order before extraction."],
15505
15635
  examples: [
15506
15636
  { id: "shared-provider", title: "Reuse a named enum schema", outcome: "no-match", files: [{ path: "src/provider.ts", source: "import { z } from 'zod'; const ProviderSchema = z.enum(['agy', 'claude', 'sol']); const JobSchema = z.object({ provider: ProviderSchema }); const StatusSchema = z.object({ provider: ProviderSchema.optional() });" }], focusPath: "src/provider.ts", expectedCount: 0, public: true },
15507
- { id: "inline-provider", title: "Do not inline enum domains in object fields", outcome: "match", files: [{ path: "src/provider.ts", source: "import { z } from 'zod'; const JobSchema = z.object({ provider: z.enum(['agy', 'claude', 'sol']) });" }], focusPath: "src/provider.ts", expectedCount: 1, public: true }
15637
+ { id: "inline-provider", title: "Do not repeat an inline enum domain", outcome: "match", files: [{ path: "src/provider.ts", source: "import { z } from 'zod'; const JobSchema = z.object({ provider: z.enum(['agy', 'claude', 'sol']) }); const StatusSchema = z.object({ provider: z.enum(['agy', 'claude', 'sol']).optional() });" }], focusPath: "src/provider.ts", expectedCount: 2, public: true }
15508
15638
  ]
15509
15639
  };
15510
15640
  function literalDomain(node) {
15641
+ if (node.arguments.length !== 1) return null;
15511
15642
  const [argument] = node.arguments;
15512
15643
  if (argument?.type !== AST_NODE_TYPES67.ArrayExpression || argument.elements.length < 2) return null;
15513
15644
  const values = [];
@@ -15533,7 +15664,7 @@ var prefer_shared_zod_enum_default = createRule({
15533
15664
  documentation: PREFER_SHARED_ZOD_ENUM_DOCUMENTATION,
15534
15665
  meta: {
15535
15666
  type: "suggestion",
15536
- docs: { description: "Give literal Zod enum domains one reusable module-level schema." },
15667
+ docs: { description: PREFER_SHARED_ZOD_ENUM_DOCUMENTATION.summary },
15537
15668
  schema: [],
15538
15669
  messages: {
15539
15670
  shareEnumDomain: "Extract this literal Zod enum to one module-level named schema and reuse it."
@@ -15544,7 +15675,7 @@ var prefer_shared_zod_enum_default = createRule({
15544
15675
  if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
15545
15676
  const zodBindings = /* @__PURE__ */ new Set();
15546
15677
  const bindingOf = (node) => ASTUtils38.findVariable(context.sourceCode.getScope(node), node.name);
15547
- const seen = /* @__PURE__ */ new Set();
15678
+ const candidates = /* @__PURE__ */ new Map();
15548
15679
  return {
15549
15680
  ImportDeclaration(node) {
15550
15681
  if (!isZodModule(node.source.value)) return;
@@ -15562,10 +15693,19 @@ var prefer_shared_zod_enum_default = createRule({
15562
15693
  const domain = literalDomain(node);
15563
15694
  if (domain === null) return;
15564
15695
  const key = JSON.stringify(domain);
15565
- const inline = !isModuleLevelNamedSchema(node);
15566
- if (inline || seen.has(key))
15567
- context.report({ node, messageId: "shareEnumDomain" });
15568
- else seen.add(key);
15696
+ const group = candidates.get(key) ?? [];
15697
+ group.push({ node, named: isModuleLevelNamedSchema(node) });
15698
+ candidates.set(key, group);
15699
+ },
15700
+ "Program:exit"() {
15701
+ for (const group of candidates.values()) {
15702
+ if (group.length < 2) continue;
15703
+ const canonical = group.find((candidate2) => candidate2.named);
15704
+ for (const candidate2 of group) {
15705
+ if (candidate2 === canonical) continue;
15706
+ context.report({ node: candidate2.node, messageId: "shareEnumDomain" });
15707
+ }
15708
+ }
15569
15709
  }
15570
15710
  };
15571
15711
  }
@@ -15640,35 +15780,6 @@ var prefer_switch_for_repeated_equality_default = createRule({
15640
15780
  import { AST_NODE_TYPES as AST_NODE_TYPES69 } from "@typescript-eslint/utils";
15641
15781
  import { existsSync as existsSync2, lstatSync as lstatSync2, readdirSync, readFileSync as readFileSync2 } from "fs";
15642
15782
  import { dirname as dirname2, join as join2, parse } from "path";
15643
-
15644
- // src/rules/_tailwind.ts
15645
- var tailwindVariantPrefix = (token) => {
15646
- let bracketDepth = 0;
15647
- let parenthesisDepth = 0;
15648
- let escaped = false;
15649
- let end = 0;
15650
- for (let index = 0; index < token.length; index += 1) {
15651
- const character = token[index];
15652
- if (escaped) {
15653
- escaped = false;
15654
- continue;
15655
- }
15656
- if (character === "\\") {
15657
- escaped = true;
15658
- continue;
15659
- }
15660
- if (character === "[") bracketDepth += 1;
15661
- else if (character === "]") bracketDepth = Math.max(0, bracketDepth - 1);
15662
- else if (character === "(") parenthesisDepth += 1;
15663
- else if (character === ")") parenthesisDepth = Math.max(0, parenthesisDepth - 1);
15664
- else if (character === ":" && bracketDepth === 0 && parenthesisDepth === 0) end = index + 1;
15665
- }
15666
- return token.slice(0, end);
15667
- };
15668
- var tailwindBase = (token) => token.slice(tailwindVariantPrefix(token).length).replace(/^!/, "");
15669
- var classTokens = (value) => value.split(/\s+/).filter(Boolean);
15670
-
15671
- // src/rules/prefer-semantic-colors.ts
15672
15783
  var PREFER_SEMANTIC_COLORS_DOCUMENTATION = {
15673
15784
  summary: "Enforce semantic color tokens over raw Tailwind palette classes, arbitrary color values, and inline color literals.",
15674
15785
  rationale: "Semantic tokens keep themes and product meaning consistent while raw colors couple components to a palette value.",
@@ -16722,7 +16833,7 @@ var TEST_MODIFIERS4 = /* @__PURE__ */ new Set(["concurrent", "fails", "only", "s
16722
16833
  var EXPECT_MODIFIERS = /* @__PURE__ */ new Set(["not", "rejects", "resolves"]);
16723
16834
  var SNAPSHOT_MATCHERS = /snapshot/iu;
16724
16835
  var MIN_CASES2 = 3;
16725
- function staticMemberName5(node) {
16836
+ function staticMemberName6(node) {
16726
16837
  if (!node.computed && node.property.type === AST_NODE_TYPES71.Identifier) return node.property.name;
16727
16838
  if (node.computed && node.property.type === AST_NODE_TYPES71.Literal && typeof node.property.value === "string") return node.property.value;
16728
16839
  return null;
@@ -16749,7 +16860,7 @@ function isDirectTestCallback2(node, context) {
16749
16860
  function testRoot2(callee) {
16750
16861
  if (callee.type === AST_NODE_TYPES71.Identifier) return callee;
16751
16862
  if (callee.type !== AST_NODE_TYPES71.MemberExpression) return null;
16752
- const modifier = staticMemberName5(callee);
16863
+ const modifier = staticMemberName6(callee);
16753
16864
  return modifier !== null && TEST_MODIFIERS4.has(modifier) ? testRoot2(callee.object) : null;
16754
16865
  }
16755
16866
  function isStatic(node) {
@@ -16813,7 +16924,7 @@ function expectCallFromMatcher(node) {
16813
16924
  const modifiers = [];
16814
16925
  let receiver = node.object;
16815
16926
  while (receiver.type === AST_NODE_TYPES71.MemberExpression) {
16816
- const modifier = staticMemberName5(receiver);
16927
+ const modifier = staticMemberName6(receiver);
16817
16928
  if (modifier === null || !EXPECT_MODIFIERS.has(modifier)) return null;
16818
16929
  modifiers.unshift(modifier);
16819
16930
  receiver = receiver.object;
@@ -18407,8 +18518,8 @@ var FLUENT_BUILDER_NAME_RE = /Builder$/;
18407
18518
  var FLUENT_RESULT_TYPE_RE = /(?:Builder|Base|Query|Without)(?:\W|$)/;
18408
18519
  var ROUTER_FACTORY_NAME = "Router";
18409
18520
  var FRAMEWORK_HTTP_TYPES = /* @__PURE__ */ new Set(["Request", "Response", "NextFunction"]);
18410
- var STORAGE_ASSIGNMENT_OPERATORS = /* @__PURE__ */ new Set(["=", "&&=", "??=", "||="]);
18411
- var staticMemberName6 = (member) => {
18521
+ var STORAGE_ASSIGNMENT_OPERATORS2 = /* @__PURE__ */ new Set(["=", "&&=", "??=", "||="]);
18522
+ var staticMemberName7 = (member) => {
18412
18523
  if (member.property.type === AST_NODE_TYPES77.PrivateIdentifier) return `#${member.property.name}`;
18413
18524
  if (!member.computed && member.property.type === AST_NODE_TYPES77.Identifier) return member.property.name;
18414
18525
  return member.computed && member.property.type === AST_NODE_TYPES77.Literal && typeof member.property.value === "string" ? member.property.value : null;
@@ -18500,8 +18611,8 @@ var readConstructor = (ctor, declared, typeParameters) => {
18500
18611
  if (current === void 0) break;
18501
18612
  if (current.type === AST_NODE_TYPES77.ArrowFunctionExpression || current.type === AST_NODE_TYPES77.FunctionExpression || current.type === AST_NODE_TYPES77.FunctionDeclaration || current.type === AST_NODE_TYPES77.ClassExpression || current.type === AST_NODE_TYPES77.ClassDeclaration) continue;
18502
18613
  const expression = current.type === AST_NODE_TYPES77.ExpressionStatement ? current.expression : null;
18503
- const storedField = expression?.type === AST_NODE_TYPES77.AssignmentExpression && expression.left.type === AST_NODE_TYPES77.MemberExpression && expression.left.object.type === AST_NODE_TYPES77.ThisExpression ? staticMemberName6(expression.left) : null;
18504
- if (expression?.type !== AST_NODE_TYPES77.AssignmentExpression || !STORAGE_ASSIGNMENT_OPERATORS.has(expression.operator) || expression.left.type !== AST_NODE_TYPES77.MemberExpression || expression.left.object.type !== AST_NODE_TYPES77.ThisExpression || storedField === null) {
18614
+ const storedField = expression?.type === AST_NODE_TYPES77.AssignmentExpression && expression.left.type === AST_NODE_TYPES77.MemberExpression && expression.left.object.type === AST_NODE_TYPES77.ThisExpression ? staticMemberName7(expression.left) : null;
18615
+ if (expression?.type !== AST_NODE_TYPES77.AssignmentExpression || !STORAGE_ASSIGNMENT_OPERATORS2.has(expression.operator) || expression.left.type !== AST_NODE_TYPES77.MemberExpression || expression.left.object.type !== AST_NODE_TYPES77.ThisExpression || storedField === null) {
18505
18616
  for (const key of Object.keys(current)) {
18506
18617
  if (key === "parent") continue;
18507
18618
  const value = current[key];
@@ -18525,7 +18636,7 @@ var readConstructor = (ctor, declared, typeParameters) => {
18525
18636
  const fields = storedFieldsFrom.get(source.object.name) ?? /* @__PURE__ */ new Set();
18526
18637
  fields.add(storedField);
18527
18638
  storedFieldsFrom.set(source.object.name, fields);
18528
- const member = staticMemberName6(source);
18639
+ const member = staticMemberName7(source);
18529
18640
  if (member !== null) {
18530
18641
  const members = storedMemberFieldsFrom.get(source.object.name) ?? /* @__PURE__ */ new Map();
18531
18642
  const memberFields = members.get(member) ?? /* @__PURE__ */ new Set();
@@ -18657,7 +18768,7 @@ var invokedInstanceField = (call) => {
18657
18768
  var instanceField = (candidate2) => {
18658
18769
  let node = candidate2;
18659
18770
  while (node.type === AST_NODE_TYPES77.ChainExpression || node.type === AST_NODE_TYPES77.TSAsExpression || node.type === AST_NODE_TYPES77.TSNonNullExpression || node.type === AST_NODE_TYPES77.TSSatisfiesExpression || node.type === AST_NODE_TYPES77.TSTypeAssertion) node = node.expression;
18660
- return node.type === AST_NODE_TYPES77.MemberExpression && node.object.type === AST_NODE_TYPES77.ThisExpression ? staticMemberName6(node) : null;
18771
+ return node.type === AST_NODE_TYPES77.MemberExpression && node.object.type === AST_NODE_TYPES77.ThisExpression ? staticMemberName7(node) : null;
18661
18772
  };
18662
18773
  var behaviorallyInvokedFields = (body2) => {
18663
18774
  const invoked = /* @__PURE__ */ new Set();
@@ -19247,14 +19358,14 @@ var REQUIRE_STATIC_NEXT_MATCHER_DOCUMENTATION = {
19247
19358
  ]
19248
19359
  };
19249
19360
  var NEXT_ENTRY_FILE = /(?:^|[/\\])(?:middleware|proxy)\.[cm]?[jt]sx?$/u;
19250
- function unwrapExpression4(node) {
19361
+ function unwrapExpression5(node) {
19251
19362
  if (node.type === AST_NODE_TYPES79.TSAsExpression || node.type === AST_NODE_TYPES79.TSSatisfiesExpression || node.type === AST_NODE_TYPES79.TSNonNullExpression || node.type === AST_NODE_TYPES79.TSTypeAssertion) {
19252
- return unwrapExpression4(node.expression);
19363
+ return unwrapExpression5(node.expression);
19253
19364
  }
19254
19365
  return node;
19255
19366
  }
19256
19367
  function isStaticValue(node) {
19257
- const value = unwrapExpression4(node);
19368
+ const value = unwrapExpression5(node);
19258
19369
  if (value.type === AST_NODE_TYPES79.Literal) {
19259
19370
  return true;
19260
19371
  }
@@ -19274,9 +19385,8 @@ function isStaticValue(node) {
19274
19385
  return false;
19275
19386
  }
19276
19387
  function propertyName5(property) {
19277
- if (property.computed) return null;
19278
- if (property.key.type === AST_NODE_TYPES79.Identifier) return property.key.name;
19279
- return typeof property.key.value === "string" ? property.key.value : null;
19388
+ if (!property.computed && property.key.type === AST_NODE_TYPES79.Identifier) return property.key.name;
19389
+ return property.key.type === AST_NODE_TYPES79.Literal && typeof property.key.value === "string" ? property.key.value : null;
19280
19390
  }
19281
19391
  var require_static_next_matcher_default = createRule({
19282
19392
  name: "require-static-next-matcher",
@@ -19305,7 +19415,7 @@ var require_static_next_matcher_default = createRule({
19305
19415
  if (declaration.id.type !== AST_NODE_TYPES79.Identifier || declaration.id.name !== "config" || declaration.init === null) {
19306
19416
  continue;
19307
19417
  }
19308
- const config = unwrapExpression4(declaration.init);
19418
+ const config = unwrapExpression5(declaration.init);
19309
19419
  if (config.type !== AST_NODE_TYPES79.ObjectExpression) {
19310
19420
  continue;
19311
19421
  }
@@ -19324,40 +19434,46 @@ var require_static_next_matcher_default = createRule({
19324
19434
  });
19325
19435
 
19326
19436
  // src/rules/require-use-form-default-values.ts
19327
- import { ASTUtils as ASTUtils44 } from "@typescript-eslint/utils";
19437
+ import { AST_NODE_TYPES as AST_NODE_TYPES80, ASTUtils as ASTUtils44 } from "@typescript-eslint/utils";
19328
19438
  var REQUIRE_USE_FORM_DEFAULT_VALUES_DOCUMENTATION = {
19329
- summary: "react-hook-form useForm call without explicit initial or reactive values",
19330
- 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.",
19331
- remediation: "Provide defaultValues for initial state, or values when reactive external state owns initialization; choose schema-appropriate values for controlled fields.",
19439
+ summary: "Require explicit form-level initialization or a field default for directly bound Controller fields.",
19440
+ 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.",
19441
+ remediation: "Provide a non-undefined defaultValues or values option to useForm, or a non-undefined defaultValue on the associated Controller/useController field.",
19332
19442
  category: "correctness",
19333
19443
  limitations: [
19334
- "Only direct calls to a scope-resolved useForm value imported from react-hook-form are checked; reactive values are accepted, while wrapper hooks, spreads and computed option objects are intentionally not inferred."
19444
+ "The rule proves only that an explicit form-level initialization option or field default is present; it does not prove that a particular field path occurs inside a defaultValues/values object.",
19445
+ "The rule reports only scope-resolved Controller/useController fields explicitly bound to a directly created useForm control. FormProvider context, wrapper hooks, dynamic options, spreads, computed properties, and interprocedural flows are intentionally left unreported."
19335
19446
  ],
19336
19447
  examples: [
19337
19448
  {
19338
- id: "form-with-initial-values",
19339
- title: "Give the form an explicit initial shape",
19449
+ id: "controlled-field-with-form-defaults",
19450
+ title: "Initialize controlled fields at form level",
19340
19451
  outcome: "no-match",
19341
- files: [{ path: "profile-form.tsx", source: "'use client'; import { useForm } from 'react-hook-form'; function ProfileForm() { const form = useForm({ defaultValues: { name: '' } }); return <input {...form.register('name')} />; }" }],
19452
+ files: [{ path: "profile-form.tsx", source: "'use client'; import { Controller, useForm } from 'react-hook-form'; function ProfileForm() { const form = useForm({ defaultValues: { name: '' } }); return <Controller control={form.control} name='name' render={() => null} />; }" }],
19342
19453
  focusPath: "profile-form.tsx",
19343
19454
  expectedCount: 0,
19344
19455
  public: true
19345
19456
  },
19346
19457
  {
19347
- id: "form-without-initial-values",
19348
- title: "Do not leave form initialization implicit",
19458
+ id: "controlled-field-without-default",
19459
+ title: "Do not leave a controlled field uninitialized",
19349
19460
  outcome: "match",
19350
- files: [{ path: "profile-form.tsx", source: "'use client'; import { useForm } from 'react-hook-form'; function ProfileForm() { const form = useForm({ mode: 'onChange' }); return <input {...form.register('name')} />; }" }],
19461
+ files: [{ path: "profile-form.tsx", source: "'use client'; import { Controller, useForm } from 'react-hook-form'; function ProfileForm() { const form = useForm(); return <Controller control={form.control} name='name' render={() => null} />; }" }],
19351
19462
  focusPath: "profile-form.tsx",
19352
19463
  expectedCount: 1,
19353
19464
  public: true
19354
19465
  }
19355
19466
  ]
19356
19467
  };
19357
- function hasInitializationOrUnknownOptions(options) {
19358
- return options?.type === "ObjectExpression" && options.properties.some(
19359
- (property) => property.type === "SpreadElement" || property.computed || (property.key.type === "Identifier" && ["defaultValues", "values"].includes(property.key.name) || property.key.type === "Literal" && ["defaultValues", "values"].includes(String(property.key.value)))
19360
- );
19468
+ function staticPropertyName(property) {
19469
+ if (property.computed) return null;
19470
+ if (property.key.type === AST_NODE_TYPES80.Identifier) return property.key.name;
19471
+ if (property.key.type === AST_NODE_TYPES80.Literal && typeof property.key.value === "string") return property.key.value;
19472
+ return null;
19473
+ }
19474
+ function unwrapExpression6(node) {
19475
+ if (node.type === AST_NODE_TYPES80.TSAsExpression || node.type === AST_NODE_TYPES80.TSSatisfiesExpression || node.type === AST_NODE_TYPES80.TSNonNullExpression || node.type === AST_NODE_TYPES80.TSTypeAssertion) return unwrapExpression6(node.expression);
19476
+ return node;
19361
19477
  }
19362
19478
  var require_use_form_default_values_default = createRule({
19363
19479
  name: "require-use-form-default-values",
@@ -19366,27 +19482,127 @@ var require_use_form_default_values_default = createRule({
19366
19482
  type: "problem",
19367
19483
  docs: { description: REQUIRE_USE_FORM_DEFAULT_VALUES_DOCUMENTATION.summary },
19368
19484
  schema: [],
19369
- messages: {
19370
- requireUseFormDefaultValues: "Provide defaultValues or reactive values to useForm so controlled fields have an explicit initial shape."
19371
- }
19485
+ messages: { requireUseFormDefaultValues: "Add non-undefined defaultValues/values to the associated useForm call or non-undefined defaultValue to this field." }
19372
19486
  },
19373
19487
  defaultOptions: [],
19374
19488
  create(context) {
19375
- const importedHooks = /* @__PURE__ */ new Set();
19489
+ const imported = /* @__PURE__ */ new Map();
19490
+ const uninitializedForms = /* @__PURE__ */ new Set();
19491
+ const uninitializedControls = /* @__PURE__ */ new Set();
19492
+ const bindingNamed = (node, name) => ASTUtils44.findVariable(context.sourceCode.getScope(node), name);
19493
+ const bindingOf = (node) => bindingNamed(node, node.name);
19494
+ const stable = (variable) => !variable.references.some((reference) => reference.isWrite() && reference.init !== true);
19495
+ const importedKind = (node) => {
19496
+ const variable = bindingOf(node);
19497
+ return variable !== null && stable(variable) ? imported.get(variable) ?? null : null;
19498
+ };
19499
+ const importedJsxKind = (node) => {
19500
+ const variable = bindingNamed(node, node.name);
19501
+ return variable !== null && stable(variable) ? imported.get(variable) ?? null : null;
19502
+ };
19503
+ const isDefinitelyUndefined = (node) => {
19504
+ const value = unwrapExpression6(node);
19505
+ return value.type === AST_NODE_TYPES80.UnaryExpression && value.operator === "void" || value.type === AST_NODE_TYPES80.Identifier && value.name === "undefined" && (bindingOf(value)?.defs.length ?? 0) === 0;
19506
+ };
19507
+ const initializationState = (node) => {
19508
+ if (node === void 0) return "uninitialized";
19509
+ if (node.type !== AST_NODE_TYPES80.ObjectExpression) return "unknown";
19510
+ const initialization = /* @__PURE__ */ new Map();
19511
+ for (const property of node.properties) {
19512
+ if (property.type === AST_NODE_TYPES80.SpreadElement || property.computed) return "unknown";
19513
+ if (property.type !== AST_NODE_TYPES80.Property) continue;
19514
+ const name = staticPropertyName(property);
19515
+ if (name === "defaultValues" || name === "values") initialization.set(name, !isDefinitelyUndefined(property.value));
19516
+ }
19517
+ return [...initialization.values()].some(Boolean) ? "initialized" : "uninitialized";
19518
+ };
19519
+ const uninitializedUseFormCall = (node) => {
19520
+ if (node.type !== AST_NODE_TYPES80.CallExpression || node.callee.type !== AST_NODE_TYPES80.Identifier || importedKind(node.callee) !== "useForm") return false;
19521
+ const options = node.arguments[0];
19522
+ return options?.type !== AST_NODE_TYPES80.SpreadElement && initializationState(options) === "uninitialized";
19523
+ };
19524
+ const isUninitializedForm = (node) => {
19525
+ if (node.type !== AST_NODE_TYPES80.Identifier) return false;
19526
+ const variable = bindingOf(node);
19527
+ return variable !== null && stable(variable) && uninitializedForms.has(variable);
19528
+ };
19529
+ const isUninitializedControl = (node) => {
19530
+ if (node.type === AST_NODE_TYPES80.Identifier) {
19531
+ const variable = bindingOf(node);
19532
+ return variable !== null && stable(variable) && uninitializedControls.has(variable);
19533
+ }
19534
+ return node.type === AST_NODE_TYPES80.MemberExpression && !node.computed && node.property.type === AST_NODE_TYPES80.Identifier && node.property.name === "control" && isUninitializedForm(node.object);
19535
+ };
19536
+ const fieldOptionsNeedDefault = (node) => {
19537
+ if (node?.type !== AST_NODE_TYPES80.ObjectExpression) return false;
19538
+ let control = null;
19539
+ let hasDefault = false;
19540
+ for (const property of node.properties) {
19541
+ if (property.type === AST_NODE_TYPES80.SpreadElement || property.computed) return false;
19542
+ if (property.type !== AST_NODE_TYPES80.Property) continue;
19543
+ const name = staticPropertyName(property);
19544
+ if (name === "control") control = property.value;
19545
+ if (name === "defaultValue") hasDefault = !isDefinitelyUndefined(property.value);
19546
+ }
19547
+ return control !== null && isUninitializedControl(control) && !hasDefault;
19548
+ };
19549
+ const jsxAttribute = (node, name) => {
19550
+ let result = null;
19551
+ for (const attribute of node.attributes) {
19552
+ if (attribute.type === AST_NODE_TYPES80.JSXSpreadAttribute) return null;
19553
+ if (attribute.name.type === AST_NODE_TYPES80.JSXIdentifier && attribute.name.name === name) result = attribute;
19554
+ }
19555
+ return result;
19556
+ };
19557
+ const trackDestructuredControl = (pattern) => {
19558
+ for (const property of pattern.properties) {
19559
+ if (property.type !== AST_NODE_TYPES80.Property || staticPropertyName(property) !== "control" || property.value.type !== AST_NODE_TYPES80.Identifier) continue;
19560
+ const variable = bindingOf(property.value);
19561
+ if (variable !== null) uninitializedControls.add(variable);
19562
+ }
19563
+ };
19376
19564
  return {
19377
19565
  ImportDeclaration(node) {
19378
19566
  if (node.source.value !== "react-hook-form") return;
19379
19567
  for (const specifier of node.specifiers) {
19380
- if (specifier.type !== "ImportSpecifier" || (specifier.imported.type === "Identifier" ? specifier.imported.name : specifier.imported.value) !== "useForm") continue;
19381
- const variable = ASTUtils44.findVariable(context.sourceCode.getScope(specifier.local), specifier.local.name);
19382
- if (variable) importedHooks.add(variable);
19568
+ if (specifier.type !== AST_NODE_TYPES80.ImportSpecifier) continue;
19569
+ const name = specifier.imported.type === AST_NODE_TYPES80.Identifier ? specifier.imported.name : String(specifier.imported.value);
19570
+ if (name !== "Controller" && name !== "useController" && name !== "useForm") continue;
19571
+ const variable = bindingOf(specifier.local);
19572
+ if (variable !== null) imported.set(variable, name);
19573
+ }
19574
+ },
19575
+ VariableDeclarator(node) {
19576
+ if (node.init === null) return;
19577
+ if (uninitializedUseFormCall(node.init)) {
19578
+ if (node.id.type === AST_NODE_TYPES80.Identifier) {
19579
+ const variable = bindingOf(node.id);
19580
+ if (variable !== null) uninitializedForms.add(variable);
19581
+ } else if (node.id.type === AST_NODE_TYPES80.ObjectPattern) {
19582
+ trackDestructuredControl(node.id);
19583
+ }
19584
+ return;
19585
+ }
19586
+ if (node.id.type === AST_NODE_TYPES80.ObjectPattern && isUninitializedForm(node.init)) {
19587
+ trackDestructuredControl(node.id);
19588
+ return;
19589
+ }
19590
+ if (node.id.type === AST_NODE_TYPES80.Identifier && node.init.type === AST_NODE_TYPES80.MemberExpression && !node.init.computed && node.init.property.type === AST_NODE_TYPES80.Identifier && node.init.property.name === "control" && isUninitializedForm(node.init.object)) {
19591
+ const variable = bindingOf(node.id);
19592
+ if (variable !== null) uninitializedControls.add(variable);
19383
19593
  }
19384
19594
  },
19385
19595
  CallExpression(node) {
19386
- if (node.callee.type !== "Identifier") return;
19387
- const variable = ASTUtils44.findVariable(context.sourceCode.getScope(node.callee), node.callee.name);
19388
- const options = node.arguments[0];
19389
- if (!variable || !importedHooks.has(variable) || options !== void 0 && options.type !== "ObjectExpression" || hasInitializationOrUnknownOptions(options)) return;
19596
+ if (node.callee.type !== AST_NODE_TYPES80.Identifier || importedKind(node.callee) !== "useController" || !fieldOptionsNeedDefault(node.arguments[0]?.type === AST_NODE_TYPES80.SpreadElement ? void 0 : node.arguments[0])) return;
19597
+ context.report({ node, messageId: "requireUseFormDefaultValues" });
19598
+ },
19599
+ JSXOpeningElement(node) {
19600
+ if (node.name.type !== AST_NODE_TYPES80.JSXIdentifier || importedJsxKind(node.name) !== "Controller") return;
19601
+ if (node.attributes.some((attribute) => attribute.type === AST_NODE_TYPES80.JSXSpreadAttribute)) return;
19602
+ const control = jsxAttribute(node, "control");
19603
+ if (control?.value?.type !== AST_NODE_TYPES80.JSXExpressionContainer || control.value.expression.type === AST_NODE_TYPES80.JSXEmptyExpression || !isUninitializedControl(control.value.expression)) return;
19604
+ const defaultValue = jsxAttribute(node, "defaultValue");
19605
+ if (defaultValue !== null && (defaultValue.value === null || defaultValue.value.type !== AST_NODE_TYPES80.JSXExpressionContainer || defaultValue.value.expression.type !== AST_NODE_TYPES80.JSXEmptyExpression && !isDefinitelyUndefined(defaultValue.value.expression))) return;
19390
19606
  context.report({ node, messageId: "requireUseFormDefaultValues" });
19391
19607
  }
19392
19608
  };
@@ -19462,7 +19678,7 @@ var require_use_server_in_actions_file_default = createRule({
19462
19678
 
19463
19679
  // src/rules/require-zod-form-validation.ts
19464
19680
  import {
19465
- AST_NODE_TYPES as AST_NODE_TYPES80,
19681
+ AST_NODE_TYPES as AST_NODE_TYPES81,
19466
19682
  ASTUtils as ASTUtils45
19467
19683
  } from "@typescript-eslint/utils";
19468
19684
  var REQUIRE_ZOD_FORM_VALIDATION_DOCUMENTATION = {
@@ -19490,14 +19706,14 @@ var FORM_VALUE_METHODS = /* @__PURE__ */ new Set(["get", "getAll"]);
19490
19706
  var zodReceiverRoot = (node) => {
19491
19707
  let current = node;
19492
19708
  while (true) {
19493
- if (current.type === AST_NODE_TYPES80.Identifier) {
19709
+ if (current.type === AST_NODE_TYPES81.Identifier) {
19494
19710
  return current;
19495
19711
  }
19496
- if (current.type === AST_NODE_TYPES80.CallExpression) {
19712
+ if (current.type === AST_NODE_TYPES81.CallExpression) {
19497
19713
  current = current.callee;
19498
19714
  continue;
19499
19715
  }
19500
- if (current.type === AST_NODE_TYPES80.MemberExpression) {
19716
+ if (current.type === AST_NODE_TYPES81.MemberExpression) {
19501
19717
  current = current.object;
19502
19718
  continue;
19503
19719
  }
@@ -19506,12 +19722,12 @@ var zodReceiverRoot = (node) => {
19506
19722
  };
19507
19723
  var isFormDataMethodCall = (node) => {
19508
19724
  let current = node;
19509
- if (current.type === AST_NODE_TYPES80.AwaitExpression) {
19725
+ if (current.type === AST_NODE_TYPES81.AwaitExpression) {
19510
19726
  current = current.argument;
19511
19727
  }
19512
- if (current.type !== AST_NODE_TYPES80.CallExpression) return false;
19728
+ if (current.type !== AST_NODE_TYPES81.CallExpression) return false;
19513
19729
  const callee = current.callee;
19514
- return callee.type === AST_NODE_TYPES80.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES80.Identifier && callee.property.name === "formData";
19730
+ return callee.type === AST_NODE_TYPES81.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES81.Identifier && callee.property.name === "formData";
19515
19731
  };
19516
19732
  var require_zod_form_validation_default = createRule({
19517
19733
  name: "require-zod-form-validation",
@@ -19542,16 +19758,16 @@ var require_zod_form_validation_default = createRule({
19542
19758
  return false;
19543
19759
  }
19544
19760
  const definition = binding.defs[0];
19545
- if (definition?.type !== "Variable" || definition.node.type !== AST_NODE_TYPES80.VariableDeclarator) {
19761
+ if (definition?.type !== "Variable" || definition.node.type !== AST_NODE_TYPES81.VariableDeclarator) {
19546
19762
  return false;
19547
19763
  }
19548
19764
  const init = definition.node.init;
19549
- return init?.type === AST_NODE_TYPES80.ObjectExpression || init?.type === AST_NODE_TYPES80.ArrayExpression || init?.type === AST_NODE_TYPES80.Literal || init?.type === AST_NODE_TYPES80.ArrowFunctionExpression || init?.type === AST_NODE_TYPES80.FunctionExpression;
19765
+ return init?.type === AST_NODE_TYPES81.ObjectExpression || init?.type === AST_NODE_TYPES81.ArrayExpression || init?.type === AST_NODE_TYPES81.Literal || init?.type === AST_NODE_TYPES81.ArrowFunctionExpression || init?.type === AST_NODE_TYPES81.FunctionExpression;
19550
19766
  };
19551
19767
  const isZodParseCall = (node) => {
19552
- if (node.type !== AST_NODE_TYPES80.CallExpression) return false;
19768
+ if (node.type !== AST_NODE_TYPES81.CallExpression) return false;
19553
19769
  const callee = node.callee;
19554
- if (callee.type !== AST_NODE_TYPES80.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES80.Identifier || !ZOD_PARSE_METHODS.has(callee.property.name)) {
19770
+ if (callee.type !== AST_NODE_TYPES81.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES81.Identifier || !ZOD_PARSE_METHODS.has(callee.property.name)) {
19555
19771
  return false;
19556
19772
  }
19557
19773
  const root = zodReceiverRoot(callee.object);
@@ -19560,14 +19776,14 @@ var require_zod_form_validation_default = createRule({
19560
19776
  return binding !== null && zodBindings.has(binding) || (root.name === "z" || ZOD_SCHEMA_NAME_RE.test(root.name)) && !isProvablyNonZodLocal(root);
19561
19777
  };
19562
19778
  const isFormSourceIdentifier = (node) => {
19563
- if (node.type !== AST_NODE_TYPES80.Identifier) return false;
19779
+ if (node.type !== AST_NODE_TYPES81.Identifier) return false;
19564
19780
  const conventionalName = /formdata/i.test(node.name);
19565
19781
  let scope = context.sourceCode.getScope(node);
19566
19782
  while (scope !== null) {
19567
19783
  const variable = scope.set.get(node.name);
19568
19784
  if (variable !== void 0 && variable.defs.length === 1) {
19569
19785
  const def = variable.defs[0];
19570
- if (def !== void 0 && def.type === "Variable" && def.node.type === AST_NODE_TYPES80.VariableDeclarator && def.node.init !== null) {
19786
+ if (def !== void 0 && def.type === "Variable" && def.node.type === AST_NODE_TYPES81.VariableDeclarator && def.node.init !== null) {
19571
19787
  return isFormDataMethodCall(def.node.init);
19572
19788
  }
19573
19789
  return def?.type === "Parameter" && conventionalName;
@@ -19578,8 +19794,8 @@ var require_zod_form_validation_default = createRule({
19578
19794
  };
19579
19795
  const isFormDataGetCall = (node) => {
19580
19796
  const callee = node.callee;
19581
- if (callee.type !== AST_NODE_TYPES80.MemberExpression) return false;
19582
- if (callee.property.type !== AST_NODE_TYPES80.Identifier || !FORM_VALUE_METHODS.has(callee.property.name)) {
19797
+ if (callee.type !== AST_NODE_TYPES81.MemberExpression) return false;
19798
+ if (callee.property.type !== AST_NODE_TYPES81.Identifier || !FORM_VALUE_METHODS.has(callee.property.name)) {
19583
19799
  return false;
19584
19800
  }
19585
19801
  return isFormSourceIdentifier(callee.object);
@@ -19588,15 +19804,15 @@ var require_zod_form_validation_default = createRule({
19588
19804
  let parent = node.parent;
19589
19805
  while (parent !== null && parent !== void 0) {
19590
19806
  if (isZodParseCall(parent)) return parent;
19591
- if (parent.type === AST_NODE_TYPES80.CallExpression && parent.callee.type === AST_NODE_TYPES80.Identifier && ["Number", "String", "Boolean"].includes(parent.callee.name) && parent.arguments.length === 1 && (resolvedBinding(parent.callee)?.defs.length ?? 0) === 0) {
19807
+ if (parent.type === AST_NODE_TYPES81.CallExpression && parent.callee.type === AST_NODE_TYPES81.Identifier && ["Number", "String", "Boolean"].includes(parent.callee.name) && parent.arguments.length === 1 && (resolvedBinding(parent.callee)?.defs.length ?? 0) === 0) {
19592
19808
  parent = parent.parent;
19593
19809
  continue;
19594
19810
  }
19595
- if (parent.type === AST_NODE_TYPES80.CallExpression && parent.callee.type === AST_NODE_TYPES80.MemberExpression && !parent.callee.computed && parent.callee.object.type === AST_NODE_TYPES80.Identifier && parent.callee.object.name === "Object" && parent.callee.property.type === AST_NODE_TYPES80.Identifier && parent.callee.property.name === "fromEntries" && (resolvedBinding(parent.callee.object)?.defs.length ?? 0) === 0) {
19811
+ if (parent.type === AST_NODE_TYPES81.CallExpression && parent.callee.type === AST_NODE_TYPES81.MemberExpression && !parent.callee.computed && parent.callee.object.type === AST_NODE_TYPES81.Identifier && parent.callee.object.name === "Object" && parent.callee.property.type === AST_NODE_TYPES81.Identifier && parent.callee.property.name === "fromEntries" && (resolvedBinding(parent.callee.object)?.defs.length ?? 0) === 0) {
19596
19812
  parent = parent.parent;
19597
19813
  continue;
19598
19814
  }
19599
- if (parent.type === AST_NODE_TYPES80.CallExpression || parent.type === AST_NODE_TYPES80.NewExpression || parent.type === AST_NODE_TYPES80.TaggedTemplateExpression || parent.type === AST_NODE_TYPES80.ArrowFunctionExpression || parent.type === AST_NODE_TYPES80.FunctionExpression || parent.type === AST_NODE_TYPES80.FunctionDeclaration) return null;
19815
+ if (parent.type === AST_NODE_TYPES81.CallExpression || parent.type === AST_NODE_TYPES81.NewExpression || parent.type === AST_NODE_TYPES81.TaggedTemplateExpression || parent.type === AST_NODE_TYPES81.ArrowFunctionExpression || parent.type === AST_NODE_TYPES81.FunctionExpression || parent.type === AST_NODE_TYPES81.FunctionDeclaration) return null;
19600
19816
  parent = parent.parent;
19601
19817
  }
19602
19818
  return null;
@@ -19604,16 +19820,16 @@ var require_zod_form_validation_default = createRule({
19604
19820
  const hasZodParseAncestor = (node) => zodParseAncestor(node) !== null;
19605
19821
  const isInstanceofNarrowing = (node) => {
19606
19822
  const parent = node.parent;
19607
- return parent !== null && parent !== void 0 && parent.type === AST_NODE_TYPES80.BinaryExpression && parent.operator === "instanceof" && parent.left === node && parent.right.type === AST_NODE_TYPES80.Identifier && (parent.right.name === "File" || parent.right.name === "Blob");
19823
+ return parent !== null && parent !== void 0 && parent.type === AST_NODE_TYPES81.BinaryExpression && parent.operator === "instanceof" && parent.left === node && parent.right.type === AST_NODE_TYPES81.Identifier && (parent.right.name === "File" || parent.right.name === "Blob");
19608
19824
  };
19609
19825
  const boundDeclarator = (node) => {
19610
19826
  let current = node;
19611
19827
  let parent = current.parent;
19612
- while ((parent.type === AST_NODE_TYPES80.TSAsExpression || parent.type === AST_NODE_TYPES80.TSSatisfiesExpression || parent.type === AST_NODE_TYPES80.TSNonNullExpression || parent.type === AST_NODE_TYPES80.ChainExpression) && parent.expression === current) {
19828
+ while ((parent.type === AST_NODE_TYPES81.TSAsExpression || parent.type === AST_NODE_TYPES81.TSSatisfiesExpression || parent.type === AST_NODE_TYPES81.TSNonNullExpression || parent.type === AST_NODE_TYPES81.ChainExpression) && parent.expression === current) {
19613
19829
  current = parent;
19614
19830
  parent = current.parent;
19615
19831
  }
19616
- if (parent.type === AST_NODE_TYPES80.VariableDeclarator && parent.init === current && parent.id.type === AST_NODE_TYPES80.Identifier) {
19832
+ if (parent.type === AST_NODE_TYPES81.VariableDeclarator && parent.init === current && parent.id.type === AST_NODE_TYPES81.Identifier) {
19617
19833
  return parent;
19618
19834
  }
19619
19835
  return null;
@@ -19622,7 +19838,7 @@ var require_zod_form_validation_default = createRule({
19622
19838
  let current = node;
19623
19839
  while (current.parent !== void 0) {
19624
19840
  const parent = current.parent;
19625
- if (parent.type === AST_NODE_TYPES80.BlockStatement || parent.type === AST_NODE_TYPES80.Program) {
19841
+ if (parent.type === AST_NODE_TYPES81.BlockStatement || parent.type === AST_NODE_TYPES81.Program) {
19626
19842
  return current;
19627
19843
  }
19628
19844
  current = parent;
@@ -19631,12 +19847,12 @@ var require_zod_form_validation_default = createRule({
19631
19847
  };
19632
19848
  const zodParseMethod = (call) => {
19633
19849
  const callee = call.callee;
19634
- return callee.type === AST_NODE_TYPES80.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES80.Identifier ? callee.property.name : null;
19850
+ return callee.type === AST_NODE_TYPES81.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES81.Identifier ? callee.property.name : null;
19635
19851
  };
19636
19852
  const hasConditionalAncestorBeforeStatement = (node, statement) => {
19637
19853
  let current = node.parent;
19638
19854
  while (current !== void 0 && current !== statement) {
19639
- if (current.type === AST_NODE_TYPES80.LogicalExpression || current.type === AST_NODE_TYPES80.ConditionalExpression) {
19855
+ if (current.type === AST_NODE_TYPES81.LogicalExpression || current.type === AST_NODE_TYPES81.ConditionalExpression) {
19640
19856
  return true;
19641
19857
  }
19642
19858
  current = current.parent;
@@ -19646,7 +19862,7 @@ var require_zod_form_validation_default = createRule({
19646
19862
  const isAwaitedBeforeStatement = (node, statement) => {
19647
19863
  let current = node.parent;
19648
19864
  while (current !== void 0 && current !== statement) {
19649
- if (current.type === AST_NODE_TYPES80.AwaitExpression) return true;
19865
+ if (current.type === AST_NODE_TYPES81.AwaitExpression) return true;
19650
19866
  current = current.parent;
19651
19867
  }
19652
19868
  return false;
@@ -19659,7 +19875,7 @@ var require_zod_form_validation_default = createRule({
19659
19875
  if (declarationStatement === null || validationStatement === null || declarationStatement.parent !== validationStatement.parent || validationStatement.range[0] <= declarationStatement.range[1] || hasConditionalAncestorBeforeStatement(parse2, validationStatement)) {
19660
19876
  return null;
19661
19877
  }
19662
- if (validationStatement.type !== AST_NODE_TYPES80.VariableDeclaration && validationStatement.type !== AST_NODE_TYPES80.ExpressionStatement) {
19878
+ if (validationStatement.type !== AST_NODE_TYPES81.VariableDeclaration && validationStatement.type !== AST_NODE_TYPES81.ExpressionStatement) {
19663
19879
  return null;
19664
19880
  }
19665
19881
  const method = zodParseMethod(parse2);
@@ -19671,16 +19887,16 @@ var require_zod_form_validation_default = createRule({
19671
19887
  };
19672
19888
  const isSafePrevalidationInspection = (identifier) => {
19673
19889
  const parent = identifier.parent;
19674
- if (parent.type === AST_NODE_TYPES80.UnaryExpression && parent.operator === "typeof") {
19890
+ if (parent.type === AST_NODE_TYPES81.UnaryExpression && parent.operator === "typeof") {
19675
19891
  return true;
19676
19892
  }
19677
- if (parent.type !== AST_NODE_TYPES80.BinaryExpression || parent.left !== identifier) {
19893
+ if (parent.type !== AST_NODE_TYPES81.BinaryExpression || parent.left !== identifier) {
19678
19894
  return false;
19679
19895
  }
19680
19896
  if (parent.operator === "instanceof") {
19681
- return parent.right.type === AST_NODE_TYPES80.Identifier && (parent.right.name === "File" || parent.right.name === "Blob");
19897
+ return parent.right.type === AST_NODE_TYPES81.Identifier && (parent.right.name === "File" || parent.right.name === "Blob");
19682
19898
  }
19683
- return ["===", "!==", "==", "!="].includes(parent.operator) && (parent.right.type === AST_NODE_TYPES80.Literal && parent.right.value === null || parent.right.type === AST_NODE_TYPES80.Identifier && parent.right.name === "undefined");
19899
+ return ["===", "!==", "==", "!="].includes(parent.operator) && (parent.right.type === AST_NODE_TYPES81.Literal && parent.right.value === null || parent.right.type === AST_NODE_TYPES81.Identifier && parent.right.name === "undefined");
19684
19900
  };
19685
19901
  const isDescendantOf = (node, ancestor) => {
19686
19902
  let current = node;
@@ -19691,23 +19907,23 @@ var require_zod_form_validation_default = createRule({
19691
19907
  return false;
19692
19908
  };
19693
19909
  const blockTerminates = (node) => {
19694
- if (node.type === AST_NODE_TYPES80.ReturnStatement || node.type === AST_NODE_TYPES80.ThrowStatement) {
19910
+ if (node.type === AST_NODE_TYPES81.ReturnStatement || node.type === AST_NODE_TYPES81.ThrowStatement) {
19695
19911
  return true;
19696
19912
  }
19697
- if (node.type !== AST_NODE_TYPES80.BlockStatement || node.body.length === 0) return false;
19913
+ if (node.type !== AST_NODE_TYPES81.BlockStatement || node.body.length === 0) return false;
19698
19914
  const last = node.body.at(-1);
19699
19915
  return last !== void 0 && blockTerminates(last);
19700
19916
  };
19701
19917
  const narrowingIf = (identifier) => {
19702
19918
  const comparison = identifier.parent;
19703
- if (comparison?.type !== AST_NODE_TYPES80.BinaryExpression || comparison.operator !== "instanceof" || comparison.left !== identifier || comparison.right.type !== AST_NODE_TYPES80.Identifier || comparison.right.name !== "File" && comparison.right.name !== "Blob") {
19919
+ if (comparison?.type !== AST_NODE_TYPES81.BinaryExpression || comparison.operator !== "instanceof" || comparison.left !== identifier || comparison.right.type !== AST_NODE_TYPES81.Identifier || comparison.right.name !== "File" && comparison.right.name !== "Blob") {
19704
19920
  return null;
19705
19921
  }
19706
19922
  const maybeNegation = comparison.parent;
19707
- const negated = maybeNegation?.type === AST_NODE_TYPES80.UnaryExpression && maybeNegation.operator === "!";
19923
+ const negated = maybeNegation?.type === AST_NODE_TYPES81.UnaryExpression && maybeNegation.operator === "!";
19708
19924
  const test = negated ? maybeNegation : comparison;
19709
19925
  const branch = test.parent;
19710
- return branch?.type === AST_NODE_TYPES80.IfStatement && branch.test === test ? { branch, positive: !negated } : null;
19926
+ return branch?.type === AST_NODE_TYPES81.IfStatement && branch.test === test ? { branch, positive: !negated } : null;
19711
19927
  };
19712
19928
  const useDominatedByNarrowing = (use, narrowings) => narrowings.some(({ branch, positive }) => {
19713
19929
  if (positive) return isDescendantOf(use, branch.consequent);
@@ -19727,7 +19943,7 @@ var require_zod_form_validation_default = createRule({
19727
19943
  const variable = context.sourceCode.getDeclaredVariables(declarator)[0];
19728
19944
  if (variable === void 0) return false;
19729
19945
  const references = variable.references.filter((reference) => !reference.isWriteOnly()).map((reference) => reference.identifier).filter(
19730
- (identifier) => identifier.type === AST_NODE_TYPES80.Identifier
19946
+ (identifier) => identifier.type === AST_NODE_TYPES81.Identifier
19731
19947
  );
19732
19948
  if (references.length === 0) return false;
19733
19949
  const narrowings = references.map(narrowingIf).filter(
@@ -19753,7 +19969,7 @@ var require_zod_form_validation_default = createRule({
19753
19969
  ImportDeclaration(node) {
19754
19970
  if (!isZodModule(node.source.value)) return;
19755
19971
  for (const specifier of node.specifiers) {
19756
- if (specifier.type === AST_NODE_TYPES80.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES80.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES80.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES80.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z")) {
19972
+ if (specifier.type === AST_NODE_TYPES81.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES81.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES81.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES81.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z")) {
19757
19973
  const binding = resolvedBinding(specifier.local);
19758
19974
  if (binding !== null) zodBindings.add(binding);
19759
19975
  }
@@ -19843,7 +20059,7 @@ var store_insert_requires_on_conflict_default = createRule({
19843
20059
  });
19844
20060
 
19845
20061
  // src/rules/stepdown.ts
19846
- import { AST_NODE_TYPES as AST_NODE_TYPES81, ASTUtils as ASTUtils46 } from "@typescript-eslint/utils";
20062
+ import { AST_NODE_TYPES as AST_NODE_TYPES82, ASTUtils as ASTUtils46 } from "@typescript-eslint/utils";
19847
20063
  var STEPDOWN_DOCUMENTATION = {
19848
20064
  summary: "Place a private helper below its sole direct same-scope caller.",
19849
20065
  rationale: "Caller-first ordering lets a reader follow the main flow before descending into implementation details.",
@@ -19861,7 +20077,7 @@ var STEPDOWN_DOCUMENTATION = {
19861
20077
  ]
19862
20078
  };
19863
20079
  function isFunction(node) {
19864
- return node.type === AST_NODE_TYPES81.ArrowFunctionExpression || node.type === AST_NODE_TYPES81.FunctionDeclaration || node.type === AST_NODE_TYPES81.FunctionExpression;
20080
+ return node.type === AST_NODE_TYPES82.ArrowFunctionExpression || node.type === AST_NODE_TYPES82.FunctionDeclaration || node.type === AST_NODE_TYPES82.FunctionExpression;
19865
20081
  }
19866
20082
  function reportMisordered(context, candidates, scopeDefinitions, calls, pinned, canMove = () => true) {
19867
20083
  const byName = new Map(scopeDefinitions.map((definition) => [definition.name, definition]));
@@ -19956,8 +20172,8 @@ function moduleScope(context, program) {
19956
20172
  for (const node of declarations) counts.set(node.name, (counts.get(node.name) ?? 0) + 1);
19957
20173
  const overloadNames = new Set(
19958
20174
  program.body.flatMap((statement) => {
19959
- const node = statement.type === AST_NODE_TYPES81.ExportNamedDeclaration ? statement.declaration : statement;
19960
- return node?.type === AST_NODE_TYPES81.TSDeclareFunction && node.id !== null ? [node.id.name] : [];
20175
+ const node = statement.type === AST_NODE_TYPES82.ExportNamedDeclaration ? statement.declaration : statement;
20176
+ return node?.type === AST_NODE_TYPES82.TSDeclareFunction && node.id !== null ? [node.id.name] : [];
19961
20177
  })
19962
20178
  );
19963
20179
  const exported = exportedNames(program);
@@ -19981,7 +20197,7 @@ function moduleScope(context, program) {
19981
20197
  const nearestFunction2 = [...ancestors].reverse().find(isFunction);
19982
20198
  const parent = identifier.parent;
19983
20199
  const callerDefinition = nearestFunction2 === void 0 ? void 0 : byFunction.get(nearestFunction2);
19984
- if (callerDefinition === void 0 || parent.type !== AST_NODE_TYPES81.CallExpression || parent.callee !== identifier) {
20200
+ if (callerDefinition === void 0 || parent.type !== AST_NODE_TYPES82.CallExpression || parent.callee !== identifier) {
19985
20201
  pinned.add(definition.name);
19986
20202
  continue;
19987
20203
  }
@@ -19996,38 +20212,38 @@ function moduleScope(context, program) {
19996
20212
  function exportedNames(program) {
19997
20213
  const names = /* @__PURE__ */ new Set();
19998
20214
  for (const statement of program.body) {
19999
- if (statement.type !== AST_NODE_TYPES81.ExportNamedDeclaration || statement.exportKind === "type" || statement.source !== null) continue;
20000
- if (statement.declaration?.type === AST_NODE_TYPES81.FunctionDeclaration && statement.declaration.id !== null) {
20215
+ if (statement.type !== AST_NODE_TYPES82.ExportNamedDeclaration || statement.exportKind === "type" || statement.source !== null) continue;
20216
+ if (statement.declaration?.type === AST_NODE_TYPES82.FunctionDeclaration && statement.declaration.id !== null) {
20001
20217
  names.add(statement.declaration.id.name);
20002
20218
  }
20003
- if (statement.declaration?.type === AST_NODE_TYPES81.VariableDeclaration) {
20219
+ if (statement.declaration?.type === AST_NODE_TYPES82.VariableDeclaration) {
20004
20220
  for (const declarator of statement.declaration.declarations) {
20005
- if (declarator.id.type === AST_NODE_TYPES81.Identifier) names.add(declarator.id.name);
20221
+ if (declarator.id.type === AST_NODE_TYPES82.Identifier) names.add(declarator.id.name);
20006
20222
  }
20007
20223
  }
20008
20224
  for (const specifier of statement.specifiers) {
20009
- if (specifier.exportKind !== "type" && specifier.local.type === AST_NODE_TYPES81.Identifier) {
20225
+ if (specifier.exportKind !== "type" && specifier.local.type === AST_NODE_TYPES82.Identifier) {
20010
20226
  names.add(specifier.local.name);
20011
20227
  }
20012
20228
  }
20013
20229
  }
20014
20230
  for (const statement of program.body) {
20015
- if (statement.type === AST_NODE_TYPES81.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES81.Identifier) names.add(statement.declaration.name);
20016
- if (statement.type === AST_NODE_TYPES81.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES81.FunctionDeclaration && statement.declaration.id !== null) names.add(statement.declaration.id.name);
20231
+ if (statement.type === AST_NODE_TYPES82.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES82.Identifier) names.add(statement.declaration.name);
20232
+ if (statement.type === AST_NODE_TYPES82.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES82.FunctionDeclaration && statement.declaration.id !== null) names.add(statement.declaration.id.name);
20017
20233
  }
20018
20234
  return names;
20019
20235
  }
20020
20236
  function moduleDefinitions(program) {
20021
20237
  const definitions = [];
20022
20238
  for (const statement of program.body) {
20023
- const node = statement.type === AST_NODE_TYPES81.ExportNamedDeclaration || statement.type === AST_NODE_TYPES81.ExportDefaultDeclaration ? statement.declaration : statement;
20024
- if (node?.type === AST_NODE_TYPES81.FunctionDeclaration && node.id !== null && node.body !== null) {
20239
+ const node = statement.type === AST_NODE_TYPES82.ExportNamedDeclaration || statement.type === AST_NODE_TYPES82.ExportDefaultDeclaration ? statement.declaration : statement;
20240
+ if (node?.type === AST_NODE_TYPES82.FunctionDeclaration && node.id !== null && node.body !== null) {
20025
20241
  definitions.push({ name: node.id.name, node, functionNode: node, bindingNode: node });
20026
20242
  continue;
20027
20243
  }
20028
- if (node?.type !== AST_NODE_TYPES81.VariableDeclaration || node.kind !== "const") continue;
20244
+ if (node?.type !== AST_NODE_TYPES82.VariableDeclaration || node.kind !== "const") continue;
20029
20245
  for (const declarator of node.declarations) {
20030
- if (declarator.id.type === AST_NODE_TYPES81.Identifier && declarator.init !== null && isFunction(declarator.init)) {
20246
+ if (declarator.id.type === AST_NODE_TYPES82.Identifier && declarator.init !== null && isFunction(declarator.init)) {
20031
20247
  definitions.push({
20032
20248
  name: declarator.id.name,
20033
20249
  node: declarator,
@@ -20040,21 +20256,21 @@ function moduleDefinitions(program) {
20040
20256
  return definitions;
20041
20257
  }
20042
20258
  function methodName(node) {
20043
- if (node.key.type === AST_NODE_TYPES81.PrivateIdentifier) return `#${node.key.name}`;
20044
- return !node.computed && node.key.type === AST_NODE_TYPES81.Identifier ? node.key.name : null;
20259
+ if (node.key.type === AST_NODE_TYPES82.PrivateIdentifier) return `#${node.key.name}`;
20260
+ return !node.computed && node.key.type === AST_NODE_TYPES82.Identifier ? node.key.name : null;
20045
20261
  }
20046
20262
  function referencedMethod(context, node, classVariables) {
20047
- const objectVariable = node.object.type === AST_NODE_TYPES81.Identifier ? ASTUtils46.findVariable(context.sourceCode.getScope(node.object), node.object.name) : null;
20263
+ const objectVariable = node.object.type === AST_NODE_TYPES82.Identifier ? ASTUtils46.findVariable(context.sourceCode.getScope(node.object), node.object.name) : null;
20048
20264
  const isClassReference = objectVariable !== null && classVariables.has(objectVariable);
20049
- if (node.object.type !== AST_NODE_TYPES81.ThisExpression && !isClassReference) return null;
20050
- if (node.property.type === AST_NODE_TYPES81.PrivateIdentifier) return `#${node.property.name}`;
20051
- if (!node.computed && node.property.type === AST_NODE_TYPES81.Identifier) return node.property.name;
20052
- return node.computed && node.property.type === AST_NODE_TYPES81.Literal && typeof node.property.value === "string" ? node.property.value : null;
20265
+ if (node.object.type !== AST_NODE_TYPES82.ThisExpression && !isClassReference) return null;
20266
+ if (node.property.type === AST_NODE_TYPES82.PrivateIdentifier) return `#${node.property.name}`;
20267
+ if (!node.computed && node.property.type === AST_NODE_TYPES82.Identifier) return node.property.name;
20268
+ return node.computed && node.property.type === AST_NODE_TYPES82.Literal && typeof node.property.value === "string" ? node.property.value : null;
20053
20269
  }
20054
20270
  function referencedPropertyName(node) {
20055
- if (node.property.type === AST_NODE_TYPES81.PrivateIdentifier) return `#${node.property.name}`;
20056
- if (!node.computed && node.property.type === AST_NODE_TYPES81.Identifier) return node.property.name;
20057
- return node.computed && node.property.type === AST_NODE_TYPES81.Literal && typeof node.property.value === "string" ? node.property.value : null;
20271
+ if (node.property.type === AST_NODE_TYPES82.PrivateIdentifier) return `#${node.property.name}`;
20272
+ if (!node.computed && node.property.type === AST_NODE_TYPES82.Identifier) return node.property.name;
20273
+ return node.computed && node.property.type === AST_NODE_TYPES82.Literal && typeof node.property.value === "string" ? node.property.value : null;
20058
20274
  }
20059
20275
  function walk(node, visitorKeys, visit, nestedFunction = false) {
20060
20276
  visit(node, nestedFunction);
@@ -20070,7 +20286,7 @@ function walk(node, visitorKeys, visit, nestedFunction = false) {
20070
20286
  }
20071
20287
  function classScope(context, node, computedReferenceNames) {
20072
20288
  const methods = node.body.body.filter(
20073
- (member) => member.type === AST_NODE_TYPES81.MethodDefinition
20289
+ (member) => member.type === AST_NODE_TYPES82.MethodDefinition
20074
20290
  );
20075
20291
  const counts = /* @__PURE__ */ new Map();
20076
20292
  for (const method of methods) {
@@ -20078,8 +20294,8 @@ function classScope(context, node, computedReferenceNames) {
20078
20294
  if (name !== null) counts.set(name, (counts.get(name) ?? 0) + 1);
20079
20295
  }
20080
20296
  for (const member of node.body.body) {
20081
- if (member.type !== AST_NODE_TYPES81.TSAbstractMethodDefinition) continue;
20082
- const name = !member.computed && member.key.type === AST_NODE_TYPES81.Identifier ? member.key.name : null;
20297
+ if (member.type !== AST_NODE_TYPES82.TSAbstractMethodDefinition) continue;
20298
+ const name = !member.computed && member.key.type === AST_NODE_TYPES82.Identifier ? member.key.name : null;
20083
20299
  if (name !== null) counts.set(name, (counts.get(name) ?? 0) + 1);
20084
20300
  }
20085
20301
  const scopeDefinitions = methods.flatMap((method) => {
@@ -20088,7 +20304,7 @@ function classScope(context, node, computedReferenceNames) {
20088
20304
  });
20089
20305
  const definitions = methods.flatMap((method) => {
20090
20306
  const name = methodName(method);
20091
- const isPrivate = method.accessibility === "private" || method.key.type === AST_NODE_TYPES81.PrivateIdentifier;
20307
+ const isPrivate = method.accessibility === "private" || method.key.type === AST_NODE_TYPES82.PrivateIdentifier;
20092
20308
  return name !== null && isPrivate && counts.get(name) === 1 && method.decorators.length === 0 ? [{ name, node: method }] : [];
20093
20309
  });
20094
20310
  if (definitions.length === 0) return;
@@ -20100,7 +20316,7 @@ function classScope(context, node, computedReferenceNames) {
20100
20316
  const internal = ASTUtils46.findVariable(context.sourceCode.getScope(node), node.id.name);
20101
20317
  if (internal !== null) classVariables.add(internal);
20102
20318
  }
20103
- if (node.type === AST_NODE_TYPES81.ClassExpression && node.parent.type === AST_NODE_TYPES81.VariableDeclarator && node.parent.id.type === AST_NODE_TYPES81.Identifier) {
20319
+ if (node.type === AST_NODE_TYPES82.ClassExpression && node.parent.type === AST_NODE_TYPES82.VariableDeclarator && node.parent.id.type === AST_NODE_TYPES82.Identifier) {
20104
20320
  const outer = ASTUtils46.findVariable(context.sourceCode.getScope(node.parent), node.parent.id.name);
20105
20321
  if (outer !== null) classVariables.add(outer);
20106
20322
  }
@@ -20117,26 +20333,26 @@ function classScope(context, node, computedReferenceNames) {
20117
20333
  }
20118
20334
  const thisValue = (value) => {
20119
20335
  let current = value;
20120
- while (current?.type === AST_NODE_TYPES81.TSAsExpression || current?.type === AST_NODE_TYPES81.TSSatisfiesExpression || current?.type === AST_NODE_TYPES81.TSNonNullExpression) current = current.expression;
20121
- return current?.type === AST_NODE_TYPES81.ThisExpression;
20336
+ while (current?.type === AST_NODE_TYPES82.TSAsExpression || current?.type === AST_NODE_TYPES82.TSSatisfiesExpression || current?.type === AST_NODE_TYPES82.TSNonNullExpression) current = current.expression;
20337
+ return current?.type === AST_NODE_TYPES82.ThisExpression;
20122
20338
  };
20123
20339
  const collectAlias = (current, nestedFunction) => {
20124
- if (nestedFunction || current.type !== AST_NODE_TYPES81.VariableDeclarator && current.type !== AST_NODE_TYPES81.AssignmentPattern) return;
20125
- if (current.type === AST_NODE_TYPES81.VariableDeclarator && (current.parent.type !== AST_NODE_TYPES81.VariableDeclaration || current.parent.kind !== "const")) return;
20126
- const binding = current.type === AST_NODE_TYPES81.VariableDeclarator ? current.id : current.left;
20127
- const value = current.type === AST_NODE_TYPES81.VariableDeclarator ? current.init : current.right;
20340
+ if (nestedFunction || current.type !== AST_NODE_TYPES82.VariableDeclarator && current.type !== AST_NODE_TYPES82.AssignmentPattern) return;
20341
+ if (current.type === AST_NODE_TYPES82.VariableDeclarator && (current.parent.type !== AST_NODE_TYPES82.VariableDeclaration || current.parent.kind !== "const")) return;
20342
+ const binding = current.type === AST_NODE_TYPES82.VariableDeclarator ? current.id : current.left;
20343
+ const value = current.type === AST_NODE_TYPES82.VariableDeclarator ? current.init : current.right;
20128
20344
  if (!thisValue(value)) return;
20129
- if (binding.type === AST_NODE_TYPES81.ObjectPattern) {
20345
+ if (binding.type === AST_NODE_TYPES82.ObjectPattern) {
20130
20346
  for (const property of binding.properties) {
20131
- if (property.type === AST_NODE_TYPES81.RestElement) {
20347
+ if (property.type === AST_NODE_TYPES82.RestElement) {
20132
20348
  for (const name of privateNames) pinned.add(name);
20133
- } else if (property.key.type === AST_NODE_TYPES81.Identifier && privateNames.has(property.key.name)) {
20349
+ } else if (property.key.type === AST_NODE_TYPES82.Identifier && privateNames.has(property.key.name)) {
20134
20350
  pinned.add(property.key.name);
20135
20351
  }
20136
20352
  }
20137
20353
  return;
20138
20354
  }
20139
- if (binding.type !== AST_NODE_TYPES81.Identifier) return;
20355
+ if (binding.type !== AST_NODE_TYPES82.Identifier) return;
20140
20356
  const variable = ASTUtils46.findVariable(context.sourceCode.getScope(binding), binding.name);
20141
20357
  if (variable !== null) {
20142
20358
  methodClassVariables.add(variable);
@@ -20150,16 +20366,16 @@ function classScope(context, node, computedReferenceNames) {
20150
20366
  walk(statement, context.sourceCode.visitorKeys, collectAlias);
20151
20367
  }
20152
20368
  const visitCall = (current, nestedFunction) => {
20153
- if (current.type === AST_NODE_TYPES81.VariableDeclarator && current.id.type === AST_NODE_TYPES81.ObjectPattern && thisValue(current.init)) {
20369
+ if (current.type === AST_NODE_TYPES82.VariableDeclarator && current.id.type === AST_NODE_TYPES82.ObjectPattern && thisValue(current.init)) {
20154
20370
  for (const property of current.id.properties) {
20155
- if (property.type === AST_NODE_TYPES81.RestElement) {
20371
+ if (property.type === AST_NODE_TYPES82.RestElement) {
20156
20372
  for (const name of privateNames) pinned.add(name);
20157
20373
  continue;
20158
20374
  }
20159
- if (property.type === AST_NODE_TYPES81.Property && property.key.type === AST_NODE_TYPES81.Identifier && privateNames.has(property.key.name)) pinned.add(property.key.name);
20375
+ if (property.type === AST_NODE_TYPES82.Property && property.key.type === AST_NODE_TYPES82.Identifier && privateNames.has(property.key.name)) pinned.add(property.key.name);
20160
20376
  }
20161
20377
  }
20162
- if (current.type !== AST_NODE_TYPES81.MemberExpression) return;
20378
+ if (current.type !== AST_NODE_TYPES82.MemberExpression) return;
20163
20379
  const target = referencedMethod(context, current, methodClassVariables);
20164
20380
  if (target === null) {
20165
20381
  const possibleTarget = referencedPropertyName(current);
@@ -20167,12 +20383,12 @@ function classScope(context, node, computedReferenceNames) {
20167
20383
  return;
20168
20384
  }
20169
20385
  if (!privateNames.has(target)) return;
20170
- const objectVariable = current.object.type === AST_NODE_TYPES81.Identifier ? ASTUtils46.findVariable(context.sourceCode.getScope(current.object), current.object.name) : null;
20386
+ const objectVariable = current.object.type === AST_NODE_TYPES82.Identifier ? ASTUtils46.findVariable(context.sourceCode.getScope(current.object), current.object.name) : null;
20171
20387
  if (objectVariable !== null && methodAliases.has(objectVariable)) {
20172
20388
  pinned.add(target);
20173
20389
  return;
20174
20390
  }
20175
- if (current.computed || nestedFunction || parameterDecoratorNodes.has(current) || current.parent.type !== AST_NODE_TYPES81.CallExpression || current.parent.callee !== current) {
20391
+ if (current.computed || nestedFunction || parameterDecoratorNodes.has(current) || current.parent.type !== AST_NODE_TYPES82.CallExpression || current.parent.callee !== current) {
20176
20392
  pinned.add(target);
20177
20393
  return;
20178
20394
  }
@@ -20192,9 +20408,9 @@ function classScope(context, node, computedReferenceNames) {
20192
20408
  }
20193
20409
  }
20194
20410
  for (const member of node.body.body) {
20195
- if (member.type === AST_NODE_TYPES81.MethodDefinition || member.type === AST_NODE_TYPES81.TSAbstractMethodDefinition) continue;
20411
+ if (member.type === AST_NODE_TYPES82.MethodDefinition || member.type === AST_NODE_TYPES82.TSAbstractMethodDefinition) continue;
20196
20412
  walk(member, context.sourceCode.visitorKeys, (current) => {
20197
- if (current.type !== AST_NODE_TYPES81.MemberExpression) return;
20413
+ if (current.type !== AST_NODE_TYPES82.MemberExpression) return;
20198
20414
  const target = referencedMethod(context, current, classVariables);
20199
20415
  const possibleTarget = target ?? referencedPropertyName(current);
20200
20416
  if (possibleTarget !== null && privateNames.has(possibleTarget)) pinned.add(possibleTarget);
@@ -20216,12 +20432,12 @@ function classScope(context, node, computedReferenceNames) {
20216
20432
  }
20217
20433
  function isClassRuntimeBarrier(member) {
20218
20434
  switch (member.type) {
20219
- case AST_NODE_TYPES81.StaticBlock:
20435
+ case AST_NODE_TYPES82.StaticBlock:
20220
20436
  return true;
20221
- case AST_NODE_TYPES81.PropertyDefinition:
20222
- case AST_NODE_TYPES81.AccessorProperty:
20437
+ case AST_NODE_TYPES82.PropertyDefinition:
20438
+ case AST_NODE_TYPES82.AccessorProperty:
20223
20439
  return member.static || member.computed || member.decorators.length > 0 || member.value !== null;
20224
- case AST_NODE_TYPES81.MethodDefinition:
20440
+ case AST_NODE_TYPES82.MethodDefinition:
20225
20441
  return member.computed || member.decorators.length > 0;
20226
20442
  default:
20227
20443
  return false;
@@ -20253,7 +20469,7 @@ var stepdown_default = createRule({
20253
20469
  moduleScope(context, program);
20254
20470
  const computedReferenceNames = /* @__PURE__ */ new Set();
20255
20471
  walk(program, context.sourceCode.visitorKeys, (node) => {
20256
- if (node.type === AST_NODE_TYPES81.MemberExpression && node.computed && node.property.type === AST_NODE_TYPES81.Literal && typeof node.property.value === "string") computedReferenceNames.add(node.property.value);
20472
+ if (node.type === AST_NODE_TYPES82.MemberExpression && node.computed && node.property.type === AST_NODE_TYPES82.Literal && typeof node.property.value === "string") computedReferenceNames.add(node.property.value);
20257
20473
  });
20258
20474
  for (const node of classes) classScope(context, node, computedReferenceNames);
20259
20475
  }
@@ -20262,8 +20478,8 @@ var stepdown_default = createRule({
20262
20478
  });
20263
20479
 
20264
20480
  // src/rules/source-coupled-test.ts
20265
- import { AST_NODE_TYPES as AST_NODE_TYPES82, ASTUtils as ASTUtils47 } from "@typescript-eslint/utils";
20266
- var GENERAL_SOURCE_SUFFIX_RE = /\.(?:bash|sh|ya?ml|jsonc|py|[cm]?[jt]s)$/iu;
20481
+ import { AST_NODE_TYPES as AST_NODE_TYPES83, ASTUtils as ASTUtils47 } from "@typescript-eslint/utils";
20482
+ var GENERAL_SOURCE_SUFFIX_RE = /\.(?:bash|sh|ya?ml|jsonc?|toml|py|[cm]?[jt]s)$/iu;
20267
20483
  var FS_MODULES = /* @__PURE__ */ new Set(["fs", "node:fs", "fs/promises", "node:fs/promises"]);
20268
20484
  var FS_READERS = /* @__PURE__ */ new Set(["readFile", "readFileSync"]);
20269
20485
  var TEXT_TRANSFORMS = /* @__PURE__ */ new Set([
@@ -20300,6 +20516,8 @@ var EXPECT_MATCHERS = /* @__PURE__ */ new Set([
20300
20516
  ]);
20301
20517
  var EXPECT_MODIFIERS2 = /* @__PURE__ */ new Set(["not", "rejects", "resolves"]);
20302
20518
  var ASSERT_MATCHERS = /* @__PURE__ */ new Set(["deepEqual", "doesNotMatch", "equal", "match", "notDeepEqual", "notEqual", "notStrictEqual", "ok", "strictEqual"]);
20519
+ var EXPECT_MODULES = /* @__PURE__ */ new Set(["@jest/globals", "@playwright/test", "bun:test", "vitest"]);
20520
+ var ASSERT_MODULES = /* @__PURE__ */ new Set(["assert", "assert/strict", "node:assert", "node:assert/strict"]);
20303
20521
  var SOURCE_COUPLED_TEST_DOCUMENTATION = {
20304
20522
  summary: "Disallow raw repository source text as a test oracle; parse or execute the artifact instead.",
20305
20523
  rationale: "Substring and regex checks can pass on comments or unreachable configuration and fail after behavior-preserving formatting changes.",
@@ -20307,6 +20525,7 @@ var SOURCE_COUPLED_TEST_DOCUMENTATION = {
20307
20525
  category: "testing",
20308
20526
  limitations: [
20309
20527
  "The rule follows stable lexical bindings, static source paths, awaited reads, and common text operations. Reassigned bindings, dynamic paths, unknown path wrappers, iterator pipelines, and interprocedural flows remain unreported.",
20528
+ "Assertion roots are scope-resolved for supported test runners and Node assert imports; local or unknown helpers with assertion-like names are not inferred.",
20310
20529
  "When raw representation is genuinely the contract (for example a golden or compatibility sentinel), use an exact line suppression with the reason."
20311
20530
  ],
20312
20531
  examples: [
@@ -20330,22 +20549,22 @@ var SOURCE_COUPLED_TEST_DOCUMENTATION = {
20330
20549
  }
20331
20550
  ]
20332
20551
  };
20333
- function staticMemberName7(node) {
20334
- if (!node.computed && node.property.type === AST_NODE_TYPES82.Identifier) return node.property.name;
20335
- if (node.computed && node.property.type === AST_NODE_TYPES82.Literal && typeof node.property.value === "string") return node.property.value;
20552
+ function staticMemberName8(node) {
20553
+ if (!node.computed && node.property.type === AST_NODE_TYPES83.Identifier) return node.property.name;
20554
+ if (node.computed && node.property.type === AST_NODE_TYPES83.Literal && typeof node.property.value === "string") return node.property.value;
20336
20555
  return null;
20337
20556
  }
20338
20557
  function unwrap7(node) {
20339
- if (node.type === AST_NODE_TYPES82.AwaitExpression) return unwrap7(node.argument);
20340
- if (node.type === AST_NODE_TYPES82.ChainExpression) return unwrap7(node.expression);
20341
- if (node.type === AST_NODE_TYPES82.TSAsExpression || node.type === AST_NODE_TYPES82.TSNonNullExpression || node.type === AST_NODE_TYPES82.TSTypeAssertion) return unwrap7(node.expression);
20558
+ if (node.type === AST_NODE_TYPES83.AwaitExpression) return unwrap7(node.argument);
20559
+ if (node.type === AST_NODE_TYPES83.ChainExpression) return unwrap7(node.expression);
20560
+ if (node.type === AST_NODE_TYPES83.TSAsExpression || node.type === AST_NODE_TYPES83.TSNonNullExpression || node.type === AST_NODE_TYPES83.TSTypeAssertion) return unwrap7(node.expression);
20342
20561
  return node;
20343
20562
  }
20344
20563
  function stringValue(node) {
20345
20564
  const current = unwrap7(node);
20346
- if (current.type === AST_NODE_TYPES82.Literal && typeof current.value === "string") return current.value;
20347
- if (current.type === AST_NODE_TYPES82.TemplateLiteral && current.expressions.length === 0) return current.quasis[0]?.value.cooked ?? null;
20348
- if (current.type === AST_NODE_TYPES82.BinaryExpression && current.operator === "+") {
20565
+ if (current.type === AST_NODE_TYPES83.Literal && typeof current.value === "string") return current.value;
20566
+ if (current.type === AST_NODE_TYPES83.TemplateLiteral && current.expressions.length === 0) return current.quasis[0]?.value.cooked ?? null;
20567
+ if (current.type === AST_NODE_TYPES83.BinaryExpression && current.operator === "+") {
20349
20568
  const left = stringValue(current.left);
20350
20569
  const right = stringValue(current.right);
20351
20570
  return left === null || right === null ? null : left + right;
@@ -20357,7 +20576,7 @@ function importSource(node) {
20357
20576
  }
20358
20577
  function requireSource(node) {
20359
20578
  const current = unwrap7(node);
20360
- if (current.type !== AST_NODE_TYPES82.CallExpression || current.callee.type !== AST_NODE_TYPES82.Identifier || current.callee.name !== "require" || current.arguments.length !== 1 || current.arguments[0]?.type === AST_NODE_TYPES82.SpreadElement) return null;
20579
+ if (current.type !== AST_NODE_TYPES83.CallExpression || current.callee.type !== AST_NODE_TYPES83.Identifier || current.callee.name !== "require" || current.arguments.length !== 1 || current.arguments[0]?.type === AST_NODE_TYPES83.SpreadElement) return null;
20361
20580
  return stringValue(current.arguments[0]);
20362
20581
  }
20363
20582
  function newScope() {
@@ -20380,6 +20599,27 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
20380
20599
  const reportedOrigins = /* @__PURE__ */ new Set();
20381
20600
  const currentScope = () => scopes.at(-1) ?? scopes[0];
20382
20601
  const bindingOf = (node) => ASTUtils47.findVariable(context.sourceCode.getScope(node), node.name);
20602
+ const assertionKind = (node) => {
20603
+ const binding = bindingOf(node);
20604
+ if (binding === null || binding.defs.length === 0) {
20605
+ return node.name === "assert" || node.name === "expect" ? node.name : null;
20606
+ }
20607
+ for (const definition of binding.defs) {
20608
+ const specifier = definition.node;
20609
+ if (specifier.type !== AST_NODE_TYPES83.ImportSpecifier && specifier.type !== AST_NODE_TYPES83.ImportDefaultSpecifier && specifier.type !== AST_NODE_TYPES83.ImportNamespaceSpecifier || specifier.parent.type !== AST_NODE_TYPES83.ImportDeclaration) continue;
20610
+ const source = importSource(specifier.parent);
20611
+ if (source !== null && ASSERT_MODULES.has(source)) {
20612
+ if (specifier.type !== AST_NODE_TYPES83.ImportSpecifier) return "assert";
20613
+ const imported2 = specifier.imported.type === AST_NODE_TYPES83.Identifier ? specifier.imported.name : String(specifier.imported.value);
20614
+ if (imported2 === "strict" || ASSERT_MATCHERS.has(imported2)) return "assert";
20615
+ continue;
20616
+ }
20617
+ if (source === null || !EXPECT_MODULES.has(source) || specifier.type !== AST_NODE_TYPES83.ImportSpecifier) continue;
20618
+ const imported = specifier.imported.type === AST_NODE_TYPES83.Identifier ? specifier.imported.name : String(specifier.imported.value);
20619
+ if (imported === "assert" || imported === "expect") return imported;
20620
+ }
20621
+ return null;
20622
+ };
20383
20623
  const visible = (kind, node) => {
20384
20624
  const name2 = bindingOf(node);
20385
20625
  if (name2 === null || name2.references.some((reference) => reference.isWrite() && reference.init !== true)) return false;
@@ -20402,70 +20642,70 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
20402
20642
  const current = unwrap7(node);
20403
20643
  const value = stringValue(current);
20404
20644
  if (value !== null) return sourceSuffixRe.test(value);
20405
- if (current.type === AST_NODE_TYPES82.Identifier) return visible("paths", current);
20406
- if (current.type === AST_NODE_TYPES82.CallExpression || current.type === AST_NODE_TYPES82.NewExpression) {
20645
+ if (current.type === AST_NODE_TYPES83.Identifier) return visible("paths", current);
20646
+ if (current.type === AST_NODE_TYPES83.CallExpression || current.type === AST_NODE_TYPES83.NewExpression) {
20407
20647
  const callee = current.callee;
20408
20648
  const first = current.arguments[0];
20409
- if (first === void 0 || first.type === AST_NODE_TYPES82.SpreadElement) return false;
20410
- if (current.type === AST_NODE_TYPES82.NewExpression && callee.type === AST_NODE_TYPES82.Identifier && callee.name === "URL" && (bindingOf(callee)?.defs.length ?? 0) === 0) return sourcePath(first);
20411
- if (callee.type === AST_NODE_TYPES82.Identifier && bindingOf(callee)?.defs.some((definition) => definition.node.type === AST_NODE_TYPES82.ImportSpecifier && definition.node.imported.type === AST_NODE_TYPES82.Identifier && definition.node.imported.name === "fileURLToPath" && definition.node.parent.type === AST_NODE_TYPES82.ImportDeclaration && ["node:url", "url"].includes(String(definition.node.parent.source.value)))) return sourcePath(first);
20649
+ if (first === void 0 || first.type === AST_NODE_TYPES83.SpreadElement) return false;
20650
+ if (current.type === AST_NODE_TYPES83.NewExpression && callee.type === AST_NODE_TYPES83.Identifier && callee.name === "URL" && (bindingOf(callee)?.defs.length ?? 0) === 0) return sourcePath(first);
20651
+ if (callee.type === AST_NODE_TYPES83.Identifier && bindingOf(callee)?.defs.some((definition) => definition.node.type === AST_NODE_TYPES83.ImportSpecifier && definition.node.imported.type === AST_NODE_TYPES83.Identifier && definition.node.imported.name === "fileURLToPath" && definition.node.parent.type === AST_NODE_TYPES83.ImportDeclaration && ["node:url", "url"].includes(String(definition.node.parent.source.value)))) return sourcePath(first);
20412
20652
  }
20413
20653
  return false;
20414
20654
  };
20415
20655
  const rawRead = (node) => {
20416
20656
  const current = unwrap7(node);
20417
- if (current.type !== AST_NODE_TYPES82.CallExpression || current.arguments.length === 0) return false;
20657
+ if (current.type !== AST_NODE_TYPES83.CallExpression || current.arguments.length === 0) return false;
20418
20658
  const callee = unwrap7(current.callee);
20419
- if (callee.type === AST_NODE_TYPES82.Identifier) {
20659
+ if (callee.type === AST_NODE_TYPES83.Identifier) {
20420
20660
  return visible("fsReaders", callee) && sourcePath(current.arguments[0]);
20421
20661
  }
20422
- if (callee.type !== AST_NODE_TYPES82.MemberExpression) return false;
20423
- const name2 = staticMemberName7(callee);
20662
+ if (callee.type !== AST_NODE_TYPES83.MemberExpression) return false;
20663
+ const name2 = staticMemberName8(callee);
20424
20664
  const object = unwrap7(callee.object);
20425
- return name2 !== null && FS_READERS.has(name2) && object.type === AST_NODE_TYPES82.Identifier && visible("fsObjects", object) && sourcePath(current.arguments[0]);
20665
+ return name2 !== null && FS_READERS.has(name2) && object.type === AST_NODE_TYPES83.Identifier && visible("fsObjects", object) && sourcePath(current.arguments[0]);
20426
20666
  };
20427
20667
  const rawOrigins = (node) => {
20428
20668
  const current = unwrap7(node);
20429
- if (current.type === AST_NODE_TYPES82.Identifier) return visibleRawOrigins(current);
20669
+ if (current.type === AST_NODE_TYPES83.Identifier) return visibleRawOrigins(current);
20430
20670
  if (rawRead(current)) return /* @__PURE__ */ new Set([`${current.range[0]}:${current.range[1]}`]);
20431
- if (current.type === AST_NODE_TYPES82.BinaryExpression && current.operator === "+") return /* @__PURE__ */ new Set([...rawOrigins(current.left), ...rawOrigins(current.right)]);
20432
- if (current.type === AST_NODE_TYPES82.MemberExpression && staticMemberName7(current) === "length") return rawOrigins(current.object);
20433
- if (current.type !== AST_NODE_TYPES82.CallExpression) return /* @__PURE__ */ new Set();
20671
+ if (current.type === AST_NODE_TYPES83.BinaryExpression && current.operator === "+") return /* @__PURE__ */ new Set([...rawOrigins(current.left), ...rawOrigins(current.right)]);
20672
+ if (current.type === AST_NODE_TYPES83.MemberExpression && staticMemberName8(current) === "length") return rawOrigins(current.object);
20673
+ if (current.type !== AST_NODE_TYPES83.CallExpression) return /* @__PURE__ */ new Set();
20434
20674
  const callee = unwrap7(current.callee);
20435
- if (callee.type !== AST_NODE_TYPES82.MemberExpression) return /* @__PURE__ */ new Set();
20436
- const name2 = staticMemberName7(callee);
20675
+ if (callee.type !== AST_NODE_TYPES83.MemberExpression) return /* @__PURE__ */ new Set();
20676
+ const name2 = staticMemberName8(callee);
20437
20677
  return name2 !== null && TEXT_TRANSFORMS.has(name2) ? rawOrigins(callee.object) : /* @__PURE__ */ new Set();
20438
20678
  };
20439
20679
  const evidenceOrigins = (node) => {
20440
20680
  const current = unwrap7(node);
20441
20681
  const direct = rawOrigins(current);
20442
20682
  if (direct.size > 0) return direct;
20443
- if (current.type === AST_NODE_TYPES82.BinaryExpression || current.type === AST_NODE_TYPES82.LogicalExpression) return /* @__PURE__ */ new Set([...evidenceOrigins(current.left), ...evidenceOrigins(current.right)]);
20444
- if (current.type === AST_NODE_TYPES82.UnaryExpression) return evidenceOrigins(current.argument);
20445
- if (current.type !== AST_NODE_TYPES82.CallExpression) return /* @__PURE__ */ new Set();
20683
+ if (current.type === AST_NODE_TYPES83.BinaryExpression || current.type === AST_NODE_TYPES83.LogicalExpression) return /* @__PURE__ */ new Set([...evidenceOrigins(current.left), ...evidenceOrigins(current.right)]);
20684
+ if (current.type === AST_NODE_TYPES83.UnaryExpression) return evidenceOrigins(current.argument);
20685
+ if (current.type !== AST_NODE_TYPES83.CallExpression) return /* @__PURE__ */ new Set();
20446
20686
  const callee = unwrap7(current.callee);
20447
- if (callee.type !== AST_NODE_TYPES82.MemberExpression) return /* @__PURE__ */ new Set();
20448
- const name2 = staticMemberName7(callee);
20687
+ if (callee.type !== AST_NODE_TYPES83.MemberExpression) return /* @__PURE__ */ new Set();
20688
+ const name2 = staticMemberName8(callee);
20449
20689
  if (name2 !== null && TEXT_PREDICATES.has(name2)) return rawOrigins(callee.object);
20450
- if (name2 !== null && REGEXP_PREDICATES.has(name2)) return new Set(current.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES82.SpreadElement ? [] : [...rawOrigins(argument)]));
20690
+ if (name2 !== null && REGEXP_PREDICATES.has(name2)) return new Set(current.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES83.SpreadElement ? [] : [...rawOrigins(argument)]));
20451
20691
  return /* @__PURE__ */ new Set();
20452
20692
  };
20453
20693
  const rawAssertionOrigins = (node) => {
20454
20694
  const callee = unwrap7(node.callee);
20455
- if (callee.type === AST_NODE_TYPES82.Identifier && callee.name === "assert") {
20456
- return new Set(node.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES82.SpreadElement ? [] : [...evidenceOrigins(argument)]));
20695
+ if (callee.type === AST_NODE_TYPES83.Identifier && assertionKind(callee) === "assert") {
20696
+ return new Set(node.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES83.SpreadElement ? [] : [...evidenceOrigins(argument)]));
20457
20697
  }
20458
- if (callee.type !== AST_NODE_TYPES82.MemberExpression) return /* @__PURE__ */ new Set();
20459
- const matcher = staticMemberName7(callee);
20698
+ if (callee.type !== AST_NODE_TYPES83.MemberExpression) return /* @__PURE__ */ new Set();
20699
+ const matcher = staticMemberName8(callee);
20460
20700
  if (matcher === null) return /* @__PURE__ */ new Set();
20461
20701
  let receiver = unwrap7(callee.object);
20462
- while (receiver.type === AST_NODE_TYPES82.MemberExpression && EXPECT_MODIFIERS2.has(staticMemberName7(receiver) ?? "")) receiver = unwrap7(receiver.object);
20463
- if (receiver.type === AST_NODE_TYPES82.CallExpression && receiver.callee.type === AST_NODE_TYPES82.Identifier && receiver.callee.name === "expect") {
20702
+ while (receiver.type === AST_NODE_TYPES83.MemberExpression && EXPECT_MODIFIERS2.has(staticMemberName8(receiver) ?? "")) receiver = unwrap7(receiver.object);
20703
+ if (receiver.type === AST_NODE_TYPES83.CallExpression && receiver.callee.type === AST_NODE_TYPES83.Identifier && assertionKind(receiver.callee) === "expect") {
20464
20704
  if (!EXPECT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
20465
- return new Set([...receiver.arguments, ...node.arguments].flatMap((argument) => argument.type === AST_NODE_TYPES82.SpreadElement ? [] : [...evidenceOrigins(argument)]));
20705
+ return new Set([...receiver.arguments, ...node.arguments].flatMap((argument) => argument.type === AST_NODE_TYPES83.SpreadElement ? [] : [...evidenceOrigins(argument)]));
20466
20706
  }
20467
- if (receiver.type !== AST_NODE_TYPES82.Identifier || receiver.name !== "assert" || !ASSERT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
20468
- return new Set(node.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES82.SpreadElement ? [] : [...evidenceOrigins(argument)]));
20707
+ if (receiver.type !== AST_NODE_TYPES83.Identifier || assertionKind(receiver) !== "assert" || !ASSERT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
20708
+ return new Set(node.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES83.SpreadElement ? [] : [...evidenceOrigins(argument)]));
20469
20709
  };
20470
20710
  const declare = (node, state) => {
20471
20711
  const name2 = bindingOf(node);
@@ -20487,7 +20727,7 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
20487
20727
  };
20488
20728
  const sourceCollection = (node) => {
20489
20729
  const current = unwrap7(node);
20490
- return current.type === AST_NODE_TYPES82.ArrayExpression && current.elements.length > 0 && current.elements.every((element) => element !== null && element.type !== AST_NODE_TYPES82.SpreadElement && sourcePath(element));
20730
+ return current.type === AST_NODE_TYPES83.ArrayExpression && current.elements.length > 0 && current.elements.every((element) => element !== null && element.type !== AST_NODE_TYPES83.SpreadElement && sourcePath(element));
20491
20731
  };
20492
20732
  const enterFunction = () => {
20493
20733
  scopes.push(newScope());
@@ -20500,8 +20740,8 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
20500
20740
  const source = importSource(node);
20501
20741
  if (source === null || !FS_MODULES.has(source)) return;
20502
20742
  for (const specifier of node.specifiers) {
20503
- if (specifier.type === AST_NODE_TYPES82.ImportSpecifier) {
20504
- const imported = specifier.imported.type === AST_NODE_TYPES82.Identifier ? specifier.imported.name : String(specifier.imported.value);
20743
+ if (specifier.type === AST_NODE_TYPES83.ImportSpecifier) {
20744
+ const imported = specifier.imported.type === AST_NODE_TYPES83.Identifier ? specifier.imported.name : String(specifier.imported.value);
20505
20745
  if (FS_READERS.has(imported)) declare(specifier.local, { fsReader: true });
20506
20746
  } else {
20507
20747
  declare(specifier.local, { fsObject: true });
@@ -20514,30 +20754,30 @@ function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
20514
20754
  if (node.init === null) return;
20515
20755
  const required = requireSource(node.init);
20516
20756
  const initializer = unwrap7(node.init);
20517
- if (required !== null && initializer.type === AST_NODE_TYPES82.CallExpression && initializer.callee.type === AST_NODE_TYPES82.Identifier && (bindingOf(initializer.callee)?.defs.length ?? 0) > 0) return;
20518
- if (required !== null && FS_MODULES.has(required) && node.id.type === AST_NODE_TYPES82.Identifier) {
20757
+ if (required !== null && initializer.type === AST_NODE_TYPES83.CallExpression && initializer.callee.type === AST_NODE_TYPES83.Identifier && (bindingOf(initializer.callee)?.defs.length ?? 0) > 0) return;
20758
+ if (required !== null && FS_MODULES.has(required) && node.id.type === AST_NODE_TYPES83.Identifier) {
20519
20759
  declare(node.id, { fsObject: true });
20520
20760
  return;
20521
20761
  }
20522
- if (node.id.type === AST_NODE_TYPES82.ObjectPattern && required !== null && FS_MODULES.has(required)) {
20762
+ if (node.id.type === AST_NODE_TYPES83.ObjectPattern && required !== null && FS_MODULES.has(required)) {
20523
20763
  for (const property of node.id.properties) {
20524
- if (property.type !== AST_NODE_TYPES82.Property || property.value.type !== AST_NODE_TYPES82.Identifier) continue;
20525
- const key = property.key.type === AST_NODE_TYPES82.Identifier ? property.key.name : property.key.type === AST_NODE_TYPES82.Literal ? String(property.key.value) : "";
20764
+ if (property.type !== AST_NODE_TYPES83.Property || property.value.type !== AST_NODE_TYPES83.Identifier) continue;
20765
+ const key = property.key.type === AST_NODE_TYPES83.Identifier ? property.key.name : property.key.type === AST_NODE_TYPES83.Literal ? String(property.key.value) : "";
20526
20766
  if (FS_READERS.has(key)) declare(property.value, { fsReader: true });
20527
20767
  }
20528
20768
  return;
20529
20769
  }
20530
- if (node.id.type !== AST_NODE_TYPES82.Identifier) return;
20770
+ if (node.id.type !== AST_NODE_TYPES83.Identifier) return;
20531
20771
  declare(node.id, { collection: sourceCollection(node.init), path: sourcePath(node.init), rawOrigins: rawOrigins(node.init) });
20532
20772
  },
20533
20773
  AssignmentExpression(node) {
20534
- if (node.left.type === AST_NODE_TYPES82.Identifier) declare(node.left, {});
20774
+ if (node.left.type === AST_NODE_TYPES83.Identifier) declare(node.left, {});
20535
20775
  },
20536
20776
  ForOfStatement(node) {
20537
20777
  const right = unwrap7(node.right);
20538
- const collection = right.type === AST_NODE_TYPES82.Identifier && visible("collections", right);
20539
- const left = node.left.type === AST_NODE_TYPES82.VariableDeclaration ? node.left.declarations[0]?.id : node.left;
20540
- if (collection && left?.type === AST_NODE_TYPES82.Identifier) declare(left, { path: true });
20778
+ const collection = right.type === AST_NODE_TYPES83.Identifier && visible("collections", right);
20779
+ const left = node.left.type === AST_NODE_TYPES83.VariableDeclaration ? node.left.declarations[0]?.id : node.left;
20780
+ if (collection && left?.type === AST_NODE_TYPES83.Identifier) declare(left, { path: true });
20541
20781
  },
20542
20782
  CallExpression(node) {
20543
20783
  const origins = rawAssertionOrigins(node);
@@ -20556,15 +20796,15 @@ var source_coupled_test_default = createSourceCoupledRule(
20556
20796
  );
20557
20797
 
20558
20798
  // src/rules/sole-export-matches-filename.ts
20559
- import { AST_NODE_TYPES as AST_NODE_TYPES83 } from "@typescript-eslint/utils";
20799
+ import { AST_NODE_TYPES as AST_NODE_TYPES84 } from "@typescript-eslint/utils";
20560
20800
  var SOLE_EXPORT_MATCHES_FILENAME_DOCUMENTATION = {
20561
- summary: "Match a module filename to its sole named public runtime export.",
20801
+ summary: "Make a module filename reflect its sole named public runtime export.",
20562
20802
  rationale: "When a module owns one runtime responsibility, matching names make that responsibility directly discoverable.",
20563
- remediation: "Rename the module stem to the kebab-case export name, or colocate genuinely related exports.",
20803
+ remediation: "Name the module for the exported responsibility, using either the full export name or a clear leading or trailing domain phrase; otherwise colocate genuinely related exports.",
20564
20804
  category: "maintainability",
20565
20805
  limitations: [
20566
20806
  "Framework entrypoints, generic stems covered by no-generic-single-export-module, tests, generated files, anonymous defaults, CommonJS, and re-exports are excluded.",
20567
- "The rule compares the primary filename stem and preserves a single private underscore prefix and conventional suffixes such as .server or .worker.",
20807
+ "The rule compares the primary filename stem and preserves a single private underscore prefix and conventional suffixes such as .server or .worker. A leading or trailing export-name phrase is accepted only at token boundaries; multi-token stems also tolerate established acronym spelling such as github versus GitHub.",
20568
20808
  "Exported destructuring patterns are excluded rather than undercounted as public exports."
20569
20809
  ],
20570
20810
  examples: [
@@ -20590,6 +20830,23 @@ var EXCLUDED_STEMS = /* @__PURE__ */ new Set([
20590
20830
  "util",
20591
20831
  "utils"
20592
20832
  ]);
20833
+ var WEAK_DOMAIN_TOKENS = /* @__PURE__ */ new Set([
20834
+ "adapter",
20835
+ "client",
20836
+ "config",
20837
+ "controller",
20838
+ "factory",
20839
+ "handler",
20840
+ "manager",
20841
+ "provider",
20842
+ "record",
20843
+ "repository",
20844
+ "router",
20845
+ "schema",
20846
+ "service",
20847
+ "store",
20848
+ "worker"
20849
+ ]);
20593
20850
  function stem3(filename) {
20594
20851
  const base = filename.replaceAll("\\", "/").split("/").at(-1) ?? "";
20595
20852
  return base.replace(/\.[cm]?[jt]sx?$/u, "").split(".")[0] ?? "";
@@ -20597,13 +20854,32 @@ function stem3(filename) {
20597
20854
  function kebabCase(name) {
20598
20855
  return name.replace(/([A-Z]{2,})([A-Z][a-z])/gu, "$1-$2").replace(/([a-z0-9])([A-Z])/gu, "$1-$2").replaceAll(/[^a-z0-9]+/giu, "-").replaceAll(/^-+|-+$/gu, "").toLowerCase();
20599
20856
  }
20857
+ function reflectsExportName(fileStem, exportedStem) {
20858
+ if (fileStem.startsWith("_")) return false;
20859
+ const visibleFileStem = fileStem.toLowerCase();
20860
+ const fileTokens = visibleFileStem.split("-").filter(Boolean);
20861
+ const exportTokens = exportedStem.split("-").filter(Boolean);
20862
+ if (fileTokens.length === 0 || exportTokens.length === 0) return false;
20863
+ if (fileTokens.length === 1) {
20864
+ const [token] = fileTokens;
20865
+ return token !== void 0 && token.length >= 4 && !WEAK_DOMAIN_TOKENS.has(token) && (exportTokens[0] === token || exportTokens.at(-1) === token);
20866
+ }
20867
+ const compactFile = fileTokens.join("");
20868
+ if (compactFile.length < 6) return false;
20869
+ const boundaryPhrases = /* @__PURE__ */ new Set();
20870
+ for (let index = 1; index <= exportTokens.length; index += 1) {
20871
+ boundaryPhrases.add(exportTokens.slice(0, index).join(""));
20872
+ boundaryPhrases.add(exportTokens.slice(-index).join(""));
20873
+ }
20874
+ return boundaryPhrases.has(compactFile);
20875
+ }
20600
20876
  function declarationExport(statement) {
20601
20877
  const declaration = statement.declaration;
20602
20878
  if (declaration === null || declaration.declare === true) return [];
20603
- if (declaration.type === AST_NODE_TYPES83.ClassDeclaration || declaration.type === AST_NODE_TYPES83.FunctionDeclaration || declaration.type === AST_NODE_TYPES83.TSEnumDeclaration) return declaration.id === null ? [] : [{ name: declaration.id.name, node: declaration }];
20604
- if (declaration.type !== AST_NODE_TYPES83.VariableDeclaration) return [];
20879
+ if (declaration.type === AST_NODE_TYPES84.ClassDeclaration || declaration.type === AST_NODE_TYPES84.FunctionDeclaration || declaration.type === AST_NODE_TYPES84.TSEnumDeclaration) return declaration.id === null ? [] : [{ name: declaration.id.name, node: declaration }];
20880
+ if (declaration.type !== AST_NODE_TYPES84.VariableDeclaration) return [];
20605
20881
  return declaration.declarations.flatMap(
20606
- (item) => item.id.type === AST_NODE_TYPES83.Identifier ? [{ name: item.id.name, node: item }] : []
20882
+ (item) => item.id.type === AST_NODE_TYPES84.Identifier ? [{ name: item.id.name, node: item }] : []
20607
20883
  );
20608
20884
  }
20609
20885
  var sole_export_matches_filename_default = createRule({
@@ -20611,7 +20887,7 @@ var sole_export_matches_filename_default = createRule({
20611
20887
  documentation: SOLE_EXPORT_MATCHES_FILENAME_DOCUMENTATION,
20612
20888
  meta: {
20613
20889
  type: "suggestion",
20614
- docs: { description: "Match a module filename to its sole named public runtime export." },
20890
+ docs: { description: SOLE_EXPORT_MATCHES_FILENAME_DOCUMENTATION.summary },
20615
20891
  schema: [],
20616
20892
  messages: {
20617
20893
  matchSoleExport: "This module's sole runtime export is `{{exported}}`; rename the file stem to `{{expected}}`."
@@ -20627,32 +20903,32 @@ var sole_export_matches_filename_default = createRule({
20627
20903
  const exports = [];
20628
20904
  const publicExports = /* @__PURE__ */ new Set();
20629
20905
  for (const statement of program.body) {
20630
- if (statement.type === AST_NODE_TYPES83.ExportAllDeclaration || statement.type === AST_NODE_TYPES83.ExportNamedDeclaration && statement.source !== null) return;
20631
- if (statement.type === AST_NODE_TYPES83.ExportDefaultDeclaration) {
20906
+ if (statement.type === AST_NODE_TYPES84.ExportAllDeclaration || statement.type === AST_NODE_TYPES84.ExportNamedDeclaration && statement.source !== null) return;
20907
+ if (statement.type === AST_NODE_TYPES84.ExportDefaultDeclaration) {
20632
20908
  publicExports.add("default");
20633
20909
  const declaration2 = statement.declaration;
20634
- if ((declaration2.type === AST_NODE_TYPES83.ClassDeclaration || declaration2.type === AST_NODE_TYPES83.FunctionDeclaration) && declaration2.id !== null) exports.push({ name: declaration2.id.name, node: declaration2 });
20910
+ if ((declaration2.type === AST_NODE_TYPES84.ClassDeclaration || declaration2.type === AST_NODE_TYPES84.FunctionDeclaration) && declaration2.id !== null) exports.push({ name: declaration2.id.name, node: declaration2 });
20635
20911
  else return;
20636
20912
  }
20637
- if (statement.type !== AST_NODE_TYPES83.ExportNamedDeclaration) continue;
20913
+ if (statement.type !== AST_NODE_TYPES84.ExportNamedDeclaration) continue;
20638
20914
  const declaration = statement.declaration;
20639
- if (declaration !== null && "id" in declaration && declaration.id?.type === AST_NODE_TYPES83.Identifier) {
20915
+ if (declaration !== null && "id" in declaration && declaration.id?.type === AST_NODE_TYPES84.Identifier) {
20640
20916
  publicExports.add(declaration.id.name);
20641
20917
  }
20642
- if (declaration?.type === AST_NODE_TYPES83.VariableDeclaration) {
20643
- if (declaration.declarations.some((item) => item.id.type !== AST_NODE_TYPES83.Identifier)) return;
20918
+ if (declaration?.type === AST_NODE_TYPES84.VariableDeclaration) {
20919
+ if (declaration.declarations.some((item) => item.id.type !== AST_NODE_TYPES84.Identifier)) return;
20644
20920
  for (const item of declaration.declarations) {
20645
- if (item.id.type === AST_NODE_TYPES83.Identifier) publicExports.add(item.id.name);
20921
+ if (item.id.type === AST_NODE_TYPES84.Identifier) publicExports.add(item.id.name);
20646
20922
  }
20647
20923
  }
20648
20924
  for (const specifier of statement.specifiers) {
20649
- const exported = specifier.exported.type === AST_NODE_TYPES83.Identifier ? specifier.exported.name : specifier.exported.value;
20925
+ const exported = specifier.exported.type === AST_NODE_TYPES84.Identifier ? specifier.exported.name : specifier.exported.value;
20650
20926
  publicExports.add(String(exported));
20651
20927
  }
20652
20928
  if (statement.exportKind === "type") continue;
20653
20929
  exports.push(...declarationExport(statement));
20654
20930
  for (const specifier of statement.specifiers) {
20655
- const exported = specifier.exported.type === AST_NODE_TYPES83.Identifier ? specifier.exported.name : specifier.exported.value;
20931
+ const exported = specifier.exported.type === AST_NODE_TYPES84.Identifier ? specifier.exported.name : specifier.exported.value;
20656
20932
  publicExports.add(String(exported));
20657
20933
  if (specifier.exportKind === "type") continue;
20658
20934
  if (exported === "default") exports.push({ name: specifier.local.name, node: specifier });
@@ -20664,11 +20940,11 @@ var sole_export_matches_filename_default = createRule({
20664
20940
  const only = [...unique.values()][0];
20665
20941
  if (only === void 0) return;
20666
20942
  if (only.name === "onRouterTransitionStart" && /(?:^|\/)instrumentation-client\.[jt]s$/u.test(normalizedFilename)) return;
20667
- if (only.name === "collections" && /(?:^|\/)src\/content\.config\.(?:ts|js|mjs)$/u.test(normalizedFilename) && program.body.some((statement) => statement.type === AST_NODE_TYPES83.ImportDeclaration && statement.source.value === "astro:content")) return;
20943
+ if (only.name === "collections" && /(?:^|\/)src\/content\.config\.(?:ts|js|mjs)$/u.test(normalizedFilename) && program.body.some((statement) => statement.type === AST_NODE_TYPES84.ImportDeclaration && statement.source.value === "astro:content")) return;
20668
20944
  const exportedStem = kebabCase(only.name);
20669
20945
  if (exportedStem === "") return;
20670
20946
  const expected = `${fileStem.startsWith("_") ? "_" : ""}${exportedStem}`;
20671
- if (expected === fileStem.toLowerCase()) return;
20947
+ if (expected === fileStem.toLowerCase() || reflectsExportName(fileStem, exportedStem)) return;
20672
20948
  context.report({ node: only.node, messageId: "matchSoleExport", data: { exported: only.name, expected } });
20673
20949
  }
20674
20950
  };
@@ -20715,7 +20991,7 @@ var iac_source_coupled_test_default = createSourceCoupledRule(
20715
20991
 
20716
20992
  // src/rules/require-pascal-case-zod-schema-name.ts
20717
20993
  import {
20718
- AST_NODE_TYPES as AST_NODE_TYPES84,
20994
+ AST_NODE_TYPES as AST_NODE_TYPES85,
20719
20995
  ASTUtils as ASTUtils48
20720
20996
  } from "@typescript-eslint/utils";
20721
20997
  var REQUIRE_PASCAL_CASE_ZOD_SCHEMA_NAME_DOCUMENTATION = {
@@ -20849,18 +21125,18 @@ var SCHEMA_RETURNING_METHODS = /* @__PURE__ */ new Set([
20849
21125
  "superRefine",
20850
21126
  "transform"
20851
21127
  ]);
20852
- var terminalMethodName = (callee) => !callee.computed && callee.property.type === AST_NODE_TYPES84.Identifier ? callee.property.name : null;
21128
+ var terminalMethodName = (callee) => !callee.computed && callee.property.type === AST_NODE_TYPES85.Identifier ? callee.property.name : null;
20853
21129
  var calleeChainRoot2 = (node) => {
20854
21130
  let current = node;
20855
21131
  for (; ; ) {
20856
- if (current.type === AST_NODE_TYPES84.Identifier) {
21132
+ if (current.type === AST_NODE_TYPES85.Identifier) {
20857
21133
  return current;
20858
21134
  }
20859
- if (current.type === AST_NODE_TYPES84.MemberExpression) {
21135
+ if (current.type === AST_NODE_TYPES85.MemberExpression) {
20860
21136
  current = current.object;
20861
21137
  continue;
20862
21138
  }
20863
- if (current.type === AST_NODE_TYPES84.CallExpression) {
21139
+ if (current.type === AST_NODE_TYPES85.CallExpression) {
20864
21140
  current = current.callee;
20865
21141
  continue;
20866
21142
  }
@@ -20871,13 +21147,13 @@ var chainMemberNames2 = (node) => {
20871
21147
  const names = [];
20872
21148
  let current = node;
20873
21149
  for (; ; ) {
20874
- if (current.type === AST_NODE_TYPES84.MemberExpression) {
20875
- if (current.computed || current.property.type !== AST_NODE_TYPES84.Identifier) return [];
21150
+ if (current.type === AST_NODE_TYPES85.MemberExpression) {
21151
+ if (current.computed || current.property.type !== AST_NODE_TYPES85.Identifier) return [];
20876
21152
  names.push(current.property.name);
20877
21153
  current = current.object;
20878
21154
  continue;
20879
21155
  }
20880
- if (current.type === AST_NODE_TYPES84.CallExpression) {
21156
+ if (current.type === AST_NODE_TYPES85.CallExpression) {
20881
21157
  current = current.callee;
20882
21158
  continue;
20883
21159
  }
@@ -20886,18 +21162,18 @@ var chainMemberNames2 = (node) => {
20886
21162
  names.reverse();
20887
21163
  return names;
20888
21164
  };
20889
- var unwrapExpression5 = (node) => {
21165
+ var unwrapExpression7 = (node) => {
20890
21166
  let current = node;
20891
- while (current.type === AST_NODE_TYPES84.TSAsExpression || current.type === AST_NODE_TYPES84.TSSatisfiesExpression || current.type === AST_NODE_TYPES84.TSNonNullExpression || current.type === AST_NODE_TYPES84.TSTypeAssertion) {
21167
+ while (current.type === AST_NODE_TYPES85.TSAsExpression || current.type === AST_NODE_TYPES85.TSSatisfiesExpression || current.type === AST_NODE_TYPES85.TSNonNullExpression || current.type === AST_NODE_TYPES85.TSTypeAssertion) {
20892
21168
  current = current.expression;
20893
21169
  }
20894
21170
  return current;
20895
21171
  };
20896
21172
  var isModuleDeclarator = (node) => {
20897
21173
  const declaration = node.parent;
20898
- if (declaration.type !== AST_NODE_TYPES84.VariableDeclaration) return false;
21174
+ if (declaration.type !== AST_NODE_TYPES85.VariableDeclaration) return false;
20899
21175
  const owner = declaration.parent;
20900
- return owner.type === AST_NODE_TYPES84.Program || owner.type === AST_NODE_TYPES84.ExportNamedDeclaration && owner.parent.type === AST_NODE_TYPES84.Program;
21176
+ return owner.type === AST_NODE_TYPES85.Program || owner.type === AST_NODE_TYPES85.ExportNamedDeclaration && owner.parent.type === AST_NODE_TYPES85.Program;
20901
21177
  };
20902
21178
  var require_pascal_case_zod_schema_name_default = createRule({
20903
21179
  name: "require-pascal-case-zod-schema-name",
@@ -20937,9 +21213,9 @@ var require_pascal_case_zod_schema_name_default = createRule({
20937
21213
  return binding !== null && schemaBindings.has(binding);
20938
21214
  }
20939
21215
  function isConfirmedSchema(expression) {
20940
- const init = unwrapExpression5(expression);
20941
- if (init.type === AST_NODE_TYPES84.Identifier) return isSchemaBinding(init);
20942
- if (init.type !== AST_NODE_TYPES84.CallExpression || init.callee.type !== AST_NODE_TYPES84.MemberExpression) {
21216
+ const init = unwrapExpression7(expression);
21217
+ if (init.type === AST_NODE_TYPES85.Identifier) return isSchemaBinding(init);
21218
+ if (init.type !== AST_NODE_TYPES85.CallExpression || init.callee.type !== AST_NODE_TYPES85.MemberExpression) {
20943
21219
  return false;
20944
21220
  }
20945
21221
  const terminal = terminalMethodName(init.callee);
@@ -20959,7 +21235,7 @@ var require_pascal_case_zod_schema_name_default = createRule({
20959
21235
  ImportDeclaration(node) {
20960
21236
  if (!isZodModule(node.source.value)) return;
20961
21237
  for (const specifier of node.specifiers) {
20962
- if (specifier.type === AST_NODE_TYPES84.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES84.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES84.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES84.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z")) {
21238
+ if (specifier.type === AST_NODE_TYPES85.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES85.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES85.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES85.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z")) {
20963
21239
  recordZodBinding(specifier.local);
20964
21240
  }
20965
21241
  }
@@ -20968,7 +21244,7 @@ var require_pascal_case_zod_schema_name_default = createRule({
20968
21244
  if (!isModuleDeclarator(node)) return;
20969
21245
  const init = node.init;
20970
21246
  if (init === null || init === void 0) return;
20971
- if (node.id.type !== AST_NODE_TYPES84.Identifier) return;
21247
+ if (node.id.type !== AST_NODE_TYPES85.Identifier) return;
20972
21248
  if (!isConfirmedSchema(init)) return;
20973
21249
  const binding = resolvedBinding(node.id);
20974
21250
  if (binding !== null) schemaBindings.add(binding);
@@ -21167,7 +21443,7 @@ var RULES = {
21167
21443
  };
21168
21444
  var meta = {
21169
21445
  name: "@sarj/eslint-plugin",
21170
- version: "15.17.16"
21446
+ version: "15.17.18"
21171
21447
  };
21172
21448
  var APPLICATION_ONLY_RULES = [];
21173
21449
  var LIBRARY_IMPORT_POLICY = ["error", {