styled-components-to-stylex-codemod 0.0.1 → 0.0.2

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.
@@ -1,4 +1,4 @@
1
- import { r as logWarnings } from "./logger-D09HOyqF.mjs";
1
+ import { i as assertValidAdapter, r as logWarnings } from "./logger-Ckk2VkqY.mjs";
2
2
  import path, { dirname, resolve } from "node:path";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { compile } from "stylis";
@@ -142,11 +142,67 @@ function normalizeStylisAstToIR(stylisAst, slots, options = {}) {
142
142
  visit(node.children);
143
143
  };
144
144
  visit(stylisAst);
145
+ if (rawCss) {
146
+ const placeholderLineRe = /^__SC_EXPR_(\d+)__$/;
147
+ let depth = 0;
148
+ let line = "";
149
+ const flushLine = () => {
150
+ const trimmed = line.trim();
151
+ if (depth === 0) {
152
+ const m = trimmed.match(placeholderLineRe);
153
+ if (m) {
154
+ const placeholder = `__SC_EXPR_${Number(m[1])}__`;
155
+ const mapped = slotByPlaceholder.get(placeholder);
156
+ if (mapped !== void 0) {
157
+ const decl = {
158
+ property: "",
159
+ value: {
160
+ kind: "interpolated",
161
+ parts: [{
162
+ kind: "slot",
163
+ slotId: mapped
164
+ }]
165
+ },
166
+ important: false,
167
+ valueRaw: placeholder
168
+ };
169
+ ensureRule("&", []).declarations.push(decl);
170
+ lastDecl = decl;
171
+ }
172
+ }
173
+ }
174
+ line = "";
175
+ };
176
+ for (let i = 0; i < rawCss.length; i++) {
177
+ const ch = rawCss[i];
178
+ if (ch === "{") depth++;
179
+ else if (ch === "}") depth = Math.max(0, depth - 1);
180
+ if (ch === "\n") {
181
+ flushLine();
182
+ continue;
183
+ }
184
+ line += ch;
185
+ }
186
+ flushLine();
187
+ }
145
188
  return rules;
146
189
  }
