From e7c1cf5b7d2eba9468804635d0c2a0fc6725e42a Mon Sep 17 00:00:00 2001 From: Miguel Jimenez Esun Date: Mon, 3 Jul 2017 09:51:28 -0700 Subject: [PATCH] Add a new babel transformer for inlining regenerator-runtime per file Reviewed By: davidaurelio Differential Revision: D5364134 fbshipit-source-id: 45aae705f961819d5a8e3a8a23c2e8b9300d3cb5 --- babel-preset/configs/main.js | 1 + ...transform-regenerator-runtime-insertion.js | 109 ++++++++++++++++++ package.json | 1 + 3 files changed, 111 insertions(+) create mode 100644 babel-preset/transforms/transform-regenerator-runtime-insertion.js diff --git a/babel-preset/configs/main.js b/babel-preset/configs/main.js index 5afbc9061a81c0..eb814e6ebdad6e 100644 --- a/babel-preset/configs/main.js +++ b/babel-preset/configs/main.js @@ -38,6 +38,7 @@ var base = { 'transform-react-jsx', 'transform-regenerator', ['transform-es2015-for-of', { loose: true }], + require('../transforms/transform-regenerator-runtime-insertion'), require('../transforms/transform-symbol-member'), ]), }; diff --git a/babel-preset/transforms/transform-regenerator-runtime-insertion.js b/babel-preset/transforms/transform-regenerator-runtime-insertion.js new file mode 100644 index 00000000000000..a8d66181481a70 --- /dev/null +++ b/babel-preset/transforms/transform-regenerator-runtime-insertion.js @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +'use strict'; + +const babel = require('babel-core'); +const t = babel.types; + +const NAME = 'regenerator-runtime'; +const REGENERATOR_NOT_NEEDED = 'NOT_NEEDED'; +const REGENERATOR_NEEDED = 'NEEDED'; +const REGENERATOR_ALREADY_REQUIRED = 'ALREADY_REQUIRED'; + +function flagState(state) { + if (state !== REGENERATOR_ALREADY_REQUIRED) { + state.regeneratorRequired = REGENERATOR_NEEDED; + } +} + +function checkRequire(node, state) { + const method = node.callee.name; + const args = node.arguments; + + if ( + method === 'require' && + t.isStringLiteral(args[0]) && + args[0].value.startsWith(NAME) + ) { + state.regeneratorRequired = REGENERATOR_ALREADY_REQUIRED; + } +} + +function checkFunction(node, state) { + // Method is neither a generator nor an async function; skip. + if (!node.generator && !node.async) { + return; + } + + // This will only set the status to needed if it hasn't already been required. + if (state.regeneratorRequired === REGENERATOR_NOT_NEEDED) { + state.regeneratorRequired = REGENERATOR_NEEDED; + } +} + +const isGeneratorRequired = { + CallExpression(path, state) { + checkRequire(path.node, state); + }, + + FunctionDeclaration(path, state) { + checkFunction(path.node, state); + }, + + ClassMethod(path, state) { + checkFunction(path.node, state); + }, + + ArrowFunctionExpression(path, state) { + checkFunction(path.node, state); + }, + + FunctionExpression(path, state) { + checkFunction(path.node, state); + }, + + YieldExpression(path, state) { + flagState(state); + }, + + AwaitExpression(path, state) { + flagState(state); + }, +}; + +/** + * Adds a "const regeneratorRuntime = require('regenerator-runtime') to each + * file that does not include regenerator-runtime, but requires it because it + * contains async/await or generators. + */ +module.exports = function() { + return { + visitor: { + Program(path, state) { + state.regeneratorRequired = REGENERATOR_NOT_NEEDED; + path.traverse(isGeneratorRequired, state); + + if (state.regeneratorRequired === REGENERATOR_NEEDED) { + path.node.body.unshift( + t.variableDeclaration('const', [ + t.variableDeclarator( + t.identifier('regeneratorRuntime'), + t.callExpression(t.identifier('require'), [ + t.stringLiteral(NAME), + ]) + ) + ]) + ); + } + }, + }, + }; +}; diff --git a/package.json b/package.json index b27cee68cd9515..e29513f4e01cfd 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ ], "unmockedModulePathPatterns": [ "node_modules/react/", + "node_modules/regenerator-runtime/", "Libraries/Renderer", "promise", "source-map",