@tbela99/css-parser 1.3.2 → 1.3.4

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +59 -20
  3. package/dist/index-umd-web.js +1846 -1075
  4. package/dist/index.cjs +1941 -1202
  5. package/dist/index.d.ts +914 -181
  6. package/dist/lib/ast/expand.js +5 -10
  7. package/dist/lib/ast/features/calc.js +8 -8
  8. package/dist/lib/ast/features/inlinecssvariables.js +9 -8
  9. package/dist/lib/ast/features/prefix.js +5 -15
  10. package/dist/lib/ast/features/shorthand.js +5 -6
  11. package/dist/lib/ast/features/transform.js +18 -25
  12. package/dist/lib/ast/features/type.js +4 -2
  13. package/dist/lib/ast/minify.js +56 -112
  14. package/dist/lib/ast/transform/compute.js +2 -4
  15. package/dist/lib/ast/transform/matrix.js +20 -20
  16. package/dist/lib/ast/transform/minify.js +105 -12
  17. package/dist/lib/ast/transform/rotate.js +11 -11
  18. package/dist/lib/ast/transform/scale.js +6 -6
  19. package/dist/lib/ast/transform/skew.js +4 -4
  20. package/dist/lib/ast/transform/translate.js +3 -3
  21. package/dist/lib/ast/transform/utils.js +30 -37
  22. package/dist/lib/ast/types.js +16 -4
  23. package/dist/lib/ast/walk.js +172 -70
  24. package/dist/lib/fs/resolve.js +12 -7
  25. package/dist/lib/parser/declaration/list.js +3 -1
  26. package/dist/lib/parser/parse.js +441 -161
  27. package/dist/lib/parser/tokenize.js +12 -14
  28. package/dist/lib/renderer/render.js +7 -7
  29. package/dist/lib/syntax/color/cmyk.js +6 -3
  30. package/dist/lib/syntax/color/color-mix.js +2 -3
  31. package/dist/lib/syntax/color/color.js +28 -6
  32. package/dist/lib/syntax/color/hex.js +3 -0
  33. package/dist/lib/syntax/color/hsl.js +18 -7
  34. package/dist/lib/syntax/color/hwb.js +3 -3
  35. package/dist/lib/syntax/color/lab.js +4 -4
  36. package/dist/lib/syntax/color/lch.js +7 -4
  37. package/dist/lib/syntax/color/oklab.js +4 -4
  38. package/dist/lib/syntax/color/oklch.js +18 -6
  39. package/dist/lib/syntax/color/relativecolor.js +9 -56
  40. package/dist/lib/syntax/color/srgb.js +1 -1
  41. package/dist/lib/syntax/syntax.js +36 -18
  42. package/dist/lib/validation/at-rules/container.js +11 -0
  43. package/dist/lib/validation/at-rules/counter-style.js +11 -0
  44. package/dist/lib/validation/at-rules/font-feature-values.js +11 -0
  45. package/dist/lib/validation/at-rules/keyframes.js +11 -0
  46. package/dist/lib/validation/at-rules/layer.js +11 -0
  47. package/dist/lib/validation/at-rules/media.js +11 -0
  48. package/dist/lib/validation/at-rules/page-margin-box.js +11 -0
  49. package/dist/lib/validation/at-rules/page.js +11 -0
  50. package/dist/lib/validation/at-rules/supports.js +11 -0
  51. package/dist/lib/validation/at-rules/when.js +11 -0
  52. package/dist/lib/validation/config.js +0 -2
  53. package/dist/lib/validation/config.json.js +21 -9
  54. package/dist/lib/validation/parser/parse.js +53 -2
  55. package/dist/lib/validation/syntax.js +199 -36
  56. package/dist/node.js +63 -36
  57. package/dist/web.js +84 -25
  58. package/package.json +7 -5
  59. package/dist/lib/validation/parser/types.js +0 -54
@@ -1,7 +1,7 @@
1
- import { isIdentStart, isIdent, isIdentColor, mathFuncs, isColor, parseColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isHexColor, isHash, mediaTypes } from '../syntax/syntax.js';
1
+ import { isIdentStart, isIdent, isIdentColor, mathFuncs, isColor, parseColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, parseDimension, isHexColor, isHash, mediaTypes } from '../syntax/syntax.js';
2
2
  import { EnumToken, ColorType, ValidationLevel, SyntaxValidationResult } from '../ast/types.js';
