]> granicus.if.org Git - clang/commitdiff
clang-format: [JS] Introduce JavaScriptWrapImports option.
authorMartin Probst <martin@probst.io>
Mon, 13 Jun 2016 16:39:50 +0000 (16:39 +0000)
committerMartin Probst <martin@probst.io>
Mon, 13 Jun 2016 16:39:50 +0000 (16:39 +0000)
Summary:
When turned on, clang-format wraps JavaScript imports (and importing exports),
instead of forcing the entire import statement onto one line.

Reviewers: djasper

Subscribers: klimek, cfe-commits

Differential Revision: http://reviews.llvm.org/D21273

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@272558 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Format/Format.h
lib/Format/Format.cpp
lib/Format/TokenAnnotator.cpp
lib/Format/UnwrappedLineFormatter.cpp
unittests/Format/FormatTestJS.cpp
unittests/Format/SortImportsTestJS.cpp

index 3600c416b99bae586770e20dd45252351fb6cb10..3f42dbfa25bc18061ca6e858bca95b4e268b70ce 100644 (file)
@@ -431,6 +431,23 @@ struct FormatStyle {
   /// type.
   bool IndentWrappedFunctionNames;
 
+  /// \brief Quotation styles for JavaScript strings. Does not affect template
+  /// strings.
+  enum JavaScriptQuoteStyle {
+    /// Leave string quotes as they are.
+    JSQS_Leave,
+    /// Always use single quotes.
+    JSQS_Single,
+    /// Always use double quotes.
+    JSQS_Double
+  };
+
+  /// \brief The JavaScriptQuoteStyle to use for JavaScript strings.
+  JavaScriptQuoteStyle JavaScriptQuotes;
+
+  /// \brief Whether to wrap JavaScript import/export statements.
+  bool JavaScriptWrapImports;
+
   /// \brief If true, empty lines at the start of blocks are kept.
   bool KeepEmptyLinesAtTheStartOfBlocks;
 
@@ -613,20 +630,6 @@ struct FormatStyle {
   /// \brief The way to use tab characters in the resulting file.
   UseTabStyle UseTab;
 
-  /// \brief Quotation styles for JavaScript strings. Does not affect template
-  /// strings.
-  enum JavaScriptQuoteStyle {
-    /// Leave string quotes as they are.
-    JSQS_Leave,
-    /// Always use single quotes.
-    JSQS_Single,
-    /// Always use double quotes.
-    JSQS_Double
-  };
-
-  /// \brief The JavaScriptQuoteStyle to use for JavaScript strings.
-  JavaScriptQuoteStyle JavaScriptQuotes;
-
   bool operator==(const FormatStyle &R) const {
     return AccessModifierOffset == R.AccessModifierOffset &&
            AlignAfterOpenBracket == R.AlignAfterOpenBracket &&
@@ -675,6 +678,8 @@ struct FormatStyle {
            IndentCaseLabels == R.IndentCaseLabels &&
            IndentWidth == R.IndentWidth && Language == R.Language &&
            IndentWrappedFunctionNames == R.IndentWrappedFunctionNames &&
+           JavaScriptQuotes == R.JavaScriptQuotes &&
+           JavaScriptWrapImports == R.JavaScriptWrapImports &&
            KeepEmptyLinesAtTheStartOfBlocks ==
                R.KeepEmptyLinesAtTheStartOfBlocks &&
            MacroBlockBegin == R.MacroBlockBegin &&
@@ -703,8 +708,7 @@ struct FormatStyle {
            SpacesInParentheses == R.SpacesInParentheses &&
            SpacesInSquareBrackets == R.SpacesInSquareBrackets &&
            Standard == R.Standard && TabWidth == R.TabWidth &&
-           UseTab == R.UseTab &&
-           JavaScriptQuotes == R.JavaScriptQuotes;
+           UseTab == R.UseTab;
   }
 };
 
index c7a7bfe2106b4d4753c0c4d6fae3132c5b4a505e..fc93d18ce12643442a40a5c629283f9e788a23fd 100644 (file)
@@ -314,6 +314,8 @@ template <> struct MappingTraits<FormatStyle> {
     IO.mapOptional("IndentWidth", Style.IndentWidth);
     IO.mapOptional("IndentWrappedFunctionNames",
                    Style.IndentWrappedFunctionNames);
+    IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
+    IO.mapOptional("JavaScriptWrapImports", Style.JavaScriptWrapImports);
     IO.mapOptional("KeepEmptyLinesAtTheStartOfBlocks",
                    Style.KeepEmptyLinesAtTheStartOfBlocks);
     IO.mapOptional("MacroBlockBegin", Style.MacroBlockBegin);
@@ -353,7 +355,6 @@ template <> struct MappingTraits<FormatStyle> {
     IO.mapOptional("Standard", Style.Standard);
     IO.mapOptional("TabWidth", Style.TabWidth);
     IO.mapOptional("UseTab", Style.UseTab);
-    IO.mapOptional("JavaScriptQuotes", Style.JavaScriptQuotes);
   }
 };
 
@@ -613,6 +614,7 @@ FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) {
     GoogleStyle.MaxEmptyLinesToKeep = 3;
     GoogleStyle.SpacesInContainerLiterals = false;
     GoogleStyle.JavaScriptQuotes = FormatStyle::JSQS_Single;
+    GoogleStyle.JavaScriptWrapImports = false;
   } else if (Language == FormatStyle::LK_Proto) {
     GoogleStyle.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_None;
     GoogleStyle.SpacesInContainerLiterals = false;
index d3a973b591b996a37500ab1d3ed77a4ce98a6edc..cd8f28b081bfeb816014f2fc07a0ab476012a31a 100644 (file)
@@ -785,13 +785,14 @@ public:
         return LT_ImportStatement;
     }
 
+    bool KeywordVirtualFound = false;
+    bool ImportStatement = false;
+
     // import {...} from '...';
     if (Style.Language == FormatStyle::LK_JavaScript &&
         CurrentToken->is(Keywords.kw_import))
-      return LT_ImportStatement;
+      ImportStatement = true;
 
-    bool KeywordVirtualFound = false;
-    bool ImportStatement = false;
     while (CurrentToken) {
       if (CurrentToken->is(tok::kw_virtual))
         KeywordVirtualFound = true;
index d75eaf54a0848fad397757b9b866971dae8b91b9..35035ea8afba15c7c80662e73ee145989d6e7b1a 100644 (file)
@@ -847,7 +847,9 @@ UnwrappedLineFormatter::format(const SmallVectorImpl<AnnotatedLine *> &Lines,
       unsigned ColumnLimit = getColumnLimit(TheLine.InPPDirective, NextLine);
       bool FitsIntoOneLine =
           TheLine.Last->TotalLength + Indent <= ColumnLimit ||
-          TheLine.Type == LT_ImportStatement;
+          (TheLine.Type == LT_ImportStatement &&
+           (Style.Language != FormatStyle::LK_JavaScript ||
+            !Style.JavaScriptWrapImports));
 
       if (Style.ColumnLimit == 0)
         NoColumnLimitLineFormatter(Indenter, Whitespaces, Style, this)
index ffcc34d971f63be53744e9a3798c66469bc6cb39..36c3dd08cbae4bf2dce6e21539bbb3590aa7a8b7 100644 (file)
@@ -1007,9 +1007,6 @@ TEST_F(FormatTestJS, Modules) {
   verifyFormat("import SomeThing from 'some/module.js';");
   verifyFormat("import {X, Y} from 'some/module.js';");
   verifyFormat("import a, {X, Y} from 'some/module.js';");
-  verifyFormat("import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,"
-               " VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying"
-               "} from 'some/module.js';");
   verifyFormat("import {X, Y,} from 'some/module.js';");
   verifyFormat("import {X as myLocalX, Y as myLocalY} from 'some/module.js';");
   // Ensure Automatic Semicolon Insertion does not break on "as\n".
@@ -1078,6 +1075,30 @@ TEST_F(FormatTestJS, Modules) {
                "}");
 }
 
+TEST_F(FormatTestJS, ImportWrapping) {
+  verifyFormat("import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying,"
+               " VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying"
+               "} from 'some/module.js';");
+  FormatStyle Style = getGoogleJSStyleWithColumns(80);
+  Style.JavaScriptWrapImports = true;
+  verifyFormat("import {\n"
+               "  VeryLongImportsAreAnnoying,\n"
+               "  VeryLongImportsAreAnnoying,\n"
+               "  VeryLongImportsAreAnnoying,\n"
+               "} from 'some/module.js';",
+               Style);
+  verifyFormat("import {\n"
+               "  A,\n"
+               "  A,\n"
+               "} from 'some/module.js';",
+               Style);
+  verifyFormat("export {\n"
+               "  A,\n"
+               "  A,\n"
+               "} from 'some/module.js';",
+               Style);
+}
+
 TEST_F(FormatTestJS, TemplateStrings) {
   // Keeps any whitespace/indentation within the template string.
   verifyFormat("var x = `hello\n"
index 17e73b085546b88ab2c2fda6f893b08758e988c6..cc408ca9da79e2f65a32cdf49e6125f47d2920ee 100644 (file)
@@ -92,12 +92,12 @@ TEST_F(SortImportsTestJS, SeparateMainCodeBody) {
 TEST_F(SortImportsTestJS, Comments) {
   verifySort("/** @fileoverview This is a great file. */\n"
              "// A very important import follows.\n"
-             "import {sym} from 'a'; /* more comments */\n"
-             "import {sym} from 'b'; // from //foo:bar\n",
+             "import {sym} from 'a';  /* more comments */\n"
+             "import {sym} from 'b';  // from //foo:bar\n",
              "/** @fileoverview This is a great file. */\n"
-             "import {sym} from 'b'; // from //foo:bar\n"
+             "import {sym} from 'b';  // from //foo:bar\n"
              "// A very important import follows.\n"
-             "import {sym} from 'a'; /* more comments */\n");
+             "import {sym} from 'a';  /* more comments */\n");
 }
 
 TEST_F(SortImportsTestJS, SortStar) {