add optimisation.react.constantElements transformer - facebook/react#3228
This commit is contained in:
@@ -80,7 +80,8 @@ export default class File {
|
||||
"object-destructuring-empty",
|
||||
"temporal-undefined",
|
||||
"temporal-assert-defined",
|
||||
"self-global"
|
||||
"self-global",
|
||||
"default-props"
|
||||
];
|
||||
|
||||
static options = require("./options");
|
||||
|
||||
@@ -147,20 +147,7 @@ export default function (exports, opts) {
|
||||
exit(node) {
|
||||
var callExpr = node.openingElement;
|
||||
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
var child = node.children[i];
|
||||
|
||||
if (t.isLiteral(child) && typeof child.value === "string") {
|
||||
cleanJSXElementLiteralChild(child, callExpr.arguments);
|
||||
continue;
|
||||
} else if (t.isJSXEmptyExpression(child)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
callExpr.arguments.push(child);
|
||||
}
|
||||
|
||||
callExpr.arguments = flatten(callExpr.arguments);
|
||||
callExpr.arguments = callExpr.arguments.concat(react.buildChildren(node));
|
||||
|
||||
if (callExpr.arguments.length >= 3) {
|
||||
callExpr._prettyCall = true;
|
||||
@@ -170,69 +157,6 @@ export default function (exports, opts) {
|
||||
}
|
||||
};
|
||||
|
||||
var isStringLiteral = function (node) {
|
||||
return t.isLiteral(node) && isString(node.value);
|
||||
};
|
||||
|
||||
var flatten = function (args) {
|
||||
var flattened = [];
|
||||
var last;
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
if (isStringLiteral(arg) && isStringLiteral(last)) {
|
||||
last.value += arg.value;
|
||||
} else {
|
||||
last = arg;
|
||||
flattened.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return flattened;
|
||||
};
|
||||
|
||||
var cleanJSXElementLiteralChild = function (child, args) {
|
||||
var lines = child.value.split(/\r\n|\n|\r/);
|
||||
|
||||
var lastNonEmptyLine = 0;
|
||||
var i;
|
||||
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
if (lines[i].match(/[^ \t]/)) {
|
||||
lastNonEmptyLine = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
|
||||
var isFirstLine = i === 0;
|
||||
var isLastLine = i === lines.length - 1;
|
||||
var isLastNonEmptyLine = i === lastNonEmptyLine;
|
||||
|
||||
// replace rendered whitespace tabs with spaces
|
||||
var trimmedLine = line.replace(/\t/g, " ");
|
||||
|
||||
// trim whitespace touching a newline
|
||||
if (!isFirstLine) {
|
||||
trimmedLine = trimmedLine.replace(/^[ ]+/, "");
|
||||
}
|
||||
|
||||
// trim whitespace touching an endline
|
||||
if (!isLastLine) {
|
||||
trimmedLine = trimmedLine.replace(/[ ]+$/, "");
|
||||
}
|
||||
|
||||
if (trimmedLine) {
|
||||
if (!isLastNonEmptyLine) {
|
||||
trimmedLine += " ";
|
||||
}
|
||||
|
||||
args.push(t.literal(trimmedLine));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// display names
|
||||
|
||||
var addDisplayName = function (id, call) {
|
||||
|
||||
84
src/babel/transformation/helpers/react.js
vendored
84
src/babel/transformation/helpers/react.js
vendored
@@ -1,3 +1,4 @@
|
||||
import isString from "lodash/lang/isString";
|
||||
import * as t from "../../types";
|
||||
|
||||
var isCreateClassCallExpression = t.buildMatchMemberExpression("React.createClass");
|
||||
@@ -24,3 +25,86 @@ export var isReactComponent = t.buildMatchMemberExpression("React.Component");
|
||||
export function isCompatTag(tagName) {
|
||||
return tagName && /^[a-z]|\-/.test(tagName);
|
||||
}
|
||||
|
||||
function flattenChildren(args) {
|
||||
var flattened = [];
|
||||
var last;
|
||||
|
||||
for (var i = 0; i < args.length; i++) {
|
||||
var arg = args[i];
|
||||
if (isStringLiteral(arg) && isStringLiteral(last)) {
|
||||
last.value += arg.value;
|
||||
} else {
|
||||
last = arg;
|
||||
flattened.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return flattened;
|
||||
}
|
||||
|
||||
function isStringLiteral(node) {
|
||||
return t.isLiteral(node) && isString(node.value);
|
||||
}
|
||||
|
||||
function cleanJSXElementLiteralChild(child, args) {
|
||||
var lines = child.value.split(/\r\n|\n|\r/);
|
||||
|
||||
var lastNonEmptyLine = 0;
|
||||
var i;
|
||||
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
if (lines[i].match(/[^ \t]/)) {
|
||||
lastNonEmptyLine = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
var line = lines[i];
|
||||
|
||||
var isFirstLine = i === 0;
|
||||
var isLastLine = i === lines.length - 1;
|
||||
var isLastNonEmptyLine = i === lastNonEmptyLine;
|
||||
|
||||
// replace rendered whitespace tabs with spaces
|
||||
var trimmedLine = line.replace(/\t/g, " ");
|
||||
|
||||
// trim whitespace touching a newline
|
||||
if (!isFirstLine) {
|
||||
trimmedLine = trimmedLine.replace(/^[ ]+/, "");
|
||||
}
|
||||
|
||||
// trim whitespace touching an endline
|
||||
if (!isLastLine) {
|
||||
trimmedLine = trimmedLine.replace(/[ ]+$/, "");
|
||||
}
|
||||
|
||||
if (trimmedLine) {
|
||||
if (!isLastNonEmptyLine) {
|
||||
trimmedLine += " ";
|
||||
}
|
||||
|
||||
args.push(t.literal(trimmedLine));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function buildChildren(node) {
|
||||
var elems = [];
|
||||
|
||||
for (var i = 0; i < node.children.length; i++) {
|
||||
var child = node.children[i];
|
||||
if (t.isJSXExpressionContainer(child)) child = child.expression;
|
||||
|
||||
if (t.isLiteral(child) && typeof child.value === "string") {
|
||||
cleanJSXElementLiteralChild(child, elems);
|
||||
continue;
|
||||
} else if (t.isJSXEmptyExpression(child)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
elems.push(child);
|
||||
}
|
||||
|
||||
return flattenChildren(elems);
|
||||
}
|
||||
|
||||
10
src/babel/transformation/templates/helper-default-props.js
Normal file
10
src/babel/transformation/templates/helper-default-props.js
Normal file
@@ -0,0 +1,10 @@
|
||||
(function (defaultProps, props) {
|
||||
if (defaultProps) {
|
||||
for (var propName in defaultProps) {
|
||||
if (typeof props[propName] === "undefined") {
|
||||
props[propName] = defaultProps[propName];
|
||||
}
|
||||
}
|
||||
}
|
||||
return props;
|
||||
})
|
||||
@@ -19,6 +19,7 @@ export default {
|
||||
"spec.blockScopedFunctions": require("./spec/block-scoped-functions"),
|
||||
|
||||
"optimisation.react.constantElements": require("./optimisation/react.constant-elements"),
|
||||
"optimisation.react.inlineElements": require("./optimisation/react.inline-elements"),
|
||||
reactCompat: require("./other/react-compat"),
|
||||
react: require("./other/react"),
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import * as react from "../../helpers/react";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var metadata = {
|
||||
optional: true
|
||||
};
|
||||
|
||||
function hasRefOrSpread(attrs) {
|
||||
for (var i = 0; i < attrs.length; i++) {
|
||||
var attr = attrs[i];
|
||||
if (t.isJSXSpreadAttribute(attr)) return true;
|
||||
if (isJSXAttributeOfName(attr, "ref")) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isJSXAttributeOfName(attr, name) {
|
||||
return t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name, { name: name });
|
||||
}
|
||||
|
||||
export function JSXElement(node, parent, scope, file) {
|
||||
// filter
|
||||
var open = node.openingElement;
|
||||
if (hasRefOrSpread(open.attributes)) return;
|
||||
|
||||
// init
|
||||
var isComponent = true;
|
||||
var props = t.objectExpression([]);
|
||||
var obj = t.objectExpression([]);
|
||||
var key = t.literal(null);
|
||||
var type = open.name;
|
||||
|
||||
if (t.isJSXIdentifier(type) && react.isCompatTag(type.name)) {
|
||||
type = t.literal(type.name);
|
||||
isComponent = false;
|
||||
}
|
||||
|
||||
function pushElemProp(key, value) {
|
||||
obj.properties.push(t.property("init", t.identifier(key), value));
|
||||
}
|
||||
|
||||
// metadata
|
||||
pushElemProp("type", type);
|
||||
pushElemProp("ref", t.literal(null));
|
||||
|
||||
if (!open.selfClosing) {
|
||||
pushElemProp("children", t.arrayExpression(react.buildChildren(node)));
|
||||
}
|
||||
|
||||
// props
|
||||
for (var i = 0; i < open.attributes.length; i++) {
|
||||
var attr = open.attributes[i];
|
||||
if (isJSXAttributeOfName(attr, "key")) {
|
||||
key = attr.value;
|
||||
} else {
|
||||
props.properties.push(t.property("init", attr.name, attr.value));
|
||||
}
|
||||
}
|
||||
|
||||
if (isComponent) {
|
||||
props = t.callExpression(file.addHelper("default-props"), [t.memberExpression(type, t.identifier("defaultProps")), props]);
|
||||
}
|
||||
|
||||
pushElemProp("props", props);
|
||||
|
||||
// key
|
||||
pushElemProp("key", key);
|
||||
|
||||
return obj;
|
||||
}
|
||||
Reference in New Issue
Block a user