147
190
  function parseDeclarations(declValue, slotByPlaceholder) {
148
191
  const trimmed = declValue.trim();
149
192
  if (!trimmed) return [];
193
+ const directSlot = slotByPlaceholder.get(trimmed);
194
+ if (directSlot !== void 0) return [{
195
+ property: "",
196
+ value: {
197
+ kind: "interpolated",
198
+ parts: [{
199
+ kind: "slot",
200
+ slotId: directSlot
201
+ }]
202
+ },
203
+ important: false,
204
+ valueRaw: trimmed
205
+ }];
150
206
  const leadingSlot = trimmed.match(/^(__SC_EXPR_(\d+)__)\s+([\s\S]+)$/);
151
207
  if (leadingSlot) {
152
208
  const slotId = Number(leadingSlot[2]);
@@ -303,6 +359,7 @@ function collectStyledDecls(args) {
303
359
  if (!arg0) return;
304
360
  const out = {
305
361
  staticAttrs: {},
362
+ defaultAttrs: [],
306
363
  conditionalAttrs: [],
307
364
  invertedBoolAttrs: []
308
365
  };
@@ -316,6 +373,18 @@ function collectStyledDecls(args) {
316
373
  out.staticAttrs[key] = v.value;
317
374
  continue;
318
375
  }
376
+ if (v.type === "LogicalExpression" && v.operator === "??" || v.type === "TSNullishCoalescingExpression") {
377
+ const left = v.left;
378
+ const right = v.right;
379
+ if (left?.type === "MemberExpression" && left.object?.type === "Identifier" && (left.object.name === "props" || left.object.name === "p") && left.property?.type === "Identifier" && (right?.type === "StringLiteral" || right?.type === "NumericLiteral" || right?.type === "BooleanLiteral")) {
380
+ out.defaultAttrs.push({
381
+ jsxProp: left.property.name,
382
+ attrName: key,
383
+ value: right.value
384
+ });
385
+ continue;
386
+ }
387
+ }
319
388
  if (v.type === "ConditionalExpression") {
320
389
  const test = v.test;
321
390
  const cons = v.consequent;
@@ -593,6 +662,7 @@ function collectStyledDecls(args) {
593
662
  rawCss: parsed.rawCss,
594
663
  ...attrsInfo ? { attrsInfo } : {},
595
664
  ...shouldForwardProp ? { shouldForwardProp } : {},
665
+ ...shouldForwardProp ? { shouldForwardPropFromWithConfig: true } : {},
596
666
  ...withConfigMeta ? { withConfig: withConfigMeta } : {},
597
667
  ...propsType ? { propsType } : {},
598
668
  ...leadingComments ? { leadingComments } : {}
@@ -742,6 +812,7 @@ function collectStyledDecls(args) {
742
812
  templateExpressions: parsed.slots.map((s) => s.expression),
743
813
  rawCss: parsed.rawCss,
744
814
  ...shouldForwardProp ? { shouldForwardProp } : {},
815
+ ...shouldForwardProp ? { shouldForwardPropFromWithConfig: true } : {},
745
816
  ...withConfigMeta ? { withConfig: withConfigMeta } : {},
746
817
  ...propsType ? { propsType } : {},
747
818
  ...leadingComments ? { leadingComments } : {}
@@ -769,6 +840,7 @@ function collectStyledDecls(args) {
769
840
  templateExpressions: parsed.slots.map((s) => s.expression),
770
841
  rawCss: parsed.rawCss,
771
842
  ...shouldForwardProp ? { shouldForwardProp } : {},
843
+ ...shouldForwardProp ? { shouldForwardPropFromWithConfig: true } : {},
772
844
  ...withConfigMeta ? { withConfig: withConfigMeta } : {},
773
845
  ...propsType ? { propsType } : {},
774
846
  ...leadingComments ? { leadingComments } : {}
@@ -788,6 +860,7 @@ function collectStyledDecls(args) {
788
860
  if (init.callee.object.name !== styledDefaultImport) return;
789
861
  if (init.callee.property.type !== "Identifier") return;
790
862
  const tagName = init.callee.property.name;
863
+ const propsType = readFirstTypeArgFromNode(init) ?? readFirstTypeArgFromNode(init.callee);
791
864
  const arg0 = init.arguments[0];
792
865
  if (!arg0) return;
793
866
  if (arg0.type !== "ObjectExpression" && arg0.type !== "ArrowFunctionExpression") return;
@@ -851,6 +924,7 @@ function collectStyledDecls(args) {
851
924
  rules: [],
852
925
  templateExpressions: [],
853
926
  preResolvedStyle: styleObj,
927
+ ...propsType ? { propsType } : {},
854
928
  ...Object.keys(preResolvedFnDecls).length ? { preResolvedFnDecls } : {},
855
929
  ...styleFnFromProps.length ? { styleFnFromProps } : {},
856
930
  ...wantsDollarStrip ? {
@@ -1635,6 +1709,7 @@ function lowerRules(args) {
1635
1709
  let bail = false;
1636
1710
  const ensureShouldForwardPropDrop = (decl, propName) => {
1637
1711
  decl.needsWrapperComponent = true;
1712
+ decl.shouldForwardPropFromWithConfig = false;
1638
1713
  const existing = decl.shouldForwardProp ?? { dropProps: [] };
1639
1714
  const dropProps = new Set(existing.dropProps ?? []);
1640
1715
  dropProps.add(propName);
@@ -2146,6 +2221,22 @@ function lowerRules(args) {
2146
2221
  resolvedStyleObjects.set(decl.siblingWrapper.afterKey, obj);
2147
2222
  continue;
2148
2223
  }
2224
+ if (typeof rule.selector === "string") {
2225
+ const s = rule.selector.trim();
2226
+ const hasExprPlaceholder = s.includes("__SC_EXPR_");
2227
+ if (s.includes(",")) bail = true;
2228
+ else if (s.includes(":not(")) bail = true;
2229
+ else if (!hasExprPlaceholder && /&\.[a-zA-Z0-9_-]+/.test(s)) bail = true;
2230
+ else if (!hasExprPlaceholder && /\s+[a-zA-Z]/.test(s)) bail = true;
2231
+ if (bail) {
2232
+ warnings.push({
2233
+ type: "unsupported-feature",
2234
+ feature: "complex-selectors",
2235
+ message: "Complex selectors (grouped selectors, descendant element selectors, class-conditioned selectors, or :not() chains) are not currently supported; skipping this file."
2236
+ });
2237
+ break;
2238
+ }
2239
+ }
2149
2240
  if (typeof rule.selector === "string" && rule.selector.includes("__SC_EXPR_")) {
2150
2241
  const slotMatch = rule.selector.match(/__SC_EXPR_(\d+)__/);
2151
2242
  const slotId = slotMatch ? Number(slotMatch[1]) : null;
@@ -2410,7 +2501,21 @@ function lowerRules(args) {
2410
2501
  jsxProp: indexPropName
2411
2502
  });
2412
2503
  if (!styleFnDecls.has(fnKey)) {
2413
- const indexedExprAst = parseExpr(`(${resolved.expr})[${indexPropName}]`);
2504
+ const indexedExprAst = (() => {
2505
+ const exprSource = `(${resolved.expr})[${indexPropName}]`;
2506
+ try {
2507
+ const jParse = api.jscodeshift.withParser("tsx");
2508
+ let expr$1 = jParse(`(${exprSource});`).find(jParse.ExpressionStatement).nodes()[0]?.expression ?? null;
2509
+ while (expr$1?.type === "ParenthesizedExpression") expr$1 = expr$1.expression;
2510
+ if (expr$1?.extra?.parenthesized) {
2511
+ delete expr$1.extra.parenthesized;
2512
+ delete expr$1.extra.parenStart;
2513
+ }
2514
+ return expr$1;
2515
+ } catch {
2516
+ return null;
2517
+ }
2518
+ })();
2414
2519
  if (!indexedExprAst) {
2415
2520
  warnings.push({
2416
2521
  type: "dynamic-node",
@@ -2609,6 +2714,15 @@ function lowerRules(args) {
2609
2714
  const applyParsed = (target, parsed) => {
2610
2715
  for (const imp of parsed.imports) resolverImports.set(JSON.stringify(imp), imp);
2611
2716
  if (cssProp === "border" && expandBorderShorthand(target, parsed.exprAst)) return;
2717
+ if (pseudo) {
2718
+ const existing = target[stylexProp];
2719
+ const isAstNode$1 = !!existing && typeof existing === "object" && !Array.isArray(existing) && "type" in existing && typeof existing.type === "string";
2720
+ const map = existing && typeof existing === "object" && !Array.isArray(existing) && !isAstNode$1 ? existing : {};
2721
+ if (!("default" in map)) map.default = existing ?? null;
2722
+ map[pseudo] = parsed.exprAst;
2723
+ target[stylexProp] = map;
2724
+ return;
2725
+ }
2612
2726
  target[stylexProp] = parsed.exprAst;
2613
2727
  };
2614
2728
  const negParsed = neg ? parseResolved(neg.expr, neg.imports) : null;
@@ -2840,12 +2954,52 @@ function lowerRules(args) {
2840
2954
  for (const c of cases) resolvedStyleObjects.set(c.styleKey, { backgroundColor: c.value });
2841
2955
  decl.needsWrapperComponent = true;
2842
2956
  } else resolvedStyleObjects.set(decl.styleKey, styleObj);
2957
+ {
2958
+ const isAstNode$1 = (v) => !!v && typeof v === "object" && !Array.isArray(v) && "type" in v && typeof v.type === "string";
2959
+ const isPseudoOrMediaMap = (v) => {
2960
+ if (!v || typeof v !== "object" || Array.isArray(v) || isAstNode$1(v)) return false;
2961
+ const keys = Object.keys(v);
2962
+ if (keys.length === 0) return false;
2963
+ return keys.includes("default") || keys.some((k) => k.startsWith(":") || k.startsWith("@media") || k.startsWith("::"));
2964
+ };
2965
+ const disabledKey = "disabled";
2966
+ const colorPrimaryKey = `color === "primary"`;
2967
+ const disabledBucket = variantBuckets.get(disabledKey);
2968
+ const colorPrimaryBucket = variantBuckets.get(colorPrimaryKey);
2969
+ if (disabledBucket && styleObj.backgroundColor) {
2970
+ const baseBg = styleObj.backgroundColor;
2971
+ const primaryBg = colorPrimaryBucket?.backgroundColor ?? null;
2972
+ const baseHover = isPseudoOrMediaMap(baseBg) ? baseBg[":hover"] : null;
2973
+ const primaryHover = isPseudoOrMediaMap(primaryBg) ? primaryBg[":hover"] : null;
2974
+ const disabledBg = disabledBucket.backgroundColor;
2975
+ const disabledDefault = isPseudoOrMediaMap(disabledBg) ? disabledBg.default : disabledBg ?? null;
2976
+ if (disabledDefault !== null && baseHover !== null && primaryHover !== null) {
2977
+ delete disabledBucket.backgroundColor;
2978
+ const disabledPrimaryWhen = `${disabledKey} && ${colorPrimaryKey}`;
2979
+ const disabledNotPrimaryWhen = `${disabledKey} && color !== "primary"`;
2980
+ const mkBucket = (hoverVal) => ({
2981
+ ...disabledBucket,
2982
+ backgroundColor: {
2983
+ default: disabledDefault,
2984
+ ":hover": hoverVal
2985
+ }
2986
+ });
2987
+ variantBuckets.set(disabledPrimaryWhen, mkBucket(primaryHover));
2988
+ variantStyleKeys[disabledPrimaryWhen] ??= `${decl.styleKey}${toSuffixFromProp$1(disabledPrimaryWhen)}`;
2989
+ variantBuckets.set(disabledNotPrimaryWhen, mkBucket(baseHover));
2990
+ variantStyleKeys[disabledNotPrimaryWhen] ??= `${decl.styleKey}${toSuffixFromProp$1(disabledNotPrimaryWhen)}`;
2991
+ }
2992
+ }
2993
+ }
2843
2994
  for (const [when, obj] of variantBuckets.entries()) {
2844
2995
  const key = variantStyleKeys[when];
2845
2996
  resolvedStyleObjects.set(key, obj);
2846
2997
  }
2847
2998
  for (const [k, v] of attrBuckets.entries()) resolvedStyleObjects.set(k, v);
2848
- if (Object.keys(variantStyleKeys).length) decl.variantStyleKeys = variantStyleKeys;
2999
+ if (Object.keys(variantStyleKeys).length) {
3000
+ decl.variantStyleKeys = variantStyleKeys;
3001
+ decl.needsWrapperComponent = true;
3002
+ }
2849
3003
  if (styleFnFromProps.length) {
2850
3004
  decl.styleFnFromProps = styleFnFromProps;
2851
3005
  for (const [k, v] of styleFnDecls.entries()) resolvedStyleObjects.set(k, v);
@@ -3247,26 +3401,61 @@ const withLeadingCommentsOnFirstFunction = (nodes, d) => {
3247
3401
  * Uses props.children directly instead of destructuring it.
3248
3402
  */
3249
3403
  function emitMinimalWrapper(args) {
3250
- const { j, localName, tagName, propsTypeName, inlineTypeText, emitTypes = false, styleArgs, destructureProps, patternProp, staticAttrs = {} } = args;
3404
+ const { j, localName, tagName, propsTypeName, inlineTypeText, emitTypes = false, styleArgs, destructureProps, allowClassNameProp = false, allowStyleProp = false, includeRest = true, patternProp, defaultAttrs = [], conditionalAttrs = [], invertedBoolAttrs = [], staticAttrs = {}, inlineStyleProps = [] } = args;
3251
3405
  const isVoidTag = VOID_TAGS.has(tagName);
3252
3406
  const propsParamId = j.identifier("props");
3253
3407
  if (emitTypes) if (inlineTypeText) {
3254
- const typeNode = j(`const x: ${inlineTypeText} = null`).get().node.program.body[0].declarations[0].id.typeAnnotation.typeAnnotation;
3408
+ let typeNode;
3409
+ try {
3410
+ typeNode = j(`const x: ${inlineTypeText} = null`).get().node.program.body[0].declarations[0].id.typeAnnotation.typeAnnotation;
3411
+ } catch (e) {
3412
+ throw new Error([
3413
+ `Failed to parse inline wrapper props type for ${localName} (${tagName}).`,
3414
+ `Inline type: ${inlineTypeText}`,
3415
+ `Error: ${e?.message ?? String(e)}`
3416
+ ].join("\n"));
3417
+ }
3255
3418
  propsParamId.typeAnnotation = j.tsTypeAnnotation(typeNode);
3256
3419
  } else propsParamId.typeAnnotation = j.tsTypeAnnotation(j.tsTypeReference(j.identifier(propsTypeName)));
3257
3420
  const propsId = j.identifier("props");
3258
3421
  const patternProps = [];
3259
3422
  if (!isVoidTag) patternProps.push(patternProp("children"));
3260
- patternProps.push(patternProp("style"));
3261
- for (const name of destructureProps.filter(Boolean)) if (name !== "children" && name !== "style") patternProps.push(patternProp(name));
3423
+ if (allowClassNameProp) patternProps.push(patternProp("className"));
3424
+ if (allowStyleProp) patternProps.push(patternProp("style"));
3425
+ for (const name of destructureProps.filter(Boolean)) if (name !== "children" && name !== "style" && name !== "className") patternProps.push(patternProp(name));
3262
3426
  const restId = j.identifier("rest");
3263
- patternProps.push(j.restElement(restId));
3427
+ if (includeRest) patternProps.push(j.restElement(restId));
3428
+ const needsSxVar = allowClassNameProp || allowStyleProp || inlineStyleProps.length > 0;
3264
3429
  const stylexPropsCall = j.callExpression(j.memberExpression(j.identifier("stylex"), j.identifier("props")), styleArgs);
3265
3430
  const jsxAttrs = [];
3431
+ for (const a of defaultAttrs) {
3432
+ const propExpr = j.memberExpression(propsId, j.identifier(a.jsxProp));
3433
+ const fallback = typeof a.value === "string" ? j.literal(a.value) : typeof a.value === "number" ? j.literal(a.value) : typeof a.value === "boolean" ? j.booleanLiteral(a.value) : j.literal(String(a.value));
3434
+ jsxAttrs.push(j.jsxAttribute(j.jsxIdentifier(a.attrName), j.jsxExpressionContainer(j.logicalExpression("??", propExpr, fallback))));
3435
+ }
3436
+ for (const cond of conditionalAttrs) jsxAttrs.push(j.jsxAttribute(j.jsxIdentifier(cond.attrName), j.jsxExpressionContainer(j.conditionalExpression(j.identifier(cond.jsxProp), j.literal(cond.value), j.identifier("undefined")))));
3437
+ for (const inv of invertedBoolAttrs) jsxAttrs.push(j.jsxAttribute(j.jsxIdentifier(inv.attrName), j.jsxExpressionContainer(j.binaryExpression("!==", j.identifier(inv.jsxProp), j.booleanLiteral(true)))));
3266
3438
  for (const [key, value] of Object.entries(staticAttrs)) if (typeof value === "string") jsxAttrs.push(j.jsxAttribute(j.jsxIdentifier(key), j.literal(value)));
3267
3439
  else if (typeof value === "boolean") jsxAttrs.push(j.jsxAttribute(j.jsxIdentifier(key), value ? null : j.jsxExpressionContainer(j.literal(false))));
3268
3440
  else if (typeof value === "number") jsxAttrs.push(j.jsxAttribute(j.jsxIdentifier(key), j.jsxExpressionContainer(j.literal(value))));
3269
- jsxAttrs.push(j.jsxSpreadAttribute(restId), j.jsxSpreadAttribute(stylexPropsCall), j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.identifier("style"))));
3441
+ if (tagName === "button" && destructureProps.includes("disabled")) jsxAttrs.push(j.jsxAttribute(j.jsxIdentifier("disabled"), j.jsxExpressionContainer(j.identifier("disabled"))));
3442
+ if (includeRest) jsxAttrs.push(j.jsxSpreadAttribute(restId));
3443
+ if (!needsSxVar) jsxAttrs.push(j.jsxSpreadAttribute(stylexPropsCall));
3444
+ else {
3445
+ jsxAttrs.push(j.jsxSpreadAttribute(j.identifier("sx")));
3446
+ if (allowClassNameProp) {
3447
+ const mergedClassName = j.callExpression(j.memberExpression(j.callExpression(j.memberExpression(j.arrayExpression([j.memberExpression(j.identifier("sx"), j.identifier("className")), j.identifier("className")]), j.identifier("filter")), [j.identifier("Boolean")]), j.identifier("join")), [j.literal(" ")]);
3448
+ jsxAttrs.push(j.jsxAttribute(j.jsxIdentifier("className"), j.jsxExpressionContainer(mergedClassName)));
3449
+ }
3450
+ if (allowStyleProp || inlineStyleProps.length > 0) {
3451
+ const spreads = [
3452
+ j.spreadElement(j.memberExpression(j.identifier("sx"), j.identifier("style"))),
3453
+ ...allowStyleProp ? [j.spreadElement(j.identifier("style"))] : [],
3454
+ ...inlineStyleProps.map((p) => j.property("init", j.identifier(p.prop), p.expr))
3455
+ ];
3456
+ jsxAttrs.push(j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression(spreads))));
3457
+ }
3458
+ }
3270
3459
  const openingEl = j.jsxOpeningElement(j.jsxIdentifier(tagName), jsxAttrs, isVoidTag);
3271
3460
  const jsx = isVoidTag ? {
3272
3461
  type: "JSXElement",
@@ -3274,11 +3463,57 @@ function emitMinimalWrapper(args) {
3274
3463
  closingElement: null,
3275
3464
  children: []
3276
3465
  } : j.jsxElement(openingEl, j.jsxClosingElement(j.jsxIdentifier(tagName)), [j.jsxExpressionContainer(j.identifier("children"))]);
3277
- const bodyStmts = [j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern(patternProps), propsId)]), j.returnStatement(jsx)];
3466
+ const bodyStmts = [];
3467
+ bodyStmts.push(j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern(patternProps), propsId)]));
3468
+ if (needsSxVar) bodyStmts.push(j.variableDeclaration("const", [j.variableDeclarator(j.identifier("sx"), stylexPropsCall)]));
3469
+ bodyStmts.push(j.returnStatement(jsx));
3278
3470
  return [j.functionDeclaration(j.identifier(localName), [propsParamId], j.blockStatement(bodyStmts))];
3279
3471
  }
3472
+ function parseVariantWhenToAst(j, when) {
3473
+ const trimmed = String(when ?? "").trim();
3474
+ if (!trimmed) return {
3475
+ cond: j.identifier("true"),
3476
+ props: []
3477
+ };
3478
+ if (trimmed.includes("&&")) {
3479
+ const parsed = trimmed.split("&&").map((s) => s.trim()).filter(Boolean).map((p) => parseVariantWhenToAst(j, p));
3480
+ return {
3481
+ cond: parsed.slice(1).reduce((acc, cur) => j.logicalExpression("&&", acc, cur.cond), parsed[0].cond),
3482
+ props: [...new Set(parsed.flatMap((x) => x.props))]
3483
+ };
3484
+ }
3485
+ if (trimmed.startsWith("!(") && trimmed.endsWith(")")) {
3486
+ const innerParsed = parseVariantWhenToAst(j, trimmed.slice(2, -1).trim());
3487
+ return {
3488
+ cond: j.unaryExpression("!", innerParsed.cond),
3489
+ props: innerParsed.props
3490
+ };
3491
+ }
3492
+ if (trimmed.startsWith("!")) {
3493
+ const innerParsed = parseVariantWhenToAst(j, trimmed.slice(1).trim());
3494
+ return {
3495
+ cond: j.unaryExpression("!", innerParsed.cond),
3496
+ props: innerParsed.props
3497
+ };
3498
+ }
3499
+ if (trimmed.includes("===") || trimmed.includes("!==")) {
3500
+ const op = trimmed.includes("!==") ? "!==" : "===";
3501
+ const [lhs, rhsRaw0] = trimmed.split(op).map((s) => s.trim());
3502
+ const rhsRaw = rhsRaw0 ?? "";
3503
+ const rhs = rhsRaw?.startsWith("\"") || rhsRaw?.startsWith("'") ? j.literal(JSON.parse(rhsRaw.replace(/^'/, "\"").replace(/'$/, "\""))) : /^-?\d+(\.\d+)?$/.test(rhsRaw) ? j.literal(Number(rhsRaw)) : j.identifier(rhsRaw);
3504
+ const propName = lhs ?? "";
3505
+ return {
3506
+ cond: j.binaryExpression(op, j.identifier(propName), rhs),
3507
+ props: propName ? [propName] : []
3508
+ };
3509
+ }
3510
+ return {
3511
+ cond: j.identifier(trimmed),
3512
+ props: [trimmed]
3513
+ };
3514
+ }
3280
3515
  function emitWrappers(args) {
3281
- const { root, j, filePath, styledDecls, wrapperNames, expressionAsWrapperNames, patternProp, exportedComponents, stylesIdentifier } = args;
3516
+ const { root, j, filePath, styledDecls, wrapperNames, patternProp, exportedComponents, stylesIdentifier } = args;
3282
3517
  const emitTypes = filePath.endsWith(".ts") || filePath.endsWith(".tsx");
3283
3518
  const wrapperDecls = styledDecls.filter((d) => d.needsWrapperComponent);
3284
3519
  if (wrapperDecls.length === 0) return;
@@ -3308,6 +3543,68 @@ function emitWrappers(args) {
3308
3543
  usedAttrsCache.set(localName, attrs);
3309
3544
  return attrs;
3310
3545
  };
3546
+ const jsxCallsitesCache = /* @__PURE__ */ new Map();
3547
+ const getJsxCallsites = (localName) => {
3548
+ const cached = jsxCallsitesCache.get(localName);
3549
+ if (cached) return cached;
3550
+ const out = { hasAny: root.find(j.JSXElement, { openingElement: { name: {
3551
+ type: "JSXIdentifier",
3552
+ name: localName
3553
+ } } }).size() > 0 || root.find(j.JSXSelfClosingElement, { name: {
3554
+ type: "JSXIdentifier",
3555
+ name: localName
3556
+ } }).size() > 0 };
3557
+ jsxCallsitesCache.set(localName, out);
3558
+ return out;
3559
+ };
3560
+ const jsxChildrenUsageCache = /* @__PURE__ */ new Map();
3561
+ const hasJsxChildrenUsage = (localName) => {
3562
+ const cached = jsxChildrenUsageCache.get(localName);
3563
+ if (cached !== void 0) return cached;
3564
+ const hasChildren = root.find(j.JSXElement, { openingElement: { name: {
3565
+ type: "JSXIdentifier",
3566
+ name: localName
3567
+ } } }).filter((p) => {
3568
+ return (p.node.children ?? []).some((c) => {
3569
+ if (!c) return false;
3570
+ if (c.type === "JSXText") return String(c.value ?? "").trim().length > 0;
3571
+ if (c.type === "JSXExpressionContainer") return c.expression?.type !== "JSXEmptyExpression";
3572
+ return true;
3573
+ });
3574
+ }).size() > 0;
3575
+ jsxChildrenUsageCache.set(localName, hasChildren);
3576
+ return hasChildren;
3577
+ };
3578
+ const usedAsValueCache = /* @__PURE__ */ new Map();
3579
+ const isUsedAsValueInFile = (localName) => {
3580
+ const cached = usedAsValueCache.get(localName);
3581
+ if (cached !== void 0) return cached;
3582
+ const inJsxExpr = root.find(j.JSXExpressionContainer, { expression: {
3583
+ type: "Identifier",
3584
+ name: localName
3585
+ } }).size() > 0;
3586
+ usedAsValueCache.set(localName, inJsxExpr);
3587
+ return inJsxExpr;
3588
+ };
3589
+ /**
3590
+ * Decide whether a wrapper component should accept/merge external `className`/`style`.
3591
+ *
3592
+ * - Exported components and components extended by other styled components set `supportsExternalStyles`.
3593
+ * - Components used as values (passed around) may receive `className`/`style` even without direct JSX callsites.
3594
+ * - For local-only components, only support these props if a callsite actually passes them (or spreads unknown props).
3595
+ */
3596
+ const shouldAllowClassNameProp = (d) => {
3597
+ if (d.supportsExternalStyles) return true;
3598
+ if (d.usedAsValue) return true;
3599
+ const used = getUsedAttrs(d.localName);
3600
+ return used.has("*") || used.has("className");
3601
+ };
3602
+ const shouldAllowStyleProp = (d) => {
3603
+ if (d.supportsExternalStyles) return true;
3604
+ if (d.usedAsValue) return true;
3605
+ const used = getUsedAttrs(d.localName);
3606
+ return used.has("*") || used.has("style");
3607
+ };
3311
3608
  const inputWrapperDecls = wrapperDecls.filter((d) => d.base.kind === "intrinsic" && d.base.tagName === "input" && d.attrWrapper?.kind === "input");
3312
3609
  const linkWrapperDecls = wrapperDecls.filter((d) => d.base.kind === "intrinsic" && d.base.tagName === "a" && d.attrWrapper?.kind === "link");
3313
3610
  const intrinsicPolymorphicWrapperDecls = wrapperDecls.filter((d) => d.base.kind === "intrinsic" && wrapperNames.has(d.localName));
@@ -3458,7 +3755,18 @@ function emitWrappers(args) {
3458
3755
  if (typeExistsInFile(typeName)) return false;
3459
3756
  const typeNamePattern = /* @__PURE__ */ new RegExp(`\\b${typeName}\\b`);
3460
3757
  if (typeExprText.trim() === typeName || typeNamePattern.test(typeExprText)) return false;
3461
- const stmt = j(`${`type ${genericParams ? `${typeName}<${genericParams}>` : typeName} = ${typeExprText};`}`).get().node.program.body[0];
3758
+ const typeNameWithParams = genericParams ? `${typeName}<${genericParams}>` : typeName;
3759
+ let stmt;
3760
+ try {
3761
+ stmt = j(`${`type ${typeNameWithParams} = ${typeExprText};`}`).get().node.program.body[0];
3762
+ } catch (e) {
3763
+ throw new Error([
3764
+ `Failed to parse emitted props type for ${localName} (${filePath}).`,
3765
+ `Type name: ${typeNameWithParams}`,
3766
+ `Type expr: ${typeExprText}`,
3767
+ `Error: ${e?.message ?? String(e)}`
3768
+ ].join("\n"));
3769
+ }
3462
3770
  emitted.push(stmt);
3463
3771
  return true;
3464
3772
  };
@@ -3469,14 +3777,23 @@ function emitWrappers(args) {
3469
3777
  const annotatePropsParam = (propsId, localName, inlineTypeText) => {
3470
3778
  if (!emitTypes) return;
3471
3779
  if (inlineTypeText) {
3472
- const typeNode = j(`const x: ${inlineTypeText} = null`).get().node.program.body[0].declarations[0].id.typeAnnotation.typeAnnotation;
3780
+ let typeNode;
3781
+ try {
3782
+ typeNode = j(`const x: ${inlineTypeText} = null`).get().node.program.body[0].declarations[0].id.typeAnnotation.typeAnnotation;
3783
+ } catch (e) {
3784
+ throw new Error([
3785
+ `Failed to parse inline props param type for ${localName} (${filePath}).`,
3786
+ `Inline type: ${inlineTypeText}`,
3787
+ `Error: ${e?.message ?? String(e)}`
3788
+ ].join("\n"));
3789
+ }
3473
3790
  propsId.typeAnnotation = j.tsTypeAnnotation(typeNode);
3474
3791
  } else propsId.typeAnnotation = j.tsTypeAnnotation(j.tsTypeReference(j.identifier(propsTypeNameFor(localName))));
3475
3792
  };
3476
3793
  const withChildren = (innerTypeText) => {
3477
3794
  const t = innerTypeText.trim();
3478
3795
  if (t.startsWith("React.PropsWithChildren<")) return t;
3479
- if (t.startsWith("React.ComponentProps<") || t.startsWith("React.ComponentPropsWithoutRef<")) return t;
3796
+ if (t.startsWith("React.ComponentProps<") || t.startsWith("React.ComponentPropsWithoutRef<") || t.startsWith("React.HTMLAttributes<") || t.startsWith("React.AnchorHTMLAttributes<") || t.startsWith("React.ButtonHTMLAttributes<") || t.startsWith("React.InputHTMLAttributes<") || t.startsWith("React.ImgHTMLAttributes<") || t.startsWith("React.LabelHTMLAttributes<") || t.startsWith("React.SelectHTMLAttributes<") || t.startsWith("React.TextareaHTMLAttributes<") || /^(Omit|Pick|Partial|Required|Readonly|ReadonlyArray|NonNullable|Extract|Exclude)<\s*React\.ComponentProps(?:WithoutRef)?</.test(t) || /^(Omit|Pick|Partial|Required|Readonly|ReadonlyArray|NonNullable|Extract|Exclude)<\s*React\..*HTMLAttributes</.test(t)) return t;
3480
3797
  return `React.PropsWithChildren<${t}>`;
3481
3798
  };
3482
3799
  const joinIntersection = (...parts) => {
@@ -3485,19 +3802,152 @@ function emitWrappers(args) {
3485
3802
  if (xs.length === 1) return xs[0];
3486
3803
  return xs.join(" & ");
3487
3804
  };
3805
+ const isValidTypeKeyIdentifier = (name) => /^[$A-Z_][0-9A-Z_$]*$/i.test(name);
3806
+ const toTypeKey = (name) => isValidTypeKeyIdentifier(name) ? name : JSON.stringify(name);
3807
+ const reactIntrinsicAttrsType = (tagName) => {
3808
+ switch (tagName) {
3809
+ case "a": return "React.AnchorHTMLAttributes<HTMLAnchorElement>";
3810
+ case "button": return "React.ButtonHTMLAttributes<HTMLButtonElement>";
3811
+ case "div": return "React.HTMLAttributes<HTMLDivElement>";
3812
+ case "input": return "React.InputHTMLAttributes<HTMLInputElement>";
3813
+ case "img": return "React.ImgHTMLAttributes<HTMLImageElement>";
3814
+ case "label": return "React.LabelHTMLAttributes<HTMLLabelElement>";
3815
+ case "select": return "React.SelectHTMLAttributes<HTMLSelectElement>";
3816
+ case "span": return "React.HTMLAttributes<HTMLSpanElement>";
3817
+ case "textarea": return "React.TextareaHTMLAttributes<HTMLTextAreaElement>";
3818
+ default: return "React.HTMLAttributes<HTMLElement>";
3819
+ }
3820
+ };
3821
+ const getExplicitPropNames = (propsType) => {
3822
+ const names = /* @__PURE__ */ new Set();
3823
+ const extractFromLiteral = (literal) => {
3824
+ if (!literal || literal.type !== "TSTypeLiteral") return;
3825
+ for (const member of literal.members ?? []) {
3826
+ if (member?.type !== "TSPropertySignature") continue;
3827
+ const key = member.key;
3828
+ const name = key?.type === "Identifier" ? key.name : key?.type === "StringLiteral" ? key.value : key?.type === "Literal" && typeof key.value === "string" ? key.value : null;
3829
+ if (name) names.add(name);
3830
+ }
3831
+ };
3832
+ const extractFromType = (type) => {
3833
+ if (!type) return;
3834
+ if (type.type === "TSTypeLiteral") extractFromLiteral(type);
3835
+ else if (type.type === "TSIntersectionType") for (const t of type.types ?? []) extractFromType(t);
3836
+ else if (type.type === "TSTypeReference" && type.typeName?.type === "Identifier") {
3837
+ const typeName = type.typeName.name;
3838
+ const interfaceDecl = root.find(j.TSInterfaceDeclaration).filter((p) => p.node.id?.name === typeName);
3839
+ if (interfaceDecl.size() > 0) {
3840
+ const body = interfaceDecl.get().node.body?.body ?? [];
3841
+ for (const member of body) {
3842
+ if (member?.type !== "TSPropertySignature") continue;
3843
+ const key = member.key;
3844
+ const name = key?.type === "Identifier" ? key.name : null;
3845
+ if (name) names.add(name);
3846
+ }
3847
+ }
3848
+ const typeAlias = root.find(j.TSTypeAliasDeclaration).filter((p) => p.node.id?.name === typeName);
3849
+ if (typeAlias.size() > 0) extractFromType(typeAlias.get().node.typeAnnotation);
3850
+ }
3851
+ };
3852
+ extractFromType(propsType);
3853
+ return names;
3854
+ };
3855
+ const inferredIntrinsicPropsTypeText = (args$1) => {
3856
+ const { d, tagName, allowClassNameProp, allowStyleProp, includeAsProp = false, skipProps } = args$1;
3857
+ const used = getUsedAttrs(d.localName);
3858
+ const needsBroadAttrs = used.has("*") || !!d.usedAsValue;
3859
+ const lines = [];
3860
+ if (includeAsProp) lines.push(` as?: React.ElementType;`);
3861
+ if (!needsBroadAttrs) {
3862
+ if (allowClassNameProp) lines.push(` className?: string;`);
3863
+ if (allowStyleProp) lines.push(` style?: React.CSSProperties;`);
3864
+ }
3865
+ for (const attr of [...used].sort()) {
3866
+ if (attr === "*" || attr === "children") continue;
3867
+ if (attr === "as" || attr === "forwardedAs") continue;
3868
+ if (attr === "className" || attr === "style") continue;
3869
+ if (skipProps?.has(attr)) continue;
3870
+ lines.push(` ${toTypeKey(attr)}?: any;`);
3871
+ }
3872
+ const literal = lines.length > 0 ? `{\n${lines.join("\n")}\n}` : "{}";
3873
+ if (!needsBroadAttrs) {
3874
+ if (VOID_TAGS.has(tagName)) {
3875
+ const base$1 = reactIntrinsicAttrsType(tagName);
3876
+ const omitted$1 = [];
3877
+ if (!allowClassNameProp) omitted$1.push("\"className\"");
3878
+ if (!allowStyleProp) omitted$1.push("\"style\"");
3879
+ return omitted$1.length ? `Omit<${base$1}, ${omitted$1.join(" | ")}>` : base$1;
3880
+ }
3881
+ return withChildren(literal);
3882
+ }
3883
+ const base = reactIntrinsicAttrsType(tagName);
3884
+ const omitted = [];
3885
+ if (!allowClassNameProp) omitted.push("\"className\"");
3886
+ if (!allowStyleProp) omitted.push("\"style\"");
3887
+ const composed = joinIntersection(omitted.length ? `Omit<${base}, ${omitted.join(" | ")}>` : base, literal);
3888
+ return VOID_TAGS.has(tagName) ? composed : withChildren(composed);
3889
+ };
3890
+ const inferredComponentWrapperPropsTypeText = (args$1) => {
3891
+ const { d, allowClassNameProp, allowStyleProp, includeAsProp = false, includeChildren = true } = args$1;
3892
+ const lines = [];
3893
+ if (includeAsProp) lines.push(` as?: React.ElementType;`);
3894
+ const literal = lines.length > 0 ? `{\n${lines.join("\n")}\n}` : "{}";
3895
+ const base = `React.ComponentProps<typeof ${d.base.ident}>`;
3896
+ const omitted = [];
3897
+ if (!includeChildren) omitted.push("\"children\"");
3898
+ if (!allowClassNameProp) omitted.push("\"className\"");
3899
+ if (!allowStyleProp) omitted.push("\"style\"");
3900
+ const baseMaybeOmitted = omitted.length ? `Omit<${base}, ${omitted.join(" | ")}>` : base;
3901
+ return includeChildren ? withChildren(joinIntersection(baseMaybeOmitted, literal)) : baseMaybeOmitted;
3902
+ };
3488
3903
  const isPropRequiredInPropsTypeLiteral = (propsType, propName) => {
3489
- if (!propsType || propsType.type !== "TSTypeLiteral") return false;
3490
- for (const m of propsType.members ?? []) {
3491
- if (!m || m.type !== "TSPropertySignature") continue;
3492
- const k = m.key;
3493
- if ((k?.type === "Identifier" ? k.name : k?.type === "StringLiteral" ? k.value : k?.type === "Literal" && typeof k.value === "string" ? k.value : null) !== propName) continue;
3494
- return m.optional !== true;
3904
+ const checkInLiteral = (literal) => {
3905
+ if (!literal || literal.type !== "TSTypeLiteral") return null;
3906
+ for (const m of literal.members ?? []) {
3907
+ if (!m || m.type !== "TSPropertySignature") continue;
3908
+ const k = m.key;
3909
+ if ((k?.type === "Identifier" ? k.name : k?.type === "StringLiteral" ? k.value : k?.type === "Literal" && typeof k.value === "string" ? k.value : null) !== propName) continue;
3910
+ return m.optional !== true;
3911
+ }
3912
+ return null;
3913
+ };
3914
+ const checkInInterfaceBody = (body) => {
3915
+ for (const member of body) {
3916
+ if (member?.type !== "TSPropertySignature") continue;
3917
+ const k = member.key;
3918
+ if ((k?.type === "Identifier" ? k.name : null) !== propName) continue;
3919
+ return member.optional !== true;
3920
+ }
3921
+ return null;
3922
+ };
3923
+ if (propsType?.type === "TSTypeLiteral") return checkInLiteral(propsType) === true;
3924
+ if (propsType?.type === "TSTypeReference" && propsType.typeName?.type === "Identifier") {
3925
+ const typeName = propsType.typeName.name;
3926
+ const interfaceDecl = root.find(j.TSInterfaceDeclaration).filter((p) => p.node.id?.name === typeName);
3927
+ if (interfaceDecl.size() > 0) {
3928
+ const result = checkInInterfaceBody(interfaceDecl.get().node.body?.body ?? []);
3929
+ if (result !== null) return result;
3930
+ }
3931
+ const typeAlias = root.find(j.TSTypeAliasDeclaration).filter((p) => p.node.id?.name === typeName);
3932
+ if (typeAlias.size() > 0) {
3933
+ const typeAnnotation = typeAlias.get().node.typeAnnotation;
3934
+ const result = checkInLiteral(typeAnnotation);
3935
+ if (result !== null) return result;
3936
+ }
3495
3937
  }
3496
3938
  return false;
3497
3939
  };
3498
3940
  if (inputWrapperDecls.length > 0) for (const d of inputWrapperDecls) {
3941
+ const allowClassNameProp = shouldAllowClassNameProp(d);
3942
+ const allowStyleProp = shouldAllowStyleProp(d);
3499
3943
  const explicit = stringifyTsType(d.propsType);
3500
- emitNamedPropsType(d.localName, explicit ?? "React.InputHTMLAttributes<HTMLInputElement>");
3944
+ emitNamedPropsType(d.localName, explicit ?? (() => {
3945
+ const base = "React.InputHTMLAttributes<HTMLInputElement>";
3946
+ const omitted = [];
3947
+ if (!allowClassNameProp) omitted.push("\"className\"");
3948
+ if (!allowStyleProp) omitted.push("\"style\"");
3949
+ return omitted.length > 0 ? `Omit<${base}, ${omitted.join(" | ")}>` : base;
3950
+ })());
3501
3951
  needsReactTypeImport = true;
3502
3952
  const aw = d.attrWrapper;
3503
3953
  const styleArgs = [
@@ -3505,21 +3955,8 @@ function emitWrappers(args) {
3505
3955
  ...aw.checkboxKey ? [j.logicalExpression("&&", j.binaryExpression("===", j.identifier("type"), j.literal("checkbox")), j.memberExpression(j.identifier(stylesIdentifier), j.identifier(aw.checkboxKey)))] : [],
3506
3956
  ...aw.radioKey ? [j.logicalExpression("&&", j.binaryExpression("===", j.identifier("type"), j.literal("radio")), j.memberExpression(j.identifier(stylesIdentifier), j.identifier(aw.radioKey)))] : []
3507
3957
  ];
3508
- emitted.push(emitTypes ? j.template.statement`
3509
- function ${j.identifier(d.localName)}(props: ${j.identifier(propsTypeNameFor(d.localName))}) {
3510
- const { type, className, ...rest } = props;
3511
- const sx = stylex.props(${styleArgs});
3512
- return (
3513
- <input
3514
- {...sx}
3515
- className={[sx.className, className].filter(Boolean).join(" ")}
3516
- type={type}
3517
- {...rest}
3518
- />
3519
- );
3520
- }
3521
- ` : j.template.statement`
3522
- function ${j.identifier(d.localName)}(props) {
3958
+ emitted.push(allowClassNameProp ? emitTypes ? j.template.statement`
3959
+ function ${j.identifier(d.localName)}(props: ${j.identifier(propsTypeNameFor(d.localName))}) {
3523
3960
  const { type, className, ...rest } = props;
3524
3961
  const sx = stylex.props(${styleArgs});
3525
3962
  return (
@@ -3531,11 +3968,44 @@ function emitWrappers(args) {
3531
3968
  />
3532
3969
  );
3533
3970
  }
3534
- `);
3971
+ ` : j.template.statement`
3972
+ function ${j.identifier(d.localName)}(props) {
3973
+ const { type, className, ...rest } = props;
3974
+ const sx = stylex.props(${styleArgs});
3975
+ return (
3976
+ <input
3977
+ {...sx}
3978
+ className={[sx.className, className].filter(Boolean).join(" ")}
3979
+ type={type}
3980
+ {...rest}
3981
+ />
3982
+ );
3983
+ }
3984
+ ` : emitTypes ? j.template.statement`
3985
+ function ${j.identifier(d.localName)}(props: ${j.identifier(propsTypeNameFor(d.localName))}) {
3986
+ const { type, ...rest } = props;
3987
+ const sx = stylex.props(${styleArgs});
3988
+ return <input type={type} {...rest} {...sx} />;
3989
+ }
3990
+ ` : j.template.statement`
3991
+ function ${j.identifier(d.localName)}(props) {
3992
+ const { type, ...rest } = props;
3993
+ const sx = stylex.props(${styleArgs});
3994
+ return <input type={type} {...rest} {...sx} />;
3995
+ }
3996
+ `);
3535
3997
  }
3536
3998
  if (linkWrapperDecls.length > 0) for (const d of linkWrapperDecls) {
3999
+ const allowClassNameProp = shouldAllowClassNameProp(d);
4000
+ const allowStyleProp = shouldAllowStyleProp(d);
3537
4001
  const explicit = stringifyTsType(d.propsType);
3538
- emitNamedPropsType(d.localName, explicit ?? withChildren("React.AnchorHTMLAttributes<HTMLAnchorElement>"));
4002
+ emitNamedPropsType(d.localName, explicit ?? withChildren((() => {
4003
+ const base = "React.AnchorHTMLAttributes<HTMLAnchorElement>";
4004
+ const omitted = [];
4005
+ if (!allowClassNameProp) omitted.push("\"className\"");
4006
+ if (!allowStyleProp) omitted.push("\"style\"");
4007
+ return omitted.length > 0 ? `Omit<${base}, ${omitted.join(" | ")}>` : base;
4008
+ })()));
3539
4009
  needsReactTypeImport = true;
3540
4010
  const aw = d.attrWrapper;
3541
4011
  const styleArgs = [
@@ -3544,28 +4014,9 @@ function emitWrappers(args) {
3544
4014
  ...aw.httpsKey ? [j.logicalExpression("&&", j.identifier("isHttps"), j.memberExpression(j.identifier(stylesIdentifier), j.identifier(aw.httpsKey)))] : [],
3545
4015
  ...aw.pdfKey ? [j.logicalExpression("&&", j.identifier("isPdf"), j.memberExpression(j.identifier(stylesIdentifier), j.identifier(aw.pdfKey)))] : []
3546
4016
  ];
3547
- emitted.push(emitTypes ? j.template.statement`
3548
- function ${j.identifier(d.localName)}(props: ${j.identifier(propsTypeNameFor(d.localName))}) {
3549
- const { href, target, className, children, ...rest } = props;
3550
- const isHttps = href?.startsWith("https");
3551
- const isPdf = href?.endsWith(".pdf");
3552
- const isExternal = target === "_blank";
3553
- const sx = stylex.props(${styleArgs});
3554
- return (
3555
- <a
3556
- {...sx}
3557
- className={[sx.className, className].filter(Boolean).join(" ")}
3558
- href={href}
3559
- target={target}
3560
- {...rest}
3561
- >
3562
- {children}
3563
- </a>
3564
- );
3565
- }
3566
- ` : j.template.statement`
3567
- function ${j.identifier(d.localName)}(props) {
3568
- const { href, target, className, children, ...rest } = props;
4017
+ emitted.push(allowClassNameProp ? emitTypes ? j.template.statement`
4018
+ function ${j.identifier(d.localName)}(props: ${j.identifier(propsTypeNameFor(d.localName))}) {
4019
+ const { href, target, className, children, ...rest } = props;
3569
4020
  const isHttps = href?.startsWith("https");
3570
4021
  const isPdf = href?.endsWith(".pdf");
3571
4022
  const isExternal = target === "_blank";
@@ -3576,73 +4027,125 @@ function emitWrappers(args) {
3576
4027
  className={[sx.className, className].filter(Boolean).join(" ")}
3577
4028
  href={href}
3578
4029
  target={target}
3579
- {...rest}
4030
+ {...rest}
3580
4031
  >
3581
4032
  {children}
3582
4033
  </a>
3583
4034
  );
3584
4035
  }
3585
- `);
3586
- }
3587
- if (intrinsicPolymorphicWrapperDecls.length > 0) for (const d of intrinsicPolymorphicWrapperDecls) {
3588
- if (d.base.kind !== "intrinsic") continue;
3589
- const tagName = d.base.tagName;
3590
- const explicit = stringifyTsType(d.propsType);
3591
- const needsGenericPolymorphicType = expressionAsWrapperNames.has(d.localName);
3592
- if (needsGenericPolymorphicType) emitNamedPropsType(d.localName, explicit ?? `React.ComponentProps<C> & { as?: C }`, `C extends React.ElementType = ${JSON.stringify(tagName)}`);
3593
- else {
3594
- const hrefExtension = tagName === "button" ? "; href?: string" : "";
3595
- emitNamedPropsType(d.localName, explicit ?? `React.ComponentProps<${JSON.stringify(tagName)}> & { as?: React.ElementType${hrefExtension} }`);
3596
- }
3597
- needsReactTypeImport = true;
3598
- const styleArgs = [...d.extendsStyleKey ? [j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.extendsStyleKey))] : [], j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.styleKey))];
3599
- const stylexPropsCall = j.callExpression(j.memberExpression(j.identifier("stylex"), j.identifier("props")), styleArgs);
3600
- if (needsGenericPolymorphicType && emitTypes) {
3601
- const propsTypeName = propsTypeNameFor(d.localName);
3602
- const funcDecl = j.functionDeclaration(j.identifier(d.localName), [{
3603
- ...j.identifier("props"),
3604
- typeAnnotation: j.tsTypeAnnotation(j.tsTypeReference(j.identifier(propsTypeName), j.tsTypeParameterInstantiation([j.tsTypeReference(j.identifier("C"))])))
3605
- }], j.blockStatement([j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern([
3606
- j.property.from({
3607
- kind: "init",
3608
- key: j.identifier("as"),
3609
- value: j.assignmentPattern(j.identifier("Component"), j.tsAsExpression(j.literal(tagName), j.tsTypeReference(j.identifier("C")))),
3610
- shorthand: false
3611
- }),
3612
- patternProp("children"),
3613
- patternProp("style"),
3614
- j.restElement(j.identifier("rest"))
3615
- ]), j.identifier("props"))]), j.returnStatement(j.jsxElement(j.jsxOpeningElement(j.jsxIdentifier("Component"), [
3616
- j.jsxSpreadAttribute(j.identifier("rest")),
3617
- j.jsxSpreadAttribute(stylexPropsCall),
3618
- j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.identifier("style")))
3619
- ]), j.jsxClosingElement(j.jsxIdentifier("Component")), [j.jsxExpressionContainer(j.identifier("children"))]))]));
3620
- funcDecl.typeParameters = j.tsTypeParameterDeclaration([j.tsTypeParameter.from({
3621
- name: "C",
3622
- constraint: j.tsTypeReference(j.tsQualifiedName(j.identifier("React"), j.identifier("ElementType"))),
3623
- default: j.tsLiteralType(j.stringLiteral(tagName))
3624
- })]);
3625
- emitted.push(funcDecl);
3626
- } else emitted.push(emitTypes ? j.template.statement`
4036
+ ` : j.template.statement`
4037
+ function ${j.identifier(d.localName)}(props) {
4038
+ const { href, target, className, children, ...rest } = props;
4039
+ const isHttps = href?.startsWith("https");
4040
+ const isPdf = href?.endsWith(".pdf");
4041
+ const isExternal = target === "_blank";
4042
+ const sx = stylex.props(${styleArgs});
4043
+ return (
4044
+ <a
4045
+ {...sx}
4046
+ className={[sx.className, className].filter(Boolean).join(" ")}
4047
+ href={href}
4048
+ target={target}
4049
+ {...rest}
4050
+ >
4051
+ {children}
4052
+ </a>
4053
+ );
4054
+ }
4055
+ ` : emitTypes ? j.template.statement`
3627
4056
  function ${j.identifier(d.localName)}(props: ${j.identifier(propsTypeNameFor(d.localName))}) {
3628
- const { as: Component = ${j.literal(tagName)}, children, style, ...rest } = props;
4057
+ const { href, target, children, ...rest } = props;
4058
+ const isHttps = href?.startsWith("https");
4059
+ const isPdf = href?.endsWith(".pdf");
4060
+ const isExternal = target === "_blank";
4061
+ const sx = stylex.props(${styleArgs});
3629
4062
  return (
3630
- <Component {...rest} {...${stylexPropsCall}} style={style}>
3631
- {children}
3632
- </Component>
3633
- );
3634
- }
4063
+ <a href={href} target={target} {...rest} {...sx}>
4064
+ {children}
4065
+ </a>
4066
+ );
4067
+ }
3635
4068
  ` : j.template.statement`
3636
4069
  function ${j.identifier(d.localName)}(props) {
3637
- const { as: Component = ${j.literal(tagName)}, children, style, ...rest } = props;
4070
+ const { href, target, children, ...rest } = props;
4071
+ const isHttps = href?.startsWith("https");
4072
+ const isPdf = href?.endsWith(".pdf");
4073
+ const isExternal = target === "_blank";
4074
+ const sx = stylex.props(${styleArgs});
3638
4075
  return (
3639
- <Component {...rest} {...${stylexPropsCall}} style={style}>
4076
+ <a href={href} target={target} {...rest} {...sx}>
3640
4077
  {children}
3641
- </Component>
4078
+ </a>
3642
4079
  );
3643
4080
  }
3644
4081
  `);
3645
4082
  }
4083
+ if (intrinsicPolymorphicWrapperDecls.length > 0) for (const d of intrinsicPolymorphicWrapperDecls) {
4084
+ if (d.base.kind !== "intrinsic") continue;
4085
+ const tagName = d.base.tagName;
4086
+ const allowStyleProp = shouldAllowStyleProp(d);
4087
+ const explicit = stringifyTsType(d.propsType);
4088
+ const typeText = (() => {
4089
+ if (explicit) return explicit;
4090
+ const baseMaybeOmitted = `Omit<React.ComponentPropsWithoutRef<C>, "className" | "style">`;
4091
+ const hasAsExpression = getUsedAttrs(d.localName).has("as") && (root.find(j.JSXElement, { openingElement: { name: {
4092
+ type: "JSXIdentifier",
4093
+ name: d.localName
4094
+ } } }).filter((p) => {
4095
+ return (p.node.openingElement?.attributes ?? []).some((a) => a?.type === "JSXAttribute" && a.name?.type === "JSXIdentifier" && a.name.name === "as" && a.value?.type === "JSXExpressionContainer");
4096
+ }).size() > 0 || root.find(j.JSXSelfClosingElement, { name: {
4097
+ type: "JSXIdentifier",
4098
+ name: d.localName
4099
+ } }).filter((p) => {
4100
+ return (p.node.attributes ?? []).some((a) => a?.type === "JSXAttribute" && a.name?.type === "JSXIdentifier" && a.name.name === "as" && a.value?.type === "JSXExpressionContainer");
4101
+ }).size() > 0);
4102
+ return joinIntersection(baseMaybeOmitted, allowStyleProp && hasAsExpression ? "{ as?: C; style?: any }" : "{ as?: C }");
4103
+ })();
4104
+ emitNamedPropsType(d.localName, typeText, `C extends React.ElementType = "${tagName}"`);
4105
+ needsReactTypeImport = true;
4106
+ const styleArgs = [...d.extendsStyleKey ? [j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.extendsStyleKey))] : [], j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.styleKey))];
4107
+ const stylexPropsCall = j.callExpression(j.memberExpression(j.identifier("stylex"), j.identifier("props")), styleArgs);
4108
+ const isVoidTag = VOID_TAGS.has(tagName);
4109
+ const propsParamId = j.identifier("props");
4110
+ if (emitTypes) {
4111
+ const tp = j(`function _<C extends React.ElementType = "${tagName}">() { return null }`).get().node.program.body[0].typeParameters;
4112
+ propsParamId.typeAnnotation = j(`const x: ${propsTypeNameFor(d.localName)}<C> = null`).get().node.program.body[0].declarations[0].id.typeAnnotation;
4113
+ propsParamId.typeParameters = tp;
4114
+ }
4115
+ const propsId = j.identifier("props");
4116
+ const childrenId = j.identifier("children");
4117
+ const restId = j.identifier("rest");
4118
+ const styleId = j.identifier("style");
4119
+ const declStmt = j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern([
4120
+ j.property.from({
4121
+ kind: "init",
4122
+ key: j.identifier("as"),
4123
+ value: j.assignmentPattern(j.identifier("Component"), j.literal(tagName)),
4124
+ shorthand: false
4125
+ }),
4126
+ ...isVoidTag ? [] : [patternProp("children", childrenId)],
4127
+ ...allowStyleProp ? [patternProp("style", styleId)] : [],
4128
+ j.restElement(restId)
4129
+ ]), propsId)]);
4130
+ const attrs = [
4131
+ j.jsxSpreadAttribute(restId),
4132
+ j.jsxSpreadAttribute(stylexPropsCall),
4133
+ ...allowStyleProp ? [j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(styleId))] : []
4134
+ ];
4135
+ const openingEl = j.jsxOpeningElement(j.jsxIdentifier("Component"), attrs, isVoidTag);
4136
+ const jsx = isVoidTag ? {
4137
+ type: "JSXElement",
4138
+ openingElement: openingEl,
4139
+ closingElement: null,
4140
+ children: []
4141
+ } : j.jsxElement(openingEl, j.jsxClosingElement(j.jsxIdentifier("Component")), [j.jsxExpressionContainer(childrenId)]);
4142
+ const fn = j.functionDeclaration(j.identifier(d.localName), [propsParamId], j.blockStatement([declStmt, j.returnStatement(jsx)]));
4143
+ if (propsParamId.typeParameters) {
4144
+ fn.typeParameters = propsParamId.typeParameters;
4145
+ propsParamId.typeParameters = void 0;
4146
+ }
4147
+ emitted.push(fn);
4148
+ }
3646
4149
  const enumVariantWrappers = wrapperDecls.filter((d) => d.enumVariant);
3647
4150
  if (enumVariantWrappers.length > 0) for (const d of enumVariantWrappers) {
3648
4151
  if (!d.enumVariant) continue;
@@ -3652,7 +4155,7 @@ function emitWrappers(args) {
3652
4155
  if (!primary || !secondary) continue;
3653
4156
  const explicit = stringifyTsType(d.propsType);
3654
4157
  if (explicit) {
3655
- emitNamedPropsType(d.localName, explicit);
4158
+ emitNamedPropsType(d.localName, withChildren(explicit));
3656
4159
  needsReactTypeImport = true;
3657
4160
  } else {
3658
4161
  const hasNeq = cases.some((c) => c.kind === "neq");
@@ -3666,14 +4169,7 @@ function emitWrappers(args) {
3666
4169
  const propsId = j.identifier("props");
3667
4170
  const variantId = j.identifier(propName);
3668
4171
  const childrenId = j.identifier("children");
3669
- const classNameId = j.identifier("className");
3670
- const restId = j.identifier("rest");
3671
- const declStmt = j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern([
3672
- patternProp(propName, variantId),
3673
- patternProp("children", childrenId),
3674
- patternProp("className", classNameId),
3675
- j.restElement(restId)
3676
- ]), propsId)]);
4172
+ const declStmt = j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern([patternProp(propName, variantId), patternProp("children", childrenId)]), propsId)]);
3677
4173
  const base = j.memberExpression(j.identifier(stylesIdentifier), j.identifier(baseKey));
3678
4174
  const condPrimary = j.binaryExpression("===", variantId, j.literal(primary.whenValue));
3679
4175
  const condSecondary = secondary.kind === "neq" ? j.binaryExpression("!==", variantId, j.literal(secondary.whenValue)) : j.binaryExpression("===", variantId, j.literal(secondary.whenValue));
@@ -3682,12 +4178,7 @@ function emitWrappers(args) {
3682
4178
  j.logicalExpression("&&", condPrimary, j.memberExpression(j.identifier(stylesIdentifier), j.identifier(primary.styleKey))),
3683
4179
  j.logicalExpression("&&", condSecondary, j.memberExpression(j.identifier(stylesIdentifier), j.identifier(secondary.styleKey)))
3684
4180
  ]))]);
3685
- const mergedClassName = j.callExpression(j.memberExpression(j.callExpression(j.memberExpression(j.arrayExpression([j.memberExpression(j.identifier("sx"), j.identifier("className")), classNameId]), j.identifier("filter")), [j.identifier("Boolean")]), j.identifier("join")), [j.literal(" ")]);
3686
- const openingEl = j.jsxOpeningElement(j.jsxIdentifier("div"), [
3687
- j.jsxSpreadAttribute(j.identifier("sx")),
3688
- j.jsxAttribute(j.jsxIdentifier("className"), j.jsxExpressionContainer(mergedClassName)),
3689
- j.jsxSpreadAttribute(restId)
3690
- ], false);
4181
+ const openingEl = j.jsxOpeningElement(j.jsxIdentifier("div"), [j.jsxSpreadAttribute(j.identifier("sx"))], false);
3691
4182
  const jsx = j.jsxElement(openingEl, j.jsxClosingElement(j.jsxIdentifier("div")), [j.jsxExpressionContainer(childrenId)]);
3692
4183
  emitted.push(withLeadingComments(j.functionDeclaration(j.identifier(d.localName), [propsParamId], j.blockStatement([
3693
4184
  declStmt,
@@ -3698,9 +4189,14 @@ function emitWrappers(args) {
3698
4189
  for (const d of shouldForwardPropWrapperDecls) {
3699
4190
  if (d.base.kind !== "intrinsic") continue;
3700
4191
  const tagName = d.base.tagName;
3701
- const supportsExternalStyles = d.supportsExternalStyles ?? false;
4192
+ const allowClassNameProp = shouldAllowClassNameProp(d);
4193
+ const allowStyleProp = shouldAllowStyleProp(d);
3702
4194
  const extraProps = /* @__PURE__ */ new Set();
3703
4195
  for (const p of d.shouldForwardProp?.dropProps ?? []) if (p) extraProps.add(p);
4196
+ for (const when of Object.keys(d.variantStyleKeys ?? {})) {
4197
+ const { props } = parseVariantWhenToAst(j, when);
4198
+ for (const p of props) if (p) extraProps.add(p);
4199
+ }
3704
4200
  for (const p of d.styleFnFromProps ?? []) if (p?.jsxProp) extraProps.add(p.jsxProp);
3705
4201
  const dropPrefixFromFilter = d.shouldForwardProp?.dropPrefix;
3706
4202
  const usedAttrs = getUsedAttrs(d.localName);
@@ -3709,6 +4205,7 @@ function emitWrappers(args) {
3709
4205
  const knownPrefixProps = dropPrefixFromFilter ? [...extraProps].filter((p) => p.startsWith(dropPrefixFromFilter) && isValidIdentifier(p)) : [];
3710
4206
  const knownPrefixPropsSet = new Set(knownPrefixProps);
3711
4207
  const explicit = stringifyTsType(d.propsType);
4208
+ const explicitPropNames = d.propsType ? getExplicitPropNames(d.propsType) : /* @__PURE__ */ new Set();
3712
4209
  const extrasTypeText = (() => {
3713
4210
  if (explicit && explicit.trim()) return dropPrefixFromFilter === "$" && shouldAllowAnyPrefixProps ? `${explicit} & { [K in \`$\${string}\`]?: any }` : explicit;
3714
4211
  const lines = [];
@@ -3717,29 +4214,51 @@ function emitWrappers(args) {
3717
4214
  if (dropPrefixFromFilter === "$") return `${literal} & { [K in \`$\${string}\`]?: any }`;
3718
4215
  return literal;
3719
4216
  })();
3720
- const rawBaseTypeText = `React.ComponentProps<${JSON.stringify(tagName)}>`;
3721
- const composedInner = joinIntersection(rawBaseTypeText, extrasTypeText);
3722
- const finalTypeText = VOID_TAGS.has(tagName) ? composedInner : withChildren(composedInner);
4217
+ const finalTypeText = (() => {
4218
+ if (explicit) {
4219
+ if (VOID_TAGS.has(tagName)) {
4220
+ const base$1 = reactIntrinsicAttrsType(tagName);
4221
+ const omitted$1 = [];
4222
+ if (!allowClassNameProp) omitted$1.push("\"className\"");
4223
+ if (!allowStyleProp) omitted$1.push("\"style\"");
4224
+ return joinIntersection(omitted$1.length ? `Omit<${base$1}, ${omitted$1.join(" | ")}>` : base$1, extrasTypeText);
4225
+ }
4226
+ if (!d.shouldForwardPropFromWithConfig) {
4227
+ const supplementalLines = [];
4228
+ if (allowClassNameProp) supplementalLines.push(` className?: string;`);
4229
+ if (allowStyleProp) supplementalLines.push(` style?: React.CSSProperties;`);
4230
+ return withChildren(joinIntersection(extrasTypeText, supplementalLines.length > 0 ? `{\n${supplementalLines.join("\n")}\n}` : "{}"));
4231
+ }
4232
+ const base = `React.ComponentProps<"${tagName}">`;
4233
+ const omitted = [];
4234
+ if (!allowClassNameProp) omitted.push("\"className\"");
4235
+ if (!allowStyleProp) omitted.push("\"style\"");
4236
+ return joinIntersection(omitted.length ? `Omit<${base}, ${omitted.join(" | ")}>` : base, extrasTypeText);
4237
+ }
4238
+ const inferred = inferredIntrinsicPropsTypeText({
4239
+ d,
4240
+ tagName,
4241
+ allowClassNameProp,
4242
+ allowStyleProp,
4243
+ skipProps: explicitPropNames
4244
+ });
4245
+ return VOID_TAGS.has(tagName) ? inferred : withChildren(inferred);
4246
+ })();
3723
4247
  if (!emitNamedPropsType(d.localName, finalTypeText) && explicit) {
3724
4248
  const propsTypeName = propsTypeNameFor(d.localName);
3725
- if (!extendExistingInterface(propsTypeName, rawBaseTypeText)) extendExistingTypeAlias(propsTypeName, rawBaseTypeText);
4249
+ const extendBaseTypeText = (() => {
4250
+ const base = reactIntrinsicAttrsType(tagName);
4251
+ const omitted = [];
4252
+ if (!allowClassNameProp) omitted.push("\"className\"");
4253
+ if (!allowStyleProp) omitted.push("\"style\"");
4254
+ return omitted.length ? `Omit<${base}, ${omitted.join(" | ")}>` : base;
4255
+ })();
4256
+ if (!extendExistingInterface(propsTypeName, extendBaseTypeText)) extendExistingTypeAlias(propsTypeName, extendBaseTypeText);
3726
4257
  }
3727
4258
  needsReactTypeImport = true;
3728
4259
  const styleArgs = [...d.extendsStyleKey ? [j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.extendsStyleKey))] : [], j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.styleKey))];
3729
4260
  if (d.variantStyleKeys) for (const [when, variantKey] of Object.entries(d.variantStyleKeys)) {
3730
- let cond = null;
3731
- const trimmed = when.trim();
3732
- if (trimmed.startsWith("!(") && trimmed.endsWith(")")) {
3733
- const inner = trimmed.slice(2, -1).trim();
3734
- cond = j.unaryExpression("!", j.identifier(inner));
3735
- } else if (trimmed.startsWith("!")) cond = j.unaryExpression("!", j.identifier(trimmed.slice(1)));
3736
- else if (trimmed.includes("===") || trimmed.includes("!==")) {
3737
- const op = trimmed.includes("!==") ? "!==" : "===";
3738
- const [lhs, rhsRaw0] = trimmed.split(op).map((s) => s.trim());
3739
- const rhsRaw = rhsRaw0 ?? "";
3740
- const rhs = rhsRaw?.startsWith("\"") || rhsRaw?.startsWith("'") ? j.literal(JSON.parse(rhsRaw.replace(/^'/, "\"").replace(/'$/, "\""))) : /^-?\d+(\.\d+)?$/.test(rhsRaw) ? j.literal(Number(rhsRaw)) : j.identifier(rhsRaw);
3741
- cond = j.binaryExpression(op, j.identifier(lhs ?? ""), rhs);
3742
- } else cond = j.identifier(trimmed);
4261
+ const { cond } = parseVariantWhenToAst(j, when);
3743
4262
  styleArgs.push(j.logicalExpression("&&", cond, j.memberExpression(j.identifier(stylesIdentifier), j.identifier(variantKey))));
3744
4263
  }
3745
4264
  const styleFnPairs = d.styleFnFromProps ?? [];
@@ -3763,31 +4282,25 @@ function emitWrappers(args) {
3763
4282
  const styleId = j.identifier("style");
3764
4283
  const restId = j.identifier("rest");
3765
4284
  const isVoidTag = tagName === "input";
3766
- const shouldOmitRestSpread = !dropPrefix && dropProps.length > 0 && dropProps.every((p) => p.startsWith("$")) && !usedAttrs.has("*") && [...usedAttrs].every((n) => n === "children" || dropProps.includes(n));
3767
- if (!supportsExternalStyles) {
4285
+ const { hasAny: hasLocalUsage } = getJsxCallsites(d.localName);
4286
+ const shouldIncludeRest = isUsedAsValueInFile(d.localName) || hasLocalUsage && usedAttrs.has("*") || hasLocalUsage && [...usedAttrs].some((n) => {
4287
+ if (n === "children" || n === "className" || n === "style" || n === "as" || n === "forwardedAs") return false;
4288
+ return !destructureParts.includes(n);
4289
+ });
4290
+ const includeRest = !(!dropPrefix && dropProps.length > 0 && dropProps.every((p) => p.startsWith("$")) && !usedAttrs.has("*") && [...usedAttrs].every((n) => n === "children" || dropProps.includes(n))) && shouldIncludeRest;
4291
+ if (!allowClassNameProp && !allowStyleProp) {
3768
4292
  const isVoid = VOID_TAGS.has(tagName);
3769
4293
  const patternProps$1 = [
3770
4294
  ...isVoid ? [] : [patternProp("children", childrenId)],
3771
- patternProp("className", classNameId),
3772
- patternProp("style", styleId),
3773
4295
  ...destructureParts.filter(Boolean).map((name) => patternProp(name)),
3774
- ...shouldOmitRestSpread ? [] : [j.restElement(restId)]
4296
+ ...includeRest ? [j.restElement(restId)] : []
3775
4297
  ];
3776
4298
  const declStmt$1 = j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern(patternProps$1), propsId)]);
3777
- const cleanupPrefixStmt$1 = dropPrefix && shouldAllowAnyPrefixProps ? j.forOfStatement(j.variableDeclaration("const", [j.variableDeclarator(j.identifier("k"), null)]), j.callExpression(j.memberExpression(j.identifier("Object"), j.identifier("keys")), [restId]), j.blockStatement([j.ifStatement(j.callExpression(j.memberExpression(j.identifier("k"), j.identifier("startsWith")), [j.literal(dropPrefix)]), j.expressionStatement(j.unaryExpression("delete", j.memberExpression(restId, j.identifier("k"), true))))])) : null;
3778
- const stylexPropsCall = j.callExpression(j.memberExpression(j.identifier("stylex"), j.identifier("props")), styleArgs);
3779
- const sxDecl$1 = j.variableDeclaration("const", [j.variableDeclarator(j.identifier("sx"), stylexPropsCall)]);
3780
- const mergedClassName$1 = j.callExpression(j.memberExpression(j.callExpression(j.memberExpression(j.arrayExpression([j.memberExpression(j.identifier("sx"), j.identifier("className")), classNameId]), j.identifier("filter")), [j.identifier("Boolean")]), j.identifier("join")), [j.literal(" ")]);
3781
- const openingEl$1 = j.jsxOpeningElement(j.jsxIdentifier(tagName), [
3782
- j.jsxSpreadAttribute(j.identifier("sx")),
3783
- j.jsxAttribute(j.jsxIdentifier("className"), j.jsxExpressionContainer(mergedClassName$1)),
3784
- ...d.inlineStyleProps && d.inlineStyleProps.length ? [j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression([
3785
- j.spreadElement(j.memberExpression(j.identifier("sx"), j.identifier("style"))),
3786
- j.spreadElement(styleId),
3787
- ...d.inlineStyleProps.map((p) => j.property("init", j.identifier(p.prop), p.expr))
3788
- ])))] : [j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression([j.spreadElement(j.memberExpression(j.identifier("sx"), j.identifier("style"))), j.spreadElement(styleId)])))],
3789
- ...shouldOmitRestSpread ? [] : [j.jsxSpreadAttribute(restId)]
3790
- ], false);
4299
+ const cleanupPrefixStmt$1 = dropPrefix && shouldAllowAnyPrefixProps && includeRest ? j.forOfStatement(j.variableDeclaration("const", [j.variableDeclarator(j.identifier("k"), null)]), j.callExpression(j.memberExpression(j.identifier("Object"), j.identifier("keys")), [restId]), j.blockStatement([j.ifStatement(j.callExpression(j.memberExpression(j.identifier("k"), j.identifier("startsWith")), [j.literal(dropPrefix)]), j.expressionStatement(j.unaryExpression("delete", j.memberExpression(restId, j.identifier("k"), true))))])) : null;
4300
+ const sxDecl$1 = j.variableDeclaration("const", [j.variableDeclarator(j.identifier("sx"), j.callExpression(j.memberExpression(j.identifier("stylex"), j.identifier("props")), styleArgs))]);
4301
+ const openingAttrs$1 = [...includeRest ? [j.jsxSpreadAttribute(restId)] : [], j.jsxSpreadAttribute(j.identifier("sx"))];
4302
+ if (d.inlineStyleProps && d.inlineStyleProps.length) openingAttrs$1.push(j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression([j.spreadElement(j.memberExpression(j.identifier("sx"), j.identifier("style"))), ...d.inlineStyleProps.map((p) => j.property("init", j.identifier(p.prop), p.expr))]))));
4303
+ const openingEl$1 = j.jsxOpeningElement(j.jsxIdentifier(tagName), openingAttrs$1, false);
3791
4304
  const jsx$1 = isVoid ? {
3792
4305
  type: "JSXElement",
3793
4306
  openingElement: {
@@ -3805,26 +4318,27 @@ function emitWrappers(args) {
3805
4318
  continue;
3806
4319
  }
3807
4320
  const patternProps = [
3808
- patternProp("className", classNameId),
4321
+ ...allowClassNameProp ? [patternProp("className", classNameId)] : [],
3809
4322
  ...isVoidTag ? [] : [patternProp("children", childrenId)],
3810
- patternProp("style", styleId),
4323
+ ...allowStyleProp ? [patternProp("style", styleId)] : [],
3811
4324
  ...destructureParts.filter(Boolean).map((name) => patternProp(name)),
3812
- ...shouldOmitRestSpread ? [] : [j.restElement(restId)]
4325
+ ...includeRest ? [j.restElement(restId)] : []
3813
4326
  ];
3814
4327
  const declStmt = j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern(patternProps), propsId)]);
3815
- const cleanupPrefixStmt = dropPrefix && shouldAllowAnyPrefixProps ? j.forOfStatement(j.variableDeclaration("const", [j.variableDeclarator(j.identifier("k"), null)]), j.callExpression(j.memberExpression(j.identifier("Object"), j.identifier("keys")), [restId]), j.blockStatement([j.ifStatement(j.callExpression(j.memberExpression(j.identifier("k"), j.identifier("startsWith")), [j.literal(dropPrefix)]), j.expressionStatement(j.unaryExpression("delete", j.memberExpression(restId, j.identifier("k"), true))))])) : null;
4328
+ const cleanupPrefixStmt = dropPrefix && shouldAllowAnyPrefixProps && includeRest ? j.forOfStatement(j.variableDeclaration("const", [j.variableDeclarator(j.identifier("k"), null)]), j.callExpression(j.memberExpression(j.identifier("Object"), j.identifier("keys")), [restId]), j.blockStatement([j.ifStatement(j.callExpression(j.memberExpression(j.identifier("k"), j.identifier("startsWith")), [j.literal(dropPrefix)]), j.expressionStatement(j.unaryExpression("delete", j.memberExpression(restId, j.identifier("k"), true))))])) : null;
3816
4329
  const sxDecl = j.variableDeclaration("const", [j.variableDeclarator(j.identifier("sx"), j.callExpression(j.memberExpression(j.identifier("stylex"), j.identifier("props")), styleArgs))]);
3817
- const mergedClassName = j.callExpression(j.memberExpression(j.callExpression(j.memberExpression(j.arrayExpression([j.memberExpression(j.identifier("sx"), j.identifier("className")), classNameId]), j.identifier("filter")), [j.identifier("Boolean")]), j.identifier("join")), [j.literal(" ")]);
3818
- const openingEl = j.jsxOpeningElement(j.jsxIdentifier(tagName), [
3819
- j.jsxSpreadAttribute(j.identifier("sx")),
3820
- j.jsxAttribute(j.jsxIdentifier("className"), j.jsxExpressionContainer(mergedClassName)),
3821
- ...d.inlineStyleProps && d.inlineStyleProps.length ? [j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression([
3822
- j.spreadElement(j.memberExpression(j.identifier("sx"), j.identifier("style"))),
3823
- j.spreadElement(styleId),
3824
- ...d.inlineStyleProps.map((p) => j.property("init", j.identifier(p.prop), p.expr))
3825
- ])))] : [j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression([j.spreadElement(j.memberExpression(j.identifier("sx"), j.identifier("style"))), j.spreadElement(styleId)])))],
3826
- ...shouldOmitRestSpread ? [] : [j.jsxSpreadAttribute(restId)]
3827
- ], false);
4330
+ const openingAttrs = [j.jsxSpreadAttribute(j.identifier("sx"))];
4331
+ if (allowClassNameProp) {
4332
+ const mergedClassName = j.callExpression(j.memberExpression(j.callExpression(j.memberExpression(j.arrayExpression([j.memberExpression(j.identifier("sx"), j.identifier("className")), classNameId]), j.identifier("filter")), [j.identifier("Boolean")]), j.identifier("join")), [j.literal(" ")]);
4333
+ openingAttrs.push(j.jsxAttribute(j.jsxIdentifier("className"), j.jsxExpressionContainer(mergedClassName)));
4334
+ }
4335
+ if (allowStyleProp || d.inlineStyleProps && d.inlineStyleProps.length) openingAttrs.push(j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression([
4336
+ j.spreadElement(j.memberExpression(j.identifier("sx"), j.identifier("style"))),
4337
+ ...allowStyleProp ? [j.spreadElement(styleId)] : [],
4338
+ ...d.inlineStyleProps && d.inlineStyleProps.length ? d.inlineStyleProps.map((p) => j.property("init", j.identifier(p.prop), p.expr)) : []
4339
+ ]))));
4340
+ if (includeRest) openingAttrs.push(j.jsxSpreadAttribute(restId));
4341
+ const openingEl = j.jsxOpeningElement(j.jsxIdentifier(tagName), openingAttrs, false);
3828
4342
  const jsx = isVoidTag ? {
3829
4343
  type: "JSXElement",
3830
4344
  openingElement: {
@@ -3856,6 +4370,8 @@ function emitWrappers(args) {
3856
4370
  if (d.base.kind !== "intrinsic") continue;
3857
4371
  const tagName = d.base.tagName;
3858
4372
  const supportsExternalStyles = d.supportsExternalStyles ?? false;
4373
+ const allowClassNameProp = shouldAllowClassNameProp(d);
4374
+ const allowStyleProp = shouldAllowStyleProp(d);
3859
4375
  {
3860
4376
  const explicit = stringifyTsType(d.propsType);
3861
4377
  const baseTypeText = (() => {
@@ -3863,8 +4379,14 @@ function emitWrappers(args) {
3863
4379
  const used = getUsedAttrs(d.localName);
3864
4380
  if (used.has("*")) return true;
3865
4381
  return used.size > 0;
3866
- })() ? `React.ComponentProps<${JSON.stringify(tagName)}>` : "{}";
3867
- emitNamedPropsType(d.localName, explicit ?? (VOID_TAGS.has(tagName) ? baseTypeText : withChildren(baseTypeText)));
4382
+ })() ? inferredIntrinsicPropsTypeText({
4383
+ d,
4384
+ tagName,
4385
+ allowClassNameProp,
4386
+ allowStyleProp
4387
+ }) : "{}";
4388
+ const typeWithChildren = !explicit && !VOID_TAGS.has(tagName) ? withChildren(baseTypeText) : baseTypeText;
4389
+ emitNamedPropsType(d.localName, explicit ?? typeWithChildren);
3868
4390
  needsReactTypeImport = true;
3869
4391
  }
3870
4392
  const styleArgs = [...d.extendsStyleKey ? [j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.extendsStyleKey))] : [], j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.styleKey))];
