@csszyx/compiler 0.10.8 → 0.10.10

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.
package/dist/index.mjs CHANGED
@@ -62,6 +62,7 @@ function transformSourceCode(source, filename, options) {
62
62
  let usesColorVar = false;
63
63
  let transformed = false;
64
64
  const collectedClasses = /* @__PURE__ */ new Set();
65
+ const szsPendingClasses = [];
65
66
  const rawClassNames = /* @__PURE__ */ new Set();
66
67
  const diagnostics = [];
67
68
  const recoveryTokens = /* @__PURE__ */ new Map();
@@ -181,6 +182,70 @@ function transformSourceCode(source, filename, options) {
181
182
  transformed = true;
182
183
  return;
183
184
  }
185
+ if (attrName === "szs") {
186
+ const openingEl = path.parentPath?.isJSXOpeningElement() ? path.parentPath.node : null;
187
+ if (openingEl && isHostElementName(openingEl.name)) {
188
+ diagnostics.push(
189
+ `[csszyx] szs at ${filename ?? "<anonymous>"}: szs has no effect on a host element \u2014 it maps slot names of a custom component. Attribute left unchanged.`
190
+ );
191
+ return;
192
+ }
193
+ const container = path.node.value;
194
+ if (!t.isJSXExpressionContainer(container) || !t.isObjectExpression(container.expression)) {
195
+ diagnostics.push(szsUnsupportedMessage$1(filename));
196
+ return;
197
+ }
198
+ const slotMap = container.expression;
199
+ if (!isValidSzsSlotMap$1(slotMap)) {
200
+ diagnostics.push(szsUnsupportedMessage$1(filename));
201
+ return;
202
+ }
203
+ setSzWarnLocation(
204
+ formatSzWarnLocation(
205
+ filename ?? "file.tsx",
206
+ path.node.loc?.start.line,
207
+ options?.rootDir
208
+ )
209
+ );
210
+ const compiledSlots = [];
211
+ for (const prop of slotMap.properties) {
212
+ const slot = prop;
213
+ if (t.isStringLiteral(slot.value)) {
214
+ compiledSlots.push({
215
+ slot,
216
+ classes: slot.value.value,
217
+ rewrite: false
218
+ });
219
+ continue;
220
+ }
221
+ const compiled = tryStaticTransformNode(slot.value);
222
+ if (!compiled || !t.isStringLiteral(compiled)) {
223
+ diagnostics.push(szsUnsupportedMessage$1(filename));
224
+ return;
225
+ }
226
+ compiledSlots.push({
227
+ slot,
228
+ classes: compiled.value,
229
+ rewrite: true
230
+ });
231
+ }
232
+ for (const {
233
+ slot,
234
+ classes: slotClasses,
235
+ rewrite
236
+ } of compiledSlots) {
237
+ if (rewrite) {
238
+ slot.value = t.stringLiteral(slotClasses);
239
+ transformed = true;
240
+ }
241
+ for (const c of slotClasses.split(/\s+/)) {
242
+ if (c) {
243
+ szsPendingClasses.push(c);
244
+ }
245
+ }
246
+ }
247
+ return;
248
+ }
184
249
  if (attrName !== "sz") {
185
250
  return;
186
251
  }
@@ -371,6 +436,17 @@ function transformSourceCode(source, filename, options) {
371
436
  transformed = true;
372
437
  return;
373
438
  }
439
+ const hoistedNested = tryHoistNestedConditional(
440
+ flatExpression,
441
+ getBinding
442
+ );
443
+ if (hoistedNested !== null) {
444
+ path.node.name.name = "className";
445
+ path.node.value = createMergedClassNameValue(hoistedNested);
446
+ collectFromExpr(hoistedNested, collectedClasses);
447
+ transformed = true;
448
+ return;
449
+ }
374
450
  const partial = evaluatePartialObject$1(flatExpression);
375
451
  if (partial !== null && !partial.hasSpread && (partial.dynamicProps.size > 0 || partial.conditionalClasses.length > 0)) {
376
452
  const staticClasses = [];
@@ -759,6 +835,9 @@ function transformSourceCode(source, filename, options) {
759
835
  })
760
836
  ]
