zod-codegen 1.0.1 → 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 {
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);