@@ -3876,7 +4398,9 @@ function emitWrappers(args) {
3876
4398
  const styleId = j.identifier("style");
3877
4399
  const restId = j.identifier("rest");
3878
4400
  const isVoidTag = VOID_TAGS.has(tagName);
3879
- if (!supportsExternalStyles) {
4401
+ if (!allowClassNameProp && !allowStyleProp) {
4402
+ const usedAttrs = getUsedAttrs(d.localName);
4403
+ const includeRest = usedAttrs.has("*") || !!d.usedAsValue || usedAttrs.size > 0;
3880
4404
  emitted.push(...withLeadingCommentsOnFirstFunction(emitMinimalWrapper({
3881
4405
  j,
3882
4406
  localName: d.localName,
@@ -3885,7 +4409,11 @@ function emitWrappers(args) {
3885
4409
  emitTypes,
3886
4410
  styleArgs,
3887
4411
  destructureProps: [],
3888
- patternProp
4412
+ allowClassNameProp: false,
4413
+ allowStyleProp: false,
4414
+ includeRest,
4415
+ patternProp,
4416
+ inlineStyleProps: d.inlineStyleProps ?? []
3889
4417
  }), d));
3890
4418
  continue;
3891
4419
  }
@@ -3929,7 +4457,13 @@ function emitWrappers(args) {
3929
4457
  extras.push(`${sw.propAdjacent}?: boolean;`);
3930
4458
  if (sw.propAfter) extras.push(`${sw.propAfter}?: boolean;`);
3931
4459
  const extraType = `{ ${extras.join(" ")} }`;
3932
- emitNamedPropsType(d.localName, explicit ?? joinIntersection(`React.ComponentProps<"div">`, extraType));
4460
+ const baseTypeText = inferredIntrinsicPropsTypeText({
4461
+ d,
4462
+ tagName: "div",
4463
+ allowClassNameProp: shouldAllowClassNameProp(d),
4464
+ allowStyleProp: shouldAllowStyleProp(d)
4465
+ });
4466
+ emitNamedPropsType(d.localName, explicit ?? joinIntersection(baseTypeText, extraType));
3933
4467
  needsReactTypeImport = true;
3934
4468
  }
3935
4469
  const propsParamId = j.identifier("props");
@@ -3978,16 +4512,30 @@ function emitWrappers(args) {
3978
4512
  for (const d of simpleExportedIntrinsicWrappers) {
3979
4513
  if (d.base.kind !== "intrinsic") continue;
3980
4514
  const tagName = d.base.tagName;
3981
- const supportsExternalStyles = d.supportsExternalStyles ?? false;
4515
+ const allowClassNameProp = shouldAllowClassNameProp(d);
4516
+ const allowStyleProp = shouldAllowStyleProp(d);
3982
4517
  let inlineTypeText;
3983
4518
  {
3984
4519
  const explicit = stringifyTsType(d.propsType);
3985
- const baseTypeText = `React.ComponentProps<${JSON.stringify(tagName)}>`;
3986
- const typeText = explicit ? `${baseTypeText} & ${explicit}` : baseTypeText;
4520
+ const baseTypeText = inferredIntrinsicPropsTypeText({
4521
+ d,
4522
+ tagName,
4523
+ allowClassNameProp,
4524
+ allowStyleProp,
4525
+ skipProps: d.propsType ? getExplicitPropNames(d.propsType) : /* @__PURE__ */ new Set()
4526
+ });
4527
+ const extendBaseTypeText = (() => {
4528
+ const base = reactIntrinsicAttrsType(tagName);
4529
+ const omitted = [];
4530
+ if (!allowClassNameProp) omitted.push("\"className\"");
4531
+ if (!allowStyleProp) omitted.push("\"style\"");
4532
+ return omitted.length ? `Omit<${base}, ${omitted.join(" | ")}>` : base;
4533
+ })();
4534
+ const typeText = explicit ? VOID_TAGS.has(tagName) ? joinIntersection(extendBaseTypeText, explicit) : withChildren(explicit) : baseTypeText;
3987
4535
  if (!emitNamedPropsType(d.localName, typeText) && explicit) {
3988
4536
  const propsTypeName = propsTypeNameFor(d.localName);
3989
- if (!extendExistingInterface(propsTypeName, baseTypeText)) {
3990
- if (!extendExistingTypeAlias(propsTypeName, baseTypeText)) inlineTypeText = `React.PropsWithChildren<${explicit} & { style?: React.CSSProperties }>`;
4537
+ if (!extendExistingInterface(propsTypeName, extendBaseTypeText)) {
4538
+ if (!extendExistingTypeAlias(propsTypeName, extendBaseTypeText)) inlineTypeText = VOID_TAGS.has(tagName) ? explicit : withChildren(explicit);
3991
4539
  }
3992
4540
  }
3993
4541
  needsReactTypeImport = true;
@@ -3995,28 +4543,8 @@ function emitWrappers(args) {
3995
4543
  const styleArgs = [...d.extendsStyleKey ? [j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.extendsStyleKey))] : [], j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.styleKey))];
3996
4544
  const destructureProps = [];
3997
4545
  if (d.variantStyleKeys) for (const [when, variantKey] of Object.entries(d.variantStyleKeys)) {
3998
- let cond = null;
3999
- const trimmed = when.trim();
4000
- let propName = "";
4001
- if (trimmed.startsWith("!(") && trimmed.endsWith(")")) {
4002
- const inner = trimmed.slice(2, -1).trim();
4003
- cond = j.unaryExpression("!", j.identifier(inner));
4004
- propName = inner;
4005
- } else if (trimmed.startsWith("!")) {
4006
- propName = trimmed.slice(1);
4007
- cond = j.unaryExpression("!", j.identifier(propName));
4008
- } else if (trimmed.includes("===") || trimmed.includes("!==")) {
4009
- const op = trimmed.includes("!==") ? "!==" : "===";
4010
- const [lhs, rhsRaw0] = trimmed.split(op).map((s) => s.trim());
4011
- const rhsRaw = rhsRaw0 ?? "";
4012
- const rhs = rhsRaw?.startsWith("\"") || rhsRaw?.startsWith("'") ? j.literal(JSON.parse(rhsRaw.replace(/^'/, "\"").replace(/'$/, "\""))) : /^-?\d+(\.\d+)?$/.test(rhsRaw) ? j.literal(Number(rhsRaw)) : j.identifier(rhsRaw);
4013
- propName = lhs ?? "";
4014
- cond = j.binaryExpression(op, j.identifier(propName), rhs);
4015
- } else {
4016
- propName = trimmed;
4017
- cond = j.identifier(trimmed);
4018
- }
4019
- if (propName && !destructureProps.includes(propName)) destructureProps.push(propName);
4546
+ const { cond, props } = parseVariantWhenToAst(j, when);
4547
+ for (const p of props) if (p && !destructureProps.includes(p)) destructureProps.push(p);
4020
4548
  styleArgs.push(j.logicalExpression("&&", cond, j.memberExpression(j.identifier(stylesIdentifier), j.identifier(variantKey))));
4021
4549
  }
4022
4550
  const styleFnPairs = d.styleFnFromProps ?? [];
@@ -4027,7 +4555,19 @@ function emitWrappers(args) {
4027
4555
  if (isPropRequiredInPropsTypeLiteral(d.propsType, p.jsxProp)) styleArgs.push(call);
4028
4556
  else styleArgs.push(j.logicalExpression("&&", j.binaryExpression("!=", propExpr, j.nullLiteral()), call));
4029
4557
  }
4030
- if (supportsExternalStyles) {
4558
+ if (d.attrsInfo?.conditionalAttrs?.length) {
4559
+ for (const c of d.attrsInfo.conditionalAttrs) if (c?.jsxProp && !destructureProps.includes(c.jsxProp)) destructureProps.push(c.jsxProp);
4560
+ }
4561
+ if (d.attrsInfo?.invertedBoolAttrs?.length) {
4562
+ for (const inv of d.attrsInfo.invertedBoolAttrs) if (inv?.jsxProp && !destructureProps.includes(inv.jsxProp)) destructureProps.push(inv.jsxProp);
4563
+ }
4564
+ const usedAttrs = getUsedAttrs(d.localName);
4565
+ const { hasAny: hasLocalUsage } = getJsxCallsites(d.localName);
4566
+ const shouldIncludeRest = isUsedAsValueInFile(d.localName) || hasLocalUsage && usedAttrs.has("*") || hasLocalUsage && [...usedAttrs].some((n) => {
4567
+ if (n === "children" || n === "className" || n === "style" || n === "as" || n === "forwardedAs") return false;
4568
+ return !destructureProps.includes(n);
4569
+ });
4570
+ if (allowClassNameProp || allowStyleProp) {
4031
4571
  const isVoidTag = VOID_TAGS.has(tagName);
4032
4572
  const propsParamId = j.identifier("props");
4033
4573
  annotatePropsParam(propsParamId, d.localName, inlineTypeText);
@@ -4035,22 +4575,26 @@ function emitWrappers(args) {
4035
4575
  const classNameId = j.identifier("className");
4036
4576
  const childrenId = j.identifier("children");
4037
4577
  const styleId = j.identifier("style");
4038
- const restId = j.identifier("rest");
4578
+ const restId = shouldIncludeRest ? j.identifier("rest") : null;
4039
4579
  const patternProps = [
4040
- patternProp("className", classNameId),
4580
+ ...allowClassNameProp ? [patternProp("className", classNameId)] : [],
4041
4581
  ...isVoidTag ? [] : [patternProp("children", childrenId)],
4042
- patternProp("style", styleId),
4582
+ ...allowStyleProp ? [patternProp("style", styleId)] : [],
4043
4583
  ...destructureProps.map((name) => patternProp(name)),
4044
- j.restElement(restId)
4584
+ ...restId ? [j.restElement(restId)] : []
4045
4585
  ];
4046
4586
  const declStmt = j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern(patternProps), propsId)]);
4047
4587
  const sxDecl = j.variableDeclaration("const", [j.variableDeclarator(j.identifier("sx"), j.callExpression(j.memberExpression(j.identifier("stylex"), j.identifier("props")), styleArgs))]);
4048
- const mergedClassName = j.callExpression(j.memberExpression(j.callExpression(j.memberExpression(j.arrayExpression([j.memberExpression(j.identifier("sx"), j.identifier("className")), classNameId]), j.identifier("filter")), [j.identifier("Boolean")]), j.identifier("join")), [j.literal(" ")]);
4588
+ const mergedClassName = allowClassNameProp ? j.callExpression(j.memberExpression(j.callExpression(j.memberExpression(j.arrayExpression([j.memberExpression(j.identifier("sx"), j.identifier("className")), classNameId]), j.identifier("filter")), [j.identifier("Boolean")]), j.identifier("join")), [j.literal(" ")]) : null;
4049
4589
  const openingEl = j.jsxOpeningElement(j.jsxIdentifier(tagName), [
4050
4590
  j.jsxSpreadAttribute(j.identifier("sx")),
4051
- j.jsxAttribute(j.jsxIdentifier("className"), j.jsxExpressionContainer(mergedClassName)),
4052
- j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression([j.spreadElement(j.memberExpression(j.identifier("sx"), j.identifier("style"))), j.spreadElement(styleId)]))),
4053
- j.jsxSpreadAttribute(restId)
4591
+ ...allowClassNameProp ? [j.jsxAttribute(j.jsxIdentifier("className"), j.jsxExpressionContainer(mergedClassName))] : [],
4592
+ ...allowStyleProp || d.inlineStyleProps && d.inlineStyleProps.length ? [j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression([
4593
+ j.spreadElement(j.memberExpression(j.identifier("sx"), j.identifier("style"))),
4594
+ ...allowStyleProp ? [j.spreadElement(styleId)] : [],
4595
+ ...d.inlineStyleProps && d.inlineStyleProps.length ? d.inlineStyleProps.map((p) => j.property("init", j.identifier(p.prop), p.expr)) : []
4596
+ ])))] : [],
4597
+ ...restId ? [j.jsxSpreadAttribute(restId)] : []
4054
4598
  ], false);