761
837
  });
838
+ for (const c of szsPendingClasses) {
839
+ collectedClasses.add(c);
840
+ }
762
841
  return {
763
842
  code: result?.code || source,
764
843
  transformed,
@@ -810,6 +889,31 @@ function parseStyleStringToObjectExpr(styleStr) {
810
889
  }
811
890
  return t.objectExpression(objProps);
812
891
  }
892
+ function isHostElementName(name) {
893
+ return t.isJSXIdentifier(name) && /^[a-z]/.test(name.name);
894
+ }
895
+ function szsUnsupportedMessage$1(filename) {
896
+ return `[csszyx] szs at ${filename ?? "<anonymous>"}: every slot must be an identifier key with a static object literal (or class string) value. Attribute left unchanged.`;
897
+ }
898
+ function isPureLiteralSzValue$1(node) {
899
+ if (t.isStringLiteral(node) || t.isNumericLiteral(node) || t.isBooleanLiteral(node)) {
900
+ return true;
901
+ }
902
+ if (t.isUnaryExpression(node) && node.operator === "-" && t.isNumericLiteral(node.argument)) {
903
+ return true;
904
+ }
905
+ if (t.isObjectExpression(node)) {
906
+ return node.properties.every(
907
+ (prop) => t.isObjectProperty(prop) && !prop.computed && t.isIdentifier(prop.key) && isPureLiteralSzValue$1(prop.value)
908
+ );
909
+ }
910
+ return false;
911
+ }
912
+ function isValidSzsSlotMap$1(slotMap) {
913
+ return slotMap.properties.every(
914
+ (prop) => t.isObjectProperty(prop) && !prop.computed && t.isIdentifier(prop.key) && (t.isStringLiteral(prop.value) || t.isObjectExpression(prop.value) && isPureLiteralSzValue$1(prop.value))
915
+ );
916
+ }
813
917
  function emptyClassToUndefined(node) {
814
918
  return t.isStringLiteral(node) && node.value === "" ? t.identifier("undefined") : node;
815
919
  }
@@ -859,6 +963,123 @@ function tryStaticTransformNode(node, getBinding) {
859
963
  }
860
964
  return null;
861
965
  }
