@tbela99/css-parser 0.5.1 → 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
  }
@@ -6446,6 +6456,9 @@
6446
6456
  const position = map.get(tokens[0]);
6447
6457
  const uniq = new Map;
6448
6458
  parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
6459
+ if (curr.typ == exports.EnumToken.CommentTokenType) {
6460
+ return acc;
6461
+ }
6449
6462
  if (curr.typ == exports.EnumToken.WhitespaceTokenType) {
6450
6463
  if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
6451
6464
  trimWhiteSpace.includes(array[index + 1]?.typ) ||
@@ -6467,7 +6480,7 @@
6467
6480
  return acc;
6468
6481
  }, uniq);
6469
6482
  const node = {
6470
- typ: exports.EnumToken.RuleNodeType,
6483
+ typ: context.typ == exports.EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? exports.EnumToken.KeyFrameRuleNodeType : exports.EnumToken.RuleNodeType,
6471
6484
  // @ts-ignore
6472
6485
  sel: [...uniq.keys()].join(','),
6473
6486
  chi: []
@@ -8406,7 +8419,7 @@
8406
8419
  const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering);
8407
8420
  function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) {
8408
8421
  if (!('nodes' in context)) {
8409
- context.nodes = new WeakSet;
8422
+ context.nodes = new Set;
8410
8423
  }
8411
8424
  if (context.nodes.has(ast)) {
8412
8425
  return ast;
@@ -8435,7 +8448,7 @@
8435
8448
  curr.splice(0, 2);
8436
8449
  }
8437
8450
  else if (combinators.includes(curr[1])) {
8438
- curr.splice(0, 1);
8451
+ curr.shift();
8439
8452
  }
8440
8453
  }
8441
8454
  else if (ast.typ == exports.EnumToken.RuleNodeType && (isIdent(curr[0]) || isFunction(curr[0]))) {
@@ -8637,7 +8650,7 @@
8637
8650
  }
8638
8651
  if (shouldMerge) {
8639
8652
  // @ts-ignore
8640
- 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) ||
8641
8654
  // @ts-ignore
8642
8655
  (node.typ == exports.EnumToken.AtRuleNodeType) && node.val != 'font-face' && node.val == previous.val) {
8643
8656
  // @ts-ignore
@@ -8656,32 +8669,33 @@
8656
8669
  nodeIndex = i;
8657
8670
  continue;
8658
8671
  }
8659
- 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)) {
8660
8673
  const intersect = diff(previous, node, reducer, options);
8661
8674
  if (intersect != null) {
8662
8675
  if (intersect.node1.chi.length == 0) {
8663
8676
  // @ts-ignore
8664
8677
  ast.chi.splice(i--, 1);
8665
8678
  // @ts-ignore
8666
- node = ast.chi[i];
8679
+ // node = ast.chi[i];
8667
8680
  }
8668
8681
  else {
8669
8682
  // @ts-ignore
8670
8683
  ast.chi.splice(i, 1, intersect.node1);
8671
- node = intersect.node1;
8684
+ // node = ast.chi intersect.node1;
8672
8685
  }
8673
8686
  if (intersect.node2.chi.length == 0) {
8674
8687
  // @ts-ignore
8675
8688
  ast.chi.splice(nodeIndex, 1, intersect.result);
8676
- previous = intersect.result;
8677
8689
  }
8678
8690
  else {
8679
8691
  // @ts-ignore
8680
8692
  ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2);
8681
- previous = intersect.result;
8682
8693
  // @ts-ignore
8683
- i = nodeIndex;
8694
+ i = (nodeIndex ?? 0) + 1;
8684
8695
  }
8696
+ reduceRuleSelector(intersect.result);
8697
+ previous = intersect.result;
8698
+ nodeIndex = i;
8685
8699
  }
8686
8700
  }
8687
8701
  }
@@ -8811,11 +8825,16 @@
8811
8825
  // combinator
8812
8826
  if (combinators.includes(optimized.at(-1))) {
8813
8827
  const combinator = optimized.pop();
8814
- selector.forEach(selector => selector.unshift(combinator));
8828
+ selector.forEach((selector) => selector.unshift(combinator));
8815
8829
  }
8816
8830
  let reducible = optimized.length == 1;
8817
- if (optimized[0] == '&' && optimized[1] == ' ') {
8818
- 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
+ // }
8819
8838
  }
8820
8839
  if (optimized.length == 0 ||
8821
8840
  (optimized[0].charAt(0) == '&' ||
@@ -8823,7 +8842,7 @@
8823
8842
  return {
8824
8843
  match: false,
8825
8844
  optimized,
8826
- 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)),
8827
8846
  reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0]))
8828
8847
  };
8829
8848
  }
@@ -8903,6 +8922,18 @@
8903
8922
  result.push([]);
8904
8923
  continue;
8905
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
+ }
8906
8937
  str += chr;
