@metaobjectsdev/codegen-ts 0.7.0-rc.8 → 0.7.0-rc.9

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.
@@ -1,6 +1,7 @@
1
1
  export { entityFile, type EntityFileOpts } from "./entity-file.js";
2
2
  export { queriesFile, type QueriesFileOpts } from "./queries-file.js";
3
3
  export { routesFile, type RoutesFileOpts } from "./routes-file.js";
4
+ export { routesFileHono, type RoutesFileHonoOpts } from "./routes-file-hono.js";
4
5
  export { barrel, type BarrelOpts } from "./barrel.js";
5
6
  export { mermaidErDiagram, type MermaidErOptions } from "./mermaid-er.js";
6
7
  export { promptRender, type PromptRenderOpts } from "./prompt-render-file.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,KAAK,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  export { entityFile } from "./entity-file.js";
2
2
  export { queriesFile } from "./queries-file.js";
3
3
  export { routesFile } from "./routes-file.js";
4
+ export { routesFileHono } from "./routes-file-hono.js";
4
5
  export { barrel } from "./barrel.js";
5
6
  export { mermaidErDiagram } from "./mermaid-er.js";
6
7
  export { promptRender } from "./prompt-render-file.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAuB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAwB,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAuB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAmB,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAyB,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAyB,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAyB,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/generators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAuB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,WAAW,EAAwB,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,UAAU,EAAuB,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,cAAc,EAA2B,MAAM,uBAAuB,CAAC;AAChF,OAAO,EAAE,MAAM,EAAmB,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAyB,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAyB,MAAM,yBAAyB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAAyB,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,21 @@
