import generate from '@babel/generator' ; import template from '@babel/template' ; import * as t from '@babel/types' ; import { unique } from '@compiled/utils' ; import type { Metadata } from '../types' ; import { buildCssVariables } from './build-css-variables' ; import { getJSXAttribute } from './get-jsx-attribute' ; import { hoistSheet } from './hoist-sheet' ; import { transformCssItems } from './transform-css-items' ; import type { CSSOutput } from './types' ; param node param sheets { string [ ] } param meta { Metadata } export const compiledTemplate = ( node , sheets , meta ) : t . Node => { const nonceAttribute = meta . state . opts . nonce ? `nonce={${ meta . state . opts . nonce }}` : '' ; const [ keyAttribute ] = getJSXAttribute ( node , 'key' ) ; return template ( `
  <CC ${ keyAttribute ? generate ( keyAttribute ) . code : '' }>
    <CS ${ nonceAttribute }>{%%cssNode%%}</CS>
    {%%jsxNode%%}
  </CC>
  ` , { plugins : [ 'jsx' ] , } ) ( { jsxNode : node , cssNode : t . arrayExpression ( unique ( sheets ) . map ( ( sheet ) => hoistSheet ( sheet , meta ) ) ) , } ) as t . Node ; } ; param node const getExpression = ( node ) : t . Expression => { const value = t . isJSXExpressionContainer ( node ) ? node . expression : node ; if ( t . isJSXEmptyExpression ( value ) ) { throw new Error ( 'Empty expression not supported.' ) ; } return value ; } ; param node param cssOutput param meta { Metadata } export const buildCompiledComponent = ( node , cssOutput , meta ) : t . Node => { const { sheets , classNames } = transformCssItems ( cssOutput . css ) ; const [ classNameAttribute ] = getJSXAttribute ( node , 'className' ) ; if ( classNameAttribute && classNameAttribute . value ) { const classNameExpression = getExpression ( classNameAttribute . value ) ; const values = classNames . concat ( classNameExpression ) ; classNameAttribute . value = t . jsxExpressionContainer ( t . callExpression ( t . identifier ( 'ax' ) , [ t . arrayExpression ( values ) ] ) ) ; } else { node . openingElement . attributes . push ( t . jsxAttribute ( t . jsxIdentifier ( 'className' ) , t . jsxExpressionContainer ( t . callExpression ( t . identifier ( 'ax' ) , [ t . arrayExpression ( classNames ) ] ) ) ) ) ; } if ( cssOutput . variables . length ) { const [ styleAttribute , styleAttributeIndex ] = getJSXAttribute ( node , 'style' ) ; const dynamicStyleProperties = buildCssVariables ( cssOutput . variables ) ; if ( styleAttribute ) { node . openingElement . attributes . splice ( styleAttributeIndex , 1 ) ; if ( styleAttribute . value && t . isJSXExpressionContainer ( styleAttribute . value ) && ! t . isJSXEmptyExpression ( styleAttribute . value . expression ) ) { if ( ! t . isObjectExpression ( styleAttribute . value . expression ) ) { dynamicStyleProperties . splice ( 0 , 0 , t . spreadElement ( styleAttribute . value . expression ) ) ; } else { styleAttribute . value . expression . properties . forEach ( ( prop , index ) => { if ( t . isObjectMethod ( prop ) ) { return ; } dynamicStyleProperties . splice ( index , 0 , prop ) ; } ) ; } } } node . openingElement . attributes . push ( t . jsxAttribute ( t . jsxIdentifier ( 'style' ) , t . jsxExpressionContainer ( t . objectExpression ( dynamicStyleProperties ) ) ) ) ; } return compiledTemplate ( node , sheets , meta ) ; } ;