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