diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 64d236bfb3761dbd144b14416bbd4f7bf639c203..f15c9e998e6996064f99ada3dbcbb9cd4cf39543 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -537,6 +537,7 @@ struct AdditionalKeywords { kw_finally = &IdentTable.get("finally"); kw_function = &IdentTable.get("function"); + kw_from = &IdentTable.get("from"); kw_import = &IdentTable.get("import"); kw_is = &IdentTable.get("is"); kw_let = &IdentTable.get("let"); @@ -583,6 +584,7 @@ struct AdditionalKeywords { // JavaScript keywords. IdentifierInfo *kw_finally; IdentifierInfo *kw_function; + IdentifierInfo *kw_from; IdentifierInfo *kw_import; IdentifierInfo *kw_is; IdentifierInfo *kw_let; diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index 69b703d03c1f4ed8ba2f25b255e16099cb908dae..b57faaad8bbdb39d3e1e413dbfcb93c16527d637 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -764,13 +764,30 @@ public: return LT_ImportStatement; } + // import {...} from '...'; + if (Style.Language == FormatStyle::LK_JavaScript && + CurrentToken->is(Keywords.kw_import)) + return LT_ImportStatement; + bool KeywordVirtualFound = false; bool ImportStatement = false; while (CurrentToken) { if (CurrentToken->is(tok::kw_virtual)) KeywordVirtualFound = true; - if (isImportStatement(*CurrentToken)) - ImportStatement = true; + if (Style.Language == FormatStyle::LK_JavaScript) { + // export {...} from '...'; + // An export followed by "from 'some string';" is a re-export from + // another module identified by a URI and is treated as a + // LT_ImportStatement (i.e. prevent wraps on it for long URIs). + // Just "export {...};" or "export class ..." should not be treated as + // an import in this sense. + if (Line.First->is(tok::kw_export) && + CurrentToken->is(Keywords.kw_from) && CurrentToken->Next && + CurrentToken->Next->isStringLiteral()) + ImportStatement = true; + if (isClosureImportStatement(*CurrentToken)) + ImportStatement = true; + } if (!consumeToken()) return LT_Invalid; } @@ -790,11 +807,10 @@ public: } private: - bool isImportStatement(const FormatToken &Tok) { + bool isClosureImportStatement(const FormatToken &Tok) { // FIXME: Closure-library specific stuff should not be hard-coded but be // configurable. - return Style.Language == FormatStyle::LK_JavaScript && - Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) && + return Tok.TokenText == "goog" && Tok.Next && Tok.Next->is(tok::period) && Tok.Next->Next && (Tok.Next->Next->TokenText == "module" || Tok.Next->Next->TokenText == "provide" || Tok.Next->Next->TokenText == "require" || diff --git a/unittests/Format/FormatTestJS.cpp b/unittests/Format/FormatTestJS.cpp index c39667613c0a1ca2610821fd2d0322bb09ae2f8b..73f3afbaf0960238ed00739e0b3bcfe601324e09 100644 --- a/unittests/Format/FormatTestJS.cpp +++ b/unittests/Format/FormatTestJS.cpp @@ -942,21 +942,10 @@ 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 {\n" - " VeryLongImportsAreAnnoying,\n" - " VeryLongImportsAreAnnoying,\n" - " VeryLongImportsAreAnnoying,\n" - " VeryLongImportsAreAnnoying\n" + verifyFormat("import {VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying," + " VeryLongImportsAreAnnoying, VeryLongImportsAreAnnoying" "} from 'some/module.js';"); - verifyFormat("import {\n" - " X,\n" - " Y,\n" - "} from 'some/module.js';"); - verifyFormat("import {\n" - " X,\n" - " Y,\n" - "} from\n 'some/long/module.js';", - getGoogleJSStyleWithColumns(20)); + verifyFormat("import {X, Y,} from 'some/module.js';"); verifyFormat("import {X as myLocalX, Y as myLocalY} from 'some/module.js';"); verifyFormat("import * as lib from 'some/module.js';"); verifyFormat("var x = {import: 1};\nx.import = 2;"); @@ -970,10 +959,19 @@ TEST_F(FormatTestJS, Modules) { verifyFormat("export const x = 12;"); verifyFormat("export default class X {}"); verifyFormat("export {X, Y} from 'some/module.js';"); + verifyFormat("export {X, Y,} from 'some/module.js';"); + verifyFormat("export {SomeVeryLongExport as X, " + "SomeOtherVeryLongExport as Y} from 'some/module.js';"); + // export without 'from' is wrapped. + verifyFormat("export let someRatherLongVariableName =\n" + " someSurprisinglyLongVariable + someOtherRatherLongVar;"); + // ... but not if from is just an identifier. verifyFormat("export {\n" - " X,\n" - " Y,\n" - "} from 'some/module.js';"); + " from as from,\n" + " someSurprisinglyLongVariable\n" + " as from\n" + "};", + getGoogleJSStyleWithColumns(20)); verifyFormat("export class C {\n" " x: number;\n" " y: string;\n"