zod-codegen 1.6.2 → 1.7.0

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.
Files changed (119) hide show
  1. package/.github/workflows/ci.yml +50 -48
  2. package/.github/workflows/release.yml +13 -3
  3. package/.husky/commit-msg +1 -1
  4. package/.husky/pre-commit +1 -1
  5. package/.lintstagedrc.json +5 -1
  6. package/.nvmrc +1 -1
  7. package/.prettierrc.json +12 -5
  8. package/CHANGELOG.md +15 -0
  9. package/CONTRIBUTING.md +12 -12
  10. package/EXAMPLES.md +135 -57
  11. package/PERFORMANCE.md +4 -4
  12. package/README.md +87 -64
  13. package/SECURITY.md +1 -1
  14. package/dist/src/cli.js +11 -18
  15. package/dist/src/generator.d.ts +2 -2
  16. package/dist/src/generator.d.ts.map +1 -1
  17. package/dist/src/generator.js +5 -3
  18. package/dist/src/interfaces/code-generator.d.ts.map +1 -1
  19. package/dist/src/services/code-generator.service.d.ts +24 -1
  20. package/dist/src/services/code-generator.service.d.ts.map +1 -1
  21. package/dist/src/services/code-generator.service.js +385 -216
  22. package/dist/src/services/file-reader.service.d.ts.map +1 -1
  23. package/dist/src/services/file-reader.service.js +1 -1
  24. package/dist/src/services/file-writer.service.d.ts.map +1 -1
  25. package/dist/src/services/file-writer.service.js +2 -2
  26. package/dist/src/services/import-builder.service.d.ts.map +1 -1
  27. package/dist/src/services/import-builder.service.js +3 -3
  28. package/dist/src/services/type-builder.service.d.ts.map +1 -1
  29. package/dist/src/types/generator-options.d.ts.map +1 -1
  30. package/dist/src/types/openapi.d.ts.map +1 -1
  31. package/dist/src/types/openapi.js +20 -20
  32. package/dist/src/utils/error-handler.d.ts.map +1 -1
  33. package/dist/src/utils/naming-convention.d.ts.map +1 -1
  34. package/dist/src/utils/naming-convention.js +6 -3
  35. package/dist/src/utils/signal-handler.d.ts.map +1 -1
  36. package/dist/tests/integration/cli-comprehensive.test.d.ts +2 -0
  37. package/dist/tests/integration/cli-comprehensive.test.d.ts.map +1 -0
  38. package/dist/tests/integration/cli-comprehensive.test.js +110 -0
  39. package/dist/tests/integration/cli.test.d.ts +2 -0
  40. package/dist/tests/integration/cli.test.d.ts.map +1 -0
  41. package/dist/tests/integration/cli.test.js +25 -0
  42. package/dist/tests/integration/error-scenarios.test.d.ts +2 -0
  43. package/dist/tests/integration/error-scenarios.test.d.ts.map +1 -0
  44. package/dist/tests/integration/error-scenarios.test.js +169 -0
  45. package/dist/tests/integration/snapshots.test.d.ts +2 -0
  46. package/dist/tests/integration/snapshots.test.d.ts.map +1 -0
  47. package/dist/tests/integration/snapshots.test.js +100 -0
  48. package/dist/tests/unit/code-generator-edge-cases.test.d.ts +2 -0
  49. package/dist/tests/unit/code-generator-edge-cases.test.d.ts.map +1 -0
  50. package/dist/tests/unit/code-generator-edge-cases.test.js +506 -0
  51. package/dist/tests/unit/code-generator.test.d.ts +2 -0
  52. package/dist/tests/unit/code-generator.test.d.ts.map +1 -0
  53. package/dist/tests/unit/code-generator.test.js +1364 -0
  54. package/dist/tests/unit/file-reader.test.d.ts +2 -0
  55. package/dist/tests/unit/file-reader.test.d.ts.map +1 -0
  56. package/dist/tests/unit/file-reader.test.js +125 -0
  57. package/dist/tests/unit/generator.test.d.ts +2 -0
  58. package/dist/tests/unit/generator.test.d.ts.map +1 -0
  59. package/dist/tests/unit/generator.test.js +119 -0
  60. package/dist/tests/unit/naming-convention.test.d.ts +2 -0
  61. package/dist/tests/unit/naming-convention.test.d.ts.map +1 -0
  62. package/dist/tests/unit/naming-convention.test.js +256 -0
  63. package/dist/tests/unit/reporter.test.d.ts +2 -0
  64. package/dist/tests/unit/reporter.test.d.ts.map +1 -0
  65. package/dist/tests/unit/reporter.test.js +44 -0
  66. package/dist/tests/unit/type-builder.test.d.ts +2 -0
  67. package/dist/tests/unit/type-builder.test.d.ts.map +1 -0
  68. package/dist/tests/unit/type-builder.test.js +108 -0
  69. package/dist/vitest.config.d.ts.map +1 -1
  70. package/dist/vitest.config.js +10 -20
  71. package/eslint.config.mjs +38 -28
  72. package/examples/.gitkeep +1 -1
  73. package/examples/README.md +4 -2
  74. package/examples/petstore/README.md +18 -17
  75. package/examples/petstore/{type.ts → api.ts} +158 -74
  76. package/examples/petstore/authenticated-usage.ts +6 -4
  77. package/examples/petstore/basic-usage.ts +4 -3
  78. package/examples/petstore/error-handling-usage.ts +84 -0
  79. package/examples/petstore/retry-handler-usage.ts +11 -18
  80. package/examples/petstore/server-variables-usage.ts +10 -10
  81. package/examples/pokeapi/README.md +8 -8
  82. package/examples/pokeapi/api.ts +218 -0
  83. package/examples/pokeapi/basic-usage.ts +3 -2
  84. package/examples/pokeapi/custom-client.ts +5 -4
  85. package/package.json +17 -21
  86. package/src/cli.ts +20 -25
  87. package/src/generator.ts +13 -11
  88. package/src/interfaces/code-generator.ts +1 -1
  89. package/src/services/code-generator.service.ts +989 -1099
  90. package/src/services/file-reader.service.ts +6 -5
  91. package/src/services/file-writer.service.ts +7 -7
  92. package/src/services/import-builder.service.ts +9 -13
  93. package/src/services/type-builder.service.ts +8 -19
  94. package/src/types/generator-options.ts +1 -1
  95. package/src/types/openapi.ts +22 -22
  96. package/src/utils/error-handler.ts +2 -2
  97. package/src/utils/naming-convention.ts +13 -10
  98. package/src/utils/reporter.ts +2 -2
  99. package/src/utils/signal-handler.ts +7 -8
  100. package/tests/integration/cli-comprehensive.test.ts +38 -32
  101. package/tests/integration/cli.test.ts +5 -5
  102. package/tests/integration/error-scenarios.test.ts +20 -26
  103. package/tests/integration/snapshots.test.ts +19 -23
  104. package/tests/unit/code-generator-edge-cases.test.ts +133 -133
  105. package/tests/unit/code-generator.test.ts +674 -268
  106. package/tests/unit/file-reader.test.ts +14 -14
  107. package/tests/unit/generator.test.ts +30 -18
  108. package/tests/unit/naming-convention.test.ts +27 -27
  109. package/tests/unit/type-builder.test.ts +2 -2
  110. package/tsconfig.json +5 -3
  111. package/vitest.config.ts +11 -21
  112. package/dist/scripts/update-manifest.d.ts +0 -14
  113. package/dist/scripts/update-manifest.d.ts.map +0 -1
  114. package/dist/scripts/update-manifest.js +0 -33
  115. package/dist/src/assets/manifest.json +0 -5
  116. package/examples/pokeapi/type.ts +0 -109
  117. package/generated/type.ts +0 -326
  118. package/scripts/update-manifest.ts +0 -49
  119. package/src/assets/manifest.json +0 -5
@@ -1,23 +1,17 @@
1
- import jp from 'jsonpath';
2
1
  import * as ts from 'typescript';
3
- import {z} from 'zod';
4
- import type {CodeGenerator, SchemaBuilder} from '../interfaces/code-generator';
5
- import type {MethodSchemaType, OpenApiSpecType, ReferenceType} from '../types/openapi';
6
- import type {GeneratorOptions} from '../types/generator-options';
7
- import {MethodSchema, Reference, SchemaProperties} from '../types/openapi';
8
- import {TypeScriptImportBuilderService} from './import-builder.service';
9
- import {TypeScriptTypeBuilderService} from './type-builder.service';
10
- import {
11
- type NamingConvention,
12
- type OperationDetails,
13
- type OperationNameTransformer,
14
- transformNamingConvention,
15
- } from '../utils/naming-convention';
2
+ import { z } from 'zod';
3
+ import type { CodeGenerator, SchemaBuilder } from '../interfaces/code-generator';
4
+ import type { GeneratorOptions } from '../types/generator-options';
5
+ import type { MethodSchemaType, OpenApiSpecType, ReferenceType } from '../types/openapi';
6
+ import { MethodSchema, Reference, SchemaProperties } from '../types/openapi';
7
+ import { type NamingConvention, type OperationDetails, type OperationNameTransformer, transformNamingConvention } from '../utils/naming-convention';
8
+ import { TypeScriptImportBuilderService } from './import-builder.service';
9
+ import { TypeScriptTypeBuilderService } from './type-builder.service';
16
10
 
17
11
  export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuilder {
18
12
  private readonly typeBuilder = new TypeScriptTypeBuilderService();
19
13
  private readonly importBuilder = new TypeScriptImportBuilderService();
20
- private readonly printer = ts.createPrinter({newLine: ts.NewLineKind.LineFeed});
14
+ private readonly printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
21
15
  private readonly namingConvention: NamingConvention | undefined;
22
16
  private readonly operationNameTransformer: OperationNameTransformer | undefined;
23
17
 
@@ -32,11 +26,40 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
32
26
 
33
27
  private readonly ZodAST = z.object({
34
28
  type: z.enum(['string', 'number', 'boolean', 'object', 'array', 'unknown', 'record']),
35
- args: z.array(z.unknown()).optional(),
29
+ args: z.array(z.unknown()).optional()
36
30
  });
37
31
 
32
+ private extractSchemaReferences(schema: unknown): string[] {
33
+ const references = new Set<string>();
34
+
35
+ const walk = (node: unknown): void => {
36
+ if (Array.isArray(node)) {
37
+ for (const item of node) {
38
+ walk(item);
39
+ }
40
+ return;
41
+ }
42
+
43
+ if (node === null || typeof node !== 'object') {
44
+ return;
45
+ }
46
+
47
+ for (const [key, value] of Object.entries(node as Record<string, unknown>)) {
48
+ if (key === '$ref' && typeof value === 'string' && value.startsWith('#/components/schemas/')) {
49
+ references.add(value.replace('#/components/schemas/', ''));
50
+ continue;
51
+ }
52
+
53
+ walk(value);
54
+ }
55
+ };
56
+
57
+ walk(schema);
58
+ return [...references];
59
+ }
60
+
38
61
  generate(spec: OpenApiSpecType): string {
39
- const file = ts.createSourceFile('generated.ts', '', ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
62
+ const file = ts.createSourceFile('api.ts', '', ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
40
63
  const nodes = this.buildAST(spec);
41
64
  return this.printer.printList(ts.ListFormat.MultiLine, ts.factory.createNodeArray(nodes), file);
42
65
  }
@@ -75,15 +98,20 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
75
98
  const serverConfig = this.buildServerConfiguration(openapi);
76
99
  const clientClass = this.buildClientClass(openapi, schemas);
77
100
 
101
+ const explicitTypeDeclarations = this.buildExplicitTypeDeclarations(openapi);
102
+
78
103
  return [
79
104
  this.createComment('Imports'),
80
105
  ...imports,
106
+ this.createComment('Explicit type declarations'),
107
+ ...explicitTypeDeclarations,
81
108
  this.createComment('Components schemas'),
82
109
  ...Object.values(schemas),
83
110
  ...schemaTypeAliases,
84
111
  ...serverConfig,
112
+ this.buildResponseValidationErrorClass(),
85
113
  this.createComment('Client class'),
86
- clientClass,
114
+ clientClass
87
115
  ];
88
116
  }
89
117
 
@@ -98,7 +126,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
98
126
 
99
127
  return sortedSchemaNames.reduce<Record<string, ts.VariableStatement>>((schemaRegistered, name) => {
100
128
  const schema = openapi.components?.schemas?.[name];
101
- if (!schema) return schemaRegistered;
129
+ if (!schema) {
130
+ return schemaRegistered;
131
+ }
102
132
 
103
133
  // Set context for current schema being built
104
134
  this.currentSchemaName = name;
@@ -108,47 +138,321 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
108
138
  // Clear context
109
139
  this.currentSchemaName = null;
110
140
 
141
+ const sanitizedName = this.typeBuilder.sanitizeIdentifier(name);
142
+
143
+ // Add type annotation: z.ZodType<Name>
144
+ const typeAnnotation = ts.factory.createTypeReferenceNode(ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('ZodType')), [
145
+ ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedName), undefined)
146
+ ]);
147
+
111
148
  const variableStatement = ts.factory.createVariableStatement(
112
149
  [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
113
150
  ts.factory.createVariableDeclarationList(
114
- [
115
- ts.factory.createVariableDeclaration(
116
- ts.factory.createIdentifier(this.typeBuilder.sanitizeIdentifier(name)),
117
- undefined,
118
- undefined,
119
- schemaExpression,
120
- ),
121
- ],
122
- ts.NodeFlags.Const,
123
- ),
151
+ [ts.factory.createVariableDeclaration(ts.factory.createIdentifier(sanitizedName), undefined, typeAnnotation, schemaExpression)],
152
+ ts.NodeFlags.Const
153
+ )
124
154
  );
125
155
 
126
156
  return {
127
157
  ...schemaRegistered,
128
- [name]: variableStatement,
158
+ [name]: variableStatement
129
159
  };
130
160
  }, {});
131
161
  }
132
162
 
133
- private buildSchemaTypeAliases(schemas: Record<string, ts.VariableStatement>): ts.TypeAliasDeclaration[] {
134
- return Object.keys(schemas).map((name) => {
163
+ private buildSchemaTypeAliases(_schemas: Record<string, ts.VariableStatement>): ts.TypeAliasDeclaration[] {
164
+ // Explicit type declarations are used instead of z.infer type exports
165
+ return [];
166
+ }
167
+
168
+ /**
169
+ * Builds explicit TypeScript type declarations for all schemas.
170
+ * Returns interface declarations for object types and type aliases for other types.
171
+ */
172
+ private buildExplicitTypeDeclarations(openapi: OpenApiSpecType): ts.Statement[] {
173
+ const schemasEntries = Object.entries(openapi.components?.schemas ?? {});
174
+ const schemasMap = Object.fromEntries(schemasEntries);
175
+ const sortedSchemaNames = this.topologicalSort(schemasMap);
176
+
177
+ const statements: ts.Statement[] = [];
178
+
179
+ for (const name of sortedSchemaNames) {
180
+ const schema = openapi.components?.schemas?.[name];
181
+ if (!schema) {
182
+ continue;
183
+ }
184
+
135
185
  const sanitizedName = this.typeBuilder.sanitizeIdentifier(name);
136
- return ts.factory.createTypeAliasDeclaration(
137
- [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
138
- ts.factory.createIdentifier(sanitizedName),
186
+ const safeSchema = SchemaProperties.safeParse(schema);
187
+
188
+ if (!safeSchema.success) {
189
+ // Unknown schema type, create a type alias to unknown
190
+ statements.push(
191
+ ts.factory.createTypeAliasDeclaration(
192
+ [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
193
+ ts.factory.createIdentifier(sanitizedName),
194
+ undefined,
195
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)
196
+ )
197
+ );
198
+ continue;
199
+ }
200
+
201
+ const schemaData = safeSchema.data;
202
+ const typeNode = this.buildTypeNode(schemaData);
203
+
204
+ // For object types with properties, create an interface
205
+ if (schemaData['type'] === 'object' && schemaData['properties']) {
206
+ statements.push(this.buildInterfaceDeclaration(sanitizedName, schemaData));
207
+ continue;
208
+ }
209
+
210
+ // For all other types (enums, arrays, unions, etc.), create a type alias
211
+ statements.push(
212
+ ts.factory.createTypeAliasDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(sanitizedName), undefined, typeNode)
213
+ );
214
+ }
215
+
216
+ return statements;
217
+ }
218
+
219
+ /**
220
+ * Converts an OpenAPI schema to a TypeScript type node.
221
+ */
222
+ private buildTypeNode(schema: unknown): ts.TypeNode {
223
+ const safeSchema = SchemaProperties.safeParse(schema);
224
+ if (!safeSchema.success) {
225
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
226
+ }
227
+
228
+ const prop = safeSchema.data;
229
+
230
+ // Handle $ref
231
+ if (this.isReference(prop)) {
232
+ const { $ref = '' } = Reference.parse(prop);
233
+ const refName = $ref.split('/').pop() ?? 'never';
234
+ const sanitizedRefName = this.typeBuilder.sanitizeIdentifier(refName);
235
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedRefName), undefined);
236
+ }
237
+
238
+ // Handle nullable
239
+ const isNullable = prop['nullable'] === true;
240
+ const baseTypeNode = this.buildBaseTypeNode(prop);
241
+
242
+ if (isNullable) {
243
+ return ts.factory.createUnionTypeNode([baseTypeNode, ts.factory.createLiteralTypeNode(ts.factory.createNull())]);
244
+ }
245
+
246
+ return baseTypeNode;
247
+ }
248
+
249
+ /**
250
+ * Builds the base type node without nullable handling.
251
+ */
252
+ private buildBaseTypeNode(prop: Record<string, unknown>): ts.TypeNode {
253
+ // Handle anyOf/oneOf (union types)
254
+ if (prop['anyOf'] && Array.isArray(prop['anyOf']) && prop['anyOf'].length > 0) {
255
+ const types = prop['anyOf'].map((s: unknown) => this.buildTypeNode(s));
256
+ return ts.factory.createUnionTypeNode(types);
257
+ }
258
+
259
+ if (prop['oneOf'] && Array.isArray(prop['oneOf']) && prop['oneOf'].length > 0) {
260
+ const types = prop['oneOf'].map((s: unknown) => this.buildTypeNode(s));
261
+ return ts.factory.createUnionTypeNode(types);
262
+ }
263
+
264
+ // Handle allOf (intersection types)
265
+ if (prop['allOf'] && Array.isArray(prop['allOf']) && prop['allOf'].length > 0) {
266
+ const types = prop['allOf'].map((s: unknown) => this.buildTypeNode(s));
267
+ return ts.factory.createIntersectionTypeNode(types);
268
+ }
269
+
270
+ // Handle enum
271
+ if (prop['enum'] && Array.isArray(prop['enum']) && prop['enum'].length > 0) {
272
+ const literalTypes = prop['enum'].map((val: unknown) => {
273
+ if (typeof val === 'string') {
274
+ return ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(val, true));
275
+ } else if (typeof val === 'number') {
276
+ if (val < 0) {
277
+ return ts.factory.createLiteralTypeNode(ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(String(Math.abs(val)))));
278
+ }
279
+
280
+ return ts.factory.createLiteralTypeNode(ts.factory.createNumericLiteral(String(val)));
281
+ } else if (typeof val === 'boolean') {
282
+ return ts.factory.createLiteralTypeNode(val ? ts.factory.createTrue() : ts.factory.createFalse());
283
+ }
284
+
285
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
286
+ });
287
+ return ts.factory.createUnionTypeNode(literalTypes);
288
+ }
289
+
290
+ // Handle type-specific schemas
291
+ switch (prop['type']) {
292
+ case 'string':
293
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
294
+ case 'number':
295
+ case 'integer':
296
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
297
+ case 'boolean':
298
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
299
+ case 'array': {
300
+ const itemsType = prop['items'] ? this.buildTypeNode(prop['items']) : ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
301
+ return ts.factory.createArrayTypeNode(itemsType);
302
+ }
303
+ case 'object': {
304
+ const properties = (prop['properties'] ?? {}) as Record<string, unknown>;
305
+ const requiredProps = (prop['required'] ?? []) as string[];
306
+
307
+ if (Object.keys(properties).length > 0) {
308
+ return this.buildObjectTypeLiteral(properties, requiredProps);
309
+ }
310
+
311
+ // Empty object or additionalProperties - use Record<string, unknown>
312
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Record'), [
313
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
314
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)
315
+ ]);
316
+ }
317
+ default:
318
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Builds a TypeScript type literal for an object schema.
324
+ */
325
+ private buildObjectTypeLiteral(properties: Record<string, unknown>, requiredProps: string[]): ts.TypeLiteralNode {
326
+ const members = Object.entries(properties).map(([name, propSchema]) => {
327
+ const isRequired = requiredProps.includes(name);
328
+ const typeNode = this.buildTypeNode(propSchema);
329
+
330
+ return ts.factory.createPropertySignature(
139
331
  undefined,
140
- ts.factory.createTypeReferenceNode(
141
- ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('infer')),
142
- [ts.factory.createTypeQueryNode(ts.factory.createIdentifier(sanitizedName), undefined)],
143
- ),
332
+ ts.factory.createIdentifier(name),
333
+ isRequired ? undefined : ts.factory.createToken(ts.SyntaxKind.QuestionToken),
334
+ typeNode
335
+ );
336
+ });
337
+
338
+ return ts.factory.createTypeLiteralNode(members);
339
+ }
340
+
341
+ /**
342
+ * Builds a TypeScript interface declaration for an object schema.
343
+ */
344
+ private buildInterfaceDeclaration(name: string, schema: Record<string, unknown>): ts.InterfaceDeclaration {
345
+ const properties = (schema['properties'] ?? {}) as Record<string, unknown>;
346
+ const requiredProps = (schema['required'] ?? []) as string[];
347
+
348
+ const members = Object.entries(properties).map(([propName, propSchema]) => {
349
+ const isRequired = requiredProps.includes(propName);
350
+ const typeNode = this.buildTypeNode(propSchema);
351
+
352
+ return ts.factory.createPropertySignature(
353
+ undefined,
354
+ ts.factory.createIdentifier(propName),
355
+ isRequired ? undefined : ts.factory.createToken(ts.SyntaxKind.QuestionToken),
356
+ typeNode
144
357
  );
145
358
  });
359
+
360
+ return ts.factory.createInterfaceDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(name), undefined, undefined, members);
146
361
  }
