Skip to content

Commit

Permalink
review
Browse files Browse the repository at this point in the history
  • Loading branch information
liuxingbaoyu committed May 16, 2022
1 parent ea5bdbf commit fa214d0
Showing 1 changed file with 36 additions and 15 deletions.
51 changes: 36 additions & 15 deletions packages/babel-types/src/clone/cloneNode.ts
Expand Up @@ -3,22 +3,21 @@ import type * as t from "..";
import { isFile, isIdentifier } from "../validators/generated";

const has = Function.call.bind(Object.prototype.hasOwnProperty);
const commentsCache: Map<any, any> = new Map();

// This function will never be called for comments, only for real nodes.
function cloneIfNode(obj, deep, withoutLoc) {
function cloneIfNode(obj, deep, withoutLoc, commentsCache) {
if (obj && typeof obj.type === "string") {
return cloneNode(obj, deep, withoutLoc);
return cloneNodeInternal(obj, deep, withoutLoc, commentsCache);
}

return obj;
}

function cloneIfNodeOrArray(obj, deep, withoutLoc) {
function cloneIfNodeOrArray(obj, deep, withoutLoc, commentsCache) {
if (Array.isArray(obj)) {
return obj.map(node => cloneIfNode(node, deep, withoutLoc));
return obj.map(node => cloneIfNode(node, deep, withoutLoc, commentsCache));
}
return cloneIfNode(obj, deep, withoutLoc);
return cloneIfNode(obj, deep, withoutLoc, commentsCache);
}

/**
Expand All @@ -31,10 +30,16 @@ export default function cloneNode<T extends t.Node>(
deep: boolean = true,
withoutLoc: boolean = false,
): T {
if (!node) return node;
return cloneNodeInternal(node, deep, withoutLoc, new Map());
}

const isTop = !commentsCache.get("inCloning");
if (isTop) commentsCache.set("inCloning", true);
function cloneNodeInternal<T extends t.Node>(
node: T,
deep: boolean = true,
withoutLoc: boolean = false,
commentsCache: Map<t.Comment, t.Comment>,
): T {
if (!node) return node;

const { type } = node;
const newNode: any = { type: node.type };
Expand All @@ -49,20 +54,34 @@ export default function cloneNode<T extends t.Node>(

if (has(node, "typeAnnotation")) {
newNode.typeAnnotation = deep
? cloneIfNodeOrArray(node.typeAnnotation, true, withoutLoc)
? cloneIfNodeOrArray(
node.typeAnnotation,
true,
withoutLoc,
commentsCache,
)
: node.typeAnnotation;
}
} else if (!has(NODE_FIELDS, type)) {
if (isTop) commentsCache.clear();
throw new Error(`Unknown node type: "${type}"`);
} else {
for (const field of Object.keys(NODE_FIELDS[type])) {
if (has(node, field)) {
if (deep) {
newNode[field] =
isFile(node) && field === "comments"
? maybeCloneComments(node.comments, deep, withoutLoc)
: cloneIfNodeOrArray(node[field], true, withoutLoc);
? maybeCloneComments(
node.comments,
deep,
withoutLoc,
commentsCache,
)
: cloneIfNodeOrArray(
node[field],
true,
withoutLoc,
commentsCache,
);
} else {
newNode[field] = node[field];
}
Expand All @@ -82,20 +101,23 @@ export default function cloneNode<T extends t.Node>(
node.leadingComments,
deep,
withoutLoc,
commentsCache,
);
}
if (has(node, "innerComments")) {
newNode.innerComments = maybeCloneComments(
node.innerComments,
deep,
withoutLoc,
commentsCache,
);
}
if (has(node, "trailingComments")) {
newNode.trailingComments = maybeCloneComments(
node.trailingComments,
deep,
withoutLoc,
commentsCache,
);
}
if (has(node, "extra")) {
Expand All @@ -104,15 +126,14 @@ export default function cloneNode<T extends t.Node>(
};
}

if (isTop) commentsCache.clear();

return newNode;
}

function maybeCloneComments<T extends t.Comment>(
comments: ReadonlyArray<T> | null,
deep: boolean,
withoutLoc: boolean,
commentsCache: Map<T, T>,
): ReadonlyArray<T> | null {
if (!comments || !deep) {
return comments;
Expand Down

0 comments on commit fa214d0

Please sign in to comment.