klasik 1.0.22 β†’ 1.0.24

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,163 @@ 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 multiple CRD URLs (merged into single output)
105
+ npx klasik generate-crd \
106
+ -u https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/application-crd.yaml \
107
+ -u https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/appproject-crd.yaml \
108
+ --output ./generated
109
+
110
+ # From a local CRD file
111
+ npx klasik generate-crd \
112
+ --url ./my-crd.yaml \
113
+ --output ./generated
114
+
115
+ # With status schemas
116
+ npx klasik generate-crd \
117
+ --url ./my-crd.yaml \
118
+ --output ./generated \
119
+ --include-status
120
+
121
+ # With NestJS and validation decorators
122
+ npx klasik generate-crd \
123
+ --url ./my-crd.yaml \
124
+ --output ./src/generated \
125
+ --nestjs-swagger \
126
+ --class-validator
127
+ ```
128
+
129
+ ### CRD Features
130
+
131
+ - βœ… **Automatic schema extraction** from `openAPIV3Schema`
132
+ - βœ… **Multiple URL support** - Generate from multiple CRD sources in one command
133
+ - βœ… **Version-based organization** - Each CRD version gets its own folder (e.g., `v1alpha1/`, `v1beta1/`)
134
+ - βœ… **Multi-document YAML support** - Process multiple CRDs from a single file
135
+ - βœ… **Nested type extraction** - Complex nested objects become separate TypeScript interfaces
136
+ - βœ… **Full decorator support** - Works with `--nestjs-swagger`, `--class-validator`, `--esm`
137
+ - βœ… **Spec and Status schemas** - Optional status model generation with `--include-status`
138
+ - βœ… **Kubernetes metadata** - Standard ObjectMeta types included
139
+
140
+ ### Generated CRD Structure
141
+
142
+ For a CRD with multiple versions, klasik generates:
143
+
144
+ ```
145
+ output/
146
+ β”œβ”€β”€ v1alpha1/
147
+ β”‚ β”œβ”€β”€ models/
148
+ β”‚ β”‚ β”œβ”€β”€ app-project.ts # Main resource
149
+ β”‚ β”‚ β”œβ”€β”€ app-project-spec.ts # Spec definition
150
+ β”‚ β”‚ β”œβ”€β”€ app-project-status.ts # Status (if --include-status)
151
+ β”‚ β”‚ β”œβ”€β”€ object-meta.ts # Kubernetes metadata
152
+ β”‚ β”‚ └── [nested-types].ts # Extracted nested types
153
+ β”‚ └── index.ts # Version exports
154
+ β”œβ”€β”€ v1beta1/
155
+ β”‚ └── ... (same structure)
156
+ └── index.ts # All versions
157
+ ```
158
+
159
+ ### Using Generated CRD Models
160
+
161
+ ```typescript
162
+ import { AppProject, AppProjectSpec } from './generated/v1alpha1';
163
+
164
+ // Create a typed Kubernetes resource
165
+ const project: AppProject = {
166
+ apiVersion: 'argoproj.io/v1alpha1',
167
+ kind: 'AppProject',
168
+ metadata: {
169
+ name: 'my-project',
170
+ namespace: 'argocd'
171
+ },
172
+ spec: {
173
+ description: 'My ArgoCD project',
174
+ destinations: [
175
+ { server: 'https://kubernetes.default.svc', namespace: '*' }
176
+ ],
177
+ sourceRepos: ['*']
178
+ }
179
+ };
180
+
181
+ // Full TypeScript intellisense and type checking!
182
+ ```
183
+
184
+ ### CRD Programmatic API
185
+
186
+ ```typescript
187
+ import { CRDGenerator } from 'klasik';
188
+
189
+ const generator = new CRDGenerator();
190
+
191
+ // Single URL
192
+ await generator.generate({
193
+ urls: './crds/my-resource.yaml',
194
+ outputDir: './generated',
195
+ includeStatus: true,
196
+ nestJsSwagger: true,
197
+ classValidator: true
198
+ });
199
+
200
+ // Multiple URLs (merged into single output)
201
+ await generator.generate({
202
+ urls: [
203
+ 'https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/application-crd.yaml',
204
+ 'https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/appproject-crd.yaml',
205
+ './local/my-crd.yaml'
206
+ ],
207
+ outputDir: './generated',
208
+ includeStatus: true,
209
+ nestJsSwagger: true
210
+ });
211
+ ```
212
+
213
+ ### Multi-CRD YAML Files
214
+
215
+ Klasik automatically handles multi-document YAML files (CRDs separated by `---`):
216
+
217
+ ```yaml
218
+ ---
219
+ apiVersion: apiextensions.k8s.io/v1
220
+ kind: CustomResourceDefinition
221
+ metadata:
222
+ name: appprojects.argoproj.io
223
+ spec:
224
+ # ... AppProject CRD
225
+ ---
226
+ apiVersion: apiextensions.k8s.io/v1
227
+ kind: CustomResourceDefinition
228
+ metadata:
229
+ name: applications.argoproj.io
230
+ spec:
231
+ # ... Application CRD
232
+ ```
233
+
234
+ Output will be organized by resource kind:
235
+
236
+ ```
237
+ output/
238
+ β”œβ”€β”€ AppProject/
239
+ β”‚ β”œβ”€β”€ v1alpha1/
240
+ β”‚ └── index.ts
241
+ β”œβ”€β”€ Application/
242
+ β”‚ β”œβ”€β”€ v1alpha1/
243
+ β”‚ └── index.ts
244
+ └── index.ts
245
+ ```
246
+
89
247
  ## CLI Commands
90
248
 
91
249
  ### `generate`
@@ -201,6 +359,101 @@ klasik download \
201
359
  --resolve-refs
202
360
  ```
