add optimisation.react.constantElements transformer - facebook/react#3228
This commit is contained in:
parent
3952eefd01
commit
ca5daca5dd
@ -80,7 +80,8 @@ export default class File {
|
|||||||
"object-destructuring-empty",
|
"object-destructuring-empty",
|
||||||
"temporal-undefined",
|
"temporal-undefined",
|
||||||
"temporal-assert-defined",
|
"temporal-assert-defined",
|
||||||
"self-global"
|
"self-global",
|
||||||
|
"default-props"
|
||||||
];
|
];
|
||||||
|
|
||||||
static options = require("./options");
|
static options = require("./options");
|
||||||
|
|||||||
@ -147,20 +147,7 @@ export default function (exports, opts) {
|
|||||||
exit(node) {
|
exit(node) {
|
||||||
var callExpr = node.openingElement;
|
var callExpr = node.openingElement;
|
||||||
|
|
||||||
for (var i = 0; i < node.children.length; i++) {
|
callExpr.arguments = callExpr.arguments.concat(react.buildChildren(node));
|
||||||
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);
|
|
||||||
|
|
||||||
if (callExpr.arguments.length >= 3) {
|
if (callExpr.arguments.length >= 3) {
|
||||||
callExpr._prettyCall = true;
|
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
|
// display names
|
||||||
|
|
||||||
var addDisplayName = function (id, call) {
|
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";
|
import * as t from "../../types";
|
||||||
|
|
||||||
var isCreateClassCallExpression = t.buildMatchMemberExpression("React.createClass");
|
var isCreateClassCallExpression = t.buildMatchMemberExpression("React.createClass");
|
||||||
@ -24,3 +25,86 @@ export var isReactComponent = t.buildMatchMemberExpression("React.Component");
|
|||||||
export function isCompatTag(tagName) {
|
export function isCompatTag(tagName) {
|
||||||
return tagName && /^[a-z]|\-/.test(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"),
|
"spec.blockScopedFunctions": require("./spec/block-scoped-functions"),
|
||||||
|
|
||||||
"optimisation.react.constantElements": require("./optimisation/react.constant-elements"),
|
"optimisation.react.constantElements": require("./optimisation/react.constant-elements"),
|
||||||
|
"optimisation.react.inlineElements": require("./optimisation/react.inline-elements"),
|
||||||
reactCompat: require("./other/react-compat"),
|
reactCompat: require("./other/react-compat"),
|
||||||
react: require("./other/react"),
|
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;
|
||||||
|
}
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
function render() {
|
||||||
|
return <foo />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
var text = getText();
|
||||||
|
return function () {
|
||||||
|
return <foo>{text}</foo>;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
var _ref = {
|
||||||
|
type: "foo",
|
||||||
|
ref: null,
|
||||||
|
props: {},
|
||||||
|
key: null
|
||||||
|
};
|
||||||
|
function render() {
|
||||||
|
return _ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
var text = getText();
|
||||||
|
var _ref = {
|
||||||
|
type: "foo",
|
||||||
|
ref: null,
|
||||||
|
children: [text],
|
||||||
|
props: {},
|
||||||
|
key: null
|
||||||
|
};
|
||||||
|
return function () {
|
||||||
|
return _ref;
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"optional": ["optimisation.react.constantElements", "optimisation.react.inlineElements"]
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<Baz foo="bar"></Baz>;
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: Baz,
|
||||||
|
ref: null,
|
||||||
|
children: [],
|
||||||
|
props: babelHelpers.defaultProps(Baz.defaultProps, {
|
||||||
|
foo: "bar"
|
||||||
|
}),
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<Baz></Baz>;
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: Baz,
|
||||||
|
ref: null,
|
||||||
|
children: [],
|
||||||
|
props: babelHelpers.defaultProps(Baz.defaultProps, {}),
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<foo bar="foo"></foo>;
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: "foo",
|
||||||
|
ref: null,
|
||||||
|
children: [],
|
||||||
|
props: {
|
||||||
|
bar: "foo"
|
||||||
|
},
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<foo></foo>;
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: "foo",
|
||||||
|
ref: null,
|
||||||
|
children: [],
|
||||||
|
props: {},
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<Foo key="foo" />
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: Foo,
|
||||||
|
ref: null,
|
||||||
|
props: babelHelpers.defaultProps(Foo.defaultProps, {}),
|
||||||
|
key: "foo"
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<Foo className="foo">{bar}<Baz key="baz" /></Foo>
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: Foo,
|
||||||
|
ref: null,
|
||||||
|
children: [bar, {
|
||||||
|
type: Baz,
|
||||||
|
ref: null,
|
||||||
|
props: babelHelpers.defaultProps(Baz.defaultProps, {}),
|
||||||
|
key: "baz"
|
||||||
|
}],
|
||||||
|
props: babelHelpers.defaultProps(Foo.defaultProps, {
|
||||||
|
className: "foo"
|
||||||
|
}),
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<div className="foo">{bar}</div>;
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: "div",
|
||||||
|
ref: null,
|
||||||
|
children: [bar],
|
||||||
|
props: {
|
||||||
|
className: "foo"
|
||||||
|
},
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<div className="foo">{bar}<Baz key="baz" /></div>
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: "div",
|
||||||
|
ref: null,
|
||||||
|
children: [bar, {
|
||||||
|
type: Baz,
|
||||||
|
ref: null,
|
||||||
|
props: babelHelpers.defaultProps(Baz.defaultProps, {}),
|
||||||
|
key: "baz"
|
||||||
|
}],
|
||||||
|
props: {
|
||||||
|
className: "foo"
|
||||||
|
},
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"externalHelpers": true,
|
||||||
|
"noCheckAst": true,
|
||||||
|
"optional": ["optimisation.react.inlineElements"]
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<Foo ref="bar" />
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
React.createElement(Foo, { ref: "bar" });
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<Baz foo="bar" />;
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: Baz,
|
||||||
|
ref: null,
|
||||||
|
props: babelHelpers.defaultProps(Baz.defaultProps, {
|
||||||
|
foo: "bar"
|
||||||
|
}),
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<Baz />;
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: Baz,
|
||||||
|
ref: null,
|
||||||
|
props: babelHelpers.defaultProps(Baz.defaultProps, {}),
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<foo bar="foo" />;
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: "foo",
|
||||||
|
ref: null,
|
||||||
|
props: {
|
||||||
|
bar: "foo"
|
||||||
|
},
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<foo />;
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
({
|
||||||
|
type: "foo",
|
||||||
|
ref: null,
|
||||||
|
props: {},
|
||||||
|
key: null
|
||||||
|
});
|
||||||
@ -0,0 +1 @@
|
|||||||
|
<Foo {...bar} />
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
React.createElement(Foo, bar);
|
||||||
Loading…
x
Reference in New Issue
Block a user