@csszyx/compiler 0.10.7 → 0.10.9
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.cjs +258 -20
- package/dist/index.d.cts +23 -1
- package/dist/index.d.mts +23 -1
- package/dist/index.mjs +259 -22
- package/dist/shared/{compiler.DINxoUCF.mjs → compiler.CghwJ6p5.mjs} +11 -0
- package/dist/shared/{compiler.DIYC1vdY.cjs → compiler.mibv6qPF.cjs} +11 -0
- package/dist/transform-core.cjs +1 -1
- package/dist/transform-core.mjs +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const core = require('@csszyx/core');
|
|
4
|
-
const transformCore = require('./shared/compiler.
|
|
4
|
+
const transformCore = require('./shared/compiler.mibv6qPF.cjs');
|
|
5
5
|
const oxcParser = require('oxc-parser');
|
|
6
6
|
const t = require('@babel/types');
|
|
7
7
|
const node_crypto = require('node:crypto');
|
|
@@ -245,6 +245,9 @@ function transformSourceCode(source, filename, options) {
|
|
|
245
245
|
}
|
|
246
246
|
const createMergedClassNameValue = (szExpr) => {
|
|
247
247
|
if (!existingClassExpr) {
|
|
248
|
+
if (t__namespace.isStringLiteral(szExpr) && szExpr.value === "") {
|
|
249
|
+
return t__namespace.jsxExpressionContainer(t__namespace.identifier("undefined"));
|
|
250
|
+
}
|
|
248
251
|
return t__namespace.isStringLiteral(szExpr) ? szExpr : t__namespace.jsxExpressionContainer(szExpr);
|
|
249
252
|
}
|
|
250
253
|
if (existingClassNameNode && path.parentPath?.isJSXOpeningElement()) {
|
|
@@ -387,6 +390,17 @@ function transformSourceCode(source, filename, options) {
|
|
|
387
390
|
transformed = true;
|
|
388
391
|
return;
|
|
389
392
|
}
|
|
393
|
+
const hoistedNested = tryHoistNestedConditional(
|
|
394
|
+
flatExpression,
|
|
395
|
+
getBinding
|
|
396
|
+
);
|
|
397
|
+
if (hoistedNested !== null) {
|
|
398
|
+
path.node.name.name = "className";
|
|
399
|
+
path.node.value = createMergedClassNameValue(hoistedNested);
|
|
400
|
+
collectFromExpr(hoistedNested, collectedClasses);
|
|
401
|
+
transformed = true;
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
390
404
|
const partial = evaluatePartialObject$1(flatExpression);
|
|
391
405
|
if (partial !== null && !partial.hasSpread && (partial.dynamicProps.size > 0 || partial.conditionalClasses.length > 0)) {
|
|
392
406
|
const staticClasses = [];
|
|
@@ -826,6 +840,9 @@ function parseStyleStringToObjectExpr(styleStr) {
|
|
|
826
840
|
}
|
|
827
841
|
return t__namespace.objectExpression(objProps);
|
|
828
842
|
}
|
|
843
|
+
function emptyClassToUndefined(node) {
|
|
844
|
+
return t__namespace.isStringLiteral(node) && node.value === "" ? t__namespace.identifier("undefined") : node;
|
|
845
|
+
}
|
|
829
846
|
function tryStaticTransformNode(node, getBinding) {
|
|
830
847
|
if (t__namespace.isTSAsExpression(node) || t__namespace.isTSSatisfiesExpression(node)) {
|
|
831
848
|
return tryStaticTransformNode(node.expression, getBinding);
|
|
@@ -862,12 +879,111 @@ function tryStaticTransformNode(node, getBinding) {
|
|
|
862
879
|
const consequent = tryStaticTransformNode(node.consequent, getBinding);
|
|
863
880
|
const alternate = tryStaticTransformNode(node.alternate, getBinding);
|
|
864
881
|
if (consequent !== null && alternate !== null) {
|
|
865
|
-
return t__namespace.conditionalExpression(
|
|
882
|
+
return t__namespace.conditionalExpression(
|
|
883
|
+
node.test,
|
|
884
|
+
emptyClassToUndefined(consequent),
|
|
885
|
+
emptyClassToUndefined(alternate)
|
|
886
|
+
);
|
|
866
887
|
}
|
|
867
888
|
return null;
|
|
868
889
|
}
|
|
869
890
|
return null;
|
|
870
891
|
}
|
|
892
|
+
function scanNestedConditionals(node) {
|
|
893
|
+
let topLevel = 0;
|
|
894
|
+
let nested = 0;
|
|
895
|
+
let test = null;
|
|
896
|
+
for (const prop of node.properties) {
|
|
897
|
+
if (!t__namespace.isObjectProperty(prop)) {
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
const value = prop.value;
|
|
901
|
+
if (t__namespace.isConditionalExpression(value)) {
|
|
902
|
+
topLevel++;
|
|
903
|
+
} else if (t__namespace.isObjectExpression(value)) {
|
|
904
|
+
nested += countAllConditionals(value);
|
|
905
|
+
test ??= firstConditionalTest(value);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return { topLevel, nested, test };
|
|
909
|
+
}
|
|
910
|
+
function countAllConditionals(node) {
|
|
911
|
+
let count = 0;
|
|
912
|
+
for (const prop of node.properties) {
|
|
913
|
+
if (!t__namespace.isObjectProperty(prop)) {
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
const value = prop.value;
|
|
917
|
+
if (t__namespace.isConditionalExpression(value)) {
|
|
918
|
+
count++;
|
|
919
|
+
} else if (t__namespace.isObjectExpression(value)) {
|
|
920
|
+
count += countAllConditionals(value);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return count;
|
|
924
|
+
}
|
|
925
|
+
function firstConditionalTest(node) {
|
|
926
|
+
for (const prop of node.properties) {
|
|
927
|
+
if (!t__namespace.isObjectProperty(prop)) {
|
|
928
|
+
continue;
|
|
929
|
+
}
|
|
930
|
+
const value = prop.value;
|
|
931
|
+
if (t__namespace.isConditionalExpression(value)) {
|
|
932
|
+
return value.test;
|
|
933
|
+
}
|
|
934
|
+
if (t__namespace.isObjectExpression(value)) {
|
|
935
|
+
const inner = firstConditionalTest(value);
|
|
936
|
+
if (inner) {
|
|
937
|
+
return inner;
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return null;
|
|
942
|
+
}
|
|
943
|
+
function cloneObjectPickingBranch(node, pick) {
|
|
944
|
+
return t__namespace.objectExpression(
|
|
945
|
+
node.properties.map((prop) => {
|
|
946
|
+
if (!t__namespace.isObjectProperty(prop)) {
|
|
947
|
+
return t__namespace.cloneNode(prop);
|
|
948
|
+
}
|
|
949
|
+
const value = prop.value;
|
|
950
|
+
let nextValue = t__namespace.cloneNode(value);
|
|
951
|
+
if (t__namespace.isConditionalExpression(value)) {
|
|
952
|
+
nextValue = t__namespace.cloneNode(value[pick]);
|
|
953
|
+
} else if (t__namespace.isObjectExpression(value)) {
|
|
954
|
+
nextValue = cloneObjectPickingBranch(value, pick);
|
|
955
|
+
}
|
|
956
|
+
return t__namespace.objectProperty(
|
|
957
|
+
t__namespace.cloneNode(prop.key),
|
|
958
|
+
nextValue,
|
|
959
|
+
prop.computed,
|
|
960
|
+
prop.shorthand
|
|
961
|
+
);
|
|
962
|
+
})
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
function tryHoistNestedConditional(node, getBinding) {
|
|
966
|
+
const { topLevel, nested, test } = scanNestedConditionals(node);
|
|
967
|
+
if (topLevel !== 0 || nested !== 1 || test === null) {
|
|
968
|
+
return null;
|
|
969
|
+
}
|
|
970
|
+
const consequent = tryStaticTransformNode(
|
|
971
|
+
cloneObjectPickingBranch(node, "consequent"),
|
|
972
|
+
getBinding
|
|
973
|
+
);
|
|
974
|
+
const alternate = tryStaticTransformNode(
|
|
975
|
+
cloneObjectPickingBranch(node, "alternate"),
|
|
976
|
+
getBinding
|
|
977
|
+
);
|
|
978
|
+
if (!consequent || !alternate || !t__namespace.isStringLiteral(consequent) || !t__namespace.isStringLiteral(alternate)) {
|
|
979
|
+
return null;
|
|
980
|
+
}
|
|
981
|
+
return t__namespace.conditionalExpression(
|
|
982
|
+
test,
|
|
983
|
+
emptyClassToUndefined(consequent),
|
|
984
|
+
emptyClassToUndefined(alternate)
|
|
985
|
+
);
|
|
986
|
+
}
|
|
871
987
|
function tryHoistConditionalSpread(node, getBinding) {
|
|
872
988
|
let conditionalSpreadIdx = -1;
|
|
873
989
|
let conditionalExpr = null;
|
|
@@ -899,7 +1015,11 @@ function tryHoistConditionalSpread(node, getBinding) {
|
|
|
899
1015
|
if (!t__namespace.isStringLiteral(resolvedA) || !t__namespace.isStringLiteral(resolvedB)) {
|
|
900
1016
|
return null;
|
|
901
1017
|
}
|
|
902
|
-
return t__namespace.conditionalExpression(
|
|
1018
|
+
return t__namespace.conditionalExpression(
|
|
1019
|
+
conditionalExpr.test,
|
|
1020
|
+
emptyClassToUndefined(resolvedA),
|
|
1021
|
+
emptyClassToUndefined(resolvedB)
|
|
1022
|
+
);
|
|
903
1023
|
}
|
|
904
1024
|
function readStaticConfigObject(configExpr, key, scope) {
|
|
905
1025
|
for (const prop of configExpr.properties) {
|
|
@@ -1029,20 +1149,20 @@ function buildConditionalClassExpr(baseClasses, conditionalClasses) {
|
|
|
1029
1149
|
if (conditionalClasses.length === 0) {
|
|
1030
1150
|
return t__namespace.stringLiteral(baseClasses);
|
|
1031
1151
|
}
|
|
1032
|
-
const makeCondExpr = (cc) => t__namespace.conditionalExpression(
|
|
1152
|
+
const makeCondExpr = (cc, bare) => t__namespace.conditionalExpression(
|
|
1033
1153
|
cc.test,
|
|
1034
|
-
t__namespace.stringLiteral(cc.consequent),
|
|
1035
|
-
t__namespace.stringLiteral(cc.alternate)
|
|
1154
|
+
bare && cc.consequent === "" ? t__namespace.identifier("undefined") : t__namespace.stringLiteral(cc.consequent),
|
|
1155
|
+
bare && cc.alternate === "" ? t__namespace.identifier("undefined") : t__namespace.stringLiteral(cc.alternate)
|
|
1036
1156
|
);
|
|
1037
1157
|
if (conditionalClasses.length === 1 && !baseClasses) {
|
|
1038
|
-
return makeCondExpr(conditionalClasses[0]);
|
|
1158
|
+
return makeCondExpr(conditionalClasses[0], true);
|
|
1039
1159
|
}
|
|
1040
1160
|
const quasis = [];
|
|
1041
1161
|
const exprs = [];
|
|
1042
1162
|
for (let i = 0; i < conditionalClasses.length; i++) {
|
|
1043
1163
|
const prefix = i === 0 ? baseClasses ? `${baseClasses} ` : "" : " ";
|
|
1044
1164
|
quasis.push(t__namespace.templateElement({ raw: prefix, cooked: prefix }, false));
|
|
1045
|
-
exprs.push(makeCondExpr(conditionalClasses[i]));
|
|
1165
|
+
exprs.push(makeCondExpr(conditionalClasses[i], false));
|
|
1046
1166
|
}
|
|
1047
1167
|
quasis.push(t__namespace.templateElement({ raw: "", cooked: "" }, true));
|
|
1048
1168
|
return t__namespace.templateLiteral(quasis, exprs);
|
|
@@ -1522,6 +1642,10 @@ class CsszyxCompiler {
|
|
|
1522
1642
|
}
|
|
1523
1643
|
}
|
|
1524
1644
|
|
|
1645
|
+
function sortStrings(values) {
|
|
1646
|
+
return [...values].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1525
1649
|
const CSS_VAR_REFERENCE_RE = /var\(\s*(--[\w-]+)/g;
|
|
1526
1650
|
function scanGlobalVarUsages(source, filename = "file.tsx", options = {}) {
|
|
1527
1651
|
if (!source.includes("--") && !source.includes("var(")) {
|
|
@@ -1731,7 +1855,7 @@ function extractVarReferences(value) {
|
|
|
1731
1855
|
for (const match of value.matchAll(CSS_VAR_REFERENCE_RE)) {
|
|
1732
1856
|
refs.add(match[1]);
|
|
1733
1857
|
}
|
|
1734
|
-
return
|
|
1858
|
+
return sortStrings(refs);
|
|
1735
1859
|
}
|
|
1736
1860
|
function shouldReportToken(name, tokenFilter) {
|
|
1737
1861
|
return tokenFilter === null || tokenFilter.has(name);
|
|
@@ -2005,7 +2129,7 @@ class ManifestBuilder {
|
|
|
2005
2129
|
* @returns {string} SHA-256 checksum
|
|
2006
2130
|
*/
|
|
2007
2131
|
computeChecksum(tokens) {
|
|
2008
|
-
const sortedKeys = Object.keys(tokens)
|
|
2132
|
+
const sortedKeys = sortStrings(Object.keys(tokens));
|
|
2009
2133
|
const sortedTokens = {};
|
|
2010
2134
|
for (const key of sortedKeys) {
|
|
2011
2135
|
sortedTokens[key] = tokens[key];
|
|
@@ -2631,6 +2755,29 @@ function transformOxc(source, filename, options) {
|
|
|
2631
2755
|
transformed = true;
|
|
2632
2756
|
return;
|
|
2633
2757
|
}
|
|
2758
|
+
const nestedConditionalClassExpr = buildNestedConditionalClassExpression(
|
|
2759
|
+
expression,
|
|
2760
|
+
effectiveFilename,
|
|
2761
|
+
objectBindings,
|
|
2762
|
+
source,
|
|
2763
|
+
classes,
|
|
2764
|
+
globalVarAliases,
|
|
2765
|
+
cssVariableMap
|
|
2766
|
+
);
|
|
2767
|
+
if (nestedConditionalClassExpr) {
|
|
2768
|
+
if (classNameAttr || szAttrs.length > 1) {
|
|
2769
|
+
runtimeFallbackExpr = expression;
|
|
2770
|
+
runtimeFallbackAttr = szAttr;
|
|
2771
|
+
break;
|
|
2772
|
+
}
|
|
2773
|
+
edits.overwrite(
|
|
2774
|
+
szAttr.start,
|
|
2775
|
+
szAttr.end,
|
|
2776
|
+
`className={${nestedConditionalClassExpr}}`
|
|
2777
|
+
);
|
|
2778
|
+
transformed = true;
|
|
2779
|
+
return;
|
|
2780
|
+
}
|
|
2634
2781
|
const partial = buildPartialObjectTransform(
|
|
2635
2782
|
expression,
|
|
2636
2783
|
effectiveFilename,
|
|
@@ -2769,7 +2916,7 @@ function transformOxc(source, filename, options) {
|
|
|
2769
2916
|
...existingRaw ? existingRaw.split(/\s+/).filter(Boolean) : [],
|
|
2770
2917
|
...szDerived
|
|
2771
2918
|
];
|
|
2772
|
-
const mergedAttr = `className="${mergedClasses.join(" ")}"`;
|
|
2919
|
+
const mergedAttr = mergedClasses.length === 0 ? "className={undefined}" : `className="${mergedClasses.join(" ")}"`;
|
|
2773
2920
|
if (classNameAttr) {
|
|
2774
2921
|
edits.overwrite(classNameAttr.start, classNameAttr.end, mergedAttr);
|
|
2775
2922
|
for (const szAttr of szAttrs) {
|
|
@@ -2867,7 +3014,7 @@ function extractElementName(nameNode) {
|
|
|
2867
3014
|
}
|
|
2868
3015
|
return "<unknown>";
|
|
2869
3016
|
}
|
|
2870
|
-
function astObjectToSzObject(node, filename, bindings) {
|
|
3017
|
+
function astObjectToSzObject(node, filename, bindings, branchPick) {
|
|
2871
3018
|
const result = {};
|
|
2872
3019
|
for (const propRaw of node.properties) {
|
|
2873
3020
|
if (propRaw.type === "SpreadElement") {
|
|
@@ -2904,7 +3051,7 @@ function astObjectToSzObject(node, filename, bindings) {
|
|
|
2904
3051
|
`unsupported key shape ${prop.key.type} at ${filename}:${prop.key.start}`
|
|
2905
3052
|
);
|
|
2906
3053
|
}
|
|
2907
|
-
result[key] = astValueToSzValue(prop.value, filename, bindings);
|
|
3054
|
+
result[key] = astValueToSzValue(prop.value, filename, bindings, branchPick);
|
|
2908
3055
|
}
|
|
2909
3056
|
return result;
|
|
2910
3057
|
}
|
|
@@ -3336,6 +3483,80 @@ function resolveObjectExpression(node, bindings) {
|
|
|
3336
3483
|
}
|
|
3337
3484
|
return null;
|
|
3338
3485
|
}
|
|
3486
|
+
function countOxcConditionals(node) {
|
|
3487
|
+
let count = 0;
|
|
3488
|
+
for (const propRaw of node.properties) {
|
|
3489
|
+
if (propRaw.type !== "Property") {
|
|
3490
|
+
continue;
|
|
3491
|
+
}
|
|
3492
|
+
const value = propRaw.value;
|
|
3493
|
+
if (value.type === "ConditionalExpression") {
|
|
3494
|
+
count++;
|
|
3495
|
+
} else if (value.type === "ObjectExpression") {
|
|
3496
|
+
count += countOxcConditionals(value);
|
|
3497
|
+
}
|
|
3498
|
+
}
|
|
3499
|
+
return count;
|
|
3500
|
+
}
|
|
3501
|
+
function firstOxcConditional(node) {
|
|
3502
|
+
for (const propRaw of node.properties) {
|
|
3503
|
+
if (propRaw.type !== "Property") {
|
|
3504
|
+
continue;
|
|
3505
|
+
}
|
|
3506
|
+
const value = propRaw.value;
|
|
3507
|
+
if (value.type === "ConditionalExpression") {
|
|
3508
|
+
return value;
|
|
3509
|
+
}
|
|
3510
|
+
if (value.type === "ObjectExpression") {
|
|
3511
|
+
const found = firstOxcConditional(value);
|
|
3512
|
+
if (found) {
|
|
3513
|
+
return found;
|
|
3514
|
+
}
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3517
|
+
return null;
|
|
3518
|
+
}
|
|
3519
|
+
function buildNestedConditionalClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3520
|
+
let topLevel = 0;
|
|
3521
|
+
for (const propRaw of node.properties) {
|
|
3522
|
+
if (propRaw.type === "Property" && propRaw.value.type === "ConditionalExpression") {
|
|
3523
|
+
topLevel++;
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
const first = firstOxcConditional(node);
|
|
3527
|
+
if (topLevel !== 0 || countOxcConditionals(node) !== 1 || !first) {
|
|
3528
|
+
return null;
|
|
3529
|
+
}
|
|
3530
|
+
const compileBranch = (pick) => {
|
|
3531
|
+
try {
|
|
3532
|
+
return transformCore.transform(
|
|
3533
|
+
applyGlobalVarAliasesToSzObject(
|
|
3534
|
+
astObjectToSzObject(node, filename, bindings, pick),
|
|
3535
|
+
globalVarAliases,
|
|
3536
|
+
cssVariableMap
|
|
3537
|
+
)
|
|
3538
|
+
).className;
|
|
3539
|
+
} catch (err) {
|
|
3540
|
+
if (err instanceof OxcNotImplementedError) {
|
|
3541
|
+
return null;
|
|
3542
|
+
}
|
|
3543
|
+
throw err;
|
|
3544
|
+
}
|
|
3545
|
+
};
|
|
3546
|
+
const consequent = compileBranch("consequent");
|
|
3547
|
+
const alternate = compileBranch("alternate");
|
|
3548
|
+
if (consequent === null || alternate === null) {
|
|
3549
|
+
return null;
|
|
3550
|
+
}
|
|
3551
|
+
for (const cls of `${consequent} ${alternate}`.split(/\s+/)) {
|
|
3552
|
+
if (cls) {
|
|
3553
|
+
classes.add(cls);
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
const testSource = source.slice(first.test.start, first.test.end);
|
|
3557
|
+
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
3558
|
+
return `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
3559
|
+
}
|
|
3339
3560
|
function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3340
3561
|
let conditionalSpread = null;
|
|
3341
3562
|
const otherProps = [];
|
|
@@ -3381,7 +3602,8 @@ function buildConditionalSpreadClassExpression(node, filename, bindings, source,
|
|
|
3381
3602
|
}
|
|
3382
3603
|
}
|
|
3383
3604
|
const testSource = source.slice(conditionalSpread.test.start, conditionalSpread.test.end);
|
|
3384
|
-
|
|
3605
|
+
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
3606
|
+
return `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
3385
3607
|
}
|
|
3386
3608
|
function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename, bindings, globalVarAliases, cssVariableMap) {
|
|
3387
3609
|
const branchObject = resolveObjectExpression(branch, bindings);
|
|
@@ -3444,7 +3666,11 @@ function buildPartialObjectTransform(node, filename, bindings, source, options,
|
|
|
3444
3666
|
classParts.push(entry.consequent, entry.alternate);
|
|
3445
3667
|
}
|
|
3446
3668
|
const className = classParts.filter(Boolean).join(" ");
|
|
3447
|
-
const classNameAttr = partial.conditionalClasses.length > 0 ? `className={${buildConditionalClassSource(classParts, partial.conditionalClasses, source)}}` :
|
|
3669
|
+
const classNameAttr = partial.conditionalClasses.length > 0 ? `className={${buildConditionalClassSource(classParts, partial.conditionalClasses, source)}}` : className === "" ? (
|
|
3670
|
+
// An sz that lowers to zero classes emits `className={undefined}` so the
|
|
3671
|
+
// DOM has no `class` attribute, instead of the noisy `class=""`.
|
|
3672
|
+
"className={undefined}"
|
|
3673
|
+
) : `className="${className}"`;
|
|
3448
3674
|
const styleProps = [...partial.dynamicProps.entries()].filter(([id]) => !hoistedNames?.has(id)).map(
|
|
3449
3675
|
([, info]) => `${JSON.stringify(info.varName)}: ${generateStyleValueSource(info, source)}`
|
|
3450
3676
|
);
|
|
@@ -4018,9 +4244,11 @@ function buildCSSVarClassName(info) {
|
|
|
4018
4244
|
function buildConditionalClassSource(classParts, conditionals, source) {
|
|
4019
4245
|
if (conditionals.length === 1) {
|
|
4020
4246
|
const [entry] = conditionals;
|
|
4021
|
-
const ternary = `${source.slice(entry.test.start, entry.test.end)} ? ${JSON.stringify(entry.consequent)} : ${JSON.stringify(entry.alternate)}`;
|
|
4022
4247
|
const staticParts = classParts.slice(0, -2).filter(Boolean);
|
|
4023
|
-
|
|
4248
|
+
const bare = staticParts.length === 0;
|
|
4249
|
+
const branch = (cls) => bare && cls === "" ? "undefined" : JSON.stringify(cls);
|
|
4250
|
+
const ternary = `${source.slice(entry.test.start, entry.test.end)} ? ${branch(entry.consequent)} : ${branch(entry.alternate)}`;
|
|
4251
|
+
if (bare) {
|
|
4024
4252
|
return ternary;
|
|
4025
4253
|
}
|
|
4026
4254
|
return `\`${staticParts.join(" ")} \${${ternary}}\``;
|
|
@@ -4072,7 +4300,8 @@ function buildStaticConditionalClassExpression(node, filename, bindings, source,
|
|
|
4072
4300
|
}
|
|
4073
4301
|
}
|
|
4074
4302
|
const testSource = source.slice(node.test.start, node.test.end);
|
|
4075
|
-
|
|
4303
|
+
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
4304
|
+
return `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
4076
4305
|
}
|
|
4077
4306
|
function resolveStaticClassString(node, filename, bindings, globalVarAliases, cssVariableMap) {
|
|
4078
4307
|
const unwrapped = unwrapExpression(node);
|
|
@@ -4112,7 +4341,15 @@ function extractKeyName(key) {
|
|
|
4112
4341
|
}
|
|
4113
4342
|
return null;
|
|
4114
4343
|
}
|
|
4115
|
-
function astValueToSzValue(node, filename, bindings) {
|
|
4344
|
+
function astValueToSzValue(node, filename, bindings, branchPick) {
|
|
4345
|
+
if (branchPick && node.type === "ConditionalExpression") {
|
|
4346
|
+
return astValueToSzValue(
|
|
4347
|
+
node[branchPick],
|
|
4348
|
+
filename,
|
|
4349
|
+
bindings,
|
|
4350
|
+
branchPick
|
|
4351
|
+
);
|
|
4352
|
+
}
|
|
4116
4353
|
if (node.type === "Literal") {
|
|
4117
4354
|
const value = node.value;
|
|
4118
4355
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
@@ -4138,7 +4375,7 @@ function astValueToSzValue(node, filename, bindings) {
|
|
|
4138
4375
|
);
|
|
4139
4376
|
}
|
|
4140
4377
|
if (node.type === "ObjectExpression") {
|
|
4141
|
-
return astObjectToSzObject(node, filename, bindings);
|
|
4378
|
+
return astObjectToSzObject(node, filename, bindings, branchPick);
|
|
4142
4379
|
}
|
|
4143
4380
|
if (node.type === "Identifier" || node.type === "MemberExpression") {
|
|
4144
4381
|
throw new OxcNotImplementedError(
|
|
@@ -4409,6 +4646,7 @@ exports.mergeOptions = mergeOptions;
|
|
|
4409
4646
|
exports.parseManifest = parseManifest;
|
|
4410
4647
|
exports.scanGlobalVarUsages = scanGlobalVarUsages;
|
|
4411
4648
|
exports.serializeManifest = serializeManifest;
|
|
4649
|
+
exports.sortStrings = sortStrings;
|
|
4412
4650
|
exports.transformOxc = transformOxc;
|
|
4413
4651
|
exports.transformRust = transformRust;
|
|
4414
4652
|
exports.transformRustBatch = transformRustBatch;
|
package/dist/index.d.cts
CHANGED
|
@@ -581,6 +581,28 @@ declare const COLOR_PROPERTIES: Set<string>;
|
|
|
581
581
|
*/
|
|
582
582
|
declare function getCSSVariableName(property: string, variantPrefix?: string): string;
|
|
583
583
|
|
|
584
|
+
/**
|
|
585
|
+
* Deterministic, locale-independent ascending sort for string collections.
|
|
586
|
+
*
|
|
587
|
+
* A bare `Array.prototype.sort()` coerces elements to strings, so it silently
|
|
588
|
+
* mis-orders numbers (`[10, 9]` → `[10, 9]`). Every ordered collection in this
|
|
589
|
+
* codebase is a set of identifiers — class names, mangle tokens, filenames,
|
|
590
|
+
* variant names, CSS-variable references — so the correct sort is lexicographic
|
|
591
|
+
* AND locale-independent (a locale-aware `localeCompare` would make build output
|
|
592
|
+
* order depend on the runner's locale and break reproducibility).
|
|
593
|
+
*
|
|
594
|
+
* This helper encodes exactly that, and its `T extends string` bound makes the
|
|
595
|
+
* intent compiler-checked: passing a `number[]` (or a `(string | number)[]`) is a
|
|
596
|
+
* type error, so a future numeric sort cannot slip through as a bare `.sort()`.
|
|
597
|
+
* The `no-restricted-syntax` lint rule forbids bare `.sort()` to route every sort
|
|
598
|
+
* through here or an explicit comparator.
|
|
599
|
+
*
|
|
600
|
+
* @template T - the (string) element type.
|
|
601
|
+
* @param values - the strings to sort (any iterable; not mutated).
|
|
602
|
+
* @returns a new array sorted ascending by UTF-16 code unit.
|
|
603
|
+
*/
|
|
604
|
+
declare function sortStrings<T extends string>(values: Iterable<T>): T[];
|
|
605
|
+
|
|
584
606
|
/**
|
|
585
607
|
* Phase D production transform — `transformOxc()` is the oxc-parser +
|
|
586
608
|
* magic-string replacement for `transformSourceCode()` (Babel). The
|
|
@@ -13639,5 +13661,5 @@ declare const DEFAULT_COMPILER_OPTIONS: Required<CompilerOptions>;
|
|
|
13639
13661
|
*/
|
|
13640
13662
|
declare function mergeOptions(options?: Partial<CompilerOptions>): Required<CompilerOptions>;
|
|
13641
13663
|
|
|
13642
|
-
export { COLOR_PROPERTIES, CsszyxCompiler, DEFAULT_COMPILER_OPTIONS, ManifestBuilder, OxcNotImplementedError, OxcRustNotImplementedError, PROPERTY_CATEGORY_MAP, PropertyCategory, SzObject, VERSION, buildParentMap, createRecoveryToken, ensureRustTransformAvailable, generateRecoveryToken, getCSSVariableName, getPropertyCategory, hoistCSSVariables, injectRecoveryToken, isRustTransformAvailable, isValidRecoveryMode, mergeOptions, parseManifest, scanGlobalVarUsages, serializeManifest, transformOxc, transformRust, transformRustBatch, transformSourceCode, validateManifest, validateSzRecover };
|
|
13664
|
+
export { COLOR_PROPERTIES, CsszyxCompiler, DEFAULT_COMPILER_OPTIONS, ManifestBuilder, OxcNotImplementedError, OxcRustNotImplementedError, PROPERTY_CATEGORY_MAP, PropertyCategory, SzObject, VERSION, buildParentMap, createRecoveryToken, ensureRustTransformAvailable, generateRecoveryToken, getCSSVariableName, getPropertyCategory, hoistCSSVariables, injectRecoveryToken, isRustTransformAvailable, isValidRecoveryMode, mergeOptions, parseManifest, scanGlobalVarUsages, serializeManifest, sortStrings, transformOxc, transformRust, transformRustBatch, transformSourceCode, validateManifest, validateSzRecover };
|
|
13643
13665
|
export type { BackgroundProps, BorderProps, BorderRadiusValue, CSSVarUsage, ColorName, ColorObjectValue, ColorPropValue, ColorShade, ColorValue, CompilerOptions, ContainerSize, CssVariableMangleValue, CustomTheme, EffectsProps, FilterProps, FlexboxGridProps, FractionValue, GlobalVarAliasTableInput, GlobalVarUsageDiagnostic, GlobalVarUsageKind, GlobalVarUsageLocation, InteractivityProps, LayoutProps, NegativeSpacingValue, RecoveryManifest, RecoveryMode, RecoveryToken, ScanGlobalVarUsagesOptions, ShadowValue, SizingProps, SourceTransformResult, SpacingProps, SpacingScale, SpacingValue, SvgProps, SzPropValue, SzProps, SzPropsBase, TableProps, TokenData, TokenMetadata, TransformOxcResult, TransformProps, TransformRustFile, TransformSourceCodeOptions, TransitionAnimationProps, TypographyProps, VariantModifiers };
|
package/dist/index.d.mts
CHANGED
|
@@ -581,6 +581,28 @@ declare const COLOR_PROPERTIES: Set<string>;
|
|
|
581
581
|
*/
|
|
582
582
|
declare function getCSSVariableName(property: string, variantPrefix?: string): string;
|
|
583
583
|
|
|
584
|
+
/**
|
|
585
|
+
* Deterministic, locale-independent ascending sort for string collections.
|
|
586
|
+
*
|
|
587
|
+
* A bare `Array.prototype.sort()` coerces elements to strings, so it silently
|
|
588
|
+
* mis-orders numbers (`[10, 9]` → `[10, 9]`). Every ordered collection in this
|
|
589
|
+
* codebase is a set of identifiers — class names, mangle tokens, filenames,
|
|
590
|
+
* variant names, CSS-variable references — so the correct sort is lexicographic
|
|
591
|
+
* AND locale-independent (a locale-aware `localeCompare` would make build output
|
|
592
|
+
* order depend on the runner's locale and break reproducibility).
|
|
593
|
+
*
|
|
594
|
+
* This helper encodes exactly that, and its `T extends string` bound makes the
|
|
595
|
+
* intent compiler-checked: passing a `number[]` (or a `(string | number)[]`) is a
|
|
596
|
+
* type error, so a future numeric sort cannot slip through as a bare `.sort()`.
|
|
597
|
+
* The `no-restricted-syntax` lint rule forbids bare `.sort()` to route every sort
|
|
598
|
+
* through here or an explicit comparator.
|
|
599
|
+
*
|
|
600
|
+
* @template T - the (string) element type.
|
|
601
|
+
* @param values - the strings to sort (any iterable; not mutated).
|
|
602
|
+
* @returns a new array sorted ascending by UTF-16 code unit.
|
|
603
|
+
*/
|
|
604
|
+
declare function sortStrings<T extends string>(values: Iterable<T>): T[];
|
|
605
|
+
|
|
584
606
|
/**
|
|
585
607
|
* Phase D production transform — `transformOxc()` is the oxc-parser +
|
|
586
608
|
* magic-string replacement for `transformSourceCode()` (Babel). The
|
|
@@ -13639,5 +13661,5 @@ declare const DEFAULT_COMPILER_OPTIONS: Required<CompilerOptions>;
|
|
|
13639
13661
|
*/
|
|
13640
13662
|
declare function mergeOptions(options?: Partial<CompilerOptions>): Required<CompilerOptions>;
|
|
13641
13663
|
|
|
13642
|
-
export { COLOR_PROPERTIES, CsszyxCompiler, DEFAULT_COMPILER_OPTIONS, ManifestBuilder, OxcNotImplementedError, OxcRustNotImplementedError, PROPERTY_CATEGORY_MAP, PropertyCategory, SzObject, VERSION, buildParentMap, createRecoveryToken, ensureRustTransformAvailable, generateRecoveryToken, getCSSVariableName, getPropertyCategory, hoistCSSVariables, injectRecoveryToken, isRustTransformAvailable, isValidRecoveryMode, mergeOptions, parseManifest, scanGlobalVarUsages, serializeManifest, transformOxc, transformRust, transformRustBatch, transformSourceCode, validateManifest, validateSzRecover };
|
|
13664
|
+
export { COLOR_PROPERTIES, CsszyxCompiler, DEFAULT_COMPILER_OPTIONS, ManifestBuilder, OxcNotImplementedError, OxcRustNotImplementedError, PROPERTY_CATEGORY_MAP, PropertyCategory, SzObject, VERSION, buildParentMap, createRecoveryToken, ensureRustTransformAvailable, generateRecoveryToken, getCSSVariableName, getPropertyCategory, hoistCSSVariables, injectRecoveryToken, isRustTransformAvailable, isValidRecoveryMode, mergeOptions, parseManifest, scanGlobalVarUsages, serializeManifest, sortStrings, transformOxc, transformRust, transformRustBatch, transformSourceCode, validateManifest, validateSzRecover };
|
|
13643
13665
|
export type { BackgroundProps, BorderProps, BorderRadiusValue, CSSVarUsage, ColorName, ColorObjectValue, ColorPropValue, ColorShade, ColorValue, CompilerOptions, ContainerSize, CssVariableMangleValue, CustomTheme, EffectsProps, FilterProps, FlexboxGridProps, FractionValue, GlobalVarAliasTableInput, GlobalVarUsageDiagnostic, GlobalVarUsageKind, GlobalVarUsageLocation, InteractivityProps, LayoutProps, NegativeSpacingValue, RecoveryManifest, RecoveryMode, RecoveryToken, ScanGlobalVarUsagesOptions, ShadowValue, SizingProps, SourceTransformResult, SpacingProps, SpacingScale, SpacingValue, SvgProps, SzPropValue, SzProps, SzPropsBase, TableProps, TokenData, TokenMetadata, TransformOxcResult, TransformProps, TransformRustFile, TransformSourceCodeOptions, TransitionAnimationProps, TypographyProps, VariantModifiers };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { init, version, transform_sz, encode } from '@csszyx/core';
|
|
2
|
-
import { t as transform, s as setSzWarnLocation, f as formatSzWarnLocation, C as COLOR_PROPERTIES, P as PROPERTY_MAP, g as getCSSVariableName, a as PropertyCategory, K as KNOWN_VARIANTS, b as getVariantPrefix, c as getPropertyCategory, d as stripInvalidColorStrings } from './shared/compiler.
|
|
3
|
-
export { B as BOOLEAN_SHORTHANDS, e as PROPERTY_CATEGORY_MAP, R as REMOVED_BOOLEAN_SUGAR, S as SPECIAL_VARIANTS, h as SUGGESTION_MAP, i as isValidSzProp, n as normalizeClassName } from './shared/compiler.
|
|
2
|
+
import { t as transform, s as setSzWarnLocation, f as formatSzWarnLocation, C as COLOR_PROPERTIES, P as PROPERTY_MAP, g as getCSSVariableName, a as PropertyCategory, K as KNOWN_VARIANTS, b as getVariantPrefix, c as getPropertyCategory, d as stripInvalidColorStrings } from './shared/compiler.CghwJ6p5.mjs';
|
|
3
|
+
export { B as BOOLEAN_SHORTHANDS, e as PROPERTY_CATEGORY_MAP, R as REMOVED_BOOLEAN_SUGAR, S as SPECIAL_VARIANTS, h as SUGGESTION_MAP, i as isValidSzProp, n as normalizeClassName } from './shared/compiler.CghwJ6p5.mjs';
|
|
4
4
|
import { parseSync } from 'oxc-parser';
|
|
5
5
|
import * as t from '@babel/types';
|
|
6
6
|
import { createHash } from 'node:crypto';
|
|
@@ -226,6 +226,9 @@ function transformSourceCode(source, filename, options) {
|
|
|
226
226
|
}
|
|
227
227
|
const createMergedClassNameValue = (szExpr) => {
|
|
228
228
|
if (!existingClassExpr) {
|
|
229
|
+
if (t.isStringLiteral(szExpr) && szExpr.value === "") {
|
|
230
|
+
return t.jsxExpressionContainer(t.identifier("undefined"));
|
|
231
|
+
}
|
|
229
232
|
return t.isStringLiteral(szExpr) ? szExpr : t.jsxExpressionContainer(szExpr);
|
|
230
233
|
}
|
|
231
234
|
if (existingClassNameNode && path.parentPath?.isJSXOpeningElement()) {
|
|
@@ -368,6 +371,17 @@ function transformSourceCode(source, filename, options) {
|
|
|
368
371
|
transformed = true;
|
|
369
372
|
return;
|
|
370
373
|
}
|
|
374
|
+
const hoistedNested = tryHoistNestedConditional(
|
|
375
|
+
flatExpression,
|
|
376
|
+
getBinding
|
|
377
|
+
);
|
|
378
|
+
if (hoistedNested !== null) {
|
|
379
|
+
path.node.name.name = "className";
|
|
380
|
+
path.node.value = createMergedClassNameValue(hoistedNested);
|
|
381
|
+
collectFromExpr(hoistedNested, collectedClasses);
|
|
382
|
+
transformed = true;
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
371
385
|
const partial = evaluatePartialObject$1(flatExpression);
|
|
372
386
|
if (partial !== null && !partial.hasSpread && (partial.dynamicProps.size > 0 || partial.conditionalClasses.length > 0)) {
|
|
373
387
|
const staticClasses = [];
|
|
@@ -807,6 +821,9 @@ function parseStyleStringToObjectExpr(styleStr) {
|
|
|
807
821
|
}
|
|
808
822
|
return t.objectExpression(objProps);
|
|
809
823
|
}
|
|
824
|
+
function emptyClassToUndefined(node) {
|
|
825
|
+
return t.isStringLiteral(node) && node.value === "" ? t.identifier("undefined") : node;
|
|
826
|
+
}
|
|
810
827
|
function tryStaticTransformNode(node, getBinding) {
|
|
811
828
|
if (t.isTSAsExpression(node) || t.isTSSatisfiesExpression(node)) {
|
|
812
829
|
return tryStaticTransformNode(node.expression, getBinding);
|
|
@@ -843,12 +860,111 @@ function tryStaticTransformNode(node, getBinding) {
|
|
|
843
860
|
const consequent = tryStaticTransformNode(node.consequent, getBinding);
|
|
844
861
|
const alternate = tryStaticTransformNode(node.alternate, getBinding);
|
|
845
862
|
if (consequent !== null && alternate !== null) {
|
|
846
|
-
return t.conditionalExpression(
|
|
863
|
+
return t.conditionalExpression(
|
|
864
|
+
node.test,
|
|
865
|
+
emptyClassToUndefined(consequent),
|
|
866
|
+
emptyClassToUndefined(alternate)
|
|
867
|
+
);
|
|
847
868
|
}
|
|
848
869
|
return null;
|
|
849
870
|
}
|
|
850
871
|
return null;
|
|
851
872
|
}
|
|
873
|
+
function scanNestedConditionals(node) {
|
|
874
|
+
let topLevel = 0;
|
|
875
|
+
let nested = 0;
|
|
876
|
+
let test = null;
|
|
877
|
+
for (const prop of node.properties) {
|
|
878
|
+
if (!t.isObjectProperty(prop)) {
|
|
879
|
+
continue;
|
|
880
|
+
}
|
|
881
|
+
const value = prop.value;
|
|
882
|
+
if (t.isConditionalExpression(value)) {
|
|
883
|
+
topLevel++;
|
|
884
|
+
} else if (t.isObjectExpression(value)) {
|
|
885
|
+
nested += countAllConditionals(value);
|
|
886
|
+
test ??= firstConditionalTest(value);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
return { topLevel, nested, test };
|
|
890
|
+
}
|
|
891
|
+
function countAllConditionals(node) {
|
|
892
|
+
let count = 0;
|
|
893
|
+
for (const prop of node.properties) {
|
|
894
|
+
if (!t.isObjectProperty(prop)) {
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
897
|
+
const value = prop.value;
|
|
898
|
+
if (t.isConditionalExpression(value)) {
|
|
899
|
+
count++;
|
|
900
|
+
} else if (t.isObjectExpression(value)) {
|
|
901
|
+
count += countAllConditionals(value);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
return count;
|
|
905
|
+
}
|
|
906
|
+
function firstConditionalTest(node) {
|
|
907
|
+
for (const prop of node.properties) {
|
|
908
|
+
if (!t.isObjectProperty(prop)) {
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
const value = prop.value;
|
|
912
|
+
if (t.isConditionalExpression(value)) {
|
|
913
|
+
return value.test;
|
|
914
|
+
}
|
|
915
|
+
if (t.isObjectExpression(value)) {
|
|
916
|
+
const inner = firstConditionalTest(value);
|
|
917
|
+
if (inner) {
|
|
918
|
+
return inner;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return null;
|
|
923
|
+
}
|
|
924
|
+
function cloneObjectPickingBranch(node, pick) {
|
|
925
|
+
return t.objectExpression(
|
|
926
|
+
node.properties.map((prop) => {
|
|
927
|
+
if (!t.isObjectProperty(prop)) {
|
|
928
|
+
return t.cloneNode(prop);
|
|
929
|
+
}
|
|
930
|
+
const value = prop.value;
|
|
931
|
+
let nextValue = t.cloneNode(value);
|
|
932
|
+
if (t.isConditionalExpression(value)) {
|
|
933
|
+
nextValue = t.cloneNode(value[pick]);
|
|
934
|
+
} else if (t.isObjectExpression(value)) {
|
|
935
|
+
nextValue = cloneObjectPickingBranch(value, pick);
|
|
936
|
+
}
|
|
937
|
+
return t.objectProperty(
|
|
938
|
+
t.cloneNode(prop.key),
|
|
939
|
+
nextValue,
|
|
940
|
+
prop.computed,
|
|
941
|
+
prop.shorthand
|
|
942
|
+
);
|
|
943
|
+
})
|
|
944
|
+
);
|
|
945
|
+
}
|
|
946
|
+
function tryHoistNestedConditional(node, getBinding) {
|
|
947
|
+
const { topLevel, nested, test } = scanNestedConditionals(node);
|
|
948
|
+
if (topLevel !== 0 || nested !== 1 || test === null) {
|
|
949
|
+
return null;
|
|
950
|
+
}
|
|
951
|
+
const consequent = tryStaticTransformNode(
|
|
952
|
+
cloneObjectPickingBranch(node, "consequent"),
|
|
953
|
+
getBinding
|
|
954
|
+
);
|
|
955
|
+
const alternate = tryStaticTransformNode(
|
|
956
|
+
cloneObjectPickingBranch(node, "alternate"),
|
|
957
|
+
getBinding
|
|
958
|
+
);
|
|
959
|
+
if (!consequent || !alternate || !t.isStringLiteral(consequent) || !t.isStringLiteral(alternate)) {
|
|
960
|
+
return null;
|
|
961
|
+
}
|
|
962
|
+
return t.conditionalExpression(
|
|
963
|
+
test,
|
|
964
|
+
emptyClassToUndefined(consequent),
|
|
965
|
+
emptyClassToUndefined(alternate)
|
|
966
|
+
);
|
|
967
|
+
}
|
|
852
968
|
function tryHoistConditionalSpread(node, getBinding) {
|
|
853
969
|
let conditionalSpreadIdx = -1;
|
|
854
970
|
let conditionalExpr = null;
|
|
@@ -880,7 +996,11 @@ function tryHoistConditionalSpread(node, getBinding) {
|
|
|
880
996
|
if (!t.isStringLiteral(resolvedA) || !t.isStringLiteral(resolvedB)) {
|
|
881
997
|
return null;
|
|
882
998
|
}
|
|
883
|
-
return t.conditionalExpression(
|
|
999
|
+
return t.conditionalExpression(
|
|
1000
|
+
conditionalExpr.test,
|
|
1001
|
+
emptyClassToUndefined(resolvedA),
|
|
1002
|
+
emptyClassToUndefined(resolvedB)
|
|
1003
|
+
);
|
|
884
1004
|
}
|
|
885
1005
|
function readStaticConfigObject(configExpr, key, scope) {
|
|
886
1006
|
for (const prop of configExpr.properties) {
|
|
@@ -1010,20 +1130,20 @@ function buildConditionalClassExpr(baseClasses, conditionalClasses) {
|
|
|
1010
1130
|
if (conditionalClasses.length === 0) {
|
|
1011
1131
|
return t.stringLiteral(baseClasses);
|
|
1012
1132
|
}
|
|
1013
|
-
const makeCondExpr = (cc) => t.conditionalExpression(
|
|
1133
|
+
const makeCondExpr = (cc, bare) => t.conditionalExpression(
|
|
1014
1134
|
cc.test,
|
|
1015
|
-
t.stringLiteral(cc.consequent),
|
|
1016
|
-
t.stringLiteral(cc.alternate)
|
|
1135
|
+
bare && cc.consequent === "" ? t.identifier("undefined") : t.stringLiteral(cc.consequent),
|
|
1136
|
+
bare && cc.alternate === "" ? t.identifier("undefined") : t.stringLiteral(cc.alternate)
|
|
1017
1137
|
);
|
|
1018
1138
|
if (conditionalClasses.length === 1 && !baseClasses) {
|
|
1019
|
-
return makeCondExpr(conditionalClasses[0]);
|
|
1139
|
+
return makeCondExpr(conditionalClasses[0], true);
|
|
1020
1140
|
}
|
|
1021
1141
|
const quasis = [];
|
|
1022
1142
|
const exprs = [];
|
|
1023
1143
|
for (let i = 0; i < conditionalClasses.length; i++) {
|
|
1024
1144
|
const prefix = i === 0 ? baseClasses ? `${baseClasses} ` : "" : " ";
|
|
1025
1145
|
quasis.push(t.templateElement({ raw: prefix, cooked: prefix }, false));
|
|
1026
|
-
exprs.push(makeCondExpr(conditionalClasses[i]));
|
|
1146
|
+
exprs.push(makeCondExpr(conditionalClasses[i], false));
|
|
1027
1147
|
}
|
|
1028
1148
|
quasis.push(t.templateElement({ raw: "", cooked: "" }, true));
|
|
1029
1149
|
return t.templateLiteral(quasis, exprs);
|
|
@@ -1503,6 +1623,10 @@ class CsszyxCompiler {
|
|
|
1503
1623
|
}
|
|
1504
1624
|
}
|
|
1505
1625
|
|
|
1626
|
+
function sortStrings(values) {
|
|
1627
|
+
return [...values].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1506
1630
|
const CSS_VAR_REFERENCE_RE = /var\(\s*(--[\w-]+)/g;
|
|
1507
1631
|
function scanGlobalVarUsages(source, filename = "file.tsx", options = {}) {
|
|
1508
1632
|
if (!source.includes("--") && !source.includes("var(")) {
|
|
@@ -1712,7 +1836,7 @@ function extractVarReferences(value) {
|
|
|
1712
1836
|
for (const match of value.matchAll(CSS_VAR_REFERENCE_RE)) {
|
|
1713
1837
|
refs.add(match[1]);
|
|
1714
1838
|
}
|
|
1715
|
-
return
|
|
1839
|
+
return sortStrings(refs);
|
|
1716
1840
|
}
|
|
1717
1841
|
function shouldReportToken(name, tokenFilter) {
|
|
1718
1842
|
return tokenFilter === null || tokenFilter.has(name);
|
|
@@ -1986,7 +2110,7 @@ class ManifestBuilder {
|
|
|
1986
2110
|
* @returns {string} SHA-256 checksum
|
|
1987
2111
|
*/
|
|
1988
2112
|
computeChecksum(tokens) {
|
|
1989
|
-
const sortedKeys = Object.keys(tokens)
|
|
2113
|
+
const sortedKeys = sortStrings(Object.keys(tokens));
|
|
1990
2114
|
const sortedTokens = {};
|
|
1991
2115
|
for (const key of sortedKeys) {
|
|
1992
2116
|
sortedTokens[key] = tokens[key];
|
|
@@ -2612,6 +2736,29 @@ function transformOxc(source, filename, options) {
|
|
|
2612
2736
|
transformed = true;
|
|
2613
2737
|
return;
|
|
2614
2738
|
}
|
|
2739
|
+
const nestedConditionalClassExpr = buildNestedConditionalClassExpression(
|
|
2740
|
+
expression,
|
|
2741
|
+
effectiveFilename,
|
|
2742
|
+
objectBindings,
|
|
2743
|
+
source,
|
|
2744
|
+
classes,
|
|
2745
|
+
globalVarAliases,
|
|
2746
|
+
cssVariableMap
|
|
2747
|
+
);
|
|
2748
|
+
if (nestedConditionalClassExpr) {
|
|
2749
|
+
if (classNameAttr || szAttrs.length > 1) {
|
|
2750
|
+
runtimeFallbackExpr = expression;
|
|
2751
|
+
runtimeFallbackAttr = szAttr;
|
|
2752
|
+
break;
|
|
2753
|
+
}
|
|
2754
|
+
edits.overwrite(
|
|
2755
|
+
szAttr.start,
|
|
2756
|
+
szAttr.end,
|
|
2757
|
+
`className={${nestedConditionalClassExpr}}`
|
|
2758
|
+
);
|
|
2759
|
+
transformed = true;
|
|
2760
|
+
return;
|
|
2761
|
+
}
|
|
2615
2762
|
const partial = buildPartialObjectTransform(
|
|
2616
2763
|
expression,
|
|
2617
2764
|
effectiveFilename,
|
|
@@ -2750,7 +2897,7 @@ function transformOxc(source, filename, options) {
|
|
|
2750
2897
|
...existingRaw ? existingRaw.split(/\s+/).filter(Boolean) : [],
|
|
2751
2898
|
...szDerived
|
|
2752
2899
|
];
|
|
2753
|
-
const mergedAttr = `className="${mergedClasses.join(" ")}"`;
|
|
2900
|
+
const mergedAttr = mergedClasses.length === 0 ? "className={undefined}" : `className="${mergedClasses.join(" ")}"`;
|
|
2754
2901
|
if (classNameAttr) {
|
|
2755
2902
|
edits.overwrite(classNameAttr.start, classNameAttr.end, mergedAttr);
|
|
2756
2903
|
for (const szAttr of szAttrs) {
|
|
@@ -2848,7 +2995,7 @@ function extractElementName(nameNode) {
|
|
|
2848
2995
|
}
|
|
2849
2996
|
return "<unknown>";
|
|
2850
2997
|
}
|
|
2851
|
-
function astObjectToSzObject(node, filename, bindings) {
|
|
2998
|
+
function astObjectToSzObject(node, filename, bindings, branchPick) {
|
|
2852
2999
|
const result = {};
|
|
2853
3000
|
for (const propRaw of node.properties) {
|
|
2854
3001
|
if (propRaw.type === "SpreadElement") {
|
|
@@ -2885,7 +3032,7 @@ function astObjectToSzObject(node, filename, bindings) {
|
|
|
2885
3032
|
`unsupported key shape ${prop.key.type} at ${filename}:${prop.key.start}`
|
|
2886
3033
|
);
|
|
2887
3034
|
}
|
|
2888
|
-
result[key] = astValueToSzValue(prop.value, filename, bindings);
|
|
3035
|
+
result[key] = astValueToSzValue(prop.value, filename, bindings, branchPick);
|
|
2889
3036
|
}
|
|
2890
3037
|
return result;
|
|
2891
3038
|
}
|
|
@@ -3317,6 +3464,80 @@ function resolveObjectExpression(node, bindings) {
|
|
|
3317
3464
|
}
|
|
3318
3465
|
return null;
|
|
3319
3466
|
}
|
|
3467
|
+
function countOxcConditionals(node) {
|
|
3468
|
+
let count = 0;
|
|
3469
|
+
for (const propRaw of node.properties) {
|
|
3470
|
+
if (propRaw.type !== "Property") {
|
|
3471
|
+
continue;
|
|
3472
|
+
}
|
|
3473
|
+
const value = propRaw.value;
|
|
3474
|
+
if (value.type === "ConditionalExpression") {
|
|
3475
|
+
count++;
|
|
3476
|
+
} else if (value.type === "ObjectExpression") {
|
|
3477
|
+
count += countOxcConditionals(value);
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
return count;
|
|
3481
|
+
}
|
|
3482
|
+
function firstOxcConditional(node) {
|
|
3483
|
+
for (const propRaw of node.properties) {
|
|
3484
|
+
if (propRaw.type !== "Property") {
|
|
3485
|
+
continue;
|
|
3486
|
+
}
|
|
3487
|
+
const value = propRaw.value;
|
|
3488
|
+
if (value.type === "ConditionalExpression") {
|
|
3489
|
+
return value;
|
|
3490
|
+
}
|
|
3491
|
+
if (value.type === "ObjectExpression") {
|
|
3492
|
+
const found = firstOxcConditional(value);
|
|
3493
|
+
if (found) {
|
|
3494
|
+
return found;
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
3498
|
+
return null;
|
|
3499
|
+
}
|
|
3500
|
+
function buildNestedConditionalClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3501
|
+
let topLevel = 0;
|
|
3502
|
+
for (const propRaw of node.properties) {
|
|
3503
|
+
if (propRaw.type === "Property" && propRaw.value.type === "ConditionalExpression") {
|
|
3504
|
+
topLevel++;
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
const first = firstOxcConditional(node);
|
|
3508
|
+
if (topLevel !== 0 || countOxcConditionals(node) !== 1 || !first) {
|
|
3509
|
+
return null;
|
|
3510
|
+
}
|
|
3511
|
+
const compileBranch = (pick) => {
|
|
3512
|
+
try {
|
|
3513
|
+
return transform(
|
|
3514
|
+
applyGlobalVarAliasesToSzObject(
|
|
3515
|
+
astObjectToSzObject(node, filename, bindings, pick),
|
|
3516
|
+
globalVarAliases,
|
|
3517
|
+
cssVariableMap
|
|
3518
|
+
)
|
|
3519
|
+
).className;
|
|
3520
|
+
} catch (err) {
|
|
3521
|
+
if (err instanceof OxcNotImplementedError) {
|
|
3522
|
+
return null;
|
|
3523
|
+
}
|
|
3524
|
+
throw err;
|
|
3525
|
+
}
|
|
3526
|
+
};
|
|
3527
|
+
const consequent = compileBranch("consequent");
|
|
3528
|
+
const alternate = compileBranch("alternate");
|
|
3529
|
+
if (consequent === null || alternate === null) {
|
|
3530
|
+
return null;
|
|
3531
|
+
}
|
|
3532
|
+
for (const cls of `${consequent} ${alternate}`.split(/\s+/)) {
|
|
3533
|
+
if (cls) {
|
|
3534
|
+
classes.add(cls);
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
const testSource = source.slice(first.test.start, first.test.end);
|
|
3538
|
+
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
3539
|
+
return `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
3540
|
+
}
|
|
3320
3541
|
function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3321
3542
|
let conditionalSpread = null;
|
|
3322
3543
|
const otherProps = [];
|
|
@@ -3362,7 +3583,8 @@ function buildConditionalSpreadClassExpression(node, filename, bindings, source,
|
|
|
3362
3583
|
}
|
|
3363
3584
|
}
|
|
3364
3585
|
const testSource = source.slice(conditionalSpread.test.start, conditionalSpread.test.end);
|
|
3365
|
-
|
|
3586
|
+
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
3587
|
+
return `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
3366
3588
|
}
|
|
3367
3589
|
function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename, bindings, globalVarAliases, cssVariableMap) {
|
|
3368
3590
|
const branchObject = resolveObjectExpression(branch, bindings);
|
|
@@ -3425,7 +3647,11 @@ function buildPartialObjectTransform(node, filename, bindings, source, options,
|
|
|
3425
3647
|
classParts.push(entry.consequent, entry.alternate);
|
|
3426
3648
|
}
|
|
3427
3649
|
const className = classParts.filter(Boolean).join(" ");
|
|
3428
|
-
const classNameAttr = partial.conditionalClasses.length > 0 ? `className={${buildConditionalClassSource(classParts, partial.conditionalClasses, source)}}` :
|
|
3650
|
+
const classNameAttr = partial.conditionalClasses.length > 0 ? `className={${buildConditionalClassSource(classParts, partial.conditionalClasses, source)}}` : className === "" ? (
|
|
3651
|
+
// An sz that lowers to zero classes emits `className={undefined}` so the
|
|
3652
|
+
// DOM has no `class` attribute, instead of the noisy `class=""`.
|
|
3653
|
+
"className={undefined}"
|
|
3654
|
+
) : `className="${className}"`;
|
|
3429
3655
|
const styleProps = [...partial.dynamicProps.entries()].filter(([id]) => !hoistedNames?.has(id)).map(
|
|
3430
3656
|
([, info]) => `${JSON.stringify(info.varName)}: ${generateStyleValueSource(info, source)}`
|
|
3431
3657
|
);
|
|
@@ -3999,9 +4225,11 @@ function buildCSSVarClassName(info) {
|
|
|
3999
4225
|
function buildConditionalClassSource(classParts, conditionals, source) {
|
|
4000
4226
|
if (conditionals.length === 1) {
|
|
4001
4227
|
const [entry] = conditionals;
|
|
4002
|
-
const ternary = `${source.slice(entry.test.start, entry.test.end)} ? ${JSON.stringify(entry.consequent)} : ${JSON.stringify(entry.alternate)}`;
|
|
4003
4228
|
const staticParts = classParts.slice(0, -2).filter(Boolean);
|
|
4004
|
-
|
|
4229
|
+
const bare = staticParts.length === 0;
|
|
4230
|
+
const branch = (cls) => bare && cls === "" ? "undefined" : JSON.stringify(cls);
|
|
4231
|
+
const ternary = `${source.slice(entry.test.start, entry.test.end)} ? ${branch(entry.consequent)} : ${branch(entry.alternate)}`;
|
|
4232
|
+
if (bare) {
|
|
4005
4233
|
return ternary;
|
|
4006
4234
|
}
|
|
4007
4235
|
return `\`${staticParts.join(" ")} \${${ternary}}\``;
|
|
@@ -4053,7 +4281,8 @@ function buildStaticConditionalClassExpression(node, filename, bindings, source,
|
|
|
4053
4281
|
}
|
|
4054
4282
|
}
|
|
4055
4283
|
const testSource = source.slice(node.test.start, node.test.end);
|
|
4056
|
-
|
|
4284
|
+
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
4285
|
+
return `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
4057
4286
|
}
|
|
4058
4287
|
function resolveStaticClassString(node, filename, bindings, globalVarAliases, cssVariableMap) {
|
|
4059
4288
|
const unwrapped = unwrapExpression(node);
|
|
@@ -4093,7 +4322,15 @@ function extractKeyName(key) {
|
|
|
4093
4322
|
}
|
|
4094
4323
|
return null;
|
|
4095
4324
|
}
|
|
4096
|
-
function astValueToSzValue(node, filename, bindings) {
|
|
4325
|
+
function astValueToSzValue(node, filename, bindings, branchPick) {
|
|
4326
|
+
if (branchPick && node.type === "ConditionalExpression") {
|
|
4327
|
+
return astValueToSzValue(
|
|
4328
|
+
node[branchPick],
|
|
4329
|
+
filename,
|
|
4330
|
+
bindings,
|
|
4331
|
+
branchPick
|
|
4332
|
+
);
|
|
4333
|
+
}
|
|
4097
4334
|
if (node.type === "Literal") {
|
|
4098
4335
|
const value = node.value;
|
|
4099
4336
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
@@ -4119,7 +4356,7 @@ function astValueToSzValue(node, filename, bindings) {
|
|
|
4119
4356
|
);
|
|
4120
4357
|
}
|
|
4121
4358
|
if (node.type === "ObjectExpression") {
|
|
4122
|
-
return astObjectToSzObject(node, filename, bindings);
|
|
4359
|
+
return astObjectToSzObject(node, filename, bindings, branchPick);
|
|
4123
4360
|
}
|
|
4124
4361
|
if (node.type === "Identifier" || node.type === "MemberExpression") {
|
|
4125
4362
|
throw new OxcNotImplementedError(
|
|
@@ -4358,4 +4595,4 @@ function mergeOptions(options = {}) {
|
|
|
4358
4595
|
};
|
|
4359
4596
|
}
|
|
4360
4597
|
|
|
4361
|
-
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 };
|
|
4598
|
+
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 };
|
|
@@ -1496,6 +1496,16 @@ function handleSupports(supportsObj, prefix) {
|
|
|
1496
1496
|
}
|
|
1497
1497
|
let szTransformDepth = 0;
|
|
1498
1498
|
let szWarnLocation;
|
|
1499
|
+
let szHintedProjectScan = false;
|
|
1500
|
+
function hintProjectScanOnce(location) {
|
|
1501
|
+
if (szHintedProjectScan || !location || process.env.CSSZYX_NO_PROJECT_SCAN_HINT === "1") {
|
|
1502
|
+
return;
|
|
1503
|
+
}
|
|
1504
|
+
szHintedProjectScan = true;
|
|
1505
|
+
console.warn(
|
|
1506
|
+
"[csszyx] Tip: run `npx @csszyx/cli check` to scan every file for sz key issues at once (dev warnings only surface files as you open them)."
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
1499
1509
|
function setSzWarnLocation(location) {
|
|
1500
1510
|
szWarnLocation = location;
|
|
1501
1511
|
}
|
|
@@ -2370,6 +2380,7 @@ function transformImpl(szProp, prefix, mangleMap) {
|
|
|
2370
2380
|
`[csszyx] Unknown property "${rawKey}" in sz prop${at}. This will be ignored. Check for typos.`
|
|
2371
2381
|
);
|
|
2372
2382
|
}
|
|
2383
|
+
hintProjectScanOnce(szWarnLocation);
|
|
2373
2384
|
}
|
|
2374
2385
|
}
|
|
2375
2386
|
if (value === true) {
|
|
@@ -1498,6 +1498,16 @@ function handleSupports(supportsObj, prefix) {
|
|
|
1498
1498
|
}
|
|
1499
1499
|
let szTransformDepth = 0;
|
|
1500
1500
|
let szWarnLocation;
|
|
1501
|
+
let szHintedProjectScan = false;
|
|
1502
|
+
function hintProjectScanOnce(location) {
|
|
1503
|
+
if (szHintedProjectScan || !location || process.env.CSSZYX_NO_PROJECT_SCAN_HINT === "1") {
|
|
1504
|
+
return;
|
|
1505
|
+
}
|
|
1506
|
+
szHintedProjectScan = true;
|
|
1507
|
+
console.warn(
|
|
1508
|
+
"[csszyx] Tip: run `npx @csszyx/cli check` to scan every file for sz key issues at once (dev warnings only surface files as you open them)."
|
|
1509
|
+
);
|
|
1510
|
+
}
|
|
1501
1511
|
function setSzWarnLocation(location) {
|
|
1502
1512
|
szWarnLocation = location;
|
|
1503
1513
|
}
|
|
@@ -2372,6 +2382,7 @@ function transformImpl(szProp, prefix, mangleMap) {
|
|
|
2372
2382
|
`[csszyx] Unknown property "${rawKey}" in sz prop${at}. This will be ignored. Check for typos.`
|
|
2373
2383
|
);
|
|
2374
2384
|
}
|
|
2385
|
+
hintProjectScanOnce(szWarnLocation);
|
|
2375
2386
|
}
|
|
2376
2387
|
}
|
|
2377
2388
|
if (value === true) {
|
package/dist/transform-core.cjs
CHANGED
package/dist/transform-core.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { B as BOOLEAN_SHORTHANDS, K as KNOWN_VARIANTS, M as MAX_SZ_DEPTH, P as PROPERTY_MAP, R as REMOVED_BOOLEAN_SUGAR, S as SPECIAL_VARIANTS, h as SUGGESTION_MAP, j as SzDepthError, V as VARIANT_MAP, f as formatSzWarnLocation, b as getVariantPrefix, k as isForbiddenSzKey, i as isValidSzProp, l as normalizeArbitraryValue, m as normalizeArbitraryVariant, n as normalizeClassName, s as setSzWarnLocation, t as transform } from './shared/compiler.
|
|
1
|
+
export { B as BOOLEAN_SHORTHANDS, K as KNOWN_VARIANTS, M as MAX_SZ_DEPTH, P as PROPERTY_MAP, R as REMOVED_BOOLEAN_SUGAR, S as SPECIAL_VARIANTS, h as SUGGESTION_MAP, j as SzDepthError, V as VARIANT_MAP, f as formatSzWarnLocation, b as getVariantPrefix, k as isForbiddenSzKey, i as isValidSzProp, l as normalizeArbitraryValue, m as normalizeArbitraryVariant, n as normalizeClassName, s as setSzWarnLocation, t as transform } from './shared/compiler.CghwJ6p5.mjs';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@csszyx/compiler",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.9",
|
|
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.
|
|
68
|
+
"@csszyx/core": "0.10.9"
|
|
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.
|
|
77
|
+
"vitest": "^4.1.9"
|
|
78
78
|
},
|
|
79
79
|
"sideEffects": false,
|
|
80
80
|
"engines": {
|