@@ -6,7 +6,7 @@ import type { JSCodeshift } from "jscodeshift";
66import type { SelectorResolveResult } from "../../adapter.js" ;
77import type { DeclProcessingState } from "./decl-setup.js" ;
88import type { StyledDecl } from "../transform-types.js" ;
9- import type { CssDeclarationIR } from "../css-ir.js" ;
9+ import type { CssDeclarationIR , CssValuePart } from "../css-ir.js" ;
1010import { computeSelectorWarningLoc } from "../css-ir.js" ;
1111import { cssDeclarationToStylexDeclarations } from "../css-prop-mapping.js" ;
1212import { 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