@tenphi/tasty 0.4.2 → 0.5.0

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.
@@ -1,4 +1,5 @@
1
1
  import { Lru } from "../parser/lru.js";
2
+ import { not } from "./conditions.js";
2
3
 
3
4
  //#region src/pipeline/materialize.ts
4
5
  /**
@@ -31,7 +32,7 @@ function emptyVariant() {
31
32
  containerConditions: [],
32
33
  supportsConditions: [],
33
34
  rootConditions: [],
34
- parentConditions: [],
35
+ parentGroups: [],
35
36
  startingStyle: false
36
37
  };
37
38
  }
@@ -65,36 +66,46 @@ function stateToCSS(state) {
65
66
  }),
66
67
  isImpossible: false
67
68
  };
68
- default: {
69
- const variant = emptyVariant();
70
- switch (state.type) {
71
- case "modifier":
72
- variant.modifierConditions.push(modifierToParsed(state));
73
- break;
74
- case "pseudo":
75
- variant.pseudoConditions.push(pseudoToParsed(state));
76
- break;
77
- case "container":
78
- variant.containerConditions.push(containerToParsed(state));
79
- break;
80
- case "supports":
81
- variant.supportsConditions.push(supportsToParsed(state));
82
- break;
83
- case "root":
84
- variant.rootConditions.push(rootToParsed(state));
85
- break;
86
- case "parent":
87
- variant.parentConditions.push(parentToParsed(state));
88
- break;
89
- case "own":
90
- variant.ownConditions.push(...ownToParsed(state));
91
- break;
92
- case "starting":
93
- variant.startingStyle = !state.negated;
94
- break;
95
- }
69
+ case "root": return innerConditionToVariants(state.innerCondition, state.negated ?? false, "rootConditions");
70
+ case "parent": return parentConditionToVariants(state.innerCondition, state.negated ?? false, state.direct);
71
+ case "own": return innerConditionToVariants(state.innerCondition, state.negated ?? false, "ownConditions");
72
+ case "modifier": {
73
+ const v = emptyVariant();
74
+ v.modifierConditions.push(modifierToParsed(state));
75
+ return {
76
+ variants: [v],
77
+ isImpossible: false
78
+ };
79
+ }
80
+ case "pseudo": {
81
+ const v = emptyVariant();
82
+ v.pseudoConditions.push(pseudoToParsed(state));
83
+ return {
84
+ variants: [v],
85
+ isImpossible: false
86
+ };
87
+ }
88
+ case "container": {
89
+ const v = emptyVariant();
90
+ v.containerConditions.push(containerToParsed(state));
96
91
  return {
97
- variants: [variant],
92
+ variants: [v],
93
+ isImpossible: false
94
+ };
95
+ }
96
+ case "supports": {
97
+ const v = emptyVariant();
98
+ v.supportsConditions.push(supportsToParsed(state));
99
+ return {
100
+ variants: [v],
101
+ isImpossible: false
102
+ };
103
+ }
104
+ case "starting": {
105
+ const v = emptyVariant();
106
+ v.startingStyle = !state.negated;
107
+ return {
108
+ variants: [v],
98
109
  isImpossible: false
99
110
  };
100
111
  }
@@ -233,12 +244,92 @@ function supportsToParsed(state) {
233
244
  };
234
245
  }
235
246
  /**
236
- * Convert root condition to parsed structure
247
+ * Collect all modifier and pseudo conditions from a variant as a flat array.
237
248
  */
