@metaobjectsdev/codegen-ts 0.6.0 → 0.7.0-rc.10

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 (119) hide show
  1. package/README.md +161 -4
  2. package/dist/column-mapper.d.ts +16 -0
  3. package/dist/column-mapper.d.ts.map +1 -1
  4. package/dist/column-mapper.js +73 -2
  5. package/dist/column-mapper.js.map +1 -1
  6. package/dist/generators/docs-file.d.ts +8 -0
  7. package/dist/generators/docs-file.d.ts.map +1 -0
  8. package/dist/generators/docs-file.js +52 -0
  9. package/dist/generators/docs-file.js.map +1 -0
  10. package/dist/generators/entity-file.d.ts +15 -0
  11. package/dist/generators/entity-file.d.ts.map +1 -1
  12. package/dist/generators/entity-file.js +2 -1
  13. package/dist/generators/entity-file.js.map +1 -1
  14. package/dist/generators/index.d.ts +4 -0
  15. package/dist/generators/index.d.ts.map +1 -1
  16. package/dist/generators/index.js +4 -0
  17. package/dist/generators/index.js.map +1 -1
  18. package/dist/generators/output-parser-file.d.ts +9 -0
  19. package/dist/generators/output-parser-file.d.ts.map +1 -0
  20. package/dist/generators/output-parser-file.js +37 -0
  21. package/dist/generators/output-parser-file.js.map +1 -0
  22. package/dist/generators/prompt-render-file.d.ts +9 -0
  23. package/dist/generators/prompt-render-file.d.ts.map +1 -0
  24. package/dist/generators/prompt-render-file.js +70 -0
  25. package/dist/generators/prompt-render-file.js.map +1 -0
  26. package/dist/generators/queries-file.d.ts +1 -1
  27. package/dist/generators/queries-file.d.ts.map +1 -1
  28. package/dist/generators/queries-file.js +11 -3
  29. package/dist/generators/queries-file.js.map +1 -1
  30. package/dist/generators/routes-file-hono.d.ts +21 -0
  31. package/dist/generators/routes-file-hono.d.ts.map +1 -0
  32. package/dist/generators/routes-file-hono.js +38 -0
  33. package/dist/generators/routes-file-hono.js.map +1 -0
  34. package/dist/index.d.ts +2 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +1 -1
  37. package/dist/index.js.map +1 -1
  38. package/dist/metaobjects-config.d.ts +10 -1
  39. package/dist/metaobjects-config.d.ts.map +1 -1
  40. package/dist/metaobjects-config.js +2 -1
  41. package/dist/metaobjects-config.js.map +1 -1
  42. package/dist/naming.d.ts +3 -12
  43. package/dist/naming.d.ts.map +1 -1
  44. package/dist/naming.js +14 -44
  45. package/dist/naming.js.map +1 -1
  46. package/dist/payload-codegen.d.ts +8 -0
  47. package/dist/payload-codegen.d.ts.map +1 -1
  48. package/dist/payload-codegen.js +33 -3
  49. package/dist/payload-codegen.js.map +1 -1
  50. package/dist/projection/extract-view-spec.d.ts +1 -1
  51. package/dist/projection/extract-view-spec.js +1 -1
  52. package/dist/source-detect.d.ts +10 -0
  53. package/dist/source-detect.d.ts.map +1 -0
  54. package/dist/source-detect.js +30 -0
  55. package/dist/source-detect.js.map +1 -0
  56. package/dist/templates/docs-file.d.ts +48 -0
  57. package/dist/templates/docs-file.d.ts.map +1 -0
  58. package/dist/templates/docs-file.js +445 -0
  59. package/dist/templates/docs-file.js.map +1 -0
  60. package/dist/templates/drizzle-schema.js +27 -3
  61. package/dist/templates/drizzle-schema.js.map +1 -1
  62. package/dist/templates/entity-file.d.ts +15 -1
  63. package/dist/templates/entity-file.d.ts.map +1 -1
  64. package/dist/templates/entity-file.js +15 -5
  65. package/dist/templates/entity-file.js.map +1 -1
  66. package/dist/templates/inferred-types.d.ts +9 -0
  67. package/dist/templates/inferred-types.d.ts.map +1 -1
  68. package/dist/templates/inferred-types.js +88 -2
  69. package/dist/templates/inferred-types.js.map +1 -1
  70. package/dist/templates/output-parser.d.ts +8 -0
  71. package/dist/templates/output-parser.d.ts.map +1 -0
  72. package/dist/templates/output-parser.js +129 -0
  73. package/dist/templates/output-parser.js.map +1 -0
  74. package/dist/templates/projection-decl.d.ts +1 -1
  75. package/dist/templates/projection-decl.js +1 -1
  76. package/dist/templates/queries-file.d.ts.map +1 -1
  77. package/dist/templates/queries-file.js +15 -4
  78. package/dist/templates/queries-file.js.map +1 -1
  79. package/dist/templates/queries.d.ts.map +1 -1
  80. package/dist/templates/queries.js +11 -30
  81. package/dist/templates/queries.js.map +1 -1
  82. package/dist/templates/routes-file-hono.d.ts +4 -0
  83. package/dist/templates/routes-file-hono.d.ts.map +1 -0
  84. package/dist/templates/routes-file-hono.js +119 -0
  85. package/dist/templates/routes-file-hono.js.map +1 -0
  86. package/dist/templates/value-object-file.d.ts +3 -0
  87. package/dist/templates/value-object-file.d.ts.map +1 -0
  88. package/dist/templates/value-object-file.js +27 -0
  89. package/dist/templates/value-object-file.js.map +1 -0
  90. package/dist/templates/zod-validators.d.ts +10 -0
  91. package/dist/templates/zod-validators.d.ts.map +1 -1
  92. package/dist/templates/zod-validators.js +108 -30
  93. package/dist/templates/zod-validators.js.map +1 -1
  94. package/package.json +5 -4
  95. package/src/column-mapper.ts +86 -1
  96. package/src/generators/docs-file.ts +64 -0
  97. package/src/generators/entity-file.ts +17 -1
  98. package/src/generators/index.ts +4 -0
  99. package/src/generators/output-parser-file.ts +50 -0
  100. package/src/generators/prompt-render-file.ts +95 -0
  101. package/src/generators/queries-file.ts +13 -4
  102. package/src/generators/routes-file-hono.ts +48 -0
  103. package/src/index.ts +2 -2
  104. package/src/metaobjects-config.ts +11 -2
  105. package/src/naming.ts +22 -46
  106. package/src/payload-codegen.ts +34 -2
  107. package/src/projection/extract-view-spec.ts +1 -1
  108. package/src/source-detect.ts +28 -0
  109. package/src/templates/docs-file.ts +545 -0
  110. package/src/templates/drizzle-schema.ts +27 -3
  111. package/src/templates/entity-file.ts +36 -5
  112. package/src/templates/inferred-types.ts +117 -3
  113. package/src/templates/output-parser.ts +143 -0
  114. package/src/templates/projection-decl.ts +1 -1
  115. package/src/templates/queries-file.ts +18 -4
  116. package/src/templates/queries.ts +11 -33
  117. package/src/templates/routes-file-hono.ts +142 -0
  118. package/src/templates/value-object-file.ts +30 -0
  119. package/src/templates/zod-validators.ts +121 -35
