refactor(store): teach the selector cache Set/Map emptiness instead of an option

This commit is contained in:
Jinwoo-H
2026-09-17 17:14:16 -04:00
parent 535c1ba679
commit bd2fd8215e
2 changed files with 10 additions and 5 deletions
@@ -5,7 +5,7 @@ import { createWorktreeRecordSelector } from '@/store/worktree-record-selector-c
const EMPTY_TAB_IDS: ReadonlySet<string> = new Set()
export type SleepingRecordParkExemptionState = {
type SleepingRecordParkExemptionState = {
sleepingAgentSessionsByPaneKey?: Record<string, SleepingAgentSessionRecord> | undefined
}
@@ -28,7 +28,6 @@ export const selectSleepingRecordParkExemptTabIds = createWorktreeRecordSelector
>({
readSources: (state) => [state.sleepingAgentSessionsByPaneKey],
empty: EMPTY_TAB_IDS,
isEmpty: (tabIds) => tabIds.size === 0,
build: (state, worktreeId) => {
const sleepingAgentSessionsByPaneKey = state.sleepingAgentSessionsByPaneKey
if (!sleepingAgentSessionsByPaneKey) {
@@ -6,6 +6,14 @@ type WorktreeRecordGeneration<TValue> = {
byWorktreeId: Map<string, TValue>
}
/** Why not `Object.keys`: a `Set`/`Map` value has none, so the default check
* would collapse every non-empty one onto the shared empty identity. */
function isEmptyValue(value: object): boolean {
return value instanceof Set || value instanceof Map
? value.size === 0
: Object.keys(value).length === 0
}
function sameSources(previous: readonly unknown[], next: readonly unknown[]): boolean {
if (previous.length !== next.length) {
return false
@@ -34,8 +42,6 @@ export function createWorktreeRecordSelector<TState, TValue extends object>(opti
readSources: (state: TState) => readonly unknown[]
build: (state: TState, worktreeId: string) => TValue
empty: TValue
/** Override for values whose emptiness is not `Object.keys` — a Set, for instance. */
isEmpty?: (value: TValue) => boolean
}): (state: TState, worktreeId: string) => TValue {
let generation: WorktreeRecordGeneration<TValue> | null = null
return (state, worktreeId) => {
@@ -54,7 +60,7 @@ export function createWorktreeRecordSelector<TState, TValue extends object>(opti
const built = options.build(state, worktreeId)
const carried = generation.carried?.get(worktreeId)
let value = built
if (options.isEmpty ? options.isEmpty(built) : Object.keys(built).length === 0) {
if (isEmptyValue(built)) {
value = options.empty
} else if (carried && shallow(carried, built)) {
value = carried