@wise/wds-codemods 1.0.0-experimental-601f194 → 1.0.0-experimental-49d2d08
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/{helpers-RWhTD5Is.js → helpers-59xSDDPO.js} +441 -1
- package/dist/helpers-59xSDDPO.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/{transformer-B9Mt_gBf.js → transformer-DnE3TyyV.js} +45 -40
- package/dist/transformer-DnE3TyyV.js.map +1 -0
- package/dist/transforms/button/transformer.js +30 -377
- package/dist/transforms/button/transformer.js.map +1 -1
- package/dist/transforms/list-item/transformer.js +2 -2
- package/package.json +2 -2
- package/dist/helpers-RWhTD5Is.js.map +0 -1
- package/dist/transformer-B9Mt_gBf.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transformer-DnE3TyyV.js","names":["modifiedFiles: string[]","findFilesWithImports","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. 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\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 // console.debug(`${CONSOLE_ICONS.info} Resolved Claude environment variables:`, JSON.stringify(envVars));\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 session ID\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 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 { findFilesWithImports } from '../../helpers';\nimport { initiateClaudeSessionOptions, queryClaude } from './claude';\nimport { generateElapsedTime } from './helpers';\n\nconst SRC = '@transferwise/components';\nconst COMPONENTS = [\n 'ActionOption',\n 'RadioOption',\n 'CheckboxOption',\n 'NavigationOption',\n 'Summary',\n 'DefinitionList',\n 'NavigationOptionList',\n];\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 const files = findFilesWithImports(targetPaths, SRC, COMPONENTS);\n\n if (files.length === 0) {\n console.log(`${CONSOLE_ICONS.info} No files with List Item-related imports found. Skipping.`);\n } else {\n for (const filePath of files) {\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 if (assessPrerequisites(filePath, codemodPath)) {\n await queryClaude(filePath, queryOptions, isDebug);\n }\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,353 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
2
|
-
const require_helpers = require('../../helpers-
|
|
2
|
+
const require_helpers = require('../../helpers-59xSDDPO.js');
|
|
3
3
|
|
|
4
|
-
//#region src/helpers/addImport.ts
|
|
5
|
-
/**
|
|
6
|
-
* Adds a named import if it doesn't already exist.
|
|
7
|
-
*/
|
|
8
|
-
function addImport(root, sourceValue, importName, j) {
|
|
9
|
-
const existingImports = root.find(j.ImportDeclaration, { source: { value: sourceValue } });
|
|
10
|
-
if (existingImports.size() > 0) {
|
|
11
|
-
if (existingImports.find(j.ImportSpecifier, { imported: { name: importName } }).size() > 0) return;
|
|
12
|
-
existingImports.forEach((path) => {
|
|
13
|
-
if (path.node.specifiers) path.node.specifiers.push(j.importSpecifier(j.identifier(importName)));
|
|
14
|
-
});
|
|
15
|
-
} else {
|
|
16
|
-
const newImport = j.importDeclaration([j.importSpecifier(j.identifier(importName))], j.literal(sourceValue));
|
|
17
|
-
const firstImport = root.find(j.ImportDeclaration).at(0);
|
|
18
|
-
if (firstImport.size() > 0) firstImport.insertBefore(newImport);
|
|
19
|
-
else {
|
|
20
|
-
const program = root.find(j.Program);
|
|
21
|
-
if (program.size() > 0) program.get("body", 0).insertBefore(newImport);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
var addImport_default = addImport;
|
|
26
|
-
|
|
27
|
-
//#endregion
|
|
28
|
-
//#region src/helpers/hasImport.ts
|
|
29
|
-
/**
|
|
30
|
-
* Checks if a specific import exists in the given root collection and provides
|
|
31
|
-
* a method to remove it if found.
|
|
32
|
-
*/
|
|
33
|
-
function hasImport(root, sourceValue, importName, j) {
|
|
34
|
-
const importDeclarations = root.find(j.ImportDeclaration, { source: { value: sourceValue } });
|
|
35
|
-
/**
|
|
36
|
-
* Finds all ImportSpecifier nodes that expose `importName` but
|
|
37
|
-
* from a different source than `sourceValue`.
|
|
38
|
-
*/
|
|
39
|
-
const conflictingImports = (() => {
|
|
40
|
-
const result = [];
|
|
41
|
-
root.find(j.ImportDeclaration).filter((path) => path.node.source.value !== sourceValue).forEach((path) => {
|
|
42
|
-
for (const specifier of path.node.specifiers ?? []) if (specifier.type === "ImportSpecifier" && specifier.imported.name === importName && specifier.local?.name === importName) result.push(specifier);
|
|
43
|
-
});
|
|
44
|
-
return result;
|
|
45
|
-
})();
|
|
46
|
-
if (importDeclarations.size() === 0) return {
|
|
47
|
-
exists: false,
|
|
48
|
-
remove: () => {},
|
|
49
|
-
resolvedName: importName,
|
|
50
|
-
conflictingImports
|
|
51
|
-
};
|
|
52
|
-
const namedImport = importDeclarations.find(j.ImportSpecifier, { imported: { name: importName } });
|
|
53
|
-
const defaultImport = importDeclarations.find(j.ImportDefaultSpecifier, { local: { name: importName } });
|
|
54
|
-
const aliasImport = importDeclarations.find(j.ImportSpecifier).filter((path) => {
|
|
55
|
-
return path.node.imported.name === importName && path.node.imported.name !== path.node.local?.name;
|
|
56
|
-
});
|
|
57
|
-
const exists = namedImport.size() > 0 || defaultImport.size() > 0;
|
|
58
|
-
const resolveName = () => {
|
|
59
|
-
if (aliasImport.size() > 0) {
|
|
60
|
-
const localName = aliasImport.get(0).node.local?.name;
|
|
61
|
-
if (typeof localName === "string") return localName;
|
|
62
|
-
if (localName && typeof localName === "object" && "name" in localName && typeof localName.name === "string") return localName.name;
|
|
63
|
-
return importName;
|
|
64
|
-
}
|
|
65
|
-
return importName;
|
|
66
|
-
};
|
|
67
|
-
const remove = () => {
|
|
68
|
-
importDeclarations.forEach((path) => {
|
|
69
|
-
const filteredSpecifiers = path.node.specifiers?.filter((specifier) => {
|
|
70
|
-
if (specifier.type === "ImportSpecifier" && specifier.imported.name === importName) return false;
|
|
71
|
-
if (specifier.type === "ImportDefaultSpecifier" && specifier.local?.name === importName) return false;
|
|
72
|
-
return true;
|
|
73
|
-
}) ?? [];
|
|
74
|
-
if (filteredSpecifiers.length === 0) path.prune();
|
|
75
|
-
else j(path).replaceWith(j.importDeclaration(filteredSpecifiers, path.node.source, path.node.importKind));
|
|
76
|
-
});
|
|
77
|
-
};
|
|
78
|
-
return {
|
|
79
|
-
exists,
|
|
80
|
-
remove,
|
|
81
|
-
aliases: aliasImport,
|
|
82
|
-
resolvedName: resolveName(),
|
|
83
|
-
conflictingImports
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
var hasImport_default = hasImport;
|
|
87
|
-
|
|
88
|
-
//#endregion
|
|
89
|
-
//#region src/helpers/iconUtils.ts
|
|
90
|
-
/**
|
|
91
|
-
* Process children of a JSX element to detect icon components and add iconStart or iconEnd attributes accordingly.
|
|
92
|
-
* This is specific to icon handling but can be reused in codemods dealing with icon children.
|
|
93
|
-
*/
|
|
94
|
-
const processIconChildren = (j, children, iconImports, openingElement) => {
|
|
95
|
-
if (!children || !openingElement.attributes) return;
|
|
96
|
-
const unwrapJsxElement = (node) => {
|
|
97
|
-
if (typeof node === "object" && node !== null && "type" in node && node.type === "JSXExpressionContainer" && j.JSXElement.check(node.expression)) return node.expression;
|
|
98
|
-
return node;
|
|
99
|
-
};
|
|
100
|
-
const totalChildren = children.length;
|
|
101
|
-
const iconChildIndex = children.findIndex((child) => {
|
|
102
|
-
const unwrapped = unwrapJsxElement(child);
|
|
103
|
-
return j.JSXElement.check(unwrapped) && unwrapped.openingElement.name.type === "JSXIdentifier" && iconImports.has(unwrapped.openingElement.name.name);
|
|
104
|
-
});
|
|
105
|
-
if (iconChildIndex === -1) return;
|
|
106
|
-
const iconChild = unwrapJsxElement(children[iconChildIndex]);
|
|
107
|
-
if (!iconChild || iconChild.openingElement.name.type !== "JSXIdentifier") return;
|
|
108
|
-
iconChild.openingElement.name.name;
|
|
109
|
-
const iconPropName = iconChildIndex <= totalChildren - 1 - iconChildIndex ? "addonStart" : "addonEnd";
|
|
110
|
-
const iconObject = j.objectExpression([j.property("init", j.identifier("type"), j.literal("icon")), j.property("init", j.identifier("value"), iconChild)]);
|
|
111
|
-
const iconProp = j.jsxAttribute(j.jsxIdentifier(iconPropName), j.jsxExpressionContainer(iconObject));
|
|
112
|
-
openingElement.attributes.push(iconProp);
|
|
113
|
-
children.splice(iconChildIndex, 1);
|
|
114
|
-
const isWhitespaceJsxText = (node) => {
|
|
115
|
-
return typeof node === "object" && node !== null && node.type === "JSXText" && typeof node.value === "string" && node.value.trim() === "";
|
|
116
|
-
};
|
|
117
|
-
if (iconChildIndex - 1 >= 0 && isWhitespaceJsxText(children[iconChildIndex - 1])) children.splice(iconChildIndex - 1, 1);
|
|
118
|
-
else if (isWhitespaceJsxText(children[iconChildIndex])) children.splice(iconChildIndex, 1);
|
|
119
|
-
};
|
|
120
|
-
var iconUtils_default = processIconChildren;
|
|
121
|
-
|
|
122
|
-
//#endregion
|
|
123
|
-
//#region src/helpers/jsxElementUtils.ts
|
|
124
|
-
/**
|
|
125
|
-
* Rename a JSX element name if it is a JSXIdentifier.
|
|
126
|
-
*/
|
|
127
|
-
const setNameIfJSXIdentifier = (elementName, newName) => {
|
|
128
|
-
if (elementName && elementName.type === "JSXIdentifier") return {
|
|
129
|
-
...elementName,
|
|
130
|
-
name: newName
|
|
131
|
-
};
|
|
132
|
-
return elementName;
|
|
133
|
-
};
|
|
134
|
-
/**
|
|
135
|
-
* Check if a list of attributes contains a specific attribute by name.
|
|
136
|
-
*/
|
|
137
|
-
const hasAttribute = (attributes, attributeName) => {
|
|
138
|
-
return Array.isArray(attributes) && attributes.some((attr) => attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === attributeName);
|
|
139
|
-
};
|
|
140
|
-
/**
|
|
141
|
-
* Check if a JSX element's openingElement has a specific attribute.
|
|
142
|
-
*/
|
|
143
|
-
const hasAttributeOnElement = (element, attributeName) => {
|
|
144
|
-
return hasAttribute(element.attributes, attributeName);
|
|
145
|
-
};
|
|
146
|
-
/**
|
|
147
|
-
* Add specified attributes to a JSX element's openingElement if they are not already present.
|
|
148
|
-
*/
|
|
149
|
-
const addAttributesIfMissing = (j, openingElement, attributesToAdd) => {
|
|
150
|
-
if (!Array.isArray(openingElement.attributes)) return;
|
|
151
|
-
const attrs = openingElement.attributes;
|
|
152
|
-
attributesToAdd.forEach(({ attribute, name }) => {
|
|
153
|
-
if (!hasAttributeOnElement(openingElement, name)) attrs.push(attribute);
|
|
154
|
-
});
|
|
155
|
-
};
|
|
156
|
-
/**
|
|
157
|
-
* Returns a collection of JSX elements that match the specified
|
|
158
|
-
* exported name or names of the found aliases.
|
|
159
|
-
*/
|
|
160
|
-
const findJSXElementsByName = (root, j) => (exportedName, aliases) => {
|
|
161
|
-
const aliasNames = aliases?.size() ? aliases.paths().map((path) => path.node.local?.name) : [];
|
|
162
|
-
return root.find(j.JSXElement).filter((path) => {
|
|
163
|
-
const { name } = path.node.openingElement;
|
|
164
|
-
return name.type === "JSXIdentifier" && (name.name === exportedName || aliasNames.includes(name.name));
|
|
165
|
-
});
|
|
166
|
-
};
|
|
167
|
-
/**
|
|
168
|
-
* Removes an attribute by name from a JSX element's openingElement.
|
|
169
|
-
*/
|
|
170
|
-
const removeAttributeByName = (j, openingElement, attributeName) => {
|
|
171
|
-
if (!Array.isArray(openingElement.attributes)) return;
|
|
172
|
-
openingElement.attributes = openingElement.attributes.filter((attr) => {
|
|
173
|
-
return !(attr.type === "JSXAttribute" && attr.name.type === "JSXIdentifier" && attr.name.name === attributeName);
|
|
174
|
-
});
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
//#endregion
|
|
178
|
-
//#region src/helpers/jsxReportingUtils.ts
|
|
179
|
-
/**
|
|
180
|
-
* CodemodReporter is a utility class for reporting issues found during codemod transformations.
|
|
181
|
-
* It provides methods to report issues related to JSX elements, props, and attributes.
|
|
182
|
-
*
|
|
183
|
-
* @example
|
|
184
|
-
* ```typescript
|
|
185
|
-
* const issues: string[] = [];
|
|
186
|
-
* const reporter = createReporter(j, issues);
|
|
187
|
-
*
|
|
188
|
-
* // Report a deprecated prop
|
|
189
|
-
* reporter.reportDeprecatedProp(buttonElement, 'flat', 'variant="text"');
|
|
190
|
-
*
|
|
191
|
-
* // Report complex expression that needs review
|
|
192
|
-
* reporter.reportAmbiguousExpression(element, 'size');
|
|
193
|
-
*
|
|
194
|
-
* // Auto-detect common issues
|
|
195
|
-
* reporter.reportAttributeIssues(element);
|
|
196
|
-
* ```
|
|
197
|
-
*/
|
|
198
|
-
var CodemodReporter = class {
|
|
199
|
-
j;
|
|
200
|
-
issues;
|
|
201
|
-
constructor(options) {
|
|
202
|
-
this.j = options.jscodeshift;
|
|
203
|
-
this.issues = options.issues;
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Reports an issue with a JSX element
|
|
207
|
-
*/
|
|
208
|
-
reportElement(element, reason) {
|
|
209
|
-
const node = this.getNode(element);
|
|
210
|
-
const componentName = this.getComponentName(node);
|
|
211
|
-
const line = this.getLineNumber(node);
|
|
212
|
-
this.addIssue(`Manual review required: <${componentName}> at line ${line} ${reason}.`);
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Reports an issue with a specific prop
|
|
216
|
-
*/
|
|
217
|
-
reportProp(element, propName, reason) {
|
|
218
|
-
const node = this.getNode(element);
|
|
219
|
-
const componentName = this.getComponentName(node);
|
|
220
|
-
const line = this.getLineNumber(node);
|
|
221
|
-
this.addIssue(`Manual review required: prop "${propName}" on <${componentName}> at line ${line} ${reason}.`);
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Reports an issue with a JSX attribute directly
|
|
225
|
-
*/
|
|
226
|
-
reportAttribute(attr, element, reason) {
|
|
227
|
-
const node = this.getNode(element);
|
|
228
|
-
const componentName = this.getComponentName(node);
|
|
229
|
-
const propName = this.getAttributeName(attr);
|
|
230
|
-
const line = this.getLineNumber(attr) || this.getLineNumber(node);
|
|
231
|
-
const defaultReason = this.getAttributeReason(attr);
|
|
232
|
-
const finalReason = reason || defaultReason;
|
|
233
|
-
this.addIssue(`Manual review required: prop "${propName}" on <${componentName}> at line ${line} ${finalReason}.`);
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Reports spread props on an element
|
|
237
|
-
*/
|
|
238
|
-
reportSpreadProps(element) {
|
|
239
|
-
this.reportElement(element, "contains spread props that need manual review");
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Reports conflicting prop and children
|
|
243
|
-
*/
|
|
244
|
-
reportPropWithChildren(element, propName) {
|
|
245
|
-
this.reportProp(element, propName, `conflicts with children - both "${propName}" prop and children are present`);
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Reports unsupported prop value
|
|
249
|
-
*/
|
|
250
|
-
reportUnsupportedValue(element, propName, value) {
|
|
251
|
-
this.reportProp(element, propName, `has unsupported value "${value}"`);
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* Reports ambiguous expression in prop
|
|
255
|
-
*/
|
|
256
|
-
reportAmbiguousExpression(element, propName) {
|
|
257
|
-
this.reportProp(element, propName, "contains a complex expression that needs manual review");
|
|
258
|
-
}
|
|
259
|
-
/**
|
|
260
|
-
* Reports ambiguous children (like dynamic icons)
|
|
261
|
-
*/
|
|
262
|
-
reportAmbiguousChildren(element, childType = "content") {
|
|
263
|
-
this.reportElement(element, `contains ambiguous ${childType} that needs manual review`);
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Reports deprecated prop usage
|
|
267
|
-
*/
|
|
268
|
-
reportDeprecatedProp(element, propName, alternative) {
|
|
269
|
-
const suggestion = alternative ? ` Use ${alternative} instead` : "";
|
|
270
|
-
this.reportProp(element, propName, `is deprecated${suggestion}`);
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Reports missing required prop
|
|
274
|
-
*/
|
|
275
|
-
reportMissingRequiredProp(element, propName) {
|
|
276
|
-
this.reportProp(element, propName, "is required but missing");
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Reports conflicting props
|
|
280
|
-
*/
|
|
281
|
-
reportConflictingProps(element, propNames) {
|
|
282
|
-
const propList = propNames.map((name) => `"${name}"`).join(", ");
|
|
283
|
-
this.reportElement(element, `has conflicting props: ${propList} cannot be used together`);
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Auto-detects and reports common attribute issues
|
|
287
|
-
*/
|
|
288
|
-
reportAttributeIssues(element) {
|
|
289
|
-
const { attributes } = this.getNode(element).openingElement;
|
|
290
|
-
if (!attributes) return;
|
|
291
|
-
if (attributes.some((attr) => attr.type === "JSXSpreadAttribute")) this.reportSpreadProps(element);
|
|
292
|
-
attributes.forEach((attr) => {
|
|
293
|
-
if (attr.type === "JSXAttribute" && attr.value?.type === "JSXExpressionContainer") this.reportAttribute(attr, element);
|
|
294
|
-
});
|
|
295
|
-
}
|
|
296
|
-
/**
|
|
297
|
-
* Finds and reports instances of components that are under an alias (imported with a different name)
|
|
298
|
-
*/
|
|
299
|
-
reportAliases(element) {
|
|
300
|
-
this.reportElement(element, "is used via an import alias and needs manual review");
|
|
301
|
-
}
|
|
302
|
-
/**
|
|
303
|
-
* Finds and reports instances of non-DS import declarations that conflict with the component name
|
|
304
|
-
*/
|
|
305
|
-
reportConflictingImports(node) {
|
|
306
|
-
this.addIssue(`Manual review required: Non-WDS package resulting in an import conflict at line ${this.getLineNumber(node)}.`);
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Reports enum usage for future conversion tracking
|
|
310
|
-
*/
|
|
311
|
-
reportEnumUsage(element, propName, enumValue) {
|
|
312
|
-
this.reportProp(element, propName, `uses enum value "${enumValue}" which has been preserved but should be migrated to a string literal in the future`);
|
|
313
|
-
}
|
|
314
|
-
getNode(element) {
|
|
315
|
-
return "node" in element ? element.node : element;
|
|
316
|
-
}
|
|
317
|
-
getComponentName(node) {
|
|
318
|
-
const { name } = node.openingElement;
|
|
319
|
-
if (name.type === "JSXIdentifier") return name.name;
|
|
320
|
-
return this.j(name).toSource();
|
|
321
|
-
}
|
|
322
|
-
getLineNumber(node) {
|
|
323
|
-
return node.loc?.start.line?.toString() || "unknown";
|
|
324
|
-
}
|
|
325
|
-
getAttributeName(attr) {
|
|
326
|
-
if (attr.name.type === "JSXIdentifier") return attr.name.name;
|
|
327
|
-
return this.j(attr.name).toSource();
|
|
328
|
-
}
|
|
329
|
-
getAttributeReason(attr) {
|
|
330
|
-
if (!attr.value) return "has no value";
|
|
331
|
-
if (attr.value.type === "JSXExpressionContainer") {
|
|
332
|
-
const expr = attr.value.expression;
|
|
333
|
-
const expressionType = expr.type.replace("Expression", "").toLowerCase();
|
|
334
|
-
if (expr.type === "Identifier" || expr.type === "MemberExpression") return `contains a ${expressionType} (${this.j(expr).toSource()})`;
|
|
335
|
-
return `contains a complex ${expressionType} expression`;
|
|
336
|
-
}
|
|
337
|
-
return "needs manual review";
|
|
338
|
-
}
|
|
339
|
-
addIssue(message) {
|
|
340
|
-
this.issues.push(message);
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
const createReporter = (j, issues) => {
|
|
344
|
-
return new CodemodReporter({
|
|
345
|
-
jscodeshift: j,
|
|
346
|
-
issues
|
|
347
|
-
});
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
//#endregion
|
|
351
4
|
//#region src/transforms/button/transformer.ts
|
|
352
5
|
const parser = "tsx";
|
|
353
6
|
const buildPriorityMapping = (opts) => {
|
|
@@ -482,10 +135,10 @@ const transformer = (file, api, options) => {
|
|
|
482
135
|
if (type && priority) return priorityMapping[type]?.[priority] || priority;
|
|
483
136
|
return priority;
|
|
484
137
|
};
|
|
485
|
-
const reporter = createReporter(j, manualReviewIssues);
|
|
486
|
-
const { exists: hasButtonImport, aliases: buttonAliases, resolvedName: buttonName, conflictingImports: conflictingButtonImport } = hasImport_default(root, "@transferwise/components", "Button", j);
|
|
138
|
+
const reporter = require_helpers.createReporter(j, manualReviewIssues);
|
|
139
|
+
const { exists: hasButtonImport, aliases: buttonAliases, resolvedName: buttonName, conflictingImports: conflictingButtonImport } = require_helpers.hasImport_default(root, "@transferwise/components", "Button", j);
|
|
487
140
|
if (conflictingButtonImport.length) conflictingButtonImport.forEach((node) => reporter.reportConflictingImports(node));
|
|
488
|
-
const { exists: hasActionButtonImport, remove: removeActionButtonImport, aliases: actionButtonAliases } = hasImport_default(root, "@transferwise/components", "ActionButton", j);
|
|
141
|
+
const { exists: hasActionButtonImport, remove: removeActionButtonImport, aliases: actionButtonAliases } = require_helpers.hasImport_default(root, "@transferwise/components", "ActionButton", j);
|
|
489
142
|
if (!hasButtonImport && !hasActionButtonImport) return file.source;
|
|
490
143
|
const iconImports = /* @__PURE__ */ new Set();
|
|
491
144
|
root.find(j.ImportDeclaration, { source: { value: "@transferwise/icons" } }).forEach((path) => {
|
|
@@ -497,12 +150,12 @@ const transformer = (file, api, options) => {
|
|
|
497
150
|
});
|
|
498
151
|
});
|
|
499
152
|
if (hasActionButtonImport) {
|
|
500
|
-
if (!hasButtonImport) addImport_default(root, "@transferwise/components", "Button", j);
|
|
501
|
-
findJSXElementsByName(root, j)("ActionButton", actionButtonAliases).forEach((path) => {
|
|
153
|
+
if (!hasButtonImport) require_helpers.addImport_default(root, "@transferwise/components", "Button", j);
|
|
154
|
+
require_helpers.findJSXElementsByName(root, j)("ActionButton", actionButtonAliases).forEach((path) => {
|
|
502
155
|
const { openingElement, closingElement } = path.node;
|
|
503
|
-
openingElement.name = setNameIfJSXIdentifier(openingElement.name, buttonName);
|
|
504
|
-
if (closingElement) closingElement.name = setNameIfJSXIdentifier(closingElement.name, buttonName);
|
|
505
|
-
iconUtils_default(j, path.node.children, iconImports, openingElement);
|
|
156
|
+
openingElement.name = require_helpers.setNameIfJSXIdentifier(openingElement.name, buttonName);
|
|
157
|
+
if (closingElement) closingElement.name = require_helpers.setNameIfJSXIdentifier(closingElement.name, buttonName);
|
|
158
|
+
require_helpers.iconUtils_default(j, path.node.children, iconImports, openingElement);
|
|
506
159
|
if ((openingElement.attributes ?? []).some((attr) => attr.type === "JSXSpreadAttribute")) reporter.reportSpreadProps(path);
|
|
507
160
|
const legacyPropNames = [
|
|
508
161
|
"priority",
|
|
@@ -525,7 +178,7 @@ const transformer = (file, api, options) => {
|
|
|
525
178
|
const hasChildren = path.node.children?.some((child) => child.type === "JSXText" && child.value.trim() !== "" || child.type === "JSXElement" || child.type === "JSXExpressionContainer") || path.node.children && path.node.children?.length > 0;
|
|
526
179
|
if (hasTextProp && hasChildren) reporter.reportPropWithChildren(path, "text");
|
|
527
180
|
else if (hasTextProp && !hasChildren && openingElement.selfClosing) path.replace(j.jsxElement(j.jsxOpeningElement(openingElement.name, openingElement.attributes), j.jsxClosingElement(openingElement.name), [j.jsxText(legacyProps.text || "")]));
|
|
528
|
-
addAttributesIfMissing(j, path.node.openingElement, [{
|
|
181
|
+
require_helpers.addAttributesIfMissing(j, path.node.openingElement, [{
|
|
529
182
|
attribute: j.jsxAttribute(j.jsxIdentifier("v2")),
|
|
530
183
|
name: "v2"
|
|
531
184
|
}, {
|
|
@@ -541,17 +194,17 @@ const transformer = (file, api, options) => {
|
|
|
541
194
|
});
|
|
542
195
|
removeActionButtonImport();
|
|
543
196
|
}
|
|
544
|
-
if (hasButtonImport) findJSXElementsByName(root, j)("Button", buttonAliases).forEach((path) => {
|
|
197
|
+
if (hasButtonImport) require_helpers.findJSXElementsByName(root, j)("Button", buttonAliases).forEach((path) => {
|
|
545
198
|
const { openingElement } = path.node;
|
|
546
|
-
if (hasAttributeOnElement(openingElement, "v2")) return;
|
|
199
|
+
if (require_helpers.hasAttributeOnElement(openingElement, "v2")) return;
|
|
547
200
|
const hasJSXChildren = path.node.children?.some((child) => child.type === "JSXText" && child.value.trim() !== "" || child.type === "JSXElement" || child.type === "JSXFragment" && child.children && child.children.length > 0 || child.type === "JSXExpressionContainer" && child.expression.type !== "JSXEmptyExpression");
|
|
548
201
|
const hasChildrenAsProp = openingElement.attributes?.some((attr) => attr.type === "JSXAttribute" && attr.name?.type === "JSXIdentifier" && attr.name.name === "children");
|
|
549
202
|
if (!hasJSXChildren && !hasChildrenAsProp) return;
|
|
550
|
-
addAttributesIfMissing(j, openingElement, [{
|
|
203
|
+
require_helpers.addAttributesIfMissing(j, openingElement, [{
|
|
551
204
|
attribute: j.jsxAttribute(j.jsxIdentifier("v2")),
|
|
552
205
|
name: "v2"
|
|
553
206
|
}]);
|
|
554
|
-
iconUtils_default(j, path.node.children, iconImports, openingElement);
|
|
207
|
+
require_helpers.iconUtils_default(j, path.node.children, iconImports, openingElement);
|
|
555
208
|
const legacyProps = {};
|
|
556
209
|
const legacyPropNames = [
|
|
557
210
|
"priority",
|
|
@@ -587,7 +240,7 @@ const transformer = (file, api, options) => {
|
|
|
587
240
|
"lg",
|
|
588
241
|
"xl"
|
|
589
242
|
].includes(resolved)) {
|
|
590
|
-
removeAttributeByName(j, openingElement, "size");
|
|
243
|
+
require_helpers.removeAttributeByName(j, openingElement, "size");
|
|
591
244
|
openingElement.attributes?.push(j.jsxAttribute(j.jsxIdentifier("size"), j.literal(resolved)));
|
|
592
245
|
} else if (typeof rawValue === "string") reporter.reportUnsupportedValue(path, "size", rawValue);
|
|
593
246
|
else if (rawValue !== void 0) reporter.reportAmbiguousExpression(path, "size");
|
|
@@ -612,7 +265,7 @@ const transformer = (file, api, options) => {
|
|
|
612
265
|
"tertiary",
|
|
613
266
|
"secondary-neutral"
|
|
614
267
|
].includes(mapped)) {
|
|
615
|
-
removeAttributeByName(j, openingElement, "priority");
|
|
268
|
+
require_helpers.removeAttributeByName(j, openingElement, "priority");
|
|
616
269
|
openingElement.attributes?.push(j.jsxAttribute(j.jsxIdentifier("priority"), j.literal(mapped)));
|
|
617
270
|
} else if (typeof rawValue === "string") reporter.reportUnsupportedValue(path, "priority", rawValue);
|
|
618
271
|
else if (rawValue !== void 0) reporter.reportAmbiguousExpression(path, "priority");
|
|
@@ -644,20 +297,20 @@ const transformer = (file, api, options) => {
|
|
|
644
297
|
"reset"
|
|
645
298
|
];
|
|
646
299
|
if (resolvedType === "negative" && isControlTypeEnum) {
|
|
647
|
-
removeAttributeByName(j, openingElement, "type");
|
|
648
|
-
if (hasAttributeOnElement(openingElement, "sentiment")) removeAttributeByName(j, openingElement, "sentiment");
|
|
649
|
-
addAttributesIfMissing(j, openingElement, [{
|
|
300
|
+
require_helpers.removeAttributeByName(j, openingElement, "type");
|
|
301
|
+
if (require_helpers.hasAttributeOnElement(openingElement, "sentiment")) require_helpers.removeAttributeByName(j, openingElement, "sentiment");
|
|
302
|
+
require_helpers.addAttributesIfMissing(j, openingElement, [{
|
|
650
303
|
attribute: j.jsxAttribute(j.jsxIdentifier("priority"), j.literal("primary")),
|
|
651
304
|
name: "priority"
|
|
652
305
|
}]);
|
|
653
306
|
if (rawType) openingElement.attributes?.push(j.jsxAttribute(j.jsxIdentifier("sentiment"), j.jsxExpressionContainer(j.identifier(rawType))));
|
|
654
307
|
} else if (resolvedType === "negative" && !isTypeEnum) {
|
|
655
|
-
removeAttributeByName(j, openingElement, "type");
|
|
656
|
-
if (hasAttributeOnElement(openingElement, "sentiment")) removeAttributeByName(j, openingElement, "sentiment");
|
|
308
|
+
require_helpers.removeAttributeByName(j, openingElement, "type");
|
|
309
|
+
if (require_helpers.hasAttributeOnElement(openingElement, "sentiment")) require_helpers.removeAttributeByName(j, openingElement, "sentiment");
|
|
657
310
|
openingElement.attributes?.push(j.jsxAttribute(j.jsxIdentifier("sentiment"), j.literal("negative")));
|
|
658
311
|
} else if (isControlTypeEnum && resolvedType && ["positive", "accent"].includes(resolvedType)) {
|
|
659
|
-
removeAttributeByName(j, openingElement, "type");
|
|
660
|
-
addAttributesIfMissing(j, openingElement, [{
|
|
312
|
+
require_helpers.removeAttributeByName(j, openingElement, "type");
|
|
313
|
+
require_helpers.addAttributesIfMissing(j, openingElement, [{
|
|
661
314
|
attribute: j.jsxAttribute(j.jsxIdentifier("priority"), j.literal("primary")),
|
|
662
315
|
name: "priority"
|
|
663
316
|
}]);
|
|
@@ -665,21 +318,21 @@ const transformer = (file, api, options) => {
|
|
|
665
318
|
if (resolvedType && typeof resolvedType === "string" && legacyButtonTypes.includes(resolvedType) && !isTypeEnum) {
|
|
666
319
|
const consistentConversion = getConsistentTypeConversions(resolvedType);
|
|
667
320
|
if (consistentConversion) {
|
|
668
|
-
removeAttributeByName(j, openingElement, "type");
|
|
669
|
-
removeAttributeByName(j, openingElement, "priority");
|
|
670
|
-
removeAttributeByName(j, openingElement, "sentiment");
|
|
321
|
+
require_helpers.removeAttributeByName(j, openingElement, "type");
|
|
322
|
+
require_helpers.removeAttributeByName(j, openingElement, "priority");
|
|
323
|
+
require_helpers.removeAttributeByName(j, openingElement, "sentiment");
|
|
671
324
|
if (consistentConversion.priority) openingElement.attributes?.push(j.jsxAttribute(j.jsxIdentifier("priority"), j.literal(consistentConversion.priority)));
|
|
672
325
|
if (consistentConversion.sentiment) openingElement.attributes?.push(j.jsxAttribute(j.jsxIdentifier("sentiment"), j.literal(consistentConversion.sentiment)));
|
|
673
326
|
} else {
|
|
674
|
-
removeAttributeByName(j, openingElement, "type");
|
|
675
|
-
addAttributesIfMissing(j, openingElement, [{
|
|
327
|
+
require_helpers.removeAttributeByName(j, openingElement, "type");
|
|
328
|
+
require_helpers.addAttributesIfMissing(j, openingElement, [{
|
|
676
329
|
attribute: j.jsxAttribute(j.jsxIdentifier("priority"), j.literal("primary")),
|
|
677
330
|
name: "priority"
|
|
678
331
|
}]);
|
|
679
332
|
}
|
|
680
333
|
} else if (isTypeEnum) {}
|
|
681
334
|
if (typeof finalHtmlType === "string" && htmlTypes.includes(finalHtmlType)) {
|
|
682
|
-
removeAttributeByName(j, openingElement, "htmlType");
|
|
335
|
+
require_helpers.removeAttributeByName(j, openingElement, "htmlType");
|
|
683
336
|
openingElement.attributes?.push(j.jsxAttribute(j.jsxIdentifier("type"), j.literal(finalHtmlType)));
|
|
684
337
|
} else if (typeof rawType === "string" || typeof rawHtmlType === "string") {
|
|
685
338
|
const valueToCheck = rawType ?? rawHtmlType ?? "";
|
|
@@ -698,7 +351,7 @@ const transformer = (file, api, options) => {
|
|
|
698
351
|
if (!openingElement.attributes?.some((attr) => attr.type === "JSXAttribute" && attr.name && attr.name.name === "sentiment")) {
|
|
699
352
|
const rawValue = legacyProps.sentiment;
|
|
700
353
|
if (rawValue === "negative") {
|
|
701
|
-
removeAttributeByName(j, openingElement, "sentiment");
|
|
354
|
+
require_helpers.removeAttributeByName(j, openingElement, "sentiment");
|
|
702
355
|
openingElement.attributes?.push(j.jsxAttribute(j.jsxIdentifier("sentiment"), j.literal("negative")));
|
|
703
356
|
} else if (typeof rawValue === "string") reporter.reportUnsupportedValue(path, "sentiment", rawValue);
|
|
704
357
|
else if (rawValue !== void 0) reporter.reportAmbiguousExpression(path, "sentiment");
|