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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,7 +29,7 @@ import {
29
29
  const adapter = defineAdapter({
30
30
  resolveValue(ctx) {
31
31
  if (ctx.kind === "theme") {
32
- // Called for patterns like: ${(props) => props.theme.colors.primary}
32
+ // Called for patterns like: ${(props) => props.theme.color.primary}
33
33
  // `ctx.path` is the dotted path after `theme.`
34
34
  const varName = ctx.path.replace(/\./g, "_");
35
35
  return {
@@ -88,43 +88,39 @@ const adapter = defineAdapter({
88
88
  };
89
89
  }
90
90
 
91
- if (ctx.kind === "call") {
92
- // Called for template interpolations like: ${transitionSpeed("slowTransition")}
93
- // `calleeImportedName` is the imported symbol name (works even with aliasing).
94
- // `calleeSource` tells you where it came from:
95
- // - { kind: "absolutePath", value: "/abs/path" } for relative imports
96
- // - { kind: "specifier", value: "some-package/foo" } for package imports
97
-
98
- if (ctx.calleeImportedName !== "transitionSpeed") {
99
- return null;
100
- }
101
-
102
- // If you need to scope resolution to a particular module, you can use:
103
- // - ctx.calleeSource
104
-
105
- const arg0 = ctx.args[0];
106
- const key =
107
- arg0?.kind === "literal" && typeof arg0.value === "string"
108
- ? arg0.value
109
- : null;
110
- if (!key) {
111
- return null;
112
- }
91
+ return null;
92
+ },
113
93
 
114
- return {
115
- expr: `transitionSpeedVars.${key}`,
116
- imports: [
117
- {
118
- from: { kind: "specifier", value: "./lib/helpers.stylex" },
119
- names: [
120
- { imported: "transitionSpeed", local: "transitionSpeedVars" },
121
- ],
122
- },
123
- ],
124
- };
94
+ resolveCall(ctx) {
95
+ // Called for template interpolations like: ${transitionSpeed("slowTransition")}
96
+ // `calleeImportedName` is the imported symbol name (works even with aliasing).
97
+ // `calleeSource` tells you where it came from:
98
+ // - { kind: "absolutePath", value: "/abs/path" } for relative imports
99
+ // - { kind: "specifier", value: "some-package/foo" } for package imports
100
+
101
+ const arg0 = ctx.args[0];
102
+ const key =
103
+ arg0?.kind === "literal" && typeof arg0.value === "string"
104
+ ? arg0.value
105
+ : null;
106
+ if (ctx.calleeImportedName !== "transitionSpeed" || !key) {
107
+ return null;
125
108
  }
126
109
 
127
- return null;
110
+ return {
111
+ usage: "create",
112
+ expr: `transitionSpeedVars.${key}`,
113
+ imports: [
114
+ {
115
+ from: { kind: "specifier", value: "./lib/helpers.stylex" },
116
+ names: [{ imported: "transitionSpeed", local: "transitionSpeedVars" }],
117
+ },
118
+ ],
119
+ };
120
+ },
121
+
122
+ shouldSupportExternalStyling() {
123
+ return false;
128
124
  },
129
125
  });
130
126
 
@@ -145,7 +141,7 @@ Adapters are the main extension point. They let you control:
145
141
 
146
142
  - how theme paths and CSS variables are turned into StyleX-compatible JS values (`resolveValue`)
147
143
  - what extra imports to inject into transformed files (returned from `resolveValue`)
148
- - how helper calls are resolved (via `resolveValue({ kind: "call", ... })`)
144
+ - how helper calls are resolved (via `resolveCall({ ... })` returning `usage: "props" | "create"`; `null`/`undefined` now bails)
149
145
  - which exported components should support external className/style extension (`shouldSupportExternalStyling`)
150
146
  - how className/style merging is handled for components accepting external styling (`styleMerger`)
151
147
 
@@ -229,7 +225,9 @@ When the codemod encounters an interpolation inside a styled template literal, i
229
225
 
230
226
  - theme access (`props.theme...`) via `resolveValue({ kind: "theme", path })`
231
227
  - prop access (`props.foo`) and conditionals (`props.foo ? "a" : "b"`, `props.foo && "color: red;"`)
232
- - simple helper calls (`transitionSpeed("slowTransition")`) via `resolveValue({ kind: "call", calleeImportedName, calleeSource, args, ... })`
228
+ - simple helper calls (`transitionSpeed("slowTransition")`) via `resolveCall({ ... })` returning `usage: "create"`
229
+ - style helper calls (returning StyleX styles) via `resolveCall({ ... })` returning `usage: "props"`; these are emitted as extra `stylex.props(...)` args
230
+ - if `resolveCall` returns `null` or `undefined`, the transform now **bails the file** and logs a warning
233
231
  - helper calls applied to prop values (e.g. `shadow(props.shadow)`) by emitting a StyleX style function that calls the helper at runtime
234
232
  - conditional CSS blocks via ternary (e.g. `props.$dim ? "opacity: 0.5;" : ""`)
235
233
 
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { i as defineAdapter, r as Adapter, t as CollectedWarning } from "./logger-BS4Evg0n.mjs";
1
+ import { i as defineAdapter, r as Adapter, t as CollectedWarning } from "./logger-CNmtK-uJ.mjs";
2
2
 
3
3
  //#region src/run.d.ts
4
4
  interface RunTransformOptions {
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as assertValidAdapter, r as describeValue, t as Logger } from "./logger-Dlnt1fYP.mjs";
1
+ import { n as assertValidAdapter, r as describeValue, t as Logger } from "./logger-DKelw2HS.mjs";
2
2
  import { run } from "jscodeshift/src/Runner.js";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { dirname, join } from "node:path";
@@ -13,6 +13,9 @@ import { spawn } from "node:child_process";
13
13
  /**
14
14
  * Helper for nicer user authoring + type inference.
15
15
  *
16
+ * `defineAdapter(...)` also performs runtime validation (helpful for JS consumers)
17
+ * and will throw a descriptive error message if the adapter shape is invalid.
18
+ *
16
19
  * Usage:
17
20
  * export default defineAdapter({
18
21
  * resolveValue(ctx) {
@@ -27,11 +30,24 @@ import { spawn } from "node:child_process";
27
30
  * return null;
28
31
  * },
29
32
  *
33
+ * resolveCall(ctx) {
34
+ * // Resolve helper calls inside template interpolations.
35
+ * // Return:
36
+ * // - { usage: "props", expr, imports } for StyleX styles (usable in stylex.props)
37
+ * // - { usage: "create", expr, imports } for a single value (usable in stylex.create)
38
+ * // - null to leave the call unresolved
39
+ * void ctx;
40
+ * return null;
41
+ * },
42
+ *
30
43
  * // Enable className/style/rest support for exported components
31
44
  * shouldSupportExternalStyling(ctx) {
32
45
  * // Example: Enable for all exported components in a shared components folder
33
46
  * return ctx.filePath.includes("/shared/components/");
34
47
  * },
48
+ *
49
+ * // Optional: provide a custom merger, or use `null` for the default verbose merge output
50
+ * styleMerger: null,
35
51
  * });
36
52
  */
37
53
  function defineAdapter(adapter) {
@@ -92,20 +108,32 @@ async function runTransform(options) {
92
108
  const { files, dryRun = false, print = false, parser = "tsx", formatterCommand } = options;
93
109
  const adapter = options.adapter;
94
110
  assertValidAdapter(adapter, "runTransform(options)");
111
+ const resolveValueWithLogging = (ctx) => {
112
+ try {
113
+ return adapter.resolveValue(ctx);
114
+ } catch (e) {
115
+ const msg = `adapter.resolveValue threw an error: ${e instanceof Error ? e.message : String(e)}`;
116
+ const filePath = ctx.filePath ?? "<unknown>";
117
+ Logger.logError(msg, filePath, void 0, ctx);
118
+ throw e;
119
+ }
120
+ };
121
+ const resolveCallWithLogging = (ctx) => {
122
+ try {
123
+ return adapter.resolveCall(ctx);
124
+ } catch (e) {
125
+ const msg = `adapter.resolveCall threw an error: ${e instanceof Error ? e.message : String(e)}`;
126
+ Logger.logError(msg, ctx.callSiteFilePath, void 0, ctx);
127
+ throw e;
128
+ }
129
+ };
95
130
  const adapterWithLogging = {
96
131
  styleMerger: adapter.styleMerger,
97
132
  shouldSupportExternalStyling(ctx) {
98
133
  return adapter.shouldSupportExternalStyling(ctx);
99
134
  },
100
- resolveValue(ctx) {
101
- try {
102
- return adapter.resolveValue(ctx);
103
- } catch (e) {
104
- const msg = `adapter.resolveValue threw an error: ${e instanceof Error ? e.message : String(e)}`;
105
- Logger.error(msg, ctx);
106
- throw e;
107
- }
108
- }
135
+ resolveValue: resolveValueWithLogging,
136
+ resolveCall: resolveCallWithLogging
109
137
  };
110
138
  const patterns = Array.isArray(files) ? files : [files];
111
139
  const filePaths = [];
@@ -2,16 +2,27 @@
2
2
  /**
3
3
  * Adapter - Single user entry point for customizing the codemod.
4
4
  */
5
- type ResolveContext = {
5
+ type ThemeResolveContext = {
6
6
  kind: "theme";
7
7
  path: string;
8
- } | {
8
+ /**
9
+ * Absolute path of the file currently being transformed.
10
+ * Useful for adapter logic that wants to branch by caller file.
11
+ */
12
+ filePath?: string;
13
+ };
14
+ type CssVariableResolveContext = {
9
15
  kind: "cssVariable";
10
16
  name: string;
11
17
  fallback?: string;
12
18
  definedValue?: string;
13
- } | {
14
- kind: "call";
19
+ /**
20
+ * Absolute path of the file currently being transformed.
21
+ * Useful for adapter logic that wants to branch by caller file.
22
+ */
23
+ filePath?: string;
24
+ };
25
+ type CallResolveContext = {
15
26
  /**
16
27
  * Absolute path of the file currently being transformed.
17
28
  * Useful for adapter logic that wants to branch by caller file.
@@ -43,7 +54,16 @@ type ResolveContext = {
43
54
  kind: "unknown";
44
55
  }>;
45
56
  };
46
- type ResolveResult = {
57
+ /**
58
+ * Context for `adapter.resolveValue(...)` (theme + css variables).
59
+ *
60
+ * Helper calls are handled separately via `adapter.resolveCall(...)`.
61
+ */
62
+ type ResolveValueContext = ThemeResolveContext | CssVariableResolveContext;
63
+ /**
64
+ * Result for `adapter.resolveValue(...)` (theme + css variables).
65
+ */
66
+ type ResolveValueResult = {
47
67
  /**
48
68
  * JS expression string to inline into generated output.
49
69
  * Example: `vars.spacingSm` or `calcVars.baseSize`
@@ -57,9 +77,30 @@ type ResolveResult = {
57
77
  /**
58
78
  * If true, the transformer should drop the corresponding `--name: ...` definition
59
79
  * from the emitted style object (useful when replacing with StyleX vars).
80
+ *
81
+ * Note: Only meaningful for `{ kind: "cssVariable" }`.
60
82
  */
61
83
  dropDefinition?: boolean;
62
84
  };
85
+ type CallResolveResult = {
86
+ /**
87
+ * Disambiguates how the resolved expression is used:
88
+ * - "props": a StyleX style object suitable for passing to `stylex.props(...)`.
89
+ * - "create": a value that can be used inside `stylex.create(...)` (e.g. tokens/vars).
90
+ */
91
+ usage: "props" | "create";
92
+ /**
93
+ * JS expression string to inline into generated output.
94
+ * Example (value): `vars.spacingSm`
95
+ * Example (styles): `borders.labelMuted`
96
+ */
97
+ expr: string;
98
+ /**
99
+ * Import statements required by `expr`.
100
+ * These are rendered and merged into the file by the codemod.
101
+ */
102
+ imports: ImportSpec[];
103
+ };
63
104
  type ImportSource = {
64
105
  kind: "absolutePath";
65
106
  value: string;
@@ -105,8 +146,26 @@ interface StyleMergerConfig {
105
146
  importSource: ImportSource;
106
147
  }
107
148
  interface Adapter {
108
- /** Unified resolver for theme paths + CSS variables. Return null to leave unresolved. */
109
- resolveValue: (context: ResolveContext) => ResolveResult | null;
149
+ /**
150
+ * Resolver for theme paths + CSS variables.
151
+ *
152
+ * Notes:
153
+ * - Return `{ expr, imports }` for both theme + css variables.
154
+ * - Optionally return `{ dropDefinition: true }` for css variables to remove the local `--x: ...` definition.
155
+ * - Return `null` to leave a value unresolved.
156
+ */
157
+ resolveValue: (context: ResolveValueContext) => ResolveValueResult | null;
158
+ /**
159
+ * Resolver for helper calls found inside template interpolations.
160
+ *
161
+ * Return:
162
+ * - `{ usage: "props", expr, imports }` when the call resolves to a StyleX style object
163
+ * (usable as an argument to `stylex.props(...)`).
164
+ * - `{ usage: "create", expr, imports }` when the call resolves to a single CSS value
165
+ * (usable inside `stylex.create(...)` declarations).
166
+ * - `null` to leave the call unresolved (the file may bail with a warning depending on context).
167
+ */
168
+ resolveCall: (context: CallResolveContext) => CallResolveResult | null;
110
169
  /**
111
170
  * Called for exported styled components to determine if they should support
112
171
  * external className/style extension. Return true to generate wrapper with
@@ -133,6 +192,9 @@ interface Adapter {
133
192
  /**
134
193
  * Helper for nicer user authoring + type inference.
135
194
  *
195
+ * `defineAdapter(...)` also performs runtime validation (helpful for JS consumers)
196
+ * and will throw a descriptive error message if the adapter shape is invalid.
197
+ *
136
198
  * Usage:
137
199
  * export default defineAdapter({
138
200
  * resolveValue(ctx) {
@@ -147,11 +209,24 @@ interface Adapter {
147
209
  * return null;
148
210
  * },
149
211
  *
212
+ * resolveCall(ctx) {
213
+ * // Resolve helper calls inside template interpolations.
214
+ * // Return:
215
+ * // - { usage: "props", expr, imports } for StyleX styles (usable in stylex.props)
216
+ * // - { usage: "create", expr, imports } for a single value (usable in stylex.create)
217
+ * // - null to leave the call unresolved
218
+ * void ctx;
219
+ * return null;
220
+ * },
221
+ *
150
222
  * // Enable className/style/rest support for exported components
151
223
  * shouldSupportExternalStyling(ctx) {
152
224
  * // Example: Enable for all exported components in a shared components folder
153
225
  * return ctx.filePath.includes("/shared/components/");
154
226
  * },
227
+ *
228
+ * // Optional: provide a custom merger, or use `null` for the default verbose merge output
229
+ * styleMerger: null,
155
230
  * });
156
231
  */
157
232
  declare function defineAdapter(adapter: Adapter): Adapter;
@@ -23,6 +23,7 @@ function describeValue(value) {
23
23
  function assertValidAdapter(candidate, where) {
24
24
  const obj = candidate;
25
25
  const resolveValue = obj?.resolveValue;
26
+ const resolveCall = obj?.resolveCall;
26
27
  const shouldSupportExternalStyling = obj?.shouldSupportExternalStyling;
27
28
  if (!candidate || typeof candidate !== "object") throw new Error([
28
29
  `${where}: expected an adapter object.`,
@@ -30,12 +31,15 @@ function assertValidAdapter(candidate, where) {
30
31
  "",
31
32
  "Adapter requirements:",
32
33
  " - adapter.resolveValue(context) is required",
34
+ " - adapter.resolveCall(context) is required",
33
35
  " - adapter.shouldSupportExternalStyling(context) is required",
34
36
  "",
35
37
  "resolveValue(context) is called with one of these shapes:",
36
38
  " - { kind: \"theme\", path }",
37
39
  " - { kind: \"cssVariable\", name, fallback?, definedValue? }",
38
- " - { kind: \"call\", callSiteFilePath, calleeImportedName, calleeSource, args }",
40
+ "",
41
+ "resolveCall(context) is called with:",
42
+ " - { callSiteFilePath, calleeImportedName, calleeSource, args }",
39
43
  "",
40
44
  `Docs/examples: ${ADAPTER_DOCS_URL}`
41
45
  ].join("\n"));
@@ -45,7 +49,21 @@ function assertValidAdapter(candidate, where) {
45
49
  "",
46
50
  "Adapter shape:",
47
51
  " {",
48
- " resolveValue(context) { return { expr: string, imports: ImportSpec[] } | null }",
52
+ " resolveValue(context) {",
53
+ " // theme/cssVariable -> { expr, imports, dropDefinition? } | null",
54
+ " }",
55
+ " resolveCall(context) { return { usage: \"props\" | \"create\", expr, imports } | null }",
56
+ " }",
57
+ "",
58
+ `Docs/examples: ${ADAPTER_DOCS_URL}`
59
+ ].join("\n"));
60
+ if (typeof resolveCall !== "function") throw new Error([
61
+ `${where}: adapter.resolveCall must be a function.`,
62
+ `Received: resolveCall=${describeValue(resolveCall)}`,
63
+ "",
64
+ "Adapter shape:",
65
+ " {",
66
+ " resolveCall(context) { return { usage: \"props\" | \"create\", expr: string, imports: ImportSpec[] } | null }",
49
67
  " }",
50
68
  "",
51
69
  `Docs/examples: ${ADAPTER_DOCS_URL}`
@@ -97,10 +115,13 @@ var Logger = class Logger {
97
115
  Logger.writeWithSpacing(message, context);
98
116
  }
99
117
  /**
100
- * Log an error message to stderr.
118
+ * Log an error message to stderr with file path and optional location.
119
+ * Formats like warnings: "Error filepath:line:column\nmessage"
101
120
  */
102
- static error(message, context) {
103
- Logger.writeWithSpacing(`${Logger.colorizeErrorLabel("Error")} ${message}`, context);
121
+ static logError(message, filePath, loc, context) {
122
+ const location = loc ? `${filePath}:${loc.line}:${loc.column}` : filePath;
123
+ const label = Logger.colorizeErrorLabel("Error");
124
+ Logger.writeWithSpacing(`${label} ${location}\n${message}`, context);
104
125
  }
105
126
  /**
106
127
  * Log transform warnings to stderr and collect them.
@@ -1,4 +1,4 @@
1
- import { n as WarningLog, r as Adapter } from "./logger-BS4Evg0n.mjs";
1
+ import { n as WarningLog, r as Adapter } from "./logger-CNmtK-uJ.mjs";
2
2
  import "stylis";
3
3
  import { API, FileInfo, Options } from "jscodeshift";
4
4