diff options
Diffstat (limited to 'babel-plugin-async-to-promises/lib/index.js')
-rw-r--r-- | babel-plugin-async-to-promises/lib/index.js | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/babel-plugin-async-to-promises/lib/index.js b/babel-plugin-async-to-promises/lib/index.js new file mode 100644 index 0000000..9d7952b --- /dev/null +++ b/babel-plugin-async-to-promises/lib/index.js @@ -0,0 +1,123 @@ +'use strict'; + +var _babelHelperHoistVariables = require('babel-helper-hoist-variables'); + +var _babelHelperHoistVariables2 = _interopRequireDefault(_babelHelperHoistVariables); + +var _babelTypes = require('babel-types'); + +var _refactor = require('./refactor'); + +var _promisechain = require('./promisechain'); + +var _promisechain2 = _interopRequireDefault(_promisechain); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +module.exports = function () { + return { + visitor: WrapperVisitor, + manipulateOptions: function manipulateOptions(opts, parserOpts) { + parserOpts.plugins.push('asyncFunctions'); + } + }; +}; + +var depth = 0; +var respID = void 0, + errID = void 0; + +var WrapperVisitor = { + // Because only ES5 is really supported, force this plugin to run as late as + // possible. At least the normal (es2015 preset) transforms have happened by + // then. + Program: { + exit: function exit(path) { + respID = path.scope.generateUid('resp'); + errID = path.scope.generateUid('err'); + path.traverse(MainVisitor); + // inline functions + path.traverse(InliningVisitor); + } + } +}; + +var MainVisitor = { + Function: { + enter: function enter(path) { + depth++; + var node = path.node; + + if (node.async) { + (function () { + var decls = []; + var addVarDecl = function addVarDecl(id) { + return decls.push((0, _babelTypes.variableDeclarator)(id)); + }; + // hoist variables + (0, _babelHelperHoistVariables2.default)(path, addVarDecl); + + // info gathering for this/arguments during the refactoring + var argumentsID = (0, _babelTypes.identifier)(path.scope.generateUid('arguments')); + var used = { argumentsID: false }; + + var newBody = []; + var addFunctionDecl = function addFunctionDecl(func) { + return newBody.push(func); + }; + + // refactor code + var args = { argumentsID: argumentsID, used: used, addVarDecl: addVarDecl, addFunctionDecl: addFunctionDecl, respID: respID, errID: errID }; + path.traverse(_refactor.RefactorVisitor, args); + // add this/arguments vars if necessary + if (used.argumentsID) { + decls.push((0, _babelTypes.variableDeclarator)(argumentsID, (0, _babelTypes.identifier)('arguments'))); + } + if (decls.length) { + newBody.push((0, _babelTypes.variableDeclaration)('var', decls)); + } + + // transformations that can only be done after all others. + path.traverse(_refactor.IfRefactorVisitor); + + // build the promise chain + var chain = new _promisechain2.default(depth > 1, node.dirtyAllowed, respID, errID); + chain.add(path.get('body.body')); + newBody.push((0, _babelTypes.returnStatement)(chain.toAST())); + + // combine all the newly generated stuff. + node.body = (0, _babelTypes.blockStatement)(newBody); + node.async = false; + })(); + } + }, + exit: function exit() { + depth--; + } + } +}; + +var InliningVisitor = { + BlockStatement: function BlockStatement(path) { + // inline blocks. Included because babel-template otherwise creates empty + // blocks. + if ((0, _babelTypes.isBlockStatement)(path.parent)) { + path.replaceWithMultiple(path.node.body); + } + }, + ReturnStatement: function ReturnStatement(path) { + // return function () { ...body... }() becomes: ...body... + var call = path.node.argument; + var inlineable = (0, _babelTypes.isCallExpression)(call) && !call.arguments.length && (0, _babelTypes.isFunctionExpression)(call.callee) && !call.callee.id && !call.callee.params.length && (0, _babelTypes.isBlockStatement)(call.callee.body) && !Object.keys(path.get('argument.callee').scope.bindings).length; + if (inlineable) { + path.replaceWithMultiple(call.callee.body.body); + } + }, + CallExpression: function CallExpression(path) { + // function () { return x; }() becomes x + var inlineable = !path.node.arguments.length && (0, _babelTypes.isFunctionExpression)(path.node.callee) && !path.node.callee.id && !path.node.callee.params.length && (0, _babelTypes.isBlockStatement)(path.node.callee.body) && path.node.callee.body.body.length === 1 && (0, _babelTypes.isReturnStatement)(path.node.callee.body.body[0]) && path.node.callee.body.body[0].argument; + if (inlineable) { + path.replaceWith(path.node.callee.body.body[0].argument); + } + } +};
\ No newline at end of file |