Files
flights_web_raw/apps/angular/node_modules/babel-plugin-emotion/src/index.js
T

243 lines
7.6 KiB
JavaScript

// @flow
import { createEmotionMacro } from './emotion-macro'
import { createStyledMacro } from './styled-macro'
import cssMacro, { transformCssCallExpression } from './css-macro'
import { addNamed } from '@babel/helper-module-imports'
import nodePath from 'path'
import { getSourceMap, getStyledOptions } from './utils'
let webStyledMacro = createStyledMacro({
importPath: '@emotion/styled-base',
originalImportPath: '@emotion/styled',
isWeb: true
})
let nativeStyledMacro = createStyledMacro({
importPath: '@emotion/native',
originalImportPath: '@emotion/native',
isWeb: false
})
let primitivesStyledMacro = createStyledMacro({
importPath: '@emotion/primitives',
originalImportPath: '@emotion/primitives',
isWeb: false
})
export const macros = {
createEmotionMacro,
css: cssMacro,
createStyledMacro
}
export type BabelPath = any
export type EmotionBabelPluginPass = any
let emotionCoreMacroThatsNotARealMacro = ({ references, state, babel }) => {
Object.keys(references).forEach(refKey => {
if (refKey === 'css') {
references[refKey].forEach(path => {
transformCssCallExpression({ babel, state, path: path.parentPath })
})
}
})
}
emotionCoreMacroThatsNotARealMacro.keepImport = true
function getAbsolutePath(instancePath: string, rootPath: string) {
if (instancePath.charAt(0) === '.') {
let absoluteInstancePath = nodePath.resolve(rootPath, instancePath)
return absoluteInstancePath
}
return false
}
function getInstancePathToCompare(instancePath: string, rootPath: string) {
let absolutePath = getAbsolutePath(instancePath, rootPath)
if (absolutePath === false) {
return instancePath
}
return absolutePath
}
export default function(babel: *) {
let t = babel.types
return {
name: 'emotion',
inherits: require('babel-plugin-syntax-jsx'),
visitor: {
ImportDeclaration(path: *, state: *) {
const hasFilepath =
path.hub.file.opts.filename &&
path.hub.file.opts.filename !== 'unknown'
let dirname = hasFilepath
? nodePath.dirname(path.hub.file.opts.filename)
: ''
if (
!state.pluginMacros[path.node.source.value] &&
state.emotionInstancePaths.indexOf(
getInstancePathToCompare(path.node.source.value, dirname)
) !== -1
) {
state.pluginMacros[path.node.source.value] = createEmotionMacro(
path.node.source.value
)
}
let pluginMacros = state.pluginMacros
// most of this is from https://github.com/kentcdodds/babel-plugin-macros/blob/master/src/index.js
if (pluginMacros[path.node.source.value] === undefined) {
return
}
if (t.isImportNamespaceSpecifier(path.node.specifiers[0])) {
return
}
const imports = path.node.specifiers.map(s => ({
localName: s.local.name,
importedName:
s.type === 'ImportDefaultSpecifier' ? 'default' : s.imported.name
}))
let shouldExit = false
let hasReferences = false
const referencePathsByImportName = imports.reduce(
(byName, { importedName, localName }) => {
let binding = path.scope.getBinding(localName)
if (!binding) {
shouldExit = true
return byName
}
byName[importedName] = binding.referencePaths
hasReferences =
hasReferences || Boolean(byName[importedName].length)
return byName
},
{}
)
if (!hasReferences || shouldExit) {
return
}
/**
* Other plugins that run before babel-plugin-macros might use path.replace, where a path is
* put into its own replacement. Apparently babel does not update the scope after such
* an operation. As a remedy, the whole scope is traversed again with an empty "Identifier"
* visitor - this makes the problem go away.
*
* See: https://github.com/kentcdodds/import-all.macro/issues/7
*/
state.file.scope.path.traverse({
Identifier() {}
})
pluginMacros[path.node.source.value]({
references: referencePathsByImportName,
state,
babel,
isBabelMacrosCall: true,
isEmotionCall: true
})
if (!pluginMacros[path.node.source.value].keepImport) {
path.remove()
}
},
Program(path: *, state: *) {
state.emotionInstancePaths = (state.opts.instances || []).map(
instancePath => getInstancePathToCompare(instancePath, process.cwd())
)
state.pluginMacros = {
'@emotion/css': cssMacro,
'@emotion/styled': webStyledMacro,
'@emotion/core': emotionCoreMacroThatsNotARealMacro,
'@emotion/primitives': primitivesStyledMacro,
'@emotion/native': nativeStyledMacro,
emotion: createEmotionMacro('emotion')
}
if (state.opts.cssPropOptimization === undefined) {
for (const node of path.node.body) {
if (
t.isImportDeclaration(node) &&
node.source.value === '@emotion/core' &&
node.specifiers.some(
x => t.isImportSpecifier(x) && x.imported.name === 'jsx'
)
) {
state.transformCssProp = true
break
}
}
} else {
state.transformCssProp = state.opts.cssPropOptimization
}
if (state.opts.sourceMap === false) {
state.emotionSourceMap = false
} else {
state.emotionSourceMap = true
}
},
JSXAttribute(path: *, state: *) {
if (path.node.name.name !== 'css' || !state.transformCssProp) {
return
}
if (
t.isJSXExpressionContainer(path.node.value) &&
(t.isObjectExpression(path.node.value.expression) ||
t.isArrayExpression(path.node.value.expression))
) {
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)) {
if (!state.cssIdentifier) {
state.cssIdentifier = addNamed(path, 'css', '@emotion/core', {
nameHint: 'css'
})
}
expressionPath
.get('callee')
.replaceWith(t.cloneDeep(state.cssIdentifier))
}
}
},
CallExpression: {
exit(path: BabelPath, state: EmotionBabelPluginPass) {
try {
if (
path.node.callee &&
path.node.callee.property &&
path.node.callee.property.name === 'withComponent'
) {
switch (path.node.arguments.length) {
case 1:
case 2: {
path.node.arguments[1] = getStyledOptions(t, path, state)
}
}
}
} catch (e) {
throw path.buildCodeFrameError(e)
}
}
}
}
}
}