Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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>
- Loading branch information
Showing
10 changed files
with
295 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
packages/babel-plugin-proposal-object-rest-spread/src/shouldStoreRHSInTemporaryVariable.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
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; | ||
} | ||
} |
7 changes: 4 additions & 3 deletions
7
...lugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-computed-key/output.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
var _ref2; | ||
var _ref3; | ||
|
||
const { | ||
[_ref => { | ||
let rest = babelHelpers.extends({}, _ref); | ||
let b = babelHelpers.extends({}, {}); | ||
let _ref2 = {}, | ||
b = babelHelpers.extends({}, _ref2); | ||
}]: a, | ||
[(_ref2 = {}, ({} = _ref2), d = babelHelpers.extends({}, _ref2), _ref2)]: c | ||
[(_ref3 = {}, ({} = _ref3), d = babelHelpers.extends({}, _ref3), _ref3)]: c | ||
} = {}; |
7 changes: 4 additions & 3 deletions
7
...ugin-proposal-object-rest-spread/test/fixtures/object-rest/nested-default-value/output.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,10 @@ | ||
var _ref2; | ||
var _ref3; | ||
|
||
const { | ||
a = _ref => { | ||
let rest = babelHelpers.extends({}, _ref); | ||
let b = babelHelpers.extends({}, {}); | ||
let _ref2 = {}, | ||
b = babelHelpers.extends({}, _ref2); | ||
}, | ||
c = (_ref2 = {}, ({} = _ref2), d = babelHelpers.extends({}, _ref2), _ref2) | ||
c = (_ref3 = {}, ({} = _ref3), d = babelHelpers.extends({}, _ref3), _ref3) | ||
} = {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
44 changes: 32 additions & 12 deletions
44
...gin-proposal-object-rest-spread/test/fixtures/object-rest/variable-destructuring/input.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,39 @@ | ||
var z = {}; | ||
var { ...x } = z; | ||
var { ...a } = { a: 1 }; | ||
var { ...x } = a.b; | ||
var { ...x } = a(); | ||
var {x1, ...y1} = z; | ||
x1++; | ||
var { [a]: b, ...c } = z; | ||
var {x1, ...y1} = z; | ||
let {x2, y2, ...z2} = z; | ||
const {w3, x3, y3, ...z4} = z; | ||
const { x15: [...{ ...y15 }] } = z(); | ||
|
||
let { | ||
x: { a: xa, [d]: f, ...asdf }, | ||
y: { ...d }, | ||
...g | ||
} = complex; | ||
|
||
let { x4: { ...y4 } } = z; | ||
let { x4: { ...y4 } } = z(); | ||
|
||
let { x5: { w5, ...y5 } } = z(); | ||
let { x6: { w6: { a6, ...y6 } } } = z(); | ||
let { x7: { e7, r7 }, q7: { w7: { a7, ...y7 } } } = z(); | ||
let { x8, ...y8 } = z(); | ||
let { x9: { w9: { a9, ...y9 } }, x10: { a10, ...y10 }, } = z(); | ||
let { x11: [{ w11, ...z11 }] } = z(); | ||
let { x12: [{ a12, b12 }, { c12, ...d12 }] } = z(); | ||
let { x13: [, { c13, ...d13 }] } = z(); | ||
const { x14: [...{ q14, ...y14 }] } = z(); | ||
const { x15: [...{ ...y16 }] } = z(); | ||
const { x16: [] } = z(); | ||
const [...[ ...y17 ]] = z(); | ||
const [...{ ...y18 }] = z(); | ||
const [...{ a19, ...y19 }] = z(); | ||
const { x20: { ...y20 } = { } } = z(); | ||
const { x22: { q22, ...y22 } = {} } = z(); | ||
const [[ ...y23 ] = []] = z(); | ||
const [{ ...y24 } = []] = z(); | ||
const { x25: [ ...y25 ] = []} = z(); | ||
const { x26: [ q26, ...y26 ] = []} = z(); | ||
const {} = {}; | ||
const [,,x27] = z(); | ||
const {x28: [,,{...y28}]} = z(); | ||
const {x29: [,,{q29, ...y29}]} = z(); | ||
const [,,{y30, ...x30}] = z(); | ||
const [,,{...x31}] = z(); | ||
const { x32: { }, w32: { ...y32 } } = z(); | ||
const [,,{}, {...q32}] = z(); | ||
const { ...y33 } = z(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.