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