Skip to content

Commit

Permalink
Add asserts this [is type] parsing support (#10677)
Browse files Browse the repository at this point in the history
  • Loading branch information
JLHwung authored and existentialism committed Nov 11, 2019
1 parent 4cb5e0a commit d413a30
Show file tree
Hide file tree
Showing 14 changed files with 1,087 additions and 20 deletions.
64 changes: 46 additions & 18 deletions packages/babel-parser/src/plugins/typescript/index.js
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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));
Expand All @@ -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;
Expand Down Expand Up @@ -989,18 +1010,25 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}

tsParseTypePredicateAsserts(): boolean {
if (!this.tsIsIdentifier()) {
return false;
}

const id = this.parseIdentifier();
if (
id.name !== "asserts" ||
this.hasPrecedingLineBreak() ||
!this.tsIsIdentifier()
!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;
}

if (containsEsc) {
this.raise(
this.state.lastTokStart,
"Escape sequence in keyword asserts",
);
}

return true;
}
Expand Down
1 change: 1 addition & 0 deletions packages/babel-parser/src/types.js
Expand Up @@ -1227,6 +1227,7 @@ export type TsTypePredicate = TsTypeBase & {
type: "TSTypePredicate",
parameterName: Identifier | TsThisType,
typeAnnotation: TsTypeAnnotation,
asserts?: boolean,
};

// `typeof` operator
Expand Down
@@ -0,0 +1,4 @@
class Foo {
isBar(): asserts this is Foo {}
isBaz = (): asserts this is Foo => {}
}
@@ -0,0 +1,5 @@
{
"plugins": [
"typescript", "classProperties"
]
}

0 comments on commit d413a30

Please sign in to comment.