@master/css-compiler 2.0.0-rc.72 → 2.0.0-rc.74

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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/dist/browser.d.ts +23 -19
  3. package/dist/browser.js +42 -0
  4. package/dist/core.d.ts +43 -41
  5. package/dist/core.js +1639 -0
  6. package/dist/css-transform.d.ts +10 -6
  7. package/dist/css-transform.js +17 -0
  8. package/dist/diagnostics.d.ts +11 -0
  9. package/dist/diagnostics.js +12 -0
  10. package/dist/index.d.ts +41 -38
  11. package/dist/index.js +330 -0
  12. package/dist/lexer/imports.d.ts +16 -12
  13. package/dist/lexer/imports.js +38 -0
  14. package/dist/lexer/source.d.ts +6 -3
  15. package/dist/lexer/source.js +8 -0
  16. package/dist/lexer/standalone-master.d.ts +23 -19
  17. package/dist/lexer/standalone-master.js +219 -0
  18. package/dist/lower-css-directives.d.ts +18 -13
  19. package/dist/lower-css-directives.js +753 -0
  20. package/dist/master-css-manifest.d.ts +18 -12
  21. package/dist/master-css-manifest.js +546 -0
  22. package/dist/native-declaration.d.ts +6 -2
  23. package/dist/native-declaration.js +23 -0
  24. package/dist/utils/selectors.d.ts +6 -3
  25. package/dist/utils/selectors.js +49 -0
  26. package/dist/utils/unquote.d.ts +4 -1
  27. package/dist/utils/unquote.js +9 -0
  28. package/dist/utils/wrap-at-rules.d.ts +4 -1
  29. package/dist/utils/wrap-at-rules.js +11 -0
  30. package/package.json +69 -1
  31. package/dist/browser.mjs +0 -47
  32. package/dist/core.mjs +0 -2146
  33. package/dist/css-transform.mjs +0 -18
  34. package/dist/index.mjs +0 -395
  35. package/dist/lexer/imports.mjs +0 -44
  36. package/dist/lexer/source.mjs +0 -9
  37. package/dist/lexer/standalone-master.mjs +0 -233
  38. package/dist/lower-css-directives.mjs +0 -969
  39. package/dist/master-css-manifest.mjs +0 -760
  40. package/dist/native-declaration.mjs +0 -25
  41. package/dist/utils/selectors.mjs +0 -55
  42. package/dist/utils/unquote.mjs +0 -10
  43. package/dist/utils/wrap-at-rules.mjs +0 -10
