From c07c8851511e744749c1e5524d185482edb69cbd Mon Sep 17 00:00:00 2001 From: Alexander T Date: Thu, 16 Jul 2020 23:56:30 +0300 Subject: [PATCH] fix(39515): fix getting a position for an element before the line break CRLF/LF on the line that contains 'after' element (#39554) --- src/services/textChanges.ts | 3 ++- src/testRunner/unittests/services/textChanges.ts | 14 ++++++++++++++ .../textChanges/insertNodeInListAfter19.js | 13 +++++++++++++ .../textChanges/insertNodeInListAfter20.js | 13 +++++++++++++ 4 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/textChanges/insertNodeInListAfter19.js create mode 100644 tests/baselines/reference/textChanges/insertNodeInListAfter20.js diff --git a/src/services/textChanges.ts b/src/services/textChanges.ts index e225ff7d3d3..f8cbf227890 100644 --- a/src/services/textChanges.ts +++ b/src/services/textChanges.ts @@ -794,7 +794,8 @@ namespace ts.textChanges { const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(afterStartLinePosition, afterStart, sourceFile, this.formatContext.options); // insert element before the line break on the line that contains 'after' element let insertPos = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true, /*stopAtComments*/ false); - if (insertPos !== end && isLineBreak(sourceFile.text.charCodeAt(insertPos - 1))) { + // find position before "\n" or "\r\n" + while (insertPos !== end && isLineBreak(sourceFile.text.charCodeAt(insertPos - 1))) { insertPos--; } this.replaceRange(sourceFile, createRange(insertPos), newNode, { indentation, prefix: this.newLineCharacter }); diff --git a/src/testRunner/unittests/services/textChanges.ts b/src/testRunner/unittests/services/textChanges.ts index 7a5c9af03ff..325607745b6 100644 --- a/src/testRunner/unittests/services/textChanges.ts +++ b/src/testRunner/unittests/services/textChanges.ts @@ -619,6 +619,20 @@ import { changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(undefined, factory.createIdentifier("a"))); }); } + { + const runTest = (name: string, text: string) => runSingleFileTest(name, /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => { + for (const specifier of ["x3", "x4", "x5"]) { + // eslint-disable-next-line boolean-trivia + changeTracker.insertNodeInListAfter(sourceFile, findChild("x2", sourceFile), factory.createImportSpecifier(undefined, factory.createIdentifier(specifier))); + } + }); + + const crlfText = "import {\r\nx1,\r\nx2\r\n} from \"bar\";"; + runTest("insertNodeInListAfter19", crlfText); + + const lfText = "import {\nx1,\nx2\n} from \"bar\";"; + runTest("insertNodeInListAfter20", lfText); + } { const text = ` class A { diff --git a/tests/baselines/reference/textChanges/insertNodeInListAfter19.js b/tests/baselines/reference/textChanges/insertNodeInListAfter19.js new file mode 100644 index 00000000000..0b5290d7000 --- /dev/null +++ b/tests/baselines/reference/textChanges/insertNodeInListAfter19.js @@ -0,0 +1,13 @@ +===ORIGINAL=== +import { +x1, +x2 +} from "bar"; +===MODIFIED=== +import { +x1, +x2, +x3, +x4, +x5 +} from "bar"; \ No newline at end of file diff --git a/tests/baselines/reference/textChanges/insertNodeInListAfter20.js b/tests/baselines/reference/textChanges/insertNodeInListAfter20.js new file mode 100644 index 00000000000..c13ddd1d395 --- /dev/null +++ b/tests/baselines/reference/textChanges/insertNodeInListAfter20.js @@ -0,0 +1,13 @@ +===ORIGINAL=== +import { +x1, +x2 +} from "bar"; +===MODIFIED=== +import { +x1, +x2, +x3, +x4, +x5 +} from "bar"; \ No newline at end of file