zod-codegen 1.3.0 → 1.4.1

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 (75) hide show
  1. package/.github/workflows/ci.yml +17 -17
  2. package/.github/workflows/release.yml +8 -8
  3. package/CHANGELOG.md +17 -0
  4. package/README.md +61 -9
  5. package/dist/src/cli.d.ts +3 -0
  6. package/dist/src/cli.d.ts.map +1 -0
  7. package/dist/src/cli.js +31 -2
  8. package/dist/src/generator.d.ts +23 -0
  9. package/dist/src/generator.d.ts.map +1 -0
  10. package/dist/src/generator.js +3 -2
  11. package/dist/src/http/fetch-client.d.ts +15 -0
  12. package/dist/src/http/fetch-client.d.ts.map +1 -0
  13. package/dist/src/interfaces/code-generator.d.ts +20 -0
  14. package/dist/src/interfaces/code-generator.d.ts.map +1 -0
  15. package/dist/src/interfaces/file-reader.d.ts +13 -0
  16. package/dist/src/interfaces/file-reader.d.ts.map +1 -0
  17. package/dist/src/polyfills/fetch.d.ts +5 -0
  18. package/dist/src/polyfills/fetch.d.ts.map +1 -0
  19. package/dist/src/services/code-generator.service.d.ts +57 -0
  20. package/dist/src/services/code-generator.service.d.ts.map +1 -0
  21. package/dist/src/services/code-generator.service.js +41 -4
  22. package/dist/src/services/file-reader.service.d.ts +9 -0
  23. package/dist/src/services/file-reader.service.d.ts.map +1 -0
  24. package/dist/src/services/file-writer.service.d.ts +10 -0
  25. package/dist/src/services/file-writer.service.d.ts.map +1 -0
  26. package/dist/src/services/import-builder.service.d.ts +14 -0
  27. package/dist/src/services/import-builder.service.d.ts.map +1 -0
  28. package/dist/src/services/type-builder.service.d.ts +12 -0
  29. package/dist/src/services/type-builder.service.d.ts.map +1 -0
  30. package/dist/src/types/generator-options.d.ts +59 -0
  31. package/dist/src/types/generator-options.d.ts.map +1 -0
  32. package/dist/src/types/generator-options.js +1 -0
  33. package/dist/src/types/http.d.ts +25 -0
  34. package/dist/src/types/http.d.ts.map +1 -0
  35. package/dist/src/types/openapi.d.ts +1120 -0
  36. package/dist/src/types/openapi.d.ts.map +1 -0
  37. package/dist/src/utils/error-handler.d.ts +3 -0
  38. package/dist/src/utils/error-handler.d.ts.map +1 -0
  39. package/dist/src/utils/error-handler.js +2 -2
  40. package/dist/src/utils/execution-time.d.ts +2 -0
  41. package/dist/src/utils/execution-time.d.ts.map +1 -0
  42. package/dist/src/utils/manifest.d.ts +8 -0
  43. package/dist/src/utils/manifest.d.ts.map +1 -0
  44. package/dist/src/utils/naming-convention.d.ts +80 -0
  45. package/dist/src/utils/naming-convention.d.ts.map +1 -0
  46. package/dist/src/utils/naming-convention.js +135 -0
  47. package/dist/src/utils/reporter.d.ts +7 -0
  48. package/dist/src/utils/reporter.d.ts.map +1 -0
  49. package/dist/src/utils/signal-handler.d.ts +3 -0
  50. package/dist/src/utils/signal-handler.d.ts.map +1 -0
  51. package/dist/src/utils/signal-handler.js +2 -2
  52. package/dist/src/utils/tty.d.ts +2 -0
  53. package/dist/src/utils/tty.d.ts.map +1 -0
  54. package/dist/vitest.config.d.ts +3 -0
  55. package/dist/vitest.config.d.ts.map +1 -0
  56. package/package.json +15 -15
  57. package/src/cli.ts +34 -3
  58. package/src/generator.ts +8 -1
  59. package/src/services/code-generator.service.ts +51 -8
  60. package/src/types/generator-options.ts +60 -0
  61. package/src/utils/error-handler.ts +2 -2
  62. package/src/utils/naming-convention.ts +214 -0
  63. package/src/utils/signal-handler.ts +2 -2
  64. package/tests/integration/cli.test.ts +2 -2
  65. package/tests/unit/code-generator.test.ts +192 -4
  66. package/tests/unit/generator.test.ts +2 -2
  67. package/tests/unit/naming-convention.test.ts +263 -0
  68. package/tsconfig.json +3 -1
  69. package/.claude/settings.local.json +0 -43
  70. package/dist/scripts/update-manifest.js +0 -31
  71. package/dist/tests/integration/cli.test.js +0 -25
  72. package/dist/tests/unit/code-generator.test.js +0 -290
  73. package/dist/tests/unit/file-reader.test.js +0 -110
  74. package/dist/tests/unit/generator.test.js +0 -100
  75. package/scripts/republish-versions.sh +0 -94
