babel-plugin-emotion
Advanced tools
Comparing version 8.0.12 to 9.0.0-0
@@ -9,3 +9,3 @@ 'use strict'; | ||
return interpolations.reduce(function (array, interp, i) { | ||
return array.concat(interp, strings[i + 1]); | ||
return array.concat([interp], strings[i + 1]); | ||
}, [strings[0]]); | ||
@@ -18,3 +18,3 @@ }; | ||
this.stringSrc = src; | ||
this.src = src; | ||
this.expressions = expressions || []; | ||
@@ -72,3 +72,5 @@ this.t = t; | ||
return interleave(strings, finalExpressions).filter(function (node) { | ||
return interleave(strings, finalExpressions).filter( | ||
// $FlowFixMe | ||
function (node) { | ||
return node.value !== ''; | ||
@@ -79,3 +81,3 @@ }); | ||
ASTObject.prototype.toExpressions = function toExpressions() { | ||
return this.replacePlaceholdersWithExpressions(this.getDynamicMatches(this.stringSrc), this.stringSrc); | ||
return this.replacePlaceholdersWithExpressions(this.getDynamicMatches(this.src), this.src); | ||
}; | ||
@@ -82,0 +84,0 @@ |
@@ -16,2 +16,3 @@ 'use strict'; | ||
function getDeclaratorName(path, t) { | ||
// $FlowFixMe | ||
var parent = path.findParent(function (p) { | ||
@@ -22,7 +23,10 @@ return p.isVariableDeclarator(); | ||
} | ||
function getIdentifierName(path, t) { | ||
var classParent = path.findParent(function (p) { | ||
return t.isClass(p); | ||
}); | ||
var classParent = void 0; | ||
if (path) { | ||
// $FlowFixMe | ||
classParent = path.findParent(function (p) { | ||
return t.isClass(p); | ||
}); | ||
} | ||
if (classParent && classParent.node.id) { | ||
@@ -38,2 +42,3 @@ return t.isIdentifier(classParent.node.id) ? classParent.node.id.name : ''; | ||
function getRuntimeImportPath(path, t) { | ||
// $FlowFixMe | ||
var binding = path.scope.getBinding(path.node.name); | ||
@@ -54,2 +59,3 @@ if (!t.isImportDeclaration(binding.path.parentPath)) { | ||
if (state.emotionImports[runtimeImportPath][importName] === undefined) { | ||
// $FlowFixMe | ||
state.emotionImports[runtimeImportPath][importName] = path.scope.generateUidIdentifier(path.node.name); | ||
@@ -61,16 +67,19 @@ } | ||
function addRuntimeImports(state, t) { | ||
if (state.emotionImports === undefined) return; | ||
Object.keys(state.emotionImports).forEach(function (importPath) { | ||
var importSpecifiers = []; | ||
Object.keys(state.emotionImports[importPath]).forEach(function (importName) { | ||
var identifier = state.emotionImports[importPath][importName]; | ||
if (importName === 'default') { | ||
importSpecifiers.push(t.importDefaultSpecifier(identifier)); | ||
} else { | ||
importSpecifiers.push(t.importSpecifier(identifier, t.identifier(importName))); | ||
} | ||
if (state.emotionImports) { | ||
var _emotionImports = state.emotionImports; | ||
Object.keys(_emotionImports).forEach(function (importPath) { | ||
var importSpecifiers = []; | ||
Object.keys(_emotionImports[importPath]).forEach(function (importName) { | ||
var identifier = _emotionImports[importPath][importName]; | ||
if (importName === 'default') { | ||
importSpecifiers.push(t.importDefaultSpecifier(identifier)); | ||
} else { | ||
importSpecifiers.push(t.importSpecifier(identifier, t.identifier(importName))); | ||
} | ||
}); | ||
// $FlowFixMe | ||
state.file.path.node.body.unshift(t.importDeclaration(importSpecifiers, t.stringLiteral(importPath))); | ||
}); | ||
state.file.path.node.body.unshift(t.importDeclaration(importSpecifiers, t.stringLiteral(importPath))); | ||
}); | ||
state.emotionImports = undefined; | ||
state.emotionImports = undefined; | ||
} | ||
} | ||
@@ -77,0 +86,0 @@ function getName(identifierName, prefix) { |
@@ -54,12 +54,14 @@ 'use strict'; | ||
cssPath.parentPath.remove(); | ||
if (t.isJSXExpressionContainer(classNamesValue)) { | ||
var _args = [add(cssTemplateExpression, add(t.stringLiteral(' '), classNamesValue.expression))]; | ||
if (classNamesPath && classNamesPath.parentPath) { | ||
if (t.isJSXExpressionContainer(classNamesValue)) { | ||
var _args = [add(cssTemplateExpression, add(t.stringLiteral(' '), classNamesValue.expression))]; | ||
if (state.opts.sourceMap) { | ||
_args.push(t.stringLiteral((0, _sourceMap.addSourceMaps)(cssPath.node.loc.start, state))); | ||
if (state.opts.sourceMap) { | ||
_args.push(t.stringLiteral((0, _sourceMap.addSourceMaps)(cssPath.node.loc.start, state))); | ||
} | ||
classNamesPath.parentPath.replaceWith(createClassNameAttr(t.callExpression(getMergeIdentifier(), _args))); | ||
} else { | ||
classNamesPath.parentPath.replaceWith(createClassNameAttr(add(cssTemplateExpression, t.stringLiteral(' ' + (classNamesValue.value || ''))))); | ||
} | ||
classNamesPath.parentPath.replaceWith(createClassNameAttr(t.callExpression(getMergeIdentifier(), _args))); | ||
} else { | ||
classNamesPath.parentPath.replaceWith(createClassNameAttr(add(cssTemplateExpression, t.stringLiteral(' ' + (classNamesValue.value || ''))))); | ||
} | ||
@@ -72,3 +74,3 @@ | ||
function createClassNameAttr(expression) { | ||
return t.jSXAttribute(t.jSXIdentifier('className'), t.JSXExpressionContainer(expression)); | ||
return t.jSXAttribute(t.jSXIdentifier('className'), t.jSXExpressionContainer(expression)); | ||
} | ||
@@ -78,3 +80,3 @@ | ||
if (state.opts.autoImportCssProp !== false) { | ||
var cssImport = (0, _helperModuleImports.addNamed)(path, 'css', 'emotion'); | ||
var cssImport = (0, _helperModuleImports.addNamed)(path, 'css', state.emotionImportPath); | ||
state.cssPropIdentifiers.push(cssImport); | ||
@@ -88,3 +90,3 @@ return cssImport; | ||
if (state.opts.autoImportCssProp !== false) { | ||
return (0, _helperModuleImports.addNamed)(path, 'merge', 'emotion'); | ||
return (0, _helperModuleImports.addNamed)(path, 'merge', state.emotionImportPath); | ||
} else { | ||
@@ -91,0 +93,0 @@ return t.identifier(state.importedNames.merge); |
135
lib/index.js
@@ -5,5 +5,4 @@ 'use strict'; | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; // weak | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
exports.hashArray = hashArray; | ||
@@ -25,2 +24,8 @@ exports.hoistPureArgs = hoistPureArgs; | ||
enter: function enter(path, state) { | ||
var hasFilepath = path.hub.file.opts.filename && path.hub.file.opts.filename !== 'unknown'; | ||
state.emotionImportPath = 'emotion'; | ||
if (state.opts.primaryInstance !== undefined) { | ||
state.emotionImportPath = getInstancePathToImport(state.opts.primaryInstance, path.hub.file.opts.filename); | ||
} | ||
state.importedNames = _extends({}, defaultImportedNames, state.opts.importedNames); | ||
@@ -44,5 +49,5 @@ | ||
var node = _ref; | ||
var _node = _ref; | ||
if (t.isModuleDeclaration(node)) { | ||
if (t.isModuleDeclaration(_node)) { | ||
isModule = true; | ||
@@ -108,3 +113,6 @@ break; | ||
} | ||
var emotionPaths = defaultEmotionPaths.concat((state.opts.instances || []).map(function (instancePath) { | ||
return getInstancePathToCompare(instancePath, process.cwd()); | ||
})); | ||
var dirname = hasFilepath ? _path2.default.dirname(path.hub.file.opts.filename) : ''; | ||
imports.forEach(function (_ref3) { | ||
@@ -115,5 +123,5 @@ var source = _ref3.source, | ||
if (source.indexOf('emotion') !== -1) { | ||
var importedNames = specifiers.filter(function (v) { | ||
return ['default', 'css', 'keyframes', 'injectGlobal', 'fontFace', 'merge'].indexOf(v.imported) !== -1; | ||
if (emotionPaths.indexOf(getInstancePathToCompare(source, dirname)) !== -1) { | ||
var _importedNames = specifiers.filter(function (v) { | ||
return importedNameKeys.indexOf(v.imported) !== -1; | ||
}).reduce(function (acc, _ref4) { | ||
@@ -126,3 +134,3 @@ var _extends2; | ||
}, defaultImportedNames); | ||
state.importedNames = _extends({}, importedNames, state.opts.importedNames); | ||
state.importedNames = _extends({}, _importedNames, state.opts.importedNames); | ||
} | ||
@@ -151,3 +159,3 @@ }); | ||
var exists = _fs2.default.existsSync(cssFilename); | ||
(0, _helperModuleImports.addSideEffect)(path, './' + (0, _path.basename)(cssFilename)); | ||
(0, _helperModuleImports.addSideEffect)(path, './' + _path2.default.basename(cssFilename)); | ||
if (exists ? _fs2.default.readFileSync(cssFilename, 'utf8') !== toWrite : true) { | ||
@@ -177,2 +185,3 @@ if (!exists) { | ||
enter: function enter(path, state) { | ||
// $FlowFixMe | ||
if (path[visited]) { | ||
@@ -197,3 +206,2 @@ return; | ||
case state.importedNames.injectGlobal: | ||
case state.importedNames.fontFace: | ||
if (state.opts.sourceMap === true && path.node.loc !== undefined) { | ||
@@ -216,3 +224,3 @@ path.node.arguments.push(t.stringLiteral((0, _sourceMap.addSourceMaps)(path.node.loc.start, state))); | ||
} | ||
// $FlowFixMe | ||
path[visited] = true; | ||
@@ -233,5 +241,7 @@ }, | ||
TaggedTemplateExpression: function TaggedTemplateExpression(path, state) { | ||
// $FlowFixMe | ||
if (path[visited]) { | ||
return; | ||
} | ||
// $FlowFixMe | ||
path[visited] = true; | ||
@@ -255,6 +265,2 @@ if ( | ||
}); | ||
} else if (path.node.tag.name === state.importedNames.fontFace) { | ||
replaceCssWithCallExpression(path, path.node.tag, state, t, function (src, name, hash) { | ||
return '@font-face {' + src + '}'; | ||
}, true); | ||
} else if (path.node.tag.name === state.importedNames.injectGlobal) { | ||
@@ -275,2 +281,6 @@ replaceCssWithCallExpression(path, path.node.tag, state, t, undefined, true, function () { | ||
var _path = require('path'); | ||
var _path2 = _interopRequireDefault(_path); | ||
var _findRoot = require('find-root'); | ||
@@ -280,4 +290,2 @@ | ||
var _path = require('path'); | ||
var _touch = require('touch'); | ||
@@ -332,13 +340,13 @@ | ||
var _createRawStringFromT = (0, _babelUtils.createRawStringFromTemplateLiteral)(path.node.quasi), | ||
hash = _createRawStringFromT.hash, | ||
src = _createRawStringFromT.src; | ||
_hash = _createRawStringFromT.hash, | ||
_src = _createRawStringFromT.src; | ||
var identifierName = (0, _babelUtils.getIdentifierName)(path, t); | ||
var name = (0, _babelUtils.getName)(identifierName, 'css'); | ||
var _name = (0, _babelUtils.getName)(identifierName, 'css'); | ||
if (state.extractStatic && !path.node.quasi.expressions.length) { | ||
var staticCSSRules = staticStylis(staticCSSSelectorCreator(name, hash), staticCSSSrcCreator(src, name, hash)); | ||
var staticCSSRules = staticStylis(staticCSSSelectorCreator(_name, _hash), staticCSSSrcCreator(_src, _name, _hash)); | ||
state.insertStaticRules([staticCSSRules]); | ||
if (!removePath) { | ||
return path.replaceWith(t.stringLiteral(name + '-' + hash)); | ||
return path.replaceWith(t.stringLiteral(_name + '-' + _hash)); | ||
} | ||
@@ -352,6 +360,6 @@ return path.replaceWith(t.identifier('undefined')); | ||
if (state.opts.sourceMap === true && path.node.quasi.loc !== undefined) { | ||
src += (0, _sourceMap.addSourceMaps)(path.node.quasi.loc.start, state); | ||
_src += (0, _sourceMap.addSourceMaps)(path.node.quasi.loc.start, state); | ||
} | ||
path.replaceWith(t.callExpression(identifier, new _astObject2.default((0, _babelUtils.minify)(src), path.node.quasi.expressions, t).toExpressions().concat(state.opts.autoLabel && identifierName ? [t.stringLiteral('label:' + identifierName.trim() + ';')] : []))); | ||
path.replaceWith(t.callExpression(identifier, new _astObject2.default((0, _babelUtils.minify)(_src), path.node.quasi.expressions, t).toExpressions().concat(state.opts.autoLabel && identifierName ? [t.stringLiteral('label:' + identifierName.trim() + ';')] : []))); | ||
@@ -372,2 +380,4 @@ if (state.opts.hoist) { | ||
var unsafeRequire = require; | ||
var getPackageRootPath = (0, _emotionUtils.memoize)(function (filename) { | ||
@@ -391,13 +401,21 @@ return (0, _findRoot2.default)(filename); | ||
rootPath = getPackageRootPath(filename); | ||
moduleName = require(rootPath + '/package.json').name; | ||
moduleName = unsafeRequire(rootPath + '/package.json').name; | ||
} catch (err) {} | ||
var finalPath = filename === rootPath ? (0, _path.basename)(filename) : filename.slice(rootPath.length); | ||
var finalPath = filename === rootPath ? _path2.default.basename(filename) : filename.slice(rootPath.length); | ||
var positionInFile = state.count++; | ||
var stableClassName = (0, _babelUtils.getName)('' + hashArray([(0, _path.normalize)(finalPath), moduleName, state.file.code]) + positionInFile, 'css'); | ||
var stuffToHash = [moduleName]; | ||
if (finalPath) { | ||
stuffToHash.push(_path2.default.normalize(finalPath)); | ||
} else { | ||
stuffToHash.push(state.file.code); | ||
} | ||
var stableClassName = 'e' + hashArray(stuffToHash) + positionInFile; | ||
return t.objectProperty(t.identifier('target'), t.stringLiteral(stableClassName)); | ||
} | ||
function buildStyledCallExpression(identifier, tag, path, state, t) { | ||
@@ -409,9 +427,8 @@ var identifierName = (0, _babelUtils.getIdentifierName)(path, t); | ||
if (state.extractStatic && !path.node.quasi.expressions.length) { | ||
var _createRawStringFromT2 = (0, _babelUtils.createRawStringFromTemplateLiteral)(path.node.quasi, identifierName, 'styled' // we don't want these styles to be merged in css`` | ||
), | ||
hash = _createRawStringFromT2.hash, | ||
_src = _createRawStringFromT2.src; | ||
var _createRawStringFromT2 = (0, _babelUtils.createRawStringFromTemplateLiteral)(path.node.quasi), | ||
_hash2 = _createRawStringFromT2.hash, | ||
_src2 = _createRawStringFromT2.src; | ||
var staticClassName = (0, _babelUtils.getName)(hash, 'css'); | ||
var staticCSSRules = staticStylis('.' + staticClassName, _src); | ||
var staticClassName = 'css-' + _hash2; | ||
var staticCSSRules = staticStylis('.' + staticClassName, _src2); | ||
@@ -442,2 +459,3 @@ state.insertStaticRules([staticCSSRules]); | ||
function buildStyledObjectCallExpression(path, state, identifier, t) { | ||
var targetProperty = buildTargetObjectProperty(path, state, t); | ||
var identifierName = (0, _babelUtils.getIdentifierName)(path, t); | ||
@@ -451,5 +469,11 @@ var tag = t.isCallExpression(path.node.callee) ? path.node.callee.arguments[0] : t.stringLiteral(path.node.callee.property.name); | ||
var objectProperties = [targetProperty]; | ||
if (state.opts.autoLabel && identifierName) { | ||
objectProperties.push(t.objectProperty(t.identifier('label'), t.stringLiteral(identifierName.trim()))); | ||
} | ||
path.addComment('leading', '#__PURE__'); | ||
return t.callExpression(t.callExpression(identifier, state.opts.autoLabel && identifierName ? [tag, t.objectExpression([t.objectProperty(t.identifier('label'), t.stringLiteral(identifierName.trim()))])] : [tag]), args); | ||
return t.callExpression(t.callExpression(identifier, [tag, t.objectExpression(objectProperties)]), args); | ||
} | ||
@@ -464,4 +488,39 @@ | ||
injectGlobal: 'injectGlobal', | ||
fontFace: 'fontFace', | ||
merge: 'merge' | ||
}; | ||
}; | ||
var importedNameKeys = Object.keys(defaultImportedNames).map(function (key) { | ||
return key === 'styled' ? 'default' : key; | ||
}); | ||
var defaultEmotionPaths = ['emotion', 'react-emotion', 'preact-emotion']; | ||
function getRelativePath(filepath, absoluteInstancePath) { | ||
var relativePath = _path2.default.relative(_path2.default.dirname(filepath), absoluteInstancePath); | ||
return relativePath.charAt(0) === '.' ? relativePath : './' + relativePath; | ||
} | ||
function getAbsolutePath(instancePath, rootPath) { | ||
if (instancePath.charAt(0) === '.') { | ||
var absoluteInstancePath = _path2.default.resolve(rootPath, instancePath); | ||
return absoluteInstancePath; | ||
} | ||
return false; | ||
} | ||
function getInstancePathToImport(instancePath, filepath) { | ||
var absolutePath = getAbsolutePath(instancePath, process.cwd()); | ||
if (absolutePath === false) { | ||
return instancePath; | ||
} | ||
return getRelativePath(filepath, absolutePath); | ||
} | ||
function getInstancePathToCompare(instancePath, rootPath) { | ||
var absolutePath = getAbsolutePath(instancePath, rootPath); | ||
if (absolutePath === false) { | ||
return instancePath; | ||
} | ||
return absolutePath; | ||
} |
@@ -11,2 +11,3 @@ 'use strict'; | ||
function macro(_ref) { | ||
@@ -21,3 +22,2 @@ var references = _ref.references, | ||
case 'injectGlobal': | ||
case 'fontFace': | ||
{ | ||
@@ -24,0 +24,0 @@ isPure = false; |
{ | ||
"name": "babel-plugin-emotion", | ||
"version": "8.0.12", | ||
"version": "9.0.0-0", | ||
"description": "A recommended babel preprocessing plugin for emotion, The Next Generation of CSS-in-JS.", | ||
@@ -21,3 +21,3 @@ "main": "lib/index.js", | ||
"convert-source-map": "^1.5.0", | ||
"emotion-utils": "^8.0.12", | ||
"emotion-utils": "^9.0.0-0", | ||
"find-root": "^1.1.0", | ||
@@ -34,5 +34,5 @@ "source-map": "^0.5.7", | ||
"author": "Kye Hohenberger", | ||
"homepage": "https://github.com/tkh44/emotion#readme", | ||
"homepage": "https://emotion.sh", | ||
"license": "MIT", | ||
"repository": "https://github.com/tkh44/emotion/tree/master/packages/babel-plugin-emotion", | ||
"repository": "https://github.com/emotion-js/emotion/tree/master/packages/babel-plugin-emotion", | ||
"keywords": [ | ||
@@ -46,4 +46,4 @@ "styles", | ||
"bugs": { | ||
"url": "https://github.com/tkh44/emotion/issues" | ||
"url": "https://github.com/emotion-js/emotion/issues" | ||
} | ||
} |
@@ -261,1 +261,27 @@ # babel-plugin-emotion | ||
### `instances` | ||
`Array<string>`, defaults to | ||
`['emotion', 'react-emotion', 'preact-emotion']` | ||
This option allows `babel-plugin-emotion` to know which imports to treat as emotion imports and transform as such. This option is **only** required if you use a custom instance of emotion created with `create-emotion` or you're importing emotion from somewhere other than the paths above. Relative paths are resolved relative to `process.cwd()`(the current working directory). | ||
[**Documentation**](docs/instances.md) | ||
### `primaryInstance` | ||
`string`, defaults to | ||
`'emotion'` | ||
This option allows `babel-plugin-emotion` to know where to import emotion from when it needs to import emotion. Currently this is only used for the css prop to import `css` and `merge` but it could be used for other purposes in the future so it's recommend to make sure that this instance exports everything returned from `createEmotion`, [an up-to-date example of this can be seen in the emotion package's source](https://github.com/emotion-js/emotion/blob/master/packages/emotion/src/index.js). | ||
[**Documentation**](docs/instances.md) | ||
@@ -1,4 +0,9 @@ | ||
const interleave = (strings, interpolations) => | ||
// @flow | ||
import type { Types, Expression, StringLiteral } from 'babel-flow-types' | ||
const interleave = ( | ||
strings: Array<StringLiteral>, | ||
interpolations: Array<Expression> | ||
) => | ||
interpolations.reduce( | ||
(array, interp, i) => array.concat(interp, strings[i + 1]), | ||
(array, interp, i) => array.concat([interp], strings[i + 1]), | ||
[strings[0]] | ||
@@ -8,13 +13,12 @@ ) | ||
export default class ASTObject { | ||
props: Array<any> | ||
expressions: Array<any> | ||
composesCount: number | ||
expressions: Array<Expression> | ||
t: any | ||
src: string | ||
constructor(src, expressions, t) { | ||
this.stringSrc = src | ||
constructor(src: string, expressions: Array<Expression>, t: Types) { | ||
this.src = src | ||
this.expressions = expressions || [] | ||
this.t = t | ||
} | ||
getDynamicMatches(str) { | ||
getDynamicMatches(str: string) { | ||
const re = /xxx(\d+)xxx/gm | ||
@@ -62,3 +66,6 @@ let match | ||
return interleave(strings, finalExpressions).filter( | ||
node => node.value !== '' | ||
// $FlowFixMe | ||
(node: StringLiteral) => { | ||
return node.value !== '' | ||
} | ||
) | ||
@@ -68,6 +75,6 @@ } | ||
return this.replacePlaceholdersWithExpressions( | ||
this.getDynamicMatches(this.stringSrc), | ||
this.stringSrc | ||
this.getDynamicMatches(this.src), | ||
this.src | ||
) | ||
} | ||
} |
@@ -0,4 +1,8 @@ | ||
// @flow | ||
import { hashArray } from './index' | ||
import type { BabelPath, EmotionBabelPluginPass } from './index' | ||
import type { Types, Identifier } from 'babel-flow-types' | ||
function getDeclaratorName(path, t) { | ||
function getDeclaratorName(path: BabelPath, t: Types) { | ||
// $FlowFixMe | ||
const parent = path.findParent(p => p.isVariableDeclarator()) | ||
@@ -8,4 +12,8 @@ return parent && t.isIdentifier(parent.node.id) ? parent.node.id.name : '' | ||
export function getIdentifierName(path, t) { | ||
const classParent = path.findParent(p => t.isClass(p)) | ||
export function getIdentifierName(path: BabelPath, t: Types) { | ||
let classParent | ||
if (path) { | ||
// $FlowFixMe | ||
classParent = path.findParent(p => t.isClass(p)) | ||
} | ||
if (classParent && classParent.node.id) { | ||
@@ -24,3 +32,4 @@ return t.isIdentifier(classParent.node.id) ? classParent.node.id.name : '' | ||
export function getRuntimeImportPath(path, t) { | ||
export function getRuntimeImportPath(path: BabelPath, t: Types) { | ||
// $FlowFixMe | ||
const binding = path.scope.getBinding(path.node.name) | ||
@@ -36,3 +45,16 @@ if (!t.isImportDeclaration(binding.path.parentPath)) { | ||
export function buildMacroRuntimeNode(path, state, importName, t) { | ||
type EmotionMacroPluginPass = EmotionBabelPluginPass & { | ||
emotionImports: void | { | ||
[key: string]: { | ||
[key: string]: Identifier | ||
} | ||
} | ||
} | ||
export function buildMacroRuntimeNode( | ||
path: BabelPath, | ||
state: EmotionMacroPluginPass, | ||
importName: string, | ||
t: Types | ||
) { | ||
const runtimeImportPath = getRuntimeImportPath(path, t) | ||
@@ -44,2 +66,3 @@ if (state.emotionImports === undefined) state.emotionImports = {} | ||
if (state.emotionImports[runtimeImportPath][importName] === undefined) { | ||
// $FlowFixMe | ||
state.emotionImports[runtimeImportPath][ | ||
@@ -52,23 +75,26 @@ importName | ||
export function addRuntimeImports(state, t) { | ||
if (state.emotionImports === undefined) return | ||
Object.keys(state.emotionImports).forEach(importPath => { | ||
const importSpecifiers = [] | ||
Object.keys(state.emotionImports[importPath]).forEach(importName => { | ||
const identifier = state.emotionImports[importPath][importName] | ||
if (importName === 'default') { | ||
importSpecifiers.push(t.importDefaultSpecifier(identifier)) | ||
} else { | ||
importSpecifiers.push( | ||
t.importSpecifier(identifier, t.identifier(importName)) | ||
) | ||
} | ||
export function addRuntimeImports(state: EmotionMacroPluginPass, t: Types) { | ||
if (state.emotionImports) { | ||
const emotionImports = state.emotionImports | ||
Object.keys(emotionImports).forEach(importPath => { | ||
const importSpecifiers = [] | ||
Object.keys(emotionImports[importPath]).forEach(importName => { | ||
const identifier = emotionImports[importPath][importName] | ||
if (importName === 'default') { | ||
importSpecifiers.push(t.importDefaultSpecifier(identifier)) | ||
} else { | ||
importSpecifiers.push( | ||
t.importSpecifier(identifier, t.identifier(importName)) | ||
) | ||
} | ||
}) | ||
// $FlowFixMe | ||
state.file.path.node.body.unshift( | ||
t.importDeclaration(importSpecifiers, t.stringLiteral(importPath)) | ||
) | ||
}) | ||
state.file.path.node.body.unshift( | ||
t.importDeclaration(importSpecifiers, t.stringLiteral(importPath)) | ||
) | ||
}) | ||
state.emotionImports = undefined | ||
state.emotionImports = undefined | ||
} | ||
} | ||
export function getName(identifierName?: string, prefix: string): string { | ||
export function getName(identifierName?: string, prefix: string) { | ||
const parts = [] | ||
@@ -84,3 +110,3 @@ parts.push(prefix) | ||
quasis: Array<{ value: { cooked: string } }> | ||
}): { src: string, dynamicValueCount: number } { | ||
}) { | ||
let strs = quasi.quasis.map(x => x.value.cooked) | ||
@@ -124,3 +150,3 @@ let hash = hashArray([...strs]) | ||
export const minify = code => | ||
export const minify = (code: string) => | ||
code.split(symbolRegex).reduce((str, fragment, index) => { | ||
@@ -127,0 +153,0 @@ // Even-indices are non-symbol fragments |
@@ -0,5 +1,12 @@ | ||
// @flow | ||
import { addNamed } from '@babel/helper-module-imports' | ||
import { addSourceMaps } from './source-map' | ||
import type { BabelPath, EmotionBabelPluginPass } from './index' | ||
import type { Types } from 'babel-flow-types' | ||
export default function(path, state, t) { | ||
export default function( | ||
path: BabelPath, | ||
state: EmotionBabelPluginPass, | ||
t: Types | ||
) { | ||
let cssPath | ||
@@ -69,26 +76,28 @@ let classNamesPath | ||
cssPath.parentPath.remove() | ||
if (t.isJSXExpressionContainer(classNamesValue)) { | ||
const args = [ | ||
add( | ||
cssTemplateExpression, | ||
add(t.stringLiteral(' '), classNamesValue.expression) | ||
) | ||
] | ||
if (state.opts.sourceMap) { | ||
args.push(t.stringLiteral(addSourceMaps(cssPath.node.loc.start, state))) | ||
} | ||
classNamesPath.parentPath.replaceWith( | ||
createClassNameAttr(t.callExpression(getMergeIdentifier(), args)) | ||
) | ||
} else { | ||
classNamesPath.parentPath.replaceWith( | ||
createClassNameAttr( | ||
if (classNamesPath && classNamesPath.parentPath) { | ||
if (t.isJSXExpressionContainer(classNamesValue)) { | ||
const args = [ | ||
add( | ||
cssTemplateExpression, | ||
t.stringLiteral(` ${classNamesValue.value || ''}`) | ||
add(t.stringLiteral(' '), classNamesValue.expression) | ||
) | ||
] | ||
if (state.opts.sourceMap) { | ||
args.push(t.stringLiteral(addSourceMaps(cssPath.node.loc.start, state))) | ||
} | ||
classNamesPath.parentPath.replaceWith( | ||
createClassNameAttr(t.callExpression(getMergeIdentifier(), args)) | ||
) | ||
) | ||
} else { | ||
classNamesPath.parentPath.replaceWith( | ||
createClassNameAttr( | ||
add( | ||
cssTemplateExpression, | ||
t.stringLiteral(` ${classNamesValue.value || ''}`) | ||
) | ||
) | ||
) | ||
} | ||
} | ||
@@ -103,3 +112,3 @@ | ||
t.jSXIdentifier('className'), | ||
t.JSXExpressionContainer(expression) | ||
t.jSXExpressionContainer(expression) | ||
) | ||
@@ -110,3 +119,3 @@ } | ||
if (state.opts.autoImportCssProp !== false) { | ||
const cssImport = addNamed(path, 'css', 'emotion') | ||
const cssImport = addNamed(path, 'css', state.emotionImportPath) | ||
state.cssPropIdentifiers.push(cssImport) | ||
@@ -120,3 +129,3 @@ return cssImport | ||
if (state.opts.autoImportCssProp !== false) { | ||
return addNamed(path, 'merge', 'emotion') | ||
return addNamed(path, 'merge', state.emotionImportPath) | ||
} else { | ||
@@ -123,0 +132,0 @@ return t.identifier(state.importedNames.merge) |
249
src/index.js
@@ -1,5 +0,5 @@ | ||
// @flow weak | ||
// @flow | ||
import fs from 'fs' | ||
import nodePath from 'path' | ||
import findRoot from 'find-root' | ||
import { basename, normalize } from 'path' | ||
import { touchSync } from 'touch' | ||
@@ -13,3 +13,10 @@ import { addSideEffect } from '@babel/helper-module-imports' | ||
} from './babel-utils' | ||
import type { | ||
BabelPath as _BabelPath, | ||
Identifier, | ||
BabelPluginPass, | ||
Types, | ||
StringLiteral, | ||
Babel | ||
} from 'babel-flow-types' | ||
import { hashString, Stylis, memoize } from 'emotion-utils' | ||
@@ -21,3 +28,7 @@ import { addSourceMaps } from './source-map' | ||
export function hashArray(arr) { | ||
export type BabelPath = _BabelPath & { | ||
node: * | ||
} | ||
export function hashArray(arr: Array<string>) { | ||
return hashString(arr.join('')) | ||
@@ -28,3 +39,3 @@ } | ||
export function hoistPureArgs(path) { | ||
export function hoistPureArgs(path: BabelPath) { | ||
const args = path.get('arguments') | ||
@@ -41,10 +52,36 @@ | ||
type ImportedNames = { | ||
css: string, | ||
keyframes: string, | ||
injectGlobal: string, | ||
styled: string, | ||
merge: string | ||
} | ||
export type EmotionBabelPluginPass = BabelPluginPass & { | ||
extractStatic: boolean, | ||
insertStaticRules: (rules: Array<string>) => void, | ||
emotionImportPath: string, | ||
staticRules: Array<string>, | ||
cssPropIdentifiers: Array<Identifier>, | ||
importedNames: ImportedNames, | ||
count: number, | ||
opts: any | ||
} | ||
export function replaceCssWithCallExpression( | ||
path, | ||
identifier, | ||
state, | ||
t, | ||
staticCSSSrcCreator = src => src, | ||
removePath = false, | ||
staticCSSSelectorCreator = (name, hash) => `.${name}-${hash}` | ||
path: BabelPath, | ||
identifier: Identifier, | ||
state: EmotionBabelPluginPass, | ||
t: Types, | ||
staticCSSSrcCreator: ( | ||
src: string, | ||
name: string, | ||
hash: string | ||
) => string = src => src, | ||
removePath: boolean = false, | ||
staticCSSSelectorCreator: (name: string, hash: string) => string = ( | ||
name, | ||
hash | ||
) => `.${name}-${hash}` | ||
) { | ||
@@ -102,2 +139,4 @@ try { | ||
const unsafeRequire = require | ||
const getPackageRootPath = memoize(filename => findRoot(filename)) | ||
@@ -119,18 +158,22 @@ | ||
rootPath = getPackageRootPath(filename) | ||
moduleName = require(rootPath + '/package.json').name | ||
moduleName = unsafeRequire(rootPath + '/package.json').name | ||
} catch (err) {} | ||
const finalPath = | ||
filename === rootPath ? basename(filename) : filename.slice(rootPath.length) | ||
filename === rootPath | ||
? nodePath.basename(filename) | ||
: filename.slice(rootPath.length) | ||
const positionInFile = state.count++ | ||
const stableClassName = getName( | ||
`${hashArray([ | ||
normalize(finalPath), | ||
moduleName, | ||
state.file.code | ||
])}${positionInFile}`, | ||
'css' | ||
) | ||
const stuffToHash = [moduleName] | ||
if (finalPath) { | ||
stuffToHash.push(nodePath.normalize(finalPath)) | ||
} else { | ||
stuffToHash.push(state.file.code) | ||
} | ||
const stableClassName = `e${hashArray(stuffToHash)}${positionInFile}` | ||
return t.objectProperty( | ||
@@ -141,4 +184,9 @@ t.identifier('target'), | ||
} | ||
export function buildStyledCallExpression(identifier, tag, path, state, t) { | ||
export function buildStyledCallExpression( | ||
identifier: Identifier, | ||
tag: StringLiteral, | ||
path: BabelPath, | ||
state: EmotionBabelPluginPass, | ||
t: Types | ||
) { | ||
const identifierName = getIdentifierName(path, t) | ||
@@ -149,8 +197,4 @@ | ||
if (state.extractStatic && !path.node.quasi.expressions.length) { | ||
const { hash, src } = createRawStringFromTemplateLiteral( | ||
path.node.quasi, | ||
identifierName, | ||
'styled' // we don't want these styles to be merged in css`` | ||
) | ||
const staticClassName = getName(hash, 'css') | ||
const { hash, src } = createRawStringFromTemplateLiteral(path.node.quasi) | ||
const staticClassName = `css-${hash}` | ||
const staticCSSRules = staticStylis(`.${staticClassName}`, src) | ||
@@ -198,3 +242,9 @@ | ||
export function buildStyledObjectCallExpression(path, state, identifier, t) { | ||
export function buildStyledObjectCallExpression( | ||
path: BabelPath, | ||
state: EmotionBabelPluginPass, | ||
identifier: Identifier, | ||
t: Types | ||
) { | ||
const targetProperty = buildTargetObjectProperty(path, state, t) | ||
const identifierName = getIdentifierName(path, t) | ||
@@ -210,19 +260,17 @@ const tag = t.isCallExpression(path.node.callee) | ||
const objectProperties = [targetProperty] | ||
if (state.opts.autoLabel && identifierName) { | ||
objectProperties.push( | ||
t.objectProperty( | ||
t.identifier('label'), | ||
t.stringLiteral(identifierName.trim()) | ||
) | ||
) | ||
} | ||
path.addComment('leading', '#__PURE__') | ||
return t.callExpression( | ||
t.callExpression( | ||
identifier, | ||
state.opts.autoLabel && identifierName | ||
? [ | ||
tag, | ||
t.objectExpression([ | ||
t.objectProperty( | ||
t.identifier('label'), | ||
t.stringLiteral(identifierName.trim()) | ||
) | ||
]) | ||
] | ||
: [tag] | ||
), | ||
t.callExpression(identifier, [tag, t.objectExpression(objectProperties)]), | ||
args | ||
@@ -234,3 +282,3 @@ ) | ||
const defaultImportedNames = { | ||
const defaultImportedNames: ImportedNames = { | ||
styled: 'styled', | ||
@@ -240,7 +288,45 @@ css: 'css', | ||
injectGlobal: 'injectGlobal', | ||
fontFace: 'fontFace', | ||
merge: 'merge' | ||
} | ||
export default function(babel) { | ||
const importedNameKeys = Object.keys(defaultImportedNames).map( | ||
key => (key === 'styled' ? 'default' : key) | ||
) | ||
const defaultEmotionPaths = ['emotion', 'react-emotion', 'preact-emotion'] | ||
function getRelativePath(filepath: string, absoluteInstancePath: string) { | ||
let relativePath = nodePath.relative( | ||
nodePath.dirname(filepath), | ||
absoluteInstancePath | ||
) | ||
return relativePath.charAt(0) === '.' ? relativePath : `./${relativePath}` | ||
} | ||
function getAbsolutePath(instancePath: string, rootPath: string) { | ||
if (instancePath.charAt(0) === '.') { | ||
let absoluteInstancePath = nodePath.resolve(rootPath, instancePath) | ||
return absoluteInstancePath | ||
} | ||
return false | ||
} | ||
function getInstancePathToImport(instancePath: string, filepath: string) { | ||
let absolutePath = getAbsolutePath(instancePath, process.cwd()) | ||
if (absolutePath === false) { | ||
return instancePath | ||
} | ||
return getRelativePath(filepath, absolutePath) | ||
} | ||
function getInstancePathToCompare(instancePath: string, rootPath: string) { | ||
let absolutePath = getAbsolutePath(instancePath, rootPath) | ||
if (absolutePath === false) { | ||
return instancePath | ||
} | ||
return absolutePath | ||
} | ||
export default function(babel: Babel) { | ||
const { types: t } = babel | ||
@@ -253,3 +339,14 @@ | ||
Program: { | ||
enter(path, state) { | ||
enter(path: BabelPath, state: EmotionBabelPluginPass) { | ||
const hasFilepath = | ||
path.hub.file.opts.filename && | ||
path.hub.file.opts.filename !== 'unknown' | ||
state.emotionImportPath = 'emotion' | ||
if (state.opts.primaryInstance !== undefined) { | ||
state.emotionImportPath = getInstancePathToImport( | ||
state.opts.primaryInstance, | ||
path.hub.file.opts.filename | ||
) | ||
} | ||
state.importedNames = { | ||
@@ -312,17 +409,18 @@ ...defaultImportedNames, | ||
} | ||
const emotionPaths = defaultEmotionPaths.concat( | ||
(state.opts.instances || []).map(instancePath => | ||
getInstancePathToCompare(instancePath, process.cwd()) | ||
) | ||
) | ||
let dirname = hasFilepath | ||
? nodePath.dirname(path.hub.file.opts.filename) | ||
: '' | ||
imports.forEach(({ source, imported, specifiers }) => { | ||
if (source.indexOf('emotion') !== -1) { | ||
if ( | ||
emotionPaths.indexOf( | ||
getInstancePathToCompare(source, dirname) | ||
) !== -1 | ||
) { | ||
const importedNames = specifiers | ||
.filter( | ||
v => | ||
[ | ||
'default', | ||
'css', | ||
'keyframes', | ||
'injectGlobal', | ||
'fontFace', | ||
'merge' | ||
].indexOf(v.imported) !== -1 | ||
) | ||
.filter(v => importedNameKeys.indexOf(v.imported) !== -1) | ||
.reduce( | ||
@@ -352,3 +450,3 @@ (acc, { imported, local }) => ({ | ||
}, | ||
exit(path, state) { | ||
exit(path: BabelPath, state: EmotionBabelPluginPass) { | ||
if (state.staticRules.length !== 0) { | ||
@@ -361,3 +459,3 @@ const toWrite = state.staticRules.join('\n').trim() | ||
const exists = fs.existsSync(cssFilename) | ||
addSideEffect(path, './' + basename(cssFilename)) | ||
addSideEffect(path, './' + nodePath.basename(cssFilename)) | ||
if ( | ||
@@ -374,3 +472,3 @@ exists ? fs.readFileSync(cssFilename, 'utf8') !== toWrite : true | ||
}, | ||
JSXOpeningElement(path, state) { | ||
JSXOpeningElement(path: BabelPath, state: EmotionBabelPluginPass) { | ||
cssProps(path, state, t) | ||
@@ -392,3 +490,4 @@ if (state.opts.hoist) { | ||
CallExpression: { | ||
enter(path, state) { | ||
enter(path: BabelPath, state: EmotionBabelPluginPass) { | ||
// $FlowFixMe | ||
if (path[visited]) { | ||
@@ -414,3 +513,2 @@ return | ||
case state.importedNames.injectGlobal: | ||
case state.importedNames.fontFace: | ||
if ( | ||
@@ -448,6 +546,6 @@ state.opts.sourceMap === true && | ||
} | ||
// $FlowFixMe | ||
path[visited] = true | ||
}, | ||
exit(path, state) { | ||
exit(path: BabelPath, state: EmotionBabelPluginPass) { | ||
try { | ||
@@ -472,6 +570,8 @@ if ( | ||
}, | ||
TaggedTemplateExpression(path, state) { | ||
TaggedTemplateExpression(path: BabelPath, state: EmotionBabelPluginPass) { | ||
// $FlowFixMe | ||
if (path[visited]) { | ||
return | ||
} | ||
// $FlowFixMe | ||
path[visited] = true | ||
@@ -522,11 +622,2 @@ if ( | ||
) | ||
} else if (path.node.tag.name === state.importedNames.fontFace) { | ||
replaceCssWithCallExpression( | ||
path, | ||
path.node.tag, | ||
state, | ||
t, | ||
(src, name, hash) => `@font-face {${src}}`, | ||
true | ||
) | ||
} else if (path.node.tag.name === state.importedNames.injectGlobal) { | ||
@@ -533,0 +624,0 @@ replaceCssWithCallExpression( |
@@ -0,1 +1,2 @@ | ||
// @flow | ||
import { | ||
@@ -2,0 +3,0 @@ buildStyledCallExpression, |
@@ -0,1 +1,2 @@ | ||
// @flow | ||
import { replaceCssWithCallExpression } from './index' | ||
@@ -11,4 +12,3 @@ import { buildMacroRuntimeNode, addRuntimeImports } from './babel-utils' | ||
switch (referenceKey) { | ||
case 'injectGlobal': | ||
case 'fontFace': { | ||
case 'injectGlobal': { | ||
isPure = false | ||
@@ -15,0 +15,0 @@ } |
@@ -0,3 +1,6 @@ | ||
// @flow | ||
import { SourceMapGenerator } from 'source-map' | ||
import convert from 'convert-source-map' | ||
import type { EmotionBabelPluginPass } from './index' | ||
import type { BabelFile } from 'babel-flow-types' | ||
@@ -8,3 +11,3 @@ function getGeneratorOpts(file) { | ||
export function makeSourceMapGenerator(file) { | ||
export function makeSourceMapGenerator(file: BabelFile) { | ||
const generatorOpts = getGeneratorOpts(file) | ||
@@ -21,3 +24,6 @@ const filename = generatorOpts.sourceFileName | ||
export function addSourceMaps(offset, state) { | ||
export function addSourceMaps( | ||
offset: { line: number, column: number }, | ||
state: EmotionBabelPluginPass | ||
) { | ||
const generator = makeSourceMapGenerator(state.file) | ||
@@ -24,0 +30,0 @@ const generatorOpts = getGeneratorOpts(state.file) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
75404
1809
287
1
+ Addedemotion-utils@9.1.0(transitive)
- Removedemotion-utils@8.0.12(transitive)
Updatedemotion-utils@^9.0.0-0