1
+ import type { MetaObject } from "@metaobjectsdev/metadata";
2
+ import { type GeneratorFactory } from "../generator.js";
3
+ export interface RoutesFileHonoOpts {
4
+ filter?: (entity: MetaObject) => boolean;
5
+ target?: string;
6
+ }
7
+ /**
8
+ * Hono variant of routesFile() — emits `<Entity>.routes.hono.ts` mounting
9
+ * the same five CRUD verbs (GET list / GET :id / POST / PATCH+PUT / DELETE)
10
+ * against `@metaobjectsdev/runtime-ts/hono` rather than `…/drizzle-fastify`.
11
+ *
12
+ * Same cross-port wire contract (envelope shape, status codes, filter +
13
+ * sort + withCount semantics) as the Fastify flavor. Workers / Bun / Node
14
+ * consumers running Hono can replace hand-written route registration with
15
+ * this generator output one entity at a time.
16
+ *
17
+ * Per-entity opt-out via `@emitRoutes: false` is honored. If the user
18
+ * supplies their own filter, both must pass (AND).
19
+ */
20
+ export declare const routesFileHono: GeneratorFactory<RoutesFileHonoOpts>;
21
+ //# sourceMappingURL=routes-file-hono.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-file-hono.d.ts","sourceRoot":"","sources":["../../src/generators/routes-file-hono.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAKnF,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,cAAc,EAuBtB,gBAAgB,CAAC,kBAAkB,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { perEntity } from "../generator.js";
2
+ import { renderRoutesFileHono } from "../templates/routes-file-hono.js";
3
+ import { formatTs } from "../format.js";
4
+ import { entityOutputPath } from "../import-path.js";
5
+ /**
6
+ * Hono variant of routesFile() — emits `<Entity>.routes.hono.ts` mounting
7
+ * the same five CRUD verbs (GET list / GET :id / POST / PATCH+PUT / DELETE)
8
+ * against `@metaobjectsdev/runtime-ts/hono` rather than `…/drizzle-fastify`.
9
+ *
10
+ * Same cross-port wire contract (envelope shape, status codes, filter +
11
+ * sort + withCount semantics) as the Fastify flavor. Workers / Bun / Node
12
+ * consumers running Hono can replace hand-written route registration with
13
+ * this generator output one entity at a time.
14
+ *
15
+ * Per-entity opt-out via `@emitRoutes: false` is honored. If the user
16
+ * supplies their own filter, both must pass (AND).
17
+ */
18
+ export const routesFileHono = function routesFileHono(opts) {
19
+ const userFilter = opts?.filter ?? (() => true);
20
+ const generator = {
21
+ name: "routes-file-hono",
22
+ filter: (e) => e.ownAttr("emitRoutes") !== false && userFilter(e),
23
+ generate: perEntity(async (entity, ctx) => {
24
+ if (!ctx.renderContext) {
25
+ throw new Error("routes-file-hono: renderContext is required (provided by runGen)");
26
+ }
27
+ return {
28
+ path: entityOutputPath(ctx.config.outputLayout ?? "flat", entity.package, `${entity.name}.routes.hono.ts`),
29
+ content: await formatTs(renderRoutesFileHono(entity, ctx.renderContext)),
30
+ };
31
+ }),
32
+ };
33
+ if (opts?.target) {
34
+ generator.target = opts.target;
35
+ }
36
+ return generator;
37
+ };
38
+ //# sourceMappingURL=routes-file-hono.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-file-hono.js","sourceRoot":"","sources":["../../src/generators/routes-file-hono.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAyC,MAAM,iBAAiB,CAAC;AACnF,OAAO,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AACxE,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAOrD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,cAAc,CAAC,IAAyB;IAC7E,MAAM,UAAU,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,SAAS,GAAc;QAC3B,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,CAAC,CAAa,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,KAAK,KAAK,IAAI,UAAU,CAAC,CAAC,CAAC;QAC7E,QAAQ,EAAE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE;YACxC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;YACtF,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,gBAAgB,CACpB,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,MAAM,EACjC,MAAM,CAAC,OAAO,EACd,GAAG,MAAM,CAAC,IAAI,iBAAiB,CAChC;gBACD,OAAO,EAAE,MAAM,QAAQ,CAAC,oBAAoB,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,CAAC;aACzE,CAAC;QACJ,CAAC,CAAC;KACH,CAAC;IACF,IAAI,IAAI,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IACjC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAyC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { MetaObject } from "@metaobjectsdev/metadata";
2
+ import { type RenderContext } from "../render-context.js";
3
+ export declare function renderRoutesFileHono(entity: MetaObject, ctx: RenderContext): string;
4
+ //# sourceMappingURL=routes-file-hono.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-file-hono.d.ts","sourceRoot":"","sources":["../../src/templates/routes-file-hono.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAM1D,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CA2GnF"}
@@ -0,0 +1,119 @@
1
+ // Hono route template — emits a per-entity routes file that delegates
2
+ // CRUD verbs to helpers from @metaobjectsdev/runtime-ts/hono.
3
+ //
4
+ // Hono parallel of templates/routes-file.ts. Two emit-shape differences
5
+ // vs the Fastify flavor, both reflecting Hono idioms rather than contract
6
+ // drift:
7
+ //
8
+ // 1) Exported function shape — `registerXxxRoutes(app, deps)` instead of
9
+ // `xxxRoutes(fastify)`. Workers/Bun consumers typically pass `db`
10
+ // through a per-request deps object (so a Worker can attach the
11
+ // D1 client pulled off bindings) rather than reaching for a
12
+ // module-level singleton. The Fastify flavor uses `import { db }`
13
+ // because Fastify apps are long-lived Node processes where a
14
+ // singleton is the norm. Both flavors talk to mountCrudRoutes /
15
+ // mountReadOnlyCrudRoutes with identical wire behavior.
16
+ //
17
+ // 2) apiPrefix is composed into the resource path (`${apiPrefix}${path}`)
18
+ // rather than wrapping the registration. Hono has no fastify.register
19
+ // / prefix-wrapping primitive; sub-apps via `app.route(prefix, sub)`
20
+ // exist but bloat the generated code. String concat is simpler and
21
+ // produces identical URL grammar.
22
+ //
23
+ // Dispatch logic mirrors Fastify:
24
+ // isProjection(entity) → mountReadOnlyCrudRoutes (GET list + GET :id)
25
+ // vanilla / write-through entity → mountCrudRoutes (all 5 CRUD verbs)
26
+ import { code, imp } from "ts-poet";
27
+ import {} from "../render-context.js";
28
+ import { entityModuleSpecifier } from "../import-path.js";
29
+ import { GENERATED_HEADER } from "../constants.js";
30
+ import { variableNameFromEntity } from "../naming.js";
31
+ import { isProjection } from "../projection/projection-detector.js";
32
+ export function renderRoutesFileHono(entity, ctx) {
33
+ const entityName = entity.name;
34
+ const handlerName = `register${entityName}Routes`;
35
+ const entityFileSpec = entityModuleSpecifier(ctx.selfTarget, ctx.entityModuleTarget, entity.package, entityName, ctx.extStyle);
36
+ const header = `// ${GENERATED_HEADER} — DO NOT EDIT.\n` +
37
+ `// Source metadata: ${entityName} (${entity.fqn()})\n` +
38
+ `// Customize via ${entityName}.extra.ts in this directory (e.g., auth, additional handlers).\n`;
39
+ // Path composition: apiPrefix is a literal string in the URL.
40
+ const pathExpr = ctx.apiPrefix
41
+ ? `\`${ctx.apiPrefix}\${${entityName}.$path}\``
42
+ : `${entityName}.$path`;
43
+ // --- Projection path: read-only routes (GET list + GET :id) ---
44
+ if (isProjection(entity)) {
45
+ const camelName = entityName.charAt(0).toLowerCase() + entityName.slice(1);
46
+ const HonoSym = imp("t:Hono@hono");
47
+ const mountReadOnlyCrudRoutesSym = imp("mountReadOnlyCrudRoutes@@metaobjectsdev/runtime-ts/hono");
48
+ const literalImports = code `
49
+ import {
50
+ ${entityName},
51
+ ${camelName}View,
52
+ ${entityName}FilterAllowlist,
53
+ ${entityName}SortAllowlist,
54
+ } from ${JSON.stringify(entityFileSpec)};
55
+ `;
56
+ const body = code `
57
+ /**
58
+ * Mount read-only REST endpoints for ${entityName} (projection — view-backed, no writes).
59
+ *
60
+ * Exposes GET list + GET :id only. POST/PATCH/DELETE return 405.
61
+ * Customize: register this as-is, or import individual route helpers from
62
+ * @metaobjectsdev/runtime-ts/hono.
63
+ */
64
+ // biome-ignore lint/suspicious/noExplicitAny: consumer-defined Hono bindings/variables
65
+ export function ${handlerName}(app: ${HonoSym}<any, any, any>, deps: { db: unknown }): void {
66
+ ${mountReadOnlyCrudRoutesSym}({
67
+ app,
68
+ path: ${pathExpr},
69
+ db: deps.db,
70
+ view: ${camelName}View,
71
+ filterAllowlist: ${entityName}FilterAllowlist,
72
+ sortAllowlist: ${entityName}SortAllowlist,
73
+ dialect: ${JSON.stringify(ctx.dialect)},
74
+ });
75
+ }
76
+ `;
77
+ return header + literalImports.toString() + body.toString();
78
+ }
79
+ // --- Vanilla / write-through entity path: full CRUD routes ---
80
+ const tableVar = variableNameFromEntity(entityName);
81
+ const HonoSym = imp("t:Hono@hono");
82
+ const mountCrudRoutesSym = imp("mountCrudRoutes@@metaobjectsdev/runtime-ts/hono");
83
+ const literalImports = code `
84
+ import {
85
+ ${entityName},
86
+ ${tableVar},
87
+ ${entityName}InsertSchema,
88
+ ${entityName}UpdateSchema,
89
+ ${entityName}FilterAllowlist,
90
+ ${entityName}SortAllowlist,
91
+ } from ${JSON.stringify(entityFileSpec)};
92
+ `;
93
+ const body = code `
94
+ /**
95
+ * Mount the 5 standard REST endpoints for ${entityName} using Drizzle directly.
96
+ *
97
+ * Customize: register this as-is for stock CRUD, OR import the per-verb
98
+ * helpers (mountListRoute, mountGetRoute, ...) from
99
+ * @metaobjectsdev/runtime-ts/hono and mix with your own handlers
100
+ * (auth, side effects, etc.).
101
+ */
102
+ // biome-ignore lint/suspicious/noExplicitAny: consumer-defined Hono bindings/variables
103
+ export function ${handlerName}(app: ${HonoSym}<any, any, any>, deps: { db: unknown }): void {
104
+ ${mountCrudRoutesSym}({
105
+ app,
106
+ path: ${pathExpr},
107
+ db: deps.db,
108
+ table: ${tableVar},
109
+ insertSchema: ${entityName}InsertSchema,
110
+ updateSchema: ${entityName}UpdateSchema,
111
+ filterAllowlist: ${entityName}FilterAllowlist,
112
+ sortAllowlist: ${entityName}SortAllowlist,
113
+ dialect: ${JSON.stringify(ctx.dialect)},
114
+ });
115
+ }
116
+ `;
117
+ return header + literalImports.toString() + body.toString();
118
+ }
119
+ //# sourceMappingURL=routes-file-hono.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes-file-hono.js","sourceRoot":"","sources":["../../src/templates/routes-file-hono.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,8DAA8D;AAC9D,EAAE;AACF,wEAAwE;AACxE,0EAA0E;AAC1E,SAAS;AACT,EAAE;AACF,2EAA2E;AAC3E,uEAAuE;AACvE,qEAAqE;AACrE,iEAAiE;AACjE,uEAAuE;AACvE,kEAAkE;AAClE,qEAAqE;AACrE,6DAA6D;AAC7D,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAC3E,0EAA0E;AAC1E,wEAAwE;AACxE,uCAAuC;AACvC,EAAE;AACF,kCAAkC;AAClC,qFAAqF;AACrF,2EAA2E;AAE3E,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAEpC,OAAO,EAAsB,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAEpE,MAAM,UAAU,oBAAoB,CAAC,MAAkB,EAAE,GAAkB;IACzE,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAC/B,MAAM,WAAW,GAAG,WAAW,UAAU,QAAQ,CAAC;IAElD,MAAM,cAAc,GAAG,qBAAqB,CAC1C,GAAG,CAAC,UAAU,EACd,GAAG,CAAC,kBAAkB,EACtB,MAAM,CAAC,OAAO,EACd,UAAU,EACV,GAAG,CAAC,QAAQ,CACb,CAAC;IAEF,MAAM,MAAM,GACV,MAAM,gBAAgB,mBAAmB;QACzC,uBAAuB,UAAU,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK;QACvD,oBAAoB,UAAU,kEAAkE,CAAC;IAEnG,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,GAAG,CAAC,SAAS;QAC5B,CAAC,CAAC,KAAK,GAAG,CAAC,SAAS,MAAM,UAAU,WAAW;QAC/C,CAAC,CAAC,GAAG,UAAU,QAAQ,CAAC;IAE1B,iEAAiE;IACjE,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAC3E,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC;QACnC,MAAM,0BAA0B,GAAG,GAAG,CACpC,yDAAyD,CAC1D,CAAC;QAEF,MAAM,cAAc,GAAG,IAAI,CAAA;;IAE3B,UAAU;IACV,SAAS;IACT,UAAU;IACV,UAAU;SACL,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;CACtC,CAAC;QAEE,MAAM,IAAI,GAAG,IAAI,CAAA;;wCAEmB,UAAU;;;;;;;kBAOhC,WAAW,SAAS,OAAO;IACzC,0BAA0B;;YAElB,QAAQ;;YAER,SAAS;uBACE,UAAU;qBACZ,UAAU;eAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;;;CAGzC,CAAC;QAEE,OAAO,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;IAC9D,CAAC;IAED,gEAAgE;IAChE,MAAM,QAAQ,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAEpD,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC;IACnC,MAAM,kBAAkB,GAAG,GAAG,CAAC,iDAAiD,CAAC,CAAC;IAElF,MAAM,cAAc,GAAG,IAAI,CAAA;;IAEzB,UAAU;IACV,QAAQ;IACR,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;SACL,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC;CACtC,CAAC;IAEA,MAAM,IAAI,GAAG,IAAI,CAAA;;6CAE0B,UAAU;;;;;;;;kBAQrC,WAAW,SAAS,OAAO;IACzC,kBAAkB;;YAEV,QAAQ;;aAEP,QAAQ;oBACD,UAAU;oBACV,UAAU;uBACP,UAAU;qBACZ,UAAU;eAChB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC;;;CAGzC,CAAC;IAEA,OAAO,MAAM,GAAG,cAAc,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;AAC9D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaobjectsdev/codegen-ts",
3
- "version": "0.7.0-rc.8",
3
+ "version": "0.7.0-rc.9",
4
4
  "description": "TypeScript codegen engine for MetaObjects — emits Drizzle, Zod, and Fastify artifacts.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -38,7 +38,7 @@
