UNPKG

pretty-lights

Version:
464 lines (373 loc) 20.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.hoistPureArgs = hoistPureArgs; exports.replaceCssWithCallExpression = replaceCssWithCallExpression; exports.buildStyledCallExpression = buildStyledCallExpression; exports.buildStyledObjectCallExpression = buildStyledObjectCallExpression; exports["default"] = _default; var _path = _interopRequireDefault(require("path")); var _findRoot = _interopRequireDefault(require("find-root")); var _hash = _interopRequireDefault(require("@emotion/hash")); var _memoize = _interopRequireDefault(require("@emotion/memoize")); var _babelUtils = require("@emotion/babel-utils"); var _babelUtils2 = require("./babel-utils"); var _sourceMap = require("./source-map"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } // export type BabelPath = any; function hashArray(arr) { return (0, _hash["default"])(arr.join('')); } function hoistPureArgs(path) { var args = path.get('arguments'); if (args && Array.isArray(args)) { args.forEach(function (arg) { if (!arg.isIdentifier() && arg.isPure()) { arg.hoist(); } }); } } // type ImportedNames = { // css: string, // keyframes: string, // injectGlobal: string, // styled: string, // merge: string, // }; // // export type PrettyLightsBabelPluginPass = BabelPluginPass & { // count: number, // opts: any, // }; function replaceCssWithCallExpression(path, identifier, state, t) { var removePath = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false; try { var identifierName = (0, _babelUtils.getLabelFromPath)(path, t); if (!removePath) { path.addComment('leading', '#__PURE__'); } var stringToAppend = ''; if (state.opts.sourceMap === true && path.node.quasi.loc !== undefined) { stringToAppend += (0, _sourceMap.addSourceMaps)(path.node.quasi.loc.start, state); } var label = (0, _babelUtils2.getLabel)(identifierName, state.opts.autoLabel, state.opts.labelFormat, state.file.opts.filename); if (label) { stringToAppend += "label:".concat(label, ";"); } path.replaceWith(t.callExpression(identifier, (0, _babelUtils.appendStringToExpressions)((0, _babelUtils.getExpressionsFromTemplateLiteral)(path.node.quasi, t), stringToAppend, t))); if (state.opts.hoist) { hoistPureArgs(path); } return; } catch (e) { if (path) { throw path.buildCodeFrameError(e); } throw e; } } var unsafeRequire = require; var getPackageRootPath = (0, _memoize["default"])(function (filename) { return (0, _findRoot["default"])(filename); }); function buildTargetObjectProperty(path, state, t) { if (state.count === undefined) { state.count = 0; } var filename = state.file.opts.filename; // normalize the file path to ignore folder structure // outside the current node project and arch-specific delimiters var moduleName = ''; var rootPath = filename; try { rootPath = getPackageRootPath(filename); moduleName = unsafeRequire("".concat(rootPath, "/package.json")).name; } catch (err) {// shhh } var finalPath = filename === rootPath ? '' : filename.slice(rootPath.length); var positionInFile = state.count; state.count += 1; var stuffToHash = [moduleName]; if (finalPath) { stuffToHash.push(_path["default"].normalize(finalPath)); } else { stuffToHash.push(state.file.code); } var stableClassName = "e".concat(hashArray(stuffToHash)).concat(positionInFile); return t.objectProperty(t.identifier('target'), t.stringLiteral(stableClassName)); } var buildFinalOptions = function buildFinalOptions(t, options) { var existingProperties = []; if (options && !t.isObjectExpression(options)) { console.warn("Second argument to a styled call is not an object, it's going to be removed."); } else if (options) { existingProperties = options.properties; } for (var _len = arguments.length, newProps = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) { newProps[_key - 2] = arguments[_key]; } return t.objectExpression([].concat(_toConsumableArray(existingProperties), _toConsumableArray(newProps.filter(Boolean)))); }; function buildStyledCallExpression(identifier, args, path, state, isCallExpression, t) { // unpacking "manually" to prevent array out of bounds access (deopt) var tag = args[0]; var options = args.length >= 2 ? args[1] : null; var restArgs = args.slice(2); var identifierName = (0, _babelUtils.getLabelFromPath)(path, t); var targetProperty = buildTargetObjectProperty(path, state, t); path.addComment('leading', '#__PURE__'); var stringToAppend = ''; if (state.opts.sourceMap === true && path.node.quasi.loc !== undefined) { stringToAppend += (0, _sourceMap.addSourceMaps)(path.node.quasi.loc.start, state); } var labelProperty; var label = (0, _babelUtils2.getLabel)(identifierName, state.opts.autoLabel, state.opts.labelFormat, state.file.opts.filename); if (label) { labelProperty = t.objectProperty(t.identifier('label'), t.stringLiteral(label)); } var finalOptions = buildFinalOptions(t, options, labelProperty, targetProperty); var styledCall = t.isStringLiteral(tag) && !isCallExpression && tag.value[0] !== tag.value[0].toLowerCase() ? t.memberExpression(identifier, t.identifier(tag.value)) : t.callExpression(identifier, [tag, finalOptions].concat(_toConsumableArray(restArgs))); return t.callExpression(styledCall, (0, _babelUtils.appendStringToExpressions)((0, _babelUtils.getExpressionsFromTemplateLiteral)(path.node.quasi, t), stringToAppend, t)); } function buildStyledObjectCallExpression(path, state, identifier, t) { var targetProperty = buildTargetObjectProperty(path, state, t); var identifierName = (0, _babelUtils.getLabelFromPath)(path, t); var tag = t.isCallExpression(path.node.callee) ? path.node.callee.arguments[0] : t.stringLiteral(path.node.callee.property.name); var isCallExpression = t.isCallExpression(path.node.callee); var styledOptions = null; var restStyledArgs = []; if (t.isCallExpression(path.node.callee)) { var styledArgs = path.node.callee.arguments; if (styledArgs.length >= 2) { var _styledArgs = _slicedToArray(styledArgs, 2); styledOptions = _styledArgs[1]; } restStyledArgs = styledArgs.slice(2); } var args = path.node.arguments; if (state.opts.sourceMap === true && path.node.loc !== undefined) { args.push(t.stringLiteral((0, _sourceMap.addSourceMaps)(path.node.loc.start, state))); } var label = (0, _babelUtils2.getLabel)(identifierName, state.opts.autoLabel, state.opts.labelFormat, state.file.opts.filename); var labelProperty = label ? t.objectProperty(t.identifier('label'), t.stringLiteral(label)) : null; path.addComment('leading', '#__PURE__'); var styledCall = t.isStringLiteral(tag) && !isCallExpression && tag.value[0] !== tag.value[0].toLowerCase() ? t.memberExpression(identifier, t.identifier(tag.value)) : t.callExpression(identifier, [tag, buildFinalOptions(t, styledOptions, targetProperty, labelProperty)].concat(_toConsumableArray(restStyledArgs))); return t.callExpression(styledCall, args); } var visited = Symbol('visited'); var defaultImportedNames = { styled: 'styled', css: 'css', keyframes: 'keyframes', injectGlobal: 'injectGlobal', merge: 'merge' }; var importedNameKeys = Object.keys(defaultImportedNames); var defaultPrettyLightPaths = ['pretty-lights']; function getAbsolutePath(instancePath, rootPath) { if (instancePath.charAt(0) === '.') { var absoluteInstancePath = _path["default"].resolve(rootPath, instancePath); return absoluteInstancePath; } return false; } function getInstancePathToCompare(instancePath, rootPath) { var absolutePath = getAbsolutePath(instancePath, rootPath); if (absolutePath === false) { return instancePath; } return absolutePath; } function _default(babel) { var t = babel.types; return { name: 'pretty-lights', // not required // eslint-disable-next-line inherits: require('@babel/plugin-syntax-jsx')["default"], visitor: { Program: { enter: function enter(path, state) { var hasFilepath = path.hub.file.opts.filename && path.hub.file.opts.filename !== 'unknown'; state.prettyLightsImportPath = 'pretty-lights'; state.importedNames = _objectSpread({}, defaultImportedNames); var imports = []; var isModule = false; // eslint-disable-next-line no-restricted-syntax var _iterator = _createForOfIteratorHelper(path.node.body), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var node = _step.value; if (t.isModuleDeclaration(node)) { isModule = true; break; } } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } if (isModule) { path.traverse({ ImportDeclaration: { exit: function exit(p) { var node = p.node; var imported = []; var specifiers = []; imports.push({ source: node.source.value, imported: imported, specifiers: specifiers }); // eslint-disable-next-line no-restricted-syntax var _iterator2 = _createForOfIteratorHelper(p.get('specifiers')), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var specifier = _step2.value; var local = specifier.node.local.name; if (specifier.isImportDefaultSpecifier()) { imported.push('default'); specifiers.push({ kind: 'named', imported: 'default', local: local }); } if (specifier.isImportSpecifier()) { var importedName = specifier.node.imported.name; imported.push(importedName); specifiers.push({ kind: 'named', imported: importedName, local: local }); } } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } } } }); } var prettyLightsPaths = defaultPrettyLightPaths; var dirname = hasFilepath ? _path["default"].dirname(path.hub.file.opts.filename) : ''; imports.forEach(function (_ref) { var source = _ref.source, specifiers = _ref.specifiers; if (prettyLightsPaths.indexOf(getInstancePathToCompare(source, dirname)) !== -1) { var importedNames = specifiers.filter(function (v) { return importedNameKeys.indexOf(v.imported) !== -1; }).reduce(function (acc, _ref2) { var imported = _ref2.imported, local = _ref2.local; return _objectSpread(_objectSpread({}, acc), {}, _defineProperty({}, imported === 'default' ? 'styled' : imported, local)); }, defaultImportedNames); state.importedNames = importedNames; } }); } }, JSXOpeningElement: function JSXOpeningElement(path, state) { if (state.opts.hoist) { path.traverse({ CallExpression: function CallExpression(callExprPath) { if (callExprPath.node.callee.name === state.importedNames.css) { hoistPureArgs(callExprPath); } } }); } }, CallExpression: { enter: function enter(path, state) { if (path[visited]) { return; } try { if (t.isIdentifier(path.node.callee)) { switch (path.node.callee.name) { case state.importedNames.css: case state.importedNames.keyframes: { path.addComment('leading', '#__PURE__'); var label = (0, _babelUtils2.getLabel)((0, _babelUtils.getLabelFromPath)(path, t), state.opts.autoLabel, state.opts.labelFormat, state.file.opts.filename); if (label) { path.node.arguments.push(t.stringLiteral("label:".concat(label, ";"))); } } // eslint-disable-next-line no-fallthrough case state.importedNames.injectGlobal: if (state.opts.sourceMap === true && path.node.loc !== undefined) { path.node.arguments.push(t.stringLiteral((0, _sourceMap.addSourceMaps)(path.node.loc.start, state))); } break; default: break; } } if (t.isCallExpression(path.node.callee) && path.node.callee.callee.name === state.importedNames.styled || t.isMemberExpression(path.node.callee) && t.isIdentifier(path.node.callee.object) && path.node.callee.object.name === state.importedNames.styled) { var identifier = t.isCallExpression(path.node.callee) ? path.node.callee.callee : path.node.callee.object; path.replaceWith(buildStyledObjectCallExpression(path, state, identifier, t)); if (state.opts.hoist) { hoistPureArgs(path); } } } catch (e) { throw path.buildCodeFrameError(e); } path[visited] = true; }, exit: function exit(path, state) { try { if (path.node.callee && path.node.callee.property && path.node.callee.property.name === 'withComponent') { if (path.node.arguments.length === 1) { path.node.arguments.push(t.objectExpression([buildTargetObjectProperty(path, state, t)])); } } } catch (e) { throw path.buildCodeFrameError(e); } } }, TaggedTemplateExpression: function TaggedTemplateExpression(path, state) { if (path[visited]) { return; } path[visited] = true; if ( // styled.h1`color:${color};` t.isMemberExpression(path.node.tag) && path.node.tag.object.name === state.importedNames.styled) { path.replaceWith(buildStyledCallExpression(path.node.tag.object, [t.stringLiteral(path.node.tag.property.name)], path, state, false, t)); } else if ( // styled('h1')`color:${color};` t.isCallExpression(path.node.tag) && path.node.tag.callee.name === state.importedNames.styled) { path.replaceWith(buildStyledCallExpression(path.node.tag.callee, path.node.tag.arguments, path, state, true, t)); } else if (t.isIdentifier(path.node.tag)) { if (path.node.tag.name === state.importedNames.css) { replaceCssWithCallExpression(path, path.node.tag, state, t); } else if (path.node.tag.name === state.importedNames.keyframes) { replaceCssWithCallExpression(path, path.node.tag, state, t, false); } else if (path.node.tag.name === state.importedNames.injectGlobal) { replaceCssWithCallExpression(path, path.node.tag, state, t, true); } } } } }; }