@tbela99/css-parser 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +318 -34
- package/dist/config.json.js +386 -4
- package/dist/index-umd-web.js +3260 -1563
- package/dist/index.cjs +3259 -1564
- package/dist/index.d.ts +687 -536
- package/dist/lib/ast/expand.js +14 -14
- package/dist/lib/ast/features/calc.js +225 -0
- package/dist/lib/ast/features/index.js +3 -0
- package/dist/lib/ast/features/inlinecssvariables.js +130 -0
- package/dist/lib/ast/features/shorthand.js +46 -0
- package/dist/lib/ast/features/utils/math.js +95 -0
- package/dist/lib/ast/minify.js +401 -372
- package/dist/lib/ast/types.js +101 -0
- package/dist/lib/ast/utils/minifyfeature.js +8 -0
- package/dist/lib/ast/walk.js +37 -9
- package/dist/lib/iterable/set.js +48 -0
- package/dist/lib/iterable/weakmap.js +53 -0
- package/dist/lib/parser/declaration/list.js +18 -4
- package/dist/lib/parser/declaration/map.js +102 -33
- package/dist/lib/parser/declaration/set.js +18 -12
- package/dist/lib/parser/parse.js +661 -421
- package/dist/lib/parser/tokenize.js +82 -46
- package/dist/lib/parser/utils/syntax.js +13 -10
- package/dist/lib/parser/utils/type.js +23 -6
- package/dist/lib/renderer/render.js +253 -84
- package/dist/lib/renderer/sourcemap/lib/encode.js +37 -0
- package/dist/lib/renderer/sourcemap/sourcemap.js +58 -0
- package/dist/lib/renderer/utils/color.js +25 -20
- package/dist/node/index.js +30 -15
- package/dist/web/index.js +36 -19
- package/package.json +9 -6
- package/dist/lib/transform.js +0 -24
package/dist/lib/ast/minify.js
CHANGED
|
@@ -1,58 +1,38 @@
|
|
|
1
|
-
import { isIdentStart, isWhiteSpace, isIdent, isFunction } from '../parser/utils/syntax.js';
|
|
2
|
-
import { PropertyList } from '../parser/declaration/list.js';
|
|
3
|
-
import { eq } from '../parser/utils/eq.js';
|
|
4
|
-
import { render, renderToken } from '../renderer/render.js';
|
|
5
1
|
import { parseString } from '../parser/parse.js';
|
|
6
|
-
import {
|
|
2
|
+
import { isWhiteSpace, isIdent, isFunction, isIdentStart } from '../parser/utils/syntax.js';
|
|
3
|
+
import { EnumToken } from './types.js';
|
|
7
4
|
import { walkValues } from './walk.js';
|
|
5
|
+
import { replaceCompound } from './expand.js';
|
|
6
|
+
import { eq } from '../parser/utils/eq.js';
|
|
7
|
+
import { renderToken, doRender } from '../renderer/render.js';
|
|
8
|
+
import * as index from './features/index.js';
|
|
8
9
|
|
|
9
|
-
const combinators = ['+', '>', '~'];
|
|
10
|
+
const combinators = ['+', '>', '~', '||'];
|
|
10
11
|
const notEndingWith = ['(', '['].concat(combinators);
|
|
11
12
|
const definedPropertySettings = { configurable: true, enumerable: false, writable: true };
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
const features = Object.values(index).sort((a, b) => a.ordering - b.ordering);
|
|
15
|
+
function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) {
|
|
16
|
+
if (!('nodes' in context)) {
|
|
17
|
+
context.nodes = new WeakSet;
|
|
18
|
+
}
|
|
19
|
+
if (context.nodes.has(ast)) {
|
|
20
|
+
// console.error('skipped', ast.typ);
|
|
21
|
+
return ast;
|
|
22
|
+
}
|
|
23
|
+
context.nodes.add(ast);
|
|
24
|
+
if (!('features' in options)) {
|
|
18
25
|
// @ts-ignore
|
|
19
|
-
|
|
26
|
+
options = {
|
|
27
|
+
removeDuplicateDeclarations: true,
|
|
28
|
+
computeShorthand: true,
|
|
29
|
+
computeCalcExpression: true,
|
|
30
|
+
features: [], ...options
|
|
31
|
+
};
|
|
20
32
|
// @ts-ignore
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
value: match.match.map(t => t.slice())
|
|
24
|
-
});
|
|
25
|
-
if (pSel == '&' || pSel === '') {
|
|
26
|
-
// @ts-ignore
|
|
27
|
-
wrapper.chi.push(...previous.chi);
|
|
28
|
-
// @ts-ignore
|
|
29
|
-
if ((nSel == '&' || nSel === '')) {
|
|
30
|
-
// @ts-ignore
|
|
31
|
-
wrapper.chi.push(...node.chi);
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
// @ts-ignore
|
|
35
|
-
wrapper.chi.push(node);
|
|
36
|
-
}
|
|
33
|
+
for (const feature of features) {
|
|
34
|
+
feature.register(options);
|
|
37
35
|
}
|
|
38
|
-
else {
|
|
39
|
-
// @ts-ignore
|
|
40
|
-
wrapper.chi.push(previous, node);
|
|
41
|
-
}
|
|
42
|
-
// @ts-ignore
|
|
43
|
-
ast.chi.splice(i, 1, wrapper);
|
|
44
|
-
// @ts-ignore
|
|
45
|
-
ast.chi.splice(nodeIndex, 1);
|
|
46
|
-
// @ts-ignore
|
|
47
|
-
previous.sel = pSel;
|
|
48
|
-
// @ts-ignore
|
|
49
|
-
previous.raw = match.selector1;
|
|
50
|
-
// @ts-ignore
|
|
51
|
-
node.sel = nSel;
|
|
52
|
-
// @ts-ignore
|
|
53
|
-
node.raw = match.selector2;
|
|
54
|
-
reduceRuleSelector(wrapper);
|
|
55
|
-
return wrapper;
|
|
56
36
|
}
|
|
57
37
|
function reducer(acc, curr, index, array) {
|
|
58
38
|
// trim :is()
|
|
@@ -67,258 +47,16 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
67
47
|
curr.splice(0, 1);
|
|
68
48
|
}
|
|
69
49
|
}
|
|
70
|
-
else if (ast.typ ==
|
|
50
|
+
else if (ast.typ == EnumToken.RuleNodeType && (isIdent(curr[0]) || isFunction(curr[0]))) {
|
|
71
51
|
curr.unshift('&', ' ');
|
|
72
52
|
}
|
|
73
53
|
acc.push(curr.join(''));
|
|
74
54
|
return acc;
|
|
75
55
|
}
|
|
76
|
-
function diff(n1, n2, options = {}) {
|
|
77
|
-
let node1 = n1;
|
|
78
|
-
let node2 = n2;
|
|
79
|
-
let exchanged = false;
|
|
80
|
-
if (node1.chi.length > node2.chi.length) {
|
|
81
|
-
const t = node1;
|
|
82
|
-
node1 = node2;
|
|
83
|
-
node2 = t;
|
|
84
|
-
exchanged = true;
|
|
85
|
-
}
|
|
86
|
-
let i = node1.chi.length;
|
|
87
|
-
let j = node2.chi.length;
|
|
88
|
-
if (i == 0 || j == 0) {
|
|
89
|
-
// @ts-ignore
|
|
90
|
-
return null;
|
|
91
|
-
}
|
|
92
|
-
// @ts-ignore
|
|
93
|
-
const raw1 = node1.raw;
|
|
94
|
-
// @ts-ignore
|
|
95
|
-
const raw2 = node2.raw;
|
|
96
|
-
// @ts-ignore
|
|
97
|
-
node1 = { ...node1, chi: node1.chi.slice() };
|
|
98
|
-
node2 = { ...node2, chi: node2.chi.slice() };
|
|
99
|
-
if (raw1 != null) {
|
|
100
|
-
Object.defineProperty(node1, 'raw', { ...definedPropertySettings, value: raw1 });
|
|
101
|
-
}
|
|
102
|
-
if (raw2 != null) {
|
|
103
|
-
Object.defineProperty(node2, 'raw', { ...definedPropertySettings, value: raw2 });
|
|
104
|
-
}
|
|
105
|
-
const intersect = [];
|
|
106
|
-
while (i--) {
|
|
107
|
-
if (node1.chi[i].typ == 'Comment') {
|
|
108
|
-
continue;
|
|
109
|
-
}
|
|
110
|
-
j = node2.chi.length;
|
|
111
|
-
if (j == 0) {
|
|
112
|
-
break;
|
|
113
|
-
}
|
|
114
|
-
while (j--) {
|
|
115
|
-
if (node2.chi[j].typ == 'Comment') {
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
if (node1.chi[i].nam == node2.chi[j].nam) {
|
|
119
|
-
if (eq(node1.chi[i], node2.chi[j])) {
|
|
120
|
-
intersect.push(node1.chi[i]);
|
|
121
|
-
node1.chi.splice(i, 1);
|
|
122
|
-
node2.chi.splice(j, 1);
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
// @ts-ignore
|
|
129
|
-
const result = (intersect.length == 0 ? null : {
|
|
130
|
-
...node1,
|
|
131
|
-
// @ts-ignore
|
|
132
|
-
sel: [...new Set([...(n1?.raw?.reduce(reducer, []) || splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) || splitRule(n2.sel))])].join(','),
|
|
133
|
-
chi: intersect.reverse()
|
|
134
|
-
});
|
|
135
|
-
if (result == null || [n1, n2].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + render(curr, options).code.length, 0) <= [node1, node2, result].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + render(curr, options).code.length, 0)) {
|
|
136
|
-
// @ts-ignore
|
|
137
|
-
return null;
|
|
138
|
-
}
|
|
139
|
-
return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 };
|
|
140
|
-
}
|
|
141
|
-
function matchSelectors(selector1, selector2, parentType) {
|
|
142
|
-
let match = [[]];
|
|
143
|
-
const j = Math.min(selector1.reduce((acc, curr) => Math.min(acc, curr.length), selector1.length > 0 ? selector1[0].length : 0), selector2.reduce((acc, curr) => Math.min(acc, curr.length), selector2.length > 0 ? selector2[0].length : 0));
|
|
144
|
-
let i = 0;
|
|
145
|
-
let k;
|
|
146
|
-
let l;
|
|
147
|
-
let token;
|
|
148
|
-
let matching = true;
|
|
149
|
-
let matchFunction = 0;
|
|
150
|
-
let inAttr = 0;
|
|
151
|
-
for (; i < j; i++) {
|
|
152
|
-
k = 0;
|
|
153
|
-
token = selector1[0][i];
|
|
154
|
-
for (; k < selector1.length; k++) {
|
|
155
|
-
if (selector1[k][i] != token) {
|
|
156
|
-
matching = false;
|
|
157
|
-
break;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
if (matching) {
|
|
161
|
-
l = 0;
|
|
162
|
-
for (; l < selector2.length; l++) {
|
|
163
|
-
if (selector2[l][i] != token) {
|
|
164
|
-
matching = false;
|
|
165
|
-
break;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
if (!matching) {
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
if (token == ',') {
|
|
173
|
-
match.push([]);
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
if (token.endsWith('(')) {
|
|
177
|
-
matchFunction++;
|
|
178
|
-
}
|
|
179
|
-
if (token.endsWith('[')) {
|
|
180
|
-
inAttr++;
|
|
181
|
-
}
|
|
182
|
-
else if (token == ')') {
|
|
183
|
-
matchFunction--;
|
|
184
|
-
}
|
|
185
|
-
else if (token == ']') {
|
|
186
|
-
inAttr--;
|
|
187
|
-
}
|
|
188
|
-
match.at(-1).push(token);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
// invalid function
|
|
192
|
-
if (matchFunction != 0 || inAttr != 0) {
|
|
193
|
-
return null;
|
|
194
|
-
}
|
|
195
|
-
if (parentType != 'Rule') {
|
|
196
|
-
for (const part of match) {
|
|
197
|
-
if (part.length > 0 && combinators.includes(part[0].charAt(0))) {
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
if (match.length > 1) {
|
|
203
|
-
errors?.push({ action: 'ignore', message: `minify: unsupported multilevel matching\n${JSON.stringify({ match, selector1, selector2 }, null, 1)}` });
|
|
204
|
-
return null;
|
|
205
|
-
}
|
|
206
|
-
for (const part of match) {
|
|
207
|
-
while (part.length > 0) {
|
|
208
|
-
const token = part.at(-1);
|
|
209
|
-
if (token == ' ' || combinators.includes(token) || notEndingWith.includes(token.at(-1))) {
|
|
210
|
-
part.pop();
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
break;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
if (match.every(t => t.length == 0)) {
|
|
217
|
-
return null;
|
|
218
|
-
}
|
|
219
|
-
if (eq([['&']], match)) {
|
|
220
|
-
return null;
|
|
221
|
-
}
|
|
222
|
-
function reduce(acc, curr) {
|
|
223
|
-
if (acc === null) {
|
|
224
|
-
return null;
|
|
225
|
-
}
|
|
226
|
-
let hasCompoundSelector = true;
|
|
227
|
-
curr = curr.slice(match[0].length);
|
|
228
|
-
while (curr.length > 0) {
|
|
229
|
-
if (curr[0] == ' ') {
|
|
230
|
-
hasCompoundSelector = false;
|
|
231
|
-
curr.unshift('&');
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
// invalid function match
|
|
237
|
-
if (curr.length > 0 && curr[0].endsWith('(') && curr.at(-1) != ')') {
|
|
238
|
-
return null;
|
|
239
|
-
}
|
|
240
|
-
if (curr.length == 1 && combinators.includes(curr[0].charAt(0))) {
|
|
241
|
-
return null;
|
|
242
|
-
}
|
|
243
|
-
if (hasCompoundSelector && curr.length > 0) {
|
|
244
|
-
hasCompoundSelector = !['&'].concat(combinators).includes(curr[0].charAt(0));
|
|
245
|
-
}
|
|
246
|
-
if (curr[0] == ':is(') {
|
|
247
|
-
let inFunction = 0;
|
|
248
|
-
let canReduce = true;
|
|
249
|
-
const isCompound = curr.reduce((acc, token, index) => {
|
|
250
|
-
if (index == 0) {
|
|
251
|
-
inFunction++;
|
|
252
|
-
canReduce = curr[1] == '&';
|
|
253
|
-
}
|
|
254
|
-
else if (token.endsWith('(')) {
|
|
255
|
-
if (inFunction == 0) {
|
|
256
|
-
canReduce = false;
|
|
257
|
-
}
|
|
258
|
-
inFunction++;
|
|
259
|
-
}
|
|
260
|
-
else if (token == ')') {
|
|
261
|
-
inFunction--;
|
|
262
|
-
}
|
|
263
|
-
else if (token == ',') {
|
|
264
|
-
if (!canReduce) {
|
|
265
|
-
canReduce = curr[index + 1] == '&';
|
|
266
|
-
}
|
|
267
|
-
acc.push([]);
|
|
268
|
-
}
|
|
269
|
-
else
|
|
270
|
-
acc.at(-1)?.push(token);
|
|
271
|
-
return acc;
|
|
272
|
-
}, [[]]);
|
|
273
|
-
if (inFunction > 0) {
|
|
274
|
-
canReduce = false;
|
|
275
|
-
}
|
|
276
|
-
if (canReduce) {
|
|
277
|
-
curr = isCompound.reduce((acc, curr) => {
|
|
278
|
-
if (acc.length > 0) {
|
|
279
|
-
acc.push(',');
|
|
280
|
-
}
|
|
281
|
-
acc.push(...curr);
|
|
282
|
-
return acc;
|
|
283
|
-
}, []);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
// @todo: check hasCompoundSelector && curr[0] == '&' && curr[1] == ' '
|
|
287
|
-
acc.push(match.length == 0 ? ['&'] : (hasCompoundSelector && curr[0] != '&' && (curr.length == 0 || !combinators.includes(curr[0].charAt(0))) ? ['&'].concat(curr) : curr));
|
|
288
|
-
return acc;
|
|
289
|
-
}
|
|
290
|
-
// @ts-ignore
|
|
291
|
-
selector1 = selector1.reduce(reduce, []);
|
|
292
|
-
// @ts-ignore
|
|
293
|
-
selector2 = selector2.reduce(reduce, []);
|
|
294
|
-
return selector1 == null || selector2 == null ? null : {
|
|
295
|
-
eq: eq(selector1, selector2),
|
|
296
|
-
match,
|
|
297
|
-
selector1,
|
|
298
|
-
selector2
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
function fixSelector(node) {
|
|
302
|
-
// @ts-ignore
|
|
303
|
-
if (node.sel.includes('&')) {
|
|
304
|
-
const attributes = parseString(node.sel);
|
|
305
|
-
for (const attr of walkValues(attributes)) {
|
|
306
|
-
if (attr.value.typ == 'Pseudo-class-func' && attr.value.val == ':is') {
|
|
307
|
-
let i = attr.value.chi.length;
|
|
308
|
-
while (i--) {
|
|
309
|
-
if (attr.value.chi[i].typ == 'Literal' && attr.value.chi[i].val == '&') {
|
|
310
|
-
attr.value.chi.splice(i, 1);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
node.sel = attributes.reduce((acc, curr) => acc + renderToken(curr), '');
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
56
|
// @ts-ignore
|
|
319
|
-
if (
|
|
57
|
+
if ('chi' in ast && ast.chi.length > 0) {
|
|
320
58
|
if (!nestingContent) {
|
|
321
|
-
nestingContent = options.nestingRules && ast.typ ==
|
|
59
|
+
nestingContent = options.nestingRules && ast.typ == EnumToken.RuleNodeType;
|
|
322
60
|
}
|
|
323
61
|
let i = 0;
|
|
324
62
|
let previous;
|
|
@@ -327,7 +65,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
327
65
|
// @ts-ignore
|
|
328
66
|
for (; i < ast.chi.length; i++) {
|
|
329
67
|
// @ts-ignore
|
|
330
|
-
if (ast.chi[i].typ ==
|
|
68
|
+
if (ast.chi[i].typ == EnumToken.CommentNodeType) {
|
|
331
69
|
continue;
|
|
332
70
|
}
|
|
333
71
|
// @ts-ignore
|
|
@@ -339,10 +77,10 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
339
77
|
i--;
|
|
340
78
|
continue;
|
|
341
79
|
}
|
|
342
|
-
if (node.typ ==
|
|
80
|
+
if (node.typ == EnumToken.AtRuleNodeType && node.nam == 'font-face') {
|
|
343
81
|
continue;
|
|
344
82
|
}
|
|
345
|
-
if (node.typ ==
|
|
83
|
+
if (node.typ == EnumToken.AtRuleNodeType) {
|
|
346
84
|
if (node.nam == 'media' && node.val == 'all') {
|
|
347
85
|
// @ts-ignore
|
|
348
86
|
ast.chi?.splice(i, 1, ...node.chi);
|
|
@@ -350,47 +88,41 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
350
88
|
continue;
|
|
351
89
|
}
|
|
352
90
|
// @ts-ignore
|
|
353
|
-
if (previous?.typ ==
|
|
91
|
+
if (previous?.typ == EnumToken.AtRuleNodeType &&
|
|
354
92
|
previous.nam == node.nam &&
|
|
355
93
|
previous.val == node.val) {
|
|
356
94
|
if ('chi' in node) {
|
|
357
95
|
// @ts-ignore
|
|
358
96
|
previous.chi.push(...node.chi);
|
|
359
97
|
}
|
|
360
|
-
// else {
|
|
361
98
|
ast?.chi?.splice(i--, 1);
|
|
362
99
|
continue;
|
|
363
|
-
// }
|
|
364
100
|
}
|
|
365
101
|
// @ts-ignore
|
|
366
|
-
if (hasDeclaration(node)) {
|
|
367
|
-
|
|
368
|
-
minifyRule(node);
|
|
369
|
-
}
|
|
370
|
-
else {
|
|
371
|
-
minify(node, options, recursive, errors, nestingContent);
|
|
102
|
+
if (!hasDeclaration(node)) {
|
|
103
|
+
minify(node, options, recursive, errors, nestingContent, context);
|
|
372
104
|
}
|
|
373
105
|
previous = node;
|
|
374
106
|
nodeIndex = i;
|
|
375
107
|
continue;
|
|
376
108
|
}
|
|
377
109
|
// @ts-ignore
|
|
378
|
-
if (node.typ ==
|
|
110
|
+
if (node.typ == EnumToken.RuleNodeType) {
|
|
379
111
|
reduceRuleSelector(node);
|
|
380
112
|
let wrapper;
|
|
381
113
|
let match;
|
|
382
114
|
// @ts-ignore
|
|
383
115
|
if (options.nestingRules) {
|
|
384
116
|
// @ts-ignore
|
|
385
|
-
if (previous?.typ ==
|
|
117
|
+
if (previous?.typ == EnumToken.RuleNodeType) {
|
|
386
118
|
// @ts-ignore
|
|
387
119
|
reduceRuleSelector(previous);
|
|
388
120
|
// @ts-ignore
|
|
389
|
-
match = matchSelectors(previous.raw, node.raw, ast.typ);
|
|
121
|
+
match = matchSelectors(previous.raw, node.raw, ast.typ, errors);
|
|
390
122
|
// @ts-ignore
|
|
391
123
|
if (match != null) {
|
|
392
124
|
// @ts-ignore
|
|
393
|
-
wrapper = wrapNodes(previous, node, match, ast, i, nodeIndex);
|
|
125
|
+
wrapper = wrapNodes(previous, node, match, ast, reducer, i, nodeIndex);
|
|
394
126
|
nodeIndex = i - 1;
|
|
395
127
|
// @ts-ignore
|
|
396
128
|
previous = ast.chi[nodeIndex];
|
|
@@ -403,26 +135,23 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
403
135
|
// @ts-ignore
|
|
404
136
|
const nextNode = ast.chi[i];
|
|
405
137
|
// @ts-ignore
|
|
406
|
-
if (nextNode.typ !=
|
|
407
|
-
// i--;
|
|
408
|
-
// previous = wrapper;
|
|
409
|
-
// nodeIndex = i;
|
|
138
|
+
if (nextNode.typ != EnumToken.RuleNodeType) {
|
|
410
139
|
break;
|
|
411
140
|
}
|
|
412
141
|
reduceRuleSelector(nextNode);
|
|
413
142
|
// @ts-ignore
|
|
414
|
-
match = matchSelectors(wrapper.raw, nextNode.raw, ast.typ);
|
|
143
|
+
match = matchSelectors(wrapper.raw, nextNode.raw, ast.typ, errors);
|
|
415
144
|
// @ts-ignore
|
|
416
145
|
if (match == null) {
|
|
417
146
|
break;
|
|
418
147
|
}
|
|
419
148
|
// @ts-ignore
|
|
420
|
-
wrapper = wrapNodes(wrapper, nextNode, match, ast, i, nodeIndex);
|
|
149
|
+
wrapper = wrapNodes(wrapper, nextNode, match, ast, reducer, i, nodeIndex);
|
|
421
150
|
}
|
|
422
151
|
nodeIndex = --i;
|
|
423
152
|
// @ts-ignore
|
|
424
153
|
previous = ast.chi[nodeIndex];
|
|
425
|
-
minify(wrapper, options, recursive, errors, nestingContent);
|
|
154
|
+
minify(wrapper, options, recursive, errors, nestingContent, context);
|
|
426
155
|
continue;
|
|
427
156
|
}
|
|
428
157
|
// @ts-ignore
|
|
@@ -460,7 +189,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
460
189
|
curr.splice(0, 2);
|
|
461
190
|
}
|
|
462
191
|
else {
|
|
463
|
-
if (ast.typ !=
|
|
192
|
+
if (ast.typ != EnumToken.RuleNodeType && combinators.includes(curr[1])) {
|
|
464
193
|
wrap = false;
|
|
465
194
|
}
|
|
466
195
|
else {
|
|
@@ -477,7 +206,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
477
206
|
return acc;
|
|
478
207
|
}, []);
|
|
479
208
|
if (!wrap) {
|
|
480
|
-
wrap = selector.some(s => s[0] != '&');
|
|
209
|
+
wrap = selector.some((s) => s[0] != '&');
|
|
481
210
|
}
|
|
482
211
|
let rule = selector.map(s => {
|
|
483
212
|
if (s[0] == '&') {
|
|
@@ -508,37 +237,36 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
508
237
|
let k = previous.chi.length;
|
|
509
238
|
while (k-- > 0) {
|
|
510
239
|
// @ts-ignore
|
|
511
|
-
if (previous.chi[k].typ ==
|
|
240
|
+
if (previous.chi[k].typ == EnumToken.CommentNodeType) {
|
|
512
241
|
continue;
|
|
513
242
|
}
|
|
514
243
|
// @ts-ignore
|
|
515
|
-
shouldMerge = previous.chi[k].typ ==
|
|
244
|
+
shouldMerge = previous.chi[k].typ == EnumToken.DeclarationNodeType;
|
|
516
245
|
break;
|
|
517
246
|
}
|
|
518
247
|
if (shouldMerge) {
|
|
519
248
|
// @ts-ignore
|
|
520
|
-
if ((node.typ ==
|
|
249
|
+
if ((node.typ == EnumToken.RuleNodeType && node.sel == previous.sel) ||
|
|
521
250
|
// @ts-ignore
|
|
522
|
-
(node.typ ==
|
|
251
|
+
(node.typ == EnumToken.AtRuleNodeType) && node.val != 'font-face' && node.val == previous.val) {
|
|
523
252
|
// @ts-ignore
|
|
524
253
|
node.chi.unshift(...previous.chi);
|
|
525
254
|
// @ts-ignore
|
|
526
255
|
ast.chi.splice(nodeIndex, 1);
|
|
527
256
|
// @ts-ignore
|
|
528
|
-
if (hasDeclaration(node)) {
|
|
257
|
+
if (!hasDeclaration(node)) {
|
|
529
258
|
// @ts-ignore
|
|
530
|
-
minifyRule(node);
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
minify(node, options, recursive, errors, nestingContent);
|
|
259
|
+
// minifyRule(node, <MinifyOptions>options, ast, context);
|
|
260
|
+
// } else {
|
|
261
|
+
minify(node, options, recursive, errors, nestingContent, context);
|
|
534
262
|
}
|
|
535
263
|
i--;
|
|
536
264
|
previous = node;
|
|
537
265
|
nodeIndex = i;
|
|
538
266
|
continue;
|
|
539
267
|
}
|
|
540
|
-
else if (node.typ ==
|
|
541
|
-
const intersect = diff(previous, node, options);
|
|
268
|
+
else if (node.typ == EnumToken.RuleNodeType && previous?.typ == EnumToken.RuleNodeType) {
|
|
269
|
+
const intersect = diff(previous, node, reducer, options);
|
|
542
270
|
if (intersect != null) {
|
|
543
271
|
if (intersect.node1.chi.length == 0) {
|
|
544
272
|
// @ts-ignore
|
|
@@ -570,24 +298,22 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
570
298
|
// @ts-ignore
|
|
571
299
|
if (recursive && previous != node) {
|
|
572
300
|
// @ts-ignore
|
|
573
|
-
if (hasDeclaration(previous)) {
|
|
301
|
+
if (!hasDeclaration(previous)) {
|
|
574
302
|
// @ts-ignore
|
|
575
|
-
minifyRule(previous);
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
minify(previous, options, recursive, errors, nestingContent);
|
|
303
|
+
// minifyRule(previous, <MinifyOptions>options, ast, context);
|
|
304
|
+
// } else {
|
|
305
|
+
minify(previous, options, recursive, errors, nestingContent, context);
|
|
579
306
|
}
|
|
580
307
|
}
|
|
581
308
|
}
|
|
582
309
|
else {
|
|
583
310
|
if ('chi' in previous) {
|
|
584
311
|
// @ts-ignore
|
|
585
|
-
if (hasDeclaration(previous)) {
|
|
312
|
+
if (!hasDeclaration(previous)) {
|
|
586
313
|
// @ts-ignore
|
|
587
|
-
minifyRule(previous);
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
minify(previous, options, recursive, errors, nestingContent);
|
|
314
|
+
// minifyRule(previous, <MinifyOptions>options, ast, context);
|
|
315
|
+
// } else {
|
|
316
|
+
minify(previous, options, recursive, errors, nestingContent, context);
|
|
591
317
|
}
|
|
592
318
|
}
|
|
593
319
|
}
|
|
@@ -596,7 +322,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
596
322
|
// @ts-ignore
|
|
597
323
|
previous != null &&
|
|
598
324
|
// previous.optimized != null &&
|
|
599
|
-
previous.typ ==
|
|
325
|
+
previous.typ == EnumToken.RuleNodeType &&
|
|
600
326
|
previous.sel.includes('&')) {
|
|
601
327
|
fixSelector(previous);
|
|
602
328
|
}
|
|
@@ -606,13 +332,10 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
606
332
|
// @ts-ignore
|
|
607
333
|
if (recursive && node != null && ('chi' in node)) {
|
|
608
334
|
// @ts-ignore
|
|
609
|
-
if (node.chi.some(n => n.typ ==
|
|
610
|
-
minifyRule(node);
|
|
611
|
-
}
|
|
612
|
-
else {
|
|
335
|
+
if (!node.chi.some(n => n.typ == EnumToken.DeclarationNodeType)) {
|
|
613
336
|
// @ts-ignore
|
|
614
|
-
if (!(node.typ ==
|
|
615
|
-
minify(node, options, recursive, errors, nestingContent);
|
|
337
|
+
if (!(node.typ == EnumToken.AtRuleNodeType && node.nam != 'font-face')) {
|
|
338
|
+
minify(node, options, recursive, errors, nestingContent, context);
|
|
616
339
|
}
|
|
617
340
|
}
|
|
618
341
|
}
|
|
@@ -620,11 +343,46 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent) {
|
|
|
620
343
|
// @ts-ignore
|
|
621
344
|
node != null &&
|
|
622
345
|
// previous.optimized != null &&
|
|
623
|
-
node.typ ==
|
|
346
|
+
node.typ == EnumToken.RuleNodeType &&
|
|
624
347
|
node.sel.includes('&')) {
|
|
625
348
|
fixSelector(node);
|
|
626
349
|
}
|
|
627
350
|
}
|
|
351
|
+
if (ast.typ == EnumToken.StyleSheetNodeType) {
|
|
352
|
+
let parent;
|
|
353
|
+
let parents = [ast];
|
|
354
|
+
while (parents.length > 0) {
|
|
355
|
+
parent = parents.shift();
|
|
356
|
+
// @ts-ignore
|
|
357
|
+
for (let k = 0; k < parent.chi.length; k++) {
|
|
358
|
+
// @ts-ignore
|
|
359
|
+
const node = parent.chi[k];
|
|
360
|
+
if (!('chi' in node) || node.typ == EnumToken.StyleSheetNodeType || (node.typ == EnumToken.AtRuleNodeType && node.nam == 'font-face')) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
// @ts-ignore
|
|
364
|
+
if (node.chi.length > 0) {
|
|
365
|
+
parents.push(node);
|
|
366
|
+
Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: parent });
|
|
367
|
+
for (const feature of options.features) {
|
|
368
|
+
feature.run(node, options, parent, context);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
// @ts-ignore
|
|
372
|
+
if (options.removeEmpty && node.chi.length == 0) {
|
|
373
|
+
// @ts-ignore
|
|
374
|
+
parent.chi.splice(k, 1);
|
|
375
|
+
k--;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
for (const feature of options.features) {
|
|
380
|
+
if ('cleanup' in feature) {
|
|
381
|
+
// @ts-ignore
|
|
382
|
+
feature.cleanup(ast, options, context);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
628
386
|
return ast;
|
|
629
387
|
}
|
|
630
388
|
function reduceSelector(selector) {
|
|
@@ -710,37 +468,14 @@ function hasDeclaration(node) {
|
|
|
710
468
|
// @ts-ignore
|
|
711
469
|
for (let i = 0; i < node.chi?.length; i++) {
|
|
712
470
|
// @ts-ignore
|
|
713
|
-
if (node.chi[i].typ ==
|
|
471
|
+
if (node.chi[i].typ == EnumToken.CommentNodeType) {
|
|
714
472
|
continue;
|
|
715
473
|
}
|
|
716
474
|
// @ts-ignore
|
|
717
|
-
return node.chi[i].typ ==
|
|
475
|
+
return node.chi[i].typ == EnumToken.DeclarationNodeType;
|
|
718
476
|
}
|
|
719
477
|
return true;
|
|
720
478
|
}
|
|
721
|
-
function minifyRule(ast) {
|
|
722
|
-
// @ts-ignore
|
|
723
|
-
if (!('chi' in ast) || ast.chi?.length <= 1) {
|
|
724
|
-
return ast;
|
|
725
|
-
}
|
|
726
|
-
// @ts-ignore
|
|
727
|
-
const j = ast.chi.length;
|
|
728
|
-
let k = 0;
|
|
729
|
-
let properties = new PropertyList();
|
|
730
|
-
// @ts-ignore
|
|
731
|
-
for (; k < j; k++) {
|
|
732
|
-
// @ts-ignore
|
|
733
|
-
const node = ast.chi[k];
|
|
734
|
-
if (node.typ == 'Comment' || node.typ == 'Declaration') {
|
|
735
|
-
properties.add(node);
|
|
736
|
-
continue;
|
|
737
|
-
}
|
|
738
|
-
break;
|
|
739
|
-
}
|
|
740
|
-
// @ts-ignore
|
|
741
|
-
ast.chi = [...properties].concat(ast.chi.slice(k));
|
|
742
|
-
return ast;
|
|
743
|
-
}
|
|
744
479
|
function splitRule(buffer) {
|
|
745
480
|
const result = [[]];
|
|
746
481
|
let str = '';
|
|
@@ -829,6 +564,300 @@ function splitRule(buffer) {
|
|
|
829
564
|
}
|
|
830
565
|
return result;
|
|
831
566
|
}
|
|
567
|
+
function matchSelectors(selector1, selector2, parentType, errors) {
|
|
568
|
+
let match = [[]];
|
|
569
|
+
const j = Math.min(selector1.reduce((acc, curr) => Math.min(acc, curr.length), selector1.length > 0 ? selector1[0].length : 0), selector2.reduce((acc, curr) => Math.min(acc, curr.length), selector2.length > 0 ? selector2[0].length : 0));
|
|
570
|
+
let i = 0;
|
|
571
|
+
let k;
|
|
572
|
+
let l;
|
|
573
|
+
let token;
|
|
574
|
+
let matching = true;
|
|
575
|
+
let matchFunction = 0;
|
|
576
|
+
let inAttr = 0;
|
|
577
|
+
for (; i < j; i++) {
|
|
578
|
+
k = 0;
|
|
579
|
+
token = selector1[0][i];
|
|
580
|
+
for (; k < selector1.length; k++) {
|
|
581
|
+
if (selector1[k][i] != token) {
|
|
582
|
+
matching = false;
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if (matching) {
|
|
587
|
+
l = 0;
|
|
588
|
+
for (; l < selector2.length; l++) {
|
|
589
|
+
if (selector2[l][i] != token) {
|
|
590
|
+
matching = false;
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
if (!matching) {
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
if (token == ',') {
|
|
599
|
+
match.push([]);
|
|
600
|
+
}
|
|
601
|
+
else {
|
|
602
|
+
if (token.endsWith('(')) {
|
|
603
|
+
matchFunction++;
|
|
604
|
+
}
|
|
605
|
+
if (token.endsWith('[')) {
|
|
606
|
+
inAttr++;
|
|
607
|
+
}
|
|
608
|
+
else if (token == ')') {
|
|
609
|
+
matchFunction--;
|
|
610
|
+
}
|
|
611
|
+
else if (token == ']') {
|
|
612
|
+
inAttr--;
|
|
613
|
+
}
|
|
614
|
+
match.at(-1).push(token);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
// invalid function
|
|
618
|
+
if (matchFunction != 0 || inAttr != 0) {
|
|
619
|
+
return null;
|
|
620
|
+
}
|
|
621
|
+
if (parentType != EnumToken.RuleNodeType) {
|
|
622
|
+
for (const part of match) {
|
|
623
|
+
if (part.length > 0 && combinators.includes(part[0].charAt(0))) {
|
|
624
|
+
return null;
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
if (match.length > 1) {
|
|
629
|
+
errors?.push({
|
|
630
|
+
action: 'ignore',
|
|
631
|
+
message: `minify: unsupported multilevel matching\n${JSON.stringify({
|
|
632
|
+
match,
|
|
633
|
+
selector1,
|
|
634
|
+
selector2
|
|
635
|
+
}, null, 1)}`
|
|
636
|
+
});
|
|
637
|
+
return null;
|
|
638
|
+
}
|
|
639
|
+
for (const part of match) {
|
|
640
|
+
while (part.length > 0) {
|
|
641
|
+
const token = part.at(-1);
|
|
642
|
+
if (token == ' ' || combinators.includes(token) || notEndingWith.includes(token.at(-1))) {
|
|
643
|
+
part.pop();
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
if (match.every(t => t.length == 0)) {
|
|
650
|
+
return null;
|
|
651
|
+
}
|
|
652
|
+
if (eq([['&']], match)) {
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
function reduce(acc, curr) {
|
|
656
|
+
if (acc === null) {
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
let hasCompoundSelector = true;
|
|
660
|
+
curr = curr.slice(match[0].length);
|
|
661
|
+
while (curr.length > 0) {
|
|
662
|
+
if (curr[0] == ' ') {
|
|
663
|
+
hasCompoundSelector = false;
|
|
664
|
+
curr.unshift('&');
|
|
665
|
+
continue;
|
|
666
|
+
}
|
|
667
|
+
break;
|
|
668
|
+
}
|
|
669
|
+
// invalid function match
|
|
670
|
+
if (curr.length > 0 && curr[0].endsWith('(') && curr.at(-1) != ')') {
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
if (curr.length == 1 && combinators.includes(curr[0].charAt(0))) {
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
if (hasCompoundSelector && curr.length > 0) {
|
|
677
|
+
hasCompoundSelector = !['&'].concat(combinators).includes(curr[0].charAt(0));
|
|
678
|
+
}
|
|
679
|
+
if (curr[0] == ':is(') {
|
|
680
|
+
let inFunction = 0;
|
|
681
|
+
let canReduce = true;
|
|
682
|
+
const isCompound = curr.reduce((acc, token, index) => {
|
|
683
|
+
if (index == 0) {
|
|
684
|
+
inFunction++;
|
|
685
|
+
canReduce = curr[1] == '&';
|
|
686
|
+
}
|
|
687
|
+
else if (token.endsWith('(')) {
|
|
688
|
+
if (inFunction == 0) {
|
|
689
|
+
canReduce = false;
|
|
690
|
+
}
|
|
691
|
+
inFunction++;
|
|
692
|
+
}
|
|
693
|
+
else if (token == ')') {
|
|
694
|
+
inFunction--;
|
|
695
|
+
}
|
|
696
|
+
else if (token == ',') {
|
|
697
|
+
if (!canReduce) {
|
|
698
|
+
canReduce = curr[index + 1] == '&';
|
|
699
|
+
}
|
|
700
|
+
acc.push([]);
|
|
701
|
+
}
|
|
702
|
+
else
|
|
703
|
+
acc.at(-1)?.push(token);
|
|
704
|
+
return acc;
|
|
705
|
+
}, [[]]);
|
|
706
|
+
if (inFunction > 0) {
|
|
707
|
+
canReduce = false;
|
|
708
|
+
}
|
|
709
|
+
if (canReduce) {
|
|
710
|
+
curr = isCompound.reduce((acc, curr) => {
|
|
711
|
+
if (acc.length > 0) {
|
|
712
|
+
acc.push(',');
|
|
713
|
+
}
|
|
714
|
+
acc.push(...curr);
|
|
715
|
+
return acc;
|
|
716
|
+
}, []);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
// @todo: check hasCompoundSelector && curr[0] == '&' && curr[1] == ' '
|
|
720
|
+
acc.push(match.length == 0 ? ['&'] : (hasCompoundSelector && curr[0] != '&' && (curr.length == 0 || !combinators.includes(curr[0].charAt(0))) ? ['&'].concat(curr) : curr));
|
|
721
|
+
return acc;
|
|
722
|
+
}
|
|
723
|
+
// @ts-ignore
|
|
724
|
+
selector1 = selector1.reduce(reduce, []);
|
|
725
|
+
// @ts-ignore
|
|
726
|
+
selector2 = selector2.reduce(reduce, []);
|
|
727
|
+
return selector1 == null || selector2 == null ? null : {
|
|
728
|
+
eq: eq(selector1, selector2),
|
|
729
|
+
match,
|
|
730
|
+
selector1,
|
|
731
|
+
selector2
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
function fixSelector(node) {
|
|
735
|
+
// @ts-ignore
|
|
736
|
+
if (node.sel.includes('&')) {
|
|
737
|
+
const attributes = parseString(node.sel);
|
|
738
|
+
for (const attr of walkValues(attributes)) {
|
|
739
|
+
if (attr.value.typ == EnumToken.PseudoClassFuncTokenType && attr.value.val == ':is') {
|
|
740
|
+
let i = attr.value.chi.length;
|
|
741
|
+
while (i--) {
|
|
742
|
+
if (attr.value.chi[i].typ == EnumToken.LiteralTokenType && attr.value.chi[i].val == '&') {
|
|
743
|
+
attr.value.chi.splice(i, 1);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
node.sel = attributes.reduce((acc, curr) => acc + renderToken(curr), '');
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
function wrapNodes(previous, node, match, ast, reducer, i, nodeIndex) {
|
|
752
|
+
// @ts-ignore
|
|
753
|
+
let pSel = match.selector1.reduce(reducer, []).join(',');
|
|
754
|
+
// @ts-ignore
|
|
755
|
+
let nSel = match.selector2.reduce(reducer, []).join(',');
|
|
756
|
+
// @ts-ignore
|
|
757
|
+
const wrapper = { ...previous, chi: [], sel: match.match.reduce(reducer, []).join(',') };
|
|
758
|
+
// @ts-ignore
|
|
759
|
+
Object.defineProperty(wrapper, 'raw', {
|
|
760
|
+
...definedPropertySettings,
|
|
761
|
+
// @ts-ignore
|
|
762
|
+
value: match.match.map(t => t.slice())
|
|
763
|
+
});
|
|
764
|
+
if (pSel == '&' || pSel === '') {
|
|
765
|
+
// @ts-ignore
|
|
766
|
+
wrapper.chi.push(...previous.chi);
|
|
767
|
+
// @ts-ignore
|
|
768
|
+
if ((nSel == '&' || nSel === '')) {
|
|
769
|
+
// @ts-ignore
|
|
770
|
+
wrapper.chi.push(...node.chi);
|
|
771
|
+
}
|
|
772
|
+
else {
|
|
773
|
+
// @ts-ignore
|
|
774
|
+
wrapper.chi.push(node);
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
// @ts-ignore
|
|
779
|
+
wrapper.chi.push(previous, node);
|
|
780
|
+
}
|
|
781
|
+
// @ts-ignore
|
|
782
|
+
ast.chi.splice(i, 1, wrapper);
|
|
783
|
+
// @ts-ignore
|
|
784
|
+
ast.chi.splice(nodeIndex, 1);
|
|
785
|
+
// @ts-ignore
|
|
786
|
+
previous.sel = pSel;
|
|
787
|
+
// @ts-ignore
|
|
788
|
+
previous.raw = match.selector1;
|
|
789
|
+
// @ts-ignore
|
|
790
|
+
node.sel = nSel;
|
|
791
|
+
// @ts-ignore
|
|
792
|
+
node.raw = match.selector2;
|
|
793
|
+
reduceRuleSelector(wrapper);
|
|
794
|
+
return wrapper;
|
|
795
|
+
}
|
|
796
|
+
function diff(n1, n2, reducer, options = {}) {
|
|
797
|
+
let node1 = n1;
|
|
798
|
+
let node2 = n2;
|
|
799
|
+
let exchanged = false;
|
|
800
|
+
if (node1.chi.length > node2.chi.length) {
|
|
801
|
+
const t = node1;
|
|
802
|
+
node1 = node2;
|
|
803
|
+
node2 = t;
|
|
804
|
+
exchanged = true;
|
|
805
|
+
}
|
|
806
|
+
let i = node1.chi.length;
|
|
807
|
+
let j = node2.chi.length;
|
|
808
|
+
if (i == 0 || j == 0) {
|
|
809
|
+
// @ts-ignore
|
|
810
|
+
return null;
|
|
811
|
+
}
|
|
812
|
+
// @ts-ignore
|
|
813
|
+
const raw1 = node1.raw;
|
|
814
|
+
// @ts-ignore
|
|
815
|
+
const raw2 = node2.raw;
|
|
816
|
+
// @ts-ignore
|
|
817
|
+
node1 = { ...node1, chi: node1.chi.slice() };
|
|
818
|
+
node2 = { ...node2, chi: node2.chi.slice() };
|
|
819
|
+
if (raw1 != null) {
|
|
820
|
+
Object.defineProperty(node1, 'raw', { ...definedPropertySettings, value: raw1 });
|
|
821
|
+
}
|
|
822
|
+
if (raw2 != null) {
|
|
823
|
+
Object.defineProperty(node2, 'raw', { ...definedPropertySettings, value: raw2 });
|
|
824
|
+
}
|
|
825
|
+
const intersect = [];
|
|
826
|
+
while (i--) {
|
|
827
|
+
if (node1.chi[i].typ == EnumToken.CommentNodeType) {
|
|
828
|
+
continue;
|
|
829
|
+
}
|
|
830
|
+
j = node2.chi.length;
|
|
831
|
+
if (j == 0) {
|
|
832
|
+
break;
|
|
833
|
+
}
|
|
834
|
+
while (j--) {
|
|
835
|
+
if (node2.chi[j].typ == EnumToken.CommentNodeType) {
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
if (node1.chi[i].nam == node2.chi[j].nam) {
|
|
839
|
+
if (eq(node1.chi[i], node2.chi[j])) {
|
|
840
|
+
intersect.push(node1.chi[i]);
|
|
841
|
+
node1.chi.splice(i, 1);
|
|
842
|
+
node2.chi.splice(j, 1);
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
// @ts-ignore
|
|
849
|
+
const result = (intersect.length == 0 ? null : {
|
|
850
|
+
...node1,
|
|
851
|
+
// @ts-ignore
|
|
852
|
+
sel: [...new Set([...(n1?.raw?.reduce(reducer, []) || splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) || splitRule(n2.sel))])].join(','),
|
|
853
|
+
chi: intersect.reverse()
|
|
854
|
+
});
|
|
855
|
+
if (result == null || [n1, n2].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + doRender(curr, options).code.length, 0) <= [node1, node2, result].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + doRender(curr, options).code.length, 0)) {
|
|
856
|
+
// @ts-ignore
|
|
857
|
+
return null;
|
|
858
|
+
}
|
|
859
|
+
return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node1 : node2 };
|
|
860
|
+
}
|
|
832
861
|
function reduceRuleSelector(node) {
|
|
833
862
|
if (node.raw == null) {
|
|
834
863
|
Object.defineProperty(node, 'raw', { ...definedPropertySettings, value: splitRule(node.sel) });
|
|
@@ -864,4 +893,4 @@ function reduceRuleSelector(node) {
|
|
|
864
893
|
}
|
|
865
894
|
}
|
|
866
895
|
|
|
867
|
-
export { combinators, hasDeclaration, minify,
|
|
896
|
+
export { combinators, hasDeclaration, minify, reduceSelector, splitRule };
|