zod-codegen 1.6.1 → 1.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +1 -1
- package/CHANGELOG.md +9 -0
- package/dist/src/services/code-generator.service.d.ts +21 -0
- package/dist/src/services/code-generator.service.d.ts.map +1 -1
- package/dist/src/services/code-generator.service.js +173 -23
- package/examples/petstore/type.ts +10 -8
- package/generated/type.ts +68 -20
- package/package.json +11 -13
- package/src/services/code-generator.service.ts +364 -125
- package/tests/unit/code-generator.test.ts +305 -0
package/.github/workflows/ci.yml
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## <small>1.6.3 (2026-01-22)</small>
|
|
2
|
+
|
|
3
|
+
- fix: do not depend on inference anymore and build strict types all ar… (#60) ([b0b663e](https://github.com/julienandreu/zod-codegen/commit/b0b663e)), closes [#60](https://github.com/julienandreu/zod-codegen/issues/60)
|
|
4
|
+
|
|
5
|
+
## <small>1.6.2 (2026-01-19)</small>
|
|
6
|
+
|
|
7
|
+
- fix: improve URL construction and filter undefined query params (#58) ([b9c3d32](https://github.com/julienandreu/zod-codegen/commit/b9c3d32)), closes [#58](https://github.com/julienandreu/zod-codegen/issues/58)
|
|
8
|
+
- chore(deps): bump the dev-dependencies group across 1 directory with 5 updates (#57) ([30110fd](https://github.com/julienandreu/zod-codegen/commit/30110fd)), closes [#57](https://github.com/julienandreu/zod-codegen/issues/57)
|
|
9
|
+
|
|
1
10
|
## <small>1.6.1 (2026-01-09)</small>
|
|
2
11
|
|
|
3
12
|
- Merge pull request #55 from julienandreu/fix/integration-tests-timeout ([1e48796](https://github.com/julienandreu/zod-codegen/commit/1e48796)), closes [#55](https://github.com/julienandreu/zod-codegen/issues/55)
|
|
@@ -17,6 +17,27 @@ export declare class TypeScriptCodeGeneratorService implements CodeGenerator, Sc
|
|
|
17
17
|
private buildAST;
|
|
18
18
|
private buildSchemas;
|
|
19
19
|
private buildSchemaTypeAliases;
|
|
20
|
+
/**
|
|
21
|
+
* Builds explicit TypeScript type declarations for all schemas.
|
|
22
|
+
* Returns interface declarations for object types and type aliases for other types.
|
|
23
|
+
*/
|
|
24
|
+
private buildExplicitTypeDeclarations;
|
|
25
|
+
/**
|
|
26
|
+
* Converts an OpenAPI schema to a TypeScript type node.
|
|
27
|
+
*/
|
|
28
|
+
private buildTypeNode;
|
|
29
|
+
/**
|
|
30
|
+
* Builds the base type node without nullable handling.
|
|
31
|
+
*/
|
|
32
|
+
private buildBaseTypeNode;
|
|
33
|
+
/**
|
|
34
|
+
* Builds a TypeScript type literal for an object schema.
|
|
35
|
+
*/
|
|
36
|
+
private buildObjectTypeLiteral;
|
|
37
|
+
/**
|
|
38
|
+
* Builds a TypeScript interface declaration for an object schema.
|
|
39
|
+
*/
|
|
40
|
+
private buildInterfaceDeclaration;
|
|
20
41
|
private buildClientClass;
|
|
21
42
|
private buildConstructor;
|
|
22
43
|
private buildGetBaseRequestOptionsMethod;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-generator.service.d.ts","sourceRoot":"","sources":["../../../src/services/code-generator.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,KAAK,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,8BAA8B,CAAC;AAC/E,OAAO,KAAK,EAAmB,eAAe,EAAgB,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AAWjE,qBAAa,8BAA+B,YAAW,aAAa,EAAE,aAAa;IACjF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwC;IACtE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwD;IAChF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA+B;IAChE,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAuC;IAGhF,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,iBAAiB,CAAuB;gBAEpC,OAAO,GAAE,gBAAqB;IAK1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGpB;IAEH,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM;IAMvC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,UAAO,GAAG,EAAE,CAAC,cAAc,GAAG,EAAE,CAAC,UAAU;IA2BhF,OAAO,CAAC,QAAQ;
|
|
1
|
+
{"version":3,"file":"code-generator.service.d.ts","sourceRoot":"","sources":["../../../src/services/code-generator.service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,YAAY,CAAC;AAEjC,OAAO,KAAK,EAAC,aAAa,EAAE,aAAa,EAAC,MAAM,8BAA8B,CAAC;AAC/E,OAAO,KAAK,EAAmB,eAAe,EAAgB,MAAM,kBAAkB,CAAC;AACvF,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,4BAA4B,CAAC;AAWjE,qBAAa,8BAA+B,YAAW,aAAa,EAAE,aAAa;IACjF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAwC;IACtE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwD;IAChF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA+B;IAChE,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAuC;IAGhF,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,iBAAiB,CAAuB;gBAEpC,OAAO,GAAE,gBAAqB;IAK1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAGpB;IAEH,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM;IAMvC,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,UAAO,GAAG,EAAE,CAAC,cAAc,GAAG,EAAE,CAAC,UAAU;IA2BhF,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,YAAY;IAmDpB,OAAO,CAAC,sBAAsB;IAK9B;;;OAGG;IACH,OAAO,CAAC,6BAA6B;IAkDrC;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IA2EzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAgB9B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAyBjC,OAAO,CAAC,gBAAgB;IAuBxB,OAAO,CAAC,gBAAgB;IAmGxB,OAAO,CAAC,gCAAgC;IAwBxC,OAAO,CAAC,yBAAyB;IAuBjC,OAAO,CAAC,sBAAsB;IA8pB9B,OAAO,CAAC,kBAAkB;IAgE1B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAoC9B,OAAO,CAAC,mBAAmB;IAgH3B,OAAO,CAAC,mBAAmB;IA6D3B,OAAO,CAAC,qBAAqB;IAwF7B,OAAO,CAAC,gBAAgB;IA0CxB,OAAO,CAAC,iBAAiB;IAmCzB,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,eAAe;IAuDvB,OAAO,CAAC,wBAAwB;IA4IhC,OAAO,CAAC,gBAAgB;IAqBxB,OAAO,CAAC,6BAA6B;IAkPrC,OAAO,CAAC,kBAAkB;IAO1B,OAAO,CAAC,aAAa;IAMrB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuFzB,OAAO,CAAC,WAAW;IA0CnB,OAAO,CAAC,aAAa;IAmjBrB,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,qBAAqB;IAe7B,OAAO,CAAC,oBAAoB;IAyE5B,OAAO,CAAC,8BAA8B;IActC,OAAO,CAAC,wBAAwB;IAyBhC,OAAO,CAAC,yBAAyB;IA8BjC,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,kBAAkB;IA8B1B;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAmB3B;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAiFlC,OAAO,CAAC,eAAe;CAuCxB"}
|
|
@@ -53,9 +53,12 @@ export class TypeScriptCodeGeneratorService {
|
|
|
53
53
|
const schemaTypeAliases = this.buildSchemaTypeAliases(schemas);
|
|
54
54
|
const serverConfig = this.buildServerConfiguration(openapi);
|
|
55
55
|
const clientClass = this.buildClientClass(openapi, schemas);
|
|
56
|
+
const explicitTypeDeclarations = this.buildExplicitTypeDeclarations(openapi);
|
|
56
57
|
return [
|
|
57
58
|
this.createComment('Imports'),
|
|
58
59
|
...imports,
|
|
60
|
+
this.createComment('Explicit type declarations'),
|
|
61
|
+
...explicitTypeDeclarations,
|
|
59
62
|
this.createComment('Components schemas'),
|
|
60
63
|
...Object.values(schemas),
|
|
61
64
|
...schemaTypeAliases,
|
|
@@ -79,8 +82,11 @@ export class TypeScriptCodeGeneratorService {
|
|
|
79
82
|
const schemaExpression = this.buildSchema(schema);
|
|
80
83
|
// Clear context
|
|
81
84
|
this.currentSchemaName = null;
|
|
85
|
+
const sanitizedName = this.typeBuilder.sanitizeIdentifier(name);
|
|
86
|
+
// Add type annotation: z.ZodType<Name>
|
|
87
|
+
const typeAnnotation = ts.factory.createTypeReferenceNode(ts.factory.createQualifiedName(ts.factory.createIdentifier('z'), ts.factory.createIdentifier('ZodType')), [ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedName), undefined)]);
|
|
82
88
|
const variableStatement = ts.factory.createVariableStatement([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createVariableDeclarationList([
|
|
83
|
-
ts.factory.createVariableDeclaration(ts.factory.createIdentifier(
|
|
89
|
+
ts.factory.createVariableDeclaration(ts.factory.createIdentifier(sanitizedName), undefined, typeAnnotation, schemaExpression),
|
|
84
90
|
], ts.NodeFlags.Const));
|
|
85
91
|
return {
|
|
86
92
|
...schemaRegistered,
|
|
@@ -88,11 +94,157 @@ export class TypeScriptCodeGeneratorService {
|
|
|
88
94
|
};
|
|
89
95
|
}, {});
|
|
90
96
|
}
|
|
91
|
-
buildSchemaTypeAliases(
|
|
92
|
-
|
|
97
|
+
buildSchemaTypeAliases(_schemas) {
|
|
98
|
+
// Explicit type declarations are used instead of z.infer type exports
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Builds explicit TypeScript type declarations for all schemas.
|
|
103
|
+
* Returns interface declarations for object types and type aliases for other types.
|
|
104
|
+
*/
|
|
105
|
+
buildExplicitTypeDeclarations(openapi) {
|
|
106
|
+
const schemasEntries = Object.entries(openapi.components?.schemas ?? {});
|
|
107
|
+
const schemasMap = Object.fromEntries(schemasEntries);
|
|
108
|
+
const sortedSchemaNames = this.topologicalSort(schemasMap);
|
|
109
|
+
const statements = [];
|
|
110
|
+
for (const name of sortedSchemaNames) {
|
|
111
|
+
const schema = openapi.components?.schemas?.[name];
|
|
112
|
+
if (!schema)
|
|
113
|
+
continue;
|
|
93
114
|
const sanitizedName = this.typeBuilder.sanitizeIdentifier(name);
|
|
94
|
-
|
|
115
|
+
const safeSchema = SchemaProperties.safeParse(schema);
|
|
116
|
+
if (!safeSchema.success) {
|
|
117
|
+
// Unknown schema type, create a type alias to unknown
|
|
118
|
+
statements.push(ts.factory.createTypeAliasDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(sanitizedName), undefined, ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword)));
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const schemaData = safeSchema.data;
|
|
122
|
+
const typeNode = this.buildTypeNode(schemaData);
|
|
123
|
+
// For object types with properties, create an interface
|
|
124
|
+
if (schemaData['type'] === 'object' && schemaData['properties']) {
|
|
125
|
+
statements.push(this.buildInterfaceDeclaration(sanitizedName, schemaData));
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
// For all other types (enums, arrays, unions, etc.), create a type alias
|
|
129
|
+
statements.push(ts.factory.createTypeAliasDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(sanitizedName), undefined, typeNode));
|
|
130
|
+
}
|
|
131
|
+
return statements;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Converts an OpenAPI schema to a TypeScript type node.
|
|
135
|
+
*/
|
|
136
|
+
buildTypeNode(schema) {
|
|
137
|
+
const safeSchema = SchemaProperties.safeParse(schema);
|
|
138
|
+
if (!safeSchema.success) {
|
|
139
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
|
|
140
|
+
}
|
|
141
|
+
const prop = safeSchema.data;
|
|
142
|
+
// Handle $ref
|
|
143
|
+
if (this.isReference(prop)) {
|
|
144
|
+
const { $ref = '' } = Reference.parse(prop);
|
|
145
|
+
const refName = $ref.split('/').pop() ?? 'never';
|
|
146
|
+
const sanitizedRefName = this.typeBuilder.sanitizeIdentifier(refName);
|
|
147
|
+
return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier(sanitizedRefName), undefined);
|
|
148
|
+
}
|
|
149
|
+
// Handle nullable
|
|
150
|
+
const isNullable = prop['nullable'] === true;
|
|
151
|
+
const baseTypeNode = this.buildBaseTypeNode(prop);
|
|
152
|
+
if (isNullable) {
|
|
153
|
+
return ts.factory.createUnionTypeNode([baseTypeNode, ts.factory.createLiteralTypeNode(ts.factory.createNull())]);
|
|
154
|
+
}
|
|
155
|
+
return baseTypeNode;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Builds the base type node without nullable handling.
|
|
159
|
+
*/
|
|
160
|
+
buildBaseTypeNode(prop) {
|
|
161
|
+
// Handle anyOf/oneOf (union types)
|
|
162
|
+
if (prop['anyOf'] && Array.isArray(prop['anyOf']) && prop['anyOf'].length > 0) {
|
|
163
|
+
const types = prop['anyOf'].map((s) => this.buildTypeNode(s));
|
|
164
|
+
return ts.factory.createUnionTypeNode(types);
|
|
165
|
+
}
|
|
166
|
+
if (prop['oneOf'] && Array.isArray(prop['oneOf']) && prop['oneOf'].length > 0) {
|
|
167
|
+
const types = prop['oneOf'].map((s) => this.buildTypeNode(s));
|
|
168
|
+
return ts.factory.createUnionTypeNode(types);
|
|
169
|
+
}
|
|
170
|
+
// Handle allOf (intersection types)
|
|
171
|
+
if (prop['allOf'] && Array.isArray(prop['allOf']) && prop['allOf'].length > 0) {
|
|
172
|
+
const types = prop['allOf'].map((s) => this.buildTypeNode(s));
|
|
173
|
+
return ts.factory.createIntersectionTypeNode(types);
|
|
174
|
+
}
|
|
175
|
+
// Handle enum
|
|
176
|
+
if (prop['enum'] && Array.isArray(prop['enum']) && prop['enum'].length > 0) {
|
|
177
|
+
const literalTypes = prop['enum'].map((val) => {
|
|
178
|
+
if (typeof val === 'string') {
|
|
179
|
+
return ts.factory.createLiteralTypeNode(ts.factory.createStringLiteral(val, true));
|
|
180
|
+
}
|
|
181
|
+
else if (typeof val === 'number') {
|
|
182
|
+
if (val < 0) {
|
|
183
|
+
return ts.factory.createLiteralTypeNode(ts.factory.createPrefixUnaryExpression(ts.SyntaxKind.MinusToken, ts.factory.createNumericLiteral(String(Math.abs(val)))));
|
|
184
|
+
}
|
|
185
|
+
return ts.factory.createLiteralTypeNode(ts.factory.createNumericLiteral(String(val)));
|
|
186
|
+
}
|
|
187
|
+
else if (typeof val === 'boolean') {
|
|
188
|
+
return ts.factory.createLiteralTypeNode(val ? ts.factory.createTrue() : ts.factory.createFalse());
|
|
189
|
+
}
|
|
190
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
|
|
191
|
+
});
|
|
192
|
+
return ts.factory.createUnionTypeNode(literalTypes);
|
|
193
|
+
}
|
|
194
|
+
// Handle type-specific schemas
|
|
195
|
+
switch (prop['type']) {
|
|
196
|
+
case 'string':
|
|
197
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword);
|
|
198
|
+
case 'number':
|
|
199
|
+
case 'integer':
|
|
200
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword);
|
|
201
|
+
case 'boolean':
|
|
202
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
|
|
203
|
+
case 'array': {
|
|
204
|
+
const itemsType = prop['items']
|
|
205
|
+
? this.buildTypeNode(prop['items'])
|
|
206
|
+
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
|
|
207
|
+
return ts.factory.createArrayTypeNode(itemsType);
|
|
208
|
+
}
|
|
209
|
+
case 'object': {
|
|
210
|
+
const properties = (prop['properties'] ?? {});
|
|
211
|
+
const requiredProps = (prop['required'] ?? []);
|
|
212
|
+
if (Object.keys(properties).length > 0) {
|
|
213
|
+
return this.buildObjectTypeLiteral(properties, requiredProps);
|
|
214
|
+
}
|
|
215
|
+
// Empty object or additionalProperties - use Record<string, unknown>
|
|
216
|
+
return ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Record'), [
|
|
217
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.StringKeyword),
|
|
218
|
+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword),
|
|
219
|
+
]);
|
|
220
|
+
}
|
|
221
|
+
default:
|
|
222
|
+
return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Builds a TypeScript type literal for an object schema.
|
|
227
|
+
*/
|
|
228
|
+
buildObjectTypeLiteral(properties, requiredProps) {
|
|
229
|
+
const members = Object.entries(properties).map(([name, propSchema]) => {
|
|
230
|
+
const isRequired = requiredProps.includes(name);
|
|
231
|
+
const typeNode = this.buildTypeNode(propSchema);
|
|
232
|
+
return ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier(name), isRequired ? undefined : ts.factory.createToken(ts.SyntaxKind.QuestionToken), typeNode);
|
|
233
|
+
});
|
|
234
|
+
return ts.factory.createTypeLiteralNode(members);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Builds a TypeScript interface declaration for an object schema.
|
|
238
|
+
*/
|
|
239
|
+
buildInterfaceDeclaration(name, schema) {
|
|
240
|
+
const properties = (schema['properties'] ?? {});
|
|
241
|
+
const requiredProps = (schema['required'] ?? []);
|
|
242
|
+
const members = Object.entries(properties).map(([propName, propSchema]) => {
|
|
243
|
+
const isRequired = requiredProps.includes(propName);
|
|
244
|
+
const typeNode = this.buildTypeNode(propSchema);
|
|
245
|
+
return ts.factory.createPropertySignature(undefined, ts.factory.createIdentifier(propName), isRequired ? undefined : ts.factory.createToken(ts.SyntaxKind.QuestionToken), typeNode);
|
|
95
246
|
});
|
|
247
|
+
return ts.factory.createInterfaceDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(name), undefined, undefined, members);
|
|
96
248
|
}
|
|
97
249
|
buildClientClass(openapi, schemas) {
|
|
98
250
|
const clientName = this.generateClientName(openapi.info.title);
|
|
@@ -161,22 +313,26 @@ export class TypeScriptCodeGeneratorService {
|
|
|
161
313
|
], ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('Promise'), [
|
|
162
314
|
ts.factory.createTypeReferenceNode(ts.factory.createIdentifier('T'), undefined),
|
|
163
315
|
]), ts.factory.createBlock([
|
|
164
|
-
//
|
|
316
|
+
// Create initial URL object that we will use to build the final URL
|
|
165
317
|
ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList([
|
|
166
|
-
ts.factory.createVariableDeclaration(ts.factory.createIdentifier('baseUrl'), undefined, undefined, ts.factory.
|
|
167
|
-
ts.factory.
|
|
168
|
-
ts.factory.
|
|
318
|
+
ts.factory.createVariableDeclaration(ts.factory.createIdentifier('baseUrl'), undefined, undefined, ts.factory.createNewExpression(ts.factory.createIdentifier('URL'), undefined, [
|
|
319
|
+
ts.factory.createIdentifier('path'),
|
|
320
|
+
ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createPrivateIdentifier('#baseUrl')),
|
|
169
321
|
])),
|
|
170
322
|
], ts.NodeFlags.Const)),
|
|
171
323
|
ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList([
|
|
172
324
|
ts.factory.createVariableDeclaration(ts.factory.createIdentifier('url'), undefined, undefined, ts.factory.createConditionalExpression(ts.factory.createBinaryExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('params')), ts.factory.createToken(ts.SyntaxKind.AmpersandAmpersandToken), ts.factory.createBinaryExpression(ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('keys')), undefined, [
|
|
173
325
|
ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('params')),
|
|
174
|
-
]), ts.factory.createIdentifier('length')), ts.factory.createToken(ts.SyntaxKind.GreaterThanToken), ts.factory.createNumericLiteral('0'))), undefined, (()
|
|
175
|
-
|
|
176
|
-
ts.factory.createIdentifier('baseUrl'),
|
|
177
|
-
]);
|
|
178
|
-
const forEachCall = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('entries')), undefined, [
|
|
326
|
+
]), ts.factory.createIdentifier('length')), ts.factory.createToken(ts.SyntaxKind.GreaterThanToken), ts.factory.createNumericLiteral('0'))), undefined, ts.factory.createCallExpression(ts.factory.createParenthesizedExpression(ts.factory.createArrowFunction(undefined, undefined, [], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBlock([
|
|
327
|
+
ts.factory.createExpressionStatement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('Object'), ts.factory.createIdentifier('entries')), undefined, [
|
|
179
328
|
ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('options'), ts.factory.createIdentifier('params')),
|
|
329
|
+
]), ts.factory.createIdentifier('filter')), undefined, [
|
|
330
|
+
ts.factory.createArrowFunction(undefined, undefined, [
|
|
331
|
+
ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createArrayBindingPattern([
|
|
332
|
+
ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier(''), undefined),
|
|
333
|
+
ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier('value'), undefined),
|
|
334
|
+
]), undefined, undefined),
|
|
335
|
+
], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBinaryExpression(ts.factory.createIdentifier('value'), ts.SyntaxKind.ExclamationEqualsEqualsToken, ts.factory.createIdentifier('undefined'))),
|
|
180
336
|
]), ts.factory.createIdentifier('forEach')), undefined, [
|
|
181
337
|
ts.factory.createArrowFunction(undefined, undefined, [
|
|
182
338
|
ts.factory.createParameterDeclaration(undefined, undefined, ts.factory.createArrayBindingPattern([
|
|
@@ -184,20 +340,14 @@ export class TypeScriptCodeGeneratorService {
|
|
|
184
340
|
ts.factory.createBindingElement(undefined, undefined, ts.factory.createIdentifier('value'), undefined),
|
|
185
341
|
]), undefined, undefined),
|
|
186
342
|
], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), ts.factory.createBlock([
|
|
187
|
-
ts.factory.createExpressionStatement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(
|
|
343
|
+
ts.factory.createExpressionStatement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('baseUrl'), ts.factory.createIdentifier('searchParams')), ts.factory.createIdentifier('set')), undefined, [
|
|
188
344
|
ts.factory.createIdentifier('key'),
|
|
189
345
|
ts.factory.createCallExpression(ts.factory.createIdentifier('String'), undefined, [ts.factory.createIdentifier('value')]),
|
|
190
346
|
])),
|
|
191
347
|
], false)),
|
|
192
|
-
])
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
ts.factory.createExpressionStatement(forEachCall),
|
|
196
|
-
ts.factory.createReturnStatement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(urlObj, ts.factory.createIdentifier('toString')), undefined, [])),
|
|
197
|
-
], false))), undefined, []);
|
|
198
|
-
})(), undefined, ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createNewExpression(ts.factory.createIdentifier('URL'), undefined, [
|
|
199
|
-
ts.factory.createIdentifier('baseUrl'),
|
|
200
|
-
]), ts.factory.createIdentifier('toString')), undefined, []))),
|
|
348
|
+
])),
|
|
349
|
+
ts.factory.createReturnStatement(ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('baseUrl'), ts.factory.createIdentifier('toString')), undefined, [])),
|
|
350
|
+
], true))), undefined, []), undefined, ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('baseUrl'), ts.factory.createIdentifier('toString')), undefined, []))),
|
|
201
351
|
], ts.NodeFlags.Const)),
|
|
202
352
|
// Get base request options (headers, signal, credentials, etc.)
|
|
203
353
|
ts.factory.createVariableStatement(undefined, ts.factory.createVariableDeclarationList([
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
2
|
-
// Built with zod-codegen@1.
|
|
3
|
-
// Latest edit:
|
|
2
|
+
// Built with zod-codegen@1.6.1
|
|
3
|
+
// Latest edit: Mon, 19 Jan 2026 14:27:35 GMT
|
|
4
4
|
// Source file: ./samples/swagger-petstore.yaml
|
|
5
5
|
/* eslint-disable */
|
|
6
6
|
// @ts-nocheck
|
|
@@ -126,16 +126,18 @@ export default class SwaggerPetstoreOpenAPI30 {
|
|
|
126
126
|
path: string,
|
|
127
127
|
options: _params___Record_string__string___number___boolean___data___unknown__contentType___string__headers___Record_string__string__ = {},
|
|
128
128
|
): Promise<T> {
|
|
129
|
-
const baseUrl =
|
|
129
|
+
const baseUrl = new URL(path, this.#baseUrl);
|
|
130
130
|
const url =
|
|
131
131
|
options.params && Object.keys(options.params).length > 0
|
|
132
132
|
? (() => {
|
|
133
|
-
Object.entries(options.params)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
Object.entries(options.params)
|
|
134
|
+
.filter(([, value]) => value !== undefined)
|
|
135
|
+
.forEach(([key, value]) => {
|
|
136
|
+
baseUrl.searchParams.set(key, String(value));
|
|
137
|
+
});
|
|
138
|
+
return baseUrl.toString();
|
|
137
139
|
})()
|
|
138
|
-
:
|
|
140
|
+
: baseUrl.toString();
|
|
139
141
|
const baseOptions = this.getBaseRequestOptions();
|
|
140
142
|
const contentType =
|
|
141
143
|
options.contentType === 'application/x-www-form-urlencoded'
|
package/generated/type.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
|
2
|
-
// Built with zod-codegen@1.6.
|
|
3
|
-
// Latest edit:
|
|
2
|
+
// Built with zod-codegen@1.6.3
|
|
3
|
+
// Latest edit: Thu, 22 Jan 2026 16:08:32 GMT
|
|
4
4
|
// Source file: ./samples/swagger-petstore.yaml
|
|
5
5
|
/* eslint-disable */
|
|
6
6
|
// @ts-nocheck
|
|
@@ -10,9 +10,62 @@
|
|
|
10
10
|
;
|
|
11
11
|
import { z } from 'zod';
|
|
12
12
|
|
|
13
|
+
// Explicit type declarations
|
|
14
|
+
;
|
|
15
|
+
export interface Order {
|
|
16
|
+
id?: number;
|
|
17
|
+
petId?: number;
|
|
18
|
+
quantity?: number;
|
|
19
|
+
shipDate?: string;
|
|
20
|
+
status?: 'placed' | 'approved' | 'delivered';
|
|
21
|
+
complete?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface Address {
|
|
24
|
+
street?: string;
|
|
25
|
+
city?: string;
|
|
26
|
+
state?: string;
|
|
27
|
+
zip?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface Customer {
|
|
30
|
+
id?: number;
|
|
31
|
+
username?: string;
|
|
32
|
+
address?: Address[];
|
|
33
|
+
}
|
|
34
|
+
export interface Category {
|
|
35
|
+
id?: number;
|
|
36
|
+
name?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface User {
|
|
39
|
+
id?: number;
|
|
40
|
+
username?: string;
|
|
41
|
+
firstName?: string;
|
|
42
|
+
lastName?: string;
|
|
43
|
+
email?: string;
|
|
44
|
+
password?: string;
|
|
45
|
+
phone?: string;
|
|
46
|
+
userStatus?: number;
|
|
47
|
+
}
|
|
48
|
+
export interface Tag {
|
|
49
|
+
id?: number;
|
|
50
|
+
name?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface Pet {
|
|
53
|
+
id?: number;
|
|
54
|
+
name: string;
|
|
55
|
+
category?: Category;
|
|
56
|
+
photoUrls: string[];
|
|
57
|
+
tags?: Tag[];
|
|
58
|
+
status?: 'available' | 'pending' | 'sold';
|
|
59
|
+
}
|
|
60
|
+
export interface ApiResponse {
|
|
61
|
+
code?: number;
|
|
62
|
+
type?: string;
|
|
63
|
+
message?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
13
66
|
// Components schemas
|
|
14
67
|
;
|
|
15
|
-
export const Order = z.object({
|
|
68
|
+
export const Order: z.ZodType<Order> = z.object({
|
|
16
69
|
id: z.number().int().optional(),
|
|
17
70
|
petId: z.number().int().optional(),
|
|
18
71
|
quantity: z.number().int().optional(),
|
|
@@ -22,22 +75,22 @@ export const Order = z.object({
|
|
|
22
75
|
status: z.enum(['placed', 'approved', 'delivered']).optional(),
|
|
23
76
|
complete: z.boolean().optional()
|
|
24
77
|
});
|
|
25
|
-
export const Address = z.object({
|
|
78
|
+
export const Address: z.ZodType<Address> = z.object({
|
|
26
79
|
street: z.string().optional(),
|
|
27
80
|
city: z.string().optional(),
|
|
28
81
|
state: z.string().optional(),
|
|
29
82
|
zip: z.string().optional()
|
|
30
83
|
});
|
|
31
|
-
export const Customer = z.object({
|
|
84
|
+
export const Customer: z.ZodType<Customer> = z.object({
|
|
32
85
|
id: z.number().int().optional(),
|
|
33
86
|
username: z.string().optional(),
|
|
34
87
|
address: z.array(Address).optional()
|
|
35
88
|
});
|
|
36
|
-
export const Category = z.object({
|
|
89
|
+
export const Category: z.ZodType<Category> = z.object({
|
|
37
90
|
id: z.number().int().optional(),
|
|
38
91
|
name: z.string().optional()
|
|
39
92
|
});
|
|
40
|
-
export const User = z.object({
|
|
93
|
+
export const User: z.ZodType<User> = z.object({
|
|
41
94
|
id: z.number().int().optional(),
|
|
42
95
|
username: z.string().optional(),
|
|
43
96
|
firstName: z.string().optional(),
|
|
@@ -47,11 +100,11 @@ export const User = z.object({
|
|
|
47
100
|
phone: z.string().optional(),
|
|
48
101
|
userStatus: z.number().int().optional()
|
|
49
102
|
});
|
|
50
|
-
export const Tag = z.object({
|
|
103
|
+
export const Tag: z.ZodType<Tag> = z.object({
|
|
51
104
|
id: z.number().int().optional(),
|
|
52
105
|
name: z.string().optional()
|
|
53
106
|
});
|
|
54
|
-
export const Pet = z.object({
|
|
107
|
+
export const Pet: z.ZodType<Pet> = z.object({
|
|
55
108
|
id: z.number().int().optional(),
|
|
56
109
|
name: z.string(),
|
|
57
110
|
category: Category.optional(),
|
|
@@ -59,19 +112,11 @@ export const Pet = z.object({
|
|
|
59
112
|
tags: z.array(Tag).optional(),
|
|
60
113
|
status: z.enum(['available', 'pending', 'sold']).optional()
|
|
61
114
|
});
|
|
62
|
-
export const ApiResponse = z.object({
|
|
115
|
+
export const ApiResponse: z.ZodType<ApiResponse> = z.object({
|
|
63
116
|
code: z.number().int().optional(),
|
|
64
117
|
type: z.string().optional(),
|
|
65
118
|
message: z.string().optional()
|
|
66
119
|
});
|
|
67
|
-
export type Order = z.infer<typeof Order>;
|
|
68
|
-
export type Address = z.infer<typeof Address>;
|
|
69
|
-
export type Customer = z.infer<typeof Customer>;
|
|
70
|
-
export type Category = z.infer<typeof Category>;
|
|
71
|
-
export type User = z.infer<typeof User>;
|
|
72
|
-
export type Tag = z.infer<typeof Tag>;
|
|
73
|
-
export type Pet = z.infer<typeof Pet>;
|
|
74
|
-
export type ApiResponse = z.infer<typeof ApiResponse>;
|
|
75
120
|
export const serverConfigurations = [{
|
|
76
121
|
url: 'https://petstore3.swagger.io/api/v3'
|
|
77
122
|
}];
|
|
@@ -114,8 +159,11 @@ export default class SwaggerPetstoreOpenAPI30 {
|
|
|
114
159
|
return response;
|
|
115
160
|
}
|
|
116
161
|
protected async makeRequest<T>(method: string, path: string, options: _params___Record_string__string___number___boolean___data___unknown__contentType___string__headers___Record_string__string__ = {}): Promise<T> {
|
|
117
|
-
const baseUrl =
|
|
118
|
-
const url = options.params && Object.keys(options.params).length > 0 ? (() => {
|
|
162
|
+
const baseUrl = new URL(path, this.#baseUrl);
|
|
163
|
+
const url = options.params && Object.keys(options.params).length > 0 ? (() => {
|
|
164
|
+
Object.entries(options.params).filter(([, value]) => value !== undefined).forEach(([key, value]) => { baseUrl.searchParams.set(key, String(value)); });
|
|
165
|
+
return baseUrl.toString();
|
|
166
|
+
})() : baseUrl.toString();
|
|
119
167
|
const baseOptions = this.getBaseRequestOptions();
|
|
120
168
|
const contentType = options.contentType === 'application/x-www-form-urlencoded' ? 'application/x-www-form-urlencoded' : 'application/json';
|
|
121
169
|
const baseHeaders = baseOptions.headers !== undefined ? baseOptions.headers : {};
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"openapi-types": "^12.1.3",
|
|
14
14
|
"openapi-typescript": "^7.10.1",
|
|
15
15
|
"path-to-regexp": "^8.3.0",
|
|
16
|
-
"prettier": "^3.
|
|
16
|
+
"prettier": "^3.8.0",
|
|
17
17
|
"typescript": "^5.9.3",
|
|
18
18
|
"url-pattern": "^1.0.3",
|
|
19
19
|
"yargs": "^18.0.0",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"@types/jest": "^30.0.0",
|
|
42
42
|
"@types/js-yaml": "^4.0.9",
|
|
43
43
|
"@types/jsonpath": "^0.2.4",
|
|
44
|
-
"@types/node": "^25.0.
|
|
44
|
+
"@types/node": "^25.0.9",
|
|
45
45
|
"@types/yargs": "^17.0.35",
|
|
46
|
-
"@vitest/coverage-v8": "^4.0.
|
|
46
|
+
"@vitest/coverage-v8": "^4.0.17",
|
|
47
47
|
"cross-env": "^10.1.0",
|
|
48
48
|
"eslint": "^9.39.2",
|
|
49
49
|
"eslint-config-prettier": "^10.1.8",
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
"lint-staged": "^16.2.7",
|
|
52
52
|
"semantic-release": "^25.0.2",
|
|
53
53
|
"ts-node": "^10.9.2",
|
|
54
|
-
"typescript-eslint": "^8.
|
|
55
|
-
"undici": "^7.
|
|
54
|
+
"typescript-eslint": "^8.53.0",
|
|
55
|
+
"undici": "^7.18.2",
|
|
56
56
|
"vitest": "^4.0.14"
|
|
57
57
|
},
|
|
58
58
|
"homepage": "https://github.com/julienandreu/zod-codegen",
|
|
@@ -75,13 +75,11 @@
|
|
|
75
75
|
"node": ">=18.0.0"
|
|
76
76
|
},
|
|
77
77
|
"overrides": {
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
"tar": "^7.5.2",
|
|
84
|
-
"yargs": "^18.0.0"
|
|
78
|
+
"tar": "^7.5.3",
|
|
79
|
+
"diff": "^8.0.3",
|
|
80
|
+
"@actions/http-client": {
|
|
81
|
+
"undici": "^7.18.0"
|
|
82
|
+
}
|
|
85
83
|
},
|
|
86
84
|
"scripts": {
|
|
87
85
|
"audit:fix": "npm audit fix",
|
|
@@ -107,5 +105,5 @@
|
|
|
107
105
|
"release": "semantic-release",
|
|
108
106
|
"release:dry": "semantic-release --dry-run"
|
|
109
107
|
},
|
|
110
|
-
"version": "1.6.
|
|
108
|
+
"version": "1.6.3"
|
|
111
109
|
}
|