@gridfox/codegen 0.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.
Files changed (61) hide show
  1. package/.env.example +3 -0
  2. package/README.md +1152 -0
  3. package/dist/cli/main.d.ts +2 -0
  4. package/dist/cli/main.js +394 -0
  5. package/dist/cli/prompt.d.ts +4 -0
  6. package/dist/cli/prompt.js +89 -0
  7. package/dist/config/loadConfig.d.ts +2 -0
  8. package/dist/config/loadConfig.js +49 -0
  9. package/dist/config/schema.d.ts +21 -0
  10. package/dist/config/schema.js +17 -0
  11. package/dist/emit/formatter.d.ts +1 -0
  12. package/dist/emit/formatter.js +2 -0
  13. package/dist/emit/writer.d.ts +7 -0
  14. package/dist/emit/writer.js +37 -0
  15. package/dist/generate.d.ts +9 -0
  16. package/dist/generate.js +53 -0
  17. package/dist/generators/generateIndexFile.d.ts +2 -0
  18. package/dist/generators/generateIndexFile.js +12 -0
  19. package/dist/generators/generateRegistryFile.d.ts +2 -0
  20. package/dist/generators/generateRegistryFile.js +7 -0
  21. package/dist/generators/generateSdkClientFile.d.ts +2 -0
  22. package/dist/generators/generateSdkClientFile.js +46 -0
  23. package/dist/generators/generateSharedTypes.d.ts +1 -0
  24. package/dist/generators/generateSharedTypes.js +4 -0
  25. package/dist/generators/generateTableModule.d.ts +2 -0
  26. package/dist/generators/generateTableModule.js +49 -0
  27. package/dist/index.d.ts +9 -0
  28. package/dist/index.js +8 -0
  29. package/dist/input/apiTransport.d.ts +6 -0
  30. package/dist/input/apiTransport.js +21 -0
  31. package/dist/input/parseTablesPayload.d.ts +21 -0
  32. package/dist/input/parseTablesPayload.js +71 -0
  33. package/dist/input/readApiInput.d.ts +9 -0
  34. package/dist/input/readApiInput.js +17 -0
  35. package/dist/input/readInput.d.ts +21 -0
  36. package/dist/input/readInput.js +14 -0
  37. package/dist/model/internalTypes.d.ts +60 -0
  38. package/dist/model/internalTypes.js +1 -0
  39. package/dist/model/normalizeTables.d.ts +6 -0
  40. package/dist/model/normalizeTables.js +68 -0
  41. package/dist/model/zodSchemas.d.ts +120 -0
  42. package/dist/model/zodSchemas.js +47 -0
  43. package/dist/naming/fieldAliases.d.ts +1 -0
  44. package/dist/naming/fieldAliases.js +3 -0
  45. package/dist/naming/identifiers.d.ts +1 -0
  46. package/dist/naming/identifiers.js +11 -0
  47. package/dist/naming/reservedWords.d.ts +1 -0
  48. package/dist/naming/reservedWords.js +13 -0
  49. package/dist/naming/tableNames.d.ts +1 -0
  50. package/dist/naming/tableNames.js +3 -0
  51. package/dist/typing/mapFieldType.d.ts +8 -0
  52. package/dist/typing/mapFieldType.js +95 -0
  53. package/dist/typing/writability.d.ts +1 -0
  54. package/dist/typing/writability.js +2 -0
  55. package/dist/utils/sort.d.ts +11 -0
  56. package/dist/utils/sort.js +5 -0
  57. package/dist/validate/crudPlan.d.ts +23 -0
  58. package/dist/validate/crudPlan.js +189 -0
  59. package/dist/validate/renderCrudTest.d.ts +2 -0
  60. package/dist/validate/renderCrudTest.js +180 -0
  61. package/package.json +57 -0
