Skip to content

refactor: settings/git-sync store の setter 集約 helper を src/lib/store-helpers.ts に共通化 #272

Description

@ymnao

背景

PR #260processMdFilesParallel (file-private helper) / PR #258getActiveTab (file-private helper) に続き、PR #271src/stores/settings.tsmakeSetter<K extends keyof SettingsValues> closure factory を導入した。

同 PR の /simplify 4 reviewer 並列 review で Reuse + Altitude の 2 reviewer が同一 mechanism を指摘:

  • src/stores/git-sync.ts:82-114同 shape の 7 setter (setGitSyncEnabled / setAutoCommitInterval / setAutoPullInterval / setAutoPushInterval / setPullBeforePush / setSyncMethod / setAutoPullOnStartup) が既に存在 → 2 箇所目確定
  • HANDOFF 49 ★「次 PR で 2 箇所目が発生したら helper 化」基準を満たす
  • 現状 makeSetterSettingsValues に固有 (create() 内 closure) → 共通化余地

PR #271 で見送った理由

  • user が明示採択した scope が「src/stores/settings.ts 1 file 内 setter 集約」で、git-sync.ts への横展開は本 scope 外
  • HANDOFF 52 ★「skip 判定は次 PR での解消策を明示」pattern に従い、shared helper 化を 本 issue で切り出し

Option A: src/lib/store-helpers.tsmakePersistedSetter<TValues, K> を hoist (推奨)

// src/lib/store-helpers.ts (新規)
export function makePersistedSetter<TValues, K extends keyof TValues>(
    set: (partial: Partial<TValues>) => void,
    key: K,
    save: (value: TValues[K]) => Promise<void>,
    normalize?: (value: TValues[K]) => TValues[K],
) {
    return (value: TValues[K]) => {
        const normalized = normalize ? normalize(value) : value;
        void save(normalized);
        set({ [key]: normalized } as Partial<TValues>);
    };
}

呼び出し側:

// src/stores/settings.ts
setShowLineNumbers: makePersistedSetter(set, "showLineNumbers", saveShowLineNumbers),
// ... 11 setter ...

// src/stores/git-sync.ts
setGitSyncEnabled: makePersistedSetter(set, "gitSyncEnabled", saveGitSyncEnabled),
// ... 7 setter ...
setCommitMessage: makePersistedSetter(set, "commitMessage", saveCommitMessage, (v) => v.trim() || DEFAULTS.commitMessage),

Option B: file-private closure を各 store で維持 (現状)

  • settings.ts と git-sync.ts に別々の makeSetter closure を配置
  • 重複するが scope 完全隔離

Option A 採用根拠 (PR #271 skip 判定の解消)

  1. HANDOFF 49 ★「次 PR で 2 箇所目が発生したら helper 化」基準成立 — settings.ts で 1 箇所目、git-sync.ts に 2 箇所目 existing → 2 箇所目確定時点で helper 化するのが judgment rule
  2. 削減効果: git-sync.ts で 7 setter × 2 行 = **-14 行**、settings.ts で +2 行 (import + factory 位置変更) 差し引き net -12 行程度
  3. generic factory で型安全TValues + K extends keyof TValues により settings/git-sync 両方の key/value 対応を静的保証
  4. setCommitMessage の normalize 統合 — Altitude reviewer が指摘: shared helper に normalize? optional transform を持たせれば、setCommitMessagenormalize → save → set shape も含めて全 setter を統一表現可能。将来 3 番目のストアで normalize 需要が出ても同 API で対応可能
  5. as Partial<SettingsState> cast を helper 内部に隔離 — TS computed-key widening の cast が呼び出し側に露出せず、helper 内部の 1 箇所で完結

対象ファイル

  • src/lib/store-helpers.ts (新規、~15 行)
  • src/stores/settings.ts (現 83 行 → 現状 closure 削除 + helper import + 呼び出し形変更、diff は ±3 行程度)
  • src/stores/git-sync.ts (setter 7 個を helper 呼び出しに置換、setCommitMessage は normalize callback で統合、~-14 行)
  • test 影響: src/stores/settings.test.ts (14 pass) と src/stores/git-sync.test.ts が外部 API 不変なので pass 継続想定

参考

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions