diff --git a/packages/prettier-plugin-java/src/comments.ts b/packages/prettier-plugin-java/src/comments.ts index 121ac0f5..a8376ea0 100644 --- a/packages/prettier-plugin-java/src/comments.ts +++ b/packages/prettier-plugin-java/src/comments.ts @@ -94,6 +94,7 @@ export function handleLineComment( ) { return [ handleBinaryExpressionComments, + handleConditionalExpressionComments, handleFqnOrRefTypeComments, handleIfStatementComments, handleJumpStatementComments, @@ -116,11 +117,7 @@ function handleBinaryExpressionComments( options: JavaParserOptions ) { const { enclosingNode, precedingNode, followingNode } = commentNode; - if ( - enclosingNode && - isNonTerminal(enclosingNode) && - enclosingNode.name === "binaryExpression" - ) { + if (enclosingNode?.name === "binaryExpression") { if (isBinaryOperator(followingNode)) { if (options.experimentalOperatorPosition === "start") { util.addLeadingComment(followingNode, commentNode); @@ -139,13 +136,17 @@ function handleBinaryExpressionComments( return false; } -function handleFqnOrRefTypeComments(commentNode: JavaComment) { - const { enclosingNode, followingNode } = commentNode; +function handleConditionalExpressionComments(commentNode: JavaComment) { + const { startLine, endLine, enclosingNode, precedingNode, followingNode } = + commentNode; if ( - enclosingNode && - isNonTerminal(enclosingNode) && - enclosingNode.name === "fqnOrRefType" && - followingNode + enclosingNode?.name === "conditionalExpression" && + precedingNode && + followingNode && + isNonTerminal(precedingNode) && + isNonTerminal(followingNode) && + precedingNode.location.endLine < startLine && + endLine < followingNode.location.startLine ) { util.addLeadingComment(followingNode, commentNode); return true; @@ -153,12 +154,19 @@ function handleFqnOrRefTypeComments(commentNode: JavaComment) { return false; } +function handleFqnOrRefTypeComments(commentNode: JavaComment) { + const { enclosingNode, followingNode } = commentNode; + if (enclosingNode?.name === "fqnOrRefType" && followingNode) { + util.addLeadingComment(followingNode, commentNode); + return true; + } + return false; +} + function handleIfStatementComments(commentNode: JavaComment) { const { enclosingNode, precedingNode } = commentNode; if ( - enclosingNode && - isNonTerminal(enclosingNode) && - enclosingNode.name === "ifStatement" && + enclosingNode?.name === "ifStatement" && precedingNode && isNonTerminal(precedingNode) && precedingNode.name === "statement" @@ -175,7 +183,6 @@ function handleJumpStatementComments(commentNode: JavaComment) { enclosingNode && !precedingNode && !followingNode && - isNonTerminal(enclosingNode) && ["breakStatement", "continueStatement", "returnStatement"].includes( enclosingNode.name ) @@ -189,10 +196,8 @@ function handleJumpStatementComments(commentNode: JavaComment) { function handleLabeledStatementComments(commentNode: JavaComment) { const { enclosingNode, precedingNode } = commentNode; if ( - enclosingNode && + enclosingNode?.name === "labeledStatement" && precedingNode && - isNonTerminal(enclosingNode) && - enclosingNode.name === "labeledStatement" && isTerminal(precedingNode) && precedingNode.tokenType.name === "Identifier" ) { @@ -205,9 +210,7 @@ function handleLabeledStatementComments(commentNode: JavaComment) { function handleMethodDeclaratorComments(commentNode: JavaComment) { const { enclosingNode } = commentNode; if ( - enclosingNode && - isNonTerminal(enclosingNode) && - enclosingNode.name === "methodDeclarator" && + enclosingNode?.name === "methodDeclarator" && !enclosingNode.children.receiverParameter && !enclosingNode.children.formalParameterList && enclosingNode.children.LBrace[0].startOffset < commentNode.startOffset && @@ -224,7 +227,6 @@ function handleNameComments(commentNode: JavaComment) { if ( enclosingNode && precedingNode && - isNonTerminal(enclosingNode) && isTerminal(precedingNode) && precedingNode.tokenType.name === "Identifier" && [ @@ -262,8 +264,8 @@ export type JavaComment = IToken & { trailing: boolean; printed: boolean; enclosingNode?: JavaNonTerminal; - precedingNode?: JavaNonTerminal; - followingNode?: JavaNonTerminal; + precedingNode?: JavaNode; + followingNode?: JavaNode; }; type FormatterOffOnRange = { diff --git a/packages/prettier-plugin-java/src/printers/expressions.ts b/packages/prettier-plugin-java/src/printers/expressions.ts index a2996dec..341f504b 100644 --- a/packages/prettier-plugin-java/src/printers/expressions.ts +++ b/packages/prettier-plugin-java/src/printers/expressions.ts @@ -30,6 +30,7 @@ import { } from "./helpers.js"; const { + align, breakParent, conditionalGroup, group, @@ -114,23 +115,28 @@ export default { conciseLambdaParameter: printSingle, lambdaBody: printSingle, - conditionalExpression(path, print) { + conditionalExpression(path, print, options) { const binaryExpression = call(path, print, "binaryExpression"); if (!path.node.children.QuestionMark) { return binaryExpression; } - const expressions = map(path, print, "expression"); - const contents = indent( - join(line, [ - binaryExpression, - ["? ", expressions[0]], - [": ", expressions[1]] - ]) - ); + const [consequent, alternate] = map(path, print, "expression"); + const parts = [binaryExpression]; + const part = [ + line, + ["? ", options.useTabs ? indent(consequent) : align(2, consequent)], + line, + [": ", options.useTabs ? indent(alternate) : align(2, alternate)] + ]; const isNestedTernary = (path.getNode(4) as JavaNonTerminal | null)?.name === "conditionalExpression"; - return isNestedTernary ? contents : group(contents); + parts.push( + !isNestedTernary || options.useTabs + ? part + : align(Math.max(0, options.tabWidth - 2), part) + ); + return isNestedTernary ? parts : group(indent(parts)); }, binaryExpression(path, print, options) { diff --git a/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-end/_input.java b/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-end/_input.java index 0e586cc0..b7574560 100644 --- a/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-end/_input.java +++ b/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-end/_input.java @@ -17,25 +17,6 @@ public String binaryOperationThatShouldNotBreak() { return "This operation should" + "not break"; } - public int ternaryOperationThatShouldBreak() { - int shortInteger = thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne : thisIsAShortInteger; - return thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne : thisIsAShortInteger; - } - - public int ternaryOperationThatShouldBreak2() { - int shortInteger = thisIsAVeryLongInteger ? thisIsAnotherVeryLongOne : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; - return thisIsAVeryLongInteger ? thisIsAnotherVeryLongOne : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; - } - - public int ternaryOperationThatShouldNotBreak() { - int a = b ? b : c; - return b ? b : c; - } - - void nestedTernary() { - aaaaaaaaaa ? bbbbbbbbbb : cccccccccc ? dddddddddd : eeeeeeeeee ? ffffffffff : gggggggggg; - } - public boolean binaryOperationWithComments() { boolean a = one || two >> 1 // one // two diff --git a/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-end/_output.java b/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-end/_output.java index c4ecb0d9..698d345e 100644 --- a/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-end/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-end/_output.java @@ -26,39 +26,6 @@ public String binaryOperationThatShouldNotBreak() { return "This operation should" + "not break"; } - public int ternaryOperationThatShouldBreak() { - int shortInteger = thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne - ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne - : thisIsAShortInteger; - return thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne - ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne - : thisIsAShortInteger; - } - - public int ternaryOperationThatShouldBreak2() { - int shortInteger = thisIsAVeryLongInteger - ? thisIsAnotherVeryLongOne - : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; - return thisIsAVeryLongInteger - ? thisIsAnotherVeryLongOne - : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; - } - - public int ternaryOperationThatShouldNotBreak() { - int a = b ? b : c; - return b ? b : c; - } - - void nestedTernary() { - aaaaaaaaaa - ? bbbbbbbbbb - : cccccccccc - ? dddddddddd - : eeeeeeeeee - ? ffffffffff - : gggggggggg; - } - public boolean binaryOperationWithComments() { boolean a = one || diff --git a/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-start/_input.java b/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-start/_input.java index 0e586cc0..b7574560 100644 --- a/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-start/_input.java +++ b/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-start/_input.java @@ -17,25 +17,6 @@ public String binaryOperationThatShouldNotBreak() { return "This operation should" + "not break"; } - public int ternaryOperationThatShouldBreak() { - int shortInteger = thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne : thisIsAShortInteger; - return thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne : thisIsAShortInteger; - } - - public int ternaryOperationThatShouldBreak2() { - int shortInteger = thisIsAVeryLongInteger ? thisIsAnotherVeryLongOne : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; - return thisIsAVeryLongInteger ? thisIsAnotherVeryLongOne : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; - } - - public int ternaryOperationThatShouldNotBreak() { - int a = b ? b : c; - return b ? b : c; - } - - void nestedTernary() { - aaaaaaaaaa ? bbbbbbbbbb : cccccccccc ? dddddddddd : eeeeeeeeee ? ffffffffff : gggggggggg; - } - public boolean binaryOperationWithComments() { boolean a = one || two >> 1 // one // two diff --git a/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-start/_output.java b/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-start/_output.java index 71932298..7af43c22 100644 --- a/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-start/_output.java +++ b/packages/prettier-plugin-java/test/unit-test/binary_expressions/operator-position-start/_output.java @@ -26,39 +26,6 @@ public String binaryOperationThatShouldNotBreak() { return "This operation should" + "not break"; } - public int ternaryOperationThatShouldBreak() { - int shortInteger = thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne - ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne - : thisIsAShortInteger; - return thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne - ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne - : thisIsAShortInteger; - } - - public int ternaryOperationThatShouldBreak2() { - int shortInteger = thisIsAVeryLongInteger - ? thisIsAnotherVeryLongOne - : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; - return thisIsAVeryLongInteger - ? thisIsAnotherVeryLongOne - : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; - } - - public int ternaryOperationThatShouldNotBreak() { - int a = b ? b : c; - return b ? b : c; - } - - void nestedTernary() { - aaaaaaaaaa - ? bbbbbbbbbb - : cccccccccc - ? dddddddddd - : eeeeeeeeee - ? ffffffffff - : gggggggggg; - } - public boolean binaryOperationWithComments() { boolean a = one diff --git a/packages/prettier-plugin-java/test/unit-test/conditional-expression/conditional-expression.spec.ts b/packages/prettier-plugin-java/test/unit-test/conditional-expression/conditional-expression.spec.ts new file mode 100644 index 00000000..44da9952 --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/conditional-expression/conditional-expression.spec.ts @@ -0,0 +1,10 @@ +import path from "path"; +import url from "url"; +import { testSample } from "../../test-utils.js"; + +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); + +describe("prettier-java", () => { + testSample(path.resolve(__dirname, "spaces")); + testSample(path.resolve(__dirname, "tabs")); +}); diff --git a/packages/prettier-plugin-java/test/unit-test/conditional-expression/spaces/.prettierrc.json b/packages/prettier-plugin-java/test/unit-test/conditional-expression/spaces/.prettierrc.json new file mode 100644 index 00000000..0a02bcef --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/conditional-expression/spaces/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "tabWidth": 4 +} diff --git a/packages/prettier-plugin-java/test/unit-test/conditional-expression/spaces/_input.java b/packages/prettier-plugin-java/test/unit-test/conditional-expression/spaces/_input.java new file mode 100644 index 00000000..cb46abda --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/conditional-expression/spaces/_input.java @@ -0,0 +1,41 @@ +class ConditionalExpression { + + int ternaryOperationThatShouldBreak() { + int shortInteger = thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne : thisIsAShortInteger; + return thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne : thisIsAShortInteger; + } + + int ternaryOperationThatShouldBreak2() { + int shortInteger = thisIsAVeryLongInteger ? thisIsAnotherVeryLongOne : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; + return thisIsAVeryLongInteger ? thisIsAnotherVeryLongOne : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; + } + + int ternaryOperationThatShouldNotBreak() { + int a = b ? b : c; + return b ? b : c; + } + + void nestedTernary() { + aaaaaaaaaa ? bbbbbbbbbb : cccccccccc ? dddddddddd : eeeeeeeeee ? ffffffffff : gggggggggg; + } + + void ternaryWithComments() { + a + ? // b + b + : // c + c; + a + // b + ? b + // c + : c; + a ? // b + b + : // c + c; + a + ? b // b + : c; // c + } +} diff --git a/packages/prettier-plugin-java/test/unit-test/conditional-expression/spaces/_output.java b/packages/prettier-plugin-java/test/unit-test/conditional-expression/spaces/_output.java new file mode 100644 index 00000000..237586b7 --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/conditional-expression/spaces/_output.java @@ -0,0 +1,56 @@ +class ConditionalExpression { + + int ternaryOperationThatShouldBreak() { + int shortInteger = + thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne + ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne + : thisIsAShortInteger; + return thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne + ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne + : thisIsAShortInteger; + } + + int ternaryOperationThatShouldBreak2() { + int shortInteger = thisIsAVeryLongInteger + ? thisIsAnotherVeryLongOne + : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; + return thisIsAVeryLongInteger + ? thisIsAnotherVeryLongOne + : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; + } + + int ternaryOperationThatShouldNotBreak() { + int a = b ? b : c; + return b ? b : c; + } + + void nestedTernary() { + aaaaaaaaaa + ? bbbbbbbbbb + : cccccccccc + ? dddddddddd + : eeeeeeeeee + ? ffffffffff + : gggggggggg; + } + + void ternaryWithComments() { + a + ? // b + b + : // c + c; + a + ? // b + b + : // c + c; + a // b + ? b + : // c + c; + a + ? b // b + : c; // c + } +} diff --git a/packages/prettier-plugin-java/test/unit-test/conditional-expression/tabs/.prettierrc.json b/packages/prettier-plugin-java/test/unit-test/conditional-expression/tabs/.prettierrc.json new file mode 100644 index 00000000..c9590876 --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/conditional-expression/tabs/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "useTabs": true +} diff --git a/packages/prettier-plugin-java/test/unit-test/conditional-expression/tabs/_input.java b/packages/prettier-plugin-java/test/unit-test/conditional-expression/tabs/_input.java new file mode 100644 index 00000000..7bab26b2 --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/conditional-expression/tabs/_input.java @@ -0,0 +1,41 @@ +class ConditionalExpression { + + int ternaryOperationThatShouldBreak() { + int shortInteger = thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne : thisIsAShortInteger; + return thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne : thisIsAShortInteger; + } + + int ternaryOperationThatShouldBreak2() { + int shortInteger = thisIsAVeryLongInteger ? thisIsAnotherVeryLongOne : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; + return thisIsAVeryLongInteger ? thisIsAnotherVeryLongOne : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; + } + + int ternaryOperationThatShouldNotBreak() { + int a = b ? b : c; + return b ? b : c; + } + + void nestedTernary() { + aaaaaaaaaa ? bbbbbbbbbb : cccccccccc ? dddddddddd : eeeeeeeeee ? ffffffffff : gggggggggg; + } + + void ternaryWithComments() { + a + ? // b + b + : // c + c; + a + // b + ? b + // c + : c; + a ? // b + b + : // c + c; + a + ? b // b + : c; // c + } +} diff --git a/packages/prettier-plugin-java/test/unit-test/conditional-expression/tabs/_output.java b/packages/prettier-plugin-java/test/unit-test/conditional-expression/tabs/_output.java new file mode 100644 index 00000000..147b9578 --- /dev/null +++ b/packages/prettier-plugin-java/test/unit-test/conditional-expression/tabs/_output.java @@ -0,0 +1,55 @@ +class ConditionalExpression { + + int ternaryOperationThatShouldBreak() { + int shortInteger = thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne + ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne + : thisIsAShortInteger; + return thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne + ? thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne + : thisIsAShortInteger; + } + + int ternaryOperationThatShouldBreak2() { + int shortInteger = thisIsAVeryLongInteger + ? thisIsAnotherVeryLongOne + : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; + return thisIsAVeryLongInteger + ? thisIsAnotherVeryLongOne + : thisIsAnotherVeryLongIntegerThatIsEvenLongerThanFirstOne; + } + + int ternaryOperationThatShouldNotBreak() { + int a = b ? b : c; + return b ? b : c; + } + + void nestedTernary() { + aaaaaaaaaa + ? bbbbbbbbbb + : cccccccccc + ? dddddddddd + : eeeeeeeeee + ? ffffffffff + : gggggggggg; + } + + void ternaryWithComments() { + a + ? // b + b + : // c + c; + a + ? // b + b + : // c + c; + a // b + ? b + : // c + c; + a + ? b // b + : c; // c + } +}