import { type ColumnNamingStrategy, type MetaDataTypeProvider } from "@metaobjectsdev/metadata"; import type { Generator } from "./generator.js"; import type { ExtStyle } from "./render-context.js"; import type { OutputLayout, ResolvedTarget } from "./import-path.js"; /** * A config `generators` entry. Either a typed generator (the primary, fully * typed form — `entityFile()`) OR a STABLE-NAME STRING resolved via the * {@link generatorRegistry} (e.g. `"entity"`). The string form is the * cross-port-consistent selection mechanism (matches C#/Python * `--generators entity,routes`); it always uses the generator's DEFAULT * options. Adopters needing options use the factory form. * * ADR-0021 #1 (TS parity). */ export type GeneratorSpec = Generator | string; export type Dialect = "sqlite" | "postgres"; /** Re-exported from metadata so codegen-ts consumers see one canonical type. */ export type { ColumnNamingStrategy, MetaDataTypeProvider } from "@metaobjectsdev/metadata"; export type { ExtStyle }; export type { OutputLayout }; export type { ResolvedTarget }; /** The implicit target synthesized from top-level config (outDir/outputLayout/dbImport). */ export declare const DEFAULT_TARGET_NAME = "default"; /** User-facing per-target output config. */ export interface TargetConfig { outDir: string; importBase?: string; outputLayout?: OutputLayout; dbImport?: string; /** * Whether this target emits server runtime bindings. Defaults to `true` (a full * server package: Drizzle tables/views + the DB layer). Set `false` for a * contract-only target — Zod schemas + inferred TS types only, no `drizzle-orm` * / `runtime-ts` import — e.g. a shared wire-contract package consumed by a web * client with no database. See {@link ResolvedTarget.runtime}. */ runtime?: boolean; } /** Subset of MetaobjectsGenConfig surfaced to generators via GenContext. */ export interface ResolvedGenConfig { outDir: string; extStyle: ExtStyle; dbImport: string; dialect: Dialect; /** "flat" (default) — all files in outDir; "package" — files placed in a sub-path derived from each entity's metadata package. */ outputLayout?: OutputLayout; /** Whether the OPT-IN Hono routes generator (routesFileHono) is active in the * run — aggregated by the runner from the suite's `emitsHonoRoutes` markers. * api-docs reads this to AUTO-DETECT whether to document the Hono CRUD surface * (it otherwise mirrors the default Fastify-only suite). Undefined ⇒ false. */ includeHonoRoutes?: boolean; /** * FR-019 / ADR-0026: the module specifier from which an externally-PROVIDED * shared enum (`@provided: true` on an abstract package-level `field.enum`) is * imported. metaobjects emits NO type for a provided enum — consuming entity * files `import { } from ""`. The per-port * namespace/module is codegen config, never a metadata attr (ADR-0001). A model * that references a provided enum without this set is a codegen-time error. */ providedEnumModule?: string; } /** Default dialect / entity-import when a value-object-only project omits them. * Inert — they are only ever read when DB code is generated, and a project that * would generate DB code is required to set them explicitly (see `runGen`'s guard). */ export declare const DEFAULT_DIALECT: Dialect; export declare const DEFAULT_DB_IMPORT = "./db"; /** * The user-facing codegen config. `dbImport` / `dialect` are OPTIONAL here (unlike the * resolved `ResolvedGenConfig` the generators consume): a value-object-only project * (no `object.entity` / `object.projection`) generates zero database / query / route * code, so requiring them would be a dead-but-mandatory `tsc` obligation. `runGen` * fills inert defaults when they are absent AND the model emits no DB artifacts, and * throws a clear error when they are absent but the model DOES emit DB code (#194). */ export interface MetaobjectsGenConfig extends Omit { dbImport?: string; dialect?: Dialect; /** * Generators to run. Each entry is either a typed generator factory result * (`entityFile()`) or a stable-name string (`"entity"`) resolved via the * registry. Mixed arrays are allowed (`["entity", routesFile()]`). String * entries use the generator's default options. ADR-0021 #1. */ generators: GeneratorSpec[]; /** How field names map to DB column names when @dbColumn is omitted. Defaults to "snake_case". */ columnNamingStrategy?: ColumnNamingStrategy; /** * Auto-pluralize the Drizzle collection (table) variable name derived from * each entity (`AgentConfig` → `agentConfigs`). Defaults to `true`. Set * `false` to keep collection vars singular. Per-entity exceptions go in * {@link collectionNameOverrides}. Naming is a per-port codegen concern * (ADR-0001), so this is config — not a metadata attribute — and carries no * cross-port conformance cost. */ pluralizeCollections?: boolean; /** * Per-entity exact collection-var-name overrides, keyed by the bare entity * name. Wins over {@link pluralizeCollections} — the escape hatch for the * handful of tables a global rule gets wrong * (e.g. `{ AuditLog: "auditLog", LlmTierConfig: "llmTierConfig" }`). */ collectionNameOverrides?: Record; /** * Drizzle timestamp column mode. "string" (default) types timestamp columns as * ISO-8601 strings (matches the generated Zod + cross-port wire contract); "date" * uses drizzle's native JS-Date mode (for consumers whose hand-written code works * with `Date`). * * **Postgres-only.** Drizzle's sqlite-core `text()` timestamp column has no * Date-typed mode (only `pg-core`'s `timestamp()` does), so `"date"` is * normalized to `"string"` whenever `dialect: "sqlite"` (which also covers * Cloudflare D1 — D1 is sqlite-at-the-SQL-level, see the D1 note in the repo's * porting docs). This keeps the option a safe no-op on sqlite/D1 instead of * emitting a non-compiling column + a Zod schema disagreeing with it. * * Date-mode filtering (`?filter[][gte]=...`) IS supported: a * `@filterable` `field.timestamp` generated under this mode carries * `dateValues: true` in its `FilterAllowlist` rule, and `runtime-ts`'s filter * parser coerces the query-string value with `new Date(...)` rather than binding * a string against a Date-typed column (a malformed value is rejected as * `filter.invalid_value`). `field.date` / `field.time` are unaffected — Drizzle * types both as strings under every dialect. */ timestampMode?: "date" | "string"; /** Path prefix applied to generated route registrations + hook fetch URLs. Defaults to "". */ apiPrefix?: string; /** * Whether abstract entities (`@isAbstract: true`) emit their shape artifact * (the type-only interface / value-object file from the entity-file * generator). Defaults to `true`. Instance/write artifacts (forms, CRUD/read * hooks, grids) are NEVER emitted for abstract entities regardless of this * flag — that invariant lives in `instance-artifacts.ts`. This knob only * governs the shape, mirroring the cross-port `emitAbstractShapes` option. */ emitAbstractShapes?: boolean; /** Docs-output config consumed by the `meta docs` door. See {@link DocsConfig}. */ docs?: DocsConfig; /** Named output destinations. Generators reference one via `target`. */ targets?: Record; /** importBase for the default target (top-level outDir). */ importBase?: string; /** * Consumer-supplied {@link MetaDataTypeProvider}s. Threaded to `loadMemory` * by the CLI's gen/migrate commands so a project can register its own * subtypes/attrs (e.g. a `template.toolcall` subtype) without forking the * loader. Composed AFTER the default core+forge bundle. */ providers?: readonly MetaDataTypeProvider[]; /** * MetaObjects-shipped library packages this project loads alongside its own metadata — * `["ai"]` makes `extends: "metaobjects::ai::LlmCallBase"` resolve. * * Sits beside `providers` because it answers the same shape of question: what does this * project's model need in scope beyond the files it declares. Opt-in, because a library * registers real top-level nodes and a project that never references one should not find * them in its model, its generated output or its docs. * * Threaded to `loadMemory` by every CLI command that loads metadata. Before it existed, * `librarySources` was reachable only from `MetaDataLoader.fromDirectory` — which the * CLI does not use — so a generator that consumes a library was registered FOR the CLI * while its input was unreachable THROUGH it (#333). */ libraries?: readonly string[]; } /** MetaobjectsGenConfig after applying defaults. All fields required. * `targets` is Omitted from the base so it can narrow from the user-facing * TargetConfig to the fully-resolved ResolvedTarget (incompatible under * exactOptionalPropertyTypes otherwise). */ export interface NormalizedMetaobjectsGenConfig extends Omit { /** Resolved to a concrete value (the user's, else the inert default). */ dbImport: string; dialect: Dialect; /** Fully resolved — every string spec has been mapped to its factory result. */ generators: Generator[]; columnNamingStrategy: ColumnNamingStrategy; pluralizeCollections: boolean; collectionNameOverrides: Record; timestampMode: "date" | "string"; apiPrefix: string; emitAbstractShapes: boolean; outputLayout: OutputLayout; targets: Record; } export type DocsSurface = "model" | "api" | "requirements"; export interface ApiSurface { lang: string; subDir: string; baseUrl?: string; } /** The single docs-output config: where ALL doc surfaces go, how pages are laid * out, and which surfaces to emit. Read by the `meta docs` door (and, when the * api surface fans out, by each port's docs command). */ export interface DocsConfig { outDir?: string; layout?: OutputLayout; baseUrl?: string; surfaces?: DocsSurface[]; apiSurfaces?: ApiSurface[]; } export interface ResolvedDocsConfig { outDir: string; layout: OutputLayout; baseUrl: string; surfaces: DocsSurface[]; apiSurfaces: ApiSurface[]; } /** Merge the config `docs:` block with CLI overrides over documented defaults. * `fallbackLayout` is the project's `outputLayout` so docs default to the same * page placement as codegen when `docs.layout` is unset. */ export declare function resolveDocsConfig(block: DocsConfig | undefined, cli: Partial, fallbackLayout: OutputLayout): ResolvedDocsConfig; /** Identity passthrough; exists for IDE type-inference + autocomplete. */ export declare function defineConfig(config: MetaobjectsGenConfig): MetaobjectsGenConfig; /** Synthesize the implicit "default" target from top-level fields and resolve * each named target (outputLayout + dbImport fall back to top-level; * importBase does NOT inherit — it is a per-target identity). */ export declare function resolveTargets(config: MetaobjectsGenConfig): Record; /** * Materialize the config `generators` array: pass typed generators through * untouched and resolve each stable-name string via the {@link generatorRegistry} * to its factory result (default options). ADR-0021 #1. * * Errors: * - a NEUTRAL name (`docs`, `mermaid-er`) is owned by `meta docs` (ADR-0021 D1) * and is not selectable in the gen suite. * - an UNKNOWN name throws listing the available NATIVE names. */ export declare function resolveGenerators(specs: readonly GeneratorSpec[]): Generator[]; /** Apply defaults to a MetaobjectsGenConfig, returning a NormalizedMetaobjectsGenConfig. */ export declare function normalizeConfig(config: MetaobjectsGenConfig): NormalizedMetaobjectsGenConfig; //# sourceMappingURL=metaobjects-config.d.ts.map