このドキュメントは、autofixer-smarthr-ui-migration ルールに新しいバージョンの移行ルールを追加する開発者向けのガイドです。
decorators属性に関する移行ルールを作成する際は、必ず DECORATORS.md を参照してください。
要点:
- decorators = デフォルト文言変更用(主用途: 多言語化)
- v94以降 = 内部で翻訳対応(decorators不要)
- エラーメッセージ = 利用者視点で「翻訳は自動対応」を明示
- 「IntlProviderのみ使用」等の内部実装詳細は避ける
新しいバージョン(例: v91→v92)の移行ルールを追加する際の手順:
- smarthr-ui のリリースノートから対応が必要な変更を確認
- 破壊的変更(BREAKING CHANGES)
- 推奨される書き方への置き換え(非破壊的だが移行を推奨するもの)
- versionディレクトリを作成(
versions/vXX-to-vYY/) - 移行ルール実装ファイルを作成(
versions/vXX-to-vYY/index.js) - 移行ガイドを作成(
versions/vXX-to-vYY/README.md) - 実装参考ドキュメントを作成(
versions/vXX-to-vYY/REFERENCE.md)- 前versionのREFERENCE.mdをベースにコピー
- 今回のversionに特有のパターンを追加
- テストケースを作成(
versions/vXX-to-vYY/test.js) - VERSION_MODULES に登録(
index.js) - メインテストファイルを更新(
test/autofixer-smarthr-ui-migration.js) - README を更新(サポートバージョンテーブル)
- このDEVELOPER.mdを更新(最新versionへの参照を更新)
rules/autofixer-smarthr-ui-migration/
├── index.js # メインファイル(VERSION_MODULESの登録)
├── README.md # 使い方と概要
├── DEVELOPER.md # このファイル
├── versions/
│ ├── v90-to-v91/ # v90→v91の移行ルール
│ │ ├── index.js # 移行ルール実装
│ │ ├── README.md # 移行ガイド(ユーザー向け)
│ │ ├── REFERENCE.md # 実装参考(開発者向け)
│ │ └── test.js # テストケース
│ └── vXX-to-vYY/ # ← 新規追加
│ ├── index.js # 移行ルール実装
│ ├── README.md # 移行ガイド(ユーザー向け)
│ ├── REFERENCE.md # 実装参考(開発者向け)
│ └── test.js # テストケース
└── test/
└── autofixer-smarthr-ui-migration.js # メインテスト(共通部分 + version別テストの統合)
Claude Code、ChatGPT、Cursor、GitHub Copilot などのAI開発アシスタントを使用する場合、以下のプロンプトを貼り付けてください。
[...] の部分を実際の値に置き換えてから使用してください。
重要: 新しいバージョンを追加したら、このプロンプトの「参考にするファイル」セクションを最新のversionディレクトリに更新してください。これにより、次回以降のversion追加時により適切な実装が行えます。
autofixer-smarthr-ui-migrationルールに新しいバージョン(v[XX]→v[YY])の移行ルールを追加してください。
## 参考にするファイル
必ず以下のファイルを読んで、実装パターンを踏襲してください(最新のversionディレクトリを参照):
- rules/autofixer-smarthr-ui-migration/versions/v94-to-v95/REFERENCE.md(実装パターンの詳細説明)
- rules/autofixer-smarthr-ui-migration/versions/v94-to-v95/index.js(実装例)
- rules/autofixer-smarthr-ui-migration/versions/v94-to-v95/README.md(ユーザー向け移行ガイド)
- rules/autofixer-smarthr-ui-migration/versions/v94-to-v95/test.js(テストケース)
- test/autofixer-smarthr-ui-migration.js(メインテスト)
- libs/common.js(rootPathの取得、tsconfig.jsonのpaths設定読み込み)
## 対応する変更
smarthr-ui v[YY]のリリースノート: [GitHubリリースページのURL]
以下の変更に対応してください(破壊的変更および推奨パターンへの移行):
1. [変更内容1の説明]
- 例: ComponentA が ComponentB にリネーム(破壊的変更)
- 自動修正: [可能/不可能/条件付き]
- セレクター: `ImportDeclaration`, `JSXOpeningElement[name.name="ComponentA"]`
2. [変更内容2の説明]
- 例: propsXがpropsYにリネーム(破壊的変更)
- 自動修正: [可能/不可能/条件付き]
- セレクター: `JSXAttribute[name.name="propsX"]`
3. [変更内容3の説明]
- 例: 非推奨パターンから推奨パターンへの置き換え(非破壊的)
- 自動修正: [可能/不可能/条件付き]
- セレクター: [該当するASTセレクター]
4. ...
**自動修正の判断基準:**
- ✅ 自動修正可能: 機械的に100%正しく変換できる場合
- ⚠️ エラーのみ: 手動確認が必要な場合(未知の属性がある、複数の対処方法がある等)
- ❌ 検出しない: 複雑すぎる、影響範囲が広すぎる場合
**escape hatch用classNameの確認(重要):**
コンポーネント名が変更される場合、escape hatch用className(例: `smarthr-ui-ComponentName`)も変更される可能性があります。
1. **確認方法**: smarthr-uiのPRの差分を確認し、`smarthr-ui-` で始まるclassNameが変更されているか調査
2. **変更がある場合**: CSS/SCSS/styled-components等での使用箇所を検出・置換するチェッカーを追加
3. **変更がない場合**: README.mdに「escape hatch classNameの変更なし」と明記
**例(v91→v92の場合):**
- RemoteTriggerダイアログのリネームがあったが、内部的にはControlledダイアログを使用しているため、className変更なし
- サイズ指定の大文字統一はReact propsの値変更のみで、className生成ロジックには影響なし
## 実装内容
1. versionディレクトリを作成: `versions/v[XX]-to-v[YY]/`
2. `versions/v[XX]-to-v[YY]/index.js` を作成
- messages定義
- createCheckers関数の実装(`createCheckers(context, sourceCode, options = {})`)
- 必要に応じてヘルパー関数
**smarthrUiAliasオプションを利用する場合:**
```javascript
const { rootPath } = require('../../../../libs/common')
createCheckers(context, sourceCode, options = {}) {
const customSmarthrUiAlias = options.smarthrUiAlias
const validSources = ['smarthr-ui']
if (customSmarthrUiAlias) {
validSources.push(customSmarthrUiAlias)
}
const isAliasFile = customSmarthrUiAlias && isFileMatchingSmarthrUiAlias(
context.getFilename(),
customSmarthrUiAlias
)
// ... チェッカー実装
}
-
versions/v[XX]-to-v[YY]/README.mdを作成(ユーザー向け移行ガイド)- 各変更の説明
- Before/Afterのコード例
- 制限事項
-
versions/v[XX]-to-v[YY]/REFERENCE.mdを作成(開発者向け実装参考)- 前versionのREFERENCE.mdをベースにコピー
- 今回のversionに特有の実装パターンを追加
-
versions/v[XX]-to-v[YY]/test.jsを作成- valid: v[YY]形式が正常に通ること
- invalid: v[XX]形式が検出されて修正されること
テストケースの構造:
const v[XX]Tov[YY]Options = [{ from: '[XX]', to: '[YY]' }] module.exports = { valid: [ { code: `import { NewComponent } from 'smarthr-ui'`, options: v[XX]Tov[YY]Options }, { code: `<NewComponent>...</NewComponent>`, options: v[XX]Tov[YY]Options }, ], invalid: [ { code: `import { OldComponent } from 'smarthr-ui'`, output: `import { NewComponent } from 'smarthr-ui'`, options: v[XX]Tov[YY]Options, errors: [{ messageId: 'renameComponent', data: { old: 'OldComponent', new: 'NewComponent', to: 'v[YY]' } }], }, ], }
-
index.jsのVERSION_MODULESに登録const v[XX]Tov[YY] = require('./versions/v[XX]-to-v[YY]/index') const VERSION_MODULES = { 'v90-v91': v90ToV91, 'v[XX]-v[YY]': v[XX]Tov[YY], // ← 追加 }
-
test/autofixer-smarthr-ui-migration.jsを更新const v[XX]Tov[YY]Tests = require('../rules/autofixer-smarthr-ui-migration/versions/v[XX]-to-v[YY]/test') ruleTester.run('autofixer-smarthr-ui-migration', rule, { valid: [ ...v90ToV91Tests.valid, ...v[XX]Tov[YY]Tests.valid, // ← 追加 ], invalid: [ // ... 共通テストケース ... ...v90ToV91Tests.invalid, ...v[XX]Tov[YY]Tests.invalid, // ← 追加 ], })
-
README.mdのサポートバージョンテーブルを更新
-
DEVELOPER.mdを更新
- AIアシスタント用プロンプトの「参考にするファイル」を最新versionに更新
- 「実装の参考ポイント」セクションの「最新version」リンクを更新
- このルールは読みやすさ重視で設計されています(一時的な使用を想定)
- 実行速度より、後から読んだときの理解しやすさを優先してください
- JSDocコメントを適切に追加してください
- ディレクトリ名は必ず
vXX-to-vYY形式にしてください(内部キーと統一)
複数のバージョンをスキップする移行(例: v90→v93)では、コンポーネント名の衝突が発生する可能性があります。
例: v90→v92の一気実行
v90→v91とv91→v92の両方が実行されると、以下のような衝突が発生します:
// 元のコード
import { ActionDialog, RemoteTriggerActionDialog } from 'smarthr-ui'
// 1回目の自動修正(v90→v91 + v91→v92が同時に適用)
import { ControlledActionDialog, ActionDialog } from 'smarthr-ui'
// ESLintは自動的に再実行される(staged fixes)
// 2回目の自動修正で、上記のActionDialogがさらに変換される
import { ControlledActionDialog, ControlledActionDialog } from 'smarthr-ui'
// ❌ 重複!RemoteTriggerActionDialogの情報が失われる原因:
- v90→v91:
ActionDialog→ControlledActionDialog - v91→v92:
RemoteTriggerActionDialog→ActionDialog - ESLintのstaged fixesにより、2回目の自動修正で新しく生成された
ActionDialogがさらにControlledActionDialogに変換されてしまう
このような衝突が予想される場合、getMigrationPath()関数で検出し、実行を禁止します。
実装例(index.js):
function getMigrationPath(from, to) {
// ... 既存のロジック ...
// コンポーネント名衝突の検出
if (path.includes('v90-v91') && path.includes('v91-v92')) {
return {
path,
skipped,
conflict: true,
conflictData: {
from,
to,
middle: '91',
},
}
}
return { path, skipped }
}エラーメッセージ(messages):
messages: {
conflictingMigration: 'v{{from}}→v{{to}}の一気実行はコンポーネント名の衝突により正しく動作しません。段階的に実行してください: 1. { "from": "{{from}}", "to": "{{middle}}" } を実行 2. { "from": "{{middle}}", "to": "{{to}}" } を実行',
// ...
}create()での使用:
create(context) {
// ... オプションチェック ...
const migrationResult = getMigrationPath(from, to)
// 衝突検出
if (migrationResult.conflict) {
return {
Program(node) {
context.report({
node,
messageId: 'conflictingMigration',
data: migrationResult.conflictData,
})
},
}
}
// ... 通常の処理 ...
}新しいバージョンを追加する際は、以下を確認してください:
-
過去のバージョンとの衝突可能性を確認
- 今回リネームするコンポーネント名が、過去のバージョンでリネーム元だった名前と一致しないか
- 例: v90で
ActionDialog→ControlledActionDialog、v92でRemoteTriggerActionDialog→ActionDialogの場合、ActionDialogという名前が衝突
-
衝突が発見された場合
getMigrationPath()に衝突検出ロジックを追加conflictingMigrationメッセージで段階的な実行を促す
-
テストケースを追加
- 衝突するバージョン組み合わせでエラーが表示されることを確認
{ code: `import { ActionDialog } from 'smarthr-ui'`, options: [{ from: '90', to: '92' }], errors: [{ messageId: 'conflictingMigration', data: { from: '90', to: '92', middle: '91' } }], },
- v91→v92追加時のコミット: v90→v92衝突検出の実装例
プロジェクト固有のsmarthr-ui aliasパスに対応するため、smarthrUiAliasオプションが利用可能です。
helpers.js に共通のヘルパー関数が用意されています。これにより、各versionファイルで重複コードを書く必要がありません。
利用可能なヘルパー:
setupSmarthrUiAliasOptions(context, options): validSources拡張とaliasファイル判定を一括で行うisFileMatchingSmarthrUiAlias(filename, smarthrUiAlias): ファイルパスマッチング(低レベル、通常は不要)
const { setupSmarthrUiAliasOptions } = require('../../helpers')
createCheckers(context, sourceCode, options = {}) {
// 1行でセットアップ完了
const { validSources, isAliasFile, filename } = setupSmarthrUiAliasOptions(context, options)
// validSourcesを使ってimportをチェック
const checkers = {
ImportDeclaration(node) {
if (!validSources.includes(node.source.value)) return
// ...
},
}
// aliasファイルの場合のみ、export変数名の置換を追加
if (isAliasFile) {
checkers['ExportNamedDeclaration > VariableDeclaration > VariableDeclarator'] = function(node) {
// ...
}
}
return checkers
}- importのチェック範囲拡張:
smarthr-uiに加えて、aliasパス(例:@/components/parts/smarthr-ui)からのimportも置換対象 - aliasファイル内のexport変数名置換:
smarthrUiAlias配下のファイルで、smarthr-uiコンポーネント名と同じexport変数名を自動置換
詳細はREADME.mdを参照。
以下の機能は helpers.js に共通化されています(v92移行ルール追加時に実装):
setupSmarthrUiAliasOptions: validSources拡張とaliasファイル判定isFileMatchingSmarthrUiAlias: ファイルパスマッチング
これにより、各versionファイルで約30行の重複コードが削減されました。
現状(v92時点): 各versionディレクトリで以下のパターンが繰り返されています:
- ImportDeclarationチェッカー(コンポーネント名リネーム)
- ExportNamedDeclarationチェッカー(re-export対応)
- JSXOpeningElementチェッカー(JSX要素のリネーム)
- Programチェッカー(aliasファイル名変更エラー)
- VariableDeclaratorチェッカー(aliasファイル内のexport変数名置換)
共通化の可能性: これらのチェッカーは構造が似ていますが、以下の理由で現時点では見送っています:
- 読みやすさ優先の方針: このルールは「一時的な使用」を想定し、読みやすさを重視
- version特有のロジック: 各versionで微妙に異なる処理が必要になる可能性
- パターンの確立: v93, v94... と増えて明確なパターンが確立されてから検討すべき
再検討のタイミング:
- v93, v94などが追加され、パターンが安定した時点
- チェッカー生成ヘルパー(
createComponentRenameCheckersなど)の実装を検討 - その際は
helpers.jsに追加し、REFERENCE.mdに「共通パターン」として記載
注意: 共通化を進める際は、抽象化しすぎて読みにくくならないよう注意してください。ヘルパー関数のパラメータが複雑になる場合は、重複を許容する方が保守性が高い場合もあります。
実装が完了したら、必ずこのDEVELOPER.mdを更新してください:
- 「参考にするファイル」セクション(AIアシスタント用プロンプト内)で、v90-to-v91を今回追加したversionに変更
- 「実装の参考ポイント」セクションの「最新version」リンクを今回追加したversionに更新
versions/vXX-to-vYY/REFERENCE.mdを作成(前versionのREFERENCE.mdをベースに、今回特有のパターンを追加)
これにより、このドキュメント自体が常に最新の実装を参照し、自己進化します。
## チェックリスト
新バージョン追加時のチェックリスト:
### ディレクトリとファイル作成
- [ ] `versions/vXX-to-vYY/` ディレクトリを作成
- [ ] `versions/vXX-to-vYY/index.js` を作成
- [ ] messages定義が含まれている
- [ ] createCheckers関数が実装されている(`createCheckers(context, sourceCode, options = {})`)
- [ ] smarthrUiAliasオプションに対応している場合:
- [ ] `const { rootPath } = require('../../../../libs/common')` をimport
- [ ] `validSources`に`customSmarthrUiAlias`を追加
- [ ] `isAliasFile`でファイル判定を実装
- [ ] ヘルパー関数にJSDocコメントがある
- [ ] ファイル冒頭に変更サマリーコメントがある
- [ ] `versions/vXX-to-vYY/README.md` を作成(ユーザー向け移行ガイド)
- [ ] 各変更の説明がある
- [ ] Before/Afterのコード例がある
- [ ] 制限事項が記載されている
- [ ] `versions/vXX-to-vYY/REFERENCE.md` を作成(開発者向け実装参考)
- [ ] 前versionのREFERENCE.mdをベースにコピー
- [ ] 今回のversionに特有の実装パターンを追加
- [ ] よくある実装パターンセクションを更新
- [ ] `versions/vXX-to-vYY/test.js` を作成
- [ ] validケースがある(v[YY]形式)
- [ ] invalidケースがある(v[XX]形式の検出と修正)
- [ ] module.exportsでvalidとinvalidをエクスポート
### 登録と統合
- [ ] `index.js`のVERSION_MODULESに登録
- [ ] `test/autofixer-smarthr-ui-migration.js` を更新(version別テストをインポート)
- [ ] README.mdのサポートバージョンテーブルに追加
- [ ] **DEVELOPER.mdを更新**
- [ ] AIアシスタント用プロンプトの「参考にするファイル」を最新versionに更新
- [ ] 「実装の参考ポイント」セクションの「最新version」リンクを更新
### 動作確認
- [ ] `npm test -- test/autofixer-smarthr-ui-migration.js` が通過
- [ ] オプション `{ from: "[XX]", to: "[YY]" }` で動作確認
- [ ] 複数バージョンスキップ(例: `{ from: "90", to: "[YY]" }`)でも動作確認
- [ ] smarthrUiAliasオプション対応がある場合:
- [ ] `{ from: "[XX]", to: "[YY]", smarthrUiAlias: "@/components/parts/smarthr-ui" }` で動作確認
- [ ] aliasファイル内のexport変数名が置換されることを確認
### 実プロダクトでの検証
単体テストが通過したら、実際のプロダクトで動作確認を行います。
**手順:**
1. **対象プロダクトの選択**
- ローカルにある実プロダクトを選択(例: `/works/workflow/michi/frontend`)
2. **ブランチ作成**
- `staging` ブランチから新しいブランチを作成(`staging` がない場合は `master` または `main`)
```bash
cd /path/to/product
git checkout staging # または master/main
git pull
git checkout -b test/migrator-vXX-to-vYY
-
migratorの追加と設定
- 開発中の
eslint-plugin-smarthrを対象プロダクトに追加
# 相対パスで開発中のパッケージを追加 pnpm add -D ../../../tamatebako/packages/eslint-plugin-smarthr # または npm/yarn の場合 # npm install -D ../../../tamatebako/packages/eslint-plugin-smarthr
- Legacy Config形式 (
.eslintrc.js) の場合:
module.exports = { extends: ['smarthr'], rules: { 'smarthr/autofixer-smarthr-ui-migration': [ 'error', { from: 'XX', to: 'YY', smarthrUiAlias: '@/components/parts/smarthr-ui' } ] } }
- Flat Config形式 (
eslint.config.mjs) の場合:
import smarthr from 'eslint-config-smarthr' import smarthrPlugin from 'eslint-plugin-smarthr' // 追加 export default [ ...smarthr, { plugins: { 'smarthr-local': smarthrPlugin, // 別名で登録 }, rules: { 'smarthr-local/autofixer-smarthr-ui-migration': [ 'error', { from: 'XX', to: 'YY', smarthrUiAlias: '@/components/parts/smarthr-ui' } ], }, }, ]
注意: Flat Configでは、すでに
eslint-config-smarthr経由でsmarthrプラグインが登録されているため、開発中のバージョンを使用するには別名(例:smarthr-local)で登録する必要があります。 - 開発中の
-
初回実行
npm run lint:fix # または eslint --fix . -
問題の修正と再実行
- 実行時に出た問題(エラー、不正な変換など)を確認
- 問題があれば migrator の実装を修正
- 重要: 再実行前に、staging が更新されていない状態(migration前の状態)に戻す
git reset --hard HEAD # 変更を破棄 # migratorを修正後、再度実行 npm run lint:fix
- 問題が解決するまで手順5を繰り返す
-
PR作成
- 問題が修正されたことを確認できたら、差分を確認しやすいよう draft で PR 作成
git add . git commit -m "test: vXX to vYY migration test" git push -u origin test/migrator-vXX-to-vYY gh pr create --draft --title "test: vXX to vYY migration test" --body "migratorの動作確認用PR"
- PR の差分をレビューして、期待通りの変換が行われているか確認
-
クリーンアップ
- 検証完了後、対象プロダクトを元の状態に戻す
# PRはクローズ(マージしない) gh pr close test/migrator-vXX-to-vYY # ブランチを削除 git checkout staging # または master/main git branch -D test/migrator-vXX-to-vYY git push origin --delete test/migrator-vXX-to-vYY # package.jsonとlockファイルを元に戻す git checkout package.json pnpm-lock.yaml # または package-lock.json/yarn.lock pnpm install # 依存関係を再インストール
確認ポイント:
- エラーが出ずに実行完了する
- 意図した変換が正しく行われている
- 不要な変更が含まれていない
- エッジケースでも正しく動作する
- aliasファイル内のexport変数名も正しく置換されている(smarthrUiAliasオプション使用時)
https://github.com/kufu/smarthr-ui/releases
各versionディレクトリにREFERENCE.mdがあり、実装パターンや注意点が記載されています。
最新version: v94-to-v95/REFERENCE.md
このドキュメントには以下が含まれます:
- ファイル構造と各セクションの説明
- 定数定義、messages、createCheckers関数の書き方
- 自動修正の判断基準
- よくある実装パターン
- トラブルシューティング
重要: 新しいバージョンを追加したら、上記の「最新version」リンクを更新してください。
- エラーメッセージの順序を確認(Programノードの警告が先に来る)
- fix関数の戻り値を確認(配列 or 単一のfix)
- セレクターの正規表現が正しいか確認
meta.fixable: 'code'が設定されているか確認- fix関数がfixerを正しく返しているか確認
- ノードの範囲(range)が正しく計算されているか確認
- キーは
'vXX-vYY'形式(ファイル名と一致) - ユーザーが指定する from/to は
"XX","YY"形式(vなし) - 内部的にstepKey生成時に
v${i}-v${i + 1}でvを付与