zod-codegen 1.6.3 → 1.7.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 (120) hide show
  1. package/.github/workflows/ci.yml +50 -48
  2. package/.github/workflows/release.yml +13 -3
  3. package/.husky/commit-msg +1 -1
  4. package/.husky/pre-commit +1 -1
  5. package/.lintstagedrc.json +5 -1
  6. package/.nvmrc +1 -1
  7. package/.prettierrc.json +12 -5
  8. package/CHANGELOG.md +17 -0
  9. package/CONTRIBUTING.md +12 -12
  10. package/EXAMPLES.md +135 -57
  11. package/PERFORMANCE.md +4 -4
  12. package/README.md +87 -64
  13. package/SECURITY.md +1 -1
  14. package/dist/src/cli.js +11 -18
  15. package/dist/src/generator.d.ts +2 -2
  16. package/dist/src/generator.d.ts.map +1 -1
  17. package/dist/src/generator.js +5 -3
  18. package/dist/src/interfaces/code-generator.d.ts.map +1 -1
  19. package/dist/src/services/code-generator.service.d.ts +3 -1
  20. package/dist/src/services/code-generator.service.d.ts.map +1 -1
  21. package/dist/src/services/code-generator.service.js +236 -219
  22. package/dist/src/services/file-reader.service.d.ts +2 -0
  23. package/dist/src/services/file-reader.service.d.ts.map +1 -1
  24. package/dist/src/services/file-reader.service.js +25 -11
  25. package/dist/src/services/file-writer.service.d.ts.map +1 -1
  26. package/dist/src/services/file-writer.service.js +2 -2
  27. package/dist/src/services/import-builder.service.d.ts.map +1 -1
  28. package/dist/src/services/import-builder.service.js +3 -3
  29. package/dist/src/services/type-builder.service.d.ts.map +1 -1
  30. package/dist/src/types/generator-options.d.ts.map +1 -1
  31. package/dist/src/types/openapi.d.ts.map +1 -1
  32. package/dist/src/types/openapi.js +20 -20
  33. package/dist/src/utils/error-handler.d.ts.map +1 -1
  34. package/dist/src/utils/naming-convention.d.ts.map +1 -1
  35. package/dist/src/utils/naming-convention.js +6 -3
  36. package/dist/src/utils/signal-handler.d.ts.map +1 -1
  37. package/dist/tests/integration/cli-comprehensive.test.d.ts +2 -0
  38. package/dist/tests/integration/cli-comprehensive.test.d.ts.map +1 -0
  39. package/dist/tests/integration/cli-comprehensive.test.js +123 -0
  40. package/dist/tests/integration/cli.test.d.ts +2 -0
  41. package/dist/tests/integration/cli.test.d.ts.map +1 -0
  42. package/dist/tests/integration/cli.test.js +25 -0
  43. package/dist/tests/integration/error-scenarios.test.d.ts +2 -0
  44. package/dist/tests/integration/error-scenarios.test.d.ts.map +1 -0
  45. package/dist/tests/integration/error-scenarios.test.js +169 -0
  46. package/dist/tests/integration/snapshots.test.d.ts +2 -0
  47. package/dist/tests/integration/snapshots.test.d.ts.map +1 -0
  48. package/dist/tests/integration/snapshots.test.js +100 -0
  49. package/dist/tests/unit/code-generator-edge-cases.test.d.ts +2 -0
  50. package/dist/tests/unit/code-generator-edge-cases.test.d.ts.map +1 -0
  51. package/dist/tests/unit/code-generator-edge-cases.test.js +506 -0
  52. package/dist/tests/unit/code-generator.test.d.ts +2 -0
  53. package/dist/tests/unit/code-generator.test.d.ts.map +1 -0
  54. package/dist/tests/unit/code-generator.test.js +1364 -0
  55. package/dist/tests/unit/file-reader.test.d.ts +2 -0
  56. package/dist/tests/unit/file-reader.test.d.ts.map +1 -0
  57. package/dist/tests/unit/file-reader.test.js +153 -0
  58. package/dist/tests/unit/generator.test.d.ts +2 -0
  59. package/dist/tests/unit/generator.test.d.ts.map +1 -0
  60. package/dist/tests/unit/generator.test.js +119 -0
  61. package/dist/tests/unit/naming-convention.test.d.ts +2 -0
  62. package/dist/tests/unit/naming-convention.test.d.ts.map +1 -0
  63. package/dist/tests/unit/naming-convention.test.js +256 -0
  64. package/dist/tests/unit/reporter.test.d.ts +2 -0
  65. package/dist/tests/unit/reporter.test.d.ts.map +1 -0
  66. package/dist/tests/unit/reporter.test.js +44 -0
  67. package/dist/tests/unit/type-builder.test.d.ts +2 -0
  68. package/dist/tests/unit/type-builder.test.d.ts.map +1 -0
  69. package/dist/tests/unit/type-builder.test.js +108 -0
  70. package/dist/vitest.config.d.ts.map +1 -1
  71. package/dist/vitest.config.js +10 -20
  72. package/eslint.config.mjs +38 -28
  73. package/examples/.gitkeep +1 -1
  74. package/examples/README.md +4 -2
  75. package/examples/petstore/README.md +18 -17
  76. package/examples/petstore/{type.ts → api.ts} +158 -74
  77. package/examples/petstore/authenticated-usage.ts +6 -4
  78. package/examples/petstore/basic-usage.ts +4 -3
  79. package/examples/petstore/error-handling-usage.ts +84 -0
  80. package/examples/petstore/retry-handler-usage.ts +11 -18
  81. package/examples/petstore/server-variables-usage.ts +10 -10
  82. package/examples/pokeapi/README.md +8 -8
  83. package/examples/pokeapi/api.ts +218 -0
  84. package/examples/pokeapi/basic-usage.ts +3 -2
  85. package/examples/pokeapi/custom-client.ts +5 -4
  86. package/package.json +17 -21
  87. package/src/cli.ts +20 -25
  88. package/src/generator.ts +13 -11
  89. package/src/interfaces/code-generator.ts +1 -1
  90. package/src/services/code-generator.service.ts +799 -1120
  91. package/src/services/file-reader.service.ts +35 -15
  92. package/src/services/file-writer.service.ts +7 -7
  93. package/src/services/import-builder.service.ts +9 -13
  94. package/src/services/type-builder.service.ts +8 -19
  95. package/src/types/generator-options.ts +1 -1
  96. package/src/types/openapi.ts +22 -22
  97. package/src/utils/error-handler.ts +2 -2
  98. package/src/utils/naming-convention.ts +13 -10
  99. package/src/utils/reporter.ts +2 -2
  100. package/src/utils/signal-handler.ts +7 -8
  101. package/tests/integration/cli-comprehensive.test.ts +53 -31
  102. package/tests/integration/cli.test.ts +5 -5
  103. package/tests/integration/error-scenarios.test.ts +20 -26
  104. package/tests/integration/snapshots.test.ts +19 -23
  105. package/tests/unit/code-generator-edge-cases.test.ts +133 -133
  106. package/tests/unit/code-generator.test.ts +431 -330
  107. package/tests/unit/file-reader.test.ts +58 -18
  108. package/tests/unit/generator.test.ts +30 -18
  109. package/tests/unit/naming-convention.test.ts +27 -27
  110. package/tests/unit/type-builder.test.ts +2 -2
  111. package/tsconfig.json +5 -3
  112. package/vitest.config.ts +11 -21
  113. package/dist/scripts/update-manifest.d.ts +0 -14
  114. package/dist/scripts/update-manifest.d.ts.map +0 -1
  115. package/dist/scripts/update-manifest.js +0 -33
  116. package/dist/src/assets/manifest.json +0 -5
  117. package/examples/pokeapi/type.ts +0 -109
  118. package/generated/type.ts +0 -371
  119. package/scripts/update-manifest.ts +0 -49
  120. package/src/assets/manifest.json +0 -5
