1+ /**
2+ * This contains:
3+ * - Static type checks to verify the Spec's types are compatible with the SDK's types
4+ * (mutually assignable, w/ slight affordances to get rid of ZodObject.passthrough() index signatures, etc)
5+ * - Runtime checks to verify all Spec types have a static check
6+ * (a few don't have SDK types, see TODOs in this file)
7+ */
18import * as SDKTypes from "./types.js" ;
29import * as SpecTypes from "./spec.types.js" ;
310
411/* eslint-disable @typescript-eslint/no-unused-vars */
512/* eslint-disable @typescript-eslint/no-unsafe-function-type */
613/* eslint-disable @typescript-eslint/no-require-imports */
714
8- // Deep version that recursively removes index signatures (caused by ZodObject.passthrough()) and turns unknowns into `object | undefined`
9- // TODO: make string index mapping tighter
10- // TODO: split into multiple transformations if needed
15+ // Removes index signatures added by ZodObject.passthrough().
1116type RemovePassthrough < T > = T extends object
1217 ? T extends Array < infer U >
1318 ? Array < RemovePassthrough < U > >
1419 : T extends Function
1520 ? T
1621 : { [ K in keyof T as string extends K ? never : K ] : RemovePassthrough < T [ K ] > }
17- : T ;
22+ : T ;
23+
24+ type IsUnknown < T > = [ unknown ] extends [ T ] ? [ T ] extends [ unknown ] ? true : false : false ;
25+
26+ // Turns {x?: unknown} into {x: unknown} but keeps {_meta?: unknown} unchanged (and leaves other optional properties unchanged, e.g. {x?: string}).
27+ // This works around an apparent quirk of ZodObject.unknown() (makes fields optional)
28+ type MakeUnknownsNotOptional < T > =
29+ IsUnknown < T > extends true
30+ ? unknown
31+ : ( T extends object
32+ ? ( T extends Array < infer U >
33+ ? Array < MakeUnknownsNotOptional < U > >
34+ : ( T extends Function
35+ ? T
36+ : Pick < T , never > & {
37+ // Start with empty object to avoid duplicates
38+ // Make unknown properties required (except _meta)
39+ [ K in keyof T as '_meta' extends K ? never : IsUnknown < T [ K ] > extends true ? K : never ] -?: unknown ;
40+ } &
41+ Pick < T , {
42+ // Pick all _meta and non-unknown properties with original modifiers
43+ [ K in keyof T ] : '_meta' extends K ? K : IsUnknown < T [ K ] > extends true ? never : K
44+ } [ keyof T ] > & {
45+ // Recurse on the picked properties
46+ [ K in keyof Pick < T , { [ K in keyof T ] : '_meta' extends K ? K : IsUnknown < T [ K ] > extends true ? never : K } [ keyof T ] > ] : MakeUnknownsNotOptional < T [ K ] >
47+ } ) )
48+ : T ) ;
1849
1950function checkCancelledNotification (
2051 sdk : SDKTypes . CancelledNotification ,
@@ -36,7 +67,7 @@ function checkImplementation(
3667) {
3768 sdk = spec ;
3869 spec = sdk ;
39- }
70+ }
4071function checkProgressNotification (
4172 sdk : SDKTypes . ProgressNotification ,
4273 spec : SpecTypes . ProgressNotification
@@ -564,70 +595,70 @@ function checkJSONRPCMessage(
564595 spec = sdk ;
565596}
566597function checkCreateMessageRequest (
567- sdk : RemovePassthrough < SDKTypes . CreateMessageRequest > , // TODO(quirk): some {} typ>e
598+ sdk : RemovePassthrough < SDKTypes . CreateMessageRequest > ,
568599 spec : SpecTypes . CreateMessageRequest
569600) {
570601 sdk = spec ;
571602 spec = sdk ;
572603}
573604function checkInitializeRequest (
574- sdk : RemovePassthrough < SDKTypes . InitializeRequest > , // TODO(quirk): some {} type
605+ sdk : RemovePassthrough < SDKTypes . InitializeRequest > ,
575606 spec : SpecTypes . InitializeRequest
576607) {
577608 sdk = spec ;
578609 spec = sdk ;
579610}
580611function checkInitializeResult (
581- sdk : RemovePassthrough < SDKTypes . InitializeResult > , // TODO(quirk): some {} type
612+ sdk : RemovePassthrough < SDKTypes . InitializeResult > ,
582613 spec : SpecTypes . InitializeResult
583614) {
584615 sdk = spec ;
585616 spec = sdk ;
586617}
587618function checkClientCapabilities (
588- sdk : RemovePassthrough < SDKTypes . ClientCapabilities > , // TODO(quirk): {}
619+ sdk : RemovePassthrough < SDKTypes . ClientCapabilities > ,
589620 spec : SpecTypes . ClientCapabilities
590621) {
591622 sdk = spec ;
592623 spec = sdk ;
593624}
594625function checkServerCapabilities (
595- sdk : RemovePassthrough < SDKTypes . ServerCapabilities > , // TODO(quirk): {}
626+ sdk : RemovePassthrough < SDKTypes . ServerCapabilities > ,
596627 spec : SpecTypes . ServerCapabilities
597628) {
598629 sdk = spec ;
599630 spec = sdk ;
600631}
601632function checkClientRequest (
602- sdk : RemovePassthrough < SDKTypes . ClientRequest > , // TODO(quirk): capabilities.logging is {}
633+ sdk : RemovePassthrough < SDKTypes . ClientRequest > ,
603634 spec : SpecTypes . ClientRequest
604635) {
605636 sdk = spec ;
606637 spec = sdk ;
607638}
608639function checkServerRequest (
609- sdk : RemovePassthrough < SDKTypes . ServerRequest > , // TODO(quirk): some {} typ
640+ sdk : RemovePassthrough < SDKTypes . ServerRequest > ,
610641 spec : SpecTypes . ServerRequest
611642) {
612643 sdk = spec ;
613644 spec = sdk ;
614645}
615646function checkLoggingMessageNotification (
616- sdk : SDKTypes . LoggingMessageNotification ,
647+ sdk : MakeUnknownsNotOptional < SDKTypes . LoggingMessageNotification > ,
617648 spec : SpecTypes . LoggingMessageNotification
618649) {
619650 sdk = spec ;
620- // spec = sdk; // TODO(bug): data is optional
651+ spec = sdk ;
621652}
622653function checkServerNotification (
623- sdk : SDKTypes . ServerNotification ,
654+ sdk : MakeUnknownsNotOptional < SDKTypes . ServerNotification > ,
624655 spec : SpecTypes . ServerNotification
625656) {
626657 sdk = spec ;
627- // spec = sdk; // TODO(bug): data is optional
658+ spec = sdk ;
628659}
629660
630- // TODO(bug): missing type in SDK
661+ // TODO(bug): missing type in SDK. This dead code is checked by the test suite below.
631662// function checkModelHint(
632663// RemovePassthrough< sdk: SDKTypes.ModelHint>,
633664// spec: SpecTypes.ModelHint
@@ -636,7 +667,7 @@ function checkServerNotification(
636667// spec = sdk;
637668// }
638669
639- // TODO(bug): missing type in SDK
670+ // TODO(bug): missing type in SDK. This dead code is checked by the test suite below.
640671// function checkModelPreferences(
641672// RemovePassthrough< sdk: SDKTypes.ModelPreferences>,
642673// spec: SpecTypes.ModelPreferences
@@ -645,7 +676,7 @@ function checkServerNotification(
645676// spec = sdk;
646677// }
647678
648- // TODO(bug): missing type in SDK
679+ // TODO(bug): missing type in SDK. This dead code is checked by the test suite below.
649680// function checkAnnotations(
650681// RemovePassthrough< sdk: SDKTypes.Annotations>,
651682// spec: SpecTypes.Annotations
@@ -661,7 +692,7 @@ describe('Spec Types', () => {
661692 const specTypesContent = require ( 'fs' ) . readFileSync ( SPEC_TYPES_FILE , 'utf-8' ) ;
662693 const typeNames = [ ...specTypesContent . matchAll ( / e x p o r t \s + i n t e r f a c e \s + ( \w + ) \b / g) ] . map ( m => m [ 1 ] ) ;
663694 const testContent = require ( 'fs' ) . readFileSync ( THIS_SOURCE_FILE , 'utf-8' ) ;
664-
695+
665696 it ( 'should define some expected types' , ( ) => {
666697 expect ( typeNames ) . toContain ( 'JSONRPCNotification' ) ;
667698 expect ( typeNames ) . toContain ( 'ElicitResult' ) ;
0 commit comments