// @flow import { transformExpressionWithStyles, getStyledOptions, addImport, createTransformerMacro } from './utils' const getReferencedSpecifier = (path, specifierName) => { const specifiers = path.get('specifiers') return specifierName === 'default' ? specifiers.find(p => p.isImportDefaultSpecifier()) : specifiers.find(p => p.node.local.name === specifierName) } export let styledTransformer = ({ state, babel, path, importSource, reference, importSpecifierName, options: { styledBaseImport, isWeb } }: { state: Object, babel: Object, path: any, importSource: string, importSpecifierName: string, reference: Object, options: { styledBaseImport?: [string, string], isWeb: boolean } }) => { let t = babel.types let getStyledIdentifier = () => { if ( !styledBaseImport || (styledBaseImport[0] === importSource && styledBaseImport[1] === importSpecifierName) ) { return t.cloneNode(reference.node) } if (path.node) { const referencedSpecifier = getReferencedSpecifier( path, importSpecifierName ) if (referencedSpecifier) { referencedSpecifier.remove() } if (!path.get('specifiers').length) { path.remove() } } const [baseImportSource, baseSpecifierName] = styledBaseImport return addImport(state, baseImportSource, baseSpecifierName, 'styled') } let createStyledComponentPath = null if ( t.isMemberExpression(reference.parent) && reference.parent.computed === false ) { if ( // checks if the first character is lowercase // becasue we don't want to transform the member expression if // it's in primitives/native reference.parent.property.name.charCodeAt(0) > 96 ) { reference.parentPath.replaceWith( t.callExpression(getStyledIdentifier(), [ t.stringLiteral(reference.parent.property.name) ]) ) } else { reference.replaceWith(getStyledIdentifier()) } createStyledComponentPath = reference.parentPath } else if ( reference.parentPath && t.isCallExpression(reference.parentPath) && reference.parent.callee === reference.node ) { reference.replaceWith(getStyledIdentifier()) createStyledComponentPath = reference.parentPath } if (!createStyledComponentPath) { return } const styledCallLikeWithStylesPath = createStyledComponentPath.parentPath let node = transformExpressionWithStyles({ path: styledCallLikeWithStylesPath, state, babel, shouldLabel: false }) if (node && isWeb) { // we know the argument length will be 1 since that's the only time we will have a node since it will be static styledCallLikeWithStylesPath.node.arguments[0] = node } styledCallLikeWithStylesPath.addComment('leading', '#__PURE__') if (isWeb) { createStyledComponentPath.node.arguments[1] = getStyledOptions( t, createStyledComponentPath, state ) } } export let createStyledMacro = ({ importSource, originalImportSource = importSource, baseImportName = 'default', isWeb }: { importSource: string, originalImportSource?: string, baseImportName?: string, isWeb: boolean }) => createTransformerMacro( { default: [ styledTransformer, { styledBaseImport: [importSource, baseImportName], isWeb } ] }, { importSource: originalImportSource } )