klasik 1.0.22 β†’ 1.0.23

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.
@@ -12,7 +12,9 @@
12
12
  "WebFetch(domain:zod.dev)",
13
13
  "Bash(node test-disc-union.js:*)",
14
14
  "Bash(node test-disc-code.js:*)",
15
- "Bash(node test-new-validators.js:*)"
15
+ "Bash(node test-new-validators.js:*)",
16
+ "Bash(node dist/cli.js generate-crd:*)",
17
+ "Bash(node test-programmatic-api.js:*)"
16
18
  ]
17
19
  }
18
20
  }
package/README.md CHANGED
@@ -5,6 +5,7 @@ Download OpenAPI specifications from remote URLs and generate TypeScript clients
5
5
  ## Features
6
6
 
7
7
  - πŸ“₯ **Download OpenAPI specs** from remote URLs or local files
8
+ - ☸️ **Kubernetes CRD support** - Generate TypeScript models from CustomResourceDefinitions
8
9
  - πŸ“ **Multiple input formats** - HTTP/HTTPS URLs, file:// URLs, absolute/relative paths
9
10
  - πŸ“„ **JSON and YAML support** - Automatically parse and handle both formats (YAML specs are converted to JSON for code generation)
10
11
  - πŸ” **Authentication support** - Custom headers including Bearer tokens and API keys
@@ -13,7 +14,7 @@ Download OpenAPI specifications from remote URLs and generate TypeScript clients
13
14
  - πŸ”„ **Automatic transformation** - Converts API responses to class instances using class-transformer
14
15
  - 🎯 **Type-safe** - Full TypeScript support with decorators
15
16
  - πŸ› οΈ **Configurable** - Custom headers, timeouts, and templates
16
- - πŸ§ͺ **Well-tested** - Comprehensive test coverage (11 tests passing)
17
+ - πŸ§ͺ **Well-tested** - Comprehensive test coverage
17
18
  - πŸ“¦ **Easy to use** - Simple CLI and programmatic API
18
19
 
19
20
  ## Installation
@@ -86,6 +87,143 @@ await generator.generate({
86
87
  });
