Refactor yaml (#9629)
This commit is contained in:
1 parent
cf8cba363f
commit
45407d82b9
7 files changed
+667
-531
No files matched your search
@@ -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;
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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;
|
||||
@@ -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
@@ -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(
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user