Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
## [Unreleased]

### Added
- **cli — `meta init` scaffolds owned codegen generators (ADR-0034 scaffold-and-own, step 2):**
`meta init` now copies the four codegen reference templates (step 1) into the
consumer repo at `codegen/generators/{entity,queries,routes,barrel}.ts` and
scaffolds `metaobjects.config.ts` to import those **local** copies, so `meta gen`
runs from generators the consumer owns and edits — not from the package. Each
generator is written only if absent, so re-running `meta init --force` never
clobbers a hand-edited generator (mirrors the existing config.ts preservation).
codegen-ts gains a small reference-template reader the CLI uses to read the
shipped assets (`resolveReferenceRoot` / `readReferenceTemplate` /
`REFERENCE_GENERATOR_NAMES`, exported from `@metaobjectsdev/codegen-ts`).
- **codegen-ts — reference template library (ADR-0034 scaffold-and-own, step 1):**
new in-repo, copyable reference generators under `src/reference/`
(`entity` / `queries` / `routes` / `barrel`) — self-contained starting points a
Expand All @@ -23,6 +33,13 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
`renderUpdateFn`, `renderDeleteByIdFn`, `getPkInfo`). (`meta init` scaffolding,
generator-export deprecation, and the guidance rewrite are later steps.)

### Deprecated
- **codegen-ts — `@metaobjectsdev/codegen-ts/generators` factory re-exports
(ADR-0034 scaffold-and-own, step 2):** importing `entityFile` / `queriesFile` /
`routesFile` / `barrel` from the package `/generators` export is deprecated in
favor of the owned local copies `meta init` scaffolds. The export still works
(pre-GA latitude) but will be removed in a future major — own a copy instead.

### Fixed
- **cli — `meta init` gitignore hardening:** the scaffolded
`.metaobjects/.gitignore` previously ignored only `.gen-state/`, so a
Expand Down
16 changes: 12 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,11 @@ A user's `metaobjects.config.ts`:

