@sarj/eslint-plugin 16.10.0 → 16.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +166 -46
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +170 -47
- 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.
|
|
55
|
+
version: "16.11.0",
|
|
56
56
|
packageManager: "npm@12.2.0",
|
|
57
57
|
description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
|
|
58
58
|
type: "module",
|
|
@@ -7706,7 +7706,8 @@ var NO_IMPOSSIBLE_ZOD_LITERAL_BOUNDS_DOCUMENTATION = {
|
|
|
7706
7706
|
remediation: "Choose compatible lower and upper bounds, or remove the constraint that does not express the intended domain.",
|
|
7707
7707
|
category: "correctness",
|
|
7708
7708
|
limitations: [
|
|
7709
|
-
"Only finite numeric literals in a single
|
|
7709
|
+
"Only finite numeric literals in a single schema chain are compared; number().int(), int(), int32(), uint32(), strings and arrays require an admitted integer value or length.",
|
|
7710
|
+
"int32() and uint32() include their intrinsic ranges. The managed preset delegates explicit real-bound conflicts to upstream zod/no-conflicting-checks to avoid duplicate findings.",
|
|
7710
7711
|
"Integer-domain comparisons abstain near the JavaScript safe-integer boundary.",
|
|
7711
7712
|
"Chains with dynamic bounds, non-bound validators, transforms, pipes, or preprocessors are skipped.",
|
|
7712
7713
|
"Test and generated files are excluded."
|
|
@@ -7742,7 +7743,14 @@ var NO_IMPOSSIBLE_ZOD_LITERAL_BOUNDS_DOCUMENTATION = {
|
|
|
7742
7743
|
}
|
|
7743
7744
|
]
|
|
7744
7745
|
};
|
|
7745
|
-
var KINDS = /* @__PURE__ */ new
|
|
7746
|
+
var KINDS = /* @__PURE__ */ new Map([
|
|
7747
|
+
["array", "array"],
|
|
7748
|
+
["number", "number"],
|
|
7749
|
+
["string", "string"],
|
|
7750
|
+
["int", "integer"],
|
|
7751
|
+
["int32", "int32"],
|
|
7752
|
+
["uint32", "uint32"]
|
|
7753
|
+
]);
|
|
7746
7754
|
var NUMBER_METHODS = /* @__PURE__ */ new Set([
|
|
7747
7755
|
"gt",
|
|
7748
7756
|
"gte",
|
|
@@ -7788,11 +7796,14 @@ function strongerUpper(current, candidate2) {
|
|
|
7788
7796
|
}
|
|
7789
7797
|
return current;
|
|
7790
7798
|
}
|
|
7799
|
+
function isRealEmpty(lower, upper) {
|
|
7800
|
+
if (lower === null || upper === null) return false;
|
|
7801
|
+
return lower.value > upper.value || lower.value === upper.value && (lower.exclusive || upper.exclusive);
|
|
7802
|
+
}
|
|
7791
7803
|
function isEmpty(lower, upper, integer) {
|
|
7792
7804
|
if (lower === null || upper === null) return false;
|
|
7793
|
-
|
|
7805
|
+
if (isRealEmpty(lower, upper)) return true;
|
|
7794
7806
|
if (integer) {
|
|
7795
|
-
if (realEmpty) return false;
|
|
7796
7807
|
const safeMargin = Number.MAX_SAFE_INTEGER - 1;
|
|
7797
7808
|
if (Math.abs(lower.value) >= safeMargin || Math.abs(upper.value) >= safeMargin) {
|
|
7798
7809
|
return false;
|
|
@@ -7801,11 +7812,12 @@ function isEmpty(lower, upper, integer) {
|
|
|
7801
7812
|
const maximum = upper.exclusive ? Math.ceil(upper.value) - 1 : Math.floor(upper.value);
|
|
7802
7813
|
return minimum > maximum;
|
|
7803
7814
|
}
|
|
7804
|
-
return
|
|
7815
|
+
return false;
|
|
7805
7816
|
}
|
|
7806
7817
|
function isOutermostCall(node) {
|
|
7807
|
-
const
|
|
7808
|
-
|
|
7818
|
+
const expression = outerExpression(node);
|
|
7819
|
+
const parent = expression.parent;
|
|
7820
|
+
return !(parent?.type === import_utils43.AST_NODE_TYPES.MemberExpression && parent.object === expression && parent.parent?.type === import_utils43.AST_NODE_TYPES.CallExpression && parent.parent.callee === parent);
|
|
7809
7821
|
}
|
|
7810
7822
|
var no_impossible_zod_literal_bounds_default = createRule({
|
|
7811
7823
|
name: "no-impossible-zod-literal-bounds",
|
|
@@ -7815,13 +7827,24 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7815
7827
|
docs: {
|
|
7816
7828
|
description: "Disallow same-chain literal Zod bounds whose accepted set is mathematically empty."
|
|
7817
7829
|
},
|
|
7818
|
-
schema: [
|
|
7830
|
+
schema: [
|
|
7831
|
+
{
|
|
7832
|
+
type: "object",
|
|
7833
|
+
additionalProperties: false,
|
|
7834
|
+
properties: {
|
|
7835
|
+
delegateRealContradictions: {
|
|
7836
|
+
type: "boolean",
|
|
7837
|
+
description: "Let enabled upstream zod/no-conflicting-checks own explicit real-bound contradictions."
|
|
7838
|
+
}
|
|
7839
|
+
}
|
|
7840
|
+
}
|
|
7841
|
+
],
|
|
7819
7842
|
messages: {
|
|
7820
7843
|
impossibleBounds: "This Zod {{kind}} schema accepts no values: {{lower}} conflicts with {{upper}}."
|
|
7821
7844
|
}
|
|
7822
7845
|
},
|
|
7823
|
-
defaultOptions: [],
|
|
7824
|
-
create(context) {
|
|
7846
|
+
defaultOptions: [{}],
|
|
7847
|
+
create(context, [options]) {
|
|
7825
7848
|
const sourceCode = context.sourceCode;
|
|
7826
7849
|
if (isTestFile(context.filename) || isGeneratedFile(context.filename, sourceCode.getText())) {
|
|
7827
7850
|
return {};
|
|
@@ -7835,9 +7858,13 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7835
7858
|
if (binding === void 0) return false;
|
|
7836
7859
|
let scope = sourceCode.getScope(node);
|
|
7837
7860
|
while (scope !== null) {
|
|
7838
|
-
const variable = scope.variables.find(
|
|
7861
|
+
const variable = scope.variables.find(
|
|
7862
|
+
(candidate2) => candidate2.name === node.name
|
|
7863
|
+
);
|
|
7839
7864
|
if (variable !== void 0) {
|
|
7840
|
-
return variable.defs.some(
|
|
7865
|
+
return variable.defs.some(
|
|
7866
|
+
(definition) => definition.name === binding
|
|
7867
|
+
);
|
|
7841
7868
|
}
|
|
7842
7869
|
scope = scope.upper;
|
|
7843
7870
|
}
|
|
@@ -7870,7 +7897,7 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7870
7897
|
return null;
|
|
7871
7898
|
}
|
|
7872
7899
|
const name = import_utils43.ASTUtils.getPropertyName(callee);
|
|
7873
|
-
return name
|
|
7900
|
+
return name === null ? null : KINDS.get(name) ?? null;
|
|
7874
7901
|
}
|
|
7875
7902
|
function isInsideReshapingCall(node) {
|
|
7876
7903
|
let child = node;
|
|
@@ -7892,10 +7919,33 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7892
7919
|
return false;
|
|
7893
7920
|
}
|
|
7894
7921
|
function contradiction(chain) {
|
|
7895
|
-
const
|
|
7922
|
+
const bounds = readConstraints(chain);
|
|
7923
|
+
if (bounds === null) return null;
|
|
7924
|
+
let { lower, upper } = bounds;
|
|
7925
|
+
const { integer, numeric } = bounds;
|
|
7926
|
+
if (isRealEmpty(lower, upper) && (numeric && integer || options?.delegateRealContradictions === true)) {
|
|
7927
|
+
return null;
|
|
7928
|
+
}
|
|
7929
|
+
if (chain.kind === "int32" || chain.kind === "uint32") {
|
|
7930
|
+
lower = strongerLower(lower, {
|
|
7931
|
+
exclusive: false,
|
|
7932
|
+
label: `${chain.kind}() minimum`,
|
|
7933
|
+
value: chain.kind === "int32" ? -(2 ** 31) : 0
|
|
7934
|
+
});
|
|
7935
|
+
upper = strongerUpper(upper, {
|
|
7936
|
+
exclusive: false,
|
|
7937
|
+
label: `${chain.kind}() maximum`,
|
|
7938
|
+
value: chain.kind === "int32" ? 2 ** 31 - 1 : 2 ** 32 - 1
|
|
7939
|
+
});
|
|
7940
|
+
}
|
|
7941
|
+
return isEmpty(lower, upper, integer) && lower !== null && upper !== null ? { lower, upper } : null;
|
|
7942
|
+
}
|
|
7943
|
+
function readConstraints(chain) {
|
|
7944
|
+
const numeric = chain.kind !== "string" && chain.kind !== "array";
|
|
7945
|
+
const allowed = numeric ? NUMBER_METHODS : LENGTH_METHODS;
|
|
7896
7946
|
let lower = null;
|
|
7897
7947
|
let upper = null;
|
|
7898
|
-
let integer =
|
|
7948
|
+
let integer = chain.kind !== "number";
|
|
7899
7949
|
function addBound(method, semantic, value) {
|
|
7900
7950
|
const label = `${method}(${String(value)})`;
|
|
7901
7951
|
if (semantic !== null) {
|
|
@@ -7939,13 +7989,13 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7939
7989
|
const semantic = zeroBoundSemantic(method);
|
|
7940
7990
|
const value = semantic?.value ?? finiteNumber(node.arguments[0]);
|
|
7941
7991
|
if (value === null) return null;
|
|
7942
|
-
if (
|
|
7992
|
+
if (!numeric && value < 0) {
|
|
7943
7993
|
return null;
|
|
7944
7994
|
}
|
|
7945
7995
|
if (semantic !== null && node.arguments.length !== 0) return null;
|
|
7946
7996
|
addBound(method, semantic, value);
|
|
7947
7997
|
}
|
|
7948
|
-
return
|
|
7998
|
+
return { integer, lower, numeric, upper };
|
|
7949
7999
|
}
|
|
7950
8000
|
return {
|
|
7951
8001
|
ImportDeclaration(node) {
|
|
@@ -7961,7 +8011,9 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7961
8011
|
namespaces.add(specifier.local.name);
|
|
7962
8012
|
importBindings.set(specifier.local.name, specifier.local);
|
|
7963
8013
|
} else if (imported !== null && KINDS.has(imported)) {
|
|
7964
|
-
|
|
8014
|
+
const kind = KINDS.get(imported);
|
|
8015
|
+
if (kind !== void 0)
|
|
8016
|
+
constructors.set(specifier.local.name, kind);
|
|
7965
8017
|
importBindings.set(specifier.local.name, specifier.local);
|
|
7966
8018
|
} else if (imported === "preprocess") {
|
|
7967
8019
|
preprocessors.add(specifier.local.name);
|
|
@@ -22145,10 +22197,39 @@ var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
|
|
|
22145
22197
|
rationale: "An unbounded request can occupy work indefinitely when an upstream stalls.",
|
|
22146
22198
|
remediation: "Pass an abort signal, such as `AbortSignal.timeout(ms)`, in the fetch init.",
|
|
22147
22199
|
category: "correctness",
|
|
22148
|
-
limitations: [
|
|
22200
|
+
limitations: [
|
|
22201
|
+
"Signal presence establishes an explicit cancellation path, not a guaranteed timeout. Literal null, global undefined, and void 0 do not provide a signal. Erased TypeScript wrappers preserve the same analysis. Unknown spreads and dynamic values are not inferred. Forwarded Request objects retain their signal unless an init explicitly resets it to null.",
|
|
22202
|
+
"Accessors and unproved prototypes are excluded because native option conversion can attach or replace a signal before it is read."
|
|
22203
|
+
],
|
|
22149
22204
|
examples: [
|
|
22150
|
-
{
|
|
22151
|
-
|
|
22205
|
+
{
|
|
22206
|
+
id: "bounded-fetch",
|
|
22207
|
+
title: "Bound the request",
|
|
22208
|
+
outcome: "no-match",
|
|
22209
|
+
files: [
|
|
22210
|
+
{
|
|
22211
|
+
path: "src/client.ts",
|
|
22212
|
+
source: "await fetch(url, { signal: AbortSignal.timeout(5000) });"
|
|
22213
|
+
}
|
|
22214
|
+
],
|
|
22215
|
+
focusPath: "src/client.ts",
|
|
22216
|
+
expectedCount: 0,
|
|
22217
|
+
public: true
|
|
22218
|
+
},
|
|
22219
|
+
{
|
|
22220
|
+
id: "unbounded-fetch",
|
|
22221
|
+
title: "Do not leave fetch unbounded",
|
|
22222
|
+
outcome: "match",
|
|
22223
|
+
files: [
|
|
22224
|
+
{
|
|
22225
|
+
path: "src/client.ts",
|
|
22226
|
+
source: "await fetch('https://api.example.com/items');"
|
|
22227
|
+
}
|
|
22228
|
+
],
|
|
22229
|
+
focusPath: "src/client.ts",
|
|
22230
|
+
expectedCount: 1,
|
|
22231
|
+
public: true
|
|
22232
|
+
}
|
|
22152
22233
|
]
|
|
22153
22234
|
};
|
|
22154
22235
|
var GLOBAL_OBJECTS2 = /* @__PURE__ */ new Set([
|
|
@@ -22165,23 +22246,50 @@ function matchesAnyPattern3(filename, patterns) {
|
|
|
22165
22246
|
}
|
|
22166
22247
|
return false;
|
|
22167
22248
|
}
|
|
22168
|
-
function
|
|
22169
|
-
|
|
22170
|
-
|
|
22249
|
+
function emptySignal(expression, resolvesToGlobal) {
|
|
22250
|
+
const value = unwrapExpression(expression);
|
|
22251
|
+
if (value.type === import_utils119.AST_NODE_TYPES.Literal && value.value === null)
|
|
22252
|
+
return "null";
|
|
22253
|
+
if (value.type === import_utils119.AST_NODE_TYPES.Identifier && value.name === "undefined" && resolvesToGlobal(value))
|
|
22254
|
+
return "undefined";
|
|
22255
|
+
if (value.type === import_utils119.AST_NODE_TYPES.UnaryExpression && value.operator === "void") {
|
|
22256
|
+
const argument = unwrapExpression(value.argument);
|
|
22257
|
+
if (argument.type === import_utils119.AST_NODE_TYPES.Literal && argument.value === 0)
|
|
22258
|
+
return "undefined";
|
|
22259
|
+
}
|
|
22260
|
+
return null;
|
|
22261
|
+
}
|
|
22262
|
+
function initSignalState(init, resolvesToGlobal) {
|
|
22263
|
+
init = unwrapExpression(init);
|
|
22264
|
+
if (init.type !== import_utils119.AST_NODE_TYPES.ObjectExpression) return "unknown";
|
|
22265
|
+
let state = "absent";
|
|
22171
22266
|
for (const prop of init.properties) {
|
|
22172
22267
|
if (prop.type === import_utils119.AST_NODE_TYPES.SpreadElement) {
|
|
22173
|
-
|
|
22268
|
+
state = "unknown";
|
|
22174
22269
|
continue;
|
|
22175
22270
|
}
|
|
22271
|
+
if (prop.kind !== "init" || hasUnprovedPrototype(prop)) return "unknown";
|
|
22176
22272
|
const isSignal = !prop.computed && prop.key.type === import_utils119.AST_NODE_TYPES.Identifier && prop.key.name === "signal" || prop.key.type === import_utils119.AST_NODE_TYPES.Literal && prop.key.value === "signal";
|
|
22177
22273
|
if (isSignal) {
|
|
22178
|
-
|
|
22179
|
-
|
|
22274
|
+
state = !prop.method ? emptySignal(prop.value, resolvesToGlobal) ?? "unknown" : "unknown";
|
|
22275
|
+
} else if (!prop.computed && import_utils119.ASTUtils.getPropertyName(prop) === "__proto__" && state === "absent") {
|
|
22276
|
+
state = "unknown";
|
|
22180
22277
|
} else if (prop.computed && prop.key.type !== import_utils119.AST_NODE_TYPES.Literal) {
|
|
22181
|
-
|
|
22278
|
+
state = "unknown";
|
|
22182
22279
|
}
|
|
22183
22280
|
}
|
|
22184
|
-
return
|
|
22281
|
+
return state;
|
|
22282
|
+
}
|
|
22283
|
+
function hasUnprovedPrototype(property) {
|
|
22284
|
+
if (property.computed || property.method || property.shorthand || import_utils119.ASTUtils.getPropertyName(property) !== "__proto__")
|
|
22285
|
+
return false;
|
|
22286
|
+
const prototype = unwrapExpression(property.value);
|
|
22287
|
+
if (prototype.type === import_utils119.AST_NODE_TYPES.Literal && prototype.value === null)
|
|
22288
|
+
return false;
|
|
22289
|
+
if (prototype.type !== import_utils119.AST_NODE_TYPES.ObjectExpression) return true;
|
|
22290
|
+
return prototype.properties.some(
|
|
22291
|
+
(member) => member.type === import_utils119.AST_NODE_TYPES.SpreadElement || member.kind !== "init" || !member.computed && import_utils119.ASTUtils.getPropertyName(member) === "__proto__" || member.computed && member.key.type !== import_utils119.AST_NODE_TYPES.Literal
|
|
22292
|
+
);
|
|
22185
22293
|
}
|
|
22186
22294
|
function isInlineUrl(node, resolvesToGlobal) {
|
|
22187
22295
|
node = unwrapExpression(node);
|
|
@@ -22227,40 +22335,50 @@ var require_fetch_timeout_default = createRule({
|
|
|
22227
22335
|
return variable === null || variable.defs.length === 0;
|
|
22228
22336
|
}
|
|
22229
22337
|
function isGlobalFetchCall2(callee) {
|
|
22338
|
+
callee = unwrapExpression(callee);
|
|
22230
22339
|
if (callee.type === import_utils119.AST_NODE_TYPES.Identifier) {
|
|
22231
22340
|
return callee.name === "fetch" && resolvesToGlobal(callee);
|
|
22232
22341
|
}
|
|
22233
|
-
|
|
22342
|
+
const receiver = callee.type === import_utils119.AST_NODE_TYPES.MemberExpression ? unwrapExpression(callee.object) : null;
|
|
22343
|
+
return callee.type === import_utils119.AST_NODE_TYPES.MemberExpression && import_utils119.ASTUtils.getPropertyName(callee) === "fetch" && receiver?.type === import_utils119.AST_NODE_TYPES.Identifier && GLOBAL_OBJECTS2.has(receiver.name) && resolvesToGlobal(receiver);
|
|
22234
22344
|
}
|
|
22235
|
-
function
|
|
22345
|
+
function localConstInitSignalState(identifier) {
|
|
22236
22346
|
const variable = import_utils119.ASTUtils.findVariable(
|
|
22237
22347
|
context.sourceCode.getScope(identifier),
|
|
22238
22348
|
identifier.name
|
|
22239
22349
|
);
|
|
22240
|
-
if (variable?.defs.length !== 1) return
|
|
22350
|
+
if (variable?.defs.length !== 1) return "unknown";
|
|
22241
22351
|
const definition = variable.defs[0];
|
|
22242
|
-
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init
|
|
22243
|
-
return
|
|
22352
|
+
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || unwrapExpression(definition.node.init).type !== import_utils119.AST_NODE_TYPES.ObjectExpression) {
|
|
22353
|
+
return "unknown";
|
|
22244
22354
|
}
|
|
22245
22355
|
for (const reference of variable.references) {
|
|
22246
22356
|
const ref = reference.identifier;
|
|
22247
22357
|
if (ref === identifier || ref === definition.name) continue;
|
|
22248
22358
|
const member = ref.parent;
|
|
22249
|
-
if (member.type !== import_utils119.AST_NODE_TYPES.MemberExpression || member.object !== ref || member.computed || member.property.type !== import_utils119.AST_NODE_TYPES.Identifier || member.property.name === "signal" || member.parent.type !== import_utils119.AST_NODE_TYPES.AssignmentExpression || member.parent.left !== member) {
|
|
22250
|
-
return
|
|
22359
|
+
if (member.type !== import_utils119.AST_NODE_TYPES.MemberExpression || member.object !== ref || member.computed || member.property.type !== import_utils119.AST_NODE_TYPES.Identifier || member.property.name === "signal" || member.property.name === "__proto__" || member.parent.type !== import_utils119.AST_NODE_TYPES.AssignmentExpression || member.parent.left !== member) {
|
|
22360
|
+
return "unknown";
|
|
22251
22361
|
}
|
|
22252
22362
|
}
|
|
22253
|
-
return
|
|
22363
|
+
return initSignalState(definition.node.init, resolvesToGlobal);
|
|
22254
22364
|
}
|
|
22255
22365
|
function isForwardedRequest(argument) {
|
|
22256
|
-
let value = argument;
|
|
22366
|
+
let value = unwrapExpression(argument);
|
|
22257
22367
|
if (value.type === import_utils119.AST_NODE_TYPES.Identifier) {
|
|
22258
|
-
const binding = import_utils119.ASTUtils.findVariable(
|
|
22368
|
+
const binding = import_utils119.ASTUtils.findVariable(
|
|
22369
|
+
context.sourceCode.getScope(value),
|
|
22370
|
+
value.name
|
|
22371
|
+
);
|
|
22259
22372
|
const definition = binding?.defs.length === 1 ? binding.defs[0] : void 0;
|
|
22260
|
-
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || binding?.references.some(
|
|
22261
|
-
|
|
22373
|
+
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || binding?.references.some(
|
|
22374
|
+
(reference) => reference.isWrite() && reference.init !== true
|
|
22375
|
+
))
|
|
22376
|
+
return false;
|
|
22377
|
+
value = unwrapExpression(definition.node.init);
|
|
22262
22378
|
}
|
|
22263
|
-
|
|
22379
|
+
if (value.type !== import_utils119.AST_NODE_TYPES.NewExpression) return false;
|
|
22380
|
+
const callee = unwrapExpression(value.callee);
|
|
22381
|
+
return callee.type === import_utils119.AST_NODE_TYPES.Identifier && callee.name === "Request" && resolvesToGlobal(callee);
|
|
22264
22382
|
}
|
|
22265
22383
|
return {
|
|
22266
22384
|
CallExpression(node) {
|
|
@@ -22268,11 +22386,13 @@ var require_fetch_timeout_default = createRule({
|
|
|
22268
22386
|
if (!isGlobalFetchCall2(unwrappedNodeCallee)) {
|
|
22269
22387
|
return;
|
|
22270
22388
|
}
|
|
22271
|
-
const [first,
|
|
22272
|
-
|
|
22389
|
+
const [first, rawInit] = node.arguments;
|
|
22390
|
+
const init = rawInit === void 0 ? void 0 : unwrapExpression(rawInit);
|
|
22391
|
+
const state = init === void 0 ? "unknown" : init.type === import_utils119.AST_NODE_TYPES.Identifier ? localConstInitSignalState(init) : initSignalState(init, resolvesToGlobal);
|
|
22392
|
+
if (first !== void 0 && (node.arguments.length === 1 && !isInlineUrl(first, resolvesToGlobal) || isForwardedRequest(first) && state !== "null")) {
|
|
22273
22393
|
return;
|
|
22274
22394
|
}
|
|
22275
|
-
if (init === void 0 ||
|
|
22395
|
+
if (init === void 0 || state !== "unknown" || first !== void 0 && isInlineUrl(first, resolvesToGlobal) && emptySignal(init, resolvesToGlobal) !== null) {
|
|
22276
22396
|
context.report({ node, messageId: "missingSignal" });
|
|
22277
22397
|
}
|
|
22278
22398
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -176,7 +176,9 @@ declare const RULES: {
|
|
|
176
176
|
readonly "no-detached-global-fetch": DocumentedRule<readonly [], "detachedGlobalFetch">;
|
|
177
177
|
readonly "no-json-stringify-error": DocumentedRule<readonly [], "noJsonStringifyError">;
|
|
178
178
|
readonly "no-json-stringify-object-equality": DocumentedRule<readonly [], "serializedObjectEquality">;
|
|
179
|
-
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [
|
|
179
|
+
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [{
|
|
180
|
+
readonly delegateRealContradictions?: boolean;
|
|
181
|
+
}?], "impossibleBounds">;
|
|
180
182
|
readonly "no-in-operator-on-built-in-collections": DocumentedRule<readonly [], "ambiguousCollectionIn">;
|
|
181
183
|
readonly "no-redundant-optional-array-default": DocumentedRule<readonly [], "redundantOptionalArrayDefault">;
|
|
182
184
|
readonly "interface-contract-members-private": DocumentedRule<readonly [], "nonContractMemberMustBePrivate">;
|
|
@@ -983,7 +985,9 @@ declare const PLUGIN: {
|
|
|
983
985
|
readonly "no-detached-global-fetch": DocumentedRule<readonly [], "detachedGlobalFetch">;
|
|
984
986
|
readonly "no-json-stringify-error": DocumentedRule<readonly [], "noJsonStringifyError">;
|
|
985
987
|
readonly "no-json-stringify-object-equality": DocumentedRule<readonly [], "serializedObjectEquality">;
|
|
986
|
-
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [
|
|
988
|
+
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [{
|
|
989
|
+
readonly delegateRealContradictions?: boolean;
|
|
990
|
+
}?], "impossibleBounds">;
|
|
987
991
|
readonly "no-in-operator-on-built-in-collections": DocumentedRule<readonly [], "ambiguousCollectionIn">;
|
|
988
992
|
readonly "no-redundant-optional-array-default": DocumentedRule<readonly [], "redundantOptionalArrayDefault">;
|
|
989
993
|
readonly "interface-contract-members-private": DocumentedRule<readonly [], "nonContractMemberMustBePrivate">;
|
package/dist/index.d.ts
CHANGED
|
@@ -176,7 +176,9 @@ declare const RULES: {
|
|
|
176
176
|
readonly "no-detached-global-fetch": DocumentedRule<readonly [], "detachedGlobalFetch">;
|
|
177
177
|
readonly "no-json-stringify-error": DocumentedRule<readonly [], "noJsonStringifyError">;
|
|
178
178
|
readonly "no-json-stringify-object-equality": DocumentedRule<readonly [], "serializedObjectEquality">;
|
|
179
|
-
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [
|
|
179
|
+
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [{
|
|
180
|
+
readonly delegateRealContradictions?: boolean;
|
|
181
|
+
}?], "impossibleBounds">;
|
|
180
182
|
readonly "no-in-operator-on-built-in-collections": DocumentedRule<readonly [], "ambiguousCollectionIn">;
|
|
181
183
|
readonly "no-redundant-optional-array-default": DocumentedRule<readonly [], "redundantOptionalArrayDefault">;
|
|
182
184
|
readonly "interface-contract-members-private": DocumentedRule<readonly [], "nonContractMemberMustBePrivate">;
|
|
@@ -983,7 +985,9 @@ declare const PLUGIN: {
|
|
|
983
985
|
readonly "no-detached-global-fetch": DocumentedRule<readonly [], "detachedGlobalFetch">;
|
|
984
986
|
readonly "no-json-stringify-error": DocumentedRule<readonly [], "noJsonStringifyError">;
|
|
985
987
|
readonly "no-json-stringify-object-equality": DocumentedRule<readonly [], "serializedObjectEquality">;
|
|
986
|
-
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [
|
|
988
|
+
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [{
|
|
989
|
+
readonly delegateRealContradictions?: boolean;
|
|
990
|
+
}?], "impossibleBounds">;
|
|
987
991
|
readonly "no-in-operator-on-built-in-collections": DocumentedRule<readonly [], "ambiguousCollectionIn">;
|
|
988
992
|
readonly "no-redundant-optional-array-default": DocumentedRule<readonly [], "redundantOptionalArrayDefault">;
|
|
989
993
|
readonly "interface-contract-members-private": DocumentedRule<readonly [], "nonContractMemberMustBePrivate">;
|
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.
|
|
4
|
+
version: "16.11.0",
|
|
5
5
|
packageManager: "npm@12.2.0",
|
|
6
6
|
description: "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
|
|
7
7
|
type: "module",
|
|
@@ -7680,7 +7680,8 @@ var NO_IMPOSSIBLE_ZOD_LITERAL_BOUNDS_DOCUMENTATION = {
|
|
|
7680
7680
|
remediation: "Choose compatible lower and upper bounds, or remove the constraint that does not express the intended domain.",
|
|
7681
7681
|
category: "correctness",
|
|
7682
7682
|
limitations: [
|
|
7683
|
-
"Only finite numeric literals in a single
|
|
7683
|
+
"Only finite numeric literals in a single schema chain are compared; number().int(), int(), int32(), uint32(), strings and arrays require an admitted integer value or length.",
|
|
7684
|
+
"int32() and uint32() include their intrinsic ranges. The managed preset delegates explicit real-bound conflicts to upstream zod/no-conflicting-checks to avoid duplicate findings.",
|
|
7684
7685
|
"Integer-domain comparisons abstain near the JavaScript safe-integer boundary.",
|
|
7685
7686
|
"Chains with dynamic bounds, non-bound validators, transforms, pipes, or preprocessors are skipped.",
|
|
7686
7687
|
"Test and generated files are excluded."
|
|
@@ -7716,7 +7717,14 @@ var NO_IMPOSSIBLE_ZOD_LITERAL_BOUNDS_DOCUMENTATION = {
|
|
|
7716
7717
|
}
|
|
7717
7718
|
]
|
|
7718
7719
|
};
|
|
7719
|
-
var KINDS = /* @__PURE__ */ new
|
|
7720
|
+
var KINDS = /* @__PURE__ */ new Map([
|
|
7721
|
+
["array", "array"],
|
|
7722
|
+
["number", "number"],
|
|
7723
|
+
["string", "string"],
|
|
7724
|
+
["int", "integer"],
|
|
7725
|
+
["int32", "int32"],
|
|
7726
|
+
["uint32", "uint32"]
|
|
7727
|
+
]);
|
|
7720
7728
|
var NUMBER_METHODS = /* @__PURE__ */ new Set([
|
|
7721
7729
|
"gt",
|
|
7722
7730
|
"gte",
|
|
@@ -7762,11 +7770,14 @@ function strongerUpper(current, candidate2) {
|
|
|
7762
7770
|
}
|
|
7763
7771
|
return current;
|
|
7764
7772
|
}
|
|
7773
|
+
function isRealEmpty(lower, upper) {
|
|
7774
|
+
if (lower === null || upper === null) return false;
|
|
7775
|
+
return lower.value > upper.value || lower.value === upper.value && (lower.exclusive || upper.exclusive);
|
|
7776
|
+
}
|
|
7765
7777
|
function isEmpty(lower, upper, integer) {
|
|
7766
7778
|
if (lower === null || upper === null) return false;
|
|
7767
|
-
|
|
7779
|
+
if (isRealEmpty(lower, upper)) return true;
|
|
7768
7780
|
if (integer) {
|
|
7769
|
-
if (realEmpty) return false;
|
|
7770
7781
|
const safeMargin = Number.MAX_SAFE_INTEGER - 1;
|
|
7771
7782
|
if (Math.abs(lower.value) >= safeMargin || Math.abs(upper.value) >= safeMargin) {
|
|
7772
7783
|
return false;
|
|
@@ -7775,11 +7786,12 @@ function isEmpty(lower, upper, integer) {
|
|
|
7775
7786
|
const maximum = upper.exclusive ? Math.ceil(upper.value) - 1 : Math.floor(upper.value);
|
|
7776
7787
|
return minimum > maximum;
|
|
7777
7788
|
}
|
|
7778
|
-
return
|
|
7789
|
+
return false;
|
|
7779
7790
|
}
|
|
7780
7791
|
function isOutermostCall(node) {
|
|
7781
|
-
const
|
|
7782
|
-
|
|
7792
|
+
const expression = outerExpression(node);
|
|
7793
|
+
const parent = expression.parent;
|
|
7794
|
+
return !(parent?.type === AST_NODE_TYPES37.MemberExpression && parent.object === expression && parent.parent?.type === AST_NODE_TYPES37.CallExpression && parent.parent.callee === parent);
|
|
7783
7795
|
}
|
|
7784
7796
|
var no_impossible_zod_literal_bounds_default = createRule({
|
|
7785
7797
|
name: "no-impossible-zod-literal-bounds",
|
|
@@ -7789,13 +7801,24 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7789
7801
|
docs: {
|
|
7790
7802
|
description: "Disallow same-chain literal Zod bounds whose accepted set is mathematically empty."
|
|
7791
7803
|
},
|
|
7792
|
-
schema: [
|
|
7804
|
+
schema: [
|
|
7805
|
+
{
|
|
7806
|
+
type: "object",
|
|
7807
|
+
additionalProperties: false,
|
|
7808
|
+
properties: {
|
|
7809
|
+
delegateRealContradictions: {
|
|
7810
|
+
type: "boolean",
|
|
7811
|
+
description: "Let enabled upstream zod/no-conflicting-checks own explicit real-bound contradictions."
|
|
7812
|
+
}
|
|
7813
|
+
}
|
|
7814
|
+
}
|
|
7815
|
+
],
|
|
7793
7816
|
messages: {
|
|
7794
7817
|
impossibleBounds: "This Zod {{kind}} schema accepts no values: {{lower}} conflicts with {{upper}}."
|
|
7795
7818
|
}
|
|
7796
7819
|
},
|
|
7797
|
-
defaultOptions: [],
|
|
7798
|
-
create(context) {
|
|
7820
|
+
defaultOptions: [{}],
|
|
7821
|
+
create(context, [options]) {
|
|
7799
7822
|
const sourceCode = context.sourceCode;
|
|
7800
7823
|
if (isTestFile(context.filename) || isGeneratedFile(context.filename, sourceCode.getText())) {
|
|
7801
7824
|
return {};
|
|
@@ -7809,9 +7832,13 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7809
7832
|
if (binding === void 0) return false;
|
|
7810
7833
|
let scope = sourceCode.getScope(node);
|
|
7811
7834
|
while (scope !== null) {
|
|
7812
|
-
const variable = scope.variables.find(
|
|
7835
|
+
const variable = scope.variables.find(
|
|
7836
|
+
(candidate2) => candidate2.name === node.name
|
|
7837
|
+
);
|
|
7813
7838
|
if (variable !== void 0) {
|
|
7814
|
-
return variable.defs.some(
|
|
7839
|
+
return variable.defs.some(
|
|
7840
|
+
(definition) => definition.name === binding
|
|
7841
|
+
);
|
|
7815
7842
|
}
|
|
7816
7843
|
scope = scope.upper;
|
|
7817
7844
|
}
|
|
@@ -7844,7 +7871,7 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7844
7871
|
return null;
|
|
7845
7872
|
}
|
|
7846
7873
|
const name = ASTUtils17.getPropertyName(callee);
|
|
7847
|
-
return name
|
|
7874
|
+
return name === null ? null : KINDS.get(name) ?? null;
|
|
7848
7875
|
}
|
|
7849
7876
|
function isInsideReshapingCall(node) {
|
|
7850
7877
|
let child = node;
|
|
@@ -7866,10 +7893,33 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7866
7893
|
return false;
|
|
7867
7894
|
}
|
|
7868
7895
|
function contradiction(chain) {
|
|
7869
|
-
const
|
|
7896
|
+
const bounds = readConstraints(chain);
|
|
7897
|
+
if (bounds === null) return null;
|
|
7898
|
+
let { lower, upper } = bounds;
|
|
7899
|
+
const { integer, numeric } = bounds;
|
|
7900
|
+
if (isRealEmpty(lower, upper) && (numeric && integer || options?.delegateRealContradictions === true)) {
|
|
7901
|
+
return null;
|
|
7902
|
+
}
|
|
7903
|
+
if (chain.kind === "int32" || chain.kind === "uint32") {
|
|
7904
|
+
lower = strongerLower(lower, {
|
|
7905
|
+
exclusive: false,
|
|
7906
|
+
label: `${chain.kind}() minimum`,
|
|
7907
|
+
value: chain.kind === "int32" ? -(2 ** 31) : 0
|
|
7908
|
+
});
|
|
7909
|
+
upper = strongerUpper(upper, {
|
|
7910
|
+
exclusive: false,
|
|
7911
|
+
label: `${chain.kind}() maximum`,
|
|
7912
|
+
value: chain.kind === "int32" ? 2 ** 31 - 1 : 2 ** 32 - 1
|
|
7913
|
+
});
|
|
7914
|
+
}
|
|
7915
|
+
return isEmpty(lower, upper, integer) && lower !== null && upper !== null ? { lower, upper } : null;
|
|
7916
|
+
}
|
|
7917
|
+
function readConstraints(chain) {
|
|
7918
|
+
const numeric = chain.kind !== "string" && chain.kind !== "array";
|
|
7919
|
+
const allowed = numeric ? NUMBER_METHODS : LENGTH_METHODS;
|
|
7870
7920
|
let lower = null;
|
|
7871
7921
|
let upper = null;
|
|
7872
|
-
let integer =
|
|
7922
|
+
let integer = chain.kind !== "number";
|
|
7873
7923
|
function addBound(method, semantic, value) {
|
|
7874
7924
|
const label = `${method}(${String(value)})`;
|
|
7875
7925
|
if (semantic !== null) {
|
|
@@ -7913,13 +7963,13 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7913
7963
|
const semantic = zeroBoundSemantic(method);
|
|
7914
7964
|
const value = semantic?.value ?? finiteNumber(node.arguments[0]);
|
|
7915
7965
|
if (value === null) return null;
|
|
7916
|
-
if (
|
|
7966
|
+
if (!numeric && value < 0) {
|
|
7917
7967
|
return null;
|
|
7918
7968
|
}
|
|
7919
7969
|
if (semantic !== null && node.arguments.length !== 0) return null;
|
|
7920
7970
|
addBound(method, semantic, value);
|
|
7921
7971
|
}
|
|
7922
|
-
return
|
|
7972
|
+
return { integer, lower, numeric, upper };
|
|
7923
7973
|
}
|
|
7924
7974
|
return {
|
|
7925
7975
|
ImportDeclaration(node) {
|
|
@@ -7935,7 +7985,9 @@ var no_impossible_zod_literal_bounds_default = createRule({
|
|
|
7935
7985
|
namespaces.add(specifier.local.name);
|
|
7936
7986
|
importBindings.set(specifier.local.name, specifier.local);
|
|
7937
7987
|
} else if (imported !== null && KINDS.has(imported)) {
|
|
7938
|
-
|
|
7988
|
+
const kind = KINDS.get(imported);
|
|
7989
|
+
if (kind !== void 0)
|
|
7990
|
+
constructors.set(specifier.local.name, kind);
|
|
7939
7991
|
importBindings.set(specifier.local.name, specifier.local);
|
|
7940
7992
|
} else if (imported === "preprocess") {
|
|
7941
7993
|
preprocessors.add(specifier.local.name);
|
|
@@ -22157,16 +22209,48 @@ var require_assert_never_default = createRule({
|
|
|
22157
22209
|
});
|
|
22158
22210
|
|
|
22159
22211
|
// src/rules/require-fetch-timeout.ts
|
|
22160
|
-
import {
|
|
22212
|
+
import {
|
|
22213
|
+
AST_NODE_TYPES as AST_NODE_TYPES103,
|
|
22214
|
+
ASTUtils as ASTUtils64
|
|
22215
|
+
} from "@typescript-eslint/utils";
|
|
22161
22216
|
var REQUIRE_FETCH_TIMEOUT_DOCUMENTATION = {
|
|
22162
22217
|
summary: "Require an explicit abort signal on locally analyzable global fetch calls.",
|
|
22163
22218
|
rationale: "An unbounded request can occupy work indefinitely when an upstream stalls.",
|
|
22164
22219
|
remediation: "Pass an abort signal, such as `AbortSignal.timeout(ms)`, in the fetch init.",
|
|
22165
22220
|
category: "correctness",
|
|
22166
|
-
limitations: [
|
|
22221
|
+
limitations: [
|
|
22222
|
+
"Signal presence establishes an explicit cancellation path, not a guaranteed timeout. Literal null, global undefined, and void 0 do not provide a signal. Erased TypeScript wrappers preserve the same analysis. Unknown spreads and dynamic values are not inferred. Forwarded Request objects retain their signal unless an init explicitly resets it to null.",
|
|
22223
|
+
"Accessors and unproved prototypes are excluded because native option conversion can attach or replace a signal before it is read."
|
|
22224
|
+
],
|
|
22167
22225
|
examples: [
|
|
22168
|
-
{
|
|
22169
|
-
|
|
22226
|
+
{
|
|
22227
|
+
id: "bounded-fetch",
|
|
22228
|
+
title: "Bound the request",
|
|
22229
|
+
outcome: "no-match",
|
|
22230
|
+
files: [
|
|
22231
|
+
{
|
|
22232
|
+
path: "src/client.ts",
|
|
22233
|
+
source: "await fetch(url, { signal: AbortSignal.timeout(5000) });"
|
|
22234
|
+
}
|
|
22235
|
+
],
|
|
22236
|
+
focusPath: "src/client.ts",
|
|
22237
|
+
expectedCount: 0,
|
|
22238
|
+
public: true
|
|
22239
|
+
},
|
|
22240
|
+
{
|
|
22241
|
+
id: "unbounded-fetch",
|
|
22242
|
+
title: "Do not leave fetch unbounded",
|
|
22243
|
+
outcome: "match",
|
|
22244
|
+
files: [
|
|
22245
|
+
{
|
|
22246
|
+
path: "src/client.ts",
|
|
22247
|
+
source: "await fetch('https://api.example.com/items');"
|
|
22248
|
+
}
|
|
22249
|
+
],
|
|
22250
|
+
focusPath: "src/client.ts",
|
|
22251
|
+
expectedCount: 1,
|
|
22252
|
+
public: true
|
|
22253
|
+
}
|
|
22170
22254
|
]
|
|
22171
22255
|
};
|
|
22172
22256
|
var GLOBAL_OBJECTS2 = /* @__PURE__ */ new Set([
|
|
@@ -22183,23 +22267,50 @@ function matchesAnyPattern3(filename, patterns) {
|
|
|
22183
22267
|
}
|
|
22184
22268
|
return false;
|
|
22185
22269
|
}
|
|
22186
|
-
function
|
|
22187
|
-
|
|
22188
|
-
|
|
22270
|
+
function emptySignal(expression, resolvesToGlobal) {
|
|
22271
|
+
const value = unwrapExpression(expression);
|
|
22272
|
+
if (value.type === AST_NODE_TYPES103.Literal && value.value === null)
|
|
22273
|
+
return "null";
|
|
22274
|
+
if (value.type === AST_NODE_TYPES103.Identifier && value.name === "undefined" && resolvesToGlobal(value))
|
|
22275
|
+
return "undefined";
|
|
22276
|
+
if (value.type === AST_NODE_TYPES103.UnaryExpression && value.operator === "void") {
|
|
22277
|
+
const argument = unwrapExpression(value.argument);
|
|
22278
|
+
if (argument.type === AST_NODE_TYPES103.Literal && argument.value === 0)
|
|
22279
|
+
return "undefined";
|
|
22280
|
+
}
|
|
22281
|
+
return null;
|
|
22282
|
+
}
|
|
22283
|
+
function initSignalState(init, resolvesToGlobal) {
|
|
22284
|
+
init = unwrapExpression(init);
|
|
22285
|
+
if (init.type !== AST_NODE_TYPES103.ObjectExpression) return "unknown";
|
|
22286
|
+
let state = "absent";
|
|
22189
22287
|
for (const prop of init.properties) {
|
|
22190
22288
|
if (prop.type === AST_NODE_TYPES103.SpreadElement) {
|
|
22191
|
-
|
|
22289
|
+
state = "unknown";
|
|
22192
22290
|
continue;
|
|
22193
22291
|
}
|
|
22292
|
+
if (prop.kind !== "init" || hasUnprovedPrototype(prop)) return "unknown";
|
|
22194
22293
|
const isSignal = !prop.computed && prop.key.type === AST_NODE_TYPES103.Identifier && prop.key.name === "signal" || prop.key.type === AST_NODE_TYPES103.Literal && prop.key.value === "signal";
|
|
22195
22294
|
if (isSignal) {
|
|
22196
|
-
|
|
22197
|
-
|
|
22295
|
+
state = !prop.method ? emptySignal(prop.value, resolvesToGlobal) ?? "unknown" : "unknown";
|
|
22296
|
+
} else if (!prop.computed && ASTUtils64.getPropertyName(prop) === "__proto__" && state === "absent") {
|
|
22297
|
+
state = "unknown";
|
|
22198
22298
|
} else if (prop.computed && prop.key.type !== AST_NODE_TYPES103.Literal) {
|
|
22199
|
-
|
|
22299
|
+
state = "unknown";
|
|
22200
22300
|
}
|
|
22201
22301
|
}
|
|
22202
|
-
return
|
|
22302
|
+
return state;
|
|
22303
|
+
}
|
|
22304
|
+
function hasUnprovedPrototype(property) {
|
|
22305
|
+
if (property.computed || property.method || property.shorthand || ASTUtils64.getPropertyName(property) !== "__proto__")
|
|
22306
|
+
return false;
|
|
22307
|
+
const prototype = unwrapExpression(property.value);
|
|
22308
|
+
if (prototype.type === AST_NODE_TYPES103.Literal && prototype.value === null)
|
|
22309
|
+
return false;
|
|
22310
|
+
if (prototype.type !== AST_NODE_TYPES103.ObjectExpression) return true;
|
|
22311
|
+
return prototype.properties.some(
|
|
22312
|
+
(member) => member.type === AST_NODE_TYPES103.SpreadElement || member.kind !== "init" || !member.computed && ASTUtils64.getPropertyName(member) === "__proto__" || member.computed && member.key.type !== AST_NODE_TYPES103.Literal
|
|
22313
|
+
);
|
|
22203
22314
|
}
|
|
22204
22315
|
function isInlineUrl(node, resolvesToGlobal) {
|
|
22205
22316
|
node = unwrapExpression(node);
|
|
@@ -22245,40 +22356,50 @@ var require_fetch_timeout_default = createRule({
|
|
|
22245
22356
|
return variable === null || variable.defs.length === 0;
|
|
22246
22357
|
}
|
|
22247
22358
|
function isGlobalFetchCall2(callee) {
|
|
22359
|
+
callee = unwrapExpression(callee);
|
|
22248
22360
|
if (callee.type === AST_NODE_TYPES103.Identifier) {
|
|
22249
22361
|
return callee.name === "fetch" && resolvesToGlobal(callee);
|
|
22250
22362
|
}
|
|
22251
|
-
|
|
22363
|
+
const receiver = callee.type === AST_NODE_TYPES103.MemberExpression ? unwrapExpression(callee.object) : null;
|
|
22364
|
+
return callee.type === AST_NODE_TYPES103.MemberExpression && ASTUtils64.getPropertyName(callee) === "fetch" && receiver?.type === AST_NODE_TYPES103.Identifier && GLOBAL_OBJECTS2.has(receiver.name) && resolvesToGlobal(receiver);
|
|
22252
22365
|
}
|
|
22253
|
-
function
|
|
22366
|
+
function localConstInitSignalState(identifier) {
|
|
22254
22367
|
const variable = ASTUtils64.findVariable(
|
|
22255
22368
|
context.sourceCode.getScope(identifier),
|
|
22256
22369
|
identifier.name
|
|
22257
22370
|
);
|
|
22258
|
-
if (variable?.defs.length !== 1) return
|
|
22371
|
+
if (variable?.defs.length !== 1) return "unknown";
|
|
22259
22372
|
const definition = variable.defs[0];
|
|
22260
|
-
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init
|
|
22261
|
-
return
|
|
22373
|
+
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || unwrapExpression(definition.node.init).type !== AST_NODE_TYPES103.ObjectExpression) {
|
|
22374
|
+
return "unknown";
|
|
22262
22375
|
}
|
|
22263
22376
|
for (const reference of variable.references) {
|
|
22264
22377
|
const ref = reference.identifier;
|
|
22265
22378
|
if (ref === identifier || ref === definition.name) continue;
|
|
22266
22379
|
const member = ref.parent;
|
|
22267
|
-
if (member.type !== AST_NODE_TYPES103.MemberExpression || member.object !== ref || member.computed || member.property.type !== AST_NODE_TYPES103.Identifier || member.property.name === "signal" || member.parent.type !== AST_NODE_TYPES103.AssignmentExpression || member.parent.left !== member) {
|
|
22268
|
-
return
|
|
22380
|
+
if (member.type !== AST_NODE_TYPES103.MemberExpression || member.object !== ref || member.computed || member.property.type !== AST_NODE_TYPES103.Identifier || member.property.name === "signal" || member.property.name === "__proto__" || member.parent.type !== AST_NODE_TYPES103.AssignmentExpression || member.parent.left !== member) {
|
|
22381
|
+
return "unknown";
|
|
22269
22382
|
}
|
|
22270
22383
|
}
|
|
22271
|
-
return
|
|
22384
|
+
return initSignalState(definition.node.init, resolvesToGlobal);
|
|
22272
22385
|
}
|
|
22273
22386
|
function isForwardedRequest(argument) {
|
|
22274
|
-
let value = argument;
|
|
22387
|
+
let value = unwrapExpression(argument);
|
|
22275
22388
|
if (value.type === AST_NODE_TYPES103.Identifier) {
|
|
22276
|
-
const binding = ASTUtils64.findVariable(
|
|
22389
|
+
const binding = ASTUtils64.findVariable(
|
|
22390
|
+
context.sourceCode.getScope(value),
|
|
22391
|
+
value.name
|
|
22392
|
+
);
|
|
22277
22393
|
const definition = binding?.defs.length === 1 ? binding.defs[0] : void 0;
|
|
22278
|
-
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || binding?.references.some(
|
|
22279
|
-
|
|
22394
|
+
if (definition?.type !== "Variable" || definition.parent.kind !== "const" || definition.node.init === null || binding?.references.some(
|
|
22395
|
+
(reference) => reference.isWrite() && reference.init !== true
|
|
22396
|
+
))
|
|
22397
|
+
return false;
|
|
22398
|
+
value = unwrapExpression(definition.node.init);
|
|
22280
22399
|
}
|
|
22281
|
-
|
|
22400
|
+
if (value.type !== AST_NODE_TYPES103.NewExpression) return false;
|
|
22401
|
+
const callee = unwrapExpression(value.callee);
|
|
22402
|
+
return callee.type === AST_NODE_TYPES103.Identifier && callee.name === "Request" && resolvesToGlobal(callee);
|
|
22282
22403
|
}
|
|
22283
22404
|
return {
|
|
22284
22405
|
CallExpression(node) {
|
|
@@ -22286,11 +22407,13 @@ var require_fetch_timeout_default = createRule({
|
|
|
22286
22407
|
if (!isGlobalFetchCall2(unwrappedNodeCallee)) {
|
|
22287
22408
|
return;
|
|
22288
22409
|
}
|
|
22289
|
-
const [first,
|
|
22290
|
-
|
|
22410
|
+
const [first, rawInit] = node.arguments;
|
|
22411
|
+
const init = rawInit === void 0 ? void 0 : unwrapExpression(rawInit);
|
|
22412
|
+
const state = init === void 0 ? "unknown" : init.type === AST_NODE_TYPES103.Identifier ? localConstInitSignalState(init) : initSignalState(init, resolvesToGlobal);
|
|
22413
|
+
if (first !== void 0 && (node.arguments.length === 1 && !isInlineUrl(first, resolvesToGlobal) || isForwardedRequest(first) && state !== "null")) {
|
|
22291
22414
|
return;
|
|
22292
22415
|
}
|
|
22293
|
-
if (init === void 0 ||
|
|
22416
|
+
if (init === void 0 || state !== "unknown" || first !== void 0 && isInlineUrl(first, resolvesToGlobal) && emptySignal(init, resolvesToGlobal) !== null) {
|
|
22294
22417
|
context.report({ node, messageId: "missingSignal" });
|
|
22295
22418
|
}
|
|
22296
22419
|
}
|