make traversal code simpler
This commit is contained in:
@@ -9,8 +9,10 @@ function CommonJSFormatter(file) {
|
||||
DefaultFormatter.apply(this, arguments);
|
||||
|
||||
var hasNonDefaultExports = false;
|
||||
traverse(file.ast, function (node) {
|
||||
if (t.isExportDeclaration(node) && !node.default) hasNonDefaultExports = true;
|
||||
traverse(file.ast, {
|
||||
enter: function (node) {
|
||||
if (t.isExportDeclaration(node) && !node.default) hasNonDefaultExports = true;
|
||||
}
|
||||
});
|
||||
this.hasNonDefaultExports = hasNonDefaultExports;
|
||||
}
|
||||
@@ -31,9 +33,6 @@ CommonJSFormatter.prototype.importSpecifier = function (specifier, node, nodes)
|
||||
]));
|
||||
} else {
|
||||
// import foo from "foo";
|
||||
if (specifier.default) {
|
||||
specifier.id = t.identifier("default");
|
||||
}
|
||||
|
||||
var templateName = "require-assign";
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var SETTER_MODULE_NAMESPACE = t.identifier("m");
|
||||
var DEFAULT_IDENTIFIER = t.identifier("default");
|
||||
var NULL_SETTER = t.literal(null);
|
||||
|
||||
function SystemFormatter(file) {
|
||||
@@ -117,9 +116,6 @@ SystemFormatter.prototype.importSpecifier = function (specifier, node) {
|
||||
var variableName = t.getSpecifierName(specifier);
|
||||
|
||||
// import foo from "foo";
|
||||
if (specifier.default) {
|
||||
specifier.id = DEFAULT_IDENTIFIER;
|
||||
}
|
||||
|
||||
var MODULE_NAME = node.source.value;
|
||||
|
||||
|
||||
@@ -15,38 +15,42 @@ var go = function (getBody, node, file, scope) {
|
||||
|
||||
// traverse the function and find all alias functions so we can alias
|
||||
// `arguments` and `this` if necessary
|
||||
traverse(node, function (node) {
|
||||
if (!node._aliasFunction) {
|
||||
if (t.isFunction(node)) {
|
||||
// stop traversal of this node as it'll be hit again by this transformer
|
||||
return false;
|
||||
} else {
|
||||
return;
|
||||
traverse(node, {
|
||||
enter: function (node) {
|
||||
if (!node._aliasFunction) {
|
||||
if (t.isFunction(node)) {
|
||||
// stop traversal of this node as it'll be hit again by this transformer
|
||||
return false;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// traverse all child nodes of this function and find `arguments` and `this`
|
||||
traverse(node, {
|
||||
enter: function (node, parent) {
|
||||
if (t.isFunction(node) && !node._aliasFunction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node._ignoreAliasFunctions) return false;
|
||||
|
||||
var getId;
|
||||
|
||||
if (t.isIdentifier(node) && node.name === "arguments") {
|
||||
getId = getArgumentsId;
|
||||
} else if (t.isThisExpression(node)) {
|
||||
getId = getThisId;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.isReferenced(node, parent)) return getId();
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// traverse all child nodes of this function and find `arguments` and `this`
|
||||
traverse(node, function (node, parent) {
|
||||
if (t.isFunction(node) && !node._aliasFunction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node._ignoreAliasFunctions) return false;
|
||||
|
||||
var getId;
|
||||
|
||||
if (t.isIdentifier(node) && node.name === "arguments") {
|
||||
getId = getArgumentsId;
|
||||
} else if (t.isThisExpression(node)) {
|
||||
getId = getThisId;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t.isReferenced(node, parent)) return getId();
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
var body;
|
||||
|
||||
@@ -247,17 +247,19 @@ Class.prototype.replaceInstanceSuperReferences = function (methodNode) {
|
||||
var method = methodNode.value;
|
||||
var self = this;
|
||||
|
||||
traverse(method, function (node, parent) {
|
||||
if (t.isIdentifier(node, { name: "super" })) {
|
||||
return self.superIdentifier(methodNode, node, parent);
|
||||
} else if (t.isCallExpression(node)) {
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (callee.object.name !== "super") return;
|
||||
traverse(method, {
|
||||
enter: function (node, parent) {
|
||||
if (t.isIdentifier(node, { name: "super" })) {
|
||||
return self.superIdentifier(methodNode, node, parent);
|
||||
} else if (t.isCallExpression(node)) {
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (callee.object.name !== "super") return;
|
||||
|
||||
// super.test(); -> ClassName.prototype.MethodName.call(this);
|
||||
callee.property = t.memberExpression(callee.property, t.identifier("call"));
|
||||
node.arguments.unshift(t.thisExpression());
|
||||
// super.test(); -> ClassName.prototype.MethodName.call(this);
|
||||
callee.property = t.memberExpression(callee.property, t.identifier("call"));
|
||||
node.arguments.unshift(t.thisExpression());
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -69,12 +69,14 @@ exports.ForStatement = function (node, parent, file) {
|
||||
|
||||
if (!hasConstants) return;
|
||||
|
||||
traverse(node, function (child, parent, scope) {
|
||||
if (child._ignoreConstant) return;
|
||||
if (t.isVariableDeclaration(child)) return;
|
||||
traverse(node, {
|
||||
enter: function (child, parent, scope) {
|
||||
if (child._ignoreConstant) return;
|
||||
if (t.isVariableDeclaration(child)) return;
|
||||
|
||||
if (t.isVariableDeclarator(child) || t.isDeclaration(child) || t.isAssignmentExpression(child)) {
|
||||
check(parent, getIds(child), scope);
|
||||
if (t.isVariableDeclarator(child) || t.isDeclaration(child) || t.isAssignmentExpression(child)) {
|
||||
check(parent, getIds(child), scope);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -37,7 +37,7 @@ exports.Function = function (node, parent, file, scope) {
|
||||
};
|
||||
|
||||
check(def, node);
|
||||
traverse(def, check);
|
||||
traverse(def, { enter: check });
|
||||
});
|
||||
|
||||
// we're accessing a variable that's already defined within this function
|
||||
|
||||
@@ -176,7 +176,7 @@ LetScoping.prototype.remap = function () {
|
||||
|
||||
var traverseReplace = function (node, parent) {
|
||||
replace(node, parent);
|
||||
traverse(node, replace);
|
||||
traverse(node, { enter: replace });
|
||||
};
|
||||
|
||||
var loopParent = this.loopParent;
|
||||
@@ -186,7 +186,7 @@ LetScoping.prototype.remap = function () {
|
||||
traverseReplace(loopParent.update, loopParent);
|
||||
}
|
||||
|
||||
traverse(block, replace);
|
||||
traverse(block, { enter: replace });
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -275,33 +275,35 @@ LetScoping.prototype.checkLoop = function () {
|
||||
hasBreak: false,
|
||||
};
|
||||
|
||||
traverse(this.block, function (node, parent) {
|
||||
var replace;
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent) {
|
||||
var replace;
|
||||
|
||||
if (t.isFunction(node) || t.isLoop(node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node && !node.label) {
|
||||
if (t.isBreakStatement(node)) {
|
||||
if (t.isSwitchCase(parent)) return;
|
||||
|
||||
has.hasBreak = true;
|
||||
replace = t.returnStatement(t.literal("break"));
|
||||
} else if (t.isContinueStatement(node)) {
|
||||
has.hasContinue = true;
|
||||
replace = t.returnStatement(t.literal("continue"));
|
||||
if (t.isFunction(node) || t.isLoop(node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isReturnStatement(node)) {
|
||||
has.hasReturn = true;
|
||||
replace = t.returnStatement(t.objectExpression([
|
||||
t.property("init", t.identifier("v"), node.argument || t.identifier("undefined"))
|
||||
]));
|
||||
}
|
||||
if (node && !node.label) {
|
||||
if (t.isBreakStatement(node)) {
|
||||
if (t.isSwitchCase(parent)) return;
|
||||
|
||||
if (replace) return t.inherits(replace, node);
|
||||
has.hasBreak = true;
|
||||
replace = t.returnStatement(t.literal("break"));
|
||||
} else if (t.isContinueStatement(node)) {
|
||||
has.hasContinue = true;
|
||||
replace = t.returnStatement(t.literal("continue"));
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isReturnStatement(node)) {
|
||||
has.hasReturn = true;
|
||||
replace = t.returnStatement(t.objectExpression([
|
||||
t.property("init", t.identifier("v"), node.argument || t.identifier("undefined"))
|
||||
]));
|
||||
}
|
||||
|
||||
if (replace) return t.inherits(replace, node);
|
||||
}
|
||||
});
|
||||
|
||||
return has;
|
||||
@@ -314,19 +316,21 @@ LetScoping.prototype.checkLoop = function () {
|
||||
|
||||
LetScoping.prototype.hoistVarDeclarations = function () {
|
||||
var self = this;
|
||||
traverse(this.block, function (node, parent) {
|
||||
if (t.isForStatement(node)) {
|
||||
if (isVar(node.init, node)) {
|
||||
node.init = t.sequenceExpression(self.pushDeclar(node.init));
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent) {
|
||||
if (t.isForStatement(node)) {
|
||||
if (isVar(node.init, node)) {
|
||||
node.init = t.sequenceExpression(self.pushDeclar(node.init));
|
||||
}
|
||||
} else if (t.isFor(node)) {
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
} else if (t.isFor(node)) {
|
||||
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)) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -359,31 +363,35 @@ LetScoping.prototype.getLetReferences = function () {
|
||||
|
||||
// traverse through this block, stopping on functions and checking if they
|
||||
// contain any outside let references
|
||||
traverse(this.block, function (node, parent, scope) {
|
||||
if (t.isFunction(node)) {
|
||||
traverse(node, function (node, parent) {
|
||||
// not an identifier so we have no use
|
||||
if (!t.isIdentifier(node)) return;
|
||||
traverse(this.block, {
|
||||
enter: function (node, parent, scope) {
|
||||
if (t.isFunction(node)) {
|
||||
traverse(node, {
|
||||
enter: function (node, parent) {
|
||||
// not an identifier so we have no use
|
||||
if (!t.isIdentifier(node)) return;
|
||||
|
||||
// not a direct reference
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
// not a direct reference
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
|
||||
// this scope has a variable with the same name so it couldn't belong
|
||||
// to our let scope
|
||||
if (scope.hasOwn(node.name)) return;
|
||||
// this scope has a variable with the same name so it couldn't belong
|
||||
// to our let scope
|
||||
if (scope.hasOwn(node.name)) return;
|
||||
|
||||
closurify = true;
|
||||
closurify = true;
|
||||
|
||||
// this key doesn't appear just outside our scope
|
||||
if (!_.contains(self.info.outsideKeys, node.name)) return;
|
||||
// this key doesn't appear just outside our scope
|
||||
if (!_.contains(self.info.outsideKeys, node.name)) return;
|
||||
|
||||
// push this badboy
|
||||
self.letReferences[node.name] = node;
|
||||
});
|
||||
// push this badboy
|
||||
self.letReferences[node.name] = node;
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
} else if (t.isLoop(node)) {
|
||||
return false;
|
||||
return false;
|
||||
} else if (t.isLoop(node)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -21,11 +21,13 @@ exports.MethodDefinition = function (node, parent, file, scope) {
|
||||
var memoId = t.memberExpression(t.thisExpression(), t.identifier(key));
|
||||
var doneId = t.memberExpression(t.thisExpression(), t.identifier(key + "Done"));
|
||||
|
||||
traverse(value, function (node) {
|
||||
if (t.isFunction(node)) return;
|
||||
traverse(value, {
|
||||
enter: function (node) {
|
||||
if (t.isFunction(node)) return;
|
||||
|
||||
if (t.isReturnStatement(node) && node.argument) {
|
||||
node.argument = t.assignmentExpression("=", memoId, node.argument);
|
||||
if (t.isReturnStatement(node) && node.argument) {
|
||||
node.argument = t.assignmentExpression("=", memoId, node.argument);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ var Scope = require("./scope");
|
||||
var t = require("../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
function traverse(parent, callbacks, opts) {
|
||||
function traverse(parent, opts, scope) {
|
||||
// falsy node
|
||||
if (!parent) return;
|
||||
|
||||
// array of nodes
|
||||
if (_.isArray(parent)) {
|
||||
_.each(parent, function (node) {
|
||||
traverse(node, callbacks, opts);
|
||||
traverse(node, opts, scope);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -21,13 +21,6 @@ function traverse(parent, callbacks, opts) {
|
||||
if (!keys) return;
|
||||
|
||||
opts = opts || {};
|
||||
if (_.isArray(opts)) opts = { blacklist: opts };
|
||||
|
||||
// blacklist these node types from being traversed
|
||||
var blacklistTypes = opts.blacklist || [];
|
||||
|
||||
// normalise callbacks
|
||||
if (_.isFunction(callbacks)) callbacks = { enter: callbacks };
|
||||
|
||||
for (var i in keys) {
|
||||
var key = keys[i];
|
||||
@@ -41,7 +34,7 @@ function traverse(parent, callbacks, opts) {
|
||||
if (!node) return;
|
||||
|
||||
// type is blacklisted
|
||||
if (blacklistTypes.indexOf(node.type) > -1) return;
|
||||
if (opts.blacklist && opts.blacklist.indexOf(node.type) > -1) return;
|
||||
|
||||
// replace node
|
||||
var maybeReplace = function (result) {
|
||||
@@ -58,12 +51,12 @@ function traverse(parent, callbacks, opts) {
|
||||
};
|
||||
|
||||
//
|
||||
var opts2 = { scope: opts.scope, blacklist: opts.blacklist };
|
||||
if (t.isScope(node)) opts2.scope = new Scope(node, opts.scope);
|
||||
var ourScope = scope;
|
||||
if (t.isScope(node)) ourScope = new Scope(node, scope);
|
||||
|
||||
// enter
|
||||
if (callbacks.enter) {
|
||||
var result = callbacks.enter(node, parent, opts2.scope);
|
||||
if (opts.enter) {
|
||||
var result = opts.enter(node, parent, ourScope);
|
||||
maybeReplace(result);
|
||||
|
||||
// stop iteration
|
||||
@@ -71,11 +64,11 @@ function traverse(parent, callbacks, opts) {
|
||||
}
|
||||
|
||||
// traverse node
|
||||
traverse(node, callbacks, opts2);
|
||||
traverse(node, opts, ourScope);
|
||||
|
||||
// exit
|
||||
if (callbacks.exit) {
|
||||
maybeReplace(callbacks.exit(node, parent, opts2.scope));
|
||||
if (opts.exit) {
|
||||
maybeReplace(opts.exit(node, parent, ourScope));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -113,7 +106,7 @@ traverse.removeProperties = function (tree) {
|
||||
};
|
||||
|
||||
clear(tree);
|
||||
traverse(tree, clear);
|
||||
traverse(tree, { enter: clear });
|
||||
|
||||
return tree;
|
||||
};
|
||||
@@ -129,12 +122,15 @@ traverse.hasType = function (tree, type, blacklistTypes) {
|
||||
// the type we're looking for is the same as the passed node
|
||||
if (tree.type === type) return true;
|
||||
|
||||
traverse(tree, function (node) {
|
||||
if (node.type === type) {
|
||||
has = true;
|
||||
return false;
|
||||
traverse(tree, {
|
||||
blacklist: blacklistTypes,
|
||||
enter: function (node) {
|
||||
if (node.type === type) {
|
||||
has = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}, { blacklist: blacklistTypes });
|
||||
});
|
||||
|
||||
return has;
|
||||
};
|
||||
|
||||
@@ -82,31 +82,33 @@ Scope.prototype.getInfo = function () {
|
||||
// Program, Function - var variables
|
||||
|
||||
if (t.isProgram(block) || t.isFunction(block)) {
|
||||
traverse(block, function (node, parent, scope) {
|
||||
if (t.isFor(node)) {
|
||||
_.each(FOR_KEYS, function (key) {
|
||||
var declar = node[key];
|
||||
if (t.isVar(declar)) add(declar);
|
||||
});
|
||||
traverse(block, {
|
||||
enter: function (node, parent, scope) {
|
||||
if (t.isFor(node)) {
|
||||
_.each(FOR_KEYS, function (key) {
|
||||
var declar = node[key];
|
||||
if (t.isVar(declar)) add(declar);
|
||||
});
|
||||
}
|
||||
|
||||
// this block is a function so we'll stop since none of the variables
|
||||
// declared within are accessible
|
||||
if (t.isFunction(node)) return false;
|
||||
|
||||
// function identifier doesn't belong to this scope
|
||||
if (block.id && node === block.id) return;
|
||||
|
||||
if (t.isIdentifier(node) && t.isReferenced(node, parent) && !scope.has(node.name)) {
|
||||
add(node, true);
|
||||
}
|
||||
|
||||
// we've ran into a declaration!
|
||||
// we'll let the BlockStatement scope deal with `let` declarations unless
|
||||
if (t.isDeclaration(node) && !t.isLet(node)) {
|
||||
add(node);
|
||||
}
|
||||
}
|
||||
|
||||
// this block is a function so we'll stop since none of the variables
|
||||
// declared within are accessible
|
||||
if (t.isFunction(node)) return false;
|
||||
|
||||
// function identifier doesn't belong to this scope
|
||||
if (block.id && node === block.id) return;
|
||||
|
||||
if (t.isIdentifier(node) && t.isReferenced(node, parent) && !scope.has(node.name)) {
|
||||
add(node, true);
|
||||
}
|
||||
|
||||
// we've ran into a declaration!
|
||||
// we'll let the BlockStatement scope deal with `let` declarations unless
|
||||
if (t.isDeclaration(node) && !t.isLet(node)) {
|
||||
add(node);
|
||||
}
|
||||
}, { scope: this });
|
||||
}, this);
|
||||
}
|
||||
|
||||
// Function - params, rest
|
||||
|
||||
@@ -150,9 +150,11 @@ exports.template = function (name, nodes, keepExpression) {
|
||||
template = _.cloneDeep(template);
|
||||
|
||||
if (!_.isEmpty(nodes)) {
|
||||
traverse(template, function (node) {
|
||||
if (t.isIdentifier(node) && _.has(nodes, node.name)) {
|
||||
return nodes[node.name];
|
||||
traverse(template, {
|
||||
enter: function (node) {
|
||||
if (t.isIdentifier(node) && _.has(nodes, node.name)) {
|
||||
return nodes[node.name];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user