styled-components-to-stylex-codemod 0.0.26 → 0.0.28
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/transform.mjs +623 -285
- package/package.json +1 -1
package/dist/transform.mjs
CHANGED
|
@@ -591,6 +591,51 @@ function literalToString(node) {
|
|
|
591
591
|
return typeof v === "string" ? v : null;
|
|
592
592
|
}
|
|
593
593
|
/**
|
|
594
|
+
* Scans the file AST for TypeScript string/numeric enum declarations and
|
|
595
|
+
* returns a two-level map: enumName -> memberName -> static value.
|
|
596
|
+
* Only handles members with literal initializers.
|
|
597
|
+
*/
|
|
598
|
+
function buildEnumValueMap(root, j) {
|
|
599
|
+
const map = /* @__PURE__ */ new Map();
|
|
600
|
+
root.find(j.TSEnumDeclaration).forEach((path) => {
|
|
601
|
+
const enumNode = path.value;
|
|
602
|
+
const enumName = enumNode.id.name;
|
|
603
|
+
const members = /* @__PURE__ */ new Map();
|
|
604
|
+
let nextNumericValue = 0;
|
|
605
|
+
for (const member of enumNode.members) {
|
|
606
|
+
const memberName = member.id.type === "Identifier" ? member.id.name : member.id.value;
|
|
607
|
+
if (member.initializer) {
|
|
608
|
+
const val = literalToStaticValue(member.initializer);
|
|
609
|
+
if (val !== null) {
|
|
610
|
+
members.set(memberName, val);
|
|
611
|
+
nextNumericValue = typeof val === "number" ? val + 1 : 0;
|
|
612
|
+
}
|
|
613
|
+
} else {
|
|
614
|
+
members.set(memberName, nextNumericValue);
|
|
615
|
+
nextNumericValue++;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (members.size > 0) map.set(enumName, members);
|
|
619
|
+
});
|
|
620
|
+
return map;
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Resolves a MemberExpression node (e.g., `ProgressType.success`) to its
|
|
624
|
+
* static enum value using a pre-built enum map. Returns null if the node
|
|
625
|
+
* is not a MemberExpression or doesn't reference a known enum member.
|
|
626
|
+
*/
|
|
627
|
+
function resolveStaticExpressionValue(node, enumValueMap) {
|
|
628
|
+
const v = literalToStaticValue(node);
|
|
629
|
+
if (v !== null) return v;
|
|
630
|
+
if (!enumValueMap || !node || typeof node !== "object") return null;
|
|
631
|
+
const n = node;
|
|
632
|
+
if (n.type !== "MemberExpression" || n.computed) return null;
|
|
633
|
+
const obj = n.object;
|
|
634
|
+
const prop = n.property;
|
|
635
|
+
if (obj?.type !== "Identifier" || !obj.name || prop?.type !== "Identifier" || !prop.name) return null;
|
|
636
|
+
return enumValueMap.get(obj.name)?.get(prop.name) ?? null;
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
594
639
|
* Returns true if an AST node represents an "empty" CSS branch value.
|
|
595
640
|
* Styled-components treats falsy interpolations as "omit this declaration".
|
|
596
641
|
*
|
|
@@ -674,6 +719,16 @@ function unwrapLogicalFallback(expr) {
|
|
|
674
719
|
return null;
|
|
675
720
|
}
|
|
676
721
|
/**
|
|
722
|
+
* Returns true when `expr` is a `??` / `||` logical expression whose
|
|
723
|
+
* right-hand side is a non-literal value (e.g., `props.fallbackColor`).
|
|
724
|
+
*
|
|
725
|
+
* Used to bail on theme resolution when the fallback references a runtime
|
|
726
|
+
* value the user depends on — dropping it silently would change semantics.
|
|
727
|
+
*/
|
|
728
|
+
function hasNonLiteralLogicalFallback(expr) {
|
|
729
|
+
return isLogicalExpressionNode(expr) && (expr.operator === "??" || expr.operator === "||") && literalToStaticValue(expr.right) === null;
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
677
732
|
* Type guard for ConditionalExpression nodes.
|
|
678
733
|
*/
|
|
679
734
|
function isConditionalExpressionNode(node) {
|
|
@@ -1360,7 +1415,7 @@ const isValidIdentifier = (name) => /^[$A-Z_][0-9A-Z_$]*$/i.test(name);
|
|
|
1360
1415
|
* - Disjunction: `"a || b"` → `a || b`
|
|
1361
1416
|
* - Grouped negation: `"!(a || b)"` → `!(a || b)`
|
|
1362
1417
|
*/
|
|
1363
|
-
function parseVariantWhenToAst(j, when) {
|
|
1418
|
+
function parseVariantWhenToAst(j, when, booleanProps) {
|
|
1364
1419
|
const buildMemberExpr = (raw) => {
|
|
1365
1420
|
if (!raw.includes(".")) return null;
|
|
1366
1421
|
const parts = raw.split(".").map((part) => part.trim()).filter(Boolean);
|
|
@@ -1414,7 +1469,7 @@ function parseVariantWhenToAst(j, when) {
|
|
|
1414
1469
|
isBoolean: true
|
|
1415
1470
|
};
|
|
1416
1471
|
if (trimmed.startsWith("!(") && trimmed.endsWith(")")) {
|
|
1417
|
-
const innerParsed = parseVariantWhenToAst(j, trimmed.slice(2, -1).trim());
|
|
1472
|
+
const innerParsed = parseVariantWhenToAst(j, trimmed.slice(2, -1).trim(), booleanProps);
|
|
1418
1473
|
return {
|
|
1419
1474
|
cond: j.unaryExpression("!", innerParsed.cond),
|
|
1420
1475
|
props: innerParsed.props,
|
|
@@ -1422,7 +1477,7 @@ function parseVariantWhenToAst(j, when) {
|
|
|
1422
1477
|
};
|
|
1423
1478
|
}
|
|
1424
1479
|
if (trimmed.includes("&&")) {
|
|
1425
|
-
const parsed = trimmed.split("&&").map((s) => s.trim()).filter(Boolean).map((p) => parseVariantWhenToAst(j, p));
|
|
1480
|
+
const parsed = trimmed.split("&&").map((s) => s.trim()).filter(Boolean).map((p) => parseVariantWhenToAst(j, p, booleanProps));
|
|
1426
1481
|
const firstParsed = parsed[0];
|
|
1427
1482
|
if (!firstParsed) return {
|
|
1428
1483
|
cond: j.identifier("true"),
|
|
@@ -1436,7 +1491,7 @@ function parseVariantWhenToAst(j, when) {
|
|
|
1436
1491
|
};
|
|
1437
1492
|
}
|
|
1438
1493
|
if (trimmed.includes(" || ")) {
|
|
1439
|
-
const parsed = trimmed.split(" || ").map((s) => s.trim()).filter(Boolean).map((p) => parseVariantWhenToAst(j, p));
|
|
1494
|
+
const parsed = trimmed.split(" || ").map((s) => s.trim()).filter(Boolean).map((p) => parseVariantWhenToAst(j, p, booleanProps));
|
|
1440
1495
|
const firstParsedOr = parsed[0];
|
|
1441
1496
|
if (!firstParsedOr) return {
|
|
1442
1497
|
cond: j.identifier("true"),
|
|
@@ -1450,7 +1505,7 @@ function parseVariantWhenToAst(j, when) {
|
|
|
1450
1505
|
};
|
|
1451
1506
|
}
|
|
1452
1507
|
if (trimmed.startsWith("!")) {
|
|
1453
|
-
const innerParsed = parseVariantWhenToAst(j, trimmed.slice(1).trim());
|
|
1508
|
+
const innerParsed = parseVariantWhenToAst(j, trimmed.slice(1).trim(), booleanProps);
|
|
1454
1509
|
return {
|
|
1455
1510
|
cond: j.unaryExpression("!", innerParsed.cond),
|
|
1456
1511
|
props: innerParsed.props,
|
|
@@ -1471,10 +1526,11 @@ function parseVariantWhenToAst(j, when) {
|
|
|
1471
1526
|
};
|
|
1472
1527
|
}
|
|
1473
1528
|
const simple = parsePropRef(trimmed);
|
|
1529
|
+
const propIsBoolean = !!(simple.propName && booleanProps?.has(simple.propName));
|
|
1474
1530
|
return {
|
|
1475
1531
|
cond: simple.expr,
|
|
1476
1532
|
props: simple.propName ? [simple.propName] : [],
|
|
1477
|
-
isBoolean:
|
|
1533
|
+
isBoolean: propIsBoolean
|
|
1478
1534
|
};
|
|
1479
1535
|
}
|
|
1480
1536
|
/**
|
|
@@ -1483,8 +1539,8 @@ function parseVariantWhenToAst(j, when) {
|
|
|
1483
1539
|
* function's parameter destructuring.
|
|
1484
1540
|
*/
|
|
1485
1541
|
function collectConditionProps(j, args) {
|
|
1486
|
-
const { when, destructureProps } = args;
|
|
1487
|
-
const parsed = parseVariantWhenToAst(j, when);
|
|
1542
|
+
const { when, destructureProps, booleanProps } = args;
|
|
1543
|
+
const parsed = parseVariantWhenToAst(j, when, booleanProps);
|
|
1488
1544
|
if (destructureProps) {
|
|
1489
1545
|
for (const p of parsed.props) if (p && !destructureProps.includes(p)) destructureProps.push(p);
|
|
1490
1546
|
}
|
|
@@ -1492,8 +1548,9 @@ function collectConditionProps(j, args) {
|
|
|
1492
1548
|
}
|
|
1493
1549
|
/**
|
|
1494
1550
|
* Creates a conditional style expression that's safe for stylex.props().
|
|
1495
|
-
* For boolean conditions, uses && (since false is valid
|
|
1496
|
-
* For non-boolean conditions
|
|
1551
|
+
* For boolean conditions, uses `cond && expr` (since `false` is a valid StyleXArray element).
|
|
1552
|
+
* For non-boolean conditions, uses `cond ? expr : undefined` to avoid producing
|
|
1553
|
+
* values like `""` or `0` which are not valid StyleXArray elements.
|
|
1497
1554
|
*/
|
|
1498
1555
|
function makeConditionalStyleExpr(j, args) {
|
|
1499
1556
|
const { cond, expr, isBoolean } = args;
|
|
@@ -1525,7 +1582,7 @@ function areEquivalentWhen(left, right) {
|
|
|
1525
1582
|
* `prop ? trueExpr : falseExpr` instead of emitting separate conditionals.
|
|
1526
1583
|
*/
|
|
1527
1584
|
function buildExtraStylexPropsExprs(j, args) {
|
|
1528
|
-
const { entries, destructureProps } = args;
|
|
1585
|
+
const { entries, destructureProps, booleanProps } = args;
|
|
1529
1586
|
const result = [];
|
|
1530
1587
|
const consumed = /* @__PURE__ */ new Set();
|
|
1531
1588
|
for (let i = 0; i < entries.length; i++) {
|
|
@@ -1552,7 +1609,8 @@ function buildExtraStylexPropsExprs(j, args) {
|
|
|
1552
1609
|
}
|
|
1553
1610
|
const { cond, isBoolean } = collectConditionProps(j, {
|
|
1554
1611
|
when: entry.when,
|
|
1555
|
-
destructureProps
|
|
1612
|
+
destructureProps,
|
|
1613
|
+
booleanProps
|
|
1556
1614
|
});
|
|
1557
1615
|
result.push(makeConditionalStyleExpr(j, {
|
|
1558
1616
|
cond,
|
|
@@ -1880,10 +1938,11 @@ function analyzeBeforeEmitStep(ctx) {
|
|
|
1880
1938
|
if (decl.isDirectJsxResolution) continue;
|
|
1881
1939
|
if (decl.base.kind !== "intrinsic") continue;
|
|
1882
1940
|
if (relationChildStyleKeys.has(decl.styleKey)) continue;
|
|
1883
|
-
|
|
1941
|
+
const usageCount = getJsxUsageCount(decl.localName);
|
|
1942
|
+
if (decl.promotedStyleProps?.length && decl.promotedStyleProps.length >= usageCount) continue;
|
|
1884
1943
|
const { ref } = getJsxAttributeUsage(decl.localName);
|
|
1885
1944
|
if (ref) continue;
|
|
1886
|
-
if (
|
|
1945
|
+
if (usageCount > INLINE_USAGE_THRESHOLD) decl.needsWrapperComponent = true;
|
|
1887
1946
|
}
|
|
1888
1947
|
const hasSpreadInJsx = (name) => {
|
|
1889
1948
|
let found = false;
|
|
@@ -1970,11 +2029,13 @@ function analyzeBeforeEmitStep(ctx) {
|
|
|
1970
2029
|
existingPropNames.add("className").add("style").add("children").add("ref").add("key").add("as");
|
|
1971
2030
|
if (decl.base.kind === "component") collectBaseComponentPropNames(root, j, decl.base.ident, existingPropNames);
|
|
1972
2031
|
if (decl.base.kind === "intrinsic") for (const attr of BLOCKED_INTRINSIC_ATTR_RENAMES[decl.base.tagName] ?? []) existingPropNames.add(attr);
|
|
1973
|
-
|
|
2032
|
+
const { hasSpread, explicitTransientAtSpreadSites } = collectCallSiteAttrNames(root, j, decl.localName, existingPropNames);
|
|
1974
2033
|
const renames = /* @__PURE__ */ new Map();
|
|
1975
2034
|
for (const prop of transientProps) {
|
|
1976
2035
|
const stripped = prop.slice(1);
|
|
1977
|
-
if (
|
|
2036
|
+
if (existingPropNames.has(stripped)) continue;
|
|
2037
|
+
if (hasSpread && !explicitTransientAtSpreadSites?.has(prop)) continue;
|
|
2038
|
+
renames.set(prop, stripped);
|
|
1978
2039
|
}
|
|
1979
2040
|
if (renames.size > 0) {
|
|
1980
2041
|
if (collectReferencedTypeNames(decl.propsType).some((name) => isTypeNameUsedElsewhere(root, j, name, decl.localName) || !isTypeLocallyDefined(root, j, name))) continue;
|
|
@@ -2148,10 +2209,12 @@ function analyzeBeforeEmitStep(ctx) {
|
|
|
2148
2209
|
decl.variantStyleKeys[whenKey] = styleKey;
|
|
2149
2210
|
}
|
|
2150
2211
|
if (decl.callSiteCombinedStyles?.length) for (const { styleKey, styles } of decl.callSiteCombinedStyles) ctx.resolvedStyleObjects.set(styleKey, styles);
|
|
2151
|
-
if (decl.promotedStyleProps?.length) for (const entry of decl.promotedStyleProps) if (entry.mergeIntoBase)
|
|
2212
|
+
if (decl.promotedStyleProps?.length) for (const entry of decl.promotedStyleProps) if (entry.mergeIntoBase) if (isAstNode(entry.styleValue)) ctx.resolvedStyleObjects.set(decl.styleKey, entry.styleValue);
|
|
2213
|
+
else {
|
|
2152
2214
|
const existing = ctx.resolvedStyleObjects.get(decl.styleKey);
|
|
2153
2215
|
if (existing && typeof existing === "object" && !isAstNode(existing)) Object.assign(existing, entry.styleValue);
|
|
2154
|
-
}
|
|
2216
|
+
}
|
|
2217
|
+
else ctx.resolvedStyleObjects.set(entry.styleKey, entry.styleValue);
|
|
2155
2218
|
}
|
|
2156
2219
|
return CONTINUE;
|
|
2157
2220
|
}
|
|
@@ -2245,19 +2308,26 @@ function collectResolverImportNames(ctx) {
|
|
|
2245
2308
|
}
|
|
2246
2309
|
return names;
|
|
2247
2310
|
}
|
|
2248
|
-
/**
|
|
2249
|
-
* Collects non-`$`-prefixed attribute names from JSX call sites of a component.
|
|
2250
|
-
* Returns true if any call site uses a JSX spread attribute (e.g., `{...props}`),
|
|
2251
|
-
* which means the spread may contain `$`-prefixed keys at runtime — all renames
|
|
2252
|
-
* must be blocked to prevent mismatches.
|
|
2253
|
-
*/
|
|
2254
2311
|
function collectCallSiteAttrNames(root, j, componentName, names) {
|
|
2255
2312
|
let hasSpread = false;
|
|
2313
|
+
const spreadSiteTransientProps = [];
|
|
2256
2314
|
const collectFromElement = (openingElement) => {
|
|
2257
|
-
|
|
2258
|
-
|
|
2315
|
+
let siteHasSpread = false;
|
|
2316
|
+
const siteTransientAfterSpread = /* @__PURE__ */ new Set();
|
|
2317
|
+
const siteTransientBeforeSpread = /* @__PURE__ */ new Set();
|
|
2318
|
+
for (const attr of openingElement.attributes ?? []) if (attr.type === "JSXSpreadAttribute") {
|
|
2319
|
+
hasSpread = true;
|
|
2320
|
+
siteHasSpread = true;
|
|
2321
|
+
for (const name of siteTransientAfterSpread) siteTransientBeforeSpread.add(name);
|
|
2322
|
+
siteTransientAfterSpread.clear();
|
|
2323
|
+
} else if (attr.type === "JSXAttribute" && attr.name?.type === "JSXIdentifier") {
|
|
2259
2324
|
const name = attr.name.name;
|
|
2260
|
-
if (
|
|
2325
|
+
if (name.startsWith("$")) siteTransientAfterSpread.add(name);
|
|
2326
|
+
else names.add(name);
|
|
2327
|
+
}
|
|
2328
|
+
if (siteHasSpread) {
|
|
2329
|
+
for (const name of siteTransientBeforeSpread) siteTransientAfterSpread.delete(name);
|
|
2330
|
+
spreadSiteTransientProps.push(siteTransientAfterSpread);
|
|
2261
2331
|
}
|
|
2262
2332
|
};
|
|
2263
2333
|
root.find(j.JSXElement, { openingElement: { name: {
|
|
@@ -2268,7 +2338,20 @@ function collectCallSiteAttrNames(root, j, componentName, names) {
|
|
|
2268
2338
|
type: "JSXIdentifier",
|
|
2269
2339
|
name: componentName
|
|
2270
2340
|
} }).forEach((p) => collectFromElement(p.node));
|
|
2271
|
-
return
|
|
2341
|
+
if (!hasSpread) return {
|
|
2342
|
+
hasSpread: false,
|
|
2343
|
+
explicitTransientAtSpreadSites: null
|
|
2344
|
+
};
|
|
2345
|
+
if (spreadSiteTransientProps.length === 0) return {
|
|
2346
|
+
hasSpread: true,
|
|
2347
|
+
explicitTransientAtSpreadSites: /* @__PURE__ */ new Set()
|
|
2348
|
+
};
|
|
2349
|
+
const intersection = new Set(spreadSiteTransientProps[0]);
|
|
2350
|
+
for (let i = 1; i < spreadSiteTransientProps.length; i++) for (const prop of intersection) if (!spreadSiteTransientProps[i].has(prop)) intersection.delete(prop);
|
|
2351
|
+
return {
|
|
2352
|
+
hasSpread: true,
|
|
2353
|
+
explicitTransientAtSpreadSites: intersection
|
|
2354
|
+
};
|
|
2272
2355
|
}
|
|
2273
2356
|
/**
|
|
2274
2357
|
* Collects prop names from a locally-defined base component's type that match
|
|
@@ -2382,6 +2465,7 @@ function applyTransientPropRenames(decl, renames) {
|
|
|
2382
2465
|
}
|
|
2383
2466
|
if (decl.styleFnFromProps) for (const sf of decl.styleFnFromProps) {
|
|
2384
2467
|
sf.jsxProp = renames.get(sf.jsxProp) ?? sf.jsxProp;
|
|
2468
|
+
if (sf.propsObjectKey) sf.propsObjectKey = renames.get(sf.propsObjectKey) ?? sf.propsObjectKey;
|
|
2385
2469
|
if (sf.conditionWhen) sf.conditionWhen = renamePropsInWhenString(sf.conditionWhen, renames);
|
|
2386
2470
|
if (sf.callArg) renameIdentifiersInAst(sf.callArg, renames);
|
|
2387
2471
|
}
|
|
@@ -2466,7 +2550,6 @@ function renameIdentifiersInAst(node, renames) {
|
|
|
2466
2550
|
if (n.type === "Identifier" && typeof n.name === "string") {
|
|
2467
2551
|
const renamed = renames.get(n.name);
|
|
2468
2552
|
if (renamed) n.name = renamed;
|
|
2469
|
-
return;
|
|
2470
2553
|
}
|
|
2471
2554
|
for (const [key, value] of Object.entries(n)) {
|
|
2472
2555
|
if (AST_METADATA_KEYS.has(key)) continue;
|
|
@@ -2621,8 +2704,11 @@ const NUMERIC_CSS_PROPS = new Set([
|
|
|
2621
2704
|
"widows",
|
|
2622
2705
|
"columnCount"
|
|
2623
2706
|
]);
|
|
2624
|
-
/**
|
|
2625
|
-
|
|
2707
|
+
/**
|
|
2708
|
+
* CSS properties that accept numeric values in standard CSS / React inline styles
|
|
2709
|
+
* but are typed as `string` in StyleX. Numeric values must be coerced to strings.
|
|
2710
|
+
*/
|
|
2711
|
+
const STYLEX_STRING_ONLY_CSS_PROPS = new Set([
|
|
2626
2712
|
"gridRow",
|
|
2627
2713
|
"gridColumn",
|
|
2628
2714
|
"gridRowStart",
|
|
@@ -2635,16 +2721,22 @@ const IDENTIFIER_NAME_RE = /^[$A-Z_][0-9A-Z_$]*$/i;
|
|
|
2635
2721
|
function isValidIdentifierName$1(name) {
|
|
2636
2722
|
return IDENTIFIER_NAME_RE.test(name);
|
|
2637
2723
|
}
|
|
2724
|
+
function coerceToStringForStyleX(cssProp, value) {
|
|
2725
|
+
if (STYLEX_STRING_ONLY_CSS_PROPS.has(cssProp) && typeof value === "number") return String(value);
|
|
2726
|
+
return value;
|
|
2727
|
+
}
|
|
2638
2728
|
/**
|
|
2639
2729
|
* Infers a TS type keyword for a dynamic expression based on the CSS property it's assigned to.
|
|
2640
2730
|
* Numeric-only properties get `number`; ambiguous length-like values get `number | string`.
|
|
2731
|
+
* Properties in STYLEX_STRING_ONLY_CSS_PROPS always get `string` even when the value is numeric.
|
|
2641
2732
|
*/
|
|
2642
2733
|
function inferTypeForCssProp(cssProp, expr) {
|
|
2734
|
+
if (STYLEX_STRING_ONLY_CSS_PROPS.has(cssProp)) return "string";
|
|
2643
2735
|
const staticVal = literalToStaticValue(expr);
|
|
2644
2736
|
if (typeof staticVal === "number") return "number";
|
|
2645
2737
|
if (typeof staticVal === "string") return "string";
|
|
2646
2738
|
if (NUMERIC_CSS_PROPS.has(cssProp)) return "number";
|
|
2647
|
-
if (
|
|
2739
|
+
if (LENGTH_LIKE_CSS_PROP_RE.test(cssProp)) return "numberOrString";
|
|
2648
2740
|
return "string";
|
|
2649
2741
|
}
|
|
2650
2742
|
/**
|
|
@@ -2773,7 +2865,7 @@ function analyzePromotableStyleProps(root, j, styledDecls, declByLocal, getJsxUs
|
|
|
2773
2865
|
const hasDynamic = site.properties.some((p) => p.dynamicExpr !== null);
|
|
2774
2866
|
if (allStatic && !hasDynamic) {
|
|
2775
2867
|
const staticObj = {};
|
|
2776
|
-
for (const p of site.properties) staticObj[p.key] = p.staticValue;
|
|
2868
|
+
for (const p of site.properties) staticObj[p.key] = coerceToStringForStyleX(p.key, p.staticValue);
|
|
2777
2869
|
if (usageCount <= 1 && !decl.isExported && !hasPropertyOverlap(staticObj, resolvedStyleObjects.get(decl.styleKey))) {
|
|
2778
2870
|
promotedEntries.push({
|
|
2779
2871
|
styleKey: decl.styleKey,
|
|
@@ -2791,15 +2883,31 @@ function analyzePromotableStyleProps(root, j, styledDecls, declByLocal, getJsxUs
|
|
|
2791
2883
|
site.opening.__promotedStyleKey = styleKey;
|
|
2792
2884
|
}
|
|
2793
2885
|
} else if (hasDynamic) {
|
|
2794
|
-
const
|
|
2795
|
-
usedKeyNames.add(styleKey);
|
|
2796
|
-
const staticObj = {};
|
|
2886
|
+
const inlineStaticObj = {};
|
|
2797
2887
|
const dynamicParams = [];
|
|
2798
|
-
for (const p of site.properties) if (p.staticValue !== null)
|
|
2888
|
+
for (const p of site.properties) if (p.staticValue !== null) inlineStaticObj[p.key] = coerceToStringForStyleX(p.key, p.staticValue);
|
|
2799
2889
|
else dynamicParams.push({
|
|
2800
2890
|
cssProp: p.key,
|
|
2801
2891
|
expr: p.dynamicExpr
|
|
2802
2892
|
});
|
|
2893
|
+
const baseObj = resolvedStyleObjects.get(decl.styleKey);
|
|
2894
|
+
const baseIsSimpleObject = baseObj && typeof baseObj === "object" && !isAstNode(baseObj) && Object.values(baseObj).every((v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" || isAstNode(v));
|
|
2895
|
+
const isExtendedByOther = styledDecls.some((d) => d !== decl && d.base.kind === "component" && d.base.ident === decl.localName);
|
|
2896
|
+
const canMergeDynamic = usageCount <= 1 && !decl.isExported && !isExtendedByOther && baseIsSimpleObject && !hasPropertyOverlap(inlineStaticObj, baseObj);
|
|
2897
|
+
const dynamicPropKeys = new Set(dynamicParams.map((dp) => dp.cssProp));
|
|
2898
|
+
const mergedStaticProps = [];
|
|
2899
|
+
if (canMergeDynamic) {
|
|
2900
|
+
for (const [k, v] of Object.entries(baseObj)) if (!dynamicPropKeys.has(k)) mergedStaticProps.push({
|
|
2901
|
+
key: k,
|
|
2902
|
+
value: v
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
for (const [k, v] of Object.entries(inlineStaticObj)) mergedStaticProps.push({
|
|
2906
|
+
key: k,
|
|
2907
|
+
value: v
|
|
2908
|
+
});
|
|
2909
|
+
const styleKey = canMergeDynamic ? decl.styleKey : generatePromotedDynamicStyleKey(decl.styleKey, usedKeyNames, site.children);
|
|
2910
|
+
if (!canMergeDynamic) usedKeyNames.add(styleKey);
|
|
2803
2911
|
const paramEntries = [];
|
|
2804
2912
|
const seenParamNames = /* @__PURE__ */ new Set();
|
|
2805
2913
|
for (const dp of dynamicParams) {
|
|
@@ -2819,24 +2927,34 @@ function analyzePromotableStyleProps(root, j, styledDecls, declByLocal, getJsxUs
|
|
|
2819
2927
|
id.typeAnnotation = j.tsTypeAnnotation(typeNode);
|
|
2820
2928
|
return id;
|
|
2821
2929
|
});
|
|
2822
|
-
const bodyProperties =
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
}
|
|
2930
|
+
const bodyProperties = [];
|
|
2931
|
+
for (const sp of mergedStaticProps) {
|
|
2932
|
+
const val = isAstNode(sp.value) ? sp.value : typeof sp.value === "string" ? j.stringLiteral(sp.value) : typeof sp.value === "number" ? j.numericLiteral(sp.value) : j.booleanLiteral(sp.value);
|
|
2933
|
+
bodyProperties.push(j.property("init", j.identifier(sp.key), val));
|
|
2934
|
+
}
|
|
2935
|
+
for (const p of site.properties) if (p.dynamicExpr !== null) {
|
|
2936
|
+
const prop = j.property("init", j.identifier(p.key), j.identifier(p.key));
|
|
2937
|
+
prop.shorthand = true;
|
|
2938
|
+
bodyProperties.push(prop);
|
|
2939
|
+
}
|
|
2832
2940
|
const fnNode = j.arrowFunctionExpression(params, j.objectExpression(bodyProperties));
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2941
|
+
if (canMergeDynamic) {
|
|
2942
|
+
promotedEntries.push({
|
|
2943
|
+
styleKey: decl.styleKey,
|
|
2944
|
+
styleValue: fnNode,
|
|
2945
|
+
mergeIntoBase: true
|
|
2946
|
+
});
|
|
2947
|
+
site.opening.__promotedMergeIntoBase = true;
|
|
2948
|
+
site.opening.__promotedMergeArgs = dynamicParams.map((dp) => STYLEX_STRING_ONLY_CSS_PROPS.has(dp.cssProp) ? j.callExpression(j.identifier("String"), [dp.expr]) : dp.expr);
|
|
2949
|
+
} else {
|
|
2950
|
+
promotedEntries.push({
|
|
2951
|
+
styleKey,
|
|
2952
|
+
styleValue: fnNode
|
|
2953
|
+
});
|
|
2954
|
+
site.opening.__promotedStyleKey = styleKey;
|
|
2955
|
+
const callArgs = dynamicParams.map((dp) => STYLEX_STRING_ONLY_CSS_PROPS.has(dp.cssProp) ? j.callExpression(j.identifier("String"), [dp.expr]) : dp.expr);
|
|
2956
|
+
site.opening.__promotedStyleArgs = callArgs;
|
|
2957
|
+
}
|
|
2840
2958
|
}
|
|
2841
2959
|
}
|
|
2842
2960
|
if (promotedEntries.length > 0) decl.promotedStyleProps = promotedEntries;
|
|
@@ -4434,6 +4552,14 @@ function printNode(node) {
|
|
|
4434
4552
|
function areAllValuesSame(values) {
|
|
4435
4553
|
return values.length > 1 && values.every((value) => value === values[0]);
|
|
4436
4554
|
}
|
|
4555
|
+
/**
|
|
4556
|
+
* Shorthands that StyleX requires to be fully expanded to physical longhands.
|
|
4557
|
+
* Unlike `padding`/`margin` (which StyleX's Babel plugin can expand internally),
|
|
4558
|
+
* `scrollPadding`/`scrollMargin` and their logical forms (Block/Inline) are not
|
|
4559
|
+
* recognized by `@stylexjs/valid-styles` and must always be written as
|
|
4560
|
+
* Top/Right/Bottom/Left.
|
|
4561
|
+
*/
|
|
4562
|
+
const PHYSICAL_ONLY_SHORTHANDS = new Set(["scrollMargin", "scrollPadding"]);
|
|
4437
4563
|
function expandQuadValues(values) {
|
|
4438
4564
|
const top = values[0] ?? "";
|
|
4439
4565
|
const right = values[1] ?? top;
|
|
@@ -4465,12 +4591,13 @@ function splitDirectionalProperty(args) {
|
|
|
4465
4591
|
const bottom = values[2] ?? top;
|
|
4466
4592
|
const left = values[3] ?? right;
|
|
4467
4593
|
const withImportant = (value) => important ? `${value} !important` : value;
|
|
4468
|
-
|
|
4594
|
+
const physicalOnly = PHYSICAL_ONLY_SHORTHANDS.has(prop);
|
|
4595
|
+
if (values.length === 1 && !important && !alwaysExpand && !physicalOnly) return [{
|
|
4469
4596
|
prop,
|
|
4470
4597
|
value: withImportant(top)
|
|
4471
4598
|
}];
|
|
4472
4599
|
const quad = expandQuadValues(values);
|
|
4473
|
-
if (important) return [
|
|
4600
|
+
if (important || physicalOnly) return [
|
|
4474
4601
|
{
|
|
4475
4602
|
prop: `${prop}Top`,
|
|
4476
4603
|
value: withImportant(quad[0])
|
|
@@ -7991,8 +8118,8 @@ function buildInlineResolverVariantDimensions(args) {
|
|
|
7991
8118
|
return type === "ArrowFunctionExpression" || type === "FunctionExpression";
|
|
7992
8119
|
});
|
|
7993
8120
|
const hasCompleteCallsiteVisibility = !willHaveExternalInterface(ctx, decl, styledDecls) && !decl.usedAsValue;
|
|
7994
|
-
if (variantKeys.length === 1
|
|
7995
|
-
if (hasCompleteCallsiteVisibility) {
|
|
8121
|
+
if (variantKeys.length === 1) {
|
|
8122
|
+
if (hasCompleteCallsiteVisibility && !hasPropReferencingTemplateExpressions) {
|
|
7996
8123
|
if (usageResult.propsByUsage.filter((siteProps) => propName in siteProps).length === totalCallSites) {
|
|
7997
8124
|
const [, singleVariantStyles] = Object.entries(variants)[0];
|
|
7998
8125
|
for (const [cssKey, cssVal] of Object.entries(singleVariantStyles)) foldedBaseSx[cssKey] = String(cssVal);
|
|
@@ -9625,6 +9752,22 @@ function buildVariantDimPropTypeMap(d) {
|
|
|
9625
9752
|
return [dim.propName, typeText];
|
|
9626
9753
|
}));
|
|
9627
9754
|
}
|
|
9755
|
+
/**
|
|
9756
|
+
* Collects prop names that are known to have `boolean` type from all available sources:
|
|
9757
|
+
* - `staticBooleanVariants` without a variantKey (confirmed boolean from prepass)
|
|
9758
|
+
* - `variantDimensions` with `isBooleanProp` flag
|
|
9759
|
+
* - `propsType` AST type literal with `boolean` type annotations
|
|
9760
|
+
*
|
|
9761
|
+
* Used to emit `cond && styles.key` (valid for StyleXArray since `false` is accepted)
|
|
9762
|
+
* instead of `cond ? styles.key : undefined` for boolean-guarded variant conditions.
|
|
9763
|
+
*/
|
|
9764
|
+
function collectBooleanPropNames(d) {
|
|
9765
|
+
const result = /* @__PURE__ */ new Set();
|
|
9766
|
+
for (const sbv of d.staticBooleanVariants ?? []) if (!sbv.variantKey) result.add(sbv.propName);
|
|
9767
|
+
for (const dim of d.variantDimensions ?? []) if (dim.isBooleanProp) result.add(dim.propName);
|
|
9768
|
+
collectBooleanPropsFromTypeLiteral(d.propsType, result);
|
|
9769
|
+
return result;
|
|
9770
|
+
}
|
|
9628
9771
|
function getAttrsAsString(d) {
|
|
9629
9772
|
const v = d.attrsInfo?.staticAttrs?.as;
|
|
9630
9773
|
return typeof v === "string" ? v : null;
|
|
@@ -9658,6 +9801,41 @@ function injectStylePropsIntoTypeLiteralString(typeText, options) {
|
|
|
9658
9801
|
}
|
|
9659
9802
|
return `${typeText} & { ${propsToAdd.join(", ")} }`;
|
|
9660
9803
|
}
|
|
9804
|
+
function collectBooleanPropsFromTypeLiteral(node, result) {
|
|
9805
|
+
for (const name of extractBooleanProps(node)) {
|
|
9806
|
+
result.add(name);
|
|
9807
|
+
if (name.startsWith("$")) result.add(name.slice(1));
|
|
9808
|
+
}
|
|
9809
|
+
}
|
|
9810
|
+
function extractBooleanProps(node) {
|
|
9811
|
+
const typed = node;
|
|
9812
|
+
if (!typed || typeof typed !== "object") return /* @__PURE__ */ new Set();
|
|
9813
|
+
if (typed.type === "TSTypeLiteral") {
|
|
9814
|
+
const props = /* @__PURE__ */ new Set();
|
|
9815
|
+
for (const member of typed.members ?? []) {
|
|
9816
|
+
if (member?.type !== "TSPropertySignature") continue;
|
|
9817
|
+
const key = member.key;
|
|
9818
|
+
const name = key?.type === "Identifier" ? key.name : null;
|
|
9819
|
+
if (!name) continue;
|
|
9820
|
+
if ((member.typeAnnotation?.typeAnnotation)?.type === "TSBooleanKeyword") props.add(name);
|
|
9821
|
+
}
|
|
9822
|
+
return props;
|
|
9823
|
+
}
|
|
9824
|
+
if (typed.type === "TSIntersectionType") {
|
|
9825
|
+
const combined = /* @__PURE__ */ new Set();
|
|
9826
|
+
for (const t of typed.types ?? []) for (const p of extractBooleanProps(t)) combined.add(p);
|
|
9827
|
+
return combined;
|
|
9828
|
+
}
|
|
9829
|
+
if (typed.type === "TSUnionType") {
|
|
9830
|
+
const arms = (typed.types ?? []).map(extractBooleanProps);
|
|
9831
|
+
if (arms.length === 0) return /* @__PURE__ */ new Set();
|
|
9832
|
+
const first = arms[0];
|
|
9833
|
+
const intersection = /* @__PURE__ */ new Set();
|
|
9834
|
+
for (const name of first) if (arms.every((arm) => arm.has(name))) intersection.add(name);
|
|
9835
|
+
return intersection;
|
|
9836
|
+
}
|
|
9837
|
+
return /* @__PURE__ */ new Set();
|
|
9838
|
+
}
|
|
9661
9839
|
|
|
9662
9840
|
//#endregion
|
|
9663
9841
|
//#region src/internal/emit-wrappers/jsx-builders.ts
|
|
@@ -9816,6 +9994,15 @@ function styleRef(j, stylesIdentifier, key) {
|
|
|
9816
9994
|
return j.memberExpression(j.identifier(stylesIdentifier), j.identifier(key));
|
|
9817
9995
|
}
|
|
9818
9996
|
/**
|
|
9997
|
+
* When a style function uses a `props` object parameter, wraps the raw call
|
|
9998
|
+
* argument in `{ [propsObjectKey]: rawArg }`. Returns `rawArg` unchanged when
|
|
9999
|
+
* `propsObjectKey` is not set.
|
|
10000
|
+
*/
|
|
10001
|
+
function wrapCallArgForPropsObject(j, rawArg, propsObjectKey) {
|
|
10002
|
+
if (!propsObjectKey) return rawArg;
|
|
10003
|
+
return j.objectExpression([j.property("init", j.identifier(propsObjectKey), rawArg)]);
|
|
10004
|
+
}
|
|
10005
|
+
/**
|
|
9819
10006
|
* Splits a declaration's extra style keys into those that appear before and
|
|
9820
10007
|
* after the base style in stylex.props() argument order.
|
|
9821
10008
|
*/
|
|
@@ -10093,9 +10280,10 @@ function buildStyleFnExpressions(emitter, args) {
|
|
|
10093
10280
|
}
|
|
10094
10281
|
return null;
|
|
10095
10282
|
};
|
|
10283
|
+
const booleanProps = collectBooleanPropNames(d);
|
|
10096
10284
|
for (const p of styleFnPairs) {
|
|
10097
10285
|
const propExpr = p.jsxProp === "__props" ? propsId : propExprBuilder(p.jsxProp);
|
|
10098
|
-
const callArg = p.callArg ?? propExpr;
|
|
10286
|
+
const callArg = wrapCallArgForPropsObject(j, p.callArg ?? propExpr, p.propsObjectKey);
|
|
10099
10287
|
const call = j.callExpression(styleRef(j, stylesIdentifier, p.fnKey), [callArg]);
|
|
10100
10288
|
if (p.callArg?.type === "Identifier") {
|
|
10101
10289
|
const name = p.callArg.name;
|
|
@@ -10122,7 +10310,8 @@ function buildStyleFnExpressions(emitter, args) {
|
|
|
10122
10310
|
if (p.conditionWhen) {
|
|
10123
10311
|
const { cond, isBoolean } = collectConditionProps(j, {
|
|
10124
10312
|
when: p.conditionWhen,
|
|
10125
|
-
destructureProps
|
|
10313
|
+
destructureProps,
|
|
10314
|
+
booleanProps
|
|
10126
10315
|
});
|
|
10127
10316
|
pushExpr(makeConditionalStyleExpr(j, {
|
|
10128
10317
|
cond,
|
|
@@ -11769,6 +11958,7 @@ function emitSimpleExportedIntrinsicWrappers(ctx) {
|
|
|
11769
11958
|
const needsUseTheme = appendThemeBooleanStyleArgs(d.needsUseThemeHook, styleArgs, j, stylesIdentifier, () => ctx.markNeedsUseThemeImport());
|
|
11770
11959
|
for (const gp of appendAllPseudoStyleArgs(d, styleArgs, j, stylesIdentifier)) if (!destructureProps.includes(gp)) destructureProps.push(gp);
|
|
11771
11960
|
const compoundVariantKeys = collectCompoundVariantKeys(d.compoundVariants);
|
|
11961
|
+
const booleanProps = collectBooleanPropNames(d);
|
|
11772
11962
|
const hasSourceOrder = !!(d.variantSourceOrder && Object.keys(d.variantSourceOrder).length > 0);
|
|
11773
11963
|
const orderedEntries = [];
|
|
11774
11964
|
if (d.variantStyleKeys) {
|
|
@@ -11787,7 +11977,8 @@ function emitSimpleExportedIntrinsicWrappers(ctx) {
|
|
|
11787
11977
|
const positiveWhen = getPositiveWhen(when, otherWhen) ?? when;
|
|
11788
11978
|
const { cond } = emitter.collectConditionProps({
|
|
11789
11979
|
when: positiveWhen,
|
|
11790
|
-
destructureProps
|
|
11980
|
+
destructureProps,
|
|
11981
|
+
booleanProps
|
|
11791
11982
|
});
|
|
11792
11983
|
const isCurrentPositive = areEquivalentWhen(when, positiveWhen);
|
|
11793
11984
|
const trueKey = isCurrentPositive ? variantKey : otherKey;
|
|
@@ -11805,7 +11996,8 @@ function emitSimpleExportedIntrinsicWrappers(ctx) {
|
|
|
11805
11996
|
}
|
|
11806
11997
|
const { cond, isBoolean } = emitter.collectConditionProps({
|
|
11807
11998
|
when,
|
|
11808
|
-
destructureProps
|
|
11999
|
+
destructureProps,
|
|
12000
|
+
booleanProps
|
|
11809
12001
|
});
|
|
11810
12002
|
const styleExpr = j.memberExpression(j.identifier(stylesIdentifier), j.identifier(variantKey));
|
|
11811
12003
|
const expr = emitter.makeConditionalStyleExpr({
|
|
@@ -12167,12 +12359,12 @@ function appendAllPseudoStyleArgs(d, styleArgs, j, stylesIdentifier) {
|
|
|
12167
12359
|
* Each entry is mapped to an expression via `buildExpr`, then optionally
|
|
12168
12360
|
* wrapped in a conditional if the entry has a `guard`.
|
|
12169
12361
|
*/
|
|
12170
|
-
function appendGuardedStyleArgs(entries, styleArgs, j, buildExpr) {
|
|
12362
|
+
function appendGuardedStyleArgs(entries, styleArgs, j, buildExpr, booleanProps) {
|
|
12171
12363
|
const guardProps = [];
|
|
12172
12364
|
for (const entry of entries) {
|
|
12173
12365
|
const expr = buildExpr(entry);
|
|
12174
12366
|
if (entry.guard) {
|
|
12175
|
-
const parsed = parseVariantWhenToAst(j, entry.guard.when);
|
|
12367
|
+
const parsed = parseVariantWhenToAst(j, entry.guard.when, booleanProps);
|
|
12176
12368
|
for (const p of parsed.props) if (p && !guardProps.includes(p)) guardProps.push(p);
|
|
12177
12369
|
styleArgs.push(makeConditionalStyleExpr(j, {
|
|
12178
12370
|
cond: parsed.cond,
|
|
@@ -12364,6 +12556,7 @@ function emitComponentWrappers(emitter) {
|
|
|
12364
12556
|
];
|
|
12365
12557
|
const hasSourceOrder = !!(d.variantSourceOrder && Object.keys(d.variantSourceOrder).length > 0);
|
|
12366
12558
|
const orderedEntries = [];
|
|
12559
|
+
const booleanProps = collectBooleanPropNames(d);
|
|
12367
12560
|
if (d.variantStyleKeys) {
|
|
12368
12561
|
const sortedEntries = sortVariantEntriesBySpecificity(Object.entries(d.variantStyleKeys));
|
|
12369
12562
|
const consumedVariantIndices = /* @__PURE__ */ new Set();
|
|
@@ -12378,7 +12571,8 @@ function emitComponentWrappers(emitter) {
|
|
|
12378
12571
|
const positiveWhen = getPositiveWhen(when, otherWhen) ?? when;
|
|
12379
12572
|
const { cond } = emitter.collectConditionProps({
|
|
12380
12573
|
when: positiveWhen,
|
|
12381
|
-
destructureProps
|
|
12574
|
+
destructureProps,
|
|
12575
|
+
booleanProps
|
|
12382
12576
|
});
|
|
12383
12577
|
for (let i = prevLength; i < destructureProps.length; i++) styleOnlyConditionProps.add(destructureProps[i]);
|
|
12384
12578
|
const isCurrentPositive = areEquivalentWhen(when, positiveWhen);
|
|
@@ -12397,7 +12591,8 @@ function emitComponentWrappers(emitter) {
|
|
|
12397
12591
|
}
|
|
12398
12592
|
const { cond, isBoolean } = emitter.collectConditionProps({
|
|
12399
12593
|
when,
|
|
12400
|
-
destructureProps
|
|
12594
|
+
destructureProps,
|
|
12595
|
+
booleanProps
|
|
12401
12596
|
});
|
|
12402
12597
|
for (let i = prevLength; i < destructureProps.length; i++) styleOnlyConditionProps.add(destructureProps[i]);
|
|
12403
12598
|
const styleExpr = j.memberExpression(j.identifier(stylesIdentifier), j.identifier(variantKey));
|
|
@@ -13344,6 +13539,7 @@ function emitIntrinsicPolymorphicWrappers(ctx) {
|
|
|
13344
13539
|
...extraStyleArgsAfterBase
|
|
13345
13540
|
];
|
|
13346
13541
|
const compoundVariantKeys = collectCompoundVariantKeys(d.compoundVariants);
|
|
13542
|
+
const booleanProps = collectBooleanPropNames(d);
|
|
13347
13543
|
const hasSourceOrder = !!(d.variantSourceOrder && Object.keys(d.variantSourceOrder).length > 0);
|
|
13348
13544
|
const orderedEntries = [];
|
|
13349
13545
|
if (d.variantStyleKeys) {
|
|
@@ -13352,7 +13548,8 @@ function emitIntrinsicPolymorphicWrappers(ctx) {
|
|
|
13352
13548
|
if (compoundVariantKeys.has(when)) continue;
|
|
13353
13549
|
const { cond, isBoolean } = emitter.collectConditionProps({
|
|
13354
13550
|
when,
|
|
13355
|
-
destructureProps
|
|
13551
|
+
destructureProps,
|
|
13552
|
+
booleanProps
|
|
13356
13553
|
});
|
|
13357
13554
|
const styleExpr = j.memberExpression(j.identifier(stylesIdentifier), j.identifier(variantKey));
|
|
13358
13555
|
const expr = emitter.makeConditionalStyleExpr({
|
|
@@ -13653,13 +13850,17 @@ function emitShouldForwardPropWrappers(ctx) {
|
|
|
13653
13850
|
const needsUseTheme = appendThemeBooleanStyleArgs(d.needsUseThemeHook, styleArgs, j, stylesIdentifier, () => ctx.markNeedsUseThemeImport());
|
|
13654
13851
|
const pseudoGuardProps = appendAllPseudoStyleArgs(d, styleArgs, j, stylesIdentifier);
|
|
13655
13852
|
const compoundVariantKeys = collectCompoundVariantKeys(d.compoundVariants);
|
|
13853
|
+
const booleanProps = collectBooleanPropNames(d);
|
|
13656
13854
|
const hasSourceOrder = !!(d.variantSourceOrder && Object.keys(d.variantSourceOrder).length > 0);
|
|
13657
13855
|
const orderedEntries = [];
|
|
13658
13856
|
if (d.variantStyleKeys) {
|
|
13659
13857
|
const sortedEntries = sortVariantEntriesBySpecificity(Object.entries(d.variantStyleKeys));
|
|
13660
13858
|
for (const [when, variantKey] of sortedEntries) {
|
|
13661
13859
|
if (compoundVariantKeys.has(when)) continue;
|
|
13662
|
-
const { cond, isBoolean } = emitter.collectConditionProps({
|
|
13860
|
+
const { cond, isBoolean } = emitter.collectConditionProps({
|
|
13861
|
+
when,
|
|
13862
|
+
booleanProps
|
|
13863
|
+
});
|
|
13663
13864
|
const styleExpr = j.memberExpression(j.identifier(stylesIdentifier), j.identifier(variantKey));
|
|
13664
13865
|
const expr = emitter.makeConditionalStyleExpr({
|
|
13665
13866
|
cond,
|
|
@@ -13703,13 +13904,14 @@ function emitShouldForwardPropWrappers(ctx) {
|
|
|
13703
13904
|
const prefix = dropPrefix;
|
|
13704
13905
|
const isPrefixProp = !!prefix && typeof p.jsxProp === "string" && p.jsxProp !== "__props" && p.jsxProp.startsWith(prefix);
|
|
13705
13906
|
const propExpr = isPrefixProp ? knownPrefixPropsSet.has(p.jsxProp) ? j.identifier(p.jsxProp) : j.memberExpression(j.identifier("props"), j.literal(p.jsxProp), true) : p.jsxProp === "__props" ? j.identifier("props") : j.identifier(p.jsxProp);
|
|
13706
|
-
const callArg = p.callArg ?? propExpr;
|
|
13907
|
+
const callArg = wrapCallArgForPropsObject(j, p.callArg ?? propExpr, p.propsObjectKey);
|
|
13707
13908
|
const call = j.callExpression(styleRef(j, stylesIdentifier, p.fnKey), [callArg]);
|
|
13708
13909
|
let expr;
|
|
13709
13910
|
if (p.conditionWhen) {
|
|
13710
13911
|
const { cond, isBoolean } = emitter.collectConditionProps({
|
|
13711
13912
|
when: p.conditionWhen,
|
|
13712
|
-
destructureProps: destructureParts
|
|
13913
|
+
destructureProps: destructureParts,
|
|
13914
|
+
booleanProps
|
|
13713
13915
|
});
|
|
13714
13916
|
expr = emitter.makeConditionalStyleExpr({
|
|
13715
13917
|
cond,
|
|
@@ -14876,8 +15078,8 @@ function createThemeResolvers(args) {
|
|
|
14876
15078
|
const themeAccessExpr = unwrapLogicalFallback(bodyExpr) ?? bodyExpr;
|
|
14877
15079
|
const direct = resolveThemeValue(themeAccessExpr, cssProperty);
|
|
14878
15080
|
if (direct) {
|
|
14879
|
-
if (
|
|
14880
|
-
return
|
|
15081
|
+
if (hasNonLiteralLogicalFallback(bodyExpr)) return null;
|
|
15082
|
+
return direct;
|
|
14881
15083
|
}
|
|
14882
15084
|
const paramName = expr.params?.[0]?.type === "Identifier" ? expr.params[0].name : null;
|
|
14883
15085
|
const unwrap = (node) => {
|
|
@@ -14911,8 +15113,8 @@ function createThemeResolvers(args) {
|
|
|
14911
15113
|
if (!themePath) return null;
|
|
14912
15114
|
const resolved = resolveThemePath(themePath, getNodeLocStart(unwrapped) ?? void 0, cssProperty);
|
|
14913
15115
|
if (!resolved) return null;
|
|
14914
|
-
if (
|
|
14915
|
-
return
|
|
15116
|
+
if (hasNonLiteralLogicalFallback(bodyExpr)) return null;
|
|
15117
|
+
return resolved;
|
|
14916
15118
|
};
|
|
14917
15119
|
return {
|
|
14918
15120
|
hasLocalThemeBinding,
|
|
@@ -14921,20 +15123,6 @@ function createThemeResolvers(args) {
|
|
|
14921
15123
|
};
|
|
14922
15124
|
}
|
|
14923
15125
|
/**
|
|
14924
|
-
* If `originalExpr` was a logical fallback (`X ?? "default"` / `X || "default"`),
|
|
14925
|
-
* wraps the resolved AST node in a LogicalExpression preserving the original
|
|
14926
|
-
* operator and fallback value.
|
|
14927
|
-
*
|
|
14928
|
-
* Returns null if the fallback (RHS) is not a static literal, because dynamic
|
|
14929
|
-
* references (e.g., `props.fallbackColor`) would be invalid in a static
|
|
14930
|
-
* `stylex.create()` context where `props` is not in scope.
|
|
14931
|
-
*/
|
|
14932
|
-
function wrapWithLogicalFallback(resolved, originalExpr, j) {
|
|
14933
|
-
if (!isLogicalExpressionNode(originalExpr) || originalExpr.operator !== "??" && originalExpr.operator !== "||") return resolved;
|
|
14934
|
-
if (literalToStaticValue(originalExpr.right) === null) return null;
|
|
14935
|
-
return j.logicalExpression(originalExpr.operator, resolved, originalExpr.right);
|
|
14936
|
-
}
|
|
14937
|
-
/**
|
|
14938
15126
|
* Type guard for the internal `__directional` tagged result.
|
|
14939
15127
|
*/
|
|
14940
15128
|
function isDirectionalThemeResult(value) {
|
|
@@ -16088,6 +16276,7 @@ function createLowerRulesState(ctx) {
|
|
|
16088
16276
|
j,
|
|
16089
16277
|
importMap
|
|
16090
16278
|
});
|
|
16279
|
+
const enumValueMap = buildEnumValueMap(root, j);
|
|
16091
16280
|
const crossFileSelectorsByLocal = /* @__PURE__ */ new Map();
|
|
16092
16281
|
if (ctx.crossFileSelectorUsages) for (const usage of ctx.crossFileSelectorUsages) crossFileSelectorsByLocal.set(usage.localName, usage);
|
|
16093
16282
|
const state = {
|
|
@@ -16132,6 +16321,7 @@ function createLowerRulesState(ctx) {
|
|
|
16132
16321
|
resolveCssHelperTemplate,
|
|
16133
16322
|
resolveImportInScope,
|
|
16134
16323
|
resolveImportForExpr,
|
|
16324
|
+
enumValueMap,
|
|
16135
16325
|
crossFileSelectorsByLocal,
|
|
16136
16326
|
inlineKeyframeNameMap: void 0,
|
|
16137
16327
|
bail: false,
|
|
@@ -17024,7 +17214,15 @@ function tryResolveConditionalValue(node, ctx) {
|
|
|
17024
17214
|
if (!isArrowFunctionExpression(expr)) return null;
|
|
17025
17215
|
const info = getArrowFnThemeParamInfo(expr);
|
|
17026
17216
|
const paramName = info?.kind === "propsParam" ? info.propsName : null;
|
|
17217
|
+
const propsParamName = paramName ?? void 0;
|
|
17218
|
+
const themeBindingName = info?.kind === "themeBinding" ? info.themeName : void 0;
|
|
17027
17219
|
const paramBindings = !paramName && !info ? getArrowFnParamBindings(expr) : null;
|
|
17220
|
+
const runtimeCallState = { info: null };
|
|
17221
|
+
const buildRuntimeCallResult = () => runtimeCallState.info ? {
|
|
17222
|
+
type: "runtimeCallOnly",
|
|
17223
|
+
resolveCallContext: runtimeCallState.info.resolveCallContext,
|
|
17224
|
+
resolveCallResult: runtimeCallState.info.resolveCallResult
|
|
17225
|
+
} : null;
|
|
17028
17226
|
const body = getFunctionBodyExpr(expr);
|
|
17029
17227
|
if (!body || body.type !== "ConditionalExpression") return null;
|
|
17030
17228
|
const checkThemeBooleanTest = (test) => {
|
|
@@ -17148,17 +17346,66 @@ function tryResolveConditionalValue(node, ctx) {
|
|
|
17148
17346
|
};
|
|
17149
17347
|
}
|
|
17150
17348
|
if (!b || typeof b !== "object") return null;
|
|
17349
|
+
const callHasThemeArg = (call) => (call.arguments ?? []).some((arg) => {
|
|
17350
|
+
if (!arg || typeof arg !== "object" || arg.type !== "MemberExpression") return false;
|
|
17351
|
+
if (propsParamName) {
|
|
17352
|
+
const parts = getMemberPathFromIdentifier(arg, propsParamName);
|
|
17353
|
+
return parts !== null && parts[0] === "theme" && parts.length > 1;
|
|
17354
|
+
}
|
|
17355
|
+
if (themeBindingName) {
|
|
17356
|
+
const parts = getMemberPathFromIdentifier(arg, themeBindingName);
|
|
17357
|
+
return parts !== null && parts.length > 0;
|
|
17358
|
+
}
|
|
17359
|
+
return false;
|
|
17360
|
+
});
|
|
17361
|
+
const markAsRuntimeCall = (call) => {
|
|
17362
|
+
runtimeCallState.info = {
|
|
17363
|
+
resolveCallContext: {
|
|
17364
|
+
callSiteFilePath: ctx.filePath,
|
|
17365
|
+
calleeImportedName: "<local>",
|
|
17366
|
+
calleeSource: {
|
|
17367
|
+
kind: "specifier",
|
|
17368
|
+
value: ctx.filePath
|
|
17369
|
+
},
|
|
17370
|
+
args: [],
|
|
17371
|
+
...call.loc?.start ? { loc: {
|
|
17372
|
+
line: call.loc.start.line,
|
|
17373
|
+
column: call.loc.start.column
|
|
17374
|
+
} } : {}
|
|
17375
|
+
},
|
|
17376
|
+
resolveCallResult: { preserveRuntimeCall: true }
|
|
17377
|
+
};
|
|
17378
|
+
};
|
|
17151
17379
|
const resolveCallExpr = (call, cssProperty) => {
|
|
17152
|
-
const res = resolveImportedHelperCall(call, ctx,
|
|
17153
|
-
if (res.kind === "resolved"
|
|
17380
|
+
const res = resolveImportedHelperCall(call, ctx, propsParamName, cssProperty, themeBindingName);
|
|
17381
|
+
if (res.kind === "resolved") {
|
|
17382
|
+
if ("expr" in res.result) return res.result;
|
|
17383
|
+
if (res.result.preserveRuntimeCall) {
|
|
17384
|
+
runtimeCallState.info = {
|
|
17385
|
+
resolveCallContext: res.resolveCallContext,
|
|
17386
|
+
resolveCallResult: res.resolveCallResult
|
|
17387
|
+
};
|
|
17388
|
+
return null;
|
|
17389
|
+
}
|
|
17390
|
+
}
|
|
17154
17391
|
if (isCallExpressionNode(call.callee)) {
|
|
17155
17392
|
const inner = call.callee;
|
|
17156
17393
|
const outerArgs = call.arguments ?? [];
|
|
17157
17394
|
if (outerArgs.length === 1 && outerArgs[0] && typeof outerArgs[0] === "object") {
|
|
17158
|
-
const innerRes = resolveImportedHelperCall(inner, ctx,
|
|
17159
|
-
if (innerRes.kind === "resolved"
|
|
17395
|
+
const innerRes = resolveImportedHelperCall(inner, ctx, propsParamName, cssProperty, themeBindingName);
|
|
17396
|
+
if (innerRes.kind === "resolved") {
|
|
17397
|
+
if ("expr" in innerRes.result) return innerRes.result;
|
|
17398
|
+
if (innerRes.result.preserveRuntimeCall) {
|
|
17399
|
+
runtimeCallState.info = {
|
|
17400
|
+
resolveCallContext: innerRes.resolveCallContext,
|
|
17401
|
+
resolveCallResult: innerRes.resolveCallResult
|
|
17402
|
+
};
|
|
17403
|
+
return null;
|
|
17404
|
+
}
|
|
17405
|
+
}
|
|
17160
17406
|
}
|
|
17161
17407
|
}
|
|
17408
|
+
if (callHasThemeArg(call)) markAsRuntimeCall(call);
|
|
17162
17409
|
return null;
|
|
17163
17410
|
};
|
|
17164
17411
|
const templateResult = resolveTemplateLiteralExpressions(b, (expr) => {
|
|
@@ -17239,7 +17486,7 @@ function tryResolveConditionalValue(node, ctx) {
|
|
|
17239
17486
|
};
|
|
17240
17487
|
const extractConditionInfo = (test) => {
|
|
17241
17488
|
if (test.type !== "BinaryExpression" || test.operator !== "===" && test.operator !== "!==") return null;
|
|
17242
|
-
const rhsRaw =
|
|
17489
|
+
const rhsRaw = resolveStaticExpressionValue(test.right, ctx.enumValueMap);
|
|
17243
17490
|
if (rhsRaw === null) return null;
|
|
17244
17491
|
if (paramName && test.left.type === "MemberExpression") {
|
|
17245
17492
|
const leftPath = getMemberPathFromIdentifier(test.left, paramName);
|
|
@@ -17389,7 +17636,7 @@ function tryResolveConditionalValue(node, ctx) {
|
|
|
17389
17636
|
}
|
|
17390
17637
|
}
|
|
17391
17638
|
}
|
|
17392
|
-
if (!cons || !alt) return
|
|
17639
|
+
if (!cons || !alt) return buildRuntimeCallResult();
|
|
17393
17640
|
if (new Set([cons.usage, alt.usage]).size !== 1) return null;
|
|
17394
17641
|
const usage = cons.usage;
|
|
17395
17642
|
const variants = [{
|
|
@@ -17438,6 +17685,7 @@ function tryResolveConditionalValue(node, ctx) {
|
|
|
17438
17685
|
};
|
|
17439
17686
|
}
|
|
17440
17687
|
}
|
|
17688
|
+
if (!cons || !alt) return buildRuntimeCallResult();
|
|
17441
17689
|
}
|
|
17442
17690
|
if (paramBindings?.kind === "destructured" && test.type === "Identifier" && typeof test.name === "string") {
|
|
17443
17691
|
const resolvedProp = resolveIdentifierToPropName(test, paramBindings);
|
|
@@ -17475,6 +17723,7 @@ function tryResolveConditionalValue(node, ctx) {
|
|
|
17475
17723
|
if (result) return result;
|
|
17476
17724
|
}
|
|
17477
17725
|
}
|
|
17726
|
+
if (!cons || !alt) return buildRuntimeCallResult();
|
|
17478
17727
|
}
|
|
17479
17728
|
}
|
|
17480
17729
|
const condInfo = extractConditionInfo(test);
|
|
@@ -17520,7 +17769,7 @@ function tryResolveConditionalValue(node, ctx) {
|
|
|
17520
17769
|
};
|
|
17521
17770
|
}
|
|
17522
17771
|
}
|
|
17523
|
-
return
|
|
17772
|
+
return buildRuntimeCallResult();
|
|
17524
17773
|
}
|
|
17525
17774
|
function tryResolveConditionalCssBlock(node, ctx) {
|
|
17526
17775
|
const expr = node.expr;
|
|
@@ -17600,7 +17849,7 @@ function tryResolveConditionalCssBlockTernary(node, ctx) {
|
|
|
17600
17849
|
return null;
|
|
17601
17850
|
}
|
|
17602
17851
|
if (t.type === "BinaryExpression" && (t.operator === "===" || t.operator === "!==")) {
|
|
17603
|
-
const rhsRaw =
|
|
17852
|
+
const rhsRaw = resolveStaticExpressionValue(t.right, ctx.enumValueMap);
|
|
17604
17853
|
if (rhsRaw === null) return null;
|
|
17605
17854
|
const left = t.left;
|
|
17606
17855
|
if (paramName && left?.type === "MemberExpression") {
|
|
@@ -17982,7 +18231,7 @@ function replaceThemeRefsWithHookVar(expr, paramName, info) {
|
|
|
17982
18231
|
* Order matters: more-specific transforms first, then fall back to prop-access emission.
|
|
17983
18232
|
*/
|
|
17984
18233
|
function resolveDynamicNode(node, ctx) {
|
|
17985
|
-
return tryResolveThemeAccess(node, ctx) ?? tryResolveCallExpression(node, ctx) ?? tryResolveArrowFnHelperCallWithThemeArg(node, ctx) ?? tryResolveArrowFnCallWithConditionalArgs(node, ctx) ?? tryResolveConditionalValue(node, ctx) ?? tryResolveIndexedThemeWithPropFallback(node, ctx) ?? tryResolveConditionalCssBlockTernary(node, ctx) ?? tryResolveConditionalCssBlock(node, ctx) ?? tryResolveArrowFnCallWithSinglePropArg(node, ctx) ?? tryResolveThemeDependentTemplateLiteral(node, ctx) ?? tryResolveStyleFunctionFromTemplateLiteral(node) ?? tryResolveInlineStyleValueForNestedPropAccess(node) ?? tryResolvePropAccess(node) ?? tryResolveConditionalPropStyleFunction(node) ?? tryResolveInlineStyleValueForConditionalExpression(node) ?? tryResolveInlineStyleValueForLogicalExpression(node) ?? tryResolveInlineStyleValueFromArrowFn(node);
|
|
18234
|
+
return tryResolveThemeAccess(node, ctx) ?? tryResolveCallExpression(node, ctx) ?? tryResolveArrowFnHelperCallWithThemeArg(node, ctx) ?? tryResolveArrowFnCallWithConditionalArgs(node, ctx) ?? tryResolveConditionalValue(node, ctx) ?? tryResolveIndexedThemeWithPropFallback(node, ctx) ?? tryResolveConditionalCssBlockTernary(node, ctx) ?? tryResolveConditionalCssBlock(node, ctx) ?? tryResolveArrowFnCallWithSinglePropArg(node, ctx) ?? tryResolveThemeDependentTemplateLiteral(node, ctx) ?? tryResolveStyleFunctionFromTemplateLiteral(node) ?? tryResolveInlineStyleValueForNestedPropAccess(node) ?? tryResolvePropAccess(node) ?? tryResolveConditionalPropStyleFunction(node) ?? tryResolveArrowFnPropExpression(node) ?? tryResolveInlineStyleValueForConditionalExpression(node) ?? tryResolveInlineStyleValueForLogicalExpression(node) ?? tryResolveInlineStyleValueFromArrowFn(node);
|
|
17986
18235
|
}
|
|
17987
18236
|
function tryResolveThemeAccess(node, ctx) {
|
|
17988
18237
|
const expr = node.expr;
|
|
@@ -18011,11 +18260,10 @@ function tryResolveThemeAccess(node, ctx) {
|
|
|
18011
18260
|
type: "resolvedDirectional",
|
|
18012
18261
|
directional: res.directional
|
|
18013
18262
|
};
|
|
18014
|
-
|
|
18015
|
-
if (resultExpr === null) return null;
|
|
18263
|
+
if (hasNonLiteralLogicalFallback(expr.body)) return null;
|
|
18016
18264
|
return {
|
|
18017
18265
|
type: "resolvedValue",
|
|
18018
|
-
expr:
|
|
18266
|
+
expr: res.expr,
|
|
18019
18267
|
imports: res.imports
|
|
18020
18268
|
};
|
|
18021
18269
|
}
|
|
@@ -18028,8 +18276,8 @@ function tryResolveThemeAccess(node, ctx) {
|
|
|
18028
18276
|
* (LogicalExpression with `??` or `||` and theme access on the left)
|
|
18029
18277
|
*
|
|
18030
18278
|
* Returns the MemberExpression node, or null if the pattern doesn't match.
|
|
18031
|
-
* The fallback (right side of `??`/`||`) is
|
|
18032
|
-
*
|
|
18279
|
+
* The fallback (right side of `??`/`||`) is dropped because StyleX `defineVars`
|
|
18280
|
+
* tokens always resolve at runtime.
|
|
18033
18281
|
*/
|
|
18034
18282
|
function extractThemeMemberExpression(body) {
|
|
18035
18283
|
if (!body || typeof body !== "object") return null;
|
|
@@ -18375,6 +18623,29 @@ function collectPropsFromExprTree(nodes, paramName) {
|
|
|
18375
18623
|
props
|
|
18376
18624
|
};
|
|
18377
18625
|
}
|
|
18626
|
+
/**
|
|
18627
|
+
* Checks whether the param name is used as a bare identifier anywhere in the
|
|
18628
|
+
* expression tree (i.e., not as the `object` of a non-computed MemberExpression
|
|
18629
|
+
* like `props.X`). This detects patterns like `helper(props)` or computed access
|
|
18630
|
+
* `props[expr]` where the full props object is needed, which would break
|
|
18631
|
+
* `emitStyleFunctionFromPropsObject` since that handler only forwards a subset
|
|
18632
|
+
* of collected prop names.
|
|
18633
|
+
*/
|
|
18634
|
+
function hasBareParamUsage(root, paramName) {
|
|
18635
|
+
const visit = (node, skipIdent) => {
|
|
18636
|
+
if (!node || typeof node !== "object") return false;
|
|
18637
|
+
if (Array.isArray(node)) return node.some((child) => visit(child, false));
|
|
18638
|
+
const n = node;
|
|
18639
|
+
if (n.type === "Identifier" && n.name === paramName && !skipIdent) return true;
|
|
18640
|
+
for (const key of Object.keys(n)) {
|
|
18641
|
+
if (key === "loc" || key === "comments") continue;
|
|
18642
|
+
const child = n[key];
|
|
18643
|
+
if (visit(child, (n.type === "MemberExpression" || n.type === "OptionalMemberExpression") && !n.computed && (key === "object" || key === "property"))) return true;
|
|
18644
|
+
}
|
|
18645
|
+
return false;
|
|
18646
|
+
};
|
|
18647
|
+
return visit(root, false);
|
|
18648
|
+
}
|
|
18378
18649
|
function tryResolveStyleFunctionFromTemplateLiteral(node) {
|
|
18379
18650
|
if (!node.css.property) return null;
|
|
18380
18651
|
const expr = node.expr;
|
|
@@ -18460,6 +18731,35 @@ function tryDecomposeConditionalBranches(condBody, paramName) {
|
|
|
18460
18731
|
isStaticWhenFalse
|
|
18461
18732
|
};
|
|
18462
18733
|
}
|
|
18734
|
+
/**
|
|
18735
|
+
* Handles arrow functions whose body is a computational expression referencing props.
|
|
18736
|
+
*
|
|
18737
|
+
* Catches expression types not covered by specific handlers (e.g. BinaryExpression,
|
|
18738
|
+
* UnaryExpression) and emits a StyleX style function that takes the props object.
|
|
18739
|
+
*
|
|
18740
|
+
* Pattern: `(props) => props.$depth * 16 + 4`
|
|
18741
|
+
* Output: `(props) => ({ paddingLeft: \`${props.$depth * 16 + 4}px\` })`
|
|
18742
|
+
*/
|
|
18743
|
+
function tryResolveArrowFnPropExpression(node) {
|
|
18744
|
+
if (!node.css.property) return null;
|
|
18745
|
+
const expr = node.expr;
|
|
18746
|
+
if (!isArrowFunctionExpression(expr)) return null;
|
|
18747
|
+
const paramName = getArrowFnSingleParamName(expr);
|
|
18748
|
+
if (!paramName) return null;
|
|
18749
|
+
const body = getFunctionBodyExpr(expr);
|
|
18750
|
+
if (!body) return null;
|
|
18751
|
+
const bodyType = body.type;
|
|
18752
|
+
if (bodyType !== "BinaryExpression" && bodyType !== "UnaryExpression") return null;
|
|
18753
|
+
if (hasThemeAccessInArrowFn(expr)) return null;
|
|
18754
|
+
if (hasBareParamUsage(body, paramName)) return null;
|
|
18755
|
+
const { hasUsableProps, hasNonTransientProps, props } = collectPropsFromExprTree([body], paramName);
|
|
18756
|
+
if (!hasUsableProps) return null;
|
|
18757
|
+
if (hasNonTransientProps && node.component.withConfig?.shouldForwardProp) return null;
|
|
18758
|
+
return {
|
|
18759
|
+
type: "emitStyleFunctionFromPropsObject",
|
|
18760
|
+
props
|
|
18761
|
+
};
|
|
18762
|
+
}
|
|
18463
18763
|
function tryResolveInlineStyleValueForNestedPropAccess(node) {
|
|
18464
18764
|
if (!node.css.property) return null;
|
|
18465
18765
|
const expr = node.expr;
|
|
@@ -18544,23 +18844,6 @@ function hasBooleanBranch(node) {
|
|
|
18544
18844
|
if (n.type === "Literal" && typeof n.value === "boolean") return true;
|
|
18545
18845
|
return false;
|
|
18546
18846
|
}
|
|
18547
|
-
/**
|
|
18548
|
-
* If `body` is a logical fallback expression (`X ?? "default"` / `X || "default"`),
|
|
18549
|
-
* appends the operator and fallback literal to the resolved expression string.
|
|
18550
|
-
*
|
|
18551
|
-
* Returns `null` when the body IS a logical expression but the fallback is non-literal
|
|
18552
|
-
* (e.g., `props.fallbackColor`, `null`, `undefined`), signalling to the caller that
|
|
18553
|
-
* it's unsafe to drop the fallback — the caller should bail instead of resolving.
|
|
18554
|
-
*
|
|
18555
|
-
* Returns `resolvedExpr` unchanged when the body is NOT a logical expression (no
|
|
18556
|
-
* fallback to preserve).
|
|
18557
|
-
*/
|
|
18558
|
-
function appendLogicalFallback(body, resolvedExpr) {
|
|
18559
|
-
if (!isLogicalExpressionNode(body) || body.operator !== "??" && body.operator !== "||") return resolvedExpr;
|
|
18560
|
-
const fallback = literalToStaticValue(body.right);
|
|
18561
|
-
if (fallback === null) return null;
|
|
18562
|
-
return `${resolvedExpr} ${body.operator} ${JSON.stringify(fallback)}`;
|
|
18563
|
-
}
|
|
18564
18847
|
|
|
18565
18848
|
//#endregion
|
|
18566
18849
|
//#region src/internal/lower-rules/template-literals.ts
|
|
@@ -20729,7 +21012,7 @@ const createValuePatternHandlers = (ctx) => {
|
|
|
20729
21012
|
const p = leftPath[0];
|
|
20730
21013
|
propName = propName ?? p;
|
|
20731
21014
|
if (propName !== p) return false;
|
|
20732
|
-
const rhs =
|
|
21015
|
+
const rhs = resolveStaticExpressionValue(test.right, ctx.enumValueMap);
|
|
20733
21016
|
if (rhs === null) return false;
|
|
20734
21017
|
const retValue = readIfReturnValue(stmt);
|
|
20735
21018
|
if (retValue === null) return false;
|
|
@@ -20892,7 +21175,7 @@ const createValuePatternHandlers = (ctx) => {
|
|
|
20892
21175
|
* Core concepts: per-component style buckets, helper factories, and resolver wiring.
|
|
20893
21176
|
*/
|
|
20894
21177
|
function createDeclProcessingState(state, decl) {
|
|
20895
|
-
const { api, j, root, filePath, warnings, resolverImports, parseExpr, resolveValue, resolveValueDirectional, resolveCall, resolveCallOptional, resolveSelector, importMap, cssHelperFunctions, stringMappingFns, hasLocalThemeBinding, isCssHelperTaggedTemplate, resolveCssHelperTemplate, resolveImportInScope, usedCssHelperFunctions, markBail } = state;
|
|
21178
|
+
const { api, j, root, filePath, warnings, resolverImports, parseExpr, resolveValue, resolveValueDirectional, resolveCall, resolveCallOptional, resolveSelector, importMap, cssHelperFunctions, stringMappingFns, hasLocalThemeBinding, isCssHelperTaggedTemplate, resolveCssHelperTemplate, resolveImportInScope, usedCssHelperFunctions, enumValueMap, markBail } = state;
|
|
20896
21179
|
const styleObj = {};
|
|
20897
21180
|
const perPropPseudo = {};
|
|
20898
21181
|
const perPropMedia = {};
|
|
@@ -20990,6 +21273,7 @@ function createDeclProcessingState(state, decl) {
|
|
|
20990
21273
|
...sharedFromState,
|
|
20991
21274
|
api,
|
|
20992
21275
|
importMap,
|
|
21276
|
+
enumValueMap,
|
|
20993
21277
|
decl,
|
|
20994
21278
|
styleObj,
|
|
20995
21279
|
variantBuckets,
|
|
@@ -21009,7 +21293,8 @@ function createDeclProcessingState(state, decl) {
|
|
|
21009
21293
|
resolveCall,
|
|
21010
21294
|
resolveCallOptional,
|
|
21011
21295
|
resolveImport: resolveImportInScope,
|
|
21012
|
-
hasImportIgnoringShadowing: (localName) => importMap.has(localName)
|
|
21296
|
+
hasImportIgnoringShadowing: (localName) => importMap.has(localName),
|
|
21297
|
+
enumValueMap
|
|
21013
21298
|
};
|
|
21014
21299
|
const withConfig = decl.shouldForwardProp ? { shouldForwardProp: true } : void 0;
|
|
21015
21300
|
const componentInfo = decl.base.kind === "intrinsic" ? {
|
|
@@ -21859,13 +22144,13 @@ function handleSplitVariantsResolvedValue(ctx) {
|
|
|
21859
22144
|
}
|
|
21860
22145
|
if (isHeterogeneousBackground) {
|
|
21861
22146
|
const isNestedTernary = allPosParsed.length > 1;
|
|
22147
|
+
const defaultStylexProp = neg ? resolveBackgroundStylexProp(neg.expr) : null;
|
|
21862
22148
|
if (neg && negParsed) {
|
|
21863
|
-
|
|
21864
|
-
|
|
21865
|
-
|
|
21866
|
-
|
|
21867
|
-
|
|
21868
|
-
variantStyleKeys[neg.when] ??= `${decl.styleKey}${suffix}`;
|
|
22149
|
+
if (!applyParsed(styleObj, negParsed, defaultStylexProp)) {
|
|
22150
|
+
bailUnsupported(decl, "Resolved conditional border variant could not be expanded to longhand properties");
|
|
22151
|
+
setBail();
|
|
22152
|
+
return true;
|
|
22153
|
+
}
|
|
21869
22154
|
}
|
|
21870
22155
|
for (let i = 0; i < allPosParsed.length; i++) {
|
|
21871
22156
|
const { when, nameHint, parsed } = allPosParsed[i];
|
|
@@ -21874,6 +22159,7 @@ function handleSplitVariantsResolvedValue(ctx) {
|
|
|
21874
22159
|
const whenClean = when.replace(/^!/, "");
|
|
21875
22160
|
const bucket = { ...variantBuckets.get(whenClean) };
|
|
21876
22161
|
applyParsed(bucket, parsed, posStylexProp);
|
|
22162
|
+
if (defaultStylexProp && posStylexProp !== defaultStylexProp) bucket[defaultStylexProp] = j.literal("transparent");
|
|
21877
22163
|
variantBuckets.set(whenClean, bucket);
|
|
21878
22164
|
const suffix = isNestedTernary && nameHint && !new Set([
|
|
21879
22165
|
"truthy",
|
|
@@ -23477,6 +23763,12 @@ function handleInterpolatedDeclaration(args) {
|
|
|
23477
23763
|
const { prefix, suffix } = extractStaticPartsForDecl(d);
|
|
23478
23764
|
const valueExpr = prefix || suffix ? buildTemplateWithStaticParts(j, valueExprRaw, prefix, suffix) : valueExprRaw;
|
|
23479
23765
|
const param = j.identifier(paramName);
|
|
23766
|
+
if (/\.(ts|tsx)$/.test(filePath)) {
|
|
23767
|
+
if (!(decl.propsType?.type === "TSTypeReference")) {
|
|
23768
|
+
const typeName = `${decl.localName}Props`;
|
|
23769
|
+
param.typeAnnotation = j.tsTypeAnnotation(j.tsTypeReference(j.identifier(typeName)));
|
|
23770
|
+
}
|
|
23771
|
+
}
|
|
23480
23772
|
const body = j.objectExpression([j.property("init", makeCssPropKey(j, out.prop), buildPseudoMediaPropValue({
|
|
23481
23773
|
j,
|
|
23482
23774
|
valueExpr,
|
|
@@ -23485,18 +23777,10 @@ function handleInterpolatedDeclaration(args) {
|
|
|
23485
23777
|
}))]);
|
|
23486
23778
|
styleFnDecls.set(fnKey, j.arrowFunctionExpression([param], body));
|
|
23487
23779
|
}
|
|
23488
|
-
if (!styleFnFromProps.some((p) => p.fnKey === fnKey)) {
|
|
23489
|
-
|
|
23490
|
-
|
|
23491
|
-
|
|
23492
|
-
return prop;
|
|
23493
|
-
}));
|
|
23494
|
-
styleFnFromProps.push({
|
|
23495
|
-
fnKey,
|
|
23496
|
-
jsxProp: "__props",
|
|
23497
|
-
callArg
|
|
23498
|
-
});
|
|
23499
|
-
}
|
|
23780
|
+
if (!styleFnFromProps.some((p) => p.fnKey === fnKey)) styleFnFromProps.push({
|
|
23781
|
+
fnKey,
|
|
23782
|
+
jsxProp: "__props"
|
|
23783
|
+
});
|
|
23500
23784
|
}
|
|
23501
23785
|
continue;
|
|
23502
23786
|
}
|
|
@@ -25560,11 +25844,195 @@ function finalizeDeclProcessing(ctx) {
|
|
|
25560
25844
|
});
|
|
25561
25845
|
decl.styleFnFromProps = styleFnFromProps;
|
|
25562
25846
|
}
|
|
25563
|
-
|
|
25847
|
+
mergeBaseIntoSingleStyleFn({
|
|
25848
|
+
j: state.j,
|
|
25849
|
+
decl,
|
|
25850
|
+
styleObj,
|
|
25851
|
+
styleFnFromProps,
|
|
25852
|
+
styleFnDecls,
|
|
25853
|
+
remainingStyleKeys,
|
|
25854
|
+
extraStyleObjects,
|
|
25855
|
+
styledDecls: state.styledDecls
|
|
25856
|
+
});
|
|
25857
|
+
convertStyleFnsToPropsPattern(state.j, styleFnDecls, styleFnFromProps, decl.styleKey);
|
|
25858
|
+
insertStyleFnDeclsAfterComponent(resolvedStyleObjects, styleFnDecls, {
|
|
25859
|
+
styleKey: decl.styleKey,
|
|
25860
|
+
extraStyleObjects,
|
|
25861
|
+
remainingStyleKeys,
|
|
25862
|
+
attrBuckets,
|
|
25863
|
+
enumVariant: decl.enumVariant
|
|
25864
|
+
});
|
|
25564
25865
|
if (styleFnDecls.has(decl.styleKey) && Object.keys(styleObj).length === 0) decl.skipBaseStyleRef = true;
|
|
25565
25866
|
if (inlineStyleProps.length) decl.inlineStyleProps = inlineStyleProps;
|
|
25566
25867
|
}
|
|
25567
25868
|
/**
|
|
25869
|
+
* Inserts styleFnDecls entries into resolvedStyleObjects right after the last
|
|
25870
|
+
* entry belonging to the current component. This ensures dynamic style functions
|
|
25871
|
+
* appear adjacent to their static counterparts in stylex.create() output.
|
|
25872
|
+
*/
|
|
25873
|
+
function insertStyleFnDeclsAfterComponent(resolvedStyleObjects, styleFnDecls, component) {
|
|
25874
|
+
if (styleFnDecls.size === 0) return;
|
|
25875
|
+
const componentKeys = /* @__PURE__ */ new Set();
|
|
25876
|
+
componentKeys.add(component.styleKey);
|
|
25877
|
+
for (const k of component.extraStyleObjects.keys()) componentKeys.add(k);
|
|
25878
|
+
for (const k of Object.values(component.remainingStyleKeys)) componentKeys.add(k);
|
|
25879
|
+
for (const k of component.attrBuckets.keys()) componentKeys.add(k);
|
|
25880
|
+
if (component.enumVariant) {
|
|
25881
|
+
componentKeys.add(component.enumVariant.baseKey);
|
|
25882
|
+
for (const c of component.enumVariant.cases) componentKeys.add(c.styleKey);
|
|
25883
|
+
}
|
|
25884
|
+
for (const k of styleFnDecls.keys()) if (resolvedStyleObjects.has(k)) componentKeys.add(k);
|
|
25885
|
+
let lastComponentKey = null;
|
|
25886
|
+
for (const k of resolvedStyleObjects.keys()) if (componentKeys.has(k)) lastComponentKey = k;
|
|
25887
|
+
if (lastComponentKey === null) {
|
|
25888
|
+
for (const [k, v] of styleFnDecls.entries()) resolvedStyleObjects.set(k, v);
|
|
25889
|
+
return;
|
|
25890
|
+
}
|
|
25891
|
+
const emittedFnKeys = /* @__PURE__ */ new Set();
|
|
25892
|
+
const entries = [...resolvedStyleObjects.entries()];
|
|
25893
|
+
resolvedStyleObjects.clear();
|
|
25894
|
+
for (const [k, v] of entries) {
|
|
25895
|
+
if (styleFnDecls.has(k)) {
|
|
25896
|
+
resolvedStyleObjects.set(k, styleFnDecls.get(k));
|
|
25897
|
+
emittedFnKeys.add(k);
|
|
25898
|
+
} else resolvedStyleObjects.set(k, v);
|
|
25899
|
+
if (k === lastComponentKey) {
|
|
25900
|
+
for (const [fk, fv] of styleFnDecls.entries()) if (!emittedFnKeys.has(fk)) {
|
|
25901
|
+
resolvedStyleObjects.set(fk, fv);
|
|
25902
|
+
emittedFnKeys.add(fk);
|
|
25903
|
+
}
|
|
25904
|
+
}
|
|
25905
|
+
}
|
|
25906
|
+
}
|
|
25907
|
+
/**
|
|
25908
|
+
* Merges static base properties into a single unconditional style function.
|
|
25909
|
+
*
|
|
25910
|
+
* When a styled component has both static CSS properties and a single
|
|
25911
|
+
* unconditional dynamic style function, the static properties are folded
|
|
25912
|
+
* into the function's return object so that the emitted code uses a single
|
|
25913
|
+
* `styles.key(arg)` call instead of separate `styles.key, styles.keyDynamic(arg)`.
|
|
25914
|
+
*
|
|
25915
|
+
* Preconditions:
|
|
25916
|
+
* - Exactly one unconditional styleFn entry (no conditionWhen)
|
|
25917
|
+
* - Base styleObj has at least one property
|
|
25918
|
+
* - No variant style keys, extra style objects, or enum variants
|
|
25919
|
+
* - The component is not extended by other styled components
|
|
25920
|
+
*/
|
|
25921
|
+
function mergeBaseIntoSingleStyleFn(args) {
|
|
25922
|
+
const { j, decl, styleObj, styleFnFromProps, styleFnDecls, remainingStyleKeys, extraStyleObjects, styledDecls } = args;
|
|
25923
|
+
if (Object.keys(styleObj).length === 0) return;
|
|
25924
|
+
if (styleFnFromProps.length === 0) return;
|
|
25925
|
+
if (Object.keys(remainingStyleKeys).length > 0) return;
|
|
25926
|
+
if (extraStyleObjects.size > 0) return;
|
|
25927
|
+
if (decl.enumVariant) return;
|
|
25928
|
+
for (const other of styledDecls) if (other !== decl && other.extendsStyleKey === decl.styleKey) return;
|
|
25929
|
+
const unconditionalEntries = styleFnFromProps.filter((p) => !p.conditionWhen && p.condition === "always");
|
|
25930
|
+
if (unconditionalEntries.length !== 1) return;
|
|
25931
|
+
const entry = unconditionalEntries[0];
|
|
25932
|
+
const fnKey = entry.fnKey;
|
|
25933
|
+
const fnAst = styleFnDecls.get(fnKey);
|
|
25934
|
+
if (!fnAst || typeof fnAst !== "object") return;
|
|
25935
|
+
const body = getFunctionBodyExpr(fnAst);
|
|
25936
|
+
if (!body || body.type !== "ObjectExpression") return;
|
|
25937
|
+
const bodyObj = body;
|
|
25938
|
+
if (!Array.isArray(bodyObj.properties)) return;
|
|
25939
|
+
const existingKeys = /* @__PURE__ */ new Set();
|
|
25940
|
+
for (const prop of bodyObj.properties) {
|
|
25941
|
+
const key = prop.key;
|
|
25942
|
+
if (key) existingKeys.add(key.name ?? key.value ?? "");
|
|
25943
|
+
}
|
|
25944
|
+
if (Object.keys(styleObj).filter((k) => !k.startsWith("__")).some((k) => existingKeys.has(k))) return;
|
|
25945
|
+
const prependProps = [];
|
|
25946
|
+
for (const [cssProp, cssValue] of Object.entries(styleObj)) {
|
|
25947
|
+
if (cssProp.startsWith("__")) continue;
|
|
25948
|
+
const valueAst = literalToAst(j, cssValue);
|
|
25949
|
+
const key = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(cssProp) ? j.identifier(cssProp) : j.literal(cssProp);
|
|
25950
|
+
prependProps.push(j.property("init", key, valueAst));
|
|
25951
|
+
}
|
|
25952
|
+
bodyObj.properties.unshift(...prependProps);
|
|
25953
|
+
if (fnKey !== decl.styleKey) {
|
|
25954
|
+
styleFnDecls.delete(fnKey);
|
|
25955
|
+
styleFnDecls.set(decl.styleKey, fnAst);
|
|
25956
|
+
entry.fnKey = decl.styleKey;
|
|
25957
|
+
}
|
|
25958
|
+
for (const key of Object.keys(styleObj)) delete styleObj[key];
|
|
25959
|
+
}
|
|
25960
|
+
/**
|
|
25961
|
+
* Converts single-positional-param style functions to use a named `props`
|
|
25962
|
+
* object parameter. Skips functions that already use a `props` parameter
|
|
25963
|
+
* (e.g. consolidated multi-param functions).
|
|
25964
|
+
*
|
|
25965
|
+
* Before: `(color: string) => ({ color })`
|
|
25966
|
+
* After: `(props: { color: string }) => ({ color: props.color })`
|
|
25967
|
+
*/
|
|
25968
|
+
function convertStyleFnsToPropsPattern(j, styleFnDecls, styleFnFromProps, baseStyleKey) {
|
|
25969
|
+
const managedFnKeys = new Set(styleFnFromProps.map((p) => p.fnKey));
|
|
25970
|
+
for (const [fnKey, fnAst] of styleFnDecls.entries()) {
|
|
25971
|
+
if (fnKey !== baseStyleKey) continue;
|
|
25972
|
+
if (!managedFnKeys.has(fnKey)) continue;
|
|
25973
|
+
if (!fnAst || typeof fnAst !== "object") continue;
|
|
25974
|
+
const fn = fnAst;
|
|
25975
|
+
if (!Array.isArray(fn.params) || fn.params.length !== 1) continue;
|
|
25976
|
+
const param = fn.params[0];
|
|
25977
|
+
if (param.type !== "Identifier" || !param.name || param.name === "props") continue;
|
|
25978
|
+
const paramName = param.name;
|
|
25979
|
+
const paramTypeAnnotation = param.typeAnnotation;
|
|
25980
|
+
const body = getFunctionBodyExpr(fn);
|
|
25981
|
+
if (!body || body.type !== "ObjectExpression") continue;
|
|
25982
|
+
replaceIdentifierInAst(j, body, paramName);
|
|
25983
|
+
const propsParam = j.identifier("props");
|
|
25984
|
+
if (paramTypeAnnotation) {
|
|
25985
|
+
const innerType = paramTypeAnnotation.typeAnnotation;
|
|
25986
|
+
if (innerType) {
|
|
25987
|
+
const propSignature = j.tsPropertySignature(j.identifier(paramName), j.tsTypeAnnotation(innerType));
|
|
25988
|
+
propsParam.typeAnnotation = j.tsTypeAnnotation(j.tsTypeLiteral([propSignature]));
|
|
25989
|
+
}
|
|
25990
|
+
}
|
|
25991
|
+
fn.params[0] = propsParam;
|
|
25992
|
+
for (const entry of styleFnFromProps) if (entry.fnKey === fnKey && !entry.propsObjectKey) entry.propsObjectKey = paramName;
|
|
25993
|
+
}
|
|
25994
|
+
}
|
|
25995
|
+
/**
|
|
25996
|
+
* Recursively replaces all `Identifier` references matching `oldName` with
|
|
25997
|
+
* `props.oldName` (a MemberExpression). Handles shorthand properties by
|
|
25998
|
+
* un-shorthanding them.
|
|
25999
|
+
*/
|
|
26000
|
+
function replaceIdentifierInAst(j, node, oldName) {
|
|
26001
|
+
if (!node || typeof node !== "object") return;
|
|
26002
|
+
const n = node;
|
|
26003
|
+
if (n.type === "ObjectExpression") {
|
|
26004
|
+
const properties = n.properties;
|
|
26005
|
+
if (!Array.isArray(properties)) return;
|
|
26006
|
+
for (const prop of properties) {
|
|
26007
|
+
if (prop.type === "SpreadElement" || prop.type === "SpreadProperty") {
|
|
26008
|
+
if (prop.argument?.type === "Identifier" && prop.argument.name === oldName) prop.argument = j.memberExpression(j.identifier("props"), j.identifier(oldName));
|
|
26009
|
+
else replaceIdentifierInAst(j, prop.argument, oldName);
|
|
26010
|
+
continue;
|
|
26011
|
+
}
|
|
26012
|
+
if (prop.type !== "Property") continue;
|
|
26013
|
+
if (prop.shorthand && prop.value?.type === "Identifier" && prop.value.name === oldName) {
|
|
26014
|
+
prop.shorthand = false;
|
|
26015
|
+
prop.value = j.memberExpression(j.identifier("props"), j.identifier(oldName));
|
|
26016
|
+
continue;
|
|
26017
|
+
}
|
|
26018
|
+
if (prop.computed) if (prop.key?.type === "Identifier" && prop.key.name === oldName) prop.key = j.memberExpression(j.identifier("props"), j.identifier(oldName));
|
|
26019
|
+
else replaceIdentifierInAst(j, prop.key, oldName);
|
|
26020
|
+
if (prop.value?.type === "Identifier" && prop.value.name === oldName) prop.value = j.memberExpression(j.identifier("props"), j.identifier(oldName));
|
|
26021
|
+
else replaceIdentifierInAst(j, prop.value, oldName);
|
|
26022
|
+
}
|
|
26023
|
+
return;
|
|
26024
|
+
}
|
|
26025
|
+
for (const key of Object.keys(n)) {
|
|
26026
|
+
if (key === "type" || key === "loc" || key === "start" || key === "end" || key === "comments") continue;
|
|
26027
|
+
if (key === "property" && n.type === "MemberExpression" && !n.computed) continue;
|
|
26028
|
+
const child = n[key];
|
|
26029
|
+
if (Array.isArray(child)) for (let i = 0; i < child.length; i++) if (child[i]?.type === "Identifier" && child[i].name === oldName) child[i] = j.memberExpression(j.identifier("props"), j.identifier(oldName));
|
|
26030
|
+
else replaceIdentifierInAst(j, child[i], oldName);
|
|
26031
|
+
else if (child?.type === "Identifier" && child.name === oldName) n[key] = j.memberExpression(j.identifier("props"), j.identifier(oldName));
|
|
26032
|
+
else if (child && typeof child === "object" && child.type) replaceIdentifierInAst(j, child, oldName);
|
|
26033
|
+
}
|
|
26034
|
+
}
|
|
26035
|
+
/**
|
|
25568
26036
|
* Merges a per-property condition bucket (pseudo or media) into the style object.
|
|
25569
26037
|
* When a property already exists as an object in styleObj, merges entries to
|
|
25570
26038
|
* preserve both pseudo-class and media query entries on the same property.
|
|
@@ -26623,123 +27091,11 @@ function appendToMapList(map, key, value) {
|
|
|
26623
27091
|
else map.set(key, [value]);
|
|
26624
27092
|
}
|
|
26625
27093
|
|
|
26626
|
-
//#endregion
|
|
26627
|
-
//#region src/internal/post-process/event-handler-annotations.ts
|
|
26628
|
-
/** Maps event handler prop names to their React event type. */
|
|
26629
|
-
const EVENT_TYPE_MAP = {
|
|
26630
|
-
onClick: "React.MouseEvent",
|
|
26631
|
-
onContextMenu: "React.MouseEvent",
|
|
26632
|
-
onMouseDown: "React.MouseEvent",
|
|
26633
|
-
onMouseUp: "React.MouseEvent",
|
|
26634
|
-
onMouseEnter: "React.MouseEvent",
|
|
26635
|
-
onMouseLeave: "React.MouseEvent",
|
|
26636
|
-
onMouseMove: "React.MouseEvent",
|
|
26637
|
-
onMouseOver: "React.MouseEvent",
|
|
26638
|
-
onDoubleClick: "React.MouseEvent",
|
|
26639
|
-
onKeyDown: "React.KeyboardEvent",
|
|
26640
|
-
onKeyUp: "React.KeyboardEvent",
|
|
26641
|
-
onKeyPress: "React.KeyboardEvent",
|
|
26642
|
-
onChange: "React.ChangeEvent",
|
|
26643
|
-
onInput: "React.FormEvent",
|
|
26644
|
-
onFocus: "React.FocusEvent",
|
|
26645
|
-
onBlur: "React.FocusEvent",
|
|
26646
|
-
onSubmit: "React.FormEvent",
|
|
26647
|
-
onScroll: "React.UIEvent",
|
|
26648
|
-
onWheel: "React.WheelEvent",
|
|
26649
|
-
onDragStart: "React.DragEvent",
|
|
26650
|
-
onDragEnd: "React.DragEvent",
|
|
26651
|
-
onDrop: "React.DragEvent",
|
|
26652
|
-
onDragOver: "React.DragEvent",
|
|
26653
|
-
onTouchStart: "React.TouchEvent",
|
|
26654
|
-
onTouchEnd: "React.TouchEvent",
|
|
26655
|
-
onTouchMove: "React.TouchEvent",
|
|
26656
|
-
onPointerDown: "React.PointerEvent",
|
|
26657
|
-
onPointerUp: "React.PointerEvent",
|
|
26658
|
-
onPointerMove: "React.PointerEvent",
|
|
26659
|
-
onCopy: "React.ClipboardEvent",
|
|
26660
|
-
onCut: "React.ClipboardEvent",
|
|
26661
|
-
onPaste: "React.ClipboardEvent",
|
|
26662
|
-
onAnimationEnd: "React.AnimationEvent",
|
|
26663
|
-
onAnimationStart: "React.AnimationEvent",
|
|
26664
|
-
onTransitionEnd: "React.TransitionEvent"
|
|
26665
|
-
};
|
|
26666
|
-
/** Maps intrinsic JSX tag names to their DOM element interface names. */
|
|
26667
|
-
const INTRINSIC_TAG_TO_ELEMENT_TYPE = {
|
|
26668
|
-
a: "HTMLAnchorElement",
|
|
26669
|
-
button: "HTMLButtonElement",
|
|
26670
|
-
div: "HTMLDivElement",
|
|
26671
|
-
form: "HTMLFormElement",
|
|
26672
|
-
img: "HTMLImageElement",
|
|
26673
|
-
input: "HTMLInputElement",
|
|
26674
|
-
label: "HTMLLabelElement",
|
|
26675
|
-
li: "HTMLLIElement",
|
|
26676
|
-
ol: "HTMLOListElement",
|
|
26677
|
-
option: "HTMLOptionElement",
|
|
26678
|
-
select: "HTMLSelectElement",
|
|
26679
|
-
span: "HTMLSpanElement",
|
|
26680
|
-
svg: "SVGSVGElement",
|
|
26681
|
-
table: "HTMLTableElement",
|
|
26682
|
-
tbody: "HTMLTableSectionElement",
|
|
26683
|
-
td: "HTMLTableCellElement",
|
|
26684
|
-
textarea: "HTMLTextAreaElement",
|
|
26685
|
-
th: "HTMLTableCellElement",
|
|
26686
|
-
thead: "HTMLTableSectionElement",
|
|
26687
|
-
tr: "HTMLTableRowElement",
|
|
26688
|
-
ul: "HTMLUListElement"
|
|
26689
|
-
};
|
|
26690
|
-
/**
|
|
26691
|
-
* Annotates event handler arrow function parameters at JSX usage sites of converted components.
|
|
26692
|
-
*
|
|
26693
|
-
* `componentTagMap` is best-effort and only populated for intrinsic-base conversions.
|
|
26694
|
-
* For wrappers around non-intrinsic components, event annotations stay non-generic.
|
|
26695
|
-
*
|
|
26696
|
-
* @returns true if any annotations were added
|
|
26697
|
-
*/
|
|
26698
|
-
function annotateEventHandlerParams(args) {
|
|
26699
|
-
const { root, j, convertedNames, componentTagMap } = args;
|
|
26700
|
-
if (convertedNames.size === 0) return false;
|
|
26701
|
-
let changed = false;
|
|
26702
|
-
root.find(j.JSXOpeningElement).filter((path) => {
|
|
26703
|
-
const name = path.node.name;
|
|
26704
|
-
if (name.type === "JSXIdentifier") return convertedNames.has(name.name);
|
|
26705
|
-
return false;
|
|
26706
|
-
}).forEach((jsxPath) => {
|
|
26707
|
-
const openingName = jsxPath.node.name;
|
|
26708
|
-
const componentName = openingName.type === "JSXIdentifier" ? openingName.name : null;
|
|
26709
|
-
const intrinsicTag = componentName ? componentTagMap.get(componentName) : void 0;
|
|
26710
|
-
const elementType = intrinsicTag ? INTRINSIC_TAG_TO_ELEMENT_TYPE[intrinsicTag] : void 0;
|
|
26711
|
-
for (const attr of jsxPath.node.attributes ?? []) {
|
|
26712
|
-
if (attr.type !== "JSXAttribute" || !attr.name || attr.name.type !== "JSXIdentifier") continue;
|
|
26713
|
-
const eventType = EVENT_TYPE_MAP[attr.name.name];
|
|
26714
|
-
if (!eventType) continue;
|
|
26715
|
-
const value = attr.value;
|
|
26716
|
-
if (!value || value.type !== "JSXExpressionContainer") continue;
|
|
26717
|
-
const expr = value.expression;
|
|
26718
|
-
if (!expr || expr.type !== "ArrowFunctionExpression") continue;
|
|
26719
|
-
const firstParam = expr.params[0];
|
|
26720
|
-
if (!firstParam) continue;
|
|
26721
|
-
if (firstParam.typeAnnotation) continue;
|
|
26722
|
-
if (firstParam.type !== "Identifier") continue;
|
|
26723
|
-
const parts = eventType.split(".");
|
|
26724
|
-
const typeRef = j.tsTypeReference(j.tsQualifiedName(j.identifier(parts[0]), j.identifier(parts[1])));
|
|
26725
|
-
if (elementType) typeRef.typeParameters = j.tsTypeParameterInstantiation([j.tsTypeReference(j.identifier(elementType))]);
|
|
26726
|
-
const annotatedParam = j.identifier(firstParam.name);
|
|
26727
|
-
annotatedParam.typeAnnotation = j.tsTypeAnnotation(typeRef);
|
|
26728
|
-
const newArrow = j.arrowFunctionExpression([annotatedParam, ...expr.params.slice(1)], expr.body, expr.expression);
|
|
26729
|
-
newArrow.async = expr.async ?? false;
|
|
26730
|
-
newArrow.returnType = expr.returnType ?? null;
|
|
26731
|
-
value.expression = newArrow;
|
|
26732
|
-
changed = true;
|
|
26733
|
-
}
|
|
26734
|
-
});
|
|
26735
|
-
return changed;
|
|
26736
|
-
}
|
|
26737
|
-
|
|
26738
27094
|
//#endregion
|
|
26739
27095
|
//#region src/internal/transform-steps/post-process.ts
|
|
26740
27096
|
/**
|
|
26741
27097
|
* Step: post-process transformed AST and cleanup imports.
|
|
26742
|
-
* Core concepts: relation overrides
|
|
27098
|
+
* Core concepts: relation overrides and import reconciliation.
|
|
26743
27099
|
*/
|
|
26744
27100
|
/**
|
|
26745
27101
|
* Performs post-processing rewrites, import cleanup, and descendant/ancestor selector adjustments.
|
|
@@ -26799,34 +27155,7 @@ function postProcessStep(ctx) {
|
|
|
26799
27155
|
return true;
|
|
26800
27156
|
}).size() === 0) fnPaths.forEach((p) => p.prune());
|
|
26801
27157
|
}
|
|
26802
|
-
if (/\.(ts|tsx)$/.test(file.path)) {
|
|
26803
|
-
const hasLocalAsUsage = (componentName) => {
|
|
26804
|
-
const hasAsAttr = (attrs) => (attrs ?? []).some((attr) => attr?.type === "JSXAttribute" && attr.name?.type === "JSXIdentifier" && (attr.name.name === "as" || attr.name.name === "forwardedAs"));
|
|
26805
|
-
if (root.find(j.JSXElement, { openingElement: { name: {
|
|
26806
|
-
type: "JSXIdentifier",
|
|
26807
|
-
name: componentName
|
|
26808
|
-
} } }).some((p) => hasAsAttr(p.node?.openingElement?.attributes))) return true;
|
|
26809
|
-
return root.find(j.JSXSelfClosingElement, { name: {
|
|
26810
|
-
type: "JSXIdentifier",
|
|
26811
|
-
name: componentName
|
|
26812
|
-
} }).some((p) => hasAsAttr(p.node?.attributes));
|
|
26813
|
-
};
|
|
26814
|
-
const convertedNames = /* @__PURE__ */ new Set();
|
|
26815
|
-
const componentTagMap = /* @__PURE__ */ new Map();
|
|
26816
|
-
for (const decl of styledDecls) {
|
|
26817
|
-
const isPolymorphic = !!decl.supportsAsProp || hasLocalAsUsage(decl.localName);
|
|
26818
|
-
if (decl.base.kind === "intrinsic" && !isPolymorphic) {
|
|
26819
|
-
convertedNames.add(decl.localName);
|
|
26820
|
-
componentTagMap.set(decl.localName, decl.base.tagName);
|
|
26821
|
-
}
|
|
26822
|
-
}
|
|
26823
|
-
if (annotateEventHandlerParams({
|
|
26824
|
-
root,
|
|
26825
|
-
j,
|
|
26826
|
-
convertedNames,
|
|
26827
|
-
componentTagMap
|
|
26828
|
-
})) ctx.markChanged();
|
|
26829
|
-
}
|
|
27158
|
+
if (/\.(ts|tsx)$/.test(file.path)) {}
|
|
26830
27159
|
return CONTINUE;
|
|
26831
27160
|
}
|
|
26832
27161
|
|
|
@@ -26921,13 +27250,16 @@ function rewriteJsxStep(ctx) {
|
|
|
26921
27250
|
if (renamed) attr.name.name = renamed;
|
|
26922
27251
|
}
|
|
26923
27252
|
});
|
|
26924
|
-
continue;
|
|
27253
|
+
if (!decl.promotedStyleProps?.length) continue;
|
|
26925
27254
|
}
|
|
26926
27255
|
root.find(j.JSXElement, { openingElement: { name: {
|
|
26927
27256
|
type: "JSXIdentifier",
|
|
26928
27257
|
name: decl.localName
|
|
26929
27258
|
} } }).forEach((p) => {
|
|
26930
27259
|
const opening = p.node.openingElement;
|
|
27260
|
+
if (decl.needsWrapperComponent) {
|
|
27261
|
+
if (!(opening.__promotedStyleKey && !opening.__promotedMergeIntoBase || opening.__promotedMergeArgs)) return;
|
|
27262
|
+
}
|
|
26931
27263
|
const closing = p.node.closingElement;
|
|
26932
27264
|
let finalTag = decl.base.kind === "intrinsic" ? decl.base.tagName : decl.base.ident;
|
|
26933
27265
|
const inlineVariantDimensions = decl.inlinedBaseComponent?.hasInlineJsxVariants ? decl.variantDimensions ?? [] : [];
|
|
@@ -27049,10 +27381,13 @@ function rewriteJsxStep(ctx) {
|
|
|
27049
27381
|
}
|
|
27050
27382
|
}
|
|
27051
27383
|
const baseStyleKey = matchedCombinedStyleKey ?? decl.styleKey;
|
|
27384
|
+
const mergeArgs = matchedCombinedStyleKey ? void 0 : opening.__promotedMergeArgs;
|
|
27385
|
+
const baseMember = j.memberExpression(j.identifier(ctx.stylesIdentifier ?? "styles"), j.identifier(baseStyleKey));
|
|
27386
|
+
const baseExpr = mergeArgs ? j.callExpression(baseMember, mergeArgs) : baseMember;
|
|
27052
27387
|
const styleArgs = [
|
|
27053
27388
|
...decl.extendsStyleKey ? [j.memberExpression(j.identifier(ctx.stylesIdentifier ?? "styles"), j.identifier(decl.extendsStyleKey))] : [],
|
|
27054
27389
|
...extraMixinArgs,
|
|
27055
|
-
|
|
27390
|
+
baseExpr,
|
|
27056
27391
|
...extraAfterBaseArgs
|
|
27057
27392
|
];
|
|
27058
27393
|
const variantKeys = decl.variantStyleKeys ?? {};
|
|
@@ -27095,7 +27430,10 @@ function rewriteJsxStep(ctx) {
|
|
|
27095
27430
|
if (styleFnProps.has(n)) {
|
|
27096
27431
|
const pairs = styleFnPairs.filter((p) => p.jsxProp === n);
|
|
27097
27432
|
const valueExpr = !attr.value ? j.literal(true) : attr.value.type === "StringLiteral" ? j.literal(attr.value.value) : attr.value.type === "Literal" ? j.literal(attr.value.value) : attr.value.type === "JSXExpressionContainer" ? attr.value.expression : null;
|
|
27098
|
-
if (valueExpr) for (const p of pairs)
|
|
27433
|
+
if (valueExpr) for (const p of pairs) {
|
|
27434
|
+
const callArg = wrapCallArgForPropsObject(j, valueExpr, p.propsObjectKey);
|
|
27435
|
+
styleArgs.push(j.callExpression(j.memberExpression(j.identifier(ctx.stylesIdentifier ?? "styles"), j.identifier(p.fnKey)), [callArg]));
|
|
27436
|
+
}
|
|
27099
27437
|
return;
|
|
27100
27438
|
}
|
|
27101
27439
|
if (combinedStylePropNames.has(n) && matchedCombinedStyleKey) return;
|