2018-09-19 23:07:27 +08:00
|
|
|
"use strict";
|
|
|
|
|
|
2018-10-13 13:55:38 +08:00
|
|
|
const {
|
|
|
|
|
CSS_DISPLAY_TAGS,
|
|
|
|
|
CSS_DISPLAY_DEFAULT,
|
|
|
|
|
CSS_WHITE_SPACE_TAGS,
|
2020-03-21 22:07:52 +02:00
|
|
|
CSS_WHITE_SPACE_DEFAULT,
|
2018-10-13 13:55:38 +08:00
|
|
|
} = require("./constants.evaluate");
|
|
|
|
|
|
2018-09-22 21:53:38 +08:00
|
|
|
const htmlTagNames = require("html-tag-names");
|
2018-09-27 20:18:00 +08:00
|
|
|
const htmlElementAttributes = require("html-element-attributes");
|
2018-09-19 23:07:27 +08:00
|
|
|
|
2018-09-22 21:53:38 +08:00
|
|
|
const HTML_TAGS = arrayToMap(htmlTagNames);
|
2018-09-27 20:18:00 +08:00
|
|
|
const HTML_ELEMENT_ATTRIBUTES = mapObject(htmlElementAttributes, arrayToMap);
|
2018-09-22 21:53:38 +08:00
|
|
|
|
|
|
|
|
function arrayToMap(array) {
|
|
|
|
|
const map = Object.create(null);
|
|
|
|
|
for (const value of array) {
|
|
|
|
|
map[value] = true;
|
|
|
|
|
}
|
|
|
|
|
return map;
|
|
|
|
|
}
|
2018-09-19 23:07:27 +08:00
|
|
|
|
2018-09-27 20:18:00 +08:00
|
|
|
function mapObject(object, fn) {
|
|
|
|
|
const newObject = Object.create(null);
|
|
|
|
|
for (const key of Object.keys(object)) {
|
|
|
|
|
newObject[key] = fn(object[key], key);
|
|
|
|
|
}
|
|
|
|
|
return newObject;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-23 12:33:48 +08:00
|
|
|
function shouldPreserveContent(node, options) {
|
2020-01-20 18:49:37 +08:00
|
|
|
if (!node.endSourceSpan) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-09 19:19:03 +08:00
|
|
|
if (
|
|
|
|
|
node.type === "element" &&
|
|
|
|
|
node.fullName === "template" &&
|
|
|
|
|
node.attrMap.lang &&
|
|
|
|
|
node.attrMap.lang !== "html"
|
|
|
|
|
) {
|
|
|
|
|
return true;
|
2018-09-19 23:07:27 +08:00
|
|
|
}
|
|
|
|
|
|
2018-11-09 23:26:59 +08:00
|
|
|
// unterminated node in ie conditional comment
|
|
|
|
|
// e.g. <!--[if lt IE 9]><html><![endif]-->
|
|
|
|
|
if (
|
|
|
|
|
node.type === "ieConditionalComment" &&
|
|
|
|
|
node.lastChild &&
|
|
|
|
|
!node.lastChild.isSelfClosing &&
|
|
|
|
|
!node.lastChild.endSourceSpan
|
|
|
|
|
) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-10 16:44:44 +08:00
|
|
|
// incomplete html in ie conditional comment
|
|
|
|
|
// e.g. <!--[if lt IE 9]></div><![endif]-->
|
|
|
|
|
if (node.type === "ieConditionalComment" && !node.complete) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-23 12:33:48 +08:00
|
|
|
// top-level elements (excluding <template>, <style> and <script>) in Vue SFC are considered custom block
|
|
|
|
|
// custom blocks can be written in other languages so we should preserve them to not break the code
|
|
|
|
|
if (
|
|
|
|
|
options.parser === "vue" &&
|
|
|
|
|
node.type === "element" &&
|
|
|
|
|
node.parent.type === "root" &&
|
2019-11-17 18:06:14 +08:00
|
|
|
![
|
2018-11-23 12:33:48 +08:00
|
|
|
"template",
|
|
|
|
|
"style",
|
|
|
|
|
"script",
|
|
|
|
|
// vue parser can be used for vue dom template as well, so we should still format top-level <html>
|
2020-03-21 22:07:52 +02:00
|
|
|
"html",
|
2019-11-17 18:06:14 +08:00
|
|
|
].includes(node.fullName)
|
2018-11-23 12:33:48 +08:00
|
|
|
) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
// TODO: handle non-text children in <pre>
|
|
|
|
|
if (
|
|
|
|
|
isPreLikeNode(node) &&
|
2018-11-09 09:50:57 +08:00
|
|
|
node.children.some(
|
2020-03-21 22:07:52 +02:00
|
|
|
(child) => child.type !== "text" && child.type !== "interpolation"
|
2018-11-09 09:50:57 +08:00
|
|
|
)
|
2018-11-04 23:03:07 +08:00
|
|
|
) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-09 19:19:03 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-09 23:26:59 +08:00
|
|
|
function hasPrettierIgnore(node) {
|
2020-02-25 03:11:08 -08:00
|
|
|
if (node.type === "attribute") {
|
2018-11-09 19:19:03 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-09 23:26:59 +08:00
|
|
|
if (!node.parent) {
|
2018-09-19 23:07:27 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-09 23:26:59 +08:00
|
|
|
if (typeof node.index !== "number" || node.index === 0) {
|
2018-09-19 23:07:27 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-09 23:26:59 +08:00
|
|
|
const prevNode = node.parent.children[node.index - 1];
|
2018-10-13 13:55:38 +08:00
|
|
|
return isPrettierIgnore(prevNode);
|
2018-09-19 23:07:27 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isPrettierIgnore(node) {
|
2018-11-04 23:03:07 +08:00
|
|
|
return node.type === "comment" && node.value.trim() === "prettier-ignore";
|
2018-09-19 23:07:27 +08:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
function getPrettierIgnoreAttributeCommentData(value) {
|
|
|
|
|
const match = value.trim().match(/^prettier-ignore-attribute(?:\s+([^]+))?$/);
|
|
|
|
|
|
|
|
|
|
if (!match) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!match[1]) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return match[1].split(/\s+/);
|
2018-09-19 23:07:27 +08:00
|
|
|
}
|
|
|
|
|
|
2018-11-23 21:25:58 +08:00
|
|
|
/** there's no opening/closing tag or it's considered not breakable */
|
|
|
|
|
function isTextLikeNode(node) {
|
|
|
|
|
return node.type === "text" || node.type === "comment";
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 13:55:38 +08:00
|
|
|
function isScriptLikeTag(node) {
|
2018-11-04 23:03:07 +08:00
|
|
|
return (
|
|
|
|
|
node.type === "element" &&
|
|
|
|
|
(node.fullName === "script" ||
|
|
|
|
|
node.fullName === "style" ||
|
2020-04-02 01:35:58 +08:00
|
|
|
node.fullName === "svg:style" ||
|
|
|
|
|
(isUnknownNamespace(node) &&
|
|
|
|
|
(node.name === "script" || node.name === "style")))
|
2018-11-04 23:03:07 +08:00
|
|
|
);
|
2018-09-19 23:07:27 +08:00
|
|
|
}
|
|
|
|
|
|
2018-10-13 13:55:38 +08:00
|
|
|
function isFrontMatterNode(node) {
|
|
|
|
|
return node.type === "yaml" || node.type === "toml";
|
2018-09-19 23:07:27 +08:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
function canHaveInterpolation(node) {
|
|
|
|
|
return node.children && !isScriptLikeTag(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isWhitespaceSensitiveNode(node) {
|
|
|
|
|
return (
|
|
|
|
|
isScriptLikeTag(node) ||
|
|
|
|
|
node.type === "interpolation" ||
|
|
|
|
|
isIndentationSensitiveNode(node)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isIndentationSensitiveNode(node) {
|
|
|
|
|
return getNodeCssStyleWhiteSpace(node).startsWith("pre");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isLeadingSpaceSensitiveNode(node) {
|
2018-11-15 10:34:42 +08:00
|
|
|
const isLeadingSpaceSensitive = _isLeadingSpaceSensitiveNode();
|
2018-10-13 13:55:38 +08:00
|
|
|
|
|
|
|
|
if (
|
2018-11-15 10:34:42 +08:00
|
|
|
isLeadingSpaceSensitive &&
|
2018-11-04 23:03:07 +08:00
|
|
|
!node.prev &&
|
2018-11-15 10:34:42 +08:00
|
|
|
node.parent &&
|
|
|
|
|
node.parent.tagDefinition &&
|
2018-11-04 23:03:07 +08:00
|
|
|
node.parent.tagDefinition.ignoreFirstLf
|
2018-10-13 13:55:38 +08:00
|
|
|
) {
|
2018-11-15 10:34:42 +08:00
|
|
|
return node.type === "interpolation";
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
|
2018-11-15 10:34:42 +08:00
|
|
|
return isLeadingSpaceSensitive;
|
|
|
|
|
|
|
|
|
|
function _isLeadingSpaceSensitiveNode() {
|
|
|
|
|
if (isFrontMatterNode(node)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
(node.type === "text" || node.type === "interpolation") &&
|
|
|
|
|
node.prev &&
|
|
|
|
|
(node.prev.type === "text" || node.prev.type === "interpolation")
|
|
|
|
|
) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!node.parent || node.parent.cssDisplay === "none") {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isPreLikeNode(node.parent)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
!node.prev &&
|
|
|
|
|
(node.parent.type === "root" ||
|
2020-01-06 11:00:09 -08:00
|
|
|
(isPreLikeNode(node) && node.parent) ||
|
2018-11-15 10:34:42 +08:00
|
|
|
isScriptLikeTag(node.parent) ||
|
|
|
|
|
!isFirstChildLeadingSpaceSensitiveCssDisplay(node.parent.cssDisplay))
|
|
|
|
|
) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
node.prev &&
|
|
|
|
|
!isNextLeadingSpaceSensitiveCssDisplay(node.prev.cssDisplay)
|
|
|
|
|
) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
return true;
|
|
|
|
|
}
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
function isTrailingSpaceSensitiveNode(node) {
|
2018-10-13 13:55:38 +08:00
|
|
|
if (isFrontMatterNode(node)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-10 01:00:26 +08:00
|
|
|
if (
|
|
|
|
|
(node.type === "text" || node.type === "interpolation") &&
|
|
|
|
|
node.next &&
|
|
|
|
|
(node.next.type === "text" || node.next.type === "interpolation")
|
|
|
|
|
) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
if (!node.parent || node.parent.cssDisplay === "none") {
|
2018-10-13 13:55:38 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
if (isPreLikeNode(node.parent)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 13:55:38 +08:00
|
|
|
if (
|
2018-11-04 23:03:07 +08:00
|
|
|
!node.next &&
|
|
|
|
|
(node.parent.type === "root" ||
|
2020-01-06 11:00:09 -08:00
|
|
|
(isPreLikeNode(node) && node.parent) ||
|
2018-11-04 23:03:07 +08:00
|
|
|
isScriptLikeTag(node.parent) ||
|
|
|
|
|
!isLastChildTrailingSpaceSensitiveCssDisplay(node.parent.cssDisplay))
|
2018-10-13 13:55:38 +08:00
|
|
|
) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
if (
|
|
|
|
|
node.next &&
|
|
|
|
|
!isPrevTrailingSpaceSensitiveCssDisplay(node.next.cssDisplay)
|
|
|
|
|
) {
|
2018-10-13 13:55:38 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isDanglingSpaceSensitiveNode(node) {
|
2018-11-04 23:03:07 +08:00
|
|
|
return (
|
|
|
|
|
isDanglingSpaceSensitiveCssDisplay(node.cssDisplay) &&
|
|
|
|
|
!isScriptLikeTag(node)
|
|
|
|
|
);
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function forceNextEmptyLine(node) {
|
2018-11-04 23:03:07 +08:00
|
|
|
return (
|
|
|
|
|
isFrontMatterNode(node) ||
|
|
|
|
|
(node.next &&
|
|
|
|
|
node.sourceSpan.end.line + 1 < node.next.sourceSpan.start.line)
|
|
|
|
|
);
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** firstChild leadingSpaces and lastChild trailingSpaces */
|
|
|
|
|
function forceBreakContent(node) {
|
|
|
|
|
return (
|
|
|
|
|
forceBreakChildren(node) ||
|
2018-11-04 23:03:07 +08:00
|
|
|
(node.type === "element" &&
|
2018-10-13 13:55:38 +08:00
|
|
|
node.children.length !== 0 &&
|
2019-11-17 18:06:14 +08:00
|
|
|
(["body", "script", "style"].includes(node.name) ||
|
2020-03-21 22:07:52 +02:00
|
|
|
node.children.some((child) => hasNonTextChild(child)))) ||
|
2018-12-11 12:43:53 +08:00
|
|
|
(node.firstChild &&
|
|
|
|
|
node.firstChild === node.lastChild &&
|
2019-11-09 01:14:31 +01:00
|
|
|
hasLeadingLineBreak(node.firstChild) &&
|
|
|
|
|
(!node.lastChild.isTrailingSpaceSensitive ||
|
|
|
|
|
hasTrailingLineBreak(node.lastChild)))
|
2018-10-13 13:55:38 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** spaces between children */
|
|
|
|
|
function forceBreakChildren(node) {
|
|
|
|
|
return (
|
2018-11-04 23:03:07 +08:00
|
|
|
node.type === "element" &&
|
2018-10-13 13:55:38 +08:00
|
|
|
node.children.length !== 0 &&
|
2019-11-17 18:06:14 +08:00
|
|
|
(["html", "head", "ul", "ol", "select"].includes(node.name) ||
|
2018-10-13 13:55:38 +08:00
|
|
|
(node.cssDisplay.startsWith("table") && node.cssDisplay !== "table-cell"))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function preferHardlineAsLeadingSpaces(node) {
|
|
|
|
|
return (
|
|
|
|
|
preferHardlineAsSurroundingSpaces(node) ||
|
2018-11-04 23:03:07 +08:00
|
|
|
(node.prev && preferHardlineAsTrailingSpaces(node.prev)) ||
|
2018-12-11 12:43:53 +08:00
|
|
|
hasSurroundingLineBreak(node)
|
2018-10-13 13:55:38 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function preferHardlineAsTrailingSpaces(node) {
|
|
|
|
|
return (
|
|
|
|
|
preferHardlineAsSurroundingSpaces(node) ||
|
2018-11-04 23:03:07 +08:00
|
|
|
(node.type === "element" && node.fullName === "br") ||
|
2018-12-11 12:43:53 +08:00
|
|
|
hasSurroundingLineBreak(node)
|
2018-11-09 09:51:31 +08:00
|
|
|
);
|
2018-11-04 23:03:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hasSurroundingLineBreak(node) {
|
|
|
|
|
return hasLeadingLineBreak(node) && hasTrailingLineBreak(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hasLeadingLineBreak(node) {
|
|
|
|
|
return (
|
|
|
|
|
node.hasLeadingSpaces &&
|
|
|
|
|
(node.prev
|
|
|
|
|
? node.prev.sourceSpan.end.line < node.sourceSpan.start.line
|
|
|
|
|
: node.parent.type === "root" ||
|
|
|
|
|
node.parent.startSourceSpan.end.line < node.sourceSpan.start.line)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hasTrailingLineBreak(node) {
|
|
|
|
|
return (
|
|
|
|
|
node.hasTrailingSpaces &&
|
|
|
|
|
(node.next
|
|
|
|
|
? node.next.sourceSpan.start.line > node.sourceSpan.end.line
|
|
|
|
|
: node.parent.type === "root" ||
|
2020-01-13 22:31:03 +08:00
|
|
|
(node.parent.endSourceSpan &&
|
|
|
|
|
node.parent.endSourceSpan.start.line > node.sourceSpan.end.line))
|
2018-10-13 13:55:38 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function preferHardlineAsSurroundingSpaces(node) {
|
|
|
|
|
switch (node.type) {
|
|
|
|
|
case "ieConditionalComment":
|
|
|
|
|
case "comment":
|
|
|
|
|
case "directive":
|
|
|
|
|
return true;
|
2018-11-04 23:03:07 +08:00
|
|
|
case "element":
|
2019-11-17 18:06:14 +08:00
|
|
|
return ["script", "select"].includes(node.name);
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getLastDescendant(node) {
|
|
|
|
|
return node.lastChild ? getLastDescendant(node.lastChild) : node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hasNonTextChild(node) {
|
2020-03-21 22:07:52 +02:00
|
|
|
return node.children && node.children.some((child) => child.type !== "text");
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function inferScriptParser(node) {
|
2018-11-04 23:03:07 +08:00
|
|
|
if (node.name === "script" && !node.attrMap.src) {
|
|
|
|
|
if (
|
|
|
|
|
(!node.attrMap.lang && !node.attrMap.type) ||
|
|
|
|
|
node.attrMap.type === "module" ||
|
|
|
|
|
node.attrMap.type === "text/javascript" ||
|
|
|
|
|
node.attrMap.type === "text/babel" ||
|
2020-01-09 05:14:19 +09:00
|
|
|
node.attrMap.type === "application/javascript" ||
|
|
|
|
|
node.attrMap.lang === "jsx"
|
2018-11-04 23:03:07 +08:00
|
|
|
) {
|
2018-12-27 08:05:19 -05:00
|
|
|
return "babel";
|
2018-11-04 23:03:07 +08:00
|
|
|
}
|
2018-10-13 13:55:38 +08:00
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
if (
|
|
|
|
|
node.attrMap.type === "application/x-typescript" ||
|
|
|
|
|
node.attrMap.lang === "ts" ||
|
|
|
|
|
node.attrMap.lang === "tsx"
|
|
|
|
|
) {
|
|
|
|
|
return "typescript";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.attrMap.type === "text/markdown") {
|
|
|
|
|
return "markdown";
|
|
|
|
|
}
|
2018-12-16 16:21:10 +08:00
|
|
|
|
2019-07-22 14:48:03 +01:00
|
|
|
if (
|
|
|
|
|
node.attrMap.type.endsWith("json") ||
|
|
|
|
|
node.attrMap.type.endsWith("importmap")
|
|
|
|
|
) {
|
2018-12-16 16:21:10 +08:00
|
|
|
return "json";
|
|
|
|
|
}
|
2020-01-21 07:55:29 +01:00
|
|
|
|
|
|
|
|
if (node.attrMap.type === "text/x-handlebars-template") {
|
|
|
|
|
return "glimmer";
|
|
|
|
|
}
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.name === "style") {
|
2019-11-09 02:33:59 +08:00
|
|
|
if (
|
|
|
|
|
!node.attrMap.lang ||
|
|
|
|
|
node.attrMap.lang === "postcss" ||
|
|
|
|
|
node.attrMap.lang === "css"
|
|
|
|
|
) {
|
2018-11-04 23:03:07 +08:00
|
|
|
return "css";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.attrMap.lang === "scss") {
|
|
|
|
|
return "scss";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.attrMap.lang === "less") {
|
|
|
|
|
return "less";
|
|
|
|
|
}
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isBlockLikeCssDisplay(cssDisplay) {
|
2018-11-04 23:03:07 +08:00
|
|
|
return (
|
|
|
|
|
cssDisplay === "block" ||
|
|
|
|
|
cssDisplay === "list-item" ||
|
|
|
|
|
cssDisplay.startsWith("table")
|
|
|
|
|
);
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
function isFirstChildLeadingSpaceSensitiveCssDisplay(cssDisplay) {
|
|
|
|
|
return !isBlockLikeCssDisplay(cssDisplay) && cssDisplay !== "inline-block";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isLastChildTrailingSpaceSensitiveCssDisplay(cssDisplay) {
|
|
|
|
|
return !isBlockLikeCssDisplay(cssDisplay) && cssDisplay !== "inline-block";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isPrevTrailingSpaceSensitiveCssDisplay(cssDisplay) {
|
|
|
|
|
return !isBlockLikeCssDisplay(cssDisplay);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isNextLeadingSpaceSensitiveCssDisplay(cssDisplay) {
|
|
|
|
|
return !isBlockLikeCssDisplay(cssDisplay);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isDanglingSpaceSensitiveCssDisplay(cssDisplay) {
|
|
|
|
|
return !isBlockLikeCssDisplay(cssDisplay) && cssDisplay !== "inline-block";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isPreLikeNode(node) {
|
|
|
|
|
return getNodeCssStyleWhiteSpace(node).startsWith("pre");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function countParents(path, predicate = () => true) {
|
|
|
|
|
let counter = 0;
|
|
|
|
|
for (let i = path.stack.length - 1; i >= 0; i--) {
|
|
|
|
|
const value = path.stack[i];
|
|
|
|
|
if (
|
|
|
|
|
value &&
|
|
|
|
|
typeof value === "object" &&
|
|
|
|
|
!Array.isArray(value) &&
|
|
|
|
|
predicate(value)
|
|
|
|
|
) {
|
|
|
|
|
counter++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return counter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hasParent(node, fn) {
|
|
|
|
|
let current = node;
|
|
|
|
|
|
|
|
|
|
while (current) {
|
|
|
|
|
if (fn(current)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current = current.parent;
|
2018-10-13 13:55:38 +08:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getNodeCssStyleDisplay(node, options) {
|
|
|
|
|
if (node.prev && node.prev.type === "comment") {
|
2018-10-13 13:55:38 +08:00
|
|
|
// <!-- display: block -->
|
2018-11-04 23:03:07 +08:00
|
|
|
const match = node.prev.value.match(/^\s*display:\s*([a-z]+)\s*$/);
|
2018-10-13 13:55:38 +08:00
|
|
|
if (match) {
|
|
|
|
|
return match[1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
let isInSvgForeignObject = false;
|
|
|
|
|
if (node.type === "element" && node.namespace === "svg") {
|
2020-03-21 22:07:52 +02:00
|
|
|
if (hasParent(node, (parent) => parent.fullName === "svg:foreignObject")) {
|
2018-11-04 23:03:07 +08:00
|
|
|
isInSvgForeignObject = true;
|
|
|
|
|
} else {
|
|
|
|
|
return node.name === "svg" ? "inline-block" : "block";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 13:55:38 +08:00
|
|
|
switch (options.htmlWhitespaceSensitivity) {
|
|
|
|
|
case "strict":
|
|
|
|
|
return "inline";
|
|
|
|
|
case "ignore":
|
|
|
|
|
return "block";
|
|
|
|
|
default:
|
|
|
|
|
return (
|
2018-11-04 23:03:07 +08:00
|
|
|
(node.type === "element" &&
|
2020-01-20 22:39:19 +08:00
|
|
|
(!node.namespace ||
|
|
|
|
|
isInSvgForeignObject ||
|
|
|
|
|
isUnknownNamespace(node)) &&
|
2018-11-04 23:03:07 +08:00
|
|
|
CSS_DISPLAY_TAGS[node.name]) ||
|
|
|
|
|
CSS_DISPLAY_DEFAULT
|
2018-10-13 13:55:38 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-20 22:39:19 +08:00
|
|
|
function isUnknownNamespace(node) {
|
|
|
|
|
return (
|
|
|
|
|
node.type === "element" &&
|
|
|
|
|
!node.hasExplicitNamespace &&
|
|
|
|
|
!["html", "svg"].includes(node.namespace)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 13:55:38 +08:00
|
|
|
function getNodeCssStyleWhiteSpace(node) {
|
|
|
|
|
return (
|
2018-11-04 23:03:07 +08:00
|
|
|
(node.type === "element" &&
|
2020-01-20 22:39:19 +08:00
|
|
|
(!node.namespace || isUnknownNamespace(node)) &&
|
2018-11-04 23:03:07 +08:00
|
|
|
CSS_WHITE_SPACE_TAGS[node.name]) ||
|
|
|
|
|
CSS_WHITE_SPACE_DEFAULT
|
2018-10-13 13:55:38 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getMinIndentation(text) {
|
|
|
|
|
let minIndentation = Infinity;
|
|
|
|
|
|
|
|
|
|
for (const lineText of text.split("\n")) {
|
2018-11-04 23:03:07 +08:00
|
|
|
if (lineText.length === 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 13:55:38 +08:00
|
|
|
if (/\S/.test(lineText[0])) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const indentation = lineText.match(/^\s*/)[0].length;
|
|
|
|
|
|
|
|
|
|
if (lineText.length === indentation) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (indentation < minIndentation) {
|
|
|
|
|
minIndentation = indentation;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return minIndentation === Infinity ? 0 : minIndentation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function dedentString(text, minIndent = getMinIndentation(text)) {
|
|
|
|
|
return minIndent === 0
|
|
|
|
|
? text
|
|
|
|
|
: text
|
|
|
|
|
.split("\n")
|
2020-03-21 22:07:52 +02:00
|
|
|
.map((lineText) => lineText.slice(minIndent))
|
2018-10-13 13:55:38 +08:00
|
|
|
.join("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeParts(parts) {
|
|
|
|
|
const newParts = [];
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
const restParts = parts.slice();
|
|
|
|
|
while (restParts.length !== 0) {
|
|
|
|
|
const part = restParts.shift();
|
|
|
|
|
|
2018-10-13 13:55:38 +08:00
|
|
|
if (!part) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
if (part.type === "concat") {
|
2020-02-25 02:05:49 +01:00
|
|
|
restParts.unshift(...part.parts);
|
2018-11-04 23:03:07 +08:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-13 13:55:38 +08:00
|
|
|
if (
|
|
|
|
|
newParts.length !== 0 &&
|
|
|
|
|
typeof newParts[newParts.length - 1] === "string" &&
|
|
|
|
|
typeof part === "string"
|
|
|
|
|
) {
|
|
|
|
|
newParts.push(newParts.pop() + part);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newParts.push(part);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return newParts;
|
2018-09-19 23:07:27 +08:00
|
|
|
}
|
|
|
|
|
|
2018-11-04 23:03:07 +08:00
|
|
|
function identity(x) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-23 12:33:48 +08:00
|
|
|
function shouldNotPrintClosingTag(node, options) {
|
2018-11-09 23:26:59 +08:00
|
|
|
return (
|
|
|
|
|
!node.isSelfClosing &&
|
|
|
|
|
!node.endSourceSpan &&
|
2018-11-23 12:33:48 +08:00
|
|
|
(hasPrettierIgnore(node) || shouldPreserveContent(node.parent, options))
|
2018-11-09 23:26:59 +08:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-05 11:15:09 +08:00
|
|
|
function countChars(text, char) {
|
|
|
|
|
let counter = 0;
|
|
|
|
|
for (let i = 0; i < text.length; i++) {
|
|
|
|
|
if (text[i] === char) {
|
|
|
|
|
counter++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return counter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function unescapeQuoteEntities(text) {
|
|
|
|
|
return text.replace(/'/g, "'").replace(/"/g, '"');
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-19 23:07:27 +08:00
|
|
|
module.exports = {
|
2018-09-27 20:18:00 +08:00
|
|
|
HTML_ELEMENT_ATTRIBUTES,
|
2018-09-22 21:53:38 +08:00
|
|
|
HTML_TAGS,
|
2018-11-04 23:03:07 +08:00
|
|
|
canHaveInterpolation,
|
2018-12-05 11:15:09 +08:00
|
|
|
countChars,
|
2018-11-04 23:03:07 +08:00
|
|
|
countParents,
|
2018-10-13 13:55:38 +08:00
|
|
|
dedentString,
|
|
|
|
|
forceBreakChildren,
|
|
|
|
|
forceBreakContent,
|
|
|
|
|
forceNextEmptyLine,
|
|
|
|
|
getLastDescendant,
|
|
|
|
|
getNodeCssStyleDisplay,
|
|
|
|
|
getNodeCssStyleWhiteSpace,
|
2018-11-04 23:03:07 +08:00
|
|
|
getPrettierIgnoreAttributeCommentData,
|
2018-09-19 23:07:27 +08:00
|
|
|
hasPrettierIgnore,
|
2018-11-04 23:03:07 +08:00
|
|
|
identity,
|
2018-10-13 13:55:38 +08:00
|
|
|
inferScriptParser,
|
|
|
|
|
isDanglingSpaceSensitiveNode,
|
|
|
|
|
isFrontMatterNode,
|
2018-11-04 23:03:07 +08:00
|
|
|
isIndentationSensitiveNode,
|
2018-10-13 13:55:38 +08:00
|
|
|
isLeadingSpaceSensitiveNode,
|
2018-11-04 23:03:07 +08:00
|
|
|
isPreLikeNode,
|
2018-10-13 13:55:38 +08:00
|
|
|
isScriptLikeTag,
|
2018-11-23 21:25:58 +08:00
|
|
|
isTextLikeNode,
|
2018-10-13 13:55:38 +08:00
|
|
|
isTrailingSpaceSensitiveNode,
|
2018-11-04 23:03:07 +08:00
|
|
|
isWhitespaceSensitiveNode,
|
2020-01-20 22:39:19 +08:00
|
|
|
isUnknownNamespace,
|
2018-10-13 13:55:38 +08:00
|
|
|
normalizeParts,
|
|
|
|
|
preferHardlineAsLeadingSpaces,
|
|
|
|
|
preferHardlineAsTrailingSpaces,
|
2018-11-09 23:26:59 +08:00
|
|
|
shouldNotPrintClosingTag,
|
2018-12-05 11:15:09 +08:00
|
|
|
shouldPreserveContent,
|
2020-03-21 22:07:52 +02:00
|
|
|
unescapeQuoteEntities,
|
2018-09-19 23:07:27 +08:00
|
|
|
};
|