@metaobjectsdev/codegen-ts 0.5.0 → 0.6.0-rc.1
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/dist/column-mapper.d.ts +3 -1
- package/dist/column-mapper.d.ts.map +1 -1
- package/dist/column-mapper.js +18 -2
- package/dist/column-mapper.js.map +1 -1
- package/dist/enum-meta.d.ts +14 -0
- package/dist/enum-meta.d.ts.map +1 -0
- package/dist/enum-meta.js +24 -0
- package/dist/enum-meta.js.map +1 -0
- package/dist/generators/index.d.ts +1 -0
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +1 -0
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/mermaid-er.d.ts +14 -0
- package/dist/generators/mermaid-er.d.ts.map +1 -0
- package/dist/generators/mermaid-er.js +21 -0
- package/dist/generators/mermaid-er.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/naming.d.ts +4 -0
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +6 -0
- package/dist/naming.js.map +1 -1
- package/dist/payload-codegen.d.ts +6 -0
- package/dist/payload-codegen.d.ts.map +1 -0
- package/dist/payload-codegen.js +95 -0
- package/dist/payload-codegen.js.map +1 -0
- package/dist/projection/extract-view-spec.d.ts.map +1 -1
- package/dist/projection/extract-view-spec.js +8 -5
- package/dist/projection/extract-view-spec.js.map +1 -1
- package/dist/projection/projection-detector.d.ts.map +1 -1
- package/dist/projection/projection-detector.js +8 -7
- package/dist/projection/projection-detector.js.map +1 -1
- package/dist/templates/drizzle-schema.d.ts.map +1 -1
- package/dist/templates/drizzle-schema.js +22 -3
- package/dist/templates/drizzle-schema.js.map +1 -1
- package/dist/templates/entity-file.d.ts.map +1 -1
- package/dist/templates/entity-file.js +5 -1
- package/dist/templates/entity-file.js.map +1 -1
- package/dist/templates/field-meta.d.ts.map +1 -1
- package/dist/templates/field-meta.js +6 -1
- package/dist/templates/field-meta.js.map +1 -1
- package/dist/templates/inferred-types.d.ts +7 -0
- package/dist/templates/inferred-types.d.ts.map +1 -1
- package/dist/templates/inferred-types.js +38 -3
- package/dist/templates/inferred-types.js.map +1 -1
- package/dist/templates/jsdoc.d.ts +26 -0
- package/dist/templates/jsdoc.d.ts.map +1 -0
- package/dist/templates/jsdoc.js +67 -0
- package/dist/templates/jsdoc.js.map +1 -0
- package/dist/templates/mermaid-er.d.ts +6 -0
- package/dist/templates/mermaid-er.d.ts.map +1 -0
- package/dist/templates/mermaid-er.js +117 -0
- package/dist/templates/mermaid-er.js.map +1 -0
- package/dist/templates/zod-validators.d.ts.map +1 -1
- package/dist/templates/zod-validators.js +12 -3
- package/dist/templates/zod-validators.js.map +1 -1
- package/package.json +4 -3
- package/src/column-mapper.ts +23 -3
- package/src/enum-meta.ts +26 -0
- package/src/generators/index.ts +1 -0
- package/src/generators/mermaid-er.ts +29 -0
- package/src/index.ts +2 -0
- package/src/naming.ts +7 -0
- package/src/payload-codegen.ts +106 -0
- package/src/projection/extract-view-spec.ts +9 -9
- package/src/projection/projection-detector.ts +11 -15
- package/src/templates/drizzle-schema.ts +24 -3
- package/src/templates/entity-file.ts +5 -1
- package/src/templates/field-meta.ts +6 -0
- package/src/templates/inferred-types.ts +42 -3
- package/src/templates/jsdoc.ts +88 -0
- package/src/templates/mermaid-er.ts +120 -0
- package/src/templates/zod-validators.ts +13 -2
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// Mermaid ER renderer — produces a docs/model.md body with:
|
|
2
|
+
// 1. A top-level ```mermaid erDiagram block of entities + identity.reference relationships.
|
|
3
|
+
// 2. A per-entity prose section consuming the 6 user-facing doc attrs (notes excluded).
|
|
4
|
+
//
|
|
5
|
+
// D5: the notes attr is NEVER emitted. Per the Documentation Provider design.
|
|
6
|
+
|
|
7
|
+
import type { MetaObject, MetaRoot } from "@metaobjectsdev/metadata";
|
|
8
|
+
import { DOC_ATTR_DESCRIPTION } from "@metaobjectsdev/metadata";
|
|
9
|
+
import { readDocAttrs } from "./jsdoc.js";
|
|
10
|
+
|
|
11
|
+
/** Render a docs/model.md body: Mermaid erDiagram + per-entity prose. Abstract
|
|
12
|
+
* entities are excluded — they have no physical table to put in a diagram
|
|
13
|
+
* (matches migrate-ts/expected-schema.ts's same filter). */
|
|
14
|
+
export function renderMermaidModel(root: MetaRoot): string {
|
|
15
|
+
const entities = root
|
|
16
|
+
.objects()
|
|
17
|
+
.filter((o) => o.isEntity() && !o.isAbstract);
|
|
18
|
+
const parts: string[] = [];
|
|
19
|
+
|
|
20
|
+
parts.push("# Data Model");
|
|
21
|
+
parts.push("");
|
|
22
|
+
parts.push("```mermaid");
|
|
23
|
+
parts.push("erDiagram");
|
|
24
|
+
for (const line of renderRelationships(entities)) parts.push(` ${line}`);
|
|
25
|
+
for (const entity of entities) {
|
|
26
|
+
parts.push("");
|
|
27
|
+
for (const line of renderEntityBlock(entity)) parts.push(` ${line}`);
|
|
28
|
+
}
|
|
29
|
+
parts.push("```");
|
|
30
|
+
parts.push("");
|
|
31
|
+
|
|
32
|
+
for (const entity of entities) {
|
|
33
|
+
for (const line of renderEntityProse(entity)) parts.push(line);
|
|
34
|
+
parts.push("");
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return parts.join("\n");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function renderRelationships(entities: MetaObject[]): string[] {
|
|
41
|
+
const lines: string[] = [];
|
|
42
|
+
for (const entity of entities) {
|
|
43
|
+
for (const ref of entity.referenceIdentities()) {
|
|
44
|
+
const refTo = ref.targetEntity;
|
|
45
|
+
if (typeof refTo !== "string" || refTo.length === 0) continue;
|
|
46
|
+
// One-to-many by default — a foreign key on `entity` references one row on `refTo`.
|
|
47
|
+
lines.push(`${refTo} ||--o{ ${entity.name} : "references"`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return lines;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function renderEntityBlock(entity: MetaObject): string[] {
|
|
54
|
+
const out: string[] = [`${entity.name} {`];
|
|
55
|
+
const pkFields = pkFieldNames(entity);
|
|
56
|
+
const fkFields = fkFieldNames(entity);
|
|
57
|
+
for (const field of entity.fields()) {
|
|
58
|
+
let marker = "";
|
|
59
|
+
if (pkFields.has(field.name)) marker = " PK";
|
|
60
|
+
else if (fkFields.has(field.name)) marker = " FK";
|
|
61
|
+
const desc = field.attr(DOC_ATTR_DESCRIPTION);
|
|
62
|
+
const comment =
|
|
63
|
+
typeof desc === "string" && desc.length > 0
|
|
64
|
+
? ` "${escapeMermaidComment(desc.split("\n")[0]!)}"`
|
|
65
|
+
: "";
|
|
66
|
+
out.push(` ${field.subType} ${field.name}${marker}${comment}`);
|
|
67
|
+
}
|
|
68
|
+
out.push("}");
|
|
69
|
+
return out;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function pkFieldNames(entity: MetaObject): Set<string> {
|
|
73
|
+
const out = new Set<string>();
|
|
74
|
+
const primary = entity.primaryIdentity();
|
|
75
|
+
if (primary) {
|
|
76
|
+
for (const f of primary.fields) out.add(f);
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function fkFieldNames(entity: MetaObject): Set<string> {
|
|
82
|
+
const out = new Set<string>();
|
|
83
|
+
for (const ref of entity.referenceIdentities()) {
|
|
84
|
+
for (const f of ref.fields) out.add(f);
|
|
85
|
+
}
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function escapeMermaidComment(s: string): string {
|
|
90
|
+
return s.replace(/"/g, '\\"');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function renderEntityProse(entity: MetaObject): string[] {
|
|
94
|
+
// readDocAttrs handles the typeof-string / Array.isArray guards and intentionally
|
|
95
|
+
// omits `notes` (D5 contract — never read, never emitted).
|
|
96
|
+
const docs = readDocAttrs(entity);
|
|
97
|
+
const out: string[] = [];
|
|
98
|
+
out.push(`## ${docs.title ?? entity.name}`);
|
|
99
|
+
if (docs.description) {
|
|
100
|
+
out.push("");
|
|
101
|
+
out.push(docs.description);
|
|
102
|
+
}
|
|
103
|
+
if (docs.aliases && docs.aliases.length > 0) {
|
|
104
|
+
out.push("");
|
|
105
|
+
out.push(`*Aliases:* ${docs.aliases.join(", ")}`);
|
|
106
|
+
}
|
|
107
|
+
// Truthy check (not !== undefined): an empty deprecated value is the same
|
|
108
|
+
// signal as none (no reason ⇒ nothing meaningful to render in the prose callout).
|
|
109
|
+
if (docs.deprecated) {
|
|
110
|
+
const replaced = docs.replacedBy ? ` Replaced by **${docs.replacedBy}**.` : "";
|
|
111
|
+
out.push("");
|
|
112
|
+
out.push(`> ⚠️ **Deprecated:** ${docs.deprecated}${replaced}`);
|
|
113
|
+
}
|
|
114
|
+
if (docs.seeAlso && docs.seeAlso.length > 0) {
|
|
115
|
+
out.push("");
|
|
116
|
+
out.push("**See also:**");
|
|
117
|
+
for (const url of docs.seeAlso) out.push(`- <${url}>`);
|
|
118
|
+
}
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
FIELD_SUBTYPE_STRING, FIELD_SUBTYPE_INT, FIELD_SUBTYPE_LONG, FIELD_SUBTYPE_CURRENCY,
|
|
10
10
|
FIELD_SUBTYPE_BOOLEAN, FIELD_SUBTYPE_DOUBLE, FIELD_SUBTYPE_FLOAT,
|
|
11
11
|
FIELD_SUBTYPE_DATE, FIELD_SUBTYPE_TIME, FIELD_SUBTYPE_TIMESTAMP,
|
|
12
|
+
FIELD_SUBTYPE_ENUM,
|
|
12
13
|
VALIDATOR_SUBTYPE_REQUIRED, VALIDATOR_SUBTYPE_LENGTH, VALIDATOR_SUBTYPE_REGEX,
|
|
13
14
|
IDENTITY_ATTR_FIELDS, IDENTITY_ATTR_GENERATION,
|
|
14
15
|
FIELD_ATTR_REQUIRED, FIELD_ATTR_MAX_LENGTH, FIELD_ATTR_DEFAULT,
|
|
@@ -16,6 +17,8 @@ import {
|
|
|
16
17
|
VALIDATOR_ATTR_MAX, VALIDATOR_ATTR_MIN, VALIDATOR_ATTR_PATTERN,
|
|
17
18
|
GENERATION_INCREMENT, GENERATION_UUID,
|
|
18
19
|
} from "@metaobjectsdev/metadata";
|
|
20
|
+
import { enumValues, zodEnumExpr } from "../enum-meta.js";
|
|
21
|
+
import { renderDocsFor } from "./jsdoc.js";
|
|
19
22
|
|
|
20
23
|
export function renderZodValidators(obj: MetaObject): Code {
|
|
21
24
|
const z = imp("z@zod");
|
|
@@ -66,12 +69,15 @@ export function renderZodValidators(obj: MetaObject): Code {
|
|
|
66
69
|
const insertSchemaName = `${obj.name}InsertSchema`;
|
|
67
70
|
const updateSchemaName = `${obj.name}UpdateSchema`;
|
|
68
71
|
|
|
72
|
+
const docs = renderDocsFor(obj);
|
|
73
|
+
const docsPrefix = docs ? `${docs}\n` : "";
|
|
74
|
+
|
|
69
75
|
return code`
|
|
70
|
-
export const ${insertSchemaName} = ${z}.object({
|
|
76
|
+
${docsPrefix}export const ${insertSchemaName} = ${z}.object({
|
|
71
77
|
${insertFieldLines.join(",\n")}
|
|
72
78
|
});
|
|
73
79
|
|
|
74
|
-
export const ${updateSchemaName} = ${z}.object({
|
|
80
|
+
${docsPrefix}export const ${updateSchemaName} = ${z}.object({
|
|
75
81
|
${updateFieldLines.join(",\n")}
|
|
76
82
|
});
|
|
77
83
|
`;
|
|
@@ -97,6 +103,11 @@ function zodFieldExpr(field: MetaField): string {
|
|
|
97
103
|
case FIELD_SUBTYPE_TIMESTAMP:
|
|
98
104
|
base = "z.string()";
|
|
99
105
|
break;
|
|
106
|
+
case FIELD_SUBTYPE_ENUM: {
|
|
107
|
+
const values = enumValues(field);
|
|
108
|
+
base = values !== undefined ? zodEnumExpr(values) : "z.string()";
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
100
111
|
case FIELD_SUBTYPE_STRING:
|
|
101
112
|
default:
|
|
102
113
|
base = "z.string()";
|