source: frontend/node_modules/postcss-normalize-repeat-style/src/index.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 3.6 KB
Line 
1'use strict';
2const valueParser = require('postcss-value-parser');
3const mappings = require('./lib/map');
4
5/**
6 * @param {unknown} item
7 * @param {number} index
8 * @return {boolean}
9 */
10function evenValues(item, index) {
11 return index % 2 === 0;
12}
13
14const repeatKeywords = new Set(mappings.values());
15
16/**
17 * @param {valueParser.Node} node
18 * @return {boolean}
19 */
20function isCommaNode(node) {
21 return node.type === 'div' && node.value === ',';
22}
23
24const variableFunctions = new Set(['var', 'env', 'constant']);
25/**
26 * @param {valueParser.Node} node
27 * @return {boolean}
28 */
29function isVariableFunctionNode(node) {
30 if (node.type !== 'function') {
31 return false;
32 }
33
34 return variableFunctions.has(node.value.toLowerCase());
35}
36
37/**
38 * @param {string} value
39 * @return {string}
40 */
41function transform(value) {
42 const parsed = valueParser(value);
43
44 if (parsed.nodes.length === 1) {
45 return value;
46 }
47 /** @type {{start: number?, end: number?}[]} */
48 const ranges = [];
49 let rangeIndex = 0;
50 let shouldContinue = true;
51
52 parsed.nodes.forEach((node, index) => {
53 // After comma (`,`) follows next background
54 if (isCommaNode(node)) {
55 rangeIndex += 1;
56 shouldContinue = true;
57
58 return;
59 }
60
61 if (!shouldContinue) {
62 return;
63 }
64
65 // After separator (`/`) follows `background-size` values
66 // Avoid them
67 if (node.type === 'div' && node.value === '/') {
68 shouldContinue = false;
69
70 return;
71 }
72
73 if (!ranges[rangeIndex]) {
74 ranges[rangeIndex] = {
75 start: null,
76 end: null,
77 };
78 }
79
80 // Do not try to be processed `var and `env` function inside background
81 if (isVariableFunctionNode(node)) {
82 shouldContinue = false;
83 ranges[rangeIndex].start = null;
84 ranges[rangeIndex].end = null;
85
86 return;
87 }
88
89 const isRepeatKeyword =
90 node.type === 'word' && repeatKeywords.has(node.value.toLowerCase());
91
92 if (ranges[rangeIndex].start === null && isRepeatKeyword) {
93 ranges[rangeIndex].start = index;
94 ranges[rangeIndex].end = index;
95
96 return;
97 }
98
99 if (ranges[rangeIndex].start !== null) {
100 if (node.type === 'space') {
101 return;
102 } else if (isRepeatKeyword) {
103 ranges[rangeIndex].end = index;
104
105 return;
106 }
107
108 return;
109 }
110 });
111
112 ranges.forEach((range) => {
113 if (range.start === null) {
114 return;
115 }
116
117 const nodes = parsed.nodes.slice(
118 range.start,
119 /** @type {number} */ (range.end) + 1
120 );
121
122 if (nodes.length !== 3) {
123 return;
124 }
125 const key = nodes
126 .filter(evenValues)
127 .map((n) => n.value.toLowerCase())
128 .toString();
129
130 const match = mappings.get(key);
131
132 if (match) {
133 nodes[0].value = match;
134 nodes[1].value = nodes[2].value = '';
135 }
136 });
137
138 return parsed.toString();
139}
140
141/**
142 * @type {import('postcss').PluginCreator<void>}
143 * @return {import('postcss').Plugin}
144 */
145function pluginCreator() {
146 return {
147 postcssPlugin: 'postcss-normalize-repeat-style',
148 prepare() {
149 const cache = new Map();
150 return {
151 OnceExit(css) {
152 css.walkDecls(
153 /^(background(-repeat)?|(-\w+-)?mask-repeat)$/i,
154 (decl) => {
155 const value = decl.value;
156
157 if (!value) {
158 return;
159 }
160
161 if (cache.has(value)) {
162 decl.value = cache.get(value);
163
164 return;
165 }
166
167 const result = transform(value);
168
169 decl.value = result;
170 cache.set(value, result);
171 }
172 );
173 },
174 };
175 },
176 };
177}
178
179pluginCreator.postcss = true;
180module.exports = pluginCreator;
Note: See TracBrowser for help on using the repository browser.