diff --git a/src/babel/messages.js b/src/babel/messages.js index f81932466a..94d65217ba 100644 --- a/src/babel/messages.js +++ b/src/babel/messages.js @@ -26,7 +26,6 @@ export const MESSAGES = { traverseNeedsParent: "Must pass a scope and parentPath unless traversing a Program/File got a $1 node", traverseVerifyRootFunction: "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?", - traverseVerifyVisitorFunction: "You passed \`traverse()\` a visitor object with the key $1 that's a `Function` instead of `{ enter: Function }`. You need to normalise your visitor with `traverse.explode(visitor)`.", traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2", traverseVerifyNodeType: "You gave us a visitor for the node type $1 but it's not a valid type", diff --git a/src/babel/transformation/modules/_default.js b/src/babel/transformation/modules/_default.js index 06eac02f99..c2fc5e2f83 100644 --- a/src/babel/transformation/modules/_default.js +++ b/src/babel/transformation/modules/_default.js @@ -5,7 +5,7 @@ import object from "../../helpers/object"; import * as util from "../../util"; import * as t from "../../types"; -var remapVisitor = traverse.explode({ +var remapVisitor = { enter(node, parent, scope, formatter) { if (node._skipModulesRemap) { return this.skip(); @@ -63,7 +63,7 @@ var remapVisitor = traverse.explode({ return t.sequenceExpression(nodes); } -}); +}; var importsVisitor = { ImportDeclaration: { @@ -74,7 +74,7 @@ var importsVisitor = { } }; -var exportsVisitor = traverse.explode({ +var exportsVisitor = { ExportDeclaration: { enter(node, parent, scope, formatter) { formatter.hasLocalExports = true; @@ -106,7 +106,7 @@ var exportsVisitor = traverse.explode({ } } } -}); +}; export default class DefaultFormatter { constructor(file) { diff --git a/src/babel/transformation/transformers/es6/classes.js b/src/babel/transformation/transformers/es6/classes.js index 90ca984e7f..4b62453e28 100644 --- a/src/babel/transformation/transformers/es6/classes.js +++ b/src/babel/transformation/transformers/es6/classes.js @@ -35,7 +35,7 @@ var collectPropertyReferencesVisitor = { } }; -var constructorVisitor = traverse.explode({ +var constructorVisitor = { ThisExpression: { enter(node, parent, scope, ref) { return ref; @@ -49,9 +49,9 @@ var constructorVisitor = traverse.explode({ } } } -}); +}; -var verifyConstructorVisitor = traverse.explode({ +var verifyConstructorVisitor = { MethodDefinition: { enter() { this.skip(); @@ -96,7 +96,7 @@ var verifyConstructorVisitor = traverse.explode({ } } } -}); +}; class ClassTransformer { diff --git a/src/babel/transformation/transformers/es6/parameters.default.js b/src/babel/transformation/transformers/es6/parameters.default.js index 165c177844..664d561cd9 100644 --- a/src/babel/transformation/transformers/es6/parameters.default.js +++ b/src/babel/transformation/transformers/es6/parameters.default.js @@ -10,7 +10,7 @@ var hasDefaults = function (node) { return false; }; -var iifeVisitor = traverse.explode({ +var iifeVisitor = { ReferencedIdentifier(node, parent, scope, state) { if (!state.scope.hasOwnBinding(node.name)) return; if (state.scope.bindingIdentifierEquals(node.name, node)) return; @@ -18,7 +18,7 @@ var iifeVisitor = traverse.explode({ state.iife = true; this.stop(); } -}); +}; exports.Function = function (node, parent, scope, file) { if (!hasDefaults(node)) return; diff --git a/src/babel/transformation/transformers/es6/spec.block-scoping.js b/src/babel/transformation/transformers/es6/spec.block-scoping.js index f7fc4ff0ab..6bc05a7793 100644 --- a/src/babel/transformation/transformers/es6/spec.block-scoping.js +++ b/src/babel/transformation/transformers/es6/spec.block-scoping.js @@ -1,7 +1,7 @@ import traverse from "../../../traversal"; import * as t from "../../../types"; -var visitor = traverse.explode({ +var visitor = { ReferencedIdentifier(node, parent, scope, state) { if (t.isFor(parent) && parent.left === node) return; @@ -25,7 +25,7 @@ var visitor = traverse.explode({ return t.logicalExpression("&&", assert, node); } } -}); +}; export var metadata = { optional: true, diff --git a/src/babel/transformation/transformers/es6/tail-call.js b/src/babel/transformation/transformers/es6/tail-call.js index 4da3e46365..732e8a1688 100644 --- a/src/babel/transformation/transformers/es6/tail-call.js +++ b/src/babel/transformation/transformers/es6/tail-call.js @@ -21,7 +21,7 @@ function returnBlock(expr) { } // looks for and replaces tail recursion calls -var firstPass = traverse.explode({ +var firstPass = { enter(node, parent, scope, state) { if (t.isTryStatement(parent)) { if (node === parent.block) { @@ -45,11 +45,11 @@ var firstPass = traverse.explode({ this.skip(); state.vars.push(node); } -}); +}; // hoists up function declarations, replaces `this` and `arguments` and marks // them as needed -var secondPass = traverse.explode({ +var secondPass = { ThisExpression(node, parent, scope, state) { state.needsThis = true; return state.getThisId(); @@ -71,10 +71,10 @@ var secondPass = traverse.explode({ return node; } } -}); +}; // optimizes recursion by removing `this` and `arguments` if they aren't used -var thirdPass = traverse.explode({ +var thirdPass = { ExpressionStatement(node, parent, scope, state) { var expr = node.expression; if (!t.isAssignmentExpression(expr)) return; @@ -87,7 +87,7 @@ var thirdPass = traverse.explode({ }); } } -}); +}; class TailCallTransformer { constructor(path, scope, file) { diff --git a/src/babel/traversal/index.js b/src/babel/traversal/index.js index 80cb1f0c93..72be189f80 100644 --- a/src/babel/traversal/index.js +++ b/src/babel/traversal/index.js @@ -14,7 +14,9 @@ export default function traverse(parent, opts, scope, state, parentPath) { } if (!opts) opts = {}; + visitors.verify(opts); + visitors.explode(opts); // array of nodes if (Array.isArray(parent)) { diff --git a/src/babel/traversal/visitors.js b/src/babel/traversal/visitors.js index f922351d1f..3d99110546 100644 --- a/src/babel/traversal/visitors.js +++ b/src/babel/traversal/visitors.js @@ -4,6 +4,9 @@ import * as t from "../types"; import esquery from "esquery"; export function explode(visitor, mergeConflicts) { + if (visitor._exploded) return visitor; + visitor._exploded = true; + // make sure there's no __esModule type since this is because we're using loose mode // and it sets __esModule to be enumerable on all modules :( delete visitor.__esModule; @@ -86,15 +89,12 @@ export function verify(visitor) { for (var nodeType in visitor) { if (shouldIgnoreKey(nodeType)) continue; - if (t.TYPES.indexOf(nodeType) < 0) { + if (t.TYPES.indexOf(nodeType) < 0 && !virtualTypes[nodeType]) { throw new Error(messages.get("traverseVerifyNodeType", nodeType)); } var visitors = visitor[nodeType]; - - if (typeof visitors === "function") { - throw new Error(messages.get("traverseVerifyVisitorFunction", nodeType)); - } else if (typeof visitors === "object") { + if (typeof visitors === "object") { for (var visitorKey in visitors) { if (visitorKey === "enter" || visitorKey === "exit") continue; throw new Error(messages.get("traverseVerifyVisitorProperty", nodeType, visitorKey));