@sarj/eslint-plugin 16.5.0 → 16.5.1

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
@@ -52,7 +52,7 @@ module.exports = __toCommonJS(src_exports);
52
52
  // package.json
53
53
  var package_default = {
54
54
  name: "@sarj/eslint-plugin",
55
- version: "16.5.0",
55
+ version: "16.5.1",
56
56
  packageManager: "npm@12.1.0",
57
57
  description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
58
58
  type: "module",
@@ -2017,13 +2017,21 @@ function attributeText(node, name) {
2017
2017
  }
2018
2018
  return attribute.value === null ? "" : staticText(attribute.value);
2019
2019
  }
2020
- function isHidden(node) {
2020
+ function isHidden(node, source) {
2021
2021
  if (attributeText(node, "aria-hidden") === "true") return true;
2022
2022
  const hidden = node.attributes.findLast(
2023
2023
  (attribute) => attribute.type === import_utils11.AST_NODE_TYPES.JSXSpreadAttribute || attribute.name.type === import_utils11.AST_NODE_TYPES.JSXIdentifier && attribute.name.name === "hidden"
2024
2024
  );
2025
2025
  if (hidden?.type !== import_utils11.AST_NODE_TYPES.JSXAttribute) return false;
2026
2026
  if (hidden.value === null) return true;
2027
+ if (hidden.value.type === import_utils11.AST_NODE_TYPES.JSXExpressionContainer) {
2028
+ const value = hidden.value.expression;
2029
+ if (value.type === import_utils11.AST_NODE_TYPES.Identifier && value.name === "undefined") {
2030
+ const binding = import_utils11.ASTUtils.findVariable(source.getScope(value), value.name);
2031
+ if (binding === null || binding.defs.length === 0) return false;
2032
+ }
2033
+ if (value.type === import_utils11.AST_NODE_TYPES.UnaryExpression && value.operator === "void" && value.argument.type === import_utils11.AST_NODE_TYPES.Literal && value.argument.value === 0) return false;
2034
+ }
2027
2035
  if (hidden.value.type === import_utils11.AST_NODE_TYPES.JSXExpressionContainer && hidden.value.expression.type === import_utils11.AST_NODE_TYPES.Literal)
2028
2036
  return hidden.value.expression.value !== false && hidden.value.expression.value !== null;
2029
2037
  return true;
@@ -2054,7 +2062,7 @@ function childrenNameStatus(children, source, iconModules) {
2054
2062
  return childrenNameStatus(child.children, source, iconModules);
2055
2063
  if (child.type !== import_utils11.AST_NODE_TYPES.JSXElement) return "unknown";
2056
2064
  const opening = child.openingElement;
2057
- if (isHidden(opening)) return "empty";
2065
+ if (isHidden(opening, source)) return "empty";
2058
2066
  const imported = importedComponent(opening.name, source);
2059
2067
  const intrinsic = opening.name.type === import_utils11.AST_NODE_TYPES.JSXIdentifier && /^[a-z]/u.test(opening.name.name);
2060
2068
  if (!intrinsic && (imported === null || !iconModules.includes(imported.module)))
@@ -2080,7 +2088,7 @@ function isPassedAsProp(node, source) {
2080
2088
  }
2081
2089
  function hasHiddenAncestor(node, source) {
2082
2090
  return source.getAncestors(node).some(
2083
- (ancestor) => ancestor.type === import_utils11.AST_NODE_TYPES.JSXElement && isHidden(ancestor.openingElement)
2091
+ (ancestor) => ancestor.type === import_utils11.AST_NODE_TYPES.JSXElement && isHidden(ancestor.openingElement, source)
2084
2092
  );
2085
2093
  }
2086
2094
  function textNameStatus(text) {
@@ -2096,7 +2104,8 @@ var REQUIRE_BUTTON_ACCESSIBLE_NAME_DOCUMENTATION = {
2096
2104
  category: "correctness",
2097
2105
  limitations: [
2098
2106
  "Native button and conventional Button elements are checked by default. Other custom buttons require exact module/export configuration; aliases and namespace imports are resolved by scope. Lucide icons are recognized by default; other icon modules are configurable.",
2099
- "Composed JSX passed as props, render/asChild adapters, dynamic labels, children, unknown components, and prop spreads are left to runtime accessibility testing. Referenced IDs, CSS visibility, and meaningful wording are not verified. Generated files, tests, fixtures, and stories are excluded. No automatic labels are invented."
2107
+ "Composed JSX passed as props, render/asChild adapters, dynamic labels, children, unknown components, and prop spreads are left to runtime accessibility testing. Referenced IDs, CSS visibility, and meaningful wording are not verified. Generated files, tests, fixtures, and stories are excluded. No automatic labels are invented.",
2108
+ "A hidden prop with unshadowed undefined or exact void 0 does not hide the element or its children. Shadowed undefined and dynamic hidden values remain unproven."
2100
2109
  ],
2101
2110
  examples: [
2102
2111
  {
@@ -2174,7 +2183,7 @@ var require_button_accessible_name_default = createRule({
2174
2183
  return;
2175
2184
  if (isPassedAsProp(node, context.sourceCode) || hasHiddenAncestor(node, context.sourceCode))
2176
2185
  return;
2177
- if (isHidden(opening) || attributeNameStatus(opening) !== "empty")
2186
+ if (isHidden(opening, context.sourceCode) || attributeNameStatus(opening) !== "empty")
2178
2187
  return;
2179
2188
  if (childrenNameStatus(node.children, context.sourceCode, iconModules) !== "empty")
2180
2189
  return;
@@ -2270,7 +2279,8 @@ var REQUIRE_SVG_ACCESSIBLE_NAME_DOCUMENTATION = {
2270
2279
  remediation: "Add aria-label, aria-labelledby, or a direct title child; mark decorative graphics aria-hidden or presentational.",
2271
2280
  category: "correctness",
2272
2281
  limitations: [
2273
- "Only intrinsic svg elements are checked. Dynamic labels, forwarded props, and dynamic title content remain runtime concerns. IDs, CSS visibility and graphic meaning are not inferred. Tests, stories, fixtures and generated files are excluded. No automatic title or decorative marker is invented."
2282
+ "Only intrinsic svg elements are checked. Dynamic labels, forwarded props, and dynamic title content remain runtime concerns. IDs, CSS visibility and graphic meaning are not inferred. Tests, stories, fixtures and generated files are excluded. No automatic title or decorative marker is invented.",
2283
+ "A hidden prop with unshadowed undefined or exact void 0 does not hide the element. Shadowed undefined and dynamic hidden values remain unproven."
2274
2284
  ],
2275
2285
  examples: [
2276
2286
  {
@@ -2320,7 +2330,7 @@ var require_svg_accessible_name_default = createRule({
2320
2330
  return;
2321
2331
  if (isPassedAsProp(node, context.sourceCode) || hasHiddenAncestor(node, context.sourceCode))
2322
2332
  return;
2323
- if (isHidden(opening) || ["none", "presentation"].includes(
2333
+ if (isHidden(opening, context.sourceCode) || ["none", "presentation"].includes(
2324
2334
  attributeText(opening, "role") ?? ""
2325
2335
  ))
2326
2336
  return;
@@ -6987,7 +6997,7 @@ var NO_JSON_STRINGIFY_ERROR_DOCUMENTATION = {
6987
6997
  rationale: "Native Error details are non-enumerable, so generic JSON serialization discards diagnostic information.",
6988
6998
  remediation: "Serialize explicit error fields or use an error-aware serializer.",
6989
6999
  category: "correctness",
6990
- limitations: ["The rule uses stable local catch bindings and unshadowed built-in constructors, not runtime type information. Custom replacers and explicit toJSON hooks are left to their serializer contract; a catch value is not guaranteed to be an Error. Member values, including cause, do not inherit the base Error's provenance; even an Error-valued member requires explicit value/dataflow proof outside this rule. Known literal __proto__ initializer chains preserve native hook inheritance and own toJSON precedence; computed __proto__ keys remain data. Unknown prototype expressions, hook values/spreads and deferred hook writes conservatively lose default serializer proof. Explicit writes invalidate constructor provenance except a later, separate top-level statement; deferred functions, loops, and unknown property keys conservatively lose constructor proof. Statically owned global/property writes and native Reflect.set/Reflect.defineProperty/Object.defineProperty/Object.defineProperties calls are tracked. Mutator aliases, replaced Reflect/Object methods, external calls, and runtime-only property names are not resolved; uncertain ordering conservatively loses proof."],
7000
+ limitations: ["The rule uses stable local catch bindings and unshadowed built-in constructors, not runtime type information. Native DOMException constructor coverage is validated in Node; browser serialization is not evaluated. Custom replacers and explicit toJSON hooks are left to their serializer contract; a catch value is not guaranteed to be an Error. Member values, including cause, do not inherit the base Error's provenance; even an Error-valued member requires explicit value/dataflow proof outside this rule. Known literal __proto__ initializer chains preserve native hook inheritance and own toJSON precedence; computed __proto__ keys remain data. Unknown prototype expressions, hook values/spreads and deferred hook writes conservatively lose default serializer proof. Explicit writes invalidate constructor provenance except a later, separate top-level statement; deferred functions, loops, and unknown property keys conservatively lose constructor proof. Statically owned global/property writes and native Reflect.set/Reflect.defineProperty/Object.defineProperty/Object.defineProperties calls are tracked. Mutator aliases, replaced Reflect/Object methods, external calls, and runtime-only property names are not resolved; uncertain ordering conservatively loses proof."],
6991
7001
  examples: [
6992
7002
  { id: "explicit-error-message", title: "Narrow an unknown catch value before selecting fields", outcome: "no-match", files: [{ path: "src/report.ts", source: "try { f(); } catch (err) { JSON.stringify({ error: err instanceof Error ? err.message : String(err) }); }" }], focusPath: "src/report.ts", expectedCount: 0, public: true },
6993
7003
  { id: "stringified-error", title: "Do not stringify an Error object", outcome: "match", files: [{ path: "src/report.ts", source: "try { f(); } catch (err) { JSON.stringify({ error: err }); }" }], focusPath: "src/report.ts", expectedCount: 1, public: true },
@@ -7009,6 +7019,7 @@ var NO_JSON_STRINGIFY_ERROR_DOCUMENTATION = {
7009
7019
  };
7010
7020
  var BUILTIN_ERROR_CONSTRUCTORS = /* @__PURE__ */ new Set([
7011
7021
  "AggregateError",
7022
+ "DOMException",
7012
7023
  "Error",
7013
7024
  "EvalError",
7014
7025
  "RangeError",
@@ -11852,7 +11863,7 @@ var NO_SILENT_PROMISE_CATCH_DOCUMENTATION = {
11852
11863
  rationale: "A swallowed rejection hides failures and gives callers an indistinguishable fallback value.",
11853
11864
  remediation: "Log, rethrow, or explicitly recover from the rejection; explain intentional teardown suppression.",
11854
11865
  category: "correctness",
11855
- limitations: ["Test files, teardown calls, explanatory comments, non-function handlers, and handlers that consume or report the error are excluded.", "Recognized imported Zod construction chains and their stable local aliases are excluded. Other untyped catch-like APIs are not proven to be Promises.", "Computed methods resolve literal syntax and stable local string aliases in lexical scope. Function-derived, object-derived and mutated computed keys remain unproven."],
11866
+ limitations: ["Test files, teardown calls, explanatory comments, non-function handlers, and handlers that consume or report the error are excluded.", "Recognized imported Zod construction chains and their stable local aliases are excluded, including URL schemas and primitive bigint, boolean, number and string coercion. Other untyped catch-like APIs are not proven to be Promises.", "Computed methods resolve literal syntax and stable local string aliases in lexical scope. Function-derived, object-derived and mutated computed keys remain unproven."],
11856
11867
  examples: [
11857
11868
  { id: "reported-rejection", title: "Report the rejection", outcome: "no-match", files: [{ path: "src/load.ts", source: "load().catch((error) => logger.error({ error }, 'load failed'));" }], focusPath: "src/load.ts", expectedCount: 0, public: true },
11858
11869
  { id: "silent-rejection", title: "Do not swallow the rejection", outcome: "match", files: [{ path: "src/load.ts", source: "load().catch(() => null);" }], focusPath: "src/load.ts", expectedCount: 1, public: true },
@@ -11888,7 +11899,8 @@ var ZOD_CONSTRUCTORS = /* @__PURE__ */ new Set([
11888
11899
  "tuple",
11889
11900
  "undefined",
11890
11901
  "union",
11891
- "unknown"
11902
+ "unknown",
11903
+ "url"
11892
11904
  ]);
11893
11905
  var ZOD_CHAIN_METHODS = /* @__PURE__ */ new Set([
11894
11906
  "array",
@@ -11996,8 +12008,9 @@ var no_silent_promise_catch_default = createRule({
11996
12008
  return binding.defs.length === 1 && definition?.node.type === import_utils68.AST_NODE_TYPES.VariableDeclarator && definition.node.init !== null && isZodSchema(definition.node.init, seen);
11997
12009
  }
11998
12010
  if (node.type !== import_utils68.AST_NODE_TYPES.CallExpression || unwrappedNodeCallee?.type !== import_utils68.AST_NODE_TYPES.MemberExpression) return false;
11999
- const { object } = unwrappedNodeCallee;
12011
+ let { object } = unwrappedNodeCallee;
12000
12012
  const method = staticPropertyName(unwrappedNodeCallee, context.sourceCode);
12013
+ if (object.type === import_utils68.AST_NODE_TYPES.MemberExpression && staticPropertyName(object, context.sourceCode) === "coerce" && method !== null && ["bigint", "boolean", "number", "string"].includes(method)) object = object.object;
12001
12014
  if (object.type === import_utils68.AST_NODE_TYPES.Identifier && method !== null && ZOD_CONSTRUCTORS.has(method)) {
12002
12015
  const binding = import_utils68.ASTUtils.findVariable(context.sourceCode.getScope(object), object.name);
12003
12016
  if (binding?.defs.some((definition) => {
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "@sarj/eslint-plugin",
4
- version: "16.5.0",
4
+ version: "16.5.1",
5
5
  packageManager: "npm@12.1.0",
6
6
  description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
7
7
  type: "module",
@@ -1976,13 +1976,21 @@ function attributeText(node, name) {
1976
1976
  }
1977
1977
  return attribute.value === null ? "" : staticText(attribute.value);
1978
1978
  }
1979
- function isHidden(node) {
1979
+ function isHidden(node, source) {
1980
1980
  if (attributeText(node, "aria-hidden") === "true") return true;
1981
1981
  const hidden = node.attributes.findLast(
1982
1982
  (attribute) => attribute.type === AST_NODE_TYPES9.JSXSpreadAttribute || attribute.name.type === AST_NODE_TYPES9.JSXIdentifier && attribute.name.name === "hidden"
1983
1983
  );
1984
1984
  if (hidden?.type !== AST_NODE_TYPES9.JSXAttribute) return false;
1985
1985
  if (hidden.value === null) return true;
1986
+ if (hidden.value.type === AST_NODE_TYPES9.JSXExpressionContainer) {
1987
+ const value = hidden.value.expression;
1988
+ if (value.type === AST_NODE_TYPES9.Identifier && value.name === "undefined") {
1989
+ const binding = ASTUtils4.findVariable(source.getScope(value), value.name);
1990
+ if (binding === null || binding.defs.length === 0) return false;
1991
+ }
1992
+ if (value.type === AST_NODE_TYPES9.UnaryExpression && value.operator === "void" && value.argument.type === AST_NODE_TYPES9.Literal && value.argument.value === 0) return false;
1993
+ }
1986
1994
  if (hidden.value.type === AST_NODE_TYPES9.JSXExpressionContainer && hidden.value.expression.type === AST_NODE_TYPES9.Literal)
1987
1995
  return hidden.value.expression.value !== false && hidden.value.expression.value !== null;
1988
1996
  return true;
@@ -2013,7 +2021,7 @@ function childrenNameStatus(children, source, iconModules) {
2013
2021
  return childrenNameStatus(child.children, source, iconModules);
2014
2022
  if (child.type !== AST_NODE_TYPES9.JSXElement) return "unknown";
2015
2023
  const opening = child.openingElement;
2016
- if (isHidden(opening)) return "empty";
2024
+ if (isHidden(opening, source)) return "empty";
2017
2025
  const imported = importedComponent(opening.name, source);
2018
2026
  const intrinsic = opening.name.type === AST_NODE_TYPES9.JSXIdentifier && /^[a-z]/u.test(opening.name.name);
2019
2027
  if (!intrinsic && (imported === null || !iconModules.includes(imported.module)))
@@ -2039,7 +2047,7 @@ function isPassedAsProp(node, source) {
2039
2047
  }
2040
2048
  function hasHiddenAncestor(node, source) {
2041
2049
  return source.getAncestors(node).some(
2042
- (ancestor) => ancestor.type === AST_NODE_TYPES9.JSXElement && isHidden(ancestor.openingElement)
2050
+ (ancestor) => ancestor.type === AST_NODE_TYPES9.JSXElement && isHidden(ancestor.openingElement, source)
2043
2051
  );
2044
2052
  }
2045
2053
  function textNameStatus(text) {
@@ -2055,7 +2063,8 @@ var REQUIRE_BUTTON_ACCESSIBLE_NAME_DOCUMENTATION = {
2055
2063
  category: "correctness",
2056
2064
  limitations: [
2057
2065
  "Native button and conventional Button elements are checked by default. Other custom buttons require exact module/export configuration; aliases and namespace imports are resolved by scope. Lucide icons are recognized by default; other icon modules are configurable.",
2058
- "Composed JSX passed as props, render/asChild adapters, dynamic labels, children, unknown components, and prop spreads are left to runtime accessibility testing. Referenced IDs, CSS visibility, and meaningful wording are not verified. Generated files, tests, fixtures, and stories are excluded. No automatic labels are invented."
2066
+ "Composed JSX passed as props, render/asChild adapters, dynamic labels, children, unknown components, and prop spreads are left to runtime accessibility testing. Referenced IDs, CSS visibility, and meaningful wording are not verified. Generated files, tests, fixtures, and stories are excluded. No automatic labels are invented.",
2067
+ "A hidden prop with unshadowed undefined or exact void 0 does not hide the element or its children. Shadowed undefined and dynamic hidden values remain unproven."
2059
2068
  ],
2060
2069
  examples: [
2061
2070
  {
@@ -2133,7 +2142,7 @@ var require_button_accessible_name_default = createRule({
2133
2142
  return;
2134
2143
  if (isPassedAsProp(node, context.sourceCode) || hasHiddenAncestor(node, context.sourceCode))
2135
2144
  return;
2136
- if (isHidden(opening) || attributeNameStatus(opening) !== "empty")
2145
+ if (isHidden(opening, context.sourceCode) || attributeNameStatus(opening) !== "empty")
2137
2146
  return;
2138
2147
  if (childrenNameStatus(node.children, context.sourceCode, iconModules) !== "empty")
2139
2148
  return;
@@ -2229,7 +2238,8 @@ var REQUIRE_SVG_ACCESSIBLE_NAME_DOCUMENTATION = {
2229
2238
  remediation: "Add aria-label, aria-labelledby, or a direct title child; mark decorative graphics aria-hidden or presentational.",
2230
2239
  category: "correctness",
2231
2240
  limitations: [
2232
- "Only intrinsic svg elements are checked. Dynamic labels, forwarded props, and dynamic title content remain runtime concerns. IDs, CSS visibility and graphic meaning are not inferred. Tests, stories, fixtures and generated files are excluded. No automatic title or decorative marker is invented."
2241
+ "Only intrinsic svg elements are checked. Dynamic labels, forwarded props, and dynamic title content remain runtime concerns. IDs, CSS visibility and graphic meaning are not inferred. Tests, stories, fixtures and generated files are excluded. No automatic title or decorative marker is invented.",
2242
+ "A hidden prop with unshadowed undefined or exact void 0 does not hide the element. Shadowed undefined and dynamic hidden values remain unproven."
2233
2243
  ],
2234
2244
  examples: [
2235
2245
  {
@@ -2279,7 +2289,7 @@ var require_svg_accessible_name_default = createRule({
2279
2289
  return;
2280
2290
  if (isPassedAsProp(node, context.sourceCode) || hasHiddenAncestor(node, context.sourceCode))
2281
2291
  return;
2282
- if (isHidden(opening) || ["none", "presentation"].includes(
2292
+ if (isHidden(opening, context.sourceCode) || ["none", "presentation"].includes(
2283
2293
  attributeText(opening, "role") ?? ""
2284
2294
  ))
2285
2295
  return;
@@ -6954,7 +6964,7 @@ var NO_JSON_STRINGIFY_ERROR_DOCUMENTATION = {
6954
6964
  rationale: "Native Error details are non-enumerable, so generic JSON serialization discards diagnostic information.",
6955
6965
  remediation: "Serialize explicit error fields or use an error-aware serializer.",
6956
6966
  category: "correctness",
6957
- limitations: ["The rule uses stable local catch bindings and unshadowed built-in constructors, not runtime type information. Custom replacers and explicit toJSON hooks are left to their serializer contract; a catch value is not guaranteed to be an Error. Member values, including cause, do not inherit the base Error's provenance; even an Error-valued member requires explicit value/dataflow proof outside this rule. Known literal __proto__ initializer chains preserve native hook inheritance and own toJSON precedence; computed __proto__ keys remain data. Unknown prototype expressions, hook values/spreads and deferred hook writes conservatively lose default serializer proof. Explicit writes invalidate constructor provenance except a later, separate top-level statement; deferred functions, loops, and unknown property keys conservatively lose constructor proof. Statically owned global/property writes and native Reflect.set/Reflect.defineProperty/Object.defineProperty/Object.defineProperties calls are tracked. Mutator aliases, replaced Reflect/Object methods, external calls, and runtime-only property names are not resolved; uncertain ordering conservatively loses proof."],
6967
+ limitations: ["The rule uses stable local catch bindings and unshadowed built-in constructors, not runtime type information. Native DOMException constructor coverage is validated in Node; browser serialization is not evaluated. Custom replacers and explicit toJSON hooks are left to their serializer contract; a catch value is not guaranteed to be an Error. Member values, including cause, do not inherit the base Error's provenance; even an Error-valued member requires explicit value/dataflow proof outside this rule. Known literal __proto__ initializer chains preserve native hook inheritance and own toJSON precedence; computed __proto__ keys remain data. Unknown prototype expressions, hook values/spreads and deferred hook writes conservatively lose default serializer proof. Explicit writes invalidate constructor provenance except a later, separate top-level statement; deferred functions, loops, and unknown property keys conservatively lose constructor proof. Statically owned global/property writes and native Reflect.set/Reflect.defineProperty/Object.defineProperty/Object.defineProperties calls are tracked. Mutator aliases, replaced Reflect/Object methods, external calls, and runtime-only property names are not resolved; uncertain ordering conservatively loses proof."],
6958
6968
  examples: [
6959
6969
  { id: "explicit-error-message", title: "Narrow an unknown catch value before selecting fields", outcome: "no-match", files: [{ path: "src/report.ts", source: "try { f(); } catch (err) { JSON.stringify({ error: err instanceof Error ? err.message : String(err) }); }" }], focusPath: "src/report.ts", expectedCount: 0, public: true },
6960
6970
  { id: "stringified-error", title: "Do not stringify an Error object", outcome: "match", files: [{ path: "src/report.ts", source: "try { f(); } catch (err) { JSON.stringify({ error: err }); }" }], focusPath: "src/report.ts", expectedCount: 1, public: true },
@@ -6976,6 +6986,7 @@ var NO_JSON_STRINGIFY_ERROR_DOCUMENTATION = {
6976
6986
  };
6977
6987
  var BUILTIN_ERROR_CONSTRUCTORS = /* @__PURE__ */ new Set([
6978
6988
  "AggregateError",
6989
+ "DOMException",
6979
6990
  "Error",
6980
6991
  "EvalError",
6981
6992
  "RangeError",
@@ -11836,7 +11847,7 @@ var NO_SILENT_PROMISE_CATCH_DOCUMENTATION = {
11836
11847
  rationale: "A swallowed rejection hides failures and gives callers an indistinguishable fallback value.",
11837
11848
  remediation: "Log, rethrow, or explicitly recover from the rejection; explain intentional teardown suppression.",
11838
11849
  category: "correctness",
11839
- limitations: ["Test files, teardown calls, explanatory comments, non-function handlers, and handlers that consume or report the error are excluded.", "Recognized imported Zod construction chains and their stable local aliases are excluded. Other untyped catch-like APIs are not proven to be Promises.", "Computed methods resolve literal syntax and stable local string aliases in lexical scope. Function-derived, object-derived and mutated computed keys remain unproven."],
11850
+ limitations: ["Test files, teardown calls, explanatory comments, non-function handlers, and handlers that consume or report the error are excluded.", "Recognized imported Zod construction chains and their stable local aliases are excluded, including URL schemas and primitive bigint, boolean, number and string coercion. Other untyped catch-like APIs are not proven to be Promises.", "Computed methods resolve literal syntax and stable local string aliases in lexical scope. Function-derived, object-derived and mutated computed keys remain unproven."],
11840
11851
  examples: [
11841
11852
  { id: "reported-rejection", title: "Report the rejection", outcome: "no-match", files: [{ path: "src/load.ts", source: "load().catch((error) => logger.error({ error }, 'load failed'));" }], focusPath: "src/load.ts", expectedCount: 0, public: true },
11842
11853
  { id: "silent-rejection", title: "Do not swallow the rejection", outcome: "match", files: [{ path: "src/load.ts", source: "load().catch(() => null);" }], focusPath: "src/load.ts", expectedCount: 1, public: true },
@@ -11872,7 +11883,8 @@ var ZOD_CONSTRUCTORS = /* @__PURE__ */ new Set([
11872
11883
  "tuple",
11873
11884
  "undefined",
11874
11885
  "union",
11875
- "unknown"
11886
+ "unknown",
11887
+ "url"
11876
11888
  ]);
11877
11889
  var ZOD_CHAIN_METHODS = /* @__PURE__ */ new Set([
11878
11890
  "array",
@@ -11980,8 +11992,9 @@ var no_silent_promise_catch_default = createRule({
11980
11992
  return binding.defs.length === 1 && definition?.node.type === AST_NODE_TYPES56.VariableDeclarator && definition.node.init !== null && isZodSchema(definition.node.init, seen);
11981
11993
  }
11982
11994
  if (node.type !== AST_NODE_TYPES56.CallExpression || unwrappedNodeCallee?.type !== AST_NODE_TYPES56.MemberExpression) return false;
11983
- const { object } = unwrappedNodeCallee;
11995
+ let { object } = unwrappedNodeCallee;
11984
11996
  const method = staticPropertyName(unwrappedNodeCallee, context.sourceCode);
11997
+ if (object.type === AST_NODE_TYPES56.MemberExpression && staticPropertyName(object, context.sourceCode) === "coerce" && method !== null && ["bigint", "boolean", "number", "string"].includes(method)) object = object.object;
11985
11998
  if (object.type === AST_NODE_TYPES56.Identifier && method !== null && ZOD_CONSTRUCTORS.has(method)) {
11986
11999
  const binding = ASTUtils31.findVariable(context.sourceCode.getScope(object), object.name);
11987
12000
  if (binding?.defs.some((definition) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sarj/eslint-plugin",
3
- "version": "16.5.0",
3
+ "version": "16.5.1",
4
4
  "packageManager": "npm@12.1.0",
5
5
  "description": "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
6
6
  "type": "module",