@wise/wds-codemods 1.0.0-experimental-f15e55a → 1.0.0-experimental-0576f11

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,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  const require_helpers = require('./helpers-RWhTD5Is.js');
3
- const require_transformer = require('./transformer-BjW09YOV.js');
3
+ const require_transformer = require('./transformer-CzKcQEmu.js');
4
4
  let node_child_process = require("node:child_process");
5
5
  let node_fs_promises = require("node:fs/promises");
6
6
  node_fs_promises = require_helpers.__toESM(node_fs_promises);
@@ -0,0 +1,284 @@
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 __anthropic_ai_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
5
+ let node_fs = require("node:fs");
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 SYSTEM_PROMPT = `Transform TypeScript/JSX code from legacy Wise Design System (WDS) components to the new ListItem component and ListItem subcomponents from '@transferwise/components'.
28
+
29
+ Rules:
30
+ 1. Ignore any files that do not contain deprecated WDS components, unless they are necessary for context.
31
+ 2. Migrate components per provided migration rules
32
+ 3. Maintain TypeScript type safety and update types to match new API
33
+ 4. Map props: handle renamed, deprecated, new required, and changed types
34
+ 5. Update imports to new WDS components and types
35
+ 6. Preserve code style, formatting, and calculated logic
36
+ 7. Handle conditional rendering, spread props, and complex expressions
37
+ 8. Note: New components may lack feature parity with legacy versions
38
+
39
+ You'll receive:
40
+ - File paths/directories to search
41
+ - Deprecated component names at the end of this prompt
42
+ - Migration context and rules for each deprecated component
43
+
44
+ Only modify code requiring changes per migration rules. Make the necessary updates to the files and do not respond with any explanations or reasoning.
45
+
46
+ Deprecated components: ${DEPRECATED_COMPONENT_NAMES.join(", ")}.
47
+
48
+ Migration rules:
49
+ # Legacy Component → ListItem Migration Guide
50
+
51
+ ## Universal Rules
52
+
53
+ 1. Wrap all \`ListItem\` in \`<List>\`
54
+ 2. \`title\` → \`title\` (direct)
55
+ 3. \`content\` or \`description\` → \`subtitle\`
56
+ 4. \`disabled\` stays on \`ListItem\` (not controls)
57
+ 5. Keep HTML attributes (\`id\`, \`name\`, \`aria-label\`), remove: \`as\`, \`complex\`, \`showMediaAtAllSizes\`, \`showMediaCircle\`, \`isContainerAligned\`
58
+
59
+ ---
60
+
61
+ ## ActionOption → ListItem.Button
62
+
63
+ - \`action\` → Button children
64
+ - \`onClick\` → Button \`onClick\`
65
+ - Priority: default/\`"primary"\` → \`"primary"\`, \`"secondary"\` → \`"secondary-neutral"\`, \`"secondary-send"\` → \`"secondary"\`, \`"tertiary"\` → \`"tertiary"\`
66
+
67
+ \`\`\`tsx
68
+ <ActionOption title="Title" content="Text" action="Click" priority="secondary" onClick={fn} />
69
+
70
+ <List><ListItem title="Title" subtitle="Text" control={<ListItem.Button priority="secondary-neutral" onClick={fn}>Click</ListItem.Button>} /></List>
71
+ \`\`\`
72
+
73
+ ---
74
+
75
+ ## CheckboxOption → ListItem.Checkbox
76
+
77
+ - \`onChange\`: \`(checked: boolean)\` → \`(event: ChangeEvent)\` use \`event.target.checked\`
78
+ - \`id\`, \`name\` move to Checkbox
79
+
80
+ \`\`\`tsx
81
+ <CheckboxOption id="x" name="y" title="Title" content="Text" checked={v} onChange={(c) => set(c)} />
82
+
83
+ <List><ListItem title="Title" subtitle="Text" control={<ListItem.Checkbox id="x" name="y" checked={v} onChange={(e) => set(e.target.checked)} />} /></List>
84
+ \`\`\`
85
+
86
+ ---
87
+
88
+ ## RadioOption → ListItem.Radio
89
+
90
+ - \`id\`, \`name\`, \`value\`, \`checked\`, \`onChange\` move to Radio
91
+
92
+ \`\`\`tsx
93
+ <RadioOption id="x" name="y" value="v" title="Title" content="Text" checked={v==='v'} onChange={set} />
94
+
95
+ <List><ListItem title="Title" subtitle="Text" control={<ListItem.Radio id="x" name="y" value="v" checked={v==='v'} onChange={set} />} /></List>
96
+ \`\`\`
97
+
98
+ ---
99
+
100
+ ## SwitchOption → ListItem.Switch
101
+
102
+ - \`onChange\` → \`onClick\`, toggle manually
103
+ - \`aria-label\` moves to Switch
104
+
105
+ \`\`\`tsx
106
+ <SwitchOption title="Title" content="Text" checked={v} aria-label="Toggle" onChange={set} />
107
+
108
+ <List><ListItem title="Title" subtitle="Text" control={<ListItem.Switch checked={v} aria-label="Toggle" onClick={() => set(!v)} />} /></List>
109
+ \`\`\`
110
+
111
+ ---
112
+
113
+ ## NavigationOption → ListItem.Navigation
114
+
115
+ - \`onClick\` or \`href\` move to Navigation
116
+
117
+ \`\`\`tsx
118
+ <NavigationOption title="Title" content="Text" onClick={fn} />
119
+
120
+ <List><ListItem title="Title" subtitle="Text" control={<ListItem.Navigation onClick={fn} />} /></List>
121
+ \`\`\`
122
+
123
+ ---
124
+
125
+ ## Option → ListItem
126
+
127
+ - Wrap \`media\` in \`ListItem.AvatarView\`
128
+
129
+ \`\`\`tsx
130
+ <Option media={<Icon />} title="Title" />
131
+
132
+ <List><ListItem title="Title" media={<ListItem.AvatarView><Icon /></ListItem.AvatarView>} /></List>
133
+ \`\`\`
134
+
135
+ ---
136
+
137
+ ## Summary → ListItem
138
+
139
+ **Basic:**
140
+
141
+ - \`icon\` → wrap in \`ListItem.AvatarView\` with \`size={32}\` as \`media\`
142
+
143
+ **Status:**
144
+
145
+ - \`Status.DONE\` → \`badge={{ status: 'positive' }}\`
146
+ - \`Status.PENDING\` → \`badge={{ status: 'pending' }}\`
147
+ - \`Status.NOT_DONE\` → no badge
148
+
149
+ **Action:**
150
+
151
+ - \`action.text\` → \`action.label\` in \`ListItem.AdditionalInfo\` as \`additionalInfo\`
152
+
153
+ **Info (requires state):**
154
+
155
+ - \`MODAL\` → \`ListItem.IconButton partiallyInteractive\` + \`<Modal>\` in \`control\`
156
+ - \`POPOVER\` → \`<Popover>\` wrapping \`ListItem.IconButton partiallyInteractive\` in \`control\`
157
+ - Use \`QuestionMarkCircle\` icon
158
+
159
+ \`\`\`tsx
160
+ // Basic
161
+ <Summary title="T" description="D" icon={<Icon />} />
162
+
163
+ <List><ListItem title="T" subtitle="D" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} /></List>
164
+
165
+ // Status
166
+ <Summary title="T" description="D" icon={<Icon />} status={Status.DONE} />
167
+
168
+ <List><ListItem title="T" subtitle="D" media={<ListItem.AvatarView size={32} badge={{status:'positive'}}><Icon /></ListItem.AvatarView>} /></List>
169
+
170
+ // Action
171
+ <Summary title="T" description="D" icon={<Icon />} action={{text:'Go', href:'/go'}} />
172
+
173
+ <List><ListItem title="T" subtitle="D" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} additionalInfo={<ListItem.AdditionalInfo action={{label:'Go', href:'/go'}} />} /></List>
174
+
175
+ // Modal (add: const [open, setOpen] = useState(false))
176
+ <Summary title="T" description="D" icon={<Icon />} info={{title:'Help', content:'Text', presentation:'MODAL', 'aria-label':'Info'}} />
177
+
178
+ <List><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>} /></List>
179
+
180
+ // Popover
181
+ <Summary title="T" description="D" icon={<Icon />} info={{title:'Help', content:'Text', presentation:'POPOVER', 'aria-label':'Info'}} />
182
+
183
+ <List><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>} /></List>
184
+ \`\`\`
185
+
186
+ ---
187
+
188
+ ## DefinitionList → Multiple ListItem
189
+
190
+ - Array → individual \`ListItem\`s
191
+ - \`value\` → \`subtitle\`
192
+ - \`key\` → React \`key\` prop
193
+ - Action type: "Edit"/"Update"/"View" → \`ListItem.Button priority="secondary-neutral"\`, "Change"/"Password" → \`ListItem.Navigation\`, "Copy" → \`ListItem.IconButton\`
194
+
195
+ \`\`\`tsx
196
+ <DefinitionList definitions={[
197
+ {title:'T1', value:'V1', key:'k1'},
198
+ {title:'T2', value:'V2', key:'k2', action:{label:'Edit', onClick:fn}}
199
+ ]} />
200
+
201
+ <List>
202
+ <ListItem key="k1" title="T1" subtitle="V1" />
203
+ <ListItem key="k2" title="T2" subtitle="V2" control={<ListItem.Button priority="secondary-neutral" onClick={fn}>Edit</ListItem.Button>} />
204
+ </List>
205
+ \`\`\`
206
+ `;
207
+
208
+ //#endregion
209
+ //#region src/transforms/list-item/claude.ts
210
+ const CLAUDE_SETTINGS_FILE = ".claude/settings.json";
211
+ function getQueryOptions(isDebug = false) {
212
+ const claudeSettingsPath = (0, node_path.resolve)(process.env.HOME || "", CLAUDE_SETTINGS_FILE);
213
+ const settings = JSON.parse((0, node_fs.readFileSync)(claudeSettingsPath, "utf-8"));
214
+ let apiKey;
215
+ try {
216
+ apiKey = (0, node_child_process.execSync)(`bash ${settings.apiKeyHelper}`, { encoding: "utf-8" }).trim();
217
+ } catch {}
218
+ 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");
219
+ return {
220
+ env: {
221
+ ANTHROPIC_AUTH_TOKEN: apiKey,
222
+ ANTHROPIC_BASE_URL: settings?.env?.ANTHROPIC_BASE_URL,
223
+ ANTHROPIC_CUSTOM_HEADERS: settings?.env?.ANTHROPIC_CUSTOM_HEADERS,
224
+ ANTHROPIC_DEFAULT_SONNET_MODEL: settings.env?.ANTHROPIC_DEFAULT_SONNET_MODEL,
225
+ ANTHROPIC_DEFAULT_HAIKU_MODEL: settings.env?.ANTHROPIC_DEFAULT_HAIKU_MODEL,
226
+ ANTHROPIC_DEFAULT_OPUS_MODEL: settings.env?.ANTHROPIC_DEFAULT_OPUS_MODEL,
227
+ API_TIMEOUT_MS: settings.env?.API_TIMEOUT_MS,
228
+ PATH: process.env.PATH
229
+ },
230
+ permissionMode: "acceptEdits",
231
+ systemPrompt: {
232
+ type: "preset",
233
+ preset: "claude_code",
234
+ append: SYSTEM_PROMPT
235
+ },
236
+ settingSources: [
237
+ "local",
238
+ "project",
239
+ "user"
240
+ ]
241
+ };
242
+ }
243
+
244
+ //#endregion
245
+ //#region src/transforms/list-item/transformer.ts
246
+ const transformer = async (targetPaths, isDebug = false) => {
247
+ console.log(`${CONSOLE_ICONS.info} Starting Claude instance...`);
248
+ const result = (0, __anthropic_ai_claude_agent_sdk.query)({
249
+ options: getQueryOptions(isDebug),
250
+ prompt: `Here are the directories to search in: ${targetPaths.join(", ")}.
251
+ In addition to making the required file changes for every relevant file, only respond with the file path/name and number of lines changed per file - e.g. "<directory/filename> - 5 lines changed".
252
+ If no changes are made for a file, respond with "<directory/filename> - No changes required". If all files require no changes, return only the same format still with nothing else.`
253
+ });
254
+ for await (const message of result) switch (message.type) {
255
+ case "system":
256
+ if (message.subtype === "init") {
257
+ console.log(`${CONSOLE_ICONS.success} Initialised Claude instance`);
258
+ console.log(`${CONSOLE_ICONS.info} Claude is processing the files... This may take a while.`);
259
+ }
260
+ break;
261
+ case "result":
262
+ if (message.subtype === "success") console.log(`${CONSOLE_ICONS.success} ${message.result.split("\n").join(`\n${CONSOLE_ICONS.success} `)}`);
263
+ else console.log(`${CONSOLE_ICONS.error} Claude encountered an error: ${message.errors.join("\n")}`);
264
+ break;
265
+ default: break;
266
+ }
267
+ console.log(`${CONSOLE_ICONS.success} Finished receiving messages from Claude.`);
268
+ };
269
+ var transformer_default = transformer;
270
+
271
+ //#endregion
272
+ Object.defineProperty(exports, 'CONSOLE_ICONS', {
273
+ enumerable: true,
274
+ get: function () {
275
+ return CONSOLE_ICONS;
276
+ }
277
+ });
278
+ Object.defineProperty(exports, 'transformer_default', {
279
+ enumerable: true,
280
+ get: function () {
281
+ return transformer_default;
282
+ }
283
+ });
284
+ //# sourceMappingURL=transformer-CzKcQEmu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformer-CzKcQEmu.js","names":[],"sources":["../src/constants.ts","../src/transforms/list-item/constants.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\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\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\n\nYou'll receive:\n- File paths/directories to search\n- Deprecated component names at the end of this prompt\n- Migration context and rules for each deprecated component\n\nOnly modify code requiring changes per migration rules. Make the necessary updates to the files and do not respond with any explanations or reasoning.\n\nDeprecated components: ${DEPRECATED_COMPONENT_NAMES.join(', ')}.\n\nMigration rules:\n# Legacy Component → ListItem Migration Guide\n\n## Universal Rules\n\n1. Wrap all \\`ListItem\\` in \\`<List>\\`\n2. \\`title\\` → \\`title\\` (direct)\n3. \\`content\\` or \\`description\\` → \\`subtitle\\`\n4. \\`disabled\\` stays on \\`ListItem\\` (not controls)\n5. Keep HTML attributes (\\`id\\`, \\`name\\`, \\`aria-label\\`), remove: \\`as\\`, \\`complex\\`, \\`showMediaAtAllSizes\\`, \\`showMediaCircle\\`, \\`isContainerAligned\\`\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<List><ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Button priority=\"secondary-neutral\" onClick={fn}>Click</ListItem.Button>} /></List>\n\\`\\`\\`\n\n---\n\n## CheckboxOption → ListItem.Checkbox\n\n- \\`onChange\\`: \\`(checked: boolean)\\` → \\`(event: ChangeEvent)\\` use \\`event.target.checked\\`\n- \\`id\\`, \\`name\\` move to Checkbox\n\n\\`\\`\\`tsx\n<CheckboxOption id=\"x\" name=\"y\" title=\"Title\" content=\"Text\" checked={v} onChange={(c) => set(c)} />\n→\n<List><ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Checkbox id=\"x\" name=\"y\" checked={v} onChange={(e) => set(e.target.checked)} />} /></List>\n\\`\\`\\`\n\n---\n\n## RadioOption → ListItem.Radio\n\n- \\`id\\`, \\`name\\`, \\`value\\`, \\`checked\\`, \\`onChange\\` move to Radio\n\n\\`\\`\\`tsx\n<RadioOption id=\"x\" name=\"y\" value=\"v\" title=\"Title\" content=\"Text\" checked={v==='v'} onChange={set} />\n→\n<List><ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Radio id=\"x\" name=\"y\" value=\"v\" checked={v==='v'} onChange={set} />} /></List>\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<List><ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Switch checked={v} aria-label=\"Toggle\" onClick={() => set(!v)} />} /></List>\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<List><ListItem title=\"Title\" subtitle=\"Text\" control={<ListItem.Navigation onClick={fn} />} /></List>\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<List><ListItem title=\"Title\" media={<ListItem.AvatarView><Icon /></ListItem.AvatarView>} /></List>\n\\`\\`\\`\n\n---\n\n## Summary → ListItem\n\n**Basic:**\n\n- \\`icon\\` → wrap in \\`ListItem.AvatarView\\` with \\`size={32}\\` as \\`media\\`\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\n\n\\`\\`\\`tsx\n// Basic\n<Summary title=\"T\" description=\"D\" icon={<Icon />} />\n→\n<List><ListItem title=\"T\" subtitle=\"D\" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} /></List>\n\n// Status\n<Summary title=\"T\" description=\"D\" icon={<Icon />} status={Status.DONE} />\n→\n<List><ListItem title=\"T\" subtitle=\"D\" media={<ListItem.AvatarView size={32} badge={{status:'positive'}}><Icon /></ListItem.AvatarView>} /></List>\n\n// Action\n<Summary title=\"T\" description=\"D\" icon={<Icon />} action={{text:'Go', href:'/go'}} />\n→\n<List><ListItem title=\"T\" subtitle=\"D\" media={<ListItem.AvatarView size={32}><Icon /></ListItem.AvatarView>} additionalInfo={<ListItem.AdditionalInfo action={{label:'Go', href:'/go'}} />} /></List>\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<List><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>} /></List>\n\n// Popover\n<Summary title=\"T\" description=\"D\" icon={<Icon />} info={{title:'Help', content:'Text', presentation:'POPOVER', 'aria-label':'Info'}} />\n→\n<List><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>} /></List>\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<List>\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</List>\n\\`\\`\\`\n`;\n","import type { Options } from '@anthropic-ai/claude-agent-sdk';\nimport { execSync } from 'child_process';\nimport { readFileSync } from 'fs';\nimport { resolve } from 'path';\n\nimport { SYSTEM_PROMPT } from './constants';\n\ninterface ClaudeSettings {\n apiKeyHelper?: string;\n env?: {\n ANTHROPIC_BASE_URL?: string;\n ANTHROPIC_CUSTOM_HEADERS?: string;\n ANTHROPIC_DEFAULT_SONNET_MODEL?: string;\n ANTHROPIC_DEFAULT_HAIKU_MODEL?: string;\n ANTHROPIC_DEFAULT_OPUS_MODEL?: string;\n API_TIMEOUT_MS?: string;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nconst CLAUDE_SETTINGS_FILE = '.claude/settings.json';\n\nexport function getQueryOptions(isDebug = false): 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 // console.debug(`${CONSOLE_ICONS.info} Resolved Claude environment variables:`, JSON.stringify(envVars));\n // }\n\n return {\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","import { query } from '@anthropic-ai/claude-agent-sdk';\n\nimport { CONSOLE_ICONS } from '../../constants';\nimport { getQueryOptions } from './claude';\n\nconst transformer = async (targetPaths: string[], isDebug = false) => {\n // TODO: We need to confirm you're connected to the VPN\n console.log(`${CONSOLE_ICONS.info} Starting Claude instance...`);\n\n const result = query({\n options: getQueryOptions(isDebug),\n prompt: `Here are the directories to search in: ${targetPaths.join(', ')}.\n In addition to making the required file changes for every relevant file, only respond with the file path/name and number of lines changed per file - e.g. \"<directory/filename> - 5 lines changed\".\n If no changes are made for a file, respond with \"<directory/filename> - No changes required\". If all files require no changes, return only the same format still with nothing else.`,\n });\n\n // TODO: Ensure we're handling all potential types of messages here.\n for await (const message of result) {\n switch (message.type) {\n case 'system':\n if (message.subtype === 'init') {\n console.log(`${CONSOLE_ICONS.success} Initialised Claude instance`);\n console.log(\n `${CONSOLE_ICONS.info} Claude is processing the files... This may take a while.`,\n );\n }\n break;\n\n case 'result':\n if (message.subtype === 'success') {\n console.log(\n `${CONSOLE_ICONS.success} ${message.result.split('\\n').join(`\\n${CONSOLE_ICONS.success} `)}`,\n );\n } else {\n console.log(\n `${CONSOLE_ICONS.error} Claude encountered an error: ${message.errors.join('\\n')}`,\n );\n }\n\n break;\n default:\n // console.log(JSON.stringify(message));\n break;\n }\n }\n\n console.log(`${CONSOLE_ICONS.success} Finished receiving messages from Claude.`);\n};\n\nexport default transformer;\n"],"mappings":";;;;;;;AAAA,MAAa,gBAAgB;CAC3B,MAAM;CACN,OAAO;CACP,SAAS;CACT,SAAS;CACT,OAAO;CACR;;;;ACND,MAAM,6BAA6B;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAa,gBAAgB;;;;;;;;;;;;;;;;;;;yBAmBJ,2BAA2B,KAAK,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACR/D,MAAM,uBAAuB;AAE7B,SAAgB,gBAAgB,UAAU,OAAgB;CAExD,MAAM,4CAA6B,QAAQ,IAAI,QAAQ,IAAI,qBAAqB;CAChF,MAAM,WAAW,KAAK,gCAAmB,oBAAoB,QAAQ,CAAC;CAGtE,IAAI;AACJ,KAAI;AACF,4CAAkB,QAAQ,SAAS,gBAAgB,EACjD,UAAU,SACX,CAAC,CAAC,MAAM;SACH;AAER,KAAI,CAAC,OACH,OAAM,IAAI,MACR,qJACD;AAkBH,QAAO;EACL,KAhBc;GACd,sBAAsB;GACtB,oBAAoB,UAAU,KAAK;GACnC,0BAA0B,UAAU,KAAK;GACzC,gCAAgC,SAAS,KAAK;GAC9C,+BAA+B,SAAS,KAAK;GAC7C,8BAA8B,SAAS,KAAK;GAC5C,gBAAgB,SAAS,KAAK;GAC9B,MAAM,QAAQ,IAAI;GACnB;EAQC,gBAAgB;EAChB,cAAc;GACZ,MAAM;GACN,QAAQ;GACR,QAAQ;GACT;EACD,gBAAgB;GAAC;GAAS;GAAW;GAAO;EAC7C;;;;;AC7DH,MAAM,cAAc,OAAO,aAAuB,UAAU,UAAU;AAEpE,SAAQ,IAAI,GAAG,cAAc,KAAK,8BAA8B;CAEhE,MAAM,oDAAe;EACnB,SAAS,gBAAgB,QAAQ;EACjC,QAAQ,0CAA0C,YAAY,KAAK,KAAK,CAAC;;;EAG1E,CAAC;AAGF,YAAW,MAAM,WAAW,OAC1B,SAAQ,QAAQ,MAAhB;EACE,KAAK;AACH,OAAI,QAAQ,YAAY,QAAQ;AAC9B,YAAQ,IAAI,GAAG,cAAc,QAAQ,8BAA8B;AACnE,YAAQ,IACN,GAAG,cAAc,KAAK,2DACvB;;AAEH;EAEF,KAAK;AACH,OAAI,QAAQ,YAAY,UACtB,SAAQ,IACN,GAAG,cAAc,QAAQ,GAAG,QAAQ,OAAO,MAAM,KAAK,CAAC,KAAK,KAAK,cAAc,QAAQ,GAAG,GAC3F;OAED,SAAQ,IACN,GAAG,cAAc,MAAM,gCAAgC,QAAQ,OAAO,KAAK,KAAK,GACjF;AAGH;EACF,QAEE;;AAIN,SAAQ,IAAI,GAAG,cAAc,QAAQ,2CAA2C;;AAGlF,0BAAe"}
@@ -1,3 +1,3 @@
1
- const require_transformer = require('../../transformer-BjW09YOV.js');
1
+ const require_transformer = require('../../transformer-CzKcQEmu.js');
2
2
 
