@sarj/eslint-plugin 18.0.0 → 18.0.3

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
@@ -50,7 +50,7 @@ __export(src_exports, {
50
50
  module.exports = __toCommonJS(src_exports);
51
51
 
52
52
  // src/rules/no-logical-or-fallback.ts
53
- var import_utils3 = require("@typescript-eslint/utils");
53
+ var import_utils4 = require("@typescript-eslint/utils");
54
54
  var import_ts_api_utils = require("ts-api-utils");
55
55
  var import_typescript = __toESM(require("typescript"), 1);
56
56
 
@@ -590,7 +590,30 @@ function commentLineEnd(sourceText, start) {
590
590
  return end === -1 ? sourceText.length : start + end;
591
591
  }
592
592
 
593
+ // src/rules/_unwrap-expression.ts
594
+ var import_utils3 = require("@typescript-eslint/utils");
595
+ function unwrapExpression(node) {
596
+ while (isErasedExpression(node)) {
597
+ node = node.expression;
598
+ }
599
+ return node;
600
+ }
601
+ function outerExpression(node) {
602
+ while (node.parent !== void 0 && node.parent !== null && isErasedExpression(node.parent) && node.parent.expression === node) node = node.parent;
603
+ return node;
604
+ }
605
+ function directArgumentCall(node) {
606
+ const argument = outerExpression(node);
607
+ const call = argument.parent;
608
+ return call?.type === import_utils3.AST_NODE_TYPES.CallExpression && call.arguments.some((item) => item === argument) ? call : null;
609
+ }
610
+ function isErasedExpression(node) {
611
+ return node.type === import_utils3.AST_NODE_TYPES.TSAsExpression || node.type === import_utils3.AST_NODE_TYPES.TSSatisfiesExpression || node.type === import_utils3.AST_NODE_TYPES.TSNonNullExpression || node.type === import_utils3.AST_NODE_TYPES.TSTypeAssertion;
612
+ }
613
+
593
614
  // src/rules/no-logical-or-fallback.ts
615
+ var PRIMITIVE_FLAGS = import_typescript.default.TypeFlags.StringLike | import_typescript.default.TypeFlags.NumberLike | import_typescript.default.TypeFlags.BigIntLike | import_typescript.default.TypeFlags.BooleanLike;
616
+ var GLOBAL_RECEIVERS = /* @__PURE__ */ new Set(["globalThis", "window", "self"]);
594
617
  var NO_LOGICAL_OR_FALLBACK_DOCUMENTATION = {
595
618
  defaultLevel: "warning",
596
619
  summary: "Use nullish defaults or explicit falsy-value checks instead of logical OR fallbacks.",
@@ -599,8 +622,8 @@ var NO_LOGICAL_OR_FALLBACK_DOCUMENTATION = {
599
622
  category: "correctness",
600
623
  autofix: "none",
601
624
  limitations: [
602
- "Requires TypeScript type information and strict null checks. Reports non-nullable string, number or bigint value fallbacks, including mixed primitive unions. Nullable inputs remain owned by @typescript-eslint/prefer-nullish-coalescing; both rules are enabled in the managed strict config.",
603
- "Preserves boolean aggregation, conditions, negations, left-hand && guards, and calls to the unshadowed Boolean constructor. Constant truthiness stays with no-unnecessary-condition. Unknown, any, generic, object-only and generated inputs are excluded. Strings and comments are never scanned as code.",
625
+ "Requires TypeScript type information and strict null checks. Reports non-nullable string, number or bigint value fallbacks, including branded primitives and mixed primitive unions. Nullable inputs, including nullable booleans, remain owned by @typescript-eslint/prefer-nullish-coalescing; both rules are enabled in the managed strict config.",
626
+ "Preserves non-nullable boolean aggregation, conditions, negations, left-hand && guards, and calls to the native unshadowed Boolean constructor, including erased TypeScript wrappers and globalThis/window/self access. Constant truthiness stays with no-unnecessary-condition. Unknown, any, unresolved generic, object-only and generated inputs are excluded. Strings and comments are never scanned as code.",
604
627
  "No automatic replacement is offered: replacing || with ?? would change empty-string or zero behavior. Non-nullable ||= expressions remain outside this companion rule."
605
628
  ],
606
629
  references: ["https://typescript-eslint.io/rules/prefer-nullish-coalescing/"],
@@ -628,83 +651,72 @@ var no_logical_or_fallback_default = createRule({
628
651
  if (!(options.strictNullChecks ?? options.strict ?? false)) return {};
629
652
  return {
630
653
  LogicalExpression(node) {
631
- if (node.operator !== "||" || booleanContext(node, context.sourceCode)) return;
654
+ if (node.operator !== "||" || booleanContext(node, context.sourceCode, services)) return;
632
655
  const type = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node.left));
633
- const members = type.isUnion() ? type.types : [type];
634
- const primitiveFlags = import_typescript.default.TypeFlags.StringLike | import_typescript.default.TypeFlags.NumberLike | import_typescript.default.TypeFlags.BigIntLike | import_typescript.default.TypeFlags.BooleanLike;
635
- if (!members.every((member3) => (member3.flags & primitiveFlags) !== 0) || !members.some((member3) => (member3.flags & (import_typescript.default.TypeFlags.StringLike | import_typescript.default.TypeFlags.NumberLike | import_typescript.default.TypeFlags.BigIntLike)) !== 0)) return;
636
- const truthiness = members.map(literalTruthiness);
656
+ const members = (type.isUnion() ? type.types : [type]).map(primitivePart);
657
+ if (members.some((member3) => member3 === void 0) || !members.some((member3) => member3 !== void 0 && (member3.flags & (import_typescript.default.TypeFlags.StringLike | import_typescript.default.TypeFlags.NumberLike | import_typescript.default.TypeFlags.BigIntLike)) !== 0)) return;
658
+ const truthiness = members.map((member3) => member3 === void 0 ? void 0 : literalTruthiness(member3));
637
659
  if (truthiness.every((value) => value === true) || truthiness.every((value) => value === false)) return;
638
660
  context.report({ node, messageId: "logicalOrFallback" });
639
661
  }
640
662
  };
641
663
  }
642
664
  });
665
+ function primitivePart(type) {
666
+ if ((type.flags & PRIMITIVE_FLAGS) !== 0) return type;
667
+ if (!type.isIntersection() || type.types.some((member3) => (member3.flags & import_typescript.default.TypeFlags.TypeParameter) !== 0)) return void 0;
668
+ return type.types.find((member3) => (member3.flags & PRIMITIVE_FLAGS) !== 0);
669
+ }
643
670
  function literalTruthiness(type) {
644
671
  if (type.isStringLiteral() || type.isNumberLiteral()) return Boolean(type.value);
645
672
  if ((0, import_ts_api_utils.isBooleanLiteralType)(type)) return type.intrinsicName === "true";
646
673
  if ((0, import_ts_api_utils.isBigIntLiteralType)(type)) return type.value.base10Value !== "0";
647
674
  return void 0;
648
675
  }
649
- function booleanContext(node, source) {
650
- let current = node;
676
+ function booleanContext(node, source, services) {
677
+ let current = outerExpression(node);
651
678
  while (current.parent !== void 0) {
652
679
  const parent = current.parent;
653
680
  switch (parent.type) {
654
- case import_utils3.AST_NODE_TYPES.TSAsExpression:
655
- case import_utils3.AST_NODE_TYPES.TSSatisfiesExpression:
656
- case import_utils3.AST_NODE_TYPES.TSNonNullExpression:
657
- current = parent;
658
- continue;
659
- case import_utils3.AST_NODE_TYPES.LogicalExpression:
681
+ case import_utils4.AST_NODE_TYPES.LogicalExpression:
660
682
  if (parent.operator === "&&" && parent.left === current) return true;
661
- current = parent;
683
+ current = outerExpression(parent);
662
684
  continue;
663
- case import_utils3.AST_NODE_TYPES.IfStatement:
664
- case import_utils3.AST_NODE_TYPES.WhileStatement:
665
- case import_utils3.AST_NODE_TYPES.DoWhileStatement:
666
- case import_utils3.AST_NODE_TYPES.ForStatement:
667
- case import_utils3.AST_NODE_TYPES.ConditionalExpression:
685
+ case import_utils4.AST_NODE_TYPES.IfStatement:
686
+ case import_utils4.AST_NODE_TYPES.WhileStatement:
687
+ case import_utils4.AST_NODE_TYPES.DoWhileStatement:
688
+ case import_utils4.AST_NODE_TYPES.ForStatement:
689
+ case import_utils4.AST_NODE_TYPES.ConditionalExpression:
668
690
  return parent.test === current;
669
- case import_utils3.AST_NODE_TYPES.UnaryExpression:
691
+ case import_utils4.AST_NODE_TYPES.UnaryExpression:
670
692
  return parent.operator === "!";
671
- case import_utils3.AST_NODE_TYPES.CallExpression:
672
- return parent.callee.type === import_utils3.AST_NODE_TYPES.Identifier && parent.callee.name === "Boolean" && parent.arguments[0] === current && import_utils3.ASTUtils.findVariable(source.getScope(parent.callee), "Boolean")?.defs.length === 0;
693
+ case import_utils4.AST_NODE_TYPES.CallExpression:
694
+ return parent.arguments[0] === current && nativeBoolean(parent.callee, source, services);
673
695
  default:
674
696
  return false;
675
697
  }
676
698
  }
677
699
  return false;
678
700
  }
679
-
680
- // src/rules/no-zod-parse-typed-object.ts
681
- var import_utils5 = require("@typescript-eslint/utils");
682
- var import_typescript2 = __toESM(require("typescript"), 1);
683
-
684
- // src/rules/_unwrap-expression.ts
685
- var import_utils4 = require("@typescript-eslint/utils");
686
- function unwrapExpression(node) {
687
- while (isErasedExpression(node)) {
688
- node = node.expression;
701
+ function nativeBoolean(node, source, services) {
702
+ const callee = unwrapExpression(node);
703
+ const checker = services.program.getTypeChecker();
704
+ let symbol;
705
+ if (callee.type === import_utils4.AST_NODE_TYPES.Identifier && callee.name === "Boolean" && !import_utils4.ASTUtils.findVariable(source.getScope(callee), callee.name)?.defs.length) {
706
+ symbol = checker.getSymbolAtLocation(services.esTreeNodeToTSNodeMap.get(callee));
707
+ } else if (callee.type === import_utils4.AST_NODE_TYPES.MemberExpression && import_utils4.ASTUtils.getPropertyName(callee) === "Boolean") {
708
+ const receiver = unwrapExpression(callee.object);
709
+ if (receiver.type !== import_utils4.AST_NODE_TYPES.Identifier || !GLOBAL_RECEIVERS.has(receiver.name) || import_utils4.ASTUtils.findVariable(source.getScope(receiver), receiver.name)?.defs.length) return false;
710
+ symbol = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(receiver)).getProperty("Boolean");
689
711
  }
690
- return node;
691
- }
692
- function outerExpression(node) {
693
- while (node.parent !== void 0 && node.parent !== null && isErasedExpression(node.parent) && node.parent.expression === node) node = node.parent;
694
- return node;
695
- }
696
- function directArgumentCall(node) {
697
- const argument = outerExpression(node);
698
- const call = argument.parent;
699
- return call?.type === import_utils4.AST_NODE_TYPES.CallExpression && call.arguments.some((item) => item === argument) ? call : null;
700
- }
701
- function isErasedExpression(node) {
702
- return node.type === import_utils4.AST_NODE_TYPES.TSAsExpression || node.type === import_utils4.AST_NODE_TYPES.TSSatisfiesExpression || node.type === import_utils4.AST_NODE_TYPES.TSNonNullExpression || node.type === import_utils4.AST_NODE_TYPES.TSTypeAssertion;
712
+ return symbol?.declarations !== void 0 && symbol.declarations.length > 0 && symbol.declarations.every((declaration) => services.program.isSourceFileDefaultLibrary(declaration.getSourceFile()));
703
713
  }
704
714
 
705
715
  // src/rules/no-zod-parse-typed-object.ts
716
+ var import_utils5 = require("@typescript-eslint/utils");
717
+ var import_ts_api_utils2 = require("ts-api-utils");
718
+ var import_typescript2 = __toESM(require("typescript"), 1);
706
719
  var PARSE_METHODS = /* @__PURE__ */ new Set(["parse", "parseAsync", "safeParse", "safeParseAsync"]);
707
- var TUPLE_INDEX_RE = /^(?:0|[1-9]\d*)$/u;
708
720
  var OPAQUE_FLAGS = import_typescript2.default.TypeFlags.Any | import_typescript2.default.TypeFlags.Unknown | import_typescript2.default.TypeFlags.Never | import_typescript2.default.TypeFlags.TypeParameter | import_typescript2.default.TypeFlags.Conditional | import_typescript2.default.TypeFlags.IndexedAccess | import_typescript2.default.TypeFlags.Intersection | import_typescript2.default.TypeFlags.NonPrimitive;
709
721
  var NO_ZOD_PARSE_TYPED_OBJECT_DOCUMENTATION = {
710
722
  defaultLevel: "warning",
@@ -717,7 +729,7 @@ var NO_ZOD_PARSE_TYPED_OBJECT_DOCUMENTATION = {
717
729
  "Requires type information, strict null checks, and a native installed Zod parse, parseAsync, safeParse or safeParseAsync signature. Recognizes imported schemas, aliases, member access and awaited service results without guessing from names.",
718
730
  "Reports fully known object or array inputs assignable to the schema input, when schema input and output have the same value shape. Optional-to-required defaults are included; type-changing transforms, coercions, brands, incompatible contracts, primitive roots and nested any/unknown/generic contracts are excluded.",
719
731
  "Static types do not establish runtime trust or prove refinements and normalization redundant. This is an architectural warning with no automatic removal. Keep intentional validation at an unknown-data boundary or document an exact local suppression. Tests, stories and generated code are excluded.",
720
- "Shape comparison ignores undefined introduced by optional properties and is bounded to 128 object pairs or visited input objects. Opaque or larger graphs are conservatively excluded."
732
+ "Shape comparison ignores undefined introduced by optional properties and checks tuple element types and rest positions. It is bounded to 128 object pairs, visited input objects, properties, tuple elements or primitive union alternatives; object unions have at most 16 alternatives. Opaque or larger graphs are conservatively excluded."
721
733
  ],
722
734
  references: ["https://zod.dev/basics"],
723
735
  examples: [
@@ -777,7 +789,11 @@ function knownValue(checker, type, location, seen) {
777
789
  if (seen.has(type)) return true;
778
790
  if (seen.size >= 128 || type.getCallSignatures().length > 0 || type.getConstructSignatures().length > 0) return false;
779
791
  seen.add(type);
780
- if (checker.isArrayType(type) || checker.isTupleType(type)) {
792
+ if ((0, import_ts_api_utils2.isTupleTypeReference)(type)) {
793
+ const elements = checker.getTypeArguments(type);
794
+ return elements.length <= 128 && elements.every((element) => knownValue(checker, element, location, seen));
795
+ }
796
+ if (checker.isArrayType(type)) {
781
797
  const element = type.getNumberIndexType();
782
798
  return element !== void 0 && knownValue(checker, element, location, seen);
783
799
  }
@@ -793,7 +809,8 @@ function sameShape(checker, input, output, location) {
793
809
  if (left.isUnion() || right.isUnion()) {
794
810
  const a = (left.isUnion() ? left.types : [left]).filter((member3) => (member3.flags & import_typescript2.default.TypeFlags.Undefined) === 0);
795
811
  const b = (right.isUnion() ? right.types : [right]).filter((member3) => (member3.flags & import_typescript2.default.TypeFlags.Undefined) === 0);
796
- return a.length > 0 && a.length === b.length && a.length <= 16 && a.every((member3) => b.some((other) => compare(member3, other))) && b.every((member3) => a.some((other) => compare(other, member3)));
812
+ const limit = [...a, ...b].every((member3) => (member3.flags & (import_typescript2.default.TypeFlags.Object | OPAQUE_FLAGS)) === 0) ? 128 : 16;
813
+ return a.length > 0 && a.length === b.length && a.length <= limit && a.every((member3) => b.some((other) => compare(member3, other))) && b.every((member3) => a.some((other) => compare(other, member3)));
797
814
  }
798
815
  if ((left.flags & import_typescript2.default.TypeFlags.Object) === 0 || (right.flags & import_typescript2.default.TypeFlags.Object) === 0) {
799
816
  return checker.isTypeAssignableTo(left, right) && checker.isTypeAssignableTo(right, left);
@@ -811,9 +828,9 @@ function sameShape(checker, input, output, location) {
811
828
  function sameObjectShape(left, right) {
812
829
  const leftTuple = checker.isTupleType(left);
813
830
  const rightTuple = checker.isTupleType(right);
814
- if (leftTuple !== rightTuple || leftTuple && !sameTuplePositions(left, right)) return false;
815
- if (checker.isArrayType(left) || leftTuple) {
816
- if (!checker.isArrayType(right) && !rightTuple) return false;
831
+ if (leftTuple || rightTuple) return leftTuple && rightTuple && sameTuplePositions(left, right);
832
+ if (checker.isArrayType(left)) {
833
+ if (!checker.isArrayType(right)) return false;
817
834
  const a2 = left.getNumberIndexType();
818
835
  const b2 = right.getNumberIndexType();
819
836
  return a2 !== void 0 && b2 !== void 0 && compare(a2, b2);
@@ -829,17 +846,13 @@ function sameShape(checker, input, output, location) {
829
846
  return a.length === b.length && a.every((index) => b.some((other) => checker.isTypeAssignableTo(index.keyType, other.keyType) && checker.isTypeAssignableTo(other.keyType, index.keyType) && compare(index.type, other.type)));
830
847
  }
831
848
  function sameTuplePositions(left, right) {
832
- const leftLength = left.getProperty("length");
833
- const rightLength = right.getProperty("length");
834
- if (leftLength === void 0 || rightLength === void 0) return false;
835
- const a = checker.getTypeOfSymbolAtLocation(leftLength, location);
836
- const b = checker.getTypeOfSymbolAtLocation(rightLength, location);
837
- if (!checker.isTypeAssignableTo(a, b) || !checker.isTypeAssignableTo(b, a)) return false;
838
- const properties = left.getProperties().filter((property) => TUPLE_INDEX_RE.test(property.name));
839
- const otherProperties = right.getProperties().filter((property) => TUPLE_INDEX_RE.test(property.name));
840
- return properties.length <= 128 && properties.length === otherProperties.length && properties.every((property) => {
841
- const other = right.getProperty(property.name);
842
- return other !== void 0 && compare(checker.getTypeOfSymbolAtLocation(property, location), checker.getTypeOfSymbolAtLocation(other, location));
849
+ if (!(0, import_ts_api_utils2.isTupleTypeReference)(left) || !(0, import_ts_api_utils2.isTupleTypeReference)(right)) return false;
850
+ const a = checker.getTypeArguments(left);
851
+ const b = checker.getTypeArguments(right);
852
+ const flags = right.target.elementFlags;
853
+ return a.length <= 128 && a.length === b.length && left.target.elementFlags.every((flag, index) => flag === flags[index]) && a.every((element, index) => {
854
+ const other = b[index];
855
+ return other !== void 0 && compare(element, other);
843
856
  });
844
857
  }
845
858
  return compare(input, output);
@@ -882,7 +895,7 @@ function stableValueBinding(variable, acceptRead) {
882
895
  var VIEWS = /* @__PURE__ */ new WeakMap();
883
896
  function renderFunction(node) {
884
897
  let parent = node.parent;
885
- while (parent !== void 0) {
898
+ while (parent !== void 0 && parent !== null) {
886
899
  if (isFunction(parent)) {
887
900
  let view = VIEWS.get(parent);
888
901
  if (view === void 0) {
@@ -2510,7 +2523,7 @@ function nativeRead(node, name) {
2510
2523
  }
2511
2524
 
2512
2525
  // src/rules/_native-fetch-reference.ts
2513
- var GLOBAL_RECEIVERS = /* @__PURE__ */ new Set(["globalThis", "self", "window"]);
2526
+ var GLOBAL_RECEIVERS2 = /* @__PURE__ */ new Set(["globalThis", "self", "window"]);
2514
2527
  function nativeFetchReference(node, sourceCode) {
2515
2528
  return lexicalFetchReference(node, sourceCode) && nativeRuntimeUnchanged(sourceCode, "fetch");
2516
2529
  }
@@ -2533,7 +2546,7 @@ function lexicalFetchReference(node, sourceCode, seen = /* @__PURE__ */ new Set(
2533
2546
  }
2534
2547
  function globalReceiver(node, sourceCode) {
2535
2548
  const receiver = unwrapExpression(node);
2536
- return receiver.type === import_utils22.AST_NODE_TYPES.Identifier && GLOBAL_RECEIVERS.has(receiver.name) && !import_utils22.ASTUtils.findVariable(sourceCode.getScope(receiver), receiver.name)?.defs.length;
2549
+ return receiver.type === import_utils22.AST_NODE_TYPES.Identifier && GLOBAL_RECEIVERS2.has(receiver.name) && !import_utils22.ASTUtils.findVariable(sourceCode.getScope(receiver), receiver.name)?.defs.length;
2537
2550
  }
2538
2551
 
2539
2552
  // src/rules/_test-mock-provenance.ts
@@ -5526,7 +5539,7 @@ function isSearchParamReceiver(call, services) {
5526
5539
  // package.json
5527
5540
  var package_default = {
5528
5541
  name: "@sarj/eslint-plugin",
5529
- version: "18.0.0",
5542
+ version: "18.0.3",
5530
5543
  packageManager: "npm@12.2.1",
5531
5544
  description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
5532
5545
  type: "module",
@@ -7958,7 +7971,7 @@ var no_known_value_widening_default = createRule({
7958
7971
 
7959
7972
  // src/rules/no-invalid-typed-mutation.ts
7960
7973
  var import_utils53 = require("@typescript-eslint/utils");
7961
- var import_ts_api_utils2 = require("ts-api-utils");
7974
+ var import_ts_api_utils3 = require("ts-api-utils");
7962
7975
  var import_typescript20 = __toESM(require("typescript"), 1);
7963
7976
  var NO_INVALID_TYPED_MUTATION_DOCUMENTATION = {
7964
7977
  summary: "Keep native object mutation APIs from writing incompatible values into declared property types.",
@@ -8129,7 +8142,7 @@ function typedDataProperty(property) {
8129
8142
  function propertyWriteType(target, property, node, checker, exact) {
8130
8143
  const exposed = checker.getTypeOfSymbolAtLocation(property, node);
8131
8144
  if (!exact || (property.flags & import_typescript20.default.SymbolFlags.Optional) === 0 || (property.flags & import_typescript20.default.SymbolFlags.Transient) !== 0) return exposed;
8132
- if ((target.aliasTypeArguments?.length ?? 0) > 0 || (0, import_ts_api_utils2.isTypeReference)(target) && checker.getTypeArguments(target).length > 0 || (0, import_ts_api_utils2.isObjectType)(target) && (target.objectFlags & (import_typescript20.default.ObjectFlags.Mapped | import_typescript20.default.ObjectFlags.Instantiated)) !== 0) return exposed;
8145
+ if ((target.aliasTypeArguments?.length ?? 0) > 0 || (0, import_ts_api_utils3.isTypeReference)(target) && checker.getTypeArguments(target).length > 0 || (0, import_ts_api_utils3.isObjectType)(target) && (target.objectFlags & (import_typescript20.default.ObjectFlags.Mapped | import_typescript20.default.ObjectFlags.Instantiated)) !== 0) return exposed;
8133
8146
  const declaration = property.getDeclarations()?.[0];
8134
8147
  if (declaration === void 0 || !(import_typescript20.default.isPropertySignature(declaration) || import_typescript20.default.isPropertyDeclaration(declaration)) || declaration.questionToken === void 0 || declaration.type === void 0) return exposed;
8135
8148
  const authored = checker.getTypeFromTypeNode(declaration.type);
@@ -8142,10 +8155,10 @@ function definiteType(type, checker, seen = /* @__PURE__ */ new Set()) {
8142
8155
  const unsafe = import_typescript20.default.TypeFlags.Any | import_typescript20.default.TypeFlags.Unknown | import_typescript20.default.TypeFlags.Never | import_typescript20.default.TypeFlags.TypeParameter | import_typescript20.default.TypeFlags.Conditional | import_typescript20.default.TypeFlags.IndexedAccess | import_typescript20.default.TypeFlags.Substitution;
8143
8156
  if ((type.flags & unsafe) !== 0) return false;
8144
8157
  if (type.isUnionOrIntersection()) return type.types.every((part) => definiteType(part, checker, seen));
8145
- const arguments_ = (0, import_ts_api_utils2.isTypeReference)(type) ? checker.getTypeArguments(type) : type.aliasTypeArguments ?? [];
8158
+ const arguments_ = (0, import_ts_api_utils3.isTypeReference)(type) ? checker.getTypeArguments(type) : type.aliasTypeArguments ?? [];
8146
8159
  if (!arguments_.every((argument) => definiteType(argument, checker, seen))) return false;
8147
8160
  if (!definiteSignatures(type, checker, seen)) return false;
8148
- if ((0, import_ts_api_utils2.isTypeReference)(type) || (type.flags & import_typescript20.default.TypeFlags.Object) === 0) return true;
8161
+ if ((0, import_ts_api_utils3.isTypeReference)(type) || (type.flags & import_typescript20.default.TypeFlags.Object) === 0) return true;
8149
8162
  return type.getProperties().every((property) => {
8150
8163
  const declaration = property.valueDeclaration ?? property.getDeclarations()?.[0];
8151
8164
  return declaration !== void 0 && definiteType(checker.getTypeOfSymbolAtLocation(property, declaration), checker, seen);
@@ -8246,7 +8259,7 @@ function hasSeparatePredicateContract(node, checker) {
8246
8259
  // src/rules/_contradictory-array-predicate.ts
8247
8260
  var import_utils54 = require("@typescript-eslint/utils");
8248
8261
  var import_typescript22 = __toESM(require("typescript"), 1);
8249
- var import_ts_api_utils3 = require("ts-api-utils");
8262
+ var import_ts_api_utils4 = require("ts-api-utils");
8250
8263
  var HOST_GLOBALS = ["globalThis", "window", "self", "global"];
8251
8264
  var PRIMITIVE_ELEMENTS = import_typescript22.default.TypeFlags.String | import_typescript22.default.TypeFlags.Number | import_typescript22.default.TypeFlags.Boolean | import_typescript22.default.TypeFlags.BigInt | import_typescript22.default.TypeFlags.ESSymbol;
8252
8265
  var OBJECT_REFLECTION2 = /* @__PURE__ */ new Set(["getPrototypeOf", "getOwnPropertyDescriptor", "getOwnPropertyDescriptors", "prototype", "constructor", "__proto__"]);
@@ -8281,7 +8294,7 @@ function contradictoryArrayPredicate(sourceCode, services) {
8281
8294
  };
8282
8295
  }
8283
8296
  function plainPrimitiveArray(target, checker) {
8284
- if (!checker.isArrayType(target) || !(0, import_ts_api_utils3.isTypeReference)(target)) return false;
8297
+ if (!checker.isArrayType(target) || !(0, import_ts_api_utils4.isTypeReference)(target)) return false;
8285
8298
  const [element] = checker.getTypeArguments(target);
8286
8299
  return element !== void 0 && (element.flags & PRIMITIVE_ELEMENTS) !== 0 && (element.flags & (import_typescript22.default.TypeFlags.Enum | import_typescript22.default.TypeFlags.EnumLiteral | import_typescript22.default.TypeFlags.Intersection)) === 0;
8287
8300
  }
@@ -8565,7 +8578,7 @@ function primitiveKind(type, allowLiterals) {
8565
8578
 
8566
8579
  // src/rules/no-partial-type-predicate.ts
8567
8580
  var import_utils57 = require("@typescript-eslint/utils");
8568
- var import_ts_api_utils4 = require("ts-api-utils");
8581
+ var import_ts_api_utils5 = require("ts-api-utils");
8569
8582
  var import_typescript25 = __toESM(require("typescript"), 1);
8570
8583
 
8571
8584
  // src/rules/_uuid-predicate-witness.ts
@@ -8737,7 +8750,7 @@ function primitiveKind2(type) {
8737
8750
  return void 0;
8738
8751
  }
8739
8752
  function numericWitnessInInput(value, input) {
8740
- return (input.isUnion() ? input.types : [input]).some((member3) => (member3.flags & (import_typescript25.default.TypeFlags.Unknown | import_typescript25.default.TypeFlags.Number)) !== 0 || Number.isFinite(value) && (0, import_ts_api_utils4.isNumberLiteralType)(member3) && member3.value === value);
8753
+ return (input.isUnion() ? input.types : [input]).some((member3) => (member3.flags & (import_typescript25.default.TypeFlags.Unknown | import_typescript25.default.TypeFlags.Number)) !== 0 || Number.isFinite(value) && (0, import_ts_api_utils5.isNumberLiteralType)(member3) && member3.value === value);
8741
8754
  }
8742
8755
  function returnedExpression2(node) {
8743
8756
  if (node.body === void 0) return void 0;
@@ -9323,7 +9336,7 @@ function isDirectTest(identifier) {
9323
9336
 
9324
9337
  // src/rules/no-invalid-zod-custom-parse.ts
9325
9338
  var import_utils61 = require("@typescript-eslint/utils");
9326
- var import_ts_api_utils5 = require("ts-api-utils");
9339
+ var import_ts_api_utils6 = require("ts-api-utils");
9327
9340
  var import_typescript27 = __toESM(require("typescript"), 1);
9328
9341
  var NO_INVALID_ZOD_CUSTOM_PARSE_DOCUMENTATION = {
9329
9342
  summary: "Do not parse an incompatible primitive literal through an unvalidated Zod custom schema.",
@@ -9419,10 +9432,10 @@ function primitiveDomain(type) {
9419
9432
  function acceptsPrimitive(type, value) {
9420
9433
  if (type.isUnion()) return type.types.some((member3) => acceptsPrimitive(member3, value));
9421
9434
  if (value === null) return (type.flags & import_typescript27.default.TypeFlags.Null) !== 0;
9422
- if (typeof value === "string") return (type.flags & import_typescript27.default.TypeFlags.String) !== 0 || (0, import_ts_api_utils5.isStringLiteralType)(type) && type.value === value;
9423
- if (typeof value === "number") return (type.flags & import_typescript27.default.TypeFlags.Number) !== 0 || (0, import_ts_api_utils5.isNumberLiteralType)(type) && type.value === value;
9424
- if (typeof value === "boolean") return (0, import_ts_api_utils5.isBooleanLiteralType)(type) && type.intrinsicName === String(value);
9425
- return (type.flags & import_typescript27.default.TypeFlags.BigInt) !== 0 || (0, import_ts_api_utils5.isBigIntLiteralType)(type) && bigintValue(type) === value;
9435
+ if (typeof value === "string") return (type.flags & import_typescript27.default.TypeFlags.String) !== 0 || (0, import_ts_api_utils6.isStringLiteralType)(type) && type.value === value;
9436
+ if (typeof value === "number") return (type.flags & import_typescript27.default.TypeFlags.Number) !== 0 || (0, import_ts_api_utils6.isNumberLiteralType)(type) && type.value === value;
9437
+ if (typeof value === "boolean") return (0, import_ts_api_utils6.isBooleanLiteralType)(type) && type.intrinsicName === String(value);
9438
+ return (type.flags & import_typescript27.default.TypeFlags.BigInt) !== 0 || (0, import_ts_api_utils6.isBigIntLiteralType)(type) && bigintValue(type) === value;
9426
9439
  }
9427
9440
  function bigintValue(type) {
9428
9441
  return BigInt(`${type.value.negative ? "-" : ""}${type.value.base10Value}`);
@@ -14808,7 +14821,7 @@ var NO_DETACHED_GLOBAL_FETCH_DOCUMENTATION = {
14808
14821
  }
14809
14822
  ]
14810
14823
  };
14811
- var GLOBAL_RECEIVERS2 = /* @__PURE__ */ new Set([
14824
+ var GLOBAL_RECEIVERS3 = /* @__PURE__ */ new Set([
14812
14825
  "globalThis",
14813
14826
  "self",
14814
14827
  "window"
@@ -14855,7 +14868,7 @@ var no_detached_global_fetch_default = createRule({
14855
14868
  return variable === null || variable.defs.length === 0;
14856
14869
  }
14857
14870
  function isGlobalReceiver(node) {
14858
- return node.type === import_utils92.AST_NODE_TYPES.Identifier && GLOBAL_RECEIVERS2.has(node.name) && resolvesToGlobal(node);
14871
+ return node.type === import_utils92.AST_NODE_TYPES.Identifier && GLOBAL_RECEIVERS3.has(node.name) && resolvesToGlobal(node);
14859
14872
  }
14860
14873
  function recordAlias(identifier) {
14861
14874
  const variable = bindingOf(identifier);
@@ -14914,7 +14927,7 @@ var no_detached_global_fetch_default = createRule({
14914
14927
  return false;
14915
14928
  if (node.type !== import_utils92.AST_NODE_TYPES.Identifier || !resolvesToGlobal(node))
14916
14929
  return false;
14917
- return GLOBAL_RECEIVERS2.has(node.name) || node.name === "undefined";
14930
+ return GLOBAL_RECEIVERS3.has(node.name) || node.name === "undefined";
14918
14931
  }
14919
14932
  return {
14920
14933
  AssignmentExpression(node) {
@@ -16202,7 +16215,7 @@ var EQUALITY_OPERATORS = /* @__PURE__ */ new Set([
16202
16215
  "==",
16203
16216
  "==="
16204
16217
  ]);
16205
- var PRIMITIVE_FLAGS = import_typescript29.default.TypeFlags.BigIntLike | import_typescript29.default.TypeFlags.BooleanLike | import_typescript29.default.TypeFlags.ESSymbolLike | import_typescript29.default.TypeFlags.Never | import_typescript29.default.TypeFlags.Null | import_typescript29.default.TypeFlags.NumberLike | import_typescript29.default.TypeFlags.StringLike | import_typescript29.default.TypeFlags.Undefined | import_typescript29.default.TypeFlags.Void;
16218
+ var PRIMITIVE_FLAGS2 = import_typescript29.default.TypeFlags.BigIntLike | import_typescript29.default.TypeFlags.BooleanLike | import_typescript29.default.TypeFlags.ESSymbolLike | import_typescript29.default.TypeFlags.Never | import_typescript29.default.TypeFlags.Null | import_typescript29.default.TypeFlags.NumberLike | import_typescript29.default.TypeFlags.StringLike | import_typescript29.default.TypeFlags.Undefined | import_typescript29.default.TypeFlags.Void;
16206
16219
  function unwrapComparisonExpression(node) {
16207
16220
  let current = unwrapExpression(node);
16208
16221
  while (current.type === import_utils98.AST_NODE_TYPES.ChainExpression) {
@@ -16256,7 +16269,7 @@ function typeMayContainObject(type, checker) {
16256
16269
  if (type.isUnionOrIntersection()) {
16257
16270
  return type.types.some((member3) => typeMayContainObject(member3, checker));
16258
16271
  }
16259
- if ((type.flags & PRIMITIVE_FLAGS) !== 0) return false;
16272
+ if ((type.flags & PRIMITIVE_FLAGS2) !== 0) return false;
16260
16273
  if ((type.flags & (import_typescript29.default.TypeFlags.Any | import_typescript29.default.TypeFlags.Unknown | import_typescript29.default.TypeFlags.TypeParameter)) !== 0) {
16261
16274
  return true;
16262
16275
  }
@@ -33451,7 +33464,7 @@ var import_utils182 = require("@typescript-eslint/utils");
33451
33464
  var import_typescript34 = __toESM(require("typescript"), 1);
33452
33465
 
33453
33466
  // src/rules/_equivalent-zod-output-contracts.ts
33454
- var import_ts_api_utils6 = require("ts-api-utils");
33467
+ var import_ts_api_utils7 = require("ts-api-utils");
33455
33468
  var import_typescript32 = __toESM(require("typescript"), 1);
33456
33469
  var MAX_CONTRACT_PAIRS = 128;
33457
33470
  var MAX_UNION_MEMBERS = 16;
@@ -33480,8 +33493,8 @@ function seenPair(comparison2, left, right) {
33480
33493
  function equivalentPair(comparison2, left, right) {
33481
33494
  if (!mutuallyAssignable(comparison2.checker, left, right)) return false;
33482
33495
  if (left.isUnion() || right.isUnion()) return equivalentUnions(comparison2, left, right);
33483
- const leftContainer = comparison2.checker.isArrayType(left) || (0, import_ts_api_utils6.isTupleTypeReference)(left);
33484
- const rightContainer = comparison2.checker.isArrayType(right) || (0, import_ts_api_utils6.isTupleTypeReference)(right);
33496
+ const leftContainer = comparison2.checker.isArrayType(left) || (0, import_ts_api_utils7.isTupleTypeReference)(left);
33497
+ const rightContainer = comparison2.checker.isArrayType(right) || (0, import_ts_api_utils7.isTupleTypeReference)(right);
33485
33498
  if (leftContainer || rightContainer) return equivalentContainers(comparison2, left, right);
33486
33499
  if (hasClassDeclaration(left) || hasClassDeclaration(right)) return false;
33487
33500
  if (!objectLike(left) || !objectLike(right)) return false;
@@ -33510,9 +33523,9 @@ function queuePair(comparison2, left, right) {
33510
33523
  return true;
33511
33524
  }
33512
33525
  function equivalentContainers(comparison2, left, right) {
33513
- if (!(0, import_ts_api_utils6.isTypeReference)(left) || !(0, import_ts_api_utils6.isTypeReference)(right)) return false;
33514
- const leftTuple = (0, import_ts_api_utils6.isTupleTypeReference)(left);
33515
- const rightTuple = (0, import_ts_api_utils6.isTupleTypeReference)(right);
33526
+ if (!(0, import_ts_api_utils7.isTypeReference)(left) || !(0, import_ts_api_utils7.isTypeReference)(right)) return false;
33527
+ const leftTuple = (0, import_ts_api_utils7.isTupleTypeReference)(left);
33528
+ const rightTuple = (0, import_ts_api_utils7.isTupleTypeReference)(right);
33516
33529
  if (leftTuple !== rightTuple) return false;
33517
33530
  if (leftTuple && rightTuple && (left.target.readonly !== right.target.readonly || left.target.elementFlags.length !== right.target.elementFlags.length || left.target.elementFlags.some((flag, index) => flag !== right.target.elementFlags[index]))) return false;
33518
33531
  const leftIndex = comparison2.checker.getIndexInfoOfType(left, import_typescript32.default.IndexKind.Number);
@@ -33550,7 +33563,7 @@ function equivalentProperty(comparison2, left, right, property, other) {
33550
33563
  const { checker } = comparison2;
33551
33564
  if (opaqueProperty(property) || opaqueProperty(other)) return false;
33552
33565
  if ((property.flags & import_typescript32.default.SymbolFlags.Optional) !== (other.flags & import_typescript32.default.SymbolFlags.Optional)) return false;
33553
- if ((0, import_ts_api_utils6.isPropertyReadonlyInType)(left, property.getEscapedName(), checker) !== (0, import_ts_api_utils6.isPropertyReadonlyInType)(right, other.getEscapedName(), checker)) return false;
33566
+ if ((0, import_ts_api_utils7.isPropertyReadonlyInType)(left, property.getEscapedName(), checker) !== (0, import_ts_api_utils7.isPropertyReadonlyInType)(right, other.getEscapedName(), checker)) return false;
33554
33567
  const declaration = property.valueDeclaration ?? property.getDeclarations()?.[0];
33555
33568
  const otherDeclaration = other.valueDeclaration ?? other.getDeclarations()?.[0];
33556
33569
  return declaration !== void 0 && otherDeclaration !== void 0 && queuePair(
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/rules/no-logical-or-fallback.ts
2
- import { ASTUtils, AST_NODE_TYPES as AST_NODE_TYPES2 } from "@typescript-eslint/utils";
2
+ import { ASTUtils, AST_NODE_TYPES as AST_NODE_TYPES3 } from "@typescript-eslint/utils";
3
3
  import { isBigIntLiteralType, isBooleanLiteralType } from "ts-api-utils";
4
4
  import ts from "typescript";
5
5
 
@@ -539,7 +539,30 @@ function commentLineEnd(sourceText, start) {
539
539
  return end === -1 ? sourceText.length : start + end;
540
540
  }
541
541
 
542
+ // src/rules/_unwrap-expression.ts
543
+ import { AST_NODE_TYPES as AST_NODE_TYPES2 } from "@typescript-eslint/utils";
544
+ function unwrapExpression(node) {
545
+ while (isErasedExpression(node)) {
546
+ node = node.expression;
547
+ }
548
+ return node;
549
+ }
550
+ function outerExpression(node) {
551
+ while (node.parent !== void 0 && node.parent !== null && isErasedExpression(node.parent) && node.parent.expression === node) node = node.parent;
552
+ return node;
553
+ }
554
+ function directArgumentCall(node) {
555
+ const argument = outerExpression(node);
556
+ const call = argument.parent;
557
+ return call?.type === AST_NODE_TYPES2.CallExpression && call.arguments.some((item) => item === argument) ? call : null;
558
+ }
559
+ function isErasedExpression(node) {
560
+ return node.type === AST_NODE_TYPES2.TSAsExpression || node.type === AST_NODE_TYPES2.TSSatisfiesExpression || node.type === AST_NODE_TYPES2.TSNonNullExpression || node.type === AST_NODE_TYPES2.TSTypeAssertion;
561
+ }
562
+
542
563
  // src/rules/no-logical-or-fallback.ts
564
+ var PRIMITIVE_FLAGS = ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike | ts.TypeFlags.BooleanLike;
565
+ var GLOBAL_RECEIVERS = /* @__PURE__ */ new Set(["globalThis", "window", "self"]);
543
566
  var NO_LOGICAL_OR_FALLBACK_DOCUMENTATION = {
544
567
  defaultLevel: "warning",
545
568
  summary: "Use nullish defaults or explicit falsy-value checks instead of logical OR fallbacks.",
@@ -548,8 +571,8 @@ var NO_LOGICAL_OR_FALLBACK_DOCUMENTATION = {
548
571
  category: "correctness",
549
572
  autofix: "none",
550
573
  limitations: [
551
- "Requires TypeScript type information and strict null checks. Reports non-nullable string, number or bigint value fallbacks, including mixed primitive unions. Nullable inputs remain owned by @typescript-eslint/prefer-nullish-coalescing; both rules are enabled in the managed strict config.",
552
- "Preserves boolean aggregation, conditions, negations, left-hand && guards, and calls to the unshadowed Boolean constructor. Constant truthiness stays with no-unnecessary-condition. Unknown, any, generic, object-only and generated inputs are excluded. Strings and comments are never scanned as code.",
574
+ "Requires TypeScript type information and strict null checks. Reports non-nullable string, number or bigint value fallbacks, including branded primitives and mixed primitive unions. Nullable inputs, including nullable booleans, remain owned by @typescript-eslint/prefer-nullish-coalescing; both rules are enabled in the managed strict config.",
575
+ "Preserves non-nullable boolean aggregation, conditions, negations, left-hand && guards, and calls to the native unshadowed Boolean constructor, including erased TypeScript wrappers and globalThis/window/self access. Constant truthiness stays with no-unnecessary-condition. Unknown, any, unresolved generic, object-only and generated inputs are excluded. Strings and comments are never scanned as code.",
553
576
  "No automatic replacement is offered: replacing || with ?? would change empty-string or zero behavior. Non-nullable ||= expressions remain outside this companion rule."
554
577
  ],
555
578
  references: ["https://typescript-eslint.io/rules/prefer-nullish-coalescing/"],
@@ -577,83 +600,72 @@ var no_logical_or_fallback_default = createRule({
577
600
  if (!(options.strictNullChecks ?? options.strict ?? false)) return {};
578
601
  return {
579
602
  LogicalExpression(node) {
580
- if (node.operator !== "||" || booleanContext(node, context.sourceCode)) return;
603
+ if (node.operator !== "||" || booleanContext(node, context.sourceCode, services)) return;
581
604
  const type = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(node.left));
582
- const members = type.isUnion() ? type.types : [type];
583
- const primitiveFlags = ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike | ts.TypeFlags.BooleanLike;
584
- if (!members.every((member3) => (member3.flags & primitiveFlags) !== 0) || !members.some((member3) => (member3.flags & (ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike)) !== 0)) return;
585
- const truthiness = members.map(literalTruthiness);
605
+ const members = (type.isUnion() ? type.types : [type]).map(primitivePart);
606
+ if (members.some((member3) => member3 === void 0) || !members.some((member3) => member3 !== void 0 && (member3.flags & (ts.TypeFlags.StringLike | ts.TypeFlags.NumberLike | ts.TypeFlags.BigIntLike)) !== 0)) return;
607
+ const truthiness = members.map((member3) => member3 === void 0 ? void 0 : literalTruthiness(member3));
586
608
  if (truthiness.every((value) => value === true) || truthiness.every((value) => value === false)) return;
587
609
  context.report({ node, messageId: "logicalOrFallback" });
588
610
  }
589
611
  };
590
612
  }
591
613
  });
614
+ function primitivePart(type) {
615
+ if ((type.flags & PRIMITIVE_FLAGS) !== 0) return type;
616
+ if (!type.isIntersection() || type.types.some((member3) => (member3.flags & ts.TypeFlags.TypeParameter) !== 0)) return void 0;
617
+ return type.types.find((member3) => (member3.flags & PRIMITIVE_FLAGS) !== 0);
618
+ }
592
619
  function literalTruthiness(type) {
593
620
  if (type.isStringLiteral() || type.isNumberLiteral()) return Boolean(type.value);
594
621
  if (isBooleanLiteralType(type)) return type.intrinsicName === "true";
595
622
  if (isBigIntLiteralType(type)) return type.value.base10Value !== "0";
596
623
  return void 0;
597
624
  }
598
- function booleanContext(node, source) {
599
- let current = node;
625
+ function booleanContext(node, source, services) {
626
+ let current = outerExpression(node);
600
627
  while (current.parent !== void 0) {
601
628
  const parent = current.parent;
602
629
  switch (parent.type) {
603
- case AST_NODE_TYPES2.TSAsExpression:
604
- case AST_NODE_TYPES2.TSSatisfiesExpression:
605
- case AST_NODE_TYPES2.TSNonNullExpression:
606
- current = parent;
607
- continue;
608
- case AST_NODE_TYPES2.LogicalExpression:
630
+ case AST_NODE_TYPES3.LogicalExpression:
609
631
  if (parent.operator === "&&" && parent.left === current) return true;
610
- current = parent;
632
+ current = outerExpression(parent);
611
633
  continue;
612
- case AST_NODE_TYPES2.IfStatement:
613
- case AST_NODE_TYPES2.WhileStatement:
614
- case AST_NODE_TYPES2.DoWhileStatement:
615
- case AST_NODE_TYPES2.ForStatement:
616
- case AST_NODE_TYPES2.ConditionalExpression:
634
+ case AST_NODE_TYPES3.IfStatement:
635
+ case AST_NODE_TYPES3.WhileStatement:
636
+ case AST_NODE_TYPES3.DoWhileStatement:
637
+ case AST_NODE_TYPES3.ForStatement:
638
+ case AST_NODE_TYPES3.ConditionalExpression:
617
639
  return parent.test === current;
618
- case AST_NODE_TYPES2.UnaryExpression:
640
+ case AST_NODE_TYPES3.UnaryExpression:
619
641
  return parent.operator === "!";
620
- case AST_NODE_TYPES2.CallExpression:
621
- return parent.callee.type === AST_NODE_TYPES2.Identifier && parent.callee.name === "Boolean" && parent.arguments[0] === current && ASTUtils.findVariable(source.getScope(parent.callee), "Boolean")?.defs.length === 0;
642
+ case AST_NODE_TYPES3.CallExpression:
643
+ return parent.arguments[0] === current && nativeBoolean(parent.callee, source, services);
622
644
  default:
623
645
  return false;
624
646
  }
625
647
  }
626
648
  return false;
627
649
  }
628
-
629
- // src/rules/no-zod-parse-typed-object.ts
630
- import { ASTUtils as ASTUtils2, AST_NODE_TYPES as AST_NODE_TYPES4 } from "@typescript-eslint/utils";
631
- import ts2 from "typescript";
632
-
633
- // src/rules/_unwrap-expression.ts
634
- import { AST_NODE_TYPES as AST_NODE_TYPES3 } from "@typescript-eslint/utils";
635
- function unwrapExpression(node) {
636
- while (isErasedExpression(node)) {
637
- node = node.expression;
650
+ function nativeBoolean(node, source, services) {
651
+ const callee = unwrapExpression(node);
652
+ const checker = services.program.getTypeChecker();
653
+ let symbol;
654
+ if (callee.type === AST_NODE_TYPES3.Identifier && callee.name === "Boolean" && !ASTUtils.findVariable(source.getScope(callee), callee.name)?.defs.length) {
655
+ symbol = checker.getSymbolAtLocation(services.esTreeNodeToTSNodeMap.get(callee));
656
+ } else if (callee.type === AST_NODE_TYPES3.MemberExpression && ASTUtils.getPropertyName(callee) === "Boolean") {
657
+ const receiver = unwrapExpression(callee.object);
658
+ if (receiver.type !== AST_NODE_TYPES3.Identifier || !GLOBAL_RECEIVERS.has(receiver.name) || ASTUtils.findVariable(source.getScope(receiver), receiver.name)?.defs.length) return false;
659
+ symbol = checker.getTypeAtLocation(services.esTreeNodeToTSNodeMap.get(receiver)).getProperty("Boolean");
638
660
  }
639
- return node;
640
- }
641
- function outerExpression(node) {
642
- while (node.parent !== void 0 && node.parent !== null && isErasedExpression(node.parent) && node.parent.expression === node) node = node.parent;
643
- return node;
644
- }
645
- function directArgumentCall(node) {
646
- const argument = outerExpression(node);
647
- const call = argument.parent;
648
- return call?.type === AST_NODE_TYPES3.CallExpression && call.arguments.some((item) => item === argument) ? call : null;
649
- }
650
- function isErasedExpression(node) {
651
- return node.type === AST_NODE_TYPES3.TSAsExpression || node.type === AST_NODE_TYPES3.TSSatisfiesExpression || node.type === AST_NODE_TYPES3.TSNonNullExpression || node.type === AST_NODE_TYPES3.TSTypeAssertion;
661
+ return symbol?.declarations !== void 0 && symbol.declarations.length > 0 && symbol.declarations.every((declaration) => services.program.isSourceFileDefaultLibrary(declaration.getSourceFile()));
652
662
  }
653
663
 
654
664
  // src/rules/no-zod-parse-typed-object.ts
665
+ import { ASTUtils as ASTUtils2, AST_NODE_TYPES as AST_NODE_TYPES4 } from "@typescript-eslint/utils";
666
+ import { isTupleTypeReference } from "ts-api-utils";
667
+ import ts2 from "typescript";
655
668
  var PARSE_METHODS = /* @__PURE__ */ new Set(["parse", "parseAsync", "safeParse", "safeParseAsync"]);
656
- var TUPLE_INDEX_RE = /^(?:0|[1-9]\d*)$/u;
657
669
  var OPAQUE_FLAGS = ts2.TypeFlags.Any | ts2.TypeFlags.Unknown | ts2.TypeFlags.Never | ts2.TypeFlags.TypeParameter | ts2.TypeFlags.Conditional | ts2.TypeFlags.IndexedAccess | ts2.TypeFlags.Intersection | ts2.TypeFlags.NonPrimitive;
658
670
  var NO_ZOD_PARSE_TYPED_OBJECT_DOCUMENTATION = {
659
671
  defaultLevel: "warning",
@@ -666,7 +678,7 @@ var NO_ZOD_PARSE_TYPED_OBJECT_DOCUMENTATION = {
666
678
  "Requires type information, strict null checks, and a native installed Zod parse, parseAsync, safeParse or safeParseAsync signature. Recognizes imported schemas, aliases, member access and awaited service results without guessing from names.",
667
679
  "Reports fully known object or array inputs assignable to the schema input, when schema input and output have the same value shape. Optional-to-required defaults are included; type-changing transforms, coercions, brands, incompatible contracts, primitive roots and nested any/unknown/generic contracts are excluded.",
668
680
  "Static types do not establish runtime trust or prove refinements and normalization redundant. This is an architectural warning with no automatic removal. Keep intentional validation at an unknown-data boundary or document an exact local suppression. Tests, stories and generated code are excluded.",
669
- "Shape comparison ignores undefined introduced by optional properties and is bounded to 128 object pairs or visited input objects. Opaque or larger graphs are conservatively excluded."
681
+ "Shape comparison ignores undefined introduced by optional properties and checks tuple element types and rest positions. It is bounded to 128 object pairs, visited input objects, properties, tuple elements or primitive union alternatives; object unions have at most 16 alternatives. Opaque or larger graphs are conservatively excluded."
670
682
  ],
671
683
  references: ["https://zod.dev/basics"],
672
684
  examples: [
@@ -726,7 +738,11 @@ function knownValue(checker, type, location, seen) {
726
738
  if (seen.has(type)) return true;
727
739
  if (seen.size >= 128 || type.getCallSignatures().length > 0 || type.getConstructSignatures().length > 0) return false;
728
740
  seen.add(type);
729
- if (checker.isArrayType(type) || checker.isTupleType(type)) {
741
+ if (isTupleTypeReference(type)) {
742
+ const elements = checker.getTypeArguments(type);
743
+ return elements.length <= 128 && elements.every((element) => knownValue(checker, element, location, seen));
744
+ }
745
+ if (checker.isArrayType(type)) {
730
746
  const element = type.getNumberIndexType();
731
747
  return element !== void 0 && knownValue(checker, element, location, seen);
732
748
  }
@@ -742,7 +758,8 @@ function sameShape(checker, input, output, location) {
742
758
  if (left.isUnion() || right.isUnion()) {
743
759
  const a = (left.isUnion() ? left.types : [left]).filter((member3) => (member3.flags & ts2.TypeFlags.Undefined) === 0);
744
760
  const b = (right.isUnion() ? right.types : [right]).filter((member3) => (member3.flags & ts2.TypeFlags.Undefined) === 0);
745
- return a.length > 0 && a.length === b.length && a.length <= 16 && a.every((member3) => b.some((other) => compare(member3, other))) && b.every((member3) => a.some((other) => compare(other, member3)));
761
+ const limit = [...a, ...b].every((member3) => (member3.flags & (ts2.TypeFlags.Object | OPAQUE_FLAGS)) === 0) ? 128 : 16;
762
+ return a.length > 0 && a.length === b.length && a.length <= limit && a.every((member3) => b.some((other) => compare(member3, other))) && b.every((member3) => a.some((other) => compare(other, member3)));
746
763
  }
747
764
  if ((left.flags & ts2.TypeFlags.Object) === 0 || (right.flags & ts2.TypeFlags.Object) === 0) {
748
765
  return checker.isTypeAssignableTo(left, right) && checker.isTypeAssignableTo(right, left);
@@ -760,9 +777,9 @@ function sameShape(checker, input, output, location) {
760
777
  function sameObjectShape(left, right) {
761
778
  const leftTuple = checker.isTupleType(left);
762
779
  const rightTuple = checker.isTupleType(right);
763
- if (leftTuple !== rightTuple || leftTuple && !sameTuplePositions(left, right)) return false;
764
- if (checker.isArrayType(left) || leftTuple) {
765
- if (!checker.isArrayType(right) && !rightTuple) return false;
780
+ if (leftTuple || rightTuple) return leftTuple && rightTuple && sameTuplePositions(left, right);
781
+ if (checker.isArrayType(left)) {
782
+ if (!checker.isArrayType(right)) return false;
766
783
  const a2 = left.getNumberIndexType();
767
784
  const b2 = right.getNumberIndexType();
768
785
  return a2 !== void 0 && b2 !== void 0 && compare(a2, b2);
@@ -778,17 +795,13 @@ function sameShape(checker, input, output, location) {
778
795
  return a.length === b.length && a.every((index) => b.some((other) => checker.isTypeAssignableTo(index.keyType, other.keyType) && checker.isTypeAssignableTo(other.keyType, index.keyType) && compare(index.type, other.type)));
779
796
  }
780
797
  function sameTuplePositions(left, right) {
781
- const leftLength = left.getProperty("length");
782
- const rightLength = right.getProperty("length");
783
- if (leftLength === void 0 || rightLength === void 0) return false;
784
- const a = checker.getTypeOfSymbolAtLocation(leftLength, location);
785
- const b = checker.getTypeOfSymbolAtLocation(rightLength, location);
786
- if (!checker.isTypeAssignableTo(a, b) || !checker.isTypeAssignableTo(b, a)) return false;
787
- const properties = left.getProperties().filter((property) => TUPLE_INDEX_RE.test(property.name));
788
- const otherProperties = right.getProperties().filter((property) => TUPLE_INDEX_RE.test(property.name));
789
- return properties.length <= 128 && properties.length === otherProperties.length && properties.every((property) => {
790
- const other = right.getProperty(property.name);
791
- return other !== void 0 && compare(checker.getTypeOfSymbolAtLocation(property, location), checker.getTypeOfSymbolAtLocation(other, location));
798
+ if (!isTupleTypeReference(left) || !isTupleTypeReference(right)) return false;
799
+ const a = checker.getTypeArguments(left);
800
+ const b = checker.getTypeArguments(right);
801
+ const flags = right.target.elementFlags;
802
+ return a.length <= 128 && a.length === b.length && left.target.elementFlags.every((flag, index) => flag === flags[index]) && a.every((element, index) => {
803
+ const other = b[index];
804
+ return other !== void 0 && compare(element, other);
792
805
  });
793
806
  }
794
807
  return compare(input, output);
@@ -837,7 +850,7 @@ function stableValueBinding(variable, acceptRead) {
837
850
  var VIEWS = /* @__PURE__ */ new WeakMap();
838
851
  function renderFunction(node) {
839
852
  let parent = node.parent;
840
- while (parent !== void 0) {
853
+ while (parent !== void 0 && parent !== null) {
841
854
  if (isFunction(parent)) {
842
855
  let view = VIEWS.get(parent);
843
856
  if (view === void 0) {
@@ -2465,7 +2478,7 @@ function nativeRead(node, name) {
2465
2478
  }
2466
2479
 
2467
2480
  // src/rules/_native-fetch-reference.ts
2468
- var GLOBAL_RECEIVERS = /* @__PURE__ */ new Set(["globalThis", "self", "window"]);
2481
+ var GLOBAL_RECEIVERS2 = /* @__PURE__ */ new Set(["globalThis", "self", "window"]);
2469
2482
  function nativeFetchReference(node, sourceCode) {
2470
2483
  return lexicalFetchReference(node, sourceCode) && nativeRuntimeUnchanged(sourceCode, "fetch");
2471
2484
  }
@@ -2488,7 +2501,7 @@ function lexicalFetchReference(node, sourceCode, seen = /* @__PURE__ */ new Set(
2488
2501
  }
2489
2502
  function globalReceiver(node, sourceCode) {
2490
2503
  const receiver = unwrapExpression(node);
2491
- return receiver.type === AST_NODE_TYPES20.Identifier && GLOBAL_RECEIVERS.has(receiver.name) && !ASTUtils10.findVariable(sourceCode.getScope(receiver), receiver.name)?.defs.length;
2504
+ return receiver.type === AST_NODE_TYPES20.Identifier && GLOBAL_RECEIVERS2.has(receiver.name) && !ASTUtils10.findVariable(sourceCode.getScope(receiver), receiver.name)?.defs.length;
2492
2505
  }
2493
2506
 
2494
2507
  // src/rules/_test-mock-provenance.ts
@@ -5481,7 +5494,7 @@ function isSearchParamReceiver(call, services) {
5481
5494
  // package.json
5482
5495
  var package_default = {
5483
5496
  name: "@sarj/eslint-plugin",
5484
- version: "18.0.0",
5497
+ version: "18.0.3",
5485
5498
  packageManager: "npm@12.2.1",
5486
5499
  description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
5487
5500
  type: "module",
@@ -14769,7 +14782,7 @@ var NO_DETACHED_GLOBAL_FETCH_DOCUMENTATION = {
14769
14782
  }
14770
14783
  ]
14771
14784
  };
14772
- var GLOBAL_RECEIVERS2 = /* @__PURE__ */ new Set([
14785
+ var GLOBAL_RECEIVERS3 = /* @__PURE__ */ new Set([
14773
14786
  "globalThis",
14774
14787
  "self",
14775
14788
  "window"
@@ -14816,7 +14829,7 @@ var no_detached_global_fetch_default = createRule({
14816
14829
  return variable === null || variable.defs.length === 0;
14817
14830
  }
14818
14831
  function isGlobalReceiver(node) {
14819
- return node.type === AST_NODE_TYPES85.Identifier && GLOBAL_RECEIVERS2.has(node.name) && resolvesToGlobal(node);
14832
+ return node.type === AST_NODE_TYPES85.Identifier && GLOBAL_RECEIVERS3.has(node.name) && resolvesToGlobal(node);
14820
14833
  }
14821
14834
  function recordAlias(identifier) {
14822
14835
  const variable = bindingOf(identifier);
@@ -14875,7 +14888,7 @@ var no_detached_global_fetch_default = createRule({
14875
14888
  return false;
14876
14889
  if (node.type !== AST_NODE_TYPES85.Identifier || !resolvesToGlobal(node))
14877
14890
  return false;
14878
- return GLOBAL_RECEIVERS2.has(node.name) || node.name === "undefined";
14891
+ return GLOBAL_RECEIVERS3.has(node.name) || node.name === "undefined";
14879
14892
  }
14880
14893
  return {
14881
14894
  AssignmentExpression(node) {
@@ -16163,7 +16176,7 @@ var EQUALITY_OPERATORS = /* @__PURE__ */ new Set([
16163
16176
  "==",
16164
16177
  "==="
16165
16178
  ]);
16166
- var PRIMITIVE_FLAGS = ts30.TypeFlags.BigIntLike | ts30.TypeFlags.BooleanLike | ts30.TypeFlags.ESSymbolLike | ts30.TypeFlags.Never | ts30.TypeFlags.Null | ts30.TypeFlags.NumberLike | ts30.TypeFlags.StringLike | ts30.TypeFlags.Undefined | ts30.TypeFlags.Void;
16179
+ var PRIMITIVE_FLAGS2 = ts30.TypeFlags.BigIntLike | ts30.TypeFlags.BooleanLike | ts30.TypeFlags.ESSymbolLike | ts30.TypeFlags.Never | ts30.TypeFlags.Null | ts30.TypeFlags.NumberLike | ts30.TypeFlags.StringLike | ts30.TypeFlags.Undefined | ts30.TypeFlags.Void;
16167
16180
  function unwrapComparisonExpression(node) {
16168
16181
  let current = unwrapExpression(node);
16169
16182
  while (current.type === AST_NODE_TYPES90.ChainExpression) {
@@ -16217,7 +16230,7 @@ function typeMayContainObject(type, checker) {
16217
16230
  if (type.isUnionOrIntersection()) {
16218
16231
  return type.types.some((member3) => typeMayContainObject(member3, checker));
16219
16232
  }
16220
- if ((type.flags & PRIMITIVE_FLAGS) !== 0) return false;
16233
+ if ((type.flags & PRIMITIVE_FLAGS2) !== 0) return false;
16221
16234
  if ((type.flags & (ts30.TypeFlags.Any | ts30.TypeFlags.Unknown | ts30.TypeFlags.TypeParameter)) !== 0) {
16222
16235
  return true;
16223
16236
  }
@@ -33440,7 +33453,7 @@ import { ASTUtils as ASTUtils111, AST_NODE_TYPES as AST_NODE_TYPES165 } from "@t
33440
33453
  import ts39 from "typescript";
33441
33454
 
33442
33455
  // src/rules/_equivalent-zod-output-contracts.ts
33443
- import { isPropertyReadonlyInType, isTupleTypeReference, isTypeReference as isTypeReference3 } from "ts-api-utils";
33456
+ import { isPropertyReadonlyInType, isTupleTypeReference as isTupleTypeReference2, isTypeReference as isTypeReference3 } from "ts-api-utils";
33444
33457
  import ts37 from "typescript";
33445
33458
  var MAX_CONTRACT_PAIRS = 128;
33446
33459
  var MAX_UNION_MEMBERS = 16;
@@ -33469,8 +33482,8 @@ function seenPair(comparison2, left, right) {
33469
33482
  function equivalentPair(comparison2, left, right) {
33470
33483
  if (!mutuallyAssignable(comparison2.checker, left, right)) return false;
33471
33484
  if (left.isUnion() || right.isUnion()) return equivalentUnions(comparison2, left, right);
33472
- const leftContainer = comparison2.checker.isArrayType(left) || isTupleTypeReference(left);
33473
- const rightContainer = comparison2.checker.isArrayType(right) || isTupleTypeReference(right);
33485
+ const leftContainer = comparison2.checker.isArrayType(left) || isTupleTypeReference2(left);
33486
+ const rightContainer = comparison2.checker.isArrayType(right) || isTupleTypeReference2(right);
33474
33487
  if (leftContainer || rightContainer) return equivalentContainers(comparison2, left, right);
33475
33488
  if (hasClassDeclaration(left) || hasClassDeclaration(right)) return false;
33476
33489
  if (!objectLike(left) || !objectLike(right)) return false;
@@ -33500,8 +33513,8 @@ function queuePair(comparison2, left, right) {
33500
33513
  }
33501
33514
  function equivalentContainers(comparison2, left, right) {
33502
33515
  if (!isTypeReference3(left) || !isTypeReference3(right)) return false;
33503
- const leftTuple = isTupleTypeReference(left);
33504
- const rightTuple = isTupleTypeReference(right);
33516
+ const leftTuple = isTupleTypeReference2(left);
33517
+ const rightTuple = isTupleTypeReference2(right);
33505
33518
  if (leftTuple !== rightTuple) return false;
33506
33519
  if (leftTuple && rightTuple && (left.target.readonly !== right.target.readonly || left.target.elementFlags.length !== right.target.elementFlags.length || left.target.elementFlags.some((flag, index) => flag !== right.target.elementFlags[index]))) return false;
33507
33520
  const leftIndex = comparison2.checker.getIndexInfoOfType(left, ts37.IndexKind.Number);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sarj/eslint-plugin",
3
- "version": "18.0.0",
3
+ "version": "18.0.3",
4
4
  "packageManager": "npm@12.2.1",
5
5
  "description": "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
6
6
  "type": "module",