Index: lib/Format/ContinuationIndenter.cpp =================================================================== --- lib/Format/ContinuationIndenter.cpp +++ lib/Format/ContinuationIndenter.cpp @@ -701,8 +701,18 @@ State.Stack.back().BreakBeforeParameter = false; if (!DryRun) { + unsigned MaxEmptyLinesToKeep = Style.MaxEmptyLinesToKeep + 1; + if (Style.Language == FormatStyle::LK_JavaScript && + Current.is(tok::r_brace) && Current.MatchingParen && + Current.MatchingParen->Previous && + Current.MatchingParen->Previous->is(TT_JsFatArrow)) { + // JavaScript arrow functions are experssions, thus their r_brace is not + // on its own line, and thus not covered by UnwrappedLineFormatter's logic + // about removing empty lines on closing blocks. Special case it here. + MaxEmptyLinesToKeep = 0; + } unsigned Newlines = std::max( - 1u, std::min(Current.NewlinesBefore, Style.MaxEmptyLinesToKeep + 1)); + 1u, std::min(Current.NewlinesBefore, MaxEmptyLinesToKeep)); bool ContinuePPDirective = State.Line->InPPDirective && State.Line->Type != LT_ImportStatement; Whitespaces.replaceWhitespace(Current, Newlines, State.Column, State.Column, Index: unittests/Format/FormatTestJS.cpp =================================================================== --- unittests/Format/FormatTestJS.cpp +++ unittests/Format/FormatTestJS.cpp @@ -1606,6 +1606,16 @@ Style); } +TEST_F(FormatTestJS, RemoveEmptyLinesTrailingArrowFunctions) { + verifyFormat("x = () => {\n" + " foo();\n" + "};\n", + "x = () => {\n" + " foo();\n" + "\n" + "};\n"); +} + TEST_F(FormatTestJS, Modules) { verifyFormat("import SomeThing from 'some/module.js';"); verifyFormat("import {X, Y} from 'some/module.js';");