Refactor yaml (#9629)

This commit is contained in:
fisker Cheung authored and GitHub committed 2020-12-17 10:39:02 +08:00
1 parent cf8cba363f
commit 45407d82b9
7 files changed
+667 -531

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
"use strict";
const { defineShortcut, mapNode } = require("./utils");
function preprocess(ast) {
return mapNode(ast, defineShortcuts);
}
function defineShortcuts(node) {
switch (node.type) {
case "document":
defineShortcut(node, "head", () => node.children[0]);
defineShortcut(node, "body", () => node.children[1]);
break;
case "documentBody":
case "sequenceItem":
case "flowSequenceItem":
case "mappingKey":
case "mappingValue":
defineShortcut(node, "content", () => node.children[0]);
break;
case "mappingItem":
case "flowMappingItem":
defineShortcut(node, "key", () => node.children[0]);
defineShortcut(node, "value", () => node.children[1]);
break;
}
return node;
}
module.exports = preprocess;
+84
View File
@@ -0,0 +1,84 @@
"use strict";
/** @typedef {import("../../document").Doc} Doc */
const {
builders: {
concat,
dedent,
dedentToRoot,
fill,
hardline,
join,
line,
literalline,
markAsRoot,
},
} = require("../../document");
const {
getAncestorCount,
getBlockValueLineContents,
hasIndicatorComment,
isLastDescendantNode,
isNode,
} = require("../utils");
const { alignWithSpaces } = require("./misc");
function printBlock(path, print, options) {
const node = path.getValue();
const parentIndent = getAncestorCount(path, (ancestorNode) =>
isNode(ancestorNode, ["sequence", "mapping"])
);
const isLastDescendant = isLastDescendantNode(path);
/** @type {Doc[]} */
const parts = [node.type === "blockFolded" ? ">" : "|"];
if (node.indent !== null) {
parts.push(node.indent.toString());
}
if (node.chomping !== "clip") {
parts.push(node.chomping === "keep" ? "+" : "-");
}
if (hasIndicatorComment(node)) {
parts.push(" ", path.call(print, "indicatorComment"));
}
const lineContents = getBlockValueLineContents(node, {
parentIndent,
isLastDescendant,
options,
});
/** @type {Doc[]} */
const contentsParts = [];
for (const [index, lineWords] of lineContents.entries()) {
if (index === 0) {
contentsParts.push(hardline);
}
contentsParts.push(fill(join(line, lineWords).parts));
if (index !== lineContents.length - 1) {
contentsParts.push(
lineWords.length === 0 ? hardline : markAsRoot(literalline)
);
} else if (node.chomping === "keep" && isLastDescendant) {
contentsParts.push(
dedentToRoot(lineWords.length === 0 ? hardline : literalline)
);
}
}
if (node.indent === null) {
parts.push(
dedent(alignWithSpaces(options.tabWidth, concat(contentsParts)))
);
} else {
parts.push(
dedentToRoot(
alignWithSpaces(node.indent - 1 + parentIndent, concat(contentsParts))
)
);
}
return concat(parts);
}
module.exports = printBlock;
@@ -0,0 +1,71 @@
"use strict";
const {
builders: { concat, ifBreak, line, softline, hardline, join },
} = require("../../document");
const { isEmptyNode, getLast, hasEndComments } = require("../utils");
const { printNextEmptyLine, alignWithSpaces } = require("./misc");
function printFlowMapping(path, print, options) {
const node = path.getValue();
const isMapping = node.type === "flowMapping";
const openMarker = isMapping ? "{" : "[";
const closeMarker = isMapping ? "}" : "]";
/** @type {softline | line} */
let bracketSpacing = softline;
if (isMapping && node.children.length !== 0 && options.bracketSpacing) {
bracketSpacing = line;
}
const lastItem = getLast(node.children);
const isLastItemEmptyMappingItem =
lastItem &&
lastItem.type === "flowMappingItem" &&
isEmptyNode(lastItem.key) &&
isEmptyNode(lastItem.value);
return concat([
openMarker,
alignWithSpaces(
options.tabWidth,
concat([
bracketSpacing,
printChildren(path, print, options),
options.trailingComma === "none" ? "" : ifBreak(",", ""),
hasEndComments(node)
? concat([hardline, join(hardline, path.map(print, "endComments"))])
: "",
])
),
isLastItemEmptyMappingItem ? "" : bracketSpacing,
closeMarker,
]);
}
function printChildren(path, print, options) {
const node = path.getValue();
const parts = path.map(
(childPath, index) =>
concat([
print(childPath),
index === node.children.length - 1
? ""
: concat([
",",
line,
node.children[index].position.start.line !==
node.children[index + 1].position.start.line
? printNextEmptyLine(childPath, options.originalText)
: "",
]),
]),
"children"
);
return concat(parts);
}
module.exports = {
printFlowMapping,
// Alias
printFlowSequence: printFlowMapping,
};
+185
View File
@@ -0,0 +1,185 @@
"use strict";
/** @typedef {import("../../document").Doc} Doc */
const {
builders: { conditionalGroup, concat, 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 concat([": "]);
}
const printedKey = path.call(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 concat([printedKey, spaceBeforeColon, ":"]);
}
return concat(["? ", alignWithSpaces(2, printedKey)]);
}
const printedValue = path.call(print, "value");
if (isEmptyMappingKey) {
return concat([": ", alignWithSpaces(2, printedValue)]);
}
// force explicit Key
if (hasLeadingComments(value) || !isInlineNode(key.content)) {
return concat([
"? ",
alignWithSpaces(2, printedKey),
hardline,
join(
"",
path
.map(print, "value", "leadingComments")
.map((comment) => concat([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 concat([printedKey, spaceBeforeColon, ": ", printedValue]);
}
const groupId = Symbol("mappingKey");
const groupedKey = group(
concat([
ifBreak("? "),
group(alignWithSpaces(2, printedKey), { id: groupId }),
])
);
const breakValue = concat([hardline, ": ", alignWithSpaces(2, printedValue)]);
/** @type {Doc[]} */
const flatValueParts = [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)
) {
flatValueParts.push(hardline);
} else if (value.content) {
flatValueParts.push(line);
}
flatValueParts.push(printedValue);
const flatValue = alignWithSpaces(options.tabWidth, concat(flatValueParts));
return conditionalGroup([
concat([groupedKey, ifBreak(breakValue, flatValue, { 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;
+55
View File
@@ -0,0 +1,55 @@
"use strict";
const {
builders: { softline, align },
} = require("../../document");
const { hasEndComments, isNextLineEmpty, isNode } = require("../utils");
const printedEmptyLineCache = new WeakMap();
function printNextEmptyLine(path, originalText) {
const node = path.getValue();
const root = path.stack[0];
let isNextEmptyLinePrintedSet;
if (printedEmptyLineCache.has(root)) {
isNextEmptyLinePrintedSet = printedEmptyLineCache.get(root);
} else {
isNextEmptyLinePrintedSet = new Set();
printedEmptyLineCache.set(root, isNextEmptyLinePrintedSet);
}
if (!isNextEmptyLinePrintedSet.has(node.position.end.line)) {
isNextEmptyLinePrintedSet.add(node.position.end.line);
if (
isNextLineEmpty(node, originalText) &&
!shouldPrintEndComments(path.getParentNode())
) {
return softline;
}
}
return "";
}
function shouldPrintEndComments(node) {
return (
hasEndComments(node) &&
!isNode(node, [
"documentHead",
"documentBody",
"flowMapping",
"flowSequence",
])
);
}
function alignWithSpaces(n, doc) {
return align(" ".repeat(n), doc);
}
module.exports = {
alignWithSpaces,
shouldPrintEndComments,
printNextEmptyLine,
};
+222 -531
View File
@@ -1,81 +1,75 @@
"use strict";
const docBuilders = require("../document").builders;
/** @typedef {import("../document").Doc} Doc */
const {
conditionalGroup,
breakParent,
concat,
dedent,
dedentToRoot,
fill,
group,
hardline,
ifBreak,
join,
line,
lineSuffix,
literalline,
markAsRoot,
softline,
} = docBuilders;
builders: {
breakParent,
concat,
fill,
group,
hardline,
join,
line,
lineSuffix,
literalline,
},
} = require("../document");
const { replaceEndOfLineWith, isPreviousLineEmpty } = require("../common/util");
const { insertPragma, isPragma } = require("./pragma");
const { locStart } = require("./loc");
const embed = require("./embed");
const {
getAncestorCount,
getBlockValueLineContents,
getFlowScalarLineContents,
getLast,
getLastDescendantNode,
hasLeadingComments,
hasMiddleComments,
hasIndicatorComment,
hasTrailingComment,
hasEndComments,
hasPrettierIgnore,
isLastDescendantNode,
isNextLineEmpty,
isNode,
isEmptyNode,
defineShortcut,
mapNode,
isInlineNode,
} = require("./utils");
function preprocess(ast) {
return mapNode(ast, defineShortcuts);
}
function defineShortcuts(node) {
switch (node.type) {
case "document":
defineShortcut(node, "head", () => node.children[0]);
defineShortcut(node, "body", () => node.children[1]);
break;
case "documentBody":
case "sequenceItem":
case "flowSequenceItem":
case "mappingKey":
case "mappingValue":
defineShortcut(node, "content", () => node.children[0]);
break;
case "mappingItem":
case "flowMappingItem":
defineShortcut(node, "key", () => node.children[0]);
defineShortcut(node, "value", () => node.children[1]);
break;
}
return node;
}
const preprocess = require("./print-preprocess");
const {
alignWithSpaces,
printNextEmptyLine,
shouldPrintEndComments,
} = require("./print/misc");
const {
printFlowMapping,
printFlowSequence,
} = require("./print/flow-mapping-sequence");
const printMappingItem = require("./print/mapping-item");
const printBlock = require("./print/block");
function genericPrint(path, options, print) {
const node = path.getValue();
const parentNode = path.getParentNode();
/** @type {Doc[]} */
const parts = [];
const tag = !node.tag ? "" : path.call(print, "tag");
const anchor = !node.anchor ? "" : path.call(print, "anchor");
if (node.type !== "mappingValue" && hasLeadingComments(node)) {
parts.push(
concat([join(hardline, path.map(print, "leadingComments")), hardline])
);
}
const nextEmptyLine =
const { tag, anchor } = node;
if (tag) {
parts.push(path.call(print, "tag"));
}
if (tag && anchor) {
parts.push(" ");
}
if (anchor) {
parts.push(path.call(print, "anchor"));
}
/** @type {Doc} */
let nextEmptyLine = "";
if (
isNode(node, [
"mapping",
"sequence",
@@ -83,167 +77,184 @@ function genericPrint(path, options, print) {
"directive",
"mappingItem",
"sequenceItem",
]) && !isLastDescendantNode(path)
? printNextEmptyLine(path, options.originalText)
: "";
]) &&
!isLastDescendantNode(path)
) {
nextEmptyLine = printNextEmptyLine(path, options.originalText);
}
return concat([
node.type !== "mappingValue" && hasLeadingComments(node)
? concat([join(hardline, path.map(print, "leadingComments")), hardline])
: "",
tag,
tag && anchor ? " " : "",
anchor,
tag || anchor
? isNode(node, ["sequence", "mapping"]) && !hasMiddleComments(node)
? hardline
: " "
: "",
hasMiddleComments(node)
? concat([
node.middleComments.length === 1 ? "" : hardline,
join(hardline, path.map(print, "middleComments")),
hardline,
if (tag || anchor) {
if (isNode(node, ["sequence", "mapping"]) && !hasMiddleComments(node)) {
parts.push(hardline);
} else {
parts.push(" ");
}
}
if (hasMiddleComments(node)) {
parts.push(
concat([
node.middleComments.length === 1 ? "" : hardline,
join(hardline, path.map(print, "middleComments")),
hardline,
])
);
}
const parentNode = path.getParentNode();
if (hasPrettierIgnore(path)) {
parts.push(
concat(
replaceEndOfLineWith(
options.originalText
.slice(node.position.start.offset, node.position.end.offset)
.trimEnd(),
literalline
)
)
);
} else {
parts.push(group(printNode(node, parentNode, path, options, print)));
}
if (hasTrailingComment(node) && !isNode(node, ["document", "documentHead"])) {
parts.push(
lineSuffix(
concat([
node.type === "mappingValue" && !node.content ? "" : " ",
parentNode.type === "mappingKey" &&
path.getParentNode(2).type === "mapping" &&
isInlineNode(node)
? ""
: breakParent,
path.call(print, "trailingComment"),
])
: "",
hasPrettierIgnore(path)
? concat(
replaceEndOfLineWith(
options.originalText
.slice(node.position.start.offset, node.position.end.offset)
.trimEnd(),
literalline
)
)
: group(_print(node, parentNode, path, options, print)),
hasTrailingComment(node) && !isNode(node, ["document", "documentHead"])
? lineSuffix(
concat([
node.type === "mappingValue" && !node.content ? "" : " ",
parentNode.type === "mappingKey" &&
path.getParentNode(2).type === "mapping" &&
isInlineNode(node)
? ""
: breakParent,
path.call(print, "trailingComment"),
])
)
: "",
shouldPrintEndComments(node)
? align(
node.type === "sequenceItem" ? 2 : 0,
concat([
)
);
}
if (shouldPrintEndComments(node)) {
parts.push(
alignWithSpaces(
node.type === "sequenceItem" ? 2 : 0,
concat([
hardline,
join(
hardline,
join(
hardline,
path.map(
(path) =>
concat([
isPreviousLineEmpty(
options.originalText,
path.getValue(),
locStart
)
? hardline
: "",
print(path),
]),
"endComments"
)
),
])
)
: "",
nextEmptyLine,
]);
path.map(
(path) =>
concat([
isPreviousLineEmpty(
options.originalText,
path.getValue(),
locStart
)
? hardline
: "",
print(path),
]),
"endComments"
)
),
])
)
);
}
parts.push(nextEmptyLine);
return concat(parts);
}
function _print(node, parentNode, path, options, print) {
function printNode(node, parentNode, path, options, print) {
switch (node.type) {
case "root":
return concat([
join(
hardline,
path.map((childPath, index) => {
const document = node.children[index];
const nextDocument = node.children[index + 1];
return concat([
print(childPath),
shouldPrintDocumentEndMarker(document, nextDocument)
? concat([
hardline,
"...",
hasTrailingComment(document)
? concat([" ", path.call(print, "trailingComment")])
: "",
])
: !nextDocument || hasTrailingComment(nextDocument.head)
? ""
: concat([hardline, "---"]),
]);
}, "children")
),
node.children.length === 0 ||
((lastDescendantNode) =>
isNode(lastDescendantNode, ["blockLiteral", "blockFolded"]) &&
lastDescendantNode.chomping === "keep")(getLastDescendantNode(node))
? ""
: hardline,
]);
case "root": {
const { children } = node;
const parts = [];
path.each((childPath, index) => {
const document = children[index];
const nextDocument = children[index + 1];
if (index !== 0) {
parts.push(hardline);
}
parts.push(print(childPath));
if (shouldPrintDocumentEndMarker(document, nextDocument)) {
parts.push(hardline, "...");
if (hasTrailingComment(document)) {
parts.push(" ", path.call(print, "trailingComment"));
}
} else if (nextDocument && !hasTrailingComment(nextDocument.head)) {
parts.push(hardline, "---");
}
}, "children");
const lastDescendantNode = getLastDescendantNode(node);
if (
!isNode(lastDescendantNode, ["blockLiteral", "blockFolded"]) ||
lastDescendantNode.chomping !== "keep"
) {
parts.push(hardline);
}
return concat(parts);
}
case "document": {
const nextDocument = parentNode.children[path.getName() + 1];
return join(
hardline,
[
shouldPrintDocumentHeadEndMarker(
node,
nextDocument,
parentNode,
options
) === "head"
? join(
hardline,
[
node.head.children.length === 0 &&
node.head.endComments.length === 0
? ""
: path.call(print, "head"),
concat([
"---",
hasTrailingComment(node.head)
? concat([
" ",
path.call(print, "head", "trailingComment"),
])
: "",
]),
].filter(Boolean)
)
: "",
shouldPrintDocumentBody(node) ? path.call(print, "body") : "",
].filter(Boolean)
);
const parts = [];
if (
shouldPrintDocumentHeadEndMarker(
node,
nextDocument,
parentNode,
options
) === "head"
) {
if (
node.head.children.length !== 0 ||
node.head.endComments.length !== 0
) {
parts.push(path.call(print, "head"));
}
if (hasTrailingComment(node.head)) {
parts.push(
concat(["---", " ", path.call(print, "head", "trailingComment")])
);
} else {
parts.push("---");
}
}
if (shouldPrintDocumentBody(node)) {
parts.push(path.call(print, "body"));
}
return join(hardline, parts);
}
case "documentHead":
return join(
hardline,
[].concat(path.map(print, "children"), path.map(print, "endComments"))
);
return join(hardline, [
...path.map(print, "children"),
...path.map(print, "endComments"),
]);
case "documentBody": {
const children = join(hardline, path.map(print, "children")).parts;
const endComments = join(hardline, path.map(print, "endComments")).parts;
const separator =
children.length === 0 || endComments.length === 0
? ""
: ((lastDescendantNode) =>
isNode(lastDescendantNode, ["blockFolded", "blockLiteral"])
? lastDescendantNode.chomping === "keep"
? // there's already a newline printed at the end of blockValue (chomping=keep, lastDescendant=true)
""
: // an extra newline for better readability
concat([hardline, hardline])
: hardline)(getLastDescendantNode(node));
return concat([].concat(children, separator, endComments));
const { children, endComments } = node;
/** @type {Doc} */
let separator = "";
if (children.length !== 0 && endComments.length !== 0) {
const lastDescendantNode = getLastDescendantNode(node);
// there's already a newline printed at the end of blockValue (chomping=keep, lastDescendant=true)
if (isNode(lastDescendantNode, ["blockFolded", "blockLiteral"])) {
// an extra newline for better readability
if (lastDescendantNode.chomping !== "keep") {
separator = concat([hardline, hardline]);
}
} else {
separator = hardline;
}
}
return concat([
join(hardline, path.map(print, "children")),
separator,
join(hardline, path.map(print, "endComments")),
]);
}
case "directive":
return concat(["%", join(" ", [node.name].concat(node.parameters))]);
@@ -331,55 +342,14 @@ function _print(node, parentNode, path, options, print) {
}
case "blockFolded":
case "blockLiteral": {
const parentIndent = getAncestorCount(path, (ancestorNode) =>
isNode(ancestorNode, ["sequence", "mapping"])
);
const isLastDescendant = isLastDescendantNode(path);
return concat([
node.type === "blockFolded" ? ">" : "|",
node.indent === null ? "" : node.indent.toString(),
node.chomping === "clip" ? "" : node.chomping === "keep" ? "+" : "-",
hasIndicatorComment(node)
? concat([" ", path.call(print, "indicatorComment")])
: "",
(node.indent === null ? dedent : dedentToRoot)(
align(
node.indent === null
? options.tabWidth
: node.indent - 1 + parentIndent,
concat(
getBlockValueLineContents(node, {
parentIndent,
isLastDescendant,
options,
}).reduce(
(reduced, lineWords, index, lineContents) =>
reduced.concat(
index === 0 ? hardline : "",
fill(join(line, lineWords).parts),
index !== lineContents.length - 1
? lineWords.length === 0
? hardline
: markAsRoot(literalline)
: node.chomping === "keep" && isLastDescendant
? lineWords.length === 0
? dedentToRoot(hardline)
: dedentToRoot(literalline)
: ""
),
[]
)
)
)
),
]);
return printBlock(path, print, options);
}
case "sequence":
return join(hardline, path.map(print, "children"));
case "sequenceItem":
return concat([
"- ",
align(2, !node.content ? "" : path.call(print, "content")),
alignWithSpaces(2, !node.content ? "" : path.call(print, "content")),
]);
case "mappingKey":
return !node.content ? "" : path.call(print, "content");
@@ -389,212 +359,18 @@ function _print(node, parentNode, path, options, print) {
return join(hardline, path.map(print, "children"));
case "mappingItem":
case "flowMappingItem": {
const isEmptyMappingKey = isEmptyNode(node.key);
const isEmptyMappingValue = isEmptyNode(node.value);
if (isEmptyMappingKey && isEmptyMappingValue) {
return concat([": "]);
}
const key = path.call(print, "key");
const value = path.call(print, "value");
if (isEmptyMappingValue) {
return node.type === "flowMappingItem" &&
parentNode.type === "flowMapping"
? key
: node.type === "mappingItem" &&
isAbsolutelyPrintedAsSingleLineNode(node.key.content, options) &&
!hasTrailingComment(node.key.content) &&
(!parentNode.tag ||
parentNode.tag.value !== "tag:yaml.org,2002:set")
? concat([key, needsSpaceInFrontOfMappingValue(node) ? " " : "", ":"])
: concat(["? ", align(2, key)]);
}
if (isEmptyMappingKey) {
return concat([": ", align(2, value)]);
}
const groupId = Symbol("mappingKey");
const forceExplicitKey =
hasLeadingComments(node.value) || !isInlineNode(node.key.content);
return forceExplicitKey
? concat([
"? ",
align(2, key),
hardline,
join(
"",
path
.map(print, "value", "leadingComments")
.map((comment) => concat([comment, hardline]))
),
": ",
align(2, value),
])
: // force singleline
isSingleLineNode(node.key.content) &&
!hasLeadingComments(node.key.content) &&
!hasMiddleComments(node.key.content) &&
!hasTrailingComment(node.key.content) &&
!hasEndComments(node.key) &&
!hasLeadingComments(node.value.content) &&
!hasMiddleComments(node.value.content) &&
!hasEndComments(node.value) &&
isAbsolutelyPrintedAsSingleLineNode(node.value.content, options)
? concat([
key,
needsSpaceInFrontOfMappingValue(node) ? " " : "",
": ",
value,
])
: conditionalGroup([
concat([
group(
concat([ifBreak("? "), group(align(2, key), { id: groupId })])
),
ifBreak(
concat([hardline, ": ", align(2, value)]),
indent(
concat([
needsSpaceInFrontOfMappingValue(node) ? " " : "",
":",
hasLeadingComments(node.value.content) ||
(hasEndComments(node.value) &&
node.value.content &&
!isNode(node.value.content, ["mapping", "sequence"])) ||
(parentNode.type === "mapping" &&
hasTrailingComment(node.key.content) &&
isInlineNode(node.value.content)) ||
(isNode(node.value.content, ["mapping", "sequence"]) &&
node.value.content.tag === null &&
node.value.content.anchor === null)
? hardline
: !node.value.content
? ""
: line,
value,
])
),
{ groupId }
),
]),
]);
return printMappingItem(node, parentNode, path, print, options);
}
case "flowMapping":
case "flowSequence": {
const openMarker = node.type === "flowMapping" ? "{" : "[";
const closeMarker = node.type === "flowMapping" ? "}" : "]";
const bracketSpacing =
node.type === "flowMapping" &&
node.children.length !== 0 &&
options.bracketSpacing
? line
: softline;
const isLastItemEmptyMappingItem =
node.children.length !== 0 &&
((lastItem) =>
lastItem.type === "flowMappingItem" &&
isEmptyNode(lastItem.key) &&
isEmptyNode(lastItem.value))(getLast(node.children));
const trailingComma =
options.trailingComma === "none" ? "" : ifBreak(",", "");
return concat([
openMarker,
indent(
concat([
bracketSpacing,
concat(
path.map(
(childPath, index) =>
concat([
print(childPath),
index === node.children.length - 1
? ""
: concat([
",",
line,
node.children[index].position.start.line !==
node.children[index + 1].position.start.line
? printNextEmptyLine(
childPath,
options.originalText
)
: "",
]),
]),
"children"
)
),
trailingComma,
hasEndComments(node)
? concat([
hardline,
join(hardline, path.map(print, "endComments")),
])
: "",
])
),
isLastItemEmptyMappingItem ? "" : bracketSpacing,
closeMarker,
]);
}
return printFlowMapping(path, print, options);
case "flowSequence":
return printFlowSequence(path, print, options);
case "flowSequenceItem":
return path.call(print, "content");
// istanbul ignore next
default:
throw new Error(`Unexpected node type ${node.type}`);
}
function indent(doc) {
return docBuilders.align(" ".repeat(options.tabWidth), doc);
}
}
function align(n, doc) {
return typeof n === "number" && n > 0
? docBuilders.align(" ".repeat(n), doc)
: docBuilders.align(n, doc);
}
function isInlineNode(node) {
/* istanbul ignore next */
if (!node) {
return true;
}
switch (node.type) {
case "plain":
case "quoteDouble":
case "quoteSingle":
case "alias":
case "flowMapping":
case "flowSequence":
return true;
default:
return false;
}
}
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;
}
}
function shouldPrintDocumentBody(document) {
@@ -663,91 +439,6 @@ function shouldPrintDocumentHeadEndMarker(
return nextDocument ? "root" : false;
}
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 shouldPrintEndComments(node) {
return (
hasEndComments(node) &&
!isNode(node, [
"documentHead",
"documentBody",
"flowMapping",
"flowSequence",
])
);
}
const printedEmptyLineCache = new WeakMap();
function printNextEmptyLine(path, originalText) {
const node = path.getValue();
const root = path.stack[0];
let isNextEmptyLinePrintedSet;
if (printedEmptyLineCache.has(root)) {
isNextEmptyLinePrintedSet = printedEmptyLineCache.get(root);
} else {
isNextEmptyLinePrintedSet = new Set();
printedEmptyLineCache.set(root, isNextEmptyLinePrintedSet);
}
if (!isNextEmptyLinePrintedSet.has(node.position.end.line)) {
isNextEmptyLinePrintedSet.add(node.position.end.line);
if (
isNextLineEmpty(node, originalText) &&
!shouldPrintEndComments(path.getParentNode())
) {
return softline;
}
}
return "";
}
function printFlowScalarContent(nodeType, content, options) {
const lineContents = getFlowScalarLineContents(nodeType, content, options);
return join(
+20
View File
@@ -327,11 +327,31 @@ function getBlockValueLineContents(
}
}
function isInlineNode(node) {
/* istanbul ignore next */
if (!node) {
return true;
}
switch (node.type) {
case "plain":
case "quoteDouble":
case "quoteSingle":
case "alias":
case "flowMapping":
case "flowSequence":
return true;
default:
return false;
}
}
module.exports = {
getLast,
getAncestorCount,
isNode,
isEmptyNode,
isInlineNode,
mapNode,
defineShortcut,
isNextLineEmpty,