Add asserts this [is type] parsing support (#10677)

This commit is contained in:
Huáng Jùnliàng
2019-11-11 17:36:10 -05:00
committed by Brian Ng
parent 4cb5e0a013
commit d413a3078c
14 changed files with 1087 additions and 20 deletions

View File

@@ -680,6 +680,15 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishNode(node, "TSLiteralType");
}
tsParseThisTypeOrThisTypePredicate(): N.TsThisType | N.TsTypePredicate {
const thisKeyword = this.tsParseThisTypeNode();
if (this.isContextual("is") && !this.hasPrecedingLineBreak()) {
return this.tsParseThisTypePredicate(thisKeyword);
} else {
return thisKeyword;
}
}
tsParseNonArrayType(): N.TsType {
switch (this.state.type) {
case tt.name:
@@ -715,14 +724,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishNode(node, "TSLiteralType");
}
break;
case tt._this: {
const thisKeyword = this.tsParseThisTypeNode();
if (this.isContextual("is") && !this.hasPrecedingLineBreak()) {
return this.tsParseThisTypePredicate(thisKeyword);
} else {
return thisKeyword;
}
}
case tt._this:
return this.tsParseThisTypeOrThisTypePredicate();
case tt._typeof:
return this.tsParseTypeQuery();
case tt._import:
@@ -937,6 +940,24 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.tsParseTypePredicateAsserts.bind(this),
);
if (asserts && this.match(tt._this)) {
// When asserts is false, thisKeyword is handled by tsParseNonArrayType
// : asserts this is type
let thisTypePredicate = this.tsParseThisTypeOrThisTypePredicate();
// if it turns out to be a `TSThisType`, wrap it with `TSTypePredicate`
// : asserts this
if (thisTypePredicate.type === "TSThisType") {
const node: N.TsTypePredicate = this.startNodeAtNode(t);
node.parameterName = (thisTypePredicate: N.TsThisType);
node.asserts = true;
thisTypePredicate = this.finishNode(node, "TSTypePredicate");
} else {
(thisTypePredicate: N.TsTypePredicate).asserts = true;
}
t.typeAnnotation = thisTypePredicate;
return this.finishNode(t, "TSTypeAnnotation");
}
const typePredicateVariable =
this.tsIsIdentifier() &&
this.tsTryParse(this.tsParseTypePredicatePrefix.bind(this));
@@ -947,15 +968,15 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.tsParseTypeAnnotation(/* eatColon */ false, t);
}
const node: N.TsTypePredicate = this.startNodeAtNode(t);
// : asserts foo
const node = this.startNodeAtNode(t);
node.parameterName = this.parseIdentifier();
node.asserts = asserts;
t.typeAnnotation = this.finishNode(node, "TSTypePredicate");
return this.finishNode(t, "TSTypeAnnotation");
}
// : foo is type
// : asserts foo is type
const type = this.tsParseTypeAnnotation(/* eatColon */ false);
const node = this.startNodeAtNode(t);
node.parameterName = typePredicateVariable;
@@ -989,17 +1010,24 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
tsParseTypePredicateAsserts(): boolean {
if (!this.tsIsIdentifier()) {
if (
!this.match(tt.name) ||
this.state.value !== "asserts" ||
this.hasPrecedingLineBreak()
) {
return false;
}
const containsEsc = this.state.containsEsc;
this.next();
if (!this.match(tt.name) && !this.match(tt._this)) {
return false;
}
const id = this.parseIdentifier();
if (
id.name !== "asserts" ||
this.hasPrecedingLineBreak() ||
!this.tsIsIdentifier()
) {
return false;
if (containsEsc) {
this.raise(
this.state.lastTokStart,
"Escape sequence in keyword asserts",
);
}
return true;