@tbela99/css-parser 1.3.3 → 1.4.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/CHANGELOG.md +44 -0
- package/README.md +64 -48
- package/dist/config.json.js +3 -0
- package/dist/index-umd-web.js +2266 -631
- package/dist/index.cjs +2271 -620
- package/dist/index.d.ts +522 -181
- package/dist/lib/ast/expand.js +5 -10
- package/dist/lib/ast/features/calc.js +3 -2
- package/dist/lib/ast/features/inlinecssvariables.js +5 -3
- package/dist/lib/ast/features/prefix.js +1 -1
- package/dist/lib/ast/features/shorthand.js +1 -0
- package/dist/lib/ast/features/transform.js +13 -19
- package/dist/lib/ast/features/type.js +1 -1
- package/dist/lib/ast/minify.js +6 -3
- package/dist/lib/ast/transform/compute.js +2 -4
- package/dist/lib/ast/transform/matrix.js +20 -20
- package/dist/lib/ast/transform/minify.js +105 -12
- package/dist/lib/ast/transform/rotate.js +11 -11
- package/dist/lib/ast/transform/scale.js +6 -6
- package/dist/lib/ast/transform/skew.js +4 -4
- package/dist/lib/ast/transform/translate.js +3 -3
- package/dist/lib/ast/transform/utils.js +30 -37
- package/dist/lib/ast/types.js +76 -5
- package/dist/lib/ast/walk.js +77 -58
- package/dist/lib/fs/resolve.js +69 -10
- package/dist/lib/parser/declaration/list.js +6 -1
- package/dist/lib/parser/parse.js +1169 -312
- package/dist/lib/parser/tokenize.js +33 -20
- package/dist/lib/parser/utils/declaration.js +54 -0
- package/dist/lib/parser/utils/hash.js +86 -0
- package/dist/lib/parser/utils/text.js +8 -0
- package/dist/lib/renderer/render.js +26 -7
- package/dist/lib/syntax/color/relativecolor.js +0 -3
- package/dist/lib/syntax/syntax.js +36 -18
- package/dist/lib/validation/at-rules/container.js +11 -0
- package/dist/lib/validation/at-rules/counter-style.js +11 -0
- package/dist/lib/validation/at-rules/font-feature-values.js +11 -0
- package/dist/lib/validation/at-rules/keyframes.js +11 -0
- package/dist/lib/validation/at-rules/layer.js +11 -0
- package/dist/lib/validation/at-rules/media.js +11 -0
- package/dist/lib/validation/at-rules/page-margin-box.js +11 -0
- package/dist/lib/validation/at-rules/page.js +11 -0
- package/dist/lib/validation/at-rules/supports.js +11 -0
- package/dist/lib/validation/at-rules/when.js +11 -0
- package/dist/lib/validation/config.js +0 -2
- package/dist/lib/validation/config.json.js +36 -4
- package/dist/lib/validation/parser/parse.js +53 -2
- package/dist/lib/validation/syntax.js +204 -36
- package/dist/lib/validation/syntaxes/compound-selector.js +1 -2
- package/dist/lib/validation/syntaxes/relative-selector-list.js +2 -5
- package/dist/node.js +60 -18
- package/dist/types.d.ts +17 -0
- package/dist/types.js +20 -0
- package/dist/web.js +43 -17
- package/package.json +20 -17
- package/dist/lib/validation/parser/types.js +0 -54
package/dist/lib/parser/parse.js
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
import { isIdentStart, isIdent, isIdentColor, mathFuncs, isColor, parseColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage,
|
|
2
|
-
import { EnumToken, ColorType, ValidationLevel, SyntaxValidationResult } from '../ast/types.js';
|
|
3
|
-
import {
|
|
4
|
-
import { walkValues,
|
|
1
|
+
import { isIdentStart, isIdent, isIdentColor, mathFuncs, isColor, parseColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, parseDimension, isHexColor, isHash, mediaTypes } from '../syntax/syntax.js';
|
|
2
|
+
import { EnumToken, ColorType, ValidationLevel, ModuleCaseTransformEnum, ModuleScopeEnumOptions, SyntaxValidationResult } from '../ast/types.js';
|
|
3
|
+
import { definedPropertySettings, minify, combinators } from '../ast/minify.js';
|
|
4
|
+
import { walkValues, WalkerEvent, walk, WalkerOptionEnum } from '../ast/walk.js';
|
|
5
5
|
import { expand } from '../ast/expand.js';
|
|
6
6
|
import './utils/config.js';
|
|
7
7
|
import { parseDeclarationNode } from './utils/declaration.js';
|
|
8
|
+
import { camelize, dasherize } from './utils/text.js';
|
|
8
9
|
import { renderToken } from '../renderer/render.js';
|
|
9
10
|
import '../renderer/sourcemap/lib/encode.js';
|
|
10
11
|
import { funcLike, timingFunc, timelineFunc, COLORS_NAMES, systemColors, deprecatedSystemColors, colorsFunc } from '../syntax/color/utils/constants.js';
|
|
11
12
|
import { buildExpression } from '../ast/math/expression.js';
|
|
12
13
|
import { tokenize, tokenizeStream } from './tokenize.js';
|
|
13
14
|
import '../validation/config.js';
|
|
14
|
-
import '../validation/parser/types.js';
|
|
15
15
|
import '../validation/parser/parse.js';
|
|
16
16
|
import { validateSelector } from '../validation/selector.js';
|
|
17
17
|
import { validateAtRule } from '../validation/atrule.js';
|
|
18
18
|
import { splitTokenList } from '../validation/utils/list.js';
|
|
19
19
|
import '../validation/syntaxes/complex-selector.js';
|
|
20
20
|
import { validateKeyframeSelector } from '../validation/syntaxes/keyframe-selector.js';
|
|
21
|
-
import { evaluateSyntax } from '../validation/syntax.js';
|
|
21
|
+
import { isNodeAllowedInContext, evaluateSyntax } from '../validation/syntax.js';
|
|
22
22
|
import { validateAtRuleKeyframes } from '../validation/at-rules/keyframes.js';
|
|
23
|
+
import { hashAlgorithms, hash } from './utils/hash.js';
|
|
23
24
|
|
|
24
25
|
const urlTokenMatcher = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/;
|
|
25
26
|
const trimWhiteSpace = [EnumToken.CommentTokenType, EnumToken.GtTokenType, EnumToken.GteTokenType, EnumToken.LtTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType];
|
|
@@ -39,16 +40,20 @@ const enumTokenHints = new Set([
|
|
|
39
40
|
function reject(reason) {
|
|
40
41
|
throw new Error(reason ?? 'Parsing aborted');
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
/**
|
|
44
|
+
* replace token in its parent node
|
|
45
|
+
* @param parent
|
|
46
|
+
* @param value
|
|
47
|
+
* @param replacement
|
|
48
|
+
*/
|
|
45
49
|
function replaceToken(parent, value, replacement) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
for (const node of (Array.isArray(replacement) ? replacement : [replacement])) {
|
|
51
|
+
if ('parent' in value && value.parent != node.parent) {
|
|
52
|
+
Object.defineProperty(node, 'parent', {
|
|
53
|
+
...definedPropertySettings,
|
|
54
|
+
value: value.parent
|
|
55
|
+
});
|
|
56
|
+
}
|
|
52
57
|
}
|
|
53
58
|
if (parent.typ == EnumToken.BinaryExpressionTokenType) {
|
|
54
59
|
if (parent.l == value) {
|
|
@@ -59,22 +64,138 @@ function replaceToken(parent, value, replacement) {
|
|
|
59
64
|
}
|
|
60
65
|
}
|
|
61
66
|
else {
|
|
62
|
-
// @ts-ignore
|
|
63
67
|
const target = 'val' in parent && Array.isArray(parent.val) ? parent.val : parent.chi;
|
|
64
68
|
// @ts-ignore
|
|
65
69
|
const index = target.indexOf(value);
|
|
66
70
|
if (index == -1) {
|
|
67
71
|
return;
|
|
68
72
|
}
|
|
69
|
-
// @ts-ignore
|
|
70
73
|
target.splice(index, 1, ...(Array.isArray(replacement) ? replacement : [replacement]));
|
|
71
74
|
}
|
|
72
75
|
}
|
|
76
|
+
/**
|
|
77
|
+
* transform case of key name
|
|
78
|
+
* @param key
|
|
79
|
+
* @param how
|
|
80
|
+
*
|
|
81
|
+
* @throws Error
|
|
82
|
+
* @private
|
|
83
|
+
*/
|
|
84
|
+
function getKeyName(key, how) {
|
|
85
|
+
switch (how) {
|
|
86
|
+
case ModuleCaseTransformEnum.CamelCase:
|
|
87
|
+
case ModuleCaseTransformEnum.CamelCaseOnly:
|
|
88
|
+
return camelize(key);
|
|
89
|
+
case ModuleCaseTransformEnum.DashCase:
|
|
90
|
+
case ModuleCaseTransformEnum.DashCaseOnly:
|
|
91
|
+
return dasherize(key);
|
|
92
|
+
}
|
|
93
|
+
return key;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* generate scoped name
|
|
97
|
+
* @param localName
|
|
98
|
+
* @param filePath
|
|
99
|
+
* @param pattern
|
|
100
|
+
* @param hashLength
|
|
101
|
+
*
|
|
102
|
+
* @throws Error
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
async function generateScopedName(localName, filePath, pattern, hashLength = 5) {
|
|
106
|
+
if (localName.startsWith('--')) {
|
|
107
|
+
localName = localName.slice(2);
|
|
108
|
+
}
|
|
109
|
+
const matches = /.*?(([^/]+)\/)?([^/\\]*?)(\.([^?/]+))?([?].*)?$/.exec(filePath);
|
|
110
|
+
const folder = matches?.[2]?.replace?.(/[^A-Za-z0-9_-]/g, "_") ?? '';
|
|
111
|
+
const fileBase = matches?.[3] ?? '';
|
|
112
|
+
const ext = matches?.[5] ?? '';
|
|
113
|
+
const path = filePath.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
114
|
+
// sanitize localName for safe char set (replace spaces/illegal chars)
|
|
115
|
+
const safeLocal = localName.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
116
|
+
const hashString = `${localName}::${filePath}`;
|
|
117
|
+
let result = '';
|
|
118
|
+
let inParens = 0;
|
|
119
|
+
let key = '';
|
|
120
|
+
let position = 0;
|
|
121
|
+
// Compose final scoped name. Ensure the entire class doesn't start with digit:
|
|
122
|
+
for (const char of pattern) {
|
|
123
|
+
position += char.length;
|
|
124
|
+
if (char == '[') {
|
|
125
|
+
inParens++;
|
|
126
|
+
if (inParens != 1) {
|
|
127
|
+
throw new Error(`Unexpected character: '${char} at position ${position - 1}' in pattern '${pattern}'`);
|
|
128
|
+
}
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (char == ']') {
|
|
132
|
+
inParens--;
|
|
133
|
+
if (inParens != 0) {
|
|
134
|
+
throw new Error(`Unexpected character: '${char}:${position - 1}'`);
|
|
135
|
+
}
|
|
136
|
+
let hashAlgo = null;
|
|
137
|
+
let length = null;
|
|
138
|
+
if (key.includes(':')) {
|
|
139
|
+
const parts = key.split(':');
|
|
140
|
+
if (parts.length == 2) {
|
|
141
|
+
// @ts-ignore
|
|
142
|
+
[key, length] = parts;
|
|
143
|
+
// @ts-ignore
|
|
144
|
+
if (key == 'hash' && hashAlgorithms.includes(length)) {
|
|
145
|
+
// @ts-ignore
|
|
146
|
+
hashAlgo = length;
|
|
147
|
+
length = null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (parts.length == 3) {
|
|
151
|
+
// @ts-ignore
|
|
152
|
+
[key, hashAlgo, length] = parts;
|
|
153
|
+
}
|
|
154
|
+
if (length != null && !Number.isInteger(+length)) {
|
|
155
|
+
throw new Error(`Unsupported hash length: '${length}'. expecting format [hash:length] or [hash:hash-algo:length]`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
switch (key) {
|
|
159
|
+
case 'hash':
|
|
160
|
+
result += await hash(hashString, length ?? hashLength, hashAlgo);
|
|
161
|
+
break;
|
|
162
|
+
case 'name':
|
|
163
|
+
result += length != null ? fileBase.slice(0, +length) : fileBase;
|
|
164
|
+
break;
|
|
165
|
+
case 'local':
|
|
166
|
+
result += length != null ? safeLocal.slice(0, +length) : localName;
|
|
167
|
+
break;
|
|
168
|
+
case 'ext':
|
|
169
|
+
result += length != null ? ext.slice(0, +length) : ext;
|
|
170
|
+
break;
|
|
171
|
+
case 'path':
|
|
172
|
+
result += length != null ? path.slice(0, +length) : path;
|
|
173
|
+
break;
|
|
174
|
+
case 'folder':
|
|
175
|
+
result += length != null ? folder.slice(0, +length) : folder;
|
|
176
|
+
break;
|
|
177
|
+
default:
|
|
178
|
+
throw new Error(`Unsupported key: '${key}'`);
|
|
179
|
+
}
|
|
180
|
+
key = '';
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (inParens > 0) {
|
|
184
|
+
key += char;
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
result += char;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
// if leading char is digit, prefix underscore (very rare)
|
|
191
|
+
return (/^[0-9]/.test(result) ? '_' : '') + result;
|
|
192
|
+
}
|
|
73
193
|
/**
|
|
74
194
|
* parse css string
|
|
75
195
|
* @param iter
|
|
76
196
|
* @param options
|
|
77
197
|
*
|
|
198
|
+
* @throws Error
|
|
78
199
|
* @private
|
|
79
200
|
*/
|
|
80
201
|
async function doParse(iter, options = {}) {
|
|
@@ -106,6 +227,9 @@ async function doParse(iter, options = {}) {
|
|
|
106
227
|
if (typeof options.validation == 'boolean') {
|
|
107
228
|
options.validation = options.validation ? ValidationLevel.All : ValidationLevel.None;
|
|
108
229
|
}
|
|
230
|
+
if (options.module) {
|
|
231
|
+
options.expandNestingRules = true;
|
|
232
|
+
}
|
|
109
233
|
if (options.expandNestingRules) {
|
|
110
234
|
options.nestingRules = false;
|
|
111
235
|
}
|
|
@@ -119,6 +243,8 @@ async function doParse(iter, options = {}) {
|
|
|
119
243
|
const stats = {
|
|
120
244
|
src: options.src ?? '',
|
|
121
245
|
bytesIn: 0,
|
|
246
|
+
nodesCount: 0,
|
|
247
|
+
tokensCount: 0,
|
|
122
248
|
importedBytesIn: 0,
|
|
123
249
|
parse: `0ms`,
|
|
124
250
|
minify: `0ms`,
|
|
@@ -147,14 +273,107 @@ async function doParse(iter, options = {}) {
|
|
|
147
273
|
src: ''
|
|
148
274
|
};
|
|
149
275
|
}
|
|
150
|
-
let
|
|
151
|
-
let
|
|
276
|
+
let valuesHandlers;
|
|
277
|
+
let preValuesHandlers;
|
|
278
|
+
let postValuesHandlers;
|
|
279
|
+
let preVisitorsHandlersMap;
|
|
280
|
+
let visitorsHandlersMap;
|
|
281
|
+
let postVisitorsHandlersMap;
|
|
152
282
|
const rawTokens = [];
|
|
153
283
|
const imports = [];
|
|
284
|
+
let item;
|
|
285
|
+
let node;
|
|
154
286
|
// @ts-ignore ignore error
|
|
155
287
|
let isAsync = typeof iter[Symbol.asyncIterator] === 'function';
|
|
288
|
+
if (options.visitor != null) {
|
|
289
|
+
valuesHandlers = new Map;
|
|
290
|
+
preValuesHandlers = new Map;
|
|
291
|
+
postValuesHandlers = new Map;
|
|
292
|
+
preVisitorsHandlersMap = new Map;
|
|
293
|
+
visitorsHandlersMap = new Map;
|
|
294
|
+
postVisitorsHandlersMap = new Map;
|
|
295
|
+
const visitors = Object.entries(options.visitor);
|
|
296
|
+
let key;
|
|
297
|
+
let value;
|
|
298
|
+
let i;
|
|
299
|
+
for (i = 0; i < visitors.length; i++) {
|
|
300
|
+
key = visitors[i][0];
|
|
301
|
+
value = visitors[i][1];
|
|
302
|
+
if (Number.isInteger(+key)) {
|
|
303
|
+
visitors.splice(i + 1, 0, ...Object.entries(value));
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
if (Array.isArray(value)) {
|
|
307
|
+
// @ts-ignore
|
|
308
|
+
visitors.splice(i + 1, 0, ...value.map((item) => [key, item]));
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (key in EnumToken) {
|
|
312
|
+
if (typeof value == 'function') {
|
|
313
|
+
if (!valuesHandlers.has(EnumToken[key])) {
|
|
314
|
+
valuesHandlers.set(EnumToken[key], []);
|
|
315
|
+
}
|
|
316
|
+
valuesHandlers.get(EnumToken[key]).push(value);
|
|
317
|
+
}
|
|
318
|
+
else if (typeof value == 'object' && 'type' in value && 'handler' in value && value.type in WalkerEvent) {
|
|
319
|
+
if (value.type == WalkerEvent.Enter) {
|
|
320
|
+
if (!preValuesHandlers.has(EnumToken[key])) {
|
|
321
|
+
preValuesHandlers.set(EnumToken[key], []);
|
|
322
|
+
}
|
|
323
|
+
preValuesHandlers.get(EnumToken[key]).push(value.handler);
|
|
324
|
+
}
|
|
325
|
+
else if (value.type == WalkerEvent.Leave) {
|
|
326
|
+
if (!postValuesHandlers.has(EnumToken[key])) {
|
|
327
|
+
postValuesHandlers.set(EnumToken[key], []);
|
|
328
|
+
}
|
|
329
|
+
postValuesHandlers.get(EnumToken[key]).push(value.handler);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
errors.push({ action: 'ignore', message: `doParse: visitor.${key} is not a valid key name` });
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
else if (['Declaration', 'Rule', 'AtRule', 'KeyframesRule', 'KeyframesAtRule'].includes(key)) {
|
|
337
|
+
if (typeof value == 'function') {
|
|
338
|
+
if (!visitorsHandlersMap.has(key)) {
|
|
339
|
+
visitorsHandlersMap.set(key, []);
|
|
340
|
+
}
|
|
341
|
+
visitorsHandlersMap.get(key).push(value);
|
|
342
|
+
}
|
|
343
|
+
else if (typeof value == 'object') {
|
|
344
|
+
if ('type' in value && 'handler' in value && value.type in WalkerEvent) {
|
|
345
|
+
if (value.type == WalkerEvent.Enter) {
|
|
346
|
+
if (!preVisitorsHandlersMap.has(key)) {
|
|
347
|
+
preVisitorsHandlersMap.set(key, []);
|
|
348
|
+
}
|
|
349
|
+
preVisitorsHandlersMap.get(key).push(value.handler);
|
|
350
|
+
}
|
|
351
|
+
else if (value.type == WalkerEvent.Leave) {
|
|
352
|
+
if (!postVisitorsHandlersMap.has(key)) {
|
|
353
|
+
postVisitorsHandlersMap.set(key, []);
|
|
354
|
+
}
|
|
355
|
+
postVisitorsHandlersMap.get(key).push(value.handler);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
if (!visitorsHandlersMap.has(key)) {
|
|
360
|
+
visitorsHandlersMap.set(key, []);
|
|
361
|
+
}
|
|
362
|
+
visitorsHandlersMap.get(key).push(value);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
errors.push({ action: 'ignore', message: `doParse: visitor.${key} is not a valid key name` });
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
errors.push({ action: 'ignore', message: `doParse: visitor.${key} is not a valid key name` });
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
156
374
|
while (item = isAsync ? (await iter.next()).value : iter.next().value) {
|
|
157
375
|
stats.bytesIn = item.bytesIn;
|
|
376
|
+
stats.tokensCount++;
|
|
158
377
|
rawTokens.push(item);
|
|
159
378
|
if (item.hint != null && BadTokensTypes.includes(item.hint)) {
|
|
160
379
|
const node = getTokenType(item.token, item.hint);
|
|
@@ -182,7 +401,7 @@ async function doParse(iter, options = {}) {
|
|
|
182
401
|
ast.loc.end = item.end;
|
|
183
402
|
}
|
|
184
403
|
if (item.token == ';' || item.token == '{') {
|
|
185
|
-
node = parseNode(tokens, context, options, errors, src, map, rawTokens);
|
|
404
|
+
node = parseNode(tokens, context, options, errors, src, map, rawTokens, stats);
|
|
186
405
|
rawTokens.length = 0;
|
|
187
406
|
if (node != null) {
|
|
188
407
|
if ('chi' in node) {
|
|
@@ -226,7 +445,7 @@ async function doParse(iter, options = {}) {
|
|
|
226
445
|
map = new Map;
|
|
227
446
|
}
|
|
228
447
|
else if (item.token == '}') {
|
|
229
|
-
parseNode(tokens, context, options, errors, src, map, rawTokens);
|
|
448
|
+
parseNode(tokens, context, options, errors, src, map, rawTokens, stats);
|
|
230
449
|
rawTokens.length = 0;
|
|
231
450
|
if (context.loc != null) {
|
|
232
451
|
context.loc.end = item.end;
|
|
@@ -247,7 +466,7 @@ async function doParse(iter, options = {}) {
|
|
|
247
466
|
}
|
|
248
467
|
}
|
|
249
468
|
if (tokens.length > 0) {
|
|
250
|
-
node = parseNode(tokens, context, options, errors, src, map, rawTokens);
|
|
469
|
+
node = parseNode(tokens, context, options, errors, src, map, rawTokens, stats);
|
|
251
470
|
rawTokens.length = 0;
|
|
252
471
|
if (node != null) {
|
|
253
472
|
if (node.typ == EnumToken.AtRuleNodeType && node.nam == 'import') {
|
|
@@ -276,6 +495,7 @@ async function doParse(iter, options = {}) {
|
|
|
276
495
|
const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream) : tokenize({
|
|
277
496
|
stream,
|
|
278
497
|
buffer: '',
|
|
498
|
+
offset: 0,
|
|
279
499
|
position: { ind: 0, lin: 1, col: 1 },
|
|
280
500
|
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
281
501
|
}), Object.assign({}, options, {
|
|
@@ -310,256 +530,675 @@ async function doParse(iter, options = {}) {
|
|
|
310
530
|
if (options.expandNestingRules) {
|
|
311
531
|
ast = expand(ast);
|
|
312
532
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
const postValuesHandlers = new Map;
|
|
316
|
-
const preVisitorsHandlersMap = new Map;
|
|
317
|
-
const visitorsHandlersMap = new Map;
|
|
318
|
-
const postVisitorsHandlersMap = new Map;
|
|
319
|
-
const allValuesHandlers = [];
|
|
533
|
+
let replacement;
|
|
534
|
+
let callable;
|
|
320
535
|
if (options.visitor != null) {
|
|
321
|
-
for (const
|
|
322
|
-
if (
|
|
323
|
-
if (
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
536
|
+
for (const result of walk(ast)) {
|
|
537
|
+
if (valuesHandlers.size > 0 || preVisitorsHandlersMap.size > 0 || visitorsHandlersMap.size > 0 || postVisitorsHandlersMap.size > 0) {
|
|
538
|
+
if ((result.node.typ == EnumToken.DeclarationNodeType &&
|
|
539
|
+
(preVisitorsHandlersMap.has('Declaration') || visitorsHandlersMap.has('Declaration') || postVisitorsHandlersMap.has('Declaration'))) ||
|
|
540
|
+
(result.node.typ == EnumToken.AtRuleNodeType && (preVisitorsHandlersMap.has('AtRule') || visitorsHandlersMap.has('AtRule') || postVisitorsHandlersMap.has('AtRule'))) ||
|
|
541
|
+
(result.node.typ == EnumToken.KeyframesAtRuleNodeType && (preVisitorsHandlersMap.has('KeyframesAtRule') || visitorsHandlersMap.has('KeyframesAtRule') || postVisitorsHandlersMap.has('KeyframesAtRule')))) {
|
|
542
|
+
const handlers = [];
|
|
543
|
+
const key = result.node.typ == EnumToken.DeclarationNodeType ? 'Declaration' : result.node.typ == EnumToken.AtRuleNodeType ? 'AtRule' : 'KeyframesAtRule';
|
|
544
|
+
if (preVisitorsHandlersMap.has(key)) {
|
|
545
|
+
// @ts-ignore
|
|
546
|
+
handlers.push(...preVisitorsHandlersMap.get(key));
|
|
329
547
|
}
|
|
330
|
-
|
|
331
|
-
|
|
548
|
+
if (visitorsHandlersMap.has(key)) {
|
|
549
|
+
// @ts-ignore
|
|
550
|
+
handlers.push(...visitorsHandlersMap.get(key));
|
|
551
|
+
}
|
|
552
|
+
if (postVisitorsHandlersMap.has(key)) {
|
|
553
|
+
// @ts-ignore
|
|
554
|
+
handlers.push(...postVisitorsHandlersMap.get(key));
|
|
555
|
+
}
|
|
556
|
+
let node = result.node;
|
|
557
|
+
for (const handler of handlers) {
|
|
558
|
+
callable = typeof handler == 'function' ? handler : handler[camelize(node.typ == EnumToken.DeclarationNodeType || node.typ == EnumToken.AtRuleNodeType ? node.nam : node.val)];
|
|
559
|
+
if (callable == null) {
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
replacement = callable(node, result.parent);
|
|
563
|
+
if (replacement == null) {
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
isAsync = replacement instanceof Promise || Object.getPrototypeOf(replacement).constructor.name == 'AsyncFunction';
|
|
567
|
+
if (replacement) {
|
|
568
|
+
replacement = await replacement;
|
|
569
|
+
}
|
|
570
|
+
if (replacement == null || replacement == node) {
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
// @ts-ignore
|
|
574
|
+
node = replacement;
|
|
575
|
+
//
|
|
576
|
+
if (Array.isArray(node)) {
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (node != result.node) {
|
|
581
|
+
// @ts-ignore
|
|
582
|
+
replaceToken(result.parent, result.node, node);
|
|
332
583
|
}
|
|
333
584
|
}
|
|
334
|
-
else
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
585
|
+
else if ((result.node.typ == EnumToken.RuleNodeType && (preVisitorsHandlersMap.has('Rule') || visitorsHandlersMap.has('Rule') || postVisitorsHandlersMap.has('Rule'))) ||
|
|
586
|
+
(result.node.typ == EnumToken.KeyFramesRuleNodeType && (preVisitorsHandlersMap.has('KeyframesRule') || visitorsHandlersMap.has('KeyframesRule') || postVisitorsHandlersMap.has('KeyframesRule')))) {
|
|
587
|
+
const handlers = [];
|
|
588
|
+
const key = result.node.typ == EnumToken.RuleNodeType ? 'Rule' : 'KeyframesRule';
|
|
589
|
+
if (preVisitorsHandlersMap.has(key)) {
|
|
590
|
+
handlers.push(...preVisitorsHandlersMap.get(key));
|
|
591
|
+
}
|
|
592
|
+
if (visitorsHandlersMap.has(key)) {
|
|
593
|
+
handlers.push(...visitorsHandlersMap.get(key));
|
|
594
|
+
}
|
|
595
|
+
if (postVisitorsHandlersMap.has(key)) {
|
|
596
|
+
handlers.push(...postVisitorsHandlersMap.get(key));
|
|
597
|
+
}
|
|
598
|
+
let node = result.node;
|
|
599
|
+
for (const callable of handlers) {
|
|
600
|
+
replacement = callable(node, result.parent);
|
|
601
|
+
if (replacement == null) {
|
|
602
|
+
continue;
|
|
603
|
+
}
|
|
604
|
+
isAsync = replacement instanceof Promise || Object.getPrototypeOf(replacement).constructor.name == 'AsyncFunction';
|
|
605
|
+
if (replacement) {
|
|
606
|
+
replacement = await replacement;
|
|
346
607
|
}
|
|
347
|
-
|
|
348
|
-
|
|
608
|
+
if (replacement == null || replacement == node) {
|
|
609
|
+
continue;
|
|
610
|
+
}
|
|
611
|
+
// @ts-ignore
|
|
612
|
+
node = replacement;
|
|
613
|
+
//
|
|
614
|
+
if (Array.isArray(node)) {
|
|
615
|
+
break;
|
|
349
616
|
}
|
|
350
617
|
}
|
|
351
|
-
|
|
352
|
-
|
|
618
|
+
// @ts-ignore
|
|
619
|
+
if (node != result.node) {
|
|
620
|
+
// @ts-ignore
|
|
621
|
+
replaceToken(result.parent, result.node, node);
|
|
353
622
|
}
|
|
354
623
|
}
|
|
355
|
-
else {
|
|
356
|
-
|
|
624
|
+
else if (valuesHandlers.size > 0) {
|
|
625
|
+
let node = null;
|
|
626
|
+
node = result.node;
|
|
627
|
+
if (valuesHandlers.has(node.typ)) {
|
|
628
|
+
for (const valueHandler of valuesHandlers.get(node.typ)) {
|
|
629
|
+
callable = valueHandler;
|
|
630
|
+
replacement = callable(node, result.parent);
|
|
631
|
+
if (replacement == null) {
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
isAsync = replacement instanceof Promise || Object.getPrototypeOf(replacement).constructor.name == 'AsyncFunction';
|
|
635
|
+
if (isAsync) {
|
|
636
|
+
replacement = await replacement;
|
|
637
|
+
}
|
|
638
|
+
if (replacement != null && replacement != node) {
|
|
639
|
+
node = replacement;
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (node != result.node) {
|
|
644
|
+
// @ts-ignore
|
|
645
|
+
replaceToken(result.parent, value, node);
|
|
646
|
+
}
|
|
647
|
+
const tokens = 'tokens' in result.node ? result.node.tokens : [];
|
|
648
|
+
if ('val' in result.node && Array.isArray(result.node.val)) {
|
|
649
|
+
tokens.push(...result.node.val);
|
|
650
|
+
}
|
|
651
|
+
if (tokens.length == 0) {
|
|
652
|
+
continue;
|
|
653
|
+
}
|
|
654
|
+
for (const { value, parent, root } of walkValues(tokens, result.node)) {
|
|
655
|
+
node = value;
|
|
656
|
+
if (valuesHandlers.has(node.typ)) {
|
|
657
|
+
for (const valueHandler of valuesHandlers.get(node.typ)) {
|
|
658
|
+
callable = valueHandler;
|
|
659
|
+
let result = callable(node, parent, root);
|
|
660
|
+
if (result == null) {
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
isAsync = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction';
|
|
664
|
+
if (isAsync) {
|
|
665
|
+
result = await result;
|
|
666
|
+
}
|
|
667
|
+
if (result != null && result != node) {
|
|
668
|
+
node = result;
|
|
669
|
+
}
|
|
670
|
+
//
|
|
671
|
+
if (Array.isArray(node)) {
|
|
672
|
+
break;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (node != value) {
|
|
677
|
+
// @ts-ignore
|
|
678
|
+
replaceToken(parent, value, node);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
357
681
|
}
|
|
358
682
|
}
|
|
359
|
-
|
|
360
|
-
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
if (options.minify) {
|
|
686
|
+
if (ast.chi.length > 0) {
|
|
687
|
+
let passes = options.pass ?? 1;
|
|
688
|
+
while (passes--) {
|
|
689
|
+
minify(ast, options, true, errors, false);
|
|
361
690
|
}
|
|
362
691
|
}
|
|
363
|
-
|
|
364
|
-
|
|
692
|
+
}
|
|
693
|
+
stats.bytesIn += stats.importedBytesIn;
|
|
694
|
+
let endTime = performance.now();
|
|
695
|
+
const result = {
|
|
696
|
+
ast,
|
|
697
|
+
errors,
|
|
698
|
+
stats: {
|
|
699
|
+
...stats,
|
|
700
|
+
parse: `${(endParseTime - startTime).toFixed(2)}ms`,
|
|
701
|
+
minify: `${(endTime - endParseTime).toFixed(2)}ms`,
|
|
702
|
+
total: `${(endTime - startTime).toFixed(2)}ms`
|
|
365
703
|
}
|
|
366
|
-
|
|
367
|
-
|
|
704
|
+
};
|
|
705
|
+
if (options.module) {
|
|
706
|
+
const moduleSettings = {
|
|
707
|
+
hashLength: 5,
|
|
708
|
+
filePath: '',
|
|
709
|
+
scoped: ModuleScopeEnumOptions.Local,
|
|
710
|
+
naming: ModuleCaseTransformEnum.IgnoreCase,
|
|
711
|
+
pattern: '',
|
|
712
|
+
generateScopedName,
|
|
713
|
+
...(typeof options.module != 'object' ? {} : options.module)
|
|
714
|
+
};
|
|
715
|
+
const parseModuleTime = performance.now();
|
|
716
|
+
const namesMapping = {};
|
|
717
|
+
const global = new Set;
|
|
718
|
+
const processed = new Set;
|
|
719
|
+
const pattern = typeof options.module == 'boolean' ? null : moduleSettings.pattern;
|
|
720
|
+
const importMapping = {};
|
|
721
|
+
const cssVariablesMap = {};
|
|
722
|
+
const importedCssVariables = {};
|
|
723
|
+
let mapping = {};
|
|
724
|
+
let revMapping = {};
|
|
725
|
+
let filePath = typeof options.module == 'boolean' ? options.src : (moduleSettings.filePath ?? options.src);
|
|
726
|
+
filePath = filePath === '' ? options.src : options.resolve(filePath, options.dirname(options.src), options.cwd).relative;
|
|
727
|
+
if (typeof options.module == 'number') {
|
|
728
|
+
if (options.module & ModuleCaseTransformEnum.CamelCase) {
|
|
729
|
+
moduleSettings.naming = ModuleCaseTransformEnum.CamelCase;
|
|
730
|
+
}
|
|
731
|
+
else if (options.module & ModuleCaseTransformEnum.CamelCaseOnly) {
|
|
732
|
+
moduleSettings.naming = ModuleCaseTransformEnum.CamelCaseOnly;
|
|
733
|
+
}
|
|
734
|
+
else if (options.module & ModuleCaseTransformEnum.DashCase) {
|
|
735
|
+
moduleSettings.naming = ModuleCaseTransformEnum.DashCase;
|
|
736
|
+
}
|
|
737
|
+
else if (options.module & ModuleCaseTransformEnum.DashCaseOnly) {
|
|
738
|
+
moduleSettings.naming = ModuleCaseTransformEnum.DashCaseOnly;
|
|
739
|
+
}
|
|
740
|
+
if (options.module & ModuleScopeEnumOptions.Global) {
|
|
741
|
+
moduleSettings.scoped = ModuleScopeEnumOptions.Global;
|
|
742
|
+
}
|
|
743
|
+
if (options.module & ModuleScopeEnumOptions.Pure) {
|
|
744
|
+
// @ts-ignore
|
|
745
|
+
moduleSettings.scoped |= ModuleScopeEnumOptions.Pure;
|
|
746
|
+
}
|
|
747
|
+
if (options.module & ModuleScopeEnumOptions.ICSS) {
|
|
748
|
+
// @ts-ignore
|
|
749
|
+
moduleSettings.scoped |= ModuleScopeEnumOptions.ICSS;
|
|
750
|
+
}
|
|
368
751
|
}
|
|
369
|
-
if (
|
|
370
|
-
|
|
752
|
+
if (typeof moduleSettings.scoped == 'boolean') {
|
|
753
|
+
moduleSettings.scoped = moduleSettings.scoped ? ModuleScopeEnumOptions.Local : ModuleScopeEnumOptions.Global;
|
|
371
754
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
755
|
+
moduleSettings.filePath = filePath;
|
|
756
|
+
moduleSettings.pattern = pattern != null && pattern !== '' ? pattern : (filePath === '' ? `[local]_[hash]` : `[local]_[hash]_[name]`);
|
|
757
|
+
for (const { node, parent } of walk(ast)) {
|
|
758
|
+
if (node.typ == EnumToken.CssVariableImportTokenType) {
|
|
759
|
+
const url = node.val.find(t => t.typ == EnumToken.StringTokenType).val.slice(1, -1);
|
|
760
|
+
const src = options.resolve(url, options.dirname(options.src), options.cwd);
|
|
761
|
+
const result = options.load(url, options.src);
|
|
762
|
+
const stream = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction' ? await result : result;
|
|
763
|
+
const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream) : tokenize({
|
|
764
|
+
stream,
|
|
765
|
+
buffer: '',
|
|
766
|
+
offset: 0,
|
|
767
|
+
position: { ind: 0, lin: 1, col: 1 },
|
|
768
|
+
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
769
|
+
}), Object.assign({}, options, {
|
|
770
|
+
minify: false,
|
|
771
|
+
setParent: false,
|
|
772
|
+
src: src.relative
|
|
773
|
+
}));
|
|
774
|
+
cssVariablesMap[node.nam] = root.cssModuleVariables;
|
|
775
|
+
parent.chi.splice(parent.chi.indexOf(node), 1);
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
if (node.typ == EnumToken.CssVariableDeclarationMapTokenType) {
|
|
779
|
+
const from = node.from.find(t => t.typ == EnumToken.IdenTokenType || isIdentColor(t));
|
|
780
|
+
if (!(from.val in cssVariablesMap)) {
|
|
781
|
+
errors.push({
|
|
782
|
+
node,
|
|
783
|
+
message: `could not resolve @value import from '${from.val}'`,
|
|
784
|
+
action: 'drop'
|
|
785
|
+
});
|
|
397
786
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
787
|
+
else {
|
|
788
|
+
for (const token of node.vars) {
|
|
789
|
+
if (token.typ == EnumToken.IdenTokenType || isIdentColor(token)) {
|
|
790
|
+
if (!(token.val in cssVariablesMap[from.val])) {
|
|
791
|
+
errors.push({
|
|
792
|
+
node,
|
|
793
|
+
message: `value '${token.val}' is not exported from '${from.val}'`,
|
|
794
|
+
action: 'drop'
|
|
795
|
+
});
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
result.cssModuleVariables ??= {};
|
|
799
|
+
result.cssModuleVariables[token.val] = importedCssVariables[token.val] = cssVariablesMap[from.val][token.val];
|
|
800
|
+
}
|
|
801
|
+
}
|
|
401
802
|
}
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
803
|
+
parent.chi.splice(parent.chi.indexOf(node), 1);
|
|
804
|
+
continue;
|
|
805
|
+
}
|
|
806
|
+
if (node.typ == EnumToken.CssVariableTokenType) {
|
|
807
|
+
if (parent?.typ == EnumToken.StyleSheetNodeType) {
|
|
808
|
+
if (result.cssModuleVariables == null) {
|
|
809
|
+
result.cssModuleVariables = {};
|
|
810
|
+
}
|
|
811
|
+
result.cssModuleVariables[node.nam] = node;
|
|
405
812
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
813
|
+
parent.chi.splice(parent.chi.indexOf(node), 1);
|
|
814
|
+
continue;
|
|
815
|
+
}
|
|
816
|
+
if (node.typ == EnumToken.DeclarationNodeType) {
|
|
817
|
+
if (node.nam.startsWith('--')) {
|
|
818
|
+
if (!(node.nam in namesMapping)) {
|
|
819
|
+
let result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? node.nam : moduleSettings.generateScopedName(node.nam, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
820
|
+
let value = result instanceof Promise ? await result : result;
|
|
821
|
+
mapping[node.nam] = '--' + (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(value, moduleSettings.naming) : value);
|
|
822
|
+
revMapping[node.nam] = node.nam;
|
|
412
823
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
824
|
+
node.nam = mapping[node.nam];
|
|
825
|
+
}
|
|
826
|
+
if ('composes' == node.nam.toLowerCase()) {
|
|
827
|
+
const tokens = [];
|
|
828
|
+
let isValid = true;
|
|
829
|
+
for (const token of node.val) {
|
|
830
|
+
if (token.typ == EnumToken.ComposesSelectorNodeType) {
|
|
831
|
+
if (!(token.r == null || token.r.typ == EnumToken.StringTokenType || token.r.typ == EnumToken.IdenTokenType)) {
|
|
832
|
+
errors.push({
|
|
833
|
+
action: 'drop',
|
|
834
|
+
message: `composes '${EnumToken[token.r.typ]}' is not supported`,
|
|
835
|
+
node
|
|
836
|
+
});
|
|
837
|
+
isValid = false;
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
840
|
+
tokens.push(token);
|
|
841
|
+
}
|
|
416
842
|
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
843
|
+
// find parent rule
|
|
844
|
+
let parentRule = node.parent;
|
|
845
|
+
while (parentRule != null && parentRule.typ != EnumToken.RuleNodeType) {
|
|
846
|
+
parentRule = parentRule.parent;
|
|
420
847
|
}
|
|
421
|
-
if (
|
|
848
|
+
if (!isValid || tokens.length == 0) {
|
|
849
|
+
if (tokens.length == 0) {
|
|
850
|
+
errors.push({
|
|
851
|
+
action: 'drop',
|
|
852
|
+
message: `composes is empty`,
|
|
853
|
+
node
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
parentRule.chi.splice(parentRule.chi.indexOf(node), 1);
|
|
422
857
|
continue;
|
|
423
858
|
}
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
859
|
+
for (const token of tokens) {
|
|
860
|
+
// composes: a b c;
|
|
861
|
+
if (token.r == null) {
|
|
862
|
+
for (const rule of token.l) {
|
|
863
|
+
if (rule.typ == EnumToken.WhitespaceTokenType || rule.typ == EnumToken.CommentTokenType) {
|
|
864
|
+
continue;
|
|
865
|
+
}
|
|
866
|
+
if (!(rule.val in mapping)) {
|
|
867
|
+
let result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? rule.val : moduleSettings.generateScopedName(rule.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
868
|
+
let value = result instanceof Promise ? await result : result;
|
|
869
|
+
mapping[rule.val] = (rule.typ == EnumToken.DashedIdenTokenType ? '--' : '') + (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(value, moduleSettings.naming) : value);
|
|
870
|
+
revMapping[mapping[rule.val]] = rule.val;
|
|
871
|
+
}
|
|
872
|
+
if (parentRule != null) {
|
|
873
|
+
for (const tk of parentRule.tokens) {
|
|
874
|
+
if (tk.typ == EnumToken.ClassSelectorTokenType) {
|
|
875
|
+
const val = tk.val.slice(1);
|
|
876
|
+
if (val in revMapping) {
|
|
877
|
+
const key = revMapping[val];
|
|
878
|
+
mapping[key] = [...new Set([...mapping[key].split(' '), mapping[rule.val]])].join(' ');
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
// composes: a b c from 'file.css';
|
|
886
|
+
else if (token.r.typ == EnumToken.String) {
|
|
887
|
+
const url = token.r.val.slice(1, -1);
|
|
888
|
+
const src = options.resolve(url, options.dirname(options.src), options.cwd);
|
|
889
|
+
const result = options.load(url, options.src);
|
|
890
|
+
const stream = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction' ? await result : result;
|
|
891
|
+
const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream) : tokenize({
|
|
892
|
+
stream,
|
|
893
|
+
buffer: '',
|
|
894
|
+
offset: 0,
|
|
895
|
+
position: { ind: 0, lin: 1, col: 1 },
|
|
896
|
+
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
897
|
+
}), Object.assign({}, options, {
|
|
898
|
+
minify: false,
|
|
899
|
+
setParent: false,
|
|
900
|
+
src: src.relative
|
|
901
|
+
}));
|
|
902
|
+
const srcIndex = (src.relative.startsWith('/') || src.relative.startsWith('../') ? '' : './') + src.relative;
|
|
903
|
+
if (Object.keys(root.mapping).length > 0) {
|
|
904
|
+
importMapping[srcIndex] = {};
|
|
905
|
+
}
|
|
906
|
+
if (parentRule != null) {
|
|
907
|
+
for (const tk of parentRule.tokens) {
|
|
908
|
+
if (tk.typ == EnumToken.ClassSelectorTokenType) {
|
|
909
|
+
const val = tk.val.slice(1);
|
|
910
|
+
if (val in revMapping) {
|
|
911
|
+
const key = revMapping[val];
|
|
912
|
+
const values = [];
|
|
913
|
+
for (const iden of token.l) {
|
|
914
|
+
if (iden.typ != EnumToken.IdenTokenType && iden.typ != EnumToken.DashedIdenTokenType) {
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
if (!(iden.val in root.mapping)) {
|
|
918
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? iden.val : moduleSettings.generateScopedName(iden.val, srcIndex, moduleSettings.pattern, moduleSettings.hashLength);
|
|
919
|
+
let value = result instanceof Promise ? await result : result;
|
|
920
|
+
root.mapping[iden.val] = (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(value, moduleSettings.naming) : value);
|
|
921
|
+
root.revMapping[root.mapping[iden.val]] = iden.val;
|
|
922
|
+
}
|
|
923
|
+
importMapping[srcIndex][iden.val] = root.mapping[iden.val];
|
|
924
|
+
values.push(root.mapping[iden.val]);
|
|
925
|
+
}
|
|
926
|
+
mapping[key] = [...new Set([...mapping[key].split(' '), ...values])].join(' ');
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
// composes: a b c from global;
|
|
933
|
+
else if (token.r.typ == EnumToken.IdenTokenType) {
|
|
934
|
+
// global
|
|
935
|
+
if (parentRule != null) {
|
|
936
|
+
if ('global' == token.r.val.toLowerCase()) {
|
|
937
|
+
for (const tk of parentRule.tokens) {
|
|
938
|
+
if (tk.typ == EnumToken.ClassSelectorTokenType) {
|
|
939
|
+
const val = tk.val.slice(1);
|
|
940
|
+
if (val in revMapping) {
|
|
941
|
+
const key = revMapping[val];
|
|
942
|
+
mapping[key] = [...new Set([...mapping[key].split(' '), ...(token.l.reduce((acc, curr) => {
|
|
943
|
+
if (curr.typ == EnumToken.IdenTokenType) {
|
|
944
|
+
acc.push(curr.val);
|
|
945
|
+
}
|
|
946
|
+
return acc;
|
|
947
|
+
}, []))])].join(' ');
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
else {
|
|
953
|
+
errors.push({
|
|
954
|
+
action: 'drop',
|
|
955
|
+
message: `composes '${token.r.val}' is not supported`,
|
|
956
|
+
node
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
429
961
|
}
|
|
962
|
+
parentRule.chi.splice(parentRule.chi.indexOf(node), 1);
|
|
430
963
|
}
|
|
431
|
-
if (node
|
|
432
|
-
|
|
433
|
-
|
|
964
|
+
if (node.typ == EnumToken.DeclarationNodeType && ['grid-column', 'grid-column-start', 'grid-column-end', 'grid-row', 'grid-row-start', 'grid-row-end', 'grid-template', 'grid-template-columns', 'grid-template-rows'].includes(node.nam)) {
|
|
965
|
+
for (const { value } of walkValues(node.val, node)) {
|
|
966
|
+
if (value.typ != EnumToken.IdenTokenType) {
|
|
967
|
+
continue;
|
|
968
|
+
}
|
|
969
|
+
let idenToken = value.val;
|
|
970
|
+
let suffix = '';
|
|
971
|
+
if (idenToken.endsWith('-start')) {
|
|
972
|
+
suffix = '-start';
|
|
973
|
+
idenToken = idenToken.slice(0, -6);
|
|
974
|
+
}
|
|
975
|
+
else if (idenToken.endsWith('-end')) {
|
|
976
|
+
suffix = '-end';
|
|
977
|
+
idenToken = idenToken.slice(0, -4);
|
|
978
|
+
}
|
|
979
|
+
if (!(idenToken in mapping)) {
|
|
980
|
+
let result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? idenToken : moduleSettings.generateScopedName(idenToken, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
981
|
+
if (result instanceof Promise) {
|
|
982
|
+
result = await result;
|
|
983
|
+
}
|
|
984
|
+
mapping[idenToken] = result;
|
|
985
|
+
revMapping[result] = idenToken;
|
|
986
|
+
if (suffix !== '') {
|
|
987
|
+
idenToken += suffix;
|
|
988
|
+
if (!(idenToken in mapping)) {
|
|
989
|
+
mapping[idenToken] = result + suffix;
|
|
990
|
+
revMapping[result + suffix] = idenToken;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
value.val = mapping[idenToken];
|
|
995
|
+
}
|
|
434
996
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
997
|
+
else if (node.nam == 'grid-template-areas' || node.nam == 'grid-template') {
|
|
998
|
+
for (let i = 0; i < node.val.length; i++) {
|
|
999
|
+
if (node.val[i].typ == EnumToken.String) {
|
|
1000
|
+
const tokens = parseString(node.val[i].val.slice(1, -1), { location: true });
|
|
1001
|
+
for (const { value } of walkValues(tokens)) {
|
|
1002
|
+
if (value.typ == EnumToken.IdenTokenType || value.typ == EnumToken.DashedIdenTokenType) {
|
|
1003
|
+
if (value.val in mapping) {
|
|
1004
|
+
value.val = mapping[value.val];
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
let result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? value.val : moduleSettings.generateScopedName(value.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1008
|
+
if (result instanceof Promise) {
|
|
1009
|
+
result = await result;
|
|
1010
|
+
}
|
|
1011
|
+
mapping[value.val] = result;
|
|
1012
|
+
revMapping[result] = value.val;
|
|
1013
|
+
value.val = result;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
node.val[i].val = node.val[i].val.charAt(0) + tokens.reduce((acc, curr) => acc + renderToken(curr), '') + node.val[i].val.charAt(node.val[i].val.length - 1);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
443
1020
|
}
|
|
444
|
-
if (
|
|
445
|
-
|
|
446
|
-
|
|
1021
|
+
else if (node.nam == 'animation' || node.nam == 'animation-name') {
|
|
1022
|
+
for (const { value } of walkValues(node.val, node)) {
|
|
1023
|
+
if (value.typ == EnumToken.IdenTokenType && ![
|
|
1024
|
+
'none', 'infinite', 'normal', 'reverse', 'alternate',
|
|
1025
|
+
'alternate-reverse', 'forwards', 'backwards', 'both',
|
|
1026
|
+
'running', 'paused', 'linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out',
|
|
1027
|
+
'step-start', 'step-end', 'jump-start', 'jump-end',
|
|
1028
|
+
'jump-none', 'jump-both', 'start', 'end',
|
|
1029
|
+
'inherit', 'initial', 'unset'
|
|
1030
|
+
].includes(value.val)) {
|
|
1031
|
+
if (!(value.val in mapping)) {
|
|
1032
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? value.val : moduleSettings.generateScopedName(value.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1033
|
+
mapping[value.val] = result instanceof Promise ? await result : result;
|
|
1034
|
+
revMapping[mapping[value.val]] = value.val;
|
|
1035
|
+
}
|
|
1036
|
+
value.val = mapping[value.val];
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
447
1039
|
}
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
1040
|
+
for (const { value, parent } of walkValues(node.val, node)) {
|
|
1041
|
+
if (value.typ == EnumToken.DashedIdenTokenType) {
|
|
1042
|
+
if (!(value.val in mapping)) {
|
|
1043
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? value.val : moduleSettings.generateScopedName(value.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1044
|
+
let val = result instanceof Promise ? await result : result;
|
|
1045
|
+
mapping[value.val] = '--' + (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(val, moduleSettings.naming) : val);
|
|
1046
|
+
revMapping[mapping[value.val]] = value.val;
|
|
1047
|
+
}
|
|
1048
|
+
value.val = mapping[value.val];
|
|
1049
|
+
}
|
|
1050
|
+
else if ((value.typ == EnumToken.IdenTokenType || isIdentColor(value)) && value.val in importedCssVariables) {
|
|
1051
|
+
replaceToken(parent, value, importedCssVariables[value.val].val);
|
|
1052
|
+
}
|
|
451
1053
|
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
1054
|
+
}
|
|
1055
|
+
else if (node.typ == EnumToken.RuleNodeType) {
|
|
1056
|
+
if (node.tokens == null) {
|
|
1057
|
+
Object.defineProperty(node, 'tokens', {
|
|
1058
|
+
...definedPropertySettings,
|
|
1059
|
+
value: parseSelector(parseString(node.sel, { location: true }))
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
let hasIdOrClass = false;
|
|
1063
|
+
for (const { value } of walkValues(node.tokens, node,
|
|
1064
|
+
// @ts-ignore
|
|
1065
|
+
(value, parent) => {
|
|
1066
|
+
if (value.typ == EnumToken.PseudoClassTokenType) {
|
|
1067
|
+
const val = value.val.toLowerCase();
|
|
1068
|
+
switch (val) {
|
|
1069
|
+
case ':local':
|
|
1070
|
+
case ':global':
|
|
1071
|
+
{
|
|
1072
|
+
let index = parent.tokens.indexOf(value);
|
|
1073
|
+
parent.tokens.splice(index, 1);
|
|
1074
|
+
if (parent.tokens[index]?.typ == EnumToken.WhitespaceTokenType || parent.tokens[index]?.typ == EnumToken.DescendantCombinatorTokenType) {
|
|
1075
|
+
parent.tokens.splice(index, 1);
|
|
1076
|
+
}
|
|
1077
|
+
if (val == ':global') {
|
|
1078
|
+
for (; index < parent.tokens.length; index++) {
|
|
1079
|
+
if (parent.tokens[index].typ == EnumToken.CommaTokenType ||
|
|
1080
|
+
([EnumToken.PseudoClassFuncTokenType, EnumToken.PseudoClassTokenType].includes(parent.tokens[index].typ) &&
|
|
1081
|
+
[':global', ':local'].includes(parent.tokens[index].val.toLowerCase()))) {
|
|
1082
|
+
break;
|
|
1083
|
+
}
|
|
1084
|
+
global.add(parent.tokens[index]);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
458
1090
|
}
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
1091
|
+
else if (value.typ == EnumToken.PseudoClassFuncTokenType) {
|
|
1092
|
+
switch (value.val.toLowerCase()) {
|
|
1093
|
+
case ':global':
|
|
1094
|
+
for (const token of value.chi) {
|
|
1095
|
+
global.add(token);
|
|
1096
|
+
}
|
|
1097
|
+
parent.tokens.splice(parent.tokens.indexOf(value), 1, ...value.chi);
|
|
1098
|
+
break;
|
|
1099
|
+
case ':local':
|
|
1100
|
+
parent.tokens.splice(parent.tokens.indexOf(value), 1, ...value.chi);
|
|
1101
|
+
break;
|
|
1102
|
+
}
|
|
462
1103
|
}
|
|
463
|
-
|
|
464
|
-
|
|
1104
|
+
})) {
|
|
1105
|
+
if (value.typ == EnumToken.HashTokenType || value.typ == EnumToken.ClassSelectorTokenType) {
|
|
1106
|
+
hasIdOrClass = true;
|
|
465
1107
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
//
|
|
469
|
-
if (Array.isArray(node)) {
|
|
470
|
-
break;
|
|
1108
|
+
if (processed.has(value)) {
|
|
1109
|
+
continue;
|
|
471
1110
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
else if (allValuesHandlers.length > 0) {
|
|
480
|
-
let callable;
|
|
481
|
-
let node = null;
|
|
482
|
-
node = result.node;
|
|
483
|
-
for (const valueHandler of allValuesHandlers) {
|
|
484
|
-
if (valueHandler.has(node.typ)) {
|
|
485
|
-
callable = valueHandler.get(node.typ);
|
|
486
|
-
let replacement = callable(node, result.parent);
|
|
487
|
-
if (replacement == null) {
|
|
1111
|
+
processed.add(value);
|
|
1112
|
+
if (value.typ == EnumToken.PseudoClassTokenType) ;
|
|
1113
|
+
else if (value.typ == EnumToken.PseudoClassFuncTokenType) ;
|
|
1114
|
+
else {
|
|
1115
|
+
if (global.has(value)) {
|
|
488
1116
|
continue;
|
|
489
1117
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
1118
|
+
if (value.typ == EnumToken.ClassSelectorTokenType) {
|
|
1119
|
+
const val = value.val.slice(1);
|
|
1120
|
+
if (!(val in mapping)) {
|
|
1121
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? val : moduleSettings.generateScopedName(val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1122
|
+
let value = result instanceof Promise ? await result : result;
|
|
1123
|
+
mapping[val] = (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(value, moduleSettings.naming) : value);
|
|
1124
|
+
revMapping[mapping[val]] = val;
|
|
1125
|
+
}
|
|
1126
|
+
value.val = '.' + mapping[val];
|
|
496
1127
|
}
|
|
497
1128
|
}
|
|
498
1129
|
}
|
|
499
|
-
if (
|
|
500
|
-
|
|
501
|
-
|
|
1130
|
+
if (moduleSettings.scoped & ModuleScopeEnumOptions.Pure) {
|
|
1131
|
+
if (!hasIdOrClass) {
|
|
1132
|
+
throw new Error(`pure module: No id or class found in selector '${node.sel}' at '${node.loc?.src ?? ''}':${node.loc?.sta?.lin ?? ''}:${node.loc?.sta?.col ?? ''}`);
|
|
1133
|
+
}
|
|
502
1134
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
1135
|
+
node.sel = '';
|
|
1136
|
+
for (const token of node.tokens) {
|
|
1137
|
+
node.sel += renderToken(token);
|
|
506
1138
|
}
|
|
507
|
-
|
|
508
|
-
|
|
1139
|
+
}
|
|
1140
|
+
else if (node.typ == EnumToken.AtRuleNodeType || node.typ == EnumToken.KeyframesAtRuleNodeType) {
|
|
1141
|
+
const val = node.nam.toLowerCase();
|
|
1142
|
+
if (node.tokens == null) {
|
|
1143
|
+
Object.defineProperty(node, 'tokens', {
|
|
1144
|
+
...definedPropertySettings,
|
|
1145
|
+
// @ts-ignore
|
|
1146
|
+
value: parseAtRulePrelude(parseString(node.val), node)
|
|
1147
|
+
});
|
|
509
1148
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
for (const
|
|
513
|
-
if (
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
isAsync = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction';
|
|
520
|
-
if (isAsync) {
|
|
521
|
-
result = await result;
|
|
1149
|
+
if (val == 'property' || val == 'keyframes') {
|
|
1150
|
+
const prefix = val == 'property' ? '--' : '';
|
|
1151
|
+
for (const value of node.tokens) {
|
|
1152
|
+
if ((prefix == '--' && value.typ == EnumToken.DashedIdenTokenType) || (prefix == '' && value.typ == EnumToken.IdenTokenType)) {
|
|
1153
|
+
if (!(value.val in mapping)) {
|
|
1154
|
+
const result = (moduleSettings.scoped & ModuleScopeEnumOptions.Global) ? value.val : moduleSettings.generateScopedName(value.val, moduleSettings.filePath, moduleSettings.pattern, moduleSettings.hashLength);
|
|
1155
|
+
let val = result instanceof Promise ? await result : result;
|
|
1156
|
+
mapping[value.val] = prefix + (moduleSettings.naming & ModuleCaseTransformEnum.DashCaseOnly || moduleSettings.naming & ModuleCaseTransformEnum.CamelCaseOnly ? getKeyName(val, moduleSettings.naming) : val);
|
|
1157
|
+
revMapping[mapping[value.val]] = value.val;
|
|
522
1158
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
1159
|
+
value.val = mapping[value.val];
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
node.val = node.tokens.reduce((a, b) => a + renderToken(b), '');
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
let isReplaced = false;
|
|
1166
|
+
for (const { value, parent } of walkValues(node.tokens, node)) {
|
|
1167
|
+
if (EnumToken.MediaQueryConditionTokenType == parent.typ && value != parent.l) {
|
|
1168
|
+
if ((value.typ == EnumToken.IdenTokenType || isIdentColor(value)) && value.val in importedCssVariables) {
|
|
1169
|
+
isReplaced = true;
|
|
1170
|
+
parent.r.splice(parent.r.indexOf(value), 1, ...importedCssVariables[value.val].val);
|
|
529
1171
|
}
|
|
530
1172
|
}
|
|
531
1173
|
}
|
|
532
|
-
if (
|
|
533
|
-
|
|
534
|
-
replaceToken(parent, value, node);
|
|
1174
|
+
if (isReplaced) {
|
|
1175
|
+
node.val = node.tokens.reduce((a, b) => a + renderToken(b), '');
|
|
535
1176
|
}
|
|
536
1177
|
}
|
|
537
1178
|
}
|
|
538
1179
|
}
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
1180
|
+
if (moduleSettings.naming != ModuleCaseTransformEnum.IgnoreCase) {
|
|
1181
|
+
revMapping = {};
|
|
1182
|
+
mapping = Object.entries(mapping).reduce((acc, [key, value]) => {
|
|
1183
|
+
const keyName = getKeyName(key, moduleSettings.naming);
|
|
1184
|
+
acc[keyName] = value;
|
|
1185
|
+
revMapping[value] = keyName;
|
|
1186
|
+
return acc;
|
|
1187
|
+
}, {});
|
|
546
1188
|
}
|
|
1189
|
+
result.mapping = mapping;
|
|
1190
|
+
result.revMapping = revMapping;
|
|
1191
|
+
if ((moduleSettings.scoped & ModuleScopeEnumOptions.ICSS) && Object.keys(importMapping).length > 0) {
|
|
1192
|
+
result.importMapping = importMapping;
|
|
1193
|
+
}
|
|
1194
|
+
endTime = performance.now();
|
|
1195
|
+
result.stats.module = `${(endTime - parseModuleTime).toFixed(2)}ms`;
|
|
1196
|
+
result.stats.total = `${(endTime - startTime).toFixed(2)}ms`;
|
|
547
1197
|
}
|
|
548
|
-
const endTime = performance.now();
|
|
549
1198
|
if (options.signal != null) {
|
|
550
1199
|
options.signal.removeEventListener('abort', reject);
|
|
551
1200
|
}
|
|
552
|
-
|
|
553
|
-
return {
|
|
554
|
-
ast,
|
|
555
|
-
errors,
|
|
556
|
-
stats: {
|
|
557
|
-
...stats,
|
|
558
|
-
parse: `${(endParseTime - startTime).toFixed(2)}ms`,
|
|
559
|
-
minify: `${(endTime - endParseTime).toFixed(2)}ms`,
|
|
560
|
-
total: `${(endTime - startTime).toFixed(2)}ms`
|
|
561
|
-
}
|
|
562
|
-
};
|
|
1201
|
+
return result;
|
|
563
1202
|
}
|
|
564
1203
|
function getLastNode(context) {
|
|
565
1204
|
let i = context.chi.length;
|
|
@@ -571,7 +1210,7 @@ function getLastNode(context) {
|
|
|
571
1210
|
}
|
|
572
1211
|
return null;
|
|
573
1212
|
}
|
|
574
|
-
function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
1213
|
+
function parseNode(results, context, options, errors, src, map, rawTokens, stats) {
|
|
575
1214
|
let tokens = [];
|
|
576
1215
|
for (const t of results) {
|
|
577
1216
|
const node = getTokenType(t.token, t.hint);
|
|
@@ -594,9 +1233,12 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
594
1233
|
}
|
|
595
1234
|
loc = location;
|
|
596
1235
|
context.chi.push(tokens[i]);
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
1236
|
+
stats.nodesCount++;
|
|
1237
|
+
Object.defineProperty(tokens[i], 'loc', {
|
|
1238
|
+
...definedPropertySettings,
|
|
1239
|
+
value: loc,
|
|
1240
|
+
enumerable: options.sourcemap !== false
|
|
1241
|
+
});
|
|
600
1242
|
}
|
|
601
1243
|
else if (tokens[i].typ != EnumToken.WhitespaceTokenType) {
|
|
602
1244
|
break;
|
|
@@ -737,10 +1379,10 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
737
1379
|
}
|
|
738
1380
|
}
|
|
739
1381
|
const t = parseAtRulePrelude(parseTokens(tokens, { minify: options.minify }), atRule);
|
|
740
|
-
const raw =
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
}
|
|
1382
|
+
const raw = [];
|
|
1383
|
+
for (const curr of t) {
|
|
1384
|
+
raw.push(renderToken(curr, { removeComments: true, convertColor: false }));
|
|
1385
|
+
}
|
|
744
1386
|
const nam = renderToken(atRule, { removeComments: true });
|
|
745
1387
|
// @ts-ignore
|
|
746
1388
|
const node = {
|
|
@@ -756,10 +1398,12 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
756
1398
|
node.chi = [];
|
|
757
1399
|
}
|
|
758
1400
|
loc = map.get(atRule);
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
1401
|
+
Object.defineProperty(node, 'loc', {
|
|
1402
|
+
...definedPropertySettings,
|
|
1403
|
+
value: loc,
|
|
1404
|
+
enumerable: options.sourcemap !== false
|
|
1405
|
+
});
|
|
1406
|
+
node.loc.end = { ...map.get(delim).end };
|
|
763
1407
|
let isValid = true;
|
|
764
1408
|
if (node.nam == 'else') {
|
|
765
1409
|
const prev = getLastNode(context);
|
|
@@ -772,21 +1416,173 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
772
1416
|
isValid = false;
|
|
773
1417
|
}
|
|
774
1418
|
}
|
|
1419
|
+
if (node.nam == 'value') {
|
|
1420
|
+
let i = 0;
|
|
1421
|
+
while (i < tokens.length) {
|
|
1422
|
+
if (tokens[i].typ == EnumToken.WhitespaceTokenType || tokens[i].typ == EnumToken.CommentTokenType) {
|
|
1423
|
+
i++;
|
|
1424
|
+
continue;
|
|
1425
|
+
}
|
|
1426
|
+
break;
|
|
1427
|
+
}
|
|
1428
|
+
if (i < tokens.length) {
|
|
1429
|
+
if (tokens[i].typ == EnumToken.IdenTokenType || isIdentColor(tokens[i])) {
|
|
1430
|
+
let k = i + 1;
|
|
1431
|
+
while (k < tokens.length) {
|
|
1432
|
+
if (tokens[k].typ == EnumToken.WhitespaceTokenType || tokens[k].typ == EnumToken.CommentTokenType) {
|
|
1433
|
+
k++;
|
|
1434
|
+
continue;
|
|
1435
|
+
}
|
|
1436
|
+
// var or import
|
|
1437
|
+
if (tokens[k].typ == EnumToken.ColonTokenType) {
|
|
1438
|
+
let j = k;
|
|
1439
|
+
while (++j < tokens.length) {
|
|
1440
|
+
if (tokens[j].typ != EnumToken.WhitespaceTokenType && tokens[j].typ != EnumToken.CommentTokenType) {
|
|
1441
|
+
break;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
let offset = k + 1;
|
|
1445
|
+
while (offset < tokens.length && tokens[offset].typ == EnumToken.WhitespaceTokenType) {
|
|
1446
|
+
offset++;
|
|
1447
|
+
}
|
|
1448
|
+
if (tokens[j].typ == EnumToken.StringTokenType) {
|
|
1449
|
+
Object.assign(node, {
|
|
1450
|
+
typ: EnumToken.CssVariableImportTokenType,
|
|
1451
|
+
nam: tokens[i].val,
|
|
1452
|
+
val: tokens.slice(offset)
|
|
1453
|
+
});
|
|
1454
|
+
delete node.tokens;
|
|
1455
|
+
// @ts-ignore
|
|
1456
|
+
delete node.raw;
|
|
1457
|
+
context.chi.push(node);
|
|
1458
|
+
return null;
|
|
1459
|
+
}
|
|
1460
|
+
Object.assign(node, {
|
|
1461
|
+
typ: EnumToken.CssVariableTokenType,
|
|
1462
|
+
nam: tokens[i].val,
|
|
1463
|
+
val: tokens.slice(offset)
|
|
1464
|
+
});
|
|
1465
|
+
context.chi.push(node);
|
|
1466
|
+
return null;
|
|
1467
|
+
}
|
|
1468
|
+
if (tokens[k].typ == EnumToken.PseudoClassTokenType) {
|
|
1469
|
+
Object.assign(tokens[k], {
|
|
1470
|
+
typ: EnumToken.IdenTokenType,
|
|
1471
|
+
val: tokens[k].val.slice(1)
|
|
1472
|
+
});
|
|
1473
|
+
Object.assign(node, {
|
|
1474
|
+
typ: EnumToken.CssVariableTokenType,
|
|
1475
|
+
nam: tokens[i].val,
|
|
1476
|
+
val: tokens.slice(k)
|
|
1477
|
+
});
|
|
1478
|
+
context.chi.push(node);
|
|
1479
|
+
return null;
|
|
1480
|
+
}
|
|
1481
|
+
if (tokens[k].typ == EnumToken.CommaTokenType) {
|
|
1482
|
+
let j = i;
|
|
1483
|
+
while (++j < tokens.length) {
|
|
1484
|
+
if (tokens[j].typ == EnumToken.IdenTokenType && tokens[j].val.toLowerCase() == 'from') {
|
|
1485
|
+
const vars = tokens.slice(i, j);
|
|
1486
|
+
const from = tokens.slice(j + 1);
|
|
1487
|
+
let l = 0;
|
|
1488
|
+
let expect = EnumToken.IdenTokenType;
|
|
1489
|
+
for (; l < vars.length; l++) {
|
|
1490
|
+
if (vars[l].typ == EnumToken.WhitespaceTokenType || vars[l].typ == EnumToken.CommentTokenType) {
|
|
1491
|
+
continue;
|
|
1492
|
+
}
|
|
1493
|
+
if (expect == vars[l].typ || (expect == EnumToken.IdenTokenType && isIdentColor(vars[l]))) {
|
|
1494
|
+
expect = expect == EnumToken.CommaTokenType ? EnumToken.IdenTokenType : EnumToken.CommaTokenType;
|
|
1495
|
+
continue;
|
|
1496
|
+
}
|
|
1497
|
+
errors.push({
|
|
1498
|
+
action: 'drop',
|
|
1499
|
+
node: node,
|
|
1500
|
+
location: map.get(vars[l]) ?? location,
|
|
1501
|
+
message: `expecting '${EnumToken[expect]}' but found ${renderToken(vars[l])}`
|
|
1502
|
+
});
|
|
1503
|
+
return null;
|
|
1504
|
+
}
|
|
1505
|
+
l = 0;
|
|
1506
|
+
expect = EnumToken.IdenTokenType;
|
|
1507
|
+
for (; l < from.length; l++) {
|
|
1508
|
+
if (from[l].typ == EnumToken.WhitespaceTokenType || from[l].typ == EnumToken.CommentTokenType) {
|
|
1509
|
+
continue;
|
|
1510
|
+
}
|
|
1511
|
+
if (expect == from[l].typ || isIdentColor(from[l])) {
|
|
1512
|
+
while (++l < from.length) {
|
|
1513
|
+
if (from[l].typ == EnumToken.WhitespaceTokenType || from[l].typ == EnumToken.CommentTokenType) {
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1516
|
+
errors.push({
|
|
1517
|
+
action: 'drop',
|
|
1518
|
+
node: node,
|
|
1519
|
+
location: map.get(from[l]) ?? location,
|
|
1520
|
+
message: `unexpected '${renderToken(from[l])}'`
|
|
1521
|
+
});
|
|
1522
|
+
return null;
|
|
1523
|
+
}
|
|
1524
|
+
break;
|
|
1525
|
+
}
|
|
1526
|
+
errors.push({
|
|
1527
|
+
action: 'drop',
|
|
1528
|
+
node: node,
|
|
1529
|
+
location: map.get(from[l]) ?? location,
|
|
1530
|
+
message: `expecting <string> but found ${renderToken(from[l])}`
|
|
1531
|
+
});
|
|
1532
|
+
return null;
|
|
1533
|
+
}
|
|
1534
|
+
// @ts-ignore
|
|
1535
|
+
delete node.nam;
|
|
1536
|
+
// @ts-ignore
|
|
1537
|
+
delete node.val;
|
|
1538
|
+
Object.assign(node, {
|
|
1539
|
+
typ: EnumToken.CssVariableDeclarationMapTokenType,
|
|
1540
|
+
vars,
|
|
1541
|
+
from
|
|
1542
|
+
});
|
|
1543
|
+
context.chi.push(node);
|
|
1544
|
+
return null;
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
k++;
|
|
1549
|
+
}
|
|
1550
|
+
Object.assign(node, {
|
|
1551
|
+
typ: EnumToken.CssVariableTokenType,
|
|
1552
|
+
nam: tokens[i].val,
|
|
1553
|
+
val: tokens.slice(k)
|
|
1554
|
+
});
|
|
1555
|
+
context.chi.push(node);
|
|
1556
|
+
return null;
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
775
1560
|
// @ts-ignore
|
|
776
|
-
const
|
|
1561
|
+
const skipValidate = (options.validation & ValidationLevel.AtRule) == 0;
|
|
1562
|
+
const isAllowed = skipValidate || isNodeAllowedInContext(node, context);
|
|
1563
|
+
// @ts-ignore
|
|
1564
|
+
const valid = skipValidate ? {
|
|
777
1565
|
valid: SyntaxValidationResult.Valid,
|
|
778
1566
|
error: '',
|
|
779
1567
|
node,
|
|
780
1568
|
syntax: '@' + node.nam
|
|
781
|
-
} :
|
|
1569
|
+
} : !isAllowed ? {
|
|
1570
|
+
valid: SyntaxValidationResult.Drop,
|
|
1571
|
+
node,
|
|
1572
|
+
syntax: '@' + node.nam,
|
|
1573
|
+
error: `${EnumToken[context.typ]}: child ${EnumToken[node.typ]} not allowed in context${context.typ == EnumToken.AtRuleNodeType ? ` '@${context.nam}'` : context.typ == EnumToken.StyleSheetNodeType ? ` 'stylesheet'` : ''}`} : isValid ? (node.typ == EnumToken.KeyframesAtRuleNodeType ? validateAtRuleKeyframes(node) : validateAtRule(node, options, context)) : {
|
|
782
1574
|
valid: SyntaxValidationResult.Drop,
|
|
783
1575
|
node,
|
|
784
1576
|
syntax: '@' + node.nam,
|
|
785
1577
|
error: '@' + node.nam + ' not allowed here'};
|
|
786
1578
|
if (valid.valid == SyntaxValidationResult.Drop) {
|
|
1579
|
+
let message = '';
|
|
1580
|
+
for (const token of tokens) {
|
|
1581
|
+
message += renderToken(token, { minify: false });
|
|
1582
|
+
}
|
|
787
1583
|
errors.push({
|
|
788
1584
|
action: 'drop',
|
|
789
|
-
message: valid.error + ' - "' +
|
|
1585
|
+
message: valid.error + ' - "' + message + '"',
|
|
790
1586
|
node,
|
|
791
1587
|
// @ts-ignore
|
|
792
1588
|
location: { src, ...(map.get(valid.node) ?? location) }
|
|
@@ -795,13 +1591,17 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
795
1591
|
node.typ = EnumToken.InvalidAtRuleTokenType;
|
|
796
1592
|
}
|
|
797
1593
|
else {
|
|
798
|
-
node.val =
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
1594
|
+
node.val = '';
|
|
1595
|
+
for (const token of node.tokens) {
|
|
1596
|
+
node.val += renderToken(token, {
|
|
1597
|
+
minify: false,
|
|
1598
|
+
convertColor: false,
|
|
1599
|
+
removeComments: true
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
803
1602
|
}
|
|
804
1603
|
context.chi.push(node);
|
|
1604
|
+
stats.nodesCount++;
|
|
805
1605
|
Object.defineProperties(node, {
|
|
806
1606
|
parent: { ...definedPropertySettings, value: context },
|
|
807
1607
|
validSyntax: { ...definedPropertySettings, value: valid.valid == SyntaxValidationResult.Valid }
|
|
@@ -899,16 +1699,23 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
899
1699
|
value: tokens.slice()
|
|
900
1700
|
});
|
|
901
1701
|
loc = location;
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
1702
|
+
Object.defineProperty(node, 'loc', {
|
|
1703
|
+
...definedPropertySettings,
|
|
1704
|
+
value: loc,
|
|
1705
|
+
enumerable: options.sourcemap !== false
|
|
1706
|
+
});
|
|
906
1707
|
context.chi.push(node);
|
|
907
1708
|
Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
|
|
908
1709
|
// @ts-ignore
|
|
909
|
-
const
|
|
1710
|
+
const skipValidate = (options.validation & ValidationLevel.Selector) == 0;
|
|
1711
|
+
const isAllowed = skipValidate || isNodeAllowedInContext(node, context);
|
|
1712
|
+
// @ts-ignore
|
|
1713
|
+
const valid = skipValidate ? {
|
|
910
1714
|
valid: SyntaxValidationResult.Valid,
|
|
911
1715
|
error: null
|
|
1716
|
+
} : !isAllowed ? {
|
|
1717
|
+
valid: SyntaxValidationResult.Drop,
|
|
1718
|
+
error: `${EnumToken[context.typ]}: child ${EnumToken[node.typ]} not allowed in context${context.typ == EnumToken.AtRuleNodeType ? ` '@${context.nam}'` : context.typ == EnumToken.StyleSheetNodeType ? ` 'stylesheet'` : ''}`
|
|
912
1719
|
} : ruleType == EnumToken.KeyFramesRuleNodeType ? validateKeyframeSelector(tokens) : validateSelector(tokens, options, context);
|
|
913
1720
|
if (valid.valid != SyntaxValidationResult.Valid) {
|
|
914
1721
|
// @ts-ignore
|
|
@@ -1018,11 +1825,13 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
1018
1825
|
nam,
|
|
1019
1826
|
val: []
|
|
1020
1827
|
};
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1828
|
+
Object.defineProperty(node, 'loc', {
|
|
1829
|
+
...definedPropertySettings,
|
|
1830
|
+
value: location,
|
|
1831
|
+
enumerable: options.sourcemap !== false
|
|
1832
|
+
});
|
|
1025
1833
|
context.chi.push(node);
|
|
1834
|
+
stats.nodesCount++;
|
|
1026
1835
|
}
|
|
1027
1836
|
return null;
|
|
1028
1837
|
}
|
|
@@ -1046,22 +1855,31 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
1046
1855
|
nam,
|
|
1047
1856
|
val: value
|
|
1048
1857
|
};
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1858
|
+
Object.defineProperty(node, 'loc', {
|
|
1859
|
+
...definedPropertySettings,
|
|
1860
|
+
value: location,
|
|
1861
|
+
enumerable: options.sourcemap !== false
|
|
1862
|
+
});
|
|
1863
|
+
node.loc.end = { ...map.get(delim).end };
|
|
1053
1864
|
// do not allow declarations in style sheets
|
|
1054
1865
|
if (context.typ == EnumToken.StyleSheetNodeType && options.lenient) {
|
|
1055
|
-
|
|
1056
|
-
node.typ = EnumToken.InvalidDeclarationNodeType;
|
|
1866
|
+
Object.assign(node, { typ: EnumToken.InvalidDeclarationNodeType });
|
|
1057
1867
|
context.chi.push(node);
|
|
1868
|
+
stats.nodesCount++;
|
|
1058
1869
|
return null;
|
|
1059
1870
|
}
|
|
1060
1871
|
const result = parseDeclarationNode(node, errors, location);
|
|
1061
1872
|
Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context });
|
|
1062
1873
|
if (result != null) {
|
|
1063
|
-
if (options.validation
|
|
1064
|
-
const
|
|
1874
|
+
if (options.validation & ValidationLevel.Declaration) {
|
|
1875
|
+
const isAllowed = isNodeAllowedInContext(node, context);
|
|
1876
|
+
// @ts-ignore
|
|
1877
|
+
const valid = !isAllowed ? {
|
|
1878
|
+
valid: SyntaxValidationResult.Drop,
|
|
1879
|
+
error: `${EnumToken[node.typ]} not allowed in context${context.typ == EnumToken.AtRuleNodeType ? ` '@${context.nam}'` : context.typ == EnumToken.StyleSheetNodeType ? ` 'stylesheet'` : ''}`,
|
|
1880
|
+
node,
|
|
1881
|
+
syntax: null
|
|
1882
|
+
} : evaluateSyntax(result, context, options);
|
|
1065
1883
|
Object.defineProperty(result, 'validSyntax', {
|
|
1066
1884
|
...definedPropertySettings,
|
|
1067
1885
|
value: valid.valid == SyntaxValidationResult.Valid
|
|
@@ -1077,11 +1895,11 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
1077
1895
|
if (!options.lenient) {
|
|
1078
1896
|
return null;
|
|
1079
1897
|
}
|
|
1080
|
-
|
|
1081
|
-
node.typ = EnumToken.InvalidDeclarationNodeType;
|
|
1898
|
+
Object.assign(node, { typ: EnumToken.InvalidDeclarationNodeType });
|
|
1082
1899
|
}
|
|
1083
1900
|
}
|
|
1084
1901
|
context.chi.push(result);
|
|
1902
|
+
stats.nodesCount++;
|
|
1085
1903
|
}
|
|
1086
1904
|
return null;
|
|
1087
1905
|
}
|
|
@@ -1093,7 +1911,6 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
1093
1911
|
* @param atRule
|
|
1094
1912
|
*/
|
|
1095
1913
|
function parseAtRulePrelude(tokens, atRule) {
|
|
1096
|
-
// @ts-ignore
|
|
1097
1914
|
for (const { value, parent } of walkValues(tokens, null, null, true)) {
|
|
1098
1915
|
if (value.typ == EnumToken.CommentTokenType ||
|
|
1099
1916
|
value.typ == EnumToken.WhitespaceTokenType ||
|
|
@@ -1129,16 +1946,14 @@ function parseAtRulePrelude(tokens, atRule) {
|
|
|
1129
1946
|
}
|
|
1130
1947
|
if (atRule.val == 'page' && value.typ == EnumToken.PseudoClassTokenType) {
|
|
1131
1948
|
if ([':left', ':right', ':first', ':blank'].includes(value.val)) {
|
|
1132
|
-
|
|
1133
|
-
value.typ = EnumToken.PseudoPageTokenType;
|
|
1949
|
+
Object.assign(value, { typ: EnumToken.PseudoPageTokenType });
|
|
1134
1950
|
}
|
|
1135
1951
|
}
|
|
1136
1952
|
if (atRule.val == 'layer') {
|
|
1137
1953
|
if (parent == null && value.typ == EnumToken.LiteralTokenType) {
|
|
1138
1954
|
if (value.val.charAt(0) == '.') {
|
|
1139
1955
|
if (isIdent(value.val.slice(1))) {
|
|
1140
|
-
|
|
1141
|
-
value.typ = EnumToken.ClassSelectorTokenType;
|
|
1956
|
+
Object.assign(value, { typ: EnumToken.ClassSelectorTokenType });
|
|
1142
1957
|
}
|
|
1143
1958
|
}
|
|
1144
1959
|
}
|
|
@@ -1147,8 +1962,7 @@ function parseAtRulePrelude(tokens, atRule) {
|
|
|
1147
1962
|
if (value.typ == EnumToken.IdenTokenType) {
|
|
1148
1963
|
if (parent == null && mediaTypes.some((t) => {
|
|
1149
1964
|
if (val === t) {
|
|
1150
|
-
|
|
1151
|
-
value.typ = EnumToken.MediaFeatureTokenType;
|
|
1965
|
+
Object.assign(value, { typ: EnumToken.MediaFeatureTokenType });
|
|
1152
1966
|
return true;
|
|
1153
1967
|
}
|
|
1154
1968
|
return false;
|
|
@@ -1156,18 +1970,15 @@ function parseAtRulePrelude(tokens, atRule) {
|
|
|
1156
1970
|
continue;
|
|
1157
1971
|
}
|
|
1158
1972
|
if (value.typ == EnumToken.IdenTokenType && 'and' === val) {
|
|
1159
|
-
|
|
1160
|
-
value.typ = EnumToken.MediaFeatureAndTokenType;
|
|
1973
|
+
Object.assign(value, { typ: EnumToken.MediaFeatureAndTokenType });
|
|
1161
1974
|
continue;
|
|
1162
1975
|
}
|
|
1163
1976
|
if (value.typ == EnumToken.IdenTokenType && 'or' === val) {
|
|
1164
|
-
|
|
1165
|
-
value.typ = EnumToken.MediaFeatureOrTokenType;
|
|
1977
|
+
Object.assign(value, { typ: EnumToken.MediaFeatureOrTokenType });
|
|
1166
1978
|
continue;
|
|
1167
1979
|
}
|
|
1168
1980
|
if (value.typ == EnumToken.IdenTokenType &&
|
|
1169
1981
|
['not', 'only'].some((t) => val === t)) {
|
|
1170
|
-
// @ts-ignore
|
|
1171
1982
|
const array = parent?.chi ?? tokens;
|
|
1172
1983
|
const startIndex = array.indexOf(value);
|
|
1173
1984
|
let index = startIndex + 1;
|
|
@@ -1212,12 +2023,15 @@ function parseAtRulePrelude(tokens, atRule) {
|
|
|
1212
2023
|
if (value.chi[i].typ == EnumToken.CommentTokenType || value.chi[i].typ == EnumToken.WhitespaceTokenType) {
|
|
1213
2024
|
continue;
|
|
1214
2025
|
}
|
|
1215
|
-
if (value.chi[i].typ == EnumToken.LiteralTokenType && value.chi[i].val.startsWith(':')
|
|
1216
|
-
value.chi.
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
2026
|
+
if (value.chi[i].typ == EnumToken.LiteralTokenType && value.chi[i].val.startsWith(':')) {
|
|
2027
|
+
const dimension = parseDimension(value.chi[i].val.slice(1));
|
|
2028
|
+
if (dimension != null) {
|
|
2029
|
+
value.chi.splice(i, 1, {
|
|
2030
|
+
typ: EnumToken.ColonTokenType,
|
|
2031
|
+
}, Object.assign(value.chi[i], dimension));
|
|
2032
|
+
i--;
|
|
2033
|
+
continue;
|
|
2034
|
+
}
|
|
1221
2035
|
}
|
|
1222
2036
|
if (nameIndex != -1 && value.chi[i].typ == EnumToken.PseudoClassTokenType) {
|
|
1223
2037
|
value.chi.splice(i, 1, {
|
|
@@ -1244,11 +2058,10 @@ function parseAtRulePrelude(tokens, atRule) {
|
|
|
1244
2058
|
const val = value.chi.splice(valueIndex, 1)[0];
|
|
1245
2059
|
const node = value.chi.splice(nameIndex, 1)[0];
|
|
1246
2060
|
// 'background'
|
|
1247
|
-
// @ts-ignore
|
|
1248
2061
|
if (node.typ == EnumToken.ColorTokenType && node.kin == ColorType.DPSYS) {
|
|
2062
|
+
Object.assign(node, { typ: EnumToken.IdenTokenType });
|
|
1249
2063
|
// @ts-ignore
|
|
1250
2064
|
delete node.kin;
|
|
1251
|
-
node.typ = EnumToken.IdenTokenType;
|
|
1252
2065
|
}
|
|
1253
2066
|
while (value.chi[0]?.typ == EnumToken.WhitespaceTokenType) {
|
|
1254
2067
|
value.chi.shift();
|
|
@@ -1282,6 +2095,7 @@ async function parseDeclarations(declaration) {
|
|
|
1282
2095
|
return doParse(tokenize({
|
|
1283
2096
|
stream: `.x{${declaration}}`,
|
|
1284
2097
|
buffer: '',
|
|
2098
|
+
offset: 0,
|
|
1285
2099
|
position: { ind: 0, lin: 1, col: 1 },
|
|
1286
2100
|
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
1287
2101
|
}), { setParent: false, minify: false, validation: false }).then(result => {
|
|
@@ -1303,43 +2117,35 @@ function parseSelector(tokens) {
|
|
|
1303
2117
|
}
|
|
1304
2118
|
if (parent == null) {
|
|
1305
2119
|
if (value.typ == EnumToken.GtTokenType) {
|
|
1306
|
-
|
|
1307
|
-
value.typ = EnumToken.ChildCombinatorTokenType;
|
|
2120
|
+
Object.assign(value, { typ: EnumToken.ChildCombinatorTokenType });
|
|
1308
2121
|
}
|
|
1309
2122
|
else if (value.typ == EnumToken.LiteralTokenType) {
|
|
1310
2123
|
if (value.val.charAt(0) == '&') {
|
|
1311
|
-
|
|
1312
|
-
value.typ = EnumToken.NestingSelectorTokenType;
|
|
2124
|
+
Object.assign(value, { typ: EnumToken.NestingSelectorTokenType });
|
|
1313
2125
|
// @ts-ignore
|
|
1314
2126
|
delete value.val;
|
|
1315
2127
|
}
|
|
1316
2128
|
else if (value.val.charAt(0) == '.') {
|
|
1317
2129
|
if (!isIdent(value.val.slice(1))) {
|
|
1318
|
-
|
|
1319
|
-
value.typ = EnumToken.InvalidClassSelectorTokenType;
|
|
2130
|
+
Object.assign(value, { typ: EnumToken.InvalidClassSelectorTokenType });
|
|
1320
2131
|
}
|
|
1321
2132
|
else {
|
|
1322
|
-
|
|
1323
|
-
value.typ = EnumToken.ClassSelectorTokenType;
|
|
2133
|
+
Object.assign(value, { typ: EnumToken.ClassSelectorTokenType });
|
|
1324
2134
|
}
|
|
1325
2135
|
}
|
|
1326
2136
|
if (['*', '>', '+', '~'].includes(value.val)) {
|
|
1327
2137
|
switch (value.val) {
|
|
1328
2138
|
case '*':
|
|
1329
|
-
|
|
1330
|
-
value.typ = EnumToken.UniversalSelectorTokenType;
|
|
2139
|
+
Object.assign(value, { typ: EnumToken.UniversalSelectorTokenType });
|
|
1331
2140
|
break;
|
|
1332
2141
|
case '>':
|
|
1333
|
-
|
|
1334
|
-
value.typ = EnumToken.ChildCombinatorTokenType;
|
|
2142
|
+
Object.assign(value, { typ: EnumToken.ChildCombinatorTokenType });
|
|
1335
2143
|
break;
|
|
1336
2144
|
case '+':
|
|
1337
|
-
|
|
1338
|
-
value.typ = EnumToken.NextSiblingCombinatorTokenType;
|
|
2145
|
+
Object.assign(value, { typ: EnumToken.NextSiblingCombinatorTokenType });
|
|
1339
2146
|
break;
|
|
1340
2147
|
case '~':
|
|
1341
|
-
|
|
1342
|
-
value.typ = EnumToken.SubsequentSiblingCombinatorTokenType;
|
|
2148
|
+
Object.assign(value, { typ: EnumToken.SubsequentSiblingCombinatorTokenType });
|
|
1343
2149
|
break;
|
|
1344
2150
|
}
|
|
1345
2151
|
// @ts-ignore
|
|
@@ -1352,12 +2158,10 @@ function parseSelector(tokens) {
|
|
|
1352
2158
|
if (!isIdent(value.val.slice(1))) {
|
|
1353
2159
|
continue;
|
|
1354
2160
|
}
|
|
1355
|
-
|
|
1356
|
-
value.typ = EnumToken.HashTokenType;
|
|
2161
|
+
Object.assign(value, { typ: EnumToken.HashTokenType });
|
|
1357
2162
|
}
|
|
1358
2163
|
else {
|
|
1359
|
-
|
|
1360
|
-
value.typ = EnumToken.IdenTokenType;
|
|
2164
|
+
Object.assign(value, { typ: EnumToken.IdenTokenType });
|
|
1361
2165
|
}
|
|
1362
2166
|
// @ts-ignore
|
|
1363
2167
|
delete value.kin;
|
|
@@ -1412,6 +2216,7 @@ function parseString(src, options = { location: false }) {
|
|
|
1412
2216
|
const parseInfo = {
|
|
1413
2217
|
stream: src,
|
|
1414
2218
|
buffer: '',
|
|
2219
|
+
offset: 0,
|
|
1415
2220
|
position: { ind: 0, lin: 1, col: 1 },
|
|
1416
2221
|
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
1417
2222
|
};
|
|
@@ -1420,15 +2225,17 @@ function parseString(src, options = { location: false }) {
|
|
|
1420
2225
|
return acc;
|
|
1421
2226
|
}
|
|
1422
2227
|
const token = getTokenType(t.token, t.hint);
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
2228
|
+
Object.defineProperty(token, 'loc', {
|
|
2229
|
+
...definedPropertySettings,
|
|
2230
|
+
value: { sta: t.sta },
|
|
2231
|
+
enumerable: options.location !== false
|
|
2232
|
+
});
|
|
1426
2233
|
acc.push(token);
|
|
1427
2234
|
return acc;
|
|
1428
2235
|
}, []));
|
|
1429
2236
|
}
|
|
1430
2237
|
/**
|
|
1431
|
-
* get token type from a string
|
|
2238
|
+
* get the token type from a string
|
|
1432
2239
|
* @param val
|
|
1433
2240
|
* @param hint
|
|
1434
2241
|
*/
|
|
@@ -1464,7 +2271,7 @@ function getTokenType(val, hint) {
|
|
|
1464
2271
|
case '>':
|
|
1465
2272
|
return { typ: EnumToken.GtTokenType };
|
|
1466
2273
|
}
|
|
1467
|
-
if (isPseudo(val)) {
|
|
2274
|
+
if (val.charAt(0) == ':' && isPseudo(val)) {
|
|
1468
2275
|
return val.endsWith('(') ? {
|
|
1469
2276
|
typ: EnumToken.PseudoClassFuncTokenType,
|
|
1470
2277
|
val: val.slice(0, -1),
|
|
@@ -1481,13 +2288,13 @@ function getTokenType(val, hint) {
|
|
|
1481
2288
|
val
|
|
1482
2289
|
});
|
|
1483
2290
|
}
|
|
1484
|
-
if (isAtKeyword(val)) {
|
|
2291
|
+
if (val.charAt(0) == '@' && isAtKeyword(val)) {
|
|
1485
2292
|
return {
|
|
1486
2293
|
typ: EnumToken.AtRuleTokenType,
|
|
1487
2294
|
val: val.slice(1)
|
|
1488
2295
|
};
|
|
1489
2296
|
}
|
|
1490
|
-
if (isFunction(val)) {
|
|
2297
|
+
if (val.endsWith('(') && isFunction(val)) {
|
|
1491
2298
|
val = val.slice(0, -1);
|
|
1492
2299
|
if (val == 'url') {
|
|
1493
2300
|
return {
|
|
@@ -1535,14 +2342,9 @@ function getTokenType(val, hint) {
|
|
|
1535
2342
|
val: +val.slice(0, -1)
|
|
1536
2343
|
};
|
|
1537
2344
|
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
val: +val.slice(0, -2)
|
|
1542
|
-
};
|
|
1543
|
-
}
|
|
1544
|
-
if (isDimension(val)) {
|
|
1545
|
-
return parseDimension(val);
|
|
2345
|
+
const dimension = parseDimension(val);
|
|
2346
|
+
if (dimension != null) {
|
|
2347
|
+
return dimension;
|
|
1546
2348
|
}
|
|
1547
2349
|
const v = val.toLowerCase();
|
|
1548
2350
|
if (v == 'currentcolor' || v == 'transparent' || v in COLORS_NAMES) {
|
|
@@ -1572,6 +2374,12 @@ function getTokenType(val, hint) {
|
|
|
1572
2374
|
val
|
|
1573
2375
|
};
|
|
1574
2376
|
}
|
|
2377
|
+
if (val.charAt(0) == '.' && isIdent(val.slice(1))) {
|
|
2378
|
+
return {
|
|
2379
|
+
typ: EnumToken.ClassSelectorTokenType,
|
|
2380
|
+
val
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
1575
2383
|
if (val.charAt(0) == '#' && isHexColor(val)) {
|
|
1576
2384
|
return {
|
|
1577
2385
|
typ: EnumToken.ColorTokenType,
|
|
@@ -1619,6 +2427,55 @@ function getTokenType(val, hint) {
|
|
|
1619
2427
|
function parseTokens(tokens, options = {}) {
|
|
1620
2428
|
for (let i = 0; i < tokens.length; i++) {
|
|
1621
2429
|
const t = tokens[i];
|
|
2430
|
+
if (t.typ == EnumToken.IdenTokenType && t.val == 'from' && i > 0) {
|
|
2431
|
+
const left = [];
|
|
2432
|
+
const right = [];
|
|
2433
|
+
let foundLeft = 0;
|
|
2434
|
+
let foundRight = 0;
|
|
2435
|
+
let k = i;
|
|
2436
|
+
let l = i;
|
|
2437
|
+
while (k > 0) {
|
|
2438
|
+
if (tokens[k - 1].typ == EnumToken.CommentTokenType || tokens[k - 1].typ == EnumToken.WhitespaceTokenType) {
|
|
2439
|
+
left.push(tokens[--k]);
|
|
2440
|
+
continue;
|
|
2441
|
+
}
|
|
2442
|
+
if (tokens[k - 1].typ == EnumToken.IdenTokenType || tokens[k - 1].typ == EnumToken.DashedIdenTokenType) {
|
|
2443
|
+
foundLeft++;
|
|
2444
|
+
left.push(tokens[--k]);
|
|
2445
|
+
continue;
|
|
2446
|
+
}
|
|
2447
|
+
break;
|
|
2448
|
+
}
|
|
2449
|
+
while (++l < tokens.length) {
|
|
2450
|
+
if (tokens[l].typ == EnumToken.CommentTokenType || tokens[l].typ == EnumToken.WhitespaceTokenType) {
|
|
2451
|
+
right.push(tokens[l]);
|
|
2452
|
+
continue;
|
|
2453
|
+
}
|
|
2454
|
+
if (tokens[l].typ == EnumToken.IdenTokenType || tokens[l].typ == EnumToken.StringTokenType) {
|
|
2455
|
+
foundRight++;
|
|
2456
|
+
right.push(tokens[l]);
|
|
2457
|
+
continue;
|
|
2458
|
+
}
|
|
2459
|
+
break;
|
|
2460
|
+
}
|
|
2461
|
+
if (foundLeft > 0 && foundRight == 1) {
|
|
2462
|
+
while (left?.[0].typ == EnumToken.WhitespaceTokenType) {
|
|
2463
|
+
left.shift();
|
|
2464
|
+
}
|
|
2465
|
+
while (left.at(-1)?.typ == EnumToken.WhitespaceTokenType) {
|
|
2466
|
+
left.pop();
|
|
2467
|
+
}
|
|
2468
|
+
tokens.splice(k, l - k + 1, {
|
|
2469
|
+
typ: EnumToken.ComposesSelectorNodeType,
|
|
2470
|
+
l: left,
|
|
2471
|
+
r: right.reduce((a, b) => {
|
|
2472
|
+
return a == null ? b : b.typ == EnumToken.IdenTokenType || b.typ == EnumToken.StringTokenType ? b : a;
|
|
2473
|
+
}, null)
|
|
2474
|
+
});
|
|
2475
|
+
i = k;
|
|
2476
|
+
continue;
|
|
2477
|
+
}
|
|
2478
|
+
}
|
|
1622
2479
|
if (t.typ == EnumToken.WhitespaceTokenType && ((i == 0 ||
|
|
1623
2480
|
i + 1 == tokens.length ||
|
|
1624
2481
|
[EnumToken.CommaTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType, EnumToken.ColumnCombinatorTokenType].includes(tokens[i + 1].typ)) ||
|
|
@@ -1902,4 +2759,4 @@ function parseTokens(tokens, options = {}) {
|
|
|
1902
2759
|
return tokens;
|
|
1903
2760
|
}
|
|
1904
2761
|
|
|
1905
|
-
export { doParse, getTokenType, parseAtRulePrelude, parseDeclarations, parseSelector, parseString, parseTokens, replaceToken, urlTokenMatcher };
|
|
2762
|
+
export { doParse, generateScopedName, getKeyName, getTokenType, parseAtRulePrelude, parseDeclarations, parseSelector, parseString, parseTokens, replaceToken, urlTokenMatcher };
|