147
362
 
148
- private buildClientClass(
149
- openapi: OpenApiSpecType,
150
- schemas: Record<string, ts.VariableStatement>,
151
- ): ts.ClassDeclaration {
363
+ private buildResponseValidationErrorClass(): ts.ClassDeclaration {
364
+ const typeParamT = ts.factory.createTypeParameterDeclaration(undefined, 'T');
365
+
366
+ const responseProperty = ts.factory.createPropertyDeclaration(
367
+ [ts.factory.createToken(ts.SyntaxKind.ReadonlyKeyword)],
368
+ 'response',
369
+ undefined,
370
+ ts.factory.createTypeReferenceNode('Response'),
371
+ undefined
372
+ );
373
+
374
+ const errorProperty = ts.factory.createPropertyDeclaration(
375
+ [ts.factory.createToken(ts.SyntaxKind.ReadonlyKeyword)],
376
+ 'error',
377
+ undefined,
378
+ ts.factory.createTypeReferenceNode(ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), 'ZodError'), [ts.factory.createTypeReferenceNode('T')]),
379
+ undefined
380
+ );
381
+
382
+ const constructorDecl = ts.factory.createConstructorDeclaration(
383
+ undefined,
384
+ [
385
+ ts.factory.createParameterDeclaration(undefined, undefined, 'message', undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)),
386
+ ts.factory.createParameterDeclaration(undefined, undefined, 'response', undefined, ts.factory.createTypeReferenceNode('Response')),
387
+ ts.factory.createParameterDeclaration(
388
+ undefined,
389
+ undefined,
390
+ 'error',
391
+ undefined,
392
+ ts.factory.createTypeReferenceNode(ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), 'ZodError'), [ts.factory.createTypeReferenceNode('T')])
393
+ )
394
+ ],
395
+ ts.factory.createBlock(
396
+ [
397
+ ts.factory.createExpressionStatement(ts.factory.createCallExpression(ts.factory.createSuper(), undefined, [ts.factory.createIdentifier('message')])),
398
+ ts.factory.createExpressionStatement(
399
+ ts.factory.createBinaryExpression(
400
+ ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'name'),
401
+ ts.SyntaxKind.EqualsToken,
402
+ ts.factory.createAsExpression(ts.factory.createStringLiteral('ResponseValidationError', true), ts.factory.createTypeReferenceNode('const'))
403
+ )
404
+ ),
405
+ ts.factory.createExpressionStatement(
406
+ ts.factory.createBinaryExpression(
407
+ ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'response'),
408
+ ts.SyntaxKind.EqualsToken,
409
+ ts.factory.createIdentifier('response')
410
+ )
411
+ ),
412
+ ts.factory.createExpressionStatement(
413
+ ts.factory.createBinaryExpression(
414
+ ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'error'),
415
+ ts.SyntaxKind.EqualsToken,
416
+ ts.factory.createIdentifier('error')
417
+ )
418
+ )
419
+ ],
420
+ true
421
+ )
422
+ );
423
+
424
+ const dataGetter = ts.factory.createGetAccessorDeclaration(
425
+ undefined,
426
+ 'data',
427
+ [],
428
+ ts.factory.createTypeReferenceNode('T'),
429
+ ts.factory.createBlock(
430
+ [
431
+ ts.factory.createReturnStatement(
432
+ ts.factory.createAsExpression(
433
+ ts.factory.createCallExpression(
434
+ ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(ts.factory.createThis(), 'response'), 'json'),
435
+ undefined,
436
+ []
437
+ ),
438
+ ts.factory.createTypeReferenceNode('T')
439
+ )
440
+ )
441
+ ],
442
+ true
443
+ )
444
+ );
445
+
446
+ return ts.factory.createClassDeclaration(
447
+ [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
448
+ 'ResponseValidationError',
449
+ [typeParamT],
450
+ [ts.factory.createHeritageClause(ts.SyntaxKind.ExtendsKeyword, [ts.factory.createExpressionWithTypeArguments(ts.factory.createIdentifier('Error'), undefined)])],
451
+ [responseProperty, errorProperty, constructorDecl, dataGetter]
452
+ );
453
+ }
454
+
455
+ private buildClientClass(openapi: OpenApiSpecType, schemas: Record<string, ts.VariableStatement>): ts.ClassDeclaration {
152
456
  const clientName = this.generateClientName(openapi.info.title);
153
457
  const methods = this.buildClientMethods(openapi, schemas);
154
458
 
@@ -163,8 +467,8 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
163
467
  this.buildGetBaseRequestOptionsMethod(),
164
468
  this.buildHandleResponseMethod(),
165
469
  this.buildHttpRequestMethod(),
166
- ...methods,
167
- ],
470
+ ...methods
471
+ ]
168
472
  );
169
473
  }
170
474
 
@@ -182,8 +486,8 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
182
486
  ts.factory.createIdentifier('options'),
183
487
  undefined,
184
488
  ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('ClientOptions'), undefined),
185
- undefined,
186
- ),
489
+ undefined
490
+ )
187
491
  ],
188
492
  ts.factory.createBlock(
189
493
  [
@@ -197,72 +501,51 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
197
501
  undefined,
198
502
  ts.factory.createConditionalExpression(
199
503
  ts.factory.createBinaryExpression(
200
- ts.factory.createPropertyAccessExpression(
201
- ts.factory.createIdentifier('options'),
202
- ts.factory.createIdentifier('baseUrl'),
203
- ),
504
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('baseUrl')),
204
505
  ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsEqualsToken),
205
- ts.factory.createNull(),
506
+ ts.factory.createNull()
206
507
  ),
207
508
  ts.factory.createToken(ts.SyntaxKind.QuestionToken),
208
- ts.factory.createPropertyAccessExpression(
209
- ts.factory.createIdentifier('options'),
210
- ts.factory.createIdentifier('baseUrl'),
211
- ),
509
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('baseUrl')),
212
510
  ts.factory.createToken(ts.SyntaxKind.ColonToken),
213
511
  ts.factory.createCallExpression(ts.factory.createIdentifier('resolveServerUrl'), undefined, [
214
- ts.factory.createPropertyAccessExpression(
215
- ts.factory.createIdentifier('options'),
216
- ts.factory.createIdentifier('serverIndex'),
217
- ),
218
- ts.factory.createPropertyAccessExpression(
219
- ts.factory.createIdentifier('options'),
220
- ts.factory.createIdentifier('serverVariables'),
221
- ),
222
- ]),
223
- ),
224
- ),
512
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('serverIndex')),
513
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('serverVariables'))
514
+ ])
515
+ )
516
+ )
225
517
  ],
226
- ts.NodeFlags.Const,
227
- ),
518
+ ts.NodeFlags.Const
519
+ )
228
520
  ),
229
521
  ts.factory.createExpressionStatement(
230
522
  ts.factory.createBinaryExpression(
231
- ts.factory.createPropertyAccessExpression(
232
- ts.factory.createThis(),
233
- ts.factory.createPrivateIdentifier('#baseUrl'),
234
- ),
523
+ ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createPrivateIdentifier('#baseUrl')),
235
524
  ts.factory.createToken(ts.SyntaxKind.EqualsToken),
236
- ts.factory.createIdentifier('resolvedUrl'),
237
- ),
238
- ),
525
+ ts.factory.createIdentifier('resolvedUrl')
526
+ )
527
+ )
239
528
  ],
240
- true,
241
- ),
529
+ true
530
+ )
242
531
  );
243
532
  } else {
244
533
  // Fallback: simple baseUrl parameter
245
534
  return ts.factory.createConstructorDeclaration(
246
535
  undefined,
247
- [
248
- this.typeBuilder.createParameter('baseUrl', 'string', ts.factory.createStringLiteral('/', true)),
249
- this.typeBuilder.createParameter('_', 'unknown', undefined, true),
250
- ],
536
+ [this.typeBuilder.createParameter('baseUrl', 'string', ts.factory.createStringLiteral('/', true)), this.typeBuilder.createParameter('_', 'unknown', undefined, true)],
251
537
  ts.factory.createBlock(
252
538
  [
253
539
  ts.factory.createExpressionStatement(
254
540
  ts.factory.createBinaryExpression(
255
- ts.factory.createPropertyAccessExpression(
256
- ts.factory.createThis(),
257
- ts.factory.createPrivateIdentifier('#baseUrl'),
258
- ),
541
+ ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createPrivateIdentifier('#baseUrl')),
259
542
  ts.factory.createToken(ts.SyntaxKind.EqualsToken),
260
- ts.factory.createIdentifier('baseUrl'),
261
- ),
262
- ),
543
+ ts.factory.createIdentifier('baseUrl')
544
+ )
545
+ )
263
546
  ],
264
- true,
265
- ),
547
+ true
548
+ )
266
549
  );
267
550
  }
268
551
  }
@@ -280,14 +563,11 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
280
563
  ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('RequestInit'), undefined),
281
564
  ts.factory.createUnionTypeNode([
282
565
  ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral('method', true)),
283
- ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral('body', true)),
284
- ]),
285
- ]),
566
+ ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral('body', true))
567
+ ])
568
+ ])
286
569
  ]),
287
- ts.factory.createBlock(
288
- [ts.factory.createReturnStatement(ts.factory.createObjectLiteralExpression([], false))],
289
- true,
290
- ),
570
+ ts.factory.createBlock([ts.factory.createReturnStatement(ts.factory.createObjectLiteralExpression([], false))], true)
291
571
  );
292
572
  }
293
573
 
@@ -302,15 +582,10 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
302
582
  this.typeBuilder.createParameter('response', 'Response'),
303
583
  this.typeBuilder.createParameter('method', 'string'),
304
584
  this.typeBuilder.createParameter('path', 'string'),
305
- this.typeBuilder.createParameter(
306
- 'options',
307
- '{params?: Record<string, string | number | boolean>; data?: unknown; contentType?: string; headers?: Record<string, string>}',
308
- ),
585
+ this.typeBuilder.createParameter('options', '{params?: Record<string, string | number | boolean>; data?: unknown; contentType?: string; headers?: Record<string, string>}')
309
586
  ],
310
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
311
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Response'), undefined),
312
- ]),
313
- ts.factory.createBlock([ts.factory.createReturnStatement(ts.factory.createIdentifier('response'))], true),
587
+ ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Response'), undefined)]),
588
+ ts.factory.createBlock([ts.factory.createReturnStatement(ts.factory.createIdentifier('response'))], true)
314
589
  );
315
590
  }
316
591
 
@@ -328,12 +603,10 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
328
603
  'options',
329
604
  '{params?: Record<string, string | number | boolean>; data?: unknown; contentType?: string; headers?: Record<string, string>}',
330
605
  ts.factory.createObjectLiteralExpression([], false),
331
- false,
332
- ),
606
+ false
607
+ )
333
608
  ],
334
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
335
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('T'), undefined),
336
- ]),
609
+ ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('T'), undefined)]),
337
610
  ts.factory.createBlock(
338
611
  [
339
612
  // Create initial URL object that we will use to build the final URL
@@ -347,15 +620,12 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
347
620
  undefined,
348
621
  ts.factory.createNewExpression(ts.factory.createIdentifier('URL'), undefined, [
349
622
  ts.factory.createIdentifier('path'),
350
- ts.factory.createPropertyAccessExpression(
351
- ts.factory.createThis(),
352
- ts.factory.createPrivateIdentifier('#baseUrl'),
353
- ),
354
- ]),
355
- ),
623
+ ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createPrivateIdentifier('#baseUrl'))
624
+ ])
625
+ )
356
626
  ],
357
- ts.NodeFlags.Const,
358
- ),
627
+ ts.NodeFlags.Const
628
+ )
359
629
  ),
360
630
  ts.factory.createVariableStatement(
361
631
  undefined,
@@ -367,31 +637,20 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
367
637
  undefined,
368
638
  ts.factory.createConditionalExpression(
369
639
  ts.factory.createBinaryExpression(
370
- ts.factory.createPropertyAccessExpression(
371
- ts.factory.createIdentifier('options'),
372
- ts.factory.createIdentifier('params'),
373
- ),
640
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('params')),
374
641
  ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken),
375
642
  ts.factory.createBinaryExpression(
376
643
  ts.factory.createPropertyAccessExpression(
377
644
  ts.factory.createCallExpression(
378
- ts.factory.createPropertyAccessExpression(
379
- ts.factory.createIdentifier('Object'),
380
- ts.factory.createIdentifier('keys'),
381
- ),
645
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('keys')),
382
646
  undefined,
383
- [
384
- ts.factory.createPropertyAccessExpression(
385
- ts.factory.createIdentifier('options'),
386
- ts.factory.createIdentifier('params'),
387
- ),
388
- ],
647
+ [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('params'))]
389
648
  ),
390
- ts.factory.createIdentifier('length'),
649
+ ts.factory.createIdentifier('length')
391
650
  ),
392
651
  ts.factory.createToken(ts.SyntaxKind.GreaterThanToken),
393
- ts.factory.createNumericLiteral('0'),
394
- ),
652
+ ts.factory.createNumericLiteral('0')
653
+ )
395
654
  ),
396
655
  undefined,
397
656
  ts.factory.createCallExpression(
@@ -410,19 +669,11 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
410
669
  ts.factory.createCallExpression(
411
670
  ts.factory.createPropertyAccessExpression(
412
671
  ts.factory.createCallExpression(
413
- ts.factory.createPropertyAccessExpression(
414
- ts.factory.createIdentifier('Object'),
415
- ts.factory.createIdentifier('entries'),
416
- ),
672
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('entries')),
417
673
  undefined,
418
- [
419
- ts.factory.createPropertyAccessExpression(
420
- ts.factory.createIdentifier('options'),
421
- ts.factory.createIdentifier('params'),
422
- ),
423
- ],
674
+ [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('params'))]
424
675
  ),
425
- ts.factory.createIdentifier('filter'),
676
+ ts.factory.createIdentifier('filter')
426
677
  ),
427
678
  undefined,
428
679
  [
@@ -434,34 +685,24 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
434
685
  undefined,
435
686
  undefined,
436
687
  ts.factory.createArrayBindingPattern([
437
- ts.factory.createBindingElement(
438
- undefined,
439
- undefined,
440
- ts.factory.createIdentifier(''),
441
- undefined,
442
- ),
443
- ts.factory.createBindingElement(
444
- undefined,
445
- undefined,
446
- ts.factory.createIdentifier('value'),
447
- undefined,
448
- ),
688
+ ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier(''), undefined),
689
+ ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier('value'), undefined)
449
690
  ]),
