From 924cfcef9595e101ec090d1f118c8f557e11469d Mon Sep 17 00:00:00 2001 From: imccyu <276526105+imccyu@users.noreply.github.com> Date: Sun, 9 Aug 2026 18:56:29 +0800 Subject: [PATCH] fix: coverage --- .../src/client/contract/conversation.ts | 4 ++++ .../client/sessions/conversation-assembler.ts | 5 ++--- .../sessions/conversation-location-index.ts | 2 +- .../client/test-runtime/tests/runtime.spec.tsx | 3 ++- .../src/client/contract/chat-nodes.ts | 2 +- .../src/client/contract/slots.ts | 2 +- .../tests/chat-snapshot-fixture.ts | 7 +++++-- .../ui-conversation/tests/chat-view.spec.tsx | 18 ++++++++++-------- .../tests/produced-files.spec.tsx | 7 +++++-- .../client/ui-settings/tests/apply.spec.ts | 12 ++++++------ packages/client/ui-slots/src/index.ts | 10 ++++++++-- packages/typert/generator/src/analyzer.ts | 2 +- 12 files changed, 46 insertions(+), 28 deletions(-) diff --git a/packages/client/runtime/src/client/contract/conversation.ts b/packages/client/runtime/src/client/contract/conversation.ts index fb98965d25..9507046b33 100644 --- a/packages/client/runtime/src/client/contract/conversation.ts +++ b/packages/client/runtime/src/client/contract/conversation.ts @@ -1,6 +1,10 @@ import type { SessionEvent } from '@deepseek-ai/dsh-session/types' import type { ToolEventView } from '@deepseek-ai/dsh-client-connection/client' +/* oxlint-disable typescript/no-duplicate-type-constituents, typescript/no-redundant-type-constituents -- + * The unaugmented declaration-merge maps intentionally resolve to never in the Runtime program; + * installed business packages supply their concrete keys in consuming Client programs. */ + /** One raw log event plus its optional envelope-level presentation view. */ export interface ConversationEventInput { readonly event: SessionEvent diff --git a/packages/client/runtime/src/client/sessions/conversation-assembler.ts b/packages/client/runtime/src/client/sessions/conversation-assembler.ts index 811bd43ebf..bdd89f56a4 100644 --- a/packages/client/runtime/src/client/sessions/conversation-assembler.ts +++ b/packages/client/runtime/src/client/sessions/conversation-assembler.ts @@ -712,9 +712,8 @@ export class ConversationNodeAssembler { context: InternalContext, scope: ConversationLocationDataScope, ): ConversationLocationData | null { - const build = context.definition.buildLocationData - if (build === undefined) return null - const data = build(contextSnapshot(context), scope) + if (context.definition.buildLocationData === undefined) return null + const data = context.definition.buildLocationData(contextSnapshot(context), scope) if (data === null) return null if (data.kind !== scope) { throw new Error( diff --git a/packages/client/runtime/src/client/sessions/conversation-location-index.ts b/packages/client/runtime/src/client/sessions/conversation-location-index.ts index c842a230a9..f4ce189b13 100644 --- a/packages/client/runtime/src/client/sessions/conversation-location-index.ts +++ b/packages/client/runtime/src/client/sessions/conversation-location-index.ts @@ -20,7 +20,7 @@ export interface ConversationLocationDataChange { class MutableLocationDataStore { private entries = new Map() - get(key: Key): unknown { + get(key: string): unknown { return this.entries.get(key)?.value } diff --git a/packages/client/test-runtime/tests/runtime.spec.tsx b/packages/client/test-runtime/tests/runtime.spec.tsx index f92d21b4b5..08a82ee251 100644 --- a/packages/client/test-runtime/tests/runtime.spec.tsx +++ b/packages/client/test-runtime/tests/runtime.spec.tsx @@ -18,6 +18,7 @@ declare module '@deepseek-ai/dsh-client-ui-slots' { 'trt.panel': { kind: 'single'; scope: 'root'; owner: { label?: string } } 'trt.chat': { kind: 'single'; scope: 'session' } 'trt.rows': { kind: 'list'; scope: 'root' } + 'trt.rows.hole': { kind: 'single'; scope: 'root' } } } @@ -419,7 +420,7 @@ describe('feature mount and disposal', () => { await feature.dispose() await feature.dispose() // idempotent expect(runtime.slots.entries('trt.rows')).toHaveLength(0) - expect(runtime.slots.spec('trt.rows.hole' as never)).toBeUndefined() + expect(runtime.slots.spec('trt.rows.hole')).toBeUndefined() expect(runtime.ctx.get('feature-service')).toBeUndefined() expect(view.queryByTestId('row')).toBeNull() await runtime.dispose() diff --git a/packages/client/ui-conversation/src/client/contract/chat-nodes.ts b/packages/client/ui-conversation/src/client/contract/chat-nodes.ts index 3415c502a5..787f391006 100644 --- a/packages/client/ui-conversation/src/client/contract/chat-nodes.ts +++ b/packages/client/ui-conversation/src/client/contract/chat-nodes.ts @@ -7,7 +7,7 @@ import type { export interface ChatNodeDataMap {} /** Renderer kinds contributed by the currently installed Chat business modules. */ -export type ChatNodeKind = keyof ChatNodeDataMap & string +export type ChatNodeKind = Extract /** Final Chat Node narrowed to one registered renderer kind and payload. */ export type ChatNode = { diff --git a/packages/client/ui-conversation/src/client/contract/slots.ts b/packages/client/ui-conversation/src/client/contract/slots.ts index eec5450e2d..56fca2381c 100644 --- a/packages/client/ui-conversation/src/client/contract/slots.ts +++ b/packages/client/ui-conversation/src/client/contract/slots.ts @@ -210,7 +210,7 @@ export interface TurnTailOwnerProps { } /** Hook constrained to business data published on the current Chat Node's Turn. */ -export type UseChatNodeTurnData = ( +export type UseChatNodeTurnData = >( key: Key, ) => Readonly | undefined diff --git a/packages/client/ui-conversation/tests/chat-snapshot-fixture.ts b/packages/client/ui-conversation/tests/chat-snapshot-fixture.ts index c675554ea0..fb343f0f68 100644 --- a/packages/client/ui-conversation/tests/chat-snapshot-fixture.ts +++ b/packages/client/ui-conversation/tests/chat-snapshot-fixture.ts @@ -78,13 +78,16 @@ class FixtureLocationIndex implements ChatLocationNodeIndex { class FixtureTurnDataStore implements ConversationLocationDataStore { private readonly values = new Map() - get( + get>( key: Key, ): Readonly | undefined { return this.values.get(key) as Readonly | undefined } - set(key: Key, value: ConversationTurnDataMap[Key]): void { + set>( + key: Key, + value: ConversationTurnDataMap[Key], + ): void { this.values.set(key, value) } } diff --git a/packages/client/ui-conversation/tests/chat-view.spec.tsx b/packages/client/ui-conversation/tests/chat-view.spec.tsx index 296dd85966..ca6223826e 100644 --- a/packages/client/ui-conversation/tests/chat-view.spec.tsx +++ b/packages/client/ui-conversation/tests/chat-view.spec.tsx @@ -181,12 +181,14 @@ function makeHarness(init?: Partial) { if (key !== 'conversation.chat.node') return opts?.fallback ?? null const nodeOwner = owner as RoutedChatNodeOwner const nodeKey = opts?.hookContext as string | undefined - const useTurnData = ((dataKey: string) => props.useSession((snapshot) => { - const location = nodeKey === undefined ? undefined : snapshot.chat.nodes.get(nodeKey)?.location - return location?.kind === 'turn' || location?.kind === 'step' - ? location.turn.data.get(dataKey as never) - : undefined - })) as UseChatNodeTurnData + const useTurnData = ((dataKey: string) => { + return props.useSession((snapshot) => { + const location = nodeKey === undefined ? undefined : snapshot.chat.nodes.get(nodeKey)?.location + return location?.kind === 'turn' || location?.kind === 'step' + ? location.turn.data.get(dataKey as never) + : undefined + }) + }) as UseChatNodeTurnData const nodeProps = (): ChatNodeViewProps => ( { ...props, ...nodeOwner, useTurnData } as unknown as ChatNodeViewProps ) @@ -226,7 +228,7 @@ function makeHarness(init?: Partial) { case 'unknown': return ()} /> case 'tool-call': { - const block = (nodeOwner.node.data as { readonly root: ToolCallBlock }).root + const block = nodeOwner.node.data.root const toolName = 'kind' in block ? block.call?.name ?? '' : block.name const tool = { callId: block.callId, @@ -843,7 +845,7 @@ describe('ChatView', () => { mounted() return () => { unmounted() } }, []) - const root = (node.data as { readonly root: ToolCallBlock }).root + const root = node.data.root return (
{root.callId} diff --git a/packages/client/ui-deliverables/tests/produced-files.spec.tsx b/packages/client/ui-deliverables/tests/produced-files.spec.tsx index b7ca73a79f..b8e7cd111e 100644 --- a/packages/client/ui-deliverables/tests/produced-files.spec.tsx +++ b/packages/client/ui-deliverables/tests/produced-files.spec.tsx @@ -34,13 +34,16 @@ afterEach(cleanup) class TestTurnDataStore implements ConversationLocationDataStore { private readonly values = new Map() - get( + get>( key: Key, ): Readonly | undefined { return this.values.get(key) as Readonly | undefined } - set(key: Key, value: ConversationTurnDataMap[Key]): void { + set>( + key: Key, + value: ConversationTurnDataMap[Key], + ): void { this.values.set(key, value) } } diff --git a/packages/client/ui-settings/tests/apply.spec.ts b/packages/client/ui-settings/tests/apply.spec.ts index c46a5bf25c..3133ad4d76 100644 --- a/packages/client/ui-settings/tests/apply.spec.ts +++ b/packages/client/ui-settings/tests/apply.spec.ts @@ -44,8 +44,8 @@ describe('ui-settings apply', () => { declare(before.slots) await before.ctx.plugin({ inject: [...inject], apply }).await() expect(before.slots.entries('sidebar.settings')[0]!.component).toBe(SettingsRoot) - for (const [name, spec] of Object.entries(CHILD_SPECS)) { - expect(before.slots.spec(name as never)).toEqual(spec) + for (const name of Object.keys(CHILD_SPECS) as Array) { + expect(before.slots.spec(name)).toEqual(CHILD_SPECS[name]) } const after = await bench() @@ -120,8 +120,8 @@ describe('ui-settings apply', () => { declare(b.slots) await Promise.resolve() expect(b.slots.entries('sidebar.settings')[0]!.component).toBe(SettingsRoot) - for (const [name, spec] of Object.entries(CHILD_SPECS)) { - expect(b.slots.spec(name as never)).toEqual(spec) + for (const name of Object.keys(CHILD_SPECS) as Array) { + expect(b.slots.spec(name)).toEqual(CHILD_SPECS[name]) } }) @@ -132,8 +132,8 @@ describe('ui-settings apply', () => { await fiber.await() await fiber.dispose() expect(b.slots.entries('sidebar.settings')).toHaveLength(0) - for (const name of Object.keys(CHILD_SPECS)) { - expect(b.slots.spec(name as never)).toBeUndefined() + for (const name of Object.keys(CHILD_SPECS) as Array) { + expect(b.slots.spec(name)).toBeUndefined() } }) }) diff --git a/packages/client/ui-slots/src/index.ts b/packages/client/ui-slots/src/index.ts index 4ed6ecf519..d6c1824c99 100644 --- a/packages/client/ui-slots/src/index.ts +++ b/packages/client/ui-slots/src/index.ts @@ -677,7 +677,10 @@ export class SlotCore { >( options: BaseOptions & { inject?: undefined }, component: C - & SlotComponent, keyof NoInfer & keyof SlotMap & string, HandleOf>, object, NoInfer, NoInfer>> + & SlotComponent, keyof NoInfer & keyof SlotMap & string, + HandleOf>, object, NoInfer, NoInfer + >> & RendersCheck, ): () => void /** @@ -702,7 +705,10 @@ export class SlotCore { >( options: BaseOptions & { inject: (...args: InjectParams) => I }, component: C - & SlotComponent, keyof NoInfer & keyof SlotMap & string, HandleOf>, I, NoInfer, NoInfer>> + & SlotComponent, keyof NoInfer & keyof SlotMap & string, + HandleOf>, I, NoInfer, NoInfer + >> & RendersCheck, ): () => void /* jscpd:ignore-end */ diff --git a/packages/typert/generator/src/analyzer.ts b/packages/typert/generator/src/analyzer.ts index 6f495aa318..68736f0b3a 100644 --- a/packages/typert/generator/src/analyzer.ts +++ b/packages/typert/generator/src/analyzer.ts @@ -274,7 +274,7 @@ export class WorkspaceAnalyzer { constructor(options: WorkspaceAnalyzerOptions) { this.options = { - root: resolve(options.root), + root: realPath(options.root), hostConfig: options.hostConfig ?? 'tsconfig.host.json', clientConfig: options.clientConfig ?? 'tsconfig.client.json', faces: options.faces ?? ['host', 'client'],