@rexeus/typeweaver-zod-to-ts 0.0.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/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # @rexeus/typeweaver-zod-to-ts
2
+
3
+ Generates TypeScript types from Zod schemas.
4
+
5
+ ## Overview
6
+
7
+ This package provides utilities to transform Zod schemas into TypeScript type representations. It's
8
+ used internally by TypeWeaver framework.
9
+
10
+ ## Features
11
+
12
+ - Converts Zod schemas to TypeScript AST nodes
13
+ - Prints TypeScript type definitions from Zod schemas
14
+ - Supports all common Zod types (string, number, boolean, object, array, union, etc.)
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @rexeus/typeweaver-zod-to-ts
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ```typescript
25
+ import { TsTypeNode, TsTypePrinter } from "@rexeus/typeweaver-zod-to-ts";
26
+ import { z } from "zod/v4";
27
+
28
+ // Define a Zod schema
29
+ const userSchema = z.object({
30
+ id: z.string(),
31
+ name: z.string(),
32
+ email: z.string().email(),
33
+ age: z.number().optional(),
34
+ });
35
+
36
+ // Convert to TypeScript AST node
37
+ const typeNode = TsTypeNode.fromZod(userSchema);
38
+
39
+ // Print as TypeScript type string
40
+ const typeString = TsTypePrinter.print(typeNode);
41
+ // Output: { id: string; name: string; email: string; age?: number | undefined; }
42
+ ```
43
+
44
+ ## API
45
+
46
+ ### TsTypeNode
47
+
48
+ - `static fromZod(zodType: $ZodType): TypeNode` - Converts a Zod schema to a TypeScript AST node
49
+
50
+ ### TsTypePrinter
51
+
52
+ - `static print(tsType: TypeNode): string` - Converts a TypeScript AST node to a string
53
+ representation
54
+
55
+ ## License
56
+
57
+ ISC
@@ -0,0 +1,58 @@
1
+ import { TypeNode } from 'typescript';
2
+ import { $ZodType } from 'zod/v4/core';
3
+
4
+ declare class TsTypeNode {
5
+ static fromZod(zodType: $ZodType): TypeNode;
6
+ private static fromZodString;
7
+ private static fromZodNumber;
8
+ private static fromZodBigInt;
9
+ private static fromZodBoolean;
10
+ private static fromZodDate;
11
+ private static fromZodSymbol;
12
+ private static fromZodUndefined;
13
+ private static fromZodNullable;
14
+ private static fromZodNull;
15
+ private static fromZodAny;
16
+ private static fromZodUnknown;
17
+ private static fromZodNever;
18
+ private static fromZodVoid;
19
+ private static fromZodArray;
20
+ private static fromZodObject;
21
+ private static fromZodUnion;
22
+ private static fromZodIntersection;
23
+ private static fromZodTuple;
24
+ private static fromZodRecord;
25
+ private static fromZodMap;
26
+ private static fromZodSet;
27
+ private static fromZodLiteral;
28
+ private static fromZodEnum;
29
+ private static fromZodPromise;
30
+ private static fromZodLazy;
31
+ private static fromZodOptional;
32
+ private static fromZodDefault;
33
+ private static fromZodTemplateLiteral;
34
+ private static fromZodCustom;
35
+ private static fromZodTransform;
36
+ private static fromZodNonOptional;
37
+ private static fromZodReadonly;
38
+ private static fromZodNaN;
39
+ private static fromZodPipe;
40
+ private static fromZodSuccess;
41
+ private static fromZodCatch;
42
+ private static fromZodFile;
43
+ /**
44
+ * Returns a TypeScript AST node representing the property key.
45
+ * If the key is a valid JavaScript identifier, returns an Identifier node.
46
+ * Otherwise, returns a StringLiteral node.
47
+ *
48
+ * @param {string} key - The property key to convert.
49
+ * @returns {Identifier | StringLiteral} The corresponding AST node for the property key.
50
+ */
51
+ private static createTsAstPropertyKey;
52
+ }
53
+
54
+ declare class TsTypePrinter {
55
+ static print(tsType: TypeNode): string;
56
+ }
57
+
58
+ export { TsTypeNode, TsTypePrinter };
package/dist/index.js ADDED
@@ -0,0 +1,352 @@
1
+ import { factory, SyntaxKind, createSourceFile, ScriptTarget, ScriptKind, createPrinter, EmitHint } from 'typescript';
2
+ import { $ZodString, $ZodNumber, $ZodBigInt, $ZodBoolean, $ZodDate, $ZodSymbol, $ZodUndefined, $ZodNullable, $ZodNull, $ZodAny, $ZodUnknown, $ZodNever, $ZodVoid, $ZodArray, $ZodObject, $ZodUnion, $ZodIntersection, $ZodTuple, $ZodRecord, $ZodMap, $ZodSet, $ZodLiteral, $ZodEnum, $ZodPromise, $ZodLazy, $ZodOptional, $ZodDefault, $ZodTemplateLiteral, $ZodCustom, $ZodTransform, $ZodNonOptional, $ZodReadonly, $ZodNaN, $ZodPipe, $ZodSuccess, $ZodCatch, $ZodFile } from 'zod/v4/core';
3
+
4
+ class TsTypeNode {
5
+ static fromZod(zodType) {
6
+ if (zodType instanceof $ZodString) {
7
+ return TsTypeNode.fromZodString(zodType);
8
+ }
9
+ if (zodType instanceof $ZodNumber) {
10
+ return TsTypeNode.fromZodNumber(zodType);
11
+ }
12
+ if (zodType instanceof $ZodBigInt) {
13
+ return TsTypeNode.fromZodBigInt(zodType);
14
+ }
15
+ if (zodType instanceof $ZodBoolean) {
16
+ return TsTypeNode.fromZodBoolean(zodType);
17
+ }
18
+ if (zodType instanceof $ZodDate) {
19
+ return TsTypeNode.fromZodDate(zodType);
20
+ }
21
+ if (zodType instanceof $ZodSymbol) {
22
+ return TsTypeNode.fromZodSymbol(zodType);
23
+ }
24
+ if (zodType instanceof $ZodUndefined) {
25
+ return TsTypeNode.fromZodUndefined(zodType);
26
+ }
27
+ if (zodType instanceof $ZodNullable) {
28
+ return TsTypeNode.fromZodNullable(zodType);
29
+ }
30
+ if (zodType instanceof $ZodNull) {
31
+ return TsTypeNode.fromZodNull(zodType);
32
+ }
33
+ if (zodType instanceof $ZodAny) {
34
+ return TsTypeNode.fromZodAny(zodType);
35
+ }
36
+ if (zodType instanceof $ZodUnknown) {
37
+ return TsTypeNode.fromZodUnknown(zodType);
38
+ }
39
+ if (zodType instanceof $ZodNever) {
40
+ return TsTypeNode.fromZodNever(zodType);
41
+ }
42
+ if (zodType instanceof $ZodVoid) {
43
+ return TsTypeNode.fromZodVoid(zodType);
44
+ }
45
+ if (zodType instanceof $ZodArray) {
46
+ return TsTypeNode.fromZodArray(zodType);
47
+ }
48
+ if (zodType instanceof $ZodObject) {
49
+ return TsTypeNode.fromZodObject(zodType);
50
+ }
51
+ if (zodType instanceof $ZodUnion) {
52
+ return TsTypeNode.fromZodUnion(zodType);
53
+ }
54
+ if (zodType instanceof $ZodIntersection) {
55
+ return TsTypeNode.fromZodIntersection(zodType);
56
+ }
57
+ if (zodType instanceof $ZodTuple) {
58
+ return TsTypeNode.fromZodTuple(zodType);
59
+ }
60
+ if (zodType instanceof $ZodRecord) {
61
+ return TsTypeNode.fromZodRecord(zodType);
62
+ }
63
+ if (zodType instanceof $ZodMap) {
64
+ return TsTypeNode.fromZodMap(zodType);
65
+ }
66
+ if (zodType instanceof $ZodSet) {
67
+ return TsTypeNode.fromZodSet(zodType);
68
+ }
69
+ if (zodType instanceof $ZodLiteral) {
70
+ if (!TsTypeNode) {
71
+ throw new Error("ZodLiteral has no values");
72
+ }
73
+ return TsTypeNode.fromZodLiteral(zodType);
74
+ }
75
+ if (zodType instanceof $ZodEnum) {
76
+ return TsTypeNode.fromZodEnum(zodType);
77
+ }
78
+ if (zodType instanceof $ZodPromise) {
79
+ return TsTypeNode.fromZodPromise(zodType);
80
+ }
81
+ if (zodType instanceof $ZodLazy) {
82
+ return TsTypeNode.fromZodLazy(zodType);
83
+ }
84
+ if (zodType instanceof $ZodOptional) {
85
+ return TsTypeNode.fromZodOptional(zodType);
86
+ }
87
+ if (zodType instanceof $ZodDefault) {
88
+ return TsTypeNode.fromZodDefault(zodType);
89
+ }
90
+ if (zodType instanceof $ZodTemplateLiteral) {
91
+ return TsTypeNode.fromZodTemplateLiteral(zodType);
92
+ }
93
+ if (zodType instanceof $ZodCustom) {
94
+ return TsTypeNode.fromZodCustom(zodType);
95
+ }
96
+ if (zodType instanceof $ZodTransform) {
97
+ return TsTypeNode.fromZodTransform(zodType);
98
+ }
99
+ if (zodType instanceof $ZodNonOptional) {
100
+ return TsTypeNode.fromZodNonOptional(zodType);
101
+ }
102
+ if (zodType instanceof $ZodReadonly) {
103
+ return TsTypeNode.fromZodReadonly(zodType);
104
+ }
105
+ if (zodType instanceof $ZodNaN) {
106
+ return TsTypeNode.fromZodNaN(zodType);
107
+ }
108
+ if (zodType instanceof $ZodPipe) {
109
+ return TsTypeNode.fromZodPipe(zodType);
110
+ }
111
+ if (zodType instanceof $ZodSuccess) {
112
+ return TsTypeNode.fromZodSuccess(zodType);
113
+ }
114
+ if (zodType instanceof $ZodCatch) {
115
+ return TsTypeNode.fromZodCatch(zodType);
116
+ }
117
+ if (zodType instanceof $ZodFile) {
118
+ return TsTypeNode.fromZodFile(zodType);
119
+ }
120
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
121
+ }
122
+ static fromZodString(zodString) {
123
+ return factory.createKeywordTypeNode(SyntaxKind.StringKeyword);
124
+ }
125
+ static fromZodNumber(zodNumber) {
126
+ return factory.createKeywordTypeNode(SyntaxKind.NumberKeyword);
127
+ }
128
+ static fromZodBigInt(zodBigInt) {
129
+ return factory.createKeywordTypeNode(SyntaxKind.BigIntKeyword);
130
+ }
131
+ static fromZodBoolean(zodBoolean) {
132
+ return factory.createKeywordTypeNode(SyntaxKind.BooleanKeyword);
133
+ }
134
+ static fromZodDate(zodDate) {
135
+ return factory.createTypeReferenceNode(factory.createIdentifier("Date"));
136
+ }
137
+ static fromZodSymbol(zodSymbol) {
138
+ return factory.createKeywordTypeNode(SyntaxKind.SymbolKeyword);
139
+ }
140
+ static fromZodUndefined(zodUndefined) {
141
+ return factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword);
142
+ }
143
+ static fromZodNullable(zodNullable) {
144
+ const innerType = TsTypeNode.fromZod(zodNullable._zod.def.innerType);
145
+ return factory.createUnionTypeNode([
146
+ innerType,
147
+ factory.createLiteralTypeNode(factory.createNull())
148
+ ]);
149
+ }
150
+ static fromZodNull(zodNull) {
151
+ return factory.createLiteralTypeNode(factory.createNull());
152
+ }
153
+ static fromZodAny(zodAny) {
154
+ return factory.createKeywordTypeNode(SyntaxKind.AnyKeyword);
155
+ }
156
+ static fromZodUnknown(zodUnknown) {
157
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
158
+ }
159
+ static fromZodNever(zodNever) {
160
+ return factory.createKeywordTypeNode(SyntaxKind.NeverKeyword);
161
+ }
162
+ static fromZodVoid(zodVoid) {
163
+ return factory.createKeywordTypeNode(SyntaxKind.VoidKeyword);
164
+ }
165
+ static fromZodArray(zodArray) {
166
+ const innerType = TsTypeNode.fromZod(zodArray._zod.def.element);
167
+ return factory.createArrayTypeNode(innerType);
168
+ }
169
+ static fromZodObject(zodObject) {
170
+ const entries = Object.entries(zodObject._zod.def.shape);
171
+ const members = entries.map(([key, nextZodNode]) => {
172
+ const type = TsTypeNode.fromZod(nextZodNode);
173
+ if (!nextZodNode._zod?.def) {
174
+ console.warn(
175
+ `Zod node for key "${key}" does not have a _zod.def property. This may indicate an issue with the Zod schema.`,
176
+ {
177
+ key
178
+ }
179
+ );
180
+ }
181
+ const { type: nextZodNodeTypeName } = nextZodNode._zod?.def ?? {};
182
+ const isOptional = nextZodNodeTypeName === "optional";
183
+ const propertySignature = factory.createPropertySignature(
184
+ void 0,
185
+ TsTypeNode.createTsAstPropertyKey(key),
186
+ isOptional ? factory.createToken(SyntaxKind.QuestionToken) : void 0,
187
+ type
188
+ );
189
+ return propertySignature;
190
+ });
191
+ return factory.createTypeLiteralNode(members);
192
+ }
193
+ static fromZodUnion(zodUnion) {
194
+ const options = zodUnion._zod.def.options.map(TsTypeNode.fromZod);
195
+ return factory.createUnionTypeNode(options);
196
+ }
197
+ static fromZodIntersection(zodIntersection) {
198
+ const left = TsTypeNode.fromZod(zodIntersection._zod.def.left);
199
+ const right = TsTypeNode.fromZod(zodIntersection._zod.def.right);
200
+ return factory.createIntersectionTypeNode([left, right]);
201
+ }
202
+ static fromZodTuple(zodTuple) {
203
+ const elements = zodTuple._zod.def.items.map(TsTypeNode.fromZod);
204
+ return factory.createTupleTypeNode(elements);
205
+ }
206
+ static fromZodRecord(zodRecord) {
207
+ const keyType = TsTypeNode.fromZod(zodRecord._zod.def.keyType);
208
+ const valueType = TsTypeNode.fromZod(zodRecord._zod.def.valueType);
209
+ return factory.createTypeReferenceNode(factory.createIdentifier("Record"), [
210
+ keyType,
211
+ valueType
212
+ ]);
213
+ }
214
+ static fromZodMap(zodMap) {
215
+ const keyType = TsTypeNode.fromZod(zodMap._zod.def.keyType);
216
+ const valueType = TsTypeNode.fromZod(zodMap._zod.def.valueType);
217
+ return factory.createTypeReferenceNode(factory.createIdentifier("Map"), [
218
+ keyType,
219
+ valueType
220
+ ]);
221
+ }
222
+ static fromZodSet(zodSet) {
223
+ const innerType = TsTypeNode.fromZod(zodSet._zod.def.valueType);
224
+ return factory.createTypeReferenceNode(factory.createIdentifier("Set"), [
225
+ innerType
226
+ ]);
227
+ }
228
+ static fromZodLiteral(zodLiteral) {
229
+ if (zodLiteral._zod.def.values.length === 0) {
230
+ throw new Error("ZodLiteral has no values");
231
+ }
232
+ const value = zodLiteral._zod.def.values[0];
233
+ if (typeof value === "string") {
234
+ return factory.createLiteralTypeNode(factory.createStringLiteral(value));
235
+ }
236
+ if (typeof value === "number") {
237
+ return factory.createLiteralTypeNode(factory.createNumericLiteral(value));
238
+ }
239
+ if (typeof value === "boolean") {
240
+ return factory.createLiteralTypeNode(
241
+ value ? factory.createTrue() : factory.createFalse()
242
+ );
243
+ }
244
+ if (typeof value === "bigint") {
245
+ return factory.createLiteralTypeNode(
246
+ factory.createBigIntLiteral(value.toString())
247
+ );
248
+ }
249
+ if (value === null) {
250
+ return factory.createLiteralTypeNode(factory.createNull());
251
+ }
252
+ if (value === void 0) {
253
+ return factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword);
254
+ }
255
+ throw new Error(`Unsupported literal type: ${typeof value}`);
256
+ }
257
+ static fromZodEnum(zodEnum) {
258
+ const entries = Object.entries(zodEnum._zod.def.entries);
259
+ const types = entries.map(([key, value]) => {
260
+ return factory.createLiteralTypeNode(factory.createStringLiteral(key));
261
+ });
262
+ return factory.createUnionTypeNode(types);
263
+ }
264
+ static fromZodPromise(zodPromise) {
265
+ const innerType = TsTypeNode.fromZod(zodPromise._zod.def.innerType);
266
+ return factory.createTypeReferenceNode(
267
+ factory.createIdentifier("Promise"),
268
+ [innerType]
269
+ );
270
+ }
271
+ static fromZodLazy(zodLazy) {
272
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
273
+ }
274
+ static fromZodOptional(zodOptional) {
275
+ const innerType = TsTypeNode.fromZod(zodOptional._zod.def.innerType);
276
+ return factory.createUnionTypeNode([
277
+ innerType,
278
+ factory.createKeywordTypeNode(SyntaxKind.UndefinedKeyword)
279
+ ]);
280
+ }
281
+ static fromZodDefault(zodDefault) {
282
+ const innerType = TsTypeNode.fromZod(zodDefault._zod.def.innerType);
283
+ const filteredNodes = [];
284
+ innerType.forEachChild((node) => {
285
+ if (node.kind !== SyntaxKind.UndefinedKeyword) {
286
+ filteredNodes.push(node);
287
+ }
288
+ });
289
+ innerType.types = filteredNodes;
290
+ return innerType;
291
+ }
292
+ static fromZodTemplateLiteral(zodTemplateLiteral) {
293
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
294
+ }
295
+ static fromZodCustom(zodCustom) {
296
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
297
+ }
298
+ static fromZodTransform(zodTransform) {
299
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
300
+ }
301
+ static fromZodNonOptional(zodNonOptional) {
302
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
303
+ }
304
+ static fromZodReadonly(zodReadonly) {
305
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
306
+ }
307
+ static fromZodNaN(zodNaN) {
308
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
309
+ }
310
+ static fromZodPipe(zodPipe) {
311
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
312
+ }
313
+ static fromZodSuccess(zodSuccess) {
314
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
315
+ }
316
+ static fromZodCatch(zodCatch) {
317
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
318
+ }
319
+ static fromZodFile(zodFile) {
320
+ return factory.createKeywordTypeNode(SyntaxKind.UnknownKeyword);
321
+ }
322
+ /**
323
+ * Returns a TypeScript AST node representing the property key.
324
+ * If the key is a valid JavaScript identifier, returns an Identifier node.
325
+ * Otherwise, returns a StringLiteral node.
326
+ *
327
+ * @param {string} key - The property key to convert.
328
+ * @returns {Identifier | StringLiteral} The corresponding AST node for the property key.
329
+ */
330
+ static createTsAstPropertyKey(key) {
331
+ if (/^[$A-Z_a-z][\w$]*$/.test(key)) {
332
+ return factory.createIdentifier(key);
333
+ }
334
+ return factory.createStringLiteral(key);
335
+ }
336
+ }
337
+
338
+ class TsTypePrinter {
339
+ static print(tsType) {
340
+ const sourceFile = createSourceFile(
341
+ "print.ts",
342
+ "",
343
+ ScriptTarget.Latest,
344
+ false,
345
+ ScriptKind.TS
346
+ );
347
+ const printer = createPrinter();
348
+ return printer.printNode(EmitHint.Unspecified, tsType, sourceFile);
349
+ }
350
+ }
351
+
352
+ export { TsTypeNode, TsTypePrinter };
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@rexeus/typeweaver-zod-to-ts",
3
+ "version": "0.0.3",
4
+ "description": "Generates TypeScript types from Zod schemas, used by TypeWeaver framework",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist",
16
+ "package.json",
17
+ "README.md"
18
+ ],
19
+ "keywords": [
20
+ "zod",
21
+ "typescript",
22
+ "type",
23
+ "conversion",
24
+ "generator",
25
+ "typeweaver"
26
+ ],
27
+ "author": "Dennis Wentzien <dw@rexeus.com>",
28
+ "license": "ISC",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/rexeus/typeweaver.git",
32
+ "directory": "packages/zod-to-ts"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/rexeus/typeweaver/issues"
36
+ },
37
+ "homepage": "https://github.com/rexeus/typeweaver#readme",
38
+ "dependencies": {
39
+ "typescript": "^5.8.3"
40
+ },
41
+ "peerDependencies": {
42
+ "zod": "^3.25.67"
43
+ },
44
+ "devDependencies": {
45
+ "zod": "^3.25.67"
46
+ },
47
+ "scripts": {
48
+ "typecheck": "tsc --noEmit",
49
+ "format": "prettier --write .",
50
+ "build": "pkgroll --clean-dist",
51
+ "preversion": "npm run build"
52
+ }
53
+ }