450
691
  undefined,
451
- undefined,
452
- ),
692
+ undefined
693
+ )
453
694
  ],
454
695
  undefined,
455
696
  ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
456
697
  ts.factory.createBinaryExpression(
457
698
  ts.factory.createIdentifier('value'),
458
699
  ts.SyntaxKind.ExclamationEqualsEqualsToken,
459
- ts.factory.createIdentifier('undefined'),
460
- ),
461
- ),
462
- ],
700
+ ts.factory.createIdentifier('undefined')
701
+ )
702
+ )
703
+ ]
463
704
  ),
464
- ts.factory.createIdentifier('forEach'),
705
+ ts.factory.createIdentifier('forEach')
465
706
  ),
466
707
  undefined,
467
708
  [
@@ -473,22 +714,12 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
473
714
  undefined,
474
715
  undefined,
475
716
  ts.factory.createArrayBindingPattern([
476
- ts.factory.createBindingElement(
477
- undefined,
478
- undefined,
479
- ts.factory.createIdentifier('key'),
480
- undefined,
481
- ),
482
- ts.factory.createBindingElement(
483
- undefined,
484
- undefined,
485
- ts.factory.createIdentifier('value'),
486
- undefined,
487
- ),
717
+ ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier('key'), undefined),
718
+ ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier('value'), undefined)
488
719
  ]),
489
720
  undefined,
490
- undefined,
491
- ),
721
+ undefined
722
+ )
492
723
  ],
493
724
  undefined,
494
725
  ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
@@ -497,62 +728,49 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
497
728
  ts.factory.createExpressionStatement(
498
729
  ts.factory.createCallExpression(
499
730
  ts.factory.createPropertyAccessExpression(
500
- ts.factory.createPropertyAccessExpression(
501
- ts.factory.createIdentifier('baseUrl'),
502
- ts.factory.createIdentifier('searchParams'),
503
- ),
504
- ts.factory.createIdentifier('set'),
731
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('baseUrl'), ts.factory.createIdentifier('searchParams')),
732
+ ts.factory.createIdentifier('set')
505
733
  ),
506
734
  undefined,
507
735
  [
508
736
  ts.factory.createIdentifier('key'),
509
- ts.factory.createCallExpression(
510
- ts.factory.createIdentifier('String'),
511
- undefined,
512
- [ts.factory.createIdentifier('value')],
513
- ),
514
- ],
515
- ),
516
- ),
737
+ ts.factory.createCallExpression(ts.factory.createIdentifier('String'), undefined, [ts.factory.createIdentifier('value')])
738
+ ]
739
+ )
740
+ )
517
741
  ],
518
- false,
519
- ),
520
- ),
521
- ],
522
- ),
742
+ false
743
+ )
744
+ )
745
+ ]
746
+ )
523
747
  ),
524
748
  ts.factory.createReturnStatement(
525
749
  ts.factory.createCallExpression(
526
- ts.factory.createPropertyAccessExpression(
527
- ts.factory.createIdentifier('baseUrl'),
528
- ts.factory.createIdentifier('toString'),
529
- ),
750
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('baseUrl'), ts.factory.createIdentifier('toString')),
530
751
  undefined,
531
- [],
532
- ),
533
- ),
752
+ []
753
+ )
754
+ )
534
755
  ],
535
- true,
536
- ),
537
- ),
756
+ true
757
+ )
758
+ )
538
759
  ),
539
760
  undefined,
540
- [],
761
+ []
541
762
  ),
542
763
  undefined,
543
764
  ts.factory.createCallExpression(
544
- ts.factory.createPropertyAccessExpression(
545
- ts.factory.createIdentifier('baseUrl'),
546
- ts.factory.createIdentifier('toString'),
547
- ),
765
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('baseUrl'), ts.factory.createIdentifier('toString')),
548
766
  undefined,
549
- [],
550
- ),
551
- ),
552
- ),
767
+ []
768
+ )
769
+ )
770
+ )
553
771
  ],
554
- ts.NodeFlags.Const,
555
- ),
772
+ ts.NodeFlags.Const
773
+ )
556
774
  ),
557
775
  // Get base request options (headers, signal, credentials, etc.)
558
776
  ts.factory.createVariableStatement(
@@ -564,17 +782,14 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
564
782
  undefined,
565
783
  undefined,
566
784
  ts.factory.createCallExpression(
567
- ts.factory.createPropertyAccessExpression(
568
- ts.factory.createThis(),
569
- ts.factory.createIdentifier('getBaseRequestOptions'),
570
- ),
785
+ ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createIdentifier('getBaseRequestOptions')),
571
786
  undefined,
572
- [],
573
- ),
574
- ),
787
+ []
788
+ )
789
+ )
575
790
  ],
576
- ts.NodeFlags.Const,
577
- ),
791
+ ts.NodeFlags.Const
792
+ )
578
793
  ),
579
794
  // Build Content-Type header
580
795
  ts.factory.createVariableStatement(
@@ -587,22 +802,19 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
587
802
  undefined,
588
803
  ts.factory.createConditionalExpression(
589
804
  ts.factory.createBinaryExpression(
590
- ts.factory.createPropertyAccessExpression(
591
- ts.factory.createIdentifier('options'),
592
- ts.factory.createIdentifier('contentType'),
593
- ),
805
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('contentType')),
594
806
  ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
595
- ts.factory.createStringLiteral('application/x-www-form-urlencoded', true),
807
+ ts.factory.createStringLiteral('application/x-www-form-urlencoded', true)
596
808
  ),
597
809
  undefined,
598
810
  ts.factory.createStringLiteral('application/x-www-form-urlencoded', true),
599
811
  undefined,
600
- ts.factory.createStringLiteral('application/json', true),
601
- ),
602
- ),
812
+ ts.factory.createStringLiteral('application/json', true)
813
+ )
814
+ )
603
815
  ],
604
- ts.NodeFlags.Const,
605
- ),
816
+ ts.NodeFlags.Const
817
+ )
606
818
  ),
607
819
  // Merge headers: base headers, Content-Type, and request-specific headers
608
820
  ts.factory.createVariableStatement(
@@ -615,25 +827,19 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
615
827
  undefined,
616
828
  ts.factory.createConditionalExpression(
617
829
  ts.factory.createBinaryExpression(
618
- ts.factory.createPropertyAccessExpression(
619
- ts.factory.createIdentifier('baseOptions'),
620
- ts.factory.createIdentifier('headers'),
621
- ),
830
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('baseOptions'), ts.factory.createIdentifier('headers')),
622
831
  ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsEqualsToken),
623
- ts.factory.createIdentifier('undefined'),
832
+ ts.factory.createIdentifier('undefined')
624
833
  ),
625
834
  undefined,
626
- ts.factory.createPropertyAccessExpression(
627
- ts.factory.createIdentifier('baseOptions'),
628
- ts.factory.createIdentifier('headers'),
629
- ),
835
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('baseOptions'), ts.factory.createIdentifier('headers')),
630
836
  undefined,
631
- ts.factory.createObjectLiteralExpression([], false),
632
- ),
633
- ),
837
+ ts.factory.createObjectLiteralExpression([], false)
838
+ )
839
+ )
634
840
  ],
635
- ts.NodeFlags.Const,
636
- ),
841
+ ts.NodeFlags.Const
842
+ )
637
843
  ),
638
844
  ts.factory.createVariableStatement(
639
845
  undefined,
@@ -644,46 +850,32 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
644
850
  undefined,
645
851
  undefined,
646
852
  ts.factory.createCallExpression(
647
- ts.factory.createPropertyAccessExpression(
648
- ts.factory.createIdentifier('Object'),
649
- ts.factory.createIdentifier('assign'),
650
- ),
853
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('assign')),
651
854
  undefined,
652
855
  [
653
856
  ts.factory.createObjectLiteralExpression([], false),
654
857
  ts.factory.createIdentifier('baseHeaders'),
655
858
  ts.factory.createObjectLiteralExpression(
656
- [
657
- ts.factory.createPropertyAssignment(
658
- ts.factory.createStringLiteral('Content-Type', true),
659
- ts.factory.createIdentifier('contentType'),
660
- ),
661
- ],
662
- false,
859
+ [ts.factory.createPropertyAssignment(ts.factory.createStringLiteral('Content-Type', true), ts.factory.createIdentifier('contentType'))],
860
+ false
663
861
  ),
664
862
  ts.factory.createConditionalExpression(
665
863
  ts.factory.createBinaryExpression(
666
- ts.factory.createPropertyAccessExpression(
667
- ts.factory.createIdentifier('options'),
668
- ts.factory.createIdentifier('headers'),
669
- ),
864
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('headers')),
670
865
  ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsEqualsToken),
671
- ts.factory.createIdentifier('undefined'),
866
+ ts.factory.createIdentifier('undefined')
672
867
  ),
673
868
  undefined,
674
- ts.factory.createPropertyAccessExpression(
675
- ts.factory.createIdentifier('options'),
676
- ts.factory.createIdentifier('headers'),
677
- ),
869
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('headers')),
678
870
  undefined,
679
- ts.factory.createObjectLiteralExpression([], false),
680
- ),
681
- ],
682
- ),
683
- ),
871
+ ts.factory.createObjectLiteralExpression([], false)
872
+ )
873
+ ]
874
+ )
875
+ )
684
876
  ],
685
- ts.NodeFlags.Const,
686
- ),
877
+ ts.NodeFlags.Const
878
+ )
687
879
  ),
688
880
  // Build body with form-urlencoded support
689
881
  ts.factory.createVariableStatement(
@@ -696,22 +888,16 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
696
888
  undefined,
697
889
  ts.factory.createConditionalExpression(
698
890
  ts.factory.createBinaryExpression(
699
- ts.factory.createPropertyAccessExpression(
700
- ts.factory.createIdentifier('options'),
701
- ts.factory.createIdentifier('data'),
702
- ),
891
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('data')),
703
892
  ts.factory.createToken(ts.SyntaxKind.ExclamationEqualsEqualsToken),
704
- ts.factory.createIdentifier('undefined'),
893
+ ts.factory.createIdentifier('undefined')
705
894
  ),
706
895
  undefined,
707
896
  ts.factory.createConditionalExpression(
708
897
  ts.factory.createBinaryExpression(
709
- ts.factory.createPropertyAccessExpression(
710
- ts.factory.createIdentifier('options'),
711
- ts.factory.createIdentifier('contentType'),
712
- ),
898
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('contentType')),
713
899
  ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
714
- ts.factory.createStringLiteral('application/x-www-form-urlencoded', true),
900
+ ts.factory.createStringLiteral('application/x-www-form-urlencoded', true)
715
901
  ),
716
902
  undefined,
717
903
  // Form-urlencoded: convert object to URLSearchParams
@@ -733,33 +919,21 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
733
919
  ts.factory.createIdentifier('params'),
734
920
  undefined,
735
921
  undefined,
736
- ts.factory.createNewExpression(
737
- ts.factory.createIdentifier('URLSearchParams'),
738
- undefined,
739
- [],
740
- ),
741
- ),
922
+ ts.factory.createNewExpression(ts.factory.createIdentifier('URLSearchParams'), undefined, [])
923
+ )
742
924
  ],
743
- ts.NodeFlags.Const,
744
- ),
925
+ ts.NodeFlags.Const
926
+ )
745
927
  ),
746
928
  ts.factory.createExpressionStatement(
747
929
  ts.factory.createCallExpression(
748
930
  ts.factory.createPropertyAccessExpression(
749
931
  ts.factory.createCallExpression(
750
- ts.factory.createPropertyAccessExpression(
751
- ts.factory.createIdentifier('Object'),
752
- ts.factory.createIdentifier('entries'),
753
- ),
932
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('entries')),
754
933
  undefined,
755
- [
756
- ts.factory.createPropertyAccessExpression(
757
- ts.factory.createIdentifier('options'),
758
- ts.factory.createIdentifier('data'),
759
- ),
760
- ],
934
+ [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('data'))]
761
935
  ),
762
- ts.factory.createIdentifier('forEach'),
936
+ ts.factory.createIdentifier('forEach')
763
937
  ),
764
938
  undefined,
765
939
  [
@@ -771,22 +945,12 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
771
945
  undefined,
772
946
  undefined,
773
947
  ts.factory.createArrayBindingPattern([
774
- ts.factory.createBindingElement(
775
- undefined,
776
- undefined,
777
- ts.factory.createIdentifier('key'),
778
- undefined,
779
- ),
780
- ts.factory.createBindingElement(
781
- undefined,
782
- undefined,
783
- ts.factory.createIdentifier('value'),
784
- undefined,
785
- ),
948
+ ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier('key'), undefined),
949
+ ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier('value'), undefined)
786
950
  ]),
787
951
  undefined,
788
- undefined,
789
- ),
952
+ undefined
953
+ )
790
954
  ],
791
955
  undefined,
792
956
  ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
@@ -794,69 +958,51 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
794
958
  [
795
959
  ts.factory.createExpressionStatement(
796
960
  ts.factory.createCallExpression(
797
- ts.factory.createPropertyAccessExpression(
798
- ts.factory.createIdentifier('params'),
799
- ts.factory.createIdentifier('set'),
800
- ),
961
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('params'), ts.factory.createIdentifier('set')),
801
962
  undefined,
802
963
  [
803
964
  ts.factory.createIdentifier('key'),
804
- ts.factory.createCallExpression(
805
- ts.factory.createIdentifier('String'),
806
- undefined,
807
- [ts.factory.createIdentifier('value')],
808
- ),
809
- ],
810
- ),
811
- ),
965
+ ts.factory.createCallExpression(ts.factory.createIdentifier('String'), undefined, [ts.factory.createIdentifier('value')])
966
+ ]
967
+ )
968
+ )
812
969
  ],
813
- false,
814
- ),
815
- ),
816
- ],
817
- ),
970
+ false
971
+ )
972
+ )
973
+ ]
974
+ )
818
975
  ),
819
976
  ts.factory.createReturnStatement(
820
977
  ts.factory.createCallExpression(
821
- ts.factory.createPropertyAccessExpression(
822
- ts.factory.createIdentifier('params'),
823
- ts.factory.createIdentifier('toString'),
824
- ),
978
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('params'), ts.factory.createIdentifier('toString')),
825
979
  undefined,
826
- [],
827
- ),
828
- ),
980
+ []
981
+ )
982
+ )
829
983
  ],
830
- false,
831
- ),
832
- ),
984
+ false
985
+ )
986
+ )
833
987
  ),
834
988
  undefined,
835
- [],
989
+ []
836
990
  ),
837
991
  undefined,
838
992
  // JSON: stringify the data
839
993
  ts.factory.createCallExpression(
840
- ts.factory.createPropertyAccessExpression(
841
- ts.factory.createIdentifier('JSON'),
842
- ts.factory.createIdentifier('stringify'),
843
- ),
994
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('JSON'), ts.factory.createIdentifier('stringify')),
844
995
  undefined,
845
- [
846
- ts.factory.createPropertyAccessExpression(
847
- ts.factory.createIdentifier('options'),
848
- ts.factory.createIdentifier('data'),
849
- ),
850
- ],
851
- ),
996
+ [ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('data'))]
997
+ )
852
998
  ),
853
999
  undefined,
854
- ts.factory.createNull(),
855
- ),
856
- ),
1000
+ ts.factory.createNull()
1001
+ )
1002
+ )
857
1003
  ],
858
- ts.NodeFlags.Const,
859
- ),
1004
+ ts.NodeFlags.Const
1005
+ )
860
1006
  ),
861
1007
  // Make fetch request: merge base options with method, headers, and body
862
1008
  ts.factory.createVariableStatement(
@@ -871,39 +1017,27 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
871
1017
  ts.factory.createCallExpression(ts.factory.createIdentifier('fetch'), undefined, [
872
1018
  ts.factory.createIdentifier('url'),
873
1019
  ts.factory.createCallExpression(
874
- ts.factory.createPropertyAccessExpression(
875
- ts.factory.createIdentifier('Object'),
876
- ts.factory.createIdentifier('assign'),
877
- ),
1020
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('assign')),
878
1021
  undefined,
879
1022
  [
880
1023
  ts.factory.createObjectLiteralExpression([], false),
881
1024
  ts.factory.createIdentifier('baseOptions'),
882
1025
  ts.factory.createObjectLiteralExpression(
883
1026
  [
884
- ts.factory.createShorthandPropertyAssignment(
885
- ts.factory.createIdentifier('method'),
886
- undefined,
887
- ),
888
- ts.factory.createPropertyAssignment(
889
- ts.factory.createIdentifier('headers'),
890
- ts.factory.createIdentifier('headers'),
891
- ),
892
- ts.factory.createPropertyAssignment(
893
- ts.factory.createIdentifier('body'),
894
- ts.factory.createIdentifier('body'),
895
- ),
1027
+ ts.factory.createShorthandPropertyAssignment(ts.factory.createIdentifier('method'), undefined),
1028
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier('headers'), ts.factory.createIdentifier('headers')),
1029
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier('body'), ts.factory.createIdentifier('body'))
896
1030
  ],
897
- false,
898
- ),
899
- ],
900
- ),
901
- ]),
902
- ),
903
- ),
1031
+ false
1032
+ )
1033
+ ]
1034
+ )
1035
+ ])
1036
+ )
1037
+ )
904
1038
  ],
905
- ts.NodeFlags.Const,
906
- ),
1039
+ ts.NodeFlags.Const
1040
+ )
907
1041
  ),
908
1042
  // Handle response through hook (allows subclasses to intercept and modify response)
909
1043
  ts.factory.createVariableStatement(
@@ -916,80 +1050,62 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
916
1050
  undefined,
917
1051
  ts.factory.createAwaitExpression(
918
1052
  ts.factory.createCallExpression(
919
- ts.factory.createPropertyAccessExpression(
920
- ts.factory.createThis(),
921
- ts.factory.createIdentifier('handleResponse'),
922
- ),
1053
+ ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createIdentifier('handleResponse')),
923
1054
  [ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('T'), undefined)],
924
1055
  [
925
1056
  ts.factory.createIdentifier('rawResponse'),
926
1057
  ts.factory.createIdentifier('method'),
927
1058
  ts.factory.createIdentifier('path'),
928
- ts.factory.createIdentifier('options'),
929
- ],
930
- ),
931
- ),
932
- ),
1059
+ ts.factory.createIdentifier('options')
1060
+ ]
1061
+ )
1062
+ )
1063
+ )
933
1064
  ],
