Project files

This commit is contained in:
2023-11-09 18:47:11 +01:00
parent 695abe054b
commit c415135aae
8554 changed files with 858111 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2014-present, Facebook, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,46 @@
# regenerator-transform
Transform async/generator functions with [regenerator](https://github.com/facebook/regenerator)
## Installation
```sh
$ npm install regenerator-transform
```
## Usage
### Via `.babelrc` (Recommended)
**.babelrc**
```js
// without options
{
"plugins": ["regenerator-transform"]
}
// with options
{
"plugins": [
["regenerator-transform", {
asyncGenerators: false, // true by default
generators: false, // true by default
async: false // true by default
}]
]
}
```
### Via CLI
```sh
$ babel --plugins regenerator-transform script.js
```
### Via Node API
```javascript
require("@babel/core").transformSync("code", {
plugins: ["regenerator-transform"]
});
```

View File

@@ -0,0 +1,43 @@
{
"name": "regenerator-transform",
"author": "Ben Newman <bn@cs.stanford.edu>",
"description": "Explode async and generator functions into a state machine.",
"version": "0.15.0",
"main": "lib/index.js",
"keywords": [
"regenerator",
"runtime",
"generator",
"async"
],
"repository": {
"type": "git",
"url": "https://github.com/facebook/regenerator/tree/master/packages/transform"
},
"license": "MIT",
"scripts": {
"prepublish": "npx babel src/ --out-dir lib/"
},
"babel": {
"plugins": [
"@babel/plugin-transform-runtime"
],
"presets": [
[
"@babel/preset-env",
{
"loose": true
}
]
]
},
"dependencies": {
"@babel/runtime": "^7.8.4"
},
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.8.4",
"@babel/plugin-transform-runtime": "^7.8.3",
"@babel/preset-env": "^7.8.4"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,161 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import * as util from "./util";
let hasOwn = Object.prototype.hasOwnProperty;
// The hoist function takes a FunctionExpression or FunctionDeclaration
// and replaces any Declaration nodes in its body with assignments, then
// returns a VariableDeclaration containing just the names of the removed
// declarations.
exports.hoist = function(funPath) {
const t = util.getTypes();
t.assertFunction(funPath.node);
let vars = {};
function varDeclToExpr({ node: vdec, scope }, includeIdentifiers) {
t.assertVariableDeclaration(vdec);
// TODO assert.equal(vdec.kind, "var");
let exprs = [];
vdec.declarations.forEach(function(dec) {
// Note: We duplicate 'dec.id' here to ensure that the variable declaration IDs don't
// have the same 'loc' value, since that can make sourcemaps and retainLines behave poorly.
vars[dec.id.name] = t.identifier(dec.id.name);
// Remove the binding, to avoid "duplicate declaration" errors when it will
// be injected again.
scope.removeBinding(dec.id.name);
if (dec.init) {
exprs.push(t.assignmentExpression(
"=", dec.id, dec.init
));
} else if (includeIdentifiers) {
exprs.push(dec.id);
}
});
if (exprs.length === 0)
return null;
if (exprs.length === 1)
return exprs[0];
return t.sequenceExpression(exprs);
}
funPath.get("body").traverse({
VariableDeclaration: {
exit: function(path) {
let expr = varDeclToExpr(path, false);
if (expr === null) {
path.remove();
} else {
// We don't need to traverse this expression any further because
// there can't be any new declarations inside an expression.
util.replaceWithOrRemove(path, t.expressionStatement(expr));
}
// Since the original node has been either removed or replaced,
// avoid traversing it any further.
path.skip();
}
},
ForStatement: function(path) {
let init = path.get("init");
if (init.isVariableDeclaration()) {
util.replaceWithOrRemove(init, varDeclToExpr(init, false));
}
},
ForXStatement: function(path) {
let left = path.get("left");
if (left.isVariableDeclaration()) {
util.replaceWithOrRemove(left, varDeclToExpr(left, true));
}
},
FunctionDeclaration: function(path) {
let node = path.node;
vars[node.id.name] = node.id;
let assignment = t.expressionStatement(
t.assignmentExpression(
"=",
t.clone(node.id),
t.functionExpression(
path.scope.generateUidIdentifierBasedOnNode(node),
node.params,
node.body,
node.generator,
node.expression
)
)
);
if (path.parentPath.isBlockStatement()) {
// Insert the assignment form before the first statement in the
// enclosing block.
path.parentPath.unshiftContainer("body", assignment);
// Remove the function declaration now that we've inserted the
// equivalent assignment form at the beginning of the block.
path.remove();
} else {
// If the parent node is not a block statement, then we can just
// replace the declaration with the equivalent assignment form
// without worrying about hoisting it.
util.replaceWithOrRemove(path, assignment);
}
// Remove the binding, to avoid "duplicate declaration" errors when it will
// be injected again.
path.scope.removeBinding(node.id.name);
// Don't hoist variables out of inner functions.
path.skip();
},
FunctionExpression: function(path) {
// Don't descend into nested function expressions.
path.skip();
},
ArrowFunctionExpression: function(path) {
// Don't descend into nested function expressions.
path.skip();
}
});
let paramNames = {};
funPath.get("params").forEach(function(paramPath) {
let param = paramPath.node;
if (t.isIdentifier(param)) {
paramNames[param.name] = param;
} else {
// Variables declared by destructuring parameter patterns will be
// harmlessly re-declared.
}
});
let declarations = [];
Object.keys(vars).forEach(function(name) {
if (!hasOwn.call(paramNames, name)) {
declarations.push(t.variableDeclarator(vars[name], null));
}
});
if (declarations.length === 0) {
return null; // Be sure to handle this case!
}
return t.variableDeclaration("var", declarations);
};

View File

@@ -0,0 +1,27 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { getVisitor } from "./visit";
export default function (context) {
const plugin = {
visitor: getVisitor(context),
};
// Some presets manually call child presets, but fail to pass along the
// context object. Out of an abundance of caution, we verify that it
// exists first to avoid causing unnecessary breaking changes.
const version = context && context.version;
// The "name" property is not allowed in older versions of Babel (6.x)
// and will cause the plugin validator to throw an exception.
if (version && parseInt(version, 10) >= 7) {
plugin.name = "regenerator-transform";
}
return plugin;
}

View File

@@ -0,0 +1,179 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import assert from "assert";
import { Emitter } from "./emit";
import { inherits } from "util";
import { getTypes } from "./util";
function Entry() {
assert.ok(this instanceof Entry);
}
function FunctionEntry(returnLoc) {
Entry.call(this);
getTypes().assertLiteral(returnLoc);
this.returnLoc = returnLoc;
}
inherits(FunctionEntry, Entry);
exports.FunctionEntry = FunctionEntry;
function LoopEntry(breakLoc, continueLoc, label) {
Entry.call(this);
const t = getTypes();
t.assertLiteral(breakLoc);
t.assertLiteral(continueLoc);
if (label) {
t.assertIdentifier(label);
} else {
label = null;
}
this.breakLoc = breakLoc;
this.continueLoc = continueLoc;
this.label = label;
}
inherits(LoopEntry, Entry);
exports.LoopEntry = LoopEntry;
function SwitchEntry(breakLoc) {
Entry.call(this);
getTypes().assertLiteral(breakLoc);
this.breakLoc = breakLoc;
}
inherits(SwitchEntry, Entry);
exports.SwitchEntry = SwitchEntry;
function TryEntry(firstLoc, catchEntry, finallyEntry) {
Entry.call(this);
const t = getTypes();
t.assertLiteral(firstLoc);
if (catchEntry) {
assert.ok(catchEntry instanceof CatchEntry);
} else {
catchEntry = null;
}
if (finallyEntry) {
assert.ok(finallyEntry instanceof FinallyEntry);
} else {
finallyEntry = null;
}
// Have to have one or the other (or both).
assert.ok(catchEntry || finallyEntry);
this.firstLoc = firstLoc;
this.catchEntry = catchEntry;
this.finallyEntry = finallyEntry;
}
inherits(TryEntry, Entry);
exports.TryEntry = TryEntry;
function CatchEntry(firstLoc, paramId) {
Entry.call(this);
const t = getTypes();
t.assertLiteral(firstLoc);
t.assertIdentifier(paramId);
this.firstLoc = firstLoc;
this.paramId = paramId;
}
inherits(CatchEntry, Entry);
exports.CatchEntry = CatchEntry;
function FinallyEntry(firstLoc, afterLoc) {
Entry.call(this);
const t = getTypes();
t.assertLiteral(firstLoc);
t.assertLiteral(afterLoc);
this.firstLoc = firstLoc;
this.afterLoc = afterLoc;
}
inherits(FinallyEntry, Entry);
exports.FinallyEntry = FinallyEntry;
function LabeledEntry(breakLoc, label) {
Entry.call(this);
const t = getTypes();
t.assertLiteral(breakLoc);
t.assertIdentifier(label);
this.breakLoc = breakLoc;
this.label = label;
}
inherits(LabeledEntry, Entry);
exports.LabeledEntry = LabeledEntry;
function LeapManager(emitter) {
assert.ok(this instanceof LeapManager);
assert.ok(emitter instanceof Emitter);
this.emitter = emitter;
this.entryStack = [new FunctionEntry(emitter.finalLoc)];
}
let LMp = LeapManager.prototype;
exports.LeapManager = LeapManager;
LMp.withEntry = function(entry, callback) {
assert.ok(entry instanceof Entry);
this.entryStack.push(entry);
try {
callback.call(this.emitter);
} finally {
let popped = this.entryStack.pop();
assert.strictEqual(popped, entry);
}
};
LMp._findLeapLocation = function(property, label) {
for (let i = this.entryStack.length - 1; i >= 0; --i) {
let entry = this.entryStack[i];
let loc = entry[property];
if (loc) {
if (label) {
if (entry.label &&
entry.label.name === label.name) {
return loc;
}
} else if (entry instanceof LabeledEntry) {
// Ignore LabeledEntry entries unless we are actually breaking to
// a label.
} else {
return loc;
}
}
}
return null;
};
LMp.getBreakLoc = function(label) {
return this._findLeapLocation("breakLoc", label);
};
LMp.getContinueLoc = function(label) {
return this._findLeapLocation("continueLoc", label);
};

View File

@@ -0,0 +1,110 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import assert from "assert";
import { getTypes } from "./util.js";
const mMap = new WeakMap();
function m(node) {
if (!mMap.has(node)) {
mMap.set(node, {});
}
return mMap.get(node);
}
const hasOwn = Object.prototype.hasOwnProperty;
function makePredicate(propertyName, knownTypes) {
function onlyChildren(node) {
const t = getTypes();
t.assertNode(node);
// Assume no side effects until we find out otherwise.
let result = false;
function check(child) {
if (result) {
// Do nothing.
} else if (Array.isArray(child)) {
child.some(check);
} else if (t.isNode(child)) {
assert.strictEqual(result, false);
result = predicate(child);
}
return result;
}
let keys = t.VISITOR_KEYS[node.type];
if (keys) {
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let child = node[key];
check(child);
}
}
return result;
}
function predicate(node) {
getTypes().assertNode(node);
let meta = m(node);
if (hasOwn.call(meta, propertyName))
return meta[propertyName];
// Certain types are "opaque," which means they have no side
// effects or leaps and we don't care about their subexpressions.
if (hasOwn.call(opaqueTypes, node.type))
return meta[propertyName] = false;
if (hasOwn.call(knownTypes, node.type))
return meta[propertyName] = true;
return meta[propertyName] = onlyChildren(node);
}
predicate.onlyChildren = onlyChildren;
return predicate;
}
let opaqueTypes = {
FunctionExpression: true,
ArrowFunctionExpression: true
};
// These types potentially have side effects regardless of what side
// effects their subexpressions have.
let sideEffectTypes = {
CallExpression: true, // Anything could happen!
ForInStatement: true, // Modifies the key variable.
UnaryExpression: true, // Think delete.
BinaryExpression: true, // Might invoke .toString() or .valueOf().
AssignmentExpression: true, // Side-effecting by definition.
UpdateExpression: true, // Updates are essentially assignments.
NewExpression: true // Similar to CallExpression.
};
// These types are the direct cause of all leaps in control flow.
let leapTypes = {
YieldExpression: true,
BreakStatement: true,
ContinueStatement: true,
ReturnStatement: true,
ThrowStatement: true
};
// All leap types are also side effect types.
for (let type in leapTypes) {
if (hasOwn.call(leapTypes, type)) {
sideEffectTypes[type] = leapTypes[type];
}
}
exports.hasSideEffects = makePredicate("hasSideEffects", sideEffectTypes);
exports.containsLeap = makePredicate("containsLeap", leapTypes);

View File

@@ -0,0 +1,82 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import * as util from "./util";
// this function converts a shorthand object generator method into a normal
// (non-shorthand) object property which is a generator function expression. for
// example, this:
//
// var foo = {
// *bar(baz) { return 5; }
// }
//
// should be replaced with:
//
// var foo = {
// bar: function*(baz) { return 5; }
// }
//
// to do this, it clones the parameter array and the body of the object generator
// method into a new FunctionExpression.
//
// this method can be passed any Function AST node path, and it will return
// either:
// a) the path that was passed in (iff the path did not need to be replaced) or
// b) the path of the new FunctionExpression that was created as a replacement
// (iff the path did need to be replaced)
//
// In either case, though, the caller can count on the fact that the return value
// is a Function AST node path.
//
// If this function is called with an AST node path that is not a Function (or with an
// argument that isn't an AST node path), it will throw an error.
export default function replaceShorthandObjectMethod(path) {
const t = util.getTypes();
if (!path.node || !t.isFunction(path.node)) {
throw new Error("replaceShorthandObjectMethod can only be called on Function AST node paths.");
}
// this function only replaces shorthand object methods (called ObjectMethod
// in Babel-speak).
if (!t.isObjectMethod(path.node)) {
return path;
}
// this function only replaces generators.
if (!path.node.generator) {
return path;
}
const parameters = path.node.params.map(function (param) {
return t.cloneDeep(param);
})
const functionExpression = t.functionExpression(
null, // id
parameters, // params
t.cloneDeep(path.node.body), // body
path.node.generator,
path.node.async
);
util.replaceWithOrRemove(path,
t.objectProperty(
t.cloneDeep(path.node.key), // key
functionExpression, //value
path.node.computed, // computed
false // shorthand
)
);
// path now refers to the ObjectProperty AST node path, but we want to return a
// Function AST node path for the function expression we created. we know that
// the FunctionExpression we just created is the value of the ObjectProperty,
// so return the "value" path off of this path.
return path.get("value");
}

View File

@@ -0,0 +1,45 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
let currentTypes = null;
export function wrapWithTypes(types, fn) {
return function (...args) {
const oldTypes = currentTypes;
currentTypes = types;
try {
return fn.apply(this, args);
} finally {
currentTypes = oldTypes;
}
};
}
export function getTypes() {
return currentTypes;
}
export function runtimeProperty(name) {
const t = getTypes();
return t.memberExpression(
t.identifier("regeneratorRuntime"),
t.identifier(name),
false
);
}
export function isReference(path) {
return path.isReferenced() || path.parentPath.isAssignmentExpression({ left: path.node });
}
export function replaceWithOrRemove(path, replacement) {
if (replacement) {
path.replaceWith(replacement)
} else {
path.remove();
}
}

View File

@@ -0,0 +1,369 @@
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
"use strict";
import assert from "assert";
import { hoist } from "./hoist";
import { Emitter } from "./emit";
import replaceShorthandObjectMethod from "./replaceShorthandObjectMethod";
import * as util from "./util";
exports.getVisitor = ({ types: t }) => ({
Method(path, state) {
let node = path.node;
if (!shouldRegenerate(node, state)) return;
const container = t.functionExpression(
null,
[],
t.cloneNode(node.body, false),
node.generator,
node.async,
);
path.get("body").set("body", [
t.returnStatement(
t.callExpression(container, []),
),
]);
// Regardless of whether or not the wrapped function is a an async method
// or generator the outer function should not be
node.async = false;
node.generator = false;
// Unwrap the wrapper IIFE's environment so super and this and such still work.
path
.get("body.body.0.argument.callee")
.unwrapFunctionEnvironment();
},
Function: {
exit: util.wrapWithTypes(t, function(path, state) {
let node = path.node;
if (!shouldRegenerate(node, state)) return;
// if this is an ObjectMethod, we need to convert it to an ObjectProperty
path = replaceShorthandObjectMethod(path);
node = path.node;
let contextId = path.scope.generateUidIdentifier("context");
let argsId = path.scope.generateUidIdentifier("args");
path.ensureBlock();
let bodyBlockPath = path.get("body");
if (node.async) {
bodyBlockPath.traverse(awaitVisitor);
}
bodyBlockPath.traverse(functionSentVisitor, {
context: contextId
});
let outerBody = [];
let innerBody = [];
bodyBlockPath.get("body").forEach(function(childPath) {
let node = childPath.node;
if (t.isExpressionStatement(node) &&
t.isStringLiteral(node.expression)) {
// Babylon represents directives like "use strict" as elements
// of a bodyBlockPath.node.directives array, but they could just
// as easily be represented (by other parsers) as traditional
// string-literal-valued expression statements, so we need to
// handle that here. (#248)
outerBody.push(node);
} else if (node && node._blockHoist != null) {
outerBody.push(node);
} else {
innerBody.push(node);
}
});
if (outerBody.length > 0) {
// Only replace the inner body if we actually hoisted any statements
// to the outer body.
bodyBlockPath.node.body = innerBody;
}
let outerFnExpr = getOuterFnExpr(path);
// Note that getOuterFnExpr has the side-effect of ensuring that the
// function has a name (so node.id will always be an Identifier), even
// if a temporary name has to be synthesized.
t.assertIdentifier(node.id);
let innerFnId = t.identifier(node.id.name + "$");
// Turn all declarations into vars, and replace the original
// declarations with equivalent assignment expressions.
let vars = hoist(path);
let context = {
usesThis: false,
usesArguments: false,
getArgsId: () => t.clone(argsId),
};
path.traverse(argumentsThisVisitor, context);
if (context.usesArguments) {
vars = vars || t.variableDeclaration("var", []);
vars.declarations.push(t.variableDeclarator(
t.clone(argsId),
t.identifier("arguments"),
));
}
let emitter = new Emitter(contextId);
emitter.explode(path.get("body"));
if (vars && vars.declarations.length > 0) {
outerBody.push(vars);
}
let wrapArgs = [emitter.getContextFunction(innerFnId)];
let tryLocsList = emitter.getTryLocsList();
if (node.generator) {
wrapArgs.push(outerFnExpr);
} else if (context.usesThis || tryLocsList || node.async) {
// Async functions that are not generators don't care about the
// outer function because they don't need it to be marked and don't
// inherit from its .prototype.
wrapArgs.push(t.nullLiteral());
}
if (context.usesThis) {
wrapArgs.push(t.thisExpression());
} else if (tryLocsList || node.async) {
wrapArgs.push(t.nullLiteral());
}
if (tryLocsList) {
wrapArgs.push(tryLocsList);
} else if (node.async) {
wrapArgs.push(t.nullLiteral());
}
if (node.async) {
// Rename any locally declared "Promise" variable,
// to use the global one.
let currentScope = path.scope;
do {
if (currentScope.hasOwnBinding("Promise")) currentScope.rename("Promise");
} while (currentScope = currentScope.parent);
wrapArgs.push(t.identifier("Promise"));
}
let wrapCall = t.callExpression(
util.runtimeProperty(node.async ? "async" : "wrap"),
wrapArgs
);
outerBody.push(t.returnStatement(wrapCall));
node.body = t.blockStatement(outerBody);
// We injected a few new variable declarations (for every hoisted var),
// so we need to add them to the scope.
path.get("body.body").forEach(p => p.scope.registerDeclaration(p));
const oldDirectives = bodyBlockPath.node.directives;
if (oldDirectives) {
// Babylon represents directives like "use strict" as elements of
// a bodyBlockPath.node.directives array. (#248)
node.body.directives = oldDirectives;
}
let wasGeneratorFunction = node.generator;
if (wasGeneratorFunction) {
node.generator = false;
}
if (node.async) {
node.async = false;
}
if (wasGeneratorFunction && t.isExpression(node)) {
util.replaceWithOrRemove(path, t.callExpression(util.runtimeProperty("mark"), [node]))
path.addComment("leading", "#__PURE__");
}
const insertedLocs = emitter.getInsertedLocs();
path.traverse({
NumericLiteral(path) {
if (!insertedLocs.has(path.node)) {
return;
}
path.replaceWith(t.numericLiteral(path.node.value));
},
})
// Generators are processed in 'exit' handlers so that regenerator only has to run on
// an ES5 AST, but that means traversal will not pick up newly inserted references
// to things like 'regeneratorRuntime'. To avoid this, we explicitly requeue.
path.requeue();
})
}
});
// Check if a node should be transformed by regenerator
function shouldRegenerate(node, state) {
if (node.generator) {
if (node.async) {
// Async generator
return state.opts.asyncGenerators !== false;
} else {
// Plain generator
return state.opts.generators !== false;
}
} else if (node.async) {
// Async function
return state.opts.async !== false;
} else {
// Not a generator or async function.
return false;
}
}
// Given a NodePath for a Function, return an Expression node that can be
// used to refer reliably to the function object from inside the function.
// This expression is essentially a replacement for arguments.callee, with
// the key advantage that it works in strict mode.
function getOuterFnExpr(funPath) {
const t = util.getTypes();
let node = funPath.node;
t.assertFunction(node);
if (!node.id) {
// Default-exported function declarations, and function expressions may not
// have a name to reference, so we explicitly add one.
node.id = funPath.scope.parent.generateUidIdentifier("callee");
}
if (node.generator && // Non-generator functions don't need to be marked.
t.isFunctionDeclaration(node)) {
// Return the identifier returned by runtime.mark(<node.id>).
return getMarkedFunctionId(funPath);
}
return t.clone(node.id);
}
const markInfo = new WeakMap();
function getMarkInfo(node) {
if (!markInfo.has(node)) {
markInfo.set(node, {});
}
return markInfo.get(node);
}
function getMarkedFunctionId(funPath) {
const t = util.getTypes();
const node = funPath.node;
t.assertIdentifier(node.id);
const blockPath = funPath.findParent(function (path) {
return path.isProgram() || path.isBlockStatement();
});
if (!blockPath) {
return node.id;
}
const block = blockPath.node;
assert.ok(Array.isArray(block.body));
const info = getMarkInfo(block);
if (!info.decl) {
info.decl = t.variableDeclaration("var", []);
blockPath.unshiftContainer("body", info.decl);
info.declPath = blockPath.get("body.0");
}
assert.strictEqual(info.declPath.node, info.decl);
// Get a new unique identifier for our marked variable.
const markedId = blockPath.scope.generateUidIdentifier("marked");
const markCallExp = t.callExpression(
util.runtimeProperty("mark"),
[t.clone(node.id)]
);
const index = info.decl.declarations.push(
t.variableDeclarator(markedId, markCallExp)
) - 1;
const markCallExpPath =
info.declPath.get("declarations." + index + ".init");
assert.strictEqual(markCallExpPath.node, markCallExp);
markCallExpPath.addComment("leading", "#__PURE__");
return t.clone(markedId);
}
let argumentsThisVisitor = {
"FunctionExpression|FunctionDeclaration|Method": function(path) {
path.skip();
},
Identifier: function(path, state) {
if (path.node.name === "arguments" && util.isReference(path)) {
util.replaceWithOrRemove(path, state.getArgsId());
state.usesArguments = true;
}
},
ThisExpression: function(path, state) {
state.usesThis = true;
}
};
let functionSentVisitor = {
MetaProperty(path) {
let { node } = path;
if (node.meta.name === "function" &&
node.property.name === "sent") {
const t = util.getTypes();
util.replaceWithOrRemove(
path,
t.memberExpression(
t.clone(this.context),
t.identifier("_sent")
)
);
}
}
};
let awaitVisitor = {
Function: function(path) {
path.skip(); // Don't descend into nested function scopes.
},
AwaitExpression: function(path) {
const t = util.getTypes();
// Convert await expressions to yield expressions.
let argument = path.node.argument;
// Transforming `await x` to `yield regeneratorRuntime.awrap(x)`
// causes the argument to be wrapped in such a way that the runtime
// can distinguish between awaited and merely yielded values.
util.replaceWithOrRemove(path, t.yieldExpression(
t.callExpression(
util.runtimeProperty("awrap"),
[argument]
),
false
));
}
};