@metaobjectsdev/codegen-ts 0.9.0 → 0.10.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/README.md +1 -1
- package/dist/column-mapper.d.ts.map +1 -1
- package/dist/column-mapper.js +24 -8
- package/dist/column-mapper.js.map +1 -1
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +16 -0
- package/dist/constants.js.map +1 -1
- package/dist/docs-paths.d.ts +58 -0
- package/dist/docs-paths.d.ts.map +1 -0
- package/dist/docs-paths.js +89 -0
- package/dist/docs-paths.js.map +1 -0
- package/dist/enum-import.d.ts +14 -0
- package/dist/enum-import.d.ts.map +1 -0
- package/dist/enum-import.js +35 -0
- package/dist/enum-import.js.map +1 -0
- package/dist/enum-shared.d.ts +32 -0
- package/dist/enum-shared.d.ts.map +1 -0
- package/dist/enum-shared.js +83 -0
- package/dist/enum-shared.js.map +1 -0
- package/dist/generator-registry.d.ts +22 -0
- package/dist/generator-registry.d.ts.map +1 -0
- package/dist/generator-registry.js +161 -0
- package/dist/generator-registry.js.map +1 -0
- package/dist/generator.d.ts +6 -0
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js.map +1 -1
- package/dist/generators/api-doc-render.d.ts +17 -0
- package/dist/generators/api-doc-render.d.ts.map +1 -0
- package/dist/generators/api-doc-render.js +431 -0
- package/dist/generators/api-doc-render.js.map +1 -0
- package/dist/generators/api-docs-file.d.ts +21 -0
- package/dist/generators/api-docs-file.d.ts.map +1 -0
- package/dist/generators/api-docs-file.js +112 -0
- package/dist/generators/api-docs-file.js.map +1 -0
- package/dist/generators/api-field-shape.d.ts +39 -0
- package/dist/generators/api-field-shape.d.ts.map +1 -0
- package/dist/generators/api-field-shape.js +92 -0
- package/dist/generators/api-field-shape.js.map +1 -0
- package/dist/generators/api-label.d.ts +3 -0
- package/dist/generators/api-label.d.ts.map +1 -0
- package/dist/generators/api-label.js +8 -0
- package/dist/generators/api-label.js.map +1 -0
- package/dist/generators/api-model.d.ts +122 -0
- package/dist/generators/api-model.d.ts.map +1 -0
- package/dist/generators/api-model.js +809 -0
- package/dist/generators/api-model.js.map +1 -0
- package/dist/generators/docs-data-builder.d.ts +26 -4
- package/dist/generators/docs-data-builder.d.ts.map +1 -1
- package/dist/generators/docs-data-builder.js +436 -164
- package/dist/generators/docs-data-builder.js.map +1 -1
- package/dist/generators/docs-data.d.ts +136 -27
- package/dist/generators/docs-data.d.ts.map +1 -1
- package/dist/generators/docs-data.js +1 -1
- package/dist/generators/docs-data.js.map +1 -1
- package/dist/generators/docs-file.d.ts +19 -0
- package/dist/generators/docs-file.d.ts.map +1 -1
- package/dist/generators/docs-file.js +154 -27
- package/dist/generators/docs-file.js.map +1 -1
- package/dist/generators/entity-file.d.ts.map +1 -1
- package/dist/generators/entity-file.js +29 -14
- package/dist/generators/entity-file.js.map +1 -1
- package/dist/generators/extractor-file.d.ts.map +1 -1
- package/dist/generators/extractor-file.js +2 -1
- package/dist/generators/extractor-file.js.map +1 -1
- package/dist/generators/field-anchor.d.ts +7 -0
- package/dist/generators/field-anchor.d.ts.map +1 -0
- package/dist/generators/field-anchor.js +23 -0
- package/dist/generators/field-anchor.js.map +1 -0
- package/dist/generators/index.d.ts +8 -1
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +6 -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 -1
- package/dist/generators/mermaid-er.js +14 -0
- package/dist/generators/mermaid-er.js.map +1 -1
- package/dist/generators/output-parser-file.d.ts.map +1 -1
- package/dist/generators/output-parser-file.js +3 -4
- package/dist/generators/output-parser-file.js.map +1 -1
- package/dist/generators/output-prompt-file.d.ts.map +1 -1
- package/dist/generators/output-prompt-file.js +2 -2
- package/dist/generators/output-prompt-file.js.map +1 -1
- package/dist/generators/prompt-render-file.d.ts.map +1 -1
- package/dist/generators/prompt-render-file.js +3 -4
- package/dist/generators/prompt-render-file.js.map +1 -1
- package/dist/generators/queries-file.d.ts.map +1 -1
- package/dist/generators/queries-file.js +8 -3
- package/dist/generators/queries-file.js.map +1 -1
- package/dist/generators/render-helper-file.d.ts.map +1 -1
- package/dist/generators/render-helper-file.js +2 -2
- package/dist/generators/render-helper-file.js.map +1 -1
- package/dist/generators/routes-file-hono.d.ts.map +1 -1
- package/dist/generators/routes-file-hono.js +5 -1
- package/dist/generators/routes-file-hono.js.map +1 -1
- package/dist/generators/routes-file.d.ts +3 -0
- package/dist/generators/routes-file.d.ts.map +1 -1
- package/dist/generators/routes-file.js +6 -1
- package/dist/generators/routes-file.js.map +1 -1
- package/dist/generators/template-doc-builder.d.ts +19 -0
- package/dist/generators/template-doc-builder.d.ts.map +1 -0
- package/dist/generators/template-doc-builder.js +220 -0
- package/dist/generators/template-doc-builder.js.map +1 -0
- package/dist/generators/template-doc-data.d.ts +62 -0
- package/dist/generators/template-doc-data.d.ts.map +1 -0
- package/dist/generators/template-doc-data.js +16 -0
- package/dist/generators/template-doc-data.js.map +1 -0
- package/dist/generators/template-payload-tree.d.ts +15 -0
- package/dist/generators/template-payload-tree.d.ts.map +1 -0
- package/dist/generators/template-payload-tree.js +61 -0
- package/dist/generators/template-payload-tree.js.map +1 -0
- package/dist/generators/template-source-annotate.d.ts +74 -0
- package/dist/generators/template-source-annotate.d.ts.map +1 -0
- package/dist/generators/template-source-annotate.js +184 -0
- package/dist/generators/template-source-annotate.js.map +1 -0
- package/dist/generators/template-source-render.d.ts +24 -0
- package/dist/generators/template-source-render.d.ts.map +1 -0
- package/dist/generators/template-source-render.js +175 -0
- package/dist/generators/template-source-render.js.map +1 -0
- package/dist/generators/trace-helper-file.d.ts +9 -0
- package/dist/generators/trace-helper-file.d.ts.map +1 -0
- package/dist/generators/trace-helper-file.js +196 -0
- package/dist/generators/trace-helper-file.js.map +1 -0
- package/dist/index.d.ts +29 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -2
- package/dist/index.js.map +1 -1
- package/dist/metaobjects-config.d.ts +75 -2
- package/dist/metaobjects-config.d.ts.map +1 -1
- package/dist/metaobjects-config.js +43 -0
- package/dist/metaobjects-config.js.map +1 -1
- package/dist/naming.d.ts +19 -0
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +41 -0
- package/dist/naming.js.map +1 -1
- package/dist/payload-codegen.d.ts.map +1 -1
- package/dist/payload-codegen.js +12 -4
- package/dist/payload-codegen.js.map +1 -1
- package/dist/projection/extract-view-spec.d.ts.map +1 -1
- package/dist/projection/extract-view-spec.js +51 -25
- package/dist/projection/extract-view-spec.js.map +1 -1
- package/dist/relation-resolver.d.ts +16 -0
- package/dist/relation-resolver.d.ts.map +1 -1
- package/dist/relation-resolver.js +82 -1
- package/dist/relation-resolver.js.map +1 -1
- package/dist/render-context.d.ts +4 -0
- package/dist/render-context.d.ts.map +1 -1
- package/dist/render-context.js.map +1 -1
- package/dist/render-engine/embedded-templates.generated.d.ts +2 -0
- package/dist/render-engine/embedded-templates.generated.d.ts.map +1 -0
- package/dist/render-engine/embedded-templates.generated.js +15 -0
- package/dist/render-engine/embedded-templates.generated.js.map +1 -0
- package/dist/render-engine/framework-provider.d.ts.map +1 -1
- package/dist/render-engine/framework-provider.js +26 -13
- package/dist/render-engine/framework-provider.js.map +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +17 -0
- package/dist/runner.js.map +1 -1
- package/dist/templates/docs-file.d.ts +2 -6
- package/dist/templates/docs-file.d.ts.map +1 -1
- package/dist/templates/docs-file.js +2 -5
- package/dist/templates/docs-file.js.map +1 -1
- package/dist/templates/drizzle-schema.d.ts.map +1 -1
- package/dist/templates/drizzle-schema.js +30 -2
- package/dist/templates/drizzle-schema.js.map +1 -1
- package/dist/templates/entity-constants.d.ts +7 -0
- package/dist/templates/entity-constants.d.ts.map +1 -1
- package/dist/templates/entity-constants.js +1 -1
- package/dist/templates/entity-constants.js.map +1 -1
- package/dist/templates/entity-file.d.ts.map +1 -1
- package/dist/templates/entity-file.js +16 -5
- package/dist/templates/entity-file.js.map +1 -1
- package/dist/templates/enums-file.d.ts +11 -0
- package/dist/templates/enums-file.d.ts.map +1 -0
- package/dist/templates/enums-file.js +44 -0
- package/dist/templates/enums-file.js.map +1 -0
- package/dist/templates/extract-delegate-emitter.d.ts.map +1 -1
- package/dist/templates/extract-delegate-emitter.js +5 -7
- package/dist/templates/extract-delegate-emitter.js.map +1 -1
- package/dist/templates/extract-schema-emitter.d.ts.map +1 -1
- package/dist/templates/extract-schema-emitter.js +5 -1
- package/dist/templates/extract-schema-emitter.js.map +1 -1
- package/dist/templates/extractor.d.ts.map +1 -1
- package/dist/templates/extractor.js +56 -39
- package/dist/templates/extractor.js.map +1 -1
- package/dist/templates/field-meta.d.ts.map +1 -1
- package/dist/templates/field-meta.js +1 -5
- package/dist/templates/field-meta.js.map +1 -1
- package/dist/templates/filter-allowlist.d.ts +7 -2
- package/dist/templates/filter-allowlist.d.ts.map +1 -1
- package/dist/templates/filter-allowlist.js +17 -9
- package/dist/templates/filter-allowlist.js.map +1 -1
- package/dist/templates/filter-type.d.ts +7 -1
- package/dist/templates/filter-type.d.ts.map +1 -1
- package/dist/templates/filter-type.js +9 -5
- package/dist/templates/filter-type.js.map +1 -1
- package/dist/templates/find-templates.d.ts +4 -0
- package/dist/templates/find-templates.d.ts.map +1 -0
- package/dist/templates/find-templates.js +15 -0
- package/dist/templates/find-templates.js.map +1 -0
- package/dist/templates/fr010-field-mapping.d.ts +2 -0
- package/dist/templates/fr010-field-mapping.d.ts.map +1 -1
- package/dist/templates/fr010-field-mapping.js +10 -6
- package/dist/templates/fr010-field-mapping.js.map +1 -1
- package/dist/templates/inferred-types.d.ts +44 -7
- package/dist/templates/inferred-types.d.ts.map +1 -1
- package/dist/templates/inferred-types.js +107 -16
- package/dist/templates/inferred-types.js.map +1 -1
- package/dist/templates/mermaid-er.d.ts +35 -2
- package/dist/templates/mermaid-er.d.ts.map +1 -1
- package/dist/templates/mermaid-er.js +174 -7
- package/dist/templates/mermaid-er.js.map +1 -1
- package/dist/templates/output-parser.d.ts.map +1 -1
- package/dist/templates/output-parser.js +30 -79
- package/dist/templates/output-parser.js.map +1 -1
- package/dist/templates/output-prompt.d.ts.map +1 -1
- package/dist/templates/output-prompt.js +2 -2
- package/dist/templates/output-prompt.js.map +1 -1
- package/dist/templates/queries-file.d.ts.map +1 -1
- package/dist/templates/queries-file.js +112 -4
- package/dist/templates/queries-file.js.map +1 -1
- package/dist/templates/queries.d.ts +5 -0
- package/dist/templates/queries.d.ts.map +1 -1
- package/dist/templates/queries.js +7 -7
- package/dist/templates/queries.js.map +1 -1
- package/dist/templates/recover-schema-emitter.d.ts +8 -0
- package/dist/templates/recover-schema-emitter.d.ts.map +1 -0
- package/dist/templates/recover-schema-emitter.js +64 -0
- package/dist/templates/recover-schema-emitter.js.map +1 -0
- package/dist/templates/relations-block.js +10 -0
- package/dist/templates/relations-block.js.map +1 -1
- package/dist/templates/render-helper.d.ts.map +1 -1
- package/dist/templates/render-helper.js +4 -4
- package/dist/templates/render-helper.js.map +1 -1
- package/dist/templates/routes-file.d.ts.map +1 -1
- package/dist/templates/routes-file.js +183 -6
- package/dist/templates/routes-file.js.map +1 -1
- package/dist/templates/tph-discriminator.d.ts +56 -0
- package/dist/templates/tph-discriminator.d.ts.map +1 -0
- package/dist/templates/tph-discriminator.js +180 -0
- package/dist/templates/tph-discriminator.js.map +1 -0
- package/dist/templates/value-object-file.d.ts +2 -1
- package/dist/templates/value-object-file.d.ts.map +1 -1
- package/dist/templates/value-object-file.js +32 -4
- package/dist/templates/value-object-file.js.map +1 -1
- package/dist/templates/zod-validators.d.ts +64 -1
- package/dist/templates/zod-validators.d.ts.map +1 -1
- package/dist/templates/zod-validators.js +181 -8
- package/dist/templates/zod-validators.js.map +1 -1
- package/package.json +103 -34
- package/src/column-mapper.ts +25 -8
- package/src/constants.ts +18 -0
- package/src/docs-paths.ts +128 -0
- package/src/enum-import.ts +43 -0
- package/src/enum-shared.ts +95 -0
- package/src/generator-registry.ts +204 -0
- package/src/generator.ts +6 -0
- package/src/generators/api-doc-render.ts +572 -0
- package/src/generators/api-docs-file.ts +146 -0
- package/src/generators/api-field-shape.ts +114 -0
- package/src/generators/api-label.ts +7 -0
- package/src/generators/api-model.ts +1067 -0
- package/src/generators/docs-data-builder.ts +479 -185
- package/src/generators/docs-data.ts +139 -28
- package/src/generators/docs-file.ts +205 -39
- package/src/generators/entity-file.ts +31 -15
- package/src/generators/extractor-file.ts +2 -1
- package/src/generators/field-anchor.ts +24 -0
- package/src/generators/index.ts +8 -1
- package/src/generators/mermaid-er.ts +14 -0
- package/src/generators/output-parser-file.ts +3 -4
- package/src/generators/output-prompt-file.ts +2 -1
- package/src/generators/prompt-render-file.ts +3 -4
- package/src/generators/queries-file.ts +9 -3
- package/src/generators/render-helper-file.ts +2 -1
- package/src/generators/routes-file-hono.ts +5 -1
- package/src/generators/routes-file.ts +7 -1
- package/src/generators/template-doc-builder.ts +306 -0
- package/src/generators/template-doc-data.ts +85 -0
- package/src/generators/template-payload-tree.ts +71 -0
- package/src/generators/template-source-annotate.ts +290 -0
- package/src/generators/template-source-render.ts +203 -0
- package/src/generators/trace-helper-file.ts +301 -0
- package/src/index.ts +55 -4
- package/src/metaobjects-config.ts +117 -2
- package/src/naming.ts +48 -0
- package/src/payload-codegen.ts +14 -3
- package/src/projection/extract-view-spec.ts +49 -30
- package/src/relation-resolver.ts +103 -1
- package/src/render-context.ts +4 -0
- package/src/render-engine/embedded-templates.generated.ts +14 -0
- package/src/render-engine/framework-provider.ts +25 -11
- package/src/runner.ts +21 -0
- package/src/templates/docs-file.ts +2 -9
- package/src/templates/drizzle-schema.ts +31 -1
- package/src/templates/entity-constants.ts +1 -1
- package/src/templates/entity-file.ts +16 -5
- package/src/templates/enums-file.ts +50 -0
- package/src/templates/extract-delegate-emitter.ts +5 -6
- package/src/templates/extractor.ts +68 -38
- package/src/templates/field-meta.ts +0 -6
- package/src/templates/filter-allowlist.ts +17 -10
- package/src/templates/filter-type.ts +8 -6
- package/src/templates/find-templates.ts +15 -0
- package/src/templates/fr010-field-mapping.ts +10 -8
- package/src/templates/inferred-types.ts +108 -18
- package/src/templates/mermaid-er.ts +176 -8
- package/src/templates/output-parser.ts +30 -79
- package/src/templates/output-prompt.ts +2 -1
- package/src/templates/queries-file.ts +132 -3
- package/src/templates/queries.ts +15 -7
- package/src/templates/relations-block.ts +17 -0
- package/src/templates/render-helper.ts +4 -3
- package/src/templates/routes-file.ts +233 -6
- package/src/templates/tph-discriminator.ts +232 -0
- package/src/templates/value-object-file.ts +38 -4
- package/src/templates/zod-validators.ts +204 -7
- package/templates/api/agent-api.md.mustache +30 -0
- package/templates/api/entity-api.md.mustache +69 -0
- package/templates/api/index.md.mustache +21 -0
- package/templates/docs/entity-page.md.mustache +33 -21
- package/templates/docs/template-page.md.mustache +56 -0
- package/src/templates/extract-schema-emitter.ts +0 -111
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// for `docs/entity-page.md` (or any of the partials) reference these keys.
|
|
9
9
|
//
|
|
10
10
|
// `EntityDocData` is the **Markdown-flavored** data shape — it intentionally
|
|
11
|
-
// mixes raw structural fields (entity,
|
|
11
|
+
// mixes raw structural fields (entity, constraints) with
|
|
12
12
|
// **pre-rendered Markdown fragments** so cross-port walk functions (TS,
|
|
13
13
|
// Python, C#, Java, Kotlin) don't have to re-derive the same escaping rules
|
|
14
14
|
// (pipe-inside-cell escapes, backtick wrapping, identity bullets,
|
|
@@ -40,20 +40,30 @@
|
|
|
40
40
|
// `{{#identities.0}}` for the same effect, at which point the flag fields
|
|
41
41
|
// can be deprecated.
|
|
42
42
|
|
|
43
|
-
/** One row in the Storage table —
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
43
|
+
/** One row in the NEUTRAL Storage table — the physical persistence MAPPING,
|
|
44
|
+
* fully-rendered as a single Markdown table row. ADR-0020: the Storage
|
|
45
|
+
* section documents declared physical facts only (column name → neutral
|
|
46
|
+
* physical type → nullable → key) and makes NO language assumption — it does
|
|
47
|
+
* NOT carry a TypeScript type or any ORM DDL. Its value-add over the
|
|
48
|
+
* Constraints table is the field→column name mapping + any physical
|
|
49
|
+
* `@dbColumnType` override + the key role. The pre-rendered `rowLine` keeps
|
|
50
|
+
* templates trivial and means cross-port walk functions don't re-derive the
|
|
51
|
+
* Markdown escaping. */
|
|
47
52
|
export interface StorageFieldDoc {
|
|
48
53
|
name: string; // raw field name (without backticks)
|
|
49
|
-
/** @markdown —
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
/** @markdown — physical column name (field's `@column` if set, else the
|
|
55
|
+
* field name), wrapped in backticks. */
|
|
56
|
+
columnCell: string;
|
|
57
|
+
/** @markdown — neutral physical type (declared `@dbColumnType` override
|
|
58
|
+
* uppercased, else the field's logical type), wrapped in backticks. */
|
|
59
|
+
typeCell: string;
|
|
60
|
+
/** @markdown — "yes" if the field is nullable (not required, not a PK),
|
|
61
|
+
* else "no". */
|
|
62
|
+
nullableCell: string;
|
|
63
|
+
/** @markdown — key role: "primary key", "foreign key → `Target`", or "". */
|
|
64
|
+
keyCell: string;
|
|
55
65
|
/** @markdown — pre-rendered full Markdown table row, e.g.
|
|
56
|
-
* "| `id` | `
|
|
66
|
+
* "| `id` | `long` | no | primary key |"
|
|
57
67
|
* Templates emit this verbatim via `{{{rowLine}}}`. */
|
|
58
68
|
rowLine: string;
|
|
59
69
|
}
|
|
@@ -77,9 +87,74 @@ export interface UsedByDoc {
|
|
|
77
87
|
bullet: string;
|
|
78
88
|
}
|
|
79
89
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
90
|
+
/** One row in the unified Fields table — merges the old Storage + Constraints
|
|
91
|
+
* cells into a single per-field row. Cells are pre-rendered Markdown so
|
|
92
|
+
* templates stay trivial. An empty cell is "".
|
|
93
|
+
*
|
|
94
|
+
* Replaces the previous Storage + Constraints split which duplicated facts
|
|
95
|
+
* (field name, logical type, key role, required-vs-nullable). Following the
|
|
96
|
+
* research synthesis: domain-model docs (FHIR, GitHub GraphQL Objects,
|
|
97
|
+
* Schema.org) all surface one Fields/Properties table per resource. */
|
|
98
|
+
export interface FieldDoc {
|
|
99
|
+
field: string; // raw field name (without backticks/anchor)
|
|
100
|
+
/** @markdown — anchored, badge-prefixed field cell:
|
|
101
|
+
* `<a id="field-id"></a>🔑 \`id\`` (PK)
|
|
102
|
+
* `<a id="field-userId"></a>🔗 \`userId\`` (FK)
|
|
103
|
+
* `<a id="field-name"></a>\`name\`` (plain) */
|
|
104
|
+
fieldCell: string;
|
|
105
|
+
/** @markdown — neutral logical type; for FK fields, suffixed with the
|
|
106
|
+
* cross-linked target — e.g. "`int` → [`User`](User.md)". */
|
|
107
|
+
typeCell: string;
|
|
108
|
+
/** @markdown — "yes" / "" — whether the field is required (or a PK). */
|
|
109
|
+
requiredCell: string;
|
|
110
|
+
/** @markdown — physical persistence info, ONLY when interesting:
|
|
111
|
+
* `@column` override that differs from the field name → "`UserId`"
|
|
112
|
+
* `@dbColumnType` set → "`UserId` `UUID`" (or "`Data` `JSONB`" when
|
|
113
|
+
* the field name happens to match the column)
|
|
114
|
+
* Empty when field name == column AND no @dbColumnType override. */
|
|
115
|
+
storageCell: string;
|
|
116
|
+
/** @markdown — all the rules: validators (regex/length/numeric), default,
|
|
117
|
+
* enum value set, extends EnumName, references, unique. Joined by " · ". */
|
|
118
|
+
rulesCell: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** One expanded per-field detail entry — rendered as a sub-section below
|
|
122
|
+
* the at-a-glance Fields table. ONLY emitted for fields with non-trivial
|
|
123
|
+
* content (@description / @summary / validators / extends-enum / FK ref /
|
|
124
|
+
* default / column-override). Skipped for plain typed fields with nothing
|
|
125
|
+
* extra to surface — keeps the entity page from ballooning with empty
|
|
126
|
+
* stubs.
|
|
127
|
+
*
|
|
128
|
+
* The `block` is fully pre-rendered Markdown so the template is trivial
|
|
129
|
+
* (`{{{block}}}` per row) and cross-port walks emit consistent output
|
|
130
|
+
* without re-implementing the layout.
|
|
131
|
+
*
|
|
132
|
+
* Authoring path: any field that wants surface in this section just sets
|
|
133
|
+
* `@description` and/or `@summary` in the metadata YAML. Mirrors the
|
|
134
|
+
* per-entity pattern. */
|
|
135
|
+
export interface FieldDetailDoc {
|
|
136
|
+
field: string; // raw field name (without backticks)
|
|
137
|
+
/** @markdown — the full per-field block, headed by `### \`fieldName\``
|
|
138
|
+
* and followed by italic summary, description paragraph, validator
|
|
139
|
+
* bullets, type/FK/extends/default lines. */
|
|
140
|
+
block: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Deprecated alias for {@link FieldDoc} — kept for back-compat in case any
|
|
144
|
+
* external template author destructured the old ConstraintRow shape.
|
|
145
|
+
* @deprecated use FieldDoc */
|
|
146
|
+
export interface ConstraintRow {
|
|
147
|
+
field: string; // raw field name (without backticks)
|
|
148
|
+
/** @markdown — "yes" / "" — whether the field is required (or a PK). */
|
|
149
|
+
required: string;
|
|
150
|
+
/** @markdown — neutral logical type cell, e.g. "`string`", "`enum`",
|
|
151
|
+
* "`Address[]`". */
|
|
152
|
+
type: string;
|
|
153
|
+
/** @markdown — size/range limits, e.g. "maxLength: 200" — "" if none. */
|
|
154
|
+
limits: string;
|
|
155
|
+
/** @markdown — declared rules: enum value sets, patterns, validators,
|
|
156
|
+
* uniqueness, default — "" if none. */
|
|
157
|
+
rules: string;
|
|
83
158
|
}
|
|
84
159
|
|
|
85
160
|
export interface EntityDocData {
|
|
@@ -96,6 +171,7 @@ export interface EntityDocData {
|
|
|
96
171
|
source?: string; // "meta.blog.json"
|
|
97
172
|
package?: string; // "acme::blog"
|
|
98
173
|
description?: string; // raw description text (may be multi-line)
|
|
174
|
+
summary?: string; // raw summary text (single line)
|
|
99
175
|
};
|
|
100
176
|
|
|
101
177
|
/** @markdown — description as a blockquote (one `> ` per line). Present
|
|
@@ -104,16 +180,49 @@ export interface EntityDocData {
|
|
|
104
180
|
* constructs. */
|
|
105
181
|
descriptionQuote?: string;
|
|
106
182
|
|
|
183
|
+
/** @markdown — `@summary` rendered as a one-line italic lead-in (e.g.
|
|
184
|
+
* `*Tracks ...*`). Present iff `entity.summary` is set. Distinct from
|
|
185
|
+
* `descriptionQuote` (a blockquote) so an entity that carries BOTH
|
|
186
|
+
* surfaces both — short headline above, expanded paragraph below. */
|
|
187
|
+
summaryLead?: string;
|
|
188
|
+
|
|
189
|
+
/** @markdown — fenced ```mermaid erDiagram block``` showing the focal
|
|
190
|
+
* entity plus its direct in/out FK neighbors (1-hop). Replaces the
|
|
191
|
+
* cognitive load of the whole-model graph with an in-context view.
|
|
192
|
+
* Mirrors the dbdocs pattern. Skipped when the entity has no neighbors. */
|
|
193
|
+
neighborhoodErBlock?: string;
|
|
194
|
+
/** Gate flag for Mustache — true iff `neighborhoodErBlock` is present.
|
|
195
|
+
* See the "Mustache idiom note" at the top of this file. */
|
|
196
|
+
hasNeighborhoodEr?: boolean;
|
|
197
|
+
|
|
107
198
|
/** @markdown — multi-line preamble block: Type / Source? / Package?, one
|
|
108
199
|
* per line, in the exact order matching the legacy emitter. Always
|
|
109
200
|
* present. */
|
|
110
201
|
preambleHeader: string;
|
|
111
202
|
|
|
112
|
-
/**
|
|
113
|
-
*
|
|
203
|
+
/** Unified Fields section — one row per field, merging the per-field facts
|
|
204
|
+
* the old Storage + Constraints tables split between. Always emitted when
|
|
205
|
+
* the entity has any fields. */
|
|
206
|
+
fields: {
|
|
207
|
+
hasFields: boolean;
|
|
208
|
+
rows: FieldDoc[];
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
/** Expanded per-field details — emitted as a "## Field details" section
|
|
212
|
+
* AFTER the at-a-glance Fields table. Skips fields with nothing extra to
|
|
213
|
+
* say (no description, no summary, no validators, no extends, no default,
|
|
214
|
+
* no FK, no column override) so the section doesn't balloon the page. */
|
|
215
|
+
fieldDetails: {
|
|
216
|
+
hasDetails: boolean;
|
|
217
|
+
rows: FieldDetailDoc[];
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
/** @deprecated Storage section. The merged Fields table covers this now;
|
|
221
|
+
* the old shape is still populated for adopters with custom templates that
|
|
222
|
+
* reference it, but new templates should use `fields` instead. */
|
|
114
223
|
storage?: {
|
|
115
|
-
/** @markdown — pre-rendered "|
|
|
116
|
-
* pair. */
|
|
224
|
+
/** @markdown — pre-rendered "| Column | Type | Nullable | Key |\n|---|...|"
|
|
225
|
+
* header pair. */
|
|
117
226
|
tableHeader: string;
|
|
118
227
|
rows: StorageFieldDoc[];
|
|
119
228
|
};
|
|
@@ -131,13 +240,14 @@ export interface EntityDocData {
|
|
|
131
240
|
/** Present-and-non-empty flag for the relationships section. */
|
|
132
241
|
hasRelationships?: boolean;
|
|
133
242
|
|
|
134
|
-
/**
|
|
135
|
-
*
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
243
|
+
/** @deprecated Constraints section. The merged Fields table covers this
|
|
244
|
+
* now; the old shape is still populated for adopters with custom templates
|
|
245
|
+
* that reference it, but new templates should use `fields` instead. */
|
|
246
|
+
constraints: {
|
|
247
|
+
/** True iff there is at least one row to render (objects always have
|
|
248
|
+
* fields, so this is generally true; gates the section header). */
|
|
249
|
+
hasConstraints: boolean;
|
|
250
|
+
rows: ConstraintRow[];
|
|
141
251
|
};
|
|
142
252
|
|
|
143
253
|
/** "Used by" — present iff any templates declare `@payloadRef` → this
|
|
@@ -149,6 +259,7 @@ export interface EntityDocData {
|
|
|
149
259
|
/** Present flag for the storage section. */
|
|
150
260
|
hasStorage?: boolean;
|
|
151
261
|
|
|
152
|
-
/**
|
|
153
|
-
|
|
262
|
+
/** Cross-links to this entity's generated-SDK api page, one per api surface
|
|
263
|
+
* (per language). Present only when api surfaces are emitted with the model. */
|
|
264
|
+
apiRefs?: Array<{ label: string; href: string; last?: boolean }>;
|
|
154
265
|
}
|
|
@@ -18,30 +18,72 @@
|
|
|
18
18
|
// byte-for-byte. If you're hacking on this and the conformance test
|
|
19
19
|
// breaks, the refactor is the bug, not the fixture.
|
|
20
20
|
|
|
21
|
-
import type { MetaObject } from "@metaobjectsdev/metadata";
|
|
21
|
+
import type { MetaObject, MetaRoot } from "@metaobjectsdev/metadata";
|
|
22
|
+
import { TYPE_TEMPLATE, TEMPLATE_SUBTYPE_OUTPUT } from "@metaobjectsdev/metadata";
|
|
22
23
|
import { render } from "@metaobjectsdev/render";
|
|
23
|
-
import type {
|
|
24
|
-
import {
|
|
24
|
+
import type { Provider } from "@metaobjectsdev/render";
|
|
25
|
+
import type { Generator, GeneratorFactory, EmittedFile } from "../generator.js";
|
|
26
|
+
import {
|
|
27
|
+
docPageOutputPath,
|
|
28
|
+
docPageHref,
|
|
29
|
+
docPageNode,
|
|
30
|
+
apiSurfaceHref,
|
|
31
|
+
assertNoDuplicateDocPaths,
|
|
32
|
+
type DocPageNode,
|
|
33
|
+
type DocPagePlacement,
|
|
34
|
+
} from "../docs-paths.js";
|
|
25
35
|
import { projectProvider } from "../render-engine/framework-provider.js";
|
|
36
|
+
import { renderMermaidErBlock } from "../templates/mermaid-er.js";
|
|
26
37
|
import { buildEntityDocData } from "./docs-data-builder.js";
|
|
38
|
+
import { buildTemplateDocData } from "./template-doc-builder.js";
|
|
39
|
+
import type { OutputLayout } from "../import-path.js";
|
|
40
|
+
|
|
41
|
+
// The neutral OVERVIEW/index page. GitHub (and most doc-site renderers) treat a
|
|
42
|
+
// folder's README.md as its landing page, so the model overview lands here.
|
|
43
|
+
const INDEX_FILENAME = "README.md";
|
|
44
|
+
// The index lives at the docs ROOT (package-less) in BOTH layouts — links are
|
|
45
|
+
// computed relative to root via docPageHref.
|
|
46
|
+
const INDEX_NODE: DocPageNode = { name: "README" };
|
|
27
47
|
|
|
28
48
|
export interface DocsFileOpts {
|
|
29
49
|
filter?: (entity: MetaObject) => boolean;
|
|
30
50
|
target?: string;
|
|
51
|
+
/** When set, one or more api surfaces are emitted alongside the model surface,
|
|
52
|
+
* each under its own sub-directory (e.g. `"api/ts"`) with a per-language label.
|
|
53
|
+
* docsFile then cross-links each model entity page to ALL its api pages and
|
|
54
|
+
* adds an "API reference" section to the index, every href computed via the
|
|
55
|
+
* shared `apiSurfaceHref` so it resolves relative in BOTH layouts (or absolute
|
|
56
|
+
* when a `baseUrl` is given). ABSENT/empty ⇒ model-only output (byte-identical
|
|
57
|
+
* to historical behaviour). */
|
|
58
|
+
apiSurfaces?: Array<{ label: string; subDir: string; baseUrl?: string }>;
|
|
31
59
|
}
|
|
32
60
|
|
|
33
|
-
/** The names of the generators that may emit sibling files for an entity.
|
|
34
|
-
* We always list them in the "Generated code" section — adopters cross-
|
|
35
|
-
* reference their own metaobjects.config.ts to confirm which are wired in.
|
|
36
|
-
* Matches the rc.11 behavior. */
|
|
37
|
-
const KNOWN_SIBLING_GENERATORS = new Set([
|
|
38
|
-
"queries-file",
|
|
39
|
-
"routes-file",
|
|
40
|
-
"routes-file-hono",
|
|
41
|
-
]);
|
|
42
|
-
|
|
43
61
|
const TEMPLATE_REF = "docs/entity-page.md";
|
|
62
|
+
// The NEUTRAL render-contract page emitted per `template.output` node — a
|
|
63
|
+
// sibling artifact, distinct from the entity page (Task 3).
|
|
64
|
+
const TEMPLATE_PAGE_REF = "docs/template-page.md";
|
|
44
65
|
|
|
66
|
+
/** Render one docs page, wrapping any engine error with the page ref + output
|
|
67
|
+
* path so a template failure points at the exact page (shared by the entity
|
|
68
|
+
* and template.output emission paths — identical error contract). */
|
|
69
|
+
function renderDocPage(ref: string, payload: unknown, provider: Provider, path: string): string {
|
|
70
|
+
try {
|
|
71
|
+
return render({ ref, payload, provider, format: "markdown" });
|
|
72
|
+
} catch (err) {
|
|
73
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
74
|
+
throw new Error(`docs-file: failed rendering '${ref}' for '${path}': ${msg}`, {
|
|
75
|
+
cause: err instanceof Error ? err : undefined,
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @deprecated ADR-0021 D1: `meta docs` is the single door for documentation.
|
|
82
|
+
* `docsFile()` stays as the INTERNAL engine that `meta docs` calls — do NOT add
|
|
83
|
+
* it to a `meta gen` config / the public generator surface. It is flagged
|
|
84
|
+
* neutral in the generator registry (`--list`) and is not part of the
|
|
85
|
+
* recommended native `meta gen` suite. Use `meta docs` instead.
|
|
86
|
+
*/
|
|
45
87
|
export const docsFile = function docsFile(opts?: DocsFileOpts): Generator {
|
|
46
88
|
const generator: Generator = {
|
|
47
89
|
name: "docs-file",
|
|
@@ -52,36 +94,160 @@ export const docsFile = function docsFile(opts?: DocsFileOpts): Generator {
|
|
|
52
94
|
const rc = ctx.renderContext;
|
|
53
95
|
const provider = projectProvider(ctx.projectRoot ?? process.cwd());
|
|
54
96
|
const layout = ctx.config.outputLayout ?? "flat";
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
97
|
+
// One {label, href} per api surface, every href computed via the shared
|
|
98
|
+
// `apiSurfaceHref` from the FROM page's own output path (so it resolves
|
|
99
|
+
// relative in BOTH layouts, or absolute when the surface declares a
|
|
100
|
+
// baseUrl). The api page for a node lives at `<subDir>/<same placement>`,
|
|
101
|
+
// so the from-path doubles as the page placement. ABSENT/empty surfaces ⇒
|
|
102
|
+
// undefined → output byte-identical to historical model-only runs.
|
|
103
|
+
const apiRefsFor = (fromPath: string): Array<{ label: string; href: string }> | undefined =>
|
|
104
|
+
opts?.apiSurfaces?.map((s) => ({ label: s.label, href: apiSurfaceHref(fromPath, s, fromPath) }));
|
|
105
|
+
// Track every (path, fqn) so we can hard-error on a collision (defense
|
|
106
|
+
// against silent doc-page overwrite) AFTER all pages are placed.
|
|
107
|
+
const placements: DocPagePlacement[] = [];
|
|
108
|
+
// Collect the placement nodes of each linkable page so the OVERVIEW/index
|
|
109
|
+
// (README.md) can link them via the SAME docPageHref used everywhere else
|
|
110
|
+
// (links resolve in flat AND package layout). Grouped entity vs template.
|
|
111
|
+
const entityNodes: DocPageNode[] = [];
|
|
112
|
+
const templateNodes: DocPageNode[] = [];
|
|
113
|
+
const files: EmittedFile[] = ctx.loadedRoot
|
|
114
|
+
.objects()
|
|
115
|
+
.filter(ctx.matches)
|
|
116
|
+
.map((entity: MetaObject) => {
|
|
117
|
+
const node = docPageNode(entity);
|
|
118
|
+
entityNodes.push(node);
|
|
119
|
+
const path = docPageOutputPath(layout, node);
|
|
120
|
+
placements.push({ path, fqn: entity.resolutionKey() });
|
|
121
|
+
// Cross-link to the sibling api surfaces, when emitted (shared builder).
|
|
122
|
+
const apiRefs = apiRefsFor(path);
|
|
123
|
+
const payload = buildEntityDocData(entity, {
|
|
124
|
+
dialect: rc.dialect,
|
|
125
|
+
layout,
|
|
126
|
+
...(rc.columnNamingStrategy !== undefined && {
|
|
127
|
+
columnNamingStrategy: rc.columnNamingStrategy,
|
|
128
|
+
}),
|
|
129
|
+
loadedRoot: rc.loadedRoot,
|
|
130
|
+
...(apiRefs !== undefined && { apiRefs }),
|
|
72
131
|
});
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
132
|
+
return { path, content: renderDocPage(TEMPLATE_REF, payload, provider, path) };
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// ALSO emit one NEUTRAL render-contract page per `template.output` node —
|
|
136
|
+
// a sibling artifact, distinct from the entity page. Raw node name → file
|
|
137
|
+
// (`<name>.md`), agreeing with the entity Used-by back-link target.
|
|
138
|
+
for (const child of ctx.loadedRoot.ownChildren()) {
|
|
139
|
+
if (child.type !== TYPE_TEMPLATE || child.subType !== TEMPLATE_SUBTYPE_OUTPUT) continue;
|
|
140
|
+
const node = docPageNode(child);
|
|
141
|
+
templateNodes.push(node);
|
|
142
|
+
const path = docPageOutputPath(layout, node);
|
|
143
|
+
placements.push({ path, fqn: child.resolutionKey() });
|
|
144
|
+
const payload = buildTemplateDocData(child, {
|
|
145
|
+
layout,
|
|
146
|
+
loadedRoot: ctx.loadedRoot,
|
|
147
|
+
provider,
|
|
148
|
+
});
|
|
149
|
+
files.push({ path, content: renderDocPage(TEMPLATE_PAGE_REF, payload, provider, path) });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Emit the neutral OVERVIEW/index page (README.md) at the docs root: the
|
|
153
|
+
// whole-model Mermaid ER diagram (reusing the single shared
|
|
154
|
+
// renderMermaidErBlock builder — no duplicated ER logic, ADR-0020) plus a
|
|
155
|
+
// navigable index linking every entity + template page. Prepended so it is
|
|
156
|
+
// the first file (and so README is included in the collision backstop).
|
|
157
|
+
// Only emitted when at least one page exists — an all-filtered/empty run
|
|
158
|
+
// produces nothing (no orphan landing page with an empty diagram).
|
|
159
|
+
if (files.length > 0) {
|
|
160
|
+
// The api index lives at `<subDir>/README.md` per surface; the model index
|
|
161
|
+
// lives at the docs root, so the from-path is the root-level index path
|
|
162
|
+
// (shared builder — same relative/absolute rule as the entity refs).
|
|
163
|
+
const apiIndexRefs = apiRefsFor(INDEX_FILENAME);
|
|
164
|
+
const indexContent = renderIndexPage(
|
|
165
|
+
ctx.loadedRoot,
|
|
166
|
+
layout,
|
|
167
|
+
entityNodes,
|
|
168
|
+
templateNodes,
|
|
169
|
+
apiIndexRefs,
|
|
170
|
+
);
|
|
171
|
+
placements.push({ path: INDEX_FILENAME, fqn: "<the auto-generated overview/index page>" });
|
|
172
|
+
files.unshift({ path: INDEX_FILENAME, content: indexContent });
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Hard backstop against silent overwrite (ALL layouts): two nodes that
|
|
176
|
+
// resolve to the same output path → throw naming both FQNs + the path.
|
|
177
|
+
assertNoDuplicateDocPaths(placements);
|
|
178
|
+
|
|
179
|
+
return files;
|
|
82
180
|
},
|
|
83
181
|
};
|
|
84
182
|
if (opts?.filter) generator.filter = opts.filter;
|
|
85
183
|
if (opts?.target) generator.target = opts.target;
|
|
86
184
|
return generator;
|
|
87
185
|
} as GeneratorFactory<DocsFileOpts>;
|
|
186
|
+
|
|
187
|
+
/** Build the neutral OVERVIEW/index page (README.md) body: a title + one-line
|
|
188
|
+
* description, the whole-model Mermaid ER diagram (the shared
|
|
189
|
+
* renderMermaidErBlock — ONE builder, no duplication), and a navigable index
|
|
190
|
+
* grouping entity pages vs template pages. Every link is computed with
|
|
191
|
+
* docPageHref(layout, INDEX_NODE, target) so it resolves in BOTH flat and
|
|
192
|
+
* package layout (the index lives at the docs root). Fully neutral — Mermaid +
|
|
193
|
+
* entity/template names + relationships only. */
|
|
194
|
+
function renderIndexPage(
|
|
195
|
+
root: MetaRoot,
|
|
196
|
+
layout: OutputLayout,
|
|
197
|
+
entityNodes: DocPageNode[],
|
|
198
|
+
templateNodes: DocPageNode[],
|
|
199
|
+
apiIndexRefs?: Array<{ label: string; href: string }>,
|
|
200
|
+
): string {
|
|
201
|
+
const pkg = root.package;
|
|
202
|
+
const out: string[] = [];
|
|
203
|
+
out.push("# Data Model");
|
|
204
|
+
out.push("");
|
|
205
|
+
out.push(
|
|
206
|
+
pkg !== undefined && pkg.length > 0
|
|
207
|
+
? `Overview of the \`${pkg}\` metadata model — entities, their relationships, and output templates.`
|
|
208
|
+
: "Overview of the metadata model — entities, their relationships, and output templates.",
|
|
209
|
+
);
|
|
210
|
+
out.push("");
|
|
211
|
+
|
|
212
|
+
// The whole-model ER diagram (shared neutral builder). Per-entity prose stays
|
|
213
|
+
// on each entity page; only the fenced erDiagram block lives on the overview.
|
|
214
|
+
out.push("## Diagram");
|
|
215
|
+
out.push("");
|
|
216
|
+
out.push(renderMermaidErBlock(root));
|
|
217
|
+
out.push("");
|
|
218
|
+
|
|
219
|
+
// Navigable index — grouped, sorted by name for stable output. Links resolve
|
|
220
|
+
// in both layouts because docPageHref derives them from the same placement.
|
|
221
|
+
const byName = (a: DocPageNode, b: DocPageNode) => a.name.localeCompare(b.name);
|
|
222
|
+
if (entityNodes.length > 0) {
|
|
223
|
+
out.push("## Entities");
|
|
224
|
+
out.push("");
|
|
225
|
+
for (const node of [...entityNodes].sort(byName)) {
|
|
226
|
+
out.push(`- [${node.name}](${docPageHref(layout, INDEX_NODE, node)})`);
|
|
227
|
+
}
|
|
228
|
+
out.push("");
|
|
229
|
+
}
|
|
230
|
+
if (templateNodes.length > 0) {
|
|
231
|
+
out.push("## Templates");
|
|
232
|
+
out.push("");
|
|
233
|
+
for (const node of [...templateNodes].sort(byName)) {
|
|
234
|
+
out.push(`- [${node.name}](${docPageHref(layout, INDEX_NODE, node)})`);
|
|
235
|
+
}
|
|
236
|
+
out.push("");
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Cross-link to the GENERATED-SDK api reference indexes, when api surfaces are
|
|
240
|
+
// emitted alongside the model surface — one bullet per language surface. ABSENT
|
|
241
|
+
// or empty → no section (index byte-identical to model-only runs).
|
|
242
|
+
if (apiIndexRefs !== undefined && apiIndexRefs.length > 0) {
|
|
243
|
+
out.push("## API reference");
|
|
244
|
+
out.push("");
|
|
245
|
+
for (const ref of apiIndexRefs) {
|
|
246
|
+
out.push(`- [${ref.label}](${ref.href})`);
|
|
247
|
+
}
|
|
248
|
+
out.push("");
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Trailing newline (one), matching the per-page convention.
|
|
252
|
+
return out.join("\n").replace(/\n+$/, "\n");
|
|
253
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { MetaObject } from "@metaobjectsdev/metadata";
|
|
2
|
-
import { perEntity, type Generator, type GeneratorFactory } from "../generator.js";
|
|
2
|
+
import { perEntity, type EmittedFile, type GenContext, type Generator, type GeneratorFactory } from "../generator.js";
|
|
3
3
|
import { renderEntityFile } from "../templates/entity-file.js";
|
|
4
|
+
import { renderSharedEnumsFile, SHARED_ENUMS_BASENAME } from "../templates/enums-file.js";
|
|
4
5
|
import { formatTs } from "../format.js";
|
|
5
6
|
import { entityOutputPath } from "../import-path.js";
|
|
6
7
|
import { isAbstract } from "../instance-artifacts.js";
|
|
@@ -27,24 +28,39 @@ export interface EntityFileOpts {
|
|
|
27
28
|
|
|
28
29
|
export const entityFile = function entityFile(opts?: EntityFileOpts): Generator {
|
|
29
30
|
const allowlists = opts?.allowlists ?? true;
|
|
31
|
+
const perEntityEmit = perEntity(async (entity, ctx) => {
|
|
32
|
+
if (!ctx.renderContext) {
|
|
33
|
+
throw new Error("entity-file: renderContext is required (provided by runGen)");
|
|
34
|
+
}
|
|
35
|
+
// Abstract entities contribute shape only. When emitAbstractShapes is off
|
|
36
|
+
// (cross-port knob; default on) the entity-file generator emits nothing for
|
|
37
|
+
// them. Instance/write generators skip abstract unconditionally elsewhere.
|
|
38
|
+
if (isAbstract(entity) && !ctx.renderContext.emitAbstractShapes) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
path: entityOutputPath(ctx.config.outputLayout ?? "flat", entity.package, `${entity.name}.ts`),
|
|
43
|
+
content: await formatTs(renderEntityFile(entity, ctx.renderContext, { allowlists })),
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
|
|
30
47
|
const generator: Generator = {
|
|
31
48
|
name: "entity-file",
|
|
32
49
|
emitsEntityModule: true,
|
|
33
|
-
generate:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
generate: async (ctx: GenContext): Promise<EmittedFile[]> => {
|
|
51
|
+
const files = await perEntityEmit(ctx);
|
|
52
|
+
// FR-019: emit the shared-enums module ONCE per run, into the entity-module
|
|
53
|
+
// target root. Returns null (no file) when the model uses no materialized
|
|
54
|
+
// shared enums — keeping the inline-enum default byte-identical (no new file).
|
|
55
|
+
const sharedEnums = renderSharedEnumsFile(ctx.loadedRoot);
|
|
56
|
+
if (sharedEnums !== null) {
|
|
57
|
+
files.push({
|
|
58
|
+
path: `${SHARED_ENUMS_BASENAME}.ts`,
|
|
59
|
+
content: await formatTs(sharedEnums),
|
|
60
|
+
});
|
|
42
61
|
}
|
|
43
|
-
return
|
|
44
|
-
|
|
45
|
-
content: await formatTs(renderEntityFile(entity, ctx.renderContext, { allowlists })),
|
|
46
|
-
};
|
|
47
|
-
}),
|
|
62
|
+
return files;
|
|
63
|
+
},
|
|
48
64
|
};
|
|
49
65
|
if (opts?.filter) {
|
|
50
66
|
generator.filter = opts.filter;
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
//
|
|
6
6
|
// The emitted extractor sits over the output-parser's nested-capable extract and turns dirty LLM
|
|
7
7
|
// text into the strict typed payload graph. It imports from the sibling <Name>.output.ts (the
|
|
8
|
-
// output-parser) and
|
|
8
|
+
// output-parser) and from each payload value-object's own entity module (<VO>.ts, emitted by
|
|
9
|
+
// entityFile), so run it alongside outputParser() + entityFile().
|
|
9
10
|
//
|
|
10
11
|
// Consumer wiring (metaobjects.config.ts):
|
|
11
12
|
// generators: [..., outputParser(), extractor()]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Per-field doc anchor convention (linked-template-source-docs).
|
|
2
|
+
//
|
|
3
|
+
// A field's stable doc anchor slug is `field-<name>` (the field name verbatim).
|
|
4
|
+
// This is the SINGLE source of truth for the slug, shared by BOTH:
|
|
5
|
+
// • the entity-page builder, which emits a literal `<a id="field-<name>">` in
|
|
6
|
+
// each Constraints-table Field cell, and
|
|
7
|
+
// • the template-source annotator, whose links target `#field-<name>`.
|
|
8
|
+
// Sharing one helper means the anchor and its links can never drift.
|
|
9
|
+
//
|
|
10
|
+
// The name is used verbatim (not URL-slugified): MetaObjects field names are
|
|
11
|
+
// already identifier-safe (no spaces / punctuation), so `field-<name>` is a
|
|
12
|
+
// valid HTML id and a valid Markdown fragment as-is.
|
|
13
|
+
|
|
14
|
+
/** The stable doc-anchor slug for a field: `field-<name>`. */
|
|
15
|
+
export function fieldAnchorSlug(name: string): string {
|
|
16
|
+
return `field-${name}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** The literal HTML anchor a Markdown link can target: `<a id="field-<name>"></a>`.
|
|
20
|
+
* Renders on GitHub-flavored Markdown and static-site generators, including
|
|
21
|
+
* inside a table cell. */
|
|
22
|
+
export function fieldAnchorHtml(name: string): string {
|
|
23
|
+
return `<a id="${fieldAnchorSlug(name)}"></a>`;
|
|
24
|
+
}
|
package/src/generators/index.ts
CHANGED
|
@@ -4,12 +4,16 @@ export { callableFile, type CallableFileOpts } from "./callable-file.js";
|
|
|
4
4
|
export { routesFile, type RoutesFileOpts } from "./routes-file.js";
|
|
5
5
|
export { routesFileHono, type RoutesFileHonoOpts } from "./routes-file-hono.js";
|
|
6
6
|
export { barrel, type BarrelOpts } from "./barrel.js";
|
|
7
|
+
/** @deprecated ADR-0021 D1 — neutral artifact owned by `meta docs` (ADR-0020); not part of the recommended `meta gen` suite. */
|
|
7
8
|
export { mermaidErDiagram, type MermaidErOptions } from "./mermaid-er.js";
|
|
8
9
|
export { promptRender, type PromptRenderOpts } from "./prompt-render-file.js";
|
|
9
10
|
export { outputParser, type OutputParserOpts } from "./output-parser-file.js";
|
|
10
11
|
export { extractor, type ExtractorOpts } from "./extractor-file.js";
|
|
11
12
|
export { outputPrompt, type OutputPromptOpts } from "./output-prompt-file.js";
|
|
12
13
|
export { renderHelper, type RenderHelperOpts } from "./render-helper-file.js";
|
|
14
|
+
/** @deprecated ADR-0025 — `meta docs` is the single docs door; `apiDocsFile` stays as the internal engine of its api surface, not a `meta gen` config generator. */
|
|
15
|
+
export { apiDocsFile, type ApiDocsFileOpts } from "./api-docs-file.js";
|
|
16
|
+
/** @deprecated ADR-0021 D1 — `meta docs` is the single docs door; `docsFile` stays as its internal engine, not a `meta gen` config generator. */
|
|
13
17
|
export { docsFile, type DocsFileOpts } from "./docs-file.js";
|
|
14
18
|
export {
|
|
15
19
|
templateGenerator,
|
|
@@ -17,12 +21,15 @@ export {
|
|
|
17
21
|
type TemplateWalkResult,
|
|
18
22
|
type TemplateFormat,
|
|
19
23
|
} from "./template-generator.js";
|
|
24
|
+
export { traceHelperFile, type TraceHelperOpts } from "./trace-helper-file.js";
|
|
20
25
|
export type {
|
|
21
26
|
EntityDocData,
|
|
22
27
|
StorageFieldDoc,
|
|
23
28
|
IdentityDoc,
|
|
24
29
|
RelationshipDoc,
|
|
25
30
|
UsedByDoc,
|
|
26
|
-
|
|
31
|
+
ConstraintRow,
|
|
27
32
|
} from "./docs-data.js";
|
|
28
33
|
export { buildEntityDocData } from "./docs-data-builder.js";
|
|
34
|
+
export type { TemplateDocData, TemplateOutputPart } from "./template-doc-data.js";
|
|
35
|
+
export { buildTemplateDocData } from "./template-doc-builder.js";
|
|
@@ -12,6 +12,20 @@ export interface MermaidErOptions {
|
|
|
12
12
|
* Emit a single Markdown file containing a Mermaid `erDiagram` plus per-entity
|
|
13
13
|
* prose sections. The renderer walks the loaded root for all entities; the
|
|
14
14
|
* default outFile is "docs/model.md".
|
|
15
|
+
*
|
|
16
|
+
* TIER NOTE (ADR-0020): the CANONICAL home of the neutral ER diagram is now the
|
|
17
|
+
* neutral docs engine — the OVERVIEW/index page (`README.md`) emitted by
|
|
18
|
+
* `docsFile()` / `meta docs` embeds the SAME `renderMermaidErBlock()` this
|
|
19
|
+
* generator's `renderMermaidModel()` reuses. This standalone Tier-1 generator is
|
|
20
|
+
* retained ONLY as a thin back-compat wrapper for adopters that already have
|
|
21
|
+
* `mermaidErDiagram` in their `meta gen` config; it adds NO ER logic of its own
|
|
22
|
+
* (no duplication) — it delegates to the shared `renderMermaidModel()` builder.
|
|
23
|
+
*
|
|
24
|
+
* @deprecated ADR-0021 D1: the ER diagram is a Tier-2 neutral artifact owned by
|
|
25
|
+
* the docs engine (ADR-0020). Use `meta docs` — it embeds the same ER block.
|
|
26
|
+
* This standalone `meta gen` generator is flagged neutral in the registry
|
|
27
|
+
* (`--list`) and is no longer part of the recommended native suite. Kept for
|
|
28
|
+
* back-compat; do not add to new gen configs.
|
|
15
29
|
*/
|
|
16
30
|
export const mermaidErDiagram = function mermaidErDiagram(
|
|
17
31
|
opts?: MermaidErOptions,
|