87
88
  ```
88
89
 
90
+ ## Kubernetes CRD Support
91
+
92
+ Klasik can generate TypeScript models directly from Kubernetes CustomResourceDefinitions (CRDs). This is perfect for working with custom Kubernetes resources like ArgoCD Applications, Cert-Manager Certificates, or your own custom resources.
93
+
94
+ ### Quick Start with CRDs
95
+
96
+ Generate TypeScript models from a CRD:
97
+
98
+ ```bash
99
+ # From a URL (e.g., ArgoCD AppProject CRD)
100
+ npx klasik generate-crd \
101
+ --url https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/appproject-crd.yaml \
102
+ --output ./generated
103
+
104
+ # From a local CRD file
105
+ npx klasik generate-crd \
106
+ --url ./my-crd.yaml \
107
+ --output ./generated
108
+
109
+ # With status schemas
110
+ npx klasik generate-crd \
111
+ --url ./my-crd.yaml \
112
+ --output ./generated \
113
+ --include-status
114
+
115
+ # With NestJS and validation decorators
116
+ npx klasik generate-crd \
117
+ --url ./my-crd.yaml \
118
+ --output ./src/generated \
119
+ --nestjs-swagger \
120
+ --class-validator
121
+ ```
122
+
123
+ ### CRD Features
124
+
125
+ - βœ… **Automatic schema extraction** from `openAPIV3Schema`
126
+ - βœ… **Version-based organization** - Each CRD version gets its own folder (e.g., `v1alpha1/`, `v1beta1/`)
127
+ - βœ… **Multi-document YAML support** - Process multiple CRDs from a single file
128
+ - βœ… **Nested type extraction** - Complex nested objects become separate TypeScript interfaces
129
+ - βœ… **Full decorator support** - Works with `--nestjs-swagger`, `--class-validator`, `--esm`
130
+ - βœ… **Spec and Status schemas** - Optional status model generation with `--include-status`
131
+ - βœ… **Kubernetes metadata** - Standard ObjectMeta types included
132
+
133
+ ### Generated CRD Structure
134
+
135
+ For a CRD with multiple versions, klasik generates:
136
+
137
+ ```
138
+ output/
139
+ β”œβ”€β”€ v1alpha1/
140
+ β”‚ β”œβ”€β”€ models/
141
+ β”‚ β”‚ β”œβ”€β”€ app-project.ts # Main resource
142
+ β”‚ β”‚ β”œβ”€β”€ app-project-spec.ts # Spec definition
143
+ β”‚ β”‚ β”œβ”€β”€ app-project-status.ts # Status (if --include-status)
144
+ β”‚ β”‚ β”œβ”€β”€ object-meta.ts # Kubernetes metadata
145
+ β”‚ β”‚ └── [nested-types].ts # Extracted nested types
146
+ β”‚ └── index.ts # Version exports
147
+ β”œβ”€β”€ v1beta1/
148
+ β”‚ └── ... (same structure)
149
+ └── index.ts # All versions
150
+ ```
151
+
152
+ ### Using Generated CRD Models
153
+
154
+ ```typescript
155
+ import { AppProject, AppProjectSpec } from './generated/v1alpha1';
156
+
157
+ // Create a typed Kubernetes resource
158
+ const project: AppProject = {
159
+ apiVersion: 'argoproj.io/v1alpha1',
160
+ kind: 'AppProject',
161
+ metadata: {
162
+ name: 'my-project',
163
+ namespace: 'argocd'
164
+ },
165
+ spec: {
166
+ description: 'My ArgoCD project',
167
+ destinations: [
168
+ { server: 'https://kubernetes.default.svc', namespace: '*' }
169
+ ],
170
+ sourceRepos: ['*']
171
+ }
172
+ };
173
+
174
+ // Full TypeScript intellisense and type checking!
175
+ ```
176
+
177
+ ### CRD Programmatic API
178
+
179
+ ```typescript
180
+ import { CRDGenerator } from 'klasik';
181
+
182
+ const generator = new CRDGenerator();
183
+
184
+ await generator.generate({
185
+ url: './crds/my-resource.yaml',
186
+ outputDir: './generated',
187
+ includeStatus: true,
188
+ nestJsSwagger: true,
189
+ classValidator: true
190
+ });
191
+ ```
192
+
193
+ ### Multi-CRD YAML Files
194
+
195
+ Klasik automatically handles multi-document YAML files (CRDs separated by `---`):
196
+
197
+ ```yaml
198
+ ---
199
+ apiVersion: apiextensions.k8s.io/v1
200
+ kind: CustomResourceDefinition
201
+ metadata:
202
+ name: appprojects.argoproj.io
203
+ spec:
204
+ # ... AppProject CRD
205
+ ---
206
+ apiVersion: apiextensions.k8s.io/v1
207
+ kind: CustomResourceDefinition
208
+ metadata:
209
+ name: applications.argoproj.io
210
+ spec:
211
+ # ... Application CRD
212
+ ```
213
+
214
+ Output will be organized by resource kind:
215
+
216
+ ```
217
+ output/
218
+ β”œβ”€β”€ AppProject/
219
+ β”‚ β”œβ”€β”€ v1alpha1/
220
+ β”‚ └── index.ts
221
+ β”œβ”€β”€ Application/
222
+ β”‚ β”œβ”€β”€ v1alpha1/
223
+ β”‚ └── index.ts
224
+ └── index.ts
225
+ ```
226
+
89
227
  ## CLI Commands
90
228
 
91
229
  ### `generate`
@@ -201,6 +339,86 @@ klasik download \
201
339
  --resolve-refs
202
340
  ```
203
341
 