934
- ts.NodeFlags.Const,
935
- ),
1065
+ ts.NodeFlags.Const
1066
+ )
936
1067
  ),
937
1068
  // Check response status
938
1069
  ts.factory.createIfStatement(
939
1070
  ts.factory.createPrefixUnaryExpression(
940
1071
  ts.SyntaxKind.ExclamationToken,
941
- ts.factory.createPropertyAccessExpression(
942
- ts.factory.createIdentifier('response'),
943
- ts.factory.createIdentifier('ok'),
944
- ),
1072
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('response'), ts.factory.createIdentifier('ok'))
945
1073
  ),
946
1074
  ts.factory.createThrowStatement(
947
1075
  ts.factory.createNewExpression(ts.factory.createIdentifier('Error'), undefined, [
948
1076
  ts.factory.createTemplateExpression(ts.factory.createTemplateHead('HTTP ', 'HTTP '), [
949
1077
  ts.factory.createTemplateSpan(
950
- ts.factory.createPropertyAccessExpression(
951
- ts.factory.createIdentifier('response'),
952
- ts.factory.createIdentifier('status'),
953
- ),
954
- ts.factory.createTemplateMiddle(': ', ': '),
1078
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('response'), ts.factory.createIdentifier('status')),
1079
+ ts.factory.createTemplateMiddle(': ', ': ')
955
1080
  ),
956
1081
  ts.factory.createTemplateSpan(
957
- ts.factory.createPropertyAccessExpression(
958
- ts.factory.createIdentifier('response'),
959
- ts.factory.createIdentifier('statusText'),
960
- ),
961
- ts.factory.createTemplateTail('', ''),
962
- ),
963
- ]),
964
- ]),
1082
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('response'), ts.factory.createIdentifier('statusText')),
1083
+ ts.factory.createTemplateTail('', '')
1084
+ )
1085
+ ])
1086
+ ])
965
1087
  ),
966
- undefined,
1088
+ undefined
967
1089
  ),
968
1090
  // Return parsed JSON
969
1091
  ts.factory.createReturnStatement(
970
1092
  ts.factory.createAwaitExpression(
971
1093
  ts.factory.createCallExpression(
972
- ts.factory.createPropertyAccessExpression(
973
- ts.factory.createIdentifier('response'),
974
- ts.factory.createIdentifier('json'),
975
- ),
1094
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('response'), ts.factory.createIdentifier('json')),
976
1095
  undefined,
977
- [],
978
- ),
979
- ),
980
- ),
1096
+ []
1097
+ )
1098
+ )
1099
+ )
981
1100
  ],
982
- true,
983
- ),
1101
+ true
1102
+ )
984
1103
  );
985
1104
  }
986
1105
 
987
- private buildClientMethods(
988
- openapi: OpenApiSpecType,
989
- schemas: Record<string, ts.VariableStatement>,
990
- ): ts.MethodDeclaration[] {
1106
+ private buildClientMethods(openapi: OpenApiSpecType, schemas: Record<string, ts.VariableStatement>): ts.MethodDeclaration[] {
991
1107
  // Track operation IDs to detect duplicates
992
- const operationIdMap = new Map<string, {method: string; path: string}[]>();
1108
+ const operationIdMap = new Map<string, { method: string; path: string }[]>();
993
1109
 
994
1110
  // First pass: collect all operation IDs and their methods/paths
995
1111
  Object.entries(openapi.paths).forEach(([path, pathItem]) => {
@@ -1001,9 +1117,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1001
1117
  const operationId = safeMethodSchema.operationId;
1002
1118
  const existing = operationIdMap.get(operationId);
1003
1119
  if (existing) {
1004
- existing.push({method, path});
1120
+ existing.push({ method, path });
1005
1121
  } else {
1006
- operationIdMap.set(operationId, [{method, path}]);
1122
+ operationIdMap.set(operationId, [{ method, path }]);
1007
1123
  }
1008
1124
  }
1009
1125
  });
@@ -1035,7 +1151,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1035
1151
  // This will be handled in transformOperationName
1036
1152
  const modifiedSchema = {
1037
1153
  ...safeMethodSchema,
1038
- operationId: `${operationId}_${methodLower}`,
1154
+ operationId: `${operationId}_${methodLower}`
1039
1155
  };
1040
1156
  return this.buildEndpointMethod(method, path, modifiedSchema, schemas);
1041
1157
  }
@@ -1062,9 +1178,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1062
1178
  operationId,
1063
1179
  method,
1064
1180
  path,
1065
- ...(schema.tags !== undefined && {tags: schema.tags}),
1066
- ...(schema.summary !== undefined && {summary: schema.summary}),
1067
- ...(schema.description !== undefined && {description: schema.description}),
1181
+ ...(schema.tags !== undefined && { tags: schema.tags }),
1182
+ ...(schema.summary !== undefined && { summary: schema.summary }),
1183
+ ...(schema.description !== undefined && { description: schema.description })
1068
1184
  };
1069
1185
  transformed = this.operationNameTransformer(details);
1070
1186
  } else if (this.namingConvention) {
@@ -1089,16 +1205,8 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1089
1205
  return this.typeBuilder.sanitizeIdentifier(transformed);
1090
1206
  }
1091
1207
 
1092
- private buildEndpointMethod(
1093
- method: string,
1094
- path: string,
1095
- schema: MethodSchemaType,
1096
- schemas: Record<string, ts.VariableStatement>,
1097
- ): ts.MethodDeclaration {
1098
- const {parameters, pathParams, queryParams, hasRequestBody, contentType} = this.buildMethodParameters(
1099
- schema,
1100
- schemas,
1101
- );
1208
+ private buildEndpointMethod(method: string, path: string, schema: MethodSchemaType, schemas: Record<string, ts.VariableStatement>): ts.MethodDeclaration {
1209
+ const { parameters, pathParams, queryParams, hasRequestBody, contentType } = this.buildMethodParameters(schema, schemas);
1102
1210
  const responseType = this.getResponseType(schema, schemas);
1103
1211
  const responseSchema = this.getResponseSchema(schema, schemas);
1104
1212
 
@@ -1113,40 +1221,28 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1113
1221
  ? ts.factory.createObjectLiteralExpression(
1114
1222
  queryParams.map((param) => {
1115
1223
  const paramName = this.typeBuilder.sanitizeIdentifier(param.name);
1116
- return ts.factory.createPropertyAssignment(
1117
- ts.factory.createStringLiteral(param.name, true),
1118
- ts.factory.createIdentifier(paramName),
1119
- );
1224
+ return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(param.name, true), ts.factory.createIdentifier(paramName));
1120
1225
  }),
1121
- false,
1226
+ false
1122
1227
  )
1123
1228
  : undefined;
1124
1229
 
1125
1230
  // Build request body
1126
- const requestBodyExpression: ts.Expression | undefined = hasRequestBody
1127
- ? ts.factory.createIdentifier('body')
1128
- : undefined;
1231
+ const requestBodyExpression: ts.Expression | undefined = hasRequestBody ? ts.factory.createIdentifier('body') : undefined;
1129
1232
 
1130
1233
  // Build options object for makeRequest
1131
1234
  const optionsProps: ts.ObjectLiteralElementLike[] = [];
1132
1235
  if (queryParamsExpression) {
1133
- optionsProps.push(
1134
- ts.factory.createPropertyAssignment(ts.factory.createIdentifier('params'), queryParamsExpression),
1135
- );
1236
+ optionsProps.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier('params'), queryParamsExpression));
1136
1237
  }
1238
+
1137
1239
  if (requestBodyExpression) {
1138
- optionsProps.push(
1139
- ts.factory.createPropertyAssignment(ts.factory.createIdentifier('data'), requestBodyExpression),
1140
- );
1240
+ optionsProps.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier('data'), requestBodyExpression));
1141
1241
  }
1242
+
1142
1243
  // Add content type if it's form-urlencoded
1143
1244
  if (hasRequestBody && contentType === 'application/x-www-form-urlencoded') {
1144
- optionsProps.push(
1145
- ts.factory.createPropertyAssignment(
1146
- ts.factory.createIdentifier('contentType'),
1147
- ts.factory.createStringLiteral('application/x-www-form-urlencoded', true),
1148
- ),
1149
- );
1245
+ optionsProps.push(ts.factory.createPropertyAssignment(ts.factory.createIdentifier('contentType'), ts.factory.createStringLiteral('application/x-www-form-urlencoded', true)));
1150
1246
  }
1151
1247
 
1152
1248
  const optionsExpression = ts.factory.createObjectLiteralExpression(optionsProps, false);
@@ -1155,18 +1251,98 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1155
1251
  const makeRequestCall = ts.factory.createCallExpression(
1156
1252
  ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createIdentifier('makeRequest')),
1157
1253
  undefined,
1158
- [ts.factory.createStringLiteral(method.toUpperCase(), true), pathExpression, optionsExpression],
1254
+ [ts.factory.createStringLiteral(method.toUpperCase(), true), pathExpression, optionsExpression]
1159
1255
  );
1160
1256
 
1161
- // Add Zod validation if we have a response schema
1162
1257
  if (responseSchema) {
1163
- const validateCall = ts.factory.createCallExpression(
1164
- ts.factory.createPropertyAccessExpression(responseSchema, ts.factory.createIdentifier('parse')),
1165
- undefined,
1166
- [ts.factory.createAwaitExpression(makeRequestCall)],
1258
+ const schemaName = responseSchema.text;
1259
+ const schemaNameLower = schemaName.charAt(0).toLowerCase() + schemaName.slice(1);
1260
+ const parsedVarName = `parsed${schemaName}`;
1261
+
1262
+ // const response = await this.makeRequest(...)
1263
+ statements.push(
1264
+ ts.factory.createVariableStatement(
1265
+ undefined,
1266
+ ts.factory.createVariableDeclarationList(
1267
+ [ts.factory.createVariableDeclaration('response', undefined, undefined, ts.factory.createAwaitExpression(makeRequestCall))],
1268
+ ts.NodeFlags.Const
1269
+ )
1270
+ )
1167
1271
  );
1168
1272
 
1169
- statements.push(ts.factory.createReturnStatement(validateCall));
1273
+ // const parsed{Name} = {Schema}.safeParse(response)
1274
+ statements.push(
1275
+ ts.factory.createVariableStatement(
1276
+ undefined,
1277
+ ts.factory.createVariableDeclarationList(
1278
+ [
1279
+ ts.factory.createVariableDeclaration(
1280
+ parsedVarName,
1281
+ undefined,
1282
+ undefined,
1283
+ ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(responseSchema, ts.factory.createIdentifier('safeParse')), undefined, [
1284
+ ts.factory.createIdentifier('response')
1285
+ ])
1286
+ )
1287
+ ],
1288
+ ts.NodeFlags.Const
1289
+ )
1290
+ )
1291
+ );
1292
+
1293
+ // if (!parsed{Name}.success) { throw new ResponseValidationError<{Type}>(...) }
1294
+ statements.push(
1295
+ ts.factory.createIfStatement(
1296
+ ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.ExclamationToken, ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(parsedVarName), 'success')),
1297
+ ts.factory.createBlock(
1298
+ [
1299
+ ts.factory.createThrowStatement(
1300
+ ts.factory.createNewExpression(
1301
+ ts.factory.createIdentifier('ResponseValidationError'),
1302
+ [ts.factory.createTypeReferenceNode(schemaName)],
1303
+ [
1304
+ ts.factory.createTemplateExpression(ts.factory.createTemplateHead(`Invalid ${schemaNameLower}: `), [
1305
+ ts.factory.createTemplateSpan(
1306
+ ts.factory.createCallExpression(
1307
+ ts.factory.createPropertyAccessExpression(
1308
+ ts.factory.createCallExpression(
1309
+ ts.factory.createPropertyAccessExpression(
1310
+ ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(parsedVarName), 'error'), 'errors'),
1311
+ 'map'
1312
+ ),
1313
+ undefined,
1314
+ [
1315
+ ts.factory.createArrowFunction(
1316
+ undefined,
1317
+ undefined,
1318
+ [ts.factory.createParameterDeclaration(undefined, undefined, 'error')],
1319
+ undefined,
1320
+ ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
1321
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('error'), 'message')
1322
+ )
1323
+ ]
1324
+ ),
1325
+ 'join'
1326
+ ),
1327
+ undefined,
1328
+ [ts.factory.createStringLiteral(', ', true)]
1329
+ ),
1330
+ ts.factory.createTemplateTail('')
1331
+ )
1332
+ ]),
1333
+ ts.factory.createIdentifier('response'),
1334
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(parsedVarName), 'error')
1335
+ ]
1336
+ )
1337
+ )
1338
+ ],
1339
+ true
1340
+ )
1341
+ )
1342
+ );
1343
+
1344
+ // return parsed{Name}.data
1345
+ statements.push(ts.factory.createReturnStatement(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier(parsedVarName), 'data')));
1170
1346
  } else {
1171
1347
  statements.push(ts.factory.createReturnStatement(ts.factory.createAwaitExpression(makeRequestCall)));
1172
1348
  }
@@ -1181,7 +1357,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1181
1357
  undefined,
1182
1358
  parameters,
1183
1359
  responseType,
1184
- ts.factory.createBlock(statements, true),
1360
+ ts.factory.createBlock(statements, true)
1185
1361
  );
1186
1362
 
1187
1363
  // Add JSDoc comment if summary or description exists
@@ -1190,22 +1366,17 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1190
1366
  if (jsdocComment) {
1191
1367
  // addSyntheticLeadingComment expects the comment content without delimiters
1192
1368
  // and will wrap it in /** */ for JSDoc-style comments
1193
- ts.addSyntheticLeadingComment(
1194
- methodDeclaration,
1195
- ts.SyntaxKind.MultiLineCommentTrivia,
1196
- `*\n${jsdocComment}\n `,
1197
- true,
1198
- );
1369
+ ts.addSyntheticLeadingComment(methodDeclaration, ts.SyntaxKind.MultiLineCommentTrivia, `*\n${jsdocComment}\n `, true);
1199
1370
  }
1200
1371
 
1201
1372
  return methodDeclaration;
1202
1373
  }
1203
1374
 
1204
- private buildPathExpression(path: string, pathParams: {name: string; type: string}[]): ts.Expression {
1375
+ private buildPathExpression(path: string, pathParams: { name: string; type: string }[]): ts.Expression {
1205
1376
  // Replace {param} with ${param} for template literal
1206
1377
  const pathParamNames = new Set(pathParams.map((p) => p.name));
1207
1378
  const pathParamRegex = /\{([^}]+)\}/g;
1208
- const matches: {index: number; length: number; name: string}[] = [];
1379
+ const matches: { index: number; length: number; name: string }[] = [];
1209
1380
 
1210
1381
  // Find all path parameters
1211
1382
  for (const match of path.matchAll(pathParamRegex)) {
@@ -1215,7 +1386,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1215
1386
  matches.push({
1216
1387
  index: match.index,
1217
1388
  length: match[0].length,
1218
- name: paramName,
1389
+ name: paramName
1219
1390
  });
1220
1391
  }
1221
1392
  }
@@ -1236,19 +1407,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1236
1407
  const after = isLast ? path.substring(m.index + m.length) : '';
1237
1408
 
1238
1409
  if (isLast) {
1239
- templateSpans.push(
1240
- ts.factory.createTemplateSpan(
1241
- ts.factory.createIdentifier(sanitizedName),
1242
- ts.factory.createTemplateTail(after, after),
1243
- ),
1244
- );
1410
+ templateSpans.push(ts.factory.createTemplateSpan(ts.factory.createIdentifier(sanitizedName), ts.factory.createTemplateTail(after, after)));
1245
1411
  } else {
1246
- templateSpans.push(
1247
- ts.factory.createTemplateSpan(
1248
- ts.factory.createIdentifier(sanitizedName),
1249
- ts.factory.createTemplateMiddle(before, before),
1250
- ),
1251
- );
1412
+ templateSpans.push(ts.factory.createTemplateSpan(ts.factory.createIdentifier(sanitizedName), ts.factory.createTemplateMiddle(before, before)));
1252
1413
  }
1253
1414
 
1254
1415
  lastIndex = m.index + m.length;
@@ -1258,23 +1419,24 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1258
1419
  if (!firstMatch) {
1259
1420
  return ts.factory.createStringLiteral(path, true);
1260
1421
  }
1422
+
1261
1423
  const head = path.substring(0, firstMatch.index);
1262
1424
  return ts.factory.createTemplateExpression(ts.factory.createTemplateHead(head, head), templateSpans);
1263
1425
  }
1264
1426
 
