@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.cjs +501 -6
- package/dist/index.d.cts +42 -2
- package/dist/index.d.mts +42 -2
- package/dist/index.mjs +501 -7
- package/package.json +3 -3
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
|
|
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)
|
|
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.
|
|
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.
|
|
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.
|
|
77
|
+
"vitest": "^4.1.9"
|
|
78
78
|
},
|
|
79
79
|
"sideEffects": false,
|
|
80
80
|
"engines": {
|