@pi-r/chrome 0.11.3 → 0.12.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/extensions/css/remove-unused/index.js +423 -0
- package/index.d.ts +1 -1
- package/index.js +418 -797
- package/package.json +5 -5
- package/types/index.d.ts +40 -11
- package/types/squared.d.ts +2 -1
- package/util.d.ts +20 -0
- package/util.js +49 -0
|
@@ -0,0 +1,423 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { randomUUID } = require('node:crypto');
|
|
4
|
+
const Document = require('@e-mc/document');
|
|
5
|
+
const { DomWriter } = require('@e-mc/document/parse/dom');
|
|
6
|
+
const { escapePattern } = require('@e-mc/types');
|
|
7
|
+
const { PATTERN_PARENTHESIS, findClosingIndex, getNewlineString, replaceMatch, spliceSource, splitEnclosing } = require('@pi-r/chrome/util');
|
|
8
|
+
const PATTERN_STRING_SOME = '(?:\\s|' + DomWriter.PATTERN_COMMENT + '|`[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}`)*';
|
|
9
|
+
const PATTERN_STRING_MANY = PATTERN_STRING_SOME.slice(0, -1) + '+';
|
|
10
|
+
const PATTERN_VARIABLE = '--(?:[-\\w]+|\\\\\\S|[^\\u0000-\\u007F]+)+';
|
|
11
|
+
const CACHE_ATRULES = Object.create(null);
|
|
12
|
+
const CACHE_QUERY = new Map();
|
|
13
|
+
const CACHE_SELECTOR = new Map();
|
|
14
|
+
const REGEXP_COMMENT = new RegExp(DomWriter.PATTERN_COMMENT, 'g');
|
|
15
|
+
const REGEXP_QUOTEDVALUE = new RegExp(`\\b(?:@import${PATTERN_STRING_MANY}|content${PATTERN_STRING_SOME}:${PATTERN_STRING_SOME})(?:"[^"]*"|'[^']*')`, 'gi');
|
|
16
|
+
const REGEXP_VARIABLES = new RegExp(`(?<!style\\()(\\s*)(${PATTERN_VARIABLE})${PATTERN_STRING_SOME}:[^;}]*([;}])` + DomWriter.PATTERN_TRAILINGSPACE, 'g');
|
|
17
|
+
const REGEXP_FONTFACE = new RegExp(`(\\s*)@font-face${PATTERN_STRING_SOME}{([^}]+)}` + DomWriter.PATTERN_TRAILINGSPACE, 'gi');
|
|
18
|
+
const REGEXP_FONTFAMILY = new RegExp(`\\bfont-family${PATTERN_STRING_SOME}:([^;}]+)`, 'i');
|
|
19
|
+
const REGEXP_KEYFRAMES = new RegExp(`(\\s*)@keyframes${PATTERN_STRING_MANY}([^{]+){`, 'gi');
|
|
20
|
+
const REGEXP_PROPERTY = new RegExp(`(\\s*)@property${PATTERN_STRING_MANY}(${PATTERN_VARIABLE})${PATTERN_STRING_SOME}{`, 'gi');
|
|
21
|
+
const REGEXP_NTHCHILD = new RegExp(`\\(${PATTERN_STRING_SOME}([+-])?(?:(\\d*)[nN]|(0))?${PATTERN_STRING_SOME}([+-])?${PATTERN_STRING_SOME}(\\d*)(?:${PATTERN_STRING_MANY}[oO][fF]${PATTERN_STRING_MANY}(${PATTERN_PARENTHESIS})${PATTERN_STRING_SOME}\\)|${PATTERN_STRING_SOME}\\))`, 'g');
|
|
22
|
+
const REGEXP_LEADINGBRACE = new RegExp(`(.)${PATTERN_STRING_SOME}{$`);
|
|
23
|
+
const REGEXP_VARIABLES_UNSAFE = new RegExp(`(?<!style\\()(\\s*)(--[^\\s:]+)\\s*:[^;}]*([;}])` + DomWriter.PATTERN_TRAILINGSPACE, 'g');
|
|
24
|
+
const REGEXP_FONTFACE_UNSAFE = new RegExp(`(\\s*)@font-face\\s*{([^}]+)}` + DomWriter.PATTERN_TRAILINGSPACE, 'gi');
|
|
25
|
+
const REGEXP_FONTFAMILY_UNSAFE = /\bfont-family\s*:([^;}]+)/i;
|
|
26
|
+
const REGEXP_KEYFRAMES_UNSAFE = /(\s*)@keyframes\s+([^{]+){/gi;
|
|
27
|
+
const REGEXP_PROPERTY_UNSAFE = /(\s*)@property\s+(--\S+)\s*{/gi;
|
|
28
|
+
const REGEXP_NTHCHILD_UNSAFE = new RegExp(`\\(\\s*([+-])?(?:(\\d*)[nN]|(0))?\\s*([+-])?\\s*(\\d*)(?:\\s+[oO][fF]\\s+(${PATTERN_PARENTHESIS})\\s*\\)|\\s*\\))`, 'g');
|
|
29
|
+
const REGEXP_LEADINGBRACE_UNSAFE = /(.)\s*{$/;
|
|
30
|
+
const getEndIndex = (match) => match.index + match[0].length;
|
|
31
|
+
function cssUnused(source, options) {
|
|
32
|
+
const { usedVariables, usedFontFace, usedKeyframes, unusedStyles, unusedMedia, unusedSupports, unusedContainer, unusedScope, useUnsafeCssReplace, useSessionCache } = options.config;
|
|
33
|
+
if (!usedVariables && !usedFontFace && !usedKeyframes && !unusedStyles && !unusedMedia && !unusedSupports && !unusedContainer && !unusedScope) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const [stringSome, stringMany] = useUnsafeCssReplace ? ['\\s*', '\\s+'] : [PATTERN_STRING_SOME, PATTERN_STRING_MANY];
|
|
37
|
+
const replaceMap = [];
|
|
38
|
+
let current = source, modified = false, checkEmpty, match;
|
|
39
|
+
const parseSelector = (value) => {
|
|
40
|
+
const items = [];
|
|
41
|
+
const revised = value.replace(useUnsafeCssReplace ? REGEXP_NTHCHILD_UNSAFE : REGEXP_NTHCHILD, (...capture) => {
|
|
42
|
+
return '`%' + (items.push('\\(' + stringSome + (capture[1] === '-' ? '\\x2d' : '\\x2b?') + (capture[2] || '[01]?') + (capture[3] === '0' ? !capture[1] && !capture[2] && !capture[4] && !capture[5] ? '[+-]?0[nN]?' : '0' : '[nN]?') + stringSome + (capture[5] ? (capture[4] === '-' ? '\\x2d' : '\\x2b?') + stringSome + capture[5] : `(?:[+-]${stringSome}0)?`) + (capture[6] ? stringMany + '[oO][fF]' + stringMany + capture[6].trim() : '') + stringSome + '\\)') - 1) + '`';
|
|
43
|
+
});
|
|
44
|
+
let selector = '';
|
|
45
|
+
for (let i = 0, length = revised.length, casing = false, attr = false, quote = false; i < length; i++) {
|
|
46
|
+
let ch = revised[i], space = 0;
|
|
47
|
+
switch (ch) {
|
|
48
|
+
case '.':
|
|
49
|
+
case '#':
|
|
50
|
+
if (!attr) {
|
|
51
|
+
casing = true;
|
|
52
|
+
}
|
|
53
|
+
break;
|
|
54
|
+
case '[':
|
|
55
|
+
if (!quote) {
|
|
56
|
+
attr = true;
|
|
57
|
+
casing = false;
|
|
58
|
+
space = 2;
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case ']':
|
|
62
|
+
if (!quote || attr && revised[i - 1] === '"' && revised[i - 2] === '\\') {
|
|
63
|
+
if (quote) {
|
|
64
|
+
selector = selector.slice(0, -1) + '`%%%`';
|
|
65
|
+
quote = false;
|
|
66
|
+
}
|
|
67
|
+
attr = false;
|
|
68
|
+
casing = false;
|
|
69
|
+
space = 1;
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
case '=':
|
|
73
|
+
if (attr && !quote) {
|
|
74
|
+
casing = true;
|
|
75
|
+
space = 3;
|
|
76
|
+
}
|
|
77
|
+
break;
|
|
78
|
+
case '\\':
|
|
79
|
+
ch = '`%%%%`';
|
|
80
|
+
break;
|
|
81
|
+
case '"':
|
|
82
|
+
if (attr) {
|
|
83
|
+
if (!quote) {
|
|
84
|
+
ch = '`%%%`';
|
|
85
|
+
quote = true;
|
|
86
|
+
}
|
|
87
|
+
else if (revised[i - 1] !== '\\') {
|
|
88
|
+
ch = '`%%%`';
|
|
89
|
+
quote = false;
|
|
90
|
+
casing = false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case '~':
|
|
95
|
+
case '^':
|
|
96
|
+
case '$':
|
|
97
|
+
case '*':
|
|
98
|
+
case '|':
|
|
99
|
+
if (attr && !quote) {
|
|
100
|
+
space = 1;
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
case ' ':
|
|
104
|
+
if (attr && !quote) {
|
|
105
|
+
ch = '`%%`';
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case ':':
|
|
109
|
+
case ',':
|
|
110
|
+
if (!attr) {
|
|
111
|
+
casing = false;
|
|
112
|
+
}
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
selector += (space & 1 ? '`%%`' : '') + (!casing && ch >= 'a' && ch <= 'z' ? '`' + ch + ch.toUpperCase() + '`' : ch) + (space & 2 ? '`%%`' : '');
|
|
116
|
+
}
|
|
117
|
+
selector = escapePattern(selector)
|
|
118
|
+
.replace(/\s*(>|~(?!=)|\\\+|\\\*(?!=)])\s*/g, (...capture) => stringSome + capture[1] + stringSome)
|
|
119
|
+
.replace(/`([a-z][A-Z]|%{2,4})`/g, (...capture) => {
|
|
120
|
+
switch (capture[1]) {
|
|
121
|
+
case '%%':
|
|
122
|
+
return stringSome;
|
|
123
|
+
case '%%%':
|
|
124
|
+
return `(?:["']|${stringSome})`;
|
|
125
|
+
case '%%%%':
|
|
126
|
+
return '\\\\{0,}';
|
|
127
|
+
default:
|
|
128
|
+
return `[${capture[1]}]`;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
for (let i = 0, length = revised.length; i < length; ++i) {
|
|
132
|
+
selector = selector.replace('`%' + i + '`', items[i]);
|
|
133
|
+
}
|
|
134
|
+
return selector.replace(/ +/g, stringMany) + stringSome;
|
|
135
|
+
};
|
|
136
|
+
const replaceUnunsed = (name, items, nesting, increment = 1) => {
|
|
137
|
+
for (let i = 0; i < items.length; i += increment) {
|
|
138
|
+
const value = items[i].trim();
|
|
139
|
+
let valueTo;
|
|
140
|
+
const key = name + '_' + value + (increment === 2 && (valueTo = items[i + 1].trim()) ? '_' + valueTo : '') + (useUnsafeCssReplace ? '_1' : '');
|
|
141
|
+
let pattern = CACHE_QUERY.get(key), rule;
|
|
142
|
+
if (!pattern) {
|
|
143
|
+
let flags = 'gi', selector = '', revised = false;
|
|
144
|
+
if (name === 'container') {
|
|
145
|
+
for (let j = 0, length = value.length, casing = true; j < length; j++) {
|
|
146
|
+
let ch = value[j];
|
|
147
|
+
if (!casing) {
|
|
148
|
+
ch = ch.toLowerCase();
|
|
149
|
+
}
|
|
150
|
+
else if (ch === '(') {
|
|
151
|
+
casing = false;
|
|
152
|
+
}
|
|
153
|
+
if (casing || ch < 'a' || ch > 'z') {
|
|
154
|
+
selector += value[j];
|
|
155
|
+
if (selector.endsWith(' not ')) {
|
|
156
|
+
selector = selector.replace(/ not $/, ' `nN``oO``tT` ');
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
selector += '`' + ch + ch.toUpperCase() + '`';
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
flags = 'g';
|
|
164
|
+
}
|
|
165
|
+
else if (name === 'scope') {
|
|
166
|
+
selector = `\\(${stringSome + parseSelector(value)}\\)`;
|
|
167
|
+
if (valueTo) {
|
|
168
|
+
selector += `${stringMany}[tT][oO]${stringMany}\\(${stringSome + parseSelector(valueTo)}\\)`;
|
|
169
|
+
}
|
|
170
|
+
flags = 'g';
|
|
171
|
+
revised = true;
|
|
172
|
+
}
|
|
173
|
+
else if (name === 'supports' && /^selector\(/i.test(value)) {
|
|
174
|
+
const startIndex = value.indexOf('(');
|
|
175
|
+
const endIndex = value.lastIndexOf(')');
|
|
176
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
177
|
+
selector = '[sS][eE][lL][eE][cC][tT][oO][rR]\\(' + stringSome + parseSelector(value.slice(startIndex + 1, endIndex)) + '\\)';
|
|
178
|
+
flags = 'g';
|
|
179
|
+
revised = true;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
if (!revised) {
|
|
183
|
+
selector = escapePattern(selector || value)
|
|
184
|
+
.replace(/\s*(\\[()])\s*/g, (...capture) => stringSome + capture[1] + stringSome)
|
|
185
|
+
.replace(/:\s+/g, stringSome + ':' + stringSome)
|
|
186
|
+
.replace(/\s+([<>/]|<=|>=|\\\*)\s+/g, (...capture) => stringSome + capture[1] + stringSome)
|
|
187
|
+
.replace(/ +/g, stringMany);
|
|
188
|
+
if (flags === 'g') {
|
|
189
|
+
selector = selector.replace(/`([a-z][A-Z])`/g, (...capture) => `[${capture[1]}]`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
pattern = new RegExp('(\\s*)@' + (flags === 'g' ? name.split('').map(ch => `[${ch + ch.toUpperCase()}]`).join('') : name) + stringMany + selector + stringSome + '{', flags);
|
|
193
|
+
if (useSessionCache !== false) {
|
|
194
|
+
CACHE_QUERY.set(key, pattern);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
pattern.lastIndex = 0;
|
|
199
|
+
}
|
|
200
|
+
while (rule = pattern.exec(current)) {
|
|
201
|
+
if (!nesting) {
|
|
202
|
+
const block = Array.from(current.slice(0, rule.index).matchAll(/[{}]/g));
|
|
203
|
+
if (block.filter(open => open[0] === '{').length !== block.filter(close => close[0] === '}').length) {
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const [endIndex, trailing] = findClosingIndex(current, getEndIndex(rule), '{');
|
|
208
|
+
if (endIndex !== -1) {
|
|
209
|
+
current = spliceSource(current, rule.index, endIndex, pattern, rule[1], trailing);
|
|
210
|
+
(checkEmpty ||= {})[name] = true;
|
|
211
|
+
modified = true;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
if (!useUnsafeCssReplace) {
|
|
217
|
+
const replaceBracket = (pattern) => {
|
|
218
|
+
let bracket;
|
|
219
|
+
while (bracket = pattern.exec(current)) {
|
|
220
|
+
const segment = bracket[0];
|
|
221
|
+
if (/[{}]/.test(segment)) {
|
|
222
|
+
const placeholder = '`' + randomUUID().slice(0, 18) + '`';
|
|
223
|
+
replaceMap.push([placeholder, segment]);
|
|
224
|
+
current = replaceMatch(bracket, current, placeholder, pattern);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
pattern.lastIndex = 0;
|
|
228
|
+
};
|
|
229
|
+
replaceBracket(REGEXP_COMMENT);
|
|
230
|
+
replaceBracket(REGEXP_QUOTEDVALUE);
|
|
231
|
+
const values = splitEnclosing(current, /\b(?<!-)url/gi);
|
|
232
|
+
for (let i = 0, length = values.length; i < length; ++i) {
|
|
233
|
+
const seg = values[i];
|
|
234
|
+
if (/^url\([^{}]*[{}].*\)$/is.test(seg)) {
|
|
235
|
+
replaceMap.push([values[i] = randomUUID().slice(0, 18), seg]);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (replaceMap.length > 0) {
|
|
239
|
+
current = values.join('');
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (unusedMedia) {
|
|
243
|
+
replaceUnunsed('media', unusedMedia, true);
|
|
244
|
+
}
|
|
245
|
+
if (unusedSupports) {
|
|
246
|
+
replaceUnunsed('supports', unusedSupports, true);
|
|
247
|
+
}
|
|
248
|
+
if (unusedContainer) {
|
|
249
|
+
replaceUnunsed('container', unusedContainer, false);
|
|
250
|
+
}
|
|
251
|
+
if (unusedScope) {
|
|
252
|
+
replaceUnunsed('scope', unusedScope.map(item => [item.start || '', item.end || '']).flat(), false, 2);
|
|
253
|
+
}
|
|
254
|
+
if (unusedStyles) {
|
|
255
|
+
current = (function recurse(target, child) {
|
|
256
|
+
let output = '', index = 0, pendingStart = 0, pendingEnd = 0, found = -1;
|
|
257
|
+
while ((found = target.indexOf('{', index)) !== -1) {
|
|
258
|
+
++found;
|
|
259
|
+
const closing = findClosingIndex(target, found, '{')[0];
|
|
260
|
+
if (closing === -1) {
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
let header = target.slice(index, found), invalid = 0, content;
|
|
264
|
+
for (const value of unusedStyles) {
|
|
265
|
+
const key = value + (child ? '_1' : '') + (useUnsafeCssReplace ? '_2' : '');
|
|
266
|
+
const pattern = CACHE_SELECTOR.get(key);
|
|
267
|
+
let single, group;
|
|
268
|
+
if (!pattern) {
|
|
269
|
+
const selector = parseSelector(value) + (child ? `(?:${stringSome}&${stringSome})*` : '');
|
|
270
|
+
single = new RegExp(`(^|;)(${stringSome})(?<!${child ? '&|' : ''}@[^};]*)${selector}\\{$`);
|
|
271
|
+
group = new RegExp(`((?:^|;)[^{]*${stringSome}(,${stringSome}|(?<!@[^};]*)))(${(child ? '(?:&\\s+|(?<!&))' : '') + selector})(,[^{]*)?\\{$`, 'g');
|
|
272
|
+
if (useSessionCache !== false) {
|
|
273
|
+
CACHE_SELECTOR.set(key, [single, group]);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
[single, group] = pattern;
|
|
278
|
+
}
|
|
279
|
+
if (match = single.exec(header)) {
|
|
280
|
+
content = match[1] === ';' ? header.slice(0, match.index + 1) + match[2].replace(/[^\n]+$/, '') : undefined;
|
|
281
|
+
invalid = 1;
|
|
282
|
+
break;
|
|
283
|
+
}
|
|
284
|
+
let leading = -1, first = true;
|
|
285
|
+
while (match = group.exec(header)) {
|
|
286
|
+
const start = match.index + match[1].length;
|
|
287
|
+
if (!child && first) {
|
|
288
|
+
if (match[1].trimEnd().endsWith(';')) {
|
|
289
|
+
leading = start;
|
|
290
|
+
}
|
|
291
|
+
first = false;
|
|
292
|
+
}
|
|
293
|
+
const sibling = match[2].startsWith(',');
|
|
294
|
+
const trailing = match[4];
|
|
295
|
+
const offset = trailing && !sibling ? /^,\s*/.exec(trailing)[0].length : 1;
|
|
296
|
+
header = header.slice(0, start - (sibling ? match[2].length : 0)) + header.slice(start + match[3].length + (trailing ? sibling ? 0 : offset : /\s$/.test(match[3]) ? -1 : 0));
|
|
297
|
+
group.lastIndex = match.index;
|
|
298
|
+
invalid = 2;
|
|
299
|
+
}
|
|
300
|
+
if (invalid) {
|
|
301
|
+
group.lastIndex = 0;
|
|
302
|
+
const empty = (useUnsafeCssReplace ? REGEXP_LEADINGBRACE_UNSAFE : REGEXP_LEADINGBRACE).exec(header);
|
|
303
|
+
if (empty) {
|
|
304
|
+
if (header.trim() === '{') {
|
|
305
|
+
content = undefined;
|
|
306
|
+
invalid = 1;
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
if (leading !== -1 && empty[1] === ';') {
|
|
310
|
+
content = target.slice(index, found).slice(0, leading).replace(/[^\n;]+$/, '');
|
|
311
|
+
invalid = 1;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (invalid === 0 || invalid === 2) {
|
|
318
|
+
const trailing = target.slice(found, closing);
|
|
319
|
+
if (content = recurse(trailing, true)) {
|
|
320
|
+
content = header + content;
|
|
321
|
+
}
|
|
322
|
+
else if (invalid === 2) {
|
|
323
|
+
content = header + trailing;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (content) {
|
|
327
|
+
if (pendingEnd) {
|
|
328
|
+
output = target.slice(pendingStart, pendingEnd) + content;
|
|
329
|
+
pendingEnd = 0;
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
output += content;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
else if (!invalid) {
|
|
336
|
+
if (output) {
|
|
337
|
+
output += target.slice(index, closing);
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
pendingEnd = closing;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
else if (pendingEnd) {
|
|
344
|
+
output = target.slice(pendingStart, pendingEnd);
|
|
345
|
+
pendingEnd = 0;
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
pendingStart = closing;
|
|
349
|
+
}
|
|
350
|
+
index = closing;
|
|
351
|
+
}
|
|
352
|
+
if (output) {
|
|
353
|
+
modified = true;
|
|
354
|
+
return output + target.slice(index);
|
|
355
|
+
}
|
|
356
|
+
return child ? '' : target;
|
|
357
|
+
})(current, false);
|
|
358
|
+
}
|
|
359
|
+
if (usedVariables) {
|
|
360
|
+
let pattern = useUnsafeCssReplace ? REGEXP_VARIABLES_UNSAFE : REGEXP_VARIABLES;
|
|
361
|
+
while (match = pattern.exec(current)) {
|
|
362
|
+
if (!usedVariables.includes(match[2])) {
|
|
363
|
+
current = replaceMatch(match, current, match[3] === ';' ? getNewlineString(match[1], match[4]) : '', pattern);
|
|
364
|
+
modified = true;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
pattern.lastIndex = 0;
|
|
368
|
+
pattern = useUnsafeCssReplace ? REGEXP_PROPERTY_UNSAFE : REGEXP_PROPERTY;
|
|
369
|
+
while (match = pattern.exec(current)) {
|
|
370
|
+
if (!usedVariables.includes(match[2])) {
|
|
371
|
+
const [endIndex, trailing] = findClosingIndex(current, getEndIndex(match), '{');
|
|
372
|
+
if (endIndex !== -1) {
|
|
373
|
+
current = spliceSource(current, match.index, endIndex, pattern, match[1], trailing);
|
|
374
|
+
modified = true;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
pattern.lastIndex = 0;
|
|
379
|
+
}
|
|
380
|
+
if (usedFontFace) {
|
|
381
|
+
const pattern = useUnsafeCssReplace ? REGEXP_FONTFACE_UNSAFE : REGEXP_FONTFACE;
|
|
382
|
+
const fontFamily = useUnsafeCssReplace ? REGEXP_FONTFAMILY_UNSAFE : REGEXP_FONTFAMILY;
|
|
383
|
+
while (match = pattern.exec(current)) {
|
|
384
|
+
const font = fontFamily.exec(match[0]);
|
|
385
|
+
if (font && !usedFontFace.includes(font[1].trim().replace(/^(["'])(.+)\1$/s, (...content) => content[2]))) {
|
|
386
|
+
current = spliceSource(current, match.index, getEndIndex(match), pattern, match[1], match[3]);
|
|
387
|
+
modified = true;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
pattern.lastIndex = 0;
|
|
391
|
+
}
|
|
392
|
+
if (usedKeyframes) {
|
|
393
|
+
const pattern = useUnsafeCssReplace ? REGEXP_KEYFRAMES_UNSAFE : REGEXP_KEYFRAMES;
|
|
394
|
+
while (match = pattern.exec(current)) {
|
|
395
|
+
if (!usedKeyframes.includes(match[2].trim())) {
|
|
396
|
+
const [endIndex, trailing] = findClosingIndex(current, getEndIndex(match), '{');
|
|
397
|
+
if (endIndex !== -1) {
|
|
398
|
+
current = spliceSource(current, match.index, endIndex, pattern, match[1], trailing);
|
|
399
|
+
modified = true;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
pattern.lastIndex = 0;
|
|
404
|
+
}
|
|
405
|
+
if (modified) {
|
|
406
|
+
for (const name in checkEmpty) {
|
|
407
|
+
const pattern = CACHE_ATRULES[name + (useUnsafeCssReplace ? '_1' : '')] ||= new RegExp(`(\\s*)@${name}[^{]*{${stringSome}}` + DomWriter.PATTERN_TRAILINGSPACE, 'gi');
|
|
408
|
+
while (match = pattern.exec(current)) {
|
|
409
|
+
current = spliceSource(current, match.index, getEndIndex(match), pattern, match[1], match[2]);
|
|
410
|
+
}
|
|
411
|
+
pattern.lastIndex = 0;
|
|
412
|
+
}
|
|
413
|
+
if (replaceMap.length > 0) {
|
|
414
|
+
for (const [placeholder, content] of replaceMap.reverse()) {
|
|
415
|
+
current = current.replace(placeholder, content);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
return current;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
var index = Document.signExtensionType(cssUnused, 'css');
|
|
422
|
+
|
|
423
|
+
module.exports = index;
|
package/index.d.ts
CHANGED
|
@@ -2,6 +2,6 @@ import type { IFileManager } from '@e-mc/types/lib';
|
|
|
2
2
|
|
|
3
3
|
import type { ChromeDocumentConstructor, DocumentAsset } from './types';
|
|
4
4
|
|
|
5
|
-
declare const Chrome: ChromeDocumentConstructor<IFileManager
|
|
5
|
+
declare const Chrome: ChromeDocumentConstructor<IFileManager, DocumentAsset>;
|
|
6
6
|
|
|
7
7
|
export = Chrome;
|