@csszyx/compiler 0.10.9 → 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 +290 -11
- package/dist/index.d.cts +19 -1
- package/dist/index.d.mts +19 -1
- package/dist/index.mjs +290 -11
- package/package.json +2 -2
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
|
}
|
|
@@ -789,6 +854,9 @@ function transformSourceCode(source, filename, options) {
|
|
|
789
854
|
})
|
|
790
855
|
]
|
|
791
856
|
});
|
|
857
|
+
for (const c of szsPendingClasses) {
|
|
858
|
+
collectedClasses.add(c);
|
|
859
|
+
}
|
|
792
860
|
return {
|
|
793
861
|
code: result?.code || source,
|
|
794
862
|
transformed,
|
|
@@ -840,6 +908,31 @@ function parseStyleStringToObjectExpr(styleStr) {
|
|
|
840
908
|
}
|
|
841
909
|
return t__namespace.objectExpression(objProps);
|
|
842
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
|
+
}
|
|
843
936
|
function emptyClassToUndefined(node) {
|
|
844
937
|
return t__namespace.isStringLiteral(node) && node.value === "" ? t__namespace.identifier("undefined") : node;
|
|
845
938
|
}
|
|
@@ -967,22 +1060,44 @@ function tryHoistNestedConditional(node, getBinding) {
|
|
|
967
1060
|
if (topLevel !== 0 || nested !== 1 || test === null) {
|
|
968
1061
|
return null;
|
|
969
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;
|
|
970
1072
|
const consequent = tryStaticTransformNode(
|
|
971
|
-
cloneObjectPickingBranch(
|
|
1073
|
+
cloneObjectPickingBranch(condNode, "consequent"),
|
|
972
1074
|
getBinding
|
|
973
1075
|
);
|
|
974
1076
|
const alternate = tryStaticTransformNode(
|
|
975
|
-
cloneObjectPickingBranch(
|
|
1077
|
+
cloneObjectPickingBranch(condNode, "alternate"),
|
|
976
1078
|
getBinding
|
|
977
1079
|
);
|
|
978
|
-
if (!consequent || !alternate || !t__namespace.isStringLiteral(consequent) || !t__namespace.isStringLiteral(alternate)) {
|
|
1080
|
+
if (!consequent || !alternate || !t__namespace.isStringLiteral(consequent) || !t__namespace.isStringLiteral(alternate) || staticNode.properties.length > 0 && (!staticClasses || !t__namespace.isStringLiteral(staticClasses))) {
|
|
979
1081
|
return null;
|
|
980
1082
|
}
|
|
981
|
-
|
|
1083
|
+
const ternary = t__namespace.conditionalExpression(
|
|
982
1084
|
test,
|
|
983
1085
|
emptyClassToUndefined(consequent),
|
|
984
1086
|
emptyClassToUndefined(alternate)
|
|
985
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
|
+
);
|
|
986
1101
|
}
|
|
987
1102
|
function tryHoistConditionalSpread(node, getBinding) {
|
|
988
1103
|
let conditionalSpreadIdx = -1;
|
|
@@ -1392,6 +1507,18 @@ function collectFromExpr(node, classes) {
|
|
|
1392
1507
|
} else if (t__namespace.isConditionalExpression(node)) {
|
|
1393
1508
|
collectFromExpr(node.consequent, classes);
|
|
1394
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
|
+
}
|
|
1395
1522
|
}
|
|
1396
1523
|
}
|
|
1397
1524
|
function collectCandidatesFromBabelExpr(node, path, classes) {
|
|
@@ -2405,6 +2532,7 @@ class OxcNotImplementedError extends Error {
|
|
|
2405
2532
|
}
|
|
2406
2533
|
function transformOxc(source, filename, options) {
|
|
2407
2534
|
const classes = /* @__PURE__ */ new Set();
|
|
2535
|
+
const szsPendingClasses = [];
|
|
2408
2536
|
const rawClassNames = /* @__PURE__ */ new Set();
|
|
2409
2537
|
const diagnostics = [];
|
|
2410
2538
|
const recoveryTokens = /* @__PURE__ */ new Map();
|
|
@@ -2476,6 +2604,7 @@ function transformOxc(source, filename, options) {
|
|
|
2476
2604
|
const openingNode = node;
|
|
2477
2605
|
const attrs = openingNode.attributes ?? [];
|
|
2478
2606
|
const szAttrs = [];
|
|
2607
|
+
const szsAttrs = [];
|
|
2479
2608
|
let classNameAttr = null;
|
|
2480
2609
|
let styleAttr = null;
|
|
2481
2610
|
let szRecoverAttr = null;
|
|
@@ -2508,6 +2637,8 @@ function transformOxc(source, filename, options) {
|
|
|
2508
2637
|
const name = attr.name?.name;
|
|
2509
2638
|
if (name === "sz") {
|
|
2510
2639
|
szAttrs.push(attr);
|
|
2640
|
+
} else if (name === "szs") {
|
|
2641
|
+
szsAttrs.push(attr);
|
|
2511
2642
|
} else if (name === "className" || name === "class") {
|
|
2512
2643
|
classNameAttr = attr;
|
|
2513
2644
|
} else if (name === "style") {
|
|
@@ -2558,6 +2689,89 @@ function transformOxc(source, filename, options) {
|
|
|
2558
2689
|
}
|
|
2559
2690
|
}
|
|
2560
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
|
+
}
|
|
2561
2775
|
if (szAttrs.length === 0) {
|
|
2562
2776
|
applyHoistedStyleProps();
|
|
2563
2777
|
return;
|
|
@@ -2936,6 +3150,9 @@ function transformOxc(source, filename, options) {
|
|
|
2936
3150
|
}
|
|
2937
3151
|
transformed = true;
|
|
2938
3152
|
});
|
|
3153
|
+
for (const c of szsPendingClasses) {
|
|
3154
|
+
classes.add(c);
|
|
3155
|
+
}
|
|
2939
3156
|
return {
|
|
2940
3157
|
code: transformed ? edits.toString() : source,
|
|
2941
3158
|
transformed,
|
|
@@ -3005,6 +3222,49 @@ function buildRuntimeFallbackDiagnostic(expression, source) {
|
|
|
3005
3222
|
return `sz fallback at ${lineCol}: ${reason}.
|
|
3006
3223
|
Suggestion: ${suggestion}`;
|
|
3007
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
|
+
}
|
|
3008
3268
|
function extractElementName(nameNode) {
|
|
3009
3269
|
if (nameNode.type === "JSXIdentifier") {
|
|
3010
3270
|
return String(nameNode.name);
|
|
@@ -3527,11 +3787,25 @@ function buildNestedConditionalClassExpression(node, filename, bindings, source,
|
|
|
3527
3787
|
if (topLevel !== 0 || countOxcConditionals(node) !== 1 || !first) {
|
|
3528
3788
|
return null;
|
|
3529
3789
|
}
|
|
3530
|
-
const
|
|
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) => {
|
|
3531
3805
|
try {
|
|
3532
3806
|
return transformCore.transform(
|
|
3533
3807
|
applyGlobalVarAliasesToSzObject(
|
|
3534
|
-
astObjectToSzObject(
|
|
3808
|
+
astObjectToSzObject(target, filename, bindings, pick),
|
|
3535
3809
|
globalVarAliases,
|
|
3536
3810
|
cssVariableMap
|
|
3537
3811
|
)
|
|
@@ -3543,19 +3817,24 @@ function buildNestedConditionalClassExpression(node, filename, bindings, source,
|
|
|
3543
3817
|
throw err;
|
|
3544
3818
|
}
|
|
3545
3819
|
};
|
|
3546
|
-
const
|
|
3547
|
-
const
|
|
3548
|
-
|
|
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) {
|
|
3549
3824
|
return null;
|
|
3550
3825
|
}
|
|
3551
|
-
for (const cls of `${consequent} ${alternate}`.split(/\s+/)) {
|
|
3826
|
+
for (const cls of `${staticClasses} ${consequent} ${alternate}`.split(/\s+/)) {
|
|
3552
3827
|
if (cls) {
|
|
3553
3828
|
classes.add(cls);
|
|
3554
3829
|
}
|
|
3555
3830
|
}
|
|
3556
3831
|
const testSource = source.slice(first.test.start, first.test.end);
|
|
3557
3832
|
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
3558
|
-
|
|
3833
|
+
const ternary = `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
3834
|
+
if (staticClasses === "") {
|
|
3835
|
+
return ternary;
|
|
3836
|
+
}
|
|
3837
|
+
return `\`${staticClasses} \${${ternary}}\``;
|
|
3559
3838
|
}
|
|
3560
3839
|
function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3561
3840
|
let conditionalSpread = null;
|
package/dist/index.d.cts
CHANGED
|
@@ -13612,6 +13612,24 @@ type SzArrayElement = SzProps | false | null | undefined;
|
|
|
13612
13612
|
* ```
|
|
13613
13613
|
*/
|
|
13614
13614
|
type SzPropValue = string | SzProps | SzArrayElement[];
|
|
13615
|
+
/**
|
|
13616
|
+
* Value of the `szs` prop — a map of a component's slot names to sz values, so a
|
|
13617
|
+
* consumer styles the parts a compound component renders internally. The build
|
|
13618
|
+
* transform compiles each slot VALUE to its Tailwind class string (keeping the
|
|
13619
|
+
* key), safelists and mangles the classes exactly like `sz`, and the component
|
|
13620
|
+
* forwards `props.szs?.<slot>` into the matching child's `className`.
|
|
13621
|
+
*
|
|
13622
|
+
* Component authors declare their slot set so consumers get autocompletion and
|
|
13623
|
+
* typo checking:
|
|
13624
|
+
*
|
|
13625
|
+
* @example
|
|
13626
|
+
* ```tsx
|
|
13627
|
+
* type CardProps = { szs?: Szs<'header' | 'icon'> };
|
|
13628
|
+
* // consumer:
|
|
13629
|
+
* <Card szs={{ header: { bg: 'gray-100' }, icon: { color: 'red-500' } }} />
|
|
13630
|
+
* ```
|
|
13631
|
+
*/
|
|
13632
|
+
type Szs<Slots extends string = string> = Partial<Record<Slots, SzPropValue>>;
|
|
13615
13633
|
|
|
13616
13634
|
/**
|
|
13617
13635
|
* @csszyx/compiler - TypeScript compiler package for csszyx.
|
|
@@ -13662,4 +13680,4 @@ declare const DEFAULT_COMPILER_OPTIONS: Required<CompilerOptions>;
|
|
|
13662
13680
|
declare function mergeOptions(options?: Partial<CompilerOptions>): Required<CompilerOptions>;
|
|
13663
13681
|
|
|
13664
13682
|
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 };
|
|
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 };
|
|
13683
|
+
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, Szs, TableProps, TokenData, TokenMetadata, TransformOxcResult, TransformProps, TransformRustFile, TransformSourceCodeOptions, TransitionAnimationProps, TypographyProps, VariantModifiers };
|
package/dist/index.d.mts
CHANGED
|
@@ -13612,6 +13612,24 @@ type SzArrayElement = SzProps | false | null | undefined;
|
|
|
13612
13612
|
* ```
|
|
13613
13613
|
*/
|
|
13614
13614
|
type SzPropValue = string | SzProps | SzArrayElement[];
|
|
13615
|
+
/**
|
|
13616
|
+
* Value of the `szs` prop — a map of a component's slot names to sz values, so a
|
|
13617
|
+
* consumer styles the parts a compound component renders internally. The build
|
|
13618
|
+
* transform compiles each slot VALUE to its Tailwind class string (keeping the
|
|
13619
|
+
* key), safelists and mangles the classes exactly like `sz`, and the component
|
|
13620
|
+
* forwards `props.szs?.<slot>` into the matching child's `className`.
|
|
13621
|
+
*
|
|
13622
|
+
* Component authors declare their slot set so consumers get autocompletion and
|
|
13623
|
+
* typo checking:
|
|
13624
|
+
*
|
|
13625
|
+
* @example
|
|
13626
|
+
* ```tsx
|
|
13627
|
+
* type CardProps = { szs?: Szs<'header' | 'icon'> };
|
|
13628
|
+
* // consumer:
|
|
13629
|
+
* <Card szs={{ header: { bg: 'gray-100' }, icon: { color: 'red-500' } }} />
|
|
13630
|
+
* ```
|
|
13631
|
+
*/
|
|
13632
|
+
type Szs<Slots extends string = string> = Partial<Record<Slots, SzPropValue>>;
|
|
13615
13633
|
|
|
13616
13634
|
/**
|
|
13617
13635
|
* @csszyx/compiler - TypeScript compiler package for csszyx.
|
|
@@ -13662,4 +13680,4 @@ declare const DEFAULT_COMPILER_OPTIONS: Required<CompilerOptions>;
|
|
|
13662
13680
|
declare function mergeOptions(options?: Partial<CompilerOptions>): Required<CompilerOptions>;
|
|
13663
13681
|
|
|
13664
13682
|
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 };
|
|
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 };
|
|
13683
|
+
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, Szs, TableProps, TokenData, TokenMetadata, TransformOxcResult, TransformProps, TransformRustFile, TransformSourceCodeOptions, TransitionAnimationProps, TypographyProps, VariantModifiers };
|
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
|
}
|
|
@@ -770,6 +835,9 @@ function transformSourceCode(source, filename, options) {
|
|
|
770
835
|
})
|
|
771
836
|
]
|
|
772
837
|
});
|
|
838
|
+
for (const c of szsPendingClasses) {
|
|
839
|
+
collectedClasses.add(c);
|
|
840
|
+
}
|
|
773
841
|
return {
|
|
774
842
|
code: result?.code || source,
|
|
775
843
|
transformed,
|
|
@@ -821,6 +889,31 @@ function parseStyleStringToObjectExpr(styleStr) {
|
|
|
821
889
|
}
|
|
822
890
|
return t.objectExpression(objProps);
|
|
823
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
|
+
}
|
|
824
917
|
function emptyClassToUndefined(node) {
|
|
825
918
|
return t.isStringLiteral(node) && node.value === "" ? t.identifier("undefined") : node;
|
|
826
919
|
}
|
|
@@ -948,22 +1041,44 @@ function tryHoistNestedConditional(node, getBinding) {
|
|
|
948
1041
|
if (topLevel !== 0 || nested !== 1 || test === null) {
|
|
949
1042
|
return null;
|
|
950
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;
|
|
951
1053
|
const consequent = tryStaticTransformNode(
|
|
952
|
-
cloneObjectPickingBranch(
|
|
1054
|
+
cloneObjectPickingBranch(condNode, "consequent"),
|
|
953
1055
|
getBinding
|
|
954
1056
|
);
|
|
955
1057
|
const alternate = tryStaticTransformNode(
|
|
956
|
-
cloneObjectPickingBranch(
|
|
1058
|
+
cloneObjectPickingBranch(condNode, "alternate"),
|
|
957
1059
|
getBinding
|
|
958
1060
|
);
|
|
959
|
-
if (!consequent || !alternate || !t.isStringLiteral(consequent) || !t.isStringLiteral(alternate)) {
|
|
1061
|
+
if (!consequent || !alternate || !t.isStringLiteral(consequent) || !t.isStringLiteral(alternate) || staticNode.properties.length > 0 && (!staticClasses || !t.isStringLiteral(staticClasses))) {
|
|
960
1062
|
return null;
|
|
961
1063
|
}
|
|
962
|
-
|
|
1064
|
+
const ternary = t.conditionalExpression(
|
|
963
1065
|
test,
|
|
964
1066
|
emptyClassToUndefined(consequent),
|
|
965
1067
|
emptyClassToUndefined(alternate)
|
|
966
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
|
+
);
|
|
967
1082
|
}
|
|
968
1083
|
function tryHoistConditionalSpread(node, getBinding) {
|
|
969
1084
|
let conditionalSpreadIdx = -1;
|
|
@@ -1373,6 +1488,18 @@ function collectFromExpr(node, classes) {
|
|
|
1373
1488
|
} else if (t.isConditionalExpression(node)) {
|
|
1374
1489
|
collectFromExpr(node.consequent, classes);
|
|
1375
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
|
+
}
|
|
1376
1503
|
}
|
|
1377
1504
|
}
|
|
1378
1505
|
function collectCandidatesFromBabelExpr(node, path, classes) {
|
|
@@ -2386,6 +2513,7 @@ class OxcNotImplementedError extends Error {
|
|
|
2386
2513
|
}
|
|
2387
2514
|
function transformOxc(source, filename, options) {
|
|
2388
2515
|
const classes = /* @__PURE__ */ new Set();
|
|
2516
|
+
const szsPendingClasses = [];
|
|
2389
2517
|
const rawClassNames = /* @__PURE__ */ new Set();
|
|
2390
2518
|
const diagnostics = [];
|
|
2391
2519
|
const recoveryTokens = /* @__PURE__ */ new Map();
|
|
@@ -2457,6 +2585,7 @@ function transformOxc(source, filename, options) {
|
|
|
2457
2585
|
const openingNode = node;
|
|
2458
2586
|
const attrs = openingNode.attributes ?? [];
|
|
2459
2587
|
const szAttrs = [];
|
|
2588
|
+
const szsAttrs = [];
|
|
2460
2589
|
let classNameAttr = null;
|
|
2461
2590
|
let styleAttr = null;
|
|
2462
2591
|
let szRecoverAttr = null;
|
|
@@ -2489,6 +2618,8 @@ function transformOxc(source, filename, options) {
|
|
|
2489
2618
|
const name = attr.name?.name;
|
|
2490
2619
|
if (name === "sz") {
|
|
2491
2620
|
szAttrs.push(attr);
|
|
2621
|
+
} else if (name === "szs") {
|
|
2622
|
+
szsAttrs.push(attr);
|
|
2492
2623
|
} else if (name === "className" || name === "class") {
|
|
2493
2624
|
classNameAttr = attr;
|
|
2494
2625
|
} else if (name === "style") {
|
|
@@ -2539,6 +2670,89 @@ function transformOxc(source, filename, options) {
|
|
|
2539
2670
|
}
|
|
2540
2671
|
}
|
|
2541
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
|
+
}
|
|
2542
2756
|
if (szAttrs.length === 0) {
|
|
2543
2757
|
applyHoistedStyleProps();
|
|
2544
2758
|
return;
|
|
@@ -2917,6 +3131,9 @@ function transformOxc(source, filename, options) {
|
|
|
2917
3131
|
}
|
|
2918
3132
|
transformed = true;
|
|
2919
3133
|
});
|
|
3134
|
+
for (const c of szsPendingClasses) {
|
|
3135
|
+
classes.add(c);
|
|
3136
|
+
}
|
|
2920
3137
|
return {
|
|
2921
3138
|
code: transformed ? edits.toString() : source,
|
|
2922
3139
|
transformed,
|
|
@@ -2986,6 +3203,49 @@ function buildRuntimeFallbackDiagnostic(expression, source) {
|
|
|
2986
3203
|
return `sz fallback at ${lineCol}: ${reason}.
|
|
2987
3204
|
Suggestion: ${suggestion}`;
|
|
2988
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
|
+
}
|
|
2989
3249
|
function extractElementName(nameNode) {
|
|
2990
3250
|
if (nameNode.type === "JSXIdentifier") {
|
|
2991
3251
|
return String(nameNode.name);
|
|
@@ -3508,11 +3768,25 @@ function buildNestedConditionalClassExpression(node, filename, bindings, source,
|
|
|
3508
3768
|
if (topLevel !== 0 || countOxcConditionals(node) !== 1 || !first) {
|
|
3509
3769
|
return null;
|
|
3510
3770
|
}
|
|
3511
|
-
const
|
|
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) => {
|
|
3512
3786
|
try {
|
|
3513
3787
|
return transform(
|
|
3514
3788
|
applyGlobalVarAliasesToSzObject(
|
|
3515
|
-
astObjectToSzObject(
|
|
3789
|
+
astObjectToSzObject(target, filename, bindings, pick),
|
|
3516
3790
|
globalVarAliases,
|
|
3517
3791
|
cssVariableMap
|
|
3518
3792
|
)
|
|
@@ -3524,19 +3798,24 @@ function buildNestedConditionalClassExpression(node, filename, bindings, source,
|
|
|
3524
3798
|
throw err;
|
|
3525
3799
|
}
|
|
3526
3800
|
};
|
|
3527
|
-
const
|
|
3528
|
-
const
|
|
3529
|
-
|
|
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) {
|
|
3530
3805
|
return null;
|
|
3531
3806
|
}
|
|
3532
|
-
for (const cls of `${consequent} ${alternate}`.split(/\s+/)) {
|
|
3807
|
+
for (const cls of `${staticClasses} ${consequent} ${alternate}`.split(/\s+/)) {
|
|
3533
3808
|
if (cls) {
|
|
3534
3809
|
classes.add(cls);
|
|
3535
3810
|
}
|
|
3536
3811
|
}
|
|
3537
3812
|
const testSource = source.slice(first.test.start, first.test.end);
|
|
3538
3813
|
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
3539
|
-
|
|
3814
|
+
const ternary = `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
3815
|
+
if (staticClasses === "") {
|
|
3816
|
+
return ternary;
|
|
3817
|
+
}
|
|
3818
|
+
return `\`${staticClasses} \${${ternary}}\``;
|
|
3540
3819
|
}
|
|
3541
3820
|
function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3542
3821
|
let conditionalSpread = null;
|
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",
|