@wise/wds-codemods 1.0.0-experimental-dfd0a93 → 1.0.0-experimental-d309319

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.
@@ -1,12 +1,13 @@
1
- const require_helpers = require('./helpers-Cca1yIbM.js');
1
+ const require_chunk = require('./chunk-CInkuQNp.js');
2
2
  let node_child_process = require("node:child_process");
3
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
- let node_https = require("node:https");
7
- node_https = require_helpers.__toESM(node_https);
8
4
  let ora = require("ora");
9
- ora = require_helpers.__toESM(ora);
5
+ ora = require_chunk.__toESM(ora);
6
+ let node_https = require("node:https");
7
+ node_https = require_chunk.__toESM(node_https);
8
+ let __anthropic_ai_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
9
+ let node_fs = require("node:fs");
10
+ let diff = require("diff");
10
11
 
11
12
  //#region src/constants.ts
12
13
  const CONSOLE_ICONS = {
@@ -14,7 +15,8 @@ const CONSOLE_ICONS = {
14
15
  focus: "\x1B[34m➙\x1B[0m",
15
16
  success: "\x1B[32m✔\x1B[0m",
16
17
  warning: "\x1B[33m⚠\x1B[0m",
17
- error: "\x1B[31m✖\x1B[0m"
18
+ error: "\x1B[31m✖\x1B[0m",
19
+ claude: "\x1B[35m💬\x1B[0m"
18
20
  };
19
21
 
20
22
  //#endregion
@@ -190,26 +192,29 @@ const MIGRATION_RULES = `Migration rules:
190
192
 
191
193
  \`\`\`
192
194
  `;
193
- 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'.
195
+ const SYSTEM_PROMPT = `You are a code migration assistant that helps migrate TypeScript/JSX code from deprecated Wise Design System (WDS) components to the new ListItem component and ListItem subcomponents from '@transferwise/components'.
194
196
 
195
- 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.
197
+ Process each file individually, before reading the next file, making a single comprehensive edit per file to replace all necessary code according to the migration context and rules provided.
196
198
 
197
199
  Rules:
198
- 1. Ignore any files that do not contain deprecated WDS components, unless they are necessary for context.
199
- 2. Migrate components per provided migration rules
200
- 3. Maintain TypeScript type safety and update types to match new API
201
- 4. Map props: handle renamed, deprecated, new required, and changed types
202
- 5. Update imports to new WDS components and types
203
- 6. Preserve code style, formatting, and calculated logic
204
- 7. Handle conditional rendering, spread props, and complex expressions
205
- 8. Note: New components may lack feature parity with legacy versions
206
- 9. Only modify code requiring changes per migration rules, and any impacted surrounding code for context.
207
- 10. Provide only the transformed code as output, without explanations or additional text
200
+ 1. Ignore any files that do not contain deprecated WDS components and are not .tsx files, unless they are necessary for context.
201
+ 2. Do not migrate files matching the provided patterns in the ignore list.
202
+ 3. Migrate components per provided migration rules
203
+ 4. Maintain TypeScript type safety and update types to match new API
204
+ 5. Map props: handle renamed, deprecated, new required, and changed types
205
+ 6. Update imports to new WDS components and types
206
+ 7. Preserve code style, formatting, and calculated logic
207
+ 8. Handle conditional rendering, spread props, and complex expressions
208
+ 9. Note: New components may lack feature parity with legacy versions
209
+ 10. Only modify code requiring changes per migration rules, and any impacted surrounding code for context.
208
210
  11. Do not summarise the initial user request in a response.
209
- 12. Use glob or grep tool usage to find the files with deprecated components.
211
+ 12. Use glob to find files in the directory and then grep to identify files with deprecated imports.
210
212
  13. Final result response should just be whether the migration was successful overall, or if any errors were encountered
213
+ 14. Explain your reasoning and justification before making changes, as you edit each file. Keep it concise and succinct as only bullet points
214
+ 15. Do not summarise the changes made after modifying a file.
215
+ 16. If you do not have permission to modify a file, still attempt to edit it and then move onto the next file.
211
216
 
212
- Make the necessary updates to the files and do not respond with any explanations or reasoning.
217
+ Make the necessary updates to the files.
213
218
 
214
219
  You'll receive:
215
220
  - File paths/directories to search in individual queries
@@ -235,6 +240,40 @@ function generateElapsedTime(startTime) {
235
240
  const seconds = elapsedTime % 60;
236
241
  return `${hours ? `${hours}h ` : ""}${minutes ? `${minutes}m ` : ""}${seconds ? `${seconds}s` : ""}`;
237
242
  }
243
+ function formatClaudeResponseContent(content) {
244
+ return `\x1b[2m${content.replace(/\*\*(.+?)\*\*/gu, "\x1B[1m$1\x1B[0m\x1B[2m").replace(/`(.+?)`/gu, "\x1B[32m$1\x1B[0m\x1B[2m").split("\n").map((line, index) => index === 0 ? line : ` ${line}`).join("\n")}\x1b[0m`;
245
+ }
246
+ function generateDiff(original, modified) {
247
+ const lines = (0, diff.createPatch)("", original, modified, "", "").trim().split("\n").slice(4).filter((line) => !line.startsWith("\"));
248
+ let oldLineNumber = 0;
249
+ let newLineNumber = 0;
250
+ return lines.map((line) => {
251
+ const trimmedLine = line.trimEnd();
252
+ if (trimmedLine.startsWith("@@")) {
253
+ const match = /@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/u.exec(trimmedLine);
254
+ if (match) {
255
+ oldLineNumber = Number.parseInt(match[1], 10);
256
+ newLineNumber = Number.parseInt(match[2], 10);
257
+ }
258
+ return `\x1b[36m${trimmedLine}\x1b[0m`;
259
+ }
260
+ let linePrefix = "";
261
+ if (trimmedLine.startsWith("+")) {
262
+ linePrefix = `${newLineNumber.toString().padStart(4, " ")} `;
263
+ newLineNumber += 1;
264
+ return `\x1b[32m${linePrefix}${trimmedLine}\x1b[0m`;
265
+ }
266
+ if (trimmedLine.startsWith("-")) {
267
+ linePrefix = `${oldLineNumber.toString().padStart(4, " ")} `;
268
+ oldLineNumber += 1;
269
+ return `\x1b[31m${linePrefix}${trimmedLine}\x1b[0m`;
270
+ }
271
+ linePrefix = `${oldLineNumber.toString().padStart(4, " ")} `;
272
+ oldLineNumber += 1;
273
+ newLineNumber += 1;
274
+ return `${linePrefix}${trimmedLine}`;
275
+ }).join("\n");
276
+ }
238
277
 
239
278
  //#endregion
240
279
  //#region src/transforms/list-item/claude.ts
@@ -242,7 +281,7 @@ const CLAUDE_SETTINGS_FILE = ".claude/settings.json";
242
281
  async function checkVPN(baseUrl) {
243
282
  if (baseUrl) {
244
283
  const vpnSpinner = (0, ora.default)("Checking VPN connection...").start();
245
- const checkOnce = async () => await new Promise((resolveCheck) => {
284
+ const checkOnce = async () => new Promise((resolveCheck) => {
246
285
  const url = new URL("/health", baseUrl);
247
286
  const req = node_https.default.get(url, {
248
287
  timeout: 2e3,
@@ -270,7 +309,7 @@ async function checkVPN(baseUrl) {
270
309
  }
271
310
  return true;
272
311
  }
273
- function getQueryOptions(sessionId, isDebug) {
312
+ function getQueryOptions(sessionId, codemodOptions, isDebug) {
274
313
  const claudeSettingsPath = (0, node_path.resolve)(process.env.HOME || "", CLAUDE_SETTINGS_FILE);
275
314
  const settings = JSON.parse((0, node_fs.readFileSync)(claudeSettingsPath, "utf-8"));
276
315
  let apiKey;
@@ -278,29 +317,34 @@ function getQueryOptions(sessionId, isDebug) {
278
317
  apiKey = (0, node_child_process.execSync)(`bash ${settings.apiKeyHelper}`, { encoding: "utf-8" }).trim();
279
318
  } catch {}
280
319
  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");
320
+ const { ANTHROPIC_CUSTOM_HEADERS, ...restEnvVars } = settings?.env || {};
281
321
  const envVars = {
282
322
  ANTHROPIC_AUTH_TOKEN: apiKey,
283
- ANTHROPIC_BASE_URL: settings?.env?.ANTHROPIC_BASE_URL,
284
- ANTHROPIC_CUSTOM_HEADERS: settings?.env?.ANTHROPIC_CUSTOM_HEADERS,
285
- ANTHROPIC_DEFAULT_SONNET_MODEL: settings.env?.ANTHROPIC_DEFAULT_SONNET_MODEL,
286
- ANTHROPIC_DEFAULT_HAIKU_MODEL: settings.env?.ANTHROPIC_DEFAULT_HAIKU_MODEL,
287
- ANTHROPIC_DEFAULT_OPUS_MODEL: settings.env?.ANTHROPIC_DEFAULT_OPUS_MODEL,
288
- API_TIMEOUT_MS: settings.env?.API_TIMEOUT_MS,
323
+ ANTHROPIC_CUSTOM_HEADERS,
324
+ ...restEnvVars,
289
325
  PATH: process.env.PATH
290
326
  };
291
327
  if (isDebug) {
292
328
  const { ANTHROPIC_AUTH_TOKEN, ...restVars } = envVars;
293
- console.log(`${CONSOLE_ICONS.info} Claude configuration environment variables:`, JSON.stringify(restVars));
329
+ console.log(`${CONSOLE_ICONS.info} Claude configuration environment variables, excluding ANTHROPIC_AUTH_TOKEN:`);
330
+ console.log(restVars);
294
331
  }
332
+ const promptPrefix = !codemodOptions?.useGitIgnore ? "Do not use .gitignore to exclude files from the migration. Ensure all relevant files are included." : "Respect .gitignore when determining which files to include in the migration.";
295
333
  return {
296
334
  resume: sessionId,
297
335
  env: envVars,
298
- permissionMode: "acceptEdits",
336
+ permissionMode: codemodOptions?.isDry ? void 0 : "acceptEdits",
299
337
  systemPrompt: {
300
338
  type: "preset",
301
339
  preset: "claude_code",
302
- append: SYSTEM_PROMPT
340
+ append: `${promptPrefix}\n${SYSTEM_PROMPT}`
303
341
  },
342
+ allowedTools: [
343
+ "Glob",
344
+ "Grep",
345
+ "Read",
346
+ ...!codemodOptions?.isDry ? ["Write", "Edit"] : []
347
+ ],
304
348
  settingSources: [
305
349
  "local",
306
350
  "project",
@@ -309,13 +353,13 @@ function getQueryOptions(sessionId, isDebug) {
309
353
  };
310
354
  }
311
355
  /** Initiate a new Claude session/conversation and return reusable options */
312
- async function initiateClaudeSessionOptions(isDebug = false) {
313
- const options = getQueryOptions(void 0, isDebug);
356
+ async function initiateClaudeSessionOptions(codemodOptions, isDebug = false) {
357
+ const options = getQueryOptions(void 0, codemodOptions, isDebug);
314
358
  await checkVPN(options.env?.ANTHROPIC_BASE_URL);
315
359
  const claudeSessionSpinner = (0, ora.default)("Starting Claude instance - your browser may open for Okta authentication if required.").start();
316
360
  const result = (0, __anthropic_ai_claude_agent_sdk.query)({
317
361
  options,
318
- 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.`
362
+ prompt: `You'll be given file paths in additional individual queries to search in for files using deprecated Wise Design System (WDS) components. Migrate the code per the provided migration rules.`
319
363
  });
320
364
  for await (const message of result) switch (message.type) {
321
365
  case "system":
@@ -328,7 +372,7 @@ async function initiateClaudeSessionOptions(isDebug = false) {
328
372
  }
329
373
  return options;
330
374
  }
331
- async function queryClaude(path, options, isDebug = false) {
375
+ async function queryClaude(path, options, codemodOptions, isDebug = false) {
332
376
  const result = (0, __anthropic_ai_claude_agent_sdk.query)({
333
377
  options,
334
378
  prompt: path
@@ -338,14 +382,21 @@ async function queryClaude(path, options, isDebug = false) {
338
382
  case "assistant":
339
383
  for (const msg of message.message.content) switch (msg.type) {
340
384
  case "tool_use":
341
- if (msg.name === "Glob" || msg.name === "Grep") console.log(`${CONSOLE_ICONS.focus} Processing directory: ${formatPathOutput(path)}...`);
385
+ if (msg.name === "Glob") console.log(`${CONSOLE_ICONS.info} Finding all files within: ${formatPathOutput(path)}...`);
386
+ else if (msg.name === "Grep") console.log(`${CONSOLE_ICONS.info} Identifying files with deprecated imports: ${formatPathOutput(path)}...`);
342
387
  else if (msg.name === "Read") console.log(`${CONSOLE_ICONS.info} Reading ${formatPathOutput(path, msg.input.file_path)}`);
343
388
  else if ((msg.name === "Write" || msg.name === "Edit") && !modifiedFiles.includes(msg.input.file_path)) {
344
389
  modifiedFiles.push(msg.input.file_path);
345
- console.log(`${CONSOLE_ICONS.info} Migrated ${formatPathOutput(path, msg.input.file_path)}`);
390
+ if (codemodOptions.isPrint || codemodOptions.isDry) {
391
+ console.log(`${CONSOLE_ICONS.info} ${codemodOptions.isDry ? "Proposed changes" : "Changes"} for ${formatPathOutput(path, msg.input.file_path)}:`);
392
+ console.log(generateDiff(msg.input.old_string, msg.input.new_string));
393
+ } else console.log(`${CONSOLE_ICONS.info} Migrated ${formatPathOutput(path, msg.input.file_path)}`);
346
394
  }
347
395
  break;
348
- default:
396
+ case "text":
397
+ if (isDebug) console.log(`${CONSOLE_ICONS.claude} ${formatClaudeResponseContent(msg.text)}`);
398
+ break;
399
+ default: if (isDebug) console.log(msg);
349
400
  }
350
401
  break;
351
402
  case "result":
@@ -358,11 +409,11 @@ async function queryClaude(path, options, isDebug = false) {
358
409
 
359
410
  //#endregion
360
411
  //#region src/transforms/list-item/transformer.ts
361
- const transformer = async (targetPaths, codemodPath, isDebug = false) => {
412
+ const transformer = async (targetPaths, codemodOptions, isDebug = false) => {
362
413
  const startTime = Date.now();
363
- const queryOptions = await initiateClaudeSessionOptions(isDebug);
414
+ const queryOptions = await initiateClaudeSessionOptions(codemodOptions, isDebug);
364
415
  console.log(`${CONSOLE_ICONS.info} Analysing targetted paths - this may take a while...`);
365
- for (const directory of targetPaths) if (require_helpers.assessPrerequisites(directory, codemodPath)) await queryClaude(directory, queryOptions, isDebug);
416
+ for (const directory of targetPaths) await queryClaude(directory, queryOptions, codemodOptions, isDebug);
366
417
  console.log(`${CONSOLE_ICONS.success} Finished migrating - elapsed time: \x1b[1m${generateElapsedTime(startTime)}\x1b[0m`);
367
418
  };
368
419
  var transformer_default = transformer;
@@ -380,4 +431,4 @@ Object.defineProperty(exports, 'transformer_default', {
380
431
  return transformer_default;
381
432
  }
382
433
  });
383
- //# sourceMappingURL=transformer-C2vxxgYT.js.map
434
+ //# sourceMappingURL=transformer-CFJ7Jq1h.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformer-CFJ7Jq1h.js","names":["https","modifiedFiles: string[]"],"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 claude: '\\x1b[35m💬\\x1b[0m', // Magenta speech bubble\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 = `You are a code migration assistant that helps migrate TypeScript/JSX code from deprecated Wise Design System (WDS) components to the new ListItem component and ListItem subcomponents from '@transferwise/components'.\n\nProcess each file individually, before reading the next file, making a single comprehensive edit per file to replace all necessary code according to the migration context and rules provided.\n\nRules:\n1. Ignore any files that do not contain deprecated WDS components and are not .tsx files, unless they are necessary for context.\n2. Do not migrate files matching the provided patterns in the ignore list.\n3. Migrate components per provided migration rules\n4. Maintain TypeScript type safety and update types to match new API\n5. Map props: handle renamed, deprecated, new required, and changed types\n6. Update imports to new WDS components and types\n7. Preserve code style, formatting, and calculated logic\n8. Handle conditional rendering, spread props, and complex expressions\n9. Note: New components may lack feature parity with legacy versions\n10. Only modify code requiring changes per migration rules, and any impacted surrounding code for context.\n11. Do not summarise the initial user request in a response.\n12. Use glob to find files in the directory and then grep to identify files with deprecated imports.\n13. Final result response should just be whether the migration was successful overall, or if any errors were encountered\n14. Explain your reasoning and justification before making changes, as you edit each file. Keep it concise and succinct as only bullet points\n15. Do not summarise the changes made after modifying a file.\n16. If you do not have permission to modify a file, still attempt to edit it and then move onto the next file.\n\nMake the necessary updates to the files. \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","import { createPatch } from 'diff';\n\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\n// Formats Claude response with ANSI codes (bold for **, green for `), indenting all lines except the first. Also wraps entire content in dim color\nexport function formatClaudeResponseContent(content: string): string {\n const formatted = content\n .replace(/\\*\\*(.+?)\\*\\*/gu, '\\x1b[1m$1\\x1b[0m\\x1b[2m')\n .replace(/`(.+?)`/gu, '\\x1b[32m$1\\x1b[0m\\x1b[2m')\n .split('\\n')\n .map((line, index) => (index === 0 ? line : ` ${line}`))\n .join('\\n');\n\n return `\\x1b[2m${formatted}\\x1b[0m`;\n}\n\n// Generates a unified diff between the original and modified strings, with ANSI color codes for additions and deletions and line numbers\nexport function generateDiff(original: string, modified: string): string {\n const diffResult = createPatch('', original, modified, '', '').trim();\n\n // Parse and colorize the diff output\n const lines = diffResult\n .split('\\n')\n .slice(4) // Skip the header lines\n .filter((line) => !line.startsWith('\\\')); // Remove \"No newline\" messages\n\n // Track current line numbers from hunk headers\n let oldLineNumber = 0;\n let newLineNumber = 0;\n\n const colouredDiff = lines\n .map((line: string) => {\n const trimmedLine = line.trimEnd();\n\n // Parse hunk header to get starting line numbers - format: @@ -oldStart,oldCount +newStart,newCount @@\n if (trimmedLine.startsWith('@@')) {\n const match = /@@ -(\\d+)(?:,\\d+)? \\+(\\d+)(?:,\\d+)? @@/u.exec(trimmedLine);\n if (match) {\n oldLineNumber = Number.parseInt(match[1], 10);\n newLineNumber = Number.parseInt(match[2], 10);\n }\n return `\\x1b[36m${trimmedLine}\\x1b[0m`; // Cyan for hunk headers\n }\n\n let linePrefix = '';\n // Green styling for additions\n if (trimmedLine.startsWith('+')) {\n linePrefix = `${newLineNumber.toString().padStart(4, ' ')} `;\n newLineNumber += 1;\n return `\\x1b[32m${linePrefix}${trimmedLine}\\x1b[0m`;\n }\n\n // Red styling for deletions\n if (trimmedLine.startsWith('-')) {\n linePrefix = `${oldLineNumber.toString().padStart(4, ' ')} `;\n oldLineNumber += 1;\n return `\\x1b[31m${linePrefix}${trimmedLine}\\x1b[0m`;\n }\n\n // Handle unchanged lines\n linePrefix = `${oldLineNumber.toString().padStart(4, ' ')} `;\n oldLineNumber += 1;\n newLineNumber += 1;\n return `${linePrefix}${trimmedLine}`;\n })\n .join('\\n');\n\n return colouredDiff;\n}\n","import https from 'node:https';\n\nimport { type Options, query } from '@anthropic-ai/claude-agent-sdk';\nimport { execSync } from 'child_process';\nimport { readFileSync } from 'fs';\nimport ora from 'ora';\nimport { resolve } from 'path';\n\nimport { CONSOLE_ICONS } from '../../constants';\nimport type { CodemodOptions } from '../../controller/types';\nimport { SYSTEM_PROMPT } from './constants';\nimport { formatClaudeResponseContent, formatPathOutput, generateDiff } from './helpers';\nimport type { ClaudeResponseToolUse, ClaudeSettings } from './types';\n\nconst CLAUDE_SETTINGS_FILE = '.claude/settings.json';\n\nasync function checkVPN(baseUrl?: string): Promise<boolean> {\n if (baseUrl) {\n const vpnSpinner = ora('Checking VPN connection...').start();\n const checkOnce = async (): Promise<boolean> =>\n new Promise<boolean>((resolveCheck) => {\n const url = new URL('/health', baseUrl);\n const req = https.get(url, { timeout: 2000, rejectUnauthorized: false }, (res) => {\n const ok = !!(res.statusCode && res.statusCode >= 200 && res.statusCode < 400);\n res.resume();\n resolveCheck(ok);\n });\n req.on('timeout', () => {\n req.destroy(new Error('timeout'));\n });\n req.on('error', () => resolveCheck(false));\n });\n\n while (true) {\n const ok = await checkOnce();\n if (ok) {\n vpnSpinner.succeed('Connected to VPN');\n break;\n }\n vpnSpinner.text = 'Please connect to VPN... retrying in 3s';\n await new Promise<void>((response) => {\n setTimeout(response, 3000);\n });\n }\n }\n return true;\n}\n\nexport function getQueryOptions(\n sessionId?: string,\n codemodOptions?: CodemodOptions,\n isDebug?: boolean,\n): 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 { ANTHROPIC_CUSTOM_HEADERS, ...restEnvVars } = settings?.env || {};\n\n const envVars = {\n ANTHROPIC_AUTH_TOKEN: apiKey,\n ANTHROPIC_CUSTOM_HEADERS,\n ...restEnvVars,\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 and path\n const { ANTHROPIC_AUTH_TOKEN, ...restVars } = envVars;\n console.log(\n `${CONSOLE_ICONS.info} Claude configuration environment variables, excluding ANTHROPIC_AUTH_TOKEN:`,\n );\n console.log(restVars);\n }\n\n const promptPrefix = !codemodOptions?.useGitIgnore\n ? 'Do not use .gitignore to exclude files from the migration. Ensure all relevant files are included.'\n : 'Respect .gitignore when determining which files to include in the migration.';\n\n // NOTE: ignore patterns not working...\n // codemodOptions?.ignorePatterns?.length ? `Ignore any files with names matching the following .gitignore glob patterns, separated by commas and do not migrate them: ${codemodOptions.ignorePatterns.replaceAll(',', ', ')}` : '';\n\n return {\n resume: sessionId,\n env: envVars,\n permissionMode: codemodOptions?.isDry ? undefined : 'acceptEdits',\n systemPrompt: {\n type: 'preset',\n preset: 'claude_code',\n append: `${promptPrefix}\\n${SYSTEM_PROMPT}`,\n },\n allowedTools: ['Glob', 'Grep', 'Read', ...(!codemodOptions?.isDry ? ['Write', 'Edit'] : [])],\n settingSources: ['local', 'project', 'user'],\n };\n}\n\n/** Initiate a new Claude session/conversation and return reusable options */\nexport async function initiateClaudeSessionOptions(\n codemodOptions: CodemodOptions,\n isDebug = false,\n): Promise<Options> {\n const options = getQueryOptions(undefined, codemodOptions, isDebug);\n await checkVPN(options.env?.ANTHROPIC_BASE_URL);\n\n const claudeSessionSpinner = ora(\n 'Starting Claude instance - your browser may open for Okta authentication if required.',\n ).start();\n\n const result = query({\n options,\n prompt: `You'll be given file paths 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 claudeSessionSpinner.succeed('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 claudeSessionSpinner.fail(`Claude encountered an error: ${message.errors.join('\\n')}`);\n }\n }\n }\n\n return options;\n}\n\n// Queries Claude with the given path and handles logging of tool uses and results\nexport async function queryClaude(\n path: string,\n options: Options,\n codemodOptions: CodemodOptions,\n isDebug = false,\n) {\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') {\n console.log(\n `${CONSOLE_ICONS.info} Finding all files within: ${formatPathOutput(path)}...`,\n );\n } else if (msg.name === 'Grep') {\n console.log(\n `${CONSOLE_ICONS.info} Identifying files with deprecated imports: ${formatPathOutput(path)}...`,\n );\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 // TODO: Consider how to handle multiple writes to the same file more gracefully (logged changes won't always match final file content)\n modifiedFiles.push((msg as ClaudeResponseToolUse).input.file_path);\n\n // Generate and print out a pretty diff of changes made by Claude\n if (codemodOptions.isPrint || codemodOptions.isDry) {\n console.log(\n `${CONSOLE_ICONS.info} ${codemodOptions.isDry ? 'Proposed changes' : 'Changes'} for ${formatPathOutput(path, (msg as ClaudeResponseToolUse).input.file_path)}:`,\n );\n console.log(\n generateDiff(\n (msg as ClaudeResponseToolUse).input.old_string as string,\n (msg as ClaudeResponseToolUse).input.new_string as string,\n ),\n );\n } else {\n console.log(\n `${CONSOLE_ICONS.info} Migrated ${formatPathOutput(path, (msg as ClaudeResponseToolUse).input.file_path)}`,\n );\n }\n }\n break;\n case 'text':\n // Logs Claude's textual responses in debug mode, to help with understanding justifications/errors\n if (isDebug) {\n console.log(`${CONSOLE_ICONS.claude} ${formatClaudeResponseContent(msg.text)}`);\n }\n break;\n default:\n if (isDebug) {\n console.log(msg);\n }\n }\n }\n break;\n case 'result':\n if (message.subtype === 'success') {\n // TODO: Handle case where migration failed for some files - maybe due to failed dependency checks?\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 type { CodemodOptions } from '../../controller/types';\nimport { initiateClaudeSessionOptions, queryClaude } from './claude';\nimport { generateElapsedTime } from './helpers';\n\nconst transformer = async (\n targetPaths: string[],\n codemodOptions: CodemodOptions,\n isDebug = false,\n) => {\n const startTime = Date.now();\n\n // TODO: We need to check whether the user is connected to the VPN first before proceeding\n\n const queryOptions = await initiateClaudeSessionOptions(codemodOptions, isDebug);\n\n console.log(`${CONSOLE_ICONS.info} Analysing targetted paths - this may take a while...`);\n\n for (const directory of targetPaths) {\n await queryClaude(directory, queryOptions, codemodOptions, 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-Cca1yIbM.js');
2
+ const require_helpers = require('../../helpers-Bgz_nSwk.js');
3
3
 
4
4
  //#region src/helpers/addImport.ts
5
5
  /**
@@ -1,4 +1,3 @@
1
- require('../../helpers-Cca1yIbM.js');
2
- const require_transformer = require('../../transformer-C2vxxgYT.js');
1
+ const require_transformer = require('../../transformer-CFJ7Jq1h.js');
3
2
 
4
3
  module.exports = require_transformer.transformer_default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wise/wds-codemods",
3
- "version": "1.0.0-experimental-dfd0a93",
3
+ "version": "1.0.0-experimental-d309319",
4
4
  "license": "UNLICENSED",
5
5
  "author": "Wise Payments Ltd.",
6
6
  "repository": {
@@ -36,6 +36,7 @@
36
36
  "dependencies": {
37
37
  "@anthropic-ai/claude-agent-sdk": "^0.1.37",
38
38
  "@inquirer/prompts": "^7.8.6",
39
+ "diff": "^8.0.2",
39
40
  "jscodeshift": "^17.3",
40
41
  "ora": "^9.0.0"
41
42
  },