@sarj/eslint-plugin 4.2.0 → 5.1.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,10 +1,11 @@
1
- // src/rules/ban-loose-type-guards-in-tests.ts
2
- import { ESLintUtils } from "@typescript-eslint/utils";
1
+ // src/rules/enforce-file-structure.ts
2
+ import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
3
3
 
4
4
  // src/rules/_paths.ts
5
5
  var SCRIPT_FILE_RE = /([\\/]scripts[\\/])|(\.mjs$)/;
6
6
  var STORY_FILE_RE = /\.stories\.[cm]?[jt]sx?$/i;
7
- var GENERATED_FILE_RE = /([\\/](?:generated|openapi-gen|graphql[\\/]types)[\\/])|(\.gen\.[cm]?[jt]sx?$)|(\.generated\.[cm]?[jt]sx?$)|(\.d\.[cm]?ts$)|(\.types\.[cm]?ts$)/;
7
+ var STORY_DIR_RE = /(^|\/)stories(?:[_-][^/]*)?\//i;
8
+ var GENERATED_FILE_RE = /([\\/](?:generated|openapi-gen|graphql[\\/]types|vendor|vendored|external|third[-_]?party)[\\/])|(\.gen\.[cm]?[jt]sx?$)|(\.generated\.[cm]?[jt]sx?$)|(\.d\.[cm]?ts$)|(\.types\.[cm]?ts$)/;
8
9
  var GENERATED_MARKER_RE = /(?:@generated\b|generated (?:with|by)|generated (?:graphql )?types|do not edit(?: directly| manually)?)/i;
9
10
  function isTestFile(filename) {
10
11
  const normalized = filename.replaceAll("\\", "/");
@@ -12,10 +13,13 @@ function isTestFile(filename) {
12
13
  if (/[.\-_](test|spec|e2e)\.[cm]?[jt]sx?$/.test(base) || /\.integration\.[cm]?[jt]sx?$/.test(base)) {
13
14
  return true;
14
15
  }
15
- return /(^|\/)(tests?|__tests__|__mocks__|fixtures|e2e|integration)\//.test(normalized);
16
+ return /(^|\/)(tests?|__tests__|__mocks__|__fixtures__|__testfixtures__|fixtures?|e2e|integration)\//.test(
17
+ normalized
18
+ );
16
19
  }
17
20
  function isStoryFile(filename) {
18
- return STORY_FILE_RE.test(filename);
21
+ const normalized = filename.replaceAll("\\", "/");
22
+ return STORY_FILE_RE.test(normalized) || STORY_DIR_RE.test(normalized);
19
23
  }