4055
4599
  const jsx = isVoidTag ? {
4056
4600
  type: "JSXElement",
@@ -4078,37 +4622,61 @@ function emitWrappers(args) {
4078
4622
  emitTypes,
4079
4623
  styleArgs,
4080
4624
  destructureProps,
4625
+ allowClassNameProp: false,
4626
+ allowStyleProp: false,
4627
+ includeRest: shouldIncludeRest,
4081
4628
  patternProp,
4082
- ...d.attrsInfo?.staticAttrs ? { staticAttrs: d.attrsInfo.staticAttrs } : {}
4629
+ ...d.attrsInfo?.defaultAttrs ? { defaultAttrs: d.attrsInfo.defaultAttrs } : {},
4630
+ ...d.attrsInfo?.conditionalAttrs ? { conditionalAttrs: d.attrsInfo.conditionalAttrs } : {},
4631
+ ...d.attrsInfo?.invertedBoolAttrs ? { invertedBoolAttrs: d.attrsInfo.invertedBoolAttrs } : {},
4632
+ ...d.attrsInfo?.staticAttrs ? { staticAttrs: d.attrsInfo.staticAttrs } : {},
4633
+ inlineStyleProps: d.inlineStyleProps ?? []
4083
4634
  }), d));
4084
4635
  }
