@master/css-engine 2.0.0-rc.70

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 (68) hide show
  1. package/README.md +57 -0
  2. package/dist/animation-rule.d.ts +12 -0
  3. package/dist/animation-rule.mjs +38 -0
  4. package/dist/common.d.ts +40 -0
  5. package/dist/common.mjs +114 -0
  6. package/dist/compile-manifest.d.ts +54 -0
  7. package/dist/compile-manifest.mjs +451 -0
  8. package/dist/compiler.d.ts +32 -0
  9. package/dist/compiler.mjs +38 -0
  10. package/dist/core.d.ts +141 -0
  11. package/dist/core.mjs +848 -0
  12. package/dist/emitted-globals.d.ts +4 -0
  13. package/dist/emitted-globals.mjs +1 -0
  14. package/dist/hydration-manifest.d.ts +4 -0
  15. package/dist/hydration-manifest.mjs +61 -0
  16. package/dist/index.d.ts +22 -0
  17. package/dist/index.mjs +15 -0
  18. package/dist/key-aliases.d.ts +4 -0
  19. package/dist/key-aliases.mjs +95 -0
  20. package/dist/layer.d.ts +17 -0
  21. package/dist/layer.mjs +78 -0
  22. package/dist/namespaces.d.ts +5 -0
  23. package/dist/namespaces.mjs +28 -0
  24. package/dist/native-value-namespaces.d.ts +9 -0
  25. package/dist/native-value-namespaces.mjs +346 -0
  26. package/dist/non-layer.d.ts +12 -0
  27. package/dist/non-layer.mjs +53 -0
  28. package/dist/rule.d.ts +7 -0
  29. package/dist/rule.mjs +14 -0
  30. package/dist/theme-layer.d.ts +21 -0
  31. package/dist/theme-layer.mjs +52 -0
  32. package/dist/utility-layer.d.ts +10 -0
  33. package/dist/utility-layer.mjs +118 -0
  34. package/dist/utility.d.ts +102 -0
  35. package/dist/utility.mjs +1263 -0
  36. package/dist/utils/collect-animation-names.d.ts +10 -0
  37. package/dist/utils/collect-animation-names.mjs +61 -0
  38. package/dist/utils/collect-variable-names.d.ts +3 -0
  39. package/dist/utils/collect-variable-names.mjs +18 -0
  40. package/dist/utils/compare-rule-priority.d.ts +14 -0
  41. package/dist/utils/compare-rule-priority.mjs +136 -0
  42. package/dist/utils/css-variables.d.ts +12 -0
  43. package/dist/utils/css-variables.mjs +197 -0
  44. package/dist/utils/find-native-css-rule-index.d.ts +1 -0
  45. package/dist/utils/find-native-css-rule-index.mjs +10 -0
  46. package/dist/utils/generate-at.d.ts +2 -0
  47. package/dist/utils/generate-at.mjs +32 -0
  48. package/dist/utils/generate-selector.d.ts +2 -0
  49. package/dist/utils/generate-selector.mjs +48 -0
  50. package/dist/utils/natural-compare.d.ts +2 -0
  51. package/dist/utils/natural-compare.mjs +6 -0
  52. package/dist/utils/parse-at.d.ts +44 -0
  53. package/dist/utils/parse-at.mjs +179 -0
  54. package/dist/utils/parse-pair.d.ts +8 -0
  55. package/dist/utils/parse-pair.mjs +46 -0
  56. package/dist/utils/parse-selector.d.ts +19 -0
  57. package/dist/utils/parse-selector.mjs +124 -0
  58. package/dist/utils/parse-value.d.ts +2 -0
  59. package/dist/utils/parse-value.mjs +37 -0
  60. package/dist/utils/replace-char-outside-quotes.d.ts +1 -0
  61. package/dist/utils/replace-char-outside-quotes.mjs +19 -0
  62. package/dist/utils/split-char-outside-quotes.d.ts +1 -0
  63. package/dist/utils/split-char-outside-quotes.mjs +27 -0
  64. package/dist/utils/wrap-at-rules.d.ts +1 -0
  65. package/dist/utils/wrap-at-rules.mjs +10 -0
  66. package/dist/variable-rule.d.ts +26 -0
  67. package/dist/variable-rule.mjs +105 -0
  68. package/package.json +1 -0
