styled-components-to-stylex-codemod 0.0.9 → 0.0.10

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.
@@ -0,0 +1,452 @@
1
+ //#region src/adapter.d.ts
2
+ /**
3
+ * Adapter entry point for customizing the codemod.
4
+ * Core concepts: value resolution hooks and adapter validation.
5
+ */
6
+ type ThemeResolveContext = {
7
+ kind: "theme";
8
+ path: string;
9
+ /**
10
+ * Absolute path of the file currently being transformed.
11
+ * Useful for adapter logic that wants to branch by caller file.
12
+ */
13
+ filePath: string;
14
+ /**
15
+ * Source location (line/column) of the expression being resolved.
16
+ * Useful for error reporting.
17
+ */
18
+ loc?: {
19
+ line: number;
20
+ column: number;
21
+ };
22
+ };
23
+ type CssVariableResolveContext = {
24
+ kind: "cssVariable";
25
+ name: string;
26
+ fallback?: string;
27
+ definedValue?: string;
28
+ /**
29
+ * Absolute path of the file currently being transformed.
30
+ * Useful for adapter logic that wants to branch by caller file.
31
+ */
32
+ filePath: string;
33
+ /**
34
+ * Source location (line/column) of the expression being resolved.
35
+ * Useful for error reporting.
36
+ */
37
+ loc?: {
38
+ line: number;
39
+ column: number;
40
+ };
41
+ };
42
+ type ImportedValueResolveContext = {
43
+ kind: "importedValue";
44
+ /**
45
+ * Imported name of the binding used in the interpolation.
46
+ * Example: `import { zIndex as z } from "./lib"` -> importedName: "zIndex"
47
+ */
48
+ importedName: string;
49
+ /**
50
+ * Import source for the binding.
51
+ */
52
+ source: ImportSource;
53
+ /**
54
+ * Member path from the imported binding (if any).
55
+ * Example: `zIndex.popover` -> "popover"
56
+ */
57
+ path?: string;
58
+ /**
59
+ * Absolute path of the file currently being transformed.
60
+ * Useful for adapter logic that wants to branch by caller file.
61
+ */
62
+ filePath: string;
63
+ /**
64
+ * Source location (line/column) of the expression being resolved.
65
+ * Useful for error reporting.
66
+ */
67
+ loc?: {
68
+ line: number;
69
+ column: number;
70
+ };
71
+ };
72
+ type CallResolveContext = {
73
+ /**
74
+ * Absolute path of the file currently being transformed.
75
+ * Useful for adapter logic that wants to branch by caller file.
76
+ */
77
+ callSiteFilePath: string;
78
+ /**
79
+ * Imported name when the callee is a named import (including aliases).
80
+ * Example: `import { transitionSpeed as ts } ...; ts("x")` -> "transitionSpeed"
81
+ */
82
+ calleeImportedName: string;
83
+ /**
84
+ * Import source for this call: either an absolute file path (relative imports)
85
+ * or the module specifier (package imports).
86
+ */
87
+ calleeSource: {
88
+ kind: "absolutePath";
89
+ value: string;
90
+ } | {
91
+ kind: "specifier";
92
+ value: string;
93
+ };
94
+ /**
95
+ * Call arguments.
96
+ * - literals are surfaced precisely
97
+ * - theme member access can be surfaced as `{ kind: "theme", path }`
98
+ * - everything else is `unknown`
99
+ */
100
+ args: Array<{
101
+ kind: "literal";
102
+ value: string | number | boolean | null;
103
+ } | {
104
+ kind: "theme";
105
+ path: string;
106
+ } | {
107
+ kind: "unknown";
108
+ }>;
109
+ /**
110
+ * Source location (line/column) of the call expression being resolved.
111
+ * Useful for error reporting.
112
+ */
113
+ loc?: {
114
+ line: number;
115
+ column: number;
116
+ };
117
+ /**
118
+ * CSS property being set (when available).
119
+ * Useful for adapters to return different results for directional properties.
120
+ * Example: "border-left", "border", "color"
121
+ */
122
+ cssProperty?: string;
123
+ };
124
+ /**
125
+ * Context for `adapter.resolveValue(...)` (theme + css variables + imported values).
126
+ *
127
+ * Helper calls are handled separately via `adapter.resolveCall(...)`.
128
+ */
129
+ type ResolveValueContext = ThemeResolveContext | CssVariableResolveContext | ImportedValueResolveContext;
130
+ /**
131
+ * Result for `adapter.resolveValue(...)` (theme + css variables + imported values).
132
+ */
133
+ type ResolveValueResult = {
134
+ /**
135
+ * JS expression string to inline into generated output.
136
+ * Example: `vars.spacingSm` or `calcVars.baseSize`
137
+ */
138
+ expr: string;
139
+ /**
140
+ * Import statements required by `expr`.
141
+ * These are rendered and merged into the file by the codemod.
142
+ */
143
+ imports: ImportSpec[];
144
+ /**
145
+ * If true, the transformer should drop the corresponding `--name: ...` definition
146
+ * from the emitted style object (useful when replacing with StyleX vars).
147
+ *
148
+ * Note: Only meaningful for `{ kind: "cssVariable" }`.
149
+ */
150
+ dropDefinition?: boolean;
151
+ /**
152
+ * Disambiguates how the resolved expression is used:
153
+ * - "props": a StyleX style object suitable for passing to `stylex.props(...)`.
154
+ * Use this when resolving imported styled component mixins to their StyleX equivalent.
155
+ * - undefined (default): a value that can be used inside `stylex.create(...)`.
156
+ *
157
+ * Note: Only meaningful for `{ kind: "importedValue" }`.
158
+ */
159
+ usage?: "props";
160
+ };
161
+ type CallResolveResult = {
162
+ /**
163
+ * JS expression string to inline into generated output.
164
+ *
165
+ * The codemod determines how to use this expression based on context:
166
+ * - If called with a CSS property (e.g., `border: ${helper()}`) → used as a CSS value
167
+ * - If called without a CSS property (e.g., `${helper()}`) → used as a StyleX style object
168
+ *
169
+ * Use `ctx.cssProperty` to check the context and return the appropriate expression.
170
+ *
171
+ * Example (CSS value): `\`1px solid \${$colors.labelMuted}\``
172
+ * Example (StyleX reference): `helpers.truncate`
173
+ */
174
+ expr: string;
175
+ /**
176
+ * Import statements required by `expr`.
177
+ * These are rendered and merged into the file by the codemod.
178
+ */
179
+ imports: ImportSpec[];
180
+ /**
181
+ * Disambiguates how the resolved expression is used:
182
+ * - `"create"`: Use as a CSS value in `stylex.create()` property values
183
+ * - `"props"`: Use as a StyleX styles reference in `stylex.props()`
184
+ *
185
+ * When not specified, the codemod infers from context:
186
+ * - If `cssProperty` exists → treated as `"create"`
187
+ * - If `cssProperty` doesn't exist → treated as `"props"`
188
+ *
189
+ * Use this field when the default inference is incorrect, such as when a helper
190
+ * returns a StyleX styles object even when used with a CSS property like `border:`.
191
+ */
192
+ usage?: "create" | "props";
193
+ /**
194
+ * Optional raw CSS text for helpers that return CSS declaration blocks.
195
+ *
196
+ * When provided alongside `usage: "props"`, the codemod can expand the CSS
197
+ * declarations for pseudo-selector wrapping. Without this, the codemod treats
198
+ * the resolved expression as opaque and cannot wrap individual properties
199
+ * inside pseudo selectors like `:hover`.
200
+ *
201
+ * Example: `"white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"`
202
+ */
203
+ cssText?: string;
204
+ };
205
+ type ImportSource = {
206
+ kind: "absolutePath";
207
+ value: string;
208
+ } | {
209
+ kind: "specifier";
210
+ value: string;
211
+ };
212
+ type ImportSpec = {
213
+ from: ImportSource;
214
+ names: Array<{
215
+ imported: string;
216
+ local?: string;
217
+ }>;
218
+ };
219
+ /**
220
+ * Context for `adapter.resolveSelector(...)`.
221
+ *
222
+ * This handles patterns like `${screenSize.phone} { ... }` where an imported
223
+ * value is used as a CSS selector (typically a media query helper).
224
+ */
225
+ type SelectorResolveContext = {
226
+ kind: "selectorInterpolation";
227
+ /**
228
+ * Imported name of the binding used in the interpolation.
229
+ * Example: `import { screenSize } from "./lib"` -> importedName: "screenSize"
230
+ */
231
+ importedName: string;
232
+ /**
233
+ * Import source for the binding.
234
+ */
235
+ source: ImportSource;
236
+ /**
237
+ * Member path from the imported binding (if any).
238
+ * Example: `screenSize.phone` -> "phone"
239
+ */
240
+ path?: string;
241
+ /**
242
+ * Absolute path of the file currently being transformed.
243
+ */
244
+ filePath: string;
245
+ /**
246
+ * Source location (line/column) of the selector interpolation being resolved.
247
+ * Useful for error reporting.
248
+ */
249
+ loc?: {
250
+ line: number;
251
+ column: number;
252
+ };
253
+ };
254
+ /**
255
+ * Result for `adapter.resolveSelector(...)`.
256
+ */
257
+ type SelectorResolveResult = {
258
+ /**
259
+ * The kind of selector resolved.
260
+ * Currently only "media" is supported.
261
+ */
262
+ kind: "media";
263
+ /**
264
+ * JS expression to use as the computed property key.
265
+ * Should reference a `defineConsts` value for media queries.
266
+ * Example: "breakpoints.phone"
267
+ */
268
+ expr: string;
269
+ /**
270
+ * Import statements required by `expr`.
271
+ * Example: [{ from: { kind: "specifier", value: "./breakpoints.stylex" }, names: [{ imported: "breakpoints" }] }]
272
+ */
273
+ imports: ImportSpec[];
274
+ };
275
+ interface ExternalInterfaceContext {
276
+ /** Absolute path of the file being transformed */
277
+ filePath: string;
278
+ /** Local name of the styled component */
279
+ componentName: string;
280
+ /** The export name (may differ from componentName for renamed exports) */
281
+ exportName: string;
282
+ /** Whether it's a default export */
283
+ isDefaultExport: boolean;
284
+ }
285
+ /**
286
+ * Result type for `adapter.externalInterface(...)`.
287
+ *
288
+ * - `null` → no external interface support (neither styles nor `as`)
289
+ * - `{ styles: true }` → enable className/style support AND polymorphic `as` prop
290
+ * - `{ styles: false, as: true }` → enable only polymorphic `as` prop (no style merging)
291
+ * - `{ styles: false, as: false }` → equivalent to `null`
292
+ *
293
+ * Note: When `styles: true`, the `as` prop is always enabled because the style
294
+ * merging implementation requires polymorphic rendering support.
295
+ */
296
+ type ExternalInterfaceResult = {
297
+ styles: true;
298
+ } | {
299
+ styles: false;
300
+ as: boolean;
301
+ } | null;
302
+ /**
303
+ * Configuration for a custom style merger function that combines stylex.props()
304
+ * results with external className/style props.
305
+ *
306
+ * When configured, generates cleaner output:
307
+ * `{...stylexProps(styles.foo, className, style)}`
308
+ * instead of the verbose pattern:
309
+ * `{...sx} className={[sx.className, className].filter(Boolean).join(" ")} style={{...sx.style, ...style}}`
310
+ */
311
+ interface StyleMergerConfig {
312
+ /**
313
+ * Function name to use for merging (e.g., "stylexProps" or "mergeStylexProps").
314
+ */
315
+ functionName: string;
316
+ /**
317
+ * Import source for the merger function.
318
+ * Example: `{ kind: "specifier", value: "@company/ui-utils" }`
319
+ */
320
+ importSource: ImportSource;
321
+ }
322
+ interface Adapter {
323
+ /**
324
+ * Resolver for theme paths + CSS variables + imported values.
325
+ *
326
+ * Return:
327
+ * - `{ expr, imports }` for theme, css variables, and imported values.
328
+ * - Optionally return `{ dropDefinition: true }` for css variables to remove the local `--x: ...` definition.
329
+ * - `undefined` to bail/skip the file (for cssVariable: keeps the original `var(...)` unchanged)
330
+ */
331
+ resolveValue: (context: ResolveValueContext) => ResolveValueResult | undefined;
332
+ /**
333
+ * Resolver for helper calls found inside template interpolations.
334
+ *
335
+ * The codemod determines how to use the result based on context:
336
+ * - If `ctx.cssProperty` exists (e.g., `border: ${helper()}`) → result is used as a CSS value
337
+ * - If `ctx.cssProperty` is undefined (e.g., `${helper()}`) → result is used as a StyleX style object
338
+ *
339
+ * Use `ctx.cssProperty` to return the appropriate expression for the context.
340
+ *
341
+ * Return:
342
+ * - `{ expr, imports }` with the resolved expression
343
+ * - `undefined` to bail/skip the file
344
+ */
345
+ resolveCall: (context: CallResolveContext) => CallResolveResult | undefined;
346
+ /**
347
+ * Resolver for interpolations used in selector position.
348
+ *
349
+ * This handles patterns like `${screenSize.phone} { ... }` where an imported
350
+ * value is used as a CSS selector (typically a media query helper).
351
+ *
352
+ * Return:
353
+ * - `{ kind: "media", expr, imports }` when the interpolation resolves to a media query
354
+ * - `undefined` to bail/skip the file
355
+ */
356
+ resolveSelector: (context: SelectorResolveContext) => SelectorResolveResult | undefined;
357
+ /**
358
+ * Called for exported styled components to determine their external interface.
359
+ *
360
+ * Return:
361
+ * - `null` → no external interface (neither styles nor `as`)
362
+ * - `{ styles: true }` → accept className/style props AND polymorphic `as` prop
363
+ * - `{ styles: false, as: true }` → accept only polymorphic `as` prop
364
+ * - `{ styles: false, as: false }` → equivalent to `null`
365
+ */
366
+ externalInterface: (context: ExternalInterfaceContext) => ExternalInterfaceResult;
367
+ /**
368
+ * Custom merger function for className/style combining.
369
+ * When provided, generates cleaner output using this function instead of
370
+ * the verbose className/style merging pattern.
371
+ * Set to `null` to use the verbose pattern (default).
372
+ *
373
+ * Expected merger function signature:
374
+ * ```typescript
375
+ * function merger(
376
+ * styles: StyleXStyles | StyleXStyles[],
377
+ * className?: string,
378
+ * style?: React.CSSProperties
379
+ * ): { className?: string; style?: React.CSSProperties }
380
+ * ```
381
+ */
382
+ styleMerger: StyleMergerConfig | null;
383
+ }
384
+ /**
385
+ * Helper for nicer user authoring + type inference.
386
+ *
387
+ * `defineAdapter(...)` also performs runtime validation (helpful for JS consumers)
388
+ * and will throw a descriptive error message if the adapter shape is invalid.
389
+ *
390
+ * Usage:
391
+ * export default defineAdapter({
392
+ * resolveValue(ctx) {
393
+ * if (ctx.kind === "theme") {
394
+ * return {
395
+ * expr: `tokens.${ctx.path}`,
396
+ * imports: [
397
+ * { from: { kind: "specifier", value: "./tokens" }, names: [{ imported: "tokens" }] },
398
+ * ],
399
+ * };
400
+ * }
401
+ * // Return undefined to bail/skip the file
402
+ * },
403
+ *
404
+ * resolveCall(ctx) {
405
+ * // Resolve helper calls inside template interpolations.
406
+ * // Use ctx.cssProperty to determine context:
407
+ * // - If ctx.cssProperty exists → return a CSS value expression
408
+ * // - If ctx.cssProperty is undefined → return a StyleX style object reference
409
+ * // Return { expr, imports } or undefined to bail/skip the file
410
+ * void ctx;
411
+ * },
412
+ *
413
+ * resolveSelector(ctx) {
414
+ * // Resolve imported values used in selector position (e.g., media query helpers).
415
+ * // Return:
416
+ * // - { kind: "media", expr, imports } for media queries (e.g., breakpoints.phone)
417
+ * // - undefined to bail/skip the file
418
+ * void ctx;
419
+ * },
420
+ *
421
+ * // Configure external interface for exported components
422
+ * externalInterface(ctx) {
423
+ * // Example: Enable styles (and `as`) for shared components folder
424
+ * if (ctx.filePath.includes("/shared/components/")) {
425
+ * return { styles: true };
426
+ * }
427
+ * return null;
428
+ * },
429
+ *
430
+ * // Optional: provide a custom merger, or use `null` for the default verbose merge output
431
+ * styleMerger: null,
432
+ * });
433
+ */
434
+ declare function defineAdapter(adapter: Adapter): Adapter;
435
+ //#endregion
436
+ //#region src/internal/logger.d.ts
437
+ type Severity = "info" | "warning" | "error";
438
+ type WarningType = "`css` helper function switch must return css templates in all branches" | "`css` helper usage as a function call (css(...)) is not supported" | "`css` helper used outside of a styled component template cannot be statically transformed" | "Adapter helper call in border interpolation did not resolve to a single CSS value" | "Adapter resolveCall returned an unparseable styles expression" | "Adapter resolveCall returned an unparseable value expression" | "Adapter resolveCall returned StyleX styles for helper call where a CSS value was expected" | "Adapter resolveCall returned undefined for helper call" | "Adapter resolved StyleX styles cannot be applied under nested selectors/at-rules" | "Adapter resolved StyleX styles inside pseudo selector but did not provide cssText for property expansion — add cssText to resolveCall result to enable pseudo-wrapping" | 'Adapter resolveCall cssText could not be parsed as CSS declarations — expected semicolon-separated property: value pairs (e.g. "white-space: nowrap; overflow: hidden;")' | "Adapter resolveValue returned an unparseable value expression" | "Adapter resolveValue returned undefined for imported value" | "Arrow function: body is not a recognized pattern (expected ternary, logical, call, or member expression)" | "Arrow function: conditional branches could not be resolved to static or theme values" | "Arrow function: helper call body is not supported" | "Arrow function: indexed theme lookup pattern not matched" | "Arrow function: logical expression pattern not supported" | "Arrow function: prop access cannot be converted to style function for this CSS property" | "Arrow function: theme access path could not be resolved" | "Component selectors like `${OtherComponent}:hover &` are not directly representable in StyleX. Manual refactor is required" | "Conditional `css` block: !important is not supported in StyleX" | "Conditional `css` block: @-rules (e.g., @media, @supports) are not supported" | "Conditional `css` block: failed to parse expression" | "Conditional `css` block: missing CSS property name" | "Conditional `css` block: missing interpolation expression" | "Conditional `css` block: mixed static/dynamic values with non-theme expressions cannot be safely transformed" | "Conditional `css` block: multiple interpolation slots in a single property value" | "Conditional `css` block: ternary branch value could not be resolved (imported values require adapter support)" | "Conditional `css` block: ternary expressions inside pseudo selectors are not supported" | "Conditional `css` block: unsupported selector" | "Directional border helper styles are not supported" | "createGlobalStyle is not supported in StyleX. Global styles should be handled separately (e.g., in a CSS file or using CSS reset libraries)" | "Dynamic styles inside pseudo elements (::before/::after) are not supported by StyleX. See https://github.com/facebook/stylex/issues/1396" | "Failed to parse theme expressions" | "Heterogeneous background values (mix of gradients and colors) not currently supported" | "Higher-order styled factory wrappers (e.g. hoc(styled)) are not supported" | "Imported CSS helper mixins: cannot determine inherited properties for correct pseudo selector handling" | "Styled-components specificity hacks like `&&` / `&&&` are not representable in StyleX" | "Theme-dependent block-level conditional could not be fully resolved (branches may contain dynamic interpolations)" | "Theme-dependant call expression could not be resolved (e.g. theme helper calls like theme.highlight() are not supported)" | "Theme value with fallback (props.theme.X ?? / || default) cannot be resolved statically — use adapter.resolveValue to map theme paths to StyleX tokens" | "Theme-dependent nested prop access requires a project-specific theme source (e.g. useTheme())" | "Theme-dependent template literals require a project-specific theme source (e.g. useTheme())" | "Theme prop overrides on styled components are not supported" | "Universal selectors (`*`) are currently unsupported" | "Unsupported call expression (expected imported helper(...) or imported helper(...)(...))" | "Unsupported conditional test in shouldForwardProp" | "Unsupported shouldForwardProp pattern (only !prop.startsWith(), ![].includes(prop), and prop !== are supported)" | "Unsupported interpolation: arrow function" | "Unsupported interpolation: call expression" | "Unsupported interpolation: identifier" | "Unsupported interpolation: member expression" | "Unsupported interpolation: property" | "Unsupported interpolation: unknown" | "Unsupported nested conditional interpolation" | "Unsupported prop-based inline style expression cannot be safely inlined" | "Unsupported prop-based inline style props.theme access is not supported" | "Unsupported selector interpolation: imported value in selector position" | "Unsupported selector: class selector" | "Unsupported selector: comma-separated selectors must all be simple pseudos" | "Unsupported selector: descendant pseudo selector (space before pseudo)" | "Unsupported selector: descendant/child/sibling selector" | "Unsupported selector: interpolated pseudo selector" | "Unsupported selector: sibling combinator" | "Unsupported selector: unknown component selector" | "Unsupported css`` mixin: after-base mixin style is not a plain object" | "Unsupported css`` mixin: nested contextual conditions in after-base mixin" | "Unsupported css`` mixin: cannot infer base default for after-base contextual override (base value is non-literal)" | "css`` helper function interpolation references closure variable that cannot be hoisted" | "Using styled-components components as mixins is not supported; use css`` mixins or strings instead";
439
+ interface WarningLog {
440
+ severity: Severity;
441
+ type: WarningType;
442
+ loc: {
443
+ line: number;
444
+ column: number;
445
+ } | null | undefined;
446
+ context?: Record<string, unknown>;
447
+ }
448
+ interface CollectedWarning extends WarningLog {
449
+ filePath: string;
450
+ }
451
+ //#endregion
452
+ export { defineAdapter as i, WarningLog as n, Adapter as r, CollectedWarning as t };
@@ -1,9 +1,8 @@
1
- import { n as WarningLog, r as Adapter } from "./logger-CNmtK-uJ.mjs";
1
+ import { n as WarningLog, r as Adapter } from "./logger-DC-1uogs.mjs";
2
2
  import "stylis";
3
3
  import { API, FileInfo, Options } from "jscodeshift";
4
4
 
5
5
  //#region src/internal/transform-types.d.ts
6
-
7
6
  /**
8
7
  * Result of the transform including any log entries
9
8
  */