4085
4636
  const componentWrappers = wrapperDecls.filter((d) => d.base.kind === "component");
4086
4637
  for (const d of componentWrappers) {
4087
4638
  if (d.base.kind !== "component") continue;
4088
4639
  const wrappedComponent = d.base.ident;
4640
+ const wrappedComponentHasAs = wrapperNames.has(wrappedComponent);
4641
+ const isPolymorphicComponentWrapper = wrapperNames.has(d.localName) && !wrappedComponentHasAs;
4642
+ const allowClassNameProp = shouldAllowClassNameProp(d);
4643
+ const allowStyleProp = shouldAllowStyleProp(d);
4644
+ const propsIdForExpr = j.identifier("props");
4089
4645
  let functionParamTypeName = null;
4090
- let needsGenericPolymorphicType = false;
4091
4646
  {
4092
4647
  const explicit = stringifyTsType(d.propsType);
4093
- const baseTypeText = `React.ComponentProps<typeof ${wrappedComponent}>`;
4094
4648
  const explicitTypeName = d.propsType?.type === "TSTypeReference" && d.propsType?.typeName?.type === "Identifier" ? d.propsType?.typeName?.name : null;
4095
- if (explicitTypeName && typeExistsInFile(explicitTypeName) && explicit) {
4649
+ if (explicitTypeName && typeExistsInFile(explicitTypeName) && explicit && explicitTypeName) {
4650
+ const baseTypeText = (() => {
4651
+ const base = `React.ComponentProps<typeof ${wrappedComponent}>`;
4652
+ const omitted = [];
4653
+ if (!allowClassNameProp) omitted.push("\"className\"");
4654
+ if (!allowStyleProp) omitted.push("\"style\"");
4655
+ return omitted.length ? `Omit<${base}, ${omitted.join(" | ")}>` : base;
4656
+ })();
4096
4657
  if (!extendExistingInterface(explicitTypeName, baseTypeText)) extendExistingTypeAlias(explicitTypeName, baseTypeText);
4097
4658
  functionParamTypeName = explicitTypeName;
4098
4659
  } else {
4099
- const wrappedComponentHasAs = wrapperNames.has(wrappedComponent);
4100
- if (wrapperNames.has(d.localName) && !wrappedComponentHasAs) {
4101
- needsGenericPolymorphicType = true;
4102
- const genericParams = `C extends React.ElementType = typeof ${wrappedComponent}`;
4103
- const omitType = `Omit<React.ComponentPropsWithoutRef<C>, keyof ${baseTypeText}>`;
4104
- const typeText = explicit ? `${baseTypeText} & ${omitType} & { as?: C } & ${explicit}` : `${baseTypeText} & ${omitType} & { as?: C }`;
4105
- emitNamedPropsType(d.localName, typeText, genericParams);
4660
+ const explicitPropNames = d.propsType ? getExplicitPropNames(d.propsType) : /* @__PURE__ */ new Set();
4661
+ if (isPolymorphicComponentWrapper) {
4662
+ const baseProps = `React.ComponentProps<typeof ${wrappedComponent}>`;
4663
+ const omitted = [];
4664
+ if (!allowClassNameProp) omitted.push("\"className\"");
4665
+ if (!allowStyleProp) omitted.push("\"style\"");
4666
+ const typeText = joinIntersection(omitted.length ? `Omit<${baseProps}, ${omitted.join(" | ")}>` : baseProps, "{ as?: C }", `Omit<React.ComponentPropsWithoutRef<C>, keyof ${baseProps} | "as">`);
4667
+ emitNamedPropsType(d.localName, typeText, `C extends React.ElementType = typeof ${wrappedComponent}`);
4106
4668
  } else {
4107
- const typeText = explicit ? `${baseTypeText} & ${explicit}` : baseTypeText;
4108
- if (!emitNamedPropsType(d.localName, typeText) && explicit) {
4109
- const propsTypeName = propsTypeNameFor(d.localName);
4110
- if (!extendExistingInterface(propsTypeName, baseTypeText)) extendExistingTypeAlias(propsTypeName, baseTypeText);
4111
- }
4669
+ const inferred = inferredComponentWrapperPropsTypeText({
4670
+ d,
4671
+ allowClassNameProp,
4672
+ allowStyleProp,
4673
+ includeAsProp: false,
4674
+ includeChildren: hasJsxChildrenUsage(d.localName),
4675
+ skipProps: explicitPropNames
4676
+ });
4677
+ const explicitWithChildren = explicit ? withChildren(explicit) : null;
4678
+ const typeText = explicitWithChildren ? joinIntersection(inferred, explicitWithChildren) : inferred;
4679
+ emitNamedPropsType(d.localName, typeText);
4112
4680
  }
4113
4681
  }
4114
4682
  needsReactTypeImport = true;
@@ -4116,42 +4684,36 @@ function emitWrappers(args) {
4116
4684
  const styleArgs = [j.memberExpression(j.identifier(stylesIdentifier), j.identifier(d.styleKey))];
4117
4685
  const destructureProps = [];
4118
4686
  if (d.variantStyleKeys) for (const [when, variantKey] of Object.entries(d.variantStyleKeys)) {
4119
- let cond = null;
4120
- const trimmed = when.trim();
4121
- let propName = "";
4122
- if (trimmed.startsWith("!(") && trimmed.endsWith(")")) {
4123
- const inner = trimmed.slice(2, -1).trim();
4124
- cond = j.unaryExpression("!", j.identifier(inner));
4125
- propName = inner;
4126
- } else if (trimmed.startsWith("!")) {
4127
- propName = trimmed.slice(1);
4128
- cond = j.unaryExpression("!", j.identifier(propName));
4129
- } else if (trimmed.includes("===") || trimmed.includes("!==")) {
4130
- const op = trimmed.includes("!==") ? "!==" : "===";
4131
- const [lhs, rhsRaw0] = trimmed.split(op).map((s) => s.trim());
4132
- const rhsRaw = rhsRaw0 ?? "";
4133
- const rhs = rhsRaw?.startsWith("\"") || rhsRaw?.startsWith("'") ? j.literal(JSON.parse(rhsRaw.replace(/^'/, "\"").replace(/'$/, "\""))) : /^-?\d+(\.\d+)?$/.test(rhsRaw) ? j.literal(Number(rhsRaw)) : j.identifier(rhsRaw);
4134
- propName = lhs ?? "";
4135
- cond = j.binaryExpression(op, j.identifier(propName), rhs);
4136
- } else {
4137
- propName = trimmed;
4138
- cond = j.identifier(trimmed);
4139
- }
4140
- if (propName && !destructureProps.includes(propName)) destructureProps.push(propName);
4687
+ const { cond, props } = parseVariantWhenToAst(j, when);
4688
+ for (const p of props) if (p && !destructureProps.includes(p)) destructureProps.push(p);
4141
4689
  styleArgs.push(j.logicalExpression("&&", cond, j.memberExpression(j.identifier(stylesIdentifier), j.identifier(variantKey))));
4142
4690
  }
4143
4691
  const styleFnPairs = d.styleFnFromProps ?? [];
4144
4692
  for (const p of styleFnPairs) {
4145
- const propExpr = j.identifier(p.jsxProp);
4693
+ const propExpr = j.memberExpression(propsIdForExpr, j.identifier(p.jsxProp));
4146
4694
  const call = j.callExpression(j.memberExpression(j.identifier(stylesIdentifier), j.identifier(p.fnKey)), [propExpr]);
4147
- if (!destructureProps.includes(p.jsxProp)) destructureProps.push(p.jsxProp);
4148
4695
  if (isPropRequiredInPropsTypeLiteral(d.propsType, p.jsxProp)) styleArgs.push(call);
4149
4696
  else styleArgs.push(j.logicalExpression("&&", j.binaryExpression("!=", propExpr, j.nullLiteral()), call));
4150
4697
  }
4151
4698
  const filterOnlyTransientProps = [];
4699
+ const wrapperOnlyTransientProps = [];
4152
4700
  {
4153
4701
  const findTransientPropsInTypeName = (typeName) => {
4154
4702
  const props = [];
4703
+ const collectFromTypeNode = (typeNode) => {
4704
+ if (!typeNode) return;
4705
+ if (typeNode.type === "TSParenthesizedType") {
4706
+ collectFromTypeNode(typeNode.typeAnnotation);
4707
+ return;
4708
+ }
4709
+ if (typeNode.type === "TSIntersectionType") {
4710
+ for (const t of typeNode.types ?? []) collectFromTypeNode(t);
4711
+ return;
4712
+ }
4713
+ if (typeNode.type === "TSTypeLiteral" && typeNode.members) {
4714
+ for (const member of typeNode.members) if (member.type === "TSPropertySignature" && member.key?.type === "Identifier" && member.key.name.startsWith("$")) props.push(member.key.name);
4715
+ }
4716
+ };
4155
4717
  const interfaceDecl = root.find(j.TSInterfaceDeclaration).filter((p) => p.node.id?.name === typeName);
4156
4718
  if (interfaceDecl.size() > 0) {
4157
4719
  const body = interfaceDecl.get().node.body?.body ?? [];
@@ -4160,19 +4722,21 @@ function emitWrappers(args) {
4160
4722
  const typeAlias = root.find(j.TSTypeAliasDeclaration).filter((p) => p.node.id?.name === typeName);
4161
4723
  if (typeAlias.size() > 0) {
4162
4724
  const typeAnnotation = typeAlias.get().node.typeAnnotation;
4163
- if (typeAnnotation?.type === "TSTypeLiteral" && typeAnnotation.members) {
4164
- for (const member of typeAnnotation.members) if (member.type === "TSPropertySignature" && member.key?.type === "Identifier" && member.key.name.startsWith("$")) props.push(member.key.name);
4165
- }
4725
+ collectFromTypeNode(typeAnnotation);
4166
4726
  }
4167
4727
  return props;
4168
4728
  };
4169
4729
  const explicit = d.propsType;
4170
4730
  let transientProps = [];
4171
4731
  if (explicit?.type === "TSTypeLiteral" && explicit.members) {
4172
- for (const member of explicit.members) if (member.type === "TSPropertySignature" && member.key?.type === "Identifier" && member.key.name.startsWith("$")) transientProps.push(member.key.name);
4732
+ for (const member of explicit.members) if (member.type === "TSPropertySignature" && member.key?.type === "Identifier" && member.key.name.startsWith("$")) {
4733
+ transientProps.push(member.key.name);
4734
+ wrapperOnlyTransientProps.push(member.key.name);
4735
+ }
4173
4736
  } else if (explicit?.type === "TSTypeReference" && explicit.typeName?.type === "Identifier") {
4174
4737
  const typeName = explicit.typeName.name;
4175
4738
  transientProps = findTransientPropsInTypeName(typeName);
4739
+ wrapperOnlyTransientProps.push(...transientProps);
4176
4740
  }
4177
4741
  if (transientProps.length === 0) {
4178
4742
  const funcDecls = root.find(j.FunctionDeclaration).filter((p) => p.node.id?.name === wrappedComponent);
@@ -4201,9 +4765,13 @@ function emitWrappers(args) {
4201
4765
  }
4202
4766
  }
4203
4767
  const propsParamId = j.identifier("props");
4204
- if (functionParamTypeName && emitTypes) propsParamId.typeAnnotation = j.tsTypeAnnotation(j.tsTypeReference(j.identifier(functionParamTypeName)));
4205
- else if (needsGenericPolymorphicType && emitTypes) propsParamId.typeAnnotation = j.tsTypeAnnotation(j.tsTypeReference(j.identifier(propsTypeNameFor(d.localName)), j.tsTypeParameterInstantiation([j.tsTypeReference(j.identifier("C"))])));
4206
- else annotatePropsParam(propsParamId, d.localName);
4768
+ let polymorphicFnTypeParams = null;
4769
+ if (isPolymorphicComponentWrapper && emitTypes) {
4770
+ polymorphicFnTypeParams = j(`function _<C extends React.ElementType = typeof ${wrappedComponent}>() { return null }`).get().node.program.body[0].typeParameters;
4771
+ propsParamId.typeAnnotation = j(`const x: ${propsTypeNameFor(d.localName)}<C> = null`).get().node.program.body[0].declarations[0].id.typeAnnotation;
4772
+ }
4773
+ if (!isPolymorphicComponentWrapper && functionParamTypeName && emitTypes) propsParamId.typeAnnotation = j.tsTypeAnnotation(j.tsTypeReference(j.identifier(functionParamTypeName)));
4774
+ else if (!isPolymorphicComponentWrapper) annotatePropsParam(propsParamId, d.localName);
4207
4775
  const propsId = j.identifier("props");
4208
4776
  const stylexPropsCall = j.callExpression(j.memberExpression(j.identifier("stylex"), j.identifier("props")), styleArgs);
4209
4777
  let jsxTagName;
@@ -4211,42 +4779,70 @@ function emitWrappers(args) {
4211
4779
  const parts = wrappedComponent.split(".");
4212
4780
  jsxTagName = j.jsxMemberExpression(j.jsxIdentifier(parts[0]), j.jsxIdentifier(parts.slice(1).join(".")));
4213
4781
  } else jsxTagName = j.jsxIdentifier(wrappedComponent);
4214
- if (destructureProps.length > 0) {
4782
+ const defaultAttrs = d.attrsInfo?.defaultAttrs ?? [];
4783
+ const staticAttrs = d.attrsInfo?.staticAttrs ?? {};
4784
+ const needsSxVar = allowClassNameProp || allowStyleProp || !!d.inlineStyleProps?.length;
4785
+ const needsDestructure = destructureProps.length > 0 || needsSxVar;
4786
+ const includeChildren = hasJsxChildrenUsage(d.localName);
4787
+ if (needsDestructure) {
4788
+ const childrenId = j.identifier("children");
4789
+ const classNameId = j.identifier("className");
4215
4790
  const styleId = j.identifier("style");
4216
4791
  const restId = j.identifier("rest");
4217
- const patternProps = destructureProps.map((name) => patternProp(name));
4218
- patternProps.push(patternProp("style", styleId));
4219
- patternProps.push(j.restElement(restId));
4220
- const declStmt = j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern(patternProps), propsId)]);
4221
- const explicitPropAttrs = destructureProps.filter((name) => {
4222
- if (!name.startsWith("$")) return false;
4223
- if (filterOnlyTransientProps.includes(name)) return false;
4224
- return root.find(j.TSInterfaceDeclaration).filter((p) => {
4225
- return (p.node.body?.body ?? []).some((member) => member.type === "TSPropertySignature" && member.key?.type === "Identifier" && member.key.name === name);
4226
- }).size() > 0;
4227
- }).map((name) => j.jsxAttribute(j.jsxIdentifier(name), j.jsxExpressionContainer(j.identifier(name))));
4228
- const jsx = j.jsxElement(j.jsxOpeningElement(jsxTagName, [
4229
- ...explicitPropAttrs,
4230
- j.jsxSpreadAttribute(restId),
4231
- j.jsxSpreadAttribute(stylexPropsCall),
4232
- j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(styleId))
4233
- ], true), null, []);
4234
- const funcDecl = j.functionDeclaration(j.identifier(d.localName), [propsParamId], j.blockStatement([declStmt, j.returnStatement(jsx)]));
4235
- if (needsGenericPolymorphicType && emitTypes) funcDecl.typeParameters = j.tsTypeParameterDeclaration([j.tsTypeParameter.from({
4236
- name: "C",
4237
- constraint: j.tsTypeReference(j.tsQualifiedName(j.identifier("React"), j.identifier("ElementType"))),
4238
- default: j.tsTypeQuery(j.identifier(wrappedComponent))
4239
- })]);
4240
- emitted.push(funcDecl);
4792
+ const patternProps = [
4793
+ ...allowClassNameProp ? [patternProp("className", classNameId)] : [],
4794
+ ...includeChildren ? [patternProp("children", childrenId)] : [],
4795
+ ...allowStyleProp ? [patternProp("style", styleId)] : [],
4796
+ ...destructureProps.filter(Boolean).map((name) => patternProp(name)),
4797
+ j.restElement(restId)
4798
+ ];
4799
+ const stmts = [j.variableDeclaration("const", [j.variableDeclarator(j.objectPattern(patternProps), propsId)])];
4800
+ const sxId = j.identifier("sx");
4801
+ if (needsSxVar) stmts.push(j.variableDeclaration("const", [j.variableDeclarator(sxId, stylexPropsCall)]));
4802
+ const openingAttrs = [];
4803
+ for (const a of defaultAttrs) if (typeof a.value === "string") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(a.attrName), j.literal(a.value)));
4804
+ else if (typeof a.value === "number") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(a.attrName), j.jsxExpressionContainer(j.literal(a.value))));
4805
+ else if (typeof a.value === "boolean") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(a.attrName), j.jsxExpressionContainer(j.booleanLiteral(a.value))));
4806
+ for (const [key, value] of Object.entries(staticAttrs)) if (typeof value === "string") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(key), j.literal(value)));
4807
+ else if (typeof value === "number") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(key), j.jsxExpressionContainer(j.literal(value))));
4808
+ else if (typeof value === "boolean") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(key), j.jsxExpressionContainer(j.booleanLiteral(value))));
4809
+ for (const propName of destructureProps) if (propName.startsWith("$") && !filterOnlyTransientProps.includes(propName) && !wrapperOnlyTransientProps.includes(propName)) openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(propName), j.jsxExpressionContainer(j.identifier(propName))));
4810
+ openingAttrs.push(j.jsxSpreadAttribute(restId));
4811
+ openingAttrs.push(j.jsxSpreadAttribute(needsSxVar ? sxId : stylexPropsCall));
4812
+ if (allowClassNameProp) {
4813
+ const mergedClassName = j.callExpression(j.memberExpression(j.callExpression(j.memberExpression(j.arrayExpression([j.memberExpression(sxId, j.identifier("className")), classNameId]), j.identifier("filter")), [j.identifier("Boolean")]), j.identifier("join")), [j.literal(" ")]);
4814
+ openingAttrs.push(j.jsxAttribute(j.jsxIdentifier("className"), j.jsxExpressionContainer(mergedClassName)));
4815
+ }
4816
+ if (allowStyleProp || d.inlineStyleProps && d.inlineStyleProps.length) openingAttrs.push(j.jsxAttribute(j.jsxIdentifier("style"), j.jsxExpressionContainer(j.objectExpression([
4817
+ j.spreadElement(j.memberExpression(sxId, j.identifier("style"))),
4818
+ ...allowStyleProp ? [j.spreadElement(styleId)] : [],
4819
+ ...d.inlineStyleProps && d.inlineStyleProps.length ? d.inlineStyleProps.map((p) => j.property("init", j.identifier(p.prop), p.expr)) : []
4820
+ ]))));
4821
+ const openingEl = j.jsxOpeningElement(jsxTagName, openingAttrs, !includeChildren);
4822
+ const jsx = includeChildren ? j.jsxElement(openingEl, j.jsxClosingElement(jsxTagName), [j.jsxExpressionContainer(childrenId)]) : {
4823
+ type: "JSXElement",
4824
+ openingElement: openingEl,
4825
+ closingElement: null,
4826
+ children: []
4827
+ };
4828
+ stmts.push(j.returnStatement(jsx));
4829
+ const fn = j.functionDeclaration(j.identifier(d.localName), [propsParamId], j.blockStatement(stmts));
4830
+ if (polymorphicFnTypeParams) fn.typeParameters = polymorphicFnTypeParams;
4831
+ emitted.push(fn);
4241
4832
  } else {
4242
- const jsx = j.jsxElement(j.jsxOpeningElement(jsxTagName, [j.jsxSpreadAttribute(propsId), j.jsxSpreadAttribute(stylexPropsCall)], true), null, []);
4243
- const funcDecl = j.functionDeclaration(j.identifier(d.localName), [propsParamId], j.blockStatement([j.returnStatement(jsx)]));
4244
- if (needsGenericPolymorphicType && emitTypes) funcDecl.typeParameters = j.tsTypeParameterDeclaration([j.tsTypeParameter.from({
4245
- name: "C",
4246
- constraint: j.tsTypeReference(j.tsQualifiedName(j.identifier("React"), j.identifier("ElementType"))),
4247
- default: j.tsTypeQuery(j.identifier(wrappedComponent))
4248
- })]);
4249
- emitted.push(funcDecl);
4833
+ const openingAttrs = [];
4834
+ for (const a of defaultAttrs) if (typeof a.value === "string") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(a.attrName), j.literal(a.value)));
4835
+ else if (typeof a.value === "number") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(a.attrName), j.jsxExpressionContainer(j.literal(a.value))));
4836
+ else if (typeof a.value === "boolean") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(a.attrName), j.jsxExpressionContainer(j.booleanLiteral(a.value))));
4837
+ openingAttrs.push(j.jsxSpreadAttribute(propsId));
4838
+ for (const [key, value] of Object.entries(staticAttrs)) if (typeof value === "string") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(key), j.literal(value)));
4839
+ else if (typeof value === "number") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(key), j.jsxExpressionContainer(j.literal(value))));
4840
+ else if (typeof value === "boolean") openingAttrs.push(j.jsxAttribute(j.jsxIdentifier(key), j.jsxExpressionContainer(j.booleanLiteral(value))));
4841
+ openingAttrs.push(j.jsxSpreadAttribute(stylexPropsCall));
4842
+ const jsx = j.jsxElement(j.jsxOpeningElement(jsxTagName, openingAttrs, true), null, []);
4843
+ const fn = j.functionDeclaration(j.identifier(d.localName), [propsParamId], j.blockStatement([j.returnStatement(jsx)]));
4844
+ if (polymorphicFnTypeParams) fn.typeParameters = polymorphicFnTypeParams;
4845
+ emitted.push(fn);
4250
4846
  }
