Proof of concept of how traversal would look like with state parameter

This commit is contained in:
Dan Abramov 2015-01-17 05:03:23 +03:00
parent f9480b5280
commit ff9511d435
4 changed files with 105 additions and 95 deletions

View File

@ -2,6 +2,24 @@ var traverse = require("../../traverse");
var util = require("../../util");
var t = require("../../types");
var traverser = {
enter: function (node, parent, scope, context, state) {
// check if this node is an identifier that matches the same as our function id
if (!t.isIdentifier(node, { name: state.id })) return;
// check if this node is the one referenced
if (!t.isReferenced(node, parent)) return;
// check that we don't have a local variable declared as that removes the need
// for the wrapper
var localDeclar = scope.get(state.id, true);
if (localDeclar !== state.outerDeclar) return;
state.selfReference = true;
context.stop();
}
};
module.exports = function (node, file, scope) {
var key = t.toComputedKey(node, node.key);
if (!t.isLiteral(key)) return node; // we can't set a function id with this
@ -15,23 +33,7 @@ module.exports = function (node, file, scope) {
outerDeclar: scope.get(id, true),
};
traverse(node, {
enter: function (node, parent, scope, context, state) {
// check if this node is an identifier that matches the same as our function id
if (!t.isIdentifier(node, { name: state.id })) return;
// check if this node is the one referenced
if (!t.isReferenced(node, parent)) return;
// check that we don't have a local variable declared as that removes the need
// for the wrapper
var localDeclar = scope.get(state.id, true);
if (localDeclar !== state.outerDeclar) return;
state.selfReference = true;
context.stop();
}
}, scope, state);
traverse(node, traverser, scope, state);
if (state.selfReference) {
node.value = util.template("property-method-assignment-wrapper", {

View File

@ -16,35 +16,51 @@ function DefaultFormatter(file) {
//this.checkCollisions();
}
var exportsTraverser = {
enter: function (node, parent, scope, context, localExports) {
var declar = node && node.declaration;
if (t.isExportDeclaration(node) && declar && t.isStatement(declar)) {
_.extend(localExports, t.getIds(declar, true));
}
}
};
DefaultFormatter.prototype.getLocalExports = function () {
var localExports = {};
traverse(this.file.ast, {
enter: function (node, parent, scope, context, localExports) {
var declar = node && node.declaration;
if (t.isExportDeclaration(node) && declar && t.isStatement(declar)) {
_.extend(localExports, t.getIds(declar, true));
}
}
}, null, localExports);
traverse(this.file.ast, exportsTraverser, null, localExports);
return localExports;
};
var importsTraverser = {
enter: function (node, parent, scope, context, localImports) {
if (t.isImportDeclaration(node)) {
_.extend(localImports, t.getIds(node, true));
}
}
};
DefaultFormatter.prototype.getLocalImports = function () {
var localImports = {};
traverse(this.file.ast, {
enter: function (node, parent, scope, context, localImports) {
if (t.isImportDeclaration(node)) {
_.extend(localImports, t.getIds(node, true));
}
}
}, null, localImports);
traverse(this.file.ast, importsTraverser, null, localImports);
return localImports;
};
var collissionsTraverser = {
enter: function (node, parent, scope, context, check) {
if (t.isAssignmentExpression(node)) {
var left = node.left;
if (t.isMemberExpression(left)) {
while (left.object) left = left.object;
}
check(left);
} else if (t.isDeclaration(node)) {
_.each(t.getIds(node, true), check);
}
}
};
DefaultFormatter.prototype.checkCollisions = function () {
// todo: all check export collissions
@ -61,21 +77,7 @@ DefaultFormatter.prototype.checkCollisions = function () {
}
};
traverse(file.ast, {
enter: function (node, parent, scope, context, check) {
if (t.isAssignmentExpression(node)) {
var left = node.left;
if (t.isMemberExpression(left)) {
while (left.object) left = left.object;
}
check(left);
} else if (t.isDeclaration(node)) {
_.each(t.getIds(node, true), check);
}
}
}, null, check);
traverse(file.ast, collissionsTraverser, null, check);
};
DefaultFormatter.prototype.remapExportAssignment = function (node) {

View File

@ -1,6 +1,46 @@
var traverse = require("../../traverse");
var t = require("../../types");
var functionChildrenTraverser = {
enter: function (node, parent, scope, context, state) {
if (t.isFunction(node) && !node._aliasFunction) {
return context.skip();
}
if (node._ignoreAliasFunctions) return context.skip();
var getId;
if (t.isIdentifier(node) && node.name === "arguments") {
getId = state.getArgumentsId;
} else if (t.isThisExpression(node)) {
getId = state.getThisId;
} else {
return;
}
if (t.isReferenced(node, parent)) return getId();
}
};
var functionTraverser = {
enter: function (node, parent, scope, context, state) {
if (!node._aliasFunction) {
if (t.isFunction(node)) {
// stop traversal of this node as it'll be hit again by this transformer
return context.skip();
} else {
return;
}
}
// traverse all child nodes of this function and find `arguments` and `this`
traverse(node, functionChildrenTraverser, null, state);
return context.skip();
}
};
var go = function (getBody, node, file, scope) {
var argumentsId;
var thisId;
@ -16,43 +56,7 @@ 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, {
enter: function (node, parent, scope, context, state) {
if (!node._aliasFunction) {
if (t.isFunction(node)) {
// stop traversal of this node as it'll be hit again by this transformer
return context.skip();
} else {
return;
}
}
// traverse all child nodes of this function and find `arguments` and `this`
traverse(node, {
enter: function (node, parent, scope, context, state) {
if (t.isFunction(node) && !node._aliasFunction) {
return context.skip();
}
if (node._ignoreAliasFunctions) return context.skip();
var getId;
if (t.isIdentifier(node) && node.name === "arguments") {
getId = state.getArgumentsId;
} else if (t.isThisExpression(node)) {
getId = state.getThisId;
} else {
return;
}
if (t.isReferenced(node, parent)) return getId();
}
}, null, state);
return context.skip();
}
}, null, state);
traverse(node, functionTraverser, null, state);
var body;

View File

@ -129,6 +129,14 @@ exports.buildDefineProperties = function (mutatorMap) {
return objExpr;
};
var templateTraverser = {
enter: function (node, parent, scope, context, nodes) {
if (t.isIdentifier(node) && _.has(nodes, node.name)) {
return nodes[node.name];
}
}
};
exports.template = function (name, nodes, keepExpression) {
var template = exports.templates[name];
if (!template) throw new ReferenceError("unknown template " + name);
@ -141,13 +149,7 @@ exports.template = function (name, nodes, keepExpression) {
template = _.cloneDeep(template);
if (!_.isEmpty(nodes)) {
traverse(template, {
enter: function (node, parent, scope, context, nodes) {
if (t.isIdentifier(node) && _.has(nodes, node.name)) {
return nodes[node.name];
}
}
}, null, nodes);
traverse(template, templateTraverser, null, nodes);
}
var node = template.body[0];