238
- function rootToParsed(state) {
249
+ function collectSelectorConditions(variant) {
250
+ return [...variant.modifierConditions, ...variant.pseudoConditions];
251
+ }
252
+ /**
253
+ * Convert an inner condition tree into SelectorVariants.
254
+ * Each inner OR branch becomes a separate variant, preserving disjunction.
255
+ * Shared by @root() and @own().
256
+ */
257
+ function innerConditionToVariants(innerCondition, negated, target) {
258
+ const innerCSS = conditionToCSS(negated ? not(innerCondition) : innerCondition);
259
+ if (innerCSS.isImpossible || innerCSS.variants.length === 0) return {
260
+ variants: [],
261
+ isImpossible: true
262
+ };
263
+ const variants = [];
264
+ for (const innerVariant of innerCSS.variants) {
265
+ const conditions = collectSelectorConditions(innerVariant);
266
+ if (conditions.length > 0) {
267
+ const v = emptyVariant();
268
+ v[target].push(...conditions);
269
+ variants.push(v);
270
+ }
271
+ }
272
+ if (variants.length === 0) return {
273
+ variants: [emptyVariant()],
274
+ isImpossible: false
275
+ };
239
276
  return {
240
- selector: state.selector,
241
- negated: state.negated ?? false
277
+ variants,
278
+ isImpossible: false
279
+ };
280
+ }
281
+ /**
282
+ * Convert a @parent() inner condition into SelectorVariants with ParentGroups.
283
+ *
284
+ * Positive: each inner OR branch becomes a separate variant with one :is() group.
285
+ * Negated: !(A | B) = !A & !B — all branches become :not() groups collected
286
+ * into a single variant so they produce :not([a] *):not([b] *) on one element.
287
+ */
288
+ function parentConditionToVariants(innerCondition, negated, direct) {
289
+ const innerCSS = conditionToCSS(innerCondition);
290
+ if (innerCSS.isImpossible || innerCSS.variants.length === 0) return {
291
+ variants: [],
292
+ isImpossible: true
293
+ };
294
+ if (negated) {
295
+ const v = emptyVariant();
296
+ for (const innerVariant of innerCSS.variants) {
297
+ const conditions = collectSelectorConditions(innerVariant);
298
+ if (conditions.length > 0) v.parentGroups.push({
299
+ conditions,
300
+ direct,
301
+ negated: true
302
+ });
303
+ }
304
+ if (v.parentGroups.length === 0) return {
305
+ variants: [emptyVariant()],
306
+ isImpossible: false
307
+ };
308
+ return {
309
+ variants: [v],
310
+ isImpossible: false
311
+ };
312
+ }
313
+ const variants = [];
314
+ for (const innerVariant of innerCSS.variants) {
315
+ const conditions = collectSelectorConditions(innerVariant);
316
+ if (conditions.length > 0) {
317
+ const v = emptyVariant();
318
+ v.parentGroups.push({
319
+ conditions,
320
+ direct,
321
+ negated: false
322
+ });
323
+ variants.push(v);
324
+ }
325
+ }
326
+ if (variants.length === 0) return {
327
+ variants: [emptyVariant()],
328
+ isImpossible: false
329
+ };
330
+ return {
331
+ variants,
332
+ isImpossible: false
242
333
  };
243
334
  }
244
335
  /**
@@ -247,49 +338,30 @@ function rootToParsed(state) {
247
338
  function rootConditionsToCSS(roots) {
248
339
  if (roots.length === 0) return void 0;
249
340
  let prefix = ":root";
250
- for (const root of roots) if (root.negated) prefix += `:not(${root.selector})`;
251
- else prefix += root.selector;
341
+ for (const cond of roots) prefix += selectorConditionToCSS(cond);
252
342
  return prefix;
253
343
  }
254
344
  /**
255
- * Convert parent condition to parsed structure
345
+ * Convert parent groups to CSS selector fragments (for final output).
346
+ * Each group produces its own :is() wrapper.
256
347
  */
257
- function parentToParsed(state) {
258
- return {
259
- selector: state.selector,
260
- direct: state.direct,
261
- negated: state.negated ?? false
262
- };
348
+ function parentGroupsToCSS(groups) {
349
+ let result = "";
350
+ for (const group of groups) {
351
+ const combinator = group.direct ? " > *" : " *";
352
+ let parts = "";
353
+ for (const cond of group.conditions) parts += selectorConditionToCSS(cond);
354
+ const wrapper = group.negated ? ":not" : ":is";
355
+ result += `${wrapper}(${parts}${combinator})`;
356
+ }
357
+ return result;
263
358
  }
264
359
  /**
265
- * Convert parsed parent condition to CSS selector fragment (for final output)
266
- *
267
- * Positive: :is([selector] *) or :is([selector] > *)
268
- * Negative: :not([selector] *) or :not([selector] > *)
360
+ * Convert a modifier or pseudo condition to a CSS selector fragment
269
361
  */
270
- function parentToCSS(parent) {
271
- const combinator = parent.direct ? " > *" : " *";
272
- if (parent.negated) return `:not(${parent.selector}${combinator})`;
273
- return `:is(${parent.selector}${combinator})`;
274
- }
275
- /**
276
- * Convert own condition to parsed structures for sub-element
277
- */
278
- function ownToParsed(state) {
279
- const innerCSS = conditionToCSS(state.innerCondition);
280
- if (innerCSS.isImpossible || innerCSS.variants.length === 0) return [];
281
- const allConditions = [];
282
- for (const variant of innerCSS.variants) {
283
- for (const mod of variant.modifierConditions) allConditions.push({
284
- ...mod,
285
- negated: state.negated ? !mod.negated : mod.negated
286
- });
287
- for (const pseudo of variant.pseudoConditions) allConditions.push({
288
- ...pseudo,
289
- negated: state.negated ? !pseudo.negated : pseudo.negated
290
- });
291
- }
292
- return allConditions;
362
+ function selectorConditionToCSS(cond) {
363
+ if ("attribute" in cond) return modifierToCSS(cond);
364
+ return pseudoToCSS(cond);
293
365
  }
294
366
  /**
295
367
  * Get unique key for a modifier condition
@@ -305,91 +377,48 @@ function getPseudoKey(pseudo) {
305
377
  return pseudo.negated ? `!${pseudo.pseudo}` : pseudo.pseudo;
306
378
  }
307
379
  /**
308
- * Get unique key for a root condition
309
- */
310
- function getRootKey(root) {
311
- return root.negated ? `!${root.selector}` : root.selector;
312
- }
313
- /**
314
- * Deduplicate modifier conditions
315
- */
316
- function dedupeModifierConditions(conditions) {
317
- const seen = /* @__PURE__ */ new Set();
318
- const result = [];
319
- for (const c of conditions) {
320
- const key = getModifierKey(c);
321
- if (!seen.has(key)) {
322
- seen.add(key);
323
- result.push(c);
324
- }
325
- }
326
- return result;
327
- }
328
- /**
329
- * Deduplicate pseudo conditions
380
+ * Get unique key for any selector condition (modifier or pseudo)
330
381
  */
331
- function dedupePseudoConditions(conditions) {
332
- const seen = /* @__PURE__ */ new Set();
333
- const result = [];
334
- for (const c of conditions) {
335
- const key = getPseudoKey(c);
336
- if (!seen.has(key)) {
337
- seen.add(key);
338
- result.push(c);
339
- }
340
- }
341
- return result;
382
+ function getSelectorConditionKey(cond) {
383
+ return "attribute" in cond ? `mod:${getModifierKey(cond)}` : `pseudo:${getPseudoKey(cond)}`;
342
384
  }
343
385
  /**
344
- * Deduplicate root conditions
386
+ * Deduplicate selector conditions (modifiers or pseudos).
387
+ * Shared by root, parent, and own conditions.
345
388
  */
346
- function dedupeRootConditions(conditions) {
389
+ function dedupeSelectorConditions(conditions) {
347
390
  const seen = /* @__PURE__ */ new Set();
348
- const result = [];
391
+ let result = [];
349
392
  for (const c of conditions) {
350
- const key = getRootKey(c);
393
+ const key = getSelectorConditionKey(c);
351
394
  if (!seen.has(key)) {
352
395
  seen.add(key);
353
396
  result.push(c);
354
397
  }
355
398
  }
356
- return result;
357
- }
358
- /**
359
- * Get unique key for a parent condition
360
- */
361
- function getParentKey(parent) {
362
- const base = `${parent.direct ? ">" : ""}${parent.selector}`;
363
- return parent.negated ? `!${base}` : base;
364
- }
365
- /**
366
- * Deduplicate parent conditions
367
- */
368
- function dedupeParentConditions(conditions) {
369
- const seen = /* @__PURE__ */ new Set();
370
- const result = [];
371
- for (const c of conditions) {
372
- const key = getParentKey(c);
373
- if (!seen.has(key)) {
374
- seen.add(key);
375
- result.push(c);
376
- }
377
- }
378
- return result;
379
- }
380
- /**
381
- * Deduplicate own conditions (modifiers or pseudos)
382
- */
383
- function dedupeOwnConditions(conditions) {
384
- const seen = /* @__PURE__ */ new Set();
385
- const result = [];
386
- for (const c of conditions) {
387
- const key = "attribute" in c ? `mod:${getModifierKey(c)}` : `pseudo:${getPseudoKey(c)}`;
388
- if (!seen.has(key)) {
389
- seen.add(key);
390
- result.push(c);
399
+ const negatedBooleanAttrs = /* @__PURE__ */ new Set();
400
+ const positiveExactValuesByAttr = /* @__PURE__ */ new Map();
401
+ for (const c of result) {
402
+ if (!("attribute" in c)) continue;
403
+ if (c.negated && c.value === void 0) negatedBooleanAttrs.add(c.attribute);
404
+ const op = c.operator ?? "=";
405
+ if (!c.negated && c.value !== void 0 && op === "=") {
406
+ let values = positiveExactValuesByAttr.get(c.attribute);
407
+ if (!values) {
408
+ values = /* @__PURE__ */ new Set();
409
+ positiveExactValuesByAttr.set(c.attribute, values);
410
+ }
411
+ values.add(c.value);
391
412
  }
392
413
  }
414
+ result = result.filter((c) => {
415
+ if (!("attribute" in c) || !c.negated || c.value === void 0) return true;
416
+ if (negatedBooleanAttrs.has(c.attribute)) return false;
417
+ if ((c.operator ?? "=") !== "=") return true;
418
+ const positiveValues = positiveExactValuesByAttr.get(c.attribute);
419
+ if (positiveValues !== void 0 && positiveValues.size === 1 && !positiveValues.has(c.value)) return false;
420
+ return true;
421
+ });
393
422
  return result;
394
423
  }
395
424
  /**
@@ -418,34 +447,10 @@ function hasPseudoContradiction(conditions) {
418
447
  return false;
419
448
  }
420
449
  /**
421
- * Check for root condition contradiction: same selector with opposite negation
450
+ * Check for selector condition contradiction (modifier or pseudo with opposite negation).
451
+ * Shared by root, parent, and own conditions.
422
452
  */
423
- function hasRootContradiction(conditions) {
424
- const byKey = /* @__PURE__ */ new Map();
425
- for (const root of conditions) {
426
- const existing = byKey.get(root.selector);
427
- if (existing !== void 0 && existing !== !root.negated) return true;
428
- byKey.set(root.selector, !root.negated);
429
- }
430
- return false;
431
- }
432
- /**
433
- * Check for parent condition contradiction: same selector+direct with opposite negation
434
- */
435
- function hasParentContradiction(conditions) {
436
- const byKey = /* @__PURE__ */ new Map();
437
- for (const parent of conditions) {
438
- const baseKey = `${parent.direct ? ">" : ""}${parent.selector}`;
439
- const existing = byKey.get(baseKey);
440
- if (existing !== void 0 && existing !== !parent.negated) return true;
441
- byKey.set(baseKey, !parent.negated);
442
- }
443
- return false;
444
- }
445
- /**
446
- * Check for own condition contradiction
447
- */
448
- function hasOwnConditionContradiction(conditions) {
453
+ function hasSelectorConditionContradiction(conditions) {
449
454
  const modifiers = [];
450
455
  const pseudos = [];
451
456
  for (const c of conditions) if ("attribute" in c) modifiers.push(c);
@@ -453,22 +458,36 @@ function hasOwnConditionContradiction(conditions) {
453
458
  return hasModifierContradiction(modifiers) || hasPseudoContradiction(pseudos);
454
459
  }
455
460
  /**
461
+ * Check for parent group contradiction: same target (direct + conditions)
462
+ * with opposite negation. E.g. :not([data-hovered] *) and :is([data-hovered] *)
463
+ * in the same variant is impossible.
464
+ */
465
+ function hasParentGroupContradiction(groups) {
466
+ const byBaseKey = /* @__PURE__ */ new Map();
467
+ for (const g of groups) {
468
+ const baseKey = `${g.direct ? ">" : ""}(${g.conditions.map(getSelectorConditionKey).sort().join(",")})`;
469
+ const existing = byBaseKey.get(baseKey);
470
+ if (existing !== void 0 && existing !== !g.negated) return true;
471
+ byBaseKey.set(baseKey, !g.negated);
472
+ }
473
+ return false;
474
+ }
475
+ /**
456
476
  * Merge two selector variants (AND operation)
457
477
  * Deduplicates conditions and checks for contradictions
458
478
  */
459
479
  function mergeVariants(a, b) {
460
480
  const mergedMedia = dedupeMediaConditions([...a.mediaConditions, ...b.mediaConditions]);
461
481
  if (hasMediaContradiction(mergedMedia)) return null;
462
- const mergedRoots = dedupeRootConditions([...a.rootConditions, ...b.rootConditions]);
463
- if (hasRootContradiction(mergedRoots)) return null;
464
- const mergedModifiers = dedupeModifierConditions([...a.modifierConditions, ...b.modifierConditions]);
465
- if (hasModifierContradiction(mergedModifiers)) return null;
466
- const mergedPseudos = dedupePseudoConditions([...a.pseudoConditions, ...b.pseudoConditions]);
467
- if (hasPseudoContradiction(mergedPseudos)) return null;
468
- const mergedParents = dedupeParentConditions([...a.parentConditions, ...b.parentConditions]);
469
- if (hasParentContradiction(mergedParents)) return null;
470
- const mergedOwn = dedupeOwnConditions([...a.ownConditions, ...b.ownConditions]);
471
- if (hasOwnConditionContradiction(mergedOwn)) return null;
482
+ const mergedRoots = dedupeSelectorConditions([...a.rootConditions, ...b.rootConditions]);
483
+ if (hasSelectorConditionContradiction(mergedRoots)) return null;
484
+ const mergedModifiers = dedupeSelectorConditions([...a.modifierConditions, ...b.modifierConditions]);
485
+ const mergedPseudos = dedupeSelectorConditions([...a.pseudoConditions, ...b.pseudoConditions]);
486
+ if (hasSelectorConditionContradiction([...mergedModifiers, ...mergedPseudos])) return null;
487
+ const mergedParentGroups = [...a.parentGroups, ...b.parentGroups];
488
+ if (hasParentGroupContradiction(mergedParentGroups)) return null;
489
+ const mergedOwn = dedupeSelectorConditions([...a.ownConditions, ...b.ownConditions]);
490
+ if (hasSelectorConditionContradiction(mergedOwn)) return null;
472
491
  const mergedContainers = dedupeContainerConditions([...a.containerConditions, ...b.containerConditions]);
473
492
  if (hasContainerStyleContradiction(mergedContainers)) return null;
474
493
  const mergedSupports = dedupeSupportsConditions([...a.supportsConditions, ...b.supportsConditions]);
@@ -481,7 +500,7 @@ function mergeVariants(a, b) {
481
500
  containerConditions: mergedContainers,
482
501
  supportsConditions: mergedSupports,
483
502
  rootConditions: mergedRoots,
484
- parentConditions: mergedParents,
503
+ parentGroups: mergedParentGroups,
485
504
  startingStyle: a.startingStyle || b.startingStyle
486
505
  };
487
506
  }
@@ -631,7 +650,7 @@ function hasContainerStyleContradiction(conditions) {
631
650
  function getVariantKey(v) {
632
651
  const modifierKey = v.modifierConditions.map(getModifierKey).sort().join("|");
633
652
  const pseudoKey = v.pseudoConditions.map(getPseudoKey).sort().join("|");
634
- const ownKey = v.ownConditions.map((c) => "attribute" in c ? `mod:${getModifierKey(c)}` : `pseudo:${getPseudoKey(c)}`).sort().join("|");
653
+ const ownKey = v.ownConditions.map(getSelectorConditionKey).sort().join("|");
635
654
  const containerKey = v.containerConditions.map((c) => `${c.name ?? ""}:${c.negated ? "!" : ""}${c.condition}`).sort().join("|");
636
655
  return [
637
656
  modifierKey,
@@ -640,8 +659,8 @@ function getVariantKey(v) {
640
659
  v.mediaConditions.map((c) => `${c.subtype}:${c.negated ? "!" : ""}${c.condition}`).sort().join("|"),
641
660
  containerKey,
642
661
  v.supportsConditions.map((c) => `${c.subtype}:${c.negated ? "!" : ""}${c.condition}`).sort().join("|"),
643
- v.rootConditions.map(getRootKey).sort().join("|"),
644
- v.parentConditions.map(getParentKey).sort().join("|"),
662
+ v.rootConditions.map(getSelectorConditionKey).sort().join("|"),
663
+ v.parentGroups.map(getParentGroupKey).sort().join("|"),
645
664
  v.startingStyle ? "1" : "0"
646
665
  ].join("###");
647
666
  }
@@ -658,15 +677,16 @@ function getVariantKey(v) {
658
677
  */
659
678
  function isVariantSuperset(a, b) {
660
679
  if (a.startingStyle !== b.startingStyle) return false;
661
- if (!isRootConditionsSuperset(a.rootConditions, b.rootConditions)) return false;
680
+ if (!isSelectorConditionsSuperset(a.rootConditions, b.rootConditions)) return false;
662
681
  if (!isMediaConditionsSuperset(a.mediaConditions, b.mediaConditions)) return false;
663
682
  if (!isContainerConditionsSuperset(a.containerConditions, b.containerConditions)) return false;
664
683
  if (!isSupportsConditionsSuperset(a.supportsConditions, b.supportsConditions)) return false;
665
684
  if (!isModifierConditionsSuperset(a.modifierConditions, b.modifierConditions)) return false;
666
685
  if (!isPseudoConditionsSuperset(a.pseudoConditions, b.pseudoConditions)) return false;
667
- if (!isOwnConditionsSuperset(a.ownConditions, b.ownConditions)) return false;
668
- if (!isParentConditionsSuperset(a.parentConditions, b.parentConditions)) return false;
669
- return a.mediaConditions.length + a.containerConditions.length + a.supportsConditions.length + a.modifierConditions.length + a.pseudoConditions.length + a.rootConditions.length + a.parentConditions.length + a.ownConditions.length > b.mediaConditions.length + b.containerConditions.length + b.supportsConditions.length + b.modifierConditions.length + b.pseudoConditions.length + b.rootConditions.length + b.parentConditions.length + b.ownConditions.length;
686
+ if (!isSelectorConditionsSuperset(a.ownConditions, b.ownConditions)) return false;
687
+ if (!isParentGroupsSuperset(a.parentGroups, b.parentGroups)) return false;
688
+ const parentConditionCount = (groups) => groups.reduce((sum, g) => sum + g.conditions.length, 0);
689
+ return a.mediaConditions.length + a.containerConditions.length + a.supportsConditions.length + a.modifierConditions.length + a.pseudoConditions.length + a.rootConditions.length + parentConditionCount(a.parentGroups) + a.ownConditions.length > b.mediaConditions.length + b.containerConditions.length + b.supportsConditions.length + b.modifierConditions.length + b.pseudoConditions.length + b.rootConditions.length + parentConditionCount(b.parentGroups) + b.ownConditions.length;
670
690
  }
671
691
  /**
672
692
  * Check if media conditions A is a superset of B
@@ -718,31 +738,26 @@ function isPseudoConditionsSuperset(a, b) {
718
738
  return true;
719
739
  }
720
740
  /**
721
- * Check if root conditions A is a superset of B
741
+ * Check if selector conditions A is a superset of B.
742
+ * Shared by root and own conditions.
722
743
  */
723
- function isRootConditionsSuperset(a, b) {
724
- const aKeys = new Set(a.map(getRootKey));
725
- for (const c of b) if (!aKeys.has(getRootKey(c))) return false;
744
+ function isSelectorConditionsSuperset(a, b) {
745
+ const aKeys = new Set(a.map(getSelectorConditionKey));
746
+ for (const c of b) if (!aKeys.has(getSelectorConditionKey(c))) return false;
726
747
  return true;
727
748
  }
728
749
  /**
729
- * Check if parent conditions A is a superset of B
750
+ * Check if parent groups A is a superset of B.
751
+ * Each group in B must have a matching group in A.
730
752
  */
731
- function isParentConditionsSuperset(a, b) {
732
- const aKeys = new Set(a.map(getParentKey));
733
- for (const c of b) if (!aKeys.has(getParentKey(c))) return false;
753
+ function isParentGroupsSuperset(a, b) {
754
+ if (a.length < b.length) return false;
755
+ const aKeys = new Set(a.map(getParentGroupKey));
756
+ for (const g of b) if (!aKeys.has(getParentGroupKey(g))) return false;
734
757
  return true;
735
758
  }
736
- /**
737
- * Check if own conditions A is a superset of B
738
- */
739
- function isOwnConditionsSuperset(a, b) {
740
- const aKeys = new Set(a.map((c) => "attribute" in c ? `mod:${getModifierKey(c)}` : `pseudo:${getPseudoKey(c)}`));
741
- for (const c of b) {
742
- const key = "attribute" in c ? `mod:${getModifierKey(c)}` : `pseudo:${getPseudoKey(c)}`;
743
- if (!aKeys.has(key)) return false;
744
- }
745
- return true;
759
+ function getParentGroupKey(g) {
760
+ return `${g.negated ? "!" : ""}${g.direct ? ">" : ""}(${g.conditions.map(getSelectorConditionKey).sort().join(",")})`;
746
761
  }
747
762
  /**
748
763
  * Deduplicate variants
@@ -761,9 +776,8 @@ function dedupeVariants(variants) {
761
776
  result.push(v);
762
777
  }
763
778
  }
764
- result.sort((a, b) => {
765
- return a.modifierConditions.length + a.pseudoConditions.length + a.ownConditions.length + a.mediaConditions.length + a.containerConditions.length + a.supportsConditions.length + a.rootConditions.length + a.parentConditions.length - (b.modifierConditions.length + b.pseudoConditions.length + b.ownConditions.length + b.mediaConditions.length + b.containerConditions.length + b.supportsConditions.length + b.rootConditions.length + b.parentConditions.length);
766
- });
779
+ const variantConditionCount = (v) => v.modifierConditions.length + v.pseudoConditions.length + v.ownConditions.length + v.mediaConditions.length + v.containerConditions.length + v.supportsConditions.length + v.rootConditions.length + v.parentGroups.reduce((sum, g) => sum + g.conditions.length, 0);
780
+ result.sort((a, b) => variantConditionCount(a) - variantConditionCount(b));
767
781
  const filtered = [];
768
782
  for (const candidate of result) {
769
783
  let isRedundant = false;
@@ -890,5 +904,5 @@ function buildAtRulesFromVariant(variant) {
890
904
  }
891
905
 
892
906
  //#endregion
893
- export { buildAtRulesFromVariant, conditionToCSS, modifierToCSS, parentToCSS, pseudoToCSS, rootConditionsToCSS };
907
+ export { buildAtRulesFromVariant, conditionToCSS, modifierToCSS, parentGroupsToCSS, pseudoToCSS, rootConditionsToCSS, selectorConditionToCSS };
894
908
  //# sourceMappingURL=materialize.js.map