diff --git a/src/babel/transformation/helpers/name-method.js b/src/babel/transformation/helpers/name-method.js index c2a9eda26a..ff76f09102 100644 --- a/src/babel/transformation/helpers/name-method.js +++ b/src/babel/transformation/helpers/name-method.js @@ -6,7 +6,7 @@ var visitor = { enter(node, parent, scope, state) { // check if this node is a referenced identifier that matches the same as our // function id - if (!t.isReferencedIdentifier(node, parent, { name: state.name })) return; + if (!this.isReferencedIdentifier({ name: state.name })) return; // check that we don't have a local variable declared as that removes the need // for the wrapper diff --git a/src/babel/transformation/helpers/remap-async-to-generator.js b/src/babel/transformation/helpers/remap-async-to-generator.js index 0e4a0842be..f93e16b286 100644 --- a/src/babel/transformation/helpers/remap-async-to-generator.js +++ b/src/babel/transformation/helpers/remap-async-to-generator.js @@ -24,7 +24,7 @@ module.exports = function (node, callId, scope) { var call = t.callExpression(callId, [node]); var id = node.id; - delete node.id; + node.id = null; if (t.isFunctionDeclaration(node)) { var declar = t.variableDeclaration("let", [ diff --git a/src/babel/transformation/transformers/es6/block-scoping-tdz.js b/src/babel/transformation/transformers/es6/block-scoping-tdz.js index 5fbb842573..e90374ee3a 100644 --- a/src/babel/transformation/transformers/es6/block-scoping-tdz.js +++ b/src/babel/transformation/transformers/es6/block-scoping-tdz.js @@ -2,7 +2,7 @@ import t from "../../../types"; var visitor = { enter(node, parent, scope, state) { - if (!t.isReferencedIdentifier(node, parent)) return; + if (!this.isReferencedIdentifier()) return; var declared = state.letRefs[node.name]; if (!declared) return; diff --git a/src/babel/transformation/transformers/es6/block-scoping.js b/src/babel/transformation/transformers/es6/block-scoping.js index 0e2aa04581..8b54cc5780 100644 --- a/src/babel/transformation/transformers/es6/block-scoping.js +++ b/src/babel/transformation/transformers/es6/block-scoping.js @@ -109,7 +109,7 @@ function traverseReplace(node, parent, scope, remaps) { var letReferenceBlockVisitor = { enter(node, parent, scope, state) { - if (t.isFunction(node)) { + if (this.isFunction()) { scope.traverse(node, letReferenceFunctionVisitor, state); return this.skip(); } @@ -119,7 +119,7 @@ var letReferenceBlockVisitor = { var letReferenceFunctionVisitor = { enter(node, parent, scope, state) { // not a direct reference - if (!t.isReferencedIdentifier(node, parent)) return; + if (!this.isReferencedIdentifier()) return; // this scope has a variable with the same name so it couldn't belong // to our let scope @@ -134,17 +134,17 @@ var letReferenceFunctionVisitor = { var hoistVarDeclarationsVisitor = { enter(node, parent, scope, self) { - if (t.isForStatement(node)) { + if (this.isForStatement()) { if (isVar(node.init, node)) { node.init = t.sequenceExpression(self.pushDeclar(node.init)); } - } else if (t.isFor(node)) { + } else if (this.isFor()) { if (isVar(node.left, node)) { node.left = node.left.declarations[0].id; } } else if (isVar(node, parent)) { return self.pushDeclar(node).map(t.expressionStatement); - } else if (t.isFunction(node)) { + } else if (this.isFunction()) { return this.skip(); } } @@ -152,7 +152,7 @@ var hoistVarDeclarationsVisitor = { var loopLabelVisitor = { enter(node, parent, scope, state) { - if (t.isLabeledStatement(node)) { + if (this.isLabeledStatement()) { state.innerLabels.push(node.label.name); } } @@ -170,13 +170,13 @@ var loopVisitor = { enter(node, parent, scope, state) { var replace; - if (t.isLoop(node)) { + if (this.isLoop()) { state.ignoreLabeless = true; scope.traverse(node, loopVisitor, state); state.ignoreLabeless = false; } - if (t.isFunction(node) || t.isLoop(node)) { + if (this.isFunction() || this.isLoop()) { return this.skip(); } @@ -204,7 +204,7 @@ var loopVisitor = { replace = t.literal(loopText); } - if (t.isReturnStatement(node)) { + if (this.isReturnStatement()) { state.hasReturn = true; replace = t.objectExpression([ t.property("init", t.identifier("v"), node.argument || t.identifier("undefined")) diff --git a/src/babel/transformation/transformers/es6/constants.js b/src/babel/transformation/transformers/es6/constants.js index 6cd1e4c95c..519d565f42 100644 --- a/src/babel/transformation/transformers/es6/constants.js +++ b/src/babel/transformation/transformers/es6/constants.js @@ -7,8 +7,8 @@ export function check(node) { var visitor = { enter(node, parent, scope, state) { - if (t.isAssignmentExpression(node) || t.isUpdateExpression(node)) { - var ids = t.getBindingIdentifiers(node); + if (this.isAssignmentExpression() || this.isUpdateExpression()) { + var ids = this.getBindingIdentifiers(); for (var name in ids) { var id = ids[name]; @@ -30,7 +30,7 @@ var visitor = { throw state.file.errorWithNode(id, messages.get("readOnly", name)); } - } else if (t.isScope(node, parent)) { + } else if (this.isScope()) { this.skip(); } } diff --git a/src/babel/transformation/transformers/es6/destructuring.js b/src/babel/transformation/transformers/es6/destructuring.js index 2648647e98..70168b16c7 100644 --- a/src/babel/transformation/transformers/es6/destructuring.js +++ b/src/babel/transformation/transformers/es6/destructuring.js @@ -219,7 +219,7 @@ export function VariableDeclaration(node, parent, scope, file) { } return nodes; -}; +} var hasRest = function (pattern) { for (var i = 0; i < pattern.elements.length; i++) { diff --git a/src/babel/transformation/transformers/es6/for-of.js b/src/babel/transformation/transformers/es6/for-of.js index 5dc26fc487..cb7f0ed326 100644 --- a/src/babel/transformation/transformers/es6/for-of.js +++ b/src/babel/transformation/transformers/es6/for-of.js @@ -41,14 +41,14 @@ export function ForOfStatement(node, parent, scope, file) { var breakVisitor = { enter(node, parent, scope, state) { - if (t.isLoop(node)) { + if (this.isLoop()) { state.ignoreLabeless = true; scope.traverse(node, breakVisitor, state); state.ignoreLabeless = false; return this.skip(); } - if (t.isBreakStatement(node)) { + if (this.isBreakStatement()) { if (!node.label && state.ignoreLabeless) return; if (node.label && node.label.name !== state.label) return; diff --git a/src/babel/transformation/transformers/es6/parameters.default.js b/src/babel/transformation/transformers/es6/parameters.default.js index e0068685ca..1a5ae2af76 100644 --- a/src/babel/transformation/transformers/es6/parameters.default.js +++ b/src/babel/transformation/transformers/es6/parameters.default.js @@ -14,7 +14,7 @@ var hasDefaults = function (node) { var iifeVisitor = { enter(node, parent, scope, state) { - if (!t.isReferencedIdentifier(node, parent)) return; + if (!this.isReferencedIdentifier()) return; if (!state.scope.hasOwnBinding(node.name)) return; if (state.scope.bindingIdentifierEquals(node.name, node)) return; diff --git a/src/babel/transformation/transformers/es6/parameters.rest.js b/src/babel/transformation/transformers/es6/parameters.rest.js index c3d0f49bf9..feec0fdc74 100644 --- a/src/babel/transformation/transformers/es6/parameters.rest.js +++ b/src/babel/transformation/transformers/es6/parameters.rest.js @@ -7,13 +7,13 @@ export var check = t.isRestElement; var memberExpressionOptimisationVisitor = { enter(node, parent, scope, state) { // check if this scope has a local binding that will shadow the rest parameter - if (t.isScope(node, parent) && !scope.bindingIdentifierEquals(state.name, state.outerBinding)) { + if (this.isScope() && !scope.bindingIdentifierEquals(state.name, state.outerBinding)) { return this.skip(); } // skip over functions as whatever `arguments` we reference inside will refer // to the wrong function - if (t.isFunctionDeclaration(node) || t.isFunctionExpression(node)) { + if (this.isFunctionDeclaration() || this.isFunctionExpression()) { state.noOptimise = true; scope.traverse(node, memberExpressionOptimisationVisitor, state); state.noOptimise = false; @@ -21,7 +21,7 @@ var memberExpressionOptimisationVisitor = { } // is this a referenced identifier and is it referencing the rest parameter? - if (!t.isReferencedIdentifier(node, parent, { name: state.name })) return; + if (!this.isReferencedIdentifier({ name: state.name })) return; if (!state.noOptimise && t.isMemberExpression(parent) && parent.computed) { // if we know that this member expression is referencing a number then we can safely diff --git a/src/babel/transformation/transformers/es6/properties.shorthand.js b/src/babel/transformation/transformers/es6/properties.shorthand.js index f27c895c06..42e11302e2 100644 --- a/src/babel/transformation/transformers/es6/properties.shorthand.js +++ b/src/babel/transformation/transformers/es6/properties.shorthand.js @@ -1,4 +1,3 @@ -import clone from "lodash/lang/clone"; import t from "../../../types"; export function check(node) { @@ -12,6 +11,6 @@ export function Property(node) { if (node.shorthand) { node.shorthand = false; - node.key = t.removeComments(clone(node.key)); + node.key = t.removeComments(t.clone(node.key)); } } diff --git a/src/babel/transformation/transformers/es6/tail-call.js b/src/babel/transformation/transformers/es6/tail-call.js index 7cb201b002..0c6cb72985 100644 --- a/src/babel/transformation/transformers/es6/tail-call.js +++ b/src/babel/transformation/transformers/es6/tail-call.js @@ -17,7 +17,7 @@ function returnBlock(expr) { // looks for and replaces tail recursion calls var firstPass = { enter(node, parent, scope, state) { - if (t.isIfStatement(node)) { + if (this.isIfStatement()) { if (t.isReturnStatement(node.alternate)) { t.ensureBlock(node, "alternate"); } @@ -25,7 +25,7 @@ var firstPass = { if (t.isReturnStatement(node.consequent)) { t.ensureBlock(node, "consequent"); } - } else if (t.isReturnStatement(node)) { + } else if (this.isReturnStatement()) { this.skip(); return state.subTransform(node.argument); } else if (t.isTryStatement(parent)) { @@ -34,9 +34,9 @@ var firstPass = { } else if (parent.finalizer && node !== parent.finalizer) { this.skip(); } - } else if (t.isFunction(node)) { + } else if (this.isFunction()) { this.skip(); - } else if (t.isVariableDeclaration(node)) { + } else if (this.isVariableDeclaration()) { this.skip(); state.vars.push(node); } @@ -47,15 +47,15 @@ var firstPass = { // them as needed var secondPass = { enter(node, parent, scope, state) { - if (t.isThisExpression(node)) { + if (this.isThisExpression()) { state.needsThis = true; return state.getThisId(); - } else if (t.isReferencedIdentifier(node, parent, { name: "arguments" })) { + } else if (this.isReferencedIdentifier({ name: "arguments" })) { state.needsArguments = true; return state.getArgumentsId(); - } else if (t.isFunction(node)) { + } else if (this.isFunction()) { this.skip(); - if (t.isFunctionDeclaration(node)) { + if (this.isFunctionDeclaration()) { node = t.variableDeclaration("var", [ t.variableDeclarator(node.id, t.toExpression(node)) ]); @@ -69,7 +69,7 @@ var secondPass = { // optimizes recursion by removing `this` and `arguments` if they aren't used var thirdPass = { enter(node, parent, scope, state) { - if (!t.isExpressionStatement(node)) return; + if (!this.isExpressionStatement()) return; var expr = node.expression; if (!t.isAssignmentExpression(expr)) return; diff --git a/src/babel/transformation/transformers/internal/alias-functions.js b/src/babel/transformation/transformers/internal/alias-functions.js index 45d06707cd..22b4a511ee 100644 --- a/src/babel/transformation/transformers/internal/alias-functions.js +++ b/src/babel/transformation/transformers/internal/alias-functions.js @@ -2,7 +2,7 @@ import t from "../../../types"; var functionChildrenVisitor = { enter(node, parent, scope, state) { - if (t.isFunction(node) && !node._aliasFunction) { + if (this.isFunction() && !node._aliasFunction) { return this.skip(); } @@ -10,22 +10,22 @@ var functionChildrenVisitor = { var getId; - if (t.isIdentifier(node) && node.name === "arguments") { + if (this.isIdentifier() && node.name === "arguments") { getId = state.getArgumentsId; - } else if (t.isThisExpression(node)) { + } else if (this.isThisExpression()) { getId = state.getThisId; } else { return; } - if (t.isReferenced(node, parent)) return getId(); + if (this.isReferenced()) return getId(); } }; var functionVisitor = { enter(node, parent, scope, state) { if (!node._aliasFunction) { - if (t.isFunction(node)) { + if (this.isFunction()) { // stop traversal of this node as it'll be hit again by this transformer return this.skip(); } else { diff --git a/src/babel/transformation/transformers/other/runtime.js b/src/babel/transformation/transformers/other/runtime.js index 231039d7a3..bf925d5dd6 100644 --- a/src/babel/transformation/transformers/other/runtime.js +++ b/src/babel/transformation/transformers/other/runtime.js @@ -16,14 +16,15 @@ var ALIASABLE_CONSTRUCTORS = [ "Map", "WeakMap", "Set", - "WeakSet" + "WeakSet", + "Number" ]; var astVisitor = { enter(node, parent, scope, file) { var prop; - if (t.isMemberExpression(node) && t.isReferenced(node, parent)) { + if (this.isMemberExpression() && this.isReferenced()) { // Array.from -> _core.Array.from var obj = node.object; prop = node.property; @@ -34,10 +35,10 @@ var astVisitor = { this.skip(); return t.prependToMemberExpression(node, file.get("coreIdentifier")); } - } else if (t.isReferencedIdentifier(node, parent) && !t.isMemberExpression(parent) && includes(ALIASABLE_CONSTRUCTORS, node.name) && !scope.getBindingIdentifier(node.name)) { + } else if (this.isReferencedIdentifier() && !t.isMemberExpression(parent) && includes(ALIASABLE_CONSTRUCTORS, node.name) && !scope.getBindingIdentifier(node.name)) { // Symbol() -> _core.Symbol(); new Promise -> new _core.Promise return t.memberExpression(file.get("coreIdentifier"), node); - } else if (t.isCallExpression(node)) { + } else if (this.isCallExpression()) { // arr[Symbol.iterator]() -> _core.$for.getIterator(arr) var callee = node.callee; @@ -53,7 +54,7 @@ var astVisitor = { CORE_ID: file.get("coreIdentifier"), VALUE: callee.object }); - } else if (t.isBinaryExpression(node)) { + } else if (this.isBinaryExpression()) { // Symbol.iterator in arr -> core.$for.isIterable(arr) if (node.operator !== "in") return; @@ -94,7 +95,7 @@ export function pre(file) { } export function Identifier(node, parent, scope, file) { - if (t.isReferencedIdentifier(node, parent, { name: "regeneratorRuntime" })) { + if (this.isReferencedIdentifier({ name: "regeneratorRuntime" })) { return file.get("regeneratorIdentifier"); } } diff --git a/src/babel/transformation/transformers/playground/mallet-operator.js b/src/babel/transformation/transformers/playground/mallet-operator.js index bcf1af4298..c70a13d62b 100644 --- a/src/babel/transformation/transformers/playground/mallet-operator.js +++ b/src/babel/transformation/transformers/playground/mallet-operator.js @@ -6,8 +6,7 @@ export var playground = true; build(exports, { is(node, file) { - var is = t.isAssignmentExpression(node) && node.operator === "||="; - if (is) { + if (t.isAssignmentExpression(node, { operator: "||=" })) { var left = node.left; if (!t.isMemberExpression(left) && !t.isIdentifier(left)) { throw file.errorWithNode(left, messages.get("expectedMemberExpressionOrIdentifier")); diff --git a/src/babel/transformation/transformers/playground/memoization-operator.js b/src/babel/transformation/transformers/playground/memoization-operator.js index ae75000ed2..1939472db6 100644 --- a/src/babel/transformation/transformers/playground/memoization-operator.js +++ b/src/babel/transformation/transformers/playground/memoization-operator.js @@ -5,7 +5,7 @@ export var playground = true; build(exports, { is(node) { - var is = t.isAssignmentExpression(node) && node.operator === "?="; + var is = t.isAssignmentExpression(node, { operator: "?=" }); if (is) t.assertMemberExpression(node.left); return is; }, diff --git a/src/babel/transformation/transformers/playground/object-getter-memoization.js b/src/babel/transformation/transformers/playground/object-getter-memoization.js index fbcf52f4ea..14b63dc454 100644 --- a/src/babel/transformation/transformers/playground/object-getter-memoization.js +++ b/src/babel/transformation/transformers/playground/object-getter-memoization.js @@ -4,9 +4,9 @@ export var playground = true; var visitor = { enter(node, parent, scope, state) { - if (t.isFunction(node)) return this.skip(); + if (this.isFunction()) return this.skip(); - if (t.isReturnStatement(node) && node.argument) { + if (this.isReturnStatement() && node.argument) { node.argument = t.memberExpression(t.callExpression(state.file.addHelper("define-property"), [ t.thisExpression(), state.key, diff --git a/src/babel/transformation/transformers/spec/undefined-to-void.js b/src/babel/transformation/transformers/spec/undefined-to-void.js index e7c8e563f3..c3b284bdf3 100644 --- a/src/babel/transformation/transformers/spec/undefined-to-void.js +++ b/src/babel/transformation/transformers/spec/undefined-to-void.js @@ -3,7 +3,7 @@ import t from "../../../types"; export var optional = true; export function Identifier(node, parent) { - if (node.name === "undefined" && t.isReferenced(node, parent)) { + if (node.name === "undefined" && this.isReferenced()) { return t.unaryExpression("void", t.literal(0), true); } } diff --git a/src/babel/transformation/transformers/utility/remove-debugger.js b/src/babel/transformation/transformers/utility/remove-debugger.js index c0509f3f2b..20a8583274 100644 --- a/src/babel/transformation/transformers/utility/remove-debugger.js +++ b/src/babel/transformation/transformers/utility/remove-debugger.js @@ -3,7 +3,7 @@ import t from "../../../types"; export var optional = true; export function ExpressionStatement(node) { - if (t.isIdentifier(node.expression, { name: "debugger" })) { + if (this.get("expression").isIdentifier({ name: "debugger" })) { this.remove(); } } diff --git a/src/babel/transformation/transformers/validation/undeclared-variable-check.js b/src/babel/transformation/transformers/validation/undeclared-variable-check.js index ea7b804053..153c7d5745 100644 --- a/src/babel/transformation/transformers/validation/undeclared-variable-check.js +++ b/src/babel/transformation/transformers/validation/undeclared-variable-check.js @@ -1,11 +1,10 @@ import levenshtein from "leven"; import * as messages from "../../../messages"; -import t from "../../../types"; export var optional = true; export function Identifier(node, parent, scope, file) { - if (!t.isReferenced(node, parent)) return; + if (!this.isReferenced()) return; if (scope.hasBinding(node.name)) return; // get the closest declaration to offer as a suggestion diff --git a/src/babel/traversal/context.js b/src/babel/traversal/context.js index c431fd3c4d..aac749a024 100644 --- a/src/babel/traversal/context.js +++ b/src/babel/traversal/context.js @@ -2,7 +2,7 @@ import TraversalPath from "./path"; import flatten from "lodash/array/flatten"; import compact from "lodash/array/compact"; -export default class TraversalConext { +export default class TraversalContext { constructor(scope, opts, state, parentPath) { this.shouldFlatten = false; this.parentPath = parentPath; @@ -17,7 +17,7 @@ export default class TraversalConext { } visitNode(node, obj, key) { - var iteration = new TraversalPath(this, node, obj, key); + var iteration = TraversalPath.get(this.parentPath, this, node, obj, key); return iteration.visit(); } diff --git a/src/babel/traversal/index.js b/src/babel/traversal/index.js index 062dd40459..f815f53ff6 100644 --- a/src/babel/traversal/index.js +++ b/src/babel/traversal/index.js @@ -42,13 +42,14 @@ traverse.node = function (node, opts, scope, state, parentPath) { function clearNode(node) { node._declarations = null; node.extendedRange = null; - node._scopeInfo = null; - node.tokens = null; - node.range = null; - node.start = null; - node.end = null; - node.loc = null; - node.raw = null; + node._scopeInfo = null; + node._paths = null; + node.tokens = null; + node.range = null; + node.start = null; + node.end = null; + node.loc = null; + node.raw = null; if (Array.isArray(node.trailingComments)) { clearComments(node.trailingComments); @@ -57,11 +58,18 @@ function clearNode(node) { if (Array.isArray(node.leadingComments)) { clearComments(node.leadingComments); } + + for (var key in node) { + var val = node[key]; + if (Array.isArray(val)) { + delete val._paths; + } + } } var clearVisitor = { noScope: true, - enter: clearNode + exit: clearNode }; function clearComments(comments) { @@ -71,8 +79,8 @@ function clearComments(comments) { } traverse.removeProperties = function (tree) { - clearNode(tree); traverse(tree, clearVisitor); + clearNode(tree); return tree; }; diff --git a/src/babel/traversal/path.js b/src/babel/traversal/path.js index a07d46a1cb..0d8e80e7e9 100644 --- a/src/babel/traversal/path.js +++ b/src/babel/traversal/path.js @@ -4,23 +4,34 @@ import Scope from "./scope"; import t from "../types"; export default class TraversalPath { - constructor(context, parent, container, key) { - this.shouldRemove = false; - this.shouldSkip = false; - this.shouldStop = false; + constructor(parentPath, parent, container) { + this.parentPath = parentPath; + this.container = container; + this.parent = parent; + this.data = {}; + } - this.parentPath = context.parentPath; - this.context = context; - this.state = this.context.state; - this.opts = this.context.opts; + static get(parentPath, context, parent, container, key) { + var targetNode = container[key]; + var paths = container._paths ||= []; + var path; - this.container = container; - this.key = key; + for (var i = 0; i < paths.length; i++) { + var pathCheck = paths[i]; + if (pathCheck.node === targetNode) { + path = pathCheck; + break; + } + } - this.parent = parent; - this.state = context.state; + if (!path) { + path = new TraversalPath(parentPath, parent, container); + paths.push(path); + } - this.setScope(); + path.setContext(context, key); + + return path; } static getScope(node, parent, scope) { @@ -34,10 +45,31 @@ export default class TraversalPath { return ourScope; } + setData(key, val) { + return this.data[key] = val; + } + + getData(key) { + return this.data[key]; + } + setScope() { this.scope = TraversalPath.getScope(this.node, this.parent, this.context.scope); } + setContext(context, key) { + this.shouldRemove = false; + this.shouldSkip = false; + this.shouldStop = false; + + this.context = context; + this.state = context.state; + this.opts = context.opts; + this.key = key; + + this.setScope(); + } + remove() { this.shouldRemove = true; this.shouldSkip = true; @@ -114,14 +146,13 @@ export default class TraversalPath { } } - visit() { - var opts = this.opts; - var node = this.node; + isBlacklisted() { + var blacklist = this.opts.blacklist; + return blacklist && blacklist.indexOf(this.node.type) > -1; + } - // type is blacklisted - if (opts.blacklist && opts.blacklist.indexOf(node.type) > -1) { - return false; - } + visit() { + if (this.isBlacklisted()) return false; this.call("enter"); @@ -129,7 +160,8 @@ export default class TraversalPath { return this.shouldStop; } - node = this.node; + var node = this.node; + var opts = this.opts; if (Array.isArray(node)) { // traverse over these replacement nodes we purposely don't call exitNode @@ -139,13 +171,38 @@ export default class TraversalPath { } } else { traverse.node(node, opts, this.scope, this.state, this); + this.call("exit"); } return this.shouldStop; } - isReferencedIdentifier() { - return t.isReferencedIdentifier(this.node); + get(key) { + return TraversalPath.get(this, this.context, this.node, this.node, key); + } + + isReferencedIdentifier(opts) { + return t.isReferencedIdentifier(this.node, this.parent, opts); + } + + isReferenced() { + return t.isReferenced(this.node, this.parent); + } + + isScope() { + return t.isScope(this.node, this.parent); + } + + getBindingIdentifiers() { + return t.getBindingIdentifiers(this.node); } } + +for (var i = 0; i < t.TYPES.length; i++) { + let type = t.TYPES[i]; + let typeKey = `is${type}`; + TraversalPath.prototype[typeKey] = function (opts) { + return t[typeKey](this.node, opts); + }; +} diff --git a/src/babel/types/index.js b/src/babel/types/index.js index 91c36ed9e3..545703d0fd 100644 --- a/src/babel/types/index.js +++ b/src/babel/types/index.js @@ -6,6 +6,7 @@ import isString from "lodash/lang/isString"; import compact from "lodash/array/compact"; import esutils from "esutils"; import object from "../helpers/object"; +import clone from "lodash/lang/clone"; import each from "lodash/collection/each"; import uniq from "lodash/array/uniq"; @@ -48,7 +49,7 @@ each(t.VISITOR_KEYS, function (keys, type) { each(t.ALIAS_KEYS, function (aliases, type) { each(aliases, function (alias) { - var types = t.FLIPPED_ALIAS_KEYS[alias] = t.FLIPPED_ALIAS_KEYS[alias] || []; + var types = t.FLIPPED_ALIAS_KEYS[alias] ||= []; types.push(type); }); }); @@ -58,6 +59,8 @@ each(t.FLIPPED_ALIAS_KEYS, function (types, type) { registerType(type, false); }); +t.TYPES = Object.keys(t.VISITOR_KEYS).concat(Object.keys(t.FLIPPED_ALIAS_KEYS)); + /** * Returns whether `node` is of given `type`. * @@ -413,6 +416,49 @@ t.ensureBlock = function (node, key) { return node[key] = t.toBlock(node[key], node); }; +/** + * Description + * + * @param {Object} node + * @returns {Object} + */ + +t.clone = function (node) { + var newNode = {}; + for (var key in node) { + if (key[0] === "_") continue; + newNode[key] = node[key]; + } + return newNode; +}; + +/** + * Description + * + * @param {Object} node + * @returns {Object} + */ + +t.cloneDeep = function (node) { + var newNode = {}; + + for (var key in node) { + var val = node[key]; + + if (val) { + if (val.type) { + val = t.cloneDeep(val); + } else if (Array.isArray(val)) { + val = val.map(t.cloneDeep); + } + } + + newNode[key] = val; + } + + return newNode; +}; + /** * Build a function that when called will return whether or not the * input `node` `MemberExpression` matches the input `match`.