Disallow private name in object elements and TS type elements (#10980)

* fix: disallow private name in object member and TS type elements

* chore: update test262 whitelist

* chore: make flow happy

* Update packages/babel-parser/src/parser/expression.js

Co-Authored-By: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>

* chore: update test fixtures

* Update packages/babel-parser/src/parser/expression.js

Co-Authored-By: Brian Ng <bng412@gmail.com>

* chore: update test fixtures

Co-authored-by: Nicolò Ribaudo <nicolo.ribaudo@gmail.com>
Co-authored-by: Brian Ng <bng412@gmail.com>
This commit is contained in:
Huáng Jùnliàng 2020-01-11 11:26:10 -05:00 committed by GitHub
parent e7b80a2cb9
commit 81c5f1f22d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1106 additions and 25 deletions

View File

@ -606,7 +606,7 @@ export default class ExpressionParser extends LValParser {
? this.parseExpression()
: optional
? this.parseIdentifier(true)
: this.parseMaybePrivateName();
: this.parseMaybePrivateName(true);
node.computed = computed;
if (node.property.type === "PrivateName") {
@ -1131,11 +1131,19 @@ export default class ExpressionParser extends LValParser {
return this.finishNode(node, "BooleanLiteral");
}
parseMaybePrivateName(): N.PrivateName | N.Identifier {
parseMaybePrivateName(
isPrivateNameAllowed: boolean,
): N.PrivateName | N.Identifier {
const isPrivate = this.match(tt.hash);
if (isPrivate) {
this.expectOnePlugin(["classPrivateProperties", "classPrivateMethods"]);
if (!isPrivateNameAllowed) {
this.raise(
this.state.pos,
"Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p).",
);
}
const node = this.startNode();
this.next();
this.assertNoSpace("Unexpected space between # and identifier");
@ -1596,12 +1604,12 @@ export default class ExpressionParser extends LValParser {
}
const containsEsc = this.state.containsEsc;
this.parsePropertyName(prop);
this.parsePropertyName(prop, /* isPrivateNameAllowed */ false);
if (!isPattern && !containsEsc && !isGenerator && this.isAsyncProp(prop)) {
isAsync = true;
isGenerator = this.eat(tt.star);
this.parsePropertyName(prop);
this.parsePropertyName(prop, /* isPrivateNameAllowed */ false);
} else {
isAsync = false;
}
@ -1688,7 +1696,7 @@ export default class ExpressionParser extends LValParser {
if (!containsEsc && this.isGetterOrSetterMethod(prop, isPattern)) {
if (isGenerator || isAsync) this.unexpected();
prop.kind = prop.key.name;
this.parsePropertyName(prop);
this.parsePropertyName(prop, /* isPrivateNameAllowed */ false);
this.parseMethod(
prop,
/* isGenerator */ false,
@ -1780,6 +1788,7 @@ export default class ExpressionParser extends LValParser {
parsePropertyName(
prop: N.ObjectOrClassMember | N.ClassMember | N.TsNamedTypeElementBase,
isPrivateNameAllowed: boolean,
): N.Expression | N.Identifier {
if (this.eat(tt.bracketL)) {
(prop: $FlowSubtype<N.ObjectOrClassMember>).computed = true;
@ -1792,7 +1801,7 @@ export default class ExpressionParser extends LValParser {
(prop: $FlowFixMe).key =
this.match(tt.num) || this.match(tt.string) || this.match(tt.bigint)
? this.parseExprAtom()
: this.parseMaybePrivateName();
: this.parseMaybePrivateName(isPrivateNameAllowed);
if (prop.key.type !== "PrivateName") {
// ClassPrivateProperty is never computed, so we don't assign in that case.

View File

@ -1474,7 +1474,7 @@ export default class StatementParser extends ExpressionParser {
}
parseClassPropertyName(member: N.ClassMember): N.Expression | N.Identifier {
const key = this.parsePropertyName(member);
const key = this.parsePropertyName(member, /* isPrivateNameAllowed */ true);
if (
!member.computed &&

View File

@ -2266,9 +2266,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
parsePropertyName(
node: N.ObjectOrClassMember | N.ClassMember | N.TsNamedTypeElementBase,
isPrivateNameAllowed: boolean,
): N.Identifier {
const variance = this.flowParseVariance();
const key = super.parsePropertyName(node);
const key = super.parsePropertyName(node, isPrivateNameAllowed);
// $FlowIgnore ("variance" not defined on TsNamedTypeElementBase)
node.variance = variance;
return key;

View File

@ -507,7 +507,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return idx;
}
this.parsePropertyName(node);
this.parsePropertyName(node, /* isPrivateNameAllowed */ false);
return this.tsParsePropertyOrMethodSignature(node, readonly);
}

View File

@ -0,0 +1,4 @@
class C {
#x = 1;
#p = ({ #x: x }) => {}
}

View File

@ -0,0 +1,3 @@
{
"plugins": ["classPrivateProperties"]
}

View File

@ -0,0 +1,324 @@
{
"type": "File",
"start": 0,
"end": 46,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 4,
"column": 1
}
},
"errors": [
"SyntaxError: Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p). (3:11)"
],
"program": {
"type": "Program",
"start": 0,
"end": 46,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 4,
"column": 1
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start": 0,
"end": 46,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 4,
"column": 1
}
},
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 7
},
"identifierName": "C"
},
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start": 8,
"end": 46,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 4,
"column": 1
}
},
"body": [
{
"type": "ClassPrivateProperty",
"start": 12,
"end": 19,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 9
}
},
"static": false,
"key": {
"type": "PrivateName",
"start": 12,
"end": 14,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 4
}
},
"id": {
"type": "Identifier",
"start": 13,
"end": 14,
"loc": {
"start": {
"line": 2,
"column": 3
},
"end": {
"line": 2,
"column": 4
},
"identifierName": "x"
},
"name": "x"
}
},
"value": {
"type": "NumericLiteral",
"start": 17,
"end": 18,
"loc": {
"start": {
"line": 2,
"column": 7
},
"end": {
"line": 2,
"column": 8
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
},
{
"type": "ClassPrivateProperty",
"start": 22,
"end": 44,
"loc": {
"start": {
"line": 3,
"column": 2
},
"end": {
"line": 3,
"column": 24
}
},
"static": false,
"key": {
"type": "PrivateName",
"start": 22,
"end": 24,
"loc": {
"start": {
"line": 3,
"column": 2
},
"end": {
"line": 3,
"column": 4
}
},
"id": {
"type": "Identifier",
"start": 23,
"end": 24,
"loc": {
"start": {
"line": 3,
"column": 3
},
"end": {
"line": 3,
"column": 4
},
"identifierName": "p"
},
"name": "p"
}
},
"value": {
"type": "ArrowFunctionExpression",
"start": 27,
"end": 44,
"loc": {
"start": {
"line": 3,
"column": 7
},
"end": {
"line": 3,
"column": 24
}
},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "ObjectPattern",
"start": 28,
"end": 37,
"loc": {
"start": {
"line": 3,
"column": 8
},
"end": {
"line": 3,
"column": 17
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 30,
"end": 35,
"loc": {
"start": {
"line": 3,
"column": 10
},
"end": {
"line": 3,
"column": 15
}
},
"method": false,
"key": {
"type": "PrivateName",
"start": 30,
"end": 32,
"loc": {
"start": {
"line": 3,
"column": 10
},
"end": {
"line": 3,
"column": 12
}
},
"id": {
"type": "Identifier",
"start": 31,
"end": 32,
"loc": {
"start": {
"line": 3,
"column": 11
},
"end": {
"line": 3,
"column": 12
},
"identifierName": "x"
},
"name": "x"
}
},
"shorthand": false,
"value": {
"type": "Identifier",
"start": 34,
"end": 35,
"loc": {
"start": {
"line": 3,
"column": 14
},
"end": {
"line": 3,
"column": 15
},
"identifierName": "x"
},
"name": "x"
}
}
]
}
],
"body": {
"type": "BlockStatement",
"start": 42,
"end": 44,
"loc": {
"start": {
"line": 3,
"column": 22
},
"end": {
"line": 3,
"column": 24
}
},
"body": [],
"directives": []
}
}
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,6 @@
class C {
#x = 1;
m() {
const {#x: x} = this;
}
}

View File

@ -0,0 +1,3 @@
{
"plugins": ["classPrivateProperties"]
}

View File

@ -0,0 +1,344 @@
{
"type": "File",
"start": 0,
"end": 59,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"column": 1
}
},
"errors": [
"SyntaxError: Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p). (4:12)"
],
"program": {
"type": "Program",
"start": 0,
"end": 59,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"column": 1
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start": 0,
"end": 59,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 6,
"column": 1
}
},
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 7
},
"identifierName": "C"
},
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start": 8,
"end": 59,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 6,
"column": 1
}
},
"body": [
{
"type": "ClassPrivateProperty",
"start": 12,
"end": 19,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 9
}
},
"static": false,
"key": {
"type": "PrivateName",
"start": 12,
"end": 14,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 4
}
},
"id": {
"type": "Identifier",
"start": 13,
"end": 14,
"loc": {
"start": {
"line": 2,
"column": 3
},
"end": {
"line": 2,
"column": 4
},
"identifierName": "x"
},
"name": "x"
}
},
"value": {
"type": "NumericLiteral",
"start": 17,
"end": 18,
"loc": {
"start": {
"line": 2,
"column": 7
},
"end": {
"line": 2,
"column": 8
}
},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
}
},
{
"type": "ClassMethod",
"start": 22,
"end": 57,
"loc": {
"start": {
"line": 3,
"column": 2
},
"end": {
"line": 5,
"column": 3
}
},
"static": false,
"key": {
"type": "Identifier",
"start": 22,
"end": 23,
"loc": {
"start": {
"line": 3,
"column": 2
},
"end": {
"line": 3,
"column": 3
},
"identifierName": "m"
},
"name": "m"
},
"computed": false,
"kind": "method",
"id": null,
"generator": false,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 26,
"end": 57,
"loc": {
"start": {
"line": 3,
"column": 6
},
"end": {
"line": 5,
"column": 3
}
},
"body": [
{
"type": "VariableDeclaration",
"start": 32,
"end": 53,
"loc": {
"start": {
"line": 4,
"column": 4
},
"end": {
"line": 4,
"column": 25
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 38,
"end": 52,
"loc": {
"start": {
"line": 4,
"column": 10
},
"end": {
"line": 4,
"column": 24
}
},
"id": {
"type": "ObjectPattern",
"start": 38,
"end": 45,
"loc": {
"start": {
"line": 4,
"column": 10
},
"end": {
"line": 4,
"column": 17
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 39,
"end": 44,
"loc": {
"start": {
"line": 4,
"column": 11
},
"end": {
"line": 4,
"column": 16
}
},
"method": false,
"key": {
"type": "PrivateName",
"start": 39,
"end": 41,
"loc": {
"start": {
"line": 4,
"column": 11
},
"end": {
"line": 4,
"column": 13
}
},
"id": {
"type": "Identifier",
"start": 40,
"end": 41,
"loc": {
"start": {
"line": 4,
"column": 12
},
"end": {
"line": 4,
"column": 13
},
"identifierName": "x"
},
"name": "x"
}
},
"shorthand": false,
"value": {
"type": "Identifier",
"start": 43,
"end": 44,
"loc": {
"start": {
"line": 4,
"column": 15
},
"end": {
"line": 4,
"column": 16
},
"identifierName": "x"
},
"name": "x"
}
}
]
},
"init": {
"type": "ThisExpression",
"start": 48,
"end": 52,
"loc": {
"start": {
"line": 4,
"column": 20
},
"end": {
"line": 4,
"column": 24
}
}
}
}
],
"kind": "const"
}
],
"directives": []
}
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
class C {
#p = ({ #x: 42 });
}

