oxlint-plugin-react-doctor 0.7.6-dev.1f14fa1 → 0.7.6-dev.47beb25
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 +298 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5964,7 +5964,7 @@ const checkedRequiresOnchangeOrReadonly = defineRule({
|
|
|
5964
5964
|
//#endregion
|
|
5965
5965
|
//#region src/plugin/utils/get-static-property-key-name.ts
|
|
5966
5966
|
const getStaticPropertyKeyName = (node, options = {}) => {
|
|
5967
|
-
if (!isNodeOfType(node, "Property")) return null;
|
|
5967
|
+
if (!isNodeOfType(node, "Property") && !isNodeOfType(node, "MethodDefinition")) return null;
|
|
5968
5968
|
if (node.computed) {
|
|
5969
5969
|
if (options.allowComputedString && isNodeOfType(node.key, "Literal") && typeof node.key.value === "string") return node.key.value;
|
|
5970
5970
|
return null;
|
|
@@ -21401,6 +21401,7 @@ const nextjsNoNativeScript = defineRule({
|
|
|
21401
21401
|
});
|
|
21402
21402
|
//#endregion
|
|
21403
21403
|
//#region src/plugin/rules/nextjs/nextjs-no-polyfill-script.ts
|
|
21404
|
+
const ABSOLUTE_URL_SCHEME_PATTERN = /^[a-z][a-z\d+.-]*:/i;
|
|
21404
21405
|
const nextjsNoPolyfillScript = defineRule({
|
|
21405
21406
|
id: "nextjs-no-polyfill-script",
|
|
21406
21407
|
title: "Redundant polyfill script",
|
|
@@ -21414,7 +21415,9 @@ const nextjsNoPolyfillScript = defineRule({
|
|
|
21414
21415
|
const srcAttribute = findJsxAttribute(node.attributes ?? [], "src");
|
|
21415
21416
|
if (!srcAttribute?.value) return;
|
|
21416
21417
|
const srcValue = isNodeOfType(srcAttribute.value, "Literal") ? srcAttribute.value.value : null;
|
|
21417
|
-
|
|
21418
|
+
const requestUrl = typeof srcValue === "string" ? srcValue.split("#", 1)[0] : null;
|
|
21419
|
+
const requestScheme = requestUrl?.trimStart().match(ABSOLUTE_URL_SCHEME_PATTERN)?.[0].toLowerCase();
|
|
21420
|
+
if (requestUrl && (!requestScheme || requestScheme === "http:" || requestScheme === "https:") && POLYFILL_SCRIPT_PATTERN.test(requestUrl)) context.report({
|
|
21418
21421
|
node,
|
|
21419
21422
|
message: "This polyfill CDN script makes your users download polyfills Next.js already includes."
|
|
21420
21423
|
});
|
|
@@ -33003,6 +33006,18 @@ const INTL_FORMAT_METHOD_NAMES = new Set([
|
|
|
33003
33006
|
"formatToParts",
|
|
33004
33007
|
"formatRange"
|
|
33005
33008
|
]);
|
|
33009
|
+
const ABSENT_PROPERTY_PROOF = { status: "absent" };
|
|
33010
|
+
const PRESENT_PROPERTY_PROOF = { status: "present" };
|
|
33011
|
+
const UNDEFINED_PROPERTY_PROOF = { status: "undefined" };
|
|
33012
|
+
const UNKNOWN_PROPERTY_PROOF = { status: "unknown" };
|
|
33013
|
+
const READ_ONLY_OBJECT_METHOD_NAMES = new Set([
|
|
33014
|
+
"hasOwnProperty",
|
|
33015
|
+
"isPrototypeOf",
|
|
33016
|
+
"propertyIsEnumerable",
|
|
33017
|
+
"toLocaleString",
|
|
33018
|
+
"toString",
|
|
33019
|
+
"valueOf"
|
|
33020
|
+
]);
|
|
33006
33021
|
const isProvableDateExpression = (expression) => {
|
|
33007
33022
|
if (!expression) return false;
|
|
33008
33023
|
const unwrapped = stripParenExpression(expression);
|
|
@@ -33017,32 +33032,290 @@ const receiverNameLooksDateFlavored = (expression) => {
|
|
|
33017
33032
|
if (isNodeOfType(unwrapped, "CallExpression")) return receiverNameLooksDateFlavored(unwrapped.callee);
|
|
33018
33033
|
return false;
|
|
33019
33034
|
};
|
|
33020
|
-
const
|
|
33021
|
-
|
|
33022
|
-
|
|
33023
|
-
if (!isNodeOfType(
|
|
33024
|
-
|
|
33025
|
-
|
|
33026
|
-
|
|
33027
|
-
|
|
33028
|
-
|
|
33035
|
+
const isStaticUndefined = (node, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
33036
|
+
const expression = stripParenExpression(node);
|
|
33037
|
+
if (isNodeOfType(expression, "UnaryExpression") && expression.operator === "void") return true;
|
|
33038
|
+
if (!isNodeOfType(expression, "Identifier")) return false;
|
|
33039
|
+
if (expression.name === "undefined" && scopes.isGlobalReference(expression)) return true;
|
|
33040
|
+
const symbol = scopes.symbolFor(expression);
|
|
33041
|
+
if (symbol?.kind !== "const" || !symbol.initializer || !isNodeOfType(symbol.declarationNode, "VariableDeclarator") || !isNodeOfType(symbol.declarationNode.id, "Identifier") || visitedSymbolIds.has(symbol.id)) return false;
|
|
33042
|
+
visitedSymbolIds.add(symbol.id);
|
|
33043
|
+
return isStaticUndefined(symbol.initializer, scopes, visitedSymbolIds);
|
|
33044
|
+
};
|
|
33045
|
+
const isNestedAssignmentTarget = (expression) => {
|
|
33046
|
+
let target = expression;
|
|
33047
|
+
let parent = target.parent;
|
|
33048
|
+
while (parent) {
|
|
33049
|
+
if (isNodeOfType(parent, "AssignmentExpression")) return parent.left === target;
|
|
33050
|
+
if (isNodeOfType(parent, "ForInStatement") || isNodeOfType(parent, "ForOfStatement")) return parent.left === target;
|
|
33051
|
+
if (isNodeOfType(parent, "AssignmentPattern")) {
|
|
33052
|
+
if (parent.left !== target) return false;
|
|
33053
|
+
} else if (isNodeOfType(parent, "RestElement")) {
|
|
33054
|
+
if (parent.argument !== target) return false;
|
|
33055
|
+
} else if (isNodeOfType(parent, "ArrayPattern")) {
|
|
33056
|
+
if (!parent.elements?.some((element) => element === target)) return false;
|
|
33057
|
+
} else if (isNodeOfType(parent, "Property")) {
|
|
33058
|
+
if (parent.value !== target || !isNodeOfType(parent.parent, "ObjectPattern")) return false;
|
|
33059
|
+
} else if (isNodeOfType(parent, "ObjectPattern")) {
|
|
33060
|
+
if (!parent.properties?.some((property) => property === target)) return false;
|
|
33061
|
+
} else return false;
|
|
33062
|
+
target = parent;
|
|
33063
|
+
parent = target.parent;
|
|
33064
|
+
}
|
|
33065
|
+
return false;
|
|
33066
|
+
};
|
|
33067
|
+
const isPotentialMutationReference = (identifier, readNode) => {
|
|
33068
|
+
let expression = identifier;
|
|
33069
|
+
let parent = expression.parent;
|
|
33070
|
+
while (parent && TRANSPARENT_EXPRESSION_WRAPPER_TYPES.has(parent.type) && "expression" in parent && parent.expression === expression) {
|
|
33071
|
+
expression = parent;
|
|
33072
|
+
parent = expression.parent;
|
|
33073
|
+
}
|
|
33074
|
+
const rootExpression = expression;
|
|
33075
|
+
let memberDepth = 0;
|
|
33076
|
+
while (parent && isNodeOfType(parent, "MemberExpression") && parent.object === expression) {
|
|
33077
|
+
memberDepth += 1;
|
|
33078
|
+
expression = parent;
|
|
33079
|
+
parent = expression.parent;
|
|
33080
|
+
while (parent && TRANSPARENT_EXPRESSION_WRAPPER_TYPES.has(parent.type) && "expression" in parent && parent.expression === expression) {
|
|
33081
|
+
expression = parent;
|
|
33082
|
+
parent = expression.parent;
|
|
33083
|
+
}
|
|
33084
|
+
}
|
|
33085
|
+
if (!parent || isAstDescendant(identifier, readNode)) return false;
|
|
33086
|
+
if (isNestedAssignmentTarget(expression)) return true;
|
|
33087
|
+
if (isNodeOfType(parent, "AssignmentExpression") && parent.left === expression) return true;
|
|
33088
|
+
if (isNodeOfType(parent, "UpdateExpression") && parent.argument === expression) return true;
|
|
33089
|
+
if (isNodeOfType(parent, "UnaryExpression") && parent.operator === "delete" && parent.argument === expression) return true;
|
|
33090
|
+
if (isNodeOfType(parent, "CallExpression")) {
|
|
33091
|
+
if (parent.callee === expression) {
|
|
33092
|
+
if (memberDepth === 0) return true;
|
|
33093
|
+
const memberExpression = stripParenExpression(expression);
|
|
33094
|
+
return memberDepth === 1 && isNodeOfType(memberExpression, "MemberExpression") && !READ_ONLY_OBJECT_METHOD_NAMES.has(getStaticPropertyName(memberExpression) ?? "");
|
|
33095
|
+
}
|
|
33096
|
+
return memberDepth === 0 && parent.arguments?.some((argument) => argument === rootExpression);
|
|
33029
33097
|
}
|
|
33098
|
+
if (isNodeOfType(parent, "NewExpression")) return memberDepth === 0 && parent.arguments?.some((argument) => argument === rootExpression);
|
|
33099
|
+
if (isNodeOfType(parent, "AssignmentExpression") && parent.right === rootExpression) return true;
|
|
33030
33100
|
return false;
|
|
33031
33101
|
};
|
|
33032
|
-
const
|
|
33102
|
+
const getSimpleAlias = (identifier, scopes) => {
|
|
33103
|
+
let expression = identifier;
|
|
33104
|
+
let parent = expression.parent;
|
|
33105
|
+
while (parent && TRANSPARENT_EXPRESSION_WRAPPER_TYPES.has(parent.type) && "expression" in parent && parent.expression === expression) {
|
|
33106
|
+
expression = parent;
|
|
33107
|
+
parent = expression.parent;
|
|
33108
|
+
}
|
|
33109
|
+
if (!isNodeOfType(parent, "VariableDeclarator") || parent.init !== expression || !isNodeOfType(parent.id, "Identifier")) return null;
|
|
33110
|
+
const symbol = scopes.symbolFor(parent.id);
|
|
33111
|
+
return symbol ? {
|
|
33112
|
+
symbol,
|
|
33113
|
+
readNode: parent.id
|
|
33114
|
+
} : null;
|
|
33115
|
+
};
|
|
33116
|
+
const getDirectCallForExpression = (expression) => {
|
|
33117
|
+
let callee = expression;
|
|
33118
|
+
let parent = callee.parent;
|
|
33119
|
+
while (parent && TRANSPARENT_EXPRESSION_WRAPPER_TYPES.has(parent.type) && "expression" in parent && parent.expression === callee) {
|
|
33120
|
+
callee = parent;
|
|
33121
|
+
parent = callee.parent;
|
|
33122
|
+
}
|
|
33123
|
+
return isNodeOfType(parent, "CallExpression") && parent.callee === callee ? parent : null;
|
|
33124
|
+
};
|
|
33125
|
+
const getMethodOwner = (functionNode, scopes) => {
|
|
33126
|
+
const methodNode = functionNode.parent;
|
|
33127
|
+
if (isNodeOfType(methodNode, "Property") && methodNode.value === functionNode && isNodeOfType(methodNode.parent, "ObjectExpression")) {
|
|
33128
|
+
const objectParent = methodNode.parent.parent;
|
|
33129
|
+
if (!isNodeOfType(objectParent, "VariableDeclarator") || objectParent.init !== methodNode.parent || !isNodeOfType(objectParent.id, "Identifier")) return null;
|
|
33130
|
+
const ownerSymbol = scopes.symbolFor(objectParent.id);
|
|
33131
|
+
const methodName = getStaticPropertyKeyName(methodNode, { allowComputedString: true });
|
|
33132
|
+
return ownerSymbol && methodName ? {
|
|
33133
|
+
methodName,
|
|
33134
|
+
ownerKind: "object",
|
|
33135
|
+
ownerSymbol,
|
|
33136
|
+
isStatic: false
|
|
33137
|
+
} : null;
|
|
33138
|
+
}
|
|
33139
|
+
if (!isNodeOfType(methodNode, "MethodDefinition") || methodNode.value !== functionNode || !isNodeOfType(methodNode.parent, "ClassBody")) return null;
|
|
33140
|
+
const classNode = methodNode.parent.parent;
|
|
33141
|
+
if (!isNodeOfType(classNode, "ClassDeclaration") && !isNodeOfType(classNode, "ClassExpression")) return null;
|
|
33142
|
+
let bindingIdentifier = isNodeOfType(classNode.id, "Identifier") ? classNode.id : null;
|
|
33143
|
+
if (!bindingIdentifier && isNodeOfType(classNode.parent, "VariableDeclarator")) bindingIdentifier = isNodeOfType(classNode.parent.id, "Identifier") ? classNode.parent.id : null;
|
|
33144
|
+
if (!bindingIdentifier) return null;
|
|
33145
|
+
const ownerSymbol = scopes.symbolFor(bindingIdentifier);
|
|
33146
|
+
const methodName = getStaticPropertyKeyName(methodNode, { allowComputedString: true });
|
|
33147
|
+
return ownerSymbol && methodName ? {
|
|
33148
|
+
methodName,
|
|
33149
|
+
ownerKind: "class",
|
|
33150
|
+
ownerSymbol,
|
|
33151
|
+
isStatic: Boolean(methodNode.static)
|
|
33152
|
+
} : null;
|
|
33153
|
+
};
|
|
33154
|
+
const doesSymbolResolveToOwner = (symbol, ownerSymbol, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
33155
|
+
if (!symbol) return false;
|
|
33156
|
+
if (symbol.declarationNode === ownerSymbol.declarationNode) return true;
|
|
33157
|
+
if (symbol.kind !== "const" || !symbol.initializer || visitedSymbolIds.has(symbol.id)) return false;
|
|
33158
|
+
visitedSymbolIds.add(symbol.id);
|
|
33159
|
+
const initializer = stripParenExpression(symbol.initializer);
|
|
33160
|
+
return isNodeOfType(initializer, "Identifier") && doesSymbolResolveToOwner(scopes.symbolFor(initializer), ownerSymbol, scopes, visitedSymbolIds);
|
|
33161
|
+
};
|
|
33162
|
+
const isClassInstanceExpression = (expression, ownerSymbol, scopes, visitedSymbolIds = /* @__PURE__ */ new Set()) => {
|
|
33163
|
+
const candidate = stripParenExpression(expression);
|
|
33164
|
+
if (isNodeOfType(candidate, "NewExpression") && isNodeOfType(candidate.callee, "Identifier")) return doesSymbolResolveToOwner(scopes.symbolFor(candidate.callee), ownerSymbol, scopes);
|
|
33165
|
+
if (!isNodeOfType(candidate, "Identifier")) return false;
|
|
33166
|
+
const symbol = scopes.symbolFor(candidate);
|
|
33167
|
+
if (symbol?.kind !== "const" || !symbol.initializer || visitedSymbolIds.has(symbol.id)) return false;
|
|
33168
|
+
visitedSymbolIds.add(symbol.id);
|
|
33169
|
+
return isClassInstanceExpression(symbol.initializer, ownerSymbol, scopes, visitedSymbolIds);
|
|
33170
|
+
};
|
|
33171
|
+
const getMethodCalls = (functionNode, scopes) => {
|
|
33172
|
+
const owner = getMethodOwner(functionNode, scopes);
|
|
33173
|
+
if (!owner) return [];
|
|
33174
|
+
const calls = [];
|
|
33175
|
+
walkAst(scopes.rootScope.node, (child) => {
|
|
33176
|
+
if (!isNodeOfType(child, "MemberExpression")) return;
|
|
33177
|
+
if (getStaticPropertyName(child) !== owner.methodName) return;
|
|
33178
|
+
const receiver = stripParenExpression(child.object);
|
|
33179
|
+
let doesReceiverMatch = isNodeOfType(receiver, "Identifier") && doesSymbolResolveToOwner(scopes.symbolFor(receiver), owner.ownerSymbol, scopes);
|
|
33180
|
+
if (owner.ownerKind === "class" && !owner.isStatic) doesReceiverMatch = isClassInstanceExpression(receiver, owner.ownerSymbol, scopes);
|
|
33181
|
+
if (!doesReceiverMatch) return;
|
|
33182
|
+
const call = getDirectCallForExpression(child);
|
|
33183
|
+
if (call) calls.push(call);
|
|
33184
|
+
});
|
|
33185
|
+
return calls;
|
|
33186
|
+
};
|
|
33187
|
+
const isFunctionInvokedBeforeUsage = (functionNode, usageNode, usageBoundary, scopes, visitedSymbolIds, visitedFunctionNodes = /* @__PURE__ */ new Set()) => {
|
|
33188
|
+
if (visitedFunctionNodes.has(functionNode)) return false;
|
|
33189
|
+
visitedFunctionNodes.add(functionNode);
|
|
33190
|
+
const usageFunction = findEnclosingFunction(usageNode);
|
|
33191
|
+
const immediateCall = getDirectCallForExpression(functionNode);
|
|
33192
|
+
if (immediateCall) {
|
|
33193
|
+
const immediateCallFunction = findEnclosingFunction(immediateCall);
|
|
33194
|
+
if (immediateCallFunction === usageFunction) {
|
|
33195
|
+
const immediateCallStart = getRangeStart(immediateCall);
|
|
33196
|
+
return immediateCallStart === null || immediateCallStart < usageBoundary;
|
|
33197
|
+
}
|
|
33198
|
+
if (!immediateCallFunction) return usageFunction !== null;
|
|
33199
|
+
return isFunctionInvokedBeforeUsage(immediateCallFunction, usageNode, usageBoundary, scopes, visitedSymbolIds, new Set(visitedFunctionNodes));
|
|
33200
|
+
}
|
|
33201
|
+
for (const methodCall of getMethodCalls(functionNode, scopes)) {
|
|
33202
|
+
const methodCallFunction = findEnclosingFunction(methodCall);
|
|
33203
|
+
if (methodCallFunction === usageFunction) {
|
|
33204
|
+
const methodCallStart = getRangeStart(methodCall);
|
|
33205
|
+
if (methodCallStart === null || methodCallStart < usageBoundary) return true;
|
|
33206
|
+
continue;
|
|
33207
|
+
}
|
|
33208
|
+
if (!methodCallFunction) {
|
|
33209
|
+
if (usageFunction) return true;
|
|
33210
|
+
continue;
|
|
33211
|
+
}
|
|
33212
|
+
if (isFunctionInvokedBeforeUsage(methodCallFunction, usageNode, usageBoundary, scopes, new Set(visitedSymbolIds), new Set(visitedFunctionNodes))) return true;
|
|
33213
|
+
}
|
|
33214
|
+
const bindingIdentifier = getFunctionBindingIdentifier(functionNode);
|
|
33215
|
+
if (!bindingIdentifier) return false;
|
|
33216
|
+
const symbol = scopes.symbolFor(bindingIdentifier);
|
|
33217
|
+
if (!symbol || visitedSymbolIds.has(symbol.id)) return false;
|
|
33218
|
+
visitedSymbolIds.add(symbol.id);
|
|
33219
|
+
let wasInvokedBeforeUsage = false;
|
|
33220
|
+
walkAst(scopes.rootScope.node, (child) => {
|
|
33221
|
+
if (wasInvokedBeforeUsage || !isNodeOfType(child, "Identifier")) return;
|
|
33222
|
+
if (scopes.symbolFor(child)?.declarationNode !== symbol.declarationNode) return;
|
|
33223
|
+
const call = getDirectCallForExpression(child);
|
|
33224
|
+
if (!call) return false;
|
|
33225
|
+
const callFunction = findEnclosingFunction(call);
|
|
33226
|
+
if (callFunction === usageFunction) {
|
|
33227
|
+
const callStart = getRangeStart(call);
|
|
33228
|
+
wasInvokedBeforeUsage = callStart === null || callStart < usageBoundary;
|
|
33229
|
+
return;
|
|
33230
|
+
}
|
|
33231
|
+
if (!callFunction) {
|
|
33232
|
+
wasInvokedBeforeUsage = usageFunction !== null;
|
|
33233
|
+
return;
|
|
33234
|
+
}
|
|
33235
|
+
wasInvokedBeforeUsage = isFunctionInvokedBeforeUsage(callFunction, usageNode, usageBoundary, scopes, new Set(visitedSymbolIds), new Set(visitedFunctionNodes));
|
|
33236
|
+
});
|
|
33237
|
+
return wasInvokedBeforeUsage;
|
|
33238
|
+
};
|
|
33239
|
+
const getMutationUsageBoundary = (usageNode, readNode) => {
|
|
33240
|
+
const readStart = getRangeStart(readNode);
|
|
33241
|
+
let readExpression = readNode;
|
|
33242
|
+
let readParent = readExpression.parent;
|
|
33243
|
+
while (readParent && TRANSPARENT_EXPRESSION_WRAPPER_TYPES.has(readParent.type) && "expression" in readParent && readParent.expression === readExpression) {
|
|
33244
|
+
readExpression = readParent;
|
|
33245
|
+
readParent = readExpression.parent;
|
|
33246
|
+
}
|
|
33247
|
+
if ((isNodeOfType(usageNode, "CallExpression") || isNodeOfType(usageNode, "NewExpression")) && usageNode.arguments?.some((argument) => argument === readExpression)) return usageNode.range?.[1] ?? null;
|
|
33248
|
+
if (isAstDescendant(readNode, usageNode)) return readStart;
|
|
33249
|
+
return getRangeStart(usageNode);
|
|
33250
|
+
};
|
|
33251
|
+
const wasMutatedBeforeUsage = (symbol, usageNode, readNode, scopes, visitedMutationSymbolIds = /* @__PURE__ */ new Set(), inheritedUsageBoundary, readNodesBySymbolId = /* @__PURE__ */ new Map()) => {
|
|
33252
|
+
if (visitedMutationSymbolIds.has(symbol.id)) return false;
|
|
33253
|
+
visitedMutationSymbolIds.add(symbol.id);
|
|
33254
|
+
const usageBoundary = inheritedUsageBoundary === void 0 ? getMutationUsageBoundary(usageNode, readNode) : inheritedUsageBoundary;
|
|
33255
|
+
if (typeof usageBoundary !== "number") return true;
|
|
33256
|
+
const usageFunction = findEnclosingFunction(usageNode);
|
|
33257
|
+
return symbol.references.some((reference) => {
|
|
33258
|
+
const referenceStart = getRangeStart(reference.identifier);
|
|
33259
|
+
const simpleAlias = getSimpleAlias(reference.identifier, scopes);
|
|
33260
|
+
if (simpleAlias) return wasMutatedBeforeUsage(simpleAlias.symbol, usageNode, readNodesBySymbolId.get(simpleAlias.symbol.id) ?? simpleAlias.readNode, scopes, new Set(visitedMutationSymbolIds), usageBoundary, readNodesBySymbolId);
|
|
33261
|
+
if (!isPotentialMutationReference(reference.identifier, readNode)) return false;
|
|
33262
|
+
if (referenceStart === null) return true;
|
|
33263
|
+
const mutationFunction = findEnclosingFunction(reference.identifier);
|
|
33264
|
+
if (mutationFunction === usageFunction) return referenceStart < usageBoundary;
|
|
33265
|
+
if (!mutationFunction) return usageFunction !== null;
|
|
33266
|
+
if (usageFunction && isAstDescendant(usageFunction, mutationFunction)) return true;
|
|
33267
|
+
return isFunctionInvokedBeforeUsage(mutationFunction, usageNode, usageBoundary, scopes, /* @__PURE__ */ new Set());
|
|
33268
|
+
});
|
|
33269
|
+
};
|
|
33270
|
+
const getObjectPropertyProof = (objectExpression, propertyName, scopes, usageNode, visitedSymbolIds = /* @__PURE__ */ new Set(), inheritedUsageBoundary, readNodesBySymbolId = /* @__PURE__ */ new Map()) => {
|
|
33271
|
+
if (!objectExpression) return ABSENT_PROPERTY_PROOF;
|
|
33272
|
+
const unwrapped = stripParenExpression(objectExpression);
|
|
33273
|
+
if (isNodeOfType(unwrapped, "Literal") || isStaticUndefined(unwrapped, scopes)) return ABSENT_PROPERTY_PROOF;
|
|
33274
|
+
if (isNodeOfType(unwrapped, "Identifier")) {
|
|
33275
|
+
const symbol = scopes.symbolFor(unwrapped);
|
|
33276
|
+
const nextReadNodesBySymbolId = new Map(readNodesBySymbolId);
|
|
33277
|
+
if (symbol) nextReadNodesBySymbolId.set(symbol.id, unwrapped);
|
|
33278
|
+
const usageBoundary = inheritedUsageBoundary === void 0 ? getMutationUsageBoundary(usageNode, unwrapped) : inheritedUsageBoundary;
|
|
33279
|
+
if (symbol?.kind !== "const" || !symbol.initializer || !isNodeOfType(symbol.declarationNode, "VariableDeclarator") || !isNodeOfType(symbol.declarationNode.id, "Identifier") || visitedSymbolIds.has(symbol.id) || wasMutatedBeforeUsage(symbol, usageNode, unwrapped, scopes, /* @__PURE__ */ new Set(), usageBoundary, nextReadNodesBySymbolId)) return UNKNOWN_PROPERTY_PROOF;
|
|
33280
|
+
visitedSymbolIds.add(symbol.id);
|
|
33281
|
+
return getObjectPropertyProof(symbol.initializer, propertyName, scopes, usageNode, visitedSymbolIds, usageBoundary, nextReadNodesBySymbolId);
|
|
33282
|
+
}
|
|
33283
|
+
if (isNodeOfType(unwrapped, "ConditionalExpression")) {
|
|
33284
|
+
const consequent = getObjectPropertyProof(unwrapped.consequent, propertyName, scopes, usageNode, new Set(visitedSymbolIds), inheritedUsageBoundary, new Map(readNodesBySymbolId));
|
|
33285
|
+
const alternate = getObjectPropertyProof(unwrapped.alternate, propertyName, scopes, usageNode, new Set(visitedSymbolIds), inheritedUsageBoundary, new Map(readNodesBySymbolId));
|
|
33286
|
+
return consequent.status === alternate.status ? consequent : UNKNOWN_PROPERTY_PROOF;
|
|
33287
|
+
}
|
|
33288
|
+
if (isNodeOfType(unwrapped, "CallExpression") && isNodeOfType(unwrapped.callee, "MemberExpression") && !unwrapped.callee.computed && isNodeOfType(unwrapped.callee.object, "Identifier") && unwrapped.callee.object.name === "Object" && scopes.isGlobalReference(unwrapped.callee.object) && isNodeOfType(unwrapped.callee.property, "Identifier") && unwrapped.callee.property.name === "freeze") return getObjectPropertyProof(unwrapped.arguments?.[0], propertyName, scopes, usageNode, visitedSymbolIds, inheritedUsageBoundary, readNodesBySymbolId);
|
|
33289
|
+
if (!isNodeOfType(unwrapped, "ObjectExpression")) return UNKNOWN_PROPERTY_PROOF;
|
|
33290
|
+
const properties = unwrapped.properties ?? [];
|
|
33291
|
+
for (let propertyIndex = properties.length - 1; propertyIndex >= 0; propertyIndex -= 1) {
|
|
33292
|
+
const property = properties[propertyIndex];
|
|
33293
|
+
if (!property) continue;
|
|
33294
|
+
if (isNodeOfType(property, "SpreadElement")) {
|
|
33295
|
+
const spreadProof = getObjectPropertyProof(property.argument, propertyName, scopes, unwrapped, new Set(visitedSymbolIds), void 0);
|
|
33296
|
+
if (spreadProof.status !== "absent") return spreadProof;
|
|
33297
|
+
continue;
|
|
33298
|
+
}
|
|
33299
|
+
if (!isNodeOfType(property, "Property") || getStaticPropertyKeyName(property) !== propertyName) continue;
|
|
33300
|
+
return isStaticUndefined(property.value, scopes) ? UNDEFINED_PROPERTY_PROOF : PRESENT_PROPERTY_PROOF;
|
|
33301
|
+
}
|
|
33302
|
+
return ABSENT_PROPERTY_PROOF;
|
|
33303
|
+
};
|
|
33304
|
+
const objectHasExplicitProperty = (objectExpression, propertyName, scopes, usageNode) => getObjectPropertyProof(objectExpression, propertyName, scopes, usageNode).status === "present";
|
|
33305
|
+
const hasExplicitLocaleArgument = (argument, scopes) => {
|
|
33033
33306
|
if (!argument) return false;
|
|
33034
33307
|
const unwrapped = stripParenExpression(argument);
|
|
33035
|
-
if (isNodeOfType(unwrapped, "Identifier") && unwrapped.name === "undefined") return false;
|
|
33308
|
+
if (isNodeOfType(unwrapped, "Identifier") && unwrapped.name === "undefined" && scopes.isGlobalReference(unwrapped) || isNodeOfType(unwrapped, "UnaryExpression") && unwrapped.operator === "void") return false;
|
|
33036
33309
|
return true;
|
|
33037
33310
|
};
|
|
33038
|
-
const isDeterministicLocaleMethodCall = (call, methodName, receiverIsProvablyDate) => {
|
|
33311
|
+
const isDeterministicLocaleMethodCall = (call, methodName, receiverIsProvablyDate, scopes) => {
|
|
33039
33312
|
const localeArgument = call.arguments?.[0];
|
|
33040
|
-
if (!hasExplicitLocaleArgument(localeArgument)) return false;
|
|
33313
|
+
if (!hasExplicitLocaleArgument(localeArgument, scopes)) return false;
|
|
33041
33314
|
const optionsArgument = call.arguments?.[1];
|
|
33042
|
-
if (
|
|
33315
|
+
if (objectHasExplicitProperty(optionsArgument, "timeZone", scopes, call)) return true;
|
|
33043
33316
|
return !DATE_ONLY_LOCALE_METHOD_NAMES.has(methodName) && !receiverIsProvablyDate;
|
|
33044
33317
|
};
|
|
33045
|
-
const matchLocaleMethodCall = (call) => {
|
|
33318
|
+
const matchLocaleMethodCall = (call, scopes) => {
|
|
33046
33319
|
const callee = call.callee;
|
|
33047
33320
|
if (!isNodeOfType(callee, "MemberExpression") || callee.computed) return null;
|
|
33048
33321
|
if (!isNodeOfType(callee.property, "Identifier")) return null;
|
|
@@ -33050,7 +33323,7 @@ const matchLocaleMethodCall = (call) => {
|
|
|
33050
33323
|
if (!LOCALE_FORMAT_METHOD_NAMES.has(methodName)) return null;
|
|
33051
33324
|
const receiverIsProvablyDate = isProvableDateExpression(callee.object);
|
|
33052
33325
|
if (methodName === "toLocaleString" && !receiverIsProvablyDate && !receiverNameLooksDateFlavored(callee.object)) return null;
|
|
33053
|
-
if (isDeterministicLocaleMethodCall(call, methodName, receiverIsProvablyDate)) return null;
|
|
33326
|
+
if (isDeterministicLocaleMethodCall(call, methodName, receiverIsProvablyDate, scopes)) return null;
|
|
33054
33327
|
return {
|
|
33055
33328
|
node: call,
|
|
33056
33329
|
display: `${methodName}()`
|
|
@@ -33066,13 +33339,13 @@ const getIntlFormatterName = (expression) => {
|
|
|
33066
33339
|
if (!isNodeOfType(callee.property, "Identifier")) return null;
|
|
33067
33340
|
return INTL_FORMATTER_NAMES.has(callee.property.name) ? callee.property.name : null;
|
|
33068
33341
|
};
|
|
33069
|
-
const isDeterministicIntlConstruction = (construction, formatterName) => {
|
|
33342
|
+
const isDeterministicIntlConstruction = (construction, formatterName, scopes) => {
|
|
33070
33343
|
if (!isNodeOfType(construction, "CallExpression") && !isNodeOfType(construction, "NewExpression")) return false;
|
|
33071
|
-
if (!hasExplicitLocaleArgument(construction.arguments?.[0])) return false;
|
|
33344
|
+
if (!hasExplicitLocaleArgument(construction.arguments?.[0], scopes)) return false;
|
|
33072
33345
|
if (formatterName !== "DateTimeFormat") return true;
|
|
33073
|
-
return
|
|
33346
|
+
return objectHasExplicitProperty(construction.arguments?.[1], "timeZone", scopes, construction);
|
|
33074
33347
|
};
|
|
33075
|
-
const matchIntlFormatCall = (call) => {
|
|
33348
|
+
const matchIntlFormatCall = (call, scopes) => {
|
|
33076
33349
|
const callee = call.callee;
|
|
33077
33350
|
if (!isNodeOfType(callee, "MemberExpression") || callee.computed) return null;
|
|
33078
33351
|
if (!isNodeOfType(callee.property, "Identifier")) return null;
|
|
@@ -33085,7 +33358,7 @@ const matchIntlFormatCall = (call) => {
|
|
|
33085
33358
|
if (!construction) return null;
|
|
33086
33359
|
const formatterName = getIntlFormatterName(construction);
|
|
33087
33360
|
if (!formatterName) return null;
|
|
33088
|
-
if (isDeterministicIntlConstruction(construction, formatterName)) return null;
|
|
33361
|
+
if (isDeterministicIntlConstruction(construction, formatterName, scopes)) return null;
|
|
33089
33362
|
return {
|
|
33090
33363
|
node: call,
|
|
33091
33364
|
display: `Intl.${formatterName}().${callee.property.name}()`
|
|
@@ -33154,7 +33427,7 @@ const noLocaleFormatInRender = defineRule({
|
|
|
33154
33427
|
fileIsEmailTemplate = hasEmailTemplateImport(node);
|
|
33155
33428
|
},
|
|
33156
33429
|
CallExpression(node) {
|
|
33157
|
-
const match = matchLocaleMethodCall(node) ?? matchIntlFormatCall(node) ?? matchDateDefaultStringification(node);
|
|
33430
|
+
const match = matchLocaleMethodCall(node, context.scopes) ?? matchIntlFormatCall(node, context.scopes) ?? matchDateDefaultStringification(node);
|
|
33158
33431
|
if (match) reportIfRenderPhase(match);
|
|
33159
33432
|
},
|
|
33160
33433
|
TemplateLiteral(node) {
|
|
@@ -33174,7 +33447,7 @@ const noLocaleFormatInRender = defineRule({
|
|
|
33174
33447
|
walkAst(helperNode.body ?? helperNode, (child) => {
|
|
33175
33448
|
if (isFunctionLike$1(child)) return false;
|
|
33176
33449
|
if (!isNodeOfType(child, "CallExpression")) return;
|
|
33177
|
-
const match = matchLocaleMethodCall(child) ?? matchIntlFormatCall(child);
|
|
33450
|
+
const match = matchLocaleMethodCall(child, context.scopes) ?? matchIntlFormatCall(child, context.scopes);
|
|
33178
33451
|
if (!match || reportedNodes.has(match.node)) return;
|
|
33179
33452
|
if (fileIsEmailTemplate) return;
|
|
33180
33453
|
if (!hasClientRenderEvidence(componentOrHookNode, fileHasUseClientDirective)) return;
|