babel/packages/babel-plugin-proposal-object-rest-spread/src/shouldStoreRHSInTemporaryVariable.js
Daniel Kezerashvili 40e43f5a14
fix: Duplicate function call in variable destructuring (#13711)
* Add test case demonstrating invalid behavior

* Add conditional check for child properties so RHS is not duplicated

* Add recursive check to find any nested non single-property case

* Add case for array destructuring

* Add test case for a nested rest element

* More safely recurse through array destructuring

* Traverse assignment and nested rest operations

* Refactor to be more clear which case statement we are executing against

* Update missed snapshots

* Update packages/babel-plugin-proposal-object-rest-spread/src/index.js

Co-authored-by: Huáng Jùnliàng <jlhwung@gmail.com>

* Filter null array elements, add early return, remove optional chaining

* Use stronger type assertions

* Update fall through to be false; add early return to RestElement case

* Move hasMoreThanOneBinding to its own file with distinct tests

* Rename testing helper to more appropriately match business logic

* Yarn Dedup & rename hasMoreThanOneBinding to shouldStoreRHSInTemporaryVariable

Co-authored-by: Huáng Jùnliàng <jlhwung@gmail.com>
2021-09-07 17:27:52 -04:00

31 lines
1.2 KiB
JavaScript

import { types as t } from "@babel/core";
/**
* This is a helper function to determine if we should create an intermediate variable
* such that the RHS of an assignment is not duplicated.
*
* See https://github.com/babel/babel/pull/13711#issuecomment-914388382 for discussion
* on further optimizations.
*/
export default function shouldStoreRHSInTemporaryVariable(node) {
if (t.isArrayPattern(node)) {
const nonNullElements = node.elements.filter(element => element !== null);
if (nonNullElements.length > 1) return true;
else return shouldStoreRHSInTemporaryVariable(nonNullElements[0]);
} else if (t.isObjectPattern(node)) {
if (node.properties.length > 1) return true;
else if (node.properties.length === 0) return false;
else return shouldStoreRHSInTemporaryVariable(node.properties[0]);
} else if (t.isObjectProperty(node)) {
return shouldStoreRHSInTemporaryVariable(node.value);
} else if (t.isAssignmentPattern(node)) {
return shouldStoreRHSInTemporaryVariable(node.left);
} else if (t.isRestElement(node)) {
if (t.isIdentifier(node.argument)) return true;
return shouldStoreRHSInTemporaryVariable(node.argument);
} else {
// node is Identifier or MemberExpression
return false;
}
}