```ts
import { defineConfig } from "@metaobjectsdev/cli";
import { entityFile, queriesFile, routesFile, barrel } from "@metaobjectsdev/codegen-ts/generators";
// Owned generators scaffolded by `meta init` (ADR-0034 scaffold-and-own).
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { routesFile } from "./codegen/generators/routes";
import { barrel } from "./codegen/generators/barrel";
import { formFile } from "@metaobjectsdev/codegen-ts-react";
import { tanstackQuery, tanstackGrid } from "@metaobjectsdev/codegen-ts-tanstack";

Expand Down Expand Up @@ -259,13 +263,17 @@ interface Generator {

Helpers `perEntity()` and `oncePerRun()` cover the common "file per entity" / "one-shot" cases.

**Built-in factories**: `entityFile`, `queriesFile`, `routesFile`, `formFile`, `barrel` — re-exported from `@metaobjectsdev/codegen-ts/generators`.
**Built-in factories**: `entityFile`, `queriesFile`, `routesFile`, `formFile`, `barrel`. Per ADR-0034 (scaffold-and-own), `meta init` copies the `entityFile`/`queriesFile`/`routesFile`/`barrel` reference templates into the consumer repo at `codegen/generators/*.ts` and the scaffolded config imports those owned local copies; importing them from `@metaobjectsdev/codegen-ts/generators` still works but is **deprecated** (removal in a future major).

**User wiring** (`metaobjects.config.ts`):

```ts
import { defineConfig } from "@metaobjectsdev/cli";
import { entityFile, queriesFile, routesFile, barrel } from "@metaobjectsdev/codegen-ts/generators";
// Owned generators scaffolded by `meta init` (ADR-0034 scaffold-and-own).
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { routesFile } from "./codegen/generators/routes";
import { barrel } from "./codegen/generators/barrel";

export default defineConfig({
outDir: "packages/database/src/generated",
Expand Down Expand Up @@ -480,7 +488,7 @@ These are the load-bearing principles that have emerged through implementation.
## Useful commands

```
meta init # scaffold metaobjects/, .metaobjects/, metaobjects.config.ts, .gitignore
meta init # scaffold metaobjects/, .metaobjects/, codegen/generators/, metaobjects.config.ts, .gitignore
meta gen [<entity>...] # codegen: render templates → format → three-way merge → write
meta gen --dry-run # preview without writing
meta gen --watch # re-run on metadata file changes
Expand Down
8 changes: 8 additions & 0 deletions docs/features/codegen-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ per-project. Don't fight a black-box generator; own a starting point and edit it
Choosing and adapting a starting template is a **human/Claude judgment call**, not a
CLI flag. (See ADR-0034.)

For a running start, `meta init` scaffolds a sensible default set —
`codegen/generators/{entity,queries,routes,barrel}.ts`, copied from the reference
templates — and wires `metaobjects.config.ts` to import them locally, so `meta gen`
runs from generators you own from the first run. Each file is written only if absent,
so re-running `meta init --force` never clobbers a hand-edited generator. Importing
those factories from `@metaobjectsdev/codegen-ts/generators` instead is **deprecated**
and slated for removal in a future major — own the local copy.

## 3. Authoring mechanisms — and their tradeoffs

There is no single right way to author a generator. The menu, and when to reach for
Expand Down
12 changes: 10 additions & 2 deletions docs/ports/typescript-client.md
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,11 @@ importBase?, outputLayout?, dbImport? }`.
```ts
// metaobjects.config.ts (multi-target)
import { defineConfig } from "@metaobjectsdev/cli";
import { entityFile, queriesFile, routesFile, barrel } from "@metaobjectsdev/codegen-ts/generators";
// Owned generators scaffolded by `meta init` (ADR-0034 scaffold-and-own).
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { routesFile } from "./codegen/generators/routes";
import { barrel } from "./codegen/generators/barrel";
import { formFile } from "@metaobjectsdev/codegen-ts-react";
import { tanstackQuery, tanstackGrid } from "@metaobjectsdev/codegen-ts-tanstack";

Expand Down Expand Up @@ -579,7 +583,11 @@ Metadata (same `Author` entity as the React examples above):

```ts
import { defineConfig } from "@metaobjectsdev/cli";
import { entityFile, queriesFile, routesFile, barrel } from "@metaobjectsdev/codegen-ts/generators";
// Owned generators scaffolded by `meta init` (ADR-0034 scaffold-and-own).
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { routesFile } from "./codegen/generators/routes";
import { barrel } from "./codegen/generators/barrel";
import {
angularServiceFile,
angularFormFile,
Expand Down
30 changes: 16 additions & 14 deletions docs/ports/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,20 @@ Two config files, by design:
- **`.metaobjects/config.json`** — JSON, static project state, parseable by
non-TS tooling.

`meta init` scaffolds both, the `metaobjects/` source directory, and the
`.gitignore` entries for `.metaobjects/.gen-state/`.
`meta init` scaffolds both, the `metaobjects/` source directory, the owned
codegen generators at `codegen/generators/{entity,queries,routes,barrel}.ts`
(ADR-0034 scaffold-and-own — copied from the reference templates, yours to edit),
and the `.gitignore` entries for `.metaobjects/.gen-state/`. The scaffolded config
imports those local copies; `meta gen` runs from them, not from the package.

```ts
// metaobjects.config.ts
import { defineConfig } from "@metaobjectsdev/cli";
import {
entityFile,
queriesFile,
routesFile,
barrel,
} from "@metaobjectsdev/codegen-ts/generators";
// Owned generators scaffolded by `meta init` — yours to edit (ADR-0034).
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { routesFile } from "./codegen/generators/routes";
import { barrel } from "./codegen/generators/barrel";

export default defineConfig({
outDir: "src/generated",
Expand Down Expand Up @@ -150,12 +152,12 @@ difference is the framework adapter the emitted code talks to.
```ts
// metaobjects.config.ts
import { defineConfig } from "@metaobjectsdev/cli";
import {
entityFile,
queriesFile,
routesFileHono,
barrel,
} from "@metaobjectsdev/codegen-ts/generators";
// Owned generators scaffolded by `meta init` (ADR-0034 scaffold-and-own).
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { barrel } from "./codegen/generators/barrel";
// Hono routes have no reference template yet — still imported from the package.
import { routesFileHono } from "@metaobjectsdev/codegen-ts/generators";

export default defineConfig({
outDir: "src/generated",
Expand Down
6 changes: 5 additions & 1 deletion docs/recipes/extending-metaobjects-with-providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ Notable bits:
```ts
// metaobjects.config.ts
import { defineConfig } from "@metaobjectsdev/cli";
import { entityFile, queriesFile, barrel, promptRender } from "@metaobjectsdev/codegen-ts/generators";
// Owned generators scaffolded by `meta init` (ADR-0034 scaffold-and-own).
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { barrel } from "./codegen/generators/barrel";
import { promptRender } from "@metaobjectsdev/codegen-ts/generators";
import { exampleProvider } from "./src/codegen/example-provider";

export default defineConfig({
Expand Down
5 changes: 4 additions & 1 deletion docs/recipes/wiring-generated-queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,10 @@ Then wire it into `metaobjects.config.ts`:

```ts
import { defineConfig } from "@metaobjectsdev/cli";
import { entityFile, queriesFile, barrel } from "@metaobjectsdev/codegen-ts/generators";
// Owned generators scaffolded by `meta init` (ADR-0034 scaffold-and-own).
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { barrel } from "./codegen/generators/barrel";
import { honoRoutesFile } from "./metaobjects-routes-hono";

export default defineConfig({
Expand Down
2 changes: 1 addition & 1 deletion server/java/integration-tests-kotlin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>com.metaobjects</groupId>
<artifactId>metaobjects</artifactId>
<version>7.4.3-SNAPSHOT</version>
<version>7.4.4-SNAPSHOT</version>
</parent>

<artifactId>metaobjects-integration-tests-kotlin</artifactId>
Expand Down
2 changes: 1 addition & 1 deletion server/java/integration-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<parent>
<groupId>com.metaobjects</groupId>
<artifactId>metaobjects</artifactId>
<version>7.4.3-SNAPSHOT</version>
<version>7.4.4-SNAPSHOT</version>
</parent>

<artifactId>metaobjects-integration-tests</artifactId>
Expand Down
23 changes: 18 additions & 5 deletions server/typescript/packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Run schema ops from the compiled binary:
## Quick start

```bash
# 1. Scaffold metaobjects/ + .metaobjects/ + metaobjects.config.ts
# 1. Scaffold metaobjects/ + .metaobjects/ + codegen/generators/ + metaobjects.config.ts
meta init

# 2. Author entity metadata
Expand Down Expand Up @@ -86,7 +86,9 @@ Running `meta` with no arguments prints a concise status line (whether a `metaob

### `meta init`

Scaffolds `metaobjects/` (visible entity declarations, with a placeholder `meta.common.json`), `.metaobjects/` (hidden tool state: `config.json`, `package.meta.json`, `AGENTS.md`, `CLAUDE.md`, `.gitignore`, `.gen-state/`), and `metaobjects.config.ts` at the repo root.
Scaffolds `metaobjects/` (visible entity declarations, with a placeholder `meta.common.json`), `.metaobjects/` (hidden tool state: `config.json`, `package.meta.json`, `AGENTS.md`, `CLAUDE.md`, `.gitignore`, `.gen-state/`), the **owned codegen generators** at `codegen/generators/{entity,queries,routes,barrel}.ts`, and `metaobjects.config.ts` at the repo root.

The generators are copied from the codegen reference templates and are **yours to edit** (ADR-0034 scaffold-and-own); the scaffolded `metaobjects.config.ts` imports them locally, and `meta gen` runs from those local copies — not from the package. Each generator file is written only if absent, so re-running with `--force` never clobbers a hand-edited generator.

Flags:
- `--force` — overwrite scaffold files (memory records preserved)
Expand Down Expand Up @@ -159,11 +161,14 @@ Flags:

Two config files, by design:

**`metaobjects.config.ts`** (at repo root) — generator wiring and codegen knobs, type-checked TS:
**`metaobjects.config.ts`** (at repo root) — generator wiring and codegen knobs, type-checked TS. The generators are imported from the **owned local copies** that `meta init` scaffolded into `codegen/generators/` (ADR-0034 scaffold-and-own), not from the package:

```ts
import { defineConfig } from "@metaobjectsdev/cli";
import { entityFile, queriesFile, routesFile, barrel } from "@metaobjectsdev/codegen-ts/generators";
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { routesFile } from "./codegen/generators/routes";
import { barrel } from "./codegen/generators/barrel";

export default defineConfig({
outDir: "packages/database/src/generated",
Expand All @@ -175,6 +180,10 @@ export default defineConfig({
});
```

> Importing these generator factories from `@metaobjectsdev/codegen-ts/generators`
> still works but is **deprecated** (ADR-0034) — own a local copy instead. The
> package export will be removed in a future major.

### Multiple output targets

By default every generator writes to `outDir`. To route each generator's output
Expand All @@ -183,7 +192,11 @@ concern — declare named **targets** and point generators at them with `target`

```ts
import { defineConfig } from "@metaobjectsdev/cli";
import { entityFile, queriesFile, routesFile, barrel } from "@metaobjectsdev/codegen-ts/generators";
// Owned generators scaffolded by `meta init` (ADR-0034 scaffold-and-own).
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { routesFile } from "./codegen/generators/routes";
import { barrel } from "./codegen/generators/barrel";
import { formFile } from "@metaobjectsdev/codegen-ts-react";
import { tanstackQuery, tanstackGrid } from "@metaobjectsdev/codegen-ts-tanstack";

Expand Down
47 changes: 40 additions & 7 deletions server/typescript/packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import { parseInitArgs } from "../lib/args.js";
import { log } from "../lib/log.js";
import { cliVersion } from "../lib/version.js";
import { findWranglerConfig, parseWranglerConfig } from "@metaobjectsdev/migrate-ts";
import { readReferenceTemplate, REFERENCE_GENERATOR_NAMES } from "@metaobjectsdev/codegen-ts";

// ADR-0034 scaffold-and-own — `meta init` copies the codegen reference templates into
// the consumer's repo so they OWN them; metaobjects.config.ts imports them locally.
const OWNED_GENERATORS_DIR = "codegen/generators";

const META_COMMON_JSON = JSON.stringify(
{
Expand Down Expand Up @@ -46,13 +51,14 @@ const METAOBJECTS_GITIGNORE_BODY = `.gen-state/

function buildMetaobjectsConfigBody(dialect: "sqlite" | "postgres" | "d1" = "sqlite"): string {
return `import { defineConfig } from "@metaobjectsdev/cli";
import {
entityFile,
queriesFile,
routesFile,
// formFile, // opt-in: emit React form components
barrel,
} from "@metaobjectsdev/codegen-ts/generators";
// Owned codegen generators (ADR-0034 scaffold-and-own). \`meta init\` copied these
// reference templates into ./codegen/generators/ — they are YOURS to edit, and
// \`meta gen\` runs from these local copies, not from the package. Read each file's
// header doc-block for what it emits and how to customize it.
import { entityFile } from "./codegen/generators/entity";
import { queriesFile } from "./codegen/generators/queries";
import { routesFile } from "./codegen/generators/routes";
import { barrel } from "./codegen/generators/barrel";

export default defineConfig({
outDir: "src/generated",
Expand All @@ -77,6 +83,7 @@ export default defineConfig({

const NEXT_STEPS = `
Initialized metaobjects/ + .metaobjects/ + metaobjects.config.ts
Codegen generators copied to codegen/generators/ — they're YOURS to edit (ADR-0034 scaffold-and-own).

Next steps (when later sub-projects ship):
meta ingest # propose entities from your existing TS code
Expand Down Expand Up @@ -212,6 +219,27 @@ async function wireRootMemory(cwd: string, result: InitResult): Promise<void> {
}
}

/**
* ADR-0034 — copy the codegen reference templates into the consumer's repo at
* `codegen/generators/<name>.ts` so they own them. Each file is written only if absent,
* so a re-run with --force never clobbers a hand-edited generator. The scaffolded
* metaobjects.config.ts imports these local copies (not the package `/generators` export).
*/
async function writeOwnedGenerators(opts: InitOptions, result: InitResult): Promise<void> {
const dir = join(opts.cwd, OWNED_GENERATORS_DIR);
await mkdir(dir, { recursive: true });
for (const name of REFERENCE_GENERATOR_NAMES) {
const rel = `${OWNED_GENERATORS_DIR}/${name}.ts`;
const abs = join(dir, `${name}.ts`);
if (await fileExists(abs)) {
result.preserved.push(rel);
continue;
}
await writeFile(abs, readReferenceTemplate(name), "utf8");
result.created.push(rel);
}
}

