feat(config-converter): JSON Schema 検証パネルに Cmd/Ctrl+Enter ショートカットを追加 - #148
Conversation
Deploying devtools with
|
| Latest commit: |
66fedb8
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://88fac5de.devtools-d9w.pages.dev |
| Branch Preview URL: | https://feat-137-config-converter-sc.devtools-d9w.pages.dev |
レビュー概要JSON Schema 検証パネルのスキーマ textarea にフォーカスした状態で 良い点
指摘事項🔴 必須(Must)特になし。機能・規約遵守ともに合格水準。 🟡 推奨(Should)1. IME 変換確定 Enter での誤発火リスク 日本語 IME で変換確定のために Enter を押した瞬間 onKeyDown={(e) => {
if (e.nativeEvent.isComposing) return;
if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {
if (!output || !schemaText || isValidating) return;
e.preventDefault();
handleValidate();
}
}}スキーマ JSON は通常コピペ前提で日本語入力する場面はほぼないため、本 PR スコープ外として別 issue 化( 2. ヒントテキストとボタンの関連付け(アクセシビリティ)
ヒント span は装飾的なので 3. プラットフォーム判定によるヒント表記の最適化(軽微) ヒントテキストが常に 🟢 提案(Nit)1. ハンドラのインライン化と useCallback 化 現状 2. ヒント span のセマンティクス
<kbd style={{ ...caption, color: colors.muted, fontFamily: 'monospace' }}>
Cmd/Ctrl+Enter
</kbd>スタイルポリシーには反しないため、見た目を整える方向の改善案としてご検討ください。 3. E2E テストの待機方法
await expect(page.getByLabel('JSON', { exact: true })).toHaveValue(/"name"/);テスト
総合的に、規約遵守・実装の正確さ・テストカバレッジともに必要水準を満たしており、必須の修正項目はありません。Should 項目(特に IME ガードと aria-keyshortcuts)は次回以降のブラッシュアップ対象として検討してください。 |
|
Should 1〜2 および Nit 2〜3 を対応しました(コミット
Should 3(プラットフォーム別ヒント表記)は Issue #137 のスコープ外かつ SSR hydration の考慮が必要なため今回は見送りました。 |
再レビュー結果最新差分(+57 / -0)と該当コミット 前回指摘事項の対応状況🟡 推奨
🟢 提案
追加の指摘確認した範囲では新規問題なし。 補足として小さな観察のみ:
前回挙げた E2E カバレッジの未補填項目(disabled 条件下 / 修飾なし Enter)は本 PR では追加されていないが、Issue #137 の AC 範囲外であり、スコープ判断として妥当。必要なら別 issue 化が 総評前回の 🟡 推奨 3 件のうち実質対応すべき 2 件(IME・aria-keyshortcuts)が両方対応済み、🟢 提案 3 件のうち採用された 2 件(kbd・E2E 統一)も実装品質が水準を満たしている。残りの見送り項目(Mac/Win 出し分け・useCallback)も判断として合理的。 マージ可能と判断します。 追加対応は不要です。 |
JSON Schema 検証 textarea にフォーカスした状態で Cmd+Enter (Mac) / Ctrl+Enter (Win/Linux) を押すと検証が実行されるよう onKeyDown ハンドラを追加。 InputField に optional な onKeyDown prop を追加して forward する形で実装。 ボタン横に "Cmd/Ctrl+Enter" のヒントテキストも表示。 Closes #137
beforeEach が既に /tools/config-converter へ遷移済みのため、
新規テスト内の page.goto('/') と waitForReactHydration を削除。
- onKeyDown に isComposing ガードを追加(IME 誤発火防止) - 検証ボタンに aria-keyshortcuts 属性を追加 - ヒントテキストに aria-hidden="true" を追加 - ヒント span を kbd 要素に変更(キーボード入力のセマンティクス) - E2E テストの waitForFunction を expect().toHaveValue() に置換
c2b36be to
66fedb8
Compare
* docs: Cloudflare Web Analytics 導入を却下した決定を [051] として記録
プロジェクトの「外部送信ゼロ・外部リソースゼロ・トラッキングなし」方針と
Cloudflare Web Analytics(beacon 自動注入)が直接矛盾するため、有効化しない判断とした。
その経緯と却下理由を decisions.md に [051] として追記する。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs: [051] サーバー側集計ログに関する誤記を修正
Cloudflare Pages のトラフィック集計は Web Analytics を有効化しないと
表示されない。beacon なしで見られるという誤った記述を削除し、
正確に「把握する手段が無い」と修正する。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: dev server / Playwright をサンドボックス除外コマンドに追加
`.claude/settings.json` のサンドボックスは listen() を拒否するため、
`npm run dev` / `npm run test:e2e` 経由の Astro dev server が
EPERM で起動できなかった。`excludedCommands` に dev / preview /
e2e / playwright / astro 系コマンドを追加し、ローカル listen を
必要とするコマンドだけサンドボックス外で実行できるようにする。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: .claude/worktrees/ を gitignore に追加
Claude Code の worktrees ディレクトリは既に `.worktrees/` を ignore
しているが、Agent Teams 機能で生成される `.claude/worktrees/` が
別パスのため取り残されていた。誤コミット防止のため追加する。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(tools): QRリーダーツールを新設(qr-reader)
カメラまたは画像ファイルからQRコードを読み取り、テキストを表示するツールを追加。
- `src/utils/qr-reader.ts`: URL/テキスト判別純粋関数 `detectQrContent()`
- `src/components/tools/QrReader.tsx`: カメラ+画像アップロード対応コンポーネント
- `src/pages/tools/qr-reader.astro`: Astro ページラッパー
- `src/data/tools.ts`: `qr-reader` エントリ追加(category: convert)
- ユニットテスト 15件(URL/テキスト判別の境界値を網羅)
- E2E テスト(.claude/settings.json 修正後に実行予定)
- SPEC.md / README.md / docs/decisions.md 更新
HTTP/HTTPS URL のみ検出してフィッシング警告付きリンクを表示。
javascript: 等の危険スキームは text として扱い自動リンク化しない([051])。
既存の useQrCamera フック・jsQR ライブラリを再利用して実装量を最小化。
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test(e2e): qr-reader の Playwright strict mode 違反を修正
- 'カメラ' ボタンの locator に exact: true を追加('カメラを起動' との多重マッチを解消)
- 'example.com' テキストの locator に exact: true を追加(URL 全体を含む <pre> との多重マッチを解消)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(qr-reader): コピーボタンと再スキャンボタンの高さ・スタイルを統一
- rescanButtonStyle を CopyButton と同じ視覚パラメータに合わせる
(lineHeight 1 / padding 0.5rem 0.75rem / borderRadius 0.25rem / fontWeight 700)
- 両ボタンを flex flex-wrap items-center gap-2 でラップし
横並びレイアウトを明示的に制御
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(qr-reader): ToolIcon.astro に qr-reader SVGアイコンを追加
QRの3つのファインダーパターン + データモジュール2点 + 水平スキャン線で構成。
qr-code(データモジュール4点)と造形を共有しつつ、スキャン線で「読取」を表現。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(qr-reader): レビュー指摘を修正(必須2件 + 推奨5件)
必須対応:
- canvas.getContext('2d') の non-null assertion を削除し、null 時に
エラーメッセージを表示するガードを追加(iOS Safari OOM 対策)
- 長辺 1600px 超の画像を jsQR 前にダウンスケールし、高解像度
スマホ写真での OOM・フリーズを防止
推奨対応:
- input[type=file] を display:none から visually-hidden に変更し
キーボード・スクリーンリーダーから操作可能にする(A11y)
- モード切替時に decoded / decodeError / cameraError をクリアし
古い結果との並存を防止
- useEffect 依存配列の参照を const { stopCamera } = camera で
分割代入し、exhaustive-deps 警告を回避
- E2E: not.toBeVisible() → toHaveCount(0) に変更(DOM から
削除されることの検証+auto-retry の安定化)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(qr-reader): e.target.value クリアの意図コメントを追加
同名ファイルの再選択を可能にするパターンであることを明示し、
onload 完了前にクリアする理由(File は file 変数で参照済み)を説明。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: 設定ファイル相互変換ツール (config-converter) を追加 (#133)
* feat: config-converter ユーティリティ層とユニットテストを実装
JSON/YAML/TOML/dotenv の相互変換・整形ユーティリティと
JSON Schema バリデーション(ajv draft-04/7対応)を追加。
TDD でテストを先行作成し、全 224 テストがパスすることを確認済み。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: config-converter 依存パッケージ追加とユーティリティ層の品質改善
- yaml, smol-toml, ajv, ajv-formats を package.json に明示追加
- toml.ts: stringifyToml に入力型ガードを追加
- dotenv.ts: quoteValue ヘルパで " を含む値のエスケープを修正
- yaml.ts: formatYaml にエラーハンドリングを追加
- schema-validator.ts: 非オブジェクトスキーマの入力ガードを追加
- テスト追加: schema-validator.test.ts 新規作成 (4件)、toml/dotenv テスト追加
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: ConfigConverter React コンポーネントを実装
From/To ToggleGroup・InputField/OutputField・警告バナー・
JSON Schema 検証パネル(dynamic import)・DownloadButton を含む
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: config-converter をツール一覧・Astro ページ・アイコンに追加
- src/data/tools.ts に Tool エントリ追加 (category: convert)
- src/pages/tools/config-converter.astro を作成
- src/components/ui/ToolIcon.astro に {} アイコンを追加
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* test(e2e): config-converter の E2E テストを追加
6ケース: YAML→JSON変換、JSON→YAML変換、ネスト拒否エラー、
クリア動作、JSON Schema 検証成功・失敗
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: config-converter のドキュメントを更新
- README.md: 変換・解析テーブルに設定ファイル相互変換を追加
- SPEC.md: ライブラリテーブル・ツール一覧・ディレクトリ構成・実装チェックリストを更新
- docs/decisions.md: [051] yaml/smol-toml/ajv 選定理由・HCL後送り判断を記録
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: develop の変更をマージ(Cloudflare Analytics 決定 [051]、.gitignore 更新)
- docs/decisions.md: develop で追加された [051] Cloudflare Web Analytics 却下エントリを挿入し、
当ブランチの config-converter ライブラリ選定エントリを [052] に繰り下げ
- .gitignore: develop で追加された `.claude/worktrees/` 除外ルールを追加
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(e2e): strict mode violation を修正(exact: true、パス文字列を使用)
- getByLabel('JSON') → getByLabel('JSON', { exact: true }): from=to=JSON 時に
入力ラベル「JSON (整形)」と出力ラベル「JSON」の2要素にマッチする問題を解消
- getByRole('button', { name: '検証する' }) → { exact: true }: 「▶ JSON Schema で検証する」
ボタンにも部分マッチしていた問題を解消
- getByText(/age/) → getByText('/age'): 正規表現がテキストエリア内の "age" を含む
全要素にマッチしていた問題を解消(パスは "/age" とスラッシュ付きなので区別可能)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: レビュー指摘対応(Critical 1-3、推奨 4-5-7、提案 10)
[Critical 1] ajv-draft-04 を dependencies に明示登録
- package.json に "ajv-draft-04": "^1.0.0" を追加
- dev tree の transitive dep に依存していたためクリーンインストール時にビルド失敗の恐れがあった
- docs/decisions.md [052] にも理由を追記
[Critical 2] handleValidate: convert() の .output を参照していなかったバグを修正
- data = convert(output, to, 'json') → data = JSON.parse(convert(output, to, 'json').output)
- to=yaml/toml/dotenv 時にスキーマ検証対象が ConvertResult オブジェクトになっていた
- to=yaml でスキーマ検証が動作することを確認する E2E テストを追加
[Critical 3] .env パーサーがインラインコメントを無視していた問題を修正
- KEY=value # comment → value として取り込むよう \s+# パターンで除去
- クォート内の # は除去しない("value # not a comment" → そのまま保持)
[推奨 4] convert() の二重呼び出しを解消
- useRef<string[]> で warnings をキャプチャし、別 useEffect での再 convert() を廃止
[推奨 5] E2E テストの waitForTimeout(500) を削除
- expect(...).toBeVisible() の auto-retry に委ねる(7件全パス確認)
[推奨 7] formatLabel ヘルパー関数を削除
- FORMAT_LABELS[f] を直接参照するよう変更
[提案 10] ajv 起因の英語エラーメッセージを日本語に統一
- 日本語文字を含まないエラーメッセージは "JSON Schema の解析に失敗しました" で上書き
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: 再レビュー指摘対応(推奨 A・B・C、提案 D)
[推奨 A] parseDotenv インラインコメントのユニットテスト追加
- クォートなし値の # 除去、クォート内保持、URL フラグメント保持、
クォート付き値+末尾コメントの 5 ケースを dotenv.test.ts に追加
- tests: 231 → 236 件
[推奨 B] クォート付き値 + 末尾コメント混在ケースを修正
- KEY="hello" # comment → "hello"(クォート残存)だったバグを修正
- 正規表現で /^"((?:[^"\\]|\\.)*)"\\s*(?:#.*)?$/ により
クォート内容抽出と末尾コメント除去を一括処理
- ループ変数 raw とのシャドウイングを避けるため内部変数を rawValue に改名
[推奨 C] package.json dependencies をアルファベット順に整列
- ajv / ajv-draft-04 / ajv-formats / smol-toml を正しい位置に移動
- lockfile との整合性も改善
[提案 D] フォーマット切替時に validationResult をクリア
- handleFromChange / handleToChange に setValidationResult(null) を追加
- 切替後の出力に対して古い検証結果が残る誤認を防止
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(config-converter): 出力変更時に validationResult をクリアする
入力を編集して output が変わっても古いスキーマ検証結果(成功/失敗)が
残り続ける問題を修正。output/error を監視する既存 useEffect に
setValidationResult(null) を追加し、出力変化と同時に検証結果を無効化する。
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore: サブエージェントが PR レビューコメントを投稿できる権限を追加 (#142)
サブエージェントには対話 UI が無いため、未承認の tool 呼び出しは即拒否される。
PR レビュー作業を並列化する際にレビュー本文の投稿および TMPDIR への一時ファイル
書き出しが拒否されていた問題を解消する。
- Bash(gh pr review*) / Bash(gh pr comment*) を allow に追加
- PR メタデータを変更する gh pr edit/create/merge/close は ask に残置
- Write(/tmp/claude*/**) / Write(/private/tmp/claude*/**) を allow に追加
- サンドボックス TMPDIR 配下への一時ファイル書き出しを許可
* docs: PR ベースは必ず develop と CLAUDE.md 最重要ルールに昇格 (#143)
`docs/shared-agent-rules.md §6.3` に既に明記されているが、Claude Code の
system prompt が毎セッション "Main branch (you will usually use this for PRs): main"
と表示してくるため、shared-agent-rules.md を読まずに main 向け PR を作る事故が
繰り返し発生していた。
CLAUDE.md は毎セッション読み込まれるため、最重要ルールの 1 行に昇格させて
即時可視化する。
* fix(qr-reader): 非HTTPS環境で専用エラーメッセージを表示 (#135)
navigator.mediaDevices が undefined の場合に getUserMedia を呼ぶと
TypeError となり「カメラの起動に失敗しました」という汎用メッセージ
が出て原因が特定できなかった。startCamera 冒頭で早期 guard を入れ、
HTTPS または localhost が必要である旨を明示する。
* fix(config-converter): parseDotenv でエスケープシーケンスを解除 (#140)
stringifyDotenv は値の \\ と \" をエスケープして書き出すが、
parseDotenv 側でアンエスケープしておらず、ラウンドトリップが
壊れていた。
unescapeDotenv ヘルパーを追加し、DQ/SQ ブランチで適用。単発走査で
クォート種・バックスラッシュのみアンエスケープするため、
\\\" のような連鎖でも順序問題なく安全に解除できる。
テスト 5 件追加(DQ 内 \"・\\・連鎖、SQ 内 \'、ラウンドトリップ)。
* test(qr-reader): HTTPS 必須メッセージの E2E テストを追加 (#135)
レビュー指摘(feedback_e2e_tests)対応。Playwright の addInitScript で
navigator.mediaDevices を undefined にし、カメラ起動時に新しいエラー
メッセージが表示されることを検証する E2E ケースを追加。
* docs(decisions): .env パーサに expand オプション追加余地を明記
レビューでの指摘を受け、ダブルクォート内のエスケープ方針と
将来 `expand` オプション(POSIX dotenv 相当の `\n` 改行展開)を
追加できる旨を 052 章 .env セクションに 1 行追記。
* docs(rules): 先送り時の issue 化を 6.4 章として追加
「別 PR で対応」「後で追記」と口頭で先送りすると形骸化して
実施されないことがレビューで指摘されたため、共通規約に
「先送り時は必ず issue を起票し PR に番号を貼る」ルールを追加。
* test(qr-reader): HTTPS guard テストの再ナビゲート意図をコメント明記
レビュー任意指摘 (#144) を受け、beforeEach で goto 済みでも
addInitScript は次回ロードから反映されるため再 goto が必要、
という意図を 1 行コメントで補足。挙動変更なし。
* ci: developブランチへのプッシュ時もカバレッジバッジを更新する (#146)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(config-converter): 変換先フォーマット変更時に入力テキストを保持する (#147)
* fix(config-converter): 変換先変更時に入力テキストを保持する
変換先のみ変更した場合、handleToChange から reset() の呼び出しを削除し
入力テキストを保持したまま出力のみ再計算するよう修正。
変換元変更時(handleFromChange)は従来どおり入力をクリアする。
Closes #141
* test(config-converter): E2E テストのナビゲーションパターンを修正
beforeEach が既に /tools/config-converter へ遷移済みのため、
新規テスト内の page.goto('/') と waitForReactHydration を削除。
* test(config-converter): E2E テストのロケータとアサーションをプロジェクト規約に準拠させる
- waitForFunction + querySelectorAll を expect().toHaveValue() に置換
- locator('textarea[readonly]') を getByLabel() に置換
- toContainText を toHaveValue に置換(textarea は value を検証する必要があるため)
docs/ui-conventions.md 3.2 章のロケータ規約に準拠。
* feat(config-converter): JSON Schema 検証パネルに Cmd/Ctrl+Enter ショートカットを追加 (#148)
スキーマ textarea に Cmd+Enter (Mac) / Ctrl+Enter (Win/Linux) で検証を実行するショートカットを追加。InputField に optional な onKeyDown prop を追加して forward する形で実装。isComposing ガード・aria-keyshortcuts・kbd 要素によるアクセシビリティ対応も含む。
Closes #137
* ci: カバレッジバッジ更新を Gist 経由に変更 (#151)
ブランチ保護ルールにより github-actions[bot] からの develop / main への
直接 push が拒否されるため、外部 Gist に JSON を書き込み shields.io の
endpoint バッジで表示する方式に切り替える。
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
* docs: Cloudflare Web Analytics 導入を却下した決定を [051] として記録
プロジェクトの「外部送信ゼロ・外部リソースゼロ・トラッキングなし」方針と
Cloudflare Web Analytics(beacon 自動注入)が直接矛盾するため、有効化しない判断とした。
その経緯と却下理由を decisions.md に [051] として追記する。
* docs: [051] サーバー側集計ログに関する誤記を修正
Cloudflare Pages のトラフィック集計は Web Analytics を有効化しないと
表示されない。beacon なしで見られるという誤った記述を削除し、
正確に「把握する手段が無い」と修正する。
* chore: dev server / Playwright をサンドボックス除外コマンドに追加
`.claude/settings.json` のサンドボックスは listen() を拒否するため、
`npm run dev` / `npm run test:e2e` 経由の Astro dev server が
EPERM で起動できなかった。`excludedCommands` に dev / preview /
e2e / playwright / astro 系コマンドを追加し、ローカル listen を
必要とするコマンドだけサンドボックス外で実行できるようにする。
* chore: .claude/worktrees/ を gitignore に追加
Claude Code の worktrees ディレクトリは既に `.worktrees/` を ignore
しているが、Agent Teams 機能で生成される `.claude/worktrees/` が
別パスのため取り残されていた。誤コミット防止のため追加する。
* feat(tools): QRリーダーツールを新設(qr-reader)
カメラまたは画像ファイルからQRコードを読み取り、テキストを表示するツールを追加。
- `src/utils/qr-reader.ts`: URL/テキスト判別純粋関数 `detectQrContent()`
- `src/components/tools/QrReader.tsx`: カメラ+画像アップロード対応コンポーネント
- `src/pages/tools/qr-reader.astro`: Astro ページラッパー
- `src/data/tools.ts`: `qr-reader` エントリ追加(category: convert)
- ユニットテスト 15件(URL/テキスト判別の境界値を網羅)
- E2E テスト(.claude/settings.json 修正後に実行予定)
- SPEC.md / README.md / docs/decisions.md 更新
HTTP/HTTPS URL のみ検出してフィッシング警告付きリンクを表示。
javascript: 等の危険スキームは text として扱い自動リンク化しない([051])。
既存の useQrCamera フック・jsQR ライブラリを再利用して実装量を最小化。
* test(e2e): qr-reader の Playwright strict mode 違反を修正
- 'カメラ' ボタンの locator に exact: true を追加('カメラを起動' との多重マッチを解消)
- 'example.com' テキストの locator に exact: true を追加(URL 全体を含む <pre> との多重マッチを解消)
* fix(qr-reader): コピーボタンと再スキャンボタンの高さ・スタイルを統一
- rescanButtonStyle を CopyButton と同じ視覚パラメータに合わせる
(lineHeight 1 / padding 0.5rem 0.75rem / borderRadius 0.25rem / fontWeight 700)
- 両ボタンを flex flex-wrap items-center gap-2 でラップし
横並びレイアウトを明示的に制御
* feat(qr-reader): ToolIcon.astro に qr-reader SVGアイコンを追加
QRの3つのファインダーパターン + データモジュール2点 + 水平スキャン線で構成。
qr-code(データモジュール4点)と造形を共有しつつ、スキャン線で「読取」を表現。
* fix(qr-reader): レビュー指摘を修正(必須2件 + 推奨5件)
必須対応:
- canvas.getContext('2d') の non-null assertion を削除し、null 時に
エラーメッセージを表示するガードを追加(iOS Safari OOM 対策)
- 長辺 1600px 超の画像を jsQR 前にダウンスケールし、高解像度
スマホ写真での OOM・フリーズを防止
推奨対応:
- input[type=file] を display:none から visually-hidden に変更し
キーボード・スクリーンリーダーから操作可能にする(A11y)
- モード切替時に decoded / decodeError / cameraError をクリアし
古い結果との並存を防止
- useEffect 依存配列の参照を const { stopCamera } = camera で
分割代入し、exhaustive-deps 警告を回避
- E2E: not.toBeVisible() → toHaveCount(0) に変更(DOM から
削除されることの検証+auto-retry の安定化)
* docs(qr-reader): e.target.value クリアの意図コメントを追加
同名ファイルの再選択を可能にするパターンであることを明示し、
onload 完了前にクリアする理由(File は file 変数で参照済み)を説明。
* feat: 設定ファイル相互変換ツール (config-converter) を追加 (#133)
* feat: config-converter ユーティリティ層とユニットテストを実装
JSON/YAML/TOML/dotenv の相互変換・整形ユーティリティと
JSON Schema バリデーション(ajv draft-04/7対応)を追加。
TDD でテストを先行作成し、全 224 テストがパスすることを確認済み。
* feat: config-converter 依存パッケージ追加とユーティリティ層の品質改善
- yaml, smol-toml, ajv, ajv-formats を package.json に明示追加
- toml.ts: stringifyToml に入力型ガードを追加
- dotenv.ts: quoteValue ヘルパで " を含む値のエスケープを修正
- yaml.ts: formatYaml にエラーハンドリングを追加
- schema-validator.ts: 非オブジェクトスキーマの入力ガードを追加
- テスト追加: schema-validator.test.ts 新規作成 (4件)、toml/dotenv テスト追加
* feat: ConfigConverter React コンポーネントを実装
From/To ToggleGroup・InputField/OutputField・警告バナー・
JSON Schema 検証パネル(dynamic import)・DownloadButton を含む
* feat: config-converter をツール一覧・Astro ページ・アイコンに追加
- src/data/tools.ts に Tool エントリ追加 (category: convert)
- src/pages/tools/config-converter.astro を作成
- src/components/ui/ToolIcon.astro に {} アイコンを追加
* test(e2e): config-converter の E2E テストを追加
6ケース: YAML→JSON変換、JSON→YAML変換、ネスト拒否エラー、
クリア動作、JSON Schema 検証成功・失敗
* docs: config-converter のドキュメントを更新
- README.md: 変換・解析テーブルに設定ファイル相互変換を追加
- SPEC.md: ライブラリテーブル・ツール一覧・ディレクトリ構成・実装チェックリストを更新
- docs/decisions.md: [051] yaml/smol-toml/ajv 選定理由・HCL後送り判断を記録
* chore: develop の変更をマージ(Cloudflare Analytics 決定 [051]、.gitignore 更新)
- docs/decisions.md: develop で追加された [051] Cloudflare Web Analytics 却下エントリを挿入し、
当ブランチの config-converter ライブラリ選定エントリを [052] に繰り下げ
- .gitignore: develop で追加された `.claude/worktrees/` 除外ルールを追加
* fix(e2e): strict mode violation を修正(exact: true、パス文字列を使用)
- getByLabel('JSON') → getByLabel('JSON', { exact: true }): from=to=JSON 時に
入力ラベル「JSON (整形)」と出力ラベル「JSON」の2要素にマッチする問題を解消
- getByRole('button', { name: '検証する' }) → { exact: true }: 「▶ JSON Schema で検証する」
ボタンにも部分マッチしていた問題を解消
- getByText(/age/) → getByText('/age'): 正規表現がテキストエリア内の "age" を含む
全要素にマッチしていた問題を解消(パスは "/age" とスラッシュ付きなので区別可能)
* fix: レビュー指摘対応(Critical 1-3、推奨 4-5-7、提案 10)
[Critical 1] ajv-draft-04 を dependencies に明示登録
- package.json に "ajv-draft-04": "^1.0.0" を追加
- dev tree の transitive dep に依存していたためクリーンインストール時にビルド失敗の恐れがあった
- docs/decisions.md [052] にも理由を追記
[Critical 2] handleValidate: convert() の .output を参照していなかったバグを修正
- data = convert(output, to, 'json') → data = JSON.parse(convert(output, to, 'json').output)
- to=yaml/toml/dotenv 時にスキーマ検証対象が ConvertResult オブジェクトになっていた
- to=yaml でスキーマ検証が動作することを確認する E2E テストを追加
[Critical 3] .env パーサーがインラインコメントを無視していた問題を修正
- KEY=value # comment → value として取り込むよう \s+# パターンで除去
- クォート内の # は除去しない("value # not a comment" → そのまま保持)
[推奨 4] convert() の二重呼び出しを解消
- useRef<string[]> で warnings をキャプチャし、別 useEffect での再 convert() を廃止
[推奨 5] E2E テストの waitForTimeout(500) を削除
- expect(...).toBeVisible() の auto-retry に委ねる(7件全パス確認)
[推奨 7] formatLabel ヘルパー関数を削除
- FORMAT_LABELS[f] を直接参照するよう変更
[提案 10] ajv 起因の英語エラーメッセージを日本語に統一
- 日本語文字を含まないエラーメッセージは "JSON Schema の解析に失敗しました" で上書き
* fix: 再レビュー指摘対応(推奨 A・B・C、提案 D)
[推奨 A] parseDotenv インラインコメントのユニットテスト追加
- クォートなし値の # 除去、クォート内保持、URL フラグメント保持、
クォート付き値+末尾コメントの 5 ケースを dotenv.test.ts に追加
- tests: 231 → 236 件
[推奨 B] クォート付き値 + 末尾コメント混在ケースを修正
- KEY="hello" # comment → "hello"(クォート残存)だったバグを修正
- 正規表現で /^"((?:[^"\\]|\\.)*)"\\s*(?:#.*)?$/ により
クォート内容抽出と末尾コメント除去を一括処理
- ループ変数 raw とのシャドウイングを避けるため内部変数を rawValue に改名
[推奨 C] package.json dependencies をアルファベット順に整列
- ajv / ajv-draft-04 / ajv-formats / smol-toml を正しい位置に移動
- lockfile との整合性も改善
[提案 D] フォーマット切替時に validationResult をクリア
- handleFromChange / handleToChange に setValidationResult(null) を追加
- 切替後の出力に対して古い検証結果が残る誤認を防止
* fix(config-converter): 出力変更時に validationResult をクリアする
入力を編集して output が変わっても古いスキーマ検証結果(成功/失敗)が
残り続ける問題を修正。output/error を監視する既存 useEffect に
setValidationResult(null) を追加し、出力変化と同時に検証結果を無効化する。
---------
* chore: サブエージェントが PR レビューコメントを投稿できる権限を追加 (#142)
サブエージェントには対話 UI が無いため、未承認の tool 呼び出しは即拒否される。
PR レビュー作業を並列化する際にレビュー本文の投稿および TMPDIR への一時ファイル
書き出しが拒否されていた問題を解消する。
- Bash(gh pr review*) / Bash(gh pr comment*) を allow に追加
- PR メタデータを変更する gh pr edit/create/merge/close は ask に残置
- Write(/tmp/claude*/**) / Write(/private/tmp/claude*/**) を allow に追加
- サンドボックス TMPDIR 配下への一時ファイル書き出しを許可
* docs: PR ベースは必ず develop と CLAUDE.md 最重要ルールに昇格 (#143)
`docs/shared-agent-rules.md §6.3` に既に明記されているが、Claude Code の
system prompt が毎セッション "Main branch (you will usually use this for PRs): main"
と表示してくるため、shared-agent-rules.md を読まずに main 向け PR を作る事故が
繰り返し発生していた。
CLAUDE.md は毎セッション読み込まれるため、最重要ルールの 1 行に昇格させて
即時可視化する。
* fix(qr-reader): 非HTTPS環境で専用エラーメッセージを表示 (#135)
navigator.mediaDevices が undefined の場合に getUserMedia を呼ぶと
TypeError となり「カメラの起動に失敗しました」という汎用メッセージ
が出て原因が特定できなかった。startCamera 冒頭で早期 guard を入れ、
HTTPS または localhost が必要である旨を明示する。
* fix(config-converter): parseDotenv でエスケープシーケンスを解除 (#140)
stringifyDotenv は値の \\ と \" をエスケープして書き出すが、
parseDotenv 側でアンエスケープしておらず、ラウンドトリップが
壊れていた。
unescapeDotenv ヘルパーを追加し、DQ/SQ ブランチで適用。単発走査で
クォート種・バックスラッシュのみアンエスケープするため、
\\\" のような連鎖でも順序問題なく安全に解除できる。
テスト 5 件追加(DQ 内 \"・\\・連鎖、SQ 内 \'、ラウンドトリップ)。
* test(qr-reader): HTTPS 必須メッセージの E2E テストを追加 (#135)
レビュー指摘(feedback_e2e_tests)対応。Playwright の addInitScript で
navigator.mediaDevices を undefined にし、カメラ起動時に新しいエラー
メッセージが表示されることを検証する E2E ケースを追加。
* docs(decisions): .env パーサに expand オプション追加余地を明記
レビューでの指摘を受け、ダブルクォート内のエスケープ方針と
将来 `expand` オプション(POSIX dotenv 相当の `\n` 改行展開)を
追加できる旨を 052 章 .env セクションに 1 行追記。
* docs(rules): 先送り時の issue 化を 6.4 章として追加
「別 PR で対応」「後で追記」と口頭で先送りすると形骸化して
実施されないことがレビューで指摘されたため、共通規約に
「先送り時は必ず issue を起票し PR に番号を貼る」ルールを追加。
* test(qr-reader): HTTPS guard テストの再ナビゲート意図をコメント明記
レビュー任意指摘 (#144) を受け、beforeEach で goto 済みでも
addInitScript は次回ロードから反映されるため再 goto が必要、
という意図を 1 行コメントで補足。挙動変更なし。
* ci: developブランチへのプッシュ時もカバレッジバッジを更新する (#146)
* fix(config-converter): 変換先フォーマット変更時に入力テキストを保持する (#147)
* fix(config-converter): 変換先変更時に入力テキストを保持する
変換先のみ変更した場合、handleToChange から reset() の呼び出しを削除し
入力テキストを保持したまま出力のみ再計算するよう修正。
変換元変更時(handleFromChange)は従来どおり入力をクリアする。
Closes #141
* test(config-converter): E2E テストのナビゲーションパターンを修正
beforeEach が既に /tools/config-converter へ遷移済みのため、
新規テスト内の page.goto('/') と waitForReactHydration を削除。
* test(config-converter): E2E テストのロケータとアサーションをプロジェクト規約に準拠させる
- waitForFunction + querySelectorAll を expect().toHaveValue() に置換
- locator('textarea[readonly]') を getByLabel() に置換
- toContainText を toHaveValue に置換(textarea は value を検証する必要があるため)
docs/ui-conventions.md 3.2 章のロケータ規約に準拠。
* feat(config-converter): JSON Schema 検証パネルに Cmd/Ctrl+Enter ショートカットを追加 (#148)
スキーマ textarea に Cmd+Enter (Mac) / Ctrl+Enter (Win/Linux) で検証を実行するショートカットを追加。InputField に optional な onKeyDown prop を追加して forward する形で実装。isComposing ガード・aria-keyshortcuts・kbd 要素によるアクセシビリティ対応も含む。
Closes #137
* ci: カバレッジバッジ更新を Gist 経由に変更 (#151)
ブランチ保護ルールにより github-actions[bot] からの develop / main への
直接 push が拒否されるため、外部 Gist に JSON を書き込み shields.io の
endpoint バッジで表示する方式に切り替える。
---------
Co-authored-by: takasefumiyuki <71715982+fumtas1k@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
概要
JSON Schema 検証パネルのスキーマ textarea にフォーカスした状態で Cmd+Enter(Mac)/ Ctrl+Enter(Windows/Linux)を押すと検証が実行されるキーボードショートカットを追加します。
変更内容
src/components/ui/InputField.tsxonKeyDownprop を追加し、<textarea>/<input>両方に forwardsrc/components/tools/ConfigConverter.tsxInputFieldにonKeyDownハンドラを追加disabled条件(!output || !schemaText || isValidating)と完全に一致させてショートカットのガードを実装caption+colors.mutedを使用)テスト
npm run test: 256 件 passnpm run test:e2e: 127 件 pass(1 skipped)Meta+Enter/Control+Enterを送信し、スキーマ検証成功メッセージが表示されることを確認Closes #137