From a269bc8765797d9618a754267aec74984095d43d Mon Sep 17 00:00:00 2001 From: Daniel Jasper Date: Tue, 22 Mar 2016 14:32:20 +0000 Subject: [PATCH] clang-format: [JS] do not wrap ES6 imports/exports. "import ... from '...';" and "export ... from '...';" should be treated the same as goog.require/provide/module/forwardDeclare calls. Patch by Martin Probst. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@264055 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Format/FormatToken.h | 2 ++ lib/Format/TokenAnnotator.cpp | 26 ++++++++++++++++++++----- unittests/Format/FormatTestJS.cpp | 32 +++++++++++++++---------------- 3 files changed, 38 insertions(+), 22 deletions(-) diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 64d236bfb3..f15c9e998e 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 69b703d03c..b57faaad8b 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 c39667613c..73f3afbaf0 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" -- 2.40.0