simplify member expression checking, flesh out react component optimiser #653

This commit is contained in:
Sebastian McKenzie
2015-02-02 01:30:06 +11:00
parent dcf91db475
commit 27138abd29
7 changed files with 184 additions and 24 deletions

View File

@@ -1,16 +1,12 @@
var t = require("../../types");
exports.isCreateClassCallExpression = function (node) {
var isCreateClassCallExpression = t.buildMatchMemberExpression("React.createClass");
exports.isCreateClass = function (node) {
if (!node || !t.isCallExpression(node)) return false;
var callee = node.callee;
if (!t.isMemberExpression(callee)) return false;
// not React call member object
if (!t.isIdentifier(callee.object, { name: "React" })) return false;
// not createClass call member property
if (!t.isIdentifier(callee.property, { name: "createClass" })) return false;
// not React.createClass call member object
if (!isCreateClassCallExpression(node.callee)) return false;
// no call arguments
var args = node.arguments;
@@ -23,9 +19,4 @@ exports.isCreateClassCallExpression = function (node) {
return true;
};
exports.isReactComponentMemberExpression = function (node) {
if (!node || !t.isMemberExpression(node)) return false;
if (!t.isIdentifier(node.object, { name: "React" })) return false;
if (!t.isIdentifier(node.property, { name: "Component" })) return false;
return true;
};
exports.isReactComponent = t.buildMatchMemberExpression("React.Component");

View File

@@ -1,9 +1,53 @@
module.exports = BaseOptimiser;
function BaseOptimiser() {
var object = require("../../../../helpers/object");
/**
* Description
*
* @param {Node} node
*/
function BaseOptimiser(node) {
this.methods = object();
this.types = object();
this.node = node;
}
BaseOptimiser.prototype.optimise = function () {
/**
* Description
*/
BaseOptimiser.prototype.run = function () {
this.getMethods();
this.getTypes();
};
/**
* Add an `ObjectExpression` `node` that contains `propTypes`.
*
* Search it and match it against the types that we can optimise
* and register it for consumption later.
*
* @param {Node} node
*/
BaseOptimiser.prototype.addPropTypes = function (node) {
var props = node.properties;
for (var i = 0; i < props.length; i++) {
this.addPropType(props[i]);
}
};
/**
* Register a `Property` node as a prop type.
*
* We'll try and resolve it to a known type if we can and normalise
* it for consumption later.
*/
BaseOptimiser.prototype.addPropType = function (prop) {
};

View File

@@ -4,7 +4,47 @@ var BaseOptimiser = require("./base");
var util = require("../../../../util");
function CreateClassOptimiser() {
BaseOptimiser.apply(this, arguments);
}
util.inherits(CreateClassOptimiser, BaseOptimiser);
/**
* Get all function expressions.
*/
CreateClassOptimiser.prototype.getMethods = function () {
var props = this.node.properties;
for (var i = 0; i < props.length; i++) {
var prop = props[i];
// irrelevant
if (!t.isFunctionExpression(prop.value)) continue;
// deopt
if (prop.computed) continue;
this.methods[prop.key.name] = prop;
}
};
/**
* Find a `propTypes` property.
*/
CreateClassOptimiser.prototype.getTypes = function () {
var props = this.node.properties;
for (var i = 0; i < props.length; i++) {
var prop = props[i];
var key = t.toComputedKey(prop, prop.key);
if (t.isLiteral(key, { value: "propTypes" }) && t.isObjectExpression(prop.value)) {
this.addPropTypes(prop.value);
return;
}
}
// not found
};

View File

@@ -5,13 +5,13 @@ var react = require("../../../helpers/react");
exports.optional = true;
exports.CallExpression = function (node) {
if (react.isCreateClassCallExpression(node)) {
new CreateClassOptimiser(node.arguments[0]).optimise();
if (react.isCreateClass(node)) {
new CreateClassOptimiser(node.arguments[0]).run();
}
};
exports.CallExpression = function (node) {
if (react.isReactComponentMemberExpression(node.superClass)) {
new NativeClassOptimiser(node).optimise();
if (react.isReactComponent(node.superClass)) {
new NativeClassOptimiser(node).run();
}
};

View File

@@ -2,9 +2,41 @@ module.exports = NativeClassOptimiser;
var BaseOptimiser = require("./base");
var util = require("../../../../util");
var t = require("../../../../types");
function NativeClassOptimiser() {
BaseOptimiser.apply(this, arguments);
}
util.inherits(NativeClassOptimiser, BaseOptimiser);
/**
* Get all instance methods.
*/
NativeClassOptimiser.prototype.getMethods = function () {
var body = this.node.body;
for (var i = 0; i < body.length; i++) {
var node = body[i];
// PrivateDeclaration etc
if (!t.isMethodDefinition(node)) continue;
// deopt
if (node.computed) continue;
// irrelevant
if (node.static) continue;
this.methods[node.key.name] = node;
}
};
/**
* Description
*/
NativeClassOptimiser.prototype.getTypes = function () {
};

View File

@@ -199,7 +199,7 @@ var cleanJSXElementLiteralChild = function (child, args) {
// display names
var addDisplayName = function (id, call) {
if (!react.isCreateClassCallExpression(call)) return;
if (!react.isCreateClass(call)) return;
var props = call.arguments[0].properties;
var safe = true;

View File

@@ -399,6 +399,59 @@ t.ensureBlock = function (node, key) {
node[key] = t.toBlock(node[key], node);
};
/**
* Build a function that when called will return whether or not the
* input `node` `MemberExpression` matches the input `match`.
*
* For example, given the match `React.createClass` it would match the
* parsed nodes of `React.createClass` and `React["createClass"]`.
*
* @param {String} match Dot delimetered string
* @returns {Function}
*/
t.buildMatchMemberExpression = function (match) {
var parts = match.split(".");
return function (node) {
// not a member expression
if (!t.isMemberExpression(node)) return false;
var search = [];
var i = 0;
while (search.length) {
var node = search.unshift();
if (t.isIdentifier(node)) {
// this part doesn't match
if (parts[i] !== node.name) return false;
} else if (t.isLiteral(node)) {
// this part doesn't match
if (parts[i] !== node.value) return false;
} else if (t.isMemberExpression(node)) {
if (node.computed && !t.isLiteral(node.property)) {
// we can't deal with this
return false;
} else {
search.push(node.object);
search.push(node.property);
}
} else {
// we can't deal with this
return false;
}
// too many parts
if (++i > parts.length) {
return false;
}
}
return true;
};
};
/**
* Description
*