zod-codegen 1.1.1 → 1.2.0
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.
- package/.github/workflows/ci.yml +17 -17
- package/.github/workflows/release.yml +8 -8
- package/CHANGELOG.md +12 -0
- package/CONTRIBUTING.md +12 -12
- package/PERFORMANCE.md +4 -4
- package/README.md +27 -27
- package/SECURITY.md +1 -1
- package/dist/src/cli.js +1 -0
- package/dist/src/services/code-generator.service.js +78 -1
- package/dist/tests/integration/cli.test.js +2 -2
- package/package.json +19 -9
- package/src/cli.ts +1 -0
- package/src/services/code-generator.service.ts +107 -1
- package/tests/integration/cli.test.ts +2 -2
package/.github/workflows/ci.yml
CHANGED
|
@@ -29,25 +29,25 @@ jobs:
|
|
|
29
29
|
uses: actions/setup-node@v5
|
|
30
30
|
with:
|
|
31
31
|
node-version: ${{ matrix.node-version }}
|
|
32
|
-
cache: '
|
|
32
|
+
cache: 'yarn'
|
|
33
33
|
|
|
34
34
|
- name: Install dependencies
|
|
35
|
-
run:
|
|
35
|
+
run: yarn install --frozen-lockfile
|
|
36
36
|
|
|
37
37
|
- name: Run type check
|
|
38
|
-
run:
|
|
38
|
+
run: yarn type-check
|
|
39
39
|
|
|
40
40
|
- name: Run linter
|
|
41
|
-
run:
|
|
41
|
+
run: yarn lint:check
|
|
42
42
|
|
|
43
43
|
- name: Run formatter check
|
|
44
|
-
run:
|
|
44
|
+
run: yarn format:check
|
|
45
45
|
|
|
46
46
|
- name: Build project
|
|
47
|
-
run:
|
|
47
|
+
run: yarn build
|
|
48
48
|
|
|
49
49
|
- name: Run tests
|
|
50
|
-
run:
|
|
50
|
+
run: yarn 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: '
|
|
73
|
+
cache: 'yarn'
|
|
74
74
|
|
|
75
75
|
- name: Install dependencies
|
|
76
|
-
run:
|
|
76
|
+
run: yarn install --frozen-lockfile
|
|
77
77
|
|
|
78
78
|
- name: Run security audit
|
|
79
|
-
run:
|
|
79
|
+
run: yarn 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: '
|
|
94
|
+
cache: 'yarn'
|
|
95
95
|
|
|
96
96
|
- name: Install dependencies
|
|
97
|
-
run:
|
|
97
|
+
run: yarn install --frozen-lockfile
|
|
98
98
|
|
|
99
99
|
- name: Build project
|
|
100
|
-
run:
|
|
100
|
+
run: yarn 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: '
|
|
132
|
+
cache: 'yarn'
|
|
133
133
|
|
|
134
134
|
- name: Install dependencies
|
|
135
|
-
run:
|
|
135
|
+
run: yarn install --frozen-lockfile
|
|
136
136
|
|
|
137
137
|
- name: Build project
|
|
138
|
-
run:
|
|
138
|
+
run: yarn build
|
|
139
139
|
|
|
140
140
|
- name: Preview semantic-release
|
|
141
141
|
env:
|
|
142
142
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
143
|
-
run:
|
|
143
|
+
run: yarn 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: '
|
|
32
|
+
cache: 'yarn'
|
|
33
33
|
registry-url: 'https://registry.npmjs.org'
|
|
34
34
|
|
|
35
35
|
- name: Install dependencies
|
|
36
|
-
run:
|
|
36
|
+
run: yarn install --frozen-lockfile
|
|
37
37
|
|
|
38
38
|
- name: Run type check
|
|
39
|
-
run:
|
|
39
|
+
run: yarn type-check
|
|
40
40
|
|
|
41
41
|
- name: Run linter check
|
|
42
|
-
run:
|
|
42
|
+
run: yarn lint:check
|
|
43
43
|
|
|
44
44
|
- name: Run formatter check
|
|
45
|
-
run:
|
|
45
|
+
run: yarn format:check
|
|
46
46
|
|
|
47
47
|
- name: Run tests with coverage
|
|
48
|
-
run:
|
|
48
|
+
run: yarn test:coverage
|
|
49
49
|
|
|
50
50
|
- name: Build project
|
|
51
|
-
run:
|
|
51
|
+
run: yarn 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:
|
|
65
|
+
run: yarn release
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 1.2.0 (2025-11-19)
|
|
2
|
+
|
|
3
|
+
- Merge pull request #31 from julienandreu/dependabot/npm_and_yarn/dev-dependencies-1dd8918b9f ([97ebb65](https://github.com/julienandreu/zod-codegen/commit/97ebb65)), closes [#31](https://github.com/julienandreu/zod-codegen/issues/31)
|
|
4
|
+
- Merge pull request #32 from julienandreu/feat/add-jsdoc-comments ([9e0d589](https://github.com/julienandreu/zod-codegen/commit/9e0d589)), closes [#32](https://github.com/julienandreu/zod-codegen/issues/32)
|
|
5
|
+
- feat: add JSDoc comments to generated API client methods ([4f42f97](https://github.com/julienandreu/zod-codegen/commit/4f42f97))
|
|
6
|
+
- chore(deps-dev): bump the dev-dependencies group with 3 updates ([43be1ab](https://github.com/julienandreu/zod-codegen/commit/43be1ab))
|
|
7
|
+
|
|
8
|
+
## <small>1.1.2 (2025-11-13)</small>
|
|
9
|
+
|
|
10
|
+
- Merge pull request #30 from julienandreu/fix/cli-strict-mode ([d098ac7](https://github.com/julienandreu/zod-codegen/commit/d098ac7)), closes [#30](https://github.com/julienandreu/zod-codegen/issues/30)
|
|
11
|
+
- fix: add strict mode to CLI to catch typos in arguments ([b5ad8aa](https://github.com/julienandreu/zod-codegen/commit/b5ad8aa))
|
|
12
|
+
|
|
1
13
|
## <small>1.1.1 (2025-11-13)</small>
|
|
2
14
|
|
|
3
15
|
- Merge pull request #29 from julienandreu/feat/server-configuration-and-examples ([c598b5a](https://github.com/julienandreu/zod-codegen/commit/c598b5a)), closes [#29](https://github.com/julienandreu/zod-codegen/issues/29)
|
package/CONTRIBUTING.md
CHANGED
|
@@ -22,7 +22,7 @@ This project adheres to a code of conduct. By participating, you are expected to
|
|
|
22
22
|
### Prerequisites
|
|
23
23
|
|
|
24
24
|
- Node.js >= 24.11.1
|
|
25
|
-
-
|
|
25
|
+
- yarn
|
|
26
26
|
- Git
|
|
27
27
|
|
|
28
28
|
### Development Setup
|
|
@@ -37,24 +37,24 @@ This project adheres to a code of conduct. By participating, you are expected to
|
|
|
37
37
|
2. **Install Dependencies**
|
|
38
38
|
|
|
39
39
|
```bash
|
|
40
|
-
|
|
40
|
+
yarn install
|
|
41
41
|
```
|
|
42
42
|
|
|
43
43
|
3. **Build the Project**
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
|
|
46
|
+
yarn build
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
4. **Run Tests**
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
|
-
|
|
52
|
+
yarn test
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
5. **Run Development Mode**
|
|
56
56
|
```bash
|
|
57
|
-
|
|
57
|
+
yarn dev
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
## Making Changes
|
|
@@ -119,7 +119,7 @@ test: add integration tests for CLI
|
|
|
119
119
|
3. **Validate Your Changes**
|
|
120
120
|
|
|
121
121
|
```bash
|
|
122
|
-
|
|
122
|
+
yarn validate
|
|
123
123
|
```
|
|
124
124
|
|
|
125
125
|
This runs:
|
|
@@ -171,10 +171,10 @@ We use ESLint and Prettier for consistent code style:
|
|
|
171
171
|
|
|
172
172
|
```bash
|
|
173
173
|
# Auto-fix linting issues
|
|
174
|
-
|
|
174
|
+
yarn lint
|
|
175
175
|
|
|
176
176
|
# Format code
|
|
177
|
-
|
|
177
|
+
yarn format
|
|
178
178
|
```
|
|
179
179
|
|
|
180
180
|
### File Structure
|
|
@@ -218,16 +218,16 @@ tests/
|
|
|
218
218
|
|
|
219
219
|
```bash
|
|
220
220
|
# Run all tests
|
|
221
|
-
|
|
221
|
+
yarn test
|
|
222
222
|
|
|
223
223
|
# Run tests in watch mode
|
|
224
|
-
|
|
224
|
+
yarn test:watch
|
|
225
225
|
|
|
226
226
|
# Run with coverage
|
|
227
|
-
|
|
227
|
+
yarn test:coverage
|
|
228
228
|
|
|
229
229
|
# Run specific test file
|
|
230
|
-
|
|
230
|
+
yarn vitest run generator.test.ts
|
|
231
231
|
```
|
|
232
232
|
|
|
233
233
|
## Documentation
|
package/PERFORMANCE.md
CHANGED
|
@@ -12,14 +12,14 @@ For even faster builds, you can optionally use the TypeScript Native Preview (TS
|
|
|
12
12
|
### Installation
|
|
13
13
|
|
|
14
14
|
```bash
|
|
15
|
-
|
|
15
|
+
yarn add -D @typescript/native-preview
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
### Usage
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
# Use native compiler for builds
|
|
22
|
-
|
|
22
|
+
yarn build:native
|
|
23
23
|
|
|
24
24
|
# Or use directly
|
|
25
25
|
npx tsgo --project tsconfig.json
|
|
@@ -52,8 +52,8 @@ To compare performance:
|
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
54
|
# Standard TypeScript
|
|
55
|
-
time
|
|
55
|
+
time yarn build
|
|
56
56
|
|
|
57
57
|
# Native TypeScript
|
|
58
|
-
time
|
|
58
|
+
time yarn build:native
|
|
59
59
|
```
|
package/README.md
CHANGED
|
@@ -28,13 +28,13 @@ A powerful TypeScript code generator that creates **Zod schemas** and **type-saf
|
|
|
28
28
|
### Global Installation (CLI)
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
|
|
31
|
+
yarn global add zod-codegen
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
### Project Installation
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
|
-
|
|
37
|
+
yarn add --dev zod-codegen
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
## 🔧 Usage
|
|
@@ -378,7 +378,7 @@ Each example includes:
|
|
|
378
378
|
### Prerequisites
|
|
379
379
|
|
|
380
380
|
- Node.js ≥ 24.11.1
|
|
381
|
-
-
|
|
381
|
+
- yarn
|
|
382
382
|
|
|
383
383
|
### Setup
|
|
384
384
|
|
|
@@ -388,52 +388,52 @@ git clone https://github.com/julienandreu/zod-codegen.git
|
|
|
388
388
|
cd zod-codegen
|
|
389
389
|
|
|
390
390
|
# Install dependencies
|
|
391
|
-
|
|
391
|
+
yarn install
|
|
392
392
|
|
|
393
393
|
# Build the project
|
|
394
|
-
|
|
394
|
+
yarn build
|
|
395
395
|
|
|
396
396
|
# Run tests
|
|
397
|
-
|
|
397
|
+
yarn test
|
|
398
398
|
|
|
399
399
|
# Run linting
|
|
400
|
-
|
|
400
|
+
yarn lint
|
|
401
401
|
|
|
402
402
|
# Format code
|
|
403
|
-
|
|
403
|
+
yarn format
|
|
404
404
|
```
|
|
405
405
|
|
|
406
406
|
### Testing
|
|
407
407
|
|
|
408
408
|
```bash
|
|
409
409
|
# Run all tests
|
|
410
|
-
|
|
410
|
+
yarn test
|
|
411
411
|
|
|
412
412
|
# Run tests in watch mode
|
|
413
|
-
|
|
413
|
+
yarn test:watch
|
|
414
414
|
|
|
415
415
|
# Run tests with coverage
|
|
416
|
-
|
|
416
|
+
yarn test:coverage
|
|
417
417
|
|
|
418
418
|
# Run tests with UI
|
|
419
|
-
|
|
419
|
+
yarn test:ui
|
|
420
420
|
```
|
|
421
421
|
|
|
422
422
|
### Available Scripts
|
|
423
423
|
|
|
424
|
-
| Script
|
|
425
|
-
|
|
|
426
|
-
| `
|
|
427
|
-
| `
|
|
428
|
-
| `
|
|
429
|
-
| `
|
|
430
|
-
| `
|
|
431
|
-
| `
|
|
432
|
-
| `
|
|
433
|
-
| `
|
|
434
|
-
| `
|
|
435
|
-
| `
|
|
436
|
-
| `
|
|
424
|
+
| Script | Description |
|
|
425
|
+
| -------------------- | ----------------------------------------------- |
|
|
426
|
+
| `yarn build` | Build the project |
|
|
427
|
+
| `yarn build:watch` | Build in watch mode |
|
|
428
|
+
| `yarn dev` | Development mode with example |
|
|
429
|
+
| `yarn test` | Run tests |
|
|
430
|
+
| `yarn test:watch` | Run tests in watch mode |
|
|
431
|
+
| `yarn test:coverage` | Run tests with coverage |
|
|
432
|
+
| `yarn lint` | Lint and fix code |
|
|
433
|
+
| `yarn format` | Format code with Prettier |
|
|
434
|
+
| `yarn type-check` | Type check without emitting |
|
|
435
|
+
| `yarn validate` | Run all checks (lint, format, type-check, test) |
|
|
436
|
+
| `yarn clean` | Clean build artifacts |
|
|
437
437
|
|
|
438
438
|
## 📋 Requirements
|
|
439
439
|
|
|
@@ -450,8 +450,8 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
|
|
|
450
450
|
1. Fork the repository
|
|
451
451
|
2. Create your feature branch: `git checkout -b feature/amazing-feature`
|
|
452
452
|
3. Make your changes
|
|
453
|
-
4. Run tests: `
|
|
454
|
-
5. Run validation: `
|
|
453
|
+
4. Run tests: `yarn test`
|
|
454
|
+
5. Run validation: `yarn validate`
|
|
455
455
|
6. Commit your changes: `git commit -m 'feat: add amazing feature'`
|
|
456
456
|
7. Push to the branch: `git push origin feature/amazing-feature`
|
|
457
457
|
8. Open a Pull Request
|
package/SECURITY.md
CHANGED
|
@@ -75,7 +75,7 @@ When using zod-codegen, please follow these security best practices:
|
|
|
75
75
|
|
|
76
76
|
- Keep zod-codegen and its dependencies up to date
|
|
77
77
|
- Regularly audit your dependency tree for known vulnerabilities
|
|
78
|
-
- Use tools like `npm audit` to check for security issues
|
|
78
|
+
- Use tools like `yarn audit` or `npm audit` to check for security issues
|
|
79
79
|
|
|
80
80
|
## Known Security Considerations
|
|
81
81
|
|
package/dist/src/cli.js
CHANGED
|
@@ -296,7 +296,15 @@ export class TypeScriptCodeGeneratorService {
|
|
|
296
296
|
else {
|
|
297
297
|
statements.push(ts.factory.createReturnStatement(ts.factory.createAwaitExpression(makeRequestCall)));
|
|
298
298
|
}
|
|
299
|
-
|
|
299
|
+
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));
|
|
300
|
+
// Add JSDoc comment if summary or description exists
|
|
301
|
+
const jsdocComment = this.buildJSDocComment(schema.summary, schema.description, schema, responseType);
|
|
302
|
+
if (jsdocComment) {
|
|
303
|
+
// addSyntheticLeadingComment expects the comment content without delimiters
|
|
304
|
+
// and will wrap it in /** */ for JSDoc-style comments
|
|
305
|
+
ts.addSyntheticLeadingComment(methodDeclaration, ts.SyntaxKind.MultiLineCommentTrivia, `*\n${jsdocComment}\n `, true);
|
|
306
|
+
}
|
|
307
|
+
return methodDeclaration;
|
|
300
308
|
}
|
|
301
309
|
buildPathExpression(path, pathParams) {
|
|
302
310
|
// Replace {param} with ${param} for template literal
|
|
@@ -669,6 +677,75 @@ export class TypeScriptCodeGeneratorService {
|
|
|
669
677
|
ts.addSyntheticTrailingComment(commentNode, ts.SyntaxKind.SingleLineCommentTrivia, ` ${text}`, true);
|
|
670
678
|
return ts.factory.createExpressionStatement(commentNode);
|
|
671
679
|
}
|
|
680
|
+
/**
|
|
681
|
+
* Builds a JSDoc comment string from operation metadata
|
|
682
|
+
*/
|
|
683
|
+
buildJSDocComment(summary, description, schema, responseType) {
|
|
684
|
+
const lines = [];
|
|
685
|
+
// Add summary or description as the main comment
|
|
686
|
+
if (summary) {
|
|
687
|
+
lines.push(` * ${summary}`);
|
|
688
|
+
}
|
|
689
|
+
else if (description) {
|
|
690
|
+
// Use first line of description as summary if no summary exists
|
|
691
|
+
const firstLine = description.split('\n')[0]?.trim();
|
|
692
|
+
if (firstLine) {
|
|
693
|
+
lines.push(` * ${firstLine}`);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
// Add full description if it exists and is different from summary
|
|
697
|
+
if (description && description !== summary) {
|
|
698
|
+
const descLines = description.split('\n');
|
|
699
|
+
if (descLines.length > 1 || descLines[0] !== summary) {
|
|
700
|
+
if (lines.length > 0) {
|
|
701
|
+
lines.push(' *');
|
|
702
|
+
}
|
|
703
|
+
descLines.forEach((line) => {
|
|
704
|
+
lines.push(` * ${line.trim() || ''}`);
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
// Add @param tags for each parameter
|
|
709
|
+
if (schema.parameters && schema.parameters.length > 0) {
|
|
710
|
+
if (lines.length > 0) {
|
|
711
|
+
lines.push(' *');
|
|
712
|
+
}
|
|
713
|
+
for (const param of schema.parameters) {
|
|
714
|
+
const paramName = this.typeBuilder.sanitizeIdentifier(param.name);
|
|
715
|
+
const paramDesc = param.description ? ` ${param.description}` : '';
|
|
716
|
+
lines.push(` * @param ${paramName}${paramDesc}`);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
// Add @param tag for request body if present
|
|
720
|
+
if (schema.requestBody) {
|
|
721
|
+
const bodyDesc = schema.requestBody.description ? ` ${schema.requestBody.description}` : '';
|
|
722
|
+
lines.push(` * @param body${bodyDesc}`);
|
|
723
|
+
}
|
|
724
|
+
// Add @returns tag if we have a response type
|
|
725
|
+
if (responseType) {
|
|
726
|
+
// Extract the inner type from Promise<T> for JSDoc
|
|
727
|
+
let returnTypeText;
|
|
728
|
+
if (ts.isTypeReferenceNode(responseType) &&
|
|
729
|
+
ts.isIdentifier(responseType.typeName) &&
|
|
730
|
+
responseType.typeName.text === 'Promise' &&
|
|
731
|
+
responseType.typeArguments &&
|
|
732
|
+
responseType.typeArguments.length > 0 &&
|
|
733
|
+
responseType.typeArguments[0]) {
|
|
734
|
+
// Extract the inner type from Promise<T>
|
|
735
|
+
const innerType = responseType.typeArguments[0];
|
|
736
|
+
returnTypeText = this.printer.printNode(ts.EmitHint.Unspecified, innerType, ts.createSourceFile('', '', ts.ScriptTarget.Latest));
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
returnTypeText = this.printer.printNode(ts.EmitHint.Unspecified, responseType, ts.createSourceFile('', '', ts.ScriptTarget.Latest));
|
|
740
|
+
}
|
|
741
|
+
lines.push(` * @returns {${returnTypeText}}`);
|
|
742
|
+
}
|
|
743
|
+
// Build the complete JSDoc comment (without delimiters, as addSyntheticLeadingComment adds them)
|
|
744
|
+
if (lines.length === 0) {
|
|
745
|
+
return '';
|
|
746
|
+
}
|
|
747
|
+
return lines.join('\n');
|
|
748
|
+
}
|
|
672
749
|
buildZodAST(input) {
|
|
673
750
|
const [initial, ...rest] = input;
|
|
674
751
|
const safeInitial = this.ZodAST.safeParse(initial);
|
|
@@ -4,7 +4,7 @@ import { resolve } from 'node:path';
|
|
|
4
4
|
describe('CLI Integration', () => {
|
|
5
5
|
describe('--help', () => {
|
|
6
6
|
it('should display help information', () => {
|
|
7
|
-
const result = execSync('
|
|
7
|
+
const result = execSync('yarn build && node ./dist/src/cli.js --help', {
|
|
8
8
|
encoding: 'utf-8',
|
|
9
9
|
cwd: resolve(__dirname, '../..'),
|
|
10
10
|
});
|
|
@@ -15,7 +15,7 @@ describe('CLI Integration', () => {
|
|
|
15
15
|
});
|
|
16
16
|
describe('--version', () => {
|
|
17
17
|
it('should display version information', () => {
|
|
18
|
-
const result = execSync('
|
|
18
|
+
const result = execSync('yarn build && node ./dist/src/cli.js --version', {
|
|
19
19
|
encoding: 'utf-8',
|
|
20
20
|
cwd: resolve(__dirname, '../..'),
|
|
21
21
|
});
|
package/package.json
CHANGED
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@apidevtools/swagger-parser": "^12.1.0",
|
|
11
|
-
"debug": "^4.3
|
|
11
|
+
"debug": "^4.4.3",
|
|
12
12
|
"js-yaml": "^4.1.1",
|
|
13
13
|
"jsonpath": "^1.1.1",
|
|
14
14
|
"loud-rejection": "^2.2.0",
|
|
15
15
|
"openapi-types": "^12.1.3",
|
|
16
16
|
"openapi-typescript": "^7.10.1",
|
|
17
|
-
"path-to-regexp": "^8.
|
|
17
|
+
"path-to-regexp": "^8.3.0",
|
|
18
18
|
"prettier": "^3.6.2",
|
|
19
19
|
"typescript": "^5.9.3",
|
|
20
20
|
"url-pattern": "^1.0.3",
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"@types/js-yaml": "^4.0.9",
|
|
45
45
|
"@types/jsonpath": "^0.2.4",
|
|
46
46
|
"@types/node": "^24.10.1",
|
|
47
|
-
"@types/yargs": "^17.0.
|
|
48
|
-
"@vitest/coverage-v8": "^4.0.
|
|
47
|
+
"@types/yargs": "^17.0.35",
|
|
48
|
+
"@vitest/coverage-v8": "^4.0.9",
|
|
49
49
|
"eslint": "^9.39.1",
|
|
50
50
|
"eslint-config-prettier": "^10.1.8",
|
|
51
51
|
"husky": "^9.1.7",
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
"ts-node": "^10.9.2",
|
|
55
55
|
"typescript-eslint": "^8.46.4",
|
|
56
56
|
"undici": "^7.16.0",
|
|
57
|
-
"vitest": "^4.0.8"
|
|
57
|
+
"vitest": "^4.0.8",
|
|
58
|
+
"yarn-audit-fix": "^10.1.1"
|
|
58
59
|
},
|
|
59
60
|
"optionalDependencies": {
|
|
60
61
|
"undici": "^7.16.0"
|
|
@@ -77,11 +78,20 @@
|
|
|
77
78
|
"engines": {
|
|
78
79
|
"node": ">=24.11.1"
|
|
79
80
|
},
|
|
81
|
+
"overrides": {
|
|
82
|
+
"npm": {
|
|
83
|
+
"glob": "^11.1.0",
|
|
84
|
+
"tar": "^7.5.2"
|
|
85
|
+
},
|
|
86
|
+
"glob": "^11.1.0",
|
|
87
|
+
"tar": "^7.5.2"
|
|
88
|
+
},
|
|
80
89
|
"scripts": {
|
|
90
|
+
"audit:fix": "yarn-audit-fix",
|
|
81
91
|
"build": "rm -rf dist && tsc --project tsconfig.json && cp -r src/assets dist/src/ && chmod +x ./dist/src/cli.js",
|
|
82
92
|
"build:native": "rm -rf dist && npx tsgo --project tsconfig.json && cp -r src/assets dist/src/ && chmod +x ./dist/src/cli.js",
|
|
83
93
|
"build:watch": "tsc --project tsconfig.json --watch",
|
|
84
|
-
"dev": "
|
|
94
|
+
"dev": "yarn build && node ./dist/src/cli.js --input ./samples/swagger-petstore.yaml --output ./examples/petstore && yarn format && yarn lint",
|
|
85
95
|
"lint": "eslint src --fix",
|
|
86
96
|
"lint:check": "eslint src",
|
|
87
97
|
"format": "prettier src --write --log-level error",
|
|
@@ -93,12 +103,12 @@
|
|
|
93
103
|
"test:ui": "vitest --ui",
|
|
94
104
|
"manifest:update": "ts-node scripts/update-manifest.ts",
|
|
95
105
|
"prepare": "husky",
|
|
96
|
-
"prepublishOnly": "
|
|
106
|
+
"prepublishOnly": "yarn build && yarn test && yarn lint:check && yarn type-check",
|
|
97
107
|
"clean": "rm -rf dist coverage node_modules/.cache",
|
|
98
|
-
"validate": "
|
|
108
|
+
"validate": "yarn type-check && yarn lint:check && yarn format:check && yarn test",
|
|
99
109
|
"validate:examples": "tsc -p ./tsconfig.examples.json --noEmit",
|
|
100
110
|
"release": "semantic-release",
|
|
101
111
|
"release:dry": "semantic-release --dry-run"
|
|
102
112
|
},
|
|
103
|
-
"version": "1.
|
|
113
|
+
"version": "1.2.0"
|
|
104
114
|
}
|
package/src/cli.ts
CHANGED
|
@@ -962,7 +962,7 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
|
|
|
962
962
|
statements.push(ts.factory.createReturnStatement(ts.factory.createAwaitExpression(makeRequestCall)));
|
|
963
963
|
}
|
|
964
964
|
|
|
965
|
-
|
|
965
|
+
const methodDeclaration = ts.factory.createMethodDeclaration(
|
|
966
966
|
[ts.factory.createToken(ts.SyntaxKind.AsyncKeyword)],
|
|
967
967
|
undefined,
|
|
968
968
|
ts.factory.createIdentifier(String(schema.operationId)),
|
|
@@ -972,6 +972,22 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
|
|
|
972
972
|
responseType,
|
|
973
973
|
ts.factory.createBlock(statements, true),
|
|
974
974
|
);
|
|
975
|
+
|
|
976
|
+
// Add JSDoc comment if summary or description exists
|
|
977
|
+
const jsdocComment = this.buildJSDocComment(schema.summary, schema.description, schema, responseType);
|
|
978
|
+
|
|
979
|
+
if (jsdocComment) {
|
|
980
|
+
// addSyntheticLeadingComment expects the comment content without delimiters
|
|
981
|
+
// and will wrap it in /** */ for JSDoc-style comments
|
|
982
|
+
ts.addSyntheticLeadingComment(
|
|
983
|
+
methodDeclaration,
|
|
984
|
+
ts.SyntaxKind.MultiLineCommentTrivia,
|
|
985
|
+
`*\n${jsdocComment}\n `,
|
|
986
|
+
true,
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
return methodDeclaration;
|
|
975
991
|
}
|
|
976
992
|
|
|
977
993
|
private buildPathExpression(path: string, pathParams: {name: string; type: string}[]): ts.Expression {
|
|
@@ -1670,6 +1686,96 @@ export class TypeScriptCodeGeneratorService implements CodeGenerator, SchemaBuil
|
|
|
1670
1686
|
return ts.factory.createExpressionStatement(commentNode);
|
|
1671
1687
|
}
|
|
1672
1688
|
|
|
1689
|
+
/**
|
|
1690
|
+
* Builds a JSDoc comment string from operation metadata
|
|
1691
|
+
*/
|
|
1692
|
+
private buildJSDocComment(
|
|
1693
|
+
summary: string | undefined,
|
|
1694
|
+
description: string | undefined,
|
|
1695
|
+
schema: MethodSchemaType,
|
|
1696
|
+
responseType: ts.TypeNode | undefined,
|
|
1697
|
+
): string {
|
|
1698
|
+
const lines: string[] = [];
|
|
1699
|
+
|
|
1700
|
+
// Add summary or description as the main comment
|
|
1701
|
+
if (summary) {
|
|
1702
|
+
lines.push(` * ${summary}`);
|
|
1703
|
+
} else if (description) {
|
|
1704
|
+
// Use first line of description as summary if no summary exists
|
|
1705
|
+
const firstLine = description.split('\n')[0]?.trim();
|
|
1706
|
+
if (firstLine) {
|
|
1707
|
+
lines.push(` * ${firstLine}`);
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
// Add full description if it exists and is different from summary
|
|
1712
|
+
if (description && description !== summary) {
|
|
1713
|
+
const descLines = description.split('\n');
|
|
1714
|
+
if (descLines.length > 1 || descLines[0] !== summary) {
|
|
1715
|
+
if (lines.length > 0) {
|
|
1716
|
+
lines.push(' *');
|
|
1717
|
+
}
|
|
1718
|
+
descLines.forEach((line) => {
|
|
1719
|
+
lines.push(` * ${line.trim() || ''}`);
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
// Add @param tags for each parameter
|
|
1725
|
+
if (schema.parameters && schema.parameters.length > 0) {
|
|
1726
|
+
if (lines.length > 0) {
|
|
1727
|
+
lines.push(' *');
|
|
1728
|
+
}
|
|
1729
|
+
for (const param of schema.parameters) {
|
|
1730
|
+
const paramName = this.typeBuilder.sanitizeIdentifier(param.name);
|
|
1731
|
+
const paramDesc = param.description ? ` ${param.description}` : '';
|
|
1732
|
+
lines.push(` * @param ${paramName}${paramDesc}`);
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
// Add @param tag for request body if present
|
|
1737
|
+
if (schema.requestBody) {
|
|
1738
|
+
const bodyDesc = schema.requestBody.description ? ` ${schema.requestBody.description}` : '';
|
|
1739
|
+
lines.push(` * @param body${bodyDesc}`);
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
// Add @returns tag if we have a response type
|
|
1743
|
+
if (responseType) {
|
|
1744
|
+
// Extract the inner type from Promise<T> for JSDoc
|
|
1745
|
+
let returnTypeText: string;
|
|
1746
|
+
if (
|
|
1747
|
+
ts.isTypeReferenceNode(responseType) &&
|
|
1748
|
+
ts.isIdentifier(responseType.typeName) &&
|
|
1749
|
+
responseType.typeName.text === 'Promise' &&
|
|
1750
|
+
responseType.typeArguments &&
|
|
1751
|
+
responseType.typeArguments.length > 0 &&
|
|
1752
|
+
responseType.typeArguments[0]
|
|
1753
|
+
) {
|
|
1754
|
+
// Extract the inner type from Promise<T>
|
|
1755
|
+
const innerType = responseType.typeArguments[0];
|
|
1756
|
+
returnTypeText = this.printer.printNode(
|
|
1757
|
+
ts.EmitHint.Unspecified,
|
|
1758
|
+
innerType,
|
|
1759
|
+
ts.createSourceFile('', '', ts.ScriptTarget.Latest),
|
|
1760
|
+
);
|
|
1761
|
+
} else {
|
|
1762
|
+
returnTypeText = this.printer.printNode(
|
|
1763
|
+
ts.EmitHint.Unspecified,
|
|
1764
|
+
responseType,
|
|
1765
|
+
ts.createSourceFile('', '', ts.ScriptTarget.Latest),
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
lines.push(` * @returns {${returnTypeText}}`);
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
// Build the complete JSDoc comment (without delimiters, as addSyntheticLeadingComment adds them)
|
|
1772
|
+
if (lines.length === 0) {
|
|
1773
|
+
return '';
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
return lines.join('\n');
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1673
1779
|
private buildZodAST(input: (string | z.infer<typeof this.ZodAST>)[]): ts.CallExpression {
|
|
1674
1780
|
const [initial, ...rest] = input;
|
|
1675
1781
|
|
|
@@ -5,7 +5,7 @@ import {resolve} from 'node:path';
|
|
|
5
5
|
describe('CLI Integration', () => {
|
|
6
6
|
describe('--help', () => {
|
|
7
7
|
it('should display help information', () => {
|
|
8
|
-
const result = execSync('
|
|
8
|
+
const result = execSync('yarn build && node ./dist/src/cli.js --help', {
|
|
9
9
|
encoding: 'utf-8',
|
|
10
10
|
cwd: resolve(__dirname, '../..'),
|
|
11
11
|
});
|
|
@@ -18,7 +18,7 @@ describe('CLI Integration', () => {
|
|
|
18
18
|
|
|
19
19
|
describe('--version', () => {
|
|
20
20
|
it('should display version information', () => {
|
|
21
|
-
const result = execSync('
|
|
21
|
+
const result = execSync('yarn build && node ./dist/src/cli.js --version', {
|
|
22
22
|
encoding: 'utf-8',
|
|
23
23
|
cwd: resolve(__dirname, '../..'),
|
|
24
24
|
});
|