Skip to content

Commit 239910a

Browse files
ochafikclaude
andcommitted
fix: generate concrete capability schemas from extracted types
Instead of using NonNullable<ParentType["property"]> which ts-to-zod can't process, extract the actual type text from parent interfaces during pre-processing. This allows ts-to-zod to generate proper schemas for: - ClientTasksCapabilitySchema - ServerTasksCapabilitySchema These are now re-exported from generated instead of using .unwrap() extraction. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b86bfc3 commit 239910a

File tree

5 files changed

+1517
-1394
lines changed

5 files changed

+1517
-1394
lines changed

scripts/generate-schemas.ts

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ const DISCRIMINATED_UNIONS: Record<string, string> = {
113113
/**
114114
* Derived capability types to add during pre-processing.
115115
* These are extracted from parent capability interfaces for convenience.
116-
* Format: { typeName: 'ParentType["property"]' }
116+
* Format: { typeName: { parent: 'ParentInterface', property: 'propertyName' } }
117117
*/
118-
const DERIVED_CAPABILITY_TYPES: Record<string, string> = {
119-
'ClientTasksCapability': 'ClientCapabilities["tasks"]',
120-
'ServerTasksCapability': 'ServerCapabilities["tasks"]',
118+
const DERIVED_CAPABILITY_TYPES: Record<string, { parent: string; property: string }> = {
119+
'ClientTasksCapability': { parent: 'ClientCapabilities', property: 'tasks' },
120+
'ServerTasksCapability': { parent: 'ServerCapabilities', property: 'tasks' },
121121
};
122122

123123
// =============================================================================
@@ -280,27 +280,52 @@ function updateRequestParamsType(sourceFile: SourceFile): void {
280280
}
281281

282282
/**
283-
* Add derived capability types that extract nested capabilities from parent types.
284-
* This allows reusing types like ClientCapabilities["tasks"] as standalone types.
283+
* Add derived capability types by extracting nested properties from parent interfaces.
284+
* This creates concrete interface definitions that ts-to-zod can generate schemas for.
285285
*
286-
* Adds type aliases like:
287-
* export type ClientTasksCapability = NonNullable<ClientCapabilities["tasks"]>;
286+
* Example: ClientCapabilities.tasks becomes a standalone ClientTasksCapability interface.
288287
*/
289288
function injectDerivedCapabilityTypes(sourceFile: SourceFile): void {
290-
for (const [typeName, sourceExpression] of Object.entries(DERIVED_CAPABILITY_TYPES)) {
289+
for (const [typeName, { parent, property }] of Object.entries(DERIVED_CAPABILITY_TYPES)) {
291290
// Check if already exists
292-
if (sourceFile.getTypeAlias(typeName)) {
291+
if (sourceFile.getInterface(typeName) || sourceFile.getTypeAlias(typeName)) {
293292
console.log(` - ${typeName} already exists`);
294293
continue;
295294
}
296295

296+
// Find the parent interface
297+
const parentInterface = sourceFile.getInterface(parent);
298+
if (!parentInterface) {
299+
console.warn(` ⚠️ Parent interface ${parent} not found for ${typeName}`);
300+
continue;
301+
}
302+
303+
// Find the property
304+
const prop = parentInterface.getProperty(property);
305+
if (!prop) {
306+
console.warn(` ⚠️ Property ${property} not found in ${parent} for ${typeName}`);
307+
continue;
308+
}
309+
310+
// Get the type text and remove the optional marker if present
311+
const typeNode = prop.getTypeNode();
312+
if (!typeNode) {
313+
console.warn(` ⚠️ No type node for ${parent}.${property}`);
314+
continue;
315+
}
316+
317+
let typeText = typeNode.getText();
318+
// Remove trailing '?' or '| undefined' to get the non-optional type
319+
typeText = typeText.replace(/\s*\|\s*undefined\s*$/, '').trim();
320+
321+
// Create the derived type alias
297322
sourceFile.addTypeAlias({
298323
name: typeName,
299324
isExported: true,
300-
type: `NonNullable<${sourceExpression}>`,
301-
docs: [`Derived from ${sourceExpression} for convenience.`]
325+
type: typeText,
326+
docs: [`Extracted from ${parent}["${property}"] for standalone use.`]
302327
});
303-
console.log(` ✓ Added derived type: ${typeName}`);
328+
console.log(` ✓ Added derived type: ${typeName} from ${parent}.${property}`);
304329
}
305330
}
306331

src/generated/sdk.schemas.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1960,6 +1960,77 @@ export const ListToolsResultSchema = PaginatedResultSchema.extend({
19601960
tools: z.array(ToolSchema)
19611961
});
19621962

1963+
/** Extracted from ClientCapabilities["tasks"] for standalone use. */
1964+
export const ClientTasksCapabilitySchema = z.object({
1965+
/**
1966+
* Whether this client supports tasks/list.
1967+
*/
1968+
list: z.record(z.string(), z.any()).optional(),
1969+
/**
1970+
* Whether this client supports tasks/cancel.
1971+
*/
1972+
cancel: z.record(z.string(), z.any()).optional(),
1973+
/**
1974+
* Specifies which request types can be augmented with tasks.
1975+
*/
1976+
requests: z
1977+
.object({
1978+
/**
1979+
* Task support for sampling-related requests.
1980+
*/
1981+
sampling: z
1982+
.object({
1983+
/**
1984+
* Whether the client supports task-augmented sampling/createMessage requests.
1985+
*/
1986+
createMessage: z.record(z.string(), z.any()).optional()
1987+
})
1988+
.optional(),
1989+
/**
1990+
* Task support for elicitation-related requests.
1991+
*/
1992+
elicitation: z
1993+
.object({
1994+
/**
1995+
* Whether the client supports task-augmented elicitation/create requests.
1996+
*/
1997+
create: z.record(z.string(), z.any()).optional()
1998+
})
1999+
.optional()
2000+
})
2001+
.optional()
2002+
});
2003+
2004+
/** Extracted from ServerCapabilities["tasks"] for standalone use. */
2005+
export const ServerTasksCapabilitySchema = z.object({
2006+
/**
2007+
* Whether this server supports tasks/list.
2008+
*/
2009+
list: z.record(z.string(), z.any()).optional(),
2010+
/**
2011+
* Whether this server supports tasks/cancel.
2012+
*/
2013+
cancel: z.record(z.string(), z.any()).optional(),
2014+
/**
2015+
* Specifies which request types can be augmented with tasks.
2016+
*/
2017+
requests: z
2018+
.object({
2019+
/**
2020+
* Task support for tool-related requests.
2021+
*/
2022+
tools: z
2023+
.object({
2024+
/**
2025+
* Whether the server supports task-augmented tools/call requests.
2026+
*/
2027+
call: z.record(z.string(), z.any()).optional()
2028+
})
2029+
.optional()
2030+
})
2031+
.optional()
2032+
});
2033+
19632034
/**
19642035
* A request that expects a response.
19652036
*

src/generated/sdk.schemas.zod.test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,10 @@ export type ReadResourceResultSchemaInferredType = z.infer<typeof generated.Read
239239

240240
export type ListToolsResultSchemaInferredType = z.infer<typeof generated.ListToolsResultSchema>;
241241

242+
export type ClientTasksCapabilitySchemaInferredType = z.infer<typeof generated.ClientTasksCapabilitySchema>;
243+
244+
export type ServerTasksCapabilitySchemaInferredType = z.infer<typeof generated.ServerTasksCapabilitySchema>;
245+
242246
export type JSONRPCRequestSchemaInferredType = z.infer<typeof generated.JSONRPCRequestSchema>;
243247

244248
export type URLElicitationRequiredErrorSchemaInferredType = z.infer<typeof generated.URLElicitationRequiredErrorSchema>;
@@ -529,6 +533,10 @@ expectType<spec.ReadResourceResult>({} as ReadResourceResultSchemaInferredType);
529533
expectType<ReadResourceResultSchemaInferredType>({} as spec.ReadResourceResult);
530534
expectType<spec.ListToolsResult>({} as ListToolsResultSchemaInferredType);
531535
expectType<ListToolsResultSchemaInferredType>({} as spec.ListToolsResult);
536+
expectType<spec.ClientTasksCapability>({} as ClientTasksCapabilitySchemaInferredType);
537+
expectType<ClientTasksCapabilitySchemaInferredType>({} as spec.ClientTasksCapability);
538+
expectType<spec.ServerTasksCapability>({} as ServerTasksCapabilitySchemaInferredType);
539+
expectType<ServerTasksCapabilitySchemaInferredType>({} as spec.ServerTasksCapability);
532540
expectType<spec.JSONRPCRequest>({} as JSONRPCRequestSchemaInferredType);
533541
expectType<JSONRPCRequestSchemaInferredType>({} as spec.JSONRPCRequest);
534542
expectType<spec.URLElicitationRequiredError>({} as URLElicitationRequiredErrorSchemaInferredType);

0 commit comments

Comments
 (0)