oxlint-plugin-react-doctor 0.7.7-dev.afed801 → 0.7.7-dev.bdd1321
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.js +3 -329
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -18333,26 +18333,6 @@ const MEMBERSHIP_COMPARISON_OPERATORS = new Set([
|
|
|
18333
18333
|
]);
|
|
18334
18334
|
const isNegativeOneLiteral = (expression) => Boolean(expression) && isNodeOfType(expression, "UnaryExpression") && expression.operator === "-" && isNodeOfType(expression.argument, "Literal") && expression.argument.value === 1;
|
|
18335
18335
|
const isZeroLiteral = (expression) => Boolean(expression) && isNodeOfType(expression, "Literal") && expression.value === 0;
|
|
18336
|
-
const isToIntegerOrInfinityZero = (value) => Number.isNaN(value) || Math.trunc(value) === 0;
|
|
18337
|
-
const isZeroFromIndex = (expression) => {
|
|
18338
|
-
if (!expression) return false;
|
|
18339
|
-
const strippedExpression = stripParenExpression(expression);
|
|
18340
|
-
if (isNodeOfType(strippedExpression, "Literal")) {
|
|
18341
|
-
if (typeof strippedExpression.value === "number") return isToIntegerOrInfinityZero(strippedExpression.value);
|
|
18342
|
-
if (typeof strippedExpression.value === "string") return isToIntegerOrInfinityZero(Number(strippedExpression.value));
|
|
18343
|
-
return strippedExpression.value === null || strippedExpression.value === false;
|
|
18344
|
-
}
|
|
18345
|
-
if (isNodeOfType(strippedExpression, "UnaryExpression") && strippedExpression.operator === "void") return true;
|
|
18346
|
-
if (isNodeOfType(strippedExpression, "UnaryExpression") && (strippedExpression.operator === "-" || strippedExpression.operator === "+") && isNodeOfType(strippedExpression.argument, "Literal") && typeof strippedExpression.argument.value === "number") return isToIntegerOrInfinityZero(strippedExpression.operator === "-" ? -strippedExpression.argument.value : strippedExpression.argument.value);
|
|
18347
|
-
if (isNodeOfType(strippedExpression, "Identifier")) return (strippedExpression.name === "undefined" || strippedExpression.name === "NaN") && findVariableInitializer(strippedExpression, strippedExpression.name) === null;
|
|
18348
|
-
return isNodeOfType(strippedExpression, "MemberExpression") && !strippedExpression.computed && isNodeOfType(strippedExpression.object, "Identifier") && strippedExpression.object.name === "Number" && isNodeOfType(strippedExpression.property, "Identifier") && strippedExpression.property.name === "NaN" && findVariableInitializer(strippedExpression.object, strippedExpression.object.name) === null;
|
|
18349
|
-
};
|
|
18350
|
-
const hasSemanticsPreservingIncludesArguments = (node) => {
|
|
18351
|
-
if (node.arguments.length === 1) return !isNodeOfType(node.arguments[0], "SpreadElement");
|
|
18352
|
-
if (node.arguments.length !== 2) return false;
|
|
18353
|
-
if (isNodeOfType(node.arguments[0], "SpreadElement") || isNodeOfType(node.arguments[1], "SpreadElement")) return false;
|
|
18354
|
-
return isZeroFromIndex(node.arguments[1]);
|
|
18355
|
-
};
|
|
18356
18336
|
const PARENT_WRAPPER_TYPES = new Set([
|
|
18357
18337
|
"ParenthesizedExpression",
|
|
18358
18338
|
"ChainExpression",
|
|
@@ -18373,306 +18353,6 @@ const isIndexOfResultUsedAsMembershipTest = (node) => {
|
|
|
18373
18353
|
if (isNegativeOneLiteral(otherOperand)) return true;
|
|
18374
18354
|
return isZeroLiteral(otherOperand) && (parent.operator === ">=" || parent.operator === "<");
|
|
18375
18355
|
};
|
|
18376
|
-
const getTypeAnnotation = (node) => {
|
|
18377
|
-
if (!node || !("typeAnnotation" in node)) return null;
|
|
18378
|
-
const annotation = node.typeAnnotation;
|
|
18379
|
-
if (!annotation || !isNodeOfType(annotation, "TSTypeAnnotation")) return null;
|
|
18380
|
-
return annotation.typeAnnotation;
|
|
18381
|
-
};
|
|
18382
|
-
const getDeclaredPropertyType = (members, propertyName) => {
|
|
18383
|
-
for (const member of members) if (isNodeOfType(member, "TSPropertySignature") && isNodeOfType(member.key, "Identifier") && member.key.name === propertyName) return getTypeAnnotation(member);
|
|
18384
|
-
return null;
|
|
18385
|
-
};
|
|
18386
|
-
const getArrayElementType = (typeNode) => {
|
|
18387
|
-
if (!typeNode) return null;
|
|
18388
|
-
if (isNodeOfType(typeNode, "TSArrayType")) return typeNode.elementType;
|
|
18389
|
-
if (isNodeOfType(typeNode, "TSTypeReference") && isNodeOfType(typeNode.typeName, "Identifier") && (typeNode.typeName.name === "Array" || typeNode.typeName.name === "ReadonlyArray")) return typeNode.typeArguments?.params?.[0] ?? null;
|
|
18390
|
-
if (isNodeOfType(typeNode, "TSUnionType")) {
|
|
18391
|
-
const arrayElementTypes = typeNode.types.map(getArrayElementType).filter(Boolean);
|
|
18392
|
-
return arrayElementTypes.length === 1 ? arrayElementTypes[0] : null;
|
|
18393
|
-
}
|
|
18394
|
-
return null;
|
|
18395
|
-
};
|
|
18396
|
-
const getDestructuredDeclaredType = (identifier) => {
|
|
18397
|
-
const binding = findVariableInitializer(identifier, identifier.name);
|
|
18398
|
-
if (!binding) return null;
|
|
18399
|
-
const property = binding.bindingIdentifier.parent;
|
|
18400
|
-
const objectPattern = property?.parent;
|
|
18401
|
-
if (!isNodeOfType(property, "Property") || !isNodeOfType(property.key, "Identifier") || !isNodeOfType(objectPattern, "ObjectPattern")) return null;
|
|
18402
|
-
const propsType = getTypeAnnotation(objectPattern);
|
|
18403
|
-
if (!propsType) return null;
|
|
18404
|
-
if (isNodeOfType(propsType, "TSTypeLiteral")) return getDeclaredPropertyType(propsType.members ?? [], property.key.name);
|
|
18405
|
-
if (!isNodeOfType(propsType, "TSTypeReference") || !isNodeOfType(propsType.typeName, "Identifier")) return null;
|
|
18406
|
-
const program = findProgramRoot(identifier);
|
|
18407
|
-
if (!program) return null;
|
|
18408
|
-
for (const statement of program.body) {
|
|
18409
|
-
const declaration = isNodeOfType(statement, "ExportNamedDeclaration") ? statement.declaration : statement;
|
|
18410
|
-
if (isNodeOfType(declaration, "TSInterfaceDeclaration") && isNodeOfType(declaration.id, "Identifier") && declaration.id.name === propsType.typeName.name) return getDeclaredPropertyType(declaration.body.body, property.key.name);
|
|
18411
|
-
if (isNodeOfType(declaration, "TSTypeAliasDeclaration") && isNodeOfType(declaration.id, "Identifier") && declaration.id.name === propsType.typeName.name && isNodeOfType(declaration.typeAnnotation, "TSTypeLiteral")) return getDeclaredPropertyType(declaration.typeAnnotation.members ?? [], property.key.name);
|
|
18412
|
-
}
|
|
18413
|
-
return null;
|
|
18414
|
-
};
|
|
18415
|
-
const getIdentifierDeclaredType = (identifier, visitedBindingIdentifiers = /* @__PURE__ */ new Set()) => {
|
|
18416
|
-
const binding = findVariableInitializer(identifier, identifier.name);
|
|
18417
|
-
if (!binding || visitedBindingIdentifiers.has(binding.bindingIdentifier)) return null;
|
|
18418
|
-
visitedBindingIdentifiers.add(binding.bindingIdentifier);
|
|
18419
|
-
const directType = getTypeAnnotation(binding.bindingIdentifier);
|
|
18420
|
-
if (directType) return directType;
|
|
18421
|
-
const initializer = binding.initializer;
|
|
18422
|
-
if (isNodeOfType(initializer, "TSAsExpression") || isNodeOfType(initializer, "TSTypeAssertion") || isNodeOfType(initializer, "TSSatisfiesExpression")) return initializer.typeAnnotation;
|
|
18423
|
-
const destructuredType = getDestructuredDeclaredType(identifier);
|
|
18424
|
-
if (destructuredType) return destructuredType;
|
|
18425
|
-
const declarator = binding.bindingIdentifier.parent;
|
|
18426
|
-
const declaration = declarator?.parent;
|
|
18427
|
-
const forOfStatement = declaration?.parent;
|
|
18428
|
-
if (isNodeOfType(declarator, "VariableDeclarator") && isNodeOfType(declaration, "VariableDeclaration") && isNodeOfType(forOfStatement, "ForOfStatement") && forOfStatement.left === declaration && isNodeOfType(forOfStatement.right, "Identifier")) return getArrayElementType(getIdentifierDeclaredType(forOfStatement.right, visitedBindingIdentifiers));
|
|
18429
|
-
return null;
|
|
18430
|
-
};
|
|
18431
|
-
const isNativeIterationIndex = (identifier) => {
|
|
18432
|
-
const binding = findVariableInitializer(identifier, identifier.name);
|
|
18433
|
-
if (!binding) return false;
|
|
18434
|
-
const callback = binding.bindingIdentifier.parent;
|
|
18435
|
-
if (!isInlineFunctionExpression(callback)) return false;
|
|
18436
|
-
const callbackCall = callback.parent;
|
|
18437
|
-
if (!isNodeOfType(callbackCall, "CallExpression") || !isIterationCallbackCall(callbackCall) || !isNodeOfType(callbackCall.callee, "MemberExpression") || !isNodeOfType(callbackCall.callee.property, "Identifier")) return false;
|
|
18438
|
-
const indexParameterPosition = callbackCall.callee.property.name === "reduce" || callbackCall.callee.property.name === "reduceRight" ? 2 : 1;
|
|
18439
|
-
return callback.params?.[indexParameterPosition] === binding.bindingIdentifier;
|
|
18440
|
-
};
|
|
18441
|
-
const hasSameIdentifierBinding = (leftIdentifier, rightIdentifier) => {
|
|
18442
|
-
if (leftIdentifier.name !== rightIdentifier.name) return false;
|
|
18443
|
-
const leftBinding = findVariableInitializer(leftIdentifier, leftIdentifier.name);
|
|
18444
|
-
const rightBinding = findVariableInitializer(rightIdentifier, rightIdentifier.name);
|
|
18445
|
-
return Boolean(leftBinding && rightBinding && leftBinding.bindingIdentifier === rightBinding.bindingIdentifier);
|
|
18446
|
-
};
|
|
18447
|
-
const NON_NAN_RELATIONAL_OPERATORS = new Set([
|
|
18448
|
-
"<",
|
|
18449
|
-
"<=",
|
|
18450
|
-
">",
|
|
18451
|
-
">="
|
|
18452
|
-
]);
|
|
18453
|
-
const testProvesIdentifierIsNotNaN = (test, identifier) => {
|
|
18454
|
-
if (!test) return false;
|
|
18455
|
-
const strippedTest = stripParenExpression(test);
|
|
18456
|
-
if (isNodeOfType(strippedTest, "LogicalExpression") && strippedTest.operator === "&&") return testProvesIdentifierIsNotNaN(strippedTest.left, identifier) || testProvesIdentifierIsNotNaN(strippedTest.right, identifier);
|
|
18457
|
-
if (!isNodeOfType(strippedTest, "BinaryExpression") || !NON_NAN_RELATIONAL_OPERATORS.has(strippedTest.operator)) return false;
|
|
18458
|
-
return isNodeOfType(strippedTest.left, "Identifier") && hasSameIdentifierBinding(strippedTest.left, identifier) || isNodeOfType(strippedTest.right, "Identifier") && hasSameIdentifierBinding(strippedTest.right, identifier);
|
|
18459
|
-
};
|
|
18460
|
-
const writeTargetContainsIdentifierBinding = (writeTarget, identifier) => {
|
|
18461
|
-
let containsBinding = false;
|
|
18462
|
-
walkAst(writeTarget, (child) => {
|
|
18463
|
-
if (isNodeOfType(child, "Identifier") && hasSameIdentifierBinding(child, identifier)) {
|
|
18464
|
-
containsBinding = true;
|
|
18465
|
-
return false;
|
|
18466
|
-
}
|
|
18467
|
-
});
|
|
18468
|
-
return containsBinding;
|
|
18469
|
-
};
|
|
18470
|
-
const hasWriteBeforeQuery = (body, identifier) => {
|
|
18471
|
-
const queryStart = getRangeStart(identifier);
|
|
18472
|
-
if (queryStart === null) return true;
|
|
18473
|
-
let hasEarlierWrite = false;
|
|
18474
|
-
walkAst(body, (child) => {
|
|
18475
|
-
if (hasEarlierWrite) return false;
|
|
18476
|
-
const childStart = getRangeStart(child);
|
|
18477
|
-
if (childStart !== null && childStart >= queryStart) return false;
|
|
18478
|
-
if (child !== body && isFunctionLike$2(child)) return false;
|
|
18479
|
-
const writeTarget = isNodeOfType(child, "AssignmentExpression") ? child.left : isNodeOfType(child, "UpdateExpression") ? child.argument : isNodeOfType(child, "ForInStatement") || isNodeOfType(child, "ForOfStatement") ? child.left : null;
|
|
18480
|
-
if (writeTarget && writeTargetContainsIdentifierBinding(writeTarget, identifier)) {
|
|
18481
|
-
hasEarlierWrite = true;
|
|
18482
|
-
return false;
|
|
18483
|
-
}
|
|
18484
|
-
});
|
|
18485
|
-
return hasEarlierWrite;
|
|
18486
|
-
};
|
|
18487
|
-
const isProtectedByRelationalLoopGuard = (identifier) => {
|
|
18488
|
-
let descendant = identifier;
|
|
18489
|
-
let ancestor = identifier.parent;
|
|
18490
|
-
while (ancestor) {
|
|
18491
|
-
if (isFunctionLike$2(ancestor)) return false;
|
|
18492
|
-
if ((isNodeOfType(ancestor, "ForStatement") || isNodeOfType(ancestor, "WhileStatement")) && ancestor.body === descendant && testProvesIdentifierIsNotNaN(ancestor.test, identifier)) return !hasWriteBeforeQuery(ancestor.body, identifier);
|
|
18493
|
-
descendant = ancestor;
|
|
18494
|
-
ancestor = ancestor.parent;
|
|
18495
|
-
}
|
|
18496
|
-
return false;
|
|
18497
|
-
};
|
|
18498
|
-
const isKnownSafeIndexOfQuery = (query) => {
|
|
18499
|
-
if (!query) return false;
|
|
18500
|
-
const strippedQuery = stripParenExpression(query);
|
|
18501
|
-
if (isNodeOfType(strippedQuery, "Literal")) return typeof strippedQuery.value !== "number" || Number.isFinite(strippedQuery.value);
|
|
18502
|
-
if (!isNodeOfType(strippedQuery, "Identifier")) return false;
|
|
18503
|
-
if (isNativeIterationIndex(strippedQuery)) return true;
|
|
18504
|
-
return isProtectedByRelationalLoopGuard(strippedQuery);
|
|
18505
|
-
};
|
|
18506
|
-
const findSameFileTypeAlias = (reference, typeName) => {
|
|
18507
|
-
const program = findProgramRoot(reference);
|
|
18508
|
-
if (!program) return null;
|
|
18509
|
-
for (const statement of program.body) {
|
|
18510
|
-
const declaration = isNodeOfType(statement, "ExportNamedDeclaration") ? statement.declaration : statement;
|
|
18511
|
-
if (declaration && isNodeOfType(declaration, "TSTypeAliasDeclaration") && isNodeOfType(declaration.id, "Identifier") && declaration.id.name === typeName) return declaration;
|
|
18512
|
-
}
|
|
18513
|
-
return null;
|
|
18514
|
-
};
|
|
18515
|
-
const hasDeclaredMembershipMethod = (members, methodName) => members.some((member) => (isNodeOfType(member, "TSMethodSignature") || isNodeOfType(member, "TSPropertySignature")) && isNodeOfType(member.key, "Identifier") && member.key.name === methodName);
|
|
18516
|
-
const isKnownUserlandMembershipReceiver = (receiver, methodName) => {
|
|
18517
|
-
if (!isNodeOfType(receiver, "Identifier")) return false;
|
|
18518
|
-
const declaredType = getIdentifierDeclaredType(receiver);
|
|
18519
|
-
if (!declaredType) return false;
|
|
18520
|
-
if (isNodeOfType(declaredType, "TSTypeLiteral")) return hasDeclaredMembershipMethod(declaredType.members ?? [], methodName);
|
|
18521
|
-
if (!isNodeOfType(declaredType, "TSTypeReference") || !isNodeOfType(declaredType.typeName, "Identifier")) return false;
|
|
18522
|
-
const typeAlias = findSameFileTypeAlias(receiver, declaredType.typeName.name);
|
|
18523
|
-
if (typeAlias && isNodeOfType(typeAlias.typeAnnotation, "TSTypeLiteral")) return hasDeclaredMembershipMethod(typeAlias.typeAnnotation.members ?? [], methodName);
|
|
18524
|
-
const program = findProgramRoot(receiver);
|
|
18525
|
-
if (!program) return false;
|
|
18526
|
-
for (const statement of program.body) {
|
|
18527
|
-
const declaration = isNodeOfType(statement, "ExportNamedDeclaration") ? statement.declaration : statement;
|
|
18528
|
-
if (declaration && isNodeOfType(declaration, "TSInterfaceDeclaration") && isNodeOfType(declaration.id, "Identifier") && declaration.id.name === declaredType.typeName.name) return hasDeclaredMembershipMethod(declaration.body.body, methodName);
|
|
18529
|
-
}
|
|
18530
|
-
return false;
|
|
18531
|
-
};
|
|
18532
|
-
const findTypeParameter = (reference, typeName) => {
|
|
18533
|
-
let ancestor = reference.parent;
|
|
18534
|
-
while (ancestor) {
|
|
18535
|
-
if (isFunctionLike$2(ancestor) || isNodeOfType(ancestor, "ClassDeclaration") || isNodeOfType(ancestor, "ClassExpression")) {
|
|
18536
|
-
const matchingTypeParameter = ancestor.typeParameters?.params?.find((typeParameter) => isNodeOfType(typeParameter, "TSTypeParameter") && isNodeOfType(typeParameter.name, "Identifier") && typeParameter.name.name === typeName);
|
|
18537
|
-
if (matchingTypeParameter && isNodeOfType(matchingTypeParameter, "TSTypeParameter")) return matchingTypeParameter;
|
|
18538
|
-
}
|
|
18539
|
-
ancestor = ancestor.parent;
|
|
18540
|
-
}
|
|
18541
|
-
return null;
|
|
18542
|
-
};
|
|
18543
|
-
const POSSIBLY_NUMERIC_TYPE_REFERENCE_NAMES = new Set(["NonNullable", "PropertyKey"]);
|
|
18544
|
-
const buildTypeAliasArguments = (typeAlias, typeReference, inheritedArguments) => {
|
|
18545
|
-
const typeArguments = new Map(inheritedArguments);
|
|
18546
|
-
for (const [index, typeParameter] of (typeAlias.typeParameters?.params ?? []).entries()) {
|
|
18547
|
-
if (!isNodeOfType(typeParameter, "TSTypeParameter")) continue;
|
|
18548
|
-
if (!isNodeOfType(typeParameter.name, "Identifier")) continue;
|
|
18549
|
-
const argument = typeReference.typeArguments?.params?.[index] ?? typeParameter.default;
|
|
18550
|
-
if (argument) typeArguments.set(typeParameter.name.name, argument);
|
|
18551
|
-
}
|
|
18552
|
-
return typeArguments;
|
|
18553
|
-
};
|
|
18554
|
-
const typeCanHaveSameValueZeroDifference = (typeNode, reference, activeTypeNodes, typeArguments = /* @__PURE__ */ new Map()) => {
|
|
18555
|
-
if (!typeNode) return false;
|
|
18556
|
-
if (isNodeOfType(typeNode, "TSNumberKeyword") || isNodeOfType(typeNode, "TSAnyKeyword") || isNodeOfType(typeNode, "TSUnknownKeyword")) return true;
|
|
18557
|
-
if (isNodeOfType(typeNode, "TSStringKeyword") || isNodeOfType(typeNode, "TSBooleanKeyword") || isNodeOfType(typeNode, "TSBigIntKeyword") || isNodeOfType(typeNode, "TSSymbolKeyword") || isNodeOfType(typeNode, "TSNullKeyword") || isNodeOfType(typeNode, "TSUndefinedKeyword") || isNodeOfType(typeNode, "TSObjectKeyword") || isNodeOfType(typeNode, "TSLiteralType") || isNodeOfType(typeNode, "TSFunctionType")) return false;
|
|
18558
|
-
if (isNodeOfType(typeNode, "TSTypeLiteral")) return (typeNode.members?.length ?? 0) === 0;
|
|
18559
|
-
if (isNodeOfType(typeNode, "TSTypeOperator") && typeNode.operator === "keyof") return false;
|
|
18560
|
-
if (isNodeOfType(typeNode, "TSUnionType") || isNodeOfType(typeNode, "TSIntersectionType")) return typeNode.types.some((memberType) => typeCanHaveSameValueZeroDifference(memberType, reference, activeTypeNodes, typeArguments));
|
|
18561
|
-
if (isNodeOfType(typeNode, "TSOptionalType") || isNodeOfType(typeNode, "TSRestType")) return typeCanHaveSameValueZeroDifference(typeNode.typeAnnotation, reference, activeTypeNodes, typeArguments);
|
|
18562
|
-
if (isNodeOfType(typeNode, "TSNamedTupleMember")) return typeCanHaveSameValueZeroDifference(typeNode.elementType, reference, activeTypeNodes, typeArguments);
|
|
18563
|
-
if (!isNodeOfType(typeNode, "TSTypeReference")) return true;
|
|
18564
|
-
if (!isNodeOfType(typeNode.typeName, "Identifier")) return false;
|
|
18565
|
-
const substitutedType = typeArguments.get(typeNode.typeName.name);
|
|
18566
|
-
if (substitutedType) {
|
|
18567
|
-
const remainingArguments = new Map(typeArguments);
|
|
18568
|
-
remainingArguments.delete(typeNode.typeName.name);
|
|
18569
|
-
return typeCanHaveSameValueZeroDifference(substitutedType, reference, activeTypeNodes, remainingArguments);
|
|
18570
|
-
}
|
|
18571
|
-
const typeParameter = findTypeParameter(reference, typeNode.typeName.name);
|
|
18572
|
-
if (typeParameter) {
|
|
18573
|
-
if (!typeParameter.constraint || activeTypeNodes.has(typeParameter)) return true;
|
|
18574
|
-
activeTypeNodes.add(typeParameter);
|
|
18575
|
-
const constraintCanDiffer = typeCanHaveSameValueZeroDifference(typeParameter.constraint, reference, activeTypeNodes, typeArguments);
|
|
18576
|
-
activeTypeNodes.delete(typeParameter);
|
|
18577
|
-
return constraintCanDiffer;
|
|
18578
|
-
}
|
|
18579
|
-
const typeAlias = findSameFileTypeAlias(reference, typeNode.typeName.name);
|
|
18580
|
-
if (!typeAlias) return POSSIBLY_NUMERIC_TYPE_REFERENCE_NAMES.has(typeNode.typeName.name) || /(?:number|numeric)/i.test(typeNode.typeName.name);
|
|
18581
|
-
if (activeTypeNodes.has(typeAlias)) return true;
|
|
18582
|
-
activeTypeNodes.add(typeAlias);
|
|
18583
|
-
const canDiffer = typeCanHaveSameValueZeroDifference(typeAlias.typeAnnotation, reference, activeTypeNodes, buildTypeAliasArguments(typeAlias, typeNode, typeArguments));
|
|
18584
|
-
activeTypeNodes.delete(typeAlias);
|
|
18585
|
-
return canDiffer;
|
|
18586
|
-
};
|
|
18587
|
-
const arrayTypeCanHaveSameValueZeroDifference = (typeNode, reference, activeTypeNodes, typeArguments = /* @__PURE__ */ new Map()) => {
|
|
18588
|
-
if (!typeNode) return false;
|
|
18589
|
-
if (isNodeOfType(typeNode, "TSArrayType")) return typeCanHaveSameValueZeroDifference(typeNode.elementType, reference, activeTypeNodes, typeArguments);
|
|
18590
|
-
if (isNodeOfType(typeNode, "TSTupleType")) return typeNode.elementTypes.some((elementType) => {
|
|
18591
|
-
if (isNodeOfType(elementType, "TSRestType")) return arrayTypeCanHaveSameValueZeroDifference(elementType.typeAnnotation, reference, activeTypeNodes, typeArguments);
|
|
18592
|
-
if (isNodeOfType(elementType, "TSNamedTupleMember")) return typeCanHaveSameValueZeroDifference(elementType.elementType, reference, activeTypeNodes, typeArguments);
|
|
18593
|
-
return typeCanHaveSameValueZeroDifference(elementType, reference, activeTypeNodes, typeArguments);
|
|
18594
|
-
});
|
|
18595
|
-
if (isNodeOfType(typeNode, "TSTypeOperator")) return arrayTypeCanHaveSameValueZeroDifference(typeNode.typeAnnotation ?? null, reference, activeTypeNodes, typeArguments);
|
|
18596
|
-
if (isNodeOfType(typeNode, "TSUnionType") || isNodeOfType(typeNode, "TSIntersectionType")) return typeNode.types.some((memberType) => arrayTypeCanHaveSameValueZeroDifference(memberType, reference, activeTypeNodes, typeArguments));
|
|
18597
|
-
if (!isNodeOfType(typeNode, "TSTypeReference") || !isNodeOfType(typeNode.typeName, "Identifier")) return false;
|
|
18598
|
-
const substitutedType = typeArguments.get(typeNode.typeName.name);
|
|
18599
|
-
if (substitutedType) {
|
|
18600
|
-
const remainingArguments = new Map(typeArguments);
|
|
18601
|
-
remainingArguments.delete(typeNode.typeName.name);
|
|
18602
|
-
return arrayTypeCanHaveSameValueZeroDifference(substitutedType, reference, activeTypeNodes, remainingArguments);
|
|
18603
|
-
}
|
|
18604
|
-
if (typeNode.typeName.name === "Array" || typeNode.typeName.name === "ReadonlyArray") return typeCanHaveSameValueZeroDifference(typeNode.typeArguments?.params?.[0] ?? null, reference, activeTypeNodes, typeArguments);
|
|
18605
|
-
const typeAlias = findSameFileTypeAlias(reference, typeNode.typeName.name);
|
|
18606
|
-
if (!typeAlias || activeTypeNodes.has(typeAlias)) return false;
|
|
18607
|
-
activeTypeNodes.add(typeAlias);
|
|
18608
|
-
const canDiffer = arrayTypeCanHaveSameValueZeroDifference(typeAlias.typeAnnotation, reference, activeTypeNodes, buildTypeAliasArguments(typeAlias, typeNode, typeArguments));
|
|
18609
|
-
activeTypeNodes.delete(typeAlias);
|
|
18610
|
-
return canDiffer;
|
|
18611
|
-
};
|
|
18612
|
-
const isKnownArrayType = (typeNode, reference, activeTypeNodes, typeArguments = /* @__PURE__ */ new Map()) => {
|
|
18613
|
-
if (!typeNode) return false;
|
|
18614
|
-
if (isNodeOfType(typeNode, "TSArrayType") || isNodeOfType(typeNode, "TSTupleType")) return true;
|
|
18615
|
-
if (isNodeOfType(typeNode, "TSTypeOperator")) return isKnownArrayType(typeNode.typeAnnotation ?? null, reference, activeTypeNodes, typeArguments);
|
|
18616
|
-
if (isNodeOfType(typeNode, "TSUnionType")) {
|
|
18617
|
-
const nonNullishTypes = typeNode.types.filter((memberType) => !isNodeOfType(memberType, "TSNullKeyword") && !isNodeOfType(memberType, "TSUndefinedKeyword"));
|
|
18618
|
-
return nonNullishTypes.length > 0 && nonNullishTypes.every((memberType) => isKnownArrayType(memberType, reference, activeTypeNodes, typeArguments));
|
|
18619
|
-
}
|
|
18620
|
-
if (isNodeOfType(typeNode, "TSIntersectionType")) return typeNode.types.some((memberType) => isKnownArrayType(memberType, reference, activeTypeNodes, typeArguments));
|
|
18621
|
-
if (!isNodeOfType(typeNode, "TSTypeReference") || !isNodeOfType(typeNode.typeName, "Identifier")) return false;
|
|
18622
|
-
const substitutedType = typeArguments.get(typeNode.typeName.name);
|
|
18623
|
-
if (substitutedType) {
|
|
18624
|
-
const remainingArguments = new Map(typeArguments);
|
|
18625
|
-
remainingArguments.delete(typeNode.typeName.name);
|
|
18626
|
-
return isKnownArrayType(substitutedType, reference, activeTypeNodes, remainingArguments);
|
|
18627
|
-
}
|
|
18628
|
-
if (typeNode.typeName.name === "Array" || typeNode.typeName.name === "ReadonlyArray") return true;
|
|
18629
|
-
const typeParameter = findTypeParameter(reference, typeNode.typeName.name);
|
|
18630
|
-
if (typeParameter?.constraint) {
|
|
18631
|
-
if (activeTypeNodes.has(typeParameter)) return false;
|
|
18632
|
-
activeTypeNodes.add(typeParameter);
|
|
18633
|
-
const isConstraintArray = isKnownArrayType(typeParameter.constraint, reference, activeTypeNodes, typeArguments);
|
|
18634
|
-
activeTypeNodes.delete(typeParameter);
|
|
18635
|
-
return isConstraintArray;
|
|
18636
|
-
}
|
|
18637
|
-
const typeAlias = findSameFileTypeAlias(reference, typeNode.typeName.name);
|
|
18638
|
-
if (!typeAlias || activeTypeNodes.has(typeAlias)) return false;
|
|
18639
|
-
activeTypeNodes.add(typeAlias);
|
|
18640
|
-
const isArray = isKnownArrayType(typeAlias.typeAnnotation, reference, activeTypeNodes, buildTypeAliasArguments(typeAlias, typeNode, typeArguments));
|
|
18641
|
-
activeTypeNodes.delete(typeAlias);
|
|
18642
|
-
return isArray;
|
|
18643
|
-
};
|
|
18644
|
-
const isKnownNativeArrayReceiver = (receiver) => {
|
|
18645
|
-
if (isNodeOfType(receiver, "ArrayExpression")) return true;
|
|
18646
|
-
if (isNodeOfType(receiver, "Identifier") && isKnownArrayType(getIdentifierDeclaredType(receiver), receiver, /* @__PURE__ */ new Set())) return true;
|
|
18647
|
-
const initializer = getResolvedInitializer(receiver)?.initializer;
|
|
18648
|
-
if (!initializer) return false;
|
|
18649
|
-
const strippedInitializer = stripParenExpression(initializer);
|
|
18650
|
-
if (isNodeOfType(strippedInitializer, "ArrayExpression")) return true;
|
|
18651
|
-
if (isNodeOfType(strippedInitializer, "NewExpression") && isNodeOfType(strippedInitializer.callee, "Identifier") && strippedInitializer.callee.name === "Array" && findVariableInitializer(strippedInitializer.callee, strippedInitializer.callee.name) === null) return true;
|
|
18652
|
-
return isNodeOfType(strippedInitializer, "CallExpression") && isNodeOfType(strippedInitializer.callee, "MemberExpression") && isNodeOfType(strippedInitializer.callee.object, "Identifier") && strippedInitializer.callee.object.name === "Array" && isNodeOfType(strippedInitializer.callee.property, "Identifier") && (strippedInitializer.callee.property.name === "from" || strippedInitializer.callee.property.name === "of") && findVariableInitializer(strippedInitializer.callee.object, strippedInitializer.callee.object.name) === null;
|
|
18653
|
-
};
|
|
18654
|
-
const isKnownDenseArrayReceiver = (receiver) => {
|
|
18655
|
-
const initializer = isNodeOfType(receiver, "Identifier") ? getResolvedInitializer(receiver)?.initializer : receiver;
|
|
18656
|
-
if (!initializer) return false;
|
|
18657
|
-
const strippedInitializer = stripParenExpression(initializer);
|
|
18658
|
-
if (isNodeOfType(strippedInitializer, "ArrayExpression")) return (strippedInitializer.elements ?? []).every((element) => element !== null && !isNodeOfType(element, "SpreadElement"));
|
|
18659
|
-
return isNodeOfType(strippedInitializer, "CallExpression") && isNodeOfType(strippedInitializer.callee, "MemberExpression") && isNodeOfType(strippedInitializer.callee.object, "Identifier") && strippedInitializer.callee.object.name === "Array" && isNodeOfType(strippedInitializer.callee.property, "Identifier") && (strippedInitializer.callee.property.name === "from" || strippedInitializer.callee.property.name === "of") && findVariableInitializer(strippedInitializer.callee.object, strippedInitializer.callee.object.name) === null;
|
|
18660
|
-
};
|
|
18661
|
-
const isKnownUnsafeIndexOfQuery = (query, receiver) => {
|
|
18662
|
-
if (!query) return true;
|
|
18663
|
-
const strippedQuery = stripParenExpression(query);
|
|
18664
|
-
if (isNodeOfType(strippedQuery, "Identifier")) {
|
|
18665
|
-
if (strippedQuery.name === "undefined" && findVariableInitializer(strippedQuery, strippedQuery.name) === null) return !isKnownDenseArrayReceiver(receiver);
|
|
18666
|
-
if (strippedQuery.name === "NaN" && findVariableInitializer(strippedQuery, strippedQuery.name) === null) return true;
|
|
18667
|
-
return typeCanHaveSameValueZeroDifference(getIdentifierDeclaredType(strippedQuery), strippedQuery, /* @__PURE__ */ new Set());
|
|
18668
|
-
}
|
|
18669
|
-
if (isNodeOfType(strippedQuery, "MemberExpression")) return !strippedQuery.computed && isNodeOfType(strippedQuery.object, "Identifier") && strippedQuery.object.name === "Number" && isNodeOfType(strippedQuery.property, "Identifier") && strippedQuery.property.name === "NaN" && findVariableInitializer(strippedQuery.object, strippedQuery.object.name) === null;
|
|
18670
|
-
return true;
|
|
18671
|
-
};
|
|
18672
|
-
const isKnownUnsafeIndexOfReceiver = (receiver) => {
|
|
18673
|
-
if (!isNodeOfType(receiver, "Identifier")) return false;
|
|
18674
|
-
return arrayTypeCanHaveSameValueZeroDifference(getIdentifierDeclaredType(receiver), receiver, /* @__PURE__ */ new Set());
|
|
18675
|
-
};
|
|
18676
18356
|
const ITERATION_CALLBACK_METHOD_NAMES = new Set([
|
|
18677
18357
|
"forEach",
|
|
18678
18358
|
"map",
|
|
@@ -18801,22 +18481,16 @@ const jsSetMapLookups = defineRule({
|
|
|
18801
18481
|
if (!isNodeOfType(node.callee, "MemberExpression") || !isNodeOfType(node.callee.property, "Identifier")) return;
|
|
18802
18482
|
const methodName = node.callee.property.name;
|
|
18803
18483
|
if (methodName !== "includes" && methodName !== "indexOf") return;
|
|
18804
|
-
if (methodName === "
|
|
18805
|
-
if (methodName === "indexOf" && (node.arguments.length !== 1 || isNodeOfType(node.arguments[0], "SpreadElement") || !isIndexOfResultUsedAsMembershipTest(node))) return;
|
|
18484
|
+
if (methodName === "indexOf" && !isIndexOfResultUsedAsMembershipTest(node)) return;
|
|
18806
18485
|
const rawReceiver = node.callee.object;
|
|
18807
18486
|
if (!rawReceiver) return;
|
|
18808
18487
|
const receiver = stripParenExpression(rawReceiver);
|
|
18809
|
-
const isKnownNativeArray = isKnownNativeArrayReceiver(receiver);
|
|
18810
|
-
if (isKnownUserlandMembershipReceiver(receiver, methodName)) return;
|
|
18811
|
-
if (methodName === "includes" && node.arguments.length === 2 && !isKnownNativeArray) return;
|
|
18812
|
-
const query = node.arguments[0];
|
|
18813
|
-
if (methodName === "indexOf" && !isKnownSafeIndexOfQuery(query) && (isKnownUnsafeIndexOfQuery(query, receiver) || isKnownUnsafeIndexOfReceiver(receiver))) return;
|
|
18814
18488
|
if (isLikelyStringReceiver(receiver)) return;
|
|
18815
18489
|
if (isSmallInlineLiteralArray(receiver)) return;
|
|
18816
18490
|
if (isScreamingSnakeCaseConstantReceiver(receiver)) return;
|
|
18817
18491
|
if (isSmallFixedListMember(receiver)) return;
|
|
18818
|
-
if (isSubstringSearchLiteral(
|
|
18819
|
-
if (isIndexedArrayElementWithStringArgument(receiver,
|
|
18492
|
+
if (isSubstringSearchLiteral(node.arguments?.[0])) return;
|
|
18493
|
+
if (isIndexedArrayElementWithStringArgument(receiver, node.arguments?.[0])) return;
|
|
18820
18494
|
const resolvedInitializer = getResolvedInitializer(receiver);
|
|
18821
18495
|
if (resolvedInitializer) {
|
|
18822
18496
|
if (isLikelyStringReceiver(resolvedInitializer.initializer)) return;
|