diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index ab2a37032ced2..376e524f9c2d5 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -2352,8 +2352,12 @@ namespace ts { return token = SyntaxKind.WhitespaceTrivia; case CharacterCodes.at: return token = SyntaxKind.AtToken; - case CharacterCodes.lineFeed: case CharacterCodes.carriageReturn: + if (text.charCodeAt(pos) === CharacterCodes.lineFeed) { + pos++; + } + // falls through + case CharacterCodes.lineFeed: tokenFlags |= TokenFlags.PrecedingLineBreak; return token = SyntaxKind.NewLineTrivia; case CharacterCodes.asterisk: diff --git a/src/testRunner/unittests/publicApi.ts b/src/testRunner/unittests/publicApi.ts index 80df40e6d9b4e..7104662d033ef 100644 --- a/src/testRunner/unittests/publicApi.ts +++ b/src/testRunner/unittests/publicApi.ts @@ -53,6 +53,24 @@ describe("unittests:: Public APIs:: createPrivateIdentifier", () => { }); }); +describe("unittests:: Public APIs:: JSDoc newlines", () => { + it("are preserved verbatim", () => { + const testFilePath = "/file.ts"; + const testFileText = ` +/** +* @example +* Some\n * text\r\n * with newlines. +*/ +function test() {}`; + + const testSourceFile = ts.createSourceFile(testFilePath, testFileText, ts.ScriptTarget.Latest, /*setParentNodes*/ true); + const funcDec = testSourceFile.statements.find(ts.isFunctionDeclaration)!; + const tags = ts.getJSDocTags(funcDec); + assert.isDefined(tags[0].comment); + assert.equal(tags[0].comment, "Some\n text\r\n with newlines."); + }); +}); + describe("unittests:: Public APIs:: isPropertyName", () => { it("checks if a PrivateIdentifier is a valid property name", () => { const prop = ts.factory.createPrivateIdentifier("#foo");