@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.cjs
CHANGED
|
@@ -81,6 +81,7 @@ function transformSourceCode(source, filename, options) {
|
|
|
81
81
|
let usesColorVar = false;
|
|
82
82
|
let transformed = false;
|
|
83
83
|
const collectedClasses = /* @__PURE__ */ new Set();
|
|
84
|
+
const szsPendingClasses = [];
|
|
84
85
|
const rawClassNames = /* @__PURE__ */ new Set();
|
|
85
86
|
const diagnostics = [];
|
|
86
87
|
const recoveryTokens = /* @__PURE__ */ new Map();
|
|
@@ -200,6 +201,70 @@ function transformSourceCode(source, filename, options) {
|
|
|
200
201
|
transformed = true;
|
|
201
202
|
return;
|
|
202
203
|
}
|
|
204
|
+
if (attrName === "szs") {
|
|
205
|
+
const openingEl = path.parentPath?.isJSXOpeningElement() ? path.parentPath.node : null;
|
|
206
|
+
if (openingEl && isHostElementName(openingEl.name)) {
|
|
207
|
+
diagnostics.push(
|
|
208
|
+
`[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.`
|
|
209
|
+
);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const container = path.node.value;
|
|
213
|
+
if (!t__namespace.isJSXExpressionContainer(container) || !t__namespace.isObjectExpression(container.expression)) {
|
|
214
|
+
diagnostics.push(szsUnsupportedMessage$1(filename));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
const slotMap = container.expression;
|
|
218
|
+
if (!isValidSzsSlotMap$1(slotMap)) {
|
|
219
|
+
diagnostics.push(szsUnsupportedMessage$1(filename));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
transformCore.setSzWarnLocation(
|
|
223
|
+
transformCore.formatSzWarnLocation(
|
|
224
|
+
filename ?? "file.tsx",
|
|
225
|
+
path.node.loc?.start.line,
|
|
226
|
+
options?.rootDir
|
|
227
|
+
)
|
|
228
|
+
);
|
|
229
|
+
const compiledSlots = [];
|
|
230
|
+
for (const prop of slotMap.properties) {
|
|
231
|
+
const slot = prop;
|
|
232
|
+
if (t__namespace.isStringLiteral(slot.value)) {
|
|
233
|
+
compiledSlots.push({
|
|
234
|
+
slot,
|
|
235
|
+
classes: slot.value.value,
|
|
236
|
+
rewrite: false
|
|
237
|
+
});
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const compiled = tryStaticTransformNode(slot.value);
|
|
241
|
+
if (!compiled || !t__namespace.isStringLiteral(compiled)) {
|
|
242
|
+
diagnostics.push(szsUnsupportedMessage$1(filename));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
compiledSlots.push({
|
|
246
|
+
slot,
|
|
247
|
+
classes: compiled.value,
|
|
248
|
+
rewrite: true
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
for (const {
|
|
252
|
+
slot,
|
|
253
|
+
classes: slotClasses,
|
|
254
|
+
rewrite
|
|
255
|
+
} of compiledSlots) {
|
|
256
|
+
if (rewrite) {
|
|
257
|
+
slot.value = t__namespace.stringLiteral(slotClasses);
|
|
258
|
+
transformed = true;
|
|
259
|
+
}
|
|
260
|
+
for (const c of slotClasses.split(/\s+/)) {
|
|
261
|
+
if (c) {
|
|
262
|
+
szsPendingClasses.push(c);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
203
268
|
if (attrName !== "sz") {
|
|
204
269
|
return;
|
|
205
270
|
}
|
|
@@ -390,6 +455,17 @@ function transformSourceCode(source, filename, options) {
|
|
|
390
455
|
transformed = true;
|
|
391
456
|
return;
|
|
392
457
|
}
|
|
458
|
+
const hoistedNested = tryHoistNestedConditional(
|
|
459
|
+
flatExpression,
|
|
460
|
+
getBinding
|
|
461
|
+
);
|
|
462
|
+
if (hoistedNested !== null) {
|
|
463
|
+
path.node.name.name = "className";
|
|
464
|
+
path.node.value = createMergedClassNameValue(hoistedNested);
|
|
465
|
+
collectFromExpr(hoistedNested, collectedClasses);
|
|
466
|
+
transformed = true;
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
393
469
|
const partial = evaluatePartialObject$1(flatExpression);
|
|
394
470
|
if (partial !== null && !partial.hasSpread && (partial.dynamicProps.size > 0 || partial.conditionalClasses.length > 0)) {
|
|
395
471
|
const staticClasses = [];
|
|
@@ -778,6 +854,9 @@ function transformSourceCode(source, filename, options) {
|
|
|
778
854
|
})
|
|
779
855
|
]
|
|
780
856
|
});
|
|
857
|
+
for (const c of szsPendingClasses) {
|
|
858
|
+
collectedClasses.add(c);
|
|
859
|
+
}
|
|
781
860
|
return {
|
|
782
861
|
code: result?.code || source,
|
|
783
862
|
transformed,
|
|
@@ -829,6 +908,31 @@ function parseStyleStringToObjectExpr(styleStr) {
|
|
|
829
908
|
}
|
|
830
909
|
return t__namespace.objectExpression(objProps);
|
|
831
910
|
}
|
|
911
|
+
function isHostElementName(name) {
|
|
912
|
+
return t__namespace.isJSXIdentifier(name) && /^[a-z]/.test(name.name);
|
|
913
|
+
}
|
|
914
|
+
function szsUnsupportedMessage$1(filename) {
|
|
915
|
+
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.`;
|
|
916
|
+
}
|
|
917
|
+
function isPureLiteralSzValue$1(node) {
|
|
918
|
+
if (t__namespace.isStringLiteral(node) || t__namespace.isNumericLiteral(node) || t__namespace.isBooleanLiteral(node)) {
|
|
919
|
+
return true;
|
|
920
|
+
}
|
|
921
|
+
if (t__namespace.isUnaryExpression(node) && node.operator === "-" && t__namespace.isNumericLiteral(node.argument)) {
|
|
922
|
+
return true;
|
|
923
|
+
}
|
|
924
|
+
if (t__namespace.isObjectExpression(node)) {
|
|
925
|
+
return node.properties.every(
|
|
926
|
+
(prop) => t__namespace.isObjectProperty(prop) && !prop.computed && t__namespace.isIdentifier(prop.key) && isPureLiteralSzValue$1(prop.value)
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
return false;
|
|
930
|
+
}
|
|
931
|
+
function isValidSzsSlotMap$1(slotMap) {
|
|
932
|
+
return slotMap.properties.every(
|
|
933
|
+
(prop) => t__namespace.isObjectProperty(prop) && !prop.computed && t__namespace.isIdentifier(prop.key) && (t__namespace.isStringLiteral(prop.value) || t__namespace.isObjectExpression(prop.value) && isPureLiteralSzValue$1(prop.value))
|
|
934
|
+
);
|
|
935
|
+
}
|
|
832
936
|
function emptyClassToUndefined(node) {
|
|
833
937
|
return t__namespace.isStringLiteral(node) && node.value === "" ? t__namespace.identifier("undefined") : node;
|
|
834
938
|
}
|
|
@@ -878,6 +982,123 @@ function tryStaticTransformNode(node, getBinding) {
|
|
|
878
982
|
}
|
|
879
983
|
return null;
|
|
880
984
|
}
|
|
985
|
+
function scanNestedConditionals(node) {
|
|
986
|
+
let topLevel = 0;
|
|
987
|
+
let nested = 0;
|
|
988
|
+
let test = null;
|
|
989
|
+
for (const prop of node.properties) {
|
|
990
|
+
if (!t__namespace.isObjectProperty(prop)) {
|
|
991
|
+
continue;
|
|
992
|
+
}
|
|
993
|
+
const value = prop.value;
|
|
994
|
+
if (t__namespace.isConditionalExpression(value)) {
|
|
995
|
+
topLevel++;
|
|
996
|
+
} else if (t__namespace.isObjectExpression(value)) {
|
|
997
|
+
nested += countAllConditionals(value);
|
|
998
|
+
test ??= firstConditionalTest(value);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
return { topLevel, nested, test };
|
|
1002
|
+
}
|
|
1003
|
+
function countAllConditionals(node) {
|
|
1004
|
+
let count = 0;
|
|
1005
|
+
for (const prop of node.properties) {
|
|
1006
|
+
if (!t__namespace.isObjectProperty(prop)) {
|
|
1007
|
+
continue;
|
|
1008
|
+
}
|
|
1009
|
+
const value = prop.value;
|
|
1010
|
+
if (t__namespace.isConditionalExpression(value)) {
|
|
1011
|
+
count++;
|
|
1012
|
+
} else if (t__namespace.isObjectExpression(value)) {
|
|
1013
|
+
count += countAllConditionals(value);
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
return count;
|
|
1017
|
+
}
|
|
1018
|
+
function firstConditionalTest(node) {
|
|
1019
|
+
for (const prop of node.properties) {
|
|
1020
|
+
if (!t__namespace.isObjectProperty(prop)) {
|
|
1021
|
+
continue;
|
|
1022
|
+
}
|
|
1023
|
+
const value = prop.value;
|
|
1024
|
+
if (t__namespace.isConditionalExpression(value)) {
|
|
1025
|
+
return value.test;
|
|
1026
|
+
}
|
|
1027
|
+
if (t__namespace.isObjectExpression(value)) {
|
|
1028
|
+
const inner = firstConditionalTest(value);
|
|
1029
|
+
if (inner) {
|
|
1030
|
+
return inner;
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
return null;
|
|
1035
|
+
}
|
|
1036
|
+
function cloneObjectPickingBranch(node, pick) {
|
|
1037
|
+
return t__namespace.objectExpression(
|
|
1038
|
+
node.properties.map((prop) => {
|
|
1039
|
+
if (!t__namespace.isObjectProperty(prop)) {
|
|
1040
|
+
return t__namespace.cloneNode(prop);
|
|
1041
|
+
}
|
|
1042
|
+
const value = prop.value;
|
|
1043
|
+
let nextValue = t__namespace.cloneNode(value);
|
|
1044
|
+
if (t__namespace.isConditionalExpression(value)) {
|
|
1045
|
+
nextValue = t__namespace.cloneNode(value[pick]);
|
|
1046
|
+
} else if (t__namespace.isObjectExpression(value)) {
|
|
1047
|
+
nextValue = cloneObjectPickingBranch(value, pick);
|
|
1048
|
+
}
|
|
1049
|
+
return t__namespace.objectProperty(
|
|
1050
|
+
t__namespace.cloneNode(prop.key),
|
|
1051
|
+
nextValue,
|
|
1052
|
+
prop.computed,
|
|
1053
|
+
prop.shorthand
|
|
1054
|
+
);
|
|
1055
|
+
})
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
function tryHoistNestedConditional(node, getBinding) {
|
|
1059
|
+
const { topLevel, nested, test } = scanNestedConditionals(node);
|
|
1060
|
+
if (topLevel !== 0 || nested !== 1 || test === null) {
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
const condPropIndex = node.properties.findIndex(
|
|
1064
|
+
(prop) => t__namespace.isObjectProperty(prop) && t__namespace.isObjectExpression(prop.value) && countAllConditionals(prop.value) === 1
|
|
1065
|
+
);
|
|
1066
|
+
if (condPropIndex === -1) {
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
const staticNode = t__namespace.objectExpression(node.properties.filter((_, i) => i !== condPropIndex));
|
|
1070
|
+
const condNode = t__namespace.objectExpression([node.properties[condPropIndex]]);
|
|
1071
|
+
const staticClasses = staticNode.properties.length > 0 ? tryStaticTransformNode(staticNode, getBinding) : null;
|
|
1072
|
+
const consequent = tryStaticTransformNode(
|
|
1073
|
+
cloneObjectPickingBranch(condNode, "consequent"),
|
|
1074
|
+
getBinding
|
|
1075
|
+
);
|
|
1076
|
+
const alternate = tryStaticTransformNode(
|
|
1077
|
+
cloneObjectPickingBranch(condNode, "alternate"),
|
|
1078
|
+
getBinding
|
|
1079
|
+
);
|
|
1080
|
+
if (!consequent || !alternate || !t__namespace.isStringLiteral(consequent) || !t__namespace.isStringLiteral(alternate) || staticNode.properties.length > 0 && (!staticClasses || !t__namespace.isStringLiteral(staticClasses))) {
|
|
1081
|
+
return null;
|
|
1082
|
+
}
|
|
1083
|
+
const ternary = t__namespace.conditionalExpression(
|
|
1084
|
+
test,
|
|
1085
|
+
emptyClassToUndefined(consequent),
|
|
1086
|
+
emptyClassToUndefined(alternate)
|
|
1087
|
+
);
|
|
1088
|
+
if (!staticClasses || !t__namespace.isStringLiteral(staticClasses) || staticClasses.value === "") {
|
|
1089
|
+
return ternary;
|
|
1090
|
+
}
|
|
1091
|
+
return t__namespace.templateLiteral(
|
|
1092
|
+
[
|
|
1093
|
+
t__namespace.templateElement(
|
|
1094
|
+
{ raw: `${staticClasses.value} `, cooked: `${staticClasses.value} ` },
|
|
1095
|
+
false
|
|
1096
|
+
),
|
|
1097
|
+
t__namespace.templateElement({ raw: "", cooked: "" }, true)
|
|
1098
|
+
],
|
|
1099
|
+
[ternary]
|
|
1100
|
+
);
|
|
1101
|
+
}
|
|
881
1102
|
function tryHoistConditionalSpread(node, getBinding) {
|
|
882
1103
|
let conditionalSpreadIdx = -1;
|
|
883
1104
|
let conditionalExpr = null;
|
|
@@ -1286,6 +1507,18 @@ function collectFromExpr(node, classes) {
|
|
|
1286
1507
|
} else if (t__namespace.isConditionalExpression(node)) {
|
|
1287
1508
|
collectFromExpr(node.consequent, classes);
|
|
1288
1509
|
collectFromExpr(node.alternate, classes);
|
|
1510
|
+
} else if (t__namespace.isTemplateLiteral(node)) {
|
|
1511
|
+
for (let i = 0; i < node.quasis.length; i++) {
|
|
1512
|
+
for (const c of (node.quasis[i].value.cooked ?? "").split(/\s+/)) {
|
|
1513
|
+
if (c) {
|
|
1514
|
+
classes.add(c);
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
const expr = node.expressions[i];
|
|
1518
|
+
if (expr && t__namespace.isExpression(expr)) {
|
|
1519
|
+
collectFromExpr(expr, classes);
|
|
1520
|
+
}
|
|
1521
|
+
}
|
|
1289
1522
|
}
|
|
1290
1523
|
}
|
|
1291
1524
|
function collectCandidatesFromBabelExpr(node, path, classes) {
|
|
@@ -1536,6 +1769,10 @@ class CsszyxCompiler {
|
|
|
1536
1769
|
}
|
|
1537
1770
|
}
|
|
1538
1771
|
|
|
1772
|
+
function sortStrings(values) {
|
|
1773
|
+
return [...values].sort((a, b) => a < b ? -1 : a > b ? 1 : 0);
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1539
1776
|
const CSS_VAR_REFERENCE_RE = /var\(\s*(--[\w-]+)/g;
|
|
1540
1777
|
function scanGlobalVarUsages(source, filename = "file.tsx", options = {}) {
|
|
1541
1778
|
if (!source.includes("--") && !source.includes("var(")) {
|
|
@@ -1745,7 +1982,7 @@ function extractVarReferences(value) {
|
|
|
1745
1982
|
for (const match of value.matchAll(CSS_VAR_REFERENCE_RE)) {
|
|
1746
1983
|
refs.add(match[1]);
|
|
1747
1984
|
}
|
|
1748
|
-
return
|
|
1985
|
+
return sortStrings(refs);
|
|
1749
1986
|
}
|
|
1750
1987
|
function shouldReportToken(name, tokenFilter) {
|
|
1751
1988
|
return tokenFilter === null || tokenFilter.has(name);
|
|
@@ -2019,7 +2256,7 @@ class ManifestBuilder {
|
|
|
2019
2256
|
* @returns {string} SHA-256 checksum
|
|
2020
2257
|
*/
|
|
2021
2258
|
computeChecksum(tokens) {
|
|
2022
|
-
const sortedKeys = Object.keys(tokens)
|
|
2259
|
+
const sortedKeys = sortStrings(Object.keys(tokens));
|
|
2023
2260
|
const sortedTokens = {};
|
|
2024
2261
|
for (const key of sortedKeys) {
|
|
2025
2262
|
sortedTokens[key] = tokens[key];
|
|
@@ -2295,6 +2532,7 @@ class OxcNotImplementedError extends Error {
|
|
|
2295
2532
|
}
|
|
2296
2533
|
function transformOxc(source, filename, options) {
|
|
2297
2534
|
const classes = /* @__PURE__ */ new Set();
|
|
2535
|
+
const szsPendingClasses = [];
|
|
2298
2536
|
const rawClassNames = /* @__PURE__ */ new Set();
|
|
2299
2537
|
const diagnostics = [];
|
|
2300
2538
|
const recoveryTokens = /* @__PURE__ */ new Map();
|
|
@@ -2366,6 +2604,7 @@ function transformOxc(source, filename, options) {
|
|
|
2366
2604
|
const openingNode = node;
|
|
2367
2605
|
const attrs = openingNode.attributes ?? [];
|
|
2368
2606
|
const szAttrs = [];
|
|
2607
|
+
const szsAttrs = [];
|
|
2369
2608
|
let classNameAttr = null;
|
|
2370
2609
|
let styleAttr = null;
|
|
2371
2610
|
let szRecoverAttr = null;
|
|
@@ -2398,6 +2637,8 @@ function transformOxc(source, filename, options) {
|
|
|
2398
2637
|
const name = attr.name?.name;
|
|
2399
2638
|
if (name === "sz") {
|
|
2400
2639
|
szAttrs.push(attr);
|
|
2640
|
+
} else if (name === "szs") {
|
|
2641
|
+
szsAttrs.push(attr);
|
|
2401
2642
|
} else if (name === "className" || name === "class") {
|
|
2402
2643
|
classNameAttr = attr;
|
|
2403
2644
|
} else if (name === "style") {
|
|
@@ -2448,6 +2689,89 @@ function transformOxc(source, filename, options) {
|
|
|
2448
2689
|
}
|
|
2449
2690
|
}
|
|
2450
2691
|
}
|
|
2692
|
+
for (const szsAttr of szsAttrs) {
|
|
2693
|
+
if (isHostOpeningElementName(openingNode.name)) {
|
|
2694
|
+
diagnostics.push(
|
|
2695
|
+
`[csszyx] szs at ${effectiveFilename}: szs has no effect on a host element \u2014 it maps slot names of a custom component. Attribute left unchanged.`
|
|
2696
|
+
);
|
|
2697
|
+
continue;
|
|
2698
|
+
}
|
|
2699
|
+
const szsValue = szsAttr.value;
|
|
2700
|
+
const szsExpression = szsValue && szsValue.type === "JSXExpressionContainer" ? szsValue.expression : null;
|
|
2701
|
+
if (!szsExpression || szsExpression.type !== "ObjectExpression") {
|
|
2702
|
+
diagnostics.push(szsUnsupportedMessage(effectiveFilename));
|
|
2703
|
+
continue;
|
|
2704
|
+
}
|
|
2705
|
+
const slotMap = szsExpression;
|
|
2706
|
+
if (!isValidSzsSlotMap(slotMap)) {
|
|
2707
|
+
diagnostics.push(szsUnsupportedMessage(effectiveFilename));
|
|
2708
|
+
continue;
|
|
2709
|
+
}
|
|
2710
|
+
const { line: szsWarnLine } = offsetToLineColumn(source, szsAttr.start);
|
|
2711
|
+
transformCore.setSzWarnLocation(
|
|
2712
|
+
transformCore.formatSzWarnLocation(effectiveFilename, szsWarnLine, options?.rootDir)
|
|
2713
|
+
);
|
|
2714
|
+
const slotEntries = [];
|
|
2715
|
+
let anyCompiled = false;
|
|
2716
|
+
let slotFailed = false;
|
|
2717
|
+
for (const propRaw of slotMap.properties) {
|
|
2718
|
+
const prop = propRaw;
|
|
2719
|
+
const keyText = source.slice(prop.key.start, prop.key.end);
|
|
2720
|
+
const propValue = prop.value;
|
|
2721
|
+
const literal = propValue.type === "Literal" ? propValue.value : null;
|
|
2722
|
+
if (typeof literal === "string") {
|
|
2723
|
+
slotEntries.push({
|
|
2724
|
+
keyText,
|
|
2725
|
+
classNames: literal,
|
|
2726
|
+
text: source.slice(propValue.start, propValue.end)
|
|
2727
|
+
});
|
|
2728
|
+
continue;
|
|
2729
|
+
}
|
|
2730
|
+
try {
|
|
2731
|
+
const slotObject = astObjectToSzObject(
|
|
2732
|
+
propValue,
|
|
2733
|
+
effectiveFilename,
|
|
2734
|
+
objectBindings
|
|
2735
|
+
);
|
|
2736
|
+
const compiled = transformCore.transform(
|
|
2737
|
+
applyGlobalVarAliasesToSzObject(
|
|
2738
|
+
slotObject,
|
|
2739
|
+
globalVarAliases,
|
|
2740
|
+
cssVariableMap
|
|
2741
|
+
)
|
|
2742
|
+
).className;
|
|
2743
|
+
slotEntries.push({
|
|
2744
|
+
keyText,
|
|
2745
|
+
classNames: compiled,
|
|
2746
|
+
text: JSON.stringify(compiled)
|
|
2747
|
+
});
|
|
2748
|
+
anyCompiled = true;
|
|
2749
|
+
} catch (err) {
|
|
2750
|
+
if (err instanceof OxcNotImplementedError) {
|
|
2751
|
+
slotFailed = true;
|
|
2752
|
+
break;
|
|
2753
|
+
}
|
|
2754
|
+
throw err;
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
transformCore.setSzWarnLocation(void 0);
|
|
2758
|
+
if (slotFailed) {
|
|
2759
|
+
diagnostics.push(szsUnsupportedMessage(effectiveFilename));
|
|
2760
|
+
continue;
|
|
2761
|
+
}
|
|
2762
|
+
if (anyCompiled) {
|
|
2763
|
+
const body = slotEntries.map((entry) => `${entry.keyText}: ${entry.text}`).join(", ");
|
|
2764
|
+
edits.overwrite(szsAttr.start, szsAttr.end, `szs={{ ${body} }}`);
|
|
2765
|
+
transformed = true;
|
|
2766
|
+
}
|
|
2767
|
+
for (const entry of slotEntries) {
|
|
2768
|
+
for (const c of entry.classNames.split(/\s+/)) {
|
|
2769
|
+
if (c) {
|
|
2770
|
+
szsPendingClasses.push(c);
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2451
2775
|
if (szAttrs.length === 0) {
|
|
2452
2776
|
applyHoistedStyleProps();
|
|
2453
2777
|
return;
|
|
@@ -2645,6 +2969,29 @@ function transformOxc(source, filename, options) {
|
|
|
2645
2969
|
transformed = true;
|
|
2646
2970
|
return;
|
|
2647
2971
|
}
|
|
2972
|
+
const nestedConditionalClassExpr = buildNestedConditionalClassExpression(
|
|
2973
|
+
expression,
|
|
2974
|
+
effectiveFilename,
|
|
2975
|
+
objectBindings,
|
|
2976
|
+
source,
|
|
2977
|
+
classes,
|
|
2978
|
+
globalVarAliases,
|
|
2979
|
+
cssVariableMap
|
|
2980
|
+
);
|
|
2981
|
+
if (nestedConditionalClassExpr) {
|
|
2982
|
+
if (classNameAttr || szAttrs.length > 1) {
|
|
2983
|
+
runtimeFallbackExpr = expression;
|
|
2984
|
+
runtimeFallbackAttr = szAttr;
|
|
2985
|
+
break;
|
|
2986
|
+
}
|
|
2987
|
+
edits.overwrite(
|
|
2988
|
+
szAttr.start,
|
|
2989
|
+
szAttr.end,
|
|
2990
|
+
`className={${nestedConditionalClassExpr}}`
|
|
2991
|
+
);
|
|
2992
|
+
transformed = true;
|
|
2993
|
+
return;
|
|
2994
|
+
}
|
|
2648
2995
|
const partial = buildPartialObjectTransform(
|
|
2649
2996
|
expression,
|
|
2650
2997
|
effectiveFilename,
|
|
@@ -2803,6 +3150,9 @@ function transformOxc(source, filename, options) {
|
|
|
2803
3150
|
}
|
|
2804
3151
|
transformed = true;
|
|
2805
3152
|
});
|
|
3153
|
+
for (const c of szsPendingClasses) {
|
|
3154
|
+
classes.add(c);
|
|
3155
|
+
}
|
|
2806
3156
|
return {
|
|
2807
3157
|
code: transformed ? edits.toString() : source,
|
|
2808
3158
|
transformed,
|
|
@@ -2872,6 +3222,49 @@ function buildRuntimeFallbackDiagnostic(expression, source) {
|
|
|
2872
3222
|
return `sz fallback at ${lineCol}: ${reason}.
|
|
2873
3223
|
Suggestion: ${suggestion}`;
|
|
2874
3224
|
}
|
|
3225
|
+
function isHostOpeningElementName(nameNode) {
|
|
3226
|
+
return nameNode.type === "JSXIdentifier" && /^[a-z]/.test(String(nameNode.name));
|
|
3227
|
+
}
|
|
3228
|
+
function szsUnsupportedMessage(filename) {
|
|
3229
|
+
return `[csszyx] szs at ${filename}: every slot must be an identifier key with a static object literal (or class string) value. Attribute left unchanged.`;
|
|
3230
|
+
}
|
|
3231
|
+
function isPureLiteralSzValue(node) {
|
|
3232
|
+
if (node.type === "Literal") {
|
|
3233
|
+
const value = node.value;
|
|
3234
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
3235
|
+
}
|
|
3236
|
+
if (node.type === "UnaryExpression") {
|
|
3237
|
+
const unary = node;
|
|
3238
|
+
return unary.operator === "-" && unary.argument.type === "Literal" && typeof unary.argument.value === "number";
|
|
3239
|
+
}
|
|
3240
|
+
if (node.type === "ObjectExpression") {
|
|
3241
|
+
const properties = node.properties;
|
|
3242
|
+
return properties.every((propRaw) => {
|
|
3243
|
+
if (propRaw.type !== "Property") {
|
|
3244
|
+
return false;
|
|
3245
|
+
}
|
|
3246
|
+
const prop = propRaw;
|
|
3247
|
+
return !prop.computed && prop.key.type === "Identifier" && isPureLiteralSzValue(prop.value);
|
|
3248
|
+
});
|
|
3249
|
+
}
|
|
3250
|
+
return false;
|
|
3251
|
+
}
|
|
3252
|
+
function isValidSzsSlotMap(slotMap) {
|
|
3253
|
+
return slotMap.properties.every((propRaw) => {
|
|
3254
|
+
if (propRaw.type !== "Property") {
|
|
3255
|
+
return false;
|
|
3256
|
+
}
|
|
3257
|
+
const prop = propRaw;
|
|
3258
|
+
if (prop.computed || prop.key.type !== "Identifier") {
|
|
3259
|
+
return false;
|
|
3260
|
+
}
|
|
3261
|
+
const value = prop.value;
|
|
3262
|
+
if (value.type === "Literal" && typeof value.value === "string") {
|
|
3263
|
+
return true;
|
|
3264
|
+
}
|
|
3265
|
+
return value.type === "ObjectExpression" && isPureLiteralSzValue(value);
|
|
3266
|
+
});
|
|
3267
|
+
}
|
|
2875
3268
|
function extractElementName(nameNode) {
|
|
2876
3269
|
if (nameNode.type === "JSXIdentifier") {
|
|
2877
3270
|
return String(nameNode.name);
|
|
@@ -2881,7 +3274,7 @@ function extractElementName(nameNode) {
|
|
|
2881
3274
|
}
|
|
2882
3275
|
return "<unknown>";
|
|
2883
3276
|
}
|
|
2884
|
-
function astObjectToSzObject(node, filename, bindings) {
|
|
3277
|
+
function astObjectToSzObject(node, filename, bindings, branchPick) {
|
|
2885
3278
|
const result = {};
|
|
2886
3279
|
for (const propRaw of node.properties) {
|
|
2887
3280
|
if (propRaw.type === "SpreadElement") {
|
|
@@ -2918,7 +3311,7 @@ function astObjectToSzObject(node, filename, bindings) {
|
|
|
2918
3311
|
`unsupported key shape ${prop.key.type} at ${filename}:${prop.key.start}`
|
|
2919
3312
|
);
|
|
2920
3313
|
}
|
|
2921
|
-
result[key] = astValueToSzValue(prop.value, filename, bindings);
|
|
3314
|
+
result[key] = astValueToSzValue(prop.value, filename, bindings, branchPick);
|
|
2922
3315
|
}
|
|
2923
3316
|
return result;
|
|
2924
3317
|
}
|
|
@@ -3350,6 +3743,99 @@ function resolveObjectExpression(node, bindings) {
|
|
|
3350
3743
|
}
|
|
3351
3744
|
return null;
|
|
3352
3745
|
}
|
|
3746
|
+
function countOxcConditionals(node) {
|
|
3747
|
+
let count = 0;
|
|
3748
|
+
for (const propRaw of node.properties) {
|
|
3749
|
+
if (propRaw.type !== "Property") {
|
|
3750
|
+
continue;
|
|
3751
|
+
}
|
|
3752
|
+
const value = propRaw.value;
|
|
3753
|
+
if (value.type === "ConditionalExpression") {
|
|
3754
|
+
count++;
|
|
3755
|
+
} else if (value.type === "ObjectExpression") {
|
|
3756
|
+
count += countOxcConditionals(value);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
return count;
|
|
3760
|
+
}
|
|
3761
|
+
function firstOxcConditional(node) {
|
|
3762
|
+
for (const propRaw of node.properties) {
|
|
3763
|
+
if (propRaw.type !== "Property") {
|
|
3764
|
+
continue;
|
|
3765
|
+
}
|
|
3766
|
+
const value = propRaw.value;
|
|
3767
|
+
if (value.type === "ConditionalExpression") {
|
|
3768
|
+
return value;
|
|
3769
|
+
}
|
|
3770
|
+
if (value.type === "ObjectExpression") {
|
|
3771
|
+
const found = firstOxcConditional(value);
|
|
3772
|
+
if (found) {
|
|
3773
|
+
return found;
|
|
3774
|
+
}
|
|
3775
|
+
}
|
|
3776
|
+
}
|
|
3777
|
+
return null;
|
|
3778
|
+
}
|
|
3779
|
+
function buildNestedConditionalClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3780
|
+
let topLevel = 0;
|
|
3781
|
+
for (const propRaw of node.properties) {
|
|
3782
|
+
if (propRaw.type === "Property" && propRaw.value.type === "ConditionalExpression") {
|
|
3783
|
+
topLevel++;
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
const first = firstOxcConditional(node);
|
|
3787
|
+
if (topLevel !== 0 || countOxcConditionals(node) !== 1 || !first) {
|
|
3788
|
+
return null;
|
|
3789
|
+
}
|
|
3790
|
+
const condPropIndex = node.properties.findIndex(
|
|
3791
|
+
(prop) => prop.type === "Property" && prop.value.type === "ObjectExpression" && countOxcConditionals(prop.value) === 1
|
|
3792
|
+
);
|
|
3793
|
+
if (condPropIndex === -1) {
|
|
3794
|
+
return null;
|
|
3795
|
+
}
|
|
3796
|
+
const staticNode = {
|
|
3797
|
+
...node,
|
|
3798
|
+
properties: node.properties.filter((_, i) => i !== condPropIndex)
|
|
3799
|
+
};
|
|
3800
|
+
const condNode = {
|
|
3801
|
+
...node,
|
|
3802
|
+
properties: [node.properties[condPropIndex]]
|
|
3803
|
+
};
|
|
3804
|
+
const compile = (target, pick) => {
|
|
3805
|
+
try {
|
|
3806
|
+
return transformCore.transform(
|
|
3807
|
+
applyGlobalVarAliasesToSzObject(
|
|
3808
|
+
astObjectToSzObject(target, filename, bindings, pick),
|
|
3809
|
+
globalVarAliases,
|
|
3810
|
+
cssVariableMap
|
|
3811
|
+
)
|
|
3812
|
+
).className;
|
|
3813
|
+
} catch (err) {
|
|
3814
|
+
if (err instanceof OxcNotImplementedError) {
|
|
3815
|
+
return null;
|
|
3816
|
+
}
|
|
3817
|
+
throw err;
|
|
3818
|
+
}
|
|
3819
|
+
};
|
|
3820
|
+
const staticClasses = staticNode.properties.length > 0 ? compile(staticNode) : "";
|
|
3821
|
+
const consequent = compile(condNode, "consequent");
|
|
3822
|
+
const alternate = compile(condNode, "alternate");
|
|
3823
|
+
if (staticClasses === null || consequent === null || alternate === null) {
|
|
3824
|
+
return null;
|
|
3825
|
+
}
|
|
3826
|
+
for (const cls of `${staticClasses} ${consequent} ${alternate}`.split(/\s+/)) {
|
|
3827
|
+
if (cls) {
|
|
3828
|
+
classes.add(cls);
|
|
3829
|
+
}
|
|
3830
|
+
}
|
|
3831
|
+
const testSource = source.slice(first.test.start, first.test.end);
|
|
3832
|
+
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
3833
|
+
const ternary = `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
3834
|
+
if (staticClasses === "") {
|
|
3835
|
+
return ternary;
|
|
3836
|
+
}
|
|
3837
|
+
return `\`${staticClasses} \${${ternary}}\``;
|
|
3838
|
+
}
|
|
3353
3839
|
function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3354
3840
|
let conditionalSpread = null;
|
|
3355
3841
|
const otherProps = [];
|
|
@@ -4134,7 +4620,15 @@ function extractKeyName(key) {
|
|
|
4134
4620
|
}
|
|
4135
4621
|
return null;
|
|
4136
4622
|
}
|
|
4137
|
-
function astValueToSzValue(node, filename, bindings) {
|
|
4623
|
+
function astValueToSzValue(node, filename, bindings, branchPick) {
|
|
4624
|
+
if (branchPick && node.type === "ConditionalExpression") {
|
|
4625
|
+
return astValueToSzValue(
|
|
4626
|
+
node[branchPick],
|
|
4627
|
+
filename,
|
|
4628
|
+
bindings,
|
|
4629
|
+
branchPick
|
|
4630
|
+
);
|
|
4631
|
+
}
|
|
4138
4632
|
if (node.type === "Literal") {
|
|
4139
4633
|
const value = node.value;
|
|
4140
4634
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
@@ -4160,7 +4654,7 @@ function astValueToSzValue(node, filename, bindings) {
|
|
|
4160
4654
|
);
|
|
4161
4655
|
}
|
|
4162
4656
|
if (node.type === "ObjectExpression") {
|
|
4163
|
-
return astObjectToSzObject(node, filename, bindings);
|
|
4657
|
+
return astObjectToSzObject(node, filename, bindings, branchPick);
|
|
4164
4658
|
}
|
|
4165
4659
|
if (node.type === "Identifier" || node.type === "MemberExpression") {
|
|
4166
4660
|
throw new OxcNotImplementedError(
|
|
@@ -4431,6 +4925,7 @@ exports.mergeOptions = mergeOptions;
|
|
|
4431
4925
|
exports.parseManifest = parseManifest;
|
|
4432
4926
|
exports.scanGlobalVarUsages = scanGlobalVarUsages;
|
|
4433
4927
|
exports.serializeManifest = serializeManifest;
|
|
4928
|
+
exports.sortStrings = sortStrings;
|
|
4434
4929
|
exports.transformOxc = transformOxc;
|
|
4435
4930
|
exports.transformRust = transformRust;
|
|
4436
4931
|
exports.transformRustBatch = transformRustBatch;
|