diff --git a/packages/babel-plugin-proposal-object-rest-spread/src/index.js b/packages/babel-plugin-proposal-object-rest-spread/src/index.js index 9263fbd56d5e..7f0d2525fbed 100644 --- a/packages/babel-plugin-proposal-object-rest-spread/src/index.js +++ b/packages/babel-plugin-proposal-object-rest-spread/src/index.js @@ -102,12 +102,12 @@ export default declare((api, opts) => { // replaces impure computed keys with new identifiers // and returns variable declarators of these new identifiers - function replaceImpureComputedKeys(path) { + function replaceImpureComputedKeys(properties, scope) { const impureComputedPropertyDeclarators = []; - for (const propPath of path.get("properties")) { + for (const propPath of properties) { const key = propPath.get("key"); if (propPath.node.computed && !key.isPure()) { - const name = path.scope.generateUidBasedOnNode(key.node); + const name = scope.generateUidBasedOnNode(key.node); const declarator = t.variableDeclarator(t.identifier(name), key.node); impureComputedPropertyDeclarators.push(declarator); key.replaceWith(t.identifier(name)); @@ -139,7 +139,10 @@ export default declare((api, opts) => { const restElement = t.cloneNode(last.node); last.remove(); - const impureComputedPropertyDeclarators = replaceImpureComputedKeys(path); + const impureComputedPropertyDeclarators = replaceImpureComputedKeys( + path.get("properties"), + path.scope, + ); const { keys, allLiteral } = extractNormalizedKeys(path); if (keys.length === 0) { @@ -265,18 +268,21 @@ export default declare((api, opts) => { path.findParent(path => { if (path.isObjectProperty()) { - refPropertyPath.unshift(path.node.key.name); + refPropertyPath.unshift(path); } else if (path.isVariableDeclarator()) { kind = path.parentPath.node.kind; return true; } }); - if (refPropertyPath.length) { - refPropertyPath.forEach(prop => { - ref = t.memberExpression(ref, t.identifier(prop)); - }); - } + const impureObjRefComputedDeclarators = replaceImpureComputedKeys( + refPropertyPath, + path.scope, + ); + refPropertyPath.forEach(prop => { + const { node } = prop; + ref = t.memberExpression(ref, t.cloneNode(node.key), node.computed); + }); const objectPatternPath = path.findParent(path => path.isObjectPattern(), @@ -296,6 +302,8 @@ export default declare((api, opts) => { insertionPath.insertBefore(impureComputedPropertyDeclarators); + insertionPath.insertBefore(impureObjRefComputedDeclarators); + insertionPath.insertAfter( t.variableDeclarator(argument, callExpression), ); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/object-ref-computed-exec/exec.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/object-ref-computed-exec/exec.js new file mode 100644 index 000000000000..53012ea3f1af --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/object-ref-computed-exec/exec.js @@ -0,0 +1,20 @@ +var key, x, y, z; +// impure +key = 1; +var { [key++]: { y, ...x } } = { 1: { a: 1, y: 1 } }; +expect(x).toEqual({ a: 1 }); +expect(key).toBe(2); +expect(y).toBe(1); + +// takes care of the order + +key = 1; +var { + [++key]: { y, ...rest_y }, + [++key]: { z, ...rest_z } +} = {2: { y: 2, z: 3 }, 3: { y: 2, z: 3 } }; +expect(y).toBe(2); +expect(rest_y).toEqual({z: 3}); +expect(z).toBe(3); +expect(rest_z).toEqual({ y: 2 }); +expect(key).toBe(3); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/object-ref-computed/input.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/object-ref-computed/input.js new file mode 100644 index 000000000000..53012ea3f1af --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/object-ref-computed/input.js @@ -0,0 +1,20 @@ +var key, x, y, z; +// impure +key = 1; +var { [key++]: { y, ...x } } = { 1: { a: 1, y: 1 } }; +expect(x).toEqual({ a: 1 }); +expect(key).toBe(2); +expect(y).toBe(1); + +// takes care of the order + +key = 1; +var { + [++key]: { y, ...rest_y }, + [++key]: { z, ...rest_z } +} = {2: { y: 2, z: 3 }, 3: { y: 2, z: 3 } }; +expect(y).toBe(2); +expect(rest_y).toEqual({z: 3}); +expect(z).toBe(3); +expect(rest_z).toEqual({ y: 2 }); +expect(key).toBe(3); diff --git a/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/object-ref-computed/output.js b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/object-ref-computed/output.js new file mode 100644 index 000000000000..319a0fe18c55 --- /dev/null +++ b/packages/babel-plugin-proposal-object-rest-spread/test/fixtures/object-rest/object-ref-computed/output.js @@ -0,0 +1,62 @@ +var key, x, y, z; // impure + +key = 1; + +var _ref = key++, + { + [_ref]: { + y + } +} = { + 1: { + a: 1, + y: 1 + } +}, + x = babelHelpers.objectWithoutProperties({ + 1: { + a: 1, + y: 1 + } +}[_ref], ["y"]); + +expect(x).toEqual({ + a: 1 +}); +expect(key).toBe(2); +expect(y).toBe(1); // takes care of the order + +key = 1; + +var _$ = { + 2: { + y: 2, + z: 3 + }, + 3: { + y: 2, + z: 3 + } +}, + _ref2 = ++key, + _ref3 = ++key, + { + [_ref3]: { + y + }, + [_ref2]: { + z + } +} = _$, + rest_y = babelHelpers.objectWithoutProperties(_$[_ref3], ["y"]), + rest_z = babelHelpers.objectWithoutProperties(_$[_ref2], ["z"]); + +expect(y).toBe(2); +expect(rest_y).toEqual({ + z: 3 +}); +expect(z).toBe(3); +expect(rest_z).toEqual({ + y: 2 +}); +expect(key).toBe(3);