@@ -0,0 +1,4 @@
1
+ import type { MetaObject } from "@metaobjectsdev/metadata";
2
+ import { type RenderContext } from "../render-context.js";
3
+ export declare function renderRoutesFileHono(entity: MetaObject, ctx: RenderContext): string;
4
+ //# sourceMappingURL=routes-file-hono.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-file-hono.d.ts","sourceRoot":"","sources":["../../src/templates/routes-file-hono.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAM1D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CA2GnF"}
@@ -0,0 +1,119 @@
1
+ // Hono route template — emits a per-entity routes file that delegates
2
+ // CRUD verbs to helpers from @metaobjectsdev/runtime-ts/hono.
3
+ //
4
+ // Hono parallel of templates/routes-file.ts. Two emit-shape differences
5
+ // vs the Fastify flavor, both reflecting Hono idioms rather than contract
6
+ // drift:
7
+ //
8
+ // 1) Exported function shape — `registerXxxRoutes(app, deps)` instead of
9
+ // `xxxRoutes(fastify)`. Workers/Bun consumers typically pass `db`
10
+ // through a per-request deps object (so a Worker can attach the
11
+ // D1 client pulled off bindings) rather than reaching for a
12
+ // module-level singleton. The Fastify flavor uses `import { db }`
13
+ // because Fastify apps are long-lived Node processes where a
14
+ // singleton is the norm. Both flavors talk to mountCrudRoutes /
15
+ // mountReadOnlyCrudRoutes with identical wire behavior.
16
+ //
17
+ // 2) apiPrefix is composed into the resource path (`${apiPrefix}${path}`)
18
+ // rather than wrapping the registration. Hono has no fastify.register
19
+ // / prefix-wrapping primitive; sub-apps via `app.route(prefix, sub)`
20
+ // exist but bloat the generated code. String concat is simpler and
21
+ // produces identical URL grammar.
22
+ //
23
+ // Dispatch logic mirrors Fastify:
24
+ // isProjection(entity) → mountReadOnlyCrudRoutes (GET list + GET :id)
25
+ // vanilla / write-through entity → mountCrudRoutes (all 5 CRUD verbs)
26
+ import { code, imp } from "ts-poet";
27
+ import {} from "../render-context.js";
28
+ import { entityModuleSpecifier } from "../import-path.js";
29
+ import { GENERATED_HEADER } from "../constants.js";
30
+ import { variableNameFromEntity } from "../naming.js";
31
+ import { isProjection } from "../projection/projection-detector.js";
32
+ export function renderRoutesFileHono(entity, ctx) {
33
+ const entityName = entity.name;
34
+ const handlerName = `register${entityName}Routes`;
35
+ const entityFileSpec = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, entity.package, entityName, ctx.extStyle);
36
+ const header = `// ${GENERATED_HEADER} — DO NOT EDIT.\n` +
37
+ `// Source metadata: ${entityName} (${entity.fqn()})\n` +
38
+ `// Customize via ${entityName}.extra.ts in this directory (e.g., auth, additional handlers).\n`;
39
+ // Path composition: apiPrefix is a literal string in the URL.
40
+ const pathExpr = ctx.apiPrefix
41
+ ? `\`${ctx.apiPrefix}\${${entityName}.$path}\``
42
+ : `${entityName}.$path`;
43
+ // --- Projection path: read-only routes (GET list + GET :id) ---
44
+ if (isProjection(entity)) {
45
+ const camelName = entityName.charAt(0).toLowerCase() + entityName.slice(1);
46
+ const HonoSym = imp("t:Hono@hono");
47
+ const mountReadOnlyCrudRoutesSym = imp("mountReadOnlyCrudRoutes@@metaobjectsdev/runtime-ts/hono");
48
+ const literalImports = code `
49
+ import {
50
+ ${entityName},
51
+ ${camelName}View,
52
+ ${entityName}FilterAllowlist,
53
+ ${entityName}SortAllowlist,
54
+ } from ${JSON.stringify(entityFileSpec)};
55
+ `;
56
+ const body = code `
57
+ /**
58
+ * Mount read-only REST endpoints for ${entityName} (projection — view-backed, no writes).
59
+ *
60
+ * Exposes GET list + GET :id only. POST/PATCH/DELETE return 405.
61
+ * Customize: register this as-is, or import individual route helpers from
62
+ * @metaobjectsdev/runtime-ts/hono.
63
+ */
64
+ // biome-ignore lint/suspicious/noExplicitAny: consumer-defined Hono bindings/variables
65
+ export function ${handlerName}(app: ${HonoSym}<any, any, any>, deps: { db: unknown }): void {
66
+ ${mountReadOnlyCrudRoutesSym}({
67
+ app,
68
+ path: ${pathExpr},
69
+ db: deps.db,
70
+ view: ${camelName}View,
71
+ filterAllowlist: ${entityName}FilterAllowlist,
72
+ sortAllowlist: ${entityName}SortAllowlist,
73
+ dialect: ${JSON.stringify(ctx.dialect)},
74
+ });
75
+ }
76
+ `;
77
+ return header + literalImports.toString() + body.toString();
78
+ }
79
+ // --- Vanilla / write-through entity path: full CRUD routes ---
80
+ const tableVar = variableNameFromEntity(entityName);
81
+ const HonoSym = imp("t:Hono@hono");
82
+ const mountCrudRoutesSym = imp("mountCrudRoutes@@metaobjectsdev/runtime-ts/hono");
83
+ const literalImports = code `
84
+ import {
85
+ ${entityName},
86
+ ${tableVar},
87
+ ${entityName}InsertSchema,
88
+ ${entityName}UpdateSchema,
89
+ ${entityName}FilterAllowlist,
90
+ ${entityName}SortAllowlist,
91
+ } from ${JSON.stringify(entityFileSpec)};
92
+ `;
93
+ const body = code `
94
+ /**
95
+ * Mount the 5 standard REST endpoints for ${entityName} using Drizzle directly.
96
+ *
97
+ * Customize: register this as-is for stock CRUD, OR import the per-verb
98
+ * helpers (mountListRoute, mountGetRoute, ...) from
99
+ * @metaobjectsdev/runtime-ts/hono and mix with your own handlers
100
+ * (auth, side effects, etc.).
101
+ */
102
+ // biome-ignore lint/suspicious/noExplicitAny: consumer-defined Hono bindings/variables
103
+ export function ${handlerName}(app: ${HonoSym}<any, any, any>, deps: { db: unknown }): void {
104
+ ${mountCrudRoutesSym}({
105
+ app,
106
+ path: ${pathExpr},
107
+ db: deps.db,
108
+ table: ${tableVar},
109
+ insertSchema: ${entityName}InsertSchema,
110
+ updateSchema: ${entityName}UpdateSchema,
111
+ filterAllowlist: ${entityName}FilterAllowlist,
112
+ sortAllowlist: ${entityName}SortAllowlist,
113
+ dialect: ${JSON.stringify(ctx.dialect)},
114
+ });
115
+ }
116
+ `;
117
+ return header + literalImports.toString() + body.toString();
118
+ }
119
+ //# sourceMappingURL=routes-file-hono.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-file-hono.js","sourceRoot":"","sources":["../../src/templates/routes-file-hono.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { MetaObject } from "@metaobjectsdev/metadata";
2
+ export declare function renderValueObjectFile(obj: MetaObject): string;
3
+ //# sourceMappingURL=value-object-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-object-file.d.ts","sourceRoot":"","sources":["../../src/templates/value-object-file.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAK3D,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAa7D"}
@@ -0,0 +1,27 @@
1
+ // Value-object file composer — emits a streamlined "value-only" module for
2
+ // metaobjects with no writable source.rdb child. Output is just the TS
3
+ // interface + the Zod schema (and enum type aliases when applicable); no
4
+ // Drizzle table, no Infer*Model aliases, no filter allowlists, no constants
5
+ // object.
6
+ //
7
+ // Dispatch: entity-file.ts routes here when hasWritableRdbSource(entity) is
8
+ // false. The entity may still have read-only source.* children (those are
9
+ // handled by the projection path before this one is reached).
10
+ import { joinCode } from "ts-poet";
11
+ import { renderValueObjectInterface, renderEnumTypeAliases } from "./inferred-types.js";
12
+ import { renderInsertSchemaOnly } from "./zod-validators.js";
13
+ import { GENERATED_HEADER } from "../constants.js";
14
+ export function renderValueObjectFile(obj) {
15
+ const enumAliases = renderEnumTypeAliases(obj);
16
+ const sections = [
17
+ renderValueObjectInterface(obj),
18
+ ...(enumAliases !== null ? [enumAliases] : []),
19
+ renderInsertSchemaOnly(obj),
20
+ ];
21
+ const body = joinCode(sections, { on: "\n" }).toString();
22
+ const header = `// ${GENERATED_HEADER} — DO NOT EDIT.\n` +
23
+ `// Source metadata: ${obj.name} (${obj.fqn()})\n` +
24
+ `// Customize via ${obj.name}.extra.ts in this directory.\n`;
25
+ return header + body;
26
+ }
27
+ //# sourceMappingURL=value-object-file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-object-file.js","sourceRoot":"","sources":["../../src/templates/value-object-file.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,uEAAuE;AACvE,yEAAyE;AACzE,4EAA4E;AAC5E,UAAU;AACV,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,8DAA8D;AAE9D,OAAO,EAAE,QAAQ,EAAa,MAAM,SAAS,CAAC;AAE9C,OAAO,EAAE,0BAA0B,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,MAAM,UAAU,qBAAqB,CAAC,GAAe;IACnD,MAAM,WAAW,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAW;QACvB,0BAA0B,CAAC,GAAG,CAAC;QAC/B,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9C,sBAAsB,CAAC,GAAG,CAAC;KAC5B,CAAC;IACF,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC;IACzD,MAAM,MAAM,GACV,MAAM,gBAAgB,mBAAmB;QACzC,uBAAuB,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG,EAAE,KAAK;QAClD,oBAAoB,GAAG,CAAC,IAAI,gCAAgC,CAAC;IAC/D,OAAO,MAAM,GAAG,IAAI,CAAC;AACvB,CAAC"}
@@ -1,4 +1,14 @@
1
1
  import { type Code } from "ts-poet";
