zinfer 0.0.1 → 0.1.2

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 (79) hide show
  1. package/README.md +477 -28
  2. package/bin/zinfer +2 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +486 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/brand-detector.d.ts +32 -0
  8. package/dist/core/brand-detector.d.ts.map +1 -0
  9. package/dist/core/brand-detector.js +121 -0
  10. package/dist/core/brand-detector.js.map +1 -0
  11. package/dist/core/config-loader.d.ts +87 -0
  12. package/dist/core/config-loader.d.ts.map +1 -0
  13. package/dist/core/config-loader.js +105 -0
  14. package/dist/core/config-loader.js.map +1 -0
  15. package/dist/core/description-extractor.d.ts +54 -0
  16. package/dist/core/description-extractor.d.ts.map +1 -0
  17. package/dist/core/description-extractor.js +180 -0
  18. package/dist/core/description-extractor.js.map +1 -0
  19. package/dist/core/errors.d.ts +35 -0
  20. package/dist/core/errors.d.ts.map +1 -0
  21. package/dist/core/errors.js +96 -0
  22. package/dist/core/errors.js.map +1 -0
  23. package/dist/core/extractor.d.ts +121 -0
  24. package/dist/core/extractor.d.ts.map +1 -0
  25. package/dist/core/extractor.js +504 -0
  26. package/dist/core/extractor.js.map +1 -0
  27. package/dist/core/file-resolver.d.ts +41 -0
  28. package/dist/core/file-resolver.d.ts.map +1 -0
  29. package/dist/core/file-resolver.js +95 -0
  30. package/dist/core/file-resolver.js.map +1 -0
  31. package/dist/core/getter-resolver.d.ts +67 -0
  32. package/dist/core/getter-resolver.d.ts.map +1 -0
  33. package/dist/core/getter-resolver.js +234 -0
  34. package/dist/core/getter-resolver.js.map +1 -0
  35. package/dist/core/import-resolver.d.ts +51 -0
  36. package/dist/core/import-resolver.d.ts.map +1 -0
  37. package/dist/core/import-resolver.js +158 -0
  38. package/dist/core/import-resolver.js.map +1 -0
  39. package/dist/core/index.d.ts +14 -0
  40. package/dist/core/index.d.ts.map +1 -0
  41. package/dist/core/index.js +13 -0
  42. package/dist/core/index.js.map +1 -0
  43. package/dist/core/logger.d.ts +20 -0
  44. package/dist/core/logger.d.ts.map +1 -0
  45. package/dist/core/logger.js +36 -0
  46. package/dist/core/logger.js.map +1 -0
  47. package/dist/core/name-mapper.d.ts +45 -0
  48. package/dist/core/name-mapper.d.ts.map +1 -0
  49. package/dist/core/name-mapper.js +82 -0
  50. package/dist/core/name-mapper.js.map +1 -0
  51. package/dist/core/normalizer.d.ts +24 -0
  52. package/dist/core/normalizer.d.ts.map +1 -0
  53. package/dist/core/normalizer.js +50 -0
  54. package/dist/core/normalizer.js.map +1 -0
  55. package/dist/core/schema-detector.d.ts +49 -0
  56. package/dist/core/schema-detector.d.ts.map +1 -0
  57. package/dist/core/schema-detector.js +272 -0
  58. package/dist/core/schema-detector.js.map +1 -0
  59. package/dist/core/schema-reference-analyzer.d.ts +77 -0
  60. package/dist/core/schema-reference-analyzer.d.ts.map +1 -0
  61. package/dist/core/schema-reference-analyzer.js +269 -0
  62. package/dist/core/schema-reference-analyzer.js.map +1 -0
  63. package/dist/core/test-generator.d.ts +97 -0
  64. package/dist/core/test-generator.d.ts.map +1 -0
  65. package/dist/core/test-generator.js +177 -0
  66. package/dist/core/test-generator.js.map +1 -0
  67. package/dist/core/type-printer.d.ts +46 -0
  68. package/dist/core/type-printer.d.ts.map +1 -0
  69. package/dist/core/type-printer.js +519 -0
  70. package/dist/core/type-printer.js.map +1 -0
  71. package/dist/core/types.d.ts +124 -0
  72. package/dist/core/types.d.ts.map +1 -0
  73. package/dist/core/types.js +5 -0
  74. package/dist/core/types.js.map +1 -0
  75. package/dist/index.d.ts +66 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +79 -0
  78. package/dist/index.js.map +1 -0
  79. package/package.json +63 -7
