Extract 'parseClassMember' method (#533)
This commit is contained in:
parent
aad95c63ec
commit
50694f99b1
@ -887,7 +887,7 @@ export default class ExpressionParser extends LValParser {
|
|||||||
|
|
||||||
// get methods aren't allowed to have any parameters
|
// get methods aren't allowed to have any parameters
|
||||||
// set methods must have exactly 1 parameter
|
// set methods must have exactly 1 parameter
|
||||||
checkGetterSetterParamCount(method: N.ObjectMethod): void {
|
checkGetterSetterParamCount(method: N.ObjectMethod | N.ClassMethod): void {
|
||||||
const paramCount = method.kind === "get" ? 0 : 1;
|
const paramCount = method.kind === "get" ? 0 : 1;
|
||||||
if (method.params.length !== paramCount) {
|
if (method.params.length !== paramCount) {
|
||||||
const start = method.start;
|
const start = method.start;
|
||||||
@ -956,12 +956,14 @@ export default class ExpressionParser extends LValParser {
|
|||||||
if (!node) this.unexpected();
|
if (!node) this.unexpected();
|
||||||
}
|
}
|
||||||
|
|
||||||
parsePropertyName(prop: N.ObjectMember): N.Identifier {
|
parsePropertyName(prop: N.ObjectOrClassMember): N.Identifier {
|
||||||
if (this.eat(tt.bracketL)) {
|
if (this.eat(tt.bracketL)) {
|
||||||
|
// $FlowFixMe (ClassPrivateMember shouldn't be allowed to be computed!)
|
||||||
prop.computed = true;
|
prop.computed = true;
|
||||||
prop.key = this.parseMaybeAssign();
|
prop.key = this.parseMaybeAssign();
|
||||||
this.expect(tt.bracketR);
|
this.expect(tt.bracketR);
|
||||||
} else {
|
} else {
|
||||||
|
// $FlowFixMe (ClassPrivateMember shouldn't be allowed to be computed!)
|
||||||
prop.computed = false;
|
prop.computed = false;
|
||||||
const oldInPropertyName = this.state.inPropertyName;
|
const oldInPropertyName = this.state.inPropertyName;
|
||||||
this.state.inPropertyName = true;
|
this.state.inPropertyName = true;
|
||||||
|
|||||||
@ -639,9 +639,11 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
return this.match(tt.parenL);
|
return this.match(tt.parenL);
|
||||||
}
|
}
|
||||||
|
|
||||||
isNonstaticConstructor(method: N.ClassMethod): boolean {
|
isNonstaticConstructor(method: N.ClassMethod | N.ClassProperty): boolean {
|
||||||
return !method.computed && !method.static && (
|
return !method.computed && !method.static && (
|
||||||
|
// $FlowFixMe ('key' downcasting)
|
||||||
(method.key.name === "constructor") || // Identifier
|
(method.key.name === "constructor") || // Identifier
|
||||||
|
// $FlowFixMe ('key' downcasting)
|
||||||
(method.key.value === "constructor") // Literal
|
(method.key.value === "constructor") // Literal
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -652,7 +654,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
this.state.strict = true;
|
this.state.strict = true;
|
||||||
this.state.inClass = true;
|
this.state.inClass = true;
|
||||||
|
|
||||||
let hadConstructor = false;
|
const state = { hadConstructor: false };
|
||||||
let decorators = [];
|
let decorators = [];
|
||||||
const classBody = this.startNode();
|
const classBody = this.startNode();
|
||||||
|
|
||||||
@ -673,22 +675,43 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const method = this.startNode();
|
const member = this.startNode();
|
||||||
|
|
||||||
// steal the decorators if there are any
|
// steal the decorators if there are any
|
||||||
if (decorators.length) {
|
if (decorators.length) {
|
||||||
method.decorators = decorators;
|
member.decorators = decorators;
|
||||||
decorators = [];
|
decorators = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasPlugin("classPrivateProperties") && this.match(tt.hash)) { // Private property
|
this.parseClassMember(classBody, member, state);
|
||||||
this.next();
|
|
||||||
this.parsePropertyName(method);
|
|
||||||
classBody.body.push(this.parsePrivateClassProperty(method));
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
method.static = false;
|
if (decorators.length) {
|
||||||
|
this.raise(this.state.start, "You have trailing decorators with no method");
|
||||||
|
}
|
||||||
|
|
||||||
|
node.body = this.finishNode(classBody, "ClassBody");
|
||||||
|
|
||||||
|
this.state.inClass = false;
|
||||||
|
this.state.strict = oldStrict;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseClassMember(classBody: N.ClassBody, member: N.ClassMember, state: { hadConstructor: boolean }): void {
|
||||||
|
// Use the appropriate variable to represent `member` once a more specific type is known.
|
||||||
|
const memberAny: any = member;
|
||||||
|
const methodOrProp: N.ClassMethod | N.ClassProperty = memberAny;
|
||||||
|
const method: N.ClassMethod = memberAny;
|
||||||
|
const prop: N.ClassProperty = memberAny;
|
||||||
|
|
||||||
|
if (this.hasPlugin("classPrivateProperties") && this.match(tt.hash)) { // Private property
|
||||||
|
this.next();
|
||||||
|
const privateProp: N.ClassPrivateProperty = memberAny;
|
||||||
|
this.parsePropertyName(privateProp);
|
||||||
|
classBody.body.push(this.parsePrivateClassProperty(privateProp));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
methodOrProp.static = false;
|
||||||
if (this.match(tt.name) && this.state.value === "static") {
|
if (this.match(tt.name) && this.state.value === "static") {
|
||||||
const key = this.parseIdentifier(true); // eats 'static'
|
const key = this.parseIdentifier(true); // eats 'static'
|
||||||
if (this.isClassMethod()) {
|
if (this.isClassMethod()) {
|
||||||
@ -697,16 +720,16 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
method.computed = false;
|
method.computed = false;
|
||||||
method.key = key;
|
method.key = key;
|
||||||
this.parseClassMethod(classBody, method, false, false);
|
this.parseClassMethod(classBody, method, false, false);
|
||||||
continue;
|
return;
|
||||||
} else if (this.isClassProperty()) {
|
} else if (this.isClassProperty()) {
|
||||||
// a property named 'static'
|
// a property named 'static'
|
||||||
method.computed = false;
|
prop.computed = false;
|
||||||
method.key = key;
|
prop.key = key;
|
||||||
classBody.body.push(this.parseClassProperty(method));
|
classBody.body.push(this.parseClassProperty(prop));
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
// otherwise something static
|
// otherwise something static
|
||||||
method.static = true;
|
methodOrProp.static = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.eat(tt.star)) {
|
if (this.eat(tt.star)) {
|
||||||
@ -720,21 +743,24 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
this.raise(method.key.start, "Classes may not have static property named prototype");
|
this.raise(method.key.start, "Classes may not have static property named prototype");
|
||||||
}
|
}
|
||||||
this.parseClassMethod(classBody, method, true, false);
|
this.parseClassMethod(classBody, method, true, false);
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isSimple = this.match(tt.name);
|
const isSimple = this.match(tt.name);
|
||||||
const key = this.parsePropertyName(method);
|
const key = this.parsePropertyName(methodOrProp);
|
||||||
if (!method.computed && method.static && (method.key.name === "prototype" || method.key.value === "prototype")) {
|
// $FlowFixMe ('key' downcasting)
|
||||||
this.raise(method.key.start, "Classes may not have static property named prototype");
|
if (!methodOrProp.computed && methodOrProp.static && (methodOrProp.key.name === "prototype" || methodOrProp.key.value === "prototype")) {
|
||||||
|
this.raise(methodOrProp.key.start, "Classes may not have static property named prototype");
|
||||||
}
|
}
|
||||||
if (this.isClassMethod()) {
|
if (this.isClassMethod()) {
|
||||||
// a normal method
|
// a normal method
|
||||||
if (this.isNonstaticConstructor(method)) {
|
if (this.isNonstaticConstructor(method)) {
|
||||||
if (hadConstructor) {
|
if (state.hadConstructor) {
|
||||||
this.raise(key.start, "Duplicate constructor in the same class");
|
this.raise(key.start, "Duplicate constructor in the same class");
|
||||||
} else if (method.decorators) {
|
} else if (method.decorators) {
|
||||||
this.raise(method.start, "You can't attach decorators to a class constructor");
|
this.raise(method.start, "You can't attach decorators to a class constructor");
|
||||||
}
|
}
|
||||||
hadConstructor = true;
|
state.hadConstructor = true;
|
||||||
method.kind = "constructor";
|
method.kind = "constructor";
|
||||||
} else {
|
} else {
|
||||||
method.kind = "method";
|
method.kind = "method";
|
||||||
@ -742,10 +768,10 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
this.parseClassMethod(classBody, method, false, false);
|
this.parseClassMethod(classBody, method, false, false);
|
||||||
} else if (this.isClassProperty()) {
|
} else if (this.isClassProperty()) {
|
||||||
// a normal property
|
// a normal property
|
||||||
if (this.isNonstaticConstructor(method)) {
|
if (this.isNonstaticConstructor(prop)) {
|
||||||
this.raise(method.key.start, "Classes may not have a non-static field named 'constructor'");
|
this.raise(prop.key.start, "Classes may not have a non-static field named 'constructor'");
|
||||||
}
|
}
|
||||||
classBody.body.push(this.parseClassProperty(method));
|
classBody.body.push(this.parseClassProperty(prop));
|
||||||
} else if (isSimple && key.name === "async" && !this.isLineTerminator()) {
|
} else if (isSimple && key.name === "async" && !this.isLineTerminator()) {
|
||||||
// an async method
|
// an async method
|
||||||
const isGenerator = this.hasPlugin("asyncGenerators") && this.eat(tt.star);
|
const isGenerator = this.hasPlugin("asyncGenerators") && this.eat(tt.star);
|
||||||
@ -766,26 +792,14 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
this.checkGetterSetterParamCount(method);
|
this.checkGetterSetterParamCount(method);
|
||||||
} else if (this.isLineTerminator()) {
|
} else if (this.isLineTerminator()) {
|
||||||
// an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
|
// an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
|
||||||
if (this.isNonstaticConstructor(method)) {
|
if (this.isNonstaticConstructor(prop)) {
|
||||||
this.raise(method.key.start, "Classes may not have a non-static field named 'constructor'");
|
this.raise(prop.key.start, "Classes may not have a non-static field named 'constructor'");
|
||||||
}
|
}
|
||||||
classBody.body.push(this.parseClassProperty(method));
|
classBody.body.push(this.parseClassProperty(prop));
|
||||||
} else {
|
} else {
|
||||||
this.unexpected();
|
this.unexpected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (decorators.length) {
|
|
||||||
this.raise(this.state.start, "You have trailing decorators with no method");
|
|
||||||
}
|
|
||||||
|
|
||||||
node.body = this.finishNode(classBody, "ClassBody");
|
|
||||||
|
|
||||||
this.state.inClass = false;
|
|
||||||
this.state.strict = oldStrict;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
parsePrivateClassProperty(node: N.ClassPrivateProperty): N.ClassPrivateProperty {
|
parsePrivateClassProperty(node: N.ClassPrivateProperty): N.ClassPrivateProperty {
|
||||||
this.state.inClassProperty = true;
|
this.state.inClassProperty = true;
|
||||||
|
|||||||
@ -59,8 +59,9 @@ export default (superClass: Class<Parser>): Class<Parser> => class extends super
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkGetterSetterParamCount(prop: N.ObjectMethod): void {
|
checkGetterSetterParamCount(prop: N.ObjectMethod | N.ClassMethod): void {
|
||||||
const paramCount = prop.kind === "get" ? 0 : 1;
|
const paramCount = prop.kind === "get" ? 0 : 1;
|
||||||
|
// $FlowFixMe (prop.value present for ObjectMethod, but for ClassMethod should use prop.params?)
|
||||||
if (prop.value.params.length !== paramCount) {
|
if (prop.value.params.length !== paramCount) {
|
||||||
const start = prop.start;
|
const start = prop.start;
|
||||||
if (prop.kind === "get") {
|
if (prop.kind === "get") {
|
||||||
|
|||||||
@ -1242,7 +1242,7 @@ export default (superClass: Class<Parser>): Class<Parser> => class extends super
|
|||||||
return this.match(tt.colon) || super.isClassProperty();
|
return this.match(tt.colon) || super.isClassProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
isNonstaticConstructor(method: N.ClassMethod): boolean {
|
isNonstaticConstructor(method: N.ClassMethod | N.ClassProperty): boolean {
|
||||||
return !this.match(tt.colon) && super.isNonstaticConstructor(method);
|
return !this.match(tt.colon) && super.isNonstaticConstructor(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1281,9 +1281,10 @@ export default (superClass: Class<Parser>): Class<Parser> => class extends super
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parsePropertyName(node: N.ObjectMember): N.Identifier {
|
parsePropertyName(node: N.ObjectOrClassMember): N.Identifier {
|
||||||
const variance = this.flowParseVariance();
|
const variance = this.flowParseVariance();
|
||||||
const key = super.parsePropertyName(node);
|
const key = super.parsePropertyName(node);
|
||||||
|
// $FlowFixMe (variance not defined on ClassPrivateProperty)
|
||||||
node.variance = variance;
|
node.variance = variance;
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user