2
2
  import { MetaObject } from "@metaobjectsdev/metadata";
3
+ /**
4
+ * Emit ONLY the `<Name>InsertSchema`. Used by the value-object file emitter
5
+ * for metaobjects with no writable source.rdb — those have no PATCH/update
6
+ * semantics, so emitting an UpdateSchema would be misleading.
7
+ *
8
+ * The schema name is kept as `<Name>InsertSchema` even for pure value objects
9
+ * so consumer imports don't churn. A future polish PR could add a `<Name>Schema`
10
+ * alias for clarity.
11
+ */
12
+ export declare function renderInsertSchemaOnly(obj: MetaObject): Code;
3
13
  export declare function renderZodValidators(obj: MetaObject): Code;
4
14
  //# sourceMappingURL=zod-validators.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"zod-validators.d.ts","sourceRoot":"","sources":["../../src/templates/zod-validators.ts"],"names":[],"mappings":"AAKA,OAAO,EAAa,KAAK,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAa,MAAM,0BAA0B,CAAC;AAgBjE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CA6DzD"}
1
+ {"version":3,"file":"zod-validators.d.ts","sourceRoot":"","sources":["../../src/templates/zod-validators.ts"],"names":[],"mappings":"AAWA,OAAO,EAAuB,KAAK,IAAI,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,EAAE,UAAU,EAAa,MAAM,0BAA0B,CAAC;AA+BjE;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CA4B5D;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI,CAqDzD"}
@@ -2,24 +2,68 @@
2
2
  // Auto-generated PKs are EXCLUDED from InsertSchema (caller doesn't provide them).
