diff --git a/src/comments.ts b/src/comments.ts index 52c19a7e..b6e0adce 100644 --- a/src/comments.ts +++ b/src/comments.ts @@ -79,7 +79,6 @@ export function canAttachComment(node: SyntaxNode, ancestors: SyntaxNode[]) { switch (node.type) { case SyntaxType.EnumBodyDeclarations: case SyntaxType.EscapeSequence: - case SyntaxType.FormalParameters: case SyntaxType.Modifier: case SyntaxType.MultilineStringFragment: case SyntaxType.Program: @@ -113,6 +112,7 @@ export function handleLineComment( ) { return [ handleBinaryExpressionComments, + handleFormalParametersComments, handleFqnOrRefTypeComments, handleIfStatementComments, handleJumpStatementComments, @@ -158,6 +158,19 @@ function handleBinaryExpressionComments( return false; } +function handleFormalParametersComments(commentNode: CommentNode) { + const { enclosingNode, precedingNode, followingNode } = commentNode; + if ( + enclosingNode?.type === SyntaxType.FormalParameters && + !precedingNode && + !followingNode + ) { + util.addDanglingComment(enclosingNode, commentNode, undefined); + return true; + } + return false; +} + function handleFqnOrRefTypeComments(commentNode: CommentNode) { const { enclosingNode, followingNode } = commentNode; if ( @@ -368,7 +381,6 @@ type PrettierIgnoreRange = { function printLeadingComment(path: AstPath) { const comment = path.node; - comment.printed = true; const parts: Doc[] = [printComment(comment)]; const originalText = path.root.value; @@ -410,7 +422,6 @@ function printTrailingComment( previousComment?: { doc: Doc; isBlock: boolean; hasLineSuffix: boolean } ): NonNullable { const comment = path.node; - comment.printed = true; const printed = printComment(comment); const originalText = path.root.value; diff --git a/src/printers/blocks-and-statements.ts b/src/printers/blocks-and-statements.ts index 8566534b..39573b33 100644 --- a/src/printers/blocks-and-statements.ts +++ b/src/printers/blocks-and-statements.ts @@ -68,8 +68,8 @@ export default { } const danglingComments = printDanglingComments(path); - if (danglingComments.length) { - statement.push(hardline, ...danglingComments, hardline); + if (danglingComments) { + statement.push(hardline, danglingComments, hardline); } else { const ifHasBlock = path.node.consequenceNode.type === SyntaxType.Block; statement.push(ifHasBlock ? " " : hardline); @@ -212,10 +212,6 @@ export default { for_statement(path, print) { const danglingComments = printDanglingComments(path); - if (danglingComments.length) { - danglingComments.push(hardline); - } - const hasInit = path.node.initNodes.length > 0; const hasCondition = hasChild(path, "conditionNode"); const hasUpdate = path.node.updateNodes.length > 0; @@ -231,7 +227,7 @@ export default { const hasEmptyStatement = path.node.bodyNode.type === ";"; const parts = [ - ...danglingComments, + danglingComments && [danglingComments, hardline], "for ", hasInit || hasCondition || hasUpdate ? group(indentInParentheses(join(line, expressions))) @@ -247,14 +243,15 @@ export default { }, enhanced_for_statement(path, print) { - const forStatement = printDanglingComments(path); - forStatement.push( + const danglingComments = printDanglingComments(path); + const forStatement = [ + danglingComments && [danglingComments, hardline], "for (", ...printModifiers(path, print), path.call(print, "typeNode"), " ", path.call(print, "nameNode") - ); + ]; if (hasChild(path, "dimensionsNode")) { forStatement.push(path.call(print, "dimensionsNode")); diff --git a/src/printers/classes.ts b/src/printers/classes.ts index 9f75b543..3885a116 100644 --- a/src/printers/classes.ts +++ b/src/printers/classes.ts @@ -9,14 +9,16 @@ import { printBlock, printBlockStatements, printBodyDeclarations, + printDanglingComments, printModifiers, printTypeParameters, printValue, printVariableDeclaration, + type NamedNodePath, type NamedNodePrinters } from "./helpers.ts"; -const { group, hardline, indent, join, line } = builders; +const { group, hardline, indent, join, line, softline } = builders; export default { class_declaration(path, print) { @@ -165,14 +167,16 @@ export default { }, formal_parameters(path, print) { - return indentInParentheses( - join( - [",", line], - (path.parent as NamedNode | null)?.type === SyntaxType.RecordDeclaration - ? printBodyDeclarations(path, print) - : path.map(print, "namedChildren") - ) - ); + const parameters = + (path.parent as NamedNode | null)?.type === SyntaxType.RecordDeclaration + ? printBodyDeclarations(path, print) + : path.map(print, "namedChildren"); + + if (parameters.length === 0) { + return ["(", printDanglingCommentsInList(path), ")"]; + } + + return indentInParentheses(join([",", line], parameters)); }, formal_parameter(path, print) { @@ -440,3 +444,19 @@ const indexByModifier = [ "non-sealed", "strictfp" ].reduce((map, name, index) => map.set(name, index), new Map()); + +function printDanglingCommentsInList(path: NamedNodePath) { + const { node } = path; + + return node.comments?.some(comment => !(comment.leading || comment.trailing)) + ? [ + indent([softline, printDanglingComments(path)]), + node.comments.some( + ({ type, leading, trailing }) => + !(leading || trailing) && type === SyntaxType.LineComment + ) + ? hardline + : softline + ] + : ""; +} diff --git a/src/printers/expressions.ts b/src/printers/expressions.ts index e85c3d4a..8380d7e1 100644 --- a/src/printers/expressions.ts +++ b/src/printers/expressions.ts @@ -763,7 +763,7 @@ function printLambdaExpressionSignature( } const dangling = printDanglingComments(path); - if (dangling.length) { + if (dangling) { parts.push(" ", dangling); } return parts; @@ -980,9 +980,9 @@ function printMemberChain( } const danglingComments = printDanglingComments(path); - if (danglingComments.length) { + if (danglingComments) { printedNodes[0].printed = [ - ...danglingComments, + danglingComments, hardline, printedNodes[0].printed ]; diff --git a/src/printers/helpers.ts b/src/printers/helpers.ts index 62520417..87cfe419 100644 --- a/src/printers/helpers.ts +++ b/src/printers/helpers.ts @@ -95,23 +95,35 @@ export function lineEndWithComments(node: SyntaxNode) { : node.end.row; } -export function printDanglingComments(path: NamedNodePath) { - if (!path.node.comments?.length) { - return []; +export function printDanglingComments( + path: NamedNodePath, + danglingCommentsPrintOptions: { indent?: boolean } = {} +): Doc { + const { indent: shouldIndent = false } = danglingCommentsPrintOptions; + const danglingComments = new Set( + path.node.comments?.filter( + comment => !(comment.leading || comment.trailing) + ) + ); + + if (danglingComments.size === 0) { + return ""; } - const comments: Doc[] = []; - path.each(commentPath => { - const comment = commentPath.node; - if (comment.leading || comment.trailing) { - return; - } - comment.printed = true; - comments.push(printComment(comment)); - }, "comments"); - return join(hardline, comments); + + const parts = path + .map( + ({ node: comment }) => + danglingComments.has(comment) ? printComment(comment) : "", + "comments" + ) + .filter(Boolean); + + const doc = join(hardline, parts); + return shouldIndent ? indent([hardline, doc]) : doc; } export function printComment(comment: CommentNode) { + comment.printed = true; const lines = comment.value.split("\n").map(line => line.trim()); return lines.length > 1 && lines[0].startsWith("/*") && @@ -129,7 +141,7 @@ export function hasLeadingComments(node: SyntaxNode) { } export function indentInParentheses(contents: Doc) { - return !Array.isArray(contents) || contents.length + return (contents && !Array.isArray(contents)) || contents.length ? ["(", indent([softline, contents]), softline, ")"] : "()"; } @@ -142,10 +154,8 @@ export function printArrayInitializer( options: JavaParserOptions ) { if (!path.node.namedChildren.length) { - const danglingComments = printDanglingComments(path); - return danglingComments.length - ? ["{", indent([hardline, ...danglingComments]), hardline, "}"] - : "{}"; + const danglingComments = printDanglingComments(path, { indent: true }); + return danglingComments ? ["{", danglingComments, hardline, "}"] : "{}"; } const list = join([",", line], path.map(print, "namedChildren")); @@ -166,9 +176,9 @@ export function printBlock(path: NamedNodePath, contents: Doc[]) { "}" ]); } - const danglingComments = printDanglingComments(path); - if (danglingComments.length) { - return ["{", indent([hardline, ...danglingComments]), hardline, "}"]; + const danglingComments = printDanglingComments(path, { indent: true }); + if (danglingComments) { + return ["{", danglingComments, hardline, "}"]; } const parent = path.parent; const grandparent = path.grandparent; diff --git a/src/printers/packages-and-modules.ts b/src/printers/packages-and-modules.ts index 91c50fde..76f3c70e 100644 --- a/src/printers/packages-and-modules.ts +++ b/src/printers/packages-and-modules.ts @@ -15,7 +15,7 @@ const { group, hardline, indent, join, line } = builders; export default { program(path, print) { if (!path.node.namedChildren.length) { - return [...printDanglingComments(path), hardline]; + return [printDanglingComments(path), hardline]; } const parts: Doc[] = []; diff --git a/test/unit-test/comments/comments-blocks-and-statements/end-of-block/_output.java b/test/unit-test/comments/comments-blocks-and-statements/end-of-block/_output.java index cbe7f0c4..cdc18c5a 100644 --- a/test/unit-test/comments/comments-blocks-and-statements/end-of-block/_output.java +++ b/test/unit-test/comments/comments-blocks-and-statements/end-of-block/_output.java @@ -48,52 +48,64 @@ class J { void one() {} - void two() // alpha - {} + void two( + // alpha + ) {} - void three() // alpha - // beta - {} + void three( + // alpha + // beta + ) {} - void four() // alpha - // beta - /* gamma */ - {} + void four( + // alpha + // beta + /* gamma */ + ) {} - void five() {} // alpha + void five( + // alpha + ) {} - void fiveBis() { // alpha + void fiveBis( + // alpha + ) { int i; } - void six /* alpha */() {} + void six(/* alpha */) {} - void seven() /* alpha */ - /* beta */ - {} + void seven( + /* alpha */ + /* beta */ + ) {} - void eight() /* alpha */ - // beta - {} + void eight( + /* alpha */ + // beta + ) {} - void nine() /* alpha */ - {} + void nine(/* alpha */) {} void one(String one) {} - void two(String one) // alpha - {} + void two( + String one + // alpha + ) {} - void three(String one) // alpha - // beta - {} + void three( + String one + // alpha + // beta + ) {} void four( // alpha String one - ) // beta - /* gamma */ - {} + // beta + /* gamma */ + ) {} void five( String one // alpha @@ -104,15 +116,17 @@ void six(String one /* alpha */) {} void seven( /* alpha */ String one - ) /* beta */ - {} + /* beta */ + ) {} void eight( /* alpha */ String one - ) // beta - {} + // beta + ) {} - void nine(String one) /* alpha */ - {} + void nine( + String one + /* alpha */ + ) {} } diff --git a/test/unit-test/jsni/_input.java b/test/unit-test/jsni/_input.java new file mode 100644 index 00000000..5f5f62cb --- /dev/null +++ b/test/unit-test/jsni/_input.java @@ -0,0 +1,11 @@ +class JSNI { + private native JsArray getItems() /*-{ + return this.items + }-*/; + + private static native void registerHandler(MyHandler handler) /*-{ + $doc.addEventListener("visibilitychange", function () { + handler.@com.example.MyHandler::onEvent()(); + }); + }-*/; +} diff --git a/test/unit-test/jsni/_output.java b/test/unit-test/jsni/_output.java new file mode 100644 index 00000000..1e496556 --- /dev/null +++ b/test/unit-test/jsni/_output.java @@ -0,0 +1,14 @@ +class JSNI { + + private native JsArray getItems() /*-{ + return this.items + }-*/; + + private static native void registerHandler( + MyHandler handler + ) /*-{ + $doc.addEventListener("visibilitychange", function () { + handler.@com.example.MyHandler::onEvent()(); + }); + }-*/; +} diff --git a/test/unit-test/jsni/jsni.spec.ts b/test/unit-test/jsni/jsni.spec.ts new file mode 100644 index 00000000..7b86c1f9 --- /dev/null +++ b/test/unit-test/jsni/jsni.spec.ts @@ -0,0 +1,9 @@ +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { testSample } from "../../test-utils.ts"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +describe("prettier-java", () => { + testSample(__dirname); +});