Skip to content

Commit e482c76

Browse files
authored
fix: Memory leak when deep cloning in babel-core (#14583)
* fix * review * review * fix and rebase * improve typing * review * fix test
1 parent f0ec180 commit e482c76

File tree

4 files changed

+70
-30
lines changed

4 files changed

+70
-30
lines changed

packages/babel-core/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,9 @@
4141
"./lib/config/files/index.js": "./lib/config/files/index-browser.js",
4242
"./lib/config/resolve-targets.js": "./lib/config/resolve-targets-browser.js",
4343
"./lib/transform-file.js": "./lib/transform-file-browser.js",
44-
"./lib/transformation/util/clone-deep.js": "./lib/transformation/util/clone-deep-browser.js",
4544
"./src/config/files/index.ts": "./src/config/files/index-browser.ts",
4645
"./src/config/resolve-targets.ts": "./src/config/resolve-targets-browser.ts",
47-
"./src/transform-file.ts": "./src/transform-file-browser.ts",
48-
"./src/transformation/util/clone-deep.ts": "./src/transformation/util/clone-deep-browser.ts"
46+
"./src/transform-file.ts": "./src/transform-file-browser.ts"
4947
},
5048
"dependencies": {
5149
"@ampproject/remapping": "^2.1.0",

packages/babel-core/src/transformation/util/clone-deep-browser.ts

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
1-
import v8 from "v8";
2-
import cloneDeep from "./clone-deep-browser";
3-
4-
export default function (value) {
5-
if (v8.deserialize && v8.serialize) {
6-
return v8.deserialize(v8.serialize(value));
1+
//https://github.com/babel/babel/pull/14583#discussion_r882828856
2+
function deepClone(value: any, cache: Map<any, any>): any {
3+
if (value !== null) {
4+
if (cache.has(value)) return cache.get(value);
5+
let cloned: any;
6+
if (Array.isArray(value)) {
7+
cloned = new Array(value.length);
8+
for (let i = 0; i < value.length; i++) {
9+
cloned[i] =
10+
typeof value[i] !== "object" ? value[i] : deepClone(value[i], cache);
11+
}
12+
} else {
13+
cloned = {};
14+
const keys = Object.keys(value);
15+
for (let i = 0; i < keys.length; i++) {
16+
const key = keys[i];
17+
cloned[key] =
18+
typeof value[key] !== "object"
19+
? value[key]
20+
: deepClone(value[key], cache);
21+
}
22+
}
23+
cache.set(value, cloned);
24+
return cloned;
725
}
8-
return cloneDeep(value);
26+
return value;
27+
}
28+
29+
export default function <T>(value: T): T {
30+
if (typeof value !== "object") return value;
31+
return deepClone(value, new Map());
932
}

packages/babel-core/test/api.js

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,45 @@ describe("api", function () {
261261
},
262262
);
263263

264-
it("transformFromAstSync should not mutate the AST", function () {
264+
it("transformFromAst should generate same code with different cloneInputAst", function () {
265+
const program = `//test1
266+
/*test2*/var/*test3*/ a = 1/*test4*/;//test5
267+
//test6
268+
var b;
269+
`;
270+
const node = parseSync(program);
271+
const { code } = transformFromAstSync(node, program, {
272+
plugins: [
273+
function () {
274+
return {
275+
visitor: {
276+
Identifier: function (path) {
277+
path.node.name = "replaced";
278+
},
279+
},
280+
};
281+
},
282+
],
283+
});
284+
const { code: code2 } = transformFromAstSync(node, program, {
285+
cloneInputAst: false,
286+
plugins: [
287+
function () {
288+
return {
289+
visitor: {
290+
Identifier: function (path) {
291+
path.node.name = "replaced";
292+
},
293+
},
294+
};
295+
},
296+
],
297+
});
298+
299+
expect(code).toBe(code2);
300+
});
301+
302+
it("transformFromAst should not mutate the AST", function () {
265303
const program = "const identifier = 1";
266304
const node = parseSync(program);
267305
const { code } = transformFromAstSync(node, program, {

0 commit comments

Comments
 (0)