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