Files
test-repo/src/language-css/printer-postcss.js
T

911 lines
27 KiB
JavaScript
Raw Normal View History

"use strict";
const clean = require("./clean");
const privateUtil = require("../common/util");
const sharedUtil = require("../common/util-shared");
2018-04-26 13:53:52 +03:00
2017-12-26 12:23:50 +11:00
const doc = require("../doc");
const docBuilders = doc.builders;
const concat = docBuilders.concat;
const join = docBuilders.join;
const line = docBuilders.line;
const hardline = docBuilders.hardline;
const softline = docBuilders.softline;
const group = docBuilders.group;
2017-06-21 15:13:51 -07:00
const fill = docBuilders.fill;
const indent = docBuilders.indent;
2018-05-17 13:39:22 +03:00
const dedent = docBuilders.dedent;
const ifBreak = docBuilders.ifBreak;
2018-04-26 13:53:52 +03:00
const docUtils = doc.utils;
const removeLines = docUtils.removeLines;
const utils = require("./utils");
2018-05-15 01:08:04 +03:00
2018-04-26 13:53:52 +03:00
const getAncestorNode = utils.getAncestorNode;
const getPropOfDeclNode = utils.getPropOfDeclNode;
2018-05-15 01:08:04 +03:00
const maybeToLowerCase = utils.maybeToLowerCase;
2018-04-26 13:53:52 +03:00
const insideValueFunctionNode = utils.insideValueFunctionNode;
const insideICSSRuleNode = utils.insideICSSRuleNode;
const insideAtRuleNode = utils.insideAtRuleNode;
2018-05-17 13:39:22 +03:00
const insideURLFunctionInImportAtRuleNode =
utils.insideURLFunctionInImportAtRuleNode;
2018-04-26 13:53:52 +03:00
const isKeyframeAtRuleKeywords = utils.isKeyframeAtRuleKeywords;
2018-05-15 01:08:04 +03:00
const isHTMLTag = utils.isHTMLTag;
2018-04-26 13:53:52 +03:00
const isWideKeywords = utils.isWideKeywords;
2018-05-15 01:08:04 +03:00
const isSCSS = utils.isSCSS;
const isLastNode = utils.isLastNode;
const isSCSSControlDirectiveNode = utils.isSCSSControlDirectiveNode;
const isDetachedRulesetDeclarationNode = utils.isDetachedRulesetDeclarationNode;
const isRelationalOperatorNode = utils.isRelationalOperatorNode;
const isEqualityOperatorNode = utils.isEqualityOperatorNode;
const isMathOperatorNode = utils.isMathOperatorNode;
const isEachKeywordNode = utils.isEachKeywordNode;
const isParenGroupNode = utils.isParenGroupNode;
const isForKeywordNode = utils.isForKeywordNode;
const isURLFunctionNode = utils.isURLFunctionNode;
const isIfElseKeywordNode = utils.isIfElseKeywordNode;
2018-04-26 13:53:52 +03:00
const hasLessExtendValueNode = utils.hasLessExtendValueNode;
2018-05-15 01:08:04 +03:00
const hasComposesValueNode = utils.hasComposesValueNode;
2018-04-26 13:53:52 +03:00
const hasParensAroundValueNode = utils.hasParensAroundValueNode;
2018-05-17 13:39:22 +03:00
const isKeyValuePairNode = utils.isKeyValuePairNode;
2018-05-15 01:08:04 +03:00
const isDetachedRulesetCallNode = utils.isDetachedRulesetCallNode;
const isPostcssSimpleVarNode = utils.isPostcssSimpleVarNode;
2018-05-17 13:39:22 +03:00
const isSCSSMapItemNode = utils.isSCSSMapItemNode;
function shouldPrintComma(options) {
switch (options.trailingComma) {
case "all":
case "es5":
return true;
case "none":
default:
return false;
}
}
function genericPrint(path, options, print) {
const node = path.getValue();
2017-09-03 22:40:44 +02:00
/* istanbul ignore if */
if (!node) {
return "";
}
if (typeof node === "string") {
return node;
}
switch (node.type) {
case "front-matter":
2018-05-14 22:17:15 -03:00
return concat([node.value, hardline]);
case "css-root": {
2018-01-12 00:05:57 +03:00
const nodes = printNodeSequence(path, options, print);
if (nodes.parts.length) {
return concat([nodes, hardline]);
}
return nodes;
}
case "css-comment": {
if (node.raws.content) {
return node.raws.content;
}
const text = options.originalText.slice(
options.locStart(node),
options.locEnd(node)
);
const rawText = node.raws.text || node.text;
// Workaround a bug where the location is off.
// https://github.com/postcss/postcss-scss/issues/63
if (text.indexOf(rawText) === -1) {
if (node.raws.inline) {
return concat(["// ", rawText]);
}
return concat(["/* ", rawText, " */"]);
}
return text;
}
case "css-rule": {
return concat([
path.call(print, "selector"),
node.important ? " !important" : "",
node.nodes
? concat([
" {",
node.nodes.length > 0
? indent(
concat([hardline, printNodeSequence(path, options, print)])
)
: "",
hardline,
"}",
2018-05-15 01:08:04 +03:00
isDetachedRulesetDeclarationNode(node) ? ";" : ""
])
: ";"
]);
}
case "css-decl": {
return concat([
node.raws.before.replace(/[\s;]/g, ""),
2018-04-26 13:53:52 +03:00
insideICSSRuleNode(path) ? node.prop : maybeToLowerCase(node.prop),
2018-02-06 18:09:42 +03:00
node.raws.between.trim() === ":" ? ":" : node.raws.between.trim(),
2018-04-26 13:53:52 +03:00
// When the following less construct &:extend(.foo); is parsed with scss,
// it will put a space after `:` and break it. Ideally we should parse
// less files with less, but we can hardcode this to work with scss as
// well.
hasLessExtendValueNode(node) ? "" : " ",
hasComposesValueNode(node)
? removeLines(path.call(print, "value"))
: path.call(print, "value"),
2018-02-06 18:09:42 +03:00
node.raws.important
? node.raws.important.replace(/\s*!\s*important/i, " !important")
2018-04-11 22:39:13 -06:00
: node.important
? " !important"
: "",
2018-02-06 18:09:42 +03:00
node.raws.scssDefault
? node.raws.scssDefault.replace(/\s*!default/i, " !default")
2018-04-11 22:39:13 -06:00
: node.scssDefault
? " !default"
: "",
2018-02-06 18:09:42 +03:00
node.raws.scssGlobal
? node.raws.scssGlobal.replace(/\s*!global/i, " !global")
2018-04-11 22:39:13 -06:00
: node.scssGlobal
? " !global"
: "",
node.nodes
? concat([
" {",
indent(
concat([softline, printNodeSequence(path, options, print)])
),
softline,
"}"
])
: ";"
]);
}
case "css-atrule": {
return concat([
"@",
// If a Less file ends up being parsed with the SCSS parser, Less
2018-04-26 13:53:52 +03:00
// variable declarations will be parsed as at-rules with names ending
// with a colon, so keep the original case then.
2018-05-15 01:08:04 +03:00
isDetachedRulesetCallNode(node) || node.name.endsWith(":")
? node.name
: maybeToLowerCase(node.name),
2018-04-26 13:53:52 +03:00
node.params
2017-09-03 21:22:28 +02:00
? concat([
2018-05-15 01:08:04 +03:00
isDetachedRulesetCallNode(node) ? "" : " ",
2017-09-03 21:22:28 +02:00
path.call(print, "params")
])
: "",
node.selector
? indent(concat([" ", path.call(print, "selector")]))
: "",
node.value
? group(
concat([
" ",
path.call(print, "value"),
2018-04-26 13:53:52 +03:00
isSCSSControlDirectiveNode(node)
? hasParensAroundValueNode(node)
2018-04-11 22:39:13 -06:00
? " "
: line
2018-02-22 12:00:08 +03:00
: ""
])
)
2018-04-11 22:39:13 -06:00
: node.name === "else"
? " "
: "",
node.nodes
? concat([
2018-04-26 13:53:52 +03:00
isSCSSControlDirectiveNode(node) ? "" : " ",
"{",
indent(
concat([
node.nodes.length > 0 ? softline : "",
printNodeSequence(path, options, print)
])
),
softline,
"}"
])
: ";"
]);
}
// postcss-media-query-parser
case "media-query-list": {
const parts = [];
path.each(childPath => {
const node = childPath.getValue();
if (node.type === "media-query" && node.value === "") {
return;
}
parts.push(childPath.call(print));
}, "nodes");
return group(indent(join(line, parts)));
}
case "media-query": {
return concat([
join(" ", path.map(print, "nodes")),
2018-02-22 12:00:08 +03:00
isLastNode(path, node) ? "" : ","
]);
}
case "media-type": {
return adjustNumbers(adjustStrings(node.value, options));
}
case "media-feature-expression": {
if (!node.nodes) {
return node.value;
}
return concat(["(", concat(path.map(print, "nodes")), ")"]);
}
case "media-feature": {
2017-09-03 21:22:28 +02:00
return maybeToLowerCase(
adjustStrings(node.value.replace(/ +/g, " "), options)
2017-09-03 21:22:28 +02:00
);
}
case "media-colon": {
return concat([node.value, " "]);
}
case "media-value": {
return adjustNumbers(adjustStrings(node.value, options));
}
case "media-keyword": {
return adjustStrings(node.value, options);
}
case "media-url": {
return adjustStrings(
node.value.replace(/^url\(\s+/gi, "url(").replace(/\s+\)$/gi, ")"),
options
);
}
case "media-unknown": {
2018-05-15 00:00:45 +03:00
return node.value;
}
// postcss-selector-parser
case "selector-root": {
const atRuleAncestorNode = getAncestorNode(path, "css-atrule");
2018-02-22 12:00:08 +03:00
const insideAtRuleNode =
atRuleAncestorNode &&
["extend", "custom-selector", "nest"].indexOf(
atRuleAncestorNode.name
) !== -1;
return group(
concat([
2018-02-22 12:00:08 +03:00
atRuleAncestorNode && atRuleAncestorNode.name === "custom-selector"
? concat([atRuleAncestorNode.customSelector, line])
: "",
join(
2018-02-22 12:00:08 +03:00
concat([",", insideAtRuleNode ? line : hardline]),
path.map(print, "nodes")
)
])
);
}
case "selector-comment": {
return node.value;
}
case "selector-string": {
return adjustStrings(node.value, options);
}
case "selector-tag": {
const parentNode = path.getParentNode();
const index = parentNode && parentNode.nodes.indexOf(node);
const prevNode = index && parentNode.nodes[index - 1];
return concat([
node.namespace
? concat([node.namespace === true ? "" : node.namespace.trim(), "|"])
: "",
prevNode.type === "selector-nesting"
? node.value
: adjustNumbers(
isHTMLTag(node.value) ||
isKeyframeAtRuleKeywords(path, node.value)
? node.value.toLowerCase()
: node.value
)
]);
}
case "selector-id": {
return concat(["#", node.value]);
}
case "selector-class": {
return concat([".", adjustNumbers(adjustStrings(node.value, options))]);
}
case "selector-attribute": {
return concat([
"[",
node.namespace
? concat([node.namespace === true ? "" : node.namespace.trim(), "|"])
: "",
node.attribute.trim(),
node.operator ? node.operator : "",
node.value
? quoteAttributeValue(
adjustStrings(node.value.trim(), options),
options
)
: "",
node.insensitive ? " i" : "",
"]"
]);
}
case "selector-combinator": {
if (
node.value === "+" ||
node.value === ">" ||
node.value === "~" ||
node.value === ">>>"
) {
const parentNode = path.getParentNode();
2017-07-08 14:07:39 +02:00
const leading =
parentNode.type === "selector-selector" &&
parentNode.nodes[0] === node
2017-07-08 14:07:39 +02:00
? ""
: line;
2018-02-22 12:00:08 +03:00
return concat([leading, node.value, isLastNode(path, node) ? "" : " "]);
}
const leading = node.value.trim().startsWith("(") ? line : "";
2017-09-03 21:22:28 +02:00
const value =
adjustNumbers(adjustStrings(node.value.trim(), options)) || line;
2017-09-03 21:22:28 +02:00
return concat([leading, value]);
}
case "selector-universal": {
return concat([
node.namespace
? concat([node.namespace === true ? "" : node.namespace.trim(), "|"])
: "",
adjustNumbers(node.value)
]);
}
case "selector-selector": {
return group(indent(concat(path.map(print, "nodes"))));
}
case "selector-pseudo": {
return concat([
maybeToLowerCase(node.value),
node.nodes && node.nodes.length > 0
? concat(["(", join(", ", path.map(print, "nodes")), ")"])
: ""
]);
}
case "selector-nesting": {
return node.value;
}
2018-05-15 00:00:45 +03:00
case "selector-unknown": {
const ruleAncestorNode = getAncestorNode(path, "css-rule");
// Nested SCSS property
if (ruleAncestorNode && ruleAncestorNode.isSCSSNesterProperty) {
return adjustNumbers(
adjustStrings(maybeToLowerCase(node.value), options)
);
}
return node.value;
}
// postcss-values-parser
case "value-root": {
return path.call(print, "group");
}
2018-02-06 18:09:42 +03:00
case "value-comment": {
return concat([
node.inline ? "//" : "/*",
node.value,
node.inline ? "" : "*/"
]);
2018-02-06 18:09:42 +03:00
}
case "value-comma_group": {
const parentNode = path.getParentNode();
2018-04-26 13:53:52 +03:00
const declAncestorProp = getPropOfDeclNode(path);
const isGridValue =
declAncestorProp &&
parentNode.type === "value-value" &&
(declAncestorProp === "grid" ||
declAncestorProp.startsWith("grid-template"));
const atRuleAncestorNode = getAncestorNode(path, "css-atrule");
const isControlDirective =
2018-04-26 13:53:52 +03:00
atRuleAncestorNode && isSCSSControlDirectiveNode(atRuleAncestorNode);
const printed = path.map(print, "groups");
const parts = [];
2018-04-26 13:53:52 +03:00
const insideURLFunction = insideValueFunctionNode(path, "url");
2018-05-22 16:05:47 +03:00
let insideSCSSInterpolationInString = false;
let didBreak = false;
for (let i = 0; i < node.groups.length; ++i) {
parts.push(printed[i]);
2018-02-16 21:58:21 +03:00
// Ignore value inside `url()`
if (insideURLFunction) {
continue;
}
const iPrevNode = node.groups[i - 1];
const iNode = node.groups[i];
const iNextNode = node.groups[i + 1];
const iNextNextNode = node.groups[i + 2];
// Ignore after latest node (i.e. before semicolon)
2018-02-16 21:58:21 +03:00
if (!iNextNode) {
continue;
}
2018-05-22 16:05:47 +03:00
// Ignore spaces before/after string interpolation (i.e. `"#{my-fn("_")}"`)
const isStartSCSSinterpolationInString =
iNode.type === "value-string" && iNode.value.startsWith("#{");
const isEndingSCSSinterpolationInString =
insideSCSSInterpolationInString &&
iNextNode.type === "value-string" &&
iNextNode.value.endsWith("}");
if (
isStartSCSSinterpolationInString ||
isEndingSCSSinterpolationInString
) {
insideSCSSInterpolationInString = !insideSCSSInterpolationInString;
continue;
}
if (insideSCSSInterpolationInString) {
continue;
}
// Ignore colon
2018-02-16 21:58:21 +03:00
if (iNode.value === ":") {
continue;
}
// Ignore `@` in Less (i.e. `@@var;`)
2018-02-16 21:58:21 +03:00
if (iNode.type === "value-atword" && iNode.value === "") {
continue;
}
// Ignore `~` in Less (i.e. `content: ~"^//* some horrible but needed css hack";`)
2018-02-16 21:58:21 +03:00
if (iNode.value === "~") {
continue;
}
2018-05-14 13:47:46 +03:00
// Ignore `\` (i.e. `$variable: \@small;`)
if (iNode.value === "\\") {
continue;
}
// Ignore `$$` (i.e. `background-color: $$(style)Color;`)
2018-05-15 01:08:04 +03:00
if (isPostcssSimpleVarNode(iNode, iNextNode)) {
2018-05-14 13:47:46 +03:00
continue;
}
if (
(iPrevNode &&
iPrevNode.type === "value-comment" &&
iPrevNode.inline) ||
(iNextNode.type === "value-comment" && iNextNode.inline)
) {
continue;
}
2018-02-16 21:58:21 +03:00
const isHash = iNode.type === "value-word" && iNode.value === "#";
const isLeftCurlyBrace =
iNode.type === "value-word" && iNode.value === "{";
const isNextLeftCurlyBrace =
iNextNode.type === "value-word" && iNextNode.value === "{";
const isRightCurlyBrace =
iNode.type === "value-word" && iNode.value === "}";
const isNextRightCurlyBrace =
iNextNode.type === "value-word" && iNextNode.value === "}";
// Ignore interpolation in SCSS (i.e. `#{variable}`)
if (
2018-02-16 21:58:21 +03:00
isHash ||
isLeftCurlyBrace ||
isNextRightCurlyBrace ||
(isNextLeftCurlyBrace &&
iNextNode.raws &&
iNextNode.raws.before === "") ||
(isRightCurlyBrace && iNextNode.raws && iNextNode.raws.before === "")
) {
continue;
}
// Ignore css variables and interpolation in SCSS (i.e. `--#{$var}`)
if (iNode.value === "--" && iNextNode.value === "#") {
continue;
}
2018-02-16 21:58:21 +03:00
const isNextHash =
iNextNode.type === "value-word" && iNextNode.value === "#";
const isMathOperator = isMathOperatorNode(iNode);
const isNextMathOperator = isMathOperatorNode(iNextNode);
const isMultiplication =
!isNextHash && isMathOperator && iNode.value === "*";
const isNextMultiplication =
!isRightCurlyBrace && isNextMathOperator && iNextNode.value === "*";
const isDivision = !isNextHash && isMathOperator && iNode.value === "/";
const isNextDivision =
!isRightCurlyBrace && isNextMathOperator && iNextNode.value === "/";
const isAddition = !isNextHash && isMathOperator && iNode.value === "+";
const isNextAddition =
!isRightCurlyBrace && isNextMathOperator && iNextNode.value === "+";
const isPrevFunction = iPrevNode && iPrevNode.type === "value-func";
const isFunction = iNode.type === "value-func";
const isNextFunction = iNextNode.type === "value-func";
const isNextNextFunction =
iNextNextNode && iNextNextNode.type === "value-func";
const isPrevWord =
iPrevNode &&
["value-word", "value-atword"].indexOf(iPrevNode.type) !== -1;
const isWord =
["value-word", "value-atword"].indexOf(iNode.type) !== -1;
const isNextWord =
["value-word", "value-atword"].indexOf(iNextNode.type) !== -1;
const isNextNextWord =
iNextNextNode &&
["value-word", "value-atword"].indexOf(iNextNextNode.type) !== -1;
// Math operators
2018-04-26 13:53:52 +03:00
const insideCalcFunction = insideValueFunctionNode(path, "calc");
2018-02-16 21:58:21 +03:00
const hasSpaceBeforeOperator =
isNextNextFunction || isNextNextWord || isFunction || isWord;
const hasSpaceAfterOperator =
isNextFunction || isNextWord || isPrevFunction || isPrevWord;
if (
(isMathOperator || isNextMathOperator) &&
// Multiplication
!isMultiplication &&
!isNextMultiplication &&
// Division
!(isNextDivision && (hasSpaceBeforeOperator || insideCalcFunction)) &&
!(isDivision && (hasSpaceAfterOperator || insideCalcFunction)) &&
// Addition
!(isNextAddition && hasSpaceBeforeOperator) &&
!(isAddition && hasSpaceAfterOperator)
) {
const isNextParenGroup = isParenGroupNode(iNextNode);
const isNextValueNumber = iNextNode.type === "value-number";
if (
(iNextNode.raws && iNextNode.raws.before === "") ||
(isMathOperator &&
(isNextParenGroup ||
isNextWord ||
isNextValueNumber ||
isMathOperatorNode(iNextNode)) &&
(!iPrevNode || (iPrevNode && isMathOperatorNode(iPrevNode))))
) {
continue;
}
}
const isEqualityOperator =
2018-02-16 21:58:21 +03:00
isControlDirective && isEqualityOperatorNode(iNode);
const isRelationalOperator =
2018-02-16 21:58:21 +03:00
isControlDirective && isRelationalOperatorNode(iNode);
const isNextEqualityOperator =
2018-02-16 21:58:21 +03:00
isControlDirective && isEqualityOperatorNode(iNextNode);
const isNextRelationalOperator =
2018-02-16 21:58:21 +03:00
isControlDirective && isRelationalOperatorNode(iNextNode);
const isNextIfElseKeyword =
2018-02-16 21:58:21 +03:00
isControlDirective && isIfElseKeywordNode(iNextNode);
const isEachKeyword = isControlDirective && isEachKeywordNode(iNode);
const isNextEachKeyword =
2018-02-16 21:58:21 +03:00
isControlDirective && isEachKeywordNode(iNextNode);
const isForKeyword =
atRuleAncestorNode &&
atRuleAncestorNode.name === "for" &&
2018-02-16 21:58:21 +03:00
isForKeywordNode(iNode);
const isNextForKeyword =
2018-02-16 21:58:21 +03:00
isControlDirective && isForKeywordNode(iNextNode);
const IsNextColon = iNextNode.value === ":";
if (isGridValue) {
2018-02-16 21:58:21 +03:00
if (iNode.source.start.line !== iNextNode.source.start.line) {
parts.push(hardline);
didBreak = true;
} else {
parts.push(" ");
}
} else if (iNode.type === "value-comment" && iNode.inline) {
parts.push(hardline);
} else if (
isNextMathOperator ||
isNextEqualityOperator ||
isNextRelationalOperator ||
isNextIfElseKeyword ||
isForKeyword ||
isEachKeyword ||
2018-04-26 13:53:52 +03:00
(atRuleAncestorNode &&
atRuleAncestorNode.name.toLowerCase() === "namespace")
) {
parts.push(" ");
} else if (
!IsNextColon ||
isEqualityOperator ||
isRelationalOperator ||
isNextForKeyword ||
isNextEachKeyword
) {
parts.push(line);
}
}
if (didBreak) {
parts.unshift(hardline);
}
if (isControlDirective) {
return group(indent(concat(parts)));
}
// Indent is not needed for import url when url is very long
// and node has two groups
// when type is value-comma_group
// example @import url("verylongurl") projection,tv
2018-05-17 13:39:22 +03:00
if (insideURLFunctionInImportAtRuleNode(path)) {
return group(fill(parts));
}
2018-05-17 13:39:22 +03:00
return group(indent(fill(parts)));
}
case "value-paren_group": {
const parentNode = path.getParentNode();
if (
2018-04-26 13:53:52 +03:00
parentNode &&
2018-05-15 01:08:04 +03:00
isURLFunctionNode(parentNode) &&
(node.groups.length === 1 ||
(node.groups.length > 0 &&
node.groups[0].type === "value-comma_group" &&
node.groups[0].groups.length > 0 &&
node.groups[0].groups[0].type === "value-word" &&
node.groups[0].groups[0].value.startsWith("data:")))
) {
return concat([
node.open ? path.call(print, "open") : "",
join(",", path.map(print, "groups")),
node.close ? path.call(print, "close") : ""
]);
}
if (!node.open) {
2017-06-21 15:13:51 -07:00
const printed = path.map(print, "groups");
const res = [];
for (let i = 0; i < printed.length; i++) {
if (i !== 0) {
res.push(concat([",", line]));
}
res.push(printed[i]);
}
return group(indent(fill(res)));
}
2018-05-17 13:39:22 +03:00
const isSCSSMapItem = isSCSSMapItemNode(path);
2017-10-21 21:35:22 -04:00
return group(
concat([
node.open ? path.call(print, "open") : "",
indent(
concat([
softline,
2017-10-21 21:35:22 -04:00
join(
2018-05-17 13:39:22 +03:00
concat([",", line]),
path.map(childPath => {
const node = childPath.getValue();
const printed = print(childPath);
// Key/Value pair in open paren already indented
if (
isKeyValuePairNode(node) &&
node.type === "value-comma_group" &&
node.groups &&
node.groups[2] &&
node.groups[2].type === "value-paren_group"
) {
printed.contents.contents.parts[1] = group(
printed.contents.contents.parts[1]
);
return group(dedent(printed));
}
return printed;
}, "groups")
2017-10-21 21:35:22 -04:00
)
])
),
2018-05-17 13:39:22 +03:00
ifBreak(
isSCSS(options.parser, options.originalText) &&
isSCSSMapItem &&
shouldPrintComma(options)
? ","
: ""
),
softline,
node.close ? path.call(print, "close") : ""
2018-05-17 13:39:22 +03:00
]),
{
shouldBreak: isSCSSMapItem
}
);
}
case "value-value": {
return path.call(print, "group");
}
case "value-func": {
2018-04-26 13:53:52 +03:00
const insideAtRuleSupportsNode = insideAtRuleNode(path, "supports");
const isKeyword =
["not", "and", "or"].indexOf(node.value.toLowerCase()) !== -1;
return concat([
node.value,
2018-04-26 13:53:52 +03:00
insideAtRuleSupportsNode && isKeyword ? " " : "",
path.call(print, "group")
]);
}
case "value-paren": {
return node.value;
}
case "value-number": {
return concat([printNumber(node.value), maybeToLowerCase(node.unit)]);
}
case "value-operator": {
return node.value;
}
case "value-word": {
if ((node.isColor && node.isHex) || isWideKeywords(node.value)) {
return node.value.toLowerCase();
}
2018-05-15 01:08:04 +03:00
return node.value;
}
case "value-colon": {
2018-04-26 13:53:52 +03:00
return concat([
node.value,
insideValueFunctionNode(path, "url") ? "" : line
]);
}
case "value-comma": {
return concat([node.value, " "]);
}
case "value-string": {
return privateUtil.printString(
node.raws.quote + node.value + node.raws.quote,
options
);
}
case "value-atword": {
return concat(["@", node.value]);
}
2018-03-07 21:15:06 +03:00
case "value-unicode-range": {
return node.value;
}
2018-05-15 00:00:45 +03:00
case "value-unknown": {
return node.value;
}
default:
2017-09-03 22:40:44 +02:00
/* istanbul ignore next */
2018-02-22 12:00:08 +03:00
throw new Error(`Unknown postcss type ${JSON.stringify(node.type)}`);
}
}
function printNodeSequence(path, options, print) {
const node = path.getValue();
const parts = [];
let i = 0;
path.map(pathChild => {
2017-06-11 00:45:59 +10:00
const prevNode = node.nodes[i - 1];
if (
prevNode &&
prevNode.type === "css-comment" &&
prevNode.text.trim() === "prettier-ignore"
) {
const childNode = pathChild.getValue();
parts.push(
options.originalText.slice(
options.locStart(childNode),
options.locEnd(childNode)
2017-06-11 00:45:59 +10:00
)
);
} else {
parts.push(pathChild.call(print));
}
if (i !== node.nodes.length - 1) {
if (
(node.nodes[i + 1].type === "css-comment" &&
!privateUtil.hasNewline(
options.originalText,
options.locStart(node.nodes[i + 1]),
{ backwards: true }
)) ||
(node.nodes[i + 1].type === "css-atrule" &&
node.nodes[i + 1].name === "else" &&
node.nodes[i].type !== "css-comment")
) {
parts.push(" ");
} else {
parts.push(hardline);
if (
sharedUtil.isNextLineEmpty(
options.originalText,
pathChild.getValue(),
options
)
) {
parts.push(hardline);
}
}
}
i++;
}, "nodes");
return concat(parts);
}
2017-08-14 08:57:16 +02:00
const STRING_REGEX = /(['"])(?:(?!\1)[^\\]|\\[\s\S])*\1/g;
2017-08-15 17:25:57 +02:00
const NUMBER_REGEX = /(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g;
2017-09-03 21:22:28 +02:00
const STANDARD_UNIT_REGEX = /[a-zA-Z]+/g;
const WORD_PART_REGEX = /[$@]?[a-zA-Z_\u0080-\uFFFF][\w\-\u0080-\uFFFF]*/g;
const ADJUST_NUMBERS_REGEX = RegExp(
STRING_REGEX.source +
`|` +
`(${WORD_PART_REGEX.source})?` +
`(${NUMBER_REGEX.source})` +
`(${STANDARD_UNIT_REGEX.source})?`,
2017-08-15 17:25:57 +02:00
"g"
);
2017-08-14 08:57:16 +02:00
function adjustStrings(value, options) {
return value.replace(STRING_REGEX, match =>
privateUtil.printString(match, options)
);
2017-08-14 08:57:16 +02:00
}
function quoteAttributeValue(value, options) {
const quote = options.singleQuote ? "'" : '"';
return value.includes('"') || value.includes("'")
? value
: quote + value + quote;
}
2017-08-15 17:25:57 +02:00
function adjustNumbers(value) {
return value.replace(
2017-09-03 21:22:28 +02:00
ADJUST_NUMBERS_REGEX,
(match, quote, wordPart, number, unit) =>
!wordPart && number
? (wordPart || "") + printNumber(number) + maybeToLowerCase(unit || "")
: match
2017-08-15 17:25:57 +02:00
);
}
function printNumber(rawNumber) {
return (
privateUtil
2017-08-15 17:25:57 +02:00
.printNumber(rawNumber)
// Remove trailing `.0`.
.replace(/\.0(?=$|e)/, "")
);
}
2017-12-26 12:23:50 +11:00
module.exports = {
print: genericPrint,
hasPrettierIgnore: privateUtil.hasIgnoreComment,
massageAstNode: clean
2017-12-26 12:23:50 +11:00
};