Add t.cloneNode and deprecate t.clone and t.cloneDeep (#7149)
This commit is contained in:
parent
dde9274986
commit
63ae923987
@ -69,7 +69,7 @@ function buildModule(whitelist) {
|
||||
t.exportNamedDeclaration(
|
||||
null,
|
||||
Object.keys(refs).map(name => {
|
||||
return t.exportSpecifier(t.clone(refs[name]), t.identifier(name));
|
||||
return t.exportSpecifier(t.cloneNode(refs[name]), t.identifier(name));
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
@ -50,7 +50,7 @@ export default class ImportBuilder {
|
||||
assert(statement.type === "ImportDeclaration");
|
||||
assert(statement.specifiers.length === 0);
|
||||
statement.specifiers = [t.importNamespaceSpecifier(name)];
|
||||
this._resultName = t.clone(name);
|
||||
this._resultName = t.cloneNode(name);
|
||||
return this;
|
||||
}
|
||||
default(name) {
|
||||
@ -59,7 +59,7 @@ export default class ImportBuilder {
|
||||
assert(statement.type === "ImportDeclaration");
|
||||
assert(statement.specifiers.length === 0);
|
||||
statement.specifiers = [t.importDefaultSpecifier(name)];
|
||||
this._resultName = t.clone(name);
|
||||
this._resultName = t.cloneNode(name);
|
||||
return this;
|
||||
}
|
||||
named(name, importName) {
|
||||
@ -70,7 +70,7 @@ export default class ImportBuilder {
|
||||
assert(statement.type === "ImportDeclaration");
|
||||
assert(statement.specifiers.length === 0);
|
||||
statement.specifiers = [t.importSpecifier(name, t.identifier(importName))];
|
||||
this._resultName = t.clone(name);
|
||||
this._resultName = t.cloneNode(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ export default class ImportBuilder {
|
||||
"var",
|
||||
[t.variableDeclarator(name, statement.expression)],
|
||||
);
|
||||
this._resultName = t.clone(name);
|
||||
this._resultName = t.cloneNode(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@ -128,7 +128,7 @@ export function buildNamespaceInitStatements(
|
||||
statements.push(
|
||||
template.statement`var NAME = SOURCE;`({
|
||||
NAME: localName,
|
||||
SOURCE: t.cloneDeep(srcNamespace),
|
||||
SOURCE: t.cloneNode(srcNamespace),
|
||||
}),
|
||||
);
|
||||
}
|
||||
@ -150,14 +150,14 @@ export function buildNamespaceInitStatements(
|
||||
: template.statement`EXPORTS.NAME = NAMESPACE;`)({
|
||||
EXPORTS: metadata.exportName,
|
||||
NAME: exportName,
|
||||
NAMESPACE: t.cloneDeep(srcNamespace),
|
||||
NAMESPACE: t.cloneNode(srcNamespace),
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (sourceMetadata.reexportAll) {
|
||||
const statement = buildNamespaceReexport(
|
||||
metadata,
|
||||
t.cloneDeep(srcNamespace),
|
||||
t.cloneNode(srcNamespace),
|
||||
loose,
|
||||
);
|
||||
statement.loc = sourceMetadata.reexportAll.loc;
|
||||
@ -191,7 +191,7 @@ const buildReexportsFromMeta = (meta, metadata, loose) => {
|
||||
templateForCurrentMode({
|
||||
EXPORTS: meta.exportName,
|
||||
EXPORT_NAME: exportName,
|
||||
NAMESPACE: t.cloneDeep(namespace),
|
||||
NAMESPACE: t.cloneNode(namespace),
|
||||
IMPORT_NAME: importName,
|
||||
}),
|
||||
);
|
||||
|
||||
@ -309,7 +309,7 @@ function checkDuplicatedNodes(ast) {
|
||||
if (isByRegenerator(node)) return;
|
||||
if (nodes.has(node)) {
|
||||
throw new Error(
|
||||
"Do not reuse nodes. Use `t.clone` or `t.cloneDeep` to copy them.\n" +
|
||||
"Do not reuse nodes. Use `t.cloneNode` to copy them.\n" +
|
||||
JSON.stringify(node, hidePrivateProperties, 2) +
|
||||
"\nParent:\n" +
|
||||
JSON.stringify(parents.get(node), hidePrivateProperties, 2),
|
||||
|
||||
@ -215,7 +215,7 @@ function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
||||
|
||||
for (const path of imps) path.remove();
|
||||
for (const path of impsBindingRefs) {
|
||||
const node = t.cloneDeep(dependenciesRefs[path.node.name]);
|
||||
const node = t.cloneNode(dependenciesRefs[path.node.name]);
|
||||
path.replaceWith(node);
|
||||
}
|
||||
|
||||
|
||||
@ -128,7 +128,7 @@ export default function(api, options) {
|
||||
t.variableDeclarator(ident, computedNode.key),
|
||||
]),
|
||||
);
|
||||
computedNode.key = t.clone(ident);
|
||||
computedNode.key = t.cloneNode(ident);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,7 @@ export default function() {
|
||||
|
||||
function inferBindContext(bind, scope) {
|
||||
const staticContext = getStaticContext(bind, scope);
|
||||
if (staticContext) return t.cloneDeep(staticContext);
|
||||
if (staticContext) return t.cloneNode(staticContext);
|
||||
|
||||
const tempId = getTempId(scope);
|
||||
if (bind.object) {
|
||||
|
||||
@ -15,7 +15,11 @@ export default function(api, { loose = false }) {
|
||||
const ref = scope.generateUidIdentifierBasedOnNode(node.left);
|
||||
scope.push({ id: ref });
|
||||
|
||||
const assignment = t.assignmentExpression("=", t.clone(ref), node.left);
|
||||
const assignment = t.assignmentExpression(
|
||||
"=",
|
||||
t.cloneNode(ref),
|
||||
node.left,
|
||||
);
|
||||
|
||||
path.replaceWith(
|
||||
t.conditionalExpression(
|
||||
@ -28,11 +32,11 @@ export default function(api, { loose = false }) {
|
||||
t.binaryExpression("!==", assignment, t.nullLiteral()),
|
||||
t.binaryExpression(
|
||||
"!==",
|
||||
t.clone(ref),
|
||||
t.cloneNode(ref),
|
||||
scope.buildUndefinedNode(),
|
||||
),
|
||||
),
|
||||
t.clone(ref),
|
||||
t.cloneNode(ref),
|
||||
node.right,
|
||||
),
|
||||
);
|
||||
|
||||
@ -74,7 +74,7 @@ export default function(api, opts) {
|
||||
const props = path.get("properties");
|
||||
const last = props[props.length - 1];
|
||||
t.assertRestElement(last.node);
|
||||
const restElement = t.clone(last.node);
|
||||
const restElement = t.cloneNode(last.node);
|
||||
last.remove();
|
||||
|
||||
const impureComputedPropertyDeclarators = replaceImpureComputedKeys(path);
|
||||
@ -291,7 +291,7 @@ export default function(api, opts) {
|
||||
);
|
||||
}
|
||||
|
||||
const nodeWithoutSpread = t.clone(path.node);
|
||||
const nodeWithoutSpread = t.cloneNode(path.node);
|
||||
nodeWithoutSpread.right = ref;
|
||||
nodes.push(t.expressionStatement(nodeWithoutSpread));
|
||||
nodes.push(
|
||||
|
||||
@ -73,13 +73,13 @@ export default function(api, options) {
|
||||
replacementPath.replaceWith(
|
||||
t.conditionalExpression(
|
||||
loose
|
||||
? t.binaryExpression("==", t.clone(check), t.nullLiteral())
|
||||
? t.binaryExpression("==", t.cloneNode(check), t.nullLiteral())
|
||||
: t.logicalExpression(
|
||||
"||",
|
||||
t.binaryExpression("===", t.clone(check), t.nullLiteral()),
|
||||
t.binaryExpression("===", t.cloneNode(check), t.nullLiteral()),
|
||||
t.binaryExpression(
|
||||
"===",
|
||||
t.clone(ref),
|
||||
t.cloneNode(ref),
|
||||
scope.buildUndefinedNode(),
|
||||
),
|
||||
),
|
||||
|
||||
@ -13,7 +13,7 @@ export default function(api, options) {
|
||||
|
||||
let wrapAsync = state.methodWrapper;
|
||||
if (wrapAsync) {
|
||||
wrapAsync = t.cloneDeep(wrapAsync);
|
||||
wrapAsync = t.cloneNode(wrapAsync);
|
||||
} else {
|
||||
wrapAsync = state.methodWrapper = addNamed(path, method, module);
|
||||
}
|
||||
|
||||
@ -525,7 +525,7 @@ class BlockScoping {
|
||||
|
||||
// turn outsideLetReferences into an array
|
||||
const args = values(outsideRefs);
|
||||
const params = args.map(id => t.clone(id));
|
||||
const params = args.map(id => t.cloneNode(id));
|
||||
|
||||
const isSwitch = this.blockPath.isSwitchStatement();
|
||||
|
||||
|
||||
@ -221,7 +221,7 @@ export default function(api, options) {
|
||||
if (t.isRestElement(prop)) {
|
||||
this.pushObjectRest(pattern, objRef, prop, i);
|
||||
} else {
|
||||
this.pushObjectProperty(prop, t.clone(objRef));
|
||||
this.pushObjectProperty(prop, t.cloneNode(objRef));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ export default function(api, options) {
|
||||
array = right;
|
||||
}
|
||||
|
||||
const item = t.memberExpression(array, t.clone(i), true);
|
||||
const item = t.memberExpression(array, t.cloneNode(i), true);
|
||||
let assignment;
|
||||
if (t.isVariableDeclaration(left)) {
|
||||
assignment = left;
|
||||
@ -44,10 +44,10 @@ export default function(api, options) {
|
||||
t.variableDeclaration("let", inits),
|
||||
t.binaryExpression(
|
||||
"<",
|
||||
t.clone(i),
|
||||
t.memberExpression(t.clone(array), t.identifier("length")),
|
||||
t.cloneNode(i),
|
||||
t.memberExpression(t.cloneNode(array), t.identifier("length")),
|
||||
),
|
||||
t.updateExpression("++", t.clone(i)),
|
||||
t.updateExpression("++", t.cloneNode(i)),
|
||||
block,
|
||||
),
|
||||
);
|
||||
|
||||
@ -63,7 +63,7 @@ export default function(api, options) {
|
||||
|
||||
let cached = cache.get(key);
|
||||
if (cached) {
|
||||
cached = t.cloneDeep(cached);
|
||||
cached = t.cloneNode(cached);
|
||||
} else {
|
||||
cached = addDefault(file.path, source, {
|
||||
importedInterop: "uncompiled",
|
||||
|
||||
@ -107,7 +107,7 @@ export default function(api, options) {
|
||||
callee.object = t.assignmentExpression("=", temp, callee.object);
|
||||
contextLiteral = temp;
|
||||
} else {
|
||||
contextLiteral = t.cloneDeep(callee.object);
|
||||
contextLiteral = t.cloneNode(callee.object);
|
||||
}
|
||||
t.appendToMemberExpression(callee, t.identifier("apply"));
|
||||
} else {
|
||||
|
||||
@ -72,7 +72,7 @@ export default function(api, options) {
|
||||
|
||||
let templateObject = this.templates.get(name);
|
||||
if (templateObject) {
|
||||
templateObject = t.clone(templateObject);
|
||||
templateObject = t.cloneNode(templateObject);
|
||||
} else {
|
||||
const programPath = path.find(p => p.isProgram());
|
||||
templateObject = programPath.scope.generateUidIdentifier(
|
||||
|
||||
@ -8,7 +8,7 @@ export default function populatePlaceholders(
|
||||
metadata: Metadata,
|
||||
replacements: TemplateReplacements,
|
||||
): BabelNodeFile {
|
||||
const ast = t.cloneDeep(metadata.ast);
|
||||
const ast = t.cloneNode(metadata.ast);
|
||||
|
||||
if (replacements) {
|
||||
metadata.placeholders.forEach(placeholder => {
|
||||
@ -57,9 +57,9 @@ function applyReplacement(
|
||||
// once to avoid injecting the same node multiple times.
|
||||
if (placeholder.isDuplicate) {
|
||||
if (Array.isArray(replacement)) {
|
||||
replacement = replacement.map(node => t.cloneDeep(node));
|
||||
replacement = replacement.map(node => t.cloneNode(node));
|
||||
} else if (typeof replacement === "object") {
|
||||
replacement = t.cloneDeep(replacement);
|
||||
replacement = t.cloneNode(replacement);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
// @flow
|
||||
|
||||
import cloneNode from "./cloneNode";
|
||||
|
||||
/**
|
||||
* Create a shallow clone of a `node` excluding `_private` properties.
|
||||
* Create a shallow clone of a `node`, including only
|
||||
* properties belonging to the node.
|
||||
* @deprecated Use t.cloneNode instead.
|
||||
*/
|
||||
export default function clone<T: Object>(node: T): T {
|
||||
if (!node) return node;
|
||||
const newNode = (({}: any): T);
|
||||
|
||||
Object.keys(node).forEach(key => {
|
||||
if (key[0] === "_") return;
|
||||
newNode[key] = node[key];
|
||||
});
|
||||
|
||||
return newNode;
|
||||
return cloneNode(node, /* deep */ false);
|
||||
}
|
||||
|
||||
@ -1,28 +1,12 @@
|
||||
// @flow
|
||||
|
||||
import cloneNode from "./cloneNode";
|
||||
|
||||
/**
|
||||
* Create a deep clone of a `node` and all of it's child nodes
|
||||
* excluding `_private` properties.
|
||||
* including only properties belonging to the node.
|
||||
* @deprecated Use t.cloneNode instead.
|
||||
*/
|
||||
export default function cloneDeep<T: Object>(node: T): T {
|
||||
if (!node) return node;
|
||||
const newNode = (({}: any): T);
|
||||
|
||||
Object.keys(node).forEach(key => {
|
||||
if (key[0] === "_") return;
|
||||
|
||||
let val = node[key];
|
||||
|
||||
if (val) {
|
||||
if (val.type) {
|
||||
val = cloneDeep(val);
|
||||
} else if (Array.isArray(val)) {
|
||||
val = val.map(cloneDeep);
|
||||
}
|
||||
}
|
||||
|
||||
newNode[key] = val;
|
||||
});
|
||||
|
||||
return newNode;
|
||||
return cloneNode(node);
|
||||
}
|
||||
|
||||
69
packages/babel-types/src/clone/cloneNode.js
Normal file
69
packages/babel-types/src/clone/cloneNode.js
Normal file
@ -0,0 +1,69 @@
|
||||
import { NODE_FIELDS } from "../definitions";
|
||||
|
||||
const has = Function.call.bind(Object.prototype.hasOwnProperty);
|
||||
|
||||
function cloneIfNode(obj, deep) {
|
||||
if (
|
||||
obj &&
|
||||
typeof obj.type === "string" &&
|
||||
// CommentLine and CommentBlock are used in File#comments, but they are
|
||||
// not defined in babel-types
|
||||
obj.type !== "CommentLine" &&
|
||||
obj.type !== "CommentBlock"
|
||||
) {
|
||||
return cloneNode(obj, deep);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
function cloneIfNodeOrArray(obj, deep) {
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(node => cloneIfNode(node, deep));
|
||||
}
|
||||
return cloneIfNode(obj, deep);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of a `node` including only properties belonging to the node.
|
||||
* If the second parameter is `false`, cloneNode performs a shallow clone.
|
||||
*/
|
||||
export default function cloneNode<T: Object>(node: T, deep: boolean = true): T {
|
||||
if (!node) return node;
|
||||
|
||||
const { type } = node;
|
||||
const newNode = (({ type }: any): T);
|
||||
|
||||
// Special-case identifiers since they are the most cloned nodes.
|
||||
if (type === "Identifier") {
|
||||
newNode.name = node.name;
|
||||
} else if (!has(NODE_FIELDS, type)) {
|
||||
throw new Error(`Unknown node type: "${type}"`);
|
||||
} else {
|
||||
for (const field of Object.keys(NODE_FIELDS[type])) {
|
||||
if (has(node, field)) {
|
||||
newNode[field] = deep
|
||||
? cloneIfNodeOrArray(node[field], true)
|
||||
: node[field];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (has(node, "loc")) {
|
||||
newNode.loc = node.loc;
|
||||
}
|
||||
if (has(node, "leadingComments")) {
|
||||
newNode.leadingComments = node.leadingComments;
|
||||
}
|
||||
if (has(node, "innerComments")) {
|
||||
newNode.innerComments = node.innerCmments;
|
||||
}
|
||||
if (has(node, "trailingComments")) {
|
||||
newNode.trailingComments = node.trailingComments;
|
||||
}
|
||||
if (has(node, "extra")) {
|
||||
newNode.extra = Object.assign({}, node.extra);
|
||||
}
|
||||
|
||||
return newNode;
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
import { isIdentifier, isStringLiteral } from "../validators/generated";
|
||||
import cloneDeep from "../clone/cloneDeep";
|
||||
import cloneNode from "../clone/cloneNode";
|
||||
import removePropertiesDeep from "../modifications/removePropertiesDeep";
|
||||
|
||||
export default function toKeyAlias(
|
||||
@ -16,7 +16,7 @@ export default function toKeyAlias(
|
||||
} else if (isStringLiteral(key)) {
|
||||
alias = JSON.stringify(key.value);
|
||||
} else {
|
||||
alias = JSON.stringify(removePropertiesDeep(cloneDeep(key)));
|
||||
alias = JSON.stringify(removePropertiesDeep(cloneNode(key)));
|
||||
}
|
||||
|
||||
if (node.computed) {
|
||||
|
||||
@ -17,6 +17,7 @@ export {
|
||||
export * from "./builders/generated";
|
||||
|
||||
// clone
|
||||
export { default as cloneNode } from "./clone/cloneNode";
|
||||
export { default as clone } from "./clone/clone";
|
||||
export { default as cloneDeep } from "./clone/cloneDeep";
|
||||
export { default as cloneWithoutLoc } from "./clone/cloneWithoutLoc";
|
||||
|
||||
@ -2,68 +2,61 @@ import * as t from "../lib";
|
||||
import assert from "assert";
|
||||
import { parse } from "babylon";
|
||||
|
||||
suite("cloning", function() {
|
||||
suite("clone", function() {
|
||||
suite("cloneNode", function() {
|
||||
it("should handle undefined", function() {
|
||||
const node = undefined;
|
||||
const cloned = t.clone(node);
|
||||
const cloned = t.cloneNode(node);
|
||||
assert(cloned === undefined);
|
||||
});
|
||||
|
||||
it("should handle null", function() {
|
||||
const node = null;
|
||||
const cloned = t.clone(node);
|
||||
const cloned = t.cloneNode(node);
|
||||
assert(cloned === null);
|
||||
});
|
||||
|
||||
it("should handle simple cases", function() {
|
||||
const node = t.arrayExpression([null, t.identifier("a")]);
|
||||
const cloned = t.clone(node);
|
||||
assert(node !== cloned);
|
||||
assert(t.isNodesEquivalent(node, cloned) === true);
|
||||
});
|
||||
});
|
||||
|
||||
suite("cloneDeep", function() {
|
||||
it("should handle undefined", function() {
|
||||
const node = undefined;
|
||||
const cloned = t.cloneDeep(node);
|
||||
assert(cloned === undefined);
|
||||
});
|
||||
|
||||
it("should handle null", function() {
|
||||
const node = null;
|
||||
const cloned = t.cloneDeep(node);
|
||||
assert(cloned === null);
|
||||
});
|
||||
|
||||
it("should handle simple cases", function() {
|
||||
const node = t.arrayExpression([null, t.identifier("a")]);
|
||||
const cloned = t.cloneDeep(node);
|
||||
const node = t.identifier("a");
|
||||
const cloned = t.cloneNode(node);
|
||||
assert(node !== cloned);
|
||||
assert(t.isNodesEquivalent(node, cloned) === true);
|
||||
});
|
||||
|
||||
it("should handle full programs", function() {
|
||||
const node = parse("1 + 1");
|
||||
const cloned = t.cloneDeep(node);
|
||||
assert(node !== cloned);
|
||||
assert(t.isNodesEquivalent(node, cloned) === true);
|
||||
const file = parse("1 + 1");
|
||||
const cloned = t.cloneNode(file);
|
||||
assert(file !== cloned);
|
||||
assert(
|
||||
file.program.body[0].expression.right !==
|
||||
cloned.program.body[0].expression.right,
|
||||
);
|
||||
assert(
|
||||
file.program.body[0].expression.left !==
|
||||
cloned.program.body[0].expression.left,
|
||||
);
|
||||
assert(t.isNodesEquivalent(file, cloned) === true);
|
||||
});
|
||||
|
||||
it("should handle complex programs", function() {
|
||||
const program = "'use strict'; function lol() { wow();return 1; }";
|
||||
const node = parse(program);
|
||||
const cloned = t.cloneDeep(node);
|
||||
const cloned = t.cloneNode(node);
|
||||
assert(node !== cloned);
|
||||
assert(t.isNodesEquivalent(node, cloned) === true);
|
||||
});
|
||||
|
||||
it("should handle missing array element", function() {
|
||||
const node = parse("[,0]");
|
||||
const cloned = t.cloneDeep(node);
|
||||
const cloned = t.cloneNode(node);
|
||||
assert(node !== cloned);
|
||||
assert(t.isNodesEquivalent(node, cloned) === true);
|
||||
});
|
||||
|
||||
it("should support shallow cloning", function() {
|
||||
const node = t.memberExpression(t.identifier("foo"), t.identifier("bar"));
|
||||
const cloned = t.cloneNode(node, /* deep */ false);
|
||||
assert.notStrictEqual(node, cloned);
|
||||
assert.strictEqual(node.object, cloned.object);
|
||||
assert.strictEqual(node.property, cloned.property);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user