xref: /llvm-project/clang/unittests/Format/FormatTestJS.cpp (revision 265309e38a99a74d872a818b1c49085165e4e1ac)
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     std::string Result = applyAllReplacements(Code, Replaces);
32     EXPECT_NE("", 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     EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
53   }
54 };
55 
56 TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
57   verifyFormat("a == = b;");
58   verifyFormat("a != = b;");
59 
60   verifyFormat("a === b;");
61   verifyFormat("aaaaaaa ===\n    b;", getGoogleJSStyleWithColumns(10));
62   verifyFormat("a !== b;");
63   verifyFormat("aaaaaaa !==\n    b;", getGoogleJSStyleWithColumns(10));
64   verifyFormat("if (a + b + c +\n"
65                "        d !==\n"
66                "    e + f + g)\n"
67                "  q();",
68                getGoogleJSStyleWithColumns(20));
69 
70   verifyFormat("a >> >= b;");
71 
72   verifyFormat("a >>> b;");
73   verifyFormat("aaaaaaa >>>\n    b;", getGoogleJSStyleWithColumns(10));
74   verifyFormat("a >>>= b;");
75   verifyFormat("aaaaaaa >>>=\n    b;", getGoogleJSStyleWithColumns(10));
76   verifyFormat("if (a + b + c +\n"
77                "        d >>>\n"
78                "    e + f + g)\n"
79                "  q();",
80                getGoogleJSStyleWithColumns(20));
81   verifyFormat("var x = aaaaaaaaaa ?\n"
82                "            bbbbbb :\n"
83                "            ccc;",
84                getGoogleJSStyleWithColumns(20));
85 
86   verifyFormat("var b = a.map((x) => x + 1);");
87   verifyFormat("return ('aaa') in bbbb;");
88 
89   // ES6 spread operator.
90   verifyFormat("someFunction(...a);");
91   verifyFormat("var x = [1, ...a, 2];");
92 }
93 
94 TEST_F(FormatTestJS, UnderstandsAmpAmp) {
95   verifyFormat("e && e.SomeFunction();");
96 }
97 
98 TEST_F(FormatTestJS, LiteralOperatorsCanBeKeywords) {
99   verifyFormat("not.and.or.not_eq = 1;");
100 }
101 
102 TEST_F(FormatTestJS, ReservedWords) {
103   // JavaScript reserved words (aka keywords) are only illegal when used as
104   // Identifiers, but are legal as IdentifierNames.
105   verifyFormat("x.class.struct = 1;");
106   verifyFormat("x.case = 1;");
107   verifyFormat("x.interface = 1;");
108   verifyFormat("x = {\n"
109                "  a: 12,\n"
110                "  interface: 1,\n"
111                "  switch: 1,\n"
112                "};");
113 }
114 
115 TEST_F(FormatTestJS, ES6DestructuringAssignment) {
116   verifyFormat("var [a, b, c] = [1, 2, 3];");
117   verifyFormat("let [a, b, c] = [1, 2, 3];");
118   verifyFormat("var {a, b} = {a: 1, b: 2};");
119   verifyFormat("let {a, b} = {a: 1, b: 2};");
120 }
121 
122 TEST_F(FormatTestJS, ContainerLiterals) {
123   verifyFormat("var x = {y: function(a) { return a; }};");
124   verifyFormat("return {\n"
125                "  link: function() {\n"
126                "    f();  //\n"
127                "  }\n"
128                "};");
129   verifyFormat("return {\n"
130                "  a: a,\n"
131                "  link: function() {\n"
132                "    f();  //\n"
133                "  }\n"
134                "};");
135   verifyFormat("return {\n"
136                "  a: a,\n"
137                "  link: function() {\n"
138                "    f();  //\n"
139                "  },\n"
140                "  link: function() {\n"
141                "    f();  //\n"
142                "  }\n"
143                "};");
144   verifyFormat("var stuff = {\n"
145                "  // comment for update\n"
146                "  update: false,\n"
147                "  // comment for modules\n"
148                "  modules: false,\n"
149                "  // comment for tasks\n"
150                "  tasks: false\n"
151                "};");
152   verifyFormat("return {\n"
153                "  'finish':\n"
154                "      //\n"
155                "      a\n"
156                "};");
157   verifyFormat("var obj = {\n"
158                "  fooooooooo: function(x) {\n"
159                "    return x.zIsTooLongForOneLineWithTheDeclarationLine();\n"
160                "  }\n"
161                "};");
162   // Simple object literal, as opposed to enum style below.
163   verifyFormat("var obj = {a: 123};");
164   // Enum style top level assignment.
165   verifyFormat("X = {\n  a: 123\n};");
166   verifyFormat("X.Y = {\n  a: 123\n};");
167   // But only on the top level, otherwise its a plain object literal assignment.
168   verifyFormat("function x() {\n"
169                "  y = {z: 1};\n"
170                "}");
171   verifyFormat("x = foo && {a: 123};");
172 
173   // Arrow functions in object literals.
174   verifyFormat("var x = {y: (a) => { return a; }};");
175   verifyFormat("var x = {y: (a) => a};");
176 
177   // Computed keys.
178   verifyFormat("var x = {[a]: 1, b: 2, [c]: 3};");
179   verifyFormat("var x = {\n"
180                "  [a]: 1,\n"
181                "  b: 2,\n"
182                "  [c]: 3,\n"
183                "};");
184 }
185 
186 TEST_F(FormatTestJS, MethodsInObjectLiterals) {
187   verifyFormat("var o = {\n"
188                "  value: 'test',\n"
189                "  get value() {  // getter\n"
190                "    return this.value;\n"
191                "  }\n"
192                "};");
193   verifyFormat("var o = {\n"
194                "  value: 'test',\n"
195                "  set value(val) {  // setter\n"
196                "    this.value = val;\n"
197                "  }\n"
198                "};");
199   verifyFormat("var o = {\n"
200                "  value: 'test',\n"
201                "  someMethod(val) {  // method\n"
202                "    doSomething(this.value + val);\n"
203                "  }\n"
204                "};");
205   verifyFormat("var o = {\n"
206                "  someMethod(val) {  // method\n"
207                "    doSomething(this.value + val);\n"
208                "  },\n"
209                "  someOtherMethod(val) {  // method\n"
210                "    doSomething(this.value + val);\n"
211                "  }\n"
212                "};");
213 }
214 
215 TEST_F(FormatTestJS, SpacesInContainerLiterals) {
216   verifyFormat("var arr = [1, 2, 3];");
217   verifyFormat("f({a: 1, b: 2, c: 3});");
218 
219   verifyFormat("var object_literal_with_long_name = {\n"
220                "  a: 'aaaaaaaaaaaaaaaaaa',\n"
221                "  b: 'bbbbbbbbbbbbbbbbbb'\n"
222                "};");
223 
224   verifyFormat("f({a: 1, b: 2, c: 3});",
225                getChromiumStyle(FormatStyle::LK_JavaScript));
226   verifyFormat("f({'a': [{}]});");
227 }
228 
229 TEST_F(FormatTestJS, SingleQuoteStrings) {
230   verifyFormat("this.function('', true);");
231 }
232 
233 TEST_F(FormatTestJS, GoogScopes) {
234   verifyFormat("goog.scope(function() {\n"
235                "var x = a.b;\n"
236                "var y = c.d;\n"
237                "});  // goog.scope");
238   verifyFormat("goog.scope(function() {\n"
239                "// test\n"
240                "var x = 0;\n"
241                "// test\n"
242                "});");
243 }
244 
245 TEST_F(FormatTestJS, GoogModules) {
246   verifyFormat("goog.module('this.is.really.absurdly.long');",
247                getGoogleJSStyleWithColumns(40));
248   verifyFormat("goog.require('this.is.really.absurdly.long');",
249                getGoogleJSStyleWithColumns(40));
250   verifyFormat("goog.provide('this.is.really.absurdly.long');",
251                getGoogleJSStyleWithColumns(40));
252   verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
253                getGoogleJSStyleWithColumns(40));
254 
255   // These should be wrapped normally.
256   verifyFormat(
257       "var MyLongClassName =\n"
258       "    goog.module.get('my.long.module.name.followedBy.MyLongClassName');");
259 }
260 
261 TEST_F(FormatTestJS, FormatsFreestandingFunctions) {
262   verifyFormat("function outer1(a, b) {\n"
263                "  function inner1(a, b) { return a; }\n"
264                "  inner1(a, b);\n"
265                "}\n"
266                "function outer2(a, b) {\n"
267                "  function inner2(a, b) { return a; }\n"
268                "  inner2(a, b);\n"
269                "}");
270   verifyFormat("function f() {}");
271 }
272 
273 TEST_F(FormatTestJS, ArrayLiterals) {
274   verifyFormat("var aaaaa: List<SomeThing> =\n"
275                "    [new SomeThingAAAAAAAAAAAA(), new SomeThingBBBBBBBBB()];");
276   verifyFormat("return [\n"
277                "  aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
278                "  bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
279                "  ccccccccccccccccccccccccccc\n"
280                "];");
281   verifyFormat("var someVariable = SomeFuntion([\n"
282                "  aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
283                "  bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
284                "  ccccccccccccccccccccccccccc\n"
285                "]);");
286   verifyFormat("var someVariable = SomeFuntion([\n"
287                "  [aaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbb],\n"
288                "]);",
289                getGoogleJSStyleWithColumns(51));
290   verifyFormat("var someVariable = SomeFuntion(aaaa, [\n"
291                "  aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
292                "  bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
293                "  ccccccccccccccccccccccccccc\n"
294                "]);");
295   verifyFormat("var someVariable = SomeFuntion(aaaa,\n"
296                "                               [\n"
297                "                                 aaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
298                "                                 bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
299                "                                 ccccccccccccccccccccccccccc\n"
300                "                               ],\n"
301                "                               aaaa);");
302 
303   verifyFormat("someFunction([], {a: a});");
304 }
305 
306 TEST_F(FormatTestJS, FunctionLiterals) {
307   verifyFormat("doFoo(function() {});");
308   verifyFormat("doFoo(function() { return 1; });");
309   verifyFormat("var func = function() {\n"
310                "  return 1;\n"
311                "};");
312   verifyFormat("var func =  //\n"
313                "    function() {\n"
314                "  return 1;\n"
315                "};");
316   verifyFormat("return {\n"
317                "  body: {\n"
318                "    setAttribute: function(key, val) { this[key] = val; },\n"
319                "    getAttribute: function(key) { return this[key]; },\n"
320                "    style: {direction: ''}\n"
321                "  }\n"
322                "};");
323   EXPECT_EQ("abc = xyz ?\n"
324             "          function() {\n"
325             "            return 1;\n"
326             "          } :\n"
327             "          function() {\n"
328             "            return -1;\n"
329             "          };",
330             format("abc=xyz?function(){return 1;}:function(){return -1;};"));
331 
332   verifyFormat("var closure = goog.bind(\n"
333                "    function() {  // comment\n"
334                "      foo();\n"
335                "      bar();\n"
336                "    },\n"
337                "    this, arg1IsReallyLongAndNeeedsLineBreaks,\n"
338                "    arg3IsReallyLongAndNeeedsLineBreaks);");
339   verifyFormat("var closure = goog.bind(function() {  // comment\n"
340                "  foo();\n"
341                "  bar();\n"
342                "}, this);");
343   verifyFormat("return {\n"
344                "  a: 'E',\n"
345                "  b: function() {\n"
346                "    return function() {\n"
347                "      f();  //\n"
348                "    };\n"
349                "  }\n"
350                "};");
351   verifyFormat("{\n"
352                "  var someVariable = function(x) {\n"
353                "    return x.zIsTooLongForOneLineWithTheDeclarationLine();\n"
354                "  };\n"
355                "}");
356   verifyFormat("someLooooooooongFunction(\n"
357                "    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
358                "    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
359                "    function(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n"
360                "      // code\n"
361                "    });");
362 
363   verifyFormat("f({a: function() { return 1; }});",
364                getGoogleJSStyleWithColumns(33));
365   verifyFormat("f({\n"
366                "  a: function() { return 1; }\n"
367                "});",
368                getGoogleJSStyleWithColumns(32));
369 
370   verifyFormat("return {\n"
371                "  a: function SomeFunction() {\n"
372                "    // ...\n"
373                "    return 1;\n"
374                "  }\n"
375                "};");
376   verifyFormat("this.someObject.doSomething(aaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
377                "    .then(goog.bind(function(aaaaaaaaaaa) {\n"
378                "      someFunction();\n"
379                "      someFunction();\n"
380                "    }, this), aaaaaaaaaaaaaaaaa);");
381 
382   // FIXME: This is not ideal yet.
383   verifyFormat("someFunction(goog.bind(\n"
384                "                 function() {\n"
385                "                   doSomething();\n"
386                "                   doSomething();\n"
387                "                 },\n"
388                "                 this),\n"
389                "             goog.bind(function() {\n"
390                "               doSomething();\n"
391                "               doSomething();\n"
392                "             }, this));");
393 
394   // FIXME: This is bad, we should be wrapping before "function() {".
395   verifyFormat("someFunction(function() {\n"
396                "  doSomething();  // break\n"
397                "})\n"
398                "    .doSomethingElse(\n"
399                "        // break\n"
400                "        );");
401 }
402 
403 TEST_F(FormatTestJS, InliningFunctionLiterals) {
404   FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
405   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
406   verifyFormat("var func = function() {\n"
407                "  return 1;\n"
408                "};",
409                Style);
410   verifyFormat("var func = doSomething(function() { return 1; });", Style);
411   verifyFormat("var outer = function() {\n"
412                "  var inner = function() { return 1; }\n"
413                "};",
414                Style);
415   verifyFormat("function outer1(a, b) {\n"
416                "  function inner1(a, b) { return a; }\n"
417                "}",
418                Style);
419 
420   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
421   verifyFormat("var func = function() { return 1; };", Style);
422   verifyFormat("var func = doSomething(function() { return 1; });", Style);
423   verifyFormat(
424       "var outer = function() { var inner = function() { return 1; } };",
425       Style);
426   verifyFormat("function outer1(a, b) {\n"
427                "  function inner1(a, b) { return a; }\n"
428                "}",
429                Style);
430 
431   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
432   verifyFormat("var func = function() {\n"
433                "  return 1;\n"
434                "};",
435                Style);
436   verifyFormat("var func = doSomething(function() {\n"
437                "  return 1;\n"
438                "});",
439                Style);
440   verifyFormat("var outer = function() {\n"
441                "  var inner = function() {\n"
442                "    return 1;\n"
443                "  }\n"
444                "};",
445                Style);
446   verifyFormat("function outer1(a, b) {\n"
447                "  function inner1(a, b) {\n"
448                "    return a;\n"
449                "  }\n"
450                "}",
451                Style);
452 }
453 
454 TEST_F(FormatTestJS, MultipleFunctionLiterals) {
455   verifyFormat("promise.then(\n"
456                "    function success() {\n"
457                "      doFoo();\n"
458                "      doBar();\n"
459                "    },\n"
460                "    function error() {\n"
461                "      doFoo();\n"
462                "      doBaz();\n"
463                "    },\n"
464                "    []);\n");
465   verifyFormat("promise.then(\n"
466                "    function success() {\n"
467                "      doFoo();\n"
468                "      doBar();\n"
469                "    },\n"
470                "    [],\n"
471                "    function error() {\n"
472                "      doFoo();\n"
473                "      doBaz();\n"
474                "    });\n");
475   // FIXME: Here, we should probably break right after the "(" for consistency.
476   verifyFormat("promise.then([],\n"
477                "             function success() {\n"
478                "               doFoo();\n"
479                "               doBar();\n"
480                "             },\n"
481                "             function error() {\n"
482                "               doFoo();\n"
483                "               doBaz();\n"
484                "             });\n");
485 
486   verifyFormat("getSomeLongPromise()\n"
487                "    .then(function(value) { body(); })\n"
488                "    .thenCatch(function(error) {\n"
489                "      body();\n"
490                "      body();\n"
491                "    });");
492   verifyFormat("getSomeLongPromise()\n"
493                "    .then(function(value) {\n"
494                "      body();\n"
495                "      body();\n"
496                "    })\n"
497                "    .thenCatch(function(error) {\n"
498                "      body();\n"
499                "      body();\n"
500                "    });");
501 
502   verifyFormat("getSomeLongPromise()\n"
503                "    .then(function(value) { body(); })\n"
504                "    .thenCatch(function(error) { body(); });");
505 }
506 
507 TEST_F(FormatTestJS, ArrowFunctions) {
508   verifyFormat("var x = (a) => {\n"
509                "  return a;\n"
510                "};");
511   verifyFormat("var x = (a) => {\n"
512                "  function y() { return 42; }\n"
513                "  return a;\n"
514                "};");
515   verifyFormat("var x = (a: type): {some: type} => {\n"
516                "  return a;\n"
517                "};");
518   verifyFormat("var x = (a) => a;");
519   verifyFormat("return () => [];");
520   verifyFormat("var aaaaaaaaaaaaaaaaaaaa = {\n"
521                "  aaaaaaaaaaaaaaaaaaaaaaaaaaaa:\n"
522                "      (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
523                "       aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =>\n"
524                "          aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
525                "};");
526   verifyFormat(
527       "var a = a.aaaaaaa((a: a) => aaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) &&\n"
528       "                            aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
529   verifyFormat(
530       "var a = a.aaaaaaa((a: a) => aaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) ?\n"
531       "                                aaaaaaaaaaaaaaaaaaaaa(bbbbbbb) :\n"
532       "                                aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
533 
534   // FIXME: This is bad, we should be wrapping before "() => {".
535   verifyFormat("someFunction(() => {\n"
536                "  doSomething();  // break\n"
537                "})\n"
538                "    .doSomethingElse(\n"
539                "        // break\n"
540                "        );");
541 }
542 
543 TEST_F(FormatTestJS, ReturnStatements) {
544   verifyFormat("function() {\n"
545                "  return [hello, world];\n"
546                "}");
547 }
548 
549 TEST_F(FormatTestJS, AutomaticSemicolonInsertion) {
550   // The following statements must not wrap, as otherwise the program meaning
551   // would change due to automatic semicolon insertion.
552   // See http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1.
553   verifyFormat("return aaaaa;", getGoogleJSStyleWithColumns(10));
554   verifyFormat("continue aaaaa;", getGoogleJSStyleWithColumns(10));
555   verifyFormat("break aaaaa;", getGoogleJSStyleWithColumns(10));
556   verifyFormat("throw aaaaa;", getGoogleJSStyleWithColumns(10));
557   verifyFormat("aaaaaaaaa++;", getGoogleJSStyleWithColumns(10));
558   verifyFormat("aaaaaaaaa--;", getGoogleJSStyleWithColumns(10));
559 }
560 
561 TEST_F(FormatTestJS, ClosureStyleCasts) {
562   verifyFormat("var x = /** @type {foo} */ (bar);");
563 }
564 
565 TEST_F(FormatTestJS, TryCatch) {
566   verifyFormat("try {\n"
567                "  f();\n"
568                "} catch (e) {\n"
569                "  g();\n"
570                "} finally {\n"
571                "  h();\n"
572                "}");
573 
574   // But, of course, "catch" is a perfectly fine function name in JavaScript.
575   verifyFormat("someObject.catch();");
576   verifyFormat("someObject.new();");
577   verifyFormat("someObject.delete();");
578 }
579 
580 TEST_F(FormatTestJS, StringLiteralConcatenation) {
581   verifyFormat("var literal = 'hello ' +\n"
582                "              'world';");
583 }
584 
585 TEST_F(FormatTestJS, RegexLiteralClassification) {
586   // Regex literals.
587   verifyFormat("var regex = /abc/;");
588   verifyFormat("f(/abc/);");
589   verifyFormat("f(abc, /abc/);");
590   verifyFormat("some_map[/abc/];");
591   verifyFormat("var x = a ? /abc/ : /abc/;");
592   verifyFormat("for (var i = 0; /abc/.test(s[i]); i++) {\n}");
593   verifyFormat("var x = !/abc/.test(y);");
594   verifyFormat("var x = a && /abc/.test(y);");
595   verifyFormat("var x = a || /abc/.test(y);");
596   verifyFormat("var x = a + /abc/.search(y);");
597   verifyFormat("/abc/.search(y);");
598   verifyFormat("var regexs = {/abc/, /abc/};");
599   verifyFormat("return /abc/;");
600 
601   // Not regex literals.
602   verifyFormat("var a = a / 2 + b / 3;");
603   verifyFormat("var a = a++ / 2;");
604   // Prefix unary can operate on regex literals, not that it makes sense.
605   verifyFormat("var a = ++/a/;");
606 
607   // This is a known issue, regular expressions are incorrectly detected if
608   // directly following a closing parenthesis.
609   verifyFormat("if (foo) / bar /.exec(baz);");
610 }
611 
612 TEST_F(FormatTestJS, RegexLiteralSpecialCharacters) {
613   verifyFormat("var regex = /=/;");
614   verifyFormat("var regex = /a*/;");
615   verifyFormat("var regex = /a+/;");
616   verifyFormat("var regex = /a?/;");
617   verifyFormat("var regex = /.a./;");
618   verifyFormat("var regex = /a\\*/;");
619   verifyFormat("var regex = /^a$/;");
620   verifyFormat("var regex = /\\/a/;");
621   verifyFormat("var regex = /(?:x)/;");
622   verifyFormat("var regex = /x(?=y)/;");
623   verifyFormat("var regex = /x(?!y)/;");
624   verifyFormat("var regex = /x|y/;");
625   verifyFormat("var regex = /a{2}/;");
626   verifyFormat("var regex = /a{1,3}/;");
627 
628   verifyFormat("var regex = /[abc]/;");
629   verifyFormat("var regex = /[^abc]/;");
630   verifyFormat("var regex = /[\\b]/;");
631   verifyFormat("var regex = /[/]/;");
632   verifyFormat("var regex = /[\\/]/;");
633   verifyFormat("var regex = /\\[/;");
634   verifyFormat("var regex = /\\\\[/]/;");
635   verifyFormat("var regex = /}[\"]/;");
636   verifyFormat("var regex = /}[/\"]/;");
637   verifyFormat("var regex = /}[\"/]/;");
638 
639   verifyFormat("var regex = /\\b/;");
640   verifyFormat("var regex = /\\B/;");
641   verifyFormat("var regex = /\\d/;");
642   verifyFormat("var regex = /\\D/;");
643   verifyFormat("var regex = /\\f/;");
644   verifyFormat("var regex = /\\n/;");
645   verifyFormat("var regex = /\\r/;");
646   verifyFormat("var regex = /\\s/;");
647   verifyFormat("var regex = /\\S/;");
648   verifyFormat("var regex = /\\t/;");
649   verifyFormat("var regex = /\\v/;");
650   verifyFormat("var regex = /\\w/;");
651   verifyFormat("var regex = /\\W/;");
652   verifyFormat("var regex = /a(a)\\1/;");
653   verifyFormat("var regex = /\\0/;");
654   verifyFormat("var regex = /\\\\/g;");
655   verifyFormat("var regex = /\\a\\\\/g;");
656   verifyFormat("var regex = /\a\\//g;");
657   verifyFormat("var regex = /a\\//;\n"
658                "var x = 0;");
659   EXPECT_EQ("var regex = /'/g;", format("var regex = /'/g ;"));
660   EXPECT_EQ("var regex = /'/g;  //'", format("var regex = /'/g ; //'"));
661   EXPECT_EQ("var regex = /\\/*/;\n"
662             "var x = 0;",
663             format("var regex = /\\/*/;\n"
664                    "var x=0;"));
665   EXPECT_EQ("var x = /a\\//;", format("var x = /a\\//  \n;"));
666   verifyFormat("var regex = /\"/;", getGoogleJSStyleWithColumns(16));
667   verifyFormat("var regex =\n"
668                "    /\"/;",
669                getGoogleJSStyleWithColumns(15));
670   verifyFormat("var regex =  //\n"
671                "    /a/;");
672   verifyFormat("var regexs = [\n"
673                "  /d/,   //\n"
674                "  /aa/,  //\n"
675                "];");
676 }
677 
678 TEST_F(FormatTestJS, RegexLiteralModifiers) {
679   verifyFormat("var regex = /abc/g;");
680   verifyFormat("var regex = /abc/i;");
681   verifyFormat("var regex = /abc/m;");
682   verifyFormat("var regex = /abc/y;");
683 }
684 
685 TEST_F(FormatTestJS, RegexLiteralLength) {
686   verifyFormat("var regex = /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
687                getGoogleJSStyleWithColumns(60));
688   verifyFormat("var regex =\n"
689                "    /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
690                getGoogleJSStyleWithColumns(60));
691   verifyFormat("var regex = /\\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
692                getGoogleJSStyleWithColumns(50));
693 }
694 
695 TEST_F(FormatTestJS, RegexLiteralExamples) {
696   verifyFormat("var regex = search.match(/(?:\?|&)times=([^?&]+)/i);");
697 }
698 
699 TEST_F(FormatTestJS, TypeAnnotations) {
700   verifyFormat("var x: string;");
701   verifyFormat("function x(): string {\n  return 'x';\n}");
702   verifyFormat("function x(): {x: string} {\n  return {x: 'x'};\n}");
703   verifyFormat("function x(y: string): string {\n  return 'x';\n}");
704   verifyFormat("for (var y: string in x) {\n  x();\n}");
705   verifyFormat("((a: string, b: number): string => a + b);");
706   verifyFormat("var x: (y: number) => string;");
707   verifyFormat("var x: P<string, (a: number) => string>;");
708   verifyFormat("var x = {y: function(): z { return 1; }};");
709   verifyFormat("var x = {y: function(): {a: number} { return 1; }};");
710 }
711 
712 TEST_F(FormatTestJS, ClassDeclarations) {
713   verifyFormat("class C {\n  x: string = 12;\n}");
714   verifyFormat("class C {\n  x(): string => 12;\n}");
715   verifyFormat("class C {\n  ['x' + 2]: string = 12;\n}");
716   verifyFormat("class C {\n  private x: string = 12;\n}");
717   verifyFormat("class C {\n  private static x: string = 12;\n}");
718   verifyFormat("class C {\n  static x(): string { return 'asd'; }\n}");
719   verifyFormat("class C extends P implements I {}");
720   verifyFormat("class C extends p.P implements i.I {}");
721   verifyFormat("class Test {\n"
722                "  aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaa):\n"
723                "      aaaaaaaaaaaaaaaaaaaaaa {}\n"
724                "}");
725 
726   // ':' is not a type declaration here.
727   verifyFormat("class X {\n"
728                "  subs = {\n"
729                "    'b': {\n"
730                "      'c': 1,\n"
731                "    },\n"
732                "  };\n"
733                "}");
734 }
735 
736 TEST_F(FormatTestJS, InterfaceDeclarations) {
737   verifyFormat("interface I {\n"
738                "  x: string;\n"
739                "}\n"
740                "var y;");
741   // Ensure that state is reset after parsing the interface.
742   verifyFormat("interface a {}\n"
743                "export function b() {}\n"
744                "var x;");
745 }
746 
747 TEST_F(FormatTestJS, EnumDeclarations) {
748   verifyFormat("enum Foo {\n"
749                "  A = 1,\n"
750                "  B\n"
751                "}");
752   verifyFormat("export /* somecomment*/ enum Foo {\n"
753                "  A = 1,\n"
754                "  B\n"
755                "}");
756   verifyFormat("enum Foo {\n"
757                "  A = 1,  // comment\n"
758                "  B\n"
759                "}\n"
760                "var x = 1;");
761 }
762 
763 TEST_F(FormatTestJS, MetadataAnnotations) {
764   verifyFormat("@A\nclass C {\n}");
765   verifyFormat("@A({arg: 'value'})\nclass C {\n}");
766   verifyFormat("@A\n@B\nclass C {\n}");
767   verifyFormat("class C {\n  @A x: string;\n}");
768   verifyFormat("class C {\n"
769                "  @A\n"
770                "  private x(): string {\n"
771                "    return 'y';\n"
772                "  }\n"
773                "}");
774   verifyFormat("class X {}\n"
775                "class Y {}");
776 }
777 
778 TEST_F(FormatTestJS, Modules) {
779   verifyFormat("import SomeThing from 'some/module.js';");
780   verifyFormat("import {X, Y} from 'some/module.js';");
781   verifyFormat("import {\n"
782                "  VeryLongImportsAreAnnoying,\n"
783                "  VeryLongImportsAreAnnoying,\n"
784                "  VeryLongImportsAreAnnoying,\n"
785                "  VeryLongImportsAreAnnoying\n"
786                "} from 'some/module.js';");
787   verifyFormat("import {\n"
788                "  X,\n"
789                "  Y,\n"
790                "} from 'some/module.js';");
791   verifyFormat("import {\n"
792                "  X,\n"
793                "  Y,\n"
794                "} from 'some/long/module.js';",
795                getGoogleJSStyleWithColumns(20));
796   verifyFormat("import {X as myLocalX, Y as myLocalY} from 'some/module.js';");
797   verifyFormat("import * as lib from 'some/module.js';");
798   verifyFormat("var x = {import: 1};\nx.import = 2;");
799 
800   verifyFormat("export function fn() {\n"
801                "  return 'fn';\n"
802                "}");
803   verifyFormat("export function A() {}\n"
804                "export default function B() {}\n"
805                "export function C() {}");
806   verifyFormat("export const x = 12;");
807   verifyFormat("export default class X {}");
808   verifyFormat("export {X, Y} from 'some/module.js';");
809   verifyFormat("export {\n"
810                "  X,\n"
811                "  Y,\n"
812                "} from 'some/module.js';");
813   verifyFormat("export class C {\n"
814                "  x: number;\n"
815                "  y: string;\n"
816                "}");
817   verifyFormat("export class X { y: number; }");
818   verifyFormat("export default class X { y: number }");
819   verifyFormat("export default function() {\n  return 1;\n}");
820   verifyFormat("export var x = 12;");
821   verifyFormat("class C {}\n"
822                "export function f() {}\n"
823                "var v;");
824   verifyFormat("export var x: number = 12;");
825   verifyFormat("export const y = {\n"
826                "  a: 1,\n"
827                "  b: 2\n"
828                "};");
829   verifyFormat("export enum Foo {\n"
830                "  BAR,\n"
831                "  // adsdasd\n"
832                "  BAZ\n"
833                "}");
834 }
835 
836 TEST_F(FormatTestJS, TemplateStrings) {
837   // Keeps any whitespace/indentation within the template string.
838   EXPECT_EQ("var x = `hello\n"
839             "     ${  name    }\n"
840             "  !`;",
841             format("var x    =    `hello\n"
842                    "     ${  name    }\n"
843                    "  !`;"));
844 
845   verifyFormat("var x =\n"
846                "    `hello ${world}` >= some();",
847                getGoogleJSStyleWithColumns(34)); // Barely doesn't fit.
848   verifyFormat("var x = `hello ${world}` >= some();",
849                getGoogleJSStyleWithColumns(35)); // Barely fits.
850   EXPECT_EQ("var x = `hello\n"
851             "  ${world}` >=\n"
852             "        some();",
853             format("var x =\n"
854                    "    `hello\n"
855                    "  ${world}` >= some();",
856                    getGoogleJSStyleWithColumns(21))); // Barely doesn't fit.
857   EXPECT_EQ("var x = `hello\n"
858             "  ${world}` >= some();",
859             format("var x =\n"
860                    "    `hello\n"
861                    "  ${world}` >= some();",
862                    getGoogleJSStyleWithColumns(22))); // Barely fits.
863 
864   verifyFormat("var x =\n"
865                "    `h`;",
866                getGoogleJSStyleWithColumns(11));
867   EXPECT_EQ(
868       "var x =\n    `multi\n  line`;",
869       format("var x = `multi\n  line`;", getGoogleJSStyleWithColumns(13)));
870   verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
871                "    `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`);");
872 
873   // Make sure template strings get a proper ColumnWidth assigned, even if they
874   // are first token in line.
875   verifyFormat(
876       "var a = aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
877       "        `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`;");
878 
879   // Two template strings.
880   verifyFormat("var x = `hello` == `hello`;");
881 
882   // Comments in template strings.
883   EXPECT_EQ("var x = `//a`;\n"
884             "var y;",
885             format("var x =\n `//a`;\n"
886                    "var y  ;"));
887   EXPECT_EQ("var x = `/*a`;\n"
888             "var y;",
889             format("var x =\n `/*a`;\n"
890                    "var y;"));
891   // Unterminated string literals in a template string.
892   verifyFormat("var x = `'`;  // comment with matching quote '\n"
893                "var y;");
894   verifyFormat("var x = `\"`;  // comment with matching quote \"\n"
895                "var y;");
896   // Backticks in a comment - not a template string.
897   EXPECT_EQ("var x = 1  // `/*a`;\n"
898             "    ;",
899             format("var x =\n 1  // `/*a`;\n"
900                    "    ;"));
901   EXPECT_EQ("/* ` */ var x = 1; /* ` */",
902             format("/* ` */ var x\n= 1; /* ` */"));
903   // Comment spans multiple template strings.
904   EXPECT_EQ("var x = `/*a`;\n"
905             "var y = ` */ `;",
906             format("var x =\n `/*a`;\n"
907                    "var y =\n ` */ `;"));
908   // Escaped backtick.
909   EXPECT_EQ("var x = ` \\` a`;\n"
910             "var y;",
911             format("var x = ` \\` a`;\n"
912                    "var y;"));
913 }
914 
915 TEST_F(FormatTestJS, CastSyntax) { verifyFormat("var x = <type>foo;"); }
916 
917 TEST_F(FormatTestJS, TypeArguments) {
918   verifyFormat("class X<Y> {}");
919   verifyFormat("new X<Y>();");
920   verifyFormat("foo<Y>(a);");
921   verifyFormat("var x: X<Y>[];");
922   verifyFormat("class C extends D<E> implements F<G>, H<I> {}");
923   verifyFormat("function f(a: List<any> = null) {}");
924   verifyFormat("function f(): List<any> {}");
925   verifyFormat("function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa():\n"
926                "    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {}");
927   verifyFormat("function aaaaaaaaaa(aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaa,\n"
928                "                    aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaa):\n"
929                "    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {}");
930 }
931 
932 TEST_F(FormatTestJS, OptionalTypes) {
933   verifyFormat("function x(a?: b, c?, d?) {}");
934   verifyFormat("class X {\n"
935                "  y?: z;\n"
936                "  z?;\n"
937                "}");
938   verifyFormat("interface X {\n"
939                "  y?(): z;\n"
940                "}");
941   verifyFormat("x ? 1 : 2;");
942   verifyFormat("constructor({aa}: {\n"
943                "  aa?: string,\n"
944                "  aaaaaaaa?: string,\n"
945                "  aaaaaaaaaaaaaaa?: boolean,\n"
946                "  aaaaaa?: List<string>\n"
947                "}) {}");
948 }
949 
950 TEST_F(FormatTestJS, IndexSignature) {
951   verifyFormat("var x: {[k: string]: v};");
952 }
953 
954 } // end namespace tooling
955 } // end namespace clang
956