@metaobjectsdev/codegen-ts-react 0.24.3 → 0.24.5

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 CHANGED
@@ -26,6 +26,14 @@ export default defineConfig({
26
26
  targets". The form imports the entity module from wherever `entityFile()` is
27
27
  routed (relative when same target, the entity-module target's `importBase` when not).
28
28
 
29
+ ### The generator is yours
30
+
31
+ `formFile()` has a reference template: `meta eject form` copies it into `codegen/generators/form.ts`
32
+ for you to own. The emitted component is React with react-hook-form — if your framework needs a
33
+ marker directive or a different import shape, compose the exported renderer and change that one
34
+ step. Inside the ejected file's existing `if (!ctx.renderContext) throw …` guard, change only the
35
+ `content:` line: `content: '"use client";\n' + renderFormFile(entity, ctx.renderContext)`.
36
+
29
37
  ## Pairs with
30
38
 
31
39
  - Runtime: [`@metaobjectsdev/react`](../../../../client/web/packages/react) — the generated forms import from here.
@@ -1 +1 @@
1
- {"version":3,"file":"form-file.d.ts","sourceRoot":"","sources":["../src/form-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,EAA6B,KAAK,gBAAgB,EAAwF,MAAM,4BAA4B,CAAC;AAGpL,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EAwChB,gBAAgB,CAAC,YAAY,CAAC,CAAC"}
1
+ {"version":3,"file":"form-file.d.ts","sourceRoot":"","sources":["../src/form-file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAE3D,OAAO,EAA6B,KAAK,gBAAgB,EAA6G,MAAM,4BAA4B,CAAC;AAGzM,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;GAIG;AACH,eAAO,MAAM,QAAQ,EA2ChB,gBAAgB,CAAC,YAAY,CAAC,CAAC"}
package/dist/form-file.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { OBJECT_ATTR_DISCRIMINATOR } from "@metaobjectsdev/metadata";
2
- import { perEntity, entityOutputPath, servesWriteApi, isProjection, isTphSubtype, CODEGEN_ATTR_EMIT_FORM } from "@metaobjectsdev/codegen-ts";
2
+ import { perEntity, entityOutputPath, servesWriteApi, isProjection, isTphSubtype, CODEGEN_ATTR_EMIT_FORM, withClientDirective } from "@metaobjectsdev/codegen-ts";
3
3
  import { renderFormFile } from "./templates/form-file.js";
4
4
  /**
5
5
  * Forms are opt-in: a user must add `formFile()` to config.generators.
@@ -42,7 +42,7 @@ export const formFile = function formFile(opts) {
42
42
  }
43
43
  return {
44
44
  path: entityOutputPath(ctx.config.outputLayout ?? "flat", entity.package, `${entity.name}.form.tsx`),
45
- content: renderFormFile(entity, ctx.renderContext),
45
+ content: withClientDirective(renderFormFile(entity, ctx.renderContext), ctx.renderContext.clientDirective),
46
46
  };
47
47
  }),
48
48
  };
@@ -1 +1 @@
1
- {"version":3,"file":"form-file.js","sourceRoot":"","sources":["../src/form-file.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,SAAS,EAAyC,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpL,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAO1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,SAAS,QAAQ,CAAC,IAAmB;IAC3D,MAAM,UAAU,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,SAAS,GAAc;QAC3B,IAAI,EAAE,WAAW;QACjB,8DAA8D;QAC9D,oEAAoE;QACpE,qEAAqE;QACrE,4BAA4B;QAC5B,2EAA2E;QAC3E,yEAAyE;QACzE,6EAA6E;QAC7E,MAAM,EAAE,CAAC,CAAa,EAAE,EAAE;YACxB,6EAA6E;YAC7E,IAAI,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,KAAK;gBAAE,OAAO,KAAK,CAAC;YAC3D,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;YACjC,IAAI,YAAY,CAAC,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC,CAAC,mBAAmB;YACrD,wDAAwD;YACxD,4EAA4E;YAC5E,8EAA8E;YAC9E,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC;YAC3E,gFAAgF;YAChF,8EAA8E;YAC9E,2EAA2E;YAC3E,wCAAwC;YACxC,OAAO,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;QACD,QAAQ,EAAE,SAAS,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;YAClC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;YAC/E,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,IAAI,WAAW,CAAC;gBACpG,OAAO,EAAE,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC;aACnD,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,CAAmC,CAAC"}
1
+ {"version":3,"file":"form-file.js","sourceRoot":"","sources":["../src/form-file.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EAAE,SAAS,EAAyC,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACzM,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAO1D;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,SAAS,QAAQ,CAAC,IAAmB;IAC3D,MAAM,UAAU,GAAG,IAAI,EAAE,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAChD,MAAM,SAAS,GAAc;QAC3B,IAAI,EAAE,WAAW;QACjB,8DAA8D;QAC9D,oEAAoE;QACpE,qEAAqE;QACrE,4BAA4B;QAC5B,2EAA2E;QAC3E,yEAAyE;QACzE,6EAA6E;QAC7E,MAAM,EAAE,CAAC,CAAa,EAAE,EAAE;YACxB,6EAA6E;YAC7E,IAAI,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,KAAK,KAAK;gBAAE,OAAO,KAAK,CAAC;YAC3D,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;gBAAE,OAAO,KAAK,CAAC;YACjC,IAAI,YAAY,CAAC,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC,CAAC,mBAAmB;YACrD,wDAAwD;YACxD,4EAA4E;YAC5E,8EAA8E;YAC9E,IAAI,OAAO,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC,KAAK,QAAQ;gBAAE,OAAO,KAAK,CAAC;YAC3E,gFAAgF;YAChF,8EAA8E;YAC9E,2EAA2E;YAC3E,wCAAwC;YACxC,OAAO,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/C,CAAC;QACD,QAAQ,EAAE,SAAS,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;YAClC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;YAC/E,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,IAAI,WAAW,CAAC;gBACpG,OAAO,EAAE,mBAAmB,CAC1B,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,aAAa,CAAC,EACzC,GAAG,CAAC,aAAa,CAAC,eAAe,CAClC;aACF,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,CAAmC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  export { formFile, type FormFileOpts } from "./form-file.js";
2
+ export { renderFormFile } from "./templates/form-file.js";
3
+ export { resolveReferenceRoot, readReferenceTemplate, REFERENCE_GENERATOR_NAMES } from "./reference-templates.js";
4
+ export type { ReferenceGeneratorName } from "./reference-templates.js";
2
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAI7D,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAI1D,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAGlH,YAAY,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,9 @@
1
1
  // Public API surface for @metaobjectsdev/codegen-ts-react.
2
2
  export { formFile } from "./form-file.js";
3
+ // FR-040 §4.2(b) — public so an owned generator composes the engine rather than
4
+ // forking it. Signature is stable API: (entity, ctx) => string.
5
+ export { renderFormFile } from "./templates/form-file.js";
6
+ // FR-040 §4.1 — the copyable reference generator(s) this package ships in
7
+ // `src/reference/`, and the reader `meta init`/`meta eject` use to read them.
8
+ export { resolveReferenceRoot, readReferenceTemplate, REFERENCE_GENERATOR_NAMES } from "./reference-templates.js";
3
9
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,OAAO,EAAE,QAAQ,EAAqB,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,2DAA2D;AAC3D,OAAO,EAAE,QAAQ,EAAqB,MAAM,gBAAgB,CAAC;AAE7D,gFAAgF;AAChF,gEAAgE;AAChE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,0EAA0E;AAC1E,8EAA8E;AAC9E,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,5 @@
1
+ export declare const REFERENCE_GENERATOR_NAMES: readonly ["form"];
2
+ export type ReferenceGeneratorName = (typeof REFERENCE_GENERATOR_NAMES)[number];
3
+ export declare function resolveReferenceRoot(): string;
4
+ export declare function readReferenceTemplate(name: ReferenceGeneratorName): string;
5
+ //# sourceMappingURL=reference-templates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference-templates.d.ts","sourceRoot":"","sources":["../src/reference-templates.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,yBAAyB,mBAAoB,CAAC;AAC3D,MAAM,MAAM,sBAAsB,GAAG,CAAC,OAAO,yBAAyB,CAAC,CAAC,MAAM,CAAC,CAAC;AAIhF,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,sBAAsB,GAAG,MAAM,CAE1E"}
@@ -0,0 +1,12 @@
1
+ // FR-040 §4.1 — this package hosts its own copyable reference generators in
2
+ // `src/reference/`, read through the shared factory so the resolver is not duplicated.
3
+ import { makeReferenceReader } from "@metaobjectsdev/codegen-ts";
4
+ export const REFERENCE_GENERATOR_NAMES = ["form"];
5
+ const reader = makeReferenceReader(import.meta.url, REFERENCE_GENERATOR_NAMES);
6
+ export function resolveReferenceRoot() {
7
+ return reader.resolveReferenceRoot();
8
+ }
9
+ export function readReferenceTemplate(name) {
10
+ return reader.readReferenceTemplate(name);
11
+ }
12
+ //# sourceMappingURL=reference-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reference-templates.js","sourceRoot":"","sources":["../src/reference-templates.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,uFAAuF;AACvF,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAEjE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,MAAM,CAAU,CAAC;AAG3D,MAAM,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC;AAE/E,MAAM,UAAU,oBAAoB;IAClC,OAAO,MAAM,CAAC,oBAAoB,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,IAA4B;IAChE,OAAO,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC;AAC5C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metaobjectsdev/codegen-ts-react",
3
- "version": "0.24.3",
3
+ "version": "0.24.5",
4
4
  "description": "React codegen for metaobjects — emits <Entity>.form.tsx files using react-hook-form and @metaobjectsdev/react helpers.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -45,8 +45,8 @@
45
45
  "access": "public"
46
46
  },
47
47
  "dependencies": {
48
- "@metaobjectsdev/metadata": "0.24.3",
49
- "@metaobjectsdev/codegen-ts": "0.24.3",
48
+ "@metaobjectsdev/metadata": "0.24.5",
49
+ "@metaobjectsdev/codegen-ts": "0.24.5",
50
50
  "ts-poet": "^6.10.0"
51
51
  },
52
52
  "peerDependencies": {
package/src/form-file.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { MetaObject } from "@metaobjectsdev/metadata";
2
2
  import { OBJECT_ATTR_DISCRIMINATOR } from "@metaobjectsdev/metadata";
3
- import { perEntity, type Generator, type GeneratorFactory, entityOutputPath, servesWriteApi, isProjection, isTphSubtype, CODEGEN_ATTR_EMIT_FORM } from "@metaobjectsdev/codegen-ts";
3
+ import { perEntity, type Generator, type GeneratorFactory, entityOutputPath, servesWriteApi, isProjection, isTphSubtype, CODEGEN_ATTR_EMIT_FORM, withClientDirective } from "@metaobjectsdev/codegen-ts";
4
4
  import { renderFormFile } from "./templates/form-file.js";
5
5
 
6
6
  export interface FormFileOpts {
@@ -45,7 +45,10 @@ export const formFile = function formFile(opts?: FormFileOpts): Generator {
45
45
  }
46
46
  return {
47
47
  path: entityOutputPath(ctx.config.outputLayout ?? "flat", entity.package, `${entity.name}.form.tsx`),
48
- content: renderFormFile(entity, ctx.renderContext),
48
+ content: withClientDirective(
49
+ renderFormFile(entity, ctx.renderContext),
50
+ ctx.renderContext.clientDirective,
51
+ ),
49
52
  };
50
53
  }),
51
54
  };
package/src/index.ts CHANGED
@@ -1,2 +1,13 @@
1
1
  // Public API surface for @metaobjectsdev/codegen-ts-react.
2
2
  export { formFile, type FormFileOpts } from "./form-file.js";
3
+
4
+ // FR-040 §4.2(b) — public so an owned generator composes the engine rather than
5
+ // forking it. Signature is stable API: (entity, ctx) => string.
6
+ export { renderFormFile } from "./templates/form-file.js";
7
+
8
+ // FR-040 §4.1 — the copyable reference generator(s) this package ships in
9
+ // `src/reference/`, and the reader `meta init`/`meta eject` use to read them.
10
+ export { resolveReferenceRoot, readReferenceTemplate, REFERENCE_GENERATOR_NAMES } from "./reference-templates.js";
11
+ // The name union travels with the names array — codegen-ts exports both, and a
12
+ // consumer keying anything by ejectable name needs the type as much as the values.
13
+ export type { ReferenceGeneratorName } from "./reference-templates.js";
@@ -0,0 +1,92 @@
1
+ // REFERENCE TEMPLATE — copy this into your repo (e.g. codegen/generators/form.ts) and own it.
2
+ // Then import it LOCALLY in metaobjects.config.ts:
3
+ // import { formFile } from "./codegen/generators/form.js";
4
+ //
5
+ // RUNTIME: this file executes under whatever runs `meta gen` — NODE, even in a Bun
6
+ // project. Do not reach for `Bun.*` globals here.
7
+ // targets: React with react-hook-form. The emitted component calls `useEntityForm`
8
+ // from `@metaobjectsdev/react`, so it is a CLIENT component.
9
+ // If your framework compiles server and client from one tree and resolves
10
+ // each half under different conditions, the emitted file may need a marker
11
+ // directive — prepend it to `renderFormFile`'s result below. That is a
12
+ // one-line change in THIS file and is the intended way to do it.
13
+ // use-when: you want a generated form per writable entity.
14
+ // emits: <target>/<Entity>.form.tsx
15
+ // customize: this generator is YOURS. `renderFormFile` (exported from
16
+ // @metaobjectsdev/codegen-ts-react) produces the component body — wrap it,
17
+ // prepend to it, or replace the call entirely with your own renderer.
18
+ // composes-with: entity.ts (imports the schemas the form validates against).
19
+
20
+ import type { MetaObject } from "@metaobjectsdev/metadata";
21
+ import { OBJECT_ATTR_DISCRIMINATOR } from "@metaobjectsdev/metadata";
22
+ import {
23
+ perEntity,
24
+ type Generator,
25
+ type GeneratorFactory,
26
+ entityOutputPath,
27
+ servesWriteApi,
28
+ isProjection,
29
+ isTphSubtype,
30
+ CODEGEN_ATTR_EMIT_FORM,
31
+ withClientDirective,
32
+ } from "@metaobjectsdev/codegen-ts";
33
+ import { renderFormFile } from "@metaobjectsdev/codegen-ts-react";
34
+
35
+ export interface FormFileOpts {
36
+ filter?: (entity: MetaObject) => boolean;
37
+ target?: string;
38
+ }
39
+
40
+ /**
41
+ * Forms are opt-in: a user must add `formFile()` to config.generators.
42
+ * Per-entity opt-out via `@emitForm: false` is honored.
43
+ * .tsx files are not piped through formatTs (Biome only handles .ts here).
44
+ */
45
+ export const formFile = function formFile(opts?: FormFileOpts): Generator {
46
+ const userFilter = opts?.filter ?? (() => true);
47
+ const generator: Generator = {
48
+ name: "form-file",
49
+ // Always set: AND-composes the framework write-artifact guard
50
+ // (skips abstract types — no instance — and read-only projections —
51
+ // instantiable for read, never for write), the metadata opt-out, and
52
+ // the optional user filter.
53
+ // FR-017 Tier 3: forms are ALWAYS per-subtype. The discriminator base gets
54
+ // NO form (you can't create an abstract base), but each concrete subtype
55
+ // does — even though it has no own writable source (it inherits the base's).
56
+ filter: (e: MetaObject) => {
57
+ // ADR-0039: resolving — a concrete entity may inherit @emitForm via extends.
58
+ if (e.attr(CODEGEN_ATTR_EMIT_FORM) === false) return false;
59
+ if (!userFilter(e)) return false;
60
+ if (isTphSubtype(e)) return true; // per-subtype form
61
+ // A discriminator base is never form-rendered directly.
62
+ // ADR-0039: own — @discriminator identifies a TPH base level (read own so a
63
+ // subtype isn't mistaken for a base); e is already known not to be a subtype.
64
+ if (typeof e.ownAttr(OBJECT_ATTR_DISCRIMINATOR) === "string") return false;
65
+ // A form is a client of a WRITE endpoint. Ask whether one exists, not where the
66
+ // data is stored — see api-surface.ts. `!isProjection` stays explicit here: a
67
+ // read-only view is a UI-tier exclusion (nothing to submit), distinct from
68
+ // whether write endpoints exist at all.
69
+ return servesWriteApi(e) && !isProjection(e);
70
+ },
71
+ generate: perEntity((entity, ctx) => {
72
+ if (!ctx.renderContext) {
73
+ throw new Error("form-file: renderContext is required (provided by runGen)");
74
+ }
75
+ // The framework-coupled seam. `withClientDirective` applies the project-level
76
+ // `clientDirective` config knob (FR-040 §6.4); for a directive your framework
77
+ // needs that MetaObjects does not model, prepend it right here.
78
+ const body = withClientDirective(
79
+ renderFormFile(entity, ctx.renderContext),
80
+ ctx.renderContext.clientDirective,
81
+ );
82
+ return {
83
+ path: entityOutputPath(ctx.config.outputLayout ?? "flat", entity.package, `${entity.name}.form.tsx`),
84
+ content: body,
85
+ };
86
+ }),
87
+ };
88
+ if (opts?.target) {
89
+ generator.target = opts.target;
90
+ }
91
+ return generator;
92
+ } as GeneratorFactory<FormFileOpts>;
@@ -0,0 +1,16 @@
1
+ // FR-040 §4.1 — this package hosts its own copyable reference generators in
2
+ // `src/reference/`, read through the shared factory so the resolver is not duplicated.
3
+ import { makeReferenceReader } from "@metaobjectsdev/codegen-ts";
4
+
5
+ export const REFERENCE_GENERATOR_NAMES = ["form"] as const;
6
+ export type ReferenceGeneratorName = (typeof REFERENCE_GENERATOR_NAMES)[number];
7
+
8
+ const reader = makeReferenceReader(import.meta.url, REFERENCE_GENERATOR_NAMES);
9
+
10
+ export function resolveReferenceRoot(): string {
11
+ return reader.resolveReferenceRoot();
12
+ }
13
+
14
+ export function readReferenceTemplate(name: ReferenceGeneratorName): string {
15
+ return reader.readReferenceTemplate(name);
16
+ }