View File

@ -0,0 +1,3 @@
{
"plugins": ["classPrivateProperties"]
}

View File

@ -0,0 +1,226 @@
{
"type": "File",
"start": 0,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"errors": [
"SyntaxError: Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p). (2:11)"
],
"program": {
"type": "Program",
"start": 0,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ClassDeclaration",
"start": 0,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"id": {
"type": "Identifier",
"start": 6,
"end": 7,
"loc": {
"start": {
"line": 1,
"column": 6
},
"end": {
"line": 1,
"column": 7
},
"identifierName": "C"
},
"name": "C"
},
"superClass": null,
"body": {
"type": "ClassBody",
"start": 8,
"end": 32,
"loc": {
"start": {
"line": 1,
"column": 8
},
"end": {
"line": 3,
"column": 1
}
},
"body": [
{
"type": "ClassPrivateProperty",
"start": 12,
"end": 30,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 20
}
},
"static": false,
"key": {
"type": "PrivateName",
"start": 12,
"end": 14,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 4
}
},
"id": {
"type": "Identifier",
"start": 13,
"end": 14,
"loc": {
"start": {
"line": 2,
"column": 3
},
"end": {
"line": 2,
"column": 4
},
"identifierName": "p"
},
"name": "p"
}
},
"value": {
"type": "ObjectExpression",
"start": 18,
"end": 28,
"loc": {
"start": {
"line": 2,
"column": 8
},
"end": {
"line": 2,
"column": 18
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 20,
"end": 26,
"loc": {
"start": {
"line": 2,
"column": 10
},
"end": {
"line": 2,
"column": 16
}
},
"method": false,
"key": {
"type": "PrivateName",
"start": 20,
"end": 22,
"loc": {
"start": {
"line": 2,
"column": 10
},
"end": {
"line": 2,
"column": 12
}
},
"id": {
"type": "Identifier",
"start": 21,
"end": 22,
"loc": {
"start": {
"line": 2,
"column": 11
},
"end": {
"line": 2,
"column": 12
},
"identifierName": "x"
},
"name": "x"
}
},
"shorthand": false,
"value": {
"type": "NumericLiteral",
"start": 24,
"end": 26,
"loc": {
"start": {
"line": 2,
"column": 14
},
"end": {
"line": 2,
"column": 16
}
},
"extra": {
"rawValue": 42,
"raw": "42"
},
"value": 42
}
}
],
"extra": {
"parenthesized": true,
"parenStart": 17
}
}
}
]
}
}
],
"directives": []
}
}

