klasik 2.0.8 โ 2.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/README.md +710 -3
- package/dist/bin/go-schema-gen +0 -0
- package/dist/builders/class-builder.d.ts +1 -0
- package/dist/builders/class-builder.d.ts.map +1 -1
- package/dist/builders/class-builder.js.map +1 -1
- package/dist/cli/commands/generate-crd.d.ts +1 -0
- package/dist/cli/commands/generate-crd.d.ts.map +1 -1
- package/dist/cli/commands/generate-crd.js +2 -0
- package/dist/cli/commands/generate-crd.js.map +1 -1
- package/dist/cli/commands/generate-go.d.ts +22 -0
- package/dist/cli/commands/generate-go.d.ts.map +1 -0
- package/dist/cli/commands/generate-go.js +130 -0
- package/dist/cli/commands/generate-go.js.map +1 -0
- package/dist/cli/commands/generate-jsonschema.d.ts +1 -0
- package/dist/cli/commands/generate-jsonschema.d.ts.map +1 -1
- package/dist/cli/commands/generate-jsonschema.js +2 -0
- package/dist/cli/commands/generate-jsonschema.js.map +1 -1
- package/dist/cli/commands/generate.d.ts +1 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +2 -0
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/index.js +3 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/options.d.ts +4 -0
- package/dist/cli/utils/options.d.ts.map +1 -1
- package/dist/cli/utils/options.js +7 -0
- package/dist/cli/utils/options.js.map +1 -1
- package/dist/generator/generator.d.ts.map +1 -1
- package/dist/generator/generator.js +4 -0
- package/dist/generator/generator.js.map +1 -1
- package/dist/loaders/go-schema-loader.d.ts +60 -0
- package/dist/loaders/go-schema-loader.d.ts.map +1 -0
- package/dist/loaders/go-schema-loader.js +221 -0
- package/dist/loaders/go-schema-loader.js.map +1 -0
- package/dist/plugins/ajv-validator-plugin.d.ts +45 -0
- package/dist/plugins/ajv-validator-plugin.d.ts.map +1 -0
- package/dist/plugins/ajv-validator-plugin.js +320 -0
- package/dist/plugins/ajv-validator-plugin.js.map +1 -0
- package/package.json +5 -3
- package/tools/go-schema-gen/README.md +147 -0
- package/tools/go-schema-gen/build.sh +24 -0
- package/tools/go-schema-gen/comment_extractor.go +128 -0
- package/tools/go-schema-gen/go-schema-gen +0 -0
- package/tools/go-schema-gen/go.mod +36 -0
- package/tools/go-schema-gen/go.sum +112 -0
- package/tools/go-schema-gen/main.go +155 -0
- package/tools/go-schema-gen/registry.go +35 -0
package/README.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# Klasik
|
|
2
2
|
|
|
3
|
-
Generate TypeScript clients from OpenAPI specifications, Kubernetes CRDs,
|
|
3
|
+
Generate TypeScript clients from OpenAPI specifications, Kubernetes CRDs, JSON Schema, and Go structs with full type safety and class-transformer support.
|
|
4
4
|
|
|
5
5
|
Perfect for:
|
|
6
6
|
- ๐ Kubernetes operators and controllers
|
|
7
7
|
- ๐ง REST API clients with type safety
|
|
8
8
|
- ๐ฆ NestJS backend services
|
|
9
9
|
- ๐ฏ Type-safe microservice communication
|
|
10
|
+
- ๐ Go-to-TypeScript code sharing
|
|
10
11
|
|
|
11
12
|
## Features
|
|
12
13
|
|
|
@@ -14,13 +15,14 @@ Perfect for:
|
|
|
14
15
|
๐ฏ **Type-Safe** - Full TypeScript support with strict typing
|
|
15
16
|
๐ **class-transformer** - Automatic serialization/deserialization
|
|
16
17
|
โ
**class-validator** - Built-in validation decorators
|
|
18
|
+
๐ **Ajv JSON Schema** - Draft 2020-12 validation with deep nesting support
|
|
17
19
|
๐จ **NestJS Ready** - @ApiProperty decorators out of the box
|
|
18
|
-
๐ฆ **Multiple Formats** - OpenAPI, Kubernetes CRDs, JSON Schema
|
|
20
|
+
๐ฆ **Multiple Formats** - OpenAPI, Kubernetes CRDs, JSON Schema, Go structs
|
|
19
21
|
๐ **ESM Support** - Modern JavaScript modules with .js extensions
|
|
20
22
|
๐ **External $refs** - Automatic resolution of external schemas
|
|
21
23
|
๐ญ **Custom Templates** - Mustache-based customization
|
|
22
24
|
โ๏ธ **Flexible Output** - Multiple export styles (namespace, direct, both)
|
|
23
|
-
๐งช **Well Tested** - Comprehensive test coverage (
|
|
25
|
+
๐งช **Well Tested** - Comprehensive test coverage (797 passing tests)
|
|
24
26
|
๐ **Production Ready** - Used in real-world projects
|
|
25
27
|
๐ **Full CLI** - Rich command-line interface with 4 commands
|
|
26
28
|
๐ **Authentication** - Custom headers including Bearer tokens
|
|
@@ -62,6 +64,17 @@ klasik generate-jsonschema \
|
|
|
62
64
|
--output ./src/generated
|
|
63
65
|
```
|
|
64
66
|
|
|
67
|
+
Generate from Go structs (requires Go installed, auto-setup on first use):
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
klasik generate-go \
|
|
71
|
+
--type "helm.sh/helm/v3/pkg/chart.Metadata" \
|
|
72
|
+
--type "helm.sh/helm/v3/pkg/chart.Chart" \
|
|
73
|
+
--output ./src/generated \
|
|
74
|
+
--class-validator \
|
|
75
|
+
--nestjs-swagger
|
|
76
|
+
```
|
|
77
|
+
|
|
65
78
|
#### Bare Mode
|
|
66
79
|
|
|
67
80
|
Generate models directly in the output directory without wrapper structure:
|
|
@@ -238,6 +251,416 @@ const tasks = await api.listTasks();
|
|
|
238
251
|
|
|
239
252
|
For more details, see the [Validation Guide](./docs/validation.md).
|
|
240
253
|
|
|
254
|
+
## Ajv JSON Schema Validation
|
|
255
|
+
|
|
256
|
+
Klasik can generate Ajv-based JSON Schema validation alongside or instead of class-validator decorators. This provides comprehensive JSON Schema Draft 2020-12 validation with deep nested object support and optimized performance.
|
|
257
|
+
|
|
258
|
+
### Why Ajv Validation?
|
|
259
|
+
|
|
260
|
+
**Advantages over class-validator:**
|
|
261
|
+
- โ
**Full JSON Schema compliance** - Supports all Draft 2020-12 features
|
|
262
|
+
- โ
**Deep nested validation** - Automatically validates nested objects at all levels
|
|
263
|
+
- โ
**Performance optimized** - Schema compilation is cached per class
|
|
264
|
+
- โ
**Standards-based** - Uses industry-standard JSON Schema format
|
|
265
|
+
- โ
**Independent** - Works alongside or without class-validator
|
|
266
|
+
|
|
267
|
+
**When to use:**
|
|
268
|
+
- Complex nested object structures (User โ Address โ Coordinates)
|
|
269
|
+
- JSON Schema-first development workflows
|
|
270
|
+
- Need for format validation (email, uuid, date-time, etc.)
|
|
271
|
+
- Projects requiring JSON Schema compliance
|
|
272
|
+
- High-performance validation scenarios
|
|
273
|
+
|
|
274
|
+
### Basic Usage
|
|
275
|
+
|
|
276
|
+
Enable with the `--use-ajv` flag:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
klasik generate \
|
|
280
|
+
--url https://api.example.com/openapi.json \
|
|
281
|
+
--output ./generated \
|
|
282
|
+
--use-ajv
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Generated Code Structure
|
|
286
|
+
|
|
287
|
+
Each generated class includes:
|
|
288
|
+
|
|
289
|
+
1. **`static getSchema()`** - Returns the JSON Schema
|
|
290
|
+
2. **`static validateWithJsonSchema(data)`** - Validates data against the schema
|
|
291
|
+
3. **Private cached validator** - Optimized for performance
|
|
292
|
+
|
|
293
|
+
**Example generated class:**
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import { Ajv } from "ajv";
|
|
297
|
+
import { addFormats } from "ajv-formats";
|
|
298
|
+
import { Expose } from "class-transformer";
|
|
299
|
+
|
|
300
|
+
export class User {
|
|
301
|
+
/**
|
|
302
|
+
* Get JSON Schema for User
|
|
303
|
+
* @returns JSON Schema Draft 2020-12
|
|
304
|
+
*/
|
|
305
|
+
static getSchema(): object {
|
|
306
|
+
return {
|
|
307
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
308
|
+
"type": "object",
|
|
309
|
+
"properties": {
|
|
310
|
+
"name": {
|
|
311
|
+
"type": "string",
|
|
312
|
+
"minLength": 1
|
|
313
|
+
},
|
|
314
|
+
"email": {
|
|
315
|
+
"type": "string",
|
|
316
|
+
"format": "email"
|
|
317
|
+
},
|
|
318
|
+
"address": {
|
|
319
|
+
"type": "object"
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
"additionalProperties": false,
|
|
323
|
+
"required": ["name", "email"]
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
private static _ajvInstance: Ajv | null = null;
|
|
328
|
+
private static _compiledValidator: any = null;
|
|
329
|
+
|
|
330
|
+
/** Get or create Ajv instance for User */
|
|
331
|
+
private static getAjvInstance(): Ajv {
|
|
332
|
+
if (!this._ajvInstance) {
|
|
333
|
+
this._ajvInstance = new Ajv({ allErrors: true, strict: false });
|
|
334
|
+
addFormats(this._ajvInstance);
|
|
335
|
+
}
|
|
336
|
+
return this._ajvInstance;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/** Get or create compiled validator for User (cached for performance) */
|
|
340
|
+
private static getCompiledValidator(): any {
|
|
341
|
+
if (!this._compiledValidator) {
|
|
342
|
+
const ajv = this.getAjvInstance();
|
|
343
|
+
const schema = this.getSchema();
|
|
344
|
+
this._compiledValidator = ajv.compile(schema);
|
|
345
|
+
}
|
|
346
|
+
return this._compiledValidator;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Validate data against JSON Schema with recursive nested validation
|
|
351
|
+
* @param data - Data to validate
|
|
352
|
+
* @returns Validation result with errors if any
|
|
353
|
+
*/
|
|
354
|
+
static validateWithJsonSchema(data: unknown): { valid: boolean; errors: any[] } {
|
|
355
|
+
const validate = this.getCompiledValidator();
|
|
356
|
+
const valid = validate(data);
|
|
357
|
+
|
|
358
|
+
// Collect errors
|
|
359
|
+
const allErrors: any[] = validate.errors || [];
|
|
360
|
+
|
|
361
|
+
// Recursively validate nested objects that have validateWithJsonSchema method
|
|
362
|
+
if (valid && typeof data === "object" && data !== null) {
|
|
363
|
+
for (const [key, value] of Object.entries(data)) {
|
|
364
|
+
if (value && typeof value === "object") {
|
|
365
|
+
const constructor = (value as any).constructor;
|
|
366
|
+
if (constructor && typeof constructor.validateWithJsonSchema === "function") {
|
|
367
|
+
const nestedResult = constructor.validateWithJsonSchema(value);
|
|
368
|
+
if (!nestedResult.valid) {
|
|
369
|
+
allErrors.push(...nestedResult.errors.map((e: any) => ({
|
|
370
|
+
...e,
|
|
371
|
+
instancePath: `/${key}${e.instancePath || ""}`
|
|
372
|
+
})));
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
return { valid: allErrors.length === 0, errors: allErrors };
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
@Expose()
|
|
383
|
+
name: string;
|
|
384
|
+
|
|
385
|
+
@Expose()
|
|
386
|
+
email: string;
|
|
387
|
+
|
|
388
|
+
@Expose()
|
|
389
|
+
address?: Address;
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Using Validation Methods
|
|
394
|
+
|
|
395
|
+
**Valid data:**
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
import { User } from './generated/models';
|
|
399
|
+
|
|
400
|
+
const userData = {
|
|
401
|
+
name: 'John Doe',
|
|
402
|
+
email: 'john@example.com'
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
const result = User.validateWithJsonSchema(userData);
|
|
406
|
+
|
|
407
|
+
if (result.valid) {
|
|
408
|
+
console.log('โ
Data is valid!');
|
|
409
|
+
} else {
|
|
410
|
+
console.error('โ Validation failed:', result.errors);
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**Invalid data:**
|
|
415
|
+
|
|
416
|
+
```typescript
|
|
417
|
+
const invalidData = {
|
|
418
|
+
name: '', // minLength: 1 violation
|
|
419
|
+
email: 'not-an-email' // format: email violation
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
const result = User.validateWithJsonSchema(invalidData);
|
|
423
|
+
|
|
424
|
+
console.log(result);
|
|
425
|
+
// {
|
|
426
|
+
// valid: false,
|
|
427
|
+
// errors: [
|
|
428
|
+
// {
|
|
429
|
+
// instancePath: '/name',
|
|
430
|
+
// schemaPath: '#/properties/name/minLength',
|
|
431
|
+
// keyword: 'minLength',
|
|
432
|
+
// params: { limit: 1 },
|
|
433
|
+
// message: 'must NOT have fewer than 1 characters'
|
|
434
|
+
// },
|
|
435
|
+
// {
|
|
436
|
+
// instancePath: '/email',
|
|
437
|
+
// schemaPath: '#/properties/email/format',
|
|
438
|
+
// keyword: 'format',
|
|
439
|
+
// params: { format: 'email' },
|
|
440
|
+
// message: 'must match format "email"'
|
|
441
|
+
// }
|
|
442
|
+
// ]
|
|
443
|
+
// }
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Deep Nested Validation
|
|
447
|
+
|
|
448
|
+
The validator automatically validates nested objects recursively:
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
import { User, Address } from './generated/models';
|
|
452
|
+
|
|
453
|
+
// Create nested structure
|
|
454
|
+
const address = new Address();
|
|
455
|
+
address.street = ''; // Invalid: minLength violation
|
|
456
|
+
address.city = 'Springfield';
|
|
457
|
+
address.zipCode = 'INVALID'; // Invalid: pattern violation
|
|
458
|
+
|
|
459
|
+
const user = {
|
|
460
|
+
name: 'John Doe',
|
|
461
|
+
email: 'john@example.com',
|
|
462
|
+
address // Nested object
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
const result = User.validateWithJsonSchema(user);
|
|
466
|
+
|
|
467
|
+
console.log(result);
|
|
468
|
+
// {
|
|
469
|
+
// valid: false,
|
|
470
|
+
// errors: [
|
|
471
|
+
// {
|
|
472
|
+
// instancePath: '/address/street',
|
|
473
|
+
// keyword: 'minLength',
|
|
474
|
+
// message: 'must NOT have fewer than 1 characters'
|
|
475
|
+
// },
|
|
476
|
+
// {
|
|
477
|
+
// instancePath: '/address/zipCode',
|
|
478
|
+
// keyword: 'pattern',
|
|
479
|
+
// message: 'must match pattern "^[0-9]{5}$"'
|
|
480
|
+
// }
|
|
481
|
+
// ]
|
|
482
|
+
// }
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
**Note:** Error paths include the full nested path (`/address/street`), making it easy to identify exactly where validation failed.
|
|
486
|
+
|
|
487
|
+
### Supported Validations
|
|
488
|
+
|
|
489
|
+
All JSON Schema Draft 2020-12 validation keywords are supported:
|
|
490
|
+
|
|
491
|
+
**String constraints:**
|
|
492
|
+
- `minLength`, `maxLength`
|
|
493
|
+
- `pattern` (regex)
|
|
494
|
+
- `format` (email, uuid, date-time, uri, etc.)
|
|
495
|
+
|
|
496
|
+
**Numeric constraints:**
|
|
497
|
+
- `minimum`, `maximum`
|
|
498
|
+
- `exclusiveMinimum`, `exclusiveMaximum`
|
|
499
|
+
- `multipleOf`
|
|
500
|
+
|
|
501
|
+
**Array constraints:**
|
|
502
|
+
- `minItems`, `maxItems`
|
|
503
|
+
- `uniqueItems`
|
|
504
|
+
|
|
505
|
+
**Object constraints:**
|
|
506
|
+
- `required` properties
|
|
507
|
+
- `additionalProperties`
|
|
508
|
+
|
|
509
|
+
**Other:**
|
|
510
|
+
- `enum` values
|
|
511
|
+
- `nullable` types
|
|
512
|
+
- Union types with `anyOf`
|
|
513
|
+
|
|
514
|
+
### Performance Optimization
|
|
515
|
+
|
|
516
|
+
The generated code includes **compilation caching** for optimal performance:
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
// First validation: Schema is compiled and cached
|
|
520
|
+
User.validateWithJsonSchema(data1); // Compile + Validate
|
|
521
|
+
|
|
522
|
+
// Subsequent validations: Uses cached compiled validator
|
|
523
|
+
User.validateWithJsonSchema(data2); // Validate only (fast!)
|
|
524
|
+
User.validateWithJsonSchema(data3); // Validate only (fast!)
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Benefits:**
|
|
528
|
+
- Schema compiled once per class, not per validation
|
|
529
|
+
- Significant performance improvement for repeated validations
|
|
530
|
+
- Singleton Ajv instance shared across validations
|
|
531
|
+
|
|
532
|
+
### Combining with class-validator
|
|
533
|
+
|
|
534
|
+
You can use both validation approaches together:
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
klasik generate \
|
|
538
|
+
--url https://api.example.com/openapi.json \
|
|
539
|
+
--output ./generated \
|
|
540
|
+
--class-validator \
|
|
541
|
+
--use-ajv
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
**Generated class has both:**
|
|
545
|
+
|
|
546
|
+
```typescript
|
|
547
|
+
export class User {
|
|
548
|
+
// class-validator decorators
|
|
549
|
+
@IsString()
|
|
550
|
+
@MinLength(1)
|
|
551
|
+
@Expose()
|
|
552
|
+
name: string;
|
|
553
|
+
|
|
554
|
+
@IsEmail()
|
|
555
|
+
@Expose()
|
|
556
|
+
email: string;
|
|
557
|
+
|
|
558
|
+
// PLUS Ajv validation methods
|
|
559
|
+
static getSchema(): object { /* ... */ }
|
|
560
|
+
static validateWithJsonSchema(data: unknown) { /* ... */ }
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
**Use case:** Runtime validation with class-validator in NestJS controllers, plus JSON Schema validation for external integrations.
|
|
565
|
+
|
|
566
|
+
### Dependencies
|
|
567
|
+
|
|
568
|
+
When using `--use-ajv`, the following dependencies are automatically added to `package.json`:
|
|
569
|
+
|
|
570
|
+
```json
|
|
571
|
+
{
|
|
572
|
+
"dependencies": {
|
|
573
|
+
"ajv": "^8.12.0",
|
|
574
|
+
"ajv-formats": "^2.1.1"
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
Install them in your project:
|
|
580
|
+
|
|
581
|
+
```bash
|
|
582
|
+
cd generated
|
|
583
|
+
npm install
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### Complete Example
|
|
587
|
+
|
|
588
|
+
```bash
|
|
589
|
+
# Generate models with Ajv validation
|
|
590
|
+
klasik generate-jsonschema \
|
|
591
|
+
--url ./schemas/user.json \
|
|
592
|
+
--output ./src/models \
|
|
593
|
+
--use-ajv
|
|
594
|
+
|
|
595
|
+
# Use in your code
|
|
596
|
+
cat > example.ts << 'EOF'
|
|
597
|
+
import { User } from './src/models';
|
|
598
|
+
|
|
599
|
+
// Valid user
|
|
600
|
+
const validUser = {
|
|
601
|
+
name: 'Alice Smith',
|
|
602
|
+
email: 'alice@example.com',
|
|
603
|
+
age: 30
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
const result1 = User.validateWithJsonSchema(validUser);
|
|
607
|
+
console.log('Valid:', result1.valid); // true
|
|
608
|
+
|
|
609
|
+
// Invalid user
|
|
610
|
+
const invalidUser = {
|
|
611
|
+
name: '', // Too short
|
|
612
|
+
email: 'invalid-email',
|
|
613
|
+
age: -5 // Negative age
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const result2 = User.validateWithJsonSchema(invalidUser);
|
|
617
|
+
console.log('Valid:', result2.valid); // false
|
|
618
|
+
console.log('Errors:', result2.errors);
|
|
619
|
+
// [
|
|
620
|
+
// { instancePath: '/name', message: 'must NOT have fewer than 1 characters' },
|
|
621
|
+
// { instancePath: '/email', message: 'must match format "email"' },
|
|
622
|
+
// { instancePath: '/age', message: 'must be >= 0' }
|
|
623
|
+
// ]
|
|
624
|
+
EOF
|
|
625
|
+
|
|
626
|
+
npx ts-node example.ts
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### Advanced: Accessing the JSON Schema
|
|
630
|
+
|
|
631
|
+
You can access the generated JSON Schema directly:
|
|
632
|
+
|
|
633
|
+
```typescript
|
|
634
|
+
import { User } from './generated/models';
|
|
635
|
+
|
|
636
|
+
// Get the schema
|
|
637
|
+
const schema = User.getSchema();
|
|
638
|
+
|
|
639
|
+
console.log(JSON.stringify(schema, null, 2));
|
|
640
|
+
// {
|
|
641
|
+
// "$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
642
|
+
// "type": "object",
|
|
643
|
+
// "properties": {
|
|
644
|
+
// "name": { "type": "string", "minLength": 1 },
|
|
645
|
+
// "email": { "type": "string", "format": "email" }
|
|
646
|
+
// },
|
|
647
|
+
// "required": ["name", "email"],
|
|
648
|
+
// "additionalProperties": false
|
|
649
|
+
// }
|
|
650
|
+
|
|
651
|
+
// Use with external JSON Schema validators
|
|
652
|
+
import Ajv from 'ajv';
|
|
653
|
+
const ajv = new Ajv();
|
|
654
|
+
const validate = ajv.compile(User.getSchema());
|
|
655
|
+
validate(data);
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
**Use cases:**
|
|
659
|
+
- Generating OpenAPI documentation
|
|
660
|
+
- Sharing schemas with other systems
|
|
661
|
+
- Custom validation workflows
|
|
662
|
+
- Schema introspection
|
|
663
|
+
|
|
241
664
|
## CLI Commands
|
|
242
665
|
|
|
243
666
|
### `klasik generate`
|
|
@@ -262,6 +685,7 @@ klasik generate [options]
|
|
|
262
685
|
| `--skip-js-extensions` | Skip .js extensions (for bundlers) | `false` |
|
|
263
686
|
| `--nestjs-swagger` | Add @ApiProperty decorators | `false` |
|
|
264
687
|
| `--class-validator` | Add class-validator decorators | `false` |
|
|
688
|
+
| `--use-ajv` | Add Ajv JSON Schema validation methods | `false` |
|
|
265
689
|
| `--header <header>` | Custom header (repeatable) | - |
|
|
266
690
|
| `--timeout <ms>` | Request timeout | `30000` |
|
|
267
691
|
| `--template <dir>` | Custom template directory | - |
|
|
@@ -292,6 +716,19 @@ klasik generate \
|
|
|
292
716
|
--nestjs-swagger \
|
|
293
717
|
--class-validator
|
|
294
718
|
|
|
719
|
+
# With Ajv JSON Schema validation
|
|
720
|
+
klasik generate \
|
|
721
|
+
--url https://api.example.com/spec.json \
|
|
722
|
+
--output ./src/api \
|
|
723
|
+
--use-ajv
|
|
724
|
+
|
|
725
|
+
# With both class-validator and Ajv
|
|
726
|
+
klasik generate \
|
|
727
|
+
--url https://api.example.com/spec.json \
|
|
728
|
+
--output ./src/api \
|
|
729
|
+
--class-validator \
|
|
730
|
+
--use-ajv
|
|
731
|
+
|
|
295
732
|
# With external refs and authentication
|
|
296
733
|
klasik generate \
|
|
297
734
|
--url https://api.example.com/spec.json \
|
|
@@ -373,6 +810,7 @@ klasik generate-crd [options]
|
|
|
373
810
|
| `--crd-kind-case <format>` | Folder naming: `pascal`, `snake`, `kebab` | `pascal` |
|
|
374
811
|
| `--nestjs-swagger` | Add @ApiProperty decorators | `false` |
|
|
375
812
|
| `--class-validator` | Add class-validator decorators | `false` |
|
|
813
|
+
| `--use-ajv` | Add Ajv JSON Schema validation methods | `false` |
|
|
376
814
|
| `--esm` | Add .js extensions for ESM | `false` |
|
|
377
815
|
| `--header <header>` | Custom header (repeatable) | - |
|
|
378
816
|
| `--resolve-refs` | Resolve external $ref files | `false` |
|
|
@@ -428,6 +866,7 @@ klasik generate-jsonschema [options]
|
|
|
428
866
|
| `-o, --output <dir>` | Output directory (required) | - |
|
|
429
867
|
| `--nestjs-swagger` | Add @ApiProperty decorators | `false` |
|
|
430
868
|
| `--class-validator` | Add class-validator decorators | `false` |
|
|
869
|
+
| `--use-ajv` | Add Ajv JSON Schema validation methods | `false` |
|
|
431
870
|
| `--esm` | Add .js extensions for ESM | `false` |
|
|
432
871
|
| `--header <header>` | Custom header (repeatable) | - |
|
|
433
872
|
| `--resolve-refs` | Resolve external $ref files | `false` |
|
|
@@ -455,8 +894,87 @@ klasik generate-jsonschema \
|
|
|
455
894
|
--output ./src/types \
|
|
456
895
|
--nestjs-swagger \
|
|
457
896
|
--class-validator
|
|
897
|
+
|
|
898
|
+
# With Ajv JSON Schema validation
|
|
899
|
+
klasik generate-jsonschema \
|
|
900
|
+
--url ./schemas/user.json \
|
|
901
|
+
--output ./src/types \
|
|
902
|
+
--use-ajv
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
### `klasik generate-go`
|
|
906
|
+
|
|
907
|
+
Generate TypeScript models from Go structs using runtime reflection.
|
|
908
|
+
|
|
909
|
+
**Usage:**
|
|
910
|
+
|
|
911
|
+
```bash
|
|
912
|
+
klasik generate-go [options]
|
|
458
913
|
```
|
|
459
914
|
|
|
915
|
+
**Options:**
|
|
916
|
+
|
|
917
|
+
| Option | Description | Default |
|
|
918
|
+
|--------|-------------|---------|
|
|
919
|
+
| `-t, --type <type>` | Go type path (package.Type) (repeatable, required) | - |
|
|
920
|
+
| `-o, --output <dir>` | Output directory (required) | - |
|
|
921
|
+
| `--nestjs-swagger` | Add @ApiProperty decorators | `false` |
|
|
922
|
+
| `--class-validator` | Add class-validator decorators | `false` |
|
|
923
|
+
| `--use-ajv` | Add Ajv JSON Schema validation methods | `false` |
|
|
924
|
+
| `--esm` | Add .js extensions for ESM | `false` |
|
|
925
|
+
| `--template <dir>` | Custom template directory | - |
|
|
926
|
+
| `--export-style <style>` | Export style: `namespace`, `direct`, `both`, `none` | `namespace` |
|
|
927
|
+
| `--bare` | Generate models directly in output dir | `false` |
|
|
928
|
+
| `--go-tool-path <path>` | Path to go-schema-gen binary | auto-detected |
|
|
929
|
+
| `--allow-additional-properties` | Allow additional properties in JSON Schema | `false` |
|
|
930
|
+
|
|
931
|
+
**Prerequisites:**
|
|
932
|
+
- Go 1.21+ must be installed (first-time setup is automatic)
|
|
933
|
+
- Types must be registered in `tools/go-schema-gen/registry.go`
|
|
934
|
+
|
|
935
|
+
**Examples:**
|
|
936
|
+
|
|
937
|
+
```bash
|
|
938
|
+
# Generate from Helm chart types
|
|
939
|
+
klasik generate-go \
|
|
940
|
+
--type "helm.sh/helm/v3/pkg/chart.Metadata" \
|
|
941
|
+
--type "helm.sh/helm/v3/pkg/chart.Chart" \
|
|
942
|
+
--output ./src/helm-types \
|
|
943
|
+
--nestjs-swagger \
|
|
944
|
+
--class-validator
|
|
945
|
+
|
|
946
|
+
# Generate with Ajv validation
|
|
947
|
+
klasik generate-go \
|
|
948
|
+
--type "helm.sh/helm/v3/pkg/chart.Metadata" \
|
|
949
|
+
--output ./src/types \
|
|
950
|
+
--use-ajv
|
|
951
|
+
|
|
952
|
+
# Generate for ESM
|
|
953
|
+
klasik generate-go \
|
|
954
|
+
--type "helm.sh/helm/v3/pkg/chart.Chart" \
|
|
955
|
+
--output ./src/types \
|
|
956
|
+
--esm
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
**How it works:**
|
|
960
|
+
1. Uses Go reflection via `invopop/jsonschema` library
|
|
961
|
+
2. Generates JSON Schema from Go structs
|
|
962
|
+
3. Feeds to existing JsonSchemaParser
|
|
963
|
+
4. Generates TypeScript with full type safety
|
|
964
|
+
|
|
965
|
+
**Adding new types:**
|
|
966
|
+
|
|
967
|
+
Edit `tools/go-schema-gen/registry.go`:
|
|
968
|
+
```go
|
|
969
|
+
import mypackage "github.com/org/package"
|
|
970
|
+
|
|
971
|
+
var typeRegistry = map[string]interface{}{
|
|
972
|
+
"github.com/org/package.MyStruct": mypackage.MyStruct{},
|
|
973
|
+
}
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
Then rebuild: `cd tools/go-schema-gen && ./build.sh`
|
|
977
|
+
|
|
460
978
|
## Kubernetes CRD Support
|
|
461
979
|
|
|
462
980
|
Klasik can generate TypeScript models directly from Kubernetes CustomResourceDefinitions (CRDs). Perfect for working with custom Kubernetes resources like ArgoCD Applications, Cert-Manager Certificates, or your own custom resources.
|
|
@@ -573,6 +1091,193 @@ const pkg: Package = {
|
|
|
573
1091
|
// Full TypeScript intellisense and type checking!
|
|
574
1092
|
```
|
|
575
1093
|
|
|
1094
|
+
## Go Struct Support
|
|
1095
|
+
|
|
1096
|
+
Klasik can generate TypeScript models from Go structs using runtime reflection. Perfect for sharing types between Go backends and TypeScript frontends, or for generating types from existing Go packages like Helm, Kubernetes, or your own custom packages.
|
|
1097
|
+
|
|
1098
|
+
### Features
|
|
1099
|
+
|
|
1100
|
+
- โ
**Runtime reflection** - Uses Go's reflection API with `invopop/jsonschema`
|
|
1101
|
+
- โ
**Struct tag support** - Respects `json`, `yaml`, `jsonschema` tags
|
|
1102
|
+
- โ
**Multiple types** - Generate from multiple structs in one command
|
|
1103
|
+
- โ
**Automatic references** - Nested types resolved with $ref
|
|
1104
|
+
- โ
**Full decorator support** - NestJS, class-validator, class-transformer, Ajv
|
|
1105
|
+
- โ
**Production-ready** - Tested with Helm chart types
|
|
1106
|
+
|
|
1107
|
+
### Prerequisites
|
|
1108
|
+
|
|
1109
|
+
- **Go 1.21+** must be installed (download from [go.dev](https://go.dev/dl/))
|
|
1110
|
+
- Types must be registered in `tools/go-schema-gen/registry.go`
|
|
1111
|
+
|
|
1112
|
+
**Note:** The first time you use `generate-go`, Klasik will automatically:
|
|
1113
|
+
1. Check if Go is installed
|
|
1114
|
+
2. Download Go dependencies (`go mod tidy`)
|
|
1115
|
+
3. Build the Go schema generator tool
|
|
1116
|
+
|
|
1117
|
+
This only happens once - subsequent runs use the cached binary.
|
|
1118
|
+
|
|
1119
|
+
### How It Works
|
|
1120
|
+
|
|
1121
|
+
1. Go tool uses reflection to inspect struct at runtime
|
|
1122
|
+
2. Generates JSON Schema Draft 2020-12
|
|
1123
|
+
3. Feeds to existing JsonSchemaParser
|
|
1124
|
+
4. Generates TypeScript with full type safety
|
|
1125
|
+
|
|
1126
|
+
**Architecture:**
|
|
1127
|
+
```
|
|
1128
|
+
Go Struct โ Reflection โ JSON Schema โ JsonSchemaParser โ IR โ TypeScript
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
### Quick Start
|
|
1132
|
+
|
|
1133
|
+
First-time users: Just run the command! Klasik will automatically set up everything:
|
|
1134
|
+
|
|
1135
|
+
```bash
|
|
1136
|
+
klasik generate-go \
|
|
1137
|
+
--type "helm.sh/helm/v3/pkg/chart.Metadata" \
|
|
1138
|
+
--output ./src/helm-types
|
|
1139
|
+
|
|
1140
|
+
# Output:
|
|
1141
|
+
# Building Go schema generator (first time only)...
|
|
1142
|
+
# Installing Go dependencies...
|
|
1143
|
+
# Compiling Go tool...
|
|
1144
|
+
# โ Go tool built successfully
|
|
1145
|
+
# โ Generation complete!
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
Subsequent runs are instant (no rebuild needed):
|
|
1149
|
+
|
|
1150
|
+
```bash
|
|
1151
|
+
klasik generate-go \
|
|
1152
|
+
--type "helm.sh/helm/v3/pkg/chart.Chart" \
|
|
1153
|
+
--output ./src/helm-types \
|
|
1154
|
+
--nestjs-swagger \
|
|
1155
|
+
--class-validator
|
|
1156
|
+
```
|
|
1157
|
+
|
|
1158
|
+
### Struct Tag Mapping
|
|
1159
|
+
|
|
1160
|
+
Go struct tags are automatically converted to JSON Schema:
|
|
1161
|
+
|
|
1162
|
+
| Go Tag | Effect | JSON Schema |
|
|
1163
|
+
|--------|--------|-------------|
|
|
1164
|
+
| `json:"fieldName"` | Property name | `"properties": {"fieldName": {...}}` |
|
|
1165
|
+
| `json:",omitempty"` | Optional field | Not in `"required"` array |
|
|
1166
|
+
| `jsonschema:"required"` | Force required | Added to `"required"` array |
|
|
1167
|
+
| `jsonschema:"minLength=5"` | Validation | `"minLength": 5` |
|
|
1168
|
+
| `jsonschema:"pattern=^[A-Z]"` | Regex | `"pattern": "^[A-Z]"` |
|
|
1169
|
+
| `jsonschema_description:"..."` | Documentation | `"description": "..."` |
|
|
1170
|
+
|
|
1171
|
+
**Example Go Struct:**
|
|
1172
|
+
```go
|
|
1173
|
+
type Metadata struct {
|
|
1174
|
+
Name string `json:"name" jsonschema:"required,minLength=1"`
|
|
1175
|
+
Version string `json:"version" jsonschema:"required"`
|
|
1176
|
+
Description string `json:"description,omitempty"`
|
|
1177
|
+
}
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
**Generated TypeScript:**
|
|
1181
|
+
```typescript
|
|
1182
|
+
export class Metadata {
|
|
1183
|
+
@ApiProperty()
|
|
1184
|
+
@IsString()
|
|
1185
|
+
name: string;
|
|
1186
|
+
|
|
1187
|
+
@ApiProperty()
|
|
1188
|
+
@IsString()
|
|
1189
|
+
version: string;
|
|
1190
|
+
|
|
1191
|
+
@ApiProperty({ required: false })
|
|
1192
|
+
@IsOptional()
|
|
1193
|
+
@IsString()
|
|
1194
|
+
description?: string;
|
|
1195
|
+
}
|
|
1196
|
+
```
|
|
1197
|
+
|
|
1198
|
+
### Adding New Types
|
|
1199
|
+
|
|
1200
|
+
To add new Go packages/types:
|
|
1201
|
+
|
|
1202
|
+
1. Edit `tools/go-schema-gen/registry.go`:
|
|
1203
|
+
```go
|
|
1204
|
+
import (
|
|
1205
|
+
chart "helm.sh/helm/v3/pkg/chart"
|
|
1206
|
+
mypackage "github.com/org/package"
|
|
1207
|
+
)
|
|
1208
|
+
|
|
1209
|
+
var typeRegistry = map[string]interface{}{
|
|
1210
|
+
// Existing types
|
|
1211
|
+
"helm.sh/helm/v3/pkg/chart.Metadata": chart.Metadata{},
|
|
1212
|
+
|
|
1213
|
+
// Add your types
|
|
1214
|
+
"github.com/org/package.MyStruct": mypackage.MyStruct{},
|
|
1215
|
+
}
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
2. Update dependencies:
|
|
1219
|
+
```bash
|
|
1220
|
+
cd tools/go-schema-gen
|
|
1221
|
+
go mod tidy
|
|
1222
|
+
```
|
|
1223
|
+
|
|
1224
|
+
3. Rebuild the tool:
|
|
1225
|
+
```bash
|
|
1226
|
+
./build.sh
|
|
1227
|
+
```
|
|
1228
|
+
|
|
1229
|
+
4. Use your new type:
|
|
1230
|
+
```bash
|
|
1231
|
+
klasik generate-go \
|
|
1232
|
+
--type "github.com/org/package.MyStruct" \
|
|
1233
|
+
--output ./src/types
|
|
1234
|
+
```
|
|
1235
|
+
|
|
1236
|
+
### Limitations
|
|
1237
|
+
|
|
1238
|
+
- **Type Registry Required** - Types must be pre-registered (no dynamic loading)
|
|
1239
|
+
- **Requires Recompilation** - Adding new packages requires rebuilding the Go tool
|
|
1240
|
+
- **Go Installation** - Go must be installed on the system
|
|
1241
|
+
|
|
1242
|
+
### Troubleshooting
|
|
1243
|
+
|
|
1244
|
+
**"Go is not installed" error:**
|
|
1245
|
+
```bash
|
|
1246
|
+
# Install Go from https://go.dev/dl/
|
|
1247
|
+
# On macOS with Homebrew:
|
|
1248
|
+
brew install go
|
|
1249
|
+
|
|
1250
|
+
# Verify installation:
|
|
1251
|
+
go version
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
**"Failed to build Go tool" error:**
|
|
1255
|
+
```bash
|
|
1256
|
+
# Try manual build:
|
|
1257
|
+
cd tools/go-schema-gen
|
|
1258
|
+
./build.sh
|
|
1259
|
+
|
|
1260
|
+
# Or rebuild from scratch:
|
|
1261
|
+
rm -rf ../../dist/bin/go-schema-gen
|
|
1262
|
+
klasik generate-go --type "..." --output ...
|
|
1263
|
+
```
|
|
1264
|
+
|
|
1265
|
+
**Rebuild the Go tool manually:**
|
|
1266
|
+
```bash
|
|
1267
|
+
cd tools/go-schema-gen
|
|
1268
|
+
go mod tidy
|
|
1269
|
+
./build.sh
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
### Future Enhancements
|
|
1273
|
+
|
|
1274
|
+
Planned features for future releases:
|
|
1275
|
+
- Go Plugin support for dynamic loading
|
|
1276
|
+
- Auto-discovery of types in packages
|
|
1277
|
+
- `validate` tag support
|
|
1278
|
+
- Custom type mappings
|
|
1279
|
+
- Multi-platform pre-built binaries
|
|
1280
|
+
|
|
576
1281
|
## NestJS Integration
|
|
577
1282
|
|
|
578
1283
|
Klasik integrates seamlessly with NestJS, generating models with `@ApiProperty` decorators for automatic Swagger/OpenAPI documentation and `class-validator` decorators for runtime validation.
|
|
@@ -890,6 +1595,8 @@ Built with:
|
|
|
890
1595
|
- [ts-morph](https://github.com/dsherret/ts-morph) - TypeScript Compiler API wrapper
|
|
891
1596
|
- [class-transformer](https://github.com/typestack/class-transformer) - Object transformation
|
|
892
1597
|
- [class-validator](https://github.com/typestack/class-validator) - Runtime validation
|
|
1598
|
+
- [ajv](https://github.com/ajv-validator/ajv) - JSON Schema validator
|
|
1599
|
+
- [ajv-formats](https://github.com/ajv-validator/ajv-formats) - Format validation for Ajv
|
|
893
1600
|
- [mustache](https://github.com/janl/mustache.js) - Template engine
|
|
894
1601
|
- [commander](https://github.com/tj/commander.js) - CLI framework
|
|
895
1602
|
|