3
3
  // @autoSet fields: INSERT → .optional().transform(() => new Date().toISOString())
4
4
  // UPDATE → onCreate fields omitted entirely; onUpdate gets same transform
5
- import { code, imp } from "ts-poet";
5
+ //
6
+ // field.object isArray:true objectRef:<Ref> — emits z.array(<Ref>InsertSchema)
7
+ // with a cross-module imp() so consumers passing the schema to
8
+ // zod-to-json-schema get a properly element-typed array. Without this, every
9
+ // object-array field collapsed to z.array(z.string()) and the JSON Schema sent
10
+ // downstream (e.g. to LLM tool_use input_schema) lost the nested object shape.
11
+ import { code, joinCode, imp } from "ts-poet";
6
12
  import { MetaObject, MetaField } from "@metaobjectsdev/metadata";
7
- import { FIELD_SUBTYPE_STRING, FIELD_SUBTYPE_INT, FIELD_SUBTYPE_LONG, FIELD_SUBTYPE_CURRENCY, FIELD_SUBTYPE_BOOLEAN, FIELD_SUBTYPE_DOUBLE, FIELD_SUBTYPE_FLOAT, FIELD_SUBTYPE_DATE, FIELD_SUBTYPE_TIME, FIELD_SUBTYPE_TIMESTAMP, FIELD_SUBTYPE_ENUM, VALIDATOR_SUBTYPE_REQUIRED, VALIDATOR_SUBTYPE_LENGTH, VALIDATOR_SUBTYPE_REGEX, IDENTITY_ATTR_FIELDS, IDENTITY_ATTR_GENERATION, FIELD_ATTR_REQUIRED, FIELD_ATTR_MAX_LENGTH, FIELD_ATTR_DEFAULT, FIELD_ATTR_AUTO_SET, AUTO_SET_ON_CREATE, AUTO_SET_ON_UPDATE, VALIDATOR_ATTR_MAX, VALIDATOR_ATTR_MIN, VALIDATOR_ATTR_PATTERN, GENERATION_INCREMENT, GENERATION_UUID, } from "@metaobjectsdev/metadata";
13
+ import { FIELD_SUBTYPE_STRING, FIELD_SUBTYPE_INT, FIELD_SUBTYPE_LONG, FIELD_SUBTYPE_CURRENCY, FIELD_SUBTYPE_BOOLEAN, FIELD_SUBTYPE_DOUBLE, FIELD_SUBTYPE_FLOAT, FIELD_SUBTYPE_DATE, FIELD_SUBTYPE_TIME, FIELD_SUBTYPE_TIMESTAMP, FIELD_SUBTYPE_ENUM, FIELD_SUBTYPE_OBJECT, VALIDATOR_SUBTYPE_REQUIRED, VALIDATOR_SUBTYPE_LENGTH, VALIDATOR_SUBTYPE_REGEX, IDENTITY_ATTR_FIELDS, IDENTITY_ATTR_GENERATION, FIELD_ATTR_REQUIRED, FIELD_ATTR_MAX_LENGTH, FIELD_ATTR_DEFAULT, FIELD_ATTR_AUTO_SET, FIELD_ATTR_OBJECT_REF, AUTO_SET_ON_CREATE, AUTO_SET_ON_UPDATE, VALIDATOR_ATTR_MAX, VALIDATOR_ATTR_MIN, VALIDATOR_ATTR_PATTERN, GENERATION_INCREMENT, GENERATION_UUID, } from "@metaobjectsdev/metadata";
8
14
  import { enumValues, zodEnumExpr } from "../enum-meta.js";