4251
4847
  }
4252
4848
  if (emitted.length > 0) {
@@ -4588,6 +5184,55 @@ function universalSelectorUnsupportedWarning(loc) {
4588
5184
  };
4589
5185
  }
4590
5186
 
5187
+ //#endregion
5188
+ //#region src/internal/dom-attrs.ts
5189
+ /**
5190
+ * DOM attribute filtering (inline-to-intrinsic only)
5191
+ *
5192
+ * When we inline a styled component into a native DOM/SVG element, we remove the component boundary.
5193
+ * That can turn "custom" props (which styled-components might have forwarded) into invalid DOM attrs.
5194
+ *
5195
+ * We keep a small allowlist here to avoid leaking obvious non-DOM props while preserving the props
5196
+ * commonly used in fixtures. This is intentionally conservative and centralized so it's easy to audit.
5197
+ */
5198
+ const KNOWN_SAFE_DOM_ATTRS = new Set([
5199
+ "className",
5200
+ "style",
5201
+ "ref",
5202
+ "key",
5203
+ "id",
5204
+ "title",
5205
+ "role",
5206
+ "tabIndex",
5207
+ "href",
5208
+ "target",
5209
+ "rel",
5210
+ "type",
5211
+ "name",
5212
+ "value",
5213
+ "placeholder",
5214
+ "disabled",
5215
+ "readOnly",
5216
+ "htmlFor",
5217
+ "src",
5218
+ "alt",
5219
+ "width",
5220
+ "height",
5221
+ "viewBox",
5222
+ "d",
5223
+ "x",
5224
+ "y",
5225
+ "rx",
5226
+ "ry",
5227
+ "fill"
5228
+ ]);
5229
+ function isLikelyValidDomAttr(name) {
5230
+ if (KNOWN_SAFE_DOM_ATTRS.has(name)) return true;
5231
+ if (name.startsWith("data-") || name.startsWith("aria-")) return true;
5232
+ if (/^on[A-Z]/.test(name)) return true;
5233
+ return false;
5234
+ }
5235
+
4591
5236
  //#endregion
