New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: Duplicate function call in variable destructuring #13711
Changes from 15 commits
51c520d
b74dfb9
cb530b1
698b776
b1c393e
87a02d1
84c2300
3c851b4
af17b56
8ace7f1
ab3b603
80fb872
60cabe8
df3d149
80b1692
317065d
4be2624
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { types as t } from "@babel/core"; | ||
|
||
export default function hasMoreThanOneBinding(node) { | ||
if (t.isArrayPattern(node)) { | ||
const nonNullElements = node.elements.filter(element => element !== null); | ||
if (nonNullElements.length > 1) return true; | ||
else return hasMoreThanOneBinding(nonNullElements[0]); | ||
} else if (t.isObjectPattern(node)) { | ||
if (node.properties.length > 1) return true; | ||
else if (node.properties.length === 0) return false; | ||
else return hasMoreThanOneBinding(node.properties[0]); | ||
} else if (t.isObjectProperty(node)) { | ||
return hasMoreThanOneBinding(node.value); | ||
} else if (t.isAssignmentPattern(node)) { | ||
return hasMoreThanOneBinding(node.left); | ||
} else if (t.isRestElement(node)) { | ||
if (t.isIdentifier(node.argument)) return true; | ||
return hasMoreThanOneBinding(node.argument); | ||
} else { | ||
// node is Identifier or MemberExpression | ||
return false; | ||
} | ||
} |
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 | ||
} = {}; |
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) | ||
} = {}; |
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(); | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! Can you add a test case with mixed arrays?
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just pushed up a commit. Thanks for the recommendation, it caught an edge case with the implementation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add a new test case? const { x: [...{ x, ...y }] } = z(); A RestElement's argument can be a pattern so we have to recurse into it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great point! I added the test case and confirmed the output looks as I'd expect. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can not return early when
has only one binding identifier but There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @JLHwung - thanks for the the detailed case. I looked through https://astexplorer.net/ and believe I was able to diagnose the issue you called out with more robust test cases for array destructuring. Happy to make any other adjustments. Thank you for the thorough review and prompt responses! |
||||||||||||
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(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unrelated to this PR: I think we should use
originalPath.scope.isStatic(originalPath.node.init)
here, becauseThisExpression
is safe to reuse, e.g.node.init
is an identifier, it can not be reused if not a constant binding. e.g.y
becomes{ v: 2 }
after transformed becausez
can be modified insideEffect()
.These two issues will be fixed by
scope.isStatic
, they can be addressed in a subsequent PR.