203
361
 
362
+ ### `generate-crd`
363
+
364
+ Generate TypeScript models from Kubernetes CustomResourceDefinition (CRD) YAML files.
365
+
366
+ **Options:**
367
+ - `-u, --url <url...>` - URL(s) or file path(s) to CRD YAML files (required)
368
+ - Can be specified multiple times: `-u url1 -u url2 -u url3`
369
+ - All CRDs from all URLs are merged into a single output directory
370
+ - Supports: `https://...`, `http://...`, `file://...`, `/absolute/path`, `./relative/path`
371
+ - `-o, --output <dir>` - Output directory for generated models (required)
372
+ - `--include-status` - Generate status schemas in addition to spec schemas (default: false)
373
+ - By default, only spec models are generated
374
+ - Enable this to also generate status models for reading resource status
375
+ - `--nestjs-swagger` - Include NestJS Swagger `@ApiProperty` decorators
376
+ - `--class-validator` - Include class-validator decorators
377
+ - `--esm` - Add `.js` extensions to imports for ESM compatibility
378
+ - `-H, --header <header...>` - Custom headers for HTTP requests (format: "Key: Value")
379
+ - `-t, --template <dir>` - Custom template directory
380
+ - `-k, --keep-spec` - Keep the generated OpenAPI spec files (for debugging)
381
+ - `--timeout <ms>` - Request timeout in milliseconds (default: 30000)
382
+
383
+ **Examples:**
384
+
385
+ ```bash
386
+ # Generate from ArgoCD AppProject CRD
387
+ klasik generate-crd \
388
+ --url https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/appproject-crd.yaml \
389
+ --output ./generated/crds
390
+
391
+ # Generate from multiple CRD URLs (merged into single output)
392
+ klasik generate-crd \
393
+ -u https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/application-crd.yaml \
394
+ -u https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/appproject-crd.yaml \
395
+ --output ./generated/argocd
396
+
397
+ # Mix remote and local CRDs
398
+ klasik generate-crd \
399
+ -u https://example.com/crd1.yaml \
400
+ -u ./crds/crd2.yaml \
401
+ -u ./crds/crd3.yaml \
402
+ --output ./src/generated
403
+
404
+ # Generate with status models
405
+ klasik generate-crd \
406
+ --url ./my-crd.yaml \
407
+ --output ./generated \
408
+ --include-status
409
+
410
+ # NestJS integration with validation
411
+ klasik generate-crd \
412
+ --url ./crds/ \
413
+ --output ./src/generated/k8s \
414
+ --nestjs-swagger \
415
+ --class-validator
416
+
417
+ # From local file with authentication (if downloading references)
418
+ klasik generate-crd \
419
+ --url ./local-crd.yaml \
420
+ --output ./generated \
421
+ --header "Authorization: Bearer token"
422
+
423
+ # Multi-CRD file
424
+ klasik generate-crd \
425
+ --url ./all-crds.yaml \
426
+ --output ./generated \
427
+ --include-status \
428
+ --nestjs-swagger
429
+ ```
430
+
431
+ **Output Structure:**
432
+
433
+ For a single CRD:
434
+ ```
435
+ output/
436
+ β”œβ”€β”€ v1alpha1/
437
+ β”‚ └── models/
438
+ β”‚ β”œβ”€β”€ my-resource.ts
439
+ β”‚ β”œβ”€β”€ my-resource-spec.ts
440
+ β”‚ β”œβ”€β”€ my-resource-status.ts (if --include-status)
441
+ β”‚ └── ...
442
+ └── index.ts
443
+ ```
444
+
445
+ For multiple CRDs:
446
+ ```
447
+ output/
448
+ β”œβ”€β”€ AppProject/
449
+ β”‚ β”œβ”€β”€ v1alpha1/
450
+ β”‚ └── index.ts
451
+ β”œβ”€β”€ Application/
452
+ β”‚ β”œβ”€β”€ v1alpha1/
453
+ β”‚ └── index.ts
454
+ └── index.ts
455
+ ```
456
+
204
457
  ## Programmatic API
