@typestyles/migrate 0.3.0 → 0.4.0
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/LICENSE +204 -0
- package/README.md +167 -0
- package/dist/chunk-D2W3OEBT.js +868 -0
- package/dist/chunk-D2W3OEBT.js.map +1 -0
- package/dist/cli.cjs +522 -81
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +522 -81
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-PZHSD3QV.js +0 -427
- package/dist/chunk-PZHSD3QV.js.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -9,7 +9,7 @@ var picomatch = require('picomatch');
|
|
|
9
9
|
var parser = require('@babel/parser');
|
|
10
10
|
var generate = require('@babel/generator');
|
|
11
11
|
var traverse = require('@babel/traverse');
|
|
12
|
-
var
|
|
12
|
+
var t4 = require('@babel/types');
|
|
13
13
|
var postcss = require('postcss');
|
|
14
14
|
|
|
15
15
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -36,7 +36,7 @@ var fg__default = /*#__PURE__*/_interopDefault(fg);
|
|
|
36
36
|
var picomatch__default = /*#__PURE__*/_interopDefault(picomatch);
|
|
37
37
|
var generate__default = /*#__PURE__*/_interopDefault(generate);
|
|
38
38
|
var traverse__default = /*#__PURE__*/_interopDefault(traverse);
|
|
39
|
-
var
|
|
39
|
+
var t4__namespace = /*#__PURE__*/_interopNamespace(t4);
|
|
40
40
|
var postcss__default = /*#__PURE__*/_interopDefault(postcss);
|
|
41
41
|
|
|
42
42
|
var DEFAULT_EXCLUDES = ["**/node_modules/**", "**/dist/**", "**/.next/**", "**/.turbo/**"];
|
|
@@ -78,42 +78,53 @@ async function collectTargetFiles(cwd, targets, extensions, include, exclude) {
|
|
|
78
78
|
function camelCaseProperty(property) {
|
|
79
79
|
return property.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
80
80
|
}
|
|
81
|
-
function toValueNode(value) {
|
|
81
|
+
function toValueNode(value, varReplacements) {
|
|
82
82
|
const trimmed = value.trim();
|
|
83
|
+
if (varReplacements?.has(trimmed)) {
|
|
84
|
+
return varReplacements.get(trimmed);
|
|
85
|
+
}
|
|
83
86
|
if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
84
|
-
return
|
|
87
|
+
return t4__namespace.numericLiteral(Number(trimmed));
|
|
85
88
|
}
|
|
86
|
-
return
|
|
89
|
+
return t4__namespace.stringLiteral(trimmed);
|
|
87
90
|
}
|
|
88
91
|
function toKeyNode(key) {
|
|
89
92
|
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
90
|
-
return
|
|
93
|
+
return t4__namespace.identifier(key);
|
|
91
94
|
}
|
|
92
|
-
return
|
|
95
|
+
return t4__namespace.stringLiteral(key);
|
|
93
96
|
}
|
|
94
|
-
function nodesToObject(nodes, warnings) {
|
|
97
|
+
function nodesToObject(nodes, warnings, varReplacements) {
|
|
95
98
|
const properties = [];
|
|
96
99
|
for (const node of nodes ?? []) {
|
|
97
100
|
if (node.type === "decl") {
|
|
98
101
|
const normalized = node.prop.startsWith("--") ? node.prop : camelCaseProperty(node.prop);
|
|
99
|
-
properties.push(
|
|
102
|
+
properties.push(
|
|
103
|
+
t4__namespace.objectProperty(toKeyNode(normalized), toValueNode(node.value, varReplacements))
|
|
104
|
+
);
|
|
100
105
|
continue;
|
|
101
106
|
}
|
|
102
107
|
if (node.type === "rule") {
|
|
103
|
-
const nested = nodesToObject(node.nodes, warnings);
|
|
104
|
-
properties.push(
|
|
108
|
+
const nested = nodesToObject(node.nodes, warnings, varReplacements);
|
|
109
|
+
properties.push(t4__namespace.objectProperty(t4__namespace.stringLiteral(node.selector.trim()), nested));
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (node.type === "atrule") {
|
|
113
|
+
const nested = nodesToObject(node.nodes, warnings, varReplacements);
|
|
114
|
+
const atRuleKey = `@${node.name}${node.params ? ` ${node.params}` : ""}`;
|
|
115
|
+
properties.push(t4__namespace.objectProperty(t4__namespace.stringLiteral(atRuleKey), nested));
|
|
105
116
|
continue;
|
|
106
117
|
}
|
|
107
118
|
warnings.push({
|
|
108
119
|
message: `Unsupported CSS node "${node.type}" skipped.`
|
|
109
120
|
});
|
|
110
121
|
}
|
|
111
|
-
return
|
|
122
|
+
return t4__namespace.objectExpression(properties);
|
|
112
123
|
}
|
|
113
|
-
function cssToObjectExpression(cssText, warnings) {
|
|
124
|
+
function cssToObjectExpression(cssText, warnings, varReplacements) {
|
|
114
125
|
try {
|
|
115
126
|
const root = postcss__default.default.parse(cssText);
|
|
116
|
-
return nodesToObject(root.nodes, warnings);
|
|
127
|
+
return nodesToObject(root.nodes, warnings, varReplacements);
|
|
117
128
|
} catch (error) {
|
|
118
129
|
warnings.push({
|
|
119
130
|
message: `Could not parse CSS template literal: ${error.message}`
|
|
@@ -121,30 +132,226 @@ function cssToObjectExpression(cssText, warnings) {
|
|
|
121
132
|
return null;
|
|
122
133
|
}
|
|
123
134
|
}
|
|
135
|
+
var PLACEHOLDER_PREFIX = "__ts_migrate_var_";
|
|
136
|
+
function camelCaseProperty2(property) {
|
|
137
|
+
return property.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
138
|
+
}
|
|
139
|
+
function placeholderToken(index) {
|
|
140
|
+
return `${PLACEHOLDER_PREFIX}${index}__`;
|
|
141
|
+
}
|
|
142
|
+
function extractSuffixFromQuasi(quasiText) {
|
|
143
|
+
const match = quasiText.match(/^([^;\n]*)/);
|
|
144
|
+
return match?.[1] ?? "";
|
|
145
|
+
}
|
|
146
|
+
function literalToCssValue(node) {
|
|
147
|
+
if (t4__namespace.isStringLiteral(node)) return node.value;
|
|
148
|
+
if (t4__namespace.isNumericLiteral(node)) return String(node.value);
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
function unwrapExpression(expression) {
|
|
152
|
+
if (t4__namespace.isParenthesizedExpression(expression)) {
|
|
153
|
+
return unwrapExpression(expression.expression);
|
|
154
|
+
}
|
|
155
|
+
return expression;
|
|
156
|
+
}
|
|
157
|
+
function extractCssPropertyBeforeInterpolation(quasiText) {
|
|
158
|
+
const match = quasiText.match(/([a-zA-Z-]+)\s*:\s*$/);
|
|
159
|
+
return match?.[1] ?? null;
|
|
160
|
+
}
|
|
161
|
+
function stripTrailingPropertyDeclaration(quasiText) {
|
|
162
|
+
return quasiText.replace(/[a-zA-Z-]+\s*:\s*$/, "");
|
|
163
|
+
}
|
|
164
|
+
function stripLeadingDeclarationRemainder(quasiText) {
|
|
165
|
+
const semiIdx = quasiText.indexOf(";");
|
|
166
|
+
if (semiIdx === -1) return quasiText;
|
|
167
|
+
return quasiText.slice(semiIdx + 1).trimStart();
|
|
168
|
+
}
|
|
169
|
+
function parsePropInterpolation(expression) {
|
|
170
|
+
if (!t4__namespace.isArrowFunctionExpression(expression)) return null;
|
|
171
|
+
const param = expression.params[0];
|
|
172
|
+
if (!param) return null;
|
|
173
|
+
const body = unwrapExpression(expression.body);
|
|
174
|
+
if (!t4__namespace.isExpression(body)) return null;
|
|
175
|
+
if (t4__namespace.isIdentifier(param)) {
|
|
176
|
+
if (t4__namespace.isMemberExpression(body) && !body.computed && t4__namespace.isIdentifier(body.object, { name: param.name }) && t4__namespace.isIdentifier(body.property)) {
|
|
177
|
+
return { propName: body.property.name };
|
|
178
|
+
}
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
if (t4__namespace.isObjectPattern(param) && t4__namespace.isIdentifier(body)) {
|
|
182
|
+
const propName = body.name;
|
|
183
|
+
const hasProp = param.properties.some((property) => {
|
|
184
|
+
if (!t4__namespace.isObjectProperty(property)) return false;
|
|
185
|
+
const keyName = t4__namespace.isIdentifier(property.key) ? property.key.name : t4__namespace.isStringLiteral(property.key) ? property.key.value : null;
|
|
186
|
+
return keyName === propName;
|
|
187
|
+
});
|
|
188
|
+
if (!hasProp) return null;
|
|
189
|
+
return { propName };
|
|
190
|
+
}
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
function parseBooleanTernaryInterpolation(expression) {
|
|
194
|
+
if (!t4__namespace.isArrowFunctionExpression(expression)) return null;
|
|
195
|
+
const param = expression.params[0];
|
|
196
|
+
if (!t4__namespace.isIdentifier(param)) return null;
|
|
197
|
+
const body = unwrapExpression(expression.body);
|
|
198
|
+
if (!t4__namespace.isConditionalExpression(body)) return null;
|
|
199
|
+
if (!t4__namespace.isMemberExpression(body.test) || body.test.computed || !t4__namespace.isIdentifier(body.test.object, { name: param.name }) || !t4__namespace.isIdentifier(body.test.property)) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
const trueValue = literalToCssValue(body.consequent);
|
|
203
|
+
const falseValue = literalToCssValue(body.alternate);
|
|
204
|
+
if (trueValue === null || falseValue === null) return null;
|
|
205
|
+
return {
|
|
206
|
+
propName: body.test.property.name,
|
|
207
|
+
trueValue,
|
|
208
|
+
falseValue
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function parseTemplateInterpolations(template) {
|
|
212
|
+
const interpolations = [];
|
|
213
|
+
for (let i = 0; i < template.expressions.length; i++) {
|
|
214
|
+
const expression = template.expressions[i];
|
|
215
|
+
if (!t4__namespace.isExpression(expression)) return null;
|
|
216
|
+
const parsed = parsePropInterpolation(expression);
|
|
217
|
+
if (!parsed) return null;
|
|
218
|
+
const followingQuasi = template.quasis[i + 1]?.value.cooked ?? "";
|
|
219
|
+
interpolations.push({
|
|
220
|
+
index: i,
|
|
221
|
+
propName: parsed.propName,
|
|
222
|
+
suffix: extractSuffixFromQuasi(followingQuasi)
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return interpolations;
|
|
226
|
+
}
|
|
227
|
+
function parseBooleanTemplateInterpolations(template) {
|
|
228
|
+
const interpolations = [];
|
|
229
|
+
for (let i = 0; i < template.expressions.length; i++) {
|
|
230
|
+
const expression = template.expressions[i];
|
|
231
|
+
if (!t4__namespace.isExpression(expression)) return null;
|
|
232
|
+
const parsed = parseBooleanTernaryInterpolation(expression);
|
|
233
|
+
if (!parsed) return null;
|
|
234
|
+
const quasiBefore = template.quasis[i]?.value.cooked ?? "";
|
|
235
|
+
const cssProperty = extractCssPropertyBeforeInterpolation(quasiBefore);
|
|
236
|
+
if (!cssProperty) return null;
|
|
237
|
+
interpolations.push({
|
|
238
|
+
index: i,
|
|
239
|
+
propName: parsed.propName,
|
|
240
|
+
trueValue: parsed.trueValue,
|
|
241
|
+
falseValue: parsed.falseValue,
|
|
242
|
+
cssProperty: camelCaseProperty2(cssProperty)
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
return interpolations;
|
|
246
|
+
}
|
|
247
|
+
function reconstructInterpolatedCss(template, interpolations) {
|
|
248
|
+
let result = "";
|
|
249
|
+
for (let i = 0; i < template.quasis.length; i++) {
|
|
250
|
+
let quasiText = template.quasis[i].value.cooked ?? "";
|
|
251
|
+
if (i > 0) {
|
|
252
|
+
const interpolation = interpolations[i - 1];
|
|
253
|
+
if (interpolation?.suffix && quasiText.startsWith(interpolation.suffix)) {
|
|
254
|
+
quasiText = quasiText.slice(interpolation.suffix.length);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
result += quasiText;
|
|
258
|
+
if (i < interpolations.length) {
|
|
259
|
+
result += placeholderToken(interpolations[i].index);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return result;
|
|
263
|
+
}
|
|
264
|
+
function reconstructStaticCssWithoutVariants(template, booleanInterpolations) {
|
|
265
|
+
const skipIndices = new Set(booleanInterpolations.map((interpolation) => interpolation.index));
|
|
266
|
+
let result = "";
|
|
267
|
+
for (let i = 0; i < template.quasis.length; i++) {
|
|
268
|
+
let quasiText = template.quasis[i].value.cooked ?? "";
|
|
269
|
+
if (skipIndices.has(i)) {
|
|
270
|
+
quasiText = stripTrailingPropertyDeclaration(quasiText);
|
|
271
|
+
}
|
|
272
|
+
if (i > 0 && skipIndices.has(i - 1)) {
|
|
273
|
+
quasiText = stripLeadingDeclarationRemainder(quasiText);
|
|
274
|
+
}
|
|
275
|
+
result += quasiText;
|
|
276
|
+
}
|
|
277
|
+
return result.trim();
|
|
278
|
+
}
|
|
279
|
+
function toVarDebugName(componentName, propName) {
|
|
280
|
+
return `${componentName}${propName.charAt(0).toUpperCase()}${propName.slice(1)}`;
|
|
281
|
+
}
|
|
282
|
+
function toComponentConstName(componentName) {
|
|
283
|
+
if (!componentName) return componentName;
|
|
284
|
+
return componentName.charAt(0).toLowerCase() + componentName.slice(1);
|
|
285
|
+
}
|
|
286
|
+
function toCssValueNode(value) {
|
|
287
|
+
if (/^-?\d+(\.\d+)?$/.test(value.trim())) {
|
|
288
|
+
return t4__namespace.numericLiteral(Number(value));
|
|
289
|
+
}
|
|
290
|
+
return t4__namespace.stringLiteral(value);
|
|
291
|
+
}
|
|
292
|
+
function toKeyNode2(key) {
|
|
293
|
+
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
|
|
294
|
+
return t4__namespace.identifier(key);
|
|
295
|
+
}
|
|
296
|
+
return t4__namespace.stringLiteral(key);
|
|
297
|
+
}
|
|
298
|
+
function buildVariantStyles(properties) {
|
|
299
|
+
return t4__namespace.objectExpression(
|
|
300
|
+
Object.entries(properties).map(
|
|
301
|
+
([key, value]) => t4__namespace.objectProperty(toKeyNode2(key), toCssValueNode(value))
|
|
302
|
+
)
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
function buildVariantComponentConfig(baseObject, booleanInterpolations) {
|
|
306
|
+
const variantGroups = /* @__PURE__ */ new Map();
|
|
307
|
+
for (const interpolation of booleanInterpolations) {
|
|
308
|
+
const group = variantGroups.get(interpolation.propName) ?? { true: {}, false: {} };
|
|
309
|
+
group.true[interpolation.cssProperty] = interpolation.trueValue;
|
|
310
|
+
group.false[interpolation.cssProperty] = interpolation.falseValue;
|
|
311
|
+
variantGroups.set(interpolation.propName, group);
|
|
312
|
+
}
|
|
313
|
+
const variantsProperties = [...variantGroups.entries()].map(
|
|
314
|
+
([propName, values]) => t4__namespace.objectProperty(
|
|
315
|
+
t4__namespace.identifier(propName),
|
|
316
|
+
t4__namespace.objectExpression([
|
|
317
|
+
t4__namespace.objectProperty(t4__namespace.identifier("true"), buildVariantStyles(values.true)),
|
|
318
|
+
t4__namespace.objectProperty(t4__namespace.identifier("false"), buildVariantStyles(values.false))
|
|
319
|
+
])
|
|
320
|
+
)
|
|
321
|
+
);
|
|
322
|
+
const defaultVariantProperties = [...variantGroups.keys()].map(
|
|
323
|
+
(propName) => t4__namespace.objectProperty(t4__namespace.identifier(propName), t4__namespace.booleanLiteral(false))
|
|
324
|
+
);
|
|
325
|
+
return t4__namespace.objectExpression([
|
|
326
|
+
t4__namespace.objectProperty(t4__namespace.identifier("base"), baseObject),
|
|
327
|
+
t4__namespace.objectProperty(t4__namespace.identifier("variants"), t4__namespace.objectExpression(variantsProperties)),
|
|
328
|
+
t4__namespace.objectProperty(t4__namespace.identifier("defaultVariants"), t4__namespace.objectExpression(defaultVariantProperties))
|
|
329
|
+
]);
|
|
330
|
+
}
|
|
124
331
|
|
|
125
332
|
// src/transform.ts
|
|
126
333
|
function toKebabCase(input) {
|
|
127
334
|
return input.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[_\s]+/g, "-").toLowerCase();
|
|
128
335
|
}
|
|
129
336
|
function memberExpressionToJsxName(expression) {
|
|
130
|
-
if (
|
|
131
|
-
return
|
|
337
|
+
if (t4__namespace.isIdentifier(expression)) {
|
|
338
|
+
return t4__namespace.jsxIdentifier(expression.name);
|
|
132
339
|
}
|
|
133
|
-
if (
|
|
340
|
+
if (t4__namespace.isMemberExpression(expression) && !expression.computed) {
|
|
134
341
|
const left = memberExpressionToJsxName(expression.object);
|
|
135
|
-
const right =
|
|
342
|
+
const right = t4__namespace.isIdentifier(expression.property) ? t4__namespace.jsxIdentifier(expression.property.name) : null;
|
|
136
343
|
if (!left || !right) return null;
|
|
137
|
-
return
|
|
344
|
+
return t4__namespace.jsxMemberExpression(left, right);
|
|
138
345
|
}
|
|
139
346
|
return null;
|
|
140
347
|
}
|
|
141
348
|
function parseStyledTarget(tag, styledNames) {
|
|
142
|
-
if (
|
|
143
|
-
return { kind: "intrinsic", jsxName:
|
|
349
|
+
if (t4__namespace.isMemberExpression(tag) && t4__namespace.isIdentifier(tag.object) && styledNames.has(tag.object.name) && t4__namespace.isIdentifier(tag.property)) {
|
|
350
|
+
return { kind: "intrinsic", jsxName: t4__namespace.jsxIdentifier(tag.property.name) };
|
|
144
351
|
}
|
|
145
|
-
if (
|
|
352
|
+
if (t4__namespace.isCallExpression(tag) && t4__namespace.isIdentifier(tag.callee) && styledNames.has(tag.callee.name)) {
|
|
146
353
|
const firstArg = tag.arguments[0];
|
|
147
|
-
if (!firstArg || !
|
|
354
|
+
if (!firstArg || !t4__namespace.isExpression(firstArg)) return null;
|
|
148
355
|
const jsxName = memberExpressionToJsxName(firstArg);
|
|
149
356
|
if (!jsxName) return null;
|
|
150
357
|
return { kind: "component", jsxName };
|
|
@@ -154,74 +361,77 @@ function parseStyledTarget(tag, styledNames) {
|
|
|
154
361
|
function addWarning(warnings, message, nodeName) {
|
|
155
362
|
warnings.push({ message, nodeName });
|
|
156
363
|
}
|
|
157
|
-
function createMergedClassExpression(existing,
|
|
158
|
-
return
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
364
|
+
function createMergedClassExpression(existing, classNameExpression) {
|
|
365
|
+
return t4__namespace.callExpression(
|
|
366
|
+
t4__namespace.memberExpression(
|
|
367
|
+
t4__namespace.callExpression(
|
|
368
|
+
t4__namespace.memberExpression(
|
|
369
|
+
t4__namespace.arrayExpression([existing, classNameExpression]),
|
|
370
|
+
t4__namespace.identifier("filter")
|
|
164
371
|
),
|
|
165
|
-
[
|
|
372
|
+
[t4__namespace.identifier("Boolean")]
|
|
166
373
|
),
|
|
167
|
-
|
|
374
|
+
t4__namespace.identifier("join")
|
|
168
375
|
),
|
|
169
|
-
[
|
|
376
|
+
[t4__namespace.stringLiteral(" ")]
|
|
170
377
|
);
|
|
171
378
|
}
|
|
172
|
-
function updateClassNameAttribute(openingElement,
|
|
379
|
+
function updateClassNameAttribute(openingElement, classNameExpression) {
|
|
173
380
|
const existingAttr = openingElement.attributes.find(
|
|
174
|
-
(attribute) =>
|
|
381
|
+
(attribute) => t4__namespace.isJSXAttribute(attribute) && t4__namespace.isJSXIdentifier(attribute.name, { name: "className" })
|
|
175
382
|
);
|
|
176
383
|
if (!existingAttr) {
|
|
177
384
|
openingElement.attributes.push(
|
|
178
|
-
|
|
385
|
+
t4__namespace.jsxAttribute(t4__namespace.jsxIdentifier("className"), t4__namespace.jsxExpressionContainer(classNameExpression))
|
|
179
386
|
);
|
|
180
387
|
return;
|
|
181
388
|
}
|
|
182
389
|
if (!existingAttr.value) {
|
|
183
|
-
existingAttr.value =
|
|
390
|
+
existingAttr.value = t4__namespace.jsxExpressionContainer(classNameExpression);
|
|
184
391
|
return;
|
|
185
392
|
}
|
|
186
|
-
if (
|
|
187
|
-
existingAttr.value =
|
|
188
|
-
createMergedClassExpression(
|
|
393
|
+
if (t4__namespace.isStringLiteral(existingAttr.value)) {
|
|
394
|
+
existingAttr.value = t4__namespace.jsxExpressionContainer(
|
|
395
|
+
createMergedClassExpression(t4__namespace.stringLiteral(existingAttr.value.value), classNameExpression)
|
|
189
396
|
);
|
|
190
397
|
return;
|
|
191
398
|
}
|
|
192
|
-
if (
|
|
193
|
-
existingAttr.value =
|
|
399
|
+
if (t4__namespace.isJSXExpressionContainer(existingAttr.value)) {
|
|
400
|
+
existingAttr.value = t4__namespace.jsxExpressionContainer(
|
|
194
401
|
createMergedClassExpression(
|
|
195
402
|
existingAttr.value.expression,
|
|
196
|
-
|
|
403
|
+
classNameExpression
|
|
197
404
|
)
|
|
198
405
|
);
|
|
199
406
|
}
|
|
200
407
|
}
|
|
201
|
-
function
|
|
408
|
+
function ensureTypestylesImport(ast, needsVars) {
|
|
409
|
+
const requiredSpecifiers = /* @__PURE__ */ new Set(["styles"]);
|
|
410
|
+
if (needsVars) {
|
|
411
|
+
requiredSpecifiers.add("createVar");
|
|
412
|
+
requiredSpecifiers.add("assignVars");
|
|
413
|
+
}
|
|
202
414
|
let typestylesImport = null;
|
|
203
415
|
for (const statement of ast.program.body) {
|
|
204
|
-
if (
|
|
416
|
+
if (t4__namespace.isImportDeclaration(statement) && statement.source.value === "typestyles") {
|
|
205
417
|
typestylesImport = statement;
|
|
206
418
|
break;
|
|
207
419
|
}
|
|
208
420
|
}
|
|
421
|
+
const buildSpecifiers = (names) => [...names].map((name) => t4__namespace.importSpecifier(t4__namespace.identifier(name), t4__namespace.identifier(name)));
|
|
209
422
|
if (!typestylesImport) {
|
|
210
423
|
ast.program.body.unshift(
|
|
211
|
-
|
|
212
|
-
[t2__namespace.importSpecifier(t2__namespace.identifier("styles"), t2__namespace.identifier("styles"))],
|
|
213
|
-
t2__namespace.stringLiteral("typestyles")
|
|
214
|
-
)
|
|
424
|
+
t4__namespace.importDeclaration(buildSpecifiers(requiredSpecifiers), t4__namespace.stringLiteral("typestyles"))
|
|
215
425
|
);
|
|
216
426
|
return;
|
|
217
427
|
}
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (!hasStylesSpecifier) {
|
|
222
|
-
typestylesImport.specifiers.push(
|
|
223
|
-
t2__namespace.importSpecifier(t2__namespace.identifier("styles"), t2__namespace.identifier("styles"))
|
|
428
|
+
for (const name of requiredSpecifiers) {
|
|
429
|
+
const hasSpecifier = typestylesImport.specifiers.some(
|
|
430
|
+
(specifier) => t4__namespace.isImportSpecifier(specifier) && t4__namespace.isIdentifier(specifier.imported, { name }) && t4__namespace.isIdentifier(specifier.local, { name })
|
|
224
431
|
);
|
|
432
|
+
if (!hasSpecifier) {
|
|
433
|
+
typestylesImport.specifiers.push(t4__namespace.importSpecifier(t4__namespace.identifier(name), t4__namespace.identifier(name)));
|
|
434
|
+
}
|
|
225
435
|
}
|
|
226
436
|
}
|
|
227
437
|
function cleanupUnusedImports(ast) {
|
|
@@ -231,7 +441,7 @@ function cleanupUnusedImports(ast) {
|
|
|
231
441
|
},
|
|
232
442
|
ImportDeclaration(path) {
|
|
233
443
|
const unusedLocals = path.node.specifiers.filter((specifier) => {
|
|
234
|
-
if (path.node.source.value === "typestyles" &&
|
|
444
|
+
if (path.node.source.value === "typestyles" && t4__namespace.isImportSpecifier(specifier) && (specifier.local.name === "styles" || specifier.local.name === "createVar" || specifier.local.name === "assignVars")) {
|
|
235
445
|
return false;
|
|
236
446
|
}
|
|
237
447
|
const local = specifier.local.name;
|
|
@@ -248,6 +458,177 @@ function cleanupUnusedImports(ast) {
|
|
|
248
458
|
}
|
|
249
459
|
});
|
|
250
460
|
}
|
|
461
|
+
function createAssignVarValue(propExpression, suffix) {
|
|
462
|
+
if (!suffix) return propExpression;
|
|
463
|
+
if (t4__namespace.isStringLiteral(propExpression)) {
|
|
464
|
+
return t4__namespace.stringLiteral(`${propExpression.value}${suffix}`);
|
|
465
|
+
}
|
|
466
|
+
return t4__namespace.binaryExpression("+", propExpression, t4__namespace.stringLiteral(suffix));
|
|
467
|
+
}
|
|
468
|
+
function buildAssignVarsCall(propVars, propValues) {
|
|
469
|
+
const properties = propVars.filter((binding) => propValues.has(binding.propName)).map((binding) => {
|
|
470
|
+
const propExpression = propValues.get(binding.propName);
|
|
471
|
+
return t4__namespace.objectProperty(
|
|
472
|
+
t4__namespace.identifier(binding.varConstName),
|
|
473
|
+
createAssignVarValue(propExpression, binding.suffix),
|
|
474
|
+
true
|
|
475
|
+
);
|
|
476
|
+
});
|
|
477
|
+
return t4__namespace.callExpression(t4__namespace.identifier("assignVars"), [t4__namespace.objectExpression(properties)]);
|
|
478
|
+
}
|
|
479
|
+
function mergeStyleExpressions(existing, assignVarsCall) {
|
|
480
|
+
return t4__namespace.objectExpression([t4__namespace.spreadElement(existing), t4__namespace.spreadElement(assignVarsCall)]);
|
|
481
|
+
}
|
|
482
|
+
function updateStyleAttribute(openingElement, assignVarsCall) {
|
|
483
|
+
const existingAttr = openingElement.attributes.find(
|
|
484
|
+
(attribute) => t4__namespace.isJSXAttribute(attribute) && t4__namespace.isJSXIdentifier(attribute.name, { name: "style" })
|
|
485
|
+
);
|
|
486
|
+
if (!existingAttr) {
|
|
487
|
+
openingElement.attributes.push(
|
|
488
|
+
t4__namespace.jsxAttribute(t4__namespace.jsxIdentifier("style"), t4__namespace.jsxExpressionContainer(assignVarsCall))
|
|
489
|
+
);
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
if (!existingAttr.value) {
|
|
493
|
+
existingAttr.value = t4__namespace.jsxExpressionContainer(assignVarsCall);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
if (t4__namespace.isJSXExpressionContainer(existingAttr.value)) {
|
|
497
|
+
existingAttr.value = t4__namespace.jsxExpressionContainer(
|
|
498
|
+
mergeStyleExpressions(existingAttr.value.expression, assignVarsCall)
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
function collectPropValuesFromJsx(openingElement, propNames) {
|
|
503
|
+
const values = /* @__PURE__ */ new Map();
|
|
504
|
+
for (const attribute of openingElement.attributes) {
|
|
505
|
+
if (!t4__namespace.isJSXAttribute(attribute) || !t4__namespace.isJSXIdentifier(attribute.name)) continue;
|
|
506
|
+
if (!propNames.has(attribute.name.name)) continue;
|
|
507
|
+
if (!attribute.value) {
|
|
508
|
+
values.set(attribute.name.name, t4__namespace.booleanLiteral(true));
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
if (t4__namespace.isStringLiteral(attribute.value)) {
|
|
512
|
+
values.set(attribute.name.name, t4__namespace.stringLiteral(attribute.value.value));
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (t4__namespace.isJSXExpressionContainer(attribute.value)) {
|
|
516
|
+
values.set(attribute.name.name, attribute.value.expression);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return values;
|
|
520
|
+
}
|
|
521
|
+
function removeStyledProps(openingElement, propNames) {
|
|
522
|
+
openingElement.attributes = openingElement.attributes.filter((attribute) => {
|
|
523
|
+
if (!t4__namespace.isJSXAttribute(attribute) || !t4__namespace.isJSXIdentifier(attribute.name)) return true;
|
|
524
|
+
return !propNames.has(attribute.name.name);
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
function buildComponentClassNameExpression(componentConstName, variantProps, propValues) {
|
|
528
|
+
const properties = variantProps.filter((propName) => propValues.has(propName)).map((propName) => t4__namespace.objectProperty(t4__namespace.identifier(propName), propValues.get(propName)));
|
|
529
|
+
if (properties.length === 0) {
|
|
530
|
+
return t4__namespace.callExpression(t4__namespace.identifier(componentConstName), []);
|
|
531
|
+
}
|
|
532
|
+
return t4__namespace.callExpression(t4__namespace.identifier(componentConstName), [t4__namespace.objectExpression(properties)]);
|
|
533
|
+
}
|
|
534
|
+
function migrateBooleanVariantTemplate(path, variableName, template, styledTarget, warnings, styledTransforms) {
|
|
535
|
+
const booleanInterpolations = parseBooleanTemplateInterpolations(template);
|
|
536
|
+
if (!booleanInterpolations) return false;
|
|
537
|
+
const staticCss = reconstructStaticCssWithoutVariants(template, booleanInterpolations);
|
|
538
|
+
const baseObject = cssToObjectExpression(staticCss, warnings);
|
|
539
|
+
if (!baseObject) {
|
|
540
|
+
addWarning(warnings, "Skipped because CSS could not be parsed.", variableName);
|
|
541
|
+
return false;
|
|
542
|
+
}
|
|
543
|
+
const componentConstName = path.scope.generateUidIdentifier(
|
|
544
|
+
toComponentConstName(variableName)
|
|
545
|
+
).name;
|
|
546
|
+
const componentConfig = buildVariantComponentConfig(baseObject, booleanInterpolations);
|
|
547
|
+
const variantProps = [
|
|
548
|
+
...new Set(booleanInterpolations.map((interpolation) => interpolation.propName))
|
|
549
|
+
];
|
|
550
|
+
const declaration = path.parentPath;
|
|
551
|
+
if (!declaration.isVariableDeclaration()) return false;
|
|
552
|
+
declaration.node.declarations = [
|
|
553
|
+
t4__namespace.variableDeclarator(
|
|
554
|
+
t4__namespace.identifier(componentConstName),
|
|
555
|
+
t4__namespace.callExpression(t4__namespace.memberExpression(t4__namespace.identifier("styles"), t4__namespace.identifier("component")), [
|
|
556
|
+
t4__namespace.stringLiteral(toKebabCase(variableName)),
|
|
557
|
+
componentConfig
|
|
558
|
+
])
|
|
559
|
+
)
|
|
560
|
+
];
|
|
561
|
+
styledTransforms.set(variableName, {
|
|
562
|
+
originalName: variableName,
|
|
563
|
+
mode: "component",
|
|
564
|
+
classConstName: componentConstName,
|
|
565
|
+
target: styledTarget,
|
|
566
|
+
propVars: [],
|
|
567
|
+
variantProps
|
|
568
|
+
});
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
function migrateInterpolatedTemplate(path, variableName, template, styledTarget, warnings, styledTransforms) {
|
|
572
|
+
const interpolations = parseTemplateInterpolations(template);
|
|
573
|
+
if (!interpolations) {
|
|
574
|
+
addWarning(
|
|
575
|
+
warnings,
|
|
576
|
+
"Skipped template literal with unsupported interpolations. Only prop-based patterns like `${props => props.color}` are migrated.",
|
|
577
|
+
variableName
|
|
578
|
+
);
|
|
579
|
+
return false;
|
|
580
|
+
}
|
|
581
|
+
const cssText = reconstructInterpolatedCss(template, interpolations);
|
|
582
|
+
const propVars = interpolations.map((interpolation) => ({
|
|
583
|
+
propName: interpolation.propName,
|
|
584
|
+
varConstName: path.scope.generateUidIdentifier(
|
|
585
|
+
`${variableName}${interpolation.propName.charAt(0).toUpperCase()}${interpolation.propName.slice(1)}Var`
|
|
586
|
+
).name,
|
|
587
|
+
suffix: interpolation.suffix
|
|
588
|
+
}));
|
|
589
|
+
const varReplacements = /* @__PURE__ */ new Map();
|
|
590
|
+
for (let i = 0; i < interpolations.length; i++) {
|
|
591
|
+
varReplacements.set(
|
|
592
|
+
placeholderToken(interpolations[i].index),
|
|
593
|
+
t4__namespace.identifier(propVars[i].varConstName)
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
const objectExpression4 = cssToObjectExpression(cssText, warnings, varReplacements);
|
|
597
|
+
if (!objectExpression4) {
|
|
598
|
+
addWarning(warnings, "Skipped because CSS could not be parsed.", variableName);
|
|
599
|
+
return false;
|
|
600
|
+
}
|
|
601
|
+
const classConstName = path.scope.generateUidIdentifier(`${variableName}Class`).name;
|
|
602
|
+
const varDeclarators = propVars.map(
|
|
603
|
+
(propVar) => t4__namespace.variableDeclarator(
|
|
604
|
+
t4__namespace.identifier(propVar.varConstName),
|
|
605
|
+
t4__namespace.callExpression(t4__namespace.identifier("createVar"), [
|
|
606
|
+
t4__namespace.stringLiteral(toVarDebugName(variableName, propVar.propName))
|
|
607
|
+
])
|
|
608
|
+
)
|
|
609
|
+
);
|
|
610
|
+
const declaration = path.parentPath;
|
|
611
|
+
if (!declaration.isVariableDeclaration()) return false;
|
|
612
|
+
declaration.node.declarations = [
|
|
613
|
+
...varDeclarators,
|
|
614
|
+
t4__namespace.variableDeclarator(
|
|
615
|
+
t4__namespace.identifier(classConstName),
|
|
616
|
+
t4__namespace.callExpression(t4__namespace.memberExpression(t4__namespace.identifier("styles"), t4__namespace.identifier("class")), [
|
|
617
|
+
t4__namespace.stringLiteral(toKebabCase(variableName)),
|
|
618
|
+
objectExpression4
|
|
619
|
+
])
|
|
620
|
+
)
|
|
621
|
+
];
|
|
622
|
+
styledTransforms.set(variableName, {
|
|
623
|
+
originalName: variableName,
|
|
624
|
+
mode: "class",
|
|
625
|
+
classConstName,
|
|
626
|
+
target: styledTarget,
|
|
627
|
+
propVars,
|
|
628
|
+
variantProps: []
|
|
629
|
+
});
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
251
632
|
function isOnlyJsxReferences(binding) {
|
|
252
633
|
return binding.referencePaths.every((referencePath) => {
|
|
253
634
|
const parent = referencePath.parentPath;
|
|
@@ -265,21 +646,22 @@ function migrateSource(filePath, source) {
|
|
|
265
646
|
const styledNames = /* @__PURE__ */ new Set();
|
|
266
647
|
const cssTagNames = /* @__PURE__ */ new Set();
|
|
267
648
|
const styledTransforms = /* @__PURE__ */ new Map();
|
|
649
|
+
let needsVars = false;
|
|
268
650
|
traverse__default.default(ast, {
|
|
269
651
|
ImportDeclaration(path) {
|
|
270
652
|
if (path.node.source.value === "styled-components" || path.node.source.value === "@emotion/styled") {
|
|
271
653
|
for (const specifier of path.node.specifiers) {
|
|
272
|
-
if (
|
|
654
|
+
if (t4__namespace.isImportDefaultSpecifier(specifier)) {
|
|
273
655
|
styledNames.add(specifier.local.name);
|
|
274
656
|
}
|
|
275
|
-
if (
|
|
657
|
+
if (t4__namespace.isImportSpecifier(specifier) && t4__namespace.isIdentifier(specifier.imported, { name: "css" })) {
|
|
276
658
|
cssTagNames.add(specifier.local.name);
|
|
277
659
|
}
|
|
278
660
|
}
|
|
279
661
|
}
|
|
280
662
|
if (path.node.source.value === "@emotion/react" || path.node.source.value === "@emotion/css") {
|
|
281
663
|
for (const specifier of path.node.specifiers) {
|
|
282
|
-
if (
|
|
664
|
+
if (t4__namespace.isImportSpecifier(specifier) && t4__namespace.isIdentifier(specifier.imported, { name: "css" })) {
|
|
283
665
|
cssTagNames.add(specifier.local.name);
|
|
284
666
|
}
|
|
285
667
|
}
|
|
@@ -288,27 +670,66 @@ function migrateSource(filePath, source) {
|
|
|
288
670
|
});
|
|
289
671
|
traverse__default.default(ast, {
|
|
290
672
|
VariableDeclarator(path) {
|
|
291
|
-
if (!
|
|
292
|
-
if (!
|
|
673
|
+
if (!t4__namespace.isIdentifier(path.node.id)) return;
|
|
674
|
+
if (!t4__namespace.isTaggedTemplateExpression(path.node.init)) return;
|
|
293
675
|
const variableName = path.node.id.name;
|
|
294
676
|
const binding = path.scope.getBinding(variableName);
|
|
295
677
|
if (!binding) return;
|
|
296
678
|
const template = path.node.init.quasi;
|
|
297
|
-
|
|
298
|
-
|
|
679
|
+
const hasInterpolations = template.expressions.length > 0;
|
|
680
|
+
const styledTarget = parseStyledTarget(path.node.init.tag, styledNames);
|
|
681
|
+
if (hasInterpolations) {
|
|
682
|
+
if (!styledTarget) {
|
|
683
|
+
addWarning(
|
|
684
|
+
warnings,
|
|
685
|
+
"Skipped template literal with interpolations. Only styled-components prop patterns are migrated.",
|
|
686
|
+
variableName
|
|
687
|
+
);
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
const declaration = path.parentPath;
|
|
691
|
+
if (declaration.parentPath?.isExportNamedDeclaration() || declaration.parentPath?.isExportDefaultDeclaration()) {
|
|
692
|
+
addWarning(
|
|
693
|
+
warnings,
|
|
694
|
+
"Skipped exported styled component to avoid changing external API shape.",
|
|
695
|
+
variableName
|
|
696
|
+
);
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
699
|
+
if (!isOnlyJsxReferences(binding)) {
|
|
700
|
+
addWarning(warnings, "Skipped styled component with non-JSX references.", variableName);
|
|
701
|
+
return;
|
|
702
|
+
}
|
|
703
|
+
if (migrateBooleanVariantTemplate(
|
|
704
|
+
path,
|
|
705
|
+
variableName,
|
|
706
|
+
template,
|
|
707
|
+
styledTarget,
|
|
299
708
|
warnings,
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
709
|
+
styledTransforms
|
|
710
|
+
)) {
|
|
711
|
+
changed = true;
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
if (migrateInterpolatedTemplate(
|
|
715
|
+
path,
|
|
716
|
+
variableName,
|
|
717
|
+
template,
|
|
718
|
+
styledTarget,
|
|
719
|
+
warnings,
|
|
720
|
+
styledTransforms
|
|
721
|
+
)) {
|
|
722
|
+
needsVars = true;
|
|
723
|
+
changed = true;
|
|
724
|
+
}
|
|
303
725
|
return;
|
|
304
726
|
}
|
|
305
727
|
const cssText = template.quasis.map((quasi) => quasi.value.cooked ?? "").join("");
|
|
306
|
-
const
|
|
307
|
-
if (!
|
|
728
|
+
const objectExpression4 = cssToObjectExpression(cssText, warnings);
|
|
729
|
+
if (!objectExpression4) {
|
|
308
730
|
addWarning(warnings, "Skipped because CSS could not be parsed.", variableName);
|
|
309
731
|
return;
|
|
310
732
|
}
|
|
311
|
-
const styledTarget = parseStyledTarget(path.node.init.tag, styledNames);
|
|
312
733
|
if (styledTarget) {
|
|
313
734
|
const declaration = path.parentPath;
|
|
314
735
|
if (declaration.parentPath?.isExportNamedDeclaration() || declaration.parentPath?.isExportDefaultDeclaration()) {
|
|
@@ -324,23 +745,26 @@ function migrateSource(filePath, source) {
|
|
|
324
745
|
return;
|
|
325
746
|
}
|
|
326
747
|
const classConstName = path.scope.generateUidIdentifier(`${variableName}Class`).name;
|
|
327
|
-
path.node.id =
|
|
328
|
-
path.node.init =
|
|
329
|
-
|
|
330
|
-
[
|
|
748
|
+
path.node.id = t4__namespace.identifier(classConstName);
|
|
749
|
+
path.node.init = t4__namespace.callExpression(
|
|
750
|
+
t4__namespace.memberExpression(t4__namespace.identifier("styles"), t4__namespace.identifier("class")),
|
|
751
|
+
[t4__namespace.stringLiteral(toKebabCase(variableName)), objectExpression4]
|
|
331
752
|
);
|
|
332
753
|
styledTransforms.set(variableName, {
|
|
333
754
|
originalName: variableName,
|
|
755
|
+
mode: "class",
|
|
334
756
|
classConstName,
|
|
335
|
-
target: styledTarget
|
|
757
|
+
target: styledTarget,
|
|
758
|
+
propVars: [],
|
|
759
|
+
variantProps: []
|
|
336
760
|
});
|
|
337
761
|
changed = true;
|
|
338
762
|
return;
|
|
339
763
|
}
|
|
340
|
-
if (
|
|
341
|
-
path.node.init =
|
|
342
|
-
|
|
343
|
-
[
|
|
764
|
+
if (t4__namespace.isIdentifier(path.node.init.tag) && cssTagNames.has(path.node.init.tag.name)) {
|
|
765
|
+
path.node.init = t4__namespace.callExpression(
|
|
766
|
+
t4__namespace.memberExpression(t4__namespace.identifier("styles"), t4__namespace.identifier("class")),
|
|
767
|
+
[t4__namespace.stringLiteral(toKebabCase(variableName)), objectExpression4]
|
|
344
768
|
);
|
|
345
769
|
changed = true;
|
|
346
770
|
}
|
|
@@ -350,19 +774,36 @@ function migrateSource(filePath, source) {
|
|
|
350
774
|
traverse__default.default(ast, {
|
|
351
775
|
JSXElement(path) {
|
|
352
776
|
const openingName = path.node.openingElement.name;
|
|
353
|
-
if (!
|
|
777
|
+
if (!t4__namespace.isJSXIdentifier(openingName)) return;
|
|
354
778
|
const transform = styledTransforms.get(openingName.name);
|
|
355
779
|
if (!transform) return;
|
|
356
780
|
path.node.openingElement.name = transform.target.jsxName;
|
|
357
781
|
if (path.node.closingElement) {
|
|
358
782
|
path.node.closingElement.name = transform.target.jsxName;
|
|
359
783
|
}
|
|
360
|
-
|
|
784
|
+
const classNameExpression = transform.mode === "component" ? buildComponentClassNameExpression(
|
|
785
|
+
transform.classConstName,
|
|
786
|
+
transform.variantProps,
|
|
787
|
+
collectPropValuesFromJsx(path.node.openingElement, new Set(transform.variantProps))
|
|
788
|
+
) : t4__namespace.identifier(transform.classConstName);
|
|
789
|
+
updateClassNameAttribute(path.node.openingElement, classNameExpression);
|
|
790
|
+
if (transform.propVars.length > 0) {
|
|
791
|
+
const propNames = new Set(transform.propVars.map((propVar) => propVar.propName));
|
|
792
|
+
const propValues = collectPropValuesFromJsx(path.node.openingElement, propNames);
|
|
793
|
+
if (propValues.size > 0) {
|
|
794
|
+
const assignVarsCall = buildAssignVarsCall(transform.propVars, propValues);
|
|
795
|
+
updateStyleAttribute(path.node.openingElement, assignVarsCall);
|
|
796
|
+
removeStyledProps(path.node.openingElement, propNames);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
if (transform.variantProps.length > 0) {
|
|
800
|
+
removeStyledProps(path.node.openingElement, new Set(transform.variantProps));
|
|
801
|
+
}
|
|
361
802
|
}
|
|
362
803
|
});
|
|
363
804
|
}
|
|
364
805
|
if (changed) {
|
|
365
|
-
|
|
806
|
+
ensureTypestylesImport(ast, needsVars);
|
|
366
807
|
cleanupUnusedImports(ast);
|
|
367
808
|
}
|
|
368
809
|
const output = generate__default.default(
|