diff --git a/.babelrc b/.babelrc index 41671a95c3..f1732adf13 100644 --- a/.babelrc +++ b/.babelrc @@ -3,6 +3,7 @@ "loose": ["all"], "blacklist": ["es6.tailCall"], "optional": ["optimisation.flow.forOf", "bluebirdCoroutines"], + //"plugins": ["./scripts/build-plugins/inline-node-type-checks", "./scripts/build-plugins/inline-node-builders"], "env": { "test": { "auxiliaryCommentBefore": "istanbul ignore next" diff --git a/scripts/build-plugins/inline-node-builders.js b/scripts/build-plugins/inline-node-builders.js new file mode 100644 index 0000000000..d3ab9d689e --- /dev/null +++ b/scripts/build-plugins/inline-node-builders.js @@ -0,0 +1,52 @@ +module.exports = function (babel) { + var t = babel.types; + + return new babel.Plugin("inline-node-builders", { + visitor: { + CallExpression: function (node, parent, scope) { + var callee = this.get("callee"); + if (!callee.isMemberExpression()) return; + + var obj = callee.get("object"); + if (!obj.referencesImport("babel-types", "*")) return; + + var prop = callee.get("property"); + if (!prop.isIdentifier()) return; + + var type = prop.node.name; + var builder = t.BUILDER_KEYS[type] || t.BUILDER_KEYS[type[0].toUpperCase() + type.slice(1)]; + if (!builder) return; + + var props = []; + + var i = 0; + + for (var key in builder) { + var def = builder[key]; + var arg = node.arguments[i]; + + if (arg) { + if (t.isLiteral(arg)) { + props.push(t.property("init", t.identifier(key), arg)); + } else { + var uid = scope.generateDeclaredUidIdentifier("temp"); + props.push(t.property("init", t.identifier(key), t.sequenceExpression([ + t.assignmentExpression("=", uid, arg), + t.conditionalExpression( + t.logicalExpression("===", uid, t.identifier("undefined")), + t.valueToNode(def), + uid + ) + ]))); + } + } else { + props.push(t.property("init", t.identifier(key), t.valueToNode(def))); + } + } + + + return t.objectExpression(props); + } + } + }); +}; diff --git a/scripts/build-plugins/inline-node-type-checks.js b/scripts/build-plugins/inline-node-type-checks.js new file mode 100644 index 0000000000..e89923eb73 --- /dev/null +++ b/scripts/build-plugins/inline-node-type-checks.js @@ -0,0 +1,107 @@ +module.exports = function (babel) { + var t = babel.types; + + function buildOr(target, aliases) { + var conditions = []; + + target = t.memberExpression(target, t.identifier("type")); + + for (var i = 0; i < aliases.length; i++) { + var alias = aliases[i]; + conditions.push(t.binaryExpression("===", target, t.literal(alias))); + } + + if (conditions.length === 1) { + return conditions[0]; + } + + var root = t.logicalExpression("||", conditions.shift(), conditions.shift()); + + for (var i = 0; i < conditions.length; i++) { + root = t.logicalExpression("||", root, conditions[i]); + } + + return root; + } + + function maybeBuildArgsComparison(or, target, obj) { + if (!obj) return or; + + var conditions = []; + + for (var i = 0; i < obj.properties.length; i++) { + var prop = obj.properties[i]; + conditions.push(t.binaryExpression("===", + t.memberExpression(target, prop.key, t.isLiteral(prop.key)), + prop.value + )); + } + + var root; + + if (!conditions.length) { + return or; + } else if (conditions.length === 1) { + root = conditions[0]; + } else { + root = t.logicalExpression("&&", conditions.shift(), conditions.shift()); + for (var i = 0; i < conditions.length; i++) { + root = t.logicalExpression("&&", root, conditions[i]); + } + } + + return t.logicalExpression("&&", or, root); + } + + function shouldDeopt(args) { + if (args.length > 1) { + return true; + } + + if (args.length) { + var obj = args[0]; + if (!t.isObjectExpression(obj)) return true; + + for (var i = 0; i < obj.properties.length; i++) { + var prop = obj.properties[i]; + if (prop.computed) return true; + } + } + + return false; + } + + function buildCheck(target, args, aliases) { + if (shouldDeopt(args)) return; + + return t.logicalExpression( + "&&", + target, + maybeBuildArgsComparison(buildOr(target, aliases), target, args[0]) + ); + } + + return new babel.Plugin("inline-node-type-checks", { + visitor: { + CallExpression: function (node) { + var callee = this.get("callee"); + if (!callee.isMemberExpression()) return; + + var prop = callee.get("property"); + if (!prop.isIdentifier() || callee.is("computed")) return; + if (prop.node.name.indexOf("is") !== 0) return; + + var type = prop.node.name.slice(2); + var aliases = t.FLIPPED_ALIAS_KEYS[type] || [type]; + + var obj = callee.get("object"); + + if (obj.referencesImport("babel-types", "*")) { + return buildCheck(node.arguments.shift(), node.arguments, aliases, this.scope); + } else { + return buildCheck(t.memberExpression(obj.node, t.identifier("node")), node.arguments, aliases, this.scope); + } + } + } + }); +};