1265
1427
  private buildMethodParameters(
1266
1428
  schema: MethodSchemaType,
1267
- schemas: Record<string, ts.VariableStatement>,
1429
+ schemas: Record<string, ts.VariableStatement>
1268
1430
  ): {
1269
1431
  parameters: ts.ParameterDeclaration[];
1270
- pathParams: {name: string; type: string}[];
1271
- queryParams: {name: string; type: string; required: boolean}[];
1432
+ pathParams: { name: string; type: string }[];
1433
+ queryParams: { name: string; type: string; required: boolean }[];
1272
1434
  hasRequestBody: boolean;
1273
1435
  contentType: string;
1274
1436
  } {
1275
1437
  const parameters: ts.ParameterDeclaration[] = [];
1276
- const pathParams: {name: string; type: string}[] = [];
1277
- const queryParams: {name: string; type: string; required: boolean}[] = [];
1438
+ const pathParams: { name: string; type: string }[] = [];
1439
+ const queryParams: { name: string; type: string; required: boolean }[] = [];
1278
1440
 
1279
1441
  // Extract path and query parameters
1280
1442
  if (schema.parameters) {
@@ -1283,7 +1445,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1283
1445
  const paramType = this.getParameterType(param.schema);
1284
1446
 
1285
1447
  if (param.in === 'path') {
1286
- pathParams.push({name: param.name, type: paramType});
1448
+ pathParams.push({ name: param.name, type: paramType });
1287
1449
  parameters.push(this.typeBuilder.createParameter(paramName, paramType, undefined, false));
1288
1450
  } else if (param.in === 'query') {
1289
1451
  // Improve type inference for query parameters
@@ -1291,24 +1453,26 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1291
1453
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1292
1454
  typeof param.schema === 'object' && param.schema !== null
1293
1455
  ? (() => {
1294
- const paramSchema = param.schema as {type?: string; items?: unknown; enum?: unknown[]};
1456
+ const paramSchema = param.schema as { type?: string; items?: unknown; enum?: unknown[] };
1295
1457
  // eslint-disable-next-line @typescript-eslint/dot-notation
1296
1458
  if (paramSchema['type'] === 'array' && paramSchema['items']) {
1297
1459
  // eslint-disable-next-line @typescript-eslint/dot-notation
1298
- const itemSchema = paramSchema['items'] as {type?: string};
1460
+ const itemSchema = paramSchema['items'] as { type?: string };
1299
1461
  // eslint-disable-next-line @typescript-eslint/dot-notation
1300
1462
  if (itemSchema['type'] === 'string') {
1301
1463
  return 'string[]' as const;
1302
1464
  }
1465
+
1303
1466
  // eslint-disable-next-line @typescript-eslint/dot-notation
1304
1467
  if (itemSchema['type'] === 'number' || itemSchema['type'] === 'integer') {
1305
1468
  return 'number[]' as const;
1306
1469
  }
1307
1470
  }
1471
+
1308
1472
  return paramType;
1309
1473
  })()
1310
1474
  : paramType;
1311
- queryParams.push({name: param.name, type: queryParamType, required: param.required ?? false});
1475
+ queryParams.push({ name: param.name, type: queryParamType, required: param.required ?? false });
1312
1476
  parameters.push(this.typeBuilder.createParameter(paramName, queryParamType, undefined, !param.required));
1313
1477
  }
1314
1478
  }
@@ -1333,6 +1497,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1333
1497
  const refName = ref.split('/').pop() ?? 'unknown';
1334
1498
  return this.typeBuilder.sanitizeIdentifier(refName);
1335
1499
  }
1500
+
1336
1501
  // Fallback to getSchemaTypeName for non-ref schemas
1337
1502
  return this.getSchemaTypeName(requestBodySchema, schemas);
1338
1503
  })()
@@ -1342,12 +1507,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1342
1507
  }
1343
1508
 
1344
1509
  // Determine content type for request body
1345
- const contentType =
1346
- hasRequestBody && schema.requestBody?.content?.['application/x-www-form-urlencoded']
1347
- ? 'application/x-www-form-urlencoded'
1348
- : 'application/json';
1510
+ const contentType = hasRequestBody && schema.requestBody?.content?.['application/x-www-form-urlencoded'] ? 'application/x-www-form-urlencoded' : 'application/json';
1349
1511
 
1350
- return {parameters, pathParams, queryParams, hasRequestBody, contentType};
1512
+ return { parameters, pathParams, queryParams, hasRequestBody, contentType };
1351
1513
  }
1352
1514
 
1353
1515
  private getParameterType(schema: unknown): string {
@@ -1397,7 +1559,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1397
1559
  return 'unknown';
1398
1560
  }
1399
1561
 
1400
- const schemaObj = schema as {$ref?: string; type?: string; items?: unknown};
1562
+ const schemaObj = schema as { $ref?: string; type?: string; items?: unknown };
1401
1563
 
1402
1564
  // Check for $ref using both dot notation and bracket notation
1403
1565
  // eslint-disable-next-line @typescript-eslint/dot-notation
@@ -1427,10 +1589,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1427
1589
  }
1428
1590
  }
1429
1591
 
1430
- private getResponseSchema(
1431
- schema: MethodSchemaType,
1432
- _schemas: Record<string, ts.VariableStatement>,
1433
- ): ts.Identifier | undefined {
1592
+ private getResponseSchema(schema: MethodSchemaType, _schemas: Record<string, ts.VariableStatement>): ts.Identifier | undefined {
1434
1593
  // Try to find a 200 response first, then 201, then default
1435
1594
  const response200 = schema.responses?.['200'];
1436
1595
  const response201 = schema.responses?.['201'];
@@ -1445,7 +1604,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1445
1604
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1446
1605
  if (responseSchema !== null && typeof responseSchema === 'object' && '$ref' in responseSchema) {
1447
1606
  // eslint-disable-next-line @typescript-eslint/dot-notation
1448
- const ref = (responseSchema as {$ref: string})['$ref'];
1607
+ const ref = (responseSchema as { $ref: string })['$ref'];
1449
1608
  if (typeof ref === 'string') {
1450
1609
  const refName = ref.split('/').pop() ?? 'unknown';
1451
1610
  return ts.factory.createIdentifier(this.typeBuilder.sanitizeIdentifier(refName));
@@ -1457,10 +1616,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1457
1616
  return undefined;
1458
1617
  }
1459
1618
 
1460
- private getResponseType(
1461
- schema: MethodSchemaType,
1462
- schemas: Record<string, ts.VariableStatement>,
1463
- ): ts.TypeNode | undefined {
1619
+ private getResponseType(schema: MethodSchemaType, schemas: Record<string, ts.VariableStatement>): ts.TypeNode | undefined {
1464
1620
  // Try to find a 200 response first, then 201, then default
1465
1621
  const response200 = schema.responses?.['200'];
1466
1622
  const response201 = schema.responses?.['201'];
@@ -1468,9 +1624,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1468
1624
 
1469
1625
  const response = response200 ?? response201 ?? responseDefault;
1470
1626
  if (!response?.content?.['application/json']?.schema) {
1471
- return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
1472
- ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword),
1473
- ]);
1627
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [ts.factory.createKeywordTypeNode(ts.SyntaxKind.VoidKeyword)]);
1474
1628
  }
1475
1629
 
1476
1630
  const responseSchema = response.content['application/json'].schema;
@@ -1485,15 +1639,12 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1485
1639
  if (schemas[sanitizedItemTypeName]) {
1486
1640
  // Use the type alias directly (it already uses z.infer)
1487
1641
  return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
1488
- ts.factory.createArrayTypeNode(
1489
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedItemTypeName), undefined),
1490
- ),
1642
+ ts.factory.createArrayTypeNode(ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedItemTypeName), undefined))
1491
1643
  ]);
1492
1644
  }
1645
+
1493
1646
  // If it's a primitive array, use the type name as-is
1494
- return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
1495
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined),
1496
- ]);
1647
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined)]);
1497
1648
  }
1498
1649
 
1499
1650
  const sanitizedTypeName = this.typeBuilder.sanitizeIdentifier(typeName);
@@ -1502,14 +1653,12 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1502
1653
  if (schemas[sanitizedTypeName]) {
1503
1654
  // Use the type name directly (we have a type alias that already uses z.infer)
1504
1655
  return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
1505
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedTypeName), undefined),
1656
+ ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedTypeName), undefined)
1506
1657
  ]);
1507
1658
  }
1508
1659
 
1509
1660
  // For primitive types and Record types, use the type name directly
1510
- return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
1511
- ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined),
1512
- ]);
1661
+ return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(typeName), undefined)]);
1513
1662
  }
1514
1663
 
1515
1664
  private buildServerConfiguration(openapi: OpenApiSpecType): ts.Statement[] {
@@ -1523,21 +1672,15 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1523
1672
 
1524
1673
  // Build server configuration array
1525
1674
  const serverConfigElements = servers.map((server) => {
1526
- const properties: ts.PropertyAssignment[] = [
1527
- ts.factory.createPropertyAssignment('url', ts.factory.createStringLiteral(server.url, true)),
1528
- ];
1675
+ const properties: ts.PropertyAssignment[] = [ts.factory.createPropertyAssignment('url', ts.factory.createStringLiteral(server.url, true))];
1529
1676
 
1530
1677
  if (server.description) {
1531
- properties.push(
1532
- ts.factory.createPropertyAssignment('description', ts.factory.createStringLiteral(server.description, true)),
1533
- );
1678
+ properties.push(ts.factory.createPropertyAssignment('description', ts.factory.createStringLiteral(server.description, true)));
1534
1679
  }
1535
1680
 
1536
1681
  if (server.variables && Object.keys(server.variables).length > 0) {
1537
1682
  const variableProperties = Object.entries(server.variables).map(([varName, varDef]) => {
1538
- const varProps: ts.PropertyAssignment[] = [
1539
- ts.factory.createPropertyAssignment('default', ts.factory.createStringLiteral(varDef.default, true)),
1540
- ];
1683
+ const varProps: ts.PropertyAssignment[] = [ts.factory.createPropertyAssignment('default', ts.factory.createStringLiteral(varDef.default, true))];
1541
1684
 
1542
1685
  if (varDef.enum && varDef.enum.length > 0) {
1543
1686
  varProps.push(
@@ -1545,30 +1688,20 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1545
1688
  'enum',
1546
1689
  ts.factory.createArrayLiteralExpression(
1547
1690
  varDef.enum.map((val) => ts.factory.createStringLiteral(val, true)),
1548
- false,
1549
- ),
1550
- ),
1691
+ false
1692
+ )
1693
+ )
1551
1694
  );
1552
1695
  }
1553
1696
 
1554
1697
  if (varDef.description) {
1555
- varProps.push(
1556
- ts.factory.createPropertyAssignment(
1557
- 'description',
1558
- ts.factory.createStringLiteral(varDef.description, true),
1559
- ),
1560
- );
1698
+ varProps.push(ts.factory.createPropertyAssignment('description', ts.factory.createStringLiteral(varDef.description, true)));
1561
1699
  }
1562
1700
 
1563
1701
  return ts.factory.createPropertyAssignment(varName, ts.factory.createObjectLiteralExpression(varProps, true));
1564
1702
  });
1565
1703
 
1566
- properties.push(
1567
- ts.factory.createPropertyAssignment(
1568
- 'variables',
1569
- ts.factory.createObjectLiteralExpression(variableProperties, true),
1570
- ),
1571
- );
1704
+ properties.push(ts.factory.createPropertyAssignment('variables', ts.factory.createObjectLiteralExpression(variableProperties, true)));
1572
1705
  }
1573
1706
 
1574
1707
  return ts.factory.createObjectLiteralExpression(properties, true);
@@ -1584,12 +1717,12 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1584
1717
  ts.factory.createIdentifier('serverConfigurations'),
1585
1718
  undefined,
1586
1719
  undefined,
1587
- ts.factory.createArrayLiteralExpression(serverConfigElements, false),
1588
- ),
1720
+ ts.factory.createArrayLiteralExpression(serverConfigElements, false)
1721
+ )
1589
1722
  ],
1590
- ts.NodeFlags.Const,
1591
- ),
1592
- ),
1723
+ ts.NodeFlags.Const
1724
+ )
1725
+ )
1593
1726
  );
1594
1727
 
1595
1728
  // Export default base URL (first server with default variables)
@@ -1599,17 +1732,10 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1599
1732
  ts.factory.createVariableStatement(
1600
1733
  [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
1601
1734
  ts.factory.createVariableDeclarationList(
1602
- [
1603
- ts.factory.createVariableDeclaration(
1604
- ts.factory.createIdentifier('defaultBaseUrl'),
1605
- undefined,
1606
- undefined,
1607
- ts.factory.createStringLiteral(defaultBaseUrl, true),
1608
- ),
1609
- ],
1610
- ts.NodeFlags.Const,
1611
- ),
1612
- ),
1735
+ [ts.factory.createVariableDeclaration(ts.factory.createIdentifier('defaultBaseUrl'), undefined, undefined, ts.factory.createStringLiteral(defaultBaseUrl, true))],
1736
+ ts.NodeFlags.Const
1737
+ )
1738
+ )
1613
1739
  );
1614
1740
 
1615
1741
  // Build ClientOptions type
@@ -1618,13 +1744,13 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1618
1744
  undefined,
1619
1745
  ts.factory.createIdentifier('baseUrl'),
1620
1746
  ts.factory.createToken(ts.SyntaxKind.QuestionToken),
1621
- ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
1747
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
1622
1748
  ),
1623
1749
  ts.factory.createPropertySignature(
1624
1750
  undefined,
1625
1751
  ts.factory.createIdentifier('serverIndex'),
1626
1752
  ts.factory.createToken(ts.SyntaxKind.QuestionToken),
1627
- ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
1753
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
1628
1754
  ),
1629
1755
  ts.factory.createPropertySignature(
1630
1756
  undefined,
@@ -1632,9 +1758,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1632
1758
  ts.factory.createToken(ts.SyntaxKind.QuestionToken),
1633
1759
  ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Record'), [
1634
1760
  ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
1635
- ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
1636
- ]),
1637
- ),
1761
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
1762
+ ])
1763
+ )
1638
1764
  ];
1639
1765
 
1640
1766
  statements.push(
@@ -1642,8 +1768,8 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1642
1768
  [ts.factory.createToken(ts.SyntaxKind.ExportKeyword)],
1643
1769
  ts.factory.createIdentifier('ClientOptions'),
1644
1770
  undefined,
1645
- ts.factory.createTypeLiteralNode(optionProperties),
1646
- ),
1771
+ ts.factory.createTypeLiteralNode(optionProperties)
1772
+ )
1647
1773
  );
1648
1774
 
1649
1775
  // Build resolveServerUrl helper function
@@ -1655,11 +1781,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1655
1781
  private resolveServerUrl(
1656
1782
  server: {
1657
1783
  url: string;
1658
- variables?:
1659
- | Record<string, {default: string; enum?: string[] | undefined; description?: string | undefined}>
1660
- | undefined;
1784
+ variables?: Record<string, { default: string; enum?: string[] | undefined; description?: string | undefined }> | undefined;
1661
1785
  },
1662
- variables: Record<string, string>,
1786
+ variables: Record<string, string>
1663
1787
  ): string {
1664
1788
  let url = server.url;
1665
1789
 
@@ -1677,22 +1801,16 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1677
1801
  servers: {
1678
1802
  url: string;
1679
1803
  description?: string | undefined;
1680
- variables?:
1681
- | Record<string, {default: string; enum?: string[] | undefined; description?: string | undefined}>
1682
- | undefined;
1683
- }[],
1804
+ variables?: Record<string, { default: string; enum?: string[] | undefined; description?: string | undefined }> | undefined;
1805
+ }[]
1684
1806
  ): ts.FunctionDeclaration {
1685
1807
  // Build server configs array inline
1686
1808
  const serverConfigElements = servers.map((server) => {
1687
- const properties: ts.PropertyAssignment[] = [
1688
- ts.factory.createPropertyAssignment('url', ts.factory.createStringLiteral(server.url, true)),
1689
- ];
1809
+ const properties: ts.PropertyAssignment[] = [ts.factory.createPropertyAssignment('url', ts.factory.createStringLiteral(server.url, true))];
1690
1810
 
1691
1811
  if (server.variables && Object.keys(server.variables).length > 0) {
1692
1812
  const variableProperties = Object.entries(server.variables).map(([varName, varDef]) => {
1693
- const varProps: ts.PropertyAssignment[] = [
1694
- ts.factory.createPropertyAssignment('default', ts.factory.createStringLiteral(varDef.default, true)),
1695
- ];
1813
+ const varProps: ts.PropertyAssignment[] = [ts.factory.createPropertyAssignment('default', ts.factory.createStringLiteral(varDef.default, true))];
1696
1814
 
1697
1815
  if (varDef.enum && varDef.enum.length > 0) {
1698
1816
  varProps.push(
@@ -1700,21 +1818,16 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1700
1818
  'enum',
1701
1819
  ts.factory.createArrayLiteralExpression(
1702
1820
  varDef.enum.map((val) => ts.factory.createStringLiteral(val, true)),
1703
- false,
1704
- ),
1705
- ),
1821
+ false
1822
+ )
1823
+ )
1706
1824
  );
1707
1825
  }
1708
1826
 
1709
1827
  return ts.factory.createPropertyAssignment(varName, ts.factory.createObjectLiteralExpression(varProps, true));
1710
1828
  });
1711
1829
 
1712
- properties.push(
1713
- ts.factory.createPropertyAssignment(
1714
- 'variables',
1715
- ts.factory.createObjectLiteralExpression(variableProperties, true),
1716
- ),
1717
- );
1830
+ properties.push(ts.factory.createPropertyAssignment('variables', ts.factory.createObjectLiteralExpression(variableProperties, true)));
1718
1831
  }
1719
1832
 
1720
1833
  return ts.factory.createObjectLiteralExpression(properties, true);
@@ -1733,16 +1846,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1733
1846
  ts.factory.createVariableStatement(
1734
1847
  undefined,
1735
1848
  ts.factory.createVariableDeclarationList(
1736
- [
1737
- ts.factory.createVariableDeclaration(
1738
- configs,
1739
- undefined,
1740
- undefined,
1741
- ts.factory.createArrayLiteralExpression(serverConfigElements, false),
1742
- ),
1743
- ],
1744
- ts.NodeFlags.Const,
1745
- ),
1849
+ [ts.factory.createVariableDeclaration(configs, undefined, undefined, ts.factory.createArrayLiteralExpression(serverConfigElements, false))],
1850
+ ts.NodeFlags.Const
1851
+ )
1746
1852
  ),
1747
1853
  // const idx = serverIndex ?? 0
1748
1854
  ts.factory.createVariableStatement(
@@ -1756,19 +1862,19 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1756
1862
  ts.factory.createBinaryExpression(
1757
1863
  ts.factory.createIdentifier('serverIndex'),
1758
1864
  ts.factory.createToken(ts.SyntaxKind.QuestionQuestionToken),
1759
- ts.factory.createNumericLiteral('0'),
1760
- ),
1761
- ),
1865
+ ts.factory.createNumericLiteral('0')
1866
+ )
1867
+ )
1762
1868
  ],
1763
- ts.NodeFlags.Const,
1764
- ),
1869
+ ts.NodeFlags.Const
1870
+ )
1765
1871
  ),
1766
1872
  // if (idx < configs.length) { ... }
