@@ -6151,10 +6151,10 @@ namespace ts {
6151
6151
return comment ;
6152
6152
}
6153
6153
6154
- const enum TagState {
6154
+ const enum JSDocState {
6155
6155
BeginningOfLine ,
6156
6156
SawAsterisk ,
6157
- SavingComments
6157
+ SavingComments ,
6158
6158
}
6159
6159
6160
6160
export function parseJSDocCommentWorker ( start : number , length : number ) : JSDoc {
@@ -6180,93 +6180,81 @@ namespace ts {
6180
6180
scanner . scanRange ( start + 3 , length - 5 , ( ) => {
6181
6181
// Initially we can parse out a tag. We also have seen a starting asterisk.
6182
6182
// This is so that /** * @type */ doesn't parse.
6183
- let canParseTag = true ;
6184
- let seenAsterisk = true ;
6185
6183
let advanceToken = true ;
6184
+ let state = JSDocState . SawAsterisk ;
6186
6185
let margin : number | undefined = undefined ;
6187
6186
let indent = start - Math . max ( content . lastIndexOf ( "\n" , start ) , 0 ) + 4 ;
6188
- let text : string ;
6187
+ function pushComment ( text : string ) {
6188
+ if ( ! margin ) {
6189
+ margin = indent ;
6190
+ }
6191
+ comments . push ( text ) ;
6192
+ indent += text . length ;
6193
+ }
6189
6194
6190
6195
nextJSDocToken ( ) ;
6191
6196
while ( token ( ) === SyntaxKind . WhitespaceTrivia ) {
6192
6197
nextJSDocToken ( ) ;
6193
6198
}
6194
6199
if ( token ( ) === SyntaxKind . NewLineTrivia ) {
6195
- canParseTag = true ;
6196
- seenAsterisk = false ;
6200
+ state = JSDocState . BeginningOfLine ;
6197
6201
nextJSDocToken ( ) ;
6198
6202
}
6199
6203
while ( token ( ) !== SyntaxKind . EndOfFileToken ) {
6200
6204
switch ( token ( ) ) {
6201
6205
case SyntaxKind . AtToken :
6202
- if ( canParseTag ) {
6206
+ if ( state === JSDocState . BeginningOfLine || state === JSDocState . SawAsterisk ) {
6203
6207
removeTrailingNewlines ( comments ) ;
6204
6208
parseTag ( indent ) ;
6205
- // This will take us past the end of the line, so it's OK to parse a tag on the next pass through the loop
6206
- // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag. But real-world comments may break this rule.
6207
- seenAsterisk = false ;
6209
+ // NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag.
6210
+ // Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning
6211
+ // for malformed examples like `/** @param {string } x @returns {number } the length */`
6212
+ state = JSDocState . BeginningOfLine ;
6208
6213
advanceToken = false ;
6209
6214
margin = undefined ;
6215
+ indent ++ ;
6210
6216
}
6211
6217
else {
6212
- comments . push ( scanner . getTokenText ( ) ) ;
6218
+ pushComment ( scanner . getTokenText ( ) ) ;
6213
6219
}
6214
- indent ++ ;
6215
6220
break ;
6216
-
6217
6221
case SyntaxKind . NewLineTrivia :
6218
- // After a line break, we can parse a tag, and we haven't seen an asterisk on the next line yet
6219
6222
comments . push ( scanner . getTokenText ( ) ) ;
6220
- canParseTag = true ;
6221
- seenAsterisk = false ;
6223
+ state = JSDocState . BeginningOfLine ;
6222
6224
indent = 0 ;
6223
6225
break ;
6224
-
6225
6226
case SyntaxKind . AsteriskToken :
6226
- text = scanner . getTokenText ( ) ;
6227
- if ( seenAsterisk ) {
6227
+ const asterisk = scanner . getTokenText ( ) ;
6228
+ if ( state === JSDocState . SawAsterisk ) {
6228
6229
// If we've already seen an asterisk, then we can no longer parse a tag on this line
6229
- canParseTag = false ;
6230
- comments . push ( text ) ;
6231
- if ( ! margin ) {
6232
- margin = indent ;
6233
- }
6230
+ state = JSDocState . SavingComments ;
6231
+ pushComment ( asterisk ) ;
6232
+ }
6233
+ else {
6234
+ // Ignore the first asterisk on a line
6235
+ state = JSDocState . SawAsterisk ;
6236
+ indent += asterisk . length ;
6234
6237
}
6235
- // Ignore the first asterisk on a line
6236
- seenAsterisk = true ;
6237
- indent += text . length ;
6238
6238
break ;
6239
-
6240
6239
case SyntaxKind . Identifier :
6241
6240
// Anything else is doc comment text. We just save it. Because it
6242
6241
// wasn't a tag, we can no longer parse a tag on this line until we hit the next
6243
6242
// line break.
6244
- text = scanner . getTokenText ( ) ;
6245
- comments . push ( text ) ;
6246
- if ( ! margin ) {
6247
- margin = indent ;
6248
- }
6249
- canParseTag = false ;
6250
- indent += text . length ;
6243
+ pushComment ( scanner . getTokenText ( ) ) ;
6244
+ state = JSDocState . SavingComments ;
6251
6245
break ;
6252
-
6253
-
6254
6246
case SyntaxKind . WhitespaceTrivia :
6255
- // only collect whitespace if we *know* that we 're just looking at comments, not a possible jsdoc tag
6256
- text = scanner . getTokenText ( ) ;
6257
- if ( ! canParseTag || margin !== undefined && indent + text . length > margin ) {
6258
- comments . push ( text . slice ( margin - indent - 1 ) ) ;
6247
+ // only collect whitespace if we're already saving comments or have just crossed the comment indent margin
6248
+ const whitespace = scanner . getTokenText ( ) ;
6249
+ if ( state === JSDocState . SavingComments || margin !== undefined && indent + whitespace . length > margin ) {
6250
+ comments . push ( whitespace . slice ( margin - indent - 1 ) ) ;
6259
6251
}
6260
- indent += text . length ;
6252
+ indent += whitespace . length ;
6261
6253
break ;
6262
-
6263
6254
case SyntaxKind . EndOfFileToken :
6264
6255
break ;
6265
-
6266
6256
default :
6267
- text = scanner . getTokenText ( ) ;
6268
- comments . push ( text ) ;
6269
- indent += text . length ;
6257
+ pushComment ( scanner . getTokenText ( ) ) ;
6270
6258
break ;
6271
6259
}
6272
6260
if ( advanceToken ) {
@@ -6365,58 +6353,58 @@ namespace ts {
6365
6353
6366
6354
function parseTagComments ( indent : number ) {
6367
6355
const comments : string [ ] = [ ] ;
6368
- let state = TagState . SawAsterisk ;
6369
- let done = false ;
6356
+ let state = JSDocState . SawAsterisk ;
6370
6357
let margin : number | undefined ;
6371
- let text : string ;
6372
6358
function pushComment ( text : string ) {
6373
6359
if ( ! margin ) {
6374
6360
margin = indent ;
6375
6361
}
6376
6362
comments . push ( text ) ;
6377
6363
indent += text . length ;
6378
6364
}
6379
- while ( ! done && token ( ) !== SyntaxKind . EndOfFileToken ) {
6380
- text = scanner . getTokenText ( ) ;
6365
+ while ( token ( ) !== SyntaxKind . AtToken && token ( ) !== SyntaxKind . EndOfFileToken ) {
6381
6366
switch ( token ( ) ) {
6382
6367
case SyntaxKind . NewLineTrivia :
6383
- if ( state >= TagState . SawAsterisk ) {
6384
- state = TagState . BeginningOfLine ;
6385
- comments . push ( text ) ;
6368
+ if ( state >= JSDocState . SawAsterisk ) {
6369
+ state = JSDocState . BeginningOfLine ;
6370
+ comments . push ( scanner . getTokenText ( ) ) ;
6386
6371
}
6387
6372
indent = 0 ;
6388
6373
break ;
6389
6374
case SyntaxKind . AtToken :
6390
- done = true ;
6375
+ // Done
6391
6376
break ;
6392
6377
case SyntaxKind . WhitespaceTrivia :
6393
- if ( state === TagState . SavingComments ) {
6394
- pushComment ( text ) ;
6378
+ if ( state === JSDocState . SavingComments ) {
6379
+ pushComment ( scanner . getTokenText ( ) ) ;
6395
6380
}
6396
6381
else {
6382
+ const whitespace = scanner . getTokenText ( ) ;
6397
6383
// if the whitespace crosses the margin, take only the whitespace that passes the margin
6398
- if ( margin !== undefined && indent + text . length > margin ) {
6399
- comments . push ( text . slice ( margin - indent - 1 ) ) ;
6384
+ if ( margin !== undefined && indent + whitespace . length > margin ) {
6385
+ comments . push ( whitespace . slice ( margin - indent - 1 ) ) ;
6400
6386
}
6401
- indent += text . length ;
6387
+ indent += whitespace . length ;
6402
6388
}
6403
6389
break ;
6404
6390
case SyntaxKind . AsteriskToken :
6405
- if ( state === TagState . BeginningOfLine ) {
6391
+ if ( state === JSDocState . BeginningOfLine ) {
6406
6392
// leading asterisks start recording on the *next* (non-whitespace) token
6407
- state = TagState . SawAsterisk ;
6408
- indent += text . length ;
6393
+ state = JSDocState . SawAsterisk ;
6394
+ indent += scanner . getTokenText ( ) . length ;
6409
6395
break ;
6410
6396
}
6411
6397
// FALLTHROUGH otherwise to record the * as a comment
6412
6398
default :
6413
- state = TagState . SavingComments ; // leading identifiers start recording as well
6414
- pushComment ( text ) ;
6399
+ state = JSDocState . SavingComments ; // leading identifiers start recording as well
6400
+ pushComment ( scanner . getTokenText ( ) ) ;
6415
6401
break ;
6416
6402
}
6417
- if ( ! done ) {
6418
- nextJSDocToken ( ) ;
6403
+ if ( token ( ) === SyntaxKind . AtToken ) {
6404
+ // Done
6405
+ break ;
6419
6406
}
6407
+ nextJSDocToken ( ) ;
6420
6408
}
6421
6409
6422
6410
removeLeadingNewlines ( comments ) ;
0 commit comments