@homebound/truss 2.0.0-next.1 → 2.0.0-next.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/build/index.js +39 -1
- package/build/index.js.map +1 -1
- package/build/plugin/index.d.ts +4 -3
- package/build/plugin/index.js +615 -101
- package/build/plugin/index.js.map +1 -1
- package/cli.js +6 -19
- package/package.json +3 -3
package/build/plugin/index.js
CHANGED
|
@@ -142,6 +142,17 @@ function resolveChain(chain, mapping) {
|
|
|
142
142
|
segments.push(seg);
|
|
143
143
|
continue;
|
|
144
144
|
}
|
|
145
|
+
if (abbr === "typography") {
|
|
146
|
+
const resolved = resolveTypographyCall(
|
|
147
|
+
node,
|
|
148
|
+
mapping,
|
|
149
|
+
currentMediaQuery,
|
|
150
|
+
currentPseudoClass,
|
|
151
|
+
currentPseudoElement
|
|
152
|
+
);
|
|
153
|
+
segments.push(...resolved);
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
145
156
|
if (abbr === "element") {
|
|
146
157
|
if (node.args.length !== 1 || node.args[0].type !== "StringLiteral") {
|
|
147
158
|
throw new UnsupportedPatternError(
|
|
@@ -215,6 +226,52 @@ function conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, breakpoints)
|
|
|
215
226
|
if (pseudoClass) parts.push(pseudoName(pseudoClass));
|
|
216
227
|
return parts.join("_");
|
|
217
228
|
}
|
|
229
|
+
function resolveTypographyCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
230
|
+
if (node.args.length !== 1) {
|
|
231
|
+
throw new UnsupportedPatternError(`typography() expects exactly 1 argument, got ${node.args.length}`);
|
|
232
|
+
}
|
|
233
|
+
const argAst = node.args[0];
|
|
234
|
+
if (argAst.type === "StringLiteral") {
|
|
235
|
+
return resolveTypographyEntry(argAst.value, mapping, mediaQuery, pseudoClass, pseudoElement);
|
|
236
|
+
}
|
|
237
|
+
const typography = mapping.typography ?? [];
|
|
238
|
+
if (typography.length === 0) {
|
|
239
|
+
throw new UnsupportedPatternError(`typography() is unavailable because no typography abbreviations were generated`);
|
|
240
|
+
}
|
|
241
|
+
const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
|
|
242
|
+
const lookupKey = suffix ? `typography__${suffix}` : "typography";
|
|
243
|
+
const segmentsByName = {};
|
|
244
|
+
for (const name of typography) {
|
|
245
|
+
segmentsByName[name] = resolveTypographyEntry(name, mapping, mediaQuery, pseudoClass, pseudoElement);
|
|
246
|
+
}
|
|
247
|
+
return [
|
|
248
|
+
{
|
|
249
|
+
key: lookupKey,
|
|
250
|
+
defs: {},
|
|
251
|
+
typographyLookup: {
|
|
252
|
+
lookupKey,
|
|
253
|
+
argNode: argAst,
|
|
254
|
+
segmentsByName
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
];
|
|
258
|
+
}
|
|
259
|
+
function resolveTypographyEntry(name, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
260
|
+
if (!(mapping.typography ?? []).includes(name)) {
|
|
261
|
+
throw new UnsupportedPatternError(`Unknown typography abbreviation "${name}"`);
|
|
262
|
+
}
|
|
263
|
+
const entry = mapping.abbreviations[name];
|
|
264
|
+
if (!entry) {
|
|
265
|
+
throw new UnsupportedPatternError(`Unknown typography abbreviation "${name}"`);
|
|
266
|
+
}
|
|
267
|
+
const resolved = resolveEntry(name, entry, mapping, mediaQuery, pseudoClass, pseudoElement, null);
|
|
268
|
+
for (const segment of resolved) {
|
|
269
|
+
if (segment.dynamicProps || segment.whenPseudo) {
|
|
270
|
+
throw new UnsupportedPatternError(`Typography abbreviation "${name}" cannot require runtime arguments`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
return resolved;
|
|
274
|
+
}
|
|
218
275
|
function wrapDefsWithConditions(defs, mediaQuery, pseudoClass) {
|
|
219
276
|
if (!mediaQuery && !pseudoClass) return defs;
|
|
220
277
|
const result = {};
|
|
@@ -869,12 +926,17 @@ function extractChain(node, cssBinding) {
|
|
|
869
926
|
import * as t2 from "@babel/types";
|
|
870
927
|
function collectCreateData(chains) {
|
|
871
928
|
const createEntries = /* @__PURE__ */ new Map();
|
|
929
|
+
const runtimeLookups = /* @__PURE__ */ new Map();
|
|
872
930
|
let needsMaybeInc = false;
|
|
873
931
|
for (const chain of chains) {
|
|
874
932
|
for (const part of chain.parts) {
|
|
875
933
|
const segs = part.type === "unconditional" ? part.segments : [...part.thenSegments, ...part.elseSegments];
|
|
876
934
|
for (const seg of segs) {
|
|
877
935
|
if (seg.error) continue;
|
|
936
|
+
if (seg.typographyLookup) {
|
|
937
|
+
collectTypographyLookup(createEntries, runtimeLookups, seg);
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
878
940
|
if (seg.dynamicProps) {
|
|
879
941
|
if (!createEntries.has(seg.key)) {
|
|
880
942
|
createEntries.set(seg.key, {
|
|
@@ -903,7 +965,36 @@ function collectCreateData(chains) {
|
|
|
903
965
|
}
|
|
904
966
|
}
|
|
905
967
|
}
|
|
906
|
-
return { createEntries, needsMaybeInc };
|
|
968
|
+
return { createEntries, runtimeLookups, needsMaybeInc };
|
|
969
|
+
}
|
|
970
|
+
function collectTypographyLookup(createEntries, runtimeLookups, seg) {
|
|
971
|
+
const lookup = seg.typographyLookup;
|
|
972
|
+
if (!lookup) return;
|
|
973
|
+
if (!runtimeLookups.has(lookup.lookupKey)) {
|
|
974
|
+
runtimeLookups.set(lookup.lookupKey, {
|
|
975
|
+
lookupKey: lookup.lookupKey,
|
|
976
|
+
refsByName: Object.fromEntries(
|
|
977
|
+
Object.entries(lookup.segmentsByName).map(function([name, segments]) {
|
|
978
|
+
return [
|
|
979
|
+
name,
|
|
980
|
+
segments.map(function(segment) {
|
|
981
|
+
return segment.key;
|
|
982
|
+
})
|
|
983
|
+
];
|
|
984
|
+
})
|
|
985
|
+
)
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
for (const segments of Object.values(lookup.segmentsByName)) {
|
|
989
|
+
for (const segment of segments) {
|
|
990
|
+
if (createEntries.has(segment.key)) continue;
|
|
991
|
+
createEntries.set(segment.key, {
|
|
992
|
+
key: segment.key,
|
|
993
|
+
defs: segment.defs,
|
|
994
|
+
whenPseudo: segment.whenPseudo
|
|
995
|
+
});
|
|
996
|
+
}
|
|
997
|
+
}
|
|
907
998
|
}
|
|
908
999
|
function buildCreateProperties(createEntries, stylexNamespaceName) {
|
|
909
1000
|
const createProperties = [];
|
|
@@ -1039,12 +1130,62 @@ function buildMaybeIncDeclaration(helperName, increment) {
|
|
|
1039
1130
|
t2.variableDeclarator(t2.identifier(helperName), t2.arrowFunctionExpression([incParam], body))
|
|
1040
1131
|
]);
|
|
1041
1132
|
}
|
|
1133
|
+
function buildMergePropsDeclaration(helperName, stylexNamespaceName) {
|
|
1134
|
+
const explicitClassNameParam = t2.identifier("explicitClassName");
|
|
1135
|
+
const stylesRestParam = t2.restElement(t2.identifier("styles"));
|
|
1136
|
+
const sxId = t2.identifier("sx");
|
|
1137
|
+
return t2.functionDeclaration(
|
|
1138
|
+
t2.identifier(helperName),
|
|
1139
|
+
[explicitClassNameParam, stylesRestParam],
|
|
1140
|
+
t2.blockStatement([
|
|
1141
|
+
t2.variableDeclaration("const", [
|
|
1142
|
+
t2.variableDeclarator(
|
|
1143
|
+
sxId,
|
|
1144
|
+
t2.callExpression(t2.memberExpression(t2.identifier(stylexNamespaceName), t2.identifier("props")), [
|
|
1145
|
+
t2.spreadElement(t2.identifier("styles"))
|
|
1146
|
+
])
|
|
1147
|
+
)
|
|
1148
|
+
]),
|
|
1149
|
+
t2.returnStatement(
|
|
1150
|
+
t2.objectExpression([
|
|
1151
|
+
t2.spreadElement(sxId),
|
|
1152
|
+
t2.objectProperty(
|
|
1153
|
+
t2.identifier("className"),
|
|
1154
|
+
t2.callExpression(
|
|
1155
|
+
t2.memberExpression(
|
|
1156
|
+
t2.binaryExpression(
|
|
1157
|
+
"+",
|
|
1158
|
+
t2.binaryExpression("+", explicitClassNameParam, t2.stringLiteral(" ")),
|
|
1159
|
+
t2.logicalExpression("||", t2.memberExpression(sxId, t2.identifier("className")), t2.stringLiteral(""))
|
|
1160
|
+
),
|
|
1161
|
+
t2.identifier("trim")
|
|
1162
|
+
),
|
|
1163
|
+
[]
|
|
1164
|
+
)
|
|
1165
|
+
)
|
|
1166
|
+
])
|
|
1167
|
+
)
|
|
1168
|
+
])
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1042
1171
|
function buildCreateDeclaration(createVarName, stylexNamespaceName, createProperties) {
|
|
1043
1172
|
const createCall = t2.callExpression(t2.memberExpression(t2.identifier(stylexNamespaceName), t2.identifier("create")), [
|
|
1044
1173
|
t2.objectExpression(createProperties)
|
|
1045
1174
|
]);
|
|
1046
1175
|
return t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(createVarName), createCall)]);
|
|
1047
1176
|
}
|
|
1177
|
+
function buildRuntimeLookupDeclaration(lookupName, createVarName, lookup) {
|
|
1178
|
+
const properties = [];
|
|
1179
|
+
for (const [name, refs] of Object.entries(lookup.refsByName)) {
|
|
1180
|
+
const values = refs.map(function(refKey) {
|
|
1181
|
+
return t2.memberExpression(t2.identifier(createVarName), t2.identifier(refKey));
|
|
1182
|
+
});
|
|
1183
|
+
properties.push(t2.objectProperty(toPropertyKey(name), t2.arrayExpression(values)));
|
|
1184
|
+
}
|
|
1185
|
+
return t2.variableDeclaration("const", [
|
|
1186
|
+
t2.variableDeclarator(t2.identifier(lookupName), t2.objectExpression(properties))
|
|
1187
|
+
]);
|
|
1188
|
+
}
|
|
1048
1189
|
function defsToAst(defs) {
|
|
1049
1190
|
const properties = [];
|
|
1050
1191
|
for (const [key, value] of Object.entries(defs)) {
|
|
@@ -1088,53 +1229,22 @@ function rewriteExpressionSites(options) {
|
|
|
1088
1229
|
t3.memberExpression(t3.identifier(options.stylexNamespaceName), t3.identifier("props")),
|
|
1089
1230
|
propsArgs
|
|
1090
1231
|
);
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
const attr = attrs[i];
|
|
1097
|
-
if (t3.isJSXAttribute(attr) && t3.isJSXIdentifier(attr.name, { name: "className" })) {
|
|
1098
|
-
if (t3.isStringLiteral(attr.value)) {
|
|
1099
|
-
existingClassNameExpr = attr.value;
|
|
1100
|
-
} else if (t3.isJSXExpressionContainer(attr.value) && t3.isExpression(attr.value.expression)) {
|
|
1101
|
-
existingClassNameExpr = attr.value.expression;
|
|
1102
|
-
}
|
|
1103
|
-
attrs.splice(i, 1);
|
|
1104
|
-
break;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
let spreadExpr;
|
|
1109
|
-
if (existingClassNameExpr) {
|
|
1110
|
-
const rId = t3.identifier("__r");
|
|
1111
|
-
const mergedClassName = t3.callExpression(
|
|
1112
|
-
t3.memberExpression(
|
|
1113
|
-
t3.binaryExpression(
|
|
1114
|
-
"+",
|
|
1115
|
-
t3.binaryExpression("+", existingClassNameExpr, t3.stringLiteral(" ")),
|
|
1116
|
-
t3.logicalExpression("||", t3.memberExpression(rId, t3.identifier("className")), t3.stringLiteral(""))
|
|
1117
|
-
),
|
|
1118
|
-
t3.identifier("trim")
|
|
1119
|
-
),
|
|
1120
|
-
[]
|
|
1121
|
-
);
|
|
1122
|
-
spreadExpr = t3.callExpression(
|
|
1123
|
-
t3.arrowFunctionExpression(
|
|
1124
|
-
[rId],
|
|
1125
|
-
t3.objectExpression([t3.spreadElement(rId), t3.objectProperty(t3.identifier("className"), mergedClassName)])
|
|
1126
|
-
),
|
|
1127
|
-
[propsCall]
|
|
1128
|
-
);
|
|
1129
|
-
} else {
|
|
1130
|
-
spreadExpr = propsCall;
|
|
1131
|
-
}
|
|
1132
|
-
cssAttrPath.replaceWith(t3.jsxSpreadAttribute(spreadExpr));
|
|
1232
|
+
cssAttrPath.replaceWith(
|
|
1233
|
+
t3.jsxSpreadAttribute(
|
|
1234
|
+
buildCssSpreadExpression(cssAttrPath, propsCall, options.mergePropsHelperName, options.needsMergePropsHelper)
|
|
1235
|
+
)
|
|
1236
|
+
);
|
|
1133
1237
|
continue;
|
|
1134
1238
|
}
|
|
1135
1239
|
site.path.replaceWith(t3.arrayExpression(propsArgs));
|
|
1136
1240
|
}
|
|
1137
|
-
|
|
1241
|
+
rewriteStyleObjectExpressions(options.ast);
|
|
1242
|
+
rewriteCssAttributeExpressions(
|
|
1243
|
+
options.ast,
|
|
1244
|
+
options.stylexNamespaceName,
|
|
1245
|
+
options.mergePropsHelperName,
|
|
1246
|
+
options.needsMergePropsHelper
|
|
1247
|
+
);
|
|
1138
1248
|
}
|
|
1139
1249
|
function getCssAttributePath(path) {
|
|
1140
1250
|
const parentPath = path.parentPath;
|
|
@@ -1165,7 +1275,7 @@ function buildPropsArgsFromChain(chain, options) {
|
|
|
1165
1275
|
}
|
|
1166
1276
|
const thenArgs = buildPropsArgs(part.thenSegments, options);
|
|
1167
1277
|
const elseArgs = buildPropsArgs(part.elseSegments, options);
|
|
1168
|
-
if (thenArgs.length === 1 && elseArgs.length === 1) {
|
|
1278
|
+
if (thenArgs.length === 1 && elseArgs.length === 1 && !t3.isSpreadElement(thenArgs[0]) && !t3.isSpreadElement(elseArgs[0])) {
|
|
1169
1279
|
args.push(t3.conditionalExpression(part.conditionNode, thenArgs[0], elseArgs[0]));
|
|
1170
1280
|
} else if (thenArgs.length > 0 || elseArgs.length > 0) {
|
|
1171
1281
|
args.push(
|
|
@@ -1181,6 +1291,19 @@ function buildPropsArgs(segments, options) {
|
|
|
1181
1291
|
const args = [];
|
|
1182
1292
|
for (const seg of segments) {
|
|
1183
1293
|
if (seg.error) continue;
|
|
1294
|
+
if (seg.typographyLookup) {
|
|
1295
|
+
const lookupName = options.runtimeLookupNames.get(seg.typographyLookup.lookupKey);
|
|
1296
|
+
if (!lookupName) {
|
|
1297
|
+
continue;
|
|
1298
|
+
}
|
|
1299
|
+
const lookupAccess = t3.memberExpression(
|
|
1300
|
+
t3.identifier(lookupName),
|
|
1301
|
+
seg.typographyLookup.argNode,
|
|
1302
|
+
true
|
|
1303
|
+
);
|
|
1304
|
+
args.push(t3.spreadElement(t3.logicalExpression("??", lookupAccess, t3.arrayExpression([]))));
|
|
1305
|
+
continue;
|
|
1306
|
+
}
|
|
1184
1307
|
const ref = t3.memberExpression(t3.identifier(options.createVarName), t3.identifier(seg.key));
|
|
1185
1308
|
if (seg.dynamicProps && seg.argNode) {
|
|
1186
1309
|
let argExpr;
|
|
@@ -1198,42 +1321,271 @@ function buildPropsArgs(segments, options) {
|
|
|
1198
1321
|
}
|
|
1199
1322
|
return args;
|
|
1200
1323
|
}
|
|
1201
|
-
function
|
|
1324
|
+
function rewriteCssAttributeExpressions(ast, stylexNamespaceName, mergePropsHelperName, needsMergePropsHelper) {
|
|
1202
1325
|
traverse(ast, {
|
|
1203
1326
|
JSXAttribute(path) {
|
|
1204
1327
|
if (!t3.isJSXIdentifier(path.node.name, { name: "css" })) return;
|
|
1205
1328
|
const value = path.node.value;
|
|
1206
1329
|
if (!t3.isJSXExpressionContainer(value)) return;
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
for (const el of expr.elements) {
|
|
1211
|
-
if (t3.isSpreadElement(el)) {
|
|
1212
|
-
const arg = el.argument;
|
|
1213
|
-
if (t3.isArrayExpression(arg)) {
|
|
1214
|
-
for (const inner of arg.elements) {
|
|
1215
|
-
if (!inner) continue;
|
|
1216
|
-
if (t3.isSpreadElement(inner)) {
|
|
1217
|
-
propsArgs.push(t3.spreadElement(inner.argument));
|
|
1218
|
-
} else {
|
|
1219
|
-
propsArgs.push(inner);
|
|
1220
|
-
}
|
|
1221
|
-
}
|
|
1222
|
-
} else {
|
|
1223
|
-
propsArgs.push(t3.spreadElement(arg));
|
|
1224
|
-
}
|
|
1225
|
-
} else if (el) {
|
|
1226
|
-
propsArgs.push(el);
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1330
|
+
if (!t3.isExpression(value.expression)) return;
|
|
1331
|
+
const propsArgs = buildStyleObjectPropsArgs(value.expression, path) ?? buildStyleArrayLikePropsArgsFromExpression(value.expression, path);
|
|
1332
|
+
if (!propsArgs) return;
|
|
1229
1333
|
const propsCall = t3.callExpression(
|
|
1230
1334
|
t3.memberExpression(t3.identifier(stylexNamespaceName), t3.identifier("props")),
|
|
1231
1335
|
propsArgs
|
|
1232
1336
|
);
|
|
1233
|
-
path.replaceWith(
|
|
1337
|
+
path.replaceWith(
|
|
1338
|
+
t3.jsxSpreadAttribute(buildCssSpreadExpression(path, propsCall, mergePropsHelperName, needsMergePropsHelper))
|
|
1339
|
+
);
|
|
1234
1340
|
}
|
|
1235
1341
|
});
|
|
1236
1342
|
}
|
|
1343
|
+
function buildCssSpreadExpression(path, propsCall, mergePropsHelperName, needsMergePropsHelper) {
|
|
1344
|
+
const existingClassNameExpr = removeExistingClassNameAttribute(path);
|
|
1345
|
+
if (!existingClassNameExpr) return propsCall;
|
|
1346
|
+
needsMergePropsHelper.current = true;
|
|
1347
|
+
return t3.callExpression(t3.identifier(mergePropsHelperName), [existingClassNameExpr, ...propsCall.arguments]);
|
|
1348
|
+
}
|
|
1349
|
+
function removeExistingClassNameAttribute(path) {
|
|
1350
|
+
const openingElement = path.parentPath;
|
|
1351
|
+
if (!openingElement || !openingElement.isJSXOpeningElement()) return null;
|
|
1352
|
+
const attrs = openingElement.node.attributes;
|
|
1353
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
1354
|
+
const attr = attrs[i];
|
|
1355
|
+
if (!t3.isJSXAttribute(attr) || !t3.isJSXIdentifier(attr.name, { name: "className" })) continue;
|
|
1356
|
+
let classNameExpr = null;
|
|
1357
|
+
if (t3.isStringLiteral(attr.value)) {
|
|
1358
|
+
classNameExpr = attr.value;
|
|
1359
|
+
} else if (t3.isJSXExpressionContainer(attr.value) && t3.isExpression(attr.value.expression)) {
|
|
1360
|
+
classNameExpr = attr.value.expression;
|
|
1361
|
+
}
|
|
1362
|
+
attrs.splice(i, 1);
|
|
1363
|
+
return classNameExpr;
|
|
1364
|
+
}
|
|
1365
|
+
return null;
|
|
1366
|
+
}
|
|
1367
|
+
function buildStyleObjectPropsArgs(expr, path) {
|
|
1368
|
+
if (!t3.isObjectExpression(expr) || expr.properties.length === 0) return null;
|
|
1369
|
+
let sawStyleArray = false;
|
|
1370
|
+
const propsArgs = [];
|
|
1371
|
+
for (const prop of expr.properties) {
|
|
1372
|
+
if (!t3.isSpreadElement(prop)) return null;
|
|
1373
|
+
const normalizedArg = normalizeStyleArrayLikeExpression(prop.argument, path, /* @__PURE__ */ new Set());
|
|
1374
|
+
if (!normalizedArg) {
|
|
1375
|
+
propsArgs.push(t3.spreadElement(prop.argument));
|
|
1376
|
+
continue;
|
|
1377
|
+
}
|
|
1378
|
+
if (isStyleArrayLike(normalizedArg, path, /* @__PURE__ */ new Set())) {
|
|
1379
|
+
sawStyleArray = true;
|
|
1380
|
+
}
|
|
1381
|
+
const nestedArgs = buildStyleArrayLikePropsArgs(normalizedArg, path, /* @__PURE__ */ new Set());
|
|
1382
|
+
if (nestedArgs && t3.isArrayExpression(normalizedArg)) {
|
|
1383
|
+
propsArgs.push(...nestedArgs);
|
|
1384
|
+
} else {
|
|
1385
|
+
propsArgs.push(t3.spreadElement(normalizedArg));
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
return sawStyleArray ? propsArgs : null;
|
|
1389
|
+
}
|
|
1390
|
+
function buildStyleArrayLikePropsArgsFromExpression(expr, path) {
|
|
1391
|
+
const normalizedExpr = normalizeStyleArrayLikeExpression(expr, path, /* @__PURE__ */ new Set());
|
|
1392
|
+
if (!normalizedExpr) return null;
|
|
1393
|
+
return buildStyleArrayLikePropsArgs(normalizedExpr, path, /* @__PURE__ */ new Set());
|
|
1394
|
+
}
|
|
1395
|
+
function buildStyleArrayLikePropsArgs(expr, path, seen) {
|
|
1396
|
+
if (seen.has(expr)) return null;
|
|
1397
|
+
seen.add(expr);
|
|
1398
|
+
if (t3.isArrayExpression(expr)) {
|
|
1399
|
+
const propsArgs = [];
|
|
1400
|
+
for (const el of expr.elements) {
|
|
1401
|
+
if (!el) continue;
|
|
1402
|
+
if (t3.isSpreadElement(el)) {
|
|
1403
|
+
const normalizedArg = normalizeStyleArrayLikeExpression(el.argument, path, /* @__PURE__ */ new Set());
|
|
1404
|
+
if (!normalizedArg) {
|
|
1405
|
+
propsArgs.push(t3.spreadElement(el.argument));
|
|
1406
|
+
continue;
|
|
1407
|
+
}
|
|
1408
|
+
const nestedArgs = buildStyleArrayLikePropsArgs(normalizedArg, path, seen);
|
|
1409
|
+
if (nestedArgs && t3.isArrayExpression(normalizedArg)) {
|
|
1410
|
+
propsArgs.push(...nestedArgs);
|
|
1411
|
+
} else {
|
|
1412
|
+
propsArgs.push(t3.spreadElement(normalizedArg));
|
|
1413
|
+
}
|
|
1414
|
+
continue;
|
|
1415
|
+
}
|
|
1416
|
+
propsArgs.push(el);
|
|
1417
|
+
}
|
|
1418
|
+
return propsArgs;
|
|
1419
|
+
}
|
|
1420
|
+
if (t3.isIdentifier(expr) || t3.isMemberExpression(expr) || t3.isConditionalExpression(expr) || t3.isLogicalExpression(expr) || t3.isCallExpression(expr)) {
|
|
1421
|
+
return [t3.spreadElement(expr)];
|
|
1422
|
+
}
|
|
1423
|
+
return null;
|
|
1424
|
+
}
|
|
1425
|
+
function rewriteStyleObjectExpressions(ast) {
|
|
1426
|
+
traverse(ast, {
|
|
1427
|
+
ObjectExpression(path) {
|
|
1428
|
+
const rewritten = tryBuildStyleArrayFromObject(path);
|
|
1429
|
+
if (!rewritten) return;
|
|
1430
|
+
path.replaceWith(rewritten);
|
|
1431
|
+
}
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
function tryBuildStyleArrayFromObject(path) {
|
|
1435
|
+
if (path.node.properties.length === 0) return null;
|
|
1436
|
+
let sawStyleArray = false;
|
|
1437
|
+
const elements = [];
|
|
1438
|
+
for (const prop of path.node.properties) {
|
|
1439
|
+
if (!t3.isSpreadElement(prop)) {
|
|
1440
|
+
return null;
|
|
1441
|
+
}
|
|
1442
|
+
const normalizedArg = normalizeStyleArrayLikeExpression(
|
|
1443
|
+
prop.argument,
|
|
1444
|
+
path,
|
|
1445
|
+
/* @__PURE__ */ new Set()
|
|
1446
|
+
// I.e. `...Css.df.$`, `...(cond ? Css.df.$ : {})`, or `...styles.wrapper`
|
|
1447
|
+
);
|
|
1448
|
+
if (!normalizedArg) {
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
if (isStyleArrayLike(normalizedArg, path, /* @__PURE__ */ new Set())) {
|
|
1452
|
+
sawStyleArray = true;
|
|
1453
|
+
}
|
|
1454
|
+
if (t3.isArrayExpression(normalizedArg)) {
|
|
1455
|
+
elements.push(...normalizedArg.elements);
|
|
1456
|
+
continue;
|
|
1457
|
+
}
|
|
1458
|
+
elements.push(t3.spreadElement(normalizedArg));
|
|
1459
|
+
}
|
|
1460
|
+
if (!sawStyleArray) return null;
|
|
1461
|
+
return t3.arrayExpression(elements);
|
|
1462
|
+
}
|
|
1463
|
+
function normalizeStyleArrayLikeExpression(expr, path, seen) {
|
|
1464
|
+
if (seen.has(expr)) return null;
|
|
1465
|
+
seen.add(expr);
|
|
1466
|
+
if (t3.isArrayExpression(expr)) return expr;
|
|
1467
|
+
if (t3.isLogicalExpression(expr) && expr.operator === "&&") {
|
|
1468
|
+
const consequent = normalizeStyleArrayLikeExpression(expr.right, path, seen);
|
|
1469
|
+
if (!consequent) return null;
|
|
1470
|
+
return t3.conditionalExpression(expr.left, consequent, t3.arrayExpression([]));
|
|
1471
|
+
}
|
|
1472
|
+
if (t3.isLogicalExpression(expr) && (expr.operator === "||" || expr.operator === "??")) {
|
|
1473
|
+
const left = normalizeStyleArrayLikeExpression(expr.left, path, seen);
|
|
1474
|
+
const right = normalizeStyleArrayLikeBranch(expr.right, path, seen);
|
|
1475
|
+
if (!left || !right) return null;
|
|
1476
|
+
return t3.logicalExpression(expr.operator, left, right);
|
|
1477
|
+
}
|
|
1478
|
+
if (t3.isConditionalExpression(expr)) {
|
|
1479
|
+
const consequent = normalizeStyleArrayLikeBranch(expr.consequent, path, seen);
|
|
1480
|
+
const alternate = normalizeStyleArrayLikeBranch(expr.alternate, path, seen);
|
|
1481
|
+
if (!consequent || !alternate) return null;
|
|
1482
|
+
return t3.conditionalExpression(expr.test, consequent, alternate);
|
|
1483
|
+
}
|
|
1484
|
+
if (t3.isIdentifier(expr) || t3.isMemberExpression(expr) || t3.isCallExpression(expr)) {
|
|
1485
|
+
const nestedSeen = new Set(seen);
|
|
1486
|
+
nestedSeen.delete(expr);
|
|
1487
|
+
if (isStyleArrayLike(expr, path, nestedSeen)) return expr;
|
|
1488
|
+
}
|
|
1489
|
+
return null;
|
|
1490
|
+
}
|
|
1491
|
+
function normalizeStyleArrayLikeBranch(expr, path, seen) {
|
|
1492
|
+
if (isEmptyObjectExpression(expr)) {
|
|
1493
|
+
return t3.arrayExpression([]);
|
|
1494
|
+
}
|
|
1495
|
+
return normalizeStyleArrayLikeExpression(expr, path, seen);
|
|
1496
|
+
}
|
|
1497
|
+
function isStyleArrayLike(expr, path, seen) {
|
|
1498
|
+
if (seen.has(expr)) return false;
|
|
1499
|
+
seen.add(expr);
|
|
1500
|
+
if (t3.isArrayExpression(expr)) return true;
|
|
1501
|
+
if (t3.isLogicalExpression(expr) && expr.operator === "&&") {
|
|
1502
|
+
return isStyleArrayLike(expr.right, path, seen);
|
|
1503
|
+
}
|
|
1504
|
+
if (t3.isLogicalExpression(expr) && (expr.operator === "||" || expr.operator === "??")) {
|
|
1505
|
+
return isStyleArrayLike(expr.left, path, seen) && isStyleArrayLikeBranch(expr.right, path, seen);
|
|
1506
|
+
}
|
|
1507
|
+
if (t3.isConditionalExpression(expr)) {
|
|
1508
|
+
return isStyleArrayLikeBranch(expr.consequent, path, seen) && isStyleArrayLikeBranch(expr.alternate, path, seen);
|
|
1509
|
+
}
|
|
1510
|
+
if (t3.isIdentifier(expr)) {
|
|
1511
|
+
const binding = path.scope.getBinding(expr.name);
|
|
1512
|
+
const bindingPath = binding?.path;
|
|
1513
|
+
if (!bindingPath || !bindingPath.isVariableDeclarator()) return false;
|
|
1514
|
+
const init = bindingPath.node.init;
|
|
1515
|
+
return !!(init && isStyleArrayLike(init, bindingPath, seen));
|
|
1516
|
+
}
|
|
1517
|
+
if (t3.isCallExpression(expr)) {
|
|
1518
|
+
const returnExpr = getLocalFunctionReturnExpression(expr, path);
|
|
1519
|
+
return !!(returnExpr && isStyleArrayLike(returnExpr, path, seen));
|
|
1520
|
+
}
|
|
1521
|
+
if (t3.isMemberExpression(expr)) {
|
|
1522
|
+
const object = expr.object;
|
|
1523
|
+
if (!t3.isIdentifier(object)) return false;
|
|
1524
|
+
const binding = path.scope.getBinding(object.name);
|
|
1525
|
+
const bindingPath = binding?.path;
|
|
1526
|
+
if (!bindingPath || !bindingPath.isVariableDeclarator()) return false;
|
|
1527
|
+
const init = bindingPath.node.init;
|
|
1528
|
+
if (!init || !t3.isObjectExpression(init)) return false;
|
|
1529
|
+
const propertyName = getStaticMemberPropertyName(expr, path);
|
|
1530
|
+
if (!propertyName) return false;
|
|
1531
|
+
for (const prop of init.properties) {
|
|
1532
|
+
if (!t3.isObjectProperty(prop) || prop.computed) continue;
|
|
1533
|
+
if (!isMatchingPropertyName(prop.key, propertyName)) continue;
|
|
1534
|
+
const value = prop.value;
|
|
1535
|
+
return t3.isExpression(value) && isStyleArrayLike(value, bindingPath, seen);
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
return false;
|
|
1539
|
+
}
|
|
1540
|
+
function isStyleArrayLikeBranch(expr, path, seen) {
|
|
1541
|
+
return isEmptyObjectExpression(expr) || isStyleArrayLike(expr, path, seen);
|
|
1542
|
+
}
|
|
1543
|
+
function isMatchingPropertyName(key, name) {
|
|
1544
|
+
return t3.isIdentifier(key) && key.name === name || t3.isStringLiteral(key) && key.value === name;
|
|
1545
|
+
}
|
|
1546
|
+
function isEmptyObjectExpression(expr) {
|
|
1547
|
+
return t3.isObjectExpression(expr) && expr.properties.length === 0;
|
|
1548
|
+
}
|
|
1549
|
+
function getStaticMemberPropertyName(expr, path) {
|
|
1550
|
+
if (!expr.computed && t3.isIdentifier(expr.property)) {
|
|
1551
|
+
return expr.property.name;
|
|
1552
|
+
}
|
|
1553
|
+
if (t3.isStringLiteral(expr.property)) {
|
|
1554
|
+
return expr.property.value;
|
|
1555
|
+
}
|
|
1556
|
+
if (t3.isIdentifier(expr.property)) {
|
|
1557
|
+
const binding = path.scope.getBinding(expr.property.name);
|
|
1558
|
+
const bindingPath = binding?.path;
|
|
1559
|
+
if (!bindingPath || !bindingPath.isVariableDeclarator()) return null;
|
|
1560
|
+
const init = bindingPath.node.init;
|
|
1561
|
+
return t3.isStringLiteral(init) ? init.value : null;
|
|
1562
|
+
}
|
|
1563
|
+
return null;
|
|
1564
|
+
}
|
|
1565
|
+
function getLocalFunctionReturnExpression(expr, path) {
|
|
1566
|
+
if (!t3.isIdentifier(expr.callee)) return null;
|
|
1567
|
+
const binding = path.scope.getBinding(expr.callee.name);
|
|
1568
|
+
const bindingPath = binding?.path;
|
|
1569
|
+
if (!bindingPath) return null;
|
|
1570
|
+
if (bindingPath.isFunctionDeclaration()) {
|
|
1571
|
+
return getFunctionLikeReturnExpression(bindingPath.node);
|
|
1572
|
+
}
|
|
1573
|
+
if (bindingPath.isVariableDeclarator()) {
|
|
1574
|
+
const init = bindingPath.node.init;
|
|
1575
|
+
if (init && (t3.isArrowFunctionExpression(init) || t3.isFunctionExpression(init))) {
|
|
1576
|
+
return getFunctionLikeReturnExpression(init);
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
return null;
|
|
1580
|
+
}
|
|
1581
|
+
function getFunctionLikeReturnExpression(fn) {
|
|
1582
|
+
if (t3.isExpression(fn.body)) {
|
|
1583
|
+
return fn.body;
|
|
1584
|
+
}
|
|
1585
|
+
if (fn.body.body.length !== 1) return null;
|
|
1586
|
+
const stmt = fn.body.body[0];
|
|
1587
|
+
return t3.isReturnStatement(stmt) && stmt.argument && t3.isExpression(stmt.argument) ? stmt.argument : null;
|
|
1588
|
+
}
|
|
1237
1589
|
|
|
1238
1590
|
// src/plugin/transform.ts
|
|
1239
1591
|
var traverse2 = _traverse2.default ?? _traverse2;
|
|
@@ -1268,19 +1620,28 @@ function transformTruss(code, filename, mapping) {
|
|
|
1268
1620
|
}
|
|
1269
1621
|
});
|
|
1270
1622
|
if (sites.length === 0) return null;
|
|
1271
|
-
const { createEntries, needsMaybeInc } = collectCreateData(sites.map((s) => s.resolvedChain));
|
|
1623
|
+
const { createEntries, runtimeLookups, needsMaybeInc } = collectCreateData(sites.map((s) => s.resolvedChain));
|
|
1272
1624
|
const usedTopLevelNames = collectTopLevelBindings(ast);
|
|
1273
1625
|
const existingStylexNamespace = findStylexNamespaceImport(ast);
|
|
1274
1626
|
const stylexNamespaceName = existingStylexNamespace ?? reservePreferredName(usedTopLevelNames, "stylex");
|
|
1275
1627
|
const createVarName = reservePreferredName(usedTopLevelNames, "css", "css_");
|
|
1276
1628
|
const maybeIncHelperName = needsMaybeInc ? reservePreferredName(usedTopLevelNames, "__maybeInc") : null;
|
|
1629
|
+
const mergePropsHelperName = reservePreferredName(usedTopLevelNames, "__mergeProps");
|
|
1630
|
+
const needsMergePropsHelper = { current: false };
|
|
1631
|
+
const runtimeLookupNames = /* @__PURE__ */ new Map();
|
|
1632
|
+
for (const [lookupKey] of runtimeLookups) {
|
|
1633
|
+
runtimeLookupNames.set(lookupKey, reservePreferredName(usedTopLevelNames, `__${lookupKey}`));
|
|
1634
|
+
}
|
|
1277
1635
|
const createProperties = buildCreateProperties(createEntries, stylexNamespaceName);
|
|
1278
1636
|
rewriteExpressionSites({
|
|
1279
1637
|
ast,
|
|
1280
1638
|
sites,
|
|
1281
1639
|
createVarName,
|
|
1282
1640
|
stylexNamespaceName,
|
|
1283
|
-
maybeIncHelperName
|
|
1641
|
+
maybeIncHelperName,
|
|
1642
|
+
mergePropsHelperName,
|
|
1643
|
+
needsMergePropsHelper,
|
|
1644
|
+
runtimeLookupNames
|
|
1284
1645
|
});
|
|
1285
1646
|
removeCssImport(ast, cssBindingName);
|
|
1286
1647
|
if (!findStylexNamespaceImport(ast)) {
|
|
@@ -1292,9 +1653,17 @@ function transformTruss(code, filename, mapping) {
|
|
|
1292
1653
|
if (maybeIncHelperName) {
|
|
1293
1654
|
declarationsToInsert.push(buildMaybeIncDeclaration(maybeIncHelperName, mapping.increment));
|
|
1294
1655
|
}
|
|
1656
|
+
if (needsMergePropsHelper.current) {
|
|
1657
|
+
declarationsToInsert.push(buildMergePropsDeclaration(mergePropsHelperName, stylexNamespaceName));
|
|
1658
|
+
}
|
|
1295
1659
|
declarationsToInsert.push(...hoistedMarkerDecls);
|
|
1296
1660
|
if (createProperties.length > 0) {
|
|
1297
1661
|
declarationsToInsert.push(buildCreateDeclaration(createVarName, stylexNamespaceName, createProperties));
|
|
1662
|
+
for (const [lookupKey, lookup] of runtimeLookups) {
|
|
1663
|
+
const lookupName = runtimeLookupNames.get(lookupKey);
|
|
1664
|
+
if (!lookupName) continue;
|
|
1665
|
+
declarationsToInsert.push(buildRuntimeLookupDeclaration(lookupName, createVarName, lookup));
|
|
1666
|
+
}
|
|
1298
1667
|
}
|
|
1299
1668
|
for (const { message, line } of errorMessages) {
|
|
1300
1669
|
const location = line !== null ? `${filename}:${line}` : filename;
|
|
@@ -1358,7 +1727,72 @@ function hoistMarkerDeclarations(ast, names) {
|
|
|
1358
1727
|
|
|
1359
1728
|
// src/plugin/transform-css.ts
|
|
1360
1729
|
import { parse as parse2 } from "@babel/parser";
|
|
1730
|
+
import * as t6 from "@babel/types";
|
|
1731
|
+
|
|
1732
|
+
// src/plugin/css-ts-utils.ts
|
|
1361
1733
|
import * as t5 from "@babel/types";
|
|
1734
|
+
function collectStaticStringBindings(ast) {
|
|
1735
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
1736
|
+
let changed = true;
|
|
1737
|
+
while (changed) {
|
|
1738
|
+
changed = false;
|
|
1739
|
+
for (const node of ast.program.body) {
|
|
1740
|
+
const declaration = getTopLevelVariableDeclaration(node);
|
|
1741
|
+
if (!declaration) continue;
|
|
1742
|
+
for (const declarator of declaration.declarations) {
|
|
1743
|
+
if (!t5.isIdentifier(declarator.id) || !declarator.init) continue;
|
|
1744
|
+
if (bindings.has(declarator.id.name)) continue;
|
|
1745
|
+
const value = resolveStaticString(declarator.init, bindings);
|
|
1746
|
+
if (value === null) continue;
|
|
1747
|
+
bindings.set(declarator.id.name, value);
|
|
1748
|
+
changed = true;
|
|
1749
|
+
}
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
return bindings;
|
|
1753
|
+
}
|
|
1754
|
+
function resolveStaticString(node, bindings) {
|
|
1755
|
+
if (!node) return null;
|
|
1756
|
+
if (t5.isStringLiteral(node)) return node.value;
|
|
1757
|
+
if (t5.isTemplateLiteral(node)) {
|
|
1758
|
+
let value = "";
|
|
1759
|
+
for (let i = 0; i < node.quasis.length; i++) {
|
|
1760
|
+
value += node.quasis[i].value.cooked ?? "";
|
|
1761
|
+
if (i >= node.expressions.length) continue;
|
|
1762
|
+
const expressionValue = resolveStaticString(node.expressions[i], bindings);
|
|
1763
|
+
if (expressionValue === null) return null;
|
|
1764
|
+
value += expressionValue;
|
|
1765
|
+
}
|
|
1766
|
+
return value;
|
|
1767
|
+
}
|
|
1768
|
+
if (t5.isIdentifier(node)) {
|
|
1769
|
+
return bindings.get(node.name) ?? null;
|
|
1770
|
+
}
|
|
1771
|
+
if (t5.isTSAsExpression(node) || t5.isTSSatisfiesExpression(node) || t5.isTSNonNullExpression(node)) {
|
|
1772
|
+
return resolveStaticString(node.expression, bindings);
|
|
1773
|
+
}
|
|
1774
|
+
if (t5.isParenthesizedExpression(node)) {
|
|
1775
|
+
return resolveStaticString(node.expression, bindings);
|
|
1776
|
+
}
|
|
1777
|
+
if (t5.isBinaryExpression(node, { operator: "+" })) {
|
|
1778
|
+
const left = resolveStaticString(node.left, bindings);
|
|
1779
|
+
const right = resolveStaticString(node.right, bindings);
|
|
1780
|
+
if (left === null || right === null) return null;
|
|
1781
|
+
return left + right;
|
|
1782
|
+
}
|
|
1783
|
+
return null;
|
|
1784
|
+
}
|
|
1785
|
+
function getTopLevelVariableDeclaration(node) {
|
|
1786
|
+
if (t5.isVariableDeclaration(node)) {
|
|
1787
|
+
return node;
|
|
1788
|
+
}
|
|
1789
|
+
if (t5.isExportNamedDeclaration(node) && node.declaration && t5.isVariableDeclaration(node.declaration)) {
|
|
1790
|
+
return node.declaration;
|
|
1791
|
+
}
|
|
1792
|
+
return null;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
// src/plugin/transform-css.ts
|
|
1362
1796
|
function transformCssTs(code, filename, mapping) {
|
|
1363
1797
|
const ast = parse2(code, {
|
|
1364
1798
|
sourceType: "module",
|
|
@@ -1370,28 +1804,29 @@ function transformCssTs(code, filename, mapping) {
|
|
|
1370
1804
|
return `/* [truss] ${filename}: no Css import found */
|
|
1371
1805
|
`;
|
|
1372
1806
|
}
|
|
1373
|
-
const
|
|
1374
|
-
if (!
|
|
1375
|
-
return `/* [truss] ${filename}: expected \`export
|
|
1807
|
+
const cssExport = findNamedCssExportObject(ast);
|
|
1808
|
+
if (!cssExport) {
|
|
1809
|
+
return `/* [truss] ${filename}: expected \`export const css = { ... }\` with an object literal */
|
|
1376
1810
|
`;
|
|
1377
1811
|
}
|
|
1378
1812
|
const rules = [];
|
|
1379
|
-
|
|
1380
|
-
|
|
1813
|
+
const stringBindings = collectStaticStringBindings(ast);
|
|
1814
|
+
for (const prop of cssExport.properties) {
|
|
1815
|
+
if (t6.isSpreadElement(prop)) {
|
|
1381
1816
|
rules.push(`/* [truss] unsupported: spread elements in css.ts export */`);
|
|
1382
1817
|
continue;
|
|
1383
1818
|
}
|
|
1384
|
-
if (!
|
|
1819
|
+
if (!t6.isObjectProperty(prop)) {
|
|
1385
1820
|
rules.push(`/* [truss] unsupported: non-property in css.ts export */`);
|
|
1386
1821
|
continue;
|
|
1387
1822
|
}
|
|
1388
|
-
const selector = objectPropertyStringKey(prop);
|
|
1823
|
+
const selector = objectPropertyStringKey(prop, stringBindings);
|
|
1389
1824
|
if (selector === null) {
|
|
1390
1825
|
rules.push(`/* [truss] unsupported: non-string-literal key in css.ts export */`);
|
|
1391
1826
|
continue;
|
|
1392
1827
|
}
|
|
1393
1828
|
const valueNode = prop.value;
|
|
1394
|
-
if (!
|
|
1829
|
+
if (!t6.isExpression(valueNode)) {
|
|
1395
1830
|
rules.push(`/* [truss] unsupported: "${selector}" value is not an expression */`);
|
|
1396
1831
|
continue;
|
|
1397
1832
|
}
|
|
@@ -1404,23 +1839,32 @@ function transformCssTs(code, filename, mapping) {
|
|
|
1404
1839
|
}
|
|
1405
1840
|
return rules.join("\n\n") + "\n";
|
|
1406
1841
|
}
|
|
1407
|
-
function
|
|
1842
|
+
function findNamedCssExportObject(ast) {
|
|
1408
1843
|
for (const node of ast.program.body) {
|
|
1409
|
-
if (!
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1844
|
+
if (!t6.isExportNamedDeclaration(node) || !node.declaration) continue;
|
|
1845
|
+
if (!t6.isVariableDeclaration(node.declaration)) continue;
|
|
1846
|
+
for (const declarator of node.declaration.declarations) {
|
|
1847
|
+
if (!t6.isIdentifier(declarator.id, { name: "css" })) continue;
|
|
1848
|
+
const value = unwrapObjectExpression(declarator.init);
|
|
1849
|
+
if (value) return value;
|
|
1850
|
+
}
|
|
1414
1851
|
}
|
|
1415
1852
|
return null;
|
|
1416
1853
|
}
|
|
1417
|
-
function
|
|
1418
|
-
if (
|
|
1419
|
-
if (
|
|
1854
|
+
function unwrapObjectExpression(node) {
|
|
1855
|
+
if (!node) return null;
|
|
1856
|
+
if (t6.isObjectExpression(node)) return node;
|
|
1857
|
+
if (t6.isTSAsExpression(node) || t6.isTSSatisfiesExpression(node)) return unwrapObjectExpression(node.expression);
|
|
1858
|
+
return null;
|
|
1859
|
+
}
|
|
1860
|
+
function objectPropertyStringKey(prop, stringBindings) {
|
|
1861
|
+
if (t6.isStringLiteral(prop.key)) return prop.key.value;
|
|
1862
|
+
if (t6.isIdentifier(prop.key) && !prop.computed) return prop.key.name;
|
|
1863
|
+
if (prop.computed) return resolveStaticString(prop.key, stringBindings);
|
|
1420
1864
|
return null;
|
|
1421
1865
|
}
|
|
1422
1866
|
function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
1423
|
-
if (!
|
|
1867
|
+
if (!t6.isMemberExpression(node) || node.computed || !t6.isIdentifier(node.property, { name: "$" })) {
|
|
1424
1868
|
return { error: "value must be a Css.*.$ expression" };
|
|
1425
1869
|
}
|
|
1426
1870
|
const chain = extractChain(node.object, cssBindingName);
|
|
@@ -1450,6 +1894,9 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
|
1450
1894
|
if (seg.dynamicProps && !seg.argResolved) {
|
|
1451
1895
|
return { error: `dynamic value with variable argument is not supported in .css.ts files` };
|
|
1452
1896
|
}
|
|
1897
|
+
if (seg.typographyLookup) {
|
|
1898
|
+
return { error: `typography() with a runtime key is not supported in .css.ts files` };
|
|
1899
|
+
}
|
|
1453
1900
|
if (seg.mediaQuery) {
|
|
1454
1901
|
return { error: `media query modifiers (ifSm, ifMd, etc.) are not supported in .css.ts files` };
|
|
1455
1902
|
}
|
|
@@ -1486,8 +1933,61 @@ ${body}
|
|
|
1486
1933
|
}`;
|
|
1487
1934
|
}
|
|
1488
1935
|
|
|
1936
|
+
// src/plugin/rewrite-css-ts-imports.ts
|
|
1937
|
+
import { parse as parse3 } from "@babel/parser";
|
|
1938
|
+
import _generate2 from "@babel/generator";
|
|
1939
|
+
import * as t7 from "@babel/types";
|
|
1940
|
+
var generate2 = _generate2.default ?? _generate2;
|
|
1941
|
+
function rewriteCssTsImports(code, filename) {
|
|
1942
|
+
if (!code.includes(".css.ts")) {
|
|
1943
|
+
return { code, changed: false };
|
|
1944
|
+
}
|
|
1945
|
+
const ast = parse3(code, {
|
|
1946
|
+
sourceType: "module",
|
|
1947
|
+
plugins: ["typescript", "jsx"],
|
|
1948
|
+
sourceFilename: filename
|
|
1949
|
+
});
|
|
1950
|
+
const existingCssSideEffects = /* @__PURE__ */ new Set();
|
|
1951
|
+
const neededCssSideEffects = /* @__PURE__ */ new Set();
|
|
1952
|
+
let changed = false;
|
|
1953
|
+
for (const node of ast.program.body) {
|
|
1954
|
+
if (!t7.isImportDeclaration(node)) continue;
|
|
1955
|
+
if (typeof node.source.value !== "string") continue;
|
|
1956
|
+
if (!node.source.value.endsWith(".css.ts")) continue;
|
|
1957
|
+
if (node.specifiers.length === 0) {
|
|
1958
|
+
node.source = t7.stringLiteral(toVirtualCssSpecifier(node.source.value));
|
|
1959
|
+
existingCssSideEffects.add(node.source.value);
|
|
1960
|
+
changed = true;
|
|
1961
|
+
continue;
|
|
1962
|
+
}
|
|
1963
|
+
neededCssSideEffects.add(toVirtualCssSpecifier(node.source.value));
|
|
1964
|
+
}
|
|
1965
|
+
const sideEffectImports = [];
|
|
1966
|
+
for (const source of neededCssSideEffects) {
|
|
1967
|
+
if (existingCssSideEffects.has(source)) continue;
|
|
1968
|
+
sideEffectImports.push(t7.importDeclaration([], t7.stringLiteral(source)));
|
|
1969
|
+
changed = true;
|
|
1970
|
+
}
|
|
1971
|
+
if (!changed) {
|
|
1972
|
+
return { code, changed: false };
|
|
1973
|
+
}
|
|
1974
|
+
if (sideEffectImports.length > 0) {
|
|
1975
|
+
const insertIndex = findLastImportIndex(ast) + 1;
|
|
1976
|
+
ast.program.body.splice(insertIndex, 0, ...sideEffectImports);
|
|
1977
|
+
}
|
|
1978
|
+
const output = generate2(ast, {
|
|
1979
|
+
sourceFileName: filename,
|
|
1980
|
+
retainLines: false
|
|
1981
|
+
});
|
|
1982
|
+
return { code: output.code, changed: true };
|
|
1983
|
+
}
|
|
1984
|
+
function toVirtualCssSpecifier(source) {
|
|
1985
|
+
return `${source}?truss-css`;
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1489
1988
|
// src/plugin/index.ts
|
|
1490
1989
|
var VIRTUAL_CSS_PREFIX = "\0truss-css:";
|
|
1990
|
+
var CSS_TS_QUERY = "?truss-css";
|
|
1491
1991
|
function trussPlugin(opts) {
|
|
1492
1992
|
let mapping = null;
|
|
1493
1993
|
let projectRoot;
|
|
@@ -1511,15 +2011,8 @@ function trussPlugin(opts) {
|
|
|
1511
2011
|
ensureMapping();
|
|
1512
2012
|
},
|
|
1513
2013
|
resolveId(source, importer) {
|
|
1514
|
-
if (!source.endsWith(
|
|
1515
|
-
|
|
1516
|
-
if (isAbsolute(source)) {
|
|
1517
|
-
absolutePath = source;
|
|
1518
|
-
} else if (importer) {
|
|
1519
|
-
absolutePath = resolve(dirname(importer), source);
|
|
1520
|
-
} else {
|
|
1521
|
-
absolutePath = resolve(projectRoot || process.cwd(), source);
|
|
1522
|
-
}
|
|
2014
|
+
if (!source.endsWith(CSS_TS_QUERY)) return null;
|
|
2015
|
+
const absolutePath = resolveImportPath(source.slice(0, -CSS_TS_QUERY.length), importer, projectRoot);
|
|
1523
2016
|
if (!existsSync(absolutePath)) return null;
|
|
1524
2017
|
return VIRTUAL_CSS_PREFIX + absolutePath.slice(0, -3);
|
|
1525
2018
|
},
|
|
@@ -1531,17 +2024,38 @@ function trussPlugin(opts) {
|
|
|
1531
2024
|
},
|
|
1532
2025
|
transform(code, id) {
|
|
1533
2026
|
if (!/\.[cm]?[jt]sx?(\?|$)/.test(id)) return null;
|
|
1534
|
-
|
|
2027
|
+
const rewrittenImports = rewriteCssTsImports(code, id);
|
|
2028
|
+
const rewrittenCode = rewrittenImports.code;
|
|
2029
|
+
const hasCssDsl = rewrittenCode.includes("Css");
|
|
2030
|
+
if (!hasCssDsl && !rewrittenImports.changed) return null;
|
|
1535
2031
|
const fileId = stripQueryAndHash(id);
|
|
1536
2032
|
if (isNodeModulesFile(fileId) && !isWhitelistedExternalPackageFile(fileId, externalPackages)) {
|
|
1537
2033
|
return null;
|
|
1538
2034
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
2035
|
+
if (fileId.endsWith(".css.ts")) {
|
|
2036
|
+
return rewrittenImports.changed ? { code: rewrittenCode, map: null } : null;
|
|
2037
|
+
}
|
|
2038
|
+
if (!hasCssDsl) {
|
|
2039
|
+
return { code: rewrittenCode, map: null };
|
|
2040
|
+
}
|
|
2041
|
+
const result = transformTruss(rewrittenCode, id, ensureMapping());
|
|
2042
|
+
if (!result) {
|
|
2043
|
+
if (!rewrittenImports.changed) return null;
|
|
2044
|
+
return { code: rewrittenCode, map: null };
|
|
2045
|
+
}
|
|
1541
2046
|
return { code: result.code, map: result.map };
|
|
1542
2047
|
}
|
|
1543
2048
|
};
|
|
1544
2049
|
}
|
|
2050
|
+
function resolveImportPath(source, importer, projectRoot) {
|
|
2051
|
+
if (isAbsolute(source)) {
|
|
2052
|
+
return source;
|
|
2053
|
+
}
|
|
2054
|
+
if (importer) {
|
|
2055
|
+
return resolve(dirname(importer), source);
|
|
2056
|
+
}
|
|
2057
|
+
return resolve(projectRoot || process.cwd(), source);
|
|
2058
|
+
}
|
|
1545
2059
|
function stripQueryAndHash(id) {
|
|
1546
2060
|
const queryIndex = id.indexOf("?");
|
|
1547
2061
|
const hashIndex = id.indexOf("#");
|