1767
1873
  ts.factory.createIfStatement(
1768
1874
  ts.factory.createBinaryExpression(
1769
1875
  idx,
1770
1876
  ts.factory.createToken(ts.SyntaxKind.LessThanToken),
1771
- ts.factory.createPropertyAccessExpression(configs, ts.factory.createIdentifier('length')),
1877
+ ts.factory.createPropertyAccessExpression(configs, ts.factory.createIdentifier('length'))
1772
1878
  ),
1773
1879
  ts.factory.createBlock(
1774
1880
  [
@@ -1776,37 +1882,23 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1776
1882
  ts.factory.createVariableStatement(
1777
1883
  undefined,
1778
1884
  ts.factory.createVariableDeclarationList(
1779
- [
1780
- ts.factory.createVariableDeclaration(
1781
- config,
1782
- undefined,
1783
- undefined,
1784
- ts.factory.createElementAccessExpression(configs, idx),
1785
- ),
1786
- ],
1787
- ts.NodeFlags.Const,
1788
- ),
1885
+ [ts.factory.createVariableDeclaration(config, undefined, undefined, ts.factory.createElementAccessExpression(configs, idx))],
1886
+ ts.NodeFlags.Const
1887
+ )
1789
1888
  ),
1790
1889
  // let url = config.url
1791
1890
  ts.factory.createVariableStatement(
1792
1891
  undefined,
1793
1892
  ts.factory.createVariableDeclarationList(
1794
- [
1795
- ts.factory.createVariableDeclaration(
1796
- url,
1797
- undefined,
1798
- undefined,
1799
- ts.factory.createPropertyAccessExpression(config, ts.factory.createIdentifier('url')),
1800
- ),
1801
- ],
1802
- ts.NodeFlags.Let,
1803
- ),
1893
+ [ts.factory.createVariableDeclaration(url, undefined, undefined, ts.factory.createPropertyAccessExpression(config, ts.factory.createIdentifier('url')))],
1894
+ ts.NodeFlags.Let
1895
+ )
1804
1896
  ),
1805
1897
  // if (config.variables && serverVariables) { ... }
1806
1898
  ts.factory.createIfStatement(
1807
1899
  ts.factory.createLogicalAnd(
1808
1900
  ts.factory.createPropertyAccessExpression(config, ts.factory.createIdentifier('variables')),
1809
- ts.factory.createIdentifier('serverVariables'),
1901
+ ts.factory.createIdentifier('serverVariables')
1810
1902
  ),
1811
1903
  ts.factory.createBlock(
1812
1904
  [
@@ -1818,21 +1910,18 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1818
1910
  ts.factory.createVariableDeclaration(
1819
1911
  ts.factory.createArrayBindingPattern([
1820
1912
  ts.factory.createBindingElement(undefined, undefined, key),
1821
- ts.factory.createBindingElement(undefined, undefined, value),
1913
+ ts.factory.createBindingElement(undefined, undefined, value)
1822
1914
  ]),
1823
1915
  undefined,
1824
- undefined,
1825
- ),
1916
+ undefined
1917
+ )
1826
1918
  ],
1827
- ts.NodeFlags.Const,
1919
+ ts.NodeFlags.Const
1828
1920
  ),
1829
1921
  ts.factory.createCallExpression(
1830
- ts.factory.createPropertyAccessExpression(
1831
- ts.factory.createIdentifier('Object'),
1832
- ts.factory.createIdentifier('entries'),
1833
- ),
1922
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('entries')),
1834
1923
  undefined,
1835
- [ts.factory.createIdentifier('serverVariables')],
1924
+ [ts.factory.createIdentifier('serverVariables')]
1836
1925
  ),
1837
1926
  ts.factory.createBlock(
1838
1927
  [
@@ -1840,45 +1929,35 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1840
1929
  ts.factory.createBinaryExpression(
1841
1930
  url,
1842
1931
  ts.factory.createToken(ts.SyntaxKind.EqualsToken),
1843
- ts.factory.createCallExpression(
1844
- ts.factory.createPropertyAccessExpression(url, ts.factory.createIdentifier('replace')),
1845
- undefined,
1846
- [
1847
- ts.factory.createNewExpression(ts.factory.createIdentifier('RegExp'), undefined, [
1848
- ts.factory.createBinaryExpression(
1849
- ts.factory.createBinaryExpression(
1850
- ts.factory.createStringLiteral('\\{'),
1851
- ts.factory.createToken(ts.SyntaxKind.PlusToken),
1852
- key,
1853
- ),
1854
- ts.factory.createToken(ts.SyntaxKind.PlusToken),
1855
- ts.factory.createStringLiteral('\\}'),
1856
- ),
1857
- ts.factory.createStringLiteral('g'),
1858
- ]),
1859
- value,
1860
- ],
1861
- ),
1862
- ),
1863
- ),
1932
+ ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(url, ts.factory.createIdentifier('replace')), undefined, [
1933
+ ts.factory.createNewExpression(ts.factory.createIdentifier('RegExp'), undefined, [
1934
+ ts.factory.createBinaryExpression(
1935
+ ts.factory.createBinaryExpression(ts.factory.createStringLiteral('\\{'), ts.factory.createToken(ts.SyntaxKind.PlusToken), key),
1936
+ ts.factory.createToken(ts.SyntaxKind.PlusToken),
1937
+ ts.factory.createStringLiteral('\\}')
1938
+ ),
1939
+ ts.factory.createStringLiteral('g')
1940
+ ]),
1941
+ value
1942
+ ])
1943
+ )
1944
+ )
1864
1945
  ],
1865
- true,
1866
- ),
1867
- ),
1946
+ true
1947
+ )
1948
+ )
1868
1949
  ],
1869
- true,
1870
- ),
1950
+ true
1951
+ )
1871
1952
  ),
1872
1953
  // return url
1873
- ts.factory.createReturnStatement(url),
1954
+ ts.factory.createReturnStatement(url)
1874
1955
  ],
1875
- true,
1876
- ),
1956
+ true
1957
+ )
1877
1958
  ),
1878
1959
  // return default (first server with defaults)
1879
- ts.factory.createReturnStatement(
1880
- ts.factory.createStringLiteral(servers[0] ? this.resolveServerUrl(servers[0], {}) : '/', true),
1881
- ),
1960
+ ts.factory.createReturnStatement(ts.factory.createStringLiteral(servers[0] ? this.resolveServerUrl(servers[0], {}) : '/', true))
1882
1961
  ];
1883
1962
 
1884
1963
  return ts.factory.createFunctionDeclaration(
@@ -1892,11 +1971,8 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1892
1971
  undefined,
1893
1972
  ts.factory.createIdentifier('serverIndex'),
1894
1973
  ts.factory.createToken(ts.SyntaxKind.QuestionToken),
1895
- ts.factory.createUnionTypeNode([
1896
- ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
1897
- ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
1898
- ]),
1899
- undefined,
1974
+ ts.factory.createUnionTypeNode([ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword), ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)]),
1975
+ undefined
1900
1976
  ),
1901
1977
  ts.factory.createParameterDeclaration(
1902
1978
  undefined,
@@ -1905,13 +1981,13 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1905
1981
  ts.factory.createToken(ts.SyntaxKind.QuestionToken),
1906
1982
  ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Record'), [
1907
1983
  ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
1908
- ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
1984
+ ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword)
1909
1985
  ]),
1910
- ts.factory.createObjectLiteralExpression([], false),
1911
- ),
1986
+ ts.factory.createObjectLiteralExpression([], false)
1987
+ )
1912
1988
  ],
1913
1989
  ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
1914
- ts.factory.createBlock(bodyStatements, true),
1990
+ ts.factory.createBlock(bodyStatements, true)
1915
1991
  );
1916
1992
  }
1917
1993
 
@@ -1931,12 +2007,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1931
2007
  /**
1932
2008
  * Builds a JSDoc comment string from operation metadata
1933
2009
  */
1934
- private buildJSDocComment(
1935
- summary: string | undefined,
1936
- description: string | undefined,
1937
- schema: MethodSchemaType,
1938
- responseType: ts.TypeNode | undefined,
1939
- ): string {
2010
+ private buildJSDocComment(summary: string | undefined, description: string | undefined, schema: MethodSchemaType, responseType: ts.TypeNode | undefined): string {
1940
2011
  const lines: string[] = [];
1941
2012
 
1942
2013
  // Add summary or description as the main comment
@@ -1957,6 +2028,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1957
2028
  if (lines.length > 0) {
1958
2029
  lines.push(' *');
1959
2030
  }
2031
+
1960
2032
  descLines.forEach((line) => {
1961
2033
  lines.push(` * ${line.trim() || ''}`);
1962
2034
  });
@@ -1968,6 +2040,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1968
2040
  if (lines.length > 0) {
1969
2041
  lines.push(' *');
1970
2042
  }
2043
+
1971
2044
  for (const param of schema.parameters) {
1972
2045
  const paramName = this.typeBuilder.sanitizeIdentifier(param.name);
1973
2046
  const paramDesc = param.description ? ` ${param.description}` : '';
@@ -1995,18 +2068,11 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
1995
2068
  ) {
1996
2069
  // Extract the inner type from Promise<T>
1997
2070
  const innerType = responseType.typeArguments[0];
1998
- returnTypeText = this.printer.printNode(
1999
- ts.EmitHint.Unspecified,
2000
- innerType,
2001
- ts.createSourceFile('', '', ts.ScriptTarget.Latest),
2002
- );
2071
+ returnTypeText = this.printer.printNode(ts.EmitHint.Unspecified, innerType, ts.createSourceFile('', '', ts.ScriptTarget.Latest));
2003
2072
  } else {
2004
- returnTypeText = this.printer.printNode(
2005
- ts.EmitHint.Unspecified,
2006
- responseType,
2007
- ts.createSourceFile('', '', ts.ScriptTarget.Latest),
2008
- );
2073
+ returnTypeText = this.printer.printNode(ts.EmitHint.Unspecified, responseType, ts.createSourceFile('', '', ts.ScriptTarget.Latest));
2009
2074
  }
2075
+
2010
2076
  lines.push(` * @returns {${returnTypeText}}`);
2011
2077
  }
2012
2078
 
@@ -2025,37 +2091,28 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2025
2091
 
2026
2092
  const initialExpression = !safeInitial.success
2027
2093
  ? ts.factory.createCallExpression(
2028
- ts.factory.createPropertyAccessExpression(
2029
- ts.factory.createIdentifier('z'),
2030
- ts.factory.createIdentifier(this.ZodAST.shape.type.parse(initial)),
2031
- ),
2094
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier(this.ZodAST.shape.type.parse(initial))),
2032
2095
  undefined,
2033
- [],
2096
+ []
2034
2097
  )
2035
2098
  : ts.factory.createCallExpression(
2036
- ts.factory.createPropertyAccessExpression(
2037
- ts.factory.createIdentifier('z'),
2038
- ts.factory.createIdentifier(safeInitial.data.type),
2039
- ),
2099
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier(safeInitial.data.type)),
2040
2100
  undefined,
2041
- (safeInitial.data.args ?? []) as ts.Expression[],
2101
+ (safeInitial.data.args ?? []) as ts.Expression[]
2042
2102
  );
2043
2103
 
2044
2104
  return rest.reduce((expression, exp: unknown) => {
2045
2105
  const safeExp = this.ZodAST.safeParse(exp);
2046
2106
  return !safeExp.success
2047
2107
  ? ts.factory.createCallExpression(
2048
- ts.factory.createPropertyAccessExpression(
2049
- expression,
2050
- ts.factory.createIdentifier(typeof exp === 'string' ? exp : String(exp)),
2051
- ),
2108
+ ts.factory.createPropertyAccessExpression(expression, ts.factory.createIdentifier(typeof exp === 'string' ? exp : String(exp))),
2052
2109
  undefined,
2053
- [],
2110
+ []
2054
2111
  )
2055
2112
  : ts.factory.createCallExpression(
2056
2113
  ts.factory.createPropertyAccessExpression(expression, ts.factory.createIdentifier(safeExp.data.type)),
2057
2114
  undefined,
2058
- (safeExp.data.args ?? []) as ts.Expression[],
2115
+ (safeExp.data.args ?? []) as ts.Expression[]
2059
2116
  );
2060
2117
  }, initialExpression);
2061
2118
  }
@@ -2071,13 +2128,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2071
2128
 
2072
2129
  if (this.isReference(prop)) {
2073
2130
  const refSchema = this.buildFromReference(prop);
2074
- return required
2075
- ? refSchema
2076
- : ts.factory.createCallExpression(
2077
- ts.factory.createPropertyAccessExpression(refSchema, ts.factory.createIdentifier('optional')),
2078
- undefined,
2079
- [],
2080
- );
2131
+ return required ? refSchema : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(refSchema, ts.factory.createIdentifier('optional')), undefined, []);
2081
2132
  }
2082
2133
 
2083
2134
  if (prop['anyOf'] && Array.isArray(prop['anyOf']) && prop['anyOf'].length > 0) {
@@ -2105,21 +2156,14 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2105
2156
  // Use z.enum() for string enums
2106
2157
  const enumValues = prop['enum'].map((val) => ts.factory.createStringLiteral(val as string, true));
2107
2158
  const enumExpression = ts.factory.createCallExpression(
2108
- ts.factory.createPropertyAccessExpression(
2109
- ts.factory.createIdentifier('z'),
2110
- ts.factory.createIdentifier('enum'),
2111
- ),
2159
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('enum')),
2112
2160
  undefined,
2113
- [ts.factory.createArrayLiteralExpression(enumValues, false)],
2161
+ [ts.factory.createArrayLiteralExpression(enumValues, false)]
2114
2162
  );
2115
2163
 
2116
2164
  return required
2117
2165
  ? enumExpression
2118
- : ts.factory.createCallExpression(
2119
- ts.factory.createPropertyAccessExpression(enumExpression, ts.factory.createIdentifier('optional')),
2120
- undefined,
2121
- [],
2122
- );
2166
+ : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(enumExpression, ts.factory.createIdentifier('optional')), undefined, []);
2123
2167
  } else {
2124
2168
  // Use z.union([z.literal(...), ...]) for numeric/boolean/mixed enums
2125
2169
  const literalSchemas = prop['enum'].map((val) => {
@@ -2129,10 +2173,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2129
2173
  } else if (typeof val === 'number') {
2130
2174
  // Handle negative numbers correctly
2131
2175
  if (val < 0) {
2132
- literalValue = ts.factory.createPrefixUnaryExpression(
2133
- ts.SyntaxKind.MinusToken,
2134
- ts.factory.createNumericLiteral(String(Math.abs(val))),
2135
- );
2176
+ literalValue = ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(String(Math.abs(val))));
2136
2177
  } else {
2137
2178
  literalValue = ts.factory.createNumericLiteral(String(val));
2138
2179
  }
@@ -2142,32 +2183,20 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2142
2183
  literalValue = ts.factory.createStringLiteral(String(val), true);
2143
2184
  }
2144
2185
 
2145
- return ts.factory.createCallExpression(
2146
- ts.factory.createPropertyAccessExpression(
2147
- ts.factory.createIdentifier('z'),
2148
- ts.factory.createIdentifier('literal'),
2149
- ),
2150
- undefined,
2151
- [literalValue],
2152
- );
2186
+ return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('literal')), undefined, [
2187
+ literalValue
2188
+ ]);
2153
2189
  });
2154
2190
 
2155
2191
  const unionExpression = ts.factory.createCallExpression(
2156
- ts.factory.createPropertyAccessExpression(
2157
- ts.factory.createIdentifier('z'),
2158
- ts.factory.createIdentifier('union'),
2159
- ),
2192
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('union')),
2160
2193
  undefined,
2161
- [ts.factory.createArrayLiteralExpression(literalSchemas, false)],
2194
+ [ts.factory.createArrayLiteralExpression(literalSchemas, false)]
2162
2195
  );
2163
2196
 
2164
2197
  return required
2165
2198
  ? unionExpression
2166
- : ts.factory.createCallExpression(
2167
- ts.factory.createPropertyAccessExpression(unionExpression, ts.factory.createIdentifier('optional')),
2168
- undefined,
2169
- [],
2170
- );
2199
+ : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(unionExpression, ts.factory.createIdentifier('optional')), undefined, []);
2171
2200
  }
2172
2201
  }
2173
2202
 
@@ -2177,33 +2206,26 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2177
2206
  let arraySchema = this.buildZodAST([
2178
2207
  {
2179
2208
  type: 'array',
2180
- args: [itemsSchema],
2181
- },
2209
+ args: [itemsSchema]
2210
+ }
2182
2211
  ]);
2183
2212
 
2184
2213
  // Apply array constraints
2185
2214
  if (typeof prop['minItems'] === 'number') {
2186
- arraySchema = ts.factory.createCallExpression(
2187
- ts.factory.createPropertyAccessExpression(arraySchema, ts.factory.createIdentifier('min')),
2188
- undefined,
2189
- [ts.factory.createNumericLiteral(String(prop['minItems']))],
2190
- );
2215
+ arraySchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(arraySchema, ts.factory.createIdentifier('min')), undefined, [
2216
+ ts.factory.createNumericLiteral(String(prop['minItems']))
2217
+ ]);
2191
2218
  }
2219
+
2192
2220
  if (typeof prop['maxItems'] === 'number') {
2193
- arraySchema = ts.factory.createCallExpression(
2194
- ts.factory.createPropertyAccessExpression(arraySchema, ts.factory.createIdentifier('max')),
2195
- undefined,
2196
- [ts.factory.createNumericLiteral(String(prop['maxItems']))],
2197
- );
2221
+ arraySchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(arraySchema, ts.factory.createIdentifier('max')), undefined, [
2222
+ ts.factory.createNumericLiteral(String(prop['maxItems']))
2223
+ ]);
2198
2224
  }
2199
2225
 
2200
2226
  return required
2201
2227
  ? arraySchema
2202
- : ts.factory.createCallExpression(
2203
- ts.factory.createPropertyAccessExpression(arraySchema, ts.factory.createIdentifier('optional')),
2204
- undefined,
2205
- [],
2206
- );
2228
+ : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(arraySchema, ts.factory.createIdentifier('optional')), undefined, []);
2207
2229
  }
2208
2230
  case 'object': {
2209
2231
  const propObj = prop satisfies {
@@ -2222,110 +2244,86 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2222
2244
  args: [
2223
2245
  ts.factory.createObjectLiteralExpression(
2224
2246
  propertiesEntries.map(([name, propValue]): ts.ObjectLiteralElementLike => {
2225
- return ts.factory.createPropertyAssignment(
2226
- ts.factory.createIdentifier(name),
2227
- this.buildProperty(propValue, propRequired.includes(name)),
2228
- );
2247
+ return ts.factory.createPropertyAssignment(ts.factory.createIdentifier(name), this.buildProperty(propValue, propRequired.includes(name)));
2229
2248
  }),
2230
- true,
2231
- ),
2232
- ],
2233
- },
2249
+ true
2250
+ )
2251
+ ]
2252
+ }
2234
2253
  ]);
