@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.
- package/.env.example +3 -0
- package/README.md +1152 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +394 -0
- package/dist/cli/prompt.d.ts +4 -0
- package/dist/cli/prompt.js +89 -0
- package/dist/config/loadConfig.d.ts +2 -0
- package/dist/config/loadConfig.js +49 -0
- package/dist/config/schema.d.ts +21 -0
- package/dist/config/schema.js +17 -0
- package/dist/emit/formatter.d.ts +1 -0
- package/dist/emit/formatter.js +2 -0
- package/dist/emit/writer.d.ts +7 -0
- package/dist/emit/writer.js +37 -0
- package/dist/generate.d.ts +9 -0
- package/dist/generate.js +53 -0
- package/dist/generators/generateIndexFile.d.ts +2 -0
- package/dist/generators/generateIndexFile.js +12 -0
- package/dist/generators/generateRegistryFile.d.ts +2 -0
- package/dist/generators/generateRegistryFile.js +7 -0
- package/dist/generators/generateSdkClientFile.d.ts +2 -0
- package/dist/generators/generateSdkClientFile.js +46 -0
- package/dist/generators/generateSharedTypes.d.ts +1 -0
- package/dist/generators/generateSharedTypes.js +4 -0
- package/dist/generators/generateTableModule.d.ts +2 -0
- package/dist/generators/generateTableModule.js +49 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +8 -0
- package/dist/input/apiTransport.d.ts +6 -0
- package/dist/input/apiTransport.js +21 -0
- package/dist/input/parseTablesPayload.d.ts +21 -0
- package/dist/input/parseTablesPayload.js +71 -0
- package/dist/input/readApiInput.d.ts +9 -0
- package/dist/input/readApiInput.js +17 -0
- package/dist/input/readInput.d.ts +21 -0
- package/dist/input/readInput.js +14 -0
- package/dist/model/internalTypes.d.ts +60 -0
- package/dist/model/internalTypes.js +1 -0
- package/dist/model/normalizeTables.d.ts +6 -0
- package/dist/model/normalizeTables.js +68 -0
- package/dist/model/zodSchemas.d.ts +120 -0
- package/dist/model/zodSchemas.js +47 -0
- package/dist/naming/fieldAliases.d.ts +1 -0
- package/dist/naming/fieldAliases.js +3 -0
- package/dist/naming/identifiers.d.ts +1 -0
- package/dist/naming/identifiers.js +11 -0
- package/dist/naming/reservedWords.d.ts +1 -0
- package/dist/naming/reservedWords.js +13 -0
- package/dist/naming/tableNames.d.ts +1 -0
- package/dist/naming/tableNames.js +3 -0
- package/dist/typing/mapFieldType.d.ts +8 -0
- package/dist/typing/mapFieldType.js +95 -0
- package/dist/typing/writability.d.ts +1 -0
- package/dist/typing/writability.js +2 -0
- package/dist/utils/sort.d.ts +11 -0
- package/dist/utils/sort.js +5 -0
- package/dist/validate/crudPlan.d.ts +23 -0
- package/dist/validate/crudPlan.js +189 -0
- package/dist/validate/renderCrudTest.d.ts +2 -0
- package/dist/validate/renderCrudTest.js +180 -0
- 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
|