@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.
- package/README.md +161 -4
- package/dist/column-mapper.d.ts +16 -0
- package/dist/column-mapper.d.ts.map +1 -1
- package/dist/column-mapper.js +73 -2
- package/dist/column-mapper.js.map +1 -1
- package/dist/generators/docs-file.d.ts +8 -0
- package/dist/generators/docs-file.d.ts.map +1 -0
- package/dist/generators/docs-file.js +52 -0
- package/dist/generators/docs-file.js.map +1 -0
- package/dist/generators/entity-file.d.ts +15 -0
- package/dist/generators/entity-file.d.ts.map +1 -1
- package/dist/generators/entity-file.js +2 -1
- package/dist/generators/entity-file.js.map +1 -1
- package/dist/generators/index.d.ts +4 -0
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +4 -0
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/output-parser-file.d.ts +9 -0
- package/dist/generators/output-parser-file.d.ts.map +1 -0
- package/dist/generators/output-parser-file.js +37 -0
- package/dist/generators/output-parser-file.js.map +1 -0
- package/dist/generators/prompt-render-file.d.ts +9 -0
- package/dist/generators/prompt-render-file.d.ts.map +1 -0
- package/dist/generators/prompt-render-file.js +70 -0
- package/dist/generators/prompt-render-file.js.map +1 -0
- package/dist/generators/queries-file.d.ts +1 -1
- package/dist/generators/queries-file.d.ts.map +1 -1
- package/dist/generators/queries-file.js +11 -3
- package/dist/generators/queries-file.js.map +1 -1
- package/dist/generators/routes-file-hono.d.ts +21 -0
- package/dist/generators/routes-file-hono.d.ts.map +1 -0
- package/dist/generators/routes-file-hono.js +38 -0
- package/dist/generators/routes-file-hono.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/metaobjects-config.d.ts +10 -1
- package/dist/metaobjects-config.d.ts.map +1 -1
- package/dist/metaobjects-config.js +2 -1
- package/dist/metaobjects-config.js.map +1 -1
- package/dist/naming.d.ts +3 -12
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +14 -44
- package/dist/naming.js.map +1 -1
- package/dist/payload-codegen.d.ts +8 -0
- package/dist/payload-codegen.d.ts.map +1 -1
- package/dist/payload-codegen.js +33 -3
- package/dist/payload-codegen.js.map +1 -1
- package/dist/projection/extract-view-spec.d.ts +1 -1
- package/dist/projection/extract-view-spec.js +1 -1
- package/dist/source-detect.d.ts +10 -0
- package/dist/source-detect.d.ts.map +1 -0
- package/dist/source-detect.js +30 -0
- package/dist/source-detect.js.map +1 -0
- package/dist/templates/docs-file.d.ts +48 -0
- package/dist/templates/docs-file.d.ts.map +1 -0
- package/dist/templates/docs-file.js +445 -0
- package/dist/templates/docs-file.js.map +1 -0
- package/dist/templates/drizzle-schema.js +27 -3
- package/dist/templates/drizzle-schema.js.map +1 -1
- package/dist/templates/entity-file.d.ts +15 -1
- package/dist/templates/entity-file.d.ts.map +1 -1
- package/dist/templates/entity-file.js +15 -5
- package/dist/templates/entity-file.js.map +1 -1
- package/dist/templates/inferred-types.d.ts +9 -0
- package/dist/templates/inferred-types.d.ts.map +1 -1
- package/dist/templates/inferred-types.js +88 -2
- package/dist/templates/inferred-types.js.map +1 -1
- package/dist/templates/output-parser.d.ts +8 -0
- package/dist/templates/output-parser.d.ts.map +1 -0
- package/dist/templates/output-parser.js +129 -0
- package/dist/templates/output-parser.js.map +1 -0
- package/dist/templates/projection-decl.d.ts +1 -1
- package/dist/templates/projection-decl.js +1 -1
- package/dist/templates/queries-file.d.ts.map +1 -1
- package/dist/templates/queries-file.js +15 -4
- package/dist/templates/queries-file.js.map +1 -1
- package/dist/templates/queries.d.ts.map +1 -1
- package/dist/templates/queries.js +11 -30
- package/dist/templates/queries.js.map +1 -1
- package/dist/templates/routes-file-hono.d.ts +4 -0
- package/dist/templates/routes-file-hono.d.ts.map +1 -0
- package/dist/templates/routes-file-hono.js +119 -0
- package/dist/templates/routes-file-hono.js.map +1 -0
- package/dist/templates/value-object-file.d.ts +3 -0
- package/dist/templates/value-object-file.d.ts.map +1 -0
- package/dist/templates/value-object-file.js +27 -0
- package/dist/templates/value-object-file.js.map +1 -0
- package/dist/templates/zod-validators.d.ts +10 -0
- package/dist/templates/zod-validators.d.ts.map +1 -1
- package/dist/templates/zod-validators.js +108 -30
- package/dist/templates/zod-validators.js.map +1 -1
- package/package.json +5 -4
- package/src/column-mapper.ts +86 -1
- package/src/generators/docs-file.ts +64 -0
- package/src/generators/entity-file.ts +17 -1
- package/src/generators/index.ts +4 -0
- package/src/generators/output-parser-file.ts +50 -0
- package/src/generators/prompt-render-file.ts +95 -0
- package/src/generators/queries-file.ts +13 -4
- package/src/generators/routes-file-hono.ts +48 -0
- package/src/index.ts +2 -2
- package/src/metaobjects-config.ts +11 -2
- package/src/naming.ts +22 -46
- package/src/payload-codegen.ts +34 -2
- package/src/projection/extract-view-spec.ts +1 -1
- package/src/source-detect.ts +28 -0
- package/src/templates/docs-file.ts +545 -0
- package/src/templates/drizzle-schema.ts +27 -3
- package/src/templates/entity-file.ts +36 -5
- package/src/templates/inferred-types.ts +117 -3
- package/src/templates/output-parser.ts +143 -0
- package/src/templates/projection-decl.ts +1 -1
- package/src/templates/queries-file.ts +18 -4
- package/src/templates/queries.ts +11 -33
- package/src/templates/routes-file-hono.ts +142 -0
- package/src/templates/value-object-file.ts +30 -0
- package/src/templates/zod-validators.ts +121 -35
|
@@ -2,53 +2,102 @@
|
|
|
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
|
+
//
|
|
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.
|
|
5
11
|
|
|
6
|
-
import { code, imp, type Code } from "ts-poet";
|
|
12
|
+
import { code, joinCode, imp, type Code } from "ts-poet";
|
|
7
13
|
import { MetaObject, MetaField } from "@metaobjectsdev/metadata";
|
|
8
14
|
import {
|
|
9
15
|
FIELD_SUBTYPE_STRING, FIELD_SUBTYPE_INT, FIELD_SUBTYPE_LONG, FIELD_SUBTYPE_CURRENCY,
|
|
10
16
|
FIELD_SUBTYPE_BOOLEAN, FIELD_SUBTYPE_DOUBLE, FIELD_SUBTYPE_FLOAT,
|
|
11
17
|
FIELD_SUBTYPE_DATE, FIELD_SUBTYPE_TIME, FIELD_SUBTYPE_TIMESTAMP,
|
|
12
|
-
FIELD_SUBTYPE_ENUM,
|
|
18
|
+
FIELD_SUBTYPE_ENUM, FIELD_SUBTYPE_OBJECT,
|
|
13
19
|
VALIDATOR_SUBTYPE_REQUIRED, VALIDATOR_SUBTYPE_LENGTH, VALIDATOR_SUBTYPE_REGEX,
|
|
14
20
|
IDENTITY_ATTR_FIELDS, IDENTITY_ATTR_GENERATION,
|
|
15
21
|
FIELD_ATTR_REQUIRED, FIELD_ATTR_MAX_LENGTH, FIELD_ATTR_DEFAULT,
|
|
16
|
-
FIELD_ATTR_AUTO_SET, AUTO_SET_ON_CREATE, AUTO_SET_ON_UPDATE,
|
|
22
|
+
FIELD_ATTR_AUTO_SET, FIELD_ATTR_OBJECT_REF, AUTO_SET_ON_CREATE, AUTO_SET_ON_UPDATE,
|
|
17
23
|
VALIDATOR_ATTR_MAX, VALIDATOR_ATTR_MIN, VALIDATOR_ATTR_PATTERN,
|
|
18
24
|
GENERATION_INCREMENT, GENERATION_UUID,
|
|
19
25
|
} from "@metaobjectsdev/metadata";
|
|
20
26
|
import { enumValues, zodEnumExpr } from "../enum-meta.js";
|
|
21
27
|
import { renderDocsFor } from "./jsdoc.js";
|
|
22
28
|
|
|
23
|
-
|
|
24
|
-
|
|
29
|
+
/** Auto-generated PK field names that should be omitted from InsertSchema. */
|
|
30
|
+
function autoGenPkFieldNames(obj: MetaObject): Set<string> {
|
|
31
|
+
const out = new Set<string>();
|
|
25
32
|
const primary = obj.primaryIdentity();
|
|
26
|
-
const autoGenPkFields = new Set<string>();
|
|
27
33
|
if (primary) {
|
|
28
34
|
const generation = primary.ownAttr(IDENTITY_ATTR_GENERATION);
|
|
29
35
|
if (generation === GENERATION_INCREMENT || generation === GENERATION_UUID) {
|
|
30
36
|
const fields = primary.ownAttr(IDENTITY_ATTR_FIELDS);
|
|
31
37
|
const fieldsList = Array.isArray(fields) ? fields : (typeof fields === "string" ? [fields] : []);
|
|
32
|
-
for (const f of fieldsList)
|
|
38
|
+
for (const f of fieldsList) out.add(String(f));
|
|
33
39
|
}
|
|
34
40
|
}
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
35
43
|
|
|
36
|
-
|
|
37
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Emit ONLY the `<Name>InsertSchema`. Used by the value-object file emitter
|
|
46
|
+
* for metaobjects with no writable source.rdb — those have no PATCH/update
|
|
47
|
+
* semantics, so emitting an UpdateSchema would be misleading.
|
|
48
|
+
*
|
|
49
|
+
* The schema name is kept as `<Name>InsertSchema` even for pure value objects
|
|
50
|
+
* so consumer imports don't churn. A future polish PR could add a `<Name>Schema`
|
|
51
|
+
* alias for clarity.
|
|
52
|
+
*/
|
|
53
|
+
export function renderInsertSchemaOnly(obj: MetaObject): Code {
|
|
54
|
+
const z = imp("z@zod");
|
|
55
|
+
const autoGenPkFields = autoGenPkFieldNames(obj);
|
|
56
|
+
|
|
57
|
+
const insertFieldLines: Code[] = [];
|
|
58
|
+
for (const child of obj.fields()) {
|
|
59
|
+
if (autoGenPkFields.has(child.name)) continue;
|
|
60
|
+
|
|
61
|
+
const autoSet = child.ownAttr(FIELD_ATTR_AUTO_SET);
|
|
62
|
+
|
|
63
|
+
if (autoSet === AUTO_SET_ON_CREATE || autoSet === AUTO_SET_ON_UPDATE) {
|
|
64
|
+
insertFieldLines.push(
|
|
65
|
+
code` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`,
|
|
66
|
+
);
|
|
67
|
+
} else {
|
|
68
|
+
insertFieldLines.push(code` ${child.name}: ${zodFieldExpr(child)}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const insertSchemaName = `${obj.name}InsertSchema`;
|
|
73
|
+
const docs = renderDocsFor(obj);
|
|
74
|
+
const docsPrefix = docs ? `${docs}\n` : "";
|
|
75
|
+
|
|
76
|
+
return code`
|
|
77
|
+
${docsPrefix}export const ${insertSchemaName} = ${z}.object({
|
|
78
|
+
${joinCode(insertFieldLines, { on: ",\n" })}
|
|
79
|
+
});
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function renderZodValidators(obj: MetaObject): Code {
|
|
84
|
+
const z = imp("z@zod");
|
|
85
|
+
const autoGenPkFields = autoGenPkFieldNames(obj);
|
|
86
|
+
|
|
87
|
+
const insertFieldLines: Code[] = [];
|
|
88
|
+
const updateFieldLines: Code[] = [];
|
|
38
89
|
for (const child of obj.fields()) {
|
|
39
90
|
if (autoGenPkFields.has(child.name)) continue;
|
|
40
91
|
|
|
41
92
|
const autoSet = child.ownAttr(FIELD_ATTR_AUTO_SET);
|
|
42
93
|
|
|
43
94
|
// Insert schema: @autoSet fields use transform (always override client input).
|
|
44
|
-
// NOTE: use "z" as a literal string here — these lines are embedded in the
|
|
45
|
-
// `code` template tag below which resolves the imp("z@zod") import.
|
|
46
95
|
if (autoSet === AUTO_SET_ON_CREATE || autoSet === AUTO_SET_ON_UPDATE) {
|
|
47
96
|
insertFieldLines.push(
|
|
48
|
-
` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`,
|
|
97
|
+
code` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`,
|
|
49
98
|
);
|
|
50
99
|
} else {
|
|
51
|
-
insertFieldLines.push(` ${child.name}: ${zodFieldExpr(child)}`);
|
|
100
|
+
insertFieldLines.push(code` ${child.name}: ${zodFieldExpr(child)}`);
|
|
52
101
|
}
|
|
53
102
|
|
|
54
103
|
// Update schema: @autoSet onCreate → omit entirely; onUpdate → transform
|
|
@@ -56,13 +105,16 @@ export function renderZodValidators(obj: MetaObject): Code {
|
|
|
56
105
|
// Omit: creation timestamps cannot be changed after creation
|
|
57
106
|
} else if (autoSet === AUTO_SET_ON_UPDATE) {
|
|
58
107
|
updateFieldLines.push(
|
|
59
|
-
` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`,
|
|
108
|
+
code` ${child.name}: z.string().optional().transform(() => new Date().toISOString())`,
|
|
60
109
|
);
|
|
61
110
|
} else {
|
|
62
|
-
// All non-autoSet fields are optional in the update schema (PATCH semantics)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
111
|
+
// All non-autoSet fields are optional in the update schema (PATCH semantics).
|
|
112
|
+
// zodFieldExpr already appends .optional() when the field is non-required
|
|
113
|
+
// OR has a default; only append once more when it didn't.
|
|
114
|
+
const baseExpr = zodFieldExpr(child);
|
|
115
|
+
updateFieldLines.push(
|
|
116
|
+
fieldWillBeOptional(child) ? code` ${child.name}: ${baseExpr}` : code` ${child.name}: ${baseExpr}.optional()`,
|
|
117
|
+
);
|
|
66
118
|
}
|
|
67
119
|
}
|
|
68
120
|
|
|
@@ -74,48 +126,82 @@ export function renderZodValidators(obj: MetaObject): Code {
|
|
|
74
126
|
|
|
75
127
|
return code`
|
|
76
128
|
${docsPrefix}export const ${insertSchemaName} = ${z}.object({
|
|
77
|
-
${insertFieldLines
|
|
129
|
+
${joinCode(insertFieldLines, { on: ",\n" })}
|
|
78
130
|
});
|
|
79
131
|
|
|
80
132
|
${docsPrefix}export const ${updateSchemaName} = ${z}.object({
|
|
81
|
-
${updateFieldLines
|
|
133
|
+
${joinCode(updateFieldLines, { on: ",\n" })}
|
|
82
134
|
});
|
|
83
135
|
`;
|
|
84
136
|
}
|
|
85
137
|
|
|
86
|
-
function zodFieldExpr(field: MetaField):
|
|
87
|
-
|
|
138
|
+
function zodFieldExpr(field: MetaField): Code {
|
|
139
|
+
// FIELD_SUBTYPE_OBJECT: emit z.array(<Ref>InsertSchema) / <Ref>InsertSchema
|
|
140
|
+
// via an imp() so ts-poet hoists the cross-module import. Without this the
|
|
141
|
+
// field used to collapse to z.string() / z.array(z.string()) and downstream
|
|
142
|
+
// JSON Schema (e.g. LLM tool_use input_schema) lost the nested object shape.
|
|
143
|
+
if (field.subType === FIELD_SUBTYPE_OBJECT) {
|
|
144
|
+
const ref = field.ownAttr(FIELD_ATTR_OBJECT_REF);
|
|
145
|
+
if (typeof ref === "string" && ref.length > 0) {
|
|
146
|
+
const refImp = imp(`${ref}InsertSchema@./${ref}.js`);
|
|
147
|
+
let base: Code = code`${refImp}`;
|
|
148
|
+
if (field.isArray) base = code`z.array(${base})`;
|
|
149
|
+
return appendValidatorChain(base, field);
|
|
150
|
+
}
|
|
151
|
+
// No resolvable @objectRef — fall through to z.unknown(); downstream code
|
|
152
|
+
// can still pass a value through but loses validation.
|
|
153
|
+
let base: Code = code`z.unknown()`;
|
|
154
|
+
if (field.isArray) base = code`z.array(${base})`;
|
|
155
|
+
return appendValidatorChain(base, field);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
let baseStr: string;
|
|
88
159
|
switch (field.subType) {
|
|
89
160
|
case FIELD_SUBTYPE_INT:
|
|
90
161
|
case FIELD_SUBTYPE_CURRENCY:
|
|
91
162
|
case FIELD_SUBTYPE_LONG:
|
|
92
|
-
|
|
163
|
+
baseStr = "z.number().int()";
|
|
93
164
|
break;
|
|
94
165
|
case FIELD_SUBTYPE_DOUBLE:
|
|
95
166
|
case FIELD_SUBTYPE_FLOAT:
|
|
96
|
-
|
|
167
|
+
baseStr = "z.number()";
|
|
97
168
|
break;
|
|
98
169
|
case FIELD_SUBTYPE_BOOLEAN:
|
|
99
|
-
|
|
170
|
+
baseStr = "z.boolean()";
|
|
100
171
|
break;
|
|
101
172
|
case FIELD_SUBTYPE_DATE:
|
|
102
173
|
case FIELD_SUBTYPE_TIME:
|
|
103
174
|
case FIELD_SUBTYPE_TIMESTAMP:
|
|
104
|
-
|
|
175
|
+
baseStr = "z.string()";
|
|
105
176
|
break;
|
|
106
177
|
case FIELD_SUBTYPE_ENUM: {
|
|
107
178
|
const values = enumValues(field);
|
|
108
|
-
|
|
179
|
+
baseStr = values !== undefined ? zodEnumExpr(values) : "z.string()";
|
|
109
180
|
break;
|
|
110
181
|
}
|
|
111
182
|
case FIELD_SUBTYPE_STRING:
|
|
112
183
|
default:
|
|
113
|
-
|
|
184
|
+
baseStr = "z.string()";
|
|
114
185
|
break;
|
|
115
186
|
}
|
|
116
187
|
|
|
117
|
-
if (field.isArray)
|
|
188
|
+
if (field.isArray) baseStr = `z.array(${baseStr})`;
|
|
189
|
+
return appendValidatorChain(code`${baseStr}`, field);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Mirrors the optional-or-not decision inside appendValidatorChain so the update-schema
|
|
193
|
+
* caller can avoid stacking a second `.optional()` onto an already-optional expression. */
|
|
194
|
+
function fieldWillBeOptional(field: MetaField): boolean {
|
|
195
|
+
let isRequired = field.ownAttr(FIELD_ATTR_REQUIRED) === true;
|
|
196
|
+
for (const child of field.validators()) {
|
|
197
|
+
if (child.subType === VALIDATOR_SUBTYPE_REQUIRED) isRequired = true;
|
|
198
|
+
}
|
|
199
|
+
const hasDefault = field.ownAttr(FIELD_ATTR_DEFAULT) !== undefined;
|
|
200
|
+
return !isRequired || hasDefault;
|
|
201
|
+
}
|
|
118
202
|
|
|
203
|
+
/** Append .min/.max/.regex/.optional() based on field-level validators + required state. */
|
|
204
|
+
function appendValidatorChain(base: Code, field: MetaField): Code {
|
|
119
205
|
let isRequired = field.ownAttr(FIELD_ATTR_REQUIRED) === true;
|
|
120
206
|
let maxLen: number | undefined = field.ownAttr(FIELD_ATTR_MAX_LENGTH) as number | undefined;
|
|
121
207
|
let minLen: number | undefined;
|
|
@@ -134,18 +220,18 @@ function zodFieldExpr(field: MetaField): string {
|
|
|
134
220
|
}
|
|
135
221
|
}
|
|
136
222
|
|
|
137
|
-
let chain = base;
|
|
223
|
+
let chain: Code = base;
|
|
138
224
|
if (field.subType === FIELD_SUBTYPE_STRING && !field.isArray) {
|
|
139
|
-
if (minLen !== undefined) chain
|
|
140
|
-
else if (isRequired) chain
|
|
141
|
-
if (maxLen !== undefined) chain
|
|
142
|
-
if (pattern !== undefined) chain
|
|
225
|
+
if (minLen !== undefined) chain = code`${chain}.min(${minLen})`;
|
|
226
|
+
else if (isRequired) chain = code`${chain}.min(1)`;
|
|
227
|
+
if (maxLen !== undefined) chain = code`${chain}.max(${maxLen})`;
|
|
228
|
+
if (pattern !== undefined) chain = code`${chain}.regex(new RegExp(${JSON.stringify(pattern)}))`;
|
|
143
229
|
}
|
|
144
230
|
|
|
145
231
|
// Fields with DB-level defaults are optional in the InsertSchema: the caller
|
|
146
232
|
// can omit them and the DB will fill in. Otherwise required-with-default
|
|
147
233
|
// would force callers to repeat the default at every call site.
|
|
148
234
|
const hasDefault = field.ownAttr(FIELD_ATTR_DEFAULT) !== undefined;
|
|
149
|
-
if (!isRequired || hasDefault) chain
|
|
235
|
+
if (!isRequired || hasDefault) chain = code`${chain}.optional()`;
|
|
150
236
|
return chain;
|
|
151
237
|
}
|