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 +35 -37
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +38 -10
- package/dist/{logger-BS4Evg0n.d.mts → logger-CNmtK-uJ.d.mts} +82 -7
- package/dist/{logger-Dlnt1fYP.mjs → logger-DKelw2HS.mjs} +26 -5
- package/dist/transform.d.mts +1 -1
- package/dist/transform.mjs +4176 -953
- package/package.json +15 -5
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.
|
|
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
|
-
|
|
92
|
-
|
|
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
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
|
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 `
|
|
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 `
|
|
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
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as assertValidAdapter, r as describeValue, t as Logger } from "./logger-
|
|
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
|
|
101
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
/**
|
|
109
|
-
|
|
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
|
-
"
|
|
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) {
|
|
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
|
|
103
|
-
|
|
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.
|
package/dist/transform.d.mts
CHANGED