8907
8938
  if (chr == '\\') {
8908
8939
  str += buffer.charAt(++i);
@@ -9204,6 +9235,52 @@
9204
9235
  const raw1 = node1.raw;
9205
9236
  // @ts-ignore
9206
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
+ }
9207
9284
  // @ts-ignore
9208
9285
  node1 = { ...node1, chi: node1.chi.slice() };
9209
9286
  node2 = { ...node2, chi: node2.chi.slice() };
@@ -9240,7 +9317,7 @@
9240
9317
  const result = (intersect.length == 0 ? null : {
9241
9318
  ...node1,
9242
9319
  // @ts-ignore
9243
- 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(','),
9244
9321
  chi: intersect.reverse()
9245
9322
  });
9246
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)) {
@@ -9264,6 +9341,11 @@
9264
9341
  Object.defineProperty(node, 'optimized', { ...definedPropertySettings, value: optimized });
9265
9342
  }
9266
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
+ }
9267
9349
  const raw = [
9268
9350
  [
9269
9351
  optimized.optimized[0], ':is('
@@ -9391,16 +9473,18 @@
9391
9473
  return response.text();
9392
9474
  }
9393
9475
  async function load(url, currentFile) {
9476
+ let t;
9394
9477
  if (matchUrl.test(url)) {
9395
- return fetch(url).then(parseResponse);
9478
+ t = new URL(url);
9396
9479
  }
9397
- if (matchUrl.test(currentFile)) {
9398
- return fetch(new URL(url, currentFile)).then(parseResponse);
9480
+ else if (matchUrl.test(currentFile)) {
9481
+ t = new URL(url, currentFile);
9482
+ }
9483
+ else {
9484
+ const path = resolve(url, currentFile).absolute;
9485
+ t = new URL(path, self.origin);
9399
9486
  }
9400
- const path = resolve(url, currentFile).absolute;
9401
- const t = new URL(path, self.origin);
9402
- // return fetch(new URL(url, new URL(currentFile, self.location.href).href)).then(parseResponse);
9403
- return fetch(url, t.origin != self.location.origin ? { mode: 'cors' } : {}).then(parseResponse);
9487
+ return fetch(t, t.origin != self.origin ? { mode: 'cors' } : {}).then(parseResponse);
9404
9488
  }
9405
9489
 
9406
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
  }
@@ -6444,6 +6454,9 @@ async function parseNode(results, context, stats, options, errors, src, map) {
6444
6454
  const position = map.get(tokens[0]);
6445
6455
  const uniq = new Map;
6446
6456
  parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
6457
+ if (curr.typ == exports.EnumToken.CommentTokenType) {
6458
+ return acc;
6459
+ }
6447
6460
  if (curr.typ == exports.EnumToken.WhitespaceTokenType) {
6448
6461
  if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
6449
6462
  trimWhiteSpace.includes(array[index + 1]?.typ) ||
@@ -6465,7 +6478,7 @@ async function parseNode(results, context, stats, options, errors, src, map) {
6465
6478
  return acc;
6466
6479
  }, uniq);
6467
6480
  const node = {
6468
- typ: exports.EnumToken.RuleNodeType,
6481
+ typ: context.typ == exports.EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? exports.EnumToken.KeyFrameRuleNodeType : exports.EnumToken.RuleNodeType,
6469
6482
  // @ts-ignore
6470
6483
  sel: [...uniq.keys()].join(','),
6471
6484
  chi: []
@@ -8404,7 +8417,7 @@ const notEndingWith = ['(', '['].concat(combinators);
8404
8417
  const features = Object.values(allFeatures).sort((a, b) => a.ordering - b.ordering);
8405
8418
  function minify(ast, options = {}, recursive = false, errors, nestingContent, context = {}) {
8406
8419
  if (!('nodes' in context)) {
8407
- context.nodes = new WeakSet;
8420
+ context.nodes = new Set;
8408
8421
  }
8409
8422
  if (context.nodes.has(ast)) {
8410
8423
  return ast;
@@ -8433,7 +8446,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
8433
8446
  curr.splice(0, 2);
8434
8447
  }
8435
8448
  else if (combinators.includes(curr[1])) {
8436
- curr.splice(0, 1);
8449
+ curr.shift();
8437
8450
  }
8438
8451
  }
8439
8452
  else if (ast.typ == exports.EnumToken.RuleNodeType && (isIdent(curr[0]) || isFunction(curr[0]))) {
@@ -8635,7 +8648,7 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
8635
8648
  }
8636
8649
  if (shouldMerge) {
8637
8650
  // @ts-ignore
8638
- 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) ||
8639
8652
  // @ts-ignore
8640
8653
  (node.typ == exports.EnumToken.AtRuleNodeType) && node.val != 'font-face' && node.val == previous.val) {
8641
8654
  // @ts-ignore
@@ -8654,32 +8667,33 @@ function minify(ast, options = {}, recursive = false, errors, nestingContent, co
8654
8667
  nodeIndex = i;
8655
8668
  continue;
8656
8669
  }
8657
- 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)) {
8658
8671
  const intersect = diff(previous, node, reducer, options);
8659
8672
  if (intersect != null) {
8660
8673
  if (intersect.node1.chi.length == 0) {
8661
8674
  // @ts-ignore
8662
8675
  ast.chi.splice(i--, 1);
8663
8676
  // @ts-ignore
8664
- node = ast.chi[i];
8677
+ // node = ast.chi[i];
8665
8678
  }
8666
8679
  else {
8667
8680
  // @ts-ignore
8668
8681
  ast.chi.splice(i, 1, intersect.node1);
8669
- node = intersect.node1;
8682
+ // node = ast.chi intersect.node1;
8670
8683
  }
8671
8684
  if (intersect.node2.chi.length == 0) {
8672
8685
  // @ts-ignore
8673
8686
  ast.chi.splice(nodeIndex, 1, intersect.result);
8674
- previous = intersect.result;
8675
8687
  }
8676
8688
  else {
8677
8689
  // @ts-ignore
8678
8690
  ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2);
8679
- previous = intersect.result;
8680
8691
  // @ts-ignore
8681
- i = nodeIndex;
8692
+ i = (nodeIndex ?? 0) + 1;
8682
8693
  }
8694
+ reduceRuleSelector(intersect.result);
8695
+ previous = intersect.result;
8696
+ nodeIndex = i;
8683
8697
  }
8684
8698
  }
