@@ -4685,20 +4685,12 @@ namespace ts {
4685
4685
&& lookAhead ( nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate ) ;
4686
4686
}
4687
4687
4688
- function hasOptionalChain ( node : Node ) {
4689
- while ( true ) {
4690
- if ( node . flags & NodeFlags . OptionalChain ) return true ;
4691
- if ( ! isNonNullExpression ( node ) ) return false ;
4692
- node = node . expression ;
4693
- }
4694
- }
4695
-
4696
4688
function parsePropertyAccessExpressionRest ( expression : LeftHandSideExpression , questionDotToken : QuestionDotToken | undefined ) {
4697
4689
const propertyAccess = < PropertyAccessExpression > createNode ( SyntaxKind . PropertyAccessExpression , expression . pos ) ;
4698
4690
propertyAccess . expression = expression ;
4699
4691
propertyAccess . questionDotToken = questionDotToken ;
4700
4692
propertyAccess . name = parseRightSideOfDot ( /*allowIdentifierNames*/ true , /*allowPrivateIdentifiers*/ true ) ;
4701
- if ( questionDotToken || hasOptionalChain ( expression ) ) {
4693
+ if ( questionDotToken || expression . flags & NodeFlags . OptionalChain ) {
4702
4694
propertyAccess . flags |= NodeFlags . OptionalChain ;
4703
4695
if ( isPrivateIdentifier ( propertyAccess . name ) ) {
4704
4696
parseErrorAtRange ( propertyAccess . name , Diagnostics . An_optional_chain_cannot_contain_private_identifiers ) ;
@@ -4724,12 +4716,43 @@ namespace ts {
4724
4716
}
4725
4717
4726
4718
parseExpected ( SyntaxKind . CloseBracketToken ) ;
4727
- if ( questionDotToken || hasOptionalChain ( expression ) ) {
4719
+ if ( questionDotToken || expression . flags & NodeFlags . OptionalChain ) {
4728
4720
indexedAccess . flags |= NodeFlags . OptionalChain ;
4729
4721
}
4730
4722
return finishNode ( indexedAccess ) ;
4731
4723
}
4732
4724
4725
+ function nextTokenContinuesOptionalChainAfterExclamationToken ( ) {
4726
+ // consume a run of `!` tokens
4727
+ while ( token ( ) === SyntaxKind . ExclamationToken && ! scanner . hasPrecedingLineBreak ( ) ) {
4728
+ nextToken ( ) ;
4729
+ }
4730
+ switch ( token ( ) ) {
4731
+ case SyntaxKind . DotToken :
4732
+ case SyntaxKind . OpenBracketToken :
4733
+ case SyntaxKind . OpenParenToken :
4734
+ case SyntaxKind . NoSubstitutionTemplateLiteral :
4735
+ case SyntaxKind . TemplateHead :
4736
+ case SyntaxKind . QuestionDotToken :
4737
+ // a?.b!.c
4738
+ // a?.b![c]
4739
+ // a?.b!()
4740
+ // a?.b!`` (illegal syntax in javascript but we must parse it)
4741
+ // a?.b!`${c}` (illegal syntax in javascript but we must parse it)
4742
+ // a?.b!?.c
4743
+ // a?.b!?.[c]
4744
+ // a?.b!?.()
4745
+ return true ;
4746
+ case SyntaxKind . LessThanToken :
4747
+ case SyntaxKind . LessThanLessThanToken :
4748
+ // a?.b!<T>()
4749
+ // a?.b!<<T>() (also handled in parseCallExpressionRest)
4750
+ // look ahead to see if we are parsing a type argument list
4751
+ return ! ! parseTypeArgumentsInExpression ( ) ;
4752
+ }
4753
+ return false ;
4754
+ }
4755
+
4733
4756
function parseMemberExpressionRest ( expression : LeftHandSideExpression , allowOptionalChain : boolean ) : MemberExpression {
4734
4757
while ( true ) {
4735
4758
let questionDotToken : QuestionDotToken | undefined ;
@@ -4751,6 +4774,9 @@ namespace ts {
4751
4774
nextToken ( ) ;
4752
4775
const nonNullExpression = < NonNullExpression > createNode ( SyntaxKind . NonNullExpression , expression . pos ) ;
4753
4776
nonNullExpression . expression = expression ;
4777
+ if ( expression . flags & NodeFlags . OptionalChain && lookAhead ( nextTokenContinuesOptionalChainAfterExclamationToken ) ) {
4778
+ nonNullExpression . flags |= NodeFlags . OptionalChain ;
4779
+ }
4754
4780
expression = finishNode ( nonNullExpression ) ;
4755
4781
continue ;
4756
4782
}
@@ -4811,7 +4837,7 @@ namespace ts {
4811
4837
callExpr . questionDotToken = questionDotToken ;
4812
4838
callExpr . typeArguments = typeArguments ;
4813
4839
callExpr . arguments = parseArgumentList ( ) ;
4814
- if ( questionDotToken || hasOptionalChain ( expression ) ) {
4840
+ if ( questionDotToken || expression . flags & NodeFlags . OptionalChain ) {
4815
4841
callExpr . flags |= NodeFlags . OptionalChain ;
4816
4842
}
4817
4843
expression = finishNode ( callExpr ) ;
@@ -4823,7 +4849,7 @@ namespace ts {
4823
4849
callExpr . expression = expression ;
4824
4850
callExpr . questionDotToken = questionDotToken ;
4825
4851
callExpr . arguments = parseArgumentList ( ) ;
4826
- if ( questionDotToken || hasOptionalChain ( expression ) ) {
4852
+ if ( questionDotToken || expression . flags & NodeFlags . OptionalChain ) {
4827
4853
callExpr . flags |= NodeFlags . OptionalChain ;
4828
4854
}
4829
4855
expression = finishNode ( callExpr ) ;
0 commit comments