20
24
  function isGeneratedFile(filename, sourceText = "") {
21
25
  return GENERATED_FILE_RE.test(filename.replaceAll("\\", "/")) || GENERATED_MARKER_RE.test(sourceText.slice(0, 2048));
@@ -24,43 +28,7 @@ function isScriptFile(filename) {
24
28
  return SCRIPT_FILE_RE.test(filename);
25
29
  }
26
30
 
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
-
62
31
  // src/rules/enforce-file-structure.ts
63
- import { ESLintUtils as ESLintUtils2, AST_NODE_TYPES } from "@typescript-eslint/utils";
64
32
  var classifyStatement = (statement) => {
65
33
  switch (statement.type) {
66
34
  case AST_NODE_TYPES.ImportDeclaration:
@@ -80,7 +48,7 @@ var isUseServerDirective = (statement) => {
80
48
  if (expr.type !== AST_NODE_TYPES.Literal) return false;
81
49
  return expr.value === "use server";
82
50
  };
83
- var enforce_file_structure_default = ESLintUtils2.RuleCreator(
51
+ var enforce_file_structure_default = ESLintUtils.RuleCreator(
84
52
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
85
53
  )({
86
54
  name: "enforce-file-structure",
@@ -142,7 +110,7 @@ var enforce_file_structure_default = ESLintUtils2.RuleCreator(
142
110
  // src/rules/no-client-side-data-fetching.ts
143
111
  import {
144
112
  AST_NODE_TYPES as AST_NODE_TYPES2,
145
- ESLintUtils as ESLintUtils3
113
+ ESLintUtils as ESLintUtils2
146
114
  } from "@typescript-eslint/utils";
147
115
  var FETCH_LIBS = /* @__PURE__ */ new Set(["axios", "ky", "superagent"]);
148
116
  var HTTP_METHOD_NAMES = /* @__PURE__ */ new Set([
@@ -240,7 +208,7 @@ function isAnalyticsCall(node) {
240
208
  if (url === "") return false;
241
209
  return url.split(/[/.]/).some((segment) => ANALYTICS_SEGMENTS.has(segment));
242
210
  }
243
- var no_client_side_data_fetching_default = ESLintUtils3.RuleCreator(
211
+ var no_client_side_data_fetching_default = ESLintUtils2.RuleCreator(
244
212
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
245
213
  )({
246
214
  name: "no-client-side-data-fetching",
@@ -278,7 +246,7 @@ var no_client_side_data_fetching_default = ESLintUtils3.RuleCreator(
278
246
  });
279
247
 
280
248
  // src/rules/no-comment-cruft.ts
281
- import { AST_NODE_TYPES as AST_NODE_TYPES4, ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
249
+ import { AST_NODE_TYPES as AST_NODE_TYPES4, ESLintUtils as ESLintUtils3 } from "@typescript-eslint/utils";
282
250
 
283
251
  // src/rules/_comments.ts
284
252
  import { AST_NODE_TYPES as AST_NODE_TYPES3 } from "@typescript-eslint/utils";
@@ -542,7 +510,8 @@ var DUMMY_TRANSLATION_RE = /^(?:increment|return|returns|get|gets|set\b(?! up\b)
542
510
  var DIAGRAM_ARROW_RE = /[-=~]{2,}>|<[-=~]{2,}/;
543
511
  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\.)/;
544
512
  var CODE_TAIL_RE = /[;{}()]\s*$|=>\s*$|,\s*$/;
545
- var CALL_OR_ASSIGN_RE = /^[A-Za-z_$][\w.$[\]]*\s*(?:=(?![=>])|\+=|-=|\*=)\s*\S.*[;)}\]]\s*$|^[A-Za-z_$][\w.$]*\([^)]*\)\s*;?\s*$/;
513
+ var ASSIGN_RE = /^[A-Za-z_$][\w.$[\]]*\s*(?:=(?![=>])|\+=|-=|\*=)\s*\S.*[;)}\]]\s*$/;
514
+ var CALL_RE = /^[A-Za-z_$][\w.$]*\([^)]*\)\s*;?\s*$/;
546
515
  var PSEUDOCODE_RE = /%\w+%|\[opt\]|(?:^|\s)<[A-Za-z]\w*>|…|\.\.\./;
547
516
  function stripCommentMarker(line) {
548
517
  return line.replace(/^\s*\/{1,2}/, "").replace(/^\s*\*+/, "").trim();
@@ -556,11 +525,12 @@ function isBanner(text) {
556
525
  if (BANNER_FULL_RE.test(t) || isRegionMarker(t)) return true;
557
526
  return BANNER_RUN_RE.test(t) && !DIAGRAM_ARROW_RE.test(t);
558
527
  }
559
- function looksLikeCode(text) {
528
+ function looksLikeCode(text, allowCall = true) {
560
529
  const t = text.trim();
561
530
  if (!t) return false;
562
531
  if (CODE_KEYWORD_RE.test(t) && CODE_TAIL_RE.test(t)) return true;
563
- return CALL_OR_ASSIGN_RE.test(t);
532
+ if (ASSIGN_RE.test(t)) return true;
533
+ return allowCall && CALL_RE.test(t);
564
534
  }
565
535
  function hasPseudocode(text) {
566
536
  return PSEUDOCODE_RE.test(text);
@@ -578,20 +548,24 @@ function isProse(text) {
578
548
  }
579
549
  return false;
580
550
  }
581
- var JUSTIFICATION_RE = /\b(?:because|since|until|due to|so that|otherwise|which is why|in order to|to avoid|to work around|to prevent)\b/i;
551
+ var JUSTIFICATION_RE = /\b(?:because|since|until|due to|so that|so we|so it|so the|otherwise|which is why|in order to|to avoid|to work around|to prevent|backwards? compat(?:ibility)?|for compatibility)\b/i;
552
+ function restatesWholeStatement(body, statement) {
553
+ return statement !== null && restatesStatementHead(body, statement.replaceAll("(", " "));
554
+ }
582
555
  function isRedundantNarration(body, statementBelow, standalone, isolatedEnumeration, nested) {
583
556
  const t = body.trim();
584
557
  if (!t || looksLikeCode(t) || hasPseudocode(t)) return false;
585
558
  if (standalone) {
586
- if (STEP_NARRATION_RE.test(t)) return true;
587
- if (META_COMMENTARY_RE.test(t) && !JUSTIFICATION_RE.test(t)) return true;
559
+ const justified = JUSTIFICATION_RE.test(t);
560
+ if (STEP_NARRATION_RE.test(t) && !justified) return true;
561
+ if (META_COMMENTARY_RE.test(t) && !justified) return true;
588
562
  if (HELPER_OPENER_RE.test(t) || LETS_RE.test(t)) return true;
589
563
  const words = t.split(/\s+/);
590
- if (words.length <= 4 && DUMMY_TRANSLATION_RE.test(t) && !/[():=]/.test(t)) {
564
+ if (words.length > 1 && words.length <= 4 && DUMMY_TRANSLATION_RE.test(t) && !/[():=]/.test(t)) {
591
565
  const lowerT = t.toLowerCase();
592
566
  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;
567
+ if (!rationaleWords.some((w) => lowerT.includes(w)) && restatesWholeStatement(t, statementBelow)) {
568
+ return true;
595
569
  }
596
570
  }
597
571
  if (!nested && isSectionLabel(t)) return true;
@@ -608,6 +582,10 @@ var STATEMENT_CONTAINERS = /* @__PURE__ */ new Set([
608
582
  AST_NODE_TYPES4.TSModuleBlock,
609
583
  AST_NODE_TYPES4.TSInterfaceBody
610
584
  ]);
585
+ var TYPE_MEMBER_CONTAINERS = /* @__PURE__ */ new Set([
586
+ AST_NODE_TYPES4.TSInterfaceBody,
587
+ AST_NODE_TYPES4.TSTypeLiteral
588
+ ]);
611
589
  function runCitesAReference(comments, index) {
612
590
  for (let i = index; i >= 0; i--) {
613
591
  if (i < index && !areAdjacentLineComments(comments[i], comments[i + 1])) break;
@@ -635,10 +613,10 @@ function hasIllustrationLeadInAbove(comments, index) {
635
613
  }
636
614
  return false;
637
615
  }
638
- function hasCommentedOutCode(texts, precedingProse) {
616
+ function hasCommentedOutCode(texts, precedingProse, allowCall) {
639
617
  for (let i = 0; i < texts.length; i++) {
640
618
  const line = texts[i];
641
- if (line === void 0 || !looksLikeCode(line) || hasPseudocode(line)) {
619
+ if (line === void 0 || !looksLikeCode(line, allowCall) || hasPseudocode(line)) {
642
620
  continue;
643
621
  }
644
622
  const prev = i > 0 ? texts[i - 1] : void 0;
@@ -647,7 +625,7 @@ function hasCommentedOutCode(texts, precedingProse) {
647
625
  }
648
626
  return false;
649
627
  }
650
- var no_comment_cruft_default = ESLintUtils4.RuleCreator(
628
+ var no_comment_cruft_default = ESLintUtils3.RuleCreator(
651
629
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
652
630
  )({
653
631
  name: "no-comment-cruft",
@@ -732,7 +710,9 @@ var no_comment_cruft_default = ESLintUtils4.RuleCreator(
732
710
  }
733
711
  const prev = comments[i - 1];
734
712
  const precedingProse = prev !== void 0 && prev.type === "Line" && prev.loc.end.line === comment.loc.start.line - 1 && isProse(stripCommentMarker(prev.value));
735
- if (hasCommentedOutCode(texts, precedingProse) && !hasIllustrationLeadInAbove(comments, i)) {
713
+ const container = sourceCode.getNodeByRangeIndex(comment.range[0]);
714
+ const inTypeMembers = container !== null && TYPE_MEMBER_CONTAINERS.has(container.type);
715
+ if (hasCommentedOutCode(texts, precedingProse, !inTypeMembers) && !hasIllustrationLeadInAbove(comments, i)) {
736
716
  context.report({ node: comment, messageId: "commentedOutCode" });
737
717
  continue;
738
718
  }
@@ -740,7 +720,6 @@ var no_comment_cruft_default = ESLintUtils4.RuleCreator(
740
720
  const body = texts[0];
741
721
  const statement = restatableStatementBelow(comment, sourceCode);
742
722
  const standalone = !isInsideCommentRun(comments, i);
743
- const container = sourceCode.getNodeByRangeIndex(comment.range[0]);
744
723
  const nested = container !== null && !STATEMENT_CONTAINERS.has(container.type);
745
724
  if (body !== void 0 && !runCitesAReference(comments, i) && isRedundantNarration(body, statement, standalone, enumerated.length === 1, nested)) {
746
725
  context.report({ node: comment, messageId: "redundantNarration" });
@@ -754,7 +733,7 @@ var no_comment_cruft_default = ESLintUtils4.RuleCreator(
754
733
  });
755
734
 
756
735
  // src/rules/no-enum.ts
757
- import { ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
736
+ import { ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
758
737
  var DEFAULT_IGNORE_PATTERNS = [
759
738
  /[\\/]generated[\\/]/,
760
739
  /[\\/]openapi-gen[\\/]/,
@@ -774,7 +753,7 @@ function hasGeneratedMarker(sourceText) {
774
753
  const head = sourceText.slice(0, 1024);
775
754
  return /@generated\b/.test(head);
776
755
  }
777
- var no_enum_default = ESLintUtils5.RuleCreator(
756
+ var no_enum_default = ESLintUtils4.RuleCreator(
778
757
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
779
758
  )({
780
759
  name: "no-enum",
@@ -825,7 +804,7 @@ var no_enum_default = ESLintUtils5.RuleCreator(
825
804
  });
826
805
 
827
806
  // src/rules/no-insecure-random-id.ts
828
- import { ESLintUtils as ESLintUtils6 } from "@typescript-eslint/utils";
807
+ import { ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
829
808
  var STRONG_SECURITY_PATTERN = /token|secret|csrf|password|passwd|apikey|api[-_]?key|nonce|salt|uuid|authid/i;
830
809
  var NON_SECURITY_ID_PATTERN = /temp|tmp|cache|correlation|request|req|trace|execution|dev|hmr|mock|test|perf|marker/i;
831
810
  var PATH_OR_DOM_MARKER = /[\\/#]|\.[A-Za-z0-9]/;
@@ -966,7 +945,7 @@ function isConcatenatedIntoPathOrDomId(node) {
966
945
  collectStaticStringParts(top, parts);
967
946
  return parts.some((part) => PATH_OR_DOM_MARKER.test(part));
968
947
  }
969
- var no_insecure_random_id_default = ESLintUtils6.RuleCreator(
948
+ var no_insecure_random_id_default = ESLintUtils5.RuleCreator(
970
949
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
971
950
  )({
972
951
  name: "no-insecure-random-id",
@@ -1010,7 +989,7 @@ var no_insecure_random_id_default = ESLintUtils6.RuleCreator(
1010
989
  });
1011
990
 
1012
991
  // src/rules/no-json-stringify-error.ts
1013
- import { ESLintUtils as ESLintUtils7 } from "@typescript-eslint/utils";
992
+ import { ESLintUtils as ESLintUtils6 } from "@typescript-eslint/utils";
1014
993
  var ERROR_NAME_PATTERN = /^(e|err|error|ex|exc)$/i;
1015
994
  var ERROR_PROP_PATTERN = /^(cause|lastError|error|err|exception|originalError|innerError)$/i;
1016
995
  var SAFE_STRING_PROPS = /* @__PURE__ */ new Set(["message", "stack", "name"]);
@@ -1144,7 +1123,7 @@ function isGuardedByInstanceofError(node, argExpr, sourceCode) {
1144
1123
  function isJsonStringify(callee) {
1145
1124
  return callee.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "JSON" && callee.property.type === "Identifier" && callee.property.name === "stringify";
1146
1125
  }
1147
- var no_json_stringify_error_default = ESLintUtils7.RuleCreator(
1126
+ var no_json_stringify_error_default = ESLintUtils6.RuleCreator(
1148
1127
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1149
1128
  )({
1150
1129
  name: "no-json-stringify-error",
@@ -1194,7 +1173,7 @@ var no_json_stringify_error_default = ESLintUtils7.RuleCreator(
1194
1173
  });
1195
1174
 
1196
1175
  // src/rules/no-log-only-catch.ts
1197
- import { ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
1176
+ import { AST_NODE_TYPES as AST_NODE_TYPES5, ASTUtils, ESLintUtils as ESLintUtils7 } from "@typescript-eslint/utils";
1198
1177
 
1199
1178
  // src/rules/_logging.ts
1200
1179
  import "@typescript-eslint/utils";
@@ -1299,12 +1278,92 @@ function createLogMatcher(options = {}) {
1299
1278
  }
1300
1279
 
1301
1280
  // src/rules/no-log-only-catch.ts
1302
- var DEFAULT_IGNORE_PATTERNS2 = [
1303
- /\.test\./,
1304
- /\.spec\./,
1305
- /[\\/]__tests__[\\/]/
1306
- ];
1307
- var no_log_only_catch_default = ESLintUtils8.RuleCreator(
1281
+ var BENCHMARK_DIR_RE = /(?:^|[\\/])benchmarks?[\\/]/;
1282
+ var SINGLE_STATEMENT_HOSTS = /* @__PURE__ */ new Set([
1283
+ AST_NODE_TYPES5.DoWhileStatement,
1284
+ AST_NODE_TYPES5.ForInStatement,
1285
+ AST_NODE_TYPES5.ForOfStatement,
1286
+ AST_NODE_TYPES5.ForStatement,
1287
+ AST_NODE_TYPES5.IfStatement,
1288
+ AST_NODE_TYPES5.WhileStatement
1289
+ ]);
1290
+ var FUNCTION_TYPES = /* @__PURE__ */ new Set([
1291
+ AST_NODE_TYPES5.ArrowFunctionExpression,
1292
+ AST_NODE_TYPES5.FunctionDeclaration,
1293
+ AST_NODE_TYPES5.FunctionExpression
1294
+ ]);
1295
+ function statementSlot(node) {
1296
+ const parent = node.parent;
1297
+ if (parent === void 0) return null;
1298
+ let list;
1299
+ switch (parent.type) {
1300
+ case AST_NODE_TYPES5.BlockStatement:
1301
+ case AST_NODE_TYPES5.Program:
1302
+ case AST_NODE_TYPES5.StaticBlock:
1303
+ list = parent.body;
1304
+ break;
1305
+ case AST_NODE_TYPES5.SwitchCase:
1306
+ list = parent.consequent;
1307
+ break;
1308
+ default:
1309
+ return null;
1310
+ }
1311
+ const index = list.indexOf(node);
1312
+ return index === -1 ? null : { list, index };
1313
+ }
1314
+ function hasFollowingStatement(node) {
1315
+ for (let current = node; current !== void 0 && !FUNCTION_TYPES.has(current.type); current = current.parent) {
1316
+ const slot = statementSlot(current);
1317
+ if (slot !== null && slot.index < slot.list.length - 1) return true;
1318
+ }
1319
+ return false;
1320
+ }
1321
+ function fallbackFollowsTry(tryStatement) {
1322
+ const body = tryStatement.block.body;
1323
+ const last = body.at(-1);
1324
+ return last?.type === AST_NODE_TYPES5.ReturnStatement && hasFollowingStatement(tryStatement);
1325
+ }
1326
+ function isSeedValue(node) {
1327
+ const inner = node.type === AST_NODE_TYPES5.TSAsExpression ? node.expression : node;
1328
+ switch (inner.type) {
1329
+ case AST_NODE_TYPES5.Literal:
1330
+ return true;
1331
+ case AST_NODE_TYPES5.Identifier:
1332
+ return inner.name === "undefined";
1333
+ case AST_NODE_TYPES5.UnaryExpression:
1334
+ return inner.argument.type === AST_NODE_TYPES5.Literal;
1335
+ case AST_NODE_TYPES5.ArrayExpression:
1336
+ return inner.elements.length === 0;
1337
+ case AST_NODE_TYPES5.ObjectExpression:
1338
+ return inner.properties.length === 0;
1339
+ default:
1340
+ return false;
1341
+ }
1342
+ }
1343
+ function seededFallbackHandled(tryStatement, scope) {
1344
+ const slot = statementSlot(tryStatement);
1345
+ if (slot === null || slot.index === 0) return false;
1346
+ const previous = slot.list[slot.index - 1];
1347
+ if (previous?.type !== AST_NODE_TYPES5.VariableDeclaration || previous.kind === "const") {
1348
+ return false;
1349
+ }
1350
+ const declarator = previous.declarations[0];
1351
+ if (previous.declarations.length !== 1 || declarator === void 0) return false;
1352
+ if (declarator.id.type !== AST_NODE_TYPES5.Identifier) return false;
1353
+ if (declarator.init == null || !isSeedValue(declarator.init)) return false;
1354
+ const variable = ASTUtils.findVariable(scope, declarator.id.name);
1355
+ if (variable === null) return false;
1356
+ const [tryStart, tryEnd] = tryStatement.block.range;
1357
+ let writtenInTry = false;
1358
+ let readAfter = false;
1359
+ for (const reference of variable.references) {
1360
+ const [start] = reference.identifier.range;
1361
+ if (reference.isWrite() && start >= tryStart && start < tryEnd) writtenInTry = true;
1362
+ if (reference.isRead() && start >= tryStatement.range[1]) readAfter = true;
1363
+ }
1364
+ return writtenInTry && readAfter;
1365
+ }
1366
+ var no_log_only_catch_default = ESLintUtils7.RuleCreator(
1308
1367
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1309
1368
  )({
1310
1369
  name: "no-log-only-catch",
@@ -1329,26 +1388,40 @@ var no_log_only_catch_default = ESLintUtils8.RuleCreator(
1329
1388
  create(context, [loggingOptions]) {
1330
1389
  const matcher = createLogMatcher(loggingOptions);
1331
1390
  const filename = context.filename;
1391
+ const sourceCode = context.sourceCode;
1332
1392
  function isLoggingCallStatement(statement) {
1333
1393
  if (statement.type !== "ExpressionStatement") {
1334
1394
  return false;
1335
1395
  }
1336
1396
  return matcher.isLoggingCall(statement.expression);
1337
1397
  }
1338
- const isIgnoredByDefault = DEFAULT_IGNORE_PATTERNS2.some(
1339
- (re) => re.test(filename)
1340
- );
1341
- if (isIgnoredByDefault) {
1398
+ function hasCommentDirectlyAbove(node) {
1399
+ const above = sourceCode.getCommentsBefore(node).at(-1);
1400
+ return above !== void 0 && above.loc.end.line === node.loc.start.line - 1;
1401
+ }
1402
+ function hasAdjacentRationale(node) {
1403
+ const tryStatement = node.parent;
1404
+ if (hasCommentDirectlyAbove(tryStatement) || hasCommentDirectlyAbove(node)) return true;
1405
+ const block = tryStatement.parent;
1406
+ if (block?.type !== AST_NODE_TYPES5.BlockStatement || block.body.length !== 1 || block.parent === void 0 || !SINGLE_STATEMENT_HOSTS.has(block.parent.type)) {
1407
+ return false;
1408
+ }
1409
+ return hasCommentDirectlyAbove(block.parent);
1410
+ }
1411
+ if (isTestFile(filename) || BENCHMARK_DIR_RE.test(filename.replaceAll("\\", "/"))) {
1342
1412
  return {};
1343
1413
  }
1344
1414
  return {
1345
1415
  CatchClause(node) {
1346
1416
  const statements = node.body.body;
1347
- const isDocumented = context.sourceCode.getCommentsInside(node.body).length > 0;
1417
+ const isDocumented = sourceCode.getCommentsInside(node.body).length > 0 || hasAdjacentRationale(node);
1348
1418
  if (statements.length === 0) {
1349
1419
  if (isDocumented) {
1350
1420
  return;
1351
1421
  }
1422
+ if (fallbackFollowsTry(node.parent) || seededFallbackHandled(node.parent, sourceCode.getScope(node))) {
1423
+ return;
1424
+ }
1352
1425
  context.report({ node, messageId: "emptyCatch" });
1353
1426
  return;
1354
1427
  }
@@ -1367,11 +1440,12 @@ var no_log_only_catch_default = ESLintUtils8.RuleCreator(
1367
1440
  });
1368
1441
 
1369
1442
  // src/rules/no-raw-env.ts
1370
- import { ESLintUtils as ESLintUtils9 } from "@typescript-eslint/utils";
1443
+ import { ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
1371
1444
  var CONFIG_FILE_RE = /(^|[\\/])[\w.-]+\.config\.[cm]?[jt]sx?$/;
1372
1445
  var ENV_BOUNDARY_FILE_RE = /(^|[\\/])(?:env|client-env|server-env|client-settings|server-settings)\.[cm]?[jt]sx?$/;
1446
+ var ENV_VALIDATION_MARKER_RE = /\bcreateEnv\s*\(|\bz\.object\s*\(|\.(?:safeParse|parse)\s*\(/;
1373
1447
  function isValidatedEnvBoundary(filename, sourceText) {
1374
- return ENV_BOUNDARY_FILE_RE.test(filename.replaceAll("\\", "/")) && /\bz\.object\s*\(/.test(sourceText) && /\.parse\s*\(/.test(sourceText);
1448
+ return ENV_BOUNDARY_FILE_RE.test(filename.replaceAll("\\", "/")) && ENV_VALIDATION_MARKER_RE.test(sourceText);
1375
1449
  }
1376
1450
  function isProcessEnv(node) {
1377
1451
  return !node.computed && node.object.type === "Identifier" && node.object.name === "process" && node.property.type === "Identifier" && node.property.name === "env";
@@ -1386,9 +1460,15 @@ var BUILD_TIME_CONSTANTS = /* @__PURE__ */ new Set([
1386
1460
  "PROD",
1387
1461
  "SSR"
1388
1462
  ]);
1389
- function isBuildTimeConstantAccess(node) {
1463
+ var PLATFORM_MARKERS = /* @__PURE__ */ new Set([
1464
+ "NEXT_RUNTIME",
1465
+ "VERCEL",
1466
+ "VERCEL_ENV",
1467
+ "CI"
1468
+ ]);
1469
+ function isExemptVariableAccess(node) {
1390
1470
  const parent = node.parent;
1391
- return parent.type === "MemberExpression" && parent.object === node && !parent.computed && parent.property.type === "Identifier" && BUILD_TIME_CONSTANTS.has(parent.property.name);
1471
+ return parent.type === "MemberExpression" && parent.object === node && !parent.computed && parent.property.type === "Identifier" && (BUILD_TIME_CONSTANTS.has(parent.property.name) || PLATFORM_MARKERS.has(parent.property.name));
1392
1472
  }
1393
1473
  function isWriteTarget(node) {
1394
1474
  const access = node.parent.type === "MemberExpression" && node.parent.object === node ? node.parent : node;
@@ -1405,7 +1485,7 @@ function isWholeEnvSpread(node) {
1405
1485
  const parent = node.parent;
1406
1486
  return parent.type === "SpreadElement" && parent.argument === node;
1407
1487
  }
1408
- var no_raw_env_default = ESLintUtils9.RuleCreator(
1488
+ var no_raw_env_default = ESLintUtils8.RuleCreator(
1409
1489
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1410
1490
  )({
1411
1491
  name: "no-raw-env",
@@ -1427,7 +1507,7 @@ var no_raw_env_default = ESLintUtils9.RuleCreator(
1427
1507
  }
1428
1508
  return {
1429
1509
  MemberExpression(node) {
1430
- if ((isProcessEnv(node) || isImportMetaEnv(node)) && !isBuildTimeConstantAccess(node) && !isWriteTarget(node) && !isWholeEnvSpread(node)) {
1510
+ if ((isProcessEnv(node) || isImportMetaEnv(node)) && !isExemptVariableAccess(node) && !isWriteTarget(node) && !isWholeEnvSpread(node)) {
1431
1511
  context.report({
1432
1512
  node,
1433
1513
  messageId: "noRawEnv"
@@ -1440,14 +1520,14 @@ var no_raw_env_default = ESLintUtils9.RuleCreator(
1440
1520
 
1441
1521
  // src/rules/no-sentinel-return-on-catch.ts
1442
1522
  import {
1443
- ESLintUtils as ESLintUtils10,
1444
- AST_NODE_TYPES as AST_NODE_TYPES5
1523
+ ESLintUtils as ESLintUtils9,
1524
+ AST_NODE_TYPES as AST_NODE_TYPES6
1445
1525
  } from "@typescript-eslint/utils";
1446
1526
  function sentinelKind(arg) {
1447
1527
  if (arg === null) {
1448
1528
  return null;
1449
1529
  }
1450
- if (arg.type === AST_NODE_TYPES5.Literal) {
1530
+ if (arg.type === AST_NODE_TYPES6.Literal) {
1451
1531
  if (arg.value === null) {
1452
1532
  return "nullish";
1453
1533
  }
@@ -1459,13 +1539,13 @@ function sentinelKind(arg) {
1459
1539
  }
1460
1540
  return null;
1461
1541
  }
1462
- if (arg.type === AST_NODE_TYPES5.Identifier && arg.name === "undefined") {
1542
+ if (arg.type === AST_NODE_TYPES6.Identifier && arg.name === "undefined") {
1463
1543
  return "nullish";
1464
1544
  }
1465
- if (arg.type === AST_NODE_TYPES5.ArrayExpression) {
1545
+ if (arg.type === AST_NODE_TYPES6.ArrayExpression) {
1466
1546
  return "array";
1467
1547
  }
1468
- if (arg.type === AST_NODE_TYPES5.ObjectExpression) {
1548
+ if (arg.type === AST_NODE_TYPES6.ObjectExpression) {
1469
1549
  return "object";
1470
1550
  }
1471
1551
  return null;
@@ -1474,25 +1554,25 @@ function isSentinelArgument(arg) {
1474
1554
  if (arg === null) {
1475
1555
  return false;
1476
1556
  }
1477
- if (arg.type === AST_NODE_TYPES5.Literal && arg.value === null) {
1557
+ if (arg.type === AST_NODE_TYPES6.Literal && arg.value === null) {
1478
1558
  return true;
1479
1559
  }
1480
- if (arg.type === AST_NODE_TYPES5.Literal && arg.value === false) {
1560
+ if (arg.type === AST_NODE_TYPES6.Literal && arg.value === false) {
1481
1561
  return true;
1482
1562
  }
1483
- if (arg.type === AST_NODE_TYPES5.Identifier && arg.name === "undefined") {
1563
+ if (arg.type === AST_NODE_TYPES6.Identifier && arg.name === "undefined") {
1484
1564
  return true;
1485
1565
  }
1486
- if (arg.type === AST_NODE_TYPES5.ArrayExpression && arg.elements.length === 0) {
1566
+ if (arg.type === AST_NODE_TYPES6.ArrayExpression && arg.elements.length === 0) {
1487
1567
  return true;
1488
1568
  }
1489
- if (arg.type === AST_NODE_TYPES5.ObjectExpression && arg.properties.length === 0) {
1569
+ if (arg.type === AST_NODE_TYPES6.ObjectExpression && arg.properties.length === 0) {
1490
1570
  return true;
1491
1571
  }
1492
1572
  return false;
1493
1573
  }
1494
1574
  function isFunctionNode(node) {
1495
- return node.type === AST_NODE_TYPES5.FunctionDeclaration || node.type === AST_NODE_TYPES5.FunctionExpression || node.type === AST_NODE_TYPES5.ArrowFunctionExpression;
1575
+ return node.type === AST_NODE_TYPES6.FunctionDeclaration || node.type === AST_NODE_TYPES6.FunctionExpression || node.type === AST_NODE_TYPES6.ArrowFunctionExpression;
1496
1576
  }
1497
1577
  function isNode(value) {
1498
1578
  return typeof value === "object" && value !== null && typeof value.type === "string";
@@ -1532,24 +1612,24 @@ function walkWithinScope(node, visit) {
1532
1612
  function containsThrow(node) {
1533
1613
  return walkWithinScope(
1534
1614
  node,
1535
- (current) => current.type === AST_NODE_TYPES5.ThrowStatement
1615
+ (current) => current.type === AST_NODE_TYPES6.ThrowStatement
1536
1616
  );
1537
1617
  }
1538
1618
  function bindsName(param, name) {
1539
1619
  switch (param.type) {
1540
- case AST_NODE_TYPES5.Identifier:
1620
+ case AST_NODE_TYPES6.Identifier:
1541
1621
  return param.name === name;
1542
- case AST_NODE_TYPES5.AssignmentPattern:
1622
+ case AST_NODE_TYPES6.AssignmentPattern:
1543
1623
  return bindsName(param.left, name);
1544
- case AST_NODE_TYPES5.RestElement:
1624
+ case AST_NODE_TYPES6.RestElement:
1545
1625
  return bindsName(param.argument, name);
1546
- case AST_NODE_TYPES5.ArrayPattern:
1626
+ case AST_NODE_TYPES6.ArrayPattern:
1547
1627
  return param.elements.some(
1548
1628
  (element) => element !== null && bindsName(element, name)
1549
1629
  );
1550
- case AST_NODE_TYPES5.ObjectPattern:
1630
+ case AST_NODE_TYPES6.ObjectPattern:
1551
1631
  return param.properties.some(
1552
- (property) => property.type === AST_NODE_TYPES5.RestElement ? bindsName(property.argument, name) : bindsName(property.value, name)
1632
+ (property) => property.type === AST_NODE_TYPES6.RestElement ? bindsName(property.argument, name) : bindsName(property.value, name)
1553
1633
  );
1554
1634
  default:
1555
1635
  return false;
@@ -1564,7 +1644,7 @@ function subtreeReadsName(node, name) {
1564
1644
  if (found) {
1565
1645
  return;
1566
1646
  }
1567
- if (current.type === AST_NODE_TYPES5.Identifier && current.name === name) {
1647
+ if (current.type === AST_NODE_TYPES6.Identifier && current.name === name) {
1568
1648
  found = true;
1569
1649
  return;
1570
1650
  }
@@ -1575,10 +1655,10 @@ function subtreeReadsName(node, name) {
1575
1655
  if (key === "parent") {
1576
1656
  continue;
1577
1657
  }
1578
- if (key === "key" && current.type === AST_NODE_TYPES5.Property && !current.computed) {
1658
+ if (key === "key" && current.type === AST_NODE_TYPES6.Property && !current.computed) {
1579
1659
  continue;
1580
1660
  }
1581
- if (key === "property" && current.type === AST_NODE_TYPES5.MemberExpression && !current.computed) {
1661
+ if (key === "property" && current.type === AST_NODE_TYPES6.MemberExpression && !current.computed) {
1582
1662
  continue;
1583
1663
  }
1584
1664
  const value = current[key];
@@ -1611,10 +1691,10 @@ var SAFE_PARSE_CONSTRUCTORS = /* @__PURE__ */ new Set([
1611
1691
  "URLPattern"
1612
1692
  ]);
1613
1693
  function isParseShapedNode(node) {
1614
- if (node.type === AST_NODE_TYPES5.CallExpression && node.callee.type === AST_NODE_TYPES5.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES5.Identifier) {
1694
+ if (node.type === AST_NODE_TYPES6.CallExpression && node.callee.type === AST_NODE_TYPES6.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES6.Identifier) {
1615
1695
  return node.callee.property.name === "parse";
1616
1696
  }
1617
- if (node.type === AST_NODE_TYPES5.NewExpression && node.callee.type === AST_NODE_TYPES5.Identifier) {
1697
+ if (node.type === AST_NODE_TYPES6.NewExpression && node.callee.type === AST_NODE_TYPES6.Identifier) {
1618
1698
  return SAFE_PARSE_CONSTRUCTORS.has(node.callee.name);
1619
1699
  }
1620
1700
  return false;
@@ -1625,10 +1705,10 @@ var BODY_DECODE_METHODS = /* @__PURE__ */ new Set([
1625
1705
  "arrayBuffer"
1626
1706
  ]);
1627
1707
  function isBodyDecodeNode(node) {
1628
- return node.type === AST_NODE_TYPES5.CallExpression && node.callee.type === AST_NODE_TYPES5.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES5.Identifier && BODY_DECODE_METHODS.has(node.callee.property.name);
1708
+ return node.type === AST_NODE_TYPES6.CallExpression && node.callee.type === AST_NODE_TYPES6.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES6.Identifier && BODY_DECODE_METHODS.has(node.callee.property.name);
1629
1709
  }
1630
1710
  function returnsMatching(stmt, predicate) {
1631
- return stmt.type === AST_NODE_TYPES5.ReturnStatement && stmt.argument !== null && walkWithinScope(stmt.argument, predicate);
1711
+ return stmt.type === AST_NODE_TYPES6.ReturnStatement && stmt.argument !== null && walkWithinScope(stmt.argument, predicate);
1632
1712
  }
1633
1713
  function enclosingReturnTypeNode(node) {
1634
1714
  let current = node.parent;
@@ -1646,11 +1726,11 @@ function enclosingFunctionName(node) {
1646
1726
  let current = node.parent;
1647
1727
  while (current !== void 0 && current !== null) {
1648
1728
  if (isFunctionNode(current)) {
1649
- if ("id" in current && isNode(current.id) && current.id.type === AST_NODE_TYPES5.Identifier) {
1729
+ if ("id" in current && isNode(current.id) && current.id.type === AST_NODE_TYPES6.Identifier) {
1650
1730
  return current.id.name;
1651
1731
  }
1652
1732
  const parent = current.parent;
1653
- if (parent?.type === AST_NODE_TYPES5.VariableDeclarator && parent.id.type === AST_NODE_TYPES5.Identifier) {
1733
+ if (parent?.type === AST_NODE_TYPES6.VariableDeclarator && parent.id.type === AST_NODE_TYPES6.Identifier) {
1654
1734
  return parent.id.name;
1655
1735
  }
1656
1736
  return null;
@@ -1671,10 +1751,10 @@ function isDeclaredBooleanPredicate(catchNode, kind) {
1671
1751
  return false;
1672
1752
  }
1673
1753
  let declared = enclosingReturnTypeNode(catchNode);
1674
- if (declared?.type === AST_NODE_TYPES5.TSTypeReference && declared.typeName.type === AST_NODE_TYPES5.Identifier && declared.typeName.name === "Promise") {
1754
+ if (declared?.type === AST_NODE_TYPES6.TSTypeReference && declared.typeName.type === AST_NODE_TYPES6.Identifier && declared.typeName.name === "Promise") {
1675
1755
  declared = declared.typeArguments?.params[0] ?? null;
1676
1756
  }
1677
- return declared?.type === AST_NODE_TYPES5.TSBooleanKeyword;
1757
+ return declared?.type === AST_NODE_TYPES6.TSBooleanKeyword;
1678
1758
  }
1679
1759
  function tryReturnsSafeParse(catchNode) {
1680
1760
  const tryBlock = tryBlockOf(catchNode);
@@ -1690,7 +1770,7 @@ function tryReturnsSafeParse(catchNode) {
1690
1770
  function enclosingFunctionBody(node) {
1691
1771
  let current = node.parent;
1692
1772
  while (current !== void 0 && current !== null) {
1693
- if (isFunctionNode(current) && "body" in current && isNode(current.body) && current.body.type === AST_NODE_TYPES5.BlockStatement) {
1773
+ if (isFunctionNode(current) && "body" in current && isNode(current.body) && current.body.type === AST_NODE_TYPES6.BlockStatement) {
1694
1774
  return current.body;
1695
1775
  }
1696
1776
  current = current.parent;
@@ -1703,7 +1783,7 @@ function functionReturnsSameSentinelKindElsewhere(catchNode, kind) {
1703
1783
  return false;
1704
1784
  }
1705
1785
  return walkWithinScope(functionBody, (current) => {
1706
- if (current.type !== AST_NODE_TYPES5.ReturnStatement) {
1786
+ if (current.type !== AST_NODE_TYPES6.ReturnStatement) {
1707
1787
  return false;
1708
1788
  }
1709
1789
  if (isWithin(current, catchNode.body)) {
@@ -1722,13 +1802,13 @@ function returnedSentinelKinds(arg) {
1722
1802
  kinds.add(direct);
1723
1803
  return kinds;
1724
1804
  }
1725
- if (arg.type === AST_NODE_TYPES5.ConditionalExpression) {
1805
+ if (arg.type === AST_NODE_TYPES6.ConditionalExpression) {
1726
1806
  for (const branch of [arg.consequent, arg.alternate]) {
1727
1807
  for (const nested of returnedSentinelKinds(branch)) {
1728
1808
  kinds.add(nested);
1729
1809
  }
1730
1810
  }
1731
- } else if (arg.type === AST_NODE_TYPES5.LogicalExpression && (arg.operator === "??" || arg.operator === "||")) {
1811
+ } else if (arg.type === AST_NODE_TYPES6.LogicalExpression && (arg.operator === "??" || arg.operator === "||")) {
1732
1812
  for (const nested of returnedSentinelKinds(arg.right)) {
1733
1813
  kinds.add(nested);
1734
1814
  }
@@ -1745,7 +1825,7 @@ function isWithin(node, ancestor) {
1745
1825
  }
1746
1826
  return false;
1747
1827
  }
1748
- var no_sentinel_return_on_catch_default = ESLintUtils10.RuleCreator(
1828
+ var no_sentinel_return_on_catch_default = ESLintUtils9.RuleCreator(
1749
1829
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1750
1830
  )({
1751
1831
  name: "no-sentinel-return-on-catch",
@@ -1773,7 +1853,7 @@ var no_sentinel_return_on_catch_default = ESLintUtils10.RuleCreator(
1773
1853
  const matcher = createLogMatcher(loggingOptions);
1774
1854
  function logsOrReportsError(catchBody, caughtName) {
1775
1855
  return walkWithinScope(catchBody, (current) => {
1776
- if (current.type !== AST_NODE_TYPES5.CallExpression) {
1856
+ if (current.type !== AST_NODE_TYPES6.CallExpression) {
1777
1857
  return false;
1778
1858
  }
1779
1859
  if (matcher.isLoggingCall(current)) {
@@ -1790,7 +1870,7 @@ var no_sentinel_return_on_catch_default = ESLintUtils10.RuleCreator(
1790
1870
  return;
1791
1871
  }
1792
1872
  const last = body[body.length - 1];
1793
- if (last === void 0 || last.type !== AST_NODE_TYPES5.ReturnStatement) {
1873
+ if (last === void 0 || last.type !== AST_NODE_TYPES6.ReturnStatement) {
1794
1874
  return;
1795
1875
  }
1796
1876
  if (!isSentinelArgument(last.argument)) {
@@ -1799,7 +1879,7 @@ var no_sentinel_return_on_catch_default = ESLintUtils10.RuleCreator(
1799
1879
  if (containsThrow(node.body)) {
1800
1880
  return;
1801
1881
  }
1802
- const caughtName = node.param?.type === AST_NODE_TYPES5.Identifier ? node.param.name : null;
1882
+ const caughtName = node.param?.type === AST_NODE_TYPES6.Identifier ? node.param.name : null;
1803
1883
  if (logsOrReportsError(node.body, caughtName)) {
1804
1884
  return;
1805
1885
  }
@@ -1826,7 +1906,7 @@ var no_sentinel_return_on_catch_default = ESLintUtils10.RuleCreator(
1826
1906
  });
1827
1907
 
1828
1908
  // src/rules/no-string-concat-in-loop.ts
1829
- import { ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
1909
+ import { ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
1830
1910
  var LOOP_NODE_TYPES = /* @__PURE__ */ new Set([
1831
1911
  "ForStatement",
1832
1912
  "ForOfStatement",
@@ -1911,7 +1991,7 @@ function enclosingLoop(node) {
1911
1991
  }
1912
1992
  return null;
1913
1993
  }
1914
- var no_string_concat_in_loop_default = ESLintUtils11.RuleCreator(
1994
+ var no_string_concat_in_loop_default = ESLintUtils10.RuleCreator(
1915
1995
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
1916
1996
  )({
1917
1997
  name: "no-string-concat-in-loop",
@@ -1975,8 +2055,8 @@ var no_string_concat_in_loop_default = ESLintUtils11.RuleCreator(
1975
2055
 
1976
2056
  // src/rules/no-unnecessary-use-client.ts
1977
2057
  import {
1978
- AST_NODE_TYPES as AST_NODE_TYPES6,
1979
- ESLintUtils as ESLintUtils12
2058
+ AST_NODE_TYPES as AST_NODE_TYPES7,
2059
+ ESLintUtils as ESLintUtils11
1980
2060
  } from "@typescript-eslint/utils";
1981
2061
  var HOOK_REGEX = /^use([A-Z]|$)/;
1982
2062
  var EVENT_PROP_REGEX = /^on[A-Z]/;
@@ -2003,13 +2083,13 @@ var CLIENT_ONLY_PACKAGES_REGEX = /^(?:@radix-ui\/|framer-motion|react-dom|react-
2003
2083
  var isBareSpecifier = (source) => !source.startsWith(".") && !source.startsWith("/") && !source.startsWith("@/") && !source.startsWith("~");
2004
2084
  var jsxRootName = (name) => {
2005
2085
  let current = name;
2006
- while (current.type === AST_NODE_TYPES6.JSXMemberExpression) {
2086
+ while (current.type === AST_NODE_TYPES7.JSXMemberExpression) {
2007
2087
  current = current.object;
2008
2088
  }
2009
- return current.type === AST_NODE_TYPES6.JSXIdentifier ? current.name : "";
2089
+ return current.type === AST_NODE_TYPES7.JSXIdentifier ? current.name : "";
2010
2090
  };
2011
2091
  var subtreeReadsImportedBinding = (node, imported) => {
2012
- if (node.type === AST_NODE_TYPES6.Identifier) {
2092
+ if (node.type === AST_NODE_TYPES7.Identifier) {
2013
2093
  return imported.has(node.name);
2014
2094
  }
2015
2095
  for (const key of Object.keys(node)) {
@@ -2024,16 +2104,16 @@ var subtreeReadsImportedBinding = (node, imported) => {
2024
2104
  return false;
2025
2105
  };
2026
2106
  var isUseClientDirective = (node) => {
2027
- return node.type === AST_NODE_TYPES6.ExpressionStatement && node.expression.type === AST_NODE_TYPES6.Literal && node.expression.value === "use client";
2107
+ return node.type === AST_NODE_TYPES7.ExpressionStatement && node.expression.type === AST_NODE_TYPES7.Literal && node.expression.value === "use client";
2028
2108
  };
2029
2109
  var isGlobalReference = (node, context) => {
2030
2110
  if (!BROWSER_GLOBALS.has(node.name)) return false;
2031
2111
  const parent = node.parent;
2032
2112
  if (parent !== void 0) {
2033
- if (parent.type === AST_NODE_TYPES6.MemberExpression && parent.property === node && !parent.computed) {
2113
+ if (parent.type === AST_NODE_TYPES7.MemberExpression && parent.property === node && !parent.computed) {
2034
2114
  return false;
2035
2115
  }
2036
- if (parent.type === AST_NODE_TYPES6.Property && parent.key === node && !parent.computed) {
2116
+ if (parent.type === AST_NODE_TYPES7.Property && parent.key === node && !parent.computed) {
2037
2117
  return false;
2038
2118
  }
2039
2119
  if (parent.type.startsWith("TS")) {
@@ -2050,7 +2130,7 @@ var isGlobalReference = (node, context) => {
2050
2130
  }
2051
2131
  return true;
2052
2132
  };
2053
- var no_unnecessary_use_client_default = ESLintUtils12.RuleCreator(
2133
+ var no_unnecessary_use_client_default = ESLintUtils11.RuleCreator(
2054
2134
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
2055
2135
  )({
2056
2136
  name: "no-unnecessary-use-client",
@@ -2075,13 +2155,13 @@ var no_unnecessary_use_client_default = ESLintUtils12.RuleCreator(
2075
2155
  const importedLocals = /* @__PURE__ */ new Set();
2076
2156
  const externalLocals = /* @__PURE__ */ new Set();
2077
2157
  const markIfHookOrContext = (callee) => {
2078
- if (callee.type === AST_NODE_TYPES6.Identifier) {
2158
+ if (callee.type === AST_NODE_TYPES7.Identifier) {
2079
2159
  if (HOOK_REGEX.test(callee.name) || callee.name === "createContext") {
2080
2160
  hasClientIndicator = true;
2081
2161
  }
2082
2162
  return;
2083
2163
  }
2084
- if (callee.type === AST_NODE_TYPES6.MemberExpression && callee.property.type === AST_NODE_TYPES6.Identifier) {
2164
+ if (callee.type === AST_NODE_TYPES7.MemberExpression && callee.property.type === AST_NODE_TYPES7.Identifier) {
2085
2165
  const name = callee.property.name;
2086
2166
  if (HOOK_REGEX.test(name) || name === "createContext") {
2087
2167
  hasClientIndicator = true;
@@ -2091,7 +2171,7 @@ var no_unnecessary_use_client_default = ESLintUtils12.RuleCreator(
2091
2171
  return {
2092
2172
  Program(node) {
2093
2173
  for (const stmt of node.body) {
2094
- if (stmt.type !== AST_NODE_TYPES6.ExpressionStatement) break;
2174
+ if (stmt.type !== AST_NODE_TYPES7.ExpressionStatement) break;
2095
2175
  if (isUseClientDirective(stmt)) {
2096
2176
  directiveNode = stmt;
2097
2177
  break;
@@ -2104,7 +2184,7 @@ var no_unnecessary_use_client_default = ESLintUtils12.RuleCreator(
2104
2184
  },
2105
2185
  JSXAttribute(node) {
2106
2186
  if (directiveNode === null) return;
2107
- if (node.name.type === AST_NODE_TYPES6.JSXIdentifier && EVENT_PROP_REGEX.test(node.name.name)) {
2187
+ if (node.name.type === AST_NODE_TYPES7.JSXIdentifier && EVENT_PROP_REGEX.test(node.name.name)) {
2108
2188
  hasClientIndicator = true;
2109
2189
  }
2110
2190
  },
@@ -2171,8 +2251,8 @@ var no_unnecessary_use_client_default = ESLintUtils12.RuleCreator(
2171
2251
  });
2172
2252
 
2173
2253
  // src/rules/prefer-discriminated-union.ts
2174
- import { ESLintUtils as ESLintUtils13 } from "@typescript-eslint/utils";
2175
- import { AST_NODE_TYPES as AST_NODE_TYPES7 } from "@typescript-eslint/utils";
2254
+ import { ESLintUtils as ESLintUtils12 } from "@typescript-eslint/utils";
2255
+ import { AST_NODE_TYPES as AST_NODE_TYPES8 } from "@typescript-eslint/utils";
2176
2256
  var STATUS_MEMBER_NAMES = /* @__PURE__ */ new Set([
2177
2257
  "success",
2178
2258
  "ok",
@@ -2182,27 +2262,27 @@ var STATUS_MEMBER_NAMES = /* @__PURE__ */ new Set([
2182
2262
  ]);
2183
2263
  var MIN_OPTIONAL_MEMBERS = 2;
2184
2264
  function getMemberName(member) {
2185
- if (member.type !== AST_NODE_TYPES7.TSPropertySignature) {
2265
+ if (member.type !== AST_NODE_TYPES8.TSPropertySignature) {
2186
2266
  return null;
2187
2267
  }
2188
2268
  const { key } = member;
2189
- if (key.type === AST_NODE_TYPES7.Identifier) {
2269
+ if (key.type === AST_NODE_TYPES8.Identifier) {
2190
2270
  return key.name;
2191
2271
  }
2192
- if (key.type === AST_NODE_TYPES7.Literal && typeof key.value === "string") {
2272
+ if (key.type === AST_NODE_TYPES8.Literal && typeof key.value === "string") {
2193
2273
  return key.value;
2194
2274
  }
2195
2275
  return null;
2196
2276
  }
2197
2277
  function isBooleanTyped(member) {
2198
- return member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES7.TSBooleanKeyword;
2278
+ return member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES8.TSBooleanKeyword;
2199
2279
  }
2200
2280
  function looksLikeMutuallyExclusiveState(typeLiteral) {
2201
2281
  let hasStatusBoolean = false;
2202
2282
  let optionalCount = 0;
2203
2283
  let optionalPayloadCount = 0;
2204
2284
  for (const member of typeLiteral.members) {
2205
- if (member.type !== AST_NODE_TYPES7.TSPropertySignature) {
2285
+ if (member.type !== AST_NODE_TYPES8.TSPropertySignature) {
2206
2286
  continue;
2207
2287
  }
2208
2288
  if (member.optional) {
@@ -2218,7 +2298,7 @@ function looksLikeMutuallyExclusiveState(typeLiteral) {
2218
2298
  }
2219
2299
  return hasStatusBoolean && optionalCount >= MIN_OPTIONAL_MEMBERS && optionalPayloadCount >= 1;
2220
2300
  }
2221
- var prefer_discriminated_union_default = ESLintUtils13.RuleCreator(
2301
+ var prefer_discriminated_union_default = ESLintUtils12.RuleCreator(
2222
2302
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
2223
2303
  )({
2224
2304
  name: "prefer-discriminated-union",
@@ -2246,7 +2326,7 @@ var prefer_discriminated_union_default = ESLintUtils13.RuleCreator(
2246
2326
  TSInterfaceDeclaration(node) {
2247
2327
  const synthetic = {
2248
2328
  ...node.body,
2249
- type: AST_NODE_TYPES7.TSTypeLiteral,
2329
+ type: AST_NODE_TYPES8.TSTypeLiteral,
2250
2330
  members: node.body.body
2251
2331
  };
2252
2332
  checkTypeLiteral(synthetic, node);
@@ -2260,15 +2340,15 @@ var prefer_discriminated_union_default = ESLintUtils13.RuleCreator(
2260
2340
 
2261
2341
  // src/rules/prefer-schema-for-api-payload.ts
2262
2342
  import {
2263
- AST_NODE_TYPES as AST_NODE_TYPES8,
2264
- ESLintUtils as ESLintUtils14
2343
+ AST_NODE_TYPES as AST_NODE_TYPES9,
2344
+ ESLintUtils as ESLintUtils13
2265
2345
  } from "@typescript-eslint/utils";
2266
2346
  var unwrap = (node) => {
2267
2347
  let current = node;
2268
2348
  while (current !== null && current !== void 0) {
2269
- if (current.type === AST_NODE_TYPES8.TSAsExpression || current.type === AST_NODE_TYPES8.TSTypeAssertion || current.type === AST_NODE_TYPES8.TSNonNullExpression || current.type === AST_NODE_TYPES8.TSSatisfiesExpression) {
2349
+ if (current.type === AST_NODE_TYPES9.TSAsExpression || current.type === AST_NODE_TYPES9.TSTypeAssertion || current.type === AST_NODE_TYPES9.TSNonNullExpression || current.type === AST_NODE_TYPES9.TSSatisfiesExpression) {
2270
2350
  current = current.expression;
2271
- } else if (current.type === AST_NODE_TYPES8.ChainExpression) {
2351
+ } else if (current.type === AST_NODE_TYPES9.ChainExpression) {
2272
2352
  current = current.expression;
2273
2353
  } else {
2274
2354
  break;
@@ -2276,28 +2356,40 @@ var unwrap = (node) => {
2276
2356
  }
2277
2357
  return current ?? null;
2278
2358
  };
2359
+ var PROMISE_CHAIN_METHODS = /* @__PURE__ */ new Set([
2360
+ "then",
2361
+ "catch",
2362
+ "finally"
2363
+ ]);
2364
+ var isSchemaParseReference = (node) => {
2365
+ const inner = unwrap(node);
2366
+ return inner !== null && inner.type === AST_NODE_TYPES9.MemberExpression && !inner.computed && inner.property.type === AST_NODE_TYPES9.Identifier && (inner.property.name === "parse" || inner.property.name === "safeParse");
2367
+ };
2279
2368
  var isRawPayloadSource = (node) => {
2280
2369
  let current = unwrap(node);
2281
2370
  if (current === null) return false;
2282
- if (current.type === AST_NODE_TYPES8.AwaitExpression) {
2371
+ if (current.type === AST_NODE_TYPES9.AwaitExpression) {
2283
2372
  current = unwrap(current.argument);
2284
2373
  }
2285
- if (current === null || current.type !== AST_NODE_TYPES8.CallExpression) {
2374
+ if (current === null || current.type !== AST_NODE_TYPES9.CallExpression) {
2286
2375
  return false;
2287
2376
  }
2288
2377
  const callee = unwrap(current.callee);
2289
- if (callee === null || callee.type !== AST_NODE_TYPES8.MemberExpression) {
2378
+ if (callee === null || callee.type !== AST_NODE_TYPES9.MemberExpression) {
2290
2379
  return false;
2291
2380
  }
2292
2381
  const property = unwrap(callee.property);
2293
- if (property === null || property.type !== AST_NODE_TYPES8.Identifier) {
2382
+ if (property === null || property.type !== AST_NODE_TYPES9.Identifier) {
2294
2383
  return false;
2295
2384
  }
2296
2385
  if (property.name === "json") {
2297
2386
  return true;
2298
2387
  }
2388
+ if (PROMISE_CHAIN_METHODS.has(property.name)) {
2389
+ return !current.arguments.some(isSchemaParseReference) && isRawPayloadSource(callee.object);
2390
+ }
2299
2391
  const object = unwrap(callee.object);
2300
- return property.name === "parse" && object !== null && object.type === AST_NODE_TYPES8.Identifier && object.name === "JSON" && // ...but not `JSON.parse(readFileSync(p, "utf8"))` — see isLocalFileRead.
2392
+ return property.name === "parse" && object !== null && object.type === AST_NODE_TYPES9.Identifier && object.name === "JSON" && // ...but not `JSON.parse(readFileSync(p, "utf8"))` — see isLocalFileRead.
2301
2393
  !isLocalFileRead(current.arguments[0]);
2302
2394
  };
2303
2395
  var FILE_READ_RE = /^(readFile|readFileSync|readJson|readJsonSync|readJSON)$/;
@@ -2305,9 +2397,9 @@ var isLocalFileRead = (node) => {
2305
2397
  let found = false;
2306
2398
  const visit = (current) => {
2307
2399
  if (found || current === null || current === void 0) return;
2308
- if (current.type === AST_NODE_TYPES8.CallExpression) {
2400
+ if (current.type === AST_NODE_TYPES9.CallExpression) {
2309
2401
  const callee = unwrap(current.callee);
2310
- const name = callee?.type === AST_NODE_TYPES8.Identifier ? callee.name : callee?.type === AST_NODE_TYPES8.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES8.Identifier ? callee.property.name : null;
2402
+ const name = callee?.type === AST_NODE_TYPES9.Identifier ? callee.name : callee?.type === AST_NODE_TYPES9.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES9.Identifier ? callee.property.name : null;
2311
2403
  if (name !== null && FILE_READ_RE.test(name)) {
2312
2404
  found = true;
2313
2405
  return;
@@ -2329,15 +2421,15 @@ var isLocalFileRead = (node) => {
2329
2421
  var ASSERTION_CALLEE_RE = /^(expect|assert|should|invariant)$/;
2330
2422
  var isInsideAssertion = (node) => {
2331
2423
  for (let current = node.parent; current !== void 0 && current !== null; current = current.parent) {
2332
- if (current.type !== AST_NODE_TYPES8.CallExpression) continue;
2424
+ if (current.type !== AST_NODE_TYPES9.CallExpression) continue;
2333
2425
  let callee = current.callee;
2334
- while (callee.type === AST_NODE_TYPES8.MemberExpression) {
2426
+ while (callee.type === AST_NODE_TYPES9.MemberExpression) {
2335
2427
  callee = callee.object;
2336
2428
  }
2337
- if (callee.type === AST_NODE_TYPES8.CallExpression) {
2429
+ if (callee.type === AST_NODE_TYPES9.CallExpression) {
2338
2430
  callee = callee.callee;
2339
2431
  }
2340
- if (callee.type === AST_NODE_TYPES8.Identifier && ASSERTION_CALLEE_RE.test(callee.name)) {
2432
+ if (callee.type === AST_NODE_TYPES9.Identifier && ASSERTION_CALLEE_RE.test(callee.name)) {
2341
2433
  return true;
2342
2434
  }
2343
2435
  }
@@ -2352,23 +2444,43 @@ var findVariable2 = (scope, name) => {
2352
2444
  }
2353
2445
  return null;
2354
2446
  };
2355
- var GUARD_NAME_RE = /^is[A-Z]/;
2447
+ var GUARD_NAME_RE = /^(?:is|validate|parse|assert|decode|coerce)[A-Z]/;
2448
+ var isValidationRead = (node) => {
2449
+ let current = node;
2450
+ let parent = current.parent;
2451
+ while (parent !== null && parent !== void 0 && (parent.type === AST_NODE_TYPES9.TSAsExpression || parent.type === AST_NODE_TYPES9.TSTypeAssertion || parent.type === AST_NODE_TYPES9.TSNonNullExpression || parent.type === AST_NODE_TYPES9.TSSatisfiesExpression || parent.type === AST_NODE_TYPES9.ChainExpression)) {
2452
+ current = parent;
2453
+ parent = parent.parent;
2454
+ }
2455
+ if (parent === null || parent === void 0) return false;
2456
+ if (parent.type === AST_NODE_TYPES9.UnaryExpression && parent.operator === "typeof" && parent.argument === current) {
2457
+ return true;
2458
+ }
2459
+ if (parent.type !== AST_NODE_TYPES9.CallExpression || !parent.arguments.some((arg) => arg === current)) {
2460
+ return false;
2461
+ }
2462
+ const callee = parent.callee;
2463
+ if (callee.type === AST_NODE_TYPES9.MemberExpression && !callee.computed && callee.object.type === AST_NODE_TYPES9.Identifier && callee.object.name === "Array" && callee.property.type === AST_NODE_TYPES9.Identifier && callee.property.name === "isArray") {
2464
+ return parent.arguments.length === 1;
2465
+ }
2466
+ return callee.type === AST_NODE_TYPES9.Identifier && GUARD_NAME_RE.test(callee.name);
2467
+ };
2356
2468
  var isGuardTestPosition = (node) => {
2357
2469
  let current = node;
2358
2470
  let parent = current.parent;
2359
2471
  while (parent !== void 0 && parent !== null) {
2360
2472
  switch (parent.type) {
2361
- case AST_NODE_TYPES8.UnaryExpression:
2362
- case AST_NODE_TYPES8.LogicalExpression:
2363
- case AST_NODE_TYPES8.ChainExpression:
2473
+ case AST_NODE_TYPES9.UnaryExpression:
2474
+ case AST_NODE_TYPES9.LogicalExpression:
2475
+ case AST_NODE_TYPES9.ChainExpression:
2364
2476
  current = parent;
2365
2477
  parent = parent.parent;
2366
2478
  continue;
2367
- case AST_NODE_TYPES8.IfStatement:
2368
- case AST_NODE_TYPES8.ConditionalExpression:
2369
- case AST_NODE_TYPES8.WhileStatement:
2370
- case AST_NODE_TYPES8.DoWhileStatement:
2371
- case AST_NODE_TYPES8.ForStatement:
2479
+ case AST_NODE_TYPES9.IfStatement:
2480
+ case AST_NODE_TYPES9.ConditionalExpression:
2481
+ case AST_NODE_TYPES9.WhileStatement:
2482
+ case AST_NODE_TYPES9.DoWhileStatement:
2483
+ case AST_NODE_TYPES9.ForStatement:
2372
2484
  return parent.test === current;
2373
2485
  default:
2374
2486
  return false;
@@ -2378,13 +2490,13 @@ var isGuardTestPosition = (node) => {
2378
2490
  };
2379
2491
  var isUnvalidatedVariableRef = (node, scope, tracked) => {
2380
2492
  const unwrapped = unwrap(node);
2381
- if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES8.Identifier) {
2493
+ if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES9.Identifier) {
2382
2494
  return false;
2383
2495
  }
2384
2496
  const variable = findVariable2(scope, unwrapped.name);
2385
2497
  return variable !== null && tracked.has(variable);
2386
2498
  };
2387
- var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2499
+ var prefer_schema_for_api_payload_default = ESLintUtils13.RuleCreator(
2388
2500
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
2389
2501
  )({
2390
2502
  name: "prefer-schema-for-api-payload",
@@ -2404,6 +2516,14 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2404
2516
  return {};
2405
2517
  }
2406
2518
  const unvalidatedVariables = /* @__PURE__ */ new Set();
2519
+ const isFullyNarrowedPattern = (declarator) => {
2520
+ const declared = context.sourceCode.getDeclaredVariables(declarator);
2521
+ return declared.length > 0 && declared.every(
2522
+ (variable) => variable.references.some(
2523
+ (reference) => isValidationRead(reference.identifier)
2524
+ )
2525
+ );
2526
+ };
2407
2527
  const trackInitializer = (declarator) => {
2408
2528
  if (!isRawPayloadSource(declarator.init)) return;
2409
2529
  const declaredVars = context.sourceCode.getDeclaredVariables(declarator);
@@ -2415,13 +2535,15 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2415
2535
  return {
2416
2536
  VariableDeclarator(node) {
2417
2537
  const scope = context.sourceCode.getScope(node);
2418
- if (node.id.type === AST_NODE_TYPES8.Identifier) {
2538
+ if (node.id.type === AST_NODE_TYPES9.Identifier) {
2419
2539
  trackInitializer(node);
2420
2540
  return;
2421
2541
  }
2422
- if (node.id.type === AST_NODE_TYPES8.ObjectPattern || node.id.type === AST_NODE_TYPES8.ArrayPattern) {
2542
+ if (node.id.type === AST_NODE_TYPES9.ObjectPattern || node.id.type === AST_NODE_TYPES9.ArrayPattern) {
2423
2543
  if (isRawPayloadSource(node.init)) {
2424
- context.report({ node: node.id, messageId: "unparsedJsonAccess" });
2544
+ if (!isFullyNarrowedPattern(node)) {
2545
+ context.report({ node: node.id, messageId: "unparsedJsonAccess" });
2546
+ }
2425
2547
  return;
2426
2548
  }
2427
2549
  if (isUnvalidatedVariableRef(node.init, scope, unvalidatedVariables)) {
@@ -2431,7 +2553,7 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2431
2553
  },
2432
2554
  AssignmentExpression(node) {
2433
2555
  const scope = context.sourceCode.getScope(node);
2434
- if (node.left.type === AST_NODE_TYPES8.Identifier) {
2556
+ if (node.left.type === AST_NODE_TYPES9.Identifier) {
2435
2557
  const variable = findVariable2(scope, node.left.name);
2436
2558
  if (variable === null) return;
2437
2559
  if (isRawPayloadSource(node.right)) {
@@ -2441,7 +2563,7 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2441
2563
  }
2442
2564
  return;
2443
2565
  }
2444
- if (node.left.type === AST_NODE_TYPES8.ObjectPattern || node.left.type === AST_NODE_TYPES8.ArrayPattern) {
2566
+ if (node.left.type === AST_NODE_TYPES9.ObjectPattern || node.left.type === AST_NODE_TYPES9.ArrayPattern) {
2445
2567
  if (isRawPayloadSource(node.right)) {
2446
2568
  context.report({
2447
2569
  node: node.left,
@@ -2458,15 +2580,15 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2458
2580
  }
2459
2581
  },
2460
2582
  CallExpression(node) {
2461
- if (node.callee.type !== AST_NODE_TYPES8.Identifier) return;
2583
+ if (node.callee.type !== AST_NODE_TYPES9.Identifier) return;
2462
2584
  if (!GUARD_NAME_RE.test(node.callee.name) && !isGuardTestPosition(node)) {
2463
2585
  return;
2464
2586
  }
2465
2587
  const scope = context.sourceCode.getScope(node);
2466
2588
  for (const arg of node.arguments) {
2467
- if (arg.type === AST_NODE_TYPES8.SpreadElement) continue;
2589
+ if (arg.type === AST_NODE_TYPES9.SpreadElement) continue;
2468
2590
  const unwrapped = unwrap(arg);
2469
- if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES8.Identifier) {
2591
+ if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES9.Identifier) {
2470
2592
  continue;
2471
2593
  }
2472
2594
  const variable = findVariable2(scope, unwrapped.name);
@@ -2475,17 +2597,18 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2475
2597
  },
2476
2598
  MemberExpression(node) {
2477
2599
  if (isInsideAssertion(node)) return;
2600
+ if (isValidationRead(node)) return;
2478
2601
  const scope = context.sourceCode.getScope(node);
2479
2602
  const obj = unwrap(node.object);
2480
2603
  if (isRawPayloadSource(obj)) {
2481
2604
  const parent = node.parent;
2482
- if (parent.type === AST_NODE_TYPES8.CallExpression && parent.callee === node && node.property.type === AST_NODE_TYPES8.Identifier && (node.property.name === "parse" || node.property.name === "safeParse")) {
2605
+ if (parent.type === AST_NODE_TYPES9.CallExpression && parent.callee === node && node.property.type === AST_NODE_TYPES9.Identifier && (node.property.name === "parse" || node.property.name === "safeParse" || PROMISE_CHAIN_METHODS.has(node.property.name))) {
2483
2606
  return;
2484
2607
  }
2485
2608
  context.report({ node, messageId: "unparsedJsonAccess" });
2486
2609
  return;
2487
2610
  }
2488
- if (obj !== null && obj.type === AST_NODE_TYPES8.Identifier && isUnvalidatedVariableRef(obj, scope, unvalidatedVariables)) {
2611
+ if (obj !== null && obj.type === AST_NODE_TYPES9.Identifier && isUnvalidatedVariableRef(obj, scope, unvalidatedVariables)) {
2489
2612
  context.report({ node, messageId: "unparsedJsonAccess" });
2490
2613
  const variable = findVariable2(scope, obj.name);
2491
2614
  if (variable !== null) {
@@ -2498,7 +2621,7 @@ var prefer_schema_for_api_payload_default = ESLintUtils14.RuleCreator(
2498
2621
  });
2499
2622
 
2500
2623
  // src/rules/prefer-semantic-colors.ts
2501
- import { AST_NODE_TYPES as AST_NODE_TYPES9, ESLintUtils as ESLintUtils15 } from "@typescript-eslint/utils";
2624
+ import { AST_NODE_TYPES as AST_NODE_TYPES10, ESLintUtils as ESLintUtils14 } from "@typescript-eslint/utils";
2502
2625
  import { existsSync, readFileSync } from "fs";
2503
2626
  import { dirname, join, parse } from "path";
2504
2627
 
@@ -2510,7 +2633,8 @@ var classTokens = (value) => value.split(/\s+/).filter(Boolean);
2510
2633
  var COLOR_PREFIXES = "text|bg|border(?:-[trblxyse])?|ring(?:-offset)?|fill|stroke|from|via|to|divide|decoration|placeholder|accent|caret|shadow|outline";
2511
2634
  var PALETTE = "red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|slate|gray|zinc|neutral|stone";
2512
2635
  var COLOR_FN = "rgba?|hsla?|hwb|oklch|oklab|lab|lch|color";
2513
- var RAW_PALETTE_RE = new RegExp(`^(?:${COLOR_PREFIXES})-(?:${PALETTE})-\\d{2,3}(?:/\\d{1,3})?$`);
2636
+ var PALETTE_STEP = "50|[1-9]00|950";
2637
+ var RAW_PALETTE_RE = new RegExp(`^(?:${COLOR_PREFIXES})-(?:${PALETTE})-(?:${PALETTE_STEP})(?:/\\d{1,3})?$`);
2514
2638
  var ARBITRARY_COLOR_RE = new RegExp(
2515
2639
  `^(?:${COLOR_PREFIXES})-\\[(?:#[0-9a-fA-F]{3,8}|(?:${COLOR_FN})\\([^\\]]*\\))\\]$`,
2516
2640
  "i"
@@ -2537,6 +2661,7 @@ var STYLE_COLOR_PROPS = /* @__PURE__ */ new Set([
2537
2661
  "lightingColor"
2538
2662
  ]);
2539
2663
  var RAW_COLOR_VALUE_RE = new RegExp(`#[0-9a-fA-F]{3,8}\\b|\\b(?:${COLOR_FN})\\s*\\(`, "i");
2664
+ var CSS_VAR_REFERENCE_RE = /var\(\s*--/;
2540
2665
  var STORIES_FILE_RE = /\.stories\.[cm]?[jt]sx?$/i;
2541
2666
  var SEMANTIC_TOKEN_RE = /--(?:background|foreground|primary|secondary|muted|accent|destructive|border|card|popover)\b|(?:bg|text|border)-(?:background|foreground|primary|secondary|muted|accent|destructive|border|card|popover)\b/;
2542
2667
  var DETECTION_FILES = [
@@ -2573,8 +2698,8 @@ var SVG_EXEMPT_COLOR_VALUES = /* @__PURE__ */ new Set([
2573
2698
  ]);
2574
2699
  function jsxElementName(node) {
2575
2700
  const name = node.openingElement.name;
2576
- if (name.type === AST_NODE_TYPES9.JSXIdentifier) return name.name;
2577
- if (name.type === AST_NODE_TYPES9.JSXMemberExpression && name.property.type === AST_NODE_TYPES9.JSXIdentifier) {
2701
+ if (name.type === AST_NODE_TYPES10.JSXIdentifier) return name.name;
2702
+ if (name.type === AST_NODE_TYPES10.JSXMemberExpression && name.property.type === AST_NODE_TYPES10.JSXIdentifier) {
2578
2703
  return name.property.name;
2579
2704
  }
2580
2705
  return null;
@@ -2582,10 +2707,25 @@ function jsxElementName(node) {
2582
2707
  function isSvgLikeElementName(name) {
2583
2708
  return name === "svg" || SVG_DEFS_CONTAINERS.has(name) || /svg$/i.test(name);
2584
2709
  }
2710
+ var SVG_SHAPE_PRIMITIVES = /* @__PURE__ */ new Set([
2711
+ "circle",
2712
+ "ellipse",
2713
+ "g",
2714
+ "line",
2715
+ "path",
2716
+ "polygon",
2717
+ "polyline",
2718
+ "rect",
2719
+ "stop",
2720
+ "text",
2721
+ "tspan",
2722
+ "use"
2723
+ ]);
2724
+ var EMAIL_OR_PDF_IMPORT_RE = /@react-(?:email|pdf)\//;
2585
2725
  var isInsideSvg = (node) => {
2586
2726
  let current = node.parent;
2587
2727
  while (current !== void 0 && current !== null) {
2588
- if (current.type === AST_NODE_TYPES9.JSXElement) {
2728
+ if (current.type === AST_NODE_TYPES10.JSXElement) {
2589
2729
  const name = jsxElementName(current);
2590
2730
  if (name !== null && isSvgLikeElementName(name)) return true;
2591
2731
  }
@@ -2596,7 +2736,7 @@ var isInsideSvg = (node) => {
2596
2736
  var isInsideIconFactoryPath = (node) => {
2597
2737
  let current = node.parent;
2598
2738
  while (current !== void 0 && current !== null) {
2599
- if (current.type === AST_NODE_TYPES9.Property && propName(current.key) === "path" && current.parent.type === AST_NODE_TYPES9.ObjectExpression && current.parent.parent.type === AST_NODE_TYPES9.CallExpression && current.parent.parent.callee.type === AST_NODE_TYPES9.Identifier && current.parent.parent.callee.name === "createIcon") {
2739
+ if (current.type === AST_NODE_TYPES10.Property && propName(current.key) === "path" && current.parent.type === AST_NODE_TYPES10.ObjectExpression && current.parent.parent.type === AST_NODE_TYPES10.CallExpression && current.parent.parent.callee.type === AST_NODE_TYPES10.Identifier && current.parent.parent.callee.name === "createIcon") {
2600
2740
  return true;
2601
2741
  }
2602
2742
  current = current.parent;
@@ -2646,11 +2786,11 @@ var hasSemanticTokenSystem = (filename) => {
2646
2786
  return answer;
2647
2787
  };
2648
2788
  var propName = (key) => {
2649
- if (key.type === AST_NODE_TYPES9.Identifier) return key.name;
2650
- if (key.type === AST_NODE_TYPES9.Literal && typeof key.value === "string") return key.value;
2789
+ if (key.type === AST_NODE_TYPES10.Identifier) return key.name;
2790
+ if (key.type === AST_NODE_TYPES10.Literal && typeof key.value === "string") return key.value;
2651
2791
  return null;
2652
2792
  };
2653
- var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2793
+ var prefer_semantic_colors_default = ESLintUtils14.RuleCreator(
2654
2794
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
2655
2795
  )({
2656
2796
  name: "prefer-semantic-colors",
@@ -2677,6 +2817,7 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2677
2817
  defaultOptions: [{}],
2678
2818
  create(context, [options]) {
2679
2819
  if (STORIES_FILE_RE.test(context.filename)) return {};
2820
+ if (EMAIL_OR_PDF_IMPORT_RE.test(context.sourceCode.getText())) return {};
2680
2821
  if (options?.requireSemanticTokens === true && !hasSemanticTokenSystem(context.filename)) {
2681
2822
  return {};
2682
2823
  }
@@ -2685,7 +2826,7 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2685
2826
  const base = tailwindBase(token);
2686
2827
  if (RAW_PALETTE_RE.test(base)) {
2687
2828
  context.report({ node, messageId: "rawPalette", data: { class: token } });
2688
- } else if (ARBITRARY_COLOR_RE.test(base)) {
2829
+ } else if (ARBITRARY_COLOR_RE.test(base) && !CSS_VAR_REFERENCE_RE.test(base)) {
2689
2830
  context.report({ node, messageId: "arbitraryColor", data: { class: token } });
2690
2831
  }
2691
2832
  }
@@ -2693,27 +2834,27 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2693
2834
  const checkClassNode = (node) => {
2694
2835
  if (node === null) return;
2695
2836
  switch (node.type) {
2696
- case AST_NODE_TYPES9.Literal:
2837
+ case AST_NODE_TYPES10.Literal:
2697
2838
  if (typeof node.value === "string") reportClasses(node.value, node);
2698
2839
  break;
2699
- case AST_NODE_TYPES9.TemplateLiteral:
2840
+ case AST_NODE_TYPES10.TemplateLiteral:
2700
2841
  for (const quasi of node.quasis) reportClasses(quasi.value.cooked ?? "", quasi);
2701
2842
  break;
2702
- case AST_NODE_TYPES9.ArrayExpression:
2843
+ case AST_NODE_TYPES10.ArrayExpression:
2703
2844
  for (const element of node.elements) {
2704
- if (element !== null && element.type !== AST_NODE_TYPES9.SpreadElement) checkClassNode(element);
2845
+ if (element !== null && element.type !== AST_NODE_TYPES10.SpreadElement) checkClassNode(element);
2705
2846
  }
2706
2847
  break;
2707
- case AST_NODE_TYPES9.ObjectExpression:
2848
+ case AST_NODE_TYPES10.ObjectExpression:
2708
2849
  for (const property of node.properties) {
2709
- if (property.type === AST_NODE_TYPES9.Property) checkClassNode(property.value);
2850
+ if (property.type === AST_NODE_TYPES10.Property) checkClassNode(property.value);
2710
2851
  }
2711
2852
  break;
2712
- case AST_NODE_TYPES9.ConditionalExpression:
2853
+ case AST_NODE_TYPES10.ConditionalExpression:
2713
2854
  checkClassNode(node.consequent);
2714
2855
  checkClassNode(node.alternate);
2715
2856
  break;
2716
- case AST_NODE_TYPES9.LogicalExpression:
2857
+ case AST_NODE_TYPES10.LogicalExpression:
2717
2858
  checkClassNode(node.right);
2718
2859
  break;
2719
2860
  default:
@@ -2721,29 +2862,29 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2721
2862
  }
2722
2863
  };
2723
2864
  const checkColorValueNode = (node) => {
2724
- if (node.type === AST_NODE_TYPES9.Literal && typeof node.value === "string" && RAW_COLOR_VALUE_RE.test(node.value)) {
2865
+ if (node.type === AST_NODE_TYPES10.Literal && typeof node.value === "string" && RAW_COLOR_VALUE_RE.test(node.value) && !CSS_VAR_REFERENCE_RE.test(node.value)) {
2725
2866
  context.report({ node, messageId: "inlineColor", data: { value: node.value } });
2726
2867
  }
2727
2868
  };
2728
2869
  return {
2729
2870
  "JSXAttribute[name.name='className']"(node) {
2730
2871
  if (node.value === null) return;
2731
- if (node.value.type === AST_NODE_TYPES9.Literal) checkClassNode(node.value);
2732
- else if (node.value.type === AST_NODE_TYPES9.JSXExpressionContainer) {
2733
- if (node.value.expression.type !== AST_NODE_TYPES9.JSXEmptyExpression) {
2872
+ if (node.value.type === AST_NODE_TYPES10.Literal) checkClassNode(node.value);
2873
+ else if (node.value.type === AST_NODE_TYPES10.JSXExpressionContainer) {
2874
+ if (node.value.expression.type !== AST_NODE_TYPES10.JSXEmptyExpression) {
2734
2875
  checkClassNode(node.value.expression);
2735
2876
  }
2736
2877
  }
2737
2878
  },
2738
2879
  CallExpression(node) {
2739
- if (node.callee.type === AST_NODE_TYPES9.Identifier && CLASS_FNS.has(node.callee.name)) {
2880
+ if (node.callee.type === AST_NODE_TYPES10.Identifier && CLASS_FNS.has(node.callee.name)) {
2740
2881
  for (const arg of node.arguments) {
2741
- if (arg.type !== AST_NODE_TYPES9.SpreadElement) checkClassNode(arg);
2882
+ if (arg.type !== AST_NODE_TYPES10.SpreadElement) checkClassNode(arg);
2742
2883
  }
2743
2884
  }
2744
2885
  },
2745
2886
  VariableDeclarator(node) {
2746
- if (node.id.type === AST_NODE_TYPES9.Identifier && CLASS_NAME_RE.test(node.id.name)) {
2887
+ if (node.id.type === AST_NODE_TYPES10.Identifier && CLASS_NAME_RE.test(node.id.name)) {
2747
2888
  checkClassNode(node.init);
2748
2889
  }
2749
2890
  },
@@ -2755,7 +2896,11 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2755
2896
  // Neutral drawing literals and anything inside an SVG defs container are
2756
2897
  // structural, not UI tokens, so they never fire.
2757
2898
  "JSXAttribute[name.name=/^(fill|stroke|color)$/]"(node) {
2758
- if (node.value?.type !== AST_NODE_TYPES9.Literal) return;
2899
+ if (node.value?.type !== AST_NODE_TYPES10.Literal) return;
2900
+ const owner = node.parent.name;
2901
+ if (owner.type === AST_NODE_TYPES10.JSXIdentifier && SVG_SHAPE_PRIMITIVES.has(owner.name)) {
2902
+ return;
2903
+ }
2759
2904
  if (typeof node.value.value === "string" && SVG_EXEMPT_COLOR_VALUES.has(node.value.value.toLowerCase())) {
2760
2905
  return;
2761
2906
  }
@@ -2772,7 +2917,7 @@ var prefer_semantic_colors_default = ESLintUtils15.RuleCreator(
2772
2917
  });
2773
2918
 
2774
2919
  // src/rules/prefer-server-actions.ts
2775
- import { ESLintUtils as ESLintUtils16 } from "@typescript-eslint/utils";
2920
+ import { ESLintUtils as ESLintUtils15 } from "@typescript-eslint/utils";
2776
2921
  var MUTATION_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "DELETE", "PATCH"]);
2777
2922
  var AXIOS_MUTATION_METHODS = /* @__PURE__ */ new Set(["post", "put", "delete", "patch"]);
2778
2923
  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\/)/;
@@ -2852,7 +2997,7 @@ function getPropertyNode(objNode, propName2) {
2852
2997
  }
2853
2998
  return null;
2854
2999
  }
2855
- var prefer_server_actions_default = ESLintUtils16.RuleCreator(
3000
+ var prefer_server_actions_default = ESLintUtils15.RuleCreator(
2856
3001
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
2857
3002
  )({
2858
3003
  name: "prefer-server-actions",
@@ -2928,38 +3073,38 @@ var prefer_server_actions_default = ESLintUtils16.RuleCreator(
2928
3073
 
2929
3074
  // src/rules/require-assert-never.ts
2930
3075
  import {
2931
- ESLintUtils as ESLintUtils17,
2932
- AST_NODE_TYPES as AST_NODE_TYPES10
3076
+ ESLintUtils as ESLintUtils16,
3077
+ AST_NODE_TYPES as AST_NODE_TYPES11
2933
3078
  } from "@typescript-eslint/utils";
2934
3079
  var isAssertNeverCall = (expression) => {
2935
- if (expression.type !== AST_NODE_TYPES10.CallExpression) return false;
3080
+ if (expression.type !== AST_NODE_TYPES11.CallExpression) return false;
2936
3081
  const callee = expression.callee;
2937
- if (callee.type === AST_NODE_TYPES10.Identifier) {
3082
+ if (callee.type === AST_NODE_TYPES11.Identifier) {
2938
3083
  return callee.name === "assertNever";
2939
3084
  }
2940
- if (callee.type === AST_NODE_TYPES10.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES10.Identifier) {
3085
+ if (callee.type === AST_NODE_TYPES11.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES11.Identifier) {
2941
3086
  return callee.property.name === "assertNever";
2942
3087
  }
2943
3088
  return false;
2944
3089
  };
2945
3090
  var statementContainsAssertNever = (statement) => {
2946
- if (statement.type === AST_NODE_TYPES10.ExpressionStatement) {
3091
+ if (statement.type === AST_NODE_TYPES11.ExpressionStatement) {
2947
3092
  return isAssertNeverCall(statement.expression);
2948
3093
  }
2949
- if (statement.type === AST_NODE_TYPES10.ThrowStatement) {
3094
+ if (statement.type === AST_NODE_TYPES11.ThrowStatement) {
2950
3095
  return isAssertNeverCall(statement.argument);
2951
3096
  }
2952
- if (statement.type === AST_NODE_TYPES10.ReturnStatement) {
3097
+ if (statement.type === AST_NODE_TYPES11.ReturnStatement) {
2953
3098
  return statement.argument !== null && isAssertNeverCall(statement.argument);
2954
3099
  }
2955
- if (statement.type === AST_NODE_TYPES10.BlockStatement) {
3100
+ if (statement.type === AST_NODE_TYPES11.BlockStatement) {
2956
3101
  return statement.body.some(statementContainsAssertNever);
2957
3102
  }
2958
3103
  return false;
2959
3104
  };
2960
3105
  var isRuntimeHandlingStatement = (statement) => {
2961
- if (statement.type === AST_NODE_TYPES10.EmptyStatement) return false;
2962
- if (statement.type === AST_NODE_TYPES10.BlockStatement) {
3106
+ if (statement.type === AST_NODE_TYPES11.EmptyStatement) return false;
3107
+ if (statement.type === AST_NODE_TYPES11.BlockStatement) {
2963
3108
  return statement.body.some(isRuntimeHandlingStatement);
2964
3109
  }
2965
3110
  return true;
@@ -2975,12 +3120,12 @@ var isCommentOnlyNoopDefault = (defaultCase, sourceCode) => {
2975
3120
  return colonToken !== null && sourceCode.getCommentsAfter(colonToken).length > 0;
2976
3121
  }
2977
3122
  const only = defaultCase.consequent[0];
2978
- if (only !== void 0 && defaultCase.consequent.length === 1 && only.type === AST_NODE_TYPES10.BlockStatement && only.body.length === 0) {
3123
+ if (only !== void 0 && defaultCase.consequent.length === 1 && only.type === AST_NODE_TYPES11.BlockStatement && only.body.length === 0) {
2979
3124
  return sourceCode.getCommentsInside(only).length > 0;
2980
3125
  }
2981
3126
  return false;
2982
3127
  };
2983
- var require_assert_never_default = ESLintUtils17.RuleCreator(
3128
+ var require_assert_never_default = ESLintUtils16.RuleCreator(
2984
3129
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
2985
3130
  )({
2986
3131
  name: "require-assert-never",
@@ -3018,7 +3163,7 @@ var require_assert_never_default = ESLintUtils17.RuleCreator(
3018
3163
  });
3019
3164
 
3020
3165
  // src/rules/require-zod-form-validation.ts
3021
- import { ESLintUtils as ESLintUtils18, AST_NODE_TYPES as AST_NODE_TYPES11 } from "@typescript-eslint/utils";
3166
+ import { ESLintUtils as ESLintUtils17, AST_NODE_TYPES as AST_NODE_TYPES12 } from "@typescript-eslint/utils";
3022
3167
 
3023
3168
  // src/rules/_zod.ts
3024
3169
  var ZOD_PREFIX_RE = /^Z[A-Z]/;
@@ -3032,14 +3177,14 @@ function isZodModule(source) {
3032
3177
  var looksLikeZodSchema = (node) => {
3033
3178
  let current = node;
3034
3179
  while (true) {
3035
- if (current.type === AST_NODE_TYPES11.Identifier) {
3180
+ if (current.type === AST_NODE_TYPES12.Identifier) {
3036
3181
  return current.name === "z" || ZOD_SCHEMA_NAME_RE.test(current.name);
3037
3182
  }
3038
- if (current.type === AST_NODE_TYPES11.CallExpression) {
3183
+ if (current.type === AST_NODE_TYPES12.CallExpression) {
3039
3184
  current = current.callee;
3040
3185
  continue;
3041
3186
  }
3042
- if (current.type === AST_NODE_TYPES11.MemberExpression) {
3187
+ if (current.type === AST_NODE_TYPES12.MemberExpression) {
3043
3188
  current = current.object;
3044
3189
  continue;
3045
3190
  }
@@ -3047,25 +3192,25 @@ var looksLikeZodSchema = (node) => {
3047
3192
  }
3048
3193
  };
3049
3194
  var isZodParseCall = (node) => {
3050
- if (node.type !== AST_NODE_TYPES11.CallExpression) return false;
3195
+ if (node.type !== AST_NODE_TYPES12.CallExpression) return false;
3051
3196
  const callee = node.callee;
3052
- if (callee.type !== AST_NODE_TYPES11.MemberExpression) return false;
3197
+ if (callee.type !== AST_NODE_TYPES12.MemberExpression) return false;
3053
3198
  if (callee.computed) return false;
3054
- if (callee.property.type !== AST_NODE_TYPES11.Identifier) return false;
3199
+ if (callee.property.type !== AST_NODE_TYPES12.Identifier) return false;
3055
3200
  const method = callee.property.name;
3056
3201
  if (method !== "parse" && method !== "safeParse") return false;
3057
3202
  return looksLikeZodSchema(callee.object);
3058
3203
  };
3059
3204
  var isFormDataMethodCall = (node) => {
3060
3205
  let current = node;
3061
- if (current.type === AST_NODE_TYPES11.AwaitExpression) {
3206
+ if (current.type === AST_NODE_TYPES12.AwaitExpression) {
3062
3207
  current = current.argument;
3063
3208
  }
3064
- if (current.type !== AST_NODE_TYPES11.CallExpression) return false;
3209
+ if (current.type !== AST_NODE_TYPES12.CallExpression) return false;
3065
3210
  const callee = current.callee;
3066
- return callee.type === AST_NODE_TYPES11.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES11.Identifier && callee.property.name === "formData";
3211
+ return callee.type === AST_NODE_TYPES12.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES12.Identifier && callee.property.name === "formData";
3067
3212
  };
3068
- var require_zod_form_validation_default = ESLintUtils18.RuleCreator(
3213
+ var require_zod_form_validation_default = ESLintUtils17.RuleCreator(
3069
3214
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3070
3215
  )({
3071
3216
  name: "require-zod-form-validation",
@@ -3085,14 +3230,14 @@ var require_zod_form_validation_default = ESLintUtils18.RuleCreator(
3085
3230
  return {};
3086
3231
  }
3087
3232
  const isFormSourceIdentifier = (node) => {
3088
- if (node.type !== AST_NODE_TYPES11.Identifier) return false;
3233
+ if (node.type !== AST_NODE_TYPES12.Identifier) return false;
3089
3234
  if (/formdata/i.test(node.name)) return true;
3090
3235
  let scope = context.sourceCode.getScope(node);
3091
3236
  while (scope !== null) {
3092
3237
  const variable = scope.set.get(node.name);
3093
3238
  if (variable !== void 0 && variable.defs.length === 1) {
3094
3239
  const def = variable.defs[0];
3095
- if (def !== void 0 && def.type === "Variable" && def.node.type === AST_NODE_TYPES11.VariableDeclarator && def.node.init !== null) {
3240
+ if (def !== void 0 && def.type === "Variable" && def.node.type === AST_NODE_TYPES12.VariableDeclarator && def.node.init !== null) {
3096
3241
  return isFormDataMethodCall(def.node.init);
3097
3242
  }
3098
3243
  return false;
@@ -3103,8 +3248,8 @@ var require_zod_form_validation_default = ESLintUtils18.RuleCreator(
3103
3248
  };
3104
3249
  const isFormDataGetCall = (node) => {
3105
3250
  const callee = node.callee;
3106
- if (callee.type !== AST_NODE_TYPES11.MemberExpression) return false;
3107
- if (callee.property.type !== AST_NODE_TYPES11.Identifier || callee.property.name !== "get") {
3251
+ if (callee.type !== AST_NODE_TYPES12.MemberExpression) return false;
3252
+ if (callee.property.type !== AST_NODE_TYPES12.Identifier || callee.property.name !== "get") {
3108
3253
  return false;
3109
3254
  }
3110
3255
  return isFormSourceIdentifier(callee.object);
@@ -3119,11 +3264,11 @@ var require_zod_form_validation_default = ESLintUtils18.RuleCreator(
3119
3264
  };
3120
3265
  const isInstanceofNarrowing = (node) => {
3121
3266
  const parent = node.parent;
3122
- return parent !== null && parent !== void 0 && parent.type === AST_NODE_TYPES11.BinaryExpression && parent.operator === "instanceof" && parent.left === node;
3267
+ return parent !== null && parent !== void 0 && parent.type === AST_NODE_TYPES12.BinaryExpression && parent.operator === "instanceof" && parent.left === node;
3123
3268
  };
3124
3269
  const boundDeclarator = (node) => {
3125
3270
  const parent = node.parent;
3126
- if (parent.type === AST_NODE_TYPES11.VariableDeclarator && parent.init === node && parent.id.type === AST_NODE_TYPES11.Identifier) {
3271
+ if (parent.type === AST_NODE_TYPES12.VariableDeclarator && parent.init === node && parent.id.type === AST_NODE_TYPES12.Identifier) {
3127
3272
  return parent;
3128
3273
  }
3129
3274
  return null;
@@ -3151,13 +3296,14 @@ var require_zod_form_validation_default = ESLintUtils18.RuleCreator(
3151
3296
  });
3152
3297
 
3153
3298
  // src/rules/zod-naming-convention.ts
3154
- import { ESLintUtils as ESLintUtils19, AST_NODE_TYPES as AST_NODE_TYPES12 } from "@typescript-eslint/utils";
3299
+ import { ESLintUtils as ESLintUtils18, AST_NODE_TYPES as AST_NODE_TYPES13 } from "@typescript-eslint/utils";
3155
3300
  var CONVENTIONS = {
3156
3301
  prefix: { test: ZOD_PREFIX_RE, messageId: "zPrefix" },
3157
3302
  suffix: { test: ZOD_SUFFIX_RE, messageId: "schemaSuffix" },
3158
3303
  either: { test: ZOD_SCHEMA_NAME_RE, messageId: "zodSchemaName" }
3159
3304
  };
3160
3305
  var CONTAINS_SCHEMA_RE = /schema/i;
3306
+ var BENCHMARK_PATH_RE = /(^|[\\/])(?:benchmarks?|bench)[\\/]/;
3161
3307
  var NON_SCHEMA_TERMINALS = /* @__PURE__ */ new Set([
3162
3308
  "parse",
3163
3309
  "parseAsync",
@@ -3175,15 +3321,15 @@ var NON_SCHEMA_TERMINALS = /* @__PURE__ */ new Set([
3175
3321
  "registry",
3176
3322
  "implement"
3177
3323
  ]);
3178
- var terminalMethodName = (callee) => !callee.computed && callee.property.type === AST_NODE_TYPES12.Identifier ? callee.property.name : null;
3324
+ var terminalMethodName = (callee) => !callee.computed && callee.property.type === AST_NODE_TYPES13.Identifier ? callee.property.name : null;
3179
3325
  var calleeChainStartsWithZ = (node) => {
3180
3326
  let current = node;
3181
- while (current.type === AST_NODE_TYPES12.MemberExpression) {
3327
+ while (current.type === AST_NODE_TYPES13.MemberExpression) {
3182
3328
  const receiver = current.object;
3183
- if (receiver.type === AST_NODE_TYPES12.Identifier && receiver.name === "z") {
3329
+ if (receiver.type === AST_NODE_TYPES13.Identifier && receiver.name === "z") {
3184
3330
  return true;
3185
3331
  }
3186
- if (receiver.type === AST_NODE_TYPES12.CallExpression) {
3332
+ if (receiver.type === AST_NODE_TYPES13.CallExpression) {
3187
3333
  current = receiver.callee;
3188
3334
  continue;
3189
3335
  }
@@ -3191,7 +3337,7 @@ var calleeChainStartsWithZ = (node) => {
3191
3337
  }
3192
3338
  return false;
3193
3339
  };
3194
- var zod_naming_convention_default = ESLintUtils19.RuleCreator(
3340
+ var zod_naming_convention_default = ESLintUtils18.RuleCreator(
3195
3341
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3196
3342
  )({
3197
3343
  name: "zod-naming-convention",
@@ -3223,20 +3369,20 @@ var zod_naming_convention_default = ESLintUtils19.RuleCreator(
3223
3369
  const convention = optionsArg?.convention ?? "either";
3224
3370
  const { test, messageId } = CONVENTIONS[convention];
3225
3371
  const acceptsSchemaWord = convention !== "prefix";
3226
- if (isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) {
3372
+ if (isTestFile(context.filename) || BENCHMARK_PATH_RE.test(context.filename.replaceAll("\\", "/")) || isGeneratedFile(context.filename, context.sourceCode.text)) {
3227
3373
  return {};
3228
3374
  }
3229
3375
  return {
3230
3376
  VariableDeclarator(node) {
3231
3377
  const init = node.init;
3232
3378
  if (init === null || init === void 0) return;
3233
- if (init.type !== AST_NODE_TYPES12.CallExpression) return;
3379
+ if (init.type !== AST_NODE_TYPES13.CallExpression) return;
3234
3380
  const callee = init.callee;
3235
- if (callee.type !== AST_NODE_TYPES12.MemberExpression) return;
3381
+ if (callee.type !== AST_NODE_TYPES13.MemberExpression) return;
3236
3382
  if (!calleeChainStartsWithZ(callee)) return;
3237
3383
  const terminal = terminalMethodName(callee);
3238
3384
  if (terminal !== null && NON_SCHEMA_TERMINALS.has(terminal)) return;
3239
- if (node.id.type !== AST_NODE_TYPES12.Identifier) return;
3385
+ if (node.id.type !== AST_NODE_TYPES13.Identifier) return;
3240
3386
  if (test.test(node.id.name)) return;
3241
3387
  if (acceptsSchemaWord && CONTAINS_SCHEMA_RE.test(node.id.name)) return;
3242
3388
  context.report({
@@ -3249,7 +3395,7 @@ var zod_naming_convention_default = ESLintUtils19.RuleCreator(
3249
3395
  });
3250
3396
 
3251
3397
  // src/rules/no-cors-wildcard-with-credentials.ts
3252
- import { ESLintUtils as ESLintUtils20 } from "@typescript-eslint/utils";
3398
+ import { ESLintUtils as ESLintUtils19 } from "@typescript-eslint/utils";
3253
3399
  var ACAO_HEADER = "access-control-allow-origin";
3254
3400
  var ACAC_HEADER = "access-control-allow-credentials";
3255
3401
  var HEADER_SET_METHODS = /* @__PURE__ */ new Set(["setheader", "set", "append"]);
@@ -3391,7 +3537,7 @@ function enclosingScope(node) {
3391
3537
  }
3392
3538
  return void 0;
3393
3539
  }
3394
- var no_cors_wildcard_with_credentials_default = ESLintUtils20.RuleCreator(
3540
+ var no_cors_wildcard_with_credentials_default = ESLintUtils19.RuleCreator(
3395
3541
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3396
3542
  )({
3397
3543
  name: "no-cors-wildcard-with-credentials",
@@ -3459,9 +3605,9 @@ var no_cors_wildcard_with_credentials_default = ESLintUtils20.RuleCreator(
3459
3605
  });
3460
3606
 
3461
3607
  // src/rules/no-silent-promise-catch.ts
3462
- import { AST_NODE_TYPES as AST_NODE_TYPES13, ESLintUtils as ESLintUtils21 } from "@typescript-eslint/utils";
3608
+ import { AST_NODE_TYPES as AST_NODE_TYPES14, ESLintUtils as ESLintUtils20 } from "@typescript-eslint/utils";
3463
3609
  function isBodyParseCall(node) {
3464
- return node.type === AST_NODE_TYPES13.CallExpression && node.arguments.length === 0 && node.callee.type === AST_NODE_TYPES13.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES13.Identifier && (node.callee.property.name === "json" || node.callee.property.name === "text");
3610
+ 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");
3465
3611
  }
3466
3612
  var TEARDOWN_METHODS = /* @__PURE__ */ new Set([
3467
3613
  "cancel",
@@ -3476,21 +3622,21 @@ var TEARDOWN_METHODS = /* @__PURE__ */ new Set([
3476
3622
  var DIRECTIVE_COMMENT_RE = /^\s*(eslint-|@ts-|prettier-ignore|biome-ignore|c8 |v8 |istanbul )/;
3477
3623
  var isExplanatory = (comment) => !DIRECTIVE_COMMENT_RE.test(comment.value);
3478
3624
  function isTeardownCall(node) {
3479
- return node.type === AST_NODE_TYPES13.CallExpression && node.callee.type === AST_NODE_TYPES13.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES13.Identifier && TEARDOWN_METHODS.has(node.callee.property.name);
3625
+ return node.type === AST_NODE_TYPES14.CallExpression && node.callee.type === AST_NODE_TYPES14.MemberExpression && !node.callee.computed && node.callee.property.type === AST_NODE_TYPES14.Identifier && TEARDOWN_METHODS.has(node.callee.property.name);
3480
3626
  }
3481
3627
  function isSilentExpression(node) {
3482
3628
  switch (node.type) {
3483
- case AST_NODE_TYPES13.Literal:
3629
+ case AST_NODE_TYPES14.Literal:
3484
3630
  return !("regex" in node);
3485
- case AST_NODE_TYPES13.Identifier:
3631
+ case AST_NODE_TYPES14.Identifier:
3486
3632
  return node.name === "undefined";
3487
- case AST_NODE_TYPES13.UnaryExpression:
3488
- return node.operator === "void" && node.argument.type === AST_NODE_TYPES13.Literal;
3489
- case AST_NODE_TYPES13.ObjectExpression:
3633
+ case AST_NODE_TYPES14.UnaryExpression:
3634
+ return node.operator === "void" && node.argument.type === AST_NODE_TYPES14.Literal;
3635
+ case AST_NODE_TYPES14.ObjectExpression:
3490
3636
  return node.properties.length === 0;
3491
- case AST_NODE_TYPES13.ArrayExpression:
3637
+ case AST_NODE_TYPES14.ArrayExpression:
3492
3638
  return node.elements.length === 0;
3493
- case AST_NODE_TYPES13.TSAsExpression:
3639
+ case AST_NODE_TYPES14.TSAsExpression:
3494
3640
  return isSilentExpression(node.expression);
3495
3641
  default:
3496
3642
  return false;
@@ -3498,7 +3644,7 @@ function isSilentExpression(node) {
3498
3644
  }
3499
3645
  function isSilentHandler(handler) {
3500
3646
  const body = handler.body;
3501
- if (body.type !== AST_NODE_TYPES13.BlockStatement) {
3647
+ if (body.type !== AST_NODE_TYPES14.BlockStatement) {
3502
3648
  return isSilentExpression(body);
3503
3649
  }
3504
3650
  if (body.body.length === 0) {
@@ -3506,13 +3652,13 @@ function isSilentHandler(handler) {
3506
3652
  }
3507
3653
  if (body.body.length === 1) {
3508
3654
  const only = body.body[0];
3509
- if (only !== void 0 && only.type === AST_NODE_TYPES13.ReturnStatement) {
3655
+ if (only !== void 0 && only.type === AST_NODE_TYPES14.ReturnStatement) {
3510
3656
  return only.argument === null || isSilentExpression(only.argument);
3511
3657
  }
3512
3658
  }
3513
3659
  return false;
3514
3660
  }
3515
- var no_silent_promise_catch_default = ESLintUtils21.RuleCreator(
3661
+ var no_silent_promise_catch_default = ESLintUtils20.RuleCreator(
3516
3662
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3517
3663
  )({
3518
3664
  name: "no-silent-promise-catch",
@@ -3537,7 +3683,7 @@ var no_silent_promise_catch_default = ESLintUtils21.RuleCreator(
3537
3683
  return true;
3538
3684
  }
3539
3685
  let statement = call;
3540
- while (statement.parent !== void 0 && statement.parent !== null && !statement.type.endsWith("Statement") && statement.type !== AST_NODE_TYPES13.VariableDeclaration) {
3686
+ while (statement.parent !== void 0 && statement.parent !== null && !statement.type.endsWith("Statement") && statement.type !== AST_NODE_TYPES14.VariableDeclaration) {
3541
3687
  statement = statement.parent;
3542
3688
  }
3543
3689
  if (sourceCode.getCommentsBefore(statement).some(isExplanatory)) {
@@ -3549,7 +3695,7 @@ var no_silent_promise_catch_default = ESLintUtils21.RuleCreator(
3549
3695
  };
3550
3696
  return {
3551
3697
  CallExpression(node) {
3552
- if (node.callee.type !== AST_NODE_TYPES13.MemberExpression || node.callee.computed || node.callee.property.type !== AST_NODE_TYPES13.Identifier || node.callee.property.name !== "catch") {
3698
+ if (node.callee.type !== AST_NODE_TYPES14.MemberExpression || node.callee.computed || node.callee.property.type !== AST_NODE_TYPES14.Identifier || node.callee.property.name !== "catch") {
3553
3699
  return;
3554
3700
  }
3555
3701
  if (isBodyParseCall(node.callee.object)) {
@@ -3558,14 +3704,14 @@ var no_silent_promise_catch_default = ESLintUtils21.RuleCreator(
3558
3704
  if (isTeardownCall(node.callee.object)) {
3559
3705
  return;
3560
3706
  }
3561
- if (node.parent.type === AST_NODE_TYPES13.MemberExpression && node.parent.object === node) {
3707
+ if (node.parent.type === AST_NODE_TYPES14.MemberExpression && node.parent.object === node) {
3562
3708
  return;
3563
3709
  }
3564
3710
  if (node.arguments.length !== 1) {
3565
3711
  return;
3566
3712
  }
3567
3713
  const handler = node.arguments[0];
3568
- if (handler === void 0 || handler.type !== AST_NODE_TYPES13.ArrowFunctionExpression && handler.type !== AST_NODE_TYPES13.FunctionExpression) {
3714
+ if (handler === void 0 || handler.type !== AST_NODE_TYPES14.ArrowFunctionExpression && handler.type !== AST_NODE_TYPES14.FunctionExpression) {
3569
3715
  return;
3570
3716
  }
3571
3717
  if (hasExplanatoryComment(node, handler)) {
@@ -3581,9 +3727,9 @@ var no_silent_promise_catch_default = ESLintUtils21.RuleCreator(
3581
3727
 
3582
3728
  // src/rules/require-fetch-timeout.ts
3583
3729
  import {
3584
- AST_NODE_TYPES as AST_NODE_TYPES14,
3585
- ASTUtils,
3586
- ESLintUtils as ESLintUtils22
3730
+ AST_NODE_TYPES as AST_NODE_TYPES15,
3731
+ ASTUtils as ASTUtils2,
3732
+ ESLintUtils as ESLintUtils21
3587
3733
  } from "@typescript-eslint/utils";
3588
3734
  var CODEMOD_FIXTURE_RE = /[\\/]__testfixtures__[\\/]/;
3589
3735
  var GLOBAL_OBJECTS = /* @__PURE__ */ new Set([
@@ -3601,14 +3747,14 @@ function matchesAnyPattern2(filename, patterns) {
3601
3747
  return false;
3602
3748
  }
3603
3749
  function initProvablyLacksSignal(init) {
3604
- if (init.type !== AST_NODE_TYPES14.ObjectExpression) {
3750
+ if (init.type !== AST_NODE_TYPES15.ObjectExpression) {
3605
3751
  return false;
3606
3752
  }
3607
3753
  for (const prop of init.properties) {
3608
- if (prop.type === AST_NODE_TYPES14.SpreadElement) {
3754
+ if (prop.type === AST_NODE_TYPES15.SpreadElement) {
3609
3755
  return false;
3610
3756
  }
3611
- if (prop.key.type === AST_NODE_TYPES14.Identifier && prop.key.name === "signal" || prop.key.type === AST_NODE_TYPES14.Literal && prop.key.value === "signal") {
3757
+ if (prop.key.type === AST_NODE_TYPES15.Identifier && prop.key.name === "signal" || prop.key.type === AST_NODE_TYPES15.Literal && prop.key.value === "signal") {
3612
3758
  return false;
3613
3759
  }
3614
3760
  if (prop.computed) {
@@ -3618,9 +3764,9 @@ function initProvablyLacksSignal(init) {
3618
3764
  return true;
3619
3765
  }
3620
3766
  function isStringish(node) {
3621
- return node.type === AST_NODE_TYPES14.Literal && typeof node.value === "string" || node.type === AST_NODE_TYPES14.TemplateLiteral;
3767
+ return node.type === AST_NODE_TYPES15.Literal && typeof node.value === "string" || node.type === AST_NODE_TYPES15.TemplateLiteral;
3622
3768
  }
3623
- var require_fetch_timeout_default = ESLintUtils22.RuleCreator(
3769
+ var require_fetch_timeout_default = ESLintUtils21.RuleCreator(
3624
3770
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
3625
3771
  )({
3626
3772
  name: "require-fetch-timeout",
@@ -3657,14 +3803,14 @@ var require_fetch_timeout_default = ESLintUtils22.RuleCreator(
3657
3803
  }
3658
3804
  function resolvesToGlobal(identifier) {
3659
3805
  const scope = context.sourceCode.getScope(identifier);
3660
- const variable = ASTUtils.findVariable(scope, identifier.name);
3806
+ const variable = ASTUtils2.findVariable(scope, identifier.name);
3661
3807
  return variable === null || variable.defs.length === 0;
3662
3808
  }
3663
3809
  function isGlobalFetchCall2(callee) {
3664
- if (callee.type === AST_NODE_TYPES14.Identifier) {
3810
+ if (callee.type === AST_NODE_TYPES15.Identifier) {
3665
3811
  return callee.name === "fetch" && resolvesToGlobal(callee);
3666
3812
  }
3667
- return callee.type === AST_NODE_TYPES14.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES14.Identifier && callee.property.name === "fetch" && callee.object.type === AST_NODE_TYPES14.Identifier && GLOBAL_OBJECTS.has(callee.object.name) && resolvesToGlobal(callee.object);
3813
+ return callee.type === AST_NODE_TYPES15.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES15.Identifier && callee.property.name === "fetch" && callee.object.type === AST_NODE_TYPES15.Identifier && GLOBAL_OBJECTS.has(callee.object.name) && resolvesToGlobal(callee.object);
3668
3814
  }
3669
3815
  return {
3670
3816
  CallExpression(node) {
@@ -3685,14 +3831,14 @@ var require_fetch_timeout_default = ESLintUtils22.RuleCreator(
3685
3831
 
3686
3832
  // src/rules/no-fat-try-blocks.ts
3687
3833
  import {
3688
- ESLintUtils as ESLintUtils23,
3689
- AST_NODE_TYPES as AST_NODE_TYPES15
3834
+ ESLintUtils as ESLintUtils22,
3835
+ AST_NODE_TYPES as AST_NODE_TYPES16
3690
3836
  } from "@typescript-eslint/utils";
3691
3837
  var MAX_TRY_BODY_STATEMENTS = 3;
3692
3838
  var NESTED_FUNCTION_TYPES = /* @__PURE__ */ new Set([
3693
- AST_NODE_TYPES15.FunctionDeclaration,
3694
- AST_NODE_TYPES15.FunctionExpression,
3695
- AST_NODE_TYPES15.ArrowFunctionExpression
3839
+ AST_NODE_TYPES16.FunctionDeclaration,
3840
+ AST_NODE_TYPES16.FunctionExpression,
3841
+ AST_NODE_TYPES16.ArrowFunctionExpression
3696
3842
  ]);
3697
3843
  var PURE_METHODS = /* @__PURE__ */ new Set([
3698
3844
  "map",
@@ -3790,22 +3936,22 @@ function isNode3(value) {
3790
3936
  }
3791
3937
  function isPureCall(node) {
3792
3938
  const callee = node.callee;
3793
- if (callee.type !== AST_NODE_TYPES15.MemberExpression) {
3939
+ if (callee.type !== AST_NODE_TYPES16.MemberExpression) {
3794
3940
  return false;
3795
3941
  }
3796
3942
  const property = callee.property;
3797
- if (property.type !== AST_NODE_TYPES15.Identifier) {
3943
+ if (property.type !== AST_NODE_TYPES16.Identifier) {
3798
3944
  return false;
3799
3945
  }
3800
- if (callee.object.type === AST_NODE_TYPES15.Identifier && PURE_NAMESPACES.has(callee.object.name)) {
3946
+ if (callee.object.type === AST_NODE_TYPES16.Identifier && PURE_NAMESPACES.has(callee.object.name)) {
3801
3947
  return true;
3802
3948
  }
3803
3949
  return PURE_METHODS.has(property.name);
3804
3950
  }
3805
3951
  function isPureNew(node) {
3806
- return node.callee.type === AST_NODE_TYPES15.Identifier && PURE_CONSTRUCTORS.has(node.callee.name);
3952
+ return node.callee.type === AST_NODE_TYPES16.Identifier && PURE_CONSTRUCTORS.has(node.callee.name);
3807
3953
  }
3808
- function subtreeMatches(stmt, predicate) {
3954
+ function subtreeMatches(stmt, predicate, descendIntoFunctions = false) {
3809
3955
  let found = false;
3810
3956
  const visit = (current) => {
3811
3957
  if (found) {
@@ -3819,7 +3965,7 @@ function subtreeMatches(stmt, predicate) {
3819
3965
  if (key === "parent") {
3820
3966
  continue;
3821
3967
  }
3822
- if (NESTED_FUNCTION_TYPES.has(current.type) && key === "body") {
3968
+ if (!descendIntoFunctions && NESTED_FUNCTION_TYPES.has(current.type) && key === "body") {
3823
3969
  continue;
3824
3970
  }
3825
3971
  const value = current[key];
@@ -3840,20 +3986,20 @@ function subtreeMatches(stmt, predicate) {
3840
3986
  visit(stmt);
3841
3987
  return found;
3842
3988
  }
3843
- var hasAwait = (node) => subtreeMatches(node, (n) => n.type === AST_NODE_TYPES15.AwaitExpression);
3989
+ var hasAwait = (node) => subtreeMatches(node, (n) => n.type === AST_NODE_TYPES16.AwaitExpression);
3844
3990
  var hasThrowingCallOrNew = (node) => subtreeMatches(
3845
3991
  node,
3846
- (n) => n.type === AST_NODE_TYPES15.CallExpression && !isPureCall(n) || n.type === AST_NODE_TYPES15.NewExpression && !isPureNew(n)
3992
+ (n) => n.type === AST_NODE_TYPES16.CallExpression && !isPureCall(n) || n.type === AST_NODE_TYPES16.NewExpression && !isPureNew(n)
3847
3993
  );
3848
3994
  function unwrap2(expr) {
3849
3995
  let current = expr;
3850
- while (current.type === AST_NODE_TYPES15.ChainExpression || current.type === AST_NODE_TYPES15.TSNonNullExpression) {
3996
+ while (current.type === AST_NODE_TYPES16.ChainExpression || current.type === AST_NODE_TYPES16.TSNonNullExpression) {
3851
3997
  current = current.expression;
3852
3998
  }
3853
3999
  return current;
3854
4000
  }
3855
4001
  function isBareCallStatement(stmt) {
3856
- return stmt.type === AST_NODE_TYPES15.ExpressionStatement && unwrap2(stmt.expression).type === AST_NODE_TYPES15.CallExpression;
4002
+ return stmt.type === AST_NODE_TYPES16.ExpressionStatement && unwrap2(stmt.expression).type === AST_NODE_TYPES16.CallExpression;
3857
4003
  }
3858
4004
  function canThrow(stmt) {
3859
4005
  if (hasAwait(stmt)) {
@@ -3862,10 +4008,10 @@ function canThrow(stmt) {
3862
4008
  if (isBareCallStatement(stmt)) {
3863
4009
  return false;
3864
4010
  }
3865
- if (stmt.type === AST_NODE_TYPES15.BlockStatement) {
4011
+ if (stmt.type === AST_NODE_TYPES16.BlockStatement) {
3866
4012
  return stmt.body.some(canThrow);
3867
4013
  }
3868
- if (stmt.type === AST_NODE_TYPES15.IfStatement) {
4014
+ if (stmt.type === AST_NODE_TYPES16.IfStatement) {
3869
4015
  return hasThrowingCallOrNew(stmt.test) || canThrow(stmt.consequent) || stmt.alternate !== null && canThrow(stmt.alternate);
3870
4016
  }
3871
4017
  return hasThrowingCallOrNew(stmt);
@@ -3876,9 +4022,137 @@ function handlerRethrows(handler) {
3876
4022
  }
3877
4023
  const body = handler.body.body;
3878
4024
  const last = body[body.length - 1];
3879
- return last !== void 0 && last.type === AST_NODE_TYPES15.ThrowStatement;
4025
+ return last !== void 0 && last.type === AST_NODE_TYPES16.ThrowStatement;
4026
+ }
4027
+ var PASS_THROUGH_PARENTS = /* @__PURE__ */ new Set([
4028
+ AST_NODE_TYPES16.IfStatement,
4029
+ AST_NODE_TYPES16.TryStatement,
4030
+ AST_NODE_TYPES16.CatchClause,
4031
+ AST_NODE_TYPES16.LabeledStatement
4032
+ ]);
4033
+ function isTerminalInFunction(node) {
4034
+ let current = node;
4035
+ let parent = current.parent;
4036
+ while (parent !== void 0) {
4037
+ if (parent.type === AST_NODE_TYPES16.BlockStatement) {
4038
+ if (parent.body[parent.body.length - 1] !== current) {
4039
+ return false;
4040
+ }
4041
+ } else if (parent.type === AST_NODE_TYPES16.Program) {
4042
+ return parent.body[parent.body.length - 1] === current;
4043
+ } else if (NESTED_FUNCTION_TYPES.has(parent.type)) {
4044
+ return true;
4045
+ } else if (!PASS_THROUGH_PARENTS.has(parent.type)) {
4046
+ return false;
4047
+ }
4048
+ current = parent;
4049
+ parent = current.parent;
4050
+ }
4051
+ return false;
4052
+ }
4053
+ function unwrapAwait(expr) {
4054
+ const inner = unwrap2(expr);
4055
+ return inner.type === AST_NODE_TYPES16.AwaitExpression ? unwrap2(inner.argument) : inner;
3880
4056
  }
3881
- var no_fat_try_blocks_default = ESLintUtils23.RuleCreator(
4057
+ function handlerEndsByHandingOff(handler) {
4058
+ const body = handler.body.body;
4059
+ const last = body[body.length - 1];
4060
+ if (last === void 0) {
4061
+ return false;
4062
+ }
4063
+ if (last.type === AST_NODE_TYPES16.ReturnStatement || last.type === AST_NODE_TYPES16.ThrowStatement) {
4064
+ return true;
4065
+ }
4066
+ return last.type === AST_NODE_TYPES16.ExpressionStatement && unwrapAwait(last.expression).type === AST_NODE_TYPES16.CallExpression;
4067
+ }
4068
+ function collectBindingNames(pattern, names) {
4069
+ if (pattern.type === AST_NODE_TYPES16.Identifier) {
4070
+ names.add(pattern.name);
4071
+ return;
4072
+ }
4073
+ if (pattern.type === AST_NODE_TYPES16.ObjectPattern) {
4074
+ for (const property of pattern.properties) {
4075
+ collectBindingNames(
4076
+ property.type === AST_NODE_TYPES16.RestElement ? property.argument : property.value,
4077
+ names
4078
+ );
4079
+ }
4080
+ return;
4081
+ }
4082
+ if (pattern.type === AST_NODE_TYPES16.ArrayPattern) {
4083
+ for (const element of pattern.elements) {
4084
+ if (element !== null) {
4085
+ collectBindingNames(element, names);
4086
+ }
4087
+ }
4088
+ return;
4089
+ }
4090
+ if (pattern.type === AST_NODE_TYPES16.AssignmentPattern || pattern.type === AST_NODE_TYPES16.RestElement) {
4091
+ collectBindingNames(
4092
+ pattern.type === AST_NODE_TYPES16.AssignmentPattern ? pattern.left : pattern.argument,
4093
+ names
4094
+ );
4095
+ }
4096
+ }
4097
+ function caughtBindingNames(handler) {
4098
+ const names = /* @__PURE__ */ new Set();
4099
+ if (handler.param !== null) {
4100
+ collectBindingNames(handler.param, names);
4101
+ }
4102
+ return names;
4103
+ }
4104
+ function isPropertyName(node) {
4105
+ const parent = node.parent;
4106
+ if (parent.type === AST_NODE_TYPES16.MemberExpression) {
4107
+ return parent.property === node && !parent.computed;
4108
+ }
4109
+ if (parent.type === AST_NODE_TYPES16.Property) {
4110
+ return parent.key === node && !parent.computed;
4111
+ }
4112
+ return false;
4113
+ }
4114
+ function handlerMentionsCaughtBinding(handler) {
4115
+ const names = caughtBindingNames(handler);
4116
+ if (names.size === 0) {
4117
+ return false;
4118
+ }
4119
+ return subtreeMatches(
4120
+ handler.body,
4121
+ (n) => n.type === AST_NODE_TYPES16.Identifier && names.has(n.name) && !isPropertyName(n),
4122
+ true
4123
+ );
4124
+ }
4125
+ function isSuccessShapedValue(expr) {
4126
+ let current = expr;
4127
+ while (current.type === AST_NODE_TYPES16.TSAsExpression || current.type === AST_NODE_TYPES16.TSNonNullExpression) {
4128
+ current = current.expression;
4129
+ }
4130
+ if (current.type === AST_NODE_TYPES16.Literal) {
4131
+ return current.value === null || current.value === false;
4132
+ }
4133
+ if (current.type === AST_NODE_TYPES16.Identifier) {
4134
+ return current.name === "undefined";
4135
+ }
4136
+ if (current.type === AST_NODE_TYPES16.UnaryExpression) {
4137
+ return current.operator === "void";
4138
+ }
4139
+ if (current.type === AST_NODE_TYPES16.ArrayExpression) {
4140
+ return current.elements.length === 0;
4141
+ }
4142
+ if (current.type === AST_NODE_TYPES16.ObjectExpression) {
4143
+ return current.properties.length === 0;
4144
+ }
4145
+ return false;
4146
+ }
4147
+ var handlerReturnsSuccessShaped = (handler) => subtreeMatches(
4148
+ handler.body,
4149
+ (n) => n.type === AST_NODE_TYPES16.ReturnStatement && n.argument !== null && isSuccessShapedValue(n.argument)
4150
+ );
4151
+ function isTerminalErrorBoundary(node) {
4152
+ const handler = node.handler;
4153
+ return handler !== null && isTerminalInFunction(node) && handlerEndsByHandingOff(handler) && handlerMentionsCaughtBinding(handler) && !handlerReturnsSuccessShaped(handler);
4154
+ }
4155
+ var no_fat_try_blocks_default = ESLintUtils22.RuleCreator(
3882
4156
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
3883
4157
  )({
3884
4158
  name: "no-fat-try-blocks",
@@ -3906,6 +4180,9 @@ var no_fat_try_blocks_default = ESLintUtils23.RuleCreator(
3906
4180
  if (handlerRethrows(node.handler)) {
3907
4181
  return;
3908
4182
  }
4183
+ if (isTerminalErrorBoundary(node)) {
4184
+ return;
4185
+ }
3909
4186
  const count = node.block.body.filter(canThrow).length;
3910
4187
  if (count <= MAX_TRY_BODY_STATEMENTS) {
3911
4188
  return;
@@ -3922,7 +4199,7 @@ var no_fat_try_blocks_default = ESLintUtils23.RuleCreator(
3922
4199
  });
3923
4200
 
3924
4201
  // src/rules/no-secret-in-log.ts
3925
- import { ESLintUtils as ESLintUtils24 } from "@typescript-eslint/utils";
4202
+ import { ESLintUtils as ESLintUtils23 } from "@typescript-eslint/utils";
3926
4203
 
3927
4204
  // src/rules/_secret_names.ts
3928
4205
  var SECRET_WORDS = /* @__PURE__ */ new Set([
@@ -4184,7 +4461,7 @@ function propertyKeyName2(prop) {
4184
4461
  }
4185
4462
  return null;
4186
4463
  }
4187
- var no_secret_in_log_default = ESLintUtils24.RuleCreator(
4464
+ var no_secret_in_log_default = ESLintUtils23.RuleCreator(
4188
4465
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
4189
4466
  )({
4190
4467
  name: "no-secret-in-log",
@@ -4261,24 +4538,24 @@ var no_secret_in_log_default = ESLintUtils24.RuleCreator(
4261
4538
  });
4262
4539
 
4263
4540
  // src/rules/no-unsafe-mock-casting.ts
4264
- import { ESLintUtils as ESLintUtils25 } from "@typescript-eslint/utils";
4265
- import { AST_NODE_TYPES as AST_NODE_TYPES16 } from "@typescript-eslint/utils";
4541
+ import { ESLintUtils as ESLintUtils24 } from "@typescript-eslint/utils";
4542
+ import { AST_NODE_TYPES as AST_NODE_TYPES17 } from "@typescript-eslint/utils";
4266
4543
  function isMockTypeReference(node) {
4267
- if (node.type !== AST_NODE_TYPES16.TSTypeReference) {
4544
+ if (node.type !== AST_NODE_TYPES17.TSTypeReference) {
4268
4545
  return false;
4269
4546
  }
4270
4547
  const typeName = node.typeName;
4271
- if (typeName.type === AST_NODE_TYPES16.Identifier) {
4548
+ if (typeName.type === AST_NODE_TYPES17.Identifier) {
4272
4549
  const name = typeName.name;
4273
4550
  return name === "Mock" || name === "MockInstance" || name === "SpyInstance";
4274
4551
  }
4275
- if (typeName.type === AST_NODE_TYPES16.TSQualifiedName) {
4552
+ if (typeName.type === AST_NODE_TYPES17.TSQualifiedName) {
4276
4553
  const rightName = typeName.right.name;
4277
4554
  return rightName === "Mock" || rightName === "MockInstance" || rightName === "SpyInstance";
4278
4555
  }
4279
4556
  return false;
4280
4557
  }
4281
- var no_unsafe_mock_casting_default = ESLintUtils25.RuleCreator(
4558
+ var no_unsafe_mock_casting_default = ESLintUtils24.RuleCreator(
4282
4559
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
4283
4560
  )({
4284
4561
  name: "no-unsafe-mock-casting",
@@ -4311,8 +4588,8 @@ var no_unsafe_mock_casting_default = ESLintUtils25.RuleCreator(
4311
4588
 
4312
4589
  // src/rules/prefer-string-literal-union.ts
4313
4590
  import {
4314
- ESLintUtils as ESLintUtils26,
4315
- AST_NODE_TYPES as AST_NODE_TYPES17
4591
+ ESLintUtils as ESLintUtils25,
4592
+ AST_NODE_TYPES as AST_NODE_TYPES18
4316
4593
  } from "@typescript-eslint/utils";
4317
4594
  import * as ts from "typescript";
4318
4595
  var CHOICE_TOKENS = /* @__PURE__ */ new Set([
@@ -4356,19 +4633,19 @@ function isChoiceLikeName(name) {
4356
4633
  return CHOICE_TOKENS.has(lastWord(name));
4357
4634
  }
4358
4635
  function keyName(key) {
4359
- if (key.type === AST_NODE_TYPES17.Identifier) {
4636
+ if (key.type === AST_NODE_TYPES18.Identifier) {
4360
4637
  return key.name;
4361
4638
  }
4362
- if (key.type === AST_NODE_TYPES17.Literal && typeof key.value === "string") {
4639
+ if (key.type === AST_NODE_TYPES18.Literal && typeof key.value === "string") {
4363
4640
  return key.value;
4364
4641
  }
4365
4642
  return null;
4366
4643
  }
4367
4644
  function isStringLiteralMember(t) {
4368
- return t.type === AST_NODE_TYPES17.TSLiteralType && t.literal.type === AST_NODE_TYPES17.Literal && typeof t.literal.value === "string";
4645
+ return t.type === AST_NODE_TYPES18.TSLiteralType && t.literal.type === AST_NODE_TYPES18.Literal && typeof t.literal.value === "string";
4369
4646
  }
4370
4647
  function isStringLiteralUnion(node) {
4371
- if (node?.type !== AST_NODE_TYPES17.TSUnionType) {
4648
+ if (node?.type !== AST_NODE_TYPES18.TSUnionType) {
4372
4649
  return false;
4373
4650
  }
4374
4651
  return node.types.filter(isStringLiteralMember).length >= MIN_CLUSTER_SIZE;
@@ -4397,12 +4674,12 @@ function bindingSourceExpression(decl) {
4397
4674
  return ts.isForOfStatement(node) ? node.expression : node.initializer;
4398
4675
  }
4399
4676
  function refKey(node) {
4400
- if (node.type === AST_NODE_TYPES17.Identifier) {
4677
+ if (node.type === AST_NODE_TYPES18.Identifier) {
4401
4678
  return node.name;
4402
4679
  }
4403
- if (node.type === AST_NODE_TYPES17.MemberExpression && !node.computed) {
4680
+ if (node.type === AST_NODE_TYPES18.MemberExpression && !node.computed) {
4404
4681
  const inner = refKey(node.object);
4405
- if (inner === null || node.property.type !== AST_NODE_TYPES17.Identifier) {
4682
+ if (inner === null || node.property.type !== AST_NODE_TYPES18.Identifier) {
4406
4683
  return null;
4407
4684
  }
4408
4685
  return `${inner}.${node.property.name}`;
@@ -4410,12 +4687,12 @@ function refKey(node) {
4410
4687
  return null;
4411
4688
  }
4412
4689
  function strLiteral(node) {
4413
- if (node.type === AST_NODE_TYPES17.Literal && typeof node.value === "string") {
4690
+ if (node.type === AST_NODE_TYPES18.Literal && typeof node.value === "string") {
4414
4691
  return node.value;
4415
4692
  }
4416
4693
  return null;
4417
4694
  }
4418
- var prefer_string_literal_union_default = ESLintUtils26.RuleCreator(
4695
+ var prefer_string_literal_union_default = ESLintUtils25.RuleCreator(
4419
4696
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
4420
4697
  )({
4421
4698
  name: "prefer-string-literal-union",
@@ -4453,7 +4730,7 @@ var prefer_string_literal_union_default = ESLintUtils26.RuleCreator(
4453
4730
  );
4454
4731
  let services;
4455
4732
  try {
4456
- services = ESLintUtils26.getParserServices(context);
4733
+ services = ESLintUtils25.getParserServices(context);
4457
4734
  } catch {
4458
4735
  services = null;
4459
4736
  }
@@ -4565,7 +4842,7 @@ var prefer_string_literal_union_default = ESLintUtils26.RuleCreator(
4565
4842
  containersWithUnion.add(container);
4566
4843
  return;
4567
4844
  }
4568
- if (typeNode?.type !== AST_NODE_TYPES17.TSStringKeyword) {
4845
+ if (typeNode?.type !== AST_NODE_TYPES18.TSStringKeyword) {
4569
4846
  return;
4570
4847
  }
4571
4848
  const name = keyName(key);
@@ -4653,10 +4930,10 @@ var prefer_string_literal_union_default = ESLintUtils26.RuleCreator(
4653
4930
  }
4654
4931
  };
4655
4932
  function refKeyText(node) {
4656
- if (node.type === AST_NODE_TYPES17.BinaryExpression) {
4933
+ if (node.type === AST_NODE_TYPES18.BinaryExpression) {
4657
4934
  return refKey(node.left) ?? refKey(node.right) ?? "value";
4658
4935
  }
4659
- if (node.type === AST_NODE_TYPES17.SwitchStatement) {
4936
+ if (node.type === AST_NODE_TYPES18.SwitchStatement) {
4660
4937
  return refKey(node.discriminant) ?? "value";
4661
4938
  }
4662
4939
  return "value";
@@ -4666,10 +4943,10 @@ var prefer_string_literal_union_default = ESLintUtils26.RuleCreator(
4666
4943
 
4667
4944
  // src/rules/prefer-zod-enum.ts
4668
4945
  import {
4669
- AST_NODE_TYPES as AST_NODE_TYPES18,
4670
- ESLintUtils as ESLintUtils27
4946
+ AST_NODE_TYPES as AST_NODE_TYPES19,
4947
+ ESLintUtils as ESLintUtils26
4671
4948
  } from "@typescript-eslint/utils";
4672
- var prefer_zod_enum_default = ESLintUtils27.RuleCreator(
4949
+ var prefer_zod_enum_default = ESLintUtils26.RuleCreator(
4673
4950
  (name) => `https://github.com/sarj-ai/standards/tree/main/packages/typescript#${name}`
4674
4951
  )({
4675
4952
  name: "prefer-zod-enum",
@@ -4690,20 +4967,20 @@ var prefer_zod_enum_default = ESLintUtils27.RuleCreator(
4690
4967
  const zodNamespaces = /* @__PURE__ */ new Set();
4691
4968
  function enumValues(node) {
4692
4969
  const callee = node.callee;
4693
- if (callee.type !== AST_NODE_TYPES18.MemberExpression || callee.computed || callee.object.type !== AST_NODE_TYPES18.Identifier || !zodNamespaces.has(callee.object.name) || callee.property.type !== AST_NODE_TYPES18.Identifier || callee.property.name !== "union" || node.arguments.length !== 1) {
4970
+ if (callee.type !== AST_NODE_TYPES19.MemberExpression || callee.computed || callee.object.type !== AST_NODE_TYPES19.Identifier || !zodNamespaces.has(callee.object.name) || callee.property.type !== AST_NODE_TYPES19.Identifier || callee.property.name !== "union" || node.arguments.length !== 1) {
4694
4971
  return null;
4695
4972
  }
4696
4973
  const argument = node.arguments[0];
4697
- if (argument === void 0 || argument.type !== AST_NODE_TYPES18.ArrayExpression || argument.elements.length === 0) {
4974
+ if (argument === void 0 || argument.type !== AST_NODE_TYPES19.ArrayExpression || argument.elements.length === 0) {
4698
4975
  return null;
4699
4976
  }
4700
4977
  const values = [];
4701
4978
  for (const element of argument.elements) {
4702
- if (element === null || element.type !== AST_NODE_TYPES18.CallExpression || element.arguments.length !== 1 || element.callee.type !== AST_NODE_TYPES18.MemberExpression || element.callee.computed || element.callee.object.type !== AST_NODE_TYPES18.Identifier || !zodNamespaces.has(element.callee.object.name) || element.callee.property.type !== AST_NODE_TYPES18.Identifier || element.callee.property.name !== "literal") {
4979
+ if (element === null || element.type !== AST_NODE_TYPES19.CallExpression || element.arguments.length !== 1 || element.callee.type !== AST_NODE_TYPES19.MemberExpression || element.callee.computed || element.callee.object.type !== AST_NODE_TYPES19.Identifier || !zodNamespaces.has(element.callee.object.name) || element.callee.property.type !== AST_NODE_TYPES19.Identifier || element.callee.property.name !== "literal") {
4703
4980
  return null;
4704
4981
  }
4705
4982
  const value = element.arguments[0];
4706
- if (value === void 0 || value.type !== AST_NODE_TYPES18.Literal || typeof value.value !== "string") {
4983
+ if (value === void 0 || value.type !== AST_NODE_TYPES19.Literal || typeof value.value !== "string") {
4707
4984
  return null;
4708
4985
  }
4709
4986
  values.push(value);
@@ -4712,11 +4989,11 @@ var prefer_zod_enum_default = ESLintUtils27.RuleCreator(
4712
4989
  }
4713
4990
  function buildFix(node, values) {
4714
4991
  const argument = node.arguments[0];
4715
- if (argument === void 0 || argument.type !== AST_NODE_TYPES18.ArrayExpression || sourceCode.getCommentsInside(argument).length > 0) {
4992
+ if (argument === void 0 || argument.type !== AST_NODE_TYPES19.ArrayExpression || sourceCode.getCommentsInside(argument).length > 0) {
4716
4993
  return void 0;
4717
4994
  }
4718
4995
  const callee = node.callee;
4719
- if (callee.type !== AST_NODE_TYPES18.MemberExpression || callee.property.type !== AST_NODE_TYPES18.Identifier) {
4996
+ if (callee.type !== AST_NODE_TYPES19.MemberExpression || callee.property.type !== AST_NODE_TYPES19.Identifier) {
4720
4997
  return void 0;
4721
4998
  }
4722
4999
  return (fixer) => [
@@ -4733,7 +5010,7 @@ var prefer_zod_enum_default = ESLintUtils27.RuleCreator(
4733
5010
  return;
4734
5011
  }
4735
5012
  for (const specifier of node.specifiers) {
4736
- if (specifier.type === AST_NODE_TYPES18.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES18.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES18.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES18.Identifier && specifier.imported.name === "z") {
5013
+ if (specifier.type === AST_NODE_TYPES19.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES19.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES19.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES19.Identifier && specifier.imported.name === "z") {
4737
5014
  zodNamespaces.add(specifier.local.name);
4738
5015
  }
4739
5016
  }
@@ -4756,8 +5033,8 @@ var prefer_zod_enum_default = ESLintUtils27.RuleCreator(
4756
5033
 
4757
5034
  // src/rules/prefer-zod-infer.ts
4758
5035
  import {
4759
- AST_NODE_TYPES as AST_NODE_TYPES19,
4760
- ESLintUtils as ESLintUtils28
5036
+ AST_NODE_TYPES as AST_NODE_TYPES20,
5037
+ ESLintUtils as ESLintUtils27
4761
5038
  } from "@typescript-eslint/utils";
4762
5039
  var SHAPE_PRESERVING_METHODS = /* @__PURE__ */ new Set([
4763
5040
  "describe",
@@ -4795,44 +5072,44 @@ var ZOD_TYPE_CONSTRAINTS = /* @__PURE__ */ new Set([
4795
5072
  "Schema"
4796
5073
  ]);
4797
5074
  var LEAF_NODE_TYPES = {
4798
- string: [AST_NODE_TYPES19.TSStringKeyword],
4799
- email: [AST_NODE_TYPES19.TSStringKeyword],
4800
- url: [AST_NODE_TYPES19.TSStringKeyword],
4801
- uuid: [AST_NODE_TYPES19.TSStringKeyword],
4802
- ulid: [AST_NODE_TYPES19.TSStringKeyword],
4803
- cuid: [AST_NODE_TYPES19.TSStringKeyword],
4804
- cuid2: [AST_NODE_TYPES19.TSStringKeyword],
4805
- nanoid: [AST_NODE_TYPES19.TSStringKeyword],
4806
- iso: [AST_NODE_TYPES19.TSStringKeyword],
4807
- number: [AST_NODE_TYPES19.TSNumberKeyword],
4808
- int: [AST_NODE_TYPES19.TSNumberKeyword],
4809
- float32: [AST_NODE_TYPES19.TSNumberKeyword],
4810
- float64: [AST_NODE_TYPES19.TSNumberKeyword],
4811
- boolean: [AST_NODE_TYPES19.TSBooleanKeyword],
4812
- bigint: [AST_NODE_TYPES19.TSBigIntKeyword],
4813
- symbol: [AST_NODE_TYPES19.TSSymbolKeyword],
4814
- any: [AST_NODE_TYPES19.TSAnyKeyword],
4815
- unknown: [AST_NODE_TYPES19.TSUnknownKeyword],
4816
- never: [AST_NODE_TYPES19.TSNeverKeyword],
4817
- void: [AST_NODE_TYPES19.TSVoidKeyword],
4818
- null: [AST_NODE_TYPES19.TSNullKeyword],
4819
- undefined: [AST_NODE_TYPES19.TSUndefinedKeyword],
4820
- literal: [AST_NODE_TYPES19.TSLiteralType],
4821
- date: [AST_NODE_TYPES19.TSTypeReference],
4822
- array: [AST_NODE_TYPES19.TSArrayType, AST_NODE_TYPES19.TSTypeReference],
4823
- tuple: [AST_NODE_TYPES19.TSTupleType],
4824
- object: [AST_NODE_TYPES19.TSTypeLiteral, AST_NODE_TYPES19.TSTypeReference],
4825
- strictObject: [AST_NODE_TYPES19.TSTypeLiteral, AST_NODE_TYPES19.TSTypeReference],
4826
- looseObject: [AST_NODE_TYPES19.TSTypeLiteral, AST_NODE_TYPES19.TSTypeReference],
4827
- record: [AST_NODE_TYPES19.TSTypeReference, AST_NODE_TYPES19.TSTypeLiteral],
4828
- map: [AST_NODE_TYPES19.TSTypeReference],
4829
- set: [AST_NODE_TYPES19.TSTypeReference],
4830
- promise: [AST_NODE_TYPES19.TSTypeReference],
4831
- enum: [AST_NODE_TYPES19.TSUnionType, AST_NODE_TYPES19.TSTypeReference, AST_NODE_TYPES19.TSLiteralType],
4832
- nativeEnum: [AST_NODE_TYPES19.TSUnionType, AST_NODE_TYPES19.TSTypeReference, AST_NODE_TYPES19.TSLiteralType],
4833
- union: [AST_NODE_TYPES19.TSUnionType, AST_NODE_TYPES19.TSTypeReference],
4834
- discriminatedUnion: [AST_NODE_TYPES19.TSUnionType, AST_NODE_TYPES19.TSTypeReference],
4835
- intersection: [AST_NODE_TYPES19.TSIntersectionType, AST_NODE_TYPES19.TSTypeReference]
5075
+ string: [AST_NODE_TYPES20.TSStringKeyword],
5076
+ email: [AST_NODE_TYPES20.TSStringKeyword],
5077
+ url: [AST_NODE_TYPES20.TSStringKeyword],
5078
+ uuid: [AST_NODE_TYPES20.TSStringKeyword],
5079
+ ulid: [AST_NODE_TYPES20.TSStringKeyword],
5080
+ cuid: [AST_NODE_TYPES20.TSStringKeyword],
5081
+ cuid2: [AST_NODE_TYPES20.TSStringKeyword],
5082
+ nanoid: [AST_NODE_TYPES20.TSStringKeyword],
5083
+ iso: [AST_NODE_TYPES20.TSStringKeyword],
5084
+ number: [AST_NODE_TYPES20.TSNumberKeyword],
5085
+ int: [AST_NODE_TYPES20.TSNumberKeyword],
5086
+ float32: [AST_NODE_TYPES20.TSNumberKeyword],
5087
+ float64: [AST_NODE_TYPES20.TSNumberKeyword],
5088
+ boolean: [AST_NODE_TYPES20.TSBooleanKeyword],
5089
+ bigint: [AST_NODE_TYPES20.TSBigIntKeyword],
5090
+ symbol: [AST_NODE_TYPES20.TSSymbolKeyword],
5091
+ any: [AST_NODE_TYPES20.TSAnyKeyword],
5092
+ unknown: [AST_NODE_TYPES20.TSUnknownKeyword],
5093
+ never: [AST_NODE_TYPES20.TSNeverKeyword],
5094
+ void: [AST_NODE_TYPES20.TSVoidKeyword],
5095
+ null: [AST_NODE_TYPES20.TSNullKeyword],
5096
+ undefined: [AST_NODE_TYPES20.TSUndefinedKeyword],
5097
+ literal: [AST_NODE_TYPES20.TSLiteralType],
5098
+ date: [AST_NODE_TYPES20.TSTypeReference],
5099
+ array: [AST_NODE_TYPES20.TSArrayType, AST_NODE_TYPES20.TSTypeReference],
5100
+ tuple: [AST_NODE_TYPES20.TSTupleType],
5101
+ object: [AST_NODE_TYPES20.TSTypeLiteral, AST_NODE_TYPES20.TSTypeReference],
5102
+ strictObject: [AST_NODE_TYPES20.TSTypeLiteral, AST_NODE_TYPES20.TSTypeReference],
5103
+ looseObject: [AST_NODE_TYPES20.TSTypeLiteral, AST_NODE_TYPES20.TSTypeReference],
5104
+ record: [AST_NODE_TYPES20.TSTypeReference, AST_NODE_TYPES20.TSTypeLiteral],
5105
+ map: [AST_NODE_TYPES20.TSTypeReference],
5106
+ set: [AST_NODE_TYPES20.TSTypeReference],
5107
+ promise: [AST_NODE_TYPES20.TSTypeReference],
5108
+ enum: [AST_NODE_TYPES20.TSUnionType, AST_NODE_TYPES20.TSTypeReference, AST_NODE_TYPES20.TSLiteralType],
5109
+ nativeEnum: [AST_NODE_TYPES20.TSUnionType, AST_NODE_TYPES20.TSTypeReference, AST_NODE_TYPES20.TSLiteralType],
5110
+ union: [AST_NODE_TYPES20.TSUnionType, AST_NODE_TYPES20.TSTypeReference],
5111
+ discriminatedUnion: [AST_NODE_TYPES20.TSUnionType, AST_NODE_TYPES20.TSTypeReference],
5112
+ intersection: [AST_NODE_TYPES20.TSIntersectionType, AST_NODE_TYPES20.TSTypeReference]
4836
5113
  };
4837
5114
  function normalizeSchemaName(name) {
4838
5115
  return name.replace(/Schema$/i, "").replace(/^Z(?=[A-Z])/, "").toLowerCase();
@@ -4841,20 +5118,20 @@ function normalizeTypeName(name) {
4841
5118
  return name.replace(/Type$/, "").toLowerCase();
4842
5119
  }
4843
5120
  function unwrapNullish(annotation) {
4844
- if (annotation.type !== AST_NODE_TYPES19.TSUnionType) {
5121
+ if (annotation.type !== AST_NODE_TYPES20.TSUnionType) {
4845
5122
  return {
4846
5123
  core: annotation,
4847
- nullable: annotation.type === AST_NODE_TYPES19.TSNullKeyword
5124
+ nullable: annotation.type === AST_NODE_TYPES20.TSNullKeyword
4848
5125
  };
4849
5126
  }
4850
5127
  const rest = [];
4851
5128
  let nullable = false;
4852
5129
  for (const member of annotation.types) {
4853
- if (member.type === AST_NODE_TYPES19.TSNullKeyword) {
5130
+ if (member.type === AST_NODE_TYPES20.TSNullKeyword) {
4854
5131
  nullable = true;
4855
5132
  continue;
4856
5133
  }
4857
- if (member.type === AST_NODE_TYPES19.TSUndefinedKeyword) {
5134
+ if (member.type === AST_NODE_TYPES20.TSUndefinedKeyword) {
4858
5135
  continue;
4859
5136
  }
4860
5137
  rest.push(member);
@@ -4878,7 +5155,7 @@ function leafAgrees(leaf, annotation) {
4878
5155
  }
4879
5156
  return expected.includes(core.type);
4880
5157
  }
4881
- var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
5158
+ var prefer_zod_infer_default = ESLintUtils27.RuleCreator(
4882
5159
  (name) => `https://github.com/sarj-ai/standards/tree/main/packages/typescript#${name}`
4883
5160
  )({
4884
5161
  name: "prefer-zod-infer",
@@ -4921,14 +5198,14 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
4921
5198
  function zodCallChain(node) {
4922
5199
  const chain = [];
4923
5200
  let current = node;
4924
- while (current.type === AST_NODE_TYPES19.CallExpression) {
5201
+ while (current.type === AST_NODE_TYPES20.CallExpression) {
4925
5202
  const callee = current.callee;
4926
- if (callee.type !== AST_NODE_TYPES19.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES19.Identifier) {
5203
+ if (callee.type !== AST_NODE_TYPES20.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES20.Identifier) {
4927
5204
  return null;
4928
5205
  }
4929
5206
  chain.push(current);
4930
5207
  const receiver = callee.object;
4931
- if (receiver.type === AST_NODE_TYPES19.Identifier) {
5208
+ if (receiver.type === AST_NODE_TYPES20.Identifier) {
4932
5209
  return zodNamespaces.has(receiver.name) ? chain.reverse() : null;
4933
5210
  }
4934
5211
  current = receiver;
@@ -4937,19 +5214,19 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
4937
5214
  }
4938
5215
  function methodName(call) {
4939
5216
  const callee = call.callee;
4940
- return callee.type === AST_NODE_TYPES19.MemberExpression && callee.property.type === AST_NODE_TYPES19.Identifier ? callee.property.name : "";
5217
+ return callee.type === AST_NODE_TYPES20.MemberExpression && callee.property.type === AST_NODE_TYPES20.Identifier ? callee.property.name : "";
4941
5218
  }
4942
5219
  function schemaField(node) {
4943
5220
  const modifiers = [];
4944
5221
  let current = node;
4945
5222
  let leaf = null;
4946
- while (current.type === AST_NODE_TYPES19.CallExpression) {
5223
+ while (current.type === AST_NODE_TYPES20.CallExpression) {
4947
5224
  const callee = current.callee;
4948
- if (callee.type !== AST_NODE_TYPES19.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES19.Identifier) {
5225
+ if (callee.type !== AST_NODE_TYPES20.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES20.Identifier) {
4949
5226
  break;
4950
5227
  }
4951
5228
  const receiver = callee.object;
4952
- if (receiver.type === AST_NODE_TYPES19.Identifier && zodNamespaces.has(receiver.name)) {
5229
+ if (receiver.type === AST_NODE_TYPES20.Identifier && zodNamespaces.has(receiver.name)) {
4953
5230
  leaf = callee.property.name;
4954
5231
  break;
4955
5232
  }
@@ -4980,16 +5257,16 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
4980
5257
  return null;
4981
5258
  }
4982
5259
  const shape = base.arguments[0];
4983
- if (shape === void 0 || shape.type !== AST_NODE_TYPES19.ObjectExpression) {
5260
+ if (shape === void 0 || shape.type !== AST_NODE_TYPES20.ObjectExpression) {
4984
5261
  return null;
4985
5262
  }
4986
5263
  const fields = /* @__PURE__ */ new Map();
4987
5264
  for (const property of shape.properties) {
4988
- if (property.type !== AST_NODE_TYPES19.Property || property.computed) {
5265
+ if (property.type !== AST_NODE_TYPES20.Property || property.computed) {
4989
5266
  return null;
4990
5267
  }
4991
5268
  const { key } = property;
4992
- const name = key.type === AST_NODE_TYPES19.Identifier ? key.name : key.type === AST_NODE_TYPES19.Literal && typeof key.value === "string" ? key.value : null;
5269
+ const name = key.type === AST_NODE_TYPES20.Identifier ? key.name : key.type === AST_NODE_TYPES20.Literal && typeof key.value === "string" ? key.value : null;
4993
5270
  if (name === null) {
4994
5271
  return null;
4995
5272
  }
@@ -5000,11 +5277,11 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
5000
5277
  function typeMembers(members) {
5001
5278
  const result = /* @__PURE__ */ new Map();
5002
5279
  for (const member of members) {
5003
- if (member.type !== AST_NODE_TYPES19.TSPropertySignature || member.computed) {
5280
+ if (member.type !== AST_NODE_TYPES20.TSPropertySignature || member.computed) {
5004
5281
  return null;
5005
5282
  }
5006
5283
  const { key } = member;
5007
- const name = key.type === AST_NODE_TYPES19.Identifier ? key.name : key.type === AST_NODE_TYPES19.Literal && typeof key.value === "string" ? key.value : null;
5284
+ const name = key.type === AST_NODE_TYPES20.Identifier ? key.name : key.type === AST_NODE_TYPES20.Literal && typeof key.value === "string" ? key.value : null;
5008
5285
  if (name === null) {
5009
5286
  return null;
5010
5287
  }
@@ -5018,8 +5295,8 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
5018
5295
  return result.size === 0 ? null : result;
5019
5296
  }
5020
5297
  function collectConstrainedNames(node) {
5021
- if (node.type === AST_NODE_TYPES19.TSTypeReference) {
5022
- if (node.typeName.type === AST_NODE_TYPES19.Identifier) {
5298
+ if (node.type === AST_NODE_TYPES20.TSTypeReference) {
5299
+ if (node.typeName.type === AST_NODE_TYPES20.Identifier) {
5023
5300
  constrainedTypeNames.add(node.typeName.name);
5024
5301
  }
5025
5302
  for (const argument of node.typeArguments?.params ?? []) {
@@ -5027,11 +5304,11 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
5027
5304
  }
5028
5305
  return;
5029
5306
  }
5030
- if (node.type === AST_NODE_TYPES19.TSArrayType) {
5307
+ if (node.type === AST_NODE_TYPES20.TSArrayType) {
5031
5308
  collectConstrainedNames(node.elementType);
5032
5309
  return;
5033
5310
  }
5034
- if (node.type === AST_NODE_TYPES19.TSUnionType || node.type === AST_NODE_TYPES19.TSIntersectionType) {
5311
+ if (node.type === AST_NODE_TYPES20.TSUnionType || node.type === AST_NODE_TYPES20.TSIntersectionType) {
5035
5312
  for (const member of node.types) {
5036
5313
  collectConstrainedNames(member);
5037
5314
  }
@@ -5075,13 +5352,13 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
5075
5352
  return;
5076
5353
  }
5077
5354
  for (const specifier of node.specifiers) {
5078
- if (specifier.type === AST_NODE_TYPES19.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES19.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES19.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES19.Identifier && specifier.imported.name === "z") {
5355
+ if (specifier.type === AST_NODE_TYPES20.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES20.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES20.ImportSpecifier && specifier.imported.type === AST_NODE_TYPES20.Identifier && specifier.imported.name === "z") {
5079
5356
  zodNamespaces.add(specifier.local.name);
5080
5357
  }
5081
5358
  }
5082
5359
  },
5083
5360
  VariableDeclarator(node) {
5084
- if (node.id.type !== AST_NODE_TYPES19.Identifier || node.init == null) {
5361
+ if (node.id.type !== AST_NODE_TYPES20.Identifier || node.init == null) {
5085
5362
  return;
5086
5363
  }
5087
5364
  const fields = schemaFields(node.init);
@@ -5091,14 +5368,14 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
5091
5368
  },
5092
5369
  /** Guard (f): `XSchema.transform(...)` anywhere in the module. */
5093
5370
  "MemberExpression[computed=false]"(node) {
5094
- if (node.object.type === AST_NODE_TYPES19.Identifier && node.property.type === AST_NODE_TYPES19.Identifier && MODULE_LEVEL_RESHAPERS.has(node.property.name)) {
5371
+ if (node.object.type === AST_NODE_TYPES20.Identifier && node.property.type === AST_NODE_TYPES20.Identifier && MODULE_LEVEL_RESHAPERS.has(node.property.name)) {
5095
5372
  reshapedSchemaNames.add(node.object.name);
5096
5373
  }
5097
5374
  },
5098
5375
  /** Guard (c): `z.ZodType<T>` and every other type argument it carries. */
5099
5376
  TSTypeReference(node) {
5100
5377
  const { typeName } = node;
5101
- const referenced = typeName.type === AST_NODE_TYPES19.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES19.TSQualifiedName && typeName.right.type === AST_NODE_TYPES19.Identifier ? typeName.right.name : null;
5378
+ const referenced = typeName.type === AST_NODE_TYPES20.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES20.TSQualifiedName && typeName.right.type === AST_NODE_TYPES20.Identifier ? typeName.right.name : null;
5102
5379
  if (referenced === null || !ZOD_TYPE_CONSTRAINTS.has(referenced)) {
5103
5380
  return;
5104
5381
  }
@@ -5116,7 +5393,7 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
5116
5393
  }
5117
5394
  },
5118
5395
  TSTypeAliasDeclaration(node) {
5119
- if (node.typeParameters !== void 0 || node.typeAnnotation.type !== AST_NODE_TYPES19.TSTypeLiteral) {
5396
+ if (node.typeParameters !== void 0 || node.typeAnnotation.type !== AST_NODE_TYPES20.TSTypeLiteral) {
5120
5397
  return;
5121
5398
  }
5122
5399
  const members = typeMembers(node.typeAnnotation.members);
@@ -5161,10 +5438,10 @@ var prefer_zod_infer_default = ESLintUtils28.RuleCreator(
5161
5438
  });
5162
5439
 
5163
5440
  // src/rules/no-offset-pagination.ts
5164
- import { ESLintUtils as ESLintUtils29 } from "@typescript-eslint/utils";
5441
+ import { ESLintUtils as ESLintUtils28 } from "@typescript-eslint/utils";
5165
5442
 
5166
5443
  // src/rules/_sql.ts
5167
- import { AST_NODE_TYPES as AST_NODE_TYPES20 } from "@typescript-eslint/utils";
5444
+ import { AST_NODE_TYPES as AST_NODE_TYPES21 } from "@typescript-eslint/utils";
5168
5445
  function stripSqlNoise(text) {
5169
5446
  const out = [...text];
5170
5447
  const n = text.length;
@@ -5225,13 +5502,13 @@ function stripSqlNoise(text) {
5225
5502
  var SUBSTITUTION_MARKER = "?";
5226
5503
  function sqlTextOf(node) {
5227
5504
  switch (node.type) {
5228
- case AST_NODE_TYPES20.Literal:
5505
+ case AST_NODE_TYPES21.Literal:
5229
5506
  return typeof node.value === "string" ? node.value : null;
5230
- case AST_NODE_TYPES20.TemplateLiteral:
5507
+ case AST_NODE_TYPES21.TemplateLiteral:
5231
5508
  return node.quasis.map((q) => q.value.cooked ?? q.value.raw).join(SUBSTITUTION_MARKER);
5232
- case AST_NODE_TYPES20.TaggedTemplateExpression:
5509
+ case AST_NODE_TYPES21.TaggedTemplateExpression:
5233
5510
  return sqlTextOf(node.quasi);
5234
- case AST_NODE_TYPES20.BinaryExpression: {
5511
+ case AST_NODE_TYPES21.BinaryExpression: {
5235
5512
  if (node.operator !== "+") {
5236
5513
  return null;
5237
5514
  }
@@ -5239,7 +5516,7 @@ function sqlTextOf(node) {
5239
5516
  const right = sqlTextOf(node.right);
5240
5517
  return left !== null && right !== null ? left + right : null;
5241
5518
  }
5242
- case AST_NODE_TYPES20.ArrayExpression: {
5519
+ case AST_NODE_TYPES21.ArrayExpression: {
5243
5520
  const parts = [];
5244
5521
  for (const element of node.elements) {
5245
5522
  if (element === null) {
@@ -5259,7 +5536,7 @@ function sqlTextOf(node) {
5259
5536
  }
5260
5537
  function isJoinedFragmentArray(node) {
5261
5538
  const parent = node.parent;
5262
- return parent?.type === AST_NODE_TYPES20.MemberExpression && parent.object === node && !parent.computed && parent.property.type === AST_NODE_TYPES20.Identifier && parent.property.name === "join" && parent.parent?.type === AST_NODE_TYPES20.CallExpression;
5539
+ 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;
5263
5540
  }
5264
5541
  function markConsumed(node, consumed) {
5265
5542
  consumed.add(node);
@@ -5309,7 +5586,7 @@ function createSqlListener(handler) {
5309
5586
  // src/rules/no-offset-pagination.ts
5310
5587
  var OFFSET_PAGINATION = /\bOFFSET\s+(?:%s|%\(\w+\)s|\?\d*|:\w+|@\w+|\$\d+|\d+)/i;
5311
5588
  var OFFSET_GATE = /offset/i;
5312
- var no_offset_pagination_default = ESLintUtils29.RuleCreator(
5589
+ var no_offset_pagination_default = ESLintUtils28.RuleCreator(
5313
5590
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5314
5591
  )({
5315
5592
  name: "no-offset-pagination",
@@ -5338,15 +5615,15 @@ var no_offset_pagination_default = ESLintUtils29.RuleCreator(
5338
5615
  });
5339
5616
 
5340
5617
  // src/rules/no-positional-tuple-return.ts
5341
- import { AST_NODE_TYPES as AST_NODE_TYPES21, ESLintUtils as ESLintUtils30 } from "@typescript-eslint/utils";
5618
+ import { AST_NODE_TYPES as AST_NODE_TYPES22, ESLintUtils as ESLintUtils29 } from "@typescript-eslint/utils";
5342
5619
  var MIN_ELEMENTS = 2;
5343
5620
  var ACCESSOR_PAIR_LENGTH = 2;
5344
5621
  var AWAITABLE_TYPES = /* @__PURE__ */ new Set(["Promise", "PromiseLike", "Awaited"]);
5345
5622
  function tupleReturnType(node) {
5346
- if (node.type === AST_NODE_TYPES21.TSTupleType) {
5623
+ if (node.type === AST_NODE_TYPES22.TSTupleType) {
5347
5624
  return node;
5348
5625
  }
5349
- if (node.type === AST_NODE_TYPES21.TSTypeReference && node.typeName.type === AST_NODE_TYPES21.Identifier && AWAITABLE_TYPES.has(node.typeName.name)) {
5626
+ if (node.type === AST_NODE_TYPES22.TSTypeReference && node.typeName.type === AST_NODE_TYPES22.Identifier && AWAITABLE_TYPES.has(node.typeName.name)) {
5350
5627
  const argument = node.typeArguments?.params[0];
5351
5628
  return argument === void 0 ? null : tupleReturnType(argument);
5352
5629
  }
@@ -5360,30 +5637,30 @@ function isPermittedTuple(tuple, sourceCode) {
5360
5637
  if (elements.length < MIN_ELEMENTS) {
5361
5638
  return true;
5362
5639
  }
5363
- if (elements.some((element) => element.type === AST_NODE_TYPES21.TSRestType)) {
5640
+ if (elements.some((element) => element.type === AST_NODE_TYPES22.TSRestType)) {
5364
5641
  return true;
5365
5642
  }
5366
- if (elements.some((element) => element.type === AST_NODE_TYPES21.TSNamedTupleMember)) {
5643
+ if (elements.some((element) => element.type === AST_NODE_TYPES22.TSNamedTupleMember)) {
5367
5644
  return true;
5368
5645
  }
5369
- if (elements[0]?.type === AST_NODE_TYPES21.TSLiteralType) {
5646
+ if (elements[0]?.type === AST_NODE_TYPES22.TSLiteralType) {
5370
5647
  return true;
5371
5648
  }
5372
- if (elements.length === ACCESSOR_PAIR_LENGTH && elements.some((element) => element.type === AST_NODE_TYPES21.TSFunctionType)) {
5649
+ if (elements.length === ACCESSOR_PAIR_LENGTH && elements.some((element) => element.type === AST_NODE_TYPES22.TSFunctionType)) {
5373
5650
  return true;
5374
5651
  }
5375
5652
  const texts = new Set(elements.map((element) => normalizedText(sourceCode, element)));
5376
5653
  return texts.size === 1;
5377
5654
  }
5378
5655
  function functionName(node) {
5379
- if (node.type === AST_NODE_TYPES21.FunctionDeclaration) {
5656
+ if (node.type === AST_NODE_TYPES22.FunctionDeclaration) {
5380
5657
  return node.id?.name ?? null;
5381
5658
  }
5382
5659
  const parent = node.parent;
5383
- if (parent?.type === AST_NODE_TYPES21.VariableDeclarator && parent.id.type === AST_NODE_TYPES21.Identifier) {
5660
+ if (parent?.type === AST_NODE_TYPES22.VariableDeclarator && parent.id.type === AST_NODE_TYPES22.Identifier) {
5384
5661
  return parent.id.name;
5385
5662
  }
5386
- if ((parent?.type === AST_NODE_TYPES21.MethodDefinition || parent?.type === AST_NODE_TYPES21.PropertyDefinition || parent?.type === AST_NODE_TYPES21.Property) && parent.key.type === AST_NODE_TYPES21.Identifier) {
5663
+ 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) {
5387
5664
  return parent.key.name;
5388
5665
  }
5389
5666
  return null;
@@ -5391,7 +5668,7 @@ function functionName(node) {
5391
5668
  function isInlineExported(node) {
5392
5669
  for (let current = node; current != null; current = current.parent) {
5393
5670
  const parent = current.parent;
5394
- if (parent?.type === AST_NODE_TYPES21.ExportNamedDeclaration || parent?.type === AST_NODE_TYPES21.ExportDefaultDeclaration) {
5671
+ if (parent?.type === AST_NODE_TYPES22.ExportNamedDeclaration || parent?.type === AST_NODE_TYPES22.ExportDefaultDeclaration) {
5395
5672
  return true;
5396
5673
  }
5397
5674
  }
@@ -5400,18 +5677,18 @@ function isInlineExported(node) {
5400
5677
  function moduleScopeBindingName(node) {
5401
5678
  let current = node;
5402
5679
  let child = node;
5403
- while (current.parent != null && current.parent.type !== AST_NODE_TYPES21.Program) {
5680
+ while (current.parent != null && current.parent.type !== AST_NODE_TYPES22.Program) {
5404
5681
  child = current;
5405
5682
  current = current.parent;
5406
5683
  }
5407
- if (current.parent?.type !== AST_NODE_TYPES21.Program) {
5684
+ if (current.parent?.type !== AST_NODE_TYPES22.Program) {
5408
5685
  return null;
5409
5686
  }
5410
- if (current.type === AST_NODE_TYPES21.FunctionDeclaration || current.type === AST_NODE_TYPES21.ClassDeclaration) {
5687
+ if (current.type === AST_NODE_TYPES22.FunctionDeclaration || current.type === AST_NODE_TYPES22.ClassDeclaration) {
5411
5688
  return current.id?.name ?? null;
5412
5689
  }
5413
- if (current.type === AST_NODE_TYPES21.VariableDeclaration) {
5414
- if (child.type !== AST_NODE_TYPES21.VariableDeclarator || child.id.type !== AST_NODE_TYPES21.Identifier) {
5690
+ if (current.type === AST_NODE_TYPES22.VariableDeclaration) {
5691
+ if (child.type !== AST_NODE_TYPES22.VariableDeclarator || child.id.type !== AST_NODE_TYPES22.Identifier) {
5415
5692
  return null;
5416
5693
  }
5417
5694
  return child.id.name;
@@ -5421,19 +5698,19 @@ function moduleScopeBindingName(node) {
5421
5698
  function specifierExportedNames(program) {
5422
5699
  const names = /* @__PURE__ */ new Set();
5423
5700
  for (const statement of program.body) {
5424
- if (statement.type === AST_NODE_TYPES21.ExportNamedDeclaration && statement.declaration == null && statement.source == null && statement.exportKind !== "type") {
5701
+ if (statement.type === AST_NODE_TYPES22.ExportNamedDeclaration && statement.declaration == null && statement.source == null && statement.exportKind !== "type") {
5425
5702
  for (const specifier of statement.specifiers) {
5426
- if (specifier.exportKind !== "type" && specifier.local.type === AST_NODE_TYPES21.Identifier) {
5703
+ if (specifier.exportKind !== "type" && specifier.local.type === AST_NODE_TYPES22.Identifier) {
5427
5704
  names.add(specifier.local.name);
5428
5705
  }
5429
5706
  }
5430
5707
  continue;
5431
5708
  }
5432
- if (statement.type === AST_NODE_TYPES21.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES21.Identifier) {
5709
+ if (statement.type === AST_NODE_TYPES22.ExportDefaultDeclaration && statement.declaration.type === AST_NODE_TYPES22.Identifier) {
5433
5710
  names.add(statement.declaration.name);
5434
5711
  continue;
5435
5712
  }
5436
- if (statement.type === AST_NODE_TYPES21.TSExportAssignment && statement.expression.type === AST_NODE_TYPES21.Identifier) {
5713
+ if (statement.type === AST_NODE_TYPES22.TSExportAssignment && statement.expression.type === AST_NODE_TYPES22.Identifier) {
5437
5714
  names.add(statement.expression.name);
5438
5715
  }
5439
5716
  }
@@ -5449,7 +5726,7 @@ function isExported(node, specifierExports) {
5449
5726
  const binding = moduleScopeBindingName(node);
5450
5727
  return binding !== null && specifierExports.has(binding);
5451
5728
  }
5452
- var no_positional_tuple_return_default = ESLintUtils30.RuleCreator(
5729
+ var no_positional_tuple_return_default = ESLintUtils29.RuleCreator(
5453
5730
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5454
5731
  )({
5455
5732
  name: "no-positional-tuple-return",
@@ -5497,16 +5774,16 @@ var no_positional_tuple_return_default = ESLintUtils30.RuleCreator(
5497
5774
  });
5498
5775
 
5499
5776
  // src/rules/no-repeated-string-literal.ts
5500
- import { AST_NODE_TYPES as AST_NODE_TYPES22, ESLintUtils as ESLintUtils31 } from "@typescript-eslint/utils";
5777
+ import { AST_NODE_TYPES as AST_NODE_TYPES23, ESLintUtils as ESLintUtils30 } from "@typescript-eslint/utils";
5501
5778
  var MIN_LENGTH = 40;
5502
5779
  var MIN_DISTINCT_SCOPES = 2;
5503
5780
  var PREVIEW_LENGTH = 40;
5504
5781
  var SQL_KEYWORD_RE = /\b(SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN|VALUES|ON CONFLICT|RETURNING|GROUP BY|ORDER BY)\b/;
5505
5782
  var IDENTIFIER_RE = /^[a-z_][a-z0-9_.]*$/;
5506
- var FUNCTION_TYPES = /* @__PURE__ */ new Set([
5507
- AST_NODE_TYPES22.FunctionDeclaration,
5508
- AST_NODE_TYPES22.FunctionExpression,
5509
- AST_NODE_TYPES22.ArrowFunctionExpression
5783
+ var FUNCTION_TYPES2 = /* @__PURE__ */ new Set([
5784
+ AST_NODE_TYPES23.FunctionDeclaration,
5785
+ AST_NODE_TYPES23.FunctionExpression,
5786
+ AST_NODE_TYPES23.ArrowFunctionExpression
5510
5787
  ]);
5511
5788
  function isStructured(value) {
5512
5789
  return value.includes("\n") || SQL_KEYWORD_RE.test(value) || IDENTIFIER_RE.test(value);
@@ -5517,7 +5794,7 @@ function preview(value) {
5517
5794
  }
5518
5795
  function enclosingFunction(node) {
5519
5796
  for (let current = node.parent; current != null; current = current.parent) {
5520
- if (FUNCTION_TYPES.has(current.type)) {
5797
+ if (FUNCTION_TYPES2.has(current.type)) {
5521
5798
  return current;
5522
5799
  }
5523
5800
  }
@@ -5528,9 +5805,9 @@ function isScaffolding(node) {
5528
5805
  if (parent === void 0) {
5529
5806
  return true;
5530
5807
  }
5531
- return parent.type === AST_NODE_TYPES22.ImportDeclaration || parent.type === AST_NODE_TYPES22.ExportNamedDeclaration || parent.type === AST_NODE_TYPES22.ExportAllDeclaration || parent.type === AST_NODE_TYPES22.TSImportType || parent.type === AST_NODE_TYPES22.JSXAttribute || parent.type === AST_NODE_TYPES22.TSLiteralType;
5808
+ 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;
5532
5809
  }
5533
- var no_repeated_string_literal_default = ESLintUtils31.RuleCreator(
5810
+ var no_repeated_string_literal_default = ESLintUtils30.RuleCreator(
5534
5811
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5535
5812
  )({
5536
5813
  name: "no-repeated-string-literal",
@@ -5570,7 +5847,7 @@ var no_repeated_string_literal_default = ESLintUtils31.RuleCreator(
5570
5847
  }
5571
5848
  },
5572
5849
  TemplateLiteral(node) {
5573
- if (node.parent.type === AST_NODE_TYPES22.TaggedTemplateExpression) {
5850
+ if (node.parent.type === AST_NODE_TYPES23.TaggedTemplateExpression) {
5574
5851
  return;
5575
5852
  }
5576
5853
  const [only] = node.quasis;
@@ -5604,7 +5881,7 @@ var no_repeated_string_literal_default = ESLintUtils31.RuleCreator(
5604
5881
  });
5605
5882
 
5606
5883
  // src/rules/no-select-star.ts
5607
- import { ESLintUtils as ESLintUtils32 } from "@typescript-eslint/utils";
5884
+ import { ESLintUtils as ESLintUtils31 } from "@typescript-eslint/utils";
5608
5885
  var QUERY_SHAPE = /\bSELECT\b[\s\S]*?\bFROM\b/i;
5609
5886
  var SELECT_KEYWORD = /\bSELECT\b/gi;
5610
5887
  var FROM_KEYWORD = /^FROM\b/i;
@@ -5644,7 +5921,7 @@ function hasRealSelectStar(sql) {
5644
5921
  }
5645
5922
  return false;
5646
5923
  }
5647
- var no_select_star_default = ESLintUtils32.RuleCreator(
5924
+ var no_select_star_default = ESLintUtils31.RuleCreator(
5648
5925
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5649
5926
  )({
5650
5927
  name: "no-select-star",
@@ -5673,7 +5950,7 @@ var no_select_star_default = ESLintUtils32.RuleCreator(
5673
5950
  });
5674
5951
 
5675
5952
  // src/rules/no-sleep-in-test-body.ts
5676
- import { AST_NODE_TYPES as AST_NODE_TYPES23, ESLintUtils as ESLintUtils33 } from "@typescript-eslint/utils";
5953
+ import { AST_NODE_TYPES as AST_NODE_TYPES24, ESLintUtils as ESLintUtils32 } from "@typescript-eslint/utils";
5677
5954
  var SLEEP_HELPERS = /* @__PURE__ */ new Set(["sleep", "delay", "wait", "pause"]);
5678
5955
  var TEST_CALLERS = /* @__PURE__ */ new Set([
5679
5956
  "it",
@@ -5681,43 +5958,43 @@ var TEST_CALLERS = /* @__PURE__ */ new Set([
5681
5958
  "beforeEach",
5682
5959
  "afterEach"
5683
5960
  ]);
5684
- var FUNCTION_TYPES2 = /* @__PURE__ */ new Set([
5685
- AST_NODE_TYPES23.FunctionDeclaration,
5686
- AST_NODE_TYPES23.FunctionExpression,
5687
- AST_NODE_TYPES23.ArrowFunctionExpression
5961
+ var FUNCTION_TYPES3 = /* @__PURE__ */ new Set([
5962
+ AST_NODE_TYPES24.FunctionDeclaration,
5963
+ AST_NODE_TYPES24.FunctionExpression,
5964
+ AST_NODE_TYPES24.ArrowFunctionExpression
5688
5965
  ]);
5689
5966
  function isNonzeroNumericLiteral(node) {
5690
- return node?.type === AST_NODE_TYPES23.Literal && typeof node.value === "number" && node.value !== 0;
5967
+ return node?.type === AST_NODE_TYPES24.Literal && typeof node.value === "number" && node.value !== 0;
5691
5968
  }
5692
5969
  function isTimedSetTimeout(node) {
5693
- return node.type === AST_NODE_TYPES23.CallExpression && node.callee.type === AST_NODE_TYPES23.Identifier && node.callee.name === "setTimeout" && node.arguments.length >= 2 && isNonzeroNumericLiteral(node.arguments[1]);
5970
+ 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]);
5694
5971
  }
5695
5972
  function isPromiseSleep(node) {
5696
- if (node.callee.type !== AST_NODE_TYPES23.Identifier || node.callee.name !== "Promise") {
5973
+ if (node.callee.type !== AST_NODE_TYPES24.Identifier || node.callee.name !== "Promise") {
5697
5974
  return false;
5698
5975
  }
5699
5976
  const executor = node.arguments[0];
5700
- if (executor?.type !== AST_NODE_TYPES23.ArrowFunctionExpression && executor?.type !== AST_NODE_TYPES23.FunctionExpression) {
5977
+ if (executor?.type !== AST_NODE_TYPES24.ArrowFunctionExpression && executor?.type !== AST_NODE_TYPES24.FunctionExpression) {
5701
5978
  return false;
5702
5979
  }
5703
5980
  const body = executor.body;
5704
- if (body.type !== AST_NODE_TYPES23.BlockStatement) {
5981
+ if (body.type !== AST_NODE_TYPES24.BlockStatement) {
5705
5982
  return isTimedSetTimeout(body);
5706
5983
  }
5707
5984
  return body.body.some(
5708
- (stmt) => stmt.type === AST_NODE_TYPES23.ExpressionStatement && isTimedSetTimeout(stmt.expression)
5985
+ (stmt) => stmt.type === AST_NODE_TYPES24.ExpressionStatement && isTimedSetTimeout(stmt.expression)
5709
5986
  );
5710
5987
  }
5711
5988
  function isHelperSleep(node) {
5712
- return node.callee.type === AST_NODE_TYPES23.Identifier && SLEEP_HELPERS.has(node.callee.name) && node.arguments.length >= 1 && isNonzeroNumericLiteral(node.arguments[0]);
5989
+ return node.callee.type === AST_NODE_TYPES24.Identifier && SLEEP_HELPERS.has(node.callee.name) && node.arguments.length >= 1 && isNonzeroNumericLiteral(node.arguments[0]);
5713
5990
  }
5714
5991
  function nearestEnclosingFunction(node) {
5715
5992
  for (let current = node.parent; current != null; current = current.parent) {
5716
- if (!FUNCTION_TYPES2.has(current.type)) {
5993
+ if (!FUNCTION_TYPES3.has(current.type)) {
5717
5994
  continue;
5718
5995
  }
5719
5996
  const grandparent = current.parent;
5720
- const isPromiseExecutor = grandparent?.type === AST_NODE_TYPES23.NewExpression && isPromiseSleep(grandparent);
5997
+ const isPromiseExecutor = grandparent?.type === AST_NODE_TYPES24.NewExpression && isPromiseSleep(grandparent);
5721
5998
  if (!isPromiseExecutor) {
5722
5999
  return current;
5723
6000
  }
@@ -5725,29 +6002,29 @@ function nearestEnclosingFunction(node) {
5725
6002
  return null;
5726
6003
  }
5727
6004
  function testCallerName(callee) {
5728
- if (callee.type === AST_NODE_TYPES23.Identifier) {
6005
+ if (callee.type === AST_NODE_TYPES24.Identifier) {
5729
6006
  return callee.name;
5730
6007
  }
5731
- if (callee.type === AST_NODE_TYPES23.MemberExpression) {
6008
+ if (callee.type === AST_NODE_TYPES24.MemberExpression) {
5732
6009
  return testCallerName(callee.object);
5733
6010
  }
5734
- if (callee.type === AST_NODE_TYPES23.CallExpression) {
6011
+ if (callee.type === AST_NODE_TYPES24.CallExpression) {
5735
6012
  return testCallerName(callee.callee);
5736
6013
  }
5737
- if (callee.type === AST_NODE_TYPES23.TaggedTemplateExpression) {
6014
+ if (callee.type === AST_NODE_TYPES24.TaggedTemplateExpression) {
5738
6015
  return testCallerName(callee.tag);
5739
6016
  }
5740
6017
  return null;
5741
6018
  }
5742
6019
  function isTestBody(fn) {
5743
6020
  const call = fn.parent;
5744
- if (call?.type !== AST_NODE_TYPES23.CallExpression || !call.arguments.some((argument) => argument === fn)) {
6021
+ if (call?.type !== AST_NODE_TYPES24.CallExpression || !call.arguments.some((argument) => argument === fn)) {
5745
6022
  return false;
5746
6023
  }
5747
6024
  const name = testCallerName(call.callee);
5748
6025
  return name !== null && TEST_CALLERS.has(name);
5749
6026
  }
5750
- var no_sleep_in_test_body_default = ESLintUtils33.RuleCreator(
6027
+ var no_sleep_in_test_body_default = ESLintUtils32.RuleCreator(
5751
6028
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5752
6029
  )({
5753
6030
  name: "no-sleep-in-test-body",
@@ -5789,45 +6066,215 @@ var no_sleep_in_test_body_default = ESLintUtils33.RuleCreator(
5789
6066
  });
5790
6067
 
5791
6068
  // src/rules/no-conditional-in-test.ts
5792
- import { AST_NODE_TYPES as AST_NODE_TYPES24, ESLintUtils as ESLintUtils34 } from "@typescript-eslint/utils";
6069
+ import { AST_NODE_TYPES as AST_NODE_TYPES25, ESLintUtils as ESLintUtils33 } from "@typescript-eslint/utils";
5793
6070
  var TEST_CALLERS2 = /* @__PURE__ */ new Set(["it", "test"]);
5794
- var FUNCTION_TYPES3 = /* @__PURE__ */ new Set([
5795
- AST_NODE_TYPES24.FunctionDeclaration,
5796
- AST_NODE_TYPES24.FunctionExpression,
5797
- AST_NODE_TYPES24.ArrowFunctionExpression
6071
+ var FUNCTION_TYPES4 = /* @__PURE__ */ new Set([
6072
+ AST_NODE_TYPES25.FunctionDeclaration,
6073
+ AST_NODE_TYPES25.FunctionExpression,
6074
+ AST_NODE_TYPES25.ArrowFunctionExpression
6075
+ ]);
6076
+ var ASSERTION_ROOTS = /* @__PURE__ */ new Set([
6077
+ "expect",
6078
+ "expectTypeOf",
6079
+ "assert",
6080
+ "assertType"
6081
+ ]);
6082
+ var TYPE_ASSERTION_ROOTS = /* @__PURE__ */ new Set([
6083
+ "expectTypeOf",
6084
+ "assertType"
5798
6085
  ]);
5799
6086
  function nearestEnclosingFunction2(node) {
5800
6087
  for (let current = node.parent; current != null; current = current.parent) {
5801
- if (FUNCTION_TYPES3.has(current.type)) {
6088
+ if (FUNCTION_TYPES4.has(current.type)) {
5802
6089
  return current;
5803
6090
  }
5804
6091
  }
5805
6092
  return null;
5806
6093
  }
5807
6094
  function testCallerName2(callee) {
5808
- if (callee.type === AST_NODE_TYPES24.Identifier) {
6095
+ if (callee.type === AST_NODE_TYPES25.Identifier) {
5809
6096
  return callee.name;
5810
6097
  }
5811
- if (callee.type === AST_NODE_TYPES24.MemberExpression) {
6098
+ if (callee.type === AST_NODE_TYPES25.MemberExpression) {
5812
6099
  return testCallerName2(callee.object);
5813
6100
  }
5814
- if (callee.type === AST_NODE_TYPES24.CallExpression) {
6101
+ if (callee.type === AST_NODE_TYPES25.CallExpression) {
5815
6102
  return testCallerName2(callee.callee);
5816
6103
  }
5817
- if (callee.type === AST_NODE_TYPES24.TaggedTemplateExpression) {
6104
+ if (callee.type === AST_NODE_TYPES25.TaggedTemplateExpression) {
5818
6105
  return testCallerName2(callee.tag);
5819
6106
  }
5820
6107
  return null;
5821
6108
  }
5822
6109
  function isTestBody2(fn) {
5823
6110
  const call = fn.parent;
5824
- if (call?.type !== AST_NODE_TYPES24.CallExpression || !call.arguments.some((argument) => argument === fn)) {
6111
+ if (call?.type !== AST_NODE_TYPES25.CallExpression || !call.arguments.some((argument) => argument === fn)) {
5825
6112
  return false;
5826
6113
  }
5827
6114
  const name = testCallerName2(call.callee);
5828
6115
  return name !== null && TEST_CALLERS2.has(name);
5829
6116
  }
5830
- var no_conditional_in_test_default = ESLintUtils34.RuleCreator(
6117
+ function subtreeMatches2(node, predicate, descendIntoFunctions = true) {
6118
+ let found = false;
6119
+ const visit = (current) => {
6120
+ if (found) {
6121
+ return;
6122
+ }
6123
+ if (predicate(current)) {
6124
+ found = true;
6125
+ return;
6126
+ }
6127
+ for (const key of Object.keys(current)) {
6128
+ if (key === "parent") {
6129
+ continue;
6130
+ }
6131
+ if (!descendIntoFunctions && FUNCTION_TYPES4.has(current.type) && key === "body") {
6132
+ continue;
6133
+ }
6134
+ const value = current[key];
6135
+ if (Array.isArray(value)) {
6136
+ for (const child of value) {
6137
+ if (typeof child === "object" && child !== null && typeof child.type === "string") {
6138
+ visit(child);
6139
+ }
6140
+ }
6141
+ } else if (typeof value === "object" && value !== null && typeof value.type === "string") {
6142
+ visit(value);
6143
+ }
6144
+ if (found) {
6145
+ return;
6146
+ }
6147
+ }
6148
+ };
6149
+ visit(node);
6150
+ return found;
6151
+ }
6152
+ function rootIdentifier(node) {
6153
+ switch (node.type) {
6154
+ case AST_NODE_TYPES25.Identifier:
6155
+ return node.name;
6156
+ case AST_NODE_TYPES25.MemberExpression:
6157
+ return rootIdentifier(node.object);
6158
+ case AST_NODE_TYPES25.UnaryExpression:
6159
+ return rootIdentifier(node.argument);
6160
+ case AST_NODE_TYPES25.AwaitExpression:
6161
+ return rootIdentifier(node.argument);
6162
+ case AST_NODE_TYPES25.ChainExpression:
6163
+ case AST_NODE_TYPES25.TSNonNullExpression:
6164
+ case AST_NODE_TYPES25.TSAsExpression:
6165
+ return rootIdentifier(node.expression);
6166
+ case AST_NODE_TYPES25.BinaryExpression:
6167
+ case AST_NODE_TYPES25.LogicalExpression:
6168
+ return rootIdentifier(node.left);
6169
+ case AST_NODE_TYPES25.CallExpression:
6170
+ return rootIdentifier(node.callee);
6171
+ default:
6172
+ return null;
6173
+ }
6174
+ }
6175
+ function calleeRootName(call) {
6176
+ let current = call.callee;
6177
+ for (; ; ) {
6178
+ if (current.type === AST_NODE_TYPES25.Identifier) {
6179
+ return current.name;
6180
+ }
6181
+ if (current.type === AST_NODE_TYPES25.MemberExpression) {
6182
+ current = current.object;
6183
+ continue;
6184
+ }
6185
+ if (current.type === AST_NODE_TYPES25.CallExpression) {
6186
+ current = current.callee;
6187
+ continue;
6188
+ }
6189
+ if (current.type === AST_NODE_TYPES25.ChainExpression || current.type === AST_NODE_TYPES25.TSNonNullExpression) {
6190
+ current = current.expression;
6191
+ continue;
6192
+ }
6193
+ return null;
6194
+ }
6195
+ }
6196
+ var isAssertionCall = (node) => node.type === AST_NODE_TYPES25.CallExpression && ASSERTION_ROOTS.has(calleeRootName(node) ?? "");
6197
+ var isTypeAssertionCall = (node) => node.type === AST_NODE_TYPES25.CallExpression && TYPE_ASSERTION_ROOTS.has(calleeRootName(node) ?? "");
6198
+ var containsAssertion = (node) => subtreeMatches2(node, isAssertionCall);
6199
+ var containsSkipCall = (node) => subtreeMatches2(
6200
+ node,
6201
+ (current) => current.type === AST_NODE_TYPES25.CallExpression && current.callee.type === AST_NODE_TYPES25.MemberExpression && !current.callee.computed && current.callee.property.type === AST_NODE_TYPES25.Identifier && current.callee.property.name === "skip"
6202
+ );
6203
+ var containsEscape = (node) => subtreeMatches2(
6204
+ node,
6205
+ (current) => current.type === AST_NODE_TYPES25.ReturnStatement || current.type === AST_NODE_TYPES25.ContinueStatement || current.type === AST_NODE_TYPES25.BreakStatement,
6206
+ false
6207
+ );
6208
+ function branchStatements(branch) {
6209
+ return branch.type === AST_NODE_TYPES25.BlockStatement ? branch.body : [branch];
6210
+ }
6211
+ function previousSibling(node) {
6212
+ const parent = node.parent;
6213
+ let siblings = null;
6214
+ if (parent.type === AST_NODE_TYPES25.BlockStatement || parent.type === AST_NODE_TYPES25.Program || parent.type === AST_NODE_TYPES25.StaticBlock) {
6215
+ siblings = parent.body;
6216
+ } else if (parent.type === AST_NODE_TYPES25.SwitchCase) {
6217
+ siblings = parent.consequent;
6218
+ }
6219
+ if (siblings === null) {
6220
+ return null;
6221
+ }
6222
+ const index = siblings.indexOf(node);
6223
+ return index > 0 ? siblings[index - 1] ?? null : null;
6224
+ }
6225
+ function isPinnedNarrowingGuard(node) {
6226
+ const testRoot = rootIdentifier(node.test);
6227
+ if (testRoot === null) {
6228
+ return false;
6229
+ }
6230
+ const previous = previousSibling(node);
6231
+ if (previous === null || previous.type !== AST_NODE_TYPES25.ExpressionStatement) {
6232
+ return false;
6233
+ }
6234
+ let matched = false;
6235
+ subtreeMatches2(previous, (current) => {
6236
+ if (current.type !== AST_NODE_TYPES25.CallExpression || current.callee.type !== AST_NODE_TYPES25.Identifier || current.callee.name !== "expect") {
6237
+ return false;
6238
+ }
6239
+ const subject = current.arguments[0];
6240
+ if (subject === void 0) {
6241
+ return false;
6242
+ }
6243
+ if (rootIdentifier(subject) === testRoot) {
6244
+ matched = true;
6245
+ return true;
6246
+ }
6247
+ return false;
6248
+ });
6249
+ return matched;
6250
+ }
6251
+ function isThrowingGuard(node) {
6252
+ if (node.alternate !== null) {
6253
+ return false;
6254
+ }
6255
+ const statements = branchStatements(node.consequent);
6256
+ return statements.length === 1 && statements[0]?.type === AST_NODE_TYPES25.ThrowStatement;
6257
+ }
6258
+ function isTypeAssertionBranch(branch) {
6259
+ const statements = branchStatements(branch);
6260
+ return statements.length > 0 && statements.every(
6261
+ (statement) => statement.type === AST_NODE_TYPES25.ExpressionStatement && isTypeAssertionCall(statement.expression)
6262
+ );
6263
+ }
6264
+ function isTypeLevelNarrowing(node) {
6265
+ return isTypeAssertionBranch(node.consequent) && (node.alternate === null || isTypeAssertionBranch(node.alternate));
6266
+ }
6267
+ var isInertBranch = (branch) => !containsAssertion(branch) && !containsEscape(branch) && !containsSkipCall(branch);
6268
+ function isInertNormalization(node) {
6269
+ return isInertBranch(node.consequent) && (node.alternate === null || isInertBranch(node.alternate));
6270
+ }
6271
+ function isExemptIfStatement(node) {
6272
+ return isPinnedNarrowingGuard(node) || isThrowingGuard(node) || isTypeLevelNarrowing(node) || isInertNormalization(node);
6273
+ }
6274
+ function isShortCircuitedAssertion(node) {
6275
+ return node.operator !== "??" && node.parent.type === AST_NODE_TYPES25.ExpressionStatement && containsAssertion(node.right);
6276
+ }
6277
+ var no_conditional_in_test_default = ESLintUtils33.RuleCreator(
5831
6278
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5832
6279
  )({
5833
6280
  name: "no-conditional-in-test",
@@ -5855,6 +6302,9 @@ var no_conditional_in_test_default = ESLintUtils34.RuleCreator(
5855
6302
  };
5856
6303
  return {
5857
6304
  IfStatement(node) {
6305
+ if (isExemptIfStatement(node)) {
6306
+ return;
6307
+ }
5858
6308
  report(node);
5859
6309
  },
5860
6310
  SwitchStatement(node) {
@@ -5864,6 +6314,9 @@ var no_conditional_in_test_default = ESLintUtils34.RuleCreator(
5864
6314
  report(node);
5865
6315
  },
5866
6316
  LogicalExpression(node) {
6317
+ if (!isShortCircuitedAssertion(node)) {
6318
+ return;
6319
+ }
5867
6320
  report(node);
5868
6321
  }
5869
6322
  };
@@ -5871,7 +6324,7 @@ var no_conditional_in_test_default = ESLintUtils34.RuleCreator(
5871
6324
  });
5872
6325
 
5873
6326
  // src/rules/prefer-constant-time-secret-compare.ts
5874
- import { AST_NODE_TYPES as AST_NODE_TYPES25, ESLintUtils as ESLintUtils35 } from "@typescript-eslint/utils";
6327
+ import { AST_NODE_TYPES as AST_NODE_TYPES26, ESLintUtils as ESLintUtils34 } from "@typescript-eslint/utils";
5875
6328
  var EQUALITY_OPERATORS = /* @__PURE__ */ new Set(["===", "!==", "==", "!="]);
5876
6329
  var SENTINEL_IDENTIFIERS = /* @__PURE__ */ new Set(["undefined", "NaN"]);
5877
6330
  var SENTINEL_WORDS = /(^|_)(SENTINEL|EMPTY|NONE|NULL|UNSET|MISSING|PLACEHOLDER|DUMMY|FAKE|EXAMPLE)(_|$)/;
@@ -5884,36 +6337,36 @@ function isConstantReference(identifier) {
5884
6337
  }
5885
6338
  function isExcludedOperand(node) {
5886
6339
  switch (node.type) {
5887
- case AST_NODE_TYPES25.Literal:
6340
+ case AST_NODE_TYPES26.Literal:
5888
6341
  return true;
5889
- case AST_NODE_TYPES25.TemplateLiteral:
6342
+ case AST_NODE_TYPES26.TemplateLiteral:
5890
6343
  return node.expressions.length === 0;
5891
- case AST_NODE_TYPES25.Identifier:
6344
+ case AST_NODE_TYPES26.Identifier:
5892
6345
  return SENTINEL_IDENTIFIERS.has(node.name) || SENTINEL_PREFIX_RE.test(node.name) || isConstantReference(node.name);
5893
- case AST_NODE_TYPES25.MemberExpression:
5894
- return !node.computed && node.property.type === AST_NODE_TYPES25.Identifier && (SENTINEL_PREFIX_RE.test(node.property.name) || isConstantReference(node.property.name));
6346
+ case AST_NODE_TYPES26.MemberExpression:
6347
+ return !node.computed && node.property.type === AST_NODE_TYPES26.Identifier && (SENTINEL_PREFIX_RE.test(node.property.name) || isConstantReference(node.property.name));
5895
6348
  default:
5896
6349
  return false;
5897
6350
  }
5898
6351
  }
5899
6352
  function operandName(node) {
5900
- if (node.type === AST_NODE_TYPES25.Identifier) {
6353
+ if (node.type === AST_NODE_TYPES26.Identifier) {
5901
6354
  return node.name;
5902
6355
  }
5903
- if (node.type === AST_NODE_TYPES25.MemberExpression && !node.computed && node.property.type === AST_NODE_TYPES25.Identifier) {
6356
+ if (node.type === AST_NODE_TYPES26.MemberExpression && !node.computed && node.property.type === AST_NODE_TYPES26.Identifier) {
5904
6357
  return node.property.name;
5905
6358
  }
5906
6359
  return null;
5907
6360
  }
5908
6361
  function isSecretOperand(node) {
5909
- if (node.type === AST_NODE_TYPES25.TemplateLiteral) {
6362
+ if (node.type === AST_NODE_TYPES26.TemplateLiteral) {
5910
6363
  return node.expressions.some((expression) => isSecretOperand(expression));
5911
6364
  }
5912
6365
  const name = operandName(node);
5913
6366
  return name !== null && isAuthSecretName(name);
5914
6367
  }
5915
6368
  function secretNameOf(node) {
5916
- if (node.type === AST_NODE_TYPES25.TemplateLiteral) {
6369
+ if (node.type === AST_NODE_TYPES26.TemplateLiteral) {
5917
6370
  for (const expression of node.expressions) {
5918
6371
  const nested = secretNameOf(expression);
5919
6372
  if (nested !== null) {
@@ -5924,7 +6377,7 @@ function secretNameOf(node) {
5924
6377
  }
5925
6378
  return operandName(node);
5926
6379
  }
5927
- var prefer_constant_time_secret_compare_default = ESLintUtils35.RuleCreator(
6380
+ var prefer_constant_time_secret_compare_default = ESLintUtils34.RuleCreator(
5928
6381
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5929
6382
  )({
5930
6383
  name: "prefer-constant-time-secret-compare",
@@ -5967,11 +6420,11 @@ var prefer_constant_time_secret_compare_default = ESLintUtils35.RuleCreator(
5967
6420
  });
5968
6421
 
5969
6422
  // src/rules/store-insert-requires-on-conflict.ts
5970
- import { ESLintUtils as ESLintUtils36 } from "@typescript-eslint/utils";
6423
+ import { ESLintUtils as ESLintUtils35 } from "@typescript-eslint/utils";
5971
6424
  var INSERT_WRITE = /\bINSERT\s+(?:OR\s+\w+\s+)?INTO\s+[\w."'`?$:@-]+\s*(?:\([^)]*\)\s*)?(?:VALUES|SELECT|DEFAULT\s+VALUES)\b/i;
5972
6425
  var CONFLICT_HANDLED = /\bON\s+CONFLICT\b|\bON\s+DUPLICATE\s+KEY\b|\bINSERT\s+OR\s+(?:IGNORE|REPLACE)\b/i;
5973
6426
  var INSERT_GATE = /insert/i;
5974
- var store_insert_requires_on_conflict_default = ESLintUtils36.RuleCreator(
6427
+ var store_insert_requires_on_conflict_default = ESLintUtils35.RuleCreator(
5975
6428
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
5976
6429
  )({
5977
6430
  name: "store-insert-requires-on-conflict",
@@ -6000,17 +6453,17 @@ var store_insert_requires_on_conflict_default = ESLintUtils36.RuleCreator(
6000
6453
  });
6001
6454
 
6002
6455
  // src/rules/no-dynamic-sql.ts
6003
- import { AST_NODE_TYPES as AST_NODE_TYPES26, ESLintUtils as ESLintUtils37 } from "@typescript-eslint/utils";
6456
+ import { AST_NODE_TYPES as AST_NODE_TYPES27, ESLintUtils as ESLintUtils36 } from "@typescript-eslint/utils";
6004
6457
  var DEFAULT_METHODS = ["prepare", "exec", "query"];
6005
6458
  var CONSTANT_CASE_RE = /^[A-Z][A-Z0-9_]*$/;
6006
6459
  function isStaticFragment(expression) {
6007
- if (expression.type === AST_NODE_TYPES26.Identifier) {
6460
+ if (expression.type === AST_NODE_TYPES27.Identifier) {
6008
6461
  return CONSTANT_CASE_RE.test(expression.name);
6009
6462
  }
6010
- if (expression.type === AST_NODE_TYPES26.MemberExpression && !expression.computed && expression.property.type === AST_NODE_TYPES26.Identifier) {
6463
+ if (expression.type === AST_NODE_TYPES27.MemberExpression && !expression.computed && expression.property.type === AST_NODE_TYPES27.Identifier) {
6011
6464
  return CONSTANT_CASE_RE.test(expression.property.name);
6012
6465
  }
6013
- if (expression.type === AST_NODE_TYPES26.Literal) {
6466
+ if (expression.type === AST_NODE_TYPES27.Literal) {
6014
6467
  return typeof expression.value === "string";
6015
6468
  }
6016
6469
  return false;
@@ -6021,36 +6474,36 @@ function runtimeInterpolations(template) {
6021
6474
  );
6022
6475
  }
6023
6476
  function concatOperands(node) {
6024
- if (node.type === AST_NODE_TYPES26.BinaryExpression && node.operator === "+") {
6477
+ if (node.type === AST_NODE_TYPES27.BinaryExpression && node.operator === "+") {
6025
6478
  return [...concatOperands(node.left), ...concatOperands(node.right)];
6026
6479
  }
6027
6480
  return [node];
6028
6481
  }
6029
6482
  function runtimeConcatOperands(node) {
6030
- if (node.type !== AST_NODE_TYPES26.BinaryExpression || node.operator !== "+") {
6483
+ if (node.type !== AST_NODE_TYPES27.BinaryExpression || node.operator !== "+") {
6031
6484
  return [];
6032
6485
  }
6033
6486
  const operands = concatOperands(node);
6034
6487
  const hasStringLiteral = operands.some(
6035
- (operand) => operand.type === AST_NODE_TYPES26.Literal && typeof operand.value === "string"
6488
+ (operand) => operand.type === AST_NODE_TYPES27.Literal && typeof operand.value === "string"
6036
6489
  );
6037
6490
  if (!hasStringLiteral) {
6038
6491
  return [];
6039
6492
  }
6040
6493
  return operands.filter(
6041
- (operand) => operand.type !== AST_NODE_TYPES26.Literal && !isStaticFragment(operand)
6494
+ (operand) => operand.type !== AST_NODE_TYPES27.Literal && !isStaticFragment(operand)
6042
6495
  );
6043
6496
  }
6044
6497
  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;
6045
6498
  var RUNTIME_MARKER = " ? ";
6046
6499
  function staticStatementText(node) {
6047
- if (node.type === AST_NODE_TYPES26.TemplateLiteral) {
6500
+ if (node.type === AST_NODE_TYPES27.TemplateLiteral) {
6048
6501
  return node.quasis.map((quasi) => quasi.value.cooked ?? quasi.value.raw).join(RUNTIME_MARKER);
6049
6502
  }
6050
- if (node.type === AST_NODE_TYPES26.Literal) {
6503
+ if (node.type === AST_NODE_TYPES27.Literal) {
6051
6504
  return typeof node.value === "string" ? node.value : RUNTIME_MARKER;
6052
6505
  }
6053
- if (node.type === AST_NODE_TYPES26.BinaryExpression && node.operator === "+") {
6506
+ if (node.type === AST_NODE_TYPES27.BinaryExpression && node.operator === "+") {
6054
6507
  return staticStatementText(node.left) + staticStatementText(node.right);
6055
6508
  }
6056
6509
  return RUNTIME_MARKER;
@@ -6060,13 +6513,13 @@ function looksLikeSql(node) {
6060
6513
  }
6061
6514
  function statementMethodName(node, methods) {
6062
6515
  const callee = node.callee;
6063
- if (callee.type !== AST_NODE_TYPES26.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES26.Identifier) {
6516
+ if (callee.type !== AST_NODE_TYPES27.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES27.Identifier) {
6064
6517
  return null;
6065
6518
  }
6066
6519
  const name = callee.property.name;
6067
6520
  return methods.has(name) ? name : null;
6068
6521
  }
6069
- var no_dynamic_sql_default = ESLintUtils37.RuleCreator(
6522
+ var no_dynamic_sql_default = ESLintUtils36.RuleCreator(
6070
6523
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
6071
6524
  )({
6072
6525
  name: "no-dynamic-sql",
@@ -6105,7 +6558,7 @@ var no_dynamic_sql_default = ESLintUtils37.RuleCreator(
6105
6558
  if (statement === void 0 || !looksLikeSql(statement)) {
6106
6559
  return;
6107
6560
  }
6108
- const offenders = statement.type === AST_NODE_TYPES26.TemplateLiteral ? runtimeInterpolations(statement) : runtimeConcatOperands(statement);
6561
+ const offenders = statement.type === AST_NODE_TYPES27.TemplateLiteral ? runtimeInterpolations(statement) : runtimeConcatOperands(statement);
6109
6562
  for (const offender of offenders) {
6110
6563
  context.report({
6111
6564
  node: offender,
@@ -6119,7 +6572,7 @@ var no_dynamic_sql_default = ESLintUtils37.RuleCreator(
6119
6572
  });
6120
6573
 
6121
6574
  // src/rules/no-raw-fetch-outside-clients.ts
6122
- import { ESLintUtils as ESLintUtils38 } from "@typescript-eslint/utils";
6575
+ import { ESLintUtils as ESLintUtils37, AST_NODE_TYPES as AST_NODE_TYPES28 } from "@typescript-eslint/utils";
6123
6576
  var DEFAULT_ALLOW = [
6124
6577
  "[\\\\/]clients?[\\\\/]",
6125
6578
  "-client\\.[cm]?[jt]sx?$",
@@ -6129,17 +6582,15 @@ var DEFAULT_ALLOW = [
6129
6582
  "[\\\\/]api[\\\\/]",
6130
6583
  "[\\\\/]api\\.[cm]?[jt]sx?$",
6131
6584
  "[-.]api\\.[cm]?[jt]sx?$",
6132
- "\\.test\\.",
6133
- "\\.spec\\.",
6134
- // `*.test-d.ts` type tests, and react-router's `single-fetch-test.ts` spelling.
6135
- "\\.(test|spec)-d\\.[cm]?[jt]sx?$",
6136
- "-(test|spec)\\.[cm]?[jt]sx?$",
6137
- "[\\\\/]__tests__[\\\\/]",
6138
- "[\\\\/]__mocks__[\\\\/]",
6139
- "[\\\\/]tests?[\\\\/]",
6140
- // jscodeshift input/output fixtures — text a codemod transforms, not code.
6141
- "[\\\\/]__testfixtures__[\\\\/]"
6585
+ // Vendor wrapper conventions: a module that exists to own one third-party
6586
+ // origin's HTTP. See the SECOND SWEEP note in the file header.
6587
+ "[\\\\/]services?[\\\\/]",
6588
+ "[\\\\/](connectors|providers|integrations|adapters|fetchers)[\\\\/]",
6589
+ "[\\\\/]notifications[\\\\/]",
6590
+ "[Ss]ervice\\.[cm]?[jt]sx?$",
6591
+ "-(service|connector|adapter|sdk|fetcher)\\.[cm]?[jt]sx?$"
6142
6592
  ];
6593
+ var NON_PRODUCTION_TREE_RE = /[\\/](playwright|cypress|__testfixtures__)[\\/]/;
6143
6594
  var GLOBAL_RECEIVERS = /* @__PURE__ */ new Set([
6144
6595
  "globalThis",
6145
6596
  "window",
@@ -6165,6 +6616,10 @@ function identifierLikeName(node) {
6165
6616
  }
6166
6617
  return null;
6167
6618
  }
6619
+ function isConstructedArgumentHandoff(node) {
6620
+ const [first] = node.arguments;
6621
+ return node.arguments.length === 1 && first !== void 0 && first.type === AST_NODE_TYPES28.NewExpression;
6622
+ }
6168
6623
  function isPresignedUrlTransfer(node) {
6169
6624
  const first = node.arguments[0];
6170
6625
  if (first === void 0) {
@@ -6183,7 +6638,7 @@ function compile(patterns) {
6183
6638
  }
6184
6639
  return compiled;
6185
6640
  }
6186
- var no_raw_fetch_outside_clients_default = ESLintUtils38.RuleCreator(
6641
+ var no_raw_fetch_outside_clients_default = ESLintUtils37.RuleCreator(
6187
6642
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
6188
6643
  )({
6189
6644
  name: "no-raw-fetch-outside-clients",
@@ -6211,15 +6666,18 @@ var no_raw_fetch_outside_clients_default = ESLintUtils38.RuleCreator(
6211
6666
  },
6212
6667
  defaultOptions: [{}],
6213
6668
  create(context, [options]) {
6669
+ const filename = context.filename;
6670
+ if (isTestFile(filename) || NON_PRODUCTION_TREE_RE.test(filename)) {
6671
+ return {};
6672
+ }
6214
6673
  const patterns = options?.allow ?? DEFAULT_ALLOW;
6215
6674
  const allowed = compile(patterns);
6216
- const filename = context.filename;
6217
6675
  if (allowed.some((re) => re.test(filename))) {
6218
6676
  return {};
6219
6677
  }
6220
6678
  return {
6221
6679
  CallExpression(node) {
6222
- if (isPresignedUrlTransfer(node)) {
6680
+ if (isPresignedUrlTransfer(node) || isConstructedArgumentHandoff(node)) {
6223
6681
  return;
6224
6682
  }
6225
6683
  if (isGlobalFetchCall(node)) {
@@ -6231,7 +6689,7 @@ var no_raw_fetch_outside_clients_default = ESLintUtils38.RuleCreator(
6231
6689
  });
6232
6690
 
6233
6691
  // src/rules/no-storage-in-stateless-modules.ts
6234
- import { AST_NODE_TYPES as AST_NODE_TYPES27, ESLintUtils as ESLintUtils39 } from "@typescript-eslint/utils";
6692
+ import { AST_NODE_TYPES as AST_NODE_TYPES29, ESLintUtils as ESLintUtils38 } from "@typescript-eslint/utils";
6235
6693
  var DEFAULT_METHODS2 = [
6236
6694
  "prepare",
6237
6695
  "put",
@@ -6250,7 +6708,7 @@ function compile2(patterns) {
6250
6708
  }
6251
6709
  function storageMethodName(node, methods) {
6252
6710
  const callee = node.callee;
6253
- if (callee.type !== AST_NODE_TYPES27.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES27.Identifier) {
6711
+ if (callee.type !== AST_NODE_TYPES29.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES29.Identifier) {
6254
6712
  return null;
6255
6713
  }
6256
6714
  const name = callee.property.name;
@@ -6262,7 +6720,7 @@ function storageMethodName(node, methods) {
6262
6720
  }
6263
6721
  return name;
6264
6722
  }
6265
- var no_storage_in_stateless_modules_default = ESLintUtils39.RuleCreator(
6723
+ var no_storage_in_stateless_modules_default = ESLintUtils38.RuleCreator(
6266
6724
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
6267
6725
  )({
6268
6726
  name: "no-storage-in-stateless-modules",
@@ -6321,8 +6779,8 @@ var no_storage_in_stateless_modules_default = ESLintUtils39.RuleCreator(
6321
6779
 
6322
6780
  // src/rules/no-zod-native-enum.ts
6323
6781
  import {
6324
- ESLintUtils as ESLintUtils40,
6325
- AST_NODE_TYPES as AST_NODE_TYPES28
6782
+ ESLintUtils as ESLintUtils39,
6783
+ AST_NODE_TYPES as AST_NODE_TYPES30
6326
6784
  } from "@typescript-eslint/utils";
6327
6785
  import * as ts2 from "typescript";
6328
6786
  var IGNORE_PATTERNS2 = [
@@ -6341,7 +6799,7 @@ function isZodModule2(source) {
6341
6799
  return /(^|[/@-])zod([/-]|$)/.test(source);
6342
6800
  }
6343
6801
  function unwrap3(node) {
6344
- if (node.type === AST_NODE_TYPES28.TSAsExpression || node.type === AST_NODE_TYPES28.TSSatisfiesExpression) {
6802
+ if (node.type === AST_NODE_TYPES30.TSAsExpression || node.type === AST_NODE_TYPES30.TSSatisfiesExpression) {
6345
6803
  return unwrap3(node.expression);
6346
6804
  }
6347
6805
  return node;
@@ -6349,14 +6807,14 @@ function unwrap3(node) {
6349
6807
  function stringValueTexts(node, sourceCode) {
6350
6808
  const texts = [];
6351
6809
  for (const prop of node.properties) {
6352
- if (prop.type !== AST_NODE_TYPES28.Property) {
6810
+ if (prop.type !== AST_NODE_TYPES30.Property) {
6353
6811
  return null;
6354
6812
  }
6355
6813
  if (prop.computed || prop.shorthand || prop.method || prop.kind !== "init") {
6356
6814
  return null;
6357
6815
  }
6358
6816
  const value = prop.value;
6359
- if (value.type !== AST_NODE_TYPES28.Literal || typeof value.value !== "string") {
6817
+ if (value.type !== AST_NODE_TYPES30.Literal || typeof value.value !== "string") {
6360
6818
  return null;
6361
6819
  }
6362
6820
  const text = sourceCode.getText(value);
@@ -6372,7 +6830,7 @@ function resolvesToLocalEnum(node, scope) {
6372
6830
  const variable = current.variables.find((v) => v.name === node.name);
6373
6831
  if (variable !== void 0) {
6374
6832
  return variable.defs.some(
6375
- (def) => def.node.type === AST_NODE_TYPES28.TSEnumDeclaration
6833
+ (def) => def.node.type === AST_NODE_TYPES30.TSEnumDeclaration
6376
6834
  );
6377
6835
  }
6378
6836
  current = current.upper;
@@ -6392,7 +6850,7 @@ function resolvesToImportedEnum(node, services) {
6392
6850
  }
6393
6851
  return (symbol.flags & ENUM_SYMBOL_FLAGS) !== 0;
6394
6852
  }
6395
- var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6853
+ var no_zod_native_enum_default = ESLintUtils39.RuleCreator(
6396
6854
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
6397
6855
  )({
6398
6856
  name: "no-zod-native-enum",
@@ -6419,32 +6877,32 @@ var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6419
6877
  }
6420
6878
  let services;
6421
6879
  try {
6422
- services = ESLintUtils40.getParserServices(context);
6880
+ services = ESLintUtils39.getParserServices(context);
6423
6881
  } catch {
6424
6882
  services = null;
6425
6883
  }
6426
6884
  const zodImportedNames = /* @__PURE__ */ new Map();
6427
6885
  function isZodMemberCall(node, api) {
6428
6886
  const callee = node.callee;
6429
- if (callee.type === AST_NODE_TYPES28.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES28.Identifier) {
6887
+ if (callee.type === AST_NODE_TYPES30.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES30.Identifier) {
6430
6888
  return callee.property.name === api;
6431
6889
  }
6432
- if (callee.type === AST_NODE_TYPES28.Identifier) {
6890
+ if (callee.type === AST_NODE_TYPES30.Identifier) {
6433
6891
  return zodImportedNames.get(callee.name) === api;
6434
6892
  }
6435
6893
  return false;
6436
6894
  }
6437
6895
  function buildFix(node) {
6438
6896
  const callee = node.callee;
6439
- if (callee.type !== AST_NODE_TYPES28.MemberExpression || callee.property.type !== AST_NODE_TYPES28.Identifier) {
6897
+ if (callee.type !== AST_NODE_TYPES30.MemberExpression || callee.property.type !== AST_NODE_TYPES30.Identifier) {
6440
6898
  return null;
6441
6899
  }
6442
6900
  const arg = node.arguments[0];
6443
- if (arg === void 0 || node.arguments.length !== 1 || arg.type === AST_NODE_TYPES28.SpreadElement) {
6901
+ if (arg === void 0 || node.arguments.length !== 1 || arg.type === AST_NODE_TYPES30.SpreadElement) {
6444
6902
  return null;
6445
6903
  }
6446
6904
  const inner = unwrap3(arg);
6447
- if (inner.type !== AST_NODE_TYPES28.ObjectExpression) {
6905
+ if (inner.type !== AST_NODE_TYPES30.ObjectExpression) {
6448
6906
  return null;
6449
6907
  }
6450
6908
  const values = stringValueTexts(inner, sourceCode);
@@ -6464,7 +6922,7 @@ var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6464
6922
  return;
6465
6923
  }
6466
6924
  for (const spec of node.specifiers) {
6467
- if (spec.type === AST_NODE_TYPES28.ImportSpecifier && spec.imported.type === AST_NODE_TYPES28.Identifier) {
6925
+ if (spec.type === AST_NODE_TYPES30.ImportSpecifier && spec.imported.type === AST_NODE_TYPES30.Identifier) {
6468
6926
  zodImportedNames.set(spec.local.name, spec.imported.name);
6469
6927
  }
6470
6928
  }
@@ -6483,7 +6941,7 @@ var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6483
6941
  return;
6484
6942
  }
6485
6943
  const arg = node.arguments[0];
6486
- if (arg === void 0 || arg.type !== AST_NODE_TYPES28.Identifier) {
6944
+ if (arg === void 0 || arg.type !== AST_NODE_TYPES30.Identifier) {
6487
6945
  return;
6488
6946
  }
6489
6947
  const isEnum = resolvesToLocalEnum(arg, sourceCode.getScope(arg)) || services !== null && resolvesToImportedEnum(arg, services);
@@ -6501,8 +6959,8 @@ var no_zod_native_enum_default = ESLintUtils40.RuleCreator(
6501
6959
 
6502
6960
  // src/rules/prefer-module-level-constant.ts
6503
6961
  import {
6504
- ESLintUtils as ESLintUtils41,
6505
- AST_NODE_TYPES as AST_NODE_TYPES29
6962
+ ESLintUtils as ESLintUtils40,
6963
+ AST_NODE_TYPES as AST_NODE_TYPES31
6506
6964
  } from "@typescript-eslint/utils";
6507
6965
  var DEFAULT_MIN_ELEMENTS = 3;
6508
6966
  var MAX_LITERAL_DEPTH = 4;
@@ -6512,13 +6970,6 @@ var IGNORE_PATTERNS3 = [
6512
6970
  /\.generated\.tsx?$/,
6513
6971
  /\.d\.ts$/
6514
6972
  ];
6515
- var TEST_FILE_PATTERNS = [
6516
- /\.(?:test|spec)\.[cm]?[jt]sx?$/,
6517
- /[\\/]__tests__[\\/]/,
6518
- /[\\/]__mocks__[\\/]/,
6519
- /[\\/]tests?[\\/]/,
6520
- /\.stories\.[cm]?[jt]sx?$/
6521
- ];
6522
6973
  var MUTATING_METHODS = /* @__PURE__ */ new Set([
6523
6974
  // Array
6524
6975
  "push",
@@ -6538,10 +6989,10 @@ var MUTATING_METHODS = /* @__PURE__ */ new Set([
6538
6989
  // Object-ish escape hatches
6539
6990
  "assign"
6540
6991
  ]);
6541
- var FUNCTION_TYPES4 = /* @__PURE__ */ new Set([
6542
- AST_NODE_TYPES29.FunctionDeclaration,
6543
- AST_NODE_TYPES29.FunctionExpression,
6544
- AST_NODE_TYPES29.ArrowFunctionExpression
6992
+ var FUNCTION_TYPES5 = /* @__PURE__ */ new Set([
6993
+ AST_NODE_TYPES31.FunctionDeclaration,
6994
+ AST_NODE_TYPES31.FunctionExpression,
6995
+ AST_NODE_TYPES31.ArrowFunctionExpression
6545
6996
  ]);
6546
6997
  var COLLECTION_CONSTRUCTORS = /* @__PURE__ */ new Set(["Set", "Map"]);
6547
6998
  function isIgnoredFile3(filename, sourceText) {
@@ -6550,17 +7001,18 @@ function isIgnoredFile3(filename, sourceText) {
6550
7001
  }
6551
7002
  return /@generated\b/.test(sourceText.slice(0, 1024));
6552
7003
  }
6553
- function isTestFile2(filename) {
6554
- return TEST_FILE_PATTERNS.some((re) => re.test(filename));
7004
+ function isLocalFixtureFile(filename) {
7005
+ return isTestFile(filename) || isStoryFile(filename);
6555
7006
  }
6556
7007
  function unwrap4(node) {
6557
- if (node.type === AST_NODE_TYPES29.TSAsExpression || node.type === AST_NODE_TYPES29.TSSatisfiesExpression || node.type === AST_NODE_TYPES29.TSNonNullExpression) {
7008
+ if (node.type === AST_NODE_TYPES31.TSAsExpression || node.type === AST_NODE_TYPES31.TSSatisfiesExpression || node.type === AST_NODE_TYPES31.TSNonNullExpression) {
6558
7009
  return unwrap4(node.expression);
6559
7010
  }
6560
7011
  return node;
6561
7012
  }
7013
+ var HAS_STATEFUL_FLAG_RE = /[gy]/;
6562
7014
  function isRegexLiteral(node) {
6563
- return node.type === AST_NODE_TYPES29.Literal && "regex" in node && node.regex !== void 0;
7015
+ return node.type === AST_NODE_TYPES31.Literal && "regex" in node && node.regex !== void 0;
6564
7016
  }
6565
7017
  function isLiteralOnly(node, depth) {
6566
7018
  if (depth > MAX_LITERAL_DEPTH) {
@@ -6568,29 +7020,29 @@ function isLiteralOnly(node, depth) {
6568
7020
  }
6569
7021
  const inner = unwrap4(node);
6570
7022
  switch (inner.type) {
6571
- case AST_NODE_TYPES29.Literal: {
6572
- return true;
7023
+ case AST_NODE_TYPES31.Literal: {
7024
+ return !(isRegexLiteral(inner) && HAS_STATEFUL_FLAG_RE.test(inner.regex.flags));
6573
7025
  }
6574
- case AST_NODE_TYPES29.TemplateLiteral: {
7026
+ case AST_NODE_TYPES31.TemplateLiteral: {
6575
7027
  return inner.expressions.length === 0;
6576
7028
  }
6577
- case AST_NODE_TYPES29.UnaryExpression: {
6578
- return (inner.operator === "-" || inner.operator === "+") && inner.argument.type === AST_NODE_TYPES29.Literal && typeof inner.argument.value === "number";
7029
+ case AST_NODE_TYPES31.UnaryExpression: {
7030
+ return (inner.operator === "-" || inner.operator === "+") && inner.argument.type === AST_NODE_TYPES31.Literal && typeof inner.argument.value === "number";
6579
7031
  }
6580
- case AST_NODE_TYPES29.ArrayExpression: {
7032
+ case AST_NODE_TYPES31.ArrayExpression: {
6581
7033
  return inner.elements.every(
6582
- (el) => el !== null && el.type !== AST_NODE_TYPES29.SpreadElement && isLiteralOnly(el, depth + 1)
7034
+ (el) => el !== null && el.type !== AST_NODE_TYPES31.SpreadElement && isLiteralOnly(el, depth + 1)
6583
7035
  );
6584
7036
  }
6585
- case AST_NODE_TYPES29.ObjectExpression: {
7037
+ case AST_NODE_TYPES31.ObjectExpression: {
6586
7038
  return inner.properties.every((prop) => {
6587
- if (prop.type !== AST_NODE_TYPES29.Property) {
7039
+ if (prop.type !== AST_NODE_TYPES31.Property) {
6588
7040
  return false;
6589
7041
  }
6590
7042
  if (prop.shorthand || prop.method || prop.kind !== "init") {
6591
7043
  return false;
6592
7044
  }
6593
- if (prop.computed && prop.key.type !== AST_NODE_TYPES29.Literal) {
7045
+ if (prop.computed && prop.key.type !== AST_NODE_TYPES31.Literal) {
6594
7046
  return false;
6595
7047
  }
6596
7048
  return isLiteralOnly(prop.value, depth + 1);
@@ -6603,7 +7055,7 @@ function isLiteralOnly(node, depth) {
6603
7055
  }
6604
7056
  function unwrapObjectFreeze(node) {
6605
7057
  const inner = unwrap4(node);
6606
- 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) {
7058
+ if (inner.type === AST_NODE_TYPES31.CallExpression && inner.callee.type === AST_NODE_TYPES31.MemberExpression && !inner.callee.computed && inner.callee.object.type === AST_NODE_TYPES31.Identifier && inner.callee.object.name === "Object" && inner.callee.property.type === AST_NODE_TYPES31.Identifier && inner.callee.property.name === "freeze" && inner.arguments.length === 1 && inner.arguments[0] !== void 0 && inner.arguments[0].type !== AST_NODE_TYPES31.SpreadElement) {
6607
7059
  return unwrap4(inner.arguments[0]);
6608
7060
  }
6609
7061
  return inner;
@@ -6614,24 +7066,24 @@ function classify(init, checkRegex) {
6614
7066
  if (!checkRegex) {
6615
7067
  return null;
6616
7068
  }
6617
- if (/[gy]/.test(node.regex.flags)) {
7069
+ if (HAS_STATEFUL_FLAG_RE.test(node.regex.flags)) {
6618
7070
  return null;
6619
7071
  }
6620
7072
  return { kind: "regex", size: 1 };
6621
7073
  }
6622
- if (node.type === AST_NODE_TYPES29.ArrayExpression) {
7074
+ if (node.type === AST_NODE_TYPES31.ArrayExpression) {
6623
7075
  return isLiteralOnly(node, 0) ? { kind: "array", size: node.elements.length } : null;
6624
7076
  }
6625
- if (node.type === AST_NODE_TYPES29.ObjectExpression) {
7077
+ if (node.type === AST_NODE_TYPES31.ObjectExpression) {
6626
7078
  return isLiteralOnly(node, 0) ? { kind: "object", size: node.properties.length } : null;
6627
7079
  }
6628
- if (node.type === AST_NODE_TYPES29.NewExpression && node.callee.type === AST_NODE_TYPES29.Identifier && COLLECTION_CONSTRUCTORS.has(node.callee.name)) {
7080
+ if (node.type === AST_NODE_TYPES31.NewExpression && node.callee.type === AST_NODE_TYPES31.Identifier && COLLECTION_CONSTRUCTORS.has(node.callee.name)) {
6629
7081
  const arg = node.arguments[0];
6630
- if (node.arguments.length !== 1 || arg === void 0 || arg.type === AST_NODE_TYPES29.SpreadElement) {
7082
+ if (node.arguments.length !== 1 || arg === void 0 || arg.type === AST_NODE_TYPES31.SpreadElement) {
6631
7083
  return null;
6632
7084
  }
6633
7085
  const entries = unwrap4(arg);
6634
- if (entries.type !== AST_NODE_TYPES29.ArrayExpression) {
7086
+ if (entries.type !== AST_NODE_TYPES31.ArrayExpression) {
6635
7087
  return null;
6636
7088
  }
6637
7089
  return isLiteralOnly(entries, 0) ? { kind: node.callee.name === "Set" ? "Set" : "Map", size: entries.elements.length } : null;
@@ -6641,7 +7093,7 @@ function classify(init, checkRegex) {
6641
7093
  function enclosingFunction2(node) {
6642
7094
  let current = node.parent;
6643
7095
  while (current !== void 0 && current !== null) {
6644
- if (FUNCTION_TYPES4.has(current.type)) {
7096
+ if (FUNCTION_TYPES5.has(current.type)) {
6645
7097
  return current;
6646
7098
  }
6647
7099
  current = current.parent;
@@ -6660,10 +7112,10 @@ var NON_RETAINING_BUILTINS = /* @__PURE__ */ new Map(
6660
7112
  );
6661
7113
  function isNonRetainingBuiltinCall(node, argument) {
6662
7114
  const callee = node.callee;
6663
- if (callee.type === AST_NODE_TYPES29.Identifier && callee.name === "structuredClone") {
7115
+ if (callee.type === AST_NODE_TYPES31.Identifier && callee.name === "structuredClone") {
6664
7116
  return true;
6665
7117
  }
6666
- if (callee.type !== AST_NODE_TYPES29.MemberExpression || callee.computed || callee.object.type !== AST_NODE_TYPES29.Identifier || callee.property.type !== AST_NODE_TYPES29.Identifier) {
7118
+ if (callee.type !== AST_NODE_TYPES31.MemberExpression || callee.computed || callee.object.type !== AST_NODE_TYPES31.Identifier || callee.property.type !== AST_NODE_TYPES31.Identifier) {
6667
7119
  return false;
6668
7120
  }
6669
7121
  const members = NON_RETAINING_BUILTINS.get(callee.object.name);
@@ -6677,43 +7129,43 @@ function isNonRetainingBuiltinCall(node, argument) {
6677
7129
  }
6678
7130
  function isSafeRead(identifier) {
6679
7131
  const parent = identifier.parent;
6680
- if (parent.type === AST_NODE_TYPES29.MemberExpression) {
7132
+ if (parent.type === AST_NODE_TYPES31.MemberExpression) {
6681
7133
  if (parent.object !== identifier) {
6682
7134
  return true;
6683
7135
  }
6684
7136
  const grandparent = parent.parent;
6685
- if (grandparent.type === AST_NODE_TYPES29.AssignmentExpression && grandparent.left === parent) {
7137
+ if (grandparent.type === AST_NODE_TYPES31.AssignmentExpression && grandparent.left === parent) {
6686
7138
  return false;
6687
7139
  }
6688
- if (grandparent.type === AST_NODE_TYPES29.UpdateExpression) {
7140
+ if (grandparent.type === AST_NODE_TYPES31.UpdateExpression) {
6689
7141
  return false;
6690
7142
  }
6691
- if (grandparent.type === AST_NODE_TYPES29.UnaryExpression && grandparent.operator === "delete") {
7143
+ if (grandparent.type === AST_NODE_TYPES31.UnaryExpression && grandparent.operator === "delete") {
6692
7144
  return false;
6693
7145
  }
6694
- 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) {
7146
+ if (!parent.computed && parent.property.type === AST_NODE_TYPES31.Identifier && MUTATING_METHODS.has(parent.property.name) && grandparent.type === AST_NODE_TYPES31.CallExpression && grandparent.callee === parent) {
6695
7147
  return false;
6696
7148
  }
6697
7149
  return true;
6698
7150
  }
6699
- if (parent.type === AST_NODE_TYPES29.ForOfStatement && parent.right === identifier) {
7151
+ if (parent.type === AST_NODE_TYPES31.ForOfStatement && parent.right === identifier) {
6700
7152
  return true;
6701
7153
  }
6702
- if (parent.type === AST_NODE_TYPES29.SpreadElement) {
7154
+ if (parent.type === AST_NODE_TYPES31.SpreadElement) {
6703
7155
  return true;
6704
7156
  }
6705
- if (parent.type === AST_NODE_TYPES29.BinaryExpression) {
7157
+ if (parent.type === AST_NODE_TYPES31.BinaryExpression) {
6706
7158
  return true;
6707
7159
  }
6708
- if (parent.type === AST_NODE_TYPES29.CallExpression && parent.arguments.includes(identifier) && isNonRetainingBuiltinCall(parent, identifier)) {
7160
+ if (parent.type === AST_NODE_TYPES31.CallExpression && parent.arguments.includes(identifier) && isNonRetainingBuiltinCall(parent, identifier)) {
6709
7161
  return true;
6710
7162
  }
6711
- if (parent.type === AST_NODE_TYPES29.UnaryExpression && parent.operator !== "delete") {
7163
+ if (parent.type === AST_NODE_TYPES31.UnaryExpression && parent.operator !== "delete") {
6712
7164
  return true;
6713
7165
  }
6714
7166
  return false;
6715
7167
  }
6716
- var prefer_module_level_constant_default = ESLintUtils41.RuleCreator(
7168
+ var prefer_module_level_constant_default = ESLintUtils40.RuleCreator(
6717
7169
  (name) => `https://github.com/sarj-ai/linting/blob/main/packages/typescript/src/rules/${name}.ts`
6718
7170
  )({
6719
7171
  name: "prefer-module-level-constant",
@@ -6749,7 +7201,7 @@ var prefer_module_level_constant_default = ESLintUtils41.RuleCreator(
6749
7201
  if (isIgnoredFile3(filename, sourceCode.getText())) {
6750
7202
  return {};
6751
7203
  }
6752
- if (ignoreTestFiles && isTestFile2(filename)) {
7204
+ if (ignoreTestFiles && isLocalFixtureFile(filename)) {
6753
7205
  return {};
6754
7206
  }
6755
7207
  function allReferencesAreSafeReads(declarator) {
@@ -6765,7 +7217,7 @@ var prefer_module_level_constant_default = ESLintUtils41.RuleCreator(
6765
7217
  if (reference.isWrite()) {
6766
7218
  return false;
6767
7219
  }
6768
- if (reference.identifier.type !== AST_NODE_TYPES29.Identifier) {
7220
+ if (reference.identifier.type !== AST_NODE_TYPES31.Identifier) {
6769
7221
  return false;
6770
7222
  }
6771
7223
  if (!isSafeRead(reference.identifier)) {
@@ -6777,10 +7229,10 @@ var prefer_module_level_constant_default = ESLintUtils41.RuleCreator(
6777
7229
  return {
6778
7230
  VariableDeclarator(node) {
6779
7231
  const declaration = node.parent;
6780
- if (declaration.type !== AST_NODE_TYPES29.VariableDeclaration || declaration.kind !== "const" || declaration.declare === true) {
7232
+ if (declaration.type !== AST_NODE_TYPES31.VariableDeclaration || declaration.kind !== "const" || declaration.declare === true) {
6781
7233
  return;
6782
7234
  }
6783
- if (node.id.type !== AST_NODE_TYPES29.Identifier || node.init === null) {
7235
+ if (node.id.type !== AST_NODE_TYPES31.Identifier || node.init === null) {
6784
7236
  return;
6785
7237
  }
6786
7238
  if (enclosingFunction2(node) === null) {
@@ -6807,7 +7259,7 @@ var prefer_module_level_constant_default = ESLintUtils41.RuleCreator(
6807
7259
  });
6808
7260
 
6809
7261
  // src/rules/jsdoc-restates-signature.ts
6810
- import { AST_NODE_TYPES as AST_NODE_TYPES30, ESLintUtils as ESLintUtils42 } from "@typescript-eslint/utils";
7262
+ import { AST_NODE_TYPES as AST_NODE_TYPES32, ESLintUtils as ESLintUtils41 } from "@typescript-eslint/utils";
6811
7263
  var VALUE_TAGS = /* @__PURE__ */ new Set([
6812
7264
  "alpha",
6813
7265
  "author",
@@ -6890,30 +7342,30 @@ function declarationNames(node) {
6890
7342
  switch (node.type) {
6891
7343
  // `export function f()` — the JSDoc sits above the `export`, so the token
6892
7344
  // after it resolves to the wrapper, not to the thing being documented.
6893
- case AST_NODE_TYPES30.ExportNamedDeclaration:
6894
- case AST_NODE_TYPES30.ExportDefaultDeclaration:
7345
+ case AST_NODE_TYPES32.ExportNamedDeclaration:
7346
+ case AST_NODE_TYPES32.ExportDefaultDeclaration:
6895
7347
  return node.declaration == null ? null : declarationNames(node.declaration);
6896
- case AST_NODE_TYPES30.FunctionDeclaration:
6897
- case AST_NODE_TYPES30.TSDeclareFunction:
7348
+ case AST_NODE_TYPES32.FunctionDeclaration:
7349
+ case AST_NODE_TYPES32.TSDeclareFunction:
6898
7350
  return node.id === null ? null : { name: node.id.name, params: paramNames(node.params) };
6899
- case AST_NODE_TYPES30.ClassDeclaration:
6900
- case AST_NODE_TYPES30.TSInterfaceDeclaration:
6901
- case AST_NODE_TYPES30.TSTypeAliasDeclaration:
6902
- case AST_NODE_TYPES30.TSEnumDeclaration:
7351
+ case AST_NODE_TYPES32.ClassDeclaration:
7352
+ case AST_NODE_TYPES32.TSInterfaceDeclaration:
7353
+ case AST_NODE_TYPES32.TSTypeAliasDeclaration:
7354
+ case AST_NODE_TYPES32.TSEnumDeclaration:
6903
7355
  return node.id === null ? null : { name: node.id.name, params: [] };
6904
- case AST_NODE_TYPES30.VariableDeclaration: {
7356
+ case AST_NODE_TYPES32.VariableDeclaration: {
6905
7357
  const declarator = node.declarations[0];
6906
- if (declarator === void 0 || declarator.id.type !== AST_NODE_TYPES30.Identifier) return null;
7358
+ if (declarator === void 0 || declarator.id.type !== AST_NODE_TYPES32.Identifier) return null;
6907
7359
  const init = declarator.init;
6908
- const params = init != null && (init.type === AST_NODE_TYPES30.ArrowFunctionExpression || init.type === AST_NODE_TYPES30.FunctionExpression) ? paramNames(init.params) : [];
7360
+ const params = init != null && (init.type === AST_NODE_TYPES32.ArrowFunctionExpression || init.type === AST_NODE_TYPES32.FunctionExpression) ? paramNames(init.params) : [];
6909
7361
  return { name: declarator.id.name, params };
6910
7362
  }
6911
- case AST_NODE_TYPES30.MethodDefinition:
6912
- case AST_NODE_TYPES30.PropertyDefinition:
6913
- case AST_NODE_TYPES30.TSMethodSignature:
6914
- case AST_NODE_TYPES30.TSPropertySignature: {
6915
- if (node.key.type !== AST_NODE_TYPES30.Identifier) return null;
6916
- const params = node.type === AST_NODE_TYPES30.MethodDefinition ? paramNames(node.value.params) : node.type === AST_NODE_TYPES30.TSMethodSignature ? paramNames(node.params) : [];
7363
+ case AST_NODE_TYPES32.MethodDefinition:
7364
+ case AST_NODE_TYPES32.PropertyDefinition:
7365
+ case AST_NODE_TYPES32.TSMethodSignature:
7366
+ case AST_NODE_TYPES32.TSPropertySignature: {
7367
+ if (node.key.type !== AST_NODE_TYPES32.Identifier) return null;
7368
+ const params = node.type === AST_NODE_TYPES32.MethodDefinition ? paramNames(node.value.params) : node.type === AST_NODE_TYPES32.TSMethodSignature ? paramNames(node.params) : [];
6917
7369
  return { name: node.key.name, params };
6918
7370
  }
6919
7371
  default:
@@ -6923,9 +7375,9 @@ function declarationNames(node) {
6923
7375
  function paramNames(params) {
6924
7376
  const names = [];
6925
7377
  for (const param of params) {
6926
- const target = param.type === AST_NODE_TYPES30.AssignmentPattern ? param.left : param;
6927
- if (target.type === AST_NODE_TYPES30.Identifier) names.push(target.name);
6928
- else if (target.type === AST_NODE_TYPES30.TSParameterProperty) continue;
7378
+ const target = param.type === AST_NODE_TYPES32.AssignmentPattern ? param.left : param;
7379
+ if (target.type === AST_NODE_TYPES32.Identifier) names.push(target.name);
7380
+ else if (target.type === AST_NODE_TYPES32.TSParameterProperty) continue;
6929
7381
  }
6930
7382
  return names;
6931
7383
  }
@@ -6934,7 +7386,7 @@ function tokensOf(names) {
6934
7386
  for (const name of names) for (const part of splitIdentifier(name)) tokens.add(part);
6935
7387
  return tokens;
6936
7388
  }
6937
- var jsdoc_restates_signature_default = ESLintUtils42.RuleCreator(
7389
+ var jsdoc_restates_signature_default = ESLintUtils41.RuleCreator(
6938
7390
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
6939
7391
  )({
6940
7392
  name: "jsdoc-restates-signature",
@@ -6970,7 +7422,7 @@ var jsdoc_restates_signature_default = ESLintUtils42.RuleCreator(
6970
7422
  if (token === null || token.loc.start.line !== comment.loc.end.line + 1) continue;
6971
7423
  let node = sourceCode.getNodeByRangeIndex(token.range[0]);
6972
7424
  let declaration = null;
6973
- while (node != null && node.type !== AST_NODE_TYPES30.Program) {
7425
+ while (node != null && node.type !== AST_NODE_TYPES32.Program) {
6974
7426
  declaration = declarationNames(node);
6975
7427
  if (declaration !== null) break;
6976
7428
  node = node.parent ?? null;
@@ -7025,7 +7477,7 @@ var jsdoc_restates_signature_default = ESLintUtils42.RuleCreator(
7025
7477
  });
7026
7478
 
7027
7479
  // src/rules/no-restated-comment.ts
7028
- import { AST_NODE_TYPES as AST_NODE_TYPES31, ESLintUtils as ESLintUtils43 } from "@typescript-eslint/utils";
7480
+ import { AST_NODE_TYPES as AST_NODE_TYPES33, ESLintUtils as ESLintUtils42 } from "@typescript-eslint/utils";
7029
7481
  var MAX_WORDS = 8;
7030
7482
  var MIN_CONTENT_TOKENS = 2;
7031
7483
  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;
@@ -7049,7 +7501,7 @@ function headsSiblingRun(node) {
7049
7501
  const next = index >= 0 ? body[index + 1] : void 0;
7050
7502
  return next !== void 0 && next.type === node.type;
7051
7503
  }
7052
- var no_restated_comment_default = ESLintUtils43.RuleCreator(
7504
+ var no_restated_comment_default = ESLintUtils42.RuleCreator(
7053
7505
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7054
7506
  )({
7055
7507
  name: "no-restated-comment",
@@ -7077,7 +7529,7 @@ var no_restated_comment_default = ESLintUtils43.RuleCreator(
7077
7529
  function labelsASiblingRun(comment) {
7078
7530
  const token = sourceCode.getTokenAfter(comment, { includeComments: false });
7079
7531
  if (token === null) return false;
7080
- for (let node = sourceCode.getNodeByRangeIndex(token.range[0]); node != null && node.type !== AST_NODE_TYPES31.Program; node = node.parent) {
7532
+ for (let node = sourceCode.getNodeByRangeIndex(token.range[0]); node != null && node.type !== AST_NODE_TYPES33.Program; node = node.parent) {
7081
7533
  if (headsSiblingRun(node)) return true;
7082
7534
  }
7083
7535
  return false;
@@ -7117,7 +7569,7 @@ var no_restated_comment_default = ESLintUtils43.RuleCreator(
7117
7569
  });
7118
7570
 
7119
7571
  // src/rules/trailing-value-narration.ts
7120
- import { ESLintUtils as ESLintUtils44 } from "@typescript-eslint/utils";
7572
+ import { ESLintUtils as ESLintUtils43 } from "@typescript-eslint/utils";
7121
7573
  var NUMBER_RE = /(?<![\w.])(\d+(?:\.\d+)?)(?![\w.])/g;
7122
7574
  var WORD_RE3 = /[A-Za-z]+(?:'[a-z]+)?|\d+(?:\.\d+)?/g;
7123
7575
  var UNIT_WORDS = /* @__PURE__ */ new Set([
@@ -7201,7 +7653,7 @@ function narratesValue(body, code) {
7201
7653
  (word) => STOPWORDS3.has(word) || UNIT_WORDS.has(word) || commentNumbers.has(word) || identifiers.has(word) || stems.has(stem(word))
7202
7654
  );
7203
7655
  }
7204
- var trailing_value_narration_default = ESLintUtils44.RuleCreator(
7656
+ var trailing_value_narration_default = ESLintUtils43.RuleCreator(
7205
7657
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7206
7658
  )({
7207
7659
  name: "trailing-value-narration",
@@ -7241,8 +7693,190 @@ var trailing_value_narration_default = ESLintUtils44.RuleCreator(
7241
7693
  }
7242
7694
  });
7243
7695
 
7696
+ // src/rules/no-type-member-comment-wall.ts
7697
+ import { AST_NODE_TYPES as AST_NODE_TYPES34, ESLintUtils as ESLintUtils44 } from "@typescript-eslint/utils";
7698
+ var DEFAULTS = {
7699
+ // Below three rows "a wall" is not a fair description of what the reader sees.
7700
+ minCommentedMembers: 3,
7701
+ // A minority of commented members is a GROUP LABEL, not a wall.
7702
+ minCommentedRatio: 0.6,
7703
+ // Room for one substantive row in four; a type where a quarter of the comments
7704
+ // say something real is a type someone was documenting, not decorating.
7705
+ minRestatedRatio: 0.75,
7706
+ // One word beyond the member's own text. Zero is `jsdoc-restates-signature`'s
7707
+ // test and is already covered there; two admits definitions ("Partial match"
7708
+ // beside "Exact match"), which the evidence file counts.
7709
+ maxNovelWords: 1
7710
+ };
7711
+ var VALUE_TAG_RE = /@(?:deprecated|see|example|throws|remarks|since|default|defaultvalue|link|internal|alpha|beta|experimental|template|typeparam|inheritdoc|todo|fixme|override)\b/i;
7712
+ var DEFAULT_RE = /^\s*@?default\b|\bdefaults? (?:to|:)/i;
7713
+ var DIGIT_RE = /\d/;
7714
+ var UNIT_WORD_RE = /\b(?:ms|milliseconds?|seconds?|minutes?|hours?|days?|weeks?|months?|years?|bytes?|kb|mb|gb|percent|pixels?|px|utc|epoch)\b/i;
7715
+ var EXAMPLE_RE = /["'`]|\be\.g\.|\bi\.e\./;
7716
+ var BANNER_RE = /[=\-─-╿*#~_.]{3,}/;
7717
+ var NON_ASCII_LETTER_RE2 = /[^\p{ASCII}\p{N}\p{P}\p{Z}]/u;
7718
+ var STOPWORDS4 = new Set(
7719
+ `the a an of to for in on with and or as at by is are was be been being
7720
+ this that it its if whether when where which what will would can could should
7721
+ must may into from over about not no does do done has have had used use uses
7722
+ using given provided specified current new existing all any each per via
7723
+ instance object value values data item
7724
+ items element callback handler prop props param arg return
7725
+ returns returning result optional required true false null undefined
7726
+ string number boolean array list promise set map record type name`.split(/\s+/)
7727
+ );
7728
+ var WORD_RE4 = /[A-Za-z][A-Za-z0-9]*/g;
7729
+ var BARE_LABEL_RE = /^[A-Za-z][A-Za-z0-9]*$/;
7730
+ function labelStems(body) {
7731
+ return splitIdentifier(body).map(stem).join(" ");
7732
+ }
7733
+ function isNamedMember(node) {
7734
+ return (node.type === AST_NODE_TYPES34.TSPropertySignature || node.type === AST_NODE_TYPES34.TSMethodSignature) && !node.computed;
7735
+ }
7736
+ function commentBody(comment) {
7737
+ return comment.value.replace(/^\*+/, "").replace(/^[ \t]*\*[ \t]?/gm, "").trim();
7738
+ }
7739
+ function carriesValue(body) {
7740
+ return isProtected(body) || VALUE_TAG_RE.test(body) || DEFAULT_RE.test(body) || DIGIT_RE.test(body) || UNIT_WORD_RE.test(body) || EXAMPLE_RE.test(body) || BANNER_RE.test(body) || NON_ASCII_LETTER_RE2.test(body);
7741
+ }
7742
+ function knownTokens(source) {
7743
+ const tokens = /* @__PURE__ */ new Set();
7744
+ for (const identifier of source.match(/[A-Za-z_$][\w$]*/g) ?? []) {
7745
+ for (const part of splitIdentifier(identifier)) {
7746
+ tokens.add(part);
7747
+ tokens.add(stem(part));
7748
+ }
7749
+ }
7750
+ return tokens;
7751
+ }
7752
+ function novelWords(body, known) {
7753
+ let novel = 0;
7754
+ for (const word of body.match(WORD_RE4) ?? []) {
7755
+ const lower = word.toLowerCase();
7756
+ if (lower.length < 2 || STOPWORDS4.has(lower)) continue;
7757
+ if (!known.has(lower) && !known.has(stem(lower))) novel += 1;
7758
+ }
7759
+ return novel;
7760
+ }
7761
+ var no_type_member_comment_wall_default = ESLintUtils44.RuleCreator(
7762
+ (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7763
+ )({
7764
+ name: "no-type-member-comment-wall",
7765
+ meta: {
7766
+ type: "suggestion",
7767
+ docs: {
7768
+ description: "Flag an object type whose member comments mostly re-spell the members' own names and types."
7769
+ },
7770
+ schema: [
7771
+ {
7772
+ type: "object",
7773
+ additionalProperties: false,
7774
+ properties: {
7775
+ minCommentedMembers: {
7776
+ type: "integer",
7777
+ minimum: 2,
7778
+ description: "Fewest commented members that can count as a wall."
7779
+ },
7780
+ minCommentedRatio: {
7781
+ type: "number",
7782
+ minimum: 0,
7783
+ maximum: 1,
7784
+ description: "Least share of the type's members that must be commented; below it the comments are group labels."
7785
+ },
7786
+ minRestatedRatio: {
7787
+ type: "number",
7788
+ minimum: 0,
7789
+ maximum: 1,
7790
+ description: "Least share of the member comments that must be restatements."
7791
+ },
7792
+ maxNovelWords: {
7793
+ type: "integer",
7794
+ minimum: 0,
7795
+ description: "Most content words a comment may add beyond its member's own source and still count as a restatement."
7796
+ }
7797
+ }
7798
+ }
7799
+ ],
7800
+ messages: {
7801
+ commentWall: "{{restated}} of this type's {{commented}} member comments only re-spell the member's own name and type \u2014 delete them, and keep the rows that say what the name cannot."
7802
+ }
7803
+ },
7804
+ defaultOptions: [DEFAULTS],
7805
+ create(context, [provided]) {
7806
+ const options = { ...DEFAULTS, ...provided };
7807
+ const sourceCode = context.sourceCode;
7808
+ if (isGeneratedFile(context.filename, sourceCode.text) || isTestFile(context.filename) || isStoryFile(context.filename)) {
7809
+ return {};
7810
+ }
7811
+ const endingOn = /* @__PURE__ */ new Map();
7812
+ const startingOn = /* @__PURE__ */ new Map();
7813
+ for (const comment of sourceCode.getAllComments()) {
7814
+ endingOn.set(comment.loc.end.line, comment);
7815
+ if (!startingOn.has(comment.loc.start.line)) startingOn.set(comment.loc.start.line, comment);
7816
+ }
7817
+ function documentingComment(member) {
7818
+ const beforeMember = sourceCode.getTokenBefore(member, { includeComments: false });
7819
+ const ownsItsLine = beforeMember === null || beforeMember.loc.end.line < member.loc.start.line;
7820
+ const lead = ownsItsLine ? endingOn.get(member.loc.start.line - 1) : void 0;
7821
+ if (lead !== void 0) {
7822
+ const before = sourceCode.getTokenBefore(lead, { includeComments: false });
7823
+ if (before === null || before.loc.end.line < lead.loc.start.line) return lead;
7824
+ }
7825
+ const trail = startingOn.get(member.loc.end.line);
7826
+ return trail !== void 0 && trail.range[0] > member.range[0] ? trail : void 0;
7827
+ }
7828
+ function isGroupLabel(comment, member, headsRun) {
7829
+ if (comment.loc.end.line >= member.loc.start.line) return false;
7830
+ const body = commentBody(comment);
7831
+ if (!BARE_LABEL_RE.test(body)) return false;
7832
+ if (labelStems(body) === labelStems(sourceCode.getText(member.key))) return false;
7833
+ const lineAbove = sourceCode.lines[comment.loc.start.line - 2];
7834
+ return headsRun || lineAbove !== void 0 && lineAbove.trim().length === 0;
7835
+ }
7836
+ function check(node) {
7837
+ const members = node.type === AST_NODE_TYPES34.TSInterfaceBody ? node.body : node.members;
7838
+ const named = members.filter(isNamedMember);
7839
+ if (named.length === 0) return;
7840
+ const documented = named.map((member) => ({ member, comment: documentingComment(member) }));
7841
+ let commented = 0;
7842
+ let restated = 0;
7843
+ const claimed = /* @__PURE__ */ new Set();
7844
+ for (const [index, { member, comment }] of documented.entries()) {
7845
+ if (comment === void 0 || claimed.has(comment)) continue;
7846
+ const next = documented[index + 1];
7847
+ if (isGroupLabel(comment, member, next !== void 0 && next.comment === void 0)) {
7848
+ continue;
7849
+ }
7850
+ claimed.add(comment);
7851
+ commented += 1;
7852
+ const body = commentBody(comment);
7853
+ if (body.length === 0 || carriesValue(body)) continue;
7854
+ if (novelWords(body, knownTokens(sourceCode.getText(member))) <= options.maxNovelWords) {
7855
+ restated += 1;
7856
+ }
7857
+ }
7858
+ if (commented < options.minCommentedMembers || commented / named.length < options.minCommentedRatio || restated / commented < options.minRestatedRatio) {
7859
+ return;
7860
+ }
7861
+ context.report({
7862
+ node,
7863
+ loc: {
7864
+ start: node.loc.start,
7865
+ end: { line: node.loc.start.line, column: node.loc.start.column + 1 }
7866
+ },
7867
+ messageId: "commentWall",
7868
+ data: { restated: String(restated), commented: String(commented) }
7869
+ });
7870
+ }
7871
+ return {
7872
+ TSInterfaceBody: check,
7873
+ TSTypeLiteral: check
7874
+ };
7875
+ }
7876
+ });
7877
+
7244
7878
  // src/rules/no-tautological-expect.ts
7245
- import { AST_NODE_TYPES as AST_NODE_TYPES32, ESLintUtils as ESLintUtils45 } from "@typescript-eslint/utils";
7879
+ import { AST_NODE_TYPES as AST_NODE_TYPES35, ESLintUtils as ESLintUtils45 } from "@typescript-eslint/utils";
7246
7880
  var EQUALITY_MATCHERS = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual"]);
7247
7881
  var ZERO_ARG_MATCHERS = /* @__PURE__ */ new Set([
7248
7882
  "toBeDefined",
@@ -7256,17 +7890,17 @@ var OPERAND_PREVIEW_CHARS = 40;
7256
7890
  var NUMERIC_SIGNS = /* @__PURE__ */ new Set(["-", "+"]);
7257
7891
  function isLiteral(node) {
7258
7892
  switch (node.type) {
7259
- case AST_NODE_TYPES32.Literal:
7893
+ case AST_NODE_TYPES35.Literal:
7260
7894
  return true;
7261
- case AST_NODE_TYPES32.TemplateLiteral:
7895
+ case AST_NODE_TYPES35.TemplateLiteral:
7262
7896
  return node.expressions.length === 0;
7263
- case AST_NODE_TYPES32.UnaryExpression:
7897
+ case AST_NODE_TYPES35.UnaryExpression:
7264
7898
  return NUMERIC_SIGNS.has(node.operator) && isLiteral(node.argument);
7265
- case AST_NODE_TYPES32.ArrayExpression:
7899
+ case AST_NODE_TYPES35.ArrayExpression:
7266
7900
  return node.elements.every((element) => element !== null && isLiteral(element));
7267
- case AST_NODE_TYPES32.ObjectExpression:
7901
+ case AST_NODE_TYPES35.ObjectExpression:
7268
7902
  return node.properties.every(
7269
- (property) => property.type === AST_NODE_TYPES32.Property && !property.computed && isLiteral(property.value)
7903
+ (property) => property.type === AST_NODE_TYPES35.Property && !property.computed && isLiteral(property.value)
7270
7904
  );
7271
7905
  default:
7272
7906
  return false;
@@ -7274,7 +7908,7 @@ function isLiteral(node) {
7274
7908
  }
7275
7909
  function expectOperand(callee) {
7276
7910
  const receiver = callee.object;
7277
- if (receiver.type !== AST_NODE_TYPES32.CallExpression || receiver.callee.type !== AST_NODE_TYPES32.Identifier || receiver.callee.name !== "expect" || receiver.arguments.length !== 1) {
7911
+ if (receiver.type !== AST_NODE_TYPES35.CallExpression || receiver.callee.type !== AST_NODE_TYPES35.Identifier || receiver.callee.name !== "expect" || receiver.arguments.length !== 1) {
7278
7912
  return null;
7279
7913
  }
7280
7914
  return receiver.arguments[0] ?? null;
@@ -7306,10 +7940,10 @@ var no_tautological_expect_default = ESLintUtils45.RuleCreator(
7306
7940
  return {
7307
7941
  CallExpression(node) {
7308
7942
  const callee = node.callee;
7309
- if (callee.type !== AST_NODE_TYPES32.MemberExpression || callee.computed) {
7943
+ if (callee.type !== AST_NODE_TYPES35.MemberExpression || callee.computed) {
7310
7944
  return;
7311
7945
  }
7312
- if (callee.property.type !== AST_NODE_TYPES32.Identifier) {
7946
+ if (callee.property.type !== AST_NODE_TYPES35.Identifier) {
7313
7947
  return;
7314
7948
  }
7315
7949
  const matcher = callee.property.name;
@@ -7343,26 +7977,26 @@ var no_tautological_expect_default = ESLintUtils45.RuleCreator(
7343
7977
  });
7344
7978
 
7345
7979
  // src/rules/require-interface-for-injected-service.ts
7346
- import { AST_NODE_TYPES as AST_NODE_TYPES33, ESLintUtils as ESLintUtils46 } from "@typescript-eslint/utils";
7980
+ import { AST_NODE_TYPES as AST_NODE_TYPES36, ESLintUtils as ESLintUtils46 } from "@typescript-eslint/utils";
7347
7981
  var CONFIGISH_TYPE_RE = /(?:Options|Opts|Config|Configuration|Settings|Params|Props|Args|Env|Environment|Callbacks|Flags)$/;
7348
7982
  var CONFIGISH_NAME_RE = /^(?:options|opts|config|configuration|settings|params|props|args|env|environment|callbacks|flags|logger|log|clock)$/i;
7349
7983
  var HTTP_TRANSPORT_TYPE_RE = /^(?:KyInstance|AxiosInstance|Session)$/;
7350
7984
  var TRANSPORT_WRAPPER_NAME_RE = /Client$/;
7351
7985
  var ROUTER_FACTORY_NAME = "Router";
7352
7986
  var FRAMEWORK_HTTP_TYPES = /* @__PURE__ */ new Set(["Request", "Response", "NextFunction"]);
7353
- var isExportedClass = (node) => node.parent.type === AST_NODE_TYPES33.ExportNamedDeclaration || node.parent.type === AST_NODE_TYPES33.ExportDefaultDeclaration;
7354
- var qualifiedName = (name) => name.type === AST_NODE_TYPES33.Identifier ? name.name : name.type === AST_NODE_TYPES33.TSQualifiedName ? `${qualifiedName(name.left)}.${name.right.name}` : "";
7987
+ var isExportedClass = (node) => node.parent.type === AST_NODE_TYPES36.ExportNamedDeclaration || node.parent.type === AST_NODE_TYPES36.ExportDefaultDeclaration;
7988
+ var qualifiedName = (name) => name.type === AST_NODE_TYPES36.Identifier ? name.name : name.type === AST_NODE_TYPES36.TSQualifiedName ? `${qualifiedName(name.left)}.${name.right.name}` : "";
7355
7989
  var typeReferenceName = (annotated) => {
7356
7990
  let target = annotated;
7357
- if (target.type === AST_NODE_TYPES33.TSParameterProperty) target = target.parameter;
7358
- if (target.type === AST_NODE_TYPES33.AssignmentPattern) target = target.left;
7359
- if (target.type !== AST_NODE_TYPES33.Identifier) return null;
7991
+ if (target.type === AST_NODE_TYPES36.TSParameterProperty) target = target.parameter;
7992
+ if (target.type === AST_NODE_TYPES36.AssignmentPattern) target = target.left;
7993
+ if (target.type !== AST_NODE_TYPES36.Identifier) return null;
7360
7994
  const annotation = target.typeAnnotation?.typeAnnotation;
7361
- if (annotation === void 0 || annotation.type !== AST_NODE_TYPES33.TSTypeReference) {
7995
+ if (annotation === void 0 || annotation.type !== AST_NODE_TYPES36.TSTypeReference) {
7362
7996
  return null;
7363
7997
  }
7364
7998
  const { typeName } = annotation;
7365
- const rightmost = typeName.type === AST_NODE_TYPES33.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES33.TSQualifiedName ? typeName.right.name : null;
7999
+ const rightmost = typeName.type === AST_NODE_TYPES36.Identifier ? typeName.name : typeName.type === AST_NODE_TYPES36.TSQualifiedName ? typeName.right.name : null;
7366
8000
  if (rightmost === null) return null;
7367
8001
  return { name: target.name, typeName: rightmost, display: qualifiedName(typeName) };
7368
8002
  };
@@ -7372,17 +8006,17 @@ var readConstructor = (ctor) => {
7372
8006
  let constructedFields = 0;
7373
8007
  if (body !== null && body !== void 0) {
7374
8008
  for (const statement of body.body) {
7375
- if (statement.type !== AST_NODE_TYPES33.ExpressionStatement) continue;
8009
+ if (statement.type !== AST_NODE_TYPES36.ExpressionStatement) continue;
7376
8010
  const expression = statement.expression;
7377
- if (expression.type !== AST_NODE_TYPES33.AssignmentExpression || expression.operator !== "=" || expression.left.type !== AST_NODE_TYPES33.MemberExpression || expression.left.object.type !== AST_NODE_TYPES33.ThisExpression) {
8011
+ if (expression.type !== AST_NODE_TYPES36.AssignmentExpression || expression.operator !== "=" || expression.left.type !== AST_NODE_TYPES36.MemberExpression || expression.left.object.type !== AST_NODE_TYPES36.ThisExpression) {
7378
8012
  continue;
7379
8013
  }
7380
8014
  const source = expression.right;
7381
- if (source.type === AST_NODE_TYPES33.NewExpression) {
8015
+ if (source.type === AST_NODE_TYPES36.NewExpression) {
7382
8016
  constructedFields += 1;
7383
- } else if (source.type === AST_NODE_TYPES33.Identifier) {
8017
+ } else if (source.type === AST_NODE_TYPES36.Identifier) {
7384
8018
  storedFrom.add(source.name);
7385
- } else if (source.type === AST_NODE_TYPES33.MemberExpression && source.object.type === AST_NODE_TYPES33.Identifier) {
8019
+ } else if (source.type === AST_NODE_TYPES36.MemberExpression && source.object.type === AST_NODE_TYPES36.Identifier) {
7386
8020
  storedFrom.add(source.object.name);
7387
8021
  }
7388
8022
  }
@@ -7391,7 +8025,7 @@ var readConstructor = (ctor) => {
7391
8025
  for (const parameter of ctor.value.params) {
7392
8026
  const reference = typeReferenceName(parameter);
7393
8027
  if (reference === null) continue;
7394
- const stored = parameter.type === AST_NODE_TYPES33.TSParameterProperty || storedFrom.has(reference.name);
8028
+ const stored = parameter.type === AST_NODE_TYPES36.TSParameterProperty || storedFrom.has(reference.name);
7395
8029
  if (!stored) continue;
7396
8030
  if (CONFIGISH_TYPE_RE.test(reference.typeName)) continue;
7397
8031
  if (CONFIGISH_NAME_RE.test(reference.name)) continue;
@@ -7421,19 +8055,19 @@ var subtreeHas = (root, found) => {
7421
8055
  return hit;
7422
8056
  };
7423
8057
  var isFrameworkWiring = (body) => subtreeHas(body, (node) => {
7424
- if (node.type === AST_NODE_TYPES33.CallExpression) {
8058
+ if (node.type === AST_NODE_TYPES36.CallExpression) {
7425
8059
  const { callee } = node;
7426
- if (callee.type === AST_NODE_TYPES33.Identifier) return callee.name === ROUTER_FACTORY_NAME;
7427
- return callee.type === AST_NODE_TYPES33.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES33.Identifier && callee.property.name === ROUTER_FACTORY_NAME;
8060
+ if (callee.type === AST_NODE_TYPES36.Identifier) return callee.name === ROUTER_FACTORY_NAME;
8061
+ return callee.type === AST_NODE_TYPES36.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES36.Identifier && callee.property.name === ROUTER_FACTORY_NAME;
7428
8062
  }
7429
- return node.type === AST_NODE_TYPES33.TSTypeReference && node.typeName.type === AST_NODE_TYPES33.TSQualifiedName && FRAMEWORK_HTTP_TYPES.has(node.typeName.right.name);
8063
+ return node.type === AST_NODE_TYPES36.TSTypeReference && node.typeName.type === AST_NODE_TYPES36.TSQualifiedName && FRAMEWORK_HTTP_TYPES.has(node.typeName.right.name);
7430
8064
  });
7431
8065
  var stem2 = (name) => name.replace(/^I(?=[A-Z])/, "").replace(/Impl$/, "");
7432
8066
  var fileInterfaceNames = (program) => {
7433
8067
  const names = [];
7434
8068
  for (const statement of program.body) {
7435
- const declaration = statement.type === AST_NODE_TYPES33.ExportNamedDeclaration ? statement.declaration : statement;
7436
- if (declaration?.type === AST_NODE_TYPES33.TSInterfaceDeclaration) names.push(declaration.id.name);
8069
+ const declaration = statement.type === AST_NODE_TYPES36.ExportNamedDeclaration ? statement.declaration : statement;
8070
+ if (declaration?.type === AST_NODE_TYPES36.TSInterfaceDeclaration) names.push(declaration.id.name);
7437
8071
  }
7438
8072
  return names;
7439
8073
  };
@@ -7451,11 +8085,11 @@ var isTransportWrapper = (className, collaborators, program) => {
7451
8085
  var publicMethodNames = (body) => {
7452
8086
  const names = [];
7453
8087
  for (const member of body.body) {
7454
- if (member.type !== AST_NODE_TYPES33.MethodDefinition) continue;
8088
+ if (member.type !== AST_NODE_TYPES36.MethodDefinition) continue;
7455
8089
  if (member.kind !== "method" || member.static) continue;
7456
8090
  if (member.accessibility === "private" || member.accessibility === "protected") continue;
7457
- if (member.key.type === AST_NODE_TYPES33.PrivateIdentifier) continue;
7458
- if (member.key.type === AST_NODE_TYPES33.Identifier) names.push(member.key.name);
8091
+ if (member.key.type === AST_NODE_TYPES36.PrivateIdentifier) continue;
8092
+ if (member.key.type === AST_NODE_TYPES36.Identifier) names.push(member.key.name);
7459
8093
  else names.push("\u2026");
7460
8094
  }
7461
8095
  return names;
@@ -7488,7 +8122,7 @@ var require_interface_for_injected_service_default = ESLintUtils46.RuleCreator(
7488
8122
  if (node.implements.length > 0) return;
7489
8123
  if (node.decorators.length > 0) return;
7490
8124
  const ctor = node.body.body.find(
7491
- (member) => member.type === AST_NODE_TYPES33.MethodDefinition && member.kind === "constructor"
8125
+ (member) => member.type === AST_NODE_TYPES36.MethodDefinition && member.kind === "constructor"
7492
8126
  );
7493
8127
  if (ctor === void 0) return;
7494
8128
  const { collaborators, constructedFields } = readConstructor(ctor);
@@ -7513,20 +8147,20 @@ var require_interface_for_injected_service_default = ESLintUtils46.RuleCreator(
7513
8147
  });
7514
8148
 
7515
8149
  // src/rules/prefer-non-nullable-collection.ts
7516
- import { AST_NODE_TYPES as AST_NODE_TYPES34, ESLintUtils as ESLintUtils47 } from "@typescript-eslint/utils";
8150
+ import { AST_NODE_TYPES as AST_NODE_TYPES37, ESLintUtils as ESLintUtils47 } from "@typescript-eslint/utils";
7517
8151
  var ARRAY_TYPE_NAMES = /* @__PURE__ */ new Set(["Array", "ReadonlyArray"]);
7518
8152
  function propertyName(node) {
7519
8153
  const key = node.key;
7520
- if (key.type === AST_NODE_TYPES34.Identifier) return key.name;
7521
- if (key.type === AST_NODE_TYPES34.Literal) return String(key.value);
8154
+ if (key.type === AST_NODE_TYPES37.Identifier) return key.name;
8155
+ if (key.type === AST_NODE_TYPES37.Literal) return String(key.value);
7522
8156
  return "collection";
7523
8157
  }
7524
8158
  function isArrayType(node) {
7525
- if (node.type === AST_NODE_TYPES34.TSArrayType) return true;
7526
- return node.type === AST_NODE_TYPES34.TSTypeReference && node.typeName.type === AST_NODE_TYPES34.Identifier && ARRAY_TYPE_NAMES.has(node.typeName.name);
8159
+ if (node.type === AST_NODE_TYPES37.TSArrayType) return true;
8160
+ return node.type === AST_NODE_TYPES37.TSTypeReference && node.typeName.type === AST_NODE_TYPES37.Identifier && ARRAY_TYPE_NAMES.has(node.typeName.name);
7527
8161
  }
7528
8162
  function isNullishType(node) {
7529
- return node.type === AST_NODE_TYPES34.TSNullKeyword || node.type === AST_NODE_TYPES34.TSUndefinedKeyword;
8163
+ return node.type === AST_NODE_TYPES37.TSNullKeyword || node.type === AST_NODE_TYPES37.TSUndefinedKeyword;
7530
8164
  }
7531
8165
  function isNullableArrayOnly(node) {
7532
8166
  const values = node.types.filter((member) => !isNullishType(member));
@@ -7555,7 +8189,7 @@ var prefer_non_nullable_collection_default = ESLintUtils47.RuleCreator(
7555
8189
  function checkOptionalProperty(node) {
7556
8190
  const annotation = node.typeAnnotation?.typeAnnotation;
7557
8191
  if (annotation === void 0) return;
7558
- if (annotation.type !== AST_NODE_TYPES34.TSUnionType || !isNullableArrayOnly(annotation)) {
8192
+ if (annotation.type !== AST_NODE_TYPES37.TSUnionType || !isNullableArrayOnly(annotation)) {
7559
8193
  return;
7560
8194
  }
7561
8195
  context.report({
@@ -7568,7 +8202,7 @@ var prefer_non_nullable_collection_default = ESLintUtils47.RuleCreator(
7568
8202
  TSPropertySignature: checkOptionalProperty,
7569
8203
  PropertyDefinition: checkOptionalProperty,
7570
8204
  TSTypeAliasDeclaration(node) {
7571
- if (node.typeAnnotation.type !== AST_NODE_TYPES34.TSUnionType) return;
8205
+ if (node.typeAnnotation.type !== AST_NODE_TYPES37.TSUnionType) return;
7572
8206
  if (!isNullableArrayOnly(node.typeAnnotation)) return;
7573
8207
  context.report({
7574
8208
  node,
@@ -7580,174 +8214,217 @@ var prefer_non_nullable_collection_default = ESLintUtils47.RuleCreator(
7580
8214
  }
7581
8215
  });
7582
8216
 
7583
- // src/rules/no-implicit-attribute-access.ts
7584
- import { AST_NODE_TYPES as AST_NODE_TYPES35, ESLintUtils as ESLintUtils48 } from "@typescript-eslint/utils";
7585
- var EXCLUDED_BASES = /* @__PURE__ */ new Set([
7586
- "environ",
7587
- "headers",
7588
- "cookies",
7589
- "session",
7590
- "redis",
7591
- "cache",
7592
- "state",
7593
- "config",
7594
- "env",
7595
- "process",
7596
- "localStorage",
7597
- "sessionStorage"
7598
- ]);
7599
- function getBaseName(node) {
7600
- if (node.type === AST_NODE_TYPES35.Identifier) {
7601
- return node.name;
8217
+ // src/rules/strict-test-assertions.ts
8218
+ import { AST_NODE_TYPES as AST_NODE_TYPES38, ESLintUtils as ESLintUtils48 } from "@typescript-eslint/utils";
8219
+ var MERGEABLE_MATCHERS = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual"]);
8220
+ var ARRAY_MATCHERS = /* @__PURE__ */ new Set(["toEqual", "toStrictEqual"]);
8221
+ var COLLECTION_PROPERTIES = /* @__PURE__ */ new Set(["length", "size"]);
8222
+ var NUMERIC_SIGNS2 = /* @__PURE__ */ new Set(["-", "+"]);
8223
+ var MIN_RUN_LENGTH = 2;
8224
+ function literalText(node, getText) {
8225
+ switch (node.type) {
8226
+ case AST_NODE_TYPES38.Literal:
8227
+ return "regex" in node ? null : getText(node);
8228
+ case AST_NODE_TYPES38.TemplateLiteral:
8229
+ return node.expressions.length === 0 ? getText(node) : null;
8230
+ case AST_NODE_TYPES38.UnaryExpression:
8231
+ return NUMERIC_SIGNS2.has(node.operator) && literalText(node.argument, getText) !== null ? getText(node) : null;
8232
+ default:
8233
+ return null;
7602
8234
  }
7603
- if (node.type === AST_NODE_TYPES35.MemberExpression && node.property.type === AST_NODE_TYPES35.Identifier) {
7604
- return node.property.name;
8235
+ }
8236
+ function isPureReceiver(node) {
8237
+ switch (node.type) {
8238
+ case AST_NODE_TYPES38.Identifier:
8239
+ case AST_NODE_TYPES38.ThisExpression:
8240
+ return true;
8241
+ case AST_NODE_TYPES38.MemberExpression:
8242
+ if (node.optional) {
8243
+ return false;
8244
+ }
8245
+ if (node.computed) {
8246
+ return node.property.type === AST_NODE_TYPES38.Literal && isPureReceiver(node.object);
8247
+ }
8248
+ return isPureReceiver(node.object);
8249
+ default:
8250
+ return false;
7605
8251
  }
7606
- return null;
7607
8252
  }
7608
- var no_implicit_attribute_access_default = ESLintUtils48.RuleCreator(
8253
+ function literalIndex(node) {
8254
+ if (node.type !== AST_NODE_TYPES38.Literal || typeof node.value !== "number") {
8255
+ return null;
8256
+ }
8257
+ return Number.isInteger(node.value) && node.value >= 0 ? node.value : null;
8258
+ }
8259
+ var strict_test_assertions_default = ESLintUtils48.RuleCreator(
7609
8260
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7610
8261
  )({
7611
- name: "no-implicit-attribute-access",
7612
- meta: {
7613
- type: "problem",
7614
- docs: {
7615
- description: "Disallow imperative dictionary access with string literals; use declarative Zod schemas."
7616
- },
7617
- schema: [],
7618
- messages: {
7619
- noImplicitAttributeAccess: "Imperative lookup for '{{key}}' \u2014 if the key is known, parse the object declaratively with a Zod schema instead."
7620
- }
7621
- },
7622
- defaultOptions: [],
7623
- create(context) {
7624
- return {
7625
- MemberExpression(node) {
7626
- if (!node.computed) {
7627
- return;
7628
- }
7629
- if (node.property.type === AST_NODE_TYPES35.Literal && typeof node.property.value === "string") {
7630
- const baseName = getBaseName(node.object);
7631
- if (!baseName || !EXCLUDED_BASES.has(baseName)) {
7632
- context.report({
7633
- node,
7634
- messageId: "noImplicitAttributeAccess",
7635
- data: { key: node.property.value }
7636
- });
7637
- }
7638
- }
7639
- },
7640
- CallExpression(node) {
7641
- const callee = node.callee;
7642
- if (callee.type === AST_NODE_TYPES35.MemberExpression) {
7643
- const method = callee.property.type === AST_NODE_TYPES35.Identifier ? callee.property.name : null;
7644
- if (method === "get") {
7645
- const arg = node.arguments[0];
7646
- if (arg && arg.type === AST_NODE_TYPES35.Literal && typeof arg.value === "string") {
7647
- const baseName = getBaseName(callee.object);
7648
- if (!baseName || !EXCLUDED_BASES.has(baseName)) {
7649
- context.report({
7650
- node,
7651
- messageId: "noImplicitAttributeAccess",
7652
- data: { key: arg.value }
7653
- });
7654
- }
7655
- }
7656
- }
7657
- }
7658
- }
7659
- };
7660
- }
7661
- });
7662
-
7663
- // src/rules/strict-test-assertions.ts
7664
- import { AST_NODE_TYPES as AST_NODE_TYPES36, ESLintUtils as ESLintUtils49 } from "@typescript-eslint/utils";
7665
- var strict_test_assertions_default = ESLintUtils49.RuleCreator.withoutDocs({
8262
+ name: "strict-test-assertions",
7666
8263
  meta: {
7667
8264
  type: "suggestion",
7668
8265
  docs: {
7669
- description: "Replace multiple sequential assertions with a single toMatchObject or toStrictEqual"
8266
+ description: "Collapse a run of consecutive assertions on the same object into one assertion about the whole object, so every mismatch is reported and nothing outside the asserted keys goes unchecked."
7670
8267
  },
7671
8268
  fixable: "code",
7672
8269
  messages: {
7673
- combineAssertions: "Combine multiple sequential assertions on the same object into a single toMatchObject or toStrictEqual"
8270
+ combineAssertions: "These {{count}} assertions each check one property of `{{receiver}}` against a literal, so the first mismatch hides the rest. Assert the object once: `expect({{receiver}}).toMatchObject({ \u2026 })`.",
8271
+ assertArrayOnce: "These {{count}} assertions check `{{receiver}}[0]`\u2026`{{receiver}}[{{last}}]` one at a time, which never checks how long `{{receiver}}` is \u2014 extra elements pass unnoticed. Assert the array once: `expect({{receiver}}).{{matcher}}([ \u2026 ])`."
7674
8272
  },
7675
8273
  schema: []
7676
8274
  },
7677
8275
  defaultOptions: [],
7678
8276
  create(context) {
7679
- function checkBody(body) {
7680
- let currentObject = null;
7681
- let sequence = [];
7682
- function getExpectObject(expr) {
7683
- if (expr.type === AST_NODE_TYPES36.CallExpression && expr.callee.type === AST_NODE_TYPES36.MemberExpression && expr.callee.object.type === AST_NODE_TYPES36.CallExpression && expr.callee.object.callee.type === AST_NODE_TYPES36.Identifier && expr.callee.object.callee.name === "expect" && expr.callee.object.arguments.length === 1) {
7684
- const arg = expr.callee.object.arguments.at(0);
7685
- if (arg?.type === AST_NODE_TYPES36.MemberExpression) {
7686
- return arg.object;
7687
- }
8277
+ if (!isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) {
8278
+ return {};
8279
+ }
8280
+ const { sourceCode } = context;
8281
+ function parseAssertion(statement) {
8282
+ if (statement.type !== AST_NODE_TYPES38.ExpressionStatement) {
8283
+ return null;
8284
+ }
8285
+ const call = statement.expression;
8286
+ if (call.type !== AST_NODE_TYPES38.CallExpression) {
8287
+ return null;
8288
+ }
8289
+ const callee = call.callee;
8290
+ if (callee.type !== AST_NODE_TYPES38.MemberExpression || callee.computed || callee.property.type !== AST_NODE_TYPES38.Identifier) {
8291
+ return null;
8292
+ }
8293
+ const matcher = callee.property.name;
8294
+ const expectCall = callee.object;
8295
+ if (expectCall.type !== AST_NODE_TYPES38.CallExpression || expectCall.callee.type !== AST_NODE_TYPES38.Identifier || expectCall.callee.name !== "expect" || expectCall.arguments.length !== 1) {
8296
+ return null;
8297
+ }
8298
+ const actual = expectCall.arguments[0];
8299
+ if (actual === void 0 || actual.type !== AST_NODE_TYPES38.MemberExpression || actual.optional) {
8300
+ return null;
8301
+ }
8302
+ if (!isPureReceiver(actual.object)) {
8303
+ return null;
8304
+ }
8305
+ let key;
8306
+ if (actual.computed) {
8307
+ const index = literalIndex(actual.property);
8308
+ if (index === null) {
8309
+ return null;
7688
8310
  }
8311
+ key = { kind: "index", index };
8312
+ } else {
8313
+ if (actual.property.type !== AST_NODE_TYPES38.Identifier || COLLECTION_PROPERTIES.has(actual.property.name)) {
8314
+ return null;
8315
+ }
8316
+ key = { kind: "property", name: actual.property.name };
8317
+ }
8318
+ if (matcher === "toBeNull" && call.arguments.length === 0) {
8319
+ return { statement, receiver: actual.object, key, matcher, expectedText: "null", expectedIsLiteral: true };
8320
+ }
8321
+ if (!MERGEABLE_MATCHERS.has(matcher)) {
7689
8322
  return null;
7690
8323
  }
7691
- function reportSequence() {
7692
- const first = sequence.at(0);
7693
- if (sequence.length > 1 && first) {
7694
- context.report({
7695
- node: first,
7696
- messageId: "combineAssertions",
7697
- fix(fixer) {
7698
- if (!currentObject) return null;
7699
- const objectText = context.sourceCode.getText(currentObject);
7700
- const props = sequence.map((stmt) => {
7701
- if (stmt.expression.type !== AST_NODE_TYPES36.CallExpression || stmt.expression.callee.type !== AST_NODE_TYPES36.MemberExpression || stmt.expression.callee.object.type !== AST_NODE_TYPES36.CallExpression) {
7702
- return null;
7703
- }
7704
- const actual = stmt.expression.callee.object.arguments.at(0);
7705
- const expected = stmt.expression.arguments.at(0);
7706
- if (actual?.type === AST_NODE_TYPES36.MemberExpression && actual.property.type === AST_NODE_TYPES36.Identifier && expected) {
7707
- const propName2 = actual.property.name;
7708
- const valText = context.sourceCode.getText(expected);
7709
- return `${propName2}: ${valText}`;
7710
- }
7711
- return null;
7712
- });
7713
- if (props.some((p) => p === null)) return null;
7714
- const replacement = `expect(${objectText}).toMatchObject({ ${props.join(", ")} });`;
7715
- return [
7716
- fixer.replaceText(first, replacement),
7717
- ...sequence.slice(1).map((stmt) => fixer.remove(stmt))
7718
- ];
7719
- }
7720
- });
8324
+ const expected = call.arguments[0];
8325
+ if (call.arguments.length !== 1 || expected === void 0 || expected.type === AST_NODE_TYPES38.SpreadElement) {
8326
+ return null;
8327
+ }
8328
+ const literal = literalText(expected, (node) => sourceCode.getText(node));
8329
+ return {
8330
+ statement,
8331
+ receiver: actual.object,
8332
+ key,
8333
+ matcher,
8334
+ expectedText: literal ?? sourceCode.getText(expected),
8335
+ expectedIsLiteral: literal !== null
8336
+ };
8337
+ }
8338
+ function reportPropertyRun(run) {
8339
+ const names = /* @__PURE__ */ new Set();
8340
+ for (const assertion of run) {
8341
+ if (assertion.key.kind !== "property" || !assertion.expectedIsLiteral) {
8342
+ return;
8343
+ }
8344
+ if (!MERGEABLE_MATCHERS.has(assertion.matcher) && assertion.matcher !== "toBeNull") {
8345
+ return;
8346
+ }
8347
+ if (names.has(assertion.key.name)) {
8348
+ return;
7721
8349
  }
8350
+ names.add(assertion.key.name);
7722
8351
  }
7723
- for (const statement of body) {
7724
- if (statement.type === AST_NODE_TYPES36.ExpressionStatement) {
7725
- const obj = getExpectObject(statement.expression);
7726
- if (obj && currentObject && context.sourceCode.getText(obj) === context.sourceCode.getText(currentObject)) {
7727
- sequence.push(statement);
8352
+ const first = run[0];
8353
+ if (first === void 0) {
8354
+ return;
8355
+ }
8356
+ const receiverText = sourceCode.getText(first.receiver);
8357
+ const properties = run.map(
8358
+ (assertion) => assertion.key.kind === "property" ? `${assertion.key.name}: ${assertion.expectedText}` : ""
8359
+ ).join(", ");
8360
+ context.report({
8361
+ node: first.statement,
8362
+ messageId: "combineAssertions",
8363
+ data: { count: String(run.length), receiver: receiverText },
8364
+ fix: (fixer) => [
8365
+ fixer.replaceText(first.statement, `expect(${receiverText}).toMatchObject({ ${properties} });`),
8366
+ ...run.slice(1).map((assertion) => fixer.remove(assertion.statement))
8367
+ ]
8368
+ });
8369
+ }
8370
+ function reportIndexRun(run) {
8371
+ const first = run[0];
8372
+ if (first === void 0 || !ARRAY_MATCHERS.has(first.matcher)) {
8373
+ return;
8374
+ }
8375
+ const indices = /* @__PURE__ */ new Set();
8376
+ for (const assertion of run) {
8377
+ if (assertion.key.kind !== "index" || assertion.matcher !== first.matcher) {
8378
+ return;
8379
+ }
8380
+ indices.add(assertion.key.index);
8381
+ }
8382
+ if (indices.size !== run.length || Math.max(...indices) !== run.length - 1) {
8383
+ return;
8384
+ }
8385
+ context.report({
8386
+ node: first.statement,
8387
+ messageId: "assertArrayOnce",
8388
+ data: {
8389
+ count: String(run.length),
8390
+ receiver: sourceCode.getText(first.receiver),
8391
+ last: String(run.length - 1),
8392
+ matcher: first.matcher
8393
+ }
8394
+ });
8395
+ }
8396
+ function checkBody(body) {
8397
+ let run = [];
8398
+ const flush = () => {
8399
+ const first = run[0];
8400
+ if (first !== void 0 && run.length >= MIN_RUN_LENGTH) {
8401
+ if (first.key.kind === "property") {
8402
+ reportPropertyRun(run);
7728
8403
  } else {
7729
- reportSequence();
7730
- if (obj) {
7731
- currentObject = obj;
7732
- sequence = [statement];
7733
- } else {
7734
- currentObject = null;
7735
- sequence = [];
7736
- }
8404
+ reportIndexRun(run);
7737
8405
  }
7738
- } else {
7739
- reportSequence();
7740
- currentObject = null;
7741
- sequence = [];
8406
+ }
8407
+ run = [];
8408
+ };
8409
+ for (const statement of body) {
8410
+ const assertion = parseAssertion(statement);
8411
+ const previous = run.at(-1);
8412
+ if (assertion !== null && previous !== void 0 && previous.key.kind === assertion.key.kind && sourceCode.getText(previous.receiver) === sourceCode.getText(assertion.receiver)) {
8413
+ run.push(assertion);
8414
+ continue;
8415
+ }
8416
+ flush();
8417
+ if (assertion !== null) {
8418
+ run = [assertion];
7742
8419
  }
7743
8420
  }
7744
- reportSequence();
8421
+ flush();
7745
8422
  }
7746
8423
  return {
7747
- BlockStatement(node) {
8424
+ BlockStatement: (node) => {
7748
8425
  checkBody(node.body);
7749
8426
  },
7750
- Program(node) {
8427
+ Program: (node) => {
7751
8428
  checkBody(node.body);
7752
8429
  }
7753
8430
  };
@@ -7755,8 +8432,8 @@ var strict_test_assertions_default = ESLintUtils49.RuleCreator.withoutDocs({
7755
8432
  });
7756
8433
 
7757
8434
  // src/rules/no-async-callback-in-waitfor.ts
7758
- import { AST_NODE_TYPES as AST_NODE_TYPES37, ESLintUtils as ESLintUtils50 } from "@typescript-eslint/utils";
7759
- var no_async_callback_in_waitfor_default = ESLintUtils50.RuleCreator(
8435
+ import { AST_NODE_TYPES as AST_NODE_TYPES39, ESLintUtils as ESLintUtils49 } from "@typescript-eslint/utils";
8436
+ var no_async_callback_in_waitfor_default = ESLintUtils49.RuleCreator(
7760
8437
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7761
8438
  )({
7762
8439
  name: "no-async-callback-in-waitfor",
@@ -7777,9 +8454,9 @@ var no_async_callback_in_waitfor_default = ESLintUtils50.RuleCreator(
7777
8454
  }
7778
8455
  return {
7779
8456
  CallExpression(node) {
7780
- if (node.callee.type === AST_NODE_TYPES37.Identifier && node.callee.name === "waitFor") {
8457
+ if (node.callee.type === AST_NODE_TYPES39.Identifier && node.callee.name === "waitFor") {
7781
8458
  const callback = node.arguments[0];
7782
- if (callback && (callback.type === AST_NODE_TYPES37.ArrowFunctionExpression || callback.type === AST_NODE_TYPES37.FunctionExpression) && callback.async) {
8459
+ if (callback && (callback.type === AST_NODE_TYPES39.ArrowFunctionExpression || callback.type === AST_NODE_TYPES39.FunctionExpression) && callback.async) {
7783
8460
  context.report({
7784
8461
  node: callback,
7785
8462
  messageId: "noAsyncCallbackInWaitFor"
@@ -7792,7 +8469,7 @@ var no_async_callback_in_waitfor_default = ESLintUtils50.RuleCreator(
7792
8469
  });
7793
8470
 
7794
8471
  // src/rules/no-hand-rolled-sleep.ts
7795
- import { AST_NODE_TYPES as AST_NODE_TYPES38, ESLintUtils as ESLintUtils51 } from "@typescript-eslint/utils";
8472
+ import { AST_NODE_TYPES as AST_NODE_TYPES40, ESLintUtils as ESLintUtils50 } from "@typescript-eslint/utils";
7796
8473
  var GLOBAL_OBJECTS2 = /* @__PURE__ */ new Set([
7797
8474
  "globalThis",
7798
8475
  "window",
@@ -7811,66 +8488,66 @@ function matchesAnyPattern3(filename, patterns) {
7811
8488
  return false;
7812
8489
  }
7813
8490
  function isSetTimeoutCallee(callee) {
7814
- if (callee.type === AST_NODE_TYPES38.Identifier) {
8491
+ if (callee.type === AST_NODE_TYPES40.Identifier) {
7815
8492
  return callee.name === "setTimeout";
7816
8493
  }
7817
- return callee.type === AST_NODE_TYPES38.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES38.Identifier && callee.property.name === "setTimeout" && callee.object.type === AST_NODE_TYPES38.Identifier && GLOBAL_OBJECTS2.has(callee.object.name);
8494
+ return callee.type === AST_NODE_TYPES40.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES40.Identifier && callee.property.name === "setTimeout" && callee.object.type === AST_NODE_TYPES40.Identifier && GLOBAL_OBJECTS2.has(callee.object.name);
7818
8495
  }
7819
8496
  function soleCall(fn) {
7820
- if (fn.body.type !== AST_NODE_TYPES38.BlockStatement) {
7821
- return fn.body.type === AST_NODE_TYPES38.CallExpression ? fn.body : null;
8497
+ if (fn.body.type !== AST_NODE_TYPES40.BlockStatement) {
8498
+ return fn.body.type === AST_NODE_TYPES40.CallExpression ? fn.body : null;
7822
8499
  }
7823
8500
  if (fn.body.body.length !== 1) {
7824
8501
  return null;
7825
8502
  }
7826
8503
  const [only] = fn.body.body;
7827
- if (only?.type !== AST_NODE_TYPES38.ExpressionStatement) {
8504
+ if (only?.type !== AST_NODE_TYPES40.ExpressionStatement) {
7828
8505
  return null;
7829
8506
  }
7830
- return only.expression.type === AST_NODE_TYPES38.CallExpression ? only.expression : null;
8507
+ return only.expression.type === AST_NODE_TYPES40.CallExpression ? only.expression : null;
7831
8508
  }
7832
8509
  function isTimedDelay(delay) {
7833
8510
  if (delay === void 0) {
7834
8511
  return false;
7835
8512
  }
7836
- if (delay.type === AST_NODE_TYPES38.Literal && typeof delay.value === "number") {
8513
+ if (delay.type === AST_NODE_TYPES40.Literal && typeof delay.value === "number") {
7837
8514
  return delay.value !== 0;
7838
8515
  }
7839
8516
  return true;
7840
8517
  }
7841
8518
  function settlesWithoutValue(callback, name) {
7842
- if (callback.type === AST_NODE_TYPES38.Identifier) {
8519
+ if (callback.type === AST_NODE_TYPES40.Identifier) {
7843
8520
  return callback.name === name;
7844
8521
  }
7845
- if (callback.type !== AST_NODE_TYPES38.ArrowFunctionExpression && callback.type !== AST_NODE_TYPES38.FunctionExpression) {
8522
+ if (callback.type !== AST_NODE_TYPES40.ArrowFunctionExpression && callback.type !== AST_NODE_TYPES40.FunctionExpression) {
7846
8523
  return false;
7847
8524
  }
7848
8525
  const call = soleCall(callback);
7849
- return call !== null && call.arguments.length === 0 && call.callee.type === AST_NODE_TYPES38.Identifier && call.callee.name === name;
8526
+ return call !== null && call.arguments.length === 0 && call.callee.type === AST_NODE_TYPES40.Identifier && call.callee.name === name;
7850
8527
  }
7851
8528
  function rejectsInCallback(callback, name) {
7852
- if (callback.type === AST_NODE_TYPES38.Identifier) {
8529
+ if (callback.type === AST_NODE_TYPES40.Identifier) {
7853
8530
  return callback.name === name;
7854
8531
  }
7855
- if (callback.type !== AST_NODE_TYPES38.ArrowFunctionExpression && callback.type !== AST_NODE_TYPES38.FunctionExpression) {
8532
+ if (callback.type !== AST_NODE_TYPES40.ArrowFunctionExpression && callback.type !== AST_NODE_TYPES40.FunctionExpression) {
7856
8533
  return false;
7857
8534
  }
7858
8535
  const call = soleCall(callback);
7859
- return call !== null && call.callee.type === AST_NODE_TYPES38.Identifier && call.callee.name === name;
8536
+ return call !== null && call.callee.type === AST_NODE_TYPES40.Identifier && call.callee.name === name;
7860
8537
  }
7861
8538
  function parameterName(fn, index) {
7862
8539
  const parameter = fn.params[index];
7863
- return parameter?.type === AST_NODE_TYPES38.Identifier ? parameter.name : null;
8540
+ return parameter?.type === AST_NODE_TYPES40.Identifier ? parameter.name : null;
7864
8541
  }
7865
8542
  function isRaceArm(node) {
7866
8543
  const array = node.parent;
7867
- if (array?.type !== AST_NODE_TYPES38.ArrayExpression) {
8544
+ if (array?.type !== AST_NODE_TYPES40.ArrayExpression) {
7868
8545
  return false;
7869
8546
  }
7870
8547
  const call = array.parent;
7871
- return call?.type === AST_NODE_TYPES38.CallExpression && call.arguments[0] === array && call.callee.type === AST_NODE_TYPES38.MemberExpression && !call.callee.computed && call.callee.object.type === AST_NODE_TYPES38.Identifier && call.callee.object.name === "Promise" && call.callee.property.type === AST_NODE_TYPES38.Identifier && RACE_METHODS.has(call.callee.property.name);
8548
+ return call?.type === AST_NODE_TYPES40.CallExpression && call.arguments[0] === array && call.callee.type === AST_NODE_TYPES40.MemberExpression && !call.callee.computed && call.callee.object.type === AST_NODE_TYPES40.Identifier && call.callee.object.name === "Promise" && call.callee.property.type === AST_NODE_TYPES40.Identifier && RACE_METHODS.has(call.callee.property.name);
7872
8549
  }
7873
- var no_hand_rolled_sleep_default = ESLintUtils51.RuleCreator(
8550
+ var no_hand_rolled_sleep_default = ESLintUtils50.RuleCreator(
7874
8551
  (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7875
8552
  )({
7876
8553
  name: "no-hand-rolled-sleep",
@@ -7918,10 +8595,10 @@ var no_hand_rolled_sleep_default = ESLintUtils51.RuleCreator(
7918
8595
  }
7919
8596
  const program = sourceCode.ast;
7920
8597
  for (const statement of program.body) {
7921
- if (statement.type === AST_NODE_TYPES38.ExpressionStatement && statement.expression.type === AST_NODE_TYPES38.Literal && statement.expression.value === "use client") {
8598
+ if (statement.type === AST_NODE_TYPES40.ExpressionStatement && statement.expression.type === AST_NODE_TYPES40.Literal && statement.expression.value === "use client") {
7922
8599
  return true;
7923
8600
  }
7924
- if (statement.type === AST_NODE_TYPES38.ImportDeclaration && typeof statement.source.value === "string" && CLIENT_ONLY_MODULES.test(statement.source.value)) {
8601
+ if (statement.type === AST_NODE_TYPES40.ImportDeclaration && typeof statement.source.value === "string" && CLIENT_ONLY_MODULES.test(statement.source.value)) {
7925
8602
  return true;
7926
8603
  }
7927
8604
  }
@@ -7937,11 +8614,11 @@ var no_hand_rolled_sleep_default = ESLintUtils51.RuleCreator(
7937
8614
  };
7938
8615
  return {
7939
8616
  NewExpression(node) {
7940
- if (node.callee.type !== AST_NODE_TYPES38.Identifier || node.callee.name !== "Promise") {
8617
+ if (node.callee.type !== AST_NODE_TYPES40.Identifier || node.callee.name !== "Promise") {
7941
8618
  return;
7942
8619
  }
7943
8620
  const executor = node.arguments[0];
7944
- if (executor?.type !== AST_NODE_TYPES38.ArrowFunctionExpression && executor?.type !== AST_NODE_TYPES38.FunctionExpression) {
8621
+ if (executor?.type !== AST_NODE_TYPES40.ArrowFunctionExpression && executor?.type !== AST_NODE_TYPES40.FunctionExpression) {
7945
8622
  return;
7946
8623
  }
7947
8624
  const call = soleCall(executor);
@@ -7968,43 +8645,8 @@ var no_hand_rolled_sleep_default = ESLintUtils51.RuleCreator(
7968
8645
  }
7969
8646
  });
7970
8647
 
7971
- // src/rules/prefer-setup-file-mocks.ts
7972
- import { AST_NODE_TYPES as AST_NODE_TYPES39, ESLintUtils as ESLintUtils52 } from "@typescript-eslint/utils";
7973
- var prefer_setup_file_mocks_default = ESLintUtils52.RuleCreator(
7974
- (name) => `https://github.com/sarj-ai/standards/blob/main/packages/typescript/src/rules/${name}.ts`
7975
- )({
7976
- name: "prefer-setup-file-mocks",
7977
- meta: {
7978
- type: "suggestion",
7979
- docs: {
7980
- description: "Prefer defining module mocks in setup files rather than using vi.mock or jest.mock inline in test files."
7981
- },
7982
- schema: [],
7983
- messages: {
7984
- 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."
7985
- }
7986
- },
7987
- defaultOptions: [],
7988
- create(context) {
7989
- if (!isTestFile(context.filename)) {
7990
- return {};
7991
- }
7992
- return {
7993
- CallExpression(node) {
7994
- if (node.callee.type === AST_NODE_TYPES39.MemberExpression && node.callee.object.type === AST_NODE_TYPES39.Identifier && (node.callee.object.name === "vi" || node.callee.object.name === "jest") && node.callee.property.type === AST_NODE_TYPES39.Identifier && node.callee.property.name === "mock") {
7995
- context.report({
7996
- node,
7997
- messageId: "preferSetupFileMocks"
7998
- });
7999
- }
8000
- }
8001
- };
8002
- }
8003
- });
8004
-
8005
8648
  // src/index.ts
8006
8649
  var rules = {
8007
- "ban-loose-type-guards-in-tests": ban_loose_type_guards_in_tests_default,
8008
8650
  "enforce-file-structure": enforce_file_structure_default,
8009
8651
  "no-client-side-data-fetching": no_client_side_data_fetching_default,
8010
8652
  "no-comment-cruft": no_comment_cruft_default,
@@ -8049,18 +8691,17 @@ var rules = {
8049
8691
  "jsdoc-restates-signature": jsdoc_restates_signature_default,
8050
8692
  "no-restated-comment": no_restated_comment_default,
8051
8693
  "trailing-value-narration": trailing_value_narration_default,
8694
+ "no-type-member-comment-wall": no_type_member_comment_wall_default,
8052
8695
  "no-tautological-expect": no_tautological_expect_default,
8053
8696
  "require-interface-for-injected-service": require_interface_for_injected_service_default,
8054
8697
  "strict-test-assertions": strict_test_assertions_default,
8055
8698
  "prefer-non-nullable-collection": prefer_non_nullable_collection_default,
8056
- "no-implicit-attribute-access": no_implicit_attribute_access_default,
8057
- "no-async-callback-in-waitfor": no_async_callback_in_waitfor_default,
8058
- "prefer-setup-file-mocks": prefer_setup_file_mocks_default
8699
+ "no-async-callback-in-waitfor": no_async_callback_in_waitfor_default
8059
8700
  };
8060
8701
  var plugin = {
8061
8702
  meta: {
8062
8703
  name: "@sarj/eslint-plugin",
8063
- version: "4.2.0"
8704
+ version: "5.1.0"
8064
8705
  },
8065
8706
  rules,
8066
8707
  configs: {
@@ -8070,7 +8711,6 @@ var plugin = {
8070
8711
  "@sarj/zod-naming-convention": "warn",
8071
8712
  "@sarj/require-assert-never": "error",
8072
8713
  "@sarj/require-zod-form-validation": "error",
8073
- "@sarj/ban-loose-type-guards-in-tests": "error",
8074
8714
  "@sarj/enforce-file-structure": "warn",
8075
8715
  "@sarj/no-client-side-data-fetching": "warn",
8076
8716
  "@sarj/prefer-server-actions": "warn",
@@ -8141,6 +8781,14 @@ var plugin = {
8141
8781
  "@sarj/no-restated-comment": "warn",
8142
8782
  "@sarj/jsdoc-restates-signature": "warn",
8143
8783
  "@sarj/trailing-value-narration": "warn",
8784
+ // The VOLUME arm of the same family (2026-07). Its siblings judge one
8785
+ // comment at a time and can only condemn one that adds nothing; this
8786
+ // one judges a TYPE, so it can report ten rows that each add a word.
8787
+ // 33 OSS TS repos / 46,861 files: 22 findings, all read, 0 false; zero
8788
+ // across ten first-party repos, where the generated-file sniff alone
8789
+ // removed 321 of the 407 raw hits. Measurements and the six false
8790
+ // positives that shaped the guards: docs/rules/no-type-member-comment-wall.md
8791
+ "@sarj/no-type-member-comment-wall": "warn",
8144
8792
  // The TS half of SARJ057 (2026-07). Python has caught the
8145
8793
  // assertion-FREE test since 0.15.0 (SARJ043) and had no TS
8146
8794
  // counterpart, which is how `expect(true).toBe(true); // placeholder`
@@ -8155,9 +8803,7 @@ var plugin = {
8155
8803
  // port, 29 fire, 28 of them true positives.
8156
8804
  "@sarj/require-interface-for-injected-service": "warn",
8157
8805
  "@sarj/prefer-non-nullable-collection": "warn",
8158
- "@sarj/no-implicit-attribute-access": "warn",
8159
- "@sarj/no-async-callback-in-waitfor": "warn",
8160
- "@sarj/prefer-setup-file-mocks": "warn"
8806
+ "@sarj/no-async-callback-in-waitfor": "warn"
8161
8807
  }
8162
8808
  },
8163
8809
  strict: {
@@ -8166,7 +8812,6 @@ var plugin = {
8166
8812
  "@sarj/zod-naming-convention": "error",
8167
8813
  "@sarj/require-assert-never": "error",
8168
8814
  "@sarj/require-zod-form-validation": "error",
8169
- "@sarj/ban-loose-type-guards-in-tests": "error",
8170
8815
  "@sarj/enforce-file-structure": "error",
8171
8816
  "@sarj/no-raw-env": "error",
8172
8817
  "@sarj/no-enum": "error",
@@ -8234,6 +8879,7 @@ var plugin = {
8234
8879
  "@sarj/no-restated-comment": "error",
8235
8880
  "@sarj/jsdoc-restates-signature": "error",
8236
8881
  "@sarj/trailing-value-narration": "error",
8882
+ "@sarj/no-type-member-comment-wall": "error",
8237
8883
  // TS half of SARJ057 — see the `recommended` block for the measurement.
8238
8884
  "@sarj/no-tautological-expect": "error",
8239
8885
  // Substitutability: the TS sibling of the Python `prefer-real-store-in-tests`
@@ -8241,9 +8887,7 @@ var plugin = {
8241
8887
  // corpus (175 `implements` clauses vs 29 hits), so strict enforces it.
8242
8888
  "@sarj/require-interface-for-injected-service": "error",
8243
8889
  "@sarj/prefer-non-nullable-collection": "error",
8244
- "@sarj/no-implicit-attribute-access": "error",
8245
- "@sarj/no-async-callback-in-waitfor": "error",
8246
- "@sarj/prefer-setup-file-mocks": "error"
8890
+ "@sarj/no-async-callback-in-waitfor": "error"
8247
8891
  }
8248
8892
  }
8249
8893
  }