@@ -1,8 +1,7 @@
1
- import {describe, expect, it, vi, beforeEach} from 'vitest';
2
- import {SyncFileReaderService, OpenApiFileParserService} from '../../src/services/file-reader.service';
3
- import {join} from 'node:path';
4
- import {fileURLToPath} from 'node:url';
5
- import {dirname} from 'node:path';
1
+ import { dirname, join } from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
4
+ import { OpenApiFileParserService, SyncFileReaderService } from '../../src/services/file-reader.service';
6
5
 
7
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
7
 
@@ -32,15 +31,15 @@ describe('SyncFileReaderService', () => {
32
31
  });
33
32
 
34
33
  it('should handle URLs', async () => {
35
- // Mock fetch for URL test
36
34
  const originalFetch = global.fetch;
37
35
  global.fetch = vi.fn().mockResolvedValue({
38
36
  ok: true,
39
- text: async () => '{"openapi": "3.0.0", "info": {"title": "Test", "version": "1.0.0"}, "paths": {}}',
37
+ text: async () => '{"openapi": "3.0.0", "info": {"title": "Test", "version": "1.0.0"}, "paths": {}}'
40
38
  } as Response);
41
39
 
42
40
  const content = await reader.readFile('https://example.com/openapi.json');
43
41
  expect(content).toBeTruthy();
42
+ expect(global.fetch).toHaveBeenCalledWith('https://example.com/openapi.json', { headers: {} });
44
43
 
45
44
  global.fetch = originalFetch;
46
45
  });
