@master/css 2.0.0-rc.61 → 2.0.0-rc.62

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/animation-rule.cjs +24 -0
  2. package/dist/animation-rule.d.ts +11 -0
  3. package/dist/animation-rule.mjs +22 -0
  4. package/dist/common.cjs +50 -1
  5. package/dist/common.d.ts +14 -0
  6. package/dist/common.mjs +45 -2
  7. package/dist/config/at.cjs +13 -10
  8. package/dist/config/at.d.ts +4 -1
  9. package/dist/config/at.mjs +13 -10
  10. package/dist/config/index.cjs +3 -0
  11. package/dist/config/index.d.ts +2 -1
  12. package/dist/config/index.mjs +3 -1
  13. package/dist/config/modes.d.ts +4 -2
  14. package/dist/config/rules.cjs +25 -13
  15. package/dist/config/rules.d.ts +4 -2
  16. package/dist/config/rules.mjs +25 -13
  17. package/dist/config/screens.cjs +17 -0
  18. package/dist/config/screens.d.ts +14 -0
  19. package/dist/config/screens.mjs +15 -0
  20. package/dist/config/selectors.cjs +11 -15
  21. package/dist/config/selectors.d.ts +10 -8
  22. package/dist/config/selectors.mjs +11 -15
  23. package/dist/config/utilities.cjs +3 -0
  24. package/dist/config/utilities.d.ts +3 -0
  25. package/dist/config/utilities.mjs +3 -0
  26. package/dist/config/variables.cjs +0 -13
  27. package/dist/config/variables.d.ts +0 -13
  28. package/dist/config/variables.mjs +0 -13
  29. package/dist/core.cjs +438 -476
  30. package/dist/core.d.ts +13 -4
  31. package/dist/core.mjs +438 -476
  32. package/dist/factories/with-syntax-layer.cjs +37 -260
  33. package/dist/factories/with-syntax-layer.mjs +37 -260
  34. package/dist/index.cjs +38 -12
  35. package/dist/index.d.ts +19 -7
  36. package/dist/index.mjs +17 -7
  37. package/dist/layer.cjs +11 -7
  38. package/dist/layer.d.ts +4 -3
  39. package/dist/layer.mjs +11 -7
  40. package/dist/non-layer.cjs +10 -17
  41. package/dist/non-layer.d.ts +1 -1
  42. package/dist/non-layer.mjs +10 -17
  43. package/dist/rule.cjs +4 -6
  44. package/dist/rule.d.ts +3 -10
  45. package/dist/rule.mjs +4 -6
  46. package/dist/syntax-rule-type.cjs +7 -8
  47. package/dist/syntax-rule-type.d.ts +7 -7
  48. package/dist/syntax-rule-type.mjs +7 -8
  49. package/dist/syntax-rule.cjs +116 -328
  50. package/dist/syntax-rule.d.ts +18 -25
  51. package/dist/syntax-rule.mjs +117 -329
  52. package/dist/types/common.d.ts +2 -0
  53. package/dist/types/config.d.ts +12 -7
  54. package/dist/types/syntax.d.ts +5 -24
  55. package/dist/utils/compare-rule-priority.cjs +143 -0
  56. package/dist/utils/compare-rule-priority.d.ts +7 -0
  57. package/dist/utils/compare-rule-priority.mjs +138 -0
  58. package/dist/utils/equal-at-rules.cjs +22 -0
  59. package/dist/utils/equal-at-rules.d.ts +2 -0
  60. package/dist/utils/equal-at-rules.mjs +20 -0
  61. package/dist/utils/equal-declarations.cjs +10 -0
  62. package/dist/utils/equal-declarations.d.ts +2 -0
  63. package/dist/utils/equal-declarations.mjs +8 -0
  64. package/dist/utils/equal-selectors.cjs +70 -0
  65. package/dist/utils/equal-selectors.d.ts +2 -0
  66. package/dist/utils/equal-selectors.mjs +68 -0
  67. package/dist/utils/equal-variants.cjs +10 -0
  68. package/dist/utils/equal-variants.d.ts +2 -0
  69. package/dist/utils/equal-variants.mjs +8 -0
  70. package/dist/utils/extend-config.cjs +0 -1
  71. package/dist/utils/extend-config.mjs +0 -1
  72. package/dist/utils/generate-at.cjs +30 -0
  73. package/dist/utils/generate-at.d.ts +2 -0
  74. package/dist/utils/generate-at.mjs +28 -0
  75. package/dist/utils/generate-selector.cjs +49 -0
  76. package/dist/utils/generate-selector.d.ts +2 -0
  77. package/dist/utils/generate-selector.mjs +47 -0
  78. package/dist/utils/get-single-at-number-rule-node.cjs +9 -0
  79. package/dist/utils/get-single-at-number-rule-node.d.ts +2 -0
  80. package/dist/utils/get-single-at-number-rule-node.mjs +7 -0
  81. package/dist/utils/parse-at.cjs +157 -0
  82. package/dist/utils/parse-at.d.ts +39 -0
  83. package/dist/utils/parse-at.mjs +155 -0
  84. package/dist/utils/parse-pair.cjs +51 -0
  85. package/dist/utils/parse-pair.d.ts +8 -0
  86. package/dist/utils/parse-pair.mjs +49 -0
  87. package/dist/utils/parse-selector.cjs +112 -0
  88. package/dist/utils/parse-selector.d.ts +19 -0
  89. package/dist/utils/parse-selector.mjs +110 -0
  90. package/dist/utils/parse-value.cjs +39 -0
  91. package/dist/utils/parse-value.d.ts +2 -0
  92. package/dist/utils/parse-value.mjs +37 -0
  93. package/dist/utils/replace-char-outside-quotes.cjs +21 -0
  94. package/dist/utils/replace-char-outside-quotes.d.ts +1 -0
  95. package/dist/utils/replace-char-outside-quotes.mjs +19 -0
  96. package/dist/utils/sort-readable-classes.cjs +74 -0
  97. package/dist/utils/{reorder-for-readable-classes.d.ts → sort-readable-classes.d.ts} +1 -1
  98. package/dist/utils/sort-readable-classes.mjs +72 -0
  99. package/dist/utils/split-char-outside-quotes.cjs +29 -0
  100. package/dist/utils/split-char-outside-quotes.d.ts +1 -0
  101. package/dist/utils/split-char-outside-quotes.mjs +27 -0
  102. package/dist/variable-rule.cjs +86 -0
  103. package/dist/variable-rule.d.ts +23 -0
  104. package/dist/variable-rule.mjs +81 -0
  105. package/package.json +1 -1
  106. package/dist/rule-node.cjs +0 -18
  107. package/dist/rule-node.d.ts +0 -14
  108. package/dist/rule-node.mjs +0 -16
  109. package/dist/utils/are-rule-at-equal.cjs +0 -12
  110. package/dist/utils/are-rule-at-equal.d.ts +0 -2
  111. package/dist/utils/are-rule-at-equal.mjs +0 -10
  112. package/dist/utils/are-rule-modes-equal.cjs +0 -7
  113. package/dist/utils/are-rule-modes-equal.d.ts +0 -2
  114. package/dist/utils/are-rule-modes-equal.mjs +0 -5
  115. package/dist/utils/are-rule-selectors-equal.cjs +0 -29
  116. package/dist/utils/are-rule-selectors-equal.d.ts +0 -2
  117. package/dist/utils/are-rule-selectors-equal.mjs +0 -27
  118. package/dist/utils/are-rule-states-equal.cjs +0 -11
  119. package/dist/utils/are-rule-states-equal.d.ts +0 -2
  120. package/dist/utils/are-rule-states-equal.mjs +0 -9
  121. package/dist/utils/are-rules-duplicated.cjs +0 -17
  122. package/dist/utils/are-rules-duplicated.d.ts +0 -2
  123. package/dist/utils/are-rules-duplicated.mjs +0 -15
  124. package/dist/utils/reorder-for-readable-classes.cjs +0 -62
  125. package/dist/utils/reorder-for-readable-classes.mjs +0 -60
