@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.d.ts
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> & {
|
package/dist/index.js
CHANGED
|
@@ -2899,6 +2899,16 @@ var PAYLOAD_PROPS = /* @__PURE__ */ new Set([
|
|
|
2899
2899
|
"metadata",
|
|
2900
2900
|
"context"
|
|
2901
2901
|
]);
|
|
2902
|
+
var BUILTIN_ERROR_CONSTRUCTORS = /* @__PURE__ */ new Set([
|
|
2903
|
+
"AggregateError",
|
|
2904
|
+
"Error",
|
|
2905
|
+
"EvalError",
|
|
2906
|
+
"RangeError",
|
|
2907
|
+
"ReferenceError",
|
|
2908
|
+
"SyntaxError",
|
|
2909
|
+
"TypeError",
|
|
2910
|
+
"URIError"
|
|
2911
|
+
]);
|
|
2902
2912
|
function isCatchBinding(scope, name) {
|
|
2903
2913
|
let current = scope;
|
|
2904
2914
|
while (current) {
|
|
@@ -3013,6 +3023,48 @@ function nodeWithin(node, container) {
|
|
|
3013
3023
|
function isJsonStringify(callee) {
|
|
3014
3024
|
return callee.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "JSON" && callee.property.type === "Identifier" && callee.property.name === "stringify";
|
|
3015
3025
|
}
|
|
3026
|
+
function directLiteralValues(argument) {
|
|
3027
|
+
if (argument.type === "ObjectExpression") {
|
|
3028
|
+
return argument.properties.flatMap((property) => {
|
|
3029
|
+
if (property.type !== "Property" || property.computed) return [];
|
|
3030
|
+
const value = property.value;
|
|
3031
|
+
if (value.type === "AssignmentPattern" || value.type === "ArrayPattern" || value.type === "ObjectPattern" || value.type === "TSEmptyBodyFunctionExpression") {
|
|
3032
|
+
return [];
|
|
3033
|
+
}
|
|
3034
|
+
return [value];
|
|
3035
|
+
});
|
|
3036
|
+
}
|
|
3037
|
+
if (argument.type === "ArrayExpression") {
|
|
3038
|
+
return argument.elements.flatMap(
|
|
3039
|
+
(element) => element !== null && element.type !== "SpreadElement" ? [element] : []
|
|
3040
|
+
);
|
|
3041
|
+
}
|
|
3042
|
+
return argument.type === "SpreadElement" ? [] : [argument];
|
|
3043
|
+
}
|
|
3044
|
+
function expressionSuggestsError(expression, scope) {
|
|
3045
|
+
if (expression.type === "Identifier") {
|
|
3046
|
+
return ERROR_NAME_PATTERN.test(expression.name) || isCatchBinding(scope, expression.name);
|
|
3047
|
+
}
|
|
3048
|
+
return expression.type === "MemberExpression" && memberSuggestsError(expression, scope);
|
|
3049
|
+
}
|
|
3050
|
+
function nestedExpressionSuggestsError(expression, scope) {
|
|
3051
|
+
if (expression.type === "Identifier") {
|
|
3052
|
+
if (isCatchBinding(scope, expression.name)) return true;
|
|
3053
|
+
let current = scope;
|
|
3054
|
+
while (current !== null && !current.set.has(expression.name)) {
|
|
3055
|
+
current = current.upper;
|
|
3056
|
+
}
|
|
3057
|
+
const variable = current?.set.get(expression.name);
|
|
3058
|
+
if (variable === void 0 || variable.defs.length !== 1) return false;
|
|
3059
|
+
const definition = variable.defs[0];
|
|
3060
|
+
if (definition?.type !== "Variable") return false;
|
|
3061
|
+
const initializer = definition.node.init;
|
|
3062
|
+
return initializer?.type === "NewExpression" && initializer.callee.type === "Identifier" && BUILTIN_ERROR_CONSTRUCTORS.has(initializer.callee.name) && variable.references.every(
|
|
3063
|
+
(reference) => !reference.isWrite() || reference.init === true
|
|
3064
|
+
);
|
|
3065
|
+
}
|
|
3066
|
+
return expression.type === "MemberExpression" && memberSuggestsError(expression, scope);
|
|
3067
|
+
}
|
|
3016
3068
|
var no_json_stringify_error_default = createRule({
|
|
3017
3069
|
name: "no-json-stringify-error",
|
|
3018
3070
|
meta: {
|
|
@@ -3037,18 +3089,11 @@ var no_json_stringify_error_default = createRule({
|
|
|
3037
3089
|
return;
|
|
3038
3090
|
}
|
|
3039
3091
|
const scope = context.sourceCode.getScope(firstArg);
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
} else {
|
|
3046
|
-
return;
|
|
3047
|
-
}
|
|
3048
|
-
if (!suggestsError) {
|
|
3049
|
-
return;
|
|
3050
|
-
}
|
|
3051
|
-
if (isGuardedByInstanceofError(node, firstArg, context.sourceCode) || isNarrowedByEarlyReturn(node, firstArg, context.sourceCode)) {
|
|
3092
|
+
const isNestedLiteral = firstArg.type === "ObjectExpression" || firstArg.type === "ArrayExpression";
|
|
3093
|
+
const unsafeValue = directLiteralValues(firstArg).find(
|
|
3094
|
+
(value) => (isNestedLiteral ? nestedExpressionSuggestsError(value, scope) : expressionSuggestsError(value, scope)) && !isGuardedByInstanceofError(node, value, context.sourceCode) && !isNarrowedByEarlyReturn(node, value, context.sourceCode)
|
|
3095
|
+
);
|
|
3096
|
+
if (unsafeValue === void 0) {
|
|
3052
3097
|
return;
|
|
3053
3098
|
}
|
|
3054
3099
|
context.report({
|
|
@@ -5118,50 +5163,59 @@ var no_select_star_default = createRule({
|
|
|
5118
5163
|
|
|
5119
5164
|
// src/rules/no-sentinel-return-on-catch.ts
|
|
5120
5165
|
import { AST_NODE_TYPES as AST_NODE_TYPES23 } from "@typescript-eslint/utils";
|
|
5166
|
+
function unwrapSentinelExpression(arg) {
|
|
5167
|
+
let current = arg;
|
|
5168
|
+
while (current?.type === AST_NODE_TYPES23.TSAsExpression || current?.type === AST_NODE_TYPES23.TSTypeAssertion || current?.type === AST_NODE_TYPES23.TSSatisfiesExpression) {
|
|
5169
|
+
current = current.expression;
|
|
5170
|
+
}
|
|
5171
|
+
return current;
|
|
5172
|
+
}
|
|
5121
5173
|
function sentinelKind(arg) {
|
|
5122
|
-
|
|
5174
|
+
const value = unwrapSentinelExpression(arg);
|
|
5175
|
+
if (value === null) {
|
|
5123
5176
|
return null;
|
|
5124
5177
|
}
|
|
5125
|
-
if (
|
|
5126
|
-
if (
|
|
5178
|
+
if (value.type === AST_NODE_TYPES23.Literal) {
|
|
5179
|
+
if (value.value === null) {
|
|
5127
5180
|
return "nullish";
|
|
5128
5181
|
}
|
|
5129
|
-
if (typeof
|
|
5182
|
+
if (typeof value.value === "boolean") {
|
|
5130
5183
|
return "boolean";
|
|
5131
5184
|
}
|
|
5132
|
-
if (typeof
|
|
5185
|
+
if (typeof value.value === "string") {
|
|
5133
5186
|
return "string";
|
|
5134
5187
|
}
|
|
5135
5188
|
return null;
|
|
5136
5189
|
}
|
|
5137
|
-
if (
|
|
5190
|
+
if (value.type === AST_NODE_TYPES23.Identifier && value.name === "undefined") {
|
|
5138
5191
|
return "nullish";
|
|
5139
5192
|
}
|
|
5140
|
-
if (
|
|
5193
|
+
if (value.type === AST_NODE_TYPES23.ArrayExpression) {
|
|
5141
5194
|
return "array";
|
|
5142
5195
|
}
|
|
5143
|
-
if (
|
|
5196
|
+
if (value.type === AST_NODE_TYPES23.ObjectExpression) {
|
|
5144
5197
|
return "object";
|
|
5145
5198
|
}
|
|
5146
5199
|
return null;
|
|
5147
5200
|
}
|
|
5148
5201
|
function isSentinelArgument(arg) {
|
|
5149
|
-
|
|
5202
|
+
const value = unwrapSentinelExpression(arg);
|
|
5203
|
+
if (value === null) {
|
|
5150
5204
|
return false;
|
|
5151
5205
|
}
|
|
5152
|
-
if (
|
|
5206
|
+
if (value.type === AST_NODE_TYPES23.Literal && value.value === null) {
|
|
5153
5207
|
return true;
|
|
5154
5208
|
}
|
|
5155
|
-
if (
|
|
5209
|
+
if (value.type === AST_NODE_TYPES23.Literal && value.value === false) {
|
|
5156
5210
|
return true;
|
|
5157
5211
|
}
|
|
5158
|
-
if (
|
|
5212
|
+
if (value.type === AST_NODE_TYPES23.Identifier && value.name === "undefined") {
|
|
5159
5213
|
return true;
|
|
5160
5214
|
}
|
|
5161
|
-
if (
|
|
5215
|
+
if (value.type === AST_NODE_TYPES23.ArrayExpression && value.elements.length === 0) {
|
|
5162
5216
|
return true;
|
|
5163
5217
|
}
|
|
5164
|
-
if (
|
|
5218
|
+
if (value.type === AST_NODE_TYPES23.ObjectExpression && value.properties.length === 0) {
|
|
5165
5219
|
return true;
|
|
5166
5220
|
}
|
|
5167
5221
|
return false;
|
|
@@ -5359,6 +5413,16 @@ function tryReturnsSafeParse(catchNode) {
|
|
|
5359
5413
|
const only = tryBlock.body.length === 1 ? tryBlock.body[0] : void 0;
|
|
5360
5414
|
return only !== void 0 && returnsMatching(only, isBodyDecodeNode);
|
|
5361
5415
|
}
|
|
5416
|
+
function isIntentionalStackCapture(catchNode, caughtName) {
|
|
5417
|
+
if (caughtName === null) return false;
|
|
5418
|
+
const tryBody = tryBlockOf(catchNode).body;
|
|
5419
|
+
const only = tryBody.length === 1 ? tryBody[0] : void 0;
|
|
5420
|
+
if (only?.type !== AST_NODE_TYPES23.ThrowStatement) return false;
|
|
5421
|
+
const thrown = unwrapSentinelExpression(only.argument);
|
|
5422
|
+
const constructsError = (thrown?.type === AST_NODE_TYPES23.CallExpression || thrown?.type === AST_NODE_TYPES23.NewExpression) && thrown.callee.type === AST_NODE_TYPES23.Identifier && thrown.callee.name === "Error";
|
|
5423
|
+
if (!constructsError) return false;
|
|
5424
|
+
return catchNode.body.body.slice(0, -1).some((statement) => subtreeReadsName(statement, caughtName));
|
|
5425
|
+
}
|
|
5362
5426
|
function tryBlockOf(catchNode) {
|
|
5363
5427
|
return catchNode.parent.block;
|
|
5364
5428
|
}
|
|
@@ -5479,6 +5543,9 @@ var no_sentinel_return_on_catch_default = createRule({
|
|
|
5479
5543
|
if (tryReturnsSafeParse(node)) {
|
|
5480
5544
|
return;
|
|
5481
5545
|
}
|
|
5546
|
+
if (isIntentionalStackCapture(node, caughtName)) {
|
|
5547
|
+
return;
|
|
5548
|
+
}
|
|
5482
5549
|
const kind = sentinelKind(last.argument);
|
|
5483
5550
|
if (kind !== null && isNamedBooleanPredicate(node, kind)) {
|
|
5484
5551
|
return;
|
|
@@ -5557,11 +5624,11 @@ var no_silent_promise_catch_default = createRule({
|
|
|
5557
5624
|
meta: {
|
|
5558
5625
|
type: "problem",
|
|
5559
5626
|
docs: {
|
|
5560
|
-
description: "Disallow `.catch()` handlers that silently swallow
|
|
5627
|
+
description: "Disallow `.catch()` and second-argument `.then()` handlers that silently swallow a rejection; log, rethrow, or handle the error."
|
|
5561
5628
|
},
|
|
5562
5629
|
schema: [],
|
|
5563
5630
|
messages: {
|
|
5564
|
-
silentCatch: "This
|
|
5631
|
+
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."
|
|
5565
5632
|
}
|
|
5566
5633
|
},
|
|
5567
5634
|
defaultOptions: [],
|
|
@@ -5587,9 +5654,12 @@ var no_silent_promise_catch_default = createRule({
|
|
|
5587
5654
|
};
|
|
5588
5655
|
return {
|
|
5589
5656
|
CallExpression(node) {
|
|
5590
|
-
if (node.callee.type !== AST_NODE_TYPES24.MemberExpression || node.callee.computed || node.callee.property.type !== AST_NODE_TYPES24.Identifier
|
|
5657
|
+
if (node.callee.type !== AST_NODE_TYPES24.MemberExpression || node.callee.computed || node.callee.property.type !== AST_NODE_TYPES24.Identifier) {
|
|
5591
5658
|
return;
|
|
5592
5659
|
}
|
|
5660
|
+
const method = node.callee.property.name;
|
|
5661
|
+
const handlerIndex = method === "catch" ? 0 : method === "then" ? 1 : null;
|
|
5662
|
+
if (handlerIndex === null) return;
|
|
5593
5663
|
if (isBodyParseCall(node.callee.object)) {
|
|
5594
5664
|
return;
|
|
5595
5665
|
}
|
|
@@ -5599,10 +5669,11 @@ var no_silent_promise_catch_default = createRule({
|
|
|
5599
5669
|
if (node.parent.type === AST_NODE_TYPES24.MemberExpression && node.parent.object === node) {
|
|
5600
5670
|
return;
|
|
5601
5671
|
}
|
|
5602
|
-
|
|
5672
|
+
const expectedArguments = method === "catch" ? 1 : 2;
|
|
5673
|
+
if (node.arguments.length !== expectedArguments) {
|
|
5603
5674
|
return;
|
|
5604
5675
|
}
|
|
5605
|
-
const handler = node.arguments[
|
|
5676
|
+
const handler = node.arguments[handlerIndex];
|
|
5606
5677
|
if (handler === void 0 || handler.type !== AST_NODE_TYPES24.ArrowFunctionExpression && handler.type !== AST_NODE_TYPES24.FunctionExpression) {
|
|
5607
5678
|
return;
|
|
5608
5679
|
}
|
|
@@ -5865,6 +5936,11 @@ function isStringLiteralInit(node) {
|
|
|
5865
5936
|
return false;
|
|
5866
5937
|
}
|
|
5867
5938
|
function isConcatOntoTarget(rhs, target) {
|
|
5939
|
+
if (rhs.type === "TemplateLiteral") {
|
|
5940
|
+
return rhs.expressions.some(
|
|
5941
|
+
(expression) => expression.type === "Identifier" && expression.name === target
|
|
5942
|
+
);
|
|
5943
|
+
}
|
|
5868
5944
|
if (rhs.type !== "BinaryExpression" || rhs.operator !== "+") {
|
|
5869
5945
|
return false;
|
|
5870
5946
|
}
|
|
@@ -7420,6 +7496,15 @@ var SUCCESS_PAYLOAD_MEMBER_NAMES = /* @__PURE__ */ new Set([
|
|
|
7420
7496
|
"value"
|
|
7421
7497
|
]);
|
|
7422
7498
|
var REQUIRED_STATUS_MEMBER_COUNT = 1;
|
|
7499
|
+
var FUNCTION_RETURN_OWNER_TYPES = /* @__PURE__ */ new Set([
|
|
7500
|
+
AST_NODE_TYPES37.ArrowFunctionExpression,
|
|
7501
|
+
AST_NODE_TYPES37.FunctionDeclaration,
|
|
7502
|
+
AST_NODE_TYPES37.FunctionExpression,
|
|
7503
|
+
AST_NODE_TYPES37.TSDeclareFunction,
|
|
7504
|
+
AST_NODE_TYPES37.TSEmptyBodyFunctionExpression,
|
|
7505
|
+
AST_NODE_TYPES37.TSFunctionType,
|
|
7506
|
+
AST_NODE_TYPES37.TSMethodSignature
|
|
7507
|
+
]);
|
|
7423
7508
|
function looksLikeMutuallyExclusiveState(typeLiteral) {
|
|
7424
7509
|
let statusMemberCount = 0;
|
|
7425
7510
|
let hasFailurePayload = false;
|
|
@@ -7460,6 +7545,17 @@ function getMemberName(member) {
|
|
|
7460
7545
|
function isBooleanTyped(member) {
|
|
7461
7546
|
return member.typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES37.TSBooleanKeyword;
|
|
7462
7547
|
}
|
|
7548
|
+
function inlineReturnTypeLiteral(node) {
|
|
7549
|
+
let annotation = null;
|
|
7550
|
+
if (node.parent.type === AST_NODE_TYPES37.TSTypeAnnotation) {
|
|
7551
|
+
annotation = node.parent;
|
|
7552
|
+
} else if (node.parent.type === AST_NODE_TYPES37.TSTypeParameterInstantiation && node.parent.params.length === 1 && node.parent.params[0] === node && node.parent.parent.type === AST_NODE_TYPES37.TSTypeReference && node.parent.parent.typeName.type === AST_NODE_TYPES37.Identifier && node.parent.parent.typeName.name === "Promise" && node.parent.parent.parent.type === AST_NODE_TYPES37.TSTypeAnnotation) {
|
|
7553
|
+
annotation = node.parent.parent.parent;
|
|
7554
|
+
}
|
|
7555
|
+
if (annotation === null) return null;
|
|
7556
|
+
const owner = annotation.parent;
|
|
7557
|
+
return FUNCTION_RETURN_OWNER_TYPES.has(owner.type) && "returnType" in owner && owner.returnType === annotation ? annotation : null;
|
|
7558
|
+
}
|
|
7463
7559
|
var prefer_discriminated_union_default = createRule({
|
|
7464
7560
|
name: "prefer-discriminated-union",
|
|
7465
7561
|
meta: {
|
|
@@ -7499,6 +7595,10 @@ var prefer_discriminated_union_default = createRule({
|
|
|
7499
7595
|
},
|
|
7500
7596
|
"TSTypeAliasDeclaration > TSTypeLiteral"(node) {
|
|
7501
7597
|
checkTypeLiteral(node, node.parent);
|
|
7598
|
+
},
|
|
7599
|
+
TSTypeLiteral(node) {
|
|
7600
|
+
const annotation = inlineReturnTypeLiteral(node);
|
|
7601
|
+
if (annotation !== null) checkTypeLiteral(node, annotation);
|
|
7502
7602
|
}
|
|
7503
7603
|
};
|
|
7504
7604
|
}
|
|
@@ -8921,7 +9021,7 @@ var isSchemaParseReference = (node) => {
|
|
|
8921
9021
|
const inner = unwrap4(node);
|
|
8922
9022
|
return inner !== null && inner.type === AST_NODE_TYPES45.MemberExpression && !inner.computed && inner.property.type === AST_NODE_TYPES45.Identifier && (inner.property.name === "parse" || inner.property.name === "safeParse");
|
|
8923
9023
|
};
|
|
8924
|
-
var isRawPayloadSource = (node) => {
|
|
9024
|
+
var isRawPayloadSource = (node, isKnownLocalText) => {
|
|
8925
9025
|
let current = unwrap4(node);
|
|
8926
9026
|
if (current === null) return false;
|
|
8927
9027
|
if (current.type === AST_NODE_TYPES45.AwaitExpression) {
|
|
@@ -8945,20 +9045,26 @@ var isRawPayloadSource = (node) => {
|
|
|
8945
9045
|
return !current.arguments.some(isSchemaParseReference) && isRawPayloadSource(callee.object);
|
|
8946
9046
|
}
|
|
8947
9047
|
const object = unwrap4(callee.object);
|
|
8948
|
-
return property.name === "parse" && object !== null && object.type === AST_NODE_TYPES45.Identifier && object.name === "JSON" && !isLocalFileRead(current.arguments[0]);
|
|
9048
|
+
return property.name === "parse" && object !== null && object.type === AST_NODE_TYPES45.Identifier && object.name === "JSON" && !isLocalFileRead(current.arguments[0]) && isKnownLocalText?.(current.arguments[0]) !== true;
|
|
8949
9049
|
};
|
|
8950
9050
|
var FILE_READ_RE = /^(readFile|readFileSync|readJson|readJsonSync|readJSON)$/;
|
|
9051
|
+
var isDirectLocalFileRead = (node) => {
|
|
9052
|
+
let current = unwrap4(node);
|
|
9053
|
+
if (current?.type === AST_NODE_TYPES45.AwaitExpression) {
|
|
9054
|
+
current = unwrap4(current.argument);
|
|
9055
|
+
}
|
|
9056
|
+
if (current?.type !== AST_NODE_TYPES45.CallExpression) return false;
|
|
9057
|
+
const callee = unwrap4(current.callee);
|
|
9058
|
+
const name = callee?.type === AST_NODE_TYPES45.Identifier ? callee.name : callee?.type === AST_NODE_TYPES45.MemberExpression && !callee.computed && callee.property.type === AST_NODE_TYPES45.Identifier ? callee.property.name : null;
|
|
9059
|
+
return name !== null && FILE_READ_RE.test(name);
|
|
9060
|
+
};
|
|
8951
9061
|
var isLocalFileRead = (node) => {
|
|
8952
9062
|
let found = false;
|
|
8953
9063
|
const visit = (current) => {
|
|
8954
9064
|
if (found || current === null || current === void 0) return;
|
|
8955
|
-
if (current
|
|
8956
|
-
|
|
8957
|
-
|
|
8958
|
-
if (name !== null && FILE_READ_RE.test(name)) {
|
|
8959
|
-
found = true;
|
|
8960
|
-
return;
|
|
8961
|
-
}
|
|
9065
|
+
if (isDirectLocalFileRead(current)) {
|
|
9066
|
+
found = true;
|
|
9067
|
+
return;
|
|
8962
9068
|
}
|
|
8963
9069
|
for (const key of Object.keys(current)) {
|
|
8964
9070
|
if (key === "parent") continue;
|
|
@@ -9020,6 +9126,87 @@ var isValidationRead = (node) => {
|
|
|
9020
9126
|
}
|
|
9021
9127
|
return callee.type === AST_NODE_TYPES45.Identifier && GUARD_NAME_RE.test(callee.name);
|
|
9022
9128
|
};
|
|
9129
|
+
var PRIMITIVE_TYPEOF_RESULTS = /* @__PURE__ */ new Set([
|
|
9130
|
+
"bigint",
|
|
9131
|
+
"boolean",
|
|
9132
|
+
"number",
|
|
9133
|
+
"string",
|
|
9134
|
+
"symbol",
|
|
9135
|
+
"undefined"
|
|
9136
|
+
]);
|
|
9137
|
+
var bindingValidationPolarity = (test, bindingName) => {
|
|
9138
|
+
if (test.type === AST_NODE_TYPES45.UnaryExpression && test.operator === "!") {
|
|
9139
|
+
const inner = bindingValidationPolarity(test.argument, bindingName);
|
|
9140
|
+
return inner === "valid-when-true" ? "valid-when-false" : inner === "valid-when-false" ? "valid-when-true" : null;
|
|
9141
|
+
}
|
|
9142
|
+
if (test.type === AST_NODE_TYPES45.BinaryExpression) {
|
|
9143
|
+
const typeofName = (node) => node.type === AST_NODE_TYPES45.UnaryExpression && node.operator === "typeof" && node.argument.type === AST_NODE_TYPES45.Identifier ? node.argument.name : null;
|
|
9144
|
+
const literalType = (node) => node.type === AST_NODE_TYPES45.Literal && typeof node.value === "string" && PRIMITIVE_TYPEOF_RESULTS.has(node.value) ? node.value : null;
|
|
9145
|
+
const matches = typeofName(test.left) === bindingName && literalType(test.right) !== null || typeofName(test.right) === bindingName && literalType(test.left) !== null;
|
|
9146
|
+
if (!matches) return null;
|
|
9147
|
+
if (test.operator === "===" || test.operator === "==") {
|
|
9148
|
+
return "valid-when-true";
|
|
9149
|
+
}
|
|
9150
|
+
return test.operator === "!==" || test.operator === "!=" ? "valid-when-false" : null;
|
|
9151
|
+
}
|
|
9152
|
+
return test.type === AST_NODE_TYPES45.CallExpression && test.arguments.length === 1 && test.arguments[0]?.type === AST_NODE_TYPES45.Identifier && test.arguments[0].name === bindingName && test.callee.type === AST_NODE_TYPES45.MemberExpression && !test.callee.computed && test.callee.object.type === AST_NODE_TYPES45.Identifier && test.callee.object.name === "Array" && test.callee.property.type === AST_NODE_TYPES45.Identifier && test.callee.property.name === "isArray" ? "valid-when-true" : null;
|
|
9153
|
+
};
|
|
9154
|
+
var nodeWithin2 = (node, container) => node.range[0] >= container.range[0] && node.range[1] <= container.range[1];
|
|
9155
|
+
var isFullyValidatedExtractedBinding = (member, source, context) => {
|
|
9156
|
+
const isValidationReference = (identifier) => {
|
|
9157
|
+
for (let current = identifier.parent; current !== void 0 && current !== null; current = current.parent) {
|
|
9158
|
+
if ((current.type === AST_NODE_TYPES45.BinaryExpression || current.type === AST_NODE_TYPES45.CallExpression || current.type === AST_NODE_TYPES45.UnaryExpression) && bindingValidationPolarity(current, identifier.name) !== null) {
|
|
9159
|
+
return true;
|
|
9160
|
+
}
|
|
9161
|
+
if (current.type !== AST_NODE_TYPES45.UnaryExpression && current.type !== AST_NODE_TYPES45.MemberExpression && current.type !== AST_NODE_TYPES45.CallExpression) {
|
|
9162
|
+
return false;
|
|
9163
|
+
}
|
|
9164
|
+
}
|
|
9165
|
+
return false;
|
|
9166
|
+
};
|
|
9167
|
+
const isGuardedUse = (identifier) => {
|
|
9168
|
+
for (let current = identifier.parent; current !== void 0 && current !== null; current = current.parent) {
|
|
9169
|
+
if (current.type === AST_NODE_TYPES45.ConditionalExpression) {
|
|
9170
|
+
const polarity = bindingValidationPolarity(current.test, identifier.name);
|
|
9171
|
+
if (polarity === "valid-when-true" && nodeWithin2(identifier, current.consequent)) {
|
|
9172
|
+
return true;
|
|
9173
|
+
}
|
|
9174
|
+
if (polarity === "valid-when-false" && nodeWithin2(identifier, current.alternate)) {
|
|
9175
|
+
return true;
|
|
9176
|
+
}
|
|
9177
|
+
}
|
|
9178
|
+
if (current.type === AST_NODE_TYPES45.IfStatement) {
|
|
9179
|
+
const polarity = bindingValidationPolarity(current.test, identifier.name);
|
|
9180
|
+
if (polarity === "valid-when-true" && nodeWithin2(identifier, current.consequent)) {
|
|
9181
|
+
return true;
|
|
9182
|
+
}
|
|
9183
|
+
if (polarity === "valid-when-false" && current.alternate !== null && nodeWithin2(identifier, current.alternate)) {
|
|
9184
|
+
return true;
|
|
9185
|
+
}
|
|
9186
|
+
}
|
|
9187
|
+
if (current.type === AST_NODE_TYPES45.FunctionDeclaration || current.type === AST_NODE_TYPES45.FunctionExpression || current.type === AST_NODE_TYPES45.ArrowFunctionExpression) {
|
|
9188
|
+
return false;
|
|
9189
|
+
}
|
|
9190
|
+
}
|
|
9191
|
+
return false;
|
|
9192
|
+
};
|
|
9193
|
+
const declarator = member.parent;
|
|
9194
|
+
if (declarator.type !== AST_NODE_TYPES45.VariableDeclarator || declarator.init !== member || declarator.id.type !== AST_NODE_TYPES45.Identifier || declarator.parent.type !== AST_NODE_TYPES45.VariableDeclaration || declarator.parent.kind !== "const") {
|
|
9195
|
+
return false;
|
|
9196
|
+
}
|
|
9197
|
+
const extracted = context.sourceCode.getDeclaredVariables(declarator)[0];
|
|
9198
|
+
if (extracted === void 0 || extracted.scope !== source.scope) return false;
|
|
9199
|
+
let hasValueUse = false;
|
|
9200
|
+
for (const reference of extracted.references) {
|
|
9201
|
+
const identifier = reference.identifier;
|
|
9202
|
+
if (identifier.type !== AST_NODE_TYPES45.Identifier) return false;
|
|
9203
|
+
if (nodeWithin2(identifier, declarator)) continue;
|
|
9204
|
+
if (isValidationReference(identifier)) continue;
|
|
9205
|
+
hasValueUse = true;
|
|
9206
|
+
if (!isGuardedUse(identifier)) return false;
|
|
9207
|
+
}
|
|
9208
|
+
return hasValueUse;
|
|
9209
|
+
};
|
|
9023
9210
|
var isGuardTestPosition = (node) => {
|
|
9024
9211
|
let current = node;
|
|
9025
9212
|
let parent = current.parent;
|
|
@@ -9043,13 +9230,13 @@ var isGuardTestPosition = (node) => {
|
|
|
9043
9230
|
}
|
|
9044
9231
|
return false;
|
|
9045
9232
|
};
|
|
9046
|
-
var
|
|
9233
|
+
var unvalidatedVariableRef = (node, scope, tracked) => {
|
|
9047
9234
|
const unwrapped = unwrap4(node);
|
|
9048
9235
|
if (unwrapped === null || unwrapped.type !== AST_NODE_TYPES45.Identifier) {
|
|
9049
|
-
return
|
|
9236
|
+
return null;
|
|
9050
9237
|
}
|
|
9051
9238
|
const variable = findVariable2(scope, unwrapped.name);
|
|
9052
|
-
return variable !== null && tracked.has(variable);
|
|
9239
|
+
return variable !== null && tracked.has(variable) ? variable : null;
|
|
9053
9240
|
};
|
|
9054
9241
|
var prefer_schema_for_api_payload_default = createRule({
|
|
9055
9242
|
name: "prefer-schema-for-api-payload",
|
|
@@ -9069,6 +9256,56 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9069
9256
|
return {};
|
|
9070
9257
|
}
|
|
9071
9258
|
const unvalidatedVariables = /* @__PURE__ */ new Set();
|
|
9259
|
+
const aliasGroups = /* @__PURE__ */ new Map();
|
|
9260
|
+
const localFileTextVariables = /* @__PURE__ */ new Set();
|
|
9261
|
+
const localFileTextRef = (node, scope) => {
|
|
9262
|
+
const unwrapped = unwrap4(node);
|
|
9263
|
+
if (unwrapped?.type !== AST_NODE_TYPES45.Identifier) return null;
|
|
9264
|
+
const variable = findVariable2(scope, unwrapped.name);
|
|
9265
|
+
return variable !== null && localFileTextVariables.has(variable) ? variable : null;
|
|
9266
|
+
};
|
|
9267
|
+
const updateLocalFileText = (target, value, scope) => {
|
|
9268
|
+
const source = localFileTextRef(value, scope);
|
|
9269
|
+
if (isDirectLocalFileRead(value) || source !== null && source.scope === target.scope) {
|
|
9270
|
+
localFileTextVariables.add(target);
|
|
9271
|
+
} else {
|
|
9272
|
+
localFileTextVariables.delete(target);
|
|
9273
|
+
}
|
|
9274
|
+
};
|
|
9275
|
+
const clearBinding = (variable) => {
|
|
9276
|
+
unvalidatedVariables.delete(variable);
|
|
9277
|
+
const group = aliasGroups.get(variable);
|
|
9278
|
+
aliasGroups.delete(variable);
|
|
9279
|
+
group?.delete(variable);
|
|
9280
|
+
};
|
|
9281
|
+
const clearAliasGroup = (variable) => {
|
|
9282
|
+
const group = aliasGroups.get(variable);
|
|
9283
|
+
if (group === void 0) {
|
|
9284
|
+
unvalidatedVariables.delete(variable);
|
|
9285
|
+
return;
|
|
9286
|
+
}
|
|
9287
|
+
for (const alias of group) {
|
|
9288
|
+
unvalidatedVariables.delete(alias);
|
|
9289
|
+
aliasGroups.delete(alias);
|
|
9290
|
+
}
|
|
9291
|
+
group.clear();
|
|
9292
|
+
};
|
|
9293
|
+
const trackRawBinding = (variable) => {
|
|
9294
|
+
clearBinding(variable);
|
|
9295
|
+
const group = /* @__PURE__ */ new Set([variable]);
|
|
9296
|
+
unvalidatedVariables.add(variable);
|
|
9297
|
+
aliasGroups.set(variable, group);
|
|
9298
|
+
};
|
|
9299
|
+
const trackAlias = (target, source) => {
|
|
9300
|
+
if (target === source) return;
|
|
9301
|
+
const group = aliasGroups.get(source) ?? /* @__PURE__ */ new Set([source]);
|
|
9302
|
+
if (aliasGroups.get(target) === group) return;
|
|
9303
|
+
clearBinding(target);
|
|
9304
|
+
unvalidatedVariables.add(target);
|
|
9305
|
+
group.add(target);
|
|
9306
|
+
aliasGroups.set(source, group);
|
|
9307
|
+
aliasGroups.set(target, group);
|
|
9308
|
+
};
|
|
9072
9309
|
const isFullyNarrowedPattern = (declarator) => {
|
|
9073
9310
|
const declared = context.sourceCode.getDeclaredVariables(declarator);
|
|
9074
9311
|
return declared.length > 0 && declared.every(
|
|
@@ -9077,29 +9314,40 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9077
9314
|
)
|
|
9078
9315
|
);
|
|
9079
9316
|
};
|
|
9080
|
-
const trackInitializer = (declarator) => {
|
|
9081
|
-
if (!isRawPayloadSource(declarator.init)) return;
|
|
9317
|
+
const trackInitializer = (declarator, scope) => {
|
|
9082
9318
|
const declaredVars = context.sourceCode.getDeclaredVariables(declarator);
|
|
9083
9319
|
const variable = declaredVars[0];
|
|
9084
|
-
if (variable
|
|
9085
|
-
|
|
9320
|
+
if (variable === void 0) return;
|
|
9321
|
+
const localText = (candidate) => localFileTextRef(candidate, scope) !== null;
|
|
9322
|
+
if (isRawPayloadSource(declarator.init, localText)) {
|
|
9323
|
+
trackRawBinding(variable);
|
|
9324
|
+
return;
|
|
9086
9325
|
}
|
|
9326
|
+
const source = unvalidatedVariableRef(declarator.init, scope, unvalidatedVariables);
|
|
9327
|
+
if (source !== null) trackAlias(variable, source);
|
|
9087
9328
|
};
|
|
9088
9329
|
return {
|
|
9089
9330
|
VariableDeclarator(node) {
|
|
9090
9331
|
const scope = context.sourceCode.getScope(node);
|
|
9091
9332
|
if (node.id.type === AST_NODE_TYPES45.Identifier) {
|
|
9092
|
-
|
|
9333
|
+
const variable = context.sourceCode.getDeclaredVariables(node)[0];
|
|
9334
|
+
if (variable !== void 0) {
|
|
9335
|
+
updateLocalFileText(variable, node.init, scope);
|
|
9336
|
+
}
|
|
9337
|
+
trackInitializer(node, scope);
|
|
9093
9338
|
return;
|
|
9094
9339
|
}
|
|
9095
9340
|
if (node.id.type === AST_NODE_TYPES45.ObjectPattern || node.id.type === AST_NODE_TYPES45.ArrayPattern) {
|
|
9096
|
-
if (isRawPayloadSource(
|
|
9341
|
+
if (isRawPayloadSource(
|
|
9342
|
+
node.init,
|
|
9343
|
+
(candidate) => localFileTextRef(candidate, scope) !== null
|
|
9344
|
+
)) {
|
|
9097
9345
|
if (!isFullyNarrowedPattern(node)) {
|
|
9098
9346
|
context.report({ node: node.id, messageId: "unparsedJsonAccess" });
|
|
9099
9347
|
}
|
|
9100
9348
|
return;
|
|
9101
9349
|
}
|
|
9102
|
-
if (
|
|
9350
|
+
if (unvalidatedVariableRef(node.init, scope, unvalidatedVariables) !== null) {
|
|
9103
9351
|
context.report({ node: node.id, messageId: "unparsedJsonAccess" });
|
|
9104
9352
|
}
|
|
9105
9353
|
}
|
|
@@ -9109,22 +9357,29 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9109
9357
|
if (node.left.type === AST_NODE_TYPES45.Identifier) {
|
|
9110
9358
|
const variable = findVariable2(scope, node.left.name);
|
|
9111
9359
|
if (variable === null) return;
|
|
9112
|
-
|
|
9113
|
-
|
|
9360
|
+
const isLocalText = (candidate) => localFileTextRef(candidate, scope) !== null;
|
|
9361
|
+
updateLocalFileText(variable, node.right, scope);
|
|
9362
|
+
if (isRawPayloadSource(node.right, isLocalText)) {
|
|
9363
|
+
trackRawBinding(variable);
|
|
9114
9364
|
} else {
|
|
9115
|
-
unvalidatedVariables
|
|
9365
|
+
const source = unvalidatedVariableRef(node.right, scope, unvalidatedVariables);
|
|
9366
|
+
if (source === null) clearBinding(variable);
|
|
9367
|
+
else trackAlias(variable, source);
|
|
9116
9368
|
}
|
|
9117
9369
|
return;
|
|
9118
9370
|
}
|
|
9119
9371
|
if (node.left.type === AST_NODE_TYPES45.ObjectPattern || node.left.type === AST_NODE_TYPES45.ArrayPattern) {
|
|
9120
|
-
if (isRawPayloadSource(
|
|
9372
|
+
if (isRawPayloadSource(
|
|
9373
|
+
node.right,
|
|
9374
|
+
(candidate) => localFileTextRef(candidate, scope) !== null
|
|
9375
|
+
)) {
|
|
9121
9376
|
context.report({
|
|
9122
9377
|
node: node.left,
|
|
9123
9378
|
messageId: "unparsedJsonAccess"
|
|
9124
9379
|
});
|
|
9125
9380
|
return;
|
|
9126
9381
|
}
|
|
9127
|
-
if (
|
|
9382
|
+
if (unvalidatedVariableRef(node.right, scope, unvalidatedVariables) !== null) {
|
|
9128
9383
|
context.report({
|
|
9129
9384
|
node: node.left,
|
|
9130
9385
|
messageId: "unparsedJsonAccess"
|
|
@@ -9145,7 +9400,7 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9145
9400
|
continue;
|
|
9146
9401
|
}
|
|
9147
9402
|
const variable = findVariable2(scope, unwrapped.name);
|
|
9148
|
-
if (variable !== null)
|
|
9403
|
+
if (variable !== null) clearAliasGroup(variable);
|
|
9149
9404
|
}
|
|
9150
9405
|
},
|
|
9151
9406
|
MemberExpression(node) {
|
|
@@ -9153,7 +9408,10 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9153
9408
|
if (isValidationRead(node)) return;
|
|
9154
9409
|
const scope = context.sourceCode.getScope(node);
|
|
9155
9410
|
const obj = unwrap4(node.object);
|
|
9156
|
-
if (isRawPayloadSource(
|
|
9411
|
+
if (isRawPayloadSource(
|
|
9412
|
+
obj,
|
|
9413
|
+
(candidate) => localFileTextRef(candidate, scope) !== null
|
|
9414
|
+
)) {
|
|
9157
9415
|
const parent = node.parent;
|
|
9158
9416
|
if (parent.type === AST_NODE_TYPES45.CallExpression && parent.callee === node && node.property.type === AST_NODE_TYPES45.Identifier && (node.property.name === "parse" || node.property.name === "safeParse" || PROMISE_CHAIN_METHODS.has(node.property.name))) {
|
|
9159
9417
|
return;
|
|
@@ -9161,12 +9419,13 @@ var prefer_schema_for_api_payload_default = createRule({
|
|
|
9161
9419
|
context.report({ node, messageId: "unparsedJsonAccess" });
|
|
9162
9420
|
return;
|
|
9163
9421
|
}
|
|
9164
|
-
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
unvalidatedVariables.delete(variable);
|
|
9422
|
+
const variable = obj?.type === AST_NODE_TYPES45.Identifier ? unvalidatedVariableRef(obj, scope, unvalidatedVariables) : null;
|
|
9423
|
+
if (variable !== null) {
|
|
9424
|
+
if (isFullyValidatedExtractedBinding(node, variable, context)) {
|
|
9425
|
+
return;
|
|
9169
9426
|
}
|
|
9427
|
+
context.report({ node, messageId: "unparsedJsonAccess" });
|
|
9428
|
+
clearAliasGroup(variable);
|
|
9170
9429
|
}
|
|
9171
9430
|
}
|
|
9172
9431
|
};
|
|
@@ -10933,8 +11192,8 @@ function initProvablyLacksSignal(init) {
|
|
|
10933
11192
|
}
|
|
10934
11193
|
return true;
|
|
10935
11194
|
}
|
|
10936
|
-
function
|
|
10937
|
-
return node.type === AST_NODE_TYPES52.Literal && typeof node.value === "string" || node.type === AST_NODE_TYPES52.TemplateLiteral;
|
|
11195
|
+
function isInlineUrl(node, resolvesToGlobal) {
|
|
11196
|
+
return node.type === AST_NODE_TYPES52.Literal && typeof node.value === "string" || node.type === AST_NODE_TYPES52.TemplateLiteral || node.type === AST_NODE_TYPES52.NewExpression && node.callee.type === AST_NODE_TYPES52.Identifier && node.callee.name === "URL" && resolvesToGlobal(node.callee);
|
|
10938
11197
|
}
|
|
10939
11198
|
var require_fetch_timeout_default = createRule({
|
|
10940
11199
|
name: "require-fetch-timeout",
|
|
@@ -10986,7 +11245,7 @@ var require_fetch_timeout_default = createRule({
|
|
|
10986
11245
|
return;
|
|
10987
11246
|
}
|
|
10988
11247
|
const [first, init] = node.arguments;
|
|
10989
|
-
if (node.arguments.length === 1 && first !== void 0 && !
|
|
11248
|
+
if (node.arguments.length === 1 && first !== void 0 && !isInlineUrl(first, resolvesToGlobal)) {
|
|
10990
11249
|
return;
|
|
10991
11250
|
}
|
|
10992
11251
|
if (init === void 0 || initProvablyLacksSignal(init)) {
|
|
@@ -11003,7 +11262,7 @@ var CONFIGISH_TYPE_RE = /(?:Options|Opts|Config|Configuration|Settings|Params|Pr
|
|
|
11003
11262
|
var CONFIGISH_NAME_RE = /^(?:options|opts|config|configuration|settings|params|props|args|env|environment|callbacks|flags|logger|log|clock)$/i;
|
|
11004
11263
|
var HTTP_TRANSPORT_TYPE_RE = /^(?:KyInstance|AxiosInstance|Session)$/;
|
|
11005
11264
|
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)$/;
|
|
11006
|
-
var VALUE_TYPE_RE = /^(?:ArrayBuffer|Blob|Buffer|Date|RegExp|URL|URLSearchParams)$/;
|
|
11265
|
+
var VALUE_TYPE_RE = /^(?:ArrayBuffer|Blob|Buffer|Date|NodePath|RegExp|URL|URLSearchParams)$/;
|
|
11007
11266
|
var TRANSPORT_WRAPPER_NAME_RE = /(?:Client$|^Http[A-Z])/;
|
|
11008
11267
|
var ERROR_VALUE_NAME_RE = /Error$/;
|
|
11009
11268
|
var FLUENT_BUILDER_NAME_RE = /Builder$/;
|
|
@@ -11467,7 +11726,7 @@ var require_interface_for_injected_service_default = createRule({
|
|
|
11467
11726
|
if (node.abstract === true) return;
|
|
11468
11727
|
if (node.decorators.length > 0) return;
|
|
11469
11728
|
const ctor = node.body.body.find(
|
|
11470
|
-
(member) => member.type === AST_NODE_TYPES53.MethodDefinition && member.kind === "constructor"
|
|
11729
|
+
(member) => member.type === AST_NODE_TYPES53.MethodDefinition && member.kind === "constructor" && member.value.body !== null && member.value.body !== void 0
|
|
11471
11730
|
);
|
|
11472
11731
|
if (ctor === void 0) return;
|
|
11473
11732
|
const constructorFacts = readConstructor(
|
|
@@ -12346,7 +12605,7 @@ var rules = {
|
|
|
12346
12605
|
};
|
|
12347
12606
|
var meta = {
|
|
12348
12607
|
name: "@sarj/eslint-plugin",
|
|
12349
|
-
version: "11.0
|
|
12608
|
+
version: "11.1.0"
|
|
12350
12609
|
};
|
|
12351
12610
|
var applicationOnlyRules = [
|
|
12352
12611
|
"no-restricted-library-load",
|