4592
5237
  //#region src/transform.ts
4593
5238
  /**
@@ -4672,9 +5317,55 @@ function transformWithWarnings(file, api, options) {
4672
5317
  }
4673
5318
  };
4674
5319
  const adapter = options.adapter;
4675
- if (!adapter || typeof adapter.resolveValue !== "function") throw new Error("Adapter must provide resolveValue(ctx) => { expr, imports } | null");
5320
+ assertValidAdapter(adapter, "transform(options) - missing `adapter` (if you run the jscodeshift transform directly, pass options.adapter)");
4676
5321
  const resolverImports = /* @__PURE__ */ new Map();
4677
5322
  let hasChanges = false;
5323
+ let bailDueToUndefinedResolveValue = false;
5324
+ const formatResolveValueContext = (ctx) => {
5325
+ const c = ctx;
5326
+ const kind = c?.kind;
5327
+ if (kind === "theme") return `kind=theme path=${JSON.stringify(String(c?.path ?? ""))}`;
5328
+ if (kind === "cssVariable") {
5329
+ const parts = [`kind=cssVariable name=${JSON.stringify(String(c?.name ?? ""))}`];
5330
+ if (typeof c?.fallback === "string") parts.push(`fallback=${JSON.stringify(c.fallback)}`);
5331
+ if (typeof c?.definedValue === "string") parts.push(`definedValue=${JSON.stringify(c.definedValue)}`);
5332
+ return parts.join(" ");
5333
+ }
5334
+ if (kind === "call") {
5335
+ const args = Array.isArray(c?.args) ? c.args : [];
5336
+ return [
5337
+ "kind=call",
5338
+ `calleeImportedName=${JSON.stringify(String(c?.calleeImportedName ?? ""))}`,
5339
+ `calleeSource=${JSON.stringify(c?.calleeSource ?? null)}`,
5340
+ `callSiteFilePath=${JSON.stringify(String(c?.callSiteFilePath ?? ""))}`,
5341
+ `args=${JSON.stringify(args)}`
5342
+ ].join(" ");
5343
+ }
5344
+ try {
5345
+ return `ctx=${JSON.stringify(ctx)}`;
5346
+ } catch {
5347
+ return `ctx=${String(ctx)}`;
5348
+ }
5349
+ };
5350
+ const resolveValueSafe = (ctx) => {
5351
+ if (bailDueToUndefinedResolveValue) return null;
5352
+ const res = adapter.resolveValue(ctx);
5353
+ if (typeof res === "undefined") {
5354
+ bailDueToUndefinedResolveValue = true;
5355
+ warnings.push({
5356
+ type: "dynamic-node",
5357
+ feature: "adapter-resolveValue",
5358
+ message: [
5359
+ "Adapter.resolveValue returned undefined. This usually means your adapter forgot to return a value.",
5360
+ "Return null to leave a value unresolved, or return { expr, imports } to resolve it.",
5361
+ `Skipping transformation for this file to avoid producing incorrect output.`,
5362
+ `resolveValue was called with: ${formatResolveValueContext(ctx)}`
5363
+ ].join(" ")
5364
+ });
5365
+ return null;
5366
+ }
5367
+ return res;
5368
+ };
4678
5369
  const styledImports = root.find(j.ImportDeclaration, { source: { value: "styled-components" } });