package/README.md CHANGED
@@ -1,45 +1,494 @@
1
1
  # zinfer
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ A tool to extract TypeScript input/output types from Zod schemas.
4
4
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
5
+ ## Features
6
6
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
7
+ - Extract `z.input<T>` / `z.output<T>` types as text from Zod schemas
8
+ - Accurate type analysis using TypeScript Compiler API (ts-morph)
9
+ - Non-invasive: does not modify original source files
10
+ - Supports both CLI and library API
11
+ - Handles circular references (`z.lazy`, getter patterns)
12
+ - Outputs `.describe()` as TSDoc comments
13
+ - Supports branded types via `.brand()`
14
+ - Configuration file support (`zinfer.config.ts`, `package.json`)
8
15
 
9
- ## Purpose
16
+ ## Installation
10
17
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `zinfer`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
18
+ ```bash
19
+ npm install zinfer
20
+ ```
15
21
 
16
- ## What is OIDC Trusted Publishing?
22
+ ## Quick Start
17
23
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
24
+ ### CLI
19
25
 
20
- ## Setup Instructions
26
+ ```bash
27
+ # Extract all schemas from a single file
28
+ zinfer src/schemas/user.ts
21
29
 
22
- To properly configure OIDC trusted publishing for this package:
30
+ # Process multiple files with glob patterns
31
+ zinfer "src/**/*.schema.ts"
23
32
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
33
+ # Output to files
34
+ zinfer src/schemas.ts --outDir ./types
28
35
 
29
- ## DO NOT USE THIS PACKAGE
36
+ # Merge into a single type when input/output are identical
37
+ zinfer src/schemas.ts --merge-same --suffix Schema
38
+ ```
30
39
 
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
40
+ ### Library API
36
41
 
