@sarj/eslint-plugin 11.0.1 → 11.1.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 +327 -68
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +327 -68
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2941,6 +2941,16 @@ var PAYLOAD_PROPS = /* @__PURE__ */ new Set([
|
|
|
2941
2941
|
"metadata",
|
|
2942
2942
|
"context"
|
|
2943
2943
|
]);
|
|
2944
|
+
var BUILTIN_ERROR_CONSTRUCTORS = /* @__PURE__ */ new Set([
|
|
2945
|
+
"AggregateError",
|
|
2946
|
+
"Error",
|
|
2947
|
+
"EvalError",
|
|
2948
|
+
"RangeError",
|
|
2949
|
+
"ReferenceError",
|
|
2950
|
+
"SyntaxError",
|
|
2951
|
+
"TypeError",
|
|
2952
|
+
"URIError"
|
|
2953
|
+
]);
|
|
2944
2954
|
function isCatchBinding(scope, name) {
|
|
2945
2955
|
let current = scope;
|
|
2946
2956
|
while (current) {
|
|
@@ -3055,6 +3065,48 @@ function nodeWithin(node, container) {
|
|
|
3055
3065
|
function isJsonStringify(callee) {
|
|
3056
3066
|
return callee.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "JSON" && callee.property.type === "Identifier" && callee.property.name === "stringify";
|
|
3057
3067
|
}
|
|
3068
|
+
function directLiteralValues(argument) {
|
|
3069
|
+
if (argument.type === "ObjectExpression") {
|
|
3070
|
+
return argument.properties.flatMap((property) => {
|
|
3071
|
+
if (property.type !== "Property" || property.computed) return [];
|
|
3072
|
+
const value = property.value;
|
|
3073
|
+
if (value.type === "AssignmentPattern" || value.type === "ArrayPattern" || value.type === "ObjectPattern" || value.type === "TSEmptyBodyFunctionExpression") {
|
|
3074
|
+
return [];
|
|
3075
|
+
}
|
|
3076
|
+
return [value];
|
|
3077
|
+
});
|
|
3078
|
+
}
|
|
3079
|
+
if (argument.type === "ArrayExpression") {
|
|
3080
|
+
return argument.elements.flatMap(
|
|
3081
|
+
(element) => element !== null && element.type !== "SpreadElement" ? [element] : []
|
|
3082
|
+
);
|
|
3083
|
+
}
|
|
3084
|
+
return argument.type === "SpreadElement" ? [] : [argument];
|
|
3085
|
+
}
|
|
3086
|
+
function expressionSuggestsError(expression, scope) {
|
|
3087
|
+
if (expression.type === "Identifier") {
|
|
3088
|
+
return ERROR_NAME_PATTERN.test(expression.name) || isCatchBinding(scope, expression.name);
|
|
3089
|
+
}
|
|
3090
|
+
return expression.type === "MemberExpression" && memberSuggestsError(expression, scope);
|
|
3091
|
+
}
|
|
3092
|
+
function nestedExpressionSuggestsError(expression, scope) {
|
|
3093
|
+
if (expression.type === "Identifier") {
|
|
3094
|
+
if (isCatchBinding(scope, expression.name)) return true;
|
|
3095
|
+
let current = scope;
|
|
3096
|
+
while (current !== null && !current.set.has(expression.name)) {
|
|
3097
|
+
current = current.upper;
|
|
3098
|
+
}
|
|
3099
|
+
const variable = current?.set.get(expression.name);
|
|
3100
|
+
if (variable === void 0 || variable.defs.length !== 1) return false;
|
|
3101
|
+
const definition = variable.defs[0];
|
|
3102
|
+
if (definition?.type !== "Variable") return false;
|
|
3103
|
+
const initializer = definition.node.init;
|
|
3104
|
+
return initializer?.type === "NewExpression" && initializer.callee.type === "Identifier" && BUILTIN_ERROR_CONSTRUCTORS.has(initializer.callee.name) && variable.references.every(
|
|
3105
|
+
(reference) => !reference.isWrite() || reference.init === true
|
|
3106
|
+
);
|
|
3107
|
+
}
|
|
3108
|
+
return expression.type === "MemberExpression" && memberSuggestsError(expression, scope);
|
|
3109
|
+
}
|
|
3058
3110
|
var no_json_stringify_error_default = createRule({
|
|
3059
3111
|
name: "no-json-stringify-error",
|
|
3060
3112
|
meta: {
|
|
@@ -3079,18 +3131,11 @@ var no_json_stringify_error_default = createRule({
|
|
|
3079
3131
|
return;
|
|
3080
3132
|
}
|
|
3081
3133
|
const scope = context.sourceCode.getScope(firstArg);
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
} else {
|
|
3088
|
-
return;
|
|
3089
|
-
}
|
|
3090
|
-
if (!suggestsError) {
|
|
3091
|
-
return;
|
|
3092
|
-
}
|
|
3093
|
-
if (isGuardedByInstanceofError(node, firstArg, context.sourceCode) || isNarrowedByEarlyReturn(node, firstArg, context.sourceCode)) {
|
|
3134
|
+
const isNestedLiteral = firstArg.type === "ObjectExpression" || firstArg.type === "ArrayExpression";
|
|
3135
|
+
const unsafeValue = directLiteralValues(firstArg).find(
|
|
3136
|
+
(value) => (isNestedLiteral ? nestedExpressionSuggestsError(value, scope) : expressionSuggestsError(value, scope)) && !isGuardedByInstanceofError(node, value, context.sourceCode) && !isNarrowedByEarlyReturn(node, value, context.sourceCode)
|
|
3137
|
+
);
|
|
3138
|
+
if (unsafeValue === void 0) {
|
|
3094
3139
|
return;
|
|
3095
3140
|
}
|
|
3096
3141
|
context.report({
|
|
@@ -5160,50 +5205,59 @@ var no_select_star_default = createRule({
|
|
|
5160
5205
|
|
|
5161
5206
|
// src/rules/no-sentinel-return-on-catch.ts
|
|
5162
5207
|
var import_utils33 = require("@typescript-eslint/utils");
|
|
5208
|
+
function unwrapSentinelExpression(arg) {
|
|
5209
|
+
let current = arg;
|
|
5210
|
+
while (current?.type === import_utils33.AST_NODE_TYPES.TSAsExpression || current?.type === import_utils33.AST_NODE_TYPES.TSTypeAssertion || current?.type === import_utils33.AST_NODE_TYPES.TSSatisfiesExpression) {
|
|
5211
|
+
current = current.expression;
|
|
5212
|
+
}
|
|
5213
|
+
return current;
|
|
5214
|
+
}
|
|
5163
5215
|
function sentinelKind(arg) {
|
|
5164
|
-
|
|
5216
|
+
const value = unwrapSentinelExpression(arg);
|
|
5217
|
+
if (value === null) {
|
|
5165
5218
|
return null;
|
|
5166
5219
|
}
|
|
5167
|
-
if (
|
|
5168
|
-
if (
|
|
5220
|
+
if (value.type === import_utils33.AST_NODE_TYPES.Literal) {
|
|
5221
|
+
if (value.value === null) {
|
|
5169
5222
|
return "nullish";
|
|
5170
5223
|
}
|
|
5171
|
-
if (typeof
|
|
5224
|
+
if (typeof value.value === "boolean") {
|
|
5172
5225
|
return "boolean";
|
|
5173
5226
|
}
|
|
5174
|
-
if (typeof
|
|
5227
|
+
if (typeof value.value === "string") {
|
|
5175
5228
|
return "string";
|
|
5176
5229
|
}
|
|
5177
5230
|
return null;
|
|
5178
5231
|
}
|
|
5179
|
-
if (
|
|
5232
|
+
if (value.type === import_utils33.AST_NODE_TYPES.Identifier && value.name === "undefined") {
|
|
5180
5233
|
return "nullish";
|
|
5181
5234
|
}
|
|
5182
|
-
if (
|
|
5235
|
+
if (value.type === import_utils33.AST_NODE_TYPES.ArrayExpression) {
|
|
5183
5236
|
return "array";
|
|
5184
5237
|
}
|
|
5185
|
-
if (
|
|
5238
|
+
if (value.type === import_utils33.AST_NODE_TYPES.ObjectExpression) {
|
|
5186
5239
|
return "object";
|
|
5187
5240
|
}
|
|
5188
5241
|
return null;
|
|
5189
5242
|
}
|
|
5190
5243
|
function isSentinelArgument(arg) {
|
|
5191
|
-
|
|
5244
|
+
const value = unwrapSentinelExpression(arg);
|
|
5245
|
+
if (value === null) {
|
|
5192
5246
|
return false;
|
|
5193
5247
|
}
|
|
5194
|
-
if (
|
|
5248
|
+
if (value.type === import_utils33.AST_NODE_TYPES.Literal && value.value === null) {
|
|
5195
5249
|
return true;
|
|
5196
5250
|
}
|
|
5197
|
-
if (
|
|
5251
|
+
if (value.type === import_utils33.AST_NODE_TYPES.Literal && value.value === false) {
|
|
5198
5252
|
return true;
|
|
5199
5253
|
}
|
|
5200
|
-
if (
|
|
5254
|
+
if (value.type === import_utils33.AST_NODE_TYPES.Identifier && value.name === "undefined") {
|
|
5201
5255
|
return true;
|
|
5202
5256
|
}
|
|
5203
|
-
if (
|
|
5257
|
+
if (value.type === import_utils33.AST_NODE_TYPES.ArrayExpression && value.elements.length === 0) {
|
|
5204
5258
|
return true;
|
|
5205
5259
|
}
|
|
5206
|
-
if (
|
|
5260
|
+
if (value.type === import_utils33.AST_NODE_TYPES.ObjectExpression && value.properties.length === 0) {
|
|
5207
5261
|
return true;
|
|
5208
5262
|
}
|
|
5209
5263
|
return false;
|
|
@@ -5401,6 +5455,16 @@ function tryReturnsSafeParse(catchNode) {
|
|
|
5401
5455
|
const only = tryBlock.body.length === 1 ? tryBlock.body[0] : void 0;
|
|
5402
5456
|
return only !== void 0 && returnsMatching(only, isBodyDecodeNode);
|
|
5403
5457
|
}
|
|
5458
|
+
function isIntentionalStackCapture(catchNode, caughtName) {
|
|
5459
|
+
if (caughtName === null) return false;
|
|
5460
|
+
const tryBody = tryBlockOf(catchNode).body;
|
|
5461
|
+
const only = tryBody.length === 1 ? tryBody[0] : void 0;
|
|
5462
|
+
if (only?.type !== import_utils33.AST_NODE_TYPES.ThrowStatement) return false;
|
|
5463
|
+
const thrown = unwrapSentinelExpression(only.argument);
|
|
5464
|
+
const constructsError = (thrown?.type === import_utils33.AST_NODE_TYPES.CallExpression || thrown?.type === import_utils33.AST_NODE_TYPES.NewExpression) && thrown.callee.type === import_utils33.AST_NODE_TYPES.Identifier && thrown.callee.name === "Error";
|
|
5465
|
+
if (!constructsError) return false;
|
|
5466
|
+
return catchNode.body.body.slice(0, -1).some((statement) => subtreeReadsName(statement, caughtName));
|
|
5467
|
+
}
|
|
5404
5468
|
function tryBlockOf(catchNode) {
|
|
5405
5469
|
return catchNode.parent.block;
|
|
5406
5470
|
}
|
|
@@ -5521,6 +5585,9 @@ var no_sentinel_return_on_catch_default = createRule({
|
|
|
5521
5585
|
if (tryReturnsSafeParse(node)) {
|
|
5522
5586
|
return;
|
|
5523
5587
|
}
|
|
5588
|
+
if (isIntentionalStackCapture(node, caughtName)) {
|
|
5589
|
+
return;
|
|
5590
|
+
}
|
|
5524
5591
|
const kind = sentinelKind(last.argument);
|
|
5525
5592
|
if (kind !== null && isNamedBooleanPredicate(node, kind)) {
|
|
5526
5593
|
return;
|
|
@@ -5599,11 +5666,11 @@ var no_silent_promise_catch_default = createRule({
|
|
|
5599
5666
|
meta: {
|
|
5600
5667
|
type: "problem",
|
|
5601
5668
|
docs: {
|
|
5602
|
-
description: "Disallow `.catch()` handlers that silently swallow
|
|
5669
|
+
description: "Disallow `.catch()` and second-argument `.then()` handlers that silently swallow a rejection; log, rethrow, or handle the error."
|
|
5603
5670
|
},
|
|
5604
5671
|
schema: [],
|
|
5605
5672
|
messages: {
|
|
5606
|
-
silentCatch: "This
|
|
5673
|
+
silentCatch: "This rejection handler swallows the error without logging, rethrowing, or handling it \u2014 failures become invisible and callers get an indistinguishable sentinel. Log the error (and only then map to a fallback), or let it propagate."
|
|
5607
5674
|
}
|
|
5608
5675
|
},
|
|
5609
5676
|
defaultOptions: [],
|
|
@@ -5629,9 +5696,12 @@ var no_silent_promise_catch_default = createRule({
|
|
|
5629
5696
|
};
|
|
5630
5697
|
return {
|
|
5631
5698
|
CallExpression(node) {
|
|
5632
|
-
if (node.callee.type !== import_utils34.AST_NODE_TYPES.MemberExpression || node.callee.computed || node.callee.property.type !== import_utils34.AST_NODE_TYPES.Identifier
|
|
5699
|
+
if (node.callee.type !== import_utils34.AST_NODE_TYPES.MemberExpression || node.callee.computed || node.callee.property.type !== import_utils34.AST_NODE_TYPES.Identifier) {
|
|
5633
5700
|
return;
|
|
5634
5701
|
}
|
|
5702
|
+
const method = node.callee.property.name;
|
|
5703
|
+
const handlerIndex = method === "catch" ? 0 : method === "then" ? 1 : null;
|
|
5704
|
+
if (handlerIndex === null) return;
|
|
5635
5705
|
if (isBodyParseCall(node.callee.object)) {
|
|
5636
5706
|
return;
|
|
5637
5707
|
}
|
|
@@ -5641,10 +5711,11 @@ var no_silent_promise_catch_default = createRule({
|
|
|
5641
5711
|
if (node.parent.type === import_utils34.AST_NODE_TYPES.MemberExpression && node.parent.object === node) {
|
|
5642
5712
|
return;
|
|
5643
5713
|
}
|
|
5644
|
-
|
|
5714
|
+
const expectedArguments = method === "catch" ? 1 : 2;
|
|
5715
|
+
if (node.arguments.length !== expectedArguments) {
|
|
5645
5716
|
return;
|
|
5646
5717
|
}
|
|
5647
|
-
const handler = node.arguments[
|
|
5718
|
+
const handler = node.arguments[handlerIndex];
|
|
5648
5719
|
if (handler === void 0 || handler.type !== import_utils34.AST_NODE_TYPES.ArrowFunctionExpression && handler.type !== import_utils34.AST_NODE_TYPES.FunctionExpression) {
|
|
5649
5720
|
return;
|
|
5650
5721
|
}
|
|
@@ -5907,6 +5978,11 @@ function isStringLiteralInit(node) {
|
|
|
5907
5978
|
return false;
|
|
5908
5979
|
}
|
|
5909
5980
|
function isConcatOntoTarget(rhs, target) {
|
|
5981
|
+
if (rhs.type === "TemplateLiteral") {
|
|
5982
|
+
return rhs.expressions.some(
|
|
5983
|
+
(expression) => expression.type === "Identifier" && expression.name === target
|
|
5984
|
+
);
|
|
5985
|
+
}
|
|
5910
5986
|
if (rhs.type !== "BinaryExpression" || rhs.operator !== "+") {
|
|
5911
5987
|
return false;
|
|
5912
5988
|
}
|
|
@@ -7459,6 +7535,15 @@ var SUCCESS_PAYLOAD_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
|
7459
7535
|
"value"
|
|
7460
7536
|
]);
|
|
7461
7537
|
var REQUIRED_STATUS_MEMBER_COUNT = 1;
|
|
7538
|
+
var FUNCTION_RETURN_OWNER_TYPES = /* @__PURE__ */ new Set([
|
|
7539
|
+
import_utils51.AST_NODE_TYPES.ArrowFunctionExpression,
|
|
7540
|
+
import_utils51.AST_NODE_TYPES.FunctionDeclaration,
|
|
7541
|
+
import_utils51.AST_NODE_TYPES.FunctionExpression,
|
|
7542
|
+
import_utils51.AST_NODE_TYPES.TSDeclareFunction,
|
|
7543
|
+
import_utils51.AST_NODE_TYPES.TSEmptyBodyFunctionExpression,
|
|
7544
|
+
import_utils51.AST_NODE_TYPES.TSFunctionType,
|
|
7545
|
+
import_utils51.AST_NODE_TYPES.TSMethodSignature
|
|
7546
|
+
]);
|
|
7462
7547
|
function looksLikeMutuallyExclusiveState(typeLiteral) {
|
|
7463
7548
|
let statusMemberCount = 0;
|
|
7464
7549
|
let hasFailurePayload = false;
|
|
@@ -7499,6 +7584,17 @@ function getMemberName(member) {
|
|
|
7499
7584
|
function isBooleanTyped(member) {
|
|
7500
7585
|
return member.typeAnnotation?.typeAnnotation.type === import_utils51.AST_NODE_TYPES.TSBooleanKeyword;
|
|
7501
7586
|
}
|
|
7587
|
+
function inlineReturnTypeLiteral(node) {
|
|
7588
|
+
let annotation = null;
|
|
7589
|
+
if (node.parent.type === import_utils51.AST_NODE_TYPES.TSTypeAnnotation) {
|
|
7590
|
+
annotation = node.parent;
|
|
7591
|
+
} else if (node.parent.type === import_utils51.AST_NODE_TYPES.TSTypeParameterInstantiation && node.parent.params.length === 1 && node.parent.params[0] === node && node.parent.parent.type === import_utils51.AST_NODE_TYPES.TSTypeReference && node.parent.parent.typeName.type === import_utils51.AST_NODE_TYPES.Identifier && node.parent.parent.typeName.name === "Promise" && node.parent.parent.parent.type === import_utils51.AST_NODE_TYPES.TSTypeAnnotation) {
|
|
7592
|
+
annotation = node.parent.parent.parent;
|
|
7593
|
+
}
|
|
7594
|
+
if (annotation === null) return null;
|
|
7595
|
+
const owner = annotation.parent;
|
|
7596
|
+
return FUNCTION_RETURN_OWNER_TYPES.has(owner.type) && "returnType" in owner && owner.returnType === annotation ? annotation : null;
|
|
7597
|
+
}
|
|
7502
7598
|
var prefer_discriminated_union_default = createRule({
|
|
7503
7599
|
name: "prefer-discriminated-union",
|
|
7504
7600
|
meta: {
|
|
@@ -7538,6 +7634,10 @@ var prefer_discriminated_union_default = createRule({
|
|
|
7538
7634
|
},
|
|
7539
7635
|
"TSTypeAliasDeclaration > TSTypeLiteral"(node) {
|
|
7540
7636
|
checkTypeLiteral(node, node.parent);
|
|
7637
|
+
},
|
|
7638
|
+
TSTypeLiteral(node) {
|
|
7639
|
+
const annotation = inlineReturnTypeLiteral(node);
|
|
7640
|
+
if (annotation !== null) checkTypeLiteral(node, annotation);
|
|
7541
7641
|
}
|
|
7542
7642
|
};
|
|
7543
7643
|
}
|
|
@@ -8960,7 +9060,7 @@ var isSchemaParseReference = (node) => {
|
|
|
8960
9060
|
const inner = unwrap4(node);
|
|
8961
9061
|
return inner !== null && inner.type === import_utils59.AST_NODE_TYPES.MemberExpression && !inner.computed && inner.property.type === import_utils59.AST_NODE_TYPES.Identifier && (inner.property.name === "parse" || inner.property.name === "safeParse");
|
|
8962
9062
|
};
|
|
8963
|
-
var isRawPayloadSource = (node) => {
|
|
9063
|
+
var isRawPayloadSource = (node, isKnownLocalText) => {
|
|
8964
9064
|
let current = unwrap4(node);
|
|
8965
9065
|
if (current === null) return false;
|
|
8966
9066
|
if (current.type === import_utils59.AST_NODE_TYPES.AwaitExpression) {
|
|
@@ -8984,20 +9084,26 @@ var isRawPayloadSource = (node) => {
|
|
|
8984
9084
|
return !current.arguments.some(isSchemaParseReference) && isRawPayloadSource(callee.object);
|
|
8985
9085
|
}
|
|
8986
9086
|
const object = unwrap4(callee.object);
|
|
8987
|
-
return property.name === "parse" && object !== null && object.type === import_utils59.AST_NODE_TYPES.Identifier && object.name === "JSON" && !isLocalFileRead(current.arguments[0]);
|
|
9087
|
+
return property.name === "parse" && object !== null && object.type === import_utils59.AST_NODE_TYPES.Identifier && object.name === "JSON" && !isLocalFileRead(current.arguments[0]) && isKnownLocalText?.(current.arguments[0]) !== true;
|
|
8988
9088
|
};
|
|
8989
9089
|
var FILE_READ_RE = /^(readFile|readFileSync|readJson|readJsonSync|readJSON)$/;
|
|
9090
|
+
var isDirectLocalFileRead = (node) => {
|
|
9091
|
+
let current = unwrap4(node);
|
|
9092
|
+
if (current?.type === import_utils59.AST_NODE_TYPES.AwaitExpression) {
|
|
9093
|
+
current = unwrap4(current.argument);
|
|
9094
|
+
}
|
|
9095
|
+
if (current?.type !== import_utils59.AST_NODE_TYPES.CallExpression) return false;
|
|
9096
|
+
const callee = unwrap4(current.callee);
|
|
9097
|
+
const name = callee?.type === import_utils59.AST_NODE_TYPES.Identifier ? callee.name : callee?.type === import_utils59.AST_NODE_TYPES.MemberExpression && !callee.computed && callee.property.type === import_utils59.AST_NODE_TYPES.Identifier ? callee.property.name : null;
|
|
9098
|
+
return name !== null && FILE_READ_RE.test(name);
|
|
9099
|
+
};
|
|
8990
9100
|
var isLocalFileRead = (node) => {
|
|
8991
9101
|
let found = false;
|
|
8992
9102
|
const visit = (current) => {
|
|
8993
9103
|
if (found || current === null || current === void 0) return;
|
|
8994
|
-
if (current
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
if (name !== null && FILE_READ_RE.test(name)) {
|
|
8998
|
-
found = true;
|
|
8999
|
-
return;
|
|
9000
|
-
}
|
|
9104
|
+
if (isDirectLocalFileRead(current)) {
|
|
9105
|
+
found = true;
|
|
9106
|
+
return;
|
|
9001
9107
|
}
|
|
9002
9108
|
for (const key of Object.keys(current)) {
|
|
9003
9109
|
if (key === "parent") continue;
|
|
@@ -9059,6 +9165,87 @@ var isValidationRead = (node) => {
|
|
|
9059
9165
|
}
|
|
9060
9166
|
return callee.type === import_utils59.AST_NODE_TYPES.Identifier && GUARD_NAME_RE.test(callee.name);
|
|
9061
9167
|
};
|
|
9168
|
+
var PRIMITIVE_TYPEOF_RESULTS = /* @__PURE__ */ new Set([
|
|
9169
|
+
"bigint",
|
|
9170
|
+
"boolean",
|
|
9171
|
+
"number",
|
|
9172
|
+
"string",
|
|
9173
|
+
"symbol",
|
|
9174
|
+
"undefined"
|
|
9175
|
+
]);
|
|
9176
|
+
var bindingValidationPolarity = (test, bindingName) => {
|
|
9177
|
+
if (test.type === import_utils59.AST_NODE_TYPES.UnaryExpression && test.operator === "!") {
|
|
9178
|
+
const inner = bindingValidationPolarity(test.argument, bindingName);
|
|
9179
|
+
return inner === "valid-when-true" ? "valid-when-false" : inner === "valid-when-false" ? "valid-when-true" : null;
|
|
9180
|
+
}
|
|
9181
|
+
if (test.type === import_utils59.AST_NODE_TYPES.BinaryExpression) {
|
|
9182
|
+
const typeofName = (node) => node.type === import_utils59.AST_NODE_TYPES.UnaryExpression && node.operator === "typeof" && node.argument.type === import_utils59.AST_NODE_TYPES.Identifier ? node.argument.name : null;
|
|
9183
|
+
const literalType = (node) => node.type === import_utils59.AST_NODE_TYPES.Literal && typeof node.value === "string" && PRIMITIVE_TYPEOF_RESULTS.has(node.value) ? node.value : null;
|
|
9184
|
+
const matches = typeofName(test.left) === bindingName && literalType(test.right) !== null || typeofName(test.right) === bindingName && literalType(test.left) !== null;
|
|
9185
|
+
if (!matches) return null;
|
|
9186
|
+
if (test.operator === "===" || test.operator === "==") {
|
|
9187
|
+
return "valid-when-true";
|
|
9188
|
+
}
|
|
9189
|
+
return test.operator === "!==" || test.operator === "!=" ? "valid-when-false" : null;
|
|
9190
|
+
}
|
|
9191
|
+
return test.type === import_utils59.AST_NODE_TYPES.CallExpression && test.arguments.length === 1 && test.arguments[0]?.type === import_utils59.AST_NODE_TYPES.Identifier && test.arguments[0].name === bindingName && test.callee.type === import_utils59.AST_NODE_TYPES.MemberExpression && !test.callee.computed && test.callee.object.type === import_utils59.AST_NODE_TYPES.Identifier && test.callee.object.name === "Array" && test.callee.property.type === import_utils59.AST_NODE_TYPES.Identifier && test.callee.property.name === "isArray" ? "valid-when-true" : null;
|
|
9192
|
+
};
|
|
9193
|
+
var nodeWithin2 = (node, container) => node.range[0] >= container.range[0] && node.range[1] <= container.range[1];
|
|
9194
|
+
var isFullyValidatedExtractedBinding = (member, source, context) => {
|
|
9195
|
+
const isValidationReference = (identifier) => {
|
|
9196
|
+
for (let current = identifier.parent; current !== void 0 && current !== null; current = current.parent) {
|
|
9197
|
+
if ((current.type === import_utils59.AST_NODE_TYPES.BinaryExpression || current.type === import_utils59.AST_NODE_TYPES.CallExpression || current.type === import_utils59.AST_NODE_TYPES.UnaryExpression) && bindingValidationPolarity(current, identifier.name) !== null) {
|
|
9198
|
+
return true;
|
|
9199
|
+
}
|
|
9200
|
+
if (current.type !== import_utils59.AST_NODE_TYPES.UnaryExpression && current.type !== import_utils59.AST_NODE_TYPES.MemberExpression && current.type !== import_utils59.AST_NODE_TYPES.CallExpression) {
|
|
9201
|
+
return false;
|
|
9202
|
+
}
|
|
9203
|
+
}
|
|
9204
|
+
return false;
|
|
9205
|
+
};
|
|
9206
|
+
const isGuardedUse = (identifier) => {
|
|
9207
|
+
for (let current = identifier.parent; current !== void 0 && current !== null; current = current.parent) {
|
|
9208
|
+
if (current.type === import_utils59.AST_NODE_TYPES.ConditionalExpression) {
|
|
9209
|
+
const polarity = bindingValidationPolarity(current.test, identifier.name);
|
|
9210
|
+
if (polarity === "valid-when-true" && nodeWithin2(identifier, current.consequent)) {
|
|
9211
|
+
return true;
|
|
9212
|
+
}
|
|
9213
|
+
if (polarity === "valid-when-false" && nodeWithin2(identifier, current.alternate)) {
|
|
9214
|
+
return true;
|
|
9215
|
+
}
|
|
9216
|
+
}
|
|
9217
|
+
if (current.type === import_utils59.AST_NODE_TYPES.IfStatement) {
|
|
9218
|
+
const polarity = bindingValidationPolarity(current.test, identifier.name);
|
|
9219
|
+
if (polarity === "valid-when-true" && nodeWithin2(identifier, current.consequent)) {
|
|
9220
|
+
return true;
|
|
9221
|
+
}
|
|
9222
|
+
if (polarity === "valid-when-false" && current.alternate !== null && nodeWithin2(identifier, current.alternate)) {
|
|
9223
|
+
return true;
|
|
9224
|
+
}
|
|
9225
|
+
}
|
|
9226
|
+
if (current.type === import_utils59.AST_NODE_TYPES.FunctionDeclaration || current.type === import_utils59.AST_NODE_TYPES.FunctionExpression || current.type === import_utils59.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
9227
|
+
return false;
|
|
9228
|
+
}
|
|
9229
|
+
}
|
|
9230
|
+
return false;
|
|
9231
|
+
};
|
|
9232
|
+
const declarator = member.parent;
|
|
9233
|
+
if (declarator.type !== import_utils59.AST_NODE_TYPES.VariableDeclarator || declarator.init !== member || declarator.id.type !== import_utils59.AST_NODE_TYPES.Identifier || declarator.parent.type !== import_utils59.AST_NODE_TYPES.VariableDeclaration || declarator.parent.kind !== "const") {
|
|
9234
|
+
return false;
|
|
9235
|
+
}
|
|
9236
|
+
const extracted = context.sourceCode.getDeclaredVariables(declarator)[0];
|
|
9237
|
+
if (extracted === void 0 || extracted.scope !== source.scope) return false;
|
|
9238
|
+
let hasValueUse = false;
|
|
9239
|
+
for (const reference of extracted.references) {
|
|
9240
|
+
const identifier = reference.identifier;
|
|
9241
|
+
if (identifier.type !== import_utils59.AST_NODE_TYPES.Identifier) return false;
|
|
9242
|
+
if (nodeWithin2(identifier, declarator)) continue;
|
|
9243
|
+
if (isValidationReference(identifier)) continue;
|
|
9244
|
+
hasValueUse = true;
|
|
9245
|
+
if (!isGuardedUse(identifier)) return false;
|
|
9246
|
+
}
|
|
9247
|
+
return hasValueUse;
|
|
9248
|
+
};
|
|
9062
9249
|
var isGuardTestPosition = (node) => {
|
|
9063
9250
|
let current = node;
|
|
9064
9251
|
let parent = current.parent;
|
|
@@ -9082,13 +9269,13 @@ var isGuardTestPosition = (node) => {
|
|
|
9082
9269
|
}
|
|
9083
9270
|
return false;
|
|
9084
9271
|
};
|
|
9085
|
-
var
|
|
9272
|
+
var unvalidatedVariableRef = (node, scope, tracked) => {
|
|
9086
9273
|
const unwrapped = unwrap4(node);
|
|
9087
9274
|
if (unwrapped === null || unwrapped.type !== import_utils59.AST_NODE_TYPES.Identifier) {
|
|
9088
|
-
return
|
|
9275
|
+
return null;
|
|
9089
9276
|
}
|
|
9090
9277
|
const variable = findVariable2(scope, unwrapped.name);
|
|
9091
|
-
return variable !== null && tracked.has(variable);
|
|
9278
|
+
return variable !== null && tracked.has(variable) ? variable : null;
|
|
9092
9279
|
};
|
|
9093
9280
|
var prefer_schema_for_api_payload_default = createRule({
|
|
9094
9281
|
name: "prefer-schema-for-api-payload",
|
|
@@ -9108,6 +9295,56 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9108
9295
|
return {};
|
|
9109
9296
|
}
|
|
9110
9297
|
const unvalidatedVariables = /* @__PURE__ */ new Set();
|
|
9298
|
+
const aliasGroups = /* @__PURE__ */ new Map();
|
|
9299
|
+
const localFileTextVariables = /* @__PURE__ */ new Set();
|
|
9300
|
+
const localFileTextRef = (node, scope) => {
|
|
9301
|
+
const unwrapped = unwrap4(node);
|
|
9302
|
+
if (unwrapped?.type !== import_utils59.AST_NODE_TYPES.Identifier) return null;
|
|
9303
|
+
const variable = findVariable2(scope, unwrapped.name);
|
|
9304
|
+
return variable !== null && localFileTextVariables.has(variable) ? variable : null;
|
|
9305
|
+
};
|
|
9306
|
+
const updateLocalFileText = (target, value, scope) => {
|
|
9307
|
+
const source = localFileTextRef(value, scope);
|
|
9308
|
+
if (isDirectLocalFileRead(value) || source !== null && source.scope === target.scope) {
|
|
9309
|
+
localFileTextVariables.add(target);
|
|
9310
|
+
} else {
|
|
9311
|
+
localFileTextVariables.delete(target);
|
|
9312
|
+
}
|
|
9313
|
+
};
|
|
9314
|
+
const clearBinding = (variable) => {
|
|
9315
|
+
unvalidatedVariables.delete(variable);
|
|
9316
|
+
const group = aliasGroups.get(variable);
|
|
9317
|
+
aliasGroups.delete(variable);
|
|
9318
|
+
group?.delete(variable);
|
|
9319
|
+
};
|
|
9320
|
+
const clearAliasGroup = (variable) => {
|
|
9321
|
+
const group = aliasGroups.get(variable);
|
|
9322
|
+
if (group === void 0) {
|
|
9323
|
+
unvalidatedVariables.delete(variable);
|
|
9324
|
+
return;
|
|
9325
|
+
}
|
|
9326
|
+
for (const alias of group) {
|
|
9327
|
+
unvalidatedVariables.delete(alias);
|
|
9328
|
+
aliasGroups.delete(alias);
|
|
9329
|
+
}
|
|
9330
|
+
group.clear();
|
|
9331
|
+
};
|
|
9332
|
+
const trackRawBinding = (variable) => {
|
|
9333
|
+
clearBinding(variable);
|
|
9334
|
+
const group = /* @__PURE__ */ new Set([variable]);
|
|
9335
|
+
unvalidatedVariables.add(variable);
|
|
9336
|
+
aliasGroups.set(variable, group);
|
|
9337
|
+
};
|
|
9338
|
+
const trackAlias = (target, source) => {
|
|
9339
|
+
if (target === source) return;
|
|
9340
|
+
const group = aliasGroups.get(source) ?? /* @__PURE__ */ new Set([source]);
|
|
9341
|
+
if (aliasGroups.get(target) === group) return;
|
|
9342
|
+
clearBinding(target);
|
|
9343
|
+
unvalidatedVariables.add(target);
|
|
9344
|
+
group.add(target);
|
|
9345
|
+
aliasGroups.set(source, group);
|
|
9346
|
+
aliasGroups.set(target, group);
|
|
9347
|
+
};
|
|
9111
9348
|
const isFullyNarrowedPattern = (declarator) => {
|
|
9112
9349
|
const declared = context.sourceCode.getDeclaredVariables(declarator);
|
|
9113
9350
|
return declared.length > 0 && declared.every(
|
|
@@ -9116,29 +9353,40 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9116
9353
|
)
|
|
9117
9354
|
);
|
|
9118
9355
|
};
|
|
9119
|
-
const trackInitializer = (declarator) => {
|
|
9120
|
-
if (!isRawPayloadSource(declarator.init)) return;
|
|
9356
|
+
const trackInitializer = (declarator, scope) => {
|
|
9121
9357
|
const declaredVars = context.sourceCode.getDeclaredVariables(declarator);
|
|
9122
9358
|
const variable = declaredVars[0];
|
|
9123
|
-
if (variable
|
|
9124
|
-
|
|
9359
|
+
if (variable === void 0) return;
|
|
9360
|
+
const localText = (candidate) => localFileTextRef(candidate, scope) !== null;
|
|
9361
|
+
if (isRawPayloadSource(declarator.init, localText)) {
|
|
9362
|
+
trackRawBinding(variable);
|
|
9363
|
+
return;
|
|
9125
9364
|
}
|
|
9365
|
+
const source = unvalidatedVariableRef(declarator.init, scope, unvalidatedVariables);
|
|
9366
|
+
if (source !== null) trackAlias(variable, source);
|
|
9126
9367
|
};
|
|
9127
9368
|
return {
|
|
9128
9369
|
VariableDeclarator(node) {
|
|
9129
9370
|
const scope = context.sourceCode.getScope(node);
|
|
9130
9371
|
if (node.id.type === import_utils59.AST_NODE_TYPES.Identifier) {
|
|
9131
|
-
|
|
9372
|
+
const variable = context.sourceCode.getDeclaredVariables(node)[0];
|
|
9373
|
+
if (variable !== void 0) {
|
|
9374
|
+
updateLocalFileText(variable, node.init, scope);
|
|
9375
|
+
}
|
|
9376
|
+
trackInitializer(node, scope);
|
|
9132
9377
|
return;
|
|
9133
9378
|
}
|
|
9134
9379
|
if (node.id.type === import_utils59.AST_NODE_TYPES.ObjectPattern || node.id.type === import_utils59.AST_NODE_TYPES.ArrayPattern) {
|
|
9135
|
-
if (isRawPayloadSource(
|
|
9380
|
+
if (isRawPayloadSource(
|
|
9381
|
+
node.init,
|
|
9382
|
+
(candidate) => localFileTextRef(candidate, scope) !== null
|
|
9383
|
+
)) {
|
|
9136
9384
|
if (!isFullyNarrowedPattern(node)) {
|
|
9137
9385
|
context.report({ node: node.id, messageId: "unparsedJsonAccess" });
|
|
9138
9386
|
}
|
|
9139
9387
|
return;
|
|
9140
9388
|
}
|
|
9141
|
-
if (
|
|
9389
|
+
if (unvalidatedVariableRef(node.init, scope, unvalidatedVariables) !== null) {
|
|
9142
9390
|
context.report({ node: node.id, messageId: "unparsedJsonAccess" });
|
|
9143
9391
|
}
|
|
9144
9392
|
}
|
|
@@ -9148,22 +9396,29 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9148
9396
|
if (node.left.type === import_utils59.AST_NODE_TYPES.Identifier) {
|
|
9149
9397
|
const variable = findVariable2(scope, node.left.name);
|
|
9150
9398
|
if (variable === null) return;
|
|
9151
|
-
|
|
9152
|
-
|
|
9399
|
+
const isLocalText = (candidate) => localFileTextRef(candidate, scope) !== null;
|
|
9400
|
+
updateLocalFileText(variable, node.right, scope);
|
|
9401
|
+
if (isRawPayloadSource(node.right, isLocalText)) {
|
|
9402
|
+
trackRawBinding(variable);
|
|
9153
9403
|
} else {
|
|
9154
|
-
unvalidatedVariables
|
|
9404
|
+
const source = unvalidatedVariableRef(node.right, scope, unvalidatedVariables);
|
|
9405
|
+
if (source === null) clearBinding(variable);
|
|
9406
|
+
else trackAlias(variable, source);
|
|
9155
9407
|
}
|
|
9156
9408
|
return;
|
|
9157
9409
|
}
|
|
9158
9410
|
if (node.left.type === import_utils59.AST_NODE_TYPES.ObjectPattern || node.left.type === import_utils59.AST_NODE_TYPES.ArrayPattern) {
|
|
9159
|
-
if (isRawPayloadSource(
|
|
9411
|
+
if (isRawPayloadSource(
|
|
9412
|
+
node.right,
|
|
9413
|
+
(candidate) => localFileTextRef(candidate, scope) !== null
|
|
9414
|
+
)) {
|
|
9160
9415
|
context.report({
|
|
9161
9416
|
node: node.left,
|
|
9162
9417
|
messageId: "unparsedJsonAccess"
|
|
9163
9418
|
});
|
|
9164
9419
|
return;
|
|
9165
9420
|
}
|
|
9166
|
-
if (
|
|
9421
|
+
if (unvalidatedVariableRef(node.right, scope, unvalidatedVariables) !== null) {
|
|
9167
9422
|
context.report({
|
|
9168
9423
|
node: node.left,
|
|
9169
9424
|
messageId: "unparsedJsonAccess"
|
|
@@ -9184,7 +9439,7 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9184
9439
|
continue;
|
|
9185
9440
|
}
|
|
9186
9441
|
const variable = findVariable2(scope, unwrapped.name);
|
|
9187
|
-
if (variable !== null)
|
|
9442
|
+
if (variable !== null) clearAliasGroup(variable);
|
|
9188
9443
|
}
|
|
9189
9444
|
},
|
|
9190
9445
|
MemberExpression(node) {
|
|
@@ -9192,7 +9447,10 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9192
9447
|
if (isValidationRead(node)) return;
|
|
9193
9448
|
const scope = context.sourceCode.getScope(node);
|
|
9194
9449
|
const obj = unwrap4(node.object);
|
|
9195
|
-
if (isRawPayloadSource(
|
|
9450
|
+
if (isRawPayloadSource(
|
|
9451
|
+
obj,
|
|
9452
|
+
(candidate) => localFileTextRef(candidate, scope) !== null
|
|
9453
|
+
)) {
|
|
9196
9454
|
const parent = node.parent;
|
|
9197
9455
|
if (parent.type === import_utils59.AST_NODE_TYPES.CallExpression && parent.callee === node && node.property.type === import_utils59.AST_NODE_TYPES.Identifier && (node.property.name === "parse" || node.property.name === "safeParse" || PROMISE_CHAIN_METHODS.has(node.property.name))) {
|
|
9198
9456
|
return;
|
|
@@ -9200,12 +9458,13 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9200
9458
|
context.report({ node, messageId: "unparsedJsonAccess" });
|
|
9201
9459
|
return;
|
|
9202
9460
|
}
|
|
9203
|
-
|
|
9204
|
-
|
|
9205
|
-
|
|
9206
|
-
|
|
9207
|
-
unvalidatedVariables.delete(variable);
|
|
9461
|
+
const variable = obj?.type === import_utils59.AST_NODE_TYPES.Identifier ? unvalidatedVariableRef(obj, scope, unvalidatedVariables) : null;
|
|
9462
|
+
if (variable !== null) {
|
|
9463
|
+
if (isFullyValidatedExtractedBinding(node, variable, context)) {
|
|
9464
|
+
return;
|
|
9208
9465
|
}
|
|
9466
|
+
context.report({ node, messageId: "unparsedJsonAccess" });
|
|
9467
|
+
clearAliasGroup(variable);
|
|
9209
9468
|
}
|
|
9210
9469
|
}
|
|
9211
9470
|
};
|
|
@@ -10969,8 +11228,8 @@ function initProvablyLacksSignal(init) {
|
|
|
10969
11228
|
}
|
|
10970
11229
|
return true;
|
|
10971
11230
|
}
|
|
10972
|
-
function
|
|
10973
|
-
return node.type === import_utils67.AST_NODE_TYPES.Literal && typeof node.value === "string" || node.type === import_utils67.AST_NODE_TYPES.TemplateLiteral;
|
|
11231
|
+
function isInlineUrl(node, resolvesToGlobal) {
|
|
11232
|
+
return node.type === import_utils67.AST_NODE_TYPES.Literal && typeof node.value === "string" || node.type === import_utils67.AST_NODE_TYPES.TemplateLiteral || node.type === import_utils67.AST_NODE_TYPES.NewExpression && node.callee.type === import_utils67.AST_NODE_TYPES.Identifier && node.callee.name === "URL" && resolvesToGlobal(node.callee);
|
|
10974
11233
|
}
|
|
10975
11234
|
var require_fetch_timeout_default = createRule({
|
|
10976
11235
|
name: "require-fetch-timeout",
|
|
@@ -11022,7 +11281,7 @@ var require_fetch_timeout_default = createRule({
|
|
|
11022
11281
|
return;
|
|
11023
11282
|
}
|
|
11024
11283
|
const [first, init] = node.arguments;
|
|
11025
|
-
if (node.arguments.length === 1 && first !== void 0 && !
|
|
11284
|
+
if (node.arguments.length === 1 && first !== void 0 && !isInlineUrl(first, resolvesToGlobal)) {
|
|
11026
11285
|
return;
|
|
11027
11286
|
}
|
|
11028
11287
|
if (init === void 0 || initProvablyLacksSignal(init)) {
|
|
@@ -11039,7 +11298,7 @@ var CONFIGISH_TYPE_RE = /(?:Options|Opts|Config|Configuration|Settings|Params|Pr
|
|
|
11039
11298
|
var CONFIGISH_NAME_RE = /^(?:options|opts|config|configuration|settings|params|props|args|env|environment|callbacks|flags|logger|log|clock)$/i;
|
|
11040
11299
|
var HTTP_TRANSPORT_TYPE_RE = /^(?:KyInstance|AxiosInstance|Session)$/;
|
|
11041
11300
|
var BUILTIN_CONTAINER_TYPE_RE = /^(?:Record|Map|WeakMap|Set|WeakSet|Array|ReadonlyArray|ReadonlyMap|ReadonlySet|Promise|Partial|Required|Readonly|Pick|Omit|Exclude|Extract|NonNullable|Awaited|Parameters|ReturnType|InstanceType)$/;
|
|
11042
|
-
var VALUE_TYPE_RE = /^(?:ArrayBuffer|Blob|Buffer|Date|RegExp|URL|URLSearchParams)$/;
|
|
11301
|
+
var VALUE_TYPE_RE = /^(?:ArrayBuffer|Blob|Buffer|Date|NodePath|RegExp|URL|URLSearchParams)$/;
|
|
11043
11302
|
var TRANSPORT_WRAPPER_NAME_RE = /(?:Client$|^Http[A-Z])/;
|
|
11044
11303
|
var ERROR_VALUE_NAME_RE = /Error$/;
|
|
11045
11304
|
var FLUENT_BUILDER_NAME_RE = /Builder$/;
|
|
@@ -11503,7 +11762,7 @@ var require_interface_for_injected_service_default = createRule({
|
|
|
11503
11762
|
if (node.abstract === true) return;
|
|
11504
11763
|
if (node.decorators.length > 0) return;
|
|
11505
11764
|
const ctor = node.body.body.find(
|
|
11506
|
-
(member) => member.type === import_utils68.AST_NODE_TYPES.MethodDefinition && member.kind === "constructor"
|
|
11765
|
+
(member) => member.type === import_utils68.AST_NODE_TYPES.MethodDefinition && member.kind === "constructor" && member.value.body !== null && member.value.body !== void 0
|
|
11507
11766
|
);
|
|
11508
11767
|
if (ctor === void 0) return;
|
|
11509
11768
|
const constructorFacts = readConstructor(
|
|
@@ -12382,7 +12641,7 @@ var rules = {
|
|
|
12382
12641
|
};
|
|
12383
12642
|
var meta = {
|
|
12384
12643
|
name: "@sarj/eslint-plugin",
|
|
12385
|
-
version: "11.0
|
|
12644
|
+
version: "11.1.0"
|
|
12386
12645
|
};
|
|
12387
12646
|
var applicationOnlyRules = [
|
|
12388
12647
|
"no-restricted-library-load",
|
package/dist/index.d.cts
CHANGED
|
@@ -453,7 +453,7 @@ type FlatPreset = {
|
|
|
453
453
|
declare const plugin: {
|
|
454
454
|
readonly meta: {
|
|
455
455
|
readonly name: "@sarj/eslint-plugin";
|
|
456
|
-
readonly version: "11.0
|
|
456
|
+
readonly version: "11.1.0";
|
|
457
457
|
};
|
|
458
458
|
readonly rules: {
|
|
459
459
|
readonly "duplicate-test-body": _typescript_eslint_utils_ts_eslint.RuleModule<"duplicateTestBody", readonly [], unknown, _typescript_eslint_utils_ts_eslint.RuleListener> & {
|