9
15
  import { renderDocsFor } from "./jsdoc.js";
10
- export function renderZodValidators(obj) {
11
- const z = imp("z@zod");
16
+ /** Auto-generated PK field names that should be omitted from InsertSchema. */
17
+ function autoGenPkFieldNames(obj) {
18
+ const out = new Set();
12
19
  const primary = obj.primaryIdentity();
13
- const autoGenPkFields = new Set();
14
20
  if (primary) {
15
21
  const generation = primary.ownAttr(IDENTITY_ATTR_GENERATION);
16
22
  if (generation === GENERATION_INCREMENT || generation === GENERATION_UUID) {
17
23
  const fields = primary.ownAttr(IDENTITY_ATTR_FIELDS);
18
24
  const fieldsList = Array.isArray(fields) ? fields : (typeof fields === "string" ? [fields] : []);
19
25
  for (const f of fieldsList)
20
- autoGenPkFields.add(String(f));
26
+ out.add(String(f));
21
27
  }
22
28
  }
29
+ return out;
30
+ }
31
+ /**
32
+ * Emit ONLY the `<Name>InsertSchema`. Used by the value-object file emitter
33
+ * for metaobjects with no writable source.rdb — those have no PATCH/update
34
+ * semantics, so emitting an UpdateSchema would be misleading.
35
+ *
36
+ * The schema name is kept as `<Name>InsertSchema` even for pure value objects
37
+ * so consumer imports don't churn. A future polish PR could add a `<Name>Schema`
38
+ * alias for clarity.
39
+ */
40
+ export function renderInsertSchemaOnly(obj) {
41
+ const z = imp("z@zod");
42
+ const autoGenPkFields = autoGenPkFieldNames(obj);
43
+ const insertFieldLines = [];
44
+ for (const child of obj.fields()) {
45
+ if (autoGenPkFields.has(child.name))
46
+ continue;
47
+ const autoSet = child.ownAttr(FIELD_ATTR_AUTO_SET);
48
+ if (autoSet === AUTO_SET_ON_CREATE || autoSet === AUTO_SET_ON_UPDATE) {
49
+ insertFieldLines.push(code ` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`);
50
+ }
51
+ else {
52
+ insertFieldLines.push(code ` ${child.name}: ${zodFieldExpr(child)}`);
53
+ }
54
+ }
55
+ const insertSchemaName = `${obj.name}InsertSchema`;
56
+ const docs = renderDocsFor(obj);
57
+ const docsPrefix = docs ? `${docs}\n` : "";
58
+ return code `
59
+ ${docsPrefix}export const ${insertSchemaName} = ${z}.object({
60
+ ${joinCode(insertFieldLines, { on: ",\n" })}
61
+ });
62
+ `;
63
+ }
64
+ export function renderZodValidators(obj) {
65
+ const z = imp("z@zod");
66
+ const autoGenPkFields = autoGenPkFieldNames(obj);
23
67
  const insertFieldLines = [];
24
68
  const updateFieldLines = [];
25
69
  for (const child of obj.fields()) {
@@ -27,26 +71,25 @@ export function renderZodValidators(obj) {
27
71
  continue;
28
72
  const autoSet = child.ownAttr(FIELD_ATTR_AUTO_SET);
29
73
  // Insert schema: @autoSet fields use transform (always override client input).
30
- // NOTE: use "z" as a literal string here — these lines are embedded in the
31
- // `code` template tag below which resolves the imp("z@zod") import.
32
74
  if (autoSet === AUTO_SET_ON_CREATE || autoSet === AUTO_SET_ON_UPDATE) {
33
- insertFieldLines.push(` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`);
75
+ insertFieldLines.push(code ` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`);
34
76
  }
35
77
  else {
36
- insertFieldLines.push(` ${child.name}: ${zodFieldExpr(child)}`);
78
+ insertFieldLines.push(code ` ${child.name}: ${zodFieldExpr(child)}`);
37
79
  }
38
80
  // Update schema: @autoSet onCreate → omit entirely; onUpdate → transform
39
81
  if (autoSet === AUTO_SET_ON_CREATE) {
40
82
  // Omit: creation timestamps cannot be changed after creation
41
83
  }
42
84
  else if (autoSet === AUTO_SET_ON_UPDATE) {
43
- updateFieldLines.push(` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`);
85
+ updateFieldLines.push(code ` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`);
44
86
  }
45
87
  else {
46
- // All non-autoSet fields are optional in the update schema (PATCH semantics)
47
- const expr = zodFieldExpr(child);
48
- const optionalExpr = expr.endsWith(".optional()") ? expr : `${expr}.optional()`;
49
- updateFieldLines.push(` ${child.name}: ${optionalExpr}`);
88
+ // All non-autoSet fields are optional in the update schema (PATCH semantics).
89
+ // zodFieldExpr already appends .optional() when the field is non-required
90
+ // OR has a default; only append once more when it didn't.
91
+ const baseExpr = zodFieldExpr(child);
92
+ updateFieldLines.push(fieldWillBeOptional(child) ? code ` ${child.name}: ${baseExpr}` : code ` ${child.name}: ${baseExpr}.optional()`);
50
93
  }
51
94
  }
52
95
  const insertSchemaName = `${obj.name}InsertSchema`;
@@ -55,46 +98,81 @@ export function renderZodValidators(obj) {
55
98
  const docsPrefix = docs ? `${docs}\n` : "";
56
99
  return code `
57
100
  ${docsPrefix}export const ${insertSchemaName} = ${z}.object({
58
- ${insertFieldLines.join(",\n")}
101
+ ${joinCode(insertFieldLines, { on: ",\n" })}
59
102
  });
60
103
 
61
104
  ${docsPrefix}export const ${updateSchemaName} = ${z}.object({
62
- ${updateFieldLines.join(",\n")}
105
+ ${joinCode(updateFieldLines, { on: ",\n" })}
63
106
  });
64
107
  `;
65
108
  }
66
109
  function zodFieldExpr(field) {
67
- let base;
110
+ // FIELD_SUBTYPE_OBJECT: emit z.array(<Ref>InsertSchema) / <Ref>InsertSchema
111
+ // via an imp() so ts-poet hoists the cross-module import. Without this the
112
+ // field used to collapse to z.string() / z.array(z.string()) and downstream
113
+ // JSON Schema (e.g. LLM tool_use input_schema) lost the nested object shape.
114
+ if (field.subType === FIELD_SUBTYPE_OBJECT) {
115
+ const ref = field.ownAttr(FIELD_ATTR_OBJECT_REF);
116
+ if (typeof ref === "string" && ref.length > 0) {
117
+ const refImp = imp(`${ref}InsertSchema@./${ref}.js`);
118
+ let base = code `${refImp}`;
119
+ if (field.isArray)
120
+ base = code `z.array(${base})`;
121
+ return appendValidatorChain(base, field);
122
+ }
123
+ // No resolvable @objectRef — fall through to z.unknown(); downstream code
124
+ // can still pass a value through but loses validation.
125
+ let base = code `z.unknown()`;
126
+ if (field.isArray)
127
+ base = code `z.array(${base})`;
128
+ return appendValidatorChain(base, field);
129
+ }
130
+ let baseStr;
68
131
  switch (field.subType) {
69
132
  case FIELD_SUBTYPE_INT:
70
133
  case FIELD_SUBTYPE_CURRENCY:
71
134
  case FIELD_SUBTYPE_LONG:
72
- base = "z.number().int()";
135
+ baseStr = "z.number().int()";
73
136
  break;
74
137
  case FIELD_SUBTYPE_DOUBLE:
75
138
  case FIELD_SUBTYPE_FLOAT:
76
- base = "z.number()";
139
+ baseStr = "z.number()";
77
140
  break;
78
141
  case FIELD_SUBTYPE_BOOLEAN:
79
- base = "z.boolean()";
142
+ baseStr = "z.boolean()";
80
143
  break;
81
144
  case FIELD_SUBTYPE_DATE:
82
145
  case FIELD_SUBTYPE_TIME:
83
146
  case FIELD_SUBTYPE_TIMESTAMP:
84
- base = "z.string()";
147
+ baseStr = "z.string()";
85
148
  break;
86
149
  case FIELD_SUBTYPE_ENUM: {
87
150
  const values = enumValues(field);
88
- base = values !== undefined ? zodEnumExpr(values) : "z.string()";
151
+ baseStr = values !== undefined ? zodEnumExpr(values) : "z.string()";
89
152
  break;
90
153
  }
91
154
  case FIELD_SUBTYPE_STRING:
92
155
  default:
93
- base = "z.string()";
156
+ baseStr = "z.string()";
94
157
  break;
95
158
  }
96
159
  if (field.isArray)
97
- base = `z.array(${base})`;
160
+ baseStr = `z.array(${baseStr})`;
161
+ return appendValidatorChain(code `${baseStr}`, field);
162
+ }
163
+ /** Mirrors the optional-or-not decision inside appendValidatorChain so the update-schema
164
+ * caller can avoid stacking a second `.optional()` onto an already-optional expression. */
165
+ function fieldWillBeOptional(field) {
166
+ let isRequired = field.ownAttr(FIELD_ATTR_REQUIRED) === true;
167
+ for (const child of field.validators()) {
168
+ if (child.subType === VALIDATOR_SUBTYPE_REQUIRED)
169
+ isRequired = true;
170
+ }
171
+ const hasDefault = field.ownAttr(FIELD_ATTR_DEFAULT) !== undefined;
172
+ return !isRequired || hasDefault;
173
+ }
174
+ /** Append .min/.max/.regex/.optional() based on field-level validators + required state. */
175
+ function appendValidatorChain(base, field) {
98
176
  let isRequired = field.ownAttr(FIELD_ATTR_REQUIRED) === true;
99
177
  let maxLen = field.ownAttr(FIELD_ATTR_MAX_LENGTH);
100
178
  let minLen;
@@ -119,20 +197,20 @@ function zodFieldExpr(field) {
119
197
  let chain = base;
120
198
  if (field.subType === FIELD_SUBTYPE_STRING && !field.isArray) {
121
199
  if (minLen !== undefined)
122
- chain += `.min(${minLen})`;
200
+ chain = code `${chain}.min(${minLen})`;
123
201
  else if (isRequired)
124
- chain += `.min(1)`;
202
+ chain = code `${chain}.min(1)`;
125
203
  if (maxLen !== undefined)
126
- chain += `.max(${maxLen})`;
204
+ chain = code `${chain}.max(${maxLen})`;
127
205
  if (pattern !== undefined)
128
- chain += `.regex(new RegExp(${JSON.stringify(pattern)}))`;
206
+ chain = code `${chain}.regex(new RegExp(${JSON.stringify(pattern)}))`;
129
207
  }
130
208
  // Fields with DB-level defaults are optional in the InsertSchema: the caller
131
209
  // can omit them and the DB will fill in. Otherwise required-with-default
132
210
  // would force callers to repeat the default at every call site.
133
211
  const hasDefault = field.ownAttr(FIELD_ATTR_DEFAULT) !== undefined;
134
212
  if (!isRequired || hasDefault)
135
- chain += `.optional()`;
213
+ chain = code `${chain}.optional()`;
136
214
  return chain;
137
215
  }
138
216
  //# sourceMappingURL=zod-validators.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"zod-validators.js","sourceRoot":"","sources":["../../src/templates/zod-validators.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"zod-validators.js","sourceRoot":"","sources":["../../src/templates/zod-validators.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaobjectsdev/codegen-ts",
3
- "version": "0.6.0",
3
+ "version": "0.7.0-rc.10",
4
4
  "description": "TypeScript codegen engine for MetaObjects — emits Drizzle, Zod, and Fastify artifacts.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,7 +38,7 @@
38
38
  "access": "public"
39
39
  },
40
40
  "dependencies": {
41
- "@metaobjectsdev/metadata": "0.6.0",
41
+ "@metaobjectsdev/metadata": "0.7.0-rc.10",
42
42
  "@biomejs/js-api": "^0.7.0",
43
43
  "@biomejs/wasm-nodejs": "^1.9.4",
44
44
  "ts-poet": "^6.10.0"
@@ -49,10 +49,11 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@biomejs/biome": "^1.9.0",
52
- "@metaobjectsdev/codegen-ts-react": "0.6.0",
53
- "@metaobjectsdev/render": "0.6.0",
52
+ "@metaobjectsdev/codegen-ts-react": "0.7.0-rc.10",
53
+ "@metaobjectsdev/render": "0.7.0-rc.10",
54
54
  "bun-types": "latest",
55
55
  "drizzle-orm": "^0.36.0",
56
+ "hono": "^4.6.0",
56
57
  "typescript": "^5.6.0",
57
58
  "zod": "^3.23.0"
58
59
  }
@@ -23,10 +23,12 @@ import {
23
23
  FIELD_ATTR_REQUIRED,
24
24
  FIELD_ATTR_UNIQUE,
25
25
  FIELD_ATTR_DEFAULT,
26
+ FIELD_ATTR_OBJECT_REF,
26
27
  VALIDATOR_ATTR_MAX,
27
28
  } from "@metaobjectsdev/metadata";
28
29
  import { columnNameFromField } from "./naming.js";
29
30
  import { enumValues } from "./enum-meta.js";
31
+ import { DEFAULT_COLUMN_NAMING_STRATEGY } from "@metaobjectsdev/metadata";
30
32
  import type { Dialect, ColumnNamingStrategy } from "./metaobjects-config.js";
31
33
 
32
34
  export type { Dialect };
@@ -62,6 +64,36 @@ function isSqlExprDefault(value: string): boolean {
62
64
  return SQL_EXPR_PATTERNS.some((re) => re.test(value));
63
65
  }
64
66
 
67
+ /**
68
+ * For an isArray:true field stored in SQLite as text(...,{mode:"json"}), return
69
+ * the TS element type used in the emitted .$type<E[]>() chain. Returns undefined
70
+ * when the field's subType doesn't have a stable scalar TS mapping (e.g.,
71
+ * field.object — leave the inferred `unknown[]` so the consumer can layer a
72
+ * richer schema on top).
73
+ */
74
+ function sqliteJsonArrayElementTsType(subType: string): string | undefined {
75
+ switch (subType) {
76
+ case FIELD_SUBTYPE_STRING:
77
+ case FIELD_SUBTYPE_ENUM:
78
+ case FIELD_SUBTYPE_CLASS:
79
+ case FIELD_SUBTYPE_DATE:
80
+ case FIELD_SUBTYPE_TIME:
81
+ case FIELD_SUBTYPE_TIMESTAMP:
82
+ case FIELD_SUBTYPE_DECIMAL:
83
+ return "string";
84
+ case FIELD_SUBTYPE_INT:
85
+ case FIELD_SUBTYPE_LONG:
86
+ case FIELD_SUBTYPE_CURRENCY:
87
+ case FIELD_SUBTYPE_DOUBLE:
88
+ case FIELD_SUBTYPE_FLOAT:
89
+ return "number";
90
+ case FIELD_SUBTYPE_BOOLEAN:
91
+ return "boolean";
92
+ default:
93
+ return undefined;
94
+ }
95
+ }
96
+
65
97
  /** Map a recognized SQL expression to its canonical raw form (uppercase keywords). */
66
98
  function canonicalizeSqlExpr(value: string): string {
67
99
  const lower = value.toLowerCase();
@@ -92,6 +124,17 @@ export interface ColumnSpec {
92
124
  leadingComment?: string;
93
125
  /** Optional CHECK constraint expression for the column (e.g., `status IN ('A', 'B')`). */
94
126
  checkConstraint?: string;
127
+ /**
128
+ * Optional `.$type<...>()` chain target. Renderer (drizzle-schema.ts) emits
129
+ * `.$type<TS[]>()` ahead of the modifiers chain, using ts-poet `imp()` for
130
+ * objectRef variants so the cross-module type import auto-hoists.
131
+ * `kind: "scalar"` covers string[]/number[]/boolean[] — no import needed.
132
+ * `kind: "objectRef"` covers SourceLens[]/Dissent[]/etc. — `module` is the
133
+ * relative import path to that entity's emitted module.
134
+ */
135
+ dollarTypeRef?:
136
+ | { kind: "scalar"; tsType: "string" | "number" | "boolean" }
137
+ | { kind: "objectRef"; name: string; module: string };
95
138
  }
96
139
 
97
140
  /** Resolve max length from validator.length child or @maxLength attr.
@@ -118,7 +161,7 @@ function isRequired(field: MetaField): boolean {
118
161
  export function mapColumnType(
119
162
  field: MetaField,
120
163
  dialect: Dialect,
121
- strategy: ColumnNamingStrategy = "snake_case",
164
+ strategy: ColumnNamingStrategy = DEFAULT_COLUMN_NAMING_STRATEGY,
122
165
  ): ColumnSpec {
123
166
  const dbName = field.column ?? columnNameFromField(field.name, strategy);
124
167
  const importModule = dialect === "sqlite" ? "drizzle-orm/sqlite-core" : "drizzle-orm/pg-core";
@@ -219,12 +262,36 @@ export function mapColumnType(
219
262
  }
220
263
  }
221
264
 
265
+ // Enum literal types: pass the values as `{ enum: [...] as const }` to
266
+ // Drizzle's text(...) so the inferred column type is a literal union
267
+ // ("a" | "b" | ...) instead of bare `string`. Skip when isArray — JSON
268
+ // arrays use { mode: "json" }, and the enum members go through Zod
269
+ // validation at the Insert/Update layer instead. Mirrors the Zod
270
+ // emission, which already uses z.enum([...]).
271
+ if (subType === FIELD_SUBTYPE_ENUM && !isArray && fnName === "text") {
272
+ const values = enumValues(field);
273
+ if (values !== undefined && values.length > 0) {
274
+ fnOptions = { ...(fnOptions ?? {}), enum: values };
275
+ }
276
+ }
277
+
222
278
  const modifiers: string[] = [];
223
279
 
224
280
  if (dialect === "postgres" && isArray) {
225
281
  modifiers.push(".array()");
226
282
  }
227
283
 
284
+ // SQLite stores arrays as JSON in a text column; Drizzle's text(...,{mode:"json"})
285
+ // infers the column as `unknown` without a $type<T>() annotation. Emit the
286
+ // chain via spec.dollarTypeRef so the renderer can hoist a type-only import
287
+ // for object refs (SourceLens[], Dissent[], etc.). Scalars (string/number/
288
+ // boolean) need no import. Postgres uses .array() above which is already
289
+ // element-typed by Drizzle.
290
+ // Determined ABOVE the modifiers chain so the renderer can position
291
+ // `.$type<>()` ahead of `.notNull()` etc.
292
+ // Note: dollarTypeRef is read alongside (and rendered ahead of) `modifiers`
293
+ // by `renderColumn` — see drizzle-schema.ts.
294
+
228
295
  if (isRequired(field)) {
229
296
  modifiers.push(".notNull()");
230
297
  }
@@ -257,6 +324,23 @@ export function mapColumnType(
257
324
  }
258
325
  }
259
326
 
327
+ // SQLite isArray columns route through {mode:"json"} above; compute the
328
+ // $type<E[]>() target so the renderer can hoist any cross-module imports.
329
+ let dollarTypeRef: ColumnSpec["dollarTypeRef"];
330
+ if (dialect === "sqlite" && isArray) {
331
+ if (subType === FIELD_SUBTYPE_OBJECT) {
332
+ const ref = field.ownAttr(FIELD_ATTR_OBJECT_REF);
333
+ if (typeof ref === "string" && ref.length > 0) {
334
+ dollarTypeRef = { kind: "objectRef", name: ref, module: `./${ref}.js` };
335
+ }
336
+ } else {
337
+ const scalar = sqliteJsonArrayElementTsType(subType);
338
+ if (scalar !== undefined) {
339
+ dollarTypeRef = { kind: "scalar", tsType: scalar as "string" | "number" | "boolean" };
340
+ }
341
+ }
342
+ }
343
+
260
344
  const result: ColumnSpec = {
261
345
  fnName,
262
346
  dbName,
@@ -266,6 +350,7 @@ export function mapColumnType(
266
350
  };
267
351
  if (fnOptions !== undefined) result.fnOptions = fnOptions;
268
352
  if (defaultExpr !== undefined) result.defaultExpr = defaultExpr;
353
+ if (dollarTypeRef !== undefined) result.dollarTypeRef = dollarTypeRef;
269
354
  if (leadingComment !== undefined) result.leadingComment = leadingComment;
270
355
 
271
356
  // Enum fields: emit a CHECK constraint listing the valid member values.