37
- ## More Information
42
+ ```typescript
43
+ import { extractZodTypes, extractAllSchemas, extractAndFormat } from "zinfer";
38
44
 
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
45
+ // Extract a single schema
46
+ const { input, output } = extractZodTypes("./schemas.ts", "UserSchema");
47
+ console.log(input); // { id: string; name: string; }
48
+ console.log(output); // { id: string; name: string; }
42
49
 
43
- ---
50
+ // Get formatted output
51
+ const formatted = extractAndFormat("./schemas.ts", "UserSchema");
52
+ console.log(formatted);
44
53
 
45
- **Maintained for OIDC setup purposes only**
54
+ // Extract all schemas from a file
55
+ const results = extractAllSchemas("./schemas.ts");
56
+ for (const result of results) {
57
+ console.log(`${result.schemaName}: ${result.input}`);
58
+ }
59
+ ```
60
+
61
+ ## CLI Options
62
+
63
+ ```
64
+ Usage: zinfer [options] [files...]
65
+
66
+ Arguments:
67
+ files File paths or glob patterns
68
+
69
+ Options:
70
+ -c, --config <path> Path to config file
71
+ -p, --project <path> Path to tsconfig.json
72
+ --schemas <names> Comma-separated schema names to extract
73
+ --input-only Output only input types
74
+ --output-only Output only output types
75
+ --merge-same Single type if input===output
76
+ --suffix <suffix> Remove suffix from schema names (e.g., 'Schema')
77
+ --input-suffix <suffix> Suffix for input type names (default: 'Input')
78
+ --output-suffix <suffix> Suffix for output type names (default: 'Output')
79
+ --map <mappings> Custom name mappings (e.g., 'UserSchema:User')
80
+ --outDir <dir> Output directory for generated files
81
+ --outFile <file> Single output file for all types
82
+ --outPattern <pattern> Output file naming pattern (e.g., '[name].types.ts')
83
+ -d, --declaration Generate .d.ts files
84
+ --dry-run Preview without writing files
85
+ --with-descriptions Include Zod .describe() as TSDoc comments
86
+ --generate-tests Generate vitest type equality tests alongside type files
87
+ -V, --version Output the version number
88
+ -h, --help Display help
89
+ ```
90
+
91
+ ## Configuration File
92
+
93
+ ### zinfer.config.ts
94
+
95
+ ```typescript
96
+ import { defineConfig } from "zinfer";
97
+
98
+ export default defineConfig({
99
+ // Target files
100
+ include: ["src/**/*.schema.ts"],
101
+
102
+ // Exclude patterns
103
+ exclude: ["**/*.test.ts"],
104
+
105
+ // Path to tsconfig.json
106
+ project: "./tsconfig.json",
107
+
108
+ // Schema names to extract (all if not specified)
109
+ schemas: ["UserSchema", "PostSchema"],
110
+
111
+ // Output options
112
+ outDir: "./types",
113
+ outFile: "./types/index.ts",
114
+ outPattern: "[name].types.ts",
115
+ declaration: true,
116
+
117
+ // Type output options
118
+ inputOnly: false, // Output only input types
119
+ outputOnly: false, // Output only output types
120
+ mergeSame: true, // Merge into single type when input === output
121
+
122
+ // Type name options
123
+ suffix: "Schema", // Suffix to remove from schema names
124
+ inputSuffix: "Input", // Suffix for input types
125
+ outputSuffix: "Output", // Suffix for output types
126
+
127
+ // Custom mappings
128
+ map: {
129
+ UserSchema: "User",
130
+ PostSchema: "Article",
131
+ },
132
+
133
+ // Output .describe() as TSDoc
134
+ withDescriptions: true,
135
+ });
136
+ ```
137
+
138
+ ### package.json
139
+
140
+ ```json
141
+ {
142
+ "zinfer": {
143
+ "include": ["src/**/*.schema.ts"],
144
+ "outDir": "./types",
145
+ "mergeSame": true,
146
+ "suffix": "Schema"
147
+ }
148
+ }
149
+ ```
150
+
151
+ Config file resolution order:
152
+
153
+ 1. `zinfer.config.ts`
154
+ 2. `zinfer.config.mts`
155
+ 3. `zinfer.config.js`
156
+ 4. `zinfer.config.mjs`
157
+ 5. `zinfer` field in `package.json`
158
+
159
+ CLI options take precedence over config file settings.
160
+
161
+ ## Output Examples
162
+
163
+ ### Basic Output
164
+
165
+ Input schema:
166
+
167
+ ```typescript
168
+ export const UserSchema = z.object({
169
+ id: z.string().uuid(),
170
+ name: z.string(),
171
+ age: z.number().optional(),
172
+ });
173
+ ```
174
+
175
+ Output (default):
176
+
177
+ ```typescript
178
+ export type UserSchemaInput = {
179
+ id: string;
180
+ name: string;
181
+ age?: number | undefined;
182
+ };
183
+
184
+ export type UserSchemaOutput = {
185
+ id: string;
186
+ name: string;
187
+ age?: number | undefined;
188
+ };
189
+ ```
190
+
191
+ Output (`--merge-same --suffix Schema`):
192
+
193
+ ```typescript
194
+ export type User = {
195
+ id: string;
196
+ name: string;
197
+ age?: number | undefined;
198
+ };
199
+ ```
200
+
201
+ ### With Transforms
202
+
203
+ Input schema:
204
+
205
+ ```typescript
206
+ export const DateSchema = z.object({
207
+ createdAt: z.string().transform((s) => new Date(s)),
208
+ count: z.string().transform(Number),
209
+ });
210
+ ```
211
+
212
+ Output:
213
+
214
+ ```typescript
215
+ export type DateSchemaInput = {
216
+ createdAt: string;
217
+ count: string;
218
+ };
219
+
220
+ export type DateSchemaOutput = {
221
+ createdAt: Date;
222
+ count: number;
223
+ };
224
+ ```
225
+
226
+ ### With TSDoc Comments (`--with-descriptions`)
227
+
228
+ Input schema:
229
+
230
+ ```typescript
231
+ export const UserSchema = z
232
+ .object({
233
+ id: z.string().uuid().describe("Unique user identifier"),
234
+ name: z.string().describe("User's display name"),
235
+ email: z.string().email().describe("Email address"),
236
+ })
237
+ .describe("User account information");
238
+ ```
239
+
240
+ Output:
241
+
242
+ ```typescript
243
+ /**
244
+ * User account information
245
+ */
246
+ export type UserSchemaInput = {
247
+ /** Unique user identifier */
248
+ id: string;
249
+ /** User's display name */
250
+ name: string;
251
+ /** Email address */
252
+ email: string;
253
+ };
254
+ ```
255
+
256
+ ### Branded Types
257
+
258
+ Input schema:
259
+
260
+ ```typescript
261
+ export const UserIdSchema = z.string().brand<"UserId">();
262
+
263
+ export const UserSchema = z.object({
264
+ id: z.string().brand<"UserId">(),
265
+ name: z.string(),
266
+ });
267
+ ```
268
+
269
+ Output:
270
+
271
+ ```typescript
272
+ import type { BRAND } from "zod";
273
+
274
+ export type UserIdSchemaInput = string;
275
+
276
+ export type UserIdSchemaOutput = string & BRAND<"UserId">;
277
+
278
+ export type UserSchemaInput = {
279
+ id: string;
280
+ name: string;
281
+ };
282
+
283
+ export type UserSchemaOutput = {
284
+ id: string & BRAND<"UserId">;
285
+ name: string;
286
+ };
287
+ ```
288
+
289
+ Branded types are applied only to output types. Input types do not include brands.
290
+
291
+ ## Circular Reference Support
292
+
293
+ ### Getter Pattern (Recommended)
294
+
295
+ ```typescript
296
+ interface Category {
297
+ name: string;
298
+ subcategories: Category[];
299
+ }
300
+
301
+ const CategoryBaseSchema = z.object({
302
+ name: z.string(),
303
+ get subcategories() {
304
+ return CategorySchema.array();
305
+ },
306
+ });
307
+
308
+ export const CategorySchema: z.ZodType<Category> = CategoryBaseSchema;
309
+ ```
310
+
311
+ ### z.lazy Pattern
312
+
313
+ ```typescript
314
+ export type JsonValue =
315
+ | string
316
+ | number
317
+ | boolean
318
+ | null
319
+ | JsonValue[]
320
+ | { [key: string]: JsonValue };
321
+
322
+ export const JsonValueSchema: z.ZodType<JsonValue> = z.lazy(() =>
323
+ z.union([
324
+ z.string(),
325
+ z.number(),
326
+ z.boolean(),
327
+ z.null(),
328
+ z.array(JsonValueSchema),
329
+ z.record(JsonValueSchema),
330
+ ]),
331
+ );
332
+ ```
333
+
334
+ When an explicit type annotation (`z.ZodType<T>`) is present, that type name is used in the output.
335
+
336
+ ## Library API
337
+
338
+ ### extractZodTypes
339
+
340
+ Extracts types from a single schema.
341
+
342
+ ```typescript
343
+ import { extractZodTypes } from "zinfer";
344
+
345
+ const { input, output } = extractZodTypes(
346
+ "./schemas.ts",
347
+ "UserSchema",
348
+ "./tsconfig.json", // optional
349
+ );
350
+ ```
351
+
352
+ ### extractAllSchemas
353
+
354
+ Extracts all schemas from a file.
355
+
356
+ ```typescript
357
+ import { extractAllSchemas } from "zinfer";
358
+
359
+ const results = extractAllSchemas("./schemas.ts");
360
+ // results: ExtractResult[]
361
+ ```
362
+
363
+ ### extractAndFormat
364
+
365
+ Extracts types and returns them as a formatted string.
366
+
367
+ ```typescript
368
+ import { extractAndFormat } from "zinfer";
369
+
370
+ const formatted = extractAndFormat("./schemas.ts", "UserSchema");
371
+ console.log(formatted);
372
+ // Output:
373
+ // // input
374
+ // { id: string; name: string; }
375
+ //
376
+ // // output
377
+ // { id: string; name: string; }
378
+ ```
379
+
380
+ ### generateTypeDeclarations
381
+
382
+ Generates TypeScript type declarations from extraction results.
383
+
384
+ ```typescript
385
+ import { extractAllSchemas, generateTypeDeclarations } from "zinfer";
386
+
387
+ const results = extractAllSchemas("./schemas.ts");
388
+ const declarations = generateTypeDeclarations(results, {
389
+ nameMapping: {
390
+ removeSuffix: "Schema",
391
+ inputSuffix: "Input",
392
+ outputSuffix: "Output",
393
+ },
394
+ declaration: {
395
+ mergeSame: true,
396
+ },
397
+ });
398
+
399
+ console.log(declarations);
400
+ ```
401
+
402
+ ### ZodTypeExtractor Class
403
+
404
+ For more fine-grained control:
405
+
406
+ ```typescript
407
+ import { ZodTypeExtractor } from "zinfer";
408
+
409
+ const extractor = new ZodTypeExtractor("./tsconfig.json");
410
+
411
+ // Single schema
412
+ const result = extractor.extract({
413
+ filePath: "./schemas.ts",
414
+ schemaName: "UserSchema",
415
+ });
416
+
417
+ // All schemas
418
+ const allResults = extractor.extractAll("./schemas.ts");
419
+
420
+ // Multiple specific schemas
421
+ const selectedResults = extractor.extractMultiple("./schemas.ts", ["UserSchema", "PostSchema"]);
422
+
423
+ // Extract by file (includes file path)
424
+ const fileResult = extractor.extractFile("./schemas.ts");
425
+ // fileResult: { filePath: string; schemas: ExtractResult[] }
426
+
427
+ // List schema names
428
+ const schemaNames = extractor.getSchemaNames("./schemas.ts");
429
+ ```
430
+
431
+ ## Type Test Generation
432
+
433
+ zinfer can automatically generate vitest tests that verify the generated types match `z.input<typeof Schema>` / `z.output<typeof Schema>`.
434
+
435
+ ### Usage
436
+
437
+ ```bash
438
+ # Generate type definitions and tests simultaneously
439
+ zinfer "src/schemas/*.ts" --outDir ./types --generate-tests --suffix Schema
440
+ # -> ./types/user.ts (type definitions)
441
+ # -> ./types/user.test.ts (tests)
442
+
443
+ # When outputting to a single file
444
+ zinfer "src/schemas/*.ts" --outFile ./types.ts --generate-tests --suffix Schema
445
+ # -> ./types.ts (type definitions)
446
+ # -> ./types.test.ts (tests)
447
+
448
+ # Run the tests
449
+ vitest run
450
+ ```
451
+
452
+ ### Example Generated Test
453
+
454
+ ```typescript
455
+ import { describe, it, expectTypeOf } from "vitest";
456
+ import type { z } from "zod";
457
+
458
+ import { UserSchema } from "../schemas/user";
459
+ import type { UserInput, UserOutput } from "./user";
460
+
461
+ describe("Type equality tests", () => {
462
+ describe("user", () => {
463
+ it("UserSchema input matches z.input", () => {
464
+ expectTypeOf<UserInput>().toEqualTypeOf<z.input<typeof UserSchema>>();
465
+ });
466
+
467
+ it("UserSchema output matches z.output", () => {
468
+ expectTypeOf<UserOutput>().toEqualTypeOf<z.output<typeof UserSchema>>();
469
+ });
470
+ });
471
+ });
472
+ ```
473
+
474
+ Re-run with `--generate-tests` after modifying schemas to continuously verify type correctness.
475
+
476
+ ## Supported Zod Features
477
+
478
+ - Primitives: `z.string()`, `z.number()`, `z.boolean()`, `z.date()`, etc.
479
+ - Objects: `z.object()`
480
+ - Arrays: `z.array()`
481
+ - Union: `z.union()`, `z.discriminatedUnion()`
482
+ - Intersection: `z.intersection()`, `.and()`, `.merge()`
483
+ - Enum: `z.enum()`, `z.nativeEnum()`
484
+ - Optional/Nullable: `.optional()`, `.nullable()`
485
+ - Transform: `.transform()`
486
+ - Refine: `.refine()`, `.superRefine()`
487
+ - Utilities: `.partial()`, `.pick()`, `.omit()`, `.extend()`
488
+ - Circular references: `z.lazy()`, getter patterns
489
+ - Descriptions: `.describe()`
490
+ - Branded types: `.brand()`
491
+
492
+ ## License
493
+
494
+ MIT
package/bin/zinfer ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import "../dist/cli.js";
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}