From 593c4d7783c7d05f3d80cdc30a79edb8c0be4da1 Mon Sep 17 00:00:00 2001 From: landaiqing Date: Fri, 12 Sep 2025 23:01:19 +0800 Subject: [PATCH] :sparkles: Added java prettier plugin --- frontend/package-lock.json | 89 +++ frontend/package.json | 1 + .../utils/prettier/plugins/java/comments.d.ts | 17 + .../utils/prettier/plugins/java/comments.js | 199 ++++++ .../utils/prettier/plugins/java/index.d.ts | 563 +++++++++++++++++ .../src/utils/prettier/plugins/java/index.js | 29 + .../utils/prettier/plugins/java/options.d.ts | 43 ++ .../utils/prettier/plugins/java/options.js | 284 +++++++++ .../utils/prettier/plugins/java/parser.d.ts | 9 + .../src/utils/prettier/plugins/java/parser.js | 24 + .../utils/prettier/plugins/java/printer.d.ts | 18 + .../utils/prettier/plugins/java/printer.js | 40 ++ .../plugins/java/printers/arrays.d.ts | 9 + .../prettier/plugins/java/printers/arrays.js | 9 + .../java/printers/blocks-and-statements.d.ts | 117 ++++ .../java/printers/blocks-and-statements.js | 337 ++++++++++ .../plugins/java/printers/classes.d.ts | 157 +++++ .../prettier/plugins/java/printers/classes.js | 446 +++++++++++++ .../plugins/java/printers/expressions.d.ts | 134 ++++ .../plugins/java/printers/expressions.js | 598 ++++++++++++++++++ .../plugins/java/printers/helpers.d.ts | 71 +++ .../prettier/plugins/java/printers/helpers.js | 239 +++++++ .../prettier/plugins/java/printers/index.d.ts | 2 + .../prettier/plugins/java/printers/index.js | 13 + .../plugins/java/printers/interfaces.d.ts | 62 ++ .../plugins/java/printers/interfaces.js | 157 +++++ .../java/printers/lexical-structure.d.ts | 14 + .../java/printers/lexical-structure.js | 29 + .../prettier/plugins/java/printers/names.d.ts | 12 + .../prettier/plugins/java/printers/names.js | 11 + .../java/printers/packages-and-modules.d.ts | 46 ++ .../java/printers/packages-and-modules.js | 169 +++++ .../printers/types-values-and-variables.d.ts | 46 ++ .../printers/types-values-and-variables.js | 90 +++ .../codeblock/lang-parser/languages.ts | 6 +- 35 files changed, 4089 insertions(+), 1 deletion(-) create mode 100644 frontend/src/utils/prettier/plugins/java/comments.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/comments.js create mode 100644 frontend/src/utils/prettier/plugins/java/index.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/index.js create mode 100644 frontend/src/utils/prettier/plugins/java/options.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/options.js create mode 100644 frontend/src/utils/prettier/plugins/java/parser.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/parser.js create mode 100644 frontend/src/utils/prettier/plugins/java/printer.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printer.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/arrays.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/arrays.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/blocks-and-statements.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/blocks-and-statements.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/classes.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/classes.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/expressions.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/expressions.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/helpers.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/helpers.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/index.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/index.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/interfaces.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/interfaces.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/lexical-structure.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/lexical-structure.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/names.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/names.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/packages-and-modules.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/packages-and-modules.js create mode 100644 frontend/src/utils/prettier/plugins/java/printers/types-values-and-variables.d.ts create mode 100644 frontend/src/utils/prettier/plugins/java/printers/types-values-and-variables.js diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5bda2ea..0f4f2cf 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -45,6 +45,7 @@ "colors-named-hex": "^1.0.2", "franc-min": "^6.2.0", "hsl-matcher": "^1.2.4", + "java-parser": "^3.0.1", "jsox": "^1.2.123", "lezer": "^0.13.5", "linguist-languages": "^9.0.0", @@ -126,6 +127,45 @@ "node": ">=6.9.0" } }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.0.3", + "resolved": "https://registry.npmmirror.com/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.0.3.tgz", + "integrity": "sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/gast": "11.0.3", + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/gast": { + "version": "11.0.3", + "resolved": "https://registry.npmmirror.com/@chevrotain/gast/-/gast-11.0.3.tgz", + "integrity": "sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/types": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.0.3", + "resolved": "https://registry.npmmirror.com/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.0.3.tgz", + "integrity": "sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/types": { + "version": "11.0.3", + "resolved": "https://registry.npmmirror.com/@chevrotain/types/-/types-11.0.3.tgz", + "integrity": "sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==", + "license": "Apache-2.0" + }, + "node_modules/@chevrotain/utils": { + "version": "11.0.3", + "resolved": "https://registry.npmmirror.com/@chevrotain/utils/-/utils-11.0.3.tgz", + "integrity": "sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==", + "license": "Apache-2.0" + }, "node_modules/@codemirror/autocomplete": { "version": "6.18.7", "resolved": "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.18.7.tgz", @@ -3225,6 +3265,32 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chevrotain": { + "version": "11.0.3", + "resolved": "https://registry.npmmirror.com/chevrotain/-/chevrotain-11.0.3.tgz", + "integrity": "sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==", + "license": "Apache-2.0", + "dependencies": { + "@chevrotain/cst-dts-gen": "11.0.3", + "@chevrotain/gast": "11.0.3", + "@chevrotain/regexp-to-ast": "11.0.3", + "@chevrotain/types": "11.0.3", + "@chevrotain/utils": "11.0.3", + "lodash-es": "4.17.21" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmmirror.com/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "license": "MIT", + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, "node_modules/chokidar": { "version": "4.0.3", "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz", @@ -4744,6 +4810,17 @@ "node": ">=10" } }, + "node_modules/java-parser": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/java-parser/-/java-parser-3.0.1.tgz", + "integrity": "sha512-sDIR7u9b7O2JViNUxiZRhnRz7URII/eE7g2B+BmGxDeS6Ex3OYAcCyz5oh0H4LQ+hL/BS8OJTz8apMy9xtGmrQ==", + "license": "Apache-2.0", + "dependencies": { + "chevrotain": "11.0.3", + "chevrotain-allstar": "0.3.1", + "lodash": "4.17.21" + } + }, "node_modules/jiti": { "version": "2.4.2", "resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.4.2.tgz", @@ -4915,6 +4992,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index f782c0e..2196178 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -49,6 +49,7 @@ "colors-named-hex": "^1.0.2", "franc-min": "^6.2.0", "hsl-matcher": "^1.2.4", + "java-parser": "^3.0.1", "jsox": "^1.2.123", "lezer": "^0.13.5", "linguist-languages": "^9.0.0", diff --git a/frontend/src/utils/prettier/plugins/java/comments.d.ts b/frontend/src/utils/prettier/plugins/java/comments.d.ts new file mode 100644 index 0000000..844c4ea --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/comments.d.ts @@ -0,0 +1,17 @@ +import type { IToken } from "java-parser"; +import { type AstPath } from "prettier"; +import { type JavaNode, type JavaNonTerminal, type JavaParserOptions } from "./printers/helpers.js"; +export declare function determineFormatterOffOnRanges(cst: JavaNonTerminal): void; +export declare function isFullyBetweenFormatterOffOn(path: AstPath): boolean; +export declare function canAttachComment(node: JavaNode): boolean; +export declare function handleLineComment(commentNode: JavaComment, _: string, options: JavaParserOptions): boolean; +export declare function handleRemainingComment(commentNode: JavaComment): boolean; +export type JavaComment = IToken & { + value: string; + leading: boolean; + trailing: boolean; + printed: boolean; + enclosingNode?: JavaNonTerminal; + precedingNode?: JavaNonTerminal; + followingNode?: JavaNonTerminal; +}; diff --git a/frontend/src/utils/prettier/plugins/java/comments.js b/frontend/src/utils/prettier/plugins/java/comments.js new file mode 100644 index 0000000..0e15efe --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/comments.js @@ -0,0 +1,199 @@ +import { util } from "prettier"; +import parser from "./parser.js"; +import { isEmptyStatement, isNonTerminal, isTerminal } from "./printers/helpers.js"; +const formatterOffOnRangesByCst = new WeakMap(); +export function determineFormatterOffOnRanges(cst) { + const { comments } = cst; + if (!comments) { + return; + } + const ranges = comments + .filter(({ image }) => /^(\/\/\s*@formatter:(off|on)\s*|\/\*\s*@formatter:(off|on)\s*\*\/)$/.test(image)) + .reduce((ranges, { image, startOffset }) => { + const previous = ranges.at(-1); + if (image.endsWith("off")) { + if ((previous === null || previous === void 0 ? void 0 : previous.on) !== Infinity) { + ranges.push({ off: startOffset, on: Infinity }); + } + } + else if ((previous === null || previous === void 0 ? void 0 : previous.on) === Infinity) { + previous.on = startOffset; + } + return ranges; + }, new Array()); + formatterOffOnRangesByCst.set(cst, ranges); +} +export function isFullyBetweenFormatterOffOn(path) { + var _a; + const { node, root } = path; + const start = parser.locStart(node); + const end = parser.locEnd(node); + return (((_a = formatterOffOnRangesByCst + .get(root)) === null || _a === void 0 ? void 0 : _a.some(range => range.off < start && end < range.on)) === true); +} +export function canAttachComment(node) { + var _a, _b, _c; + if (isTerminal(node)) { + const { name, CATEGORIES } = node.tokenType; + return (name === "Identifier" || + (CATEGORIES === null || CATEGORIES === void 0 ? void 0 : CATEGORIES.find(({ name }) => name === "BinaryOperator")) !== undefined); + } + const { children, name } = node; + switch (name) { + case "argumentList": + case "blockStatements": + case "emptyStatement": + case "enumBodyDeclarations": + return false; + case "annotationInterfaceMemberDeclaration": + case "classMemberDeclaration": + case "interfaceMemberDeclaration": + case "methodBody": + return !children.Semicolon; + case "blockStatement": + return !children.statement || !isEmptyStatement(children.statement[0]); + case "classBodyDeclaration": + return !((_a = children.classMemberDeclaration) === null || _a === void 0 ? void 0 : _a[0].children.Semicolon); + case "recordBodyDeclaration": + return !((_c = (_b = children.classBodyDeclaration) === null || _b === void 0 ? void 0 : _b[0].children.classMemberDeclaration) === null || _c === void 0 ? void 0 : _c[0].children.Semicolon); + case "statement": + return !isEmptyStatement(node); + case "statementWithoutTrailingSubstatement": + return !children.emptyStatement; + default: + return true; + } +} +export function handleLineComment(commentNode, _, options) { + return [ + handleBinaryExpressionComments, + handleFqnOrRefTypeComments, + handleIfStatementComments, + handleJumpStatementComments, + handleLabeledStatementComments, + handleNameComments + ].some(fn => fn(commentNode, options)); +} +export function handleRemainingComment(commentNode) { + return [ + handleFqnOrRefTypeComments, + handleMethodDeclaratorComments, + handleNameComments, + handleJumpStatementComments + ].some(fn => fn(commentNode)); +} +function handleBinaryExpressionComments(commentNode, options) { + const { enclosingNode, precedingNode, followingNode } = commentNode; + if (enclosingNode && + isNonTerminal(enclosingNode) && + enclosingNode.name === "binaryExpression") { + if (isBinaryOperator(followingNode)) { + if (options.experimentalOperatorPosition === "start") { + util.addLeadingComment(followingNode, commentNode); + } + else { + util.addTrailingComment(followingNode, commentNode); + } + return true; + } + else if (options.experimentalOperatorPosition === "start" && + isBinaryOperator(precedingNode)) { + util.addLeadingComment(precedingNode, commentNode); + return true; + } + } + return false; +} +function handleFqnOrRefTypeComments(commentNode) { + const { enclosingNode, followingNode } = commentNode; + if (enclosingNode && + isNonTerminal(enclosingNode) && + enclosingNode.name === "fqnOrRefType" && + followingNode) { + util.addLeadingComment(followingNode, commentNode); + return true; + } + return false; +} +function handleIfStatementComments(commentNode) { + const { enclosingNode, precedingNode } = commentNode; + if (enclosingNode && + isNonTerminal(enclosingNode) && + enclosingNode.name === "ifStatement" && + precedingNode && + isNonTerminal(precedingNode) && + precedingNode.name === "statement") { + util.addDanglingComment(enclosingNode, commentNode, undefined); + return true; + } + return false; +} +function handleJumpStatementComments(commentNode) { + const { enclosingNode, precedingNode, followingNode } = commentNode; + if (enclosingNode && + !precedingNode && + !followingNode && + isNonTerminal(enclosingNode) && + ["breakStatement", "continueStatement", "returnStatement"].includes(enclosingNode.name)) { + util.addTrailingComment(enclosingNode, commentNode); + return true; + } + return false; +} +function handleLabeledStatementComments(commentNode) { + const { enclosingNode, precedingNode } = commentNode; + if (enclosingNode && + precedingNode && + isNonTerminal(enclosingNode) && + enclosingNode.name === "labeledStatement" && + isTerminal(precedingNode) && + precedingNode.tokenType.name === "Identifier") { + util.addLeadingComment(precedingNode, commentNode); + return true; + } + return false; +} +function handleMethodDeclaratorComments(commentNode) { + const { enclosingNode } = commentNode; + if (enclosingNode && + isNonTerminal(enclosingNode) && + enclosingNode.name === "methodDeclarator" && + !enclosingNode.children.receiverParameter && + !enclosingNode.children.formalParameterList && + enclosingNode.children.LBrace[0].startOffset < commentNode.startOffset && + commentNode.startOffset < enclosingNode.children.RBrace[0].startOffset) { + util.addDanglingComment(enclosingNode, commentNode, undefined); + return true; + } + return false; +} +function handleNameComments(commentNode) { + const { enclosingNode, precedingNode } = commentNode; + if (enclosingNode && + precedingNode && + isNonTerminal(enclosingNode) && + isTerminal(precedingNode) && + precedingNode.tokenType.name === "Identifier" && + [ + "ambiguousName", + "classOrInterfaceTypeToInstantiate", + "expressionName", + "moduleDeclaration", + "moduleName", + "packageDeclaration", + "packageName", + "packageOrTypeName", + "typeName" + ].includes(enclosingNode.name)) { + util.addTrailingComment(precedingNode, commentNode); + return true; + } + return false; +} +function isBinaryOperator(node) { + var _a; + return (node !== undefined && + (isNonTerminal(node) + ? node.name === "shiftOperator" + : (_a = node.tokenType.CATEGORIES) === null || _a === void 0 ? void 0 : _a.some(({ name }) => name === "BinaryOperator"))); +} diff --git a/frontend/src/utils/prettier/plugins/java/index.d.ts b/frontend/src/utils/prettier/plugins/java/index.d.ts new file mode 100644 index 0000000..1ae54b6 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/index.d.ts @@ -0,0 +1,563 @@ +import type { JavaNode } from "./printers/helpers.js"; +declare const _default: { + languages: { + name: string; + parsers: "java"[]; + group: string; + tmScope: string; + aceMode: string; + codemirrorMode: string; + codemirrorMimeType: string; + extensions: string[]; + linguistLanguageId: number; + vscodeLanguageIds: string[]; + }[]; + parsers: { + java: { + parse(text: string, options: import("./printers/helpers.js").JavaParserOptions): import("./printers/helpers.js").JavaNonTerminal; + astFormat: string; + hasPragma(text: string): boolean; + locStart(node: JavaNode): number; + locEnd(node: JavaNode): number; + }; + }; + printers: { + java: { + print(path: import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath | import("prettier").AstPath, options: import("prettier").ParserOptions, print: (path: import("prettier").AstPath) => import("prettier").Doc, args: unknown): import("prettier/doc.js").builders.Doc; + hasPrettierIgnore(path: import("prettier").AstPath): boolean; + canAttachComment: typeof import("./comments.js").canAttachComment; + isBlockComment(node: JavaNode): boolean; + printComment(commentPath: import("prettier").AstPath): string | import("prettier/doc.js").builders.Doc[]; + getCommentChildNodes(node: JavaNode): any[]; + handleComments: { + ownLine: typeof import("./comments.js").handleLineComment; + endOfLine: typeof import("./comments.js").handleLineComment; + remaining: typeof import("./comments.js").handleRemainingComment; + }; + }; + }; + options: { + entrypoint: { + type: "choice"; + category: string; + default: string; + choices: { + value: string; + description: string; + }[]; + description: string; + }; + arrowParens: { + type: "choice"; + category: string; + default: string; + choices: { + value: string; + description: string; + }[]; + description: string; + }; + trailingComma: { + type: "choice"; + category: string; + default: string; + choices: { + value: string; + description: string; + }[]; + description: string; + }; + experimentalOperatorPosition: { + type: "choice"; + category: string; + default: string; + choices: { + value: string; + description: string; + }[]; + description: string; + }; + }; + defaultOptions: { + arrowParens: "avoid"; + }; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/index.js b/frontend/src/utils/prettier/plugins/java/index.js new file mode 100644 index 0000000..b83a443 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/index.js @@ -0,0 +1,29 @@ +import options from "./options.js"; +import parser from "./parser.js"; +import printer from "./printer.js"; +export default { + languages: [ + { + name: "Java", + parsers: ["java"], + group: "Java", + tmScope: "source.java", + aceMode: "java", + codemirrorMode: "clike", + codemirrorMimeType: "text/x-java", + extensions: [".java"], + linguistLanguageId: 181, + vscodeLanguageIds: ["java"] + } + ], + parsers: { + java: parser + }, + printers: { + java: printer + }, + options, + defaultOptions: { + arrowParens: "avoid" + } +}; diff --git a/frontend/src/utils/prettier/plugins/java/options.d.ts b/frontend/src/utils/prettier/plugins/java/options.d.ts new file mode 100644 index 0000000..c67b27f --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/options.d.ts @@ -0,0 +1,43 @@ +declare const _default: { + entrypoint: { + type: "choice"; + category: string; + default: string; + choices: { + value: string; + description: string; + }[]; + description: string; + }; + arrowParens: { + type: "choice"; + category: string; + default: string; + choices: { + value: string; + description: string; + }[]; + description: string; + }; + trailingComma: { + type: "choice"; + category: string; + default: string; + choices: { + value: string; + description: string; + }[]; + description: string; + }; + experimentalOperatorPosition: { + type: "choice"; + category: string; + default: string; + choices: { + value: string; + description: string; + }[]; + description: string; + }; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/options.js b/frontend/src/utils/prettier/plugins/java/options.js new file mode 100644 index 0000000..2651cb7 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/options.js @@ -0,0 +1,284 @@ +export default { + entrypoint: { + type: "choice", + category: "Global", + default: "compilationUnit", + // sed -nr 's/.*\.RULE\(([^,]+),.*/\1/p' $(ls path/to/java-parser/rules/folder/*) + choices: [ + { value: "arrayInitializer", description: "" }, + { value: "variableInitializerList", description: "" }, + { value: "block", description: "" }, + { value: "blockStatements", description: "" }, + { value: "blockStatement", description: "" }, + { value: "localVariableDeclarationStatement", description: "" }, + { value: "localVariableDeclaration", description: "" }, + { value: "localVariableType", description: "" }, + { value: "statement", description: "" }, + { value: "statementWithoutTrailingSubstatement", description: "" }, + { value: "emptyStatement", description: "" }, + { value: "labeledStatement", description: "" }, + { value: "expressionStatement", description: "" }, + { value: "statementExpression", description: "" }, + { value: "ifStatement", description: "" }, + { value: "assertStatement", description: "" }, + { value: "switchStatement", description: "" }, + { value: "switchBlock", description: "" }, + { value: "switchBlockStatementGroup", description: "" }, + { value: "switchLabel", description: "" }, + { value: "switchRule", description: "" }, + { value: "caseConstant", description: "" }, + { value: "casePattern", description: "" }, + { value: "whileStatement", description: "" }, + { value: "doStatement", description: "" }, + { value: "forStatement", description: "" }, + { value: "basicForStatement", description: "" }, + { value: "forInit", description: "" }, + { value: "forUpdate", description: "" }, + { value: "statementExpressionList", description: "" }, + { value: "enhancedForStatement", description: "" }, + { value: "breakStatement", description: "" }, + { value: "continueStatement", description: "" }, + { value: "returnStatement", description: "" }, + { value: "throwStatement", description: "" }, + { value: "synchronizedStatement", description: "" }, + { value: "tryStatement", description: "" }, + { value: "catches", description: "" }, + { value: "catchClause", description: "" }, + { value: "catchFormalParameter", description: "" }, + { value: "catchType", description: "" }, + { value: "finally", description: "" }, + { value: "tryWithResourcesStatement", description: "" }, + { value: "resourceSpecification", description: "" }, + { value: "resourceList", description: "" }, + { value: "resource", description: "" }, + { value: "yieldStatement", description: "" }, + { value: "variableAccess", description: "" }, + { value: "classDeclaration", description: "" }, + { value: "normalClassDeclaration", description: "" }, + { value: "classModifier", description: "" }, + { value: "typeParameters", description: "" }, + { value: "typeParameterList", description: "" }, + { value: "classExtends", description: "" }, + { value: "classImplements", description: "" }, + { value: "interfaceTypeList", description: "" }, + { value: "classPermits", description: "" }, + { value: "classBody", description: "" }, + { value: "classBodyDeclaration", description: "" }, + { value: "classMemberDeclaration", description: "" }, + { value: "fieldDeclaration", description: "" }, + { value: "fieldModifier", description: "" }, + { value: "variableDeclaratorList", description: "" }, + { value: "variableDeclarator", description: "" }, + { value: "variableDeclaratorId", description: "" }, + { value: "variableInitializer", description: "" }, + { value: "unannType", description: "" }, + { value: "unannPrimitiveTypeWithOptionalDimsSuffix", description: "" }, + { value: "unannPrimitiveType", description: "" }, + { value: "unannReferenceType", description: "" }, + { value: "unannClassOrInterfaceType", description: "" }, + { value: "unannClassType", description: "" }, + { value: "unannInterfaceType", description: "" }, + { value: "unannTypeVariable", description: "" }, + { value: "methodDeclaration", description: "" }, + { value: "methodModifier", description: "" }, + { value: "methodHeader", description: "" }, + { value: "result", description: "" }, + { value: "methodDeclarator", description: "" }, + { value: "receiverParameter", description: "" }, + { value: "formalParameterList", description: "" }, + { value: "formalParameter", description: "" }, + { value: "variableParaRegularParameter", description: "" }, + { value: "variableArityParameter", description: "" }, + { value: "variableModifier", description: "" }, + { value: "throws", description: "" }, + { value: "exceptionTypeList", description: "" }, + { value: "exceptionType", description: "" }, + { value: "methodBody", description: "" }, + { value: "instanceInitializer", description: "" }, + { value: "staticInitializer", description: "" }, + { value: "constructorDeclaration", description: "" }, + { value: "constructorModifier", description: "" }, + { value: "constructorDeclarator", description: "" }, + { value: "simpleTypeName", description: "" }, + { value: "constructorBody", description: "" }, + { value: "explicitConstructorInvocation", description: "" }, + { value: "unqualifiedExplicitConstructorInvocation", description: "" }, + { value: "qualifiedExplicitConstructorInvocation", description: "" }, + { value: "enumDeclaration", description: "" }, + { value: "enumBody", description: "" }, + { value: "enumConstantList", description: "" }, + { value: "enumConstant", description: "" }, + { value: "enumConstantModifier", description: "" }, + { value: "enumBodyDeclarations", description: "" }, + { value: "recordDeclaration", description: "" }, + { value: "recordHeader", description: "" }, + { value: "recordComponentList", description: "" }, + { value: "recordComponent", description: "" }, + { value: "variableArityRecordComponent", description: "" }, + { value: "recordComponentModifier", description: "" }, + { value: "recordBody", description: "" }, + { value: "recordBodyDeclaration", description: "" }, + { value: "compactConstructorDeclaration", description: "" }, + { value: "isDims", description: "" }, + { value: "expression", description: "" }, + { value: "lambdaExpression", description: "" }, + { value: "lambdaParameters", description: "" }, + { value: "lambdaParametersWithBraces", description: "" }, + { value: "lambdaParameterList", description: "" }, + { value: "conciseLambdaParameterList", description: "" }, + { value: "normalLambdaParameterList", description: "" }, + { value: "normalLambdaParameter", description: "" }, + { value: "regularLambdaParameter", description: "" }, + { value: "lambdaParameterType", description: "" }, + { value: "conciseLambdaParameter", description: "" }, + { value: "lambdaBody", description: "" }, + { value: "conditionalExpression", description: "" }, + { value: "binaryExpression", description: "" }, + { value: "unaryExpression", description: "" }, + { value: "unaryExpressionNotPlusMinus", description: "" }, + { value: "primary", description: "" }, + { value: "primaryPrefix", description: "" }, + { value: "primarySuffix", description: "" }, + { value: "fqnOrRefType", description: "" }, + { value: "fqnOrRefTypePartRest", description: "" }, + { value: "fqnOrRefTypePartCommon", description: "" }, + { value: "fqnOrRefTypePartFirst", description: "" }, + { value: "parenthesisExpression", description: "" }, + { value: "castExpression", description: "" }, + { value: "primitiveCastExpression", description: "" }, + { value: "referenceTypeCastExpression", description: "" }, + { value: "newExpression", description: "" }, + { value: "unqualifiedClassInstanceCreationExpression", description: "" }, + { value: "classOrInterfaceTypeToInstantiate", description: "" }, + { value: "typeArgumentsOrDiamond", description: "" }, + { value: "diamond", description: "" }, + { value: "methodInvocationSuffix", description: "" }, + { value: "argumentList", description: "" }, + { value: "arrayCreationExpression", description: "" }, + { + value: "arrayCreationExpressionWithoutInitializerSuffix", + description: "" + }, + { value: "arrayCreationWithInitializerSuffix", description: "" }, + { value: "dimExprs", description: "" }, + { value: "dimExpr", description: "" }, + { value: "classLiteralSuffix", description: "" }, + { value: "arrayAccessSuffix", description: "" }, + { value: "methodReferenceSuffix", description: "" }, + { value: "templateArgument", description: "" }, + { value: "template", description: "" }, + { value: "stringTemplate", description: "" }, + { value: "textBlockTemplate", description: "" }, + { value: "embeddedExpression", description: "" }, + { value: "pattern", description: "" }, + { value: "typePattern", description: "" }, + { value: "recordPattern", description: "" }, + { value: "componentPatternList", description: "" }, + { value: "componentPattern", description: "" }, + { value: "matchAllPattern", description: "" }, + { value: "guard", description: "" }, + { value: "isRefTypeInMethodRef", description: "" }, + { value: "interfaceDeclaration", description: "" }, + { value: "normalInterfaceDeclaration", description: "" }, + { value: "interfaceModifier", description: "" }, + { value: "interfaceExtends", description: "" }, + { value: "interfacePermits", description: "" }, + { value: "interfaceBody", description: "" }, + { value: "interfaceMemberDeclaration", description: "" }, + { value: "constantDeclaration", description: "" }, + { value: "constantModifier", description: "" }, + { value: "interfaceMethodDeclaration", description: "" }, + { value: "interfaceMethodModifier", description: "" }, + { value: "annotationInterfaceDeclaration", description: "" }, + { value: "annotationInterfaceBody", description: "" }, + { value: "annotationInterfaceMemberDeclaration", description: "" }, + { value: "annotationInterfaceElementDeclaration", description: "" }, + { value: "annotationInterfaceElementModifier", description: "" }, + { value: "defaultValue", description: "" }, + { value: "annotation", description: "" }, + { value: "elementValuePairList", description: "" }, + { value: "elementValuePair", description: "" }, + { value: "elementValue", description: "" }, + { value: "elementValueArrayInitializer", description: "" }, + { value: "elementValueList", description: "" }, + { value: "literal", description: "" }, + { value: "integerLiteral", description: "" }, + { value: "floatingPointLiteral", description: "" }, + { value: "booleanLiteral", description: "" }, + { value: "shiftOperator", description: "" }, + { value: "moduleName", description: "" }, + { value: "packageName", description: "" }, + { value: "typeName", description: "" }, + { value: "expressionName", description: "" }, + { value: "methodName", description: "" }, + { value: "packageOrTypeName", description: "" }, + { value: "ambiguousName", description: "" }, + { value: "compilationUnit", description: "" }, + { value: "ordinaryCompilationUnit", description: "" }, + { value: "modularCompilationUnit", description: "" }, + { value: "packageDeclaration", description: "" }, + { value: "packageModifier", description: "" }, + { value: "importDeclaration", description: "" }, + { value: "typeDeclaration", description: "" }, + { value: "moduleDeclaration", description: "" }, + { value: "moduleDirective", description: "" }, + { value: "requiresModuleDirective", description: "" }, + { value: "exportsModuleDirective", description: "" }, + { value: "opensModuleDirective", description: "" }, + { value: "usesModuleDirective", description: "" }, + { value: "providesModuleDirective", description: "" }, + { value: "requiresModifier", description: "" }, + { value: "primitiveType", description: "" }, + { value: "numericType", description: "" }, + { value: "integralType", description: "" }, + { value: "floatingPointType", description: "" }, + { value: "referenceType", description: "" }, + { value: "classOrInterfaceType", description: "" }, + { value: "classType", description: "" }, + { value: "interfaceType", description: "" }, + { value: "typeVariable", description: "" }, + { value: "dims", description: "" }, + { value: "typeParameter", description: "" }, + { value: "typeParameterModifier", description: "" }, + { value: "typeBound", description: "" }, + { value: "additionalBound", description: "" }, + { value: "typeArguments", description: "" }, + { value: "typeArgumentList", description: "" }, + { value: "typeArgument", description: "" }, + { value: "wildcard", description: "" }, + { value: "wildcardBounds", description: "" } + ], + description: "Prettify from the entrypoint, allowing to use prettier on snippet." + }, + arrowParens: { + type: "choice", + category: "Java", + default: "always", + choices: [ + { value: "always", description: "" }, + { value: "avoid", description: "" } + ], + description: "Include parentheses around a sole arrow function parameter." + }, + trailingComma: { + type: "choice", + category: "Java", + default: "all", + choices: [ + { value: "all", description: "" }, + { value: "es5", description: "" }, + { value: "none", description: "" } + ], + description: "Print trailing commas wherever possible when multi-line." + }, + experimentalOperatorPosition: { + type: "choice", + category: "Java", + default: "end", + choices: [ + { value: "start", description: "" }, + { value: "end", description: "" } + ], + description: "Where to print operators when binary expressions wrap lines." + } +}; diff --git a/frontend/src/utils/prettier/plugins/java/parser.d.ts b/frontend/src/utils/prettier/plugins/java/parser.d.ts new file mode 100644 index 0000000..4ed8b4d --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/parser.d.ts @@ -0,0 +1,9 @@ +import { type JavaNode, type JavaNonTerminal, type JavaParserOptions } from "./printers/helpers.js"; +declare const _default: { + parse(text: string, options: JavaParserOptions): JavaNonTerminal; + astFormat: string; + hasPragma(text: string): boolean; + locStart(node: JavaNode): number; + locEnd(node: JavaNode): number; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/parser.js b/frontend/src/utils/prettier/plugins/java/parser.js new file mode 100644 index 0000000..f5befcf --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/parser.js @@ -0,0 +1,24 @@ +import { parse } from "java-parser"; +import { determineFormatterOffOnRanges } from "./comments.js"; +import { isTerminal } from "./printers/helpers.js"; +export default { + parse(text, options) { + var _a; + const cst = parse(text, options.entrypoint); + (_a = cst.comments) === null || _a === void 0 ? void 0 : _a.forEach(comment => { + comment.value = comment.image; + }); + determineFormatterOffOnRanges(cst); + return cst; + }, + astFormat: "java", + hasPragma(text) { + return /^\/\*\*\n\s+\*\s@(format|prettier)\n\s+\*\//.test(text); + }, + locStart(node) { + return isTerminal(node) ? node.startOffset : node.location.startOffset; + }, + locEnd(node) { + return (isTerminal(node) ? node.endOffset : node.location.endOffset) + 1; + } +}; diff --git a/frontend/src/utils/prettier/plugins/java/printer.d.ts b/frontend/src/utils/prettier/plugins/java/printer.d.ts new file mode 100644 index 0000000..565fc6e --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printer.d.ts @@ -0,0 +1,18 @@ +import type { AstPath } from "prettier"; +import { canAttachComment, handleLineComment, handleRemainingComment } from "./comments.js"; +import { type JavaNode } from "./printers/helpers.js"; +declare const _default: { + print(path: DistributedAstPath, options: import("prettier").ParserOptions, print: (path: AstPath) => import("prettier").Doc, args: unknown): import("prettier/doc.js").builders.Doc; + hasPrettierIgnore(path: AstPath): boolean; + canAttachComment: typeof canAttachComment; + isBlockComment(node: JavaNode): boolean; + printComment(commentPath: AstPath): string | import("prettier/doc.js").builders.Doc[]; + getCommentChildNodes(node: JavaNode): any[]; + handleComments: { + ownLine: typeof handleLineComment; + endOfLine: typeof handleLineComment; + remaining: typeof handleRemainingComment; + }; +}; +export default _default; +type DistributedAstPath = T extends any ? AstPath : never; diff --git a/frontend/src/utils/prettier/plugins/java/printer.js b/frontend/src/utils/prettier/plugins/java/printer.js new file mode 100644 index 0000000..88b0164 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printer.js @@ -0,0 +1,40 @@ +import { canAttachComment, handleLineComment, handleRemainingComment, isFullyBetweenFormatterOffOn } from "./comments.js"; +import { isNonTerminal, isTerminal, printComment } from "./printers/helpers.js"; +import { printerForNodeType } from "./printers/index.js"; +export default { + print(path, options, print, args) { + return hasTerminal(path) + ? path.node.image + : printerForNodeType(path.node.name)(path, print, options, args); + }, + hasPrettierIgnore(path) { + var _a; + const { node } = path; + return (((_a = node.comments) === null || _a === void 0 ? void 0 : _a.some(({ image }) => /^(\/\/\s*prettier-ignore|\/\*\s*prettier-ignore\s*\*\/)$/.test(image))) === true || + (canAttachComment(node) && isFullyBetweenFormatterOffOn(path))); + }, + canAttachComment, + isBlockComment(node) { + return isTerminal(node) && node.tokenType.name === "TraditionalComment"; + }, + printComment(commentPath) { + const { node } = commentPath; + if (isNonTerminal(node) || node.tokenType.GROUP !== "comments") { + throw new Error(`Not a comment: ${JSON.stringify(node)}`); + } + return printComment(node); + }, + getCommentChildNodes(node) { + return isNonTerminal(node) + ? Object.values(node.children).flatMap(child => child) + : []; + }, + handleComments: { + ownLine: handleLineComment, + endOfLine: handleLineComment, + remaining: handleRemainingComment + } +}; +function hasTerminal(path) { + return isTerminal(path.node); +} diff --git a/frontend/src/utils/prettier/plugins/java/printers/arrays.d.ts b/frontend/src/utils/prettier/plugins/java/printers/arrays.d.ts new file mode 100644 index 0000000..ab22bfc --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/arrays.d.ts @@ -0,0 +1,9 @@ +declare const _default: { + arrayInitializer(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn, options: import("./helpers.js").JavaParserOptions): import("prettier/doc.js").builders.Group | "{}"; + variableInitializerList(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): import("prettier/doc.js").builders.Doc[]; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/printers/arrays.js b/frontend/src/utils/prettier/plugins/java/printers/arrays.js new file mode 100644 index 0000000..704bc6c --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/arrays.js @@ -0,0 +1,9 @@ +import { printArrayInitializer, printList } from "./helpers.js"; +export default { + arrayInitializer(path, print, options) { + return printArrayInitializer(path, print, options, "variableInitializerList"); + }, + variableInitializerList(path, print) { + return printList(path, print, "variableInitializer"); + } +}; diff --git a/frontend/src/utils/prettier/plugins/java/printers/blocks-and-statements.d.ts b/frontend/src/utils/prettier/plugins/java/printers/blocks-and-statements.d.ts new file mode 100644 index 0000000..a5af49e --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/blocks-and-statements.d.ts @@ -0,0 +1,117 @@ +import { builders } from "prettier/doc"; +import { printSingle } from "./helpers.js"; +declare const _default: { + block(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[]; + blockStatements(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + blockStatement: typeof printSingle; + localVariableDeclarationStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + localVariableDeclaration(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + localVariableType: typeof printSingle; + statement: typeof printSingle; + statementWithoutTrailingSubstatement: typeof printSingle; + emptyStatement(): string; + labeledStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + expressionStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + statementExpression: typeof printSingle; + ifStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + assertStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + switchStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + switchBlock(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[]; + switchBlockStatementGroup(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + switchLabel(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): "default" | builders.Group | builders.Doc[]; + switchRule(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + caseConstant: typeof printSingle; + casePattern: typeof printSingle; + whileStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + doStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): (string | builders.Group | builders.Doc[])[]; + forStatement: typeof printSingle; + basicForStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + forInit: typeof printSingle; + forUpdate: typeof printSingle; + statementExpressionList(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group; + enhancedForStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group; + breakStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[] | "break;"; + continueStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[] | "continue;"; + returnStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + throwStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + synchronizedStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + tryStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc; + catches(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + catchClause(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + catchFormalParameter(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + catchType(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + finally(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + tryWithResourcesStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + resourceSpecification(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group | "()"; + resourceList(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + resource: typeof printSingle; + yieldStatement(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + variableAccess: typeof printSingle; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/printers/blocks-and-statements.js b/frontend/src/utils/prettier/plugins/java/printers/blocks-and-statements.js new file mode 100644 index 0000000..224f156 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/blocks-and-statements.js @@ -0,0 +1,337 @@ +import { builders } from "prettier/doc"; +import { call, definedKeys, indentInParentheses, isBinaryExpression, isEmptyStatement, lineEndWithComments, lineStartWithComments, map, onlyDefinedKey, printBlock, printDanglingComments, printSingle, printWithModifiers } from "./helpers.js"; +const { group, hardline, ifBreak, indent, join, line, softline } = builders; +export default { + block(path, print) { + const statements = path.node.children.blockStatements + ? call(path, print, "blockStatements") + : []; + return printBlock(path, statements.length ? [statements] : []); + }, + blockStatements(path, print) { + return join(hardline, map(path, statementPath => { + const { node, previous } = statementPath; + const statement = print(statementPath); + return previous && + lineStartWithComments(node) > lineEndWithComments(previous) + 1 + ? [hardline, statement] + : statement; + }, "blockStatement").filter(doc => doc !== "")); + }, + blockStatement: printSingle, + localVariableDeclarationStatement(path, print) { + return [call(path, print, "localVariableDeclaration"), ";"]; + }, + localVariableDeclaration(path, print) { + const declaration = join(" ", [ + call(path, print, "localVariableType"), + call(path, print, "variableDeclaratorList") + ]); + return printWithModifiers(path, print, "variableModifier", declaration); + }, + localVariableType: printSingle, + statement: printSingle, + statementWithoutTrailingSubstatement: printSingle, + emptyStatement() { + return ""; + }, + labeledStatement(path, print) { + return [ + call(path, print, "Identifier"), + ": ", + call(path, print, "statement") + ]; + }, + expressionStatement(path, print) { + return [call(path, print, "statementExpression"), ";"]; + }, + statementExpression: printSingle, + ifStatement(path, print) { + var _a; + const { children } = path.node; + const hasEmptyStatement = isEmptyStatement(children.statement[0]); + const statements = map(path, print, "statement"); + const statement = [ + "if ", + indentInParentheses(call(path, print, "expression")), + hasEmptyStatement ? ";" : [" ", statements[0]] + ]; + if (children.Else) { + const danglingComments = printDanglingComments(path); + if (danglingComments.length) { + statement.push(hardline, ...danglingComments, hardline); + } + else { + const elseHasBlock = ((_a = children.statement[0].children + .statementWithoutTrailingSubstatement) === null || _a === void 0 ? void 0 : _a[0].children.block) !== + undefined; + statement.push(elseHasBlock ? " " : hardline); + } + const elseHasEmptyStatement = isEmptyStatement(children.statement[1]); + statement.push("else", elseHasEmptyStatement ? ";" : [" ", statements[1]]); + } + return statement; + }, + assertStatement(path, print) { + return ["assert ", ...join([" : "], map(path, print, "expression")), ";"]; + }, + switchStatement(path, print) { + return join(" ", [ + "switch", + indentInParentheses(call(path, print, "expression")), + call(path, print, "switchBlock") + ]); + }, + switchBlock(path, print) { + const { children } = path.node; + const caseKeys = definedKeys(children, [ + "switchBlockStatementGroup", + "switchRule" + ]); + const cases = caseKeys.length === 1 ? map(path, print, caseKeys[0]) : []; + return printBlock(path, cases); + }, + switchBlockStatementGroup(path, print) { + var _a, _b; + const { children } = path.node; + const switchLabel = call(path, print, "switchLabel"); + if (!children.blockStatements) { + return [switchLabel, ":"]; + } + const blockStatements = call(path, print, "blockStatements"); + const statements = children.blockStatements[0].children.blockStatement; + const onlyStatementIsBlock = statements.length === 1 && + ((_b = (_a = statements[0].children.statement) === null || _a === void 0 ? void 0 : _a[0].children.statementWithoutTrailingSubstatement) === null || _b === void 0 ? void 0 : _b[0].children.block) !== undefined; + return [ + switchLabel, + ":", + onlyStatementIsBlock + ? [" ", blockStatements] + : indent([hardline, blockStatements]) + ]; + }, + switchLabel(path, print) { + var _a, _b; + const { children } = path.node; + if (!((_b = (_a = children.caseConstant) !== null && _a !== void 0 ? _a : children.casePattern) !== null && _b !== void 0 ? _b : children.Null)) { + return "default"; + } + const values = []; + if (children.Null) { + values.push("null"); + if (children.Default) { + values.push("default"); + } + } + else { + const valuesKey = onlyDefinedKey(children, [ + "caseConstant", + "casePattern" + ]); + values.push(...map(path, print, valuesKey)); + } + const hasMultipleValues = values.length > 1; + const label = hasMultipleValues + ? ["case", indent([line, ...join([",", line], values)])] + : ["case ", values[0]]; + return children.guard + ? [ + group([...label, hasMultipleValues ? line : " "]), + call(path, print, "guard") + ] + : group(label); + }, + switchRule(path, print) { + const { children } = path.node; + const bodyKey = onlyDefinedKey(children, [ + "block", + "expression", + "throwStatement" + ]); + const parts = [ + call(path, print, "switchLabel"), + " -> ", + call(path, print, bodyKey) + ]; + if (children.Semicolon) { + parts.push(";"); + } + return parts; + }, + caseConstant: printSingle, + casePattern: printSingle, + whileStatement(path, print) { + const statement = call(path, print, "statement"); + const hasEmptyStatement = isEmptyStatement(path.node.children.statement[0]); + return [ + "while ", + indentInParentheses(call(path, print, "expression")), + ...[hasEmptyStatement ? ";" : " ", statement] + ]; + }, + doStatement(path, print) { + const hasEmptyStatement = isEmptyStatement(path.node.children.statement[0]); + return [ + "do", + hasEmptyStatement ? ";" : [" ", call(path, print, "statement")], + " while ", + indentInParentheses(call(path, print, "expression")), + ";" + ]; + }, + forStatement: printSingle, + basicForStatement(path, print) { + const { children } = path.node; + const danglingComments = printDanglingComments(path); + if (danglingComments.length) { + danglingComments.push(hardline); + } + const expressions = ["forInit", "expression", "forUpdate"].map(expressionKey => expressionKey in children ? call(path, print, expressionKey) : ""); + const hasEmptyStatement = isEmptyStatement(children.statement[0]); + return [ + ...danglingComments, + "for ", + expressions.some(expression => expression !== "") + ? indentInParentheses(join([";", line], expressions)) + : "(;;)", + hasEmptyStatement ? ";" : [" ", call(path, print, "statement")] + ]; + }, + forInit: printSingle, + forUpdate: printSingle, + statementExpressionList(path, print) { + return group(map(path, print, "statementExpression").map((expression, index) => index === 0 ? expression : [",", indent([line, expression])])); + }, + enhancedForStatement(path, print) { + var _a; + const statementNode = path.node.children.statement[0]; + const forStatement = [ + printDanglingComments(path), + "for ", + "(", + call(path, print, "localVariableDeclaration"), + " : ", + call(path, print, "expression"), + ")" + ]; + if (isEmptyStatement(statementNode)) { + forStatement.push(";"); + } + else { + const hasStatementBlock = ((_a = statementNode.children.statementWithoutTrailingSubstatement) === null || _a === void 0 ? void 0 : _a[0].children.block) !== undefined; + const statement = call(path, print, "statement"); + forStatement.push(hasStatementBlock ? [" ", statement] : indent([line, statement])); + } + return group(forStatement); + }, + breakStatement(path, print) { + return path.node.children.Identifier + ? ["break ", call(path, print, "Identifier"), ";"] + : "break;"; + }, + continueStatement(path, print) { + return path.node.children.Identifier + ? ["continue ", call(path, print, "Identifier"), ";"] + : "continue;"; + }, + returnStatement(path, print) { + const { children } = path.node; + const statement = ["return"]; + if (children.expression) { + statement.push(" "); + const expression = call(path, print, "expression"); + if (isBinaryExpression(children.expression[0])) { + statement.push(group([ + ifBreak("("), + indent([softline, expression]), + softline, + ifBreak(")") + ])); + } + else { + statement.push(expression); + } + } + statement.push(";"); + return statement; + }, + throwStatement(path, print) { + return ["throw ", call(path, print, "expression"), ";"]; + }, + synchronizedStatement(path, print) { + return [ + "synchronized ", + indentInParentheses(call(path, print, "expression")), + " ", + call(path, print, "block") + ]; + }, + tryStatement(path, print) { + const { children } = path.node; + if (children.tryWithResourcesStatement) { + return call(path, print, "tryWithResourcesStatement"); + } + const blocks = ["try", call(path, print, "block")]; + if (children.catches) { + blocks.push(call(path, print, "catches")); + } + if (children.finally) { + blocks.push(call(path, print, "finally")); + } + return join(" ", blocks); + }, + catches(path, print) { + return join(" ", map(path, print, "catchClause")); + }, + catchClause(path, print) { + return [ + "catch ", + indentInParentheses(call(path, print, "catchFormalParameter")), + " ", + call(path, print, "block") + ]; + }, + catchFormalParameter(path, print) { + return join(" ", [ + ...map(path, print, "variableModifier"), + call(path, print, "catchType"), + call(path, print, "variableDeclaratorId") + ]); + }, + catchType(path, print) { + return join([line, "| "], [call(path, print, "unannClassType"), ...map(path, print, "classType")]); + }, + finally(path, print) { + return ["finally ", call(path, print, "block")]; + }, + tryWithResourcesStatement(path, print) { + const { children } = path.node; + const blocks = [ + "try", + call(path, print, "resourceSpecification"), + call(path, print, "block") + ]; + if (children.catches) { + blocks.push(call(path, print, "catches")); + } + if (children.finally) { + blocks.push(call(path, print, "finally")); + } + return join(" ", blocks); + }, + resourceSpecification(path, print) { + const resources = [call(path, print, "resourceList")]; + if (path.node.children.Semicolon) { + resources.push(ifBreak(";")); + } + return indentInParentheses(resources); + }, + resourceList(path, print) { + return join([";", line], map(path, print, "resource")); + }, + resource: printSingle, + yieldStatement(path, print) { + return ["yield ", call(path, print, "expression"), ";"]; + }, + variableAccess: printSingle +}; diff --git a/frontend/src/utils/prettier/plugins/java/printers/classes.d.ts b/frontend/src/utils/prettier/plugins/java/printers/classes.d.ts new file mode 100644 index 0000000..dae34f5 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/classes.d.ts @@ -0,0 +1,157 @@ +import type { ClassBodyCstNode, EnumBodyDeclarationsCstNode } from "java-parser"; +import type { AstPath } from "prettier"; +import { builders } from "prettier/doc"; +import { printClassPermits, printClassType, printSingle, type JavaPrintFn } from "./helpers.js"; +declare const _default: { + classDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; + normalClassDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; + classModifier: typeof printSingle; + typeParameters(path: AstPath, print: JavaPrintFn): builders.Group; + typeParameterList(path: AstPath, print: JavaPrintFn): builders.Doc[]; + classExtends(path: AstPath, print: JavaPrintFn): builders.Doc[]; + classImplements(path: AstPath, print: JavaPrintFn): builders.Group; + classPermits: typeof printClassPermits; + interfaceTypeList(path: AstPath, print: JavaPrintFn): builders.Group; + classBody(path: AstPath, print: JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[]; + classBodyDeclaration: typeof printSingle; + classMemberDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc; + fieldDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; + fieldModifier: typeof printSingle; + variableDeclaratorList(path: AstPath, print: JavaPrintFn): builders.Group | builders.Doc[]; + variableDeclarator(path: AstPath, print: JavaPrintFn): builders.Doc; + variableDeclaratorId(path: AstPath, print: JavaPrintFn): builders.Doc; + variableInitializer: typeof printSingle; + unannType: typeof printSingle; + unannPrimitiveTypeWithOptionalDimsSuffix(path: AstPath, print: JavaPrintFn): builders.Doc; + unannPrimitiveType: typeof printSingle; + unannReferenceType(path: AstPath, print: JavaPrintFn): builders.Doc; + unannClassOrInterfaceType: typeof printSingle; + unannClassType: typeof printClassType; + unannInterfaceType: typeof printSingle; + unannTypeVariable: typeof printSingle; + methodDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; + methodModifier: typeof printSingle; + methodHeader(path: AstPath, print: JavaPrintFn): builders.Group; + result: typeof printSingle; + methodDeclarator(path: AstPath, print: JavaPrintFn): builders.Doc[]; + receiverParameter(path: AstPath, print: JavaPrintFn): builders.Doc[]; + formalParameterList(path: AstPath, print: JavaPrintFn): builders.Doc[]; + formalParameter: typeof printSingle; + variableParaRegularParameter(path: AstPath, print: JavaPrintFn): builders.Doc[]; + variableArityParameter(path: AstPath, print: JavaPrintFn): builders.Doc[]; + variableModifier: typeof printSingle; + throws(path: AstPath, print: JavaPrintFn): builders.Doc[]; + exceptionTypeList(path: AstPath, print: JavaPrintFn): builders.Doc[]; + exceptionType: typeof printSingle; + methodBody: typeof printSingle; + instanceInitializer: typeof printSingle; + staticInitializer(path: AstPath, print: JavaPrintFn): builders.Doc[]; + constructorDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; + constructorModifier: typeof printSingle; + constructorDeclarator(path: AstPath, print: JavaPrintFn): builders.Doc[]; + simpleTypeName: typeof printSingle; + constructorBody(path: AstPath, print: JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[]; + explicitConstructorInvocation: typeof printSingle; + unqualifiedExplicitConstructorInvocation(path: AstPath, print: JavaPrintFn): builders.Doc[]; + qualifiedExplicitConstructorInvocation(path: AstPath, print: JavaPrintFn): builders.Doc[]; + enumDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; + enumBody(path: AstPath, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[]; + enumConstantList(path: AstPath, print: JavaPrintFn): builders.Doc[]; + enumConstant(path: AstPath, print: JavaPrintFn): builders.Doc[]; + enumConstantModifier: typeof printSingle; + enumBodyDeclarations(path: AstPath, print: JavaPrintFn): builders.Doc[]; + recordDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; + recordHeader(path: AstPath, print: JavaPrintFn): builders.Group | "()"; + recordComponentList(path: AstPath, print: JavaPrintFn): builders.Doc[]; + recordComponent(path: AstPath, print: JavaPrintFn): builders.Group; + variableArityRecordComponent(path: AstPath, print: JavaPrintFn): builders.Doc[]; + recordComponentModifier: typeof printSingle; + recordBody(path: AstPath, print: JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[]; + recordBodyDeclaration: typeof printSingle; + compactConstructorDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/printers/classes.js b/frontend/src/utils/prettier/plugins/java/printers/classes.js new file mode 100644 index 0000000..b69b51d --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/classes.js @@ -0,0 +1,446 @@ +import { builders } from "prettier/doc"; +import { call, each, hasDeclarationAnnotations, hasLeadingComments, indentInParentheses, isBinaryExpression, lineEndWithComments, lineStartWithComments, map, onlyDefinedKey, printBlock, printClassPermits, printClassType, printDanglingComments, printList, printSingle, printWithModifiers } from "./helpers.js"; +const { group, hardline, indent, indentIfBreak, join, line, softline } = builders; +export default { + classDeclaration(path, print) { + const declarationKey = onlyDefinedKey(path.node.children, [ + "enumDeclaration", + "normalClassDeclaration", + "recordDeclaration" + ]); + const declaration = call(path, print, declarationKey); + return printWithModifiers(path, print, "classModifier", declaration, true); + }, + normalClassDeclaration(path, print) { + const { classExtends, classImplements, classPermits, typeParameters } = path.node.children; + const header = ["class ", call(path, print, "typeIdentifier")]; + if (typeParameters) { + header.push(call(path, print, "typeParameters")); + } + if (classExtends) { + header.push(indent([line, call(path, print, "classExtends")])); + } + if (classImplements) { + header.push(indent([line, call(path, print, "classImplements")])); + } + if (classPermits) { + header.push(indent([line, call(path, print, "classPermits")])); + } + return [group(header), " ", call(path, print, "classBody")]; + }, + classModifier: printSingle, + typeParameters(path, print) { + return group([ + "<", + indent([softline, call(path, print, "typeParameterList")]), + softline, + ">" + ]); + }, + typeParameterList(path, print) { + return printList(path, print, "typeParameter"); + }, + classExtends(path, print) { + return ["extends ", call(path, print, "classType")]; + }, + classImplements(path, print) { + return group([ + "implements", + indent([line, call(path, print, "interfaceTypeList")]) + ]); + }, + classPermits: printClassPermits, + interfaceTypeList(path, print) { + return group(printList(path, print, "interfaceType")); + }, + classBody(path, print) { + return printBlock(path, printClassBodyDeclarations(path, print)); + }, + classBodyDeclaration: printSingle, + classMemberDeclaration(path, print) { + const { children } = path.node; + return children.Semicolon + ? "" + : call(path, print, onlyDefinedKey(children)); + }, + fieldDeclaration(path, print) { + const declaration = [ + call(path, print, "unannType"), + " ", + call(path, print, "variableDeclaratorList"), + ";" + ]; + return printWithModifiers(path, print, "fieldModifier", declaration); + }, + fieldModifier: printSingle, + variableDeclaratorList(path, print) { + var _a; + const declarators = map(path, print, "variableDeclarator"); + return declarators.length > 1 && + path.node.children.variableDeclarator.some(({ children }) => children.Equals) + ? group(indent(join([",", line], declarators)), { + shouldBreak: ((_a = path.getNode(4)) === null || _a === void 0 ? void 0 : _a.name) !== "forInit" + }) + : join(", ", declarators); + }, + variableDeclarator(path, print) { + var _a, _b; + const { children } = path.node; + const variableInitializer = (_a = children.variableInitializer) === null || _a === void 0 ? void 0 : _a[0]; + const declaratorId = call(path, print, "variableDeclaratorId"); + if (!variableInitializer) { + return declaratorId; + } + const expression = (_b = variableInitializer.children.expression) === null || _b === void 0 ? void 0 : _b[0]; + const declarator = [declaratorId, " ", call(path, print, "Equals")]; + const initializer = call(path, print, "variableInitializer"); + if (hasLeadingComments(variableInitializer) || + (expression && isBinaryExpression(expression))) { + declarator.push(group(indent([line, initializer]))); + } + else { + const groupId = Symbol("assignment"); + declarator.push(group(indent(line), { id: groupId }), indentIfBreak(initializer, { groupId })); + } + return group(declarator); + }, + variableDeclaratorId(path, print) { + const { dims, Underscore } = path.node.children; + if (Underscore) { + return "_"; + } + const identifier = call(path, print, "Identifier"); + return dims ? [identifier, call(path, print, "dims")] : identifier; + }, + variableInitializer: printSingle, + unannType: printSingle, + unannPrimitiveTypeWithOptionalDimsSuffix(path, print) { + const type = call(path, print, "unannPrimitiveType"); + return path.node.children.dims ? [type, call(path, print, "dims")] : type; + }, + unannPrimitiveType: printSingle, + unannReferenceType(path, print) { + const type = call(path, print, "unannClassOrInterfaceType"); + return path.node.children.dims ? [type, call(path, print, "dims")] : type; + }, + unannClassOrInterfaceType: printSingle, + unannClassType: printClassType, + unannInterfaceType: printSingle, + unannTypeVariable: printSingle, + methodDeclaration(path, print) { + const declaration = [ + call(path, print, "methodHeader"), + path.node.children.methodBody[0].children.Semicolon ? "" : " ", + call(path, print, "methodBody") + ]; + return printWithModifiers(path, print, "methodModifier", declaration); + }, + methodModifier: printSingle, + methodHeader(path, print) { + const { typeParameters, annotation, throws } = path.node.children; + const header = []; + if (typeParameters) { + header.push(call(path, print, "typeParameters")); + } + if (annotation) { + header.push(join(line, map(path, print, "annotation"))); + } + header.push(call(path, print, "result"), call(path, print, "methodDeclarator")); + return throws + ? group([ + ...join(" ", header), + group(indent([line, call(path, print, "throws")])) + ]) + : group(join(" ", header)); + }, + result: printSingle, + methodDeclarator(path, print) { + const { dims, formalParameterList, receiverParameter } = path.node.children; + const declarator = [call(path, print, "Identifier")]; + const parameters = []; + if (receiverParameter) { + parameters.push(call(path, print, "receiverParameter")); + } + if (formalParameterList) { + parameters.push(call(path, print, "formalParameterList")); + } + const items = parameters.length + ? join([",", line], parameters) + : printDanglingComments(path); + declarator.push(items.length ? indentInParentheses(items) : "()"); + if (dims) { + declarator.push(call(path, print, "dims")); + } + return declarator; + }, + receiverParameter(path, print) { + return join(" ", [ + ...map(path, print, "annotation"), + call(path, print, "unannType"), + path.node.children.Identifier + ? [call(path, print, "Identifier"), ".this"] + : "this" + ]); + }, + formalParameterList(path, print) { + return printList(path, print, "formalParameter"); + }, + formalParameter: printSingle, + variableParaRegularParameter(path, print) { + return join(" ", [ + ...map(path, print, "variableModifier"), + call(path, print, "unannType"), + call(path, print, "variableDeclaratorId") + ]); + }, + variableArityParameter(path, print) { + const type = join(" ", [ + ...map(path, print, "variableModifier"), + call(path, print, "unannType"), + ...map(path, print, "annotation") + ]); + return [type, "... ", call(path, print, "Identifier")]; + }, + variableModifier: printSingle, + throws(path, print) { + return ["throws ", call(path, print, "exceptionTypeList")]; + }, + exceptionTypeList(path, print) { + return join(", ", map(path, print, "exceptionType")); + }, + exceptionType: printSingle, + methodBody: printSingle, + instanceInitializer: printSingle, + staticInitializer(path, print) { + return ["static ", call(path, print, "block")]; + }, + constructorDeclaration(path, print) { + const declaration = [call(path, print, "constructorDeclarator")]; + if (path.node.children.throws) { + declaration.push(group(indent([line, call(path, print, "throws")]))); + } + declaration.push(" ", call(path, print, "constructorBody")); + return printWithModifiers(path, print, "constructorModifier", declaration, true); + }, + constructorModifier: printSingle, + constructorDeclarator(path, print) { + const { children } = path.node; + const parameters = []; + if (children.receiverParameter) { + parameters.push(call(path, print, "receiverParameter")); + } + if (children.formalParameterList) { + parameters.push(call(path, print, "formalParameterList")); + } + const header = [call(path, print, "simpleTypeName")]; + header.push(parameters.length + ? indentInParentheses(join([",", line], parameters)) + : "()"); + return children.typeParameters + ? [call(path, print, "typeParameters"), " ", ...header] + : header; + }, + simpleTypeName: printSingle, + constructorBody(path, print) { + const { children } = path.node; + const statements = []; + if (children.explicitConstructorInvocation) { + statements.push(call(path, print, "explicitConstructorInvocation")); + } + if (children.blockStatements) { + statements.push(call(path, print, "blockStatements")); + } + return printBlock(path, statements); + }, + explicitConstructorInvocation: printSingle, + unqualifiedExplicitConstructorInvocation(path, print) { + const { children } = path.node; + const invocation = []; + if (children.typeArguments) { + invocation.push(call(path, print, "typeArguments")); + } + invocation.push(children.Super ? "super" : "this"); + if (children.argumentList) { + invocation.push(group(["(", call(path, print, "argumentList"), ")"])); + } + else { + invocation.push(indentInParentheses(printDanglingComments(path), { shouldBreak: true })); + } + invocation.push(";"); + return invocation; + }, + qualifiedExplicitConstructorInvocation(path, print) { + const { children } = path.node; + const invocation = [call(path, print, "expressionName"), "."]; + if (children.typeArguments) { + invocation.push(call(path, print, "typeArguments")); + } + invocation.push("super"); + if (children.argumentList) { + invocation.push(group(["(", call(path, print, "argumentList"), ")"])); + } + else { + invocation.push(indentInParentheses(printDanglingComments(path), { shouldBreak: true })); + } + invocation.push(";"); + return invocation; + }, + enumDeclaration(path, print) { + const header = ["enum", call(path, print, "typeIdentifier")]; + if (path.node.children.classImplements) { + header.push(call(path, print, "classImplements")); + } + return join(" ", [...header, call(path, print, "enumBody")]); + }, + enumBody(path, print, options) { + var _a; + const { children } = path.node; + const contents = []; + const hasNonEmptyDeclaration = ((_a = children.enumBodyDeclarations) !== null && _a !== void 0 ? _a : []) + .flatMap(({ children }) => { var _a; return (_a = children.classBodyDeclaration) !== null && _a !== void 0 ? _a : []; }) + .some(({ children }) => { var _a; return !((_a = children.classMemberDeclaration) === null || _a === void 0 ? void 0 : _a[0].children.Semicolon); }); + if (children.enumConstantList) { + contents.push(call(path, print, "enumConstantList")); + if (!hasNonEmptyDeclaration && options.trailingComma !== "none") { + contents.push(","); + } + } + if (hasNonEmptyDeclaration) { + contents.push(";", hardline, call(path, print, "enumBodyDeclarations")); + } + return printBlock(path, contents.length ? [contents] : []); + }, + enumConstantList(path, print) { + return join([",", hardline], map(path, constantPath => { + const constant = print(constantPath); + const { node, previous } = constantPath; + return !previous || + lineStartWithComments(node) <= lineEndWithComments(previous) + 1 + ? constant + : [hardline, constant]; + }, "enumConstant")); + }, + enumConstant(path, print) { + const { argumentList, classBody } = path.node.children; + const initializer = [call(path, print, "Identifier")]; + if (argumentList) { + initializer.push(group(["(", call(path, print, "argumentList"), ")"])); + } + if (classBody) { + initializer.push(" ", call(path, print, "classBody")); + } + return printWithModifiers(path, print, "enumConstantModifier", initializer); + }, + enumConstantModifier: printSingle, + enumBodyDeclarations(path, print) { + return join(hardline, printClassBodyDeclarations(path, print)); + }, + recordDeclaration(path, print) { + const { children } = path.node; + const header = ["record ", call(path, print, "typeIdentifier")]; + if (children.typeParameters) { + header.push(call(path, print, "typeParameters")); + } + header.push(call(path, print, "recordHeader")); + if (children.classImplements) { + header.push(" ", call(path, print, "classImplements")); + } + return [group(header), " ", call(path, print, "recordBody")]; + }, + recordHeader(path, print) { + return path.node.children.recordComponentList + ? indentInParentheses(call(path, print, "recordComponentList")) + : indentInParentheses(printDanglingComments(path), { shouldBreak: true }); + }, + recordComponentList(path, print) { + return join([",", line], map(path, componentPath => { + const { node, previous } = componentPath; + const blankLine = previous && + lineStartWithComments(node) > lineEndWithComments(previous) + 1; + const component = print(componentPath); + return blankLine ? [softline, component] : component; + }, "recordComponent")); + }, + recordComponent(path, print) { + const { children } = path.node; + const component = [call(path, print, "unannType")]; + if (children.Identifier || + children.variableArityRecordComponent[0].children.annotation) { + component.push(" "); + } + const suffixKey = onlyDefinedKey(children, [ + "Identifier", + "variableArityRecordComponent" + ]); + component.push(call(path, print, suffixKey)); + return group(join(line, [...map(path, print, "recordComponentModifier"), component])); + }, + variableArityRecordComponent(path, print) { + return [ + ...join(" ", map(path, print, "annotation")), + "... ", + call(path, print, "Identifier") + ]; + }, + recordComponentModifier: printSingle, + recordBody(path, print) { + const declarations = []; + let previousRequiresPadding = false; + each(path, declarationPath => { + var _a, _b, _c, _d; + const declaration = print(declarationPath); + if (declaration === "") { + return; + } + const { node, previous } = declarationPath; + const fieldDeclaration = (_c = (_b = (_a = node.children.classBodyDeclaration) === null || _a === void 0 ? void 0 : _a[0].children.classMemberDeclaration) === null || _b === void 0 ? void 0 : _b[0].children.fieldDeclaration) === null || _c === void 0 ? void 0 : _c[0].children; + const currentRequiresPadding = !fieldDeclaration || + hasDeclarationAnnotations((_d = fieldDeclaration.fieldModifier) !== null && _d !== void 0 ? _d : []); + const blankLine = declarations.length > 0 && + (previousRequiresPadding || + currentRequiresPadding || + lineStartWithComments(node) > lineEndWithComments(previous) + 1); + declarations.push(blankLine ? [hardline, declaration] : declaration); + previousRequiresPadding = currentRequiresPadding; + }, "recordBodyDeclaration"); + return printBlock(path, declarations); + }, + recordBodyDeclaration: printSingle, + compactConstructorDeclaration(path, print) { + const declaration = [ + call(path, print, "simpleTypeName"), + " ", + call(path, print, "constructorBody") + ]; + return printWithModifiers(path, print, "constructorModifier", declaration, true); + } +}; +function printClassBodyDeclarations(path, print) { + var _a; + if (!path.node.children.classBodyDeclaration) { + return []; + } + const declarations = []; + let previousRequiresPadding = path.node.name === "enumBodyDeclarations" || + ((_a = path.grandparent) === null || _a === void 0 ? void 0 : _a.name) === + "normalClassDeclaration"; + each(path, declarationPath => { + var _a, _b, _c; + const declaration = print(declarationPath); + if (declaration === "") { + return; + } + const { node, previous } = declarationPath; + const fieldDeclaration = (_b = (_a = node.children.classMemberDeclaration) === null || _a === void 0 ? void 0 : _a[0].children.fieldDeclaration) === null || _b === void 0 ? void 0 : _b[0].children; + const currentRequiresPadding = fieldDeclaration + ? hasDeclarationAnnotations((_c = fieldDeclaration.fieldModifier) !== null && _c !== void 0 ? _c : []) + : true; + const blankLine = previousRequiresPadding || + (declarations.length > 0 && + (currentRequiresPadding || + lineStartWithComments(node) > lineEndWithComments(previous) + 1)); + declarations.push(blankLine ? [hardline, declaration] : declaration); + previousRequiresPadding = currentRequiresPadding; + }, "classBodyDeclaration"); + return declarations; +} diff --git a/frontend/src/utils/prettier/plugins/java/printers/expressions.d.ts b/frontend/src/utils/prettier/plugins/java/printers/expressions.d.ts new file mode 100644 index 0000000..29eff55 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/expressions.d.ts @@ -0,0 +1,134 @@ +import type { StringTemplateCstNode, TextBlockTemplateCstNode } from "java-parser"; +import type { AstPath } from "prettier"; +import { builders } from "prettier/doc"; +import type { JavaComment } from "../comments.js"; +import { printSingle, type JavaPrintFn } from "./helpers.js"; +declare const _default: { + expression: typeof printSingle; + lambdaExpression(path: AstPath, print: JavaPrintFn, _: import("./helpers.js").JavaParserOptions, args?: unknown): builders.Doc[]; + lambdaParameters(path: AstPath, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Doc; + lambdaParametersWithBraces(path: AstPath, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Doc; + lambdaParameterList: typeof printSingle; + conciseLambdaParameterList(path: AstPath, print: JavaPrintFn): builders.Doc[]; + normalLambdaParameterList(path: AstPath, print: JavaPrintFn): builders.Doc[]; + normalLambdaParameter: typeof printSingle; + regularLambdaParameter(path: AstPath, print: JavaPrintFn): builders.Doc[]; + lambdaParameterType: typeof printSingle; + conciseLambdaParameter: typeof printSingle; + lambdaBody: typeof printSingle; + conditionalExpression(path: AstPath, print: JavaPrintFn): builders.Doc; + binaryExpression(path: AstPath, print: JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Doc; + unaryExpression(path: AstPath, print: JavaPrintFn): builders.Doc[]; + unaryExpressionNotPlusMinus(path: AstPath, print: JavaPrintFn): builders.Doc[]; + primary(path: AstPath, print: JavaPrintFn): builders.Doc; + primaryPrefix: typeof printSingle; + primarySuffix(path: AstPath, print: JavaPrintFn): builders.Doc; + fqnOrRefType(path: AstPath, print: JavaPrintFn, _: import("./helpers.js").JavaParserOptions, args: unknown): builders.Doc[]; + fqnOrRefTypePartFirst(path: AstPath, print: JavaPrintFn): builders.Doc[]; + fqnOrRefTypePartRest(path: AstPath, print: JavaPrintFn): builders.Doc[]; + fqnOrRefTypePartCommon(path: AstPath, print: JavaPrintFn): builders.Doc; + parenthesisExpression(path: AstPath, print: JavaPrintFn): builders.Group | "()" | (string | builders.Indent)[]; + castExpression: typeof printSingle; + primitiveCastExpression(path: AstPath, print: JavaPrintFn): builders.Doc[]; + referenceTypeCastExpression(path: AstPath, print: JavaPrintFn): builders.Doc[]; + newExpression: typeof printSingle; + unqualifiedClassInstanceCreationExpression(path: AstPath, print: JavaPrintFn): builders.Doc[]; + classOrInterfaceTypeToInstantiate(path: AstPath, print: JavaPrintFn): builders.Doc[]; + typeArgumentsOrDiamond: typeof printSingle; + diamond(): string; + methodInvocationSuffix(path: AstPath, print: JavaPrintFn): builders.Group | "()"; + argumentList(path: AstPath, print: JavaPrintFn): builders.Group | (builders.Indent | builders.Softline)[] | (builders.BreakParent | builders.Group)[]; + arrayCreationExpression(path: AstPath, print: JavaPrintFn): builders.Doc[]; + arrayCreationExpressionWithoutInitializerSuffix(path: AstPath, print: JavaPrintFn): builders.Doc; + arrayCreationWithInitializerSuffix(path: AstPath, print: JavaPrintFn): builders.Doc[]; + dimExprs(path: AstPath, print: JavaPrintFn): builders.Doc[]; + dimExpr(path: AstPath, print: JavaPrintFn): builders.Doc[]; + classLiteralSuffix(path: AstPath, print: JavaPrintFn): builders.Doc[]; + arrayAccessSuffix(path: AstPath, print: JavaPrintFn): builders.Doc[]; + methodReferenceSuffix(path: AstPath, print: JavaPrintFn): builders.Doc[]; + templateArgument: typeof printSingle; + template: typeof printSingle; + stringTemplate(path: AstPath, print: JavaPrintFn): builders.Indent; + textBlockTemplate(path: AstPath, print: JavaPrintFn): builders.Indent; + embeddedExpression: typeof printSingle; + pattern: typeof printSingle; + typePattern: typeof printSingle; + recordPattern(path: AstPath, print: JavaPrintFn): builders.Doc[]; + componentPatternList(path: AstPath, print: JavaPrintFn): builders.Doc[]; + componentPattern: typeof printSingle; + matchAllPattern: typeof printSingle; + guard(path: AstPath, print: JavaPrintFn): builders.Doc[]; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/printers/expressions.js b/frontend/src/utils/prettier/plugins/java/printers/expressions.js new file mode 100644 index 0000000..9f3fa45 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/expressions.js @@ -0,0 +1,598 @@ +import { builders, utils } from "prettier/doc"; +import { call, definedKeys, each, findBaseIndent, flatMap, hasLeadingComments, indentInParentheses, isBinaryExpression, isNonTerminal, isTerminal, map, onlyDefinedKey, printDanglingComments, printList, printName, printSingle } from "./helpers.js"; +const { breakParent, conditionalGroup, group, hardline, ifBreak, indent, indentIfBreak, join, line, lineSuffixBoundary, softline } = builders; +const { removeLines, willBreak } = utils; +export default { + expression: printSingle, + lambdaExpression(path, print, _, args = {}) { + var _a; + const hug = (_a = args.hug) !== null && _a !== void 0 ? _a : false; + const parameters = call(path, print, "lambdaParameters"); + const expression = [hug ? removeLines(parameters) : parameters, " ->"]; + const lambdaExpression = path.node.children.lambdaBody[0].children.expression; + const body = call(path, print, "lambdaBody"); + if (lambdaExpression) { + const suffix = indent([line, body]); + expression.push(group(hug ? [suffix, softline] : suffix)); + } + else { + expression.push(" ", body); + } + return expression; + }, + lambdaParameters(path, print, options) { + const parameters = printSingle(path, print); + return !path.node.children.lambdaParametersWithBraces && + options.arrowParens === "always" + ? ["(", parameters, ")"] + : parameters; + }, + lambdaParametersWithBraces(path, print, options) { + var _a; + const { lambdaParameterList } = path.node.children; + if (!lambdaParameterList) { + return "()"; + } + const { conciseLambdaParameterList, normalLambdaParameterList } = lambdaParameterList[0].children; + const parameterCount = ((_a = conciseLambdaParameterList === null || conciseLambdaParameterList === void 0 ? void 0 : conciseLambdaParameterList[0].children.conciseLambdaParameter) !== null && _a !== void 0 ? _a : normalLambdaParameterList === null || normalLambdaParameterList === void 0 ? void 0 : normalLambdaParameterList[0].children.normalLambdaParameter).length; + const parameters = call(path, print, "lambdaParameterList"); + if (parameterCount > 1) { + return indentInParentheses(parameters); + } + return conciseLambdaParameterList && options.arrowParens === "avoid" + ? parameters + : ["(", parameters, ")"]; + }, + lambdaParameterList: printSingle, + conciseLambdaParameterList(path, print) { + return printList(path, print, "conciseLambdaParameter"); + }, + normalLambdaParameterList(path, print) { + return printList(path, print, "normalLambdaParameter"); + }, + normalLambdaParameter: printSingle, + regularLambdaParameter(path, print) { + return join(" ", [ + ...map(path, print, "variableModifier"), + call(path, print, "lambdaParameterType"), + call(path, print, "variableDeclaratorId") + ]); + }, + lambdaParameterType: printSingle, + conciseLambdaParameter: printSingle, + lambdaBody: printSingle, + conditionalExpression(path, print) { + var _a; + 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 isNestedTernary = ((_a = path.getNode(4)) === null || _a === void 0 ? void 0 : _a.name) === + "conditionalExpression"; + return isNestedTernary ? contents : group(contents); + }, + binaryExpression(path, print, options) { + var _a, _b; + const { children } = path.node; + const operands = flatMap(path, print, definedKeys(children, [ + "expression", + "pattern", + "referenceType", + "unaryExpression" + ])); + const operators = flatMap(path, operatorPath => { + const { node } = operatorPath; + let image; + if (isTerminal(node)) { + image = node.image; + } + else if (node.children.Less) { + image = "<<"; + } + else { + image = node.children.Greater.length === 2 ? ">>" : ">>>"; + } + return { image, doc: print(operatorPath) }; + }, definedKeys(children, [ + "AssignmentOperator", + "BinaryOperator", + "Instanceof", + "shiftOperator" + ])); + const hasNonAssignmentOperators = (operators.length > 0 && !children.AssignmentOperator) || + (children.expression !== undefined && + isBinaryExpression(children.expression[0])); + const isInList = ((_a = path.getNode(4)) === null || _a === void 0 ? void 0 : _a.name) === "elementValue" || + ((_b = path.getNode(6)) === null || _b === void 0 ? void 0 : _b.name) === "argumentList"; + return binary(operands, operators, { + hasNonAssignmentOperators, + isInList, + isRoot: true, + operatorPosition: options.experimentalOperatorPosition + }); + }, + unaryExpression(path, print) { + return [ + ...map(path, print, "UnaryPrefixOperator"), + call(path, print, "primary"), + ...map(path, print, "UnarySuffixOperator") + ]; + }, + unaryExpressionNotPlusMinus(path, print) { + const { children } = path.node; + const expression = []; + if (children.UnaryPrefixOperatorNotPlusMinus) { + expression.push(...map(path, print, "UnaryPrefixOperatorNotPlusMinus")); + } + expression.push(call(path, print, "primary")); + if (children.UnarySuffixOperator) { + expression.push(...map(path, print, "UnarySuffixOperator")); + } + return join(" ", expression); + }, + primary(path, print) { + var _a, _b; + const { children } = path.node; + if (!children.primarySuffix) { + return call(path, print, "primaryPrefix"); + } + const methodInvocations = children.primarySuffix + .filter(({ children }) => children.methodInvocationSuffix) + .map(({ children }) => children.methodInvocationSuffix[0].children); + const hasLambdaMethodParameter = methodInvocations.some(({ argumentList }) => argumentList === null || argumentList === void 0 ? void 0 : argumentList[0].children.expression.some(({ children }) => children.lambdaExpression)); + const prefixIsCallExpression = children.primaryPrefix[0].children.newExpression; + const callExpressionCount = methodInvocations.length + + (prefixIsCallExpression ? 1 : 0) + + children.primarySuffix.filter(({ children }) => children.unqualifiedClassInstanceCreationExpression).length; + const fqnOrRefType = (_a = children.primaryPrefix[0].children.fqnOrRefType) === null || _a === void 0 ? void 0 : _a[0].children; + const prefixIsMethodInvocation = (fqnOrRefType === null || fqnOrRefType === void 0 ? void 0 : fqnOrRefType.fqnOrRefTypePartRest) !== undefined && + ((_b = children.primarySuffix) === null || _b === void 0 ? void 0 : _b[0].children.methodInvocationSuffix) !== undefined; + const prefixIsStaticMethodInvocation = prefixIsMethodInvocation && isCapitalizedIdentifier(fqnOrRefType); + const prefixIsInstanceMethodInvocation = prefixIsMethodInvocation && !prefixIsStaticMethodInvocation; + const mustBreakForCallExpressions = methodInvocations.length > 2 && hasLambdaMethodParameter; + const separator = mustBreakForCallExpressions ? hardline : softline; + const prefix = [ + call(path, prefixPath => print(prefixPath, { + lastSeparator: prefixIsStaticMethodInvocation || + (prefixIsInstanceMethodInvocation && callExpressionCount === 1) + ? "" + : separator + }), "primaryPrefix") + ]; + const canBreakForCallExpressions = callExpressionCount > 2 || + (callExpressionCount === 2 && prefixIsInstanceMethodInvocation) || + willBreak(prefix); + const suffixes = []; + each(path, suffixPath => { + const { node, previous } = suffixPath; + const suffix = print(suffixPath); + if (node.children.Dot) { + if ((canBreakForCallExpressions && + ((!previous && prefixIsCallExpression) || + (previous === null || previous === void 0 ? void 0 : previous.children.methodInvocationSuffix) || + (previous === null || previous === void 0 ? void 0 : previous.children.unqualifiedClassInstanceCreationExpression))) || + (!node.children.templateArgument && willBreak(suffix))) { + suffixes.push(separator); + } + suffixes.push(suffix); + } + else if (previous) { + suffixes.push(suffix); + } + else { + prefix.push(prefixIsInstanceMethodInvocation && callExpressionCount >= 2 + ? indent(suffix) + : suffix); + } + }, "primarySuffix"); + const hasSuffixComments = children.primarySuffix.some(suffix => hasLeadingComments(suffix)); + return group(canBreakForCallExpressions || hasSuffixComments + ? [prefix, indent(suffixes)] + : [prefix, ...suffixes]); + }, + primaryPrefix: printSingle, + primarySuffix(path, print) { + const { children } = path.node; + if (!children.Dot) { + return printSingle(path, print); + } + const suffix = ["."]; + if (children.This) { + suffix.push("this"); + } + else if (children.Identifier) { + if (children.typeArguments) { + suffix.push(call(path, print, "typeArguments")); + } + suffix.push(call(path, print, "Identifier")); + } + else { + const suffixKey = onlyDefinedKey(children, [ + "templateArgument", + "unqualifiedClassInstanceCreationExpression" + ]); + suffix.push(call(path, print, suffixKey)); + } + return suffix; + }, + fqnOrRefType(path, print, _, args) { + var _a; + const lastSeparator = (_a = args.lastSeparator) !== null && _a !== void 0 ? _a : ""; + const fqnOrRefType = [ + call(path, print, "fqnOrRefTypePartFirst"), + ...map(path, partPath => { + const part = print(partPath); + return partPath.isLast + ? [willBreak(part) ? hardline : lastSeparator, part] + : part; + }, "fqnOrRefTypePartRest") + ]; + fqnOrRefType.push(indent(fqnOrRefType.pop())); + return path.node.children.dims + ? [fqnOrRefType, call(path, print, "dims")] + : fqnOrRefType; + }, + fqnOrRefTypePartFirst(path, print) { + return join(" ", [ + ...map(path, print, "annotation"), + call(path, print, "fqnOrRefTypePartCommon") + ]); + }, + fqnOrRefTypePartRest(path, print) { + const common = call(path, print, "fqnOrRefTypePartCommon"); + const type = path.node.children.typeArguments + ? [call(path, print, "typeArguments"), common] + : common; + return [".", ...join(" ", [...map(path, print, "annotation"), type])]; + }, + fqnOrRefTypePartCommon(path, print) { + const { children } = path.node; + const keywordKey = onlyDefinedKey(children, ["Identifier", "Super"]); + const keyword = call(path, print, keywordKey); + return children.typeArguments + ? [keyword, call(path, print, "typeArguments")] + : keyword; + }, + parenthesisExpression(path, print) { + var _a; + const expression = call(path, print, "expression"); + const ancestorName = (_a = path.getNode(14)) === null || _a === void 0 ? void 0 : _a.name; + const binaryExpression = path.getNode(8); + return ancestorName && + ["guard", "returnStatement"].includes(ancestorName) && + binaryExpression && + binaryExpression.name === "binaryExpression" && + Object.keys(binaryExpression.children).length === 1 + ? indentInParentheses(expression) + : ["(", indent(expression), ")"]; + }, + castExpression: printSingle, + primitiveCastExpression(path, print) { + return [ + "(", + call(path, print, "primitiveType"), + ") ", + call(path, print, "unaryExpression") + ]; + }, + referenceTypeCastExpression(path, print) { + const { children } = path.node; + const type = call(path, print, "referenceType"); + const cast = children.additionalBound + ? indentInParentheses(join(line, [type, ...map(path, print, "additionalBound")])) + : ["(", type, ")"]; + const expressionKey = onlyDefinedKey(children, [ + "lambdaExpression", + "unaryExpressionNotPlusMinus" + ]); + return [cast, " ", call(path, print, expressionKey)]; + }, + newExpression: printSingle, + unqualifiedClassInstanceCreationExpression(path, print) { + const { children } = path.node; + const expression = ["new "]; + if (children.typeArguments) { + expression.push(call(path, print, "typeArguments")); + } + expression.push(call(path, print, "classOrInterfaceTypeToInstantiate"), children.argumentList + ? group(["(", call(path, print, "argumentList"), ")"]) + : "()"); + if (children.classBody) { + expression.push(" ", call(path, print, "classBody")); + } + return expression; + }, + classOrInterfaceTypeToInstantiate(path, print) { + const { children } = path.node; + const type = children.annotation + ? flatMap(path, childPath => [ + print(childPath), + isNonTerminal(childPath.node) ? " " : "." + ], ["annotation", "Identifier"]) + : printName(path, print); + if (children.typeArgumentsOrDiamond) { + type.push(call(path, print, "typeArgumentsOrDiamond")); + } + return type; + }, + typeArgumentsOrDiamond: printSingle, + diamond() { + return "<>"; + }, + methodInvocationSuffix(path, print) { + return path.node.children.argumentList + ? group(["(", call(path, print, "argumentList"), ")"]) + : indentInParentheses(printDanglingComments(path), { shouldBreak: true }); + }, + argumentList(path, print) { + var _a, _b, _c, _d; + const expressions = path.node.children.expression; + const lastExpression = expressions.at(-1); + const lastExpressionLambdaBodyExpression = (_b = (_a = lastExpression.children.lambdaExpression) === null || _a === void 0 ? void 0 : _a[0].children.lambdaBody[0].children.expression) === null || _b === void 0 ? void 0 : _b[0].children; + const lastExpressionLambdaBodyTernaryExpression = (_c = lastExpressionLambdaBodyExpression === null || lastExpressionLambdaBodyExpression === void 0 ? void 0 : lastExpressionLambdaBodyExpression.conditionalExpression) === null || _c === void 0 ? void 0 : _c[0].children; + const isHuggable = !lastExpression.comments && + (!lastExpressionLambdaBodyExpression || + (lastExpressionLambdaBodyTernaryExpression === null || lastExpressionLambdaBodyTernaryExpression === void 0 ? void 0 : lastExpressionLambdaBodyTernaryExpression.QuestionMark) !== undefined || + ((_d = lastExpressionLambdaBodyTernaryExpression === null || lastExpressionLambdaBodyTernaryExpression === void 0 ? void 0 : lastExpressionLambdaBodyTernaryExpression.binaryExpression) === null || _d === void 0 ? void 0 : _d[0].children.unaryExpression.length) === 1) && + expressions.findIndex(({ children }) => children.lambdaExpression) === + expressions.length - 1; + const args = map(path, print, "expression"); + const allArgsExpandable = [ + indent([softline, ...join([",", line], args)]), + softline + ]; + if (!isHuggable || willBreak(args.at(-1)[0])) { + return allArgsExpandable; + } + const headArgs = args.slice(0, -1); + const huggedLastArg = path.call(argPath => print(argPath, { hug: true }), "children", "expression", args.length - 1); + const lastArgExpanded = join(", ", [ + ...headArgs, + group(huggedLastArg, { shouldBreak: true }) + ]); + if (willBreak(huggedLastArg)) { + return [ + breakParent, + conditionalGroup([lastArgExpanded, allArgsExpandable]) + ]; + } + return conditionalGroup([ + join(", ", [...headArgs, huggedLastArg]), + lastArgExpanded, + allArgsExpandable + ]); + }, + arrayCreationExpression(path, print) { + const { children } = path.node; + const typeKey = onlyDefinedKey(children, [ + "classOrInterfaceType", + "primitiveType" + ]); + const suffixKey = onlyDefinedKey(children, [ + "arrayCreationExpressionWithoutInitializerSuffix", + "arrayCreationWithInitializerSuffix" + ]); + return ["new ", call(path, print, typeKey), call(path, print, suffixKey)]; + }, + arrayCreationExpressionWithoutInitializerSuffix(path, print) { + const expressions = call(path, print, "dimExprs"); + return path.node.children.dims + ? [expressions, call(path, print, "dims")] + : expressions; + }, + arrayCreationWithInitializerSuffix(path, print) { + return [ + call(path, print, "dims"), + " ", + call(path, print, "arrayInitializer") + ]; + }, + dimExprs(path, print) { + return map(path, print, "dimExpr"); + }, + dimExpr(path, print) { + return join(" ", [ + ...map(path, print, "annotation"), + ["[", call(path, print, "expression"), "]"] + ]); + }, + classLiteralSuffix(path, print) { + const lSquares = map(path, print, "LSquare"); + const rSquares = map(path, print, "RSquare"); + return [ + ...lSquares.flatMap((lSquare, index) => [lSquare, rSquares[index]]), + ".class" + ]; + }, + arrayAccessSuffix(path, print) { + return ["[", call(path, print, "expression"), "]"]; + }, + methodReferenceSuffix(path, print) { + const { children } = path.node; + const reference = ["::"]; + if (children.typeArguments) { + reference.push(call(path, print, "typeArguments")); + } + reference.push(call(path, print, onlyDefinedKey(children, ["Identifier", "New"]))); + return reference; + }, + templateArgument: printSingle, + template: printSingle, + stringTemplate(path, print) { + return printTemplate(path, print, "StringTemplateBegin", "StringTemplateMid", "StringTemplateEnd"); + }, + textBlockTemplate(path, print) { + return printTemplate(path, print, "TextBlockTemplateBegin", "TextBlockTemplateMid", "TextBlockTemplateEnd"); + }, + embeddedExpression: printSingle, + pattern: printSingle, + typePattern: printSingle, + recordPattern(path, print) { + const patterns = path.node.children.componentPatternList + ? indentInParentheses(call(path, print, "componentPatternList")) + : "()"; + return [call(path, print, "referenceType"), patterns]; + }, + componentPatternList(path, print) { + return printList(path, print, "componentPattern"); + }, + componentPattern: printSingle, + matchAllPattern: printSingle, + guard(path, print) { + var _a; + const expression = call(path, print, "expression"); + const hasParentheses = ((_a = path.node.children.expression[0].children.conditionalExpression) === null || _a === void 0 ? void 0 : _a[0].children.binaryExpression[0].children.unaryExpression[0].children.primary[0].children.primaryPrefix[0].children.parenthesisExpression) !== + undefined; + return [ + "when ", + hasParentheses + ? expression + : group([ + ifBreak("("), + indent([softline, expression]), + softline, + ifBreak(")") + ]) + ]; + } +}; +function binary(operands, operators, { hasNonAssignmentOperators = false, isInList = false, isRoot = false, operatorPosition }) { + let levelOperator; + let levelPrecedence; + let level = []; + while (operators.length) { + const nextOperator = operators[0].image; + const nextPrecedence = getOperatorPrecedence(nextOperator); + if (levelPrecedence === undefined || nextPrecedence === levelPrecedence) { + const { image: operator, doc: operatorDoc } = operators.shift(); + level.push(operands.shift()); + if (levelOperator !== undefined && + needsParentheses(levelOperator, operator)) { + level = [["(", group(indent(level)), ")"]]; + } + const parts = [" ", operatorDoc, line]; + if (operatorPosition === "start" && !isAssignmentOperator(operator)) { + parts.reverse(); + } + level.push(parts); + levelOperator = operator; + levelPrecedence = nextPrecedence; + } + else if (nextPrecedence < levelPrecedence) { + if (!isRoot) { + break; + } + level.push(operands.shift()); + const content = group(indent(level)); + operands.unshift(levelOperator !== undefined && + needsParentheses(levelOperator, nextOperator) + ? ["(", content, ")"] + : content); + level = []; + levelOperator = undefined; + levelPrecedence = undefined; + } + else { + const content = binary(operands, operators, { operatorPosition }); + operands.unshift(levelOperator !== undefined && + needsParentheses(nextOperator, levelOperator) + ? ["(", indent(content), ")"] + : content); + } + } + level.push(operands.shift()); + if (!levelOperator || + (!isInList && + !isAssignmentOperator(levelOperator) && + levelOperator !== "instanceof")) { + return group(level); + } + if (!isRoot || hasNonAssignmentOperators) { + return group(indent(level)); + } + const groupId = Symbol("assignment"); + return group([ + level[0], + group(indent(level[1]), { id: groupId }), + indentIfBreak(level[2], { groupId }) + ]); +} +const precedencesByOperator = new Map([ + ["||"], + ["&&"], + ["|"], + ["^"], + ["&"], + ["==", "!="], + ["<", ">", "<=", ">=", "instanceof"], + ["<<", ">>", ">>>"], + ["+", "-"], + ["*", "/", "%"] +].flatMap((operators, index) => operators.map(operator => [operator, index]))); +function getOperatorPrecedence(operator) { + var _a; + return (_a = precedencesByOperator.get(operator)) !== null && _a !== void 0 ? _a : -1; +} +function needsParentheses(operator, parentOperator) { + return ((operator === "&&" && parentOperator === "||") || + (["|", "^", "&", "<<", ">>", ">>>"].includes(parentOperator) && + getOperatorPrecedence(operator) > + getOperatorPrecedence(parentOperator)) || + [operator, parentOperator].every(o => ["==", "!="].includes(o)) || + [operator, parentOperator].every(o => ["<<", ">>", ">>>"].includes(o)) || + (operator === "*" && parentOperator === "/") || + (operator === "/" && parentOperator === "*") || + (operator === "%" && ["+", "-", "*", "/"].includes(parentOperator)) || + (["*", "/"].includes(operator) && parentOperator === "%")); +} +const assignmentOperators = new Set([ + "=", + "*=", + "/=", + "%=", + "+=", + "-=", + "<<=", + ">>=", + ">>>=", + "&=", + "^=", + "|=" +]); +function isAssignmentOperator(operator) { + return assignmentOperators.has(operator); +} +function isCapitalizedIdentifier(fqnOrRefType) { + var _a, _b, _c; + const nextToLastIdentifier = (_c = (_b = [ + fqnOrRefType.fqnOrRefTypePartFirst[0], + ...((_a = fqnOrRefType.fqnOrRefTypePartRest) !== null && _a !== void 0 ? _a : []) + ].at(-2)) === null || _b === void 0 ? void 0 : _b.children.fqnOrRefTypePartCommon[0].children.Identifier) === null || _c === void 0 ? void 0 : _c[0].image; + return /^\p{Uppercase_Letter}/u.test(nextToLastIdentifier !== null && nextToLastIdentifier !== void 0 ? nextToLastIdentifier : ""); +} +function printTemplate(path, print, beginKey, midKey, endKey) { + const begin = call(path, ({ node }) => node.image, beginKey); + const mids = map(path, ({ node }) => node.image, midKey); + const end = call(path, ({ node }) => node.image, endKey); + const lines = [begin, ...mids, end].join("").split("\n").slice(1); + const baseIndent = findBaseIndent(lines); + const prefix = "\n" + " ".repeat(baseIndent); + const parts = [begin, ...mids, end].map(image => join(hardline, image.split(prefix))); + return indent([ + parts[0], + ...map(path, (expressionPath, index) => { + const expression = group([ + indent([softline, print(expressionPath), lineSuffixBoundary]), + softline + ]); + return index === 0 ? expression : [parts[index], expression]; + }, "embeddedExpression"), + parts.at(-1) + ]); +} diff --git a/frontend/src/utils/prettier/plugins/java/printers/helpers.d.ts b/frontend/src/utils/prettier/plugins/java/printers/helpers.d.ts new file mode 100644 index 0000000..c3eda0c --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/helpers.d.ts @@ -0,0 +1,71 @@ +import type { AnnotationCstNode, ClassPermitsCstNode, ClassTypeCtx, CstElement, CstNode, ExpressionCstNode, InterfacePermitsCstNode, IToken, StatementCstNode } from "java-parser"; +import type { AstPath, Doc, ParserOptions } from "prettier"; +import { builders } from "prettier/doc"; +import type { JavaComment } from "../comments.js"; +export declare function onlyDefinedKey, K extends Key & string>(obj: T, options?: K[]): K; +export declare function definedKeys, K extends Key & string>(obj: T, options?: K[]): K[]; +export declare function printWithModifiers>(path: AstPath, print: JavaPrintFn, modifierChild: P, contents: Doc, noTypeAnnotations?: boolean): builders.Doc[]; +export declare function hasDeclarationAnnotations(modifiers: ModifierNode[]): boolean; +export declare function call>(path: AstPath, callback: MapCallback, P>, U>, child: P): U; +export declare function each>(path: AstPath, callback: MapCallback, P>, void>, child: P): void; +export declare function map>(path: AstPath, callback: MapCallback, P>, U>, child: P): U[]; +export declare function flatMap>(path: AstPath, callback: MapCallback, P>, U>, children: P[]): U[]; +export declare function printSingle(path: AstPath, print: JavaPrintFn, _?: JavaParserOptions, args?: unknown): builders.Doc; +export declare function lineStartWithComments(node: JavaNonTerminal): number; +export declare function lineEndWithComments(node: JavaNonTerminal): number; +export declare function printDanglingComments(path: AstPath): builders.Doc[]; +export declare function printComment(node: JavaTerminal): string | builders.Doc[]; +export declare function hasLeadingComments(node: JavaNode): boolean | undefined; +export declare function indentInParentheses(contents: Doc, opts?: { + shouldBreak?: boolean; +}): builders.Group | "()"; +export declare function printArrayInitializer>(path: AstPath, print: JavaPrintFn, options: JavaParserOptions, child: P): builders.Group | "{}"; +export declare function printBlock(path: AstPath, contents: Doc[]): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[]; +export declare function printName(path: AstPath, print: JavaPrintFn): builders.Doc[]; +export declare function printList>(path: AstPath, print: JavaPrintFn, child: P): builders.Doc[]; +export declare function printClassPermits(path: AstPath, print: JavaPrintFn): builders.Group; +export declare function printClassType(path: AstPath, print: JavaPrintFn): builders.Doc[]; +export declare function isBinaryExpression(expression: ExpressionCstNode): boolean; +export declare function findBaseIndent(lines: string[]): number; +export declare function isEmptyStatement(statement: StatementCstNode): boolean; +export declare function isNonTerminal(node: CstElement): node is JavaNonTerminal; +export declare function isTerminal(node: CstElement): node is IToken; +export type JavaNode = CstElement & { + comments?: JavaComment[]; +}; +export type JavaNonTerminal = Exclude; +export type JavaTerminal = Exclude; +export type JavaNodePrinters = { + [T in JavaNonTerminal["name"]]: JavaNodePrinter; +}; +export type JavaNodePrinter = (path: AstPath>, print: JavaPrintFn, options: JavaParserOptions, args?: unknown) => Doc; +export type JavaPrintFn = (path: AstPath, args?: unknown) => Doc; +export type JavaParserOptions = ParserOptions & { + entrypoint?: string; +}; +export type IterProperties = T extends any[] ? IndexProperties : ArrayProperties; +type Key = T extends T ? keyof T : never; +type ModifierNode = JavaNonTerminal & { + children: { + annotation?: AnnotationCstNode[]; + }; +}; +type IsTuple = T extends [] ? true : T extends [infer First, ...infer Remain] ? IsTuple : false; +type IndexProperties = IsTuple extends true ? Exclude["length"], T["length"]> : number; +type ArrayProperties = { + [K in keyof T]: NonNullable extends readonly any[] ? K : never; +}[keyof T]; +type ArrayElement = T extends Array ? E : never; +type MapCallback = (path: AstPath>, index: number, value: any) => U; +type IndexValue = T extends any[] ? P extends number ? T[P] : never : P extends keyof T ? T[P] : never; +export {}; diff --git a/frontend/src/utils/prettier/plugins/java/printers/helpers.js b/frontend/src/utils/prettier/plugins/java/printers/helpers.js new file mode 100644 index 0000000..e0072c8 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/helpers.js @@ -0,0 +1,239 @@ +import { builders } from "prettier/doc"; +import parser from "../parser.js"; +const { group, hardline, ifBreak, indent, join, line, softline } = builders; +export function onlyDefinedKey(obj, options) { + const keys = definedKeys(obj, options); + if (keys.length === 1) { + return keys[0]; + } + throw new Error(keys.length > 1 + ? `More than one defined key found: ${keys}` + : "No defined keys found"); +} +export function definedKeys(obj, options) { + return (options !== null && options !== void 0 ? options : Object.keys(obj)).filter(key => obj[key] !== undefined); +} +const indexByModifier = [ + "public", + "protected", + "private", + "abstract", + "default", + "static", + "final", + "transient", + "volatile", + "synchronized", + "native", + "sealed", + "non-sealed", + "strictfp" +].reduce((map, name, index) => map.set(name, index), new Map()); +export function printWithModifiers(path, print, modifierChild, contents, noTypeAnnotations = false) { + const declarationAnnotations = []; + const otherModifiers = []; + const typeAnnotations = []; + each(path, modifierPath => { + const { children } = modifierPath.node; + const modifier = print(modifierPath); + if (children.annotation) { + (otherModifiers.length ? typeAnnotations : declarationAnnotations).push(modifier); + } + else { + otherModifiers.push(modifier); + declarationAnnotations.push(...typeAnnotations); + typeAnnotations.length = 0; + } + }, modifierChild); + if (noTypeAnnotations) { + declarationAnnotations.push(...typeAnnotations); + typeAnnotations.length = 0; + } + otherModifiers.sort((a, b) => indexByModifier.get(a) - indexByModifier.get(b)); + return join(hardline, [ + ...declarationAnnotations, + join(" ", [...otherModifiers, ...typeAnnotations, contents]) + ]); +} +export function hasDeclarationAnnotations(modifiers) { + let hasAnnotation = false; + let hasNonAnnotation = false; + for (const modifier of modifiers) { + if (modifier.children.annotation) { + hasAnnotation = true; + } + else if (hasAnnotation) { + return true; + } + else { + hasNonAnnotation = true; + } + } + return hasAnnotation && !hasNonAnnotation; +} +export function call(path, callback, child) { + return path.map(callback, "children", child)[0]; +} +export function each(path, callback, child) { + if (path.node.children[child]) { + path.each(callback, "children", child); + } +} +export function map(path, callback, child) { + return path.node.children[child] ? path.map(callback, "children", child) : []; +} +export function flatMap(path, callback, children) { + return children + .flatMap(child => map(path, callback, child).map((doc, index) => { + const node = path.node.children[child][index]; + return { + doc, + startOffset: parser.locStart(node) + }; + })) + .sort((a, b) => a.startOffset - b.startOffset) + .map(({ doc }) => doc); +} +export function printSingle(path, print, _, args) { + return call(path, childPath => print(childPath, args), onlyDefinedKey(path.node.children)); +} +export function lineStartWithComments(node) { + const { comments, location } = node; + return comments + ? Math.min(location.startLine, comments[0].startLine) + : location.startLine; +} +export function lineEndWithComments(node) { + const { comments, location } = node; + return comments + ? Math.max(location.endLine, comments.at(-1).endLine) + : location.endLine; +} +export function printDanglingComments(path) { + if (!path.node.comments) { + return []; + } + const comments = []; + 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); +} +export function printComment(node) { + const { image } = node; + const lines = image.split("\n").map(line => line.trim()); + return lines.length > 1 && + lines[0].startsWith("/*") && + lines.slice(1).every(line => line.startsWith("*")) && + lines.at(-1).endsWith("*/") + ? join(hardline, lines.map((line, index) => (index === 0 ? line : ` ${line}`))) + : image; +} +export function hasLeadingComments(node) { + var _a; + return (_a = node.comments) === null || _a === void 0 ? void 0 : _a.some(({ leading }) => leading); +} +export function indentInParentheses(contents, opts) { + return !Array.isArray(contents) || contents.length + ? group(["(", indent([softline, contents]), softline, ")"], opts) + : "()"; +} +export function printArrayInitializer(path, print, options, child) { + const list = []; + if (child && child in path.node.children) { + list.push(call(path, print, child)); + if (options.trailingComma !== "none") { + list.push(ifBreak(",")); + } + } + list.push(...printDanglingComments(path)); + return list.length ? group(["{", indent([line, ...list]), line, "}"]) : "{}"; +} +export function printBlock(path, contents) { + if (!contents.length) { + const danglingComments = printDanglingComments(path); + return danglingComments.length + ? ["{", indent([hardline, ...danglingComments]), hardline, "}"] + : "{}"; + } + return group([ + "{", + indent([hardline, ...join(hardline, contents)]), + hardline, + "}" + ]); +} +export function printName(path, print) { + return join(".", map(path, print, "Identifier")); +} +export function printList(path, print, child) { + return join([",", line], map(path, print, child)); +} +export function printClassPermits(path, print) { + return group([ + "permits", + indent([line, group(printList(path, print, "typeName"))]) + ]); +} +export function printClassType(path, print) { + const { children } = path.node; + return definedKeys(children, ["annotation", "Identifier", "typeArguments"]) + .flatMap(child => children[child].map((node, index) => ({ + child, + index, + startOffset: parser.locStart(node) + }))) + .sort((a, b) => a.startOffset - b.startOffset) + .flatMap(({ child, index: childIndex }, index, array) => { + const node = children[child][childIndex]; + const next = array.at(index + 1); + const nextNode = next && children[next.child][next.index]; + const docs = [path.call(print, "children", child, childIndex)]; + if (nextNode) { + if (isNonTerminal(node)) { + docs.push(node.name === "annotation" ? " " : "."); + } + else if (isTerminal(nextNode) || nextNode.name === "annotation") { + docs.push("."); + } + } + return docs; + }); +} +export function isBinaryExpression(expression) { + var _a; + const conditionalExpression = (_a = expression.children.conditionalExpression) === null || _a === void 0 ? void 0 : _a[0].children; + if (!conditionalExpression) { + return false; + } + const isTernary = conditionalExpression.QuestionMark !== undefined; + if (isTernary) { + return false; + } + const hasNonAssignmentOperators = Object.values(conditionalExpression.binaryExpression[0].children).some(child => { + var _a; + return isTerminal(child[0]) && + !((_a = child[0].tokenType.CATEGORIES) === null || _a === void 0 ? void 0 : _a.some(category => category.name === "AssignmentOperator")); + }); + return hasNonAssignmentOperators; +} +export function findBaseIndent(lines) { + return lines.length + ? Math.min(...lines.map(line => line.search(/\S/)).filter(indent => indent >= 0)) + : 0; +} +export function isEmptyStatement(statement) { + var _a; + return (((_a = statement.children.statementWithoutTrailingSubstatement) === null || _a === void 0 ? void 0 : _a[0].children.emptyStatement) !== undefined); +} +export function isNonTerminal(node) { + return !isTerminal(node); +} +export function isTerminal(node) { + return "tokenType" in node; +} diff --git a/frontend/src/utils/prettier/plugins/java/printers/index.d.ts b/frontend/src/utils/prettier/plugins/java/printers/index.d.ts new file mode 100644 index 0000000..569b54a --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/index.d.ts @@ -0,0 +1,2 @@ +import type { JavaNodePrinter, JavaNodePrinters } from "./helpers.js"; +export declare function printerForNodeType(type: T): JavaNodePrinter; diff --git a/frontend/src/utils/prettier/plugins/java/printers/index.js b/frontend/src/utils/prettier/plugins/java/printers/index.js new file mode 100644 index 0000000..e629424 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/index.js @@ -0,0 +1,13 @@ +import arrays from "./arrays.js"; +import blocksAndStatements from "./blocks-and-statements.js"; +import classes from "./classes.js"; +import expressions from "./expressions.js"; +import interfaces from "./interfaces.js"; +import lexicalStructure from "./lexical-structure.js"; +import names from "./names.js"; +import packagesAndModules from "./packages-and-modules.js"; +import typesValuesAndVariables from "./types-values-and-variables.js"; +const printersByNodeType = Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, arrays), blocksAndStatements), classes), expressions), interfaces), lexicalStructure), names), packagesAndModules), typesValuesAndVariables); +export function printerForNodeType(type) { + return printersByNodeType[type]; +} diff --git a/frontend/src/utils/prettier/plugins/java/printers/interfaces.d.ts b/frontend/src/utils/prettier/plugins/java/printers/interfaces.d.ts new file mode 100644 index 0000000..cb9025e --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/interfaces.d.ts @@ -0,0 +1,62 @@ +import { builders } from "prettier/doc"; +import { printClassPermits, printSingle } from "./helpers.js"; +declare const _default: { + interfaceDeclaration(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + normalInterfaceDeclaration(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + interfaceModifier: typeof printSingle; + interfaceExtends(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group; + interfacePermits: typeof printClassPermits; + interfaceBody(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[]; + interfaceMemberDeclaration(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc; + constantDeclaration(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + constantModifier: typeof printSingle; + interfaceMethodDeclaration(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + interfaceMethodModifier: typeof printSingle; + annotationInterfaceDeclaration(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + annotationInterfaceBody(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group | "{}" | (string | builders.Indent | builders.Hardline)[]; + annotationInterfaceMemberDeclaration(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc; + annotationInterfaceElementDeclaration(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + annotationInterfaceElementModifier: typeof printSingle; + defaultValue(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + annotation(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + elementValuePairList(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + elementValuePair(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + elementValue: typeof printSingle; + elementValueArrayInitializer(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn, options: import("./helpers.js").JavaParserOptions): builders.Group | "{}"; + elementValueList(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/printers/interfaces.js b/frontend/src/utils/prettier/plugins/java/printers/interfaces.js new file mode 100644 index 0000000..93a5109 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/interfaces.js @@ -0,0 +1,157 @@ +import { builders } from "prettier/doc"; +import { call, each, hasDeclarationAnnotations, indentInParentheses, lineEndWithComments, lineStartWithComments, onlyDefinedKey, printArrayInitializer, printBlock, printClassPermits, printList, printSingle, printWithModifiers } from "./helpers.js"; +const { group, hardline, indent, join, line } = builders; +export default { + interfaceDeclaration(path, print) { + const declarationKey = onlyDefinedKey(path.node.children, [ + "annotationInterfaceDeclaration", + "normalInterfaceDeclaration" + ]); + return printWithModifiers(path, print, "interfaceModifier", call(path, print, declarationKey), true); + }, + normalInterfaceDeclaration(path, print) { + const { interfaceExtends, interfacePermits, typeParameters } = path.node.children; + const header = ["interface ", call(path, print, "typeIdentifier")]; + if (typeParameters) { + header.push(call(path, print, "typeParameters")); + } + if (interfaceExtends) { + header.push(indent([line, call(path, print, "interfaceExtends")])); + } + if (interfacePermits) { + header.push(indent([line, call(path, print, "interfacePermits")])); + } + return [group(header), " ", call(path, print, "interfaceBody")]; + }, + interfaceModifier: printSingle, + interfaceExtends(path, print) { + return group([ + "extends", + indent([line, call(path, print, "interfaceTypeList")]) + ]); + }, + interfacePermits: printClassPermits, + interfaceBody(path, print) { + const declarations = []; + let previousRequiresPadding = false; + each(path, declarationPath => { + var _a, _b, _c, _d; + const declaration = print(declarationPath); + if (declaration === "") { + return; + } + const { node, previous } = declarationPath; + const constantDeclaration = (_a = node.children.constantDeclaration) === null || _a === void 0 ? void 0 : _a[0].children; + const methodDeclaration = (_b = node.children.interfaceMethodDeclaration) === null || _b === void 0 ? void 0 : _b[0].children; + const currentRequiresPadding = (!constantDeclaration && !methodDeclaration) || + (methodDeclaration === null || methodDeclaration === void 0 ? void 0 : methodDeclaration.methodBody[0].children.block) !== undefined || + hasDeclarationAnnotations((_d = (_c = constantDeclaration === null || constantDeclaration === void 0 ? void 0 : constantDeclaration.constantModifier) !== null && _c !== void 0 ? _c : methodDeclaration === null || methodDeclaration === void 0 ? void 0 : methodDeclaration.interfaceMethodModifier) !== null && _d !== void 0 ? _d : []); + const blankLine = declarations.length > 0 && + (previousRequiresPadding || + currentRequiresPadding || + lineStartWithComments(node) > lineEndWithComments(previous) + 1); + declarations.push(blankLine ? [hardline, declaration] : declaration); + previousRequiresPadding = currentRequiresPadding; + }, "interfaceMemberDeclaration"); + return printBlock(path, declarations); + }, + interfaceMemberDeclaration(path, print) { + const { children } = path.node; + return children.Semicolon + ? "" + : call(path, print, onlyDefinedKey(children)); + }, + constantDeclaration(path, print) { + const declaration = [ + call(path, print, "unannType"), + " ", + call(path, print, "variableDeclaratorList"), + ";" + ]; + return printWithModifiers(path, print, "constantModifier", declaration); + }, + constantModifier: printSingle, + interfaceMethodDeclaration(path, print) { + const declaration = [ + call(path, print, "methodHeader"), + path.node.children.methodBody[0].children.Semicolon ? "" : " ", + call(path, print, "methodBody") + ]; + return printWithModifiers(path, print, "interfaceMethodModifier", declaration); + }, + interfaceMethodModifier: printSingle, + annotationInterfaceDeclaration(path, print) { + return join(" ", [ + "@interface", + call(path, print, "typeIdentifier"), + call(path, print, "annotationInterfaceBody") + ]); + }, + annotationInterfaceBody(path, print) { + const declarations = []; + each(path, declarationPath => { + const declaration = print(declarationPath); + if (declaration === "") { + return; + } + declarations.push(declarationPath.isFirst ? declaration : [hardline, declaration]); + }, "annotationInterfaceMemberDeclaration"); + return printBlock(path, declarations); + }, + annotationInterfaceMemberDeclaration(path, print) { + const { children } = path.node; + return children.Semicolon + ? "" + : call(path, print, onlyDefinedKey(children)); + }, + annotationInterfaceElementDeclaration(path, print) { + const { dims, defaultValue } = path.node.children; + const declaration = [ + call(path, print, "unannType"), + " ", + call(path, print, "Identifier"), + "()" + ]; + if (dims) { + declaration.push(call(path, print, "dims")); + } + if (defaultValue) { + declaration.push(" ", call(path, print, "defaultValue")); + } + declaration.push(";"); + return printWithModifiers(path, print, "annotationInterfaceElementModifier", declaration); + }, + annotationInterfaceElementModifier: printSingle, + defaultValue(path, print) { + return ["default ", call(path, print, "elementValue")]; + }, + annotation(path, print) { + const { children } = path.node; + const annotation = ["@", call(path, print, "typeName")]; + if (children.elementValue || children.elementValuePairList) { + const valuesKey = onlyDefinedKey(children, [ + "elementValue", + "elementValuePairList" + ]); + annotation.push(indentInParentheses(call(path, print, valuesKey))); + } + return annotation; + }, + elementValuePairList(path, print) { + return printList(path, print, "elementValuePair"); + }, + elementValuePair(path, print) { + return join(" ", [ + call(path, print, "Identifier"), + call(path, print, "Equals"), + call(path, print, "elementValue") + ]); + }, + elementValue: printSingle, + elementValueArrayInitializer(path, print, options) { + return printArrayInitializer(path, print, options, "elementValueList"); + }, + elementValueList(path, print) { + return group(printList(path, print, "elementValue")); + } +}; diff --git a/frontend/src/utils/prettier/plugins/java/printers/lexical-structure.d.ts b/frontend/src/utils/prettier/plugins/java/printers/lexical-structure.d.ts new file mode 100644 index 0000000..a63a9e2 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/lexical-structure.d.ts @@ -0,0 +1,14 @@ +import { builders } from "prettier/doc"; +import { printSingle } from "./helpers.js"; +declare const _default: { + literal(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc; + integerLiteral: typeof printSingle; + floatingPointLiteral: typeof printSingle; + booleanLiteral: typeof printSingle; + shiftOperator(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/printers/lexical-structure.js b/frontend/src/utils/prettier/plugins/java/printers/lexical-structure.js new file mode 100644 index 0000000..d94cfd5 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/lexical-structure.js @@ -0,0 +1,29 @@ +import { builders } from "prettier/doc"; +import { findBaseIndent, map, onlyDefinedKey, printSingle } from "./helpers.js"; +const { hardline, indent, join } = builders; +export default { + literal(path, print) { + const { TextBlock } = path.node.children; + if (!TextBlock) { + return printSingle(path, print); + } + const [open, ...lines] = TextBlock[0].image.split("\n"); + const baseIndent = findBaseIndent(lines); + const textBlock = join(hardline, [ + open, + ...lines.map(line => line.slice(baseIndent)) + ]); + const ancestor = path.getNode(14); + return (ancestor === null || ancestor === void 0 ? void 0 : ancestor.name) === "variableInitializer" || + ((ancestor === null || ancestor === void 0 ? void 0 : ancestor.name) === "binaryExpression" && + ancestor.children.AssignmentOperator) + ? indent(textBlock) + : textBlock; + }, + integerLiteral: printSingle, + floatingPointLiteral: printSingle, + booleanLiteral: printSingle, + shiftOperator(path, print) { + return map(path, print, onlyDefinedKey(path.node.children)); + } +}; diff --git a/frontend/src/utils/prettier/plugins/java/printers/names.d.ts b/frontend/src/utils/prettier/plugins/java/printers/names.d.ts new file mode 100644 index 0000000..18ad1e8 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/names.d.ts @@ -0,0 +1,12 @@ +import { printName, printSingle } from "./helpers.js"; +declare const _default: { + typeIdentifier: typeof printSingle; + moduleName: typeof printName; + packageName: typeof printName; + typeName: typeof printName; + expressionName: typeof printName; + methodName: typeof printSingle; + packageOrTypeName: typeof printName; + ambiguousName: typeof printName; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/printers/names.js b/frontend/src/utils/prettier/plugins/java/printers/names.js new file mode 100644 index 0000000..3dfec2f --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/names.js @@ -0,0 +1,11 @@ +import { printName, printSingle } from "./helpers.js"; +export default { + typeIdentifier: printSingle, + moduleName: printName, + packageName: printName, + typeName: printName, + expressionName: printName, + methodName: printSingle, + packageOrTypeName: printName, + ambiguousName: printName +}; diff --git a/frontend/src/utils/prettier/plugins/java/printers/packages-and-modules.d.ts b/frontend/src/utils/prettier/plugins/java/printers/packages-and-modules.d.ts new file mode 100644 index 0000000..c35219e --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/packages-and-modules.d.ts @@ -0,0 +1,46 @@ +import type { ExportsModuleDirectiveCstNode, ImportDeclarationCstNode, OpensModuleDirectiveCstNode } from "java-parser"; +import type { AstPath } from "prettier"; +import { builders } from "prettier/doc"; +import { printSingle, type JavaPrintFn } from "./helpers.js"; +declare const _default: { + compilationUnit(path: AstPath, print: JavaPrintFn): builders.Doc[]; + ordinaryCompilationUnit(path: AstPath, print: JavaPrintFn): builders.Doc[]; + modularCompilationUnit(path: AstPath, print: JavaPrintFn): builders.Doc[]; + packageDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; + packageModifier: typeof printSingle; + importDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc; + typeDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc; + moduleDeclaration(path: AstPath, print: JavaPrintFn): builders.Doc[]; + moduleDirective: typeof printSingle; + requiresModuleDirective(path: AstPath, print: JavaPrintFn): builders.Doc[]; + exportsModuleDirective(path: AstPath, print: JavaPrintFn): builders.Doc[]; + opensModuleDirective(path: AstPath, print: JavaPrintFn): builders.Doc[]; + usesModuleDirective(path: AstPath, print: JavaPrintFn): builders.Doc[]; + providesModuleDirective(path: AstPath, print: JavaPrintFn): builders.Doc[]; + requiresModifier: typeof printSingle; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/printers/packages-and-modules.js b/frontend/src/utils/prettier/plugins/java/printers/packages-and-modules.js new file mode 100644 index 0000000..e1a98c0 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/packages-and-modules.js @@ -0,0 +1,169 @@ +import { builders } from "prettier/doc"; +import { call, lineEndWithComments, lineStartWithComments, map, printBlock, printDanglingComments, printName, printSingle } from "./helpers.js"; +const { group, hardline, indent, join, line } = builders; +export default { + compilationUnit(path, print) { + return [...printDanglingComments(path), printSingle(path, print), hardline]; + }, + ordinaryCompilationUnit(path, print) { + const { children } = path.node; + const declarations = []; + if (children.packageDeclaration) { + declarations.push(call(path, print, "packageDeclaration")); + } + if (children.importDeclaration) { + const staticCount = sortImports(children.importDeclaration); + const importDeclarations = map(path, print, "importDeclaration").filter(doc => doc !== ""); + const staticDeclarations = importDeclarations.slice(0, staticCount); + const nonStaticDeclarations = importDeclarations.slice(staticCount); + declarations.push(...[staticDeclarations, nonStaticDeclarations] + .filter(({ length }) => length) + .map(declarations => join(hardline, declarations))); + } + if (children.typeDeclaration) { + declarations.push(...map(path, print, "typeDeclaration").filter(declaration => declaration !== "")); + } + return join([hardline, hardline], declarations); + }, + modularCompilationUnit(path, print) { + const { children } = path.node; + const declarations = []; + if (children.importDeclaration) { + const staticCount = sortImports(children.importDeclaration); + const importDeclarations = map(path, print, "importDeclaration").filter(doc => doc !== ""); + const staticDeclarations = importDeclarations.slice(0, staticCount); + const nonStaticDeclarations = importDeclarations.slice(staticCount); + declarations.push(...[staticDeclarations, nonStaticDeclarations] + .filter(({ length }) => length) + .map(declarations => join(hardline, declarations))); + } + declarations.push(call(path, print, "moduleDeclaration")); + return join([hardline, hardline], declarations); + }, + packageDeclaration(path, print) { + return join(hardline, [ + ...map(path, print, "packageModifier"), + ["package ", printName(path, print), ";"] + ]); + }, + packageModifier: printSingle, + importDeclaration(path, print) { + const { children } = path.node; + if (children.emptyStatement) { + return call(path, print, "emptyStatement"); + } + const declaration = ["import "]; + if (children.Static) { + declaration.push("static "); + } + declaration.push(call(path, print, "packageOrTypeName")); + if (children.Star) { + declaration.push(".*"); + } + declaration.push(";"); + return declaration; + }, + typeDeclaration(path, print) { + return path.node.children.Semicolon ? "" : printSingle(path, print); + }, + moduleDeclaration(path, print) { + const { annotation, Open } = path.node.children; + const prefix = []; + if (annotation) { + prefix.push(...map(path, print, "annotation")); + } + if (Open) { + prefix.push("open"); + } + const declarations = map(path, declarationPath => { + const declaration = print(declarationPath); + const { node, previous } = declarationPath; + return !previous || + lineStartWithComments(node) <= lineEndWithComments(previous) + 1 + ? declaration + : [hardline, declaration]; + }, "moduleDirective"); + return join(" ", [ + ...prefix, + "module", + printName(path, print), + printBlock(path, declarations) + ]); + }, + moduleDirective: printSingle, + requiresModuleDirective(path, print) { + return join(" ", [ + "requires", + ...map(path, print, "requiresModifier"), + [call(path, print, "moduleName"), ";"] + ]); + }, + exportsModuleDirective(path, print) { + return printToModuleNamesDirective(path, print, "exports"); + }, + opensModuleDirective(path, print) { + return printToModuleNamesDirective(path, print, "opens"); + }, + usesModuleDirective(path, print) { + return ["uses ", call(path, print, "typeName"), ";"]; + }, + providesModuleDirective(path, print) { + const [firstTypeName, ...restTypeNames] = map(path, print, "typeName"); + return [ + "provides ", + firstTypeName, + group(indent([ + line, + group(indent(["with", line, ...join([",", line], restTypeNames)])) + ])), + ";" + ]; + }, + requiresModifier: printSingle +}; +function sortImports(importDeclarations) { + importDeclarations.sort(({ children: a }, { children: b }) => { + if (a.Static && !b.Static) { + return -1; + } + else if (b.Static && !a.Static) { + return 1; + } + if (!b.packageOrTypeName) { + if (a.packageOrTypeName) { + return -1; + } + return 0; + } + else if (!a.packageOrTypeName) { + return 1; + } + return compareFqn(a.packageOrTypeName[0], b.packageOrTypeName[0]); + }); + return importDeclarations.reduce((staticCount, importDeclaration) => importDeclaration.children.Static ? staticCount + 1 : staticCount, 0); +} +function compareFqn(a, b) { + const identifiersA = a.children.Identifier; + const identifiersB = b.children.Identifier; + const minParts = Math.min(identifiersA.length, identifiersB.length); + for (let i = 0; i < minParts; i++) { + const imageA = identifiersA[i].image; + const imageB = identifiersB[i].image; + if (imageA < imageB) { + return -1; + } + else if (imageA > imageB) { + return 1; + } + } + return identifiersA.length - identifiersB.length; +} +function printToModuleNamesDirective(path, print, prefix) { + const directive = [prefix, " ", call(path, print, "packageName")]; + if (path.node.children.moduleName) { + const moduleNames = join([",", line], map(path, print, "moduleName")); + directive.push(group(indent([line, group(indent(["to", line, ...moduleNames]))]))); + } + directive.push(";"); + return directive; +} diff --git a/frontend/src/utils/prettier/plugins/java/printers/types-values-and-variables.d.ts b/frontend/src/utils/prettier/plugins/java/printers/types-values-and-variables.d.ts new file mode 100644 index 0000000..776c47b --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/types-values-and-variables.d.ts @@ -0,0 +1,46 @@ +import { builders } from "prettier/doc"; +import { printClassType, printSingle } from "./helpers.js"; +declare const _default: { + primitiveType(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + numericType: typeof printSingle; + integralType: typeof printSingle; + floatingPointType: typeof printSingle; + referenceType(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + classOrInterfaceType: typeof printSingle; + classType: typeof printClassType; + interfaceType: typeof printSingle; + typeVariable(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + dims(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + typeParameter(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + typeParameterModifier: typeof printSingle; + typeBound(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + additionalBound(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + typeArguments(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Group; + typeArgumentList(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + typeArgument: typeof printSingle; + wildcard(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; + wildcardBounds(path: import("prettier").AstPath, print: import("./helpers.js").JavaPrintFn): builders.Doc[]; +}; +export default _default; diff --git a/frontend/src/utils/prettier/plugins/java/printers/types-values-and-variables.js b/frontend/src/utils/prettier/plugins/java/printers/types-values-and-variables.js new file mode 100644 index 0000000..3738ac5 --- /dev/null +++ b/frontend/src/utils/prettier/plugins/java/printers/types-values-and-variables.js @@ -0,0 +1,90 @@ +import { builders } from "prettier/doc"; +import { call, definedKeys, flatMap, isNonTerminal, map, onlyDefinedKey, printClassType, printList, printSingle } from "./helpers.js"; +const { group, indent, join, line, softline } = builders; +export default { + primitiveType(path, print) { + const { children } = path.node; + const typeKey = onlyDefinedKey(children, ["Boolean", "numericType"]); + return join(" ", [ + ...map(path, print, "annotation"), + call(path, print, typeKey) + ]); + }, + numericType: printSingle, + integralType: printSingle, + floatingPointType: printSingle, + referenceType(path, print) { + const { children } = path.node; + const typeKey = onlyDefinedKey(children, [ + "primitiveType", + "classOrInterfaceType" + ]); + const type = call(path, print, typeKey); + return join(" ", [ + ...map(path, print, "annotation"), + children.dims ? [type, call(path, print, "dims")] : type + ]); + }, + classOrInterfaceType: printSingle, + classType: printClassType, + interfaceType: printSingle, + typeVariable(path, print) { + return join(" ", [ + ...map(path, print, "annotation"), + call(path, print, "Identifier") + ]); + }, + dims(path, print) { + return flatMap(path, childPath => { + const child = print(childPath); + return isNonTerminal(childPath.node) ? [child, " "] : child; + }, definedKeys(path.node.children, ["annotation", "LSquare", "RSquare"])); + }, + typeParameter(path, print) { + const parameter = [ + ...map(path, print, "typeParameterModifier"), + call(path, print, "typeIdentifier") + ]; + if (path.node.children.typeBound) { + parameter.push(call(path, print, "typeBound")); + } + return join(" ", parameter); + }, + typeParameterModifier: printSingle, + typeBound(path, print) { + const bound = ["extends ", call(path, print, "classOrInterfaceType")]; + if (path.node.children.additionalBound) { + bound.push(group(indent([line, ...join(line, map(path, print, "additionalBound"))]))); + } + return bound; + }, + additionalBound(path, print) { + return ["& ", call(path, print, "interfaceType")]; + }, + typeArguments(path, print) { + return group([ + "<", + indent([softline, call(path, print, "typeArgumentList")]), + softline, + ">" + ]); + }, + typeArgumentList(path, print) { + return printList(path, print, "typeArgument"); + }, + typeArgument: printSingle, + wildcard(path, print) { + const wildcard = [...map(path, print, "annotation"), "?"]; + if (path.node.children.wildcardBounds) { + wildcard.push(call(path, print, "wildcardBounds")); + } + return join(" ", wildcard); + }, + wildcardBounds(path, print) { + return [ + path.node.children.Extends ? "extends" : "super", + " ", + call(path, print, "referenceType") + ]; + } +}; diff --git a/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts b/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts index 5b6922e..44aa189 100644 --- a/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts +++ b/frontend/src/views/editor/extensions/codeblock/lang-parser/languages.ts @@ -39,6 +39,7 @@ import yamlPrettierPlugin from "prettier/plugins/yaml" import goPrettierPlugin from "@/utils/prettier/plugins/go/go" import sqlPrettierPlugin from "@/utils/prettier/plugins/sql/sql" import phpPrettierPlugin from "@/utils/prettier/plugins/php" +import javaPrettierPlugin from "@/utils/prettier/plugins/java" import * as prettierPluginEstree from "prettier/plugins/estree"; /** @@ -78,7 +79,10 @@ export const LANGUAGES: LanguageInfo[] = [ parser: "markdown", plugins: [markdownPrettierPlugin] }), - new LanguageInfo("java", "Java", javaLanguage.parser), + new LanguageInfo("java", "Java", javaLanguage.parser,{ + parser: "java", + plugins: [javaPrettierPlugin] + }), new LanguageInfo("php", "PHP", phpLanguage.configure({top: "Program"}).parser, { parser: "php", plugins: [phpPrettierPlugin]