touchdesigner-mcp-server 1.4.7 → 1.4.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/features/tools/handlers/tdTools.js +23 -256
- package/dist/features/tools/metadata/touchDesignerToolMetadata.js +96 -474
- package/dist/features/tools/toolDefinitions.js +317 -0
- package/dist/gen/endpoints/TouchDesignerAPI.js +23 -25
- package/dist/gen/mcp/touchDesignerAPI.zod.js +32 -34
- package/package.json +23 -34
|
@@ -1,476 +1,98 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { TOOL_DEFINITIONS, } from "../toolDefinitions.js";
|
|
2
2
|
const MODULE_ROOT = "servers/touchdesigner";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
required: false,
|
|
99
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
100
|
-
},
|
|
101
|
-
{
|
|
102
|
-
description: "Optional cap on how many nodes to return.",
|
|
103
|
-
name: "limit",
|
|
104
|
-
required: false,
|
|
105
|
-
type: "number",
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
description: "Structured export for writing to disk.",
|
|
109
|
-
name: "responseFormat",
|
|
110
|
-
required: false,
|
|
111
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
returns: "Set of nodes (id, opType, name, path, optional properties) under parentPath.",
|
|
115
|
-
tool: TOOL_NAMES.GET_TD_NODES,
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
category: "nodes",
|
|
119
|
-
description: "Inspect an individual node with formatter-aware output",
|
|
120
|
-
example: `import { getTdNodeParameters } from './servers/touchdesigner/getTdNodeParameters';
|
|
121
|
-
|
|
122
|
-
const node = await getTdNodeParameters({ nodePath: '/project1/text1' });
|
|
123
|
-
console.log(node.properties?.Text);`,
|
|
124
|
-
functionName: "getTdNodeParameters",
|
|
125
|
-
modulePath: `${MODULE_ROOT}/getTdNodeParameters.ts`,
|
|
126
|
-
parameters: [
|
|
127
|
-
{
|
|
128
|
-
description: "Absolute path to the operator (e.g. /project1/text1).",
|
|
129
|
-
name: "nodePath",
|
|
130
|
-
required: true,
|
|
131
|
-
type: "string",
|
|
132
|
-
},
|
|
133
|
-
{
|
|
134
|
-
description: "Controls how many parameters and properties are shown.",
|
|
135
|
-
name: "detailLevel",
|
|
136
|
-
required: false,
|
|
137
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
138
|
-
},
|
|
139
|
-
{
|
|
140
|
-
description: "Trim parameter listings to the first N entries.",
|
|
141
|
-
name: "limit",
|
|
142
|
-
required: false,
|
|
143
|
-
type: "number",
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
description: "Switch between machine vs human friendly layouts.",
|
|
147
|
-
name: "responseFormat",
|
|
148
|
-
required: false,
|
|
149
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
150
|
-
},
|
|
151
|
-
],
|
|
152
|
-
returns: "Full node record with parameters, paths, and metadata.",
|
|
153
|
-
tool: TOOL_NAMES.GET_TD_NODE_PARAMETERS,
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
category: "nodes",
|
|
157
|
-
description: "Collect errors emitted by a node and its children",
|
|
158
|
-
example: `import { getTdNodeErrors } from './servers/touchdesigner/getTdNodeErrors';
|
|
159
|
-
|
|
160
|
-
const report = await getTdNodeErrors({
|
|
161
|
-
nodePath: '/project1/text1',
|
|
162
|
-
});
|
|
163
|
-
if (report.hasErrors) {
|
|
164
|
-
console.log(report.errors?.map(err => err.message));
|
|
165
|
-
}`,
|
|
166
|
-
functionName: "getTdNodeErrors",
|
|
167
|
-
modulePath: `${MODULE_ROOT}/getTdNodeErrors.ts`,
|
|
168
|
-
parameters: [
|
|
169
|
-
{
|
|
170
|
-
description: "Absolute path to inspect (e.g. /project1/text1).",
|
|
171
|
-
name: "nodePath",
|
|
172
|
-
required: true,
|
|
173
|
-
type: "string",
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
description: "Formatter verbosity for the returned error list.",
|
|
177
|
-
name: "detailLevel",
|
|
178
|
-
required: false,
|
|
179
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
description: "Optional limit on how many errors are displayed.",
|
|
183
|
-
name: "limit",
|
|
184
|
-
required: false,
|
|
185
|
-
type: "number",
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
description: "Structured output encoding (json/yaml/markdown).",
|
|
189
|
-
name: "responseFormat",
|
|
190
|
-
required: false,
|
|
191
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
192
|
-
},
|
|
193
|
-
],
|
|
194
|
-
returns: "Error report outlining offending nodes, messages, and counts.",
|
|
195
|
-
tool: TOOL_NAMES.GET_TD_NODE_ERRORS,
|
|
196
|
-
},
|
|
197
|
-
{
|
|
198
|
-
category: "nodes",
|
|
199
|
-
description: "Create an operator under a parent path",
|
|
200
|
-
example: `import { createTdNode } from './servers/touchdesigner/createTdNode';
|
|
201
|
-
|
|
202
|
-
const created = await createTdNode({
|
|
203
|
-
parentPath: '/project1',
|
|
204
|
-
nodeType: 'textTOP',
|
|
205
|
-
nodeName: 'title',
|
|
206
|
-
});
|
|
207
|
-
console.log(created.result?.path);`,
|
|
208
|
-
functionName: "createTdNode",
|
|
209
|
-
modulePath: `${MODULE_ROOT}/createTdNode.ts`,
|
|
210
|
-
parameters: [
|
|
211
|
-
{
|
|
212
|
-
description: "Where the new node should be created.",
|
|
213
|
-
name: "parentPath",
|
|
214
|
-
required: true,
|
|
215
|
-
type: "string",
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
description: "OP type (e.g. textTOP, constantCHOP).",
|
|
219
|
-
name: "nodeType",
|
|
220
|
-
required: true,
|
|
221
|
-
type: "string",
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
description: "Optional custom name. When omitted TouchDesigner assigns one.",
|
|
225
|
-
name: "nodeName",
|
|
226
|
-
required: false,
|
|
227
|
-
type: "string",
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
description: "Formatter verbosity for the creation result.",
|
|
231
|
-
name: "detailLevel",
|
|
232
|
-
required: false,
|
|
233
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
234
|
-
},
|
|
235
|
-
{
|
|
236
|
-
description: "Switch result serialization to JSON for scripts.",
|
|
237
|
-
name: "responseFormat",
|
|
238
|
-
required: false,
|
|
239
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
240
|
-
},
|
|
241
|
-
],
|
|
242
|
-
returns: "Created node metadata including resolved path and properties.",
|
|
243
|
-
tool: TOOL_NAMES.CREATE_TD_NODE,
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
category: "nodes",
|
|
247
|
-
description: "Patch node properties in bulk",
|
|
248
|
-
example: `import { updateTdNodeParameters } from './servers/touchdesigner/updateTdNodeParameters';
|
|
249
|
-
|
|
250
|
-
await updateTdNodeParameters({
|
|
251
|
-
nodePath: '/project1/text1',
|
|
252
|
-
properties: { text: 'Hello TouchDesigner' },
|
|
253
|
-
});`,
|
|
254
|
-
functionName: "updateTdNodeParameters",
|
|
255
|
-
modulePath: `${MODULE_ROOT}/updateTdNodeParameters.ts`,
|
|
256
|
-
parameters: [
|
|
257
|
-
{
|
|
258
|
-
description: "Target operator path.",
|
|
259
|
-
name: "nodePath",
|
|
260
|
-
required: true,
|
|
261
|
-
type: "string",
|
|
262
|
-
},
|
|
263
|
-
{
|
|
264
|
-
description: "Key/value pairs to update on the node.",
|
|
265
|
-
name: "properties",
|
|
266
|
-
required: true,
|
|
267
|
-
type: "Record<string, unknown>",
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
description: "Controls how many updated keys are echoed back.",
|
|
271
|
-
name: "detailLevel",
|
|
272
|
-
required: false,
|
|
273
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
description: "Choose JSON when writing audit logs to disk.",
|
|
277
|
-
name: "responseFormat",
|
|
278
|
-
required: false,
|
|
279
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
280
|
-
},
|
|
281
|
-
],
|
|
282
|
-
returns: "Lists of updated vs failed parameters so the agent can retry selectively.",
|
|
283
|
-
tool: TOOL_NAMES.UPDATE_TD_NODE_PARAMETERS,
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
category: "nodes",
|
|
287
|
-
description: "Remove an operator safely",
|
|
288
|
-
example: `import { deleteTdNode } from './servers/touchdesigner/deleteTdNode';
|
|
289
|
-
|
|
290
|
-
const result = await deleteTdNode({ nodePath: '/project1/tmp1' });
|
|
291
|
-
console.log(result.deleted);`,
|
|
292
|
-
functionName: "deleteTdNode",
|
|
293
|
-
modulePath: `${MODULE_ROOT}/deleteTdNode.ts`,
|
|
294
|
-
parameters: [
|
|
295
|
-
{
|
|
296
|
-
description: "Absolute path of the operator to delete.",
|
|
297
|
-
name: "nodePath",
|
|
298
|
-
required: true,
|
|
299
|
-
type: "string",
|
|
300
|
-
},
|
|
301
|
-
{
|
|
302
|
-
description: "Sends only boolean flags when set to minimal.",
|
|
303
|
-
name: "detailLevel",
|
|
304
|
-
required: false,
|
|
305
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
306
|
-
},
|
|
307
|
-
{
|
|
308
|
-
description: "Structured payload when you need audit logs.",
|
|
309
|
-
name: "responseFormat",
|
|
310
|
-
required: false,
|
|
311
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
312
|
-
},
|
|
313
|
-
],
|
|
314
|
-
returns: "Deletion status plus previous node metadata when available.",
|
|
315
|
-
tool: TOOL_NAMES.DELETE_TD_NODE,
|
|
316
|
-
},
|
|
317
|
-
{
|
|
318
|
-
category: "nodes",
|
|
319
|
-
description: "Call TouchDesigner node methods directly",
|
|
320
|
-
example: `import { execNodeMethod } from './servers/touchdesigner/execNodeMethod';
|
|
321
|
-
|
|
322
|
-
const renderStatus = await execNodeMethod({
|
|
323
|
-
nodePath: '/project1/render1',
|
|
324
|
-
method: 'par',
|
|
325
|
-
kwargs: { enable: true },
|
|
326
|
-
});
|
|
327
|
-
console.log(renderStatus.result);`,
|
|
328
|
-
functionName: "execNodeMethod",
|
|
329
|
-
modulePath: `${MODULE_ROOT}/execNodeMethod.ts`,
|
|
330
|
-
parameters: [
|
|
331
|
-
{
|
|
332
|
-
description: "OP to target.",
|
|
333
|
-
name: "nodePath",
|
|
334
|
-
required: true,
|
|
335
|
-
type: "string",
|
|
336
|
-
},
|
|
337
|
-
{
|
|
338
|
-
description: "Name of the method to call on that operator.",
|
|
339
|
-
name: "method",
|
|
340
|
-
required: true,
|
|
341
|
-
type: "string",
|
|
342
|
-
},
|
|
343
|
-
{
|
|
344
|
-
description: "Positional arguments forwarded to the TouchDesigner API.",
|
|
345
|
-
name: "args",
|
|
346
|
-
required: false,
|
|
347
|
-
type: "Array<string | number | boolean>",
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
description: "Keyword arguments for the method call.",
|
|
351
|
-
name: "kwargs",
|
|
352
|
-
required: false,
|
|
353
|
-
type: "Record<string, unknown>",
|
|
354
|
-
},
|
|
355
|
-
{
|
|
356
|
-
description: "How much of the result payload to echo back.",
|
|
357
|
-
name: "detailLevel",
|
|
358
|
-
required: false,
|
|
359
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
360
|
-
},
|
|
361
|
-
{
|
|
362
|
-
description: "Switch to JSON when storing method responses.",
|
|
363
|
-
name: "responseFormat",
|
|
364
|
-
required: false,
|
|
365
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
366
|
-
},
|
|
367
|
-
],
|
|
368
|
-
returns: "Raw method return payload including any serializable values.",
|
|
369
|
-
tool: TOOL_NAMES.EXECUTE_NODE_METHOD,
|
|
370
|
-
},
|
|
371
|
-
{
|
|
372
|
-
category: "classes",
|
|
373
|
-
description: "List TouchDesigner Python classes/modules",
|
|
374
|
-
example: `import { getTdClasses } from './servers/touchdesigner/getTdClasses';
|
|
375
|
-
|
|
376
|
-
const classes = await getTdClasses({ limit: 20 });
|
|
377
|
-
console.log(classes.classes?.map(cls => cls.name));`,
|
|
378
|
-
functionName: "getTdClasses",
|
|
379
|
-
modulePath: `${MODULE_ROOT}/getTdClasses.ts`,
|
|
380
|
-
parameters: [
|
|
381
|
-
{
|
|
382
|
-
description: "Minimal returns only names, summary adds short descriptions.",
|
|
383
|
-
name: "detailLevel",
|
|
384
|
-
required: false,
|
|
385
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
386
|
-
},
|
|
387
|
-
{
|
|
388
|
-
description: "Restrict the number of classes returned to save tokens.",
|
|
389
|
-
name: "limit",
|
|
390
|
-
required: false,
|
|
391
|
-
type: "number",
|
|
392
|
-
},
|
|
393
|
-
{
|
|
394
|
-
description: "Return the catalog as JSON when writing caches.",
|
|
395
|
-
name: "responseFormat",
|
|
396
|
-
required: false,
|
|
397
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
398
|
-
},
|
|
399
|
-
],
|
|
400
|
-
returns: "Python class catalogue with names, types, and optional summaries.",
|
|
401
|
-
tool: TOOL_NAMES.GET_TD_CLASSES,
|
|
402
|
-
},
|
|
403
|
-
{
|
|
404
|
-
category: "classes",
|
|
405
|
-
description: "Fetch detailed docs for a TouchDesigner class or module",
|
|
406
|
-
example: `import { getTdClassDetails } from './servers/touchdesigner/getTdClassDetails';
|
|
407
|
-
|
|
408
|
-
const textTop = await getTdClassDetails({ className: 'textTOP' });
|
|
409
|
-
console.log(textTop.methods?.length);`,
|
|
410
|
-
functionName: "getTdClassDetails",
|
|
411
|
-
modulePath: `${MODULE_ROOT}/getTdClassDetails.ts`,
|
|
412
|
-
parameters: [
|
|
413
|
-
{
|
|
414
|
-
description: "Class/module name like textTOP or CHOP.",
|
|
415
|
-
name: "className",
|
|
416
|
-
required: true,
|
|
417
|
-
type: "string",
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
description: "Switch to detailed when generating docs.",
|
|
421
|
-
name: "detailLevel",
|
|
422
|
-
required: false,
|
|
423
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
424
|
-
},
|
|
425
|
-
{
|
|
426
|
-
description: "Cap how many methods/properties are surfaced.",
|
|
427
|
-
name: "limit",
|
|
428
|
-
required: false,
|
|
429
|
-
type: "number",
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
description: "Emit YAML or JSON for caching results to disk.",
|
|
433
|
-
name: "responseFormat",
|
|
434
|
-
required: false,
|
|
435
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
436
|
-
},
|
|
437
|
-
],
|
|
438
|
-
returns: "Deep description of a Python class including methods and properties.",
|
|
439
|
-
tool: TOOL_NAMES.GET_TD_CLASS_DETAILS,
|
|
440
|
-
},
|
|
441
|
-
{
|
|
442
|
-
category: "classes",
|
|
443
|
-
description: "Run Python help() to inspect documentation for TouchDesigner modules or classes",
|
|
444
|
-
example: `import { getTdModuleHelp } from './servers/touchdesigner/getTdModuleHelp';
|
|
445
|
-
|
|
446
|
-
const docs = await getTdModuleHelp({ moduleName: 'noiseCHOP' });
|
|
447
|
-
console.log(docs.helpText?.slice(0, 200));`,
|
|
448
|
-
functionName: "getTdModuleHelp",
|
|
449
|
-
modulePath: `${MODULE_ROOT}/getTdModuleHelp.ts`,
|
|
450
|
-
parameters: [
|
|
451
|
-
{
|
|
452
|
-
description: "Module or class name (e.g., 'noiseCHOP', 'td.noiseCHOP', 'tdu').",
|
|
453
|
-
name: "moduleName",
|
|
454
|
-
required: true,
|
|
455
|
-
type: "string",
|
|
456
|
-
},
|
|
457
|
-
{
|
|
458
|
-
description: "Controls how much of the help text is shown.",
|
|
459
|
-
name: "detailLevel",
|
|
460
|
-
required: false,
|
|
461
|
-
type: "'minimal' | 'summary' | 'detailed'",
|
|
462
|
-
},
|
|
463
|
-
{
|
|
464
|
-
description: "Select markdown/json/yaml output for automation.",
|
|
465
|
-
name: "responseFormat",
|
|
466
|
-
required: false,
|
|
467
|
-
type: "'json' | 'yaml' | 'markdown'",
|
|
468
|
-
},
|
|
469
|
-
],
|
|
470
|
-
returns: "Captured Python help() output with formatter context.",
|
|
471
|
-
tool: TOOL_NAMES.GET_TD_MODULE_HELP,
|
|
472
|
-
},
|
|
473
|
-
];
|
|
474
|
-
export function getTouchDesignerToolMetadata() {
|
|
475
|
-
return TOUCH_DESIGNER_TOOL_METADATA;
|
|
3
|
+
/** snake_case tool name -> camelCase function name (e.g. get_td_info -> getTdInfo). */
|
|
4
|
+
function toFunctionName(toolName) {
|
|
5
|
+
return toolName.replace(/_(.)/g, (_, char) => char.toUpperCase());
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Builds the `describe_td_tools` manifest from the tool table. Parameter
|
|
9
|
+
* metadata is introspected from each tool's Zod schema, so it always reflects
|
|
10
|
+
* the schema that is actually registered (sourced from the OpenAPI spec).
|
|
11
|
+
*/
|
|
12
|
+
export function buildToolMetadata(definitions = TOOL_DEFINITIONS) {
|
|
13
|
+
return definitions.map((definition) => {
|
|
14
|
+
const functionName = toFunctionName(definition.name);
|
|
15
|
+
return {
|
|
16
|
+
category: definition.category,
|
|
17
|
+
description: definition.description,
|
|
18
|
+
example: definition.example,
|
|
19
|
+
functionName,
|
|
20
|
+
modulePath: `${MODULE_ROOT}/${functionName}.ts`,
|
|
21
|
+
notes: definition.notes,
|
|
22
|
+
parameters: deriveParameters(definition.schema),
|
|
23
|
+
returns: definition.returns,
|
|
24
|
+
tool: definition.name,
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** Introspects a Zod object schema into flat parameter metadata. */
|
|
29
|
+
export function deriveParameters(schema) {
|
|
30
|
+
return Object.entries(schema.shape).map(([name, field]) => {
|
|
31
|
+
const { base, description, required } = unwrap(field);
|
|
32
|
+
return {
|
|
33
|
+
description,
|
|
34
|
+
name,
|
|
35
|
+
required,
|
|
36
|
+
type: renderType(base),
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/** Peels optional/default/nullable wrappers to reach the base type. */
|
|
41
|
+
function unwrap(field) {
|
|
42
|
+
let node = field;
|
|
43
|
+
let description = node.description;
|
|
44
|
+
let required = true;
|
|
45
|
+
while (node.def) {
|
|
46
|
+
if (description === undefined && node.description) {
|
|
47
|
+
description = node.description;
|
|
48
|
+
}
|
|
49
|
+
const type = node.def.type;
|
|
50
|
+
if (type === "optional" ||
|
|
51
|
+
type === "default" ||
|
|
52
|
+
type === "prefault" ||
|
|
53
|
+
type === "nullish") {
|
|
54
|
+
required = false;
|
|
55
|
+
}
|
|
56
|
+
if ((type === "optional" ||
|
|
57
|
+
type === "default" ||
|
|
58
|
+
type === "prefault" ||
|
|
59
|
+
type === "nullable" ||
|
|
60
|
+
type === "nullish") &&
|
|
61
|
+
node.def.innerType) {
|
|
62
|
+
node = node.def.innerType;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
return { base: node, description: description ?? node.description, required };
|
|
68
|
+
}
|
|
69
|
+
/** Renders a base Zod type as a TypeScript-flavored type string. */
|
|
70
|
+
function renderType(node) {
|
|
71
|
+
const def = node.def;
|
|
72
|
+
switch (def?.type) {
|
|
73
|
+
case "enum":
|
|
74
|
+
return Object.values(def.entries ?? {})
|
|
75
|
+
.map((value) => `'${value}'`)
|
|
76
|
+
.join(" | ");
|
|
77
|
+
case "string":
|
|
78
|
+
return "string";
|
|
79
|
+
case "number":
|
|
80
|
+
case "int":
|
|
81
|
+
return "number";
|
|
82
|
+
case "boolean":
|
|
83
|
+
return "boolean";
|
|
84
|
+
case "array":
|
|
85
|
+
return `Array<${def.element ? renderType(def.element) : "unknown"}>`;
|
|
86
|
+
case "record":
|
|
87
|
+
return `Record<${def.keyType ? renderType(def.keyType) : "string"}, ${def.valueType ? renderType(def.valueType) : "unknown"}>`;
|
|
88
|
+
case "union":
|
|
89
|
+
return (def.options ?? []).map(renderType).join(" | ");
|
|
90
|
+
case "unknown":
|
|
91
|
+
case "any":
|
|
92
|
+
return "unknown";
|
|
93
|
+
case "object":
|
|
94
|
+
return "object";
|
|
95
|
+
default:
|
|
96
|
+
return def?.type ?? "unknown";
|
|
97
|
+
}
|
|
476
98
|
}
|