38
38
  "access": "public"
39
39
  },
40
40
  "dependencies": {
41
- "@metaobjectsdev/metadata": "0.7.0-rc.8",
41
+ "@metaobjectsdev/metadata": "0.7.0-rc.9",
42
42
  "@biomejs/js-api": "^0.7.0",
43
43
  "@biomejs/wasm-nodejs": "^1.9.4",
44
44
  "ts-poet": "^6.10.0"
@@ -49,10 +49,11 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@biomejs/biome": "^1.9.0",
52
- "@metaobjectsdev/codegen-ts-react": "0.7.0-rc.8",
53
- "@metaobjectsdev/render": "0.7.0-rc.8",
52
+ "@metaobjectsdev/codegen-ts-react": "0.7.0-rc.9",
53
+ "@metaobjectsdev/render": "0.7.0-rc.9",
54
54
  "bun-types": "latest",
55
55
  "drizzle-orm": "^0.36.0",
56
+ "hono": "^4.6.0",
56
57
  "typescript": "^5.6.0",
57
58
  "zod": "^3.23.0"
58
59
  }
@@ -1,6 +1,7 @@
1
1
  export { entityFile, type EntityFileOpts } from "./entity-file.js";
2
2
  export { queriesFile, type QueriesFileOpts } from "./queries-file.js";
