zod-codegen 1.0.0 → 1.0.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.
@@ -5,24 +5,37 @@ import type {OpenApiSpecType} from '../types/openapi.js';
5
5
  import {OpenApiSpec} from '../types/openapi.js';
6
6
 
7
7
  export class SyncFileReaderService implements OpenApiFileReader {
8
- readFile(path: string): string {
9
- return readFileSync(path, 'utf8');
8
+ async readFile(path: string): Promise<string> {
9
+ // Check if path is a URL
10
+ try {
11
+ const url = new URL(path);
12
+ // If it's a valid URL, fetch it
13
+ const response = await fetch(url.toString());
14
+ if (!response.ok) {
15
+ throw new Error(`Failed to fetch ${path}: ${String(response.status)} ${response.statusText}`);
16
+ }
17
+ return await response.text();
18
+ } catch {
19
+ // If URL parsing fails, treat it as a local file path
20
+ return readFileSync(path, 'utf8');
21
+ }
10
22
  }
11
23
  }
12
24
 
13
25
  export class OpenApiFileParserService implements OpenApiFileParser<OpenApiSpecType> {
14
26
  parse(input: unknown): OpenApiSpecType {
15
- let parsedInput: unknown;
16
-
17
- if (typeof input === 'string') {
18
- try {
19
- parsedInput = JSON.parse(input);
20
- } catch {
21
- parsedInput = load(input);
22
- }
23
- } else {
24
- parsedInput = input;
25
- }
27
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
28
+ const parsedInput =
29
+ typeof input === 'string'
30
+ ? (() => {
31
+ try {
32
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
33
+ return JSON.parse(input);
34
+ } catch {
35
+ return load(input);
36
+ }
37
+ })()
38
+ : input;
26
39
 
27
40
  return OpenApiSpec.parse(parsedInput);
28
41
  }
@@ -16,10 +16,7 @@ export class TypeScriptImportBuilderService implements ImportBuilder {
16
16
  buildImports(): ts.ImportDeclaration[] {
17
17
  return [
18
18
  this.createImport('zod', {
19
- defaultImport: {z: false},
20
- }),
21
- this.createImport('path-to-regexp', {
22
- namedImports: {compile: false},
19
+ namedImports: {z: false},
23
20
  }),
24
21
  ];
25
22
  }
@@ -46,16 +43,16 @@ export class TypeScriptImportBuilderService implements ImportBuilder {
46
43
  const hasAnyImports = hasDefaultImport || namedImports;
47
44
 
48
45
  // For side effects imports, we can pass undefined as the import clause
49
- // For imports with bindings, we need to create the clause differently
46
+ // For imports with bindings, we need to create the clause using the factory
50
47
  return ts.factory.createImportDeclaration(
51
48
  undefined,
52
49
  hasAnyImports
53
- ? ({
54
- kind: ts.SyntaxKind.ImportClause,
55
- isTypeOnly: false,
56
- name: hasDefaultImport && defaultImport ? ts.factory.createIdentifier(defaultImport) : undefined,
57
- namedBindings: namedImports,
58
- } as ts.ImportClause)
50
+ ? // eslint-disable-next-line @typescript-eslint/no-deprecated
51
+ ts.factory.createImportClause(
52
+ false,
53
+ hasDefaultImport && defaultImport ? ts.factory.createIdentifier(defaultImport) : undefined,
54
+ namedImports ?? undefined,
55
+ )
59
56
  : undefined,
60
57
  ts.factory.createStringLiteral(target, true),
61
58
  undefined,
@@ -11,8 +11,23 @@ export class TypeScriptTypeBuilderService implements TypeBuilder {
11
11
  case 'boolean':
12
12
  return ts.factory.createKeywordTypeNode(ts.SyntaxKind.BooleanKeyword);
13
13
  case 'unknown':
14
- default:
15
14
  return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
15
+ default:
16
+ // Handle custom types (like Pet, Order, User, etc.) and array types
17
+ if (type.endsWith('[]')) {
18
+ const itemType = type.slice(0, -2);
19
+ return ts.factory.createArrayTypeNode(this.buildType(itemType));
20
+ }
21
+ // Handle Record types
22
+ if (type.startsWith('Record<')) {
23
+ // For now, return unknown for complex Record types
24
+ return ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword);
25
+ }
26
+ // Custom type name - create a type reference
27
+ return ts.factory.createTypeReferenceNode(
28
+ ts.factory.createIdentifier(this.sanitizeIdentifier(type)),
29
+ undefined,
30
+ );
16
31
  }
17
32
  }
18
33
 
@@ -54,17 +69,9 @@ export class TypeScriptTypeBuilderService implements TypeBuilder {
54
69
  }
55
70
 
56
71
  sanitizeIdentifier(name: string): string {
57
- let sanitized = name.replace(/[^a-zA-Z0-9_]/g, '_');
58
-
59
- if (/^[0-9]/.test(sanitized)) {
60
- sanitized = '_' + sanitized;
61
- }
62
-
63
- if (sanitized.length === 0) {
64
- sanitized = '_';
65
- }
66
-
67
- return sanitized;
72
+ const sanitized = name.replace(/[^a-zA-Z0-9_]/g, '_');
73
+ const withPrefix = /^[0-9]/.test(sanitized) ? '_' + sanitized : sanitized;
74
+ return withPrefix.length === 0 ? '_' : withPrefix;
68
75
  }
69
76
 
70
77
  toCamelCase(word: string): string {
@@ -61,7 +61,7 @@ const ServerVariable = z.object({
61
61
  });
62
62
 
63
63
  const Server = z.object({
64
- url: z.string().url(),
64
+ url: z.url(),
65
65
  description: z.string().optional(),
66
66
  variables: z.record(z.string(), ServerVariable).optional(),
67
67
  });
@@ -140,18 +140,18 @@ const Info = z.object({
140
140
  title: z.string().min(1),
141
141
  version: z.string().min(1),
142
142
  description: z.string().optional(),
143
- termsOfService: z.string().url().optional(),
143
+ termsOfService: z.url().optional(),
144
144
  contact: z
145
145
  .object({
146
146
  name: z.string().optional(),
147
- email: z.string().email().optional(),
148
- url: z.string().url().optional(),
147
+ email: z.email().optional(),
148
+ url: z.url().optional(),
149
149
  })
150
150
  .optional(),
151
151
  license: z
152
152
  .object({
153
153
  name: z.string().min(1),
154
- url: z.string().url().optional(),
154
+ url: z.url().optional(),
155
155
  })
156
156
  .optional(),
157
157
  });
@@ -166,7 +166,7 @@ const Tag = z.object({
166
166
 
167
167
  const ExternalDocumentation = z.object({
168
168
  description: z.string().optional(),
169
- url: z.string().url(),
169
+ url: z.url(),
170
170
  });
171
171
 
172
172
  const Components = z.object({
package/tsconfig.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "checkJs": false,
7
7
  "downlevelIteration": true,
8
8
  "esModuleInterop": true,
9
- "exactOptionalPropertyTypes": false,
9
+ "exactOptionalPropertyTypes": true,
10
10
  "forceConsistentCasingInFileNames": true,
11
11
  "incremental": true,
12
12
  "isolatedModules": true,
@@ -19,7 +19,7 @@
19
19
  "noImplicitOverride": true,
20
20
  "noImplicitReturns": true,
21
21
  "noImplicitThis": true,
22
- "noPropertyAccessFromIndexSignature": false,
22
+ "noPropertyAccessFromIndexSignature": true,
23
23
  "noUncheckedIndexedAccess": true,
24
24
  "noUnusedLocals": true,
25
25
  "noUnusedParameters": true,
@@ -37,8 +37,8 @@
37
37
  "target": "ES2022",
38
38
  "typeRoots": ["./node_modules/@types"],
39
39
  "useUnknownInCatchVariables": true,
40
- "verbatimModuleSyntax": false
40
+ "verbatimModuleSyntax": true
41
41
  },
42
42
  "exclude": ["node_modules", "dist", "build"],
43
- "include": ["src/**/*.ts", "generated/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts", "vitest.config.ts"]
43
+ "include": ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts", "vitest.config.ts"]
44
44
  }
@@ -1,31 +0,0 @@
1
- import {readFileSync, writeFileSync} from 'fs';
2
- import {resolve} from 'path';
3
- import {z} from 'zod';
4
- /**
5
- * Type guard for the package.json object
6
- *
7
- * @param input Unknown input
8
- * @returns true if the input is an event object
9
- */
10
- export function isPackageJson(input) {
11
- const event = z
12
- .object({
13
- name: z.string(),
14
- version: z.string(),
15
- description: z.string(),
16
- })
17
- .strict()
18
- .catchall(z.any())
19
- .required();
20
- const {success} = event.safeParse(input);
21
- return success;
22
- }
23
- const sourcePath = resolve(__dirname, '..', 'package.json');
24
- const data = JSON.parse(readFileSync(sourcePath, 'utf8'));
25
- if (!isPackageJson(data)) {
26
- process.exit(1);
27
- }
28
- const {name, version, description} = data;
29
- const targetPath = resolve(__dirname, '..', 'src', 'assets', 'manifest.json');
30
- writeFileSync(targetPath, JSON.stringify({name, version, description}, null, 2));
31
- process.exit(0);