package/README.md ADDED
@@ -0,0 +1,1152 @@
1
+ # @gridfox/codegen
2
+
3
+ ## Quick start (implementation)
4
+
5
+ ```bash
6
+ pnpm install
7
+ pnpm --filter @gridfox/codegen run build
8
+ ```
9
+
10
+ Run generator:
11
+
12
+ ```bash
13
+ node dist/cli/main.js generate --input ./tables.json --output ./src/generated/gridfox
14
+ # optional: emit fluent SDK wrapper that imports @gridfox/sdk
15
+ node dist/cli/main.js generate --input ./tables.json --output ./src/generated/gridfox --client
16
+ ```
17
+
18
+ Generate directly from Gridfox API:
19
+
20
+ ```bash
21
+ # populate .env.example values first
22
+ node dist/cli/main.js generate \
23
+ --output ./src/generated/gridfox \
24
+ --api-key "$GRIDFOX_API_KEY"
25
+ ```
26
+
27
+ Preview changes without writing files:
28
+
29
+ ```bash
30
+ node dist/cli/main.js generate --input ./tables.json --output ./src/generated/gridfox --dry-run
31
+ ```
32
+
33
+ CI check mode:
34
+
35
+ ```bash
36
+ node dist/cli/main.js generate --input ./tables.json --output ./src/generated/gridfox --check
37
+ ```
38
+
39
+ Run validation:
40
+
41
+ ```bash
42
+ pnpm --filter @gridfox/codegen run test
43
+ pnpm --filter @gridfox/codegen run typecheck
44
+ ```
45
+
46
+ Maintainer release process: see [`RELEASING.md`](./RELEASING.md).
47
+
48
+ Run local real-project checks (live Gridfox API):
49
+
50
+ ```bash
51
+ # from npm (published package): starts interactive flow
52
+ npx @gridfox/codegen validate
53
+ # shortest path: defaults to interactive generate flow when no command is provided
54
+ npx @gridfox/codegen
55
+ # non-interactive:
56
+ export GRIDFOX_API_KEY="your-key"
57
+ node dist/cli/main.js validate --table "Assets" --yes-live-writes
58
+ # npm script wrapper:
59
+ pnpm --filter @gridfox/codegen run test:real -- --table "Assets" --yes-live-writes
60
+ # debug options:
61
+ # pnpm --filter @gridfox/codegen run test:real -- --verbose
62
+ # pnpm --filter @gridfox/codegen run test:real -- --keep-temp
63
+ # pnpm --filter @gridfox/codegen run test:real -- --plan-only
64
+ # pnpm --filter @gridfox/codegen run test:real -- --allow-table-regex "^(Assets|Collections)$" --yes-live-writes
65
+ # pnpm --filter @gridfox/codegen run test:real -- --json
66
+ ```
67
+
68
+ Programmatic usage:
69
+
70
+ ```ts
71
+ import { generateFromTables } from '@gridfox/codegen'
72
+
73
+ await generateFromTables(tables, { output: './src/generated/gridfox' })
74
+ ```
75
+
76
+ ## 1. Overview
77
+
78
+ **Product name:** `@gridfox/codegen`
79
+
80
+ **Purpose:**
81
+ `@gridfox/codegen` is a schema-driven TypeScript code generator for Gridfox projects. It reads Gridfox table metadata JSON and emits stable, typed TypeScript artifacts that remove stringly-typed table access, reduce field alias drift, and centralize schema knowledge for application code and AI-assisted development.
82
+
83
+ **Primary outcome:**
84
+ Given a Gridfox `/tables` payload, the tool generates TypeScript modules that expose canonical table constants, field constants, metadata, list unions, and basic record/input types.
85
+
86
+ Useful resource: https://api.gridfox.com/swagger/v1/swagger.json
87
+
88
+ ## 2. Why this product exists
89
+
90
+ Application code built on top of Gridfox tends to accumulate repeated, bespoke logic in several areas:
91
+
92
+ * Repeated field name strings like `"Location"`, `"Customer"`, `"Difference"`
93
+ * Alias drift between human-friendly names, local aliases, and ad hoc constants
94
+ * Repetitive CRUD, value coercion, and status-handling code
95
+ * Repeated linked-record parsing and token-to-record mapping
96
+ * Large AI prompts because the schema has to be re-explained in context
97
+ * Dashboard logic that becomes embedded in UI components instead of remaining schema-driven
98
+
99
+ This leads to several concrete problems:
100
+
101
+ 1. **Field drift:** the same field is referred to differently in different files.
102
+ 2. **Weak typing:** field usage often relies on raw strings and `unknown` values.
103
+ 3. **Boilerplate:** each workspace reimplements schema helpers, record coercion, and ad hoc joins.
104
+ 4. **Slower iteration:** changing or adding fields requires many manual updates.
105
+ 5. **Larger AI context:** prompts must repeatedly include field names, table relationships, and conventions.
106
+
107
+ `@gridfox/codegen` exists to make Gridfox integration:
108
+
109
+ * more type-safe
110
+ * more maintainable
111
+ * easier to scale across workspaces
112
+ * easier to reason about for both humans and AI tools
113
+
114
+ ---
115
+
116
+ ## 3. What problem it solves
117
+
118
+ ### 3.1 Immediate problems solved by code generation
119
+
120
+ From a single schema payload, `@gridfox/codegen` can generate:
121
+
122
+ * stable table constants
123
+ * stable field constants
124
+ * strongly typed list unions for enum-like fields
125
+ * typed record shapes
126
+ * typed create and update inputs
127
+ * table metadata for future runtime helpers
128
+
129
+ This alone solves:
130
+
131
+ * alias drift
132
+ * repeated schema transcription
133
+ * raw string field access
134
+ * inconsistent naming conventions
135
+ * many category errors when reading or writing fields
136
+
137
+ ### 3.2 Longer-term problems it enables us to solve
138
+
139
+ Once codegen establishes a typed schema layer, we can later add shared runtime helpers that use generated metadata to centralize:
140
+
141
+ * field alias resolution
142
+ * linked-record parsing
143
+ * record-id extraction
144
+ * generic repositories
145
+ * shared filter helpers
146
+ * metrics and dashboard definitions
147
+
148
+ The code generator is therefore both a product in its own right and the foundation for a broader Gridfox SDK.
149
+
150
+ ---
151
+
152
+ ## 4. Product goals
153
+
154
+ ### 4.1 Primary goals
155
+
156
+ * Generate stable TypeScript artifacts from Gridfox table metadata
157
+ * Eliminate raw string field access in application code
158
+ * Provide canonical field aliases like `Products.fields.location`
159
+ * Reduce repeated schema knowledge in app code and prompts
160
+ * Create a durable foundation for future runtime helpers
161
+
162
+ ### 4.2 Secondary goals
163
+
164
+ * Keep generated files deterministic and diff-friendly
165
+ * Make the generator easy to run locally and in CI
166
+ * Keep the MVP narrow enough to ship quickly
167
+ * Support gradual adoption table by table
168
+
169
+ ### 4.3 Non-goals for the MVP
170
+
171
+ The initial version should **not** try to solve everything.
172
+
173
+ Out of scope for MVP:
174
+
175
+ * runtime repositories
176
+ * transport/client abstractions
177
+ * filter/query DSLs
178
+ * link token parsing
179
+ * error extraction
180
+ * metrics engine
181
+ * UI integration
182
+ * OpenAPI generation
183
+ * code mutation of existing handwritten files
184
+
185
+ ---
186
+
187
+ ## 5. Users and use cases
188
+
189
+ ### 5.1 Primary users
190
+
191
+ * application developers integrating with Gridfox-backed workspaces
192
+ * teams maintaining multiple Gridfox-heavy codebases
193
+ * AI-assisted development workflows that need small, stable schema references
194
+
195
+ ### 5.2 Main use cases
196
+
197
+ #### Use case 1: Safe field access
198
+
199
+ Instead of:
200
+
201
+ ```ts
202
+ record.fields["Location"]
203
+ ```
204
+
205
+ Use:
206
+
207
+ ```ts
208
+ record.fields[Products.fields.location]
209
+ ```
210
+
211
+ #### Use case 2: Safer enum usage
212
+
213
+ Instead of arbitrary strings:
214
+
215
+ ```ts
216
+ const location = "In Office"
217
+ ```
218
+
219
+ Use generated unions:
220
+
221
+ ```ts
222
+ const location: ProductLocation = "In Office"
223
+ ```
224
+
225
+ #### Use case 3: Typed input payloads
226
+
227
+ Instead of loosely shaped update payloads:
228
+
229
+ ```ts
230
+ const input = {
231
+ "Product Name": "Signet Ring",
232
+ Location: "In Office",
233
+ }
234
+ ```
235
+
236
+ Use generated input types:
237
+
238
+ ```ts
239
+ const input: ProductCreateInput = {
240
+ "Product Name": "Signet Ring",
241
+ Location: "In Office",
242
+ }
243
+ ```
244
+
245
+ #### Use case 4: Reduced AI prompt context
246
+
247
+ Prompts can refer to canonical references like:
248
+
249
+ * `Products.fields.location`
250
+ * `Orders.fields.status`
251
+ * `QuoteComponentRequirements.fields.difference`
252
+
253
+ rather than pasting long field lists repeatedly.
254
+
255
+ ---
256
+
257
+ ## 6. Product scope
258
+
259
+ ## 6.1 MVP scope
260
+
261
+ The MVP should be **codegen-only** and generate these artifacts:
262
+
263
+ ### Per table
264
+
265
+ * table constant
266
+ * field constants
267
+ * optional reverse alias map
268
+ * lightweight field metadata map
269
+ * list-field literal unions
270
+ * record type
271
+ * create input type
272
+ * update input type
273
+ * writable/readonly field classification constants
274
+
275
+ ### Shared output
276
+
277
+ * `index.ts` barrel
278
+ * optional `tables.ts` registry
279
+ * optional shared primitive types file
280
+
281
+ ### Example generated API
282
+
283
+ ```ts
284
+ export const Products = {
285
+ tableName: "Products",
286
+ singularName: "Product",
287
+ referenceFieldName: "SKU",
288
+ fields: {
289
+ sku: "SKU",
290
+ productName: "Product Name",
291
+ location: "Location",
292
+ productTemplate: "Product Template",
293
+ },
294
+ } as const
295
+
296
+ export type ProductLocation =
297
+ | "Virtual Product"
298
+ | "In Production"
299
+ | "At Assay Office"
300
+ | "In Office"
301
+ | "On Approval"
302
+ | "Sold"
303
+
304
+ export interface ProductRecord {
305
+ id?: string
306
+ fields: {
307
+ SKU?: number
308
+ "Product Name"?: string | null
309
+ Location?: ProductLocation | null
310
+ }
311
+ }
312
+ ```
313
+
314
+ ---
315
+
316
+ ## 7. Functional requirements
317
+
318
+ ### 7.1 Input
319
+
320
+ The generator must accept Gridfox table metadata as JSON.
321
+
322
+ Supported input forms for v1:
323
+
324
+ * local JSON file
325
+ * programmatic input from a JS/TS API
326
+
327
+ Later versions may support:
328
+
329
+ * direct API fetching from Gridfox with API key
330
+
331
+ ### 7.2 Output
332
+
333
+ The generator must emit TypeScript source files to a configured directory.
334
+
335
+ ### 7.3 Deterministic generation
336
+
337
+ The same input must always produce the same output ordering and formatting.
338
+
339
+ ### 7.4 Name normalization
340
+
341
+ The generator must convert human-readable table and field names into valid, predictable TypeScript identifiers.
342
+
343
+ Examples:
344
+
345
+ * `Quote Component Requirements` -> `QuoteComponentRequirements`
346
+ * `QR Code` -> `qrCode`
347
+ * `Sub-Products` -> `subProducts`
348
+ * `Customer ID` -> `customerId`
349
+
350
+ ### 7.5 Field typing
351
+
352
+ The generator must map Gridfox field types into sensible TypeScript types.
353
+
354
+ ### 7.6 Writability rules
355
+
356
+ The generator must distinguish likely writable fields from readonly/computed fields.
357
+
358
+ Default readonly types in MVP:
359
+
360
+ * `autoCounter`
361
+ * `formula`
362
+ * `child`
363
+
364
+ ### 7.7 List unions
365
+
366
+ For `list` fields, the generator must emit literal unions from allowed values.
367
+
368
+ For `multiSelectList`, the generator may emit array unions when item values are available.
369
+
370
+ ### 7.8 Metadata emission
371
+
372
+ The generator should emit lightweight metadata for future runtime consumers.
373
+
374
+ ---
375
+
376
+ ## 8. Non-functional requirements
377
+
378
+ * **Fast:** generation should complete quickly on typical workspace schemas
379
+ * **Deterministic:** stable ordering and formatting
380
+ * **Diff-friendly:** generated files should produce readable git diffs
381
+ * **Strict-TypeScript compatible:** output should compile under `strict`
382
+ * **Minimal magic:** generated code should be easy to inspect and understand
383
+ * **Low lock-in:** output should remain usable even without the generator runtime
384
+
385
+ ---
386
+
387
+ ## 9. Proposed architecture
388
+
389
+ The product should be split into a small number of clearly separated layers.
390
+
391
+ ### 9.1 High-level pipeline
392
+
393
+ 1. Read config
394
+ 2. Read input JSON
395
+ 3. Validate and normalize schema
396
+ 4. Build internal model
397
+ 5. Generate per-table artifacts
398
+ 6. Generate shared artifacts
399
+ 7. Format output
400
+ 8. Write files
401
+
402
+ ### 9.2 Internal modules
403
+
404
+ ```txt
405
+ packages/codegen/
406
+ src/
407
+ cli/
408
+ main.ts
409
+ config/
410
+ schema.ts
411
+ loadConfig.ts
412
+ input/
413
+ readInput.ts
414
+ model/
415
+ zodSchemas.ts
416
+ normalizeTables.ts
417
+ internalTypes.ts
418
+ naming/
419
+ tableNames.ts
420
+ fieldAliases.ts
421
+ reservedWords.ts
422
+ typing/
423
+ mapFieldType.ts
424
+ writability.ts
425
+ generators/
426
+ generateTableModule.ts
427
+ generateIndexFile.ts
428
+ generateRegistryFile.ts
429
+ generateSharedTypes.ts
430
+ emit/
431
+ writer.ts
432
+ formatter.ts
433
+ utils/
434
+ sort.ts
435
+ strings.ts
436
+ ```
437
+
438
+ ### 9.3 Internal data model
439
+
440
+ The generator should convert raw Gridfox metadata into a normalized internal representation before emitting code.
441
+
442
+ Example conceptual model:
443
+
444
+ ```ts
445
+ interface NormalizedTable {
446
+ tableName: string
447
+ singularName: string
448
+ symbolName: string
449
+ referenceFieldName: string
450
+ fields: NormalizedField[]
451
+ }
452
+
453
+ interface NormalizedField {
454
+ fieldName: string
455
+ alias: string
456
+ kind: string
457
+ tsReadType: string
458
+ tsWriteType: string
459
+ writable: boolean
460
+ required: boolean
461
+ unique: boolean
462
+ relatedTableName?: string
463
+ options?: string[]
464
+ }
465
+ ```
466
+
467
+ This internal model should be the source of truth for emission.
468
+
469
+ ---
470
+
471
+ ## 10. Dependencies and how we will use them
472
+
473
+ The generator should rely on a few focused packages rather than building custom infrastructure for every layer.
474
+
475
+ ### 10.1 `zod`
476
+
477
+ **Why:** runtime-safe validation and normalization of input JSON and config.
478
+
479
+ **How we will use it:**
480
+
481
+ * validate the Gridfox `/tables` payload shape
482
+ * validate generator config
483
+ * normalize optional `properties`
484
+ * infer TypeScript types for internal parser inputs
485
+
486
+ **Benefit:** reduces hand-written validation code and makes bad schema failures easier to diagnose.
487
+
488
+ ### 10.2 `change-case`
489
+
490
+ **Why:** deterministic, reusable identifier casing.
491
+
492
+ **How we will use it:**
493
+
494
+ * convert table names into exported symbol names
495
+ * convert field names into alias keys
496
+ * generate filename-safe identifiers
497
+ * standardize enum and type names
498
+
499
+ **Benefit:** removes bespoke string transformation logic and makes naming rules consistent.
500
+
501
+ ### 10.3 `ts-poet` or `ts-morph`
502
+
503
+ We should choose one generation strategy.
504
+
505
+ #### Option A: `ts-poet`
506
+
507
+ **Why:** lightweight TS code generation with import handling.
508
+
509
+ **How we will use it:**
510
+
511
+ * build per-table source modules
512
+ * emit imports and exports cleanly
513
+ * compose type aliases, constants, and interfaces
514
+
515
+ **Benefit:** simpler than AST generation, less fragile than raw string templates.
516
+
517
+ #### Option B: `ts-morph`
518
+
519
+ **Why:** AST-based generation on top of the TypeScript compiler API.
520
+
521
+ **How we will use it:**
522
+
523
+ * create source files structurally
524
+ * emit interfaces, type aliases, constants, and barrels
525
+ * support future advanced generation or file mutation workflows
526
+
527
+ **Benefit:** more structured and maintainable for long-term evolution.
528
+
529
+ **Recommendation:**
530
+ For the MVP, use **`ts-poet`** unless we know we will need AST-level editing soon. It keeps the generator simpler while still removing most import and formatting headaches.
531
+
532
+ ### 10.4 `prettier`
533
+
534
+ **Why:** final formatting of generated TypeScript.
535
+
536
+ **How we will use it:**
537
+
538
+ * format generated source before writing to disk
539
+ * keep output deterministic and readable
540
+ * align with existing repo formatting if Prettier is already used
541
+
542
+ **Benefit:** avoids writing custom formatting logic and keeps snapshots stable.
543
+
544
+ ### 10.5 `commander` or `cac`
545
+
546
+ **Why:** CLI parsing.
547
+
548
+ **How we will use it:**
549
+
550
+ * parse flags like `--input`, `--output`, `--config`
551
+ * provide help text and subcommands later if needed
552
+
553
+ **Benefit:** keeps CLI concerns simple and standard.
554
+
555
+ **Recommendation:** `cac` if we want minimal surface area, `commander` if we want a more traditional CLI framework.
556
+
557
+ ### 10.6 Node built-ins
558
+
559
+ Use Node built-ins where possible instead of extra dependencies:
560
+
561
+ * `fs/promises` for file I/O
562
+ * `path` for path resolution
563
+ * `url` if needed for ESM helpers
564
+
565
+ ### 10.7 Testing stack
566
+
567
+ Recommended test packages:
568
+
569
+ * `vitest` for unit and snapshot tests
570
+ * `typescript` for compile verification in CI
571
+
572
+ **How we will use them:**
573
+
574
+ * unit test parsing, naming, typing, and writability rules
575
+ * snapshot test generated files
576
+ * verify generated output compiles under strict settings
577
+
578
+ ---
579
+
580
+ ## 11. Generation strategy
581
+
582
+ ### 11.1 Output structure
583
+
584
+ Recommended generated output:
585
+
586
+ ```txt
587
+ src/generated/gridfox/
588
+ index.ts
589
+ tables.ts
590
+ shared.ts
591
+ Customers.ts
592
+ Orders.ts
593
+ Products.ts
594
+ ProductVariants.ts
595
+ Quotes.ts
596
+ QuoteComponentRequirements.ts
597
+ ```
598
+
599
+ ### 11.2 Per-table module contents
600
+
601
+ Each generated table module should include:
602
+
603
+ 1. exported table constant
604
+ 2. exported metadata object
605
+ 3. exported literal unions for list fields
606
+ 4. exported record type
607
+ 5. exported create input type
608
+ 6. exported update input type
609
+ 7. exported writable and readonly field arrays
610
+ 8. exported reverse alias map if enabled
611
+
612
+ ### 11.3 Shared types file
613
+
614
+ `shared.ts` should define lightweight placeholders for field types whose shapes may vary by endpoint.
615
+
616
+ Example:
617
+
618
+ ```ts
619
+ export type GridfoxLinkedValue = unknown
620
+ export type GridfoxFileValue = unknown
621
+ export type GridfoxImageValue = unknown
622
+ ```
623
+
624
+ This lets the MVP ship without fully standardizing every complex value shape.
625
+
626
+ ---
627
+
628
+ ## 12. Type mapping rules
629
+
630
+ The generator should define a single, explicit mapping from Gridfox field types to TypeScript output types.
631
+
632
+ ### 12.1 Read types
633
+
634
+ * `text` -> `string | null`
635
+ * `email` -> `string | null`
636
+ * `textArea` -> `string | null`
637
+ * `richText` -> `string | null`
638
+ * `user` -> `string | null` for MVP
639
+ * `number` -> `number | null`
640
+ * `money` -> `number | null`
641
+ * `percentage` -> `number | null`
642
+ * `formula` -> `number | null` for numeric formula types (`number`, `money`, `percentage`, `autoCounter`), `string | null` for explicit non-numeric formula types, and `number | string | null` when formula subtype is absent
643
+ * `autoCounter` -> `number | null`
644
+ * `checkbox` -> `boolean | null`
645
+ * `date` -> `string | null`
646
+ * `dateTime` -> `string | null`
647
+ * `list` -> generated union | `null`
648
+ * `multiSelectList` -> union array by default when options exist; configurable to always `string[] | null` via `multiSelectMode: "stringArray"`
649
+ * `parent` -> `GridfoxLinkedValue | null`
650
+ * `child` -> `GridfoxLinkedValue[] | null`
651
+ * `manyToMany` -> `GridfoxLinkedValue[] | null`
652
+ * `file` -> `GridfoxFileValue[] | null`
653
+ * `image` -> `GridfoxImageValue | null`
654
+
655
+ ### 12.2 Write types
656
+
657
+ For the MVP, create/update inputs should omit:
658
+
659
+ * `autoCounter`
660
+ * `formula`
661
+ * `child`
662
+
663
+ May include:
664
+
665
+ * scalar fields
666
+ * list fields
667
+ * parent/manyToMany fields
668
+ * file/image fields as placeholder types if supported
669
+
670
+ ---
671
+
672
+ ## 13. Naming and collision rules
673
+
674
+ ### 13.1 Table symbols
675
+
676
+ Generate PascalCase symbols from table names.
677
+
678
+ Examples:
679
+
680
+ * `Customers` -> `Customers`
681
+ * `Product Variants` -> `ProductVariants`
682
+ * `Quote Component Requirements` -> `QuoteComponentRequirements`
683
+
684
+ ### 13.2 Field aliases
685
+
686
+ Generate camelCase alias keys.
687
+
688
+ Examples:
689
+
690
+ * `Customer ID` -> `customerId`
691
+ * `QR Code` -> `qrCode`
692
+ * `Product Template` -> `productTemplate`
693
+ * `Sub-Products` -> `subProducts`
694
+
695
+ ### 13.3 Reserved words
696
+
697
+ Reserved or unsafe identifiers should be adjusted.
698
+
699
+ Examples:
700
+
701
+ * `default` -> `defaultField`
702
+ * `delete` -> `deleteField`
703
+ * `class` -> `classField`
704
+
705
+ ### 13.4 Collision policy
706
+
707
+ If two field names normalize to the same alias:
708
+
709
+ * fail generation by default
710
+ * include a clear error message explaining the collision
711
+ * optionally support config overrides later
712
+
713
+ ---
714
+
715
+ ## 14. CLI and configuration
716
+
717
+ ### 14.1 CLI shape
718
+
719
+ Proposed CLI:
720
+
721
+ ```bash
722
+ npx @gridfox/codegen generate --input ./gridfox-tables.json --output ./src/generated/gridfox
723
+ ```
724
+
725
+ Optional config file:
726
+
727
+ ```bash
728
+ npx @gridfox/codegen generate --config ./gridfox.config.ts
729
+ ```
730
+
731
+ Optional direct API mode:
732
+
733
+ ```bash
734
+ npx @gridfox/codegen generate --output ./src/generated/gridfox --api-key "$GRIDFOX_API_KEY"
735
+ ```
736
+
737
+ ### 14.2 Config shape
738
+
739
+ ```ts
740
+ export interface GridfoxCodegenConfig {
741
+ input?: string
742
+ output: string
743
+ includeTables?: string[]
744
+ excludeTables?: string[]
745
+ apiKey?: string
746
+ apiBaseUrl?: string
747
+ apiTimeoutMs?: number
748
+ multiSelectMode?: 'union' | 'stringArray'
749
+ emitRegistry?: boolean
750
+ emitClient?: boolean
751
+ emitReverseAliasMap?: boolean
752
+ emitMetadata?: boolean
753
+ format?: boolean
754
+ }
755
+ ```
756
+
757
+ ### 14.3 Initial config recommendations
758
+
759
+ Defaults:
760
+
761
+ * `multiSelectMode: "union"`
762
+ * `emitRegistry: true`
763
+ * `emitClient: false`
764
+ * `emitMetadata: true`
765
+ * `emitReverseAliasMap: false`
766
+ * `format: true`
767
+ * `apiBaseUrl: "https://api.gridfox.com"` (when API mode is used)
768
+ * `apiTimeoutMs: 10000` (when API mode is used)
769
+
770
+ Additional CLI flags:
771
+
772
+ * `--multi-select-mode <union|stringArray>`
773
+ * `--client` (generate `client.ts` that imports `@gridfox/sdk`)
774
+ * `--dry-run` (show per-file new/changed/unchanged summary, no writes)
775
+ * `--check` (same comparison, exits non-zero when files are outdated)
776
+ * `--api-key <key>`
777
+ * `--api-base-url <url>`
778
+ * `--api-timeout-ms <ms>`
779
+
780
+ Environment variables for API mode:
781
+
782
+ * `GRIDFOX_API_KEY`
783
+ * `GRIDFOX_API_BASE_URL`
784
+ * `GRIDFOX_API_TIMEOUT_MS`
785
+
786
+ ### 14.4 Recommended generate/check workflow
787
+
788
+ Local development:
789
+
790
+ ```bash
791
+ npx @gridfox/codegen generate --input ./tables.json --output ./src/generated/gridfox
792
+ ```
793
+
794
+ CI validation:
795
+
796
+ ```bash
797
+ npx @gridfox/codegen generate --input ./tables.json --output ./src/generated/gridfox --check
798
+ ```
799
+
800
+ ---
801
+
802
+ ## 15. Implementation plan
803
+
804
+ ### Phase 1: Foundation
805
+
806
+ Build the generator core:
807
+
808
+ * config loading
809
+ * JSON input loading
810
+ * zod validation
811
+ * normalized internal model
812
+ * naming utilities
813
+ * field type mapping utilities
814
+
815
+ ### Phase 2: Table module generation
816
+
817
+ Generate per-table modules with:
818
+
819
+ * table constant
820
+ * field constants
821
+ * list unions
822
+ * record type
823
+ * create/update input types
824
+ * metadata
825
+
826
+ ### Phase 3: Shared artifacts
827
+
828
+ Generate:
829
+
830
+ * barrel file
831
+ * registry file
832
+ * shared primitive placeholder types
833
+
834
+ ### Phase 4: Formatting and file writing
835
+
836
+ * format output with Prettier
837
+ * write only changed files if practical
838
+ * improve diff stability
839
+
840
+ ### Phase 5: Test coverage and adoption
841
+
842
+ * snapshot tests
843
+ * compile tests
844
+ * integrate with one real workspace
845
+ * replace raw string field access incrementally
846
+
847
+ ---
848
+
849
+ ## 16. Example generated output
850
+
851
+ ### Example: `Products`
852
+
853
+ ```ts
854
+ export const Products = {
855
+ tableName: "Products",
856
+ singularName: "Product",
857
+ referenceFieldName: "SKU",
858
+ fields: {
859
+ sku: "SKU",
860
+ productName: "Product Name",
861
+ productDescription: "Product Description",
862
+ internalProductId: "Internal Product ID",
863
+ totalCost: "Total Cost",
864
+ location: "Location",
865
+ productState: "Product State",
866
+ productType: "Product Type",
867
+ basePrice: "Base Price",
868
+ retailPrice: "Retail Price",
869
+ multiplier: "Multiplier",
870
+ category: "Category",
871
+ active: "Active",
872
+ images: "Images",
873
+ qrCode: "QR Code",
874
+ productVariants: "Product Variants",
875
+ mainImage: "Main Image",
876
+ subProducts: "Sub-Products",
877
+ productCostComponents: "Product Cost Components",
878
+ productTemplate: "Product Template",
879
+ productMovements: "Product Movements",
880
+ supplierTransactions: "Supplier Transactions",
881
+ },
882
+ } as const
883
+
884
+ export type ProductLocation =
885
+ | "Virtual Product"
886
+ | "In Production"
887
+ | "At Assay Office"
888
+ | "In Office"
889
+ | "On Approval"
890
+ | "Sold"
891
+ ```
892
+
893
+ ### Example usage
894
+
895
+ ```ts
896
+ product.fields[Products.fields.location]
897
+ quoteRequirement.fields[QuoteComponentRequirements.fields.difference]
898
+ ```
899
+
900
+ ---
901
+
902
+ ## 17. Testing strategy
903
+
904
+ Testing should focus on the highest-risk transformation points.
905
+
906
+ ### 17.1 Unit tests
907
+
908
+ #### Parsing and validation
909
+
910
+ * valid Gridfox payloads are accepted
911
+ * malformed payloads fail with useful errors
912
+ * optional properties normalize correctly
913
+
914
+ #### Naming
915
+
916
+ * table names normalize correctly
917
+ * field names normalize correctly
918
+ * acronym handling works as expected
919
+ * reserved words are handled safely
920
+ * collisions fail loudly
921
+
922
+ #### Type mapping
923
+
924
+ * each Gridfox field type maps to expected read type
925
+ * writable field selection is correct
926
+ * list unions are emitted correctly
927
+ * multi-select behavior is correct
928
+
929
+ #### Metadata generation
930
+
931
+ * related table names are preserved
932
+ * list options are preserved
933
+ * required and unique flags are preserved
934
+
935
+ ### 17.2 Snapshot tests
936
+
937
+ Use real sample schemas to snapshot generated files.
938
+
939
+ Important snapshot fixtures:
940
+
941
+ * small schema with 1 to 2 tables
942
+ * realistic schema like the provided Customers/Orders/Products/Quotes example
943
+ * schema containing edge-case field names and collisions
944
+
945
+ ### 17.3 Compile tests
946
+
947
+ Run TypeScript over generated output under `strict` mode.
948
+
949
+ Verify:
950
+
951
+ * emitted files compile
952
+ * imports resolve cleanly
953
+ * no duplicate identifier issues exist
954
+
955
+ ### 17.4 Integration tests
956
+
957
+ End-to-end test the CLI:
958
+
959
+ * read input JSON
960
+ * generate files
961
+ * format output
962
+ * verify expected file set and contents
963
+
964
+ ---
965
+
966
+ ## 18. Risks and edge cases
967
+
968
+ ### 18.1 Inconsistent field value shapes
969
+
970
+ Some Gridfox field kinds may have shapes that differ by endpoint or usage. The MVP should treat complex field values conservatively using placeholder types.
971
+
972
+ ### 18.2 Formula typing ambiguity
973
+
974
+ Formula fields may vary by formula subtype. The MVP may intentionally simplify these until more precise behavior is known.
975
+
976
+ ### 18.3 Name collisions
977
+
978
+ Different field names may normalize to the same alias. The generator must fail clearly instead of guessing.
979
+
980
+ ### 18.4 Writability assumptions
981
+
982
+ A field being required does not always mean it must appear in updates. The MVP should focus on likely writable vs likely readonly rather than perfect API semantics.
983
+
984
+ ### 18.5 Schema evolution
985
+
986
+ Table or field renames will change generated symbols. Consumers should be encouraged to import from the generated layer rather than hardcode names elsewhere.
987
+
988
+ ---
989
+
990
+ ## 19. Rollout plan
991
+
992
+ ### Step 1
993
+
994
+ Build the generator using fixture-driven development and the provided sample schema.
995
+
996
+ ### Step 2
997
+
998
+ Generate a small subset of high-value tables first:
999
+
1000
+ * `Products`
1001
+ * `Orders`
1002
+ * `Quotes`
1003
+ * `QuoteComponentRequirements`
1004
+ * `Customers`
1005
+
1006
+ ### Step 3
1007
+
1008
+ Replace raw string field access in one app surface, such as Catalog or Quotes.
1009
+
1010
+ ### Step 4
1011
+
1012
+ Measure immediate impact:
1013
+
1014
+ * fewer raw field strings
1015
+ * fewer bespoke field constants
1016
+ * fewer schema snippets in prompts
1017
+ * simpler type-safe access patterns
1018
+
1019
+ ### Step 5
1020
+
1021
+ Expand to remaining tables and adopt generated imports broadly.
1022
+
1023
+ ---
1024
+
1025
+ ## 20. Success metrics
1026
+
1027
+ The MVP should be considered successful if it achieves most of the following:
1028
+
1029
+ * raw string field access drops significantly
1030
+ * generated output is committed and stable in git
1031
+ * developers prefer generated constants over handwritten aliases
1032
+ * prompts and docs can reference generated symbols instead of copying schema text
1033
+ * the generator becomes the source of truth for field names and table metadata
1034
+
1035
+ Potential measurable indicators:
1036
+
1037
+ * number of hardcoded field strings removed
1038
+ * number of bespoke schema helper files deleted
1039
+ * lines of duplicated alias code removed
1040
+ * number of tables successfully generated
1041
+
1042
+ ---
1043
+
1044
+ ## 21. Future roadmap
1045
+
1046
+ After the codegen-only MVP is stable, likely next steps are:
1047
+
1048
+ ### 21.1 Shared runtime helpers
1049
+
1050
+ Future additions to `@gridfox/sdk` may provide:
1051
+
1052
+ * field alias resolver
1053
+ * linked-record parser
1054
+ * record-id extraction
1055
+ * error extraction
1056
+ * value coercion helpers
1057
+
1058
+ ### 21.2 Generic repositories
1059
+
1060
+ Generated tables and metadata can later back generic repositories with methods like:
1061
+
1062
+ * `findAll`
1063
+ * `create`
1064
+ * `update`
1065
+ * `remove`
1066
+ * `resolveTable`
1067
+
1068
+ ### 21.3 Link resolution helpers
1069
+
1070
+ Helpers like:
1071
+
1072
+ * `resolveLinkedRecord`
1073
+ * `resolveLinkedRecords`
1074
+ * `mapTokensToField`
1075
+
1076
+ ### 21.4 Declarative metrics engine
1077
+
1078
+ Schema-driven dashboard helpers like:
1079
+
1080
+ * `countByStatus`
1081
+ * `countByLocation`
1082
+ * `riskRules`
1083
+
1084
+ These should come after the schema layer is proven.
1085
+
1086
+ ---
1087
+
1088
+ ## 22. Recommended MVP summary
1089
+
1090
+ The recommended first version of `@gridfox/codegen` is:
1091
+
1092
+ **A CLI and library that reads Gridfox table metadata JSON and emits per-table TypeScript modules containing canonical field constants, list unions, metadata, and basic record/input types.**
1093
+
1094
+ This version delivers immediate value while keeping scope small, implementation risk low, and future extension paths clear.
1095
+
1096
+ ---
1097
+
1098
+ ## 23. Open decisions
1099
+
1100
+ A few implementation choices still need to be finalized:
1101
+
1102
+ 1. Should emission use `ts-poet` or `ts-morph`?
1103
+ 2. Should reverse alias maps be enabled by default?
1104
+ 3. Should file and image fields remain `unknown` in MVP, or use minimal placeholder interfaces?
1105
+ 4. Should registry generation be on by default?
1106
+
1107
+ Current recommendation:
1108
+
1109
+ * use `ts-poet`
1110
+ * emit metadata by default
1111
+ * emit registry by default
1112
+ * keep complex field shapes conservative in MVP
1113
+ * keep reverse alias maps optional
1114
+
1115
+ ---
1116
+
1117
+ ## 24. Appendix: Suggested package.json dependencies
1118
+
1119
+ Example initial dependency set:
1120
+
1121
+ ```json
1122
+ {
1123
+ "dependencies": {
1124
+ "change-case": "^5.4.4",
1125
+ "zod": "^3.25.0",
1126
+ "ts-poet": "^6.12.0",
1127
+ "cac": "^6.7.14"
1128
+ },
1129
+ "devDependencies": {
1130
+ "prettier": "^3.5.0",
1131
+ "typescript": "^5.8.0",
1132
+ "vitest": "^3.0.0"
1133
+ }
1134
+ }
1135
+ ```
1136
+
1137
+ If we choose `ts-morph` instead of `ts-poet`, swap it in accordingly.
1138
+
1139
+ ---
1140
+
1141
+ ## 25. Final recommendation
1142
+
1143
+ Build the MVP as a focused code generator, not a full SDK.
1144
+
1145
+ Keep it narrow, deterministic, and schema-first.
1146
+
1147
+ That gives us the fastest route to:
1148
+
1149
+ * killing alias drift
1150
+ * reducing schema boilerplate
1151
+ * shrinking AI context
1152
+ * establishing a stable base for future Gridfox tooling