@tbela99/css-parser 1.3.1 → 1.3.3
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 +9 -0
- package/README.md +41 -5
- package/dist/index-umd-web.js +1272 -961
- package/dist/index.cjs +1194 -920
- package/dist/index.d.ts +921 -264
- package/dist/lib/ast/features/calc.js +5 -6
- package/dist/lib/ast/features/inlinecssvariables.js +5 -6
- package/dist/lib/ast/features/prefix.js +4 -14
- package/dist/lib/ast/features/shorthand.js +4 -6
- package/dist/lib/ast/features/transform.js +5 -6
- package/dist/lib/ast/features/type.js +4 -2
- package/dist/lib/ast/minify.js +55 -114
- package/dist/lib/ast/types.js +2 -2
- package/dist/lib/ast/walk.js +149 -59
- package/dist/lib/fs/resolve.js +6 -4
- package/dist/lib/parser/declaration/list.js +1 -1
- package/dist/lib/parser/parse.js +297 -57
- package/dist/lib/parser/tokenize.js +1 -1
- package/dist/lib/renderer/render.js +5 -5
- package/dist/lib/syntax/color/cmyk.js +6 -3
- package/dist/lib/syntax/color/color-mix.js +2 -3
- package/dist/lib/syntax/color/color.js +28 -6
- package/dist/lib/syntax/color/hex.js +3 -0
- package/dist/lib/syntax/color/hsl.js +18 -7
- package/dist/lib/syntax/color/hwb.js +3 -3
- package/dist/lib/syntax/color/lab.js +4 -4
- package/dist/lib/syntax/color/lch.js +7 -4
- package/dist/lib/syntax/color/oklab.js +4 -4
- package/dist/lib/syntax/color/oklch.js +18 -6
- package/dist/lib/syntax/color/relativecolor.js +9 -56
- package/dist/lib/syntax/color/srgb.js +1 -1
- package/dist/lib/validation/config.json.js +4 -12
- package/dist/node.js +53 -31
- package/dist/web.js +76 -17
- package/package.json +2 -3
package/dist/lib/parser/parse.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isIdentStart, isIdent, isIdentColor, mathFuncs, isColor, parseColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isHexColor, isHash, mediaTypes } from '../syntax/syntax.js';
|
|
2
2
|
import { EnumToken, ColorType, ValidationLevel, SyntaxValidationResult } from '../ast/types.js';
|
|
3
3
|
import { minify, definedPropertySettings, combinators } from '../ast/minify.js';
|
|
4
|
-
import { walkValues, walk, WalkerOptionEnum } from '../ast/walk.js';
|
|
4
|
+
import { walkValues, WalkerValueEvent, 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';
|
|
@@ -39,6 +39,37 @@ const enumTokenHints = new Set([
|
|
|
39
39
|
function reject(reason) {
|
|
40
40
|
throw new Error(reason ?? 'Parsing aborted');
|
|
41
41
|
}
|
|
42
|
+
function normalizeVisitorKeyName(keyName) {
|
|
43
|
+
return keyName.replace(/-([a-z])/g, (all, one) => one.toUpperCase());
|
|
44
|
+
}
|
|
45
|
+
function replaceToken(parent, value, replacement) {
|
|
46
|
+
// @ts-ignore
|
|
47
|
+
if ('parent' in value && value.parent != replacement.parent) {
|
|
48
|
+
Object.defineProperty(replacement, 'parent', {
|
|
49
|
+
...definedPropertySettings,
|
|
50
|
+
value: value.parent
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (parent.typ == EnumToken.BinaryExpressionTokenType) {
|
|
54
|
+
if (parent.l == value) {
|
|
55
|
+
parent.l = replacement;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
parent.r = replacement;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
const target = 'val' in parent && Array.isArray(parent.val) ? parent.val : parent.chi;
|
|
64
|
+
// @ts-ignore
|
|
65
|
+
const index = target.indexOf(value);
|
|
66
|
+
if (index == -1) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
target.splice(index, 1, ...(Array.isArray(replacement) ? replacement : [replacement]));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
42
73
|
/**
|
|
43
74
|
* parse css string
|
|
44
75
|
* @param iter
|
|
@@ -121,7 +152,7 @@ async function doParse(iter, options = {}) {
|
|
|
121
152
|
const rawTokens = [];
|
|
122
153
|
const imports = [];
|
|
123
154
|
// @ts-ignore ignore error
|
|
124
|
-
|
|
155
|
+
let isAsync = typeof iter[Symbol.asyncIterator] === 'function';
|
|
125
156
|
while (item = isAsync ? (await iter.next()).value : iter.next().value) {
|
|
126
157
|
stats.bytesIn = item.bytesIn;
|
|
127
158
|
rawTokens.push(item);
|
|
@@ -240,21 +271,18 @@ async function doParse(iter, options = {}) {
|
|
|
240
271
|
const token = node.tokens[0];
|
|
241
272
|
const url = token.typ == EnumToken.StringTokenType ? token.val.slice(1, -1) : token.val;
|
|
242
273
|
try {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
// src: options.resolve!(url, options.src as string).absolute
|
|
256
|
-
// }))
|
|
257
|
-
// });
|
|
274
|
+
const result = options.load(url, options.src);
|
|
275
|
+
const stream = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction' ? await result : result;
|
|
276
|
+
const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream) : tokenize({
|
|
277
|
+
stream,
|
|
278
|
+
buffer: '',
|
|
279
|
+
position: { ind: 0, lin: 1, col: 1 },
|
|
280
|
+
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
281
|
+
}), Object.assign({}, options, {
|
|
282
|
+
minify: false,
|
|
283
|
+
setParent: false,
|
|
284
|
+
src: options.resolve(url, options.src).absolute
|
|
285
|
+
}));
|
|
258
286
|
stats.importedBytesIn += root.stats.bytesIn;
|
|
259
287
|
stats.imports.push(root.stats);
|
|
260
288
|
node.parent.chi.splice(node.parent.chi.indexOf(node), 1, ...root.ast.chi);
|
|
@@ -282,39 +310,230 @@ async function doParse(iter, options = {}) {
|
|
|
282
310
|
if (options.expandNestingRules) {
|
|
283
311
|
ast = expand(ast);
|
|
284
312
|
}
|
|
313
|
+
const valuesHandlers = new Map;
|
|
314
|
+
const preValuesHandlers = new Map;
|
|
315
|
+
const postValuesHandlers = new Map;
|
|
316
|
+
const preVisitorsHandlersMap = new Map;
|
|
317
|
+
const visitorsHandlersMap = new Map;
|
|
318
|
+
const postVisitorsHandlersMap = new Map;
|
|
319
|
+
const allValuesHandlers = [];
|
|
285
320
|
if (options.visitor != null) {
|
|
286
|
-
for (const
|
|
287
|
-
if (
|
|
288
|
-
(typeof
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
321
|
+
for (const [key, value] of Object.entries(options.visitor)) {
|
|
322
|
+
if (key in EnumToken) {
|
|
323
|
+
if (typeof value == 'function') {
|
|
324
|
+
valuesHandlers.set(EnumToken[key], value);
|
|
325
|
+
}
|
|
326
|
+
else if (typeof value == 'object' && 'type' in value && 'handler' in value && value.type in WalkerValueEvent) {
|
|
327
|
+
if (WalkerValueEvent[value.type] == WalkerValueEvent.Enter) {
|
|
328
|
+
preValuesHandlers.set(EnumToken[key], value.handler);
|
|
329
|
+
}
|
|
330
|
+
else if (WalkerValueEvent[value.type] == WalkerValueEvent.Leave) {
|
|
331
|
+
postValuesHandlers.set(EnumToken[key], value.handler);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
console.warn(`doParse: visitor.${key} is not a valid key name`);
|
|
294
336
|
}
|
|
295
|
-
// @ts-ignore
|
|
296
|
-
result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
|
|
297
337
|
}
|
|
298
|
-
else if (
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
338
|
+
else if (['Declaration', 'Rule', 'AtRule', 'KeyframesRule', 'KeyframesAtRule'].includes(key)) {
|
|
339
|
+
if (typeof value == 'function') {
|
|
340
|
+
visitorsHandlersMap.set(key, value);
|
|
341
|
+
}
|
|
342
|
+
else if (typeof value == 'object') {
|
|
343
|
+
if ('type' in value && 'handler' in value && value.type in WalkerValueEvent) {
|
|
344
|
+
if (WalkerValueEvent[value.type] == WalkerValueEvent.Enter) {
|
|
345
|
+
preVisitorsHandlersMap.set(key, value.handler);
|
|
346
|
+
}
|
|
347
|
+
else if (WalkerValueEvent[value.type] == WalkerValueEvent.Leave) {
|
|
348
|
+
postVisitorsHandlersMap.set(key, value.handler);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
visitorsHandlersMap.set(key, value);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
console.warn(`doParse: visitor.${key} is not a valid key name`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
console.warn(`doParse: visitor.${key} is not a valid key name`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (preValuesHandlers.size > 0) {
|
|
364
|
+
allValuesHandlers.push(preValuesHandlers);
|
|
365
|
+
}
|
|
366
|
+
if (valuesHandlers.size > 0) {
|
|
367
|
+
allValuesHandlers.push(valuesHandlers);
|
|
368
|
+
}
|
|
369
|
+
if (postValuesHandlers.size > 0) {
|
|
370
|
+
allValuesHandlers.push(postValuesHandlers);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
for (const result of walk(ast)) {
|
|
374
|
+
// if (result.parent != null && !isNodeAllowedInContext(result.node, result.parent as AstNode)) {
|
|
375
|
+
//
|
|
376
|
+
// errors.push({
|
|
377
|
+
// action: 'drop',
|
|
378
|
+
// message: `${EnumToken[result.parent.typ]}: child ${EnumToken[result.node.typ]}${result.node.typ == EnumToken.DeclarationNodeType ? ` '${(result.node as AstDeclaration).nam}'` : result.node.typ == EnumToken.AtRuleNodeType || result.node.typ == EnumToken.KeyframesAtRuleNodeType ? ` '@${(result.node as AstAtRule).nam}'` : ''} not allowed in context${result.parent.typ == EnumToken.AtRuleNodeType ? ` '@${(result.parent as AstAtRule).nam}'` : result.parent.typ == EnumToken.StyleSheetNodeType ? ` 'stylesheet'` : ''}`,
|
|
379
|
+
// // @ts-ignore
|
|
380
|
+
// location: result.node.loc ?? map.get(result.node ) ?? null
|
|
381
|
+
// });
|
|
382
|
+
//
|
|
383
|
+
// // @ts-ignore
|
|
384
|
+
// removeNode(result.node, result.parent as AstNode);
|
|
385
|
+
// continue;
|
|
386
|
+
// }
|
|
387
|
+
if (allValuesHandlers.length > 0 || preVisitorsHandlersMap.size > 0 || visitorsHandlersMap.size > 0 || postVisitorsHandlersMap.size > 0) {
|
|
388
|
+
if ((result.node.typ == EnumToken.DeclarationNodeType &&
|
|
389
|
+
(preVisitorsHandlersMap.has('Declaration') || visitorsHandlersMap.has('Declaration') || postVisitorsHandlersMap.has('Declaration'))) ||
|
|
390
|
+
(result.node.typ == EnumToken.AtRuleNodeType && (preVisitorsHandlersMap.has('AtRule') || visitorsHandlersMap.has('AtRule') || postVisitorsHandlersMap.has('AtRule'))) ||
|
|
391
|
+
(result.node.typ == EnumToken.KeyframesAtRuleNodeType && (preVisitorsHandlersMap.has('KeyframesAtRule') || visitorsHandlersMap.has('KeyframesAtRule') || postVisitorsHandlersMap.has('KeyframesAtRule')))) {
|
|
392
|
+
const handlers = [];
|
|
393
|
+
const key = result.node.typ == EnumToken.DeclarationNodeType ? 'Declaration' : result.node.typ == EnumToken.AtRuleNodeType ? 'AtRule' : 'KeyframesAtRule';
|
|
394
|
+
if (preVisitorsHandlersMap.has(key)) {
|
|
395
|
+
// @ts-ignore
|
|
396
|
+
handlers.push(preVisitorsHandlersMap.get(key));
|
|
397
|
+
}
|
|
398
|
+
if (visitorsHandlersMap.has(key)) {
|
|
399
|
+
// @ts-ignore
|
|
400
|
+
handlers.push(visitorsHandlersMap.get(key));
|
|
401
|
+
}
|
|
402
|
+
if (postVisitorsHandlersMap.has(key)) {
|
|
403
|
+
// @ts-ignore
|
|
404
|
+
handlers.push(postVisitorsHandlersMap.get(key));
|
|
405
|
+
}
|
|
406
|
+
let callable;
|
|
407
|
+
let node = result.node;
|
|
408
|
+
for (const handler of handlers) {
|
|
409
|
+
callable = typeof handler == 'function' ? handler : handler[normalizeVisitorKeyName(node.typ == EnumToken.DeclarationNodeType || node.typ == EnumToken.AtRuleNodeType ? node.nam : node.val)];
|
|
410
|
+
if (callable == null) {
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
let replacement = callable(node, result.parent);
|
|
414
|
+
if (replacement == null) {
|
|
415
|
+
continue;
|
|
416
|
+
}
|
|
417
|
+
isAsync = replacement instanceof Promise || Object.getPrototypeOf(replacement).constructor.name == 'AsyncFunction';
|
|
418
|
+
if (replacement) {
|
|
419
|
+
replacement = await replacement;
|
|
420
|
+
}
|
|
421
|
+
if (replacement == null || replacement == node) {
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
// @ts-ignore
|
|
425
|
+
node = replacement;
|
|
426
|
+
//
|
|
427
|
+
if (Array.isArray(node)) {
|
|
428
|
+
break;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (node != result.node) {
|
|
432
|
+
// @ts-ignore
|
|
433
|
+
replaceToken(result.parent, result.node, node);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
else if ((result.node.typ == EnumToken.RuleNodeType && (preVisitorsHandlersMap.has('Rule') || visitorsHandlersMap.has('Rule') || postVisitorsHandlersMap.has('Rule'))) ||
|
|
437
|
+
(result.node.typ == EnumToken.KeyFramesRuleNodeType && (preVisitorsHandlersMap.has('KeyframesRule') || visitorsHandlersMap.has('KeyframesRule') || postVisitorsHandlersMap.has('KeyframesRule')))) {
|
|
438
|
+
const handlers = [];
|
|
439
|
+
const key = result.node.typ == EnumToken.RuleNodeType ? 'Rule' : 'KeyframesRule';
|
|
440
|
+
if (preVisitorsHandlersMap.has(key)) {
|
|
441
|
+
// @ts-ignore
|
|
442
|
+
handlers.push(preVisitorsHandlersMap.get(key));
|
|
443
|
+
}
|
|
444
|
+
if (visitorsHandlersMap.has(key)) {
|
|
445
|
+
// @ts-ignore
|
|
446
|
+
handlers.push(visitorsHandlersMap.get(key));
|
|
447
|
+
}
|
|
448
|
+
if (postVisitorsHandlersMap.has(key)) {
|
|
449
|
+
// @ts-ignore
|
|
450
|
+
handlers.push(postVisitorsHandlersMap.get(key));
|
|
451
|
+
}
|
|
452
|
+
let node = result.node;
|
|
453
|
+
for (const callable of handlers) {
|
|
454
|
+
// @ts-ignore
|
|
455
|
+
let replacement = callable(node, result.parent);
|
|
456
|
+
if (replacement == null) {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
isAsync = replacement instanceof Promise || Object.getPrototypeOf(replacement).constructor.name == 'AsyncFunction';
|
|
460
|
+
if (replacement) {
|
|
461
|
+
replacement = await replacement;
|
|
462
|
+
}
|
|
463
|
+
if (replacement == null || replacement == node) {
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
// @ts-ignore
|
|
467
|
+
node = replacement;
|
|
468
|
+
//
|
|
469
|
+
if (Array.isArray(node)) {
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
303
472
|
}
|
|
304
473
|
// @ts-ignore
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
474
|
+
if (node != result.node) {
|
|
475
|
+
// @ts-ignore
|
|
476
|
+
replaceToken(result.parent, result.node, node);
|
|
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) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
isAsync = replacement instanceof Promise || Object.getPrototypeOf(replacement).constructor.name == 'AsyncFunction';
|
|
491
|
+
if (isAsync) {
|
|
492
|
+
replacement = await replacement;
|
|
493
|
+
}
|
|
494
|
+
if (replacement != null && replacement != node) {
|
|
495
|
+
node = replacement;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
if (node != result.node) {
|
|
500
|
+
// @ts-ignore
|
|
501
|
+
replaceToken(result.parent, value, node);
|
|
502
|
+
}
|
|
503
|
+
const tokens = 'tokens' in result.node ? result.node.tokens : [];
|
|
504
|
+
if ('val' in result.node && Array.isArray(result.node.val)) {
|
|
505
|
+
tokens.push(...result.node.val);
|
|
506
|
+
}
|
|
507
|
+
if (tokens.length == 0) {
|
|
314
508
|
continue;
|
|
315
509
|
}
|
|
316
|
-
|
|
317
|
-
|
|
510
|
+
for (const { value, parent, root } of walkValues(tokens, result.node)) {
|
|
511
|
+
node = value;
|
|
512
|
+
for (const valueHandler of allValuesHandlers) {
|
|
513
|
+
if (valueHandler.has(node.typ)) {
|
|
514
|
+
callable = valueHandler.get(node.typ);
|
|
515
|
+
let result = callable(node, parent, root);
|
|
516
|
+
if (result == null) {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
isAsync = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction';
|
|
520
|
+
if (isAsync) {
|
|
521
|
+
result = await result;
|
|
522
|
+
}
|
|
523
|
+
if (result != null && result != node) {
|
|
524
|
+
node = result;
|
|
525
|
+
}
|
|
526
|
+
//
|
|
527
|
+
if (Array.isArray(node)) {
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
if (node != value) {
|
|
533
|
+
// @ts-ignore
|
|
534
|
+
replaceToken(parent, value, node);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
318
537
|
}
|
|
319
538
|
}
|
|
320
539
|
}
|
|
@@ -374,7 +593,6 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
374
593
|
continue;
|
|
375
594
|
}
|
|
376
595
|
loc = location;
|
|
377
|
-
// @ts-ignore
|
|
378
596
|
context.chi.push(tokens[i]);
|
|
379
597
|
if (options.sourcemap) {
|
|
380
598
|
tokens[i].loc = loc;
|
|
@@ -408,9 +626,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
408
626
|
rawTokens.shift();
|
|
409
627
|
if (atRule.val == 'import') {
|
|
410
628
|
// only @charset and @layer are accepted before @import
|
|
411
|
-
// @ts-ignore
|
|
412
629
|
if (context.chi.length > 0) {
|
|
413
|
-
// @ts-ignore
|
|
414
630
|
let i = context.chi.length;
|
|
415
631
|
while (i--) {
|
|
416
632
|
// @ts-ignore
|
|
@@ -419,11 +635,8 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
419
635
|
continue;
|
|
420
636
|
}
|
|
421
637
|
if (type != EnumToken.AtRuleNodeType) {
|
|
422
|
-
// @ts-ignore
|
|
423
638
|
if (!(type == EnumToken.InvalidAtRuleTokenType &&
|
|
424
|
-
// @ts-ignore
|
|
425
639
|
['charset', 'layer', 'import'].includes(context.chi[i].nam))) {
|
|
426
|
-
// @ts-ignore
|
|
427
640
|
errors.push({
|
|
428
641
|
action: 'drop',
|
|
429
642
|
message: 'invalid @import',
|
|
@@ -434,7 +647,6 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
434
647
|
return null;
|
|
435
648
|
}
|
|
436
649
|
}
|
|
437
|
-
// @ts-ignore
|
|
438
650
|
const name = context.chi[i].nam;
|
|
439
651
|
if (name != 'charset' && name != 'import' && name != 'layer') {
|
|
440
652
|
errors.push({ action: 'drop', message: 'invalid @import', location });
|
|
@@ -532,7 +744,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
532
744
|
const nam = renderToken(atRule, { removeComments: true });
|
|
533
745
|
// @ts-ignore
|
|
534
746
|
const node = {
|
|
535
|
-
typ: /^(-[a-z]+-)?keyframes$/.test(nam) ? EnumToken.
|
|
747
|
+
typ: /^(-[a-z]+-)?keyframes$/.test(nam) ? EnumToken.KeyframesAtRuleNodeType : EnumToken.AtRuleNodeType,
|
|
536
748
|
nam,
|
|
537
749
|
val: raw.join('')
|
|
538
750
|
};
|
|
@@ -566,7 +778,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
566
778
|
error: '',
|
|
567
779
|
node,
|
|
568
780
|
syntax: '@' + node.nam
|
|
569
|
-
} : isValid ? (node.typ == EnumToken.
|
|
781
|
+
} : isValid ? (node.typ == EnumToken.KeyframesAtRuleNodeType ? validateAtRuleKeyframes(node) : validateAtRule(node, options, context)) : {
|
|
570
782
|
valid: SyntaxValidationResult.Drop,
|
|
571
783
|
node,
|
|
572
784
|
syntax: '@' + node.nam,
|
|
@@ -602,7 +814,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
602
814
|
const location = map.get(tokens[0]);
|
|
603
815
|
const uniq = new Map;
|
|
604
816
|
parseTokens(tokens, { minify: true });
|
|
605
|
-
const ruleType = context.typ == EnumToken.
|
|
817
|
+
const ruleType = context.typ == EnumToken.KeyframesAtRuleNodeType ? EnumToken.KeyFramesRuleNodeType : EnumToken.RuleNodeType;
|
|
606
818
|
if (ruleType == EnumToken.RuleNodeType) {
|
|
607
819
|
parseSelector(tokens);
|
|
608
820
|
}
|
|
@@ -612,6 +824,34 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
612
824
|
if (curr.typ == EnumToken.CommentTokenType) {
|
|
613
825
|
return acc;
|
|
614
826
|
}
|
|
827
|
+
if (options.minify) {
|
|
828
|
+
if (curr.typ == EnumToken.PseudoClassFuncTokenType && curr.val == ':nth-child') {
|
|
829
|
+
let i = 0;
|
|
830
|
+
for (; i < curr.chi.length; i++) {
|
|
831
|
+
if (curr.chi[i].typ == EnumToken.IdenTokenType && curr.chi[i].val == 'even') {
|
|
832
|
+
Object.assign(curr.chi[i], {
|
|
833
|
+
typ: EnumToken.Dimension,
|
|
834
|
+
val: 2,
|
|
835
|
+
unit: 'n'
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
else if (curr.chi[i].typ == EnumToken.Dimension &&
|
|
839
|
+
curr.chi[i].val == 2 &&
|
|
840
|
+
curr.chi[i].unit == 'n' &&
|
|
841
|
+
curr.chi[i + 1]?.typ == EnumToken.WhitespaceTokenType &&
|
|
842
|
+
curr.chi[i + 2]?.typ == EnumToken.LiteralTokenType &&
|
|
843
|
+
curr.chi[i + 2].val == '+' &&
|
|
844
|
+
curr.chi[i + 3]?.typ == EnumToken.WhitespaceTokenType &&
|
|
845
|
+
curr.chi[i + 4]?.typ == EnumToken.NumberTokenType &&
|
|
846
|
+
curr.chi[i + 4].val == 1) {
|
|
847
|
+
curr.chi.splice(i, 5, Object.assign(curr.chi[i], {
|
|
848
|
+
typ: EnumToken.IdenTokenType,
|
|
849
|
+
val: 'odd'
|
|
850
|
+
}));
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
}
|
|
615
855
|
if (curr.typ == EnumToken.WhitespaceTokenType) {
|
|
616
856
|
if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
|
|
617
857
|
trimWhiteSpace.includes(array[index + 1]?.typ) ||
|
|
@@ -620,7 +860,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
620
860
|
return acc;
|
|
621
861
|
}
|
|
622
862
|
}
|
|
623
|
-
if (ruleType == EnumToken.
|
|
863
|
+
if (ruleType == EnumToken.KeyFramesRuleNodeType && options.minify) {
|
|
624
864
|
if (curr.typ == EnumToken.IdenTokenType && curr.val == 'from') {
|
|
625
865
|
Object.assign(curr, { typ: EnumToken.PercentageTokenType, val: '0' });
|
|
626
866
|
}
|
|
@@ -669,7 +909,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
|
|
|
669
909
|
const valid = options.validation == ValidationLevel.None ? {
|
|
670
910
|
valid: SyntaxValidationResult.Valid,
|
|
671
911
|
error: null
|
|
672
|
-
} : ruleType == EnumToken.
|
|
912
|
+
} : ruleType == EnumToken.KeyFramesRuleNodeType ? validateKeyframeSelector(tokens) : validateSelector(tokens, options, context);
|
|
673
913
|
if (valid.valid != SyntaxValidationResult.Valid) {
|
|
674
914
|
// @ts-ignore
|
|
675
915
|
node.typ = EnumToken.InvalidRuleTokenType;
|
|
@@ -1045,7 +1285,7 @@ async function parseDeclarations(declaration) {
|
|
|
1045
1285
|
position: { ind: 0, lin: 1, col: 1 },
|
|
1046
1286
|
currentPosition: { ind: -1, lin: 1, col: 0 }
|
|
1047
1287
|
}), { setParent: false, minify: false, validation: false }).then(result => {
|
|
1048
|
-
return result.ast.chi[0].chi.filter(t => t.typ == EnumToken.DeclarationNodeType);
|
|
1288
|
+
return result.ast.chi[0].chi.filter(t => t.typ == EnumToken.DeclarationNodeType || t.typ == EnumToken.CommentNodeType);
|
|
1049
1289
|
});
|
|
1050
1290
|
}
|
|
1051
1291
|
/**
|
|
@@ -1662,4 +1902,4 @@ function parseTokens(tokens, options = {}) {
|
|
|
1662
1902
|
return tokens;
|
|
1663
1903
|
}
|
|
1664
1904
|
|
|
1665
|
-
export { doParse, getTokenType, parseAtRulePrelude, parseDeclarations, parseSelector, parseString, parseTokens, urlTokenMatcher };
|
|
1905
|
+
export { doParse, getTokenType, parseAtRulePrelude, parseDeclarations, parseSelector, parseString, parseTokens, replaceToken, urlTokenMatcher };
|
|
@@ -579,7 +579,7 @@ async function* tokenizeStream(input) {
|
|
|
579
579
|
const reader = input.getReader();
|
|
580
580
|
while (true) {
|
|
581
581
|
const { done, value } = await reader.read();
|
|
582
|
-
parseInfo.stream += decoder.decode(value, { stream: true });
|
|
582
|
+
parseInfo.stream += ArrayBuffer.isView(value) ? decoder.decode(value, { stream: true }) : value;
|
|
583
583
|
yield* tokenize(parseInfo, done);
|
|
584
584
|
if (done) {
|
|
585
585
|
break;
|
|
@@ -111,7 +111,7 @@ function doRender(data, options = {}) {
|
|
|
111
111
|
function updateSourceMap(node, options, cache, sourcemap, position, str) {
|
|
112
112
|
if ([
|
|
113
113
|
EnumToken.RuleNodeType, EnumToken.AtRuleNodeType,
|
|
114
|
-
EnumToken.
|
|
114
|
+
EnumToken.KeyFramesRuleNodeType, EnumToken.KeyframesAtRuleNodeType
|
|
115
115
|
].includes(node.typ)) {
|
|
116
116
|
let src = node.loc?.src ?? '';
|
|
117
117
|
let output = options.output ?? '';
|
|
@@ -185,9 +185,9 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
|
|
|
185
185
|
}, '');
|
|
186
186
|
case EnumToken.AtRuleNodeType:
|
|
187
187
|
case EnumToken.RuleNodeType:
|
|
188
|
-
case EnumToken.
|
|
189
|
-
case EnumToken.
|
|
190
|
-
if ([EnumToken.AtRuleNodeType, EnumToken.
|
|
188
|
+
case EnumToken.KeyFramesRuleNodeType:
|
|
189
|
+
case EnumToken.KeyframesAtRuleNodeType:
|
|
190
|
+
if ([EnumToken.AtRuleNodeType, EnumToken.KeyframesAtRuleNodeType].includes(data.typ) && !('chi' in data)) {
|
|
191
191
|
return `${indent}@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val};`;
|
|
192
192
|
}
|
|
193
193
|
// @ts-ignore
|
|
@@ -228,7 +228,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
|
|
|
228
228
|
if (children.endsWith(';')) {
|
|
229
229
|
children = children.slice(0, -1);
|
|
230
230
|
}
|
|
231
|
-
if ([EnumToken.AtRuleNodeType, EnumToken.
|
|
231
|
+
if ([EnumToken.AtRuleNodeType, EnumToken.KeyframesAtRuleNodeType].includes(data.typ)) {
|
|
232
232
|
return `@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val}${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
|
|
233
233
|
}
|
|
234
234
|
return data.sel + `${options.indent}{${options.newLine}` + (children === '' ? '' : indentSub + children + options.newLine) + indent + `}`;
|
|
@@ -4,7 +4,7 @@ import '../../ast/walk.js';
|
|
|
4
4
|
import '../../parser/parse.js';
|
|
5
5
|
import '../../parser/tokenize.js';
|
|
6
6
|
import '../../parser/utils/config.js';
|
|
7
|
-
import { color2srgbvalues } from './color.js';
|
|
7
|
+
import { color2srgbvalues, toPrecisionValue } from './color.js';
|
|
8
8
|
import { hsl2srgbvalues } from './rgb.js';
|
|
9
9
|
import './utils/constants.js';
|
|
10
10
|
import { lch2srgbvalues, lab2srgbvalues, oklch2srgbvalues, oklab2srgbvalues, hwb2srgbvalues, rgb2srgbvalues } from './srgb.js';
|
|
@@ -92,11 +92,14 @@ function cmyktoken(values) {
|
|
|
92
92
|
chi: values.reduce((acc, curr, index) => index < 4 ? [...acc, {
|
|
93
93
|
typ: EnumToken.PercentageTokenType,
|
|
94
94
|
// @ts-ignore
|
|
95
|
-
val: curr * 100
|
|
95
|
+
val: toPrecisionValue(curr) * 100
|
|
96
96
|
}] : [...acc, {
|
|
97
97
|
typ: EnumToken.LiteralTokenType,
|
|
98
98
|
val: '/'
|
|
99
|
-
}, {
|
|
99
|
+
}, {
|
|
100
|
+
typ: EnumToken.PercentageTokenType,
|
|
101
|
+
val: toPrecisionValue(curr) * 100
|
|
102
|
+
}], []),
|
|
100
103
|
kin: ColorType.DEVICE_CMYK
|
|
101
104
|
};
|
|
102
105
|
}
|
|
@@ -129,11 +129,10 @@ function colorMix(colorSpace, hueInterpolationMethod, color1, percentage1, color
|
|
|
129
129
|
// @ts-ignore
|
|
130
130
|
const calculate = () => [colorSpace].concat(values1.map((v1, i) => {
|
|
131
131
|
return {
|
|
132
|
-
|
|
133
|
-
typ: EnumToken.NumberTokenType, val: String((mul1 * v1 * p1 + mul2 * values2[i] * p2) / mul)
|
|
132
|
+
typ: EnumToken.NumberTokenType, val: (mul1 * v1 * p1 + mul2 * values2[i] * p2) / mul
|
|
134
133
|
};
|
|
135
134
|
}).concat(mul == 1 ? [] : [{
|
|
136
|
-
typ: EnumToken.NumberTokenType, val:
|
|
135
|
+
typ: EnumToken.NumberTokenType, val: mul
|
|
137
136
|
}]));
|
|
138
137
|
switch (colorSpace.val) {
|
|
139
138
|
case 'srgb':
|
|
@@ -25,6 +25,7 @@ import { reduceHexValue, rgb2HexToken, color2HexToken, lch2HexToken, lab2HexToke
|
|
|
25
25
|
import { parseRelativeColor } from './relativecolor.js';
|
|
26
26
|
import { color2cmykToken, lch2cmykToken, lab2cmykToken, oklch2cmykToken, oklab2cmyk, hwb2cmykToken, hsl2cmykToken, rgb2cmykToken } from './cmyk.js';
|
|
27
27
|
import { a98rgb2srgbvalues, srgb2a98values } from './a98rgb.js';
|
|
28
|
+
import { epsilon } from '../../ast/transform/utils.js';
|
|
28
29
|
import '../../renderer/sourcemap/lib/encode.js';
|
|
29
30
|
|
|
30
31
|
/**
|
|
@@ -32,6 +33,8 @@ import '../../renderer/sourcemap/lib/encode.js';
|
|
|
32
33
|
* @param token
|
|
33
34
|
* @param to
|
|
34
35
|
*
|
|
36
|
+
* @private
|
|
37
|
+
*
|
|
35
38
|
* <code>
|
|
36
39
|
*
|
|
37
40
|
* const token = {typ: EnumToken.ColorTokenType, kin: ColorType.HEX, val: '#F00'}
|
|
@@ -73,7 +76,8 @@ function convertColor(token, to) {
|
|
|
73
76
|
if (components != null) {
|
|
74
77
|
token = {
|
|
75
78
|
...token,
|
|
76
|
-
chi: [...(token.val == 'color' ? [chi[offset]] : []), ...Object.values(components)]
|
|
79
|
+
chi: [...(token.val == 'color' ? [chi[offset]] : []), ...Object.values(components)],
|
|
80
|
+
kin: ColorType[token.val.toUpperCase().replaceAll('-', '_')]
|
|
77
81
|
};
|
|
78
82
|
delete token.cal;
|
|
79
83
|
}
|
|
@@ -89,6 +93,11 @@ function convertColor(token, to) {
|
|
|
89
93
|
if (token.kin == ColorType.COLOR) {
|
|
90
94
|
const colorSpace = token.chi.find(t => ![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ));
|
|
91
95
|
if (colorSpace.val == ColorType[to].toLowerCase().replaceAll('_', '-')) {
|
|
96
|
+
for (const chi of token.chi) {
|
|
97
|
+
if (chi.typ == EnumToken.NumberTokenType && typeof chi.val == 'number') {
|
|
98
|
+
chi.val = toPrecisionValue(getNumber(chi));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
92
101
|
return token;
|
|
93
102
|
}
|
|
94
103
|
}
|
|
@@ -512,9 +521,9 @@ function color2srgbvalues(token) {
|
|
|
512
521
|
function values2colortoken(values, to) {
|
|
513
522
|
values = srgb2srgbcolorspace(values, to);
|
|
514
523
|
const chi = [
|
|
515
|
-
{ typ: EnumToken.NumberTokenType, val: values[0] },
|
|
516
|
-
{ typ: EnumToken.NumberTokenType, val: values[1] },
|
|
517
|
-
{ typ: EnumToken.NumberTokenType, val: values[2] },
|
|
524
|
+
{ typ: EnumToken.NumberTokenType, val: toPrecisionValue(values[0]) },
|
|
525
|
+
{ typ: EnumToken.NumberTokenType, val: toPrecisionValue(values[1]) },
|
|
526
|
+
{ typ: EnumToken.NumberTokenType, val: toPrecisionValue(values[2]) },
|
|
518
527
|
];
|
|
519
528
|
if (values.length == 4) {
|
|
520
529
|
chi.push({ typ: EnumToken.LiteralTokenType, val: "/" }, {
|
|
@@ -539,8 +548,17 @@ function getNumber(token) {
|
|
|
539
548
|
if (token.typ == EnumToken.IdenTokenType && token.val == 'none') {
|
|
540
549
|
return 0;
|
|
541
550
|
}
|
|
551
|
+
let val;
|
|
542
552
|
// @ts-ignore
|
|
543
|
-
|
|
553
|
+
if (typeof token.val != 'number' && token.val?.typ == EnumToken.FractionTokenType) {
|
|
554
|
+
// @ts-ignore
|
|
555
|
+
val = token.val.l.val / token.val.r.val;
|
|
556
|
+
}
|
|
557
|
+
else {
|
|
558
|
+
val = token.val;
|
|
559
|
+
}
|
|
560
|
+
// @ts-ignore
|
|
561
|
+
return token.typ == EnumToken.PercentageTokenType ? val / 100 : val;
|
|
544
562
|
}
|
|
545
563
|
/**
|
|
546
564
|
* convert angle to turn
|
|
@@ -571,6 +589,10 @@ function getAngle(token) {
|
|
|
571
589
|
// @ts-ignore
|
|
572
590
|
return token.val / 360;
|
|
573
591
|
}
|
|
592
|
+
function toPrecisionValue(value) {
|
|
593
|
+
value = +value.toFixed(colorPrecision);
|
|
594
|
+
return Math.abs(value) < epsilon ? 0 : value;
|
|
595
|
+
}
|
|
574
596
|
function toPrecisionAngle(angle) {
|
|
575
597
|
angle = +angle.toPrecision(colorPrecision);
|
|
576
598
|
if (Math.abs(angle) >= 360) {
|
|
@@ -585,4 +607,4 @@ function toPrecisionAngle(angle) {
|
|
|
585
607
|
return angle;
|
|
586
608
|
}
|
|
587
609
|
|
|
588
|
-
export { cmyk2colorToken, color2colorToken, color2srgbvalues, convertColor, getAngle, getNumber, hex2colorToken, hsl2colorToken, hwb2colorToken, lab2colorToken, lch2colorToken, minmax, oklab2colorToken, oklch2colorToken, rgb2colorToken, toPrecisionAngle };
|
|
610
|
+
export { cmyk2colorToken, color2colorToken, color2srgbvalues, convertColor, getAngle, getNumber, hex2colorToken, hsl2colorToken, hwb2colorToken, lab2colorToken, lch2colorToken, minmax, oklab2colorToken, oklch2colorToken, rgb2colorToken, toPrecisionAngle, toPrecisionValue };
|
|
@@ -33,6 +33,9 @@ function reduceHexValue(value) {
|
|
|
33
33
|
value[7] == value[8]) {
|
|
34
34
|
value = `#${value[1]}${value[3]}${value[5]}${value[7] == 'f' ? '' : value[7]}`;
|
|
35
35
|
}
|
|
36
|
+
if (value.endsWith('ff')) {
|
|
37
|
+
value = value.slice(0, -2);
|
|
38
|
+
}
|
|
36
39
|
}
|
|
37
40
|
return named_color != null && named_color.length <= value.length ? named_color : value;
|
|
38
41
|
}
|