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