205
458
 
206
459
  ### K8sClientGenerator
@@ -250,6 +503,59 @@ console.log(`Spec downloaded to: ${specPath}`);
250
503
  downloader.cleanupTemp();
251
504
  ```
252
505
 
506
+ ### CRDGenerator
507
+
508
+ Generate TypeScript models from Kubernetes CustomResourceDefinitions programmatically:
509
+
510
+ ```typescript
511
+ import { CRDGenerator } from 'klasik';
512
+
513
+ const generator = new CRDGenerator();
514
+
515
+ await generator.generate({
516
+ url: 'https://raw.githubusercontent.com/argoproj/argo-cd/master/manifests/crds/appproject-crd.yaml',
517
+ outputDir: './generated/crds',
518
+ includeStatus: true, // Generate status models
519
+ nestJsSwagger: true, // Include @ApiProperty decorators
520
+ classValidator: true, // Include validation decorators
521
+ fixEsmImports: false, // Add .js extensions
522
+ headers: {
523
+ 'Authorization': 'Bearer token123'
524
+ },
525
+ timeout: 60000
526
+ });
527
+ ```
528
+
529
+ **CRDGeneratorOptions:**
530
+ - `url: string` - URL or file path to CRD YAML (required)
531
+ - `outputDir: string` - Output directory (required)
532
+ - `includeStatus?: boolean` - Generate status schemas (default: false)
533
+ - `headers?: Record<string, string>` - Custom HTTP headers
534
+ - `timeout?: number` - Request timeout in milliseconds (default: 30000)
535
+ - `fixEsmImports?: boolean` - Add .js extensions for ESM (default: false)
536
+ - `nestJsSwagger?: boolean` - Include NestJS decorators (default: false)
537
+ - `classValidator?: boolean` - Include validation decorators (default: false)
538
+ - `skipJsExtensions?: boolean` - Skip .js extensions (default: false)
539
+ - `templateDir?: string` - Custom template directory
540
+ - `keepSpec?: boolean` - Keep intermediate OpenAPI specs (default: false)
541
+
542
+ **Multi-CRD YAML:**
543
+
544
+ The CRDGenerator automatically handles multi-document YAML files:
545
+
546
+ ```typescript
547
+ // This YAML contains multiple CRDs separated by ---
548
+ await generator.generate({
549
+ url: './all-crds.yaml', // Contains AppProject, Application, etc.
550
+ outputDir: './generated',
551
+ includeStatus: true
552
+ });
553
+
554
+ // Output will be organized by CRD kind
555
+ // ./generated/AppProject/v1alpha1/...
556
+ // ./generated/Application/v1alpha1/...
557
+ ```
558
+
253
559
  ## Generated Client Features
254
560
 
255
561
  The generated TypeScript client includes:
package/dist/cli.js CHANGED
@@ -134,4 +134,55 @@ 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(s) or file path(s) to CRD YAML files (can be specified multiple times)')
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
+ // Handle both single URL (backwards compat) and multiple URLs
168
+ const urls = Array.isArray(options.url) ? options.url : [options.url];
169
+ await generator.generate({
170
+ urls,
171
+ outputDir,
172
+ includeStatus: options.includeStatus,
173
+ headers: Object.keys(headers).length > 0 ? headers : undefined,
174
+ timeout: parseInt(options.timeout, 10),
175
+ fixEsmImports: options.esm,
176
+ nestJsSwagger: options.nestjsSwagger,
177
+ classValidator: options.classValidator,
178
+ templateDir: options.template,
179
+ keepSpec: options.keepSpec,
180
+ });
181
+ process.exit(0);
182
+ }
183
+ catch (error) {
184
+ console.error('Error:', error instanceof Error ? error.message : error);
185
+ process.exit(1);
186
+ }
187
+ });
137
188
  program.parse();
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Options for CRD client generation
3
+ */
4
+ export interface CRDGeneratorOptions {
5
+ /**
6
+ * URL(s) or file path(s) to CRD YAML file(s)
7
+ * Can be a single URL string or array of URLs
8
+ */
9
+ urls: string | string[];
10
+ /**
11
+ * Output directory for generated models
12
+ */
13
+ outputDir: string;
14
+ /**
15
+ * Whether to include status schemas in generation
16
+ * @default false
17
+ */
18
+ includeStatus?: boolean;
19
+ /**
20
+ * Custom headers for downloading CRDs from URLs
21
+ */
22
+ headers?: Record<string, string>;
23
+ /**
24
+ * Request timeout for downloading specs in milliseconds
25
+ * @default 30000
26
+ */
27
+ timeout?: number;
28
+ /**
29
+ * Whether to fix ESM imports by adding .js extensions
30
+ * @default false
31
+ */
32
+ fixEsmImports?: boolean;
33
+ /**
34
+ * Include NestJS Swagger @ApiProperty decorators
35
+ * @default false
36
+ */
37
+ nestJsSwagger?: boolean;
38
+ /**
39
+ * Include class-validator decorators
40
+ * @default false
41
+ */
42
+ classValidator?: boolean;
43
+ /**
44
+ * Skip adding .js extensions to imports/exports
45
+ * @default false
46
+ */
47
+ skipJsExtensions?: boolean;
48
+ /**
49
+ * Custom template directory
50
+ */
51
+ templateDir?: string;
52
+ /**
53
+ * Whether to keep the intermediate OpenAPI specs
54
+ * @default false
55
+ */
56
+ keepSpec?: boolean;
57
+ }
58
+ /**
59
+ * Main orchestrator for generating TypeScript models from Kubernetes CRDs
60
+ */
61
+ export declare class CRDGenerator {
62
+ private parser;
63
+ private converter;
64
+ private k8sGenerator;
65
+ constructor();
66
+ /**
67
+ * Main generation workflow
68
+ * @param options Generation options
69
+ */
70
+ generate(options: CRDGeneratorOptions): Promise<void>;
71
+ /**
72
+ * Process a single CRD
73
+ * @param crd Parsed CRD
74
+ * @param outputDir Output directory for this CRD
75
+ * @param options Generation options
76
+ * @returns Array of version directory names
77
+ */
78
+ private processCRD;
79
+ /**
80
+ * Generate index file for a CRD (when multiple CRDs in one file)
81
+ * @param crdDir CRD directory
82
+ * @param versions Array of version names
83
+ */
84
+ private generateCRDIndex;
85
+ /**
86
+ * Generate main index file (when multiple CRDs in one file)
87
+ * @param outputDir Output directory
88
+ * @param crdNames Array of CRD kind names
89
+ */
90
+ private generateMainIndex;
91
+ /**
92
+ * Generate version index file (for single CRD)
93
+ * @param outputDir Output directory
94
+ * @param versions Array of version names
95
+ */
96
+ private generateVersionIndex;
97
+ /**
98
+ * Load CRD file from URL or local path
99
+ * @param url URL or file path
100
+ * @param headers Optional HTTP headers
101
+ * @param timeout Optional timeout in milliseconds
102
+ * @returns CRD file content as string
103
+ */
104
+ private loadCRDFile;
105
+ /**
106
+ * Check if the URL is a local file path
107
+ */
108
+ private isLocalFile;
109
+ /**
110
+ * Load CRD from local file
111
+ */
112
+ private loadLocalCRDFile;
113
+ }