package/dist/core.mjs ADDED
@@ -0,0 +1,848 @@
1
+ import { Utility } from './utility.mjs';
2
+ import ThemeLayer from './theme-layer.mjs';
3
+ import UtilityLayer from './utility-layer.mjs';
4
+ import NonLayer from './non-layer.mjs';
5
+ import VariableRule from './variable-rule.mjs';
6
+ import AnimationRule from './animation-rule.mjs';
7
+ import UtilityType from '@master/css-schema/utility-type';
8
+ import parseValue from './utils/parse-value.mjs';
9
+ import { isNativeCSSShorthandProperty } from '@master/css-schema/native-css-shorthand';
10
+ import { getCompiledManifest, cloneCompiledSettings, isPureNativeDeclarationUtilityDefinition } from './compile-manifest.mjs';
11
+ import { MATCH_NAME_BOUNDARY } from './common.mjs';
12
+
13
+ const builtinGroupUtility = {
14
+ id: 'group',
15
+ name: 'group',
16
+ type: UtilityType.Shorthand,
17
+ order: 0,
18
+ emit: {
19
+ type: 'group'
20
+ },
21
+ matchers: []
22
+ };
23
+ function isNameBoundary(char) {
24
+ return char === undefined || !/[a-zA-Z0-9-]/.test(char);
25
+ }
26
+ function getKeyedValue(className, keys) {
27
+ for (const key of keys){
28
+ const prefix = key + ':';
29
+ if (className.startsWith(prefix) && className.length > prefix.length) {
30
+ return className.slice(prefix.length);
31
+ }
32
+ }
33
+ }
34
+ function matchesStaticUtility(className, name) {
35
+ if (!className.startsWith(name)) return false;
36
+ const next = className[name.length];
37
+ return next === undefined || next === '!' || next === '*' || next === '>' || next === '+' || next === '~' || next === ':' || next === '[' || next === '@' || next === '_' || next === '.';
38
+ }
39
+ function getFunctionValueName(value) {
40
+ return /^-{0,2}([_a-zA-Z][-_a-zA-Z0-9]*)\(/.exec(value)?.[1];
41
+ }
42
+ function matchesNumericFunctionValue(value) {
43
+ const name = getFunctionValueName(value);
44
+ return name === 'calc' || name === 'clamp' || name === 'min' || name === 'max';
45
+ }
46
+ function matchesImageFunctionValue(value) {
47
+ const name = getFunctionValueName(value);
48
+ if (!name) return false;
49
+ return name === 'url' || name === 'element' || name === 'paint' || name === 'cross-fade' || name.endsWith('-gradient') || name.includes('image');
50
+ }
51
+ function matchesColorFunctionValue(value) {
52
+ const name = getFunctionValueName(value);
53
+ return Boolean(name) && !matchesNumericFunctionValue(value) && !matchesImageFunctionValue(value);
54
+ }
55
+ function hasTopLevelValueSeparator(value) {
56
+ let depth = 0;
57
+ let quote = '';
58
+ for(let index = 0; index < value.length; index++){
59
+ const char = value[index];
60
+ if (quote) {
61
+ if (char === '\\') {
62
+ index++;
63
+ } else if (char === quote) {
64
+ quote = '';
65
+ }
66
+ continue;
67
+ }
68
+ if (char === '"' || char === '\'') {
69
+ quote = char;
70
+ continue;
71
+ }
72
+ if (char === '(' || char === '[' || char === '{') {
73
+ depth++;
74
+ continue;
75
+ }
76
+ if (char === ')' || char === ']' || char === '}') {
77
+ if (depth > 0) depth--;
78
+ continue;
79
+ }
80
+ if (char === '|' && depth === 0) return true;
81
+ }
82
+ return false;
83
+ }
84
+ function matchesValueSegmentPolicy(value, matcher) {
85
+ return matcher.type !== 'variable' && matcher.type !== 'value' || matcher.segments === 'multiple' || !hasTopLevelValueSeparator(value);
86
+ }
87
+ function getClassKey(className) {
88
+ if (className[0] === '{') return;
89
+ const indexOfColon = className.indexOf(':');
90
+ if (indexOfColon <= 0) return;
91
+ return className.slice(0, indexOfColon);
92
+ }
93
+ function getMatchName(className) {
94
+ for(let index = 0; index < className.length; index++){
95
+ if (MATCH_NAME_BOUNDARY.has(className[index])) {
96
+ return index ? className.slice(0, index) : className;
97
+ }
98
+ }
99
+ return className;
100
+ }
101
+ class MasterCSS {
102
+ options;
103
+ definedUtilities = [];
104
+ variableMatcherUtilities = [];
105
+ valueMatcherUtilities = [];
106
+ keyMatcherUtilities = [];
107
+ patternMatcherUtilities = [];
108
+ arbitraryMatcherUtilities = [];
109
+ variableMatcherIndex = new Map();
110
+ valueMatcherIndex = new Map();
111
+ keyMatcherIndex = new Map();
112
+ patternMatcherIndex;
113
+ arbitraryStaticMatcherIndex;
114
+ settings;
115
+ rules = [];
116
+ classUtilities = new Map();
117
+ animationsNonLayer = new NonLayer(this);
118
+ baseLayer = new UtilityLayer('base', this);
119
+ themeLayer = new ThemeLayer('theme', this);
120
+ defaultsLayer = new UtilityLayer('defaults', this);
121
+ componentsLayer = new UtilityLayer('components', this);
122
+ utilitiesLayer = new UtilityLayer('utilities', this);
123
+ selectors = new Map();
124
+ variables = new Map();
125
+ modes = [];
126
+ atRules = new Map();
127
+ variants = new Map();
128
+ breakpointAtRules = new Map();
129
+ containerAtRules = new Map();
130
+ animations = new Map();
131
+ staticVariableTokens = new Set();
132
+ staticAnimationTokens = new Set();
133
+ emittedGlobals = {
134
+ variables: {},
135
+ animations: {}
136
+ };
137
+ nativeDeclarationFastPathBlockedProperties = new Set();
138
+ nativeDeclarationMatches = new Map();
139
+ nativeDeclarationUtilities = new Map();
140
+ nativeValueNamespaceUtilities = new Map();
141
+ keyAliases = new Map();
142
+ manifest;
143
+ static create(options) {
144
+ const { manifest, emittedGlobals, ...engineOptions } = options;
145
+ return new this(manifest, emittedGlobals, engineOptions);
146
+ }
147
+ constructor(manifest, emittedGlobals, options = {}){
148
+ this.options = options;
149
+ this.loadManifest(manifest);
150
+ this.registerEmittedGlobals(emittedGlobals);
151
+ if (new.target === MasterCSS) {
152
+ this.insertStaticResources();
153
+ }
154
+ }
155
+ get text() {
156
+ return this.rules.sort((a, b)=>{
157
+ const order = [
158
+ 'theme',
159
+ 'base',
160
+ 'defaults',
161
+ 'components',
162
+ 'utilities'
163
+ ];
164
+ const indexA = order.indexOf(a.name) === -1 ? Infinity : order.indexOf(a.name);
165
+ const indexB = order.indexOf(b.name) === -1 ? Infinity : order.indexOf(b.name);
166
+ return indexA - indexB;
167
+ }).map(({ text })=>text).join('');
168
+ }
169
+ getUtilityLayer(layerName = 'utilities') {
170
+ switch(layerName){
171
+ case 'base':
172
+ return this.baseLayer;
173
+ case 'defaults':
174
+ return this.defaultsLayer;
175
+ case 'components':
176
+ return this.componentsLayer;
177
+ case 'utilities':
178
+ return this.utilitiesLayer;
179
+ default:
180
+ throw new Error(`Unsupported utility layer: ${layerName}`);
181
+ }
182
+ }
183
+ getUtilityLayers() {
184
+ return [
185
+ this.baseLayer,
186
+ this.defaultsLayer,
187
+ this.componentsLayer,
188
+ this.utilitiesLayer
189
+ ];
190
+ }
191
+ loadManifest(manifest) {
192
+ const compiledManifest = getCompiledManifest(manifest);
193
+ this.manifest = compiledManifest.manifest;
194
+ this.settings = cloneCompiledSettings(compiledManifest.settings);
195
+ this.definedUtilities = compiledManifest.definedUtilities;
196
+ this.variableMatcherUtilities = compiledManifest.variableMatcherUtilities;
197
+ this.valueMatcherUtilities = compiledManifest.valueMatcherUtilities;
198
+ this.keyMatcherUtilities = compiledManifest.keyMatcherUtilities;
199
+ this.patternMatcherUtilities = compiledManifest.patternMatcherUtilities;
200
+ this.arbitraryMatcherUtilities = compiledManifest.arbitraryMatcherUtilities;
201
+ this.variableMatcherIndex = compiledManifest.variableMatcherIndex;
202
+ this.valueMatcherIndex = compiledManifest.valueMatcherIndex;
203
+ this.keyMatcherIndex = compiledManifest.keyMatcherIndex;
204
+ this.patternMatcherIndex = compiledManifest.patternMatcherIndex;
205
+ this.arbitraryStaticMatcherIndex = compiledManifest.arbitraryStaticMatcherIndex;
206
+ this.selectors = compiledManifest.selectors;
207
+ this.variables = compiledManifest.variables;
208
+ this.modes = [
209
+ ...compiledManifest.modes
210
+ ];
211
+ this.atRules = compiledManifest.atRules;
212
+ this.variants = compiledManifest.variants;
213
+ this.breakpointAtRules = compiledManifest.breakpointAtRules;
214
+ this.containerAtRules = compiledManifest.containerAtRules;
215
+ this.animations = compiledManifest.animations;
216
+ this.nativeDeclarationFastPathBlockedProperties = compiledManifest.nativeDeclarationFastPathBlockedProperties;
217
+ this.nativeValueNamespaceUtilities = compiledManifest.nativeValueNamespaceUtilities;
218
+ this.keyAliases = compiledManifest.keyAliases;
219
+ }
220
+ applyEmittedGlobalsCounts(emittedGlobals) {
221
+ for (const [name, count] of Object.entries(emittedGlobals.variables || {})){
222
+ if (!count) continue;
223
+ this.themeLayer.tokenCounts.set(name, (this.themeLayer.tokenCounts.get(name) || 0) + count);
224
+ }
225
+ for (const [name, count] of Object.entries(emittedGlobals.animations || {})){
226
+ if (!count) continue;
227
+ this.animationsNonLayer.tokenCounts.set(name, (this.animationsNonLayer.tokenCounts.get(name) || 0) + count);
228
+ }
229
+ }
230
+ registerEmittedGlobals(emittedGlobals) {
231
+ if (!emittedGlobals) return;
232
+ for (const [name, count] of Object.entries(emittedGlobals.variables || {})){
233
+ if (!count) continue;
234
+ this.emittedGlobals.variables[name] = (this.emittedGlobals.variables[name] || 0) + count;
235
+ }
236
+ for (const [name, count] of Object.entries(emittedGlobals.animations || {})){
237
+ if (!count) continue;
238
+ this.emittedGlobals.animations[name] = (this.emittedGlobals.animations[name] || 0) + count;
239
+ }
240
+ this.applyEmittedGlobalsCounts(emittedGlobals);
241
+ }
242
+ isEmittedGlobalsVariable(name) {
243
+ return Boolean(this.emittedGlobals.variables[name]);
244
+ }
245
+ isEmittedGlobalsAnimation(name) {
246
+ return Boolean(this.emittedGlobals.animations[name]);
247
+ }
248
+ insertStaticVariable(name, visited = new Set()) {
249
+ if (visited.has(name)) return;
250
+ visited.add(name);
251
+ const variable = this.variables.get(name);
252
+ if (!variable || variable.inline) return;
253
+ if (!this.staticVariableTokens.has(name)) {
254
+ if (!this.isEmittedGlobalsVariable(name)) {
255
+ if (!this.themeLayer.get(name)) {
256
+ this.themeLayer.insert(new VariableRule(name, variable, this));
257
+ }
258
+ const count = this.themeLayer.tokenCounts.get(name) || 0;
259
+ this.themeLayer.tokenCounts.set(name, count + 1);
260
+ }
261
+ this.staticVariableTokens.add(name);
262
+ }
263
+ variable.dependencies?.forEach((dependency)=>this.insertStaticVariable(dependency, visited));
264
+ }
265
+ insertStaticAnimation(name) {
266
+ if (this.staticAnimationTokens.has(name)) return;
267
+ const keyframes = this.animations.get(name);
268
+ if (!keyframes) return;
269
+ let rule = this.animationsNonLayer.rules.find((eachRule)=>eachRule.name === name);
270
+ if (!this.isEmittedGlobalsAnimation(name)) {
271
+ if (!rule) {
272
+ rule = new AnimationRule(name, keyframes, this);
273
+ this.animationsNonLayer.insert(rule);
274
+ }
275
+ const count = this.animationsNonLayer.tokenCounts.get(name) || 0;
276
+ this.animationsNonLayer.tokenCounts.set(name, count + 1);
277
+ } else if (!rule) {
278
+ rule = new AnimationRule(name, keyframes, this);
279
+ }
280
+ this.staticAnimationTokens.add(name);
281
+ rule.variableNames?.forEach((variableName)=>this.insertStaticVariable(variableName));
282
+ }
283
+ insertStaticResources() {
284
+ for (const [name, variable] of this.variables){
285
+ if (variable.static) this.insertStaticVariable(name);
286
+ }
287
+ for (const name of this.animations.keys()){
288
+ if (this.manifest.animationOptions?.[name]?.static) this.insertStaticAnimation(name);
289
+ }
290
+ return this;
291
+ }
292
+ resolveVariant(token) {
293
+ return this.variants.get(token);
294
+ }
295
+ parseValue(token, unit = '') {
296
+ return parseValue(token, unit, this.settings.rootSize);
297
+ }
298
+ /**
299
+ * Match check if Master CSS utility
300
+ * @param className
301
+ * @returns css text
302
+ */ matchesMatcher(className, utility, matcher) {
303
+ switch(matcher.type){
304
+ case 'static':
305
+ return matchesStaticUtility(className, matcher.name);
306
+ case 'key':
307
+ return getKeyedValue(className, matcher.keys) !== undefined;
308
+ case 'variable':
309
+ {
310
+ const value = getKeyedValue(className, matcher.keys);
311
+ if (value === undefined || !utility.variables?.size) return false;
312
+ if (!matchesValueSegmentPolicy(value, matcher)) return false;
313
+ for (const [variableKey, variable] of utility.variables){
314
+ if (value.startsWith(variableKey) && isNameBoundary(value[variableKey.length])) return true;
315
+ const negativeVariableKey = '-' + variableKey;
316
+ if (variableKey[0] !== '-' && variable.type === 'number' && value.startsWith(negativeVariableKey) && isNameBoundary(value[negativeVariableKey.length])) return true;
317
+ }
318
+ return false;
319
+ }
320
+ case 'value':
321
+ {
322
+ const value = getKeyedValue(className, matcher.keys);
323
+ if (value === undefined) return false;
324
+ if (!matchesValueSegmentPolicy(value, matcher)) return false;
325
+ switch(utility.kind){
326
+ case 'color':
327
+ return value[0] === '#' || matchesColorFunctionValue(value) || value.startsWith('currentColor') && isNameBoundary(value[12]) || value.startsWith('transparent') && isNameBoundary(value[11]);
328
+ case 'number':
329
+ return /[\d.]/.test(value[0]) || matchesNumericFunctionValue(value);
330
+ case 'image':
331
+ return matchesImageFunctionValue(value);
332
+ default:
333
+ return false;
334
+ }
335
+ }
336
+ case 'pattern':
337
+ return matcher.values.some((value)=>matchesStaticUtility(className, matcher.prefix + value));
338
+ }
339
+ }
340
+ matchesUtility(className, utility, matcherType) {
341
+ return utility.matchers.some((matcher)=>(!matcherType || matcher.type === matcherType) && this.matchesMatcher(className, utility, matcher));
342
+ }
343
+ matchesExactUtilityDefinition(className, utility) {
344
+ return utility.matchers.some((matcher)=>matcher.type === 'static' && matchesStaticUtility(className, matcher.name));
345
+ }
346
+ hasClassKey(className) {
347
+ const key = getClassKey(className);
348
+ return Boolean(key && !key.startsWith('--'));
349
+ }
350
+ isGroupClassName(className) {
351
+ return className[0] === '{' && className.includes('}');
352
+ }
353
+ getClassKeyAlias(className) {
354
+ const key = getClassKey(className);
355
+ if (!key) return;
356
+ if (key.startsWith('--')) return;
357
+ const canonicalKey = this.keyAliases.get(key);
358
+ if (!canonicalKey) return;
359
+ return {
360
+ canonicalKey,
361
+ indexOfColon: key.length,
362
+ key
363
+ };
364
+ }
365
+ canonicalizeClassName(className, fixedClass) {
366
+ const keyAlias = this.getClassKeyAlias(className);
367
+ if (!keyAlias) return {
368
+ className,
369
+ fixedClass
370
+ };
371
+ return {
372
+ className: keyAlias.canonicalKey + className.slice(keyAlias.indexOfColon),
373
+ fixedClass
374
+ };
375
+ }
376
+ matchResolvedClassName(className) {
377
+ const classKey = getClassKey(className);
378
+ for (const eachUtility of classKey ? this.variableMatcherIndex.get(classKey) || [] : []){
379
+ if (this.matchesUtility(className, eachUtility, 'variable')) return eachUtility;
380
+ }
381
+ for (const eachUtility of classKey ? this.valueMatcherIndex.get(classKey) || [] : []){
382
+ if (this.matchesUtility(className, eachUtility, 'value')) return eachUtility;
383
+ }
384
+ for (const eachUtility of classKey ? this.keyMatcherIndex.get(classKey) || [] : []){
385
+ if (this.matchesUtility(className, eachUtility, 'key')) return eachUtility;
386
+ }
387
+ if (this.arbitraryStaticMatcherIndex) {
388
+ for (const eachUtility of this.arbitraryStaticMatcherIndex.get(getMatchName(className)) || []){
389
+ if (this.matchesUtility(className, eachUtility)) return eachUtility;
390
+ }
391
+ } else {
392
+ for (const eachUtility of this.arbitraryMatcherUtilities){
393
+ if (this.matchesUtility(className, eachUtility)) return eachUtility;
394
+ }
395
+ }
396
+ if (this.patternMatcherIndex) {
397
+ for (const eachUtility of this.patternMatcherIndex.get(getMatchName(className)) || []){
398
+ if (this.matchesUtility(className, eachUtility, 'pattern')) return eachUtility;
399
+ }
400
+ } else {
401
+ for (const eachUtility of this.patternMatcherUtilities){
402
+ if (this.matchesUtility(className, eachUtility, 'pattern')) return eachUtility;
403
+ }
404
+ }
405
+ }
406
+ createGroupUtility(className, fixedClass, mode, branchIndex = 0) {
407
+ if (!this.isGroupClassName(className)) return;
408
+ return this.createRuleWithDefinition(className, builtinGroupUtility, fixedClass, mode, branchIndex);
409
+ }
410
+ createAllGroupUtilities(className, fixedClass, mode) {
411
+ const utility = this.createGroupUtility(className, fixedClass, mode);
412
+ if (!utility?.valid) return [];
413
+ const utilities = [
414
+ utility
415
+ ];
416
+ for(let branchIndex = 1; branchIndex < utility.branchCount; branchIndex++){
417
+ const branchUtility = this.createGroupUtility(className, fixedClass, mode, branchIndex);
418
+ if (branchUtility?.valid) utilities.push(branchUtility);
419
+ }
420
+ return utilities;
421
+ }
422
+ matchRawManagedClassName(className) {
423
+ const classKey = getClassKey(className);
424
+ if (!classKey) return;
425
+ for (const eachUtility of this.variableMatcherIndex.get(classKey) || []){
426
+ if (this.matchesUtility(className, eachUtility, 'variable')) return eachUtility;
427
+ }
428
+ for (const eachUtility of this.valueMatcherIndex.get(classKey) || []){
429
+ if (this.matchesUtility(className, eachUtility, 'value')) return eachUtility;
430
+ }
431
+ for (const eachUtility of this.keyMatcherIndex.get(classKey) || []){
432
+ if (this.matchesUtility(className, eachUtility, 'key')) return eachUtility;
433
+ }
434
+ if (this.patternMatcherIndex) {
435
+ for (const eachUtility of this.patternMatcherIndex.get(getMatchName(className)) || []){
436
+ if (this.matchesUtility(className, eachUtility, 'pattern')) return eachUtility;
437
+ }
438
+ } else {
439
+ for (const eachUtility of this.patternMatcherUtilities){
440
+ if (this.matchesUtility(className, eachUtility, 'pattern')) return eachUtility;
441
+ }
442
+ }
443
+ }
444
+ match(className) {
445
+ if (this.isGroupClassName(className)) return builtinGroupUtility;
446
+ if (this.hasClassKey(className)) {
447
+ const rawRegisteredUtility = this.matchRawManagedClassName(className);
448
+ if (rawRegisteredUtility) return rawRegisteredUtility;
449
+ }
450
+ return this.matchResolvedClassName(this.canonicalizeClassName(className).className);
451
+ }
452
+ matchAllResolvedClassName(className) {
453
+ const classKey = getClassKey(className);
454
+ /**
455
+ * 1. variable
456
+ * @example fg:primary bg:blue
457
+ */ for (const eachUtility of classKey ? this.variableMatcherIndex.get(classKey) || [] : []){
458
+ if (this.matchesUtility(className, eachUtility, 'variable')) return [
459
+ eachUtility
460
+ ];
461
+ }
462
+ /**
463
+ * 2. value (ambiguous key with raw color/number/image)
464
+ * @example bg:#fff font:.75rem
465
+ */ for (const eachUtility of classKey ? this.valueMatcherIndex.get(classKey) || [] : []){
466
+ if (this.matchesUtility(className, eachUtility, 'value')) return [
467
+ eachUtility
468
+ ];
469
+ }
470
+ /**
471
+ * 3. full key
472
+ * @example text-align:center color:blue-40
473
+ */ for (const eachUtility of classKey ? this.keyMatcherIndex.get(classKey) || [] : []){
474
+ if (this.matchesUtility(className, eachUtility, 'key')) return [
475
+ eachUtility
476
+ ];
477
+ }
478
+ /**
479
+ * 4. arbitrary
480
+ * @example custom RegExp, utility
481
+ */ const staticUtilities = [];
482
+ if (this.arbitraryStaticMatcherIndex) {
483
+ for (const eachUtility of this.arbitraryStaticMatcherIndex.get(getMatchName(className)) || []){
484
+ if (this.matchesUtility(className, eachUtility)) staticUtilities.push(eachUtility);
485
+ }
486
+ } else {
487
+ for (const eachUtility of this.arbitraryMatcherUtilities){
488
+ if (!this.matchesUtility(className, eachUtility)) continue;
489
+ if (eachUtility.matchers.some((matcher)=>matcher.type === 'static')) {
490
+ staticUtilities.push(eachUtility);
491
+ continue;
492
+ }
493
+ return [
494
+ eachUtility
495
+ ];
496
+ }
497
+ }
498
+ if (staticUtilities.length) return staticUtilities;
499
+ /**
500
+ * 5. enum pattern
501
+ * @example text-center bg-cover
502
+ */ if (this.patternMatcherIndex) {
503
+ for (const eachUtility of this.patternMatcherIndex.get(getMatchName(className)) || []){
504
+ if (this.matchesUtility(className, eachUtility, 'pattern')) return [
505
+ eachUtility
506
+ ];
507
+ }
508
+ } else {
509
+ for (const eachUtility of this.patternMatcherUtilities){
510
+ if (this.matchesUtility(className, eachUtility, 'pattern')) return [
511
+ eachUtility
512
+ ];
513
+ }
514
+ }
515
+ return [];
516
+ }
517
+ matchAllRawManagedClassName(className) {
518
+ const classKey = getClassKey(className);
519
+ if (!classKey) return [];
520
+ for (const eachUtility of this.variableMatcherIndex.get(classKey) || []){
521
+ if (this.matchesUtility(className, eachUtility, 'variable')) return [
522
+ eachUtility
523
+ ];
524
+ }
525
+ for (const eachUtility of this.valueMatcherIndex.get(classKey) || []){
526
+ if (this.matchesUtility(className, eachUtility, 'value')) return [
527
+ eachUtility
528
+ ];
529
+ }
530
+ for (const eachUtility of this.keyMatcherIndex.get(classKey) || []){
531
+ if (this.matchesUtility(className, eachUtility, 'key')) return [
532
+ eachUtility
533
+ ];
534
+ }
535
+ if (this.patternMatcherIndex) {
536
+ for (const eachUtility of this.patternMatcherIndex.get(getMatchName(className)) || []){
537
+ if (this.matchesUtility(className, eachUtility, 'pattern')) return [
538
+ eachUtility
539
+ ];
540
+ }
541
+ } else {
542
+ for (const eachUtility of this.patternMatcherUtilities){
543
+ if (this.matchesUtility(className, eachUtility, 'pattern')) return [
544
+ eachUtility
545
+ ];
546
+ }
547
+ }
548
+ return [];
549
+ }
550
+ matchAll(className) {
551
+ if (this.isGroupClassName(className)) return [
552
+ builtinGroupUtility
553
+ ];
554
+ if (this.hasClassKey(className)) {
555
+ const rawRegisteredUtilities = this.matchAllRawManagedClassName(className);
556
+ if (rawRegisteredUtilities.length) return rawRegisteredUtilities;
557
+ }
558
+ return this.matchAllResolvedClassName(this.canonicalizeClassName(className).className);
559
+ }
560
+ parseNativeDeclarationProperty(className) {
561
+ const indexOfColon = className.indexOf(':');
562
+ if (indexOfColon <= 0) return;
563
+ const property = className.slice(0, indexOfColon);
564
+ if (!/^(?:--[-_a-zA-Z0-9]+|-?[_a-zA-Z][-_a-zA-Z0-9]*)$/.test(property)) return;
565
+ return property;
566
+ }
567
+ getNativeDeclarationUtility(property) {
568
+ const cached = this.nativeDeclarationUtilities.get(property);
569
+ if (cached) return cached;
570
+ const utility = {
571
+ id: property,
572
+ name: property,
573
+ type: isNativeCSSShorthandProperty(property) ? UtilityType.Shorthand : UtilityType.Normal,
574
+ order: 0,
575
+ emit: {
576
+ type: 'property',
577
+ property
578
+ },
579
+ matchers: [
580
+ {
581
+ type: 'key',
582
+ keys: [
583
+ property
584
+ ]
585
+ }
586
+ ]
587
+ };
588
+ this.nativeDeclarationUtilities.set(property, utility);
589
+ return utility;
590
+ }
591
+ matchNativeDeclaration(declaration) {
592
+ if (declaration.property.startsWith('--')) return true;
593
+ const matcher = this.options.nativeDeclarationMatcher;
594
+ if (!matcher) return false;
595
+ const cacheKey = declaration.property + '\0' + declaration.value;
596
+ const cached = this.nativeDeclarationMatches.get(cacheKey);
597
+ if (cached !== undefined) return cached;
598
+ const matched = matcher(declaration);
599
+ this.nativeDeclarationMatches.set(cacheKey, matched);
600
+ return matched;
601
+ }
602
+ isNativeDeclarationUtility(utility) {
603
+ const entries = Object.entries(utility.declarations || {});
604
+ if (entries.length !== 1) return false;
605
+ const [[property, value]] = entries;
606
+ return this.matchNativeDeclaration({
607
+ property,
608
+ value: String(value)
609
+ });
610
+ }
611
+ shouldValidateNativeDeclarationUtility(utility) {
612
+ if (!this.options.nativeDeclarationMatcher) return false;
613
+ return isPureNativeDeclarationUtilityDefinition(utility) && utility.matchers.every((matcher)=>matcher.type === 'key');
614
+ }
615
+ createNativeDeclarationFallback(className, fixedClass, mode, sourceClassName = className) {
616
+ if (!this.options.nativeDeclarationMatcher) return [];
617
+ const property = this.parseNativeDeclarationProperty(className);
618
+ if (!property) return [];
619
+ const registeredUtility = this.getNativeDeclarationUtility(property);
620
+ const utility = this.createRuleWithDefinition(sourceClassName, registeredUtility, fixedClass, mode);
621
+ if (!utility?.valid || !this.isNativeDeclarationUtility(utility)) return [];
622
+ const utilities = [
623
+ utility
624
+ ];
625
+ for(let branchIndex = 1; branchIndex < utility.branchCount; branchIndex++){
626
+ const branchUtility = this.createRuleWithDefinition(sourceClassName, registeredUtility, fixedClass, mode, branchIndex);
627
+ if (branchUtility?.valid && this.isNativeDeclarationUtility(branchUtility)) utilities.push(branchUtility);
628
+ }
629
+ return utilities;
630
+ }
631
+ createNativeValueNamespaceFallback(className, fixedClass, mode, sourceClassName = className) {
632
+ const property = this.parseNativeDeclarationProperty(className);
633
+ if (!property) return [];
634
+ const registeredUtility = this.nativeValueNamespaceUtilities.get(property);
635
+ if (!registeredUtility) return [];
636
+ const utility = this.createRuleWithDefinition(sourceClassName, registeredUtility, fixedClass, mode);
637
+ if (!utility?.valid || this.options.nativeDeclarationMatcher && !this.isNativeDeclarationUtility(utility)) return [];
638
+ const utilities = [
639
+ utility
640
+ ];
641
+ for(let branchIndex = 1; branchIndex < utility.branchCount; branchIndex++){
642
+ const branchUtility = this.createRuleWithDefinition(sourceClassName, registeredUtility, fixedClass, mode, branchIndex);
643
+ if (branchUtility?.valid && (!this.options.nativeDeclarationMatcher || this.isNativeDeclarationUtility(branchUtility))) {
644
+ utilities.push(branchUtility);
645
+ }
646
+ }
647
+ return utilities;
648
+ }
649
+ createNativeValueNamespaceFastPath(className, fixedClass, mode, sourceClassName = className) {
650
+ const property = this.parseNativeDeclarationProperty(className);
651
+ if (!property) return [];
652
+ if (this.nativeDeclarationFastPathBlockedProperties.has(property)) return [];
653
+ return this.createNativeValueNamespaceFallback(className, fixedClass, mode, sourceClassName);
654
+ }
655
+ createNativeDeclarationFastPath(className, fixedClass, mode, sourceClassName = className) {
656
+ const property = this.parseNativeDeclarationProperty(className);
657
+ if (!property) return [];
658
+ if (!property.startsWith('--') && this.nativeDeclarationFastPathBlockedProperties.has(property)) return [];
659
+ return this.createNativeDeclarationFallback(className, fixedClass, mode, sourceClassName);
660
+ }
661
+ /**
662
+ * Generate utilities from class name
663
+ * @param className
664
+ * @returns Utility[]
665
+ */ generate(className, mode) {
666
+ return this.createRules(className, undefined, mode);
667
+ }
668
+ /**
669
+ * Create utility from given class name
670
+ * @param className
671
+ * @returns Utility
672
+ */ createRule(className, fixedClass, mode) {
673
+ const groupUtility = this.createGroupUtility(className, fixedClass, mode);
674
+ if (groupUtility) return groupUtility;
675
+ const sourceClassName = className;
676
+ if (this.hasClassKey(className)) {
677
+ const rawRegisteredUtility = this.matchRawManagedClassName(className);
678
+ if (rawRegisteredUtility) {
679
+ const utility = this.createRuleWithDefinition(sourceClassName, rawRegisteredUtility, fixedClass, mode);
680
+ if (utility?.valid) return utility;
681
+ }
682
+ }
683
+ const canonicalClass = this.canonicalizeClassName(className, fixedClass);
684
+ className = canonicalClass.className;
685
+ fixedClass = canonicalClass.fixedClass;
686
+ const fastPathNativeValueNamespaceUtilities = this.createNativeValueNamespaceFastPath(className, fixedClass, mode, sourceClassName);
687
+ if (fastPathNativeValueNamespaceUtilities.length) return fastPathNativeValueNamespaceUtilities[0];
688
+ const fastPathNativeUtilities = this.createNativeDeclarationFastPath(className, fixedClass, mode, sourceClassName);
689
+ if (fastPathNativeUtilities.length) return fastPathNativeUtilities[0];
690
+ const registeredUtility = this.matchResolvedClassName(className);
691
+ if (registeredUtility && this.matchesExactUtilityDefinition(className, registeredUtility)) {
692
+ const nativeValueNamespaceUtilities = this.createNativeValueNamespaceFallback(className, fixedClass, mode, sourceClassName);
693
+ if (nativeValueNamespaceUtilities.length) return nativeValueNamespaceUtilities[0];
694
+ const nativeUtilities = this.createNativeDeclarationFallback(className, fixedClass, mode, sourceClassName);
695
+ if (nativeUtilities.length) return nativeUtilities[0];
696
+ }
697
+ if (registeredUtility) return this.createRuleWithDefinition(sourceClassName, registeredUtility, fixedClass, mode);
698
+ return this.createNativeValueNamespaceFallback(className, fixedClass, mode, sourceClassName)[0] || this.createNativeDeclarationFallback(className, fixedClass, mode, sourceClassName)[0];
699
+ }
700
+ createRules(className, fixedClass, mode) {
701
+ const groupUtilities = this.createAllGroupUtilities(className, fixedClass, mode);
702
+ if (groupUtilities.length) return groupUtilities;
703
+ const sourceClassName = className;
704
+ if (this.hasClassKey(className)) {
705
+ const rawRegisteredUtilities = this.matchAllRawManagedClassName(className);
706
+ const rawUtilities = [];
707
+ for (const registeredUtility of rawRegisteredUtilities){
708
+ const utility = this.createRuleWithDefinition(sourceClassName, registeredUtility, fixedClass, mode);
709
+ if (utility && utility.valid) {
710
+ rawUtilities.push(utility);
711
+ for(let branchIndex = 1; branchIndex < utility.branchCount; branchIndex++){
712
+ const branchUtility = this.createRuleWithDefinition(sourceClassName, registeredUtility, fixedClass, mode, branchIndex);
713
+ if (branchUtility?.valid) rawUtilities.push(branchUtility);
714
+ }
715
+ }
716
+ }
717
+ if (rawUtilities.length) return rawUtilities;
718
+ }
719
+ const canonicalClass = this.canonicalizeClassName(className, fixedClass);
720
+ className = canonicalClass.className;
721
+ fixedClass = canonicalClass.fixedClass;
722
+ const fastPathNativeValueNamespaceUtilities = this.createNativeValueNamespaceFastPath(className, fixedClass, mode, sourceClassName);
723
+ if (fastPathNativeValueNamespaceUtilities.length) return fastPathNativeValueNamespaceUtilities;
724
+ const fastPathNativeUtilities = this.createNativeDeclarationFastPath(className, fixedClass, mode, sourceClassName);
725
+ if (fastPathNativeUtilities.length) return fastPathNativeUtilities;
726
+ const registeredUtilities = this.matchAllResolvedClassName(className);
727
+ if (registeredUtilities.length && registeredUtilities.every((utility)=>this.matchesExactUtilityDefinition(className, utility))) {
728
+ const nativeValueNamespaceUtilities = this.createNativeValueNamespaceFallback(className, fixedClass, mode, sourceClassName);
729
+ if (nativeValueNamespaceUtilities.length) return nativeValueNamespaceUtilities;
730
+ const nativeUtilities = this.createNativeDeclarationFallback(className, fixedClass, mode, sourceClassName);
731
+ if (nativeUtilities.length) return nativeUtilities;
732
+ }
733
+ const utilities = [];
734
+ for (const registeredUtility of registeredUtilities){
735
+ const utility = this.createRuleWithDefinition(sourceClassName, registeredUtility, fixedClass, mode);
736
+ if (utility && utility.valid) {
737
+ utilities.push(utility);
738
+ for(let branchIndex = 1; branchIndex < utility.branchCount; branchIndex++){
739
+ const branchUtility = this.createRuleWithDefinition(sourceClassName, registeredUtility, fixedClass, mode, branchIndex);
740
+ if (branchUtility?.valid) utilities.push(branchUtility);
741
+ }
742
+ }
743
+ }
744
+ if (utilities.length) return utilities;
745
+ const nativeValueNamespaceUtilities = this.createNativeValueNamespaceFallback(className, fixedClass, mode, sourceClassName);
746
+ return nativeValueNamespaceUtilities.length ? nativeValueNamespaceUtilities : this.createNativeDeclarationFallback(className, fixedClass, mode, sourceClassName);
747
+ }
748
+ createRuleWithDefinition(className, registeredUtility, fixedClass, mode, branchIndex = 0) {
749
+ const candidate = new Utility(className, this, registeredUtility, fixedClass, mode, branchIndex);
750
+ if (candidate.valid && this.shouldValidateNativeDeclarationUtility(registeredUtility) && !this.isNativeDeclarationUtility(candidate)) return;
751
+ for (const layer of this.getUtilityLayers()){
752
+ const rule = layer.get(candidate.key);
753
+ const utility = rule instanceof Utility && rule.registeredUtility === registeredUtility ? rule : undefined;
754
+ if (utility) return utility;
755
+ }
756
+ return candidate;
757
+ }
758
+ /**
759
+ * Create utility from given selector text
760
+ * @param selectorText
761
+ */ createRulesFromSelectorText(selectorText, layerName) {
762
+ const selectorTextSplits = selectorText.split(' ');
763
+ const stopChars = /[.#\[!\*>+~:,\s]/;
764
+ for(let i = 0; i < selectorTextSplits.length; i++){
765
+ const eachField = selectorTextSplits[i];
766
+ const modeSelector = this.getModeSelector(eachField);
767
+ if (i === 0 && eachField === modeSelector || (i === 0 || i === 1) && eachField === this.settings.scope) continue;
768
+ if (eachField.startsWith('.')) {
769
+ const eachFieldName = eachField.slice(1);
770
+ let className = '';
771
+ let l = 0;
772
+ while(l < eachFieldName.length){
773
+ const char = eachFieldName[l];
774
+ const nextChar = eachFieldName[l + 1];
775
+ if (char === '\\' && nextChar) {
776
+ className += nextChar;
777
+ l += 2;
778
+ continue;
779
+ }
780
+ if (stopChars.test(char)) break;
781
+ className += char;
782
+ l++;
783
+ }
784
+ const utilities = this.generate(className).filter((utility)=>!layerName || utility.layerName === layerName);
785
+ if (utilities.length) return utilities;
786
+ }
787
+ }
788
+ }
789
+ /**
790
+ * 根據蒐集到的所有 DOM class 重新 create
791
+ */ refresh(manifest = this.manifest) {
792
+ this.reset();
793
+ this.loadManifest(manifest);
794
+ this.applyEmittedGlobalsCounts(this.emittedGlobals);
795
+ this.insertStaticResources();
796
+ return this;
797
+ }
798
+ reset() {
799
+ this.classUtilities.clear();
800
+ this.staticVariableTokens.clear();
801
+ this.staticAnimationTokens.clear();
802
+ this.baseLayer.reset();
803
+ this.themeLayer.reset();
804
+ this.defaultsLayer.reset();
805
+ this.componentsLayer.reset();
806
+ this.utilitiesLayer.reset();
807
+ this.animationsNonLayer.reset();
808
+ return this;
809
+ }
810
+ destroy() {
811
+ this.reset();
812
+ return this;
813
+ }
814
+ add(...classNames) {
815
+ for (const className of classNames){
816
+ const rules = this.classUtilities.get(className);
817
+ if (rules) continue;
818
+ const newRules = this.generate(className);
819
+ if (newRules.length) {
820
+ newRules.forEach((eachUtility)=>eachUtility.layer.insert(eachUtility));
821
+ this.classUtilities.set(className, newRules);
822
+ }
823
+ }
824
+ return this;
825
+ }
826
+ remove(...classNames) {
827
+ /**
828
+ * class name 從 DOM tree 中被移除,
829
+ * 匹配並刪除對應的 rule
830
+ */ for (const className of classNames){
831
+ const rules = this.classUtilities.get(className);
832
+ if (rules) {
833
+ rules.forEach((rule)=>rule.layer.delete(rule.key));
834
+ this.classUtilities.delete(className);
835
+ }
836
+ }
837
+ }
838
+ getModeSelector(modeName) {
839
+ switch(this.settings.modeTrigger){
840
+ case 'class':
841
+ return '.' + modeName;
842
+ case 'host':
843
+ return ':host(.' + modeName + ')';
844
+ }
845
+ }
846
+ }
847
+
848
+ export { MasterCSS as default };