• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Some tests have trailing whitespace
2
3namespace ts {
4    describe("unittests:: services:: textChanges", () => {
5        function findChild(name: string, n: Node) {
6            return find(n)!;
7
8            function find(node: Node): Node | undefined {
9                if (isDeclaration(node) && node.name && isIdentifier(node.name) && node.name.escapedText === name) {
10                    return node;
11                }
12                else {
13                    return forEachChild(node, find);
14                }
15            }
16        }
17
18        const printerOptions = { newLine: NewLineKind.LineFeed };
19        const newLineCharacter = getNewLineCharacter(printerOptions);
20
21        function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean): formatting.FormatContext {
22            return formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...testFormatSettings, placeOpenBraceOnNewLineForFunctions: true } : testFormatSettings, notImplementedHost);
23        }
24
25        // validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed.
26        function verifyPositions(node: Node, text: string): void {
27            const nodeList = flattenNodes(node);
28            const sourceFile = createSourceFile("f.ts", text, ScriptTarget.ES2015);
29            const parsedNodeList = flattenNodes(sourceFile.statements[0]);
30            zipWith(nodeList, parsedNodeList, (left, right) => {
31                Debug.assert(left.pos === right.pos);
32                Debug.assert(left.end === right.end);
33            });
34
35            function flattenNodes(n: Node) {
36                const data: (Node | NodeArray<Node>)[] = [];
37                walk(n);
38                return data;
39
40                function walk(n: Node | NodeArray<Node>): void {
41                    data.push(n);
42                    return isArray(n) ? forEach(n, walk) : forEachChild(n, walk, walk);
43                }
44            }
45        }
46
47        function runSingleFileTest(caption: string, placeOpenBraceOnNewLineForFunctions: boolean, text: string, validateNodes: boolean, testBlock: (sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker) => void) {
48            it(caption, () => {
49                const sourceFile = createSourceFile("source.ts", text, ScriptTarget.ES2015, /*setParentNodes*/ true);
50                const rulesProvider = getRuleProvider(placeOpenBraceOnNewLineForFunctions);
51                const changeTracker = new textChanges.ChangeTracker(newLineCharacter, rulesProvider);
52                testBlock(sourceFile, changeTracker);
53                const changes = changeTracker.getChanges(validateNodes ? verifyPositions : undefined);
54                assert.equal(changes.length, 1);
55                assert.equal(changes[0].fileName, sourceFile.fileName);
56                const modified = textChanges.applyChanges(sourceFile.text, changes[0].textChanges);
57                Harness.Baseline.runBaseline(`textChanges/${caption}.js`, `===ORIGINAL===${newLineCharacter}${text}${newLineCharacter}===MODIFIED===${newLineCharacter}${modified}`);
58            });
59        }
60
61        {
62            const text = `
63namespace M
64{
65    namespace M2
66    {
67        function foo() {
68            // comment 1
69            const x = 1;
70
71            /**
72             * comment 2 line 1
73             * comment 2 line 2
74             */
75            function f() {
76                return 100;
77            }
78            const y = 2; // comment 3
79            return 1;
80        }
81    }
82}`;
83            runSingleFileTest("extractMethodLike", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
84                const statements = (<FunctionDeclaration>findChild("foo", sourceFile)).body!.statements.slice(1);
85                const newFunction = factory.createFunctionDeclaration(
86                    /*decorators*/ undefined,
87                    /*modifiers*/ undefined,
88                    /*asteriskToken*/ undefined,
89                    /*name*/ "bar",
90                    /*typeParameters*/ undefined,
91                    /*parameters*/ emptyArray,
92                    /*type*/ factory.createKeywordTypeNode(SyntaxKind.AnyKeyword),
93                    /*body */ factory.createBlock(statements)
94                );
95
96                changeTracker.insertNodeBefore(sourceFile, /*before*/findChild("M2", sourceFile), newFunction);
97
98                // replace statements with return statement
99                const newStatement = factory.createReturnStatement(
100                    factory.createCallExpression(
101                        /*expression*/ newFunction.name!,
102                        /*typeArguments*/ undefined,
103                        /*argumentsArray*/ emptyArray
104                    ));
105                changeTracker.replaceNodeRange(sourceFile, statements[0], last(statements), newStatement, { suffix: newLineCharacter });
106            });
107        }
108        {
109            const text = `
110function foo() {
111    return 1;
112}
113
114function bar() {
115    return 2;
116}
117`;
118            runSingleFileTest("deleteRange1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
119                changeTracker.deleteRange(sourceFile, { pos: text.indexOf("function foo"), end: text.indexOf("function bar") });
120            });
121        }
122        function findVariableStatementContaining(name: string, sourceFile: SourceFile): VariableStatement {
123            return cast(findVariableDeclarationContaining(name, sourceFile).parent.parent, isVariableStatement);
124        }
125        function findVariableDeclarationContaining(name: string, sourceFile: SourceFile): VariableDeclaration {
126            return cast(findChild(name, sourceFile), isVariableDeclaration);
127        }
128        const { deleteNode } = textChanges;
129        {
130            const text = `
131var x = 1; // some comment - 1
132/**
133 * comment 2
134 */
135var y = 2; // comment 3
136var z = 3; // comment 4
137`;
138            runSingleFileTest("deleteNode1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
139                deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile));
140            });
141            runSingleFileTest("deleteNode2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
142                deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude });
143            });
144            runSingleFileTest("deleteNode3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
145                deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude });
146            });
147            runSingleFileTest("deleteNode4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
148                deleteNode(changeTracker, sourceFile, findVariableStatementContaining("y", sourceFile), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude });
149            });
150            runSingleFileTest("deleteNode5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
151                deleteNode(changeTracker, sourceFile, findVariableStatementContaining("x", sourceFile));
152            });
153        }
154        {
155            const text = `
156// comment 1
157var x = 1; // comment 2
158// comment 3
159var y = 2; // comment 4
160var z = 3; // comment 5
161// comment 6
162var a = 4; // comment 7
163`;
164            runSingleFileTest("deleteNodeRange1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
165                changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile));
166            });
167            runSingleFileTest("deleteNodeRange2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
168                changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile),
169                    { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude });
170            });
171            runSingleFileTest("deleteNodeRange3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
172                changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile),
173                    { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude });
174            });
175            runSingleFileTest("deleteNodeRange4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
176                changeTracker.deleteNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile),
177                    { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude });
178            });
179        }
180        function createTestVariableDeclaration(name: string) {
181            return factory.createVariableDeclaration(name, /*exclamationToken*/ undefined, /*type*/ undefined, factory.createObjectLiteralExpression([factory.createPropertyAssignment("p1", factory.createNumericLiteral(1))], /*multiline*/ true));
182        }
183        function createTestClass() {
184            return factory.createClassDeclaration(
185                /*decorators*/ undefined,
186                [
187                    factory.createToken(SyntaxKind.PublicKeyword)
188                ],
189                "class1",
190                /*typeParameters*/ undefined,
191                [
192                    factory.createHeritageClause(
193                        SyntaxKind.ImplementsKeyword,
194                        [
195                            factory.createExpressionWithTypeArguments(factory.createIdentifier("interface1"), /*typeArguments*/ undefined)
196                        ]
197                    )
198                ],
199                [
200                    factory.createPropertyDeclaration(
201                        /*decorators*/ undefined,
202                        /*modifiers*/ undefined,
203                        "property1",
204                        /*questionToken*/ undefined,
205                        factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword),
206                        /*initializer*/ undefined
207                    )
208                ]
209            );
210        }
211        {
212            const text = `
213// comment 1
214var x = 1; // comment 2
215// comment 3
216var y = 2; // comment 4
217var z = 3; // comment 5
218// comment 6
219var a = 4; // comment 7`;
220            runSingleFileTest("replaceRange", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
221                changeTracker.replaceRange(sourceFile, { pos: text.indexOf("var y"), end: text.indexOf("var a") }, createTestClass(), { suffix: newLineCharacter });
222            });
223            runSingleFileTest("replaceRangeWithForcedIndentation", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
224                changeTracker.replaceRange(sourceFile, { pos: text.indexOf("var y"), end: text.indexOf("var a") }, createTestClass(), { suffix: newLineCharacter, indentation: 8, delta: 0 });
225            });
226
227            runSingleFileTest("replaceRangeNoLineBreakBefore", /*placeOpenBraceOnNewLineForFunctions*/ true, `const x = 1, y = "2";`, /*validateNodes*/ false, (sourceFile, changeTracker) => {
228                const newNode = createTestVariableDeclaration("z1");
229                changeTracker.replaceRange(sourceFile, { pos: sourceFile.text.indexOf("y"), end: sourceFile.text.indexOf(";") }, newNode);
230            });
231        }
232        {
233            const text = `
234namespace A {
235    const x = 1, y = "2";
236}
237`;
238            runSingleFileTest("replaceNode1NoLineBreakBefore", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
239                const newNode = createTestVariableDeclaration("z1");
240                changeTracker.replaceNode(sourceFile, findChild("y", sourceFile), newNode);
241            });
242        }
243        {
244            const text = `
245// comment 1
246var x = 1; // comment 2
247// comment 3
248var y = 2; // comment 4
249var z = 3; // comment 5
250// comment 6
251var a = 4; // comment 7`;
252            runSingleFileTest("replaceNode1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
253                changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { suffix: newLineCharacter });
254            });
255            runSingleFileTest("replaceNode2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
256                changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, suffix: newLineCharacter, prefix: newLineCharacter });
257            });
258            runSingleFileTest("replaceNode3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
259                changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter });
260            });
261            runSingleFileTest("replaceNode4", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
262                changeTracker.replaceNode(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude });
263            });
264            runSingleFileTest("replaceNode5", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
265                changeTracker.replaceNode(sourceFile, findVariableStatementContaining("x", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude });
266            });
267        }
268        {
269            const text = `
270// comment 1
271var x = 1; // comment 2
272// comment 3
273var y = 2; // comment 4
274var z = 3; // comment 5
275// comment 6
276var a = 4; // comment 7`;
277            runSingleFileTest("replaceNodeRange1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
278                changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { suffix: newLineCharacter });
279            });
280            runSingleFileTest("replaceNodeRange2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
281                changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, suffix: newLineCharacter, prefix: newLineCharacter });
282            });
283            runSingleFileTest("replaceNodeRange3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
284                changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude, suffix: newLineCharacter });
285            });
286            runSingleFileTest("replaceNodeRange4", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
287                changeTracker.replaceNodeRange(sourceFile, findVariableStatementContaining("y", sourceFile), findVariableStatementContaining("z", sourceFile), createTestClass(), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.Exclude });
288            });
289        }
290        {
291            const text = `
292// comment 1
293var x = 1; // comment 2
294// comment 3
295var y; // comment 4
296var z = 3; // comment 5
297// comment 6
298var a = 4; // comment 7`;
299            runSingleFileTest("insertNodeBefore3", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
300                changeTracker.insertNodeBefore(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass());
301            });
302            runSingleFileTest("insertNodeAfterVariableDeclaration", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
303                changeTracker.insertNodeAfter(sourceFile, findVariableDeclarationContaining("y", sourceFile), createTestVariableDeclaration("z1"));
304            });
305        }
306        {
307            const text = `
308namespace M {
309    // comment 1
310    var x = 1; // comment 2
311    // comment 3
312    var y; // comment 4
313    var z = 3; // comment 5
314    // comment 6
315    var a = 4; // comment 7
316}`;
317            runSingleFileTest("insertNodeBefore1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
318                changeTracker.insertNodeBefore(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass());
319            });
320            runSingleFileTest("insertNodeBefore2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
321                changeTracker.insertNodeBefore(sourceFile, findChild("M", sourceFile), createTestClass());
322            });
323            runSingleFileTest("insertNodeAfter1", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
324                changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("y", sourceFile), createTestClass());
325            });
326            runSingleFileTest("insertNodeAfter2", /*placeOpenBraceOnNewLineForFunctions*/ true, text, /*validateNodes*/ true, (sourceFile, changeTracker) => {
327                changeTracker.insertNodeAfter(sourceFile, findChild("M", sourceFile), createTestClass());
328            });
329        }
330
331        function findConstructor(sourceFile: SourceFile): ConstructorDeclaration {
332            const classDecl = <ClassDeclaration>sourceFile.statements[0];
333            return find<ClassElement, ConstructorDeclaration>(classDecl.members, (m): m is ConstructorDeclaration => isConstructorDeclaration(m) && !!m.body)!;
334        }
335        function createTestSuperCall() {
336            const superCall = factory.createCallExpression(
337                factory.createSuper(),
338                /*typeArguments*/ undefined,
339                /*argumentsArray*/ emptyArray
340            );
341            return factory.createExpressionStatement(superCall);
342        }
343
344        {
345            const text1 = `
346class A {
347    constructor() {
348    }
349}
350`;
351            runSingleFileTest("insertNodeAtConstructorStart", /*placeOpenBraceOnNewLineForFunctions*/ false, text1, /*validateNodes*/ false, (sourceFile, changeTracker) => {
352                changeTracker.insertNodeAtConstructorStart(sourceFile, findConstructor(sourceFile), createTestSuperCall());
353            });
354            const text2 = `
355class A {
356    constructor() {
357        var x = 1;
358    }
359}
360`;
361            runSingleFileTest("insertNodeAfter4", /*placeOpenBraceOnNewLineForFunctions*/ false, text2, /*validateNodes*/ false, (sourceFile, changeTracker) => {
362                changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), createTestSuperCall());
363            });
364            const text3 = `
365class A {
366    constructor() {
367
368    }
369}
370`;
371            runSingleFileTest("insertNodeAtConstructorStart-block with newline", /*placeOpenBraceOnNewLineForFunctions*/ false, text3, /*validateNodes*/ false, (sourceFile, changeTracker) => {
372                changeTracker.insertNodeAtConstructorStart(sourceFile, findConstructor(sourceFile), createTestSuperCall());
373            });
374        }
375        {
376            const text = `var a = 1, b = 2, c = 3;`;
377            runSingleFileTest("deleteNodeInList1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
378                changeTracker.delete(sourceFile, findChild("a", sourceFile));
379            });
380            runSingleFileTest("deleteNodeInList2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
381                changeTracker.delete(sourceFile, findChild("b", sourceFile));
382            });
383            runSingleFileTest("deleteNodeInList3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
384                changeTracker.delete(sourceFile, findChild("c", sourceFile));
385            });
386        }
387        {
388            const text = `var a = 1,b = 2,c = 3;`;
389            runSingleFileTest("deleteNodeInList1_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
390                changeTracker.delete(sourceFile, findChild("a", sourceFile));
391            });
392            runSingleFileTest("deleteNodeInList2_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
393                changeTracker.delete(sourceFile, findChild("b", sourceFile));
394            });
395            runSingleFileTest("deleteNodeInList3_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
396                changeTracker.delete(sourceFile, findChild("c", sourceFile));
397            });
398        }
399        {
400            const text = `
401namespace M {
402    var a = 1,
403        b = 2,
404        c = 3;
405}`;
406            runSingleFileTest("deleteNodeInList4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
407                changeTracker.delete(sourceFile, findChild("a", sourceFile));
408            });
409            runSingleFileTest("deleteNodeInList5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
410                changeTracker.delete(sourceFile, findChild("b", sourceFile));
411            });
412            runSingleFileTest("deleteNodeInList6", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
413                changeTracker.delete(sourceFile, findChild("c", sourceFile));
414            });
415        }
416        {
417            const text = `
418namespace M {
419    var a = 1, // comment 1
420        // comment 2
421        b = 2, // comment 3
422        // comment 4
423        c = 3; // comment 5
424}`;
425            runSingleFileTest("deleteNodeInList4_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
426                changeTracker.delete(sourceFile, findChild("a", sourceFile));
427            });
428            runSingleFileTest("deleteNodeInList5_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
429                changeTracker.delete(sourceFile, findChild("b", sourceFile));
430            });
431            runSingleFileTest("deleteNodeInList6_1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
432                changeTracker.delete(sourceFile, findChild("c", sourceFile));
433            });
434        }
435        {
436            const text = `
437function foo(a: number, b: string, c = true) {
438    return 1;
439}`;
440            runSingleFileTest("deleteNodeInList7", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
441                changeTracker.delete(sourceFile, findChild("a", sourceFile));
442            });
443            runSingleFileTest("deleteNodeInList8", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
444                changeTracker.delete(sourceFile, findChild("b", sourceFile));
445            });
446            runSingleFileTest("deleteNodeInList9", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
447                changeTracker.delete(sourceFile, findChild("c", sourceFile));
448            });
449        }
450        {
451            const text = `
452function foo(a: number,b: string,c = true) {
453    return 1;
454}`;
455            runSingleFileTest("deleteNodeInList10", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
456                changeTracker.delete(sourceFile, findChild("a", sourceFile));
457            });
458            runSingleFileTest("deleteNodeInList11", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
459                changeTracker.delete(sourceFile, findChild("b", sourceFile));
460            });
461            runSingleFileTest("deleteNodeInList12", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
462                changeTracker.delete(sourceFile, findChild("c", sourceFile));
463            });
464        }
465        {
466            const text = `
467function foo(
468    a: number,
469    b: string,
470    c = true) {
471    return 1;
472}`;
473            runSingleFileTest("deleteNodeInList13", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
474                changeTracker.delete(sourceFile, findChild("a", sourceFile));
475            });
476            runSingleFileTest("deleteNodeInList14", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
477                changeTracker.delete(sourceFile, findChild("b", sourceFile));
478            });
479            runSingleFileTest("deleteNodeInList15", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
480                changeTracker.delete(sourceFile, findChild("c", sourceFile));
481            });
482        }
483        {
484            const text = `
485const x = 1, y = 2;`;
486            runSingleFileTest("insertNodeInListAfter1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
487                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1)));
488            });
489            runSingleFileTest("insertNodeInListAfter2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
490                changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1)));
491            });
492        }
493        {
494            const text = `
495const /*x*/ x = 1, /*y*/ y = 2;`;
496            runSingleFileTest("insertNodeInListAfter3", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
497                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1)));
498            });
499            runSingleFileTest("insertNodeInListAfter4", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
500                changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1)));
501            });
502        }
503        {
504            const text = `
505const x = 1;`;
506            runSingleFileTest("insertNodeInListAfter5", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
507                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1)));
508            });
509        }
510        {
511            const text = `
512const x = 1,
513    y = 2;`;
514            runSingleFileTest("insertNodeInListAfter6", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
515                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1)));
516            });
517            runSingleFileTest("insertNodeInListAfter7", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
518                changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1)));
519            });
520        }
521        {
522            const text = `
523const /*x*/ x = 1,
524    /*y*/ y = 2;`;
525            runSingleFileTest("insertNodeInListAfter8", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
526                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1)));
527            });
528            runSingleFileTest("insertNodeInListAfter9", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
529                changeTracker.insertNodeInListAfter(sourceFile, findChild("y", sourceFile), factory.createVariableDeclaration("z", /*exclamationToken*/ undefined, /*type*/ undefined, factory.createNumericLiteral(1)));
530            });
531        }
532        {
533            const text = `
534import {
535    x
536} from "bar"`;
537            runSingleFileTest("insertNodeInListAfter10", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
538                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(factory.createIdentifier("b"), factory.createIdentifier("a")));
539            });
540        }
541        {
542            const text = `
543import {
544    x // this is x
545} from "bar"`;
546            runSingleFileTest("insertNodeInListAfter11", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
547                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(factory.createIdentifier("b"), factory.createIdentifier("a")));
548            });
549        }
550        {
551            const text = `
552import {
553    x
554} from "bar"`;
555            runSingleFileTest("insertNodeInListAfter12", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
556                // eslint-disable-next-line boolean-trivia
557                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(undefined, factory.createIdentifier("a")));
558            });
559        }
560        {
561            const text = `
562import {
563    x // this is x
564} from "bar"`;
565            runSingleFileTest("insertNodeInListAfter13", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
566                // eslint-disable-next-line boolean-trivia
567                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(undefined, factory.createIdentifier("a")));
568            });
569        }
570        {
571            const text = `
572import {
573    x0,
574    x
575} from "bar"`;
576            runSingleFileTest("insertNodeInListAfter14", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
577                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(factory.createIdentifier("b"), factory.createIdentifier("a")));
578            });
579        }
580        {
581            const text = `
582import {
583    x0,
584    x // this is x
585} from "bar"`;
586            runSingleFileTest("insertNodeInListAfter15", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
587                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(factory.createIdentifier("b"), factory.createIdentifier("a")));
588            });
589        }
590        {
591            const text = `
592import {
593    x0,
594    x
595} from "bar"`;
596            runSingleFileTest("insertNodeInListAfter16", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
597                // eslint-disable-next-line boolean-trivia
598                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(undefined, factory.createIdentifier("a")));
599            });
600        }
601        {
602            const text = `
603import {
604    x0,
605    x // this is x
606} from "bar"`;
607            runSingleFileTest("insertNodeInListAfter17", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
608                // eslint-disable-next-line boolean-trivia
609                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(undefined, factory.createIdentifier("a")));
610            });
611        }
612        {
613            const text = `
614import {
615    x0, x
616} from "bar"`;
617            runSingleFileTest("insertNodeInListAfter18", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
618                // eslint-disable-next-line boolean-trivia
619                changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), factory.createImportSpecifier(undefined, factory.createIdentifier("a")));
620            });
621        }
622        {
623            const runTest = (name: string, text: string) => runSingleFileTest(name, /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
624                for (const specifier of ["x3", "x4", "x5"]) {
625                    // eslint-disable-next-line boolean-trivia
626                    changeTracker.insertNodeInListAfter(sourceFile, findChild("x2", sourceFile), factory.createImportSpecifier(undefined, factory.createIdentifier(specifier)));
627                }
628            });
629
630            const crlfText = "import {\r\nx1,\r\nx2\r\n} from \"bar\";";
631            runTest("insertNodeInListAfter19", crlfText);
632
633            const lfText = "import {\nx1,\nx2\n} from \"bar\";";
634            runTest("insertNodeInListAfter20", lfText);
635        }
636        {
637            const text = `
638class A {
639    x;
640}`;
641            runSingleFileTest("insertNodeAfterMultipleNodes", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
642                const newNodes = [];
643                for (let i = 0; i < 11 /*error doesn't occur with fewer nodes*/; ++i) {
644                    newNodes.push(
645                        // eslint-disable-next-line boolean-trivia
646                        factory.createPropertyDeclaration(undefined, undefined, i + "", undefined, undefined, undefined));
647                }
648                const insertAfter = findChild("x", sourceFile);
649                for (const newNode of newNodes) {
650                    changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode);
651                }
652            });
653        }
654        {
655            const text = `
656class A {
657    x
658}
659`;
660            runSingleFileTest("insertNodeAfterInClass1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
661                // eslint-disable-next-line boolean-trivia
662                changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), factory.createPropertyDeclaration(undefined, undefined, "a", undefined, factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword), undefined));
663            });
664        }
665        {
666            const text = `
667class A {
668    x;
669}
670`;
671            runSingleFileTest("insertNodeAfterInClass2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
672                // eslint-disable-next-line boolean-trivia
673                changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), factory.createPropertyDeclaration(undefined, undefined, "a", undefined, factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword), undefined));
674            });
675        }
676        {
677            const text = `
678class A {
679    x;
680    y = 1;
681}
682`;
683            runSingleFileTest("deleteNodeAfterInClass1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
684                deleteNode(changeTracker, sourceFile, findChild("x", sourceFile));
685            });
686        }
687        {
688            const text = `
689class A {
690    x
691    y = 1;
692}
693`;
694            runSingleFileTest("deleteNodeAfterInClass2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
695                deleteNode(changeTracker, sourceFile, findChild("x", sourceFile));
696            });
697        }
698        {
699            const text = `
700class A {
701    x = foo
702}
703`;
704            runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
705                const newNode = factory.createPropertyDeclaration(
706                    /*decorators*/ undefined,
707                    /*modifiers*/ undefined,
708                    factory.createComputedPropertyName(factory.createNumericLiteral(1)),
709                    /*questionToken*/ undefined,
710                    factory.createKeywordTypeNode(SyntaxKind.AnyKeyword),
711                    /*initializer*/ undefined);
712                changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode);
713            });
714        }
715        {
716            const text = `
717class A {
718    x() {
719    }
720}
721`;
722            runSingleFileTest("insertNodeInClassAfterNodeWithoutSeparator2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
723                const newNode = factory.createPropertyDeclaration(
724                    /*decorators*/ undefined,
725                    /*modifiers*/ undefined,
726                    factory.createComputedPropertyName(factory.createNumericLiteral(1)),
727                    /*questionToken*/ undefined,
728                    factory.createKeywordTypeNode(SyntaxKind.AnyKeyword),
729                    /*initializer*/ undefined);
730                changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode);
731            });
732        }
733        {
734            const text = `
735interface A {
736    x
737}
738`;
739            runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
740                const newNode = factory.createPropertyDeclaration(
741                    /*decorators*/ undefined,
742                    /*modifiers*/ undefined,
743                    factory.createComputedPropertyName(factory.createNumericLiteral(1)),
744                    /*questionToken*/ undefined,
745                    factory.createKeywordTypeNode(SyntaxKind.AnyKeyword),
746                    /*initializer*/ undefined);
747                changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode);
748            });
749        }
750        {
751            const text = `
752interface A {
753    x()
754}
755`;
756            runSingleFileTest("insertNodeInInterfaceAfterNodeWithoutSeparator2", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
757                const newNode = factory.createPropertyDeclaration(
758                    /*decorators*/ undefined,
759                    /*modifiers*/ undefined,
760                    factory.createComputedPropertyName(factory.createNumericLiteral(1)),
761                    /*questionToken*/ undefined,
762                    factory.createKeywordTypeNode(SyntaxKind.AnyKeyword),
763                    /*initializer*/ undefined);
764                changeTracker.insertNodeAfter(sourceFile, findChild("x", sourceFile), newNode);
765            });
766        }
767        {
768            const text = `
769let x = foo
770`;
771            runSingleFileTest("insertNodeInStatementListAfterNodeWithoutSeparator1", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
772                const newNode = factory.createExpressionStatement(factory.createParenthesizedExpression(factory.createNumericLiteral(1)));
773                changeTracker.insertNodeAfter(sourceFile, findVariableStatementContaining("x", sourceFile), newNode);
774            });
775        }
776    });
777}
778