@sarj/eslint-plugin 11.0.1 → 11.2.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.cjs CHANGED
@@ -869,6 +869,7 @@ var BANNER_RUN_RE = /={4,}|-{4,}|#{4,}|\*{4,}|~{4,}|[\u2500-\u257f]{4,}/;
869
869
  var REGION_MARKER_RE = /^#?(?:end)?region\b(.*)$/i;
870
870
  var REGION_TITLE_RE = /^[\s:\-\u2013\u2014]*\w[\w \-/&+]*$/;
871
871
  var REGION_TITLE_MAX_WORDS = 5;
872
+ var REGION_PROSE_VERB_RE = /^(?:is|are|was|were|comes?|defaults?|derives?|inherits?|depends?|uses?|maps?|resolves?)\b/i;
872
873
  function stripCommentMarker(line) {
873
874
  return line.replace(/^\s*\/{1,2}/, "").replace(/^\s*\*+/, "").trim();
874
875
  }
@@ -930,7 +931,9 @@ var CALL_RE = /^[A-Za-z_$][\w.$]*\([^)]*\)\s*;?\s*$/;
930
931
  var ASSERTION_CODE_RE = /^(?:await\s+)?(?:expect(?:TypeOf)?|assert(?:\.\w+)?)\s*\(/;
931
932
  var HTTP_CONTRACT_RE = /\b(?:GET|HEAD|OPTIONS|PATCH|POST|PUT|DELETE)\s+(?:https?:\/\/|\/|\{[A-Za-z_$])/;
932
933
  var PROSE_ASSIGNMENT_RE = /^[A-Za-z_$][\w.$[\]]*\s*=\s*[A-Za-z][A-Za-z '-]{2,}\s+\((?:how|what|when|where|which|who|why)\b[^)]*\)[.!]?$/i;
933
- var PSEUDOCODE_RE = /%\w+%|\[opt\]|(?:^|\s)<[A-Za-z]\w*>|…|\.\.\./;
934
+ var PSEUDOCODE_RE = /%\w+%|\[opt\]|(?:^|\s)<[A-Za-z]\w*>|\b[A-Za-z_$][\w$]*\s+x\d+\b|…|\.\.\./;
935
+ var CALL_LABEL_RE = /^([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*)\([^;{}]*\)$/;
936
+ var MULTIPLIER_PSEUDOCODE_RE = /\b[A-Za-z_$][\w$]*\s+x\d+\b/;
934
937
  function isBanner(text) {
935
938
  const t = text.trim();
936
939
  if (!t) return false;
@@ -942,6 +945,7 @@ function isRegionMarker(text) {
942
945
  if (match === null) return false;
943
946
  const title = (match[1] ?? "").trim();
944
947
  if (title.length === 0) return true;
948
+ if (REGION_PROSE_VERB_RE.test(title)) return false;
945
949
  if (!REGION_TITLE_RE.test(title)) return false;
946
950
  return title.split(/\s+/).length <= REGION_TITLE_MAX_WORDS;
947
951
  }
@@ -957,6 +961,15 @@ function looksLikeCode(text, allowCall = true) {
957
961
  function hasPseudocode(text) {
958
962
  return PSEUDOCODE_RE.test(text);
959
963
  }
964
+ function testCallMatrixStems(comments) {
965
+ const stems = /* @__PURE__ */ new Set();
966
+ for (const comment of comments) {
967
+ const body2 = stripCommentMarker(comment.value);
968
+ const stem3 = CALL_LABEL_RE.exec(body2)?.[1];
969
+ if (stem3 !== void 0 && MULTIPLIER_PSEUDOCODE_RE.test(body2)) stems.add(stem3);
970
+ }
971
+ return stems;
972
+ }
960
973
  function isEnumeratedProseItem(text) {
961
974
  const t = text.trim();
962
975
  return ENUMERATED_ITEM_RE.test(t) && t.split(/\s+/).length >= ENUMERATED_ITEM_MIN_WORDS;
@@ -1245,6 +1258,7 @@ var no_comment_cruft_default = createRule({
1245
1258
  return {
1246
1259
  Program() {
1247
1260
  const comments = sourceCode.getAllComments();
1261
+ const callMatrixStems = isTestFile(context.filename) ? testCallMatrixStems(comments) : /* @__PURE__ */ new Set();
1248
1262
  const walls = findCommentWalls(comments);
1249
1263
  const wallByLeader = new Map(walls.map((wall) => [wall.leader, wall]));
1250
1264
  const wallMembers = new Set(walls.flatMap((wall) => [...wall.members]));
@@ -1282,6 +1296,8 @@ var no_comment_cruft_default = createRule({
1282
1296
  continue;
1283
1297
  }
1284
1298
  const firstText = texts[0];
1299
+ const firstTextStem = firstText === void 0 ? void 0 : CALL_LABEL_RE.exec(firstText)?.[1];
1300
+ if (firstTextStem !== void 0 && texts.length === 1 && callMatrixStems.has(firstTextStem)) continue;
1285
1301
  if (firstText !== void 0 && /^(?:todo|fixme)\b/i.test(firstText)) {
1286
1302
  if (!runCitesAReference(comments, i)) {
1287
1303
  context.report({
@@ -2211,6 +2227,20 @@ var PURE_METHODS = /* @__PURE__ */ new Set([
2211
2227
  "startsWith",
2212
2228
  "endsWith"
2213
2229
  ]);
2230
+ var SYNC_CALLBACK_METHODS = /* @__PURE__ */ new Set([
2231
+ "every",
2232
+ "filter",
2233
+ "findIndex",
2234
+ "findLast",
2235
+ "findLastIndex",
2236
+ "flatMap",
2237
+ "forEach",
2238
+ "map",
2239
+ "reduce",
2240
+ "reduceRight",
2241
+ "some",
2242
+ "sort"
2243
+ ]);
2214
2244
  var PURE_NAMESPACES = /* @__PURE__ */ new Set([
2215
2245
  "Object",
2216
2246
  "Array",
@@ -2260,7 +2290,17 @@ function isPureCall(node) {
2260
2290
  if (callee.object.type === import_utils13.AST_NODE_TYPES.Identifier && PURE_NAMESPACES.has(callee.object.name)) {
2261
2291
  return !IMPURE_NAMESPACE_METHODS.has(`${callee.object.name}.${property.name}`);
2262
2292
  }
2263
- return PURE_METHODS.has(property.name);
2293
+ return PURE_METHODS.has(property.name) && (!SYNC_CALLBACK_METHODS.has(property.name) || !synchronousCallbackCanThrow(node));
2294
+ }
2295
+ function synchronousCallbackCanThrow(node) {
2296
+ return node.arguments.some((argument) => {
2297
+ if (argument.type !== import_utils13.AST_NODE_TYPES.ArrowFunctionExpression && argument.type !== import_utils13.AST_NODE_TYPES.FunctionExpression) return false;
2298
+ if (argument.async) return false;
2299
+ return subtreeMatches2(
2300
+ argument.body,
2301
+ (current) => current.type === import_utils13.AST_NODE_TYPES.ThrowStatement || current.type === import_utils13.AST_NODE_TYPES.CallExpression && current.callee.type === import_utils13.AST_NODE_TYPES.MemberExpression && !current.callee.computed && current.callee.object.type === import_utils13.AST_NODE_TYPES.Identifier && current.callee.object.name === "JSON" && current.callee.property.type === import_utils13.AST_NODE_TYPES.Identifier && current.callee.property.name === "parse"
2302
+ );
2303
+ });
2264
2304
  }
2265
2305
  function isPureNew(node) {
2266
2306
  return node.callee.type === import_utils13.AST_NODE_TYPES.Identifier && PURE_CONSTRUCTORS.has(node.callee.name);
@@ -2941,6 +2981,16 @@ var PAYLOAD_PROPS = /* @__PURE__ */ new Set([
2941
2981
  "metadata",
2942
2982
  "context"
2943
2983
  ]);
2984
+ var BUILTIN_ERROR_CONSTRUCTORS = /* @__PURE__ */ new Set([
2985
+ "AggregateError",
2986
+ "Error",
2987
+ "EvalError",
2988
+ "RangeError",
2989
+ "ReferenceError",
2990
+ "SyntaxError",
2991
+ "TypeError",
2992
+ "URIError"
2993
+ ]);
2944
2994
  function isCatchBinding(scope, name) {
2945
2995
  let current = scope;
2946
2996
  while (current) {
@@ -3055,6 +3105,48 @@ function nodeWithin(node, container) {
3055
3105
  function isJsonStringify(callee) {
3056
3106
  return callee.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "JSON" && callee.property.type === "Identifier" && callee.property.name === "stringify";
3057
3107
  }
3108
+ function directLiteralValues(argument) {
3109
+ if (argument.type === "ObjectExpression") {
3110
+ return argument.properties.flatMap((property) => {
3111
+ if (property.type !== "Property" || property.computed) return [];
3112
+ const value = property.value;
3113
+ if (value.type === "AssignmentPattern" || value.type === "ArrayPattern" || value.type === "ObjectPattern" || value.type === "TSEmptyBodyFunctionExpression") {
3114
+ return [];
3115
+ }
3116
+ return [value];
3117
+ });
3118
+ }
3119
+ if (argument.type === "ArrayExpression") {
3120
+ return argument.elements.flatMap(
3121
+ (element) => element !== null && element.type !== "SpreadElement" ? [element] : []
3122
+ );
3123
+ }
3124
+ return argument.type === "SpreadElement" ? [] : [argument];
3125
+ }
3126
+ function expressionSuggestsError(expression, scope) {
3127
+ if (expression.type === "Identifier") {
3128
+ return ERROR_NAME_PATTERN.test(expression.name) || isCatchBinding(scope, expression.name);
3129
+ }
3130
+ return expression.type === "MemberExpression" && memberSuggestsError(expression, scope);
3131
+ }
3132
+ function nestedExpressionSuggestsError(expression, scope) {
3133
+ if (expression.type === "Identifier") {
3134
+ if (isCatchBinding(scope, expression.name)) return true;
3135
+ let current = scope;
3136
+ while (current !== null && !current.set.has(expression.name)) {
3137
+ current = current.upper;
3138
+ }
3139
+ const variable = current?.set.get(expression.name);
3140
+ if (variable === void 0 || variable.defs.length !== 1) return false;
3141
+ const definition = variable.defs[0];
3142
+ if (definition?.type !== "Variable") return false;
3143
+ const initializer = definition.node.init;
3144
+ return initializer?.type === "NewExpression" && initializer.callee.type === "Identifier" && BUILTIN_ERROR_CONSTRUCTORS.has(initializer.callee.name) && variable.references.every(
3145
+ (reference) => !reference.isWrite() || reference.init === true
3146
+ );
3147
+ }
3148
+ return expression.type === "MemberExpression" && memberSuggestsError(expression, scope);
3149
+ }
3058
3150
  var no_json_stringify_error_default = createRule({
3059
3151
  name: "no-json-stringify-error",
3060
3152
  meta: {
@@ -3079,18 +3171,11 @@ var no_json_stringify_error_default = createRule({
3079
3171
  return;
3080
3172
  }
3081
3173
  const scope = context.sourceCode.getScope(firstArg);
3082
- let suggestsError;
3083
- if (firstArg.type === "Identifier") {
3084
- suggestsError = ERROR_NAME_PATTERN.test(firstArg.name) || isCatchBinding(scope, firstArg.name);
3085
- } else if (firstArg.type === "MemberExpression") {
3086
- suggestsError = memberSuggestsError(firstArg, scope);
3087
- } else {
3088
- return;
3089
- }
3090
- if (!suggestsError) {
3091
- return;
3092
- }
3093
- if (isGuardedByInstanceofError(node, firstArg, context.sourceCode) || isNarrowedByEarlyReturn(node, firstArg, context.sourceCode)) {
3174
+ const isNestedLiteral = firstArg.type === "ObjectExpression" || firstArg.type === "ArrayExpression";
3175
+ const unsafeValue = directLiteralValues(firstArg).find(
3176
+ (value) => (isNestedLiteral ? nestedExpressionSuggestsError(value, scope) : expressionSuggestsError(value, scope)) && !isGuardedByInstanceofError(node, value, context.sourceCode) && !isNarrowedByEarlyReturn(node, value, context.sourceCode)
3177
+ );
3178
+ if (unsafeValue === void 0) {
3094
3179
  return;
3095
3180
  }
3096
3181
  context.report({
@@ -3477,6 +3562,8 @@ function typedFunction(node) {
3477
3562
 
3478
3563
  // src/rules/no-long-comment.ts
3479
3564
  var EXCESSIVE_SENTENCE_COUNT = 8;
3565
+ var EXCESSIVE_WORD_COUNT = 120;
3566
+ var PROSE_WORD_RE = /[\p{L}\p{N}][\p{L}\p{N}'’-]*/gu;
3480
3567
  var VERSIONED_DEPENDENCY_TREE_RE = /(?:^|\/)lib\/[^/]*-?v?\d+\.\d+(?:\.\d+)?[^/]*\//iu;
3481
3568
  function documentsTypeOrMember(sourceCode, comment) {
3482
3569
  const token = sourceCode.getTokenAfter(comment, { includeComments: false });
@@ -3488,6 +3575,9 @@ function documentsTypeOrMember(sourceCode, comment) {
3488
3575
  }
3489
3576
  return false;
3490
3577
  }
3578
+ function wordUnits(text) {
3579
+ return text.match(PROSE_WORD_RE)?.length ?? 0;
3580
+ }
3491
3581
  var no_long_comment_default = createRule({
3492
3582
  name: "no-long-comment",
3493
3583
  meta: {
@@ -3505,7 +3595,7 @@ var no_long_comment_default = createRule({
3505
3595
  return {
3506
3596
  Program() {
3507
3597
  for (const group of proseGroups(context.filename, context.sourceCode)) {
3508
- if (group.comment.type !== "Block" || !group.comment.value.startsWith("*") || group.hasTypedTags || hasDocumentationStructure(group.text) || hasTechnicalAnchor(group.text) || documentsTypedFunction(context.sourceCode, group.comment) || documentsTypeOrMember(context.sourceCode, group.comment) || sentenceUnits(group.text) < EXCESSIVE_SENTENCE_COUNT) continue;
3598
+ if (group.comment.type !== "Block" || !group.comment.value.startsWith("*") || group.hasTypedTags || hasDocumentationStructure(group.text) || hasTechnicalAnchor(group.text) || documentsTypedFunction(context.sourceCode, group.comment) || documentsTypeOrMember(context.sourceCode, group.comment) || sentenceUnits(group.text) < EXCESSIVE_SENTENCE_COUNT && wordUnits(group.text) < EXCESSIVE_WORD_COUNT) continue;
3509
3599
  context.report({ node: group.comment, messageId: "tooLong" });
3510
3600
  }
3511
3601
  }
@@ -5160,50 +5250,59 @@ var no_select_star_default = createRule({
5160
5250
 
5161
5251
  // src/rules/no-sentinel-return-on-catch.ts
5162
5252
  var import_utils33 = require("@typescript-eslint/utils");
5253
+ function unwrapSentinelExpression(arg) {
5254
+ let current = arg;
5255
+ while (current?.type === import_utils33.AST_NODE_TYPES.TSAsExpression || current?.type === import_utils33.AST_NODE_TYPES.TSTypeAssertion || current?.type === import_utils33.AST_NODE_TYPES.TSSatisfiesExpression) {
5256
+ current = current.expression;
5257
+ }
5258
+ return current;
5259
+ }
5163
5260
  function sentinelKind(arg) {
5164
- if (arg === null) {
5261
+ const value = unwrapSentinelExpression(arg);
5262
+ if (value === null) {
5165
5263
  return null;
5166
5264
  }
5167
- if (arg.type === import_utils33.AST_NODE_TYPES.Literal) {
5168
- if (arg.value === null) {
5265
+ if (value.type === import_utils33.AST_NODE_TYPES.Literal) {
5266
+ if (value.value === null) {
5169
5267
  return "nullish";
5170
5268
  }
5171
- if (typeof arg.value === "boolean") {
5269
+ if (typeof value.value === "boolean") {
5172
5270
  return "boolean";
5173
5271
  }
5174
- if (typeof arg.value === "string") {
5272
+ if (typeof value.value === "string") {
5175
5273
  return "string";
5176
5274
  }
5177
5275
  return null;
5178
5276
  }
5179
- if (arg.type === import_utils33.AST_NODE_TYPES.Identifier && arg.name === "undefined") {
5277
+ if (value.type === import_utils33.AST_NODE_TYPES.Identifier && value.name === "undefined") {
5180
5278
  return "nullish";
5181
5279
  }
5182
- if (arg.type === import_utils33.AST_NODE_TYPES.ArrayExpression) {
5280
+ if (value.type === import_utils33.AST_NODE_TYPES.ArrayExpression) {
5183
5281
  return "array";
5184
5282
  }
5185
- if (arg.type === import_utils33.AST_NODE_TYPES.ObjectExpression) {
5283
+ if (value.type === import_utils33.AST_NODE_TYPES.ObjectExpression) {
5186
5284
  return "object";
5187
5285
  }
5188
5286
  return null;
5189
5287
  }
5190
5288
  function isSentinelArgument(arg) {
5191
- if (arg === null) {
5289
+ const value = unwrapSentinelExpression(arg);
5290
+ if (value === null) {
5192
5291
  return false;
5193
5292
  }
5194
- if (arg.type === import_utils33.AST_NODE_TYPES.Literal && arg.value === null) {
5293
+ if (value.type === import_utils33.AST_NODE_TYPES.Literal && value.value === null) {
5195
5294
  return true;
5196
5295
  }
5197
- if (arg.type === import_utils33.AST_NODE_TYPES.Literal && arg.value === false) {
5296
+ if (value.type === import_utils33.AST_NODE_TYPES.Literal && value.value === false) {
5198
5297
  return true;
5199
5298
  }
5200
- if (arg.type === import_utils33.AST_NODE_TYPES.Identifier && arg.name === "undefined") {
5299
+ if (value.type === import_utils33.AST_NODE_TYPES.Identifier && value.name === "undefined") {
5201
5300
  return true;
5202
5301
  }
5203
- if (arg.type === import_utils33.AST_NODE_TYPES.ArrayExpression && arg.elements.length === 0) {
5302
+ if (value.type === import_utils33.AST_NODE_TYPES.ArrayExpression && value.elements.length === 0) {
5204
5303
  return true;
5205
5304
  }
5206
- if (arg.type === import_utils33.AST_NODE_TYPES.ObjectExpression && arg.properties.length === 0) {
5305
+ if (value.type === import_utils33.AST_NODE_TYPES.ObjectExpression && value.properties.length === 0) {
5207
5306
  return true;
5208
5307
  }
5209
5308
  return false;
@@ -5401,6 +5500,16 @@ function tryReturnsSafeParse(catchNode) {
5401
5500
  const only = tryBlock.body.length === 1 ? tryBlock.body[0] : void 0;
5402
5501
  return only !== void 0 && returnsMatching(only, isBodyDecodeNode);
5403
5502
  }
5503
+ function isIntentionalStackCapture(catchNode, caughtName) {
5504
+ if (caughtName === null) return false;
5505
+ const tryBody = tryBlockOf(catchNode).body;
5506
+ const only = tryBody.length === 1 ? tryBody[0] : void 0;
5507
+ if (only?.type !== import_utils33.AST_NODE_TYPES.ThrowStatement) return false;
5508
+ const thrown = unwrapSentinelExpression(only.argument);
5509
+ const constructsError = (thrown?.type === import_utils33.AST_NODE_TYPES.CallExpression || thrown?.type === import_utils33.AST_NODE_TYPES.NewExpression) && thrown.callee.type === import_utils33.AST_NODE_TYPES.Identifier && thrown.callee.name === "Error";
5510
+ if (!constructsError) return false;
5511
+ return catchNode.body.body.slice(0, -1).some((statement) => subtreeReadsName(statement, caughtName));
5512
+ }
5404
5513
  function tryBlockOf(catchNode) {
5405
5514
  return catchNode.parent.block;
5406
5515
  }
@@ -5521,6 +5630,9 @@ var no_sentinel_return_on_catch_default = createRule({
5521
5630
  if (tryReturnsSafeParse(node)) {
5522
5631
  return;
5523
5632
  }
5633
+ if (isIntentionalStackCapture(node, caughtName)) {
5634
+ return;
5635
+ }
5524
5636
  const kind = sentinelKind(last.argument);
5525
5637
  if (kind !== null && isNamedBooleanPredicate(node, kind)) {
5526
5638
  return;
@@ -5599,11 +5711,11 @@ var no_silent_promise_catch_default = createRule({
5599
5711
  meta: {
5600
5712
  type: "problem",
5601
5713
  docs: {
5602
- description: "Disallow `.catch()` handlers that silently swallow the rejection (e.g. `.catch(() => null)`); log, rethrow, or handle the error."
5714
+ description: "Disallow `.catch()` and second-argument `.then()` handlers that silently swallow a rejection; log, rethrow, or handle the error."
5603
5715
  },
5604
5716
  schema: [],
5605
5717
  messages: {
5606
- silentCatch: "This `.catch()` swallows the rejection without logging, rethrowing, or handling it \u2014 failures become invisible and callers get an indistinguishable sentinel. Log the error (and only then map to a fallback), or let it propagate."
5718
+ silentCatch: "This rejection handler swallows the error without logging, rethrowing, or handling it \u2014 failures become invisible and callers get an indistinguishable sentinel. Log the error (and only then map to a fallback), or let it propagate."
5607
5719
  }
5608
5720
  },
5609
5721
  defaultOptions: [],
@@ -5629,9 +5741,12 @@ var no_silent_promise_catch_default = createRule({
5629
5741
  };
5630
5742
  return {
5631
5743
  CallExpression(node) {
5632
- if (node.callee.type !== import_utils34.AST_NODE_TYPES.MemberExpression || node.callee.computed || node.callee.property.type !== import_utils34.AST_NODE_TYPES.Identifier || node.callee.property.name !== "catch") {
5744
+ if (node.callee.type !== import_utils34.AST_NODE_TYPES.MemberExpression || node.callee.computed || node.callee.property.type !== import_utils34.AST_NODE_TYPES.Identifier) {
5633
5745
  return;
5634
5746
  }
5747
+ const method = node.callee.property.name;
5748
+ const handlerIndex = method === "catch" ? 0 : method === "then" ? 1 : null;
5749
+ if (handlerIndex === null) return;
5635
5750
  if (isBodyParseCall(node.callee.object)) {
5636
5751
  return;
5637
5752
  }
@@ -5641,10 +5756,11 @@ var no_silent_promise_catch_default = createRule({
5641
5756
  if (node.parent.type === import_utils34.AST_NODE_TYPES.MemberExpression && node.parent.object === node) {
5642
5757
  return;
5643
5758
  }
5644
- if (node.arguments.length !== 1) {
5759
+ const expectedArguments = method === "catch" ? 1 : 2;
5760
+ if (node.arguments.length !== expectedArguments) {
5645
5761
  return;
5646
5762
  }
5647
- const handler = node.arguments[0];
5763
+ const handler = node.arguments[handlerIndex];
5648
5764
  if (handler === void 0 || handler.type !== import_utils34.AST_NODE_TYPES.ArrowFunctionExpression && handler.type !== import_utils34.AST_NODE_TYPES.FunctionExpression) {
5649
5765
  return;
5650
5766
  }
@@ -5907,6 +6023,11 @@ function isStringLiteralInit(node) {
5907
6023
  return false;
5908
6024
  }
5909
6025
  function isConcatOntoTarget(rhs, target) {
6026
+ if (rhs.type === "TemplateLiteral") {
6027
+ return rhs.expressions.some(
6028
+ (expression) => expression.type === "Identifier" && expression.name === target
6029
+ );
6030
+ }
5910
6031
  if (rhs.type !== "BinaryExpression" || rhs.operator !== "+") {
5911
6032
  return false;
5912
6033
  }
@@ -7459,6 +7580,15 @@ var SUCCESS_PAYLOAD_MEMBER_NAMES = /* @__PURE__ */ new Set([
7459
7580
  "value"
7460
7581
  ]);
7461
7582
  var REQUIRED_STATUS_MEMBER_COUNT = 1;
7583
+ var FUNCTION_RETURN_OWNER_TYPES = /* @__PURE__ */ new Set([
7584
+ import_utils51.AST_NODE_TYPES.ArrowFunctionExpression,
7585
+ import_utils51.AST_NODE_TYPES.FunctionDeclaration,
7586
+ import_utils51.AST_NODE_TYPES.FunctionExpression,
7587
+ import_utils51.AST_NODE_TYPES.TSDeclareFunction,
7588
+ import_utils51.AST_NODE_TYPES.TSEmptyBodyFunctionExpression,
7589
+ import_utils51.AST_NODE_TYPES.TSFunctionType,
7590
+ import_utils51.AST_NODE_TYPES.TSMethodSignature
7591
+ ]);
7462
7592
  function looksLikeMutuallyExclusiveState(typeLiteral) {
7463
7593
  let statusMemberCount = 0;
7464
7594
  let hasFailurePayload = false;
@@ -7499,6 +7629,17 @@ function getMemberName(member) {
7499
7629
  function isBooleanTyped(member) {
7500
7630
  return member.typeAnnotation?.typeAnnotation.type === import_utils51.AST_NODE_TYPES.TSBooleanKeyword;
7501
7631
  }
7632
+ function inlineReturnTypeLiteral(node) {
7633
+ let annotation = null;
7634
+ if (node.parent.type === import_utils51.AST_NODE_TYPES.TSTypeAnnotation) {
7635
+ annotation = node.parent;
7636
+ } else if (node.parent.type === import_utils51.AST_NODE_TYPES.TSTypeParameterInstantiation && node.parent.params.length === 1 && node.parent.params[0] === node && node.parent.parent.type === import_utils51.AST_NODE_TYPES.TSTypeReference && node.parent.parent.typeName.type === import_utils51.AST_NODE_TYPES.Identifier && node.parent.parent.typeName.name === "Promise" && node.parent.parent.parent.type === import_utils51.AST_NODE_TYPES.TSTypeAnnotation) {
7637
+ annotation = node.parent.parent.parent;
7638
+ }
7639
+ if (annotation === null) return null;
7640
+ const owner = annotation.parent;
7641
+ return FUNCTION_RETURN_OWNER_TYPES.has(owner.type) && "returnType" in owner && owner.returnType === annotation ? annotation : null;
7642
+ }
7502
7643
  var prefer_discriminated_union_default = createRule({
7503
7644
  name: "prefer-discriminated-union",
7504
7645
  meta: {
@@ -7538,6 +7679,10 @@ var prefer_discriminated_union_default = createRule({
7538
7679
  },
7539
7680
  "TSTypeAliasDeclaration > TSTypeLiteral"(node) {
7540
7681
  checkTypeLiteral(node, node.parent);
7682
+ },
7683
+ TSTypeLiteral(node) {
7684
+ const annotation = inlineReturnTypeLiteral(node);
7685
+ if (annotation !== null) checkTypeLiteral(node, annotation);
7541
7686
  }
7542
7687
  };
7543
7688
  }
@@ -8454,6 +8599,11 @@ var prefer_module_level_schema_default = createRule({
8454
8599
  type: "boolean",
8455
8600
  description: "Skip test files, where a fixture schema belongs next to its assertion."
8456
8601
  },
8602
+ memoCallees: {
8603
+ type: "array",
8604
+ items: { type: "string" },
8605
+ description: "Wrappers that construct their callback at most once. Defaults to lazy, memo, once, and useMemo."
8606
+ },
8457
8607
  minProperties: {
8458
8608
  type: "number",
8459
8609
  minimum: 0,
@@ -8471,6 +8621,7 @@ var prefer_module_level_schema_default = createRule({
8471
8621
  create(context, [options]) {
8472
8622
  const factories = new Set(options?.factories ?? DEFAULT_FACTORIES);
8473
8623
  const ignoreTestFiles = options?.ignoreTestFiles ?? true;
8624
+ const memoCallees = new Set(options?.memoCallees ?? MEMO_CALLEES);
8474
8625
  const minProperties = options?.minProperties ?? DEFAULT_MIN_PROPERTIES;
8475
8626
  const sourceCode = context.sourceCode;
8476
8627
  const filename = context.filename;
@@ -8490,7 +8641,7 @@ var prefer_module_level_schema_default = createRule({
8490
8641
  if (current !== node && isZodCall(current) && current.callee.type === import_utils56.AST_NODE_TYPES.MemberExpression && current.callee.property.type === import_utils56.AST_NODE_TYPES.Identifier && factories.has(current.callee.property.name)) {
8491
8642
  return true;
8492
8643
  }
8493
- if (current.type === import_utils56.AST_NODE_TYPES.CallExpression && (current.callee.type === import_utils56.AST_NODE_TYPES.Identifier && MEMO_CALLEES.has(current.callee.name) || current.callee.type === import_utils56.AST_NODE_TYPES.MemberExpression && !current.callee.computed && current.callee.property.type === import_utils56.AST_NODE_TYPES.Identifier && MEMO_CALLEES.has(current.callee.property.name))) {
8644
+ if (current.type === import_utils56.AST_NODE_TYPES.CallExpression && (current.callee.type === import_utils56.AST_NODE_TYPES.Identifier && memoCallees.has(current.callee.name) || current.callee.type === import_utils56.AST_NODE_TYPES.MemberExpression && !current.callee.computed && current.callee.property.type === import_utils56.AST_NODE_TYPES.Identifier && memoCallees.has(current.callee.property.name))) {
8494
8645
  return true;
8495
8646
  }
8496
8647
  current = current.parent ?? void 0;
@@ -8540,6 +8691,9 @@ var prefer_module_level_schema_default = createRule({
8540
8691
  if (definition.type === "ImportBinding") {
8541
8692
  continue;
8542
8693
  }
8694
+ if (definition.node.type === import_utils56.AST_NODE_TYPES.VariableDeclarator && definition.node.parent.type === import_utils56.AST_NODE_TYPES.VariableDeclaration && definition.node.parent.kind !== "const") {
8695
+ return false;
8696
+ }
8543
8697
  const [defStart, defEnd] = definition.node.range;
8544
8698
  if (defStart >= schemaStart && defEnd <= schemaEnd) {
8545
8699
  continue;
@@ -8774,7 +8928,7 @@ function sameAccess(node, access) {
8774
8928
  return node.type === import_utils58.AST_NODE_TYPES.MemberExpression && !node.computed && node.object.type === import_utils58.AST_NODE_TYPES.Identifier && node.object.name === access.object && node.property.type === import_utils58.AST_NODE_TYPES.Identifier && node.property.name === access.property;
8775
8929
  }
8776
8930
  function isNullGuard(node, access) {
8777
- if (node.type === import_utils58.AST_NODE_TYPES.UnaryExpression && node.operator === "!" && sameAccess(node.argument, access)) return true;
8931
+ if (node.type === import_utils58.AST_NODE_TYPES.UnaryExpression && node.operator === "!" && (sameAccess(node.argument, access) || optionalMemberLengthOf(node.argument, access))) return true;
8778
8932
  if (node.type !== import_utils58.AST_NODE_TYPES.BinaryExpression || !["==", "==="].includes(node.operator)) {
8779
8933
  return false;
8780
8934
  }
@@ -8790,7 +8944,11 @@ function isEmptyGuard(node, access) {
8790
8944
  return memberLengthOf(node.left, access) && zero(node.right) || memberLengthOf(node.right, access) && zero(node.left);
8791
8945
  }
8792
8946
  function memberLengthOf(node, access) {
8793
- return node.type === import_utils58.AST_NODE_TYPES.MemberExpression && !node.computed && node.property.type === import_utils58.AST_NODE_TYPES.Identifier && node.property.name === "length" && sameAccess(node.object, access);
8947
+ const target = node.type === import_utils58.AST_NODE_TYPES.ChainExpression ? node.expression : node;
8948
+ return target.type === import_utils58.AST_NODE_TYPES.MemberExpression && !target.computed && target.property.type === import_utils58.AST_NODE_TYPES.Identifier && target.property.name === "length" && sameAccess(target.object, access);
8949
+ }
8950
+ function optionalMemberLengthOf(node, access) {
8951
+ return node.type === import_utils58.AST_NODE_TYPES.ChainExpression && node.expression.type === import_utils58.AST_NODE_TYPES.MemberExpression && node.expression.optional && memberLengthOf(node, access);
8794
8952
  }
8795
8953
  function hasEquivalentLeadingGuard(fn, access, visitorKeys) {
8796
8954
  if (fn.body.type !== import_utils58.AST_NODE_TYPES.BlockStatement) return false;
@@ -8798,6 +8956,7 @@ function hasEquivalentLeadingGuard(fn, access, visitorKeys) {
8798
8956
  if (first?.type !== import_utils58.AST_NODE_TYPES.IfStatement) return false;
8799
8957
  const terminating = first.consequent.type === import_utils58.AST_NODE_TYPES.ReturnStatement || first.consequent.type === import_utils58.AST_NODE_TYPES.ThrowStatement || first.consequent.type === import_utils58.AST_NODE_TYPES.BlockStatement && first.consequent.body.length === 1 && (first.consequent.body[0]?.type === import_utils58.AST_NODE_TYPES.ReturnStatement || first.consequent.body[0]?.type === import_utils58.AST_NODE_TYPES.ThrowStatement);
8800
8958
  if (!terminating) return false;
8959
+ if (contains(first.consequent, visitorKeys, (node) => sameAccess(node, access))) return false;
8801
8960
  return contains(first.test, visitorKeys, (node) => isNullGuard(node, access)) && contains(first.test, visitorKeys, (node) => isEmptyGuard(node, access));
8802
8961
  }
8803
8962
  function contains(node, visitorKeys, predicate) {
@@ -8960,7 +9119,7 @@ var isSchemaParseReference = (node) => {
8960
9119
  const inner = unwrap4(node);
8961
9120
  return inner !== null && inner.type === import_utils59.AST_NODE_TYPES.MemberExpression && !inner.computed && inner.property.type === import_utils59.AST_NODE_TYPES.Identifier && (inner.property.name === "parse" || inner.property.name === "safeParse");
8962
9121
  };
8963
- var isRawPayloadSource = (node) => {
9122
+ var isRawPayloadSource = (node, isKnownLocalText) => {
8964
9123
  let current = unwrap4(node);
8965
9124
  if (current === null) return false;
8966
9125
  if (current.type === import_utils59.AST_NODE_TYPES.AwaitExpression) {
@@ -8984,20 +9143,26 @@ var isRawPayloadSource = (node) => {
8984
9143
  return !current.arguments.some(isSchemaParseReference) && isRawPayloadSource(callee.object);
8985
9144
  }
8986
9145
  const object = unwrap4(callee.object);
8987
- return property.name === "parse" && object !== null && object.type === import_utils59.AST_NODE_TYPES.Identifier && object.name === "JSON" && !isLocalFileRead(current.arguments[0]);
9146
+ return property.name === "parse" && object !== null && object.type === import_utils59.AST_NODE_TYPES.Identifier && object.name === "JSON" && !isLocalFileRead(current.arguments[0]) && isKnownLocalText?.(current.arguments[0]) !== true;
8988
9147
  };
8989
9148
  var FILE_READ_RE = /^(readFile|readFileSync|readJson|readJsonSync|readJSON)$/;
9149
+ var isDirectLocalFileRead = (node) => {
9150
+ let current = unwrap4(node);
9151
+ if (current?.type === import_utils59.AST_NODE_TYPES.AwaitExpression) {
9152
+ current = unwrap4(current.argument);
9153
+ }
9154
+ if (current?.type !== import_utils59.AST_NODE_TYPES.CallExpression) return false;
9155
+ const callee = unwrap4(current.callee);
9156
+ const name = callee?.type === import_utils59.AST_NODE_TYPES.Identifier ? callee.name : callee?.type === import_utils59.AST_NODE_TYPES.MemberExpression && !callee.computed && callee.property.type === import_utils59.AST_NODE_TYPES.Identifier ? callee.property.name : null;
9157
+ return name !== null && FILE_READ_RE.test(name);
9158
+ };
8990
9159
  var isLocalFileRead = (node) => {
8991
9160
  let found = false;
8992
9161
  const visit = (current) => {
8993
9162
  if (found || current === null || current === void 0) return;
8994
- if (current.type === import_utils59.AST_NODE_TYPES.CallExpression) {
8995
- const callee = unwrap4(current.callee);
8996
- const name = callee?.type === import_utils59.AST_NODE_TYPES.Identifier ? callee.name : callee?.type === import_utils59.AST_NODE_TYPES.MemberExpression && !callee.computed && callee.property.type === import_utils59.AST_NODE_TYPES.Identifier ? callee.property.name : null;
8997
- if (name !== null && FILE_READ_RE.test(name)) {
8998
- found = true;
8999
- return;
9000
- }
9163
+ if (isDirectLocalFileRead(current)) {
9164
+ found = true;
9165
+ return;
9001
9166
  }
9002
9167
  for (const key of Object.keys(current)) {
9003
9168
  if (key === "parent") continue;
@@ -9059,6 +9224,87 @@ var isValidationRead = (node) => {
9059
9224
  }
9060
9225
  return callee.type === import_utils59.AST_NODE_TYPES.Identifier && GUARD_NAME_RE.test(callee.name);
9061
9226
  };
9227
+ var PRIMITIVE_TYPEOF_RESULTS = /* @__PURE__ */ new Set([
9228
+ "bigint",
9229
+ "boolean",
9230
+ "number",
9231
+ "string",
9232
+ "symbol",
9233
+ "undefined"
9234
+ ]);
9235
+ var bindingValidationPolarity = (test, bindingName) => {
9236
+ if (test.type === import_utils59.AST_NODE_TYPES.UnaryExpression && test.operator === "!") {
9237
+ const inner = bindingValidationPolarity(test.argument, bindingName);
9238
+ return inner === "valid-when-true" ? "valid-when-false" : inner === "valid-when-false" ? "valid-when-true" : null;
9239
+ }
9240
+ if (test.type === import_utils59.AST_NODE_TYPES.BinaryExpression) {
9241
+ const typeofName = (node) => node.type === import_utils59.AST_NODE_TYPES.UnaryExpression && node.operator === "typeof" && node.argument.type === import_utils59.AST_NODE_TYPES.Identifier ? node.argument.name : null;
9242
+ const literalType = (node) => node.type === import_utils59.AST_NODE_TYPES.Literal && typeof node.value === "string" && PRIMITIVE_TYPEOF_RESULTS.has(node.value) ? node.value : null;
9243
+ const matches = typeofName(test.left) === bindingName && literalType(test.right) !== null || typeofName(test.right) === bindingName && literalType(test.left) !== null;
9244
+ if (!matches) return null;
9245
+ if (test.operator === "===" || test.operator === "==") {
9246
+ return "valid-when-true";
9247
+ }
9248
+ return test.operator === "!==" || test.operator === "!=" ? "valid-when-false" : null;
9249
+ }
9250
+ return test.type === import_utils59.AST_NODE_TYPES.CallExpression && test.arguments.length === 1 && test.arguments[0]?.type === import_utils59.AST_NODE_TYPES.Identifier && test.arguments[0].name === bindingName && test.callee.type === import_utils59.AST_NODE_TYPES.MemberExpression && !test.callee.computed && test.callee.object.type === import_utils59.AST_NODE_TYPES.Identifier && test.callee.object.name === "Array" && test.callee.property.type === import_utils59.AST_NODE_TYPES.Identifier && test.callee.property.name === "isArray" ? "valid-when-true" : null;
9251
+ };
9252
+ var nodeWithin2 = (node, container) => node.range[0] >= container.range[0] && node.range[1] <= container.range[1];
9253
+ var isFullyValidatedExtractedBinding = (member, source, context) => {
9254
+ const isValidationReference = (identifier) => {
9255
+ for (let current = identifier.parent; current !== void 0 && current !== null; current = current.parent) {
9256
+ if ((current.type === import_utils59.AST_NODE_TYPES.BinaryExpression || current.type === import_utils59.AST_NODE_TYPES.CallExpression || current.type === import_utils59.AST_NODE_TYPES.UnaryExpression) && bindingValidationPolarity(current, identifier.name) !== null) {
9257
+ return true;
9258
+ }
9259
+ if (current.type !== import_utils59.AST_NODE_TYPES.UnaryExpression && current.type !== import_utils59.AST_NODE_TYPES.MemberExpression && current.type !== import_utils59.AST_NODE_TYPES.CallExpression) {
9260
+ return false;
9261
+ }
9262
+ }
9263
+ return false;
9264
+ };
9265
+ const isGuardedUse = (identifier) => {
9266
+ for (let current = identifier.parent; current !== void 0 && current !== null; current = current.parent) {
9267
+ if (current.type === import_utils59.AST_NODE_TYPES.ConditionalExpression) {
9268
+ const polarity = bindingValidationPolarity(current.test, identifier.name);
9269
+ if (polarity === "valid-when-true" && nodeWithin2(identifier, current.consequent)) {
9270
+ return true;
9271
+ }
9272
+ if (polarity === "valid-when-false" && nodeWithin2(identifier, current.alternate)) {
9273
+ return true;
9274
+ }
9275
+ }
9276
+ if (current.type === import_utils59.AST_NODE_TYPES.IfStatement) {
9277
+ const polarity = bindingValidationPolarity(current.test, identifier.name);
9278
+ if (polarity === "valid-when-true" && nodeWithin2(identifier, current.consequent)) {
9279
+ return true;
9280
+ }
9281
+ if (polarity === "valid-when-false" && current.alternate !== null && nodeWithin2(identifier, current.alternate)) {
9282
+ return true;
9283
+ }
9284
+ }
9285
+ if (current.type === import_utils59.AST_NODE_TYPES.FunctionDeclaration || current.type === import_utils59.AST_NODE_TYPES.FunctionExpression || current.type === import_utils59.AST_NODE_TYPES.ArrowFunctionExpression) {
9286
+ return false;
9287
+ }
9288
+ }
9289
+ return false;
9290
+ };
9291
+ const declarator = member.parent;
9292
+ if (declarator.type !== import_utils59.AST_NODE_TYPES.VariableDeclarator || declarator.init !== member || declarator.id.type !== import_utils59.AST_NODE_TYPES.Identifier || declarator.parent.type !== import_utils59.AST_NODE_TYPES.VariableDeclaration || declarator.parent.kind !== "const") {
9293
+ return false;
9294
+ }
9295
+ const extracted = context.sourceCode.getDeclaredVariables(declarator)[0];
9296
+ if (extracted === void 0 || extracted.scope !== source.scope) return false;
9297
+ let hasValueUse = false;
9298
+ for (const reference of extracted.references) {
9299
+ const identifier = reference.identifier;
9300
+ if (identifier.type !== import_utils59.AST_NODE_TYPES.Identifier) return false;
9301
+ if (nodeWithin2(identifier, declarator)) continue;
9302
+ if (isValidationReference(identifier)) continue;
9303
+ hasValueUse = true;
9304
+ if (!isGuardedUse(identifier)) return false;
9305
+ }
9306
+ return hasValueUse;
9307
+ };
9062
9308
  var isGuardTestPosition = (node) => {
9063
9309
  let current = node;
9064
9310
  let parent = current.parent;
@@ -9082,13 +9328,13 @@ var isGuardTestPosition = (node) => {
9082
9328
  }
9083
9329
  return false;
9084
9330
  };
9085
- var isUnvalidatedVariableRef = (node, scope, tracked) => {
9331
+ var unvalidatedVariableRef = (node, scope, tracked) => {
9086
9332
  const unwrapped = unwrap4(node);
9087
9333
  if (unwrapped === null || unwrapped.type !== import_utils59.AST_NODE_TYPES.Identifier) {
9088
- return false;
9334
+ return null;
9089
9335
  }
9090
9336
  const variable = findVariable2(scope, unwrapped.name);
9091
- return variable !== null && tracked.has(variable);
9337
+ return variable !== null && tracked.has(variable) ? variable : null;
9092
9338
  };
9093
9339
  var prefer_schema_for_api_payload_default = createRule({
9094
9340
  name: "prefer-schema-for-api-payload",
@@ -9108,6 +9354,56 @@ var prefer_schema_for_api_payload_default = createRule({
9108
9354
  return {};
9109
9355
  }
9110
9356
  const unvalidatedVariables = /* @__PURE__ */ new Set();
9357
+ const aliasGroups = /* @__PURE__ */ new Map();
9358
+ const localFileTextVariables = /* @__PURE__ */ new Set();
9359
+ const localFileTextRef = (node, scope) => {
9360
+ const unwrapped = unwrap4(node);
9361
+ if (unwrapped?.type !== import_utils59.AST_NODE_TYPES.Identifier) return null;
9362
+ const variable = findVariable2(scope, unwrapped.name);
9363
+ return variable !== null && localFileTextVariables.has(variable) ? variable : null;
9364
+ };
9365
+ const updateLocalFileText = (target, value, scope) => {
9366
+ const source = localFileTextRef(value, scope);
9367
+ if (isDirectLocalFileRead(value) || source !== null && source.scope === target.scope) {
9368
+ localFileTextVariables.add(target);
9369
+ } else {
9370
+ localFileTextVariables.delete(target);
9371
+ }
9372
+ };
9373
+ const clearBinding = (variable) => {
9374
+ unvalidatedVariables.delete(variable);
9375
+ const group = aliasGroups.get(variable);
9376
+ aliasGroups.delete(variable);
9377
+ group?.delete(variable);
9378
+ };
9379
+ const clearAliasGroup = (variable) => {
9380
+ const group = aliasGroups.get(variable);
9381
+ if (group === void 0) {
9382
+ unvalidatedVariables.delete(variable);
9383
+ return;
9384
+ }
9385
+ for (const alias of group) {
9386
+ unvalidatedVariables.delete(alias);
9387
+ aliasGroups.delete(alias);
9388
+ }
9389
+ group.clear();
9390
+ };
9391
+ const trackRawBinding = (variable) => {
9392
+ clearBinding(variable);
9393
+ const group = /* @__PURE__ */ new Set([variable]);
9394
+ unvalidatedVariables.add(variable);
9395
+ aliasGroups.set(variable, group);
9396
+ };
9397
+ const trackAlias = (target, source) => {
9398
+ if (target === source) return;
9399
+ const group = aliasGroups.get(source) ?? /* @__PURE__ */ new Set([source]);
9400
+ if (aliasGroups.get(target) === group) return;
9401
+ clearBinding(target);
9402
+ unvalidatedVariables.add(target);
9403
+ group.add(target);
9404
+ aliasGroups.set(source, group);
9405
+ aliasGroups.set(target, group);
9406
+ };
9111
9407
  const isFullyNarrowedPattern = (declarator) => {
9112
9408
  const declared = context.sourceCode.getDeclaredVariables(declarator);
9113
9409
  return declared.length > 0 && declared.every(
@@ -9116,29 +9412,40 @@ var prefer_schema_for_api_payload_default = createRule({
9116
9412
  )
9117
9413
  );
9118
9414
  };
9119
- const trackInitializer = (declarator) => {
9120
- if (!isRawPayloadSource(declarator.init)) return;
9415
+ const trackInitializer = (declarator, scope) => {
9121
9416
  const declaredVars = context.sourceCode.getDeclaredVariables(declarator);
9122
9417
  const variable = declaredVars[0];
9123
- if (variable !== void 0) {
9124
- unvalidatedVariables.add(variable);
9418
+ if (variable === void 0) return;
9419
+ const localText = (candidate) => localFileTextRef(candidate, scope) !== null;
9420
+ if (isRawPayloadSource(declarator.init, localText)) {
9421
+ trackRawBinding(variable);
9422
+ return;
9125
9423
  }
9424
+ const source = unvalidatedVariableRef(declarator.init, scope, unvalidatedVariables);
9425
+ if (source !== null) trackAlias(variable, source);
9126
9426
  };
9127
9427
  return {
9128
9428
  VariableDeclarator(node) {
9129
9429
  const scope = context.sourceCode.getScope(node);
9130
9430
  if (node.id.type === import_utils59.AST_NODE_TYPES.Identifier) {
9131
- trackInitializer(node);
9431
+ const variable = context.sourceCode.getDeclaredVariables(node)[0];
9432
+ if (variable !== void 0) {
9433
+ updateLocalFileText(variable, node.init, scope);
9434
+ }
9435
+ trackInitializer(node, scope);
9132
9436
  return;
9133
9437
  }
9134
9438
  if (node.id.type === import_utils59.AST_NODE_TYPES.ObjectPattern || node.id.type === import_utils59.AST_NODE_TYPES.ArrayPattern) {
9135
- if (isRawPayloadSource(node.init)) {
9439
+ if (isRawPayloadSource(
9440
+ node.init,
9441
+ (candidate) => localFileTextRef(candidate, scope) !== null
9442
+ )) {
9136
9443
  if (!isFullyNarrowedPattern(node)) {
9137
9444
  context.report({ node: node.id, messageId: "unparsedJsonAccess" });
9138
9445
  }
9139
9446
  return;
9140
9447
  }
9141
- if (isUnvalidatedVariableRef(node.init, scope, unvalidatedVariables)) {
9448
+ if (unvalidatedVariableRef(node.init, scope, unvalidatedVariables) !== null) {
9142
9449
  context.report({ node: node.id, messageId: "unparsedJsonAccess" });
9143
9450
  }
9144
9451
  }
@@ -9148,22 +9455,29 @@ var prefer_schema_for_api_payload_default = createRule({
9148
9455
  if (node.left.type === import_utils59.AST_NODE_TYPES.Identifier) {
9149
9456
  const variable = findVariable2(scope, node.left.name);
9150
9457
  if (variable === null) return;
9151
- if (isRawPayloadSource(node.right)) {
9152
- unvalidatedVariables.add(variable);
9458
+ const isLocalText = (candidate) => localFileTextRef(candidate, scope) !== null;
9459
+ updateLocalFileText(variable, node.right, scope);
9460
+ if (isRawPayloadSource(node.right, isLocalText)) {
9461
+ trackRawBinding(variable);
9153
9462
  } else {
9154
- unvalidatedVariables.delete(variable);
9463
+ const source = unvalidatedVariableRef(node.right, scope, unvalidatedVariables);
9464
+ if (source === null) clearBinding(variable);
9465
+ else trackAlias(variable, source);
9155
9466
  }
9156
9467
  return;
9157
9468
  }
9158
9469
  if (node.left.type === import_utils59.AST_NODE_TYPES.ObjectPattern || node.left.type === import_utils59.AST_NODE_TYPES.ArrayPattern) {
9159
- if (isRawPayloadSource(node.right)) {
9470
+ if (isRawPayloadSource(
9471
+ node.right,
9472
+ (candidate) => localFileTextRef(candidate, scope) !== null
9473
+ )) {
9160
9474
  context.report({
9161
9475
  node: node.left,
9162
9476
  messageId: "unparsedJsonAccess"
9163
9477
  });
9164
9478
  return;
9165
9479
  }
9166
- if (isUnvalidatedVariableRef(node.right, scope, unvalidatedVariables)) {
9480
+ if (unvalidatedVariableRef(node.right, scope, unvalidatedVariables) !== null) {
9167
9481
  context.report({
9168
9482
  node: node.left,
9169
9483
  messageId: "unparsedJsonAccess"
@@ -9184,7 +9498,7 @@ var prefer_schema_for_api_payload_default = createRule({
9184
9498
  continue;
9185
9499
  }
9186
9500
  const variable = findVariable2(scope, unwrapped.name);
9187
- if (variable !== null) unvalidatedVariables.delete(variable);
9501
+ if (variable !== null) clearAliasGroup(variable);
9188
9502
  }
9189
9503
  },
9190
9504
  MemberExpression(node) {
@@ -9192,7 +9506,10 @@ var prefer_schema_for_api_payload_default = createRule({
9192
9506
  if (isValidationRead(node)) return;
9193
9507
  const scope = context.sourceCode.getScope(node);
9194
9508
  const obj = unwrap4(node.object);
9195
- if (isRawPayloadSource(obj)) {
9509
+ if (isRawPayloadSource(
9510
+ obj,
9511
+ (candidate) => localFileTextRef(candidate, scope) !== null
9512
+ )) {
9196
9513
  const parent = node.parent;
9197
9514
  if (parent.type === import_utils59.AST_NODE_TYPES.CallExpression && parent.callee === node && node.property.type === import_utils59.AST_NODE_TYPES.Identifier && (node.property.name === "parse" || node.property.name === "safeParse" || PROMISE_CHAIN_METHODS.has(node.property.name))) {
9198
9515
  return;
@@ -9200,12 +9517,13 @@ var prefer_schema_for_api_payload_default = createRule({
9200
9517
  context.report({ node, messageId: "unparsedJsonAccess" });
9201
9518
  return;
9202
9519
  }
9203
- if (obj !== null && obj.type === import_utils59.AST_NODE_TYPES.Identifier && isUnvalidatedVariableRef(obj, scope, unvalidatedVariables)) {
9204
- context.report({ node, messageId: "unparsedJsonAccess" });
9205
- const variable = findVariable2(scope, obj.name);
9206
- if (variable !== null) {
9207
- unvalidatedVariables.delete(variable);
9520
+ const variable = obj?.type === import_utils59.AST_NODE_TYPES.Identifier ? unvalidatedVariableRef(obj, scope, unvalidatedVariables) : null;
9521
+ if (variable !== null) {
9522
+ if (isFullyValidatedExtractedBinding(node, variable, context)) {
9523
+ return;
9208
9524
  }
9525
+ context.report({ node, messageId: "unparsedJsonAccess" });
9526
+ clearAliasGroup(variable);
9209
9527
  }
9210
9528
  }
9211
9529
  };
@@ -10969,8 +11287,8 @@ function initProvablyLacksSignal(init) {
10969
11287
  }
10970
11288
  return true;
10971
11289
  }
10972
- function isStringish(node) {
10973
- return node.type === import_utils67.AST_NODE_TYPES.Literal && typeof node.value === "string" || node.type === import_utils67.AST_NODE_TYPES.TemplateLiteral;
11290
+ function isInlineUrl(node, resolvesToGlobal) {
11291
+ return node.type === import_utils67.AST_NODE_TYPES.Literal && typeof node.value === "string" || node.type === import_utils67.AST_NODE_TYPES.TemplateLiteral || node.type === import_utils67.AST_NODE_TYPES.NewExpression && node.callee.type === import_utils67.AST_NODE_TYPES.Identifier && node.callee.name === "URL" && resolvesToGlobal(node.callee);
10974
11292
  }
10975
11293
  var require_fetch_timeout_default = createRule({
10976
11294
  name: "require-fetch-timeout",
@@ -11022,7 +11340,7 @@ var require_fetch_timeout_default = createRule({
11022
11340
  return;
11023
11341
  }
11024
11342
  const [first, init] = node.arguments;
11025
- if (node.arguments.length === 1 && first !== void 0 && !isStringish(first)) {
11343
+ if (node.arguments.length === 1 && first !== void 0 && !isInlineUrl(first, resolvesToGlobal)) {
11026
11344
  return;
11027
11345
  }
11028
11346
  if (init === void 0 || initProvablyLacksSignal(init)) {
@@ -11039,7 +11357,7 @@ var CONFIGISH_TYPE_RE = /(?:Options|Opts|Config|Configuration|Settings|Params|Pr
11039
11357
  var CONFIGISH_NAME_RE = /^(?:options|opts|config|configuration|settings|params|props|args|env|environment|callbacks|flags|logger|log|clock)$/i;
11040
11358
  var HTTP_TRANSPORT_TYPE_RE = /^(?:KyInstance|AxiosInstance|Session)$/;
11041
11359
  var BUILTIN_CONTAINER_TYPE_RE = /^(?:Record|Map|WeakMap|Set|WeakSet|Array|ReadonlyArray|ReadonlyMap|ReadonlySet|Promise|Partial|Required|Readonly|Pick|Omit|Exclude|Extract|NonNullable|Awaited|Parameters|ReturnType|InstanceType)$/;
11042
- var VALUE_TYPE_RE = /^(?:ArrayBuffer|Blob|Buffer|Date|RegExp|URL|URLSearchParams)$/;
11360
+ var VALUE_TYPE_RE = /^(?:ArrayBuffer|Blob|Buffer|Date|NodePath|RegExp|URL|URLSearchParams)$/;
11043
11361
  var TRANSPORT_WRAPPER_NAME_RE = /(?:Client$|^Http[A-Z])/;
11044
11362
  var ERROR_VALUE_NAME_RE = /Error$/;
11045
11363
  var FLUENT_BUILDER_NAME_RE = /Builder$/;
@@ -11503,7 +11821,7 @@ var require_interface_for_injected_service_default = createRule({
11503
11821
  if (node.abstract === true) return;
11504
11822
  if (node.decorators.length > 0) return;
11505
11823
  const ctor = node.body.body.find(
11506
- (member) => member.type === import_utils68.AST_NODE_TYPES.MethodDefinition && member.kind === "constructor"
11824
+ (member) => member.type === import_utils68.AST_NODE_TYPES.MethodDefinition && member.kind === "constructor" && member.value.body !== null && member.value.body !== void 0
11507
11825
  );
11508
11826
  if (ctor === void 0) return;
11509
11827
  const constructorFacts = readConstructor(
@@ -12382,7 +12700,7 @@ var rules = {
12382
12700
  };
12383
12701
  var meta = {
12384
12702
  name: "@sarj/eslint-plugin",
12385
- version: "11.0.1"
12703
+ version: "11.2.0"
12386
12704
  };
12387
12705
  var applicationOnlyRules = [
12388
12706
  "no-restricted-library-load",