966
+ function scanNestedConditionals(node) {
967
+ let topLevel = 0;
968
+ let nested = 0;
969
+ let test = null;
970
+ for (const prop of node.properties) {
971
+ if (!t.isObjectProperty(prop)) {
972
+ continue;
973
+ }
974
+ const value = prop.value;
975
+ if (t.isConditionalExpression(value)) {
976
+ topLevel++;
977
+ } else if (t.isObjectExpression(value)) {
978
+ nested += countAllConditionals(value);
979
+ test ??= firstConditionalTest(value);
980
+ }
981
+ }
982
+ return { topLevel, nested, test };
983
+ }
984
+ function countAllConditionals(node) {
985
+ let count = 0;
986
+ for (const prop of node.properties) {
987
+ if (!t.isObjectProperty(prop)) {
988
+ continue;
989
+ }
990
+ const value = prop.value;
991
+ if (t.isConditionalExpression(value)) {
992
+ count++;
993
+ } else if (t.isObjectExpression(value)) {
994
+ count += countAllConditionals(value);
995
+ }
996
+ }
997
+ return count;
998
+ }
999
+ function firstConditionalTest(node) {
1000
+ for (const prop of node.properties) {
1001
+ if (!t.isObjectProperty(prop)) {
1002
+ continue;
1003
+ }
1004
+ const value = prop.value;
1005
+ if (t.isConditionalExpression(value)) {
1006
+ return value.test;
1007
+ }
1008
+ if (t.isObjectExpression(value)) {
1009
+ const inner = firstConditionalTest(value);
1010
+ if (inner) {
1011
+ return inner;
1012
+ }
1013
+ }
1014
+ }
1015
+ return null;
1016
+ }
1017
+ function cloneObjectPickingBranch(node, pick) {
1018
+ return t.objectExpression(
1019
+ node.properties.map((prop) => {
1020
+ if (!t.isObjectProperty(prop)) {
1021
+ return t.cloneNode(prop);
1022
+ }
1023
+ const value = prop.value;
1024
+ let nextValue = t.cloneNode(value);
1025
+ if (t.isConditionalExpression(value)) {
1026
+ nextValue = t.cloneNode(value[pick]);
1027
+ } else if (t.isObjectExpression(value)) {
1028
+ nextValue = cloneObjectPickingBranch(value, pick);
1029
+ }
1030
+ return t.objectProperty(
1031
+ t.cloneNode(prop.key),
1032
+ nextValue,
1033
+ prop.computed,
1034
+ prop.shorthand
1035
+ );
1036
+ })
1037
+ );
1038
+ }
1039
+ function tryHoistNestedConditional(node, getBinding) {
1040
+ const { topLevel, nested, test } = scanNestedConditionals(node);
1041
+ if (topLevel !== 0 || nested !== 1 || test === null) {
1042
+ return null;
1043
+ }
1044
+ const condPropIndex = node.properties.findIndex(
1045
+ (prop) => t.isObjectProperty(prop) && t.isObjectExpression(prop.value) && countAllConditionals(prop.value) === 1
1046
+ );
1047
+ if (condPropIndex === -1) {
1048
+ return null;
1049
+ }
1050
+ const staticNode = t.objectExpression(node.properties.filter((_, i) => i !== condPropIndex));
1051
+ const condNode = t.objectExpression([node.properties[condPropIndex]]);
1052
+ const staticClasses = staticNode.properties.length > 0 ? tryStaticTransformNode(staticNode, getBinding) : null;
1053
+ const consequent = tryStaticTransformNode(
1054
+ cloneObjectPickingBranch(condNode, "consequent"),
1055
+ getBinding
1056
+ );
1057
+ const alternate = tryStaticTransformNode(
1058
+ cloneObjectPickingBranch(condNode, "alternate"),
1059
+ getBinding
1060
+ );
1061
+ if (!consequent || !alternate || !t.isStringLiteral(consequent) || !t.isStringLiteral(alternate) || staticNode.properties.length > 0 && (!staticClasses || !t.isStringLiteral(staticClasses))) {
1062
+ return null;
1063
+ }
1064
+ const ternary = t.conditionalExpression(
1065
+ test,
1066
+ emptyClassToUndefined(consequent),
1067
+ emptyClassToUndefined(alternate)
1068
+ );
1069
+ if (!staticClasses || !t.isStringLiteral(staticClasses) || staticClasses.value === "") {
1070
+ return ternary;
1071
+ }
1072
+ return t.templateLiteral(
1073
+ [
1074
+ t.templateElement(
1075
+ { raw: `${staticClasses.value} `, cooked: `${staticClasses.value} ` },
1076
+ false
1077
+ ),
1078
+ t.templateElement({ raw: "", cooked: "" }, true)
1079
+ ],
1080
+ [ternary]
1081
+ );
1082
+ }
862
1083
  function tryHoistConditionalSpread(node, getBinding) {
863
1084
  let conditionalSpreadIdx = -1;
864
1085
  let conditionalExpr = null;
@@ -1267,6 +1488,18 @@ function collectFromExpr(node, classes) {
1267
1488
  } else if (t.isConditionalExpression(node)) {
1268
1489
  collectFromExpr(node.consequent, classes);
1269
1490
  collectFromExpr(node.alternate, classes);
1491
+ } else if (t.isTemplateLiteral(node)) {
1492
+ for (let i = 0; i < node.quasis.length; i++) {
1493
+ for (const c of (node.quasis[i].value.cooked ?? "").split(/\s+/)) {
1494
+ if (c) {
1495
+ classes.add(c);
1496
+ }
1497
+ }
1498
+ const expr = node.expressions[i];
1499
+ if (expr && t.isExpression(expr)) {
1500
+ collectFromExpr(expr, classes);
1501
+ }
1502
+ }
1270
1503
  }
1271
1504
  }
