mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Rewrite vendor/constants.js to use require("ast-types").traverse.
Most notably, this new style of transformation gives us access to this.parent.node, which allows us to avoid replacing identifiers that are not actually free variables, such as member expression properties. Closes #496. Conflicts: package.json
This commit is contained in:
committed by
Paul O’Shannessy
parent
a426f1f216
commit
1d9a0ce7ff
Vendored
+42
-40
@@ -16,58 +16,60 @@
|
||||
'use strict';
|
||||
|
||||
var recast = require('recast');
|
||||
var types = recast.types;
|
||||
var namedTypes = types.namedTypes;
|
||||
var builders = types.builders;
|
||||
var hasOwn = Object.prototype.hasOwnProperty;
|
||||
|
||||
exports.propagate = function(constants, source) {
|
||||
var ast = recast.parse(source);
|
||||
ast = new ConstantVisitor(constants).visit(ast);
|
||||
return recast.print(ast);
|
||||
};
|
||||
function propagate(constants, source) {
|
||||
return recast.print(transform(recast.parse(source), constants));
|
||||
}
|
||||
|
||||
var ConstantVisitor = recast.Visitor.extend({
|
||||
init: function(constants) {
|
||||
this.constants = constants || {};
|
||||
},
|
||||
function transform(ast, constants) {
|
||||
constants = constants || {};
|
||||
|
||||
visitIdentifier: function(ident) {
|
||||
if (this.constants.hasOwnProperty(ident.name)) {
|
||||
return recast.builder.literal(this.constants[ident.name]);
|
||||
}
|
||||
},
|
||||
|
||||
visitCallExpression: function(call) {
|
||||
if (!this.constants.__DEV__) {
|
||||
if (call.callee.type === 'Identifier' && call.callee.name === 'invariant') {
|
||||
call.arguments.length = 1;
|
||||
return types.traverse(ast, function(node, traverse) {
|
||||
if (namedTypes.Identifier.check(node)) {
|
||||
if (namedTypes.MemberExpression.check(this.parent.node) &&
|
||||
this.name === 'property' &&
|
||||
!this.parent.node.computed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
this.genericVisit(call);
|
||||
},
|
||||
|
||||
visitIfStatement: function(stmt) {
|
||||
// Replaces all identifiers in this.constants with literal values.
|
||||
this.genericVisit(stmt);
|
||||
if (hasOwn.call(constants, node.name)) {
|
||||
this.replace(builders.literal(constants[node.name]));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stmt.test.type === recast.Syntax.Literal) {
|
||||
if (stmt.test.value) {
|
||||
stmt.alternate = null;
|
||||
} else if (stmt.alternate) {
|
||||
return stmt.alternate;
|
||||
} else if (namedTypes.CallExpression.check(node)) {
|
||||
if (!constants.__DEV__) {
|
||||
if (namedTypes.Identifier.check(node.callee) &&
|
||||
node.callee.name === 'invariant') {
|
||||
node.arguments.length = 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (namedTypes.IfStatement.check(node) &&
|
||||
namedTypes.Literal.check(node.test)) {
|
||||
if (node.test.value) {
|
||||
node.alternate = null;
|
||||
} else if (node.alternate) {
|
||||
this.replace(node.alternate);
|
||||
return false;
|
||||
} else {
|
||||
// In case this if statement is an alternate clause for another
|
||||
// if-statement, replacing that alternate with null will have the
|
||||
// effect of pruning the unnecessary clause. If this is just a
|
||||
// free-floating if statement, replacing it with null will have
|
||||
// the effect of removing it from the enclosing list of
|
||||
// statements.
|
||||
return null;
|
||||
this.replace(); // Remove the if-statement.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (!module.parent) {
|
||||
var constants = JSON.parse(process.argv[3]);
|
||||
recast.run(function(ast, callback) {
|
||||
callback(new ConstantVisitor(constants).visit(ast));
|
||||
callback(transform(ast, constants));
|
||||
});
|
||||
}
|
||||
|
||||
exports.propagate = propagate;
|
||||
exports.transform = transform;
|
||||
|
||||
Reference in New Issue
Block a user