@homebound/truss 2.11.3 → 2.13.0
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 +35 -8
- package/build/index.js.map +1 -1
- package/build/plugin/index.js +62 -11
- package/build/plugin/index.js.map +1 -1
- package/build/runtime.d.ts +42 -1
- package/build/runtime.js +57 -0
- package/build/runtime.js.map +1 -1
- package/package.json +6 -1
package/build/plugin/index.js
CHANGED
|
@@ -2773,6 +2773,7 @@ function rewriteCssPropsAndCssAttributes(options) {
|
|
|
2773
2773
|
// I.e. css={someVariable}, css={{ ...a, ...b }}, css={cond ? a : b}
|
|
2774
2774
|
JSXAttribute(path) {
|
|
2775
2775
|
if (!t3.isJSXIdentifier(path.node.name, { name: "css" })) return;
|
|
2776
|
+
if (isRuntimeStyleCssAttribute(path)) return;
|
|
2776
2777
|
const value = path.node.value;
|
|
2777
2778
|
if (!t3.isJSXExpressionContainer(value)) return;
|
|
2778
2779
|
if (!t3.isExpression(value.expression)) return;
|
|
@@ -2820,6 +2821,11 @@ function extractSiblingClassName(callPath) {
|
|
|
2820
2821
|
function isMatchingPropertyName(key, name) {
|
|
2821
2822
|
return t3.isIdentifier(key) && key.name === name || t3.isStringLiteral(key) && key.value === name;
|
|
2822
2823
|
}
|
|
2824
|
+
function isRuntimeStyleCssAttribute(path) {
|
|
2825
|
+
const openingElementPath = path.parentPath;
|
|
2826
|
+
if (!openingElementPath || !openingElementPath.isJSXOpeningElement()) return false;
|
|
2827
|
+
return t3.isJSXIdentifier(openingElementPath.node.name, { name: "RuntimeStyle" });
|
|
2828
|
+
}
|
|
2823
2829
|
function isFullyStaticStyleHash(hash) {
|
|
2824
2830
|
for (const prop of hash.properties) {
|
|
2825
2831
|
if (!t3.isObjectProperty(prop)) return false;
|
|
@@ -2860,7 +2866,8 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
2860
2866
|
const sites = [];
|
|
2861
2867
|
const errorMessages = [];
|
|
2862
2868
|
let hasCssPropsCall = false;
|
|
2863
|
-
let
|
|
2869
|
+
let hasBuildtimeJsxCssAttribute = false;
|
|
2870
|
+
let hasRuntimeStyleCssUsage = false;
|
|
2864
2871
|
traverse2(ast, {
|
|
2865
2872
|
// -- Css.*.$ chain collection --
|
|
2866
2873
|
MemberExpression(path) {
|
|
@@ -2869,6 +2876,10 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
2869
2876
|
if (path.node.computed) return;
|
|
2870
2877
|
const chain = extractChain(path.node.object, cssBindingName);
|
|
2871
2878
|
if (!chain) return;
|
|
2879
|
+
if (isInsideRuntimeStyleCssObject(path)) {
|
|
2880
|
+
hasRuntimeStyleCssUsage = true;
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2872
2883
|
const parentPath = path.parentPath;
|
|
2873
2884
|
if (parentPath && parentPath.isMemberExpression() && t4.isIdentifier(parentPath.node.property, { name: "$" })) {
|
|
2874
2885
|
return;
|
|
@@ -2890,13 +2901,12 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
2890
2901
|
},
|
|
2891
2902
|
// -- JSX css={...} attribute detection (so we don't bail when there are only css props) --
|
|
2892
2903
|
JSXAttribute(path) {
|
|
2893
|
-
if (
|
|
2894
|
-
if (
|
|
2895
|
-
|
|
2896
|
-
}
|
|
2904
|
+
if (!t4.isJSXIdentifier(path.node.name, { name: "css" })) return;
|
|
2905
|
+
if (isRuntimeStyleCssAttribute2(path)) return;
|
|
2906
|
+
hasBuildtimeJsxCssAttribute = true;
|
|
2897
2907
|
}
|
|
2898
2908
|
});
|
|
2899
|
-
if (sites.length === 0 && !hasCssPropsCall && !
|
|
2909
|
+
if (sites.length === 0 && !hasCssPropsCall && !hasBuildtimeJsxCssAttribute) return null;
|
|
2900
2910
|
const chains = sites.map((s) => s.resolvedChain);
|
|
2901
2911
|
const { rules, needsMaybeInc } = collectAtomicRules(chains, mapping);
|
|
2902
2912
|
const cssText = generateCssText(rules);
|
|
@@ -2946,7 +2956,7 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
2946
2956
|
runtimeImports.push({ importedName: "__injectTrussCSS", localName: "__injectTrussCSS" });
|
|
2947
2957
|
}
|
|
2948
2958
|
let reusedCssImportLine = false;
|
|
2949
|
-
if (cssIsImported) {
|
|
2959
|
+
if (cssIsImported && !hasRuntimeStyleCssUsage) {
|
|
2950
2960
|
reusedCssImportLine = runtimeImports.length > 0 && findImportDeclaration(ast, "@homebound/truss/runtime") === null && replaceCssImportWithNamedImports(ast, cssImportBinding, "@homebound/truss/runtime", runtimeImports);
|
|
2951
2961
|
if (!reusedCssImportLine) {
|
|
2952
2962
|
removeCssImport(ast, cssImportBinding);
|
|
@@ -2994,6 +3004,24 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
2994
3004
|
const outputCode = preserveBlankLineAfterImports(code, output.code);
|
|
2995
3005
|
return { code: outputCode, map: output.map, css: cssText, rules };
|
|
2996
3006
|
}
|
|
3007
|
+
function isInsideRuntimeStyleCssObject(path) {
|
|
3008
|
+
let current = path.parentPath;
|
|
3009
|
+
while (current) {
|
|
3010
|
+
if (current.isJSXExpressionContainer()) {
|
|
3011
|
+
const attrPath = current.parentPath;
|
|
3012
|
+
if (!attrPath || !attrPath.isJSXAttribute()) return false;
|
|
3013
|
+
return t4.isObjectExpression(current.node.expression) && isRuntimeStyleCssAttribute2(attrPath);
|
|
3014
|
+
}
|
|
3015
|
+
current = current.parentPath;
|
|
3016
|
+
}
|
|
3017
|
+
return false;
|
|
3018
|
+
}
|
|
3019
|
+
function isRuntimeStyleCssAttribute2(path) {
|
|
3020
|
+
if (!t4.isJSXIdentifier(path.node.name, { name: "css" })) return false;
|
|
3021
|
+
const openingElementPath = path.parentPath;
|
|
3022
|
+
if (!openingElementPath || !openingElementPath.isJSXOpeningElement()) return false;
|
|
3023
|
+
return t4.isJSXIdentifier(openingElementPath.node.name, { name: "RuntimeStyle" });
|
|
3024
|
+
}
|
|
2997
3025
|
function collectRuntimeLookups(chains) {
|
|
2998
3026
|
const lookups = /* @__PURE__ */ new Map();
|
|
2999
3027
|
for (const chain of chains) {
|
|
@@ -3111,10 +3139,6 @@ function transformCssTs(code, filename, mapping) {
|
|
|
3111
3139
|
sourceFilename: filename
|
|
3112
3140
|
});
|
|
3113
3141
|
const cssBindingName = findCssImportBinding(ast);
|
|
3114
|
-
if (!cssBindingName) {
|
|
3115
|
-
return `/* [truss] ${filename}: no Css import found */
|
|
3116
|
-
`;
|
|
3117
|
-
}
|
|
3118
3142
|
const cssExport = findNamedCssExportObject(ast);
|
|
3119
3143
|
if (!cssExport) {
|
|
3120
3144
|
return `/* [truss] ${filename}: expected \`export const css = { ... }\` with an object literal */
|
|
@@ -3137,10 +3161,19 @@ function transformCssTs(code, filename, mapping) {
|
|
|
3137
3161
|
continue;
|
|
3138
3162
|
}
|
|
3139
3163
|
const valueNode = prop.value;
|
|
3164
|
+
const rawCss = extractStaticStringValue(valueNode, cssBindingName);
|
|
3165
|
+
if (rawCss !== null) {
|
|
3166
|
+
rules.push(formatRawCssRule(selector, rawCss));
|
|
3167
|
+
continue;
|
|
3168
|
+
}
|
|
3140
3169
|
if (!t6.isExpression(valueNode)) {
|
|
3141
3170
|
rules.push(`/* [truss] unsupported: "${selector}" value is not an expression */`);
|
|
3142
3171
|
continue;
|
|
3143
3172
|
}
|
|
3173
|
+
if (!cssBindingName) {
|
|
3174
|
+
rules.push(`/* [truss] unsupported: "${selector}" \u2014 Css.*.$ chain requires a Css import */`);
|
|
3175
|
+
continue;
|
|
3176
|
+
}
|
|
3144
3177
|
const cssResult = resolveCssExpression(valueNode, cssBindingName, mapping, filename);
|
|
3145
3178
|
if ("error" in cssResult) {
|
|
3146
3179
|
rules.push(`/* [truss] unsupported: "${selector}" \u2014 ${cssResult.error} */`);
|
|
@@ -3174,6 +3207,16 @@ function objectPropertyStringKey(prop, stringBindings) {
|
|
|
3174
3207
|
if (prop.computed) return resolveStaticString(prop.key, stringBindings);
|
|
3175
3208
|
return null;
|
|
3176
3209
|
}
|
|
3210
|
+
function extractStaticStringValue(node, cssBindingName) {
|
|
3211
|
+
if (t6.isStringLiteral(node)) return node.value;
|
|
3212
|
+
if (t6.isTemplateLiteral(node) && node.expressions.length === 0 && node.quasis.length === 1) {
|
|
3213
|
+
return node.quasis[0].value.cooked ?? node.quasis[0].value.raw;
|
|
3214
|
+
}
|
|
3215
|
+
if (t6.isTaggedTemplateExpression(node) && t6.isMemberExpression(node.tag) && !node.tag.computed && t6.isIdentifier(node.tag.property, { name: "raw" }) && t6.isIdentifier(node.tag.object, { name: cssBindingName ?? "" }) && node.quasi.expressions.length === 0 && node.quasi.quasis.length === 1) {
|
|
3216
|
+
return node.quasi.quasis[0].value.cooked ?? node.quasi.quasis[0].value.raw;
|
|
3217
|
+
}
|
|
3218
|
+
return null;
|
|
3219
|
+
}
|
|
3177
3220
|
function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
3178
3221
|
if (!t6.isMemberExpression(node) || node.computed || !t6.isIdentifier(node.property, { name: "$" })) {
|
|
3179
3222
|
return { error: "value must be a Css.*.$ expression" };
|
|
@@ -3234,6 +3277,14 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
|
3234
3277
|
}
|
|
3235
3278
|
return { declarations };
|
|
3236
3279
|
}
|
|
3280
|
+
function formatRawCssRule(selector, raw) {
|
|
3281
|
+
const trimmed = raw.trim();
|
|
3282
|
+
if (!trimmed) return `${selector} {}`;
|
|
3283
|
+
const body = trimmed.split("\n").map((line) => ` ${line.trim()}`).filter((line) => line.trim().length > 0).join("\n");
|
|
3284
|
+
return `${selector} {
|
|
3285
|
+
${body}
|
|
3286
|
+
}`;
|
|
3287
|
+
}
|
|
3237
3288
|
function formatCssRule(selector, declarations) {
|
|
3238
3289
|
if (declarations.length === 0) {
|
|
3239
3290
|
return `${selector} {}`;
|