@@ -0,0 +1,143 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ // ✅ Pseudo-class priority (lower = weaker)
6
+ const selectorPriority = {
7
+ hover: 1,
8
+ focus: 2,
9
+ active: 3,
10
+ disabled: 4
11
+ };
12
+ function extractSelectorPriority(nodes = []) {
13
+ let priority = 0;
14
+ for (const node of nodes){
15
+ if ('value' in node && typeof node.value === 'string') {
16
+ priority += selectorPriority[node.value] ?? 0;
17
+ }
18
+ if ('children' in node && Array.isArray(node.children)) {
19
+ priority += extractSelectorPriority(node.children);
20
+ }
21
+ }
22
+ return priority;
23
+ }
24
+ const NOT_COMPARISON_OPERATORS = {
25
+ '>=': '<',
26
+ '<=': '>',
27
+ '>': '<=',
28
+ '<': '>='
29
+ };
30
+ function getAtRuleEntries(nestNodes) {
31
+ const featureMap = new Map();
32
+ const walk = (list, isOutsideNot = false)=>{
33
+ (list ?? []).forEach((node, i, arr)=>{
34
+ const prev = arr[i - 1];
35
+ if ('operator' in node) {
36
+ const entry = featureMap.get(node.name) ?? {};
37
+ let operator = node.operator;
38
+ if (isOutsideNot) operator = NOT_COMPARISON_OPERATORS[operator];
39
+ if (prev?.type === 'logical' && prev.value === 'not') operator = NOT_COMPARISON_OPERATORS[operator];
40
+ switch(operator){
41
+ case '>':
42
+ entry.min = node.value + 0.02;
43
+ break;
44
+ case '>=':
45
+ entry.min = node.value;
46
+ break;
47
+ case '<':
48
+ entry.max = node.value - 0.02;
49
+ break;
50
+ case '<=':
51
+ entry.max = node.value;
52
+ break;
53
+ }
54
+ featureMap.set(node.name, entry);
55
+ }
56
+ if ('children' in node && Array.isArray(node.children)) {
57
+ walk(node.children, prev?.type === 'logical' && prev.value === 'not');
58
+ }
59
+ });
60
+ };
61
+ walk(nestNodes);
62
+ return featureMap;
63
+ }
64
+ // ✅ Calculate RulePriority from AST
65
+ function calcRulePriority(rule) {
66
+ const features = [];
67
+ const extractFeatures = (nodes)=>{
68
+ const featureMap = getAtRuleEntries(nodes);
69
+ for (const [name, entry] of featureMap.entries()){
70
+ const max = entry.max ?? Number.MAX_SAFE_INTEGER;
71
+ const min = entry.min ?? 0;
72
+ features.push([
73
+ name,
74
+ min,
75
+ max
76
+ ]);
77
+ }
78
+ };
79
+ if (rule.atRules?.media) extractFeatures(rule.atRules.media);
80
+ if (rule.atRules?.container) extractFeatures(rule.atRules.container);
81
+ features.sort(([a], [b])=>a.localeCompare(b, undefined, {
82
+ numeric: true
83
+ }));
84
+ const selector = extractSelectorPriority(rule.selectorNodes ?? []);
85
+ return {
86
+ features,
87
+ selector
88
+ };
89
+ }
90
+ function compareFeatureTuples(a, b) {
91
+ const len = Math.max(a.length, b.length);
92
+ for(let i = 0; i < len; i++){
93
+ const aa = a[i];
94
+ const bb = b[i];
95
+ if (!aa) return -1;
96
+ if (!bb) return 1;
97
+ const [nameA, minA, maxA] = aa;
98
+ const [nameB, minB, maxB] = bb;
99
+ const nameCmp = nameA.localeCompare(nameB, undefined, {
100
+ numeric: true
101
+ });
102
+ if (nameCmp !== 0) return nameCmp;
103
+ const rangeA = maxA - minA;
104
+ const rangeB = maxB - minB;
105
+ if (rangeA !== rangeB) return rangeB - rangeA;
106
+ if (minA !== minB) return minB - minA;
107
+ if (maxA !== maxB) return maxB - maxA;
108
+ }
109
+ return 0;
110
+ }
111
+ // ✅ Compare function
112
+ function compareRulePriority(a, b) {
113
+ const getTier = (rule)=>{
114
+ const hasSelector = rule.selectorNodes?.length;
115
+ const hasAtRules = !!rule.atRules;
116
+ const hasMode = !!rule.mode;
117
+ if (hasAtRules) return 3;
118
+ if (hasMode) return 2;
119
+ if (hasSelector) return 1;
120
+ return 0;
121
+ };
122
+ const aTier = getTier(a);
123
+ const bTier = getTier(b);
124
+ if (aTier !== bTier) return aTier - bTier;
125
+ // 1. features
126
+ const fa = a.priority.features || [];
127
+ const fb = b.priority.features || [];
128
+ const featureCmp = compareFeatureTuples(fa, fb);
129
+ if (featureCmp !== 0) return featureCmp;
130
+ // 2. selector
131
+ const selectorCmp = a.priority.selector - b.priority.selector;
132
+ if (selectorCmp !== 0) return selectorCmp;
133
+ // 3. rule.type
134
+ const typeCmp = a.type - b.type;
135
+ if (typeCmp !== 0) return typeCmp;
136
+ // 4. fallback: name
137
+ return a.key.localeCompare(b.key, undefined, {
138
+ numeric: true
139
+ });
140
+ }
141
+
142
+ exports.calcRulePriority = calcRulePriority;
143
+ exports.default = compareRulePriority;
@@ -0,0 +1,7 @@
1
+ import { SyntaxRule } from '../syntax-rule';
2
+ export type RulePriority = {
3
+ features?: [string, number, number][];
4
+ selector: number;
5
+ };
6
+ export declare function calcRulePriority(rule: SyntaxRule): RulePriority;
7
+ export default function compareRulePriority(a: SyntaxRule, b: SyntaxRule): number;
@@ -0,0 +1,138 @@
1
+ // ✅ Pseudo-class priority (lower = weaker)
2
+ const selectorPriority = {
3
+ hover: 1,
4
+ focus: 2,
5
+ active: 3,
6
+ disabled: 4
7
+ };
8
+ function extractSelectorPriority(nodes = []) {
9
+ let priority = 0;
10
+ for (const node of nodes){
11
+ if ('value' in node && typeof node.value === 'string') {
12
+ priority += selectorPriority[node.value] ?? 0;
13
+ }
14
+ if ('children' in node && Array.isArray(node.children)) {
15
+ priority += extractSelectorPriority(node.children);
16
+ }
17
+ }
18
+ return priority;
19
+ }
20
+ const NOT_COMPARISON_OPERATORS = {
21
+ '>=': '<',
22
+ '<=': '>',
23
+ '>': '<=',
24
+ '<': '>='
25
+ };
26
+ function getAtRuleEntries(nestNodes) {
27
+ const featureMap = new Map();
28
+ const walk = (list, isOutsideNot = false)=>{
29
+ (list ?? []).forEach((node, i, arr)=>{
30
+ const prev = arr[i - 1];
31
+ if ('operator' in node) {
32
+ const entry = featureMap.get(node.name) ?? {};
33
+ let operator = node.operator;
34
+ if (isOutsideNot) operator = NOT_COMPARISON_OPERATORS[operator];
35
+ if (prev?.type === 'logical' && prev.value === 'not') operator = NOT_COMPARISON_OPERATORS[operator];
36
+ switch(operator){
37
+ case '>':
38
+ entry.min = node.value + 0.02;
39
+ break;
40
+ case '>=':
41
+ entry.min = node.value;
42
+ break;
43
+ case '<':
44
+ entry.max = node.value - 0.02;
45
+ break;
46
+ case '<=':
47
+ entry.max = node.value;
48
+ break;
49
+ }
50
+ featureMap.set(node.name, entry);
51
+ }
52
+ if ('children' in node && Array.isArray(node.children)) {
53
+ walk(node.children, prev?.type === 'logical' && prev.value === 'not');
54
+ }
55
+ });
56
+ };
57
+ walk(nestNodes);
58
+ return featureMap;
59
+ }
60
+ // ✅ Calculate RulePriority from AST
61
+ function calcRulePriority(rule) {
62
+ const features = [];
63
+ const extractFeatures = (nodes)=>{
64
+ const featureMap = getAtRuleEntries(nodes);
65
+ for (const [name, entry] of featureMap.entries()){
66
+ const max = entry.max ?? Number.MAX_SAFE_INTEGER;
67
+ const min = entry.min ?? 0;
68
+ features.push([
69
+ name,
70
+ min,
71
+ max
72
+ ]);
73
+ }
74
+ };
75
+ if (rule.atRules?.media) extractFeatures(rule.atRules.media);
76
+ if (rule.atRules?.container) extractFeatures(rule.atRules.container);
77
+ features.sort(([a], [b])=>a.localeCompare(b, undefined, {
78
+ numeric: true
79
+ }));
80
+ const selector = extractSelectorPriority(rule.selectorNodes ?? []);
81
+ return {
82
+ features,
83
+ selector
84
+ };
85
+ }
86
+ function compareFeatureTuples(a, b) {
87
+ const len = Math.max(a.length, b.length);
88
+ for(let i = 0; i < len; i++){
89
+ const aa = a[i];
90
+ const bb = b[i];
91
+ if (!aa) return -1;
92
+ if (!bb) return 1;
93
+ const [nameA, minA, maxA] = aa;
94
+ const [nameB, minB, maxB] = bb;
95
+ const nameCmp = nameA.localeCompare(nameB, undefined, {
96
+ numeric: true
97
+ });
98
+ if (nameCmp !== 0) return nameCmp;
99
+ const rangeA = maxA - minA;
100
+ const rangeB = maxB - minB;
101
+ if (rangeA !== rangeB) return rangeB - rangeA;
102
+ if (minA !== minB) return minB - minA;
103
+ if (maxA !== maxB) return maxB - maxA;
104
+ }
105
+ return 0;
106
+ }
107
+ // ✅ Compare function
108
+ function compareRulePriority(a, b) {
109
+ const getTier = (rule)=>{
110
+ const hasSelector = rule.selectorNodes?.length;
111
+ const hasAtRules = !!rule.atRules;
112
+ const hasMode = !!rule.mode;
113
+ if (hasAtRules) return 3;
114
+ if (hasMode) return 2;
115
+ if (hasSelector) return 1;
116
+ return 0;
117
+ };
118
+ const aTier = getTier(a);
119
+ const bTier = getTier(b);
120
+ if (aTier !== bTier) return aTier - bTier;
121
+ // 1. features
122
+ const fa = a.priority.features || [];
123
+ const fb = b.priority.features || [];
124
+ const featureCmp = compareFeatureTuples(fa, fb);
125
+ if (featureCmp !== 0) return featureCmp;
126
+ // 2. selector
127
+ const selectorCmp = a.priority.selector - b.priority.selector;
128
+ if (selectorCmp !== 0) return selectorCmp;
129
+ // 3. rule.type
130
+ const typeCmp = a.type - b.type;
131
+ if (typeCmp !== 0) return typeCmp;
132
+ // 4. fallback: name
133
+ return a.key.localeCompare(b.key, undefined, {
134
+ numeric: true
135
+ });
136
+ }
137
+
138
+ export { calcRulePriority, compareRulePriority as default };
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+
3
+ var common = require('../common.cjs');
4
+
5
+ function areNodesEqual(a, b) {
6
+ return a.type === b.type && a.value === b.value && a.unit === b.unit && a.name === b.name && a.operator === b.operator && areNodeArraysEqual(a.children ?? [], b.children ?? []);
7
+ }
8
+ function areNodeArraysEqual(aNodes, bNodes) {
9
+ if (aNodes.length !== bNodes.length) return false;
10
+ const matched = new Array(bNodes.length).fill(false);
11
+ for (const aNode of aNodes){
12
+ const index = bNodes.findIndex((bNode, i)=>!matched[i] && areNodesEqual(aNode, bNode));
13
+ if (index === -1) return false;
14
+ matched[index] = true;
15
+ }
16
+ return true;
17
+ }
18
+ function equalAtRules(a, b) {
19
+ return common.AT_IDENTIFIERS.every((key)=>areNodeArraysEqual(a?.[key] ?? [], b?.[key] ?? []));
20
+ }
21
+
22
+ module.exports = equalAtRules;
@@ -0,0 +1,2 @@
1
+ import type { SyntaxRule } from '../syntax-rule';
2
+ export default function equalAtRules(a: SyntaxRule['atRules'], b: SyntaxRule['atRules']): boolean;
@@ -0,0 +1,20 @@
1
+ import { AT_IDENTIFIERS } from '../common.mjs';
2
+
3
+ function areNodesEqual(a, b) {
4
+ return a.type === b.type && a.value === b.value && a.unit === b.unit && a.name === b.name && a.operator === b.operator && areNodeArraysEqual(a.children ?? [], b.children ?? []);
5
+ }
6
+ function areNodeArraysEqual(aNodes, bNodes) {
7
+ if (aNodes.length !== bNodes.length) return false;
8
+ const matched = new Array(bNodes.length).fill(false);
9
+ for (const aNode of aNodes){
10
+ const index = bNodes.findIndex((bNode, i)=>!matched[i] && areNodesEqual(aNode, bNode));
11
+ if (index === -1) return false;
12
+ matched[index] = true;
13
+ }
14
+ return true;
15
+ }
16
+ function equalAtRules(a, b) {
17
+ return AT_IDENTIFIERS.every((key)=>areNodeArraysEqual(a?.[key] ?? [], b?.[key] ?? []));
18
+ }
19
+
20
+ export { equalAtRules as default };
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ function equalDeclarations(a = {}, b = {}) {
4
+ if (Object.keys(a).length !== Object.keys(b).length) {
5
+ return false;
6
+ }
7
+ return Object.keys(a).every((key)=>key in b);
8
+ }
9
+
10
+ module.exports = equalDeclarations;
@@ -0,0 +1,2 @@
1
+ import { SyntaxRule } from '../syntax-rule';
2
+ export default function equalDeclarations(a?: SyntaxRule['declarations'], b?: SyntaxRule['declarations']): boolean;
@@ -0,0 +1,8 @@
1
+ function equalDeclarations(a = {}, b = {}) {
2
+ if (Object.keys(a).length !== Object.keys(b).length) {
3
+ return false;
4
+ }
5
+ return Object.keys(a).every((key)=>key in b);
6
+ }
7
+
8
+ export { equalDeclarations as default };
@@ -0,0 +1,70 @@
1
+ 'use strict';
2
+
3
+ function isCombinator(node) {
4
+ return node.type === 'combinator';
5
+ }
6
+ function areSelectorNodesEqual(a, b) {
7
+ if (a.type !== b.type) return false;
8
+ if (a.value !== b.value) return false;
9
+ const aChildren = a.children ?? [];
10
+ const bChildren = b.children ?? [];
11
+ if (aChildren.length !== bChildren.length) return false;
12
+ return equalUnorderedSelectorNodes(aChildren, bChildren);
13
+ }
14
+ function equalUnorderedSelectorNodes(a, b) {
15
+ if (a.length !== b.length) return false;
16
+ const unmatchedB = new Set(b);
17
+ for (const nodeA of a){
18
+ let matched = false;
19
+ for (const nodeB of unmatchedB){
20
+ if (areSelectorNodesEqual(nodeA, nodeB)) {
21
+ unmatchedB.delete(nodeB);
22
+ matched = true;
23
+ break;
24
+ }
25
+ }
26
+ if (!matched) return false;
27
+ }
28
+ return true;
29
+ }
30
+ function splitByCombinators(nodes) {
31
+ const parts = [];
32
+ let buffer = [];
33
+ for (const node of nodes){
34
+ if (isCombinator(node)) {
35
+ if (buffer.length > 0) {
36
+ parts.push(buffer);
37
+ buffer = [];
38
+ }
39
+ parts.push(node) // push combinator as-is
40
+ ;
41
+ } else {
42
+ buffer.push(node);
43
+ }
44
+ }
45
+ if (buffer.length > 0) {
46
+ parts.push(buffer);
47
+ }
48
+ return parts;
49
+ }
50
+ function equalSelectors(a = [], b = []) {
51
+ const aParts = splitByCombinators(a);
52
+ const bParts = splitByCombinators(b);
53
+ if (aParts.length !== bParts.length) return false;
54
+ for(let i = 0; i < aParts.length; i++){
55
+ const partA = aParts[i];
56
+ const partB = bParts[i];
57
+ if (Array.isArray(partA) && Array.isArray(partB)) {
58
+ if (!equalUnorderedSelectorNodes(partA, partB)) return false;
59
+ } else if (!Array.isArray(partA) && !Array.isArray(partB)) {
60
+ // both are combinators
61
+ if (!areSelectorNodesEqual(partA, partB)) return false;
62
+ } else {
63
+ return false // mismatch between combinator vs non-combinator
64
+ ;
65
+ }
66
+ }
67
+ return true;
68
+ }
69
+
70
+ module.exports = equalSelectors;
@@ -0,0 +1,2 @@
1
+ import type { SelectorNode } from './parse-selector';
2
+ export default function equalSelectors(a?: SelectorNode[], b?: SelectorNode[]): boolean;
@@ -0,0 +1,68 @@
1
+ function isCombinator(node) {
2
+ return node.type === 'combinator';
3
+ }
4
+ function areSelectorNodesEqual(a, b) {
5
+ if (a.type !== b.type) return false;
6
+ if (a.value !== b.value) return false;
7
+ const aChildren = a.children ?? [];
8
+ const bChildren = b.children ?? [];
9
+ if (aChildren.length !== bChildren.length) return false;
10
+ return equalUnorderedSelectorNodes(aChildren, bChildren);
11
+ }
12
+ function equalUnorderedSelectorNodes(a, b) {
13
+ if (a.length !== b.length) return false;
14
+ const unmatchedB = new Set(b);
15
+ for (const nodeA of a){
16
+ let matched = false;
17
+ for (const nodeB of unmatchedB){
18
+ if (areSelectorNodesEqual(nodeA, nodeB)) {
19
+ unmatchedB.delete(nodeB);
20
+ matched = true;
21
+ break;
22
+ }
23
+ }
24
+ if (!matched) return false;
25
+ }
26
+ return true;
27
+ }
28
+ function splitByCombinators(nodes) {
29
+ const parts = [];
30
+ let buffer = [];
31
+ for (const node of nodes){
32
+ if (isCombinator(node)) {
33
+ if (buffer.length > 0) {
34
+ parts.push(buffer);
35
+ buffer = [];
36
+ }
37
+ parts.push(node) // push combinator as-is
38
+ ;
39
+ } else {
40
+ buffer.push(node);
41
+ }
42
+ }
43
+ if (buffer.length > 0) {
44
+ parts.push(buffer);
45
+ }
46
+ return parts;
47
+ }
48
+ function equalSelectors(a = [], b = []) {
49
+ const aParts = splitByCombinators(a);
50
+ const bParts = splitByCombinators(b);
51
+ if (aParts.length !== bParts.length) return false;
52
+ for(let i = 0; i < aParts.length; i++){
53
+ const partA = aParts[i];
54
+ const partB = bParts[i];
55
+ if (Array.isArray(partA) && Array.isArray(partB)) {
56
+ if (!equalUnorderedSelectorNodes(partA, partB)) return false;
57
+ } else if (!Array.isArray(partA) && !Array.isArray(partB)) {
58
+ // both are combinators
59
+ if (!areSelectorNodesEqual(partA, partB)) return false;
60
+ } else {
61
+ return false // mismatch between combinator vs non-combinator
62
+ ;
63
+ }
64
+ }
65
+ return true;
66
+ }
67
+
68
+ export { equalSelectors as default };
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ var equalSelectors = require('./equal-selectors.cjs');
4
+ var equalAtRules = require('./equal-at-rules.cjs');
5
+
6
+ function equalVariants(a, b) {
7
+ return a.mode === b.mode && equalSelectors(a.selectorNodes, b.selectorNodes) && equalAtRules(a.atRules, b.atRules);
8
+ }
9
+
10
+ module.exports = equalVariants;
@@ -0,0 +1,2 @@
1
+ import type { SyntaxRule } from '../syntax-rule';
2
+ export default function equalVariants(a: SyntaxRule, b: SyntaxRule): boolean;
@@ -0,0 +1,8 @@
1
+ import equalSelectors from './equal-selectors.mjs';
2
+ import equalAtRules from './equal-at-rules.mjs';
3
+
4
+ function equalVariants(a, b) {
5
+ return a.mode === b.mode && equalSelectors(a.selectorNodes, b.selectorNodes) && equalAtRules(a.atRules, b.atRules);
6
+ }
7
+
8
+ export { equalVariants as default };
@@ -19,7 +19,6 @@ function extendConfig(...configs) {
19
19
  };
