@typestyles/migrate 0.0.0-unstable.00cf16386ea7

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/dist/cli.cjs ADDED
@@ -0,0 +1,967 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ var path = require('path');
5
+ var promises = require('fs/promises');
6
+ var diff = require('diff');
7
+ var fg = require('fast-glob');
8
+ var picomatch = require('picomatch');
9
+ var parser = require('@babel/parser');
10
+ var generate = require('@babel/generator');
11
+ var traverse = require('@babel/traverse');
12
+ var t4 = require('@babel/types');
13
+ var postcss = require('postcss');
14
+
15
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
16
+
17
+ function _interopNamespace(e) {
18
+ if (e && e.__esModule) return e;
19
+ var n = Object.create(null);
20
+ if (e) {
21
+ Object.keys(e).forEach(function (k) {
22
+ if (k !== 'default') {
23
+ var d = Object.getOwnPropertyDescriptor(e, k);
24
+ Object.defineProperty(n, k, d.get ? d : {
25
+ enumerable: true,
26
+ get: function () { return e[k]; }
27
+ });
28
+ }
29
+ });
30
+ }
31
+ n.default = e;
32
+ return Object.freeze(n);
33
+ }
34
+
35
+ var fg__default = /*#__PURE__*/_interopDefault(fg);
36
+ var picomatch__default = /*#__PURE__*/_interopDefault(picomatch);
37
+ var generate__default = /*#__PURE__*/_interopDefault(generate);
38
+ var traverse__default = /*#__PURE__*/_interopDefault(traverse);
39
+ var t4__namespace = /*#__PURE__*/_interopNamespace(t4);
40
+ var postcss__default = /*#__PURE__*/_interopDefault(postcss);
41
+
42
+ var DEFAULT_EXCLUDES = ["**/node_modules/**", "**/dist/**", "**/.next/**", "**/.turbo/**"];
43
+ function normalizeExtension(extension) {
44
+ return extension.startsWith(".") ? extension : `.${extension}`;
45
+ }
46
+ async function collectTargetFiles(cwd, targets, extensions, include, exclude) {
47
+ const normalizedTargets = targets.length > 0 ? targets : ["."];
48
+ const literalFiles = [];
49
+ const dynamicPatterns = [];
50
+ for (const target of normalizedTargets) {
51
+ const absolute = path.resolve(cwd, target);
52
+ try {
53
+ const targetStat = await promises.stat(absolute);
54
+ if (targetStat.isFile()) {
55
+ literalFiles.push(absolute);
56
+ } else if (targetStat.isDirectory()) {
57
+ dynamicPatterns.push(`${absolute.split("\\").join("/")}/**/*`);
58
+ }
59
+ } catch {
60
+ dynamicPatterns.push(target);
61
+ }
62
+ }
63
+ const globbed = await fg__default.default(dynamicPatterns, {
64
+ cwd,
65
+ absolute: true,
66
+ onlyFiles: true,
67
+ ignore: [...DEFAULT_EXCLUDES, ...exclude]
68
+ });
69
+ const extensionSet = new Set(extensions.map(normalizeExtension));
70
+ const includeMatchers = include.length > 0 ? include.map((pattern) => picomatch__default.default(pattern)) : null;
71
+ const unique = /* @__PURE__ */ new Set([...literalFiles, ...globbed]);
72
+ return Array.from(unique).filter((filePath) => extensionSet.has(path.extname(filePath))).filter((filePath) => {
73
+ if (!includeMatchers) return true;
74
+ const rel = path.relative(cwd, filePath).split("\\").join("/");
75
+ return includeMatchers.some((matcher) => matcher(rel));
76
+ }).sort();
77
+ }
78
+ function camelCaseProperty(property) {
79
+ return property.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
80
+ }
81
+ function toValueNode(value, varReplacements) {
82
+ const trimmed = value.trim();
83
+ if (varReplacements?.has(trimmed)) {
84
+ return varReplacements.get(trimmed);
85
+ }
86
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
87
+ return t4__namespace.numericLiteral(Number(trimmed));
88
+ }
89
+ return t4__namespace.stringLiteral(trimmed);
90
+ }
91
+ function toKeyNode(key) {
92
+ if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(key)) {
93
+ return t4__namespace.identifier(key);
94
+ }
95
+ return t4__namespace.stringLiteral(key);
96
+ }
97
+ function nodesToObject(nodes, warnings, varReplacements) {
98
+ const properties = [];
99
+ for (const node of nodes ?? []) {
100
+ if (node.type === "decl") {
101
+ const normalized = node.prop.startsWith("--") ? node.prop : camelCaseProperty(node.prop);
102
+ properties.push(
103
+ t4__namespace.objectProperty(toKeyNode(normalized), toValueNode(node.value, varReplacements))
104
+ );
105
+ continue;
106
+ }
107
+ if (node.type === "rule") {
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));
116
+ continue;
117
+ }
118
+ warnings.push({
119
+ message: `Unsupported CSS node "${node.type}" skipped.`
120
+ });
121
+ }
122
+ return t4__namespace.objectExpression(properties);
123
+ }
124
+ function cssToObjectExpression(cssText, warnings, varReplacements) {
125
+ try {
126
+ const root = postcss__default.default.parse(cssText);
127
+ return nodesToObject(root.nodes, warnings, varReplacements);
128
+ } catch (error) {
129
+ warnings.push({
130
+ message: `Could not parse CSS template literal: ${error.message}`
131
+ });
132
+ return null;
133
+ }
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
+ }
331
+
332
+ // src/transform.ts
333
+ function toKebabCase(input) {
334
+ return input.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/[_\s]+/g, "-").toLowerCase();
335
+ }
336
+ function memberExpressionToJsxName(expression) {
337
+ if (t4__namespace.isIdentifier(expression)) {
338
+ return t4__namespace.jsxIdentifier(expression.name);
339
+ }
340
+ if (t4__namespace.isMemberExpression(expression) && !expression.computed) {
341
+ const left = memberExpressionToJsxName(expression.object);
342
+ const right = t4__namespace.isIdentifier(expression.property) ? t4__namespace.jsxIdentifier(expression.property.name) : null;
343
+ if (!left || !right) return null;
344
+ return t4__namespace.jsxMemberExpression(left, right);
345
+ }
346
+ return null;
347
+ }
348
+ function parseStyledTarget(tag, styledNames) {
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) };
351
+ }
352
+ if (t4__namespace.isCallExpression(tag) && t4__namespace.isIdentifier(tag.callee) && styledNames.has(tag.callee.name)) {
353
+ const firstArg = tag.arguments[0];
354
+ if (!firstArg || !t4__namespace.isExpression(firstArg)) return null;
355
+ const jsxName = memberExpressionToJsxName(firstArg);
356
+ if (!jsxName) return null;
357
+ return { kind: "component", jsxName };
358
+ }
359
+ return null;
360
+ }
361
+ function addWarning(warnings, message, nodeName) {
362
+ warnings.push({ message, nodeName });
363
+ }
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")
371
+ ),
372
+ [t4__namespace.identifier("Boolean")]
373
+ ),
374
+ t4__namespace.identifier("join")
375
+ ),
376
+ [t4__namespace.stringLiteral(" ")]
377
+ );
378
+ }
379
+ function updateClassNameAttribute(openingElement, classNameExpression) {
380
+ const existingAttr = openingElement.attributes.find(
381
+ (attribute) => t4__namespace.isJSXAttribute(attribute) && t4__namespace.isJSXIdentifier(attribute.name, { name: "className" })
382
+ );
383
+ if (!existingAttr) {
384
+ openingElement.attributes.push(
385
+ t4__namespace.jsxAttribute(t4__namespace.jsxIdentifier("className"), t4__namespace.jsxExpressionContainer(classNameExpression))
386
+ );
387
+ return;
388
+ }
389
+ if (!existingAttr.value) {
390
+ existingAttr.value = t4__namespace.jsxExpressionContainer(classNameExpression);
391
+ return;
392
+ }
393
+ if (t4__namespace.isStringLiteral(existingAttr.value)) {
394
+ existingAttr.value = t4__namespace.jsxExpressionContainer(
395
+ createMergedClassExpression(t4__namespace.stringLiteral(existingAttr.value.value), classNameExpression)
396
+ );
397
+ return;
398
+ }
399
+ if (t4__namespace.isJSXExpressionContainer(existingAttr.value)) {
400
+ existingAttr.value = t4__namespace.jsxExpressionContainer(
401
+ createMergedClassExpression(
402
+ existingAttr.value.expression,
403
+ classNameExpression
404
+ )
405
+ );
406
+ }
407
+ }
408
+ function ensureTypestylesImport(ast, needsVars) {
409
+ const requiredSpecifiers = /* @__PURE__ */ new Set(["styles"]);
410
+ if (needsVars) {
411
+ requiredSpecifiers.add("createVar");
412
+ requiredSpecifiers.add("assignVars");
413
+ }
414
+ let typestylesImport = null;
415
+ for (const statement of ast.program.body) {
416
+ if (t4__namespace.isImportDeclaration(statement) && statement.source.value === "typestyles") {
417
+ typestylesImport = statement;
418
+ break;
419
+ }
420
+ }
421
+ const buildSpecifiers = (names) => [...names].map((name) => t4__namespace.importSpecifier(t4__namespace.identifier(name), t4__namespace.identifier(name)));
422
+ if (!typestylesImport) {
423
+ ast.program.body.unshift(
424
+ t4__namespace.importDeclaration(buildSpecifiers(requiredSpecifiers), t4__namespace.stringLiteral("typestyles"))
425
+ );
426
+ return;
427
+ }
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 })
431
+ );
432
+ if (!hasSpecifier) {
433
+ typestylesImport.specifiers.push(t4__namespace.importSpecifier(t4__namespace.identifier(name), t4__namespace.identifier(name)));
434
+ }
435
+ }
436
+ }
437
+ function cleanupUnusedImports(ast) {
438
+ traverse__default.default(ast, {
439
+ Program(path) {
440
+ path.scope.crawl();
441
+ },
442
+ ImportDeclaration(path) {
443
+ const unusedLocals = path.node.specifiers.filter((specifier) => {
444
+ if (path.node.source.value === "typestyles" && t4__namespace.isImportSpecifier(specifier) && (specifier.local.name === "styles" || specifier.local.name === "createVar" || specifier.local.name === "assignVars")) {
445
+ return false;
446
+ }
447
+ const local = specifier.local.name;
448
+ const binding = path.scope.getBinding(local);
449
+ return !binding || binding.referencePaths.length === 0;
450
+ });
451
+ if (unusedLocals.length === 0) return;
452
+ path.node.specifiers = path.node.specifiers.filter(
453
+ (specifier) => !unusedLocals.includes(specifier)
454
+ );
455
+ if (path.node.specifiers.length === 0) {
456
+ path.remove();
457
+ }
458
+ }
459
+ });
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
+ }
632
+ function isOnlyJsxReferences(binding) {
633
+ return binding.referencePaths.every((referencePath) => {
634
+ const parent = referencePath.parentPath;
635
+ if (!parent) return false;
636
+ return parent.isJSXOpeningElement() && parent.get("name") === referencePath || parent.isJSXClosingElement() && parent.get("name") === referencePath;
637
+ });
638
+ }
639
+ function migrateSource(filePath, source) {
640
+ const warnings = [];
641
+ let changed = false;
642
+ const ast = parser.parse(source, {
643
+ sourceType: "module",
644
+ plugins: ["typescript", "jsx"]
645
+ });
646
+ const styledNames = /* @__PURE__ */ new Set();
647
+ const cssTagNames = /* @__PURE__ */ new Set();
648
+ const styledTransforms = /* @__PURE__ */ new Map();
649
+ let needsVars = false;
650
+ traverse__default.default(ast, {
651
+ ImportDeclaration(path) {
652
+ if (path.node.source.value === "styled-components" || path.node.source.value === "@emotion/styled") {
653
+ for (const specifier of path.node.specifiers) {
654
+ if (t4__namespace.isImportDefaultSpecifier(specifier)) {
655
+ styledNames.add(specifier.local.name);
656
+ }
657
+ if (t4__namespace.isImportSpecifier(specifier) && t4__namespace.isIdentifier(specifier.imported, { name: "css" })) {
658
+ cssTagNames.add(specifier.local.name);
659
+ }
660
+ }
661
+ }
662
+ if (path.node.source.value === "@emotion/react" || path.node.source.value === "@emotion/css") {
663
+ for (const specifier of path.node.specifiers) {
664
+ if (t4__namespace.isImportSpecifier(specifier) && t4__namespace.isIdentifier(specifier.imported, { name: "css" })) {
665
+ cssTagNames.add(specifier.local.name);
666
+ }
667
+ }
668
+ }
669
+ }
670
+ });
671
+ traverse__default.default(ast, {
672
+ VariableDeclarator(path) {
673
+ if (!t4__namespace.isIdentifier(path.node.id)) return;
674
+ if (!t4__namespace.isTaggedTemplateExpression(path.node.init)) return;
675
+ const variableName = path.node.id.name;
676
+ const binding = path.scope.getBinding(variableName);
677
+ if (!binding) return;
678
+ const template = path.node.init.quasi;
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,
708
+ warnings,
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
+ }
725
+ return;
726
+ }
727
+ const cssText = template.quasis.map((quasi) => quasi.value.cooked ?? "").join("");
728
+ const objectExpression4 = cssToObjectExpression(cssText, warnings);
729
+ if (!objectExpression4) {
730
+ addWarning(warnings, "Skipped because CSS could not be parsed.", variableName);
731
+ return;
732
+ }
733
+ if (styledTarget) {
734
+ const declaration = path.parentPath;
735
+ if (declaration.parentPath?.isExportNamedDeclaration() || declaration.parentPath?.isExportDefaultDeclaration()) {
736
+ addWarning(
737
+ warnings,
738
+ "Skipped exported styled component to avoid changing external API shape.",
739
+ variableName
740
+ );
741
+ return;
742
+ }
743
+ if (!isOnlyJsxReferences(binding)) {
744
+ addWarning(warnings, "Skipped styled component with non-JSX references.", variableName);
745
+ return;
746
+ }
747
+ const classConstName = path.scope.generateUidIdentifier(`${variableName}Class`).name;
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]
752
+ );
753
+ styledTransforms.set(variableName, {
754
+ originalName: variableName,
755
+ mode: "class",
756
+ classConstName,
757
+ target: styledTarget,
758
+ propVars: [],
759
+ variantProps: []
760
+ });
761
+ changed = true;
762
+ return;
763
+ }
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]
768
+ );
769
+ changed = true;
770
+ }
771
+ }
772
+ });
773
+ if (styledTransforms.size > 0) {
774
+ traverse__default.default(ast, {
775
+ JSXElement(path) {
776
+ const openingName = path.node.openingElement.name;
777
+ if (!t4__namespace.isJSXIdentifier(openingName)) return;
778
+ const transform = styledTransforms.get(openingName.name);
779
+ if (!transform) return;
780
+ path.node.openingElement.name = transform.target.jsxName;
781
+ if (path.node.closingElement) {
782
+ path.node.closingElement.name = transform.target.jsxName;
783
+ }
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
+ }
802
+ }
803
+ });
804
+ }
805
+ if (changed) {
806
+ ensureTypestylesImport(ast, needsVars);
807
+ cleanupUnusedImports(ast);
808
+ }
809
+ const output = generate__default.default(
810
+ ast,
811
+ {
812
+ retainLines: false,
813
+ comments: true,
814
+ concise: false
815
+ },
816
+ source
817
+ );
818
+ return {
819
+ filePath,
820
+ changed: changed && output.code !== source,
821
+ code: output.code,
822
+ warnings
823
+ };
824
+ }
825
+
826
+ // src/migrate.ts
827
+ function renderPatch(filePath, before, after) {
828
+ return diff.createPatch(filePath, before, after, "before", "after").split("\n").slice(2).join("\n");
829
+ }
830
+ async function runMigration(cwd, options) {
831
+ const files = await collectTargetFiles(
832
+ cwd,
833
+ options.targets,
834
+ options.extensions,
835
+ options.include,
836
+ options.exclude
837
+ );
838
+ const reportEntries = [];
839
+ let changedCount = 0;
840
+ let warningCount = 0;
841
+ for (const filePath of files) {
842
+ const before = await promises.readFile(filePath, "utf8");
843
+ const result = migrateSource(filePath, before);
844
+ const relativePath = path.relative(cwd, filePath);
845
+ warningCount += result.warnings.length;
846
+ if (result.changed) {
847
+ changedCount += 1;
848
+ if (options.write) {
849
+ await promises.writeFile(filePath, result.code, "utf8");
850
+ process.stdout.write(`updated ${relativePath}
851
+ `);
852
+ } else {
853
+ process.stdout.write(`
854
+ --- ${relativePath} (dry-run) ---
855
+ `);
856
+ process.stdout.write(`${renderPatch(relativePath, before, result.code)}
857
+ `);
858
+ }
859
+ }
860
+ for (const warning of result.warnings) {
861
+ const nodeLabel = warning.nodeName ? ` (${warning.nodeName})` : "";
862
+ process.stdout.write(`warning ${relativePath}${nodeLabel}: ${warning.message}
863
+ `);
864
+ }
865
+ reportEntries.push({
866
+ filePath: relativePath,
867
+ changed: result.changed,
868
+ warnings: result.warnings
869
+ });
870
+ }
871
+ const summary = {
872
+ filesScanned: files.length,
873
+ filesChanged: changedCount,
874
+ warnings: warningCount
875
+ };
876
+ process.stdout.write(
877
+ `
878
+ Scanned ${summary.filesScanned} files, changed ${summary.filesChanged}, warnings ${summary.warnings}.
879
+ `
880
+ );
881
+ const report = {
882
+ summary,
883
+ files: reportEntries
884
+ };
885
+ if (options.reportPath) {
886
+ await promises.mkdir(path.dirname(options.reportPath), { recursive: true });
887
+ await promises.writeFile(options.reportPath, `${JSON.stringify(report, null, 2)}
888
+ `, "utf8");
889
+ process.stdout.write(`Report written to ${options.reportPath}
890
+ `);
891
+ }
892
+ return report;
893
+ }
894
+
895
+ // src/cli.ts
896
+ var HELP_TEXT = `typestyles-migrate <paths...> [options]
897
+
898
+ Options:
899
+ --write Apply changes in-place (default is dry-run)
900
+ --include <glob> Include glob (repeatable)
901
+ --exclude <glob> Exclude glob (repeatable)
902
+ --extensions <list> Comma-separated extensions (default: .ts,.tsx)
903
+ --report <path> Write JSON report to the provided path
904
+ --help Show this help
905
+ `;
906
+ function parseCliArgs(argv) {
907
+ if (argv.includes("--help")) {
908
+ process.stdout.write(HELP_TEXT);
909
+ process.exit(0);
910
+ }
911
+ const targets = [];
912
+ const include = [];
913
+ const exclude = [];
914
+ let extensions = [".ts", ".tsx"];
915
+ let reportPath;
916
+ let write = false;
917
+ for (let i = 0; i < argv.length; i += 1) {
918
+ const token = argv[i];
919
+ if (token === "--write") {
920
+ write = true;
921
+ continue;
922
+ }
923
+ if (token === "--include" && argv[i + 1]) {
924
+ include.push(argv[i + 1]);
925
+ i += 1;
926
+ continue;
927
+ }
928
+ if (token === "--exclude" && argv[i + 1]) {
929
+ exclude.push(argv[i + 1]);
930
+ i += 1;
931
+ continue;
932
+ }
933
+ if (token === "--extensions" && argv[i + 1]) {
934
+ extensions = argv[i + 1].split(",").map((item) => item.trim()).filter(Boolean);
935
+ i += 1;
936
+ continue;
937
+ }
938
+ if (token === "--report" && argv[i + 1]) {
939
+ reportPath = path.resolve(process.cwd(), argv[i + 1]);
940
+ i += 1;
941
+ continue;
942
+ }
943
+ if (!token.startsWith("--")) {
944
+ targets.push(token);
945
+ }
946
+ }
947
+ return {
948
+ targets: targets.length > 0 ? targets : ["."],
949
+ write,
950
+ include,
951
+ exclude,
952
+ extensions,
953
+ reportPath
954
+ };
955
+ }
956
+ async function main() {
957
+ const args = process.argv.slice(2);
958
+ const options = parseCliArgs(args);
959
+ await runMigration(process.cwd(), options);
960
+ }
961
+ main().catch((error) => {
962
+ process.stderr.write(`${error.message}
963
+ `);
964
+ process.exit(1);
965
+ });
966
+ //# sourceMappingURL=cli.cjs.map
967
+ //# sourceMappingURL=cli.cjs.map