@@ -50,16 +49,57 @@ describe('SyncFileReaderService', () => {
50
49
  const mockFetch = vi.fn().mockResolvedValue({
51
50
  ok: false,
52
51
  status: 404,
53
- statusText: 'Not Found',
52
+ statusText: 'Not Found'
54
53
  } as Response);
55
54
  global.fetch = mockFetch;
56
55
 
57
- await expect(reader.readFile('https://example.com/not-found.json')).rejects.toThrow();
56
+ await expect(reader.readFile('https://example.com/not-found.json')).rejects.toThrow('Failed to fetch');
58
57
 
59
- // Verify fetch was called
60
- expect(mockFetch).toHaveBeenCalledWith('https://example.com/not-found.json');
61
58
  global.fetch = originalFetch;
62
59
  });
60
+
61
+ it('should propagate network errors for URLs instead of falling back to readFileSync', async () => {
62
+ const originalFetch = global.fetch;
63
+ global.fetch = vi.fn().mockRejectedValue(new TypeError('fetch failed'));
64
+
65
+ await expect(reader.readFile('https://example.com/openapi.json')).rejects.toThrow('fetch failed');
66
+
67
+ global.fetch = originalFetch;
68
+ });
69
+
70
+ it('should extract basic auth credentials from URL into Authorization header', async () => {
71
+ const originalFetch = global.fetch;
72
+ const mockFetch = vi.fn().mockResolvedValue({
73
+ ok: true,
74
+ text: async () => '{}'
75
+ } as Response);
76
+ global.fetch = mockFetch;
77
+
78
+ await reader.readFile('https://user:pass@example.com/openapi.json');
79
+
80
+ expect(mockFetch).toHaveBeenCalledWith('https://example.com/openapi.json', { headers: { Authorization: `Basic ${btoa('user:pass')}` } });
81
+
82
+ global.fetch = originalFetch;
83
+ });
84
+
85
+ it('should decode percent-encoded credentials from URL', async () => {
86
+ const originalFetch = global.fetch;
87
+ const mockFetch = vi.fn().mockResolvedValue({
88
+ ok: true,
89
+ text: async () => '{}'
90
+ } as Response);
91
+ global.fetch = mockFetch;
92
+
93
+ await reader.readFile('https://julien%2Bstaging%40saris.ai:qwerty123@api.staging.saris.ai/api/openapi.json');
94
+
95
+ expect(mockFetch).toHaveBeenCalledWith('https://api.staging.saris.ai/api/openapi.json', { headers: { Authorization: `Basic ${btoa('julien+staging@saris.ai:qwerty123')}` } });
96
+
97
+ global.fetch = originalFetch;
98
+ });
99
+
100
+ it('should not treat non-http schemes as URLs', async () => {
101
+ await expect(reader.readFile('file:///etc/passwd')).rejects.toThrow();
102
+ });
63
103
  });
