1namespace ts { 2 function testExtractRangeFailed(caption: string, s: string, expectedErrors: string[]) { 3 return it(caption, () => { 4 const t = extractTest(s); 5 const file = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true); 6 const selectionRange = t.ranges.get("selection"); 7 if (!selectionRange) { 8 throw new Error(`Test ${s} does not specify selection range`); 9 } 10 const result = refactor.extractSymbol.getRangeToExtract(file, createTextSpanFromRange(selectionRange), /*userRequested*/ false); 11 const sortedErrors = result.errors!.map(e => <string>e.messageText).sort(); 12 assert.deepEqual(sortedErrors, expectedErrors.sort(), "unexpected errors"); 13 }); 14 } 15 16 function testExtractRange(s: string): void { 17 const t = extractTest(s); 18 const f = createSourceFile("a.ts", t.source, ScriptTarget.Latest, /*setParentNodes*/ true); 19 const selectionRange = t.ranges.get("selection"); 20 if (!selectionRange) { 21 throw new Error(`Test ${s} does not specify selection range`); 22 } 23 const result = refactor.extractSymbol.getRangeToExtract(f, createTextSpanFromRange(selectionRange)); 24 const expectedRange = t.ranges.get("extracted"); 25 if (expectedRange) { 26 let pos: number, end: number; 27 const targetRange = result.targetRange!; 28 if (isArray(targetRange.range)) { 29 pos = targetRange.range[0].getStart(f); 30 end = last(targetRange.range).getEnd(); 31 } 32 else { 33 pos = targetRange.range.getStart(f); 34 end = targetRange.range.getEnd(); 35 } 36 assert.equal(pos, expectedRange.pos, "incorrect pos of range"); 37 assert.equal(end, expectedRange.end, "incorrect end of range"); 38 } 39 else { 40 assert.isTrue(!result.targetRange, `expected range to extract to be undefined`); 41 } 42 } 43 44 describe("unittests:: services:: extract:: extractRanges", () => { 45 it("get extract range from selection", () => { 46 testExtractRange(` 47 [#| 48 [$|var x = 1; 49 var y = 2;|]|] 50 `); 51 testExtractRange(` 52 [#| 53 var x = 1; 54 var y = 2|]; 55 `); 56 testExtractRange(` 57 [#|var x = 1|]; 58 var y = 2; 59 `); 60 testExtractRange(` 61 if ([#|[#extracted|a && b && c && d|]|]) { 62 } 63 `); 64 testExtractRange(` 65 if [#|(a && b && c && d|]) { 66 } 67 `); 68 testExtractRange(` 69 if (a && b && c && d) { 70 [#| [$|var x = 1; 71 console.log(x);|] |] 72 } 73 `); 74 testExtractRange(` 75 [#| 76 if (a) { 77 return 100; 78 } |] 79 `); 80 testExtractRange(` 81 function foo() { 82 [#| [$|if (a) { 83 } 84 return 100|] |] 85 } 86 `); 87 testExtractRange(` 88 [#| 89 [$|l1: 90 if (x) { 91 break l1; 92 }|]|] 93 `); 94 testExtractRange(` 95 [#| 96 [$|l2: 97 { 98 if (x) { 99 } 100 break l2; 101 }|]|] 102 `); 103 testExtractRange(` 104 while (true) { 105 [#| if(x) { 106 } 107 break; |] 108 } 109 `); 110 testExtractRange(` 111 while (true) { 112 [#| if(x) { 113 } 114 continue; |] 115 } 116 `); 117 testExtractRange(` 118 l3: 119 { 120 [#| 121 if (x) { 122 } 123 break l3; |] 124 } 125 `); 126 testExtractRange(` 127 function f() { 128 while (true) { 129 [#| 130 if (x) { 131 return; 132 } |] 133 } 134 } 135 `); 136 testExtractRange(` 137 function f() { 138 while (true) { 139 [#| 140 [$|if (x) { 141 } 142 return;|] 143 |] 144 } 145 } 146 `); 147 testExtractRange(` 148 function f() { 149 return [#| [$|1 + 2|] |]+ 3; 150 } 151 } 152 `); 153 testExtractRange(` 154 function f(x: number) { 155 [#|[$|try { 156 x++; 157 } 158 finally { 159 return 1; 160 }|]|] 161 } 162 `); 163 164 // Variable statements 165 testExtractRange(`[#|let x = [$|1|];|]`); 166 testExtractRange(`[#|let x = [$|1|], y;|]`); 167 testExtractRange(`[#|[$|let x = 1, y = 1;|]|]`); 168 169 // Variable declarations 170 testExtractRange(`let [#|x = [$|1|]|];`); 171 testExtractRange(`let [#|x = [$|1|]|], y = 2;`); 172 testExtractRange(`let x = 1, [#|y = [$|2|]|];`); 173 174 // Return statements 175 testExtractRange(`[#|return [$|1|];|]`); 176 }); 177 178 testExtractRangeFailed("extractRangeFailed1", 179 ` 180namespace A { 181function f() { 182 [#| 183 let x = 1 184 if (x) { 185 return 10; 186 } 187 |] 188} 189} 190 `, 191 [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message]); 192 193 testExtractRangeFailed("extractRangeFailed2", 194 ` 195namespace A { 196function f() { 197 while (true) { 198 [#| 199 let x = 1 200 if (x) { 201 break; 202 } 203 |] 204 } 205} 206} 207 `, 208 [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); 209 210 testExtractRangeFailed("extractRangeFailed3", 211 ` 212namespace A { 213function f() { 214 while (true) { 215 [#| 216 let x = 1 217 if (x) { 218 continue; 219 } 220 |] 221 } 222} 223} 224 `, 225 [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); 226 227 testExtractRangeFailed("extractRangeFailed4", 228 ` 229namespace A { 230function f() { 231 l1: { 232 [#| 233 let x = 1 234 if (x) { 235 break l1; 236 } 237 |] 238 } 239} 240} 241 `, 242 [refactor.extractSymbol.Messages.cannotExtractRangeContainingLabeledBreakOrContinueStatementWithTargetOutsideOfTheRange.message]); 243 244 testExtractRangeFailed("extractRangeFailed5", 245 ` 246namespace A { 247function f() { 248 [#| 249 try { 250 f2() 251 return 10; 252 } 253 catch (e) { 254 } 255 |] 256} 257function f2() { 258} 259} 260 `, 261 [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message]); 262 263 testExtractRangeFailed("extractRangeFailed6", 264 ` 265namespace A { 266function f() { 267 [#| 268 try { 269 f2() 270 } 271 catch (e) { 272 return 10; 273 } 274 |] 275} 276function f2() { 277} 278} 279 `, 280 [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalReturnStatement.message]); 281 282 testExtractRangeFailed("extractRangeFailed7", 283 ` 284function test(x: number) { 285while (x) { 286 x--; 287 [#|break;|] 288} 289} 290 `, 291 [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); 292 293 testExtractRangeFailed("extractRangeFailed8", 294 ` 295function test(x: number) { 296switch (x) { 297 case 1: 298 [#|break;|] 299} 300} 301 `, 302 [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); 303 304 testExtractRangeFailed("extractRangeFailed9", 305 `var x = ([#||]1 + 2);`, 306 [refactor.extractSymbol.Messages.cannotExtractEmpty.message]); 307 308 testExtractRangeFailed("extractRangeFailed10", 309 ` 310 function f() { 311 return 1 + [#|2 + 3|]; 312 } 313 } 314 `, 315 [refactor.extractSymbol.Messages.cannotExtractRange.message]); 316 317 testExtractRangeFailed("extractRangeFailed11", 318 ` 319 function f(x: number) { 320 while (true) { 321 [#|try { 322 x++; 323 } 324 finally { 325 break; 326 }|] 327 } 328 } 329 `, 330 [refactor.extractSymbol.Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements.message]); 331 332 testExtractRangeFailed("extractRangeFailed12", 333 `let [#|x|];`, 334 [refactor.extractSymbol.Messages.statementOrExpressionExpected.message]); 335 336 testExtractRangeFailed("extractRangeFailed13", 337 `[#|return;|]`, 338 [refactor.extractSymbol.Messages.cannotExtractRange.message]); 339 340 testExtractRangeFailed("extractRangeFailed14", 341 ` 342 switch(1) { 343 case [#|1: 344 break;|] 345 } 346 `, 347 [refactor.extractSymbol.Messages.cannotExtractRange.message]); 348 349 testExtractRangeFailed("extractRangeFailed15", 350 ` 351 switch(1) { 352 case [#|1: 353 break|]; 354 } 355 `, 356 [refactor.extractSymbol.Messages.cannotExtractRange.message]); 357 358 // Documentation only - it would be nice if the result were [$|1|] 359 testExtractRangeFailed("extractRangeFailed16", 360 ` 361 switch(1) { 362 [#|case 1|]: 363 break; 364 } 365 `, 366 [refactor.extractSymbol.Messages.cannotExtractRange.message]); 367 368 // Documentation only - it would be nice if the result were [$|1|] 369 testExtractRangeFailed("extractRangeFailed17", 370 ` 371 switch(1) { 372 [#|case 1:|] 373 break; 374 } 375 `, 376 [refactor.extractSymbol.Messages.cannotExtractRange.message]); 377 378 testExtractRangeFailed("extractRangeFailed18", 379 `[#|{ 1;|] }`, 380 [refactor.extractSymbol.Messages.cannotExtractRange.message]); 381 382 testExtractRangeFailed("extractRangeFailed19", 383 `[#|/** @type {number} */|] const foo = 1;`, 384 [refactor.extractSymbol.Messages.cannotExtractJSDoc.message]); 385 386 testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, [refactor.extractSymbol.Messages.cannotExtractIdentifier.message]); 387 }); 388} 389