4679
5370
  if (styledImports.length === 0) return {
4680
5371
  code: null,
@@ -4710,7 +5401,8 @@ function transformWithWarnings(file, api, options) {
4710
5401
  let keyframesNames = /* @__PURE__ */ new Set();
4711
5402
  const parseExpr = (exprSource) => {
4712
5403
  try {
4713
- let expr = j(`(${exprSource});`).find(j.ExpressionStatement).nodes()[0]?.expression ?? null;
5404
+ const jParse = api.jscodeshift.withParser("tsx");
5405
+ let expr = jParse(`(${exprSource});`).find(jParse.ExpressionStatement).nodes()[0]?.expression ?? null;
4714
5406
  while (expr?.type === "ParenthesizedExpression") expr = expr.expression;
4715
5407
  if (expr?.extra?.parenthesized) {
4716
5408
  delete expr.extra.parenthesized;
@@ -4728,18 +5420,15 @@ function transformWithWarnings(file, api, options) {
4728
5420
  rewriteCssVarsInStyleObject(v, definedVars, varsToDrop);
4729
5421
  continue;
4730
5422
  }
4731
- if (typeof v === "string") {
4732
- if (!adapter.resolveValue) continue;
4733
- obj[k] = rewriteCssVarsInString({
4734
- raw: v,
4735
- definedVars,
4736
- varsToDrop,
4737
- resolveValue: adapter.resolveValue,
4738
- addImport: (imp) => resolverImports.set(JSON.stringify(imp), imp),
4739
- parseExpr,
4740
- j
4741
- });
4742
- }
5423
+ if (typeof v === "string") obj[k] = rewriteCssVarsInString({
5424
+ raw: v,
5425
+ definedVars,
5426
+ varsToDrop,
5427
+ resolveValue: resolveValueSafe,
5428
+ addImport: (imp) => resolverImports.set(JSON.stringify(imp), imp),
5429
+ parseExpr,
5430
+ j
5431
+ });
4743
5432
  }
4744
5433
  };
4745
5434
  if (keyframesLocal) {
@@ -4908,6 +5597,10 @@ function transformWithWarnings(file, api, options) {
4908
5597
  loc: componentSelectorLoc
4909
5598
  });
4910
5599
  else warnings.push(warning);
5600
+ return {
5601
+ code: null,
5602
+ warnings
5603
+ };
4911
5604
  }
4912
5605
  if (hasSpecificityHack) {
4913
5606
  const warning = {
@@ -5009,7 +5702,7 @@ function transformWithWarnings(file, api, options) {
5009
5702
  j,
5010
5703
  root,
5011
5704
  filePath: file.path,
5012
- resolveValue: adapter.resolveValue,
5705
+ resolveValue: resolveValueSafe,
5013
5706
  importMap,
5014
5707
  warnings,
5015
5708
  resolverImports,
@@ -5027,7 +5720,7 @@ function transformWithWarnings(file, api, options) {
5027
5720
  const resolvedStyleObjects = lowered.resolvedStyleObjects;
5028
5721
  const descendantOverrides = lowered.descendantOverrides;
5029
5722
  const ancestorSelectorParents = lowered.ancestorSelectorParents;
5030
- if (lowered.bail) return {
5723
+ if (lowered.bail || bailDueToUndefinedResolveValue) return {
5031
5724
  code: null,
5032
5725
  warnings
5033
5726
  };
@@ -5094,6 +5787,7 @@ function transformWithWarnings(file, api, options) {
5094
5787
  if (new Set(styledDecls.map((d) => d.localName)).has(obj.name)) componentsWithStaticProps.add(obj.name);
5095
5788
  });
5096
5789
  for (const decl of styledDecls) {
5790
+ if (decl.base.kind === "intrinsic" && (decl.attrsInfo?.conditionalAttrs?.length ?? 0) > 0) decl.needsWrapperComponent = true;
5097
5791
  if (decl.shouldForwardProp) decl.needsWrapperComponent = true;
5098
5792
  if (decl.base.kind === "intrinsic" && decl.withConfig?.componentId) decl.needsWrapperComponent = true;
5099
5793
  if (extendedBy.has(decl.localName) && componentsWithStaticProps.has(decl.localName)) decl.needsWrapperComponent = true;
@@ -5155,11 +5849,7 @@ function transformWithWarnings(file, api, options) {
5155
5849
  decl.supportsExternalStyles = false;
5156
5850
  continue;
5157
5851
  }
5158
- if (!adapter.shouldSupportExternalStyles) {
5159
- decl.supportsExternalStyles = true;
5160
- continue;
5161
- }
5162
- decl.supportsExternalStyles = adapter.shouldSupportExternalStyles({
5852
+ decl.supportsExternalStyles = adapter.shouldSupportExternalStyling({
5163
5853
  filePath: file.path,
5164
5854
  componentName: decl.localName,
5165
5855
  exportName: exportInfo.exportName,
@@ -5258,7 +5948,10 @@ function transformWithWarnings(file, api, options) {
5258
5948
  if (p.parentPath?.node?.type === "CallExpression" && p.parentPath.parentPath?.node?.type === "TaggedTemplateExpression") return false;
5259
5949
  if (p.parentPath?.node?.type === "TemplateLiteral") return false;
5260
5950
  return true;
5261
- }).size() > 0) decl.needsWrapperComponent = true;
5951
+ }).size() > 0) {
5952
+ decl.usedAsValue = true;
5953
+ decl.needsWrapperComponent = true;
5954
+ }
5262
5955
  }
5263
5956
  for (const decl of styledDecls) if (decl.base.kind === "component") {
5264
5957
  const baseDecl = declByLocal.get(decl.base.ident);
@@ -5295,7 +5988,7 @@ function transformWithWarnings(file, api, options) {
5295
5988
  staticPropertyNames.set(componentName, names);
5296
5989
  }
5297
5990
  if (baseComponentNames.has(componentName)) return;
5298
- if (exportedComponents.has(componentName)) {
5991
+ if (exportedComponents.has(componentName) || extendedBy.has(componentName)) {
5299
5992
  const existing = staticPropertyAssignments.get(componentName) ?? [];
5300
5993
  existing.push(p.node);
5301
5994
  staticPropertyAssignments.set(componentName, existing);
@@ -5308,16 +6001,14 @@ function transformWithWarnings(file, api, options) {
5308
6001
  const baseComponentName = declByLocal.get(baseIdent)?.localName ?? baseIdent;
5309
6002
  const baseProps = staticPropertyNames.get(baseComponentName);
5310
6003
  if (!baseProps || baseProps.length === 0) continue;
6004
+ if ((staticPropertyAssignments.get(decl.localName) ?? []).length > 0) continue;
5311
6005
  const inheritanceStatements = [];
5312
6006
  for (const propName of baseProps) {
5313
- const stmt = j.expressionStatement(j.assignmentExpression("=", j.memberExpression(j.identifier(decl.localName), j.identifier(propName)), j.memberExpression(j.identifier(baseComponentName), j.identifier(propName))));
6007
+ const rhs = j(`const __x = (${baseComponentName} as any).${propName};`).get().node.program.body[0].declarations[0].init;
6008
+ const stmt = j.expressionStatement(j.assignmentExpression("=", j.memberExpression(j.identifier(decl.localName), j.identifier(propName)), rhs));
5314
6009
  inheritanceStatements.push(stmt);
5315
6010
  }
5316
- if (inheritanceStatements.length > 0) {
5317
- const existing = staticPropertyAssignments.get(decl.localName) ?? [];
5318
- existing.push(...inheritanceStatements);
5319
- staticPropertyAssignments.set(decl.localName, existing);
5320
- }
6011
+ if (inheritanceStatements.length > 0) staticPropertyAssignments.set(decl.localName, inheritanceStatements);
5321
6012
  }
5322
6013
  for (const decl of styledDecls) {
5323
6014
  const baseIdent = decl.originalBaseIdent ?? (decl.base.kind === "component" ? decl.base.ident : null);
@@ -5528,6 +6219,9 @@ function transformWithWarnings(file, api, options) {
5528
6219
  }
5529
6220
  if (!variantProps.has(n)) {
5530
6221
  if (n.startsWith("$")) continue;
6222
+ if (decl.base.kind === "intrinsic") {
6223
+ if (!isLikelyValidDomAttr(n)) continue;
6224
+ }
5531
6225
  keptAfterVariants.push(attr);
5532
6226
  continue;
5533
6227
  }
@@ -5554,7 +6248,6 @@ function transformWithWarnings(file, api, options) {
5554
6248
  filePath: file.path,
5555
6249
  styledDecls,
5556
6250
  wrapperNames,
5557
- expressionAsWrapperNames,
5558
6251
  patternProp,
5559
6252
  exportedComponents,
5560
6253
  stylesIdentifier
@@ -5693,6 +6386,10 @@ function toSuffixFromProp(propName) {
5693
6386
  const raw = propName.startsWith("$") ? propName.slice(1) : propName;
5694
6387
  if (!raw) return "Variant";
5695
6388
  const trimmed = raw.trim();
6389
+ if (trimmed.includes("&&")) {
6390
+ const parts = trimmed.split("&&").map((s) => s.trim()).filter(Boolean);
6391
+ if (parts.length) return parts.map((p) => toSuffixFromProp(p)).join("");
6392
+ }
5696
6393
  if (trimmed.startsWith("!")) return `Not${toSuffixFromProp(trimmed.slice(1).trim().replace(/^\(|\)$/g, ""))}`;
5697
6394
  const eq = trimmed.includes("!==") ? "!==" : trimmed.includes("===") ? "===" : null;
5698
6395
  if (eq) {