64
104
  });
65
105
 
@@ -74,8 +114,8 @@ describe('OpenApiFileParserService', () => {
74
114
  it('should parse valid JSON OpenAPI spec', () => {
75
115
  const jsonSpec = JSON.stringify({
76
116
  openapi: '3.0.0',
77
- info: {title: 'Test API', version: '1.0.0'},
78
- paths: {},
117
+ info: { title: 'Test API', version: '1.0.0' },
118
+ paths: {}
79
119
  });
80
120
 
81
121
  const result = parser.parse(jsonSpec);
@@ -102,8 +142,8 @@ paths: {}
102
142
  it('should parse already parsed objects', () => {
103
143
  const spec = {
104
144
  openapi: '3.0.0',
105
- info: {title: 'Test API', version: '1.0.0'},
106
- paths: {},
145
+ info: { title: 'Test API', version: '1.0.0' },
146
+ paths: {}
107
147
  };
108
148
 
109
149
  const result = parser.parse(spec);
@@ -114,8 +154,8 @@ paths: {}
114
154
  it('should validate OpenAPI structure', () => {
115
155
  const invalidSpec = {
116
156
  openapi: '2.0.0', // Wrong version format
117
- info: {title: 'Test API', version: '1.0.0'},
118
- paths: {},
157
+ info: { title: 'Test API', version: '1.0.0' },
158
+ paths: {}
119
159
  };
120
160
 
121
161
  expect(() => parser.parse(invalidSpec)).toThrow();
@@ -125,7 +165,7 @@ paths: {}
125
165
  const invalidSpec = {
126
166
  openapi: '3.0.0',
127
167
  // Missing info
128
- paths: {},
168
+ paths: {}
129
169
  };
130
170
 
131
171
  expect(() => parser.parse(invalidSpec)).toThrow();
@@ -1,10 +1,9 @@
1
- import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
2
- import {Generator} from '../../src/generator';
3
- import {Reporter} from '../../src/utils/reporter';
4
- import {readFileSync, existsSync, mkdirSync, rmSync} from 'node:fs';
5
- import {join} from 'node:path';
6
- import {fileURLToPath} from 'node:url';
7
- import {dirname} from 'node:path';
1
+ import { existsSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
+ import { Generator } from '../../src/generator';
6
+ import { Reporter } from '../../src/utils/reporter';
8
7
 
9
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
10
9
  const testOutputDir = join(__dirname, '../../test-output');
@@ -16,21 +15,22 @@ describe('Generator', () => {
16
15
  beforeEach(() => {
17
16
  // Clean up test output directory
18
17
  if (existsSync(testOutputDir)) {
19
- rmSync(testOutputDir, {recursive: true, force: true});
18
+ rmSync(testOutputDir, { recursive: true, force: true });
20
19
  }
21
- mkdirSync(testOutputDir, {recursive: true});
20
+
21
+ mkdirSync(testOutputDir, { recursive: true });
22
22
 
23
23
  // Create a mock reporter
24
24
  mockReporter = {
25
25
  log: vi.fn(),
26
- error: vi.fn(),
26
+ error: vi.fn()
27
27
  } as unknown as Reporter;
28
28
  });
29
29
 
30
30
  afterEach(() => {
31
31
  // Clean up test output directory
32
32
  if (existsSync(testOutputDir)) {
33
- rmSync(testOutputDir, {recursive: true, force: true});
33
+ rmSync(testOutputDir, { recursive: true, force: true });
34
34
  }
35
35
  });
36
36
 
@@ -62,7 +62,7 @@ describe('Generator', () => {
62
62
  expect(mockReporter.error).not.toHaveBeenCalled();
63
63
 
64
64
  // Verify output file was created
65
- const outputFile = join(testOutputDir, 'type.ts');
65
+ const outputFile = join(testOutputDir, 'api.ts');
66
66
  expect(existsSync(outputFile)).toBe(true);
67
67
 
68
68
  // Verify file contains expected content
@@ -84,9 +84,8 @@ describe('Generator', () => {
84
84
  it('should handle invalid OpenAPI specifications', async () => {
85
85
  // Create a temporary invalid OpenAPI file
86
86
  const invalidFile = join(testOutputDir, 'invalid.yaml');
87
- mkdirSync(testOutputDir, {recursive: true});
88
- readFileSync; // Ensure we can write
89
- const {writeFileSync} = await import('node:fs');
87
+ mkdirSync(testOutputDir, { recursive: true });
88
+ const { writeFileSync } = await import('node:fs');
90
89
  writeFileSync(invalidFile, 'invalid: yaml: content: [unclosed');
91
90
 
92
91
  generator = new Generator('test-app', '1.0.0', mockReporter, invalidFile, testOutputDir);
@@ -102,7 +101,7 @@ describe('Generator', () => {
102
101
 
103
102
  await generator.run();
104
103
 
105
- const outputFile = join(testOutputDir, 'type.ts');
104
+ const outputFile = join(testOutputDir, 'api.ts');
106
105
  const content = readFileSync(outputFile, 'utf-8');
107
106
 
108
107
  // Check for key components
@@ -117,7 +116,7 @@ describe('Generator', () => {
117
116
 
118
117
  await generator.run();
119
118
 
120
- const outputFile = join(testOutputDir, 'type.ts');
119
+ const outputFile = join(testOutputDir, 'api.ts');
121
120
  const content = readFileSync(outputFile, 'utf-8');
122
121
 
123
122
  expect(content).toContain('AUTOGENERATED');
@@ -125,11 +124,24 @@ describe('Generator', () => {
125
124
  expect(content).toContain('eslint-disable');
126
125
  });
127
126
 
127
+ it('should write to custom file path when output is a .ts path', async () => {
128
+ const customPath = join(testOutputDir, 'custom.ts');
129
+ generator = new Generator('test-app', '1.0.0', mockReporter, './samples/swagger-petstore.yaml', customPath);
130
+
131
+ const exitCode = await generator.run();
132
+
133
+ expect(exitCode).toBe(0);
134
+ expect(existsSync(customPath)).toBe(true);
135
+ expect(existsSync(join(testOutputDir, 'api.ts'))).toBe(false);
136
+ const content = readFileSync(customPath, 'utf-8');
137
+ expect(content).toMatch(/import\s*{\s*z\s*}\s*from\s*['"]zod['"]/);
138
+ });
139
+
128
140
  it('should handle unknown error type (not Error instance)', async () => {
129
141
  generator = new Generator('test-app', '1.0.0', mockReporter, './samples/swagger-petstore.yaml', testOutputDir);
130
142
 
131
143
  // Mock the fileReader to throw a non-Error object
132
- const {SyncFileReaderService} = await import('../../src/services/file-reader.service');
144
+ const { SyncFileReaderService } = await import('../../src/services/file-reader.service');
133
145
  const originalReadFile = SyncFileReaderService.prototype.readFile;
134
146
  SyncFileReaderService.prototype.readFile = vi.fn().mockRejectedValue('string error');
135
147
 
@@ -1,38 +1,38 @@
1
- import {describe, expect, it} from 'vitest';
2
- import {transformNamingConvention, type NamingConvention} from '../../src/utils/naming-convention';
1
+ import { describe, expect, it } from 'vitest';
2
+ import { type NamingConvention, transformNamingConvention } from '../../src/utils/naming-convention';
3
3
 
4
4
  describe('transformNamingConvention', () => {
5
5
  describe('transform', () => {
6
- const testCases: Array<{
6
+ const testCases: {
7
7
  input: string;
8
8
  convention: NamingConvention;
9
9
  expected: string;
10
10
  description: string;
11
- }> = [
11
+ }[] = [
12
12
  // camelCase
13
13
  {
14
14
  input: 'get_user_by_id',
15
15
  convention: 'camelCase',
16
16
  expected: 'getUserById',
17
- description: 'should convert snake_case to camelCase',
17
+ description: 'should convert snake_case to camelCase'
18
18
  },
19
19
  {
20
20
  input: 'GetUserById',
21
21
  convention: 'camelCase',
22
22
  expected: 'getUserById',
23
- description: 'should convert PascalCase to camelCase',
23
+ description: 'should convert PascalCase to camelCase'
24
24
  },
25
25
  {
26
26
  input: 'get-user-by-id',
27
27
  convention: 'camelCase',
28
28
  expected: 'getUserById',
29
- description: 'should convert kebab-case to camelCase',
29
+ description: 'should convert kebab-case to camelCase'
30
30
  },
31
31
  {
32
32
  input: 'getUserById',
33
33
  convention: 'camelCase',
34
34
  expected: 'getUserById',
35
- description: 'should keep camelCase as camelCase',
35
+ description: 'should keep camelCase as camelCase'
36
36
  },
37
37
 
38
38
  // PascalCase
@@ -40,19 +40,19 @@ describe('transformNamingConvention', () => {
40
40
  input: 'get_user_by_id',
41
41
  convention: 'PascalCase',
42
42
  expected: 'GetUserById',
43
- description: 'should convert snake_case to PascalCase',
43
+ description: 'should convert snake_case to PascalCase'
44
44
  },
45
45
  {
46
46
  input: 'get-user-by-id',
47
47
  convention: 'PascalCase',
48
48
  expected: 'GetUserById',
49
- description: 'should convert kebab-case to PascalCase',
49
+ description: 'should convert kebab-case to PascalCase'
50
50
  },
51
51
  {
52
52
  input: 'getUserById',
53
53
  convention: 'PascalCase',
54
54
  expected: 'GetUserById',
55
- description: 'should convert camelCase to PascalCase',
55
+ description: 'should convert camelCase to PascalCase'
56
56
  },
57
57
 
58
58
  // snake_case
@@ -60,19 +60,19 @@ describe('transformNamingConvention', () => {
60
60
  input: 'getUserById',
61
61
  convention: 'snake_case',
62
62
  expected: 'get_user_by_id',
63
- description: 'should convert camelCase to snake_case',
63
+ description: 'should convert camelCase to snake_case'
64
64
  },
65
65
  {
66
66
  input: 'GetUserById',
67
67
  convention: 'snake_case',
68
68
  expected: 'get_user_by_id',
69
- description: 'should convert PascalCase to snake_case',
69
+ description: 'should convert PascalCase to snake_case'
70
70
  },
71
71
  {
72
72
  input: 'get-user-by-id',
73
73
  convention: 'snake_case',
74
74
  expected: 'get_user_by_id',
75
- description: 'should convert kebab-case to snake_case',
75
+ description: 'should convert kebab-case to snake_case'
76
76
  },
77
77
 
78
78
  // kebab-case
@@ -80,19 +80,19 @@ describe('transformNamingConvention', () => {
80
80
  input: 'getUserById',
81
81
  convention: 'kebab-case',
82
82
  expected: 'get-user-by-id',
83
- description: 'should convert camelCase to kebab-case',
83
+ description: 'should convert camelCase to kebab-case'
84
84
  },
85
85
  {
86
86
  input: 'GetUserById',
87
87
  convention: 'kebab-case',
88
88
  expected: 'get-user-by-id',
89
- description: 'should convert PascalCase to kebab-case',
89
+ description: 'should convert PascalCase to kebab-case'
90
90
  },
91
91
  {
92
92
  input: 'get_user_by_id',
93
93
  convention: 'kebab-case',
94
94
  expected: 'get-user-by-id',
95
- description: 'should convert snake_case to kebab-case',
95
+ description: 'should convert snake_case to kebab-case'
96
96
  },
97
97
 
98
98
  // SCREAMING_SNAKE_CASE
@@ -100,13 +100,13 @@ describe('transformNamingConvention', () => {
100
100
  input: 'getUserById',
101
101
  convention: 'SCREAMING_SNAKE_CASE',
102
102
  expected: 'GET_USER_BY_ID',
103
- description: 'should convert camelCase to SCREAMING_SNAKE_CASE',
103
+ description: 'should convert camelCase to SCREAMING_SNAKE_CASE'
104
104
  },
105
105
  {
106
106
  input: 'get-user-by-id',
107
107
  convention: 'SCREAMING_SNAKE_CASE',
108
108
  expected: 'GET_USER_BY_ID',
109
- description: 'should convert kebab-case to SCREAMING_SNAKE_CASE',
109
+ description: 'should convert kebab-case to SCREAMING_SNAKE_CASE'
110
110
  },
111
111
 
112
112
  // SCREAMING-KEBAB-CASE
@@ -114,13 +114,13 @@ describe('transformNamingConvention', () => {
114
114
  input: 'getUserById',
115
115
  convention: 'SCREAMING-KEBAB-CASE',
116
116
  expected: 'GET-USER-BY-ID',
117
- description: 'should convert camelCase to SCREAMING-KEBAB-CASE',
117
+ description: 'should convert camelCase to SCREAMING-KEBAB-CASE'
118
118
  },
119
119
  {
120
120
  input: 'get_user_by_id',
121
121
  convention: 'SCREAMING-KEBAB-CASE',
122
122
  expected: 'GET-USER-BY-ID',
123
- description: 'should convert snake_case to SCREAMING-KEBAB-CASE',
123
+ description: 'should convert snake_case to SCREAMING-KEBAB-CASE'
124
124
  },
125
125
 
126
126
  // Edge cases
@@ -128,29 +128,29 @@ describe('transformNamingConvention', () => {
128
128
  input: '',
129
129
  convention: 'camelCase',
130
130
  expected: '',
131
- description: 'should handle empty string',
131
+ description: 'should handle empty string'
132
132
  },
133
133
  {
134
134
  input: 'a',
135
135
  convention: 'camelCase',
136
136
  expected: 'a',
137
- description: 'should handle single character',
137
+ description: 'should handle single character'
138
138
  },
139
139
  {
140
140
  input: 'API',
141
141
  convention: 'camelCase',
142
142
  expected: 'aPI',
143
- description: 'should handle all uppercase (splits at uppercase boundaries)',
143
+ description: 'should handle all uppercase (splits at uppercase boundaries)'
144
144
  },
145
145
  {
146
146
  input: 'getUser123ById',
147
147
  convention: 'snake_case',
148
148
  expected: 'get_user_123_by_id',
149
- description: 'should handle numbers in identifiers (splits at digit boundaries)',
150
- },
149
+ description: 'should handle numbers in identifiers (splits at digit boundaries)'
150
+ }
151
151
  ];
152
152
 
153
- testCases.forEach(({input, convention, expected, description}) => {
153
+ testCases.forEach(({ input, convention, expected, description }) => {
154
154
  it(description, () => {
155
155
  const result = transformNamingConvention(input, convention);
156
156
  expect(result).toBe(expected);
@@ -1,5 +1,5 @@
1
- import {describe, expect, it, beforeEach} from 'vitest';
2
- import {TypeScriptTypeBuilderService} from '../../src/services/type-builder.service';
1
+ import { beforeEach, describe, expect, it } from 'vitest';
2
+ import { TypeScriptTypeBuilderService } from '../../src/services/type-builder.service';
3
3
  import * as ts from 'typescript';
4
4
 
5
5
  describe('TypeScriptTypeBuilderService', () => {
package/tsconfig.json CHANGED
@@ -4,17 +4,19 @@
4
4
  "alwaysStrict": true,
5
5
  "baseUrl": ".",
6
6
  "checkJs": false,
7
+ "declaration": true,
8
+ "declarationMap": true,
7
9
  "downlevelIteration": true,
10
+ "emitDecoratorMetadata": true,
8
11
  "esModuleInterop": true,
9
12
  "exactOptionalPropertyTypes": true,
13
+ "experimentalDecorators": true,
10
14
  "forceConsistentCasingInFileNames": true,
11
15
  "incremental": true,
12
16
  "isolatedModules": true,
13
17
  "lib": ["ES2022", "DOM"],
14
18
  "module": "ESNext",
15
19
  "moduleResolution": "bundler",
16
- "declaration": true,
17
- "declarationMap": true,
18
20
  "noEmit": false,
19
21
  "noFallthroughCasesInSwitch": true,
20
22
  "noImplicitAny": true,
@@ -41,6 +43,6 @@
41
43
  "useUnknownInCatchVariables": true,
42
44
  "verbatimModuleSyntax": false
43
45
  },
44
- "exclude": ["node_modules", "dist", "build", "examples/**/*.ts", "tests/**/*.ts"],
46
+ "exclude": ["node_modules", "dist", "build", "examples"],
45
47
  "include": ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts", "vitest.config.ts"]
46
48
  }
package/vitest.config.ts CHANGED
@@ -1,39 +1,29 @@
1
- import {defineConfig} from 'vitest/config';
2
- import {resolve} from 'node:path';
1
+ import { resolve } from 'node:path';
2
+ import { defineConfig } from 'vitest/config';
3
3
 
4
4
  export default defineConfig({
5
5
  test: {
6
6
  globals: true,
7
7
  environment: 'node',
8
- include: ['**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
8
+ include: ['**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts}'],
9
9
  exclude: ['node_modules', 'dist', 'coverage'],
10
10
  coverage: {
11
11
  provider: 'v8',
12
12
  reporter: ['text', 'json', 'html', 'lcov'],
13
- exclude: [
14
- 'coverage/**',
15
- 'dist/**',
16
- 'node_modules/**',
17
- '**/*.d.ts',
18
- '**/*.config.*',
19
- '**/*.test.*',
20
- '**/*.spec.*',
21
- 'scripts/**',
22
- 'samples/**',
23
- ],
13
+ exclude: ['coverage/**', 'dist/**', 'node_modules/**', '**/*.d.ts', '**/*.config.*', '**/*.test.*', '**/*.spec.*', 'scripts/**', 'samples/**'],
24
14
  thresholds: {
25
15
  global: {
26
16
  branches: 80,
27
17
  functions: 80,
28
18
  lines: 80,
29
- statements: 80,
30
- },
31
- },
32
- },
19
+ statements: 80
20
+ }
21
+ }
22
+ }
33
23
  },
34
24
  resolve: {
35
25
  alias: {
36
- '@': resolve(__dirname, 'src'),
37
- },
38
- },
26
+ '@': resolve(__dirname, 'src')
27
+ }
28
+ }
39
29
  });
@@ -1,14 +0,0 @@
1
- interface PackageJson {
2
- name: string;
3
- version: string;
4
- description: string;
5
- }
6
- /**
7
- * Type guard for the package.json object
8
- *
9
- * @param input Unknown input
10
- * @returns true if the input is an event object
11
- */
12
- export declare function isPackageJson(input: unknown): input is PackageJson;
13
- export {};
14
- //# sourceMappingURL=update-manifest.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"update-manifest.d.ts","sourceRoot":"","sources":["../../scripts/update-manifest.ts"],"names":[],"mappings":"AAKA,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAclE"}
@@ -1,33 +0,0 @@
1
- import { readFileSync, writeFileSync } from 'node:fs';
2
- import { dirname, resolve } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { z } from 'zod';
5
- /**
6
- * Type guard for the package.json object
7
- *
8
- * @param input Unknown input
9
- * @returns true if the input is an event object
10
- */
11
- export function isPackageJson(input) {
12
- const event = z
13
- .object({
14
- name: z.string(),
15
- version: z.string(),
16
- description: z.string(),
17
- })
18
- .strict()
19
- .catchall(z.any())
20
- .required();
21
- const { success } = event.safeParse(input);
22
- return success;
23
- }
24
- const __dirname = dirname(fileURLToPath(import.meta.url));
25
- const sourcePath = resolve(__dirname, '..', 'package.json');
26
- const data = JSON.parse(readFileSync(sourcePath, 'utf8'));
27
- if (!isPackageJson(data)) {
28
- process.exit(1);
29
- }
30
- const { name, version, description } = data;
31
- const targetPath = resolve(__dirname, '..', 'src', 'assets', 'manifest.json');
32
- writeFileSync(targetPath, JSON.stringify({ name, version, description }, null, 2));
33
- process.exit(0);
@@ -1,5 +0,0 @@
1
- {
2
- "name": "zod-codegen",
3
- "version": "1.5.0",
4
- "description": "A powerful TypeScript code generator that creates Zod schemas and type-safe clients from OpenAPI specifications"
5
- }