@type-crafter/mcp 0.6.0 → 1.0.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/src/SPEC_RULES.md DELETED
@@ -1,1755 +0,0 @@
1
- # Type Crafter YAML Specification Rules
2
-
3
- Complete guide for writing Type Crafter YAML specifications and understanding TypeScript generation.
4
-
5
- ---
6
-
7
- ## Table of Contents
8
-
9
- - [🚨 Common Mistakes (Read This First)](#-common-mistakes-read-this-first)
10
- - [Multi-File Specifications](#multi-file-specifications)
11
- - [Root Structure](#root-structure)
12
- - [Data Types & Type Mapping](#data-types--type-mapping)
13
- - [Constraints & Limitations](#constraints--limitations)
14
- - [Nullable Types (Critical)](#nullable-types-critical)
15
- - [Type Definitions](#type-definitions)
16
- - [References](#references)
17
- - [Composition](#composition)
18
- - [TypeScript Generation Examples](#typescript-generation-examples)
19
- - [Best Practices](#best-practices)
20
- - [Common Patterns](#common-patterns)
21
- - [Rules Checklist](#rules-checklist)
22
-
23
- ---
24
-
25
- ## 🚨 Common Mistakes (Read This First)
26
-
27
- ### ❌ NEVER Do These
28
-
29
- ```yaml
30
- # ❌ WRONG: Adding 'nullable: true' property
31
- User:
32
- type: object
33
- properties:
34
- name:
35
- type: string
36
- nullable: true # ❌ INVALID! This property does NOT exist
37
-
38
- # ❌ WRONG: Using 'optional: true' property
39
- User:
40
- type: object
41
- properties:
42
- name:
43
- type: string
44
- optional: true # ❌ INVALID! This property does NOT exist
45
-
46
- # ❌ WRONG: Using '?' suffix for optional
47
- User:
48
- type: object
49
- properties:
50
- name?: # ❌ INVALID! Don't use ? suffix
51
- type: string
52
-
53
- # ❌ WRONG: Creating top-level array types
54
- Tags:
55
- type: array # ❌ INVALID! Arrays cannot be top-level types
56
- items:
57
- type: string
58
-
59
- # ❌ WRONG: Using relative paths from current file
60
- # File: src/api/users.yaml
61
- User:
62
- type: object
63
- properties:
64
- profile:
65
- $ref: './profile.yaml#/Profile' # ❌ WRONG! Not relative to current file
66
-
67
- # ❌ WRONG: Using # reference in non-top file (file without info section)
68
- # File: docs/cart.yaml (NON-TOP FILE - no info section)
69
- Cart:
70
- SCart:
71
- type: object
72
- properties:
73
- items:
74
- type: array
75
- items:
76
- $ref: '#/Cart/SCartItem' # ❌ WRONG! Must use full path in non-top files
77
-
78
- # ❌ WRONG: Using full path in top file for same-file reference
79
- # File: types.yaml (TOP FILE - has info section)
80
- info:
81
- version: '1.0.0'
82
- title: 'Types'
83
- types:
84
- User:
85
- type: object
86
- properties:
87
- profile:
88
- $ref: './types.yaml#/types/Profile' # ❌ WRONG! Use # in top files for same-file refs
89
- ```
90
-
91
- ### ✅ CORRECT Ways
92
-
93
- ```yaml
94
- # ✅ CORRECT: Use 'required' array to control nullable
95
- User:
96
- type: object
97
- required:
98
- - id # id is required (NOT nullable)
99
- # name is NOT in required, so it's nullable
100
- properties:
101
- id:
102
- type: string # Generates: string
103
- name:
104
- type: string # Generates: string | null (because not in required)
105
-
106
- # ✅ CORRECT: Arrays must be properties within objects
107
- Post:
108
- type: object
109
- properties:
110
- tags:
111
- type: array
112
- items:
113
- type: string
114
-
115
- # ✅ CORRECT: Use paths from project root
116
- # File: src/api/users.yaml (running type-crafter from project root)
117
- User:
118
- type: object
119
- properties:
120
- profile:
121
- $ref: './src/api/profile.yaml#/Profile' # ✅ From project root
122
-
123
- # ✅ CORRECT: Top file using # for same-file references
124
- # File: types.yaml (TOP FILE - has info section)
125
- info:
126
- version: '1.0.0'
127
- title: 'API Types'
128
- types:
129
- User:
130
- type: object
131
- properties:
132
- profile:
133
- $ref: '#/types/Profile' # ✅ Use # in top files for same-file refs
134
- Profile:
135
- type: object
136
- properties:
137
- bio: { type: string }
138
-
139
- # ✅ CORRECT: Non-top file using full path for all references
140
- # File: docs/cart.yaml (NON-TOP FILE - no info section)
141
- Cart:
142
- SCart:
143
- type: object
144
- properties:
145
- items:
146
- type: array
147
- items:
148
- $ref: './docs/cart.yaml#/Cart/SCartItem' # ✅ Full path in non-top files
149
- SCartItem:
150
- type: object
151
- properties:
152
- id: { type: number }
153
- ```
154
-
155
- ### 🔑 Key Rules to Remember
156
-
157
- 1. **Nullable is controlled by `required` array ONLY**
158
- - In `required` → generates `Type`
159
- - NOT in `required` → generates `Type | null`
160
- - No properties like `nullable`, `optional`, `?` exist
161
-
162
- 2. **Arrays cannot be top-level types**
163
- - Arrays MUST be properties within objects
164
- - Use `type: array` with `items` specification
165
-
166
- 3. **File paths are from project root**
167
- - NOT relative to current YAML file
168
- - Always use `./path/from/root/file.yaml#/Type`
169
-
170
- 4. **Referencing depends on file type**
171
- - **Top file** (has `info:` at root): Use `#/types/TypeName` for same-file refs
172
- - **Non-top file** (no `info:` at root): MUST use `'./path/from/root/file.yaml#/TypeName'` for ALL refs
173
- - Identify top files by presence of `info` section at root level
174
-
175
- 5. **Top file is required for generation**
176
- - Only files with `info:` section can be used with `type-crafter generate`
177
- - Non-top files must be referenced from a top file
178
-
179
- ---
180
-
181
- ## Multi-File Specifications
182
-
183
- ### File Organization Patterns
184
-
185
- #### Pattern 1: Single Top-Level File
186
-
187
- **Best for:** Small to medium projects
188
-
189
- ```
190
- project/
191
- ├── types.yaml # Single file with all types
192
- └── src/
193
- └── index.ts
194
- ```
195
-
196
- **types.yaml:**
197
- ```yaml
198
- info:
199
- version: '1.0.0'
200
- title: 'Project Types'
201
-
202
- types:
203
- User:
204
- type: object
205
- properties:
206
- id: { type: string }
207
-
208
- Post:
209
- type: object
210
- properties:
211
- author: { $ref: '#/types/User' }
212
- ```
213
-
214
- #### Pattern 2: Multiple Files with Main Entry Point
215
-
216
- **Best for:** Large projects with logical domain separation
217
-
218
- ```
219
- project/
220
- ├── types/
221
- │ ├── index.yaml # Main entry point (top-level file)
222
- │ ├── user.yaml # User-related types (sub-file)
223
- │ ├── post.yaml # Post-related types (sub-file)
224
- │ └── comment.yaml # Comment-related types (sub-file)
225
- └── src/
226
- └── index.ts
227
- ```
228
-
229
- **types/index.yaml (Top-level file):**
230
- ```yaml
231
- info:
232
- version: '1.0.0'
233
- title: 'Main API Types'
234
-
235
- # Import types from other files
236
- types:
237
- # Reference to external file (from project root)
238
- User:
239
- $ref: './types/user.yaml#/User'
240
-
241
- Post:
242
- $ref: './types/post.yaml#/Post'
243
-
244
- Comment:
245
- $ref: './types/comment.yaml#/Comment'
246
- ```
247
-
248
- **types/user.yaml (Sub-file):**
249
- ```yaml
250
- info:
251
- version: '1.0.0'
252
- title: 'User Types'
253
-
254
- types:
255
- User:
256
- type: object
257
- required:
258
- - id
259
- - email
260
- properties:
261
- id:
262
- type: string
263
- email:
264
- type: string
265
- name:
266
- type: string # nullable (not in required)
267
- ```
268
-
269
- **types/post.yaml (Sub-file):**
270
- ```yaml
271
- info:
272
- version: '1.0.0'
273
- title: 'Post Types'
274
-
275
- types:
276
- Post:
277
- type: object
278
- required:
279
- - id
280
- - title
281
- - author
282
- properties:
283
- id:
284
- type: string
285
- title:
286
- type: string
287
- author:
288
- # Reference to user.yaml from project root
289
- $ref: './types/user.yaml#/User'
290
- ```
291
-
292
- #### Pattern 3: Grouped Types with External References
293
-
294
- **Best for:** Complex domains with many related types
295
-
296
- ```
297
- project/
298
- ├── specs/
299
- │ ├── api.yaml # Main entry point
300
- │ ├── auth/
301
- │ │ └── types.yaml # Auth domain types
302
- │ └── shop/
303
- │ ├── cart.yaml # Shopping cart types
304
- │ └── product.yaml # Product types
305
- └── src/
306
- ```
307
-
308
- **specs/api.yaml (Top-level file):**
309
- ```yaml
310
- info:
311
- version: '1.0.0'
312
- title: 'API Specification'
313
-
314
- groupedTypes:
315
- # Import entire groups from external files
316
- Auth:
317
- $ref: './specs/auth/types.yaml#/AuthTypes'
318
-
319
- Shop:
320
- Cart:
321
- $ref: './specs/shop/cart.yaml#/ShopTypes/Cart'
322
- Product:
323
- $ref: './specs/shop/product.yaml#/ShopTypes/Product'
324
- ```
325
-
326
- **specs/auth/types.yaml:**
327
- ```yaml
328
- info:
329
- version: '1.0.0'
330
- title: 'Authentication Types'
331
-
332
- groupedTypes:
333
- AuthTypes:
334
- LoginRequest:
335
- type: object
336
- required:
337
- - email
338
- - password
339
- properties:
340
- email: { type: string }
341
- password: { type: string }
342
-
343
- LoginResponse:
344
- type: object
345
- required:
346
- - token
347
- - user
348
- properties:
349
- token: { type: string }
350
- user:
351
- $ref: './specs/user.yaml#/User' # Cross-file reference
352
- ```
353
-
354
- ### Multi-File Reference Rules
355
-
356
- #### 1. Every File Needs `info` Section
357
-
358
- ```yaml
359
- # ✅ CORRECT: All files need info section
360
- info:
361
- version: '1.0.0'
362
- title: 'File Title'
363
-
364
- types:
365
- # ... your types
366
- ```
367
-
368
- #### 2. Reference Format
369
-
370
- ```yaml
371
- # Local reference (same file)
372
- $ref: '#/types/TypeName'
373
- $ref: '#/groupedTypes/GroupName/TypeName'
374
-
375
- # External reference (from project root)
376
- $ref: './path/from/root/file.yaml#/TypeName'
377
- $ref: './path/from/root/file.yaml#/GroupName/TypeName'
378
- ```
379
-
380
- #### 3. Path Resolution
381
-
382
- **CRITICAL:** All paths are from **project root** (where you run `type-crafter` command)
383
-
384
- ```bash
385
- # If you run this command from /project
386
- cd /project
387
- type-crafter generate typescript ./specs/api.yaml ./output
388
-
389
- # Then all $ref paths in ANY file are relative to /project
390
- ```
391
-
392
- **Example:**
393
- ```
394
- /project/
395
- ├── specs/
396
- │ ├── api.yaml # File A
397
- │ └── user/
398
- │ └── types.yaml # File B
399
- ```
400
-
401
- **In specs/api.yaml:**
402
- ```yaml
403
- # ✅ CORRECT: Path from project root
404
- User:
405
- $ref: './specs/user/types.yaml#/User'
406
-
407
- # ❌ WRONG: Don't use relative path from current file
408
- User:
409
- $ref: './user/types.yaml#/User'
410
- ```
411
-
412
- **In specs/user/types.yaml:**
413
- ```yaml
414
- # ✅ CORRECT: Path from project root
415
- Profile:
416
- $ref: './specs/api.yaml#/ApiTypes/Profile'
417
-
418
- # ❌ WRONG: Don't use relative path
419
- Profile:
420
- $ref: '../api.yaml#/ApiTypes/Profile'
421
- ```
422
-
423
- ### Generating Types from Multi-File Specs
424
-
425
- ```bash
426
- # Generate from top-level file (references will be resolved automatically)
427
- type-crafter generate typescript ./types/index.yaml ./output
428
-
429
- # Or from any entry point
430
- type-crafter generate typescript ./specs/api.yaml ./src/types
431
- ```
432
-
433
- All referenced files will be automatically processed and types generated.
434
-
435
- ---
436
-
437
- ## Root Structure
438
-
439
- ### Required Fields
440
-
441
- ```yaml
442
- info:
443
- version: '0.0.0' # Semver format (required)
444
- title: 'My API Types' # Specification title (required)
445
- ```
446
-
447
- ### Type Organization
448
-
449
- **At least ONE is required:**
450
-
451
- ```yaml
452
- types: {} # Flat/top-level types
453
- groupedTypes: {} # Grouped/organized types
454
- ```
455
-
456
- **Can have both:**
457
-
458
- ```yaml
459
- types:
460
- User: {}
461
- Post: {}
462
-
463
- groupedTypes:
464
- Auth:
465
- LoginRequest: {}
466
- LoginResponse: {}
467
- ```
468
-
469
- ---
470
-
471
- ## Data Types & Type Mapping
472
-
473
- ### Primitive Types → TypeScript Mapping
474
-
475
- | YAML Type | TypeScript Output | Notes |
476
- | ----------------------- | ----------------- | ------------------------------ |
477
- | `string` | `string` | Default string |
478
- | `string` (format: date) | `Date` | With format specified |
479
- | `number` | `number` | Floating point |
480
- | `integer` | `number` | TypeScript has no integer type |
481
- | `boolean` | `boolean` | |
482
- | `array` | `Type[]` | Requires `items` specification |
483
- | `object` | `{ ... }` | Custom object type |
484
- | `unknown` | `unknown` | For dynamic/any type |
485
-
486
- ### Format Modifiers
487
-
488
- ```yaml
489
- # String with format
490
- dateField:
491
- type: string
492
- format: date # Generates: Date (not string)
493
- ```
494
-
495
- ---
496
-
497
- ## Constraints & Limitations
498
-
499
- ### ❌ Arrays Cannot Be Top-Level Types
500
-
501
- Arrays can **ONLY** be used as properties within object types, never as standalone top-level types.
502
-
503
- ```yaml
504
- # ❌ INVALID - This will NOT work
505
- Tags:
506
- type: array
507
- items:
508
- type: string
509
-
510
- # ✅ VALID - Arrays must be properties
511
- Post:
512
- type: object
513
- properties:
514
- tags:
515
- type: array
516
- items:
517
- type: string
518
- ```
519
-
520
- **Why:** Type Crafter generates named types. An array alone has no semantic meaning - it must be a property that describes what the array contains.
521
-
522
- ### ✅ Valid Type Categories
523
-
524
- Only these can be top-level types:
525
-
526
- - **Objects** (`type: object` with properties)
527
- - **Enums** (`type: string/number` with enum array)
528
- - **Primitives** (string, number, boolean, unknown)
529
- - **Unions** (oneOf)
530
- - **Intersections** (allOf)
531
- - **References** ($ref)
532
-
533
- ---
534
-
535
- ## Nullable Types (Critical)
536
-
537
- ### ⚠️ IMPORTANT: Required vs Optional Properties
538
-
539
- **Properties NOT in `required` array become nullable (`Type | null`)**
540
-
541
- This is controlled EXCLUSIVELY by the `required` array. There are NO other properties or syntax for controlling nullability.
542
-
543
- ### ❌ WRONG: What NOT to Do
544
-
545
- ```yaml
546
- # ❌ WRONG: Do NOT use 'nullable' property
547
- User:
548
- type: object
549
- properties:
550
- name:
551
- type: string
552
- nullable: true # ❌ INVALID! This property does NOT exist in Type Crafter
553
-
554
- # ❌ WRONG: Do NOT use 'optional' property
555
- User:
556
- type: object
557
- properties:
558
- name:
559
- type: string
560
- optional: true # ❌ INVALID! This property does NOT exist
561
-
562
- # ❌ WRONG: Do NOT use '?' suffix
563
- User:
564
- type: object
565
- properties:
566
- name?: # ❌ INVALID! Don't use ? in property names
567
- type: string
568
-
569
- # ❌ WRONG: Do NOT use null in type
570
- User:
571
- type: object
572
- properties:
573
- name:
574
- type: [string, null] # ❌ INVALID! Don't use array of types here
575
- ```
576
-
577
- ### ✅ CORRECT: Use `required` Array Only
578
-
579
- ```yaml
580
- # ✅ CORRECT: Control nullability with 'required' array
581
- User:
582
- type: object
583
- required:
584
- - id # id is required → generates: string
585
- - email # email is required → generates: string
586
- # name is NOT in required → generates: string | null
587
- # age is NOT in required → generates: number | null
588
- properties:
589
- id:
590
- type: string
591
- email:
592
- type: string
593
- name:
594
- type: string
595
- age:
596
- type: number
597
- ```
598
-
599
- **TypeScript Output:**
600
-
601
- ```typescript
602
- export type User = {
603
- id: string; // Required (in required array)
604
- email: string; // Required (in required array)
605
- name: string | null; // Nullable (NOT in required array)
606
- age: number | null; // Nullable (NOT in required array)
607
- };
608
- ```
609
-
610
- ### Detailed Rules
611
-
612
- 1. ✅ **Property in `required` array** → Generates `Type` (NOT nullable)
613
-
614
- ```yaml
615
- User:
616
- type: object
617
- required:
618
- - name
619
- properties:
620
- name: { type: string }
621
- # Generates: name: string
622
- ```
623
-
624
- 2. ✅ **Property NOT in `required` array** → Generates `Type | null` (nullable)
625
-
626
- ```yaml
627
- User:
628
- type: object
629
- required:
630
- - id
631
- properties:
632
- id: { type: string }
633
- name: { type: string } # NOT in required
634
- # Generates: name: string | null
635
- ```
636
-
637
- 3. ✅ **No `required` array at all** → All properties are `Type | null`
638
-
639
- ```yaml
640
- User:
641
- type: object
642
- # No required array
643
- properties:
644
- id: { type: string }
645
- name: { type: string }
646
- # Generates: id: string | null, name: string | null
647
- ```
648
-
649
- 4. ✅ **Empty `required: []`** → All properties are `Type | null`
650
- ```yaml
651
- User:
652
- type: object
653
- required: [] # Empty array
654
- properties:
655
- id: { type: string }
656
- # Generates: id: string | null
657
- ```
658
-
659
- ### Complete Examples
660
-
661
- #### Example 1: All Properties Required
662
-
663
- ```yaml
664
- User:
665
- type: object
666
- required:
667
- - id
668
- - email
669
- - name
670
- - age
671
- properties:
672
- id: { type: string }
673
- email: { type: string }
674
- name: { type: string }
675
- age: { type: number }
676
- ```
677
-
678
- ```typescript
679
- // Generated TypeScript
680
- export type User = {
681
- id: string;
682
- email: string;
683
- name: string;
684
- age: number;
685
- };
686
- ```
687
-
688
- #### Example 2: Some Properties Required
689
-
690
- ```yaml
691
- User:
692
- type: object
693
- required:
694
- - id
695
- - email
696
- properties:
697
- id: { type: string }
698
- email: { type: string }
699
- name: { type: string }
700
- age: { type: number }
701
- ```
702
-
703
- ```typescript
704
- // Generated TypeScript
705
- export type User = {
706
- id: string;
707
- email: string;
708
- name: string | null;
709
- age: number | null;
710
- };
711
- ```
712
-
713
- #### Example 3: No Properties Required
714
-
715
- ```yaml
716
- User:
717
- type: object
718
- properties:
719
- id: { type: string }
720
- email: { type: string }
721
- name: { type: string }
722
- age: { type: number }
723
- ```
724
-
725
- ```typescript
726
- // Generated TypeScript - All nullable
727
- export type User = {
728
- id: string | null;
729
- email: string | null;
730
- name: string | null;
731
- age: number | null;
732
- };
733
- ```
734
-
735
- ### Nested Objects and Arrays
736
-
737
- ```yaml
738
- User:
739
- type: object
740
- required:
741
- - profile
742
- - posts
743
- properties:
744
- profile:
745
- type: object
746
- required:
747
- - name
748
- properties:
749
- name: { type: string }
750
- bio: { type: string } # NOT in profile.required
751
- posts:
752
- type: array
753
- items:
754
- type: object
755
- required:
756
- - title
757
- properties:
758
- title: { type: string }
759
- content: { type: string } # NOT in items.required
760
- ```
761
-
762
- ```typescript
763
- // Generated TypeScript
764
- export type User = {
765
- profile: {
766
- // profile is required (in User.required)
767
- name: string; // required in profile
768
- bio: string | null; // NOT required in profile
769
- };
770
- posts: Array<{
771
- // posts array is required
772
- title: string; // required in post item
773
- content: string | null; // NOT required in post item
774
- }>;
775
- };
776
- ```
777
-
778
- ---
779
-
780
- ## Type Definitions
781
-
782
- ### Object Type
783
-
784
- ```yaml
785
- User:
786
- type: object
787
- description: 'User account type' # Optional metadata
788
- example: "{ id: '123', name: 'John' }" # Optional example
789
- required:
790
- - id
791
- - email
792
- properties:
793
- id:
794
- type: string
795
- description: 'Unique identifier'
796
- example: 'user-123'
797
- email:
798
- type: string
799
- name:
800
- type: string
801
- age:
802
- type: number
803
- ```
804
-
805
- **TypeScript:**
806
-
807
- ```typescript
808
- /**
809
- * @type { User }
810
- * @description User account type
811
- * @example { id: '123', name: 'John' }
812
- */
813
- export type User = {
814
- /**
815
- * @description Unique identifier
816
- * @type { string }
817
- * @memberof User
818
- * @example user-123
819
- */
820
- id: string;
821
- email: string;
822
- name: string | null;
823
- age: number | null;
824
- };
825
- ```
826
-
827
- ### Enum Type (Top-Level)
828
-
829
- ```yaml
830
- Status:
831
- type: string
832
- description: 'User status enum'
833
- example: 'active'
834
- enum:
835
- - active
836
- - inactive
837
- - pending
838
-
839
- Priority:
840
- type: number
841
- enum:
842
- - 1
843
- - 2
844
- - 3
845
- ```
846
-
847
- **TypeScript:**
848
-
849
- ```typescript
850
- // String enum
851
- export type Status = 'active' | 'inactive' | 'pending';
852
-
853
- // Number enum
854
- export type Priority = 1 | 2 | 3;
855
- ```
856
-
857
- ### Inline Enum (Property)
858
-
859
- ```yaml
860
- User:
861
- type: object
862
- properties:
863
- role:
864
- type: string
865
- enum:
866
- - admin
867
- - user
868
- - guest
869
- ```
870
-
871
- **TypeScript:**
872
-
873
- ```typescript
874
- export type User = {
875
- role: ('admin' | 'user' | 'guest') | null;
876
- };
877
- ```
878
-
879
- ### Array Types (Property-Level Only)
880
-
881
- **⚠️ IMPORTANT: Arrays cannot be top-level types. They must be properties within an object type.**
882
-
883
- ```yaml
884
- # ❌ INVALID - Cannot create standalone array types
885
- Tags:
886
- type: array
887
- items:
888
- type: string
889
-
890
- # ✅ VALID - Arrays as properties within objects
891
- Post:
892
- type: object
893
- required:
894
- - id
895
- - tags
896
- properties:
897
- id:
898
- type: string
899
- tags:
900
- type: array
901
- items:
902
- type: string
903
- comments:
904
- type: array
905
- items:
906
- type: object
907
- properties:
908
- text:
909
- type: string
910
- relatedPosts:
911
- type: array
912
- items:
913
- $ref: '#/types/Post'
914
- ```
915
-
916
- **TypeScript:**
917
-
918
- ```typescript
919
- // Arrays only appear as properties, never as top-level types
920
- export type Post = {
921
- id: string;
922
- tags: string[];
923
- comments: { text: string | null }[] | null;
924
- relatedPosts: Post[] | null;
925
- };
926
- ```
927
-
928
- ### Nested Objects
929
-
930
- ```yaml
931
- Company:
932
- type: object
933
- required:
934
- - id
935
- - address
936
- properties:
937
- id:
938
- type: string
939
- address:
940
- type: object
941
- required:
942
- - street
943
- properties:
944
- street:
945
- type: string
946
- city:
947
- type: string
948
- zipCode:
949
- type: string
950
- ```
951
-
952
- **TypeScript:**
953
-
954
- ```typescript
955
- export type Company = {
956
- id: string;
957
- address: {
958
- street: string;
959
- city: string | null;
960
- zipCode: string | null;
961
- };
962
- };
963
- ```
964
-
965
- ### Additional Properties (Hashmap/Dictionary)
966
-
967
- ```yaml
968
- # Simple hashmap (any keys → any values)
969
- SimpleMap:
970
- type: object
971
- additionalProperties: true
972
-
973
- # Typed hashmap (string keys → string values)
974
- StringMap:
975
- type: object
976
- additionalProperties:
977
- keyType: string
978
- valueType:
979
- type: string
980
-
981
- # Number keys → Object values
982
- IdMap:
983
- type: object
984
- additionalProperties:
985
- keyType: number
986
- valueType:
987
- $ref: '#/types/User'
988
-
989
- # Properties + additional (mixed)
990
- UserWithMeta:
991
- type: object
992
- required:
993
- - id
994
- properties:
995
- id:
996
- type: string
997
- additionalProperties:
998
- keyType: string
999
- valueType:
1000
- type: string
1001
- ```
1002
-
1003
- **TypeScript:**
1004
-
1005
- ```typescript
1006
- export type SimpleMap = {
1007
- [keys: string]: unknown;
1008
- };
1009
-
1010
- export type StringMap = {
1011
- [keys: string]: string;
1012
- };
1013
-
1014
- export type IdMap = {
1015
- [keys: number]: User;
1016
- };
1017
-
1018
- export type UserWithMeta = {
1019
- id: string;
1020
- [keys: string]: string; // Additional dynamic properties
1021
- };
1022
- ```
1023
-
1024
- ---
1025
-
1026
- ## References
1027
-
1028
- ### Understanding Top Files vs Non-Top Files
1029
-
1030
- **CRITICAL:** Referencing rules differ based on whether you're in a top file or non-top file.
1031
-
1032
- #### What is a Top File?
1033
-
1034
- A **top file** is the root specification file that contains the `info` section at the root level.
1035
-
1036
- **Identifying a top file:**
1037
- ```yaml
1038
- # ✅ This is a TOP FILE
1039
- info:
1040
- version: '1.0.0' # Has info section at root
1041
- title: 'My API Types'
1042
-
1043
- types:
1044
- User: { ... }
1045
- ```
1046
-
1047
- **Characteristics:**
1048
- - Contains `info:` section with `version` and `title` at the root level
1049
- - Is the root of all schemas
1050
- - Can be directly used with `type-crafter generate` command
1051
- - Typically referenced by other files
1052
-
1053
- #### What is a Non-Top File?
1054
-
1055
- A **non-top file** is any YAML file that does NOT have `info:` at the root level. These files are used to organize types into domain-specific files.
1056
-
1057
- **Identifying a non-top file:**
1058
- ```yaml
1059
- # ✅ This is a NON-TOP FILE (no info section at root)
1060
- Cart:
1061
- SCart:
1062
- type: object
1063
- properties:
1064
- items: { ... }
1065
-
1066
- SCartItem:
1067
- type: object
1068
- properties:
1069
- id: { ... }
1070
- ```
1071
-
1072
- **Characteristics:**
1073
- - Does NOT have `info:` section at the root level
1074
- - Must be referenced from a top file or another file
1075
- - Used for better organization of types in domain-specific files
1076
- - Cannot be used directly with `type-crafter generate` command
1077
-
1078
- ### Referencing Rules
1079
-
1080
- #### Rule 1: References in TOP Files
1081
-
1082
- **In top files, you can reference types using `#` without specifying the file path.**
1083
-
1084
- **Example:**
1085
-
1086
- ```yaml
1087
- # File: types.yaml (TOP FILE - has info section)
1088
- info:
1089
- version: '0.0.0'
1090
- title: 'Sample Typing Spec'
1091
-
1092
- types:
1093
- TypeObjectTwo:
1094
- type: object
1095
- properties:
1096
- propOne:
1097
- $ref: '#/types/TypeObjectOne' # ✅ Direct reference (no file path needed)
1098
-
1099
- TypeObjectOne:
1100
- type: object
1101
- properties:
1102
- name:
1103
- type: string
1104
- ```
1105
-
1106
- **Valid reference formats in top files:**
1107
- - Same file, top-level type: `#/types/TypeName`
1108
- - Same file, grouped type: `#/groupedTypes/GroupName/TypeName`
1109
- - External file: `'./path/from/root/file.yaml#/TypeName'` (when referencing another file)
1110
-
1111
- #### Rule 2: References in NON-TOP Files
1112
-
1113
- **In non-top files, you MUST specify the complete file path (from project root) when referencing ANY type, even types in the same file.**
1114
-
1115
- **Example:**
1116
-
1117
- ```yaml
1118
- # File: docs/cart.yaml (NON-TOP FILE - no info section)
1119
- Cart:
1120
- SCart:
1121
- description: 'Shopify cart object'
1122
- type: object
1123
- properties:
1124
- items:
1125
- type: array
1126
- items:
1127
- $ref: './docs/cart.yaml#/Cart/SCartItem' # ✅ MUST include full file path
1128
-
1129
- SCartItem:
1130
- description: 'Individual cart item'
1131
- type: object
1132
- properties:
1133
- id:
1134
- type: number
1135
- ```
1136
-
1137
- **Why the full path?** Non-top files don't have an `info` section, so they don't have a root context. You must always specify where the type is located.
1138
-
1139
- ### Complete Examples
1140
-
1141
- #### Example 1: Top File with Local References
1142
-
1143
- ```yaml
1144
- # File: types.yaml (TOP FILE)
1145
- info:
1146
- version: '1.0.0'
1147
- title: 'API Types'
1148
-
1149
- types:
1150
- Post:
1151
- type: object
1152
- properties:
1153
- author:
1154
- $ref: '#/types/User' # ✅ Local reference in top file (no path)
1155
- comments:
1156
- type: array
1157
- items:
1158
- $ref: '#/types/Comment' # ✅ Local reference in top file (no path)
1159
-
1160
- User:
1161
- type: object
1162
- properties:
1163
- id: { type: string }
1164
- name: { type: string }
1165
-
1166
- Comment:
1167
- type: object
1168
- properties:
1169
- text: { type: string }
1170
- ```
1171
-
1172
- #### Example 2: Top File Referencing Non-Top Files
1173
-
1174
- ```yaml
1175
- # File: types.yaml (TOP FILE)
1176
- info:
1177
- version: '0.0.0'
1178
- title: 'Sample Typing Spec'
1179
-
1180
- groupedTypes:
1181
- Cart:
1182
- $ref: './docs/cart.yaml#/Cart' # ✅ Importing entire Cart group from non-top file
1183
-
1184
- # Project structure:
1185
- # .
1186
- # ├── types.yaml (this file - top file)
1187
- # └── docs/
1188
- # └── cart.yaml (non-top file)
1189
- ```
1190
-
1191
- ```yaml
1192
- # File: docs/cart.yaml (NON-TOP FILE)
1193
- Cart:
1194
- SCart:
1195
- description: 'Shopify cart object'
1196
- type: object
1197
- required:
1198
- - items
1199
- properties:
1200
- items:
1201
- type: array
1202
- items:
1203
- $ref: './docs/cart.yaml#/Cart/SCartItem' # ✅ Full path required in non-top file
1204
-
1205
- SCartItem:
1206
- description: 'Individual item in the cart'
1207
- type: object
1208
- required:
1209
- - id
1210
- properties:
1211
- id:
1212
- type: number
1213
- description: 'Unique item identifier'
1214
- quantity:
1215
- type: number
1216
- ```
1217
-
1218
- #### Example 3: Non-Top File Referencing Another Non-Top File
1219
-
1220
- ```yaml
1221
- # File: docs/order.yaml (NON-TOP FILE)
1222
- Order:
1223
- SOrder:
1224
- type: object
1225
- properties:
1226
- items:
1227
- type: array
1228
- items:
1229
- $ref: './docs/cart.yaml#/Cart/SCartItem' # ✅ Full path to another non-top file
1230
- customer:
1231
- $ref: './docs/user.yaml#/User/SCustomer' # ✅ Full path to another non-top file
1232
- ```
1233
-
1234
- ### Reference Format Summary
1235
-
1236
- | File Type | Referencing Same File | Referencing Another File |
1237
- |-----------|----------------------|--------------------------|
1238
- | **Top File** | `#/types/TypeName`<br>`#/groupedTypes/Group/TypeName` | `'./path/from/root/file.yaml#/TypeName'` |
1239
- | **Non-Top File** | `'./path/from/root/current-file.yaml#/TypeName'`<br>(full path required) | `'./path/from/root/other-file.yaml#/TypeName'` |
1240
-
1241
- ### Path Rules (All Files)
1242
-
1243
- 1. **Paths are from project root** (where you run `type-crafter` command), NOT relative to current file
1244
- 2. **Always start with `./`** for file paths
1245
- 3. **Never use `../`** for relative navigation
1246
- 4. **Case matters** - file paths are case-sensitive on some systems
1247
-
1248
- **Example project structure:**
1249
- ```
1250
- project-root/
1251
- ├── types.yaml (top file)
1252
- └── docs/
1253
- ├── cart.yaml (non-top file)
1254
- └── user.yaml (non-top file)
1255
- ```
1256
-
1257
- If running `type-crafter generate typescript ./types.yaml ./output` from `project-root/`:
1258
- - Path to cart.yaml: `'./docs/cart.yaml#/...'`
1259
- - Path to user.yaml: `'./docs/user.yaml#/...'`
1260
-
1261
- ### Group References (Entire Group)
1262
-
1263
- ```yaml
1264
- groupedTypes:
1265
- # Import entire group from external file
1266
- SharedModels:
1267
- $ref: './shared.yaml#/Models'
1268
- ```
1269
-
1270
- ### Cyclic References (Self-Referencing)
1271
-
1272
- ```yaml
1273
- TreeNode:
1274
- type: object
1275
- properties:
1276
- value:
1277
- type: string
1278
- children:
1279
- type: array
1280
- items:
1281
- $ref: '#/types/TreeNode' # Self-reference allowed
1282
-
1283
- LinkedList:
1284
- type: object
1285
- properties:
1286
- value:
1287
- type: number
1288
- next:
1289
- $ref: '#/types/LinkedList' # Self-reference allowed
1290
- ```
1291
-
1292
- **TypeScript:**
1293
-
1294
- ```typescript
1295
- export type TreeNode = {
1296
- value: string | null;
1297
- children: TreeNode[] | null;
1298
- };
1299
-
1300
- export type LinkedList = {
1301
- value: number | null;
1302
- next: LinkedList | null;
1303
- };
1304
- ```
1305
-
1306
- ---
1307
-
1308
- ## Composition
1309
-
1310
- ### oneOf (Union Types)
1311
-
1312
- Creates TypeScript union: `TypeA | TypeB | TypeC`
1313
-
1314
- ```yaml
1315
- Response:
1316
- oneOf:
1317
- # Reference types
1318
- - $ref: '#/types/SuccessResponse'
1319
- - $ref: '#/types/ErrorResponse'
1320
- # Primitive types
1321
- - type: string
1322
- - type: number
1323
- # Inline enum
1324
- - type: string
1325
- enum:
1326
- - pending
1327
- - loading
1328
- # Inline object
1329
- - type: object
1330
- properties:
1331
- status:
1332
- type: string
1333
- # Array type
1334
- - type: array
1335
- items:
1336
- type: string
1337
- ```
1338
-
1339
- **TypeScript:**
1340
-
1341
- ```typescript
1342
- export type Response =
1343
- | SuccessResponse
1344
- | ErrorResponse
1345
- | string
1346
- | number
1347
- | ('pending' | 'loading')
1348
- | { status: string | null }
1349
- | string[];
1350
- ```
1351
-
1352
- ### allOf (Intersection/Merge Types)
1353
-
1354
- Creates TypeScript intersection: `TypeA & TypeB & TypeC`
1355
-
1356
- ```yaml
1357
- AdminUser:
1358
- allOf:
1359
- - $ref: '#/types/BaseUser'
1360
- - $ref: '#/types/AdminPermissions'
1361
- - type: object
1362
- properties:
1363
- adminLevel:
1364
- type: number
1365
-
1366
- # Output merges all types together
1367
- ```
1368
-
1369
- **TypeScript:**
1370
-
1371
- ```typescript
1372
- export type AdminUser = BaseUser &
1373
- AdminPermissions & {
1374
- adminLevel: number | null;
1375
- };
1376
- ```
1377
-
1378
- ---
1379
-
1380
- ## TypeScript Generation Examples
1381
-
1382
- ### Complete Example
1383
-
1384
- **YAML:**
1385
-
1386
- ```yaml
1387
- info:
1388
- version: '1.0.0'
1389
- title: 'Blog API Types'
1390
-
1391
- types:
1392
- User:
1393
- type: object
1394
- description: 'Blog user account'
1395
- required:
1396
- - id
1397
- - email
1398
- - role
1399
- properties:
1400
- id:
1401
- type: string
1402
- description: 'Unique user ID'
1403
- email:
1404
- type: string
1405
- role:
1406
- $ref: '#/types/UserRole'
1407
- profile:
1408
- type: object
1409
- properties:
1410
- name:
1411
- type: string
1412
- avatar:
1413
- type: string
1414
-
1415
- UserRole:
1416
- type: string
1417
- enum:
1418
- - admin
1419
- - editor
1420
- - viewer
1421
-
1422
- Post:
1423
- type: object
1424
- required:
1425
- - id
1426
- - title
1427
- - author
1428
- properties:
1429
- id:
1430
- type: string
1431
- title:
1432
- type: string
1433
- content:
1434
- type: string
1435
- author:
1436
- $ref: '#/types/User'
1437
- tags:
1438
- type: array
1439
- items:
1440
- type: string
1441
- metadata:
1442
- type: object
1443
- additionalProperties:
1444
- keyType: string
1445
- valueType:
1446
- type: string
1447
- ```
1448
-
1449
- **TypeScript Output:**
1450
-
1451
- ```typescript
1452
- /**
1453
- * @type { User }
1454
- * @description Blog user account
1455
- */
1456
- export type User = {
1457
- /**
1458
- * @description Unique user ID
1459
- * @type { string }
1460
- * @memberof User
1461
- */
1462
- id: string;
1463
- email: string;
1464
- role: UserRole;
1465
- profile: {
1466
- name: string | null;
1467
- avatar: string | null;
1468
- } | null;
1469
- };
1470
-
1471
- export type UserRole = 'admin' | 'editor' | 'viewer';
1472
-
1473
- export type Post = {
1474
- id: string;
1475
- title: string;
1476
- content: string | null;
1477
- author: User;
1478
- tags: string[] | null;
1479
- metadata: {
1480
- [keys: string]: string;
1481
- } | null;
1482
- };
1483
- ```
1484
-
1485
- ---
1486
-
1487
- ## Best Practices
1488
-
1489
- ### 1. Always Use `required` Array
1490
-
1491
- ```yaml
1492
- # ❌ BAD - All properties become nullable
1493
- User:
1494
- type: object
1495
- properties:
1496
- id: { type: string }
1497
- email: { type: string }
1498
-
1499
- # ✅ GOOD - Explicit required fields
1500
- User:
1501
- type: object
1502
- required:
1503
- - id
1504
- - email
1505
- properties:
1506
- id: { type: string }
1507
- email: { type: string }
1508
- ```
1509
-
1510
- ### 2. Use PascalCase for Type Names
1511
-
1512
- ```yaml
1513
- # ✅ GOOD
1514
- types:
1515
- UserProfile: {}
1516
- BlogPost: {}
1517
- APIResponse: {}
1518
-
1519
- # ❌ AVOID
1520
- types:
1521
- userProfile: {}
1522
- blog_post: {}
1523
- api-response: {}
1524
- ```
1525
-
1526
- ### 3. Group Related Types
1527
-
1528
- ```yaml
1529
- # ✅ GOOD
1530
- groupedTypes:
1531
- Auth:
1532
- LoginRequest: {}
1533
- LoginResponse: {}
1534
- RefreshToken: {}
1535
-
1536
- Users:
1537
- UserProfile: {}
1538
- UserSettings: {}
1539
- UserPreferences: {}
1540
- ```
1541
-
1542
- ### 4. Use Descriptions for Complex Types
1543
-
1544
- ```yaml
1545
- # ✅ GOOD
1546
- User:
1547
- type: object
1548
- description: 'Represents a registered user account with authentication details'
1549
- properties:
1550
- passwordHash:
1551
- type: string
1552
- description: 'Bcrypt hashed password (never expose in responses)'
1553
- ```
1554
-
1555
- ### 5. Reference External Types for Reusability
1556
-
1557
- ```yaml
1558
- # ✅ GOOD - Reuse common types (paths from project root)
1559
- Post:
1560
- type: object
1561
- properties:
1562
- author:
1563
- $ref: './src/types/common.yaml#/User'
1564
- metadata:
1565
- $ref: './src/types/common.yaml#/Metadata'
1566
-
1567
- # Real example: Shopify cart referencing item types
1568
- SCart:
1569
- type: object
1570
- properties:
1571
- items:
1572
- type: array
1573
- items:
1574
- $ref: './docs/specs/Cart.yaml#/Cart/SCartItem'
1575
- ```
1576
-
1577
- **Remember:** Paths are from project root, not relative to current file location.
1578
-
1579
- ---
1580
-
1581
- ## Common Patterns
1582
-
1583
- ### Pattern 1: Paginated Response
1584
-
1585
- ```yaml
1586
- PaginatedUsers:
1587
- type: object
1588
- required:
1589
- - data
1590
- - total
1591
- - page
1592
- properties:
1593
- data:
1594
- type: array
1595
- items:
1596
- $ref: '#/types/User'
1597
- total:
1598
- type: number
1599
- page:
1600
- type: number
1601
- perPage:
1602
- type: number
1603
- ```
1604
-
1605
- ### Pattern 2: API Response Wrapper
1606
-
1607
- ```yaml
1608
- ApiResponse:
1609
- oneOf:
1610
- - type: object
1611
- required:
1612
- - success
1613
- - data
1614
- properties:
1615
- success:
1616
- type: boolean
1617
- data:
1618
- type: unknown
1619
- - type: object
1620
- required:
1621
- - success
1622
- - error
1623
- properties:
1624
- success:
1625
- type: boolean
1626
- error:
1627
- type: string
1628
- ```
1629
-
1630
- ### Pattern 3: Timestamps Mixin
1631
-
1632
- ```yaml
1633
- Timestamped:
1634
- type: object
1635
- required:
1636
- - createdAt
1637
- - updatedAt
1638
- properties:
1639
- createdAt:
1640
- type: string
1641
- format: date
1642
- updatedAt:
1643
- type: string
1644
- format: date
1645
-
1646
- # Use with allOf
1647
- User:
1648
- allOf:
1649
- - $ref: '#/types/Timestamped'
1650
- - type: object
1651
- required:
1652
- - id
1653
- properties:
1654
- id: { type: string }
1655
- ```
1656
-
1657
- ### Pattern 4: Enum + Metadata
1658
-
1659
- ```yaml
1660
- StatusType:
1661
- type: string
1662
- enum:
1663
- - draft
1664
- - published
1665
- - archived
1666
-
1667
- Post:
1668
- type: object
1669
- required:
1670
- - status
1671
- properties:
1672
- status:
1673
- $ref: '#/types/StatusType'
1674
- statusChangedAt:
1675
- type: string
1676
- format: date
1677
- ```
1678
-
1679
- ---
1680
-
1681
- ## Rules Checklist
1682
-
1683
- ### Required ✅
1684
-
1685
- - [ ] Has `info.version` (string)
1686
- - [ ] Has `info.title` (string)
1687
- - [ ] Has `types` OR `groupedTypes` (or both)
1688
-
1689
- ### Constraints ✅
1690
-
1691
- - [ ] **Arrays CANNOT be top-level types** - must be properties within objects
1692
- - [ ] Only objects, enums, primitives, unions, intersections, and references can be top-level types
1693
- - [ ] Arrays require `items` specification
1694
-
1695
- ### Type Definitions ✅
1696
-
1697
- - [ ] Objects have `type: object`
1698
- - [ ] Arrays are only used as properties (never top-level)
1699
- - [ ] Enums have `type` (string/number) with `enum` array
1700
- - [ ] Use `required` array for non-nullable properties
1701
- - [ ] Properties not in `required` become `Type | null`
1702
-
1703
- ### References ✅
1704
-
1705
- - [ ] Local references: `#/types/Name` or `#/groupedTypes/Group/Name`
1706
- - [ ] External references: `./path/from/root/file.yaml#/Name`
1707
- - [ ] **External paths are from project root, NOT relative to current file**
1708
- - [ ] Cyclic references are allowed
1709
-
1710
- ### Composition ✅
1711
-
1712
- - [ ] `oneOf` creates unions (`A | B | C`)
1713
- - [ ] `allOf` creates intersections (`A & B & C`)
1714
- - [ ] Can mix inline types and references
1715
-
1716
- ### TypeScript Generation ✅
1717
-
1718
- - [ ] `string` → `string`
1719
- - [ ] `string` (format: date) → `Date`
1720
- - [ ] `number`/`integer` → `number`
1721
- - [ ] `boolean` → `boolean`
1722
- - [ ] `array` → `Type[]`
1723
- - [ ] `object` → `{ ... }`
1724
- - [ ] `unknown` → `unknown`
1725
- - [ ] NOT in `required` → `Type | null`
1726
-
1727
- ### Best Practices ✅
1728
-
1729
- - [ ] Use PascalCase for type names
1730
- - [ ] Always specify `required` array for objects
1731
- - [ ] Group related types in `groupedTypes`
1732
- - [ ] Add descriptions for complex types
1733
- - [ ] Use references for reusability
1734
- - [ ] Prefer explicit over implicit nullability
1735
-
1736
- ---
1737
-
1738
- ## Summary
1739
-
1740
- | Concept | YAML | TypeScript |
1741
- | ----------------- | ----------------------------- | -------------------- |
1742
- | Required property | In `required` array | `prop: Type` |
1743
- | Optional property | NOT in `required` array | `prop: Type \| null` |
1744
- | String enum | `type: string, enum: [...]` | `'a' \| 'b' \| 'c'` |
1745
- | Number enum | `type: number, enum: [...]` | `1 \| 2 \| 3` |
1746
- | Union | `oneOf: [...]` | `A \| B \| C` |
1747
- | Intersection | `allOf: [...]` | `A & B & C` |
1748
- | Array | `type: array, items: {...}` | `Type[]` |
1749
- | Hashmap | `additionalProperties: {...}` | `[key: Type]: Type` |
1750
- | Reference | `$ref: '#/...'` | Type name |
1751
- | Nested object | Inline `type: object` | `{ ... }` |
1752
-
1753
- ---
1754
-
1755
- **Remember:** Properties NOT in the `required` array automatically become `Type | null` in TypeScript!