Use for..of Object.keys instead of for..in (#9518)
In https://github.com/babel/babel/issues/9511 (and #9495 is another symptom), @PavelKastornyy reported a node crash becaue the JavaScript heap run out of memory. The problem was that their code was adding enumerable properties to `Object.prototype`: it is something that shouldn't be done, but Babel shouldn't make node crash if someone adds them. I reduced down the problem to `for...in` loops in `@babel/traverse` that grew the memory consumption exponentially because of that unexpected properties.
This commit is contained in:
@@ -28,7 +28,7 @@ export default function builder(type: string, ...args: Array<any>): Object {
|
||||
i++;
|
||||
});
|
||||
|
||||
for (const key in node) {
|
||||
for (const key of Object.keys(node)) {
|
||||
validate(node, key, node[key]);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function gatherSequenceExpressions(
|
||||
|
||||
for (const declar of (node.declarations: Array<any>)) {
|
||||
const bindings = getBindingIdentifiers(declar);
|
||||
for (const key in bindings) {
|
||||
for (const key of Object.keys(bindings)) {
|
||||
declars.push({
|
||||
kind: node.kind,
|
||||
id: cloneNode(bindings[key]),
|
||||
|
||||
@@ -77,7 +77,7 @@ export default function valueToNode(value: any): Object {
|
||||
// object
|
||||
if (isPlainObject(value)) {
|
||||
const props = [];
|
||||
for (const key in value) {
|
||||
for (const key of Object.keys(value)) {
|
||||
let nodeKey;
|
||||
if (isValidIdentifier(key)) {
|
||||
nodeKey = identifier(key);
|
||||
|
||||
@@ -201,7 +201,7 @@ export default function defineType(
|
||||
fields[key] = fields[key] || {};
|
||||
}
|
||||
|
||||
for (const key in fields) {
|
||||
for (const key of Object.keys(fields)) {
|
||||
const field = fields[key];
|
||||
|
||||
if (builder.indexOf(key) === -1) {
|
||||
|
||||
@@ -73,12 +73,12 @@ export default function removeTypeDuplicates(
|
||||
}
|
||||
|
||||
// add back in bases
|
||||
for (const type in bases) {
|
||||
for (const type of Object.keys(bases)) {
|
||||
types.push(bases[type]);
|
||||
}
|
||||
|
||||
// add back in generics
|
||||
for (const name in generics) {
|
||||
for (const name of Object.keys(generics)) {
|
||||
types.push(generics[name]);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export default function inherits<T: Object>(child: T, parent: Object): T {
|
||||
}
|
||||
|
||||
// force inherit "private" properties
|
||||
for (const key in parent) {
|
||||
for (const key of Object.keys(parent)) {
|
||||
if (key[0] === "_" && key !== "__clone") child[key] = parent[key];
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export default function removeProperties(
|
||||
if (node[key] != null) node[key] = undefined;
|
||||
}
|
||||
|
||||
for (const key in node) {
|
||||
for (const key of Object.keys(node)) {
|
||||
if (key[0] === "_" && node[key] != null) node[key] = undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,11 @@ export default function isNodesEquivalent(a: any, b: any): boolean {
|
||||
if (typeof a[field] !== typeof b[field]) {
|
||||
return false;
|
||||
}
|
||||
if (a[field] == null && b[field] == null) {
|
||||
continue;
|
||||
} else if (a[field] == null || b[field] == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Array.isArray(a[field])) {
|
||||
if (!Array.isArray(b[field])) {
|
||||
@@ -46,7 +51,7 @@ export default function isNodesEquivalent(a: any, b: any): boolean {
|
||||
typeof a[field] === "object" &&
|
||||
(!visitorKeys || !visitorKeys.includes(field))
|
||||
) {
|
||||
for (const key in a[field]) {
|
||||
for (const key of Object.keys(a[field])) {
|
||||
if (a[field][key] !== b[field][key]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user