You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
199 lines
4.2 KiB
199 lines
4.2 KiB
// @flow
|
|
import {
|
|
transformExpressionWithStyles,
|
|
createTransformerMacro,
|
|
getSourceMap,
|
|
addImport
|
|
} from './utils'
|
|
|
|
export const transformCssCallExpression = ({
|
|
state,
|
|
babel,
|
|
path,
|
|
sourceMap,
|
|
annotateAsPure = true
|
|
}: {
|
|
state: *,
|
|
babel: *,
|
|
path: *,
|
|
sourceMap?: string,
|
|
annotateAsPure?: boolean
|
|
}) => {
|
|
let node = transformExpressionWithStyles({
|
|
babel,
|
|
state,
|
|
path,
|
|
shouldLabel: true,
|
|
sourceMap
|
|
})
|
|
if (node) {
|
|
path.replaceWith(node)
|
|
path.hoist()
|
|
} else if (annotateAsPure && path.isCallExpression()) {
|
|
path.addComment('leading', '#__PURE__')
|
|
}
|
|
}
|
|
|
|
export const transformCsslessArrayExpression = ({
|
|
state,
|
|
babel,
|
|
path
|
|
}: {
|
|
babel: *,
|
|
state: *,
|
|
path: *
|
|
}) => {
|
|
let t = babel.types
|
|
let expressionPath = path.get('value.expression')
|
|
let sourceMap =
|
|
state.emotionSourceMap && path.node.loc !== undefined
|
|
? getSourceMap(path.node.loc.start, state)
|
|
: ''
|
|
|
|
expressionPath.replaceWith(
|
|
t.callExpression(
|
|
// the name of this identifier doesn't really matter at all
|
|
// it'll never appear in generated code
|
|
t.identifier('___shouldNeverAppearCSS'),
|
|
path.node.value.expression.elements
|
|
)
|
|
)
|
|
|
|
transformCssCallExpression({
|
|
babel,
|
|
state,
|
|
path: expressionPath,
|
|
sourceMap,
|
|
annotateAsPure: false
|
|
})
|
|
|
|
if (t.isCallExpression(expressionPath)) {
|
|
expressionPath.replaceWith(t.arrayExpression(expressionPath.node.arguments))
|
|
}
|
|
}
|
|
|
|
export const transformCsslessObjectExpression = ({
|
|
state,
|
|
babel,
|
|
path,
|
|
cssImport
|
|
}: {
|
|
babel: *,
|
|
state: *,
|
|
path: *,
|
|
cssImport: { importSource: string, cssExport: string }
|
|
}) => {
|
|
let t = babel.types
|
|
let expressionPath = path.get('value.expression')
|
|
let sourceMap =
|
|
state.emotionSourceMap && path.node.loc !== undefined
|
|
? getSourceMap(path.node.loc.start, state)
|
|
: ''
|
|
|
|
expressionPath.replaceWith(
|
|
t.callExpression(
|
|
// the name of this identifier doesn't really matter at all
|
|
// it'll never appear in generated code
|
|
t.identifier('___shouldNeverAppearCSS'),
|
|
[path.node.value.expression]
|
|
)
|
|
)
|
|
|
|
transformCssCallExpression({
|
|
babel,
|
|
state,
|
|
path: expressionPath,
|
|
sourceMap
|
|
})
|
|
|
|
if (t.isCallExpression(expressionPath)) {
|
|
expressionPath
|
|
.get('callee')
|
|
.replaceWith(
|
|
addImport(state, cssImport.importSource, cssImport.cssExport, 'css')
|
|
)
|
|
}
|
|
}
|
|
|
|
let cssTransformer = ({
|
|
state,
|
|
babel,
|
|
reference
|
|
}: {
|
|
state: any,
|
|
babel: any,
|
|
reference: any
|
|
}) => {
|
|
transformCssCallExpression({ babel, state, path: reference.parentPath })
|
|
}
|
|
|
|
let globalTransformer = ({
|
|
state,
|
|
babel,
|
|
reference,
|
|
importSource,
|
|
options
|
|
}: {
|
|
state: any,
|
|
babel: any,
|
|
reference: any,
|
|
importSource: string,
|
|
options: { cssExport?: string }
|
|
}) => {
|
|
const t = babel.types
|
|
|
|
if (
|
|
!t.isJSXIdentifier(reference.node) ||
|
|
!t.isJSXOpeningElement(reference.parentPath.node)
|
|
) {
|
|
return
|
|
}
|
|
|
|
const stylesPropPath = reference.parentPath
|
|
.get('attributes')
|
|
.find(p => t.isJSXAttribute(p.node) && p.node.name.name === 'styles')
|
|
|
|
if (!stylesPropPath) {
|
|
return
|
|
}
|
|
|
|
if (t.isJSXExpressionContainer(stylesPropPath.node.value)) {
|
|
if (t.isArrayExpression(stylesPropPath.node.value.expression)) {
|
|
transformCsslessArrayExpression({
|
|
state,
|
|
babel,
|
|
path: stylesPropPath
|
|
})
|
|
} else if (t.isObjectExpression(stylesPropPath.node.value.expression)) {
|
|
transformCsslessObjectExpression({
|
|
state,
|
|
babel,
|
|
path: stylesPropPath,
|
|
cssImport:
|
|
options.cssExport !== undefined
|
|
? {
|
|
importSource,
|
|
cssExport: options.cssExport
|
|
}
|
|
: {
|
|
importSource: '@emotion/react',
|
|
cssExport: 'css'
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
export const transformers = {
|
|
// this is an empty function because this transformer is never called
|
|
// we don't run any transforms on `jsx` directly
|
|
// instead we use it as a hint to enable css prop optimization
|
|
jsx: () => {},
|
|
css: cssTransformer,
|
|
Global: globalTransformer
|
|
}
|
|
|
|
export default createTransformerMacro(transformers, {
|
|
importSource: '@emotion/react'
|
|
})
|