@@ -29,25 +29,25 @@ jobs:
29
29
  uses: actions/setup-node@v5
30
30
  with:
31
31
  node-version: ${{ matrix.node-version }}
32
- cache: 'yarn'
32
+ cache: 'npm'
33
33
 
34
34
  - name: Install dependencies
35
- run: yarn install --frozen-lockfile
35
+ run: npm ci
36
36
 
37
37
  - name: Run type check
38
- run: yarn type-check
38
+ run: npm run type-check
39
39
 
40
40
  - name: Run linter
41
- run: yarn lint:check
41
+ run: npm run lint:check
42
42
 
43
43
  - name: Run formatter check
44
- run: yarn format:check
44
+ run: npm run format:check
45
45
 
46
46
  - name: Build project
47
- run: yarn build
47
+ run: npm run build
48
48
 
49
49
  - name: Run tests
50
- run: yarn test:coverage
50
+ run: npm run test:coverage
51
51
 
52
52
  - name: Upload coverage to Codecov
53
53
  if: matrix.node-version == '24.11.1' && matrix.os == 'ubuntu-latest'
@@ -70,13 +70,13 @@ jobs:
70
70
  uses: actions/setup-node@v5
71
71
  with:
72
72
  node-version: '24.11.1'
73
- cache: 'yarn'
73
+ cache: 'npm'
74
74
 
75
75
  - name: Install dependencies
76
- run: yarn install --frozen-lockfile
76
+ run: npm ci
77
77
 
78
78
  - name: Run security audit
79
- run: yarn audit --level high
79
+ run: npm audit --audit-level=high
80
80
 
81
81
  build:
82
82
  name: Build & Package
@@ -91,13 +91,13 @@ jobs:
91
91
  uses: actions/setup-node@v5
92
92
  with:
93
93
  node-version: '24.11.1'
94
- cache: 'yarn'
94
+ cache: 'npm'
95
95
 
96
96
  - name: Install dependencies
97
- run: yarn install --frozen-lockfile
97
+ run: npm ci
98
98
 
99
99
  - name: Build project
100
- run: yarn build
100
+ run: npm run build
101
101
 
102
102
  - name: Test CLI
103
103
  run: |
@@ -129,15 +129,15 @@ jobs:
129
129
  uses: actions/setup-node@v5
130
130
  with:
131
131
  node-version: '24.11.1'
132
- cache: 'yarn'
132
+ cache: 'npm'
133
133
 
134
134
  - name: Install dependencies
135
- run: yarn install --frozen-lockfile
135
+ run: npm ci
136
136
 
137
137
  - name: Build project
138
- run: yarn build
138
+ run: npm run build
139
139
 
140
140
  - name: Preview semantic-release
141
141
  env:
142
142
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
143
- run: yarn release:dry
143
+ run: npm run release:dry
@@ -29,26 +29,26 @@ jobs:
29
29
  uses: actions/setup-node@v5
30
30
  with:
31
31
  node-version: '24.11.1'
32
- cache: 'yarn'
32
+ cache: 'npm'
33
33
  registry-url: 'https://registry.npmjs.org'
34
34
 
35
35
  - name: Install dependencies
36
- run: yarn install --frozen-lockfile
36
+ run: npm ci
37
37
 
38
38
  - name: Run type check
39
- run: yarn type-check
39
+ run: npm run type-check
40
40
 
41
41
  - name: Run linter check
42
- run: yarn lint:check
42
+ run: npm run lint:check
43
43
 
44
44
  - name: Run formatter check
45
- run: yarn format:check
45
+ run: npm run format:check
46
46
 
47
47
  - name: Run tests with coverage
48
- run: yarn test:coverage
48
+ run: npm run test:coverage
49
49
 
50
50
  - name: Build project
51
- run: yarn build
51
+ run: npm run build
52
52
 
53
53
  - name: Test CLI functionality
54
54
  run: |
