1 //===- unittest/Format/FormatTestJS.cpp - Formatting unit tests for JS ----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "FormatTestUtils.h"
10 #include "clang/Format/Format.h"
11 #include "llvm/Support/Debug.h"
12 #include "gtest/gtest.h"
13
14 #define DEBUG_TYPE "format-test"
15
16 namespace clang {
17 namespace format {
18
19 class FormatTestJS : public ::testing::Test {
20 protected:
format(llvm::StringRef Code,unsigned Offset,unsigned Length,const FormatStyle & Style)21 static std::string format(llvm::StringRef Code, unsigned Offset,
22 unsigned Length, const FormatStyle &Style) {
23 LLVM_DEBUG(llvm::errs() << "---\n");
24 LLVM_DEBUG(llvm::errs() << Code << "\n\n");
25 std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
26 FormattingAttemptStatus Status;
27 tooling::Replacements Replaces =
28 reformat(Style, Code, Ranges, "<stdin>", &Status);
29 EXPECT_TRUE(Status.FormatComplete);
30 auto Result = applyAllReplacements(Code, Replaces);
31 EXPECT_TRUE(static_cast<bool>(Result));
32 LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
33 return *Result;
34 }
35
format(llvm::StringRef Code,const FormatStyle & Style=getGoogleStyle (FormatStyle::LK_JavaScript))36 static std::string format(
37 llvm::StringRef Code,
38 const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) {
39 return format(Code, 0, Code.size(), Style);
40 }
41
getGoogleJSStyleWithColumns(unsigned ColumnLimit)42 static FormatStyle getGoogleJSStyleWithColumns(unsigned ColumnLimit) {
43 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
44 Style.ColumnLimit = ColumnLimit;
45 return Style;
46 }
47
verifyFormat(llvm::StringRef Code,const FormatStyle & Style=getGoogleStyle (FormatStyle::LK_JavaScript))48 static void verifyFormat(
49 llvm::StringRef Code,
50 const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) {
51 EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable";
52 std::string Result = format(test::messUp(Code), Style);
53 EXPECT_EQ(Code.str(), Result) << "Formatted:\n" << Result;
54 }
55
verifyFormat(llvm::StringRef Expected,llvm::StringRef Code,const FormatStyle & Style=getGoogleStyle (FormatStyle::LK_JavaScript))56 static void verifyFormat(
57 llvm::StringRef Expected, llvm::StringRef Code,
58 const FormatStyle &Style = getGoogleStyle(FormatStyle::LK_JavaScript)) {
59 EXPECT_EQ(Expected.str(), format(Expected, Style))
60 << "Expected code is not stable";
61 std::string Result = format(Code, Style);
62 EXPECT_EQ(Expected.str(), Result) << "Formatted:\n" << Result;
63 }
64 };
65
TEST_F(FormatTestJS,BlockComments)66 TEST_F(FormatTestJS, BlockComments) {
67 verifyFormat("/* aaaaaaaaaaaaa */ aaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
68 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
69 // Breaks after a single line block comment.
70 EXPECT_EQ("aaaaa = bbbb.ccccccccccccccc(\n"
71 " /** @type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala} */\n"
72 " mediaMessage);",
73 format("aaaaa = bbbb.ccccccccccccccc(\n"
74 " /** "
75 "@type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala} */ "
76 "mediaMessage);",
77 getGoogleJSStyleWithColumns(70)));
78 // Breaks after a multiline block comment.
79 EXPECT_EQ(
80 "aaaaa = bbbb.ccccccccccccccc(\n"
81 " /**\n"
82 " * @type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala}\n"
83 " */\n"
84 " mediaMessage);",
85 format("aaaaa = bbbb.ccccccccccccccc(\n"
86 " /**\n"
87 " * @type_{!cccc.rrrrrrr.MMMMMMMMMMMM.LLLLLLLLLLL.lala}\n"
88 " */ mediaMessage);",
89 getGoogleJSStyleWithColumns(70)));
90 }
91
TEST_F(FormatTestJS,JSDocComments)92 TEST_F(FormatTestJS, JSDocComments) {
93 // Break the first line of a multiline jsdoc comment.
94 EXPECT_EQ("/**\n"
95 " * jsdoc line 1\n"
96 " * jsdoc line 2\n"
97 " */",
98 format("/** jsdoc line 1\n"
99 " * jsdoc line 2\n"
100 " */",
101 getGoogleJSStyleWithColumns(20)));
102 // Both break after '/**' and break the line itself.
103 EXPECT_EQ("/**\n"
104 " * jsdoc line long\n"
105 " * long jsdoc line 2\n"
106 " */",
107 format("/** jsdoc line long long\n"
108 " * jsdoc line 2\n"
109 " */",
110 getGoogleJSStyleWithColumns(20)));
111 // Break a short first line if the ending '*/' is on a newline.
112 EXPECT_EQ("/**\n"
113 " * jsdoc line 1\n"
114 " */",
115 format("/** jsdoc line 1\n"
116 " */",
117 getGoogleJSStyleWithColumns(20)));
118 // Don't break the first line of a short single line jsdoc comment.
119 EXPECT_EQ("/** jsdoc line 1 */",
120 format("/** jsdoc line 1 */", getGoogleJSStyleWithColumns(20)));
121 // Don't break the first line of a single line jsdoc comment if it just fits
122 // the column limit.
123 EXPECT_EQ("/** jsdoc line 12 */",
124 format("/** jsdoc line 12 */", getGoogleJSStyleWithColumns(20)));
125 // Don't break after '/**' and before '*/' if there is no space between
126 // '/**' and the content.
127 EXPECT_EQ(
128 "/*** nonjsdoc long\n"
129 " * line */",
130 format("/*** nonjsdoc long line */", getGoogleJSStyleWithColumns(20)));
131 EXPECT_EQ(
132 "/**strange long long\n"
133 " * line */",
134 format("/**strange long long line */", getGoogleJSStyleWithColumns(20)));
135 // Break the first line of a single line jsdoc comment if it just exceeds the
136 // column limit.
137 EXPECT_EQ("/**\n"
138 " * jsdoc line 123\n"
139 " */",
140 format("/** jsdoc line 123 */", getGoogleJSStyleWithColumns(20)));
141 // Break also if the leading indent of the first line is more than 1 column.
142 EXPECT_EQ("/**\n"
143 " * jsdoc line 123\n"
144 " */",
145 format("/** jsdoc line 123 */", getGoogleJSStyleWithColumns(20)));
146 // Break also if the leading indent of the first line is more than 1 column.
147 EXPECT_EQ("/**\n"
148 " * jsdoc line 123\n"
149 " */",
150 format("/** jsdoc line 123 */", getGoogleJSStyleWithColumns(20)));
151 // Break after the content of the last line.
152 EXPECT_EQ("/**\n"
153 " * line 1\n"
154 " * line 2\n"
155 " */",
156 format("/**\n"
157 " * line 1\n"
158 " * line 2 */",
159 getGoogleJSStyleWithColumns(20)));
160 // Break both the content and after the content of the last line.
161 EXPECT_EQ("/**\n"
162 " * line 1\n"
163 " * line long long\n"
164 " * long\n"
165 " */",
166 format("/**\n"
167 " * line 1\n"
168 " * line long long long */",
169 getGoogleJSStyleWithColumns(20)));
170
171 // The comment block gets indented.
172 EXPECT_EQ("function f() {\n"
173 " /**\n"
174 " * comment about\n"
175 " * x\n"
176 " */\n"
177 " var x = 1;\n"
178 "}",
179 format("function f() {\n"
180 "/** comment about x */\n"
181 "var x = 1;\n"
182 "}",
183 getGoogleJSStyleWithColumns(20)));
184
185 // Don't break the first line of a single line short jsdoc comment pragma.
186 EXPECT_EQ("/** @returns j */",
187 format("/** @returns j */", getGoogleJSStyleWithColumns(20)));
188
189 // Break a single line long jsdoc comment pragma.
190 EXPECT_EQ("/**\n"
191 " * @returns {string}\n"
192 " * jsdoc line 12\n"
193 " */",
194 format("/** @returns {string} jsdoc line 12 */",
195 getGoogleJSStyleWithColumns(20)));
196
197 // FIXME: this overcounts the */ as a continuation of the 12 when breaking.
198 // Cf. BreakableBlockComment::getRemainingLength.
199 EXPECT_EQ("/**\n"
200 " * @returns {string}\n"
201 " * jsdoc line line\n"
202 " * 12\n"
203 " */",
204 format("/** @returns {string} jsdoc line line 12*/",
205 getGoogleJSStyleWithColumns(25)));
206
207 // Fix a multiline jsdoc comment ending in a comment pragma.
208 EXPECT_EQ("/**\n"
209 " * line 1\n"
210 " * line 2\n"
211 " * @returns {string}\n"
212 " * jsdoc line 12\n"
213 " */",
214 format("/** line 1\n"
215 " * line 2\n"
216 " * @returns {string} jsdoc line 12 */",
217 getGoogleJSStyleWithColumns(20)));
218
219 EXPECT_EQ("/**\n"
220 " * line 1\n"
221 " * line 2\n"
222 " *\n"
223 " * @returns j\n"
224 " */",
225 format("/** line 1\n"
226 " * line 2\n"
227 " *\n"
228 " * @returns j */",
229 getGoogleJSStyleWithColumns(20)));
230 }
231
TEST_F(FormatTestJS,UnderstandsJavaScriptOperators)232 TEST_F(FormatTestJS, UnderstandsJavaScriptOperators) {
233 verifyFormat("a == = b;");
234 verifyFormat("a != = b;");
235
236 verifyFormat("a === b;");
237 verifyFormat("aaaaaaa ===\n b;", getGoogleJSStyleWithColumns(10));
238 verifyFormat("a !== b;");
239 verifyFormat("aaaaaaa !==\n b;", getGoogleJSStyleWithColumns(10));
240 verifyFormat("if (a + b + c +\n"
241 " d !==\n"
242 " e + f + g)\n"
243 " q();",
244 getGoogleJSStyleWithColumns(20));
245
246 verifyFormat("a >> >= b;");
247
248 verifyFormat("a >>> b;");
249 verifyFormat("aaaaaaa >>>\n b;", getGoogleJSStyleWithColumns(10));
250 verifyFormat("a >>>= b;");
251 verifyFormat("aaaaaaa >>>=\n b;", getGoogleJSStyleWithColumns(10));
252 verifyFormat("if (a + b + c +\n"
253 " d >>>\n"
254 " e + f + g)\n"
255 " q();",
256 getGoogleJSStyleWithColumns(20));
257 verifyFormat("var x = aaaaaaaaaa ?\n"
258 " bbbbbb :\n"
259 " ccc;",
260 getGoogleJSStyleWithColumns(20));
261
262 verifyFormat("var b = a.map((x) => x + 1);");
263 verifyFormat("return ('aaa') in bbbb;");
264 verifyFormat("var x = aaaaaaaaaaaaaaaaaaaaaaaaa() in\n"
265 " aaaa.aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;");
266 FormatStyle Style = getGoogleJSStyleWithColumns(80);
267 Style.AlignOperands = FormatStyle::OAS_Align;
268 verifyFormat("var x = aaaaaaaaaaaaaaaaaaaaaaaaa() in\n"
269 " aaaa.aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
270 Style);
271 Style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
272 verifyFormat("var x = aaaaaaaaaaaaaaaaaaaaaaaaa()\n"
273 " in aaaa.aaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;",
274 Style);
275
276 // ES6 spread operator.
277 verifyFormat("someFunction(...a);");
278 verifyFormat("var x = [1, ...a, 2];");
279
280 // "- -1" is legal JS syntax, but must not collapse into "--".
281 verifyFormat("- -1;", " - -1;");
282 verifyFormat("-- -1;", " -- -1;");
283 verifyFormat("+ +1;", " + +1;");
284 verifyFormat("++ +1;", " ++ +1;");
285 }
286
TEST_F(FormatTestJS,UnderstandsAmpAmp)287 TEST_F(FormatTestJS, UnderstandsAmpAmp) {
288 verifyFormat("e && e.SomeFunction();");
289 }
290
TEST_F(FormatTestJS,LiteralOperatorsCanBeKeywords)291 TEST_F(FormatTestJS, LiteralOperatorsCanBeKeywords) {
292 verifyFormat("not.and.or.not_eq = 1;");
293 }
294
TEST_F(FormatTestJS,ReservedWords)295 TEST_F(FormatTestJS, ReservedWords) {
296 // JavaScript reserved words (aka keywords) are only illegal when used as
297 // Identifiers, but are legal as IdentifierNames.
298 verifyFormat("x.class.struct = 1;");
299 verifyFormat("x.case = 1;");
300 verifyFormat("x.interface = 1;");
301 verifyFormat("x.for = 1;");
302 verifyFormat("x.of();");
303 verifyFormat("of(null);");
304 verifyFormat("return of(null);");
305 verifyFormat("import {of} from 'x';");
306 verifyFormat("x.in();");
307 verifyFormat("x.let();");
308 verifyFormat("x.var();");
309 verifyFormat("x.for();");
310 verifyFormat("x.as();");
311 verifyFormat("x.instanceof();");
312 verifyFormat("x.switch();");
313 verifyFormat("x.case();");
314 verifyFormat("x.delete();");
315 verifyFormat("x.throw();");
316 verifyFormat("x.throws();");
317 verifyFormat("x.if();");
318 verifyFormat("x = {\n"
319 " a: 12,\n"
320 " interface: 1,\n"
321 " switch: 1,\n"
322 "};");
323 verifyFormat("var struct = 2;");
324 verifyFormat("var union = 2;");
325 verifyFormat("var interface = 2;");
326 verifyFormat("var requires = {};");
327 verifyFormat("interface = 2;");
328 verifyFormat("x = interface instanceof y;");
329 verifyFormat("interface Test {\n"
330 " x: string;\n"
331 " switch: string;\n"
332 " case: string;\n"
333 " default: string;\n"
334 "}\n");
335 verifyFormat("const Axis = {\n"
336 " for: 'for',\n"
337 " x: 'x'\n"
338 "};",
339 "const Axis = {for: 'for', x: 'x'};");
340 verifyFormat("export class Foo extends Bar {\n"
341 " get case(): Case {\n"
342 " return (\n"
343 " (this.Bar$has('case')) ? (this.Bar$get('case')) :\n"
344 " (this.case = new Case()));\n"
345 " }\n"
346 "}");
347 }
348
TEST_F(FormatTestJS,ReservedWordsMethods)349 TEST_F(FormatTestJS, ReservedWordsMethods) {
350 verifyFormat("class X {\n"
351 " delete() {\n"
352 " x();\n"
353 " }\n"
354 " interface() {\n"
355 " x();\n"
356 " }\n"
357 " let() {\n"
358 " x();\n"
359 " }\n"
360 "}\n");
361 verifyFormat("class KeywordNamedMethods {\n"
362 " do() {\n"
363 " }\n"
364 " for() {\n"
365 " }\n"
366 " while() {\n"
367 " }\n"
368 " if() {\n"
369 " }\n"
370 " else() {\n"
371 " }\n"
372 " try() {\n"
373 " }\n"
374 " catch() {\n"
375 " }\n"
376 "}\n");
377 }
378
TEST_F(FormatTestJS,ReservedWordsParenthesized)379 TEST_F(FormatTestJS, ReservedWordsParenthesized) {
380 // All of these are statements using the keyword, not function calls.
381 verifyFormat("throw (x + y);\n"
382 "await (await x).y;\n"
383 "typeof (x) === 'string';\n"
384 "void (0);\n"
385 "delete (x.y);\n"
386 "return (x);\n");
387 }
388
TEST_F(FormatTestJS,ES6DestructuringAssignment)389 TEST_F(FormatTestJS, ES6DestructuringAssignment) {
390 verifyFormat("var [a, b, c] = [1, 2, 3];");
391 verifyFormat("const [a, b, c] = [1, 2, 3];");
392 verifyFormat("let [a, b, c] = [1, 2, 3];");
393 verifyFormat("var {a, b} = {a: 1, b: 2};");
394 verifyFormat("let {a, b} = {a: 1, b: 2};");
395 }
396
TEST_F(FormatTestJS,ContainerLiterals)397 TEST_F(FormatTestJS, ContainerLiterals) {
398 verifyFormat("var x = {\n"
399 " y: function(a) {\n"
400 " return a;\n"
401 " }\n"
402 "};");
403 verifyFormat("return {\n"
404 " link: function() {\n"
405 " f(); //\n"
406 " }\n"
407 "};");
408 verifyFormat("return {\n"
409 " a: a,\n"
410 " link: function() {\n"
411 " f(); //\n"
412 " }\n"
413 "};");
414 verifyFormat("return {\n"
415 " a: a,\n"
416 " link: function() {\n"
417 " f(); //\n"
418 " },\n"
419 " link: function() {\n"
420 " f(); //\n"
421 " }\n"
422 "};");
423 verifyFormat("var stuff = {\n"
424 " // comment for update\n"
425 " update: false,\n"
426 " // comment for modules\n"
427 " modules: false,\n"
428 " // comment for tasks\n"
429 " tasks: false\n"
430 "};");
431 verifyFormat("return {\n"
432 " 'finish':\n"
433 " //\n"
434 " a\n"
435 "};");
436 verifyFormat("var obj = {\n"
437 " fooooooooo: function(x) {\n"
438 " return x.zIsTooLongForOneLineWithTheDeclarationLine();\n"
439 " }\n"
440 "};");
441 // Simple object literal, as opposed to enum style below.
442 verifyFormat("var obj = {a: 123};");
443 // Enum style top level assignment.
444 verifyFormat("X = {\n a: 123\n};");
445 verifyFormat("X.Y = {\n a: 123\n};");
446 // But only on the top level, otherwise its a plain object literal assignment.
447 verifyFormat("function x() {\n"
448 " y = {z: 1};\n"
449 "}");
450 verifyFormat("x = foo && {a: 123};");
451
452 // Arrow functions in object literals.
453 verifyFormat("var x = {\n"
454 " y: (a) => {\n"
455 " x();\n"
456 " return a;\n"
457 " },\n"
458 "};");
459 verifyFormat("var x = {y: (a) => a};");
460
461 // Methods in object literals.
462 verifyFormat("var x = {\n"
463 " y(a: string): number {\n"
464 " return a;\n"
465 " }\n"
466 "};");
467 verifyFormat("var x = {\n"
468 " y(a: string) {\n"
469 " return a;\n"
470 " }\n"
471 "};");
472
473 // Computed keys.
474 verifyFormat("var x = {[a]: 1, b: 2, [c]: 3};");
475 verifyFormat("var x = {\n"
476 " [a]: 1,\n"
477 " b: 2,\n"
478 " [c]: 3,\n"
479 "};");
480
481 // Object literals can leave out labels.
482 verifyFormat("f({a}, () => {\n"
483 " x;\n"
484 " g();\n"
485 "});");
486
487 // Keys can be quoted.
488 verifyFormat("var x = {\n"
489 " a: a,\n"
490 " b: b,\n"
491 " 'c': c,\n"
492 "};");
493
494 // Dict literals can skip the label names.
495 verifyFormat("var x = {\n"
496 " aaa,\n"
497 " aaa,\n"
498 " aaa,\n"
499 "};");
500 verifyFormat("return {\n"
501 " a,\n"
502 " b: 'b',\n"
503 " c,\n"
504 "};");
505 }
506
TEST_F(FormatTestJS,MethodsInObjectLiterals)507 TEST_F(FormatTestJS, MethodsInObjectLiterals) {
508 verifyFormat("var o = {\n"
509 " value: 'test',\n"
510 " get value() { // getter\n"
511 " return this.value;\n"
512 " }\n"
513 "};");
514 verifyFormat("var o = {\n"
515 " value: 'test',\n"
516 " set value(val) { // setter\n"
517 " this.value = val;\n"
518 " }\n"
519 "};");
520 verifyFormat("var o = {\n"
521 " value: 'test',\n"
522 " someMethod(val) { // method\n"
523 " doSomething(this.value + val);\n"
524 " }\n"
525 "};");
526 verifyFormat("var o = {\n"
527 " someMethod(val) { // method\n"
528 " doSomething(this.value + val);\n"
529 " },\n"
530 " someOtherMethod(val) { // method\n"
531 " doSomething(this.value + val);\n"
532 " }\n"
533 "};");
534 }
535
TEST_F(FormatTestJS,GettersSettersVisibilityKeywords)536 TEST_F(FormatTestJS, GettersSettersVisibilityKeywords) {
537 // Don't break after "protected"
538 verifyFormat("class X {\n"
539 " protected get getter():\n"
540 " number {\n"
541 " return 1;\n"
542 " }\n"
543 "}",
544 getGoogleJSStyleWithColumns(12));
545 // Don't break after "get"
546 verifyFormat("class X {\n"
547 " protected get someReallyLongGetterName():\n"
548 " number {\n"
549 " return 1;\n"
550 " }\n"
551 "}",
552 getGoogleJSStyleWithColumns(40));
553 }
554
TEST_F(FormatTestJS,SpacesInContainerLiterals)555 TEST_F(FormatTestJS, SpacesInContainerLiterals) {
556 verifyFormat("var arr = [1, 2, 3];");
557 verifyFormat("f({a: 1, b: 2, c: 3});");
558
559 verifyFormat("var object_literal_with_long_name = {\n"
560 " a: 'aaaaaaaaaaaaaaaaaa',\n"
561 " b: 'bbbbbbbbbbbbbbbbbb'\n"
562 "};");
563
564 verifyFormat("f({a: 1, b: 2, c: 3});",
565 getChromiumStyle(FormatStyle::LK_JavaScript));
566 verifyFormat("f({'a': [{}]});");
567 }
568
TEST_F(FormatTestJS,SingleQuotedStrings)569 TEST_F(FormatTestJS, SingleQuotedStrings) {
570 verifyFormat("this.function('', true);");
571 }
572
TEST_F(FormatTestJS,GoogScopes)573 TEST_F(FormatTestJS, GoogScopes) {
574 verifyFormat("goog.scope(function() {\n"
575 "var x = a.b;\n"
576 "var y = c.d;\n"
577 "}); // goog.scope");
578 verifyFormat("goog.scope(function() {\n"
579 "// test\n"
580 "var x = 0;\n"
581 "// test\n"
582 "});");
583 }
584
TEST_F(FormatTestJS,IIFEs)585 TEST_F(FormatTestJS, IIFEs) {
586 // Internal calling parens; no semi.
587 verifyFormat("(function() {\n"
588 "var a = 1;\n"
589 "}())");
590 // External calling parens; no semi.
591 verifyFormat("(function() {\n"
592 "var b = 2;\n"
593 "})()");
594 // Internal calling parens; with semi.
595 verifyFormat("(function() {\n"
596 "var c = 3;\n"
597 "}());");
598 // External calling parens; with semi.
599 verifyFormat("(function() {\n"
600 "var d = 4;\n"
601 "})();");
602 }
603
TEST_F(FormatTestJS,GoogModules)604 TEST_F(FormatTestJS, GoogModules) {
605 verifyFormat("goog.module('this.is.really.absurdly.long');",
606 getGoogleJSStyleWithColumns(40));
607 verifyFormat("goog.require('this.is.really.absurdly.long');",
608 getGoogleJSStyleWithColumns(40));
609 verifyFormat("goog.provide('this.is.really.absurdly.long');",
610 getGoogleJSStyleWithColumns(40));
611 verifyFormat("var long = goog.require('this.is.really.absurdly.long');",
612 getGoogleJSStyleWithColumns(40));
613 verifyFormat("const X = goog.requireType('this.is.really.absurdly.long');",
614 getGoogleJSStyleWithColumns(40));
615 verifyFormat("goog.forwardDeclare('this.is.really.absurdly.long');",
616 getGoogleJSStyleWithColumns(40));
617
618 // These should be wrapped normally.
619 verifyFormat(
620 "var MyLongClassName =\n"
621 " goog.module.get('my.long.module.name.followedBy.MyLongClassName');");
622 verifyFormat("function a() {\n"
623 " goog.setTestOnly();\n"
624 "}\n",
625 "function a() {\n"
626 "goog.setTestOnly();\n"
627 "}\n");
628 }
629
TEST_F(FormatTestJS,FormatsNamespaces)630 TEST_F(FormatTestJS, FormatsNamespaces) {
631 verifyFormat("namespace Foo {\n"
632 " export let x = 1;\n"
633 "}\n");
634 verifyFormat("declare namespace Foo {\n"
635 " export let x: number;\n"
636 "}\n");
637 }
638
TEST_F(FormatTestJS,NamespacesMayNotWrap)639 TEST_F(FormatTestJS, NamespacesMayNotWrap) {
640 verifyFormat("declare namespace foobarbaz {\n"
641 "}\n",
642 getGoogleJSStyleWithColumns(18));
643 verifyFormat("declare module foobarbaz {\n"
644 "}\n",
645 getGoogleJSStyleWithColumns(15));
646 verifyFormat("namespace foobarbaz {\n"
647 "}\n",
648 getGoogleJSStyleWithColumns(10));
649 verifyFormat("module foobarbaz {\n"
650 "}\n",
651 getGoogleJSStyleWithColumns(7));
652 }
653
TEST_F(FormatTestJS,AmbientDeclarations)654 TEST_F(FormatTestJS, AmbientDeclarations) {
655 FormatStyle NineCols = getGoogleJSStyleWithColumns(9);
656 verifyFormat("declare class\n"
657 " X {}",
658 NineCols);
659 verifyFormat("declare function\n"
660 "x();", // TODO(martinprobst): should ideally be indented.
661 NineCols);
662 verifyFormat("declare function foo();\n"
663 "let x = 1;\n");
664 verifyFormat("declare function foo(): string;\n"
665 "let x = 1;\n");
666 verifyFormat("declare function foo(): {x: number};\n"
667 "let x = 1;\n");
668 verifyFormat("declare class X {}\n"
669 "let x = 1;\n");
670 verifyFormat("declare interface Y {}\n"
671 "let x = 1;\n");
672 verifyFormat("declare enum X {\n"
673 "}",
674 NineCols);
675 verifyFormat("declare let\n"
676 " x: number;",
677 NineCols);
678 }
679
TEST_F(FormatTestJS,FormatsFreestandingFunctions)680 TEST_F(FormatTestJS, FormatsFreestandingFunctions) {
681 verifyFormat("function outer1(a, b) {\n"
682 " function inner1(a, b) {\n"
683 " return a;\n"
684 " }\n"
685 " inner1(a, b);\n"
686 "}\n"
687 "function outer2(a, b) {\n"
688 " function inner2(a, b) {\n"
689 " return a;\n"
690 " }\n"
691 " inner2(a, b);\n"
692 "}");
693 verifyFormat("function f() {}");
694 verifyFormat("function aFunction() {}\n"
695 "(function f() {\n"
696 " var x = 1;\n"
697 "}());\n");
698 verifyFormat("function aFunction() {}\n"
699 "{\n"
700 " let x = 1;\n"
701 " console.log(x);\n"
702 "}\n");
703 EXPECT_EQ("a = function(x) {}\n"
704 "\n"
705 "function f(x) {}",
706 format("a = function(x) {}\n"
707 "\n"
708 "function f(x) {}",
709 getGoogleJSStyleWithColumns(20)));
710 }
711
TEST_F(FormatTestJS,FormatsDecorators)712 TEST_F(FormatTestJS, FormatsDecorators) {
713 // No line break after argument decorators.
714 verifyFormat("class A {\n"
715 " constructor(@arg(DECOR) private arg: Type) {}\n"
716 "}");
717 // Ensure that there is a break before functions, getters and setters.
718 EXPECT_EQ("class A {\n"
719 " private p = () => {}\n"
720 "\n"
721 " @decorated('a')\n"
722 " get f() {\n"
723 " return result;\n"
724 " }\n"
725 "}\n"
726 "\n"
727 "class B {\n"
728 " private p = () => {}\n"
729 "\n"
730 " @decorated('a')\n"
731 " set f() {\n"
732 " return result;\n"
733 " }\n"
734 "}\n"
735 "\n"
736 "class C {\n"
737 " private p = () => {}\n"
738 "\n"
739 " @decorated('a')\n"
740 " function f() {\n"
741 " return result;\n"
742 " }\n"
743 "}",
744 format("class A {\n"
745 " private p = () => {}\n"
746 "\n"
747 " @decorated('a')\n"
748 " get f() {\n"
749 " return result;\n"
750 " }\n"
751 "}\n"
752 "\n"
753 "class B {\n"
754 " private p = () => {}\n"
755 "\n"
756 " @decorated('a')\n"
757 " set f() {\n"
758 " return result;\n"
759 " }\n"
760 "}\n"
761 "\n"
762 "class C {\n"
763 " private p = () => {}\n"
764 "\n"
765 " @decorated('a')\n"
766 " function f() {\n"
767 " return result;\n"
768 " }\n"
769 "}",
770 getGoogleJSStyleWithColumns(50)));
771 }
772
TEST_F(FormatTestJS,GeneratorFunctions)773 TEST_F(FormatTestJS, GeneratorFunctions) {
774 verifyFormat("function* f() {\n"
775 " let x = 1;\n"
776 " yield x;\n"
777 " yield* something();\n"
778 " yield [1, 2];\n"
779 " yield {a: 1};\n"
780 "}");
781 verifyFormat("function*\n"
782 " f() {\n"
783 "}",
784 getGoogleJSStyleWithColumns(8));
785 verifyFormat("export function* f() {\n"
786 " yield 1;\n"
787 "}\n");
788 verifyFormat("class X {\n"
789 " * generatorMethod() {\n"
790 " yield x;\n"
791 " }\n"
792 "}");
793 verifyFormat("var x = {\n"
794 " a: function*() {\n"
795 " //\n"
796 " }\n"
797 "}\n");
798 }
799
TEST_F(FormatTestJS,AsyncFunctions)800 TEST_F(FormatTestJS, AsyncFunctions) {
801 verifyFormat("async function f() {\n"
802 " let x = 1;\n"
803 " return fetch(x);\n"
804 "}");
805 verifyFormat("async function f() {\n"
806 " return 1;\n"
807 "}\n"
808 "\n"
809 "function a() {\n"
810 " return 1;\n"
811 "}\n",
812 " async function f() {\n"
813 " return 1;\n"
814 "}\n"
815 "\n"
816 " function a() {\n"
817 " return 1;\n"
818 "} \n");
819 // clang-format must not insert breaks between async and function, otherwise
820 // automatic semicolon insertion may trigger (in particular in a class body).
821 verifyFormat("async function\n"
822 "hello(\n"
823 " myparamnameiswaytooloooong) {\n"
824 "}",
825 "async function hello(myparamnameiswaytooloooong) {}",
826 getGoogleJSStyleWithColumns(10));
827 verifyFormat("class C {\n"
828 " async hello(\n"
829 " myparamnameiswaytooloooong) {\n"
830 " }\n"
831 "}",
832 "class C {\n"
833 " async hello(myparamnameiswaytooloooong) {} }",
834 getGoogleJSStyleWithColumns(10));
835 verifyFormat("async function* f() {\n"
836 " yield fetch(x);\n"
837 "}");
838 verifyFormat("export async function f() {\n"
839 " return fetch(x);\n"
840 "}");
841 verifyFormat("let x = async () => f();");
842 verifyFormat("let x = async function() {\n"
843 " f();\n"
844 "};");
845 verifyFormat("let x = async();");
846 verifyFormat("class X {\n"
847 " async asyncMethod() {\n"
848 " return fetch(1);\n"
849 " }\n"
850 "}");
851 verifyFormat("function initialize() {\n"
852 " // Comment.\n"
853 " return async.then();\n"
854 "}\n");
855 verifyFormat("for await (const x of y) {\n"
856 " console.log(x);\n"
857 "}\n");
858 verifyFormat("function asyncLoop() {\n"
859 " for await (const x of y) {\n"
860 " console.log(x);\n"
861 " }\n"
862 "}\n");
863 }
864
TEST_F(FormatTestJS,OverriddenMembers)865 TEST_F(FormatTestJS, OverriddenMembers) {
866 verifyFormat(
867 "class C extends P {\n"
868 " protected override "
869 "anOverlyLongPropertyNameSoLongItHasToGoInASeparateLineWhenOverriden:\n"
870 " undefined;\n"
871 "}\n");
872 verifyFormat(
873 "class C extends P {\n"
874 " protected override "
875 "anOverlyLongMethodNameSoLongItHasToGoInASeparateLineWhenOverriden() {\n"
876 " }\n"
877 "}\n");
878 verifyFormat("class C extends P {\n"
879 " protected override aMethodName<ATypeParam extends {},\n"
880 " BTypeParam "
881 "extends {}>() {}\n"
882 "}\n");
883 }
884
TEST_F(FormatTestJS,FunctionParametersTrailingComma)885 TEST_F(FormatTestJS, FunctionParametersTrailingComma) {
886 verifyFormat("function trailingComma(\n"
887 " p1,\n"
888 " p2,\n"
889 " p3,\n"
890 ") {\n"
891 " a; //\n"
892 "}\n",
893 "function trailingComma(p1, p2, p3,) {\n"
894 " a; //\n"
895 "}\n");
896 verifyFormat("trailingComma(\n"
897 " p1,\n"
898 " p2,\n"
899 " p3,\n"
900 ");\n",
901 "trailingComma(p1, p2, p3,);\n");
902 verifyFormat("trailingComma(\n"
903 " p1 // hello\n"
904 ");\n",
905 "trailingComma(p1 // hello\n"
906 ");\n");
907 }
908
TEST_F(FormatTestJS,ArrayLiterals)909 TEST_F(FormatTestJS, ArrayLiterals) {
910 verifyFormat("var aaaaa: List<SomeThing> =\n"
911 " [new SomeThingAAAAAAAAAAAA(), new SomeThingBBBBBBBBB()];");
912 verifyFormat("return [\n"
913 " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
914 " ccccccccccccccccccccccccccc\n"
915 "];");
916 verifyFormat("return [\n"
917 " aaaa().bbbbbbbb('A'),\n"
918 " aaaa().bbbbbbbb('B'),\n"
919 " aaaa().bbbbbbbb('C'),\n"
920 "];");
921 verifyFormat("var someVariable = SomeFunction([\n"
922 " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
923 " ccccccccccccccccccccccccccc\n"
924 "]);");
925 verifyFormat("var someVariable = SomeFunction([\n"
926 " [aaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbb],\n"
927 "]);",
928 getGoogleJSStyleWithColumns(51));
929 verifyFormat("var someVariable = SomeFunction(aaaa, [\n"
930 " aaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
931 " ccccccccccccccccccccccccccc\n"
932 "]);");
933 verifyFormat("var someVariable = SomeFunction(\n"
934 " aaaa,\n"
935 " [\n"
936 " aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbb,\n"
937 " cccccccccccccccccccccccccc\n"
938 " ],\n"
939 " aaaa);");
940 verifyFormat("var aaaa = aaaaa || // wrap\n"
941 " [];");
942
943 verifyFormat("someFunction([], {a: a});");
944
945 verifyFormat("var string = [\n"
946 " 'aaaaaa',\n"
947 " 'bbbbbb',\n"
948 "].join('+');");
949 }
950
TEST_F(FormatTestJS,ColumnLayoutForArrayLiterals)951 TEST_F(FormatTestJS, ColumnLayoutForArrayLiterals) {
952 verifyFormat("var array = [\n"
953 " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n"
954 " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n"
955 "];");
956 verifyFormat("var array = someFunction([\n"
957 " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n"
958 " a, a, a, a, a, a, a, a, a, a, a, a, a, a, a,\n"
959 "]);");
960 }
961
TEST_F(FormatTestJS,TrailingCommaInsertion)962 TEST_F(FormatTestJS, TrailingCommaInsertion) {
963 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
964 Style.InsertTrailingCommas = FormatStyle::TCS_Wrapped;
965 // Insert comma in wrapped array.
966 verifyFormat("const x = [\n"
967 " 1, //\n"
968 " 2,\n"
969 "];",
970 "const x = [\n"
971 " 1, //\n"
972 " 2];",
973 Style);
974 // Insert comma in newly wrapped array.
975 Style.ColumnLimit = 30;
976 verifyFormat("const x = [\n"
977 " aaaaaaaaaaaaaaaaaaaaaaaaa,\n"
978 "];",
979 "const x = [aaaaaaaaaaaaaaaaaaaaaaaaa];", Style);
980 // Do not insert trailing commas if they'd exceed the colum limit
981 verifyFormat("const x = [\n"
982 " aaaaaaaaaaaaaaaaaaaaaaaaaaaa\n"
983 "];",
984 "const x = [aaaaaaaaaaaaaaaaaaaaaaaaaaaa];", Style);
985 // Object literals.
986 verifyFormat("const x = {\n"
987 " a: aaaaaaaaaaaaaaaaa,\n"
988 "};",
989 "const x = {a: aaaaaaaaaaaaaaaaa};", Style);
990 verifyFormat("const x = {\n"
991 " a: aaaaaaaaaaaaaaaaaaaaaaaaa\n"
992 "};",
993 "const x = {a: aaaaaaaaaaaaaaaaaaaaaaaaa};", Style);
994 // Object literal types.
995 verifyFormat("let x: {\n"
996 " a: aaaaaaaaaaaaaaaaaaaaa,\n"
997 "};",
998 "let x: {a: aaaaaaaaaaaaaaaaaaaaa};", Style);
999 }
1000
TEST_F(FormatTestJS,FunctionLiterals)1001 TEST_F(FormatTestJS, FunctionLiterals) {
1002 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
1003 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
1004 verifyFormat("doFoo(function() {});");
1005 verifyFormat("doFoo(function() { return 1; });", Style);
1006 verifyFormat("var func = function() {\n"
1007 " return 1;\n"
1008 "};");
1009 verifyFormat("var func = //\n"
1010 " function() {\n"
1011 " return 1;\n"
1012 "};");
1013 verifyFormat("return {\n"
1014 " body: {\n"
1015 " setAttribute: function(key, val) { this[key] = val; },\n"
1016 " getAttribute: function(key) { return this[key]; },\n"
1017 " style: {direction: ''}\n"
1018 " }\n"
1019 "};",
1020 Style);
1021 verifyFormat("abc = xyz ? function() {\n"
1022 " return 1;\n"
1023 "} : function() {\n"
1024 " return -1;\n"
1025 "};");
1026
1027 verifyFormat("var closure = goog.bind(\n"
1028 " function() { // comment\n"
1029 " foo();\n"
1030 " bar();\n"
1031 " },\n"
1032 " this, arg1IsReallyLongAndNeedsLineBreaks,\n"
1033 " arg3IsReallyLongAndNeedsLineBreaks);");
1034 verifyFormat("var closure = goog.bind(function() { // comment\n"
1035 " foo();\n"
1036 " bar();\n"
1037 "}, this);");
1038 verifyFormat("return {\n"
1039 " a: 'E',\n"
1040 " b: function() {\n"
1041 " return function() {\n"
1042 " f(); //\n"
1043 " };\n"
1044 " }\n"
1045 "};");
1046 verifyFormat("{\n"
1047 " var someVariable = function(x) {\n"
1048 " return x.zIsTooLongForOneLineWithTheDeclarationLine();\n"
1049 " };\n"
1050 "}");
1051 verifyFormat("someLooooooooongFunction(\n"
1052 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
1053 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
1054 " function(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa) {\n"
1055 " // code\n"
1056 " });");
1057
1058 verifyFormat("return {\n"
1059 " a: function SomeFunction() {\n"
1060 " // ...\n"
1061 " return 1;\n"
1062 " }\n"
1063 "};");
1064 verifyFormat("this.someObject.doSomething(aaaaaaaaaaaaaaaaaaaaaaaaaa)\n"
1065 " .then(goog.bind(function(aaaaaaaaaaa) {\n"
1066 " someFunction();\n"
1067 " someFunction();\n"
1068 " }, this), aaaaaaaaaaaaaaaaa);");
1069
1070 verifyFormat("someFunction(goog.bind(function() {\n"
1071 " doSomething();\n"
1072 " doSomething();\n"
1073 "}, this), goog.bind(function() {\n"
1074 " doSomething();\n"
1075 " doSomething();\n"
1076 "}, this));");
1077
1078 verifyFormat("SomeFunction(function() {\n"
1079 " foo();\n"
1080 " bar();\n"
1081 "}.bind(this));");
1082
1083 verifyFormat("SomeFunction((function() {\n"
1084 " foo();\n"
1085 " bar();\n"
1086 " }).bind(this));");
1087
1088 // FIXME: This is bad, we should be wrapping before "function() {".
1089 verifyFormat("someFunction(function() {\n"
1090 " doSomething(); // break\n"
1091 "})\n"
1092 " .doSomethingElse(\n"
1093 " // break\n"
1094 " );");
1095
1096 Style.ColumnLimit = 33;
1097 verifyFormat("f({a: function() { return 1; }});", Style);
1098 Style.ColumnLimit = 32;
1099 verifyFormat("f({\n"
1100 " a: function() { return 1; }\n"
1101 "});",
1102 Style);
1103 }
1104
TEST_F(FormatTestJS,DontWrapEmptyLiterals)1105 TEST_F(FormatTestJS, DontWrapEmptyLiterals) {
1106 verifyFormat("(aaaaaaaaaaaaaaaaaaaaa.getData as jasmine.Spy)\n"
1107 " .and.returnValue(Observable.of([]));");
1108 verifyFormat("(aaaaaaaaaaaaaaaaaaaaa.getData as jasmine.Spy)\n"
1109 " .and.returnValue(Observable.of({}));");
1110 verifyFormat("(aaaaaaaaaaaaaaaaaaaaa.getData as jasmine.Spy)\n"
1111 " .and.returnValue(Observable.of(()));");
1112 }
1113
TEST_F(FormatTestJS,InliningFunctionLiterals)1114 TEST_F(FormatTestJS, InliningFunctionLiterals) {
1115 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
1116 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
1117 verifyFormat("var func = function() {\n"
1118 " return 1;\n"
1119 "};",
1120 Style);
1121 verifyFormat("var func = doSomething(function() { return 1; });", Style);
1122 verifyFormat("var outer = function() {\n"
1123 " var inner = function() { return 1; }\n"
1124 "};",
1125 Style);
1126 verifyFormat("function outer1(a, b) {\n"
1127 " function inner1(a, b) { return a; }\n"
1128 "}",
1129 Style);
1130
1131 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
1132 verifyFormat("var func = function() { return 1; };", Style);
1133 verifyFormat("var func = doSomething(function() { return 1; });", Style);
1134 verifyFormat(
1135 "var outer = function() { var inner = function() { return 1; } };",
1136 Style);
1137 verifyFormat("function outer1(a, b) {\n"
1138 " function inner1(a, b) { return a; }\n"
1139 "}",
1140 Style);
1141
1142 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
1143 verifyFormat("var func = function() {\n"
1144 " return 1;\n"
1145 "};",
1146 Style);
1147 verifyFormat("var func = doSomething(function() {\n"
1148 " return 1;\n"
1149 "});",
1150 Style);
1151 verifyFormat("var outer = function() {\n"
1152 " var inner = function() {\n"
1153 " return 1;\n"
1154 " }\n"
1155 "};",
1156 Style);
1157 verifyFormat("function outer1(a, b) {\n"
1158 " function inner1(a, b) {\n"
1159 " return a;\n"
1160 " }\n"
1161 "}",
1162 Style);
1163
1164 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Empty;
1165 verifyFormat("var func = function() {\n"
1166 " return 1;\n"
1167 "};",
1168 Style);
1169 }
1170
TEST_F(FormatTestJS,MultipleFunctionLiterals)1171 TEST_F(FormatTestJS, MultipleFunctionLiterals) {
1172 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
1173 Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_All;
1174 verifyFormat("promise.then(\n"
1175 " function success() {\n"
1176 " doFoo();\n"
1177 " doBar();\n"
1178 " },\n"
1179 " function error() {\n"
1180 " doFoo();\n"
1181 " doBaz();\n"
1182 " },\n"
1183 " []);\n");
1184 verifyFormat("promise.then(\n"
1185 " function success() {\n"
1186 " doFoo();\n"
1187 " doBar();\n"
1188 " },\n"
1189 " [],\n"
1190 " function error() {\n"
1191 " doFoo();\n"
1192 " doBaz();\n"
1193 " });\n");
1194 verifyFormat("promise.then(\n"
1195 " [],\n"
1196 " function success() {\n"
1197 " doFoo();\n"
1198 " doBar();\n"
1199 " },\n"
1200 " function error() {\n"
1201 " doFoo();\n"
1202 " doBaz();\n"
1203 " });\n");
1204
1205 verifyFormat("getSomeLongPromise()\n"
1206 " .then(function(value) { body(); })\n"
1207 " .thenCatch(function(error) {\n"
1208 " body();\n"
1209 " body();\n"
1210 " });",
1211 Style);
1212 verifyFormat("getSomeLongPromise()\n"
1213 " .then(function(value) {\n"
1214 " body();\n"
1215 " body();\n"
1216 " })\n"
1217 " .thenCatch(function(error) {\n"
1218 " body();\n"
1219 " body();\n"
1220 " });");
1221
1222 verifyFormat("getSomeLongPromise()\n"
1223 " .then(function(value) { body(); })\n"
1224 " .thenCatch(function(error) { body(); });",
1225 Style);
1226
1227 verifyFormat("return [aaaaaaaaaaaaaaaaaaaaaa]\n"
1228 " .aaaaaaa(function() {\n"
1229 " //\n"
1230 " })\n"
1231 " .bbbbbb();");
1232 }
1233
TEST_F(FormatTestJS,ArrowFunctions)1234 TEST_F(FormatTestJS, ArrowFunctions) {
1235 verifyFormat("var x = (a) => {\n"
1236 " x;\n"
1237 " return a;\n"
1238 "};\n");
1239 verifyFormat("var x = (a) => {\n"
1240 " function y() {\n"
1241 " return 42;\n"
1242 " }\n"
1243 " return a;\n"
1244 "};");
1245 verifyFormat("var x = (a: type): {some: type} => {\n"
1246 " y;\n"
1247 " return a;\n"
1248 "};");
1249 verifyFormat("var x = (a) => a;");
1250 verifyFormat("return () => [];");
1251 verifyFormat("var aaaaaaaaaaaaaaaaaaaa = {\n"
1252 " aaaaaaaaaaaaaaaaaaaaaaaaaaaa:\n"
1253 " (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
1254 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) =>\n"
1255 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
1256 "};");
1257 verifyFormat("var a = a.aaaaaaa(\n"
1258 " (a: a) => aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) &&\n"
1259 " aaaaaaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
1260 verifyFormat("var a = a.aaaaaaa(\n"
1261 " (a: a) => aaaaaaaaaaaaaaaaaaaaa(bbbbbbbbb) ?\n"
1262 " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb) :\n"
1263 " aaaaaaaaaaaaaaaaaaaaa(bbbbbbb));");
1264
1265 // FIXME: This is bad, we should be wrapping before "() => {".
1266 verifyFormat("someFunction(() => {\n"
1267 " doSomething(); // break\n"
1268 "})\n"
1269 " .doSomethingElse(\n"
1270 " // break\n"
1271 " );");
1272 verifyFormat("const f = (x: string|null): string|null => {\n"
1273 " y;\n"
1274 " return x;\n"
1275 "}\n");
1276 }
1277
TEST_F(FormatTestJS,ArrowFunctionStyle)1278 TEST_F(FormatTestJS, ArrowFunctionStyle) {
1279 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
1280 Style.AllowShortLambdasOnASingleLine = FormatStyle::SLS_All;
1281 verifyFormat("const arr = () => { x; };", Style);
1282 verifyFormat("const arrInlineAll = () => {};", Style);
1283 Style.AllowShortLambdasOnASingleLine = FormatStyle::SLS_None;
1284 verifyFormat("const arr = () => {\n"
1285 " x;\n"
1286 "};",
1287 Style);
1288 verifyFormat("const arrInlineNone = () => {\n"
1289 "};",
1290 Style);
1291 Style.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Empty;
1292 verifyFormat("const arr = () => {\n"
1293 " x;\n"
1294 "};",
1295 Style);
1296 verifyFormat("const arrInlineEmpty = () => {};", Style);
1297 Style.AllowShortLambdasOnASingleLine = FormatStyle::SLS_Inline;
1298 verifyFormat("const arr = () => {\n"
1299 " x;\n"
1300 "};",
1301 Style);
1302 verifyFormat("foo(() => {});", Style);
1303 verifyFormat("const arrInlineInline = () => {};", Style);
1304 }
1305
TEST_F(FormatTestJS,ReturnStatements)1306 TEST_F(FormatTestJS, ReturnStatements) {
1307 verifyFormat("function() {\n"
1308 " return [hello, world];\n"
1309 "}");
1310 }
1311
TEST_F(FormatTestJS,ForLoops)1312 TEST_F(FormatTestJS, ForLoops) {
1313 verifyFormat("for (var i in [2, 3]) {\n"
1314 "}");
1315 verifyFormat("for (var i of [2, 3]) {\n"
1316 "}");
1317 verifyFormat("for (let {a, b} of x) {\n"
1318 "}");
1319 verifyFormat("for (let {a, b} of [x]) {\n"
1320 "}");
1321 verifyFormat("for (let [a, b] of [x]) {\n"
1322 "}");
1323 verifyFormat("for (let {a, b} in x) {\n"
1324 "}");
1325 }
1326
TEST_F(FormatTestJS,WrapRespectsAutomaticSemicolonInsertion)1327 TEST_F(FormatTestJS, WrapRespectsAutomaticSemicolonInsertion) {
1328 // The following statements must not wrap, as otherwise the program meaning
1329 // would change due to automatic semicolon insertion.
1330 // See http://www.ecma-international.org/ecma-262/5.1/#sec-7.9.1.
1331 verifyFormat("return aaaaa;", getGoogleJSStyleWithColumns(10));
1332 verifyFormat("yield aaaaa;", getGoogleJSStyleWithColumns(10));
1333 verifyFormat("return /* hello! */ aaaaa;", getGoogleJSStyleWithColumns(10));
1334 verifyFormat("continue aaaaa;", getGoogleJSStyleWithColumns(10));
1335 verifyFormat("continue /* hello! */ aaaaa;", getGoogleJSStyleWithColumns(10));
1336 verifyFormat("break aaaaa;", getGoogleJSStyleWithColumns(10));
1337 verifyFormat("throw aaaaa;", getGoogleJSStyleWithColumns(10));
1338 verifyFormat("aaaaaaaaa++;", getGoogleJSStyleWithColumns(10));
1339 verifyFormat("aaaaaaaaa--;", getGoogleJSStyleWithColumns(10));
1340 verifyFormat("return [\n"
1341 " aaa\n"
1342 "];",
1343 getGoogleJSStyleWithColumns(12));
1344 verifyFormat("class X {\n"
1345 " readonly ratherLongField =\n"
1346 " 1;\n"
1347 "}",
1348 "class X {\n"
1349 " readonly ratherLongField = 1;\n"
1350 "}",
1351 getGoogleJSStyleWithColumns(20));
1352 verifyFormat("const x = (5 + 9)\n"
1353 "const y = 3\n",
1354 "const x = ( 5 + 9)\n"
1355 "const y = 3\n");
1356 // Ideally the foo() bit should be indented relative to the async function().
1357 verifyFormat("async function\n"
1358 "foo() {}",
1359 getGoogleJSStyleWithColumns(10));
1360 verifyFormat("await theReckoning;", getGoogleJSStyleWithColumns(10));
1361 verifyFormat("some['a']['b']", getGoogleJSStyleWithColumns(10));
1362 verifyFormat("x = (a['a']\n"
1363 " ['b']);",
1364 getGoogleJSStyleWithColumns(10));
1365 verifyFormat("function f() {\n"
1366 " return foo.bar(\n"
1367 " (param): param is {\n"
1368 " a: SomeType\n"
1369 " }&ABC => 1)\n"
1370 "}",
1371 getGoogleJSStyleWithColumns(25));
1372 }
1373
TEST_F(FormatTestJS,AddsIsTheDictKeyOnNewline)1374 TEST_F(FormatTestJS, AddsIsTheDictKeyOnNewline) {
1375 // Do not confuse is, the dict key with is, the type matcher. Put is, the dict
1376 // key, on a newline.
1377 verifyFormat("Polymer({\n"
1378 " is: '', //\n"
1379 " rest: 1\n"
1380 "});",
1381 getGoogleJSStyleWithColumns(20));
1382 }
1383
TEST_F(FormatTestJS,AutomaticSemicolonInsertionHeuristic)1384 TEST_F(FormatTestJS, AutomaticSemicolonInsertionHeuristic) {
1385 verifyFormat("a\n"
1386 "b;",
1387 " a \n"
1388 " b ;");
1389 verifyFormat("a()\n"
1390 "b;",
1391 " a ()\n"
1392 " b ;");
1393 verifyFormat("a[b]\n"
1394 "c;",
1395 "a [b]\n"
1396 "c ;");
1397 verifyFormat("1\n"
1398 "a;",
1399 "1 \n"
1400 "a ;");
1401 verifyFormat("a\n"
1402 "1;",
1403 "a \n"
1404 "1 ;");
1405 verifyFormat("a\n"
1406 "'x';",
1407 "a \n"
1408 " 'x';");
1409 verifyFormat("a++\n"
1410 "b;",
1411 "a ++\n"
1412 "b ;");
1413 verifyFormat("a\n"
1414 "!b && c;",
1415 "a \n"
1416 " ! b && c;");
1417 verifyFormat("a\n"
1418 "if (1) f();",
1419 " a\n"
1420 " if (1) f();");
1421 verifyFormat("a\n"
1422 "class X {}",
1423 " a\n"
1424 " class X {}");
1425 verifyFormat("var a", "var\n"
1426 "a");
1427 verifyFormat("x instanceof String", "x\n"
1428 "instanceof\n"
1429 "String");
1430 verifyFormat("function f(@Foo bar) {}", "function f(@Foo\n"
1431 " bar) {}");
1432 verifyFormat("function f(@Foo(Param) bar) {}", "function f(@Foo(Param)\n"
1433 " bar) {}");
1434 verifyFormat("a = true\n"
1435 "return 1",
1436 "a = true\n"
1437 " return 1");
1438 verifyFormat("a = 's'\n"
1439 "return 1",
1440 "a = 's'\n"
1441 " return 1");
1442 verifyFormat("a = null\n"
1443 "return 1",
1444 "a = null\n"
1445 " return 1");
1446 // Below "class Y {}" should ideally be on its own line.
1447 verifyFormat("x = {\n"
1448 " a: 1\n"
1449 "} class Y {}",
1450 " x = {a : 1}\n"
1451 " class Y { }");
1452 verifyFormat("if (x) {\n"
1453 "}\n"
1454 "return 1",
1455 "if (x) {}\n"
1456 " return 1");
1457 verifyFormat("if (x) {\n"
1458 "}\n"
1459 "class X {}",
1460 "if (x) {}\n"
1461 " class X {}");
1462 }
1463
TEST_F(FormatTestJS,ImportExportASI)1464 TEST_F(FormatTestJS, ImportExportASI) {
1465 verifyFormat("import {x} from 'y'\n"
1466 "export function z() {}",
1467 "import {x} from 'y'\n"
1468 " export function z() {}");
1469 // Below "class Y {}" should ideally be on its own line.
1470 verifyFormat("export {x} class Y {}", " export {x}\n"
1471 " class Y {\n}");
1472 verifyFormat("if (x) {\n"
1473 "}\n"
1474 "export class Y {}",
1475 "if ( x ) { }\n"
1476 " export class Y {}");
1477 }
1478
TEST_F(FormatTestJS,ClosureStyleCasts)1479 TEST_F(FormatTestJS, ClosureStyleCasts) {
1480 verifyFormat("var x = /** @type {foo} */ (bar);");
1481 }
1482
TEST_F(FormatTestJS,TryCatch)1483 TEST_F(FormatTestJS, TryCatch) {
1484 verifyFormat("try {\n"
1485 " f();\n"
1486 "} catch (e) {\n"
1487 " g();\n"
1488 "} finally {\n"
1489 " h();\n"
1490 "}");
1491
1492 // But, of course, "catch" is a perfectly fine function name in JavaScript.
1493 verifyFormat("someObject.catch();");
1494 verifyFormat("someObject.new();");
1495 }
1496
TEST_F(FormatTestJS,StringLiteralConcatenation)1497 TEST_F(FormatTestJS, StringLiteralConcatenation) {
1498 verifyFormat("var literal = 'hello ' +\n"
1499 " 'world';");
1500 }
1501
TEST_F(FormatTestJS,RegexLiteralClassification)1502 TEST_F(FormatTestJS, RegexLiteralClassification) {
1503 // Regex literals.
1504 verifyFormat("var regex = /abc/;");
1505 verifyFormat("f(/abc/);");
1506 verifyFormat("f(abc, /abc/);");
1507 verifyFormat("some_map[/abc/];");
1508 verifyFormat("var x = a ? /abc/ : /abc/;");
1509 verifyFormat("for (var i = 0; /abc/.test(s[i]); i++) {\n}");
1510 verifyFormat("var x = !/abc/.test(y);");
1511 verifyFormat("var x = foo()! / 10;");
1512 verifyFormat("var x = a && /abc/.test(y);");
1513 verifyFormat("var x = a || /abc/.test(y);");
1514 verifyFormat("var x = a + /abc/.search(y);");
1515 verifyFormat("/abc/.search(y);");
1516 verifyFormat("var regexs = {/abc/, /abc/};");
1517 verifyFormat("return /abc/;");
1518
1519 // Not regex literals.
1520 verifyFormat("var a = a / 2 + b / 3;");
1521 verifyFormat("var a = a++ / 2;");
1522 // Prefix unary can operate on regex literals, not that it makes sense.
1523 verifyFormat("var a = ++/a/;");
1524
1525 // This is a known issue, regular expressions are incorrectly detected if
1526 // directly following a closing parenthesis.
1527 verifyFormat("if (foo) / bar /.exec(baz);");
1528 }
1529
TEST_F(FormatTestJS,RegexLiteralSpecialCharacters)1530 TEST_F(FormatTestJS, RegexLiteralSpecialCharacters) {
1531 verifyFormat("var regex = /=/;");
1532 verifyFormat("var regex = /a*/;");
1533 verifyFormat("var regex = /a+/;");
1534 verifyFormat("var regex = /a?/;");
1535 verifyFormat("var regex = /.a./;");
1536 verifyFormat("var regex = /a\\*/;");
1537 verifyFormat("var regex = /^a$/;");
1538 verifyFormat("var regex = /\\/a/;");
1539 verifyFormat("var regex = /(?:x)/;");
1540 verifyFormat("var regex = /x(?=y)/;");
1541 verifyFormat("var regex = /x(?!y)/;");
1542 verifyFormat("var regex = /x|y/;");
1543 verifyFormat("var regex = /a{2}/;");
1544 verifyFormat("var regex = /a{1,3}/;");
1545
1546 verifyFormat("var regex = /[abc]/;");
1547 verifyFormat("var regex = /[^abc]/;");
1548 verifyFormat("var regex = /[\\b]/;");
1549 verifyFormat("var regex = /[/]/;");
1550 verifyFormat("var regex = /[\\/]/;");
1551 verifyFormat("var regex = /\\[/;");
1552 verifyFormat("var regex = /\\\\[/]/;");
1553 verifyFormat("var regex = /}[\"]/;");
1554 verifyFormat("var regex = /}[/\"]/;");
1555 verifyFormat("var regex = /}[\"/]/;");
1556
1557 verifyFormat("var regex = /\\b/;");
1558 verifyFormat("var regex = /\\B/;");
1559 verifyFormat("var regex = /\\d/;");
1560 verifyFormat("var regex = /\\D/;");
1561 verifyFormat("var regex = /\\f/;");
1562 verifyFormat("var regex = /\\n/;");
1563 verifyFormat("var regex = /\\r/;");
1564 verifyFormat("var regex = /\\s/;");
1565 verifyFormat("var regex = /\\S/;");
1566 verifyFormat("var regex = /\\t/;");
1567 verifyFormat("var regex = /\\v/;");
1568 verifyFormat("var regex = /\\w/;");
1569 verifyFormat("var regex = /\\W/;");
1570 verifyFormat("var regex = /a(a)\\1/;");
1571 verifyFormat("var regex = /\\0/;");
1572 verifyFormat("var regex = /\\\\/g;");
1573 verifyFormat("var regex = /\\a\\\\/g;");
1574 verifyFormat("var regex = /\a\\//g;");
1575 verifyFormat("var regex = /a\\//;\n"
1576 "var x = 0;");
1577 verifyFormat("var regex = /'/g;", "var regex = /'/g ;");
1578 verifyFormat("var regex = /'/g; //'", "var regex = /'/g ; //'");
1579 verifyFormat("var regex = /\\/*/;\n"
1580 "var x = 0;",
1581 "var regex = /\\/*/;\n"
1582 "var x=0;");
1583 verifyFormat("var x = /a\\//;", "var x = /a\\// \n;");
1584 verifyFormat("var regex = /\"/;", getGoogleJSStyleWithColumns(16));
1585 verifyFormat("var regex =\n"
1586 " /\"/;",
1587 getGoogleJSStyleWithColumns(15));
1588 verifyFormat("var regex = //\n"
1589 " /a/;");
1590 verifyFormat("var regexs = [\n"
1591 " /d/, //\n"
1592 " /aa/, //\n"
1593 "];");
1594 }
1595
TEST_F(FormatTestJS,RegexLiteralModifiers)1596 TEST_F(FormatTestJS, RegexLiteralModifiers) {
1597 verifyFormat("var regex = /abc/g;");
1598 verifyFormat("var regex = /abc/i;");
1599 verifyFormat("var regex = /abc/m;");
1600 verifyFormat("var regex = /abc/y;");
1601 }
1602
TEST_F(FormatTestJS,RegexLiteralLength)1603 TEST_F(FormatTestJS, RegexLiteralLength) {
1604 verifyFormat("var regex = /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
1605 getGoogleJSStyleWithColumns(60));
1606 verifyFormat("var regex =\n"
1607 " /aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
1608 getGoogleJSStyleWithColumns(60));
1609 verifyFormat("var regex = /\\xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/;",
1610 getGoogleJSStyleWithColumns(50));
1611 }
1612
TEST_F(FormatTestJS,RegexLiteralExamples)1613 TEST_F(FormatTestJS, RegexLiteralExamples) {
1614 verifyFormat("var regex = search.match(/(?:\?|&)times=([^?&]+)/i);");
1615 }
1616
TEST_F(FormatTestJS,IgnoresMpegTS)1617 TEST_F(FormatTestJS, IgnoresMpegTS) {
1618 std::string MpegTS(200, ' ');
1619 MpegTS.replace(0, strlen("nearlyLooks + like + ts + code; "),
1620 "nearlyLooks + like + ts + code; ");
1621 MpegTS[0] = 0x47;
1622 MpegTS[188] = 0x47;
1623 verifyFormat(MpegTS, MpegTS);
1624 }
1625
TEST_F(FormatTestJS,TypeAnnotations)1626 TEST_F(FormatTestJS, TypeAnnotations) {
1627 verifyFormat("var x: string;");
1628 verifyFormat("var x: {a: string; b: number;} = {};");
1629 verifyFormat("function x(): string {\n return 'x';\n}");
1630 verifyFormat("function x(): {x: string} {\n return {x: 'x'};\n}");
1631 verifyFormat("function x(y: string): string {\n return 'x';\n}");
1632 verifyFormat("for (var y: string in x) {\n x();\n}");
1633 verifyFormat("for (var y: string of x) {\n x();\n}");
1634 verifyFormat("function x(y: {a?: number;} = {}): number {\n"
1635 " return 12;\n"
1636 "}");
1637 verifyFormat("const x: Array<{a: number; b: string;}> = [];");
1638 verifyFormat("((a: string, b: number): string => a + b);");
1639 verifyFormat("var x: (y: number) => string;");
1640 verifyFormat("var x: P<string, (a: number) => string>;");
1641 verifyFormat("var x = {\n"
1642 " y: function(): z {\n"
1643 " return 1;\n"
1644 " }\n"
1645 "};");
1646 verifyFormat("var x = {\n"
1647 " y: function(): {a: number} {\n"
1648 " return 1;\n"
1649 " }\n"
1650 "};");
1651 verifyFormat("function someFunc(args: string[]):\n"
1652 " {longReturnValue: string[]} {}",
1653 getGoogleJSStyleWithColumns(60));
1654 verifyFormat(
1655 "var someValue = (v as aaaaaaaaaaaaaaaaaaaa<T>[])\n"
1656 " .someFunction(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);");
1657 verifyFormat("const xIsALongIdent:\n"
1658 " YJustBarelyFitsLinex[];",
1659 getGoogleJSStyleWithColumns(20));
1660 verifyFormat("const x = {\n"
1661 " y: 1\n"
1662 "} as const;");
1663 }
1664
TEST_F(FormatTestJS,UnionIntersectionTypes)1665 TEST_F(FormatTestJS, UnionIntersectionTypes) {
1666 verifyFormat("let x: A|B = A | B;");
1667 verifyFormat("let x: A&B|C = A & B;");
1668 verifyFormat("let x: Foo<A|B> = new Foo<A|B>();");
1669 verifyFormat("function(x: A|B): C&D {}");
1670 verifyFormat("function(x: A|B = A | B): C&D {}");
1671 verifyFormat("function x(path: number|string) {}");
1672 verifyFormat("function x(): string|number {}");
1673 verifyFormat("type Foo = Bar|Baz;");
1674 verifyFormat("type Foo = Bar<X>|Baz;");
1675 verifyFormat("type Foo = (Bar<X>|Baz);");
1676 verifyFormat("let x: Bar|Baz;");
1677 verifyFormat("let x: Bar<X>|Baz;");
1678 verifyFormat("let x: (Foo|Bar)[];");
1679 verifyFormat("type X = {\n"
1680 " a: Foo|Bar;\n"
1681 "};");
1682 verifyFormat("export type X = {\n"
1683 " a: Foo|Bar;\n"
1684 "};");
1685 }
1686
TEST_F(FormatTestJS,UnionIntersectionTypesInObjectType)1687 TEST_F(FormatTestJS, UnionIntersectionTypesInObjectType) {
1688 verifyFormat("let x: {x: number|null} = {x: number | null};");
1689 verifyFormat("let nested: {x: {y: number|null}};");
1690 verifyFormat("let mixed: {x: [number|null, {w: number}]};");
1691 verifyFormat("class X {\n"
1692 " contructor(x: {\n"
1693 " a: a|null,\n"
1694 " b: b|null,\n"
1695 " }) {}\n"
1696 "}");
1697 }
1698
TEST_F(FormatTestJS,ClassDeclarations)1699 TEST_F(FormatTestJS, ClassDeclarations) {
1700 verifyFormat("class C {\n x: string = 12;\n}");
1701 verifyFormat("class C {\n x(): string => 12;\n}");
1702 verifyFormat("class C {\n ['x' + 2]: string = 12;\n}");
1703 verifyFormat("class C {\n"
1704 " foo() {}\n"
1705 " [bar]() {}\n"
1706 "}\n");
1707 verifyFormat("class C {\n private x: string = 12;\n}");
1708 verifyFormat("class C {\n private static x: string = 12;\n}");
1709 verifyFormat("class C {\n static x(): string {\n return 'asd';\n }\n}");
1710 verifyFormat("class C extends P implements I {}");
1711 verifyFormat("class C extends p.P implements i.I {}");
1712 verifyFormat("x(class {\n"
1713 " a(): A {}\n"
1714 "});");
1715 verifyFormat("class Test {\n"
1716 " aaaaaaaaaaaaaaaa(aaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaaa):\n"
1717 " aaaaaaaaaaaaaaaaaaaaaa {}\n"
1718 "}");
1719 verifyFormat("foo = class Name {\n"
1720 " constructor() {}\n"
1721 "};");
1722 verifyFormat("foo = class {\n"
1723 " constructor() {}\n"
1724 "};");
1725 verifyFormat("class C {\n"
1726 " x: {y: Z;} = {};\n"
1727 " private y: {y: Z;} = {};\n"
1728 "}");
1729
1730 // ':' is not a type declaration here.
1731 verifyFormat("class X {\n"
1732 " subs = {\n"
1733 " 'b': {\n"
1734 " 'c': 1,\n"
1735 " },\n"
1736 " };\n"
1737 "}");
1738 verifyFormat("@Component({\n"
1739 " moduleId: module.id,\n"
1740 "})\n"
1741 "class SessionListComponent implements OnDestroy, OnInit {\n"
1742 "}");
1743 }
1744
TEST_F(FormatTestJS,StrictPropInitWrap)1745 TEST_F(FormatTestJS, StrictPropInitWrap) {
1746 const FormatStyle &Style = getGoogleJSStyleWithColumns(22);
1747 verifyFormat("class X {\n"
1748 " strictPropInitField!:\n"
1749 " string;\n"
1750 "}",
1751 Style);
1752 }
1753
TEST_F(FormatTestJS,InterfaceDeclarations)1754 TEST_F(FormatTestJS, InterfaceDeclarations) {
1755 verifyFormat("interface I {\n"
1756 " x: string;\n"
1757 " enum: string[];\n"
1758 " enum?: string[];\n"
1759 "}\n"
1760 "var y;");
1761 // Ensure that state is reset after parsing the interface.
1762 verifyFormat("interface a {}\n"
1763 "export function b() {}\n"
1764 "var x;");
1765
1766 // Arrays of object type literals.
1767 verifyFormat("interface I {\n"
1768 " o: {}[];\n"
1769 "}");
1770 }
1771
TEST_F(FormatTestJS,ObjectTypesInExtendsImplements)1772 TEST_F(FormatTestJS, ObjectTypesInExtendsImplements) {
1773 verifyFormat("class C extends {} {}");
1774 verifyFormat("class C implements {bar: number} {}");
1775 // Somewhat odd, but probably closest to reasonable formatting?
1776 verifyFormat("class C implements {\n"
1777 " bar: number,\n"
1778 " baz: string,\n"
1779 "} {}");
1780 verifyFormat("class C<P extends {}> {}");
1781 }
1782
TEST_F(FormatTestJS,EnumDeclarations)1783 TEST_F(FormatTestJS, EnumDeclarations) {
1784 verifyFormat("enum Foo {\n"
1785 " A = 1,\n"
1786 " B\n"
1787 "}");
1788 verifyFormat("export /* somecomment*/ enum Foo {\n"
1789 " A = 1,\n"
1790 " B\n"
1791 "}");
1792 verifyFormat("enum Foo {\n"
1793 " A = 1, // comment\n"
1794 " B\n"
1795 "}\n"
1796 "var x = 1;");
1797 verifyFormat("const enum Foo {\n"
1798 " A = 1,\n"
1799 " B\n"
1800 "}");
1801 verifyFormat("export const enum Foo {\n"
1802 " A = 1,\n"
1803 " B\n"
1804 "}");
1805 }
1806
TEST_F(FormatTestJS,Decorators)1807 TEST_F(FormatTestJS, Decorators) {
1808 verifyFormat("@A\nclass C {\n}");
1809 verifyFormat("@A({arg: 'value'})\nclass C {\n}");
1810 verifyFormat("@A\n@B\nclass C {\n}");
1811 verifyFormat("class C {\n @A x: string;\n}");
1812 verifyFormat("class C {\n"
1813 " @A\n"
1814 " private x(): string {\n"
1815 " return 'y';\n"
1816 " }\n"
1817 "}");
1818 verifyFormat("class C {\n"
1819 " private x(@A x: string) {}\n"
1820 "}");
1821 verifyFormat("class X {}\n"
1822 "class Y {}");
1823 verifyFormat("class X {\n"
1824 " @property() private isReply = false;\n"
1825 "}\n");
1826 }
1827
TEST_F(FormatTestJS,TypeAliases)1828 TEST_F(FormatTestJS, TypeAliases) {
1829 verifyFormat("type X = number;\n"
1830 "class C {}");
1831 verifyFormat("type X<Y> = Z<Y>;");
1832 verifyFormat("type X = {\n"
1833 " y: number\n"
1834 "};\n"
1835 "class C {}");
1836 verifyFormat("export type X = {\n"
1837 " a: string,\n"
1838 " b?: string,\n"
1839 "};\n");
1840 }
1841
TEST_F(FormatTestJS,TypeInterfaceLineWrapping)1842 TEST_F(FormatTestJS, TypeInterfaceLineWrapping) {
1843 const FormatStyle &Style = getGoogleJSStyleWithColumns(20);
1844 verifyFormat("type LongTypeIsReallyUnreasonablyLong =\n"
1845 " string;\n",
1846 "type LongTypeIsReallyUnreasonablyLong = string;\n", Style);
1847 verifyFormat("interface AbstractStrategyFactoryProvider {\n"
1848 " a: number\n"
1849 "}\n",
1850 "interface AbstractStrategyFactoryProvider { a: number }\n",
1851 Style);
1852 }
1853
TEST_F(FormatTestJS,RemoveEmptyLinesInArrowFunctions)1854 TEST_F(FormatTestJS, RemoveEmptyLinesInArrowFunctions) {
1855 verifyFormat("x = () => {\n"
1856 " foo();\n"
1857 " bar();\n"
1858 "};\n",
1859 "x = () => {\n"
1860 "\n"
1861 " foo();\n"
1862 " bar();\n"
1863 "\n"
1864 "};\n");
1865 }
1866
TEST_F(FormatTestJS,Modules)1867 TEST_F(FormatTestJS, Modules) {
1868 verifyFormat("import SomeThing from 'some/module.js';");
1869 verifyFormat("import {X, Y} from 'some/module.js';");
1870 verifyFormat("import a, {X, Y} from 'some/module.js';");
1871 verifyFormat("import {X, Y,} from 'some/module.js';");
1872 verifyFormat("import {X as myLocalX, Y as myLocalY} from 'some/module.js';");
1873 // Ensure Automatic Semicolon Insertion does not break on "as\n".
1874 verifyFormat("import {X as myX} from 'm';", "import {X as\n"
1875 " myX} from 'm';");
1876 verifyFormat("import * as lib from 'some/module.js';");
1877 verifyFormat("var x = {import: 1};\nx.import = 2;");
1878 // Ensure an import statement inside a block is at the correct level.
1879 verifyFormat("function() {\n"
1880 " var x;\n"
1881 " import 'some/module.js';\n"
1882 "}");
1883
1884 verifyFormat("export function fn() {\n"
1885 " return 'fn';\n"
1886 "}");
1887 verifyFormat("export function A() {}\n"
1888 "export default function B() {}\n"
1889 "export function C() {}");
1890 verifyFormat("export default () => {\n"
1891 " let x = 1;\n"
1892 " return x;\n"
1893 "}");
1894 verifyFormat("export const x = 12;");
1895 verifyFormat("export default class X {}");
1896 verifyFormat("export {X, Y} from 'some/module.js';");
1897 verifyFormat("export {X, Y,} from 'some/module.js';");
1898 verifyFormat("export {SomeVeryLongExport as X, "
1899 "SomeOtherVeryLongExport as Y} from 'some/module.js';");
1900 // export without 'from' is wrapped.
1901 verifyFormat("export let someRatherLongVariableName =\n"
1902 " someSurprisinglyLongVariable + someOtherRatherLongVar;");
1903 // ... but not if from is just an identifier.
1904 verifyFormat("export {\n"
1905 " from as from,\n"
1906 " someSurprisinglyLongVariable as\n"
1907 " from\n"
1908 "};",
1909 getGoogleJSStyleWithColumns(20));
1910 verifyFormat("export class C {\n"
1911 " x: number;\n"
1912 " y: string;\n"
1913 "}");
1914 verifyFormat("export class X {\n"
1915 " y: number;\n"
1916 "}");
1917 verifyFormat("export abstract class X {\n"
1918 " y: number;\n"
1919 "}");
1920 verifyFormat("export default class X {\n"
1921 " y: number\n"
1922 "}");
1923 verifyFormat("export default function() {\n return 1;\n}");
1924 verifyFormat("export var x = 12;");
1925 verifyFormat("class C {}\n"
1926 "export function f() {}\n"
1927 "var v;");
1928 verifyFormat("export var x: number = 12;");
1929 verifyFormat("export const y = {\n"
1930 " a: 1,\n"
1931 " b: 2\n"
1932 "};");
1933 verifyFormat("export enum Foo {\n"
1934 " BAR,\n"
1935 " // adsdasd\n"
1936 " BAZ\n"
1937 "}");
1938 verifyFormat("export default [\n"
1939 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,\n"
1940 " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\n"
1941 "];");
1942 verifyFormat("export default [];");
1943 verifyFormat("export default () => {};");
1944 verifyFormat("export default () => {\n"
1945 " x;\n"
1946 " x;\n"
1947 "};");
1948 verifyFormat("export interface Foo {\n"
1949 " foo: number;\n"
1950 "}\n"
1951 "export class Bar {\n"
1952 " blah(): string {\n"
1953 " return this.blah;\n"
1954 " };\n"
1955 "}");
1956 }
1957
TEST_F(FormatTestJS,ImportWrapping)1958 TEST_F(FormatTestJS, ImportWrapping) {
1959 verifyFormat("import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,"
1960 " VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying"
1961 "} from 'some/module.js';");
1962 FormatStyle Style = getGoogleJSStyleWithColumns(80);
1963 Style.JavaScriptWrapImports = true;
1964 verifyFormat("import {\n"
1965 " VeryLongImportsAreAnnoying,\n"
1966 " VeryLongImportsAreAnnoying,\n"
1967 " VeryLongImportsAreAnnoying,\n"
1968 "} from 'some/module.js';",
1969 Style);
1970 verifyFormat("import {\n"
1971 " A,\n"
1972 " A,\n"
1973 "} from 'some/module.js';",
1974 Style);
1975 verifyFormat("export {\n"
1976 " A,\n"
1977 " A,\n"
1978 "} from 'some/module.js';",
1979 Style);
1980 Style.ColumnLimit = 40;
1981 // Using this version of verifyFormat because test::messUp hides the issue.
1982 verifyFormat("import {\n"
1983 " A,\n"
1984 "} from\n"
1985 " 'some/path/longer/than/column/limit/module.js';",
1986 " import { \n"
1987 " A, \n"
1988 " } from\n"
1989 " 'some/path/longer/than/column/limit/module.js' ; ",
1990 Style);
1991 }
1992
TEST_F(FormatTestJS,TemplateStrings)1993 TEST_F(FormatTestJS, TemplateStrings) {
1994 // Keeps any whitespace/indentation within the template string.
1995 verifyFormat("var x = `hello\n"
1996 " ${name}\n"
1997 " !`;",
1998 "var x = `hello\n"
1999 " ${ name }\n"
2000 " !`;");
2001
2002 verifyFormat("var x =\n"
2003 " `hello ${world}` >= some();",
2004 getGoogleJSStyleWithColumns(34)); // Barely doesn't fit.
2005 verifyFormat("var x = `hello ${world}` >= some();",
2006 getGoogleJSStyleWithColumns(35)); // Barely fits.
2007 verifyFormat("var x = `hellö ${wörld}` >= söme();",
2008 getGoogleJSStyleWithColumns(35)); // Fits due to UTF-8.
2009 verifyFormat("var x = `hello\n"
2010 " ${world}` >=\n"
2011 " some();",
2012 "var x =\n"
2013 " `hello\n"
2014 " ${world}` >= some();",
2015 getGoogleJSStyleWithColumns(21)); // Barely doesn't fit.
2016 verifyFormat("var x = `hello\n"
2017 " ${world}` >= some();",
2018 "var x =\n"
2019 " `hello\n"
2020 " ${world}` >= some();",
2021 getGoogleJSStyleWithColumns(22)); // Barely fits.
2022
2023 verifyFormat("var x =\n"
2024 " `h`;",
2025 getGoogleJSStyleWithColumns(11));
2026 verifyFormat("var x =\n `multi\n line`;", "var x = `multi\n line`;",
2027 getGoogleJSStyleWithColumns(13));
2028 verifyFormat("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n"
2029 " `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`);");
2030 // Repro for an obscure width-miscounting issue with template strings.
2031 verifyFormat(
2032 "someLongVariable =\n"
2033 " "
2034 "`${logPrefix[11]}/${logPrefix[12]}/${logPrefix[13]}${logPrefix[14]}`;",
2035 "someLongVariable = "
2036 "`${logPrefix[11]}/${logPrefix[12]}/${logPrefix[13]}${logPrefix[14]}`;");
2037
2038 // Make sure template strings get a proper ColumnWidth assigned, even if they
2039 // are first token in line.
2040 verifyFormat("var a = aaaaaaaaaaaaaaaaaaaaaaaaaaaa ||\n"
2041 " `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`;");
2042
2043 // Two template strings.
2044 verifyFormat("var x = `hello` == `hello`;");
2045
2046 // Comments in template strings.
2047 verifyFormat("var x = `//a`;\n"
2048 "var y;",
2049 "var x =\n `//a`;\n"
2050 "var y ;");
2051 verifyFormat("var x = `/*a`;\n"
2052 "var y;",
2053 "var x =\n `/*a`;\n"
2054 "var y;");
2055 // Unterminated string literals in a template string.
2056 verifyFormat("var x = `'`; // comment with matching quote '\n"
2057 "var y;");
2058 verifyFormat("var x = `\"`; // comment with matching quote \"\n"
2059 "var y;");
2060 verifyFormat("it(`'aaaaaaaaaaaaaaa `, aaaaaaaaa);",
2061 "it(`'aaaaaaaaaaaaaaa `, aaaaaaaaa) ;",
2062 getGoogleJSStyleWithColumns(40));
2063 // Backticks in a comment - not a template string.
2064 verifyFormat("var x = 1 // `/*a`;\n"
2065 " ;",
2066 "var x =\n 1 // `/*a`;\n"
2067 " ;");
2068 verifyFormat("/* ` */ var x = 1; /* ` */", "/* ` */ var x\n= 1; /* ` */");
2069 // Comment spans multiple template strings.
2070 verifyFormat("var x = `/*a`;\n"
2071 "var y = ` */ `;",
2072 "var x =\n `/*a`;\n"
2073 "var y =\n ` */ `;");
2074 // Escaped backtick.
2075 verifyFormat("var x = ` \\` a`;\n"
2076 "var y;",
2077 "var x = ` \\` a`;\n"
2078 "var y;");
2079 // Escaped dollar.
2080 verifyFormat("var x = ` \\${foo}`;\n");
2081
2082 // The token stream can contain two string_literals in sequence, but that
2083 // doesn't mean that they are implicitly concatenated in JavaScript.
2084 verifyFormat("var f = `aaaa ${a ? 'a' : 'b'}`;");
2085
2086 // Ensure that scopes are appropriately set around evaluated expressions in
2087 // template strings.
2088 verifyFormat("var f = `aaaaaaaaaaaaa:${aaaaaaa.aaaaa} aaaaaaaa\n"
2089 " aaaaaaaaaaaaa:${aaaaaaa.aaaaa} aaaaaaaa`;",
2090 "var f = `aaaaaaaaaaaaa:${aaaaaaa. aaaaa} aaaaaaaa\n"
2091 " aaaaaaaaaaaaa:${ aaaaaaa. aaaaa} aaaaaaaa`;");
2092 verifyFormat("var x = someFunction(`${})`) //\n"
2093 " .oooooooooooooooooon();");
2094 verifyFormat("var x = someFunction(`${aaaa}${\n"
2095 " aaaaa( //\n"
2096 " aaaaa)})`);");
2097 }
2098
TEST_F(FormatTestJS,TemplateStringMultiLineExpression)2099 TEST_F(FormatTestJS, TemplateStringMultiLineExpression) {
2100 verifyFormat("var f = `aaaaaaaaaaaaaaaaaa: ${\n"
2101 " aaaaa + //\n"
2102 " bbbb}`;",
2103 "var f = `aaaaaaaaaaaaaaaaaa: ${aaaaa + //\n"
2104 " bbbb}`;");
2105 verifyFormat("var f = `\n"
2106 " aaaaaaaaaaaaaaaaaa: ${\n"
2107 " aaaaa + //\n"
2108 " bbbb}`;",
2109 "var f = `\n"
2110 " aaaaaaaaaaaaaaaaaa: ${ aaaaa + //\n"
2111 " bbbb }`;");
2112 verifyFormat("var f = `\n"
2113 " aaaaaaaaaaaaaaaaaa: ${\n"
2114 " someFunction(\n"
2115 " aaaaa + //\n"
2116 " bbbb)}`;",
2117 "var f = `\n"
2118 " aaaaaaaaaaaaaaaaaa: ${someFunction (\n"
2119 " aaaaa + //\n"
2120 " bbbb)}`;");
2121
2122 // It might be preferable to wrap before "someFunction".
2123 verifyFormat("var f = `\n"
2124 " aaaaaaaaaaaaaaaaaa: ${someFunction({\n"
2125 " aaaa: aaaaa,\n"
2126 " bbbb: bbbbb,\n"
2127 "})}`;",
2128 "var f = `\n"
2129 " aaaaaaaaaaaaaaaaaa: ${someFunction ({\n"
2130 " aaaa: aaaaa,\n"
2131 " bbbb: bbbbb,\n"
2132 " })}`;");
2133 }
2134
TEST_F(FormatTestJS,TemplateStringASI)2135 TEST_F(FormatTestJS, TemplateStringASI) {
2136 verifyFormat("var x = `hello${world}`;", "var x = `hello${\n"
2137 " world\n"
2138 "}`;");
2139 }
2140
TEST_F(FormatTestJS,NestedTemplateStrings)2141 TEST_F(FormatTestJS, NestedTemplateStrings) {
2142 verifyFormat(
2143 "var x = `<ul>${xs.map(x => `<li>${x}</li>`).join('\\n')}</ul>`;");
2144 verifyFormat("var x = `he${({text: 'll'}.text)}o`;");
2145
2146 // Crashed at some point.
2147 verifyFormat("}");
2148 }
2149
TEST_F(FormatTestJS,TaggedTemplateStrings)2150 TEST_F(FormatTestJS, TaggedTemplateStrings) {
2151 verifyFormat("var x = html`<ul>`;");
2152 verifyFormat("yield `hello`;");
2153 verifyFormat("var f = {\n"
2154 " param: longTagName`This is a ${\n"
2155 " 'really'} long line`\n"
2156 "};",
2157 "var f = {param: longTagName`This is a ${'really'} long line`};",
2158 getGoogleJSStyleWithColumns(40));
2159 }
2160
TEST_F(FormatTestJS,CastSyntax)2161 TEST_F(FormatTestJS, CastSyntax) {
2162 verifyFormat("var x = <type>foo;");
2163 verifyFormat("var x = foo as type;");
2164 verifyFormat("let x = (a + b) as\n"
2165 " LongTypeIsLong;",
2166 getGoogleJSStyleWithColumns(20));
2167 verifyFormat("foo = <Bar[]>[\n"
2168 " 1, //\n"
2169 " 2\n"
2170 "];");
2171 verifyFormat("var x = [{x: 1} as type];");
2172 verifyFormat("x = x as [a, b];");
2173 verifyFormat("x = x as {a: string};");
2174 verifyFormat("x = x as (string);");
2175 verifyFormat("x = x! as (string);");
2176 verifyFormat("x = y! in z;");
2177 verifyFormat("var x = something.someFunction() as\n"
2178 " something;",
2179 getGoogleJSStyleWithColumns(40));
2180 }
2181
TEST_F(FormatTestJS,TypeArguments)2182 TEST_F(FormatTestJS, TypeArguments) {
2183 verifyFormat("class X<Y> {}");
2184 verifyFormat("new X<Y>();");
2185 verifyFormat("foo<Y>(a);");
2186 verifyFormat("var x: X<Y>[];");
2187 verifyFormat("class C extends D<E> implements F<G>, H<I> {}");
2188 verifyFormat("function f(a: List<any> = null) {}");
2189 verifyFormat("function f(): List<any> {}");
2190 verifyFormat("function aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa():\n"
2191 " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb {}");
2192 verifyFormat("function aaaaaaaaaa(\n"
2193 " aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaa,\n"
2194 " aaaaaaaaaaaaaaaa: aaaaaaaaaaaaaaaaaaa):\n"
2195 " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa {}");
2196 }
2197
TEST_F(FormatTestJS,UserDefinedTypeGuards)2198 TEST_F(FormatTestJS, UserDefinedTypeGuards) {
2199 verifyFormat(
2200 "function foo(check: Object):\n"
2201 " check is {foo: string, bar: string, baz: string, foobar: string} {\n"
2202 " return 'bar' in check;\n"
2203 "}\n");
2204 }
2205
TEST_F(FormatTestJS,OptionalTypes)2206 TEST_F(FormatTestJS, OptionalTypes) {
2207 verifyFormat("function x(a?: b, c?, d?) {}");
2208 verifyFormat("class X {\n"
2209 " y?: z;\n"
2210 " z?;\n"
2211 "}");
2212 verifyFormat("interface X {\n"
2213 " y?(): z;\n"
2214 "}");
2215 verifyFormat("constructor({aa}: {\n"
2216 " aa?: string,\n"
2217 " aaaaaaaa?: string,\n"
2218 " aaaaaaaaaaaaaaa?: boolean,\n"
2219 " aaaaaa?: List<string>\n"
2220 "}) {}");
2221 }
2222
TEST_F(FormatTestJS,IndexSignature)2223 TEST_F(FormatTestJS, IndexSignature) {
2224 verifyFormat("var x: {[k: string]: v};");
2225 }
2226
TEST_F(FormatTestJS,WrapAfterParen)2227 TEST_F(FormatTestJS, WrapAfterParen) {
2228 verifyFormat("xxxxxxxxxxx(\n"
2229 " aaa, aaa);",
2230 getGoogleJSStyleWithColumns(20));
2231 verifyFormat("xxxxxxxxxxx(\n"
2232 " aaa, aaa, aaa,\n"
2233 " aaa, aaa, aaa);",
2234 getGoogleJSStyleWithColumns(20));
2235 verifyFormat("xxxxxxxxxxx(\n"
2236 " aaaaaaaaaaaaaaaaaaaaaaaa,\n"
2237 " function(x) {\n"
2238 " y(); //\n"
2239 " });",
2240 getGoogleJSStyleWithColumns(40));
2241 verifyFormat("while (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&\n"
2242 " bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) {\n}");
2243 }
2244
TEST_F(FormatTestJS,JSDocAnnotations)2245 TEST_F(FormatTestJS, JSDocAnnotations) {
2246 verifyFormat("/**\n"
2247 " * @exports {this.is.a.long.path.to.a.Type}\n"
2248 " */",
2249 "/**\n"
2250 " * @exports {this.is.a.long.path.to.a.Type}\n"
2251 " */",
2252 getGoogleJSStyleWithColumns(20));
2253 verifyFormat("/**\n"
2254 " * @mods {this.is.a.long.path.to.a.Type}\n"
2255 " */",
2256 "/**\n"
2257 " * @mods {this.is.a.long.path.to.a.Type}\n"
2258 " */",
2259 getGoogleJSStyleWithColumns(20));
2260 verifyFormat("/**\n"
2261 " * @mods {this.is.a.long.path.to.a.Type}\n"
2262 " */",
2263 "/**\n"
2264 " * @mods {this.is.a.long.path.to.a.Type}\n"
2265 " */",
2266 getGoogleJSStyleWithColumns(20));
2267 verifyFormat("/**\n"
2268 " * @param {canWrap\n"
2269 " * onSpace}\n"
2270 " */",
2271 "/**\n"
2272 " * @param {canWrap onSpace}\n"
2273 " */",
2274 getGoogleJSStyleWithColumns(20));
2275 // make sure clang-format doesn't break before *any* '{'
2276 verifyFormat("/**\n"
2277 " * @lala {lala {lalala\n"
2278 " */\n",
2279 "/**\n"
2280 " * @lala {lala {lalala\n"
2281 " */\n",
2282 getGoogleJSStyleWithColumns(20));
2283 // cases where '{' is around the column limit
2284 for (int ColumnLimit = 6; ColumnLimit < 13; ++ColumnLimit) {
2285 verifyFormat("/**\n"
2286 " * @param {type}\n"
2287 " */",
2288 "/**\n"
2289 " * @param {type}\n"
2290 " */",
2291 getGoogleJSStyleWithColumns(ColumnLimit));
2292 }
2293 // don't break before @tags
2294 verifyFormat("/**\n"
2295 " * This\n"
2296 " * tag @param\n"
2297 " * stays.\n"
2298 " */",
2299 "/**\n"
2300 " * This tag @param stays.\n"
2301 " */",
2302 getGoogleJSStyleWithColumns(13));
2303 verifyFormat("/**\n"
2304 " * @see http://very/very/long/url/is/long\n"
2305 " */",
2306 "/**\n"
2307 " * @see http://very/very/long/url/is/long\n"
2308 " */",
2309 getGoogleJSStyleWithColumns(20));
2310 verifyFormat("/**\n"
2311 " * @param This is a\n"
2312 " * long comment\n"
2313 " * but no type\n"
2314 " */",
2315 "/**\n"
2316 " * @param This is a long comment but no type\n"
2317 " */",
2318 getGoogleJSStyleWithColumns(20));
2319 // Break and reindent @param line and reflow unrelated lines.
2320 EXPECT_EQ("{\n"
2321 " /**\n"
2322 " * long long long\n"
2323 " * long\n"
2324 " * @param {this.is.a.long.path.to.a.Type}\n"
2325 " * a\n"
2326 " * long long long\n"
2327 " * long long\n"
2328 " */\n"
2329 " function f(a) {}\n"
2330 "}",
2331 format("{\n"
2332 "/**\n"
2333 " * long long long long\n"
2334 " * @param {this.is.a.long.path.to.a.Type} a\n"
2335 " * long long long long\n"
2336 " * long\n"
2337 " */\n"
2338 " function f(a) {}\n"
2339 "}",
2340 getGoogleJSStyleWithColumns(20)));
2341 }
2342
TEST_F(FormatTestJS,TslintComments)2343 TEST_F(FormatTestJS, TslintComments) {
2344 // tslint uses pragma comments that must be on their own line.
2345 verifyFormat("// Comment that needs wrapping. Comment that needs wrapping. "
2346 "Comment that needs\n"
2347 "// wrapping. Trailing line.\n"
2348 "// tslint:disable-next-line:must-be-on-own-line",
2349 "// Comment that needs wrapping. Comment that needs wrapping. "
2350 "Comment that needs wrapping.\n"
2351 "// Trailing line.\n"
2352 "// tslint:disable-next-line:must-be-on-own-line");
2353 }
2354
TEST_F(FormatTestJS,TscComments)2355 TEST_F(FormatTestJS, TscComments) {
2356 // As above, @ts-ignore and @ts-check comments must be on their own line.
2357 verifyFormat("// Comment that needs wrapping. Comment that needs wrapping. "
2358 "Comment that needs\n"
2359 "// wrapping. Trailing line.\n"
2360 "// @ts-ignore",
2361 "// Comment that needs wrapping. Comment that needs wrapping. "
2362 "Comment that needs wrapping.\n"
2363 "// Trailing line.\n"
2364 "// @ts-ignore");
2365 verifyFormat("// Comment that needs wrapping. Comment that needs wrapping. "
2366 "Comment that needs\n"
2367 "// wrapping. Trailing line.\n"
2368 "// @ts-check",
2369 "// Comment that needs wrapping. Comment that needs wrapping. "
2370 "Comment that needs wrapping.\n"
2371 "// Trailing line.\n"
2372 "// @ts-check");
2373 }
2374
TEST_F(FormatTestJS,RequoteStringsSingle)2375 TEST_F(FormatTestJS, RequoteStringsSingle) {
2376 verifyFormat("var x = 'foo';", "var x = \"foo\";");
2377 verifyFormat("var x = 'fo\\'o\\'';", "var x = \"fo'o'\";");
2378 verifyFormat("var x = 'fo\\'o\\'';", "var x = \"fo\\'o'\";");
2379 verifyFormat("var x =\n"
2380 " 'foo\\'';",
2381 // Code below is 15 chars wide, doesn't fit into the line with
2382 // the \ escape added.
2383 "var x = \"foo'\";", getGoogleJSStyleWithColumns(15));
2384 // Removes no-longer needed \ escape from ".
2385 verifyFormat("var x = 'fo\"o';", "var x = \"fo\\\"o\";");
2386 // Code below fits into 15 chars *after* removing the \ escape.
2387 verifyFormat("var x = 'fo\"o';", "var x = \"fo\\\"o\";",
2388 getGoogleJSStyleWithColumns(15));
2389 verifyFormat("// clang-format off\n"
2390 "let x = \"double\";\n"
2391 "// clang-format on\n"
2392 "let x = 'single';\n",
2393 "// clang-format off\n"
2394 "let x = \"double\";\n"
2395 "// clang-format on\n"
2396 "let x = \"single\";\n");
2397 }
2398
TEST_F(FormatTestJS,RequoteAndIndent)2399 TEST_F(FormatTestJS, RequoteAndIndent) {
2400 verifyFormat("let x = someVeryLongFunctionThatGoesOnAndOn(\n"
2401 " 'double quoted string that needs wrapping');",
2402 "let x = someVeryLongFunctionThatGoesOnAndOn("
2403 "\"double quoted string that needs wrapping\");");
2404
2405 verifyFormat("let x =\n"
2406 " 'foo\\'oo';\n"
2407 "let x =\n"
2408 " 'foo\\'oo';",
2409 "let x=\"foo'oo\";\n"
2410 "let x=\"foo'oo\";",
2411 getGoogleJSStyleWithColumns(15));
2412 }
2413
TEST_F(FormatTestJS,RequoteStringsDouble)2414 TEST_F(FormatTestJS, RequoteStringsDouble) {
2415 FormatStyle DoubleQuotes = getGoogleStyle(FormatStyle::LK_JavaScript);
2416 DoubleQuotes.JavaScriptQuotes = FormatStyle::JSQS_Double;
2417 verifyFormat("var x = \"foo\";", DoubleQuotes);
2418 verifyFormat("var x = \"foo\";", "var x = 'foo';", DoubleQuotes);
2419 verifyFormat("var x = \"fo'o\";", "var x = 'fo\\'o';", DoubleQuotes);
2420 }
2421
TEST_F(FormatTestJS,RequoteStringsLeave)2422 TEST_F(FormatTestJS, RequoteStringsLeave) {
2423 FormatStyle LeaveQuotes = getGoogleStyle(FormatStyle::LK_JavaScript);
2424 LeaveQuotes.JavaScriptQuotes = FormatStyle::JSQS_Leave;
2425 verifyFormat("var x = \"foo\";", LeaveQuotes);
2426 verifyFormat("var x = 'foo';", LeaveQuotes);
2427 }
2428
TEST_F(FormatTestJS,SupportShebangLines)2429 TEST_F(FormatTestJS, SupportShebangLines) {
2430 verifyFormat("#!/usr/bin/env node\n"
2431 "var x = hello();",
2432 "#!/usr/bin/env node\n"
2433 "var x = hello();");
2434 }
2435
TEST_F(FormatTestJS,NonNullAssertionOperator)2436 TEST_F(FormatTestJS, NonNullAssertionOperator) {
2437 verifyFormat("let x = foo!.bar();\n");
2438 verifyFormat("let x = foo ? bar! : baz;\n");
2439 verifyFormat("let x = !foo;\n");
2440 verifyFormat("if (!+a) {\n}");
2441 verifyFormat("let x = foo[0]!;\n");
2442 verifyFormat("let x = (foo)!;\n");
2443 verifyFormat("let x = x(foo!);\n");
2444 verifyFormat("a.aaaaaa(a.a!).then(\n"
2445 " x => x(x));\n",
2446 getGoogleJSStyleWithColumns(20));
2447 verifyFormat("let x = foo! - 1;\n");
2448 verifyFormat("let x = {foo: 1}!;\n");
2449 verifyFormat("let x = hello.foo()!\n"
2450 " .foo()!\n"
2451 " .foo()!\n"
2452 " .foo()!;\n",
2453 getGoogleJSStyleWithColumns(20));
2454 verifyFormat("let x = namespace!;\n");
2455 verifyFormat("return !!x;\n");
2456 }
2457
TEST_F(FormatTestJS,CppKeywords)2458 TEST_F(FormatTestJS, CppKeywords) {
2459 // Make sure we don't mess stuff up because of C++ keywords.
2460 verifyFormat("return operator && (aa);");
2461 // .. or QT ones.
2462 verifyFormat("const slots: Slot[];");
2463 // use the "!" assertion operator to validate that clang-format understands
2464 // these C++ keywords aren't keywords in JS/TS.
2465 verifyFormat("auto!;");
2466 verifyFormat("char!;");
2467 verifyFormat("concept!;");
2468 verifyFormat("double!;");
2469 verifyFormat("extern!;");
2470 verifyFormat("float!;");
2471 verifyFormat("inline!;");
2472 verifyFormat("int!;");
2473 verifyFormat("long!;");
2474 verifyFormat("register!;");
2475 verifyFormat("restrict!;");
2476 verifyFormat("sizeof!;");
2477 verifyFormat("struct!;");
2478 verifyFormat("typedef!;");
2479 verifyFormat("union!;");
2480 verifyFormat("unsigned!;");
2481 verifyFormat("volatile!;");
2482 verifyFormat("_Alignas!;");
2483 verifyFormat("_Alignof!;");
2484 verifyFormat("_Atomic!;");
2485 verifyFormat("_Bool!;");
2486 verifyFormat("_Complex!;");
2487 verifyFormat("_Generic!;");
2488 verifyFormat("_Imaginary!;");
2489 verifyFormat("_Noreturn!;");
2490 verifyFormat("_Static_assert!;");
2491 verifyFormat("_Thread_local!;");
2492 verifyFormat("__func__!;");
2493 verifyFormat("__objc_yes!;");
2494 verifyFormat("__objc_no!;");
2495 verifyFormat("asm!;");
2496 verifyFormat("bool!;");
2497 verifyFormat("const_cast!;");
2498 verifyFormat("dynamic_cast!;");
2499 verifyFormat("explicit!;");
2500 verifyFormat("friend!;");
2501 verifyFormat("mutable!;");
2502 verifyFormat("operator!;");
2503 verifyFormat("reinterpret_cast!;");
2504 verifyFormat("static_cast!;");
2505 verifyFormat("template!;");
2506 verifyFormat("typename!;");
2507 verifyFormat("typeid!;");
2508 verifyFormat("using!;");
2509 verifyFormat("virtual!;");
2510 verifyFormat("wchar_t!;");
2511
2512 // Positive tests:
2513 verifyFormat("x.type!;");
2514 verifyFormat("x.get!;");
2515 verifyFormat("x.set!;");
2516 }
2517
TEST_F(FormatTestJS,NullPropagatingOperator)2518 TEST_F(FormatTestJS, NullPropagatingOperator) {
2519 verifyFormat("let x = foo?.bar?.baz();\n");
2520 verifyFormat("let x = foo?.(foo);\n");
2521 verifyFormat("let x = foo?.['arr'];\n");
2522 }
2523
TEST_F(FormatTestJS,NullishCoalescingOperator)2524 TEST_F(FormatTestJS, NullishCoalescingOperator) {
2525 verifyFormat("const val = something ?? 'some other default';\n");
2526 verifyFormat(
2527 "const val = something ?? otherDefault ??\n"
2528 " evenMore ?? evenMore;\n",
2529 "const val = something ?? otherDefault ?? evenMore ?? evenMore;\n",
2530 getGoogleJSStyleWithColumns(40));
2531 }
2532
TEST_F(FormatTestJS,AssignmentOperators)2533 TEST_F(FormatTestJS, AssignmentOperators) {
2534 verifyFormat("a &&= b;\n");
2535 verifyFormat("a ||= b;\n");
2536 // NB: need to split ? ?= to avoid it being interpreted by C++ as a trigraph
2537 // for #.
2538 verifyFormat("a ?"
2539 "?= b;\n");
2540 }
2541
TEST_F(FormatTestJS,Conditional)2542 TEST_F(FormatTestJS, Conditional) {
2543 verifyFormat("y = x ? 1 : 2;");
2544 verifyFormat("x ? 1 : 2;");
2545 verifyFormat("class Foo {\n"
2546 " field = true ? 1 : 2;\n"
2547 " method(a = true ? 1 : 2) {}\n"
2548 "}");
2549 }
2550
TEST_F(FormatTestJS,ImportComments)2551 TEST_F(FormatTestJS, ImportComments) {
2552 verifyFormat("import {x} from 'x'; // from some location",
2553 getGoogleJSStyleWithColumns(25));
2554 verifyFormat("// taze: x from 'location'", getGoogleJSStyleWithColumns(10));
2555 verifyFormat("/// <reference path=\"some/location\" />",
2556 getGoogleJSStyleWithColumns(10));
2557 }
2558
TEST_F(FormatTestJS,Exponentiation)2559 TEST_F(FormatTestJS, Exponentiation) {
2560 verifyFormat("squared = x ** 2;");
2561 verifyFormat("squared **= 2;");
2562 }
2563
TEST_F(FormatTestJS,NestedLiterals)2564 TEST_F(FormatTestJS, NestedLiterals) {
2565 FormatStyle FourSpaces = getGoogleJSStyleWithColumns(15);
2566 FourSpaces.IndentWidth = 4;
2567 verifyFormat("var l = [\n"
2568 " [\n"
2569 " 1,\n"
2570 " ],\n"
2571 "];",
2572 FourSpaces);
2573 verifyFormat("var l = [\n"
2574 " {\n"
2575 " 1: 1,\n"
2576 " },\n"
2577 "];",
2578 FourSpaces);
2579 verifyFormat("someFunction(\n"
2580 " p1,\n"
2581 " [\n"
2582 " 1,\n"
2583 " ],\n"
2584 ");",
2585 FourSpaces);
2586 verifyFormat("someFunction(\n"
2587 " p1,\n"
2588 " {\n"
2589 " 1: 1,\n"
2590 " },\n"
2591 ");",
2592 FourSpaces);
2593 verifyFormat("var o = {\n"
2594 " 1: 1,\n"
2595 " 2: {\n"
2596 " 3: 3,\n"
2597 " },\n"
2598 "};",
2599 FourSpaces);
2600 verifyFormat("var o = {\n"
2601 " 1: 1,\n"
2602 " 2: [\n"
2603 " 3,\n"
2604 " ],\n"
2605 "};",
2606 FourSpaces);
2607 }
2608
TEST_F(FormatTestJS,BackslashesInComments)2609 TEST_F(FormatTestJS, BackslashesInComments) {
2610 verifyFormat("// hello \\\n"
2611 "if (x) foo();\n",
2612 "// hello \\\n"
2613 " if ( x) \n"
2614 " foo();\n");
2615 verifyFormat("/* ignore \\\n"
2616 " */\n"
2617 "if (x) foo();\n",
2618 "/* ignore \\\n"
2619 " */\n"
2620 " if ( x) foo();\n");
2621 verifyFormat("// st \\ art\\\n"
2622 "// comment"
2623 "// continue \\\n"
2624 "formatMe();\n",
2625 "// st \\ art\\\n"
2626 "// comment"
2627 "// continue \\\n"
2628 "formatMe( );\n");
2629 }
2630
TEST_F(FormatTestJS,AddsLastLinePenaltyIfEndingIsBroken)2631 TEST_F(FormatTestJS, AddsLastLinePenaltyIfEndingIsBroken) {
2632 EXPECT_EQ(
2633 "a = function() {\n"
2634 " b = function() {\n"
2635 " this.aaaaaaaaaaaaaaaaaaa[aaaaaaaaaaa] = aaaa.aaaaaa ?\n"
2636 " aaaa.aaaaaa : /** @type "
2637 "{aaaa.aaaa.aaaaaaaaa.aaaaaaaaaaaaaaaaaaa} */\n"
2638 " (aaaa.aaaa.aaaaaaaaa.aaaaaaaaaaaaa.aaaaaaaaaaaaaaaaa);\n"
2639 " };\n"
2640 "};",
2641 format("a = function() {\n"
2642 " b = function() {\n"
2643 " this.aaaaaaaaaaaaaaaaaaa[aaaaaaaaaaa] = aaaa.aaaaaa ? "
2644 "aaaa.aaaaaa : /** @type "
2645 "{aaaa.aaaa.aaaaaaaaa.aaaaaaaaaaaaaaaaaaa} */\n"
2646 " (aaaa.aaaa.aaaaaaaaa.aaaaaaaaaaaaa.aaaaaaaaaaaaaaaaa);\n"
2647 " };\n"
2648 "};"));
2649 }
2650
TEST_F(FormatTestJS,ParameterNamingComment)2651 TEST_F(FormatTestJS, ParameterNamingComment) {
2652 verifyFormat("callFoo(/*spaceAfterParameterNamingComment=*/ 1);");
2653 }
2654
TEST_F(FormatTestJS,ConditionalTypes)2655 TEST_F(FormatTestJS, ConditionalTypes) {
2656 // Formatting below is not necessarily intentional, this just ensures that
2657 // clang-format does not break the code.
2658 verifyFormat( // wrap
2659 "type UnionToIntersection<U> =\n"
2660 " (U extends any ? (k: U) => void :\n"
2661 " never) extends((k: infer I) => void) ? I : never;");
2662 }
2663
TEST_F(FormatTestJS,SupportPrivateFieldsAndMethods)2664 TEST_F(FormatTestJS, SupportPrivateFieldsAndMethods) {
2665 verifyFormat("class Example {\n"
2666 " pub = 1;\n"
2667 " #priv = 2;\n"
2668 " static pub2 = 'foo';\n"
2669 " static #priv2 = 'bar';\n"
2670 " method() {\n"
2671 " this.#priv = 5;\n"
2672 " }\n"
2673 " static staticMethod() {\n"
2674 " switch (this.#priv) {\n"
2675 " case '1':\n"
2676 " #priv = 3;\n"
2677 " break;\n"
2678 " }\n"
2679 " }\n"
2680 " #privateMethod() {\n"
2681 " this.#privateMethod(); // infinite loop\n"
2682 " }\n"
2683 " static #staticPrivateMethod() {}\n");
2684 }
2685
TEST_F(FormatTestJS,DeclaredFields)2686 TEST_F(FormatTestJS, DeclaredFields) {
2687 verifyFormat("class Example {\n"
2688 " declare pub: string;\n"
2689 " declare private priv: string;\n"
2690 "}\n");
2691 }
2692
TEST_F(FormatTestJS,NoBreakAfterAsserts)2693 TEST_F(FormatTestJS, NoBreakAfterAsserts) {
2694 verifyFormat(
2695 "interface Assertable<State extends {}> {\n"
2696 " assert<ExportedState extends {}, DependencyState extends State = "
2697 "State>(\n"
2698 " callback: Callback<ExportedState, DependencyState>):\n"
2699 " asserts this is ExtendedState<DependencyState&ExportedState>;\n"
2700 "}\n",
2701 "interface Assertable<State extends {}> {\n"
2702 " assert<ExportedState extends {}, DependencyState extends State = "
2703 "State>(callback: Callback<ExportedState, DependencyState>): asserts "
2704 "this is ExtendedState<DependencyState&ExportedState>;\n"
2705 "}\n");
2706 }
2707
TEST_F(FormatTestJS,NumericSeparators)2708 TEST_F(FormatTestJS, NumericSeparators) {
2709 verifyFormat("x = 1_000_000 + 12;", "x = 1_000_000 + 12;");
2710 }
2711
TEST_F(FormatTestJS,AlignConsecutiveDeclarations)2712 TEST_F(FormatTestJS, AlignConsecutiveDeclarations) {
2713 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
2714 Style.AlignConsecutiveDeclarations.Enabled = true;
2715 verifyFormat("let letVariable = 5;\n"
2716 "double constVariable = 10;",
2717 Style);
2718
2719 verifyFormat("let letVariable = 5;\n"
2720 "const constVariable = 10;",
2721 Style);
2722
2723 verifyFormat("let letVariable = 5;\n"
2724 "static const constVariable = 10;",
2725 Style);
2726
2727 verifyFormat("let letVariable = 5;\n"
2728 "static var constVariable = 10;",
2729 Style);
2730
2731 verifyFormat("let letVariable = 5;\n"
2732 "var constVariable = 10;",
2733 Style);
2734
2735 verifyFormat("double letVariable = 5;\n"
2736 "var constVariable = 10;",
2737 Style);
2738
2739 verifyFormat("const letVariable = 5;\n"
2740 "var constVariable = 10;",
2741 Style);
2742
2743 verifyFormat("int letVariable = 5;\n"
2744 "int constVariable = 10;",
2745 Style);
2746 }
2747
TEST_F(FormatTestJS,AlignConsecutiveAssignments)2748 TEST_F(FormatTestJS, AlignConsecutiveAssignments) {
2749 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
2750
2751 Style.AlignConsecutiveAssignments.Enabled = true;
2752 verifyFormat("let letVariable = 5;\n"
2753 "double constVariable = 10;",
2754 Style);
2755
2756 verifyFormat("let letVariable = 5;\n"
2757 "const constVariable = 10;",
2758 Style);
2759
2760 verifyFormat("let letVariable = 5;\n"
2761 "static const constVariable = 10;",
2762 Style);
2763
2764 verifyFormat("let letVariable = 5;\n"
2765 "static var constVariable = 10;",
2766 Style);
2767
2768 verifyFormat("let letVariable = 5;\n"
2769 "var constVariable = 10;",
2770 Style);
2771
2772 verifyFormat("double letVariable = 5;\n"
2773 "var constVariable = 10;",
2774 Style);
2775
2776 verifyFormat("const letVariable = 5;\n"
2777 "var constVariable = 10;",
2778 Style);
2779
2780 verifyFormat("int letVariable = 5;\n"
2781 "int constVariable = 10;",
2782 Style);
2783 }
2784
TEST_F(FormatTestJS,AlignConsecutiveAssignmentsAndDeclarations)2785 TEST_F(FormatTestJS, AlignConsecutiveAssignmentsAndDeclarations) {
2786 FormatStyle Style = getGoogleStyle(FormatStyle::LK_JavaScript);
2787 Style.AlignConsecutiveDeclarations.Enabled = true;
2788 Style.AlignConsecutiveAssignments.Enabled = true;
2789 verifyFormat("let letVariable = 5;\n"
2790 "double constVariable = 10;",
2791 Style);
2792
2793 verifyFormat("let letVariable = 5;\n"
2794 "const constVariable = 10;",
2795 Style);
2796
2797 verifyFormat("let letVariable = 5;\n"
2798 "static const constVariable = 10;",
2799 Style);
2800
2801 verifyFormat("let letVariable = 5;\n"
2802 "static var constVariable = 10;",
2803 Style);
2804
2805 verifyFormat("let letVariable = 5;\n"
2806 "var constVariable = 10;",
2807 Style);
2808
2809 verifyFormat("double letVariable = 5;\n"
2810 "var constVariable = 10;",
2811 Style);
2812
2813 verifyFormat("const letVariable = 5;\n"
2814 "var constVariable = 10;",
2815 Style);
2816
2817 verifyFormat("int letVariable = 5;\n"
2818 "int constVariable = 10;",
2819 Style);
2820 }
2821
2822 } // namespace format
2823 } // end namespace clang
2824