refactor: Extract printChildren and printElement (#11466)

* Extract printChildrent and printElement

* Refactor printChildren
This commit is contained in:
Sosuke Suzuki authored and GitHub committed 2021-09-09 19:00:14 +09:00
1 parent d812687502
commit a1cc5d4ecd
3 files changed
+389 -361

No files matched your search

+210
View File
@@ -0,0 +1,210 @@
"use strict";
const {
builders: { breakParent, group, ifBreak, line, softline, hardline },
utils: { replaceTextEndOfLine },
} = require("../../document/index.js");
const { locStart, locEnd } = require("../loc.js");
const {
forceBreakChildren,
forceNextEmptyLine,
isTextLikeNode,
hasPrettierIgnore,
preferHardlineAsLeadingSpaces,
} = require("../utils.js");
const {
printOpeningTagPrefix,
needsToBorrowNextOpeningTagStartMarker,
printOpeningTagStartMarker,
needsToBorrowPrevClosingTagEndMarker,
printClosingTagEndMarker,
printClosingTagSuffix,
needsToBorrowParentClosingTagStartMarker,
} = require("./tag.js");
function printChild(childPath, options, print) {
const child = childPath.getValue();
if (hasPrettierIgnore(child)) {
return [
printOpeningTagPrefix(child, options),
...replaceTextEndOfLine(
options.originalText.slice(
locStart(child) +
(child.prev && needsToBorrowNextOpeningTagStartMarker(child.prev)
? printOpeningTagStartMarker(child).length
: 0),
locEnd(child) -
(child.next && needsToBorrowPrevClosingTagEndMarker(child.next)
? printClosingTagEndMarker(child, options).length
: 0)
)
),
printClosingTagSuffix(child, options),
];
}
return print();
}
function printBetweenLine(prevNode, nextNode) {
return isTextLikeNode(prevNode) && isTextLikeNode(nextNode)
? prevNode.isTrailingSpaceSensitive
? prevNode.hasTrailingSpaces
? preferHardlineAsLeadingSpaces(nextNode)
? hardline
: line
: ""
: preferHardlineAsLeadingSpaces(nextNode)
? hardline
: softline
: (needsToBorrowNextOpeningTagStartMarker(prevNode) &&
(hasPrettierIgnore(nextNode) ||
/**
* 123<a
* ~
* ><b>
*/
nextNode.firstChild ||
/**
* 123<!--
* ~
* -->
*/
nextNode.isSelfClosing ||
/**
* 123<span
* ~
* attr
*/
(nextNode.type === "element" && nextNode.attrs.length > 0))) ||
/**
* <img
* src="long"
* ~
* />123
*/
(prevNode.type === "element" &&
prevNode.isSelfClosing &&
needsToBorrowPrevClosingTagEndMarker(nextNode))
? ""
: !nextNode.isLeadingSpaceSensitive ||
preferHardlineAsLeadingSpaces(nextNode) ||
/**
* Want to write us a letter? Use our<a
* ><b><a>mailing address</a></b></a
* ~
* >.
*/
(needsToBorrowPrevClosingTagEndMarker(nextNode) &&
prevNode.lastChild &&
needsToBorrowParentClosingTagStartMarker(prevNode.lastChild) &&
prevNode.lastChild.lastChild &&
needsToBorrowParentClosingTagStartMarker(prevNode.lastChild.lastChild))
? hardline
: nextNode.hasLeadingSpaces
? line
: softline;
}
function printChildren(path, options, print) {
const node = path.getValue();
if (forceBreakChildren(node)) {
return [
breakParent,
...path.map((childPath) => {
const childNode = childPath.getValue();
const prevBetweenLine = !childNode.prev
? ""
: printBetweenLine(childNode.prev, childNode);
return [
!prevBetweenLine
? ""
: [
prevBetweenLine,
forceNextEmptyLine(childNode.prev) ? hardline : "",
],
printChild(childPath, options, print),
];
}, "children"),
];
}
const groupIds = node.children.map(() => Symbol(""));
return path.map((childPath, childIndex) => {
const childNode = childPath.getValue();
if (isTextLikeNode(childNode)) {
if (childNode.prev && isTextLikeNode(childNode.prev)) {
const prevBetweenLine = printBetweenLine(childNode.prev, childNode);
if (prevBetweenLine) {
if (forceNextEmptyLine(childNode.prev)) {
return [hardline, hardline, printChild(childPath, options, print)];
}
return [prevBetweenLine, printChild(childPath, options, print)];
}
}
return printChild(childPath, options, print);
}
const prevParts = [];
const leadingParts = [];
const trailingParts = [];
const nextParts = [];
const prevBetweenLine = childNode.prev
? printBetweenLine(childNode.prev, childNode)
: "";
const nextBetweenLine = childNode.next
? printBetweenLine(childNode, childNode.next)
: "";
if (prevBetweenLine) {
if (forceNextEmptyLine(childNode.prev)) {
prevParts.push(hardline, hardline);
} else if (prevBetweenLine === hardline) {
prevParts.push(hardline);
} else {
if (isTextLikeNode(childNode.prev)) {
leadingParts.push(prevBetweenLine);
} else {
leadingParts.push(
ifBreak("", softline, {
groupId: groupIds[childIndex - 1],
})
);
}
}
}
if (nextBetweenLine) {
if (forceNextEmptyLine(childNode)) {
if (isTextLikeNode(childNode.next)) {
nextParts.push(hardline, hardline);
}
} else if (nextBetweenLine === hardline) {
if (isTextLikeNode(childNode.next)) {
nextParts.push(hardline);
}
} else {
trailingParts.push(nextBetweenLine);
}
}
return [
...prevParts,
group([
...leadingParts,
group([printChild(childPath, options, print), ...trailingParts], {
id: groupIds[childIndex],
}),
]),
...nextParts,
];
}, "children");
}
module.exports = { printChildren };
+176
View File
@@ -0,0 +1,176 @@
"use strict";
const {
builders: {
breakParent,
dedentToRoot,
group,
ifBreak,
indentIfBreak,
indent,
line,
softline,
},
utils: { replaceTextEndOfLine },
} = require("../../document/index.js");
const getNodeContent = require("../get-node-content.js");
const {
shouldPreserveContent,
isScriptLikeTag,
isVueCustomBlock,
countParents,
forceBreakContent,
} = require("../utils.js");
const {
printOpeningTagPrefix,
printOpeningTag,
printClosingTagSuffix,
printClosingTag,
needsToBorrowPrevClosingTagEndMarker,
needsToBorrowLastChildClosingTagEndMarker,
} = require("./tag.js");
const { printChildren } = require("./children.js");
function printElement(path, options, print) {
const node = path.getValue();
if (shouldPreserveContent(node, options)) {
return [
printOpeningTagPrefix(node, options),
group(printOpeningTag(path, options, print)),
...replaceTextEndOfLine(getNodeContent(node, options)),
...printClosingTag(node, options),
printClosingTagSuffix(node, options),
];
}
/**
* do not break:
*
* <div>{{
* ~
* interpolation
* }}</div>
* ~
*
* exception: break if the opening tag breaks
*
* <div
* long
* ~
* >{{
* interpolation
* }}</div
* ~
* >
*/
const shouldHugContent =
node.children.length === 1 &&
node.firstChild.type === "interpolation" &&
node.firstChild.isLeadingSpaceSensitive &&
!node.firstChild.hasLeadingSpaces &&
node.lastChild.isTrailingSpaceSensitive &&
!node.lastChild.hasTrailingSpaces;
const attrGroupId = Symbol("element-attr-group-id");
const printTag = (doc) =>
group([
group(printOpeningTag(path, options, print), { id: attrGroupId }),
doc,
printClosingTag(node, options),
]);
const printChildrenDoc = (childrenDoc) => {
if (shouldHugContent) {
return indentIfBreak(childrenDoc, { groupId: attrGroupId });
}
if (
(isScriptLikeTag(node) || isVueCustomBlock(node, options)) &&
node.parent.type === "root" &&
options.parser === "vue" &&
!options.vueIndentScriptAndStyle
) {
return childrenDoc;
}
return indent(childrenDoc);
};
const printLineBeforeChildren = () => {
if (shouldHugContent) {
return ifBreak(softline, "", { groupId: attrGroupId });
}
if (
node.firstChild.hasLeadingSpaces &&
node.firstChild.isLeadingSpaceSensitive
) {
return line;
}
if (
node.firstChild.type === "text" &&
node.isWhitespaceSensitive &&
node.isIndentationSensitive
) {
return dedentToRoot(softline);
}
return softline;
};
const printLineAfterChildren = () => {
const needsToBorrow = node.next
? needsToBorrowPrevClosingTagEndMarker(node.next)
: needsToBorrowLastChildClosingTagEndMarker(node.parent);
if (needsToBorrow) {
if (
node.lastChild.hasTrailingSpaces &&
node.lastChild.isTrailingSpaceSensitive
) {
return " ";
}
return "";
}
if (shouldHugContent) {
return ifBreak(softline, "", { groupId: attrGroupId });
}
if (
node.lastChild.hasTrailingSpaces &&
node.lastChild.isTrailingSpaceSensitive
) {
return line;
}
if (
(node.lastChild.type === "comment" ||
(node.lastChild.type === "text" &&
node.isWhitespaceSensitive &&
node.isIndentationSensitive)) &&
new RegExp(
`\\n[\\t ]{${
options.tabWidth *
countParents(
path,
(node) => node.parent && node.parent.type !== "root"
)
}}$`
).test(node.lastChild.value)
) {
return "";
}
return softline;
};
if (node.children.length === 0) {
return printTag(
node.hasDanglingSpaces && node.isDanglingSpaceSensitive ? line : ""
);
}
return printTag([
forceBreakContent(node) ? breakParent : "",
printChildrenDoc([
printLineBeforeChildren(),
printChildren(path, options, print),
]),
printLineAfterChildren(),
]);
}
module.exports = { printElement };
+3 -361
View File
@@ -5,34 +5,12 @@
*/
const {
builders: {
breakParent,
dedentToRoot,
fill,
group,
hardline,
ifBreak,
indentIfBreak,
indent,
line,
literalline,
softline,
},
builders: { fill, group, hardline, literalline },
utils: { cleanDoc, getDocParts, isConcat, replaceTextEndOfLine },
} = require("../document/index.js");
const clean = require("./clean.js");
const {
countChars,
countParents,
forceBreakChildren,
forceBreakContent,
forceNextEmptyLine,
hasPrettierIgnore,
isVueCustomBlock,
isScriptLikeTag,
isTextLikeNode,
preferHardlineAsLeadingSpaces,
shouldPreserveContent,
unescapeQuoteEntities,
getTextValueParts,
} = require("./utils.js");
@@ -41,20 +19,13 @@ const { insertPragma } = require("./pragma.js");
const { locStart, locEnd } = require("./loc.js");
const embed = require("./embed.js");
const {
printClosingTagEndMarker,
printClosingTagSuffix,
printClosingTag,
printClosingTagEnd,
needsToBorrowPrevClosingTagEndMarker,
needsToBorrowLastChildClosingTagEndMarker,
needsToBorrowParentClosingTagStartMarker,
printOpeningTagPrefix,
printOpeningTag,
printOpeningTagStart,
printOpeningTagStartMarker,
needsToBorrowNextOpeningTagStartMarker,
} = require("./print/tag.js");
const getNodeContent = require("./get-node-content.js");
const { printElement } = require("./print/element.js");
const { printChildren } = require("./print/children.js");
function genericPrint(path, options, print) {
const node = path.getValue();
@@ -153,335 +124,6 @@ function genericPrint(path, options, print) {
}
}
function printElement(path, options, print) {
const node = path.getValue();
if (shouldPreserveContent(node, options)) {
return [
printOpeningTagPrefix(node, options),
group(printOpeningTag(path, options, print)),
...replaceTextEndOfLine(getNodeContent(node, options)),
...printClosingTag(node, options),
printClosingTagSuffix(node, options),
];
}
/**
* do not break:
*
* <div>{{
* ~
* interpolation
* }}</div>
* ~
*
* exception: break if the opening tag breaks
*
* <div
* long
* ~
* >{{
* interpolation
* }}</div
* ~
* >
*/
const shouldHugContent =
node.children.length === 1 &&
node.firstChild.type === "interpolation" &&
node.firstChild.isLeadingSpaceSensitive &&
!node.firstChild.hasLeadingSpaces &&
node.lastChild.isTrailingSpaceSensitive &&
!node.lastChild.hasTrailingSpaces;
const attrGroupId = Symbol("element-attr-group-id");
const printTag = (doc) =>
group([
group(printOpeningTag(path, options, print), { id: attrGroupId }),
doc,
printClosingTag(node, options),
]);
const printChildrenDoc = (childrenDoc) => {
if (shouldHugContent) {
return indentIfBreak(childrenDoc, { groupId: attrGroupId });
}
if (
(isScriptLikeTag(node) || isVueCustomBlock(node, options)) &&
node.parent.type === "root" &&
options.parser === "vue" &&
!options.vueIndentScriptAndStyle
) {
return childrenDoc;
}
return indent(childrenDoc);
};
const printLineBeforeChildren = () => {
if (shouldHugContent) {
return ifBreak(softline, "", { groupId: attrGroupId });
}
if (
node.firstChild.hasLeadingSpaces &&
node.firstChild.isLeadingSpaceSensitive
) {
return line;
}
if (
node.firstChild.type === "text" &&
node.isWhitespaceSensitive &&
node.isIndentationSensitive
) {
return dedentToRoot(softline);
}
return softline;
};
const printLineAfterChildren = () => {
const needsToBorrow = node.next
? needsToBorrowPrevClosingTagEndMarker(node.next)
: needsToBorrowLastChildClosingTagEndMarker(node.parent);
if (needsToBorrow) {
if (
node.lastChild.hasTrailingSpaces &&
node.lastChild.isTrailingSpaceSensitive
) {
return " ";
}
return "";
}
if (shouldHugContent) {
return ifBreak(softline, "", { groupId: attrGroupId });
}
if (
node.lastChild.hasTrailingSpaces &&
node.lastChild.isTrailingSpaceSensitive
) {
return line;
}
if (
(node.lastChild.type === "comment" ||
(node.lastChild.type === "text" &&
node.isWhitespaceSensitive &&
node.isIndentationSensitive)) &&
new RegExp(
`\\n[\\t ]{${
options.tabWidth *
countParents(
path,
(node) => node.parent && node.parent.type !== "root"
)
}}$`
).test(node.lastChild.value)
) {
return "";
}
return softline;
};
if (node.children.length === 0) {
return printTag(
node.hasDanglingSpaces && node.isDanglingSpaceSensitive ? line : ""
);
}
return printTag([
forceBreakContent(node) ? breakParent : "",
printChildrenDoc([
printLineBeforeChildren(),
printChildren(path, options, print),
]),
printLineAfterChildren(),
]);
}
function printChildren(path, options, print) {
const node = path.getValue();
if (forceBreakChildren(node)) {
return [
breakParent,
...path.map((childPath) => {
const childNode = childPath.getValue();
const prevBetweenLine = !childNode.prev
? ""
: printBetweenLine(childNode.prev, childNode);
return [
!prevBetweenLine
? ""
: [
prevBetweenLine,
forceNextEmptyLine(childNode.prev) ? hardline : "",
],
printChild(childPath),
];
}, "children"),
];
}
const groupIds = node.children.map(() => Symbol(""));
return path.map((childPath, childIndex) => {
const childNode = childPath.getValue();
if (isTextLikeNode(childNode)) {
if (childNode.prev && isTextLikeNode(childNode.prev)) {
const prevBetweenLine = printBetweenLine(childNode.prev, childNode);
if (prevBetweenLine) {
if (forceNextEmptyLine(childNode.prev)) {
return [hardline, hardline, printChild(childPath)];
}
return [prevBetweenLine, printChild(childPath)];
}
}
return printChild(childPath);
}
const prevParts = [];
const leadingParts = [];
const trailingParts = [];
const nextParts = [];
const prevBetweenLine = childNode.prev
? printBetweenLine(childNode.prev, childNode)
: "";
const nextBetweenLine = childNode.next
? printBetweenLine(childNode, childNode.next)
: "";
if (prevBetweenLine) {
if (forceNextEmptyLine(childNode.prev)) {
prevParts.push(hardline, hardline);
} else if (prevBetweenLine === hardline) {
prevParts.push(hardline);
} else {
if (isTextLikeNode(childNode.prev)) {
leadingParts.push(prevBetweenLine);
} else {
leadingParts.push(
ifBreak("", softline, {
groupId: groupIds[childIndex - 1],
})
);
}
}
}
if (nextBetweenLine) {
if (forceNextEmptyLine(childNode)) {
if (isTextLikeNode(childNode.next)) {
nextParts.push(hardline, hardline);
}
} else if (nextBetweenLine === hardline) {
if (isTextLikeNode(childNode.next)) {
nextParts.push(hardline);
}
} else {
trailingParts.push(nextBetweenLine);
}
}
return [
...prevParts,
group([
...leadingParts,
group([printChild(childPath), ...trailingParts], {
id: groupIds[childIndex],
}),
]),
...nextParts,
];
}, "children");
function printChild(childPath) {
const child = childPath.getValue();
if (hasPrettierIgnore(child)) {
return [
printOpeningTagPrefix(child, options),
...replaceTextEndOfLine(
options.originalText.slice(
locStart(child) +
(child.prev && needsToBorrowNextOpeningTagStartMarker(child.prev)
? printOpeningTagStartMarker(child).length
: 0),
locEnd(child) -
(child.next && needsToBorrowPrevClosingTagEndMarker(child.next)
? printClosingTagEndMarker(child, options).length
: 0)
)
),
printClosingTagSuffix(child, options),
];
}
return print();
}
function printBetweenLine(prevNode, nextNode) {
return isTextLikeNode(prevNode) && isTextLikeNode(nextNode)
? prevNode.isTrailingSpaceSensitive
? prevNode.hasTrailingSpaces
? preferHardlineAsLeadingSpaces(nextNode)
? hardline
: line
: ""
: preferHardlineAsLeadingSpaces(nextNode)
? hardline
: softline
: (needsToBorrowNextOpeningTagStartMarker(prevNode) &&
(hasPrettierIgnore(nextNode) ||
/**
* 123<a
* ~
* ><b>
*/
nextNode.firstChild ||
/**
* 123<!--
* ~
* -->
*/
nextNode.isSelfClosing ||
/**
* 123<span
* ~
* attr
*/
(nextNode.type === "element" && nextNode.attrs.length > 0))) ||
/**
* <img
* src="long"
* ~
* />123
*/
(prevNode.type === "element" &&
prevNode.isSelfClosing &&
needsToBorrowPrevClosingTagEndMarker(nextNode))
? ""
: !nextNode.isLeadingSpaceSensitive ||
preferHardlineAsLeadingSpaces(nextNode) ||
/**
* Want to write us a letter? Use our<a
* ><b><a>mailing address</a></b></a
* ~
* >.
*/
(needsToBorrowPrevClosingTagEndMarker(nextNode) &&
prevNode.lastChild &&
needsToBorrowParentClosingTagStartMarker(prevNode.lastChild) &&
prevNode.lastChild.lastChild &&
needsToBorrowParentClosingTagStartMarker(
prevNode.lastChild.lastChild
))
? hardline
: nextNode.hasLeadingSpaces
? line
: softline;
}
}
module.exports = {
preprocess,
print: genericPrint,