From ea6261eb962a04a191c01e16387faddfdea48352 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 2 Feb 2016 14:06:04 -0800 Subject: [PATCH] Fix: Object rest/spread in assign (fixes #247) --- espree.js | 29 + .../destructuring-assign-mirror.result.js | 549 +++++++++++++++ .../destructuring-assign-mirror.src.js | 1 + .../shorthand-method-args.result.js | 626 ++++++++++++++++++ .../shorthand-method-args.src.js | 5 + tests/lib/ecma-features.js | 2 +- tests/lib/tester.js | 1 + 7 files changed, 1212 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/ecma-features/experimentalObjectRestSpread/destructuring-assign-mirror.result.js create mode 100644 tests/fixtures/ecma-features/experimentalObjectRestSpread/destructuring-assign-mirror.src.js create mode 100644 tests/fixtures/ecma-features/experimentalObjectRestSpread/shorthand-method-args.result.js create mode 100644 tests/fixtures/ecma-features/experimentalObjectRestSpread/shorthand-method-args.src.js diff --git a/espree.js b/espree.js index e65cf07f..e085d2d5 100644 --- a/espree.js +++ b/espree.js @@ -275,6 +275,35 @@ pp.extend("parseTopLevel", function(parseTopLevel) { }; }); +pp.extend("toAssignable", function(toAssignable) { + + return /** @this acorn.Parser */ function(node, isBinding) { + + if (extra.ecmaFeatures.experimentalObjectRestSpread && + node.type === "ObjectExpression" + ) { + node.type = "ObjectPattern"; + + for (var i = 0; i < node.properties.length; i++) { + var prop = node.properties[i]; + + if (prop.type === "ExperimentalSpreadProperty") { + prop.type = "ExperimentalRestProperty"; + } else if (prop.kind !== "init") { + this.raise(prop.key.start, "Object pattern can't contain getter or setter"); + } else { + this.toAssignable(prop.value, isBinding); + } + } + + return node; + } else { + return toAssignable.call(this, node, isBinding); + } + }; + +}); + /** * Method to parse an object rest or object spread. * @returns {ASTNode} The node representing object rest or object spread. diff --git a/tests/fixtures/ecma-features/experimentalObjectRestSpread/destructuring-assign-mirror.result.js b/tests/fixtures/ecma-features/experimentalObjectRestSpread/destructuring-assign-mirror.result.js new file mode 100644 index 00000000..49acb2b8 --- /dev/null +++ b/tests/fixtures/ecma-features/experimentalObjectRestSpread/destructuring-assign-mirror.result.js @@ -0,0 +1,549 @@ +module.exports = { + "type": "Program", + "body": [ + { + "type": "ExpressionStatement", + "expression": { + "type": "AssignmentExpression", + "operator": "=", + "left": { + "type": "ObjectPattern", + "properties": [ + { + "type": "Property", + "key": { + "type": "Identifier", + "name": "a", + "range": [ + 2, + 3 + ], + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "value": { + "type": "Identifier", + "name": "a", + "range": [ + 2, + 3 + ], + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + "kind": "init", + "method": false, + "shorthand": true, + "computed": false, + "range": [ + 2, + 3 + ], + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "ExperimentalRestProperty", + "argument": { + "type": "Identifier", + "name": "b", + "range": [ + 8, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 1, + "column": 9 + } + } + }, + "range": [ + 5, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 9 + } + } + } + ], + "range": [ + 1, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 10 + } + } + }, + "right": { + "type": "ObjectExpression", + "properties": [ + { + "type": "Property", + "key": { + "type": "Identifier", + "name": "a", + "range": [ + 14, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + } + } + }, + "value": { + "type": "Identifier", + "name": "a", + "range": [ + 14, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + } + } + }, + "kind": "init", + "method": false, + "shorthand": true, + "computed": false, + "range": [ + 14, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + } + } + }, + { + "type": "ExperimentalSpreadProperty", + "argument": { + "type": "Identifier", + "name": "b", + "range": [ + 20, + 21 + ], + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 21 + } + } + }, + "range": [ + 17, + 21 + ], + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 21 + } + } + } + ], + "range": [ + 13, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 13 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + "range": [ + 1, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + "range": [ + 0, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + } + } + ], + "sourceType": "script", + "range": [ + 0, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 23 + } + }, + "tokens": [ + { + "type": "Punctuator", + "value": "(", + "range": [ + 0, + 1 + ], + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 1, + 2 + ], + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + } + }, + { + "type": "Identifier", + "value": "a", + "range": [ + 2, + 3 + ], + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 3 + } + } + }, + { + "type": "Punctuator", + "value": ",", + "range": [ + 3, + 4 + ], + "loc": { + "start": { + "line": 1, + "column": 3 + }, + "end": { + "line": 1, + "column": 4 + } + } + }, + { + "type": "Punctuator", + "value": "...", + "range": [ + 5, + 8 + ], + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 8 + } + } + }, + { + "type": "Identifier", + "value": "b", + "range": [ + 8, + 9 + ], + "loc": { + "start": { + "line": 1, + "column": 8 + }, + "end": { + "line": 1, + "column": 9 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 9, + 10 + ], + "loc": { + "start": { + "line": 1, + "column": 9 + }, + "end": { + "line": 1, + "column": 10 + } + } + }, + { + "type": "Punctuator", + "value": "=", + "range": [ + 11, + 12 + ], + "loc": { + "start": { + "line": 1, + "column": 11 + }, + "end": { + "line": 1, + "column": 12 + } + } + }, + { + "type": "Punctuator", + "value": "{", + "range": [ + 13, + 14 + ], + "loc": { + "start": { + "line": 1, + "column": 13 + }, + "end": { + "line": 1, + "column": 14 + } + } + }, + { + "type": "Identifier", + "value": "a", + "range": [ + 14, + 15 + ], + "loc": { + "start": { + "line": 1, + "column": 14 + }, + "end": { + "line": 1, + "column": 15 + } + } + }, + { + "type": "Punctuator", + "value": ",", + "range": [ + 15, + 16 + ], + "loc": { + "start": { + "line": 1, + "column": 15 + }, + "end": { + "line": 1, + "column": 16 + } + } + }, + { + "type": "Punctuator", + "value": "...", + "range": [ + 17, + 20 + ], + "loc": { + "start": { + "line": 1, + "column": 17 + }, + "end": { + "line": 1, + "column": 20 + } + } + }, + { + "type": "Identifier", + "value": "b", + "range": [ + 20, + 21 + ], + "loc": { + "start": { + "line": 1, + "column": 20 + }, + "end": { + "line": 1, + "column": 21 + } + } + }, + { + "type": "Punctuator", + "value": "}", + "range": [ + 21, + 22 + ], + "loc": { + "start": { + "line": 1, + "column": 21 + }, + "end": { + "line": 1, + "column": 22 + } + } + }, + { + "type": "Punctuator", + "value": ")", + "range": [ + 22, + 23 + ], + "loc": { + "start": { + "line": 1, + "column": 22 + }, + "end": { + "line": 1, + "column": 23 + } + } + } + ] +}; diff --git a/tests/fixtures/ecma-features/experimentalObjectRestSpread/destructuring-assign-mirror.src.js b/tests/fixtures/ecma-features/experimentalObjectRestSpread/destructuring-assign-mirror.src.js new file mode 100644 index 00000000..0caa3fab --- /dev/null +++ b/tests/fixtures/ecma-features/experimentalObjectRestSpread/destructuring-assign-mirror.src.js @@ -0,0 +1 @@ +({a, ...b} = {a, ...b}) diff --git a/tests/fixtures/ecma-features/experimentalObjectRestSpread/shorthand-method-args.result.js b/tests/fixtures/ecma-features/experimentalObjectRestSpread/shorthand-method-args.result.js new file mode 100644 index 00000000..bb091b07 --- /dev/null +++ b/tests/fixtures/ecma-features/experimentalObjectRestSpread/shorthand-method-args.result.js @@ -0,0 +1,626 @@ +module.exports = { + "type": "Program", + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 5, + "column": 3 + } + }, + "range": [0, 108], + "sourceType": "script", + "body": [ + { + "type": "ExpressionStatement", + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 5, + "column": 3 + } + }, + "expression": { + "type": "ObjectExpression", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 5, + "column": 1 + } + }, + "properties": [ + { + "type": "Property", + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 4, + "column": 5 + } + }, + "method": true, + "shorthand": false, + "computed": false, + "key": { + "type": "Identifier", + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "name": "initialize", + "range": [ + 7, + 17 + ], + }, + "kind": "init", + "value": { + "type": "FunctionExpression", + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 4, + "column": 5 + } + }, + "id": null, + "generator": false, + "expression": false, + "params": [ + { + "type": "ObjectPattern", + "loc": { + "start": { + "line": 2, + "column": 15 + }, + "end": { + "line": 2, + "column": 46 + } + }, + "properties": [ + { + "type": "Property", + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 23 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 23 + } + }, + "name": "someVar", + "range": [ + 19, + 26 + ], + }, + "kind": "init", + "value": { + "type": "Identifier", + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 23 + } + }, + "name": "someVar", + "range": [ + 19, + 26 + ], + }, + "range": [ + 19, + 26 + ], + }, + { + "type": "Property", + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "method": false, + "shorthand": true, + "computed": false, + "key": { + "type": "Identifier", + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "name": "otherVar", + "range": [ + 28, + 36 + ], + }, + "kind": "init", + "value": { + "type": "Identifier", + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "name": "otherVar", + "range": [ + 28, + 36 + ], + }, + "range": [ + 28, + 36 + ], + }, + { + "type": "ExperimentalRestProperty", + "loc": { + "start": { + "line": 2, + "column": 35 + }, + "end": { + "line": 2, + "column": 45 + } + }, + "argument": { + "type": "Identifier", + "loc": { + "start": { + "line": 2, + "column": 38 + }, + "end": { + "line": 2, + "column": 45 + } + }, + "name": "options", + "range": [ + 41, + 48 + ], + }, + "range": [ + 38, + 48 + ] + } + ], + "range": [ + 18, + 49 + ], + } + ], + "body": { + "type": "BlockStatement", + "loc": { + "start": { + "line": 2, + "column": 48 + }, + "end": { + "line": 4, + "column": 5 + } + }, + "body": [], + "range": [ + 51, + 104 + ], + }, + "range": [ + 17, + 104 + ], + }, + "range": [ + 7, + 104 + ], + } + ], + "range": [ + 1, + 106 + ], + }, + "range": [ + 0, + 108 + ], + } + ], + "tokens": [ + { + "type": "Punctuator", + "value": "(", + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "range": [ + 0, + 1 + ] + }, + { + "type": "Punctuator", + "value": "{", + "loc": { + "start": { + "line": 1, + "column": 1 + }, + "end": { + "line": 1, + "column": 2 + } + }, + "range": [ + 1, + 2 + ] + }, + { + "type": "Identifier", + "value": "initialize", + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 14 + } + }, + "range": [ + 7, + 17 + ] + }, + { + "type": "Punctuator", + "value": "(", + "loc": { + "start": { + "line": 2, + "column": 14 + }, + "end": { + "line": 2, + "column": 15 + } + }, + "range": [ + 17, + 18 + ] + }, + { + "type": "Punctuator", + "value": "{", + "loc": { + "start": { + "line": 2, + "column": 15 + }, + "end": { + "line": 2, + "column": 16 + } + }, + "range": [ + 18, + 19 + ] + }, + { + "type": "Identifier", + "value": "someVar", + "loc": { + "start": { + "line": 2, + "column": 16 + }, + "end": { + "line": 2, + "column": 23 + } + }, + "range": [ + 19, + 26 + ] + }, + { + "type": "Punctuator", + "value": ",", + "loc": { + "start": { + "line": 2, + "column": 23 + }, + "end": { + "line": 2, + "column": 24 + } + }, + "range": [ + 26, + 27 + ] + }, + { + "type": "Identifier", + "value": "otherVar", + "loc": { + "start": { + "line": 2, + "column": 25 + }, + "end": { + "line": 2, + "column": 33 + } + }, + "range": [ + 28, + 36 + ] + }, + { + "type": "Punctuator", + "value": ",", + "loc": { + "start": { + "line": 2, + "column": 33 + }, + "end": { + "line": 2, + "column": 34 + } + }, + "range": [ + 36, + 37 + ] + }, + { + "type": "Punctuator", + "value": "...", + "loc": { + "start": { + "line": 2, + "column": 35 + }, + "end": { + "line": 2, + "column": 38 + } + }, + "range": [ + 38, + 41 + ] + }, + { + "type": "Identifier", + "value": "options", + "loc": { + "start": { + "line": 2, + "column": 38 + }, + "end": { + "line": 2, + "column": 45 + } + }, + "range": [ + 41, + 48 + ] + }, + { + "type": "Punctuator", + "value": "}", + "loc": { + "start": { + "line": 2, + "column": 45 + }, + "end": { + "line": 2, + "column": 46 + } + }, + "range": [ + 48, + 49 + ] + }, + { + "type": "Punctuator", + "value": ")", + "loc": { + "start": { + "line": 2, + "column": 46 + }, + "end": { + "line": 2, + "column": 47 + } + }, + "range": [ + 49, + 50 + ] + }, + { + "type": "Punctuator", + "value": "{", + "loc": { + "start": { + "line": 2, + "column": 48 + }, + "end": { + "line": 2, + "column": 49 + } + }, + "range": [ + 51, + 52 + ] + }, + { + "type": "Punctuator", + "value": "}", + "loc": { + "start": { + "line": 4, + "column": 4 + }, + "end": { + "line": 4, + "column": 5 + } + }, + "range": [ + 103, + 104 + ] + }, + { + "type": "Punctuator", + "value": "}", + "loc": { + "start": { + "line": 5, + "column": 0 + }, + "end": { + "line": 5, + "column": 1 + } + }, + "range": [ + 105, + 106 + ] + }, + { + "type": "Punctuator", + "value": ")", + "loc": { + "start": { + "line": 5, + "column": 1 + }, + "end": { + "line": 5, + "column": 2 + } + }, + "range": [ + 106, + 107 + ] + }, + { + "type": "Punctuator", + "value": ";", + "loc": { + "start": { + "line": 5, + "column": 2 + }, + "end": { + "line": 5, + "column": 3 + } + }, + "range": [ + 107, + 108 + ] + } + ] +}; diff --git a/tests/fixtures/ecma-features/experimentalObjectRestSpread/shorthand-method-args.src.js b/tests/fixtures/ecma-features/experimentalObjectRestSpread/shorthand-method-args.src.js new file mode 100644 index 00000000..4247e4a5 --- /dev/null +++ b/tests/fixtures/ecma-features/experimentalObjectRestSpread/shorthand-method-args.src.js @@ -0,0 +1,5 @@ +({ + initialize({someVar, otherVar, ...options}) { + // ... do some stuff with options ... + } +}); diff --git a/tests/lib/ecma-features.js b/tests/lib/ecma-features.js index 47931581..7eac23ce 100644 --- a/tests/lib/ecma-features.js +++ b/tests/lib/ecma-features.js @@ -49,7 +49,7 @@ var testFiles = shelljs.find(FIXTURES_DIR).filter(function(filename) { }).map(function(filename) { return filename.substring(FIXTURES_DIR.length - 1, filename.length - 7); // strip off ".src.js" // }).filter(function(filename) { -// return /simple-new-target/.test(filename); +// return /experimental/.test(filename); }); diff --git a/tests/lib/tester.js b/tests/lib/tester.js index bcdcbb6f..6b94a383 100644 --- a/tests/lib/tester.js +++ b/tests/lib/tester.js @@ -78,6 +78,7 @@ module.exports = { } } + assert.deepEqual(result, expected); } };