2235
2254
 
2236
2255
  // Apply object constraints
2237
2256
  let constrainedSchema = objectSchema;
2238
2257
  if (typeof prop['minProperties'] === 'number') {
2239
- constrainedSchema = ts.factory.createCallExpression(
2240
- ts.factory.createPropertyAccessExpression(constrainedSchema, ts.factory.createIdentifier('refine')),
2241
- undefined,
2242
- [
2243
- ts.factory.createArrowFunction(
2244
- undefined,
2245
- undefined,
2246
- [ts.factory.createParameterDeclaration(undefined, undefined, 'obj', undefined, undefined, undefined)],
2247
- undefined,
2248
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2249
- ts.factory.createBinaryExpression(
2250
- ts.factory.createPropertyAccessExpression(
2251
- ts.factory.createCallExpression(
2252
- ts.factory.createPropertyAccessExpression(
2253
- ts.factory.createIdentifier('Object'),
2254
- ts.factory.createIdentifier('keys'),
2255
- ),
2256
- undefined,
2257
- [ts.factory.createIdentifier('obj')],
2258
- ),
2259
- ts.factory.createIdentifier('length'),
2260
- ),
2261
- ts.factory.createToken(ts.SyntaxKind.GreaterThanEqualsToken),
2262
- ts.factory.createNumericLiteral(String(prop['minProperties'])),
2263
- ),
2264
- ),
2265
- ts.factory.createObjectLiteralExpression([
2266
- ts.factory.createPropertyAssignment(
2267
- ts.factory.createIdentifier('message'),
2268
- ts.factory.createStringLiteral(
2269
- `Object must have at least ${String(prop['minProperties'])} properties`,
2258
+ constrainedSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(constrainedSchema, ts.factory.createIdentifier('refine')), undefined, [
2259
+ ts.factory.createArrowFunction(
2260
+ undefined,
2261
+ undefined,
2262
+ [ts.factory.createParameterDeclaration(undefined, undefined, 'obj', undefined, undefined, undefined)],
2263
+ undefined,
2264
+ ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2265
+ ts.factory.createBinaryExpression(
2266
+ ts.factory.createPropertyAccessExpression(
2267
+ ts.factory.createCallExpression(
2268
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('keys')),
2269
+ undefined,
2270
+ [ts.factory.createIdentifier('obj')]
2270
2271
  ),
2272
+ ts.factory.createIdentifier('length')
2271
2273
  ),
2272
- ]),
2273
- ],
2274
- );
2274
+ ts.factory.createToken(ts.SyntaxKind.GreaterThanEqualsToken),
2275
+ ts.factory.createNumericLiteral(String(prop['minProperties']))
2276
+ )
2277
+ ),
2278
+ ts.factory.createObjectLiteralExpression([
2279
+ ts.factory.createPropertyAssignment(
2280
+ ts.factory.createIdentifier('message'),
2281
+ ts.factory.createStringLiteral(`Object must have at least ${String(prop['minProperties'])} properties`)
2282
+ )
2283
+ ])
2284
+ ]);
2275
2285
  }
2286
+
2276
2287
  if (typeof prop['maxProperties'] === 'number') {
2277
- constrainedSchema = ts.factory.createCallExpression(
2278
- ts.factory.createPropertyAccessExpression(constrainedSchema, ts.factory.createIdentifier('refine')),
2279
- undefined,
2280
- [
2281
- ts.factory.createArrowFunction(
2282
- undefined,
2283
- undefined,
2284
- [ts.factory.createParameterDeclaration(undefined, undefined, 'obj', undefined, undefined, undefined)],
2285
- undefined,
2286
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2287
- ts.factory.createBinaryExpression(
2288
- ts.factory.createPropertyAccessExpression(
2289
- ts.factory.createCallExpression(
2290
- ts.factory.createPropertyAccessExpression(
2291
- ts.factory.createIdentifier('Object'),
2292
- ts.factory.createIdentifier('keys'),
2293
- ),
2294
- undefined,
2295
- [ts.factory.createIdentifier('obj')],
2296
- ),
2297
- ts.factory.createIdentifier('length'),
2298
- ),
2299
- ts.factory.createToken(ts.SyntaxKind.LessThanEqualsToken),
2300
- ts.factory.createNumericLiteral(String(prop['maxProperties'])),
2301
- ),
2302
- ),
2303
- ts.factory.createObjectLiteralExpression([
2304
- ts.factory.createPropertyAssignment(
2305
- ts.factory.createIdentifier('message'),
2306
- ts.factory.createStringLiteral(
2307
- `Object must have at most ${String(prop['maxProperties'])} properties`,
2288
+ constrainedSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(constrainedSchema, ts.factory.createIdentifier('refine')), undefined, [
2289
+ ts.factory.createArrowFunction(
2290
+ undefined,
2291
+ undefined,
2292
+ [ts.factory.createParameterDeclaration(undefined, undefined, 'obj', undefined, undefined, undefined)],
2293
+ undefined,
2294
+ ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2295
+ ts.factory.createBinaryExpression(
2296
+ ts.factory.createPropertyAccessExpression(
2297
+ ts.factory.createCallExpression(
2298
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('keys')),
2299
+ undefined,
2300
+ [ts.factory.createIdentifier('obj')]
2308
2301
  ),
2302
+ ts.factory.createIdentifier('length')
2309
2303
  ),
2310
- ]),
2311
- ],
2312
- );
2304
+ ts.factory.createToken(ts.SyntaxKind.LessThanEqualsToken),
2305
+ ts.factory.createNumericLiteral(String(prop['maxProperties']))
2306
+ )
2307
+ ),
2308
+ ts.factory.createObjectLiteralExpression([
2309
+ ts.factory.createPropertyAssignment(
2310
+ ts.factory.createIdentifier('message'),
2311
+ ts.factory.createStringLiteral(`Object must have at most ${String(prop['maxProperties'])} properties`)
2312
+ )
2313
+ ])
2314
+ ]);
2313
2315
  }
2314
2316
 
2315
2317
  return required
2316
2318
  ? constrainedSchema
2317
- : ts.factory.createCallExpression(
2318
- ts.factory.createPropertyAccessExpression(constrainedSchema, ts.factory.createIdentifier('optional')),
2319
- undefined,
2320
- [],
2321
- );
2319
+ : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(constrainedSchema, ts.factory.createIdentifier('optional')), undefined, []);
2322
2320
  }
2323
2321
 
2324
2322
  return this.buildZodAST([
2325
2323
  {
2326
2324
  type: 'record',
2327
- args: [this.buildZodAST(['string']), this.buildZodAST(['unknown'])],
2328
- },
2325
+ args: [this.buildZodAST(['string']), this.buildZodAST(['unknown'])]
2326
+ }
2329
2327
  ]);
2330
2328
  }
2331
2329
  case 'integer': {
@@ -2333,35 +2331,26 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2333
2331
 
2334
2332
  // Apply number constraints
2335
2333
  if (prop['minimum'] !== undefined && typeof prop['minimum'] === 'number') {
2336
- const minValue =
2337
- prop['exclusiveMinimum'] && typeof prop['exclusiveMinimum'] === 'boolean'
2338
- ? prop['minimum'] + 1
2339
- : prop['minimum'];
2334
+ const minValue = prop['exclusiveMinimum'] && typeof prop['exclusiveMinimum'] === 'boolean' ? prop['minimum'] + 1 : prop['minimum'];
2340
2335
  numberSchema = ts.factory.createCallExpression(
2341
2336
  ts.factory.createPropertyAccessExpression(
2342
2337
  numberSchema,
2343
- ts.factory.createIdentifier(
2344
- prop['exclusiveMinimum'] && typeof prop['exclusiveMinimum'] === 'boolean' ? 'gt' : 'gte',
2345
- ),
2338
+ ts.factory.createIdentifier(prop['exclusiveMinimum'] && typeof prop['exclusiveMinimum'] === 'boolean' ? 'gt' : 'gte')
2346
2339
  ),
2347
2340
  undefined,
2348
- [ts.factory.createNumericLiteral(String(minValue))],
2341
+ [ts.factory.createNumericLiteral(String(minValue))]
2349
2342
  );
2350
2343
  }
2344
+
2351
2345
  if (prop['maximum'] !== undefined && typeof prop['maximum'] === 'number') {
2352
- const maxValue =
2353
- prop['exclusiveMaximum'] && typeof prop['exclusiveMaximum'] === 'boolean'
2354
- ? prop['maximum'] - 1
2355
- : prop['maximum'];
2346
+ const maxValue = prop['exclusiveMaximum'] && typeof prop['exclusiveMaximum'] === 'boolean' ? prop['maximum'] - 1 : prop['maximum'];
2356
2347
  numberSchema = ts.factory.createCallExpression(
2357
- ts.factory.createPropertyAccessExpression(
2358
- numberSchema,
2359
- ts.factory.createIdentifier(prop['exclusiveMaximum'] ? 'lt' : 'lte'),
2360
- ),
2348
+ ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier(prop['exclusiveMaximum'] ? 'lt' : 'lte')),
2361
2349
  undefined,
2362
- [ts.factory.createNumericLiteral(String(maxValue))],
2350
+ [ts.factory.createNumericLiteral(String(maxValue))]
2363
2351
  );
2364
2352
  }
2353
+
2365
2354
  if (typeof prop['multipleOf'] === 'number') {
2366
2355
  const refineFunction = ts.factory.createArrowFunction(
2367
2356
  undefined,
@@ -2373,67 +2362,53 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2373
2362
  ts.factory.createBinaryExpression(
2374
2363
  ts.factory.createIdentifier('val'),
2375
2364
  ts.factory.createToken(ts.SyntaxKind.PercentToken),
2376
- ts.factory.createNumericLiteral(String(prop['multipleOf'])),
2365
+ ts.factory.createNumericLiteral(String(prop['multipleOf']))
2377
2366
  ),
2378
2367
  ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
2379
- ts.factory.createNumericLiteral('0'),
2380
- ),
2368
+ ts.factory.createNumericLiteral('0')
2369
+ )
2381
2370
  );
2382
2371
  const refineOptions = ts.factory.createObjectLiteralExpression([
2383
2372
  ts.factory.createPropertyAssignment(
2384
2373
  ts.factory.createIdentifier('message'),
2385
- ts.factory.createStringLiteral(`Number must be a multiple of ${String(prop['multipleOf'])}`),
2386
- ),
2374
+ ts.factory.createStringLiteral(`Number must be a multiple of ${String(prop['multipleOf'])}`)
2375
+ )
2376
+ ]);
2377
+ numberSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier('refine')), undefined, [
2378
+ refineFunction,
2379
+ refineOptions
2387
2380
  ]);
2388
- numberSchema = ts.factory.createCallExpression(
2389
- ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier('refine')),
2390
- undefined,
2391
- [refineFunction, refineOptions],
2392
- );
2393
2381
  }
2394
2382
 
2395
2383
  return required
2396
2384
  ? numberSchema
2397
- : ts.factory.createCallExpression(
2398
- ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier('optional')),
2399
- undefined,
2400
- [],
2401
- );
2385
+ : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier('optional')), undefined, []);
2402
2386
  }
2403
2387
  case 'number': {
2404
2388
  let numberSchema = this.buildZodAST(['number']);
2405
2389
 
2406
2390
  // Apply number constraints
2407
2391
  if (prop['minimum'] !== undefined && typeof prop['minimum'] === 'number') {
2408
- const minValue =
2409
- prop['exclusiveMinimum'] && typeof prop['exclusiveMinimum'] === 'boolean'
2410
- ? prop['minimum'] + 1
2411
- : prop['minimum'];
2392
+ const minValue = prop['exclusiveMinimum'] && typeof prop['exclusiveMinimum'] === 'boolean' ? prop['minimum'] + 1 : prop['minimum'];
2412
2393
  numberSchema = ts.factory.createCallExpression(
2413
2394
  ts.factory.createPropertyAccessExpression(
2414
2395
  numberSchema,
2415
- ts.factory.createIdentifier(
2416
- prop['exclusiveMinimum'] && typeof prop['exclusiveMinimum'] === 'boolean' ? 'gt' : 'gte',
2417
- ),
2396
+ ts.factory.createIdentifier(prop['exclusiveMinimum'] && typeof prop['exclusiveMinimum'] === 'boolean' ? 'gt' : 'gte')
2418
2397
  ),
2419
2398
  undefined,
2420
- [ts.factory.createNumericLiteral(String(minValue))],
2399
+ [ts.factory.createNumericLiteral(String(minValue))]
2421
2400
  );
2422
2401
  }
2402
+
2423
2403
  if (prop['maximum'] !== undefined && typeof prop['maximum'] === 'number') {
2424
- const maxValue =
2425
- prop['exclusiveMaximum'] && typeof prop['exclusiveMaximum'] === 'boolean'
2426
- ? prop['maximum'] - 1
2427
- : prop['maximum'];
2404
+ const maxValue = prop['exclusiveMaximum'] && typeof prop['exclusiveMaximum'] === 'boolean' ? prop['maximum'] - 1 : prop['maximum'];
2428
2405
  numberSchema = ts.factory.createCallExpression(
2429
- ts.factory.createPropertyAccessExpression(
2430
- numberSchema,
2431
- ts.factory.createIdentifier(prop['exclusiveMaximum'] ? 'lt' : 'lte'),
2432
- ),
2406
+ ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier(prop['exclusiveMaximum'] ? 'lt' : 'lte')),
2433
2407
  undefined,
2434
- [ts.factory.createNumericLiteral(String(maxValue))],
2408
+ [ts.factory.createNumericLiteral(String(maxValue))]
2435
2409
  );
2436
2410
  }
2411
+
2437
2412
  if (typeof prop['multipleOf'] === 'number') {
2438
2413
  const refineFunction = ts.factory.createArrowFunction(
2439
2414
  undefined,
@@ -2445,32 +2420,27 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2445
2420
  ts.factory.createBinaryExpression(
2446
2421
  ts.factory.createIdentifier('val'),
2447
2422
  ts.factory.createToken(ts.SyntaxKind.PercentToken),
2448
- ts.factory.createNumericLiteral(String(prop['multipleOf'])),
2423
+ ts.factory.createNumericLiteral(String(prop['multipleOf']))
2449
2424
  ),
2450
2425
  ts.factory.createToken(ts.SyntaxKind.EqualsEqualsEqualsToken),
2451
- ts.factory.createNumericLiteral('0'),
2452
- ),
2426
+ ts.factory.createNumericLiteral('0')
2427
+ )
2453
2428
  );
2454
2429
  const refineOptions = ts.factory.createObjectLiteralExpression([
2455
2430
  ts.factory.createPropertyAssignment(
2456
2431
  ts.factory.createIdentifier('message'),
2457
- ts.factory.createStringLiteral(`Number must be a multiple of ${String(prop['multipleOf'])}`),
2458
- ),
2432
+ ts.factory.createStringLiteral(`Number must be a multiple of ${String(prop['multipleOf'])}`)
2433
+ )
2434
+ ]);
2435
+ numberSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier('refine')), undefined, [
2436
+ refineFunction,
2437
+ refineOptions
2459
2438
  ]);
2460
- numberSchema = ts.factory.createCallExpression(
2461
- ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier('refine')),
2462
- undefined,
2463
- [refineFunction, refineOptions],
2464
- );
2465
2439
  }
2466
2440
 
2467
2441
  return required
2468
2442
  ? numberSchema
2469
- : ts.factory.createCallExpression(
2470
- ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier('optional')),
2471
- undefined,
2472
- [],
2473
- );
2443
+ : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(numberSchema, ts.factory.createIdentifier('optional')), undefined, []);
2474
2444
  }
2475
2445
  case 'string': {
2476
2446
  let stringSchema = this.buildZodAST(['string']);
@@ -2480,67 +2450,48 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2480
2450
  switch (prop['format']) {
2481
2451
  case 'email':
2482
2452
  stringSchema = ts.factory.createCallExpression(
2483
- ts.factory.createPropertyAccessExpression(
2484
- ts.factory.createIdentifier('z'),
2485
- ts.factory.createIdentifier('email'),
2486
- ),
2453
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('email')),
2487
2454
  undefined,
2488
- [],
2455
+ []
2489
2456
  );
2490
2457
  break;
2491
2458
  case 'uri':
2492
2459
  case 'url':
2493
2460
  stringSchema = ts.factory.createCallExpression(
2494
- ts.factory.createPropertyAccessExpression(
2495
- ts.factory.createIdentifier('z'),
2496
- ts.factory.createIdentifier('url'),
2497
- ),
2461
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('url')),
2498
2462
  undefined,
2499
- [],
2463
+ []
2500
2464
  );
2501
2465
  break;
2502
2466
  case 'uuid':
2503
2467
  stringSchema = ts.factory.createCallExpression(
2504
- ts.factory.createPropertyAccessExpression(
2505
- ts.factory.createIdentifier('z'),
2506
- ts.factory.createIdentifier('uuid'),
2507
- ),
2468
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('uuid')),
2508
2469
  undefined,
2509
- [],
2470
+ []
2510
2471
  );
2511
2472
  break;
2512
2473
  case 'date-time':
2513
2474
  stringSchema = ts.factory.createCallExpression(
2514
2475
  ts.factory.createPropertyAccessExpression(
2515
- ts.factory.createPropertyAccessExpression(
2516
- ts.factory.createIdentifier('z'),
2517
- ts.factory.createIdentifier('iso'),
2518
- ),
2519
- ts.factory.createIdentifier('datetime'),
2476
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('iso')),
2477
+ ts.factory.createIdentifier('datetime')
2520
2478
  ),
2521
2479
  undefined,
2522
- [this.buildDefaultValue({local: true})],
2480
+ [this.buildDefaultValue({ local: true })]
2523
2481
  );
2524
2482
  break;
2525
2483
  case 'date':
