@tbela99/css-parser 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![npm](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Ftbela99%2Fcss-parser%2Fmaster%2Fpackage.json&query=version&logo=npm&label=npm&link=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2F%40tbela99%2Fcss-parser)](https://www.npmjs.com/package/@tbela99/css-parser) [![cov](https://tbela99.github.io/css-parser/badges/coverage.svg)](https://github.com/tbela99/css-parser/actions) [![NPM Downloads](https://img.shields.io/npm/dy/%40tbela99%2Fcss-parser)](https://www.npmjs.com/package/@tbela99/css-parser)
1
+ [![npm](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Ftbela99%2Fcss-parser%2Fmaster%2Fpackage.json&query=version&logo=npm&label=npm&link=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2F%40tbela99%2Fcss-parser)](https://www.npmjs.com/package/@tbela99/css-parser) [![cov](https://tbela99.github.io/css-parser/badges/coverage.svg)](https://github.com/tbela99/css-parser/actions) [![NPM Downloads](https://img.shields.io/npm/dm/%40tbela99%2Fcss-parser)](https://www.npmjs.com/package/@tbela99/css-parser)
2
2
 
3
3
  # css-parser
4
4
 
@@ -497,30 +497,36 @@ for (const {node, parent, root} of walk(ast)) {
497
497
 
498
498
  ### Comment
499
499
 
500
- - typ: string 'Comment'
500
+ - typ: number
501
501
  - val: string, the comment
502
502
 
503
503
  ### Declaration
504
504
 
505
- - typ: string 'Declaration'
505
+ - typ: number
506
506
  - nam: string, declaration name
507
507
  - val: array of tokens
508
508
 
509
509
  ### Rule
510
510
 
511
- - typ: string 'Rule'
511
+ - typ: number
512
512
  - sel: string, css selector
513
513
  - chi: array of children
514
514
 
515
515
  ### AtRule
516
516
 
517
- - typ: string 'AtRule'
517
+ - typ: number
518
518
  - nam: string. AtRule name
519
519
  - val: rule prelude
520
520
 
521
521
  ### AtRuleStyleSheet
522
522
 
523
- - typ: string 'Stylesheet'
523
+ - typ: number
524
+ - chi: array of children
525
+
526
+ ### KeyFrameRule
527
+
528
+ - typ: number
529
+ - sel: string, css selector
524
530
  - chi: array of children
525
531
 
526
532
  ## Sourcemap
@@ -81,6 +81,7 @@
81
81
  EnumToken[EnumToken["FractionTokenType"] = 69] = "FractionTokenType";
82
82
  EnumToken[EnumToken["IdenListTokenType"] = 70] = "IdenListTokenType";
83
83
  EnumToken[EnumToken["GridTemplateFuncTokenType"] = 71] = "GridTemplateFuncTokenType";
84
+ EnumToken[EnumToken["KeyFrameRuleNodeType"] = 72] = "KeyFrameRuleNodeType";
84
85
  /* aliases */
85
86
  EnumToken[EnumToken["Time"] = 25] = "Time";
86
87
  EnumToken[EnumToken["Iden"] = 7] = "Iden";
@@ -2510,7 +2511,15 @@
2510
2511
  * @param tokens
2511
2512
  */
2512
2513
  function evaluate(tokens) {
2513
- const nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
2514
+ let nodes;
2515
+ try {
2516
+ nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
2517
+ }
2518
+ catch (e) {
2519
+ // console.error({tokens});
2520
+ // console.error(e);
2521
+ return tokens;
2522
+ }
2514
2523
  if (nodes.length <= 1) {
2515
2524
  return nodes;
2516
2525
  }
@@ -3036,7 +3045,7 @@
3036
3045
  return result;
3037
3046
  }
3038
3047
  function updateSourceMap(node, options, cache, sourcemap, position, str) {
3039
- if ([exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType].includes(node.typ)) {
3048
+ if ([exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType, exports.EnumToken.KeyFrameRuleNodeType].includes(node.typ)) {
3040
3049
  let src = node.loc?.src ?? '';
3041
3050
  let output = options.output ?? '';
3042
3051
  if (!(src in cache)) {
@@ -3096,6 +3105,7 @@
3096
3105
  }, '');
3097
3106
  case exports.EnumToken.AtRuleNodeType:
3098
3107
  case exports.EnumToken.RuleNodeType:
3108
+ case exports.EnumToken.KeyFrameRuleNodeType:
3099
3109
  if (data.typ == exports.EnumToken.AtRuleNodeType && !('chi' in data)) {
3100
3110
  return `${indent}@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val};`;
3101
3111
  }
@@ -6371,12 +6381,16 @@
6371
6381
  }
6372
6382
  if (atRule.val == 'import') {
6373
6383
  // @ts-ignore
6374
- if (tokens[0].typ == exports.EnumToken.UrlFunctionTokenType && tokens[1].typ == exports.EnumToken.UrlTokenTokenType) {
6375
- tokens.shift();
6376
- // @ts-ignore
6377
- tokens[0].typ = exports.EnumToken.StringTokenType;
6378
- // @ts-ignore
6379
- tokens[0].val = `"${tokens[0].val}"`;
6384
+ if (tokens[0].typ == exports.EnumToken.UrlFunctionTokenType) {
6385
+ if (tokens[1].typ == exports.EnumToken.UrlTokenTokenType || tokens[1].typ == exports.EnumToken.StringTokenType) {
6386
+ tokens.shift();
6387
+ if (tokens[1].typ == exports.EnumToken.UrlTokenTokenType) {
6388
+ // @ts-ignore
6389
+ tokens[0].typ = exports.EnumToken.StringTokenType;
6390
+ // @ts-ignore
6391
+ tokens[0].val = `"${tokens[0].val}"`;
6392
+ }
6393
+ }
6380
6394
  }
6381
6395
  // @ts-ignore
6382
6396
  if (tokens[0].typ == exports.EnumToken.StringTokenType) {
@@ -6442,6 +6456,9 @@
6442
6456
  const position = map.get(tokens[0]);
6443
6457
  const uniq = new Map;
6444
6458
  parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
6459
+ if (curr.typ == exports.EnumToken.CommentTokenType) {
6460
+ return acc;
6461
+ }
6445
6462
  if (curr.typ == exports.EnumToken.WhitespaceTokenType) {
6446
6463
  if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
6447
6464
  trimWhiteSpace.includes(array[index + 1]?.typ) ||
@@ -6463,7 +6480,7 @@
6463
6480
  return acc;
6464
6481
  }, uniq);
6465
6482
  const node = {
6466
- typ: exports.EnumToken.RuleNodeType,
6483
+ typ: context.typ == exports.EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? exports.EnumToken.KeyFrameRuleNodeType : exports.EnumToken.RuleNodeType,
6467
6484
  // @ts-ignore
6468
6485
  sel: [...uniq.keys()].join(','),
6469
6486
  chi: []
@@ -8402,7 +8419,7 @@
8402
8419
  const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering);
8403
8420
  function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) {
8404
8421
  if (!('nodes' in context)) {
8405
- context.nodes = new WeakSet;
8422
+ context.nodes = new Set;
8406
8423
  }
8407
8424
  if (context.nodes.has(ast)) {
8408
8425
  return ast;
@@ -8431,7 +8448,7 @@
8431
8448
  curr.splice(0, 2);
8432
8449
  }
8433
8450
  else if (combinators.includes(curr[1])) {
8434
- curr.splice(0, 1);
8451
+ curr.shift();
8435
8452
  }
8436
8453
  }
8437
8454
  else if (ast.typ == exports.EnumToken.RuleNodeType && (isIdent(curr[0]) || isFunction(curr[0]))) {
@@ -8633,7 +8650,7 @@
8633
8650
  }
8634
8651
  if (shouldMerge) {
8635
8652
  // @ts-ignore
8636
- if ((node.typ == exports.EnumToken.RuleNodeType && node.sel == previous.sel) ||
8653
+ if (((node.typ == exports.EnumToken.RuleNodeType || node.typ == exports.EnumToken.KeyFrameRuleNodeType) && node.sel == previous.sel) ||
8637
8654
  // @ts-ignore
8638
8655
  (node.typ == exports.EnumToken.AtRuleNodeType) && node.val != 'font-face' && node.val == previous.val) {
8639
8656
  // @ts-ignore
@@ -8652,32 +8669,33 @@
8652
8669
  nodeIndex = i;
8653
8670
  continue;
8654
8671
  }
8655
- else if (node.typ == exports.EnumToken.RuleNodeType && previous?.typ == exports.EnumToken.RuleNodeType) {
8672
+ else if (node.typ == previous?.typ && [exports.EnumToken.KeyFrameRuleNodeType, exports.EnumToken.RuleNodeType].includes(node.typ)) {
8656
8673
  const intersect = diff(previous, node, reducer, options);
8657
8674
  if (intersect != null) {
8658
8675
  if (intersect.node1.chi.length == 0) {
8659
8676
  // @ts-ignore
8660
8677
  ast.chi.splice(i--, 1);
8661
8678
  // @ts-ignore
8662
- node = ast.chi[i];
8679
+ // node = ast.chi[i];
8663
8680
  }
8664
8681
  else {
8665
8682
  // @ts-ignore
8666
8683
  ast.chi.splice(i, 1, intersect.node1);
8667
- node = intersect.node1;
8684
+ // node = ast.chi intersect.node1;
8668
8685
  }
8669
8686
  if (intersect.node2.chi.length == 0) {
8670
8687
  // @ts-ignore
8671
8688
  ast.chi.splice(nodeIndex, 1, intersect.result);
8672
- previous = intersect.result;
8673
8689
  }
8674
8690
  else {
8675
8691
  // @ts-ignore
8676
8692
  ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2);
8677
- previous = intersect.result;
8678
8693
  // @ts-ignore
8679
- i = nodeIndex;
8694
+ i = (nodeIndex ?? 0) + 1;
8680
8695
  }
8696
+ reduceRuleSelector(intersect.result);
8697
+ previous = intersect.result;
8698
+ nodeIndex = i;
8681
8699
  }
8682
8700
  }
8683
8701
  }
@@ -8807,11 +8825,16 @@
8807
8825
  // combinator
8808
8826
  if (combinators.includes(optimized.at(-1))) {
8809
8827
  const combinator = optimized.pop();
8810
- selector.forEach(selector => selector.unshift(combinator));
8828
+ selector.forEach((selector) => selector.unshift(combinator));
8811
8829
  }
8812
8830
  let reducible = optimized.length == 1;
8813
- if (optimized[0] == '&' && optimized[1] == ' ') {
8814
- optimized.splice(0, 2);
8831
+ if (optimized[0] == '&') {
8832
+ if (optimized[1] == ' ') {
8833
+ optimized.splice(0, 2);
8834
+ }
8835
+ // else if (combinators.includes(optimized[1])) {
8836
+ //
8837
+ // }
8815
8838
  }
8816
8839
  if (optimized.length == 0 ||
8817
8840
  (optimized[0].charAt(0) == '&' ||
@@ -8819,7 +8842,7 @@
8819
8842
  return {
8820
8843
  match: false,
8821
8844
  optimized,
8822
- selector: selector.map(selector => selector[0] == '&' && selector[1] == ' ' ? selector.slice(2) : selector),
8845
+ selector: selector.map((selector) => selector[0] == '&' && selector[1] == ' ' ? selector.slice(2) : (selector)),
8823
8846
  reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0]))
8824
8847
  };
8825
8848
  }
@@ -8899,6 +8922,18 @@
8899
8922
  result.push([]);
8900
8923
  continue;
8901
8924
  }
8925
+ if (chr == ':') {
8926
+ if (str !== '') {
8927
+ // @ts-ignore
8928
+ result.at(-1).push(str);
8929
+ str = '';
8930
+ }
8931
+ if (buffer.charAt(i + 1) == ':') {
8932
+ chr += buffer.charAt(++i);
8933
+ }
8934
+ str += chr;
8935
+ continue;
8936
+ }
8902
8937
  str += chr;
8903
8938
  if (chr == '\\') {
8904
8939
  str += buffer.charAt(++i);
@@ -9200,6 +9235,52 @@
9200
9235
  const raw1 = node1.raw;
9201
9236
  // @ts-ignore
9202
9237
  const raw2 = node2.raw;
9238
+ if (raw1 != null && raw2 != null) {
9239
+ const prefixes1 = new Set;
9240
+ const prefixes2 = new Set;
9241
+ for (const token1 of raw1) {
9242
+ for (const t of token1) {
9243
+ if (t[0] == ':') {
9244
+ const matches = t.match(/::?-([a-z]+)-/);
9245
+ if (matches == null) {
9246
+ continue;
9247
+ }
9248
+ prefixes1.add(matches[1]);
9249
+ if (prefixes1.size > 1) {
9250
+ break;
9251
+ }
9252
+ }
9253
+ }
9254
+ if (prefixes1.size > 1) {
9255
+ break;
9256
+ }
9257
+ }
9258
+ for (const token2 of raw2) {
9259
+ for (const t of token2) {
9260
+ if (t[0] == ':') {
9261
+ const matches = t.match(/::?-([a-z]+)-/);
9262
+ if (matches == null) {
9263
+ continue;
9264
+ }
9265
+ prefixes2.add(matches[1]);
9266
+ if (prefixes2.size > 1) {
9267
+ break;
9268
+ }
9269
+ }
9270
+ }
9271
+ if (prefixes2.size > 1) {
9272
+ break;
9273
+ }
9274
+ }
9275
+ if (prefixes1.size != prefixes2.size) {
9276
+ return null;
9277
+ }
9278
+ for (const prefix of prefixes1) {
9279
+ if (!prefixes2.has(prefix)) {
9280
+ return null;
9281
+ }
9282
+ }
9283
+ }
9203
9284
  // @ts-ignore
9204
9285
  node1 = { ...node1, chi: node1.chi.slice() };
9205
9286
  node2 = { ...node2, chi: node2.chi.slice() };
@@ -9236,7 +9317,7 @@
9236
9317
  const result = (intersect.length == 0 ? null : {
9237
9318
  ...node1,
9238
9319
  // @ts-ignore
9239
- sel: [...new Set([...(n1?.raw?.reduce(reducer, []) || splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) || splitRule(n2.sel))])].join(','),
9320
+ sel: [...new Set([...(n1?.raw?.reduce(reducer, []) ?? splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) ?? splitRule(n2.sel))])].join(','),
9240
9321
  chi: intersect.reverse()
9241
9322
  });
9242
9323
  if (result == null || [n1, n2].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + doRender(curr, options).code.length, 0) <= [node1, node2, result].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + doRender(curr, options).code.length, 0)) {
@@ -9260,6 +9341,11 @@
9260
9341
  Object.defineProperty(node, 'optimized', { ...definedPropertySettings, value: optimized });
9261
9342
  }
9262
9343
  if (optimized != null && optimized.match && optimized.reducible && optimized.selector.length > 1) {
9344
+ for (const selector of optimized.selector) {
9345
+ if (selector.length > 1 && selector[0] == '&' && combinators.includes(selector[1])) {
9346
+ selector.shift();
9347
+ }
9348
+ }
9263
9349
  const raw = [
9264
9350
  [
9265
9351
  optimized.optimized[0], ':is('
@@ -9387,16 +9473,18 @@
9387
9473
  return response.text();
9388
9474
  }
9389
9475
  async function load(url, currentFile) {
9476
+ let t;
9390
9477
  if (matchUrl.test(url)) {
9391
- return fetch(url).then(parseResponse);
9478
+ t = new URL(url);
9479
+ }
9480
+ else if (matchUrl.test(currentFile)) {
9481
+ t = new URL(url, currentFile);
9392
9482
  }
9393
- if (matchUrl.test(currentFile)) {
9394
- return fetch(new URL(url, currentFile)).then(parseResponse);
9483
+ else {
9484
+ const path = resolve(url, currentFile).absolute;
9485
+ t = new URL(path, self.origin);
9395
9486
  }
9396
- const path = resolve(url, currentFile).absolute;
9397
- const t = new URL(path, self.origin);
9398
- // return fetch(new URL(url, new URL(currentFile, self.location.href).href)).then(parseResponse);
9399
- return fetch(url, t.origin != self.location.origin ? { mode: 'cors' } : {}).then(parseResponse);
9487
+ return fetch(t, t.origin != self.origin ? { mode: 'cors' } : {}).then(parseResponse);
9400
9488
  }
9401
9489
 
9402
9490
  function render(data, options = {}) {
package/dist/index.cjs CHANGED
@@ -79,6 +79,7 @@ exports.EnumToken = void 0;
79
79
  EnumToken[EnumToken["FractionTokenType"] = 69] = "FractionTokenType";
80
80
  EnumToken[EnumToken["IdenListTokenType"] = 70] = "IdenListTokenType";
81
81
  EnumToken[EnumToken["GridTemplateFuncTokenType"] = 71] = "GridTemplateFuncTokenType";
82
+ EnumToken[EnumToken["KeyFrameRuleNodeType"] = 72] = "KeyFrameRuleNodeType";
82
83
  /* aliases */
83
84
  EnumToken[EnumToken["Time"] = 25] = "Time";
84
85
  EnumToken[EnumToken["Iden"] = 7] = "Iden";
@@ -2508,7 +2509,15 @@ function simplify(a, b) {
2508
2509
  * @param tokens
2509
2510
  */
2510
2511
  function evaluate(tokens) {
2511
- const nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
2512
+ let nodes;
2513
+ try {
2514
+ nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
2515
+ }
2516
+ catch (e) {
2517
+ // console.error({tokens});
2518
+ // console.error(e);
2519
+ return tokens;
2520
+ }
2512
2521
  if (nodes.length <= 1) {
2513
2522
  return nodes;
2514
2523
  }
@@ -3034,7 +3043,7 @@ function doRender(data, options = {}) {
3034
3043
  return result;
3035
3044
  }
3036
3045
  function updateSourceMap(node, options, cache, sourcemap, position, str) {
3037
- if ([exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType].includes(node.typ)) {
3046
+ if ([exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType, exports.EnumToken.KeyFrameRuleNodeType].includes(node.typ)) {
3038
3047
  let src = node.loc?.src ?? '';
3039
3048
  let output = options.output ?? '';
3040
3049
  if (!(src in cache)) {
@@ -3094,6 +3103,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
3094
3103
  }, '');
3095
3104
  case exports.EnumToken.AtRuleNodeType:
3096
3105
  case exports.EnumToken.RuleNodeType:
3106
+ case exports.EnumToken.KeyFrameRuleNodeType:
3097
3107
  if (data.typ == exports.EnumToken.AtRuleNodeType && !('chi' in data)) {
3098
3108
  return `${indent}@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val};`;
3099
3109
  }
@@ -6369,12 +6379,16 @@ async function parseNode(results, context, stats, options, errors, src, map) {
6369
6379
  }
6370
6380
  if (atRule.val == 'import') {
6371
6381
  // @ts-ignore
6372
- if (tokens[0].typ == exports.EnumToken.UrlFunctionTokenType && tokens[1].typ == exports.EnumToken.UrlTokenTokenType) {
6373
- tokens.shift();
6374
- // @ts-ignore
6375
- tokens[0].typ = exports.EnumToken.StringTokenType;
6376
- // @ts-ignore
6377
- tokens[0].val = `"${tokens[0].val}"`;
6382
+ if (tokens[0].typ == exports.EnumToken.UrlFunctionTokenType) {
6383
+ if (tokens[1].typ == exports.EnumToken.UrlTokenTokenType || tokens[1].typ == exports.EnumToken.StringTokenType) {
6384
+ tokens.shift();
6385
+ if (tokens[1].typ == exports.EnumToken.UrlTokenTokenType) {
6386
+ // @ts-ignore
6387
+ tokens[0].typ = exports.EnumToken.StringTokenType;
6388
+ // @ts-ignore
6389
+ tokens[0].val = `"${tokens[0].val}"`;
6390
+ }
6391
+ }
6378
6392
  }
6379
6393
  // @ts-ignore
6380
6394
  if (tokens[0].typ == exports.EnumToken.StringTokenType) {
@@ -6440,6 +6454,9 @@ async function parseNode(results, context, stats, options, errors, src, map) {
6440
6454
  const position = map.get(tokens[0]);
6441
6455
  const uniq = new Map;
6442
6456
  parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
6457
+ if (curr.typ == exports.EnumToken.CommentTokenType) {
6458
+ return acc;
6459
+ }
6443
6460
  if (curr.typ == exports.EnumToken.WhitespaceTokenType) {
6444
6461
  if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
6445
6462
  trimWhiteSpace.includes(array[index + 1]?.typ) ||
@@ -6461,7 +6478,7 @@ async function parseNode(results, context, stats, options, errors, src, map) {
6461
6478
  return acc;
6462
6479
  }, uniq);
6463
6480
  const node = {
6464
- typ: exports.EnumToken.RuleNodeType,
6481
+ typ: context.typ == exports.EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? exports.EnumToken.KeyFrameRuleNodeType : exports.EnumToken.RuleNodeType,
6465
6482
  // @ts-ignore
6466
6483
  sel: [...uniq.keys()].join(','),
6467
6484
  chi: []
@@ -8400,7 +8417,7 @@ const notEndingWith = ['(', '['].concat(combinators);
8400
8417
  const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering);
8401
8418
  function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) {
8402
8419
  if (!('nodes' in context)) {
8403
- context.nodes = new WeakSet;
8420
+ context.nodes = new Set;
8404
8421
  }
8405
8422
  if (context.nodes.has(ast)) {
8406
8423
  return ast;
@@ -8429,7 +8446,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
8429
8446
  curr.splice(0, 2);
8430
8447
  }
8431
8448
  else if (combinators.includes(curr[1])) {
8432
- curr.splice(0, 1);
8449
+ curr.shift();
8433
8450
  }
8434
8451
  }
8435
8452
  else if (ast.typ == exports.EnumToken.RuleNodeType && (isIdent(curr[0]) || isFunction(curr[0]))) {
@@ -8631,7 +8648,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
8631
8648
  }
8632
8649
  if (shouldMerge) {
8633
8650
  // @ts-ignore
8634
- if ((node.typ == exports.EnumToken.RuleNodeType && node.sel == previous.sel) ||
8651
+ if (((node.typ == exports.EnumToken.RuleNodeType || node.typ == exports.EnumToken.KeyFrameRuleNodeType) && node.sel == previous.sel) ||
8635
8652
  // @ts-ignore
8636
8653
  (node.typ == exports.EnumToken.AtRuleNodeType) && node.val != 'font-face' && node.val == previous.val) {
8637
8654
  // @ts-ignore
@@ -8650,32 +8667,33 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
8650
8667
  nodeIndex = i;
8651
8668
  continue;
8652
8669
  }
8653
- else if (node.typ == exports.EnumToken.RuleNodeType && previous?.typ == exports.EnumToken.RuleNodeType) {
8670
+ else if (node.typ == previous?.typ && [exports.EnumToken.KeyFrameRuleNodeType, exports.EnumToken.RuleNodeType].includes(node.typ)) {
8654
8671
  const intersect = diff(previous, node, reducer, options);
8655
8672
  if (intersect != null) {
8656
8673
  if (intersect.node1.chi.length == 0) {
8657
8674
  // @ts-ignore
8658
8675
  ast.chi.splice(i--, 1);
8659
8676
  // @ts-ignore
8660
- node = ast.chi[i];
8677
+ // node = ast.chi[i];
8661
8678
  }
8662
8679
  else {
8663
8680
  // @ts-ignore
8664
8681
  ast.chi.splice(i, 1, intersect.node1);
8665
- node = intersect.node1;
8682
+ // node = ast.chi intersect.node1;
8666
8683
  }
8667
8684
  if (intersect.node2.chi.length == 0) {
8668
8685
  // @ts-ignore
8669
8686
  ast.chi.splice(nodeIndex, 1, intersect.result);
8670
- previous = intersect.result;
8671
8687
  }
8672
8688
  else {
8673
8689
  // @ts-ignore
8674
8690
  ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2);
8675
- previous = intersect.result;
8676
8691
  // @ts-ignore
8677
- i = nodeIndex;
8692
+ i = (nodeIndex ?? 0) + 1;
8678
8693
  }
8694
+ reduceRuleSelector(intersect.result);
8695
+ previous = intersect.result;
8696
+ nodeIndex = i;
8679
8697
  }
8680
8698
  }
8681
8699
  }
@@ -8805,11 +8823,16 @@ function reduceSelector(selector) {
8805
8823
  // combinator
8806
8824
  if (combinators.includes(optimized.at(-1))) {
8807
8825
  const combinator = optimized.pop();
8808
- selector.forEach(selector => selector.unshift(combinator));
8826
+ selector.forEach((selector) => selector.unshift(combinator));
8809
8827
  }
8810
8828
  let reducible = optimized.length == 1;
8811
- if (optimized[0] == '&' && optimized[1] == ' ') {
8812
- optimized.splice(0, 2);
8829
+ if (optimized[0] == '&') {
8830
+ if (optimized[1] == ' ') {
8831
+ optimized.splice(0, 2);
8832
+ }
8833
+ // else if (combinators.includes(optimized[1])) {
8834
+ //
8835
+ // }
8813
8836
  }
8814
8837
  if (optimized.length == 0 ||
8815
8838
  (optimized[0].charAt(0) == '&' ||
@@ -8817,7 +8840,7 @@ function reduceSelector(selector) {
8817
8840
  return {
8818
8841
  match: false,
8819
8842
  optimized,
8820
- selector: selector.map(selector => selector[0] == '&' && selector[1] == ' ' ? selector.slice(2) : selector),
8843
+ selector: selector.map((selector) => selector[0] == '&' && selector[1] == ' ' ? selector.slice(2) : (selector)),
8821
8844
  reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0]))
8822
8845
  };
8823
8846
  }
@@ -8897,6 +8920,18 @@ function splitRule(buffer) {
8897
8920
  result.push([]);
8898
8921
  continue;
8899
8922
  }
8923
+ if (chr == ':') {
8924
+ if (str !== '') {
8925
+ // @ts-ignore
8926
+ result.at(-1).push(str);
8927
+ str = '';
8928
+ }
8929
+ if (buffer.charAt(i + 1) == ':') {
8930
+ chr += buffer.charAt(++i);
8931
+ }
8932
+ str += chr;
8933
+ continue;
8934
+ }
8900
8935
  str += chr;
8901
8936
  if (chr == '\\') {
8902
8937
  str += buffer.charAt(++i);
@@ -9198,6 +9233,52 @@ function diff(n1, n2, reducer, options = {}) {
9198
9233
  const raw1 = node1.raw;
9199
9234
  // @ts-ignore
9200
9235
  const raw2 = node2.raw;
9236
+ if (raw1 != null && raw2 != null) {
9237
+ const prefixes1 = new Set;
9238
+ const prefixes2 = new Set;
9239
+ for (const token1 of raw1) {
9240
+ for (const t of token1) {
9241
+ if (t[0] == ':') {
9242
+ const matches = t.match(/::?-([a-z]+)-/);
9243
+ if (matches == null) {
9244
+ continue;
9245
+ }
9246
+ prefixes1.add(matches[1]);
9247
+ if (prefixes1.size > 1) {
9248
+ break;
9249
+ }
9250
+ }
9251
+ }
9252
+ if (prefixes1.size > 1) {
9253
+ break;
9254
+ }
9255
+ }
9256
+ for (const token2 of raw2) {
9257
+ for (const t of token2) {
9258
+ if (t[0] == ':') {
9259
+ const matches = t.match(/::?-([a-z]+)-/);
9260
+ if (matches == null) {
9261
+ continue;
9262
+ }
9263
+ prefixes2.add(matches[1]);
9264
+ if (prefixes2.size > 1) {
9265
+ break;
9266
+ }
9267
+ }
9268
+ }
9269
+ if (prefixes2.size > 1) {
9270
+ break;
9271
+ }
9272
+ }
9273
+ if (prefixes1.size != prefixes2.size) {
9274
+ return null;
9275
+ }
9276
+ for (const prefix of prefixes1) {
9277
+ if (!prefixes2.has(prefix)) {
9278
+ return null;
9279
+ }
9280
+ }
9281
+ }
9201
9282
  // @ts-ignore
9202
9283
  node1 = { ...node1, chi: node1.chi.slice() };
9203
9284
  node2 = { ...node2, chi: node2.chi.slice() };
@@ -9234,7 +9315,7 @@ function diff(n1, n2, reducer, options = {}) {
9234
9315
  const result = (intersect.length == 0 ? null : {
9235
9316
  ...node1,
9236
9317
  // @ts-ignore
9237
- sel: [...new Set([...(n1?.raw?.reduce(reducer, []) || splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) || splitRule(n2.sel))])].join(','),
9318
+ sel: [...new Set([...(n1?.raw?.reduce(reducer, []) ?? splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) ?? splitRule(n2.sel))])].join(','),
9238
9319
  chi: intersect.reverse()
9239
9320
  });
9240
9321
  if (result == null || [n1, n2].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + doRender(curr, options).code.length, 0) <= [node1, node2, result].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + doRender(curr, options).code.length, 0)) {
@@ -9258,6 +9339,11 @@ function reduceRuleSelector(node) {
9258
9339
  Object.defineProperty(node, 'optimized', { ...definedPropertySettings, value: optimized });
9259
9340
  }
9260
9341
  if (optimized != null && optimized.match && optimized.reducible && optimized.selector.length > 1) {
9342
+ for (const selector of optimized.selector) {
9343
+ if (selector.length > 1 && selector[0] == '&' && combinators.includes(selector[1])) {
9344
+ selector.shift();
9345
+ }
9346
+ }
9261
9347
  const raw = [
9262
9348
  [
9263
9349
  optimized.optimized[0], ':is('
package/dist/index.d.ts CHANGED
@@ -71,6 +71,7 @@ declare enum EnumToken {
71
71
  FractionTokenType = 69,
72
72
  IdenListTokenType = 70,
73
73
  GridTemplateFuncTokenType = 71,
74
+ KeyFrameRuleNodeType = 72,
74
75
  Time = 25,
75
76
  Iden = 7,
76
77
  EOF = 47,
@@ -664,6 +665,7 @@ export declare interface AstDeclaration extends Node {
664
665
  typ: EnumToken.DeclarationNodeType
665
666
  }
666
667
 
668
+
667
669
  export declare interface AstRule extends Node {
668
670
 
669
671
  typ: EnumToken.RuleNodeType;
@@ -7,7 +7,15 @@ import { reduceNumber } from '../../renderer/render.js';
7
7
  * @param tokens
8
8
  */
9
9
  function evaluate(tokens) {
10
- const nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
10
+ let nodes;
11
+ try {
12
+ nodes = inlineExpression(evaluateExpression(buildExpression(tokens)));
13
+ }
14
+ catch (e) {
15
+ // console.error({tokens});
16
+ // console.error(e);
17
+ return tokens;
18
+ }
11
19
  if (nodes.length <= 1) {
12
20
  return nodes;
13
21
  }
@@ -14,7 +14,7 @@ const notEndingWith = ['(', '['].concat(combinators);
14
14
  const features = Object.values(index).sort((a, b) => a.ordering - b.ordering);
15
15
  function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) {
16
16
  if (!('nodes' in context)) {
17
- context.nodes = new WeakSet;
17
+ context.nodes = new Set;
18
18
  }
19
19
  if (context.nodes.has(ast)) {
20
20
  return ast;
@@ -43,7 +43,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
43
43
  curr.splice(0, 2);
44
44
  }
45
45
  else if (combinators.includes(curr[1])) {
46
- curr.splice(0, 1);
46
+ curr.shift();
47
47
  }
48
48
  }
49
49
  else if (ast.typ == EnumToken.RuleNodeType && (isIdent(curr[0]) || isFunction(curr[0]))) {
@@ -245,7 +245,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
245
245
  }
246
246
  if (shouldMerge) {
247
247
  // @ts-ignore
248
- if ((node.typ == EnumToken.RuleNodeType && node.sel == previous.sel) ||
248
+ if (((node.typ == EnumToken.RuleNodeType || node.typ == EnumToken.KeyFrameRuleNodeType) && node.sel == previous.sel) ||
249
249
  // @ts-ignore
250
250
  (node.typ == EnumToken.AtRuleNodeType) && node.val != 'font-face' && node.val == previous.val) {
251
251
  // @ts-ignore
@@ -264,32 +264,33 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
264
264
  nodeIndex = i;
265
265
  continue;
266
266
  }
267
- else if (node.typ == EnumToken.RuleNodeType && previous?.typ == EnumToken.RuleNodeType) {
267
+ else if (node.typ == previous?.typ && [EnumToken.KeyFrameRuleNodeType, EnumToken.RuleNodeType].includes(node.typ)) {
268
268
  const intersect = diff(previous, node, reducer, options);
269
269
  if (intersect != null) {
270
270
  if (intersect.node1.chi.length == 0) {
271
271
  // @ts-ignore
272
272
  ast.chi.splice(i--, 1);
273
273
  // @ts-ignore
274
- node = ast.chi[i];
274
+ // node = ast.chi[i];
275
275
  }
276
276
  else {
277
277
  // @ts-ignore
278
278
  ast.chi.splice(i, 1, intersect.node1);
279
- node = intersect.node1;
279
+ // node = ast.chi intersect.node1;
280
280
  }
281
281
  if (intersect.node2.chi.length == 0) {
282
282
  // @ts-ignore
283
283
  ast.chi.splice(nodeIndex, 1, intersect.result);
284
- previous = intersect.result;
285
284
  }
286
285
  else {
287
286
  // @ts-ignore
288
287
  ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2);
289
- previous = intersect.result;
290
288
  // @ts-ignore
291
- i = nodeIndex;
289
+ i = (nodeIndex ?? 0) + 1;
292
290
  }
291
+ reduceRuleSelector(intersect.result);
292
+ previous = intersect.result;
293
+ nodeIndex = i;
293
294
  }
294
295
  }
295
296
  }
@@ -419,11 +420,16 @@ function reduceSelector(selector) {
419
420
  // combinator
420
421
  if (combinators.includes(optimized.at(-1))) {
421
422
  const combinator = optimized.pop();
422
- selector.forEach(selector => selector.unshift(combinator));
423
+ selector.forEach((selector) => selector.unshift(combinator));
423
424
  }
424
425
  let reducible = optimized.length == 1;
425
- if (optimized[0] == '&' && optimized[1] == ' ') {
426
- optimized.splice(0, 2);
426
+ if (optimized[0] == '&') {
427
+ if (optimized[1] == ' ') {
428
+ optimized.splice(0, 2);
429
+ }
430
+ // else if (combinators.includes(optimized[1])) {
431
+ //
432
+ // }
427
433
  }
428
434
  if (optimized.length == 0 ||
429
435
  (optimized[0].charAt(0) == '&' ||
@@ -431,7 +437,7 @@ function reduceSelector(selector) {
431
437
  return {
432
438
  match: false,
433
439
  optimized,
434
- selector: selector.map(selector => selector[0] == '&' && selector[1] == ' ' ? selector.slice(2) : selector),
440
+ selector: selector.map((selector) => selector[0] == '&' && selector[1] == ' ' ? selector.slice(2) : (selector)),
435
441
  reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0]))
436
442
  };
437
443
  }
@@ -511,6 +517,18 @@ function splitRule(buffer) {
511
517
  result.push([]);
512
518
  continue;
513
519
  }
520
+ if (chr == ':') {
521
+ if (str !== '') {
522
+ // @ts-ignore
523
+ result.at(-1).push(str);
524
+ str = '';
525
+ }
526
+ if (buffer.charAt(i + 1) == ':') {
527
+ chr += buffer.charAt(++i);
528
+ }
529
+ str += chr;
530
+ continue;
531
+ }
514
532
  str += chr;
515
533
  if (chr == '\\') {
516
534
  str += buffer.charAt(++i);
@@ -812,6 +830,52 @@ function diff(n1, n2, reducer, options = {}) {
812
830
  const raw1 = node1.raw;
813
831
  // @ts-ignore
814
832
  const raw2 = node2.raw;
833
+ if (raw1 != null && raw2 != null) {
834
+ const prefixes1 = new Set;
835
+ const prefixes2 = new Set;
836
+ for (const token1 of raw1) {
837
+ for (const t of token1) {
838
+ if (t[0] == ':') {
839
+ const matches = t.match(/::?-([a-z]+)-/);
840
+ if (matches == null) {
841
+ continue;
842
+ }
843
+ prefixes1.add(matches[1]);
844
+ if (prefixes1.size > 1) {
845
+ break;
846
+ }
847
+ }
848
+ }
849
+ if (prefixes1.size > 1) {
850
+ break;
851
+ }
852
+ }
853
+ for (const token2 of raw2) {
854
+ for (const t of token2) {
855
+ if (t[0] == ':') {
856
+ const matches = t.match(/::?-([a-z]+)-/);
857
+ if (matches == null) {
858
+ continue;
859
+ }
860
+ prefixes2.add(matches[1]);
861
+ if (prefixes2.size > 1) {
862
+ break;
863
+ }
864
+ }
865
+ }
866
+ if (prefixes2.size > 1) {
867
+ break;
868
+ }
869
+ }
870
+ if (prefixes1.size != prefixes2.size) {
871
+ return null;
872
+ }
873
+ for (const prefix of prefixes1) {
874
+ if (!prefixes2.has(prefix)) {
875
+ return null;
876
+ }
877
+ }
878
+ }
815
879
  // @ts-ignore
816
880
  node1 = { ...node1, chi: node1.chi.slice() };
817
881
  node2 = { ...node2, chi: node2.chi.slice() };
@@ -848,7 +912,7 @@ function diff(n1, n2, reducer, options = {}) {
848
912
  const result = (intersect.length == 0 ? null : {
849
913
  ...node1,
850
914
  // @ts-ignore
851
- sel: [...new Set([...(n1?.raw?.reduce(reducer, []) || splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) || splitRule(n2.sel))])].join(','),
915
+ sel: [...new Set([...(n1?.raw?.reduce(reducer, []) ?? splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) ?? splitRule(n2.sel))])].join(','),
852
916
  chi: intersect.reverse()
853
917
  });
854
918
  if (result == null || [n1, n2].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + doRender(curr, options).code.length, 0) <= [node1, node2, result].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + doRender(curr, options).code.length, 0)) {
@@ -872,6 +936,11 @@ function reduceRuleSelector(node) {
872
936
  Object.defineProperty(node, 'optimized', { ...definedPropertySettings, value: optimized });
873
937
  }
874
938
  if (optimized != null && optimized.match && optimized.reducible && optimized.selector.length > 1) {
939
+ for (const selector of optimized.selector) {
940
+ if (selector.length > 1 && selector[0] == '&' && combinators.includes(selector[1])) {
941
+ selector.shift();
942
+ }
943
+ }
875
944
  const raw = [
876
945
  [
877
946
  optimized.optimized[0], ':is('
@@ -75,6 +75,7 @@ var EnumToken;
75
75
  EnumToken[EnumToken["FractionTokenType"] = 69] = "FractionTokenType";
76
76
  EnumToken[EnumToken["IdenListTokenType"] = 70] = "IdenListTokenType";
77
77
  EnumToken[EnumToken["GridTemplateFuncTokenType"] = 71] = "GridTemplateFuncTokenType";
78
+ EnumToken[EnumToken["KeyFrameRuleNodeType"] = 72] = "KeyFrameRuleNodeType";
78
79
  /* aliases */
79
80
  EnumToken[EnumToken["Time"] = 25] = "Time";
80
81
  EnumToken[EnumToken["Iden"] = 7] = "Iden";
@@ -346,12 +346,16 @@ async function parseNode(results, context, stats, options, errors, src, map) {
346
346
  }
347
347
  if (atRule.val == 'import') {
348
348
  // @ts-ignore
349
- if (tokens[0].typ == EnumToken.UrlFunctionTokenType && tokens[1].typ == EnumToken.UrlTokenTokenType) {
350
- tokens.shift();
351
- // @ts-ignore
352
- tokens[0].typ = EnumToken.StringTokenType;
353
- // @ts-ignore
354
- tokens[0].val = `"${tokens[0].val}"`;
349
+ if (tokens[0].typ == EnumToken.UrlFunctionTokenType) {
350
+ if (tokens[1].typ == EnumToken.UrlTokenTokenType || tokens[1].typ == EnumToken.StringTokenType) {
351
+ tokens.shift();
352
+ if (tokens[1].typ == EnumToken.UrlTokenTokenType) {
353
+ // @ts-ignore
354
+ tokens[0].typ = EnumToken.StringTokenType;
355
+ // @ts-ignore
356
+ tokens[0].val = `"${tokens[0].val}"`;
357
+ }
358
+ }
355
359
  }
356
360
  // @ts-ignore
357
361
  if (tokens[0].typ == EnumToken.StringTokenType) {
@@ -417,6 +421,9 @@ async function parseNode(results, context, stats, options, errors, src, map) {
417
421
  const position = map.get(tokens[0]);
418
422
  const uniq = new Map;
419
423
  parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
424
+ if (curr.typ == EnumToken.CommentTokenType) {
425
+ return acc;
426
+ }
420
427
  if (curr.typ == EnumToken.WhitespaceTokenType) {
421
428
  if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
422
429
  trimWhiteSpace.includes(array[index + 1]?.typ) ||
@@ -438,7 +445,7 @@ async function parseNode(results, context, stats, options, errors, src, map) {
438
445
  return acc;
439
446
  }, uniq);
440
447
  const node = {
441
- typ: EnumToken.RuleNodeType,
448
+ typ: context.typ == EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? EnumToken.KeyFrameRuleNodeType : EnumToken.RuleNodeType,
442
449
  // @ts-ignore
443
450
  sel: [...uniq.keys()].join(','),
444
451
  chi: []
@@ -98,7 +98,7 @@ function doRender(data, options = {}) {
98
98
  return result;
99
99
  }
100
100
  function updateSourceMap(node, options, cache, sourcemap, position, str) {
101
- if ([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType].includes(node.typ)) {
101
+ if ([EnumToken.RuleNodeType, EnumToken.AtRuleNodeType, EnumToken.KeyFrameRuleNodeType].includes(node.typ)) {
102
102
  let src = node.loc?.src ?? '';
103
103
  let output = options.output ?? '';
104
104
  if (!(src in cache)) {
@@ -158,6 +158,7 @@ function renderAstNode(data, options, sourcemap, position, errors, reducer, cach
158
158
  }, '');
159
159
  case EnumToken.AtRuleNodeType:
160
160
  case EnumToken.RuleNodeType:
161
+ case EnumToken.KeyFrameRuleNodeType:
161
162
  if (data.typ == EnumToken.AtRuleNodeType && !('chi' in data)) {
162
163
  return `${indent}@${data.nam}${data.val === '' ? '' : options.indent || ' '}${data.val};`;
163
164
  }
package/dist/web/load.js CHANGED
@@ -7,16 +7,18 @@ function parseResponse(response) {
7
7
  return response.text();
8
8
  }
9
9
  async function load(url, currentFile) {
10
+ let t;
10
11
  if (matchUrl.test(url)) {
11
- return fetch(url).then(parseResponse);
12
+ t = new URL(url);
12
13
  }
13
- if (matchUrl.test(currentFile)) {
14
- return fetch(new URL(url, currentFile)).then(parseResponse);
14
+ else if (matchUrl.test(currentFile)) {
15
+ t = new URL(url, currentFile);
15
16
  }
16
- const path = resolve(url, currentFile).absolute;
17
- const t = new URL(path, self.origin);
18
- // return fetch(new URL(url, new URL(currentFile, self.location.href).href)).then(parseResponse);
19
- return fetch(url, t.origin != self.location.origin ? { mode: 'cors' } : {}).then(parseResponse);
17
+ else {
18
+ const path = resolve(url, currentFile).absolute;
19
+ t = new URL(path, self.origin);
20
+ }
21
+ return fetch(t, t.origin != self.origin ? { mode: 'cors' } : {}).then(parseResponse);
20
22
  }
21
23
 
22
24
  export { load };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tbela99/css-parser",
3
3
  "description": "CSS parser for node and the browser",
4
- "version": "0.5.0",
4
+ "version": "0.5.2",
5
5
  "exports": {
6
6
  ".": "./dist/node/index.js",
7
7
  "./umd": "./dist/index-umd-web.js",
@@ -10,6 +10,9 @@
10
10
  },
11
11
  "type": "module",
12
12
  "typings": "dist/index.d.ts",
13
+ "directories": {
14
+ "test": "test"
15
+ },
13
16
  "scripts": {
14
17
  "build": "rollup -c;./build.sh dist/index.d.ts 'declare interface' 'declare type'",
15
18
  "test": "web-test-runner \"test/**/web.spec.js\" --node-resolve --playwright --browsers chromium firefox webkit --root-dir=.; mocha --reporter-options='maxDiffSize=1801920' \"test/**/node.spec.js\"",