.gitignore added
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / stylelint / lib / utils / findFontFamily.js
1 /* @flow */
2 "use strict";
3
4 const isNumbery = require("./isNumbery");
5 const isStandardSyntaxValue = require("./isStandardSyntaxValue");
6 const isValidFontSize = require("./isValidFontSize");
7 const isVariable = require("./isVariable");
8 const keywordSets = require("../reference/keywordSets");
9 const postcssValueParser = require("postcss-value-parser");
10
11 const nodeTypesToCheck = new Set(["word", "string", "space", "div"]);
12
13 function joinValueNodes(firstNode, secondNode, charactersBetween) {
14   firstNode.value = firstNode.value + charactersBetween + secondNode.value;
15
16   return firstNode;
17 }
18
19 /**
20  * Get the font-families within a `font` shorthand property value.
21  *
22  * @param {string} value
23  * @return {object} Collection font-family nodes
24  */
25 module.exports = function findFontFamily(
26   value /*: string*/
27 ) /*: Array<Object>*/ {
28   const fontFamilies = [];
29
30   const valueNodes = postcssValueParser(value);
31
32   // Handle `inherit`, `initial` and etc
33   if (
34     valueNodes.nodes.length === 1 &&
35     keywordSets.basicKeywords.has(valueNodes.nodes[0].value.toLowerCase())
36   ) {
37     return [valueNodes.nodes[0]];
38   }
39
40   let needMergeNodesByValue = false;
41   let mergeCharacters = null;
42
43   valueNodes.walk((valueNode, index, nodes) => {
44     if (valueNode.type === "function") {
45       return false;
46     }
47     if (!nodeTypesToCheck.has(valueNode.type)) {
48       return;
49     }
50
51     const valueLowerCase = valueNode.value.toLowerCase();
52
53     // Ignore non standard syntax
54     if (!isStandardSyntaxValue(valueLowerCase)) {
55       return;
56     }
57
58     // Ignore variables
59     if (isVariable(valueLowerCase)) {
60       return;
61     }
62
63     // Ignore keywords for other font parts
64     if (
65       keywordSets.fontShorthandKeywords.has(valueLowerCase) &&
66       !keywordSets.fontFamilyKeywords.has(valueLowerCase)
67     ) {
68       return;
69     }
70
71     // Ignore font-sizes
72     if (isValidFontSize(valueNode.value)) {
73       return;
74     }
75
76     // Ignore anything come after a <font-size>/, because it's a line-height
77     if (
78       nodes[index - 1] &&
79       nodes[index - 1].value === "/" &&
80       nodes[index - 2] &&
81       isValidFontSize(nodes[index - 2].value)
82     ) {
83       return;
84     }
85
86     // Ignore number values
87     if (isNumbery(valueLowerCase)) {
88       return;
89     }
90
91     // Detect when a space or comma is dividing a list of font-families, and save the joining character.
92     if (
93       (valueNode.type === "space" ||
94         (valueNode.type === "div" && valueNode.value !== ",")) &&
95       fontFamilies.length !== 0
96     ) {
97       needMergeNodesByValue = true;
98       mergeCharacters = valueNode.value;
99       return;
100     } else if (valueNode.type === "space" || valueNode.type === "div") {
101       return;
102     }
103
104     const fontFamily = valueNode;
105
106     if (needMergeNodesByValue) {
107       joinValueNodes(
108         fontFamilies[fontFamilies.length - 1],
109         valueNode,
110         mergeCharacters
111       );
112       needMergeNodesByValue = false;
113       mergeCharacters = null;
114     } else {
115       fontFamilies.push(fontFamily);
116     }
117   });
118
119   return fontFamilies;
120 };