3
- import { minify, definedPropertySettings, combinators } from '../ast/minify.js';
4
- import { walkValues, walk, WalkerOptionEnum } from '../ast/walk.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';
@@ -11,14 +11,13 @@ import { funcLike, timingFunc, timelineFunc, COLORS_NAMES, systemColors, depreca
11
11
  import { buildExpression } from '../ast/math/expression.js';
12
12
  import { tokenize, tokenizeStream } from './tokenize.js';
13
13
  import '../validation/config.js';
14
- import '../validation/parser/types.js';
15
14
  import '../validation/parser/parse.js';
16
15
  import { validateSelector } from '../validation/selector.js';
17
16
  import { validateAtRule } from '../validation/atrule.js';
18
17
  import { splitTokenList } from '../validation/utils/list.js';
19
18
  import '../validation/syntaxes/complex-selector.js';
20
19
  import { validateKeyframeSelector } from '../validation/syntaxes/keyframe-selector.js';
21
- import { evaluateSyntax } from '../validation/syntax.js';
20
+ import { isNodeAllowedInContext, evaluateSyntax } from '../validation/syntax.js';
22
21
  import { validateAtRuleKeyframes } from '../validation/at-rules/keyframes.js';
23
22
 
24
23
  const urlTokenMatcher = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/;
@@ -39,6 +38,36 @@ const enumTokenHints = new Set([
39
38
  function reject(reason) {
40
39
  throw new Error(reason ?? 'Parsing aborted');
41
40
  }
41
+ function normalizeVisitorKeyName(keyName) {
42
+ return keyName.replace(/-([a-z])/g, (all, one) => one.toUpperCase());
43
+ }
44
+ function replaceToken(parent, value, replacement) {
45
+ for (const node of (Array.isArray(replacement) ? replacement : [replacement])) {
46
+ if ('parent' in value && value.parent != node.parent) {
47
+ Object.defineProperty(node, 'parent', {
48
+ ...definedPropertySettings,
49
+ value: value.parent
50
+ });
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
+ const target = 'val' in parent && Array.isArray(parent.val) ? parent.val : parent.chi;
63
+ // @ts-ignore
64
+ const index = target.indexOf(value);
65
+ if (index == -1) {
66
+ return;
67
+ }
68
+ target.splice(index, 1, ...(Array.isArray(replacement) ? replacement : [replacement]));
69
+ }
70
+ }
42
71
  /**
43
72
  * parse css string
44
73
  * @param iter
@@ -88,6 +117,8 @@ async function doParse(iter, options = {}) {
88
117
  const stats = {
89
118
  src: options.src ?? '',
90
119
  bytesIn: 0,
120
+ nodesCount: 0,
121
+ tokensCount: 0,
91
122
  importedBytesIn: 0,
92
123
  parse: `0ms`,
93
124
  minify: `0ms`,
@@ -116,14 +147,107 @@ async function doParse(iter, options = {}) {
116
147
  src: ''
117
148
  };
118
149
  }
119
- let item;
120
- let node;
150
+ let valuesHandlers;
151
+ let preValuesHandlers;
152
+ let postValuesHandlers;
153
+ let preVisitorsHandlersMap;
154
+ let visitorsHandlersMap;
155
+ let postVisitorsHandlersMap;
121
156
  const rawTokens = [];
122
157
  const imports = [];
158
+ let item;
159
+ let node;
123
160
  // @ts-ignore ignore error
124
- const isAsync = typeof iter[Symbol.asyncIterator] === 'function';
161
+ let isAsync = typeof iter[Symbol.asyncIterator] === 'function';
162
+ if (options.visitor != null) {
163
+ valuesHandlers = new Map;
164
+ preValuesHandlers = new Map;
165
+ postValuesHandlers = new Map;
166
+ preVisitorsHandlersMap = new Map;
167
+ visitorsHandlersMap = new Map;
168
+ postVisitorsHandlersMap = new Map;
169
+ const visitors = Object.entries(options.visitor);
170
+ let key;
171
+ let value;
172
+ let i;
173
+ for (i = 0; i < visitors.length; i++) {
174
+ key = visitors[i][0];
175
+ value = visitors[i][1];
176
+ if (Number.isInteger(+key)) {
177
+ visitors.splice(i + 1, 0, ...Object.entries(value));
178
+ continue;
179
+ }
180
+ if (Array.isArray(value)) {
181
+ // @ts-ignore
182
+ visitors.splice(i + 1, 0, ...value.map((item) => [key, item]));
183
+ continue;
184
+ }
185
+ if (key in EnumToken) {
186
+ if (typeof value == 'function') {
187
+ if (!valuesHandlers.has(EnumToken[key])) {
188
+ valuesHandlers.set(EnumToken[key], []);
189
+ }
190
+ valuesHandlers.get(EnumToken[key]).push(value);
191
+ }
192
+ else if (typeof value == 'object' && 'type' in value && 'handler' in value && value.type in WalkerEvent) {
193
+ if (value.type == WalkerEvent.Enter) {
194
+ if (!preValuesHandlers.has(EnumToken[key])) {
195
+ preValuesHandlers.set(EnumToken[key], []);
196
+ }
197
+ preValuesHandlers.get(EnumToken[key]).push(value.handler);
198
+ }
199
+ else if (value.type == WalkerEvent.Leave) {
200
+ if (!postValuesHandlers.has(EnumToken[key])) {
201
+ postValuesHandlers.set(EnumToken[key], []);
202
+ }
203
+ postValuesHandlers.get(EnumToken[key]).push(value.handler);
204
+ }
205
+ }
206
+ else {
207
+ errors.push({ action: 'ignore', message: `doParse: visitor.${key} is not a valid key name` });
208
+ }
209
+ }
210
+ else if (['Declaration', 'Rule', 'AtRule', 'KeyframesRule', 'KeyframesAtRule'].includes(key)) {
211
+ if (typeof value == 'function') {
212
+ if (!visitorsHandlersMap.has(key)) {
213
+ visitorsHandlersMap.set(key, []);
214
+ }
215
+ visitorsHandlersMap.get(key).push(value);
216
+ }
217
+ else if (typeof value == 'object') {
218
+ if ('type' in value && 'handler' in value && value.type in WalkerEvent) {
219
+ if (value.type == WalkerEvent.Enter) {
220
+ if (!preVisitorsHandlersMap.has(key)) {
221
+ preVisitorsHandlersMap.set(key, []);
222
+ }
223
+ preVisitorsHandlersMap.get(key).push(value.handler);
224
+ }
225
+ else if (value.type == WalkerEvent.Leave) {
226
+ if (!postVisitorsHandlersMap.has(key)) {
227
+ postVisitorsHandlersMap.set(key, []);
228
+ }
229
+ postVisitorsHandlersMap.get(key).push(value.handler);
230
+ }
231
+ }
232
+ else {
233
+ if (!visitorsHandlersMap.has(key)) {
234
+ visitorsHandlersMap.set(key, []);
235
+ }
236
+ visitorsHandlersMap.get(key).push(value);
237
+ }
238
+ }
239
+ else {
240
+ errors.push({ action: 'ignore', message: `doParse: visitor.${key} is not a valid key name` });
241
+ }
242
+ }
243
+ else {
244
+ errors.push({ action: 'ignore', message: `doParse: visitor.${key} is not a valid key name` });
245
+ }
246
+ }
247
+ }
125
248
  while (item = isAsync ? (await iter.next()).value : iter.next().value) {
126
249
  stats.bytesIn = item.bytesIn;
250
+ stats.tokensCount++;
127
251
  rawTokens.push(item);
128
252
  if (item.hint != null && BadTokensTypes.includes(item.hint)) {
129
253
  const node = getTokenType(item.token, item.hint);
@@ -151,7 +275,7 @@ async function doParse(iter, options = {}) {
151
275
  ast.loc.end = item.end;
152
276
  }
153
277
  if (item.token == ';' || item.token == '{') {
154
- node = parseNode(tokens, context, options, errors, src, map, rawTokens);
278
+ node = parseNode(tokens, context, options, errors, src, map, rawTokens, stats);
155
279
  rawTokens.length = 0;
156
280
  if (node != null) {
157
281
  if ('chi' in node) {
@@ -195,7 +319,7 @@ async function doParse(iter, options = {}) {
195
319
  map = new Map;
196
320
  }
197
321
  else if (item.token == '}') {
198
- parseNode(tokens, context, options, errors, src, map, rawTokens);
322
+ parseNode(tokens, context, options, errors, src, map, rawTokens, stats);
199
323
  rawTokens.length = 0;
200
324
  if (context.loc != null) {
201
325
  context.loc.end = item.end;
@@ -216,7 +340,7 @@ async function doParse(iter, options = {}) {
216
340
  }
217
341
  }
218
342
  if (tokens.length > 0) {
219
- node = parseNode(tokens, context, options, errors, src, map, rawTokens);
343
+ node = parseNode(tokens, context, options, errors, src, map, rawTokens, stats);
220
344
  rawTokens.length = 0;
221
345
  if (node != null) {
222
346
  if (node.typ == EnumToken.AtRuleNodeType && node.nam == 'import') {
@@ -240,21 +364,18 @@ async function doParse(iter, options = {}) {
240
364
  const token = node.tokens[0];
241
365
  const url = token.typ == EnumToken.StringTokenType ? token.val.slice(1, -1) : token.val;
242
366
  try {
243
- const root = await options.getStream(url, options.src).then(async (stream) => {
244
- return doParse(tokenizeStream(stream), Object.assign({}, options, {
245
- minify: false,
246
- setParent: false,
247
- src: options.resolve(url, options.src).absolute
248
- })); // )
249
- });
250
- // const root: ParseResult = await options.load!(url, <string>options.src).then((src: string) => {
251
- //
252
- // return doParse(src, Object.assign({}, options, {
253
- // minify: false,
254
- // setParent: false,
255
- // src: options.resolve!(url, options.src as string).absolute
256
- // }))
257
- // });
367
+ const result = options.load(url, options.src);
368
+ const stream = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction' ? await result : result;
369
+ const root = await doParse(stream instanceof ReadableStream ? tokenizeStream(stream) : tokenize({
370
+ stream,
371
+ buffer: '',
372
+ position: { ind: 0, lin: 1, col: 1 },
373
+ currentPosition: { ind: -1, lin: 1, col: 0 }
374
+ }), Object.assign({}, options, {
375
+ minify: false,
376
+ setParent: false,
377
+ src: options.resolve(url, options.src).absolute
378
+ }));
258
379
  stats.importedBytesIn += root.stats.bytesIn;
259
380
  stats.imports.push(root.stats);
260
381
  node.parent.chi.splice(node.parent.chi.indexOf(node), 1, ...root.ast.chi);
@@ -282,39 +403,155 @@ async function doParse(iter, options = {}) {
282
403
  if (options.expandNestingRules) {
283
404
  ast = expand(ast);
284
405
  }
406
+ let replacement;
407
+ let callable;
285
408
  if (options.visitor != null) {
286
409
  for (const result of walk(ast)) {
287
- if (result.node.typ == EnumToken.DeclarationNodeType &&
288
- (typeof options.visitor.Declaration == 'function' || options.visitor.Declaration?.[result.node.nam] != null)) {
289
- const callable = typeof options.visitor.Declaration == 'function' ? options.visitor.Declaration : options.visitor.Declaration[result.node.nam];
290
- const isAsync = Object.getPrototypeOf(callable).constructor.name == 'AsyncFunction';
291
- const results = isAsync ? await callable(result.node) : callable(result.node);
292
- if (results == null || (Array.isArray(results) && results.length == 0)) {
293
- continue;
410
+ if (valuesHandlers.size > 0 || preVisitorsHandlersMap.size > 0 || visitorsHandlersMap.size > 0 || postVisitorsHandlersMap.size > 0) {
411
+ if ((result.node.typ == EnumToken.DeclarationNodeType &&
412
+ (preVisitorsHandlersMap.has('Declaration') || visitorsHandlersMap.has('Declaration') || postVisitorsHandlersMap.has('Declaration'))) ||
413
+ (result.node.typ == EnumToken.AtRuleNodeType && (preVisitorsHandlersMap.has('AtRule') || visitorsHandlersMap.has('AtRule') || postVisitorsHandlersMap.has('AtRule'))) ||
414
+ (result.node.typ == EnumToken.KeyframesAtRuleNodeType && (preVisitorsHandlersMap.has('KeyframesAtRule') || visitorsHandlersMap.has('KeyframesAtRule') || postVisitorsHandlersMap.has('KeyframesAtRule')))) {
415
+ const handlers = [];
416
+ const key = result.node.typ == EnumToken.DeclarationNodeType ? 'Declaration' : result.node.typ == EnumToken.AtRuleNodeType ? 'AtRule' : 'KeyframesAtRule';
417
+ if (preVisitorsHandlersMap.has(key)) {
418
+ // @ts-ignore
419
+ handlers.push(...preVisitorsHandlersMap.get(key));
420
+ }
421
+ if (visitorsHandlersMap.has(key)) {
422
+ // @ts-ignore
423
+ handlers.push(...visitorsHandlersMap.get(key));
424
+ }
425
+ if (postVisitorsHandlersMap.has(key)) {
426
+ // @ts-ignore
427
+ handlers.push(...postVisitorsHandlersMap.get(key));
428
+ }
429
+ let node = result.node;
430
+ for (const handler of handlers) {
431
+ callable = typeof handler == 'function' ? handler : handler[normalizeVisitorKeyName(node.typ == EnumToken.DeclarationNodeType || node.typ == EnumToken.AtRuleNodeType ? node.nam : node.val)];
432
+ if (callable == null) {
433
+ continue;
434
+ }
435
+ replacement = callable(node, result.parent);
436
+ if (replacement == null) {
437
+ continue;
438
+ }
439
+ isAsync = replacement instanceof Promise || Object.getPrototypeOf(replacement).constructor.name == 'AsyncFunction';
440
+ if (replacement) {
441
+ replacement = await replacement;
442
+ }
443
+ if (replacement == null || replacement == node) {
444
+ continue;
445
+ }
446
+ // @ts-ignore
447
+ node = replacement;
448
+ //
449
+ if (Array.isArray(node)) {
450
+ break;
451
+ }
452
+ }
453
+ if (node != result.node) {
454
+ // @ts-ignore
455
+ replaceToken(result.parent, result.node, node);
456
+ }
294
457
  }
295
- // @ts-ignore
296
- result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
297
- }
298
- else if (options.visitor.Rule != null && result.node.typ == EnumToken.RuleNodeType) {
299
- const isAsync = Object.getPrototypeOf(options.visitor.Rule).constructor.name == 'AsyncFunction';
300
- const results = isAsync ? await options.visitor.Rule(result.node) : options.visitor.Rule(result.node);
301
- if (results == null || (Array.isArray(results) && results.length == 0)) {
302
- continue;
458
+ else if ((result.node.typ == EnumToken.RuleNodeType && (preVisitorsHandlersMap.has('Rule') || visitorsHandlersMap.has('Rule') || postVisitorsHandlersMap.has('Rule'))) ||
459
+ (result.node.typ == EnumToken.KeyFramesRuleNodeType && (preVisitorsHandlersMap.has('KeyframesRule') || visitorsHandlersMap.has('KeyframesRule') || postVisitorsHandlersMap.has('KeyframesRule')))) {
460
+ const handlers = [];
461
+ const key = result.node.typ == EnumToken.RuleNodeType ? 'Rule' : 'KeyframesRule';
462
+ if (preVisitorsHandlersMap.has(key)) {
463
+ handlers.push(...preVisitorsHandlersMap.get(key));
464
+ }
465
+ if (visitorsHandlersMap.has(key)) {
466
+ handlers.push(...visitorsHandlersMap.get(key));
467
+ }
468
+ if (postVisitorsHandlersMap.has(key)) {
469
+ handlers.push(...postVisitorsHandlersMap.get(key));
470
+ }
471
+ let node = result.node;
472
+ for (const callable of handlers) {
473
+ replacement = callable(node, result.parent);
474
+ if (replacement == null) {
475
+ continue;
476
+ }
477
+ isAsync = replacement instanceof Promise || Object.getPrototypeOf(replacement).constructor.name == 'AsyncFunction';
478
+ if (replacement) {
479
+ replacement = await replacement;
480
+ }
481
+ if (replacement == null || replacement == node) {
482
+ continue;
483
+ }
484
+ // @ts-ignore
485
+ node = replacement;
486
+ //
487
+ if (Array.isArray(node)) {
488
+ break;
489
+ }
490
+ }
491
+ // @ts-ignore
492
+ if (node != result.node) {
493
+ // @ts-ignore
494
+ replaceToken(result.parent, result.node, node);
495
+ }
303
496
  }
304
- // @ts-ignore
305
- result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
306
- }
307
- else if (options.visitor.AtRule != null &&
308
- result.node.typ == EnumToken.AtRuleNodeType &&
309
- (typeof options.visitor.AtRule == 'function' || options.visitor.AtRule?.[result.node.nam] != null)) {
310
- const callable = typeof options.visitor.AtRule == 'function' ? options.visitor.AtRule : options.visitor.AtRule[result.node.nam];
311
- const isAsync = Object.getPrototypeOf(callable).constructor.name == 'AsyncFunction';
312
- const results = isAsync ? await callable(result.node) : callable(result.node);
313
- if (results == null || (Array.isArray(results) && results.length == 0)) {
314
- continue;
497
+ else if (valuesHandlers.size > 0) {
498
+ let node = null;
499
+ node = result.node;
500
+ if (valuesHandlers.has(node.typ)) {
501
+ for (const valueHandler of valuesHandlers.get(node.typ)) {
502
+ callable = valueHandler;
503
+ replacement = callable(node, result.parent);
504
+ if (replacement == null) {
505
+ continue;
506
+ }
507
+ isAsync = replacement instanceof Promise || Object.getPrototypeOf(replacement).constructor.name == 'AsyncFunction';
508
+ if (isAsync) {
509
+ replacement = await replacement;
510
+ }
511
+ if (replacement != null && replacement != node) {
512
+ node = replacement;
513
+ }
514
+ }
515
+ }
516
+ if (node != result.node) {
517
+ // @ts-ignore
518
+ replaceToken(result.parent, value, node);
519
+ }
520
+ const tokens = 'tokens' in result.node ? result.node.tokens : [];
521
+ if ('val' in result.node && Array.isArray(result.node.val)) {
522
+ tokens.push(...result.node.val);
523
+ }
524
+ if (tokens.length == 0) {
525
+ continue;
526
+ }
527
+ for (const { value, parent, root } of walkValues(tokens, result.node)) {
528
+ node = value;
529
+ if (valuesHandlers.has(node.typ)) {
530
+ for (const valueHandler of valuesHandlers.get(node.typ)) {
531
+ callable = valueHandler;
532
+ let result = callable(node, parent, root);
533
+ if (result == null) {
534
+ continue;
535
+ }
536
+ isAsync = result instanceof Promise || Object.getPrototypeOf(result).constructor.name == 'AsyncFunction';
537
+ if (isAsync) {
538
+ result = await result;
539
+ }
540
+ if (result != null && result != node) {
541
+ node = result;
542
+ }
543
+ //
544
+ if (Array.isArray(node)) {
545
+ break;
546
+ }
547
+ }
548
+ }
549
+ if (node != value) {
550
+ // @ts-ignore
551
+ replaceToken(parent, value, node);
552
+ }
553
+ }
315
554
  }
316
- // @ts-ignore
317
- result.parent.chi.splice(result.parent.chi.indexOf(result.node), 1, ...(Array.isArray(results) ? results : [results]));
318
555
  }
319
556
  }
320
557
  }
@@ -352,7 +589,7 @@ function getLastNode(context) {
352
589
  }
353
590
  return null;
354
591
  }
355
- function parseNode(results, context, options, errors, src, map, rawTokens) {
592
+ function parseNode(results, context, options, errors, src, map, rawTokens, stats) {
356
593
  let tokens = [];
357
594
  for (const t of results) {
358
595
  const node = getTokenType(t.token, t.hint);
@@ -374,11 +611,13 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
374
611
  continue;
375
612
  }
376
613
  loc = location;
377
- // @ts-ignore
378
614
  context.chi.push(tokens[i]);
379
- if (options.sourcemap) {
380
- tokens[i].loc = loc;
381
- }
615
+ stats.nodesCount++;
616
+ Object.defineProperty(tokens[i], 'loc', {
617
+ ...definedPropertySettings,
618
+ value: loc,
619
+ enumerable: options.sourcemap !== false
620
+ });
382
621
  }
383
622
  else if (tokens[i].typ != EnumToken.WhitespaceTokenType) {
384
623
  break;
@@ -408,9 +647,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
408
647
  rawTokens.shift();
409
648
  if (atRule.val == 'import') {
410
649
  // only @charset and @layer are accepted before @import
411
- // @ts-ignore
412
650
  if (context.chi.length > 0) {
413
- // @ts-ignore
414
651
  let i = context.chi.length;
415
652
  while (i--) {
416
653
  // @ts-ignore
@@ -419,11 +656,8 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
419
656
  continue;
420
657
  }
421
658
  if (type != EnumToken.AtRuleNodeType) {
422
- // @ts-ignore
423
659
  if (!(type == EnumToken.InvalidAtRuleTokenType &&
424
- // @ts-ignore
425
660
  ['charset', 'layer', 'import'].includes(context.chi[i].nam))) {
426
- // @ts-ignore
427
661
  errors.push({
428
662
  action: 'drop',
429
663
  message: 'invalid @import',
@@ -434,7 +668,6 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
434
668
  return null;
435
669
  }
436
670
  }
437
- // @ts-ignore
438
671
  const name = context.chi[i].nam;
439
672
  if (name != 'charset' && name != 'import' && name != 'layer') {
440
673
  errors.push({ action: 'drop', message: 'invalid @import', location });
@@ -525,14 +758,14 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
525
758
  }
526
759
  }
527
760
  const t = parseAtRulePrelude(parseTokens(tokens, { minify: options.minify }), atRule);
528
- const raw = t.reduce((acc, curr) => {
529
- acc.push(renderToken(curr, { removeComments: true, convertColor: false }));
530
- return acc;
531
- }, []);
761
+ const raw = [];
762
+ for (const curr of t) {
763
+ raw.push(renderToken(curr, { removeComments: true, convertColor: false }));
764
+ }
532
765
  const nam = renderToken(atRule, { removeComments: true });
533
766
  // @ts-ignore
534
767
  const node = {
535
- typ: /^(-[a-z]+-)?keyframes$/.test(nam) ? EnumToken.KeyframeAtRuleNodeType : EnumToken.AtRuleNodeType,
768
+ typ: /^(-[a-z]+-)?keyframes$/.test(nam) ? EnumToken.KeyframesAtRuleNodeType : EnumToken.AtRuleNodeType,
536
769
  nam,
537
770
  val: raw.join('')
538
771
  };
@@ -544,10 +777,12 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
544
777
  node.chi = [];
545
778
  }
546
779
  loc = map.get(atRule);
547
- if (options.sourcemap) {
548
- node.loc = loc;
549
- node.loc.end = { ...map.get(delim).end };
550
- }
780
+ Object.defineProperty(node, 'loc', {
781
+ ...definedPropertySettings,
782
+ value: loc,
783
+ enumerable: options.sourcemap !== false
784
+ });
785
+ node.loc.end = { ...map.get(delim).end };
551
786
  let isValid = true;
552
787
  if (node.nam == 'else') {
553
788
  const prev = getLastNode(context);
@@ -561,20 +796,31 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
561
796
  }
562
797
  }
563
798
  // @ts-ignore
564
- const valid = options.validation == ValidationLevel.None ? {
799
+ const skipValidate = (options.validation & ValidationLevel.AtRule) == 0;
800
+ const isAllowed = skipValidate || isNodeAllowedInContext(node, context);
801
+ // @ts-ignore
802
+ const valid = skipValidate ? {
565
803
  valid: SyntaxValidationResult.Valid,
566
804
  error: '',
567
805
  node,
568
806
  syntax: '@' + node.nam
569
- } : isValid ? (node.typ == EnumToken.KeyframeAtRuleNodeType ? validateAtRuleKeyframes(node) : validateAtRule(node, options, context)) : {
807
+ } : !isAllowed ? {
808
+ valid: SyntaxValidationResult.Drop,
809
+ node,
810
+ syntax: '@' + node.nam,
811
+ 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)) : {
570
812
  valid: SyntaxValidationResult.Drop,
571
813
  node,
572
814
  syntax: '@' + node.nam,
573
815
  error: '@' + node.nam + ' not allowed here'};
574
816
  if (valid.valid == SyntaxValidationResult.Drop) {
817
+ let message = '';
818
+ for (const token of tokens) {
819
+ message += renderToken(token, { minify: false });
820
+ }
575
821
  errors.push({
576
822
  action: 'drop',
577
- message: valid.error + ' - "' + tokens.reduce((acc, curr) => acc + renderToken(curr, { minify: false }), '') + '"',
823
+ message: valid.error + ' - "' + message + '"',
578
824
  node,
579
825
  // @ts-ignore
580
826
  location: { src, ...(map.get(valid.node) ?? location) }
@@ -583,13 +829,17 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
583
829
  node.typ = EnumToken.InvalidAtRuleTokenType;
584
830
  }
585
831
  else {
586
- node.val = node.tokens.reduce((acc, curr) => acc + renderToken(curr, {
587
- minify: false,
588
- convertColor: false,
589
- removeComments: true
590
- }), '');
832
+ node.val = '';
833
+ for (const token of node.tokens) {
834
+ node.val += renderToken(token, {
835
+ minify: false,
836
+ convertColor: false,
837
+ removeComments: true
838
+ });
839
+ }
591
840
  }
592
841
  context.chi.push(node);
842
+ stats.nodesCount++;
593
843
  Object.defineProperties(node, {
594
844
  parent: { ...definedPropertySettings, value: context },
595
845
  validSyntax: { ...definedPropertySettings, value: valid.valid == SyntaxValidationResult.Valid }
@@ -602,7 +852,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
602
852
  const location = map.get(tokens[0]);
603
853
  const uniq = new Map;
604
854
  parseTokens(tokens, { minify: true });
605
- const ruleType = context.typ == EnumToken.KeyframeAtRuleNodeType ? EnumToken.KeyFrameRuleNodeType : EnumToken.RuleNodeType;
855
+ const ruleType = context.typ == EnumToken.KeyframesAtRuleNodeType ? EnumToken.KeyFramesRuleNodeType : EnumToken.RuleNodeType;
606
856
  if (ruleType == EnumToken.RuleNodeType) {
607
857
  parseSelector(tokens);
608
858
  }
@@ -612,6 +862,34 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
612
862
  if (curr.typ == EnumToken.CommentTokenType) {
613
863
  return acc;
614
864
  }
865
+ if (options.minify) {
866
+ if (curr.typ == EnumToken.PseudoClassFuncTokenType && curr.val == ':nth-child') {
867
+ let i = 0;
868
+ for (; i < curr.chi.length; i++) {
869
+ if (curr.chi[i].typ == EnumToken.IdenTokenType && curr.chi[i].val == 'even') {
870
+ Object.assign(curr.chi[i], {
871
+ typ: EnumToken.Dimension,
872
+ val: 2,
873
+ unit: 'n'
874
+ });
875
+ }
876
+ else if (curr.chi[i].typ == EnumToken.Dimension &&
877
+ curr.chi[i].val == 2 &&
878
+ curr.chi[i].unit == 'n' &&
879
+ curr.chi[i + 1]?.typ == EnumToken.WhitespaceTokenType &&
880
+ curr.chi[i + 2]?.typ == EnumToken.LiteralTokenType &&
881
+ curr.chi[i + 2].val == '+' &&
882
+ curr.chi[i + 3]?.typ == EnumToken.WhitespaceTokenType &&
883
+ curr.chi[i + 4]?.typ == EnumToken.NumberTokenType &&
884
+ curr.chi[i + 4].val == 1) {
885
+ curr.chi.splice(i, 5, Object.assign(curr.chi[i], {
886
+ typ: EnumToken.IdenTokenType,
887
+ val: 'odd'
888
+ }));
889
+ }
890
+ }
891
+ }
892
+ }
615
893
  if (curr.typ == EnumToken.WhitespaceTokenType) {
616
894
  if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
617
895
  trimWhiteSpace.includes(array[index + 1]?.typ) ||
@@ -620,7 +898,7 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
620
898
  return acc;
621
899
  }
622
900
  }
623
- if (ruleType == EnumToken.KeyFrameRuleNodeType) {
901
+ if (ruleType == EnumToken.KeyFramesRuleNodeType && options.minify) {
624
902
  if (curr.typ == EnumToken.IdenTokenType && curr.val == 'from') {
625
903
  Object.assign(curr, { typ: EnumToken.PercentageTokenType, val: '0' });
626
904
  }
@@ -659,17 +937,24 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
659
937
  value: tokens.slice()
660
938
  });
661
939
  loc = location;
662
- if (options.sourcemap) {
663
- node.loc = loc;
664
- }
665
- // @ts-ignore
940
+ Object.defineProperty(node, 'loc', {
941
+ ...definedPropertySettings,
942
+ value: loc,
943
+ enumerable: options.sourcemap !== false
944
+ });
666
945
  context.chi.push(node);
667
946
  Object.defineProperty(node, 'parent', { ...definedPropertySettings, value: context });
668
947
  // @ts-ignore
669
- const valid = options.validation == ValidationLevel.None ? {
948
+ const skipValidate = (options.validation & ValidationLevel.Selector) == 0;
949
+ const isAllowed = skipValidate || isNodeAllowedInContext(node, context);
950
+ // @ts-ignore
951
+ const valid = skipValidate ? {
670
952
  valid: SyntaxValidationResult.Valid,
671
953
  error: null
672
- } : ruleType == EnumToken.KeyFrameRuleNodeType ? validateKeyframeSelector(tokens) : validateSelector(tokens, options, context);
954
+ } : !isAllowed ? {
955
+ valid: SyntaxValidationResult.Drop,
956
+ error: `${EnumToken[context.typ]}: child ${EnumToken[node.typ]} not allowed in context${context.typ == EnumToken.AtRuleNodeType ? ` '@${context.nam}'` : context.typ == EnumToken.StyleSheetNodeType ? ` 'stylesheet'` : ''}`
957
+ } : ruleType == EnumToken.KeyFramesRuleNodeType ? validateKeyframeSelector(tokens) : validateSelector(tokens, options, context);
673
958
  if (valid.valid != SyntaxValidationResult.Valid) {
674
959
  // @ts-ignore
675
960
  node.typ = EnumToken.InvalidRuleTokenType;
@@ -778,11 +1063,13 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
778
1063
  nam,
779
1064
  val: []
780
1065
  };
781
- if (options.sourcemap) {
782
- node.loc = location;
783
- node.loc.end = { ...map.get(delim).end };
784
- }
1066
+ Object.defineProperty(node, 'loc', {
1067
+ ...definedPropertySettings,
1068
+ value: location,
1069
+ enumerable: options.sourcemap !== false
1070
+ });
785
1071
  context.chi.push(node);
1072
+ stats.nodesCount++;
786
1073
  }
787
1074
  return null;
788
1075
  }
@@ -806,22 +1093,31 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
806
1093
  nam,
807
1094
  val: value
808
1095
  };
809
- if (options.sourcemap) {
810
- node.loc = location;
811
- node.loc.end = { ...map.get(delim).end };
812
- }
1096
+ Object.defineProperty(node, 'loc', {
1097
+ ...definedPropertySettings,
1098
+ value: location,
1099
+ enumerable: options.sourcemap !== false
1100
+ });
1101
+ node.loc.end = { ...map.get(delim).end };
813
1102
  // do not allow declarations in style sheets
814
1103
  if (context.typ == EnumToken.StyleSheetNodeType && options.lenient) {
815
- // @ts-ignore
816
- node.typ = EnumToken.InvalidDeclarationNodeType;
1104
+ Object.assign(node, { typ: EnumToken.InvalidDeclarationNodeType });
817
1105
  context.chi.push(node);
1106
+ stats.nodesCount++;
818
1107
  return null;
819
1108
  }
820
1109
  const result = parseDeclarationNode(node, errors, location);
821
1110
  Object.defineProperty(result, 'parent', { ...definedPropertySettings, value: context });
822
1111
  if (result != null) {
823
- if (options.validation == ValidationLevel.All) {
824
- const valid = evaluateSyntax(result, options);
1112
+ if (options.validation & ValidationLevel.Declaration) {
1113
+ const isAllowed = isNodeAllowedInContext(node, context);
1114
+ // @ts-ignore
1115
+ const valid = !isAllowed ? {
1116
+ valid: SyntaxValidationResult.Drop,
1117
+ error: `${EnumToken[node.typ]} not allowed in context${context.typ == EnumToken.AtRuleNodeType ? ` '@${context.nam}'` : context.typ == EnumToken.StyleSheetNodeType ? ` 'stylesheet'` : ''}`,
1118
+ node,
1119
+ syntax: null
1120
+ } : evaluateSyntax(result, context, options);
825
1121
  Object.defineProperty(result, 'validSyntax', {
826
1122
  ...definedPropertySettings,
827
1123
  value: valid.valid == SyntaxValidationResult.Valid
@@ -837,11 +1133,11 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
837
1133
  if (!options.lenient) {
838
1134
  return null;
839
1135
  }
840
- // @ts-ignore
841
- node.typ = EnumToken.InvalidDeclarationNodeType;
1136
+ Object.assign(node, { typ: EnumToken.InvalidDeclarationNodeType });
842
1137
  }
843
1138
  }
844
1139
  context.chi.push(result);
1140
+ stats.nodesCount++;
845
1141
  }
846
1142
  return null;
847
1143
  }
@@ -853,7 +1149,6 @@ function parseNode(results, context, options, errors, src, map, rawTokens) {
853
1149
  * @param atRule
854
1150
  */
855
1151
  function parseAtRulePrelude(tokens, atRule) {
856
- // @ts-ignore
857
1152
  for (const { value, parent } of walkValues(tokens, null, null, true)) {
858
1153
  if (value.typ == EnumToken.CommentTokenType ||
859
1154
  value.typ == EnumToken.WhitespaceTokenType ||
@@ -889,16 +1184,14 @@ function parseAtRulePrelude(tokens, atRule) {
889
1184
  }
890
1185
  if (atRule.val == 'page' && value.typ == EnumToken.PseudoClassTokenType) {
891
1186
  if ([':left', ':right', ':first', ':blank'].includes(value.val)) {
892
- // @ts-ignore
893
- value.typ = EnumToken.PseudoPageTokenType;
1187
+ Object.assign(value, { typ: EnumToken.PseudoPageTokenType });
894
1188
  }
895
1189
  }
896
1190
  if (atRule.val == 'layer') {
897
1191
  if (parent == null && value.typ == EnumToken.LiteralTokenType) {
898
1192
  if (value.val.charAt(0) == '.') {
899
1193
  if (isIdent(value.val.slice(1))) {
900
- // @ts-ignore
901
- value.typ = EnumToken.ClassSelectorTokenType;
1194
+ Object.assign(value, { typ: EnumToken.ClassSelectorTokenType });
902
1195
  }
903
1196
  }
904
1197
  }
@@ -907,8 +1200,7 @@ function parseAtRulePrelude(tokens, atRule) {
907
1200
  if (value.typ == EnumToken.IdenTokenType) {
908
1201
  if (parent == null && mediaTypes.some((t) => {
909
1202
  if (val === t) {
910
- // @ts-ignore
911
- value.typ = EnumToken.MediaFeatureTokenType;
1203
+ Object.assign(value, { typ: EnumToken.MediaFeatureTokenType });
912
1204
  return true;
913
1205
  }
914
1206
  return false;
@@ -916,18 +1208,15 @@ function parseAtRulePrelude(tokens, atRule) {
916
1208
  continue;
917
1209
  }
918
1210
  if (value.typ == EnumToken.IdenTokenType && 'and' === val) {
919
- // @ts-ignore
920
- value.typ = EnumToken.MediaFeatureAndTokenType;
1211
+ Object.assign(value, { typ: EnumToken.MediaFeatureAndTokenType });
921
1212
  continue;
922
1213
  }
923
1214
  if (value.typ == EnumToken.IdenTokenType && 'or' === val) {
924
- // @ts-ignore
925
- value.typ = EnumToken.MediaFeatureOrTokenType;
1215
+ Object.assign(value, { typ: EnumToken.MediaFeatureOrTokenType });
926
1216
  continue;
927
1217
  }
928
1218
  if (value.typ == EnumToken.IdenTokenType &&
929
1219
  ['not', 'only'].some((t) => val === t)) {
930
- // @ts-ignore
931
1220
  const array = parent?.chi ?? tokens;
932
1221
  const startIndex = array.indexOf(value);
933
1222
  let index = startIndex + 1;
@@ -972,12 +1261,15 @@ function parseAtRulePrelude(tokens, atRule) {
972
1261
  if (value.chi[i].typ == EnumToken.CommentTokenType || value.chi[i].typ == EnumToken.WhitespaceTokenType) {
973
1262
  continue;
974
1263
  }
975
- if (value.chi[i].typ == EnumToken.LiteralTokenType && value.chi[i].val.startsWith(':') && isDimension(value.chi[i].val.slice(1))) {
976
- value.chi.splice(i, 1, {
977
- typ: EnumToken.ColonTokenType,
978
- }, Object.assign(value.chi[i], parseDimension(value.chi[i].val.slice(1))));
979
- i--;
980
- continue;
1264
+ if (value.chi[i].typ == EnumToken.LiteralTokenType && value.chi[i].val.startsWith(':')) {
1265
+ const dimension = parseDimension(value.chi[i].val.slice(1));
1266
+ if (dimension != null) {
1267
+ value.chi.splice(i, 1, {
1268
+ typ: EnumToken.ColonTokenType,
1269
+ }, Object.assign(value.chi[i], dimension));
1270
+ i--;
1271
+ continue;
1272
+ }
981
1273
  }
982
1274
  if (nameIndex != -1 && value.chi[i].typ == EnumToken.PseudoClassTokenType) {
983
1275
  value.chi.splice(i, 1, {
@@ -1004,11 +1296,10 @@ function parseAtRulePrelude(tokens, atRule) {
1004
1296
  const val = value.chi.splice(valueIndex, 1)[0];
1005
1297
  const node = value.chi.splice(nameIndex, 1)[0];
1006
1298
  // 'background'
1007
- // @ts-ignore
1008
1299
  if (node.typ == EnumToken.ColorTokenType && node.kin == ColorType.DPSYS) {
1300
+ Object.assign(node, { typ: EnumToken.IdenTokenType });
1009
1301
  // @ts-ignore
1010
1302
  delete node.kin;
1011
- node.typ = EnumToken.IdenTokenType;
1012
1303
  }
1013
1304
  while (value.chi[0]?.typ == EnumToken.WhitespaceTokenType) {
1014
1305
  value.chi.shift();
@@ -1045,7 +1336,7 @@ async function parseDeclarations(declaration) {
1045
1336
  position: { ind: 0, lin: 1, col: 1 },
1046
1337
  currentPosition: { ind: -1, lin: 1, col: 0 }
1047
1338
  }), { setParent: false, minify: false, validation: false }).then(result => {
1048
- return result.ast.chi[0].chi.filter(t => t.typ == EnumToken.DeclarationNodeType);
1339
+ return result.ast.chi[0].chi.filter(t => t.typ == EnumToken.DeclarationNodeType || t.typ == EnumToken.CommentNodeType);
1049
1340
  });
1050
1341
  }
1051
1342
  /**
@@ -1063,43 +1354,35 @@ function parseSelector(tokens) {
1063
1354
  }
1064
1355
  if (parent == null) {
1065
1356
  if (value.typ == EnumToken.GtTokenType) {
1066
- // @ts-ignore
1067
- value.typ = EnumToken.ChildCombinatorTokenType;
1357
+ Object.assign(value, { typ: EnumToken.ChildCombinatorTokenType });
1068
1358
  }
1069
1359
  else if (value.typ == EnumToken.LiteralTokenType) {
1070
1360
  if (value.val.charAt(0) == '&') {
1071
- // @ts-ignore
1072
- value.typ = EnumToken.NestingSelectorTokenType;
1361
+ Object.assign(value, { typ: EnumToken.NestingSelectorTokenType });
1073
1362
  // @ts-ignore
1074
1363
  delete value.val;
1075
1364
  }
1076
1365
  else if (value.val.charAt(0) == '.') {
1077
1366
  if (!isIdent(value.val.slice(1))) {
1078
- // @ts-ignore
1079
- value.typ = EnumToken.InvalidClassSelectorTokenType;
1367
+ Object.assign(value, { typ: EnumToken.InvalidClassSelectorTokenType });
1080
1368
  }
1081
1369
  else {
1082
- // @ts-ignore
1083
- value.typ = EnumToken.ClassSelectorTokenType;
1370
+ Object.assign(value, { typ: EnumToken.ClassSelectorTokenType });
1084
1371
  }
1085
1372
  }
1086
1373
  if (['*', '>', '+', '~'].includes(value.val)) {
1087
1374
  switch (value.val) {
1088
1375
  case '*':
1089
- // @ts-ignore
1090
- value.typ = EnumToken.UniversalSelectorTokenType;
1376
+ Object.assign(value, { typ: EnumToken.UniversalSelectorTokenType });
1091
1377
  break;
1092
1378
  case '>':
1093
- // @ts-ignore
1094
- value.typ = EnumToken.ChildCombinatorTokenType;
1379
+ Object.assign(value, { typ: EnumToken.ChildCombinatorTokenType });
1095
1380
  break;
1096
1381
  case '+':
1097
- // @ts-ignore
1098
- value.typ = EnumToken.NextSiblingCombinatorTokenType;
1382
+ Object.assign(value, { typ: EnumToken.NextSiblingCombinatorTokenType });
1099
1383
  break;
1100
1384
  case '~':
1101
- // @ts-ignore
1102
- value.typ = EnumToken.SubsequentSiblingCombinatorTokenType;
1385
+ Object.assign(value, { typ: EnumToken.SubsequentSiblingCombinatorTokenType });
1103
1386
  break;
1104
1387
  }
1105
1388
  // @ts-ignore
@@ -1112,12 +1395,10 @@ function parseSelector(tokens) {
1112
1395
  if (!isIdent(value.val.slice(1))) {
1113
1396
  continue;
1114
1397
  }
1115
- // @ts-ignore
1116
- value.typ = EnumToken.HashTokenType;
1398
+ Object.assign(value, { typ: EnumToken.HashTokenType });
1117
1399
  }
1118
1400
  else {
1119
- // @ts-ignore
1120
- value.typ = EnumToken.IdenTokenType;
1401
+ Object.assign(value, { typ: EnumToken.IdenTokenType });
1121
1402
  }
1122
1403
  // @ts-ignore
1123
1404
  delete value.kin;
@@ -1180,15 +1461,17 @@ function parseString(src, options = { location: false }) {
1180
1461
  return acc;
1181
1462
  }
1182
1463
  const token = getTokenType(t.token, t.hint);
1183
- if (options.location) {
1184
- Object.assign(token, { loc: t.sta });
1185
- }
1464
+ Object.defineProperty(token, 'loc', {
1465
+ ...definedPropertySettings,
1466
+ value: { sta: t.sta },
1467
+ enumerable: options.location !== false
1468
+ });
1186
1469
  acc.push(token);
1187
1470
  return acc;
1188
1471
  }, []));
1189
1472
  }
1190
1473
  /**
1191
- * get token type from a string
1474
+ * get the token type from a string
1192
1475
  * @param val
1193
1476
  * @param hint
1194
1477
  */
@@ -1224,7 +1507,7 @@ function getTokenType(val, hint) {
1224
1507
  case '>':
1225
1508
  return { typ: EnumToken.GtTokenType };
1226
1509
  }
1227
- if (isPseudo(val)) {
1510
+ if (val.charAt(0) == ':' && isPseudo(val)) {
1228
1511
  return val.endsWith('(') ? {
1229
1512
  typ: EnumToken.PseudoClassFuncTokenType,
1230
1513
  val: val.slice(0, -1),
@@ -1241,13 +1524,13 @@ function getTokenType(val, hint) {
1241
1524
  val
1242
1525
  });
1243
1526
  }
1244
- if (isAtKeyword(val)) {
1527
+ if (val.charAt(0) == '@' && isAtKeyword(val)) {
1245
1528
  return {
1246
1529
  typ: EnumToken.AtRuleTokenType,
1247
1530
  val: val.slice(1)
1248
1531
  };
1249
1532
  }
1250
- if (isFunction(val)) {
1533
+ if (val.endsWith('(') && isFunction(val)) {
1251
1534
  val = val.slice(0, -1);
1252
1535
  if (val == 'url') {
1253
1536
  return {
@@ -1295,15 +1578,12 @@ function getTokenType(val, hint) {
1295
1578
  val: +val.slice(0, -1)
1296
1579
  };
1297
1580
  }
1298
- if (isFlex(val)) {
1299
- return {
1300
- typ: EnumToken.FlexTokenType,
1301
- val: +val.slice(0, -2)
1302
- };
1303
- }
1304
- if (isDimension(val)) {
1305
- return parseDimension(val);
1581
+ // if (isDimension(val)) {
1582
+ const dimension = parseDimension(val);
1583
+ if (dimension != null) {
1584
+ return dimension;
1306
1585
  }
1586
+ // }
1307
1587
  const v = val.toLowerCase();
1308
1588
  if (v == 'currentcolor' || v == 'transparent' || v in COLORS_NAMES) {
1309
1589
  return {
@@ -1662,4 +1942,4 @@ function parseTokens(tokens, options = {}) {
1662
1942
  return tokens;
1663
1943
  }
1664
1944
 
1665
- export { doParse, getTokenType, parseAtRulePrelude, parseDeclarations, parseSelector, parseString, parseTokens, urlTokenMatcher };
1945
+ export { doParse, getTokenType, parseAtRulePrelude, parseDeclarations, parseSelector, parseString, parseTokens, replaceToken, urlTokenMatcher };