UNPKG

babel-plugin-lodash

Version:
164 lines (129 loc) 5.36 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = lodash; var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _config = require('./config'); var _config2 = _interopRequireDefault(_config); var _importModule = require('./importModule'); var _importModule2 = _interopRequireDefault(_importModule); var _mapping = require('./mapping'); var _mapping2 = _interopRequireDefault(_mapping); var _Store = require('./Store'); var _Store2 = _interopRequireDefault(_Store); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** The error message used when chain sequences are detected. */ var CHAIN_ERROR = ['Lodash chain sequences are not supported by babel-plugin-lodash.', 'Consider substituting chain sequences with composition patterns.', 'See https://medium.com/making-internets/why-using-chain-is-a-mistake-9bc1f80d51ba'].join('\n'); /*----------------------------------------------------------------------------*/ function lodash(_ref) { var types = _ref.types; var identifiers = { 'PLACEHOLDER': types.identifier('placeholder'), 'UNDEFINED': types.identifier('undefined') }; /** * Used to track variables built during the AST pass. We instantiate these in * the `Program` visitor in order to support running the plugin in watch mode * or on multiple files. * * @type Store */ var store = new _Store2.default(); function getCallee(_ref2) { var parentPath = _ref2.parentPath; // Trace curried calls to their origin, e.g. `fp.partial(func)([fp, 2])(1)`. while (!parentPath.isStatement()) { if (parentPath.isCallExpression()) { var result = parentPath.node.callee; while (types.isCallExpression(result)) { result = result.callee; } return result; } parentPath = parentPath.parentPath; } } /*--------------------------------------------------------------------------*/ var visitor = { Program: function Program(path, state) { var _$assign = _lodash2.default.assign(_mapping2.default, (0, _config2.default)(state.opts)); var ids = _$assign.ids; var file = path.hub.file; if (_lodash2.default.isEmpty(ids)) { throw new Error('Cannot find module'); } // Clear tracked method imports. _importModule2.default.cache.clear(); store.clear(); // Populate module paths per package. _lodash2.default.each(ids, function (id) { store.set(id); _mapping2.default.modules.get(id).forEach(function (value, key) { store.set(id + '/' + key); }); }); // Replace old members with their method imports. _lodash2.default.each(file.metadata.modules.imports, function (module) { var pkgStore = store.get(module.source); if (!pkgStore) { return; } var isLodash = pkgStore.isLodash(); var specs = _lodash2.default.sortBy(module.specifiers, function (spec) { return spec.imported == 'default'; }); _lodash2.default.each(specs, function (spec) { var imported = spec.imported; var local = spec.local; var binding = file.scope.getBinding(local); var isChain = isLodash && imported == 'chain'; _lodash2.default.each(binding.referencePaths, function (refPath) { var parentPath = refPath.parentPath; if (imported != 'default') { if (isChain && refPath.parentPath.isCallExpression()) { throw refPath.buildCodeFrameError(CHAIN_ERROR); } var identifier = (0, _importModule2.default)(pkgStore, imported, file); refPath.replaceWith(types.clone(identifier)); } else if (parentPath.isMemberExpression()) { var key = refPath.parent.property.name; if (isLodash && key == 'chain' && parentPath.parentPath.isCallExpression()) { throw refPath.buildCodeFrameError(CHAIN_ERROR); } var _identifier = (0, _importModule2.default)(pkgStore, key, file); parentPath.replaceWith(types.clone(_identifier)); } else if (isLodash) { var callee = getCallee(refPath); if (callee && callee.name == local) { throw refPath.buildCodeFrameError(CHAIN_ERROR); } refPath.replaceWith(callee ? types.memberExpression(callee, identifiers.PLACEHOLDER) : identifiers.UNDEFINED); } }); }); }); }, ImportDeclaration: function ImportDeclaration(path) { if (store.get(path.node.source.value)) { // Remove old import. path.remove(); } }, ExportNamedDeclaration: function ExportNamedDeclaration(path) { var node = path.node; var pkgPath = _lodash2.default.get(node, 'source.value'); var pkgStore = store.get(pkgPath); if (!pkgStore) { return; } node.source = null; _lodash2.default.each(node.specifiers, function (spec) { spec.local = (0, _importModule2.default)(pkgStore, spec.local.name, path.hub.file); }); } }; return { visitor: visitor }; }; module.exports = exports['default'];