diff --git a/packages/babel-parser/src/parser/error-message.js b/packages/babel-parser/src/parser/error-message.js index 0737323af392..363873efb5ec 100644 --- a/packages/babel-parser/src/parser/error-message.js +++ b/packages/babel-parser/src/parser/error-message.js @@ -126,6 +126,7 @@ export const ErrorMessages = Object.freeze({ "Record expressions starting with '{|' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'bar'", RecordExpressionHashIncorrectStartSyntaxType: "Record expressions starting with '#{' are only allowed when the 'syntaxType' option of the 'recordAndTuple' plugin is set to 'hash'", + RecordNoProto: "'__proto__' is not allowed in Record expressions", RestTrailingComma: "Unexpected trailing comma after rest element", SloppyFunction: "In non-strict mode code, functions can only be declared at top level, inside a block, or as the body of an if statement", diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index cee5d30bc0d2..d59223926640 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -74,12 +74,15 @@ export default class ExpressionParser extends LValParser { +takeDecorators: (node: N.HasDecorators) => void; */ - // Check if property __proto__ has been used more than once. + // For object literal, check if property __proto__ has been used more than once. // If the expression is a destructuring assignment, then __proto__ may appear // multiple times. Otherwise, __proto__ is a duplicated key. - checkDuplicatedProto( + // For record expression, check if property __proto__ exists but allows "__proto__" + + checkProto( prop: N.ObjectMember | N.SpreadElement, + isRecord: boolean, protoRef: { used: boolean }, refExpressionErrors: ?ExpressionErrors, ): void { @@ -88,16 +91,21 @@ export default class ExpressionParser extends LValParser { prop.type === "ObjectMethod" || prop.computed || // $FlowIgnore - prop.shorthand + (prop.shorthand && !isRecord) ) { return; } const key = prop.key; + const keyIsIdentifier = key.type === "Identifier"; // It is either an Identifier or a String/NumericLiteral - const name = key.type === "Identifier" ? key.name : String(key.value); + const name = keyIsIdentifier ? key.name : key.value; if (name === "__proto__") { + if (isRecord) { + if (keyIsIdentifier) this.raise(key.start, Errors.RecordNoProto); + return; + } if (protoRef.used) { if (refExpressionErrors) { // Store the first redefinition's position, otherwise ignore because @@ -1554,7 +1562,7 @@ export default class ExpressionParser extends LValParser { const prop = this.parseObjectMember(isPattern, refExpressionErrors); if (!isPattern) { // $FlowIgnore RestElement will never be returned if !isPattern - this.checkDuplicatedProto(prop, propHash, refExpressionErrors); + this.checkProto(prop, isRecord, propHash, refExpressionErrors); } if ( diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index f8021751dfcd..796e0d7e5293 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -143,8 +143,9 @@ export default (superClass: Class): Class => } } - checkDuplicatedProto( + checkProto( prop: N.ObjectMember | N.SpreadElement, + isRecord: boolean, protoRef: { used: boolean }, refExpressionErrors: ?ExpressionErrors, ): void { @@ -152,7 +153,7 @@ export default (superClass: Class): Class => if (prop.method) { return; } - super.checkDuplicatedProto(prop, protoRef, refExpressionErrors); + super.checkProto(prop, isRecord, protoRef, refExpressionErrors); } isValidDirective(stmt: N.Statement): boolean { diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-identifier/input.js b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-identifier/input.js new file mode 100644 index 000000000000..adc41ad4d9b8 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-identifier/input.js @@ -0,0 +1,3 @@ +#{ + __proto__: null +} diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-identifier/options.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-identifier/options.json new file mode 100644 index 000000000000..703c537be360 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-identifier/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["recordAndTuple", { "syntaxType": "hash" }]] +} diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-identifier/output.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-identifier/output.json new file mode 100644 index 000000000000..dfef90fb7e65 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-identifier/output.json @@ -0,0 +1,42 @@ +{ + "type": "File", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "errors": [ + "SyntaxError: '__proto__' is not allowed in Record expressions (2:2)" + ], + "program": { + "type": "Program", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "expression": { + "type": "RecordExpression", + "start":0,"end":22,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "properties": [ + { + "type": "ObjectProperty", + "start":5,"end":20,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":17}}, + "method": false, + "key": { + "type": "Identifier", + "start":5,"end":14,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":11},"identifierName":"__proto__"}, + "name": "__proto__" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "NullLiteral", + "start":16,"end":20,"loc":{"start":{"line":2,"column":13},"end":{"line":2,"column":17}} + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-shorthand/input.js b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-shorthand/input.js new file mode 100644 index 000000000000..b2f934a93b8d --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-shorthand/input.js @@ -0,0 +1,4 @@ +var __proto__; +#{ + __proto__ +} diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-shorthand/options.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-shorthand/options.json new file mode 100644 index 000000000000..703c537be360 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-shorthand/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["recordAndTuple", { "syntaxType": "hash" }]] +} diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-shorthand/output.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-shorthand/output.json new file mode 100644 index 000000000000..4bbb03bc273c --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/invalid-record-proto-shorthand/output.json @@ -0,0 +1,63 @@ +{ + "type": "File", + "start":0,"end":31,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "errors": [ + "SyntaxError: '__proto__' is not allowed in Record expressions (3:2)" + ], + "program": { + "type": "Program", + "start":0,"end":31,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "VariableDeclaration", + "start":0,"end":14,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":14}}, + "declarations": [ + { + "type": "VariableDeclarator", + "start":4,"end":13,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":13}}, + "id": { + "type": "Identifier", + "start":4,"end":13,"loc":{"start":{"line":1,"column":4},"end":{"line":1,"column":13},"identifierName":"__proto__"}, + "name": "__proto__" + }, + "init": null + } + ], + "kind": "var" + }, + { + "type": "ExpressionStatement", + "start":15,"end":31,"loc":{"start":{"line":2,"column":0},"end":{"line":4,"column":1}}, + "expression": { + "type": "RecordExpression", + "start":15,"end":31,"loc":{"start":{"line":2,"column":0},"end":{"line":4,"column":1}}, + "properties": [ + { + "type": "ObjectProperty", + "start":20,"end":29,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":11}}, + "method": false, + "key": { + "type": "Identifier", + "start":20,"end":29,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":11},"identifierName":"__proto__"}, + "name": "__proto__" + }, + "computed": false, + "shorthand": true, + "value": { + "type": "Identifier", + "start":20,"end":29,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":11},"identifierName":"__proto__"}, + "name": "__proto__" + }, + "extra": { + "shorthand": true + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/record-proto-string-literal/input.js b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/record-proto-string-literal/input.js new file mode 100644 index 000000000000..b632681d3d25 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/record-proto-string-literal/input.js @@ -0,0 +1,4 @@ +#{ + "__proto__": null, + "__proto__": null, +} diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/record-proto-string-literal/options.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/record-proto-string-literal/options.json new file mode 100644 index 000000000000..703c537be360 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/record-proto-string-literal/options.json @@ -0,0 +1,3 @@ +{ + "plugins": [["recordAndTuple", { "syntaxType": "hash" }]] +} diff --git a/packages/babel-parser/test/fixtures/experimental/record-and-tuple/record-proto-string-literal/output.json b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/record-proto-string-literal/output.json new file mode 100644 index 000000000000..dc814f7992f5 --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/record-and-tuple/record-proto-string-literal/output.json @@ -0,0 +1,66 @@ +{ + "type": "File", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ExpressionStatement", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "expression": { + "type": "RecordExpression", + "start":0,"end":46,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "properties": [ + { + "type": "ObjectProperty", + "start":5,"end":22,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":19}}, + "method": false, + "key": { + "type": "StringLiteral", + "start":5,"end":16,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":13}}, + "extra": { + "rawValue": "__proto__", + "raw": "\"__proto__\"" + }, + "value": "__proto__" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "NullLiteral", + "start":18,"end":22,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":19}} + } + }, + { + "type": "ObjectProperty", + "start":26,"end":43,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":19}}, + "method": false, + "key": { + "type": "StringLiteral", + "start":26,"end":37,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":13}}, + "extra": { + "rawValue": "__proto__", + "raw": "\"__proto__\"" + }, + "value": "__proto__" + }, + "computed": false, + "shorthand": false, + "value": { + "type": "NullLiteral", + "start":39,"end":43,"loc":{"start":{"line":3,"column":15},"end":{"line":3,"column":19}} + } + } + ], + "extra": { + "trailingComma": 43 + } + } + } + ], + "directives": [] + } +}