20
20
  [
21
21
  'components',
22
- 'at',
23
22
  'variables'
24
23
  ].forEach((key)=>{
25
24
  if (clonedConfig[key]) {
@@ -17,7 +17,6 @@ function extendConfig(...configs) {
17
17
  };
18
18
  [
19
19
  'components',
20
- 'at',
21
20
  'variables'
22
21
  ].forEach((key)=>{
23
22
  if (clonedConfig[key]) {
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ function generateAt(atRule) {
4
+ const generate = (nodes)=>{
5
+ let text = nodes.map((comp)=>{
6
+ let current = '';
7
+ if ('children' in comp) {
8
+ const body = generate(comp.children);
9
+ current = comp.type === 'group' ? '(' + body + ')' : body;
10
+ } else {
11
+ const value = comp.type === 'number' ? String(comp.value) + (comp.unit || '') : comp.value;
12
+ if ('name' in comp) {
13
+ if ('operator' in comp) {
14
+ current = '(' + `${comp.name}${comp.operator}${value}` + ')';
15
+ } else {
16
+ current = '(' + `${comp.name}:${value}` + ')';
17
+ }
18
+ } else {
19
+ current = value;
20
+ }
21
+ }
22
+ return current;
23
+ }).filter(Boolean).join(atRule.id === 'layer' ? '.' : ' ');
24
+ return text;
25
+ };
26
+ const result = generate(atRule.nodes);
27
+ return '@' + atRule.id + (result ? ' ' + result : '');
28
+ }
29
+
30
+ module.exports = generateAt;
@@ -0,0 +1,2 @@
1
+ import { AtRule } from './parse-at';
2
+ export default function generateAt(atRule: AtRule): string;
@@ -0,0 +1,28 @@
1
+ function generateAt(atRule) {
2
+ const generate = (nodes)=>{
3
+ let text = nodes.map((comp)=>{
4
+ let current = '';
5
+ if ('children' in comp) {
6
+ const body = generate(comp.children);
7
+ current = comp.type === 'group' ? '(' + body + ')' : body;
8
+ } else {
9
+ const value = comp.type === 'number' ? String(comp.value) + (comp.unit || '') : comp.value;
10
+ if ('name' in comp) {
11
+ if ('operator' in comp) {
12
+ current = '(' + `${comp.name}${comp.operator}${value}` + ')';
13
+ } else {
14
+ current = '(' + `${comp.name}:${value}` + ')';
15
+ }
16
+ } else {
17
+ current = value;
18
+ }
19
+ }
20
+ return current;
21
+ }).filter(Boolean).join(atRule.id === 'layer' ? '.' : ' ');
22
+ return text;
23
+ };
24
+ const result = generate(atRule.nodes);
25
+ return '@' + atRule.id + (result ? ' ' + result : '');
26
+ }
27
+
28
+ export { generateAt as default };
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ var common = require('../common.cjs');
4
+
5
+ const prefixMap = {
6
+ 'class': '.',
7
+ 'pseudo-class': ':',
8
+ 'pseudo-element': '::',
9
+ 'attribute': '',
10
+ 'combinator': ''
11
+ };
12
+ function generateSelector(nodes, body = '') {
13
+ const generate = (node)=>{
14
+ if (node.type === 'attribute') return `[${node.value}]`;
15
+ if (node.type === 'combinator') return node.value;
16
+ const prefix = node.type && prefixMap[node.type] || '';
17
+ const base = node.value ? prefix + node.value : '';
18
+ if ('children' in node && node.children?.length) {
19
+ const childrenText = node.children.map(generate).join('');
20
+ return node.value ? base + `(${childrenText})` : base + childrenText;
21
+ }
22
+ return base;
23
+ };
24
+ let pre = '';
25
+ let current = '';
26
+ const groups = [];
27
+ const flatNodes = nodes.flatMap((node)=>!('value' in node) && 'children' in node && node.children?.length ? node.children : node);
28
+ flatNodes.forEach((node)=>{
29
+ if (node.value === ',') {
30
+ groups.push(current);
31
+ current = '';
32
+ } else if (node.value === 'of' && 'children' in node) {
33
+ pre += node.children.map(generate).join('');
34
+ } else {
35
+ current += generate(node);
36
+ }
37
+ });
38
+ if (current) groups.push(current);
39
+ if (pre) {
40
+ const lastChar = pre.charAt(pre.length - 1);
41
+ if (!common.SELECTOR_COMBINATORS.includes(lastChar) && lastChar !== ' ') {
42
+ pre += ' ';
43
+ }
44
+ }
45
+ const result = groups.length ? groups.map((text)=>pre + body + text).join(',') : pre + body;
46
+ return result;
47
+ }
48
+
49
+ module.exports = generateSelector;
@@ -0,0 +1,2 @@
1
+ import { SelectorNode } from './parse-selector';
2
+ export default function generateSelector(nodes: SelectorNode[], body?: string): string;