fix(javascript): derive loop cardinality from exact literal values

Use the canonical cooked literal value for for-in and for-of string cardinality, preserving possible assignments and prototype uncertainty across quoted and template spellings.

Validation: 473 focused tests across six files, including public CLI assignment Evidence and exported return shapes. Refs #4617
This commit is contained in:
morluto committed 2026-10-17 08:27:39 +08:00
1 parent 746a044e42
commit c3e42385e7
3 files changed
+141 -5

No files matched your search

@@ -19,6 +19,7 @@ export const semanticIterationCardinality = (
prototypeMayAffectEnumeration: boolean | undefined,
): JavaScriptSemanticIterationCardinality => {
const iterable = unwrapJavaScriptExpression(loop.right).node;
const literal = readExactJavaScriptLiteral(iterable);
if (t.isForOfStatement(loop)) {
if (prototypeMayAffectEnumeration !== false) return "unknown";
if (t.isArrayExpression(iterable)) {
@@ -31,8 +32,8 @@ export const semanticIterationCardinality = (
return "nonempty";
return "unknown";
}
if (t.isStringLiteral(iterable))
return iterable.value.length === 0 ? "empty" : "nonempty";
if (literal.found && typeof literal.value === "string")
return literal.value.length === 0 ? "empty" : "nonempty";
return "unknown";
}
if (t.isObjectExpression(iterable)) {
@@ -57,10 +58,14 @@ export const semanticIterationCardinality = (
return "unknown";
return prototypeMayAffectEnumeration === false ? "empty" : "unknown";
}
if (t.isNullLiteral(iterable)) return "empty";
if (t.isStringLiteral(iterable) && iterable.value.length > 0)
if (literal.found && literal.value === null) return "empty";
if (
literal.found &&
typeof literal.value === "string" &&
literal.value.length > 0
)
return "nonempty";
if (readExactJavaScriptLiteral(iterable).found)
if (literal.found)
return prototypeMayAffectEnumeration === false ? "empty" : "unknown";
return "unknown";
};