Skip to content

Commit a1cd1f1

Browse files
committed
refactor: improve code quality in tryDynamicRelationOverrideFallback
- Fix potential duplication bug: clear firstBucket before dynamic fallback to prevent partially-processed static declarations from creating duplicate entries in finalizeRelationOverrides - Deduplicate ancestor pseudo map building by reusing buildAncestorPseudoMap - Use proper CssValuePart type instead of inline type annotation - Simplify slot filter predicate (slotId is always present on slot parts) https://claude.ai/code/session_017ZD61A5aZG3vQWkJPMRFex
1 parent c1a4ce9 commit a1cd1f1

1 file changed

Lines changed: 21 additions & 14 deletions

File tree

src/internal/lower-rules/process-rules.ts

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { JSCodeshift } from "jscodeshift";
66
import type { SelectorResolveResult } from "../../adapter.js";
77
import type { DeclProcessingState } from "./decl-setup.js";
88
import type { StyledDecl } from "../transform-types.js";
9-
import type { CssDeclarationIR } from "../css-ir.js";
9+
import type { CssDeclarationIR, CssValuePart } from "../css-ir.js";
1010
import { computeSelectorWarningLoc } from "../css-ir.js";
1111
import { cssDeclarationToStylexDeclarations } from "../css-prop-mapping.js";
1212
import { addPropComments } from "./comments.js";
@@ -499,6 +499,16 @@ export function processDeclRules(ctx: DeclProcessingState): void {
499499
{ bailOnUnresolved: true },
500500
);
501501
if (result === "bail") {
502+
// Clear partially-processed entries from the firstBucket before
503+
// attempting the dynamic fallback. processDeclarationsIntoBucket may
504+
// have written some static declarations before encountering the
505+
// unresolvable interpolation that caused the bail. The fallback
506+
// re-processes ALL declarations itself, so stale entries in the
507+
// bucket would create duplicate outputs in finalizeRelationOverrides.
508+
for (const key of Object.keys(firstBucket)) {
509+
delete firstBucket[key];
510+
}
511+
502512
// Try dynamic style fallback before bailing: if the unresolved
503513
// interpolations are prop-based arrow functions, we can emit styleFn
504514
// entries with ancestor pseudo wrapping instead.
@@ -2069,10 +2079,11 @@ function tryDynamicRelationOverrideFallback(args: {
20692079
return false;
20702080
}
20712081

2072-
// Extract slots — only support single-slot interpolations for now
2073-
const parts: Array<{ kind?: string; slotId?: number }> = d.value.parts ?? [];
2082+
// Extract slots — only support single-slot interpolations for now.
2083+
// After the kind === "interpolated" check above, d.value is guaranteed to have parts.
2084+
const parts: CssValuePart[] = (d.value as { parts: CssValuePart[] }).parts;
20742085
const slotParts = parts.filter(
2075-
(p): p is { kind: "slot"; slotId: number } => p.kind === "slot" && p.slotId !== undefined,
2086+
(p): p is CssValuePart & { kind: "slot"; slotId: number } => p.kind === "slot",
20762087
);
20772088
if (slotParts.length !== 1) {
20782089
return false;
@@ -2148,16 +2159,12 @@ function tryDynamicRelationOverrideFallback(args: {
21482159
}
21492160

21502161
// Build { default: null, [stylex.when.ancestor(pseudo, marker?)]: paramExpr }
2151-
const pseudoEntries = ancestorPseudos.map((pseudo) => {
2152-
const ancestorKey = makeAncestorKeyExpr(j, pseudo, markerVarName);
2153-
return Object.assign(j.property("init", ancestorKey, j.identifier(outParamName)), {
2154-
computed: true,
2155-
});
2156-
});
2157-
const conditionalMap = j.objectExpression([
2158-
j.property("init", j.identifier("default"), j.literal(null)),
2159-
...pseudoEntries,
2160-
]);
2162+
const conditionalMap = buildAncestorPseudoMap(
2163+
j,
2164+
j.identifier(outParamName),
2165+
ancestorPseudos,
2166+
markerVarName,
2167+
);
21612168

21622169
const cssPropKeyNode = makeCssPropKey(j, out.prop);
21632170
const bodyProp = j.property("init", cssPropKeyNode, conditionalMap);

0 commit comments

Comments
 (0)