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