inline-loops.macro
Version:
Macros that will inline loops for arrays and objects
179 lines (178 loc) • 6.59 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getCachedFnArgs = getCachedFnArgs;
exports.getImportedHandlerName = getImportedHandlerName;
exports.getLocalName = getLocalName;
exports.handleArrowFunctionExpressionUse = handleArrowFunctionExpressionUse;
exports.handleInvalidUsage = handleInvalidUsage;
exports.isMacroHandlerName = isMacroHandlerName;
exports.isPossiblyDynamic = isPossiblyDynamic;
exports.processNestedInlineLoopMacros = processNestedInlineLoopMacros;
exports.rename = rename;
exports.replaceOrRemove = replaceOrRemove;
exports.shouldWrapInClosure = shouldWrapInClosure;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _babelPluginMacros = require("babel-plugin-macros");
function getCachedFnArgs(local, isReduce) {
return isReduce ? [local.accumulated, local.value, local.key, local.collection] : [local.value, local.key, local.collection];
}
function getImportedHandlerName(callee, handlers) {
var binding = callee.scope.getBinding(callee.node.name);
if (!binding) {
return;
}
var owner = binding.path;
if (owner.isImportSpecifier()) {
var imported = owner.get('imported');
var name = imported.isIdentifier() ? imported.node.name : imported.node.value;
if (!Object.keys(handlers).some(function (handler) {
return handler === name;
})) {
return;
}
var importSource = owner.parentPath.get('source.value');
if (!importSource.node.endsWith('inline-loops.macro')) {
return;
}
return name;
}
if (owner.isVariableDeclarator()) {
var init = owner.get('init');
if (!init || !init.isCallExpression() || !init.get('callee').isIdentifier({
name: 'require'
})) {
return;
}
var requireSource = init.get('arguments.0.value');
if (!requireSource.node.endsWith('inline-loops.macro')) {
return;
}
var _imported = owner.get('id.properties').find(function (property) {
var value = property.get('value');
return value.isIdentifier({
name: callee.node.name
});
});
if (!_imported) {
return;
}
var _name = _imported.get('key').node.name;
if (!Object.keys(handlers).some(function (handler) {
return handler === _name;
})) {
return;
}
return _name;
}
}
function getLocalName(path) {
var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : path.isIdentifier() ? path.node.name : undefined;
return path.scope.generateUidIdentifier(name);
}
function handleArrowFunctionExpressionUse(path) {
if (path.parentPath.isArrowFunctionExpression()) {
path.parentPath.arrowFunctionToExpression({
allowInsertArrow: false,
noNewArrows: true
});
}
}
function handleInvalidUsage(path, handlers) {
var _path$get = path.get('arguments'),
_path$get2 = (0, _slicedToArray2["default"])(_path$get, 2),
collection = _path$get2[0],
handler = _path$get2[1];
if (collection !== null && collection !== void 0 && collection.isSpreadElement()) {
throw new _babelPluginMacros.MacroError('You cannot use spread arguments with `inline-loops.macro`; please declare the arguments explicitly.');
}
var importedHandlerName = getImportedHandlerName(handler, handlers);
if (importedHandlerName) {
throw new _babelPluginMacros.MacroError('You cannot use a method from `inline-loops.macro` directly as a handler; please wrap it in a export function call.');
}
}
function isMacroHandlerName(handlers, name) {
return !!(name && handlers[name]);
}
function processNestedInlineLoopMacros(path, handlers) {
if (!path.isCallExpression()) {
return;
}
var callee = path.get('callee');
if (!callee.isIdentifier()) {
return;
}
var importedHandlerName = getImportedHandlerName(callee, handlers);
if (isMacroHandlerName(handlers, importedHandlerName)) {
handlers[importedHandlerName](path.get('callee'));
}
}
function rename(path, newName) {
path.scope.rename(path.node.name, newName);
}
function replaceOrRemove(_ref, path, local, templates, replacement) {
var t = _ref.types;
if (shouldWrapInClosure(path)) {
if (!t.isIdentifier(replacement, {
name: 'undefined'
})) {
local.contents.push(t.returnStatement(replacement));
}
var iife = templates.iife({
BODY: local.contents.flat()
});
path.replaceWith(iife.expression);
} else {
var statement = path.getStatementParent();
if (!statement) {
throw new _babelPluginMacros.MacroError('Could not insert contents because the statement was indeterminable.');
}
local.contents.forEach(function (content) {
statement.insertBefore(content);
});
var parentPath = path.parentPath;
if (parentPath !== null && parentPath !== void 0 && parentPath.isExpressionStatement()) {
path.remove();
} else {
path.replaceWith(replacement);
}
}
}
function isPossiblyDynamic(path) {
if (path.isPattern()) {
return true;
}
if (path.isBinaryExpression() || path.isCallExpression() || path.isTemplateLiteral()) {
return isPossiblyDynamic(path.parentPath);
}
return path.isExpression();
}
function shouldWrapInClosure(path) {
var parentPath = path.parentPath;
if (!parentPath) {
return false;
}
if (parentPath.isAssignmentPattern()) {
return true;
}
if (parentPath.isArrayExpression() || parentPath.isAwaitExpression() || parentPath.isBinaryExpression() || parentPath.isJSXElement() || parentPath.isJSXExpressionContainer() || parentPath.isObjectExpression() || parentPath.isObjectProperty() || parentPath.isUnaryExpression()) {
return shouldWrapInClosure(parentPath);
}
if (parentPath.isLogicalExpression()) {
return !path.isCallExpression() || parentPath.get('right').node === path.node || shouldWrapInClosure(parentPath);
}
if (parentPath.isConditionalExpression()) {
return !path.isCallExpression() || parentPath.get('test').node !== path.node || shouldWrapInClosure(parentPath);
}
var functionParent = path.getFunctionParent();
if (!functionParent || parentPath.node === functionParent.node || parentPath.parent === functionParent.node) {
return false;
}
if ((parentPath.isReturnStatement() || parentPath.isExpressionStatement()) && parentPath.parentPath.isBlockStatement() && parentPath.parentPath.parent === functionParent.node) {
var body = functionParent.get('body.body');
return !Array.isArray(body) || body.length > 1;
}
return true;
}