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) {
ref.body._compact = true;
ref._generated = true;
ref.id = uid;
ref.type = "FunctionDeclaration";
this.path.unshiftContainer("body", ref);

View File

@ -91,13 +91,6 @@ export function Decorator(node: Object) {
this.newline();
}
function commaSeparatorNewline() {
this.token(",");
this.newline();
if (!this.endsWith("\n")) this.space();
}
export function CallExpression(node: Object) {
this.print(node.callee, node);
@ -105,23 +98,7 @@ export function CallExpression(node: Object) {
this.token("?.");
}
this.token("(");
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.printList(node.arguments, node);
this.token(")");
}

View File

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

View File

@ -64,7 +64,6 @@ function wrap(state, method, id, scope) {
FUNCTION_ID: id,
FUNCTION_KEY: scope.generateUidIdentifier(id.name),
}).expression;
template.callee._skipModulesRemap = true;
// 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,15 +1,6 @@
/** @jsx dom */
dom(Foo, null);
var profile = dom(
"div",
null,
dom("img", {
var profile = dom("div", null, dom("img", {
src: "avatar.png",
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 */
dom(Foo, null);
var profile = dom(
"div",
null,
dom("img", {
var profile = dom("div", null, dom("img", {
src: "avatar.png",
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);
var profile = dom(
"div",
null,
dom("img", {
var profile = dom("div", null, dom("img", {
src: "avatar.png",
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(
"div",
null,
"test"
);
var div = React.createElement("div", null, "test");

View File

@ -1,20 +1,4 @@
var x = React.createElement(
"div",
null,
React.createElement(Component, 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)
);
var x = React.createElement("div", null, React.createElement(Component, 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(
"div",
null,
"text"
);
var x = React.createElement("div", null, "text");

View File

@ -1,46 +1,9 @@
React.createElement(
"div",
null,
"wow"
);
React.createElement(
"div",
null,
"w\xF4w"
);
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"
);
React.createElement("div", null, "wow");
React.createElement("div", null, "w\xF4w");
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({
displayName: "HelloMessage",
render: function () {
return React.createElement(
"div",
null,
"Hello ",
this.props.name
);
return React.createElement("div", null, "Hello ", this.props.name);
}
});
React.render(React.createElement(HelloMessage, {
name: React.createElement(
"span",
null,
"Sebastian"
)
name: React.createElement("span", null, "Sebastian")
}), mountNode);

View File

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

View File

@ -1,17 +1 @@
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)
);
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));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -304,7 +304,7 @@ export function clone(node: Object): Object {
export function cloneWithoutLoc(node: Object): Object {
const newNode = clone(node);
delete newNode.loc;
newNode.loc = null;
return newNode;
}
@ -405,7 +405,7 @@ export function buildMatchMemberExpression(
export function removeComments(node: Object): Object {
for (const key of t.COMMENT_KEYS) {
delete node[key];
node[key] = null;
}
return node;
}
@ -455,7 +455,7 @@ export function inherits(child: Object, parent: Object): Object {
// force inherit "private" properties
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