Stop mutating nodes (#5963)

* Stop mutating nodes

* Update tests

* linting
This commit is contained in:
Justin Ridgewell 2017-07-18 13:24:07 -04:00 committed by GitHub
parent aa684d1b0c
commit 28ae47a174
34 changed files with 83 additions and 275 deletions

View File

@ -236,7 +236,6 @@ export default class File extends Store {
if (t.isFunctionExpression(ref) && !ref.id) { if (t.isFunctionExpression(ref) && !ref.id) {
ref.body._compact = true; ref.body._compact = true;
ref._generated = true;
ref.id = uid; ref.id = uid;
ref.type = "FunctionDeclaration"; ref.type = "FunctionDeclaration";
this.path.unshiftContainer("body", ref); this.path.unshiftContainer("body", ref);

View File

@ -91,13 +91,6 @@ export function Decorator(node: Object) {
this.newline(); this.newline();
} }
function commaSeparatorNewline() {
this.token(",");
this.newline();
if (!this.endsWith("\n")) this.space();
}
export function CallExpression(node: Object) { export function CallExpression(node: Object) {
this.print(node.callee, node); this.print(node.callee, node);
@ -105,23 +98,7 @@ export function CallExpression(node: Object) {
this.token("?."); this.token("?.");
} }
this.token("("); this.token("(");
this.printList(node.arguments, node);
const isPrettyCall = node._prettyCall;
let separator;
if (isPrettyCall) {
separator = commaSeparatorNewline;
this.newline();
this.indent();
}
this.printList(node.arguments, node, { separator });
if (isPrettyCall) {
this.newline();
this.dedent();
}
this.token(")"); this.token(")");
} }

View File

@ -24,11 +24,6 @@ export default function(opts) {
const callExpr = buildElementCall(path.get("openingElement"), file); const callExpr = buildElementCall(path.get("openingElement"), file);
callExpr.arguments = callExpr.arguments.concat(path.node.children); callExpr.arguments = callExpr.arguments.concat(path.node.children);
if (callExpr.arguments.length >= 3) {
callExpr._prettyCall = true;
}
path.replaceWith(t.inherits(callExpr, path.node)); path.replaceWith(t.inherits(callExpr, path.node));
}, },
}; };

View File

@ -64,7 +64,6 @@ function wrap(state, method, id, scope) {
FUNCTION_ID: id, FUNCTION_ID: id,
FUNCTION_KEY: scope.generateUidIdentifier(id.name), FUNCTION_KEY: scope.generateUidIdentifier(id.name),
}).expression; }).expression;
template.callee._skipModulesRemap = true;
// shim in dummy params to retain function arity, if you try to read the // shim in dummy params to retain function arity, if you try to read the
// source then you'll get the original since it's proxied so it's all good // source then you'll get the original since it's proxied so it's all good

View File

@ -4,7 +4,7 @@ import * as messages from "babel-messages";
import * as t from "babel-types"; import * as t from "babel-types";
// ✌️ // ✌️
const HARDCORE_THIS_REF = Symbol(); const HARDCORE_THIS_REF = new WeakSet();
function isIllegalBareSuper(node, parent) { function isIllegalBareSuper(node, parent) {
if (!t.isSuper(node)) return false; if (!t.isSuper(node)) return false;
@ -57,7 +57,7 @@ const visitor = {
}, },
ThisExpression(path, state) { ThisExpression(path, state) {
if (!path.node[HARDCORE_THIS_REF]) { if (!HARDCORE_THIS_REF.has(path.node)) {
state.thises.push(path); state.thises.push(path);
} }
}, },
@ -309,7 +309,7 @@ export default class ReplaceSupers {
optimiseCall(callee, args) { optimiseCall(callee, args) {
const thisNode = t.thisExpression(); const thisNode = t.thisExpression();
thisNode[HARDCORE_THIS_REF] = true; HARDCORE_THIS_REF.add(thisNode);
return optimiseCall(callee, thisNode, args); return optimiseCall(callee, thisNode, args);
} }
} }

View File

