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
@@ -1,110 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach } from 'vitest';
2
- import { SyncFileReaderService, OpenApiFileParserService } from '../../src/services/file-reader.service.js';
3
- import { join } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { dirname } from 'node:path';
6
- const __dirname = dirname(fileURLToPath(import.meta.url));
7
- describe('SyncFileReaderService', () => {
8
- let reader;
9
- beforeEach(() => {
10
- reader = new SyncFileReaderService();
11
- });
12
- describe('readFile', () => {
13
- it('should read local JSON files', async () => {
14
- const content = await reader.readFile(join(__dirname, '../../samples/openapi.json'));
15
- expect(content).toBeTruthy();
16
- expect(typeof content).toBe('string');
17
- });
18
- it('should read local YAML files', async () => {
19
- const content = await reader.readFile(join(__dirname, '../../samples/swagger-petstore.yaml'));
20
- expect(content).toBeTruthy();
21
- expect(typeof content).toBe('string');
22
- expect(content).toContain('openapi:');
23
- });
24
- it('should handle non-existent files', async () => {
25
- await expect(reader.readFile('./non-existent-file.json')).rejects.toThrow();
26
- });
27
- it('should handle URLs', async () => {
28
- // Mock fetch for URL test
29
- const originalFetch = global.fetch;
30
- global.fetch = vi.fn().mockResolvedValue({
31
- ok: true,
32
- text: async () => '{"openapi": "3.0.0", "info": {"title": "Test", "version": "1.0.0"}, "paths": {}}',
33
- });
34
- const content = await reader.readFile('https://example.com/openapi.json');
35
- expect(content).toBeTruthy();
36
- global.fetch = originalFetch;
37
- });
38
- it('should handle URL fetch errors with non-ok responses', async () => {
39
- const originalFetch = global.fetch;
40
- const mockFetch = vi.fn().mockResolvedValue({
41
- ok: false,
42
- status: 404,
43
- statusText: 'Not Found',
44
- });
45
- global.fetch = mockFetch;
46
- await expect(reader.readFile('https://example.com/not-found.json')).rejects.toThrow();
47
- // Verify fetch was called
48
- expect(mockFetch).toHaveBeenCalledWith('https://example.com/not-found.json');
49
- global.fetch = originalFetch;
50
- });
51
- });
52
- });
53
- describe('OpenApiFileParserService', () => {
54
- let parser;
55
- beforeEach(() => {
56
- parser = new OpenApiFileParserService();
57
- });
58
- describe('parse', () => {
59
- it('should parse valid JSON OpenAPI spec', () => {
60
- const jsonSpec = JSON.stringify({
61
- openapi: '3.0.0',
62
- info: { title: 'Test API', version: '1.0.0' },
63
- paths: {},
64
- });
65
- const result = parser.parse(jsonSpec);
66
- expect(result).toBeDefined();
67
- expect(result.openapi).toBe('3.0.0');
68
- expect(result.info.title).toBe('Test API');
69
- });
70
- it('should parse valid YAML OpenAPI spec', () => {
71
- const yamlSpec = `
72
- openapi: 3.0.0
73
- info:
74
- title: Test API
75
- version: 1.0.0
76
- paths: {}
77
- `;
78
- const result = parser.parse(yamlSpec);
79
- expect(result).toBeDefined();
80
- expect(result.openapi).toBe('3.0.0');
81
- expect(result.info.title).toBe('Test API');
82
- });
83
- it('should parse already parsed objects', () => {
84
- const spec = {
85
- openapi: '3.0.0',
86
- info: { title: 'Test API', version: '1.0.0' },
87
- paths: {},
88
- };
89
- const result = parser.parse(spec);
90
- expect(result).toBeDefined();
91
- expect(result.openapi).toBe('3.0.0');
92
- });
93
- it('should validate OpenAPI structure', () => {
94
- const invalidSpec = {
95
- openapi: '2.0.0', // Wrong version format
96
- info: { title: 'Test API', version: '1.0.0' },
97
- paths: {},
98
- };
99
- expect(() => parser.parse(invalidSpec)).toThrow();
100
- });
101
- it('should handle missing required fields', () => {
102
- const invalidSpec = {
103
- openapi: '3.0.0',
104
- // Missing info
105
- paths: {},
106
- };
107
- expect(() => parser.parse(invalidSpec)).toThrow();
108
- });
109
- });
110
- });
@@ -1,100 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
- import { Generator } from '../../src/generator.js';
3
- import { Reporter } from '../../src/utils/reporter.js';
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';
8
- const __dirname = dirname(fileURLToPath(import.meta.url));
9
- const testOutputDir = join(__dirname, '../../test-output');
10
- describe('Generator', () => {
11
- let generator;
12
- let mockReporter;
13
- beforeEach(() => {
14
- // Clean up test output directory
15
- if (existsSync(testOutputDir)) {
16
- rmSync(testOutputDir, { recursive: true, force: true });
17
- }
18
- mkdirSync(testOutputDir, { recursive: true });
19
- // Create a mock reporter
20
- mockReporter = {
21
- log: vi.fn(),
22
- error: vi.fn(),
23
- };
24
- });
25
- afterEach(() => {
26
- // Clean up test output directory
27
- if (existsSync(testOutputDir)) {
28
- rmSync(testOutputDir, { recursive: true, force: true });
29
- }
30
- });
31
- describe('constructor', () => {
32
- it('should create a new Generator instance', () => {
33
- generator = new Generator('test-app', '1.0.0', mockReporter, './samples/swagger-petstore.yaml', testOutputDir);
34
- expect(generator).toBeInstanceOf(Generator);
35
- });
36
- it('should initialize with correct parameters', () => {
37
- generator = new Generator('test-app', '1.0.0', mockReporter, './samples/swagger-petstore.yaml', testOutputDir);
38
- expect(generator).toBeDefined();
39
- });
40
- });
41
- describe('run', () => {
42
- it('should be a function', () => {
43
- generator = new Generator('test-app', '1.0.0', mockReporter, './samples/swagger-petstore.yaml', testOutputDir);
44
- expect(typeof generator.run).toBe('function');
45
- });
46
- it('should generate code from a valid OpenAPI file', async () => {
47
- generator = new Generator('test-app', '1.0.0', mockReporter, './samples/swagger-petstore.yaml', testOutputDir);
48
- const exitCode = await generator.run();
49
- expect(exitCode).toBe(0);
50
- expect(mockReporter.log).toHaveBeenCalled();
51
- expect(mockReporter.error).not.toHaveBeenCalled();
52
- // Verify output file was created
53
- const outputFile = join(testOutputDir, 'type.ts');
54
- expect(existsSync(outputFile)).toBe(true);
55
- // Verify file contains expected content
56
- const content = readFileSync(outputFile, 'utf-8');
57
- expect(content).toMatch(/import\s*{\s*z\s*}\s*from\s*['"]zod['"]/);
58
- expect(content).toContain('export class');
59
- expect(content).toContain('getBaseRequestOptions');
60
- });
61
- it('should handle invalid file paths gracefully', async () => {
62
- generator = new Generator('test-app', '1.0.0', mockReporter, './non-existent-file.yaml', testOutputDir);
63
- const exitCode = await generator.run();
64
- expect(exitCode).toBe(1);
65
- expect(mockReporter.error).toHaveBeenCalled();
66
- });
67
- it('should handle invalid OpenAPI specifications', async () => {
68
- // Create a temporary invalid OpenAPI file
69
- const invalidFile = join(testOutputDir, 'invalid.yaml');
70
- mkdirSync(testOutputDir, { recursive: true });
71
- readFileSync; // Ensure we can write
72
- const { writeFileSync } = await import('node:fs');
73
- writeFileSync(invalidFile, 'invalid: yaml: content: [unclosed');
74
- generator = new Generator('test-app', '1.0.0', mockReporter, invalidFile, testOutputDir);
75
- const exitCode = await generator.run();
76
- expect(exitCode).toBe(1);
77
- expect(mockReporter.error).toHaveBeenCalled();
78
- });
79
- it('should generate code with correct structure', async () => {
80
- generator = new Generator('test-app', '1.0.0', mockReporter, './samples/swagger-petstore.yaml', testOutputDir);
81
- await generator.run();
82
- const outputFile = join(testOutputDir, 'type.ts');
83
- const content = readFileSync(outputFile, 'utf-8');
84
- // Check for key components
85
- expect(content).toMatch(/import\s*{\s*z\s*}\s*from\s*['"]zod['"]/);
86
- expect(content).toContain('export const');
87
- expect(content).toContain('protected getBaseRequestOptions');
88
- expect(content).toContain('async #makeRequest');
89
- });
90
- it('should include header comments in generated file', async () => {
91
- generator = new Generator('test-app', '1.0.0', mockReporter, './samples/swagger-petstore.yaml', testOutputDir);
92
- await generator.run();
93
- const outputFile = join(testOutputDir, 'type.ts');
94
- const content = readFileSync(outputFile, 'utf-8');
95
- expect(content).toContain('AUTOGENERATED');
96
- expect(content).toContain('test-app@1.0.0');
97
- expect(content).toContain('eslint-disable');
98
- });
99
- });
100
- });
@@ -1,94 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Script to republish missing versions to npm
4
- # Usage: ./scripts/republish-versions.sh [version1] [version2]
5
- # Example: ./scripts/republish-versions.sh 1.3.0 1.4.0
6
-
7
- set -e
8
-
9
- # Colors for output
10
- RED='\033[0;31m'
11
- GREEN='\033[0;32m'
12
- YELLOW='\033[1;33m'
13
- NC='\033[0m' # No Color
14
-
15
- # Function to publish a version
16
- publish_version() {
17
- local version=$1
18
- local tag="v${version}"
19
-
20
- echo -e "${YELLOW}📦 Publishing version ${version}...${NC}"
21
-
22
- # Check if tag exists
23
- if ! git rev-parse "$tag" >/dev/null 2>&1; then
24
- echo -e "${RED}❌ Tag ${tag} does not exist${NC}"
25
- return 1
26
- fi
27
-
28
- # Check if version is already published
29
- if npm view "zod-codegen@${version}" version >/dev/null 2>&1; then
30
- echo -e "${YELLOW}⚠️ Version ${version} already exists on npm. Skipping...${NC}"
31
- return 0
32
- fi
33
-
34
- # Save current branch/commit
35
- local current_branch=$(git rev-parse --abbrev-ref HEAD)
36
- local current_commit=$(git rev-parse HEAD)
37
-
38
- echo -e "${GREEN}✓ Checking out tag ${tag}${NC}"
39
- git checkout "$tag" --quiet
40
-
41
- # Verify package.json version matches
42
- local package_version=$(node -p "require('./package.json').version")
43
- if [ "$package_version" != "$version" ]; then
44
- echo -e "${RED}❌ Package.json version (${package_version}) doesn't match tag version (${version})${NC}"
45
- git checkout "$current_branch" --quiet 2>/dev/null || git checkout "$current_commit" --quiet
46
- return 1
47
- fi
48
-
49
- # Install dependencies
50
- echo -e "${GREEN}✓ Installing dependencies...${NC}"
51
- yarn install --frozen-lockfile
52
-
53
- # Build project
54
- echo -e "${GREEN}✓ Building project...${NC}"
55
- yarn build
56
-
57
- # Run prepublishOnly checks (build, test, lint, type-check)
58
- echo -e "${GREEN}✓ Running prepublish checks...${NC}"
59
- yarn test
60
- yarn lint:check
61
- yarn type-check
62
-
63
- # Publish to npm
64
- echo -e "${GREEN}✓ Publishing to npm...${NC}"
65
- npm publish --access public
66
-
67
- echo -e "${GREEN}✅ Successfully published version ${version}${NC}"
68
-
69
- # Return to original branch/commit
70
- echo -e "${GREEN}✓ Returning to ${current_branch}...${NC}"
71
- git checkout "$current_branch" --quiet 2>/dev/null || git checkout "$current_commit" --quiet
72
-
73
- echo ""
74
- }
75
-
76
- # Check if npm is authenticated
77
- if ! npm whoami >/dev/null 2>&1; then
78
- echo -e "${RED}❌ Not authenticated to npm. Please run 'npm login' first.${NC}"
79
- exit 1
80
- fi
81
-
82
- echo -e "${GREEN}✓ Authenticated as $(npm whoami)${NC}"
83
- echo ""
84
-
85
- # Get versions from arguments or use defaults
86
- VERSIONS=("${@:-1.3.0 1.4.0}")
87
-
88
- # Publish each version
89
- for version in "${VERSIONS[@]}"; do
90
- publish_version "$version"
91
- done
92
-
93
- echo -e "${GREEN}🎉 All versions published successfully!${NC}"
94
-