feat: MUI 4 to BUI migration - complex component codemods (#117, #118, #119, #120, #121)#130
Open
schultzp2020 wants to merge 6 commits into
Open
feat: MUI 4 to BUI migration - complex component codemods (#117, #118, #119, #120, #121)#130schultzp2020 wants to merge 6 commits into
schultzp2020 wants to merge 6 commits into
Conversation
Use Promise.resolve returns, remove non-null assertions, and type regex replace callbacks to satisfy oxlint --deny-warnings in CI. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Pull request overview
Adds five new “misc” codemods to support Backstage’s MUI v4 → BUI component migration (Dialog, Tabs, Menu/Popover, List family, Chip→Tag), including workflow configs, test fixtures, and a changeset for publishing.
Changes:
- Introduce new AST-based codemods for Tabs, Menu/Popover, List family, Dialog, and Chip→Tag migrations.
- Add per-codemod workflows/tsconfig/package metadata plus fixture-based tests and metrics snapshots.
- Document the new codemods in the root README and register them for release via a changeset (plus yarn.lock workspace entries).
Reviewed changes
Copilot reviewed 126 out of 127 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| yarn.lock | Adds workspace entries for the 5 new codemod packages. |
| README.md | Documents the new “misc” codemods in the repository index. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/workflow.yaml | Defines the codemod workflow entrypoint for the Tabs migration. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tsconfig.json | TS config for authoring/testing the Tabs codemod script. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/vertical-tabs-todo/metrics.json | Metrics snapshot for the “vertical tabs → TODO” fixture. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/vertical-tabs-todo/input.tsx | Input fixture for vertical tabs case. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/vertical-tabs-todo/expected.tsx | Expected output fixture for vertical tabs case. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/tab-context-pattern/metrics.json | Metrics snapshot for TabContext-based tabs fixture. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/tab-context-pattern/input.tsx | Input fixture for TabContext-based tabs. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/tab-context-pattern/expected.tsx | Expected output fixture for TabContext-based tabs. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/standalone-tabs/metrics.json | Metrics snapshot for standalone Tabs+Tab fixture. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/standalone-tabs/input.tsx | Input fixture for standalone Tabs+Tab. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/standalone-tabs/expected.tsx | Expected output fixture for standalone Tabs+Tab. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/noop-no-import/input.tsx | No-op fixture when code already uses BUI Tabs. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/noop-no-import/expected.tsx | Expected no-op output for already-migrated BUI Tabs. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/named-barrel-import/metrics.json | Metrics snapshot for named barrel import fixture. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/named-barrel-import/input.tsx | Input fixture for import { Tabs, Tab } from '@material-ui/core'. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/named-barrel-import/expected.tsx | Expected output fixture for named barrel import. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/merge-existing-bui/metrics.json | Metrics snapshot for merging into existing @backstage/ui import. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/merge-existing-bui/input.tsx | Input fixture with existing BUI import and MUI tab imports. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/tests/merge-existing-bui/expected.tsx | Expected output fixture verifying import merge behavior. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/scripts/codemod.ts | Implements the Tabs→BUI Tabs AST transform logic. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/package.json | Declares the Tabs codemod package and test script. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/codemod.yaml | Codemod registry metadata for Tabs migration. |
| codemods/misc/migrate-mui-tabs-to-bui-tabs/CHANGELOG.md | Initializes changelog for the Tabs codemod package. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/workflow.yaml | Defines the codemod workflow entrypoint for Menu/Popover migration. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tsconfig.json | TS config for Menu/Popover codemod authoring/testing. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/simple-menu/metrics.json | Metrics snapshot for simple Menu migration fixture. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/simple-menu/input.tsx | Input fixture for Menu + MenuItem pattern. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/simple-menu/expected.tsx | Expected output fixture for MenuTrigger/Menu/MenuItem result. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/popover-with-menu-list/metrics.json | Metrics snapshot for Popover + MenuList fixture. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/popover-with-menu-list/input.tsx | Input fixture for Popover wrapping MenuList/MenuItem. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/popover-with-menu-list/expected.tsx | Expected output fixture for Popover→MenuTrigger/Menu conversion. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/noop-no-import/input.tsx | No-op fixture when code already uses BUI Menu components. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/noop-no-import/expected.tsx | Expected no-op output for already-migrated BUI Menu. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/named-barrel-import/metrics.json | Metrics snapshot for named barrel import fixture. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/named-barrel-import/input.tsx | Input fixture for import { Menu, MenuItem } from '@material-ui/core'. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/named-barrel-import/expected.tsx | Expected output fixture for named barrel import case. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/merge-existing-bui/metrics.json | Metrics snapshot for import merging with existing @backstage/ui. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/merge-existing-bui/input.tsx | Input fixture with both MUI menu imports and existing BUI imports. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/merge-existing-bui/expected.tsx | Expected output fixture verifying BUI import merge. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/anchor-el-todo/metrics.json | Metrics snapshot for anchorEl TODO fixture. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/anchor-el-todo/input.tsx | Input fixture for anchorEl-driven menu host. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/tests/anchor-el-todo/expected.tsx | Expected output fixture demonstrating TODO insertion. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/scripts/codemod.ts | Implements Menu/Popover→BUI MenuTrigger/Menu/MenuItem transform logic. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/package.json | Declares the Menu/Popover codemod package and test script. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/codemod.yaml | Codemod registry metadata for Menu/Popover migration. |
| codemods/misc/migrate-mui-menu-popover-to-bui-menu/CHANGELOG.md | Initializes changelog for the Menu/Popover codemod package. |
| codemods/misc/migrate-mui-list-family-to-bui-list/workflow.yaml | Defines the codemod workflow entrypoint for List family migration. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tsconfig.json | TS config for List family codemod authoring/testing. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/text-only-no-icon/metrics.json | Metrics snapshot for text-only ListItem fixture. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/text-only-no-icon/input.tsx | Input fixture for ListItemText primary-only case. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/text-only-no-icon/expected.tsx | Expected output fixture for ListRow conversion (no icon). |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/simple-list-with-icon/metrics.json | Metrics snapshot for ListItemIcon + ListItemText fixture. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/simple-list-with-icon/input.tsx | Input fixture for icon + primary/secondary ListItemText. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/simple-list-with-icon/expected.tsx | Expected output fixture for ListRow with icon/description. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/noop-no-import/input.tsx | No-op fixture when code already uses BUI List/ListRow. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/noop-no-import/expected.tsx | Expected no-op output for already-migrated list. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/named-barrel-import/metrics.json | Metrics snapshot for named barrel import list fixture. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/named-barrel-import/input.tsx | Input fixture for import { List, ListItem, ... } from '@material-ui/core'. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/named-barrel-import/expected.tsx | Expected output fixture for named barrel import list case. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/merge-existing-bui/metrics.json | Metrics snapshot for import merge into existing @backstage/ui. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/merge-existing-bui/input.tsx | Input fixture containing other BUI components plus MUI list imports. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/merge-existing-bui/expected.tsx | Expected output fixture verifying BUI import merge for lists. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/interactive-todo/metrics.json | Metrics snapshot for interactive ListItem TODO fixture. |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/interactive-todo/input.tsx | Input fixture for interactive ListItem (button, onClick). |
| codemods/misc/migrate-mui-list-family-to-bui-list/tests/interactive-todo/expected.tsx | Expected output fixture demonstrating TODO insertion for complex rows. |
| codemods/misc/migrate-mui-list-family-to-bui-list/scripts/codemod.ts | Implements ListItem/ListItemText/ListItemIcon→ListRow transform logic. |
| codemods/misc/migrate-mui-list-family-to-bui-list/package.json | Declares the List family codemod package and test script. |
| codemods/misc/migrate-mui-list-family-to-bui-list/codemod.yaml | Codemod registry metadata for List family migration. |
| codemods/misc/migrate-mui-list-family-to-bui-list/CHANGELOG.md | Initializes changelog for the List family codemod package. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/workflow.yaml | Defines the codemod workflow entrypoint for Dialog shell migration. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tsconfig.json | TS config for Dialog codemod authoring/testing. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/noop-no-import/input.tsx | No-op fixture when code already uses BUI Dialog components. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/noop-no-import/expected.tsx | Expected no-op output for already-migrated dialog. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/named-barrel-import/metrics.json | Metrics snapshot for named barrel import dialog fixture. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/named-barrel-import/input.tsx | Input fixture for import { Dialog, DialogTitle, ... } from '@material-ui/core'. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/named-barrel-import/expected.tsx | Expected output fixture for barrel import dialog case. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/merge-existing-bui/metrics.json | Metrics snapshot for import merging with existing @backstage/ui. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/merge-existing-bui/input.tsx | Input fixture with existing BUI imports plus MUI dialog imports. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/merge-existing-bui/expected.tsx | Expected output fixture verifying BUI import merge for dialogs. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/full-width-todo/metrics.json | Metrics snapshot for fullWidth/maxWidth TODO dialog fixture. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/full-width-todo/input.tsx | Input fixture for dialog sizing props case. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/full-width-todo/expected.tsx | Expected output fixture demonstrating TODO insertion for sizing props. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/controlled-dialog/metrics.json | Metrics snapshot for controlled dialog shell fixture. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/controlled-dialog/input.tsx | Input fixture for dialog with title/content/actions shell. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/controlled-dialog/expected.tsx | Expected output fixture for BUI dialog header/body/footer conversion. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/complex-on-close-todo/metrics.json | Metrics snapshot for complex onClose TODO fixture. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/complex-on-close-todo/input.tsx | Input fixture for inline/complex onClose handler. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/tests/complex-on-close-todo/expected.tsx | Expected output fixture demonstrating TODO insertion for complex close logic. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/scripts/codemod.ts | Implements Dialog→BUI Dialog shell transform logic. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/package.json | Declares the Dialog codemod package and test script. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/codemod.yaml | Codemod registry metadata for Dialog shell migration. |
| codemods/misc/migrate-mui-dialog-to-bui-dialog/CHANGELOG.md | Initializes changelog for the Dialog codemod package. |
| codemods/misc/migrate-mui-chip-to-tag/workflow.yaml | Defines the codemod workflow entrypoint for Chip→Tag migration. |
| codemods/misc/migrate-mui-chip-to-tag/tsconfig.json | TS config for Chip→Tag codemod authoring/testing. |
| codemods/misc/migrate-mui-chip-to-tag/tests/simple-display-chip/metrics.json | Metrics snapshot for simple display chip fixture. |
| codemods/misc/migrate-mui-chip-to-tag/tests/simple-display-chip/input.tsx | Input fixture for Chip label="..." size="small". |
| codemods/misc/migrate-mui-chip-to-tag/tests/simple-display-chip/expected.tsx | Expected output fixture for Tag conversion. |
| codemods/misc/migrate-mui-chip-to-tag/tests/noop-no-import/input.tsx | No-op fixture when code already uses BUI Tag. |
| codemods/misc/migrate-mui-chip-to-tag/tests/noop-no-import/expected.tsx | Expected no-op output for already-migrated Tag. |
| codemods/misc/migrate-mui-chip-to-tag/tests/named-import-barrel/metrics.json | Metrics snapshot for barrel import Chip fixture. |
| codemods/misc/migrate-mui-chip-to-tag/tests/named-import-barrel/input.tsx | Input fixture for import { Chip } from '@material-ui/core'. |
| codemods/misc/migrate-mui-chip-to-tag/tests/named-import-barrel/expected.tsx | Expected output fixture for barrel import Chip conversion. |
| codemods/misc/migrate-mui-chip-to-tag/tests/merge-existing-bui/metrics.json | Metrics snapshot for merging Tag into existing BUI import. |
| codemods/misc/migrate-mui-chip-to-tag/tests/merge-existing-bui/input.tsx | Input fixture with existing BUI import plus Chip import. |
| codemods/misc/migrate-mui-chip-to-tag/tests/merge-existing-bui/expected.tsx | Expected output fixture verifying import merge for Tag. |
| codemods/misc/migrate-mui-chip-to-tag/tests/interactive-chip-todo/metrics.json | Metrics snapshot for interactive chip TODO fixture. |
| codemods/misc/migrate-mui-chip-to-tag/tests/interactive-chip-todo/input.tsx | Input fixture for onDelete interactive chip. |
| codemods/misc/migrate-mui-chip-to-tag/tests/interactive-chip-todo/expected.tsx | Expected output fixture demonstrating TODO insertion for interactive chip. |
| codemods/misc/migrate-mui-chip-to-tag/tests/dynamic-label/metrics.json | Metrics snapshot for dynamic label chip fixture. |
| codemods/misc/migrate-mui-chip-to-tag/tests/dynamic-label/input.tsx | Input fixture for label={name}. |
| codemods/misc/migrate-mui-chip-to-tag/tests/dynamic-label/expected.tsx | Expected output fixture for Tag with expression children. |
| codemods/misc/migrate-mui-chip-to-tag/tests/clickable-chip-todo/metrics.json | Metrics snapshot for clickable chip TODO fixture. |
| codemods/misc/migrate-mui-chip-to-tag/tests/clickable-chip-todo/input.tsx | Input fixture for clickable + onClick chip. |
| codemods/misc/migrate-mui-chip-to-tag/tests/clickable-chip-todo/expected.tsx | Expected output fixture demonstrating TODO insertion for clickable chip. |
| codemods/misc/migrate-mui-chip-to-tag/tests/chip-no-size/metrics.json | Metrics snapshot for chip without size prop. |
| codemods/misc/migrate-mui-chip-to-tag/tests/chip-no-size/input.tsx | Input fixture for Chip label="..." (no size). |
| codemods/misc/migrate-mui-chip-to-tag/tests/chip-no-size/expected.tsx | Expected output fixture for basic Tag conversion. |
| codemods/misc/migrate-mui-chip-to-tag/tests/chip-group/metrics.json | Metrics snapshot for sibling chips grouped into TagGroup. |
| codemods/misc/migrate-mui-chip-to-tag/tests/chip-group/input.tsx | Input fixture for adjacent sibling chips. |
| codemods/misc/migrate-mui-chip-to-tag/tests/chip-group/expected.tsx | Expected output fixture for TagGroup wrapping. |
| codemods/misc/migrate-mui-chip-to-tag/scripts/codemod.ts | Implements Chip→Tag (+ TagGroup) transform logic. |
| codemods/misc/migrate-mui-chip-to-tag/package.json | Declares the Chip→Tag codemod package and test script. |
| codemods/misc/migrate-mui-chip-to-tag/codemod.yaml | Codemod registry metadata for Chip→Tag migration. |
| codemods/misc/migrate-mui-chip-to-tag/CHANGELOG.md | Initializes changelog for the Chip→Tag codemod package. |
| .changeset/mui-to-bui-complex-components.md | Adds a changeset to release the 5 new codemods as minor bumps. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Cursor <cursoragent@cursor.com>
Harden import anchoring, menu trigger detection, tabs onChange rewriting, list icon props, and consecutive TagGroup grouping so migrations stay valid when MUI-only imports are removed or handlers reference event. Co-authored-by: Cursor <cursoragent@cursor.com>
| if (!arrow) { | ||
| const innerText = expr.text().slice(1, -1).trim() | ||
| if (/^[\w$.]+$/.test(innerText)) { | ||
| return `{(key) => ${innerText}(undefined, key)}` |
Comment on lines
+107
to
+111
| if (foundCount > 0) { | ||
| const allSpecifiers = imp.findAll({ rule: { kind: 'import_specifier' } }) | ||
| if (foundCount >= allSpecifiers.length) { | ||
| importNodesToRemove.push(imp) | ||
| } |
Comment on lines
+305
to
+315
| for (const sibling of getNonWhitespaceChildren(parent)) { | ||
| if (sibling.id() === menuEl.id()) { | ||
| continue | ||
| } | ||
| if (isTriggerElement(sibling)) { | ||
| return sibling | ||
| } | ||
| } | ||
|
|
||
| return null | ||
| } |
Comment on lines
+265
to
+275
| const buttonPattern = new RegExp( | ||
| `<button\\s+onClick=\\{${escapeRegex(closeHandler)}\\}([^>]*)>([\\s\\S]*?)</button>`, | ||
| 'g', | ||
| ) | ||
|
|
||
| return content.replace(buttonPattern, (_match: string, attrs: string, label: string) => { | ||
| migrationMetric.increment({ action: 'footer-close-button-migrated' }) | ||
| const extraAttrs = attrs.trim() | ||
| const attrStr = extraAttrs.length > 0 ? ` ${extraAttrs}` : '' | ||
| return `<Button slot="close" onPress={${closeHandler}}${attrStr}>${label}</Button>` | ||
| }) |
Prune partial MUI barrel imports for tabs, pick the preceding menu trigger sibling, and match dialog footer close buttons regardless of attribute order. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add 5 complex component codemods for the MUI 4 to BUI migration:
@backstage/migrate-mui-dialog-to-bui-dialog@backstage/migrate-mui-tabs-to-bui-tabs@backstage/migrate-mui-menu-popover-to-bui-menu@backstage/migrate-mui-list-family-to-bui-list@backstage/migrate-mui-chip-to-tagAll codemods use AST-based transforms (JSSG/ast-grep). All tests pass. All workflows validate.
Closes #117
Closes #118
Closes #119
Closes #120
Closes #121