@intellegens/cornerstone-cli 0.0.0-experimental-upgrade-20260302-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.
- package/README.md +92 -0
- package/dist/commands/openapi-generator.d.ts +15 -0
- package/dist/commands/openapi-generator.js +161 -0
- package/dist/commands/zod-schema-generator.d.ts +7 -0
- package/dist/commands/zod-schema-generator.js +88 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +13 -0
- package/package.json +46 -0
- package/src/commands/openapi-generator.ts +185 -0
- package/src/commands/zod-schema-generator.ts +116 -0
- package/src/index.ts +14 -0
- package/tsconfig.json +7 -0
- package/vitest.config.ts +37 -0
package/README.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Cornerstone TypeScript CLI Tool(s)
|
|
2
|
+
|
|
3
|
+
A command-line interface (CLI) with various utilities. The CLI is built using yargs and supports the following commands:
|
|
4
|
+
|
|
5
|
+
## Getting started
|
|
6
|
+
|
|
7
|
+
1. Install dependencies:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm install
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Available scripts
|
|
14
|
+
|
|
15
|
+
2. `build`: Compiles the TypeScript code
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pnpm run build
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
3. `cli`: Runs the CLI in development mode using tsx
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pnpm run cli <command> [options]
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Install and run
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pnpm install -g @intellegens/cornerstone-cli
|
|
31
|
+
cornerstone-ts <command> [options]
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## API reference
|
|
35
|
+
|
|
36
|
+
### Zod Schema Generator
|
|
37
|
+
|
|
38
|
+
Generates Zod schemas from JSON schema files, preserving namespace structure.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Development
|
|
42
|
+
pnpm run cli zod-gen --input <input-dir> --output <output-dir>
|
|
43
|
+
|
|
44
|
+
# After building
|
|
45
|
+
./dist/utils/cli/index.js zod-gen --input <input-dir> --output <output-dir>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Options:
|
|
49
|
+
|
|
50
|
+
- `--input, -i`: Path to the folder containing JSON schemas
|
|
51
|
+
- `--output, -o`: Path to the folder where Zod schemas will be saved
|
|
52
|
+
|
|
53
|
+
The command will:
|
|
54
|
+
|
|
55
|
+
1. Read JSON schema files from the input directory
|
|
56
|
+
2. Create a folder structure matching the type's namespace
|
|
57
|
+
3. Generate Zod schemas with proper type names
|
|
58
|
+
4. Save the generated schemas in their respective namespace folders
|
|
59
|
+
|
|
60
|
+
For example, if you have a JSON schema file named `MyCompany.ModuleA.Models.UserDto.json`, it will:
|
|
61
|
+
|
|
62
|
+
- Create directories: `output-dir/MyCompany/ModuleA/Models/`
|
|
63
|
+
- Generate and save `UserDto.ts` in that directory with the Zod schema
|
|
64
|
+
|
|
65
|
+
### OpenAPI Generator
|
|
66
|
+
|
|
67
|
+
Generates client code from OpenAPI schema files using Orval.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Development
|
|
71
|
+
pnpm run cli openapi-gen --input <input-file> --output <output-dir> [options]
|
|
72
|
+
|
|
73
|
+
# After building
|
|
74
|
+
./dist/utils/cli/index.js openapi-gen --input <input-file> --output <output-dir> [options]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Options:
|
|
78
|
+
|
|
79
|
+
- `--input, -i`: Path to the OPENAPI schema .json file
|
|
80
|
+
- `--output, -o`: Path to the folder where client and types will be saved
|
|
81
|
+
- `--prettier, -p`: Format generated code with Prettier (default: false)
|
|
82
|
+
- `--fetchClient, -f`: Generate fetch client (default: false)
|
|
83
|
+
- `--angularClient, -a`: Generate Angular client (default: false)
|
|
84
|
+
- `--zod, -z`: Generate Zod schemas (default: false)
|
|
85
|
+
- `--mock, -m`: Generate mock client (default: false)
|
|
86
|
+
- `--clean, -c`: Clean output folder (default: true)
|
|
87
|
+
- `--project, -pr`: Project name (default: 'my-project')
|
|
88
|
+
- `--baseUrl, -b`: Base URL for the API (default: '')
|
|
89
|
+
|
|
90
|
+
The command will generate client code based on the selected options. By default, it generates only types; additionally, you can generate fetch client, angular client or zod schemas.
|
|
91
|
+
|
|
92
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { CommandModule } from 'yargs';
|
|
2
|
+
interface OpenApiGeneratorArgs {
|
|
3
|
+
input: string;
|
|
4
|
+
output: string;
|
|
5
|
+
prettier: boolean;
|
|
6
|
+
zod: boolean;
|
|
7
|
+
fetchClient: boolean;
|
|
8
|
+
angularClient: boolean;
|
|
9
|
+
mock: boolean;
|
|
10
|
+
project: string;
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
clean: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare const openApiGeneratorCommand: CommandModule<{}, OpenApiGeneratorArgs>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { generate } from 'orval';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
export const openApiGeneratorCommand = {
|
|
5
|
+
command: 'openapi-gen',
|
|
6
|
+
describe: 'Generate Zod schemas from JSON schemas',
|
|
7
|
+
builder: {
|
|
8
|
+
input: {
|
|
9
|
+
alias: 'i',
|
|
10
|
+
type: 'string',
|
|
11
|
+
describe: 'Path to the OPENAPI schema .json file',
|
|
12
|
+
demandOption: true,
|
|
13
|
+
},
|
|
14
|
+
output: {
|
|
15
|
+
alias: 'o',
|
|
16
|
+
type: 'string',
|
|
17
|
+
describe: 'Path to the folder where client will be saved',
|
|
18
|
+
demandOption: true,
|
|
19
|
+
},
|
|
20
|
+
prettier: {
|
|
21
|
+
alias: 'p',
|
|
22
|
+
type: 'boolean',
|
|
23
|
+
describe: 'Format generated code with Prettier',
|
|
24
|
+
default: false,
|
|
25
|
+
},
|
|
26
|
+
fetchClient: {
|
|
27
|
+
alias: 'f',
|
|
28
|
+
type: 'boolean',
|
|
29
|
+
describe: 'Generate fetch client',
|
|
30
|
+
default: false,
|
|
31
|
+
},
|
|
32
|
+
angularClient: {
|
|
33
|
+
alias: 'a',
|
|
34
|
+
type: 'boolean',
|
|
35
|
+
describe: 'Generate Angular client',
|
|
36
|
+
default: false,
|
|
37
|
+
},
|
|
38
|
+
zod: {
|
|
39
|
+
alias: 'z',
|
|
40
|
+
type: 'boolean',
|
|
41
|
+
describe: 'Generate Zod schemas',
|
|
42
|
+
default: false,
|
|
43
|
+
},
|
|
44
|
+
mock: {
|
|
45
|
+
alias: 'm',
|
|
46
|
+
type: 'boolean',
|
|
47
|
+
describe: 'Generate mock client',
|
|
48
|
+
default: false,
|
|
49
|
+
},
|
|
50
|
+
clean: {
|
|
51
|
+
alias: 'c',
|
|
52
|
+
type: 'boolean',
|
|
53
|
+
describe: 'Clean output folder',
|
|
54
|
+
default: true,
|
|
55
|
+
},
|
|
56
|
+
project: {
|
|
57
|
+
alias: 'pr',
|
|
58
|
+
type: 'string',
|
|
59
|
+
describe: 'Project name',
|
|
60
|
+
default: 'my-project',
|
|
61
|
+
},
|
|
62
|
+
baseUrl: {
|
|
63
|
+
alias: 'b',
|
|
64
|
+
type: 'string',
|
|
65
|
+
describe: 'Base URL for the API',
|
|
66
|
+
default: '',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
async handler(args) {
|
|
70
|
+
try {
|
|
71
|
+
const absoluteInputPath = path.resolve(args.input);
|
|
72
|
+
const absoluteOutputPath = path.resolve(args.output);
|
|
73
|
+
// Check if input file exists
|
|
74
|
+
if (!fs.existsSync(absoluteInputPath)) {
|
|
75
|
+
console.error('🔴 OpenAPI schema file not found:', absoluteInputPath);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
let configs = [];
|
|
79
|
+
// Add configurations based on selected options
|
|
80
|
+
if ((!args.fetchClient && !args.angularClient) || args.zod) {
|
|
81
|
+
configs.push({
|
|
82
|
+
input: absoluteInputPath,
|
|
83
|
+
output: {
|
|
84
|
+
mode: 'tags-split',
|
|
85
|
+
target: './zod',
|
|
86
|
+
schemas: './models',
|
|
87
|
+
client: 'zod',
|
|
88
|
+
mock: args.mock,
|
|
89
|
+
prettier: args.prettier,
|
|
90
|
+
clean: args.clean,
|
|
91
|
+
override: {
|
|
92
|
+
useTypeOverInterfaces: true,
|
|
93
|
+
zod: {
|
|
94
|
+
generate: {
|
|
95
|
+
param: false,
|
|
96
|
+
body: args.zod,
|
|
97
|
+
response: false,
|
|
98
|
+
query: false,
|
|
99
|
+
header: false,
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
if (args.fetchClient) {
|
|
107
|
+
configs.push({
|
|
108
|
+
input: absoluteInputPath,
|
|
109
|
+
output: {
|
|
110
|
+
mode: 'tags-split',
|
|
111
|
+
target: './endpoints',
|
|
112
|
+
schemas: './models',
|
|
113
|
+
client: 'fetch',
|
|
114
|
+
httpClient: 'fetch',
|
|
115
|
+
mock: args.mock,
|
|
116
|
+
prettier: args.prettier,
|
|
117
|
+
clean: args.clean,
|
|
118
|
+
override: {
|
|
119
|
+
useTypeOverInterfaces: true,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (args.angularClient) {
|
|
125
|
+
configs.push({
|
|
126
|
+
input: absoluteInputPath,
|
|
127
|
+
output: {
|
|
128
|
+
mode: 'tags-split',
|
|
129
|
+
target: './endpoints',
|
|
130
|
+
schemas: './models',
|
|
131
|
+
client: 'angular',
|
|
132
|
+
mock: args.mock,
|
|
133
|
+
prettier: args.prettier,
|
|
134
|
+
clean: args.clean,
|
|
135
|
+
baseUrl: args.baseUrl,
|
|
136
|
+
override: {
|
|
137
|
+
useTypeOverInterfaces: true,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (configs.length === 0) {
|
|
143
|
+
console.error('🔴 No options selected. Please select at least one option.');
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
// Generate
|
|
147
|
+
for (const config of configs) {
|
|
148
|
+
await generate(config, absoluteOutputPath, { projectName: args.project });
|
|
149
|
+
}
|
|
150
|
+
console.log('🟢 Schemas generated successfully!');
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
console.error('🔴 Error generating schemas:', error);
|
|
154
|
+
if (error instanceof Error) {
|
|
155
|
+
console.error('🔴 Error message:', error.message);
|
|
156
|
+
console.error('🔴 Error stack:', error.stack);
|
|
157
|
+
}
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { jsonSchemaToZod } from 'json-schema-to-zod';
|
|
4
|
+
import { resolveRefs } from 'json-refs';
|
|
5
|
+
export const zodSchemaGeneratorCommand = {
|
|
6
|
+
command: 'zod-gen',
|
|
7
|
+
describe: 'Generate Zod schemas from JSON schemas',
|
|
8
|
+
builder: {
|
|
9
|
+
input: {
|
|
10
|
+
alias: 'i',
|
|
11
|
+
type: 'string',
|
|
12
|
+
describe: 'Path to the folder containing JSON schemas',
|
|
13
|
+
demandOption: true,
|
|
14
|
+
},
|
|
15
|
+
output: {
|
|
16
|
+
alias: 'o',
|
|
17
|
+
type: 'string',
|
|
18
|
+
describe: 'Path to the folder where Zod schemas will be saved',
|
|
19
|
+
demandOption: true,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
async handler(args) {
|
|
23
|
+
try {
|
|
24
|
+
const { input: inputPath, output: outputPath } = args;
|
|
25
|
+
if (!fs.existsSync(inputPath)) {
|
|
26
|
+
console.warn('🟡 Input directory not found.');
|
|
27
|
+
process.exit(0);
|
|
28
|
+
}
|
|
29
|
+
const files = fs
|
|
30
|
+
.readdirSync(inputPath)
|
|
31
|
+
.filter((file) => file.endsWith('.json'));
|
|
32
|
+
if (files.length === 0) {
|
|
33
|
+
console.warn('🟡 No JSON schema files found in the input directory.');
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
if (!fs.existsSync(outputPath)) {
|
|
37
|
+
fs.emptyDirSync(outputPath);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
fs.mkdirSync(outputPath, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
var exports = {};
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
const filePath = path.join(inputPath, file);
|
|
45
|
+
const schemaContent = fs.readFileSync(filePath, 'utf-8');
|
|
46
|
+
const schema = JSON.parse(schemaContent);
|
|
47
|
+
const fullName = path.basename(file, '.json');
|
|
48
|
+
const parts = fullName.split('.');
|
|
49
|
+
// Last part is the type name, everything before is namespace
|
|
50
|
+
const typeName = parts[parts.length - 1];
|
|
51
|
+
const namespaceParts = parts.slice(0, -1);
|
|
52
|
+
// Create the namespace folder structure
|
|
53
|
+
const namespaceDir = path.join(outputPath, ...namespaceParts);
|
|
54
|
+
fs.mkdirSync(namespaceDir, { recursive: true });
|
|
55
|
+
const { resolved } = await resolveRefs(schema);
|
|
56
|
+
// Convert JSON Schema to Zod
|
|
57
|
+
const zodSchema = jsonSchemaToZod(resolved, {
|
|
58
|
+
withJsdocs: true,
|
|
59
|
+
module: 'esm',
|
|
60
|
+
type: true,
|
|
61
|
+
name: typeName,
|
|
62
|
+
depth: 5,
|
|
63
|
+
});
|
|
64
|
+
// Generate TypeScript file
|
|
65
|
+
const fileName = `${typeName}.ts`;
|
|
66
|
+
const outputFilePath = path.join(namespaceDir, fileName);
|
|
67
|
+
const outputTypePath = path.join(namespaceDir, typeName);
|
|
68
|
+
fs.writeFileSync(outputFilePath, zodSchema, 'utf-8');
|
|
69
|
+
console.log(`- Generated Zod schema: ${outputFilePath}`);
|
|
70
|
+
// Register for (re)export
|
|
71
|
+
exports[typeName] = path.relative(outputPath, outputTypePath);
|
|
72
|
+
}
|
|
73
|
+
// Write (re)export file
|
|
74
|
+
let exportFileContent = '';
|
|
75
|
+
for (const typeName in exports) {
|
|
76
|
+
const typePath = `./${exports[typeName]}`.replace(/\\/g, '/');
|
|
77
|
+
exportFileContent += `export * from '${typePath}'; // .NET ${typeName} class\n`;
|
|
78
|
+
}
|
|
79
|
+
fs.writeFileSync(path.join(outputPath, './index.ts'), exportFileContent, 'utf-8');
|
|
80
|
+
// Prompt done
|
|
81
|
+
console.log('🟢 Zod schemas generated successfully!');
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
console.error('🔴 Error generating Zod schemas:', error);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
};
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import yargs from 'yargs';
|
|
3
|
+
import { hideBin } from 'yargs/helpers';
|
|
4
|
+
import { zodSchemaGeneratorCommand } from './commands/zod-schema-generator.js';
|
|
5
|
+
import { openApiGeneratorCommand } from './commands/openapi-generator.js';
|
|
6
|
+
yargs(hideBin(process.argv))
|
|
7
|
+
.scriptName('cornerstone-ts')
|
|
8
|
+
.command(zodSchemaGeneratorCommand)
|
|
9
|
+
.command(openApiGeneratorCommand)
|
|
10
|
+
.demandCommand(1, 'You need to specify a command')
|
|
11
|
+
.strict()
|
|
12
|
+
.alias('h', 'help')
|
|
13
|
+
.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intellegens/cornerstone-cli",
|
|
3
|
+
"version": "0.0.0-experimental-upgrade-20260302-1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"publishable": true,
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"author": "Intellegens",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"description": "",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"intellegens",
|
|
14
|
+
"cornerstone"
|
|
15
|
+
],
|
|
16
|
+
"bin": {
|
|
17
|
+
"cornerstone-ts": "./dist/index.js"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@orval/core": "^7.21.0",
|
|
21
|
+
"fs-extra": "^11.3.3",
|
|
22
|
+
"json-refs": "^3.0.15",
|
|
23
|
+
"json-schema-to-zod": "^2.7.0",
|
|
24
|
+
"orval": "^7.21.0",
|
|
25
|
+
"typescript": "~5.9.3",
|
|
26
|
+
"yargs": "^17.7.2",
|
|
27
|
+
"zod": "^3.25.76"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/fs-extra": "^11.0.4",
|
|
31
|
+
"@types/node": "^25.3.1",
|
|
32
|
+
"@types/yargs": "^17.0.35",
|
|
33
|
+
"tsc-alias": "^1.8.16",
|
|
34
|
+
"tsx": "^4.21.0",
|
|
35
|
+
"vitest": "^4.0.18"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"clean": "pnpx rimraf '{dist}'",
|
|
39
|
+
"test": "vitest run --passWithNoTests",
|
|
40
|
+
"test:unit": "vitest run --project unit --passWithNoTests",
|
|
41
|
+
"test:integration": "vitest run --project integration --passWithNoTests",
|
|
42
|
+
"coverage": "vitest run --coverage",
|
|
43
|
+
"build": "pnpm run clean && tsc && tsc-alias",
|
|
44
|
+
"start": "tsx ./src/index.ts"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { generate } from 'orval';
|
|
2
|
+
import { CommandModule } from 'yargs';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { OptionsExport } from '@orval/core';
|
|
6
|
+
|
|
7
|
+
interface OpenApiGeneratorArgs {
|
|
8
|
+
input: string;
|
|
9
|
+
output: string;
|
|
10
|
+
prettier: boolean;
|
|
11
|
+
zod: boolean;
|
|
12
|
+
fetchClient: boolean;
|
|
13
|
+
angularClient: boolean;
|
|
14
|
+
mock: boolean;
|
|
15
|
+
project: string;
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
clean: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const openApiGeneratorCommand: CommandModule<{}, OpenApiGeneratorArgs> = {
|
|
21
|
+
command: 'openapi-gen',
|
|
22
|
+
describe: 'Generate Zod schemas from JSON schemas',
|
|
23
|
+
|
|
24
|
+
builder: {
|
|
25
|
+
input: {
|
|
26
|
+
alias: 'i',
|
|
27
|
+
type: 'string',
|
|
28
|
+
describe: 'Path to the OPENAPI schema .json file',
|
|
29
|
+
demandOption: true,
|
|
30
|
+
},
|
|
31
|
+
output: {
|
|
32
|
+
alias: 'o',
|
|
33
|
+
type: 'string',
|
|
34
|
+
describe: 'Path to the folder where client will be saved',
|
|
35
|
+
demandOption: true,
|
|
36
|
+
},
|
|
37
|
+
prettier: {
|
|
38
|
+
alias: 'p',
|
|
39
|
+
type: 'boolean',
|
|
40
|
+
describe: 'Format generated code with Prettier',
|
|
41
|
+
default: false,
|
|
42
|
+
},
|
|
43
|
+
fetchClient: {
|
|
44
|
+
alias: 'f',
|
|
45
|
+
type: 'boolean',
|
|
46
|
+
describe: 'Generate fetch client',
|
|
47
|
+
default: false,
|
|
48
|
+
},
|
|
49
|
+
angularClient: {
|
|
50
|
+
alias: 'a',
|
|
51
|
+
type: 'boolean',
|
|
52
|
+
describe: 'Generate Angular client',
|
|
53
|
+
default: false,
|
|
54
|
+
},
|
|
55
|
+
zod: {
|
|
56
|
+
alias: 'z',
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
describe: 'Generate Zod schemas',
|
|
59
|
+
default: false,
|
|
60
|
+
},
|
|
61
|
+
mock: {
|
|
62
|
+
alias: 'm',
|
|
63
|
+
type: 'boolean',
|
|
64
|
+
describe: 'Generate mock client',
|
|
65
|
+
default: false,
|
|
66
|
+
},
|
|
67
|
+
clean: {
|
|
68
|
+
alias: 'c',
|
|
69
|
+
type: 'boolean',
|
|
70
|
+
describe: 'Clean output folder',
|
|
71
|
+
default: true,
|
|
72
|
+
},
|
|
73
|
+
project: {
|
|
74
|
+
alias: 'pr',
|
|
75
|
+
type: 'string',
|
|
76
|
+
describe: 'Project name',
|
|
77
|
+
default: 'my-project',
|
|
78
|
+
},
|
|
79
|
+
baseUrl: {
|
|
80
|
+
alias: 'b',
|
|
81
|
+
type: 'string',
|
|
82
|
+
describe: 'Base URL for the API',
|
|
83
|
+
default: '',
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
async handler(args: OpenApiGeneratorArgs) {
|
|
88
|
+
try {
|
|
89
|
+
const absoluteInputPath = path.resolve(args.input);
|
|
90
|
+
const absoluteOutputPath = path.resolve(args.output);
|
|
91
|
+
// Check if input file exists
|
|
92
|
+
if (!fs.existsSync(absoluteInputPath)) {
|
|
93
|
+
console.error('🔴 OpenAPI schema file not found:', absoluteInputPath);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let configs: OptionsExport[] = [];
|
|
98
|
+
|
|
99
|
+
// Add configurations based on selected options
|
|
100
|
+
if ((!args.fetchClient && !args.angularClient) || args.zod) {
|
|
101
|
+
configs.push({
|
|
102
|
+
input: absoluteInputPath,
|
|
103
|
+
output: {
|
|
104
|
+
mode: 'tags-split',
|
|
105
|
+
target: './zod',
|
|
106
|
+
schemas: './models',
|
|
107
|
+
client: 'zod',
|
|
108
|
+
mock: args.mock,
|
|
109
|
+
prettier: args.prettier,
|
|
110
|
+
clean: args.clean,
|
|
111
|
+
override: {
|
|
112
|
+
useTypeOverInterfaces: true,
|
|
113
|
+
zod: {
|
|
114
|
+
generate: {
|
|
115
|
+
param: false,
|
|
116
|
+
body: args.zod,
|
|
117
|
+
response: false,
|
|
118
|
+
query: false,
|
|
119
|
+
header: false,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (args.fetchClient) {
|
|
128
|
+
configs.push({
|
|
129
|
+
input: absoluteInputPath,
|
|
130
|
+
output: {
|
|
131
|
+
mode: 'tags-split',
|
|
132
|
+
target: './endpoints',
|
|
133
|
+
schemas: './models',
|
|
134
|
+
client: 'fetch',
|
|
135
|
+
httpClient: 'fetch',
|
|
136
|
+
mock: args.mock,
|
|
137
|
+
prettier: args.prettier,
|
|
138
|
+
clean: args.clean,
|
|
139
|
+
override: {
|
|
140
|
+
useTypeOverInterfaces: true,
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (args.angularClient) {
|
|
147
|
+
configs.push({
|
|
148
|
+
input: absoluteInputPath,
|
|
149
|
+
output: {
|
|
150
|
+
mode: 'tags-split',
|
|
151
|
+
target: './endpoints',
|
|
152
|
+
schemas: './models',
|
|
153
|
+
client: 'angular',
|
|
154
|
+
mock: args.mock,
|
|
155
|
+
prettier: args.prettier,
|
|
156
|
+
clean: args.clean,
|
|
157
|
+
baseUrl: args.baseUrl,
|
|
158
|
+
override: {
|
|
159
|
+
useTypeOverInterfaces: true,
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (configs.length === 0) {
|
|
166
|
+
console.error('🔴 No options selected. Please select at least one option.');
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Generate
|
|
171
|
+
for (const config of configs) {
|
|
172
|
+
await generate(config, absoluteOutputPath, { projectName: args.project });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
console.log('🟢 Schemas generated successfully!');
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('🔴 Error generating schemas:', error);
|
|
178
|
+
if (error instanceof Error) {
|
|
179
|
+
console.error('🔴 Error message:', error.message);
|
|
180
|
+
console.error('🔴 Error stack:', error.stack);
|
|
181
|
+
}
|
|
182
|
+
process.exit(1);
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
};
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { jsonSchemaToZod } from 'json-schema-to-zod';
|
|
4
|
+
import { resolveRefs } from 'json-refs';
|
|
5
|
+
import { CommandModule } from 'yargs';
|
|
6
|
+
|
|
7
|
+
interface ZodSchemaGeneratorArgs {
|
|
8
|
+
input: string;
|
|
9
|
+
output: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const zodSchemaGeneratorCommand: CommandModule<
|
|
13
|
+
{},
|
|
14
|
+
ZodSchemaGeneratorArgs
|
|
15
|
+
> = {
|
|
16
|
+
command: 'zod-gen',
|
|
17
|
+
describe: 'Generate Zod schemas from JSON schemas',
|
|
18
|
+
|
|
19
|
+
builder: {
|
|
20
|
+
input: {
|
|
21
|
+
alias: 'i',
|
|
22
|
+
type: 'string',
|
|
23
|
+
describe: 'Path to the folder containing JSON schemas',
|
|
24
|
+
demandOption: true,
|
|
25
|
+
},
|
|
26
|
+
output: {
|
|
27
|
+
alias: 'o',
|
|
28
|
+
type: 'string',
|
|
29
|
+
describe: 'Path to the folder where Zod schemas will be saved',
|
|
30
|
+
demandOption: true,
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
async handler(args: ZodSchemaGeneratorArgs) {
|
|
35
|
+
try {
|
|
36
|
+
const { input: inputPath, output: outputPath } = args;
|
|
37
|
+
|
|
38
|
+
if (!fs.existsSync(inputPath)) {
|
|
39
|
+
console.warn('🟡 Input directory not found.');
|
|
40
|
+
process.exit(0);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const files = fs
|
|
44
|
+
.readdirSync(inputPath)
|
|
45
|
+
.filter((file) => file.endsWith('.json'));
|
|
46
|
+
|
|
47
|
+
if (files.length === 0) {
|
|
48
|
+
console.warn('🟡 No JSON schema files found in the input directory.');
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!fs.existsSync(outputPath)) {
|
|
53
|
+
fs.emptyDirSync(outputPath);
|
|
54
|
+
} else {
|
|
55
|
+
fs.mkdirSync(outputPath, { recursive: true });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var exports: Record<string, string> = {};
|
|
59
|
+
for (const file of files) {
|
|
60
|
+
const filePath = path.join(inputPath, file);
|
|
61
|
+
const schemaContent = fs.readFileSync(filePath, 'utf-8');
|
|
62
|
+
const schema = JSON.parse(schemaContent);
|
|
63
|
+
|
|
64
|
+
const fullName = path.basename(file, '.json');
|
|
65
|
+
const parts = fullName.split('.');
|
|
66
|
+
|
|
67
|
+
// Last part is the type name, everything before is namespace
|
|
68
|
+
const typeName = parts[parts.length - 1];
|
|
69
|
+
const namespaceParts = parts.slice(0, -1);
|
|
70
|
+
|
|
71
|
+
// Create the namespace folder structure
|
|
72
|
+
const namespaceDir = path.join(outputPath, ...namespaceParts);
|
|
73
|
+
fs.mkdirSync(namespaceDir, { recursive: true });
|
|
74
|
+
|
|
75
|
+
const { resolved } = await resolveRefs(schema);
|
|
76
|
+
// Convert JSON Schema to Zod
|
|
77
|
+
const zodSchema = jsonSchemaToZod(resolved, {
|
|
78
|
+
withJsdocs: true,
|
|
79
|
+
module: 'esm',
|
|
80
|
+
type: true,
|
|
81
|
+
name: typeName,
|
|
82
|
+
depth: 5,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Generate TypeScript file
|
|
86
|
+
const fileName = `${typeName}.ts`;
|
|
87
|
+
const outputFilePath = path.join(namespaceDir, fileName);
|
|
88
|
+
const outputTypePath = path.join(namespaceDir, typeName);
|
|
89
|
+
|
|
90
|
+
fs.writeFileSync(outputFilePath, zodSchema, 'utf-8');
|
|
91
|
+
console.log(`- Generated Zod schema: ${outputFilePath}`);
|
|
92
|
+
|
|
93
|
+
// Register for (re)export
|
|
94
|
+
exports[typeName] = path.relative(outputPath, outputTypePath);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Write (re)export file
|
|
98
|
+
let exportFileContent = '';
|
|
99
|
+
for (const typeName in exports) {
|
|
100
|
+
const typePath = `./${exports[typeName]}`.replace(/\\/g, '/');
|
|
101
|
+
exportFileContent += `export * from '${typePath}'; // .NET ${typeName} class\n`;
|
|
102
|
+
}
|
|
103
|
+
fs.writeFileSync(
|
|
104
|
+
path.join(outputPath, './index.ts'),
|
|
105
|
+
exportFileContent,
|
|
106
|
+
'utf-8',
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Prompt done
|
|
110
|
+
console.log('🟢 Zod schemas generated successfully!');
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error('🔴 Error generating Zod schemas:', error);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import yargs from 'yargs';
|
|
3
|
+
import { hideBin } from 'yargs/helpers';
|
|
4
|
+
import { zodSchemaGeneratorCommand } from './commands/zod-schema-generator.js';
|
|
5
|
+
import { openApiGeneratorCommand } from './commands/openapi-generator.js';
|
|
6
|
+
|
|
7
|
+
yargs(hideBin(process.argv))
|
|
8
|
+
.scriptName('cornerstone-ts')
|
|
9
|
+
.command(zodSchemaGeneratorCommand)
|
|
10
|
+
.command(openApiGeneratorCommand)
|
|
11
|
+
.demandCommand(1, 'You need to specify a command')
|
|
12
|
+
.strict()
|
|
13
|
+
.alias('h', 'help')
|
|
14
|
+
.parse();
|
package/tsconfig.json
ADDED
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { defineConfig } from 'vitest/config';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
test: {
|
|
6
|
+
projects: [
|
|
7
|
+
{
|
|
8
|
+
test: {
|
|
9
|
+
name: 'unit',
|
|
10
|
+
environment: 'jsdom',
|
|
11
|
+
testTimeout: 60000,
|
|
12
|
+
include: ['./**/*.unit.test.{ts,tsx,js}', './**/*.unit.test.{ts,tsx,js}'],
|
|
13
|
+
exclude: ['**/node_modules/**', '**/dist/**'],
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
test: {
|
|
18
|
+
name: 'integration',
|
|
19
|
+
environment: 'jsdom',
|
|
20
|
+
testTimeout: 60000,
|
|
21
|
+
globalSetup: [path.resolve(__dirname, '../../vitest-setup-integration.ts')],
|
|
22
|
+
include: ['./**/*.integration.test.{ts,tsx,js}', './**/*.integration.test.{ts,tsx,js}'],
|
|
23
|
+
exclude: ['**/node_modules/**', '**/dist/**'],
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
test: {
|
|
28
|
+
name: 'debug',
|
|
29
|
+
testTimeout: 60000,
|
|
30
|
+
globalSetup: [path.resolve(__dirname, '../../vitest-setup-integration.ts')],
|
|
31
|
+
include: ['./**/*.{test,spec,debug}.{js,ts}'],
|
|
32
|
+
exclude: ['**/node_modules/**', '**/dist/**'],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
});
|