3
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-f15e55a",
3
+ "version": "1.0.0-experimental-0576f11",
4
4
  "license": "UNLICENSED",
5
5
  "author": "Wise Payments Ltd.",
6
6
  "repository": {
@@ -1,124 +0,0 @@
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 __anthropic_ai_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
5
- let node_fs = require("node:fs");
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 SYSTEM_PROMPT = `Transform TypeScript/JSX code from legacy Wise Design System (WDS) components to the new ListItem component and ListItem subcomponents from '@transferwise/components'.
28
-
29
- Rules:
30
- 1. Migrate components per provided migration rules
31
- 2. Maintain TypeScript type safety and update types to match new API
32
- 3. Map props: handle renamed, deprecated, new required, and changed types
33
- 4. Update imports to new WDS components and types
34
- 5. Preserve code style, formatting, and calculated logic
35
- 6. Handle conditional rendering, spread props, and complex expressions
36
- 7. Note: New components may lack feature parity with legacy versions
37
-
38
- You'll receive:
39
- - File paths/directories to search
40
- - Deprecated component names at the end of this prompt
41
-
42
- Migration context and rules can be found in the MAPPINGS.md file.
43
-
44
- Only modify code requiring changes per migration rules. Make the necessary updates to the files and do not respond with any explanations or reasoning.
45
-
46
- Deprecated components: ${DEPRECATED_COMPONENT_NAMES.join(", ")}.`;
47
-
48
- //#endregion
49
- //#region src/transforms/list-item/claude.ts
50
- const CLAUDE_SETTINGS_FILE = ".claude/settings.json";
51
- function getQueryOptions(isDebug = false) {
52
- const claudeSettingsPath = (0, node_path.resolve)(process.env.HOME || "", CLAUDE_SETTINGS_FILE);
53
- const settings = JSON.parse((0, node_fs.readFileSync)(claudeSettingsPath, "utf-8"));
54
- let apiKey;
55
- try {
56
- apiKey = (0, node_child_process.execSync)(`bash ${settings.apiKeyHelper}`, { encoding: "utf-8" }).trim();
57
- } catch {}
58
- 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");
59
- return {
60
- env: {
61
- ANTHROPIC_AUTH_TOKEN: apiKey,
62
- ANTHROPIC_BASE_URL: settings?.env?.ANTHROPIC_BASE_URL,
63
- ANTHROPIC_CUSTOM_HEADERS: settings?.env?.ANTHROPIC_CUSTOM_HEADERS,
64
- ANTHROPIC_DEFAULT_SONNET_MODEL: settings.env?.ANTHROPIC_DEFAULT_SONNET_MODEL,
65
- ANTHROPIC_DEFAULT_HAIKU_MODEL: settings.env?.ANTHROPIC_DEFAULT_HAIKU_MODEL,
66
- ANTHROPIC_DEFAULT_OPUS_MODEL: settings.env?.ANTHROPIC_DEFAULT_OPUS_MODEL,
67
- API_TIMEOUT_MS: settings.env?.API_TIMEOUT_MS,
68
- PATH: process.env.PATH
69
- },
70
- permissionMode: "acceptEdits",
71
- systemPrompt: {
72
- type: "preset",
73
- preset: "claude_code",
74
- append: SYSTEM_PROMPT
75
- },
76
- settingSources: [
77
- "local",
78
- "project",
79
- "user"
80
- ]
81
- };
82
- }
83
-
84
- //#endregion
85
- //#region src/transforms/list-item/transformer.ts
86
- const transformer = async (targetPaths, isDebug = false) => {
87
- console.log(`${CONSOLE_ICONS.info} Starting Claude instance...`);
88
- const result = (0, __anthropic_ai_claude_agent_sdk.query)({
89
- options: getQueryOptions(isDebug),
90
- prompt: `Here are the directories to search in: ${targetPaths.join(", ")}.
91
- In addition to making the required file changes for every relevant file, only respond with the file path/name and number of lines changed per file - e.g. "<directory/filename> - 5 lines changed".
92
- If no changes are made for a file, respond with "<directory/filename> - No changes required". If all files require no changes, return only the same format still with nothing else.`
93
- });
94
- for await (const message of result) switch (message.type) {
95
- case "system":
96
- if (message.subtype === "init") {
97
- console.log(`${CONSOLE_ICONS.success} Initialised Claude instance`);
98
- console.log(`${CONSOLE_ICONS.info} Claude is processing the files... This may take a while.`);
99
- }
100
- break;
101
- case "result":
102
- if (message.subtype === "success") console.log(`${CONSOLE_ICONS.success} ${message.result.split("\n").join(`\n${CONSOLE_ICONS.success} `)}`);
103
- else console.log(`${CONSOLE_ICONS.error} Claude encountered an error: ${message.errors.join("\n")}`);
104
- break;
105
- default: break;
106
- }
107
- console.log(`${CONSOLE_ICONS.success} Finished receiving messages from Claude.`);
108
- };
109
- var transformer_default = transformer;
110
-
111
- //#endregion
112
- Object.defineProperty(exports, 'CONSOLE_ICONS', {
113
- enumerable: true,
114
- get: function () {
115
- return CONSOLE_ICONS;
116
- }
117
- });
118
- Object.defineProperty(exports, 'transformer_default', {
119
- enumerable: true,
120
- get: function () {
121
- return transformer_default;
122
- }
123
- });
124
- //# sourceMappingURL=transformer-BjW09YOV.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transformer-BjW09YOV.js","names":[],"sources":["../src/constants.ts","../src/transforms/list-item/constants.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\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\nRules:\n1. Migrate components per provided migration rules\n2. Maintain TypeScript type safety and update types to match new API\n3. Map props: handle renamed, deprecated, new required, and changed types\n4. Update imports to new WDS components and types\n5. Preserve code style, formatting, and calculated logic\n6. Handle conditional rendering, spread props, and complex expressions\n7. Note: New components may lack feature parity with legacy versions\n\nYou'll receive:\n- File paths/directories to search\n- Deprecated component names at the end of this prompt\n\nMigration context and rules can be found in the MAPPINGS.md file.\n\nOnly modify code requiring changes per migration rules. Make the necessary updates to the files and do not respond with any explanations or reasoning.\n\nDeprecated components: ${DEPRECATED_COMPONENT_NAMES.join(', ')}.`;\n","import type { Options } from '@anthropic-ai/claude-agent-sdk';\nimport { execSync } from 'child_process';\nimport { readFileSync } from 'fs';\nimport { resolve } from 'path';\n\nimport { SYSTEM_PROMPT } from './constants';\n\ninterface ClaudeSettings {\n apiKeyHelper?: string;\n env?: {\n ANTHROPIC_BASE_URL?: string;\n ANTHROPIC_CUSTOM_HEADERS?: string;\n ANTHROPIC_DEFAULT_SONNET_MODEL?: string;\n ANTHROPIC_DEFAULT_HAIKU_MODEL?: string;\n ANTHROPIC_DEFAULT_OPUS_MODEL?: string;\n API_TIMEOUT_MS?: string;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nconst CLAUDE_SETTINGS_FILE = '.claude/settings.json';\n\nexport function getQueryOptions(isDebug = false): 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 // console.debug(`${CONSOLE_ICONS.info} Resolved Claude environment variables:`, JSON.stringify(envVars));\n // }\n\n return {\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","import { query } from '@anthropic-ai/claude-agent-sdk';\n\nimport { CONSOLE_ICONS } from '../../constants';\nimport { getQueryOptions } from './claude';\n\nconst transformer = async (targetPaths: string[], isDebug = false) => {\n // TODO: We need to confirm you're connected to the VPN\n console.log(`${CONSOLE_ICONS.info} Starting Claude instance...`);\n\n const result = query({\n options: getQueryOptions(isDebug),\n prompt: `Here are the directories to search in: ${targetPaths.join(', ')}.\n In addition to making the required file changes for every relevant file, only respond with the file path/name and number of lines changed per file - e.g. \"<directory/filename> - 5 lines changed\".\n If no changes are made for a file, respond with \"<directory/filename> - No changes required\". If all files require no changes, return only the same format still with nothing else.`,\n });\n\n // TODO: Ensure we're handling all potential types of messages here.\n for await (const message of result) {\n switch (message.type) {\n case 'system':\n if (message.subtype === 'init') {\n console.log(`${CONSOLE_ICONS.success} Initialised Claude instance`);\n console.log(\n `${CONSOLE_ICONS.info} Claude is processing the files... This may take a while.`,\n );\n }\n break;\n\n case 'result':\n if (message.subtype === 'success') {\n console.log(\n `${CONSOLE_ICONS.success} ${message.result.split('\\n').join(`\\n${CONSOLE_ICONS.success} `)}`,\n );\n } else {\n console.log(\n `${CONSOLE_ICONS.error} Claude encountered an error: ${message.errors.join('\\n')}`,\n );\n }\n\n break;\n default:\n // console.log(JSON.stringify(message));\n break;\n }\n }\n\n console.log(`${CONSOLE_ICONS.success} Finished receiving messages from Claude.`);\n};\n\nexport default transformer;\n"],"mappings":";;;;;;;AAAA,MAAa,gBAAgB;CAC3B,MAAM;CACN,OAAO;CACP,SAAS;CACT,SAAS;CACT,OAAO;CACR;;;;ACND,MAAM,6BAA6B;CACjC;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAa,gBAAgB;;;;;;;;;;;;;;;;;;;yBAmBJ,2BAA2B,KAAK,KAAK,CAAC;;;;ACR/D,MAAM,uBAAuB;AAE7B,SAAgB,gBAAgB,UAAU,OAAgB;CAExD,MAAM,4CAA6B,QAAQ,IAAI,QAAQ,IAAI,qBAAqB;CAChF,MAAM,WAAW,KAAK,gCAAmB,oBAAoB,QAAQ,CAAC;CAGtE,IAAI;AACJ,KAAI;AACF,4CAAkB,QAAQ,SAAS,gBAAgB,EACjD,UAAU,SACX,CAAC,CAAC,MAAM;SACH;AAER,KAAI,CAAC,OACH,OAAM,IAAI,MACR,qJACD;AAkBH,QAAO;EACL,KAhBc;GACd,sBAAsB;GACtB,oBAAoB,UAAU,KAAK;GACnC,0BAA0B,UAAU,KAAK;GACzC,gCAAgC,SAAS,KAAK;GAC9C,+BAA+B,SAAS,KAAK;GAC7C,8BAA8B,SAAS,KAAK;GAC5C,gBAAgB,SAAS,KAAK;GAC9B,MAAM,QAAQ,IAAI;GACnB;EAQC,gBAAgB;EAChB,cAAc;GACZ,MAAM;GACN,QAAQ;GACR,QAAQ;GACT;EACD,gBAAgB;GAAC;GAAS;GAAW;GAAO;EAC7C;;;;;AC7DH,MAAM,cAAc,OAAO,aAAuB,UAAU,UAAU;AAEpE,SAAQ,IAAI,GAAG,cAAc,KAAK,8BAA8B;CAEhE,MAAM,oDAAe;EACnB,SAAS,gBAAgB,QAAQ;EACjC,QAAQ,0CAA0C,YAAY,KAAK,KAAK,CAAC;;;EAG1E,CAAC;AAGF,YAAW,MAAM,WAAW,OAC1B,SAAQ,QAAQ,MAAhB;EACE,KAAK;AACH,OAAI,QAAQ,YAAY,QAAQ;AAC9B,YAAQ,IAAI,GAAG,cAAc,QAAQ,8BAA8B;AACnE,YAAQ,IACN,GAAG,cAAc,KAAK,2DACvB;;AAEH;EAEF,KAAK;AACH,OAAI,QAAQ,YAAY,UACtB,SAAQ,IACN,GAAG,cAAc,QAAQ,GAAG,QAAQ,OAAO,MAAM,KAAK,CAAC,KAAK,KAAK,cAAc,QAAQ,GAAG,GAC3F;OAED,SAAQ,IACN,GAAG,cAAc,MAAM,gCAAgC,QAAQ,OAAO,KAAK,KAAK,GACjF;AAGH;EACF,QAEE;;AAIN,SAAQ,IAAI,GAAG,cAAc,QAAQ,2CAA2C;;AAGlF,0BAAe"}