@aphrody/m3-codemods

中文文档
1.4.7发布于 2026/10/23Apache-2.0TypeScriptCommonJS零依赖近 30 天下载 1806

Codemods MUI React -> @aphrody/m3-react (Bun, sans dépendance runtime) + règles ast-grep

原始使用文档
文档目录7 节
  1. Two tools
  2. Transforms
  3. Automated
  4. Manual (marked MIGRATION-TODO )
  5. Known limits
  6. ast-grep rules ( rules/ , sgconfig.yml )
  7. Fixtures

@aphrody/m3-codemods

Codemods and ast-grep rules that migrate MUI React (@mui/material, @mui/icons-material) to @aphrody/m3-react and Material Symbols.

bun add -d @aphrody/m3-codemods
import { transformSource } from "@aphrody/m3-codemods";

const { source, diagnostics } =
  transformSource(`import { Button } from "@mui/material";
export const Save = () => <Button variant="outlined">Save</Button>;`);
console.log(source); // MdOutlinedButton from @aphrody/m3-react
console.log(diagnostics); // MIGRATION-TODO notes left for manual work

License: Apache-2.0 (LICENSE). Install guide: docs/material/m3/INSTALL.md.

No runtime dependency: the engine runs on Bun alone. m3-bun migrate runs these transforms over a project.

Two tools

ToolRole
transforms (transforms/)Full rewrite: imports, JSX, props, slots; variant-aware and idempotent.
ast-grep rules (rules/)Inventory of what is left to migrate, plus a few trivial fixes.

Transforms

All transforms share lib/engine.ts (mapping table lib/mapping.ts, JSX helpers lib/jsx-helpers.ts). Sources are read by a TSX scanner (lib/tsx-scan.ts) and changed by positioned text edits (lib/edits.ts), so untouched code keeps its formatting. Input must be TSX that Bun.Transpiler accepts; otherwise the file is left unchanged with a SyntaxError.

TransformScope
transforms/orchestrator.tsThe whole mapping (recommended for bulk migration).
transforms/mui-imports.tsSame as the orchestrator (semantic alias).
transforms/button.tsButton, IconButton, Fab only (variant-aware).
transforms/fields.tsTextField, Select, NativeSelect (+ MenuItem) only.
transforms/icons.ts@mui/icons-material to <md-icon> (Material Symbols names).

From a checkout of this package:

bun scripts/codemod.ts orchestrator 'src/**/*.tsx' --dry   # list the files that would change
bun scripts/codemod.ts icons src/App.tsx                   # write the change

Each transform exports default (file: { path?, source }, api?, options?) => string. icons.ts is separate (the orchestrator does not touch @mui/icons-material): <CloseIcon/> becomes <md-icon>close</md-icon> through lib/icon-names.ts (PascalCase to snake_case, checked against the 4253 official glyphs in data/material-symbols-names.json); brand logos are kept with a TODO. The consolidated component and icon mapping is mui-m3-map.json (bun scripts/export-map-json.ts). Targeted transforms (button, fields) touch only their components.

Automated

  • Imports: @mui/material named, default sub-path and aliased imports become one sorted import { ... } from "@aphrody/m3-react"; the side-effect import @aphrody/material-web/icon/icon.js is added when an <md-icon> is generated.
  • Variant-aware wrappers: Button contained (or none) / outlined / text / elevated / tonal become MdFilledButton, MdOutlinedButton, MdTextButton, MdElevatedButton, MdFilledTonalButton; TextField and Select filled or outlined become the matching MdFilled* / MdOutlined*. The variant prop is consumed.
  • One-to-one renames: Checkbox to MdCheckbox, Switch to MdSwitch, Dialog to MdDialog, MenuItem to MdMenuItem, Divider to MdDivider, Typography to MdType, and so on.
  • Icons: startIcon / endIcon become <md-icon slot="icon"> as the first child (TODO for endIcon).
  • Slotted parts: DialogTitle / DialogContent / DialogActions and CardContent / CardHeader / CardMedia become <div slot="headline|content|actions|media"> (with a TODO).
  • Layout: Box, Container, Stack, Grid, Paper become <div> (TODO for Tailwind classes).
  • Everything else gets a MIGRATION-TODO marker that is always valid JSX.

Manual (marked MIGRATION-TODO)

  • sx: removed; convert to Tailwind classes and --md-sys-* tokens. Tailwind cannot reach the shadow DOM of md-*.
  • onChange(e, value): material-web emits native input / change events; read e.target.value. Handler bodies are not rewritten.
  • Props without an equivalent (color, size, fullWidth, disableElevation, disableRipple) are removed.
  • Gap components (Avatar, Alert, Breadcrumbs, Rating, Skeleton, Backdrop, Modal, Popover, Popper, Link, transitions, CssBaseline, ...) are not transformed; their JSX and MUI import stay.
  • Dialog and Card slots: check that each <div slot> is a direct child of the md-* parent.

Known limits

  • Handler bodies and controlled-state logic are not rewritten.
  • Member-expression components (<Foo.Bar/>) and indirect re-exports (import { Button } from "./ui") are not handled.
  • Tab always becomes MdPrimaryTab.
  • Children of a renamed element lose line-break JSX whitespace (cosmetic; run bun fmt afterwards).
  • startIcon / endIcon on a self-closing element is removed without an <md-icon> (TODO added).

ast-grep rules (rules/, sgconfig.yml)

ast-grep scan                                           # report for the project (from this directory)
ast-grep scan --filter '^fix-divider$' --update-all     # apply the Divider fix
RuleKindEffect
detect-mui-importsreport, warningEvery @mui/material import (root and sub-paths).
detect-gap-componentsreport, errorGap components without an md-* equivalent.
detect-sx-propreport, warningsx props to convert.
fix-dividerfixable<Divider .../> to <md-divider ...> (the import stays).

The rules do not choose variants or manage imports; use the transforms for a real migration.

Fixtures

Before/after fixtures live in __testfixtures__/ (prefix icons- runs the icons transform, others the orchestrator). bun scripts/run-fixtures.ts compares them (--update regenerates the expected outputs after an intended change).

版本与发布记录

@aphrody/m3-codemods 共发布 8 个版本,首次发布于 2026/10/05;过去 12 个月发布了 8 个版本。

版本发布日期距今
1.4.7latest2026/10/2316 天前
1.4.42026/10/1821 天前
3.3.112026/10/1029 天前
3.3.102026/10/1029 天前
3.3.92026/10/1029 天前
3.3.82026/10/0930 天前

关于 @aphrody/m3-codemods 的常见问题

@aphrody/m3-codemods 是什么?

Codemods MUI React -> @aphrody/m3-react (Bun, sans dépendance runtime) + règles ast-grep

如何安装 @aphrody/m3-codemods?

在项目目录运行 npm install @aphrody/m3-codemods,或使用 pnpm add / yarn add / bun add。

@aphrody/m3-codemods 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@aphrody/m3-codemods 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@aphrody/m3-codemods 可以商用吗?

@aphrody/m3-codemods 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@aphrody/m3-codemods 的下载量有多少?

根据 npm 官方下载统计,@aphrody/m3-codemods 在 2026/10/06 – 2026/11/04 这 30 天内被下载 1,806 次,日均约 60 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@aphrody/m3-codemods 还在维护吗?

最新版本 1.4.7 发布于 2026/10/23(16 天前);至今共发布 8 个版本,其中过去 12 个月发布了 8 个;首次发布于 2026/10/05。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。