Skip to content

Commit

Permalink
fix: duplicate __proto__ keys should be allowed in patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
JLHwung committed Jan 11, 2020
1 parent 046c18c commit 880891a
Show file tree
Hide file tree
Showing 9 changed files with 483 additions and 17 deletions.
30 changes: 18 additions & 12 deletions packages/babel-parser/src/parser/expression.js
Expand Up @@ -70,7 +70,8 @@ export default class ExpressionParser extends LValParser {

checkDuplicatedProto(
prop: N.ObjectMember | N.SpreadElement,
protoRef: { used: boolean, start?: number },
protoRef: { used: boolean },
refExpressionErrors: ?ExpressionErrors,
): void {
if (
prop.type === "SpreadElement" ||
Expand All @@ -88,8 +89,12 @@ export default class ExpressionParser extends LValParser {

if (name === "__proto__") {
// Store the first redefinition's position
if (protoRef.used && !protoRef.start) {
protoRef.start = key.start;
if (protoRef.used) {
if (refExpressionErrors && refExpressionErrors.doubleProto === -1) {
refExpressionErrors.doubleProto = key.start;
} else {
this.raise(key.start, "Redefinition of __proto__ property");
}
}

protoRef.used = true;
Expand Down Expand Up @@ -203,9 +208,12 @@ export default class ExpressionParser extends LValParser {
if (operator === "||=" || operator === "&&=") {
this.expectPlugin("logicalAssignment");
}
node.left = this.match(tt.eq)
? this.toAssignable(left, undefined, "assignment expression")
: left;
if (this.match(tt.eq)) {
node.left = this.toAssignable(left, undefined, "assignment expression");
refExpressionErrors.doubleProto = -1; // reset because double __proto__ is valid in assignment expression
} else {
node.left = left;
}

if (refExpressionErrors.shorthandAssign >= node.left.start) {
refExpressionErrors.shorthandAssign = -1; // reset because shorthand default was used correctly
Expand Down Expand Up @@ -1513,8 +1521,10 @@ export default class ExpressionParser extends LValParser {
}

const prop = this.parseObjectMember(isPattern, refExpressionErrors);
// $FlowIgnore RestElement will never be returned if !isPattern
if (!isPattern) this.checkDuplicatedProto(prop, propHash);
if (!isPattern) {
// $FlowIgnore RestElement will never be returned if !isPattern
this.checkDuplicatedProto(prop, propHash, refExpressionErrors);
}

// $FlowIgnore
if (prop.shorthand) {
Expand All @@ -1524,10 +1534,6 @@ export default class ExpressionParser extends LValParser {
node.properties.push(prop);
}

if (!this.match(tt.eq) && propHash.start !== undefined) {
this.raise(propHash.start, "Redefinition of __proto__ property");
}

return this.finishNode(
node,
isPattern ? "ObjectPattern" : "ObjectExpression",
Expand Down
8 changes: 6 additions & 2 deletions packages/babel-parser/src/parser/util.js
Expand Up @@ -274,11 +274,14 @@ export default class UtilParser extends Tokenizer {
andThrow: boolean,
) {
if (!refExpressionErrors) return false;
const { shorthandAssign } = refExpressionErrors;
if (!andThrow) return shorthandAssign >= 0;
const { shorthandAssign, doubleProto } = refExpressionErrors;
if (!andThrow) return shorthandAssign >= 0 || doubleProto >= 0;
if (shorthandAssign >= 0) {
this.unexpected(shorthandAssign);
}
if (doubleProto >= 0) {
this.raise(doubleProto, "Redefinition of __proto__ property");
}
}
}

Expand All @@ -290,4 +293,5 @@ export default class UtilParser extends Tokenizer {
*/
export class ExpressionErrors {
shorthandAssign = -1;
doubleProto = -1;
}
11 changes: 8 additions & 3 deletions packages/babel-parser/src/plugins/estree.js
Expand Up @@ -149,7 +149,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>

checkDuplicatedProto(
prop: N.ObjectMember | N.SpreadElement,
protoRef: { used: boolean, start?: number },
protoRef: { used: boolean },
refExpressionErrors: ?ExpressionErrors,
): void {
if (
prop.type === "SpreadElement" ||
Expand All @@ -167,8 +168,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>

if (name === "__proto__" && prop.kind === "init") {
// Store the first redefinition's position
if (protoRef.used && !protoRef.start) {
protoRef.start = key.start;
if (protoRef.used) {
if (refExpressionErrors && refExpressionErrors.doubleProto === -1) {
refExpressionErrors.doubleProto = key.start;
} else {
this.raise(key.start, "Redefinition of __proto__ property");
}
}

protoRef.used = true;
Expand Down
@@ -0,0 +1 @@
([{ __proto__: x, __proto__: y }] = [{}]);
@@ -0,0 +1,241 @@
{
"type": "File",
"start": 0,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 42
}
},
"program": {
"type": "Program",
"start": 0,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 42
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 42,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 42
}
},
"expression": {
"type": "AssignmentExpression",
"start": 1,
"end": 40,
"loc": {
"start": {
"line": 1,
"column": 1
},
"end": {
"line": 1,
"column": 40
}
},
"operator": "=",
"left": {
"type": "ArrayPattern",
"start": 1,
"end": 33,
"loc": {
"start": {
"line": 1,
"column": 1
},
"end": {
"line": 1,
"column": 33
}
},
"elements": [
{
"type": "ObjectPattern",
"start": 2,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 2
},
"end": {
"line": 1,
"column": 32
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 4,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 16
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 4,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 4
},
"end": {
"line": 1,
"column": 13
},
"identifierName": "__proto__"
},
"name": "__proto__"
},
"computed": false,
"shorthand": false,
"value": {
"type": "Identifier",
"start": 15,
"end": 16,
"loc": {
"start": {
"line": 1,
"column": 15
},
"end": {
"line": 1,
"column": 16
},
"identifierName": "x"
},
"name": "x"
}
},
{
"type": "ObjectProperty",
"start": 18,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 30
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 18,
"end": 27,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 27
},
"identifierName": "__proto__"
},
"name": "__proto__"
},
"computed": false,
"shorthand": false,
"value": {
"type": "Identifier",
"start": 29,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 29
},
"end": {
"line": 1,
"column": 30
},
"identifierName": "y"
},
"name": "y"
}
}
]
}
]
},
"right": {
"type": "ArrayExpression",
"start": 36,
"end": 40,
"loc": {
"start": {
"line": 1,
"column": 36
},
"end": {
"line": 1,
"column": 40
}
},
"elements": [
{
"type": "ObjectExpression",
"start": 37,
"end": 39,
"loc": {
"start": {
"line": 1,
"column": 37
},
"end": {
"line": 1,
"column": 39
}
},
"properties": []
}
]
},
"extra": {
"parenthesized": true,
"parenStart": 0
}
}
}
],
"directives": []
}
}
@@ -0,0 +1 @@
({ __proto__: x, __proto__: y }) => {};

0 comments on commit 880891a

Please sign in to comment.