@master/css-compiler 2.0.0-rc.84 → 2.0.0-rc.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
+ import { normalizeStylesheetValue } from "./stylesheet-value.js";
1
2
  import { addCompilerDiagnosticCount, setCompilerDiagnosticCount, timeCompilerDiagnostic } from "./diagnostics.js";
2
- import { createCompilerCSS, parseAt, parseSelector } from "@master/css-engine/compiler";
3
+ import { createCompilerCSS, parseCondition, parseSelector } from "@master/css-engine/compiler";
3
4
  import UtilityType from "@master/css-schema/utility-type";
4
5
  import { flattenMasterCSSManifestVariables, groupMasterCSSManifestVariables } from "@master/css-schema/manifest";
5
6
  import { builtinNamespaces } from "@master/css-engine";
@@ -92,12 +93,6 @@ function getVariableNumericValue(value, namespace) {
92
93
  ...match[2] ? { unit: match[2] } : {}
93
94
  };
94
95
  }
95
- function collectVariableDependencies(value, dependencies = /* @__PURE__ */ new Set()) {
96
- if (typeof value !== "string") return dependencies;
97
- for (const match of value.matchAll(/\$(-?[_a-zA-Z0-9-]+)/g)) dependencies.add(match[1]);
98
- for (const match of value.matchAll(/var\(\s*--(-?[_a-zA-Z0-9-]+)/g)) dependencies.add(match[1]);
99
- return dependencies;
100
- }
101
96
  function variableSlot(variable) {
102
97
  return variable.name || `${variable.namespace || ""}\0${variable.key}`;
103
98
  }
@@ -114,10 +109,15 @@ function compileVariables(input, resolveVariableName) {
114
109
  for (const definition of input) {
115
110
  const resolved = resolveVariableName(definition);
116
111
  if (!resolved.name) continue;
117
- const value = normalizeZero(definition.value);
112
+ const rawValue = normalizeZero(definition.value);
113
+ const normalized = typeof rawValue === "string" || typeof rawValue === "number" ? normalizeStylesheetValue(rawValue, { replacePipes: true }) : {
114
+ value: rawValue,
115
+ dependencies: /* @__PURE__ */ new Set()
116
+ };
117
+ const value = typeof rawValue === "number" ? rawValue : normalized.value;
118
118
  const numeric = getVariableNumericValue(value, resolved.namespace);
119
119
  const type = numeric ? "number" : getVariableType(value);
120
- const dependencies = collectVariableDependencies(value);
120
+ const dependencies = normalized.dependencies;
121
121
  if (definition.mode) {
122
122
  let target = byName.get(resolved.name);
123
123
  if (!target) {
@@ -161,7 +161,7 @@ function compileVariables(input, resolveVariableName) {
161
161
  }
162
162
  return variables.length ? variables : void 0;
163
163
  }
164
- function normalizeNumericAtRuleValue(variable, rootSize) {
164
+ function normalizeNumericConditionValue(variable, rootSize) {
165
165
  if (variable.key.startsWith("-")) return;
166
166
  const numeric = variable.numeric || (typeof variable.value === "number" ? { value: variable.value } : void 0);
167
167
  if (!numeric) return;
@@ -173,8 +173,8 @@ function normalizeNumericAtRuleValue(variable, rootSize) {
173
173
  default: return;
174
174
  }
175
175
  }
176
- function createVariableAtRule(variable, id, rootSize) {
177
- const value = normalizeNumericAtRuleValue(variable, rootSize);
176
+ function createVariableCondition(variable, id, rootSize) {
177
+ const value = normalizeNumericConditionValue(variable, rootSize);
178
178
  if (value === void 0) return;
179
179
  return {
180
180
  id,
@@ -185,36 +185,36 @@ function createVariableAtRule(variable, id, rootSize) {
185
185
  }]
186
186
  };
187
187
  }
188
- function compileAtRules(variables, rootSize) {
189
- const atRules = {};
190
- const breakpointAtRules = {};
191
- const containerAtRules = {};
188
+ function compileConditions(variables, rootSize) {
189
+ const conditions = {};
190
+ const breakpointConditions = {};
191
+ const containerConditions = {};
192
192
  for (const variable of variables || []) if (variable.namespace === "breakpoint") {
193
- const atRule = createVariableAtRule(variable, "media", rootSize);
194
- if (atRule) {
195
- atRules[variable.key] = atRule;
196
- breakpointAtRules[variable.key] = atRule;
193
+ const condition = createVariableCondition(variable, "media", rootSize);
194
+ if (condition) {
195
+ conditions[variable.key] = condition;
196
+ breakpointConditions[variable.key] = condition;
197
197
  }
198
198
  } else if (variable.namespace === "container") {
199
- const atRule = createVariableAtRule(variable, "container", rootSize);
200
- if (atRule) containerAtRules[variable.key] = atRule;
199
+ const condition = createVariableCondition(variable, "container", rootSize);
200
+ if (condition) containerConditions[variable.key] = condition;
201
201
  }
202
202
  return {
203
- atRules: Object.keys(atRules).length ? atRules : void 0,
204
- breakpointAtRules: Object.keys(breakpointAtRules).length ? breakpointAtRules : void 0,
205
- containerAtRules: Object.keys(containerAtRules).length ? containerAtRules : void 0
203
+ conditions: Object.keys(conditions).length ? conditions : void 0,
204
+ breakpointConditions: Object.keys(breakpointConditions).length ? breakpointConditions : void 0,
205
+ containerConditions: Object.keys(containerConditions).length ? containerConditions : void 0
206
206
  };
207
207
  }
208
- function cloneAtRuleNode(node) {
208
+ function cloneConditionNode(node) {
209
209
  return "children" in node ? {
210
210
  ...node,
211
- children: node.children.map(cloneAtRuleNode)
211
+ children: node.children.map(cloneConditionNode)
212
212
  } : { ...node };
213
213
  }
214
- function cloneAtRule(atRule) {
214
+ function cloneCondition(condition) {
215
215
  return {
216
- id: atRule.id,
217
- nodes: atRule.nodes.map(cloneAtRuleNode)
216
+ id: condition.id,
217
+ nodes: condition.nodes.map(cloneConditionNode)
218
218
  };
219
219
  }
220
220
  function cloneSelectorNode(node) {
@@ -227,12 +227,12 @@ function compileVariantBranch(branch, css) {
227
227
  const selector = branch.selector?.trim();
228
228
  const bodylessSelector = selector ? selector.includes("&") ? selector.replace(/&/g, "") : selector : void 0;
229
229
  const selectorNodes = branch.selectorNodes?.length ? branch.selectorNodes.map(cloneSelectorNode) : bodylessSelector ? parseSelector(bodylessSelector, css, false).map((node) => cloneSelectorNode(node)) : void 0;
230
- const atRuleNodes = branch.atRuleNodes?.length ? branch.atRuleNodes.map(cloneAtRule) : branch.atRules?.length ? branch.atRules.map((atRule) => cloneAtRule(parseAt(atRule, css, false))) : void 0;
230
+ const conditionNodes = branch.conditionNodes?.length ? branch.conditionNodes.map(cloneCondition) : branch.conditions?.length ? branch.conditions.map((condition) => cloneCondition(parseCondition(condition, css, false))) : void 0;
231
231
  return {
232
232
  ...branch,
233
233
  ...selectorNodes?.length ? { selectorNodes } : {},
234
- ...branch.atRules?.length ? { atRules: [...branch.atRules] } : {},
235
- ...atRuleNodes?.length ? { atRuleNodes } : {}
234
+ ...branch.conditions?.length ? { conditions: [...branch.conditions] } : {},
235
+ ...conditionNodes?.length ? { conditionNodes } : {}
236
236
  };
237
237
  }
238
238
  function compileVariants(input, baseManifest) {
@@ -240,7 +240,7 @@ function compileVariants(input, baseManifest) {
240
240
  const css = createCompilerCSS(baseManifest);
241
241
  const variants = [];
242
242
  const selectors = {};
243
- const atRules = {};
243
+ const conditions = {};
244
244
  for (const variant of input) {
245
245
  const branches = variant.branches.map((branch) => compileVariantBranch(branch, css));
246
246
  variants.push({
@@ -252,11 +252,11 @@ function compileVariants(input, baseManifest) {
252
252
  if (firstSelectorNodes?.length) selectors[variant.token] = firstSelectorNodes.map(cloneSelectorNode);
253
253
  }
254
254
  if (variant.token.startsWith("@")) {
255
- const firstAtRule = branches.find((branch) => branch.atRuleNodes?.length)?.atRuleNodes?.[0];
256
- if (firstAtRule) atRules[variant.token.slice(1)] = cloneAtRule(firstAtRule);
255
+ const firstCondition = branches.find((branch) => branch.conditionNodes?.length)?.conditionNodes?.[0];
256
+ if (firstCondition) conditions[variant.token.slice(1)] = cloneCondition(firstCondition);
257
257
  else {
258
258
  const firstLayer = branches.find((branch) => branch.layer)?.layer;
259
- if (firstLayer) atRules[variant.token.slice(1)] = {
259
+ if (firstLayer) conditions[variant.token.slice(1)] = {
260
260
  id: "layer",
261
261
  nodes: [{
262
262
  type: "string",
@@ -269,39 +269,100 @@ function compileVariants(input, baseManifest) {
269
269
  return {
270
270
  variants,
271
271
  ...Object.keys(selectors).length ? { selectors } : {},
272
- ...Object.keys(atRules).length ? { atRules } : {}
272
+ ...Object.keys(conditions).length ? { conditions } : {}
273
273
  };
274
274
  }
275
275
  function cloneDeclarations(declarations) {
276
276
  return Array.isArray(declarations) ? [...declarations] : { ...declarations };
277
277
  }
278
278
  function assertNoValuePlaceholder(declarations) {
279
- for (const property in declarations) if (declarations[property].includes("--value")) throw new Error("--value() is only supported inside managed pattern declarations");
279
+ for (const property in declarations) if (containsValuePlaceholderReference(declarations[property])) throw new Error("--value() is only supported inside managed pattern declarations");
280
280
  }
281
281
  function compileUtilityRule(rule) {
282
282
  assertNoValuePlaceholder(rule.declarations);
283
283
  return {
284
284
  declarations: cloneDeclarations(rule.declarations),
285
- ...rule.atRules?.length ? { atRules: [...rule.atRules] } : {},
285
+ ...rule.conditions?.length ? { conditions: [...rule.conditions] } : {},
286
286
  ...rule.selector && rule.selector !== "&" ? { selector: rule.selector } : {}
287
287
  };
288
288
  }
289
+ const VALUE_PLACEHOLDER_NAME = "--value";
289
290
  const VALUE_PLACEHOLDER_FUNCTION = "--value()";
290
- const VALUE_PLACEHOLDER_CALL = /--value\s*\(([^)]*)\)/g;
291
+ function isCSSIdentifierCharacter(value) {
292
+ return value !== void 0 && /[-_a-zA-Z0-9]/.test(value);
293
+ }
294
+ function skipQuotedText(value, index) {
295
+ const quote = value[index];
296
+ index++;
297
+ while (index < value.length) {
298
+ if (value[index] === "\\") {
299
+ index += 2;
300
+ continue;
301
+ }
302
+ if (value[index] === quote) return index + 1;
303
+ index++;
304
+ }
305
+ return index;
306
+ }
307
+ function skipComment(value, index) {
308
+ const end = value.indexOf("*/", index + 2);
309
+ return end === -1 ? value.length : end + 2;
310
+ }
311
+ function containsValuePlaceholderReference(value) {
312
+ if (!value.includes(VALUE_PLACEHOLDER_NAME)) return false;
313
+ for (let index = 0; index < value.length;) {
314
+ const character = value[index];
315
+ if (character === "\"" || character === "'") {
316
+ index = skipQuotedText(value, index);
317
+ continue;
318
+ }
319
+ if (character === "/" && value[index + 1] === "*") {
320
+ index = skipComment(value, index);
321
+ continue;
322
+ }
323
+ if (value.startsWith(VALUE_PLACEHOLDER_NAME, index)) return true;
324
+ index++;
325
+ }
326
+ return false;
327
+ }
328
+ function parseValuePlaceholderCall(value, index) {
329
+ if (isCSSIdentifierCharacter(value[index - 1])) throw new Error("--value() must be a standalone CSS value placeholder");
330
+ const openParenIndex = index + 7;
331
+ if (value[openParenIndex] !== "(") throw new Error("--value() must be called as --value()");
332
+ const closeParenIndex = value.indexOf(")", openParenIndex + 1);
333
+ if (closeParenIndex === -1) throw new Error("--value() must be called as --value()");
334
+ if (value.slice(openParenIndex + 1, closeParenIndex).trim()) throw new Error("--value() does not accept arguments");
335
+ const end = closeParenIndex + 1;
336
+ if (isCSSIdentifierCharacter(value[end])) throw new Error("--value() must be a standalone CSS value placeholder");
337
+ return end;
338
+ }
291
339
  function compilePatternDeclarationValue(value) {
292
- if (!value.includes("--value")) return value;
340
+ if (!value.includes(VALUE_PLACEHOLDER_NAME)) return value;
293
341
  const parts = [];
294
342
  let lastIndex = 0;
295
343
  let matched = false;
296
- VALUE_PLACEHOLDER_CALL.lastIndex = 0;
297
- for (const match of value.matchAll(VALUE_PLACEHOLDER_CALL)) {
344
+ for (let index = 0; index < value.length;) {
345
+ const character = value[index];
346
+ if (character === "\"" || character === "'") {
347
+ index = skipQuotedText(value, index);
348
+ continue;
349
+ }
350
+ if (character === "/" && value[index + 1] === "*") {
351
+ index = skipComment(value, index);
352
+ continue;
353
+ }
354
+ if (!value.startsWith(VALUE_PLACEHOLDER_NAME, index)) {
355
+ index++;
356
+ continue;
357
+ }
358
+ const end = parseValuePlaceholderCall(value, index);
298
359
  matched = true;
299
- if (match[1].trim()) throw new Error("--value() does not accept arguments");
300
- if (match.index > lastIndex) parts.push(value.slice(lastIndex, match.index));
360
+ if (index > lastIndex) parts.push(value.slice(lastIndex, index));
301
361
  parts.push(null);
302
- lastIndex = match.index + match[0].length;
362
+ lastIndex = end;
363
+ index = end;
303
364
  }
304
- if (!matched || value.slice(lastIndex).includes("--value")) throw new Error("--value() must be called as --value()");
365
+ if (!matched) return value;
305
366
  if (lastIndex < value.length) parts.push(value.slice(lastIndex));
306
367
  return value === VALUE_PLACEHOLDER_FUNCTION ? null : parts;
307
368
  }
@@ -313,7 +374,7 @@ function compilePatternDeclarations(declarations) {
313
374
  function compilePatternUtilityRule(rule) {
314
375
  return {
315
376
  declarations: compilePatternDeclarations(rule.declarations),
316
- ...rule.atRules?.length ? { atRules: [...rule.atRules] } : {},
377
+ ...rule.conditions?.length ? { conditions: [...rule.conditions] } : {},
317
378
  ...rule.selector && rule.selector !== "&" ? { selector: rule.selector } : {}
318
379
  };
319
380
  }
@@ -335,7 +396,8 @@ function getPatternMatcher(pattern) {
335
396
  return {
336
397
  type: "pattern",
337
398
  prefix: pattern.prefix,
338
- values: [...pattern.values]
399
+ values: [...pattern.values],
400
+ ...pattern.valueMap ? { valueMap: { ...pattern.valueMap } } : {}
339
401
  };
340
402
  }
341
403
  function getDynamicMatchers(dynamic) {
@@ -366,7 +428,7 @@ function compileUtility(definition, order) {
366
428
  const rules = [];
367
429
  if (definition.declarations) rules.push({
368
430
  declarations: compilePatternDeclarations(definition.declarations),
369
- ...definition.atRules?.length ? { atRules: [...definition.atRules] } : {}
431
+ ...definition.conditions?.length ? { conditions: [...definition.conditions] } : {}
370
432
  });
371
433
  if (definition.rules?.length) rules.push(...definition.rules.map(compilePatternUtilityRule));
372
434
  return {
@@ -387,7 +449,7 @@ function compileUtility(definition, order) {
387
449
  const rules = [];
388
450
  if (definition.declarations) rules.push({
389
451
  declarations: compilePatternDeclarations(definition.declarations),
390
- ...definition.atRules?.length ? { atRules: [...definition.atRules] } : {}
452
+ ...definition.conditions?.length ? { conditions: [...definition.conditions] } : {}
391
453
  });
392
454
  if (definition.rules?.length) rules.push(...definition.rules.map(compilePatternUtilityRule));
393
455
  return {
@@ -411,7 +473,7 @@ function compileUtility(definition, order) {
411
473
  assertNoValuePlaceholder(definition.declarations);
412
474
  rules.push({
413
475
  declarations: cloneDeclarations(definition.declarations),
414
- ...definition.atRules?.length ? { atRules: [...definition.atRules] } : {}
476
+ ...definition.conditions?.length ? { conditions: [...definition.conditions] } : {}
415
477
  });
416
478
  }
417
479
  if (definition.rules?.length) rules.push(...definition.rules.map(compileUtilityRule));
@@ -478,9 +540,9 @@ function mergeManifest(baseManifest, fragment) {
478
540
  animations: mergeRecords(baseManifest.animations, fragment.animations),
479
541
  animationOptions: mergeAnimationOptions(baseManifest.animationOptions, fragment.animationOptions, fragment.animations),
480
542
  variants: mergeBy(baseManifest.variants, fragment.variants, (variant) => variant.token),
481
- atRules: mergeRecords(baseManifest.atRules, fragment.atRules),
482
- breakpointAtRules: mergeRecords(baseManifest.breakpointAtRules, fragment.breakpointAtRules),
483
- containerAtRules: mergeRecords(baseManifest.containerAtRules, fragment.containerAtRules),
543
+ conditions: mergeRecords(baseManifest.conditions, fragment.conditions),
544
+ breakpointConditions: mergeRecords(baseManifest.breakpointConditions, fragment.breakpointConditions),
545
+ containerConditions: mergeRecords(baseManifest.containerConditions, fragment.containerConditions),
484
546
  selectors: mergeRecords(baseManifest.selectors, fragment.selectors),
485
547
  utilities: mergeBy(baseManifest.utilities, fragment.utilities, (utility) => `${utility.id}\0${utility.layer || ""}`),
486
548
  debug: mergeRecords(baseManifest.debug, fragment.debug)
@@ -498,7 +560,7 @@ function createMasterCSSManifest(input = {}, options = {}) {
498
560
  const resolveVariableName = timeCompilerDiagnostic(diagnostics, "manifest-variable-name-resolver-ms", () => createVariableNameResolver(input, options));
499
561
  const variableDefinitions = timeCompilerDiagnostic(diagnostics, "manifest-compile-variables-ms", () => compileVariables(input.variables, resolveVariableName));
500
562
  const variables = timeCompilerDiagnostic(diagnostics, "manifest-group-variables-ms", () => groupMasterCSSManifestVariables(variableDefinitions));
501
- const { atRules, breakpointAtRules, containerAtRules } = timeCompilerDiagnostic(diagnostics, "manifest-compile-at-rules-ms", () => compileAtRules(variableDefinitions, rootSize));
563
+ const { conditions, breakpointConditions, containerConditions } = timeCompilerDiagnostic(diagnostics, "manifest-compile-conditions-ms", () => compileConditions(variableDefinitions, rootSize));
502
564
  const settings = {
503
565
  ...input.rootSize !== void 0 ? { rootSize: input.rootSize } : {},
504
566
  ...input.baseUnit !== void 0 ? { baseUnit: input.baseUnit } : {},
@@ -512,11 +574,11 @@ function createMasterCSSManifest(input = {}, options = {}) {
512
574
  version: 1,
513
575
  ...Object.keys(settings).length ? { settings } : {},
514
576
  ...variables ? { variables } : {},
515
- ...atRules ? { atRules } : {},
516
- ...breakpointAtRules ? { breakpointAtRules } : {},
517
- ...containerAtRules ? { containerAtRules } : {}
577
+ ...conditions ? { conditions } : {},
578
+ ...breakpointConditions ? { breakpointConditions } : {},
579
+ ...containerConditions ? { containerConditions } : {}
518
580
  }));
519
- const { variants, selectors, atRules: variantAtRules } = timeCompilerDiagnostic(diagnostics, "manifest-compile-variants-ms", () => compileVariants(input.variants, variantBaseManifest));
581
+ const { variants, selectors, conditions: variantConditions } = timeCompilerDiagnostic(diagnostics, "manifest-compile-variants-ms", () => compileVariants(input.variants, variantBaseManifest));
520
582
  const utilities = timeCompilerDiagnostic(diagnostics, "manifest-compile-utilities-ms", () => compileUtilities(input.utilities));
521
583
  const animations = timeCompilerDiagnostic(diagnostics, "manifest-compile-animations-ms", () => compileAnimations(input.animations));
522
584
  const animationOptions = timeCompilerDiagnostic(diagnostics, "manifest-compile-animation-options-ms", () => compileAnimationOptions(input.animationOptions));
@@ -527,9 +589,9 @@ function createMasterCSSManifest(input = {}, options = {}) {
527
589
  ...animations ? { animations } : {},
528
590
  ...animationOptions ? { animationOptions } : {},
529
591
  ...variants?.length ? { variants } : {},
530
- ...atRules || variantAtRules ? { atRules: mergeRecords(atRules, variantAtRules) } : {},
531
- ...breakpointAtRules ? { breakpointAtRules } : {},
532
- ...containerAtRules ? { containerAtRules } : {},
592
+ ...conditions || variantConditions ? { conditions: mergeRecords(conditions, variantConditions) } : {},
593
+ ...breakpointConditions ? { breakpointConditions } : {},
594
+ ...containerConditions ? { containerConditions } : {},
533
595
  ...selectors ? { selectors } : {},
534
596
  ...utilities?.length ? { utilities } : {}
535
597
  };
@@ -538,7 +600,7 @@ function createMasterCSSManifest(input = {}, options = {}) {
538
600
  setCompilerDiagnosticCount(diagnostics, "manifest-output-utility-count", manifest.utilities?.length || 0);
539
601
  setCompilerDiagnosticCount(diagnostics, "manifest-output-variant-count", manifest.variants?.length || 0);
540
602
  setCompilerDiagnosticCount(diagnostics, "manifest-output-selector-count", Object.keys(manifest.selectors || {}).length);
541
- setCompilerDiagnosticCount(diagnostics, "manifest-output-at-rule-count", Object.keys(manifest.atRules || {}).length);
603
+ setCompilerDiagnosticCount(diagnostics, "manifest-output-condition-count", Object.keys(manifest.conditions || {}).length);
542
604
  setCompilerDiagnosticCount(diagnostics, "manifest-output-animation-count", Object.keys(manifest.animations || {}).length);
543
605
  return manifest;
544
606
  }
@@ -1,5 +1,4 @@
1
1
  import { NativeCSSDeclarationMatcher } from "@master/css-engine";
2
-
3
2
  //#region src/native-declaration.d.ts
4
3
  declare const cssTreeNativeDeclarationMatcher: NativeCSSDeclarationMatcher;
5
4
  //#endregion
@@ -0,0 +1,9 @@
1
+ //#region src/stylesheet-value.d.ts
2
+ declare function normalizeStylesheetValue(value: string | number, options?: {
3
+ replacePipes?: boolean;
4
+ }): {
5
+ value: string;
6
+ dependencies: Set<string>;
7
+ };
8
+ //#endregion
9
+ export { normalizeStylesheetValue };
@@ -0,0 +1,141 @@
1
+ import { collectCSSVariableReferences, findCSSClosingQuote, findCSSCommentEnd, readCSSFunction } from "@master/css-lexer";
2
+ //#region src/stylesheet-value.ts
3
+ const CSS_VARIABLE_ALIAS = /\$(-?[_a-zA-Z0-9-]+)\b/g;
4
+ const CSS_NUMBER = /^[+-]?(?:\d+(?:\.\d+)?|\.\d+)$/;
5
+ function collectUnquotedMatches(value, pattern) {
6
+ const matches = [];
7
+ for (let index = 0; index < value.length;) {
8
+ const char = value[index];
9
+ if (char === "\"" || char === "'") {
10
+ index = findCSSClosingQuote(value, index, char) + 1;
11
+ continue;
12
+ }
13
+ if (char === "/" && value[index + 1] === "*") {
14
+ index = findCSSCommentEnd(value, index);
15
+ continue;
16
+ }
17
+ pattern.lastIndex = index;
18
+ const match = pattern.exec(value);
19
+ if (!match || match.index !== index) {
20
+ index++;
21
+ continue;
22
+ }
23
+ matches.push(match);
24
+ index = pattern.lastIndex;
25
+ }
26
+ return matches;
27
+ }
28
+ function collectCSSVariableAliases(value) {
29
+ return collectUnquotedMatches(value, CSS_VARIABLE_ALIAS).filter((match) => value[match.index - 1] !== "\\");
30
+ }
31
+ function findTopLevelAlphaSeparator(value) {
32
+ let separatorIndex = -1;
33
+ let depth = 0;
34
+ for (let index = 0; index < value.length; index++) {
35
+ const char = value[index];
36
+ if (char === "\"" || char === "'") {
37
+ index = findCSSClosingQuote(value, index, char);
38
+ continue;
39
+ }
40
+ if (char === "/" && value[index + 1] === "*") {
41
+ index = findCSSCommentEnd(value, index) - 1;
42
+ continue;
43
+ }
44
+ if (char === "(") {
45
+ depth++;
46
+ continue;
47
+ }
48
+ if (char === ")") {
49
+ if (depth > 0) depth--;
50
+ continue;
51
+ }
52
+ if (char === "/" && depth === 0) {
53
+ if (separatorIndex !== -1) return;
54
+ separatorIndex = index;
55
+ }
56
+ }
57
+ return separatorIndex;
58
+ }
59
+ function isWholeCSSFunction(value, name) {
60
+ const trimmed = value.trim();
61
+ const fn = readCSSFunction(trimmed, 0, name);
62
+ return Boolean(fn && fn.end === trimmed.length);
63
+ }
64
+ function formatAlphaPercentage(value) {
65
+ return String(Object.is(value, -0) ? 0 : value).replace(/^(-?)0\./, "$1.") + "%";
66
+ }
67
+ function normalizeStylesheetAlpha(value) {
68
+ const trimmed = value.trim();
69
+ if (!trimmed) throw new Error("Invalid --alpha() function: alpha value cannot be empty");
70
+ if (CSS_NUMBER.test(trimmed)) {
71
+ const alpha = Number(trimmed);
72
+ if (alpha < 0 || alpha > 1) throw new Error(`Invalid --alpha() function: numeric alpha must be between 0 and 1: ${trimmed}`);
73
+ return formatAlphaPercentage(alpha * 100);
74
+ }
75
+ if (trimmed.endsWith("%") && CSS_NUMBER.test(trimmed.slice(0, -1))) {
76
+ const percentage = Number(trimmed.slice(0, -1));
77
+ if (percentage < 0 || percentage > 100) throw new Error(`Invalid --alpha() function: percentage alpha must be between 0% and 100%: ${trimmed}`);
78
+ return formatAlphaPercentage(percentage);
79
+ }
80
+ if (isWholeCSSFunction(trimmed, "var") || isWholeCSSFunction(trimmed, "calc")) return trimmed;
81
+ throw new Error(`Invalid --alpha() function: unsupported alpha value "${trimmed}"`);
82
+ }
83
+ function createStylesheetAlphaColorValue(value, alpha) {
84
+ return `color-mix(in oklab,${value} ${alpha},transparent)`;
85
+ }
86
+ function normalizeAlphaFunction(body) {
87
+ const separatorIndex = findTopLevelAlphaSeparator(body);
88
+ if (separatorIndex === void 0 || separatorIndex === -1) throw new Error("Invalid --alpha() function: expected \"<color> / <alpha>\"");
89
+ const color = body.slice(0, separatorIndex).trim();
90
+ const alpha = body.slice(separatorIndex + 1).trim();
91
+ if (!color) throw new Error("Invalid --alpha() function: color value cannot be empty");
92
+ return createStylesheetAlphaColorValue(color, normalizeStylesheetAlpha(alpha));
93
+ }
94
+ function normalizeStylesheetValue(value, options = {}) {
95
+ if (typeof value === "number") return {
96
+ value: String(value),
97
+ dependencies: /* @__PURE__ */ new Set()
98
+ };
99
+ const aliases = collectCSSVariableAliases(value);
100
+ if (aliases.length) {
101
+ const alias = aliases[0][1];
102
+ throw new Error(`Stylesheet values use native CSS variable references. Replace "$${alias}" with "var(--${alias})".`);
103
+ }
104
+ let result = "";
105
+ for (let index = 0; index < value.length;) {
106
+ const char = value[index];
107
+ if (char === "\"" || char === "'") {
108
+ const end = findCSSClosingQuote(value, index, char) + 1;
109
+ result += value.slice(index, end);
110
+ index = end;
111
+ continue;
112
+ }
113
+ if (char === "/" && value[index + 1] === "*") {
114
+ const end = findCSSCommentEnd(value, index);
115
+ result += value.slice(index, end);
116
+ index = end;
117
+ continue;
118
+ }
119
+ if (value.startsWith("--alpha(", index)) {
120
+ const alphaFunction = readCSSFunction(value, index, "--alpha");
121
+ if (alphaFunction) {
122
+ result += normalizeAlphaFunction(alphaFunction.body);
123
+ index = alphaFunction.end;
124
+ continue;
125
+ }
126
+ }
127
+ if (options.replacePipes && char === "|") {
128
+ result += " ";
129
+ index++;
130
+ continue;
131
+ }
132
+ result += char;
133
+ index++;
134
+ }
135
+ return {
136
+ value: result,
137
+ dependencies: collectCSSVariableReferences(result)
138
+ };
139
+ }
140
+ //#endregion
141
+ export { normalizeStylesheetValue };
@@ -39,9 +39,14 @@ function splitSelectorList(selectorText) {
39
39
  }
40
40
  function combineSelectorLists(parentSelectors, childSelectors) {
41
41
  const selectors = [];
42
- for (const child of childSelectors) for (const parent of parentSelectors) selectors.push(child.includes("&") ? child.replace(/&/g, parent) : `${parent} ${child}`);
42
+ for (const child of childSelectors) for (const parent of parentSelectors) selectors.push(combineSelector(parent, child));
43
43
  return selectors;
44
44
  }
45
+ function combineSelector(parent, child) {
46
+ const trimmedChild = child.trim();
47
+ if (trimmedChild.includes("&")) return trimmedChild.replace(/&/g, parent);
48
+ return `${parent} ${child}`;
49
+ }
45
50
  function combineStyleSelectors(parentSelector, childSelector) {
46
51
  return combineSelectorLists(splitSelectorList(parentSelector), splitSelectorList(childSelector)).join(",");
47
52
  }
@@ -0,0 +1,4 @@
1
+ //#region src/utils/wrap-conditions.d.ts
2
+ declare function wrapConditions(text: string, conditions?: string[]): string;
3
+ //#endregion
4
+ export { wrapConditions as default };
@@ -0,0 +1,11 @@
1
+ //#region src/utils/wrap-conditions.ts
2
+ function wrapConditions(text, conditions) {
3
+ if (!conditions?.length) return text;
4
+ for (let index = conditions.length - 1; index >= 0; index--) {
5
+ const condition = conditions[index]?.trim();
6
+ if (condition) text = `${condition}{${text}}`;
7
+ }
8
+ return text;
9
+ }
10
+ //#endregion
11
+ export { wrapConditions as default };
package/package.json CHANGED
@@ -50,15 +50,15 @@
50
50
  "csstype": "^3.2.3",
51
51
  "lightningcss": "^1.32.0",
52
52
  "lightningcss-wasm": "^1.32.0",
53
- "@master/css-engine": "^2.0.0-rc.84",
54
- "@master/css-lexer": "^2.0.0-rc.84",
55
- "@master/css-schema": "^2.0.0-rc.84"
53
+ "@master/css-lexer": "^2.0.0-rc.86",
54
+ "@master/css-engine": "^2.0.0-rc.86",
55
+ "@master/css-schema": "^2.0.0-rc.86"
56
56
  },
57
57
  "devDependencies": {
58
58
  "@types/css-tree": "^2.3.11",
59
- "@master/css-preset": "^2.0.0-rc.84"
59
+ "@master/css-preset": "^2.0.0-rc.86"
60
60
  },
61
- "version": "2.0.0-rc.84",
61
+ "version": "2.0.0-rc.86",
62
62
  "scripts": {
63
63
  "build": "tsdown --config ../../shared/tsdown-package.config.ts",
64
64
  "dev": "tsdown --config ../../shared/tsdown-package.config.ts --watch",
@@ -1,4 +0,0 @@
1
- //#region src/utils/wrap-at-rules.d.ts
2
- declare function wrapAtRules(text: string, atRules?: string[]): string;
3
- //#endregion
4
- export { wrapAtRules as default };
@@ -1,11 +0,0 @@
1
- //#region src/utils/wrap-at-rules.ts
2
- function wrapAtRules(text, atRules) {
3
- if (!atRules?.length) return text;
4
- for (let index = atRules.length - 1; index >= 0; index--) {
5
- const atRule = atRules[index]?.trim();
6
- if (atRule) text = `${atRule}{${text}}`;
7
- }
8
- return text;
9
- }
10
- //#endregion
11
- export { wrapAtRules as default };