chore(lint): apply eslint auto-fixes across the .tsx backlog
Mechanical --fix output over the newly linted .tsx files (indent, arrow-parens, comma-dangle, member-delimiter-style, unnecessary type assertions), plus the three generic-arrow test hooks converted to function declarations up front: the comma-dangle fixer strips the <T,> disambiguation comma and turns them into parse errors otherwise.
This commit is contained in:
@@ -8,7 +8,7 @@ import type { HostObservable as ObservableSnapshot, SnapshotSelectorHook } from
|
||||
// Keep equality local: this suite asserts the eq parameter contract without
|
||||
// adding a reverse dependency from web-react to runtime.
|
||||
const shallowEqual = (a: Record<string, unknown>, b: Record<string, unknown>): boolean =>
|
||||
Object.keys(a).length === Object.keys(b).length && Object.keys(a).every((k) => Object.is(a[k], b[k]))
|
||||
Object.keys(a).length === Object.keys(b).length && Object.keys(a).every(k => Object.is(a[k], b[k]))
|
||||
|
||||
interface Snap { a: number; b: number }
|
||||
|
||||
@@ -51,7 +51,7 @@ describe('bindSnapshotSelector', () => {
|
||||
const { source, set } = makeSource({ a: 1, b: 10 })
|
||||
const useSelector = bindSnapshotSelector(source)
|
||||
const probe = { renders: 0, value: undefined as number | undefined }
|
||||
render(<Harness useSelector={useSelector} sel={(s) => s.a} probe={probe} />)
|
||||
render(<Harness useSelector={useSelector} sel={s => s.a} probe={probe} />)
|
||||
expect(probe.value).toBe(1)
|
||||
const before = probe.renders
|
||||
act(() => { set({ a: 1, b: 11 }) }) // unrelated field: Object.is bail
|
||||
@@ -65,7 +65,7 @@ describe('bindSnapshotSelector', () => {
|
||||
const { source, set } = makeSource({ a: 1, b: 10 })
|
||||
const useSelector = bindSnapshotSelector(source)
|
||||
const probe = { renders: 0, value: undefined as { a: number } | undefined }
|
||||
render(<Harness useSelector={useSelector} sel={(s) => ({ a: s.a })} eq={shallowEqual} probe={probe} />)
|
||||
render(<Harness useSelector={useSelector} sel={s => ({ a: s.a })} eq={shallowEqual} probe={probe} />)
|
||||
const before = probe.renders
|
||||
act(() => { set({ a: 1, b: 99 }) }) // fresh object, shallow-equal slice
|
||||
expect(probe.renders).toBe(before)
|
||||
@@ -78,11 +78,11 @@ describe('bindSnapshotSelector', () => {
|
||||
const { source, set, stats } = makeSource({ a: 1, b: 10 })
|
||||
const useSelector = bindSnapshotSelector(source)
|
||||
const probe = { renders: 0, value: undefined as number | undefined }
|
||||
const { rerender } = render(<Harness useSelector={useSelector} sel={(s) => s.a} probe={probe} />)
|
||||
const { rerender } = render(<Harness useSelector={useSelector} sel={s => s.a} probe={probe} />)
|
||||
const after = stats.subscribeCalls
|
||||
rerender(<Harness useSelector={useSelector} sel={(s) => s.a} probe={probe} />)
|
||||
rerender(<Harness useSelector={useSelector} sel={s => s.a} probe={probe} />)
|
||||
act(() => { set({ a: 2, b: 10 }) })
|
||||
rerender(<Harness useSelector={useSelector} sel={(s) => s.a} probe={probe} />)
|
||||
rerender(<Harness useSelector={useSelector} sel={s => s.a} probe={probe} />)
|
||||
expect(stats.subscribeCalls).toBe(after)
|
||||
})
|
||||
|
||||
@@ -92,7 +92,7 @@ describe('bindSnapshotSelector', () => {
|
||||
const probe = { renders: 0, value: undefined as number | undefined }
|
||||
const view = render(
|
||||
<StrictMode>
|
||||
<Harness useSelector={useSelector} sel={(s) => s.a} probe={probe} />
|
||||
<Harness useSelector={useSelector} sel={s => s.a} probe={probe} />
|
||||
</StrictMode>,
|
||||
)
|
||||
expect(probe.value).toBe(1)
|
||||
@@ -112,7 +112,7 @@ describe('bindSnapshotSelector', () => {
|
||||
}
|
||||
const useSelector = bindSnapshotSelector(new MethodSource())
|
||||
const probe = { renders: 0, value: undefined as number | undefined }
|
||||
render(<Harness useSelector={useSelector} sel={(s) => s.a} probe={probe} />)
|
||||
render(<Harness useSelector={useSelector} sel={s => s.a} probe={probe} />)
|
||||
expect(probe.value).toBe(7)
|
||||
})
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@ type FrameSlots = PropsRenderSlots<'spec.single' | 'spec.list'>
|
||||
function hostOver(core: SlotCore): SlotRendererHost {
|
||||
return {
|
||||
subscribe: (key, fn) => core.subscribe(key, fn),
|
||||
getVersion: (key) => core.getVersion(key),
|
||||
entriesOf: (key) => core.entries(key),
|
||||
specOf: (key) => core.specDynamic(key),
|
||||
isLive: (entry) => core.isLive(entry),
|
||||
getVersion: key => core.getVersion(key),
|
||||
entriesOf: key => core.entries(key),
|
||||
specOf: key => core.specDynamic(key),
|
||||
isLive: entry => core.isLive(entry),
|
||||
storeOf: () => undefined,
|
||||
sessions: {
|
||||
list: { getSnapshot: () => ({}), subscribe: () => () => {} },
|
||||
@@ -61,7 +61,7 @@ function mountFrame(core: SlotCore, body: (renderSlot: FrameSlots['renderSlot'])
|
||||
describe('createSlotRenderer over the real SlotCore', () => {
|
||||
it('renders registrations live through real microtask batching: register, dispose back to fallback', async () => {
|
||||
const core = new SlotCore()
|
||||
const { view } = mountFrame(core, (renderSlot) =>
|
||||
const { view } = mountFrame(core, renderSlot =>
|
||||
renderSlot('spec.single', {}, { fallback: <i>none</i> }))
|
||||
expect(view.container.textContent).toBe('none')
|
||||
let dispose = () => {}
|
||||
@@ -78,7 +78,7 @@ describe('createSlotRenderer over the real SlotCore', () => {
|
||||
const core = new SlotCore()
|
||||
const notified = vi.fn()
|
||||
core.subscribe('spec.list', notified)
|
||||
const { view } = mountFrame(core, (renderSlot) => renderSlot('spec.list', {}))
|
||||
const { view } = mountFrame(core, renderSlot => renderSlot('spec.list', {}))
|
||||
await act(async () => {
|
||||
core.register({ name: 'spec.list', id: 'two', order: 2 }, () => <span>2</span>)
|
||||
core.register({ name: 'spec.list', id: 'one', order: 1 }, () => <span>1</span>)
|
||||
|
||||
@@ -96,10 +96,10 @@ function makeHost() {
|
||||
subs.set(key, set)
|
||||
return () => { set.delete(fn) }
|
||||
},
|
||||
getVersion: (key) => versions.get(key) ?? 0,
|
||||
entriesOf: (key) => entries.get(key) ?? [],
|
||||
specOf: (key) => specs.get(key),
|
||||
isLive: (entry) => live.has(entry),
|
||||
getVersion: key => versions.get(key) ?? 0,
|
||||
entriesOf: key => entries.get(key) ?? [],
|
||||
specOf: key => specs.get(key),
|
||||
isLive: entry => live.has(entry),
|
||||
storeOf: (entry, scopeKey) => {
|
||||
if (entry.store === undefined) return undefined
|
||||
let perScope = storeCache.get(entry)
|
||||
@@ -121,8 +121,8 @@ function makeHost() {
|
||||
sessions: {
|
||||
list,
|
||||
current,
|
||||
provideInfo: (id) => infos.get(id),
|
||||
maybeProvideInfo: (id) => (id === undefined ? undefined : infos.get(id))
|
||||
provideInfo: id => infos.get(id),
|
||||
maybeProvideInfo: id => (id === undefined ? undefined : infos.get(id))
|
||||
?? { sessionId: undefined, hooks: {}, props: {} },
|
||||
},
|
||||
workspaces: { list: workspaces },
|
||||
@@ -145,7 +145,7 @@ function makeHost() {
|
||||
live.add(entry)
|
||||
bump(key)
|
||||
return () => {
|
||||
entries.set(key, (entries.get(key) ?? []).filter((e) => e !== entry))
|
||||
entries.set(key, (entries.get(key) ?? []).filter(e => e !== entry))
|
||||
live.delete(entry)
|
||||
bump(key)
|
||||
}
|
||||
@@ -187,7 +187,7 @@ const chainEntryOf = (partial: {
|
||||
priority?: number
|
||||
}): Omit<StoredEntry, 'options'> & { options?: StoredEntry['options'] } => ({
|
||||
component: partial.component,
|
||||
select: partial.select as StoredEntry['select'],
|
||||
select: partial.select,
|
||||
...(partial.priority !== undefined ? { options: { priority: partial.priority } } : {}),
|
||||
})
|
||||
|
||||
@@ -230,7 +230,7 @@ describe('child outlets and the renderSlot binding', () => {
|
||||
const h = makeHost()
|
||||
h.declare('k.single', SINGLE_ROOT)
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT },
|
||||
(renderSlot) => renderSlot('k.single', {}, { fallback: <i>none</i> }))
|
||||
renderSlot => renderSlot('k.single', {}, { fallback: <i>none</i> }))
|
||||
expect(view.container.textContent).toBe('none')
|
||||
let dispose = () => {}
|
||||
act(() => { dispose = h.add('k.single', { component: () => <b>SB</b> }) })
|
||||
@@ -242,7 +242,7 @@ describe('child outlets and the renderSlot binding', () => {
|
||||
it('renders an undeclared key as empty (declaring entry unloaded = natural blank, not a crash)', () => {
|
||||
const h = makeHost()
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT },
|
||||
(renderSlot) => <main>{renderSlot('k.single', {}, { fallback: <i>fb</i> })}</main>)
|
||||
renderSlot => <main>{renderSlot('k.single', {}, { fallback: <i>fb</i> })}</main>)
|
||||
// Declared by children (authorization) but absent from the ledger (specOf
|
||||
// undefined): the outlet renders nothing, not even the fallback path's spec dispatch.
|
||||
expect(view.container.querySelector('main')!.textContent).toBe('')
|
||||
@@ -256,7 +256,7 @@ describe('child outlets and the renderSlot binding', () => {
|
||||
h.add('k.list', { component: () => <span>a</span>, options: { id: 'a', order: 1 } })
|
||||
h.add('k.keyed', { component: () => <span>goal</span>, options: { key: 'goal' } })
|
||||
const children = { 'k.list': { kind: 'list', scope: 'root' } as DeclaredSpec, 'k.keyed': { kind: 'keyed', scope: 'root' } as DeclaredSpec }
|
||||
const { view } = mountRoot(h, children, (renderSlot) => <>
|
||||
const { view } = mountRoot(h, children, renderSlot => <>
|
||||
<main>{renderSlot('k.list', {})}</main>
|
||||
<aside>{renderSlot('k.list', {}, { only: 'b' })}</aside>
|
||||
<nav>{renderSlot('k.keyed', {}, { entryKey: 'goal' })}</nav>
|
||||
@@ -291,7 +291,7 @@ describe('child outlets and the renderSlot binding', () => {
|
||||
h.add('k.list', { component: () => <span>alive</span>, options: { id: 'ok', order: 2 } })
|
||||
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const { view } = mountRoot(h, { 'k.list': { kind: 'list', scope: 'root' } },
|
||||
(renderSlot) => renderSlot('k.list', {}))
|
||||
renderSlot => renderSlot('k.list', {}))
|
||||
spy.mockRestore()
|
||||
expect(view.container.textContent).toBe('alive')
|
||||
expect(view.container.querySelector('[data-slot-error]')).not.toBeNull()
|
||||
@@ -309,10 +309,10 @@ describe('chain outlets and the renderSlotChain binding', () => {
|
||||
}))
|
||||
h.add('k.chain', chainEntryOf({
|
||||
component: ({ matched }: { matched?: { label: string } }) => <b>{matched?.label}</b>,
|
||||
select: (owner) => ({ label: `hit:${(owner as { tag: string }).tag}` }),
|
||||
select: owner => ({ label: `hit:${(owner as { tag: string }).tag}` }),
|
||||
}))
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT },
|
||||
(renderSlotChain) => renderSlotChain('k.chain', { tag: 'T' }))
|
||||
renderSlotChain => renderSlotChain('k.chain', { tag: 'T' }))
|
||||
// The declining entry never mounts: the routing decision is select-layer only.
|
||||
expect(view.container.textContent).toBe('hit:T')
|
||||
expect(declinerBody).not.toHaveBeenCalled()
|
||||
@@ -327,10 +327,10 @@ describe('chain outlets and the renderSlotChain binding', () => {
|
||||
}))
|
||||
h.add('k.chain', chainEntryOf({
|
||||
component: ({ matched }: { matched?: string }) => <b>{matched}</b>,
|
||||
select: (owner) => (owner as { pick?: string }).pick ?? null,
|
||||
select: owner => (owner as { pick?: string }).pick ?? null,
|
||||
}))
|
||||
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT }, (renderSlotChain) => <>
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT }, renderSlotChain => <>
|
||||
<main>{renderSlotChain('k.chain', { pick: 'OK' })}</main>
|
||||
<aside>{renderSlotChain('k.chain', {}, { fallback: <i>fb</i> })}</aside>
|
||||
</>)
|
||||
@@ -347,16 +347,16 @@ describe('chain outlets and the renderSlotChain binding', () => {
|
||||
h.declare('k.chain', CHAIN_ROOT)
|
||||
h.add('k.chain', chainEntryOf({
|
||||
component: () => { throw new Error('entry A boom') },
|
||||
select: (owner) => (owner as { pick?: string }).pick === 'A' ? {} : null,
|
||||
select: owner => (owner as { pick?: string }).pick === 'A' ? {} : null,
|
||||
}))
|
||||
h.add('k.chain', chainEntryOf({
|
||||
component: () => <b>B-ok</b>,
|
||||
select: (owner) => (owner as { pick?: string }).pick === 'B' ? {} : null,
|
||||
select: owner => (owner as { pick?: string }).pick === 'B' ? {} : null,
|
||||
}))
|
||||
let pick = 'A'
|
||||
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT },
|
||||
(renderSlotChain) => renderSlotChain('k.chain', { pick }))
|
||||
renderSlotChain => renderSlotChain('k.chain', { pick }))
|
||||
spy.mockRestore()
|
||||
expect(view.container.querySelector('[data-slot-error]')).not.toBeNull()
|
||||
// Re-elect entry B: the entry-keyed boundary remounts fresh instead of
|
||||
@@ -372,9 +372,9 @@ describe('chain outlets and the renderSlotChain binding', () => {
|
||||
h.declare('k.chain', CHAIN_ROOT)
|
||||
h.add('k.chain', chainEntryOf({
|
||||
component: ({ matched }: { matched?: string }) => <b>{matched}</b>,
|
||||
select: (owner) => (owner as { pick?: string }).pick ?? null,
|
||||
select: owner => (owner as { pick?: string }).pick ?? null,
|
||||
}))
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT }, (renderSlotChain) => <>
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT }, renderSlotChain => <>
|
||||
<main>{renderSlotChain('k.chain', {}, { fallback: <i>bar</i> })}</main>
|
||||
<aside>{renderSlotChain('k.chain', { pick: 'P' }, { fallback: <i>bar</i> })}</aside>
|
||||
</>)
|
||||
@@ -387,7 +387,7 @@ describe('chain outlets and the renderSlotChain binding', () => {
|
||||
const h = makeHost()
|
||||
h.declare('k.chain', CHAIN_ROOT)
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT },
|
||||
(renderSlotChain) => renderSlotChain('k.chain', {}, { fallback: <i>none</i> }))
|
||||
renderSlotChain => renderSlotChain('k.chain', {}, { fallback: <i>none</i> }))
|
||||
expect(view.container.textContent).toBe('none')
|
||||
let dispose = () => {}
|
||||
act(() => {
|
||||
@@ -422,7 +422,7 @@ describe('chain outlets and the renderSlotChain binding', () => {
|
||||
priority: 1,
|
||||
}))
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT },
|
||||
(renderSlotChain) => renderSlotChain('k.chain', {}))
|
||||
renderSlotChain => renderSlotChain('k.chain', {}))
|
||||
expect(view.container.textContent).toBe('early')
|
||||
})
|
||||
|
||||
@@ -490,13 +490,13 @@ describe('overlay chains (ChainRenderOpts.overlay)', () => {
|
||||
h.declare('k.chain', CHAIN_ROOT)
|
||||
h.add('k.chain', chainEntryOf({
|
||||
component: () => <b>TAKEOVER</b>,
|
||||
select: (owner) => (owner as { take?: boolean }).take ? {} : null,
|
||||
select: owner => (owner as { take?: boolean }).take ? {} : null,
|
||||
}))
|
||||
const mounted = vi.fn()
|
||||
const Probe = fallbackProbe(mounted)
|
||||
let take = false
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT },
|
||||
(renderSlotChain) => renderSlotChain('k.chain', { take }, { fallback: <Probe />, overlay: true }))
|
||||
renderSlotChain => renderSlotChain('k.chain', { take }, { fallback: <Probe />, overlay: true }))
|
||||
const wrapper = () => view.container.querySelector<HTMLElement>('[data-chain-overlay-fallback="k.chain"]')!
|
||||
const input = () => view.container.querySelector<HTMLInputElement>('input[aria-label="probe"]')!
|
||||
|
||||
@@ -525,13 +525,13 @@ describe('overlay chains (ChainRenderOpts.overlay)', () => {
|
||||
h.declare('k.chain', CHAIN_ROOT)
|
||||
h.add('k.chain', chainEntryOf({
|
||||
component: () => <b>TAKEOVER</b>,
|
||||
select: (owner) => (owner as { take?: boolean }).take ? {} : null,
|
||||
select: owner => (owner as { take?: boolean }).take ? {} : null,
|
||||
}))
|
||||
const mounted = vi.fn()
|
||||
const Probe = fallbackProbe(mounted)
|
||||
let take = false
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT },
|
||||
(renderSlotChain) => renderSlotChain('k.chain', { take }, { fallback: <Probe /> }))
|
||||
renderSlotChain => renderSlotChain('k.chain', { take }, { fallback: <Probe /> }))
|
||||
fireEvent.change(view.container.querySelector('input[aria-label="probe"]')!, { target: { value: 'gone' } })
|
||||
expect(view.container.querySelector('[data-chain-overlay-fallback]')).toBeNull()
|
||||
|
||||
@@ -561,7 +561,7 @@ describe('overlay chains (ChainRenderOpts.overlay)', () => {
|
||||
priority: 2,
|
||||
}))
|
||||
const { view } = mountChainRoot(h, { 'k.chain': CHAIN_ROOT },
|
||||
(renderSlotChain) => renderSlotChain('k.chain', {}, { fallback: <i>resident</i>, overlay: true }))
|
||||
renderSlotChain => renderSlotChain('k.chain', {}, { fallback: <i>resident</i>, overlay: true }))
|
||||
expect(view.container.textContent).toContain('ELECTED')
|
||||
expect(spy.mock.calls.some(([msg]) => String(msg).includes('chain selector crashed'))).toBe(true)
|
||||
spy.mockRestore()
|
||||
@@ -578,9 +578,9 @@ describe('standard-kit synthesis', () => {
|
||||
h.declare('k.single', SINGLE_ROOT)
|
||||
h.add('k.single', {
|
||||
component: ({ useSessions }: { useSessions: <S>(sel: (s: { ids: string[] }) => S) => S }) =>
|
||||
<b>{useSessions((s) => s.ids.length)}</b>,
|
||||
<b>{useSessions(s => s.ids.length)}</b>,
|
||||
})
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT }, (renderSlot) => renderSlot('k.single', {}))
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT }, renderSlot => renderSlot('k.single', {}))
|
||||
expect(view.container.textContent).toBe('0')
|
||||
act(() => { h.list.set({ ids: ['a', 'b'] }) })
|
||||
expect(view.container.textContent).toBe('2')
|
||||
@@ -591,9 +591,9 @@ describe('standard-kit synthesis', () => {
|
||||
h.declare('k.single', SINGLE_ROOT)
|
||||
h.add('k.single', {
|
||||
component: ({ useWorkspaces }: { useWorkspaces: <S>(sel: (s: { ids: string[] }) => S) => S }) =>
|
||||
<b>{useWorkspaces((s) => s.ids.length)}</b>,
|
||||
<b>{useWorkspaces(s => s.ids.length)}</b>,
|
||||
})
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT }, (renderSlot) => renderSlot('k.single', {}))
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT }, renderSlot => renderSlot('k.single', {}))
|
||||
expect(view.container.textContent).toBe('0')
|
||||
act(() => { h.workspaces.set({ ids: ['w1'] }) })
|
||||
expect(view.container.textContent).toBe('1')
|
||||
@@ -606,11 +606,11 @@ describe('standard-kit synthesis', () => {
|
||||
const seen: AnyProps[] = []
|
||||
h.add('k.session', {
|
||||
component: (props: { useSession?: <S>(sel: (s: { sid: string }) => S) => S; sessionId?: string }) => {
|
||||
seen.push({ ...props, read: props.useSession!((s) => s.sid) })
|
||||
seen.push({ ...props, read: props.useSession!(s => s.sid) })
|
||||
return null
|
||||
},
|
||||
})
|
||||
mountRoot(h, { 'k.session': SINGLE_SESSION }, (renderSlot) => (
|
||||
mountRoot(h, { 'k.session': SINGLE_SESSION }, renderSlot => (
|
||||
<SessionProvider empty={() => <i>empty</i>}>
|
||||
{() => renderSlot('k.session', {})}
|
||||
</SessionProvider>
|
||||
@@ -669,14 +669,14 @@ describe('standard-kit synthesis', () => {
|
||||
h.declare('k.session', SINGLE_SESSION)
|
||||
h.add('k.session', { component: () => <b>x</b> })
|
||||
const { view } = mountRoot(h, { 'k.session': SINGLE_SESSION },
|
||||
(renderSlot) => renderSlot('k.session', {}))
|
||||
renderSlot => renderSlot('k.session', {}))
|
||||
expect(view.container.querySelector('b')).toBeNull()
|
||||
})
|
||||
|
||||
it('delivers the store pair for store-declaring entries and writes through baked actions', () => {
|
||||
const h = makeHost()
|
||||
h.declare('k.single', SINGLE_ROOT)
|
||||
const handle = miniStore(() => ({ n: 0 }), { inc: (s) => ({ n: s.n + 1 }) })
|
||||
const handle = miniStore(() => ({ n: 0 }), { inc: s => ({ n: s.n + 1 }) })
|
||||
let bump = () => {}
|
||||
h.add('k.single', {
|
||||
component: ({ useStore, actions }: {
|
||||
@@ -684,11 +684,11 @@ describe('standard-kit synthesis', () => {
|
||||
actions: { inc: () => void }
|
||||
}) => {
|
||||
bump = actions.inc
|
||||
return <b>{useStore((s) => s.n)}</b>
|
||||
return <b>{useStore(s => s.n)}</b>
|
||||
},
|
||||
store: handle,
|
||||
})
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT }, (renderSlot) => renderSlot('k.single', {}))
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT }, renderSlot => renderSlot('k.single', {}))
|
||||
expect(view.container.textContent).toBe('0')
|
||||
act(() => { bump() })
|
||||
expect(view.container.textContent).toBe('1')
|
||||
@@ -707,11 +707,11 @@ describe('standard-kit synthesis', () => {
|
||||
actions: { setDraft: (text: string) => void }
|
||||
}) => {
|
||||
setDraft = actions.setDraft
|
||||
return <b>{useStore((s) => s.draft) || '(blank)'}</b>
|
||||
return <b>{useStore(s => s.draft) || '(blank)'}</b>
|
||||
},
|
||||
store: handle,
|
||||
})
|
||||
const { view } = mountRoot(h, { 'k.session': SINGLE_SESSION }, (renderSlot) => (
|
||||
const { view } = mountRoot(h, { 'k.session': SINGLE_SESSION }, renderSlot => (
|
||||
<SessionProvider>{() => renderSlot('k.session', {})}</SessionProvider>
|
||||
))
|
||||
act(() => { h.current.set('s1') })
|
||||
@@ -730,7 +730,7 @@ describe('inject: execution point, parameter derivation, cache granularity', ()
|
||||
h.declare('k.single', SINGLE_ROOT)
|
||||
const inject = vi.fn(() => ({ tag: 'FROM-INJECT' }))
|
||||
h.add('k.single', { component: ({ tag }: { tag?: string }) => <b>{tag}</b>, inject })
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT }, (renderSlot) => renderSlot('k.single', {}))
|
||||
const { view } = mountRoot(h, { 'k.single': SINGLE_ROOT }, renderSlot => renderSlot('k.single', {}))
|
||||
expect(view.container.textContent).toBe('FROM-INJECT')
|
||||
act(() => { h.add('k.single', { component: () => null }) }) // sibling bump re-renders the outlet
|
||||
expect(inject).toHaveBeenCalledTimes(1)
|
||||
@@ -745,9 +745,9 @@ describe('inject: execution point, parameter derivation, cache granularity', ()
|
||||
const inject = vi.fn((sessionId: string) => ({ sid: sessionId }))
|
||||
h.add('k.session', {
|
||||
component: ({ sid }: { sid?: string }) => <b>{sid}</b>,
|
||||
inject: inject as unknown as StoredEntry['inject'],
|
||||
inject: inject,
|
||||
})
|
||||
const { view } = mountRoot(h, { 'k.session': SINGLE_SESSION }, (renderSlot) => (
|
||||
const { view } = mountRoot(h, { 'k.session': SINGLE_SESSION }, renderSlot => (
|
||||
<SessionProvider>{() => renderSlot('k.session', {})}</SessionProvider>
|
||||
))
|
||||
act(() => { h.current.set('s1') })
|
||||
@@ -767,22 +767,22 @@ describe('inject: execution point, parameter derivation, cache granularity', ()
|
||||
h.declare('k.single', SINGLE_ROOT)
|
||||
h.declare('k.session', SINGLE_SESSION)
|
||||
h.addSession('s1')
|
||||
const handle = miniStore(() => ({ n: 0 }), { inc: (s) => ({ n: s.n + 1 }) })
|
||||
const handle = miniStore(() => ({ n: 0 }), { inc: s => ({ n: s.n + 1 }) })
|
||||
const rootInject = vi.fn((actions: { inc: () => void }) => ({ viaRoot: actions }))
|
||||
const sessionInject = vi.fn((sessionId: string, actions: { inc: () => void }) => ({ sid: sessionId, viaSession: actions }))
|
||||
const seenRoot: AnyProps[] = []
|
||||
const seenSession: AnyProps[] = []
|
||||
h.add('k.single', {
|
||||
component: (props: object) => { seenRoot.push(props as AnyProps); return null },
|
||||
inject: rootInject as unknown as StoredEntry['inject'],
|
||||
inject: rootInject,
|
||||
store: handle,
|
||||
})
|
||||
h.add('k.session', {
|
||||
component: (props: object) => { seenSession.push(props as AnyProps); return null },
|
||||
inject: sessionInject as unknown as StoredEntry['inject'],
|
||||
inject: sessionInject,
|
||||
store: handle,
|
||||
})
|
||||
mountRoot(h, { 'k.single': SINGLE_ROOT, 'k.session': SINGLE_SESSION }, (renderSlot) => <>
|
||||
mountRoot(h, { 'k.single': SINGLE_ROOT, 'k.session': SINGLE_SESSION }, renderSlot => <>
|
||||
{renderSlot('k.single', {})}
|
||||
<SessionProvider>{() => renderSlot('k.session', {})}</SessionProvider>
|
||||
</>)
|
||||
@@ -807,7 +807,7 @@ describe('inject: execution point, parameter derivation, cache granularity', ()
|
||||
h.add('k.list', { component: () => <span>alive</span>, options: { id: 'ok', order: 2 } })
|
||||
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
const { view } = mountRoot(h, { 'k.list': { kind: 'list', scope: 'root' } },
|
||||
(renderSlot) => <main>{renderSlot('k.list', {})}</main>)
|
||||
renderSlot => <main>{renderSlot('k.list', {})}</main>)
|
||||
spy.mockRestore()
|
||||
// The failing entry blacks out alone; the sibling and the tree above survive.
|
||||
expect(view.container.querySelector('main')).not.toBeNull()
|
||||
@@ -824,7 +824,7 @@ describe('inject: execution point, parameter derivation, cache granularity', ()
|
||||
inject: () => ({ fromInject: 'inject', shared: 'inject' }),
|
||||
})
|
||||
mountRoot(h, { 'k.single': SINGLE_ROOT },
|
||||
(renderSlot) => renderSlot('k.single', { owner: 'owner', shared: 'owner' }))
|
||||
renderSlot => renderSlot('k.single', { owner: 'owner', shared: 'owner' }))
|
||||
const props = seen.at(-1)!
|
||||
expect(typeof props['useSessions']).toBe('function') // kit always present
|
||||
expect(typeof props['useWorkspaces']).toBe('function')
|
||||
|
||||
@@ -43,15 +43,15 @@ function makeHost(bodies: { root: (rp: (key: string, owner: object) => React.Rea
|
||||
const host: SlotRendererHost = {
|
||||
subscribe: () => () => {},
|
||||
getVersion: () => 0,
|
||||
entriesOf: (key) => key === 'root' ? [rootEntry] : sessionEntries,
|
||||
specOf: (key) => key === 'k.session' ? { kind: 'single', scope: 'session' } : undefined,
|
||||
entriesOf: key => key === 'root' ? [rootEntry] : sessionEntries,
|
||||
specOf: key => key === 'k.session' ? { kind: 'single', scope: 'session' } : undefined,
|
||||
isLive: () => true,
|
||||
storeOf: () => undefined,
|
||||
sessions: {
|
||||
list: observable<unknown>({ ids: [] }),
|
||||
current,
|
||||
provideInfo: (id) => infos.get(id),
|
||||
maybeProvideInfo: (id) => (id === undefined ? undefined : infos.get(id))
|
||||
provideInfo: id => infos.get(id),
|
||||
maybeProvideInfo: id => (id === undefined ? undefined : infos.get(id))
|
||||
?? { sessionId: undefined, hooks: { session: undefined }, props: {} },
|
||||
},
|
||||
workspaces: { list: observable<unknown>({ items: [] }) },
|
||||
@@ -78,7 +78,7 @@ describe('SessionProvider', () => {
|
||||
const h = makeHost({
|
||||
root: () => (
|
||||
<SessionProvider empty={() => <span>empty</span>}>
|
||||
{(id) => <div data-testid="body">{id}</div>}
|
||||
{id => <div data-testid="body">{id}</div>}
|
||||
</SessionProvider>
|
||||
),
|
||||
})
|
||||
@@ -93,7 +93,7 @@ describe('SessionProvider', () => {
|
||||
|
||||
it('renders null empty state when the empty prop is omitted', () => {
|
||||
const h = makeHost({
|
||||
root: () => <SessionProvider>{(id) => <b>{id}</b>}</SessionProvider>,
|
||||
root: () => <SessionProvider>{id => <b>{id}</b>}</SessionProvider>,
|
||||
})
|
||||
const view = render(<>{createSlotRenderer().renderRoot(h.host, {})}</>)
|
||||
expect(view.container.textContent).toBe('')
|
||||
@@ -110,7 +110,7 @@ describe('SessionProvider', () => {
|
||||
return <div>{id}</div>
|
||||
}
|
||||
const h = makeHost({
|
||||
root: () => <SessionProvider>{(id) => <Body id={id} />}</SessionProvider>,
|
||||
root: () => <SessionProvider>{id => <Body id={id} />}</SessionProvider>,
|
||||
})
|
||||
h.addSession('s1')
|
||||
h.addSession('s2')
|
||||
@@ -127,7 +127,7 @@ describe('SessionProvider', () => {
|
||||
it('delivers the resolved cell to session slots under it (observable behavior, not context internals)', () => {
|
||||
const seen: Record<string, unknown>[] = []
|
||||
const h = makeHost({
|
||||
root: (renderSlot) => <SessionProvider>{() => renderSlot('k.session', {})}</SessionProvider>,
|
||||
root: renderSlot => <SessionProvider>{() => renderSlot('k.session', {})}</SessionProvider>,
|
||||
})
|
||||
h.addSession('s1')
|
||||
h.addSession('s2')
|
||||
@@ -135,7 +135,7 @@ describe('SessionProvider', () => {
|
||||
component: (props: { useSession?: <S>(sel: (s: { sid: string }) => S) => S; sessionId?: string }) => {
|
||||
// The bound hook reads the cell's bare source — asserting through it
|
||||
// proves the machinery wired THIS session's source, not another's.
|
||||
seen.push({ sessionId: props.sessionId, read: props.useSession!((s) => s.sid) })
|
||||
seen.push({ sessionId: props.sessionId, read: props.useSession!(s => s.sid) })
|
||||
return null
|
||||
},
|
||||
options: {},
|
||||
@@ -152,7 +152,7 @@ describe('SessionProvider', () => {
|
||||
it('fails loud when mounted outside the renderer tree (no host channel)', () => {
|
||||
const spy = vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
expect(() => render(
|
||||
<SessionProvider>{(id) => <b>{id}</b>}</SessionProvider>,
|
||||
<SessionProvider>{id => <b>{id}</b>}</SessionProvider>,
|
||||
)).toThrow(/outside the installed renderer tree/)
|
||||
spy.mockRestore()
|
||||
})
|
||||
|
||||
@@ -32,10 +32,10 @@ function makeHost() {
|
||||
subs.set(key, set)
|
||||
return () => { set.delete(fn) }
|
||||
},
|
||||
getVersion: (key) => versions.get(key) ?? 0,
|
||||
entriesOf: (key) => entries.get(key) ?? [],
|
||||
getVersion: key => versions.get(key) ?? 0,
|
||||
entriesOf: key => entries.get(key) ?? [],
|
||||
specOf: () => ({ kind: 'single', scope: 'root' }),
|
||||
isLive: (entry) => live.has(entry),
|
||||
isLive: entry => live.has(entry),
|
||||
storeOf: () => undefined,
|
||||
sessions: {
|
||||
list: { getSnapshot: () => ({}), subscribe: () => () => {} },
|
||||
@@ -54,7 +54,7 @@ function makeHost() {
|
||||
live.add(entry)
|
||||
bump(key)
|
||||
return () => {
|
||||
entries.set(key, (entries.get(key) ?? []).filter((e) => e !== entry))
|
||||
entries.set(key, (entries.get(key) ?? []).filter(e => e !== entry))
|
||||
live.delete(entry)
|
||||
bump(key)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user