View File

@ -0,0 +1,3 @@
interface I {
#p: string
}

View File

@ -0,0 +1,3 @@
{
"plugins": ["classPrivateProperties", "typescript"]
}

View File

@ -0,0 +1,164 @@
{
"type": "File",
"start": 0,
"end": 28,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"errors": [
"SyntaxError: Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p). (2:3)"
],
"program": {
"type": "Program",
"start": 0,
"end": 28,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "TSInterfaceDeclaration",
"start": 0,
"end": 28,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"id": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "I"
},
"name": "I"
},
"body": {
"type": "TSInterfaceBody",
"start": 12,
"end": 28,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 3,
"column": 1
}
},
"body": [
{
"type": "TSPropertySignature",
"start": 16,
"end": 26,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 12
}
},
"key": {
"type": "PrivateName",
"start": 16,
"end": 18,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 4
}
},
"id": {
"type": "Identifier",
"start": 17,
"end": 18,
"loc": {
"start": {
"line": 2,
"column": 3
},
"end": {
"line": 2,
"column": 4
},
"identifierName": "p"
},
"name": "p"
}
},
"typeAnnotation": {
"type": "TSTypeAnnotation",
"start": 18,
"end": 26,
"loc": {
"start": {
"line": 2,
"column": 4
},
"end": {
"line": 2,
"column": 12
}
},
"typeAnnotation": {
"type": "TSStringKeyword",
"start": 20,
"end": 26,
"loc": {
"start": {
"line": 2,
"column": 6
},
"end": {
"line": 2,
"column": 12
}
}
}
}
}
]
}
}
],
"directives": []
}
}

