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 };