@prettier/plugin-ruby
Version:
prettier plugin for the Ruby programming language
86 lines (74 loc) • 2.48 kB
JavaScript
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" ||
stmts[0].comments
) {
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[0].type === "void_stmt" &&
stmts[0].comments
) {
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
};