View File

@ -1,16 +1 @@
language/expressions/class/elements/syntax/early-errors/grammar-private-field-on-object-destructuring.js(default)
language/expressions/class/elements/syntax/early-errors/grammar-private-field-on-object-destructuring.js(strict mode)
language/expressions/object/method-definition/private-name-early-error-async-gen-inside-class.js(default)
language/expressions/object/method-definition/private-name-early-error-async-gen-inside-class.js(strict mode)
language/expressions/object/method-definition/private-name-early-error-async-gen.js(default)
language/expressions/object/method-definition/private-name-early-error-async-gen.js(strict mode)
language/expressions/object/method-definition/private-name-early-error-gen-inside-class.js(default)
language/expressions/object/method-definition/private-name-early-error-gen-inside-class.js(strict mode)
language/expressions/object/method-definition/private-name-early-error-gen.js(default)
language/expressions/object/method-definition/private-name-early-error-gen.js(strict mode)
language/expressions/object/method-definition/private-name-early-error-method-inside-class.js(default)
language/expressions/object/method-definition/private-name-early-error-method-inside-class.js(strict mode)
language/expressions/object/method-definition/private-name-early-error-method.js(default)
language/expressions/object/method-definition/private-name-early-error-method.js(strict mode)
language/statements/class/elements/syntax/early-errors/grammar-private-field-on-object-destructuring.js(default)
language/statements/class/elements/syntax/early-errors/grammar-private-field-on-object-destructuring.js(strict mode)