@csszyx/compiler 0.10.9 → 0.10.11
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 +345 -34
- package/dist/index.d.cts +19 -1
- package/dist/index.d.mts +19 -1
- package/dist/index.mjs +346 -35
- package/dist/shared/{compiler.mibv6qPF.cjs → compiler.dkTeNO_S.cjs} +12 -0
- package/dist/shared/{compiler.CghwJ6p5.mjs → compiler.zZfo8y65.mjs} +12 -0
- package/dist/transform-core.cjs +1 -1
- package/dist/transform-core.mjs +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const core = require('@csszyx/core');
|
|
4
|
-
const transformCore = require('./shared/compiler.
|
|
4
|
+
const transformCore = require('./shared/compiler.dkTeNO_S.cjs');
|
|
5
5
|
const oxcParser = require('oxc-parser');
|
|
6
6
|
const t = require('@babel/types');
|
|
7
7
|
const node_crypto = require('node:crypto');
|
|
@@ -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
|
}
|
|
@@ -724,22 +789,23 @@ function transformSourceCode(source, filename, options) {
|
|
|
724
789
|
transformed = true;
|
|
725
790
|
}
|
|
726
791
|
},
|
|
727
|
-
// ── dynamic() literal extraction
|
|
728
|
-
// Detects `dynamic({...})`
|
|
729
|
-
// with statically-analyzable arguments
|
|
730
|
-
// class tokens to collectedClasses so
|
|
731
|
-
// includes them in csszyx-classes.html
|
|
732
|
-
//
|
|
733
|
-
// without
|
|
792
|
+
// ── dynamic() / szr() literal extraction ─────────────────────────
|
|
793
|
+
// Detects `dynamic({...})` / `szr({...})` and their
|
|
794
|
+
// `(CONST_IDENTIFIER)` forms with statically-analyzable arguments
|
|
795
|
+
// and adds the resulting class tokens to collectedClasses so
|
|
796
|
+
// prescanAndWriteClasses() includes them in csszyx-classes.html
|
|
797
|
+
// for Tailwind to scan. A bare static `szr({...})` type-checks and
|
|
798
|
+
// resolves at runtime, so without this its classes were silently
|
|
799
|
+
// dead under Tailwind `source(none)`.
|
|
734
800
|
CallExpression(path) {
|
|
735
801
|
const callee = path.node.callee;
|
|
736
|
-
if (!t__namespace.isIdentifier(callee) || callee.name !== "dynamic") {
|
|
802
|
+
if (!t__namespace.isIdentifier(callee) || callee.name !== "dynamic" && callee.name !== "szr") {
|
|
737
803
|
return;
|
|
738
804
|
}
|
|
739
805
|
if (path.node.arguments.length === 0) {
|
|
740
806
|
return;
|
|
741
807
|
}
|
|
742
|
-
const arg = path.node.arguments[0];
|
|
808
|
+
const arg = unwrapTsExpression(path.node.arguments[0]);
|
|
743
809
|
if (t__namespace.isObjectExpression(arg)) {
|
|
744
810
|
const staticObj = evaluateStaticObject(arg);
|
|
745
811
|
if (!staticObj) {
|
|
@@ -753,10 +819,7 @@ function transformSourceCode(source, filename, options) {
|
|
|
753
819
|
}
|
|
754
820
|
return;
|
|
755
821
|
}
|
|
756
|
-
|
|
757
|
-
while (t__namespace.isTSAsExpression(argExpr) || t__namespace.isTSSatisfiesExpression(argExpr)) {
|
|
758
|
-
argExpr = argExpr.expression;
|
|
759
|
-
}
|
|
822
|
+
const argExpr = arg;
|
|
760
823
|
if (t__namespace.isIdentifier(argExpr)) {
|
|
761
824
|
const binding = path.scope.getBinding(argExpr.name);
|
|
762
825
|
if (!binding) {
|
|
@@ -789,6 +852,9 @@ function transformSourceCode(source, filename, options) {
|
|
|
789
852
|
})
|
|
790
853
|
]
|
|
791
854
|
});
|
|
855
|
+
for (const c of szsPendingClasses) {
|
|
856
|
+
collectedClasses.add(c);
|
|
857
|
+
}
|
|
792
858
|
return {
|
|
793
859
|
code: result?.code || source,
|
|
794
860
|
transformed,
|
|
@@ -840,6 +906,31 @@ function parseStyleStringToObjectExpr(styleStr) {
|
|
|
840
906
|
}
|
|
841
907
|
return t__namespace.objectExpression(objProps);
|
|
842
908
|
}
|
|
909
|
+
function isHostElementName(name) {
|
|
910
|
+
return t__namespace.isJSXIdentifier(name) && /^[a-z]/.test(name.name);
|
|
911
|
+
}
|
|
912
|
+
function szsUnsupportedMessage$1(filename) {
|
|
913
|
+
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.`;
|
|
914
|
+
}
|
|
915
|
+
function isPureLiteralSzValue$1(node) {
|
|
916
|
+
if (t__namespace.isStringLiteral(node) || t__namespace.isNumericLiteral(node) || t__namespace.isBooleanLiteral(node)) {
|
|
917
|
+
return true;
|
|
918
|
+
}
|
|
919
|
+
if (t__namespace.isUnaryExpression(node) && node.operator === "-" && t__namespace.isNumericLiteral(node.argument)) {
|
|
920
|
+
return true;
|
|
921
|
+
}
|
|
922
|
+
if (t__namespace.isObjectExpression(node)) {
|
|
923
|
+
return node.properties.every(
|
|
924
|
+
(prop) => t__namespace.isObjectProperty(prop) && !prop.computed && t__namespace.isIdentifier(prop.key) && isPureLiteralSzValue$1(prop.value)
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
return false;
|
|
928
|
+
}
|
|
929
|
+
function isValidSzsSlotMap$1(slotMap) {
|
|
930
|
+
return slotMap.properties.every(
|
|
931
|
+
(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))
|
|
932
|
+
);
|
|
933
|
+
}
|
|
843
934
|
function emptyClassToUndefined(node) {
|
|
844
935
|
return t__namespace.isStringLiteral(node) && node.value === "" ? t__namespace.identifier("undefined") : node;
|
|
845
936
|
}
|
|
@@ -967,22 +1058,44 @@ function tryHoistNestedConditional(node, getBinding) {
|
|
|
967
1058
|
if (topLevel !== 0 || nested !== 1 || test === null) {
|
|
968
1059
|
return null;
|
|
969
1060
|
}
|
|
1061
|
+
const condPropIndex = node.properties.findIndex(
|
|
1062
|
+
(prop) => t__namespace.isObjectProperty(prop) && t__namespace.isObjectExpression(prop.value) && countAllConditionals(prop.value) === 1
|
|
1063
|
+
);
|
|
1064
|
+
if (condPropIndex === -1) {
|
|
1065
|
+
return null;
|
|
1066
|
+
}
|
|
1067
|
+
const staticNode = t__namespace.objectExpression(node.properties.filter((_, i) => i !== condPropIndex));
|
|
1068
|
+
const condNode = t__namespace.objectExpression([node.properties[condPropIndex]]);
|
|
1069
|
+
const staticClasses = staticNode.properties.length > 0 ? tryStaticTransformNode(staticNode, getBinding) : null;
|
|
970
1070
|
const consequent = tryStaticTransformNode(
|
|
971
|
-
cloneObjectPickingBranch(
|
|
1071
|
+
cloneObjectPickingBranch(condNode, "consequent"),
|
|
972
1072
|
getBinding
|
|
973
1073
|
);
|
|
974
1074
|
const alternate = tryStaticTransformNode(
|
|
975
|
-
cloneObjectPickingBranch(
|
|
1075
|
+
cloneObjectPickingBranch(condNode, "alternate"),
|
|
976
1076
|
getBinding
|
|
977
1077
|
);
|
|
978
|
-
if (!consequent || !alternate || !t__namespace.isStringLiteral(consequent) || !t__namespace.isStringLiteral(alternate)) {
|
|
1078
|
+
if (!consequent || !alternate || !t__namespace.isStringLiteral(consequent) || !t__namespace.isStringLiteral(alternate) || staticNode.properties.length > 0 && (!staticClasses || !t__namespace.isStringLiteral(staticClasses))) {
|
|
979
1079
|
return null;
|
|
980
1080
|
}
|
|
981
|
-
|
|
1081
|
+
const ternary = t__namespace.conditionalExpression(
|
|
982
1082
|
test,
|
|
983
1083
|
emptyClassToUndefined(consequent),
|
|
984
1084
|
emptyClassToUndefined(alternate)
|
|
985
1085
|
);
|
|
1086
|
+
if (!staticClasses || !t__namespace.isStringLiteral(staticClasses) || staticClasses.value === "") {
|
|
1087
|
+
return ternary;
|
|
1088
|
+
}
|
|
1089
|
+
return t__namespace.templateLiteral(
|
|
1090
|
+
[
|
|
1091
|
+
t__namespace.templateElement(
|
|
1092
|
+
{ raw: `${staticClasses.value} `, cooked: `${staticClasses.value} ` },
|
|
1093
|
+
false
|
|
1094
|
+
),
|
|
1095
|
+
t__namespace.templateElement({ raw: "", cooked: "" }, true)
|
|
1096
|
+
],
|
|
1097
|
+
[ternary]
|
|
1098
|
+
);
|
|
986
1099
|
}
|
|
987
1100
|
function tryHoistConditionalSpread(node, getBinding) {
|
|
988
1101
|
let conditionalSpreadIdx = -1;
|
|
@@ -1035,16 +1148,27 @@ function readStaticConfigObject(configExpr, key, scope) {
|
|
|
1035
1148
|
}
|
|
1036
1149
|
return null;
|
|
1037
1150
|
}
|
|
1151
|
+
function unwrapTsExpression(node) {
|
|
1152
|
+
let current = node;
|
|
1153
|
+
while (t__namespace.isTSSatisfiesExpression(current) || t__namespace.isTSAsExpression(current) || t__namespace.isTSNonNullExpression(current) || t__namespace.isParenthesizedExpression(current)) {
|
|
1154
|
+
current = current.expression;
|
|
1155
|
+
}
|
|
1156
|
+
return current;
|
|
1157
|
+
}
|
|
1038
1158
|
function resolveToConstObjectExpression(node, scope) {
|
|
1039
|
-
|
|
1040
|
-
|
|
1159
|
+
const unwrapped = unwrapTsExpression(node);
|
|
1160
|
+
if (t__namespace.isObjectExpression(unwrapped)) {
|
|
1161
|
+
return unwrapped;
|
|
1041
1162
|
}
|
|
1042
|
-
if (t__namespace.isIdentifier(
|
|
1043
|
-
const binding = scope.getBinding(
|
|
1163
|
+
if (t__namespace.isIdentifier(unwrapped)) {
|
|
1164
|
+
const binding = scope.getBinding(unwrapped.name);
|
|
1044
1165
|
if (binding?.kind === "const" && binding.constant) {
|
|
1045
1166
|
const declNode = binding.path.node;
|
|
1046
|
-
if (t__namespace.isVariableDeclarator(declNode)
|
|
1047
|
-
|
|
1167
|
+
if (t__namespace.isVariableDeclarator(declNode)) {
|
|
1168
|
+
const init = unwrapTsExpression(declNode.init);
|
|
1169
|
+
if (t__namespace.isObjectExpression(init)) {
|
|
1170
|
+
return init;
|
|
1171
|
+
}
|
|
1048
1172
|
}
|
|
1049
1173
|
}
|
|
1050
1174
|
}
|
|
@@ -1069,7 +1193,7 @@ function evaluateStaticObject(node) {
|
|
|
1069
1193
|
} else {
|
|
1070
1194
|
return null;
|
|
1071
1195
|
}
|
|
1072
|
-
const value = prop.value;
|
|
1196
|
+
const value = unwrapTsExpression(prop.value);
|
|
1073
1197
|
if (t__namespace.isStringLiteral(value)) {
|
|
1074
1198
|
result[key] = value.value;
|
|
1075
1199
|
} else if (t__namespace.isNumericLiteral(value)) {
|
|
@@ -1392,6 +1516,18 @@ function collectFromExpr(node, classes) {
|
|
|
1392
1516
|
} else if (t__namespace.isConditionalExpression(node)) {
|
|
1393
1517
|
collectFromExpr(node.consequent, classes);
|
|
1394
1518
|
collectFromExpr(node.alternate, classes);
|
|
1519
|
+
} else if (t__namespace.isTemplateLiteral(node)) {
|
|
1520
|
+
for (let i = 0; i < node.quasis.length; i++) {
|
|
1521
|
+
for (const c of (node.quasis[i].value.cooked ?? "").split(/\s+/)) {
|
|
1522
|
+
if (c) {
|
|
1523
|
+
classes.add(c);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
const expr = node.expressions[i];
|
|
1527
|
+
if (expr && t__namespace.isExpression(expr)) {
|
|
1528
|
+
collectFromExpr(expr, classes);
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1395
1531
|
}
|
|
1396
1532
|
}
|
|
1397
1533
|
function collectCandidatesFromBabelExpr(node, path, classes) {
|
|
@@ -2405,6 +2541,7 @@ class OxcNotImplementedError extends Error {
|
|
|
2405
2541
|
}
|
|
2406
2542
|
function transformOxc(source, filename, options) {
|
|
2407
2543
|
const classes = /* @__PURE__ */ new Set();
|
|
2544
|
+
const szsPendingClasses = [];
|
|
2408
2545
|
const rawClassNames = /* @__PURE__ */ new Set();
|
|
2409
2546
|
const diagnostics = [];
|
|
2410
2547
|
const recoveryTokens = /* @__PURE__ */ new Map();
|
|
@@ -2427,7 +2564,7 @@ function transformOxc(source, filename, options) {
|
|
|
2427
2564
|
const effectiveFilename = filename ?? "file.tsx";
|
|
2428
2565
|
transformCore.setSzWarnLocation(void 0);
|
|
2429
2566
|
const astBudget = options?.astBudget ?? AST_BUDGET;
|
|
2430
|
-
const parsed = oxcParser.parseSync(effectiveFilename, source);
|
|
2567
|
+
const parsed = /\.(?:js|mjs|cjs)$/.test(effectiveFilename) ? oxcParser.parseSync(effectiveFilename, source, { lang: "jsx" }) : oxcParser.parseSync(effectiveFilename, source);
|
|
2431
2568
|
if (parsed.errors.length > 0) {
|
|
2432
2569
|
throw new Error(
|
|
2433
2570
|
`oxc-parser errors in ${effectiveFilename}: ` + parsed.errors.map((e) => e.message).join("; ")
|
|
@@ -2476,6 +2613,7 @@ function transformOxc(source, filename, options) {
|
|
|
2476
2613
|
const openingNode = node;
|
|
2477
2614
|
const attrs = openingNode.attributes ?? [];
|
|
2478
2615
|
const szAttrs = [];
|
|
2616
|
+
const szsAttrs = [];
|
|
2479
2617
|
let classNameAttr = null;
|
|
2480
2618
|
let styleAttr = null;
|
|
2481
2619
|
let szRecoverAttr = null;
|
|
@@ -2508,6 +2646,8 @@ function transformOxc(source, filename, options) {
|
|
|
2508
2646
|
const name = attr.name?.name;
|
|
2509
2647
|
if (name === "sz") {
|
|
2510
2648
|
szAttrs.push(attr);
|
|
2649
|
+
} else if (name === "szs") {
|
|
2650
|
+
szsAttrs.push(attr);
|
|
2511
2651
|
} else if (name === "className" || name === "class") {
|
|
2512
2652
|
classNameAttr = attr;
|
|
2513
2653
|
} else if (name === "style") {
|
|
@@ -2558,6 +2698,89 @@ function transformOxc(source, filename, options) {
|
|
|
2558
2698
|
}
|
|
2559
2699
|
}
|
|
2560
2700
|
}
|
|
2701
|
+
for (const szsAttr of szsAttrs) {
|
|
2702
|
+
if (isHostOpeningElementName(openingNode.name)) {
|
|
2703
|
+
diagnostics.push(
|
|
2704
|
+
`[csszyx] szs at ${effectiveFilename}: szs has no effect on a host element \u2014 it maps slot names of a custom component. Attribute left unchanged.`
|
|
2705
|
+
);
|
|
2706
|
+
continue;
|
|
2707
|
+
}
|
|
2708
|
+
const szsValue = szsAttr.value;
|
|
2709
|
+
const szsExpression = szsValue && szsValue.type === "JSXExpressionContainer" ? szsValue.expression : null;
|
|
2710
|
+
if (!szsExpression || szsExpression.type !== "ObjectExpression") {
|
|
2711
|
+
diagnostics.push(szsUnsupportedMessage(effectiveFilename));
|
|
2712
|
+
continue;
|
|
2713
|
+
}
|
|
2714
|
+
const slotMap = szsExpression;
|
|
2715
|
+
if (!isValidSzsSlotMap(slotMap)) {
|
|
2716
|
+
diagnostics.push(szsUnsupportedMessage(effectiveFilename));
|
|
2717
|
+
continue;
|
|
2718
|
+
}
|
|
2719
|
+
const { line: szsWarnLine } = offsetToLineColumn(source, szsAttr.start);
|
|
2720
|
+
transformCore.setSzWarnLocation(
|
|
2721
|
+
transformCore.formatSzWarnLocation(effectiveFilename, szsWarnLine, options?.rootDir)
|
|
2722
|
+
);
|
|
2723
|
+
const slotEntries = [];
|
|
2724
|
+
let anyCompiled = false;
|
|
2725
|
+
let slotFailed = false;
|
|
2726
|
+
for (const propRaw of slotMap.properties) {
|
|
2727
|
+
const prop = propRaw;
|
|
2728
|
+
const keyText = source.slice(prop.key.start, prop.key.end);
|
|
2729
|
+
const propValue = prop.value;
|
|
2730
|
+
const literal = propValue.type === "Literal" ? propValue.value : null;
|
|
2731
|
+
if (typeof literal === "string") {
|
|
2732
|
+
slotEntries.push({
|
|
2733
|
+
keyText,
|
|
2734
|
+
classNames: literal,
|
|
2735
|
+
text: source.slice(propValue.start, propValue.end)
|
|
2736
|
+
});
|
|
2737
|
+
continue;
|
|
2738
|
+
}
|
|
2739
|
+
try {
|
|
2740
|
+
const slotObject = astObjectToSzObject(
|
|
2741
|
+
propValue,
|
|
2742
|
+
effectiveFilename,
|
|
2743
|
+
objectBindings
|
|
2744
|
+
);
|
|
2745
|
+
const compiled = transformCore.transform(
|
|
2746
|
+
applyGlobalVarAliasesToSzObject(
|
|
2747
|
+
slotObject,
|
|
2748
|
+
globalVarAliases,
|
|
2749
|
+
cssVariableMap
|
|
2750
|
+
)
|
|
2751
|
+
).className;
|
|
2752
|
+
slotEntries.push({
|
|
2753
|
+
keyText,
|
|
2754
|
+
classNames: compiled,
|
|
2755
|
+
text: JSON.stringify(compiled)
|
|
2756
|
+
});
|
|
2757
|
+
anyCompiled = true;
|
|
2758
|
+
} catch (err) {
|
|
2759
|
+
if (err instanceof OxcNotImplementedError) {
|
|
2760
|
+
slotFailed = true;
|
|
2761
|
+
break;
|
|
2762
|
+
}
|
|
2763
|
+
throw err;
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
transformCore.setSzWarnLocation(void 0);
|
|
2767
|
+
if (slotFailed) {
|
|
2768
|
+
diagnostics.push(szsUnsupportedMessage(effectiveFilename));
|
|
2769
|
+
continue;
|
|
2770
|
+
}
|
|
2771
|
+
if (anyCompiled) {
|
|
2772
|
+
const body = slotEntries.map((entry) => `${entry.keyText}: ${entry.text}`).join(", ");
|
|
2773
|
+
edits.overwrite(szsAttr.start, szsAttr.end, `szs={{ ${body} }}`);
|
|
2774
|
+
transformed = true;
|
|
2775
|
+
}
|
|
2776
|
+
for (const entry of slotEntries) {
|
|
2777
|
+
for (const c of entry.classNames.split(/\s+/)) {
|
|
2778
|
+
if (c) {
|
|
2779
|
+
szsPendingClasses.push(c);
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2783
|
+
}
|
|
2561
2784
|
if (szAttrs.length === 0) {
|
|
2562
2785
|
applyHoistedStyleProps();
|
|
2563
2786
|
return;
|
|
@@ -2918,6 +3141,24 @@ function transformOxc(source, filename, options) {
|
|
|
2918
3141
|
];
|
|
2919
3142
|
const mergedAttr = mergedClasses.length === 0 ? "className={undefined}" : `className="${mergedClasses.join(" ")}"`;
|
|
2920
3143
|
if (classNameAttr) {
|
|
3144
|
+
const classNameValue = classNameAttr.value;
|
|
3145
|
+
if (existingRaw === null && classNameValue && classNameValue.type === "JSXExpressionContainer") {
|
|
3146
|
+
const exprNode = classNameValue.expression;
|
|
3147
|
+
const exprSource = source.slice(exprNode.start, exprNode.end);
|
|
3148
|
+
edits.overwrite(
|
|
3149
|
+
classNameAttr.start,
|
|
3150
|
+
classNameAttr.end,
|
|
3151
|
+
`className={_szMerge(${exprSource}, ${JSON.stringify(szDerived.join(" "))})}`
|
|
3152
|
+
);
|
|
3153
|
+
for (const szAttr of szAttrs) {
|
|
3154
|
+
const deleteStart = whitespaceStart(source, szAttr.start);
|
|
3155
|
+
edits.remove(deleteStart, szAttr.end);
|
|
3156
|
+
}
|
|
3157
|
+
usesRuntime = true;
|
|
3158
|
+
usesMerge = true;
|
|
3159
|
+
transformed = true;
|
|
3160
|
+
return;
|
|
3161
|
+
}
|
|
2921
3162
|
edits.overwrite(classNameAttr.start, classNameAttr.end, mergedAttr);
|
|
2922
3163
|
for (const szAttr of szAttrs) {
|
|
2923
3164
|
const deleteStart = whitespaceStart(source, szAttr.start);
|
|
@@ -2936,6 +3177,9 @@ function transformOxc(source, filename, options) {
|
|
|
2936
3177
|
}
|
|
2937
3178
|
transformed = true;
|
|
2938
3179
|
});
|
|
3180
|
+
for (const c of szsPendingClasses) {
|
|
3181
|
+
classes.add(c);
|
|
3182
|
+
}
|
|
2939
3183
|
return {
|
|
2940
3184
|
code: transformed ? edits.toString() : source,
|
|
2941
3185
|
transformed,
|
|
@@ -3005,6 +3249,49 @@ function buildRuntimeFallbackDiagnostic(expression, source) {
|
|
|
3005
3249
|
return `sz fallback at ${lineCol}: ${reason}.
|
|
3006
3250
|
Suggestion: ${suggestion}`;
|
|
3007
3251
|
}
|
|
3252
|
+
function isHostOpeningElementName(nameNode) {
|
|
3253
|
+
return nameNode.type === "JSXIdentifier" && /^[a-z]/.test(String(nameNode.name));
|
|
3254
|
+
}
|
|
3255
|
+
function szsUnsupportedMessage(filename) {
|
|
3256
|
+
return `[csszyx] szs at ${filename}: every slot must be an identifier key with a static object literal (or class string) value. Attribute left unchanged.`;
|
|
3257
|
+
}
|
|
3258
|
+
function isPureLiteralSzValue(node) {
|
|
3259
|
+
if (node.type === "Literal") {
|
|
3260
|
+
const value = node.value;
|
|
3261
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
3262
|
+
}
|
|
3263
|
+
if (node.type === "UnaryExpression") {
|
|
3264
|
+
const unary = node;
|
|
3265
|
+
return unary.operator === "-" && unary.argument.type === "Literal" && typeof unary.argument.value === "number";
|
|
3266
|
+
}
|
|
3267
|
+
if (node.type === "ObjectExpression") {
|
|
3268
|
+
const properties = node.properties;
|
|
3269
|
+
return properties.every((propRaw) => {
|
|
3270
|
+
if (propRaw.type !== "Property") {
|
|
3271
|
+
return false;
|
|
3272
|
+
}
|
|
3273
|
+
const prop = propRaw;
|
|
3274
|
+
return !prop.computed && prop.key.type === "Identifier" && isPureLiteralSzValue(prop.value);
|
|
3275
|
+
});
|
|
3276
|
+
}
|
|
3277
|
+
return false;
|
|
3278
|
+
}
|
|
3279
|
+
function isValidSzsSlotMap(slotMap) {
|
|
3280
|
+
return slotMap.properties.every((propRaw) => {
|
|
3281
|
+
if (propRaw.type !== "Property") {
|
|
3282
|
+
return false;
|
|
3283
|
+
}
|
|
3284
|
+
const prop = propRaw;
|
|
3285
|
+
if (prop.computed || prop.key.type !== "Identifier") {
|
|
3286
|
+
return false;
|
|
3287
|
+
}
|
|
3288
|
+
const value = prop.value;
|
|
3289
|
+
if (value.type === "Literal" && typeof value.value === "string") {
|
|
3290
|
+
return true;
|
|
3291
|
+
}
|
|
3292
|
+
return value.type === "ObjectExpression" && isPureLiteralSzValue(value);
|
|
3293
|
+
});
|
|
3294
|
+
}
|
|
3008
3295
|
function extractElementName(nameNode) {
|
|
3009
3296
|
if (nameNode.type === "JSXIdentifier") {
|
|
3010
3297
|
return String(nameNode.name);
|
|
@@ -3385,7 +3672,11 @@ function assertAstBudget(root, filename, astBudget) {
|
|
|
3385
3672
|
});
|
|
3386
3673
|
}
|
|
3387
3674
|
function collectDynamicCallClasses(node, filename, bindings, classes) {
|
|
3388
|
-
if (node.callee.type !== "Identifier"
|
|
3675
|
+
if (node.callee.type !== "Identifier") {
|
|
3676
|
+
return;
|
|
3677
|
+
}
|
|
3678
|
+
const calleeName = node.callee.name;
|
|
3679
|
+
if (calleeName !== "dynamic" && calleeName !== "szr") {
|
|
3389
3680
|
return;
|
|
3390
3681
|
}
|
|
3391
3682
|
const [firstArg] = node.arguments;
|
|
@@ -3527,11 +3818,25 @@ function buildNestedConditionalClassExpression(node, filename, bindings, source,
|
|
|
3527
3818
|
if (topLevel !== 0 || countOxcConditionals(node) !== 1 || !first) {
|
|
3528
3819
|
return null;
|
|
3529
3820
|
}
|
|
3530
|
-
const
|
|
3821
|
+
const condPropIndex = node.properties.findIndex(
|
|
3822
|
+
(prop) => prop.type === "Property" && prop.value.type === "ObjectExpression" && countOxcConditionals(prop.value) === 1
|
|
3823
|
+
);
|
|
3824
|
+
if (condPropIndex === -1) {
|
|
3825
|
+
return null;
|
|
3826
|
+
}
|
|
3827
|
+
const staticNode = {
|
|
3828
|
+
...node,
|
|
3829
|
+
properties: node.properties.filter((_, i) => i !== condPropIndex)
|
|
3830
|
+
};
|
|
3831
|
+
const condNode = {
|
|
3832
|
+
...node,
|
|
3833
|
+
properties: [node.properties[condPropIndex]]
|
|
3834
|
+
};
|
|
3835
|
+
const compile = (target, pick) => {
|
|
3531
3836
|
try {
|
|
3532
3837
|
return transformCore.transform(
|
|
3533
3838
|
applyGlobalVarAliasesToSzObject(
|
|
3534
|
-
astObjectToSzObject(
|
|
3839
|
+
astObjectToSzObject(target, filename, bindings, pick),
|
|
3535
3840
|
globalVarAliases,
|
|
3536
3841
|
cssVariableMap
|
|
3537
3842
|
)
|
|
@@ -3543,19 +3848,24 @@ function buildNestedConditionalClassExpression(node, filename, bindings, source,
|
|
|
3543
3848
|
throw err;
|
|
3544
3849
|
}
|
|
3545
3850
|
};
|
|
3546
|
-
const
|
|
3547
|
-
const
|
|
3548
|
-
|
|
3851
|
+
const staticClasses = staticNode.properties.length > 0 ? compile(staticNode) : "";
|
|
3852
|
+
const consequent = compile(condNode, "consequent");
|
|
3853
|
+
const alternate = compile(condNode, "alternate");
|
|
3854
|
+
if (staticClasses === null || consequent === null || alternate === null) {
|
|
3549
3855
|
return null;
|
|
3550
3856
|
}
|
|
3551
|
-
for (const cls of `${consequent} ${alternate}`.split(/\s+/)) {
|
|
3857
|
+
for (const cls of `${staticClasses} ${consequent} ${alternate}`.split(/\s+/)) {
|
|
3552
3858
|
if (cls) {
|
|
3553
3859
|
classes.add(cls);
|
|
3554
3860
|
}
|
|
3555
3861
|
}
|
|
3556
3862
|
const testSource = source.slice(first.test.start, first.test.end);
|
|
3557
3863
|
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
3558
|
-
|
|
3864
|
+
const ternary = `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
3865
|
+
if (staticClasses === "") {
|
|
3866
|
+
return ternary;
|
|
3867
|
+
}
|
|
3868
|
+
return `\`${staticClasses} \${${ternary}}\``;
|
|
3559
3869
|
}
|
|
3560
3870
|
function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3561
3871
|
let conditionalSpread = null;
|
|
@@ -4342,6 +4652,7 @@ function extractKeyName(key) {
|
|
|
4342
4652
|
return null;
|
|
4343
4653
|
}
|
|
4344
4654
|
function astValueToSzValue(node, filename, bindings, branchPick) {
|
|
4655
|
+
node = unwrapExpression(node);
|
|
4345
4656
|
if (branchPick && node.type === "ConditionalExpression") {
|
|
4346
4657
|
return astValueToSzValue(
|
|
4347
4658
|
node[branchPick],
|
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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { init, version, transform_sz, encode } from '@csszyx/core';
|
|
2
|
-
import { t as transform, s as setSzWarnLocation, f as formatSzWarnLocation, C as COLOR_PROPERTIES, P as PROPERTY_MAP, g as getCSSVariableName, a as PropertyCategory, K as KNOWN_VARIANTS, b as getVariantPrefix, c as getPropertyCategory, d as stripInvalidColorStrings } from './shared/compiler.
|
|
3
|
-
export { B as BOOLEAN_SHORTHANDS, e as PROPERTY_CATEGORY_MAP, R as REMOVED_BOOLEAN_SUGAR, S as SPECIAL_VARIANTS, h as SUGGESTION_MAP, i as isValidSzProp, n as normalizeClassName } from './shared/compiler.
|
|
2
|
+
import { t as transform, s as setSzWarnLocation, f as formatSzWarnLocation, C as COLOR_PROPERTIES, P as PROPERTY_MAP, g as getCSSVariableName, a as PropertyCategory, K as KNOWN_VARIANTS, b as getVariantPrefix, c as getPropertyCategory, d as stripInvalidColorStrings } from './shared/compiler.zZfo8y65.mjs';
|
|
3
|
+
export { B as BOOLEAN_SHORTHANDS, e as PROPERTY_CATEGORY_MAP, R as REMOVED_BOOLEAN_SUGAR, S as SPECIAL_VARIANTS, h as SUGGESTION_MAP, i as isValidSzProp, n as normalizeClassName } from './shared/compiler.zZfo8y65.mjs';
|
|
4
4
|
import { parseSync } from 'oxc-parser';
|
|
5
5
|
import * as t from '@babel/types';
|
|
6
6
|
import { createHash } from 'node:crypto';
|
|
@@ -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
|
}
|
|
@@ -705,22 +770,23 @@ function transformSourceCode(source, filename, options) {
|
|
|
705
770
|
transformed = true;
|
|
706
771
|
}
|
|
707
772
|
},
|
|
708
|
-
// ── dynamic() literal extraction
|
|
709
|
-
// Detects `dynamic({...})`
|
|
710
|
-
// with statically-analyzable arguments
|
|
711
|
-
// class tokens to collectedClasses so
|
|
712
|
-
// includes them in csszyx-classes.html
|
|
713
|
-
//
|
|
714
|
-
// without
|
|
773
|
+
// ── dynamic() / szr() literal extraction ─────────────────────────
|
|
774
|
+
// Detects `dynamic({...})` / `szr({...})` and their
|
|
775
|
+
// `(CONST_IDENTIFIER)` forms with statically-analyzable arguments
|
|
776
|
+
// and adds the resulting class tokens to collectedClasses so
|
|
777
|
+
// prescanAndWriteClasses() includes them in csszyx-classes.html
|
|
778
|
+
// for Tailwind to scan. A bare static `szr({...})` type-checks and
|
|
779
|
+
// resolves at runtime, so without this its classes were silently
|
|
780
|
+
// dead under Tailwind `source(none)`.
|
|
715
781
|
CallExpression(path) {
|
|
716
782
|
const callee = path.node.callee;
|
|
717
|
-
if (!t.isIdentifier(callee) || callee.name !== "dynamic") {
|
|
783
|
+
if (!t.isIdentifier(callee) || callee.name !== "dynamic" && callee.name !== "szr") {
|
|
718
784
|
return;
|
|
719
785
|
}
|
|
720
786
|
if (path.node.arguments.length === 0) {
|
|
721
787
|
return;
|
|
722
788
|
}
|
|
723
|
-
const arg = path.node.arguments[0];
|
|
789
|
+
const arg = unwrapTsExpression(path.node.arguments[0]);
|
|
724
790
|
if (t.isObjectExpression(arg)) {
|
|
725
791
|
const staticObj = evaluateStaticObject(arg);
|
|
726
792
|
if (!staticObj) {
|
|
@@ -734,10 +800,7 @@ function transformSourceCode(source, filename, options) {
|
|
|
734
800
|
}
|
|
735
801
|
return;
|
|
736
802
|
}
|
|
737
|
-
|
|
738
|
-
while (t.isTSAsExpression(argExpr) || t.isTSSatisfiesExpression(argExpr)) {
|
|
739
|
-
argExpr = argExpr.expression;
|
|
740
|
-
}
|
|
803
|
+
const argExpr = arg;
|
|
741
804
|
if (t.isIdentifier(argExpr)) {
|
|
742
805
|
const binding = path.scope.getBinding(argExpr.name);
|
|
743
806
|
if (!binding) {
|
|
@@ -770,6 +833,9 @@ function transformSourceCode(source, filename, options) {
|
|
|
770
833
|
})
|
|
771
834
|
]
|
|
772
835
|
});
|
|
836
|
+
for (const c of szsPendingClasses) {
|
|
837
|
+
collectedClasses.add(c);
|
|
838
|
+
}
|
|
773
839
|
return {
|
|
774
840
|
code: result?.code || source,
|
|
775
841
|
transformed,
|
|
@@ -821,6 +887,31 @@ function parseStyleStringToObjectExpr(styleStr) {
|
|
|
821
887
|
}
|
|
822
888
|
return t.objectExpression(objProps);
|
|
823
889
|
}
|
|
890
|
+
function isHostElementName(name) {
|
|
891
|
+
return t.isJSXIdentifier(name) && /^[a-z]/.test(name.name);
|
|
892
|
+
}
|
|
893
|
+
function szsUnsupportedMessage$1(filename) {
|
|
894
|
+
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.`;
|
|
895
|
+
}
|
|
896
|
+
function isPureLiteralSzValue$1(node) {
|
|
897
|
+
if (t.isStringLiteral(node) || t.isNumericLiteral(node) || t.isBooleanLiteral(node)) {
|
|
898
|
+
return true;
|
|
899
|
+
}
|
|
900
|
+
if (t.isUnaryExpression(node) && node.operator === "-" && t.isNumericLiteral(node.argument)) {
|
|
901
|
+
return true;
|
|
902
|
+
}
|
|
903
|
+
if (t.isObjectExpression(node)) {
|
|
904
|
+
return node.properties.every(
|
|
905
|
+
(prop) => t.isObjectProperty(prop) && !prop.computed && t.isIdentifier(prop.key) && isPureLiteralSzValue$1(prop.value)
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
function isValidSzsSlotMap$1(slotMap) {
|
|
911
|
+
return slotMap.properties.every(
|
|
912
|
+
(prop) => t.isObjectProperty(prop) && !prop.computed && t.isIdentifier(prop.key) && (t.isStringLiteral(prop.value) || t.isObjectExpression(prop.value) && isPureLiteralSzValue$1(prop.value))
|
|
913
|
+
);
|
|
914
|
+
}
|
|
824
915
|
function emptyClassToUndefined(node) {
|
|
825
916
|
return t.isStringLiteral(node) && node.value === "" ? t.identifier("undefined") : node;
|
|
826
917
|
}
|
|
@@ -948,22 +1039,44 @@ function tryHoistNestedConditional(node, getBinding) {
|
|
|
948
1039
|
if (topLevel !== 0 || nested !== 1 || test === null) {
|
|
949
1040
|
return null;
|
|
950
1041
|
}
|
|
1042
|
+
const condPropIndex = node.properties.findIndex(
|
|
1043
|
+
(prop) => t.isObjectProperty(prop) && t.isObjectExpression(prop.value) && countAllConditionals(prop.value) === 1
|
|
1044
|
+
);
|
|
1045
|
+
if (condPropIndex === -1) {
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
const staticNode = t.objectExpression(node.properties.filter((_, i) => i !== condPropIndex));
|
|
1049
|
+
const condNode = t.objectExpression([node.properties[condPropIndex]]);
|
|
1050
|
+
const staticClasses = staticNode.properties.length > 0 ? tryStaticTransformNode(staticNode, getBinding) : null;
|
|
951
1051
|
const consequent = tryStaticTransformNode(
|
|
952
|
-
cloneObjectPickingBranch(
|
|
1052
|
+
cloneObjectPickingBranch(condNode, "consequent"),
|
|
953
1053
|
getBinding
|
|
954
1054
|
);
|
|
955
1055
|
const alternate = tryStaticTransformNode(
|
|
956
|
-
cloneObjectPickingBranch(
|
|
1056
|
+
cloneObjectPickingBranch(condNode, "alternate"),
|
|
957
1057
|
getBinding
|
|
958
1058
|
);
|
|
959
|
-
if (!consequent || !alternate || !t.isStringLiteral(consequent) || !t.isStringLiteral(alternate)) {
|
|
1059
|
+
if (!consequent || !alternate || !t.isStringLiteral(consequent) || !t.isStringLiteral(alternate) || staticNode.properties.length > 0 && (!staticClasses || !t.isStringLiteral(staticClasses))) {
|
|
960
1060
|
return null;
|
|
961
1061
|
}
|
|
962
|
-
|
|
1062
|
+
const ternary = t.conditionalExpression(
|
|
963
1063
|
test,
|
|
964
1064
|
emptyClassToUndefined(consequent),
|
|
965
1065
|
emptyClassToUndefined(alternate)
|
|
966
1066
|
);
|
|
1067
|
+
if (!staticClasses || !t.isStringLiteral(staticClasses) || staticClasses.value === "") {
|
|
1068
|
+
return ternary;
|
|
1069
|
+
}
|
|
1070
|
+
return t.templateLiteral(
|
|
1071
|
+
[
|
|
1072
|
+
t.templateElement(
|
|
1073
|
+
{ raw: `${staticClasses.value} `, cooked: `${staticClasses.value} ` },
|
|
1074
|
+
false
|
|
1075
|
+
),
|
|
1076
|
+
t.templateElement({ raw: "", cooked: "" }, true)
|
|
1077
|
+
],
|
|
1078
|
+
[ternary]
|
|
1079
|
+
);
|
|
967
1080
|
}
|
|
968
1081
|
function tryHoistConditionalSpread(node, getBinding) {
|
|
969
1082
|
let conditionalSpreadIdx = -1;
|
|
@@ -1016,16 +1129,27 @@ function readStaticConfigObject(configExpr, key, scope) {
|
|
|
1016
1129
|
}
|
|
1017
1130
|
return null;
|
|
1018
1131
|
}
|
|
1132
|
+
function unwrapTsExpression(node) {
|
|
1133
|
+
let current = node;
|
|
1134
|
+
while (t.isTSSatisfiesExpression(current) || t.isTSAsExpression(current) || t.isTSNonNullExpression(current) || t.isParenthesizedExpression(current)) {
|
|
1135
|
+
current = current.expression;
|
|
1136
|
+
}
|
|
1137
|
+
return current;
|
|
1138
|
+
}
|
|
1019
1139
|
function resolveToConstObjectExpression(node, scope) {
|
|
1020
|
-
|
|
1021
|
-
|
|
1140
|
+
const unwrapped = unwrapTsExpression(node);
|
|
1141
|
+
if (t.isObjectExpression(unwrapped)) {
|
|
1142
|
+
return unwrapped;
|
|
1022
1143
|
}
|
|
1023
|
-
if (t.isIdentifier(
|
|
1024
|
-
const binding = scope.getBinding(
|
|
1144
|
+
if (t.isIdentifier(unwrapped)) {
|
|
1145
|
+
const binding = scope.getBinding(unwrapped.name);
|
|
1025
1146
|
if (binding?.kind === "const" && binding.constant) {
|
|
1026
1147
|
const declNode = binding.path.node;
|
|
1027
|
-
if (t.isVariableDeclarator(declNode)
|
|
1028
|
-
|
|
1148
|
+
if (t.isVariableDeclarator(declNode)) {
|
|
1149
|
+
const init = unwrapTsExpression(declNode.init);
|
|
1150
|
+
if (t.isObjectExpression(init)) {
|
|
1151
|
+
return init;
|
|
1152
|
+
}
|
|
1029
1153
|
}
|
|
1030
1154
|
}
|
|
1031
1155
|
}
|
|
@@ -1050,7 +1174,7 @@ function evaluateStaticObject(node) {
|
|
|
1050
1174
|
} else {
|
|
1051
1175
|
return null;
|
|
1052
1176
|
}
|
|
1053
|
-
const value = prop.value;
|
|
1177
|
+
const value = unwrapTsExpression(prop.value);
|
|
1054
1178
|
if (t.isStringLiteral(value)) {
|
|
1055
1179
|
result[key] = value.value;
|
|
1056
1180
|
} else if (t.isNumericLiteral(value)) {
|
|
@@ -1373,6 +1497,18 @@ function collectFromExpr(node, classes) {
|
|
|
1373
1497
|
} else if (t.isConditionalExpression(node)) {
|
|
1374
1498
|
collectFromExpr(node.consequent, classes);
|
|
1375
1499
|
collectFromExpr(node.alternate, classes);
|
|
1500
|
+
} else if (t.isTemplateLiteral(node)) {
|
|
1501
|
+
for (let i = 0; i < node.quasis.length; i++) {
|
|
1502
|
+
for (const c of (node.quasis[i].value.cooked ?? "").split(/\s+/)) {
|
|
1503
|
+
if (c) {
|
|
1504
|
+
classes.add(c);
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
const expr = node.expressions[i];
|
|
1508
|
+
if (expr && t.isExpression(expr)) {
|
|
1509
|
+
collectFromExpr(expr, classes);
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1376
1512
|
}
|
|
1377
1513
|
}
|
|
1378
1514
|
function collectCandidatesFromBabelExpr(node, path, classes) {
|
|
@@ -2386,6 +2522,7 @@ class OxcNotImplementedError extends Error {
|
|
|
2386
2522
|
}
|
|
2387
2523
|
function transformOxc(source, filename, options) {
|
|
2388
2524
|
const classes = /* @__PURE__ */ new Set();
|
|
2525
|
+
const szsPendingClasses = [];
|
|
2389
2526
|
const rawClassNames = /* @__PURE__ */ new Set();
|
|
2390
2527
|
const diagnostics = [];
|
|
2391
2528
|
const recoveryTokens = /* @__PURE__ */ new Map();
|
|
@@ -2408,7 +2545,7 @@ function transformOxc(source, filename, options) {
|
|
|
2408
2545
|
const effectiveFilename = filename ?? "file.tsx";
|
|
2409
2546
|
setSzWarnLocation(void 0);
|
|
2410
2547
|
const astBudget = options?.astBudget ?? AST_BUDGET;
|
|
2411
|
-
const parsed = parseSync(effectiveFilename, source);
|
|
2548
|
+
const parsed = /\.(?:js|mjs|cjs)$/.test(effectiveFilename) ? parseSync(effectiveFilename, source, { lang: "jsx" }) : parseSync(effectiveFilename, source);
|
|
2412
2549
|
if (parsed.errors.length > 0) {
|
|
2413
2550
|
throw new Error(
|
|
2414
2551
|
`oxc-parser errors in ${effectiveFilename}: ` + parsed.errors.map((e) => e.message).join("; ")
|
|
@@ -2457,6 +2594,7 @@ function transformOxc(source, filename, options) {
|
|
|
2457
2594
|
const openingNode = node;
|
|
2458
2595
|
const attrs = openingNode.attributes ?? [];
|
|
2459
2596
|
const szAttrs = [];
|
|
2597
|
+
const szsAttrs = [];
|
|
2460
2598
|
let classNameAttr = null;
|
|
2461
2599
|
let styleAttr = null;
|
|
2462
2600
|
let szRecoverAttr = null;
|
|
@@ -2489,6 +2627,8 @@ function transformOxc(source, filename, options) {
|
|
|
2489
2627
|
const name = attr.name?.name;
|
|
2490
2628
|
if (name === "sz") {
|
|
2491
2629
|
szAttrs.push(attr);
|
|
2630
|
+
} else if (name === "szs") {
|
|
2631
|
+
szsAttrs.push(attr);
|
|
2492
2632
|
} else if (name === "className" || name === "class") {
|
|
2493
2633
|
classNameAttr = attr;
|
|
2494
2634
|
} else if (name === "style") {
|
|
@@ -2539,6 +2679,89 @@ function transformOxc(source, filename, options) {
|
|
|
2539
2679
|
}
|
|
2540
2680
|
}
|
|
2541
2681
|
}
|
|
2682
|
+
for (const szsAttr of szsAttrs) {
|
|
2683
|
+
if (isHostOpeningElementName(openingNode.name)) {
|
|
2684
|
+
diagnostics.push(
|
|
2685
|
+
`[csszyx] szs at ${effectiveFilename}: szs has no effect on a host element \u2014 it maps slot names of a custom component. Attribute left unchanged.`
|
|
2686
|
+
);
|
|
2687
|
+
continue;
|
|
2688
|
+
}
|
|
2689
|
+
const szsValue = szsAttr.value;
|
|
2690
|
+
const szsExpression = szsValue && szsValue.type === "JSXExpressionContainer" ? szsValue.expression : null;
|
|
2691
|
+
if (!szsExpression || szsExpression.type !== "ObjectExpression") {
|
|
2692
|
+
diagnostics.push(szsUnsupportedMessage(effectiveFilename));
|
|
2693
|
+
continue;
|
|
2694
|
+
}
|
|
2695
|
+
const slotMap = szsExpression;
|
|
2696
|
+
if (!isValidSzsSlotMap(slotMap)) {
|
|
2697
|
+
diagnostics.push(szsUnsupportedMessage(effectiveFilename));
|
|
2698
|
+
continue;
|
|
2699
|
+
}
|
|
2700
|
+
const { line: szsWarnLine } = offsetToLineColumn(source, szsAttr.start);
|
|
2701
|
+
setSzWarnLocation(
|
|
2702
|
+
formatSzWarnLocation(effectiveFilename, szsWarnLine, options?.rootDir)
|
|
2703
|
+
);
|
|
2704
|
+
const slotEntries = [];
|
|
2705
|
+
let anyCompiled = false;
|
|
2706
|
+
let slotFailed = false;
|
|
2707
|
+
for (const propRaw of slotMap.properties) {
|
|
2708
|
+
const prop = propRaw;
|
|
2709
|
+
const keyText = source.slice(prop.key.start, prop.key.end);
|
|
2710
|
+
const propValue = prop.value;
|
|
2711
|
+
const literal = propValue.type === "Literal" ? propValue.value : null;
|
|
2712
|
+
if (typeof literal === "string") {
|
|
2713
|
+
slotEntries.push({
|
|
2714
|
+
keyText,
|
|
2715
|
+
classNames: literal,
|
|
2716
|
+
text: source.slice(propValue.start, propValue.end)
|
|
2717
|
+
});
|
|
2718
|
+
continue;
|
|
2719
|
+
}
|
|
2720
|
+
try {
|
|
2721
|
+
const slotObject = astObjectToSzObject(
|
|
2722
|
+
propValue,
|
|
2723
|
+
effectiveFilename,
|
|
2724
|
+
objectBindings
|
|
2725
|
+
);
|
|
2726
|
+
const compiled = transform(
|
|
2727
|
+
applyGlobalVarAliasesToSzObject(
|
|
2728
|
+
slotObject,
|
|
2729
|
+
globalVarAliases,
|
|
2730
|
+
cssVariableMap
|
|
2731
|
+
)
|
|
2732
|
+
).className;
|
|
2733
|
+
slotEntries.push({
|
|
2734
|
+
keyText,
|
|
2735
|
+
classNames: compiled,
|
|
2736
|
+
text: JSON.stringify(compiled)
|
|
2737
|
+
});
|
|
2738
|
+
anyCompiled = true;
|
|
2739
|
+
} catch (err) {
|
|
2740
|
+
if (err instanceof OxcNotImplementedError) {
|
|
2741
|
+
slotFailed = true;
|
|
2742
|
+
break;
|
|
2743
|
+
}
|
|
2744
|
+
throw err;
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
setSzWarnLocation(void 0);
|
|
2748
|
+
if (slotFailed) {
|
|
2749
|
+
diagnostics.push(szsUnsupportedMessage(effectiveFilename));
|
|
2750
|
+
continue;
|
|
2751
|
+
}
|
|
2752
|
+
if (anyCompiled) {
|
|
2753
|
+
const body = slotEntries.map((entry) => `${entry.keyText}: ${entry.text}`).join(", ");
|
|
2754
|
+
edits.overwrite(szsAttr.start, szsAttr.end, `szs={{ ${body} }}`);
|
|
2755
|
+
transformed = true;
|
|
2756
|
+
}
|
|
2757
|
+
for (const entry of slotEntries) {
|
|
2758
|
+
for (const c of entry.classNames.split(/\s+/)) {
|
|
2759
|
+
if (c) {
|
|
2760
|
+
szsPendingClasses.push(c);
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2542
2765
|
if (szAttrs.length === 0) {
|
|
2543
2766
|
applyHoistedStyleProps();
|
|
2544
2767
|
return;
|
|
@@ -2899,6 +3122,24 @@ function transformOxc(source, filename, options) {
|
|
|
2899
3122
|
];
|
|
2900
3123
|
const mergedAttr = mergedClasses.length === 0 ? "className={undefined}" : `className="${mergedClasses.join(" ")}"`;
|
|
2901
3124
|
if (classNameAttr) {
|
|
3125
|
+
const classNameValue = classNameAttr.value;
|
|
3126
|
+
if (existingRaw === null && classNameValue && classNameValue.type === "JSXExpressionContainer") {
|
|
3127
|
+
const exprNode = classNameValue.expression;
|
|
3128
|
+
const exprSource = source.slice(exprNode.start, exprNode.end);
|
|
3129
|
+
edits.overwrite(
|
|
3130
|
+
classNameAttr.start,
|
|
3131
|
+
classNameAttr.end,
|
|
3132
|
+
`className={_szMerge(${exprSource}, ${JSON.stringify(szDerived.join(" "))})}`
|
|
3133
|
+
);
|
|
3134
|
+
for (const szAttr of szAttrs) {
|
|
3135
|
+
const deleteStart = whitespaceStart(source, szAttr.start);
|
|
3136
|
+
edits.remove(deleteStart, szAttr.end);
|
|
3137
|
+
}
|
|
3138
|
+
usesRuntime = true;
|
|
3139
|
+
usesMerge = true;
|
|
3140
|
+
transformed = true;
|
|
3141
|
+
return;
|
|
3142
|
+
}
|
|
2902
3143
|
edits.overwrite(classNameAttr.start, classNameAttr.end, mergedAttr);
|
|
2903
3144
|
for (const szAttr of szAttrs) {
|
|
2904
3145
|
const deleteStart = whitespaceStart(source, szAttr.start);
|
|
@@ -2917,6 +3158,9 @@ function transformOxc(source, filename, options) {
|
|
|
2917
3158
|
}
|
|
2918
3159
|
transformed = true;
|
|
2919
3160
|
});
|
|
3161
|
+
for (const c of szsPendingClasses) {
|
|
3162
|
+
classes.add(c);
|
|
3163
|
+
}
|
|
2920
3164
|
return {
|
|
2921
3165
|
code: transformed ? edits.toString() : source,
|
|
2922
3166
|
transformed,
|
|
@@ -2986,6 +3230,49 @@ function buildRuntimeFallbackDiagnostic(expression, source) {
|
|
|
2986
3230
|
return `sz fallback at ${lineCol}: ${reason}.
|
|
2987
3231
|
Suggestion: ${suggestion}`;
|
|
2988
3232
|
}
|
|
3233
|
+
function isHostOpeningElementName(nameNode) {
|
|
3234
|
+
return nameNode.type === "JSXIdentifier" && /^[a-z]/.test(String(nameNode.name));
|
|
3235
|
+
}
|
|
3236
|
+
function szsUnsupportedMessage(filename) {
|
|
3237
|
+
return `[csszyx] szs at ${filename}: every slot must be an identifier key with a static object literal (or class string) value. Attribute left unchanged.`;
|
|
3238
|
+
}
|
|
3239
|
+
function isPureLiteralSzValue(node) {
|
|
3240
|
+
if (node.type === "Literal") {
|
|
3241
|
+
const value = node.value;
|
|
3242
|
+
return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
3243
|
+
}
|
|
3244
|
+
if (node.type === "UnaryExpression") {
|
|
3245
|
+
const unary = node;
|
|
3246
|
+
return unary.operator === "-" && unary.argument.type === "Literal" && typeof unary.argument.value === "number";
|
|
3247
|
+
}
|
|
3248
|
+
if (node.type === "ObjectExpression") {
|
|
3249
|
+
const properties = node.properties;
|
|
3250
|
+
return properties.every((propRaw) => {
|
|
3251
|
+
if (propRaw.type !== "Property") {
|
|
3252
|
+
return false;
|
|
3253
|
+
}
|
|
3254
|
+
const prop = propRaw;
|
|
3255
|
+
return !prop.computed && prop.key.type === "Identifier" && isPureLiteralSzValue(prop.value);
|
|
3256
|
+
});
|
|
3257
|
+
}
|
|
3258
|
+
return false;
|
|
3259
|
+
}
|
|
3260
|
+
function isValidSzsSlotMap(slotMap) {
|
|
3261
|
+
return slotMap.properties.every((propRaw) => {
|
|
3262
|
+
if (propRaw.type !== "Property") {
|
|
3263
|
+
return false;
|
|
3264
|
+
}
|
|
3265
|
+
const prop = propRaw;
|
|
3266
|
+
if (prop.computed || prop.key.type !== "Identifier") {
|
|
3267
|
+
return false;
|
|
3268
|
+
}
|
|
3269
|
+
const value = prop.value;
|
|
3270
|
+
if (value.type === "Literal" && typeof value.value === "string") {
|
|
3271
|
+
return true;
|
|
3272
|
+
}
|
|
3273
|
+
return value.type === "ObjectExpression" && isPureLiteralSzValue(value);
|
|
3274
|
+
});
|
|
3275
|
+
}
|
|
2989
3276
|
function extractElementName(nameNode) {
|
|
2990
3277
|
if (nameNode.type === "JSXIdentifier") {
|
|
2991
3278
|
return String(nameNode.name);
|
|
@@ -3366,7 +3653,11 @@ function assertAstBudget(root, filename, astBudget) {
|
|
|
3366
3653
|
});
|
|
3367
3654
|
}
|
|
3368
3655
|
function collectDynamicCallClasses(node, filename, bindings, classes) {
|
|
3369
|
-
if (node.callee.type !== "Identifier"
|
|
3656
|
+
if (node.callee.type !== "Identifier") {
|
|
3657
|
+
return;
|
|
3658
|
+
}
|
|
3659
|
+
const calleeName = node.callee.name;
|
|
3660
|
+
if (calleeName !== "dynamic" && calleeName !== "szr") {
|
|
3370
3661
|
return;
|
|
3371
3662
|
}
|
|
3372
3663
|
const [firstArg] = node.arguments;
|
|
@@ -3508,11 +3799,25 @@ function buildNestedConditionalClassExpression(node, filename, bindings, source,
|
|
|
3508
3799
|
if (topLevel !== 0 || countOxcConditionals(node) !== 1 || !first) {
|
|
3509
3800
|
return null;
|
|
3510
3801
|
}
|
|
3511
|
-
const
|
|
3802
|
+
const condPropIndex = node.properties.findIndex(
|
|
3803
|
+
(prop) => prop.type === "Property" && prop.value.type === "ObjectExpression" && countOxcConditionals(prop.value) === 1
|
|
3804
|
+
);
|
|
3805
|
+
if (condPropIndex === -1) {
|
|
3806
|
+
return null;
|
|
3807
|
+
}
|
|
3808
|
+
const staticNode = {
|
|
3809
|
+
...node,
|
|
3810
|
+
properties: node.properties.filter((_, i) => i !== condPropIndex)
|
|
3811
|
+
};
|
|
3812
|
+
const condNode = {
|
|
3813
|
+
...node,
|
|
3814
|
+
properties: [node.properties[condPropIndex]]
|
|
3815
|
+
};
|
|
3816
|
+
const compile = (target, pick) => {
|
|
3512
3817
|
try {
|
|
3513
3818
|
return transform(
|
|
3514
3819
|
applyGlobalVarAliasesToSzObject(
|
|
3515
|
-
astObjectToSzObject(
|
|
3820
|
+
astObjectToSzObject(target, filename, bindings, pick),
|
|
3516
3821
|
globalVarAliases,
|
|
3517
3822
|
cssVariableMap
|
|
3518
3823
|
)
|
|
@@ -3524,19 +3829,24 @@ function buildNestedConditionalClassExpression(node, filename, bindings, source,
|
|
|
3524
3829
|
throw err;
|
|
3525
3830
|
}
|
|
3526
3831
|
};
|
|
3527
|
-
const
|
|
3528
|
-
const
|
|
3529
|
-
|
|
3832
|
+
const staticClasses = staticNode.properties.length > 0 ? compile(staticNode) : "";
|
|
3833
|
+
const consequent = compile(condNode, "consequent");
|
|
3834
|
+
const alternate = compile(condNode, "alternate");
|
|
3835
|
+
if (staticClasses === null || consequent === null || alternate === null) {
|
|
3530
3836
|
return null;
|
|
3531
3837
|
}
|
|
3532
|
-
for (const cls of `${consequent} ${alternate}`.split(/\s+/)) {
|
|
3838
|
+
for (const cls of `${staticClasses} ${consequent} ${alternate}`.split(/\s+/)) {
|
|
3533
3839
|
if (cls) {
|
|
3534
3840
|
classes.add(cls);
|
|
3535
3841
|
}
|
|
3536
3842
|
}
|
|
3537
3843
|
const testSource = source.slice(first.test.start, first.test.end);
|
|
3538
3844
|
const branch = (cls) => cls === "" ? "undefined" : JSON.stringify(cls);
|
|
3539
|
-
|
|
3845
|
+
const ternary = `${testSource} ? ${branch(consequent)} : ${branch(alternate)}`;
|
|
3846
|
+
if (staticClasses === "") {
|
|
3847
|
+
return ternary;
|
|
3848
|
+
}
|
|
3849
|
+
return `\`${staticClasses} \${${ternary}}\``;
|
|
3540
3850
|
}
|
|
3541
3851
|
function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
|
|
3542
3852
|
let conditionalSpread = null;
|
|
@@ -4323,6 +4633,7 @@ function extractKeyName(key) {
|
|
|
4323
4633
|
return null;
|
|
4324
4634
|
}
|
|
4325
4635
|
function astValueToSzValue(node, filename, bindings, branchPick) {
|
|
4636
|
+
node = unwrapExpression(node);
|
|
4326
4637
|
if (branchPick && node.type === "ConditionalExpression") {
|
|
4327
4638
|
return astValueToSzValue(
|
|
4328
4639
|
node[branchPick],
|
|
@@ -1186,6 +1186,8 @@ function handleImportant(value) {
|
|
|
1186
1186
|
}
|
|
1187
1187
|
return { value, important: false };
|
|
1188
1188
|
}
|
|
1189
|
+
const ALPHA_SAFE_NAMED_COLORS = /* @__PURE__ */ new Set(["white", "black", "transparent", "current", "inherit"]);
|
|
1190
|
+
const _warnedOpacityTokens = /* @__PURE__ */ new Set();
|
|
1189
1191
|
function formatOpacity(op) {
|
|
1190
1192
|
if (typeof op === "number") {
|
|
1191
1193
|
if (Number.isInteger(op * 2)) {
|
|
@@ -1649,6 +1651,13 @@ function transformImpl(szProp, prefix, mangleMap) {
|
|
|
1649
1651
|
const colorBase = rawColorBase.startsWith("--") ? `(${rawColorBase})` : needsArbitraryBrackets(rawColorBase) ? `[${normalizeArbitraryValue(rawColorBase)}]` : normalizeArbitraryValue(rawColorBase);
|
|
1650
1652
|
if (colorObj.op !== void 0) {
|
|
1651
1653
|
const opStr = formatOpacity(colorObj.op);
|
|
1654
|
+
if (process.env.NODE_ENV !== "production" && typeof window === "undefined" && !rawColorBase.startsWith("--") && !needsArbitraryBrackets(rawColorBase) && !/-\d{2,3}$/.test(rawColorBase) && !ALPHA_SAFE_NAMED_COLORS.has(rawColorBase) && !_warnedOpacityTokens.has(rawColorBase)) {
|
|
1655
|
+
_warnedOpacityTokens.add(rawColorBase);
|
|
1656
|
+
const at = szWarnLocation ? ` at ${szWarnLocation}` : "";
|
|
1657
|
+
console.warn(
|
|
1658
|
+
`[csszyx] "${prefix}${twPrefix}-${colorBase}/${opStr}"${at}: the /${opStr} opacity applies only if the "${rawColorBase}" theme token is alpha-capable (oklch or space-separated RGB). A comma-separated RGB triplet, or a token that resolves through its own alpha variable, silently ignores the modifier \u2014 verify the emitted rule.`
|
|
1659
|
+
);
|
|
1660
|
+
}
|
|
1652
1661
|
classes.push(`${prefix}${twPrefix}-${colorBase}/${opStr}`);
|
|
1653
1662
|
} else {
|
|
1654
1663
|
classes.push(`${prefix}${twPrefix}-${colorBase}`);
|
|
@@ -2385,6 +2394,9 @@ function transformImpl(szProp, prefix, mangleMap) {
|
|
|
2385
2394
|
hintProjectScanOnce(szWarnLocation);
|
|
2386
2395
|
}
|
|
2387
2396
|
}
|
|
2397
|
+
if (/^\d+(?:\.\d+)?$/.test(rawKey)) {
|
|
2398
|
+
continue;
|
|
2399
|
+
}
|
|
2388
2400
|
if (value === true) {
|
|
2389
2401
|
if (BOOLEAN_SHORTHANDS.has(rawKey)) {
|
|
2390
2402
|
const mappedClass = BOOLEAN_TO_CLASS[rawKey] || key;
|
|
@@ -1184,6 +1184,8 @@ function handleImportant(value) {
|
|
|
1184
1184
|
}
|
|
1185
1185
|
return { value, important: false };
|
|
1186
1186
|
}
|
|
1187
|
+
const ALPHA_SAFE_NAMED_COLORS = /* @__PURE__ */ new Set(["white", "black", "transparent", "current", "inherit"]);
|
|
1188
|
+
const _warnedOpacityTokens = /* @__PURE__ */ new Set();
|
|
1187
1189
|
function formatOpacity(op) {
|
|
1188
1190
|
if (typeof op === "number") {
|
|
1189
1191
|
if (Number.isInteger(op * 2)) {
|
|
@@ -1647,6 +1649,13 @@ function transformImpl(szProp, prefix, mangleMap) {
|
|
|
1647
1649
|
const colorBase = rawColorBase.startsWith("--") ? `(${rawColorBase})` : needsArbitraryBrackets(rawColorBase) ? `[${normalizeArbitraryValue(rawColorBase)}]` : normalizeArbitraryValue(rawColorBase);
|
|
1648
1650
|
if (colorObj.op !== void 0) {
|
|
1649
1651
|
const opStr = formatOpacity(colorObj.op);
|
|
1652
|
+
if (process.env.NODE_ENV !== "production" && typeof window === "undefined" && !rawColorBase.startsWith("--") && !needsArbitraryBrackets(rawColorBase) && !/-\d{2,3}$/.test(rawColorBase) && !ALPHA_SAFE_NAMED_COLORS.has(rawColorBase) && !_warnedOpacityTokens.has(rawColorBase)) {
|
|
1653
|
+
_warnedOpacityTokens.add(rawColorBase);
|
|
1654
|
+
const at = szWarnLocation ? ` at ${szWarnLocation}` : "";
|
|
1655
|
+
console.warn(
|
|
1656
|
+
`[csszyx] "${prefix}${twPrefix}-${colorBase}/${opStr}"${at}: the /${opStr} opacity applies only if the "${rawColorBase}" theme token is alpha-capable (oklch or space-separated RGB). A comma-separated RGB triplet, or a token that resolves through its own alpha variable, silently ignores the modifier \u2014 verify the emitted rule.`
|
|
1657
|
+
);
|
|
1658
|
+
}
|
|
1650
1659
|
classes.push(`${prefix}${twPrefix}-${colorBase}/${opStr}`);
|
|
1651
1660
|
} else {
|
|
1652
1661
|
classes.push(`${prefix}${twPrefix}-${colorBase}`);
|
|
@@ -2383,6 +2392,9 @@ function transformImpl(szProp, prefix, mangleMap) {
|
|
|
2383
2392
|
hintProjectScanOnce(szWarnLocation);
|
|
2384
2393
|
}
|
|
2385
2394
|
}
|
|
2395
|
+
if (/^\d+(?:\.\d+)?$/.test(rawKey)) {
|
|
2396
|
+
continue;
|
|
2397
|
+
}
|
|
2386
2398
|
if (value === true) {
|
|
2387
2399
|
if (BOOLEAN_SHORTHANDS.has(rawKey)) {
|
|
2388
2400
|
const mappedClass = BOOLEAN_TO_CLASS[rawKey] || key;
|
package/dist/transform-core.cjs
CHANGED
package/dist/transform-core.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { B as BOOLEAN_SHORTHANDS, K as KNOWN_VARIANTS, M as MAX_SZ_DEPTH, P as PROPERTY_MAP, R as REMOVED_BOOLEAN_SUGAR, S as SPECIAL_VARIANTS, h as SUGGESTION_MAP, j as SzDepthError, V as VARIANT_MAP, f as formatSzWarnLocation, b as getVariantPrefix, k as isForbiddenSzKey, i as isValidSzProp, l as normalizeArbitraryValue, m as normalizeArbitraryVariant, n as normalizeClassName, s as setSzWarnLocation, t as transform } from './shared/compiler.
|
|
1
|
+
export { B as BOOLEAN_SHORTHANDS, K as KNOWN_VARIANTS, M as MAX_SZ_DEPTH, P as PROPERTY_MAP, R as REMOVED_BOOLEAN_SUGAR, S as SPECIAL_VARIANTS, h as SUGGESTION_MAP, j as SzDepthError, V as VARIANT_MAP, f as formatSzWarnLocation, b as getVariantPrefix, k as isForbiddenSzKey, i as isValidSzProp, l as normalizeArbitraryValue, m as normalizeArbitraryVariant, n as normalizeClassName, s as setSzWarnLocation, t as transform } from './shared/compiler.zZfo8y65.mjs';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@csszyx/compiler",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.11",
|
|
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.11"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@types/babel__core": "^7.20.5",
|