342
+ ### `generate-crd`
343
+
344
+ Generate TypeScript models from Kubernetes CustomResourceDefinition (CRD) YAML files.
345
+
346
+ **Options:**
347
+ - `-u, --url <url>` - URL or file path to CRD YAML (required)
348
+ - Supports: `https://...`, `http://...`, `file://...`, `/absolute/path`, `./relative/path`
349
+ - `-o, --output <dir>` - Output directory for generated models (required)
350
+ - `--include-status` - Generate status schemas in addition to spec schemas (default: false)
351
+ - By default, only spec models are generated
352
+ - Enable this to also generate status models for reading resource status
353
+ - `--nestjs-swagger` - Include NestJS Swagger `@ApiProperty` decorators
354
+ - `--class-validator` - Include class-validator decorators
355
+ - `--esm` - Add `.js` extensions to imports for ESM compatibility
356
+ - `-H, --header <header...>` - Custom headers for HTTP requests (format: "Key: Value")
357
+ - `-t, --template <dir>` - Custom template directory
358
+ - `-k, --keep-spec` - Keep the generated OpenAPI spec files (for debugging)
359
+ - `--timeout <ms>` - Request timeout in milliseconds (default: 30000)
360
+
361
+ **Examples:**
362
+
363
+ ```bash
364
+ # Generate from ArgoCD AppProject CRD
365
+ klasik generate-crd \
366
+ --url https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/appproject-crd.yaml \
367
+ --output ./generated/crds
368
+
369
+ # Generate with status models
370
+ klasik generate-crd \
371
+ --url ./my-crd.yaml \
372
+ --output ./generated \
373
+ --include-status
374
+
375
+ # NestJS integration with validation
376
+ klasik generate-crd \
377
+ --url ./crds/ \
378
+ --output ./src/generated/k8s \
379
+ --nestjs-swagger \
380
+ --class-validator
381
+
382
+ # From local file with authentication (if downloading references)
383
+ klasik generate-crd \
384
+ --url ./local-crd.yaml \
385
+ --output ./generated \
386
+ --header "Authorization: Bearer token"
387
+
388
+ # Multi-CRD file
389
+ klasik generate-crd \
390
+ --url ./all-crds.yaml \
391
+ --output ./generated \
392
+ --include-status \
393
+ --nestjs-swagger
394
+ ```
395
+
396
+ **Output Structure:**
397
+
398
+ For a single CRD:
399
+ ```
400
+ output/
401
+ β”œβ”€β”€ v1alpha1/
402
+ β”‚ └── models/
403
+ β”‚ β”œβ”€β”€ my-resource.ts
404
+ β”‚ β”œβ”€β”€ my-resource-spec.ts
405
+ β”‚ β”œβ”€β”€ my-resource-status.ts (if --include-status)
406
+ β”‚ └── ...
407
+ └── index.ts
408
+ ```
409
+
410
+ For multiple CRDs:
411
+ ```
412
+ output/
413
+ β”œβ”€β”€ AppProject/
414
+ β”‚ β”œβ”€β”€ v1alpha1/
415
+ β”‚ └── index.ts
416
+ β”œβ”€β”€ Application/
417
+ β”‚ β”œβ”€β”€ v1alpha1/
418
+ β”‚ └── index.ts
419
+ └── index.ts
420
+ ```
421
+
204
422
  ## Programmatic API
205
423
 
206
424
  ### K8sClientGenerator
@@ -250,6 +468,59 @@ console.log(`Spec downloaded to: ${specPath}`);
250
468
  downloader.cleanupTemp();
