babel-plugin-transform-currency-operators
Version:
https://github.com/scurker/babel-plugin-transform-currency-operators
231 lines (188 loc) • 7.68 kB
JavaScript
;
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var path = _interopDefault(require('path'));
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
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 _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;
}
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.");
}
var rootPath = process.cwd();
function resolveRelativePath(currentFile, importPath) {
var absolutePath = path.resolve(rootPath, importPath),
relativePathToImport = path.relative(path.dirname(currentFile), absolutePath); // Check to see if path is relative to currentFile's folder
if (relativePathToImport.indexOf('../') !== 0) {
relativePathToImport = "./".concat(relativePathToImport);
}
return relativePathToImport;
}
var arithmeticOperators = {
'+': 'add',
'-': 'subtract',
'/': 'divide',
'*': 'multiply'
};
var compareOperators = ['===', '==', '>', '<', '>=', '<=', '!=', '!=='];
function transformCurrencyOperators(_ref) {
var t = _ref.types;
function expressionCallsCurrency(node, identifiers) {
if (!node) {
return false;
}
if (t.isBinaryExpression(node)) {
return expressionCallsCurrency(node.left, identifiers);
}
if (t.isCallExpression(node)) {
return expressionCallsCurrency(node.callee, identifiers);
}
if (t.isMemberExpression(node)) {
return expressionCallsCurrency(node.object, identifiers);
}
if (t.isFunctionExpression(node)) {
return expressionCallsCurrency(node.body.body.find(function (n) {
return t.isReturnStatement(n);
}), identifiers);
}
if (t.isArrowFunctionExpression(node)) {
if (t.isCallExpression(node.body)) {
return expressionCallsCurrency(node.body, identifiers);
} else if (t.isBlockStatement(node.body)) {
return expressionCallsCurrency(node.body.body.find(function (n) {
return t.isReturnStatement(n);
}), identifiers);
}
}
if (t.isReturnStatement(node)) {
return expressionCallsCurrency(node.argument.callee, identifiers);
}
return t.isIdentifier(node) && identifiers.has(node.name);
}
function pathContainsCurrency(refPath, methodName) {
var node = refPath.node,
currencyVariables = new Set([methodName]);
var Visitors = {
FunctionDeclaration: function FunctionDeclaration(_ref2) {
var node = _ref2.node;
if (expressionCallsCurrency(node.body.body.find(function (n) {
return t.isReturnStatement(n);
}), currencyVariables)) {
currencyVariables.add(node.id.name);
}
},
VariableDeclarator: function VariableDeclarator(_ref3) {
var scope = _ref3.scope,
node = _ref3.node;
if (expressionCallsCurrency(node.init, currencyVariables)) {
var binding = scope.bindings[node.id.name] || {};
if (binding.kind !== 'let' || binding.kind === 'let' && binding.scope === refPath.scope) {
currencyVariables.add(node.id.name);
}
}
},
AssignmentExpression: function AssignmentExpression(_ref4) {
var node = _ref4.node;
var left = node.left,
right = node.right;
if (!expressionCallsCurrency(right, currencyVariables)) {
currencyVariables["delete"](left.name);
} else {
currencyVariables.add(left.name);
}
}
}; // Attempt to find any currency variables in scope
var currentPath = refPath.parentPath;
while (currentPath) {
currentPath.traverse(Visitors);
currentPath = currentPath.parentPath;
}
return node && expressionCallsCurrency(node, currencyVariables);
}
function buildExpression(path, methodName) {
var node = path.node,
operator = node.operator,
left = node.left,
right = node.right;
if (t.isBinaryExpression(left)) {
left = buildExpression(path.get('left'));
}
var currencyMethod = arithmeticOperators[operator];
if (currencyMethod) {
return t.callExpression(t.memberExpression(t.isIdentifier(left) ? t.identifier(left.name) : left, t.identifier(currencyMethod)), [right]);
} else if (compareOperators.includes(operator) && !t.isMemberExpression(node.left)) {
return t.binaryExpression(operator, t.memberExpression(left, t.identifier('value')), pathContainsCurrency(path.get('right'), methodName) ? t.memberExpression(right, t.identifier('value')) : right);
} else {
return node;
}
}
return {
pre: function pre(_ref5) {
var opts = _ref5.opts;
var filename = opts.filename,
pluginOptions = this.opts,
paths = Array.isArray(pluginOptions.customCurrency) ? pluginOptions.customCurrency.filter(function (path) {
return typeof path === 'string';
}) : typeof pluginOptions.customCurrency === 'string' ? [pluginOptions.customCurrency] : [];
this.currencyResolution = new Set(['currency.js'].concat(_toConsumableArray(paths.map(function (path) {
return resolveRelativePath(filename, path);
}))));
},
visitor: {
VariableDeclarator: function VariableDeclarator(_ref6, _ref7) {
var node = _ref6.node;
var opts = _ref7.opts,
currencyResolution = _ref7.currencyResolution;
var init = node.init;
if (t.isCallExpression(init) && init.callee.name === 'require' && currencyResolution.has(init.arguments[0].value)) {
opts.hasCurrency = true;
opts.methodName = node.id.name;
}
return;
},
ImportDeclaration: function ImportDeclaration(_ref8, _ref9) {
var node = _ref8.node;
var opts = _ref9.opts,
currencyResolution = _ref9.currencyResolution;
var source = node.source,
specifiers = node.specifiers;
if (currencyResolution.has(source.value)) {
var defaultImport = specifiers.find(function (specifier) {
return t.isImportDefaultSpecifier(specifier);
});
opts.hasCurrency = true;
opts.methodName = defaultImport.local.name;
}
return;
},
BinaryExpression: function BinaryExpression(path, _ref10) {
var opts = _ref10.opts;
if (opts.hasCurrency && pathContainsCurrency(path.get('left'), opts.methodName)) {
// Prevent replacement nodes from being visited multiple times
path.stop();
path.replaceWith(buildExpression(path, opts.methodName));
return;
}
return;
}
}
};
}
module.exports = transformCurrencyOperators;