3
3
  export { routesFile, type RoutesFileOpts } from "./routes-file.js";
4
+ export { routesFileHono, type RoutesFileHonoOpts } from "./routes-file-hono.js";
4
5
  export { barrel, type BarrelOpts } from "./barrel.js";
5
6
  export { mermaidErDiagram, type MermaidErOptions } from "./mermaid-er.js";
6
7
  export { promptRender, type PromptRenderOpts } from "./prompt-render-file.js";
@@ -0,0 +1,48 @@
1
+ import type { MetaObject } from "@metaobjectsdev/metadata";
2
+ import { perEntity, type Generator, type GeneratorFactory } from "../generator.js";
3
+ import { renderRoutesFileHono } from "../templates/routes-file-hono.js";
4
+ import { formatTs } from "../format.js";
5
+ import { entityOutputPath } from "../import-path.js";
6
+
7
+ export interface RoutesFileHonoOpts {
8
+ filter?: (entity: MetaObject) => boolean;
9
+ target?: string;
10
+ }
11
+
12
+ /**
13
+ * Hono variant of routesFile() — emits `<Entity>.routes.hono.ts` mounting
14
+ * the same five CRUD verbs (GET list / GET :id / POST / PATCH+PUT / DELETE)
15
+ * against `@metaobjectsdev/runtime-ts/hono` rather than `…/drizzle-fastify`.
16
+ *
17
+ * Same cross-port wire contract (envelope shape, status codes, filter +
18
+ * sort + withCount semantics) as the Fastify flavor. Workers / Bun / Node
19
+ * consumers running Hono can replace hand-written route registration with
20
+ * this generator output one entity at a time.
21
+ *
22
+ * Per-entity opt-out via `@emitRoutes: false` is honored. If the user
23
+ * supplies their own filter, both must pass (AND).
24
+ */
25
+ export const routesFileHono = function routesFileHono(opts?: RoutesFileHonoOpts): Generator {
26
+ const userFilter = opts?.filter ?? (() => true);
27
+ const generator: Generator = {
28
+ name: "routes-file-hono",
29
+ filter: (e: MetaObject) => e.ownAttr("emitRoutes") !== false && userFilter(e),
30
+ generate: perEntity(async (entity, ctx) => {
31
+ if (!ctx.renderContext) {
32
+ throw new Error("routes-file-hono: renderContext is required (provided by runGen)");
33
+ }
34
+ return {
35
+ path: entityOutputPath(
36
+ ctx.config.outputLayout ?? "flat",
37
+ entity.package,
38
+ `${entity.name}.routes.hono.ts`,
39
+ ),
40
+ content: await formatTs(renderRoutesFileHono(entity, ctx.renderContext)),
41
+ };
42
+ }),
43
+ };
44
+ if (opts?.target) {
45
+ generator.target = opts.target;
46
+ }
47
+ return generator;
48
+ } as GeneratorFactory<RoutesFileHonoOpts>;
@@ -0,0 +1,142 @@
1
+ // Hono route template — emits a per-entity routes file that delegates
2
+ // CRUD verbs to helpers from @metaobjectsdev/runtime-ts/hono.
3
+ //
4
+ // Hono parallel of templates/routes-file.ts. Two emit-shape differences
5
+ // vs the Fastify flavor, both reflecting Hono idioms rather than contract
6
+ // drift:
7
+ //
8
+ // 1) Exported function shape — `registerXxxRoutes(app, deps)` instead of
9
+ // `xxxRoutes(fastify)`. Workers/Bun consumers typically pass `db`
10
+ // through a per-request deps object (so a Worker can attach the
11
+ // D1 client pulled off bindings) rather than reaching for a
12
+ // module-level singleton. The Fastify flavor uses `import { db }`
13
+ // because Fastify apps are long-lived Node processes where a
14
+ // singleton is the norm. Both flavors talk to mountCrudRoutes /
15
+ // mountReadOnlyCrudRoutes with identical wire behavior.
16
+ //
17
+ // 2) apiPrefix is composed into the resource path (`${apiPrefix}${path}`)
18
+ // rather than wrapping the registration. Hono has no fastify.register
19
+ // / prefix-wrapping primitive; sub-apps via `app.route(prefix, sub)`
20
+ // exist but bloat the generated code. String concat is simpler and
21
+ // produces identical URL grammar.
22
+ //
23
+ // Dispatch logic mirrors Fastify:
24
+ // isProjection(entity) → mountReadOnlyCrudRoutes (GET list + GET :id)
25
+ // vanilla / write-through entity → mountCrudRoutes (all 5 CRUD verbs)
26
+
27
+ import { code, imp } from "ts-poet";
28
+ import type { MetaObject } from "@metaobjectsdev/metadata";
29
+ import { type RenderContext } from "../render-context.js";
30
+ import { entityModuleSpecifier } from "../import-path.js";
31
+ import { GENERATED_HEADER } from "../constants.js";
32
+ import { variableNameFromEntity } from "../naming.js";
33
+ import { isProjection } from "../projection/projection-detector.js";
34
+
35
+ export function renderRoutesFileHono(entity: MetaObject, ctx: RenderContext): string {
36
+ const entityName = entity.name;
37
+ const handlerName = `register${entityName}Routes`;
38
+
39
+ const entityFileSpec = entityModuleSpecifier(
40
+ ctx.selfTarget,
41
+ ctx.entityModuleTarget,
42
+ entity.package,
43
+ entityName,
44
+ ctx.extStyle,
45
+ );
46
+
47
+ const header =
48
+ `// ${GENERATED_HEADER} — DO NOT EDIT.\n` +
49
+ `// Source metadata: ${entityName} (${entity.fqn()})\n` +
50
+ `// Customize via ${entityName}.extra.ts in this directory (e.g., auth, additional handlers).\n`;
51
+
52
+ // Path composition: apiPrefix is a literal string in the URL.
53
+ const pathExpr = ctx.apiPrefix
54
+ ? `\`${ctx.apiPrefix}\${${entityName}.$path}\``
55
+ : `${entityName}.$path`;
56
+
57
+ // --- Projection path: read-only routes (GET list + GET :id) ---
58
+ if (isProjection(entity)) {
59
+ const camelName = entityName.charAt(0).toLowerCase() + entityName.slice(1);
60
+ const HonoSym = imp("t:Hono@hono");
61
+ const mountReadOnlyCrudRoutesSym = imp(
62
+ "mountReadOnlyCrudRoutes@@metaobjectsdev/runtime-ts/hono",
63
+ );
64
+
65
+ const literalImports = code`
66
+ import {
67
+ ${entityName},
68
+ ${camelName}View,
69
+ ${entityName}FilterAllowlist,
70
+ ${entityName}SortAllowlist,
71
+ } from ${JSON.stringify(entityFileSpec)};
72
+ `;
73
+
74
+ const body = code`
75
+ /**
76
+ * Mount read-only REST endpoints for ${entityName} (projection — view-backed, no writes).
77
+ *
78
+ * Exposes GET list + GET :id only. POST/PATCH/DELETE return 405.
79
+ * Customize: register this as-is, or import individual route helpers from
80
+ * @metaobjectsdev/runtime-ts/hono.
81
+ */
82
+ // biome-ignore lint/suspicious/noExplicitAny: consumer-defined Hono bindings/variables
83
+ export function ${handlerName}(app: ${HonoSym}<any, any, any>, deps: { db: unknown }): void {
84
+ ${mountReadOnlyCrudRoutesSym}({
85
+ app,
86
+ path: ${pathExpr},
87
+ db: deps.db,
88
+ view: ${camelName}View,
89
+ filterAllowlist: ${entityName}FilterAllowlist,
90
+ sortAllowlist: ${entityName}SortAllowlist,
91
+ dialect: ${JSON.stringify(ctx.dialect)},
92
+ });
93
+ }
94
+ `;
95
+
96
+ return header + literalImports.toString() + body.toString();
97
+ }
98
+
99
+ // --- Vanilla / write-through entity path: full CRUD routes ---
100
+ const tableVar = variableNameFromEntity(entityName);
101
+
102
+ const HonoSym = imp("t:Hono@hono");
103
+ const mountCrudRoutesSym = imp("mountCrudRoutes@@metaobjectsdev/runtime-ts/hono");
104
+
105
+ const literalImports = code`
106
+ import {
107
+ ${entityName},
108
+ ${tableVar},
109
+ ${entityName}InsertSchema,
110
+ ${entityName}UpdateSchema,
111
+ ${entityName}FilterAllowlist,
112
+ ${entityName}SortAllowlist,
113
+ } from ${JSON.stringify(entityFileSpec)};
114
+ `;
115
+
116
+ const body = code`
117
+ /**
118
+ * Mount the 5 standard REST endpoints for ${entityName} using Drizzle directly.
119
+ *
120
+ * Customize: register this as-is for stock CRUD, OR import the per-verb
121
+ * helpers (mountListRoute, mountGetRoute, ...) from
122
+ * @metaobjectsdev/runtime-ts/hono and mix with your own handlers
123
+ * (auth, side effects, etc.).
124
+ */
125
+ // biome-ignore lint/suspicious/noExplicitAny: consumer-defined Hono bindings/variables
126
+ export function ${handlerName}(app: ${HonoSym}<any, any, any>, deps: { db: unknown }): void {
127
+ ${mountCrudRoutesSym}({
128
+ app,
129
+ path: ${pathExpr},
130
+ db: deps.db,
131
+ table: ${tableVar},
132
+ insertSchema: ${entityName}InsertSchema,
133
+ updateSchema: ${entityName}UpdateSchema,
134
+ filterAllowlist: ${entityName}FilterAllowlist,
135
+ sortAllowlist: ${entityName}SortAllowlist,
136
+ dialect: ${JSON.stringify(ctx.dialect)},
137
+ });
138
+ }
139
+ `;
140
+
141
+ return header + literalImports.toString() + body.toString();
142
+ }