export async function init(opts: InitOptions): Promise<InitResult> {
const result: InitResult = { created: [], preserved: [], warnings: [] };
const agentDir = join(opts.cwd, DEFAULT_METAOBJECTS_DIR);
Expand Down Expand Up @@ -254,6 +282,7 @@ export async function init(opts: InitOptions): Promise<InitResult> {
`.metaobjects/${PACKAGE_MANIFEST_FILE}`,
);
result.created.push(".metaobjects/AGENTS.md", ".metaobjects/CLAUDE.md", ".claude/skills/metaobjects-*", AGENT_CONTEXT_MANIFEST_PATH);
for (const name of REFERENCE_GENERATOR_NAMES) result.created.push(`${OWNED_GENERATORS_DIR}/${name}.ts`);
result.created.push("metaobjects.config.ts");
return result;
}
Expand Down Expand Up @@ -334,6 +363,10 @@ export async function init(opts: InitOptions): Promise<InitResult> {

await writeAgentContext(opts, result);

// ADR-0034 — scaffold the OWNED codegen generators that metaobjects.config.ts imports
// locally. Done before the config so the import targets exist on first `meta gen`.
await writeOwnedGenerators(opts, result);

// Scaffold metaobjects.config.ts at the project root. Never overwrite if it exists.
const forgeConfigPath = join(opts.cwd, "metaobjects.config.ts");
if (!(await fileExists(forgeConfigPath))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ describe("metaobjects.config.ts wiring still scaffolded", () => {
await init({ cwd });
const configTs = readFileSync(join(cwd, "metaobjects.config.ts"), "utf8");
expect(configTs).toContain("defineConfig");
expect(configTs).toContain("@metaobjectsdev/codegen-ts/generators");
// ADR-0034 — the scaffolded config imports the OWNED local generators, never the
// deprecated package `/generators` export.
expect(configTs).toContain('from "./codegen/generators/entity"');
expect(configTs).not.toContain("@metaobjectsdev/codegen-ts/generators");
});
});

Expand Down
Loading
Loading