From e06ec920f7a5d784e674c4c4b4e6d1da3dc7391d Mon Sep 17 00:00:00 2001 From: Piotr Russ Date: Mon, 16 Nov 2020 00:10:28 +0100 Subject: api, login, auth --- node_modules/regenerator-transform/.npmignore | 1 + node_modules/regenerator-transform/README.md | 46 + node_modules/regenerator-transform/lib/emit.js | 996 ++++++++++++++++ node_modules/regenerator-transform/lib/hoist.js | 151 +++ node_modules/regenerator-transform/lib/index.js | 22 + node_modules/regenerator-transform/lib/leap.js | 183 +++ node_modules/regenerator-transform/lib/meta.js | 112 ++ .../lib/replaceShorthandObjectMethod.js | 80 ++ node_modules/regenerator-transform/lib/util.js | 36 + node_modules/regenerator-transform/lib/visit.js | 290 +++++ node_modules/regenerator-transform/package.json | 72 ++ node_modules/regenerator-transform/src/emit.js | 1184 ++++++++++++++++++++ node_modules/regenerator-transform/src/hoist.js | 151 +++ node_modules/regenerator-transform/src/index.js | 28 + node_modules/regenerator-transform/src/leap.js | 174 +++ node_modules/regenerator-transform/src/meta.js | 104 ++ .../src/replaceShorthandObjectMethod.js | 74 ++ node_modules/regenerator-transform/src/util.js | 31 + node_modules/regenerator-transform/src/visit.js | 293 +++++ 19 files changed, 4028 insertions(+) create mode 100644 node_modules/regenerator-transform/.npmignore create mode 100644 node_modules/regenerator-transform/README.md create mode 100644 node_modules/regenerator-transform/lib/emit.js create mode 100644 node_modules/regenerator-transform/lib/hoist.js create mode 100644 node_modules/regenerator-transform/lib/index.js create mode 100644 node_modules/regenerator-transform/lib/leap.js create mode 100644 node_modules/regenerator-transform/lib/meta.js create mode 100644 node_modules/regenerator-transform/lib/replaceShorthandObjectMethod.js create mode 100644 node_modules/regenerator-transform/lib/util.js create mode 100644 node_modules/regenerator-transform/lib/visit.js create mode 100644 node_modules/regenerator-transform/package.json create mode 100644 node_modules/regenerator-transform/src/emit.js create mode 100644 node_modules/regenerator-transform/src/hoist.js create mode 100644 node_modules/regenerator-transform/src/index.js create mode 100644 node_modules/regenerator-transform/src/leap.js create mode 100644 node_modules/regenerator-transform/src/meta.js create mode 100644 node_modules/regenerator-transform/src/replaceShorthandObjectMethod.js create mode 100644 node_modules/regenerator-transform/src/util.js create mode 100644 node_modules/regenerator-transform/src/visit.js (limited to 'node_modules/regenerator-transform') diff --git a/node_modules/regenerator-transform/.npmignore b/node_modules/regenerator-transform/.npmignore new file mode 100644 index 0000000..07e6e47 --- /dev/null +++ b/node_modules/regenerator-transform/.npmignore @@ -0,0 +1 @@ +/node_modules diff --git a/node_modules/regenerator-transform/README.md b/node_modules/regenerator-transform/README.md new file mode 100644 index 0000000..1b09792 --- /dev/null +++ b/node_modules/regenerator-transform/README.md @@ -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").transform("code", { + plugins: ["regenerator-transform"] +}); +``` diff --git a/node_modules/regenerator-transform/lib/emit.js b/node_modules/regenerator-transform/lib/emit.js new file mode 100644 index 0000000..6d3c4ec --- /dev/null +++ b/node_modules/regenerator-transform/lib/emit.js @@ -0,0 +1,996 @@ +"use strict"; + +var _stringify = require("babel-runtime/core-js/json/stringify"); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _assert = require("assert"); + +var _assert2 = _interopRequireDefault(_assert); + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +var _leap = require("./leap"); + +var leap = _interopRequireWildcard(_leap); + +var _meta = require("./meta"); + +var meta = _interopRequireWildcard(_meta); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var hasOwn = Object.prototype.hasOwnProperty; /** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +function Emitter(contextId) { + _assert2.default.ok(this instanceof Emitter); + t.assertIdentifier(contextId); + + // Used to generate unique temporary names. + this.nextTempId = 0; + + // In order to make sure the context object does not collide with + // anything in the local scope, we might have to rename it, so we + // refer to it symbolically instead of just assuming that it will be + // called "context". + this.contextId = contextId; + + // An append-only list of Statements that grows each time this.emit is + // called. + this.listing = []; + + // A sparse array whose keys correspond to locations in this.listing + // that have been marked as branch/jump targets. + this.marked = [true]; + + // The last location will be marked when this.getDispatchLoop is + // called. + this.finalLoc = loc(); + + // A list of all leap.TryEntry statements emitted. + this.tryEntries = []; + + // Each time we evaluate the body of a loop, we tell this.leapManager + // to enter a nested loop context that determines the meaning of break + // and continue statements therein. + this.leapManager = new leap.LeapManager(this); +} + +var Ep = Emitter.prototype; +exports.Emitter = Emitter; + +// Offsets into this.listing that could be used as targets for branches or +// jumps are represented as numeric Literal nodes. This representation has +// the amazingly convenient benefit of allowing the exact value of the +// location to be determined at any time, even after generating code that +// refers to the location. +function loc() { + return t.numericLiteral(-1); +} + +// Sets the exact value of the given location to the offset of the next +// Statement emitted. +Ep.mark = function (loc) { + t.assertLiteral(loc); + var index = this.listing.length; + if (loc.value === -1) { + loc.value = index; + } else { + // Locations can be marked redundantly, but their values cannot change + // once set the first time. + _assert2.default.strictEqual(loc.value, index); + } + this.marked[index] = true; + return loc; +}; + +Ep.emit = function (node) { + if (t.isExpression(node)) { + node = t.expressionStatement(node); + } + + t.assertStatement(node); + this.listing.push(node); +}; + +// Shorthand for emitting assignment statements. This will come in handy +// for assignments to temporary variables. +Ep.emitAssign = function (lhs, rhs) { + this.emit(this.assign(lhs, rhs)); + return lhs; +}; + +// Shorthand for an assignment statement. +Ep.assign = function (lhs, rhs) { + return t.expressionStatement(t.assignmentExpression("=", lhs, rhs)); +}; + +// Convenience function for generating expressions like context.next, +// context.sent, and context.rval. +Ep.contextProperty = function (name, computed) { + return t.memberExpression(this.contextId, computed ? t.stringLiteral(name) : t.identifier(name), !!computed); +}; + +// Shorthand for setting context.rval and jumping to `context.stop()`. +Ep.stop = function (rval) { + if (rval) { + this.setReturnValue(rval); + } + + this.jump(this.finalLoc); +}; + +Ep.setReturnValue = function (valuePath) { + t.assertExpression(valuePath.value); + + this.emitAssign(this.contextProperty("rval"), this.explodeExpression(valuePath)); +}; + +Ep.clearPendingException = function (tryLoc, assignee) { + t.assertLiteral(tryLoc); + + var catchCall = t.callExpression(this.contextProperty("catch", true), [tryLoc]); + + if (assignee) { + this.emitAssign(assignee, catchCall); + } else { + this.emit(catchCall); + } +}; + +// Emits code for an unconditional jump to the given location, even if the +// exact value of the location is not yet known. +Ep.jump = function (toLoc) { + this.emitAssign(this.contextProperty("next"), toLoc); + this.emit(t.breakStatement()); +}; + +// Conditional jump. +Ep.jumpIf = function (test, toLoc) { + t.assertExpression(test); + t.assertLiteral(toLoc); + + this.emit(t.ifStatement(test, t.blockStatement([this.assign(this.contextProperty("next"), toLoc), t.breakStatement()]))); +}; + +// Conditional jump, with the condition negated. +Ep.jumpIfNot = function (test, toLoc) { + t.assertExpression(test); + t.assertLiteral(toLoc); + + var negatedTest = void 0; + if (t.isUnaryExpression(test) && test.operator === "!") { + // Avoid double negation. + negatedTest = test.argument; + } else { + negatedTest = t.unaryExpression("!", test); + } + + this.emit(t.ifStatement(negatedTest, t.blockStatement([this.assign(this.contextProperty("next"), toLoc), t.breakStatement()]))); +}; + +// Returns a unique MemberExpression that can be used to store and +// retrieve temporary values. Since the object of the member expression is +// the context object, which is presumed to coexist peacefully with all +// other local variables, and since we just increment `nextTempId` +// monotonically, uniqueness is assured. +Ep.makeTempVar = function () { + return this.contextProperty("t" + this.nextTempId++); +}; + +Ep.getContextFunction = function (id) { + return t.functionExpression(id || null /*Anonymous*/ + , [this.contextId], t.blockStatement([this.getDispatchLoop()]), false, // Not a generator anymore! + false // Nor an expression. + ); +}; + +// Turns this.listing into a loop of the form +// +// while (1) switch (context.next) { +// case 0: +// ... +// case n: +// return context.stop(); +// } +// +// Each marked location in this.listing will correspond to one generated +// case statement. +Ep.getDispatchLoop = function () { + var self = this; + var cases = []; + var current = void 0; + + // If we encounter a break, continue, or return statement in a switch + // case, we can skip the rest of the statements until the next case. + var alreadyEnded = false; + + self.listing.forEach(function (stmt, i) { + if (self.marked.hasOwnProperty(i)) { + cases.push(t.switchCase(t.numericLiteral(i), current = [])); + alreadyEnded = false; + } + + if (!alreadyEnded) { + current.push(stmt); + if (t.isCompletionStatement(stmt)) alreadyEnded = true; + } + }); + + // Now that we know how many statements there will be in this.listing, + // we can finally resolve this.finalLoc.value. + this.finalLoc.value = this.listing.length; + + cases.push(t.switchCase(this.finalLoc, [ + // Intentionally fall through to the "end" case... + ]), + + // So that the runtime can jump to the final location without having + // to know its offset, we provide the "end" case as a synonym. + t.switchCase(t.stringLiteral("end"), [ + // This will check/clear both context.thrown and context.rval. + t.returnStatement(t.callExpression(this.contextProperty("stop"), []))])); + + return t.whileStatement(t.numericLiteral(1), t.switchStatement(t.assignmentExpression("=", this.contextProperty("prev"), this.contextProperty("next")), cases)); +}; + +Ep.getTryLocsList = function () { + if (this.tryEntries.length === 0) { + // To avoid adding a needless [] to the majority of runtime.wrap + // argument lists, force the caller to handle this case specially. + return null; + } + + var lastLocValue = 0; + + return t.arrayExpression(this.tryEntries.map(function (tryEntry) { + var thisLocValue = tryEntry.firstLoc.value; + _assert2.default.ok(thisLocValue >= lastLocValue, "try entries out of order"); + lastLocValue = thisLocValue; + + var ce = tryEntry.catchEntry; + var fe = tryEntry.finallyEntry; + + var locs = [tryEntry.firstLoc, + // The null here makes a hole in the array. + ce ? ce.firstLoc : null]; + + if (fe) { + locs[2] = fe.firstLoc; + locs[3] = fe.afterLoc; + } + + return t.arrayExpression(locs); + })); +}; + +// All side effects must be realized in order. + +// If any subexpression harbors a leap, all subexpressions must be +// neutered of side effects. + +// No destructive modification of AST nodes. + +Ep.explode = function (path, ignoreResult) { + var node = path.node; + var self = this; + + t.assertNode(node); + + if (t.isDeclaration(node)) throw getDeclError(node); + + if (t.isStatement(node)) return self.explodeStatement(path); + + if (t.isExpression(node)) return self.explodeExpression(path, ignoreResult); + + switch (node.type) { + case "Program": + return path.get("body").map(self.explodeStatement, self); + + case "VariableDeclarator": + throw getDeclError(node); + + // These node types should be handled by their parent nodes + // (ObjectExpression, SwitchStatement, and TryStatement, respectively). + case "Property": + case "SwitchCase": + case "CatchClause": + throw new Error(node.type + " nodes should be handled by their parents"); + + default: + throw new Error("unknown Node of type " + (0, _stringify2.default)(node.type)); + } +}; + +function getDeclError(node) { + return new Error("all declarations should have been transformed into " + "assignments before the Exploder began its work: " + (0, _stringify2.default)(node)); +} + +Ep.explodeStatement = function (path, labelId) { + var stmt = path.node; + var self = this; + var before = void 0, + after = void 0, + head = void 0; + + t.assertStatement(stmt); + + if (labelId) { + t.assertIdentifier(labelId); + } else { + labelId = null; + } + + // Explode BlockStatement nodes even if they do not contain a yield, + // because we don't want or need the curly braces. + if (t.isBlockStatement(stmt)) { + path.get("body").forEach(function (path) { + self.explodeStatement(path); + }); + return; + } + + if (!meta.containsLeap(stmt)) { + // Technically we should be able to avoid emitting the statement + // altogether if !meta.hasSideEffects(stmt), but that leads to + // confusing generated code (for instance, `while (true) {}` just + // disappears) and is probably a more appropriate job for a dedicated + // dead code elimination pass. + self.emit(stmt); + return; + } + + switch (stmt.type) { + case "ExpressionStatement": + self.explodeExpression(path.get("expression"), true); + break; + + case "LabeledStatement": + after = loc(); + + // Did you know you can break from any labeled block statement or + // control structure? Well, you can! Note: when a labeled loop is + // encountered, the leap.LabeledEntry created here will immediately + // enclose a leap.LoopEntry on the leap manager's stack, and both + // entries will have the same label. Though this works just fine, it + // may seem a bit redundant. In theory, we could check here to + // determine if stmt knows how to handle its own label; for example, + // stmt happens to be a WhileStatement and so we know it's going to + // establish its own LoopEntry when we explode it (below). Then this + // LabeledEntry would be unnecessary. Alternatively, we might be + // tempted not to pass stmt.label down into self.explodeStatement, + // because we've handled the label here, but that's a mistake because + // labeled loops may contain labeled continue statements, which is not + // something we can handle in this generic case. All in all, I think a + // little redundancy greatly simplifies the logic of this case, since + // it's clear that we handle all possible LabeledStatements correctly + // here, regardless of whether they interact with the leap manager + // themselves. Also remember that labels and break/continue-to-label + // statements are rare, and all of this logic happens at transform + // time, so it has no additional runtime cost. + self.leapManager.withEntry(new leap.LabeledEntry(after, stmt.label), function () { + self.explodeStatement(path.get("body"), stmt.label); + }); + + self.mark(after); + + break; + + case "WhileStatement": + before = loc(); + after = loc(); + + self.mark(before); + self.jumpIfNot(self.explodeExpression(path.get("test")), after); + self.leapManager.withEntry(new leap.LoopEntry(after, before, labelId), function () { + self.explodeStatement(path.get("body")); + }); + self.jump(before); + self.mark(after); + + break; + + case "DoWhileStatement": + var first = loc(); + var test = loc(); + after = loc(); + + self.mark(first); + self.leapManager.withEntry(new leap.LoopEntry(after, test, labelId), function () { + self.explode(path.get("body")); + }); + self.mark(test); + self.jumpIf(self.explodeExpression(path.get("test")), first); + self.mark(after); + + break; + + case "ForStatement": + head = loc(); + var update = loc(); + after = loc(); + + if (stmt.init) { + // We pass true here to indicate that if stmt.init is an expression + // then we do not care about its result. + self.explode(path.get("init"), true); + } + + self.mark(head); + + if (stmt.test) { + self.jumpIfNot(self.explodeExpression(path.get("test")), after); + } else { + // No test means continue unconditionally. + } + + self.leapManager.withEntry(new leap.LoopEntry(after, update, labelId), function () { + self.explodeStatement(path.get("body")); + }); + + self.mark(update); + + if (stmt.update) { + // We pass true here to indicate that if stmt.update is an + // expression then we do not care about its result. + self.explode(path.get("update"), true); + } + + self.jump(head); + + self.mark(after); + + break; + + case "TypeCastExpression": + return self.explodeExpression(path.get("expression")); + + case "ForInStatement": + head = loc(); + after = loc(); + + var keyIterNextFn = self.makeTempVar(); + self.emitAssign(keyIterNextFn, t.callExpression(util.runtimeProperty("keys"), [self.explodeExpression(path.get("right"))])); + + self.mark(head); + + var keyInfoTmpVar = self.makeTempVar(); + self.jumpIf(t.memberExpression(t.assignmentExpression("=", keyInfoTmpVar, t.callExpression(keyIterNextFn, [])), t.identifier("done"), false), after); + + self.emitAssign(stmt.left, t.memberExpression(keyInfoTmpVar, t.identifier("value"), false)); + + self.leapManager.withEntry(new leap.LoopEntry(after, head, labelId), function () { + self.explodeStatement(path.get("body")); + }); + + self.jump(head); + + self.mark(after); + + break; + + case "BreakStatement": + self.emitAbruptCompletion({ + type: "break", + target: self.leapManager.getBreakLoc(stmt.label) + }); + + break; + + case "ContinueStatement": + self.emitAbruptCompletion({ + type: "continue", + target: self.leapManager.getContinueLoc(stmt.label) + }); + + break; + + case "SwitchStatement": + // Always save the discriminant into a temporary variable in case the + // test expressions overwrite values like context.sent. + var disc = self.emitAssign(self.makeTempVar(), self.explodeExpression(path.get("discriminant"))); + + after = loc(); + var defaultLoc = loc(); + var condition = defaultLoc; + var caseLocs = []; + + // If there are no cases, .cases might be undefined. + var cases = stmt.cases || []; + + for (var i = cases.length - 1; i >= 0; --i) { + var c = cases[i]; + t.assertSwitchCase(c); + + if (c.test) { + condition = t.conditionalExpression(t.binaryExpression("===", disc, c.test), caseLocs[i] = loc(), condition); + } else { + caseLocs[i] = defaultLoc; + } + } + + var discriminant = path.get("discriminant"); + util.replaceWithOrRemove(discriminant, condition); + self.jump(self.explodeExpression(discriminant)); + + self.leapManager.withEntry(new leap.SwitchEntry(after), function () { + path.get("cases").forEach(function (casePath) { + var i = casePath.key; + self.mark(caseLocs[i]); + + casePath.get("consequent").forEach(function (path) { + self.explodeStatement(path); + }); + }); + }); + + self.mark(after); + if (defaultLoc.value === -1) { + self.mark(defaultLoc); + _assert2.default.strictEqual(after.value, defaultLoc.value); + } + + break; + + case "IfStatement": + var elseLoc = stmt.alternate && loc(); + after = loc(); + + self.jumpIfNot(self.explodeExpression(path.get("test")), elseLoc || after); + + self.explodeStatement(path.get("consequent")); + + if (elseLoc) { + self.jump(after); + self.mark(elseLoc); + self.explodeStatement(path.get("alternate")); + } + + self.mark(after); + + break; + + case "ReturnStatement": + self.emitAbruptCompletion({ + type: "return", + value: self.explodeExpression(path.get("argument")) + }); + + break; + + case "WithStatement": + throw new Error("WithStatement not supported in generator functions."); + + case "TryStatement": + after = loc(); + + var handler = stmt.handler; + + var catchLoc = handler && loc(); + var catchEntry = catchLoc && new leap.CatchEntry(catchLoc, handler.param); + + var finallyLoc = stmt.finalizer && loc(); + var finallyEntry = finallyLoc && new leap.FinallyEntry(finallyLoc, after); + + var tryEntry = new leap.TryEntry(self.getUnmarkedCurrentLoc(), catchEntry, finallyEntry); + + self.tryEntries.push(tryEntry); + self.updateContextPrevLoc(tryEntry.firstLoc); + + self.leapManager.withEntry(tryEntry, function () { + self.explodeStatement(path.get("block")); + + if (catchLoc) { + if (finallyLoc) { + // If we have both a catch block and a finally block, then + // because we emit the catch block first, we need to jump over + // it to the finally block. + self.jump(finallyLoc); + } else { + // If there is no finally block, then we need to jump over the + // catch block to the fall-through location. + self.jump(after); + } + + self.updateContextPrevLoc(self.mark(catchLoc)); + + var bodyPath = path.get("handler.body"); + var safeParam = self.makeTempVar(); + self.clearPendingException(tryEntry.firstLoc, safeParam); + + bodyPath.traverse(catchParamVisitor, { + safeParam: safeParam, + catchParamName: handler.param.name + }); + + self.leapManager.withEntry(catchEntry, function () { + self.explodeStatement(bodyPath); + }); + } + + if (finallyLoc) { + self.updateContextPrevLoc(self.mark(finallyLoc)); + + self.leapManager.withEntry(finallyEntry, function () { + self.explodeStatement(path.get("finalizer")); + }); + + self.emit(t.returnStatement(t.callExpression(self.contextProperty("finish"), [finallyEntry.firstLoc]))); + } + }); + + self.mark(after); + + break; + + case "ThrowStatement": + self.emit(t.throwStatement(self.explodeExpression(path.get("argument")))); + + break; + + default: + throw new Error("unknown Statement of type " + (0, _stringify2.default)(stmt.type)); + } +}; + +var catchParamVisitor = { + Identifier: function Identifier(path, state) { + if (path.node.name === state.catchParamName && util.isReference(path)) { + util.replaceWithOrRemove(path, state.safeParam); + } + }, + + Scope: function Scope(path, state) { + if (path.scope.hasOwnBinding(state.catchParamName)) { + // Don't descend into nested scopes that shadow the catch + // parameter with their own declarations. + path.skip(); + } + } +}; + +Ep.emitAbruptCompletion = function (record) { + if (!isValidCompletion(record)) { + _assert2.default.ok(false, "invalid completion record: " + (0, _stringify2.default)(record)); + } + + _assert2.default.notStrictEqual(record.type, "normal", "normal completions are not abrupt"); + + var abruptArgs = [t.stringLiteral(record.type)]; + + if (record.type === "break" || record.type === "continue") { + t.assertLiteral(record.target); + abruptArgs[1] = record.target; + } else if (record.type === "return" || record.type === "throw") { + if (record.value) { + t.assertExpression(record.value); + abruptArgs[1] = record.value; + } + } + + this.emit(t.returnStatement(t.callExpression(this.contextProperty("abrupt"), abruptArgs))); +}; + +function isValidCompletion(record) { + var type = record.type; + + if (type === "normal") { + return !hasOwn.call(record, "target"); + } + + if (type === "break" || type === "continue") { + return !hasOwn.call(record, "value") && t.isLiteral(record.target); + } + + if (type === "return" || type === "throw") { + return hasOwn.call(record, "value") && !hasOwn.call(record, "target"); + } + + return false; +} + +// Not all offsets into emitter.listing are potential jump targets. For +// example, execution typically falls into the beginning of a try block +// without jumping directly there. This method returns the current offset +// without marking it, so that a switch case will not necessarily be +// generated for this offset (I say "not necessarily" because the same +// location might end up being marked in the process of emitting other +// statements). There's no logical harm in marking such locations as jump +// targets, but minimizing the number of switch cases keeps the generated +// code shorter. +Ep.getUnmarkedCurrentLoc = function () { + return t.numericLiteral(this.listing.length); +}; + +// The context.prev property takes the value of context.next whenever we +// evaluate the switch statement discriminant, which is generally good +// enough for tracking the last location we jumped to, but sometimes +// context.prev needs to be more precise, such as when we fall +// successfully out of a try block and into a finally block without +// jumping. This method exists to update context.prev to the freshest +// available location. If we were implementing a full interpreter, we +// would know the location of the current instruction with complete +// precision at all times, but we don't have that luxury here, as it would +// be costly and verbose to set context.prev before every statement. +Ep.updateContextPrevLoc = function (loc) { + if (loc) { + t.assertLiteral(loc); + + if (loc.value === -1) { + // If an uninitialized location literal was passed in, set its value + // to the current this.listing.length. + loc.value = this.listing.length; + } else { + // Otherwise assert that the location matches the current offset. + _assert2.default.strictEqual(loc.value, this.listing.length); + } + } else { + loc = this.getUnmarkedCurrentLoc(); + } + + // Make sure context.prev is up to date in case we fell into this try + // statement without jumping to it. TODO Consider avoiding this + // assignment when we know control must have jumped here. + this.emitAssign(this.contextProperty("prev"), loc); +}; + +Ep.explodeExpression = function (path, ignoreResult) { + var expr = path.node; + if (expr) { + t.assertExpression(expr); + } else { + return expr; + } + + var self = this; + var result = void 0; // Used optionally by several cases below. + var after = void 0; + + function finish(expr) { + t.assertExpression(expr); + if (ignoreResult) { + self.emit(expr); + } else { + return expr; + } + } + + // If the expression does not contain a leap, then we either emit the + // expression as a standalone statement or return it whole. + if (!meta.containsLeap(expr)) { + return finish(expr); + } + + // If any child contains a leap (such as a yield or labeled continue or + // break statement), then any sibling subexpressions will almost + // certainly have to be exploded in order to maintain the order of their + // side effects relative to the leaping child(ren). + var hasLeapingChildren = meta.containsLeap.onlyChildren(expr); + + // In order to save the rest of explodeExpression from a combinatorial + // trainwreck of special cases, explodeViaTempVar is responsible for + // deciding when a subexpression needs to be "exploded," which is my + // very technical term for emitting the subexpression as an assignment + // to a temporary variable and the substituting the temporary variable + // for the original subexpression. Think of exploded view diagrams, not + // Michael Bay movies. The point of exploding subexpressions is to + // control the precise order in which the generated code realizes the + // side effects of those subexpressions. + function explodeViaTempVar(tempVar, childPath, ignoreChildResult) { + _assert2.default.ok(!ignoreChildResult || !tempVar, "Ignoring the result of a child expression but forcing it to " + "be assigned to a temporary variable?"); + + var result = self.explodeExpression(childPath, ignoreChildResult); + + if (ignoreChildResult) { + // Side effects already emitted above. + + } else if (tempVar || hasLeapingChildren && !t.isLiteral(result)) { + // If tempVar was provided, then the result will always be assigned + // to it, even if the result does not otherwise need to be assigned + // to a temporary variable. When no tempVar is provided, we have + // the flexibility to decide whether a temporary variable is really + // necessary. Unfortunately, in general, a temporary variable is + // required whenever any child contains a yield expression, since it + // is difficult to prove (at all, let alone efficiently) whether + // this result would evaluate to the same value before and after the + // yield (see #206). One narrow case where we can prove it doesn't + // matter (and thus we do not need a temporary variable) is when the + // result in question is a Literal value. + result = self.emitAssign(tempVar || self.makeTempVar(), result); + } + return result; + } + + // If ignoreResult is true, then we must take full responsibility for + // emitting the expression with all its side effects, and we should not + // return a result. + + switch (expr.type) { + case "MemberExpression": + return finish(t.memberExpression(self.explodeExpression(path.get("object")), expr.computed ? explodeViaTempVar(null, path.get("property")) : expr.property, expr.computed)); + + case "CallExpression": + var calleePath = path.get("callee"); + var argsPath = path.get("arguments"); + + var newCallee = void 0; + var newArgs = []; + + var hasLeapingArgs = false; + argsPath.forEach(function (argPath) { + hasLeapingArgs = hasLeapingArgs || meta.containsLeap(argPath.node); + }); + + if (t.isMemberExpression(calleePath.node)) { + if (hasLeapingArgs) { + // If the arguments of the CallExpression contained any yield + // expressions, then we need to be sure to evaluate the callee + // before evaluating the arguments, but if the callee was a member + // expression, then we must be careful that the object of the + // member expression still gets bound to `this` for the call. + + var newObject = explodeViaTempVar( + // Assign the exploded callee.object expression to a temporary + // variable so that we can use it twice without reevaluating it. + self.makeTempVar(), calleePath.get("object")); + + var newProperty = calleePath.node.computed ? explodeViaTempVar(null, calleePath.get("property")) : calleePath.node.property; + + newArgs.unshift(newObject); + + newCallee = t.memberExpression(t.memberExpression(newObject, newProperty, calleePath.node.computed), t.identifier("call"), false); + } else { + newCallee = self.explodeExpression(calleePath); + } + } else { + newCallee = explodeViaTempVar(null, calleePath); + + if (t.isMemberExpression(newCallee)) { + // If the callee was not previously a MemberExpression, then the + // CallExpression was "unqualified," meaning its `this` object + // should be the global object. If the exploded expression has + // become a MemberExpression (e.g. a context property, probably a + // temporary variable), then we need to force it to be unqualified + // by using the (0, object.property)(...) trick; otherwise, it + // will receive the object of the MemberExpression as its `this` + // object. + newCallee = t.sequenceExpression([t.numericLiteral(0), newCallee]); + } + } + + argsPath.forEach(function (argPath) { + newArgs.push(explodeViaTempVar(null, argPath)); + }); + + return finish(t.callExpression(newCallee, newArgs)); + + case "NewExpression": + return finish(t.newExpression(explodeViaTempVar(null, path.get("callee")), path.get("arguments").map(function (argPath) { + return explodeViaTempVar(null, argPath); + }))); + + case "ObjectExpression": + return finish(t.objectExpression(path.get("properties").map(function (propPath) { + if (propPath.isObjectProperty()) { + return t.objectProperty(propPath.node.key, explodeViaTempVar(null, propPath.get("value")), propPath.node.computed); + } else { + return propPath.node; + } + }))); + + case "ArrayExpression": + return finish(t.arrayExpression(path.get("elements").map(function (elemPath) { + return explodeViaTempVar(null, elemPath); + }))); + + case "SequenceExpression": + var lastIndex = expr.expressions.length - 1; + + path.get("expressions").forEach(function (exprPath) { + if (exprPath.key === lastIndex) { + result = self.explodeExpression(exprPath, ignoreResult); + } else { + self.explodeExpression(exprPath, true); + } + }); + + return result; + + case "LogicalExpression": + after = loc(); + + if (!ignoreResult) { + result = self.makeTempVar(); + } + + var left = explodeViaTempVar(result, path.get("left")); + + if (expr.operator === "&&") { + self.jumpIfNot(left, after); + } else { + _assert2.default.strictEqual(expr.operator, "||"); + self.jumpIf(left, after); + } + + explodeViaTempVar(result, path.get("right"), ignoreResult); + + self.mark(after); + + return result; + + case "ConditionalExpression": + var elseLoc = loc(); + after = loc(); + var test = self.explodeExpression(path.get("test")); + + self.jumpIfNot(test, elseLoc); + + if (!ignoreResult) { + result = self.makeTempVar(); + } + + explodeViaTempVar(result, path.get("consequent"), ignoreResult); + self.jump(after); + + self.mark(elseLoc); + explodeViaTempVar(result, path.get("alternate"), ignoreResult); + + self.mark(after); + + return result; + + case "UnaryExpression": + return finish(t.unaryExpression(expr.operator, + // Can't (and don't need to) break up the syntax of the argument. + // Think about delete a[b]. + self.explodeExpression(path.get("argument")), !!expr.prefix)); + + case "BinaryExpression": + return finish(t.binaryExpression(expr.operator, explodeViaTempVar(null, path.get("left")), explodeViaTempVar(null, path.get("right")))); + + case "AssignmentExpression": + return finish(t.assignmentExpression(expr.operator, self.explodeExpression(path.get("left")), self.explodeExpression(path.get("right")))); + + case "UpdateExpression": + return finish(t.updateExpression(expr.operator, self.explodeExpression(path.get("argument")), expr.prefix)); + + case "YieldExpression": + after = loc(); + var arg = expr.argument && self.explodeExpression(path.get("argument")); + + if (arg && expr.delegate) { + var _result = self.makeTempVar(); + + self.emit(t.returnStatement(t.callExpression(self.contextProperty("delegateYield"), [arg, t.stringLiteral(_result.property.name), after]))); + + self.mark(after); + + return _result; + } + + self.emitAssign(self.contextProperty("next"), after); + self.emit(t.returnStatement(arg || null)); + self.mark(after); + + return self.contextProperty("sent"); + + default: + throw new Error("unknown Expression of type " + (0, _stringify2.default)(expr.type)); + } +}; \ No newline at end of file diff --git a/node_modules/regenerator-transform/lib/hoist.js b/node_modules/regenerator-transform/lib/hoist.js new file mode 100644 index 0000000..8aff3f4 --- /dev/null +++ b/node_modules/regenerator-transform/lib/hoist.js @@ -0,0 +1,151 @@ +"use strict"; + +var _keys = require("babel-runtime/core-js/object/keys"); + +var _keys2 = _interopRequireDefault(_keys); + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +var 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) { + t.assertFunction(funPath.node); + + var vars = {}; + + function varDeclToExpr(vdec, includeIdentifiers) { + t.assertVariableDeclaration(vdec); + // TODO assert.equal(vdec.kind, "var"); + var 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); + + 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 exit(path) { + var expr = varDeclToExpr(path.node, 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 ForStatement(path) { + var init = path.node.init; + if (t.isVariableDeclaration(init)) { + util.replaceWithOrRemove(path.get("init"), varDeclToExpr(init, false)); + } + }, + + ForXStatement: function ForXStatement(path) { + var left = path.get("left"); + if (left.isVariableDeclaration()) { + util.replaceWithOrRemove(left, varDeclToExpr(left.node, true)); + } + }, + + FunctionDeclaration: function FunctionDeclaration(path) { + var node = path.node; + vars[node.id.name] = node.id; + + var assignment = t.expressionStatement(t.assignmentExpression("=", node.id, t.functionExpression(node.id, 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); + } + + // Don't hoist variables out of inner functions. + path.skip(); + }, + + FunctionExpression: function FunctionExpression(path) { + // Don't descend into nested function expressions. + path.skip(); + } + }); + + var paramNames = {}; + funPath.get("params").forEach(function (paramPath) { + var param = paramPath.node; + if (t.isIdentifier(param)) { + paramNames[param.name] = param; + } else { + // Variables declared by destructuring parameter patterns will be + // harmlessly re-declared. + } + }); + + var declarations = []; + + (0, _keys2.default)(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); +}; \ No newline at end of file diff --git a/node_modules/regenerator-transform/lib/index.js b/node_modules/regenerator-transform/lib/index.js new file mode 100644 index 0000000..713417a --- /dev/null +++ b/node_modules/regenerator-transform/lib/index.js @@ -0,0 +1,22 @@ +"use strict"; + +exports.__esModule = true; + +exports.default = function (context) { + var plugin = { + visitor: require("./visit").visitor + }; + + // 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. + var 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; +}; \ No newline at end of file diff --git a/node_modules/regenerator-transform/lib/leap.js b/node_modules/regenerator-transform/lib/leap.js new file mode 100644 index 0000000..3f295c2 --- /dev/null +++ b/node_modules/regenerator-transform/lib/leap.js @@ -0,0 +1,183 @@ +"use strict"; + +var _assert = require("assert"); + +var _assert2 = _interopRequireDefault(_assert); + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +var _util = require("util"); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function Entry() { + _assert2.default.ok(this instanceof Entry); +} /** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +function FunctionEntry(returnLoc) { + Entry.call(this); + t.assertLiteral(returnLoc); + this.returnLoc = returnLoc; +} + +(0, _util.inherits)(FunctionEntry, Entry); +exports.FunctionEntry = FunctionEntry; + +function LoopEntry(breakLoc, continueLoc, label) { + Entry.call(this); + + t.assertLiteral(breakLoc); + t.assertLiteral(continueLoc); + + if (label) { + t.assertIdentifier(label); + } else { + label = null; + } + + this.breakLoc = breakLoc; + this.continueLoc = continueLoc; + this.label = label; +} + +(0, _util.inherits)(LoopEntry, Entry); +exports.LoopEntry = LoopEntry; + +function SwitchEntry(breakLoc) { + Entry.call(this); + t.assertLiteral(breakLoc); + this.breakLoc = breakLoc; +} + +(0, _util.inherits)(SwitchEntry, Entry); +exports.SwitchEntry = SwitchEntry; + +function TryEntry(firstLoc, catchEntry, finallyEntry) { + Entry.call(this); + + t.assertLiteral(firstLoc); + + if (catchEntry) { + _assert2.default.ok(catchEntry instanceof CatchEntry); + } else { + catchEntry = null; + } + + if (finallyEntry) { + _assert2.default.ok(finallyEntry instanceof FinallyEntry); + } else { + finallyEntry = null; + } + + // Have to have one or the other (or both). + _assert2.default.ok(catchEntry || finallyEntry); + + this.firstLoc = firstLoc; + this.catchEntry = catchEntry; + this.finallyEntry = finallyEntry; +} + +(0, _util.inherits)(TryEntry, Entry); +exports.TryEntry = TryEntry; + +function CatchEntry(firstLoc, paramId) { + Entry.call(this); + + t.assertLiteral(firstLoc); + t.assertIdentifier(paramId); + + this.firstLoc = firstLoc; + this.paramId = paramId; +} + +(0, _util.inherits)(CatchEntry, Entry); +exports.CatchEntry = CatchEntry; + +function FinallyEntry(firstLoc, afterLoc) { + Entry.call(this); + t.assertLiteral(firstLoc); + t.assertLiteral(afterLoc); + this.firstLoc = firstLoc; + this.afterLoc = afterLoc; +} + +(0, _util.inherits)(FinallyEntry, Entry); +exports.FinallyEntry = FinallyEntry; + +function LabeledEntry(breakLoc, label) { + Entry.call(this); + + t.assertLiteral(breakLoc); + t.assertIdentifier(label); + + this.breakLoc = breakLoc; + this.label = label; +} + +(0, _util.inherits)(LabeledEntry, Entry); +exports.LabeledEntry = LabeledEntry; + +function LeapManager(emitter) { + _assert2.default.ok(this instanceof LeapManager); + + var Emitter = require("./emit").Emitter; + _assert2.default.ok(emitter instanceof Emitter); + + this.emitter = emitter; + this.entryStack = [new FunctionEntry(emitter.finalLoc)]; +} + +var LMp = LeapManager.prototype; +exports.LeapManager = LeapManager; + +LMp.withEntry = function (entry, callback) { + _assert2.default.ok(entry instanceof Entry); + this.entryStack.push(entry); + try { + callback.call(this.emitter); + } finally { + var popped = this.entryStack.pop(); + _assert2.default.strictEqual(popped, entry); + } +}; + +LMp._findLeapLocation = function (property, label) { + for (var i = this.entryStack.length - 1; i >= 0; --i) { + var entry = this.entryStack[i]; + var 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); +}; \ No newline at end of file diff --git a/node_modules/regenerator-transform/lib/meta.js b/node_modules/regenerator-transform/lib/meta.js new file mode 100644 index 0000000..20049f6 --- /dev/null +++ b/node_modules/regenerator-transform/lib/meta.js @@ -0,0 +1,112 @@ +"use strict"; + +var _assert = require("assert"); + +var _assert2 = _interopRequireDefault(_assert); + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var m = require("private").makeAccessor(); /** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +var hasOwn = Object.prototype.hasOwnProperty; + +function makePredicate(propertyName, knownTypes) { + function onlyChildren(node) { + t.assertNode(node); + + // Assume no side effects until we find out otherwise. + var result = false; + + function check(child) { + if (result) { + // Do nothing. + } else if (Array.isArray(child)) { + child.some(check); + } else if (t.isNode(child)) { + _assert2.default.strictEqual(result, false); + result = predicate(child); + } + return result; + } + + var keys = t.VISITOR_KEYS[node.type]; + if (keys) { + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + var child = node[key]; + check(child); + } + } + + return result; + } + + function predicate(node) { + t.assertNode(node); + + var 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; +} + +var opaqueTypes = { + FunctionExpression: true, + ArrowFunctionExpression: true +}; + +// These types potentially have side effects regardless of what side +// effects their subexpressions have. +var 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. +var leapTypes = { + YieldExpression: true, + BreakStatement: true, + ContinueStatement: true, + ReturnStatement: true, + ThrowStatement: true +}; + +// All leap types are also side effect types. +for (var type in leapTypes) { + if (hasOwn.call(leapTypes, type)) { + sideEffectTypes[type] = leapTypes[type]; + } +} + +exports.hasSideEffects = makePredicate("hasSideEffects", sideEffectTypes); +exports.containsLeap = makePredicate("containsLeap", leapTypes); \ No newline at end of file diff --git a/node_modules/regenerator-transform/lib/replaceShorthandObjectMethod.js b/node_modules/regenerator-transform/lib/replaceShorthandObjectMethod.js new file mode 100644 index 0000000..82d905e --- /dev/null +++ b/node_modules/regenerator-transform/lib/replaceShorthandObjectMethod.js @@ -0,0 +1,80 @@ +"use strict"; + +exports.__esModule = true; +exports.default = replaceShorthandObjectMethod; + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +// 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. +function replaceShorthandObjectMethod(path) { + 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; + } + + var parameters = path.node.params.map(function (param) { + return t.cloneDeep(param); + }); + + var 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"); +} \ No newline at end of file diff --git a/node_modules/regenerator-transform/lib/util.js b/node_modules/regenerator-transform/lib/util.js new file mode 100644 index 0000000..bc42ed1 --- /dev/null +++ b/node_modules/regenerator-transform/lib/util.js @@ -0,0 +1,36 @@ +"use strict"; + +exports.__esModule = true; +exports.runtimeProperty = runtimeProperty; +exports.isReference = isReference; +exports.replaceWithOrRemove = replaceWithOrRemove; + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function runtimeProperty(name) { + return t.memberExpression(t.identifier("regeneratorRuntime"), t.identifier(name), false); +} /** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +function isReference(path) { + return path.isReferenced() || path.parentPath.isAssignmentExpression({ left: path.node }); +} + +function replaceWithOrRemove(path, replacement) { + if (replacement) { + path.replaceWith(replacement); + } else { + path.remove(); + } +} \ No newline at end of file diff --git a/node_modules/regenerator-transform/lib/visit.js b/node_modules/regenerator-transform/lib/visit.js new file mode 100644 index 0000000..df0c332 --- /dev/null +++ b/node_modules/regenerator-transform/lib/visit.js @@ -0,0 +1,290 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +"use strict"; + +var _assert = require("assert"); + +var _assert2 = _interopRequireDefault(_assert); + +var _babelTypes = require("babel-types"); + +var t = _interopRequireWildcard(_babelTypes); + +var _hoist = require("./hoist"); + +var _emit = require("./emit"); + +var _replaceShorthandObjectMethod = require("./replaceShorthandObjectMethod"); + +var _replaceShorthandObjectMethod2 = _interopRequireDefault(_replaceShorthandObjectMethod); + +var _util = require("./util"); + +var util = _interopRequireWildcard(_util); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.visitor = { + Function: { + exit: function exit(path, state) { + var node = path.node; + + if (node.generator) { + if (node.async) { + // Async generator + if (state.opts.asyncGenerators === false) return; + } else { + // Plain generator + if (state.opts.generators === false) return; + } + } else if (node.async) { + // Async function + if (state.opts.async === false) return; + } else { + // Not a generator or async function. + return; + } + + // if this is an ObjectMethod, we need to convert it to an ObjectProperty + path = (0, _replaceShorthandObjectMethod2.default)(path); + node = path.node; + + var contextId = path.scope.generateUidIdentifier("context"); + var argsId = path.scope.generateUidIdentifier("args"); + + path.ensureBlock(); + var bodyBlockPath = path.get("body"); + + if (node.async) { + bodyBlockPath.traverse(awaitVisitor); + } + + bodyBlockPath.traverse(functionSentVisitor, { + context: contextId + }); + + var outerBody = []; + var innerBody = []; + + bodyBlockPath.get("body").forEach(function (childPath) { + var 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; + } + + var 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); + var innerFnId = t.identifier(node.id.name + "$"); + + // Turn all declarations into vars, and replace the original + // declarations with equivalent assignment expressions. + var vars = (0, _hoist.hoist)(path); + + var didRenameArguments = renameArguments(path, argsId); + if (didRenameArguments) { + vars = vars || t.variableDeclaration("var", []); + var argumentIdentifier = t.identifier("arguments"); + // we need to do this as otherwise arguments in arrow functions gets hoisted + argumentIdentifier._shadowedFunctionLiteral = path; + vars.declarations.push(t.variableDeclarator(argsId, argumentIdentifier)); + } + + var emitter = new _emit.Emitter(contextId); + emitter.explode(path.get("body")); + + if (vars && vars.declarations.length > 0) { + outerBody.push(vars); + } + + var wrapArgs = [emitter.getContextFunction(innerFnId), + // 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. + node.generator ? outerFnExpr : t.nullLiteral(), t.thisExpression()]; + + var tryLocsList = emitter.getTryLocsList(); + if (tryLocsList) { + wrapArgs.push(tryLocsList); + } + + var wrapCall = t.callExpression(util.runtimeProperty(node.async ? "async" : "wrap"), wrapArgs); + + outerBody.push(t.returnStatement(wrapCall)); + node.body = t.blockStatement(outerBody); + + var 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; + } + + var 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__"); + } + + // 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(); + } + } +}; + +// 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) { + var 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(). + return getMarkedFunctionId(funPath); + } + + return node.id; +} + +var getMarkInfo = require("private").makeAccessor(); + +function getMarkedFunctionId(funPath) { + var node = funPath.node; + t.assertIdentifier(node.id); + + var blockPath = funPath.findParent(function (path) { + return path.isProgram() || path.isBlockStatement(); + }); + + if (!blockPath) { + return node.id; + } + + var block = blockPath.node; + _assert2.default.ok(Array.isArray(block.body)); + + var info = getMarkInfo(block); + if (!info.decl) { + info.decl = t.variableDeclaration("var", []); + blockPath.unshiftContainer("body", info.decl); + info.declPath = blockPath.get("body.0"); + } + + _assert2.default.strictEqual(info.declPath.node, info.decl); + + // Get a new unique identifier for our marked variable. + var markedId = blockPath.scope.generateUidIdentifier("marked"); + var markCallExp = t.callExpression(util.runtimeProperty("mark"), [node.id]); + + var index = info.decl.declarations.push(t.variableDeclarator(markedId, markCallExp)) - 1; + + var markCallExpPath = info.declPath.get("declarations." + index + ".init"); + + _assert2.default.strictEqual(markCallExpPath.node, markCallExp); + + markCallExpPath.addComment("leading", "#__PURE__"); + + return markedId; +} + +function renameArguments(funcPath, argsId) { + var state = { + didRenameArguments: false, + argsId: argsId + }; + + funcPath.traverse(argumentsVisitor, state); + + // If the traversal replaced any arguments references, then we need to + // alias the outer function's arguments binding (be it the implicit + // arguments object or some other parameter or variable) to the variable + // named by argsId. + return state.didRenameArguments; +} + +var argumentsVisitor = { + "FunctionExpression|FunctionDeclaration": function FunctionExpressionFunctionDeclaration(path) { + path.skip(); + }, + + Identifier: function Identifier(path, state) { + if (path.node.name === "arguments" && util.isReference(path)) { + util.replaceWithOrRemove(path, state.argsId); + state.didRenameArguments = true; + } + } +}; + +var functionSentVisitor = { + MetaProperty: function MetaProperty(path) { + var node = path.node; + + + if (node.meta.name === "function" && node.property.name === "sent") { + util.replaceWithOrRemove(path, t.memberExpression(this.context, t.identifier("_sent"))); + } + } +}; + +var awaitVisitor = { + Function: function Function(path) { + path.skip(); // Don't descend into nested function scopes. + }, + + AwaitExpression: function AwaitExpression(path) { + // Convert await expressions to yield expressions. + var 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)); + } +}; \ No newline at end of file diff --git a/node_modules/regenerator-transform/package.json b/node_modules/regenerator-transform/package.json new file mode 100644 index 0000000..5fba01e --- /dev/null +++ b/node_modules/regenerator-transform/package.json @@ -0,0 +1,72 @@ +{ + "_from": "regenerator-transform@^0.10.0", + "_id": "regenerator-transform@0.10.1", + "_inBundle": false, + "_integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "_location": "/regenerator-transform", + "_phantomChildren": {}, + "_requested": { + "type": "range", + "registry": true, + "raw": "regenerator-transform@^0.10.0", + "name": "regenerator-transform", + "escapedName": "regenerator-transform", + "rawSpec": "^0.10.0", + "saveSpec": null, + "fetchSpec": "^0.10.0" + }, + "_requiredBy": [ + "/babel-plugin-transform-regenerator" + ], + "_resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "_shasum": "1e4996837231da8b7f3cf4114d71b5691a0680dd", + "_spec": "regenerator-transform@^0.10.0", + "_where": "/home/pruss/Dev/3-minute-website/node_modules/babel-plugin-transform-regenerator", + "author": { + "name": "Ben Newman", + "email": "bn@cs.stanford.edu" + }, + "babel": { + "presets": [ + [ + "env", + { + "loose": true + } + ] + ], + "plugins": [ + "transform-runtime" + ] + }, + "bundleDependencies": false, + "dependencies": { + "babel-runtime": "^6.18.0", + "babel-types": "^6.19.0", + "private": "^0.1.6" + }, + "deprecated": false, + "description": "Explode async and generator functions into a state machine.", + "devDependencies": { + "babel-cli": "^6.9.0", + "babel-plugin-transform-runtime": "^6.9.0", + "babel-preset-env": "^1.2.2" + }, + "keywords": [ + "regenerator", + "runtime", + "generator", + "async" + ], + "license": "BSD", + "main": "lib/index.js", + "name": "regenerator-transform", + "repository": { + "type": "git", + "url": "https://github.com/facebook/regenerator/tree/master/packages/regenerator-transform" + }, + "scripts": { + "prepublish": "babel src/ --out-dir lib/" + }, + "version": "0.10.1" +} diff --git a/node_modules/regenerator-transform/src/emit.js b/node_modules/regenerator-transform/src/emit.js new file mode 100644 index 0000000..9a3aa73 --- /dev/null +++ b/node_modules/regenerator-transform/src/emit.js @@ -0,0 +1,1184 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +import assert from "assert"; +import * as t from "babel-types"; +import * as leap from "./leap"; +import * as meta from "./meta"; +import * as util from "./util"; + +let hasOwn = Object.prototype.hasOwnProperty; + +function Emitter(contextId) { + assert.ok(this instanceof Emitter); + t.assertIdentifier(contextId); + + // Used to generate unique temporary names. + this.nextTempId = 0; + + // In order to make sure the context object does not collide with + // anything in the local scope, we might have to rename it, so we + // refer to it symbolically instead of just assuming that it will be + // called "context". + this.contextId = contextId; + + // An append-only list of Statements that grows each time this.emit is + // called. + this.listing = []; + + // A sparse array whose keys correspond to locations in this.listing + // that have been marked as branch/jump targets. + this.marked = [true]; + + // The last location will be marked when this.getDispatchLoop is + // called. + this.finalLoc = loc(); + + // A list of all leap.TryEntry statements emitted. + this.tryEntries = []; + + // Each time we evaluate the body of a loop, we tell this.leapManager + // to enter a nested loop context that determines the meaning of break + // and continue statements therein. + this.leapManager = new leap.LeapManager(this); +} + +let Ep = Emitter.prototype; +exports.Emitter = Emitter; + +// Offsets into this.listing that could be used as targets for branches or +// jumps are represented as numeric Literal nodes. This representation has +// the amazingly convenient benefit of allowing the exact value of the +// location to be determined at any time, even after generating code that +// refers to the location. +function loc() { + return t.numericLiteral(-1); +} + +// Sets the exact value of the given location to the offset of the next +// Statement emitted. +Ep.mark = function(loc) { + t.assertLiteral(loc); + let index = this.listing.length; + if (loc.value === -1) { + loc.value = index; + } else { + // Locations can be marked redundantly, but their values cannot change + // once set the first time. + assert.strictEqual(loc.value, index); + } + this.marked[index] = true; + return loc; +}; + +Ep.emit = function(node) { + if (t.isExpression(node)) { + node = t.expressionStatement(node); + } + + t.assertStatement(node); + this.listing.push(node); +}; + +// Shorthand for emitting assignment statements. This will come in handy +// for assignments to temporary variables. +Ep.emitAssign = function(lhs, rhs) { + this.emit(this.assign(lhs, rhs)); + return lhs; +}; + +// Shorthand for an assignment statement. +Ep.assign = function(lhs, rhs) { + return t.expressionStatement( + t.assignmentExpression("=", lhs, rhs)); +}; + +// Convenience function for generating expressions like context.next, +// context.sent, and context.rval. +Ep.contextProperty = function(name, computed) { + return t.memberExpression( + this.contextId, + computed ? t.stringLiteral(name) : t.identifier(name), + !!computed + ); +}; + +// Shorthand for setting context.rval and jumping to `context.stop()`. +Ep.stop = function(rval) { + if (rval) { + this.setReturnValue(rval); + } + + this.jump(this.finalLoc); +}; + +Ep.setReturnValue = function(valuePath) { + t.assertExpression(valuePath.value); + + this.emitAssign( + this.contextProperty("rval"), + this.explodeExpression(valuePath) + ); +}; + +Ep.clearPendingException = function(tryLoc, assignee) { + t.assertLiteral(tryLoc); + + let catchCall = t.callExpression( + this.contextProperty("catch", true), + [tryLoc] + ); + + if (assignee) { + this.emitAssign(assignee, catchCall); + } else { + this.emit(catchCall); + } +}; + +// Emits code for an unconditional jump to the given location, even if the +// exact value of the location is not yet known. +Ep.jump = function(toLoc) { + this.emitAssign(this.contextProperty("next"), toLoc); + this.emit(t.breakStatement()); +}; + +// Conditional jump. +Ep.jumpIf = function(test, toLoc) { + t.assertExpression(test); + t.assertLiteral(toLoc); + + this.emit(t.ifStatement( + test, + t.blockStatement([ + this.assign(this.contextProperty("next"), toLoc), + t.breakStatement() + ]) + )); +}; + +// Conditional jump, with the condition negated. +Ep.jumpIfNot = function(test, toLoc) { + t.assertExpression(test); + t.assertLiteral(toLoc); + + let negatedTest; + if (t.isUnaryExpression(test) && + test.operator === "!") { + // Avoid double negation. + negatedTest = test.argument; + } else { + negatedTest = t.unaryExpression("!", test); + } + + this.emit(t.ifStatement( + negatedTest, + t.blockStatement([ + this.assign(this.contextProperty("next"), toLoc), + t.breakStatement() + ]) + )); +}; + +// Returns a unique MemberExpression that can be used to store and +// retrieve temporary values. Since the object of the member expression is +// the context object, which is presumed to coexist peacefully with all +// other local variables, and since we just increment `nextTempId` +// monotonically, uniqueness is assured. +Ep.makeTempVar = function() { + return this.contextProperty("t" + this.nextTempId++); +}; + +Ep.getContextFunction = function(id) { + return t.functionExpression( + id || null/*Anonymous*/, + [this.contextId], + t.blockStatement([this.getDispatchLoop()]), + false, // Not a generator anymore! + false // Nor an expression. + ); +}; + +// Turns this.listing into a loop of the form +// +// while (1) switch (context.next) { +// case 0: +// ... +// case n: +// return context.stop(); +// } +// +// Each marked location in this.listing will correspond to one generated +// case statement. +Ep.getDispatchLoop = function() { + let self = this; + let cases = []; + let current; + + // If we encounter a break, continue, or return statement in a switch + // case, we can skip the rest of the statements until the next case. + let alreadyEnded = false; + + self.listing.forEach(function(stmt, i) { + if (self.marked.hasOwnProperty(i)) { + cases.push(t.switchCase( + t.numericLiteral(i), + current = [])); + alreadyEnded = false; + } + + if (!alreadyEnded) { + current.push(stmt); + if (t.isCompletionStatement(stmt)) + alreadyEnded = true; + } + }); + + // Now that we know how many statements there will be in this.listing, + // we can finally resolve this.finalLoc.value. + this.finalLoc.value = this.listing.length; + + cases.push( + t.switchCase(this.finalLoc, [ + // Intentionally fall through to the "end" case... + ]), + + // So that the runtime can jump to the final location without having + // to know its offset, we provide the "end" case as a synonym. + t.switchCase(t.stringLiteral("end"), [ + // This will check/clear both context.thrown and context.rval. + t.returnStatement( + t.callExpression(this.contextProperty("stop"), []) + ) + ]) + ); + + return t.whileStatement( + t.numericLiteral(1), + t.switchStatement( + t.assignmentExpression( + "=", + this.contextProperty("prev"), + this.contextProperty("next") + ), + cases + ) + ); +}; + +Ep.getTryLocsList = function() { + if (this.tryEntries.length === 0) { + // To avoid adding a needless [] to the majority of runtime.wrap + // argument lists, force the caller to handle this case specially. + return null; + } + + let lastLocValue = 0; + + return t.arrayExpression( + this.tryEntries.map(function(tryEntry) { + let thisLocValue = tryEntry.firstLoc.value; + assert.ok(thisLocValue >= lastLocValue, "try entries out of order"); + lastLocValue = thisLocValue; + + let ce = tryEntry.catchEntry; + let fe = tryEntry.finallyEntry; + + let locs = [ + tryEntry.firstLoc, + // The null here makes a hole in the array. + ce ? ce.firstLoc : null + ]; + + if (fe) { + locs[2] = fe.firstLoc; + locs[3] = fe.afterLoc; + } + + return t.arrayExpression(locs); + }) + ); +}; + +// All side effects must be realized in order. + +// If any subexpression harbors a leap, all subexpressions must be +// neutered of side effects. + +// No destructive modification of AST nodes. + +Ep.explode = function(path, ignoreResult) { + let node = path.node; + let self = this; + + t.assertNode(node); + + if (t.isDeclaration(node)) + throw getDeclError(node); + + if (t.isStatement(node)) + return self.explodeStatement(path); + + if (t.isExpression(node)) + return self.explodeExpression(path, ignoreResult); + + switch (node.type) { + case "Program": + return path.get("body").map( + self.explodeStatement, + self + ); + + case "VariableDeclarator": + throw getDeclError(node); + + // These node types should be handled by their parent nodes + // (ObjectExpression, SwitchStatement, and TryStatement, respectively). + case "Property": + case "SwitchCase": + case "CatchClause": + throw new Error( + node.type + " nodes should be handled by their parents"); + + default: + throw new Error( + "unknown Node of type " + + JSON.stringify(node.type)); + } +}; + +function getDeclError(node) { + return new Error( + "all declarations should have been transformed into " + + "assignments before the Exploder began its work: " + + JSON.stringify(node)); +} + +Ep.explodeStatement = function(path, labelId) { + let stmt = path.node; + let self = this; + let before, after, head; + + t.assertStatement(stmt); + + if (labelId) { + t.assertIdentifier(labelId); + } else { + labelId = null; + } + + // Explode BlockStatement nodes even if they do not contain a yield, + // because we don't want or need the curly braces. + if (t.isBlockStatement(stmt)) { + path.get("body").forEach(function (path) { + self.explodeStatement(path); + }); + return; + } + + if (!meta.containsLeap(stmt)) { + // Technically we should be able to avoid emitting the statement + // altogether if !meta.hasSideEffects(stmt), but that leads to + // confusing generated code (for instance, `while (true) {}` just + // disappears) and is probably a more appropriate job for a dedicated + // dead code elimination pass. + self.emit(stmt); + return; + } + + switch (stmt.type) { + case "ExpressionStatement": + self.explodeExpression(path.get("expression"), true); + break; + + case "LabeledStatement": + after = loc(); + + // Did you know you can break from any labeled block statement or + // control structure? Well, you can! Note: when a labeled loop is + // encountered, the leap.LabeledEntry created here will immediately + // enclose a leap.LoopEntry on the leap manager's stack, and both + // entries will have the same label. Though this works just fine, it + // may seem a bit redundant. In theory, we could check here to + // determine if stmt knows how to handle its own label; for example, + // stmt happens to be a WhileStatement and so we know it's going to + // establish its own LoopEntry when we explode it (below). Then this + // LabeledEntry would be unnecessary. Alternatively, we might be + // tempted not to pass stmt.label down into self.explodeStatement, + // because we've handled the label here, but that's a mistake because + // labeled loops may contain labeled continue statements, which is not + // something we can handle in this generic case. All in all, I think a + // little redundancy greatly simplifies the logic of this case, since + // it's clear that we handle all possible LabeledStatements correctly + // here, regardless of whether they interact with the leap manager + // themselves. Also remember that labels and break/continue-to-label + // statements are rare, and all of this logic happens at transform + // time, so it has no additional runtime cost. + self.leapManager.withEntry( + new leap.LabeledEntry(after, stmt.label), + function() { + self.explodeStatement(path.get("body"), stmt.label); + } + ); + + self.mark(after); + + break; + + case "WhileStatement": + before = loc(); + after = loc(); + + self.mark(before); + self.jumpIfNot(self.explodeExpression(path.get("test")), after); + self.leapManager.withEntry( + new leap.LoopEntry(after, before, labelId), + function() { self.explodeStatement(path.get("body")); } + ); + self.jump(before); + self.mark(after); + + break; + + case "DoWhileStatement": + let first = loc(); + let test = loc(); + after = loc(); + + self.mark(first); + self.leapManager.withEntry( + new leap.LoopEntry(after, test, labelId), + function() { self.explode(path.get("body")); } + ); + self.mark(test); + self.jumpIf(self.explodeExpression(path.get("test")), first); + self.mark(after); + + break; + + case "ForStatement": + head = loc(); + let update = loc(); + after = loc(); + + if (stmt.init) { + // We pass true here to indicate that if stmt.init is an expression + // then we do not care about its result. + self.explode(path.get("init"), true); + } + + self.mark(head); + + if (stmt.test) { + self.jumpIfNot(self.explodeExpression(path.get("test")), after); + } else { + // No test means continue unconditionally. + } + + self.leapManager.withEntry( + new leap.LoopEntry(after, update, labelId), + function() { self.explodeStatement(path.get("body")); } + ); + + self.mark(update); + + if (stmt.update) { + // We pass true here to indicate that if stmt.update is an + // expression then we do not care about its result. + self.explode(path.get("update"), true); + } + + self.jump(head); + + self.mark(after); + + break; + + case "TypeCastExpression": + return self.explodeExpression(path.get("expression")); + + case "ForInStatement": + head = loc(); + after = loc(); + + let keyIterNextFn = self.makeTempVar(); + self.emitAssign( + keyIterNextFn, + t.callExpression( + util.runtimeProperty("keys"), + [self.explodeExpression(path.get("right"))] + ) + ); + + self.mark(head); + + let keyInfoTmpVar = self.makeTempVar(); + self.jumpIf( + t.memberExpression( + t.assignmentExpression( + "=", + keyInfoTmpVar, + t.callExpression(keyIterNextFn, []) + ), + t.identifier("done"), + false + ), + after + ); + + self.emitAssign( + stmt.left, + t.memberExpression( + keyInfoTmpVar, + t.identifier("value"), + false + ) + ); + + self.leapManager.withEntry( + new leap.LoopEntry(after, head, labelId), + function() { self.explodeStatement(path.get("body")); } + ); + + self.jump(head); + + self.mark(after); + + break; + + case "BreakStatement": + self.emitAbruptCompletion({ + type: "break", + target: self.leapManager.getBreakLoc(stmt.label) + }); + + break; + + case "ContinueStatement": + self.emitAbruptCompletion({ + type: "continue", + target: self.leapManager.getContinueLoc(stmt.label) + }); + + break; + + case "SwitchStatement": + // Always save the discriminant into a temporary variable in case the + // test expressions overwrite values like context.sent. + let disc = self.emitAssign( + self.makeTempVar(), + self.explodeExpression(path.get("discriminant")) + ); + + after = loc(); + let defaultLoc = loc(); + let condition = defaultLoc; + let caseLocs = []; + + // If there are no cases, .cases might be undefined. + let cases = stmt.cases || []; + + for (let i = cases.length - 1; i >= 0; --i) { + let c = cases[i]; + t.assertSwitchCase(c); + + if (c.test) { + condition = t.conditionalExpression( + t.binaryExpression("===", disc, c.test), + caseLocs[i] = loc(), + condition + ); + } else { + caseLocs[i] = defaultLoc; + } + } + + let discriminant = path.get("discriminant"); + util.replaceWithOrRemove(discriminant, condition); + self.jump(self.explodeExpression(discriminant)); + + self.leapManager.withEntry( + new leap.SwitchEntry(after), + function() { + path.get("cases").forEach(function(casePath) { + let i = casePath.key; + self.mark(caseLocs[i]); + + casePath.get("consequent").forEach(function (path) { + self.explodeStatement(path); + }); + }); + } + ); + + self.mark(after); + if (defaultLoc.value === -1) { + self.mark(defaultLoc); + assert.strictEqual(after.value, defaultLoc.value); + } + + break; + + case "IfStatement": + let elseLoc = stmt.alternate && loc(); + after = loc(); + + self.jumpIfNot( + self.explodeExpression(path.get("test")), + elseLoc || after + ); + + self.explodeStatement(path.get("consequent")); + + if (elseLoc) { + self.jump(after); + self.mark(elseLoc); + self.explodeStatement(path.get("alternate")); + } + + self.mark(after); + + break; + + case "ReturnStatement": + self.emitAbruptCompletion({ + type: "return", + value: self.explodeExpression(path.get("argument")) + }); + + break; + + case "WithStatement": + throw new Error("WithStatement not supported in generator functions."); + + case "TryStatement": + after = loc(); + + let handler = stmt.handler; + + let catchLoc = handler && loc(); + let catchEntry = catchLoc && new leap.CatchEntry( + catchLoc, + handler.param + ); + + let finallyLoc = stmt.finalizer && loc(); + let finallyEntry = finallyLoc && + new leap.FinallyEntry(finallyLoc, after); + + let tryEntry = new leap.TryEntry( + self.getUnmarkedCurrentLoc(), + catchEntry, + finallyEntry + ); + + self.tryEntries.push(tryEntry); + self.updateContextPrevLoc(tryEntry.firstLoc); + + self.leapManager.withEntry(tryEntry, function() { + self.explodeStatement(path.get("block")); + + if (catchLoc) { + if (finallyLoc) { + // If we have both a catch block and a finally block, then + // because we emit the catch block first, we need to jump over + // it to the finally block. + self.jump(finallyLoc); + + } else { + // If there is no finally block, then we need to jump over the + // catch block to the fall-through location. + self.jump(after); + } + + self.updateContextPrevLoc(self.mark(catchLoc)); + + let bodyPath = path.get("handler.body"); + let safeParam = self.makeTempVar(); + self.clearPendingException(tryEntry.firstLoc, safeParam); + + bodyPath.traverse(catchParamVisitor, { + safeParam: safeParam, + catchParamName: handler.param.name + }); + + self.leapManager.withEntry(catchEntry, function() { + self.explodeStatement(bodyPath); + }); + } + + if (finallyLoc) { + self.updateContextPrevLoc(self.mark(finallyLoc)); + + self.leapManager.withEntry(finallyEntry, function() { + self.explodeStatement(path.get("finalizer")); + }); + + self.emit(t.returnStatement(t.callExpression( + self.contextProperty("finish"), + [finallyEntry.firstLoc] + ))); + } + }); + + self.mark(after); + + break; + + case "ThrowStatement": + self.emit(t.throwStatement( + self.explodeExpression(path.get("argument")) + )); + + break; + + default: + throw new Error( + "unknown Statement of type " + + JSON.stringify(stmt.type)); + } +}; + +let catchParamVisitor = { + Identifier: function(path, state) { + if (path.node.name === state.catchParamName && util.isReference(path)) { + util.replaceWithOrRemove(path, state.safeParam); + } + }, + + Scope: function(path, state) { + if (path.scope.hasOwnBinding(state.catchParamName)) { + // Don't descend into nested scopes that shadow the catch + // parameter with their own declarations. + path.skip(); + } + } +}; + +Ep.emitAbruptCompletion = function(record) { + if (!isValidCompletion(record)) { + assert.ok( + false, + "invalid completion record: " + + JSON.stringify(record) + ); + } + + assert.notStrictEqual( + record.type, "normal", + "normal completions are not abrupt" + ); + + let abruptArgs = [t.stringLiteral(record.type)]; + + if (record.type === "break" || + record.type === "continue") { + t.assertLiteral(record.target); + abruptArgs[1] = record.target; + } else if (record.type === "return" || + record.type === "throw") { + if (record.value) { + t.assertExpression(record.value); + abruptArgs[1] = record.value; + } + } + + this.emit( + t.returnStatement( + t.callExpression( + this.contextProperty("abrupt"), + abruptArgs + ) + ) + ); +}; + +function isValidCompletion(record) { + let type = record.type; + + if (type === "normal") { + return !hasOwn.call(record, "target"); + } + + if (type === "break" || + type === "continue") { + return !hasOwn.call(record, "value") + && t.isLiteral(record.target); + } + + if (type === "return" || + type === "throw") { + return hasOwn.call(record, "value") + && !hasOwn.call(record, "target"); + } + + return false; +} + + +// Not all offsets into emitter.listing are potential jump targets. For +// example, execution typically falls into the beginning of a try block +// without jumping directly there. This method returns the current offset +// without marking it, so that a switch case will not necessarily be +// generated for this offset (I say "not necessarily" because the same +// location might end up being marked in the process of emitting other +// statements). There's no logical harm in marking such locations as jump +// targets, but minimizing the number of switch cases keeps the generated +// code shorter. +Ep.getUnmarkedCurrentLoc = function() { + return t.numericLiteral(this.listing.length); +}; + +// The context.prev property takes the value of context.next whenever we +// evaluate the switch statement discriminant, which is generally good +// enough for tracking the last location we jumped to, but sometimes +// context.prev needs to be more precise, such as when we fall +// successfully out of a try block and into a finally block without +// jumping. This method exists to update context.prev to the freshest +// available location. If we were implementing a full interpreter, we +// would know the location of the current instruction with complete +// precision at all times, but we don't have that luxury here, as it would +// be costly and verbose to set context.prev before every statement. +Ep.updateContextPrevLoc = function(loc) { + if (loc) { + t.assertLiteral(loc); + + if (loc.value === -1) { + // If an uninitialized location literal was passed in, set its value + // to the current this.listing.length. + loc.value = this.listing.length; + } else { + // Otherwise assert that the location matches the current offset. + assert.strictEqual(loc.value, this.listing.length); + } + + } else { + loc = this.getUnmarkedCurrentLoc(); + } + + // Make sure context.prev is up to date in case we fell into this try + // statement without jumping to it. TODO Consider avoiding this + // assignment when we know control must have jumped here. + this.emitAssign(this.contextProperty("prev"), loc); +}; + +Ep.explodeExpression = function(path, ignoreResult) { + let expr = path.node; + if (expr) { + t.assertExpression(expr); + } else { + return expr; + } + + let self = this; + let result; // Used optionally by several cases below. + let after; + + function finish(expr) { + t.assertExpression(expr); + if (ignoreResult) { + self.emit(expr); + } else { + return expr; + } + } + + // If the expression does not contain a leap, then we either emit the + // expression as a standalone statement or return it whole. + if (!meta.containsLeap(expr)) { + return finish(expr); + } + + // If any child contains a leap (such as a yield or labeled continue or + // break statement), then any sibling subexpressions will almost + // certainly have to be exploded in order to maintain the order of their + // side effects relative to the leaping child(ren). + let hasLeapingChildren = meta.containsLeap.onlyChildren(expr); + + // In order to save the rest of explodeExpression from a combinatorial + // trainwreck of special cases, explodeViaTempVar is responsible for + // deciding when a subexpression needs to be "exploded," which is my + // very technical term for emitting the subexpression as an assignment + // to a temporary variable and the substituting the temporary variable + // for the original subexpression. Think of exploded view diagrams, not + // Michael Bay movies. The point of exploding subexpressions is to + // control the precise order in which the generated code realizes the + // side effects of those subexpressions. + function explodeViaTempVar(tempVar, childPath, ignoreChildResult) { + assert.ok( + !ignoreChildResult || !tempVar, + "Ignoring the result of a child expression but forcing it to " + + "be assigned to a temporary variable?" + ); + + let result = self.explodeExpression(childPath, ignoreChildResult); + + if (ignoreChildResult) { + // Side effects already emitted above. + + } else if (tempVar || (hasLeapingChildren && + !t.isLiteral(result))) { + // If tempVar was provided, then the result will always be assigned + // to it, even if the result does not otherwise need to be assigned + // to a temporary variable. When no tempVar is provided, we have + // the flexibility to decide whether a temporary variable is really + // necessary. Unfortunately, in general, a temporary variable is + // required whenever any child contains a yield expression, since it + // is difficult to prove (at all, let alone efficiently) whether + // this result would evaluate to the same value before and after the + // yield (see #206). One narrow case where we can prove it doesn't + // matter (and thus we do not need a temporary variable) is when the + // result in question is a Literal value. + result = self.emitAssign( + tempVar || self.makeTempVar(), + result + ); + } + return result; + } + + // If ignoreResult is true, then we must take full responsibility for + // emitting the expression with all its side effects, and we should not + // return a result. + + switch (expr.type) { + case "MemberExpression": + return finish(t.memberExpression( + self.explodeExpression(path.get("object")), + expr.computed + ? explodeViaTempVar(null, path.get("property")) + : expr.property, + expr.computed + )); + + case "CallExpression": + let calleePath = path.get("callee"); + let argsPath = path.get("arguments"); + + let newCallee; + let newArgs = []; + + let hasLeapingArgs = false; + argsPath.forEach(function(argPath) { + hasLeapingArgs = hasLeapingArgs || + meta.containsLeap(argPath.node); + }); + + if (t.isMemberExpression(calleePath.node)) { + if (hasLeapingArgs) { + // If the arguments of the CallExpression contained any yield + // expressions, then we need to be sure to evaluate the callee + // before evaluating the arguments, but if the callee was a member + // expression, then we must be careful that the object of the + // member expression still gets bound to `this` for the call. + + let newObject = explodeViaTempVar( + // Assign the exploded callee.object expression to a temporary + // variable so that we can use it twice without reevaluating it. + self.makeTempVar(), + calleePath.get("object") + ); + + let newProperty = calleePath.node.computed + ? explodeViaTempVar(null, calleePath.get("property")) + : calleePath.node.property; + + newArgs.unshift(newObject); + + newCallee = t.memberExpression( + t.memberExpression( + newObject, + newProperty, + calleePath.node.computed + ), + t.identifier("call"), + false + ); + + } else { + newCallee = self.explodeExpression(calleePath); + } + + } else { + newCallee = explodeViaTempVar(null, calleePath); + + if (t.isMemberExpression(newCallee)) { + // If the callee was not previously a MemberExpression, then the + // CallExpression was "unqualified," meaning its `this` object + // should be the global object. If the exploded expression has + // become a MemberExpression (e.g. a context property, probably a + // temporary variable), then we need to force it to be unqualified + // by using the (0, object.property)(...) trick; otherwise, it + // will receive the object of the MemberExpression as its `this` + // object. + newCallee = t.sequenceExpression([ + t.numericLiteral(0), + newCallee + ]); + } + } + + argsPath.forEach(function(argPath) { + newArgs.push(explodeViaTempVar(null, argPath)); + }); + + return finish(t.callExpression( + newCallee, + newArgs + )); + + case "NewExpression": + return finish(t.newExpression( + explodeViaTempVar(null, path.get("callee")), + path.get("arguments").map(function(argPath) { + return explodeViaTempVar(null, argPath); + }) + )); + + case "ObjectExpression": + return finish(t.objectExpression( + path.get("properties").map(function(propPath) { + if (propPath.isObjectProperty()) { + return t.objectProperty( + propPath.node.key, + explodeViaTempVar(null, propPath.get("value")), + propPath.node.computed + ); + } else { + return propPath.node; + } + }) + )); + + case "ArrayExpression": + return finish(t.arrayExpression( + path.get("elements").map(function(elemPath) { + return explodeViaTempVar(null, elemPath); + }) + )); + + case "SequenceExpression": + let lastIndex = expr.expressions.length - 1; + + path.get("expressions").forEach(function(exprPath) { + if (exprPath.key === lastIndex) { + result = self.explodeExpression(exprPath, ignoreResult); + } else { + self.explodeExpression(exprPath, true); + } + }); + + return result; + + case "LogicalExpression": + after = loc(); + + if (!ignoreResult) { + result = self.makeTempVar(); + } + + let left = explodeViaTempVar(result, path.get("left")); + + if (expr.operator === "&&") { + self.jumpIfNot(left, after); + } else { + assert.strictEqual(expr.operator, "||"); + self.jumpIf(left, after); + } + + explodeViaTempVar(result, path.get("right"), ignoreResult); + + self.mark(after); + + return result; + + case "ConditionalExpression": + let elseLoc = loc(); + after = loc(); + let test = self.explodeExpression(path.get("test")); + + self.jumpIfNot(test, elseLoc); + + if (!ignoreResult) { + result = self.makeTempVar(); + } + + explodeViaTempVar(result, path.get("consequent"), ignoreResult); + self.jump(after); + + self.mark(elseLoc); + explodeViaTempVar(result, path.get("alternate"), ignoreResult); + + self.mark(after); + + return result; + + case "UnaryExpression": + return finish(t.unaryExpression( + expr.operator, + // Can't (and don't need to) break up the syntax of the argument. + // Think about delete a[b]. + self.explodeExpression(path.get("argument")), + !!expr.prefix + )); + + case "BinaryExpression": + return finish(t.binaryExpression( + expr.operator, + explodeViaTempVar(null, path.get("left")), + explodeViaTempVar(null, path.get("right")) + )); + + case "AssignmentExpression": + return finish(t.assignmentExpression( + expr.operator, + self.explodeExpression(path.get("left")), + self.explodeExpression(path.get("right")) + )); + + case "UpdateExpression": + return finish(t.updateExpression( + expr.operator, + self.explodeExpression(path.get("argument")), + expr.prefix + )); + + case "YieldExpression": + after = loc(); + let arg = expr.argument && self.explodeExpression(path.get("argument")); + + if (arg && expr.delegate) { + let result = self.makeTempVar(); + + self.emit(t.returnStatement(t.callExpression( + self.contextProperty("delegateYield"), [ + arg, + t.stringLiteral(result.property.name), + after + ] + ))); + + self.mark(after); + + return result; + } + + self.emitAssign(self.contextProperty("next"), after); + self.emit(t.returnStatement(arg || null)); + self.mark(after); + + return self.contextProperty("sent"); + + default: + throw new Error( + "unknown Expression of type " + + JSON.stringify(expr.type)); + } +}; diff --git a/node_modules/regenerator-transform/src/hoist.js b/node_modules/regenerator-transform/src/hoist.js new file mode 100644 index 0000000..9181bdf --- /dev/null +++ b/node_modules/regenerator-transform/src/hoist.js @@ -0,0 +1,151 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +import * as t from "babel-types"; +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) { + t.assertFunction(funPath.node); + + let vars = {}; + + function varDeclToExpr(vdec, 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); + + 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.node, 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.node.init; + if (t.isVariableDeclaration(init)) { + util.replaceWithOrRemove(path.get("init"), varDeclToExpr(init, false)); + } + }, + + ForXStatement: function(path) { + let left = path.get("left"); + if (left.isVariableDeclaration()) { + util.replaceWithOrRemove(left, varDeclToExpr(left.node, true)); + } + }, + + FunctionDeclaration: function(path) { + let node = path.node; + vars[node.id.name] = node.id; + + let assignment = t.expressionStatement( + t.assignmentExpression( + "=", + node.id, + t.functionExpression( + node.id, + 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); + } + + // Don't hoist variables out of inner functions. + path.skip(); + }, + + FunctionExpression: 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); +}; diff --git a/node_modules/regenerator-transform/src/index.js b/node_modules/regenerator-transform/src/index.js new file mode 100644 index 0000000..356f334 --- /dev/null +++ b/node_modules/regenerator-transform/src/index.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +export default function (context) { + const plugin = { + visitor: require("./visit").visitor, + }; + + // 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; +} diff --git a/node_modules/regenerator-transform/src/leap.js b/node_modules/regenerator-transform/src/leap.js new file mode 100644 index 0000000..047a2bf --- /dev/null +++ b/node_modules/regenerator-transform/src/leap.js @@ -0,0 +1,174 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +import assert from "assert"; +import * as t from "babel-types"; +import { inherits } from "util"; + +function Entry() { + assert.ok(this instanceof Entry); +} + +function FunctionEntry(returnLoc) { + Entry.call(this); + t.assertLiteral(returnLoc); + this.returnLoc = returnLoc; +} + +inherits(FunctionEntry, Entry); +exports.FunctionEntry = FunctionEntry; + +function LoopEntry(breakLoc, continueLoc, label) { + Entry.call(this); + + 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); + t.assertLiteral(breakLoc); + this.breakLoc = breakLoc; +} + +inherits(SwitchEntry, Entry); +exports.SwitchEntry = SwitchEntry; + +function TryEntry(firstLoc, catchEntry, finallyEntry) { + Entry.call(this); + + 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); + + 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); + 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); + + 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); + + let Emitter = require("./emit").Emitter; + 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); +}; diff --git a/node_modules/regenerator-transform/src/meta.js b/node_modules/regenerator-transform/src/meta.js new file mode 100644 index 0000000..59568ea --- /dev/null +++ b/node_modules/regenerator-transform/src/meta.js @@ -0,0 +1,104 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +import assert from "assert"; +let m = require("private").makeAccessor(); +import * as t from "babel-types"; +let hasOwn = Object.prototype.hasOwnProperty; + +function makePredicate(propertyName, knownTypes) { + function onlyChildren(node) { + 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) { + t.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); diff --git a/node_modules/regenerator-transform/src/replaceShorthandObjectMethod.js b/node_modules/regenerator-transform/src/replaceShorthandObjectMethod.js new file mode 100644 index 0000000..72aaf8f --- /dev/null +++ b/node_modules/regenerator-transform/src/replaceShorthandObjectMethod.js @@ -0,0 +1,74 @@ +import * as t from "babel-types"; +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) { + 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"); +} diff --git a/node_modules/regenerator-transform/src/util.js b/node_modules/regenerator-transform/src/util.js new file mode 100644 index 0000000..420f955 --- /dev/null +++ b/node_modules/regenerator-transform/src/util.js @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +import * as t from "babel-types"; + +export function runtimeProperty(name) { + 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(); + } +} diff --git a/node_modules/regenerator-transform/src/visit.js b/node_modules/regenerator-transform/src/visit.js new file mode 100644 index 0000000..f8089a6 --- /dev/null +++ b/node_modules/regenerator-transform/src/visit.js @@ -0,0 +1,293 @@ +/** + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * https://raw.github.com/facebook/regenerator/master/LICENSE file. An + * additional grant of patent rights can be found in the PATENTS file in + * the same directory. + */ + +"use strict"; + +import assert from "assert"; +import * as t from "babel-types"; +import { hoist } from "./hoist"; +import { Emitter } from "./emit"; +import replaceShorthandObjectMethod from "./replaceShorthandObjectMethod"; +import * as util from "./util"; + +exports.visitor = { + Function: { + exit: function(path, state) { + let node = path.node; + + if (node.generator) { + if (node.async) { + // Async generator + if (state.opts.asyncGenerators === false) return; + } else { + // Plain generator + if (state.opts.generators === false) return; + } + } else if (node.async) { + // Async function + if (state.opts.async === false) return; + } else { + // Not a generator or async function. + 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 didRenameArguments = renameArguments(path, argsId); + if (didRenameArguments) { + vars = vars || t.variableDeclaration("var", []); + const argumentIdentifier = t.identifier("arguments"); + // we need to do this as otherwise arguments in arrow functions gets hoisted + argumentIdentifier._shadowedFunctionLiteral = path; + vars.declarations.push(t.variableDeclarator( + argsId, argumentIdentifier + )); + } + + let emitter = new Emitter(contextId); + emitter.explode(path.get("body")); + + if (vars && vars.declarations.length > 0) { + outerBody.push(vars); + } + + let wrapArgs = [ + emitter.getContextFunction(innerFnId), + // 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. + node.generator ? outerFnExpr : t.nullLiteral(), + t.thisExpression() + ]; + + let tryLocsList = emitter.getTryLocsList(); + if (tryLocsList) { + wrapArgs.push(tryLocsList); + } + + let wrapCall = t.callExpression( + util.runtimeProperty(node.async ? "async" : "wrap"), + wrapArgs + ); + + outerBody.push(t.returnStatement(wrapCall)); + node.body = t.blockStatement(outerBody); + + 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__"); + } + + // 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(); + } + } +}; + +// 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) { + 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(). + return getMarkedFunctionId(funPath); + } + + return node.id; +} + +const getMarkInfo = require("private").makeAccessor(); + +function getMarkedFunctionId(funPath) { + 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"), + [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 markedId; +} + +function renameArguments(funcPath, argsId) { + let state = { + didRenameArguments: false, + argsId: argsId + }; + + funcPath.traverse(argumentsVisitor, state); + + // If the traversal replaced any arguments references, then we need to + // alias the outer function's arguments binding (be it the implicit + // arguments object or some other parameter or variable) to the variable + // named by argsId. + return state.didRenameArguments; +} + +let argumentsVisitor = { + "FunctionExpression|FunctionDeclaration": function(path) { + path.skip(); + }, + + Identifier: function(path, state) { + if (path.node.name === "arguments" && util.isReference(path)) { + util.replaceWithOrRemove(path, state.argsId); + state.didRenameArguments = true; + } + } +}; + +let functionSentVisitor = { + MetaProperty(path) { + let { node } = path; + + if (node.meta.name === "function" && node.property.name === "sent") { + util.replaceWithOrRemove(path, t.memberExpression(this.context, t.identifier("_sent"))); + } + } +}; + +let awaitVisitor = { + Function: function(path) { + path.skip(); // Don't descend into nested function scopes. + }, + + AwaitExpression: function(path) { + // 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 + )); + } +}; -- cgit v1.2.3