Skip to content

Commit 396f9bf

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 767b0ee commit 396f9bf

File tree

1 file changed

+21
-14
lines changed

1 file changed

+21
-14
lines changed

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";
@@ -539,6 +539,16 @@ export function processDeclRules(ctx: DeclProcessingState): void {
539539
{ bailOnUnresolved: true },
540540
);
541541
if (result === "bail") {
542+
// Clear partially-processed entries from the firstBucket before
543+
// attempting the dynamic fallback. processDeclarationsIntoBucket may
544+
// have written some static declarations before encountering the
545+
// unresolvable interpolation that caused the bail. The fallback
546+
// re-processes ALL declarations itself, so stale entries in the
547+
// bucket would create duplicate outputs in finalizeRelationOverrides.
548+
for (const key of Object.keys(firstBucket)) {
549+
delete firstBucket[key];
550+
}
551+
542552
// Try dynamic style fallback before bailing: if the unresolved
543553
// interpolations are prop-based arrow functions, we can emit styleFn
544554
// entries with ancestor pseudo wrapping instead.
@@ -2255,10 +2265,11 @@ function tryDynamicRelationOverrideFallback(args: {
22552265
return false;
22562266
}
22572267

2258-
// Extract slots — only support single-slot interpolations for now
2259-
const parts: Array<{ kind?: string; slotId?: number }> = d.value.parts ?? [];
2268+
// Extract slots — only support single-slot interpolations for now.
2269+
// After the kind === "interpolated" check above, d.value is guaranteed to have parts.
2270+
const parts: CssValuePart[] = (d.value as { parts: CssValuePart[] }).parts;
22602271
const slotParts = parts.filter(
2261-
(p): p is { kind: "slot"; slotId: number } => p.kind === "slot" && p.slotId !== undefined,
2272+
(p): p is CssValuePart & { kind: "slot"; slotId: number } => p.kind === "slot",
22622273
);
22632274
if (slotParts.length !== 1) {
22642275
return false;
@@ -2334,16 +2345,12 @@ function tryDynamicRelationOverrideFallback(args: {
23342345
}
23352346

23362347
// Build { default: null, [stylex.when.ancestor(pseudo, marker?)]: paramExpr }
2337-
const pseudoEntries = ancestorPseudos.map((pseudo) => {
2338-
const ancestorKey = makeAncestorKeyExpr(j, pseudo, markerVarName);
2339-
return Object.assign(j.property("init", ancestorKey, j.identifier(outParamName)), {
2340-
computed: true,
2341-
});
2342-
});
2343-
const conditionalMap = j.objectExpression([
2344-
j.property("init", j.identifier("default"), j.literal(null)),
2345-
...pseudoEntries,
2346-
]);
2348+
const conditionalMap = buildAncestorPseudoMap(
2349+
j,
2350+
j.identifier(outParamName),
2351+
ancestorPseudos,
2352+
markerVarName,
2353+
);
23472354

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

0 commit comments

Comments
 (0)