@ -8,6 +8,8 @@ import values from "lodash/values";
import extend from "lodash/extend"; import extend from "lodash/extend";
import template from "babel-template"; import template from "babel-template";
const DONE = new WeakSet();
export default function() { export default function() {
return { return {
visitor: { visitor: {
@ -340,8 +342,8 @@ class BlockScoping {
run() { run() {
const block = this.block; const block = this.block;
if (block._letDone) return; if (DONE.has(block)) return;
block._letDone = true; DONE.add(block);
const needsClosure = this.getLetReferences(); const needsClosure = this.getLetReferences();

View File

@ -565,7 +565,6 @@ export default class ClassTransformer {
t.inheritsComments(construct, method); t.inheritsComments(construct, method);
construct._ignoreUserWhitespace = true;
construct.params = method.params; construct.params = method.params;
t.inherits(construct.body, method.body); t.inherits(construct.body, method.body);

View File

@ -20,17 +20,9 @@ var RandomComponent = function (_Component) {
babelHelpers.createClass(RandomComponent, [{ babelHelpers.createClass(RandomComponent, [{
key: "render", key: "render",
value: function render() { value: function render() {
return _react2.default.createElement( return _react2.default.createElement("div", {
"div",
{
className: "sui-RandomComponent" className: "sui-RandomComponent"
}, }, _react2.default.createElement("h2", null, "Hi there!"));
_react2.default.createElement(
"h2",
null,
"Hi there!"
)
);
} }
}]); }]);
return RandomComponent; return RandomComponent;

View File

@ -5,7 +5,6 @@ export default function({ types: t }) {
exit(path) { exit(path) {
const { node } = path; const { node } = path;
if (!node.id) return; if (!node.id) return;
node._ignoreUserWhitespace = true;
path.replaceWith( path.replaceWith(
t.callExpression( t.callExpression(

View File

@ -1,4 +1,6 @@
export default function({ types: t }) { export default function({ types: t }) {
const HOISTED = new WeakSet();
const immutabilityVisitor = { const immutabilityVisitor = {
enter(path, state) { enter(path, state) {
const stop = () => { const stop = () => {
@ -59,15 +61,14 @@ export default function({ types: t }) {
return { return {
visitor: { visitor: {
JSXElement(path) { JSXElement(path) {
if (path.node._hoisted) return; if (HOISTED.has(path.node)) return;
HOISTED.add(path.node);
const state = { isImmutable: true }; const state = { isImmutable: true };
path.traverse(immutabilityVisitor, state); path.traverse(immutabilityVisitor, state);
if (state.isImmutable) { if (state.isImmutable) {
path.hoist(); path.hoist();
} else {
path.node._hoisted = true;
} }
}, },
}, },

View File

@ -1,15 +1 @@
var x = React.createElement( var x = React.createElement("div", null, "foo", "bar", "baz", React.createElement("div", null, "buz bang"), "qux", null, "quack");
"div",
null,
"foo",
"bar",
"baz",
React.createElement(
"div",
null,
"buz bang"
),
"qux",
null,
"quack"
);

View File

@ -1,7 +1 @@
React.createElement( React.createElement(Text, null, "To get started, edit index.ios.js!!!", "\n", "Press Cmd+R to reload");
Text,
null,
"To get started, edit index.ios.js!!!",
"\n",
"Press Cmd+R to reload"
);

View File

@ -1,15 +1,6 @@
/** @jsx dom */ /** @jsx dom */
dom(Foo, null); dom(Foo, null);
var profile = dom( var profile = dom("div", null, dom("img", {
"div",
null,
dom("img", {
src: "avatar.png", src: "avatar.png",
className: "profile" className: "profile"
}), }), dom("h3", null, [user.firstName, user.lastName].join(" ")));
dom(
"h3",
null,
[user.firstName, user.lastName].join(" ")
)
);

View File

@ -1,15 +1,6 @@
/** @jsx dom */ /** @jsx dom */
dom(Foo, null); dom(Foo, null);
var profile = dom( var profile = dom("div", null, dom("img", {
"div",
null,
dom("img", {
src: "avatar.png", src: "avatar.png",
className: "profile" className: "profile"
}), }), dom("h3", null, [user.firstName, user.lastName].join(" ")));
dom(
"h3",
null,
[user.firstName, user.lastName].join(" ")
)
);

View File

@ -1,14 +1,5 @@
dom(Foo, null); dom(Foo, null);
var profile = dom( var profile = dom("div", null, dom("img", {
"div",
null,
dom("img", {
src: "avatar.png", src: "avatar.png",
className: "profile" className: "profile"
}), }), dom("h3", null, [user.firstName, user.lastName].join(" ")));
dom(
"h3",
null,
[user.firstName, user.lastName].join(" ")
)
);

View File

@ -1,5 +1 @@
var div = React.createElement( var div = React.createElement("div", null, "test");
"div",
null,
"test"
);

View File

@ -1,20 +1,4 @@
var x = React.createElement( var x = React.createElement("div", null, React.createElement(Component, null));
"div", var x = React.createElement("div", null, props.children);
null, var x = React.createElement(Composite, null, props.children);
React.createElement(Component, null) var x = React.createElement(Composite, null, React.createElement(Composite2, null));
);
var x = React.createElement(
"div",
null,
props.children
);
var x = React.createElement(
Composite,
null,
props.children
);
var x = React.createElement(
Composite,
null,
React.createElement(Composite2, null)
);

View File

@ -1,5 +1 @@
var x = React.createElement( var x = React.createElement("div", null, "text");
"div",
null,
"text"
);

View File

@ -1,46 +1,9 @@
React.createElement( React.createElement("div", null, "wow");
"div", React.createElement("div", null, "w\xF4w");
null, React.createElement("div", null, "w & w");
"wow" React.createElement("div", null, "w & w");
); React.createElement("div", null, "w \xA0 w");
React.createElement( React.createElement("div", null, "this should not parse as unicode: \\u00a0");
"div", React.createElement("div", null, "this should parse as nbsp: \xA0 ");
null, React.createElement("div", null, "this should parse as unicode: ", '\u00a0 ');
"w\xF4w" React.createElement("div", null, "w < w");
);
React.createElement(
"div",
null,
"w & w"
);
React.createElement(
"div",
null,
"w & w"
);
React.createElement(
"div",
null,
"w \xA0 w"
);
React.createElement(
"div",
null,
"this should not parse as unicode: \\u00a0"
);
React.createElement(
"div",
null,
"this should parse as nbsp: \xA0 "
);
React.createElement(
"div",
null,
"this should parse as unicode: ",
'\u00a0 '
);
React.createElement(
"div",
null,
"w < w"
);

View File

@ -1,18 +1,9 @@
var HelloMessage = React.createClass({ var HelloMessage = React.createClass({
displayName: "HelloMessage", displayName: "HelloMessage",
render: function () { render: function () {
return React.createElement( return React.createElement("div", null, "Hello ", this.props.name);
"div",
null,
"Hello ",
this.props.name
);
} }
}); });
React.render(React.createElement(HelloMessage, { React.render(React.createElement(HelloMessage, {
name: React.createElement( name: React.createElement("span", null, "Sebastian")
"span",
null,
"Sebastian"
)
}), mountNode); }), mountNode);

View File

@ -1,5 +1 @@
React.createElement( React.createElement("hasOwnProperty", null, "testing");
"hasOwnProperty",
null,
"testing"
);

View File

@ -1,17 +1 @@
var x = React.createElement( var x = React.createElement("div", null, React.createElement("div", null, React.createElement("br", null)), React.createElement(Component, null, foo, React.createElement("br", null), bar), React.createElement("br", null));
"div",
null,
React.createElement(
"div",
null,
React.createElement("br", null)
),
React.createElement(
Component,
null,
foo,
React.createElement("br", null),
bar
),
React.createElement("br", null)
);

View File

@ -1,7 +1,3 @@
React.createElement( React.createElement("button", {
"button",
{
"data-value": "a value\n with\nnewlines\n and spaces" "data-value": "a value\n with\nnewlines\n and spaces"
}, }, "Button");
"Button"
);

View File

@ -1,7 +1,3 @@
React.createElement( React.createElement("button", {
"button",
{
"data-value": "a value" "data-value": "a value"
}, }, "Button");
"Button"
);

View File

@ -2,10 +2,8 @@ import cloneDeep from "lodash/cloneDeep";
import has from "lodash/has"; import has from "lodash/has";
import traverse from "babel-traverse"; import traverse from "babel-traverse";
import * as babylon from "babylon"; import * as babylon from "babylon";
import * as t from "babel-types";
const FROM_TEMPLATE = "_fromTemplate"; //Symbol(); // todo: probably wont get copied over const FROM_TEMPLATE = new Set();
const TEMPLATE_SKIP = Symbol();
export default function(code: string, opts?: Object): Function { export default function(code: string, opts?: Object): Function {
// since we lazy parse the template, we get the current stack so we have the // since we lazy parse the template, we get the current stack so we have the
@ -40,10 +38,6 @@ export default function(code: string, opts?: Object): Function {
ast = traverse.removeProperties(ast, { ast = traverse.removeProperties(ast, {
preserveComments: opts.preserveComments, preserveComments: opts.preserveComments,
}); });
traverse.cheap(ast, function(node) {
node[FROM_TEMPLATE] = true;
});
} catch (err) { } catch (err) {
err.stack = `${err.stack}from\n${stack}`; err.stack = `${err.stack}from\n${stack}`;
throw err; throw err;
@ -66,7 +60,13 @@ function useTemplate(ast, nodes?: Array<Object>) {
const { program } = ast; const { program } = ast;
if (nodes.length) { if (nodes.length) {
traverse.cheap(ast, function(node) {
FROM_TEMPLATE.add(node);
});
traverse(ast, templateVisitor, null, nodes); traverse(ast, templateVisitor, null, nodes);
FROM_TEMPLATE.clear();
} }
if (program.body.length > 1) { if (program.body.length > 1) {
@ -80,32 +80,27 @@ const templateVisitor = {
// 360 // 360
noScope: true, noScope: true,
enter(path, args) { Identifier(path, args) {
let { node } = path; const { node, parentPath } = path;
if (node[TEMPLATE_SKIP]) return path.skip(); if (!FROM_TEMPLATE.has(node)) return path.skip();
if (t.isExpressionStatement(node)) {
node = node.expression;
}
let replacement; let replacement;
if (t.isIdentifier(node) && node[FROM_TEMPLATE]) {
if (has(args[0], node.name)) { if (has(args[0], node.name)) {
replacement = args[0][node.name]; replacement = args[0][node.name];
} else if (node.name[0] === "$") { } else if (node.name[0] === "$") {
const i = +node.name.slice(1); const i = +node.name.slice(1);
if (args[i]) replacement = args[i]; if (args[i]) replacement = args[i];
} }
if (parentPath.isExpressionStatement()) {
path = parentPath;
} }
if (replacement === null) { if (replacement === null) {
path.remove(); path.remove();
} } else if (replacement) {
if (replacement) {
replacement[TEMPLATE_SKIP] = true;
path.replaceInline(replacement); path.replaceInline(replacement);
path.skip();
} }
}, },

View File

@ -199,10 +199,6 @@ export default class PathHoister {
} }
run() { run() {
const node = this.path.node;
if (node._hoisted) return;
node._hoisted = true;
this.path.traverse(referenceVisitor, this); this.path.traverse(referenceVisitor, this);
this.getCompatibleScopes(); this.getCompatibleScopes();

View File

@ -803,7 +803,6 @@ export default class Scope {
if (!declarPath) { if (!declarPath) {
const declar = t.variableDeclaration(kind, []); const declar = t.variableDeclaration(kind, []);
declar._generated = true;
declar._blockHoist = blockHoist; declar._blockHoist = blockHoist;
[declarPath] = path.unshiftContainer("body", [declar]); [declarPath] = path.unshiftContainer("body", [declar]);

View File

@ -304,7 +304,7 @@ export function clone(node: Object): Object {
export function cloneWithoutLoc(node: Object): Object { export function cloneWithoutLoc(node: Object): Object {
const newNode = clone(node); const newNode = clone(node);
delete newNode.loc; newNode.loc = null;
return newNode; return newNode;
} }
@ -405,7 +405,7 @@ export function buildMatchMemberExpression(
export function removeComments(node: Object): Object { export function removeComments(node: Object): Object {
for (const key of t.COMMENT_KEYS) { for (const key of t.COMMENT_KEYS) {
delete node[key]; node[key] = null;
} }
return node; return node;
} }
@ -455,7 +455,7 @@ export function inherits(child: Object, parent: Object): Object {
// force inherit "private" properties // force inherit "private" properties
for (const key in parent) { for (const key in parent) {
if (key[0] === "_") child[key] = parent[key]; if (key[0] === "_" && key !== "__clone") child[key] = parent[key];
} }
// force inherit select properties // force inherit select properties