brintos

brintos / llvm-project-archived public Read only

0
0
Text · 98.4 KiB · 4847151 Raw
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