@tbela99/css-parser 0.0.1-alpha3 → 0.0.1-alpha4

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/dist/index.d.ts CHANGED
@@ -191,6 +191,7 @@ interface ParserOptions {
191
191
  src?: string;
192
192
  sourcemap?: boolean;
193
193
  compress?: boolean;
194
+ nestingRules?: boolean;
194
195
  removeEmpty?: boolean;
195
196
  resolveUrls?: boolean;
196
197
  resolveImport?: boolean;
@@ -304,6 +305,12 @@ type AstNode =
304
305
  declare function deduplicate(ast: AstNode, options?: ParserOptions, recursive?: boolean): AstNode;
305
306
  declare function hasDeclaration(node: AstAtRule | AstRule | AstRuleList): boolean;
306
307
  declare function deduplicateRule(ast: AstNode, options?: ParserOptions): AstNode;
308
+ declare function reduceSelector(selector: string[][]): null | {
309
+ match: boolean;
310
+ optimized: string[];
311
+ selector: string[][];
312
+ reducible: boolean;
313
+ };
307
314
 
308
315
  declare function render(data: AstNode, opt?: RenderOptions): RenderResult;
309
316
  declare function renderToken(token: Token, options?: RenderOptions): string;
@@ -326,4 +333,4 @@ declare function resolve(url: string, currentDirectory: string, cwd?: string): {
326
333
  declare function parse(iterator: string, opt?: ParserOptions): Promise<ParseResult>;
327
334
  declare function transform(css: string, options?: TransformOptions): Promise<TransformResult>;
328
335
 
329
- export { deduplicate, deduplicateRule, dirname, hasDeclaration, load, matchUrl, parse, render, renderToken, resolve, transform, walk };
336
+ export { deduplicate, deduplicateRule, dirname, hasDeclaration, load, matchUrl, parse, reduceSelector, render, renderToken, resolve, transform, walk };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { parse, transform } from './node/index.js';
2
- export { deduplicate, deduplicateRule, hasDeclaration } from './lib/parser/deduplicate.js';
2
+ export { deduplicate, deduplicateRule, hasDeclaration, reduceSelector } from './lib/parser/deduplicate.js';
3
3
  export { render, renderToken } from './lib/renderer/render.js';
4
4
  export { walk } from './lib/walker/walk.js';
5
5
  export { load } from './node/load.js';
@@ -1,5 +1,6 @@
1
1
  import { PropertyList } from './declaration/list.js';
2
2
  import { eq } from './utils/eq.js';
3
+ import { isIdentStart } from './utils/syntax.js';
3
4
  import { getConfig } from './utils/config.js';
4
5
  import { render } from '../renderer/render.js';
5
6
 
@@ -29,6 +30,125 @@ function deduplicate(ast, options = {}, recursive = false) {
29
30
  continue;
30
31
  }
31
32
  // @ts-ignore
33
+ if (node.typ == 'Rule') {
34
+ reduceRuleSelector(node);
35
+ // @ts-ignore
36
+ if (options.nestingRules && node.raw != null && previous?.raw != null && node.raw.length == 1 && previous.raw.length == 1) {
37
+ const match = [];
38
+ // @ts-ignore
39
+ while (node.raw[0].length > 0 && previous.raw[0].length > 0) {
40
+ // @ts-ignore
41
+ if (node.raw[0][0] != previous.raw[0][0]) {
42
+ break;
43
+ }
44
+ // @ts-ignore
45
+ match.push(node.raw[0].shift());
46
+ // @ts-ignore
47
+ previous.raw[0].shift();
48
+ }
49
+ if (match.length > 0) {
50
+ // @ts-ignore
51
+ const wrapper = { ...previous, chi: [] };
52
+ // @ts-ignore
53
+ if (previous.raw[0].length == 0) {
54
+ // @ts-ignore
55
+ wrapper.chi.push(...previous.chi);
56
+ }
57
+ else {
58
+ // @ts-ignore
59
+ previous.sel = previous.raw.reduce((acc, curr) => {
60
+ acc.push(curr.join(''));
61
+ return acc;
62
+ }, []).join(',');
63
+ // @ts-ignore
64
+ wrapper.chi.push(previous);
65
+ }
66
+ // @ts-ignore
67
+ if (node.raw[0].length == 0) {
68
+ // @ts-ignore
69
+ if (previous.raw.length == 0) {
70
+ // @ts-ignore
71
+ wrapper.chi.push(...node.chi);
72
+ }
73
+ else {
74
+ if (hasOnlyDeclarations(wrapper)) {
75
+ wrapper.chi.push(...node.chi);
76
+ }
77
+ else {
78
+ // @ts-ignore
79
+ node.raw[0].push('&');
80
+ // @ts-ignore
81
+ node.sel = node.raw.reduce((acc, curr) => {
82
+ acc.push(curr.join(''));
83
+ return acc;
84
+ }, []).join(',');
85
+ // @ts-ignore
86
+ wrapper.chi.push(node);
87
+ }
88
+ }
89
+ }
90
+ else {
91
+ // @ts-ignore
92
+ node.sel = node.raw.reduce((acc, curr) => {
93
+ acc.push(curr.join(''));
94
+ return acc;
95
+ }, []).join(',');
96
+ // @ts-ignore
97
+ wrapper.chi.push(node);
98
+ }
99
+ Object.defineProperty(wrapper, 'raw', { enumerable: false, writable: true, value: [match] });
100
+ // @ts-ignore
101
+ ast.chi.splice(i, 1, wrapper);
102
+ // @ts-ignore
103
+ ast.chi.splice(nodeIndex, 1);
104
+ // @ts-ignore
105
+ while (i < ast.chi.length) {
106
+ // @ts-ignore
107
+ const nextNode = ast.chi[i];
108
+ // @ts-ignore
109
+ if (nextNode.typ != 'Rule' || nextNode.raw == null) {
110
+ break;
111
+ }
112
+ reduceRuleSelector(nextNode);
113
+ // @ts-ignore
114
+ if (nextNode.raw.length != 1 || !eq(wrapper.raw[0], nextNode.raw[0].slice(0, wrapper.raw[0].length))) {
115
+ break;
116
+ }
117
+ // @ts-ignore
118
+ nextNode.raw[0].splice(0, wrapper.raw[0].length);
119
+ // @ts-ignore
120
+ if (nextNode.raw[0].length == 0 ||
121
+ // @ts-ignore
122
+ (nextNode.raw.length == 1 && nextNode.raw[0] == '&')) {
123
+ if (hasOnlyDeclarations(wrapper)) {
124
+ wrapper.chi.push(...nextNode.chi);
125
+ // @ts-ignore
126
+ ast.chi.splice(i, 1);
127
+ continue;
128
+ }
129
+ else {
130
+ // @ts-ignore
131
+ nextNode.raw[0].push('&');
132
+ }
133
+ }
134
+ // @ts-ignore
135
+ nextNode.sel = nextNode.raw.reduce((acc, curr) => {
136
+ acc.push(curr.join(''));
137
+ return acc;
138
+ }, []).join(',');
139
+ wrapper.chi.push(nextNode);
140
+ // @ts-ignore
141
+ ast.chi.splice(i, 1);
142
+ }
143
+ deduplicateRule(wrapper);
144
+ nodeIndex = --i;
145
+ // @ts-ignore
146
+ previous = ast.chi[i];
147
+ continue;
148
+ }
149
+ }
150
+ }
151
+ // @ts-ignore
32
152
  if (previous != null && 'chi' in previous && ('chi' in node)) {
33
153
  // @ts-ignore
34
154
  if (previous.typ == node.typ) {
@@ -48,7 +168,7 @@ function deduplicate(ast, options = {}, recursive = false) {
48
168
  // @ts-ignore
49
169
  if ((node.typ == 'Rule' && node.sel == previous.sel) ||
50
170
  // @ts-ignore
51
- (node.typ == 'AtRule') && node.val == previous.val) {
171
+ (node.typ == 'AtRule') && node.val != 'font-face' && node.val == previous.val) {
52
172
  // @ts-ignore
53
173
  node.chi.unshift(...previous.chi);
54
174
  // @ts-ignore
@@ -70,19 +190,26 @@ function deduplicate(ast, options = {}, recursive = false) {
70
190
  if (intersect != null) {
71
191
  if (intersect.node1.chi.length == 0) {
72
192
  // @ts-ignore
73
- ast.chi.splice(i, 1);
193
+ ast.chi.splice(i--, 1);
194
+ // @ts-ignore
195
+ node = ast.chi[i];
74
196
  }
75
197
  else {
76
198
  // @ts-ignore
77
199
  ast.chi.splice(i, 1, intersect.node1);
200
+ node = intersect.node1;
78
201
  }
79
202
  if (intersect.node2.chi.length == 0) {
80
203
  // @ts-ignore
81
204
  ast.chi.splice(nodeIndex, 1, intersect.result);
205
+ previous = intersect.result;
82
206
  }
83
207
  else {
84
208
  // @ts-ignore
85
209
  ast.chi.splice(nodeIndex, 1, intersect.result, intersect.node2);
210
+ previous = intersect.result;
211
+ // @ts-ignore
212
+ i = nodeIndex;
86
213
  }
87
214
  }
88
215
  }
@@ -109,12 +236,24 @@ function deduplicate(ast, options = {}, recursive = false) {
109
236
  deduplicateRule(node);
110
237
  }
111
238
  else {
112
- deduplicate(node, options, recursive);
239
+ if (!(node.typ == 'AtRule' && node.nam != 'font-face')) {
240
+ deduplicate(node, options, recursive);
241
+ }
113
242
  }
114
243
  }
115
244
  }
116
245
  return ast;
117
246
  }
247
+ function hasOnlyDeclarations(node) {
248
+ let k = node.chi.length;
249
+ while (k--) {
250
+ if (node.chi[k].typ == 'Comment') {
251
+ continue;
252
+ }
253
+ return node.chi[k].typ == 'Declaration';
254
+ }
255
+ return true;
256
+ }
118
257
  function hasDeclaration(node) {
119
258
  // @ts-ignore
120
259
  for (let i = 0; i < node.chi?.length; i++) {
@@ -174,30 +313,6 @@ function deduplicateRule(ast, options = {}) {
174
313
  }
175
314
  // @ts-ignore
176
315
  ast.chi = children.concat(ast.chi?.slice(k));
177
- /*
178
- // @ts-ignore
179
-
180
- const properties: PropertyList = new PropertyList();
181
-
182
- for (; k < j; k++) {
183
-
184
- // @ts-ignore
185
- if ('Comment' == ast.chi[k].typ || 'Declaration' == ast.chi[k].typ) {
186
-
187
- // @ts-ignore
188
- properties.add(ast.chi[k]);
189
- continue;
190
- }
191
-
192
- break;
193
- }
194
-
195
- // @ts-ignore
196
- ast.chi = [...properties].concat(ast.chi.slice(k));
197
- */
198
- //
199
- // @ts-ignore
200
- // ast.chi.splice(0, k - 1, ...properties);
201
316
  return ast;
202
317
  }
203
318
  function splitRule(buffer) {
@@ -256,7 +371,6 @@ function splitRule(buffer) {
256
371
  }
257
372
  }
258
373
  i = k;
259
- continue;
260
374
  }
261
375
  }
262
376
  if (str !== '') {
@@ -264,6 +378,35 @@ function splitRule(buffer) {
264
378
  }
265
379
  return result;
266
380
  }
381
+ function reduceRuleSelector(node) {
382
+ // @ts-ignore
383
+ if (node.raw != null) {
384
+ // @ts-ignore
385
+ let optimized = reduceSelector(node.raw);
386
+ if (optimized != null) {
387
+ Object.defineProperty(node, 'optimized', { enumerable: false, writable: true, value: optimized });
388
+ }
389
+ if (optimized != null && optimized.match && optimized.reducible) {
390
+ const raw = [
391
+ [
392
+ optimized.optimized[0], ':is('
393
+ ].concat(optimized.selector.reduce((acc, curr) => {
394
+ if (acc.length > 0) {
395
+ acc.push(',');
396
+ }
397
+ acc.push(...curr);
398
+ return acc;
399
+ }, [])).concat(')')
400
+ ];
401
+ const sel = raw[0].join('');
402
+ if (sel.length < node.sel.length) {
403
+ node.sel = sel;
404
+ // node.raw = raw;
405
+ Object.defineProperty(node, 'raw', { enumerable: false, writable: true, value: raw });
406
+ }
407
+ }
408
+ }
409
+ }
267
410
  function diff(n1, n2, options = {}) {
268
411
  let node1 = n1;
269
412
  let node2 = n2;
@@ -280,8 +423,28 @@ function diff(n1, n2, options = {}) {
280
423
  // @ts-ignore
281
424
  return null;
282
425
  }
426
+ // @ts-ignore
427
+ const raw1 = node1.raw;
428
+ // @ts-ignore
429
+ const optimized1 = node1.optimized;
430
+ // @ts-ignore
431
+ const raw2 = node2.raw;
432
+ // @ts-ignore
433
+ const optimized2 = node2.optimized;
283
434
  node1 = { ...node1, chi: node1.chi.slice() };
284
435
  node2 = { ...node2, chi: node2.chi.slice() };
436
+ if (raw1 != null) {
437
+ Object.defineProperty(node1, 'raw', { enumerable: false, writable: true, value: raw1 });
438
+ }
439
+ if (optimized1 != null) {
440
+ Object.defineProperty(node1, 'optimized', { enumerable: false, writable: true, value: optimized1 });
441
+ }
442
+ if (raw2 != null) {
443
+ Object.defineProperty(node2, 'raw', { enumerable: false, writable: true, value: raw2 });
444
+ }
445
+ if (optimized2 != null) {
446
+ Object.defineProperty(node2, 'optimized', { enumerable: false, writable: true, value: optimized2 });
447
+ }
285
448
  const intersect = [];
286
449
  while (i--) {
287
450
  if (node1.chi[i].typ == 'Comment') {
@@ -309,7 +472,7 @@ function diff(n1, n2, options = {}) {
309
472
  const result = (intersect.length == 0 ? null : {
310
473
  ...node1,
311
474
  // @ts-ignore
312
- sel: [...new Set([...(n1.raw || splitRule(n1.sel)).concat(n2.raw || splitRule(n2.sel))])].join(),
475
+ sel: [...new Set([...(n1?.raw?.reduce(reducer, []) || splitRule(n1.sel)).concat(n2?.raw?.reduce(reducer, []) || splitRule(n2.sel))])].join(),
313
476
  chi: intersect.reverse()
314
477
  });
315
478
  if (result == null || [n1, n2].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + render(curr, options).code.length, 0) <= [node1, node2, result].reduce((acc, curr) => curr.chi.length == 0 ? acc : acc + render(curr, options).code.length, 0)) {
@@ -318,5 +481,62 @@ function diff(n1, n2, options = {}) {
318
481
  }
319
482
  return { result, node1: exchanged ? node2 : node1, node2: exchanged ? node2 : node2 };
320
483
  }
484
+ function reduceSelector(selector) {
485
+ if (selector.length < 2) {
486
+ return null;
487
+ }
488
+ const optimized = [];
489
+ const k = selector.reduce((acc, curr) => acc == 0 ? curr.length : (curr.length == 0 ? acc : Math.min(acc, curr.length)), 0);
490
+ let i = 0;
491
+ let j;
492
+ let match;
493
+ for (; i < k; i++) {
494
+ const item = selector[0][i];
495
+ match = true;
496
+ for (j = 1; j < selector.length; j++) {
497
+ if (item != selector[j][i]) {
498
+ match = false;
499
+ break;
500
+ }
501
+ }
502
+ if (!match) {
503
+ break;
504
+ }
505
+ optimized.push(item);
506
+ }
507
+ if (optimized.at(-1) == ' ') {
508
+ optimized.pop();
509
+ }
510
+ let reducible = optimized.length == 1;
511
+ if (optimized.length == 0) {
512
+ return { match: false, optimized, selector, reducible };
513
+ }
514
+ return {
515
+ match: true,
516
+ optimized,
517
+ selector: selector.reduce((acc, curr) => {
518
+ const slice = curr.slice(optimized.length);
519
+ // @ts-ignore
520
+ if (slice.length > 0 && slice[0] == ' ') {
521
+ slice.shift();
522
+ }
523
+ if (slice.length == 0) {
524
+ slice.push('&');
525
+ }
526
+ if (reducible) {
527
+ const chr = slice[0].charAt(0);
528
+ // @ts-ignore
529
+ reducible = chr == '.' || chr == ':' || isIdentStart(chr.codePointAt(0));
530
+ }
531
+ acc.push(slice);
532
+ return acc;
533
+ }, []),
534
+ reducible
535
+ };
536
+ }
537
+ function reducer(acc, curr) {
538
+ acc.push(curr.join(''));
539
+ return acc;
540
+ }
321
541
 
322
- export { deduplicate, deduplicateRule, hasDeclaration };
542
+ export { deduplicate, deduplicateRule, hasDeclaration, reduceSelector };