pretty-lights
Version:
CSS-in-JS with a reliable API
464 lines (373 loc) • 20.1 kB
JavaScript
;
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);
}
}
}
}
};
}