@@ -1,969 +0,0 @@
1
- import { readCSSDirectiveVariantReference, CSSDirectiveError } from '@master/css-schema/css-directives';
2
- import { createCompilerCSS, generateAt, parseAt, generateSelector, compareRulePriority, parseSelector } from '@master/css-engine/compiler';
3
- import { createVariableNameResolver, createMasterCSSManifest } from './master-css-manifest.mjs';
4
- import { combineStyleSelectors } from './utils/selectors.mjs';
5
- import wrapAtRules from './utils/wrap-at-rules.mjs';
6
- import { cssTreeNativeDeclarationMatcher } from './native-declaration.mjs';
7
-
8
- const STYLE_AT_FEATURE_REGEX = /\(\s*(width|height|resolution)\s*(>=|<=|>|<)\s*(-?(?:\d+(?:\.\d+)?|\.\d+))([a-z%]*)\s*\)/g;
9
- const MEDIA_MODE_NAMES = new Set([
10
- 'light',
11
- 'dark'
12
- ]);
13
- const DEFAULT_MODE_NONE = 'none';
14
- const CONDITION_VARIABLE_NAMESPACES = new Set([
15
- 'breakpoint',
16
- 'container'
17
- ]);
18
- function isCSSDirectiveResult(input) {
19
- return 'manifestInput' in input;
20
- }
21
- function getDirectiveInput(input) {
22
- return isCSSDirectiveResult(input) ? input.manifestInput : input;
23
- }
24
- function getStyleDefinitions(input) {
25
- return isCSSDirectiveResult(input) ? input.styleDefinitions : undefined;
26
- }
27
- function getResolutionManifest(options) {
28
- return options.resolutionManifest || options.baseManifest;
29
- }
30
- function warn(warnings, options, message) {
31
- warnings.push(message);
32
- options.onWarning?.(message);
33
- }
34
- function isNamedDefaultMode(defaultMode) {
35
- return typeof defaultMode === 'string' && defaultMode !== DEFAULT_MODE_NONE;
36
- }
37
- function normalizeVariable(variable, resolveVariableName) {
38
- const resolved = resolveVariableName(variable);
39
- if (variable.mode && resolved.namespace && CONDITION_VARIABLE_NAMESPACES.has(resolved.namespace)) {
40
- throw new Error(`${resolved.namespace[0].toUpperCase()}${resolved.namespace.slice(1)} variables cannot be mode-specific: ${resolved.namespace}-${resolved.key}@${variable.mode}`);
41
- }
42
- if (variable.inline && variable.mode) {
43
- throw new Error(`Inline theme variables cannot be mode-specific: ${resolved.name}@${variable.mode}`);
44
- }
45
- if (variable.inline && variable.static) {
46
- throw new Error(`Inline and static theme variables cannot be combined: ${resolved.name}`);
47
- }
48
- return {
49
- name: resolved.name,
50
- ...resolved.namespace ? {
51
- namespace: resolved.namespace
52
- } : {},
53
- key: resolved.key,
54
- value: variable.value,
55
- ...variable.mode ? {
56
- mode: variable.mode
57
- } : {},
58
- ...variable.inline ? {
59
- inline: true
60
- } : {},
61
- ...variable.static ? {
62
- static: true
63
- } : {}
64
- };
65
- }
66
- function variableSlot(variable) {
67
- return [
68
- variable.key ?? variable.name,
69
- variable.namespace || '',
70
- variable.mode || ''
71
- ].join('\0');
72
- }
73
- function addVariable(input, variable, resolveVariableName) {
74
- const definition = normalizeVariable(variable, resolveVariableName);
75
- if (definition.mode) {
76
- input.modes ??= [];
77
- if (!input.modes.includes(definition.mode)) input.modes.push(definition.mode);
78
- }
79
- input.variables ??= [];
80
- const foundIndex = input.variables.findIndex((existing)=>variableSlot(existing) === variableSlot(definition));
81
- if (foundIndex !== -1) input.variables.splice(foundIndex, 1);
82
- input.variables.push(definition);
83
- }
84
- function cloneUtilityRule(rule) {
85
- return {
86
- declarations: {
87
- ...rule.declarations
88
- },
89
- ...rule.selector ? {
90
- selector: rule.selector
91
- } : {},
92
- ...rule.atRules?.length ? {
93
- atRules: [
94
- ...rule.atRules
95
- ]
96
- } : {}
97
- };
98
- }
99
- function cloneUtility(definition) {
100
- return {
101
- ...definition,
102
- type: definition.type || 'static',
103
- ...definition.pattern ? {
104
- pattern: {
105
- prefix: definition.pattern.prefix,
106
- values: [
107
- ...definition.pattern.values
108
- ]
109
- }
110
- } : {},
111
- ...definition.dynamic ? {
112
- dynamic: {
113
- key: definition.dynamic.key,
114
- ...definition.dynamic.variableAliasRefs?.length ? {
115
- variableAliasRefs: [
116
- ...definition.dynamic.variableAliasRefs
117
- ]
118
- } : {},
119
- ...definition.dynamic.kind ? {
120
- kind: definition.dynamic.kind
121
- } : {},
122
- ...definition.dynamic.values?.length ? {
123
- values: [
124
- ...definition.dynamic.values
125
- ]
126
- } : {},
127
- ...definition.dynamic.arbitrary ? {
128
- arbitrary: true
129
- } : {}
130
- }
131
- } : {},
132
- ...definition.declarations ? {
133
- declarations: {
134
- ...definition.declarations
135
- }
136
- } : {},
137
- ...definition.atRules?.length ? {
138
- atRules: [
139
- ...definition.atRules
140
- ]
141
- } : {},
142
- ...definition.rules?.length ? {
143
- rules: definition.rules.map(cloneUtilityRule)
144
- } : {}
145
- };
146
- }
147
- function normalizeDirectiveInput(input = {}, options = {}) {
148
- const source = getDirectiveInput(input);
149
- const resolveVariableName = createVariableNameResolver(source, {
150
- baseManifest: getResolutionManifest(options)
151
- });
152
- const normalized = {};
153
- if (source.rootSize !== undefined) normalized.rootSize = source.rootSize;
154
- if (source.baseUnit !== undefined) normalized.baseUnit = source.baseUnit;
155
- if (source.defaultMode !== undefined) normalized.defaultMode = source.defaultMode;
156
- if (source.modeTrigger !== undefined) normalized.modeTrigger = source.modeTrigger;
157
- if (source.scope !== undefined) normalized.scope = source.scope;
158
- if (source.important !== undefined) normalized.important = source.important;
159
- if (source.variants?.length) normalized.variants = source.variants.map((variant)=>({
160
- token: variant.token,
161
- branches: variant.branches.map((branch)=>({
162
- ...branch,
163
- ...branch.atRules?.length ? {
164
- atRules: [
165
- ...branch.atRules
166
- ]
167
- } : {}
168
- }))
169
- }));
170
- if (source.animations) normalized.animations = {
171
- ...source.animations
172
- };
173
- if (source.animationOptions) normalized.animationOptions = {
174
- ...source.animationOptions
175
- };
176
- if (source.utilities?.length) normalized.utilities = source.utilities.map(cloneUtility);
177
- for (const mode of source.modes || []){
178
- normalized.modes ??= [];
179
- if (!normalized.modes.includes(mode)) normalized.modes.push(mode);
180
- }
181
- for (const variable of source.variables || []){
182
- addVariable(normalized, variable, resolveVariableName);
183
- }
184
- return normalized;
185
- }
186
- function collectModeNames(input) {
187
- const modes = new Set(input.modes || []);
188
- if (isNamedDefaultMode(input.defaultMode)) modes.add(input.defaultMode);
189
- return modes;
190
- }
191
- function collectVariablesByNamespace(input, namespace, resolveVariableName) {
192
- return new Set((input.variables || []).map(resolveVariableName).filter((variable)=>variable.namespace === namespace).map((variable)=>variable.key).filter((key)=>Boolean(key)));
193
- }
194
- function validateTokenConflicts(input, resolveVariableName) {
195
- const modes = collectModeNames(input);
196
- const breakpoints = collectVariablesByNamespace(input, 'breakpoint', resolveVariableName);
197
- const containers = collectVariablesByNamespace(input, 'container', resolveVariableName);
198
- for (const mode of modes){
199
- if (breakpoints.has(mode)) {
200
- throw new Error(`Mode "${mode}" conflicts with breakpoint variable "--breakpoint-${mode}"`);
201
- }
202
- }
203
- for (const breakpoint of breakpoints){
204
- if (modes.has(breakpoint)) {
205
- throw new Error(`Breakpoint variable "--breakpoint-${breakpoint}" conflicts with mode "${breakpoint}"`);
206
- }
207
- }
208
- const variantNames = (input.variants || []).filter((variant)=>variant.token.startsWith('@')).map((variant)=>variant.token.slice(1));
209
- for (const token of variantNames){
210
- if (modes.has(token)) {
211
- throw new Error(`Variant "${token}" conflicts with mode "${token}"`);
212
- }
213
- if (breakpoints.has(token)) {
214
- throw new Error(`Variant "${token}" conflicts with breakpoint variable "--breakpoint-${token}"`);
215
- }
216
- if (containers.has(token)) {
217
- throw new Error(`Variant "${token}" conflicts with container variable "--container-${token}"`);
218
- }
219
- }
220
- }
221
- function warnUnsupportedMediaModes(input, options, warnings) {
222
- if (input.modeTrigger !== 'media') return;
223
- const customModes = new Set((input.modes || []).filter((mode)=>!MEDIA_MODE_NAMES.has(mode)));
224
- if (isNamedDefaultMode(input.defaultMode) && !MEDIA_MODE_NAMES.has(input.defaultMode)) {
225
- customModes.add(input.defaultMode);
226
- }
227
- if (!customModes.size) return;
228
- const modeList = [
229
- ...customModes
230
- ].map((mode)=>`"${mode}"`).join(', ');
231
- const subject = customModes.size === 1 ? 'mode' : 'modes';
232
- warn(warnings, options, `Custom ${subject} ${modeList} will not work with mode-trigger: media. Browsers only support light and dark prefers-color-scheme values; use mode-trigger: class or host for custom modes.`);
233
- }
234
- function createDirectiveCSS(input, options) {
235
- return createCompilerCSS(createMasterCSSManifest(input, {
236
- baseManifest: getResolutionManifest(options)
237
- }), undefined, {
238
- nativeDeclarationMatcher: cssTreeNativeDeclarationMatcher
239
- });
240
- }
241
- function getUtilityAtRuleDefinitions(utility) {
242
- const atRules = [];
243
- if (utility.atRules) {
244
- for (const id of [
245
- 'container',
246
- 'starting-style',
247
- 'supports',
248
- 'media',
249
- 'layer'
250
- ]){
251
- const nodes = utility.atRules[id];
252
- if (!nodes) continue;
253
- if (id === 'layer' && utility.explicitLayerName) continue;
254
- atRules.push(generateAt({
255
- id,
256
- nodes
257
- }));
258
- }
259
- }
260
- return atRules;
261
- }
262
- function getComposedUtilitySelector(utility, css) {
263
- let selector = utility.selectorTemplate ? '&' : utility.selectorNodes ? generateSelector(utility.selectorNodes, '&') : '&';
264
- if (utility.selectorTemplate) {
265
- selector = utility.selectorTemplate.replace(/&/g, selector);
266
- }
267
- if (utility.mode && css.settings.modeTrigger !== 'media') {
268
- const modeSelector = css.getModeSelector(utility.mode);
269
- if (modeSelector) selector = `${modeSelector} ${selector}`;
270
- }
271
- return selector;
272
- }
273
- function cloneDeclarations(declarations, important) {
274
- const result = {};
275
- for(const propertyName in declarations){
276
- const propertyValue = declarations[propertyName];
277
- const value = String(propertyValue);
278
- result[propertyName] = important && !value.endsWith('!important') ? `${value}!important` : value;
279
- }
280
- return result;
281
- }
282
- function createStyleDefinitionsFromCompose(definition, css) {
283
- const utilities = css.createRules(definition.className);
284
- if (!utilities.length) {
285
- throw new CSSDirectiveError('invalid-compose-class', `Invalid @compose class: ${definition.className}`, definition.source || definition.directiveSource);
286
- }
287
- return utilities.flatMap((utility)=>{
288
- const selector = getComposedUtilitySelector(utility, css);
289
- const layer = utility.explicitLayerName;
290
- const utilityAtRules = getUtilityAtRuleDefinitions(utility);
291
- const declarationRules = utility.declarationRules || (utility.declarations ? [
292
- {
293
- declarations: utility.declarations
294
- }
295
- ] : []);
296
- return declarationRules.map(({ declarations, atRules, selector: ruleSelector })=>({
297
- utility,
298
- selector: ruleSelector ? combineStyleSelectors(selector, ruleSelector) : selector,
299
- declarations: cloneDeclarations(declarations, utility.important),
300
- ...layer ? {
301
- layer
302
- } : {},
303
- ...[
304
- ...utilityAtRules,
305
- ...atRules || []
306
- ].length ? {
307
- atRules: [
308
- ...utilityAtRules,
309
- ...atRules || []
310
- ]
311
- } : {}
312
- }));
313
- });
314
- }
315
- function combineSelectorWrapper(selector, wrapper) {
316
- return wrapper.replace(/&/g, selector);
317
- }
318
- function mergeResolvedVariantReferenceBranch(branch, resolved, token) {
319
- const nextLayer = resolved.layer || branch.layer;
320
- if (branch.layer && resolved.layer && branch.layer !== resolved.layer) {
321
- throw new Error(`@variant ${token} cannot assign multiple layers`);
322
- }
323
- return {
324
- selector: resolved.selector ? combineSelectorWrapper(branch.selector || '&', resolved.selector) : branch.selector,
325
- atRules: [
326
- ...branch.atRules || [],
327
- ...resolved.atRules || []
328
- ],
329
- ...nextLayer ? {
330
- layer: nextLayer
331
- } : {}
332
- };
333
- }
334
- function cloneConfiguredVariantBranches(token, css) {
335
- const configuredVariant = css.resolveVariant(token);
336
- if (configuredVariant) {
337
- return configuredVariant.map((branch)=>({
338
- ...branch.selector ? {
339
- selector: branch.selector
340
- } : {},
341
- ...branch.atRules?.length ? {
342
- atRules: [
343
- ...branch.atRules
344
- ]
345
- } : {},
346
- ...branch.layer ? {
347
- layer: branch.layer
348
- } : {}
349
- }));
350
- }
351
- }
352
- function findClosingParen(value, start) {
353
- let depth = 0;
354
- let quote = '';
355
- for(let index = start; index < value.length; index++){
356
- const char = value[index];
357
- if (quote) {
358
- if (char === '\\') {
359
- index++;
360
- } else if (char === quote) {
361
- quote = '';
362
- }
363
- continue;
364
- }
365
- if (char === '"' || char === '\'') {
366
- quote = char;
367
- continue;
368
- }
369
- if (char === '(') depth++;
370
- if (char === ')') {
371
- depth--;
372
- if (depth === 0) return index;
373
- }
374
- }
375
- return -1;
376
- }
377
- function resolveSelectorVariantStack(selectorStack, css, token) {
378
- let branches = [
379
- {}
380
- ];
381
- const selectorVariantTokens = [
382
- ...css.variants.keys()
383
- ].filter((variantToken)=>variantToken.startsWith(':')).sort((a, b)=>b.length - a.length);
384
- let index = 0;
385
- let raw = '';
386
- const flushRaw = ()=>{
387
- if (!raw) return;
388
- const selector = generateSelector(parseSelector(raw, css), '&');
389
- branches = branches.map((branch)=>mergeResolvedVariantReferenceBranch(branch, {
390
- selector
391
- }, token));
392
- raw = '';
393
- };
394
- while(index < selectorStack.length){
395
- const matchedToken = selectorVariantTokens.find((variantToken)=>{
396
- if (!selectorStack.startsWith(variantToken, index)) return false;
397
- const next = selectorStack[index + variantToken.length];
398
- return next === undefined || next === '(' || !/[-_a-zA-Z0-9]/.test(next);
399
- });
400
- if (!matchedToken) {
401
- raw += selectorStack[index++];
402
- continue;
403
- }
404
- const configuredBranches = cloneConfiguredVariantBranches(matchedToken, css);
405
- if (!configuredBranches) {
406
- raw += selectorStack[index++];
407
- continue;
408
- }
409
- flushRaw();
410
- index += matchedToken.length;
411
- let suffix = '';
412
- if (selectorStack[index] === '(') {
413
- const end = findClosingParen(selectorStack, index);
414
- if (end !== -1) {
415
- suffix = selectorStack.slice(index, end + 1);
416
- index = end + 1;
417
- }
418
- }
419
- branches = branches.flatMap((branch)=>configuredBranches.map((configuredBranch)=>{
420
- const selector = configuredBranch.selector && suffix ? configuredBranch.selector + suffix : configuredBranch.selector;
421
- return mergeResolvedVariantReferenceBranch(branch, {
422
- ...configuredBranch,
423
- ...selector ? {
424
- selector
425
- } : {}
426
- }, token);
427
- }));
428
- }
429
- flushRaw();
430
- return branches;
431
- }
432
- function resolveAtVariantReference(token, css) {
433
- const configuredVariant = cloneConfiguredVariantBranches(token, css);
434
- if (configuredVariant) return configuredVariant;
435
- const atToken = token.slice(1);
436
- if (css.modes.includes(atToken)) {
437
- const modeSelector = css.getModeSelector(atToken);
438
- return modeSelector ? [
439
- {
440
- selector: `${modeSelector} &`
441
- }
442
- ] : [
443
- {
444
- atRules: [
445
- `@media (prefers-color-scheme:${atToken})`
446
- ]
447
- }
448
- ];
449
- }
450
- if (/^-?[_a-zA-Z][-_a-zA-Z0-9]*$/.test(atToken) && !css.atRules.has(atToken)) {
451
- throw new Error(`Unknown @variant token: ${token}`);
452
- }
453
- return [
454
- {
455
- atRules: [
456
- generateAt(parseAt(atToken, css))
457
- ]
458
- }
459
- ];
460
- }
461
- function resolveMasterVariantReference(token, css) {
462
- if (!token.startsWith(':') && !token.startsWith('@')) {
463
- throw new Error(`@variant requires a full variant token: ${token}`);
464
- }
465
- const [selectorStack = '', ...conditionStacks] = token.split('@');
466
- let branches = selectorStack ? resolveSelectorVariantStack(selectorStack, css, token) : [
467
- {}
468
- ];
469
- for (const conditionStack of conditionStacks){
470
- if (!conditionStack) continue;
471
- const resolvedBranches = resolveAtVariantReference(`@${conditionStack}`, css);
472
- branches = branches.flatMap((branch)=>resolvedBranches.map((resolved)=>mergeResolvedVariantReferenceBranch(branch, resolved, token)));
473
- }
474
- return branches;
475
- }
476
- function resolveConfiguredBranches(atRules, css, selector = '&', layer) {
477
- let branches = [
478
- {
479
- selector,
480
- ...layer ? {
481
- layer
482
- } : {}
483
- }
484
- ];
485
- if (!atRules?.length) return branches;
486
- for (const atRule of atRules){
487
- const token = readCSSDirectiveVariantReference(atRule);
488
- if (!token) {
489
- branches = branches.map((branch)=>({
490
- ...branch,
491
- atRules: [
492
- ...branch.atRules || [],
493
- atRule
494
- ]
495
- }));
496
- continue;
497
- }
498
- const resolvedBranches = resolveMasterVariantReference(token, css);
499
- branches = branches.flatMap((branch)=>resolvedBranches.map((resolved)=>{
500
- const nextLayer = resolved.layer || branch.layer;
501
- if (branch.layer && resolved.layer && branch.layer !== resolved.layer) {
502
- throw new Error(`@variant ${token} cannot assign multiple layers`);
503
- }
504
- return {
505
- selector: resolved.selector ? combineSelectorWrapper(branch.selector, resolved.selector) : branch.selector,
506
- atRules: [
507
- ...branch.atRules || [],
508
- ...resolved.atRules || []
509
- ],
510
- ...nextLayer ? {
511
- layer: nextLayer
512
- } : {}
513
- };
514
- }));
515
- }
516
- return branches.map((branch)=>({
517
- selector: branch.selector,
518
- ...branch.atRules?.length ? {
519
- atRules: branch.atRules
520
- } : {},
521
- ...branch.layer ? {
522
- layer: branch.layer
523
- } : {}
524
- }));
525
- }
526
- function ensureUtilityRules(definition) {
527
- if (!definition.declarations) return;
528
- const declarations = definition.declarations;
529
- delete definition.declarations;
530
- const atRules = definition.atRules;
531
- delete definition.atRules;
532
- definition.rules ??= [];
533
- definition.rules.push({
534
- ...atRules?.length ? {
535
- atRules: [
536
- ...atRules
537
- ]
538
- } : {},
539
- declarations
540
- });
541
- }
542
- function finalizeUtilityDefinitions(input, css) {
543
- const utilities = input.utilities;
544
- if (!utilities?.length) return;
545
- for (const definition of utilities){
546
- if (definition.atRules?.some(readCSSDirectiveVariantReference)) {
547
- const resolvedBranches = resolveConfiguredBranches(definition.atRules, css);
548
- delete definition.atRules;
549
- if (definition.declarations) {
550
- definition.rules ??= [];
551
- for (const resolved of resolvedBranches){
552
- definition.rules.push({
553
- declarations: definition.declarations,
554
- ...resolved.selector !== '&' ? {
555
- selector: resolved.selector
556
- } : {},
557
- ...resolved.atRules?.length ? {
558
- atRules: resolved.atRules
559
- } : {}
560
- });
561
- }
562
- delete definition.declarations;
563
- }
564
- }
565
- if (!definition.rules?.length) continue;
566
- definition.rules = definition.rules.flatMap((rule)=>{
567
- const resolvedBranches = resolveConfiguredBranches(rule.atRules, css, rule.selector || '&');
568
- return resolvedBranches.map((resolved)=>({
569
- declarations: rule.declarations,
570
- ...resolved.selector !== '&' ? {
571
- selector: resolved.selector
572
- } : {},
573
- ...resolved.atRules?.length ? {
574
- atRules: resolved.atRules
575
- } : {}
576
- }));
577
- });
578
- }
579
- }
580
- function getStyleMergeBucketKey(selector, atRules, layer) {
581
- return JSON.stringify([
582
- layer || '',
583
- selector,
584
- atRules || []
585
- ]);
586
- }
587
- function pushStyleMergeEvent(buckets, selector, atRules, layer, event) {
588
- const key = getStyleMergeBucketKey(selector, atRules, layer);
589
- const bucket = buckets.get(key) || {
590
- selector,
591
- ...atRules?.length ? {
592
- atRules
593
- } : {},
594
- ...layer ? {
595
- layer
596
- } : {},
597
- order: event.order,
598
- events: []
599
- };
600
- bucket.order = Math.min(bucket.order, event.order);
601
- bucket.events.push(event);
602
- buckets.set(key, bucket);
603
- }
604
- function isImportantStyleDeclarationValue(value) {
605
- return String(value).trim().endsWith('!important');
606
- }
607
- function applyStyleDeclaration(declarations, propertyName, value) {
608
- const key = propertyName;
609
- const currentValue = declarations[key];
610
- if (currentValue !== undefined && isImportantStyleDeclarationValue(currentValue) && !isImportantStyleDeclarationValue(value)) {
611
- return;
612
- }
613
- delete declarations[key];
614
- declarations[key] = value;
615
- }
616
- function applyStyleDeclarations(declarations, incomingDeclarations) {
617
- for(const propertyName in incomingDeclarations){
618
- applyStyleDeclaration(declarations, propertyName, incomingDeclarations[propertyName]);
619
- }
620
- }
621
- function createMergedStyleDefinition(bucket) {
622
- const declarations = {};
623
- const composeBatch = [];
624
- const flushComposeBatch = ()=>{
625
- composeBatch.sort((a, b)=>compareRulePriority(a.utility, b.utility) || a.order - b.order);
626
- for (const event of composeBatch){
627
- applyStyleDeclarations(declarations, event.declarations);
628
- }
629
- composeBatch.length = 0;
630
- };
631
- for (const event of [
632
- ...bucket.events
633
- ].sort((a, b)=>a.order - b.order)){
634
- if (event.type === 'compose') {
635
- composeBatch.push(event);
636
- continue;
637
- }
638
- flushComposeBatch();
639
- applyStyleDeclarations(declarations, event.declarations);
640
- }
641
- flushComposeBatch();
642
- if (!Object.keys(declarations).length) return;
643
- return {
644
- selector: bucket.selector,
645
- declarations,
646
- ...bucket.atRules?.length ? {
647
- atRules: bucket.atRules
648
- } : {},
649
- ...bucket.layer ? {
650
- layer: bucket.layer
651
- } : {}
652
- };
653
- }
654
- function normalizeStyleAtFeatureValue(value, unit, rootSize) {
655
- if (unit === 'px') return value / rootSize;
656
- return value;
657
- }
658
- function getStyleAtRuleFeatures(atRules, rootSize) {
659
- const featureMap = new Map();
660
- for (const atRule of atRules || []){
661
- for (const match of atRule.matchAll(STYLE_AT_FEATURE_REGEX)){
662
- const [, name, operator, rawValue, unit] = match;
663
- const value = normalizeStyleAtFeatureValue(Number(rawValue), unit, rootSize);
664
- const entry = featureMap.get(name) ?? {};
665
- switch(operator){
666
- case '>':
667
- entry.min = value + 0.02;
668
- break;
669
- case '>=':
670
- entry.min = value;
671
- break;
672
- case '<':
673
- entry.max = value - 0.02;
674
- break;
675
- case '<=':
676
- entry.max = value;
677
- break;
678
- }
679
- featureMap.set(name, entry);
680
- }
681
- }
682
- return [
683
- ...featureMap.entries()
684
- ].map(([name, entry])=>[
685
- name,
686
- entry.min ?? 0,
687
- entry.max ?? Number.MAX_SAFE_INTEGER
688
- ]).sort(([a], [b])=>a.localeCompare(b, undefined, {
689
- numeric: true
690
- }));
691
- }
692
- function compareStyleAtRuleFeatures(a, b) {
693
- const len = Math.max(a.length, b.length);
694
- for(let index = 0; index < len; index++){
695
- const left = a[index];
696
- const right = b[index];
697
- if (!left) return -1;
698
- if (!right) return 1;
699
- const [nameA, minA, maxA] = left;
700
- const [nameB, minB, maxB] = right;
701
- const nameCompare = nameA.localeCompare(nameB, undefined, {
702
- numeric: true
703
- });
704
- if (nameCompare !== 0) return nameCompare;
705
- const rangeA = maxA - minA;
706
- const rangeB = maxB - minB;
707
- if (rangeA !== rangeB) return rangeB - rangeA;
708
- if (minA !== minB) return minB - minA;
709
- if (maxA !== maxB) return maxB - maxA;
710
- }
711
- return 0;
712
- }
713
- function compareStyleMergeBuckets(a, b, rootSize) {
714
- const layerA = a.layer || 'components';
715
- const layerB = b.layer || 'components';
716
- if (layerA === layerB && a.selector === b.selector) {
717
- const atRuleStateA = a.atRules?.length ? 1 : 0;
718
- const atRuleStateB = b.atRules?.length ? 1 : 0;
719
- if (atRuleStateA !== atRuleStateB) return atRuleStateA - atRuleStateB;
720
- if (atRuleStateA && atRuleStateB) {
721
- const featuresA = getStyleAtRuleFeatures(a.atRules, rootSize);
722
- const featuresB = getStyleAtRuleFeatures(b.atRules, rootSize);
723
- if (featuresA.length && featuresB.length) {
724
- const featureCompare = compareStyleAtRuleFeatures(featuresA, featuresB);
725
- if (featureCompare !== 0) return featureCompare;
726
- }
727
- }
728
- }
729
- return a.order - b.order;
730
- }
731
- function createMergedStyleDefinitions(definitions, css, targetLayer) {
732
- const buckets = new Map();
733
- for (const definition of definitions){
734
- if (definition.type === 'compose') {
735
- const composedDefinitions = createStyleDefinitionsFromCompose(definition, css);
736
- for (const composedDefinition of composedDefinitions){
737
- const { atRules: composedAtRules, ...composedDefinitionWithoutAtRules } = composedDefinition;
738
- const selector = combineStyleSelectors(definition.selector, composedDefinition.selector);
739
- const resolvedBranches = resolveConfiguredBranches([
740
- ...definition.atRules || [],
741
- ...composedAtRules || []
742
- ], css, selector, targetLayer || composedDefinitionWithoutAtRules.layer);
743
- for (const resolved of resolvedBranches){
744
- pushStyleMergeEvent(buckets, resolved.selector, resolved.atRules, resolved.layer, {
745
- type: 'compose',
746
- order: definition.order,
747
- utility: composedDefinitionWithoutAtRules.utility,
748
- declarations: composedDefinitionWithoutAtRules.declarations
749
- });
750
- }
751
- }
752
- } else {
753
- const resolvedBranches = resolveConfiguredBranches(definition.atRules, css, definition.selector, targetLayer || definition.layer);
754
- for (const resolved of resolvedBranches){
755
- pushStyleMergeEvent(buckets, resolved.selector, resolved.atRules, resolved.layer, {
756
- type: 'native',
757
- order: definition.order,
758
- declarations: definition.declarations
759
- });
760
- }
761
- }
762
- }
763
- const rootSize = css.settings.rootSize || 16;
764
- return [
765
- ...buckets.values()
766
- ].sort((a, b)=>compareStyleMergeBuckets(a, b, rootSize)).flatMap((bucket)=>{
767
- const definition = createMergedStyleDefinition(bucket);
768
- return definition ? [
769
- definition
770
- ] : [];
771
- });
772
- }
773
- function isManagedStyleDefinition(definition) {
774
- return Boolean(definition.name);
775
- }
776
- function getManagedStyleDefinitionLayer(definition) {
777
- return definition.layer || 'components';
778
- }
779
- function getManagedStyleDefinitionKey(definition) {
780
- return `${definition.name}\0${getManagedStyleDefinitionLayer(definition)}`;
781
- }
782
- function splitManagedStyleDefinitionKey(key) {
783
- const [name, layer] = key.split('\0');
784
- return {
785
- name,
786
- layer: layer
787
- };
788
- }
789
- function getManagedComposeDependencyName(className, names) {
790
- const sortedNames = [
791
- ...names
792
- ].sort((a, b)=>b.length - a.length);
793
- for (const name of sortedNames){
794
- if (className === name) return name;
795
- const next = className[name.length];
796
- if (className.startsWith(name) && (next === ':' || next === '@' || next === '!')) {
797
- return name;
798
- }
799
- }
800
- }
801
- function sortManagedStyleDefinitionKeys(groups, keysByName) {
802
- const names = new Set(keysByName.keys());
803
- const dependencies = new Map();
804
- const dependencyDefinitions = new Map();
805
- for (const [key, definitions] of groups){
806
- const keyDependencies = new Set();
807
- for (const definition of definitions){
808
- if (definition.type !== 'compose') continue;
809
- const dependencyName = getManagedComposeDependencyName(definition.className, names);
810
- if (!dependencyName) continue;
811
- for (const dependencyKey of keysByName.get(dependencyName) || []){
812
- keyDependencies.add(dependencyKey);
813
- dependencyDefinitions.set(`${key}\0${dependencyKey}`, definition);
814
- }
815
- }
816
- dependencies.set(key, keyDependencies);
817
- }
818
- const sorted = [];
819
- const seen = new Set();
820
- const visiting = new Set();
821
- const path = [];
822
- function visit(key) {
823
- if (seen.has(key)) return;
824
- if (visiting.has(key)) {
825
- const cycleKeys = [
826
- ...path.slice(path.indexOf(key)),
827
- key
828
- ];
829
- const cycle = cycleKeys.map((cycleKey)=>splitManagedStyleDefinitionKey(cycleKey).name).join(' -> ');
830
- const related = cycleKeys.slice(0, -1).flatMap((cycleKey, index)=>{
831
- const nextKey = cycleKeys[index + 1];
832
- const definition = dependencyDefinitions.get(`${cycleKey}\0${nextKey}`);
833
- const source = definition?.source || definition?.directiveSource;
834
- return source ? [
835
- {
836
- message: `${splitManagedStyleDefinitionKey(cycleKey).name} composes ${definition.className}`,
837
- source
838
- }
839
- ] : [];
840
- });
841
- throw new CSSDirectiveError('circular-compose-dependency', `Circular @compose dependency detected: ${cycle}`, related[0]?.source, related);
842
- }
843
- visiting.add(key);
844
- path.push(key);
845
- for (const dependency of dependencies.get(key) || []){
846
- visit(dependency);
847
- }
848
- path.pop();
849
- visiting.delete(key);
850
- seen.add(key);
851
- sorted.push(key);
852
- }
853
- for (const key of groups.keys()){
854
- visit(key);
855
- }
856
- return sorted;
857
- }
858
- function renderStyleDefinitions(definitions) {
859
- return definitions.map((definition)=>{
860
- const body = Object.entries(definition.declarations).map(([propertyName, value])=>`${propertyName}:${value}`).join(';');
861
- return wrapAtRules(`${definition.selector}{${body}}`, definition.atRules);
862
- }).join('');
863
- }
864
- function getStaticUtilityDefinition(input, name, layer) {
865
- input.utilities ??= [];
866
- const existing = input.utilities.find((utility)=>utility.name === name && (utility.layer || 'utilities') === layer);
867
- if (existing) {
868
- existing.type = 'static';
869
- existing.layer = layer;
870
- return existing;
871
- }
872
- const utility = {
873
- name,
874
- type: 'static',
875
- layer
876
- };
877
- input.utilities.push(utility);
878
- return utility;
879
- }
880
- function pushStaticUtilityStyleRule(definition, styleDefinition) {
881
- const rule = {
882
- declarations: styleDefinition.declarations,
883
- ...styleDefinition.selector !== '&' ? {
884
- selector: styleDefinition.selector
885
- } : {},
886
- ...styleDefinition.atRules?.length ? {
887
- atRules: styleDefinition.atRules
888
- } : {}
889
- };
890
- if (!definition.declarations && !definition.rules?.length && !rule.selector && !rule.atRules?.length) {
891
- definition.declarations = rule.declarations;
892
- return;
893
- }
894
- ensureUtilityRules(definition);
895
- definition.rules ??= [];
896
- definition.rules.push(rule);
897
- }
898
- function finalizeStyleDefinitions(input, styleDefinitions, css, options) {
899
- if (!styleDefinitions?.length) return '';
900
- const managedGroups = new Map();
901
- const keysByName = new Map();
902
- const nativeDefinitions = [];
903
- for (const definition of styleDefinitions){
904
- if (!isManagedStyleDefinition(definition)) {
905
- nativeDefinitions.push(definition);
906
- continue;
907
- }
908
- const key = getManagedStyleDefinitionKey(definition);
909
- const group = managedGroups.get(key);
910
- if (group) {
911
- group.push(definition);
912
- } else {
913
- managedGroups.set(key, [
914
- definition
915
- ]);
916
- }
917
- const nameKeys = keysByName.get(definition.name);
918
- if (nameKeys) {
919
- nameKeys.add(key);
920
- } else {
921
- keysByName.set(definition.name, new Set([
922
- key
923
- ]));
924
- }
925
- }
926
- for (const key of sortManagedStyleDefinitionKeys(managedGroups, keysByName)){
927
- const definitions = managedGroups.get(key);
928
- if (!definitions) continue;
929
- const { name, layer } = splitManagedStyleDefinitionKey(key);
930
- const mergedDefinitions = createMergedStyleDefinitions(definitions, css, layer);
931
- for (const definition of mergedDefinitions){
932
- const utilityDefinition = getStaticUtilityDefinition(input, name, layer);
933
- pushStaticUtilityStyleRule(utilityDefinition, definition);
934
- }
935
- css.refresh(createMasterCSSManifest(input, {
936
- baseManifest: getResolutionManifest(options)
937
- }));
938
- }
939
- if (!nativeDefinitions.length) return '';
940
- return renderStyleDefinitions(createMergedStyleDefinitions(nativeDefinitions, css));
941
- }
942
- function lowerCSSDirectives(input, options = {}) {
943
- const directiveInput = normalizeDirectiveInput(input, options);
944
- const resolveVariableName = createVariableNameResolver(directiveInput, {
945
- baseManifest: getResolutionManifest(options)
946
- });
947
- const warnings = isCSSDirectiveResult(input) ? [
948
- ...input.warnings
949
- ] : [];
950
- validateTokenConflicts(directiveInput, resolveVariableName);
951
- warnUnsupportedMediaModes(directiveInput, options, warnings);
952
- const css = createDirectiveCSS(directiveInput, options);
953
- finalizeUtilityDefinitions(directiveInput, css);
954
- css.refresh(createMasterCSSManifest(directiveInput, {
955
- baseManifest: getResolutionManifest(options)
956
- }));
957
- const generatedCSS = finalizeStyleDefinitions(directiveInput, getStyleDefinitions(input), css, options);
958
- const manifest = createMasterCSSManifest(directiveInput, {
959
- baseManifest: options.baseManifest
960
- });
961
- return {
962
- input: directiveInput,
963
- manifest,
964
- warnings,
965
- generatedCSS
966
- };
967
- }
968
-
969
- export { lowerCSSDirectives as default };