@@ -56,7 +56,7 @@ export function collectStyledDecls(args: {
5656
5757 const fillFromObject = ( obj : any ) => {
5858 for ( const prop of obj . properties ?? [ ] ) {
59- if ( ! prop || prop . type !== "ObjectProperty" ) {
59+ if ( ! prop || ( prop . type !== "ObjectProperty" && prop . type !== "Property" ) ) {
6060 continue ;
6161 }
6262 const key =
@@ -131,7 +131,7 @@ export function collectStyledDecls(args: {
131131 return undefined ;
132132 }
133133 const prop = ( arg0 . properties ?? [ ] ) . find ( ( p : any ) => {
134- if ( ! p || p . type !== "ObjectProperty" ) {
134+ if ( ! p || ( p . type !== "ObjectProperty" && p . type !== "Property" ) ) {
135135 return false ;
136136 }
137137 if ( p . key ?. type === "Identifier" ) {
@@ -251,10 +251,9 @@ export function collectStyledDecls(args: {
251251 if ( ! arg0 || arg0 . type !== "ObjectExpression" ) {
252252 return undefined ;
253253 }
254- let displayName : string | undefined ;
255254 let componentId : string | undefined ;
256255 for ( const p of arg0 . properties ?? [ ] ) {
257- if ( ! p || p . type !== "ObjectProperty" ) {
256+ if ( ! p || ( p . type !== "ObjectProperty" && p . type !== "Property" ) ) {
258257 continue ;
259258 }
260259 const key =
@@ -276,20 +275,83 @@ export function collectStyledDecls(args: {
276275 if ( ! val ) {
277276 continue ;
278277 }
279- if ( key === "displayName" ) {
280- displayName = val ;
281- }
282278 if ( key === "componentId" ) {
283279 componentId = val ;
284280 }
285281 }
286- if ( ! displayName && ! componentId ) {
282+ if ( ! componentId ) {
287283 return undefined ;
288284 }
289- return {
290- ...( displayName ? { displayName } : { } ) ,
291- ...( componentId ? { componentId } : { } ) ,
285+ return { componentId } ;
286+ } ;
287+
288+ /**
289+ * Unwrap TS generic instantiation wrappers and capture the first type argument, e.g.:
290+ * - styled.button<ButtonProps>`...`
291+ * - styled(Component)<CardProps>`...`
292+ *
293+ * Babel/Recast may represent this as:
294+ * - TSInstantiationExpression { expression, typeParameters }
295+ * - or an expression node with `.typeParameters` / `.typeArguments`
296+ */
297+ const unwrapTypeInstantiation = ( expr : any ) : { expr : any ; propsType : any } => {
298+ let cur = expr ;
299+ let propsType : any ;
300+
301+ const readFirstTypeArg = ( tp : any ) : any => {
302+ if ( ! tp ) {
303+ return undefined ;
304+ }
305+ const arr =
306+ ( Array . isArray ( tp . params ) ? tp . params : null ) ??
307+ ( Array . isArray ( tp . parameters ) ? tp . parameters : null ) ??
308+ ( Array . isArray ( tp . typeParameters ) ? tp . typeParameters : null ) ;
309+ return Array . isArray ( arr ) && arr . length > 0 ? arr [ 0 ] : undefined ;
292310 } ;
311+
312+ // Prefer TSInstantiationExpression wrapper (Babel)
313+ while ( cur && cur . type === "TSInstantiationExpression" ) {
314+ if ( ! propsType ) {
315+ propsType = readFirstTypeArg ( cur . typeParameters ) ;
316+ }
317+ cur = cur . expression ;
318+ }
319+
320+ // Some parsers attach type params directly to CallExpression/MemberExpression/etc.
321+ if ( ! propsType ) {
322+ propsType =
323+ readFirstTypeArg ( cur ?. typeParameters ) ?? readFirstTypeArg ( cur ?. typeArguments ) ?? undefined ;
324+ }
325+
326+ // If we consumed type params from a direct attachment, strip them from the expr so downstream
327+ // tag/callee matching is stable.
328+ if ( cur && ( cur . typeParameters || cur . typeArguments ) ) {
329+ try {
330+ delete cur . typeParameters ;
331+ delete cur . typeArguments ;
332+ } catch {
333+ // ignore (non-extensible nodes)
334+ }
335+ }
336+
337+ return { expr : cur , propsType } ;
338+ } ;
339+
340+ // Some parsers attach generic type args to the TaggedTemplateExpression itself.
341+ // (e.g. `styled.div.withConfig(...)<Props>\`...\`` where `<Props>` ends up on the tag wrapper.)
342+ const readFirstTypeArgFromNode = ( node : any ) : any => {
343+ if ( ! node ) {
344+ return undefined ;
345+ }
346+ const tp = ( node as any ) . typeParameters ?? ( node as any ) . typeArguments ?? undefined ;
347+ if ( ! tp ) {
348+ return undefined ;
349+ }
350+ const arr =
351+ ( Array . isArray ( tp . params ) ? tp . params : null ) ??
352+ ( Array . isArray ( tp . parameters ) ? tp . parameters : null ) ??
353+ ( Array . isArray ( tp . typeParameters ) ? tp . typeParameters : null ) ;
354+ return Array . isArray ( arr ) && arr . length > 0 ? arr [ 0 ] : undefined ;
293355 } ;
294356
295357 /**
@@ -391,7 +453,18 @@ export function collectStyledDecls(args: {
391453 const leadingComments = getLeadingComments ( p ) ;
392454 const placementHints = getPlacementHints ( p ) ;
393455
394- const tag = init . tag ;
456+ let { expr : tag , propsType } = unwrapTypeInstantiation ( init . tag ) ;
457+ if ( ! propsType ) {
458+ propsType = readFirstTypeArgFromNode ( init ) ;
459+ if ( propsType ) {
460+ try {
461+ delete ( init as any ) . typeParameters ;
462+ delete ( init as any ) . typeArguments ;
463+ } catch {
464+ // ignore
465+ }
466+ }
467+ }
395468 // styled.h1
396469 if (
397470 tag . type === "MemberExpression" &&
@@ -418,6 +491,7 @@ export function collectStyledDecls(args: {
418491 rules,
419492 templateExpressions : parsed . slots . map ( ( s ) => s . expression ) ,
420493 rawCss : parsed . rawCss ,
494+ ...( propsType ? { propsType } : { } ) ,
421495 ...( leadingComments ? { leadingComments } : { } ) ,
422496 } ) ;
423497 return ;
@@ -466,6 +540,7 @@ export function collectStyledDecls(args: {
466540 ...( attrsInfo ? { attrsInfo } : { } ) ,
467541 ...( shouldForwardProp ? { shouldForwardProp } : { } ) ,
468542 ...( withConfigMeta ? { withConfig : withConfigMeta } : { } ) ,
543+ ...( propsType ? { propsType } : { } ) ,
469544 ...( leadingComments ? { leadingComments } : { } ) ,
470545 } ) ;
471546 return ;
@@ -499,6 +574,7 @@ export function collectStyledDecls(args: {
499574 rules,
500575 templateExpressions : parsed . slots . map ( ( s ) => s . expression ) ,
501576 rawCss : parsed . rawCss ,
577+ ...( propsType ? { propsType } : { } ) ,
502578 ...( leadingComments ? { leadingComments } : { } ) ,
503579 } ) ;
504580 }
@@ -538,6 +614,7 @@ export function collectStyledDecls(args: {
538614 rawCss : parsed . rawCss ,
539615 ...( shouldForwardProp ? { shouldForwardProp } : { } ) ,
540616 ...( withConfigMeta ? { withConfig : withConfigMeta } : { } ) ,
617+ ...( propsType ? { propsType } : { } ) ,
541618 ...( leadingComments ? { leadingComments } : { } ) ,
542619 } ) ;
543620 }
@@ -580,6 +657,7 @@ export function collectStyledDecls(args: {
580657 rawCss : parsed . rawCss ,
581658 ...( shouldForwardProp ? { shouldForwardProp } : { } ) ,
582659 ...( withConfigMeta ? { withConfig : withConfigMeta } : { } ) ,
660+ ...( propsType ? { propsType } : { } ) ,
583661 ...( leadingComments ? { leadingComments } : { } ) ,
584662 } ) ;
585663 }
0 commit comments