diff --git a/include/clang/Format/Format.h b/include/clang/Format/Format.h index 3600c416b99bae586770e20dd45252351fb6cb10..3f42dbfa25bc18061ca6e858bca95b4e268b70ce 100644 --- a/include/clang/Format/Format.h +++ b/include/clang/Format/Format.h @@ -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; } }; diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index c7a7bfe2106b4d4753c0c4d6fae3132c5b4a505e..fc93d18ce12643442a40a5c629283f9e788a23fd 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -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; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index d3a973b591b996a37500ab1d3ed77a4ce98a6edc..cd8f28b081bfeb816014f2fc07a0ab476012a31a 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -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; diff --git a/lib/Format/UnwrappedLineFormatter.cpp b/lib/Format/UnwrappedLineFormatter.cpp index d75eaf54a0848fad397757b9b866971dae8b91b9..35035ea8afba15c7c80662e73ee145989d6e7b1a 100644 --- a/lib/Format/UnwrappedLineFormatter.cpp +++ b/lib/Format/UnwrappedLineFormatter.cpp @@ -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) diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index ffcc34d971f63be53744e9a3798c66469bc6cb39..36c3dd08cbae4bf2dce6e21539bbb3590aa7a8b7 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -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" diff --git a/unittests/Format/SortImportsTestJS.cpp b/unittests/Format/SortImportsTestJS.cpp index 17e73b085546b88ab2c2fda6f893b08758e988c6..cc408ca9da79e2f65a32cdf49e6125f47d2920ee 100644 --- a/unittests/Format/SortImportsTestJS.cpp +++ b/unittests/Format/SortImportsTestJS.cpp @@ -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) {