1272
1505
  function collectCandidatesFromBabelExpr(node, path, classes) {
@@ -1517,6 +1750,10 @@ class CsszyxCompiler {
1517
1750
  }
1518
1751
  }
1519
1752
 
1753
+ function sortStrings(values) {
1754
+ return [...values].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
1755
+ }
1756
+
1520
1757
  const CSS_VAR_REFERENCE_RE = /var\(\s*(--[\w-]+)/g;
1521
1758
  function scanGlobalVarUsages(source, filename = "file.tsx", options = {}) {
1522
1759
  if (!source.includes("--") && !source.includes("var(")) {
@@ -1726,7 +1963,7 @@ function extractVarReferences(value) {
1726
1963
  for (const match of value.matchAll(CSS_VAR_REFERENCE_RE)) {
1727
1964
  refs.add(match[1]);
1728
1965
  }
1729
- return [...refs].sort();
1966
+ return sortStrings(refs);
1730
1967
  }
1731
1968
  function shouldReportToken(name, tokenFilter) {
1732
1969
  return tokenFilter === null || tokenFilter.has(name);
@@ -2000,7 +2237,7 @@ class ManifestBuilder {
2000
2237
  * @returns {string} SHA-256 checksum
2001
2238
  */
2002
2239
  computeChecksum(tokens) {
2003
- const sortedKeys = Object.keys(tokens).sort();
2240
+ const sortedKeys = sortStrings(Object.keys(tokens));
2004
2241
  const sortedTokens = {};
2005
2242
  for (const key of sortedKeys) {
2006
2243
  sortedTokens[key] = tokens[key];
@@ -2276,6 +2513,7 @@ class OxcNotImplementedError extends Error {
2276
2513
  }
2277
2514
  function transformOxc(source, filename, options) {
2278
2515
  const classes = /* @__PURE__ */ new Set();
2516
+ const szsPendingClasses = [];
2279
2517
  const rawClassNames = /* @__PURE__ */ new Set();
2280
2518
  const diagnostics = [];
2281
2519
  const recoveryTokens = /* @__PURE__ */ new Map();
@@ -2347,6 +2585,7 @@ function transformOxc(source, filename, options) {
2347
2585
  const openingNode = node;
2348
2586
  const attrs = openingNode.attributes ?? [];
2349
2587
  const szAttrs = [];
2588
+ const szsAttrs = [];
2350
2589
  let classNameAttr = null;
2351
2590
  let styleAttr = null;
2352
2591
  let szRecoverAttr = null;
@@ -2379,6 +2618,8 @@ function transformOxc(source, filename, options) {
2379
2618
  const name = attr.name?.name;
2380
2619
  if (name === "sz") {
2381
2620
  szAttrs.push(attr);
2621
+ } else if (name === "szs") {
2622
+ szsAttrs.push(attr);
2382
2623
  } else if (name === "className" || name === "class") {
2383
2624
  classNameAttr = attr;
2384
2625
  } else if (name === "style") {
@@ -2429,6 +2670,89 @@ function transformOxc(source, filename, options) {
2429
2670
  }
2430
2671
  }
2431
2672
  }
2673
+ for (const szsAttr of szsAttrs) {
2674
+ if (isHostOpeningElementName(openingNode.name)) {
2675
+ diagnostics.push(
2676
+ `[csszyx] szs at ${effectiveFilename}: szs has no effect on a host element \u2014 it maps slot names of a custom component. Attribute left unchanged.`
2677
+ );
2678
+ continue;
2679
+ }
2680
+ const szsValue = szsAttr.value;
2681
+ const szsExpression = szsValue && szsValue.type === "JSXExpressionContainer" ? szsValue.expression : null;
2682
+ if (!szsExpression || szsExpression.type !== "ObjectExpression") {
2683
+ diagnostics.push(szsUnsupportedMessage(effectiveFilename));
2684
+ continue;
2685
+ }
2686
+ const slotMap = szsExpression;
2687
+ if (!isValidSzsSlotMap(slotMap)) {
2688
+ diagnostics.push(szsUnsupportedMessage(effectiveFilename));
2689
+ continue;
2690
+ }
2691
+ const { line: szsWarnLine } = offsetToLineColumn(source, szsAttr.start);
2692
+ setSzWarnLocation(
2693
+ formatSzWarnLocation(effectiveFilename, szsWarnLine, options?.rootDir)
2694
+ );
2695
+ const slotEntries = [];
2696
+ let anyCompiled = false;
2697
+ let slotFailed = false;
2698
+ for (const propRaw of slotMap.properties) {
2699
+ const prop = propRaw;
2700
+ const keyText = source.slice(prop.key.start, prop.key.end);
2701
+ const propValue = prop.value;
2702
+ const literal = propValue.type === "Literal" ? propValue.value : null;
2703
+ if (typeof literal === "string") {
2704
+ slotEntries.push({
2705
+ keyText,
2706
+ classNames: literal,
2707
+ text: source.slice(propValue.start, propValue.end)
2708
+ });
2709
+ continue;
2710
+ }
2711
+ try {
2712
+ const slotObject = astObjectToSzObject(
2713
+ propValue,
2714
+ effectiveFilename,
2715
+ objectBindings
2716
+ );
2717
+ const compiled = transform(
2718
+ applyGlobalVarAliasesToSzObject(
2719
+ slotObject,
2720
+ globalVarAliases,
2721
+ cssVariableMap
2722
+ )
2723
+ ).className;
2724
+ slotEntries.push({
2725
+ keyText,
2726
+ classNames: compiled,
2727
+ text: JSON.stringify(compiled)
2728
+ });
2729
+ anyCompiled = true;
2730
+ } catch (err) {
2731
+ if (err instanceof OxcNotImplementedError) {
2732
+ slotFailed = true;
2733
+ break;
2734
+ }
2735
+ throw err;
2736
+ }
2737
+ }
2738
+ setSzWarnLocation(void 0);
2739
+ if (slotFailed) {
2740
+ diagnostics.push(szsUnsupportedMessage(effectiveFilename));
2741
+ continue;
2742
+ }
2743
+ if (anyCompiled) {
2744
+ const body = slotEntries.map((entry) => `${entry.keyText}: ${entry.text}`).join(", ");
2745
+ edits.overwrite(szsAttr.start, szsAttr.end, `szs={{ ${body} }}`);
2746
+ transformed = true;
2747
+ }
2748
+ for (const entry of slotEntries) {
2749
+ for (const c of entry.classNames.split(/\s+/)) {
2750
+ if (c) {
2751
+ szsPendingClasses.push(c);
2752
+ }
2753
+ }
2754
+ }
2755
+ }
2432
2756
  if (szAttrs.length === 0) {
2433
2757
  applyHoistedStyleProps();
2434
2758
  return;
@@ -2626,6 +2950,29 @@ function transformOxc(source, filename, options) {
2626
2950
  transformed = true;
2627
2951
  return;
2628
2952
  }
2953
+ const nestedConditionalClassExpr = buildNestedConditionalClassExpression(
2954
+ expression,
2955
+ effectiveFilename,
2956
+ objectBindings,
2957
+ source,
2958
+ classes,
2959
+ globalVarAliases,
2960
+ cssVariableMap
2961
+ );
2962
+ if (nestedConditionalClassExpr) {
2963
+ if (classNameAttr || szAttrs.length > 1) {
2964
+ runtimeFallbackExpr = expression;
2965
+ runtimeFallbackAttr = szAttr;
2966
+ break;
2967
+ }
2968
+ edits.overwrite(
2969
+ szAttr.start,
2970
+ szAttr.end,
2971
+ `className={${nestedConditionalClassExpr}}`
2972
+ );
2973
+ transformed = true;
2974
+ return;
2975
+ }
2629
2976
  const partial = buildPartialObjectTransform(
2630
2977
  expression,
2631
2978
  effectiveFilename,
@@ -2784,6 +3131,9 @@ function transformOxc(source, filename, options) {
2784
3131
  }
2785
3132
  transformed = true;
2786
3133
  });
3134
+ for (const c of szsPendingClasses) {
3135
+ classes.add(c);
3136
+ }
2787
3137
  return {
2788
3138
  code: transformed ? edits.toString() : source,
2789
3139
  transformed,
@@ -2853,6 +3203,49 @@ function buildRuntimeFallbackDiagnostic(expression, source) {
2853
3203
  return `sz fallback at ${lineCol}: ${reason}.
2854
3204
  Suggestion: ${suggestion}`;
2855
3205
  }
3206
+ function isHostOpeningElementName(nameNode) {
3207
+ return nameNode.type === "JSXIdentifier" && /^[a-z]/.test(String(nameNode.name));
3208
+ }
3209
+ function szsUnsupportedMessage(filename) {
3210
+ return `[csszyx] szs at ${filename}: every slot must be an identifier key with a static object literal (or class string) value. Attribute left unchanged.`;
3211
+ }
3212
+ function isPureLiteralSzValue(node) {
3213
+ if (node.type === "Literal") {
3214
+ const value = node.value;
3215
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
3216
+ }
3217
+ if (node.type === "UnaryExpression") {
3218
+ const unary = node;
3219
+ return unary.operator === "-" && unary.argument.type === "Literal" && typeof unary.argument.value === "number";
3220
+ }
3221
+ if (node.type === "ObjectExpression") {
3222
+ const properties = node.properties;
3223
+ return properties.every((propRaw) => {
3224
+ if (propRaw.type !== "Property") {
3225
+ return false;
3226
+ }
3227
+ const prop = propRaw;
3228
+ return !prop.computed && prop.key.type === "Identifier" && isPureLiteralSzValue(prop.value);
3229
+ });
3230
+ }
3231
+ return false;
3232
+ }
3233
+ function isValidSzsSlotMap(slotMap) {
3234
+ return slotMap.properties.every((propRaw) => {
3235
+ if (propRaw.type !== "Property") {
3236
+ return false;
3237
+ }
3238
+ const prop = propRaw;
3239
+ if (prop.computed || prop.key.type !== "Identifier") {
3240
+ return false;
3241
+ }
3242
+ const value = prop.value;
3243
+ if (value.type === "Literal" && typeof value.value === "string") {
3244
+ return true;
3245
+ }
3246
+ return value.type === "ObjectExpression" && isPureLiteralSzValue(value);
3247
+ });
3248
+ }
2856
3249
  function extractElementName(nameNode) {
2857
3250
  if (nameNode.type === "JSXIdentifier") {
2858
3251
  return String(nameNode.name);
@@ -2862,7 +3255,7 @@ function extractElementName(nameNode) {
2862
3255
  }
2863
3256
  return "<unknown>";
2864
3257
  }
2865
- function astObjectToSzObject(node, filename, bindings) {
3258
+ function astObjectToSzObject(node, filename, bindings, branchPick) {
2866
3259
  const result = {};
2867
3260
  for (const propRaw of node.properties) {
2868
3261
  if (propRaw.type === "SpreadElement") {
@@ -2899,7 +3292,7 @@ function astObjectToSzObject(node, filename, bindings) {
2899
3292
  `unsupported key shape ${prop.key.type} at ${filename}:${prop.key.start}`
2900
3293
  );
2901
3294
  }
2902
- result[key] = astValueToSzValue(prop.value, filename, bindings);
3295
+ result[key] = astValueToSzValue(prop.value, filename, bindings, branchPick);
2903
3296
  }
2904
3297
  return result;
2905
3298
  }
@@ -3331,6 +3724,99 @@ function resolveObjectExpression(node, bindings) {
3331
3724
  }
3332
3725
  return null;
3333
3726
  }
3727
+ function countOxcConditionals(node) {
3728
+ let count = 0;
3729
+ for (const propRaw of node.properties) {
3730
+ if (propRaw.type !== "Property") {
3731
+ continue;
3732
+ }
3733
+ const value = propRaw.value;
3734
+ if (value.type === "ConditionalExpression") {
3735
+ count++;
3736
+ } else if (value.type === "ObjectExpression") {
3737
+ count += countOxcConditionals(value);
3738
+ }
3739
+ }
3740
+ return count;
3741
+ }
3742
+ function firstOxcConditional(node) {
3743
+ for (const propRaw of node.properties) {
3744
+ if (propRaw.type !== "Property") {
3745
+ continue;
3746
+ }
3747
+ const value = propRaw.value;
3748
+ if (value.type === "ConditionalExpression") {
3749
+ return value;
3750
+ }
3751
+ if (value.type === "ObjectExpression") {
3752
+ const found = firstOxcConditional(value);
3753
+ if (found) {
3754
+ return found;
3755
+ }
3756
+ }
3757
+ }
3758
+ return null;
3759
+ }
3760
+ function buildNestedConditionalClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
3761
+ let topLevel = 0;
3762
+ for (const propRaw of node.properties) {
3763
+ if (propRaw.type === "Property" && propRaw.value.type === "ConditionalExpression") {
3764
+ topLevel++;
3765
+ }
3766
+ }
3767
+ const first = firstOxcConditional(node);
3768
+ if (topLevel !== 0 || countOxcConditionals(node) !== 1 || !first) {
3769
+ return null;
3770
+ }
3771
+ const condPropIndex = node.properties.findIndex(
3772
+ (prop) => prop.type === "Property" && prop.value.type === "ObjectExpression" && countOxcConditionals(prop.value) === 1
3773
+ );
3774
+ if (condPropIndex === -1) {
3775
+ return null;
3776
+ }
3777
+ const staticNode = {
3778
+ ...node,
3779
+ properties: node.properties.filter((_, i) => i !== condPropIndex)
3780
+ };
3781
+ const condNode = {
3782
+ ...node,
3783
+ properties: [node.properties[condPropIndex]]
3784
+ };
3785
+ const compile = (target, pick) => {
3786
+ try {
3787
+ return transform(
3788
+ applyGlobalVarAliasesToSzObject(
3789
+ astObjectToSzObject(target, filename, bindings, pick),
3790
+ globalVarAliases,
3791
+ cssVariableMap
3792
+ )
3793
+ ).className;
3794
+ } catch (err) {
3795
+ if (err instanceof OxcNotImplementedError) {
3796
+ return null;
3797
+ }
3798
+ throw err;
3799
+ }
3800
+ };
3801
+ const staticClasses = staticNode.properties.length > 0 ? compile(staticNode) : "";
3802
+ const consequent = compile(condNode, "consequent");
3803
+ const alternate = compile(condNode, "alternate");
3804
+ if (staticClasses === null || consequent === null || alternate === null) {
3805
+ return null;
3806
+ }
3807
+ for (const cls of `${staticClasses} ${consequent} ${alternate}`.split(/\s+/)) {
3808
+ if (cls) {
3809
+ classes.add(cls);
3810
+ }
3811
+ }
3812
+ const testSource = source.slice(first.test.start, first.test.end);
3813
+ const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
3814
+ const ternary = `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
3815
+ if (staticClasses === "") {
3816
+ return ternary;
3817
+ }
3818
+ return `\`${staticClasses} \${${ternary}}\``;
3819
+ }
3334
3820
  function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
3335
3821
  let conditionalSpread = null;
3336
3822
  const otherProps = [];
@@ -4115,7 +4601,15 @@ function extractKeyName(key) {
4115
4601
  }
4116
4602
  return null;
4117
4603
  }
4118
- function astValueToSzValue(node, filename, bindings) {
4604
+ function astValueToSzValue(node, filename, bindings, branchPick) {
4605
+ if (branchPick && node.type === "ConditionalExpression") {
4606
+ return astValueToSzValue(
4607
+ node[branchPick],
4608
+ filename,
4609
+ bindings,
4610
+ branchPick
4611
+ );
4612
+ }
4119
4613
  if (node.type === "Literal") {
4120
4614
  const value = node.value;
4121
4615
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
@@ -4141,7 +4635,7 @@ function astValueToSzValue(node, filename, bindings) {
4141
4635
  );
4142
4636
  }
4143
4637
  if (node.type === "ObjectExpression") {
4144
- return astObjectToSzObject(node, filename, bindings);
4638
+ return astObjectToSzObject(node, filename, bindings, branchPick);
4145
4639
  }
4146
4640
  if (node.type === "Identifier" || node.type === "MemberExpression") {
4147
4641
  throw new OxcNotImplementedError(
@@ -4380,4 +4874,4 @@ function mergeOptions(options = {}) {
4380
4874
  };
4381
4875
  }
4382
4876
 
4383
- export { COLOR_PROPERTIES, CsszyxCompiler, DEFAULT_COMPILER_OPTIONS, KNOWN_VARIANTS, ManifestBuilder, OxcNotImplementedError, OxcRustNotImplementedError, PROPERTY_MAP, PropertyCategory, VERSION, buildParentMap, createRecoveryToken, ensureRustTransformAvailable, generateRecoveryToken, getCSSVariableName, getPropertyCategory, hoistCSSVariables, injectRecoveryToken, isRustTransformAvailable, isValidRecoveryMode, mergeOptions, parseManifest, scanGlobalVarUsages, serializeManifest, transform, transformOxc, transformRust, transformRustBatch, transformSourceCode, validateManifest, validateSzRecover };
4877
+ export { COLOR_PROPERTIES, CsszyxCompiler, DEFAULT_COMPILER_OPTIONS, KNOWN_VARIANTS, ManifestBuilder, OxcNotImplementedError, OxcRustNotImplementedError, PROPERTY_MAP, PropertyCategory, VERSION, buildParentMap, createRecoveryToken, ensureRustTransformAvailable, generateRecoveryToken, getCSSVariableName, getPropertyCategory, hoistCSSVariables, injectRecoveryToken, isRustTransformAvailable, isValidRecoveryMode, mergeOptions, parseManifest, scanGlobalVarUsages, serializeManifest, sortStrings, transform, transformOxc, transformRust, transformRustBatch, transformSourceCode, validateManifest, validateSzRecover };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@csszyx/compiler",
3
- "version": "0.10.8",
3
+ "version": "0.10.10",
4
4
  "description": "Core compiler and transformation logic for csszyx",
5
5
  "keywords": [
6
6
  "csszyx",
@@ -65,7 +65,7 @@
65
65
  "@babel/types": "^7.23.6",
66
66
  "magic-string": "0.30.21",
67
67
  "oxc-parser": "0.131.0",
68
- "@csszyx/core": "0.10.8"
68
+ "@csszyx/core": "0.10.10"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@types/babel__core": "^7.20.5",
@@ -74,7 +74,7 @@
74
74
  "csstype": "^3.0.0",
75
75
  "typescript": "^6.0.3",
76
76
  "unbuild": "^3.6.1",
77
- "vitest": "^4.1.6"
77
+ "vitest": "^4.1.9"
78
78
  },
79
79
  "sideEffects": false,
80
80
  "engines": {