simplify member expression checking, flesh out react component optimiser #653
This commit is contained in:
21
lib/6to5/transformation/helpers/react.js
vendored
21
lib/6to5/transformation/helpers/react.js
vendored
@@ -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");
|
||||
|
||||
@@ -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) {
|
||||
|
||||
};
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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 () {
|
||||
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user