@metaobjectsdev/codegen-ts 0.24.4 → 0.25.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 +37 -12
- package/dist/api-surface.d.ts +29 -0
- package/dist/api-surface.d.ts.map +1 -1
- package/dist/api-surface.js +47 -0
- package/dist/api-surface.js.map +1 -1
- package/dist/client-directive.d.ts +18 -0
- package/dist/client-directive.d.ts.map +1 -0
- package/dist/client-directive.js +37 -0
- package/dist/client-directive.js.map +1 -0
- package/dist/column-mapper.d.ts +12 -0
- package/dist/column-mapper.d.ts.map +1 -1
- package/dist/column-mapper.js +1 -0
- package/dist/column-mapper.js.map +1 -1
- package/dist/constants.d.ts +24 -11
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +54 -19
- package/dist/constants.js.map +1 -1
- package/dist/db-emitting.d.ts +6 -0
- package/dist/db-emitting.d.ts.map +1 -0
- package/dist/db-emitting.js +26 -0
- package/dist/db-emitting.js.map +1 -0
- package/dist/generator-registry.d.ts.map +1 -1
- package/dist/generator-registry.js +7 -1
- package/dist/generator-registry.js.map +1 -1
- package/dist/generator.d.ts +5 -0
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js.map +1 -1
- package/dist/generators/agent-docs-file.d.ts +19 -0
- package/dist/generators/agent-docs-file.d.ts.map +1 -0
- package/dist/generators/agent-docs-file.js +257 -0
- package/dist/generators/agent-docs-file.js.map +1 -0
- package/dist/generators/agent-requirements-page.d.ts +22 -0
- package/dist/generators/agent-requirements-page.d.ts.map +1 -0
- package/dist/generators/agent-requirements-page.js +175 -0
- package/dist/generators/agent-requirements-page.js.map +1 -0
- package/dist/generators/agent-schema-input.d.ts +69 -0
- package/dist/generators/agent-schema-input.d.ts.map +1 -0
- package/dist/generators/agent-schema-input.js +23 -0
- package/dist/generators/agent-schema-input.js.map +1 -0
- package/dist/generators/agent-schema-page.d.ts +21 -0
- package/dist/generators/agent-schema-page.d.ts.map +1 -0
- package/dist/generators/agent-schema-page.js +241 -0
- package/dist/generators/agent-schema-page.js.map +1 -0
- package/dist/generators/agent-ui-page.d.ts +22 -0
- package/dist/generators/agent-ui-page.d.ts.map +1 -0
- package/dist/generators/agent-ui-page.js +253 -0
- package/dist/generators/agent-ui-page.js.map +1 -0
- package/dist/generators/api-docs-file.d.ts.map +1 -1
- package/dist/generators/api-docs-file.js +13 -6
- package/dist/generators/api-docs-file.js.map +1 -1
- package/dist/generators/api-model.d.ts +6 -0
- package/dist/generators/api-model.d.ts.map +1 -1
- package/dist/generators/api-model.js +54 -35
- package/dist/generators/api-model.js.map +1 -1
- package/dist/generators/callable-file.js +1 -1
- package/dist/generators/callable-file.js.map +1 -1
- package/dist/generators/docs-data-builder.d.ts.map +1 -1
- package/dist/generators/docs-data-builder.js +47 -2
- package/dist/generators/docs-data-builder.js.map +1 -1
- package/dist/generators/docs-data.d.ts +6 -2
- package/dist/generators/docs-data.d.ts.map +1 -1
- package/dist/generators/index.d.ts +3 -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/names-file.d.ts +17 -0
- package/dist/generators/names-file.d.ts.map +1 -0
- package/dist/generators/names-file.js +95 -0
- package/dist/generators/names-file.js.map +1 -0
- package/dist/generators/requirements-markdown.d.ts +18 -1
- package/dist/generators/requirements-markdown.d.ts.map +1 -1
- package/dist/generators/requirements-markdown.js +11 -9
- package/dist/generators/requirements-markdown.js.map +1 -1
- package/dist/generators/routes-file-hono.d.ts +17 -2
- package/dist/generators/routes-file-hono.d.ts.map +1 -1
- package/dist/generators/routes-file-hono.js +15 -12
- package/dist/generators/routes-file-hono.js.map +1 -1
- package/dist/generators/routes-file.d.ts +17 -2
- package/dist/generators/routes-file.d.ts.map +1 -1
- package/dist/generators/routes-file.js +10 -8
- package/dist/generators/routes-file.js.map +1 -1
- package/dist/generators/template-generator.d.ts.map +1 -1
- package/dist/generators/template-generator.js +20 -6
- package/dist/generators/template-generator.js.map +1 -1
- package/dist/index.d.ts +21 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +40 -4
- package/dist/index.js.map +1 -1
- package/dist/metaobjects-config.d.ts +67 -1
- package/dist/metaobjects-config.d.ts.map +1 -1
- package/dist/metaobjects-config.js +10 -1
- package/dist/metaobjects-config.js.map +1 -1
- package/dist/names.d.ts +275 -0
- package/dist/names.d.ts.map +1 -0
- package/dist/names.js +434 -0
- package/dist/names.js.map +1 -0
- package/dist/naming.d.ts +17 -0
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +21 -0
- package/dist/naming.js.map +1 -1
- package/dist/overwrite-policy.d.ts.map +1 -1
- package/dist/overwrite-policy.js +15 -3
- package/dist/overwrite-policy.js.map +1 -1
- package/dist/payload-codegen.d.ts.map +1 -1
- package/dist/payload-codegen.js +4 -3
- package/dist/payload-codegen.js.map +1 -1
- package/dist/projection/extract-view-spec.d.ts +25 -1
- package/dist/projection/extract-view-spec.d.ts.map +1 -1
- package/dist/projection/extract-view-spec.js +79 -6
- package/dist/projection/extract-view-spec.js.map +1 -1
- package/dist/prompt-generator-gate.d.ts +27 -0
- package/dist/prompt-generator-gate.d.ts.map +1 -0
- package/dist/prompt-generator-gate.js +62 -0
- package/dist/prompt-generator-gate.js.map +1 -0
- package/dist/reference-templates.d.ts +22 -5
- package/dist/reference-templates.d.ts.map +1 -1
- package/dist/reference-templates.js +55 -21
- package/dist/reference-templates.js.map +1 -1
- package/dist/render-context.d.ts +20 -1
- package/dist/render-context.d.ts.map +1 -1
- package/dist/render-context.js +2 -0
- package/dist/render-context.js.map +1 -1
- package/dist/retired-codegen-attrs.d.ts +32 -0
- package/dist/retired-codegen-attrs.d.ts.map +1 -0
- package/dist/retired-codegen-attrs.js +47 -0
- package/dist/retired-codegen-attrs.js.map +1 -0
- package/dist/routes-expose.d.ts +63 -0
- package/dist/routes-expose.d.ts.map +1 -0
- package/dist/routes-expose.js +57 -0
- package/dist/routes-expose.js.map +1 -0
- package/dist/runner.d.ts +18 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +115 -7
- package/dist/runner.js.map +1 -1
- package/dist/templates/callable-file.d.ts +7 -2
- package/dist/templates/callable-file.d.ts.map +1 -1
- package/dist/templates/callable-file.js +54 -9
- package/dist/templates/callable-file.js.map +1 -1
- package/dist/templates/drizzle-schema.d.ts.map +1 -1
- package/dist/templates/drizzle-schema.js +236 -65
- package/dist/templates/drizzle-schema.js.map +1 -1
- package/dist/templates/entity-constants.d.ts +15 -6
- package/dist/templates/entity-constants.d.ts.map +1 -1
- package/dist/templates/entity-constants.js +85 -161
- 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 +38 -4
- package/dist/templates/entity-file.js.map +1 -1
- package/dist/templates/entity-meta-file.d.ts +15 -1
- package/dist/templates/entity-meta-file.d.ts.map +1 -1
- package/dist/templates/entity-meta-file.js +12 -2
- package/dist/templates/entity-meta-file.js.map +1 -1
- package/dist/templates/entity-ui-descriptor.d.ts +112 -0
- package/dist/templates/entity-ui-descriptor.d.ts.map +1 -0
- package/dist/templates/entity-ui-descriptor.js +238 -0
- package/dist/templates/entity-ui-descriptor.js.map +1 -0
- package/dist/templates/field-meta.d.ts +46 -9
- package/dist/templates/field-meta.d.ts.map +1 -1
- package/dist/templates/field-meta.js +95 -21
- package/dist/templates/field-meta.js.map +1 -1
- package/dist/templates/names-decl.d.ts +38 -0
- package/dist/templates/names-decl.d.ts.map +1 -0
- package/dist/templates/names-decl.js +104 -0
- package/dist/templates/names-decl.js.map +1 -0
- package/dist/templates/output-parser.d.ts.map +1 -1
- package/dist/templates/output-parser.js +54 -8
- package/dist/templates/output-parser.js.map +1 -1
- package/dist/templates/projection-decl.d.ts +21 -0
- package/dist/templates/projection-decl.d.ts.map +1 -1
- package/dist/templates/projection-decl.js +53 -29
- package/dist/templates/projection-decl.js.map +1 -1
- package/dist/templates/queries-file.d.ts.map +1 -1
- package/dist/templates/queries-file.js +17 -2
- package/dist/templates/queries-file.js.map +1 -1
- package/dist/templates/render-helper.d.ts.map +1 -1
- package/dist/templates/render-helper.js +3 -1
- package/dist/templates/render-helper.js.map +1 -1
- package/dist/templates/requirement-test.d.ts.map +1 -1
- package/dist/templates/requirement-test.js +48 -21
- package/dist/templates/requirement-test.js.map +1 -1
- package/dist/templates/routes-file-hono.d.ts +2 -1
- package/dist/templates/routes-file-hono.d.ts.map +1 -1
- package/dist/templates/routes-file-hono.js +11 -2
- package/dist/templates/routes-file-hono.js.map +1 -1
- package/dist/templates/routes-file.d.ts +2 -1
- package/dist/templates/routes-file.d.ts.map +1 -1
- package/dist/templates/routes-file.js +54 -21
- package/dist/templates/routes-file.js.map +1 -1
- package/dist/templates/value-object-file.d.ts.map +1 -1
- package/dist/templates/value-object-file.js +15 -1
- package/dist/templates/value-object-file.js.map +1 -1
- package/dist/templates/view-decl.d.ts +37 -1
- package/dist/templates/view-decl.d.ts.map +1 -1
- package/dist/templates/view-decl.js +27 -3
- package/dist/templates/view-decl.js.map +1 -1
- package/dist/templates/zod-validators.d.ts +21 -0
- package/dist/templates/zod-validators.d.ts.map +1 -1
- package/dist/templates/zod-validators.js +40 -5
- package/dist/templates/zod-validators.js.map +1 -1
- package/dist/view-context.d.ts +24 -0
- package/dist/view-context.d.ts.map +1 -0
- package/dist/view-context.js +81 -0
- package/dist/view-context.js.map +1 -0
- package/package.json +6 -6
- package/src/api-surface.ts +53 -0
- package/src/client-directive.ts +36 -0
- package/src/column-mapper.ts +13 -0
- package/src/constants.ts +91 -16
- package/src/db-emitting.ts +31 -0
- package/src/generator-registry.ts +7 -0
- package/src/generator.ts +5 -0
- package/src/generators/agent-docs-file.ts +297 -0
- package/src/generators/agent-requirements-page.ts +199 -0
- package/src/generators/agent-schema-input.ts +88 -0
- package/src/generators/agent-schema-page.ts +297 -0
- package/src/generators/agent-ui-page.ts +290 -0
- package/src/generators/api-docs-file.ts +13 -6
- package/src/generators/api-model.ts +63 -34
- package/src/generators/callable-file.ts +1 -1
- package/src/generators/docs-data-builder.ts +46 -2
- package/src/generators/docs-data.ts +6 -2
- package/src/generators/index.ts +10 -0
- package/src/generators/names-file.ts +98 -0
- package/src/generators/requirements-markdown.ts +36 -2
- package/src/generators/routes-file-hono.ts +26 -15
- package/src/generators/routes-file.ts +20 -7
- package/src/generators/template-generator.ts +20 -6
- package/src/index.ts +63 -5
- package/src/metaobjects-config.ts +78 -2
- package/src/names.ts +630 -0
- package/src/naming.ts +23 -0
- package/src/overwrite-policy.ts +15 -3
- package/src/payload-codegen.ts +4 -3
- package/src/projection/extract-view-spec.ts +85 -6
- package/src/prompt-generator-gate.ts +73 -0
- package/src/reference/barrel.ts +3 -0
- package/src/reference/entity.ts +28 -2
- package/src/reference/names.ts +125 -0
- package/src/reference/queries.ts +14 -2
- package/src/reference/routes-hono.ts +113 -0
- package/src/reference/routes.ts +30 -9
- package/src/reference-templates.ts +61 -21
- package/src/render-context.ts +22 -1
- package/src/retired-codegen-attrs.ts +52 -0
- package/src/routes-expose.ts +86 -0
- package/src/runner.ts +129 -11
- package/src/templates/callable-file.ts +60 -8
- package/src/templates/drizzle-schema.ts +248 -60
- package/src/templates/entity-constants.ts +95 -184
- package/src/templates/entity-file.ts +46 -4
- package/src/templates/entity-meta-file.ts +16 -3
- package/src/templates/entity-ui-descriptor.ts +305 -0
- package/src/templates/field-meta.ts +100 -19
- package/src/templates/names-decl.ts +165 -0
- package/src/templates/output-parser.ts +54 -7
- package/src/templates/projection-decl.ts +72 -31
- package/src/templates/queries-file.ts +17 -2
- package/src/templates/render-helper.ts +3 -1
- package/src/templates/requirement-test.ts +49 -18
- package/src/templates/routes-file-hono.ts +14 -2
- package/src/templates/routes-file.ts +69 -24
- package/src/templates/value-object-file.ts +15 -1
- package/src/templates/view-decl.ts +53 -3
- package/src/templates/zod-validators.ts +41 -5
- package/src/view-context.ts +88 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { Generator, GenContext, EmittedFile } from "../generator.js";
|
|
2
|
+
import { entityOutputPath, crossEntitySpecifier } from "../import-path.js";
|
|
3
|
+
import { renderNamesDecl } from "../templates/names-decl.js";
|
|
4
|
+
import { namesArtifactSuperOf, resolveObjectNames } from "../names.js";
|
|
5
|
+
import type { MetaObject } from "@metaobjectsdev/metadata";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* §A1/§A2/§A6 — `<Entity>Names`: the physical database names for one object, as constants a
|
|
9
|
+
* hand-written consumer references instead of a string literal.
|
|
10
|
+
*
|
|
11
|
+
* This is the built-in twin of `src/reference/names.ts` (ADR-0034 scaffold-and-own —
|
|
12
|
+
* `meta init` copies the reference file into the adopter's repo; this one stays the
|
|
13
|
+
* engine's internal composer and the reference-byte-identical gate's other half). Same
|
|
14
|
+
* `generate` body; only the import paths differ (relative package-internal here, the
|
|
15
|
+
* public `@metaobjectsdev/codegen-ts` barrel there).
|
|
16
|
+
*
|
|
17
|
+
* Deliberately a SEPARATE generator, never a boolean on the entity generator — a new
|
|
18
|
+
* artifact is a MINOR under docs/compatibility-policy.md and adds zero bytes to existing
|
|
19
|
+
* files, where a flag would move every $table-carrying golden for the same functionality.
|
|
20
|
+
*/
|
|
21
|
+
export function namesFile(): Generator {
|
|
22
|
+
return {
|
|
23
|
+
name: "names",
|
|
24
|
+
// §A6 — the marker the runner aggregates into ResolvedGenConfig.includeNames, so the
|
|
25
|
+
// entity generator can tell whether this artifact will exist. Exactly the mechanism
|
|
26
|
+
// routesFileHono already uses via emitsHonoRoutes/includeHonoRoutes.
|
|
27
|
+
emitsNames: true,
|
|
28
|
+
generate: (ctx: GenContext): EmittedFile[] => {
|
|
29
|
+
const layout = ctx.config.outputLayout ?? "flat";
|
|
30
|
+
const extStyle = ctx.config.extStyle ?? "js";
|
|
31
|
+
// The strategy lives on the RENDER CONTEXT, not on ResolvedGenConfig — `ctx.config`
|
|
32
|
+
// carries outDir/extStyle/dbImport/dialect and nothing about naming.
|
|
33
|
+
const strategy = ctx.renderContext?.columnNamingStrategy;
|
|
34
|
+
|
|
35
|
+
const pathOf = (obj: MetaObject): string =>
|
|
36
|
+
// entityOutputPath, not a bare filename: §A6 makes the entity module IMPORT these
|
|
37
|
+
// constants, so the artifact has to land in the same directory the entity module
|
|
38
|
+
// does. Under outputLayout: "package" a bare name puts it at the target ROOT while
|
|
39
|
+
// its entity sits at <pkg>/<Entity>.ts — an unresolvable import, and a hard
|
|
40
|
+
// conflicting-duplicate-path failure as soon as two packages declare a
|
|
41
|
+
// same-bare-named entity.
|
|
42
|
+
entityOutputPath(layout, obj.package, `${obj.name}.names.ts`);
|
|
43
|
+
|
|
44
|
+
const superSpecifierFor = (obj: MetaObject): string | undefined => {
|
|
45
|
+
const sup = namesArtifactSuperOf(obj);
|
|
46
|
+
return sup === undefined
|
|
47
|
+
? undefined
|
|
48
|
+
: crossEntitySpecifier(layout, obj.package, sup.package, `${sup.name}.names`, extStyle);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const out: EmittedFile[] = [];
|
|
52
|
+
// Pass 1 — every matched object that participates in the database (#248).
|
|
53
|
+
// `emitted` tracks what pass 1 actually WROTE, not what it looked at: a matched
|
|
54
|
+
// abstract base emits nothing here, and seeding it as already-emitted is what would
|
|
55
|
+
// make pass 2 skip the very object it exists to produce.
|
|
56
|
+
const emitted = new Set<string>();
|
|
57
|
+
const participants = ctx.entities.filter(ctx.matches);
|
|
58
|
+
for (const entity of participants) {
|
|
59
|
+
const content = renderNamesDecl(entity, {
|
|
60
|
+
strategy, superSpecifier: superSpecifierFor(entity),
|
|
61
|
+
});
|
|
62
|
+
if (content === "") continue; // no primary source ⇒ no names artifact (#248)
|
|
63
|
+
emitted.add(entity.resolutionKey());
|
|
64
|
+
out.push({ path: pathOf(entity), content });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Pass 2 — the abstract bases those participants EXTEND. Each carries the columns it
|
|
68
|
+
// declares, so a child states them once rather than restating its parent's.
|
|
69
|
+
//
|
|
70
|
+
// Reached by walking UP from a participant, never by scanning for abstracts: that is
|
|
71
|
+
// what keeps #248 intact. A sourceless object nothing persistable extends — an
|
|
72
|
+
// `object.value`, say — is not reached, so it acquires no artifact and no phantom
|
|
73
|
+
// participation. Two children of one base both reach it and emit the same file at
|
|
74
|
+
// the same path with the same bytes; the runner collapses byte-identical duplicates
|
|
75
|
+
// (#266), so it is written once. `emitted` keeps that from even arising, and keeps
|
|
76
|
+
// the walk from re-rendering the same base once per child.
|
|
77
|
+
for (const entity of participants) {
|
|
78
|
+
if (resolveObjectNames(entity, strategy) === undefined) continue;
|
|
79
|
+
for (let sup = namesArtifactSuperOf(entity); sup !== undefined;
|
|
80
|
+
sup = namesArtifactSuperOf(sup)) {
|
|
81
|
+
const key = sup.resolutionKey();
|
|
82
|
+
if (emitted.has(key)) break; // already emitted, and so is everything above it
|
|
83
|
+
emitted.add(key);
|
|
84
|
+
// `fragment` says "this is an ancestor render", not which shape to render:
|
|
85
|
+
// `renderNamesDecl` derives that from the object itself, so a TPH base reached
|
|
86
|
+
// by this walk keeps the shared table it owns. Deciding it there rather than
|
|
87
|
+
// here is what makes the EJECTED copy of this generator correct too.
|
|
88
|
+
const content = renderNamesDecl(sup, {
|
|
89
|
+
strategy, superSpecifier: superSpecifierFor(sup), fragment: true,
|
|
90
|
+
});
|
|
91
|
+
if (content === "") continue;
|
|
92
|
+
out.push({ path: pathOf(sup), content });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return out;
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
@@ -86,14 +86,48 @@ function renderOne(r: RequirementRow): string {
|
|
|
86
86
|
* The generator keys on that to emit no file at all, which is in turn what lets the
|
|
87
87
|
* surface default to on without changing output for any project lacking a ledger.
|
|
88
88
|
*/
|
|
89
|
-
export
|
|
89
|
+
export interface RequirementsMarkdownOpts {
|
|
90
|
+
/**
|
|
91
|
+
* Render the ledger as a SECTION of a larger page rather than as the page.
|
|
92
|
+
*
|
|
93
|
+
* The `agent/requirements.md` surface carries this ledger under its own `## The ledger`
|
|
94
|
+
* heading, and an embedded copy that keeps its `# Requirements` title gives the page two
|
|
95
|
+
* H1s and reparents every entry as a sibling of the section that contains it — the
|
|
96
|
+
* document silently loses its outline. So the title is dropped and every heading moves
|
|
97
|
+
* down one level.
|
|
98
|
+
*
|
|
99
|
+
* A POST-HOC REGEX OVER THIS FUNCTION'S OUTPUT would do the same thing and would be the
|
|
100
|
+
* wrong shape: heading depth is this renderer's decision (it already caps at h6), and a
|
|
101
|
+
* caller rewriting it from outside would have to re-derive that cap and would drift from
|
|
102
|
+
* it the next time this file changes.
|
|
103
|
+
*/
|
|
104
|
+
readonly embedded?: boolean;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function renderRequirementsMarkdown(
|
|
108
|
+
rows: readonly RequirementRow[],
|
|
109
|
+
opts?: RequirementsMarkdownOpts,
|
|
110
|
+
): string {
|
|
90
111
|
if (rows.length === 0) return "";
|
|
91
112
|
|
|
113
|
+
const body = rows.map(renderOne);
|
|
114
|
+
if (opts?.embedded === true) {
|
|
115
|
+
return [
|
|
116
|
+
`${rows.length} declared requirement${rows.length === 1 ? "" : "s"}, in declaration order.`,
|
|
117
|
+
"",
|
|
118
|
+
// One extra `#` on every heading line, capped at h6 exactly as `heading()` caps.
|
|
119
|
+
...body.map((entry) =>
|
|
120
|
+
entry.replace(/^(#{1,6}) /gm, (_m, hashes: string) =>
|
|
121
|
+
`${"#".repeat(Math.min(hashes.length + 1, 6))} `,
|
|
122
|
+
),
|
|
123
|
+
),
|
|
124
|
+
].join("\n");
|
|
125
|
+
}
|
|
92
126
|
return [
|
|
93
127
|
"# Requirements",
|
|
94
128
|
"",
|
|
95
129
|
`${rows.length} declared requirement${rows.length === 1 ? "" : "s"}, in declaration order.`,
|
|
96
130
|
"",
|
|
97
|
-
...
|
|
131
|
+
...body,
|
|
98
132
|
].join("\n");
|
|
99
133
|
}
|
|
@@ -4,11 +4,21 @@ import { renderRoutesFileHono } from "../templates/routes-file-hono.js";
|
|
|
4
4
|
import { hasAnyRdbSource } from "../source-detect.js";
|
|
5
5
|
import { formatTs } from "../format.js";
|
|
6
6
|
import { entityOutputPath } from "../import-path.js";
|
|
7
|
-
import { CODEGEN_ATTR_EMIT_ROUTES } from "../constants.js";
|
|
8
7
|
import { isTphSubtype } from "../templates/zod-validators.js";
|
|
8
|
+
import { resolveExpose, type ExposeOption } from "../routes-expose.js";
|
|
9
9
|
|
|
10
10
|
export interface RoutesFileHonoOpts {
|
|
11
11
|
filter?: (entity: MetaObject) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Which CRUD verbs the emitted file mounts (#348). Verbs, or a per-entity function;
|
|
14
|
+
* absent means all five and emits byte-identical output.
|
|
15
|
+
*
|
|
16
|
+
* routesFileHono({ expose: (e) => e.name === "AuditEntry" ? ["list", "get"] : undefined })
|
|
17
|
+
*
|
|
18
|
+
* A `filter` cannot express this — it decides whether the file emits AT ALL, so it can
|
|
19
|
+
* only remove the whole surface, not restrict it to a subset of verbs.
|
|
20
|
+
*/
|
|
21
|
+
expose?: ExposeOption;
|
|
12
22
|
target?: string;
|
|
13
23
|
}
|
|
14
24
|
|
|
@@ -22,8 +32,12 @@ export interface RoutesFileHonoOpts {
|
|
|
22
32
|
* consumers running Hono can replace hand-written route registration with
|
|
23
33
|
* this generator output one entity at a time.
|
|
24
34
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
35
|
+
* If the user supplies their own filter, it AND-composes with the built-in gates.
|
|
36
|
+
*
|
|
37
|
+
* Decide per generator what you consume: wire only the generators whose output you
|
|
38
|
+
* actually import, and narrow this one with its `filter` option. There is no `@emit*`
|
|
39
|
+
* metadata attribute — those were never registered vocabulary, so `meta verify` rejects
|
|
40
|
+
* them (ERR_UNKNOWN_ATTR).
|
|
27
41
|
*
|
|
28
42
|
* #248 R2: an object with no declared/inherited source.rdb (of ANY kind) isn't
|
|
29
43
|
* backed by any store — gated by `hasAnyRdbSource` (does NOT add TPH handling;
|
|
@@ -31,13 +45,17 @@ export interface RoutesFileHonoOpts {
|
|
|
31
45
|
*/
|
|
32
46
|
export const routesFileHono = function routesFileHono(opts?: RoutesFileHonoOpts): Generator {
|
|
33
47
|
const userFilter = opts?.filter ?? (() => true);
|
|
48
|
+
// Eligibility, minus the TPH question — stated ONCE so the emit set and the warn set
|
|
49
|
+
// below cannot drift apart. They differ only by `!isTphSubtype` vs `isTphSubtype`, and
|
|
50
|
+
// written out twice a later edit to one silently makes an entity either stop emitting
|
|
51
|
+
// without being named as held back, or get warned about while still emitting.
|
|
52
|
+
const passesOtherGates = (e: MetaObject): boolean =>
|
|
53
|
+
hasAnyRdbSource(e) && userFilter(e);
|
|
34
54
|
const generator: Generator = {
|
|
35
55
|
name: "routes-file-hono",
|
|
36
56
|
// Marks this as the Hono routes generator so the runner can aggregate
|
|
37
57
|
// `ctx.config.includeHonoRoutes` and api-docs auto-documents the Hono surface.
|
|
38
58
|
emitsHonoRoutes: true,
|
|
39
|
-
// ADR-0039: resolving — a concrete entity may inherit @emitRoutes via extends.
|
|
40
|
-
//
|
|
41
59
|
// TPH subtypes are EXCLUDED, matching the Fastify generator. A TPH subtype shares
|
|
42
60
|
// its base's table, so mounting vanilla CRUD for it produced routes with no
|
|
43
61
|
// discriminator scoping at all: the list returned EVERY subtype's rows, and
|
|
@@ -46,18 +64,11 @@ export const routesFileHono = function routesFileHono(opts?: RoutesFileHonoOpts)
|
|
|
46
64
|
// these to a discriminator-aware renderer; the Hono runtime has no discriminator
|
|
47
65
|
// support yet, so this fails CLOSED and the run says so (see the warning below)
|
|
48
66
|
// rather than shipping an artifact that returns the wrong rows.
|
|
49
|
-
filter: (e: MetaObject) =>
|
|
50
|
-
e.attr(CODEGEN_ATTR_EMIT_ROUTES) !== false
|
|
51
|
-
&& hasAnyRdbSource(e)
|
|
52
|
-
&& !isTphSubtype(e)
|
|
53
|
-
&& userFilter(e),
|
|
67
|
+
filter: (e: MetaObject) => passesOtherGates(e) && !isTphSubtype(e),
|
|
54
68
|
generate: async (ctx) => {
|
|
55
69
|
// One note per run naming every TPH subtype held back, so the gap is visible at
|
|
56
70
|
// `meta gen` time rather than discovered as missing endpoints in production.
|
|
57
|
-
const skipped = ctx.entities.filter(
|
|
58
|
-
(e) => e.attr(CODEGEN_ATTR_EMIT_ROUTES) !== false
|
|
59
|
-
&& hasAnyRdbSource(e) && isTphSubtype(e) && userFilter(e),
|
|
60
|
-
);
|
|
71
|
+
const skipped = ctx.entities.filter((e) => passesOtherGates(e) && isTphSubtype(e));
|
|
61
72
|
if (skipped.length > 0) {
|
|
62
73
|
ctx.warn(
|
|
63
74
|
`no Hono routes emitted for the TPH subtype(s) ${skipped.map((e) => e.name).join(", ")} — ` +
|
|
@@ -79,7 +90,7 @@ export const routesFileHono = function routesFileHono(opts?: RoutesFileHonoOpts)
|
|
|
79
90
|
entity.package,
|
|
80
91
|
`${entity.name}.routes.hono.ts`,
|
|
81
92
|
),
|
|
82
|
-
content: await formatTs(renderRoutesFileHono(entity, ctx.renderContext)),
|
|
93
|
+
content: await formatTs(renderRoutesFileHono(entity, ctx.renderContext, resolveExpose(entity, opts?.expose))),
|
|
83
94
|
};
|
|
84
95
|
});
|
|
85
96
|
if (opts?.target) {
|
|
@@ -5,16 +5,30 @@ import { isTphSubtype } from "../templates/zod-validators.js";
|
|
|
5
5
|
import { hasAnyRdbSource } from "../source-detect.js";
|
|
6
6
|
import { formatTs } from "../format.js";
|
|
7
7
|
import { entityOutputPath } from "../import-path.js";
|
|
8
|
-
import {
|
|
8
|
+
import { resolveExpose, type ExposeOption } from "../routes-expose.js";
|
|
9
9
|
|
|
10
10
|
export interface RoutesFileOpts {
|
|
11
11
|
filter?: (entity: MetaObject) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Which CRUD verbs the emitted file mounts (#348). Verbs, or a per-entity function;
|
|
14
|
+
* absent means all five and emits byte-identical output.
|
|
15
|
+
*
|
|
16
|
+
* routesFile({ expose: (e) => e.name === "AuditEntry" ? ["list", "get"] : undefined })
|
|
17
|
+
*
|
|
18
|
+
* A `filter` cannot express this — it decides whether the file emits AT ALL, so it can
|
|
19
|
+
* only remove the whole surface, not restrict it to a subset of verbs.
|
|
20
|
+
*/
|
|
21
|
+
expose?: ExposeOption;
|
|
12
22
|
target?: string;
|
|
13
23
|
}
|
|
14
24
|
|
|
15
25
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
26
|
+
* If the user supplies their own filter, it AND-composes with the built-in gates.
|
|
27
|
+
*
|
|
28
|
+
* Decide per generator what you consume: wire only the generators whose output you
|
|
29
|
+
* actually import, and narrow this one with its `filter` option. There is no `@emit*`
|
|
30
|
+
* metadata attribute — those were never registered vocabulary, so `meta verify` rejects
|
|
31
|
+
* them (ERR_UNKNOWN_ATTR).
|
|
18
32
|
*
|
|
19
33
|
* #248 R2: an object with no declared/inherited source.rdb (of ANY kind) isn't
|
|
20
34
|
* backed by any store — routes against it would import Drizzle table/allowlist
|
|
@@ -27,17 +41,16 @@ export const routesFile = function routesFile(opts?: RoutesFileOpts): Generator
|
|
|
27
41
|
const userFilter = opts?.filter ?? (() => true);
|
|
28
42
|
const generator: Generator = {
|
|
29
43
|
name: "routes-file",
|
|
30
|
-
// Always set: AND-composes
|
|
44
|
+
// Always set: AND-composes the built-in gates with the optional user filter.
|
|
31
45
|
filter: (e: MetaObject) =>
|
|
32
|
-
|
|
33
|
-
e.attr(CODEGEN_ATTR_EMIT_ROUTES) !== false && hasAnyRdbSource(e) && !isTphSubtype(e) && userFilter(e),
|
|
46
|
+
hasAnyRdbSource(e) && !isTphSubtype(e) && userFilter(e),
|
|
34
47
|
generate: perEntity(async (entity, ctx) => {
|
|
35
48
|
if (!ctx.renderContext) {
|
|
36
49
|
throw new Error("routes-file: renderContext is required (provided by runGen)");
|
|
37
50
|
}
|
|
38
51
|
return {
|
|
39
52
|
path: entityOutputPath(ctx.config.outputLayout ?? "flat", entity.package, `${entity.name}.routes.ts`),
|
|
40
|
-
content: await formatTs(renderRoutesFile(entity, ctx.renderContext)),
|
|
53
|
+
content: await formatTs(renderRoutesFile(entity, ctx.renderContext, resolveExpose(entity, opts?.expose))),
|
|
41
54
|
};
|
|
42
55
|
}),
|
|
43
56
|
};
|
|
@@ -5,13 +5,27 @@
|
|
|
5
5
|
// generators; just adds the "Mustache template" + "walk that yields a
|
|
6
6
|
// data dict per output" primitives.
|
|
7
7
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// SUPERSEDED, and left here as a correction because the old line still circulates:
|
|
9
|
+
// the original 2026-05-28 split was "Code → hand-coded generators, Documents →
|
|
10
|
+
// templateGenerator", with code emission an explicit NON-GOAL for this primitive.
|
|
11
|
+
// SP-1 (docs/superpowers/specs/2026-06-28-mustache-codegen-parity-design.md §2)
|
|
12
|
+
// moved past it — its goal is a consumer authoring "a working code generator, on ANY
|
|
13
|
+
// port, with NO generator code", and its worked outputPattern is
|
|
14
|
+
// "{package}/{name}Service.java". Source, not a document.
|
|
11
15
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
//
|
|
16
|
+
// The axis is NOT what kind of file comes out. It is: pick a template when the output
|
|
17
|
+
// SHAPE is what you are iterating on, or when you want the same output across
|
|
18
|
+
// languages (that is what the neutral data dict buys); pick a hand-coded generator
|
|
19
|
+
// when the logic is gnarly or the run is hot. Tradeoff table:
|
|
20
|
+
// docs/features/codegen-concepts.md §3.
|
|
21
|
+
//
|
|
22
|
+
// This matters most where a port has no choice: C# and Python expose closed built-in
|
|
23
|
+
// generator registries, so the declarative spec is the ONLY consumer authoring path
|
|
24
|
+
// there — and a documents-only reading of this primitive would tell those adopters
|
|
25
|
+
// their port cannot emit a custom shape at all.
|
|
26
|
+
//
|
|
27
|
+
// docsFile() is the first templateGenerator instance (rc.12), which is why the
|
|
28
|
+
// documents framing stuck; it is the first instance, not the boundary.
|
|
15
29
|
|
|
16
30
|
import type { MetaRoot, MetaObject } from "@metaobjectsdev/metadata";
|
|
17
31
|
import { render, type Provider, type RenderFormat } from "@metaobjectsdev/render";
|
package/src/index.ts
CHANGED
|
@@ -37,8 +37,16 @@ export {
|
|
|
37
37
|
} from "./generator-registry.js";
|
|
38
38
|
export type { GeneratorRegistryEntry, GeneratorTier } from "./generator-registry.js";
|
|
39
39
|
|
|
40
|
-
export type { MetaobjectsGenConfig, NormalizedMetaobjectsGenConfig, ResolvedGenConfig, Dialect, ExtStyle, ColumnNamingStrategy, MetaDataTypeProvider, GeneratorSpec, DocsConfig, ResolvedDocsConfig, DocsSurface, ApiSurface } from "./metaobjects-config.js";
|
|
40
|
+
export type { MetaobjectsGenConfig, NormalizedMetaobjectsGenConfig, ResolvedGenConfig, Dialect, ExtStyle, ColumnNamingStrategy, MetaDataTypeProvider, GeneratorSpec, DocsConfig, ResolvedDocsConfig, DocsSurface, ApiSurface, VerifyConfig } from "./metaobjects-config.js";
|
|
41
41
|
export { defineConfig, normalizeConfig, resolveGenerators, resolveDocsConfig } from "./metaobjects-config.js";
|
|
42
|
+
// The dialect every generator falls back to when a config declares none. Exported because
|
|
43
|
+
// `meta docs` must apply the SAME default `normalizeConfig` does — a command that resolved
|
|
44
|
+
// the dialect differently would document a schema the toolchain does not produce.
|
|
45
|
+
export { DEFAULT_DIALECT } from "./metaobjects-config.js";
|
|
46
|
+
// The runner's own "does this model need a dialect?" guard. `meta docs` must ask it rather
|
|
47
|
+
// than defaulting, because DEFAULT_DIALECT is inert and a DB project with no dialect is one
|
|
48
|
+
// `meta gen` REFUSES — documenting it as sqlite states an answer the toolchain never gave.
|
|
49
|
+
export { dbEmittingObjects, missingDialectMessage } from "./db-emitting.js";
|
|
42
50
|
export { apiLabel } from "./generators/api-label.js";
|
|
43
51
|
|
|
44
52
|
export type { ColumnSpec, DefaultExpr } from "./column-mapper.js";
|
|
@@ -70,7 +78,8 @@ export { decideAndWrite, GitMissingError } from "./overwrite-policy.js";
|
|
|
70
78
|
export { contentHash, readGeneratedHash, listGeneratedPaths } from "./overwrite-policy.js";
|
|
71
79
|
|
|
72
80
|
export { CodegenError } from "./errors.js";
|
|
73
|
-
export { GENERATED_HEADER,
|
|
81
|
+
export { GENERATED_HEADER, DEFAULT_OUT_DIR, RETIRED_CODEGEN_ATTRS, type RetiredCodegenAttr } from "./constants.js";
|
|
82
|
+
export { warnRetiredCodegenAttrs } from "./retired-codegen-attrs.js";
|
|
74
83
|
|
|
75
84
|
export { formatTs } from "./format.js";
|
|
76
85
|
|
|
@@ -90,14 +99,30 @@ export type { DocPageNode, DocPagePlacement } from "./docs-paths.js";
|
|
|
90
99
|
export { isProjection, isWriteThrough } from "./projection/projection-detector.js";
|
|
91
100
|
export { isAbstract, emitsInstanceArtifacts, emitsWriteArtifacts } from "./instance-artifacts.js";
|
|
92
101
|
// The UI tier asks THESE — "is there an endpoint?" — never the storage predicates.
|
|
93
|
-
export { servesReadApi, servesWriteApi } from "./api-surface.js";
|
|
102
|
+
export { hasGeneratedForm, restPath, servesReadApi, servesWriteApi } from "./api-surface.js";
|
|
103
|
+
// #356 — every emitter selects a field's view by the SURFACE it renders, never by
|
|
104
|
+
// declaration position. An owned generator (FR-040) composing the render layer must
|
|
105
|
+
// use this too, or it reinstates the order-dependence in its own copy.
|
|
106
|
+
export { viewForContext, VIEW_CONTEXT_FORM, VIEW_CONTEXT_GRID } from "./view-context.js";
|
|
107
|
+
// The shared per-field UI derivation. `valueObjectFor` is the predicate the React form
|
|
108
|
+
// generator and the `agent/ui.md` docs page must both ask — it decides whether a field is
|
|
109
|
+
// rendered as an input at all — and `humanize` is the one body behind every generated
|
|
110
|
+
// label. Both are exported so the react tier reads them rather than keeping a copy.
|
|
111
|
+
export { humanize, inferViewKind, labelFor, currencyMetaFor, valueObjectFor } from "./templates/field-meta.js";
|
|
94
112
|
// The DB-free descriptor module the UI tier imports from (see entity-meta-file.ts).
|
|
95
113
|
export { renderEntityMetaFile, entityMetaFileName, entityMetaSpecifier } from "./templates/entity-meta-file.js";
|
|
96
114
|
// FR-017 TPH helpers — used by the per-framework codegen packages (tanstack,
|
|
97
115
|
// react) to dispatch polymorphic/per-subtype emission and skip subtype files.
|
|
98
116
|
export { isTphDiscriminatorBase, tphConcreteSubtypes, collectTphSubtypeFields, tphPlan, tphRouteSegment } from "./templates/tph-discriminator.js";
|
|
99
117
|
export type { TphPlan, TphSubtypePlan } from "./templates/tph-discriminator.js";
|
|
100
|
-
export { isTphSubtype, tphDiscriminatorPin } from "./templates/zod-validators.js";
|
|
118
|
+
export { isTphSubtype, tphDiscriminatorBase, tphDiscriminatorPin } from "./templates/zod-validators.js";
|
|
119
|
+
|
|
120
|
+
// The ONE sortability rule. It builds the server-side `<Entity>SortAllowlist` and the
|
|
121
|
+
// client-side sort union, and it is public so a UI-tier generator (a data-grid column
|
|
122
|
+
// emitter, say) marks a column sortable by ASKING the server's rule rather than
|
|
123
|
+
// reimplementing its three branches out of tree. A hand-copied predicate is how the
|
|
124
|
+
// grid came to offer headers the allowlist rejects (#352/#354).
|
|
125
|
+
export { isSortableField, sortableFields } from "./templates/filter-shared.js";
|
|
101
126
|
|
|
102
127
|
// ADR-0034 reference-template composition helpers. Promoted to the public engine
|
|
103
128
|
// surface so a COPIED reference generator (src/reference/*.ts → consumer's
|
|
@@ -110,7 +135,7 @@ export { renderSharedEnumsFile, SHARED_ENUMS_BASENAME } from "./templates/enums-
|
|
|
110
135
|
|
|
111
136
|
// ADR-0034 scaffold-and-own — reader for the copyable reference generators in
|
|
112
137
|
// `src/reference/*.ts`. `meta init` uses this to copy them into the consumer's repo.
|
|
113
|
-
export { resolveReferenceRoot, readReferenceTemplate, REFERENCE_GENERATOR_NAMES } from "./reference-templates.js";
|
|
138
|
+
export { resolveReferenceRoot, readReferenceTemplate, REFERENCE_GENERATOR_NAMES, makeReferenceReader } from "./reference-templates.js";
|
|
114
139
|
export type { ReferenceGeneratorName } from "./reference-templates.js";
|
|
115
140
|
|
|
116
141
|
// ts-poet composition primitives, re-exported from THIS package's own ts-poet
|
|
@@ -160,8 +185,27 @@ export { renderFilterType } from "./templates/filter-type.js";
|
|
|
160
185
|
export { renderFilterAllowlist, renderSortAllowlist } from "./templates/filter-allowlist.js";
|
|
161
186
|
export { renderEntityConstants, resourcePath } from "./templates/entity-constants.js";
|
|
162
187
|
export { renderQueriesFile } from "./templates/queries-file.js";
|
|
188
|
+
// #348 — which CRUD verbs a generated routes file mounts. Public because an OWNED
|
|
189
|
+
// routes generator (ADR-0034) composes the same render call and needs the same option.
|
|
190
|
+
export { CRUD_VERBS, resolveExpose, intersectExpose, exposeLine } from "./routes-expose.js";
|
|
191
|
+
export type { CrudVerb, ExposeOption } from "./routes-expose.js";
|
|
163
192
|
export { renderRoutesFile } from "./templates/routes-file.js";
|
|
193
|
+
export { renderRoutesFileHono } from "./templates/routes-file-hono.js";
|
|
164
194
|
export { renderValueObjectFile } from "./templates/value-object-file.js";
|
|
195
|
+
export { renderNamesDecl } from "./templates/names-decl.js";
|
|
196
|
+
export type { NamesDeclOpts } from "./templates/names-decl.js";
|
|
197
|
+
export {
|
|
198
|
+
resolveObjectNames,
|
|
199
|
+
resolveSuperFragmentNames,
|
|
200
|
+
namesArtifactSuperOf,
|
|
201
|
+
namesRef,
|
|
202
|
+
namesConstArg,
|
|
203
|
+
physicalNameExpr,
|
|
204
|
+
columnExpr,
|
|
205
|
+
type ObjectNames,
|
|
206
|
+
type FieldNames,
|
|
207
|
+
type SuperNames,
|
|
208
|
+
} from "./names.js";
|
|
165
209
|
export { renderProjectionDecl } from "./templates/projection-decl.js";
|
|
166
210
|
export type { ProjectionDeclOpts } from "./templates/projection-decl.js";
|
|
167
211
|
export { extractViewSpec } from "./projection/extract-view-spec.js";
|
|
@@ -210,6 +254,16 @@ export { buildTemplateDocData } from "./generators/template-doc-builder.js";
|
|
|
210
254
|
// worse than the bug report this is meant to avoid.
|
|
211
255
|
export { requirementTests } from "./generators/requirement-tests.js";
|
|
212
256
|
export { requirementsFile } from "./generators/requirements-file.js";
|
|
257
|
+
// The `agent` docs surface. `AgentSchemaInput` is exported because the CLI SUPPLIES it —
|
|
258
|
+
// codegen-ts deliberately does not compute the physical schema (see agent-schema-input.ts).
|
|
259
|
+
export { agentDocsFile } from "./generators/agent-docs-file.js";
|
|
260
|
+
export type { AgentDocsFileOpts } from "./generators/agent-docs-file.js";
|
|
261
|
+
export type {
|
|
262
|
+
AgentSchemaInput,
|
|
263
|
+
SchemaColumnLike,
|
|
264
|
+
SchemaTableLike,
|
|
265
|
+
SchemaViewLike,
|
|
266
|
+
} from "./generators/agent-schema-input.js";
|
|
213
267
|
export type { RequirementRow } from "./generators/requirements-view.js";
|
|
214
268
|
// The projection itself, not just its type: it is the authority on WHICH doc slots a
|
|
215
269
|
// requirement surface actually renders, and `meta verify`'s authoring lint tells an
|
|
@@ -251,3 +305,7 @@ export type {
|
|
|
251
305
|
SweepOrphansArgs,
|
|
252
306
|
SweepOrphansResult,
|
|
253
307
|
} from "./orphan-sweep.js";
|
|
308
|
+
|
|
309
|
+
// FR-040 §6.4 — the client-component directive for generated CLIENT artifacts.
|
|
310
|
+
// Public so an OWNED generator applies it the same way the built-ins do.
|
|
311
|
+
export { withClientDirective, CLIENT_DIRECTIVE } from "./client-directive.js";
|
|
@@ -55,6 +55,14 @@ export interface ResolvedGenConfig {
|
|
|
55
55
|
* api-docs reads this to AUTO-DETECT whether to document the Hono CRUD surface
|
|
56
56
|
* (it otherwise mirrors the default Fastify-only suite). Undefined ⇒ false. */
|
|
57
57
|
includeHonoRoutes?: boolean;
|
|
58
|
+
/** §A6 — whether the OPT-IN names generator (namesFile) is active in the run,
|
|
59
|
+
* aggregated by the runner from the suite's `emitsNames` markers. A generator that
|
|
60
|
+
* wants to REFERENCE `<Entity>Names` reads this to know the artifact will exist:
|
|
61
|
+
* the names generator is opt-in under ADR-0034 scaffold-and-own, so an
|
|
62
|
+
* unconditional import would break every project that has not enabled it.
|
|
63
|
+
* Undefined ⇒ false. Templates read the same fact off `RenderContext.includeNames`,
|
|
64
|
+
* which the runner sets from this same aggregation. */
|
|
65
|
+
includeNames?: boolean;
|
|
58
66
|
/**
|
|
59
67
|
* FR-019 / ADR-0026: the module specifier from which an externally-PROVIDED
|
|
60
68
|
* shared enum (`@provided: true` on an abstract package-level `field.enum`) is
|
|
@@ -108,6 +116,34 @@ export interface MetaobjectsGenConfig extends Omit<ResolvedGenConfig, "dbImport"
|
|
|
108
116
|
* (e.g. `{ AuditLog: "auditLog", LlmTierConfig: "llmTierConfig" }`).
|
|
109
117
|
*/
|
|
110
118
|
collectionNameOverrides?: Record<string, string>;
|
|
119
|
+
/**
|
|
120
|
+
* Prepend a module-level client-component directive — `"use client";` — to every
|
|
121
|
+
* generated CLIENT artifact (forms, hooks, grid columns, grid hooks). Defaults to
|
|
122
|
+
* `false`. FR-040 §6.4.
|
|
123
|
+
*
|
|
124
|
+
* **Why this is config and not a metadata attribute.** It is a fact about the
|
|
125
|
+
* adopter's BUNDLER TOPOLOGY, not about the entity — the metamodel contains nothing
|
|
126
|
+
* that could derive it, and every non-TS port would carry a registration it can never
|
|
127
|
+
* dispatch on, which is the `source.rdb @role` mistake that retired four members in
|
|
128
|
+
* 0.21.0. It sits here beside `extStyle` and `columnNamingStrategy` for the same
|
|
129
|
+
* reason `pluralizeCollections` does: a per-port codegen concern (ADR-0001), so
|
|
130
|
+
* config, and no cross-port conformance cost.
|
|
131
|
+
*
|
|
132
|
+
* **Why it defaults to `false`.** The generated form and hook modules genuinely ARE
|
|
133
|
+
* client components, so the directive is a true statement about them — but it is only
|
|
134
|
+
* REQUIRED by frameworks that compile server and client from one tree (React Server
|
|
135
|
+
* Components). Elsewhere it is inert and provokes module-level-directive warnings in
|
|
136
|
+
* some bundlers, so defaulting it on would put noise in every generated UI file for
|
|
137
|
+
* the majority to save the minority one line. The asymmetry that would argue for
|
|
138
|
+
* defaulting on — a runtime error for RSC adopters versus a build warning for
|
|
139
|
+
* everyone else — is what FR-040 itself removed: before it, an RSC adopter had no
|
|
140
|
+
* seam at all; now it is this flag, or `meta eject form` and a one-line prepend.
|
|
141
|
+
*
|
|
142
|
+
* Flipping the default needs EVIDENCE, not a guess about majorities — the standard
|
|
143
|
+
* `extStyle` was held to in 0.20.1, where the default moved because the documented
|
|
144
|
+
* quickstart provably failed under a stock `tsc --init`.
|
|
145
|
+
*/
|
|
146
|
+
clientDirective?: boolean;
|
|
111
147
|
/**
|
|
112
148
|
* Drizzle timestamp column mode. "string" (default) types timestamp columns as
|
|
113
149
|
* ISO-8601 strings (matches the generated Zod + cross-port wire contract); "date"
|
|
@@ -143,6 +179,9 @@ export interface MetaobjectsGenConfig extends Omit<ResolvedGenConfig, "dbImport"
|
|
|
143
179
|
emitAbstractShapes?: boolean;
|
|
144
180
|
/** Docs-output config consumed by the `meta docs` door. See {@link DocsConfig}. */
|
|
145
181
|
docs?: DocsConfig;
|
|
182
|
+
/** `meta verify` / `meta gen` advisory settings. Nothing here affects codegen.
|
|
183
|
+
* See {@link VerifyConfig}. */
|
|
184
|
+
verify?: VerifyConfig;
|
|
146
185
|
/** Named output destinations. Generators reference one via `target`. */
|
|
147
186
|
targets?: Record<string, TargetConfig>;
|
|
148
187
|
/** importBase for the default target (top-level outDir). */
|
|
@@ -186,13 +225,14 @@ export interface NormalizedMetaobjectsGenConfig
|
|
|
186
225
|
pluralizeCollections: boolean;
|
|
187
226
|
collectionNameOverrides: Record<string, string>;
|
|
188
227
|
timestampMode: "date" | "string";
|
|
228
|
+
clientDirective: boolean;
|
|
189
229
|
apiPrefix: string;
|
|
190
230
|
emitAbstractShapes: boolean;
|
|
191
231
|
outputLayout: OutputLayout;
|
|
192
232
|
targets: Record<string, ResolvedTarget>;
|
|
193
233
|
}
|
|
194
234
|
|
|
195
|
-
export type DocsSurface = "model" | "api" | "requirements";
|
|
235
|
+
export type DocsSurface = "model" | "api" | "requirements" | "agent";
|
|
196
236
|
|
|
197
237
|
export interface ApiSurface {
|
|
198
238
|
lang: string;
|
|
@@ -203,6 +243,33 @@ export interface ApiSurface {
|
|
|
203
243
|
/** The single docs-output config: where ALL doc surfaces go, how pages are laid
|
|
204
244
|
* out, and which surfaces to emit. Read by the `meta docs` door (and, when the
|
|
205
245
|
* api surface fans out, by each port's docs command). */
|
|
246
|
+
/**
|
|
247
|
+
* `meta verify` settings. Nothing here changes what codegen emits.
|
|
248
|
+
*
|
|
249
|
+
* This block existed once before, for `verify.testFiles`, and was removed in 0.24.0 with
|
|
250
|
+
* the `@verifiedBy` vocabulary it served. It returns for exactly the reason it was added:
|
|
251
|
+
* the advisory scans carry a list of conventions that is, unavoidably, a guess about
|
|
252
|
+
* someone else's repository. Built-in defaults for the layouts that demonstrably exist,
|
|
253
|
+
* PLUS a project-declared list, is the shape that survives being wrong.
|
|
254
|
+
*/
|
|
255
|
+
export interface VerifyConfig {
|
|
256
|
+
/**
|
|
257
|
+
* Path globs the "you hand-rolled what MetaObjects models" advisory skips entirely.
|
|
258
|
+
* Relative to the project root, forward-slash, `**` spans separators; a glob matching a
|
|
259
|
+
* directory prunes the whole subtree. ADDS to the built-in exclusions rather than
|
|
260
|
+
* replacing them.
|
|
261
|
+
*
|
|
262
|
+
* verify: { antiPatternIgnore: ["db/changelog/**", "vendor/sql/**"] }
|
|
263
|
+
*
|
|
264
|
+
* Reach for this when the advisory reports a file you cannot act on — a vendored SQL
|
|
265
|
+
* archive, read-only reference DDL, a migration tool whose naming the built-ins do not
|
|
266
|
+
* recognise. It is deliberately narrower than `--no-antipatterns`: silencing the whole
|
|
267
|
+
* scan to quiet one directory is how a useful advisory gets switched off wholesale, the
|
|
268
|
+
* same failure `--no-requirement-lint` was carved out to avoid.
|
|
269
|
+
*/
|
|
270
|
+
antiPatternIgnore?: string[];
|
|
271
|
+
}
|
|
272
|
+
|
|
206
273
|
export interface DocsConfig {
|
|
207
274
|
outDir?: string;
|
|
208
275
|
layout?: OutputLayout;
|
|
@@ -235,7 +302,15 @@ export function resolveDocsConfig(
|
|
|
235
302
|
// files for a project declaring no `requirement.*` node — not an empty page. A
|
|
236
303
|
// project without a ledger sees byte-identical output to before the surface
|
|
237
304
|
// existed; see requirements-file.ts.
|
|
238
|
-
|
|
305
|
+
//
|
|
306
|
+
// `agent` defaults ON for the same reason and under the same discipline: each of
|
|
307
|
+
// its three pages renders "" when its tier has nothing to describe, and an empty
|
|
308
|
+
// render emits no file. It is additionally gated on a loadable gen config, exactly
|
|
309
|
+
// as `api` is — physical names, the dialect and view dispatch all come from there,
|
|
310
|
+
// so without one there is nothing true to say. Turning it on by default is what
|
|
311
|
+
// makes the always-on agent-context pointer able to name the files: a pointer to a
|
|
312
|
+
// page an adopter has to opt into is a pointer at nothing.
|
|
313
|
+
surfaces: cli.surfaces ?? block?.surfaces ?? ["model", "api", "requirements", "agent"],
|
|
239
314
|
apiSurfaces: cli.apiSurfaces ?? block?.apiSurfaces ?? [{ lang: "ts", subDir: "api" }],
|
|
240
315
|
};
|
|
241
316
|
}
|
|
@@ -322,6 +397,7 @@ export function normalizeConfig(config: MetaobjectsGenConfig): NormalizedMetaobj
|
|
|
322
397
|
// normalize to "string" on sqlite/D1 at this one choke point so the option
|
|
323
398
|
// can never silently emit a non-compiling column + a disagreeing Zod schema.
|
|
324
399
|
timestampMode: dialect === "sqlite" ? "string" : (config.timestampMode ?? "string"),
|
|
400
|
+
clientDirective: config.clientDirective ?? false,
|
|
325
401
|
apiPrefix: config.apiPrefix ?? "",
|
|
326
402
|
emitAbstractShapes: config.emitAbstractShapes ?? true,
|
|
327
403
|
outputLayout: config.outputLayout ?? "flat",
|