@@ -1081,6 +1081,10 @@ namespace ts {
10811081 return currentToken = scanner . scan ( ) ;
10821082 }
10831083
1084+ function nextTokenJSDoc ( ) : JSDocSyntaxKind {
1085+ return currentToken = scanner . scanJsDocToken ( ) ;
1086+ }
1087+
10841088 function reScanGreaterToken ( ) : SyntaxKind {
10851089 return currentToken = scanner . reScanGreaterToken ( ) ;
10861090 }
@@ -1198,6 +1202,15 @@ namespace ts {
11981202 return false ;
11991203 }
12001204
1205+ function parseExpectedJSDoc ( kind : JSDocSyntaxKind ) {
1206+ if ( token ( ) === kind ) {
1207+ nextTokenJSDoc ( ) ;
1208+ return true ;
1209+ }
1210+ parseErrorAtCurrentToken ( Diagnostics . _0_expected , tokenToString ( kind ) ) ;
1211+ return false ;
1212+ }
1213+
12011214 function parseOptional ( t : SyntaxKind ) : boolean {
12021215 if ( token ( ) === t ) {
12031216 nextToken ( ) ;
@@ -1214,18 +1227,38 @@ namespace ts {
12141227 return undefined ;
12151228 }
12161229
1230+ function parseOptionalTokenJSDoc < TKind extends JSDocSyntaxKind > ( t : TKind ) : Token < TKind > ;
1231+ function parseOptionalTokenJSDoc ( t : JSDocSyntaxKind ) : Node | undefined {
1232+ if ( token ( ) === t ) {
1233+ return parseTokenNodeJSDoc ( ) ;
1234+ }
1235+ return undefined ;
1236+ }
1237+
12171238 function parseExpectedToken < TKind extends SyntaxKind > ( t : TKind , diagnosticMessage ?: DiagnosticMessage , arg0 ?: any ) : Token < TKind > ;
12181239 function parseExpectedToken ( t : SyntaxKind , diagnosticMessage ?: DiagnosticMessage , arg0 ?: any ) : Node {
12191240 return parseOptionalToken ( t ) ||
12201241 createMissingNode ( t , /*reportAtCurrentPosition*/ false , diagnosticMessage || Diagnostics . _0_expected , arg0 || tokenToString ( t ) ) ;
12211242 }
12221243
1244+ function parseExpectedTokenJSDoc < TKind extends JSDocSyntaxKind > ( t : TKind ) : Token < TKind > ;
1245+ function parseExpectedTokenJSDoc ( t : JSDocSyntaxKind ) : Node {
1246+ return parseOptionalTokenJSDoc ( t ) ||
1247+ createMissingNode ( t , /*reportAtCurrentPosition*/ false , Diagnostics . _0_expected , tokenToString ( t ) ) ;
1248+ }
1249+
12231250 function parseTokenNode < T extends Node > ( ) : T {
12241251 const node = < T > createNode ( token ( ) ) ;
12251252 nextToken ( ) ;
12261253 return finishNode ( node ) ;
12271254 }
12281255
1256+ function parseTokenNodeJSDoc < T extends Node > ( ) : T {
1257+ const node = < T > createNode ( token ( ) ) ;
1258+ nextTokenJSDoc ( ) ;
1259+ return finishNode ( node ) ;
1260+ }
1261+
12291262 function canParseSemicolon ( ) {
12301263 // If there's a real semicolon, then we can always parse it out.
12311264 if ( token ( ) === SyntaxKind . SemicolonToken ) {
@@ -6345,7 +6378,7 @@ namespace ts {
63456378 const hasBrace = ( mayOmitBraces ? parseOptional : parseExpected ) ( SyntaxKind . OpenBraceToken ) ;
63466379 result . type = doInsideOfContext ( NodeFlags . JSDoc , parseJSDocType ) ;
63476380 if ( ! mayOmitBraces || hasBrace ) {
6348- parseExpected ( SyntaxKind . CloseBraceToken ) ;
6381+ parseExpectedJSDoc ( SyntaxKind . CloseBraceToken ) ;
63496382 }
63506383
63516384 fixupParentReferences ( result ) ;
@@ -6432,7 +6465,7 @@ namespace ts {
64326465 indent += text . length ;
64336466 }
64346467
6435- nextJSDocToken ( ) ;
6468+ nextTokenJSDoc ( ) ;
64366469 while ( parseOptionalJsdoc ( SyntaxKind . WhitespaceTrivia ) ) ;
64376470 if ( parseOptionalJsdoc ( SyntaxKind . NewLineTrivia ) ) {
64386471 state = JSDocState . BeginningOfLine ;
@@ -6493,7 +6526,7 @@ namespace ts {
64936526 pushComment ( scanner . getTokenText ( ) ) ;
64946527 break ;
64956528 }
6496- nextJSDocToken ( ) ;
6529+ nextTokenJSDoc ( ) ;
64976530 }
64986531 removeLeadingNewlines ( comments ) ;
64996532 removeTrailingWhitespace ( comments ) ;
@@ -6522,7 +6555,7 @@ namespace ts {
65226555 function isNextNonwhitespaceTokenEndOfFile ( ) : boolean {
65236556 // We must use infinite lookahead, as there could be any number of newlines :(
65246557 while ( true ) {
6525- nextJSDocToken ( ) ;
6558+ nextTokenJSDoc ( ) ;
65266559 if ( token ( ) === SyntaxKind . EndOfFileToken ) {
65276560 return true ;
65286561 }
@@ -6539,7 +6572,7 @@ namespace ts {
65396572 }
65406573 }
65416574 while ( token ( ) === SyntaxKind . WhitespaceTrivia || token ( ) === SyntaxKind . NewLineTrivia ) {
6542- nextJSDocToken ( ) ;
6575+ nextTokenJSDoc ( ) ;
65436576 }
65446577 }
65456578
@@ -6563,15 +6596,15 @@ namespace ts {
65636596 else if ( token ( ) === SyntaxKind . AsteriskToken ) {
65646597 precedingLineBreak = false ;
65656598 }
6566- nextJSDocToken ( ) ;
6599+ nextTokenJSDoc ( ) ;
65676600 }
65686601 return seenLineBreak ? indentText : "" ;
65696602 }
65706603
65716604 function parseTag ( margin : number ) {
65726605 Debug . assert ( token ( ) === SyntaxKind . AtToken ) ;
65736606 const start = scanner . getTokenPos ( ) ;
6574- nextJSDocToken ( ) ;
6607+ nextTokenJSDoc ( ) ;
65756608
65766609 const tagName = parseJSDocIdentifierName ( /*message*/ undefined ) ;
65776610 const indentText = skipWhitespaceOrAsterisk ( ) ;
@@ -6643,7 +6676,7 @@ namespace ts {
66436676 pushComment ( initialMargin ) ;
66446677 state = JSDocState . SavingComments ;
66456678 }
6646- let tok = token ( ) as JsDocSyntaxKind ;
6679+ let tok = token ( ) as JSDocSyntaxKind ;
66476680 loop: while ( true ) {
66486681 switch ( tok ) {
66496682 case SyntaxKind . NewLineTrivia :
@@ -6674,11 +6707,11 @@ namespace ts {
66746707 break ;
66756708 case SyntaxKind . OpenBraceToken :
66766709 state = JSDocState . SavingComments ;
6677- if ( lookAhead ( ( ) => nextJSDocToken ( ) === SyntaxKind . AtToken && tokenIsIdentifierOrKeyword ( nextJSDocToken ( ) ) && scanner . getTokenText ( ) === "link" ) ) {
6710+ if ( lookAhead ( ( ) => nextTokenJSDoc ( ) === SyntaxKind . AtToken && tokenIsIdentifierOrKeyword ( nextTokenJSDoc ( ) ) && scanner . getTokenText ( ) === "link" ) ) {
66786711 pushComment ( scanner . getTokenText ( ) ) ;
6679- nextJSDocToken ( ) ;
6712+ nextTokenJSDoc ( ) ;
66806713 pushComment ( scanner . getTokenText ( ) ) ;
6681- nextJSDocToken ( ) ;
6714+ nextTokenJSDoc ( ) ;
66826715 }
66836716 pushComment ( scanner . getTokenText ( ) ) ;
66846717 break ;
@@ -6696,7 +6729,7 @@ namespace ts {
66966729 pushComment ( scanner . getTokenText ( ) ) ;
66976730 break ;
66986731 }
6699- tok = nextJSDocToken ( ) ;
6732+ tok = nextTokenJSDoc ( ) ;
67006733 }
67016734
67026735 removeLeadingNewlines ( comments ) ;
@@ -6730,16 +6763,19 @@ namespace ts {
67306763 }
67316764
67326765 function parseBracketNameInPropertyAndParamTag ( ) : { name : EntityName , isBracketed : boolean } {
6733- if ( token ( ) === SyntaxKind . NoSubstitutionTemplateLiteral ) {
6734- // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild
6735- return { name : createIdentifier ( /*isIdentifier*/ true ) , isBracketed : false } ;
6736- }
67376766 // Looking for something like '[foo]', 'foo', '[foo.bar]' or 'foo.bar'
6738- const isBracketed = parseOptional ( SyntaxKind . OpenBracketToken ) ;
6767+ const isBracketed = parseOptionalJsdoc ( SyntaxKind . OpenBracketToken ) ;
6768+ if ( isBracketed ) {
6769+ skipWhitespace ( ) ;
6770+ }
6771+ // a markdown-quoted name: `arg` is not legal jsdoc, but occurs in the wild
6772+ const isBackquoted = parseOptionalJsdoc ( SyntaxKind . BacktickToken ) ;
67396773 const name = parseJSDocEntityName ( ) ;
6774+ if ( isBackquoted ) {
6775+ parseExpectedTokenJSDoc ( SyntaxKind . BacktickToken ) ;
6776+ }
67406777 if ( isBracketed ) {
67416778 skipWhitespace ( ) ;
6742-
67436779 // May have an optional default, e.g. '[foo = 42]'
67446780 if ( parseOptionalToken ( SyntaxKind . EqualsToken ) ) {
67456781 parseExpression ( ) ;
@@ -7022,7 +7058,7 @@ namespace ts {
70227058 let canParseTag = true ;
70237059 let seenAsterisk = false ;
70247060 while ( true ) {
7025- switch ( nextJSDocToken ( ) ) {
7061+ switch ( nextTokenJSDoc ( ) ) {
70267062 case SyntaxKind . AtToken :
70277063 if ( canParseTag ) {
70287064 const child = tryParseChildTag ( target , indent ) ;
@@ -7057,7 +7093,7 @@ namespace ts {
70577093 function tryParseChildTag ( target : PropertyLikeParse , indent : number ) : JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
70587094 Debug . assert ( token ( ) === SyntaxKind . AtToken ) ;
70597095 const start = scanner . getStartPos ( ) ;
7060- nextJSDocToken ( ) ;
7096+ nextTokenJSDoc ( ) ;
70617097
70627098 const tagName = parseJSDocIdentifierName ( ) ;
70637099 skipWhitespace ( ) ;
@@ -7109,13 +7145,9 @@ namespace ts {
71097145 return result ;
71107146 }
71117147
7112- function nextJSDocToken ( ) : JsDocSyntaxKind {
7113- return currentToken = scanner . scanJSDocToken ( ) ;
7114- }
7115-
7116- function parseOptionalJsdoc ( t : JsDocSyntaxKind ) : boolean {
7148+ function parseOptionalJsdoc ( t : JSDocSyntaxKind ) : boolean {
71177149 if ( token ( ) === t ) {
7118- nextJSDocToken ( ) ;
7150+ nextTokenJSDoc ( ) ;
71197151 return true ;
71207152 }
71217153 return false ;
@@ -7150,7 +7182,7 @@ namespace ts {
71507182 result . escapedText = escapeLeadingUnderscores ( scanner . getTokenText ( ) ) ;
71517183 finishNode ( result , end ) ;
71527184
7153- nextJSDocToken ( ) ;
7185+ nextTokenJSDoc ( ) ;
71547186 return result ;
71557187 }
71567188 }
0 commit comments