251
469
  ```
252
470
 
471
+ ### CRDGenerator
472
+
473
+ Generate TypeScript models from Kubernetes CustomResourceDefinitions programmatically:
474
+
475
+ ```typescript
476
+ import { CRDGenerator } from 'klasik';
477
+
478
+ const generator = new CRDGenerator();
479
+
480
+ await generator.generate({
481
+ url: 'https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/appproject-crd.yaml',
482
+ outputDir: './generated/crds',
483
+ includeStatus: true, // Generate status models
484
+ nestJsSwagger: true, // Include @ApiProperty decorators
485
+ classValidator: true, // Include validation decorators
486
+ fixEsmImports: false, // Add .js extensions
487
+ headers: {
488
+ 'Authorization': 'Bearer token123'
489
+ },
490
+ timeout: 60000
491
+ });
492
+ ```
493
+
494
+ **CRDGeneratorOptions:**
495
+ - `url: string` - URL or file path to CRD YAML (required)
496
+ - `outputDir: string` - Output directory (required)
497
+ - `includeStatus?: boolean` - Generate status schemas (default: false)
498
+ - `headers?: Record<string, string>` - Custom HTTP headers
499
+ - `timeout?: number` - Request timeout in milliseconds (default: 30000)
500
+ - `fixEsmImports?: boolean` - Add .js extensions for ESM (default: false)
501
+ - `nestJsSwagger?: boolean` - Include NestJS decorators (default: false)
502
+ - `classValidator?: boolean` - Include validation decorators (default: false)
503
+ - `skipJsExtensions?: boolean` - Skip .js extensions (default: false)
504
+ - `templateDir?: string` - Custom template directory
505
+ - `keepSpec?: boolean` - Keep intermediate OpenAPI specs (default: false)
506
+
507
+ **Multi-CRD YAML:**
508
+
509
+ The CRDGenerator automatically handles multi-document YAML files:
510
+
511
+ ```typescript
512
+ // This YAML contains multiple CRDs separated by ---
513
+ await generator.generate({
514
+ url: './all-crds.yaml', // Contains AppProject, Application, etc.
515
+ outputDir: './generated',
516
+ includeStatus: true
517
+ });
518
+
519
+ // Output will be organized by CRD kind
520
+ // ./generated/AppProject/v1alpha1/...
521
+ // ./generated/Application/v1alpha1/...
522
+ ```
523
+
253
524
  ## Generated Client Features
254
525
 
255
526
  The generated TypeScript client includes:
package/dist/cli.js CHANGED
@@ -134,4 +134,53 @@ program
134
134
  process.exit(1);
135
135
  }
136
136
  });
137
+ program
138
+ .command('generate-crd')
139
+ .description('Generate TypeScript models from Kubernetes CRD YAML files')
140
+ .requiredOption('-u, --url <url>', 'URL or file path to CRD YAML')
141
+ .requiredOption('-o, --output <dir>', 'Output directory for generated models')
142
+ .option('--include-status', 'Generate status schemas in addition to spec schemas', false)
143
+ .option('--nestjs-swagger', 'Include NestJS Swagger @ApiProperty decorators in generated models', false)
144
+ .option('--class-validator', 'Include class-validator decorators in generated models', false)
145
+ .option('--esm', 'Add .js extensions to imports for ESM compatibility', false)
146
+ .option('-H, --header <header...>', 'Custom headers for the request (format: "Key: Value")')
147
+ .option('--timeout <ms>', 'Request timeout in milliseconds', '30000')
148
+ .option('-t, --template <dir>', 'Custom template directory')
149
+ .option('-k, --keep-spec', 'Keep the generated OpenAPI spec files', false)
150
+ .action(async (options) => {
151
+ try {
152
+ // Parse headers if provided
153
+ const headers = {};
154
+ if (options.header) {
155
+ for (const header of options.header) {
156
+ const [key, ...valueParts] = header.split(':');
157
+ const value = valueParts.join(':').trim();
158
+ if (key && value) {
159
+ headers[key.trim()] = value;
160
+ }
161
+ }
162
+ }
163
+ // Resolve output directory to absolute path
164
+ const outputDir = path.resolve(options.output);
165
+ const { CRDGenerator } = await Promise.resolve().then(() => __importStar(require('./crd/crd-generator')));
166
+ const generator = new CRDGenerator();
167
+ await generator.generate({
168
+ url: options.url,
169
+ outputDir,
170
+ includeStatus: options.includeStatus,
171
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
172
+ timeout: parseInt(options.timeout, 10),
173
+ fixEsmImports: options.esm,
174
+ nestJsSwagger: options.nestjsSwagger,
175
+ classValidator: options.classValidator,
176
+ templateDir: options.template,
177
+ keepSpec: options.keepSpec,
178
+ });
179
+ process.exit(0);
180
+ }
181
+ catch (error) {
182
+ console.error('Error:', error instanceof Error ? error.message : error);
183
+ process.exit(1);
184
+ }
185
+ });
137
186
  program.parse();
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Options for CRD client generation
3
+ */
4
+ export interface CRDGeneratorOptions {
5
+ /**
6
+ * URL or file path to CRD YAML file(s)
7
+ */
8
+ url: string;
9
+ /**
10
+ * Output directory for generated models
11
+ */
12
+ outputDir: string;
13
+ /**
14
+ * Whether to include status schemas in generation
15
+ * @default false
16
+ */
17
+ includeStatus?: boolean;
18
+ /**
19
+ * Custom headers for downloading CRDs from URLs
20
+ */
21
+ headers?: Record<string, string>;
22
+ /**
23
+ * Request timeout for downloading specs in milliseconds
24
+ * @default 30000
25
+ */
26
+ timeout?: number;
27
+ /**
28
+ * Whether to fix ESM imports by adding .js extensions
29
+ * @default false
30
+ */
31
+ fixEsmImports?: boolean;
32
+ /**
33
+ * Include NestJS Swagger @ApiProperty decorators
34
+ * @default false
35
+ */
36
+ nestJsSwagger?: boolean;
37
+ /**
38
+ * Include class-validator decorators
39
+ * @default false
40
+ */
41
+ classValidator?: boolean;
42
+ /**
43
+ * Skip adding .js extensions to imports/exports
44
+ * @default false
45
+ */
46
+ skipJsExtensions?: boolean;
47
+ /**
48
+ * Custom template directory
49
+ */
50
+ templateDir?: string;
51
+ /**
52
+ * Whether to keep the intermediate OpenAPI specs
53
+ * @default false
54
+ */
55
+ keepSpec?: boolean;
56
+ }
57
+ /**
58
+ * Main orchestrator for generating TypeScript models from Kubernetes CRDs
59
+ */
60
+ export declare class CRDGenerator {
61
+ private parser;
62
+ private converter;
63
+ private k8sGenerator;
64
+ constructor();
65
+ /**
66
+ * Main generation workflow
67
+ * @param options Generation options
68
+ */
69
+ generate(options: CRDGeneratorOptions): Promise<void>;
70
+ /**
71
+ * Process a single CRD
72
+ * @param crd Parsed CRD
73
+ * @param outputDir Output directory for this CRD
74
+ * @param options Generation options
75
+ * @returns Array of version directory names
76
+ */
77
+ private processCRD;
78
+ /**
79
+ * Generate index file for a CRD (when multiple CRDs in one file)
80
+ * @param crdDir CRD directory
81
+ * @param versions Array of version names
82
+ */
83
+ private generateCRDIndex;
84
+ /**
85
+ * Generate main index file (when multiple CRDs in one file)
86
+ * @param outputDir Output directory
87
+ * @param crdNames Array of CRD kind names
88
+ */
89
+ private generateMainIndex;
90
+ /**
91
+ * Generate version index file (for single CRD)
92
+ * @param outputDir Output directory
93
+ * @param versions Array of version names
94
+ */
95
+ private generateVersionIndex;
96
+ /**
97
+ * Load CRD file from URL or local path
98
+ * @param url URL or file path
99
+ * @param headers Optional HTTP headers
100
+ * @param timeout Optional timeout in milliseconds
101
+ * @returns CRD file content as string
102
+ */
103
+ private loadCRDFile;
104
+ /**
105
+ * Check if the URL is a local file path
106
+ */
107
+ private isLocalFile;
108
+ /**
109
+ * Load CRD from local file
110
+ */
111
+ private loadLocalCRDFile;
112
+ }