1 //===- unittest/Format/FormatTestJS.cpp - Formatting unit tests for JS ----===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "FormatTestUtils.h" 11 #include "clang/Format/Format.h" 12 #include "llvm/Support/Debug.h" 13 #include "gtest/gtest.h" 14 15 #define DEBUG_TYPE "format-test" 16 17 namespace clang { 18 namespace format { 19 20 class FormatTestJS : public ::testing::Test { 21 protected: 22 static std::string format(llvm::StringRef Code, unsigned Offset, 23 unsigned Length, const FormatStyle &Style) { 24 DEBUG(llvm::errs() << "---\n"); 25 DEBUG(llvm::errs() << Code << "\n\n"); 26 std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length)); 27 bool IncompleteFormat = false; 28 tooling::Replacements Replaces = 29 reformat(Style, Code, Ranges, "<stdin>", &IncompleteFormat); 30 EXPECT_FALSE(IncompleteFormat); 31 auto Result = applyAllReplacements(Code, Replaces); 32 EXPECT_TRUE(static_cast<bool>(Result)); 33 DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); 34 return *Result; 35 } 36 37 static std::string format( 38 llvm::StringRef Code, 39 const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) { 40 return format(Code, 0, Code.size(), Style); 41 } 42 43 static FormatStyle getGoogleJSStyleWithColumns(unsigned ColumnLimit) { 44 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript); 45 Style.ColumnLimit = ColumnLimit; 46 return Style; 47 } 48 49 static void verifyFormat( 50 llvm::StringRef Code, 51 const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) { 52 std::string Result = format(test::messUp(Code), Style); 53 EXPECT_EQ(Code.str(), Result) << "Formatted:\n" << Result; 54 } 55 56 static void verifyFormat( 57 llvm::StringRef Expected, 58 llvm::StringRef Code, 59 const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) { 60 std::string Result = format(Code, Style); 61 EXPECT_EQ(Expected.str(), Result) << "Formatted:\n" << Result; 62 } 63 }; 64 65 TEST_F(FormatTestJS, BlockComments) { 66 verifyFormat("/* aaaaaaaaaaaaa */ aaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" 67 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);"); 68 } 69 70 TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) { 71 verifyFormat("a == = b;"); 72 verifyFormat("a != = b;"); 73 74 verifyFormat("a === b;"); 75 verifyFormat("aaaaaaa ===\n b;", getGoogleJSStyleWithColumns(10)); 76 verifyFormat("a !== b;"); 77 verifyFormat("aaaaaaa !==\n b;", getGoogleJSStyleWithColumns(10)); 78 verifyFormat("if (a + b + c +\n" 79 " d !==\n" 80 " e + f + g)\n" 81 " q();", 82 getGoogleJSStyleWithColumns(20)); 83 84 verifyFormat("a >> >= b;"); 85 86 verifyFormat("a >>> b;"); 87 verifyFormat("aaaaaaa >>>\n b;", getGoogleJSStyleWithColumns(10)); 88 verifyFormat("a >>>= b;"); 89 verifyFormat("aaaaaaa >>>=\n b;", getGoogleJSStyleWithColumns(10)); 90 verifyFormat("if (a + b + c +\n" 91 " d >>>\n" 92 " e + f + g)\n" 93 " q();", 94 getGoogleJSStyleWithColumns(20)); 95 verifyFormat("var x = aaaaaaaaaa ?\n" 96 " bbbbbb :\n" 97 " ccc;", 98 getGoogleJSStyleWithColumns(20)); 99 100 verifyFormat("var b = a.map((x) => x + 1);"); 101 verifyFormat("return ('aaa') in bbbb;"); 102 verifyFormat("var x = aaaaaaaaaaaaaaaaaaaaaaaaa() in\n" 103 " aaaa.aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;"); 104 FormatStyle Style = getGoogleJSStyleWithColumns(80); 105 Style.AlignOperands = true; 106 verifyFormat("var x = aaaaaaaaaaaaaaaaaaaaaaaaa() in\n" 107 " aaaa.aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;", 108 Style); 109 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; 110 verifyFormat("var x = aaaaaaaaaaaaaaaaaaaaaaaaa()\n" 111 " in aaaa.aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;", 112 Style); 113 114 // ES6 spread operator. 115 verifyFormat("someFunction(...a);"); 116 verifyFormat("var x = [1, ...a, 2];"); 117 } 118 119 TEST_F(FormatTestJS, UnderstandsAmpAmp) { 120 verifyFormat("e && e.SomeFunction();"); 121 } 122 123 TEST_F(FormatTestJS, LiteralOperatorsCanBeKeywords) { 124 verifyFormat("not.and.or.not_eq = 1;"); 125 } 126 127 TEST_F(FormatTestJS, ReservedWords) { 128 // JavaScript reserved words (aka keywords) are only illegal when used as 129 // Identifiers, but are legal as IdentifierNames. 130 verifyFormat("x.class.struct = 1;"); 131 verifyFormat("x.case = 1;"); 132 verifyFormat("x.interface = 1;"); 133 verifyFormat("x.for = 1;"); 134 verifyFormat("x.of() = 1;"); 135 verifyFormat("x.in() = 1;"); 136 verifyFormat("x.let() = 1;"); 137 verifyFormat("x.var() = 1;"); 138 verifyFormat("x.for() = 1;"); 139 verifyFormat("x.as() = 1;"); 140 verifyFormat("x = {\n" 141 " a: 12,\n" 142 " interface: 1,\n" 143 " switch: 1,\n" 144 "};"); 145 verifyFormat("var struct = 2;"); 146 verifyFormat("var union = 2;"); 147 verifyFormat("var interface = 2;"); 148 verifyFormat("interface = 2;"); 149 verifyFormat("x = interface instanceof y;"); 150 } 151 152 TEST_F(FormatTestJS, ReservedWordsMethods) { 153 verifyFormat( 154 "class X {\n" 155 " delete() {\n" 156 " x();\n" 157 " }\n" 158 " interface() {\n" 159 " x();\n" 160 " }\n" 161 " let() {\n" 162 " x();\n" 163 " }\n" 164 "}\n"); 165 } 166 167 TEST_F(FormatTestJS, CppKeywords) { 168 // Make sure we don't mess stuff up because of C++ keywords. 169 verifyFormat("return operator && (aa);"); 170 } 171 172 TEST_F(FormatTestJS, ES6DestructuringAssignment) { 173 verifyFormat("var [a, b, c] = [1, 2, 3];"); 174 verifyFormat("const [a, b, c] = [1, 2, 3];"); 175 verifyFormat("let [a, b, c] = [1, 2, 3];"); 176 verifyFormat("var {a, b} = {a: 1, b: 2};"); 177 verifyFormat("let {a, b} = {a: 1, b: 2};"); 178 } 179 180 TEST_F(FormatTestJS, ContainerLiterals) { 181 verifyFormat("var x = {\n" 182 " y: function(a) {\n" 183 " return a;\n" 184 " }\n" 185 "};"); 186 verifyFormat("return {\n" 187 " link: function() {\n" 188 " f(); //\n" 189 " }\n" 190 "};"); 191 verifyFormat("return {\n" 192 " a: a,\n" 193 " link: function() {\n" 194 " f(); //\n" 195 " }\n" 196 "};"); 197 verifyFormat("return {\n" 198 " a: a,\n" 199 " link: function() {\n" 200 " f(); //\n" 201 " },\n" 202 " link: function() {\n" 203 " f(); //\n" 204 " }\n" 205 "};"); 206 verifyFormat("var stuff = {\n" 207 " // comment for update\n" 208 " update: false,\n" 209 " // comment for modules\n" 210 " modules: false,\n" 211 " // comment for tasks\n" 212 " tasks: false\n" 213 "};"); 214 verifyFormat("return {\n" 215 " 'finish':\n" 216 " //\n" 217 " a\n" 218 "};"); 219 verifyFormat("var obj = {\n" 220 " fooooooooo: function(x) {\n" 221 " return x.zIsTooLongForOneLineWithTheDeclarationLine();\n" 222 " }\n" 223 "};"); 224 // Simple object literal, as opposed to enum style below. 225 verifyFormat("var obj = {a: 123};"); 226 // Enum style top level assignment. 227 verifyFormat("X = {\n a: 123\n};"); 228 verifyFormat("X.Y = {\n a: 123\n};"); 229 // But only on the top level, otherwise its a plain object literal assignment. 230 verifyFormat("function x() {\n" 231 " y = {z: 1};\n" 232 "}"); 233 verifyFormat("x = foo && {a: 123};"); 234 235 // Arrow functions in object literals. 236 verifyFormat("var x = {\n" 237 " y: (a) => {\n" 238 " return a;\n" 239 " }\n" 240 "};"); 241 verifyFormat("var x = {y: (a) => a};"); 242 243 // Methods in object literals. 244 verifyFormat("var x = {\n" 245 " y(a: string): number {\n" 246 " return a;\n" 247 " }\n" 248 "};"); 249 verifyFormat("var x = {\n" 250 " y(a: string) {\n" 251 " return a;\n" 252 " }\n" 253 "};"); 254 255 // Computed keys. 256 verifyFormat("var x = {[a]: 1, b: 2, [c]: 3};"); 257 verifyFormat("var x = {\n" 258 " [a]: 1,\n" 259 " b: 2,\n" 260 " [c]: 3,\n" 261 "};"); 262 263 // Object literals can leave out labels. 264 verifyFormat("f({a}, () => {\n" 265 " g(); //\n" 266 "});"); 267 268 // Keys can be quoted. 269 verifyFormat("var x = {\n" 270 " a: a,\n" 271 " b: b,\n" 272 " 'c': c,\n" 273 "};"); 274 275 // Dict literals can skip the label names. 276 verifyFormat("var x = {\n" 277 " aaa,\n" 278 " aaa,\n" 279 " aaa,\n" 280 "};"); 281 } 282 283 TEST_F(FormatTestJS, MethodsInObjectLiterals) { 284 verifyFormat("var o = {\n" 285 " value: 'test',\n" 286 " get value() { // getter\n" 287 " return this.value;\n" 288 " }\n" 289 "};"); 290 verifyFormat("var o = {\n" 291 " value: 'test',\n" 292 " set value(val) { // setter\n" 293 " this.value = val;\n" 294 " }\n" 295 "};"); 296 verifyFormat("var o = {\n" 297 " value: 'test',\n" 298 " someMethod(val) { // method\n" 299 " doSomething(this.value + val);\n" 300 " }\n" 301 "};"); 302 verifyFormat("var o = {\n" 303 " someMethod(val) { // method\n" 304 " doSomething(this.value + val);\n" 305 " },\n" 306 " someOtherMethod(val) { // method\n" 307 " doSomething(this.value + val);\n" 308 " }\n" 309 "};"); 310 } 311 312 TEST_F(FormatTestJS, SpacesInContainerLiterals) { 313 verifyFormat("var arr = [1, 2, 3];"); 314 verifyFormat("f({a: 1, b: 2, c: 3});"); 315 316 verifyFormat("var object_literal_with_long_name = {\n" 317 " a: 'aaaaaaaaaaaaaaaaaa',\n" 318 " b: 'bbbbbbbbbbbbbbbbbb'\n" 319 "};"); 320 321 verifyFormat("f({a: 1, b: 2, c: 3});", 322 getChromiumStyle(FormatStyle::LK_JavaScript)); 323 verifyFormat("f({'a': [{}]});"); 324 } 325 326 TEST_F(FormatTestJS, SingleQuotedStrings) { 327 verifyFormat("this.function('', true);"); 328 } 329 330 TEST_F(FormatTestJS, GoogScopes) { 331 verifyFormat("goog.scope(function() {\n" 332 "var x = a.b;\n" 333 "var y = c.d;\n" 334 "}); // goog.scope"); 335 verifyFormat("goog.scope(function() {\n" 336 "// test\n" 337 "var x = 0;\n" 338 "// test\n" 339 "});"); 340 } 341 342 TEST_F(FormatTestJS, GoogModules) { 343 verifyFormat("goog.module('this.is.really.absurdly.long');", 344 getGoogleJSStyleWithColumns(40)); 345 verifyFormat("goog.require('this.is.really.absurdly.long');", 346 getGoogleJSStyleWithColumns(40)); 347 verifyFormat("goog.provide('this.is.really.absurdly.long');", 348 getGoogleJSStyleWithColumns(40)); 349 verifyFormat("var long = goog.require('this.is.really.absurdly.long');", 350 getGoogleJSStyleWithColumns(40)); 351 verifyFormat("goog.setTestOnly('this.is.really.absurdly.long');", 352 getGoogleJSStyleWithColumns(40)); 353 verifyFormat("goog.forwardDeclare('this.is.really.absurdly.long');", 354 getGoogleJSStyleWithColumns(40)); 355 356 // These should be wrapped normally. 357 verifyFormat( 358 "var MyLongClassName =\n" 359 " goog.module.get('my.long.module.name.followedBy.MyLongClassName');"); 360 } 361 362 TEST_F(FormatTestJS, FormatsNamespaces) { 363 verifyFormat("namespace Foo {\n" 364 " export let x = 1;\n" 365 "}\n"); 366 verifyFormat("declare namespace Foo {\n" 367 " export let x: number;\n" 368 "}\n"); 369 } 370 371 TEST_F(FormatTestJS, NamespacesMayNotWrap) { 372 verifyFormat("declare namespace foobarbaz {\n" 373 "}\n", getGoogleJSStyleWithColumns(18)); 374 verifyFormat("declare module foobarbaz {\n" 375 "}\n", getGoogleJSStyleWithColumns(15)); 376 verifyFormat("namespace foobarbaz {\n" 377 "}\n", getGoogleJSStyleWithColumns(10)); 378 verifyFormat("module foobarbaz {\n" 379 "}\n", getGoogleJSStyleWithColumns(7)); 380 } 381 382 TEST_F(FormatTestJS, AmbientDeclarations) { 383 FormatStyle NineCols = getGoogleJSStyleWithColumns(9); 384 verifyFormat( 385 "declare class\n" 386 " X {}", 387 NineCols); 388 verifyFormat( 389 "declare function\n" 390 "x();", // TODO(martinprobst): should ideally be indented. 391 NineCols); 392 verifyFormat("declare function foo();\n" 393 "let x = 1;\n"); 394 verifyFormat("declare function foo(): string;\n" 395 "let x = 1;\n"); 396 verifyFormat("declare function foo(): {x: number};\n" 397 "let x = 1;\n"); 398 verifyFormat("declare class X {}\n" 399 "let x = 1;\n"); 400 verifyFormat("declare interface Y {}\n" 401 "let x = 1;\n"); 402 verifyFormat( 403 "declare enum X {\n" 404 "}", 405 NineCols); 406 verifyFormat( 407 "declare let\n" 408 " x: number;", 409 NineCols); 410 } 411 412 TEST_F(FormatTestJS, FormatsFreestandingFunctions) { 413 verifyFormat("function outer1(a, b) {\n" 414 " function inner1(a, b) {\n" 415 " return a;\n" 416 " }\n" 417 " inner1(a, b);\n" 418 "}\n" 419 "function outer2(a, b) {\n" 420 " function inner2(a, b) {\n" 421 " return a;\n" 422 " }\n" 423 " inner2(a, b);\n" 424 "}"); 425 verifyFormat("function f() {}"); 426 } 427 428 TEST_F(FormatTestJS, GeneratorFunctions) { 429 verifyFormat("function* f() {\n" 430 " let x = 1;\n" 431 " yield x;\n" 432 " yield* something();\n" 433 " yield [1, 2];\n" 434 " yield {a: 1};\n" 435 "}"); 436 verifyFormat("function*\n" 437 " f() {\n" 438 "}", 439 getGoogleJSStyleWithColumns(8)); 440 verifyFormat("export function* f() {\n" 441 " yield 1;\n" 442 "}\n"); 443 verifyFormat("class X {\n" 444 " * generatorMethod() {\n" 445 " yield x;\n" 446 " }\n" 447 "}"); 448 verifyFormat("var x = {\n" 449 " a: function*() {\n" 450 " //\n" 451 " }\n" 452 "}\n"); 453 } 454 455 TEST_F(FormatTestJS, AsyncFunctions) { 456 verifyFormat("async function f() {\n" 457 " let x = 1;\n" 458 " return fetch(x);\n" 459 "}"); 460 verifyFormat("async function* f() {\n" 461 " yield fetch(x);\n" 462 "}"); 463 verifyFormat("export async function f() {\n" 464 " return fetch(x);\n" 465 "}"); 466 verifyFormat("let x = async () => f();"); 467 verifyFormat("let x = async();"); 468 verifyFormat("class X {\n" 469 " async asyncMethod() {\n" 470 " return fetch(1);\n" 471 " }\n" 472 "}"); 473 verifyFormat("function initialize() {\n" 474 " // Comment.\n" 475 " return async.then();\n" 476 "}\n"); 477 } 478 479 TEST_F(FormatTestJS, ArrayLiterals) { 480 verifyFormat("var aaaaa: List<SomeThing> =\n" 481 " [new SomeThingAAAAAAAAAAAA(), new SomeThingBBBBBBBBB()];"); 482 verifyFormat("return [\n" 483 " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n" 484 " ccccccccccccccccccccccccccc\n" 485 "];"); 486 verifyFormat("return [\n" 487 " aaaa().bbbbbbbb('A'),\n" 488 " aaaa().bbbbbbbb('B'),\n" 489 " aaaa().bbbbbbbb('C'),\n" 490 "];"); 491 verifyFormat("var someVariable = SomeFunction([\n" 492 " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n" 493 " ccccccccccccccccccccccccccc\n" 494 "]);"); 495 verifyFormat("var someVariable = SomeFunction([\n" 496 " [aaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbb],\n" 497 "]);", 498 getGoogleJSStyleWithColumns(51)); 499 verifyFormat("var someVariable = SomeFunction(aaaa, [\n" 500 " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n" 501 " ccccccccccccccccccccccccccc\n" 502 "]);"); 503 verifyFormat("var someVariable = SomeFunction(\n" 504 " aaaa,\n" 505 " [\n" 506 " aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbb,\n" 507 " cccccccccccccccccccccccccc\n" 508 " ],\n" 509 " aaaa);"); 510 verifyFormat("var aaaa = aaaaa || // wrap\n" 511 " [];"); 512 513 verifyFormat("someFunction([], {a: a});"); 514 515 verifyFormat("var string = [\n" 516 " 'aaaaaa',\n" 517 " 'bbbbbb',\n" 518 "].join('+');"); 519 } 520 521 TEST_F(FormatTestJS, ColumnLayoutForArrayLiterals) { 522 verifyFormat("var array = [\n" 523 " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n" 524 " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n" 525 "];"); 526 verifyFormat("var array = someFunction([\n" 527 " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n" 528 " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n" 529 "]);"); 530 } 531 532 TEST_F(FormatTestJS, FunctionLiterals) { 533 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript); 534 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; 535 verifyFormat("doFoo(function() {});"); 536 verifyFormat("doFoo(function() { return 1; });", Style); 537 verifyFormat("var func = function() {\n" 538 " return 1;\n" 539 "};"); 540 verifyFormat("var func = //\n" 541 " function() {\n" 542 " return 1;\n" 543 "};"); 544 verifyFormat("return {\n" 545 " body: {\n" 546 " setAttribute: function(key, val) { this[key] = val; },\n" 547 " getAttribute: function(key) { return this[key]; },\n" 548 " style: {direction: ''}\n" 549 " }\n" 550 "};", 551 Style); 552 verifyFormat("abc = xyz ? function() {\n" 553 " return 1;\n" 554 "} : function() {\n" 555 " return -1;\n" 556 "};"); 557 558 verifyFormat("var closure = goog.bind(\n" 559 " function() { // comment\n" 560 " foo();\n" 561 " bar();\n" 562 " },\n" 563 " this, arg1IsReallyLongAndNeedsLineBreaks,\n" 564 " arg3IsReallyLongAndNeedsLineBreaks);"); 565 verifyFormat("var closure = goog.bind(function() { // comment\n" 566 " foo();\n" 567 " bar();\n" 568 "}, this);"); 569 verifyFormat("return {\n" 570 " a: 'E',\n" 571 " b: function() {\n" 572 " return function() {\n" 573 " f(); //\n" 574 " };\n" 575 " }\n" 576 "};"); 577 verifyFormat("{\n" 578 " var someVariable = function(x) {\n" 579 " return x.zIsTooLongForOneLineWithTheDeclarationLine();\n" 580 " };\n" 581 "}"); 582 verifyFormat("someLooooooooongFunction(\n" 583 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" 584 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" 585 " function(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n" 586 " // code\n" 587 " });"); 588 589 verifyFormat("return {\n" 590 " a: function SomeFunction() {\n" 591 " // ...\n" 592 " return 1;\n" 593 " }\n" 594 "};"); 595 verifyFormat("this.someObject.doSomething(aaaaaaaaaaaaaaaaaaaaaaaaaa)\n" 596 " .then(goog.bind(function(aaaaaaaaaaa) {\n" 597 " someFunction();\n" 598 " someFunction();\n" 599 " }, this), aaaaaaaaaaaaaaaaa);"); 600 601 verifyFormat("someFunction(goog.bind(function() {\n" 602 " doSomething();\n" 603 " doSomething();\n" 604 "}, this), goog.bind(function() {\n" 605 " doSomething();\n" 606 " doSomething();\n" 607 "}, this));"); 608 609 verifyFormat("SomeFunction(function() {\n" 610 " foo();\n" 611 " bar();\n" 612 "}.bind(this));"); 613 614 // FIXME: This is bad, we should be wrapping before "function() {". 615 verifyFormat("someFunction(function() {\n" 616 " doSomething(); // break\n" 617 "})\n" 618 " .doSomethingElse(\n" 619 " // break\n" 620 " );"); 621 622 Style.ColumnLimit = 33; 623 verifyFormat("f({a: function() { return 1; }});", Style); 624 Style.ColumnLimit = 32; 625 verifyFormat("f({\n" 626 " a: function() { return 1; }\n" 627 "});", 628 Style); 629 630 } 631 632 TEST_F(FormatTestJS, InliningFunctionLiterals) { 633 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript); 634 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; 635 verifyFormat("var func = function() {\n" 636 " return 1;\n" 637 "};", 638 Style); 639 verifyFormat("var func = doSomething(function() { return 1; });", Style); 640 verifyFormat("var outer = function() {\n" 641 " var inner = function() { return 1; }\n" 642 "};", 643 Style); 644 verifyFormat("function outer1(a, b) {\n" 645 " function inner1(a, b) { return a; }\n" 646 "}", 647 Style); 648 649 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; 650 verifyFormat("var func = function() { return 1; };", Style); 651 verifyFormat("var func = doSomething(function() { return 1; });", Style); 652 verifyFormat( 653 "var outer = function() { var inner = function() { return 1; } };", 654 Style); 655 verifyFormat("function outer1(a, b) {\n" 656 " function inner1(a, b) { return a; }\n" 657 "}", 658 Style); 659 660 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None; 661 verifyFormat("var func = function() {\n" 662 " return 1;\n" 663 "};", 664 Style); 665 verifyFormat("var func = doSomething(function() {\n" 666 " return 1;\n" 667 "});", 668 Style); 669 verifyFormat("var outer = function() {\n" 670 " var inner = function() {\n" 671 " return 1;\n" 672 " }\n" 673 "};", 674 Style); 675 verifyFormat("function outer1(a, b) {\n" 676 " function inner1(a, b) {\n" 677 " return a;\n" 678 " }\n" 679 "}", 680 Style); 681 682 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty; 683 verifyFormat("var func = function() {\n" 684 " return 1;\n" 685 "};", 686 Style); 687 } 688 689 TEST_F(FormatTestJS, MultipleFunctionLiterals) { 690 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript); 691 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All; 692 verifyFormat("promise.then(\n" 693 " function success() {\n" 694 " doFoo();\n" 695 " doBar();\n" 696 " },\n" 697 " function error() {\n" 698 " doFoo();\n" 699 " doBaz();\n" 700 " },\n" 701 " []);\n"); 702 verifyFormat("promise.then(\n" 703 " function success() {\n" 704 " doFoo();\n" 705 " doBar();\n" 706 " },\n" 707 " [],\n" 708 " function error() {\n" 709 " doFoo();\n" 710 " doBaz();\n" 711 " });\n"); 712 verifyFormat("promise.then(\n" 713 " [],\n" 714 " function success() {\n" 715 " doFoo();\n" 716 " doBar();\n" 717 " },\n" 718 " function error() {\n" 719 " doFoo();\n" 720 " doBaz();\n" 721 " });\n"); 722 723 verifyFormat("getSomeLongPromise()\n" 724 " .then(function(value) { body(); })\n" 725 " .thenCatch(function(error) {\n" 726 " body();\n" 727 " body();\n" 728 " });", 729 Style); 730 verifyFormat("getSomeLongPromise()\n" 731 " .then(function(value) {\n" 732 " body();\n" 733 " body();\n" 734 " })\n" 735 " .thenCatch(function(error) {\n" 736 " body();\n" 737 " body();\n" 738 " });"); 739 740 verifyFormat("getSomeLongPromise()\n" 741 " .then(function(value) { body(); })\n" 742 " .thenCatch(function(error) { body(); });", 743 Style); 744 745 verifyFormat("return [aaaaaaaaaaaaaaaaaaaaaa]\n" 746 " .aaaaaaa(function() {\n" 747 " //\n" 748 " })\n" 749 " .bbbbbb();"); 750 } 751 752 TEST_F(FormatTestJS, ArrowFunctions) { 753 verifyFormat("var x = (a) => {\n" 754 " return a;\n" 755 "};"); 756 verifyFormat("var x = (a) => {\n" 757 " function y() {\n" 758 " return 42;\n" 759 " }\n" 760 " return a;\n" 761 "};"); 762 verifyFormat("var x = (a: type): {some: type} => {\n" 763 " return a;\n" 764 "};"); 765 verifyFormat("var x = (a) => a;"); 766 verifyFormat("return () => [];"); 767 verifyFormat("var aaaaaaaaaaaaaaaaaaaa = {\n" 768 " aaaaaaaaaaaaaaaaaaaaaaaaaaaa:\n" 769 " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" 770 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =>\n" 771 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" 772 "};"); 773 verifyFormat("var a = a.aaaaaaa(\n" 774 " (a: a) => aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) &&\n" 775 " aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbb));"); 776 verifyFormat("var a = a.aaaaaaa(\n" 777 " (a: a) => aaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) ?\n" 778 " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb) :\n" 779 " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));"); 780 781 // FIXME: This is bad, we should be wrapping before "() => {". 782 verifyFormat("someFunction(() => {\n" 783 " doSomething(); // break\n" 784 "})\n" 785 " .doSomethingElse(\n" 786 " // break\n" 787 " );"); 788 } 789 790 TEST_F(FormatTestJS, ReturnStatements) { 791 verifyFormat("function() {\n" 792 " return [hello, world];\n" 793 "}"); 794 } 795 796 TEST_F(FormatTestJS, ForLoops) { 797 verifyFormat("for (var i in [2, 3]) {\n" 798 "}"); 799 verifyFormat("for (var i of [2, 3]) {\n" 800 "}"); 801 verifyFormat("for (let {a, b} of x) {\n" 802 "}"); 803 verifyFormat("for (let {a, b} in x) {\n" 804 "}"); 805 } 806 807 TEST_F(FormatTestJS, WrapRespectsAutomaticSemicolonInsertion) { 808 // The following statements must not wrap, as otherwise the program meaning 809 // would change due to automatic semicolon insertion. 810 // See http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1. 811 verifyFormat("return aaaaa;", getGoogleJSStyleWithColumns(10)); 812 verifyFormat("return /* hello! */ aaaaa;", getGoogleJSStyleWithColumns(10)); 813 verifyFormat("continue aaaaa;", getGoogleJSStyleWithColumns(10)); 814 verifyFormat("continue /* hello! */ aaaaa;", getGoogleJSStyleWithColumns(10)); 815 verifyFormat("break aaaaa;", getGoogleJSStyleWithColumns(10)); 816 verifyFormat("throw aaaaa;", getGoogleJSStyleWithColumns(10)); 817 verifyFormat("aaaaaaaaa++;", getGoogleJSStyleWithColumns(10)); 818 verifyFormat("aaaaaaaaa--;", getGoogleJSStyleWithColumns(10)); 819 verifyFormat("return [\n" 820 " aaa\n" 821 "];", 822 getGoogleJSStyleWithColumns(12)); 823 } 824 825 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) { 826 verifyFormat("a\n" 827 "b;", 828 " a \n" 829 " b ;"); 830 verifyFormat("a()\n" 831 "b;", 832 " a ()\n" 833 " b ;"); 834 verifyFormat("a[b]\n" 835 "c;", 836 "a [b]\n" 837 "c ;"); 838 verifyFormat("1\n" 839 "a;", 840 "1 \n" 841 "a ;"); 842 verifyFormat("a\n" 843 "1;", 844 "a \n" 845 "1 ;"); 846 verifyFormat("a\n" 847 "'x';", 848 "a \n" 849 " 'x';"); 850 verifyFormat("a++\n" 851 "b;", 852 "a ++\n" 853 "b ;"); 854 verifyFormat("a\n" 855 "!b && c;", 856 "a \n" 857 " ! b && c;"); 858 verifyFormat("a\n" 859 "if (1) f();", 860 " a\n" 861 " if (1) f();"); 862 verifyFormat("a\n" 863 "class X {}", 864 " a\n" 865 " class X {}"); 866 verifyFormat("var a", "var\n" 867 "a"); 868 verifyFormat("x instanceof String", "x\n" 869 "instanceof\n" 870 "String"); 871 verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n" 872 " bar) {}"); 873 verifyFormat("a = true\n" 874 "return 1", 875 "a = true\n" 876 " return 1"); 877 verifyFormat("a = 's'\n" 878 "return 1", 879 "a = 's'\n" 880 " return 1"); 881 verifyFormat("a = null\n" 882 "return 1", 883 "a = null\n" 884 " return 1"); 885 // Below "class Y {}" should ideally be on its own line. 886 verifyFormat( 887 "x = {\n" 888 " a: 1\n" 889 "} class Y {}", 890 " x = {a : 1}\n" 891 " class Y { }"); 892 verifyFormat( 893 "if (x) {\n" 894 "}\n" 895 "return 1", 896 "if (x) {}\n" 897 " return 1"); 898 verifyFormat( 899 "if (x) {\n" 900 "}\n" 901 "class X {}", 902 "if (x) {}\n" 903 " class X {}"); 904 } 905 906 TEST_F(FormatTestJS, ImportExportASI) { 907 verifyFormat( 908 "import {x} from 'y'\n" 909 "export function z() {}", 910 "import {x} from 'y'\n" 911 " export function z() {}"); 912 // Below "class Y {}" should ideally be on its own line. 913 verifyFormat( 914 "export {x} class Y {}", 915 " export {x}\n" 916 " class Y {\n}"); 917 verifyFormat( 918 "if (x) {\n" 919 "}\n" 920 "export class Y {}", 921 "if ( x ) { }\n" 922 " export class Y {}"); 923 } 924 925 TEST_F(FormatTestJS, ClosureStyleCasts) { 926 verifyFormat("var x = /** @type {foo} */ (bar);"); 927 } 928 929 TEST_F(FormatTestJS, TryCatch) { 930 verifyFormat("try {\n" 931 " f();\n" 932 "} catch (e) {\n" 933 " g();\n" 934 "} finally {\n" 935 " h();\n" 936 "}"); 937 938 // But, of course, "catch" is a perfectly fine function name in JavaScript. 939 verifyFormat("someObject.catch();"); 940 verifyFormat("someObject.new();"); 941 verifyFormat("someObject.delete();"); 942 } 943 944 TEST_F(FormatTestJS, StringLiteralConcatenation) { 945 verifyFormat("var literal = 'hello ' +\n" 946 " 'world';"); 947 } 948 949 TEST_F(FormatTestJS, RegexLiteralClassification) { 950 // Regex literals. 951 verifyFormat("var regex = /abc/;"); 952 verifyFormat("f(/abc/);"); 953 verifyFormat("f(abc, /abc/);"); 954 verifyFormat("some_map[/abc/];"); 955 verifyFormat("var x = a ? /abc/ : /abc/;"); 956 verifyFormat("for (var i = 0; /abc/.test(s[i]); i++) {\n}"); 957 verifyFormat("var x = !/abc/.test(y);"); 958 verifyFormat("var x = foo()! / 10;"); 959 verifyFormat("var x = a && /abc/.test(y);"); 960 verifyFormat("var x = a || /abc/.test(y);"); 961 verifyFormat("var x = a + /abc/.search(y);"); 962 verifyFormat("/abc/.search(y);"); 963 verifyFormat("var regexs = {/abc/, /abc/};"); 964 verifyFormat("return /abc/;"); 965 966 // Not regex literals. 967 verifyFormat("var a = a / 2 + b / 3;"); 968 verifyFormat("var a = a++ / 2;"); 969 // Prefix unary can operate on regex literals, not that it makes sense. 970 verifyFormat("var a = ++/a/;"); 971 972 // This is a known issue, regular expressions are incorrectly detected if 973 // directly following a closing parenthesis. 974 verifyFormat("if (foo) / bar /.exec(baz);"); 975 } 976 977 TEST_F(FormatTestJS, RegexLiteralSpecialCharacters) { 978 verifyFormat("var regex = /=/;"); 979 verifyFormat("var regex = /a*/;"); 980 verifyFormat("var regex = /a+/;"); 981 verifyFormat("var regex = /a?/;"); 982 verifyFormat("var regex = /.a./;"); 983 verifyFormat("var regex = /a\\*/;"); 984 verifyFormat("var regex = /^a$/;"); 985 verifyFormat("var regex = /\\/a/;"); 986 verifyFormat("var regex = /(?:x)/;"); 987 verifyFormat("var regex = /x(?=y)/;"); 988 verifyFormat("var regex = /x(?!y)/;"); 989 verifyFormat("var regex = /x|y/;"); 990 verifyFormat("var regex = /a{2}/;"); 991 verifyFormat("var regex = /a{1,3}/;"); 992 993 verifyFormat("var regex = /[abc]/;"); 994 verifyFormat("var regex = /[^abc]/;"); 995 verifyFormat("var regex = /[\\b]/;"); 996 verifyFormat("var regex = /[/]/;"); 997 verifyFormat("var regex = /[\\/]/;"); 998 verifyFormat("var regex = /\\[/;"); 999 verifyFormat("var regex = /\\\\[/]/;"); 1000 verifyFormat("var regex = /}[\"]/;"); 1001 verifyFormat("var regex = /}[/\"]/;"); 1002 verifyFormat("var regex = /}[\"/]/;"); 1003 1004 verifyFormat("var regex = /\\b/;"); 1005 verifyFormat("var regex = /\\B/;"); 1006 verifyFormat("var regex = /\\d/;"); 1007 verifyFormat("var regex = /\\D/;"); 1008 verifyFormat("var regex = /\\f/;"); 1009 verifyFormat("var regex = /\\n/;"); 1010 verifyFormat("var regex = /\\r/;"); 1011 verifyFormat("var regex = /\\s/;"); 1012 verifyFormat("var regex = /\\S/;"); 1013 verifyFormat("var regex = /\\t/;"); 1014 verifyFormat("var regex = /\\v/;"); 1015 verifyFormat("var regex = /\\w/;"); 1016 verifyFormat("var regex = /\\W/;"); 1017 verifyFormat("var regex = /a(a)\\1/;"); 1018 verifyFormat("var regex = /\\0/;"); 1019 verifyFormat("var regex = /\\\\/g;"); 1020 verifyFormat("var regex = /\\a\\\\/g;"); 1021 verifyFormat("var regex = /\a\\//g;"); 1022 verifyFormat("var regex = /a\\//;\n" 1023 "var x = 0;"); 1024 verifyFormat("var regex = /'/g;", "var regex = /'/g ;"); 1025 verifyFormat("var regex = /'/g; //'", "var regex = /'/g ; //'"); 1026 verifyFormat("var regex = /\\/*/;\n" 1027 "var x = 0;", 1028 "var regex = /\\/*/;\n" 1029 "var x=0;"); 1030 verifyFormat("var x = /a\\//;", "var x = /a\\// \n;"); 1031 verifyFormat("var regex = /\"/;", getGoogleJSStyleWithColumns(16)); 1032 verifyFormat("var regex =\n" 1033 " /\"/;", 1034 getGoogleJSStyleWithColumns(15)); 1035 verifyFormat("var regex = //\n" 1036 " /a/;"); 1037 verifyFormat("var regexs = [\n" 1038 " /d/, //\n" 1039 " /aa/, //\n" 1040 "];"); 1041 } 1042 1043 TEST_F(FormatTestJS, RegexLiteralModifiers) { 1044 verifyFormat("var regex = /abc/g;"); 1045 verifyFormat("var regex = /abc/i;"); 1046 verifyFormat("var regex = /abc/m;"); 1047 verifyFormat("var regex = /abc/y;"); 1048 } 1049 1050 TEST_F(FormatTestJS, RegexLiteralLength) { 1051 verifyFormat("var regex = /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;", 1052 getGoogleJSStyleWithColumns(60)); 1053 verifyFormat("var regex =\n" 1054 " /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;", 1055 getGoogleJSStyleWithColumns(60)); 1056 verifyFormat("var regex = /\\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;", 1057 getGoogleJSStyleWithColumns(50)); 1058 } 1059 1060 TEST_F(FormatTestJS, RegexLiteralExamples) { 1061 verifyFormat("var regex = search.match(/(?:\?|&)times=([^?&]+)/i);"); 1062 } 1063 1064 TEST_F(FormatTestJS, IgnoresMpegTS) { 1065 std::string MpegTS(200, ' '); 1066 MpegTS.replace(0, strlen("nearlyLooks + like + ts + code; "), 1067 "nearlyLooks + like + ts + code; "); 1068 MpegTS[0] = 0x47; 1069 MpegTS[188] = 0x47; 1070 verifyFormat(MpegTS, MpegTS); 1071 } 1072 1073 TEST_F(FormatTestJS, TypeAnnotations) { 1074 verifyFormat("var x: string;"); 1075 verifyFormat("var x: {a: string; b: number;} = {};"); 1076 verifyFormat("function x(): string {\n return 'x';\n}"); 1077 verifyFormat("function x(): {x: string} {\n return {x: 'x'};\n}"); 1078 verifyFormat("function x(y: string): string {\n return 'x';\n}"); 1079 verifyFormat("for (var y: string in x) {\n x();\n}"); 1080 verifyFormat("for (var y: string of x) {\n x();\n}"); 1081 verifyFormat("function x(y: {a?: number;} = {}): number {\n" 1082 " return 12;\n" 1083 "}"); 1084 verifyFormat("((a: string, b: number): string => a + b);"); 1085 verifyFormat("var x: (y: number) => string;"); 1086 verifyFormat("var x: P<string, (a: number) => string>;"); 1087 verifyFormat("var x = {\n" 1088 " y: function(): z {\n" 1089 " return 1;\n" 1090 " }\n" 1091 "};"); 1092 verifyFormat("var x = {\n" 1093 " y: function(): {a: number} {\n" 1094 " return 1;\n" 1095 " }\n" 1096 "};"); 1097 verifyFormat("function someFunc(args: string[]):\n" 1098 " {longReturnValue: string[]} {}", 1099 getGoogleJSStyleWithColumns(60)); 1100 verifyFormat( 1101 "var someValue = (v as aaaaaaaaaaaaaaaaaaaa<T>[])\n" 1102 " .someFunction(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);"); 1103 } 1104 1105 TEST_F(FormatTestJS, UnionIntersectionTypes) { 1106 verifyFormat("let x: A|B = A | B;"); 1107 verifyFormat("let x: A&B|C = A & B;"); 1108 verifyFormat("let x: Foo<A|B> = new Foo<A|B>();"); 1109 verifyFormat("function(x: A|B): C&D {}"); 1110 verifyFormat("function(x: A|B = A | B): C&D {}"); 1111 verifyFormat("function x(path: number|string) {}"); 1112 verifyFormat("function x(): string|number {}"); 1113 verifyFormat("type Foo = Bar|Baz;"); 1114 verifyFormat("type Foo = Bar<X>|Baz;"); 1115 verifyFormat("type Foo = (Bar<X>|Baz);"); 1116 verifyFormat("let x: Bar|Baz;"); 1117 verifyFormat("let x: Bar<X>|Baz;"); 1118 verifyFormat("let x: (Foo|Bar)[];"); 1119 } 1120 1121 TEST_F(FormatTestJS, ClassDeclarations) { 1122 verifyFormat("class C {\n x: string = 12;\n}"); 1123 verifyFormat("class C {\n x(): string => 12;\n}"); 1124 verifyFormat("class C {\n ['x' + 2]: string = 12;\n}"); 1125 verifyFormat("class C {\n private x: string = 12;\n}"); 1126 verifyFormat("class C {\n private static x: string = 12;\n}"); 1127 verifyFormat("class C {\n static x(): string {\n return 'asd';\n }\n}"); 1128 verifyFormat("class C extends P implements I {}"); 1129 verifyFormat("class C extends p.P implements i.I {}"); 1130 verifyFormat( 1131 "x(class {\n" 1132 " a(): A {}\n" 1133 "});"); 1134 verifyFormat("class Test {\n" 1135 " aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaa):\n" 1136 " aaaaaaaaaaaaaaaaaaaaaa {}\n" 1137 "}"); 1138 verifyFormat("foo = class Name {\n" 1139 " constructor() {}\n" 1140 "};"); 1141 verifyFormat("foo = class {\n" 1142 " constructor() {}\n" 1143 "};"); 1144 verifyFormat("class C {\n" 1145 " x: {y: Z;} = {};\n" 1146 " private y: {y: Z;} = {};\n" 1147 "}"); 1148 1149 // ':' is not a type declaration here. 1150 verifyFormat("class X {\n" 1151 " subs = {\n" 1152 " 'b': {\n" 1153 " 'c': 1,\n" 1154 " },\n" 1155 " };\n" 1156 "}"); 1157 verifyFormat("@Component({\n" 1158 " moduleId: module.id,\n" 1159 "})\n" 1160 "class SessionListComponent implements OnDestroy, OnInit {\n" 1161 "}"); 1162 } 1163 1164 TEST_F(FormatTestJS, InterfaceDeclarations) { 1165 verifyFormat("interface I {\n" 1166 " x: string;\n" 1167 " enum: string[];\n" 1168 " enum?: string[];\n" 1169 "}\n" 1170 "var y;"); 1171 // Ensure that state is reset after parsing the interface. 1172 verifyFormat("interface a {}\n" 1173 "export function b() {}\n" 1174 "var x;"); 1175 1176 // Arrays of object type literals. 1177 verifyFormat("interface I {\n" 1178 " o: {}[];\n" 1179 "}"); 1180 } 1181 1182 TEST_F(FormatTestJS, EnumDeclarations) { 1183 verifyFormat("enum Foo {\n" 1184 " A = 1,\n" 1185 " B\n" 1186 "}"); 1187 verifyFormat("export /* somecomment*/ enum Foo {\n" 1188 " A = 1,\n" 1189 " B\n" 1190 "}"); 1191 verifyFormat("enum Foo {\n" 1192 " A = 1, // comment\n" 1193 " B\n" 1194 "}\n" 1195 "var x = 1;"); 1196 } 1197 1198 TEST_F(FormatTestJS, MetadataAnnotations) { 1199 verifyFormat("@A\nclass C {\n}"); 1200 verifyFormat("@A({arg: 'value'})\nclass C {\n}"); 1201 verifyFormat("@A\n@B\nclass C {\n}"); 1202 verifyFormat("class C {\n @A x: string;\n}"); 1203 verifyFormat("class C {\n" 1204 " @A\n" 1205 " private x(): string {\n" 1206 " return 'y';\n" 1207 " }\n" 1208 "}"); 1209 verifyFormat("class C {\n" 1210 " private x(@A x: string) {}\n" 1211 "}"); 1212 verifyFormat("class X {}\n" 1213 "class Y {}"); 1214 } 1215 1216 TEST_F(FormatTestJS, TypeAliases) { 1217 verifyFormat("type X = number;\n" 1218 "class C {}"); 1219 verifyFormat("type X<Y> = Z<Y>;"); 1220 verifyFormat("type X = {\n" 1221 " y: number\n" 1222 "};\n" 1223 "class C {}"); 1224 } 1225 1226 TEST_F(FormatTestJS, Modules) { 1227 verifyFormat("import SomeThing from 'some/module.js';"); 1228 verifyFormat("import {X, Y} from 'some/module.js';"); 1229 verifyFormat("import a, {X, Y} from 'some/module.js';"); 1230 verifyFormat("import {X, Y,} from 'some/module.js';"); 1231 verifyFormat("import {X as myLocalX, Y as myLocalY} from 'some/module.js';"); 1232 // Ensure Automatic Semicolon Insertion does not break on "as\n". 1233 verifyFormat("import {X as myX} from 'm';", "import {X as\n" 1234 " myX} from 'm';"); 1235 verifyFormat("import * as lib from 'some/module.js';"); 1236 verifyFormat("var x = {import: 1};\nx.import = 2;"); 1237 1238 verifyFormat("export function fn() {\n" 1239 " return 'fn';\n" 1240 "}"); 1241 verifyFormat("export function A() {}\n" 1242 "export default function B() {}\n" 1243 "export function C() {}"); 1244 verifyFormat("export default () => {\n" 1245 " let x = 1;\n" 1246 " return x;\n" 1247 "}"); 1248 verifyFormat("export const x = 12;"); 1249 verifyFormat("export default class X {}"); 1250 verifyFormat("export {X, Y} from 'some/module.js';"); 1251 verifyFormat("export {X, Y,} from 'some/module.js';"); 1252 verifyFormat("export {SomeVeryLongExport as X, " 1253 "SomeOtherVeryLongExport as Y} from 'some/module.js';"); 1254 // export without 'from' is wrapped. 1255 verifyFormat("export let someRatherLongVariableName =\n" 1256 " someSurprisinglyLongVariable + someOtherRatherLongVar;"); 1257 // ... but not if from is just an identifier. 1258 verifyFormat("export {\n" 1259 " from as from,\n" 1260 " someSurprisinglyLongVariable as\n" 1261 " from\n" 1262 "};", 1263 getGoogleJSStyleWithColumns(20)); 1264 verifyFormat("export class C {\n" 1265 " x: number;\n" 1266 " y: string;\n" 1267 "}"); 1268 verifyFormat("export class X { y: number; }"); 1269 verifyFormat("export abstract class X { y: number; }"); 1270 verifyFormat("export default class X { y: number }"); 1271 verifyFormat("export default function() {\n return 1;\n}"); 1272 verifyFormat("export var x = 12;"); 1273 verifyFormat("class C {}\n" 1274 "export function f() {}\n" 1275 "var v;"); 1276 verifyFormat("export var x: number = 12;"); 1277 verifyFormat("export const y = {\n" 1278 " a: 1,\n" 1279 " b: 2\n" 1280 "};"); 1281 verifyFormat("export enum Foo {\n" 1282 " BAR,\n" 1283 " // adsdasd\n" 1284 " BAZ\n" 1285 "}"); 1286 verifyFormat("export default [\n" 1287 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n" 1288 " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n" 1289 "];"); 1290 verifyFormat("export default [];"); 1291 verifyFormat("export default () => {};"); 1292 verifyFormat("export interface Foo { foo: number; }\n" 1293 "export class Bar {\n" 1294 " blah(): string {\n" 1295 " return this.blah;\n" 1296 " };\n" 1297 "}"); 1298 } 1299 1300 TEST_F(FormatTestJS, ImportWrapping) { 1301 verifyFormat("import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying," 1302 " VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying" 1303 "} from 'some/module.js';"); 1304 FormatStyle Style = getGoogleJSStyleWithColumns(80); 1305 Style.JavaScriptWrapImports = true; 1306 verifyFormat("import {\n" 1307 " VeryLongImportsAreAnnoying,\n" 1308 " VeryLongImportsAreAnnoying,\n" 1309 " VeryLongImportsAreAnnoying,\n" 1310 "} from 'some/module.js';", 1311 Style); 1312 verifyFormat("import {\n" 1313 " A,\n" 1314 " A,\n" 1315 "} from 'some/module.js';", 1316 Style); 1317 verifyFormat("export {\n" 1318 " A,\n" 1319 " A,\n" 1320 "} from 'some/module.js';", 1321 Style); 1322 } 1323 1324 TEST_F(FormatTestJS, TemplateStrings) { 1325 // Keeps any whitespace/indentation within the template string. 1326 verifyFormat("var x = `hello\n" 1327 " ${name}\n" 1328 " !`;", 1329 "var x = `hello\n" 1330 " ${ name }\n" 1331 " !`;"); 1332 1333 verifyFormat("var x =\n" 1334 " `hello ${world}` >= some();", 1335 getGoogleJSStyleWithColumns(34)); // Barely doesn't fit. 1336 verifyFormat("var x = `hello ${world}` >= some();", 1337 getGoogleJSStyleWithColumns(35)); // Barely fits. 1338 verifyFormat("var x = `hellö ${wörld}` >= söme();", 1339 getGoogleJSStyleWithColumns(35)); // Fits due to UTF-8. 1340 verifyFormat("var x = `hello\n" 1341 " ${world}` >=\n" 1342 " some();", 1343 "var x =\n" 1344 " `hello\n" 1345 " ${world}` >= some();", 1346 getGoogleJSStyleWithColumns(21)); // Barely doesn't fit. 1347 verifyFormat("var x = `hello\n" 1348 " ${world}` >= some();", 1349 "var x =\n" 1350 " `hello\n" 1351 " ${world}` >= some();", 1352 getGoogleJSStyleWithColumns(22)); // Barely fits. 1353 1354 verifyFormat("var x =\n" 1355 " `h`;", 1356 getGoogleJSStyleWithColumns(11)); 1357 verifyFormat("var x =\n `multi\n line`;", "var x = `multi\n line`;", 1358 getGoogleJSStyleWithColumns(13)); 1359 verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" 1360 " `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`);"); 1361 // Repro for an obscure width-miscounting issue with template strings. 1362 verifyFormat( 1363 "someLongVariable =\n" 1364 " " 1365 "`${logPrefix[11]}/${logPrefix[12]}/${logPrefix[13]}${logPrefix[14]}`;", 1366 "someLongVariable = " 1367 "`${logPrefix[11]}/${logPrefix[12]}/${logPrefix[13]}${logPrefix[14]}`;"); 1368 1369 // Make sure template strings get a proper ColumnWidth assigned, even if they 1370 // are first token in line. 1371 verifyFormat( 1372 "var a = aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n" 1373 " `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`;"); 1374 1375 // Two template strings. 1376 verifyFormat("var x = `hello` == `hello`;"); 1377 1378 // Comments in template strings. 1379 verifyFormat("var x = `//a`;\n" 1380 "var y;", 1381 "var x =\n `//a`;\n" 1382 "var y ;"); 1383 verifyFormat("var x = `/*a`;\n" 1384 "var y;", 1385 "var x =\n `/*a`;\n" 1386 "var y;"); 1387 // Unterminated string literals in a template string. 1388 verifyFormat("var x = `'`; // comment with matching quote '\n" 1389 "var y;"); 1390 verifyFormat("var x = `\"`; // comment with matching quote \"\n" 1391 "var y;"); 1392 verifyFormat("it(`'aaaaaaaaaaaaaaa `, aaaaaaaaa);", 1393 "it(`'aaaaaaaaaaaaaaa `, aaaaaaaaa) ;", 1394 getGoogleJSStyleWithColumns(40)); 1395 // Backticks in a comment - not a template string. 1396 verifyFormat("var x = 1 // `/*a`;\n" 1397 " ;", 1398 "var x =\n 1 // `/*a`;\n" 1399 " ;"); 1400 verifyFormat("/* ` */ var x = 1; /* ` */", "/* ` */ var x\n= 1; /* ` */"); 1401 // Comment spans multiple template strings. 1402 verifyFormat("var x = `/*a`;\n" 1403 "var y = ` */ `;", 1404 "var x =\n `/*a`;\n" 1405 "var y =\n ` */ `;"); 1406 // Escaped backtick. 1407 verifyFormat("var x = ` \\` a`;\n" 1408 "var y;", 1409 "var x = ` \\` a`;\n" 1410 "var y;"); 1411 // Escaped dollar. 1412 verifyFormat("var x = ` \\${foo}`;\n"); 1413 1414 // The token stream can contain two string_literals in sequence, but that 1415 // doesn't mean that they are implicitly concatenated in JavaScript. 1416 verifyFormat("var f = `aaaa ${a ? 'a' : 'b'}`;"); 1417 1418 // Ensure that scopes are appropriately set around evaluated expressions in 1419 // template strings. 1420 verifyFormat("var f = `aaaaaaaaaaaaa:${aaaaaaa.aaaaa} aaaaaaaa\n" 1421 " aaaaaaaaaaaaa:${aaaaaaa.aaaaa} aaaaaaaa`;", 1422 "var f = `aaaaaaaaaaaaa:${aaaaaaa. aaaaa} aaaaaaaa\n" 1423 " aaaaaaaaaaaaa:${ aaaaaaa. aaaaa} aaaaaaaa`;"); 1424 verifyFormat("var x = someFunction(`${})`) //\n" 1425 " .oooooooooooooooooon();"); 1426 verifyFormat("var x = someFunction(`${aaaa}${\n" 1427 " aaaaa( //\n" 1428 " aaaaa)\n" 1429 " })`);"); 1430 } 1431 1432 TEST_F(FormatTestJS, TemplateStringMultiLineExpression) { 1433 verifyFormat("var f = `aaaaaaaaaaaaaaaaaa: ${\n" 1434 " aaaaa + //\n" 1435 " bbbb\n" 1436 " }`;", 1437 "var f = `aaaaaaaaaaaaaaaaaa: ${aaaaa + //\n" 1438 " bbbb}`;"); 1439 verifyFormat("var f = `\n" 1440 " aaaaaaaaaaaaaaaaaa: ${\n" 1441 " aaaaa + //\n" 1442 " bbbb\n" 1443 " }`;", 1444 "var f = `\n" 1445 " aaaaaaaaaaaaaaaaaa: ${ aaaaa + //\n" 1446 " bbbb }`;"); 1447 verifyFormat("var f = `\n" 1448 " aaaaaaaaaaaaaaaaaa: ${\n" 1449 " someFunction(\n" 1450 " aaaaa + //\n" 1451 " bbbb)\n" 1452 " }`;", 1453 "var f = `\n" 1454 " aaaaaaaaaaaaaaaaaa: ${someFunction (\n" 1455 " aaaaa + //\n" 1456 " bbbb)}`;"); 1457 1458 // It might be preferable to wrap before "someFunction". 1459 verifyFormat("var f = `\n" 1460 " aaaaaaaaaaaaaaaaaa: ${someFunction({\n" 1461 " aaaa: aaaaa,\n" 1462 " bbbb: bbbbb,\n" 1463 " })}`;", 1464 "var f = `\n" 1465 " aaaaaaaaaaaaaaaaaa: ${someFunction ({\n" 1466 " aaaa: aaaaa,\n" 1467 " bbbb: bbbbb,\n" 1468 " })}`;"); 1469 } 1470 1471 TEST_F(FormatTestJS, TemplateStringASI) { 1472 verifyFormat("var x = `hello${world}`;", "var x = `hello${\n" 1473 " world\n" 1474 "}`;"); 1475 } 1476 1477 TEST_F(FormatTestJS, NestedTemplateStrings) { 1478 verifyFormat( 1479 "var x = `<ul>${xs.map(x => `<li>${x}</li>`).join('\\n')}</ul>`;"); 1480 verifyFormat("var x = `he${({text: 'll'}.text)}o`;"); 1481 1482 // Crashed at some point. 1483 verifyFormat("}"); 1484 } 1485 1486 TEST_F(FormatTestJS, TaggedTemplateStrings) { 1487 verifyFormat("var x = html`<ul>`;"); 1488 } 1489 1490 TEST_F(FormatTestJS, CastSyntax) { 1491 verifyFormat("var x = <type>foo;"); 1492 verifyFormat("var x = foo as type;"); 1493 verifyFormat("let x = (a + b) as\n" 1494 " LongTypeIsLong;", 1495 getGoogleJSStyleWithColumns(20)); 1496 verifyFormat("foo = <Bar[]>[\n" 1497 " 1, //\n" 1498 " 2\n" 1499 "];"); 1500 verifyFormat("var x = [{x: 1} as type];"); 1501 verifyFormat("x = x as [a, b];"); 1502 verifyFormat("x = x as {a: string};"); 1503 verifyFormat("x = x as (string);"); 1504 verifyFormat("x = x! as (string);"); 1505 verifyFormat("var x = something.someFunction() as\n" 1506 " something;", 1507 getGoogleJSStyleWithColumns(40)); 1508 } 1509 1510 TEST_F(FormatTestJS, TypeArguments) { 1511 verifyFormat("class X<Y> {}"); 1512 verifyFormat("new X<Y>();"); 1513 verifyFormat("foo<Y>(a);"); 1514 verifyFormat("var x: X<Y>[];"); 1515 verifyFormat("class C extends D<E> implements F<G>, H<I> {}"); 1516 verifyFormat("function f(a: List<any> = null) {}"); 1517 verifyFormat("function f(): List<any> {}"); 1518 verifyFormat("function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa():\n" 1519 " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {}"); 1520 verifyFormat("function aaaaaaaaaa(\n" 1521 " aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaa,\n" 1522 " aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaa):\n" 1523 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {}"); 1524 } 1525 1526 TEST_F(FormatTestJS, UserDefinedTypeGuards) { 1527 verifyFormat( 1528 "function foo(check: Object):\n" 1529 " check is {foo: string, bar: string, baz: string, foobar: string} {\n" 1530 " return 'bar' in check;\n" 1531 "}\n"); 1532 } 1533 1534 TEST_F(FormatTestJS, OptionalTypes) { 1535 verifyFormat("function x(a?: b, c?, d?) {}"); 1536 verifyFormat("class X {\n" 1537 " y?: z;\n" 1538 " z?;\n" 1539 "}"); 1540 verifyFormat("interface X {\n" 1541 " y?(): z;\n" 1542 "}"); 1543 verifyFormat("constructor({aa}: {\n" 1544 " aa?: string,\n" 1545 " aaaaaaaa?: string,\n" 1546 " aaaaaaaaaaaaaaa?: boolean,\n" 1547 " aaaaaa?: List<string>\n" 1548 "}) {}"); 1549 } 1550 1551 TEST_F(FormatTestJS, IndexSignature) { 1552 verifyFormat("var x: {[k: string]: v};"); 1553 } 1554 1555 TEST_F(FormatTestJS, WrapAfterParen) { 1556 verifyFormat("xxxxxxxxxxx(\n" 1557 " aaa, aaa);", 1558 getGoogleJSStyleWithColumns(20)); 1559 verifyFormat("xxxxxxxxxxx(\n" 1560 " aaa, aaa, aaa,\n" 1561 " aaa, aaa, aaa);", 1562 getGoogleJSStyleWithColumns(20)); 1563 verifyFormat("xxxxxxxxxxx(\n" 1564 " aaaaaaaaaaaaaaaaaaaaaaaa,\n" 1565 " function(x) {\n" 1566 " y(); //\n" 1567 " });", 1568 getGoogleJSStyleWithColumns(40)); 1569 verifyFormat("while (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&\n" 1570 " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}"); 1571 } 1572 1573 TEST_F(FormatTestJS, JSDocAnnotations) { 1574 verifyFormat("/**\n" 1575 " * @export {this.is.a.long.path.to.a.Type}\n" 1576 " */", 1577 "/**\n" 1578 " * @export {this.is.a.long.path.to.a.Type}\n" 1579 " */", 1580 getGoogleJSStyleWithColumns(20)); 1581 verifyFormat("/**\n" 1582 " * @mods {this.is.a.long.path.to.a.Type}\n" 1583 " */", 1584 "/**\n" 1585 " * @mods {this.is.a.long.path.to.a.Type}\n" 1586 " */", 1587 getGoogleJSStyleWithColumns(20)); 1588 verifyFormat("/**\n" 1589 " * @param {this.is.a.long.path.to.a.Type}\n" 1590 " */", 1591 "/**\n" 1592 " * @param {this.is.a.long.path.to.a.Type}\n" 1593 " */", 1594 getGoogleJSStyleWithColumns(20)); 1595 verifyFormat( 1596 "/**\n" 1597 " * @param This is a\n" 1598 " * long comment but\n" 1599 " * no type\n" 1600 " */", 1601 "/**\n" 1602 " * @param This is a long comment but no type\n" 1603 " */", 1604 getGoogleJSStyleWithColumns(20)); 1605 } 1606 1607 TEST_F(FormatTestJS, RequoteStringsSingle) { 1608 verifyFormat("var x = 'foo';", "var x = \"foo\";"); 1609 verifyFormat("var x = 'fo\\'o\\'';", "var x = \"fo'o'\";"); 1610 verifyFormat("var x = 'fo\\'o\\'';", "var x = \"fo\\'o'\";"); 1611 verifyFormat( 1612 "var x =\n" 1613 " 'foo\\'';", 1614 // Code below is 15 chars wide, doesn't fit into the line with the 1615 // \ escape added. 1616 "var x = \"foo'\";", getGoogleJSStyleWithColumns(15)); 1617 // Removes no-longer needed \ escape from ". 1618 verifyFormat("var x = 'fo\"o';", "var x = \"fo\\\"o\";"); 1619 // Code below fits into 15 chars *after* removing the \ escape. 1620 verifyFormat("var x = 'fo\"o';", "var x = \"fo\\\"o\";", 1621 getGoogleJSStyleWithColumns(15)); 1622 verifyFormat("// clang-format off\n" 1623 "let x = \"double\";\n" 1624 "// clang-format on\n" 1625 "let x = 'single';\n", 1626 "// clang-format off\n" 1627 "let x = \"double\";\n" 1628 "// clang-format on\n" 1629 "let x = \"single\";\n"); 1630 } 1631 1632 TEST_F(FormatTestJS, RequoteAndIndent) { 1633 verifyFormat("let x = someVeryLongFunctionThatGoesOnAndOn(\n" 1634 " 'double quoted string that needs wrapping');", 1635 "let x = someVeryLongFunctionThatGoesOnAndOn(" 1636 "\"double quoted string that needs wrapping\");"); 1637 1638 verifyFormat("let x =\n" 1639 " 'foo\\'oo';\n" 1640 "let x =\n" 1641 " 'foo\\'oo';", 1642 "let x=\"foo'oo\";\n" 1643 "let x=\"foo'oo\";", 1644 getGoogleJSStyleWithColumns(15)); 1645 } 1646 1647 TEST_F(FormatTestJS, RequoteStringsDouble) { 1648 FormatStyle DoubleQuotes = getGoogleStyle(FormatStyle::LK_JavaScript); 1649 DoubleQuotes.JavaScriptQuotes = FormatStyle::JSQS_Double; 1650 verifyFormat("var x = \"foo\";", DoubleQuotes); 1651 verifyFormat("var x = \"foo\";", "var x = 'foo';", DoubleQuotes); 1652 verifyFormat("var x = \"fo'o\";", "var x = 'fo\\'o';", DoubleQuotes); 1653 } 1654 1655 TEST_F(FormatTestJS, RequoteStringsLeave) { 1656 FormatStyle LeaveQuotes = getGoogleStyle(FormatStyle::LK_JavaScript); 1657 LeaveQuotes.JavaScriptQuotes = FormatStyle::JSQS_Leave; 1658 verifyFormat("var x = \"foo\";", LeaveQuotes); 1659 verifyFormat("var x = 'foo';", LeaveQuotes); 1660 } 1661 1662 TEST_F(FormatTestJS, SupportShebangLines) { 1663 verifyFormat("#!/usr/bin/env node\n" 1664 "var x = hello();", 1665 "#!/usr/bin/env node\n" 1666 "var x = hello();"); 1667 } 1668 1669 TEST_F(FormatTestJS, NonNullAssertionOperator) { 1670 verifyFormat("let x = foo!.bar();\n"); 1671 verifyFormat("let x = foo ? bar! : baz;\n"); 1672 verifyFormat("let x = !foo;\n"); 1673 verifyFormat("let x = foo[0]!;\n"); 1674 verifyFormat("let x = (foo)!;\n"); 1675 verifyFormat("let x = foo! - 1;\n"); 1676 verifyFormat("let x = {foo: 1}!;\n"); 1677 } 1678 1679 TEST_F(FormatTestJS, Conditional) { 1680 verifyFormat("y = x ? 1 : 2;"); 1681 verifyFormat("x ? 1 : 2;"); 1682 verifyFormat("class Foo {\n" 1683 " field = true ? 1 : 2;\n" 1684 " method(a = true ? 1 : 2) {}\n" 1685 "}"); 1686 } 1687 1688 TEST_F(FormatTestJS, ImportComments) { 1689 verifyFormat("import {x} from 'x'; // from some location", 1690 getGoogleJSStyleWithColumns(25)); 1691 verifyFormat("// taze: x from 'location'", getGoogleJSStyleWithColumns(10)); 1692 } 1693 1694 } // end namespace tooling 1695 } // end namespace clang 1696