source: trip-planner-front/node_modules/svgo/lib/css-tools.js

Last change on this file was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 6.3 KB
RevLine 
[6a3a178]1'use strict';
2
3var csstree = require('css-tree'),
4 List = csstree.List,
5 stable = require('stable'),
6 specificity = require('csso/lib/restructure/prepare/specificity');
7
8/**
9 * Flatten a CSS AST to a selectors list.
10 *
11 * @param {import('css-tree').CssNode} cssAst css-tree AST to flatten
12 * @return {Array} selectors
13 */
14function flattenToSelectors(cssAst) {
15 var selectors = [];
16
17 csstree.walk(cssAst, {
18 visit: 'Rule',
19 enter: function (node) {
20 if (node.type !== 'Rule') {
21 return;
22 }
23
24 var atrule = this.atrule;
25 var rule = node;
26
27 node.prelude.children.each(function (selectorNode, selectorItem) {
28 var selector = {
29 item: selectorItem,
30 atrule: atrule,
31 rule: rule,
32 pseudos: /** @type {{item: any; list: any[]}[]} */ ([]),
33 };
34
35 selectorNode.children.each(function (
36 selectorChildNode,
37 selectorChildItem,
38 selectorChildList
39 ) {
40 if (
41 selectorChildNode.type === 'PseudoClassSelector' ||
42 selectorChildNode.type === 'PseudoElementSelector'
43 ) {
44 selector.pseudos.push({
45 item: selectorChildItem,
46 list: selectorChildList,
47 });
48 }
49 });
50
51 selectors.push(selector);
52 });
53 },
54 });
55
56 return selectors;
57}
58
59/**
60 * Filter selectors by Media Query.
61 *
62 * @param {Array} selectors to filter
63 * @param {Array} useMqs Array with strings of media queries that should pass (<name> <expression>)
64 * @return {Array} Filtered selectors that match the passed media queries
65 */
66function filterByMqs(selectors, useMqs) {
67 return selectors.filter(function (selector) {
68 if (selector.atrule === null) {
69 return ~useMqs.indexOf('');
70 }
71
72 var mqName = selector.atrule.name;
73 var mqStr = mqName;
74 if (
75 selector.atrule.expression &&
76 selector.atrule.expression.children.first().type === 'MediaQueryList'
77 ) {
78 var mqExpr = csstree.generate(selector.atrule.expression);
79 mqStr = [mqName, mqExpr].join(' ');
80 }
81
82 return ~useMqs.indexOf(mqStr);
83 });
84}
85
86/**
87 * Filter selectors by the pseudo-elements and/or -classes they contain.
88 *
89 * @param {Array} selectors to filter
90 * @param {Array} usePseudos Array with strings of single or sequence of pseudo-elements and/or -classes that should pass
91 * @return {Array} Filtered selectors that match the passed pseudo-elements and/or -classes
92 */
93function filterByPseudos(selectors, usePseudos) {
94 return selectors.filter(function (selector) {
95 var pseudoSelectorsStr = csstree.generate({
96 type: 'Selector',
97 children: new List().fromArray(
98 selector.pseudos.map(function (pseudo) {
99 return pseudo.item.data;
100 })
101 ),
102 });
103 return ~usePseudos.indexOf(pseudoSelectorsStr);
104 });
105}
106
107/**
108 * Remove pseudo-elements and/or -classes from the selectors for proper matching.
109 *
110 * @param {Array} selectors to clean
111 * @return {void}
112 */
113function cleanPseudos(selectors) {
114 selectors.forEach(function (selector) {
115 selector.pseudos.forEach(function (pseudo) {
116 pseudo.list.remove(pseudo.item);
117 });
118 });
119}
120
121/**
122 * Compares two selector specificities.
123 * extracted from https://github.com/keeganstreet/specificity/blob/master/specificity.js#L211
124 *
125 * @param {Array} aSpecificity Specificity of selector A
126 * @param {Array} bSpecificity Specificity of selector B
127 * @return {number} Score of selector specificity A compared to selector specificity B
128 */
129function compareSpecificity(aSpecificity, bSpecificity) {
130 for (var i = 0; i < 4; i += 1) {
131 if (aSpecificity[i] < bSpecificity[i]) {
132 return -1;
133 } else if (aSpecificity[i] > bSpecificity[i]) {
134 return 1;
135 }
136 }
137
138 return 0;
139}
140
141/**
142 * Compare two simple selectors.
143 *
144 * @param {Object} aSimpleSelectorNode Simple selector A
145 * @param {Object} bSimpleSelectorNode Simple selector B
146 * @return {number} Score of selector A compared to selector B
147 */
148function compareSimpleSelectorNode(aSimpleSelectorNode, bSimpleSelectorNode) {
149 var aSpecificity = specificity(aSimpleSelectorNode),
150 bSpecificity = specificity(bSimpleSelectorNode);
151 return compareSpecificity(aSpecificity, bSpecificity);
152}
153
154function _bySelectorSpecificity(selectorA, selectorB) {
155 return compareSimpleSelectorNode(selectorA.item.data, selectorB.item.data);
156}
157
158/**
159 * Sort selectors stably by their specificity.
160 *
161 * @param {Array} selectors to be sorted
162 * @return {Array} Stable sorted selectors
163 */
164function sortSelectors(selectors) {
165 return stable(selectors, _bySelectorSpecificity);
166}
167
168/**
169 * Convert a css-tree AST style declaration to CSSStyleDeclaration property.
170 *
171 * @param {import('css-tree').CssNode} declaration css-tree style declaration
172 * @return {Object} CSSStyleDeclaration property
173 */
174function csstreeToStyleDeclaration(declaration) {
175 var propertyName = declaration.property,
176 propertyValue = csstree.generate(declaration.value),
177 propertyPriority = declaration.important ? 'important' : '';
178 return {
179 name: propertyName,
180 value: propertyValue,
181 priority: propertyPriority,
182 };
183}
184
185/**
186 * Gets the CSS string of a style element
187 *
188 * @param {Object} elem style element
189 * @return {string} CSS string or empty array if no styles are set
190 */
191function getCssStr(elem) {
192 if (
193 elem.children.length > 0 &&
194 (elem.children[0].type === 'text' || elem.children[0].type === 'cdata')
195 ) {
196 return elem.children[0].value;
197 }
198 return '';
199}
200
201/**
202 * Sets the CSS string of a style element
203 *
204 * @param {Object} elem style element
205 * @param {string} css string to be set
206 * @return {string} reference to field with CSS
207 */
208function setCssStr(elem, css) {
209 if (elem.children.length === 0) {
210 elem.children.push({
211 type: 'text',
212 value: '',
213 });
214 }
215
216 if (elem.children[0].type !== 'text' && elem.children[0].type !== 'cdata') {
217 return css;
218 }
219
220 elem.children[0].value = css;
221
222 return css;
223}
224
225module.exports.flattenToSelectors = flattenToSelectors;
226
227module.exports.filterByMqs = filterByMqs;
228module.exports.filterByPseudos = filterByPseudos;
229module.exports.cleanPseudos = cleanPseudos;
230
231module.exports.compareSpecificity = compareSpecificity;
232module.exports.compareSimpleSelectorNode = compareSimpleSelectorNode;
233
234module.exports.sortSelectors = sortSelectors;
235
236module.exports.csstreeToStyleDeclaration = csstreeToStyleDeclaration;
237
238module.exports.getCssStr = getCssStr;
239module.exports.setCssStr = setCssStr;
Note: See TracBrowser for help on using the repository browser.