UNPKG

prettierx

Version:

prettierX - a less opinionated fork of the Prettier code formatter

212 lines (185 loc) 5.44 kB
"use strict"; /** @typedef {import("../../document").Doc} Doc */ const { builders: { conditionalGroup, group, hardline, ifBreak, join, line }, } = require("../../document"); const { hasLeadingComments, hasMiddleComments, hasTrailingComment, hasEndComments, isNode, isEmptyNode, isInlineNode, } = require("../utils"); const { alignWithSpaces } = require("./misc"); function printMappingItem(node, parentNode, path, print, options) { const { key, value } = node; const isEmptyMappingKey = isEmptyNode(key); const isEmptyMappingValue = isEmptyNode(value); if (isEmptyMappingKey && isEmptyMappingValue) { return ": "; } const printedKey = print("key"); const spaceBeforeColon = needsSpaceInFrontOfMappingValue(node) ? " " : ""; if (isEmptyMappingValue) { if (node.type === "flowMappingItem" && parentNode.type === "flowMapping") { return printedKey; } if ( node.type === "mappingItem" && isAbsolutelyPrintedAsSingleLineNode(key.content, options) && !hasTrailingComment(key.content) && (!parentNode.tag || parentNode.tag.value !== "tag:yaml.org,2002:set") ) { return [printedKey, spaceBeforeColon, ":"]; } return ["? ", alignWithSpaces(2, printedKey)]; } const printedValue = print("value"); if (isEmptyMappingKey) { return [": ", alignWithSpaces(2, printedValue)]; } // force explicit Key if (hasLeadingComments(value) || !isInlineNode(key.content)) { return [ "? ", alignWithSpaces(2, printedKey), hardline, join( "", path .map(print, "value", "leadingComments") .map((comment) => [comment, hardline]) ), ": ", alignWithSpaces(2, printedValue), ]; } // force singleline if ( isSingleLineNode(key.content) && !hasLeadingComments(key.content) && !hasMiddleComments(key.content) && !hasTrailingComment(key.content) && !hasEndComments(key) && !hasLeadingComments(value.content) && !hasMiddleComments(value.content) && !hasEndComments(value) && isAbsolutelyPrintedAsSingleLineNode(value.content, options) ) { return [printedKey, spaceBeforeColon, ": ", printedValue]; } const groupId = Symbol("mappingKey"); const groupedKey = group([ ifBreak("? "), group(alignWithSpaces(2, printedKey), { id: groupId }), ]); // Construct both explicit and implicit mapping values. const explicitMappingValue = [ hardline, ": ", alignWithSpaces(2, printedValue), ]; /** @type {Doc[]} */ // In the implicit case, it's convenient to treat everything from the key's colon // as part of the mapping value const implicitMappingValueParts = [spaceBeforeColon, ":"]; if ( hasLeadingComments(value.content) || (hasEndComments(value) && value.content && !isNode(value.content, ["mapping", "sequence"])) || (parentNode.type === "mapping" && hasTrailingComment(key.content) && isInlineNode(value.content)) || (isNode(value.content, ["mapping", "sequence"]) && value.content.tag === null && value.content.anchor === null) ) { implicitMappingValueParts.push(hardline); } else if (value.content) { implicitMappingValueParts.push(line); } implicitMappingValueParts.push(printedValue); const implicitMappingValue = alignWithSpaces( options.tabWidth, implicitMappingValueParts ); // If a key is definitely single-line, forcibly use implicit style to avoid edge cases (very long // keys) that would otherwise trigger explicit style as if it was multiline. // In those cases, explicit style makes the line even longer and causes confusion. if ( isAbsolutelyPrintedAsSingleLineNode(key.content, options) && !hasLeadingComments(key.content) && !hasMiddleComments(key.content) && !hasEndComments(key) ) { return conditionalGroup([[printedKey, implicitMappingValue]]); } // Use explicit mapping syntax if the key breaks, implicit otherwise return conditionalGroup([ [ groupedKey, ifBreak(explicitMappingValue, implicitMappingValue, { groupId }), ], ]); } function isAbsolutelyPrintedAsSingleLineNode(node, options) { if (!node) { return true; } switch (node.type) { case "plain": case "quoteSingle": case "quoteDouble": break; case "alias": return true; default: return false; } if (options.proseWrap === "preserve") { return node.position.start.line === node.position.end.line; } if ( // backslash-newline /\\$/m.test( options.originalText.slice( node.position.start.offset, node.position.end.offset ) ) ) { return false; } switch (options.proseWrap) { case "never": return !node.value.includes("\n"); case "always": return !/[\n ]/.test(node.value); // istanbul ignore next default: return false; } } function needsSpaceInFrontOfMappingValue(node) { return node.key.content && node.key.content.type === "alias"; } function isSingleLineNode(node) { /* istanbul ignore next */ if (!node) { return true; } switch (node.type) { case "plain": case "quoteDouble": case "quoteSingle": return node.position.start.line === node.position.end.line; case "alias": return true; default: return false; } } module.exports = printMappingItem;