diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index be81d789c57d0..c71d56880833d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2161,6 +2161,9 @@ namespace Parser { return nextTokenWithoutCheck(); } + function nextTokenJSDocInitialIndent(): JSDocSyntaxKind { + return currentToken = scanner.scanJSDocInitialIndent(); + } function nextTokenJSDoc(): JSDocSyntaxKind { return currentToken = scanner.scanJsDocToken(); } @@ -8636,14 +8639,14 @@ namespace Parser { break; case SyntaxKind.WhitespaceTrivia: // only collect whitespace if we're already saving comments or have just crossed the comment indent margin - const whitespace = scanner.getTokenText(); + const whitespaceLength = scanner.getTextPos() - scanner.getTokenPos(); if (state === JSDocState.SavingComments) { - comments.push(whitespace); + comments.push(scanner.getTokenText()); } - else if (margin !== undefined && indent + whitespace.length > margin) { - comments.push(whitespace.slice(margin - indent)); + else if (margin !== undefined && indent + whitespaceLength > margin) { + comments.push(scanner.getText().slice(scanner.getTokenPos() + margin - indent, scanner.getTextPos())); } - indent += whitespace.length; + indent += whitespaceLength; break; case SyntaxKind.EndOfFileToken: break loop; @@ -8671,7 +8674,12 @@ namespace Parser { pushComment(scanner.getTokenText()); break; } - nextTokenJSDoc(); + if (state === JSDocState.BeginningOfLine) { + nextTokenJSDocInitialIndent(); + } + else { + nextTokenJSDoc(); + } } removeTrailingWhitespace(comments); if (parts.length && comments.length) { @@ -8888,12 +8896,12 @@ namespace Parser { pushComment(scanner.getTokenText()); } else { - const whitespace = scanner.getTokenText(); + const whitespaceLength = scanner.getTextPos() - scanner.getTokenPos(); // if the whitespace crosses the margin, take only the whitespace that passes the margin - if (margin !== undefined && indent + whitespace.length > margin) { - comments.push(whitespace.slice(margin - indent)); + if (margin !== undefined && indent + whitespaceLength > margin) { + comments.push(scanner.getText().slice(scanner.getTokenPos() + margin - indent, scanner.getTextPos())); } - indent += whitespace.length; + indent += whitespaceLength; } break; case SyntaxKind.OpenBraceToken: @@ -8937,7 +8945,12 @@ namespace Parser { break; } previousWhitespace = token() === SyntaxKind.WhitespaceTrivia; - tok = nextTokenJSDoc(); + if (state === JSDocState.BeginningOfLine) { + tok = nextTokenJSDocInitialIndent(); + } + else { + tok = nextTokenJSDoc(); + } } removeLeadingNewlines(comments); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index e517b18e685f8..8f516fb037ddf 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -74,6 +74,8 @@ export interface Scanner { reScanQuestionToken(): SyntaxKind; reScanInvalidIdentifier(): SyntaxKind; scanJsxToken(): JsxTokenSyntaxKind; + /** @internal */ + scanJSDocInitialIndent(): JSDocSyntaxKind; scanJsDocToken(): JSDocSyntaxKind; scan(): SyntaxKind; @@ -1019,6 +1021,7 @@ export function createScanner(languageVersion: ScriptTarget, reScanQuestionToken, reScanInvalidIdentifier, scanJsxToken, + scanJSDocInitialIndent, scanJsDocToken, scan, getText, @@ -2455,6 +2458,21 @@ export function createScanner(languageVersion: ScriptTarget, return scanJsxAttributeValue(); } + function scanJSDocInitialIndent(): JSDocSyntaxKind { + startPos = tokenPos = pos; + tokenFlags = TokenFlags.None; + if (pos >= end) { + return token = SyntaxKind.EndOfFileToken; + } + for (let ch = codePointAt(text, pos); // TODO: Only allow 1 (one) asterisk! + pos < end && (isWhiteSpaceSingleLine(ch) || ch === CharacterCodes.asterisk); + ch = codePointAt(text, pos += charSize(ch))); + if (pos === tokenPos) { + return scanJsDocToken(); + } + return token = SyntaxKind.WhitespaceTrivia; + } + function scanJsDocToken(): JSDocSyntaxKind { startPos = tokenPos = pos; tokenFlags = TokenFlags.None;