eslint-plugin-smarthr 6.10.4 → 6.11.0
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/CHANGELOG.md +14 -0
- package/libs/common_domain.js +2 -1
- package/package.json +2 -5
- package/rules/autofixer-smarthr-ui-migration/DEVELOPER.md +189 -24
- package/rules/autofixer-smarthr-ui-migration/README.md +1 -0
- package/rules/autofixer-smarthr-ui-migration/helpers.js +78 -0
- package/rules/autofixer-smarthr-ui-migration/index.js +41 -3
- package/rules/autofixer-smarthr-ui-migration/versions/v90-to-v91/README.md +8 -0
- package/rules/autofixer-smarthr-ui-migration/versions/v90-to-v91/index.js +20 -42
- package/rules/autofixer-smarthr-ui-migration/versions/v90-to-v91/test.js +35 -0
- package/rules/autofixer-smarthr-ui-migration/versions/v91-to-v92/README.md +198 -0
- package/rules/autofixer-smarthr-ui-migration/versions/v91-to-v92/REFERENCE.md +1356 -0
- package/rules/autofixer-smarthr-ui-migration/versions/v91-to-v92/index.js +430 -0
- package/rules/autofixer-smarthr-ui-migration/versions/v91-to-v92/test.js +348 -0
- package/rules/require-barrel-import/index.js +25 -2
- package/test/autofixer-smarthr-ui-migration.js +19 -12
- package/test/format-import-path.js +337 -0
- package/test/require-barrel-import.js +4 -4
- package/tsconfig.json +2 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [6.11.0](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v6.10.4...eslint-plugin-smarthr-v6.11.0) (2026-04-14)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* **autofixer-smarthr-ui-migration:** v91→v92移行ルールを追加 ([#1209](https://github.com/kufu/tamatebako/issues/1209)) ([c29bf7c](https://github.com/kufu/tamatebako/commit/c29bf7c628e25216245f4082354a88add7e650b2))
|
|
11
|
+
* **require-barrel-import:** エラーメッセージを詳細化して実用性を向上 ([#1227](https://github.com/kufu/tamatebako/issues/1227)) ([e2280e5](https://github.com/kufu/tamatebako/commit/e2280e5e47bfb5c9a2b89bd08331a0b2643c278e))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* **eslint-plugin-smarthr:** 不要な engines フィールドを削除 ([#1240](https://github.com/kufu/tamatebako/issues/1240)) ([678cfc6](https://github.com/kufu/tamatebako/commit/678cfc6fa4b05eb8547f45c135d27d44f51a7fc7))
|
|
17
|
+
* **format-import-path:** 複数の拡張子(.presentational.tsx等)に対応 ([#1242](https://github.com/kufu/tamatebako/issues/1242)) ([9f51b41](https://github.com/kufu/tamatebako/commit/9f51b41e1be02f6d6f982f1211c4bfb516179119))
|
|
18
|
+
|
|
5
19
|
## [6.10.4](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v6.10.3...eslint-plugin-smarthr-v6.10.4) (2026-04-13)
|
|
6
20
|
|
|
7
21
|
|
package/libs/common_domain.js
CHANGED
|
@@ -63,7 +63,8 @@ const calculateDomainNode = (calclatedContext, node) => {
|
|
|
63
63
|
replacedPath = exts.map((j) => `${replacedPath}${j}`).find((j) => fs.existsSync(j)) || replacedPath
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
// 拡張子を除去(.js, .jsx, .ts, .tsx のみ除去し、.presentational などは残す)
|
|
67
|
+
replacedPath = replacedPath.replace(/^(.+?)((\/index)?\.(js|jsx|ts|tsx)|\/)$/, '$1')
|
|
67
68
|
}
|
|
68
69
|
|
|
69
70
|
const resolvedImportPath = replacedPath[0] === '/' ? replacedPath : ''
|
package/package.json
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-smarthr",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.11.0",
|
|
4
4
|
"author": "SmartHR",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "A sharable ESLint plugin for SmartHR",
|
|
7
7
|
"main": "index.js",
|
|
8
|
-
"engines": {
|
|
9
|
-
"node": ">=24.14.1"
|
|
10
|
-
},
|
|
11
8
|
"scripts": {
|
|
12
9
|
"test": "jest"
|
|
13
10
|
},
|
|
@@ -37,5 +34,5 @@
|
|
|
37
34
|
"eslintplugin",
|
|
38
35
|
"smarthr"
|
|
39
36
|
],
|
|
40
|
-
"gitHead": "
|
|
37
|
+
"gitHead": "17b3e279b5cf8ffeef90d1eccce77101c7b68cba"
|
|
41
38
|
}
|
|
@@ -56,10 +56,10 @@ autofixer-smarthr-ui-migrationルールに新しいバージョン(v[XX]→v[Y
|
|
|
56
56
|
## 参考にするファイル
|
|
57
57
|
|
|
58
58
|
必ず以下のファイルを読んで、実装パターンを踏襲してください(最新のversionディレクトリを参照):
|
|
59
|
-
- rules/autofixer-smarthr-ui-migration/versions/
|
|
60
|
-
- rules/autofixer-smarthr-ui-migration/versions/
|
|
61
|
-
- rules/autofixer-smarthr-ui-migration/versions/
|
|
62
|
-
- rules/autofixer-smarthr-ui-migration/versions/
|
|
59
|
+
- rules/autofixer-smarthr-ui-migration/versions/v91-to-v92/REFERENCE.md(実装パターンの詳細説明)
|
|
60
|
+
- rules/autofixer-smarthr-ui-migration/versions/v91-to-v92/index.js(実装例)
|
|
61
|
+
- rules/autofixer-smarthr-ui-migration/versions/v91-to-v92/README.md(ユーザー向け移行ガイド)
|
|
62
|
+
- rules/autofixer-smarthr-ui-migration/versions/v91-to-v92/test.js(テストケース)
|
|
63
63
|
- test/autofixer-smarthr-ui-migration.js(メインテスト)
|
|
64
64
|
- libs/common.js(rootPathの取得、tsconfig.jsonのpaths設定読み込み)
|
|
65
65
|
|
|
@@ -91,6 +91,18 @@ smarthr-ui v[YY]のリリースノート: [GitHubリリースページのURL]
|
|
|
91
91
|
- ⚠️ エラーのみ: 手動確認が必要な場合(未知の属性がある、複数の対処方法がある等)
|
|
92
92
|
- ❌ 検出しない: 複雑すぎる、影響範囲が広すぎる場合
|
|
93
93
|
|
|
94
|
+
**escape hatch用classNameの確認(重要):**
|
|
95
|
+
|
|
96
|
+
コンポーネント名が変更される場合、escape hatch用className(例: `smarthr-ui-ComponentName`)も変更される可能性があります。
|
|
97
|
+
|
|
98
|
+
1. **確認方法**: smarthr-uiのPRの差分を確認し、`smarthr-ui-` で始まるclassNameが変更されているか調査
|
|
99
|
+
2. **変更がある場合**: CSS/SCSS/styled-components等での使用箇所を検出・置換するチェッカーを追加
|
|
100
|
+
3. **変更がない場合**: README.mdに「escape hatch classNameの変更なし」と明記
|
|
101
|
+
|
|
102
|
+
**例(v91→v92の場合):**
|
|
103
|
+
- RemoteTriggerダイアログのリネームがあったが、内部的にはControlledダイアログを使用しているため、className変更なし
|
|
104
|
+
- サイズ指定の大文字統一はReact propsの値変更のみで、className生成ロジックには影響なし
|
|
105
|
+
|
|
94
106
|
## 実装内容
|
|
95
107
|
|
|
96
108
|
1. versionディレクトリを作成: `versions/v[XX]-to-v[YY]/`
|
|
@@ -193,27 +205,159 @@ smarthr-ui v[YY]のリリースノート: [GitHubリリースページのURL]
|
|
|
193
205
|
- JSDocコメントを適切に追加してください
|
|
194
206
|
- ディレクトリ名は必ず `vXX-to-vYY` 形式にしてください(内部キーと統一)
|
|
195
207
|
|
|
208
|
+
## 複数バージョンスキップ時の考慮事項
|
|
209
|
+
|
|
210
|
+
複数のバージョンをスキップする移行(例: v90→v93)では、コンポーネント名の衝突が発生する可能性があります。
|
|
211
|
+
|
|
212
|
+
### 問題が起こるケース
|
|
213
|
+
|
|
214
|
+
**例: v90→v92の一気実行**
|
|
215
|
+
|
|
216
|
+
v90→v91とv91→v92の両方が実行されると、以下のような衝突が発生します:
|
|
217
|
+
|
|
218
|
+
```javascript
|
|
219
|
+
// 元のコード
|
|
220
|
+
import { ActionDialog, RemoteTriggerActionDialog } from 'smarthr-ui'
|
|
221
|
+
|
|
222
|
+
// 1回目の自動修正(v90→v91 + v91→v92が同時に適用)
|
|
223
|
+
import { ControlledActionDialog, ActionDialog } from 'smarthr-ui'
|
|
224
|
+
|
|
225
|
+
// ESLintは自動的に再実行される(staged fixes)
|
|
226
|
+
// 2回目の自動修正で、上記のActionDialogがさらに変換される
|
|
227
|
+
import { ControlledActionDialog, ControlledActionDialog } from 'smarthr-ui'
|
|
228
|
+
// ❌ 重複!RemoteTriggerActionDialogの情報が失われる
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**原因:**
|
|
232
|
+
- v90→v91: `ActionDialog` → `ControlledActionDialog`
|
|
233
|
+
- v91→v92: `RemoteTriggerActionDialog` → `ActionDialog`
|
|
234
|
+
- ESLintのstaged fixesにより、2回目の自動修正で新しく生成された`ActionDialog`がさらに`ControlledActionDialog`に変換されてしまう
|
|
235
|
+
|
|
236
|
+
### 衝突検出の実装
|
|
237
|
+
|
|
238
|
+
このような衝突が予想される場合、`getMigrationPath()`関数で検出し、実行を禁止します。
|
|
239
|
+
|
|
240
|
+
**実装例(index.js):**
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
function getMigrationPath(from, to) {
|
|
244
|
+
// ... 既存のロジック ...
|
|
245
|
+
|
|
246
|
+
// コンポーネント名衝突の検出
|
|
247
|
+
if (path.includes('v90-v91') && path.includes('v91-v92')) {
|
|
248
|
+
return {
|
|
249
|
+
path,
|
|
250
|
+
skipped,
|
|
251
|
+
conflict: true,
|
|
252
|
+
conflictData: {
|
|
253
|
+
from,
|
|
254
|
+
to,
|
|
255
|
+
middle: '91',
|
|
256
|
+
},
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return { path, skipped }
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**エラーメッセージ(messages):**
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
messages: {
|
|
268
|
+
conflictingMigration: 'v{{from}}→v{{to}}の一気実行はコンポーネント名の衝突により正しく動作しません。段階的に実行してください: 1. { "from": "{{from}}", "to": "{{middle}}" } を実行 2. { "from": "{{middle}}", "to": "{{to}}" } を実行',
|
|
269
|
+
// ...
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**create()での使用:**
|
|
274
|
+
|
|
275
|
+
```javascript
|
|
276
|
+
create(context) {
|
|
277
|
+
// ... オプションチェック ...
|
|
278
|
+
|
|
279
|
+
const migrationResult = getMigrationPath(from, to)
|
|
280
|
+
|
|
281
|
+
// 衝突検出
|
|
282
|
+
if (migrationResult.conflict) {
|
|
283
|
+
return {
|
|
284
|
+
Program(node) {
|
|
285
|
+
context.report({
|
|
286
|
+
node,
|
|
287
|
+
messageId: 'conflictingMigration',
|
|
288
|
+
data: migrationResult.conflictData,
|
|
289
|
+
})
|
|
290
|
+
},
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ... 通常の処理 ...
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 新バージョン追加時のチェック項目
|
|
299
|
+
|
|
300
|
+
新しいバージョンを追加する際は、以下を確認してください:
|
|
301
|
+
|
|
302
|
+
1. **過去のバージョンとの衝突可能性を確認**
|
|
303
|
+
- 今回リネームするコンポーネント名が、過去のバージョンでリネーム**元**だった名前と一致しないか
|
|
304
|
+
- 例: v90で`ActionDialog`→`ControlledActionDialog`、v92で`RemoteTriggerActionDialog`→`ActionDialog`の場合、`ActionDialog`という名前が衝突
|
|
305
|
+
|
|
306
|
+
2. **衝突が発見された場合**
|
|
307
|
+
- `getMigrationPath()`に衝突検出ロジックを追加
|
|
308
|
+
- `conflictingMigration`メッセージで段階的な実行を促す
|
|
309
|
+
|
|
310
|
+
3. **テストケースを追加**
|
|
311
|
+
- 衝突するバージョン組み合わせでエラーが表示されることを確認
|
|
312
|
+
```javascript
|
|
313
|
+
{
|
|
314
|
+
code: `import { ActionDialog } from 'smarthr-ui'`,
|
|
315
|
+
options: [{ from: '90', to: '92' }],
|
|
316
|
+
errors: [{ messageId: 'conflictingMigration', data: { from: '90', to: '92', middle: '91' } }],
|
|
317
|
+
},
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### 参考実装
|
|
321
|
+
|
|
322
|
+
- [v91→v92追加時のコミット](https://github.com/kufu/tamatebako/commit/dc29036): v90→v92衝突検出の実装例
|
|
323
|
+
|
|
196
324
|
## 共通機能:smarthrUiAlias オプション
|
|
197
325
|
|
|
198
326
|
プロジェクト固有のsmarthr-ui aliasパスに対応するため、`smarthrUiAlias`オプションが利用可能です。
|
|
199
327
|
|
|
328
|
+
### 共通ヘルパー関数の使用
|
|
329
|
+
|
|
330
|
+
`helpers.js` に共通のヘルパー関数が用意されています。これにより、各versionファイルで重複コードを書く必要がありません。
|
|
331
|
+
|
|
332
|
+
**利用可能なヘルパー:**
|
|
333
|
+
- `setupSmarthrUiAliasOptions(context, options)`: validSources拡張とaliasファイル判定を一括で行う
|
|
334
|
+
- `isFileMatchingSmarthrUiAlias(filename, smarthrUiAlias)`: ファイルパスマッチング(低レベル、通常は不要)
|
|
335
|
+
|
|
200
336
|
### createCheckers関数でのオプション利用
|
|
201
337
|
|
|
202
338
|
```javascript
|
|
339
|
+
const { setupSmarthrUiAliasOptions } = require('../../helpers')
|
|
340
|
+
|
|
203
341
|
createCheckers(context, sourceCode, options = {}) {
|
|
204
|
-
|
|
205
|
-
const validSources =
|
|
206
|
-
|
|
207
|
-
|
|
342
|
+
// 1行でセットアップ完了
|
|
343
|
+
const { validSources, isAliasFile, filename } = setupSmarthrUiAliasOptions(context, options)
|
|
344
|
+
|
|
345
|
+
// validSourcesを使ってimportをチェック
|
|
346
|
+
const checkers = {
|
|
347
|
+
ImportDeclaration(node) {
|
|
348
|
+
if (!validSources.includes(node.source.value)) return
|
|
349
|
+
// ...
|
|
350
|
+
},
|
|
208
351
|
}
|
|
209
352
|
|
|
210
|
-
// alias
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
353
|
+
// aliasファイルの場合のみ、export変数名の置換を追加
|
|
354
|
+
if (isAliasFile) {
|
|
355
|
+
checkers['ExportNamedDeclaration > VariableDeclaration > VariableDeclarator'] = function(node) {
|
|
356
|
+
// ...
|
|
357
|
+
}
|
|
358
|
+
}
|
|
215
359
|
|
|
216
|
-
|
|
360
|
+
return checkers
|
|
217
361
|
}
|
|
218
362
|
```
|
|
219
363
|
|
|
@@ -224,18 +368,39 @@ createCheckers(context, sourceCode, options = {}) {
|
|
|
224
368
|
|
|
225
369
|
詳細は[README.md](./README.md#smarthr-ui-の-alias-を使用している場合)を参照。
|
|
226
370
|
|
|
227
|
-
###
|
|
371
|
+
### ✅ 共通化済みの機能
|
|
372
|
+
|
|
373
|
+
以下の機能は `helpers.js` に共通化されています(v92移行ルール追加時に実装):
|
|
374
|
+
|
|
375
|
+
- `setupSmarthrUiAliasOptions`: validSources拡張とaliasファイル判定
|
|
376
|
+
- `isFileMatchingSmarthrUiAlias`: ファイルパスマッチング
|
|
377
|
+
|
|
378
|
+
これにより、各versionファイルで約30行の重複コードが削減されました。
|
|
379
|
+
|
|
380
|
+
### 🔄 将来的な共通化の検討事項
|
|
381
|
+
|
|
382
|
+
**現状(v92時点):**
|
|
383
|
+
各versionディレクトリで以下のパターンが繰り返されています:
|
|
384
|
+
- ImportDeclarationチェッカー(コンポーネント名リネーム)
|
|
385
|
+
- ExportNamedDeclarationチェッカー(re-export対応)
|
|
386
|
+
- JSXOpeningElementチェッカー(JSX要素のリネーム)
|
|
387
|
+
- Programチェッカー(aliasファイル名変更エラー)
|
|
388
|
+
- VariableDeclaratorチェッカー(aliasファイル内のexport変数名置換)
|
|
389
|
+
|
|
390
|
+
**共通化の可能性:**
|
|
391
|
+
これらのチェッカーは構造が似ていますが、以下の理由で現時点では見送っています:
|
|
228
392
|
|
|
229
|
-
|
|
393
|
+
1. **読みやすさ優先の方針**: このルールは「一時的な使用」を想定し、読みやすさを重視
|
|
394
|
+
2. **version特有のロジック**: 各versionで微妙に異なる処理が必要になる可能性
|
|
395
|
+
3. **パターンの確立**: v93, v94... と増えて明確なパターンが確立されてから検討すべき
|
|
230
396
|
|
|
231
|
-
|
|
232
|
-
-
|
|
233
|
-
-
|
|
234
|
-
-
|
|
397
|
+
**再検討のタイミング:**
|
|
398
|
+
- v93, v94などが追加され、パターンが安定した時点
|
|
399
|
+
- チェッカー生成ヘルパー(`createComponentRenameCheckers`など)の実装を検討
|
|
400
|
+
- その際は `helpers.js` に追加し、REFERENCE.mdに「共通パターン」として記載
|
|
235
401
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
- 各versionモジュールで共通の基底関数を提供
|
|
402
|
+
**注意:**
|
|
403
|
+
共通化を進める際は、抽象化しすぎて読みにくくならないよう注意してください。ヘルパー関数のパラメータが複雑になる場合は、重複を許容する方が保守性が高い場合もあります。
|
|
239
404
|
|
|
240
405
|
## 完了後の作業
|
|
241
406
|
|
|
@@ -413,7 +578,7 @@ https://github.com/kufu/smarthr-ui/releases
|
|
|
413
578
|
|
|
414
579
|
各versionディレクトリに`REFERENCE.md`があり、実装パターンや注意点が記載されています。
|
|
415
580
|
|
|
416
|
-
**最新version:** [
|
|
581
|
+
**最新version:** [v91-to-v92/REFERENCE.md](./versions/v91-to-v92/REFERENCE.md)
|
|
417
582
|
|
|
418
583
|
このドキュメントには以下が含まれます:
|
|
419
584
|
- ファイル構造と各セクションの説明
|
|
@@ -192,6 +192,7 @@ export const ActionDialog = (props) => <div>{props.children}</div>
|
|
|
192
192
|
| バージョン | 詳細 |
|
|
193
193
|
|-----------|------|
|
|
194
194
|
| `90` → `91` | [移行ガイド](./versions/v90-to-v91/README.md) |
|
|
195
|
+
| `91` → `92` | [移行ガイド](./versions/v91-to-v92/README.md) |
|
|
195
196
|
|
|
196
197
|
## 使用方法
|
|
197
198
|
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* autofixer-smarthr-ui-migration 専用のヘルパー関数
|
|
3
|
+
*
|
|
4
|
+
* このファイルは複数のバージョン間で共通して使用されるヘルパー関数を提供します。
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { rootPath } = require('../../libs/common')
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* smarthrUiAliasで指定されたパスと現在のファイルパスがマッチするか判定
|
|
11
|
+
*
|
|
12
|
+
* @param {string} filename - 現在処理中のファイルパス
|
|
13
|
+
* @param {string} smarthrUiAlias - smarthrUiAliasオプションの値(例: '@/components/parts/smarthr-ui')
|
|
14
|
+
* @returns {boolean} マッチする場合true
|
|
15
|
+
*/
|
|
16
|
+
function isFileMatchingSmarthrUiAlias(filename, smarthrUiAlias) {
|
|
17
|
+
// rootPathを使って絶対パスで比較を試みる
|
|
18
|
+
const resolved = smarthrUiAlias.replace(/^@\//, `${rootPath}/`)
|
|
19
|
+
if (filename.includes(resolved)) {
|
|
20
|
+
return true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// rootPathでマッチしない場合:
|
|
24
|
+
// パスの一部としてマッチング(テスト環境などで使用)
|
|
25
|
+
// 例: '@/components/parts/smarthr-ui' -> 'components/parts/smarthr-ui'
|
|
26
|
+
const pathPart = smarthrUiAlias.replace(/^@\//, '').replace(/^~\//, '')
|
|
27
|
+
|
|
28
|
+
// 以下のパターンにマッチング:
|
|
29
|
+
// 1. ディレクトリ形式: /components/parts/smarthr-ui/index.tsx
|
|
30
|
+
// 2. 個別ファイル: /components/parts/smarthr-ui/ActionDialog.tsx
|
|
31
|
+
// 3. 単一ファイル形式: /components/parts/smarthr-ui.tsx
|
|
32
|
+
return (
|
|
33
|
+
filename.includes(`/${pathPart}/`) ||
|
|
34
|
+
filename.endsWith(`/${pathPart}`) ||
|
|
35
|
+
filename.includes(`/${pathPart}.`)
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* smarthrUiAliasオプションのセットアップ
|
|
41
|
+
*
|
|
42
|
+
* validSourcesの拡張とaliasファイル判定を行います。
|
|
43
|
+
*
|
|
44
|
+
* @param {Object} context - ESLintのcontext
|
|
45
|
+
* @param {Object} options - ルールオプション({ smarthrUiAlias?: string })
|
|
46
|
+
* @returns {{ validSources: string[], isAliasFile: boolean, filename: string }}
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* const { validSources, isAliasFile, filename } = setupSmarthrUiAliasOptions(context, options)
|
|
50
|
+
*
|
|
51
|
+
* // ImportDeclarationで使用
|
|
52
|
+
* if (!validSources.includes(node.source.value)) return
|
|
53
|
+
*
|
|
54
|
+
* // aliasファイル内のexport変数名置換で使用
|
|
55
|
+
* if (isAliasFile) {
|
|
56
|
+
* // aliasファイル専用の処理
|
|
57
|
+
* }
|
|
58
|
+
*/
|
|
59
|
+
function setupSmarthrUiAliasOptions(context, options) {
|
|
60
|
+
const customSmarthrUiAlias = options.smarthrUiAlias
|
|
61
|
+
const validSources = ['smarthr-ui']
|
|
62
|
+
if (customSmarthrUiAlias) {
|
|
63
|
+
validSources.push(customSmarthrUiAlias)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const filename = context.getFilename()
|
|
67
|
+
const isAliasFile = customSmarthrUiAlias && isFileMatchingSmarthrUiAlias(
|
|
68
|
+
filename,
|
|
69
|
+
customSmarthrUiAlias
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return { validSources, isAliasFile, filename }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
isFileMatchingSmarthrUiAlias,
|
|
77
|
+
setupSmarthrUiAliasOptions,
|
|
78
|
+
}
|
|
@@ -16,10 +16,12 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
const v90ToV91 = require('./versions/v90-to-v91/index')
|
|
19
|
+
const v91ToV92 = require('./versions/v91-to-v92/index')
|
|
19
20
|
|
|
20
21
|
// サポートしているバージョン間の移行モジュール
|
|
21
22
|
const VERSION_MODULES = {
|
|
22
23
|
'v90-v91': v90ToV91,
|
|
24
|
+
'v91-v92': v91ToV92,
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
module.exports = {
|
|
@@ -49,8 +51,10 @@ module.exports = {
|
|
|
49
51
|
messages: {
|
|
50
52
|
missingOptions: 'オプションで from と to を指定してください。例: { "from": "90", "to": "91" }',
|
|
51
53
|
unsupportedVersion: 'サポートされていないバージョンです: {{from}} to {{to}}',
|
|
54
|
+
conflictingMigration: 'v{{from}}→v{{to}}の一気実行はコンポーネント名の衝突により正しく動作しません。段階的に実行してください: 1. { "from": "{{from}}", "to": "{{middle}}" } を実行 2. { "from": "{{middle}}", "to": "{{to}}" } を実行',
|
|
52
55
|
skippedVersion: 'v{{version}} の自動修正ルールが実装されていません。変更内容は https://github.com/kufu/smarthr-ui/releases から対応するversionの情報を確認してください',
|
|
53
56
|
...v90ToV91.messages,
|
|
57
|
+
...v91ToV92.messages,
|
|
54
58
|
},
|
|
55
59
|
},
|
|
56
60
|
create(context) {
|
|
@@ -87,6 +91,19 @@ module.exports = {
|
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
// コンポーネント名衝突の検出
|
|
95
|
+
if (migrationResult.conflict) {
|
|
96
|
+
return {
|
|
97
|
+
Program(node) {
|
|
98
|
+
context.report({
|
|
99
|
+
node,
|
|
100
|
+
messageId: 'conflictingMigration',
|
|
101
|
+
data: migrationResult.conflictData,
|
|
102
|
+
})
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
90
107
|
const { path, skipped } = migrationResult
|
|
91
108
|
|
|
92
109
|
// 各ステップのチェッカーを収集してマージ
|
|
@@ -113,16 +130,21 @@ module.exports = {
|
|
|
113
130
|
*
|
|
114
131
|
* @param {string} from - 移行元バージョン(例: "90")
|
|
115
132
|
* @param {string} to - 移行先バージョン(例: "91")
|
|
116
|
-
* @returns {{ path: string[], skipped: number[] } | null} 移行パス情報、または無効な場合はnull
|
|
133
|
+
* @returns {{ path: string[], skipped: number[], conflict?: boolean, conflictData?: object } | null} 移行パス情報、または無効な場合はnull
|
|
117
134
|
*
|
|
118
135
|
* @example
|
|
119
136
|
* getMigrationPath('90', '91')
|
|
120
|
-
* // => { path: ['
|
|
137
|
+
* // => { path: ['v90-v91'], skipped: [] }
|
|
121
138
|
*
|
|
122
139
|
* @example
|
|
123
140
|
* getMigrationPath('90', '93')
|
|
124
141
|
* // 92のモジュールがない場合
|
|
125
|
-
* // => { path: ['
|
|
142
|
+
* // => { path: ['v90-v91'], skipped: [92, 93] }
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* getMigrationPath('90', '92')
|
|
146
|
+
* // v90-v91とv91-v92の組み合わせは衝突
|
|
147
|
+
* // => { path: ['v90-v91', 'v91-v92'], skipped: [], conflict: true, conflictData: {...} }
|
|
126
148
|
*/
|
|
127
149
|
function getMigrationPath(from, to) {
|
|
128
150
|
const fromNum = parseInt(from)
|
|
@@ -153,6 +175,22 @@ function getMigrationPath(from, to) {
|
|
|
153
175
|
return null
|
|
154
176
|
}
|
|
155
177
|
|
|
178
|
+
// コンポーネント名衝突の検出
|
|
179
|
+
// v90→v91とv91→v92の両方が含まれる場合、ActionDialogの名前が衝突する
|
|
180
|
+
// (v90のActionDialog→ControlledActionDialog、v90のRemoteTriggerActionDialog→ActionDialog)
|
|
181
|
+
if (path.includes('v90-v91') && path.includes('v91-v92')) {
|
|
182
|
+
return {
|
|
183
|
+
path,
|
|
184
|
+
skipped,
|
|
185
|
+
conflict: true,
|
|
186
|
+
conflictData: {
|
|
187
|
+
from,
|
|
188
|
+
to,
|
|
189
|
+
middle: '91',
|
|
190
|
+
},
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
156
194
|
return { path, skipped }
|
|
157
195
|
}
|
|
158
196
|
|
|
@@ -15,11 +15,13 @@ v91 では Dialog 系コンポーネントが Controlled プレフィックス
|
|
|
15
15
|
import { ActionDialog, FormDialog } from 'smarthr-ui'
|
|
16
16
|
<ActionDialog>...</ActionDialog>
|
|
17
17
|
<FormDialog>...</FormDialog>
|
|
18
|
+
type Props = ComponentProps<typeof ActionDialog>
|
|
18
19
|
|
|
19
20
|
// Correct(自動修正)
|
|
20
21
|
import { ControlledActionDialog, ControlledFormDialog } from 'smarthr-ui'
|
|
21
22
|
<ControlledActionDialog>...</ControlledActionDialog>
|
|
22
23
|
<ControlledFormDialog>...</ControlledFormDialog>
|
|
24
|
+
type Props = ComponentProps<typeof ControlledActionDialog>
|
|
23
25
|
```
|
|
24
26
|
|
|
25
27
|
**対応コンポーネント:**
|
|
@@ -28,6 +30,12 @@ import { ControlledActionDialog, ControlledFormDialog } from 'smarthr-ui'
|
|
|
28
30
|
- `MessageDialog` → `ControlledMessageDialog`
|
|
29
31
|
- `StepFormDialog` → `ControlledStepFormDialog`
|
|
30
32
|
|
|
33
|
+
**自動修正される箇所:**
|
|
34
|
+
- import文
|
|
35
|
+
- JSX要素(開始タグ・終了タグ)
|
|
36
|
+
- export文(re-export)
|
|
37
|
+
- typeof型参照(`typeof ActionDialog` など)
|
|
38
|
+
|
|
31
39
|
### 2. ResponseMessage の `type` → `status` リネーム
|
|
32
40
|
|
|
33
41
|
```tsx
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* 参考: https://github.com/kufu/smarthr-ui/releases/tag/smarthr-ui-v91.0.0
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
const {
|
|
16
|
+
const { setupSmarthrUiAliasOptions } = require('../../helpers')
|
|
17
17
|
|
|
18
18
|
// ============================================================
|
|
19
19
|
// 定数定義
|
|
@@ -57,18 +57,7 @@ module.exports = {
|
|
|
57
57
|
},
|
|
58
58
|
|
|
59
59
|
createCheckers(context, sourceCode, options = {}) {
|
|
60
|
-
const
|
|
61
|
-
const validSources = ['smarthr-ui']
|
|
62
|
-
if (customSmarthrUiAlias) {
|
|
63
|
-
validSources.push(customSmarthrUiAlias)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// 現在のファイルがaliasファイルか判定
|
|
67
|
-
const filename = context.getFilename()
|
|
68
|
-
const isAliasFile = customSmarthrUiAlias && isFileMatchingSmarthrUiAlias(
|
|
69
|
-
filename,
|
|
70
|
-
customSmarthrUiAlias
|
|
71
|
-
)
|
|
60
|
+
const { validSources, isAliasFile, filename } = setupSmarthrUiAliasOptions(context, options)
|
|
72
61
|
|
|
73
62
|
const checkers = {
|
|
74
63
|
// ============================================================
|
|
@@ -192,6 +181,24 @@ module.exports = {
|
|
|
192
181
|
}
|
|
193
182
|
},
|
|
194
183
|
|
|
184
|
+
// typeof型参照での検出と修正
|
|
185
|
+
// 例: typeof ActionDialog → typeof ControlledActionDialog
|
|
186
|
+
'TSTypeQuery > Identifier'(node) {
|
|
187
|
+
const componentName = node.name
|
|
188
|
+
const newName = DIALOG_COMPONENTS[componentName]
|
|
189
|
+
|
|
190
|
+
if (newName) {
|
|
191
|
+
context.report({
|
|
192
|
+
node,
|
|
193
|
+
messageId: 'renameDialog',
|
|
194
|
+
data: { old: componentName, new: newName, to: TARGET_VERSION },
|
|
195
|
+
fix(fixer) {
|
|
196
|
+
return fixer.replaceText(node, newName)
|
|
197
|
+
},
|
|
198
|
+
})
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
|
|
195
202
|
// ============================================================
|
|
196
203
|
// 2, 3, 4. ResponseMessageの属性変更
|
|
197
204
|
// ============================================================
|
|
@@ -576,32 +583,3 @@ module.exports = {
|
|
|
576
583
|
},
|
|
577
584
|
}
|
|
578
585
|
|
|
579
|
-
/**
|
|
580
|
-
* smarthrUiAliasで指定されたパスと現在のファイルパスがマッチするか判定
|
|
581
|
-
*
|
|
582
|
-
* @param {string} filename - 現在処理中のファイルパス
|
|
583
|
-
* @param {string} smarthrUiAlias - smarthrUiAliasオプションの値(例: '@/components/parts/smarthr-ui')
|
|
584
|
-
* @returns {boolean} マッチする場合true
|
|
585
|
-
*/
|
|
586
|
-
function isFileMatchingSmarthrUiAlias(filename, smarthrUiAlias) {
|
|
587
|
-
// rootPathを使って絶対パスで比較を試みる
|
|
588
|
-
const resolved = smarthrUiAlias.replace(/^@\//, `${rootPath}/`)
|
|
589
|
-
if (filename.includes(resolved)) {
|
|
590
|
-
return true
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// rootPathでマッチしない場合:
|
|
594
|
-
// パスの一部としてマッチング(テスト環境などで使用)
|
|
595
|
-
// 例: '@/components/parts/smarthr-ui' -> 'components/parts/smarthr-ui'
|
|
596
|
-
const pathPart = smarthrUiAlias.replace(/^@\//, '').replace(/^~\//, '')
|
|
597
|
-
|
|
598
|
-
// 以下のパターンにマッチング:
|
|
599
|
-
// 1. ディレクトリ形式: /components/parts/smarthr-ui/index.tsx
|
|
600
|
-
// 2. 個別ファイル: /components/parts/smarthr-ui/ActionDialog.tsx
|
|
601
|
-
// 3. 単一ファイル形式: /components/parts/smarthr-ui.tsx
|
|
602
|
-
return (
|
|
603
|
-
filename.includes(`/${pathPart}/`) ||
|
|
604
|
-
filename.endsWith(`/${pathPart}`) ||
|
|
605
|
-
filename.includes(`/${pathPart}.`)
|
|
606
|
-
)
|
|
607
|
-
}
|
|
@@ -119,6 +119,41 @@ module.exports = {
|
|
|
119
119
|
errors: [{ messageId: 'renameDialog', data: { old: 'ActionDialog', new: 'ControlledActionDialog', to: 'v91' } }],
|
|
120
120
|
},
|
|
121
121
|
|
|
122
|
+
// typeof型参照
|
|
123
|
+
{
|
|
124
|
+
code: `import { ActionDialog } from 'smarthr-ui'
|
|
125
|
+
type Props = ComponentProps<typeof ActionDialog>`,
|
|
126
|
+
output: `import { ControlledActionDialog } from 'smarthr-ui'
|
|
127
|
+
type Props = ComponentProps<typeof ControlledActionDialog>`,
|
|
128
|
+
options: v90ToV91Options,
|
|
129
|
+
languageOptions: {
|
|
130
|
+
parser: require('typescript-eslint').parser,
|
|
131
|
+
},
|
|
132
|
+
errors: [
|
|
133
|
+
{ messageId: 'renameDialog', data: { old: 'ActionDialog', new: 'ControlledActionDialog', to: 'v91' } },
|
|
134
|
+
{ messageId: 'renameDialog', data: { old: 'ActionDialog', new: 'ControlledActionDialog', to: 'v91' } },
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
// 複数のtypeof型参照
|
|
139
|
+
{
|
|
140
|
+
code: `import { FormDialog } from 'smarthr-ui'
|
|
141
|
+
type RefType = ElementRef<typeof FormDialog>
|
|
142
|
+
const handleAction: ComponentPropsWithoutRef<typeof FormDialog>['onClickClose'] = () => {}`,
|
|
143
|
+
output: `import { ControlledFormDialog } from 'smarthr-ui'
|
|
144
|
+
type RefType = ElementRef<typeof ControlledFormDialog>
|
|
145
|
+
const handleAction: ComponentPropsWithoutRef<typeof ControlledFormDialog>['onClickClose'] = () => {}`,
|
|
146
|
+
options: v90ToV91Options,
|
|
147
|
+
languageOptions: {
|
|
148
|
+
parser: require('typescript-eslint').parser,
|
|
149
|
+
},
|
|
150
|
+
errors: [
|
|
151
|
+
{ messageId: 'renameDialog', data: { old: 'FormDialog', new: 'ControlledFormDialog', to: 'v91' } },
|
|
152
|
+
{ messageId: 'renameDialog', data: { old: 'FormDialog', new: 'ControlledFormDialog', to: 'v91' } },
|
|
153
|
+
{ messageId: 'renameDialog', data: { old: 'FormDialog', new: 'ControlledFormDialog', to: 'v91' } },
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
|
|
122
157
|
// ============================================================
|
|
123
158
|
// 2. ResponseMessageのtype→status
|
|
124
159
|
// ============================================================
|