@sarj/eslint-plugin 2.15.0 → 2.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- // src/rules/enforce-file-structure.ts
2
- import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
1
+ // src/rules/ban-loose-type-guards-in-tests.ts
2
+ import { ESLintUtils } from "@typescript-eslint/utils";
3
3
 
4
4
  // src/rules/_paths.ts
5
5
  var SCRIPT_FILE_RE = /([\\/]scripts[\\/])|(\.mjs$)/;
@@ -24,7 +24,43 @@ function isScriptFile(filename) {
24
24
  return SCRIPT_FILE_RE.test(filename);
25
25
  }
26
26
 
27
+ // src/rules/ban-loose-type-guards-in-tests.ts
28
+ var ban_loose_type_guards_in_tests_default = ESLintUtils.RuleCreator(
29
+ (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
30
+ )({
31
+ name: "ban-loose-type-guards-in-tests",
32
+ meta: {
33
+ type: "problem",
34
+ docs: {
35
+ description: "Disallow loose type guards (`typeof` and `in`) in test files. Enforce Zod schemas or strict matchers for type validation."
36
+ },
37
+ schema: [],
38
+ messages: {
39
+ banLooseTypeGuardsInTests: "Do not use `typeof` or `in` for type validation in tests. Use Zod schemas or strict assertion matchers instead."
40
+ }
41
+ },
42
+ defaultOptions: [],
43
+ create(context) {
44
+ if (!isTestFile(context.filename)) {
45
+ return {};
46
+ }
47
+ return {
48
+ UnaryExpression(node) {
49
+ if (node.operator === "typeof") {
50
+ context.report({ node, messageId: "banLooseTypeGuardsInTests" });
51
+ }
52
+ },
53
+ BinaryExpression(node) {
54
+ if (node.operator === "in") {
55
+ context.report({ node, messageId: "banLooseTypeGuardsInTests" });
56
+ }
57
+ }
58
+ };
59
+ }
60
+ });
61
+
27
62
  // src/rules/enforce-file-structure.ts
63
+ import { ESLintUtils as ESLintUtils2, AST_NODE_TYPES } from "@typescript-eslint/utils";
28
64
  var classifyStatement = (statement) => {
29
65
  switch (statement.type) {
30
66
  case AST_NODE_TYPES.ImportDeclaration:
@@ -44,7 +80,7 @@ var isUseServerDirective = (statement) => {
44
80
  if (expr.type !== AST_NODE_TYPES.Literal) return false;
45
81
  return expr.value === "use server";
46
82
  };
47
- var enforce_file_structure_default = ESLintUtils.RuleCreator(
83
+ var enforce_file_structure_default = ESLintUtils2.RuleCreator(
48
84
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
49
85
  )({
50
86
  name: "enforce-file-structure",
@@ -106,7 +142,7 @@ var enforce_file_structure_default = ESLintUtils.RuleCreator(
106
142
  // src/rules/no-client-side-data-fetching.ts
107
143
  import {
108
144
  AST_NODE_TYPES as AST_NODE_TYPES2,
109
- ESLintUtils as ESLintUtils2
145
+ ESLintUtils as ESLintUtils3
110
146
  } from "@typescript-eslint/utils";
111
147
  var FETCH_LIBS = /* @__PURE__ */ new Set(["axios", "ky", "superagent"]);
112
148
  var HTTP_METHOD_NAMES = /* @__PURE__ */ new Set([
@@ -204,7 +240,7 @@ function isAnalyticsCall(node) {
204
240
  if (url === "") return false;
205
241
  return url.split(/[/.]/).some((segment) => ANALYTICS_SEGMENTS.has(segment));
206
242
  }
207
- var no_client_side_data_fetching_default = ESLintUtils2.RuleCreator(
243
+ var no_client_side_data_fetching_default = ESLintUtils3.RuleCreator(
208
244
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
209
245
  )({
210
246
  name: "no-client-side-data-fetching",
@@ -242,7 +278,7 @@ var no_client_side_data_fetching_default = ESLintUtils2.RuleCreator(
242
278
  });
243
279
 
244
280
  // src/rules/no-comment-cruft.ts
245
- import { AST_NODE_TYPES as AST_NODE_TYPES4, ESLintUtils as ESLintUtils3 } from "@typescript-eslint/utils";
281
+ import { AST_NODE_TYPES as AST_NODE_TYPES4, ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
246
282
 
247
283
  // src/rules/_comments.ts
248
284
  import { AST_NODE_TYPES as AST_NODE_TYPES3 } from "@typescript-eslint/utils";
@@ -433,9 +469,9 @@ function restatesStatementHead(body, statement) {
433
469
 
434
470
  // src/rules/no-comment-cruft.ts
435
471
  var LEADING_PREAMBLE_MIN = 4;
436
- var STEP_NARRATION_RE = /^(?:first(?:ly)?|second(?:ly)?|third(?:ly)?|then|next|after(?:wards| that)?|finally|lastly|now)\s*[,:]\s*\S|^step\s+\d+\b/i;
472
+ var STEP_NARRATION_RE = /^(?:first(?:ly)?|second(?:ly)?|third(?:ly)?|then|next|after(?:wards| that)?|finally|lastly|now)\s*[,:]\s*\S/i;
437
473
  var META_COMMENTARY_RE = /\b(?:for now|keeping (?:it|this) simple|could be (?:refactored|improved|cleaned up|simplified)|refactor(?:ed|ing)? (?:later|this)|not sure (?:if|whether|why|how)|quick[- ](?:and[- ]dirty|fix)|(?:a |bit of a )?hacky|is a hack|temporary (?:solution|workaround|fix|hack)|revisit (?:this|later|below)|clean (?:this|it) up|not ideal|placeholder for now)\b/i;
438
- var DIRECTIVE_RE = /^(eslint\b|eslint-|sarj-noqa\b|@ts-|prettier-ignore|prettier\b|biome-|c8\b|v8\b|istanbul\b|@type\b|@vite|webpack|<reference|<amd|global\b|noinspection|todo\b|fixme\b|hack\b|xxx\b)/i;
474
+ var DIRECTIVE_RE = /^(eslint\b|eslint-|sarj-noqa\b|@ts-|prettier-ignore|prettier\b|biome-|c8\b|v8\b|istanbul\b|@type\b|@vite|webpack|<reference|<amd|global\b|noinspection|hack\b|xxx\b)/i;
439
475
  var LICENSE_RE = /copyright|licen[cs]ed?|spdx|permission is hereby granted|all rights reserved/i;
440
476
  var ENUMERATED_ITEM_RE = /^(?:\d+[.):]|[-*•])\s+\S/;
441
477
  var ENUMERATED_ITEM_MIN_WORDS = 3;
@@ -501,7 +537,8 @@ function isSectionLabel(text) {
501
537
  }
502
538
  var HELPER_OPENER_RE = /^(?:a\s+)?helper\s+(?:function|method|component|hook|class|type|util(?:ity)?)\b/i;
503
539
  var LETS_RE = /^let'?s\s+(?:not\s+|just\s+|now\s+|first\s+)?(?:add|append|assign|await|build|calculate|call|check|clear|close|compute|convert|copy|count|create|declare|decrement|define|delete|extract|fetch|filter|find|format|generate|get|handle|increment|init|initialise|initialize|insert|iterate|join|load|log|loop|map|merge|open|parse|print|process|push|read|remove|render|reset|return|save|send|set|setup|sort|split|start|stop|store|update|validate|wrap|write)(?:s|es|ed|ing)?\b/i;
504
- var ENUMERATION_RE = /^(?:\d+[.)]\s+\S|phase\s+\d+\b)/i;
540
+ var ENUMERATION_RE = /^(?:\d+[.)]\s+\S|(?:phase|step)\s+\d+\b)/i;
541
+ var DUMMY_TRANSLATION_RE = /^(?:increment|return|returns|get|gets|set\b(?! up\b)|sets\b(?! up\b)|function to|method to)\b/i;
505
542
  var DIAGRAM_ARROW_RE = /[-=~]{2,}>|<[-=~]{2,}/;
506
543
  var CODE_KEYWORD_RE = /^(import |export |const |let |var |function\b|class |interface |type \w|enum |return\b|throw |await |async |if\s*\(|for\s*\(|while\s*\(|switch\s*\(|new |console\.)/;
507
544
  var CODE_TAIL_RE = /[;{}()]\s*$|=>\s*$|,\s*$/;
@@ -549,6 +586,14 @@ function isRedundantNarration(body, statementBelow, standalone, isolatedEnumerat
549
586
  if (STEP_NARRATION_RE.test(t)) return true;
550
587
  if (META_COMMENTARY_RE.test(t) && !JUSTIFICATION_RE.test(t)) return true;
551
588
  if (HELPER_OPENER_RE.test(t) || LETS_RE.test(t)) return true;
589
+ const words = t.split(/\s+/);
590
+ if (words.length <= 4 && DUMMY_TRANSLATION_RE.test(t) && !/[():=]/.test(t)) {
591
+ const lowerT = t.toLowerCase();
592
+ const rationaleWords = ["when", "because", "if", "so that", "due to", "for", "instead of", "to prevent", "to avoid", "only"];
593
+ if (!rationaleWords.some((w) => lowerT.includes(w))) {
594
+ if (words.length > 1) return true;
595
+ }
596
+ }
552
597
  if (!nested && isSectionLabel(t)) return true;
553
598
  if (isolatedEnumeration && ENUMERATION_RE.test(t)) return true;
554
599
  }
@@ -602,7 +647,7 @@ function hasCommentedOutCode(texts, precedingProse) {
602
647
  }
603
648
  return false;
604
649
  }
605
- var no_comment_cruft_default = ESLintUtils3.RuleCreator(
650
+ var no_comment_cruft_default = ESLintUtils4.RuleCreator(
606
651
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
607
652
  )({
608
653
  name: "no-comment-cruft",
@@ -616,7 +661,8 @@ var no_comment_cruft_default = ESLintUtils3.RuleCreator(
616
661
  commentedOutCode: "Commented-out code \u2014 delete it; git history remembers.",
617
662
  sectionBanner: "Section-banner / region comment \u2014 structure code with functions, not ASCII rules.",
618
663
  fileHeaderPreamble: "File-header comment preamble \u2014 use a brief doc comment for the why, not a block of `//` lines.",
619
- redundantNarration: "Comment narrates the code \u2014 delete it or say *why*, not *what*. Code is self-documenting."
664
+ redundantNarration: "Comment narrates the code \u2014 delete it or say *why*, not *what*. Code is self-documenting.",
665
+ untrackedTodo: "Untracked TODO/FIXME marker \u2014 add an issue ticket or context link."
620
666
  }
621
667
  },
622
668
  defaultOptions: [],
@@ -670,6 +716,16 @@ var no_comment_cruft_default = ESLintUtils3.RuleCreator(
670
716
  if (isJsDoc(comment) || !isStandalone(comment)) continue;
671
717
  if (LICENSE_RE.test(comment.value)) continue;
672
718
  const texts = comment.value.split("\n").map(stripCommentMarker).filter((l) => l.length > 0 && !isDirective(l));
719
+ const firstText = texts[0];
720
+ if (firstText !== void 0 && /^(?:todo|fixme)\b/i.test(firstText)) {
721
+ if (!runCitesAReference(comments, i)) {
722
+ context.report({
723
+ node: comment,
724
+ messageId: "untrackedTodo"
725
+ });
726
+ }
727
+ continue;
728
+ }
673
729
  if (texts.some(isBanner)) {
674
730
  context.report({ node: comment, messageId: "sectionBanner" });
675
731
  continue;
@@ -698,7 +754,7 @@ var no_comment_cruft_default = ESLintUtils3.RuleCreator(
698
754
  });
699
755
 
700
756
  // src/rules/no-enum.ts
701
- import { ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
757
+ import { ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
702
758
  var DEFAULT_IGNORE_PATTERNS = [
703
759
  /[\\/]generated[\\/]/,
704
760
  /[\\/]openapi-gen[\\/]/,
@@ -718,7 +774,7 @@ function hasGeneratedMarker(sourceText) {
718
774
  const head = sourceText.slice(0, 1024);
719
775
  return /@generated\b/.test(head);
720
776
  }
721
- var no_enum_default = ESLintUtils4.RuleCreator(
777
+ var no_enum_default = ESLintUtils5.RuleCreator(
722
778
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
723
779
  )({
724
780
  name: "no-enum",
@@ -769,7 +825,7 @@ var no_enum_default = ESLintUtils4.RuleCreator(
769
825
  });
770
826
 
771
827
  // src/rules/no-insecure-random-id.ts
772
- import { ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
828
+ import { ESLintUtils as ESLintUtils6 } from "@typescript-eslint/utils";
773
829
  var STRONG_SECURITY_PATTERN = /token|secret|csrf|password|passwd|apikey|api[-_]?key|nonce|salt|uuid|authid/i;
774
830
  var NON_SECURITY_ID_PATTERN = /temp|tmp|cache|correlation|request|req|trace|execution|dev|hmr|mock|test|perf|marker/i;
775
831
  var PATH_OR_DOM_MARKER = /[\\/#]|\.[A-Za-z0-9]/;
@@ -910,7 +966,7 @@ function isConcatenatedIntoPathOrDomId(node) {
910
966
  collectStaticStringParts(top, parts);
911
967
  return parts.some((part) => PATH_OR_DOM_MARKER.test(part));
912
968
  }
913
- var no_insecure_random_id_default = ESLintUtils5.RuleCreator(
969
+ var no_insecure_random_id_default = ESLintUtils6.RuleCreator(
914
970
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
915
971
  )({
916
972
  name: "no-insecure-random-id",
@@ -954,7 +1010,7 @@ var no_insecure_random_id_default = ESLintUtils5.RuleCreator(
954
1010
  });
955
1011
 
956
1012
  // src/rules/no-json-stringify-error.ts
957
- import { ESLintUtils as ESLintUtils6 } from "@typescript-eslint/utils";
1013
+ import { ESLintUtils as ESLintUtils7 } from "@typescript-eslint/utils";
958
1014
  var ERROR_NAME_PATTERN = /^(e|err|error|ex|exc)$/i;
959
1015
  var ERROR_PROP_PATTERN = /^(cause|lastError|error|err|exception|originalError|innerError)$/i;
960
1016
  var SAFE_STRING_PROPS = /* @__PURE__ */ new Set(["message", "stack", "name"]);
@@ -1088,7 +1144,7 @@ function isGuardedByInstanceofError(node, argExpr, sourceCode) {
1088
1144
  function isJsonStringify(callee) {
1089
1145
  return callee.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "JSON" && callee.property.type === "Identifier" && callee.property.name === "stringify";
1090
1146
  }
1091
- var no_json_stringify_error_default = ESLintUtils6.RuleCreator(
1147
+ var no_json_stringify_error_default = ESLintUtils7.RuleCreator(
1092
1148
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1093
1149
  )({
1094
1150
  name: "no-json-stringify-error",
@@ -1138,7 +1194,7 @@ var no_json_stringify_error_default = ESLintUtils6.RuleCreator(
1138
1194
  });
1139
1195
 
1140
1196
  // src/rules/no-log-only-catch.ts
1141
- import { ESLintUtils as ESLintUtils7 } from "@typescript-eslint/utils";
1197
+ import { ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
1142
1198
 
1143
1199
  // src/rules/_logging.ts
1144
1200
  import "@typescript-eslint/utils";
@@ -1248,7 +1304,7 @@ var DEFAULT_IGNORE_PATTERNS2 = [
1248
1304
  /\.spec\./,
1249
1305
  /[\\/]__tests__[\\/]/
1250
1306
  ];
1251
- var no_log_only_catch_default = ESLintUtils7.RuleCreator(
1307
+ var no_log_only_catch_default = ESLintUtils8.RuleCreator(
1252
1308
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1253
1309
  )({
1254
1310
  name: "no-log-only-catch",
@@ -1311,7 +1367,7 @@ var no_log_only_catch_default = ESLintUtils7.RuleCreator(
1311
1367
  });
1312
1368
 
1313
1369
  // src/rules/no-raw-env.ts
1314
- import { ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
1370
+ import { ESLintUtils as ESLintUtils9 } from "@typescript-eslint/utils";
1315
1371
  var CONFIG_FILE_RE = /(^|[\\/])[\w.-]+\.config\.[cm]?[jt]sx?$/;
1316
1372
  var ENV_BOUNDARY_FILE_RE = /(^|[\\/])(?:env|client-env|server-env|client-settings|server-settings)\.[cm]?[jt]sx?$/;
1317
1373
  function isValidatedEnvBoundary(filename, sourceText) {
@@ -1349,7 +1405,7 @@ function isWholeEnvSpread(node) {
1349
1405
  const parent = node.parent;
1350
1406
  return parent.type === "SpreadElement" && parent.argument === node;
1351
1407
  }
1352
- var no_raw_env_default = ESLintUtils8.RuleCreator(
1408
+ var no_raw_env_default = ESLintUtils9.RuleCreator(
1353
1409
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1354
1410
  )({
1355
1411
  name: "no-raw-env",
@@ -1384,7 +1440,7 @@ var no_raw_env_default = ESLintUtils8.RuleCreator(
1384
1440
 
1385
1441
  // src/rules/no-sentinel-return-on-catch.ts
1386
1442
  import {
1387
- ESLintUtils as ESLintUtils9,
1443
+ ESLintUtils as ESLintUtils10,
1388
1444
  AST_NODE_TYPES as AST_NODE_TYPES5
1389
1445
  } from "@typescript-eslint/utils";
1390
1446
  function sentinelKind(arg) {
@@ -1689,7 +1745,7 @@ function isWithin(node, ancestor) {
1689
1745
  }
1690
1746
  return false;
1691
1747
  }
1692
- var no_sentinel_return_on_catch_default = ESLintUtils9.RuleCreator(
1748
+ var no_sentinel_return_on_catch_default = ESLintUtils10.RuleCreator(
1693
1749
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1694
1750
  )({
1695
1751
  name: "no-sentinel-return-on-catch",
@@ -1770,7 +1826,7 @@ var no_sentinel_return_on_catch_default = ESLintUtils9.RuleCreator(
1770
1826
  });
1771
1827
 
1772
1828
  // src/rules/no-sequential-await.ts
1773
- import { ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
1829
+ import { ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
1774
1830
  var ARRAY_ITERATION_METHODS = /* @__PURE__ */ new Set(["forEach", "map", "filter"]);
1775
1831
  var SEQUENTIAL_ITERABLE_HINT = /sort|reverse|ordered|sequence|hook|middleware|pipeline|preset|plugin|extension|\bstage|\bstep|\bphase|migration|chain|buffer|stream|teleport|chunk|\bqueue|drain/i;
1776
1832
  var BENCH_FILE_RE = /(^|[\\/])bench(marks?)?[\\/]|\.bench\.[cm]?[jt]sx?$/i;
@@ -1924,7 +1980,7 @@ function shouldReport(awaits, earlyExit, iterableText, asserts = false) {
1924
1980
  (node) => !isTimerYield(node) && !isThreadedAccumulator(node) && !isQueueDrain(node)
1925
1981
  );
1926
1982
  }
1927
- var no_sequential_await_default = ESLintUtils10.RuleCreator(
1983
+ var no_sequential_await_default = ESLintUtils11.RuleCreator(
1928
1984
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1929
1985
  )({
1930
1986
  name: "no-sequential-await",
@@ -2019,7 +2075,7 @@ var no_sequential_await_default = ESLintUtils10.RuleCreator(
2019
2075
  });
2020
2076
 
2021
2077
  // src/rules/no-string-concat-in-loop.ts
2022
- import { ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
2078
+ import { ESLintUtils as ESLintUtils12 } from "@typescript-eslint/utils";
2023
2079
  var LOOP_NODE_TYPES = /* @__PURE__ */ new Set([
2024
2080
  "ForStatement",
2025
2081
  "ForOfStatement",
@@ -2104,7 +2160,7 @@ function enclosingLoop(node) {
2104
2160
  }
2105
2161
  return null;
2106
2162
  }
2107
- var no_string_concat_in_loop_default = ESLintUtils11.RuleCreator(
2163
+ var no_string_concat_in_loop_default = ESLintUtils12.RuleCreator(
2108
2164
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
2109
2165
  )({
2110
2166
  name: "no-string-concat-in-loop",
@@ -2169,7 +2225,7 @@ var no_string_concat_in_loop_default = ESLintUtils11.RuleCreator(
2169
2225
  // src/rules/no-unnecessary-use-client.ts
2170
2226
  import {
2171
2227
  AST_NODE_TYPES as AST_NODE_TYPES6,
2172
- ESLintUtils as ESLintUtils12
2228
+ ESLintUtils as ESLintUtils13
2173
2229
  } from "@typescript-eslint/utils";
2174
2230
  var HOOK_REGEX = /^use([A-Z]|$)/;
2175
2231
  var EVENT_PROP_REGEX = /^on[A-Z]/;
@@ -2243,7 +2299,7 @@ var isGlobalReference = (node, context) => {
2243
2299
  }
2244
2300
  return true;
2245
2301
  };
2246
- var no_unnecessary_use_client_default = ESLintUtils12.RuleCreator(
2302
+ var no_unnecessary_use_client_default = ESLintUtils13.RuleCreator(
2247
2303
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
2248
2304
  )({
2249
2305
  name: "no-unnecessary-use-client",
@@ -2364,7 +2420,7 @@ var no_unnecessary_use_client_default = ESLintUtils12.RuleCreator(
2364
2420
  });
2365
2421
 
2366
2422
  // src/rules/prefer-discriminated-union.ts
2367
- import { ESLintUtils as ESLintUtils13 } from "@typescript-eslint/utils";
2423
+ import { ESLintUtils as ESLintUtils14 } from "@typescript-eslint/utils";
2368
2424
  import { AST_NODE_TYPES as AST_NODE_TYPES7 } from "@typescript-eslint/utils";
2369
2425
  var STATUS_MEMBER_NAMES = /* @__PURE__ */ new Set([
2370
2426
  "success",
@@ -2411,7 +2467,7 @@ function looksLikeMutuallyExclusiveState(typeLiteral) {
2411
2467
  }
2412
2468
  return hasStatusBoolean && optionalCount >= MIN_OPTIONAL_MEMBERS && optionalPayloadCount >= 1;
2413
2469
  }
2414
- var prefer_discriminated_union_default = ESLintUtils13.RuleCreator(
2470
+ var prefer_discriminated_union_default = ESLintUtils14.RuleCreator(
2415
2471
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
2416
2472
  )({
2417
2473
  name: "prefer-discriminated-union",
@@ -2454,7 +2510,7 @@ var prefer_discriminated_union_default = ESLintUtils13.RuleCreator(
2454
2510
  // src/rules/prefer-schema-for-api-payload.ts
2455
2511
  import {
2456
2512
  AST_NODE_TYPES as AST_NODE_TYPES8,
2457
- ESLintUtils as ESLintUtils14
2513
+ ESLintUtils as ESLintUtils15
2458
2514
  } from "@typescript-eslint/utils";
2459
2515
  var unwrap = (node) => {
2460
2516
  let current = node;
@@ -2577,7 +2633,7 @@ var isUnvalidatedVariableRef = (node, scope, tracked) => {
2577
2633
  const variable = findVariable2(scope, unwrapped.name);
2578
2634
  return variable !== null && tracked.has(variable);
2579
2635
  };
2580
- var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2636
+ var prefer_schema_for_api_payload_default = ESLintUtils15.RuleCreator(
2581
2637
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
2582
2638
  )({
2583
2639
  name: "prefer-schema-for-api-payload",
@@ -2691,7 +2747,7 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2691
2747
  });
2692
2748
 
2693
2749
  // src/rules/prefer-semantic-colors.ts
2694
- import { AST_NODE_TYPES as AST_NODE_TYPES9, ESLintUtils as ESLintUtils15 } from "@typescript-eslint/utils";
2750
+ import { AST_NODE_TYPES as AST_NODE_TYPES9, ESLintUtils as ESLintUtils16 } from "@typescript-eslint/utils";
2695
2751
  import { existsSync, readFileSync } from "fs";
2696
2752
  import { dirname, join, parse } from "path";
2697
2753
 
@@ -2828,7 +2884,7 @@ var propName = (key) => {
2828
2884
  if (key.type === AST_NODE_TYPES9.Literal && typeof key.value === "string") return key.value;
2829
2885
  return null;
2830
2886
  };
2831
- var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2887
+ var prefer_semantic_colors_default = ESLintUtils16.RuleCreator(
2832
2888
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
2833
2889
  )({
2834
2890
  name: "prefer-semantic-colors",
@@ -2950,7 +3006,7 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2950
3006
  });
2951
3007
 
2952
3008
  // src/rules/prefer-server-actions.ts
2953
- import { ESLintUtils as ESLintUtils16 } from "@typescript-eslint/utils";
3009
+ import { ESLintUtils as ESLintUtils17 } from "@typescript-eslint/utils";
2954
3010
  var MUTATION_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "DELETE", "PATCH"]);
2955
3011
  var AXIOS_MUTATION_METHODS = /* @__PURE__ */ new Set(["post", "put", "delete", "patch"]);
2956
3012
  var SKIP_FILE_REGEX = /(?:\.test\.[jt]sx?$|\.spec\.[jt]sx?$|-(?:test|spec)\.[jt]sx?$|\/tests?\/|\/__tests__\/|\/__testfixtures__\/|\/scripts?\/|\/app\/api\/.*\/route\.[jt]sx?$|\/pages\/api\/)/;
@@ -3030,7 +3086,7 @@ function getPropertyNode(objNode, propName2) {
3030
3086
  }
3031
3087
  return null;
3032
3088
  }
3033
- var prefer_server_actions_default = ESLintUtils16.RuleCreator(
3089
+ var prefer_server_actions_default = ESLintUtils17.RuleCreator(
3034
3090
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3035
3091
  )({
3036
3092
  name: "prefer-server-actions",
@@ -3107,7 +3163,7 @@ var prefer_server_actions_default = ESLintUtils16.RuleCreator(
3107
3163
  // src/rules/prefer-shadcn.ts
3108
3164
  import {
3109
3165
  AST_NODE_TYPES as AST_NODE_TYPES10,
3110
- ESLintUtils as ESLintUtils17
3166
+ ESLintUtils as ESLintUtils18
3111
3167
  } from "@typescript-eslint/utils";
3112
3168
  var REPLACEMENTS = {
3113
3169
  select: "Select",
@@ -3143,7 +3199,7 @@ var resolveInputReplacement = (node) => {
3143
3199
  if (SKIPPED_INPUT_TYPES.has(typeAttr.value)) return null;
3144
3200
  return INPUT_TYPE_REPLACEMENTS[typeAttr.value] ?? "Input";
3145
3201
  };
3146
- var prefer_shadcn_default = ESLintUtils17.RuleCreator(
3202
+ var prefer_shadcn_default = ESLintUtils18.RuleCreator(
3147
3203
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3148
3204
  )({
3149
3205
  name: "prefer-shadcn",
@@ -3188,7 +3244,7 @@ var prefer_shadcn_default = ESLintUtils17.RuleCreator(
3188
3244
 
3189
3245
  // src/rules/require-assert-never.ts
3190
3246
  import {
3191
- ESLintUtils as ESLintUtils18,
3247
+ ESLintUtils as ESLintUtils19,
3192
3248
  AST_NODE_TYPES as AST_NODE_TYPES11
3193
3249
  } from "@typescript-eslint/utils";
3194
3250
  var isAssertNeverCall = (expression) => {
@@ -3240,7 +3296,7 @@ var isCommentOnlyNoopDefault = (defaultCase, sourceCode) => {
3240
3296
  }
3241
3297
  return false;
3242
3298
  };
3243
- var require_assert_never_default = ESLintUtils18.RuleCreator(
3299
+ var require_assert_never_default = ESLintUtils19.RuleCreator(
3244
3300
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3245
3301
  )({
3246
3302
  name: "require-assert-never",
@@ -3278,7 +3334,7 @@ var require_assert_never_default = ESLintUtils18.RuleCreator(
3278
3334
  });
3279
3335
 
3280
3336
  // src/rules/require-zod-form-validation.ts
3281
- import { ESLintUtils as ESLintUtils19, AST_NODE_TYPES as AST_NODE_TYPES12 } from "@typescript-eslint/utils";
3337
+ import { ESLintUtils as ESLintUtils20, AST_NODE_TYPES as AST_NODE_TYPES12 } from "@typescript-eslint/utils";
3282
3338
 
3283
3339
  // src/rules/_zod.ts
3284
3340
  var ZOD_PREFIX_RE = /^Z[A-Z]/;
@@ -3322,7 +3378,7 @@ var isFormDataMethodCall = (node) => {
3322
3378
  const callee = current.callee;
3323
3379
  return callee.type === AST_NODE_TYPES12.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES12.Identifier && callee.property.name === "formData";
3324
3380
  };
3325
- var require_zod_form_validation_default = ESLintUtils19.RuleCreator(
3381
+ var require_zod_form_validation_default = ESLintUtils20.RuleCreator(
3326
3382
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3327
3383
  )({
3328
3384
  name: "require-zod-form-validation",
@@ -3408,7 +3464,7 @@ var require_zod_form_validation_default = ESLintUtils19.RuleCreator(
3408
3464
  });
3409
3465
 
3410
3466
  // src/rules/zod-naming-convention.ts
3411
- import { ESLintUtils as ESLintUtils20, AST_NODE_TYPES as AST_NODE_TYPES13 } from "@typescript-eslint/utils";
3467
+ import { ESLintUtils as ESLintUtils21, AST_NODE_TYPES as AST_NODE_TYPES13 } from "@typescript-eslint/utils";
3412
3468
  var CONVENTIONS = {
3413
3469
  prefix: { test: ZOD_PREFIX_RE, messageId: "zPrefix" },
3414
3470
  suffix: { test: ZOD_SUFFIX_RE, messageId: "schemaSuffix" },
@@ -3448,7 +3504,7 @@ var calleeChainStartsWithZ = (node) => {
3448
3504
  }
3449
3505
  return false;
3450
3506
  };
3451
- var zod_naming_convention_default = ESLintUtils20.RuleCreator(
3507
+ var zod_naming_convention_default = ESLintUtils21.RuleCreator(
3452
3508
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3453
3509
  )({
3454
3510
  name: "zod-naming-convention",
@@ -3506,7 +3562,7 @@ var zod_naming_convention_default = ESLintUtils20.RuleCreator(
3506
3562
  });
3507
3563
 
3508
3564
  // src/rules/no-cors-wildcard-with-credentials.ts
3509
- import { ESLintUtils as ESLintUtils21 } from "@typescript-eslint/utils";
3565
+ import { ESLintUtils as ESLintUtils22 } from "@typescript-eslint/utils";
3510
3566
  var ACAO_HEADER = "access-control-allow-origin";
3511
3567
  var ACAC_HEADER = "access-control-allow-credentials";
3512
3568
  var HEADER_SET_METHODS = /* @__PURE__ */ new Set(["setheader", "set", "append"]);
@@ -3648,7 +3704,7 @@ function enclosingScope(node) {
3648
3704
  }
3649
3705
  return void 0;
3650
3706
  }
3651
- var no_cors_wildcard_with_credentials_default = ESLintUtils21.RuleCreator(
3707
+ var no_cors_wildcard_with_credentials_default = ESLintUtils22.RuleCreator(
3652
3708
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3653
3709
  )({
3654
3710
  name: "no-cors-wildcard-with-credentials",
@@ -3716,7 +3772,7 @@ var no_cors_wildcard_with_credentials_default = ESLintUtils21.RuleCreator(
3716
3772
  });
3717
3773
 
3718
3774
  // src/rules/no-silent-promise-catch.ts
3719
- import { AST_NODE_TYPES as AST_NODE_TYPES14, ESLintUtils as ESLintUtils22 } from "@typescript-eslint/utils";
3775
+ import { AST_NODE_TYPES as AST_NODE_TYPES14, ESLintUtils as ESLintUtils23 } from "@typescript-eslint/utils";
3720
3776
  function isBodyParseCall(node) {
3721
3777
  return node.type === AST_NODE_TYPES14.CallExpression && node.arguments.length === 0 && node.callee.type === AST_NODE_TYPES14.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES14.Identifier && (node.callee.property.name === "json" || node.callee.property.name === "text");
3722
3778
  }
@@ -3769,7 +3825,7 @@ function isSilentHandler(handler) {
3769
3825
  }
3770
3826
  return false;
3771
3827
  }
3772
- var no_silent_promise_catch_default = ESLintUtils22.RuleCreator(
3828
+ var no_silent_promise_catch_default = ESLintUtils23.RuleCreator(
3773
3829
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3774
3830
  )({
3775
3831
  name: "no-silent-promise-catch",
@@ -3840,7 +3896,7 @@ var no_silent_promise_catch_default = ESLintUtils22.RuleCreator(
3840
3896
  import {
3841
3897
  AST_NODE_TYPES as AST_NODE_TYPES15,
3842
3898
  ASTUtils,
3843
- ESLintUtils as ESLintUtils23
3899
+ ESLintUtils as ESLintUtils24
3844
3900
  } from "@typescript-eslint/utils";
3845
3901
  var CODEMOD_FIXTURE_RE = /[\\/]__testfixtures__[\\/]/;
3846
3902
  var GLOBAL_OBJECTS = /* @__PURE__ */ new Set([
@@ -3877,7 +3933,7 @@ function initProvablyLacksSignal(init) {
3877
3933
  function isStringish(node) {
3878
3934
  return node.type === AST_NODE_TYPES15.Literal && typeof node.value === "string" || node.type === AST_NODE_TYPES15.TemplateLiteral;
3879
3935
  }
3880
- var require_fetch_timeout_default = ESLintUtils23.RuleCreator(
3936
+ var require_fetch_timeout_default = ESLintUtils24.RuleCreator(
3881
3937
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3882
3938
  )({
3883
3939
  name: "require-fetch-timeout",
@@ -3941,7 +3997,7 @@ var require_fetch_timeout_default = ESLintUtils23.RuleCreator(
3941
3997
  });
3942
3998
 
3943
3999
  // src/rules/require-schema-validate-search.ts
3944
- import { AST_NODE_TYPES as AST_NODE_TYPES16, ESLintUtils as ESLintUtils24 } from "@typescript-eslint/utils";
4000
+ import { AST_NODE_TYPES as AST_NODE_TYPES16, ESLintUtils as ESLintUtils25 } from "@typescript-eslint/utils";
3945
4001
  var VALIDATOR_METHODS = /* @__PURE__ */ new Set([
3946
4002
  "parse",
3947
4003
  "safeParse",
@@ -3990,7 +4046,7 @@ function findCastExpression(node, insideValidatorArg) {
3990
4046
  }
3991
4047
  return null;
3992
4048
  }
3993
- var require_schema_validate_search_default = ESLintUtils24.RuleCreator(
4049
+ var require_schema_validate_search_default = ESLintUtils25.RuleCreator(
3994
4050
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3995
4051
  )({
3996
4052
  name: "require-schema-validate-search",
@@ -4029,7 +4085,7 @@ var require_schema_validate_search_default = ESLintUtils24.RuleCreator(
4029
4085
 
4030
4086
  // src/rules/no-fat-try-blocks.ts
4031
4087
  import {
4032
- ESLintUtils as ESLintUtils25,
4088
+ ESLintUtils as ESLintUtils26,
4033
4089
  AST_NODE_TYPES as AST_NODE_TYPES17
4034
4090
  } from "@typescript-eslint/utils";
4035
4091
  var MAX_TRY_BODY_STATEMENTS = 3;
@@ -4222,7 +4278,7 @@ function handlerRethrows(handler) {
4222
4278
  const last = body[body.length - 1];
4223
4279
  return last !== void 0 && last.type === AST_NODE_TYPES17.ThrowStatement;
4224
4280
  }
4225
- var no_fat_try_blocks_default = ESLintUtils25.RuleCreator(
4281
+ var no_fat_try_blocks_default = ESLintUtils26.RuleCreator(
4226
4282
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
4227
4283
  )({
4228
4284
  name: "no-fat-try-blocks",
@@ -4266,7 +4322,7 @@ var no_fat_try_blocks_default = ESLintUtils25.RuleCreator(
4266
4322
  });
4267
4323
 
4268
4324
  // src/rules/no-secret-in-log.ts
4269
- import { ESLintUtils as ESLintUtils26 } from "@typescript-eslint/utils";
4325
+ import { ESLintUtils as ESLintUtils27 } from "@typescript-eslint/utils";
4270
4326
 
4271
4327
  // src/rules/_secret_names.ts
4272
4328
  var SECRET_WORDS = /* @__PURE__ */ new Set([
@@ -4528,7 +4584,7 @@ function propertyKeyName2(prop) {
4528
4584
  }
4529
4585
  return null;
4530
4586
  }
4531
- var no_secret_in_log_default = ESLintUtils26.RuleCreator(
4587
+ var no_secret_in_log_default = ESLintUtils27.RuleCreator(
4532
4588
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
4533
4589
  )({
4534
4590
  name: "no-secret-in-log",
@@ -4605,7 +4661,7 @@ var no_secret_in_log_default = ESLintUtils26.RuleCreator(
4605
4661
  });
4606
4662
 
4607
4663
  // src/rules/no-unsafe-cast.ts
4608
- import { ESLintUtils as ESLintUtils27 } from "@typescript-eslint/utils";
4664
+ import { ESLintUtils as ESLintUtils28 } from "@typescript-eslint/utils";
4609
4665
  import { AST_NODE_TYPES as AST_NODE_TYPES18 } from "@typescript-eslint/utils";
4610
4666
  function isAnyAnnotation(node) {
4611
4667
  return node.type === AST_NODE_TYPES18.TSAnyKeyword;
@@ -4613,7 +4669,7 @@ function isAnyAnnotation(node) {
4613
4669
  function isConstAssertion(typeAnnotation) {
4614
4670
  return typeAnnotation.type === AST_NODE_TYPES18.TSTypeReference && typeAnnotation.typeName.type === AST_NODE_TYPES18.Identifier && typeAnnotation.typeName.name === "const";
4615
4671
  }
4616
- var no_unsafe_cast_default = ESLintUtils27.RuleCreator(
4672
+ var no_unsafe_cast_default = ESLintUtils28.RuleCreator(
4617
4673
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
4618
4674
  )({
4619
4675
  name: "no-unsafe-cast",
@@ -4653,10 +4709,59 @@ var no_unsafe_cast_default = ESLintUtils27.RuleCreator(
4653
4709
  }
4654
4710
  });
4655
4711
 
4712
+ // src/rules/no-unsafe-mock-casting.ts
4713
+ import { ESLintUtils as ESLintUtils29 } from "@typescript-eslint/utils";
4714
+ import { AST_NODE_TYPES as AST_NODE_TYPES19 } from "@typescript-eslint/utils";
4715
+ function isMockTypeReference(node) {
4716
+ if (node.type !== AST_NODE_TYPES19.TSTypeReference) {
4717
+ return false;
4718
+ }
4719
+ const typeName = node.typeName;
4720
+ if (typeName.type === AST_NODE_TYPES19.Identifier) {
4721
+ const name = typeName.name;
4722
+ return name === "Mock" || name === "MockInstance" || name === "SpyInstance";
4723
+ }
4724
+ if (typeName.type === AST_NODE_TYPES19.TSQualifiedName) {
4725
+ const rightName = typeName.right.name;
4726
+ return rightName === "Mock" || rightName === "MockInstance" || rightName === "SpyInstance";
4727
+ }
4728
+ return false;
4729
+ }
4730
+ var no_unsafe_mock_casting_default = ESLintUtils29.RuleCreator(
4731
+ (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
4732
+ )({
4733
+ name: "no-unsafe-mock-casting",
4734
+ meta: {
4735
+ type: "problem",
4736
+ docs: {
4737
+ description: "Disallow casting to mock types like `jest.Mock` or `vi.Mock`. Use `vi.mocked()` or `jest.mocked()` instead."
4738
+ },
4739
+ schema: [],
4740
+ messages: {
4741
+ unsafeMockCast: "Do not cast to a Mock type. Use `vi.mocked(fn)` or `jest.mocked(fn)` instead to preserve type safety."
4742
+ }
4743
+ },
4744
+ defaultOptions: [],
4745
+ create(context) {
4746
+ if (isGeneratedFile(context.filename, context.sourceCode.text)) {
4747
+ return {};
4748
+ }
4749
+ function checkAssertion(node) {
4750
+ if (isMockTypeReference(node.typeAnnotation)) {
4751
+ context.report({ node, messageId: "unsafeMockCast" });
4752
+ }
4753
+ }
4754
+ return {
4755
+ TSAsExpression: checkAssertion,
4756
+ TSTypeAssertion: checkAssertion
4757
+ };
4758
+ }
4759
+ });
4760
+
4656
4761
  // src/rules/prefer-string-literal-union.ts
4657
4762
  import {
4658
- ESLintUtils as ESLintUtils28,
4659
- AST_NODE_TYPES as AST_NODE_TYPES19
4763
+ ESLintUtils as ESLintUtils30,
4764
+ AST_NODE_TYPES as AST_NODE_TYPES20
4660
4765
  } from "@typescript-eslint/utils";
4661
4766
  import * as ts from "typescript";
4662
4767
  var CHOICE_TOKENS = /* @__PURE__ */ new Set([
@@ -4700,19 +4805,19 @@ function isChoiceLikeName(name) {
4700
4805
  return CHOICE_TOKENS.has(lastWord(name));
4701
4806
  }
4702
4807
  function keyName(key) {
4703
- if (key.type === AST_NODE_TYPES19.Identifier) {
4808
+ if (key.type === AST_NODE_TYPES20.Identifier) {
4704
4809
  return key.name;
4705
4810
  }
4706
- if (key.type === AST_NODE_TYPES19.Literal && typeof key.value === "string") {
4811
+ if (key.type === AST_NODE_TYPES20.Literal && typeof key.value === "string") {
4707
4812
  return key.value;
4708
4813
  }
4709
4814
  return null;
4710
4815
  }
4711
4816
  function isStringLiteralMember(t) {
4712
- return t.type === AST_NODE_TYPES19.TSLiteralType && t.literal.type === AST_NODE_TYPES19.Literal && typeof t.literal.value === "string";
4817
+ return t.type === AST_NODE_TYPES20.TSLiteralType && t.literal.type === AST_NODE_TYPES20.Literal && typeof t.literal.value === "string";
4713
4818
  }
4714
4819
  function isStringLiteralUnion(node) {
4715
- if (node?.type !== AST_NODE_TYPES19.TSUnionType) {
4820
+ if (node?.type !== AST_NODE_TYPES20.TSUnionType) {
4716
4821
  return false;
4717
4822
  }
4718
4823
  return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;
@@ -4741,12 +4846,12 @@ function bindingSourceExpression(decl) {
4741
4846
  return ts.isForOfStatement(node) ? node.expression : node.initializer;
4742
4847
  }
4743
4848
  function refKey(node) {
4744
- if (node.type === AST_NODE_TYPES19.Identifier) {
4849
+ if (node.type === AST_NODE_TYPES20.Identifier) {
4745
4850
  return node.name;
4746
4851
  }
4747
- if (node.type === AST_NODE_TYPES19.MemberExpression && !node.computed) {
4852
+ if (node.type === AST_NODE_TYPES20.MemberExpression && !node.computed) {
4748
4853
  const inner = refKey(node.object);
4749
- if (inner === null || node.property.type !== AST_NODE_TYPES19.Identifier) {
4854
+ if (inner === null || node.property.type !== AST_NODE_TYPES20.Identifier) {
4750
4855
  return null;
4751
4856
  }
4752
4857
  return `${inner}.${node.property.name}`;
@@ -4754,12 +4859,12 @@ function refKey(node) {
4754
4859
  return null;
4755
4860
  }
4756
4861
  function strLiteral(node) {
4757
- if (node.type === AST_NODE_TYPES19.Literal && typeof node.value === "string") {
4862
+ if (node.type === AST_NODE_TYPES20.Literal && typeof node.value === "string") {
4758
4863
  return node.value;
4759
4864
  }
4760
4865
  return null;
4761
4866
  }
4762
- var prefer_string_literal_union_default = ESLintUtils28.RuleCreator(
4867
+ var prefer_string_literal_union_default = ESLintUtils30.RuleCreator(
4763
4868
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
4764
4869
  )({
4765
4870
  name: "prefer-string-literal-union",
@@ -4797,7 +4902,7 @@ var prefer_string_literal_union_default = ESLintUtils28.RuleCreator(
4797
4902
  );
4798
4903
  let services;
4799
4904
  try {
4800
- services = ESLintUtils28.getParserServices(context);
4905
+ services = ESLintUtils30.getParserServices(context);
4801
4906
  } catch {
4802
4907
  services = null;
4803
4908
  }
@@ -4909,7 +5014,7 @@ var prefer_string_literal_union_default = ESLintUtils28.RuleCreator(
4909
5014
  containersWithUnion.add(container);
4910
5015
  return;
4911
5016
  }
4912
- if (typeNode?.type !== AST_NODE_TYPES19.TSStringKeyword) {
5017
+ if (typeNode?.type !== AST_NODE_TYPES20.TSStringKeyword) {
4913
5018
  return;
4914
5019
  }
4915
5020
  const name = keyName(key);
@@ -4997,10 +5102,10 @@ var prefer_string_literal_union_default = ESLintUtils28.RuleCreator(
4997
5102
  }
4998
5103
  };
4999
5104
  function refKeyText(node) {
5000
- if (node.type === AST_NODE_TYPES19.BinaryExpression) {
5105
+ if (node.type === AST_NODE_TYPES20.BinaryExpression) {
5001
5106
  return refKey(node.left) ?? refKey(node.right) ?? "value";
5002
5107
  }
5003
- if (node.type === AST_NODE_TYPES19.SwitchStatement) {
5108
+ if (node.type === AST_NODE_TYPES20.SwitchStatement) {
5004
5109
  return refKey(node.discriminant) ?? "value";
5005
5110
  }
5006
5111
  return "value";
@@ -5008,8 +5113,101 @@ var prefer_string_literal_union_default = ESLintUtils28.RuleCreator(
5008
5113
  }
5009
5114
  });
5010
5115
 
5116
+ // src/rules/prefer-zod-enum.ts
5117
+ import {
5118
+ AST_NODE_TYPES as AST_NODE_TYPES21,
5119
+ ESLintUtils as ESLintUtils31
5120
+ } from "@typescript-eslint/utils";
5121
+ function isZodModule(source) {
5122
+ return /(^|[/@-])zod([/-]|$)/.test(source);
5123
+ }
5124
+ var prefer_zod_enum_default = ESLintUtils31.RuleCreator(
5125
+ (name) => `https://github.com/sarj-ai/standards/tree/main/packages/typescript#${name}`
5126
+ )({
5127
+ name: "prefer-zod-enum",
5128
+ meta: {
5129
+ type: "suggestion",
5130
+ docs: {
5131
+ description: "Prefer z.enum([...]) over z.union([z.literal(...), ...]) for string choices"
5132
+ },
5133
+ fixable: "code",
5134
+ schema: [],
5135
+ messages: {
5136
+ preferEnum: "Use `z.enum([...])` instead of a union of string-literal schemas."
5137
+ }
5138
+ },
5139
+ defaultOptions: [],
5140
+ create(context) {
5141
+ const sourceCode = context.sourceCode;
5142
+ const zodNamespaces = /* @__PURE__ */ new Set();
5143
+ function enumValues(node) {
5144
+ const callee = node.callee;
5145
+ if (callee.type !== AST_NODE_TYPES21.MemberExpression || callee.computed || callee.object.type !== AST_NODE_TYPES21.Identifier || !zodNamespaces.has(callee.object.name) || callee.property.type !== AST_NODE_TYPES21.Identifier || callee.property.name !== "union" || node.arguments.length !== 1) {
5146
+ return null;
5147
+ }
5148
+ const argument = node.arguments[0];
5149
+ if (argument === void 0 || argument.type !== AST_NODE_TYPES21.ArrayExpression || argument.elements.length === 0) {
5150
+ return null;
5151
+ }
5152
+ const values = [];
5153
+ for (const element of argument.elements) {
5154
+ if (element === null || element.type !== AST_NODE_TYPES21.CallExpression || element.arguments.length !== 1 || element.callee.type !== AST_NODE_TYPES21.MemberExpression || element.callee.computed || element.callee.object.type !== AST_NODE_TYPES21.Identifier || !zodNamespaces.has(element.callee.object.name) || element.callee.property.type !== AST_NODE_TYPES21.Identifier || element.callee.property.name !== "literal") {
5155
+ return null;
5156
+ }
5157
+ const value = element.arguments[0];
5158
+ if (value === void 0 || value.type !== AST_NODE_TYPES21.Literal || typeof value.value !== "string") {
5159
+ return null;
5160
+ }
5161
+ values.push(value);
5162
+ }
5163
+ return values;
5164
+ }
5165
+ function buildFix(node, values) {
5166
+ const argument = node.arguments[0];
5167
+ if (argument === void 0 || argument.type !== AST_NODE_TYPES21.ArrayExpression || sourceCode.getCommentsInside(argument).length > 0) {
5168
+ return void 0;
5169
+ }
5170
+ const callee = node.callee;
5171
+ if (callee.type !== AST_NODE_TYPES21.MemberExpression || callee.property.type !== AST_NODE_TYPES21.Identifier) {
5172
+ return void 0;
5173
+ }
5174
+ return (fixer) => [
5175
+ fixer.replaceText(callee.property, "enum"),
5176
+ fixer.replaceText(
5177
+ argument,
5178
+ `[${values.map((value) => sourceCode.getText(value)).join(", ")}]`
5179
+ )
5180
+ ];
5181
+ }
5182
+ return {
5183
+ ImportDeclaration(node) {
5184
+ if (!isZodModule(node.source.value)) {
5185
+ return;
5186
+ }
5187
+ for (const specifier of node.specifiers) {
5188
+ if (specifier.type === AST_NODE_TYPES21.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES21.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES21.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES21.Identifier && specifier.imported.name === "z") {
5189
+ zodNamespaces.add(specifier.local.name);
5190
+ }
5191
+ }
5192
+ },
5193
+ CallExpression(node) {
5194
+ const values = enumValues(node);
5195
+ if (values === null) {
5196
+ return;
5197
+ }
5198
+ const fix = buildFix(node, values);
5199
+ context.report({
5200
+ node,
5201
+ messageId: "preferEnum",
5202
+ ...fix === void 0 ? {} : { fix }
5203
+ });
5204
+ }
5205
+ };
5206
+ }
5207
+ });
5208
+
5011
5209
  // src/rules/single-public-export.ts
5012
- import { ESLintUtils as ESLintUtils29, AST_NODE_TYPES as AST_NODE_TYPES20 } from "@typescript-eslint/utils";
5210
+ import { ESLintUtils as ESLintUtils32, AST_NODE_TYPES as AST_NODE_TYPES22 } from "@typescript-eslint/utils";
5013
5211
  var JUNK_DRAWER_STEMS = /* @__PURE__ */ new Set([
5014
5212
  "util",
5015
5213
  "utils",
@@ -5043,12 +5241,12 @@ var kebabCase2 = (name) => {
5043
5241
  }
5044
5242
  return normalized.replace(CAMEL_BOUNDARY_RE, "-").toLowerCase();
5045
5243
  };
5046
- var isFunctionExpression = (node) => node !== null && (node.type === AST_NODE_TYPES20.ArrowFunctionExpression || node.type === AST_NODE_TYPES20.FunctionExpression);
5244
+ var isFunctionExpression = (node) => node !== null && (node.type === AST_NODE_TYPES22.ArrowFunctionExpression || node.type === AST_NODE_TYPES22.FunctionExpression);
5047
5245
  var functionConstName = (decl) => {
5048
5246
  if (decl.declarations.length !== 1) return null;
5049
5247
  const [declarator] = decl.declarations;
5050
5248
  if (declarator === void 0) return null;
5051
- if (declarator.id.type !== AST_NODE_TYPES20.Identifier) return null;
5249
+ if (declarator.id.type !== AST_NODE_TYPES22.Identifier) return null;
5052
5250
  if (!isFunctionExpression(declarator.init)) return null;
5053
5251
  return declarator.id.name;
5054
5252
  };
@@ -5062,20 +5260,20 @@ var summarizeExports = (body) => {
5062
5260
  };
5063
5261
  for (const statement of body) {
5064
5262
  switch (statement.type) {
5065
- case AST_NODE_TYPES20.ExportAllDeclaration:
5263
+ case AST_NODE_TYPES22.ExportAllDeclaration:
5066
5264
  hasReExport = true;
5067
5265
  break;
5068
- case AST_NODE_TYPES20.ExportDefaultDeclaration: {
5266
+ case AST_NODE_TYPES22.ExportDefaultDeclaration: {
5069
5267
  names += 1;
5070
5268
  const decl = statement.declaration;
5071
- if (decl.type === AST_NODE_TYPES20.FunctionDeclaration && decl.id !== null) {
5269
+ if (decl.type === AST_NODE_TYPES22.FunctionDeclaration && decl.id !== null) {
5072
5270
  candidate = { name: decl.id.name, node: statement };
5073
- } else if (decl.type === AST_NODE_TYPES20.ClassDeclaration && decl.id !== null) {
5271
+ } else if (decl.type === AST_NODE_TYPES22.ClassDeclaration && decl.id !== null) {
5074
5272
  candidate = { name: decl.id.name, node: statement };
5075
5273
  }
5076
5274
  break;
5077
5275
  }
5078
- case AST_NODE_TYPES20.ExportNamedDeclaration: {
5276
+ case AST_NODE_TYPES22.ExportNamedDeclaration: {
5079
5277
  if (statement.source !== null) {
5080
5278
  hasReExport = true;
5081
5279
  break;
@@ -5086,15 +5284,15 @@ var summarizeExports = (body) => {
5086
5284
  break;
5087
5285
  }
5088
5286
  switch (decl.type) {
5089
- case AST_NODE_TYPES20.FunctionDeclaration:
5287
+ case AST_NODE_TYPES22.FunctionDeclaration:
5090
5288
  if (decl.id !== null) addCandidate(decl.id.name, statement);
5091
5289
  else names += 1;
5092
5290
  break;
5093
- case AST_NODE_TYPES20.ClassDeclaration:
5291
+ case AST_NODE_TYPES22.ClassDeclaration:
5094
5292
  if (decl.id !== null) addCandidate(decl.id.name, statement);
5095
5293
  else names += 1;
5096
5294
  break;
5097
- case AST_NODE_TYPES20.VariableDeclaration: {
5295
+ case AST_NODE_TYPES22.VariableDeclaration: {
5098
5296
  const fnName = functionConstName(decl);
5099
5297
  if (fnName !== null && decl.declarations.length === 1) {
5100
5298
  addCandidate(fnName, statement);
@@ -5114,7 +5312,7 @@ var summarizeExports = (body) => {
5114
5312
  }
5115
5313
  return { names, hasReExport, candidate };
5116
5314
  };
5117
- var single_public_export_default = ESLintUtils29.RuleCreator(
5315
+ var single_public_export_default = ESLintUtils32.RuleCreator(
5118
5316
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5119
5317
  )({
5120
5318
  name: "single-public-export",
@@ -5155,10 +5353,10 @@ var single_public_export_default = ESLintUtils29.RuleCreator(
5155
5353
  });
5156
5354
 
5157
5355
  // src/rules/no-offset-pagination.ts
5158
- import { ESLintUtils as ESLintUtils30 } from "@typescript-eslint/utils";
5356
+ import { ESLintUtils as ESLintUtils33 } from "@typescript-eslint/utils";
5159
5357
 
5160
5358
  // src/rules/_sql.ts
5161
- import { AST_NODE_TYPES as AST_NODE_TYPES21 } from "@typescript-eslint/utils";
5359
+ import { AST_NODE_TYPES as AST_NODE_TYPES23 } from "@typescript-eslint/utils";
5162
5360
  function stripSqlNoise(text) {
5163
5361
  const out = [...text];
5164
5362
  const n = text.length;
@@ -5219,13 +5417,13 @@ function stripSqlNoise(text) {
5219
5417
  var SUBSTITUTION_MARKER = "?";
5220
5418
  function sqlTextOf(node) {
5221
5419
  switch (node.type) {
5222
- case AST_NODE_TYPES21.Literal:
5420
+ case AST_NODE_TYPES23.Literal:
5223
5421
  return typeof node.value === "string" ? node.value : null;
5224
- case AST_NODE_TYPES21.TemplateLiteral:
5422
+ case AST_NODE_TYPES23.TemplateLiteral:
5225
5423
  return node.quasis.map((q) => q.value.cooked ?? q.value.raw).join(SUBSTITUTION_MARKER);
5226
- case AST_NODE_TYPES21.TaggedTemplateExpression:
5424
+ case AST_NODE_TYPES23.TaggedTemplateExpression:
5227
5425
  return sqlTextOf(node.quasi);
5228
- case AST_NODE_TYPES21.BinaryExpression: {
5426
+ case AST_NODE_TYPES23.BinaryExpression: {
5229
5427
  if (node.operator !== "+") {
5230
5428
  return null;
5231
5429
  }
@@ -5233,7 +5431,7 @@ function sqlTextOf(node) {
5233
5431
  const right = sqlTextOf(node.right);
5234
5432
  return left !== null && right !== null ? left + right : null;
5235
5433
  }
5236
- case AST_NODE_TYPES21.ArrayExpression: {
5434
+ case AST_NODE_TYPES23.ArrayExpression: {
5237
5435
  const parts = [];
5238
5436
  for (const element of node.elements) {
5239
5437
  if (element === null) {
@@ -5253,7 +5451,7 @@ function sqlTextOf(node) {
5253
5451
  }
5254
5452
  function isJoinedFragmentArray(node) {
5255
5453
  const parent = node.parent;
5256
- return parent?.type === AST_NODE_TYPES21.MemberExpression && parent.object === node && !parent.computed && parent.property.type === AST_NODE_TYPES21.Identifier && parent.property.name === "join" && parent.parent?.type === AST_NODE_TYPES21.CallExpression;
5454
+ return parent?.type === AST_NODE_TYPES23.MemberExpression && parent.object === node && !parent.computed && parent.property.type === AST_NODE_TYPES23.Identifier && parent.property.name === "join" && parent.parent?.type === AST_NODE_TYPES23.CallExpression;
5257
5455
  }
5258
5456
  function markConsumed(node, consumed) {
5259
5457
  consumed.add(node);
@@ -5303,7 +5501,7 @@ function createSqlListener(handler) {
5303
5501
  // src/rules/no-offset-pagination.ts
5304
5502
  var OFFSET_PAGINATION = /\bOFFSET\s+(?:%s|%\(\w+\)s|\?\d*|:\w+|@\w+|\$\d+|\d+)/i;
5305
5503
  var OFFSET_GATE = /offset/i;
5306
- var no_offset_pagination_default = ESLintUtils30.RuleCreator(
5504
+ var no_offset_pagination_default = ESLintUtils33.RuleCreator(
5307
5505
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5308
5506
  )({
5309
5507
  name: "no-offset-pagination",
@@ -5332,15 +5530,15 @@ var no_offset_pagination_default = ESLintUtils30.RuleCreator(
5332
5530
  });
5333
5531
 
5334
5532
  // src/rules/no-positional-tuple-return.ts
5335
- import { AST_NODE_TYPES as AST_NODE_TYPES22, ESLintUtils as ESLintUtils31 } from "@typescript-eslint/utils";
5533
+ import { AST_NODE_TYPES as AST_NODE_TYPES24, ESLintUtils as ESLintUtils34 } from "@typescript-eslint/utils";
5336
5534
  var MIN_ELEMENTS = 2;
5337
5535
  var ACCESSOR_PAIR_LENGTH = 2;
5338
5536
  var AWAITABLE_TYPES = /* @__PURE__ */ new Set(["Promise", "PromiseLike", "Awaited"]);
5339
5537
  function tupleReturnType(node) {
5340
- if (node.type === AST_NODE_TYPES22.TSTupleType) {
5538
+ if (node.type === AST_NODE_TYPES24.TSTupleType) {
5341
5539
  return node;
5342
5540
  }
5343
- if (node.type === AST_NODE_TYPES22.TSTypeReference && node.typeName.type === AST_NODE_TYPES22.Identifier && AWAITABLE_TYPES.has(node.typeName.name)) {
5541
+ if (node.type === AST_NODE_TYPES24.TSTypeReference && node.typeName.type === AST_NODE_TYPES24.Identifier && AWAITABLE_TYPES.has(node.typeName.name)) {
5344
5542
  const argument = node.typeArguments?.params[0];
5345
5543
  return argument === void 0 ? null : tupleReturnType(argument);
5346
5544
  }
@@ -5354,30 +5552,30 @@ function isPermittedTuple(tuple, sourceCode) {
5354
5552
  if (elements.length < MIN_ELEMENTS) {
5355
5553
  return true;
5356
5554
  }
5357
- if (elements.some((element) => element.type === AST_NODE_TYPES22.TSRestType)) {
5555
+ if (elements.some((element) => element.type === AST_NODE_TYPES24.TSRestType)) {
5358
5556
  return true;
5359
5557
  }
5360
- if (elements.some((element) => element.type === AST_NODE_TYPES22.TSNamedTupleMember)) {
5558
+ if (elements.some((element) => element.type === AST_NODE_TYPES24.TSNamedTupleMember)) {
5361
5559
  return true;
5362
5560
  }
5363
- if (elements[0]?.type === AST_NODE_TYPES22.TSLiteralType) {
5561
+ if (elements[0]?.type === AST_NODE_TYPES24.TSLiteralType) {
5364
5562
  return true;
5365
5563
  }
5366
- if (elements.length === ACCESSOR_PAIR_LENGTH && elements.some((element) => element.type === AST_NODE_TYPES22.TSFunctionType)) {
5564
+ if (elements.length === ACCESSOR_PAIR_LENGTH && elements.some((element) => element.type === AST_NODE_TYPES24.TSFunctionType)) {
5367
5565
  return true;
5368
5566
  }
5369
5567
  const texts = new Set(elements.map((element) => normalizedText(sourceCode, element)));
5370
5568
  return texts.size === 1;
5371
5569
  }
5372
5570
  function functionName(node) {
5373
- if (node.type === AST_NODE_TYPES22.FunctionDeclaration) {
5571
+ if (node.type === AST_NODE_TYPES24.FunctionDeclaration) {
5374
5572
  return node.id?.name ?? null;
5375
5573
  }
5376
5574
  const parent = node.parent;
5377
- if (parent?.type === AST_NODE_TYPES22.VariableDeclarator && parent.id.type === AST_NODE_TYPES22.Identifier) {
5575
+ if (parent?.type === AST_NODE_TYPES24.VariableDeclarator && parent.id.type === AST_NODE_TYPES24.Identifier) {
5378
5576
  return parent.id.name;
5379
5577
  }
5380
- if ((parent?.type === AST_NODE_TYPES22.MethodDefinition || parent?.type === AST_NODE_TYPES22.PropertyDefinition || parent?.type === AST_NODE_TYPES22.Property) && parent.key.type === AST_NODE_TYPES22.Identifier) {
5578
+ if ((parent?.type === AST_NODE_TYPES24.MethodDefinition || parent?.type === AST_NODE_TYPES24.PropertyDefinition || parent?.type === AST_NODE_TYPES24.Property) && parent.key.type === AST_NODE_TYPES24.Identifier) {
5381
5579
  return parent.key.name;
5382
5580
  }
5383
5581
  return null;
@@ -5385,7 +5583,7 @@ function functionName(node) {
5385
5583
  function isInlineExported(node) {
5386
5584
  for (let current = node; current != null; current = current.parent) {
5387
5585
  const parent = current.parent;
5388
- if (parent?.type === AST_NODE_TYPES22.ExportNamedDeclaration || parent?.type === AST_NODE_TYPES22.ExportDefaultDeclaration) {
5586
+ if (parent?.type === AST_NODE_TYPES24.ExportNamedDeclaration || parent?.type === AST_NODE_TYPES24.ExportDefaultDeclaration) {
5389
5587
  return true;
5390
5588
  }
5391
5589
  }
@@ -5394,18 +5592,18 @@ function isInlineExported(node) {
5394
5592
  function moduleScopeBindingName(node) {
5395
5593
  let current = node;
5396
5594
  let child = node;
5397
- while (current.parent != null && current.parent.type !== AST_NODE_TYPES22.Program) {
5595
+ while (current.parent != null && current.parent.type !== AST_NODE_TYPES24.Program) {
5398
5596
  child = current;
5399
5597
  current = current.parent;
5400
5598
  }
5401
- if (current.parent?.type !== AST_NODE_TYPES22.Program) {
5599
+ if (current.parent?.type !== AST_NODE_TYPES24.Program) {
5402
5600
  return null;
5403
5601
  }
5404
- if (current.type === AST_NODE_TYPES22.FunctionDeclaration || current.type === AST_NODE_TYPES22.ClassDeclaration) {
5602
+ if (current.type === AST_NODE_TYPES24.FunctionDeclaration || current.type === AST_NODE_TYPES24.ClassDeclaration) {
5405
5603
  return current.id?.name ?? null;
5406
5604
  }
5407
- if (current.type === AST_NODE_TYPES22.VariableDeclaration) {
5408
- if (child.type !== AST_NODE_TYPES22.VariableDeclarator || child.id.type !== AST_NODE_TYPES22.Identifier) {
5605
+ if (current.type === AST_NODE_TYPES24.VariableDeclaration) {
5606
+ if (child.type !== AST_NODE_TYPES24.VariableDeclarator || child.id.type !== AST_NODE_TYPES24.Identifier) {
5409
5607
  return null;
5410
5608
  }
5411
5609
  return child.id.name;
@@ -5415,19 +5613,19 @@ function moduleScopeBindingName(node) {
5415
5613
  function specifierExportedNames(program) {
5416
5614
  const names = /* @__PURE__ */ new Set();
5417
5615
  for (const statement of program.body) {
5418
- if (statement.type === AST_NODE_TYPES22.ExportNamedDeclaration && statement.declaration == null && statement.source == null && statement.exportKind !== "type") {
5616
+ if (statement.type === AST_NODE_TYPES24.ExportNamedDeclaration && statement.declaration == null && statement.source == null && statement.exportKind !== "type") {
5419
5617
  for (const specifier of statement.specifiers) {
5420
- if (specifier.exportKind !== "type" && specifier.local.type === AST_NODE_TYPES22.Identifier) {
5618
+ if (specifier.exportKind !== "type" && specifier.local.type === AST_NODE_TYPES24.Identifier) {
5421
5619
  names.add(specifier.local.name);
5422
5620
  }
5423
5621
  }
5424
5622
  continue;
5425
5623
  }
5426
- if (statement.type === AST_NODE_TYPES22.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES22.Identifier) {
5624
+ if (statement.type === AST_NODE_TYPES24.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES24.Identifier) {
5427
5625
  names.add(statement.declaration.name);
5428
5626
  continue;
5429
5627
  }
5430
- if (statement.type === AST_NODE_TYPES22.TSExportAssignment && statement.expression.type === AST_NODE_TYPES22.Identifier) {
5628
+ if (statement.type === AST_NODE_TYPES24.TSExportAssignment && statement.expression.type === AST_NODE_TYPES24.Identifier) {
5431
5629
  names.add(statement.expression.name);
5432
5630
  }
5433
5631
  }
@@ -5443,7 +5641,7 @@ function isExported(node, specifierExports) {
5443
5641
  const binding = moduleScopeBindingName(node);
5444
5642
  return binding !== null && specifierExports.has(binding);
5445
5643
  }
5446
- var no_positional_tuple_return_default = ESLintUtils31.RuleCreator(
5644
+ var no_positional_tuple_return_default = ESLintUtils34.RuleCreator(
5447
5645
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5448
5646
  )({
5449
5647
  name: "no-positional-tuple-return",
@@ -5491,16 +5689,16 @@ var no_positional_tuple_return_default = ESLintUtils31.RuleCreator(
5491
5689
  });
5492
5690
 
5493
5691
  // src/rules/no-repeated-string-literal.ts
5494
- import { AST_NODE_TYPES as AST_NODE_TYPES23, ESLintUtils as ESLintUtils32 } from "@typescript-eslint/utils";
5692
+ import { AST_NODE_TYPES as AST_NODE_TYPES25, ESLintUtils as ESLintUtils35 } from "@typescript-eslint/utils";
5495
5693
  var MIN_LENGTH = 40;
5496
5694
  var MIN_DISTINCT_SCOPES = 2;
5497
5695
  var PREVIEW_LENGTH = 40;
5498
5696
  var SQL_KEYWORD_RE = /\b(SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN|VALUES|ON CONFLICT|RETURNING|GROUP BY|ORDER BY)\b/;
5499
5697
  var IDENTIFIER_RE = /^[a-z_][a-z0-9_.]*$/;
5500
5698
  var FUNCTION_TYPES = /* @__PURE__ */ new Set([
5501
- AST_NODE_TYPES23.FunctionDeclaration,
5502
- AST_NODE_TYPES23.FunctionExpression,
5503
- AST_NODE_TYPES23.ArrowFunctionExpression
5699
+ AST_NODE_TYPES25.FunctionDeclaration,
5700
+ AST_NODE_TYPES25.FunctionExpression,
5701
+ AST_NODE_TYPES25.ArrowFunctionExpression
5504
5702
  ]);
5505
5703
  function isStructured(value) {
5506
5704
  return value.includes("\n") || SQL_KEYWORD_RE.test(value) || IDENTIFIER_RE.test(value);
@@ -5522,9 +5720,9 @@ function isScaffolding(node) {
5522
5720
  if (parent === void 0) {
5523
5721
  return true;
5524
5722
  }
5525
- return parent.type === AST_NODE_TYPES23.ImportDeclaration || parent.type === AST_NODE_TYPES23.ExportNamedDeclaration || parent.type === AST_NODE_TYPES23.ExportAllDeclaration || parent.type === AST_NODE_TYPES23.TSImportType || parent.type === AST_NODE_TYPES23.JSXAttribute || parent.type === AST_NODE_TYPES23.TSLiteralType;
5723
+ return parent.type === AST_NODE_TYPES25.ImportDeclaration || parent.type === AST_NODE_TYPES25.ExportNamedDeclaration || parent.type === AST_NODE_TYPES25.ExportAllDeclaration || parent.type === AST_NODE_TYPES25.TSImportType || parent.type === AST_NODE_TYPES25.JSXAttribute || parent.type === AST_NODE_TYPES25.TSLiteralType;
5526
5724
  }
5527
- var no_repeated_string_literal_default = ESLintUtils32.RuleCreator(
5725
+ var no_repeated_string_literal_default = ESLintUtils35.RuleCreator(
5528
5726
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5529
5727
  )({
5530
5728
  name: "no-repeated-string-literal",
@@ -5564,7 +5762,7 @@ var no_repeated_string_literal_default = ESLintUtils32.RuleCreator(
5564
5762
  }
5565
5763
  },
5566
5764
  TemplateLiteral(node) {
5567
- if (node.parent.type === AST_NODE_TYPES23.TaggedTemplateExpression) {
5765
+ if (node.parent.type === AST_NODE_TYPES25.TaggedTemplateExpression) {
5568
5766
  return;
5569
5767
  }
5570
5768
  const [only] = node.quasis;
@@ -5598,7 +5796,7 @@ var no_repeated_string_literal_default = ESLintUtils32.RuleCreator(
5598
5796
  });
5599
5797
 
5600
5798
  // src/rules/no-select-star.ts
5601
- import { ESLintUtils as ESLintUtils33 } from "@typescript-eslint/utils";
5799
+ import { ESLintUtils as ESLintUtils36 } from "@typescript-eslint/utils";
5602
5800
  var QUERY_SHAPE = /\bSELECT\b[\s\S]*?\bFROM\b/i;
5603
5801
  var SELECT_KEYWORD = /\bSELECT\b/gi;
5604
5802
  var FROM_KEYWORD = /^FROM\b/i;
@@ -5638,7 +5836,7 @@ function hasRealSelectStar(sql) {
5638
5836
  }
5639
5837
  return false;
5640
5838
  }
5641
- var no_select_star_default = ESLintUtils33.RuleCreator(
5839
+ var no_select_star_default = ESLintUtils36.RuleCreator(
5642
5840
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5643
5841
  )({
5644
5842
  name: "no-select-star",
@@ -5667,7 +5865,7 @@ var no_select_star_default = ESLintUtils33.RuleCreator(
5667
5865
  });
5668
5866
 
5669
5867
  // src/rules/no-sleep-in-test-body.ts
5670
- import { AST_NODE_TYPES as AST_NODE_TYPES24, ESLintUtils as ESLintUtils34 } from "@typescript-eslint/utils";
5868
+ import { AST_NODE_TYPES as AST_NODE_TYPES26, ESLintUtils as ESLintUtils37 } from "@typescript-eslint/utils";
5671
5869
  var SLEEP_HELPERS = /* @__PURE__ */ new Set(["sleep", "delay", "wait", "pause"]);
5672
5870
  var TEST_CALLERS = /* @__PURE__ */ new Set([
5673
5871
  "it",
@@ -5676,34 +5874,34 @@ var TEST_CALLERS = /* @__PURE__ */ new Set([
5676
5874
  "afterEach"
5677
5875
  ]);
5678
5876
  var FUNCTION_TYPES2 = /* @__PURE__ */ new Set([
5679
- AST_NODE_TYPES24.FunctionDeclaration,
5680
- AST_NODE_TYPES24.FunctionExpression,
5681
- AST_NODE_TYPES24.ArrowFunctionExpression
5877
+ AST_NODE_TYPES26.FunctionDeclaration,
5878
+ AST_NODE_TYPES26.FunctionExpression,
5879
+ AST_NODE_TYPES26.ArrowFunctionExpression
5682
5880
  ]);
5683
5881
  function isNonzeroNumericLiteral(node) {
5684
- return node?.type === AST_NODE_TYPES24.Literal && typeof node.value === "number" && node.value !== 0;
5882
+ return node?.type === AST_NODE_TYPES26.Literal && typeof node.value === "number" && node.value !== 0;
5685
5883
  }
5686
5884
  function isTimedSetTimeout(node) {
5687
- return node.type === AST_NODE_TYPES24.CallExpression && node.callee.type === AST_NODE_TYPES24.Identifier && node.callee.name === "setTimeout" && node.arguments.length >= 2 && isNonzeroNumericLiteral(node.arguments[1]);
5885
+ return node.type === AST_NODE_TYPES26.CallExpression && node.callee.type === AST_NODE_TYPES26.Identifier && node.callee.name === "setTimeout" && node.arguments.length >= 2 && isNonzeroNumericLiteral(node.arguments[1]);
5688
5886
  }
5689
5887
  function isPromiseSleep(node) {
5690
- if (node.callee.type !== AST_NODE_TYPES24.Identifier || node.callee.name !== "Promise") {
5888
+ if (node.callee.type !== AST_NODE_TYPES26.Identifier || node.callee.name !== "Promise") {
5691
5889
  return false;
5692
5890
  }
5693
5891
  const executor = node.arguments[0];
5694
- if (executor?.type !== AST_NODE_TYPES24.ArrowFunctionExpression && executor?.type !== AST_NODE_TYPES24.FunctionExpression) {
5892
+ if (executor?.type !== AST_NODE_TYPES26.ArrowFunctionExpression && executor?.type !== AST_NODE_TYPES26.FunctionExpression) {
5695
5893
  return false;
5696
5894
  }
5697
5895
  const body = executor.body;
5698
- if (body.type !== AST_NODE_TYPES24.BlockStatement) {
5896
+ if (body.type !== AST_NODE_TYPES26.BlockStatement) {
5699
5897
  return isTimedSetTimeout(body);
5700
5898
  }
5701
5899
  return body.body.some(
5702
- (stmt) => stmt.type === AST_NODE_TYPES24.ExpressionStatement && isTimedSetTimeout(stmt.expression)
5900
+ (stmt) => stmt.type === AST_NODE_TYPES26.ExpressionStatement && isTimedSetTimeout(stmt.expression)
5703
5901
  );
5704
5902
  }
5705
5903
  function isHelperSleep(node) {
5706
- return node.callee.type === AST_NODE_TYPES24.Identifier && SLEEP_HELPERS.has(node.callee.name) && node.arguments.length >= 1 && isNonzeroNumericLiteral(node.arguments[0]);
5904
+ return node.callee.type === AST_NODE_TYPES26.Identifier && SLEEP_HELPERS.has(node.callee.name) && node.arguments.length >= 1 && isNonzeroNumericLiteral(node.arguments[0]);
5707
5905
  }
5708
5906
  function nearestEnclosingFunction(node) {
5709
5907
  for (let current = node.parent; current != null; current = current.parent) {
@@ -5711,7 +5909,7 @@ function nearestEnclosingFunction(node) {
5711
5909
  continue;
5712
5910
  }
5713
5911
  const grandparent = current.parent;
5714
- const isPromiseExecutor = grandparent?.type === AST_NODE_TYPES24.NewExpression && isPromiseSleep(grandparent);
5912
+ const isPromiseExecutor = grandparent?.type === AST_NODE_TYPES26.NewExpression && isPromiseSleep(grandparent);
5715
5913
  if (!isPromiseExecutor) {
5716
5914
  return current;
5717
5915
  }
@@ -5719,29 +5917,29 @@ function nearestEnclosingFunction(node) {
5719
5917
  return null;
5720
5918
  }
5721
5919
  function testCallerName(callee) {
5722
- if (callee.type === AST_NODE_TYPES24.Identifier) {
5920
+ if (callee.type === AST_NODE_TYPES26.Identifier) {
5723
5921
  return callee.name;
5724
5922
  }
5725
- if (callee.type === AST_NODE_TYPES24.MemberExpression) {
5923
+ if (callee.type === AST_NODE_TYPES26.MemberExpression) {
5726
5924
  return testCallerName(callee.object);
5727
5925
  }
5728
- if (callee.type === AST_NODE_TYPES24.CallExpression) {
5926
+ if (callee.type === AST_NODE_TYPES26.CallExpression) {
5729
5927
  return testCallerName(callee.callee);
5730
5928
  }
5731
- if (callee.type === AST_NODE_TYPES24.TaggedTemplateExpression) {
5929
+ if (callee.type === AST_NODE_TYPES26.TaggedTemplateExpression) {
5732
5930
  return testCallerName(callee.tag);
5733
5931
  }
5734
5932
  return null;
5735
5933
  }
5736
5934
  function isTestBody(fn) {
5737
5935
  const call = fn.parent;
5738
- if (call?.type !== AST_NODE_TYPES24.CallExpression || !call.arguments.some((argument) => argument === fn)) {
5936
+ if (call?.type !== AST_NODE_TYPES26.CallExpression || !call.arguments.some((argument) => argument === fn)) {
5739
5937
  return false;
5740
5938
  }
5741
5939
  const name = testCallerName(call.callee);
5742
5940
  return name !== null && TEST_CALLERS.has(name);
5743
5941
  }
5744
- var no_sleep_in_test_body_default = ESLintUtils34.RuleCreator(
5942
+ var no_sleep_in_test_body_default = ESLintUtils37.RuleCreator(
5745
5943
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5746
5944
  )({
5747
5945
  name: "no-sleep-in-test-body",
@@ -5782,8 +5980,90 @@ var no_sleep_in_test_body_default = ESLintUtils34.RuleCreator(
5782
5980
  }
5783
5981
  });
5784
5982
 
5983
+ // src/rules/no-conditional-in-test.ts
5984
+ import { AST_NODE_TYPES as AST_NODE_TYPES27, ESLintUtils as ESLintUtils38 } from "@typescript-eslint/utils";
5985
+ var TEST_CALLERS2 = /* @__PURE__ */ new Set(["it", "test"]);
5986
+ var FUNCTION_TYPES3 = /* @__PURE__ */ new Set([
5987
+ AST_NODE_TYPES27.FunctionDeclaration,
5988
+ AST_NODE_TYPES27.FunctionExpression,
5989
+ AST_NODE_TYPES27.ArrowFunctionExpression
5990
+ ]);
5991
+ function nearestEnclosingFunction2(node) {
5992
+ for (let current = node.parent; current != null; current = current.parent) {
5993
+ if (FUNCTION_TYPES3.has(current.type)) {
5994
+ return current;
5995
+ }
5996
+ }
5997
+ return null;
5998
+ }
5999
+ function testCallerName2(callee) {
6000
+ if (callee.type === AST_NODE_TYPES27.Identifier) {
6001
+ return callee.name;
6002
+ }
6003
+ if (callee.type === AST_NODE_TYPES27.MemberExpression) {
6004
+ return testCallerName2(callee.object);
6005
+ }
6006
+ if (callee.type === AST_NODE_TYPES27.CallExpression) {
6007
+ return testCallerName2(callee.callee);
6008
+ }
6009
+ if (callee.type === AST_NODE_TYPES27.TaggedTemplateExpression) {
6010
+ return testCallerName2(callee.tag);
6011
+ }
6012
+ return null;
6013
+ }
6014
+ function isTestBody2(fn) {
6015
+ const call = fn.parent;
6016
+ if (call?.type !== AST_NODE_TYPES27.CallExpression || !call.arguments.some((argument) => argument === fn)) {
6017
+ return false;
6018
+ }
6019
+ const name = testCallerName2(call.callee);
6020
+ return name !== null && TEST_CALLERS2.has(name);
6021
+ }
6022
+ var no_conditional_in_test_default = ESLintUtils38.RuleCreator(
6023
+ (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
6024
+ )({
6025
+ name: "no-conditional-in-test",
6026
+ meta: {
6027
+ type: "problem",
6028
+ docs: {
6029
+ description: "Disallow conditional logic (if, switch, ternary) in test bodies, which can hide missing assertions or test multiple code paths."
6030
+ },
6031
+ schema: [],
6032
+ messages: {
6033
+ noConditionalInTest: "Avoid using conditional logic in tests. It can obscure intent and hide unexecuted assertions. Split the test instead."
6034
+ }
6035
+ },
6036
+ defaultOptions: [],
6037
+ create(context) {
6038
+ if (!isTestFile(context.filename)) {
6039
+ return {};
6040
+ }
6041
+ const report = (node) => {
6042
+ const enclosing = nearestEnclosingFunction2(node);
6043
+ if (enclosing === null || !isTestBody2(enclosing)) {
6044
+ return;
6045
+ }
6046
+ context.report({ node, messageId: "noConditionalInTest" });
6047
+ };
6048
+ return {
6049
+ IfStatement(node) {
6050
+ report(node);
6051
+ },
6052
+ SwitchStatement(node) {
6053
+ report(node);
6054
+ },
6055
+ ConditionalExpression(node) {
6056
+ report(node);
6057
+ },
6058
+ LogicalExpression(node) {
6059
+ report(node);
6060
+ }
6061
+ };
6062
+ }
6063
+ });
6064
+
5785
6065
  // src/rules/prefer-constant-time-secret-compare.ts
5786
- import { AST_NODE_TYPES as AST_NODE_TYPES25, ESLintUtils as ESLintUtils35 } from "@typescript-eslint/utils";
6066
+ import { AST_NODE_TYPES as AST_NODE_TYPES28, ESLintUtils as ESLintUtils39 } from "@typescript-eslint/utils";
5787
6067
  var EQUALITY_OPERATORS = /* @__PURE__ */ new Set(["===", "!==", "==", "!="]);
5788
6068
  var SENTINEL_IDENTIFIERS = /* @__PURE__ */ new Set(["undefined", "NaN"]);
5789
6069
  var SENTINEL_WORDS = /(^|_)(SENTINEL|EMPTY|NONE|NULL|UNSET|MISSING|PLACEHOLDER|DUMMY|FAKE|EXAMPLE)(_|$)/;
@@ -5796,36 +6076,36 @@ function isConstantReference(identifier) {
5796
6076
  }
5797
6077
  function isExcludedOperand(node) {
5798
6078
  switch (node.type) {
5799
- case AST_NODE_TYPES25.Literal:
6079
+ case AST_NODE_TYPES28.Literal:
5800
6080
  return true;
5801
- case AST_NODE_TYPES25.TemplateLiteral:
6081
+ case AST_NODE_TYPES28.TemplateLiteral:
5802
6082
  return node.expressions.length === 0;
5803
- case AST_NODE_TYPES25.Identifier:
6083
+ case AST_NODE_TYPES28.Identifier:
5804
6084
  return SENTINEL_IDENTIFIERS.has(node.name) || SENTINEL_PREFIX_RE.test(node.name) || isConstantReference(node.name);
5805
- case AST_NODE_TYPES25.MemberExpression:
5806
- return !node.computed && node.property.type === AST_NODE_TYPES25.Identifier && (SENTINEL_PREFIX_RE.test(node.property.name) || isConstantReference(node.property.name));
6085
+ case AST_NODE_TYPES28.MemberExpression:
6086
+ return !node.computed && node.property.type === AST_NODE_TYPES28.Identifier && (SENTINEL_PREFIX_RE.test(node.property.name) || isConstantReference(node.property.name));
5807
6087
  default:
5808
6088
  return false;
5809
6089
  }
5810
6090
  }
5811
6091
  function operandName(node) {
5812
- if (node.type === AST_NODE_TYPES25.Identifier) {
6092
+ if (node.type === AST_NODE_TYPES28.Identifier) {
5813
6093
  return node.name;
5814
6094
  }
5815
- if (node.type === AST_NODE_TYPES25.MemberExpression && !node.computed && node.property.type === AST_NODE_TYPES25.Identifier) {
6095
+ if (node.type === AST_NODE_TYPES28.MemberExpression && !node.computed && node.property.type === AST_NODE_TYPES28.Identifier) {
5816
6096
  return node.property.name;
5817
6097
  }
5818
6098
  return null;
5819
6099
  }
5820
6100
  function isSecretOperand(node) {
5821
- if (node.type === AST_NODE_TYPES25.TemplateLiteral) {
6101
+ if (node.type === AST_NODE_TYPES28.TemplateLiteral) {
5822
6102
  return node.expressions.some((expression) => isSecretOperand(expression));
5823
6103
  }
5824
6104
  const name = operandName(node);
5825
6105
  return name !== null && isAuthSecretName(name);
5826
6106
  }
5827
6107
  function secretNameOf(node) {
5828
- if (node.type === AST_NODE_TYPES25.TemplateLiteral) {
6108
+ if (node.type === AST_NODE_TYPES28.TemplateLiteral) {
5829
6109
  for (const expression of node.expressions) {
5830
6110
  const nested = secretNameOf(expression);
5831
6111
  if (nested !== null) {
@@ -5836,7 +6116,7 @@ function secretNameOf(node) {
5836
6116
  }
5837
6117
  return operandName(node);
5838
6118
  }
5839
- var prefer_constant_time_secret_compare_default = ESLintUtils35.RuleCreator(
6119
+ var prefer_constant_time_secret_compare_default = ESLintUtils39.RuleCreator(
5840
6120
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5841
6121
  )({
5842
6122
  name: "prefer-constant-time-secret-compare",
@@ -5879,11 +6159,11 @@ var prefer_constant_time_secret_compare_default = ESLintUtils35.RuleCreator(
5879
6159
  });
5880
6160
 
5881
6161
  // src/rules/store-insert-requires-on-conflict.ts
5882
- import { ESLintUtils as ESLintUtils36 } from "@typescript-eslint/utils";
6162
+ import { ESLintUtils as ESLintUtils40 } from "@typescript-eslint/utils";
5883
6163
  var INSERT_WRITE = /\bINSERT\s+(?:OR\s+\w+\s+)?INTO\s+[\w."'`?$:@-]+\s*(?:\([^)]*\)\s*)?(?:VALUES|SELECT|DEFAULT\s+VALUES)\b/i;
5884
6164
  var CONFLICT_HANDLED = /\bON\s+CONFLICT\b|\bON\s+DUPLICATE\s+KEY\b|\bINSERT\s+OR\s+(?:IGNORE|REPLACE)\b/i;
5885
6165
  var INSERT_GATE = /insert/i;
5886
- var store_insert_requires_on_conflict_default = ESLintUtils36.RuleCreator(
6166
+ var store_insert_requires_on_conflict_default = ESLintUtils40.RuleCreator(
5887
6167
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5888
6168
  )({
5889
6169
  name: "store-insert-requires-on-conflict",
@@ -5912,17 +6192,17 @@ var store_insert_requires_on_conflict_default = ESLintUtils36.RuleCreator(
5912
6192
  });
5913
6193
 
5914
6194
  // src/rules/no-dynamic-sql.ts
5915
- import { AST_NODE_TYPES as AST_NODE_TYPES26, ESLintUtils as ESLintUtils37 } from "@typescript-eslint/utils";
6195
+ import { AST_NODE_TYPES as AST_NODE_TYPES29, ESLintUtils as ESLintUtils41 } from "@typescript-eslint/utils";
5916
6196
  var DEFAULT_METHODS = ["prepare", "exec", "query"];
5917
6197
  var CONSTANT_CASE_RE = /^[A-Z][A-Z0-9_]*$/;
5918
6198
  function isStaticFragment(expression) {
5919
- if (expression.type === AST_NODE_TYPES26.Identifier) {
6199
+ if (expression.type === AST_NODE_TYPES29.Identifier) {
5920
6200
  return CONSTANT_CASE_RE.test(expression.name);
5921
6201
  }
5922
- if (expression.type === AST_NODE_TYPES26.MemberExpression && !expression.computed && expression.property.type === AST_NODE_TYPES26.Identifier) {
6202
+ if (expression.type === AST_NODE_TYPES29.MemberExpression && !expression.computed && expression.property.type === AST_NODE_TYPES29.Identifier) {
5923
6203
  return CONSTANT_CASE_RE.test(expression.property.name);
5924
6204
  }
5925
- if (expression.type === AST_NODE_TYPES26.Literal) {
6205
+ if (expression.type === AST_NODE_TYPES29.Literal) {
5926
6206
  return typeof expression.value === "string";
5927
6207
  }
5928
6208
  return false;
@@ -5933,36 +6213,36 @@ function runtimeInterpolations(template) {
5933
6213
  );
5934
6214
  }
5935
6215
  function concatOperands(node) {
5936
- if (node.type === AST_NODE_TYPES26.BinaryExpression && node.operator === "+") {
6216
+ if (node.type === AST_NODE_TYPES29.BinaryExpression && node.operator === "+") {
5937
6217
  return [...concatOperands(node.left), ...concatOperands(node.right)];
5938
6218
  }
5939
6219
  return [node];
5940
6220
  }
5941
6221
  function runtimeConcatOperands(node) {
5942
- if (node.type !== AST_NODE_TYPES26.BinaryExpression || node.operator !== "+") {
6222
+ if (node.type !== AST_NODE_TYPES29.BinaryExpression || node.operator !== "+") {
5943
6223
  return [];
5944
6224
  }
5945
6225
  const operands = concatOperands(node);
5946
6226
  const hasStringLiteral = operands.some(
5947
- (operand) => operand.type === AST_NODE_TYPES26.Literal && typeof operand.value === "string"
6227
+ (operand) => operand.type === AST_NODE_TYPES29.Literal && typeof operand.value === "string"
5948
6228
  );
5949
6229
  if (!hasStringLiteral) {
5950
6230
  return [];
5951
6231
  }
5952
6232
  return operands.filter(
5953
- (operand) => operand.type !== AST_NODE_TYPES26.Literal && !isStaticFragment(operand)
6233
+ (operand) => operand.type !== AST_NODE_TYPES29.Literal && !isStaticFragment(operand)
5954
6234
  );
5955
6235
  }
5956
6236
  var SQL_STATEMENT_RE = /\b(?:select\s|insert\s+into\b|insert\s+or\b|update\s+\w|delete\s+from\b|replace\s+into\b|merge\s+into\b|upsert\s+into\b|create\s+(?:temp(?:orary)?\s+)?(?:table|index|view|trigger|schema|database)\b|alter\s+table\b|drop\s+(?:table|index|view|trigger)\b|truncate\s+table\b|pragma\s+\w|with\s+\w+\s+as\s*\(|from\s+\w+\s+where\b)/i;
5957
6237
  var RUNTIME_MARKER = " ? ";
5958
6238
  function staticStatementText(node) {
5959
- if (node.type === AST_NODE_TYPES26.TemplateLiteral) {
6239
+ if (node.type === AST_NODE_TYPES29.TemplateLiteral) {
5960
6240
  return node.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join(RUNTIME_MARKER);
5961
6241
  }
5962
- if (node.type === AST_NODE_TYPES26.Literal) {
6242
+ if (node.type === AST_NODE_TYPES29.Literal) {
5963
6243
  return typeof node.value === "string" ? node.value : RUNTIME_MARKER;
5964
6244
  }
5965
- if (node.type === AST_NODE_TYPES26.BinaryExpression && node.operator === "+") {
6245
+ if (node.type === AST_NODE_TYPES29.BinaryExpression && node.operator === "+") {
5966
6246
  return staticStatementText(node.left) + staticStatementText(node.right);
5967
6247
  }
5968
6248
  return RUNTIME_MARKER;
@@ -5972,13 +6252,13 @@ function looksLikeSql(node) {
5972
6252
  }
5973
6253
  function statementMethodName(node, methods) {
5974
6254
  const callee = node.callee;
5975
- if (callee.type !== AST_NODE_TYPES26.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES26.Identifier) {
6255
+ if (callee.type !== AST_NODE_TYPES29.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES29.Identifier) {
5976
6256
  return null;
5977
6257
  }
5978
6258
  const name = callee.property.name;
5979
6259
  return methods.has(name) ? name : null;
5980
6260
  }
5981
- var no_dynamic_sql_default = ESLintUtils37.RuleCreator(
6261
+ var no_dynamic_sql_default = ESLintUtils41.RuleCreator(
5982
6262
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5983
6263
  )({
5984
6264
  name: "no-dynamic-sql",
@@ -6017,7 +6297,7 @@ var no_dynamic_sql_default = ESLintUtils37.RuleCreator(
6017
6297
  if (statement === void 0 || !looksLikeSql(statement)) {
6018
6298
  return;
6019
6299
  }
6020
- const offenders = statement.type === AST_NODE_TYPES26.TemplateLiteral ? runtimeInterpolations(statement) : runtimeConcatOperands(statement);
6300
+ const offenders = statement.type === AST_NODE_TYPES29.TemplateLiteral ? runtimeInterpolations(statement) : runtimeConcatOperands(statement);
6021
6301
  for (const offender of offenders) {
6022
6302
  context.report({
6023
6303
  node: offender,
@@ -6031,7 +6311,7 @@ var no_dynamic_sql_default = ESLintUtils37.RuleCreator(
6031
6311
  });
6032
6312
 
6033
6313
  // src/rules/no-raw-fetch-outside-clients.ts
6034
- import { ESLintUtils as ESLintUtils38 } from "@typescript-eslint/utils";
6314
+ import { ESLintUtils as ESLintUtils42 } from "@typescript-eslint/utils";
6035
6315
  var DEFAULT_ALLOW = [
6036
6316
  "[\\\\/]clients?[\\\\/]",
6037
6317
  "-client\\.[cm]?[jt]sx?$",
@@ -6095,7 +6375,7 @@ function compile(patterns) {
6095
6375
  }
6096
6376
  return compiled;
6097
6377
  }
6098
- var no_raw_fetch_outside_clients_default = ESLintUtils38.RuleCreator(
6378
+ var no_raw_fetch_outside_clients_default = ESLintUtils42.RuleCreator(
6099
6379
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
6100
6380
  )({
6101
6381
  name: "no-raw-fetch-outside-clients",
@@ -6143,7 +6423,7 @@ var no_raw_fetch_outside_clients_default = ESLintUtils38.RuleCreator(
6143
6423
  });
6144
6424
 
6145
6425
  // src/rules/no-storage-in-stateless-modules.ts
6146
- import { AST_NODE_TYPES as AST_NODE_TYPES27, ESLintUtils as ESLintUtils39 } from "@typescript-eslint/utils";
6426
+ import { AST_NODE_TYPES as AST_NODE_TYPES30, ESLintUtils as ESLintUtils43 } from "@typescript-eslint/utils";
6147
6427
  var DEFAULT_METHODS2 = [
6148
6428
  "prepare",
6149
6429
  "put",
@@ -6162,7 +6442,7 @@ function compile2(patterns) {
6162
6442
  }
6163
6443
  function storageMethodName(node, methods) {
6164
6444
  const callee = node.callee;
6165
- if (callee.type !== AST_NODE_TYPES27.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES27.Identifier) {
6445
+ if (callee.type !== AST_NODE_TYPES30.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES30.Identifier) {
6166
6446
  return null;
6167
6447
  }
6168
6448
  const name = callee.property.name;
@@ -6174,7 +6454,7 @@ function storageMethodName(node, methods) {
6174
6454
  }
6175
6455
  return name;
6176
6456
  }
6177
- var no_storage_in_stateless_modules_default = ESLintUtils39.RuleCreator(
6457
+ var no_storage_in_stateless_modules_default = ESLintUtils43.RuleCreator(
6178
6458
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
6179
6459
  )({
6180
6460
  name: "no-storage-in-stateless-modules",
@@ -6233,8 +6513,8 @@ var no_storage_in_stateless_modules_default = ESLintUtils39.RuleCreator(
6233
6513
 
6234
6514
  // src/rules/no-zod-native-enum.ts
6235
6515
  import {
6236
- ESLintUtils as ESLintUtils40,
6237
- AST_NODE_TYPES as AST_NODE_TYPES28
6516
+ ESLintUtils as ESLintUtils44,
6517
+ AST_NODE_TYPES as AST_NODE_TYPES31
6238
6518
  } from "@typescript-eslint/utils";
6239
6519
  import * as ts2 from "typescript";
6240
6520
  var IGNORE_PATTERNS2 = [
@@ -6249,11 +6529,11 @@ function isIgnoredFile2(filename, sourceText) {
6249
6529
  }
6250
6530
  return /@generated\b/.test(sourceText.slice(0, 1024));
6251
6531
  }
6252
- function isZodModule(source) {
6532
+ function isZodModule2(source) {
6253
6533
  return /(^|[/@-])zod([/-]|$)/.test(source);
6254
6534
  }
6255
6535
  function unwrap3(node) {
6256
- if (node.type === AST_NODE_TYPES28.TSAsExpression || node.type === AST_NODE_TYPES28.TSSatisfiesExpression) {
6536
+ if (node.type === AST_NODE_TYPES31.TSAsExpression || node.type === AST_NODE_TYPES31.TSSatisfiesExpression) {
6257
6537
  return unwrap3(node.expression);
6258
6538
  }
6259
6539
  return node;
@@ -6261,14 +6541,14 @@ function unwrap3(node) {
6261
6541
  function stringValueTexts(node, sourceCode) {
6262
6542
  const texts = [];
6263
6543
  for (const prop of node.properties) {
6264
- if (prop.type !== AST_NODE_TYPES28.Property) {
6544
+ if (prop.type !== AST_NODE_TYPES31.Property) {
6265
6545
  return null;
6266
6546
  }
6267
6547
  if (prop.computed || prop.shorthand || prop.method || prop.kind !== "init") {
6268
6548
  return null;
6269
6549
  }
6270
6550
  const value = prop.value;
6271
- if (value.type !== AST_NODE_TYPES28.Literal || typeof value.value !== "string") {
6551
+ if (value.type !== AST_NODE_TYPES31.Literal || typeof value.value !== "string") {
6272
6552
  return null;
6273
6553
  }
6274
6554
  const text = sourceCode.getText(value);
@@ -6284,7 +6564,7 @@ function resolvesToLocalEnum(node, scope) {
6284
6564
  const variable = current.variables.find((v) => v.name === node.name);
6285
6565
  if (variable !== void 0) {
6286
6566
  return variable.defs.some(
6287
- (def) => def.node.type === AST_NODE_TYPES28.TSEnumDeclaration
6567
+ (def) => def.node.type === AST_NODE_TYPES31.TSEnumDeclaration
6288
6568
  );
6289
6569
  }
6290
6570
  current = current.upper;
@@ -6304,7 +6584,7 @@ function resolvesToImportedEnum(node, services) {
6304
6584
  }
6305
6585
  return (symbol.flags & ENUM_SYMBOL_FLAGS) !== 0;
6306
6586
  }
6307
- var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6587
+ var no_zod_native_enum_default = ESLintUtils44.RuleCreator(
6308
6588
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
6309
6589
  )({
6310
6590
  name: "no-zod-native-enum",
@@ -6331,32 +6611,32 @@ var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6331
6611
  }
6332
6612
  let services;
6333
6613
  try {
6334
- services = ESLintUtils40.getParserServices(context);
6614
+ services = ESLintUtils44.getParserServices(context);
6335
6615
  } catch {
6336
6616
  services = null;
6337
6617
  }
6338
6618
  const zodImportedNames = /* @__PURE__ */ new Map();
6339
6619
  function isZodMemberCall(node, api) {
6340
6620
  const callee = node.callee;
6341
- if (callee.type === AST_NODE_TYPES28.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES28.Identifier) {
6621
+ if (callee.type === AST_NODE_TYPES31.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES31.Identifier) {
6342
6622
  return callee.property.name === api;
6343
6623
  }
6344
- if (callee.type === AST_NODE_TYPES28.Identifier) {
6624
+ if (callee.type === AST_NODE_TYPES31.Identifier) {
6345
6625
  return zodImportedNames.get(callee.name) === api;
6346
6626
  }
6347
6627
  return false;
6348
6628
  }
6349
6629
  function buildFix(node) {
6350
6630
  const callee = node.callee;
6351
- if (callee.type !== AST_NODE_TYPES28.MemberExpression || callee.property.type !== AST_NODE_TYPES28.Identifier) {
6631
+ if (callee.type !== AST_NODE_TYPES31.MemberExpression || callee.property.type !== AST_NODE_TYPES31.Identifier) {
6352
6632
  return null;
6353
6633
  }
6354
6634
  const arg = node.arguments[0];
6355
- if (arg === void 0 || node.arguments.length !== 1 || arg.type === AST_NODE_TYPES28.SpreadElement) {
6635
+ if (arg === void 0 || node.arguments.length !== 1 || arg.type === AST_NODE_TYPES31.SpreadElement) {
6356
6636
  return null;
6357
6637
  }
6358
6638
  const inner = unwrap3(arg);
6359
- if (inner.type !== AST_NODE_TYPES28.ObjectExpression) {
6639
+ if (inner.type !== AST_NODE_TYPES31.ObjectExpression) {
6360
6640
  return null;
6361
6641
  }
6362
6642
  const values = stringValueTexts(inner, sourceCode);
@@ -6372,11 +6652,11 @@ var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6372
6652
  }
6373
6653
  return {
6374
6654
  ImportDeclaration(node) {
6375
- if (!isZodModule(node.source.value)) {
6655
+ if (!isZodModule2(node.source.value)) {
6376
6656
  return;
6377
6657
  }
6378
6658
  for (const spec of node.specifiers) {
6379
- if (spec.type === AST_NODE_TYPES28.ImportSpecifier && spec.imported.type === AST_NODE_TYPES28.Identifier) {
6659
+ if (spec.type === AST_NODE_TYPES31.ImportSpecifier && spec.imported.type === AST_NODE_TYPES31.Identifier) {
6380
6660
  zodImportedNames.set(spec.local.name, spec.imported.name);
6381
6661
  }
6382
6662
  }
@@ -6395,7 +6675,7 @@ var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6395
6675
  return;
6396
6676
  }
6397
6677
  const arg = node.arguments[0];
6398
- if (arg === void 0 || arg.type !== AST_NODE_TYPES28.Identifier) {
6678
+ if (arg === void 0 || arg.type !== AST_NODE_TYPES31.Identifier) {
6399
6679
  return;
6400
6680
  }
6401
6681
  const isEnum = resolvesToLocalEnum(arg, sourceCode.getScope(arg)) || services !== null && resolvesToImportedEnum(arg, services);
@@ -6413,8 +6693,8 @@ var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6413
6693
 
6414
6694
  // src/rules/prefer-module-level-constant.ts
6415
6695
  import {
6416
- ESLintUtils as ESLintUtils41,
6417
- AST_NODE_TYPES as AST_NODE_TYPES29
6696
+ ESLintUtils as ESLintUtils45,
6697
+ AST_NODE_TYPES as AST_NODE_TYPES32
6418
6698
  } from "@typescript-eslint/utils";
6419
6699
  var DEFAULT_MIN_ELEMENTS = 3;
6420
6700
  var MAX_LITERAL_DEPTH = 4;
@@ -6450,10 +6730,10 @@ var MUTATING_METHODS = /* @__PURE__ */ new Set([
6450
6730
  // Object-ish escape hatches
6451
6731
  "assign"
6452
6732
  ]);
6453
- var FUNCTION_TYPES3 = /* @__PURE__ */ new Set([
6454
- AST_NODE_TYPES29.FunctionDeclaration,
6455
- AST_NODE_TYPES29.FunctionExpression,
6456
- AST_NODE_TYPES29.ArrowFunctionExpression
6733
+ var FUNCTION_TYPES4 = /* @__PURE__ */ new Set([
6734
+ AST_NODE_TYPES32.FunctionDeclaration,
6735
+ AST_NODE_TYPES32.FunctionExpression,
6736
+ AST_NODE_TYPES32.ArrowFunctionExpression
6457
6737
  ]);
6458
6738
  var COLLECTION_CONSTRUCTORS = /* @__PURE__ */ new Set(["Set", "Map"]);
6459
6739
  function isIgnoredFile3(filename, sourceText) {
@@ -6466,13 +6746,13 @@ function isTestFile2(filename) {
6466
6746
  return TEST_FILE_PATTERNS.some((re) => re.test(filename));
6467
6747
  }
6468
6748
  function unwrap4(node) {
6469
- if (node.type === AST_NODE_TYPES29.TSAsExpression || node.type === AST_NODE_TYPES29.TSSatisfiesExpression || node.type === AST_NODE_TYPES29.TSNonNullExpression) {
6749
+ if (node.type === AST_NODE_TYPES32.TSAsExpression || node.type === AST_NODE_TYPES32.TSSatisfiesExpression || node.type === AST_NODE_TYPES32.TSNonNullExpression) {
6470
6750
  return unwrap4(node.expression);
6471
6751
  }
6472
6752
  return node;
6473
6753
  }
6474
6754
  function isRegexLiteral(node) {
6475
- return node.type === AST_NODE_TYPES29.Literal && "regex" in node && node.regex !== void 0;
6755
+ return node.type === AST_NODE_TYPES32.Literal && "regex" in node && node.regex !== void 0;
6476
6756
  }
6477
6757
  function isLiteralOnly(node, depth) {
6478
6758
  if (depth > MAX_LITERAL_DEPTH) {
@@ -6480,29 +6760,29 @@ function isLiteralOnly(node, depth) {
6480
6760
  }
6481
6761
  const inner = unwrap4(node);
6482
6762
  switch (inner.type) {
6483
- case AST_NODE_TYPES29.Literal: {
6763
+ case AST_NODE_TYPES32.Literal: {
6484
6764
  return true;
6485
6765
  }
6486
- case AST_NODE_TYPES29.TemplateLiteral: {
6766
+ case AST_NODE_TYPES32.TemplateLiteral: {
6487
6767
  return inner.expressions.length === 0;
6488
6768
  }
6489
- case AST_NODE_TYPES29.UnaryExpression: {
6490
- return (inner.operator === "-" || inner.operator === "+") && inner.argument.type === AST_NODE_TYPES29.Literal && typeof inner.argument.value === "number";
6769
+ case AST_NODE_TYPES32.UnaryExpression: {
6770
+ return (inner.operator === "-" || inner.operator === "+") && inner.argument.type === AST_NODE_TYPES32.Literal && typeof inner.argument.value === "number";
6491
6771
  }
6492
- case AST_NODE_TYPES29.ArrayExpression: {
6772
+ case AST_NODE_TYPES32.ArrayExpression: {
6493
6773
  return inner.elements.every(
6494
- (el) => el !== null && el.type !== AST_NODE_TYPES29.SpreadElement && isLiteralOnly(el, depth + 1)
6774
+ (el) => el !== null && el.type !== AST_NODE_TYPES32.SpreadElement && isLiteralOnly(el, depth + 1)
6495
6775
  );
6496
6776
  }
6497
- case AST_NODE_TYPES29.ObjectExpression: {
6777
+ case AST_NODE_TYPES32.ObjectExpression: {
6498
6778
  return inner.properties.every((prop) => {
6499
- if (prop.type !== AST_NODE_TYPES29.Property) {
6779
+ if (prop.type !== AST_NODE_TYPES32.Property) {
6500
6780
  return false;
6501
6781
  }
6502
6782
  if (prop.shorthand || prop.method || prop.kind !== "init") {
6503
6783
  return false;
6504
6784
  }
6505
- if (prop.computed && prop.key.type !== AST_NODE_TYPES29.Literal) {
6785
+ if (prop.computed && prop.key.type !== AST_NODE_TYPES32.Literal) {
6506
6786
  return false;
6507
6787
  }
6508
6788
  return isLiteralOnly(prop.value, depth + 1);
@@ -6515,7 +6795,7 @@ function isLiteralOnly(node, depth) {
6515
6795
  }
6516
6796
  function unwrapObjectFreeze(node) {
6517
6797
  const inner = unwrap4(node);
6518
- if (inner.type === AST_NODE_TYPES29.CallExpression && inner.callee.type === AST_NODE_TYPES29.MemberExpression && !inner.callee.computed && inner.callee.object.type === AST_NODE_TYPES29.Identifier && inner.callee.object.name === "Object" && inner.callee.property.type === AST_NODE_TYPES29.Identifier && inner.callee.property.name === "freeze" && inner.arguments.length === 1 && inner.arguments[0] !== void 0 && inner.arguments[0].type !== AST_NODE_TYPES29.SpreadElement) {
6798
+ if (inner.type === AST_NODE_TYPES32.CallExpression && inner.callee.type === AST_NODE_TYPES32.MemberExpression && !inner.callee.computed && inner.callee.object.type === AST_NODE_TYPES32.Identifier && inner.callee.object.name === "Object" && inner.callee.property.type === AST_NODE_TYPES32.Identifier && inner.callee.property.name === "freeze" && inner.arguments.length === 1 && inner.arguments[0] !== void 0 && inner.arguments[0].type !== AST_NODE_TYPES32.SpreadElement) {
6519
6799
  return unwrap4(inner.arguments[0]);
6520
6800
  }
6521
6801
  return inner;
@@ -6531,19 +6811,19 @@ function classify(init, checkRegex) {
6531
6811
  }
6532
6812
  return { kind: "regex", size: 1 };
6533
6813
  }
6534
- if (node.type === AST_NODE_TYPES29.ArrayExpression) {
6814
+ if (node.type === AST_NODE_TYPES32.ArrayExpression) {
6535
6815
  return isLiteralOnly(node, 0) ? { kind: "array", size: node.elements.length } : null;
6536
6816
  }
6537
- if (node.type === AST_NODE_TYPES29.ObjectExpression) {
6817
+ if (node.type === AST_NODE_TYPES32.ObjectExpression) {
6538
6818
  return isLiteralOnly(node, 0) ? { kind: "object", size: node.properties.length } : null;
6539
6819
  }
6540
- if (node.type === AST_NODE_TYPES29.NewExpression && node.callee.type === AST_NODE_TYPES29.Identifier && COLLECTION_CONSTRUCTORS.has(node.callee.name)) {
6820
+ if (node.type === AST_NODE_TYPES32.NewExpression && node.callee.type === AST_NODE_TYPES32.Identifier && COLLECTION_CONSTRUCTORS.has(node.callee.name)) {
6541
6821
  const arg = node.arguments[0];
6542
- if (node.arguments.length !== 1 || arg === void 0 || arg.type === AST_NODE_TYPES29.SpreadElement) {
6822
+ if (node.arguments.length !== 1 || arg === void 0 || arg.type === AST_NODE_TYPES32.SpreadElement) {
6543
6823
  return null;
6544
6824
  }
6545
6825
  const entries = unwrap4(arg);
6546
- if (entries.type !== AST_NODE_TYPES29.ArrayExpression) {
6826
+ if (entries.type !== AST_NODE_TYPES32.ArrayExpression) {
6547
6827
  return null;
6548
6828
  }
6549
6829
  return isLiteralOnly(entries, 0) ? { kind: node.callee.name === "Set" ? "Set" : "Map", size: entries.elements.length } : null;
@@ -6553,7 +6833,7 @@ function classify(init, checkRegex) {
6553
6833
  function enclosingFunction2(node) {
6554
6834
  let current = node.parent;
6555
6835
  while (current !== void 0 && current !== null) {
6556
- if (FUNCTION_TYPES3.has(current.type)) {
6836
+ if (FUNCTION_TYPES4.has(current.type)) {
6557
6837
  return current;
6558
6838
  }
6559
6839
  current = current.parent;
@@ -6572,10 +6852,10 @@ var NON_RETAINING_BUILTINS = /* @__PURE__ */ new Map(
6572
6852
  );
6573
6853
  function isNonRetainingBuiltinCall(node, argument) {
6574
6854
  const callee = node.callee;
6575
- if (callee.type === AST_NODE_TYPES29.Identifier && callee.name === "structuredClone") {
6855
+ if (callee.type === AST_NODE_TYPES32.Identifier && callee.name === "structuredClone") {
6576
6856
  return true;
6577
6857
  }
6578
- if (callee.type !== AST_NODE_TYPES29.MemberExpression || callee.computed || callee.object.type !== AST_NODE_TYPES29.Identifier || callee.property.type !== AST_NODE_TYPES29.Identifier) {
6858
+ if (callee.type !== AST_NODE_TYPES32.MemberExpression || callee.computed || callee.object.type !== AST_NODE_TYPES32.Identifier || callee.property.type !== AST_NODE_TYPES32.Identifier) {
6579
6859
  return false;
6580
6860
  }
6581
6861
  const members = NON_RETAINING_BUILTINS.get(callee.object.name);
@@ -6589,43 +6869,43 @@ function isNonRetainingBuiltinCall(node, argument) {
6589
6869
  }
6590
6870
  function isSafeRead(identifier) {
6591
6871
  const parent = identifier.parent;
6592
- if (parent.type === AST_NODE_TYPES29.MemberExpression) {
6872
+ if (parent.type === AST_NODE_TYPES32.MemberExpression) {
6593
6873
  if (parent.object !== identifier) {
6594
6874
  return true;
6595
6875
  }
6596
6876
  const grandparent = parent.parent;
6597
- if (grandparent.type === AST_NODE_TYPES29.AssignmentExpression && grandparent.left === parent) {
6877
+ if (grandparent.type === AST_NODE_TYPES32.AssignmentExpression && grandparent.left === parent) {
6598
6878
  return false;
6599
6879
  }
6600
- if (grandparent.type === AST_NODE_TYPES29.UpdateExpression) {
6880
+ if (grandparent.type === AST_NODE_TYPES32.UpdateExpression) {
6601
6881
  return false;
6602
6882
  }
6603
- if (grandparent.type === AST_NODE_TYPES29.UnaryExpression && grandparent.operator === "delete") {
6883
+ if (grandparent.type === AST_NODE_TYPES32.UnaryExpression && grandparent.operator === "delete") {
6604
6884
  return false;
6605
6885
  }
6606
- if (!parent.computed && parent.property.type === AST_NODE_TYPES29.Identifier && MUTATING_METHODS.has(parent.property.name) && grandparent.type === AST_NODE_TYPES29.CallExpression && grandparent.callee === parent) {
6886
+ if (!parent.computed && parent.property.type === AST_NODE_TYPES32.Identifier && MUTATING_METHODS.has(parent.property.name) && grandparent.type === AST_NODE_TYPES32.CallExpression && grandparent.callee === parent) {
6607
6887
  return false;
6608
6888
  }
6609
6889
  return true;
6610
6890
  }
6611
- if (parent.type === AST_NODE_TYPES29.ForOfStatement && parent.right === identifier) {
6891
+ if (parent.type === AST_NODE_TYPES32.ForOfStatement && parent.right === identifier) {
6612
6892
  return true;
6613
6893
  }
6614
- if (parent.type === AST_NODE_TYPES29.SpreadElement) {
6894
+ if (parent.type === AST_NODE_TYPES32.SpreadElement) {
6615
6895
  return true;
6616
6896
  }
6617
- if (parent.type === AST_NODE_TYPES29.BinaryExpression) {
6897
+ if (parent.type === AST_NODE_TYPES32.BinaryExpression) {
6618
6898
  return true;
6619
6899
  }
6620
- if (parent.type === AST_NODE_TYPES29.CallExpression && parent.arguments.includes(identifier) && isNonRetainingBuiltinCall(parent, identifier)) {
6900
+ if (parent.type === AST_NODE_TYPES32.CallExpression && parent.arguments.includes(identifier) && isNonRetainingBuiltinCall(parent, identifier)) {
6621
6901
  return true;
6622
6902
  }
6623
- if (parent.type === AST_NODE_TYPES29.UnaryExpression && parent.operator !== "delete") {
6903
+ if (parent.type === AST_NODE_TYPES32.UnaryExpression && parent.operator !== "delete") {
6624
6904
  return true;
6625
6905
  }
6626
6906
  return false;
6627
6907
  }
6628
- var prefer_module_level_constant_default = ESLintUtils41.RuleCreator(
6908
+ var prefer_module_level_constant_default = ESLintUtils45.RuleCreator(
6629
6909
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
6630
6910
  )({
6631
6911
  name: "prefer-module-level-constant",
@@ -6677,7 +6957,7 @@ var prefer_module_level_constant_default = ESLintUtils41.RuleCreator(
6677
6957
  if (reference.isWrite()) {
6678
6958
  return false;
6679
6959
  }
6680
- if (reference.identifier.type !== AST_NODE_TYPES29.Identifier) {
6960
+ if (reference.identifier.type !== AST_NODE_TYPES32.Identifier) {
6681
6961
  return false;
6682
6962
  }
6683
6963
  if (!isSafeRead(reference.identifier)) {
@@ -6689,10 +6969,10 @@ var prefer_module_level_constant_default = ESLintUtils41.RuleCreator(
6689
6969
  return {
6690
6970
  VariableDeclarator(node) {
6691
6971
  const declaration = node.parent;
6692
- if (declaration.type !== AST_NODE_TYPES29.VariableDeclaration || declaration.kind !== "const" || declaration.declare === true) {
6972
+ if (declaration.type !== AST_NODE_TYPES32.VariableDeclaration || declaration.kind !== "const" || declaration.declare === true) {
6693
6973
  return;
6694
6974
  }
6695
- if (node.id.type !== AST_NODE_TYPES29.Identifier || node.init === null) {
6975
+ if (node.id.type !== AST_NODE_TYPES32.Identifier || node.init === null) {
6696
6976
  return;
6697
6977
  }
6698
6978
  if (enclosingFunction2(node) === null) {
@@ -6719,7 +6999,7 @@ var prefer_module_level_constant_default = ESLintUtils41.RuleCreator(
6719
6999
  });
6720
7000
 
6721
7001
  // src/rules/jsdoc-restates-signature.ts
6722
- import { AST_NODE_TYPES as AST_NODE_TYPES30, ESLintUtils as ESLintUtils42 } from "@typescript-eslint/utils";
7002
+ import { AST_NODE_TYPES as AST_NODE_TYPES33, ESLintUtils as ESLintUtils46 } from "@typescript-eslint/utils";
6723
7003
  var VALUE_TAGS = /* @__PURE__ */ new Set([
6724
7004
  "alpha",
6725
7005
  "author",
@@ -6802,30 +7082,30 @@ function declarationNames(node) {
6802
7082
  switch (node.type) {
6803
7083
  // `export function f()` — the JSDoc sits above the `export`, so the token
6804
7084
  // after it resolves to the wrapper, not to the thing being documented.
6805
- case AST_NODE_TYPES30.ExportNamedDeclaration:
6806
- case AST_NODE_TYPES30.ExportDefaultDeclaration:
7085
+ case AST_NODE_TYPES33.ExportNamedDeclaration:
7086
+ case AST_NODE_TYPES33.ExportDefaultDeclaration:
6807
7087
  return node.declaration == null ? null : declarationNames(node.declaration);
6808
- case AST_NODE_TYPES30.FunctionDeclaration:
6809
- case AST_NODE_TYPES30.TSDeclareFunction:
7088
+ case AST_NODE_TYPES33.FunctionDeclaration:
7089
+ case AST_NODE_TYPES33.TSDeclareFunction:
6810
7090
  return node.id === null ? null : { name: node.id.name, params: paramNames(node.params) };
6811
- case AST_NODE_TYPES30.ClassDeclaration:
6812
- case AST_NODE_TYPES30.TSInterfaceDeclaration:
6813
- case AST_NODE_TYPES30.TSTypeAliasDeclaration:
6814
- case AST_NODE_TYPES30.TSEnumDeclaration:
7091
+ case AST_NODE_TYPES33.ClassDeclaration:
7092
+ case AST_NODE_TYPES33.TSInterfaceDeclaration:
7093
+ case AST_NODE_TYPES33.TSTypeAliasDeclaration:
7094
+ case AST_NODE_TYPES33.TSEnumDeclaration:
6815
7095
  return node.id === null ? null : { name: node.id.name, params: [] };
6816
- case AST_NODE_TYPES30.VariableDeclaration: {
7096
+ case AST_NODE_TYPES33.VariableDeclaration: {
6817
7097
  const declarator = node.declarations[0];
6818
- if (declarator === void 0 || declarator.id.type !== AST_NODE_TYPES30.Identifier) return null;
7098
+ if (declarator === void 0 || declarator.id.type !== AST_NODE_TYPES33.Identifier) return null;
6819
7099
  const init = declarator.init;
6820
- const params = init != null && (init.type === AST_NODE_TYPES30.ArrowFunctionExpression || init.type === AST_NODE_TYPES30.FunctionExpression) ? paramNames(init.params) : [];
7100
+ const params = init != null && (init.type === AST_NODE_TYPES33.ArrowFunctionExpression || init.type === AST_NODE_TYPES33.FunctionExpression) ? paramNames(init.params) : [];
6821
7101
  return { name: declarator.id.name, params };
6822
7102
  }
6823
- case AST_NODE_TYPES30.MethodDefinition:
6824
- case AST_NODE_TYPES30.PropertyDefinition:
6825
- case AST_NODE_TYPES30.TSMethodSignature:
6826
- case AST_NODE_TYPES30.TSPropertySignature: {
6827
- if (node.key.type !== AST_NODE_TYPES30.Identifier) return null;
6828
- const params = node.type === AST_NODE_TYPES30.MethodDefinition ? paramNames(node.value.params) : node.type === AST_NODE_TYPES30.TSMethodSignature ? paramNames(node.params) : [];
7103
+ case AST_NODE_TYPES33.MethodDefinition:
7104
+ case AST_NODE_TYPES33.PropertyDefinition:
7105
+ case AST_NODE_TYPES33.TSMethodSignature:
7106
+ case AST_NODE_TYPES33.TSPropertySignature: {
7107
+ if (node.key.type !== AST_NODE_TYPES33.Identifier) return null;
7108
+ const params = node.type === AST_NODE_TYPES33.MethodDefinition ? paramNames(node.value.params) : node.type === AST_NODE_TYPES33.TSMethodSignature ? paramNames(node.params) : [];
6829
7109
  return { name: node.key.name, params };
6830
7110
  }
6831
7111
  default:
@@ -6835,9 +7115,9 @@ function declarationNames(node) {
6835
7115
  function paramNames(params) {
6836
7116
  const names = [];
6837
7117
  for (const param of params) {
6838
- const target = param.type === AST_NODE_TYPES30.AssignmentPattern ? param.left : param;
6839
- if (target.type === AST_NODE_TYPES30.Identifier) names.push(target.name);
6840
- else if (target.type === AST_NODE_TYPES30.TSParameterProperty) continue;
7118
+ const target = param.type === AST_NODE_TYPES33.AssignmentPattern ? param.left : param;
7119
+ if (target.type === AST_NODE_TYPES33.Identifier) names.push(target.name);
7120
+ else if (target.type === AST_NODE_TYPES33.TSParameterProperty) continue;
6841
7121
  }
6842
7122
  return names;
6843
7123
  }
@@ -6846,7 +7126,7 @@ function tokensOf(names) {
6846
7126
  for (const name of names) for (const part of splitIdentifier(name)) tokens.add(part);
6847
7127
  return tokens;
6848
7128
  }
6849
- var jsdoc_restates_signature_default = ESLintUtils42.RuleCreator(
7129
+ var jsdoc_restates_signature_default = ESLintUtils46.RuleCreator(
6850
7130
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
6851
7131
  )({
6852
7132
  name: "jsdoc-restates-signature",
@@ -6882,7 +7162,7 @@ var jsdoc_restates_signature_default = ESLintUtils42.RuleCreator(
6882
7162
  if (token === null || token.loc.start.line !== comment.loc.end.line + 1) continue;
6883
7163
  let node = sourceCode.getNodeByRangeIndex(token.range[0]);
6884
7164
  let declaration = null;
6885
- while (node != null && node.type !== AST_NODE_TYPES30.Program) {
7165
+ while (node != null && node.type !== AST_NODE_TYPES33.Program) {
6886
7166
  declaration = declarationNames(node);
6887
7167
  if (declaration !== null) break;
6888
7168
  node = node.parent ?? null;
@@ -6937,7 +7217,7 @@ var jsdoc_restates_signature_default = ESLintUtils42.RuleCreator(
6937
7217
  });
6938
7218
 
6939
7219
  // src/rules/no-restated-comment.ts
6940
- import { AST_NODE_TYPES as AST_NODE_TYPES31, ESLintUtils as ESLintUtils43 } from "@typescript-eslint/utils";
7220
+ import { AST_NODE_TYPES as AST_NODE_TYPES34, ESLintUtils as ESLintUtils47 } from "@typescript-eslint/utils";
6941
7221
  var MAX_WORDS = 8;
6942
7222
  var MIN_CONTENT_TOKENS = 2;
6943
7223
  var DIRECTIVE_RE3 = /^(eslint\b|eslint-|sarj-noqa\b|@ts-|prettier-ignore|prettier\b|biome-|c8\b|v8\b|istanbul\b|@type\b|@vite|webpack|<reference|<amd|global\b|noinspection|todo\b|fixme\b|hack\b|xxx\b)/i;
@@ -6961,7 +7241,7 @@ function headsSiblingRun(node) {
6961
7241
  const next = index >= 0 ? body[index + 1] : void 0;
6962
7242
  return next !== void 0 && next.type === node.type;
6963
7243
  }
6964
- var no_restated_comment_default = ESLintUtils43.RuleCreator(
7244
+ var no_restated_comment_default = ESLintUtils47.RuleCreator(
6965
7245
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
6966
7246
  )({
6967
7247
  name: "no-restated-comment",
@@ -6989,7 +7269,7 @@ var no_restated_comment_default = ESLintUtils43.RuleCreator(
6989
7269
  function labelsASiblingRun(comment) {
6990
7270
  const token = sourceCode.getTokenAfter(comment, { includeComments: false });
6991
7271
  if (token === null) return false;
6992
- for (let node = sourceCode.getNodeByRangeIndex(token.range[0]); node != null && node.type !== AST_NODE_TYPES31.Program; node = node.parent) {
7272
+ for (let node = sourceCode.getNodeByRangeIndex(token.range[0]); node != null && node.type !== AST_NODE_TYPES34.Program; node = node.parent) {
6993
7273
  if (headsSiblingRun(node)) return true;
6994
7274
  }
6995
7275
  return false;
@@ -7029,7 +7309,7 @@ var no_restated_comment_default = ESLintUtils43.RuleCreator(
7029
7309
  });
7030
7310
 
7031
7311
  // src/rules/trailing-value-narration.ts
7032
- import { ESLintUtils as ESLintUtils44 } from "@typescript-eslint/utils";
7312
+ import { ESLintUtils as ESLintUtils48 } from "@typescript-eslint/utils";
7033
7313
  var NUMBER_RE = /(?<![\w.])(\d+(?:\.\d+)?)(?![\w.])/g;
7034
7314
  var WORD_RE3 = /[A-Za-z]+(?:'[a-z]+)?|\d+(?:\.\d+)?/g;
7035
7315
  var UNIT_WORDS = /* @__PURE__ */ new Set([
@@ -7113,7 +7393,7 @@ function narratesValue(body, code) {
7113
7393
  (word) => STOPWORDS3.has(word) || UNIT_WORDS.has(word) || commentNumbers.has(word) || identifiers.has(word) || stems.has(stem(word))
7114
7394
  );
7115
7395
  }
7116
- var trailing_value_narration_default = ESLintUtils44.RuleCreator(
7396
+ var trailing_value_narration_default = ESLintUtils48.RuleCreator(
7117
7397
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7118
7398
  )({
7119
7399
  name: "trailing-value-narration",
@@ -7154,7 +7434,7 @@ var trailing_value_narration_default = ESLintUtils44.RuleCreator(
7154
7434
  });
7155
7435
 
7156
7436
  // src/rules/no-tautological-expect.ts
7157
- import { AST_NODE_TYPES as AST_NODE_TYPES32, ESLintUtils as ESLintUtils45 } from "@typescript-eslint/utils";
7437
+ import { AST_NODE_TYPES as AST_NODE_TYPES35, ESLintUtils as ESLintUtils49 } from "@typescript-eslint/utils";
7158
7438
  var EQUALITY_MATCHERS = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual"]);
7159
7439
  var ZERO_ARG_MATCHERS = /* @__PURE__ */ new Set([
7160
7440
  "toBeDefined",
@@ -7168,17 +7448,17 @@ var OPERAND_PREVIEW_CHARS = 40;
7168
7448
  var NUMERIC_SIGNS = /* @__PURE__ */ new Set(["-", "+"]);
7169
7449
  function isLiteral(node) {
7170
7450
  switch (node.type) {
7171
- case AST_NODE_TYPES32.Literal:
7451
+ case AST_NODE_TYPES35.Literal:
7172
7452
  return true;
7173
- case AST_NODE_TYPES32.TemplateLiteral:
7453
+ case AST_NODE_TYPES35.TemplateLiteral:
7174
7454
  return node.expressions.length === 0;
7175
- case AST_NODE_TYPES32.UnaryExpression:
7455
+ case AST_NODE_TYPES35.UnaryExpression:
7176
7456
  return NUMERIC_SIGNS.has(node.operator) && isLiteral(node.argument);
7177
- case AST_NODE_TYPES32.ArrayExpression:
7457
+ case AST_NODE_TYPES35.ArrayExpression:
7178
7458
  return node.elements.every((element) => element !== null && isLiteral(element));
7179
- case AST_NODE_TYPES32.ObjectExpression:
7459
+ case AST_NODE_TYPES35.ObjectExpression:
7180
7460
  return node.properties.every(
7181
- (property) => property.type === AST_NODE_TYPES32.Property && !property.computed && isLiteral(property.value)
7461
+ (property) => property.type === AST_NODE_TYPES35.Property && !property.computed && isLiteral(property.value)
7182
7462
  );
7183
7463
  default:
7184
7464
  return false;
@@ -7186,12 +7466,12 @@ function isLiteral(node) {
7186
7466
  }
7187
7467
  function expectOperand(callee) {
7188
7468
  const receiver = callee.object;
7189
- if (receiver.type !== AST_NODE_TYPES32.CallExpression || receiver.callee.type !== AST_NODE_TYPES32.Identifier || receiver.callee.name !== "expect" || receiver.arguments.length !== 1) {
7469
+ if (receiver.type !== AST_NODE_TYPES35.CallExpression || receiver.callee.type !== AST_NODE_TYPES35.Identifier || receiver.callee.name !== "expect" || receiver.arguments.length !== 1) {
7190
7470
  return null;
7191
7471
  }
7192
7472
  return receiver.arguments[0] ?? null;
7193
7473
  }
7194
- var no_tautological_expect_default = ESLintUtils45.RuleCreator(
7474
+ var no_tautological_expect_default = ESLintUtils49.RuleCreator(
7195
7475
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7196
7476
  )({
7197
7477
  name: "no-tautological-expect",
@@ -7218,10 +7498,10 @@ var no_tautological_expect_default = ESLintUtils45.RuleCreator(
7218
7498
  return {
7219
7499
  CallExpression(node) {
7220
7500
  const callee = node.callee;
7221
- if (callee.type !== AST_NODE_TYPES32.MemberExpression || callee.computed) {
7501
+ if (callee.type !== AST_NODE_TYPES35.MemberExpression || callee.computed) {
7222
7502
  return;
7223
7503
  }
7224
- if (callee.property.type !== AST_NODE_TYPES32.Identifier) {
7504
+ if (callee.property.type !== AST_NODE_TYPES35.Identifier) {
7225
7505
  return;
7226
7506
  }
7227
7507
  const matcher = callee.property.name;
@@ -7255,26 +7535,26 @@ var no_tautological_expect_default = ESLintUtils45.RuleCreator(
7255
7535
  });
7256
7536
 
7257
7537
  // src/rules/require-interface-for-injected-service.ts
7258
- import { AST_NODE_TYPES as AST_NODE_TYPES33, ESLintUtils as ESLintUtils46 } from "@typescript-eslint/utils";
7538
+ import { AST_NODE_TYPES as AST_NODE_TYPES36, ESLintUtils as ESLintUtils50 } from "@typescript-eslint/utils";
7259
7539
  var CONFIGISH_TYPE_RE = /(?:Options|Opts|Config|Configuration|Settings|Params|Props|Args|Env|Environment|Callbacks|Flags)$/;
7260
7540
  var CONFIGISH_NAME_RE = /^(?:options|opts|config|configuration|settings|params|props|args|env|environment|callbacks|flags|logger|log|clock)$/i;
7261
7541
  var HTTP_TRANSPORT_TYPE_RE = /^(?:KyInstance|AxiosInstance|Session)$/;
7262
7542
  var TRANSPORT_WRAPPER_NAME_RE = /Client$/;
7263
7543
  var ROUTER_FACTORY_NAME = "Router";
7264
7544
  var FRAMEWORK_HTTP_TYPES = /* @__PURE__ */ new Set(["Request", "Response", "NextFunction"]);
7265
- var isExportedClass = (node) => node.parent.type === AST_NODE_TYPES33.ExportNamedDeclaration || node.parent.type === AST_NODE_TYPES33.ExportDefaultDeclaration;
7266
- var qualifiedName = (name) => name.type === AST_NODE_TYPES33.Identifier ? name.name : name.type === AST_NODE_TYPES33.TSQualifiedName ? `${qualifiedName(name.left)}.${name.right.name}` : "";
7545
+ var isExportedClass = (node) => node.parent.type === AST_NODE_TYPES36.ExportNamedDeclaration || node.parent.type === AST_NODE_TYPES36.ExportDefaultDeclaration;
7546
+ var qualifiedName = (name) => name.type === AST_NODE_TYPES36.Identifier ? name.name : name.type === AST_NODE_TYPES36.TSQualifiedName ? `${qualifiedName(name.left)}.${name.right.name}` : "";
7267
7547
  var typeReferenceName = (annotated) => {
7268
7548
  let target = annotated;
7269
- if (target.type === AST_NODE_TYPES33.TSParameterProperty) target = target.parameter;
7270
- if (target.type === AST_NODE_TYPES33.AssignmentPattern) target = target.left;
7271
- if (target.type !== AST_NODE_TYPES33.Identifier) return null;
7549
+ if (target.type === AST_NODE_TYPES36.TSParameterProperty) target = target.parameter;
7550
+ if (target.type === AST_NODE_TYPES36.AssignmentPattern) target = target.left;
7551
+ if (target.type !== AST_NODE_TYPES36.Identifier) return null;
7272
7552
  const annotation = target.typeAnnotation?.typeAnnotation;
7273
- if (annotation === void 0 || annotation.type !== AST_NODE_TYPES33.TSTypeReference) {
7553
+ if (annotation === void 0 || annotation.type !== AST_NODE_TYPES36.TSTypeReference) {
7274
7554
  return null;
7275
7555
  }
7276
7556
  const { typeName } = annotation;
7277
- const rightmost = typeName.type === AST_NODE_TYPES33.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES33.TSQualifiedName ? typeName.right.name : null;
7557
+ const rightmost = typeName.type === AST_NODE_TYPES36.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES36.TSQualifiedName ? typeName.right.name : null;
7278
7558
  if (rightmost === null) return null;
7279
7559
  return { name: target.name, typeName: rightmost, display: qualifiedName(typeName) };
7280
7560
  };
@@ -7284,17 +7564,17 @@ var readConstructor = (ctor) => {
7284
7564
  let constructedFields = 0;
7285
7565
  if (body !== null && body !== void 0) {
7286
7566
  for (const statement of body.body) {
7287
- if (statement.type !== AST_NODE_TYPES33.ExpressionStatement) continue;
7567
+ if (statement.type !== AST_NODE_TYPES36.ExpressionStatement) continue;
7288
7568
  const expression = statement.expression;
7289
- if (expression.type !== AST_NODE_TYPES33.AssignmentExpression || expression.operator !== "=" || expression.left.type !== AST_NODE_TYPES33.MemberExpression || expression.left.object.type !== AST_NODE_TYPES33.ThisExpression) {
7569
+ if (expression.type !== AST_NODE_TYPES36.AssignmentExpression || expression.operator !== "=" || expression.left.type !== AST_NODE_TYPES36.MemberExpression || expression.left.object.type !== AST_NODE_TYPES36.ThisExpression) {
7290
7570
  continue;
7291
7571
  }
7292
7572
  const source = expression.right;
7293
- if (source.type === AST_NODE_TYPES33.NewExpression) {
7573
+ if (source.type === AST_NODE_TYPES36.NewExpression) {
7294
7574
  constructedFields += 1;
7295
- } else if (source.type === AST_NODE_TYPES33.Identifier) {
7575
+ } else if (source.type === AST_NODE_TYPES36.Identifier) {
7296
7576
  storedFrom.add(source.name);
7297
- } else if (source.type === AST_NODE_TYPES33.MemberExpression && source.object.type === AST_NODE_TYPES33.Identifier) {
7577
+ } else if (source.type === AST_NODE_TYPES36.MemberExpression && source.object.type === AST_NODE_TYPES36.Identifier) {
7298
7578
  storedFrom.add(source.object.name);
7299
7579
  }
7300
7580
  }
@@ -7303,7 +7583,7 @@ var readConstructor = (ctor) => {
7303
7583
  for (const parameter of ctor.value.params) {
7304
7584
  const reference = typeReferenceName(parameter);
7305
7585
  if (reference === null) continue;
7306
- const stored = parameter.type === AST_NODE_TYPES33.TSParameterProperty || storedFrom.has(reference.name);
7586
+ const stored = parameter.type === AST_NODE_TYPES36.TSParameterProperty || storedFrom.has(reference.name);
7307
7587
  if (!stored) continue;
7308
7588
  if (CONFIGISH_TYPE_RE.test(reference.typeName)) continue;
7309
7589
  if (CONFIGISH_NAME_RE.test(reference.name)) continue;
@@ -7333,19 +7613,19 @@ var subtreeHas = (root, found) => {
7333
7613
  return hit;
7334
7614
  };
7335
7615
  var isFrameworkWiring = (body) => subtreeHas(body, (node) => {
7336
- if (node.type === AST_NODE_TYPES33.CallExpression) {
7616
+ if (node.type === AST_NODE_TYPES36.CallExpression) {
7337
7617
  const { callee } = node;
7338
- if (callee.type === AST_NODE_TYPES33.Identifier) return callee.name === ROUTER_FACTORY_NAME;
7339
- return callee.type === AST_NODE_TYPES33.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES33.Identifier && callee.property.name === ROUTER_FACTORY_NAME;
7618
+ if (callee.type === AST_NODE_TYPES36.Identifier) return callee.name === ROUTER_FACTORY_NAME;
7619
+ return callee.type === AST_NODE_TYPES36.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES36.Identifier && callee.property.name === ROUTER_FACTORY_NAME;
7340
7620
  }
7341
- return node.type === AST_NODE_TYPES33.TSTypeReference && node.typeName.type === AST_NODE_TYPES33.TSQualifiedName && FRAMEWORK_HTTP_TYPES.has(node.typeName.right.name);
7621
+ return node.type === AST_NODE_TYPES36.TSTypeReference && node.typeName.type === AST_NODE_TYPES36.TSQualifiedName && FRAMEWORK_HTTP_TYPES.has(node.typeName.right.name);
7342
7622
  });
7343
7623
  var stem2 = (name) => name.replace(/^I(?=[A-Z])/, "").replace(/Impl$/, "");
7344
7624
  var fileInterfaceNames = (program) => {
7345
7625
  const names = [];
7346
7626
  for (const statement of program.body) {
7347
- const declaration = statement.type === AST_NODE_TYPES33.ExportNamedDeclaration ? statement.declaration : statement;
7348
- if (declaration?.type === AST_NODE_TYPES33.TSInterfaceDeclaration) names.push(declaration.id.name);
7627
+ const declaration = statement.type === AST_NODE_TYPES36.ExportNamedDeclaration ? statement.declaration : statement;
7628
+ if (declaration?.type === AST_NODE_TYPES36.TSInterfaceDeclaration) names.push(declaration.id.name);
7349
7629
  }
7350
7630
  return names;
7351
7631
  };
@@ -7363,16 +7643,16 @@ var isTransportWrapper = (className, collaborators, program) => {
7363
7643
  var publicMethodNames = (body) => {
7364
7644
  const names = [];
7365
7645
  for (const member of body.body) {
7366
- if (member.type !== AST_NODE_TYPES33.MethodDefinition) continue;
7646
+ if (member.type !== AST_NODE_TYPES36.MethodDefinition) continue;
7367
7647
  if (member.kind !== "method" || member.static) continue;
7368
7648
  if (member.accessibility === "private" || member.accessibility === "protected") continue;
7369
- if (member.key.type === AST_NODE_TYPES33.PrivateIdentifier) continue;
7370
- if (member.key.type === AST_NODE_TYPES33.Identifier) names.push(member.key.name);
7649
+ if (member.key.type === AST_NODE_TYPES36.PrivateIdentifier) continue;
7650
+ if (member.key.type === AST_NODE_TYPES36.Identifier) names.push(member.key.name);
7371
7651
  else names.push("\u2026");
7372
7652
  }
7373
7653
  return names;
7374
7654
  };
7375
- var require_interface_for_injected_service_default = ESLintUtils46.RuleCreator(
7655
+ var require_interface_for_injected_service_default = ESLintUtils50.RuleCreator(
7376
7656
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7377
7657
  )({
7378
7658
  name: "require-interface-for-injected-service",
@@ -7400,7 +7680,7 @@ var require_interface_for_injected_service_default = ESLintUtils46.RuleCreator(
7400
7680
  if (node.implements.length > 0) return;
7401
7681
  if (node.decorators.length > 0) return;
7402
7682
  const ctor = node.body.body.find(
7403
- (member) => member.type === AST_NODE_TYPES33.MethodDefinition && member.kind === "constructor"
7683
+ (member) => member.type === AST_NODE_TYPES36.MethodDefinition && member.kind === "constructor"
7404
7684
  );
7405
7685
  if (ctor === void 0) return;
7406
7686
  const { collaborators, constructedFields } = readConstructor(ctor);
@@ -7425,26 +7705,26 @@ var require_interface_for_injected_service_default = ESLintUtils46.RuleCreator(
7425
7705
  });
7426
7706
 
7427
7707
  // src/rules/prefer-non-nullable-collection.ts
7428
- import { AST_NODE_TYPES as AST_NODE_TYPES34, ESLintUtils as ESLintUtils47 } from "@typescript-eslint/utils";
7708
+ import { AST_NODE_TYPES as AST_NODE_TYPES37, ESLintUtils as ESLintUtils51 } from "@typescript-eslint/utils";
7429
7709
  var ARRAY_TYPE_NAMES = /* @__PURE__ */ new Set(["Array", "ReadonlyArray"]);
7430
7710
  function propertyName(node) {
7431
7711
  const key = node.key;
7432
- if (key.type === AST_NODE_TYPES34.Identifier) return key.name;
7433
- if (key.type === AST_NODE_TYPES34.Literal) return String(key.value);
7712
+ if (key.type === AST_NODE_TYPES37.Identifier) return key.name;
7713
+ if (key.type === AST_NODE_TYPES37.Literal) return String(key.value);
7434
7714
  return "collection";
7435
7715
  }
7436
7716
  function isArrayType(node) {
7437
- if (node.type === AST_NODE_TYPES34.TSArrayType) return true;
7438
- return node.type === AST_NODE_TYPES34.TSTypeReference && node.typeName.type === AST_NODE_TYPES34.Identifier && ARRAY_TYPE_NAMES.has(node.typeName.name);
7717
+ if (node.type === AST_NODE_TYPES37.TSArrayType) return true;
7718
+ return node.type === AST_NODE_TYPES37.TSTypeReference && node.typeName.type === AST_NODE_TYPES37.Identifier && ARRAY_TYPE_NAMES.has(node.typeName.name);
7439
7719
  }
7440
7720
  function isNullishType(node) {
7441
- return node.type === AST_NODE_TYPES34.TSNullKeyword || node.type === AST_NODE_TYPES34.TSUndefinedKeyword;
7721
+ return node.type === AST_NODE_TYPES37.TSNullKeyword || node.type === AST_NODE_TYPES37.TSUndefinedKeyword;
7442
7722
  }
7443
7723
  function isNullableArrayOnly(node) {
7444
7724
  const values = node.types.filter((member) => !isNullishType(member));
7445
7725
  return values.length > 0 && values.length < node.types.length && values.every(isArrayType);
7446
7726
  }
7447
- var prefer_non_nullable_collection_default = ESLintUtils47.RuleCreator(
7727
+ var prefer_non_nullable_collection_default = ESLintUtils51.RuleCreator(
7448
7728
  (name) => `https://github.com/sarj-ai/standards/tree/main/packages/typescript#${name}`
7449
7729
  )({
7450
7730
  name: "prefer-non-nullable-collection",
@@ -7467,7 +7747,7 @@ var prefer_non_nullable_collection_default = ESLintUtils47.RuleCreator(
7467
7747
  function checkOptionalProperty(node) {
7468
7748
  const annotation = node.typeAnnotation?.typeAnnotation;
7469
7749
  if (annotation === void 0) return;
7470
- if (annotation.type !== AST_NODE_TYPES34.TSUnionType || !isNullableArrayOnly(annotation)) {
7750
+ if (annotation.type !== AST_NODE_TYPES37.TSUnionType || !isNullableArrayOnly(annotation)) {
7471
7751
  return;
7472
7752
  }
7473
7753
  context.report({
@@ -7480,7 +7760,7 @@ var prefer_non_nullable_collection_default = ESLintUtils47.RuleCreator(
7480
7760
  TSPropertySignature: checkOptionalProperty,
7481
7761
  PropertyDefinition: checkOptionalProperty,
7482
7762
  TSTypeAliasDeclaration(node) {
7483
- if (node.typeAnnotation.type !== AST_NODE_TYPES34.TSUnionType) return;
7763
+ if (node.typeAnnotation.type !== AST_NODE_TYPES37.TSUnionType) return;
7484
7764
  if (!isNullableArrayOnly(node.typeAnnotation)) return;
7485
7765
  context.report({
7486
7766
  node,
@@ -7492,8 +7772,372 @@ var prefer_non_nullable_collection_default = ESLintUtils47.RuleCreator(
7492
7772
  }
7493
7773
  });
7494
7774
 
7775
+ // src/rules/primary-export-file-name.ts
7776
+ import { AST_NODE_TYPES as AST_NODE_TYPES38, ESLintUtils as ESLintUtils52 } from "@typescript-eslint/utils";
7777
+ var CONVENTIONAL_BUCKET_EXPORTS2 = /* @__PURE__ */ new Set(["cn"]);
7778
+ var GENERIC_ENTRYPOINTS = /* @__PURE__ */ new Set(["main", "run", "cli", "setup", "teardown", "execute"]);
7779
+ var ACRONYM_OVERRIDES2 = [
7780
+ [/OAuth/g, "Oauth"],
7781
+ [/GraphQL/g, "Graphql"],
7782
+ [/gRPC/g, "Grpc"]
7783
+ ];
7784
+ var CAMEL_BOUNDARY_RE2 = /(?<=[a-z0-9])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/g;
7785
+ var basename2 = (filename) => filename.split(/[/\\]/).pop() ?? filename;
7786
+ var stemOf2 = (base) => base.replace(/\.(test|spec|config|d|stories)\.[cm]?[jt]sx?$/i, "").replace(/\.[cm]?[jt]sx?$/i, "");
7787
+ var kebabCase3 = (name) => {
7788
+ let normalized = name;
7789
+ for (const [pattern, replacement] of ACRONYM_OVERRIDES2) {
7790
+ normalized = normalized.replace(pattern, replacement);
7791
+ }
7792
+ return normalized.replace(CAMEL_BOUNDARY_RE2, "-").toLowerCase();
7793
+ };
7794
+ var isFunctionOrClass = (node) => node.type === AST_NODE_TYPES38.ArrowFunctionExpression || node.type === AST_NODE_TYPES38.FunctionExpression;
7795
+ var findPrimaryExport = (body) => {
7796
+ let exportCount = 0;
7797
+ let primaryCandidate = null;
7798
+ for (const statement of body) {
7799
+ if (statement.type === AST_NODE_TYPES38.ExportAllDeclaration) {
7800
+ return null;
7801
+ }
7802
+ if (statement.type === AST_NODE_TYPES38.ExportDefaultDeclaration) {
7803
+ exportCount += 1;
7804
+ const decl = statement.declaration;
7805
+ if ((decl.type === AST_NODE_TYPES38.FunctionDeclaration || decl.type === AST_NODE_TYPES38.ClassDeclaration) && decl.id !== null) {
7806
+ primaryCandidate = { name: decl.id.name, node: statement, isDefault: true };
7807
+ } else if (decl.type === AST_NODE_TYPES38.Identifier) {
7808
+ primaryCandidate = { name: decl.name, node: statement, isDefault: true };
7809
+ }
7810
+ } else if (statement.type === AST_NODE_TYPES38.ExportNamedDeclaration) {
7811
+ if (statement.source !== null) {
7812
+ return null;
7813
+ }
7814
+ const decl = statement.declaration;
7815
+ if (decl === null) {
7816
+ exportCount += statement.specifiers.length;
7817
+ if (statement.specifiers.length === 1 && primaryCandidate === null) {
7818
+ const spec = statement.specifiers[0];
7819
+ if (spec && spec.exported.type === AST_NODE_TYPES38.Identifier) {
7820
+ primaryCandidate = { name: spec.exported.name, node: statement, isDefault: false };
7821
+ }
7822
+ }
7823
+ } else if (decl.type === AST_NODE_TYPES38.FunctionDeclaration || decl.type === AST_NODE_TYPES38.ClassDeclaration) {
7824
+ if (decl.id !== null) {
7825
+ exportCount += 1;
7826
+ if (primaryCandidate === null) {
7827
+ primaryCandidate = { name: decl.id.name, node: statement, isDefault: false };
7828
+ }
7829
+ }
7830
+ } else if (decl.type === AST_NODE_TYPES38.VariableDeclaration) {
7831
+ for (const declarator of decl.declarations) {
7832
+ if (declarator.id.type === AST_NODE_TYPES38.Identifier) {
7833
+ exportCount += 1;
7834
+ if (primaryCandidate === null && declarator.init && isFunctionOrClass(declarator.init)) {
7835
+ primaryCandidate = { name: declarator.id.name, node: statement, isDefault: false };
7836
+ }
7837
+ }
7838
+ }
7839
+ } else if (decl.type === AST_NODE_TYPES38.TSTypeAliasDeclaration || decl.type === AST_NODE_TYPES38.TSInterfaceDeclaration) {
7840
+ exportCount += 1;
7841
+ if (primaryCandidate === null) {
7842
+ primaryCandidate = { name: decl.id.name, node: statement, isDefault: false };
7843
+ }
7844
+ }
7845
+ }
7846
+ }
7847
+ if (primaryCandidate === null || exportCount > 2) {
7848
+ return null;
7849
+ }
7850
+ return { ...primaryCandidate, count: exportCount };
7851
+ };
7852
+ var primary_export_file_name_default = ESLintUtils52.RuleCreator(
7853
+ (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7854
+ )({
7855
+ name: "primary-export-file-name",
7856
+ meta: {
7857
+ type: "suggestion",
7858
+ docs: {
7859
+ description: "Enforce semantic naming alignment: a file with a single primary export must be named after that export."
7860
+ },
7861
+ schema: [],
7862
+ messages: {
7863
+ primaryExportMismatch: "Module stem '{{stem}}' does not match its primary export '{{name}}' \u2014 rename the file to '{{expected}}{{ext}}' to describe its responsibility."
7864
+ }
7865
+ },
7866
+ defaultOptions: [],
7867
+ create(context) {
7868
+ const base = basename2(context.filename);
7869
+ if (base.endsWith(".d.ts") || base.startsWith("index.") || base.startsWith("_")) return {};
7870
+ if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
7871
+ const stem3 = stemOf2(base);
7872
+ if (stem3 === "page" || stem3 === "layout" || stem3 === "loading" || stem3 === "error" || stem3 === "not-found" || stem3 === "route" || stem3 === "__root" || stem3 === "config" || stem3 === "constants" || stem3 === "types" || stem3.startsWith("$") || stem3.startsWith("[")) {
7873
+ return {};
7874
+ }
7875
+ return {
7876
+ Program(node) {
7877
+ const primary = findPrimaryExport(node.body);
7878
+ if (primary === null) return;
7879
+ if (CONVENTIONAL_BUCKET_EXPORTS2.has(primary.name) || GENERIC_ENTRYPOINTS.has(primary.name)) return;
7880
+ const expectedStem = kebabCase3(primary.name);
7881
+ if (stem3 === expectedStem) return;
7882
+ const ext = base.endsWith(".tsx") ? ".tsx" : ".ts";
7883
+ context.report({
7884
+ node: primary.node,
7885
+ messageId: "primaryExportMismatch",
7886
+ data: { stem: stem3, name: primary.name, expected: expectedStem, ext }
7887
+ });
7888
+ }
7889
+ };
7890
+ }
7891
+ });
7892
+
7893
+ // src/rules/no-implicit-attribute-access.ts
7894
+ import { AST_NODE_TYPES as AST_NODE_TYPES39, ESLintUtils as ESLintUtils53 } from "@typescript-eslint/utils";
7895
+ var EXCLUDED_BASES = /* @__PURE__ */ new Set([
7896
+ "environ",
7897
+ "headers",
7898
+ "cookies",
7899
+ "session",
7900
+ "redis",
7901
+ "cache",
7902
+ "state",
7903
+ "config",
7904
+ "env",
7905
+ "process",
7906
+ "localStorage",
7907
+ "sessionStorage"
7908
+ ]);
7909
+ function getBaseName(node) {
7910
+ if (node.type === AST_NODE_TYPES39.Identifier) {
7911
+ return node.name;
7912
+ }
7913
+ if (node.type === AST_NODE_TYPES39.MemberExpression && node.property.type === AST_NODE_TYPES39.Identifier) {
7914
+ return node.property.name;
7915
+ }
7916
+ return null;
7917
+ }
7918
+ var no_implicit_attribute_access_default = ESLintUtils53.RuleCreator(
7919
+ (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7920
+ )({
7921
+ name: "no-implicit-attribute-access",
7922
+ meta: {
7923
+ type: "problem",
7924
+ docs: {
7925
+ description: "Disallow imperative dictionary access with string literals; use declarative Zod schemas."
7926
+ },
7927
+ schema: [],
7928
+ messages: {
7929
+ noImplicitAttributeAccess: "Imperative lookup for '{{key}}' \u2014 if the key is known, parse the object declaratively with a Zod schema instead."
7930
+ }
7931
+ },
7932
+ defaultOptions: [],
7933
+ create(context) {
7934
+ return {
7935
+ MemberExpression(node) {
7936
+ if (!node.computed) {
7937
+ return;
7938
+ }
7939
+ if (node.property.type === AST_NODE_TYPES39.Literal && typeof node.property.value === "string") {
7940
+ const baseName = getBaseName(node.object);
7941
+ if (!baseName || !EXCLUDED_BASES.has(baseName)) {
7942
+ context.report({
7943
+ node,
7944
+ messageId: "noImplicitAttributeAccess",
7945
+ data: { key: node.property.value }
7946
+ });
7947
+ }
7948
+ }
7949
+ },
7950
+ CallExpression(node) {
7951
+ const callee = node.callee;
7952
+ if (callee.type === AST_NODE_TYPES39.MemberExpression) {
7953
+ const method = callee.property.type === AST_NODE_TYPES39.Identifier ? callee.property.name : null;
7954
+ if (method === "get") {
7955
+ const arg = node.arguments[0];
7956
+ if (arg && arg.type === AST_NODE_TYPES39.Literal && typeof arg.value === "string") {
7957
+ const baseName = getBaseName(callee.object);
7958
+ if (!baseName || !EXCLUDED_BASES.has(baseName)) {
7959
+ context.report({
7960
+ node,
7961
+ messageId: "noImplicitAttributeAccess",
7962
+ data: { key: arg.value }
7963
+ });
7964
+ }
7965
+ }
7966
+ }
7967
+ }
7968
+ }
7969
+ };
7970
+ }
7971
+ });
7972
+
7973
+ // src/rules/strict-test-assertions.ts
7974
+ import { AST_NODE_TYPES as AST_NODE_TYPES40, ESLintUtils as ESLintUtils54 } from "@typescript-eslint/utils";
7975
+ var strict_test_assertions_default = ESLintUtils54.RuleCreator.withoutDocs({
7976
+ meta: {
7977
+ type: "suggestion",
7978
+ docs: {
7979
+ description: "Replace multiple sequential assertions with a single toMatchObject or toStrictEqual"
7980
+ },
7981
+ fixable: "code",
7982
+ messages: {
7983
+ combineAssertions: "Combine multiple sequential assertions on the same object into a single toMatchObject or toStrictEqual"
7984
+ },
7985
+ schema: []
7986
+ },
7987
+ defaultOptions: [],
7988
+ create(context) {
7989
+ function checkBody(body) {
7990
+ let currentObject = null;
7991
+ let sequence = [];
7992
+ function getExpectObject(expr) {
7993
+ if (expr.type === AST_NODE_TYPES40.CallExpression && expr.callee.type === AST_NODE_TYPES40.MemberExpression && expr.callee.object.type === AST_NODE_TYPES40.CallExpression && expr.callee.object.callee.type === AST_NODE_TYPES40.Identifier && expr.callee.object.callee.name === "expect" && expr.callee.object.arguments.length === 1) {
7994
+ const arg = expr.callee.object.arguments.at(0);
7995
+ if (arg?.type === AST_NODE_TYPES40.MemberExpression) {
7996
+ return arg.object;
7997
+ }
7998
+ }
7999
+ return null;
8000
+ }
8001
+ function reportSequence() {
8002
+ const first = sequence.at(0);
8003
+ if (sequence.length > 1 && first) {
8004
+ context.report({
8005
+ node: first,
8006
+ messageId: "combineAssertions",
8007
+ fix(fixer) {
8008
+ if (!currentObject) return null;
8009
+ const objectText = context.sourceCode.getText(currentObject);
8010
+ const props = sequence.map((stmt) => {
8011
+ if (stmt.expression.type !== AST_NODE_TYPES40.CallExpression || stmt.expression.callee.type !== AST_NODE_TYPES40.MemberExpression || stmt.expression.callee.object.type !== AST_NODE_TYPES40.CallExpression) {
8012
+ return null;
8013
+ }
8014
+ const actual = stmt.expression.callee.object.arguments.at(0);
8015
+ const expected = stmt.expression.arguments.at(0);
8016
+ if (actual?.type === AST_NODE_TYPES40.MemberExpression && actual.property.type === AST_NODE_TYPES40.Identifier && expected) {
8017
+ const propName2 = actual.property.name;
8018
+ const valText = context.sourceCode.getText(expected);
8019
+ return `${propName2}: ${valText}`;
8020
+ }
8021
+ return null;
8022
+ });
8023
+ if (props.some((p) => p === null)) return null;
8024
+ const replacement = `expect(${objectText}).toMatchObject({ ${props.join(", ")} });`;
8025
+ return [
8026
+ fixer.replaceText(first, replacement),
8027
+ ...sequence.slice(1).map((stmt) => fixer.remove(stmt))
8028
+ ];
8029
+ }
8030
+ });
8031
+ }
8032
+ }
8033
+ for (const statement of body) {
8034
+ if (statement.type === AST_NODE_TYPES40.ExpressionStatement) {
8035
+ const obj = getExpectObject(statement.expression);
8036
+ if (obj && currentObject && context.sourceCode.getText(obj) === context.sourceCode.getText(currentObject)) {
8037
+ sequence.push(statement);
8038
+ } else {
8039
+ reportSequence();
8040
+ if (obj) {
8041
+ currentObject = obj;
8042
+ sequence = [statement];
8043
+ } else {
8044
+ currentObject = null;
8045
+ sequence = [];
8046
+ }
8047
+ }
8048
+ } else {
8049
+ reportSequence();
8050
+ currentObject = null;
8051
+ sequence = [];
8052
+ }
8053
+ }
8054
+ reportSequence();
8055
+ }
8056
+ return {
8057
+ BlockStatement(node) {
8058
+ checkBody(node.body);
8059
+ },
8060
+ Program(node) {
8061
+ checkBody(node.body);
8062
+ }
8063
+ };
8064
+ }
8065
+ });
8066
+
8067
+ // src/rules/no-async-callback-in-waitfor.ts
8068
+ import { AST_NODE_TYPES as AST_NODE_TYPES41, ESLintUtils as ESLintUtils55 } from "@typescript-eslint/utils";
8069
+ var no_async_callback_in_waitfor_default = ESLintUtils55.RuleCreator(
8070
+ (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
8071
+ )({
8072
+ name: "no-async-callback-in-waitfor",
8073
+ meta: {
8074
+ type: "problem",
8075
+ docs: {
8076
+ description: "Disallow async callbacks in `waitFor` to prevent swallowed promise rejections."
8077
+ },
8078
+ schema: [],
8079
+ messages: {
8080
+ noAsyncCallbackInWaitFor: "The callback to `waitFor` should not be async. It expects synchronous assertions and runs the callback repeatedly."
8081
+ }
8082
+ },
8083
+ defaultOptions: [],
8084
+ create(context) {
8085
+ if (!isTestFile(context.filename)) {
8086
+ return {};
8087
+ }
8088
+ return {
8089
+ CallExpression(node) {
8090
+ if (node.callee.type === AST_NODE_TYPES41.Identifier && node.callee.name === "waitFor") {
8091
+ const callback = node.arguments[0];
8092
+ if (callback && (callback.type === AST_NODE_TYPES41.ArrowFunctionExpression || callback.type === AST_NODE_TYPES41.FunctionExpression) && callback.async) {
8093
+ context.report({
8094
+ node: callback,
8095
+ messageId: "noAsyncCallbackInWaitFor"
8096
+ });
8097
+ }
8098
+ }
8099
+ }
8100
+ };
8101
+ }
8102
+ });
8103
+
8104
+ // src/rules/prefer-setup-file-mocks.ts
8105
+ import { AST_NODE_TYPES as AST_NODE_TYPES42, ESLintUtils as ESLintUtils56 } from "@typescript-eslint/utils";
8106
+ var prefer_setup_file_mocks_default = ESLintUtils56.RuleCreator(
8107
+ (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
8108
+ )({
8109
+ name: "prefer-setup-file-mocks",
8110
+ meta: {
8111
+ type: "suggestion",
8112
+ docs: {
8113
+ description: "Prefer defining module mocks in setup files rather than using vi.mock or jest.mock inline in test files."
8114
+ },
8115
+ schema: [],
8116
+ messages: {
8117
+ preferSetupFileMocks: "Define module mocks in a setup file (e.g. vitest.setup.ts) instead of using vi.mock or jest.mock directly in test files."
8118
+ }
8119
+ },
8120
+ defaultOptions: [],
8121
+ create(context) {
8122
+ if (!isTestFile(context.filename)) {
8123
+ return {};
8124
+ }
8125
+ return {
8126
+ CallExpression(node) {
8127
+ if (node.callee.type === AST_NODE_TYPES42.MemberExpression && node.callee.object.type === AST_NODE_TYPES42.Identifier && (node.callee.object.name === "vi" || node.callee.object.name === "jest") && node.callee.property.type === AST_NODE_TYPES42.Identifier && node.callee.property.name === "mock") {
8128
+ context.report({
8129
+ node,
8130
+ messageId: "preferSetupFileMocks"
8131
+ });
8132
+ }
8133
+ }
8134
+ };
8135
+ }
8136
+ });
8137
+
7495
8138
  // src/index.ts
7496
8139
  var rules = {
8140
+ "ban-loose-type-guards-in-tests": ban_loose_type_guards_in_tests_default,
7497
8141
  "enforce-file-structure": enforce_file_structure_default,
7498
8142
  "no-client-side-data-fetching": no_client_side_data_fetching_default,
7499
8143
  "no-comment-cruft": no_comment_cruft_default,
@@ -7518,8 +8162,11 @@ var rules = {
7518
8162
  "no-fat-try-blocks": no_fat_try_blocks_default,
7519
8163
  "no-secret-in-log": no_secret_in_log_default,
7520
8164
  "no-unsafe-cast": no_unsafe_cast_default,
8165
+ "no-unsafe-mock-casting": no_unsafe_mock_casting_default,
7521
8166
  "prefer-string-literal-union": prefer_string_literal_union_default,
8167
+ "prefer-zod-enum": prefer_zod_enum_default,
7522
8168
  "single-public-export": single_public_export_default,
8169
+ "primary-export-file-name": primary_export_file_name_default,
7523
8170
  "no-silent-promise-catch": no_silent_promise_catch_default,
7524
8171
  "require-fetch-timeout": require_fetch_timeout_default,
7525
8172
  "require-schema-validate-search": require_schema_validate_search_default,
@@ -7528,6 +8175,7 @@ var rules = {
7528
8175
  "no-repeated-string-literal": no_repeated_string_literal_default,
7529
8176
  "no-select-star": no_select_star_default,
7530
8177
  "no-sleep-in-test-body": no_sleep_in_test_body_default,
8178
+ "no-conditional-in-test": no_conditional_in_test_default,
7531
8179
  "prefer-constant-time-secret-compare": prefer_constant_time_secret_compare_default,
7532
8180
  "store-insert-requires-on-conflict": store_insert_requires_on_conflict_default,
7533
8181
  "no-dynamic-sql": no_dynamic_sql_default,
@@ -7540,12 +8188,16 @@ var rules = {
7540
8188
  "trailing-value-narration": trailing_value_narration_default,
7541
8189
  "no-tautological-expect": no_tautological_expect_default,
7542
8190
  "require-interface-for-injected-service": require_interface_for_injected_service_default,
7543
- "prefer-non-nullable-collection": prefer_non_nullable_collection_default
8191
+ "strict-test-assertions": strict_test_assertions_default,
8192
+ "prefer-non-nullable-collection": prefer_non_nullable_collection_default,
8193
+ "no-implicit-attribute-access": no_implicit_attribute_access_default,
8194
+ "no-async-callback-in-waitfor": no_async_callback_in_waitfor_default,
8195
+ "prefer-setup-file-mocks": prefer_setup_file_mocks_default
7544
8196
  };
7545
8197
  var plugin = {
7546
8198
  meta: {
7547
8199
  name: "@sarj/eslint-plugin",
7548
- version: "2.15.0"
8200
+ version: "2.17.0"
7549
8201
  },
7550
8202
  rules,
7551
8203
  configs: {
@@ -7555,6 +8207,7 @@ var plugin = {
7555
8207
  "@sarj/zod-naming-convention": "warn",
7556
8208
  "@sarj/require-assert-never": "error",
7557
8209
  "@sarj/require-zod-form-validation": "error",
8210
+ "@sarj/ban-loose-type-guards-in-tests": "error",
7558
8211
  "@sarj/enforce-file-structure": "warn",
7559
8212
  "@sarj/no-client-side-data-fetching": "warn",
7560
8213
  "@sarj/prefer-server-actions": "warn",
@@ -7579,8 +8232,11 @@ var plugin = {
7579
8232
  "@sarj/no-cors-wildcard-with-credentials": "warn",
7580
8233
  "@sarj/no-secret-in-log": "warn",
7581
8234
  "@sarj/no-unsafe-cast": "warn",
8235
+ "@sarj/no-unsafe-mock-casting": "warn",
7582
8236
  "@sarj/single-public-export": "warn",
8237
+ "@sarj/primary-export-file-name": "warn",
7583
8238
  "@sarj/prefer-string-literal-union": "warn",
8239
+ "@sarj/prefer-zod-enum": "warn",
7584
8240
  // Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).
7585
8241
  "@sarj/require-fetch-timeout": "warn",
7586
8242
  "@sarj/no-silent-promise-catch": "warn",
@@ -7594,6 +8250,7 @@ var plugin = {
7594
8250
  "@sarj/no-offset-pagination": "warn",
7595
8251
  "@sarj/no-select-star": "warn",
7596
8252
  "@sarj/no-sleep-in-test-body": "warn",
8253
+ "@sarj/no-conditional-in-test": "warn",
7597
8254
  "@sarj/no-repeated-string-literal": "warn",
7598
8255
  "@sarj/no-positional-tuple-return": "warn",
7599
8256
  // Injection guard — low FP, applies to any repo touching SQL.
@@ -7629,7 +8286,10 @@ var plugin = {
7629
8286
  // mocking. 11-repo sweep: 229 exported classes, 82% already carry a
7630
8287
  // port, 29 fire, 28 of them true positives.
7631
8288
  "@sarj/require-interface-for-injected-service": "warn",
7632
- "@sarj/prefer-non-nullable-collection": "warn"
8289
+ "@sarj/prefer-non-nullable-collection": "warn",
8290
+ "@sarj/no-implicit-attribute-access": "warn",
8291
+ "@sarj/no-async-callback-in-waitfor": "warn",
8292
+ "@sarj/prefer-setup-file-mocks": "warn"
7633
8293
  }
7634
8294
  },
7635
8295
  strict: {
@@ -7638,6 +8298,7 @@ var plugin = {
7638
8298
  "@sarj/zod-naming-convention": "error",
7639
8299
  "@sarj/require-assert-never": "error",
7640
8300
  "@sarj/require-zod-form-validation": "error",
8301
+ "@sarj/ban-loose-type-guards-in-tests": "error",
7641
8302
  "@sarj/enforce-file-structure": "error",
7642
8303
  "@sarj/no-raw-env": "error",
7643
8304
  "@sarj/prefer-shadcn": "error",
@@ -7666,9 +8327,12 @@ var plugin = {
7666
8327
  "@sarj/no-cors-wildcard-with-credentials": "error",
7667
8328
  "@sarj/no-secret-in-log": "error",
7668
8329
  "@sarj/no-unsafe-cast": "error",
8330
+ "@sarj/no-unsafe-mock-casting": "error",
7669
8331
  "@sarj/single-public-export": "error",
8332
+ "@sarj/primary-export-file-name": "error",
7670
8333
  // Promoted to error 2026-07-25 — strict means strict (user directive).
7671
8334
  "@sarj/prefer-string-literal-union": "error",
8335
+ "@sarj/prefer-zod-enum": "error",
7672
8336
  // Mined from 2y of PR review feedback + 5-repo code-smell audit (2026-07).
7673
8337
  "@sarj/require-fetch-timeout": "error",
7674
8338
  "@sarj/no-silent-promise-catch": "error",
@@ -7679,6 +8343,7 @@ var plugin = {
7679
8343
  "@sarj/no-offset-pagination": "error",
7680
8344
  "@sarj/no-select-star": "error",
7681
8345
  "@sarj/no-sleep-in-test-body": "error",
8346
+ "@sarj/no-conditional-in-test": "error",
7682
8347
  "@sarj/no-repeated-string-literal": "error",
7683
8348
  // API-shape advice rather than a runtime defect — a corpus sweep found its
7684
8349
  // only hits are parser `[value, cursor]` returns, which are conventional.
@@ -7707,7 +8372,10 @@ var plugin = {
7707
8372
  // / `prefer-library-fake` wave. The convention already exists in the
7708
8373
  // corpus (175 `implements` clauses vs 29 hits), so strict enforces it.
7709
8374
  "@sarj/require-interface-for-injected-service": "error",
7710
- "@sarj/prefer-non-nullable-collection": "error"
8375
+ "@sarj/prefer-non-nullable-collection": "error",
8376
+ "@sarj/no-implicit-attribute-access": "error",
8377
+ "@sarj/no-async-callback-in-waitfor": "error",
8378
+ "@sarj/prefer-setup-file-mocks": "error"
7711
8379
  }
7712
8380
  }
7713
8381
  }