2526
2484
  stringSchema = ts.factory.createCallExpression(
2527
2485
  ts.factory.createPropertyAccessExpression(
2528
- ts.factory.createPropertyAccessExpression(
2529
- ts.factory.createIdentifier('z'),
2530
- ts.factory.createIdentifier('iso'),
2531
- ),
2532
- ts.factory.createIdentifier('date'),
2486
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('iso')),
2487
+ ts.factory.createIdentifier('date')
2533
2488
  ),
2534
2489
  undefined,
2535
- [],
2490
+ []
2536
2491
  );
2537
2492
  break;
2538
2493
  case 'time':
2539
- stringSchema = ts.factory.createCallExpression(
2540
- ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('time')),
2541
- undefined,
2542
- [],
2543
- );
2494
+ stringSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('time')), undefined, []);
2544
2495
  break;
2545
2496
  // Add more formats as needed
2546
2497
  }
@@ -2548,74 +2499,49 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2548
2499
 
2549
2500
  // Apply string constraints
2550
2501
  if (typeof prop['minLength'] === 'number') {
2551
- stringSchema = ts.factory.createCallExpression(
2552
- ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('min')),
2553
- undefined,
2554
- [ts.factory.createNumericLiteral(String(prop['minLength']))],
2555
- );
2502
+ stringSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('min')), undefined, [
2503
+ ts.factory.createNumericLiteral(String(prop['minLength']))
2504
+ ]);
2556
2505
  }
2506
+
2557
2507
  if (typeof prop['maxLength'] === 'number') {
2558
- stringSchema = ts.factory.createCallExpression(
2559
- ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('max')),
2560
- undefined,
2561
- [ts.factory.createNumericLiteral(String(prop['maxLength']))],
2562
- );
2508
+ stringSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('max')), undefined, [
2509
+ ts.factory.createNumericLiteral(String(prop['maxLength']))
2510
+ ]);
2563
2511
  }
2512
+
2564
2513
  if (prop['pattern'] && typeof prop['pattern'] === 'string') {
2565
- stringSchema = ts.factory.createCallExpression(
2566
- ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('regex')),
2567
- undefined,
2568
- [
2569
- ts.factory.createNewExpression(ts.factory.createIdentifier('RegExp'), undefined, [
2570
- ts.factory.createStringLiteral(prop['pattern'], true),
2571
- ]),
2572
- ],
2573
- );
2514
+ stringSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('regex')), undefined, [
2515
+ ts.factory.createNewExpression(ts.factory.createIdentifier('RegExp'), undefined, [ts.factory.createStringLiteral(prop['pattern'], true)])
2516
+ ]);
2574
2517
  }
2575
2518
 
2576
2519
  // Apply default value if not required
2577
2520
  if (!required && prop['default'] !== undefined) {
2578
2521
  const defaultValue = this.buildDefaultValue(prop['default']);
2579
- stringSchema = ts.factory.createCallExpression(
2580
- ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('default')),
2581
- undefined,
2582
- [defaultValue],
2583
- );
2522
+ stringSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('default')), undefined, [
2523
+ defaultValue
2524
+ ]);
2584
2525
  }
2585
2526
 
2586
2527
  return required
2587
2528
  ? stringSchema
2588
- : ts.factory.createCallExpression(
2589
- ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('optional')),
2590
- undefined,
2591
- [],
2592
- );
2529
+ : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(stringSchema, ts.factory.createIdentifier('optional')), undefined, []);
2593
2530
  }
2594
2531
  case 'boolean': {
2595
2532
  let booleanSchema = this.buildZodAST(['boolean']);
2596
2533
 
2597
2534
  // Apply default value if not required
2598
2535
  if (!required && prop['default'] !== undefined) {
2599
- const defaultValue =
2600
- typeof prop['default'] === 'boolean'
2601
- ? prop['default']
2602
- ? ts.factory.createTrue()
2603
- : ts.factory.createFalse()
2604
- : ts.factory.createFalse();
2605
- booleanSchema = ts.factory.createCallExpression(
2606
- ts.factory.createPropertyAccessExpression(booleanSchema, ts.factory.createIdentifier('default')),
2607
- undefined,
2608
- [defaultValue],
2609
- );
2536
+ const defaultValue = typeof prop['default'] === 'boolean' ? (prop['default'] ? ts.factory.createTrue() : ts.factory.createFalse()) : ts.factory.createFalse();
2537
+ booleanSchema = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(booleanSchema, ts.factory.createIdentifier('default')), undefined, [
2538
+ defaultValue
2539
+ ]);
2610
2540
  }
2611
2541
 
2612
2542
  return required
2613
2543
  ? booleanSchema
2614
- : ts.factory.createCallExpression(
2615
- ts.factory.createPropertyAccessExpression(booleanSchema, ts.factory.createIdentifier('optional')),
2616
- undefined,
2617
- [],
2618
- );
2544
+ : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(booleanSchema, ts.factory.createIdentifier('optional')), undefined, []);
2619
2545
  }
2620
2546
  case 'unknown':
2621
2547
  default:
@@ -2627,54 +2553,52 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2627
2553
  if (typeof value === 'string') {
2628
2554
  return ts.factory.createStringLiteral(value, true);
2629
2555
  }
2556
+
2630
2557
  if (typeof value === 'number') {
2631
2558
  return ts.factory.createNumericLiteral(String(value));
2632
2559
  }
2560
+
2633
2561
  if (typeof value === 'boolean') {
2634
2562
  return value ? ts.factory.createTrue() : ts.factory.createFalse();
2635
2563
  }
2564
+
2636
2565
  if (value === null) {
2637
2566
  return ts.factory.createNull();
2638
2567
  }
2568
+
2639
2569
  if (Array.isArray(value)) {
2640
2570
  return ts.factory.createArrayLiteralExpression(
2641
2571
  value.map((item) => this.buildDefaultValue(item)),
2642
- false,
2572
+ false
2643
2573
  );
2644
2574
  }
2575
+
2645
2576
  if (typeof value === 'object') {
2646
2577
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
2647
2578
  if (value === null) {
2648
2579
  return ts.factory.createNull();
2649
2580
  }
2581
+
2650
2582
  return ts.factory.createObjectLiteralExpression(
2651
- Object.entries(value).map(([key, val]) =>
2652
- ts.factory.createPropertyAssignment(ts.factory.createIdentifier(key), this.buildDefaultValue(val)),
2653
- ),
2654
- true,
2583
+ Object.entries(value).map(([key, val]) => ts.factory.createPropertyAssignment(ts.factory.createIdentifier(key), this.buildDefaultValue(val))),
2584
+ true
2655
2585
  );
2656
2586
  }
2587
+
2657
2588
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
2658
2589
  return ts.factory.createStringLiteral(String(value), true);
2659
2590
  }
2591
+
2660
2592
  // For objects and arrays, we need to handle them differently
2661
2593
  // This should not happen in practice, but we handle it for type safety
2662
2594
  return ts.factory.createStringLiteral(JSON.stringify(value), true);
2663
2595
  }
2664
2596
 
2665
- private handleLogicalOperator(
2666
- operator: 'anyOf' | 'oneOf' | 'allOf' | 'not',
2667
- schemas: unknown[],
2668
- required: boolean,
2669
- ): ts.CallExpression {
2597
+ private handleLogicalOperator(operator: 'anyOf' | 'oneOf' | 'allOf' | 'not', schemas: unknown[], required: boolean): ts.CallExpression {
2670
2598
  const logicalExpression = this.buildLogicalOperator(operator, schemas);
2671
2599
  return required
2672
2600
  ? logicalExpression
2673
- : ts.factory.createCallExpression(
2674
- ts.factory.createPropertyAccessExpression(logicalExpression, ts.factory.createIdentifier('optional')),
2675
- undefined,
2676
- [],
2677
- );
2601
+ : ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(logicalExpression, ts.factory.createIdentifier('optional')), undefined, []);
2678
2602
  }
2679
2603
 
2680
2604
  private buildLogicalOperator(operator: 'anyOf' | 'oneOf' | 'allOf' | 'not', schemas: unknown[]): ts.CallExpression {
@@ -2682,14 +2606,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2682
2606
  case 'anyOf':
2683
2607
  case 'oneOf': {
2684
2608
  const unionSchemas = schemas.map((schema) => this.buildSchemaFromLogicalOperator(schema));
2685
- return ts.factory.createCallExpression(
2686
- ts.factory.createPropertyAccessExpression(
2687
- ts.factory.createIdentifier('z'),
2688
- ts.factory.createIdentifier('union'),
2689
- ),
2690
- undefined,
2691
- [ts.factory.createArrayLiteralExpression(unionSchemas, false)],
2692
- );
2609
+ return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('union')), undefined, [
2610
+ ts.factory.createArrayLiteralExpression(unionSchemas, false)
2611
+ ]);
2693
2612
  }
2694
2613
  case 'allOf': {
2695
2614
  if (schemas.length === 0) {
@@ -2700,12 +2619,9 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2700
2619
  return schemas.slice(1).reduce<ts.Expression>((acc, schema) => {
2701
2620
  const schemaExpression = this.buildSchemaFromLogicalOperator(schema);
2702
2621
  return ts.factory.createCallExpression(
2703
- ts.factory.createPropertyAccessExpression(
2704
- ts.factory.createIdentifier('z'),
2705
- ts.factory.createIdentifier('intersection'),
2706
- ),
2622
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('intersection')),
2707
2623
  undefined,
2708
- [acc, schemaExpression],
2624
+ [acc, schemaExpression]
2709
2625
  );
2710
2626
  }, firstSchema) as ts.CallExpression;
2711
2627
  }
@@ -2713,11 +2629,8 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2713
2629
  const notSchema = this.buildSchemaFromLogicalOperator(schemas[0]);
2714
2630
  return ts.factory.createCallExpression(
2715
2631
  ts.factory.createPropertyAccessExpression(
2716
- ts.factory.createPropertyAccessExpression(
2717
- ts.factory.createIdentifier('z'),
2718
- ts.factory.createIdentifier('any'),
2719
- ),
2720
- ts.factory.createIdentifier('refine'),
2632
+ ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('any')),
2633
+ ts.factory.createIdentifier('refine')
2721
2634
  ),
2722
2635
  undefined,
2723
2636
  [
@@ -2729,20 +2642,15 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2729
2642
  ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2730
2643
  ts.factory.createPrefixUnaryExpression(
2731
2644
  ts.SyntaxKind.ExclamationToken,
2732
- ts.factory.createCallExpression(
2733
- ts.factory.createPropertyAccessExpression(notSchema, ts.factory.createIdentifier('safeParse')),
2734
- undefined,
2735
- [ts.factory.createIdentifier('val')],
2736
- ),
2737
- ),
2645
+ ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(notSchema, ts.factory.createIdentifier('safeParse')), undefined, [
2646
+ ts.factory.createIdentifier('val')
2647
+ ])
2648
+ )
2738
2649
  ),
2739
2650
  ts.factory.createObjectLiteralExpression([
2740
- ts.factory.createPropertyAssignment(
2741
- ts.factory.createIdentifier('message'),
2742
- ts.factory.createStringLiteral('Value must not match the excluded schema'),
2743
- ),
2744
- ]),
2745
- ],
2651
+ ts.factory.createPropertyAssignment(ts.factory.createIdentifier('message'), ts.factory.createStringLiteral('Value must not match the excluded schema'))
2652
+ ])
2653
+ ]
2746
2654
  );
2747
2655
  }
2748
2656
  default:
@@ -2766,7 +2674,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2766
2674
 
2767
2675
  private buildBasicTypeFromSchema(schema: unknown): ts.CallExpression | ts.Identifier {
2768
2676
  if (typeof schema === 'object' && schema !== null && 'type' in schema) {
2769
- const schemaObj = schema as {type: string; properties?: Record<string, unknown>; items?: unknown};
2677
+ const schemaObj = schema as { type: string; properties?: Record<string, unknown>; items?: unknown };
2770
2678
 
2771
2679
  switch (schemaObj.type) {
2772
2680
  case 'string':
@@ -2789,7 +2697,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2789
2697
  return this.buildZodAST(['unknown']);
2790
2698
  }
2791
2699
 
2792
- private buildObjectTypeFromSchema(schemaObj: {properties?: Record<string, unknown>}): ts.CallExpression {
2700
+ private buildObjectTypeFromSchema(schemaObj: { properties?: Record<string, unknown> }): ts.CallExpression {
2793
2701
  const properties = Object.entries(schemaObj.properties ?? {});
2794
2702
 
2795
2703
  if (properties.length > 0) {
@@ -2799,71 +2707,63 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2799
2707
  args: [
2800
2708
  ts.factory.createObjectLiteralExpression(
2801
2709
  properties.map(([name, property]): ts.ObjectLiteralElementLike => {
2802
- return ts.factory.createPropertyAssignment(
2803
- ts.factory.createIdentifier(name),
2804
- this.buildSchemaFromLogicalOperator(property),
2805
- );
2710
+ return ts.factory.createPropertyAssignment(ts.factory.createIdentifier(name), this.buildSchemaFromLogicalOperator(property));
2806
2711
  }),
2807
- true,
2808
- ),
2809
- ],
2810
- },
2712
+ true
2713
+ )
2714
+ ]
2715
+ }
2811
2716
  ]);
2812
2717
  }
2813
2718
 
2814
2719
  return this.buildZodAST([
2815
2720
  {
2816
2721
  type: 'record',
2817
- args: [this.buildZodAST(['string']), this.buildZodAST(['unknown'])],
2818
- },
2722
+ args: [this.buildZodAST(['string']), this.buildZodAST(['unknown'])]
2723
+ }
2819
2724
  ]);
2820
2725
  }
2821
2726
 
2822
- private buildArrayTypeFromSchema(schemaObj: {items?: unknown}): ts.CallExpression {
2727
+ private buildArrayTypeFromSchema(schemaObj: { items?: unknown }): ts.CallExpression {
2823
2728
  if (schemaObj.items) {
2824
2729
  return this.buildZodAST([
2825
2730
  {
2826
2731
  type: 'array',
2827
- args: [this.buildSchemaFromLogicalOperator(schemaObj.items)],
2828
- },
2732
+ args: [this.buildSchemaFromLogicalOperator(schemaObj.items)]
2733
+ }
2829
2734
  ]);
2830
2735
  }
2736
+
2831
2737
  return this.buildZodAST(['array']);
2832
2738
  }
2833
2739
 
2834
2740
  private isReference(reference: unknown): reference is ReferenceType {
2835
2741
  if (typeof reference === 'object' && reference !== null && '$ref' in reference) {
2836
- const ref = reference satisfies {$ref?: unknown};
2742
+ const ref = reference satisfies { $ref?: unknown };
2837
2743
  return typeof ref.$ref === 'string' && ref.$ref.length > 0;
2838
2744
  }
2745
+
2839
2746
  return false;
2840
2747
  }
2841
2748
 
2842
2749
  private buildFromReference(reference: ReferenceType): ts.CallExpression | ts.Identifier {
2843
- const {$ref = ''} = Reference.parse(reference);
2750
+ const { $ref = '' } = Reference.parse(reference);
2844
2751
  const refName = $ref.split('/').pop() ?? 'never';
2845
2752
  const sanitizedRefName = this.typeBuilder.sanitizeIdentifier(refName);
2846
2753
 
2847
2754
  // Check if this reference creates a circular dependency
2848
2755
  if (this.isCircularReference(refName)) {
2849
2756
  // Generate: z.lazy(() => RefSchema)
2850
- return ts.factory.createCallExpression(
2851
- ts.factory.createPropertyAccessExpression(
2852
- ts.factory.createIdentifier('z'),
2853
- ts.factory.createIdentifier('lazy'),
2854
- ),
2855
- undefined,
2856
- [
2857
- ts.factory.createArrowFunction(
2858
- undefined,
2859
- undefined,
2860
- [],
2861
- undefined,
2862
- ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2863
- ts.factory.createIdentifier(sanitizedRefName),
2864
- ),
2865
- ],
2866
- );
2757
+ return ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('lazy')), undefined, [
2758
+ ts.factory.createArrowFunction(
2759
+ undefined,
2760
+ undefined,
2761
+ [],
2762
+ undefined,
2763
+ ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
2764
+ ts.factory.createIdentifier(sanitizedRefName)
2765
+ )
2766
+ ]);
2867
2767
  }
2868
2768
 
2869
2769
  return ts.factory.createIdentifier(sanitizedRefName);
@@ -2883,11 +2783,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2883
2783
 
2884
2784
  // Case 2: Reference to a schema that's part of a circular dependency chain
2885
2785
  // and we're currently building a schema that's also in that chain
2886
- if (
2887
- this.circularSchemas.has(refName) &&
2888
- this.currentSchemaName !== null &&
2889
- this.circularSchemas.has(this.currentSchemaName)
2890
- ) {
2786
+ if (this.circularSchemas.has(refName) && this.currentSchemaName !== null && this.circularSchemas.has(this.currentSchemaName)) {
2891
2787
  return true;
2892
2788
  }
2893
2789
 
@@ -2905,11 +2801,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2905
2801
  // Build dependency graph
2906
2802
  const graph = new Map<string, string[]>();
2907
2803
  for (const [name, schema] of Object.entries(schemas)) {
2908
- const dependencies = jp
2909
- .query(schema, '$..["$ref"]')
2910
- .filter((ref: string) => ref.startsWith('#/components/schemas/'))
2911
- .map((ref: string) => ref.replace('#/components/schemas/', ''))
2912
- .filter((dep: string) => dep in schemas);
2804
+ const dependencies = this.extractSchemaReferences(schema).filter((dep: string) => dep in schemas);
2913
2805
  graph.set(name, dependencies);
2914
2806
  }
2915
2807
 
@@ -2989,16 +2881,14 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
2989
2881
  if (visiting.has(name)) {
2990
2882
  return;
2991
2883
  }
2884
+
2992
2885
  if (visited.has(name)) {
2993
2886
  return;
2994
2887
  }
2995
2888
 
2996
2889
  visiting.add(name);
2997
2890
  const schema = schemas[name];
2998
- const dependencies = jp
2999
- .query(schema, '$..["$ref"]')
3000
- .filter((ref: string) => ref.startsWith('#/components/schemas/'))
3001
- .map((ref: string) => ref.replace('#/components/schemas/', ''));
2891
+ const dependencies = this.extractSchemaReferences(schema);
3002
2892
 
3003
2893
  for (const dep of dependencies) {
3004
2894
  if (schemas[dep]) {