diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md index 3f98ee10..70752e4c 100644 --- a/CHANGELOG.unreleased.md +++ b/CHANGELOG.unreleased.md @@ -42,6 +42,64 @@ Examples: --> +- JavaScript: Respect newlines between parameters ([#5260] by [@evilebottnawi]) + + + ```js + // Input + function foo( + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + + ) {} + + // Output (Prettier stable) + function foo( + one, + two, + three, + four, + five, + six, + seven, + eight, + nine, + ten, + eleven + ) {} + + // Output (Prettier master) + function foo( + one, + + two, + three, + four, + + five, + six, + seven, + eight, + nine, + ten, + + eleven + ) {} + ``` + - JavaScript: Fix multiline dynamic import comments ([#6025] by [@noahsug]) diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js index 76184506..b9c440d7 100644 --- a/src/language-js/printer-estree.js +++ b/src/language-js/printer-estree.js @@ -4104,7 +4104,12 @@ function printFunctionTypeParameters(path, options, print) { function printFunctionParams(path, print, options, expandArg, printTypeParams) { const fun = path.getValue(); + const parent = path.getParentNode(); const paramsField = fun.parameters ? "parameters" : "params"; + const isParametersInTestCall = isTestCall(parent); + const shouldHugParameters = shouldHugArguments(fun); + const shouldExpandParameters = + expandArg && !(fun[paramsField] && fun[paramsField].some(n => n.comments)); const typeParams = printTypeParams ? printFunctionTypeParameters(path, options, print) @@ -4112,7 +4117,32 @@ function printFunctionParams(path, print, options, expandArg, printTypeParams) { let printed = []; if (fun[paramsField]) { - printed = path.map(print, paramsField); + const lastArgIndex = fun[paramsField].length - 1; + + printed = path.map((childPath, index) => { + const parts = []; + const param = childPath.getValue(); + + parts.push(print(childPath)); + + if (index === lastArgIndex) { + if (fun.rest) { + parts.push(",", line); + } + } else if ( + isParametersInTestCall || + shouldHugParameters || + shouldExpandParameters + ) { + parts.push(", "); + } else if (isNextLineEmpty(options.originalText, param, options)) { + parts.push(",", hardline, hardline); + } else { + parts.push(",", line); + } + + return concat(parts); + }, paramsField); } if (fun.rest) { @@ -4150,15 +4180,12 @@ function printFunctionParams(path, print, options, expandArg, printTypeParams) { // } b, // }) ) => { // }) - if ( - expandArg && - !(fun[paramsField] && fun[paramsField].some(n => n.comments)) - ) { + if (shouldExpandParameters) { return group( concat([ removeLines(typeParams), "(", - join(", ", printed.map(removeLines)), + concat(printed.map(removeLines)), ")" ]) ); @@ -4171,15 +4198,13 @@ function printFunctionParams(path, print, options, expandArg, printTypeParams) { // b, // c // }) {} - if (shouldHugArguments(fun)) { - return concat([typeParams, "(", join(", ", printed), ")"]); + if (shouldHugParameters) { + return concat([typeParams, "(", concat(printed), ")"]); } - const parent = path.getParentNode(); - // don't break in specs, eg; `it("should maintain parens around done even when long", (done) => {})` - if (isTestCall(parent)) { - return concat([typeParams, "(", join(", ", printed), ")"]); + if (isParametersInTestCall) { + return concat([typeParams, "(", concat(printed), ")"]); } const isFlowShorthandWithOneArg = @@ -4211,7 +4236,7 @@ function printFunctionParams(path, print, options, expandArg, printTypeParams) { return concat([ typeParams, "(", - indent(concat([softline, join(concat([",", line]), printed)])), + indent(concat([softline, concat(printed)])), ifBreak( canHaveTrailingComma && shouldPrintComma(options, "all") ? "," : "" ), diff --git a/tests/preserve_line/__snapshots__/jsfmt.spec.js.snap b/tests/preserve_line/__snapshots__/jsfmt.spec.js.snap index 85510057..950cc4d7 100644 --- a/tests/preserve_line/__snapshots__/jsfmt.spec.js.snap +++ b/tests/preserve_line/__snapshots__/jsfmt.spec.js.snap @@ -194,6 +194,25 @@ doSomething( ); +function foo( + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + +) {} + =====================================output===================================== longArgNamesWithComments( // Hello World @@ -356,6 +375,23 @@ doSomething( { helloWorld, someImportantStuff } ); +function foo( + one, + + two, + three, + four, + + five, + six, + seven, + eight, + nine, + ten, + + eleven +) {} + ================================================================================ `; @@ -556,3 +592,261 @@ const sel = this.connections ================================================================================ `; + +exports[`parameter-list.js 1`] = ` +====================================options===================================== +parsers: ["flow", "typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +class Foo { + constructor( + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + + ) {} +} + +function foo( + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + +) {} + +call((a, b) => {}); + +call(( + one, + two, + three, + four, + five, + six, + seven, + eight, + nine, + ten, + eleven +) => {}); + +call(( + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + +) => {}); + +function test({ + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + +}) {} + +function test({ + one, + two, + three, + four, +}) {} + +function test({ + one, + + two, + three, + four, + +}) {} + +function test({ one, two, three, four }, $a) {} + + +function test( + { one, two, three, four }, + + $a +) {} + +function foo( + + ...rest + +) {} + +function foo( + one, + + ...rest +) {} + +function foo(one,...rest) {} + +f( + superSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperLong,...args +); + +it( + + "does something really long and complicated so I have to write a very long name for the test", + + function( + + done, + + foo + ) { + + console.log("hello!"); + } +); + +=====================================output===================================== +class Foo { + constructor( + one, + + two, + three, + four, + + five, + six, + seven, + eight, + nine, + ten, + + eleven + ) {} +} + +function foo( + one, + + two, + three, + four, + + five, + six, + seven, + eight, + nine, + ten, + + eleven +) {} + +call((a, b) => {}); + +call((one, two, three, four, five, six, seven, eight, nine, ten, eleven) => {}); + +call((one, two, three, four, five, six, seven, eight, nine, ten, eleven) => {}); + +function test({ + one, + + two, + three, + four, + + five, + six, + seven, + eight, + nine, + ten, + + eleven +}) {} + +function test({ one, two, three, four }) {} + +function test({ + one, + + two, + three, + four +}) {} + +function test({ one, two, three, four }, $a) {} + +function test( + { one, two, three, four }, + + $a +) {} + +function foo(...rest) {} + +function foo( + one, + + ...rest +) {} + +function foo(one, ...rest) {} + +f( + superSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperLong, + ...args +); + +it("does something really long and complicated so I have to write a very long name for the test", function(done, foo) { + console.log("hello!"); +}); + +================================================================================ +`; diff --git a/tests/preserve_line/argument-list.js b/tests/preserve_line/argument-list.js index d2d0194b..16358bc8 100644 --- a/tests/preserve_line/argument-list.js +++ b/tests/preserve_line/argument-list.js @@ -185,3 +185,22 @@ doSomething( ); + +function foo( + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + +) {} diff --git a/tests/preserve_line/parameter-list.js b/tests/preserve_line/parameter-list.js new file mode 100644 index 00000000..ecf8d43c --- /dev/null +++ b/tests/preserve_line/parameter-list.js @@ -0,0 +1,151 @@ +class Foo { + constructor( + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + + ) {} +} + +function foo( + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + +) {} + +call((a, b) => {}); + +call(( + one, + two, + three, + four, + five, + six, + seven, + eight, + nine, + ten, + eleven +) => {}); + +call(( + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + +) => {}); + +function test({ + one, + + two, + three, + four, + + + five, + six, + seven, + eight, + nine, + ten, + + eleven + +}) {} + +function test({ + one, + two, + three, + four, +}) {} + +function test({ + one, + + two, + three, + four, + +}) {} + +function test({ one, two, three, four }, $a) {} + + +function test( + { one, two, three, four }, + + $a +) {} + +function foo( + + ...rest + +) {} + +function foo( + one, + + ...rest +) {} + +function foo(one,...rest) {} + +f( + superSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperSuperLong,...args +); + +it( + + "does something really long and complicated so I have to write a very long name for the test", + + function( + + done, + + foo + ) { + + console.log("hello!"); + } +); diff --git a/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap b/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap index cc974b01..d6f0f540 100644 --- a/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap +++ b/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap @@ -1,5 +1,42 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`argument-list-preserve-line.ts 1`] = ` +====================================options===================================== +parsers: ["typescript"] +printWidth: 80 + | printWidth +=====================================input====================================== +class Foo { + constructor( + @inject(Bar) + private readonly bar: IBar, + + @inject(MyProcessor) + private readonly myProcessor: IMyProcessor, + + @inject(InjectionTypes.AnotherThing) + + private readonly anotherThing: IAnotherThing | undefined, + ) { } +} + +=====================================output===================================== +class Foo { + constructor( + @inject(Bar) + private readonly bar: IBar, + + @inject(MyProcessor) + private readonly myProcessor: IMyProcessor, + + @inject(InjectionTypes.AnotherThing) + private readonly anotherThing: IAnotherThing | undefined + ) {} +} + +================================================================================ +`; + exports[`decorator-type-assertion.ts 1`] = ` ====================================options===================================== parsers: ["typescript"] diff --git a/tests/typescript_decorators/argument-list-preserve-line.ts b/tests/typescript_decorators/argument-list-preserve-line.ts new file mode 100644 index 00000000..f9816d0d --- /dev/null +++ b/tests/typescript_decorators/argument-list-preserve-line.ts @@ -0,0 +1,13 @@ +class Foo { + constructor( + @inject(Bar) + private readonly bar: IBar, + + @inject(MyProcessor) + private readonly myProcessor: IMyProcessor, + + @inject(InjectionTypes.AnotherThing) + + private readonly anotherThing: IAnotherThing | undefined, + ) { } +}