@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 +25 -12
- package/dist/index.js +25 -12
- package/package.json +1 -1
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.
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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) => {
|