@wise/wds-codemods 0.0.1-experimental-cc95209 → 0.0.1-experimental-cbae00f
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/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/runCodemod.ts
|
|
4
|
-
import
|
|
4
|
+
import fs3 from "fs/promises";
|
|
5
5
|
import { execSync } from "child_process";
|
|
6
6
|
import path3 from "path";
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
@@ -77,6 +77,7 @@ async function loadTransformModules(transformsDir) {
|
|
|
77
77
|
var loadTransformModules_default = loadTransformModules;
|
|
78
78
|
|
|
79
79
|
// src/utils/reportManualReview.ts
|
|
80
|
+
import fs2 from "fs/promises";
|
|
80
81
|
import path2 from "path";
|
|
81
82
|
var REPORT_PATH = path2.resolve(process.cwd(), "codemod-report.txt");
|
|
82
83
|
|
|
@@ -108,15 +109,15 @@ async function runCodemod(transformsDir) {
|
|
|
108
109
|
console.debug(`Running: ${command}`);
|
|
109
110
|
const reportPath = path3.resolve(process.cwd(), "codemod-report.txt");
|
|
110
111
|
try {
|
|
111
|
-
await
|
|
112
|
-
await
|
|
112
|
+
await fs3.access(reportPath);
|
|
113
|
+
await fs3.rm(reportPath);
|
|
113
114
|
console.debug(`Removed existing report file: ${reportPath}`);
|
|
114
115
|
} catch {
|
|
115
116
|
console.debug(`No existing report file to remove: ${reportPath}`);
|
|
116
117
|
}
|
|
117
118
|
execSync(command, { stdio: "inherit" });
|
|
118
119
|
try {
|
|
119
|
-
const reportContent = await
|
|
120
|
+
const reportContent = await fs3.readFile(reportPath, "utf8");
|
|
120
121
|
const lines = reportContent.split("\n").filter(Boolean);
|
|
121
122
|
if (lines.length) {
|
|
122
123
|
console.log(
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/runCodemod.ts","../src/utils/getOptions.ts","../src/utils/loadTransformModules.ts","../src/utils/reportManualReview.ts","../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport fs from 'node:fs/promises';\n\nimport { execSync } from 'child_process';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { getOptions, handleError, loadTransformModules } from './utils';\n\nconst currentFilePath = fileURLToPath(import.meta.url);\nconst currentDirPath = path.dirname(currentFilePath);\n\nasync function runCodemod(transformsDir?: string) {\n try {\n const resolvedTransformsDir =\n transformsDir ?? path.resolve(currentDirPath, '../dist/transforms');\n console.debug(`Resolved transforms directory: ${resolvedTransformsDir}`);\n\n const { transformFiles } = await loadTransformModules(resolvedTransformsDir);\n\n if (transformFiles.length === 0) {\n throw new Error(`No transform scripts found in directory: ${resolvedTransformsDir}`);\n }\n\n const resolvedTransformFiles = await Promise.all(transformFiles);\n const options = await getOptions(resolvedTransformFiles);\n\n const codemodPath = path.resolve(resolvedTransformsDir, `${options.transformFile}.js`);\n console.debug(`Resolved codemod path: ${codemodPath}`);\n\n const args = [\n '-t',\n codemodPath,\n options.targetPath,\n options.dry ? '--dry' : '',\n options.print ? '--print' : '',\n options.ignorePattern\n ? options.ignorePattern\n .split(',')\n .map((pattern) => `--ignore-pattern=${pattern.trim()}`)\n .join(' ')\n : '',\n options.gitignore ? '--gitignore' : '',\n ].filter(Boolean);\n\n const command = `npx jscodeshift ${args.join(' ')}`;\n\n console.debug(`Running: ${command}`);\n\n const reportPath = path.resolve(process.cwd(), 'codemod-report.txt');\n\n try {\n await fs.access(reportPath);\n await fs.rm(reportPath);\n console.debug(`Removed existing report file: ${reportPath}`);\n } catch {\n console.debug(`No existing report file to remove: ${reportPath}`);\n }\n\n execSync(command, { stdio: 'inherit' });\n\n try {\n const reportContent = await fs.readFile(reportPath, 'utf8');\n const lines = reportContent.split('\\n').filter(Boolean);\n if (lines.length) {\n console.log(\n `\\n⚠️ ${lines.length} manual review${lines.length > 1 ? 's are' : ' is'} required. See ${reportPath} for details.`,\n );\n } else {\n console.debug(`Report file exists but is empty: ${reportPath}`);\n }\n } catch {\n console.debug(`No report file generated - no manual reviews needed`);\n }\n } catch (error: unknown) {\n if (error instanceof Error) {\n console.error('Error running codemod:', error.message);\n } else {\n console.error('Error running codemod:', error);\n }\n if (process.env.NODE_ENV !== 'test') {\n process.exit(1);\n }\n }\n}\n\nexport { runCodemod };\n","import { confirm, input, select as list } from '@inquirer/prompts';\n\nasync function getOptions(transformFiles: string[]) {\n const args = process.argv.slice(2);\n if (args.length > 0) {\n const [transformFile, targetPath] = args;\n const dry = args.includes('--dry') || args.includes('--dry-run');\n const print = args.includes('--print');\n const ignorePatternIndex = args.findIndex((arg) => arg === '--ignore-pattern');\n let ignorePattern: string | undefined;\n if (ignorePatternIndex !== -1 && args.length > ignorePatternIndex + 1) {\n ignorePattern = args[ignorePatternIndex + 1];\n }\n const gitignore = args.includes('--gitignore');\n const noGitignore = args.includes('--no-gitignore');\n\n if (!transformFile || !transformFiles.includes(transformFile)) {\n throw new Error('Invalid transform file specified.');\n }\n if (!targetPath) {\n throw new Error('Target path cannot be empty.');\n }\n\n // If both --gitignore and --no-gitignore are specified, prioritize --gitignore\n const useGitignore = !!(gitignore || (!gitignore && !noGitignore));\n\n return { transformFile, targetPath, dry, print, ignorePattern, gitignore: useGitignore };\n }\n\n const transformFile = await list({\n message: 'Select a codemod transform to run:',\n choices: transformFiles.map((file) => ({ name: file, value: file })),\n });\n\n const targetPath = await input({\n message: 'Enter the target directory or file path to run codemod on:',\n validate: (value) => value.trim() !== '' || 'Target path cannot be empty',\n });\n\n const dry = await confirm({\n message: 'Run in dry mode (no changes written to files)?',\n default: true,\n });\n\n const print = await confirm({\n message: 'Print transformed source to console?',\n default: false,\n });\n\n const ignorePattern = await input({\n message: 'Enter ignore pattern(s) (comma separated) or leave empty:',\n validate: (value) => true,\n });\n\n const gitignore = await confirm({\n message: 'Respect .gitignore files?',\n default: true,\n });\n\n return { transformFile, targetPath, dry, print, ignorePattern, gitignore };\n}\n\nexport default getOptions;\n","import { promises as fs } from 'fs';\nimport path from 'path';\n\ninterface TransformModule {\n default: {\n default: unknown;\n };\n}\n\nasync function loadTransformModules(transformsDir: string) {\n let transformModules: Record<string, unknown> = {};\n\n const files = await fs.readdir(transformsDir);\n const transformFiles = await Promise.all(\n files\n .filter((file) => file.endsWith('.js'))\n .map(async (file) => {\n const transformPath = path.join(transformsDir, file);\n const transformModule = (await import(transformPath)) as TransformModule;\n transformModules = { ...transformModules, [file]: transformModule.default.default };\n return file.replace('.js', '');\n }),\n );\n\n return { transformModules, transformFiles };\n}\n\nexport default loadTransformModules;\n","import fs from 'node:fs/promises';\n\nimport path from 'path';\n\nconst REPORT_PATH = path.resolve(process.cwd(), 'codemod-report.txt');\n\nconst reportManualReview = async (filePath: string, message: string): Promise<void> => {\n const lineMatch = /at line (\\d+)/u.exec(message);\n const lineNumber = lineMatch?.[1];\n\n const cleanMessage = message.replace(/ at line \\d+/u, '');\n const lineInfo = lineNumber ? `:${lineNumber}` : '';\n\n await fs.appendFile(REPORT_PATH, `[${filePath}${lineInfo}] ${cleanMessage}\\n`, 'utf8');\n};\n\nexport default reportManualReview;\n","#!/usr/bin/env node\nimport { runCodemod } from './runCodemod';\n\nvoid runCodemod();\n"],"mappings":"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","names":["fs","path","transformFile","targetPath","dry","print","ignorePattern","gitignore","path","path","fs"]}
|
|
1
|
+
{"version":3,"sources":["../src/runCodemod.ts","../src/utils/getOptions.ts","../src/utils/loadTransformModules.ts","../src/utils/reportManualReview.ts","../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport fs from 'node:fs/promises';\n\nimport { execSync } from 'child_process';\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { getOptions, handleError, loadTransformModules } from './utils';\n\nconst currentFilePath = fileURLToPath(import.meta.url);\nconst currentDirPath = path.dirname(currentFilePath);\n\nasync function runCodemod(transformsDir?: string) {\n try {\n const resolvedTransformsDir =\n transformsDir ?? path.resolve(currentDirPath, '../dist/transforms');\n console.debug(`Resolved transforms directory: ${resolvedTransformsDir}`);\n\n const { transformFiles } = await loadTransformModules(resolvedTransformsDir);\n\n if (transformFiles.length === 0) {\n throw new Error(`No transform scripts found in directory: ${resolvedTransformsDir}`);\n }\n\n const resolvedTransformFiles = await Promise.all(transformFiles);\n const options = await getOptions(resolvedTransformFiles);\n\n const codemodPath = path.resolve(resolvedTransformsDir, `${options.transformFile}.js`);\n console.debug(`Resolved codemod path: ${codemodPath}`);\n\n const args = [\n '-t',\n codemodPath,\n options.targetPath,\n options.dry ? '--dry' : '',\n options.print ? '--print' : '',\n options.ignorePattern\n ? options.ignorePattern\n .split(',')\n .map((pattern) => `--ignore-pattern=${pattern.trim()}`)\n .join(' ')\n : '',\n options.gitignore ? '--gitignore' : '',\n ].filter(Boolean);\n\n const command = `npx jscodeshift ${args.join(' ')}`;\n\n console.debug(`Running: ${command}`);\n\n const reportPath = path.resolve(process.cwd(), 'codemod-report.txt');\n\n try {\n await fs.access(reportPath);\n await fs.rm(reportPath);\n console.debug(`Removed existing report file: ${reportPath}`);\n } catch {\n console.debug(`No existing report file to remove: ${reportPath}`);\n }\n\n execSync(command, { stdio: 'inherit' });\n\n try {\n const reportContent = await fs.readFile(reportPath, 'utf8');\n const lines = reportContent.split('\\n').filter(Boolean);\n if (lines.length) {\n console.log(\n `\\n⚠️ ${lines.length} manual review${lines.length > 1 ? 's are' : ' is'} required. See ${reportPath} for details.`,\n );\n } else {\n console.debug(`Report file exists but is empty: ${reportPath}`);\n }\n } catch {\n console.debug(`No report file generated - no manual reviews needed`);\n }\n } catch (error: unknown) {\n if (error instanceof Error) {\n console.error('Error running codemod:', error.message);\n } else {\n console.error('Error running codemod:', error);\n }\n if (process.env.NODE_ENV !== 'test') {\n process.exit(1);\n }\n }\n}\n\nexport { runCodemod };\n","import { confirm, input, select as list } from '@inquirer/prompts';\n\nasync function getOptions(transformFiles: string[]) {\n const args = process.argv.slice(2);\n if (args.length > 0) {\n const [transformFile, targetPath] = args;\n const dry = args.includes('--dry') || args.includes('--dry-run');\n const print = args.includes('--print');\n const ignorePatternIndex = args.findIndex((arg) => arg === '--ignore-pattern');\n let ignorePattern: string | undefined;\n if (ignorePatternIndex !== -1 && args.length > ignorePatternIndex + 1) {\n ignorePattern = args[ignorePatternIndex + 1];\n }\n const gitignore = args.includes('--gitignore');\n const noGitignore = args.includes('--no-gitignore');\n\n if (!transformFile || !transformFiles.includes(transformFile)) {\n throw new Error('Invalid transform file specified.');\n }\n if (!targetPath) {\n throw new Error('Target path cannot be empty.');\n }\n\n // If both --gitignore and --no-gitignore are specified, prioritize --gitignore\n const useGitignore = !!(gitignore || (!gitignore && !noGitignore));\n\n return { transformFile, targetPath, dry, print, ignorePattern, gitignore: useGitignore };\n }\n\n const transformFile = await list({\n message: 'Select a codemod transform to run:',\n choices: transformFiles.map((file) => ({ name: file, value: file })),\n });\n\n const targetPath = await input({\n message: 'Enter the target directory or file path to run codemod on:',\n validate: (value) => value.trim() !== '' || 'Target path cannot be empty',\n });\n\n const dry = await confirm({\n message: 'Run in dry mode (no changes written to files)?',\n default: true,\n });\n\n const print = await confirm({\n message: 'Print transformed source to console?',\n default: false,\n });\n\n const ignorePattern = await input({\n message: 'Enter ignore pattern(s) (comma separated) or leave empty:',\n validate: (value) => true,\n });\n\n const gitignore = await confirm({\n message: 'Respect .gitignore files?',\n default: true,\n });\n\n return { transformFile, targetPath, dry, print, ignorePattern, gitignore };\n}\n\nexport default getOptions;\n","import { promises as fs } from 'fs';\nimport path from 'path';\n\ninterface TransformModule {\n default: {\n default: unknown;\n };\n}\n\nasync function loadTransformModules(transformsDir: string) {\n let transformModules: Record<string, unknown> = {};\n\n const files = await fs.readdir(transformsDir);\n const transformFiles = await Promise.all(\n files\n .filter((file) => file.endsWith('.js'))\n .map(async (file) => {\n const transformPath = path.join(transformsDir, file);\n const transformModule = (await import(transformPath)) as TransformModule;\n transformModules = { ...transformModules, [file]: transformModule.default.default };\n return file.replace('.js', '');\n }),\n );\n\n return { transformModules, transformFiles };\n}\n\nexport default loadTransformModules;\n","import fs from 'node:fs/promises';\n\nimport path from 'path';\n\nconst REPORT_PATH = path.resolve(process.cwd(), 'codemod-report.txt');\n\nconst reportManualReview = async (filePath: string, message: string): Promise<void> => {\n const lineMatch = /at line (\\d+)/u.exec(message);\n const lineNumber = lineMatch?.[1];\n\n const cleanMessage = message.replace(/ at line \\d+/u, '');\n const lineInfo = lineNumber ? `:${lineNumber}` : '';\n\n await fs.appendFile(REPORT_PATH, `[${filePath}${lineInfo}] ${cleanMessage}\\n`, 'utf8');\n};\n\nexport default reportManualReview;\n","#!/usr/bin/env node\nimport { runCodemod } from './runCodemod';\n\nvoid runCodemod();\n"],"mappings":"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","names":["fs","path","transformFile","targetPath","dry","print","ignorePattern","gitignore","fs","path","path","fs"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/utils/reportManualReview.ts
|
|
2
|
-
import fs from "
|
|
2
|
+
import fs from "fs/promises";
|
|
3
3
|
import path from "path";
|
|
4
4
|
var REPORT_PATH = path.resolve(process.cwd(), "codemod-report.txt");
|
|
5
5
|
var reportManualReview = async (filePath, message) => {
|
|
@@ -12,9 +12,6 @@ var reportManualReview = async (filePath, message) => {
|
|
|
12
12
|
};
|
|
13
13
|
var reportManualReview_default = reportManualReview;
|
|
14
14
|
|
|
15
|
-
// src/transforms/helpers/createTestTransform.ts
|
|
16
|
-
import { applyTransform } from "jscodeshift/src/testUtils";
|
|
17
|
-
|
|
18
15
|
// src/transforms/helpers/hasImport.ts
|
|
19
16
|
function hasImport(root, sourceValue, importName, j) {
|
|
20
17
|
const importDeclarations = root.find(j.ImportDeclaration, {
|
|
@@ -335,15 +332,12 @@ var resolveType = (type, htmlType) => {
|
|
|
335
332
|
"pay",
|
|
336
333
|
"secondary",
|
|
337
334
|
"danger",
|
|
338
|
-
"link"
|
|
339
|
-
"button",
|
|
340
|
-
"reset",
|
|
341
|
-
"submit"
|
|
335
|
+
"link"
|
|
342
336
|
];
|
|
343
337
|
return type && legacyButtonTypes.includes(type) ? type : null;
|
|
344
338
|
};
|
|
345
339
|
var convertEnumValue = (value) => {
|
|
346
|
-
if (!value) return
|
|
340
|
+
if (!value) return value;
|
|
347
341
|
const strippedValue = value.replace(/^['"]|['"]$/gu, "");
|
|
348
342
|
const enumMapping = {
|
|
349
343
|
"Priority.SECONDARY": "secondary",
|
|
@@ -351,17 +345,9 @@ var convertEnumValue = (value) => {
|
|
|
351
345
|
"Priority.TERTIARY": "tertiary",
|
|
352
346
|
"ControlType.NEGATIVE": "negative",
|
|
353
347
|
"ControlType.POSITIVE": "positive",
|
|
354
|
-
"ControlType.ACCENT": "accent"
|
|
355
|
-
"ControlType.BUTTON": "button",
|
|
356
|
-
"ControlType.RESET": "reset",
|
|
357
|
-
"HtmlType.SUBMIT": "submit",
|
|
358
|
-
"HtmlType.BUTTON": "button",
|
|
359
|
-
"HtmlType.RESET": "reset",
|
|
360
|
-
"Sentiment.NEGATIVE": "negative"
|
|
348
|
+
"ControlType.ACCENT": "accent"
|
|
361
349
|
};
|
|
362
|
-
|
|
363
|
-
const converted = enumMapping[strippedValue] || strippedValue;
|
|
364
|
-
return { converted, wasEnum };
|
|
350
|
+
return enumMapping[strippedValue] || strippedValue;
|
|
365
351
|
};
|
|
366
352
|
var transformer = (file, api, options) => {
|
|
367
353
|
const j = api.jscodeshift;
|
|
@@ -445,114 +431,107 @@ var transformer = (file, api, options) => {
|
|
|
445
431
|
iconUtils_default(j, path2.node.children, iconImports, openingElement);
|
|
446
432
|
const legacyProps = {};
|
|
447
433
|
const legacyPropNames = ["priority", "size", "type", "htmlType", "sentiment"];
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
if (attr.type === "JSXAttribute" && attr.name && attr.name.type === "JSXIdentifier" && legacyPropNames.includes(attr.name.name)) {
|
|
434
|
+
openingElement.attributes?.forEach((attr) => {
|
|
435
|
+
if (attr.type === "JSXAttribute" && attr.name && attr.name.type === "JSXIdentifier") {
|
|
451
436
|
const { name } = attr.name;
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
legacyProps[name] = converted;
|
|
462
|
-
}
|
|
463
|
-
} else {
|
|
464
|
-
legacyProps[name] = void 0;
|
|
465
|
-
}
|
|
466
|
-
const { wasEnum } = convertEnumValue(rawStringValue);
|
|
467
|
-
if (rawStringValue && wasEnum) {
|
|
468
|
-
migrated = true;
|
|
469
|
-
} else if (name === "size") {
|
|
470
|
-
const rawValue = legacyProps.size;
|
|
471
|
-
const resolved2 = resolveSize(rawValue);
|
|
472
|
-
const supportedSizes = ["xs", "sm", "md", "lg", "xl"];
|
|
473
|
-
if (typeof rawValue === "string" && typeof resolved2 === "string" && supportedSizes.includes(resolved2)) {
|
|
474
|
-
migrated = true;
|
|
475
|
-
} else if (typeof rawValue === "string") {
|
|
476
|
-
reporter.reportUnsupportedValue(path2, "size", rawValue);
|
|
477
|
-
} else if (rawValue !== void 0) {
|
|
478
|
-
reporter.reportAmbiguousExpression(path2, "size");
|
|
479
|
-
}
|
|
480
|
-
} else if (name === "priority") {
|
|
481
|
-
const rawValue = legacyProps.priority;
|
|
482
|
-
const { converted } = convertEnumValue(rawValue);
|
|
483
|
-
const mapped = resolvePriority(legacyProps.type, converted);
|
|
484
|
-
const supportedPriorities = ["primary", "secondary", "tertiary", "secondary-neutral"];
|
|
485
|
-
if (typeof rawValue === "string" && typeof mapped === "string" && supportedPriorities.includes(mapped)) {
|
|
486
|
-
migrated = true;
|
|
487
|
-
} else if (typeof rawValue === "string") {
|
|
488
|
-
reporter.reportUnsupportedValue(path2, "priority", rawValue);
|
|
489
|
-
} else if (rawValue !== void 0) {
|
|
490
|
-
reporter.reportAmbiguousExpression(path2, "priority");
|
|
491
|
-
}
|
|
492
|
-
} else if (name === "type" || name === "htmlType") {
|
|
493
|
-
const rawType2 = legacyProps.type;
|
|
494
|
-
const rawHtmlType2 = legacyProps.htmlType;
|
|
495
|
-
const resolvedType2 = typeof rawType2 === "string" ? rawType2 : rawType2 && typeof rawType2 === "object" ? convertEnumValue(j(rawType2).toSource()).converted : void 0;
|
|
496
|
-
const resolved2 = resolveType(resolvedType2, rawHtmlType2);
|
|
497
|
-
const supportedTypes2 = ["button", "reset", "submit"];
|
|
498
|
-
if (typeof resolved2 === "string" && supportedTypes2.includes(resolved2)) {
|
|
499
|
-
migrated = true;
|
|
500
|
-
} else if (typeof rawType2 === "string" || typeof rawHtmlType2 === "string") {
|
|
501
|
-
reporter.reportUnsupportedValue(path2, "type", rawType2 ?? rawHtmlType2 ?? "");
|
|
502
|
-
} else if (rawType2 !== void 0 || rawHtmlType2 !== void 0) {
|
|
503
|
-
reporter.reportAmbiguousExpression(path2, "type");
|
|
504
|
-
}
|
|
505
|
-
} else if (name === "sentiment") {
|
|
506
|
-
const rawValue = legacyProps.sentiment;
|
|
507
|
-
if (rawValue === "negative") {
|
|
508
|
-
migrated = true;
|
|
509
|
-
} else if (typeof rawValue === "string") {
|
|
510
|
-
reporter.reportUnsupportedValue(path2, "sentiment", rawValue);
|
|
511
|
-
} else if (rawValue !== void 0) {
|
|
512
|
-
reporter.reportAmbiguousExpression(path2, "sentiment");
|
|
437
|
+
if (legacyPropNames.includes(name)) {
|
|
438
|
+
if (attr.value) {
|
|
439
|
+
if (attr.value.type === "StringLiteral") {
|
|
440
|
+
legacyProps[name] = attr.value.value;
|
|
441
|
+
} else if (attr.value.type === "JSXExpressionContainer") {
|
|
442
|
+
legacyProps[name] = convertEnumValue(String(j(attr.value.expression).toSource()));
|
|
443
|
+
}
|
|
444
|
+
} else {
|
|
445
|
+
legacyProps[name] = void 0;
|
|
513
446
|
}
|
|
514
447
|
}
|
|
515
|
-
if (!migrated) keepAttributes.push(attr);
|
|
516
|
-
} else {
|
|
517
|
-
keepAttributes.push(attr);
|
|
518
448
|
}
|
|
519
449
|
});
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
newAttributes.push(j.jsxAttribute(j.jsxIdentifier("size"), j.literal(resolvedSize)));
|
|
450
|
+
if (openingElement.attributes) {
|
|
451
|
+
openingElement.attributes = openingElement.attributes.filter(
|
|
452
|
+
(attr) => !(attr.type === "JSXAttribute" && attr.name && legacyPropNames.includes(attr.name.name))
|
|
453
|
+
);
|
|
525
454
|
}
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
455
|
+
if ("size" in legacyProps) {
|
|
456
|
+
const rawValue = legacyProps.size;
|
|
457
|
+
const resolved = resolveSize(rawValue);
|
|
458
|
+
const supportedSizes = ["xs", "sm", "md", "lg", "xl"];
|
|
459
|
+
if (typeof rawValue === "string" && typeof resolved === "string" && supportedSizes.includes(resolved)) {
|
|
460
|
+
openingElement.attributes?.push(
|
|
461
|
+
j.jsxAttribute(j.jsxIdentifier("size"), j.literal(resolved))
|
|
462
|
+
);
|
|
463
|
+
} else if (typeof rawValue === "string") {
|
|
464
|
+
reporter.reportUnsupportedValue(path2, "size", rawValue);
|
|
465
|
+
} else if (rawValue !== void 0) {
|
|
466
|
+
reporter.reportAmbiguousExpression(path2, "size");
|
|
467
|
+
}
|
|
531
468
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
469
|
+
if ("priority" in legacyProps) {
|
|
470
|
+
const rawValue = legacyProps.priority;
|
|
471
|
+
const converted = convertEnumValue(rawValue);
|
|
472
|
+
const mapped = resolvePriority(legacyProps.type, converted);
|
|
473
|
+
const supportedPriorities = ["primary", "secondary", "tertiary", "secondary-neutral"];
|
|
474
|
+
if (typeof rawValue === "string" && typeof mapped === "string" && supportedPriorities.includes(mapped)) {
|
|
475
|
+
openingElement.attributes?.push(
|
|
476
|
+
j.jsxAttribute(j.jsxIdentifier("priority"), j.literal(mapped))
|
|
477
|
+
);
|
|
478
|
+
} else if (typeof rawValue === "string") {
|
|
479
|
+
reporter.reportUnsupportedValue(path2, "priority", rawValue);
|
|
480
|
+
} else if (rawValue !== void 0) {
|
|
481
|
+
reporter.reportAmbiguousExpression(path2, "priority");
|
|
540
482
|
}
|
|
541
|
-
|
|
542
|
-
|
|
483
|
+
}
|
|
484
|
+
if ("type" in legacyProps || "htmlType" in legacyProps) {
|
|
485
|
+
const rawType = legacyProps.type;
|
|
486
|
+
const rawHtmlType = legacyProps.htmlType;
|
|
487
|
+
const resolvedType = typeof rawType === "string" ? rawType : rawType && typeof rawType === "object" ? convertEnumValue(j(rawType).toSource()) : void 0;
|
|
488
|
+
const resolved = resolveType(resolvedType, rawHtmlType);
|
|
489
|
+
const supportedTypes = [
|
|
490
|
+
"accent",
|
|
491
|
+
"negative",
|
|
492
|
+
"positive",
|
|
493
|
+
"primary",
|
|
494
|
+
"pay",
|
|
495
|
+
"secondary",
|
|
496
|
+
"danger",
|
|
497
|
+
"link",
|
|
498
|
+
"submit",
|
|
499
|
+
"button",
|
|
500
|
+
"reset"
|
|
501
|
+
];
|
|
502
|
+
if (typeof resolved === "string" && supportedTypes.includes(resolved)) {
|
|
503
|
+
openingElement.attributes?.push(
|
|
504
|
+
j.jsxAttribute(j.jsxIdentifier("type"), j.literal(resolved))
|
|
505
|
+
);
|
|
506
|
+
if (resolved === "negative") {
|
|
507
|
+
openingElement.attributes?.push(
|
|
508
|
+
j.jsxAttribute(j.jsxIdentifier("sentiment"), j.literal("negative"))
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
} else if (typeof rawType === "string" || typeof rawHtmlType === "string") {
|
|
512
|
+
reporter.reportUnsupportedValue(path2, "type", rawType ?? rawHtmlType ?? "");
|
|
513
|
+
} else if (rawType !== void 0 || rawHtmlType !== void 0) {
|
|
514
|
+
reporter.reportAmbiguousExpression(path2, "type");
|
|
543
515
|
}
|
|
544
516
|
}
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
517
|
+
if ("sentiment" in legacyProps) {
|
|
518
|
+
const rawValue = legacyProps.sentiment;
|
|
519
|
+
if (rawValue === "negative") {
|
|
520
|
+
openingElement.attributes?.push(
|
|
521
|
+
j.jsxAttribute(j.jsxIdentifier("sentiment"), j.literal("negative"))
|
|
522
|
+
);
|
|
523
|
+
} else if (typeof rawValue === "string") {
|
|
524
|
+
reporter.reportUnsupportedValue(path2, "sentiment", rawValue);
|
|
525
|
+
} else if (rawValue !== void 0) {
|
|
526
|
+
reporter.reportAmbiguousExpression(path2, "sentiment");
|
|
527
|
+
}
|
|
548
528
|
}
|
|
549
|
-
Array.prototype.push.apply(newAttributes, keepAttributes);
|
|
550
529
|
let asIndex = -1;
|
|
551
530
|
let asValue = null;
|
|
552
531
|
let hrefExists = false;
|
|
553
532
|
let asAmbiguous = false;
|
|
554
533
|
let hrefAmbiguous = false;
|
|
555
|
-
|
|
534
|
+
openingElement.attributes?.forEach((attr, index) => {
|
|
556
535
|
if (attr.type === "JSXAttribute" && attr.name) {
|
|
557
536
|
if (attr.name.name === "as") {
|
|
558
537
|
if (attr.value) {
|
|
@@ -579,13 +558,17 @@ var transformer = (file, api, options) => {
|
|
|
579
558
|
}
|
|
580
559
|
if (asValue === "a") {
|
|
581
560
|
if (asIndex !== -1) {
|
|
582
|
-
|
|
561
|
+
openingElement.attributes = openingElement.attributes?.filter(
|
|
562
|
+
(_, idx) => idx !== asIndex
|
|
563
|
+
);
|
|
583
564
|
}
|
|
584
565
|
if (!hrefExists) {
|
|
585
|
-
|
|
566
|
+
openingElement.attributes = [
|
|
567
|
+
...openingElement.attributes ?? [],
|
|
568
|
+
j.jsxAttribute(j.jsxIdentifier("href"), j.literal("#"))
|
|
569
|
+
];
|
|
586
570
|
}
|
|
587
571
|
}
|
|
588
|
-
openingElement.attributes = newAttributes;
|
|
589
572
|
if ((openingElement.attributes ?? []).some((attr) => attr.type === "JSXSpreadAttribute")) {
|
|
590
573
|
reporter.reportSpreadProps(path2);
|
|
591
574
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/reportManualReview.ts","../../src/transforms/helpers/createTestTransform.ts","../../src/transforms/helpers/hasImport.ts","../../src/transforms/helpers/iconUtils.ts","../../src/transforms/helpers/jsxElementUtils.ts","../../src/transforms/helpers/jsxReportingUtils.ts","../../src/transforms/button/button.ts"],"sourcesContent":["import fs from 'node:fs/promises';\n\nimport path from 'path';\n\nconst REPORT_PATH = path.resolve(process.cwd(), 'codemod-report.txt');\n\nconst reportManualReview = async (filePath: string, message: string): Promise<void> => {\n const lineMatch = /at line (\\d+)/u.exec(message);\n const lineNumber = lineMatch?.[1];\n\n const cleanMessage = message.replace(/ at line \\d+/u, '');\n const lineInfo = lineNumber ? `:${lineNumber}` : '';\n\n await fs.appendFile(REPORT_PATH, `[${filePath}${lineInfo}] ${cleanMessage}\\n`, 'utf8');\n};\n\nexport default reportManualReview;\n","import type { Options, Transform } from 'jscodeshift';\nimport { applyTransform, type TestOptions } from 'jscodeshift/src/testUtils';\n\n/**\n * This function creates a test transform function that applies a given transformer to the input code.\n * It uses the 'tsx' parser to support both TypeScript and JSX syntax.\n *\n * The transform function is used to modify the input code based on the provided transformer.\n */\nfunction createTestTransform(transformer: Transform) {\n const options: Options = {};\n // Use 'tsx' parser to support both TypeScript and JSX syntax\n const testOptions: TestOptions = { parser: 'tsx' };\n return (input: { path?: string; source: string }) =>\n applyTransform(transformer, options, input, testOptions);\n}\n\nexport default createTestTransform;\n","import type { Collection, JSCodeshift } from 'jscodeshift';\n\n/**\n * Checks if a specific import exists in the given root collection and provides\n * a method to remove it if found.\n */\nfunction hasImport(\n root: Collection,\n sourceValue: string,\n importName: string,\n j: JSCodeshift,\n): { exists: boolean; remove: () => void } {\n const importDeclarations = root.find(j.ImportDeclaration, {\n source: { value: sourceValue },\n });\n\n if (importDeclarations.size() === 0) {\n return {\n exists: false,\n remove: () => {},\n };\n }\n\n const namedImport = importDeclarations.find(j.ImportSpecifier, {\n imported: { name: importName },\n });\n\n const defaultImport = importDeclarations.find(j.ImportDefaultSpecifier, {\n local: { name: importName },\n });\n\n const exists = namedImport.size() > 0 || defaultImport.size() > 0;\n\n const remove = () => {\n importDeclarations.forEach((path) => {\n const filteredSpecifiers =\n path.node.specifiers?.filter((specifier) => {\n if (specifier.type === 'ImportSpecifier' && specifier.imported.name === importName) {\n return false;\n }\n if (specifier.type === 'ImportDefaultSpecifier' && specifier.local?.name === importName) {\n return false;\n }\n return true;\n }) ?? [];\n\n if (filteredSpecifiers.length === 0) {\n path.prune();\n } else {\n j(path).replaceWith(\n j.importDeclaration(filteredSpecifiers, path.node.source, path.node.importKind),\n );\n }\n });\n };\n\n return { exists, remove };\n}\n\nexport default hasImport;\n","import type { JSCodeshift, JSXElement, JSXExpressionContainer } from 'jscodeshift';\n\n/**\n * Process children of a JSX element to detect icon components and add iconStart or iconEnd attributes accordingly.\n * This is specific to icon handling but can be reused in codemods dealing with icon children.\n */\nconst processIconChildren = (\n j: JSCodeshift,\n children: (JSXElement | JSXExpressionContainer | unknown)[] | undefined,\n iconImports: Set<string>,\n openingElement: JSXElement['openingElement'],\n) => {\n if (!children || !openingElement.attributes) return;\n\n const unwrapJsxElement = (node: unknown): JSXElement | unknown => {\n if (\n typeof node === 'object' &&\n node !== null &&\n 'type' in node &&\n node.type === 'JSXExpressionContainer' &&\n j.JSXElement.check((node as JSXExpressionContainer).expression)\n ) {\n return (node as JSXExpressionContainer).expression;\n }\n return node;\n };\n\n const totalChildren = children.length;\n\n // Find index of icon child\n const iconChildIndex = children.findIndex((child) => {\n const unwrapped = unwrapJsxElement(child);\n return (\n j.JSXElement.check(unwrapped) &&\n unwrapped.openingElement.name.type === 'JSXIdentifier' &&\n iconImports.has(unwrapped.openingElement.name.name)\n );\n });\n\n if (iconChildIndex === -1) return;\n\n const iconChild = unwrapJsxElement(children[iconChildIndex]) as JSXElement;\n\n if (!iconChild || iconChild.openingElement.name.type !== 'JSXIdentifier') return;\n\n const iconName = iconChild.openingElement.name.name;\n\n // Determine if icon is closer to start or end\n const distanceToStart = iconChildIndex;\n const distanceToEnd = totalChildren - 1 - iconChildIndex;\n const iconPropName = distanceToStart <= distanceToEnd ? 'addonStart' : 'addonEnd';\n\n // Build: { type: 'icon', value: <IconName /> }\n const iconObject = j.objectExpression([\n j.property('init', j.identifier('type'), j.literal('icon')),\n j.property('init', j.identifier('value'), iconChild),\n ]);\n const iconProp = j.jsxAttribute(\n j.jsxIdentifier(iconPropName),\n j.jsxExpressionContainer(iconObject),\n );\n\n openingElement.attributes.push(iconProp);\n\n // Remove the icon child\n children.splice(iconChildIndex, 1);\n\n // Helper to check if a child is whitespace-only JSXText\n const isWhitespaceJsxText = (node: unknown): boolean => {\n return (\n typeof node === 'object' &&\n node !== null &&\n (node as { type?: unknown }).type === 'JSXText' &&\n typeof (node as { value?: string }).value === 'string' &&\n (node as { value?: string }).value!.trim() === ''\n );\n };\n\n // Remove adjacent whitespace-only JSXText node if any\n if (iconChildIndex - 1 >= 0 && isWhitespaceJsxText(children[iconChildIndex - 1])) {\n children.splice(iconChildIndex - 1, 1);\n } else if (isWhitespaceJsxText(children[iconChildIndex])) {\n children.splice(iconChildIndex, 1);\n }\n};\n\nexport default processIconChildren;\n","import type {\n JSCodeshift,\n JSXAttribute,\n JSXElement,\n JSXIdentifier,\n JSXMemberExpression,\n JSXNamespacedName,\n JSXSpreadAttribute,\n} from 'jscodeshift';\n\n/**\n * Rename a JSX element name if it is a JSXIdentifier.\n */\nexport const setNameIfJSXIdentifier = (\n elementName: JSXIdentifier | JSXNamespacedName | JSXMemberExpression | undefined,\n newName: string,\n): JSXIdentifier | JSXNamespacedName | JSXMemberExpression | undefined => {\n if (elementName && elementName.type === 'JSXIdentifier') {\n return { ...elementName, name: newName };\n }\n return elementName;\n};\n\n/**\n * Check if a list of attributes contains a specific attribute by name.\n */\nexport const hasAttribute = (\n attributes: (JSXAttribute | JSXSpreadAttribute)[] | undefined,\n attributeName: string,\n): boolean => {\n return (\n Array.isArray(attributes) &&\n attributes.some(\n (attr): attr is JSXAttribute =>\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attr.name.name === attributeName,\n )\n );\n};\n\n/**\n * Check if a JSX element's openingElement has a specific attribute.\n */\nexport const hasAttributeOnElement = (\n element: JSXElement['openingElement'],\n attributeName: string,\n): boolean => {\n return hasAttribute(element.attributes, attributeName);\n};\n\n/**\n * Add specified attributes to a JSX element's openingElement if they are not already present.\n */\nexport const addAttributesIfMissing = (\n j: JSCodeshift,\n openingElement: JSXElement['openingElement'],\n attributesToAdd: { attribute: JSXAttribute; name: string }[],\n) => {\n if (!Array.isArray(openingElement.attributes)) return;\n const attrs = openingElement.attributes;\n attributesToAdd.forEach(({ attribute, name }) => {\n if (!hasAttributeOnElement(openingElement, name)) {\n attrs.push(attribute);\n }\n });\n};\n","import type { ASTPath, JSCodeshift, JSXAttribute, JSXElement, Node } from 'jscodeshift';\n\nexport interface ReporterOptions {\n jscodeshift: JSCodeshift;\n issues: string[];\n}\n\n/**\n * CodemodReporter is a utility class for reporting issues found during codemod transformations.\n * It provides methods to report issues related to JSX elements, props, and attributes.\n *\n * @example\n * ```typescript\n * const issues: string[] = [];\n * const reporter = createReporter(j, issues);\n *\n * // Report a deprecated prop\n * reporter.reportDeprecatedProp(buttonElement, 'flat', 'variant=\"text\"');\n *\n * // Report complex expression that needs review\n * reporter.reportAmbiguousExpression(element, 'size');\n *\n * // Auto-detect common issues\n * reporter.reportAttributeIssues(element);\n * ```\n */\nexport class CodemodReporter {\n private readonly j: JSCodeshift;\n private readonly issues: string[];\n\n constructor(options: ReporterOptions) {\n this.j = options.jscodeshift;\n this.issues = options.issues;\n }\n\n /**\n * Reports an issue with a JSX element\n */\n reportElement(element: JSXElement | ASTPath<JSXElement>, reason: string): void {\n const node = this.getNode(element);\n const componentName = this.getComponentName(node);\n const line = this.getLineNumber(node);\n\n this.addIssue(`Manual review required: <${componentName}> at line ${line} ${reason}.`);\n }\n\n /**\n * Reports an issue with a specific prop\n */\n reportProp(element: JSXElement | ASTPath<JSXElement>, propName: string, reason: string): void {\n const node = this.getNode(element);\n const componentName = this.getComponentName(node);\n const line = this.getLineNumber(node);\n\n this.addIssue(\n `Manual review required: prop \"${propName}\" on <${componentName}> at line ${line} ${reason}.`,\n );\n }\n\n /**\n * Reports an issue with a JSX attribute directly\n */\n reportAttribute(\n attr: JSXAttribute,\n element: JSXElement | ASTPath<JSXElement>,\n reason?: string,\n ): void {\n const node = this.getNode(element);\n const componentName = this.getComponentName(node);\n const propName = this.getAttributeName(attr);\n const line = this.getLineNumber(attr) || this.getLineNumber(node);\n\n const defaultReason = this.getAttributeReason(attr);\n const finalReason = reason || defaultReason;\n\n this.addIssue(\n `Manual review required: prop \"${propName}\" on <${componentName}> at line ${line} ${finalReason}.`,\n );\n }\n\n /**\n * Reports spread props on an element\n */\n reportSpreadProps(element: JSXElement | ASTPath<JSXElement>): void {\n this.reportElement(element, 'contains spread props that need manual review');\n }\n\n /**\n * Reports conflicting prop and children\n */\n reportPropWithChildren(element: JSXElement | ASTPath<JSXElement>, propName: string): void {\n this.reportProp(\n element,\n propName,\n `conflicts with children - both \"${propName}\" prop and children are present`,\n );\n }\n\n /**\n * Reports unsupported prop value\n */\n reportUnsupportedValue(\n element: JSXElement | ASTPath<JSXElement>,\n propName: string,\n value: string,\n ): void {\n this.reportProp(element, propName, `has unsupported value \"${value}\"`);\n }\n\n /**\n * Reports ambiguous expression in prop\n */\n reportAmbiguousExpression(element: JSXElement | ASTPath<JSXElement>, propName: string): void {\n this.reportProp(element, propName, 'contains a complex expression that needs manual review');\n }\n\n /**\n * Reports ambiguous children (like dynamic icons)\n */\n reportAmbiguousChildren(element: JSXElement | ASTPath<JSXElement>, childType = 'content'): void {\n this.reportElement(element, `contains ambiguous ${childType} that needs manual review`);\n }\n\n /**\n * Reports deprecated prop usage\n */\n reportDeprecatedProp(\n element: JSXElement | ASTPath<JSXElement>,\n propName: string,\n alternative?: string,\n ): void {\n const suggestion = alternative ? ` Use ${alternative} instead` : '';\n this.reportProp(element, propName, `is deprecated${suggestion}`);\n }\n\n /**\n * Reports missing required prop\n */\n reportMissingRequiredProp(element: JSXElement | ASTPath<JSXElement>, propName: string): void {\n this.reportProp(element, propName, 'is required but missing');\n }\n\n /**\n * Reports conflicting props\n */\n reportConflictingProps(element: JSXElement | ASTPath<JSXElement>, propNames: string[]): void {\n const propList = propNames.map((name) => `\"${name}\"`).join(', ');\n this.reportElement(element, `has conflicting props: ${propList} cannot be used together`);\n }\n\n /**\n * Auto-detects and reports common attribute issues\n */\n reportAttributeIssues(element: JSXElement | ASTPath<JSXElement>): void {\n const node = this.getNode(element);\n const { attributes } = node.openingElement;\n\n if (!attributes) return;\n\n // Check for spread props\n if (attributes.some((attr) => attr.type === 'JSXSpreadAttribute')) {\n this.reportSpreadProps(element);\n }\n\n // Check for complex expressions in attributes\n attributes.forEach((attr) => {\n if (attr.type === 'JSXAttribute' && attr.value?.type === 'JSXExpressionContainer') {\n this.reportAttribute(attr, element);\n }\n });\n }\n\n // Private helper methods\n private getNode(element: JSXElement | ASTPath<JSXElement>): JSXElement {\n return 'node' in element ? element.node : element;\n }\n\n private getComponentName(node: JSXElement): string {\n const { name } = node.openingElement;\n if (name.type === 'JSXIdentifier') {\n return name.name;\n }\n // Handle JSXMemberExpression, JSXNamespacedName, etc.\n return this.j(name).toSource();\n }\n\n private getLineNumber(node: JSXElement | JSXAttribute | Node): string {\n return node.loc?.start.line?.toString() || 'unknown';\n }\n\n private getAttributeName(attr: JSXAttribute): string {\n if (attr.name.type === 'JSXIdentifier') {\n return attr.name.name;\n }\n return this.j(attr.name).toSource();\n }\n\n private getAttributeReason(attr: JSXAttribute): string {\n if (!attr.value) return 'has no value';\n\n if (attr.value.type === 'JSXExpressionContainer') {\n const expr = attr.value.expression;\n const expressionType = expr.type.replace('Expression', '').toLowerCase();\n\n // Show actual value for simple cases\n if (expr.type === 'Identifier' || expr.type === 'MemberExpression') {\n const valueText = this.j(expr).toSource();\n return `contains a ${expressionType} (${valueText})`;\n }\n\n return `contains a complex ${expressionType} expression`;\n }\n\n return 'needs manual review';\n }\n\n private addIssue(message: string): void {\n this.issues.push(message);\n }\n}\n\nexport const createReporter = (j: JSCodeshift, issues: string[]): CodemodReporter => {\n return new CodemodReporter({ jscodeshift: j, issues });\n};\n","import type { API, FileInfo, JSCodeshift, Options } from 'jscodeshift';\n\nimport reportManualReview from '../../utils/reportManualReview';\nimport {\n addAttributesIfMissing,\n createReporter,\n hasAttributeOnElement,\n hasImport,\n processIconChildren,\n setNameIfJSXIdentifier,\n} from '../helpers';\n\nexport const parser = 'tsx';\n\ninterface LegacyProps {\n priority?: string;\n size?: string;\n type?: string;\n htmlType?: string;\n sentiment?: string;\n [key: string]: unknown;\n}\n\nconst priorityMapping: Record<string, Record<string, string>> = {\n accent: {\n primary: 'primary',\n secondary: 'secondary-neutral',\n tertiary: 'tertiary',\n },\n positive: {\n primary: 'primary',\n secondary: 'secondary-neutral',\n tertiary: 'secondary-neutral',\n },\n negative: {\n primary: 'primary',\n secondary: 'secondary',\n tertiary: 'secondary',\n },\n};\n\nconst sizeMap: Record<string, string> = {\n EXTRA_SMALL: 'xs',\n SMALL: 'sm',\n MEDIUM: 'md',\n LARGE: 'lg',\n EXTRA_LARGE: 'xl',\n xs: 'sm',\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n xl: 'xl',\n};\n\nconst resolveSize = (size?: string): string | undefined => {\n if (!size) return size;\n const match = /^Size\\.(EXTRA_SMALL|SMALL|MEDIUM|LARGE|EXTRA_LARGE)$/u.exec(size);\n if (match) {\n return sizeMap[match[1]];\n }\n return sizeMap[size] || size;\n};\n\nconst resolvePriority = (type?: string, priority?: string): string | undefined => {\n if (type && priority) {\n return priorityMapping[type]?.[priority] || priority;\n }\n return priority;\n};\n\nconst resolveType = (type?: string, htmlType?: string): string | null => {\n if (htmlType) {\n return htmlType;\n }\n\n const legacyButtonTypes = [\n 'accent',\n 'negative',\n 'positive',\n 'primary',\n 'pay',\n 'secondary',\n 'danger',\n 'link',\n 'button',\n 'reset',\n 'submit',\n ];\n return type && legacyButtonTypes.includes(type) ? type : null;\n};\n\nconst convertEnumValue = (value?: string): { converted: string | undefined; wasEnum: boolean } => {\n if (!value) return { converted: value, wasEnum: false };\n\n const strippedValue = value.replace(/^['\"]|['\"]$/gu, '');\n const enumMapping: Record<string, string> = {\n 'Priority.SECONDARY': 'secondary',\n 'Priority.PRIMARY': 'primary',\n 'Priority.TERTIARY': 'tertiary',\n 'ControlType.NEGATIVE': 'negative',\n 'ControlType.POSITIVE': 'positive',\n 'ControlType.ACCENT': 'accent',\n 'ControlType.BUTTON': 'button',\n 'ControlType.RESET': 'reset',\n 'HtmlType.SUBMIT': 'submit',\n 'HtmlType.BUTTON': 'button',\n 'HtmlType.RESET': 'reset',\n 'Sentiment.NEGATIVE': 'negative',\n };\n\n const wasEnum = strippedValue in enumMapping;\n const converted = enumMapping[strippedValue] || strippedValue;\n\n return { converted, wasEnum };\n};\n\n/**\n * This transform function modifies the Button and ActionButton components from the @transferwise/components library.\n * It updates the ActionButton component to use the Button component with specific attributes and mappings.\n * It also processes icon children and removes legacy props.\n *\n * @param {FileInfo} file - The file information object.\n * @param {API} api - The API object for jscodeshift.\n * @param {Options} options - The options object for jscodeshift.\n * @returns {string} - The transformed source code.\n */\nconst transformer = (file: FileInfo, api: API, options: Options) => {\n const j: JSCodeshift = api.jscodeshift;\n const root = j(file.source);\n const manualReviewIssues: string[] = [];\n\n // Create reporter instance\n const reporter = createReporter(j, manualReviewIssues);\n\n const { exists: hasButtonImport } = hasImport(root, '@transferwise/components', 'Button', j);\n const { exists: hasActionButtonImport, remove: removeActionButtonImport } = hasImport(\n root,\n '@transferwise/components',\n 'ActionButton',\n j,\n );\n\n const iconImports = new Set<string>();\n root.find(j.ImportDeclaration, { source: { value: '@transferwise/icons' } }).forEach((path) => {\n path.node.specifiers?.forEach((specifier) => {\n if (\n (specifier.type === 'ImportDefaultSpecifier' || specifier.type === 'ImportSpecifier') &&\n specifier.local\n ) {\n const localName = (specifier.local as { name: string }).name;\n iconImports.add(localName);\n }\n });\n });\n\n if (hasActionButtonImport) {\n root.findJSXElements('ActionButton').forEach((path) => {\n const { openingElement, closingElement } = path.node;\n\n openingElement.name = setNameIfJSXIdentifier(openingElement.name, 'Button')!;\n if (closingElement) {\n closingElement.name = setNameIfJSXIdentifier(closingElement.name, 'Button')!;\n }\n\n addAttributesIfMissing(j, openingElement, [\n { attribute: j.jsxAttribute(j.jsxIdentifier('v2')), name: 'v2' },\n { attribute: j.jsxAttribute(j.jsxIdentifier('size'), j.literal('sm')), name: 'size' },\n ]);\n\n processIconChildren(j, path.node.children, iconImports, openingElement);\n\n if ((openingElement.attributes ?? []).some((attr) => attr.type === 'JSXSpreadAttribute')) {\n reporter.reportSpreadProps(path);\n }\n\n const legacyPropNames = ['priority', 'text'];\n const legacyProps: LegacyProps = {};\n\n openingElement.attributes?.forEach((attr) => {\n if (attr.type === 'JSXAttribute' && attr.name && attr.name.type === 'JSXIdentifier') {\n const { name } = attr.name;\n if (legacyPropNames.includes(name)) {\n if (attr.value) {\n if (attr.value.type === 'StringLiteral') {\n legacyProps[name] = attr.value.value;\n } else if (attr.value.type === 'JSXExpressionContainer') {\n reporter.reportAttribute(attr, path);\n }\n }\n }\n }\n });\n\n const hasTextProp = openingElement.attributes?.some(\n (attr) =>\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attr.name.name === 'text',\n );\n const hasChildren = path.node.children?.some(\n (child) =>\n (child.type === 'JSXText' && child.value.trim() !== '') ||\n child.type === 'JSXElement' ||\n child.type === 'JSXExpressionContainer',\n );\n\n if (hasTextProp && hasChildren) {\n reporter.reportPropWithChildren(path, 'text');\n }\n\n (path.node.children || []).forEach((child) => {\n if (child.type === 'JSXExpressionContainer') {\n const expr = child.expression;\n if (\n expr.type === 'ConditionalExpression' ||\n expr.type === 'CallExpression' ||\n expr.type === 'Identifier' ||\n expr.type === 'MemberExpression'\n ) {\n reporter.reportAmbiguousChildren(path, 'icon');\n }\n }\n });\n });\n\n removeActionButtonImport();\n }\n\n if (hasButtonImport) {\n root.findJSXElements('Button').forEach((path) => {\n const { openingElement } = path.node;\n\n if (hasAttributeOnElement(openingElement, 'v2')) return;\n\n addAttributesIfMissing(j, openingElement, [\n { attribute: j.jsxAttribute(j.jsxIdentifier('v2')), name: 'v2' },\n ]);\n\n processIconChildren(j, path.node.children, iconImports, openingElement);\n\n const legacyProps: LegacyProps = {};\n const legacyPropNames = ['priority', 'size', 'type', 'htmlType', 'sentiment'];\n const keepAttributes: typeof openingElement.attributes = [];\n\n (openingElement.attributes ?? []).forEach((attr) => {\n if (\n attr.type === 'JSXAttribute' &&\n attr.name &&\n attr.name.type === 'JSXIdentifier' &&\n legacyPropNames.includes(attr.name.name)\n ) {\n const { name } = attr.name;\n let migrated = false;\n let rawStringValue: string | undefined;\n\n if (attr.value) {\n if (attr.value.type === 'StringLiteral') {\n rawStringValue = attr.value.value;\n legacyProps[name] = attr.value.value;\n } else if (attr.value.type === 'JSXExpressionContainer') {\n rawStringValue = String(j(attr.value.expression).toSource());\n const { converted } = convertEnumValue(rawStringValue);\n legacyProps[name] = converted;\n }\n } else {\n legacyProps[name] = undefined;\n }\n\n // Check if this is an enum value that should be removed\n const { wasEnum } = convertEnumValue(rawStringValue);\n if (rawStringValue && wasEnum) {\n migrated = true; // Remove enum values\n } else if (name === 'size') {\n const rawValue = legacyProps.size;\n const resolved = resolveSize(rawValue);\n const supportedSizes = ['xs', 'sm', 'md', 'lg', 'xl'];\n if (\n typeof rawValue === 'string' &&\n typeof resolved === 'string' &&\n supportedSizes.includes(resolved)\n ) {\n migrated = true;\n } else if (typeof rawValue === 'string') {\n reporter.reportUnsupportedValue(path, 'size', rawValue);\n } else if (rawValue !== undefined) {\n reporter.reportAmbiguousExpression(path, 'size');\n }\n } else if (name === 'priority') {\n const rawValue = legacyProps.priority;\n const { converted } = convertEnumValue(rawValue);\n const mapped = resolvePriority(legacyProps.type, converted);\n const supportedPriorities = ['primary', 'secondary', 'tertiary', 'secondary-neutral'];\n if (\n typeof rawValue === 'string' &&\n typeof mapped === 'string' &&\n supportedPriorities.includes(mapped)\n ) {\n migrated = true;\n } else if (typeof rawValue === 'string') {\n reporter.reportUnsupportedValue(path, 'priority', rawValue);\n } else if (rawValue !== undefined) {\n reporter.reportAmbiguousExpression(path, 'priority');\n }\n } else if (name === 'type' || name === 'htmlType') {\n const rawType = legacyProps.type;\n const rawHtmlType = legacyProps.htmlType;\n const resolvedType =\n typeof rawType === 'string'\n ? rawType\n : rawType && typeof rawType === 'object'\n ? convertEnumValue(j(rawType).toSource()).converted\n : undefined;\n const resolved = resolveType(resolvedType, rawHtmlType);\n const supportedTypes = ['button', 'reset', 'submit'];\n if (typeof resolved === 'string' && supportedTypes.includes(resolved)) {\n migrated = true;\n } else if (typeof rawType === 'string' || typeof rawHtmlType === 'string') {\n reporter.reportUnsupportedValue(path, 'type', rawType ?? rawHtmlType ?? '');\n } else if (rawType !== undefined || rawHtmlType !== undefined) {\n reporter.reportAmbiguousExpression(path, 'type');\n }\n } else if (name === 'sentiment') {\n const rawValue = legacyProps.sentiment;\n if (rawValue === 'negative') {\n migrated = true;\n } else if (typeof rawValue === 'string') {\n reporter.reportUnsupportedValue(path, 'sentiment', rawValue);\n } else if (rawValue !== undefined) {\n reporter.reportAmbiguousExpression(path, 'sentiment');\n }\n }\n\n if (!migrated) keepAttributes.push(attr);\n } else {\n keepAttributes.push(attr);\n }\n });\n\n const newAttributes = [];\n const rawSize = legacyProps.size;\n const resolvedSize = resolveSize(rawSize);\n if (\n typeof rawSize === 'string' &&\n typeof resolvedSize === 'string' &&\n ['xs', 'sm', 'md', 'lg', 'xl'].includes(resolvedSize)\n ) {\n newAttributes.push(j.jsxAttribute(j.jsxIdentifier('size'), j.literal(resolvedSize)));\n }\n\n const rawPriority = legacyProps.priority;\n const { converted: convertedPriority } = convertEnumValue(rawPriority);\n const mappedPriority = resolvePriority(legacyProps.type, convertedPriority);\n if (\n typeof rawPriority === 'string' &&\n typeof mappedPriority === 'string' &&\n ['primary', 'secondary', 'tertiary', 'secondary-neutral'].includes(mappedPriority)\n ) {\n newAttributes.push(j.jsxAttribute(j.jsxIdentifier('priority'), j.literal(mappedPriority)));\n }\n\n const rawType = legacyProps.type;\n const rawHtmlType = legacyProps.htmlType;\n const resolvedType =\n typeof rawType === 'string'\n ? rawType\n : rawType && typeof rawType === 'object'\n ? convertEnumValue(j(rawType).toSource()).converted\n : undefined;\n const resolved = resolveType(resolvedType, rawHtmlType);\n const supportedTypes = ['button', 'reset', 'submit', 'negative'];\n if (typeof resolved === 'string' && supportedTypes.includes(resolved)) {\n if (resolved !== 'negative') {\n newAttributes.push(j.jsxAttribute(j.jsxIdentifier('type'), j.literal(resolved)));\n }\n if (resolved === 'negative') {\n newAttributes.push(j.jsxAttribute(j.jsxIdentifier('sentiment'), j.literal('negative')));\n }\n }\n\n const rawSentiment = legacyProps.sentiment;\n if (rawSentiment === 'negative') {\n newAttributes.push(j.jsxAttribute(j.jsxIdentifier('sentiment'), j.literal('negative')));\n }\n\n Array.prototype.push.apply(newAttributes, keepAttributes);\n\n // as/href logic as before\n let asIndex = -1;\n let asValue: string | null = null;\n let hrefExists = false;\n let asAmbiguous = false;\n let hrefAmbiguous = false;\n\n newAttributes.forEach((attr, index) => {\n if (attr.type === 'JSXAttribute' && attr.name) {\n if (attr.name.name === 'as') {\n if (attr.value) {\n if (attr.value.type === 'StringLiteral') {\n asValue = attr.value.value;\n } else if (attr.value.type === 'JSXExpressionContainer') {\n asAmbiguous = true;\n reporter.reportAttribute(attr, path);\n }\n }\n asIndex = index;\n }\n if (attr.name.name === 'href') {\n hrefExists = true;\n if (attr.value && attr.value.type !== 'StringLiteral') {\n hrefAmbiguous = true;\n reporter.reportAttribute(attr, path);\n }\n }\n }\n });\n\n if (asValue && asValue !== 'a') {\n reporter.reportUnsupportedValue(path, 'as', asValue);\n }\n\n if (asValue === 'a') {\n if (asIndex !== -1) {\n newAttributes.splice(asIndex, 1);\n }\n if (!hrefExists) {\n newAttributes.push(j.jsxAttribute(j.jsxIdentifier('href'), j.literal('#')));\n }\n }\n\n openingElement.attributes = newAttributes;\n\n if ((openingElement.attributes ?? []).some((attr) => attr.type === 'JSXSpreadAttribute')) {\n reporter.reportSpreadProps(path);\n }\n });\n }\n\n if (manualReviewIssues.length > 0) {\n manualReviewIssues.forEach(async (issue) => {\n await reportManualReview(file.path, issue);\n });\n }\n\n return root.toSource();\n};\n\nexport default transformer;\n"],"mappings":"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","names":["path","path","resolved","rawType","rawHtmlType","resolvedType","supportedTypes"]}
|
|
1
|
+
{"version":3,"sources":["../../src/utils/reportManualReview.ts","../../src/transforms/helpers/hasImport.ts","../../src/transforms/helpers/iconUtils.ts","../../src/transforms/helpers/jsxElementUtils.ts","../../src/transforms/helpers/jsxReportingUtils.ts","../../src/transforms/button/button.ts"],"sourcesContent":["import fs from 'node:fs/promises';\n\nimport path from 'path';\n\nconst REPORT_PATH = path.resolve(process.cwd(), 'codemod-report.txt');\n\nconst reportManualReview = async (filePath: string, message: string): Promise<void> => {\n const lineMatch = /at line (\\d+)/u.exec(message);\n const lineNumber = lineMatch?.[1];\n\n const cleanMessage = message.replace(/ at line \\d+/u, '');\n const lineInfo = lineNumber ? `:${lineNumber}` : '';\n\n await fs.appendFile(REPORT_PATH, `[${filePath}${lineInfo}] ${cleanMessage}\\n`, 'utf8');\n};\n\nexport default reportManualReview;\n","import type { Collection, JSCodeshift } from 'jscodeshift';\n\n/**\n * Checks if a specific import exists in the given root collection and provides\n * a method to remove it if found.\n */\nfunction hasImport(\n root: Collection,\n sourceValue: string,\n importName: string,\n j: JSCodeshift,\n): { exists: boolean; remove: () => void } {\n const importDeclarations = root.find(j.ImportDeclaration, {\n source: { value: sourceValue },\n });\n\n if (importDeclarations.size() === 0) {\n return {\n exists: false,\n remove: () => {},\n };\n }\n\n const namedImport = importDeclarations.find(j.ImportSpecifier, {\n imported: { name: importName },\n });\n\n const defaultImport = importDeclarations.find(j.ImportDefaultSpecifier, {\n local: { name: importName },\n });\n\n const exists = namedImport.size() > 0 || defaultImport.size() > 0;\n\n const remove = () => {\n importDeclarations.forEach((path) => {\n const filteredSpecifiers =\n path.node.specifiers?.filter((specifier) => {\n if (specifier.type === 'ImportSpecifier' && specifier.imported.name === importName) {\n return false;\n }\n if (specifier.type === 'ImportDefaultSpecifier' && specifier.local?.name === importName) {\n return false;\n }\n return true;\n }) ?? [];\n\n if (filteredSpecifiers.length === 0) {\n path.prune();\n } else {\n j(path).replaceWith(\n j.importDeclaration(filteredSpecifiers, path.node.source, path.node.importKind),\n );\n }\n });\n };\n\n return { exists, remove };\n}\n\nexport default hasImport;\n","import type { JSCodeshift, JSXElement, JSXExpressionContainer } from 'jscodeshift';\n\n/**\n * Process children of a JSX element to detect icon components and add iconStart or iconEnd attributes accordingly.\n * This is specific to icon handling but can be reused in codemods dealing with icon children.\n */\nconst processIconChildren = (\n j: JSCodeshift,\n children: (JSXElement | JSXExpressionContainer | unknown)[] | undefined,\n iconImports: Set<string>,\n openingElement: JSXElement['openingElement'],\n) => {\n if (!children || !openingElement.attributes) return;\n\n const unwrapJsxElement = (node: unknown): JSXElement | unknown => {\n if (\n typeof node === 'object' &&\n node !== null &&\n 'type' in node &&\n node.type === 'JSXExpressionContainer' &&\n j.JSXElement.check((node as JSXExpressionContainer).expression)\n ) {\n return (node as JSXExpressionContainer).expression;\n }\n return node;\n };\n\n const totalChildren = children.length;\n\n // Find index of icon child\n const iconChildIndex = children.findIndex((child) => {\n const unwrapped = unwrapJsxElement(child);\n return (\n j.JSXElement.check(unwrapped) &&\n unwrapped.openingElement.name.type === 'JSXIdentifier' &&\n iconImports.has(unwrapped.openingElement.name.name)\n );\n });\n\n if (iconChildIndex === -1) return;\n\n const iconChild = unwrapJsxElement(children[iconChildIndex]) as JSXElement;\n\n if (!iconChild || iconChild.openingElement.name.type !== 'JSXIdentifier') return;\n\n const iconName = iconChild.openingElement.name.name;\n\n // Determine if icon is closer to start or end\n const distanceToStart = iconChildIndex;\n const distanceToEnd = totalChildren - 1 - iconChildIndex;\n const iconPropName = distanceToStart <= distanceToEnd ? 'addonStart' : 'addonEnd';\n\n // Build: { type: 'icon', value: <IconName /> }\n const iconObject = j.objectExpression([\n j.property('init', j.identifier('type'), j.literal('icon')),\n j.property('init', j.identifier('value'), iconChild),\n ]);\n const iconProp = j.jsxAttribute(\n j.jsxIdentifier(iconPropName),\n j.jsxExpressionContainer(iconObject),\n );\n\n openingElement.attributes.push(iconProp);\n\n // Remove the icon child\n children.splice(iconChildIndex, 1);\n\n // Helper to check if a child is whitespace-only JSXText\n const isWhitespaceJsxText = (node: unknown): boolean => {\n return (\n typeof node === 'object' &&\n node !== null &&\n (node as { type?: unknown }).type === 'JSXText' &&\n typeof (node as { value?: string }).value === 'string' &&\n (node as { value?: string }).value!.trim() === ''\n );\n };\n\n // Remove adjacent whitespace-only JSXText node if any\n if (iconChildIndex - 1 >= 0 && isWhitespaceJsxText(children[iconChildIndex - 1])) {\n children.splice(iconChildIndex - 1, 1);\n } else if (isWhitespaceJsxText(children[iconChildIndex])) {\n children.splice(iconChildIndex, 1);\n }\n};\n\nexport default processIconChildren;\n","import type {\n JSCodeshift,\n JSXAttribute,\n JSXElement,\n JSXIdentifier,\n JSXMemberExpression,\n JSXNamespacedName,\n JSXSpreadAttribute,\n} from 'jscodeshift';\n\n/**\n * Rename a JSX element name if it is a JSXIdentifier.\n */\nexport const setNameIfJSXIdentifier = (\n elementName: JSXIdentifier | JSXNamespacedName | JSXMemberExpression | undefined,\n newName: string,\n): JSXIdentifier | JSXNamespacedName | JSXMemberExpression | undefined => {\n if (elementName && elementName.type === 'JSXIdentifier') {\n return { ...elementName, name: newName };\n }\n return elementName;\n};\n\n/**\n * Check if a list of attributes contains a specific attribute by name.\n */\nexport const hasAttribute = (\n attributes: (JSXAttribute | JSXSpreadAttribute)[] | undefined,\n attributeName: string,\n): boolean => {\n return (\n Array.isArray(attributes) &&\n attributes.some(\n (attr): attr is JSXAttribute =>\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attr.name.name === attributeName,\n )\n );\n};\n\n/**\n * Check if a JSX element's openingElement has a specific attribute.\n */\nexport const hasAttributeOnElement = (\n element: JSXElement['openingElement'],\n attributeName: string,\n): boolean => {\n return hasAttribute(element.attributes, attributeName);\n};\n\n/**\n * Add specified attributes to a JSX element's openingElement if they are not already present.\n */\nexport const addAttributesIfMissing = (\n j: JSCodeshift,\n openingElement: JSXElement['openingElement'],\n attributesToAdd: { attribute: JSXAttribute; name: string }[],\n) => {\n if (!Array.isArray(openingElement.attributes)) return;\n const attrs = openingElement.attributes;\n attributesToAdd.forEach(({ attribute, name }) => {\n if (!hasAttributeOnElement(openingElement, name)) {\n attrs.push(attribute);\n }\n });\n};\n","import type { ASTPath, JSCodeshift, JSXAttribute, JSXElement, Node } from 'jscodeshift';\n\nexport interface ReporterOptions {\n jscodeshift: JSCodeshift;\n issues: string[];\n}\n\n/**\n * CodemodReporter is a utility class for reporting issues found during codemod transformations.\n * It provides methods to report issues related to JSX elements, props, and attributes.\n *\n * @example\n * ```typescript\n * const issues: string[] = [];\n * const reporter = createReporter(j, issues);\n *\n * // Report a deprecated prop\n * reporter.reportDeprecatedProp(buttonElement, 'flat', 'variant=\"text\"');\n *\n * // Report complex expression that needs review\n * reporter.reportAmbiguousExpression(element, 'size');\n *\n * // Auto-detect common issues\n * reporter.reportAttributeIssues(element);\n * ```\n */\nexport class CodemodReporter {\n private readonly j: JSCodeshift;\n private readonly issues: string[];\n\n constructor(options: ReporterOptions) {\n this.j = options.jscodeshift;\n this.issues = options.issues;\n }\n\n /**\n * Reports an issue with a JSX element\n */\n reportElement(element: JSXElement | ASTPath<JSXElement>, reason: string): void {\n const node = this.getNode(element);\n const componentName = this.getComponentName(node);\n const line = this.getLineNumber(node);\n\n this.addIssue(`Manual review required: <${componentName}> at line ${line} ${reason}.`);\n }\n\n /**\n * Reports an issue with a specific prop\n */\n reportProp(element: JSXElement | ASTPath<JSXElement>, propName: string, reason: string): void {\n const node = this.getNode(element);\n const componentName = this.getComponentName(node);\n const line = this.getLineNumber(node);\n\n this.addIssue(\n `Manual review required: prop \"${propName}\" on <${componentName}> at line ${line} ${reason}.`,\n );\n }\n\n /**\n * Reports an issue with a JSX attribute directly\n */\n reportAttribute(\n attr: JSXAttribute,\n element: JSXElement | ASTPath<JSXElement>,\n reason?: string,\n ): void {\n const node = this.getNode(element);\n const componentName = this.getComponentName(node);\n const propName = this.getAttributeName(attr);\n const line = this.getLineNumber(attr) || this.getLineNumber(node);\n\n const defaultReason = this.getAttributeReason(attr);\n const finalReason = reason || defaultReason;\n\n this.addIssue(\n `Manual review required: prop \"${propName}\" on <${componentName}> at line ${line} ${finalReason}.`,\n );\n }\n\n /**\n * Reports spread props on an element\n */\n reportSpreadProps(element: JSXElement | ASTPath<JSXElement>): void {\n this.reportElement(element, 'contains spread props that need manual review');\n }\n\n /**\n * Reports conflicting prop and children\n */\n reportPropWithChildren(element: JSXElement | ASTPath<JSXElement>, propName: string): void {\n this.reportProp(\n element,\n propName,\n `conflicts with children - both \"${propName}\" prop and children are present`,\n );\n }\n\n /**\n * Reports unsupported prop value\n */\n reportUnsupportedValue(\n element: JSXElement | ASTPath<JSXElement>,\n propName: string,\n value: string,\n ): void {\n this.reportProp(element, propName, `has unsupported value \"${value}\"`);\n }\n\n /**\n * Reports ambiguous expression in prop\n */\n reportAmbiguousExpression(element: JSXElement | ASTPath<JSXElement>, propName: string): void {\n this.reportProp(element, propName, 'contains a complex expression that needs manual review');\n }\n\n /**\n * Reports ambiguous children (like dynamic icons)\n */\n reportAmbiguousChildren(element: JSXElement | ASTPath<JSXElement>, childType = 'content'): void {\n this.reportElement(element, `contains ambiguous ${childType} that needs manual review`);\n }\n\n /**\n * Reports deprecated prop usage\n */\n reportDeprecatedProp(\n element: JSXElement | ASTPath<JSXElement>,\n propName: string,\n alternative?: string,\n ): void {\n const suggestion = alternative ? ` Use ${alternative} instead` : '';\n this.reportProp(element, propName, `is deprecated${suggestion}`);\n }\n\n /**\n * Reports missing required prop\n */\n reportMissingRequiredProp(element: JSXElement | ASTPath<JSXElement>, propName: string): void {\n this.reportProp(element, propName, 'is required but missing');\n }\n\n /**\n * Reports conflicting props\n */\n reportConflictingProps(element: JSXElement | ASTPath<JSXElement>, propNames: string[]): void {\n const propList = propNames.map((name) => `\"${name}\"`).join(', ');\n this.reportElement(element, `has conflicting props: ${propList} cannot be used together`);\n }\n\n /**\n * Auto-detects and reports common attribute issues\n */\n reportAttributeIssues(element: JSXElement | ASTPath<JSXElement>): void {\n const node = this.getNode(element);\n const { attributes } = node.openingElement;\n\n if (!attributes) return;\n\n // Check for spread props\n if (attributes.some((attr) => attr.type === 'JSXSpreadAttribute')) {\n this.reportSpreadProps(element);\n }\n\n // Check for complex expressions in attributes\n attributes.forEach((attr) => {\n if (attr.type === 'JSXAttribute' && attr.value?.type === 'JSXExpressionContainer') {\n this.reportAttribute(attr, element);\n }\n });\n }\n\n // Private helper methods\n private getNode(element: JSXElement | ASTPath<JSXElement>): JSXElement {\n return 'node' in element ? element.node : element;\n }\n\n private getComponentName(node: JSXElement): string {\n const { name } = node.openingElement;\n if (name.type === 'JSXIdentifier') {\n return name.name;\n }\n // Handle JSXMemberExpression, JSXNamespacedName, etc.\n return this.j(name).toSource();\n }\n\n private getLineNumber(node: JSXElement | JSXAttribute | Node): string {\n return node.loc?.start.line?.toString() || 'unknown';\n }\n\n private getAttributeName(attr: JSXAttribute): string {\n if (attr.name.type === 'JSXIdentifier') {\n return attr.name.name;\n }\n return this.j(attr.name).toSource();\n }\n\n private getAttributeReason(attr: JSXAttribute): string {\n if (!attr.value) return 'has no value';\n\n if (attr.value.type === 'JSXExpressionContainer') {\n const expr = attr.value.expression;\n const expressionType = expr.type.replace('Expression', '').toLowerCase();\n\n // Show actual value for simple cases\n if (expr.type === 'Identifier' || expr.type === 'MemberExpression') {\n const valueText = this.j(expr).toSource();\n return `contains a ${expressionType} (${valueText})`;\n }\n\n return `contains a complex ${expressionType} expression`;\n }\n\n return 'needs manual review';\n }\n\n private addIssue(message: string): void {\n this.issues.push(message);\n }\n}\n\nexport const createReporter = (j: JSCodeshift, issues: string[]): CodemodReporter => {\n return new CodemodReporter({ jscodeshift: j, issues });\n};\n","import type { API, FileInfo, JSCodeshift, JSXIdentifier, Options } from 'jscodeshift';\n\nimport reportManualReview from '../../utils/reportManualReview';\nimport hasImport from '../helpers/hasImport';\nimport processIconChildren from '../helpers/iconUtils';\nimport {\n addAttributesIfMissing,\n hasAttributeOnElement,\n setNameIfJSXIdentifier,\n} from '../helpers/jsxElementUtils';\nimport { createReporter } from '../helpers/jsxReportingUtils';\n\nexport const parser = 'tsx';\n\ninterface LegacyProps {\n priority?: string;\n size?: string;\n type?: string;\n htmlType?: string;\n sentiment?: string;\n [key: string]: unknown;\n}\n\nconst priorityMapping: Record<string, Record<string, string>> = {\n accent: {\n primary: 'primary',\n secondary: 'secondary-neutral',\n tertiary: 'tertiary',\n },\n positive: {\n primary: 'primary',\n secondary: 'secondary-neutral',\n tertiary: 'secondary-neutral',\n },\n negative: {\n primary: 'primary',\n secondary: 'secondary',\n tertiary: 'secondary',\n },\n};\n\nconst sizeMap: Record<string, string> = {\n EXTRA_SMALL: 'xs',\n SMALL: 'sm',\n MEDIUM: 'md',\n LARGE: 'lg',\n EXTRA_LARGE: 'xl',\n xs: 'sm',\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n xl: 'xl',\n};\n\nconst resolveSize = (size?: string): string | undefined => {\n if (!size) return size;\n const match = /^Size\\.(EXTRA_SMALL|SMALL|MEDIUM|LARGE|EXTRA_LARGE)$/u.exec(size);\n if (match) {\n return sizeMap[match[1]];\n }\n return sizeMap[size] || size;\n};\n\nconst resolvePriority = (type?: string, priority?: string): string | undefined => {\n if (type && priority) {\n return priorityMapping[type]?.[priority] || priority;\n }\n return priority;\n};\n\nconst resolveType = (type?: string, htmlType?: string): string | null => {\n if (htmlType) {\n return htmlType;\n }\n\n const legacyButtonTypes = [\n 'accent',\n 'negative',\n 'positive',\n 'primary',\n 'pay',\n 'secondary',\n 'danger',\n 'link',\n ];\n return type && legacyButtonTypes.includes(type) ? type : null;\n};\n\nconst convertEnumValue = (value?: string): string | undefined => {\n if (!value) return value;\n const strippedValue = value.replace(/^['\"]|['\"]$/gu, '');\n const enumMapping: Record<string, string> = {\n 'Priority.SECONDARY': 'secondary',\n 'Priority.PRIMARY': 'primary',\n 'Priority.TERTIARY': 'tertiary',\n 'ControlType.NEGATIVE': 'negative',\n 'ControlType.POSITIVE': 'positive',\n 'ControlType.ACCENT': 'accent',\n };\n return enumMapping[strippedValue] || strippedValue;\n};\n\n/**\n * This transform function modifies the Button and ActionButton components from the @transferwise/components library.\n * It updates the ActionButton component to use the Button component with specific attributes and mappings.\n * It also processes icon children and removes legacy props.\n *\n * @param {FileInfo} file - The file information object.\n * @param {API} api - The API object for jscodeshift.\n * @param {Options} options - The options object for jscodeshift.\n * @returns {string} - The transformed source code.\n */\nconst transformer = (file: FileInfo, api: API, options: Options) => {\n const j: JSCodeshift = api.jscodeshift;\n const root = j(file.source);\n const manualReviewIssues: string[] = [];\n\n // Create reporter instance\n const reporter = createReporter(j, manualReviewIssues);\n\n const { exists: hasButtonImport } = hasImport(root, '@transferwise/components', 'Button', j);\n const { exists: hasActionButtonImport, remove: removeActionButtonImport } = hasImport(\n root,\n '@transferwise/components',\n 'ActionButton',\n j,\n );\n\n const iconImports = new Set<string>();\n root.find(j.ImportDeclaration, { source: { value: '@transferwise/icons' } }).forEach((path) => {\n path.node.specifiers?.forEach((specifier) => {\n if (\n (specifier.type === 'ImportDefaultSpecifier' || specifier.type === 'ImportSpecifier') &&\n specifier.local\n ) {\n const localName = (specifier.local as { name: string }).name;\n iconImports.add(localName);\n }\n });\n });\n\n if (hasActionButtonImport) {\n root.findJSXElements('ActionButton').forEach((path) => {\n const { openingElement, closingElement } = path.node;\n\n openingElement.name = setNameIfJSXIdentifier(openingElement.name, 'Button')!;\n if (closingElement) {\n closingElement.name = setNameIfJSXIdentifier(closingElement.name, 'Button')!;\n }\n\n addAttributesIfMissing(j, openingElement, [\n { attribute: j.jsxAttribute(j.jsxIdentifier('v2')), name: 'v2' },\n { attribute: j.jsxAttribute(j.jsxIdentifier('size'), j.literal('sm')), name: 'size' },\n ]);\n\n processIconChildren(j, path.node.children, iconImports, openingElement);\n\n if ((openingElement.attributes ?? []).some((attr) => attr.type === 'JSXSpreadAttribute')) {\n reporter.reportSpreadProps(path);\n }\n\n const legacyPropNames = ['priority', 'text'];\n const legacyProps: LegacyProps = {};\n\n openingElement.attributes?.forEach((attr) => {\n if (attr.type === 'JSXAttribute' && attr.name && attr.name.type === 'JSXIdentifier') {\n const { name } = attr.name;\n if (legacyPropNames.includes(name)) {\n if (attr.value) {\n if (attr.value.type === 'StringLiteral') {\n legacyProps[name] = attr.value.value;\n } else if (attr.value.type === 'JSXExpressionContainer') {\n reporter.reportAttribute(attr, path);\n }\n }\n }\n }\n });\n\n const hasTextProp = openingElement.attributes?.some(\n (attr) =>\n attr.type === 'JSXAttribute' &&\n attr.name.type === 'JSXIdentifier' &&\n attr.name.name === 'text',\n );\n const hasChildren = path.node.children?.some(\n (child) =>\n (child.type === 'JSXText' && child.value.trim() !== '') ||\n child.type === 'JSXElement' ||\n child.type === 'JSXExpressionContainer',\n );\n\n if (hasTextProp && hasChildren) {\n reporter.reportPropWithChildren(path, 'text');\n }\n\n (path.node.children || []).forEach((child) => {\n if (child.type === 'JSXExpressionContainer') {\n const expr = child.expression;\n if (\n expr.type === 'ConditionalExpression' ||\n expr.type === 'CallExpression' ||\n expr.type === 'Identifier' ||\n expr.type === 'MemberExpression'\n ) {\n reporter.reportAmbiguousChildren(path, 'icon');\n }\n }\n });\n });\n\n removeActionButtonImport();\n }\n\n if (hasButtonImport) {\n root.findJSXElements('Button').forEach((path) => {\n const { openingElement } = path.node;\n\n if (hasAttributeOnElement(openingElement, 'v2')) return;\n\n addAttributesIfMissing(j, openingElement, [\n { attribute: j.jsxAttribute(j.jsxIdentifier('v2')), name: 'v2' },\n ]);\n processIconChildren(j, path.node.children, iconImports, openingElement);\n\n const legacyProps: LegacyProps = {};\n const legacyPropNames = ['priority', 'size', 'type', 'htmlType', 'sentiment'];\n\n openingElement.attributes?.forEach((attr) => {\n if (attr.type === 'JSXAttribute' && attr.name && attr.name.type === 'JSXIdentifier') {\n const { name } = attr.name;\n if (legacyPropNames.includes(name)) {\n if (attr.value) {\n if (attr.value.type === 'StringLiteral') {\n legacyProps[name] = attr.value.value;\n } else if (attr.value.type === 'JSXExpressionContainer') {\n legacyProps[name] = convertEnumValue(String(j(attr.value.expression).toSource()));\n }\n } else {\n legacyProps[name] = undefined;\n }\n }\n }\n });\n\n if (openingElement.attributes) {\n openingElement.attributes = openingElement.attributes.filter(\n (attr) =>\n !(\n attr.type === 'JSXAttribute' &&\n attr.name &&\n legacyPropNames.includes((attr.name as JSXIdentifier).name)\n ),\n );\n }\n\n if ('size' in legacyProps) {\n const rawValue = legacyProps.size;\n const resolved = resolveSize(rawValue);\n const supportedSizes = ['xs', 'sm', 'md', 'lg', 'xl'];\n\n if (\n typeof rawValue === 'string' &&\n typeof resolved === 'string' &&\n supportedSizes.includes(resolved)\n ) {\n openingElement.attributes?.push(\n j.jsxAttribute(j.jsxIdentifier('size'), j.literal(resolved)),\n );\n } else if (typeof rawValue === 'string') {\n reporter.reportUnsupportedValue(path, 'size', rawValue);\n } else if (rawValue !== undefined) {\n reporter.reportAmbiguousExpression(path, 'size');\n }\n }\n\n if ('priority' in legacyProps) {\n const rawValue = legacyProps.priority;\n const converted = convertEnumValue(rawValue);\n const mapped = resolvePriority(legacyProps.type, converted);\n const supportedPriorities = ['primary', 'secondary', 'tertiary', 'secondary-neutral'];\n\n if (\n typeof rawValue === 'string' &&\n typeof mapped === 'string' &&\n supportedPriorities.includes(mapped)\n ) {\n openingElement.attributes?.push(\n j.jsxAttribute(j.jsxIdentifier('priority'), j.literal(mapped)),\n );\n } else if (typeof rawValue === 'string') {\n reporter.reportUnsupportedValue(path, 'priority', rawValue);\n } else if (rawValue !== undefined) {\n reporter.reportAmbiguousExpression(path, 'priority');\n }\n }\n\n if ('type' in legacyProps || 'htmlType' in legacyProps) {\n const rawType = legacyProps.type;\n const rawHtmlType = legacyProps.htmlType;\n\n const resolvedType =\n typeof rawType === 'string'\n ? rawType\n : rawType && typeof rawType === 'object'\n ? convertEnumValue(j(rawType).toSource())\n : undefined;\n\n const resolved = resolveType(resolvedType, rawHtmlType);\n\n const supportedTypes = [\n 'accent',\n 'negative',\n 'positive',\n 'primary',\n 'pay',\n 'secondary',\n 'danger',\n 'link',\n 'submit',\n 'button',\n 'reset',\n ];\n\n if (typeof resolved === 'string' && supportedTypes.includes(resolved)) {\n openingElement.attributes?.push(\n j.jsxAttribute(j.jsxIdentifier('type'), j.literal(resolved)),\n );\n\n if (resolved === 'negative') {\n openingElement.attributes?.push(\n j.jsxAttribute(j.jsxIdentifier('sentiment'), j.literal('negative')),\n );\n }\n } else if (typeof rawType === 'string' || typeof rawHtmlType === 'string') {\n reporter.reportUnsupportedValue(path, 'type', rawType ?? rawHtmlType ?? '');\n } else if (rawType !== undefined || rawHtmlType !== undefined) {\n reporter.reportAmbiguousExpression(path, 'type');\n }\n }\n\n if ('sentiment' in legacyProps) {\n const rawValue = legacyProps.sentiment;\n if (rawValue === 'negative') {\n openingElement.attributes?.push(\n j.jsxAttribute(j.jsxIdentifier('sentiment'), j.literal('negative')),\n );\n } else if (typeof rawValue === 'string') {\n reporter.reportUnsupportedValue(path, 'sentiment', rawValue);\n } else if (rawValue !== undefined) {\n reporter.reportAmbiguousExpression(path, 'sentiment');\n }\n }\n\n let asIndex = -1;\n let asValue: string | null = null;\n let hrefExists = false;\n let asAmbiguous = false;\n let hrefAmbiguous = false;\n\n openingElement.attributes?.forEach((attr, index) => {\n if (attr.type === 'JSXAttribute' && attr.name) {\n if (attr.name.name === 'as') {\n if (attr.value) {\n if (attr.value.type === 'StringLiteral') {\n asValue = attr.value.value;\n } else if (attr.value.type === 'JSXExpressionContainer') {\n asAmbiguous = true;\n reporter.reportAttribute(attr, path);\n }\n }\n asIndex = index;\n }\n\n if (attr.name.name === 'href') {\n hrefExists = true;\n if (attr.value && attr.value.type !== 'StringLiteral') {\n hrefAmbiguous = true;\n reporter.reportAttribute(attr, path);\n }\n }\n }\n });\n\n if (asValue && asValue !== 'a') {\n reporter.reportUnsupportedValue(path, 'as', asValue);\n }\n\n if (asValue === 'a') {\n if (asIndex !== -1) {\n openingElement.attributes = openingElement.attributes?.filter(\n (_, idx) => idx !== asIndex,\n );\n }\n if (!hrefExists) {\n openingElement.attributes = [\n ...(openingElement.attributes ?? []),\n j.jsxAttribute(j.jsxIdentifier('href'), j.literal('#')),\n ];\n }\n }\n\n if ((openingElement.attributes ?? []).some((attr) => attr.type === 'JSXSpreadAttribute')) {\n reporter.reportSpreadProps(path);\n }\n });\n }\n\n if (manualReviewIssues.length > 0) {\n manualReviewIssues.forEach(async (issue) => {\n await reportManualReview(file.path, issue);\n });\n }\n\n return root.toSource();\n};\n\nexport default transformer;\n"],"mappings":"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","names":["path","path"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wise/wds-codemods",
|
|
3
|
-
"version": "0.0.1-experimental-
|
|
3
|
+
"version": "0.0.1-experimental-cbae00f",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"author": "Wise Payments Ltd.",
|
|
6
6
|
"type": "module",
|
|
@@ -30,38 +30,38 @@
|
|
|
30
30
|
"test:watch": "jest --watch"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@inquirer/prompts": "^7.
|
|
33
|
+
"@inquirer/prompts": "^7.8.4",
|
|
34
34
|
"jscodeshift": "^17.3"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@babel/core": "^7.
|
|
37
|
+
"@babel/core": "^7.28.3",
|
|
38
38
|
"@babel/plugin-syntax-import-meta": "^7.10.4",
|
|
39
|
-
"@babel/preset-env": "^7.
|
|
39
|
+
"@babel/preset-env": "^7.28.3",
|
|
40
40
|
"@babel/preset-typescript": "^7.27.1",
|
|
41
41
|
"@changesets/changelog-github": "^0.5.1",
|
|
42
|
-
"@changesets/cli": "^2.29.
|
|
43
|
-
"@commitlint/cli": "^19.8.
|
|
44
|
-
"@commitlint/config-conventional": "^19.8.
|
|
45
|
-
"@inquirer/testing": "^2.1.
|
|
42
|
+
"@changesets/cli": "^2.29.6",
|
|
43
|
+
"@commitlint/cli": "^19.8.1",
|
|
44
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
45
|
+
"@inquirer/testing": "^2.1.49",
|
|
46
46
|
"@jest/globals": "^29.7.0",
|
|
47
47
|
"@types/jest": "^29.5.14",
|
|
48
48
|
"@types/jscodeshift": "^17.3.0",
|
|
49
|
-
"@types/node": "^22.
|
|
49
|
+
"@types/node": "^22.17.2",
|
|
50
50
|
"@types/semver": "^7.7.0",
|
|
51
51
|
"@wise/eslint-config": "^12.3.0",
|
|
52
52
|
"babel-jest": "^29.7.0",
|
|
53
53
|
"babel-plugin-transform-import-meta": "^2.3.3",
|
|
54
54
|
"husky": "^9.1.7",
|
|
55
55
|
"jest": "^29.7.0",
|
|
56
|
-
"prettier": "^3.
|
|
56
|
+
"prettier": "^3.6.2",
|
|
57
57
|
"semver": "^7.7.2",
|
|
58
|
-
"ts-jest": "^29.
|
|
58
|
+
"ts-jest": "^29.4.1",
|
|
59
59
|
"ts-node": "^10.9.2",
|
|
60
|
-
"tsup": "^8.
|
|
61
|
-
"typescript": "^5.
|
|
60
|
+
"tsup": "^8.5.0",
|
|
61
|
+
"typescript": "^5.9.2"
|
|
62
62
|
},
|
|
63
63
|
"publishConfig": {
|
|
64
64
|
"access": "public"
|
|
65
65
|
},
|
|
66
|
-
"packageManager": "pnpm@9.15.
|
|
66
|
+
"packageManager": "pnpm@9.15.9+sha512.68046141893c66fad01c079231128e9afb89ef87e2691d69e4d40eee228988295fd4682181bae55b58418c3a253bde65a505ec7c5f9403ece5cc3cd37dcf2531"
|
|
67
67
|
}
|
|
@@ -33,7 +33,7 @@ describe('button codemod', () => {
|
|
|
33
33
|
}
|
|
34
34
|
`;
|
|
35
35
|
const output = transform({ source: input });
|
|
36
|
-
expect(output).toContain('v2');
|
|
36
|
+
expect(output).toContain('<Button v2 type="button">Click</Button>');
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
it('removes legacy props and adds new ones', () => {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type { API, FileInfo, JSCodeshift, Options } from 'jscodeshift';
|
|
1
|
+
import type { API, FileInfo, JSCodeshift, JSXIdentifier, Options } from 'jscodeshift';
|
|
2
2
|
|
|
3
3
|
import reportManualReview from '../../utils/reportManualReview';
|
|
4
|
+
import hasImport from '../helpers/hasImport';
|
|
5
|
+
import processIconChildren from '../helpers/iconUtils';
|
|
4
6
|
import {
|
|
5
7
|
addAttributesIfMissing,
|
|
6
|
-
createReporter,
|
|
7
8
|
hasAttributeOnElement,
|
|
8
|
-
hasImport,
|
|
9
|
-
processIconChildren,
|
|
10
9
|
setNameIfJSXIdentifier,
|
|
11
|
-
} from '../helpers';
|
|
10
|
+
} from '../helpers/jsxElementUtils';
|
|
11
|
+
import { createReporter } from '../helpers/jsxReportingUtils';
|
|
12
12
|
|
|
13
13
|
export const parser = 'tsx';
|
|
14
14
|
|
|
@@ -82,16 +82,12 @@ const resolveType = (type?: string, htmlType?: string): string | null => {
|
|
|
82
82
|
'secondary',
|
|
83
83
|
'danger',
|
|
84
84
|
'link',
|
|
85
|
-
'button',
|
|
86
|
-
'reset',
|
|
87
|
-
'submit',
|
|
88
85
|
];
|
|
89
86
|
return type && legacyButtonTypes.includes(type) ? type : null;
|
|
90
87
|
};
|
|
91
88
|
|
|
92
|
-
const convertEnumValue = (value?: string):
|
|
93
|
-
if (!value) return
|
|
94
|
-
|
|
89
|
+
const convertEnumValue = (value?: string): string | undefined => {
|
|
90
|
+
if (!value) return value;
|
|
95
91
|
const strippedValue = value.replace(/^['"]|['"]$/gu, '');
|
|
96
92
|
const enumMapping: Record<string, string> = {
|
|
97
93
|
'Priority.SECONDARY': 'secondary',
|
|
@@ -100,18 +96,8 @@ const convertEnumValue = (value?: string): { converted: string | undefined; wasE
|
|
|
100
96
|
'ControlType.NEGATIVE': 'negative',
|
|
101
97
|
'ControlType.POSITIVE': 'positive',
|
|
102
98
|
'ControlType.ACCENT': 'accent',
|
|
103
|
-
'ControlType.BUTTON': 'button',
|
|
104
|
-
'ControlType.RESET': 'reset',
|
|
105
|
-
'HtmlType.SUBMIT': 'submit',
|
|
106
|
-
'HtmlType.BUTTON': 'button',
|
|
107
|
-
'HtmlType.RESET': 'reset',
|
|
108
|
-
'Sentiment.NEGATIVE': 'negative',
|
|
109
99
|
};
|
|
110
|
-
|
|
111
|
-
const wasEnum = strippedValue in enumMapping;
|
|
112
|
-
const converted = enumMapping[strippedValue] || strippedValue;
|
|
113
|
-
|
|
114
|
-
return { converted, wasEnum };
|
|
100
|
+
return enumMapping[strippedValue] || strippedValue;
|
|
115
101
|
};
|
|
116
102
|
|
|
117
103
|
/**
|
|
@@ -235,163 +221,144 @@ const transformer = (file: FileInfo, api: API, options: Options) => {
|
|
|
235
221
|
addAttributesIfMissing(j, openingElement, [
|
|
236
222
|
{ attribute: j.jsxAttribute(j.jsxIdentifier('v2')), name: 'v2' },
|
|
237
223
|
]);
|
|
238
|
-
|
|
239
224
|
processIconChildren(j, path.node.children, iconImports, openingElement);
|
|
240
225
|
|
|
241
226
|
const legacyProps: LegacyProps = {};
|
|
242
227
|
const legacyPropNames = ['priority', 'size', 'type', 'htmlType', 'sentiment'];
|
|
243
|
-
const keepAttributes: typeof openingElement.attributes = [];
|
|
244
228
|
|
|
245
|
-
|
|
246
|
-
if (
|
|
247
|
-
attr.type === 'JSXAttribute' &&
|
|
248
|
-
attr.name &&
|
|
249
|
-
attr.name.type === 'JSXIdentifier' &&
|
|
250
|
-
legacyPropNames.includes(attr.name.name)
|
|
251
|
-
) {
|
|
229
|
+
openingElement.attributes?.forEach((attr) => {
|
|
230
|
+
if (attr.type === 'JSXAttribute' && attr.name && attr.name.type === 'JSXIdentifier') {
|
|
252
231
|
const { name } = attr.name;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
} else
|
|
261
|
-
|
|
262
|
-
const { converted } = convertEnumValue(rawStringValue);
|
|
263
|
-
legacyProps[name] = converted;
|
|
264
|
-
}
|
|
265
|
-
} else {
|
|
266
|
-
legacyProps[name] = undefined;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// Check if this is an enum value that should be removed
|
|
270
|
-
const { wasEnum } = convertEnumValue(rawStringValue);
|
|
271
|
-
if (rawStringValue && wasEnum) {
|
|
272
|
-
migrated = true; // Remove enum values
|
|
273
|
-
} else if (name === 'size') {
|
|
274
|
-
const rawValue = legacyProps.size;
|
|
275
|
-
const resolved = resolveSize(rawValue);
|
|
276
|
-
const supportedSizes = ['xs', 'sm', 'md', 'lg', 'xl'];
|
|
277
|
-
if (
|
|
278
|
-
typeof rawValue === 'string' &&
|
|
279
|
-
typeof resolved === 'string' &&
|
|
280
|
-
supportedSizes.includes(resolved)
|
|
281
|
-
) {
|
|
282
|
-
migrated = true;
|
|
283
|
-
} else if (typeof rawValue === 'string') {
|
|
284
|
-
reporter.reportUnsupportedValue(path, 'size', rawValue);
|
|
285
|
-
} else if (rawValue !== undefined) {
|
|
286
|
-
reporter.reportAmbiguousExpression(path, 'size');
|
|
287
|
-
}
|
|
288
|
-
} else if (name === 'priority') {
|
|
289
|
-
const rawValue = legacyProps.priority;
|
|
290
|
-
const { converted } = convertEnumValue(rawValue);
|
|
291
|
-
const mapped = resolvePriority(legacyProps.type, converted);
|
|
292
|
-
const supportedPriorities = ['primary', 'secondary', 'tertiary', 'secondary-neutral'];
|
|
293
|
-
if (
|
|
294
|
-
typeof rawValue === 'string' &&
|
|
295
|
-
typeof mapped === 'string' &&
|
|
296
|
-
supportedPriorities.includes(mapped)
|
|
297
|
-
) {
|
|
298
|
-
migrated = true;
|
|
299
|
-
} else if (typeof rawValue === 'string') {
|
|
300
|
-
reporter.reportUnsupportedValue(path, 'priority', rawValue);
|
|
301
|
-
} else if (rawValue !== undefined) {
|
|
302
|
-
reporter.reportAmbiguousExpression(path, 'priority');
|
|
303
|
-
}
|
|
304
|
-
} else if (name === 'type' || name === 'htmlType') {
|
|
305
|
-
const rawType = legacyProps.type;
|
|
306
|
-
const rawHtmlType = legacyProps.htmlType;
|
|
307
|
-
const resolvedType =
|
|
308
|
-
typeof rawType === 'string'
|
|
309
|
-
? rawType
|
|
310
|
-
: rawType && typeof rawType === 'object'
|
|
311
|
-
? convertEnumValue(j(rawType).toSource()).converted
|
|
312
|
-
: undefined;
|
|
313
|
-
const resolved = resolveType(resolvedType, rawHtmlType);
|
|
314
|
-
const supportedTypes = ['button', 'reset', 'submit'];
|
|
315
|
-
if (typeof resolved === 'string' && supportedTypes.includes(resolved)) {
|
|
316
|
-
migrated = true;
|
|
317
|
-
} else if (typeof rawType === 'string' || typeof rawHtmlType === 'string') {
|
|
318
|
-
reporter.reportUnsupportedValue(path, 'type', rawType ?? rawHtmlType ?? '');
|
|
319
|
-
} else if (rawType !== undefined || rawHtmlType !== undefined) {
|
|
320
|
-
reporter.reportAmbiguousExpression(path, 'type');
|
|
321
|
-
}
|
|
322
|
-
} else if (name === 'sentiment') {
|
|
323
|
-
const rawValue = legacyProps.sentiment;
|
|
324
|
-
if (rawValue === 'negative') {
|
|
325
|
-
migrated = true;
|
|
326
|
-
} else if (typeof rawValue === 'string') {
|
|
327
|
-
reporter.reportUnsupportedValue(path, 'sentiment', rawValue);
|
|
328
|
-
} else if (rawValue !== undefined) {
|
|
329
|
-
reporter.reportAmbiguousExpression(path, 'sentiment');
|
|
232
|
+
if (legacyPropNames.includes(name)) {
|
|
233
|
+
if (attr.value) {
|
|
234
|
+
if (attr.value.type === 'StringLiteral') {
|
|
235
|
+
legacyProps[name] = attr.value.value;
|
|
236
|
+
} else if (attr.value.type === 'JSXExpressionContainer') {
|
|
237
|
+
legacyProps[name] = convertEnumValue(String(j(attr.value.expression).toSource()));
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
legacyProps[name] = undefined;
|
|
330
241
|
}
|
|
331
242
|
}
|
|
332
|
-
|
|
333
|
-
if (!migrated) keepAttributes.push(attr);
|
|
334
|
-
} else {
|
|
335
|
-
keepAttributes.push(attr);
|
|
336
243
|
}
|
|
337
244
|
});
|
|
338
245
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
246
|
+
if (openingElement.attributes) {
|
|
247
|
+
openingElement.attributes = openingElement.attributes.filter(
|
|
248
|
+
(attr) =>
|
|
249
|
+
!(
|
|
250
|
+
attr.type === 'JSXAttribute' &&
|
|
251
|
+
attr.name &&
|
|
252
|
+
legacyPropNames.includes((attr.name as JSXIdentifier).name)
|
|
253
|
+
),
|
|
254
|
+
);
|
|
348
255
|
}
|
|
349
256
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
typeof rawPriority === 'string' &&
|
|
355
|
-
typeof mappedPriority === 'string' &&
|
|
356
|
-
['primary', 'secondary', 'tertiary', 'secondary-neutral'].includes(mappedPriority)
|
|
357
|
-
) {
|
|
358
|
-
newAttributes.push(j.jsxAttribute(j.jsxIdentifier('priority'), j.literal(mappedPriority)));
|
|
359
|
-
}
|
|
257
|
+
if ('size' in legacyProps) {
|
|
258
|
+
const rawValue = legacyProps.size;
|
|
259
|
+
const resolved = resolveSize(rawValue);
|
|
260
|
+
const supportedSizes = ['xs', 'sm', 'md', 'lg', 'xl'];
|
|
360
261
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
newAttributes.push(j.jsxAttribute(j.jsxIdentifier('type'), j.literal(resolved)));
|
|
262
|
+
if (
|
|
263
|
+
typeof rawValue === 'string' &&
|
|
264
|
+
typeof resolved === 'string' &&
|
|
265
|
+
supportedSizes.includes(resolved)
|
|
266
|
+
) {
|
|
267
|
+
openingElement.attributes?.push(
|
|
268
|
+
j.jsxAttribute(j.jsxIdentifier('size'), j.literal(resolved)),
|
|
269
|
+
);
|
|
270
|
+
} else if (typeof rawValue === 'string') {
|
|
271
|
+
reporter.reportUnsupportedValue(path, 'size', rawValue);
|
|
272
|
+
} else if (rawValue !== undefined) {
|
|
273
|
+
reporter.reportAmbiguousExpression(path, 'size');
|
|
374
274
|
}
|
|
375
|
-
|
|
376
|
-
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if ('priority' in legacyProps) {
|
|
278
|
+
const rawValue = legacyProps.priority;
|
|
279
|
+
const converted = convertEnumValue(rawValue);
|
|
280
|
+
const mapped = resolvePriority(legacyProps.type, converted);
|
|
281
|
+
const supportedPriorities = ['primary', 'secondary', 'tertiary', 'secondary-neutral'];
|
|
282
|
+
|
|
283
|
+
if (
|
|
284
|
+
typeof rawValue === 'string' &&
|
|
285
|
+
typeof mapped === 'string' &&
|
|
286
|
+
supportedPriorities.includes(mapped)
|
|
287
|
+
) {
|
|
288
|
+
openingElement.attributes?.push(
|
|
289
|
+
j.jsxAttribute(j.jsxIdentifier('priority'), j.literal(mapped)),
|
|
290
|
+
);
|
|
291
|
+
} else if (typeof rawValue === 'string') {
|
|
292
|
+
reporter.reportUnsupportedValue(path, 'priority', rawValue);
|
|
293
|
+
} else if (rawValue !== undefined) {
|
|
294
|
+
reporter.reportAmbiguousExpression(path, 'priority');
|
|
377
295
|
}
|
|
378
296
|
}
|
|
379
297
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
298
|
+
if ('type' in legacyProps || 'htmlType' in legacyProps) {
|
|
299
|
+
const rawType = legacyProps.type;
|
|
300
|
+
const rawHtmlType = legacyProps.htmlType;
|
|
301
|
+
|
|
302
|
+
const resolvedType =
|
|
303
|
+
typeof rawType === 'string'
|
|
304
|
+
? rawType
|
|
305
|
+
: rawType && typeof rawType === 'object'
|
|
306
|
+
? convertEnumValue(j(rawType).toSource())
|
|
307
|
+
: undefined;
|
|
308
|
+
|
|
309
|
+
const resolved = resolveType(resolvedType, rawHtmlType);
|
|
310
|
+
|
|
311
|
+
const supportedTypes = [
|
|
312
|
+
'accent',
|
|
313
|
+
'negative',
|
|
314
|
+
'positive',
|
|
315
|
+
'primary',
|
|
316
|
+
'pay',
|
|
317
|
+
'secondary',
|
|
318
|
+
'danger',
|
|
319
|
+
'link',
|
|
320
|
+
'submit',
|
|
321
|
+
'button',
|
|
322
|
+
'reset',
|
|
323
|
+
];
|
|
324
|
+
|
|
325
|
+
if (typeof resolved === 'string' && supportedTypes.includes(resolved)) {
|
|
326
|
+
openingElement.attributes?.push(
|
|
327
|
+
j.jsxAttribute(j.jsxIdentifier('type'), j.literal(resolved)),
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
if (resolved === 'negative') {
|
|
331
|
+
openingElement.attributes?.push(
|
|
332
|
+
j.jsxAttribute(j.jsxIdentifier('sentiment'), j.literal('negative')),
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
} else if (typeof rawType === 'string' || typeof rawHtmlType === 'string') {
|
|
336
|
+
reporter.reportUnsupportedValue(path, 'type', rawType ?? rawHtmlType ?? '');
|
|
337
|
+
} else if (rawType !== undefined || rawHtmlType !== undefined) {
|
|
338
|
+
reporter.reportAmbiguousExpression(path, 'type');
|
|
339
|
+
}
|
|
383
340
|
}
|
|
384
341
|
|
|
385
|
-
|
|
342
|
+
if ('sentiment' in legacyProps) {
|
|
343
|
+
const rawValue = legacyProps.sentiment;
|
|
344
|
+
if (rawValue === 'negative') {
|
|
345
|
+
openingElement.attributes?.push(
|
|
346
|
+
j.jsxAttribute(j.jsxIdentifier('sentiment'), j.literal('negative')),
|
|
347
|
+
);
|
|
348
|
+
} else if (typeof rawValue === 'string') {
|
|
349
|
+
reporter.reportUnsupportedValue(path, 'sentiment', rawValue);
|
|
350
|
+
} else if (rawValue !== undefined) {
|
|
351
|
+
reporter.reportAmbiguousExpression(path, 'sentiment');
|
|
352
|
+
}
|
|
353
|
+
}
|
|
386
354
|
|
|
387
|
-
// as/href logic as before
|
|
388
355
|
let asIndex = -1;
|
|
389
356
|
let asValue: string | null = null;
|
|
390
357
|
let hrefExists = false;
|
|
391
358
|
let asAmbiguous = false;
|
|
392
359
|
let hrefAmbiguous = false;
|
|
393
360
|
|
|
394
|
-
|
|
361
|
+
openingElement.attributes?.forEach((attr, index) => {
|
|
395
362
|
if (attr.type === 'JSXAttribute' && attr.name) {
|
|
396
363
|
if (attr.name.name === 'as') {
|
|
397
364
|
if (attr.value) {
|
|
@@ -404,6 +371,7 @@ const transformer = (file: FileInfo, api: API, options: Options) => {
|
|
|
404
371
|
}
|
|
405
372
|
asIndex = index;
|
|
406
373
|
}
|
|
374
|
+
|
|
407
375
|
if (attr.name.name === 'href') {
|
|
408
376
|
hrefExists = true;
|
|
409
377
|
if (attr.value && attr.value.type !== 'StringLiteral') {
|
|
@@ -420,15 +388,18 @@ const transformer = (file: FileInfo, api: API, options: Options) => {
|
|
|
420
388
|
|
|
421
389
|
if (asValue === 'a') {
|
|
422
390
|
if (asIndex !== -1) {
|
|
423
|
-
|
|
391
|
+
openingElement.attributes = openingElement.attributes?.filter(
|
|
392
|
+
(_, idx) => idx !== asIndex,
|
|
393
|
+
);
|
|
424
394
|
}
|
|
425
395
|
if (!hrefExists) {
|
|
426
|
-
|
|
396
|
+
openingElement.attributes = [
|
|
397
|
+
...(openingElement.attributes ?? []),
|
|
398
|
+
j.jsxAttribute(j.jsxIdentifier('href'), j.literal('#')),
|
|
399
|
+
];
|
|
427
400
|
}
|
|
428
401
|
}
|
|
429
402
|
|
|
430
|
-
openingElement.attributes = newAttributes;
|
|
431
|
-
|
|
432
403
|
if ((openingElement.attributes ?? []).some((attr) => attr.type === 'JSXSpreadAttribute')) {
|
|
433
404
|
reporter.reportSpreadProps(path);
|
|
434
405
|
}
|