const { breakParent, concat, group, ifBreak, indent, join, removeLines, softline } = require("../prettier"); const { empty, hasAncestor } = require("../utils"); const printBlock = (braces) => (path, opts, print) => { const [variables, statements] = path.getValue().body; const stmts = statements.type === "stmts" ? statements.body : statements.body[0].body; let doBlockBody = ""; if (stmts.length !== 1 || stmts[0].type !== "void_stmt") { doBlockBody = indent(concat([softline, path.call(print, "body", 1)])); } // If this block is nested underneath a command or command_call node, then we // can't use `do...end` because that will get associated with the parent node // as opposed to the current node (because of the difference in operator // precedence). Instead, we still use a multi-line format but switch to using // braces instead. const useBraces = braces && hasAncestor(path, ["command", "command_call"]); const doBlock = concat([ useBraces ? " {" : " do", variables ? concat([" ", path.call(print, "body", 0)]) : "", doBlockBody, concat([softline, useBraces ? "}" : "end"]) ]); // We can hit this next pattern if within the block the only statement is a // comment. if ( stmts.length > 1 && stmts.filter((stmt) => stmt.type !== "@comment").length === 1 ) { return concat([breakParent, doBlock]); } // If the parent node is a command node, then there are no parentheses around // the arguments to that command, so we need to break the block if (["command", "command_call"].includes(path.getParentNode().body[0].type)) { return concat([breakParent, doBlock]); } const hasBody = stmts.some(({ type }) => type !== "void_stmt"); const braceBlock = concat([ " {", hasBody || variables ? " " : "", variables ? path.call(print, "body", 0) : "", path.call(print, "body", 1), hasBody ? " " : "", "}" ]); return group(ifBreak(doBlock, braceBlock)); }; module.exports = { block_var: (path, opts, print) => { const parts = ["|", removeLines(path.call(print, "body", 0))]; // The second part of this node is a list of optional block-local variables if (path.getValue().body[1]) { parts.push("; ", join(", ", path.map(print, "body", 1))); } parts.push("| "); return concat(parts); }, brace_block: printBlock(true), do_block: printBlock(false), excessed_comma: empty };