@wise/wds-codemods 1.0.0-experimental-f022965 → 1.0.0-experimental-2bdcab0

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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["path","fs","findPackages","findProjectRoot","loadTransformModules","logToInquirer","transformFile: string","runTransformPrompts","getOptions","assessPrerequisites","error: unknown"],"sources":["../src/controller/index.ts","../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { execSync } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { select as list } from '@inquirer/prompts';\n\nimport {\n assessPrerequisites,\n findPackages,\n findProjectRoot,\n getOptions,\n loadTransformModules,\n logToInquirer,\n runTransformPrompts,\n} from './helpers';\n\nlet isDebug = false;\nconst currentFilePath = fileURLToPath(import.meta.url);\nconst currentDirPath = path.dirname(currentFilePath);\nconst ICONS = {\n info: '\\x1b[34mℹ\\x1b[0m', // Blue info icon\n focus: '\\x1b[34m➙\\x1b[0m', // Blue arrow icon\n success: '\\x1b[32m✔\\x1b[0m', // Green checkmark\n warning: '\\x1b[33m⚠\\x1b[0m', // Yellow warning icon\n error: '\\x1b[31m✖\\x1b[0m', // Red cross icon\n};\n\nconst resetReportFile = async (reportPath: string) => {\n try {\n await fs.access(reportPath);\n await fs.rm(reportPath);\n console.debug(`${ICONS.info} Removed existing report file${isDebug ? `: ${reportPath}` : '.'}`);\n } catch {\n console.debug(\n `${ICONS.info} No existing report file to remove${isDebug ? `: ${reportPath}` : '.'}`,\n );\n }\n};\n\nconst summariseReportFile = async (reportPath: string) => {\n try {\n const reportContent = await fs.readFile(reportPath, 'utf8');\n const lines = reportContent.split('\\n').filter(Boolean);\n if (lines.length) {\n console.debug(\n `\\n⚠️ ${lines.length} manual review${lines.length > 1 ? 's are' : ' is'} required. See ${reportPath} for details.`,\n );\n } else {\n console.debug(\n `${ICONS.info} Report file exists but is empty${isDebug ? `: ${reportPath}` : '.'}`,\n );\n }\n } catch {\n console.debug(`${ICONS.info} No report file generated - no manual reviews needed`);\n }\n};\n\nasync function runCodemod(transformsDir?: string) {\n try {\n const args = process.argv.slice(2);\n const candidate = args[0];\n isDebug = args.includes('--debug');\n const packages = findPackages();\n const reportPath = path.resolve(findProjectRoot(), 'codemod-report.txt');\n const resolvedTransformsDir =\n transformsDir ?? path.resolve(currentDirPath, '../dist/transforms');\n\n if (isDebug) {\n console.debug(`${ICONS.info} Resolved transforms directory: ${resolvedTransformsDir}`);\n }\n\n await resetReportFile(reportPath);\n\n const { transformFiles } = await loadTransformModules(resolvedTransformsDir);\n\n const resolvedTransformNames = await Promise.all(transformFiles);\n if (resolvedTransformNames.length === 0) {\n throw new Error(\n `${ICONS.error} No transform scripts found${isDebug ? ` in: ${resolvedTransformsDir}` : '.'}`,\n );\n }\n\n const log = (label: string, value: string): void => {\n if (typeof logToInquirer === 'function') {\n logToInquirer(label, value);\n } else {\n console.info(label, value);\n }\n };\n\n let transformFile: string;\n\n if (candidate && resolvedTransformNames.includes(candidate)) {\n log('Select codemod to run:', candidate);\n transformFile = candidate;\n } else {\n transformFile = await list({\n message: 'Select codemod to run:',\n choices: resolvedTransformNames.map((name) => ({ name, value: name })),\n });\n log('Selected codemod:', transformFile);\n }\n\n const codemodPath = path.resolve(resolvedTransformsDir, transformFile, 'transformer.js');\n if (isDebug) {\n console.debug(`${ICONS.info} Resolved codemod path: ${codemodPath}`);\n }\n\n const promptAnswers = await runTransformPrompts(codemodPath);\n\n const options = await getOptions({\n packages,\n root: findProjectRoot(),\n transformFiles: resolvedTransformNames,\n preselectedTransformFile: transformFile,\n });\n\n options.targetPaths.map((targetPath) => {\n console.info(`${ICONS.focus} \\x1b[1mProcessing:\\x1b[0m \\x1b[32m${targetPath}\\x1b[0m`);\n\n const isCompliant = assessPrerequisites(targetPath, codemodPath);\n if (isCompliant) {\n const answerArgs = Object.entries(promptAnswers).map(\n ([promptName, answerValue]) => `--${promptName}=${String(answerValue)}`,\n );\n\n const argsList = [\n '-t',\n codemodPath,\n targetPath,\n options.isDry ? '--dry' : '',\n options.isPrint ? '--print' : '',\n options.ignorePatterns\n ? options.ignorePatterns\n .split(',')\n .map((pattern) => `--ignore-pattern=${pattern.trim()}`)\n .join(' ')\n : '',\n options.useGitIgnore ? '--gitignore' : '',\n ...answerArgs,\n ].filter(Boolean);\n\n const command = `npx jscodeshift ${argsList.join(' ')}`;\n if (isDebug) {\n console.debug(`${ICONS.info} Running: ${command}`);\n }\n return execSync(command, { stdio: 'inherit' });\n }\n return undefined;\n });\n\n await summariseReportFile(reportPath);\n } catch (error: unknown) {\n if (error instanceof Error) {\n console.error(`${ICONS.error} Error running codemod:`, error.message);\n } else {\n console.error(`${ICONS.error} Error running codemod:`, error);\n }\n if (process.env.NODE_ENV !== 'test') {\n process.exit(1);\n }\n }\n}\n\nexport { runCodemod };\n","#!/usr/bin/env node\nimport { runCodemod } from './controller';\n\nvoid runCodemod();\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["path","fs","CONSOLE_ICONS","logToInquirer","findPackages","findProjectRoot","loadTransformModules","transformFile: string","runTransformPrompts","getOptions","transformer","assessPrerequisites","error: unknown"],"sources":["../src/controller/index.ts","../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { execSync } from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { select as list } from '@inquirer/prompts';\n\nimport { CONSOLE_ICONS } from '../constants';\nimport transformer from '../transforms/list-item/transformer';\nimport {\n assessPrerequisites,\n findPackages,\n findProjectRoot,\n getOptions,\n loadTransformModules,\n logToInquirer,\n runTransformPrompts,\n} from './helpers';\n\nlet isDebug = false;\nconst currentFilePath = fileURLToPath(import.meta.url);\nconst currentDirPath = path.dirname(currentFilePath);\n\nconst resetReportFile = async (reportPath: string) => {\n try {\n await fs.access(reportPath);\n await fs.rm(reportPath);\n console.debug(\n `${CONSOLE_ICONS.info} Removed existing report file${isDebug ? `: ${reportPath}` : '.'}`,\n );\n } catch {\n console.debug(\n `${CONSOLE_ICONS.info} No existing report file to remove${isDebug ? `: ${reportPath}` : '.'}`,\n );\n }\n};\n\nconst summariseReportFile = async (reportPath: string) => {\n try {\n const reportContent = await fs.readFile(reportPath, 'utf8');\n const lines = reportContent.split('\\n').filter(Boolean);\n if (lines.length) {\n console.debug(\n `\\n${CONSOLE_ICONS.warning} ${lines.length} manual review${lines.length > 1 ? 's are' : ' is'} required. See ${reportPath} for details.`,\n );\n } else {\n console.debug(\n `${CONSOLE_ICONS.info} Report file exists but is empty${isDebug ? `: ${reportPath}` : '.'}`,\n );\n }\n } catch {\n console.debug(`${CONSOLE_ICONS.info} No report file generated - no manual reviews needed`);\n }\n};\n\nconst log = (label: string, value?: string): void => {\n if (typeof logToInquirer === 'function') {\n logToInquirer(label, value || '');\n } else {\n console.info(label, value || '');\n }\n};\n\nasync function runCodemod(transformsDir?: string) {\n const args = process.argv.slice(2);\n const candidate = args[0];\n isDebug = args.includes('--debug');\n\n try {\n const packages = findPackages();\n const reportPath = path.resolve(findProjectRoot(), 'codemod-report.txt');\n const resolvedTransformsDir =\n transformsDir ?? path.resolve(currentDirPath, '../dist/transforms');\n\n if (isDebug) {\n console.debug(\n `${CONSOLE_ICONS.info} Resolved transforms directory: ${resolvedTransformsDir}`,\n );\n }\n\n await resetReportFile(reportPath);\n\n const { transformFiles } = await loadTransformModules(resolvedTransformsDir);\n\n const resolvedTransformNames = await Promise.all(transformFiles);\n if (resolvedTransformNames.length === 0) {\n throw new Error(\n `${CONSOLE_ICONS.error} No transform scripts found${isDebug ? ` in: ${resolvedTransformsDir}` : '.'}`,\n );\n }\n\n let transformFile: string;\n\n if (candidate && resolvedTransformNames.includes(candidate)) {\n log('Select codemod to run:', candidate);\n transformFile = candidate;\n } else {\n transformFile = await list({\n message: 'Select codemod to run:',\n choices: resolvedTransformNames.map((name) => ({ name, value: name })),\n });\n log('Selected codemod:', transformFile);\n }\n\n const codemodPath = path.resolve(resolvedTransformsDir, transformFile, 'transformer.js');\n if (isDebug) {\n console.debug(`${CONSOLE_ICONS.info} Resolved codemod path: ${codemodPath}`);\n }\n\n const promptAnswers = await runTransformPrompts(codemodPath);\n\n const options = await getOptions({\n packages,\n root: findProjectRoot(),\n transformFiles: resolvedTransformNames,\n preselectedTransformFile: transformFile,\n });\n\n // Handle ListItem transform differently as it uses Claude, not jscodeshift\n if (transformFile === 'list-item') {\n // TODO: Handle ALL args and options properly - isDry, isPrint, ignorePatterns, useGitIgnore, etc\n await transformer(options.targetPaths, codemodPath, isDebug);\n } else {\n await Promise.all(\n options.targetPaths.map(async (targetPath) => {\n console.info(\n `${CONSOLE_ICONS.focus} \\x1b[1mProcessing:\\x1b[0m \\x1b[32m${targetPath}\\x1b[0m`,\n );\n\n const isCompliant = assessPrerequisites(targetPath, codemodPath);\n if (isCompliant) {\n const answerArgs = Object.entries(promptAnswers).map(\n ([promptName, answerValue]) => `--${promptName}=${String(answerValue)}`,\n );\n\n const argsList = [\n '-t',\n codemodPath,\n targetPath,\n options.isDry ? '--dry' : '',\n options.isPrint ? '--print' : '',\n options.ignorePatterns\n ? options.ignorePatterns\n .split(',')\n .map((pattern) => `--ignore-pattern=${pattern.trim()}`)\n .join(' ')\n : '',\n options.useGitIgnore ? '--gitignore' : '',\n ...answerArgs,\n ].filter(Boolean);\n const command = `npx jscodeshift ${argsList.join(' ')}`;\n\n if (isDebug) {\n console.debug(`${CONSOLE_ICONS.info} Running: ${command}`);\n }\n\n return execSync(command, { stdio: 'inherit' });\n }\n return undefined;\n }),\n );\n }\n\n await summariseReportFile(reportPath);\n } catch (error: unknown) {\n if (error instanceof Error) {\n console.error(`${CONSOLE_ICONS.error} Error running ${candidate} codemod:`, error.message);\n } else {\n console.error(`${CONSOLE_ICONS.error} Error running ${candidate} codemod:`, error);\n }\n if (process.env.NODE_ENV !== 'test') {\n process.exit(1);\n }\n }\n}\n\nexport { runCodemod };\n","#!/usr/bin/env node\nimport { runCodemod } from './controller';\n\nvoid runCodemod();\n"],"mappings":"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"}
@@ -0,0 +1,347 @@
1
+ const require_helpers = require('./helpers-RWhTD5Is.js');
2
+ let node_child_process = require("node:child_process");
3
+ let node_path = require("node:path");
4
+ let node_fs = require("node:fs");
5
+ let __anthropic_ai_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
6
+
7
+ //#region src/constants.ts
8
+ const CONSOLE_ICONS = {
9
+ info: "\x1B[34mℹ\x1B[0m",
10
+ focus: "\x1B[34m➙\x1B[0m",
11
+ success: "\x1B[32m✔\x1B[0m",
12
+ warning: "\x1B[33m⚠\x1B[0m",
13
+ error: "\x1B[31m✖\x1B[0m"
14
+ };
15
+
16
+ //#endregion
17
+ //#region src/transforms/list-item/constants.ts
18
+ const DEPRECATED_COMPONENT_NAMES = [
19
+ "ActionOption",
20
+ "NavigationOption",
21
+ "NavigationOptionsList",
22
+ "Summary",
23
+ "SwitchOption",
24
+ "CheckboxOption",
25
+ "RadioOption"
26
+ ];
27
+ const MIGRATION_RULES = `Migration rules:
28
+ # Legacy Component → ListItem Migration Guide
29
+
30
+ ## Universal Rules
31
+
32
+ 1. \`title\` → \`title\` (direct)
33
+ 2. \`content\` or \`description\` → \`subtitle\`
34
+ 3. \`disabled\` stays on \`ListItem\` (not controls)
35
+ 4. Keep HTML attributes (\`id\`, \`name\`, \`aria-label\`), remove: \`as\`, \`complex\`, \`showMediaAtAllSizes\`, \`showMediaCircle\`, \`isContainerAligned\`
36
+ 5. In strings, don't convert \`\`to\`'\`or\`"\`. Preserve what is there.
37
+
38
+ ---
39
+
40
+ ## ActionOption → ListItem.Button
41
+
42
+ - \`action\` → Button children
43
+ - \`onClick\` → Button \`onClick\`
44
+ - Priority: default/\`"primary"\` → \`"primary"\`, \`"secondary"\` → \`"secondary-neutral"\`, \`"secondary-send"\` → \`"secondary"\`, \`"tertiary"\` → \`"tertiary"\`
45
+
46
+ \`\`\`tsx
47
+ <ActionOption title="Title" content="Text" action="Click" priority="secondary" onClick={fn} />
48
+
49
+ <ListItem title="Title" subtitle="Text" control={<ListItem.Button priority="secondary-neutral" onClick={fn}>Click</ListItem.Button>} />
50
+ \`\`\`
51
+
52
+ ---
53
+
54
+ ## CheckboxOption → ListItem.Checkbox
55
+
56
+ - \`onChange\`: \`(checked: boolean)\` → \`(event: ChangeEvent)\` use \`event.target.checked\`
57
+ - \`name\` move to Checkbox
58
+ - Don't move \`id\` to Checkbox
59
+
60
+ \`\`\`tsx
61
+ <CheckboxOption id="x" name="y" title="Title" content="Text" checked={v} onChange={(c) => set(c)} />
62
+
63
+ <ListItem title="Title" subtitle="Text" control={<ListItem.Checkbox name="y" checked={v} onChange={(e) => set(e.target.checked)} />} />
64
+ \`\`\`
65
+
66
+ ---
67
+
68
+ ## RadioOption → ListItem.Radio
69
+
70
+ - \`name\`, \`value\`, \`checked\`, \`onChange\` move to Radio
71
+ - Don't move \`id\` to Radio
72
+
73
+ \`\`\`tsx
74
+ <RadioOption id="x" name="y" value="v" title="Title" content="Text" checked={v==='v'} onChange={set} />
75
+
76
+ <ListItem title="Title" subtitle="Text" control={<ListItem.Radio name="y" value="v" checked={v==='v'} onChange={set} />} />
77
+ \`\`\`
78
+
79
+ ---
80
+
81
+ ## SwitchOption → ListItem.Switch
82
+
83
+ - \`onChange\` → \`onClick\`, toggle manually
84
+ - \`aria-label\` moves to Switch
85
+
86
+ \`\`\`tsx
87
+ <SwitchOption title="Title" content="Text" checked={v} aria-label="Toggle" onChange={set} />
88
+
89
+ <ListItem title="Title" subtitle="Text" control={<ListItem.Switch checked={v} aria-label="Toggle" onClick={() => set(!v)} />} />
90
+ \`\`\`
91
+
92
+ ---
93
+
94
+ ## NavigationOption → ListItem.Navigation
95
+
96
+ - \`onClick\` or \`href\` move to Navigation
97
+
98
+ \`\`\`tsx
99
+ <NavigationOption title="Title" content="Text" onClick={fn} />
100
+
101
+ <ListItem title="Title" subtitle="Text" control={<ListItem.Navigation onClick={fn} />} />
102
+ \`\`\`
103
+
104
+ ---
105
+
106
+ ## Option → ListItem
107
+
108
+ - Wrap \`media\` in \`ListItem.AvatarView\`
109
+
110
+ \`\`\`tsx
111
+ <Option media={<Icon />} title="Title" />
112
+
113
+ <ListItem title="Title" media={<ListItem.AvatarView><Icon /></ListItem.AvatarView>} />
114
+ \`\`\`
115
+
116
+ ---
117
+
118
+ ## Summary → ListItem
119
+
120
+ **Basic:**
121
+
122
+ - \`icon\` → wrap in \`ListItem.AvatarView\` with \`size={32}\` as \`media\`
123
+ - Remove \`size\` from child \`<Icon />\`
124
+
125
+ **Status:**
126
+
127
+ - \`Status.DONE\` → \`badge={{ status: 'positive' }}\`
128
+ - \`Status.PENDING\` → \`badge={{ status: 'pending' }}\`
129
+ - \`Status.NOT_DONE\` → no badge
130
+
131
+ **Action:**
132
+
133
+ - \`action.text\` → \`action.label\` in \`ListItem.AdditionalInfo\` as \`additionalInfo\`
134
+
135
+ **Info (requires state):**
136
+
137
+ - \`MODAL\` → \`ListItem.IconButton partiallyInteractive\` + \`<Modal>\` in \`control\`
138
+ - \`POPOVER\` → \`<Popover>\` wrapping \`ListItem.IconButton partiallyInteractive\` in \`control\`
139
+ - Use \`QuestionMarkCircle\` icon (import from \`@transferwise/icons\`)
140
+
141
+ \`\`\`tsx
142
+ // Basic
143
+ <Summary title="T" description="D" icon={<Icon />} />
144
+
145
+ <ListItem title="T" subtitle="D" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} />
146
+
147
+ // Status
148
+ <Summary title="T" description="D" icon={<Icon />} status={Status.DONE} />
149
+
150
+ <ListItem title="T" subtitle="D" media={<ListItem.AvatarView size={32} badge={{status:'positive'}}><Icon /></ListItem.AvatarView>} />
151
+
152
+ // Action
153
+ <Summary title="T" description="D" icon={<Icon />} action={{text:'Go', href:'/go'}} />
154
+
155
+ <ListItem title="T" subtitle="D" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} additionalInfo={<ListItem.AdditionalInfo action={{label:'Go', href:'/go'}} />} />
156
+
157
+ // Modal (add: const [open, setOpen] = useState(false))
158
+ <Summary title="T" description="D" icon={<Icon />} info={{title:'Help', content:'Text', presentation:'MODAL', 'aria-label':'Info'}} />
159
+
160
+ <ListItem title="T" subtitle="D" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} control={<ListItem.IconButton partiallyInteractive aria-label="Info" onClick={()=>setOpen(!open)}><QuestionMarkCircle /><Modal open={open} title="Help" body="Text" onClose={()=>setOpen(false)} /></ListItem.IconButton>} />
161
+
162
+ // Popover
163
+ <Summary title="T" description="D" icon={<Icon />} info={{title:'Help', content:'Text', presentation:'POPOVER', 'aria-label':'Info'}} />
164
+
165
+ <ListItem title="T" subtitle="D" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} control={<Popover title="Help" content="Text" onClose={()=>setOpen(false)}><ListItem.IconButton partiallyInteractive aria-label="Info"><QuestionMarkCircle /></ListItem.IconButton></Popover>} />
166
+ \`\`\`
167
+
168
+ ---
169
+
170
+ ## DefinitionList → Multiple ListItem
171
+
172
+ - Array → individual \`ListItem\`s
173
+ - \`value\` → \`subtitle\`
174
+ - \`key\` → React \`key\` prop
175
+ - Action type: "Edit"/"Update"/"View" → \`ListItem.Button priority="secondary-neutral"\`, "Change"/"Password" → \`ListItem.Navigation\`, "Copy" → \`ListItem.IconButton\`
176
+
177
+ \`\`\`tsx
178
+ <DefinitionList definitions={[
179
+ {title:'T1', value:'V1', key:'k1'},
180
+ {title:'T2', value:'V2', key:'k2', action:{label:'Edit', onClick:fn}}
181
+ ]} />
182
+
183
+
184
+ <ListItem key="k1" title="T1" subtitle="V1" />
185
+ <ListItem key="k2" title="T2" subtitle="V2" control={<ListItem.Button priority="secondary-neutral" onClick={fn}>Edit</ListItem.Button>} />
186
+
187
+ \`\`\`
188
+ `;
189
+ const SYSTEM_PROMPT = `Transform TypeScript/JSX code from legacy Wise Design System (WDS) components to the new ListItem component and ListItem subcomponents from '@transferwise/components'.
190
+
191
+ Read and transform each file individually, instead of reading them all at the start. Only make a single edit or write per file, once you've fully processed it.
192
+
193
+ Rules:
194
+ 1. Ignore any files that do not contain deprecated WDS components, unless they are necessary for context.
195
+ 2. Migrate components per provided migration rules
196
+ 3. Maintain TypeScript type safety and update types to match new API
197
+ 4. Map props: handle renamed, deprecated, new required, and changed types
198
+ 5. Update imports to new WDS components and types
199
+ 6. Preserve code style, formatting, and calculated logic
200
+ 7. Handle conditional rendering, spread props, and complex expressions
201
+ 8. Note: New components may lack feature parity with legacy versions
202
+ 9. Only modify code requiring changes per migration rules, and any impacted surrounding code for context.
203
+ 10. Provide only the transformed code as output, without explanations or additional text
204
+ 11. Do not summarise the initial user request in a response.
205
+ 12. Use glob or grep tool usage to find the files with deprecated components.
206
+ 13. Final result response should just be whether the migration was successful overall, or if any errors were encountered
207
+
208
+ Make the necessary updates to the files and do not respond with any explanations or reasoning.
209
+
210
+ You'll receive:
211
+ - File paths/directories to search in individual queries
212
+ - Deprecated component names at the end of this prompt
213
+ - Migration context and rules for each deprecated component
214
+
215
+ Deprecated components: ${DEPRECATED_COMPONENT_NAMES.join(", ")}.
216
+
217
+ ${MIGRATION_RULES}`;
218
+
219
+ //#endregion
220
+ //#region src/transforms/list-item/helpers.ts
221
+ /** Split the path to get the relative path after the directory, and wrap with ANSI color codes */
222
+ function formatPathOutput(directory, path) {
223
+ return `\x1b[32m${path ? path.split(directory)[1] ?? path : directory}\x1b[0m`;
224
+ }
225
+ /** Generates a formatted string representing the total elapsed time since the given start time */
226
+ function generateElapsedTime(startTime) {
227
+ const endTime = Date.now();
228
+ const elapsedTime = Math.floor((endTime - startTime) / 1e3);
229
+ const hours = Math.floor(elapsedTime / 3600);
230
+ const minutes = Math.floor(elapsedTime % 3600 / 60);
231
+ const seconds = elapsedTime % 60;
232
+ return `${hours ? `${hours}h ` : ""}${minutes ? `${minutes}m ` : ""}${seconds ? `${seconds}s` : ""}`;
233
+ }
234
+
235
+ //#endregion
236
+ //#region src/transforms/list-item/claude.ts
237
+ const CLAUDE_SETTINGS_FILE = ".claude/settings.json";
238
+ function getQueryOptions(sessionId, isDebug) {
239
+ const claudeSettingsPath = (0, node_path.resolve)(process.env.HOME || "", CLAUDE_SETTINGS_FILE);
240
+ const settings = JSON.parse((0, node_fs.readFileSync)(claudeSettingsPath, "utf-8"));
241
+ let apiKey;
242
+ try {
243
+ apiKey = (0, node_child_process.execSync)(`bash ${settings.apiKeyHelper}`, { encoding: "utf-8" }).trim();
244
+ } catch {}
245
+ if (!apiKey) throw new Error("Failed to retrieve Anthropic API key. Please check your Claude Code x LLM Gateway configuration - https://transferwise.atlassian.net/wiki/x/_YUe3Q");
246
+ const envVars = {
247
+ ANTHROPIC_AUTH_TOKEN: apiKey,
248
+ ANTHROPIC_BASE_URL: settings?.env?.ANTHROPIC_BASE_URL,
249
+ ANTHROPIC_CUSTOM_HEADERS: settings?.env?.ANTHROPIC_CUSTOM_HEADERS,
250
+ ANTHROPIC_DEFAULT_SONNET_MODEL: settings.env?.ANTHROPIC_DEFAULT_SONNET_MODEL,
251
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: settings.env?.ANTHROPIC_DEFAULT_HAIKU_MODEL,
252
+ ANTHROPIC_DEFAULT_OPUS_MODEL: settings.env?.ANTHROPIC_DEFAULT_OPUS_MODEL,
253
+ API_TIMEOUT_MS: settings.env?.API_TIMEOUT_MS,
254
+ PATH: process.env.PATH
255
+ };
256
+ if (isDebug) {
257
+ const { ANTHROPIC_AUTH_TOKEN, ...restVars } = envVars;
258
+ console.log(`${CONSOLE_ICONS.info} Claude configuration environment variables:`, JSON.stringify(restVars));
259
+ }
260
+ return {
261
+ resume: sessionId,
262
+ env: envVars,
263
+ permissionMode: "acceptEdits",
264
+ systemPrompt: {
265
+ type: "preset",
266
+ preset: "claude_code",
267
+ append: SYSTEM_PROMPT
268
+ },
269
+ settingSources: [
270
+ "local",
271
+ "project",
272
+ "user"
273
+ ]
274
+ };
275
+ }
276
+ /** Initiate a new Claude session/conversation and return reusable options */
277
+ async function initiateClaudeSessionOptions(isDebug = false) {
278
+ console.log(`${CONSOLE_ICONS.info} Starting Claude instance - your browser may open for Okta authentication if required.`);
279
+ const options = getQueryOptions(void 0, isDebug);
280
+ const result = (0, __anthropic_ai_claude_agent_sdk.query)({
281
+ options,
282
+ prompt: `You'll be given directories in additional individual queries to search in for files using deprecated Wise Design System (WDS) components. Migrate the code per the provided migration rules.`
283
+ });
284
+ for await (const message of result) switch (message.type) {
285
+ case "system":
286
+ if (message.subtype === "init" && !options.resume) {
287
+ console.log(`${CONSOLE_ICONS.success} Successfully initialised Claude instance`);
288
+ options.resume = message.session_id;
289
+ }
290
+ break;
291
+ default: if (message.type === "result" && message.subtype !== "success") console.log(`${CONSOLE_ICONS.error} Claude encountered an error: ${message.errors.join("\n")}`);
292
+ }
293
+ return options;
294
+ }
295
+ async function queryClaude(path, options, isDebug = false) {
296
+ const result = (0, __anthropic_ai_claude_agent_sdk.query)({
297
+ options,
298
+ prompt: path
299
+ });
300
+ const modifiedFiles = [];
301
+ for await (const message of result) switch (message.type) {
302
+ case "assistant":
303
+ for (const msg of message.message.content) switch (msg.type) {
304
+ case "tool_use":
305
+ if (msg.name === "Glob" || msg.name === "Grep") console.log(`${CONSOLE_ICONS.focus} Processing directory: ${formatPathOutput(path)}...`);
306
+ else if (msg.name === "Read") console.log(`${CONSOLE_ICONS.info} Reading ${formatPathOutput(path, msg.input.file_path)}`);
307
+ else if ((msg.name === "Write" || msg.name === "Edit") && !modifiedFiles.includes(msg.input.file_path)) {
308
+ modifiedFiles.push(msg.input.file_path);
309
+ console.log(`${CONSOLE_ICONS.info} Migrated ${formatPathOutput(path, msg.input.file_path)}`);
310
+ }
311
+ break;
312
+ default:
313
+ }
314
+ break;
315
+ case "result":
316
+ if (message.subtype === "success") console.log(`${CONSOLE_ICONS.success} Migrated all applicable files in ${formatPathOutput(path)}`);
317
+ else console.log(`${CONSOLE_ICONS.error} Claude encountered an error: ${message.errors.join("\n").trim()}`);
318
+ break;
319
+ default:
320
+ }
321
+ }
322
+
323
+ //#endregion
324
+ //#region src/transforms/list-item/transformer.ts
325
+ const transformer = async (targetPaths, codemodPath, isDebug = false) => {
326
+ const startTime = Date.now();
327
+ const queryOptions = await initiateClaudeSessionOptions(isDebug);
328
+ console.log(`${CONSOLE_ICONS.info} Analysing targetted paths - this may take a while...`);
329
+ for (const directory of targetPaths) if (require_helpers.assessPrerequisites(directory, codemodPath)) await queryClaude(directory, queryOptions, isDebug);
330
+ console.log(`${CONSOLE_ICONS.success} Finished migrating - elapsed time: \x1b[1m${generateElapsedTime(startTime)}\x1b[0m`);
331
+ };
332
+ var transformer_default = transformer;
333
+
334
+ //#endregion
335
+ Object.defineProperty(exports, 'CONSOLE_ICONS', {
336
+ enumerable: true,
337
+ get: function () {
338
+ return CONSOLE_ICONS;
339
+ }
340
+ });
341
+ Object.defineProperty(exports, 'transformer_default', {
342
+ enumerable: true,
343
+ get: function () {
344
+ return transformer_default;
345
+ }
346
+ });
347
+ //# sourceMappingURL=transformer-BQ6Pzrxx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformer-BQ6Pzrxx.js","names":["modifiedFiles: string[]","assessPrerequisites"],"sources":["../src/constants.ts","../src/transforms/list-item/constants.ts","../src/transforms/list-item/helpers.ts","../src/transforms/list-item/claude.ts","../src/transforms/list-item/transformer.ts"],"sourcesContent":["export const CONSOLE_ICONS = {\n info: '\\x1b[34mℹ\\x1b[0m', // Blue info icon\n focus: '\\x1b[34m➙\\x1b[0m', // Blue arrow icon\n success: '\\x1b[32m✔\\x1b[0m', // Green checkmark\n warning: '\\x1b[33m⚠\\x1b[0m', // Yellow warning icon\n error: '\\x1b[31m✖\\x1b[0m', // Red cross icon\n};\n","const DEPRECATED_COMPONENT_NAMES = [\n 'ActionOption',\n 'NavigationOption',\n 'NavigationOptionsList',\n 'Summary',\n 'SwitchOption',\n 'CheckboxOption',\n 'RadioOption',\n];\n\nconst MIGRATION_RULES = `Migration rules:\n# Legacy Component → ListItem Migration Guide\n\n## Universal Rules\n\n1. \\`title\\` → \\`title\\` (direct)\n2. \\`content\\` or \\`description\\` → \\`subtitle\\`\n3. \\`disabled\\` stays on \\`ListItem\\` (not controls)\n4. Keep HTML attributes (\\`id\\`, \\`name\\`, \\`aria-label\\`), remove: \\`as\\`, \\`complex\\`, \\`showMediaAtAllSizes\\`, \\`showMediaCircle\\`, \\`isContainerAligned\\`\n5. In strings, don't convert \\`\\`to\\`'\\`or\\`\"\\`. Preserve what is there.\n\n---\n\n## ActionOption → ListItem.Button\n\n- \\`action\\` → Button children\n- \\`onClick\\` → Button \\`onClick\\`\n- Priority: default/\\`\"primary\"\\` → \\`\"primary\"\\`, \\`\"secondary\"\\` → \\`\"secondary-neutral\"\\`, \\`\"secondary-send\"\\` → \\`\"secondary\"\\`, \\`\"tertiary\"\\` → \\`\"tertiary\"\\`\n\n\\`\\`\\`tsx\n<ActionOption title=\"Title\" content=\"Text\" action=\"Click\" priority=\"secondary\" onClick={fn} />\n→\n<ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Button priority=\"secondary-neutral\" onClick={fn}>Click</ListItem.Button>} />\n\\`\\`\\`\n\n---\n\n## CheckboxOption → ListItem.Checkbox\n\n- \\`onChange\\`: \\`(checked: boolean)\\` → \\`(event: ChangeEvent)\\` use \\`event.target.checked\\`\n- \\`name\\` move to Checkbox\n- Don't move \\`id\\` to Checkbox\n\n\\`\\`\\`tsx\n<CheckboxOption id=\"x\" name=\"y\" title=\"Title\" content=\"Text\" checked={v} onChange={(c) => set(c)} />\n→\n<ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Checkbox name=\"y\" checked={v} onChange={(e) => set(e.target.checked)} />} />\n\\`\\`\\`\n\n---\n\n## RadioOption → ListItem.Radio\n\n- \\`name\\`, \\`value\\`, \\`checked\\`, \\`onChange\\` move to Radio\n- Don't move \\`id\\` to Radio\n\n\\`\\`\\`tsx\n<RadioOption id=\"x\" name=\"y\" value=\"v\" title=\"Title\" content=\"Text\" checked={v==='v'} onChange={set} />\n→\n<ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Radio name=\"y\" value=\"v\" checked={v==='v'} onChange={set} />} />\n\\`\\`\\`\n\n---\n\n## SwitchOption → ListItem.Switch\n\n- \\`onChange\\` → \\`onClick\\`, toggle manually\n- \\`aria-label\\` moves to Switch\n\n\\`\\`\\`tsx\n<SwitchOption title=\"Title\" content=\"Text\" checked={v} aria-label=\"Toggle\" onChange={set} />\n→\n<ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Switch checked={v} aria-label=\"Toggle\" onClick={() => set(!v)} />} />\n\\`\\`\\`\n\n---\n\n## NavigationOption → ListItem.Navigation\n\n- \\`onClick\\` or \\`href\\` move to Navigation\n\n\\`\\`\\`tsx\n<NavigationOption title=\"Title\" content=\"Text\" onClick={fn} />\n→\n<ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Navigation onClick={fn} />} />\n\\`\\`\\`\n\n---\n\n## Option → ListItem\n\n- Wrap \\`media\\` in \\`ListItem.AvatarView\\`\n\n\\`\\`\\`tsx\n<Option media={<Icon />} title=\"Title\" />\n→\n<ListItem title=\"Title\" media={<ListItem.AvatarView><Icon /></ListItem.AvatarView>} />\n\\`\\`\\`\n\n---\n\n## Summary → ListItem\n\n**Basic:**\n\n- \\`icon\\` → wrap in \\`ListItem.AvatarView\\` with \\`size={32}\\` as \\`media\\`\n- Remove \\`size\\` from child \\`<Icon />\\`\n\n**Status:**\n\n- \\`Status.DONE\\` → \\`badge={{ status: 'positive' }}\\`\n- \\`Status.PENDING\\` → \\`badge={{ status: 'pending' }}\\`\n- \\`Status.NOT_DONE\\` → no badge\n\n**Action:**\n\n- \\`action.text\\` → \\`action.label\\` in \\`ListItem.AdditionalInfo\\` as \\`additionalInfo\\`\n\n**Info (requires state):**\n\n- \\`MODAL\\` → \\`ListItem.IconButton partiallyInteractive\\` + \\`<Modal>\\` in \\`control\\`\n- \\`POPOVER\\` → \\`<Popover>\\` wrapping \\`ListItem.IconButton partiallyInteractive\\` in \\`control\\`\n- Use \\`QuestionMarkCircle\\` icon (import from \\`@transferwise/icons\\`)\n\n\\`\\`\\`tsx\n// Basic\n<Summary title=\"T\" description=\"D\" icon={<Icon />} />\n→\n<ListItem title=\"T\" subtitle=\"D\" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} />\n\n// Status\n<Summary title=\"T\" description=\"D\" icon={<Icon />} status={Status.DONE} />\n→\n<ListItem title=\"T\" subtitle=\"D\" media={<ListItem.AvatarView size={32} badge={{status:'positive'}}><Icon /></ListItem.AvatarView>} />\n\n// Action\n<Summary title=\"T\" description=\"D\" icon={<Icon />} action={{text:'Go', href:'/go'}} />\n→\n<ListItem title=\"T\" subtitle=\"D\" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} additionalInfo={<ListItem.AdditionalInfo action={{label:'Go', href:'/go'}} />} />\n\n// Modal (add: const [open, setOpen] = useState(false))\n<Summary title=\"T\" description=\"D\" icon={<Icon />} info={{title:'Help', content:'Text', presentation:'MODAL', 'aria-label':'Info'}} />\n→\n<ListItem title=\"T\" subtitle=\"D\" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} control={<ListItem.IconButton partiallyInteractive aria-label=\"Info\" onClick={()=>setOpen(!open)}><QuestionMarkCircle /><Modal open={open} title=\"Help\" body=\"Text\" onClose={()=>setOpen(false)} /></ListItem.IconButton>} />\n\n// Popover\n<Summary title=\"T\" description=\"D\" icon={<Icon />} info={{title:'Help', content:'Text', presentation:'POPOVER', 'aria-label':'Info'}} />\n→\n<ListItem title=\"T\" subtitle=\"D\" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} control={<Popover title=\"Help\" content=\"Text\" onClose={()=>setOpen(false)}><ListItem.IconButton partiallyInteractive aria-label=\"Info\"><QuestionMarkCircle /></ListItem.IconButton></Popover>} />\n\\`\\`\\`\n\n---\n\n## DefinitionList → Multiple ListItem\n\n- Array → individual \\`ListItem\\`s\n- \\`value\\` → \\`subtitle\\`\n- \\`key\\` → React \\`key\\` prop\n- Action type: \"Edit\"/\"Update\"/\"View\" → \\`ListItem.Button priority=\"secondary-neutral\"\\`, \"Change\"/\"Password\" → \\`ListItem.Navigation\\`, \"Copy\" → \\`ListItem.IconButton\\`\n\n\\`\\`\\`tsx\n<DefinitionList definitions={[\n {title:'T1', value:'V1', key:'k1'},\n {title:'T2', value:'V2', key:'k2', action:{label:'Edit', onClick:fn}}\n]} />\n→\n\n <ListItem key=\"k1\" title=\"T1\" subtitle=\"V1\" />\n <ListItem key=\"k2\" title=\"T2\" subtitle=\"V2\" control={<ListItem.Button priority=\"secondary-neutral\" onClick={fn}>Edit</ListItem.Button>} />\n\n\\`\\`\\`\n`;\n\nexport const SYSTEM_PROMPT = `Transform TypeScript/JSX code from legacy Wise Design System (WDS) components to the new ListItem component and ListItem subcomponents from '@transferwise/components'.\n\nRead and transform each file individually, instead of reading them all at the start. Only make a single edit or write per file, once you've fully processed it.\n\nRules:\n1. Ignore any files that do not contain deprecated WDS components, unless they are necessary for context.\n2. Migrate components per provided migration rules\n3. Maintain TypeScript type safety and update types to match new API\n4. Map props: handle renamed, deprecated, new required, and changed types\n5. Update imports to new WDS components and types\n6. Preserve code style, formatting, and calculated logic\n7. Handle conditional rendering, spread props, and complex expressions\n8. Note: New components may lack feature parity with legacy versions\n9. Only modify code requiring changes per migration rules, and any impacted surrounding code for context.\n10. Provide only the transformed code as output, without explanations or additional text\n11. Do not summarise the initial user request in a response.\n12. Use glob or grep tool usage to find the files with deprecated components.\n13. Final result response should just be whether the migration was successful overall, or if any errors were encountered\n\nMake the necessary updates to the files and do not respond with any explanations or reasoning. \n\nYou'll receive:\n- File paths/directories to search in individual queries\n- Deprecated component names at the end of this prompt\n- Migration context and rules for each deprecated component\n\nDeprecated components: ${DEPRECATED_COMPONENT_NAMES.join(', ')}.\n\n${MIGRATION_RULES}`;\n","/** Split the path to get the relative path after the directory, and wrap with ANSI color codes */\nexport function formatPathOutput(directory: string, path?: string): string {\n return `\\x1b[32m${path ? (path.split(directory)[1] ?? path) : directory}\\x1b[0m`;\n}\n\n/** Generates a formatted string representing the total elapsed time since the given start time */\nexport function generateElapsedTime(startTime: number): string {\n const endTime = Date.now();\n const elapsedTime = Math.floor((endTime - startTime) / 1000);\n const hours = Math.floor(elapsedTime / 3600);\n const minutes = Math.floor((elapsedTime % 3600) / 60);\n const seconds = elapsedTime % 60;\n\n return `${hours ? `${hours}h ` : ''}${minutes ? `${minutes}m ` : ''}${seconds ? `${seconds}s` : ''}`;\n}\n","import { type Options, query } from '@anthropic-ai/claude-agent-sdk';\nimport { execSync } from 'child_process';\nimport { readFileSync } from 'fs';\nimport { resolve } from 'path';\n\nimport { CONSOLE_ICONS } from '../../constants';\nimport { SYSTEM_PROMPT } from './constants';\nimport { formatPathOutput } from './helpers';\nimport type { ClaudeResponseToolUse, ClaudeSettings } from './types';\n\nconst CLAUDE_SETTINGS_FILE = '.claude/settings.json';\n\nexport function getQueryOptions(sessionId?: string, isDebug?: boolean): Options {\n // Read settings from ~/.claude/settings.json to get headers and apiKeyHelper\n const claudeSettingsPath = resolve(process.env.HOME || '', CLAUDE_SETTINGS_FILE);\n const settings = JSON.parse(readFileSync(claudeSettingsPath, 'utf-8')) as ClaudeSettings;\n\n // Get API key by executing the apiKeyHelper script, for authenticating with Okta via LLM Gateway\n let apiKey;\n try {\n apiKey = execSync(`bash ${settings.apiKeyHelper}`, {\n encoding: 'utf-8',\n }).trim();\n } catch {}\n\n if (!apiKey) {\n throw new Error(\n 'Failed to retrieve Anthropic API key. Please check your Claude Code x LLM Gateway configuration - https://transferwise.atlassian.net/wiki/x/_YUe3Q',\n );\n }\n\n const envVars = {\n ANTHROPIC_AUTH_TOKEN: apiKey,\n ANTHROPIC_BASE_URL: settings?.env?.ANTHROPIC_BASE_URL,\n ANTHROPIC_CUSTOM_HEADERS: settings?.env?.ANTHROPIC_CUSTOM_HEADERS,\n ANTHROPIC_DEFAULT_SONNET_MODEL: settings.env?.ANTHROPIC_DEFAULT_SONNET_MODEL,\n ANTHROPIC_DEFAULT_HAIKU_MODEL: settings.env?.ANTHROPIC_DEFAULT_HAIKU_MODEL,\n ANTHROPIC_DEFAULT_OPUS_MODEL: settings.env?.ANTHROPIC_DEFAULT_OPUS_MODEL,\n API_TIMEOUT_MS: settings.env?.API_TIMEOUT_MS,\n PATH: process.env.PATH, // Specifying PATH, as Claude Agent SDK seems to struggle consuming the actual environment PATH\n };\n\n if (isDebug) {\n // Not logging the auth token for security reasons\n const { ANTHROPIC_AUTH_TOKEN, ...restVars } = envVars;\n console.log(\n `${CONSOLE_ICONS.info} Claude configuration environment variables:`,\n JSON.stringify(restVars),\n );\n }\n\n return {\n resume: sessionId,\n env: envVars,\n permissionMode: 'acceptEdits',\n systemPrompt: {\n type: 'preset',\n preset: 'claude_code',\n append: SYSTEM_PROMPT,\n },\n settingSources: ['local', 'project', 'user'],\n };\n}\n\n/** Initiate a new Claude session/conversation and return reusable options */\nexport async function initiateClaudeSessionOptions(isDebug = false): Promise<Options> {\n console.log(\n `${CONSOLE_ICONS.info} Starting Claude instance - your browser may open for Okta authentication if required.`,\n );\n\n const options = getQueryOptions(undefined, isDebug);\n const result = query({\n options,\n prompt: `You'll be given directories in additional individual queries to search in for files using deprecated Wise Design System (WDS) components. Migrate the code per the provided migration rules.`,\n });\n\n for await (const message of result) {\n switch (message.type) {\n case 'system':\n if (message.subtype === 'init' && !options.resume) {\n console.log(`${CONSOLE_ICONS.success} Successfully initialised Claude instance`);\n\n // Set the session ID to resume the conversation in future queries\n options.resume = message.session_id;\n }\n break;\n default:\n if (message.type === 'result' && message.subtype !== 'success') {\n console.log(\n `${CONSOLE_ICONS.error} Claude encountered an error: ${message.errors.join('\\n')}`,\n );\n }\n }\n }\n\n return options;\n}\n\nexport async function queryClaude(path: string, options: Options, isDebug = false) {\n const result = query({\n options,\n prompt: path,\n });\n const modifiedFiles: string[] = [];\n\n for await (const message of result) {\n switch (message.type) {\n case 'assistant':\n for (const msg of message.message.content) {\n switch (msg.type) {\n // Handles logging of tool uses to determine key stages of the migration ()\n case 'tool_use':\n if (msg.name === 'Glob' || msg.name === 'Grep') {\n console.log(\n `${CONSOLE_ICONS.focus} Processing directory: ${formatPathOutput(path)}...`,\n );\n // NOTE: Possibly want to only log reading files when in debug mode, to reduce noise\n } else if (msg.name === 'Read') {\n console.log(\n `${CONSOLE_ICONS.info} Reading ${formatPathOutput(path, (msg as ClaudeResponseToolUse).input.file_path)}`,\n );\n } else if (\n (msg.name === 'Write' || msg.name === 'Edit') &&\n !modifiedFiles.includes((msg as ClaudeResponseToolUse).input.file_path) // Safeguard against duplicate logs, where Claude may write multiple times to the same file\n ) {\n modifiedFiles.push((msg as ClaudeResponseToolUse).input.file_path);\n console.log(\n `${CONSOLE_ICONS.info} Migrated ${formatPathOutput(path, (msg as ClaudeResponseToolUse).input.file_path)}`,\n );\n }\n break;\n default:\n }\n }\n break;\n case 'result':\n if (message.subtype === 'success') {\n // TODO: Handle case where migration failed for some files?\n console.log(\n `${CONSOLE_ICONS.success} Migrated all applicable files in ${formatPathOutput(path)}`,\n );\n } else {\n console.log(\n `${CONSOLE_ICONS.error} Claude encountered an error: ${message.errors.join('\\n').trim()}`,\n );\n }\n break;\n default:\n }\n }\n}\n","import { CONSOLE_ICONS } from '../../constants';\nimport { assessPrerequisites } from '../../controller/helpers';\nimport { initiateClaudeSessionOptions, queryClaude } from './claude';\nimport { generateElapsedTime } from './helpers';\n\nconst transformer = async (targetPaths: string[], codemodPath: string, isDebug = false) => {\n const startTime = Date.now();\n\n // TODO: We need to check whether the user is connected to the VPN\n\n const queryOptions = await initiateClaudeSessionOptions(isDebug);\n\n console.log(`${CONSOLE_ICONS.info} Analysing targetted paths - this may take a while...`);\n\n for (const directory of targetPaths) {\n const isCompliant = assessPrerequisites(directory, codemodPath);\n\n if (isCompliant) {\n // TODO: Potential improvement could be getting all of the file paths first -\n // Make sure claude can still handle related files (imported components/wrapping parents)\n // Get all files within directory, and call queryClaude for each file\n await queryClaude(directory, queryOptions, isDebug);\n }\n\n // await queryClaude(directory, queryOptions, isDebug);\n }\n\n console.log(\n `${CONSOLE_ICONS.success} Finished migrating - elapsed time: \\x1b[1m${generateElapsedTime(startTime)}\\x1b[0m`,\n );\n};\n\nexport default transformer;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
- const require_helpers = require('../../helpers-auDAwIcO.js');
2
+ const require_helpers = require('../../helpers-RWhTD5Is.js');
3
3
 
4
4
  //#region src/helpers/addImport.ts
5
5
  /**
@@ -106,9 +106,7 @@ const processIconChildren = (j, children, iconImports, openingElement) => {
106
106
  const iconChild = unwrapJsxElement(children[iconChildIndex]);
107
107
  if (!iconChild || iconChild.openingElement.name.type !== "JSXIdentifier") return;
108
108
  iconChild.openingElement.name.name;
109
- const distanceToStart = iconChildIndex;
110
- const distanceToEnd = totalChildren - 1 - iconChildIndex;
111
- const iconPropName = distanceToStart <= distanceToEnd ? "addonStart" : "addonEnd";
109
+ const iconPropName = iconChildIndex <= totalChildren - 1 - iconChildIndex ? "addonStart" : "addonEnd";
112
110
  const iconObject = j.objectExpression([j.property("init", j.identifier("type"), j.literal("icon")), j.property("init", j.identifier("value"), iconChild)]);
113
111
  const iconProp = j.jsxAttribute(j.jsxIdentifier(iconPropName), j.jsxExpressionContainer(iconObject));
114
112
  openingElement.attributes.push(iconProp);
@@ -333,10 +331,7 @@ var CodemodReporter = class {
333
331
  if (attr.value.type === "JSXExpressionContainer") {
334
332
  const expr = attr.value.expression;
335
333
  const expressionType = expr.type.replace("Expression", "").toLowerCase();
336
- if (expr.type === "Identifier" || expr.type === "MemberExpression") {
337
- const valueText = this.j(expr).toSource();
338
- return `contains a ${expressionType} (${valueText})`;
339
- }
334
+ if (expr.type === "Identifier" || expr.type === "MemberExpression") return `contains a ${expressionType} (${this.j(expr).toSource()})`;
340
335
  return `contains a complex ${expressionType} expression`;
341
336
  }
342
337
  return "needs manual review";