8685
8699
  }
@@ -8809,11 +8823,16 @@ function reduceSelector(selector) {
8809
8823
  // combinator
8810
8824
  if (combinators.includes(optimized.at(-1))) {
8811
8825
  const combinator = optimized.pop();
8812
- selector.forEach(selector => selector.unshift(combinator));
8826
+ selector.forEach((selector) => selector.unshift(combinator));
8813
8827
  }
8814
8828
  let reducible = optimized.length == 1;
8815
- if (optimized[0] == '&' && optimized[1] == ' ') {
8816
- 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
+ // }
8817
8836
  }
8818
8837
  if (optimized.length == 0 ||
8819
8838
  (optimized[0].charAt(0) == '&' ||
@@ -8821,7 +8840,7 @@ function reduceSelector(selector) {
8821
8840
  return {
8822
8841
  match: false,
8823
8842
  optimized,
8824
- 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)),
8825
8844
  reducible: selector.length > 1 && selector.every((selector) => !combinators.includes(selector[0]))
8826
8845
  };
8827
8846
  }
@@ -8901,6 +8920,18 @@ function splitRule(buffer) {
8901
8920
  result.push([]);
8902
8921
  continue;
8903
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
+ }
8904
8935
  str += chr;
8905
8936
  if (chr == '\\') {
8906
8937
  str += buffer.charAt(++i);
@@ -9202,6 +9233,52 @@ function diff(n1, n2, reducer, options = {}) {
9202
9233
  const raw1 = node1.raw;
9203
9234
  // @ts-ignore
9204
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
+ }
9205
9282
  // @ts-ignore
9206
9283
  node1 = { ...node1, chi: node1.chi.slice() };
9207
9284
  node2 = { ...node2, chi: node2.chi.slice() };
@@ -9238,7 +9315,7 @@ function diff(n1, n2, reducer, options = {}) {
9238
9315
  const result = (intersect.length == 0 ? null : {
9239
9316
  ...node1,
9240
9317
  // @ts-ignore
9241
- 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(','),
9242
9319
  chi: intersect.reverse()
9243
9320
  });
9244
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)) {
@@ -9262,6 +9339,11 @@ function reduceRuleSelector(node) {
9262
9339
  Object.defineProperty(node, 'optimized', { ...definedPropertySettings, value: optimized });
9263
9340
  }
9264
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
+ }
9265
9347
  const raw = [
9266
9348
  [
9267
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";
@@ -421,6 +421,9 @@ async function parseNode(results, context, stats, options, errors, src, map) {
421
421
  const position = map.get(tokens[0]);
422
422
  const uniq = new Map;
423
423
  parseTokens(tokens, { minify: true }).reduce((acc, curr, index, array) => {
424
+ if (curr.typ == EnumToken.CommentTokenType) {
425
+ return acc;
426
+ }
424
427
  if (curr.typ == EnumToken.WhitespaceTokenType) {
425
428
  if (trimWhiteSpace.includes(array[index - 1]?.typ) ||
426
429
  trimWhiteSpace.includes(array[index + 1]?.typ) ||
@@ -442,7 +445,7 @@ async function parseNode(results, context, stats, options, errors, src, map) {
442
445
  return acc;
443
446
  }, uniq);
444
447
  const node = {
445
- typ: EnumToken.RuleNodeType,
448
+ typ: context.typ == EnumToken.AtRuleNodeType && context.nam == 'keyframes' ? EnumToken.KeyFrameRuleNodeType : EnumToken.RuleNodeType,
446
449
  // @ts-ignore
447
450
  sel: [...uniq.keys()].join(','),
448
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.1",
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\"",