@metaobjectsdev/codegen-ts 1.0.0-rc.4 → 1.0.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/column-mapper.d.ts +12 -0
- package/dist/column-mapper.d.ts.map +1 -1
- package/dist/column-mapper.js +16 -0
- package/dist/column-mapper.js.map +1 -1
- package/dist/constants.d.ts +10 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +10 -0
- package/dist/constants.js.map +1 -1
- package/dist/generator-registry.d.ts.map +1 -1
- package/dist/generator-registry.js +1 -0
- package/dist/generator-registry.js.map +1 -1
- package/dist/generator.d.ts +15 -0
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js.map +1 -1
- package/dist/generators/agent-docs-file.d.ts.map +1 -1
- package/dist/generators/agent-docs-file.js +12 -3
- package/dist/generators/agent-docs-file.js.map +1 -1
- package/dist/generators/agent-schema-input.d.ts +11 -0
- package/dist/generators/agent-schema-input.d.ts.map +1 -1
- package/dist/generators/agent-schema-page.d.ts.map +1 -1
- package/dist/generators/agent-schema-page.js +13 -1
- package/dist/generators/agent-schema-page.js.map +1 -1
- package/dist/generators/agent-ui-page.d.ts.map +1 -1
- package/dist/generators/agent-ui-page.js +11 -9
- package/dist/generators/agent-ui-page.js.map +1 -1
- package/dist/generators/api-model.d.ts +2 -1
- package/dist/generators/api-model.d.ts.map +1 -1
- package/dist/generators/api-model.js +12 -6
- package/dist/generators/api-model.js.map +1 -1
- package/dist/generators/barrel.d.ts.map +1 -1
- package/dist/generators/barrel.js +2 -1
- package/dist/generators/barrel.js.map +1 -1
- package/dist/generators/callable-file.d.ts.map +1 -1
- package/dist/generators/callable-file.js +2 -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 +6 -5
- package/dist/generators/docs-data-builder.js.map +1 -1
- package/dist/generators/entity-file.d.ts.map +1 -1
- package/dist/generators/entity-file.js +2 -1
- package/dist/generators/entity-file.js.map +1 -1
- package/dist/generators/names-file.d.ts +22 -1
- package/dist/generators/names-file.d.ts.map +1 -1
- package/dist/generators/names-file.js +13 -18
- package/dist/generators/names-file.js.map +1 -1
- package/dist/generators/queries-file.d.ts.map +1 -1
- package/dist/generators/queries-file.js +2 -1
- package/dist/generators/queries-file.js.map +1 -1
- package/dist/generators/render-helper-file.js +1 -1
- package/dist/generators/render-helper-file.js.map +1 -1
- package/dist/generators/requirements-markdown.d.ts.map +1 -1
- package/dist/generators/requirements-markdown.js +26 -1
- package/dist/generators/requirements-markdown.js.map +1 -1
- package/dist/generators/routes-file-hono.d.ts.map +1 -1
- package/dist/generators/routes-file-hono.js +2 -1
- package/dist/generators/routes-file-hono.js.map +1 -1
- package/dist/generators/routes-file.d.ts.map +1 -1
- package/dist/generators/routes-file.js +2 -1
- package/dist/generators/routes-file.js.map +1 -1
- package/dist/index.d.ts +9 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -7
- package/dist/index.js.map +1 -1
- package/dist/metaobjects-config.d.ts +10 -0
- package/dist/metaobjects-config.d.ts.map +1 -1
- package/dist/metaobjects-config.js +14 -1
- package/dist/metaobjects-config.js.map +1 -1
- package/dist/names.d.ts.map +1 -1
- package/dist/names.js +5 -4
- package/dist/names.js.map +1 -1
- package/dist/overwrite-policy.d.ts +23 -9
- package/dist/overwrite-policy.d.ts.map +1 -1
- package/dist/overwrite-policy.js +48 -0
- package/dist/overwrite-policy.js.map +1 -1
- package/dist/runner.d.ts +24 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +143 -13
- package/dist/runner.js.map +1 -1
- package/dist/templates/callable-file.d.ts.map +1 -1
- package/dist/templates/callable-file.js +2 -1
- 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 +39 -14
- package/dist/templates/drizzle-schema.js.map +1 -1
- package/dist/templates/entity-file.d.ts.map +1 -1
- package/dist/templates/entity-file.js +4 -2
- package/dist/templates/entity-file.js.map +1 -1
- package/dist/templates/filter-allowlist.d.ts.map +1 -1
- package/dist/templates/filter-allowlist.js +10 -6
- package/dist/templates/filter-allowlist.js.map +1 -1
- package/dist/templates/filter-shared.d.ts +42 -1
- package/dist/templates/filter-shared.d.ts.map +1 -1
- package/dist/templates/filter-shared.js +68 -5
- package/dist/templates/filter-shared.js.map +1 -1
- package/dist/templates/inferred-types.d.ts.map +1 -1
- package/dist/templates/inferred-types.js +9 -6
- package/dist/templates/inferred-types.js.map +1 -1
- package/dist/templates/projection-decl.d.ts.map +1 -1
- package/dist/templates/projection-decl.js +4 -2
- 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 +6 -5
- package/dist/templates/queries-file.js.map +1 -1
- package/dist/templates/relations-block.d.ts.map +1 -1
- package/dist/templates/relations-block.js +2 -1
- package/dist/templates/relations-block.js.map +1 -1
- package/dist/templates/render-helper.d.ts +12 -1
- package/dist/templates/render-helper.d.ts.map +1 -1
- package/dist/templates/render-helper.js +30 -7
- package/dist/templates/render-helper.js.map +1 -1
- package/dist/templates/routes-file-hono.d.ts.map +1 -1
- package/dist/templates/routes-file-hono.js +2 -1
- package/dist/templates/routes-file-hono.js.map +1 -1
- package/dist/templates/routes-file.d.ts.map +1 -1
- package/dist/templates/routes-file.js +18 -10
- package/dist/templates/routes-file.js.map +1 -1
- package/dist/templates/zod-validators.d.ts.map +1 -1
- package/dist/templates/zod-validators.js +7 -4
- package/dist/templates/zod-validators.js.map +1 -1
- package/dist/ui-tier-gate.d.ts +44 -0
- package/dist/ui-tier-gate.d.ts.map +1 -0
- package/dist/ui-tier-gate.js +68 -0
- package/dist/ui-tier-gate.js.map +1 -0
- package/package.json +6 -6
- package/src/column-mapper.ts +17 -0
- package/src/constants.ts +11 -0
- package/src/generator-registry.ts +1 -0
- package/src/generator.ts +15 -0
- package/src/generators/agent-docs-file.ts +11 -2
- package/src/generators/agent-schema-input.ts +11 -0
- package/src/generators/agent-schema-page.ts +14 -1
- package/src/generators/agent-ui-page.ts +10 -10
- package/src/generators/api-model.ts +14 -7
- package/src/generators/barrel.ts +2 -1
- package/src/generators/callable-file.ts +2 -1
- package/src/generators/docs-data-builder.ts +6 -5
- package/src/generators/entity-file.ts +2 -1
- package/src/generators/names-file.ts +34 -4
- package/src/generators/queries-file.ts +2 -1
- package/src/generators/render-helper-file.ts +1 -1
- package/src/generators/requirements-markdown.ts +28 -1
- package/src/generators/routes-file-hono.ts +2 -1
- package/src/generators/routes-file.ts +2 -1
- package/src/index.ts +23 -7
- package/src/metaobjects-config.ts +20 -1
- package/src/names.ts +5 -4
- package/src/overwrite-policy.ts +62 -11
- package/src/reference/barrel.ts +2 -1
- package/src/reference/entity.ts +2 -2
- package/src/reference/names.ts +30 -4
- package/src/reference/queries.ts +3 -3
- package/src/reference/routes-hono.ts +2 -1
- package/src/reference/routes.ts +2 -1
- package/src/runner.ts +162 -12
- package/src/templates/callable-file.ts +2 -1
- package/src/templates/drizzle-schema.ts +43 -13
- package/src/templates/entity-file.ts +4 -2
- package/src/templates/filter-allowlist.ts +9 -6
- package/src/templates/filter-shared.ts +91 -6
- package/src/templates/inferred-types.ts +9 -6
- package/src/templates/projection-decl.ts +4 -2
- package/src/templates/queries-file.ts +6 -5
- package/src/templates/relations-block.ts +2 -1
- package/src/templates/render-helper.ts +31 -6
- package/src/templates/routes-file-hono.ts +2 -1
- package/src/templates/routes-file.ts +18 -10
- package/src/templates/zod-validators.ts +7 -4
- package/src/ui-tier-gate.ts +79 -0
|
@@ -26,6 +26,7 @@ import { GENERATED_HEADER } from "../constants.js";
|
|
|
26
26
|
import { isTphDiscriminatorBase, tphConcreteSubtypes } from "./tph-discriminator.js";
|
|
27
27
|
import { isProjection, isWriteThrough } from "../projection/projection-detector.js";
|
|
28
28
|
import { hasAutoSetFields } from "./zod-validators.js";
|
|
29
|
+
import { effectivePackage } from "../docs-paths.js";
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
32
|
* The dialect-correct Drizzle `Db` type alias + its import — parameter-passed into every
|
|
@@ -94,7 +95,7 @@ export function renderQueriesFile(obj: MetaObject, ctx: RenderContext): string {
|
|
|
94
95
|
const entityFileName = entityModuleSpecifier(
|
|
95
96
|
ctx.selfTarget,
|
|
96
97
|
ctx.entityModuleTarget,
|
|
97
|
-
obj
|
|
98
|
+
effectivePackage(obj),
|
|
98
99
|
entityName,
|
|
99
100
|
ctx.extStyle,
|
|
100
101
|
);
|
|
@@ -163,7 +164,7 @@ function renderProjectionQueriesFile(obj: MetaObject, ctx: RenderContext): strin
|
|
|
163
164
|
const camelName = entityName.charAt(0).toLowerCase() + entityName.slice(1);
|
|
164
165
|
const viewVar = `${camelName}View`;
|
|
165
166
|
const entityFileName = entityModuleSpecifier(
|
|
166
|
-
ctx.selfTarget, ctx.entityModuleTarget, obj
|
|
167
|
+
ctx.selfTarget, ctx.entityModuleTarget, effectivePackage(obj), entityName, ctx.extStyle,
|
|
167
168
|
);
|
|
168
169
|
const { fieldName: pkField, tsType: pkType } = getPkInfo(obj, ctx);
|
|
169
170
|
const eqSym = imp("eq@drizzle-orm");
|
|
@@ -215,7 +216,7 @@ function renderWriteThroughQueriesFile(obj: MetaObject, ctx: RenderContext): str
|
|
|
215
216
|
const tableVar = ctx.collectionName(entityName);
|
|
216
217
|
const singularVar = camelName;
|
|
217
218
|
const entityFileName = entityModuleSpecifier(
|
|
218
|
-
ctx.selfTarget, ctx.entityModuleTarget, obj
|
|
219
|
+
ctx.selfTarget, ctx.entityModuleTarget, effectivePackage(obj), entityName, ctx.extStyle,
|
|
219
220
|
);
|
|
220
221
|
const { fieldName: pkField, tsType: pkType } = getPkInfo(obj, ctx);
|
|
221
222
|
const pkFields = getPkFields(obj);
|
|
@@ -309,7 +310,7 @@ function renderTphQueriesFile(base: MetaObject, ctx: RenderContext): string {
|
|
|
309
310
|
const { fieldName: pkField, tsType: pkType } = getPkInfo(base, ctx);
|
|
310
311
|
|
|
311
312
|
const baseFileSpec = entityModuleSpecifier(
|
|
312
|
-
ctx.selfTarget, ctx.entityModuleTarget, base
|
|
313
|
+
ctx.selfTarget, ctx.entityModuleTarget, effectivePackage(base), baseName, ctx.extStyle,
|
|
313
314
|
);
|
|
314
315
|
const tableSym = imp(`${tableVar}@${baseFileSpec}`);
|
|
315
316
|
const baseTypeSym = imp(`t:${baseName}@${baseFileSpec}`);
|
|
@@ -342,7 +343,7 @@ export async function list${pluralize(baseName)}(db: Db, opts?: { limit?: number
|
|
|
342
343
|
const value = sub.ownAttr(OBJECT_ATTR_DISCRIMINATOR_VALUE) as string;
|
|
343
344
|
const valueLit = JSON.stringify(value);
|
|
344
345
|
const subFileSpec = entityModuleSpecifier(
|
|
345
|
-
ctx.selfTarget, ctx.entityModuleTarget, sub
|
|
346
|
+
ctx.selfTarget, ctx.entityModuleTarget, effectivePackage(sub), sub.name, ctx.extStyle,
|
|
346
347
|
);
|
|
347
348
|
const subTypeSym = imp(`t:${sub.name}@${subFileSpec}`);
|
|
348
349
|
const subSchemaSym = imp(`${sub.name}Schema@${subFileSpec}`);
|
|
@@ -7,6 +7,7 @@ import { CARDINALITY_ONE, CARDINALITY_MANY } from "@metaobjectsdev/metadata";
|
|
|
7
7
|
import { type RenderContext } from "../render-context.js";
|
|
8
8
|
import { crossEntitySpecifier } from "../import-path.js";
|
|
9
9
|
import type { RelationEntry } from "../relation-resolver.js";
|
|
10
|
+
import { effectivePackage } from "../docs-paths.js";
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Render the relations() block for one entity.
|
|
@@ -28,7 +29,7 @@ export function renderRelationsBlock(entity: MetaObject, ctx: RenderContext): Co
|
|
|
28
29
|
if (hasMany) paramParts.push("many");
|
|
29
30
|
const params = `{ ${paramParts.join(", ")} }`;
|
|
30
31
|
|
|
31
|
-
const thisEntityPackage = entity
|
|
32
|
+
const thisEntityPackage = effectivePackage(entity);
|
|
32
33
|
const lines: Code[] = entries.map((entry) =>
|
|
33
34
|
renderRelationEntry(entry, ctx, varName, thisEntityPackage),
|
|
34
35
|
);
|
|
@@ -53,6 +53,8 @@ import {
|
|
|
53
53
|
type VerifyError,
|
|
54
54
|
} from "@metaobjectsdev/render";
|
|
55
55
|
import { templateSymbolBase } from "../naming.js";
|
|
56
|
+
import { GENERATED_HEADER } from "../constants.js";
|
|
57
|
+
import type { ExtStyle } from "../metaobjects-config.js";
|
|
56
58
|
|
|
57
59
|
// ADR-0039: resolving — root has no super (children()==ownChildren()); a top-level object/template may itself extend, so resolve rather than work-by-accident.
|
|
58
60
|
// ADR-0042: package-local — resolveObjectRef binds a bare @objectRef in `referrerPkg` first (else root-level), an FQN exactly.
|
|
@@ -65,6 +67,20 @@ function findTemplate(root: MetaData, name: string): MetaData | undefined {
|
|
|
65
67
|
return root.children().find((c) => c.type === TYPE_TEMPLATE && c.name === name);
|
|
66
68
|
}
|
|
67
69
|
|
|
70
|
+
/**
|
|
71
|
+
* The three lines every emitted render-helper module opens with: the generated-file
|
|
72
|
+
* marker, the `render()` import, and the typed payload import. Identical between the
|
|
73
|
+
* email and document kinds below — only the `@metaobjectsdev/render` type import
|
|
74
|
+
* differs (email additionally needs `EmailDocument`), so that piece is a parameter
|
|
75
|
+
* rather than a second near-copy of this block.
|
|
76
|
+
*/
|
|
77
|
+
function renderHelperHeader(typeImports: string, payloadTypeName: string, ext: string): string {
|
|
78
|
+
return `// ${GENERATED_HEADER} — DO NOT EDIT.
|
|
79
|
+
import { render } from "@metaobjectsdev/render";
|
|
80
|
+
import type { ${typeImports} } from "@metaobjectsdev/render";
|
|
81
|
+
import type { ${payloadTypeName} } from "./${payloadTypeName}${ext}";`;
|
|
82
|
+
}
|
|
83
|
+
|
|
68
84
|
/**
|
|
69
85
|
* Walk an `object.value` view-object into a render `PayloadField[]`. Object-ref
|
|
70
86
|
* fields recurse into their referenced view-object; a `seen` set guards a
|
|
@@ -150,6 +166,16 @@ export function renderRenderHelper(
|
|
|
150
166
|
root: MetaData,
|
|
151
167
|
templateName: string,
|
|
152
168
|
provider: Provider,
|
|
169
|
+
/**
|
|
170
|
+
* The project's import-extension style, as every other emitter honours it.
|
|
171
|
+
* Defaults to "js" — the engine default — so an existing caller is unchanged.
|
|
172
|
+
*
|
|
173
|
+
* This file used to hardcode `.js` regardless. Both spellings happen to resolve
|
|
174
|
+
* under nodenext AND bundler, so nothing broke; it was simply the one emitter
|
|
175
|
+
* that did not read the setting, which is how a project with `extStyle: "none"`
|
|
176
|
+
* ended up with one file spelling its imports differently from every other.
|
|
177
|
+
*/
|
|
178
|
+
extStyle: ExtStyle = "js",
|
|
153
179
|
): string {
|
|
154
180
|
const tmpl = findTemplate(root, templateName);
|
|
155
181
|
if (!tmpl) {
|
|
@@ -186,6 +212,9 @@ export function renderRenderHelper(
|
|
|
186
212
|
// resolution above (findObject/derivePayloadFieldTree) intentionally keeps
|
|
187
213
|
// using the raw `payloadRef`.
|
|
188
214
|
const payloadTypeName = stripPackage(payloadRef);
|
|
215
|
+
// The emitted relative import's extension, from the project's setting rather than
|
|
216
|
+
// hardcoded — see the `extStyle` parameter doc.
|
|
217
|
+
const ext = extStyle === "none" ? "" : ".js";
|
|
189
218
|
|
|
190
219
|
// ADR-0039: resolving — a template may inherit its @* refs/format/kind via extends.
|
|
191
220
|
const kind = ((tmpl.attr(TEMPLATE_ATTR_KIND) as string | undefined) ?? TEMPLATE_KIND_DEFAULT)
|
|
@@ -215,9 +244,7 @@ export function renderRenderHelper(
|
|
|
215
244
|
? `\n textBody: render({ ref: ${JSON.stringify(textBodyRef)}, payload, format: "text", provider, verify: ${ft} }),`
|
|
216
245
|
: "";
|
|
217
246
|
|
|
218
|
-
return
|
|
219
|
-
import type { Provider, EmailDocument } from "@metaobjectsdev/render";
|
|
220
|
-
import type { ${payloadTypeName} } from "./${payloadTypeName}.js";
|
|
247
|
+
return `${renderHelperHeader("Provider, EmailDocument", payloadTypeName, ext)}
|
|
221
248
|
|
|
222
249
|
/**
|
|
223
250
|
* Render the ${templateName} email (subject + html body${typeof textBodyRef === "string" ? " + text body" : ""}) from a
|
|
@@ -255,9 +282,7 @@ export function ${fnName}(payload: ${payloadTypeName}, provider: Provider): Emai
|
|
|
255
282
|
const maxCharsArg =
|
|
256
283
|
maxChars !== undefined && Number.isFinite(maxChars) ? `, maxChars: ${maxChars}` : "";
|
|
257
284
|
|
|
258
|
-
return
|
|
259
|
-
import type { Provider } from "@metaobjectsdev/render";
|
|
260
|
-
import type { ${payloadTypeName} } from "./${payloadTypeName}.js";
|
|
285
|
+
return `${renderHelperHeader("Provider", payloadTypeName, ext)}
|
|
261
286
|
|
|
262
287
|
/**
|
|
263
288
|
* Render the ${templateName} document from a typed ${payloadTypeName} payload. Wraps the
|
|
@@ -31,6 +31,7 @@ import { entityModuleSpecifier } from "../import-path.js";
|
|
|
31
31
|
import { GENERATED_HEADER } from "../constants.js";
|
|
32
32
|
import { isProjection, isWriteThrough } from "../projection/projection-detector.js";
|
|
33
33
|
import { type CrudVerb, exposeLine } from "../routes-expose.js";
|
|
34
|
+
import { effectivePackage } from "../docs-paths.js";
|
|
34
35
|
|
|
35
36
|
export function renderRoutesFileHono(
|
|
36
37
|
entity: MetaObject,
|
|
@@ -49,7 +50,7 @@ export function renderRoutesFileHono(
|
|
|
49
50
|
const entityFileSpec = entityModuleSpecifier(
|
|
50
51
|
ctx.selfTarget,
|
|
51
52
|
ctx.entityModuleTarget,
|
|
52
|
-
entity
|
|
53
|
+
effectivePackage(entity),
|
|
53
54
|
entityName,
|
|
54
55
|
ctx.extStyle,
|
|
55
56
|
);
|
|
@@ -30,6 +30,7 @@ import { isProjection, isWriteThrough } from "../projection/projection-detector.
|
|
|
30
30
|
import type { RelationEntry } from "../relation-resolver.js";
|
|
31
31
|
import { isTphDiscriminatorBase, tphPlan } from "./tph-discriminator.js";
|
|
32
32
|
import { type CrudVerb, exposeLine, intersectExpose, TPH_POLYMORPHIC_VERBS } from "../routes-expose.js";
|
|
33
|
+
import { effectivePackage } from "../docs-paths.js";
|
|
33
34
|
|
|
34
35
|
export function renderRoutesFile(
|
|
35
36
|
entity: MetaObject,
|
|
@@ -49,16 +50,17 @@ export function renderRoutesFile(
|
|
|
49
50
|
|
|
50
51
|
const entityName = entity.name;
|
|
51
52
|
const handlerName = routesHandlerName(entityName);
|
|
53
|
+
const entityPkg = effectivePackage(entity);
|
|
52
54
|
// Import the entity's own file. Same target → relative "./Entity"; cross
|
|
53
55
|
// target → importBase-qualified package path.
|
|
54
56
|
const entityFileSpec = entityModuleSpecifier(
|
|
55
57
|
ctx.selfTarget,
|
|
56
58
|
ctx.entityModuleTarget,
|
|
57
|
-
|
|
59
|
+
entityPkg,
|
|
58
60
|
entityName,
|
|
59
61
|
ctx.extStyle,
|
|
60
62
|
);
|
|
61
|
-
const dbImportSpec = relativeModuleSpecifier(ctx.outputLayout,
|
|
63
|
+
const dbImportSpec = relativeModuleSpecifier(ctx.outputLayout, entityPkg, ctx.dbImport, ctx.extStyle);
|
|
62
64
|
|
|
63
65
|
const header =
|
|
64
66
|
`// ${GENERATED_HEADER} — DO NOT EDIT.\n` +
|
|
@@ -260,10 +262,15 @@ function renderM2mMount(
|
|
|
260
262
|
ctx: RenderContext,
|
|
261
263
|
fastifyVar: string,
|
|
262
264
|
): Code {
|
|
265
|
+
// `source` never changes across this function, so its effective package is computed
|
|
266
|
+
// once and reused below (both crossEntitySpecifier calls, and the three
|
|
267
|
+
// resolveJunctionColumn calls' `fromPackage` — see that comment for why it must be
|
|
268
|
+
// SOURCE's package rather than the junction/target entity's own).
|
|
269
|
+
const sourcePkg = effectivePackage(source);
|
|
263
270
|
const junctionVarSym = imp(
|
|
264
271
|
`${ctx.collectionName(entry.junctionEntity)}@${crossEntitySpecifier(
|
|
265
272
|
ctx.outputLayout,
|
|
266
|
-
|
|
273
|
+
sourcePkg,
|
|
267
274
|
ctx.packageOf.get(entry.junctionEntity),
|
|
268
275
|
entry.junctionEntity,
|
|
269
276
|
ctx.extStyle,
|
|
@@ -272,7 +279,7 @@ function renderM2mMount(
|
|
|
272
279
|
const targetVarSym = imp(
|
|
273
280
|
`${ctx.collectionName(entry.targetEntity)}@${crossEntitySpecifier(
|
|
274
281
|
ctx.outputLayout,
|
|
275
|
-
|
|
282
|
+
sourcePkg,
|
|
276
283
|
ctx.packageOf.get(entry.targetEntity),
|
|
277
284
|
entry.targetEntity,
|
|
278
285
|
ctx.extStyle,
|
|
@@ -284,13 +291,13 @@ function renderM2mMount(
|
|
|
284
291
|
// fromPackage = source.package: this routes file is SOURCE's own module, never the
|
|
285
292
|
// junction's or the target's — see resolveJunctionColumn's doc comment (B1).
|
|
286
293
|
const sourceColumn: Code = junction
|
|
287
|
-
? resolveJunctionColumn(junction, entry.sourceJoinField!, ctx,
|
|
294
|
+
? resolveJunctionColumn(junction, entry.sourceJoinField!, ctx, sourcePkg)
|
|
288
295
|
: code`${JSON.stringify(entry.sourceJoinField!)}`;
|
|
289
296
|
const targetColumn: Code = junction
|
|
290
|
-
? resolveJunctionColumn(junction, entry.targetJoinField!, ctx,
|
|
297
|
+
? resolveJunctionColumn(junction, entry.targetJoinField!, ctx, sourcePkg)
|
|
291
298
|
: code`${JSON.stringify(entry.targetJoinField!)}`;
|
|
292
299
|
const targetPkColumn: Code = target
|
|
293
|
-
? resolveJunctionColumn(target, ctx.pkMap.get(entry.targetEntity)?.fieldName ?? "id", ctx,
|
|
300
|
+
? resolveJunctionColumn(target, ctx.pkMap.get(entry.targetEntity)?.fieldName ?? "id", ctx, sourcePkg)
|
|
294
301
|
: code`${JSON.stringify("id")}`;
|
|
295
302
|
|
|
296
303
|
return code` ${mountM2mRouteSym}({
|
|
@@ -368,10 +375,11 @@ function renderTphRoutesFile(
|
|
|
368
375
|
const discField = plan.discriminatorField;
|
|
369
376
|
const tableVar = ctx.collectionName(baseName);
|
|
370
377
|
|
|
378
|
+
const basePkg = effectivePackage(base);
|
|
371
379
|
const baseFileSpec = entityModuleSpecifier(
|
|
372
|
-
ctx.selfTarget, ctx.entityModuleTarget,
|
|
380
|
+
ctx.selfTarget, ctx.entityModuleTarget, basePkg, baseName, ctx.extStyle,
|
|
373
381
|
);
|
|
374
|
-
const dbImportSpec = relativeModuleSpecifier(ctx.outputLayout,
|
|
382
|
+
const dbImportSpec = relativeModuleSpecifier(ctx.outputLayout, basePkg, ctx.dbImport, ctx.extStyle);
|
|
375
383
|
|
|
376
384
|
const FastifyInstanceSym = imp("t:FastifyInstance@fastify");
|
|
377
385
|
const mountCrudRoutesSym = imp("mountCrudRoutes@@metaobjectsdev/runtime-ts/drizzle-fastify");
|
|
@@ -405,7 +413,7 @@ function renderTphRoutesFile(
|
|
|
405
413
|
|
|
406
414
|
const subtypeMounts: Code[] = plan.subtypes.map(({ entity: sub, value, routeSegment: segment }) => {
|
|
407
415
|
const subFileSpec = entityModuleSpecifier(
|
|
408
|
-
ctx.selfTarget, ctx.entityModuleTarget, sub
|
|
416
|
+
ctx.selfTarget, ctx.entityModuleTarget, effectivePackage(sub), sub.name, ctx.extStyle,
|
|
409
417
|
);
|
|
410
418
|
const subInsertSym = imp(`${sub.name}InsertSchema@${subFileSpec}`);
|
|
411
419
|
// FR-036 Program B: the per-subtype UPDATE must carry the FR-035 present-key
|
|
@@ -42,6 +42,7 @@ import { valueObjectModuleSpecifier } from "../import-path.js";
|
|
|
42
42
|
// FR-035: the SAME required-predicate that drives the Drizzle column's .notNull()
|
|
43
43
|
// drives the UpdateSchema's .nullable() exclusion — shared so they cannot drift.
|
|
44
44
|
import { isRequired } from "../column-mapper.js";
|
|
45
|
+
import { effectivePackage } from "../docs-paths.js";
|
|
45
46
|
|
|
46
47
|
/**
|
|
47
48
|
* FR-017 Tier 1 — when this object is a TPH subtype (@discriminatorValue set
|
|
@@ -593,9 +594,10 @@ function zodFieldExpr(
|
|
|
593
594
|
// layout/package/extStyle-aware helper (the SAME one the field's TS type +
|
|
594
595
|
// Drizzle .$type<> use) so all three agree. Without owner/ctx (bare
|
|
595
596
|
// unit-test calls) fall back to the bare name + flat same-dir.
|
|
596
|
-
const
|
|
597
|
+
const ownerPkg = (ctx && owner) ? effectivePackage(owner) : undefined;
|
|
598
|
+
const refName = (ctx && owner) ? ctx.resolveValueObjectName(ref, fieldDeclaringPackage(field, ownerPkg)) : stripPackage(ref);
|
|
597
599
|
const moduleSpec = (ctx && owner)
|
|
598
|
-
? valueObjectModuleSpecifier(refName, ctx.packageOf,
|
|
600
|
+
? valueObjectModuleSpecifier(refName, ctx.packageOf, ownerPkg, ctx.outputLayout, ctx.extStyle)
|
|
599
601
|
: `./${refName}.js`;
|
|
600
602
|
const refImp = imp(`${refName}InsertSchema@${moduleSpec}`);
|
|
601
603
|
let base: Code = code`${refImp}`;
|
|
@@ -614,9 +616,10 @@ function zodFieldExpr(
|
|
|
614
616
|
if (field.subType === FIELD_SUBTYPE_MAP) {
|
|
615
617
|
const ref = field.attr(FIELD_ATTR_OBJECT_REF);
|
|
616
618
|
if (typeof ref === "string" && ref.length > 0) {
|
|
617
|
-
const
|
|
619
|
+
const ownerPkg = (ctx && owner) ? effectivePackage(owner) : undefined;
|
|
620
|
+
const refName = (ctx && owner) ? ctx.resolveValueObjectName(ref, fieldDeclaringPackage(field, ownerPkg)) : stripPackage(ref);
|
|
618
621
|
const moduleSpec = (ctx && owner)
|
|
619
|
-
? valueObjectModuleSpecifier(refName, ctx.packageOf,
|
|
622
|
+
? valueObjectModuleSpecifier(refName, ctx.packageOf, ownerPkg, ctx.outputLayout, ctx.extStyle)
|
|
620
623
|
: `./${refName}.js`;
|
|
621
624
|
const refImp = imp(`${refName}InsertSchema@${moduleSpec}`);
|
|
622
625
|
return appendValidatorChain(code`z.record(z.string(), ${refImp})`, field, forceRequired);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { Generator } from "./generator.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generators that emit a CLIENT UI artifact — a form, a hook, a grid or its columns.
|
|
5
|
+
*
|
|
6
|
+
* Names, not identities, for the same reason `PROMPT_GENERATOR_NAMES` uses names: under
|
|
7
|
+
* ADR-0034 scaffold-and-own an adopter runs their OWN copy, and `meta eject` copies the
|
|
8
|
+
* template verbatim, so the name survives the copy while the object identity does not.
|
|
9
|
+
*
|
|
10
|
+
* This set exists ONLY as a compatibility path for a copy ejected before `emitsUiTier`
|
|
11
|
+
* existed. The marker is the mechanism; a name match makes the run behave as it did
|
|
12
|
+
* before AND says the marker is missing (see {@link warnUnmarkedUiGenerators}), because
|
|
13
|
+
* a page silently disappearing is exactly the kind of degradation that must announce
|
|
14
|
+
* itself.
|
|
15
|
+
*/
|
|
16
|
+
export const UI_TIER_GENERATOR_NAMES: ReadonlySet<string> = new Set([
|
|
17
|
+
"form-file",
|
|
18
|
+
"tanstack-query",
|
|
19
|
+
"tanstack-grid",
|
|
20
|
+
"tanstack-grid-hook",
|
|
21
|
+
"angular-form",
|
|
22
|
+
"angular-grid",
|
|
23
|
+
"angular-service",
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
/** Generators in the suite that emit a UI artifact but carry no `emitsUiTier` marker. */
|
|
27
|
+
function unmarked(generators: readonly Generator[]): Generator[] {
|
|
28
|
+
return generators.filter(
|
|
29
|
+
(g) => g.emitsUiTier !== true && UI_TIER_GENERATOR_NAMES.has(g.name),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Does this run emit a client UI tier?
|
|
35
|
+
*
|
|
36
|
+
* The declared marker OR the legacy name. `agent/ui.md` gates on the answer: its own
|
|
37
|
+
* predicate was metadata-only (`servesReadApi`), which says a UI *could* be generated
|
|
38
|
+
* for an object and never that this run generates one — so a project with
|
|
39
|
+
* `generators: []` was handed a confident page naming endpoints nothing serves.
|
|
40
|
+
*/
|
|
41
|
+
export function runEmitsUiTier(generators: readonly Generator[]): boolean {
|
|
42
|
+
return generators.some((g) => g.emitsUiTier === true) || unmarked(generators).length > 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A generator ejected before `emitsUiTier` existed still emits its tier, so the run is
|
|
47
|
+
* NOT degraded — the name match above keeps `agent/ui.md` emitting. It is warned about
|
|
48
|
+
* anyway: an adopter who renames their copy loses the page with no signal at all, and
|
|
49
|
+
* the one-line fix belongs where the fact is known rather than in a migration note
|
|
50
|
+
* nobody re-reads. Self-extinguishing — adding the marker silences it forever.
|
|
51
|
+
*/
|
|
52
|
+
export function warnUnmarkedUiGenerators(
|
|
53
|
+
generators: readonly Generator[],
|
|
54
|
+
warn: (msg: string) => void,
|
|
55
|
+
): void {
|
|
56
|
+
const stale = unmarked(generators);
|
|
57
|
+
if (stale.length === 0) return;
|
|
58
|
+
const names = stale.map((g) => `'${g.name}'`).join(", ");
|
|
59
|
+
warn(
|
|
60
|
+
`${names} emit${stale.length === 1 ? "s" : ""} a UI artifact but carr${stale.length === 1 ? "ies" : "y"} no ` +
|
|
61
|
+
`'emitsUiTier: true' marker — an owned copy ejected before the marker existed. ` +
|
|
62
|
+
`agent/ui.md still emits (matched by name), but a renamed copy would not: add ` +
|
|
63
|
+
`'emitsUiTier: true' beside 'name:' in your copy, or re-eject it.`,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Does this run emit the OPT-IN Hono routes surface?
|
|
69
|
+
*
|
|
70
|
+
* Lives beside `runEmitsUiTier` for one reason: both are "aggregate a marker across the
|
|
71
|
+
* suite", and both were being re-derived at the `meta docs` door — which read the RAW
|
|
72
|
+
* config, where a generator wired by stable name (`generators: ["routes-hono"]`, legal
|
|
73
|
+
* under ADR-0021 #1) is a string carrying no marker at all. So `api-docs` omitted the
|
|
74
|
+
* Hono surface for a project that had wired it. One helper, called after the strings are
|
|
75
|
+
* resolved, is what stops the two doors disagreeing again.
|
|
76
|
+
*/
|
|
77
|
+
export function runEmitsHonoRoutes(generators: readonly Generator[]): boolean {
|
|
78
|
+
return generators.some((g) => g.emitsHonoRoutes === true);
|
|
79
|
+
}
|