@@ -62,4 +62,4 @@ jobs:
62
62
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
63
63
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
64
64
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
65
- run: yarn release
65
+ run: npm run release
package/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## <small>1.4.1 (2025-12-08)</small>
2
+
3
+ - Merge branch 'refactor/build-config-and-class-exports' of github.com:julienandreu/zod-codegen into r ([bdd9bc5](https://github.com/julienandreu/zod-codegen/commit/bdd9bc5))
4
+ - Merge pull request #41 from julienandreu/dependabot/npm_and_yarn/tar-7.5.2 ([192cd47](https://github.com/julienandreu/zod-codegen/commit/192cd47)), closes [#41](https://github.com/julienandreu/zod-codegen/issues/41)
5
+ - Merge pull request #43 from julienandreu/refactor/build-config-and-class-exports ([61de21b](https://github.com/julienandreu/zod-codegen/commit/61de21b)), closes [#43](https://github.com/julienandreu/zod-codegen/issues/43)
6
+ - refactor: improve build configuration and class exports ([060f714](https://github.com/julienandreu/zod-codegen/commit/060f714))
7
+ - refactor: improve build configuration and class exports ([b8771ad](https://github.com/julienandreu/zod-codegen/commit/b8771ad))
8
+ - refactor: remove tsconfig.build.json and use tsconfig.json directly ([407c46a](https://github.com/julienandreu/zod-codegen/commit/407c46a))
9
+ - chore: restore yarn.lock for yarn 4 with corepack ([a93f018](https://github.com/julienandreu/zod-codegen/commit/a93f018))
10
+ - chore(deps): bump tar from 7.5.1 to 7.5.2 ([b867dce](https://github.com/julienandreu/zod-codegen/commit/b867dce))
11
+
12
+ ## 1.4.0 (2025-12-01)
13
+
14
+ - Merge pull request #40 from julienandreu/feat/naming-conventions-and-improvements ([d7c8146](https://github.com/julienandreu/zod-codegen/commit/d7c8146)), closes [#40](https://github.com/julienandreu/zod-codegen/issues/40)
15
+ - feat: add naming convention support and code quality improvements ([3ec8824](https://github.com/julienandreu/zod-codegen/commit/3ec8824))
16
+ - feat: add naming convention support for operation IDs ([0a52f14](https://github.com/julienandreu/zod-codegen/commit/0a52f14))
17
+
1
18
  ## 1.3.0 (2025-11-24)
2
19
 
3
20
  - Merge pull request #36 from julienandreu/dependabot/npm_and_yarn/dev-dependencies-16beb30ed0 ([3d85de4](https://github.com/julienandreu/zod-codegen/commit/3d85de4)), closes [#36](https://github.com/julienandreu/zod-codegen/issues/36)
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # zod-codegen
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/zod-codegen.svg)](https://www.npmjs.com/package/zod-codegen)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
6
6
  [![CI](https://github.com/julienandreu/zod-codegen/workflows/CI/badge.svg)](https://github.com/julienandreu/zod-codegen/actions)
7
7
  [![Coverage](https://img.shields.io/codecov/c/github/julienandreu/zod-codegen)](https://codecov.io/gh/julienandreu/zod-codegen)
@@ -54,17 +54,42 @@ zod-codegen -i ./swagger.yaml -o ./src/generated
54
54
 
55
55
  #### CLI Options
56
56
 
57
- | Option | Alias | Description | Default |
58
- | ----------- | ----- | ----------------------------------- | ----------- |
59
- | `--input` | `-i` | Path or URL to OpenAPI file | Required |
60
- | `--output` | `-o` | Directory to output generated files | `generated` |
61
- | `--help` | `-h` | Show help | |
62
- | `--version` | `-v` | Show version | |
57
+ | Option | Alias | Description | Default |
58
+ | --------------------- | ----- | ----------------------------------- | ----------- |
59
+ | `--input` | `-i` | Path or URL to OpenAPI file | Required |
60
+ | `--output` | `-o` | Directory to output generated files | `generated` |
61
+ | `--naming-convention` | `-n` | Naming convention for operation IDs | (none) |
62
+ | `--help` | `-h` | Show help | |
63
+ | `--version` | `-v` | Show version | |
64
+
65
+ #### Naming Conventions
66
+
67
+ The `--naming-convention` option allows you to transform operation IDs according to common naming conventions. Supported conventions:
68
+
69
+ - `camelCase` - e.g., `getUserById`
70
+ - `PascalCase` - e.g., `GetUserById`
71
+ - `snake_case` - e.g., `get_user_by_id`
72
+ - `kebab-case` - e.g., `get-user-by-id`
73
+ - `SCREAMING_SNAKE_CASE` - e.g., `GET_USER_BY_ID`
74
+ - `SCREAMING-KEBAB-CASE` - e.g., `GET-USER-BY-ID`
75
+
76
+ **Example:**
77
+
78
+ ```bash
79
+ # Transform operation IDs to camelCase
80
+ zod-codegen --input ./openapi.json --output ./generated --naming-convention camelCase
81
+
82
+ # Transform operation IDs to snake_case
83
+ zod-codegen -i ./openapi.json -o ./generated -n snake_case
84
+ ```
85
+
86
+ This is particularly useful when OpenAPI specs have inconsistent or poorly named operation IDs.
63
87
 
64
88
  ### Programmatic Usage
65
89
 
66
90
  ```typescript
67
91
  import {Generator} from 'zod-codegen';
92
+ import type {GeneratorOptions} from 'zod-codegen';
68
93
 
69
94
  // Create a simple reporter object
70
95
  const reporter = {
@@ -72,19 +97,46 @@ const reporter = {
72
97
  error: (...args: unknown[]) => console.error(...args),
73
98
  };
74
99
 
75
- // Create generator instance
100
+ // Create generator instance with naming convention
76
101
  const generator = new Generator(
77
102
  'my-app',
78
103
  '1.0.0',
79
104
  reporter,
80
105
  './openapi.json', // Input path or URL
81
106
  './generated', // Output directory
107
+ {
108
+ namingConvention: 'camelCase', // Transform operation IDs to camelCase
109
+ },
82
110
  );
83
111
 
84
112
  // Run the generator
85
113
  const exitCode = await generator.run();
86
114
  ```
87
115
 
116
+ #### Custom Operation Name Transformer
117
+
118
+ For more advanced use cases, you can provide a custom transformer function that receives full operation details:
119
+
120
+ ```typescript
121
+ import {Generator} from 'zod-codegen';
122
+ import type {GeneratorOptions, OperationDetails} from 'zod-codegen';
123
+
124
+ const customTransformer: GeneratorOptions['operationNameTransformer'] = (details: OperationDetails) => {
125
+ // details includes: operationId, method, path, tags, summary, description
126
+ const {operationId, method, tags} = details;
127
+
128
+ // Example: Prefix with HTTP method and tag
129
+ const tag = tags?.[0] || 'default';
130
+ return `${method.toUpperCase()}_${tag}_${operationId}`;
131
+ };
132
+
133
+ const generator = new Generator('my-app', '1.0.0', reporter, './openapi.json', './generated', {
134
+ operationNameTransformer: customTransformer,
135
+ });
136
+ ```
137
+
138
+ **Note:** Custom transformers take precedence over naming conventions if both are provided.
139
+
88
140
  ## 📁 Generated Output
89
141
 
90
142
  The generator creates a single TypeScript file (`type.ts`) containing:
@@ -458,7 +510,7 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
458
510
 
459
511
  ## 📝 License
460
512
 
461
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
513
+ This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENCE) file for details.
462
514
 
463
515
  ## 🙏 Acknowledgments
464
516
 
@@ -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":""}
package/dist/src/cli.js CHANGED
@@ -58,14 +58,43 @@ const argv = yargs(hideBin(process.argv))
58
58
  type: 'string',
59
59
  description: 'Directory to output the generated files',
60
60
  default: 'generated',
61
+ })
62
+ .option('naming-convention', {
63
+ alias: 'n',
64
+ type: 'string',
65
+ description: 'Naming convention to apply to operation IDs',
66
+ choices: ['camelCase', 'PascalCase', 'snake_case', 'kebab-case', 'SCREAMING_SNAKE_CASE', 'SCREAMING-KEBAB-CASE'],
67
+ default: undefined,
61
68
  })
62
69
  .strict()
63
70
  .help()
64
71
  .parseSync();
65
- const { input, output } = argv;
72
+ const { input, output, namingConvention } = argv;
73
+ /**
74
+ * Type guard to validate that a string is a valid naming convention.
75
+ * This ensures type safety when parsing CLI arguments.
76
+ *
77
+ * @param value - The value to check
78
+ * @returns True if the value is a valid NamingConvention
79
+ */
80
+ function isValidNamingConvention(value) {
81
+ if (value === undefined) {
82
+ return false;
83
+ }
84
+ const validConventions = [
85
+ 'camelCase',
86
+ 'PascalCase',
87
+ 'snake_case',
88
+ 'kebab-case',
89
+ 'SCREAMING_SNAKE_CASE',
90
+ 'SCREAMING-KEBAB-CASE',
91
+ ];
92
+ return validConventions.includes(value);
93
+ }
66
94
  void (async () => {
67
95
  try {
68
- const generator = new Generator(name, version, reporter, input, output);
96
+ const options = isValidNamingConvention(namingConvention) ? { namingConvention } : {};
97
+ const generator = new Generator(name, version, reporter, input, output, options);
69
98
  const exitCode = await generator.run();
70
99
  process.exit(exitCode);
71
100
  }
@@ -0,0 +1,23 @@
1
+ import type { Reporter } from './utils/reporter.js';
2
+ import type { GeneratorOptions } from './types/generator-options.js';
3
+ export type { GeneratorOptions } from './types/generator-options.js';
4
+ export type { NamingConvention, OperationDetails, OperationNameTransformer } from './utils/naming-convention.js';
5
+ export declare class Generator {
6
+ private readonly _name;
7
+ private readonly _version;
8
+ private readonly reporter;
9
+ private readonly inputPath;
10
+ private readonly _outputDir;
11
+ private readonly fileReader;
12
+ private readonly fileParser;
13
+ private readonly codeGenerator;
14
+ private readonly fileWriter;
15
+ private readonly outputPath;
16
+ constructor(_name: string, _version: string, reporter: Reporter, inputPath: string, _outputDir: string, options?: GeneratorOptions);
17
+ run(): Promise<number>;
18
+ private readFile;
19
+ private parseFile;
20
+ private generateCode;
21
+ private writeFile;
22
+ }
23
+ //# sourceMappingURL=generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,qBAAqB,CAAC;AAElD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,8BAA8B,CAAC;AAMnE,YAAY,EAAC,gBAAgB,EAAC,MAAM,8BAA8B,CAAC;AACnE,YAAY,EAAC,gBAAgB,EAAE,gBAAgB,EAAE,wBAAwB,EAAC,MAAM,8BAA8B,CAAC;AAE/G,qBAAa,SAAS;IAQlB,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAX7B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;IAC1D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;IAC7D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAiC;IAC/D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAwB;IACnD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAGjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EACnC,OAAO,GAAE,gBAAqB;IAO1B,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;YAqBd,QAAQ;IAItB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,SAAS;CAGlB"}
@@ -9,10 +9,10 @@ export class Generator {
9
9
  _outputDir;
10
10
  fileReader = new SyncFileReaderService();
11
11
  fileParser = new OpenApiFileParserService();
12
- codeGenerator = new TypeScriptCodeGeneratorService();
12
+ codeGenerator;
13
13
  fileWriter;
14
14
  outputPath;
15
- constructor(_name, _version, reporter, inputPath, _outputDir) {
15
+ constructor(_name, _version, reporter, inputPath, _outputDir, options = {}) {
16
16
  this._name = _name;
17
17
  this._version = _version;
18
18
  this.reporter = reporter;
@@ -20,6 +20,7 @@ export class Generator {
20
20
  this._outputDir = _outputDir;
21
21
  this.fileWriter = new SyncFileWriterService(this._name, this._version, inputPath);
22
22
  this.outputPath = this.fileWriter.resolveOutputPath(this._outputDir);
23
+ this.codeGenerator = new TypeScriptCodeGeneratorService(options);
23
24
  }
24
25
  async run() {
25
26
  try {
@@ -0,0 +1,15 @@
1
+ import type { HttpClient, HttpRequestConfig, HttpResponse } from '../types/http.js';
2
+ export declare class FetchHttpClient implements HttpClient {
3
+ private readonly baseUrl;
4
+ private readonly defaultHeaders;
5
+ private readonly fetch;
6
+ private readonly Headers;
7
+ constructor(baseUrl?: string, defaultHeaders?: Record<string, string>);
8
+ request<TResponse = unknown, TRequest = unknown>(config: HttpRequestConfig<TRequest>): Promise<HttpResponse<TResponse>>;
9
+ private buildUrl;
10
+ private buildHeaders;
11
+ private buildBody;
12
+ private extractHeaders;
13
+ private parseResponse;
14
+ }
15
+ //# sourceMappingURL=fetch-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-client.d.ts","sourceRoot":"","sources":["../../../src/http/fetch-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAE,iBAAiB,EAAE,YAAY,EAAC,MAAM,kBAAkB,CAAC;AAclF,qBAAa,eAAgB,YAAW,UAAU;IAK9C,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,cAAc;IALjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAG1B,OAAO,SAAK,EACZ,cAAc,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM;IAoBxD,OAAO,CAAC,SAAS,GAAG,OAAO,EAAE,QAAQ,GAAG,OAAO,EACnD,MAAM,EAAE,iBAAiB,CAAC,QAAQ,CAAC,GAClC,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;IA4DnC,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,SAAS;IAqBjB,OAAO,CAAC,cAAc;YAQR,aAAa;CAkB5B"}
@@ -0,0 +1,20 @@
1
+ import type { OpenApiSpecType } from '../types/openapi.js';
2
+ export interface CodeGenerator {
3
+ generate(spec: OpenApiSpecType): string;
4
+ }
5
+ export interface SchemaBuilder {
6
+ buildSchema(schema: unknown, required?: boolean): unknown;
7
+ }
8
+ export interface TypeBuilder {
9
+ buildType(type: string): unknown;
10
+ }
11
+ export interface ImportBuilder {
12
+ buildImports(): unknown[];
13
+ }
14
+ export interface ClassBuilder {
15
+ buildClass(spec: OpenApiSpecType): unknown;
16
+ }
17
+ export interface FileWriter {
18
+ writeFile(filePath: string, content: string): Promise<void> | void;
19
+ }
20
+ //# sourceMappingURL=code-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-generator.d.ts","sourceRoot":"","sources":["../../../src/interfaces/code-generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAAC;CACzC;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CAC3D;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,aAAa;IAC5B,YAAY,IAAI,OAAO,EAAE,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC;CAC5C;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACpE"}
@@ -0,0 +1,13 @@
1
+ export interface FileReader {
2
+ readFile(path: string): Promise<string> | string;
3
+ }
4
+ export interface FileParser<TInput, TOutput> {
5
+ parse(input: TInput): TOutput;
6
+ }
7
+ export interface OpenApiFileReader extends FileReader {
8
+ readFile(path: string): Promise<string> | string;
9
+ }
10
+ export interface OpenApiFileParser<TOutput> extends FileParser<unknown, TOutput> {
11
+ parse(input: unknown): TOutput;
12
+ }
13
+ //# sourceMappingURL=file-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-reader.d.ts","sourceRoot":"","sources":["../../../src/interfaces/file-reader.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAClD;AAED,MAAM,WAAW,UAAU,CAAC,MAAM,EAAE,OAAO;IACzC,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAClD;AAED,MAAM,WAAW,iBAAiB,CAAC,OAAO,CAAE,SAAQ,UAAU,CAAC,OAAO,EAAE,OAAO,CAAC;IAC9E,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CAChC"}
@@ -0,0 +1,5 @@
1
+ export interface FetchPolyfillOptions {
2
+ enableNodejsPolyfill?: boolean;
3
+ }
4
+ export declare function setupFetchPolyfill(options?: FetchPolyfillOptions): Promise<void>;
5
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../../../src/polyfills/fetch.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,oBAAoB;IACnC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB1F"}
@@ -0,0 +1,57 @@
1
+ import * as ts from 'typescript';
2
+ import type { CodeGenerator, SchemaBuilder } from '../interfaces/code-generator.js';
3
+ import type { OpenApiSpecType } from '../types/openapi.js';
4
+ import type { GeneratorOptions } from '../types/generator-options.js';
5
+ export declare class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuilder {
6
+ private readonly typeBuilder;
7
+ private readonly importBuilder;
8
+ private readonly printer;
9
+ private readonly namingConvention;
10
+ private readonly operationNameTransformer;
11
+ constructor(options?: GeneratorOptions);
12
+ private readonly ZodAST;
13
+ generate(spec: OpenApiSpecType): string;
14
+ buildSchema(schema: unknown, required?: boolean): ts.CallExpression | ts.Identifier;
15
+ private buildAST;
16
+ private buildSchemas;
17
+ private buildSchemaTypeAliases;
18
+ private buildClientClass;
19
+ private buildConstructor;
20
+ private buildGetBaseRequestOptionsMethod;
21
+ private buildHttpRequestMethod;
22
+ private buildClientMethods;
23
+ /**
24
+ * Transforms operation ID according to the configured naming convention or transformer
25
+ * Ensures the result is a valid TypeScript identifier
26
+ */
27
+ private transformOperationName;
28
+ private buildEndpointMethod;
29
+ private buildPathExpression;
30
+ private buildMethodParameters;
31
+ private getParameterType;
32
+ private getSchemaTypeName;
33
+ private getResponseSchema;
34
+ private getResponseType;
35
+ private buildServerConfiguration;
36
+ private resolveServerUrl;
37
+ private buildResolveServerUrlFunction;
38
+ private generateClientName;
39
+ private createComment;
40
+ /**
41
+ * Builds a JSDoc comment string from operation metadata
42
+ */
43
+ private buildJSDocComment;
44
+ private buildZodAST;
45
+ private buildProperty;
46
+ private buildDefaultValue;
47
+ private handleLogicalOperator;
48
+ private buildLogicalOperator;
49
+ private buildSchemaFromLogicalOperator;
50
+ private buildBasicTypeFromSchema;
51
+ private buildObjectTypeFromSchema;
52
+ private buildArrayTypeFromSchema;
53
+ private isReference;
54
+ private buildFromReference;
55
+ private topologicalSort;
56
+ }
57
+ //# sourceMappingURL=code-generator.service.d.ts.map
@@ -0,0 +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,iCAAiC,CAAC;AAClF,OAAO,KAAK,EAAmB,eAAe,EAAgB,MAAM,qBAAqB,CAAC;AAC1F,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,+BAA+B,CAAC;AAWpE,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;gBAEpE,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;IAmBhB,OAAO,CAAC,YAAY;IA8BpB,OAAO,CAAC,sBAAsB;IAe9B,OAAO,CAAC,gBAAgB;IAsBxB,OAAO,CAAC,gBAAgB;IAmGxB,OAAO,CAAC,gCAAgC;IAwBxC,OAAO,CAAC,sBAAsB;IAqmB9B,OAAO,CAAC,kBAAkB;IAsB1B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IA0B9B,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;IAM1B,OAAO,CAAC,eAAe;CAuCxB"}
@@ -4,10 +4,17 @@ import { z } from 'zod';
4
4
  import { MethodSchema, Reference, SchemaProperties } from '../types/openapi.js';
5
5
  import { TypeScriptImportBuilderService } from './import-builder.service.js';
6
6
  import { TypeScriptTypeBuilderService } from './type-builder.service.js';
7
+ import { transformNamingConvention, } from '../utils/naming-convention.js';
7
8
  export class TypeScriptCodeGeneratorService {
8
9
  typeBuilder = new TypeScriptTypeBuilderService();
9
10
  importBuilder = new TypeScriptImportBuilderService();
10
11
  printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
12
+ namingConvention;
13
+ operationNameTransformer;
14
+ constructor(options = {}) {
15
+ this.namingConvention = options.namingConvention;
16
+ this.operationNameTransformer = options.operationNameTransformer;
17
+ }
11
18
  ZodAST = z.object({
12
19
  type: z.enum(['string', 'number', 'boolean', 'object', 'array', 'unknown', 'record']),
13
20
  args: z.array(z.unknown()).optional(),
@@ -79,7 +86,7 @@ export class TypeScriptCodeGeneratorService {
79
86
  buildClientClass(openapi, schemas) {
80
87
  const clientName = this.generateClientName(openapi.info.title);
81
88
  const methods = this.buildClientMethods(openapi, schemas);
82
- return ts.factory.createClassDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword)], ts.factory.createIdentifier(clientName), undefined, undefined, [
89
+ return ts.factory.createClassDeclaration([ts.factory.createToken(ts.SyntaxKind.ExportKeyword), ts.factory.createToken(ts.SyntaxKind.DefaultKeyword)], ts.factory.createIdentifier(clientName), undefined, undefined, [
83
90
  this.typeBuilder.createProperty('#baseUrl', 'string', true),
84
91
  this.buildConstructor(openapi),
85
92
  this.buildGetBaseRequestOptionsMethod(),
@@ -125,7 +132,7 @@ export class TypeScriptCodeGeneratorService {
125
132
  ]), ts.factory.createBlock([ts.factory.createReturnStatement(ts.factory.createObjectLiteralExpression([], false))], true));
126
133
  }
127
134
  buildHttpRequestMethod() {
128
- return ts.factory.createMethodDeclaration([ts.factory.createToken(ts.SyntaxKind.AsyncKeyword)], undefined, ts.factory.createPrivateIdentifier('#makeRequest'), undefined, [this.typeBuilder.createGenericType('T')], [
135
+ return ts.factory.createMethodDeclaration([ts.factory.createToken(ts.SyntaxKind.ProtectedKeyword), ts.factory.createToken(ts.SyntaxKind.AsyncKeyword)], undefined, ts.factory.createIdentifier('makeRequest'), undefined, [this.typeBuilder.createGenericType('T')], [
129
136
  this.typeBuilder.createParameter('method', 'string'),
130
137
  this.typeBuilder.createParameter('path', 'string'),
131
138
  this.typeBuilder.createParameter('options', '{params?: Record<string, string | number | boolean>; data?: unknown; contentType?: string; headers?: Record<string, string>}', ts.factory.createObjectLiteralExpression([], false), false),
@@ -263,6 +270,35 @@ export class TypeScriptCodeGeneratorService {
263
270
  return [...endpoints, ...methods];
264
271
  }, []);
265
272
  }
273
+ /**
274
+ * Transforms operation ID according to the configured naming convention or transformer
275
+ * Ensures the result is a valid TypeScript identifier
276
+ */
277
+ transformOperationName(operationId, method, path, schema) {
278
+ let transformed;
279
+ // Custom transformer takes precedence
280
+ if (this.operationNameTransformer) {
281
+ const details = {
282
+ operationId,
283
+ method,
284
+ path,
285
+ ...(schema.tags !== undefined && { tags: schema.tags }),
286
+ ...(schema.summary !== undefined && { summary: schema.summary }),
287
+ ...(schema.description !== undefined && { description: schema.description }),
288
+ };
289
+ transformed = this.operationNameTransformer(details);
290
+ }
291
+ else if (this.namingConvention) {
292
+ // Apply naming convention if specified
293
+ transformed = transformNamingConvention(operationId, this.namingConvention);
294
+ }
295
+ else {
296
+ // Return original operationId if no transformation is configured
297
+ transformed = operationId;
298
+ }
299
+ // Sanitize to ensure valid TypeScript identifier (handles edge cases from custom transformers)
300
+ return this.typeBuilder.sanitizeIdentifier(transformed);
301
+ }
266
302
  buildEndpointMethod(method, path, schema, schemas) {
267
303
  const { parameters, pathParams, queryParams, hasRequestBody, contentType } = this.buildMethodParameters(schema, schemas);
268
304
  const responseType = this.getResponseType(schema, schemas);
@@ -295,7 +331,7 @@ export class TypeScriptCodeGeneratorService {
295
331
  }
296
332
  const optionsExpression = ts.factory.createObjectLiteralExpression(optionsProps, false);
297
333
  // Call makeRequest
298
- const makeRequestCall = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createPrivateIdentifier('#makeRequest')), undefined, [ts.factory.createStringLiteral(method.toUpperCase(), true), pathExpression, optionsExpression]);
334
+ const makeRequestCall = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(ts.factory.createThis(), ts.factory.createIdentifier('makeRequest')), undefined, [ts.factory.createStringLiteral(method.toUpperCase(), true), pathExpression, optionsExpression]);
299
335
  // Add Zod validation if we have a response schema
300
336
  if (responseSchema) {
301
337
  const validateCall = ts.factory.createCallExpression(ts.factory.createPropertyAccessExpression(responseSchema, ts.factory.createIdentifier('parse')), undefined, [ts.factory.createAwaitExpression(makeRequestCall)]);
@@ -304,7 +340,8 @@ export class TypeScriptCodeGeneratorService {
304
340
  else {
305
341
  statements.push(ts.factory.createReturnStatement(ts.factory.createAwaitExpression(makeRequestCall)));
306
342
  }
307
- const methodDeclaration = ts.factory.createMethodDeclaration([ts.factory.createToken(ts.SyntaxKind.AsyncKeyword)], undefined, ts.factory.createIdentifier(String(schema.operationId)), undefined, undefined, parameters, responseType, ts.factory.createBlock(statements, true));
343
+ const transformedOperationId = this.transformOperationName(String(schema.operationId), method, path, schema);
344
+ const methodDeclaration = ts.factory.createMethodDeclaration([ts.factory.createToken(ts.SyntaxKind.AsyncKeyword)], undefined, ts.factory.createIdentifier(transformedOperationId), undefined, undefined, parameters, responseType, ts.factory.createBlock(statements, true));
308
345
  // Add JSDoc comment if summary or description exists
309
346
  const jsdocComment = this.buildJSDocComment(schema.summary, schema.description, schema, responseType);
310
347
  if (jsdocComment) {
@@ -0,0 +1,9 @@
1
+ import type { OpenApiFileParser, OpenApiFileReader } from '../interfaces/file-reader.js';
2
+ import type { OpenApiSpecType } from '../types/openapi.js';
3
+ export declare class SyncFileReaderService implements OpenApiFileReader {
4
+ readFile(path: string): Promise<string>;
5
+ }
6
+ export declare class OpenApiFileParserService implements OpenApiFileParser<OpenApiSpecType> {
7
+ parse(input: unknown): OpenApiSpecType;
8
+ }
9
+ //# sourceMappingURL=file-reader.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-reader.service.d.ts","sourceRoot":"","sources":["../../../src/services/file-reader.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,iBAAiB,EAAE,iBAAiB,EAAC,MAAM,8BAA8B,CAAC;AACvF,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,qBAAqB,CAAC;AAGzD,qBAAa,qBAAsB,YAAW,iBAAiB;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAe9C;AAED,qBAAa,wBAAyB,YAAW,iBAAiB,CAAC,eAAe,CAAC;IACjF,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe;CAgBvC"}
@@ -0,0 +1,10 @@
1
+ import type { FileWriter } from '../interfaces/code-generator.js';
2
+ export declare class SyncFileWriterService implements FileWriter {
3
+ private readonly name;
4
+ private readonly version;
5
+ private readonly inputPath;
6
+ constructor(name: string, version: string, inputPath: string);
7
+ writeFile(filePath: string, content: string): void;
8
+ resolveOutputPath(outputDir: string, fileName?: string): string;
9
+ }
10
+ //# sourceMappingURL=file-writer.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-writer.service.d.ts","sourceRoot":"","sources":["../../../src/services/file-writer.service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,iCAAiC,CAAC;AAEhE,qBAAa,qBAAsB,YAAW,UAAU;IAEpD,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFT,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM;IAGpC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAqBlD,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,SAAY,GAAG,MAAM;CAGnE"}
@@ -0,0 +1,14 @@
1
+ import * as ts from 'typescript';
2
+ import { z } from 'zod';
3
+ import type { ImportBuilder } from '../interfaces/code-generator.js';
4
+ declare const ImportOptions: z.ZodObject<{
5
+ defaultImport: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
6
+ namedImports: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
7
+ }, z.core.$strip>;
8
+ type ImportOptionsType = z.infer<typeof ImportOptions>;
9
+ export declare class TypeScriptImportBuilderService implements ImportBuilder {
10
+ buildImports(): ts.ImportDeclaration[];
11
+ createImport(target: string, options: ImportOptionsType): ts.ImportDeclaration;
12
+ }
13
+ export {};
14
+ //# sourceMappingURL=import-builder.service.d.ts.map