@kurotako/gen-angular 0.1.0
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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +40 -0
- package/dist/index.cjs +888 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +82 -0
- package/dist/index.d.ts +82 -0
- package/dist/index.js +847 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/generator.ts","../src/artifact.ts","../src/names.ts","../src/zod-artifact.ts","../src/emit/barrel.ts","../src/render/imports.ts","../src/render/controls.ts","../src/render/relations.ts","../src/render/variants.ts","../src/render/reactive.ts","../src/render/signal.ts","../src/emit/entity.ts","../src/emit/runtime.ts","../src/options.ts"],"sourcesContent":["/**\n * `@kurotako/gen-angular` error classes.\n *\n * `AngularGenError` is a plain `Error` subclass carrying a stable `code`; the\n * Angular generator has no dependency on `@kurotako/core` at runtime, and\n * `@kurotako/core` wraps any throw from `generate()` as a `DriverError` for the\n * CLI's single `instanceof TakoError` catch.\n *\n * Codes: `angular_missing_zod_symbol`, `angular_missing_zod_namespace`.\n */\n\nexport class AngularGenError extends Error {\n readonly code: string;\n\n constructor(code: string, message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = new.target.name;\n this.code = code;\n }\n}\n\n/**\n * The Zod artifact has no entry (or no `role` symbol) for `${ns}.${entity}`.\n * `dependsOn: ['zod']` guarantees the dependency ran, but a role can still be\n * absent if the consumed `gen-zod` version predates it.\n */\nexport class MissingZodSymbolError extends AngularGenError {\n readonly entityKey: string;\n readonly role: string;\n\n constructor(entityKey: string, role: string) {\n super(\n 'angular_missing_zod_symbol',\n `Zod artifact for '${entityKey}' has no '${role}' symbol; regenerate with a gen-zod version that exposes it`,\n );\n this.entityKey = entityKey;\n this.role = role;\n }\n}\n\n/** The Zod artifact's `extra.perNamespace` has no entry for a namespace the IR carries. */\nexport class MissingZodNamespaceError extends AngularGenError {\n readonly namespace: string;\n\n constructor(namespace: string) {\n super(\n 'angular_missing_zod_namespace',\n `Zod artifact has no 'extra.perNamespace[${JSON.stringify(namespace)}]' entry`,\n );\n this.namespace = namespace;\n }\n}\n","/**\n * `angularGenerator` — the `@kurotako/gen-angular` driver.\n *\n * Hard `dependsOn: ['zod']`: core rejects a config that enables `angular`\n * without `zod`, and the topological order guarantees `ctx.dependencies.zod` is\n * always present here. `generate` is synchronous and pure: same IR + same Zod\n * artifact + same options -> deep-equal `GenOutput` (drift-guard requirement).\n */\nimport { defineGenerator } from '@kurotako/config';\nimport type { GenerateContext, GenOutput, VirtualFile } from '@kurotako/core';\nimport { buildArtifact } from './artifact.js';\nimport { emitBarrel } from './emit/barrel.js';\nimport { emitEntity } from './emit/entity.js';\nimport { emitRuntime } from './emit/runtime.js';\nimport { AngularGeneratorOptions } from './options.js';\n\nexport const angularGenerator = defineGenerator({\n name: 'angular',\n dependsOn: ['zod'],\n optionsSchema: AngularGeneratorOptions,\n\n generate(ctx: GenerateContext, options): GenOutput {\n const zod = ctx.dependencies.zod;\n if (zod === undefined) {\n throw new Error(\n \"gen-angular: 'zod' dependency artifact is missing at runtime despite dependsOn: ['zod']\",\n );\n }\n\n const files: VirtualFile[] = [];\n\n for (const [namespace, source] of Object.entries(ctx.ir.sources)) {\n const prefix = `${namespace}/angular`;\n const entities = Object.values(source.entities);\n\n if (entities.length > 0 && options.forms.length > 0) {\n files.push({\n path: `${prefix}/zod-forms.runtime.ts`,\n content: emitRuntime(source, options),\n });\n }\n for (const entity of entities) {\n files.push({\n path: `${prefix}/${entity.name}.form.ts`,\n content: emitEntity(\n entity,\n namespace,\n source,\n options,\n zod,\n ctx.logger,\n ),\n });\n }\n files.push({\n path: `${prefix}/index.ts`,\n content: emitBarrel(source, options),\n });\n }\n\n return { files, artifact: buildArtifact(ctx.ir, zod, options) };\n },\n});\n","/**\n * Assemble the `GeneratorArtifact` (entities symbol matrix +\n * `AngularArtifactExtra`). No generator depends on `angular` in v1; the\n * artifact exists for uniformity and future consumers\n * (`generator-angular/technical.md` §Artifact).\n */\nimport type { EntitySymbols, GeneratorArtifact } from '@kurotako/core';\nimport type { IR } from '@kurotako/ir';\nimport { iterEntities } from '@kurotako/ir';\nimport {\n barrelModule,\n controlsTypeName,\n entityModule,\n factoryName,\n formTypeName,\n modelFactoryName,\n runtimeModule,\n signalFormFactoryName,\n signalSchemaName,\n} from './names.js';\nimport type { AngularGeneratorOptions } from './options.js';\nimport { zodExtra } from './zod-artifact.js';\n\nexport interface AngularArtifactExtra {\n forms: ('reactive' | 'signal')[];\n relations: 'flat' | 'deep';\n /** Echoed from the consumed `ZodArtifactExtra`. */\n zodVersion: 3 | 4;\n perNamespace: Record<\n string,\n {\n runtimeModule: string;\n barrelModule: string;\n }\n >;\n}\n\nfunction entitySymbols(\n entityName: string,\n options: AngularGeneratorOptions,\n): Record<string, string> {\n const symbols: Record<string, string> = {};\n const deep = options.relations === 'deep';\n const family = deep ? 'Deep' : ('' as const);\n\n if (options.forms.includes('reactive')) {\n const createControls = controlsTypeName(entityName, 'Create', family);\n const createForm = formTypeName(entityName, 'Create', family);\n const updateControls = controlsTypeName(entityName, 'Update', family);\n const updateForm = formTypeName(entityName, 'Update', family);\n\n symbols.createControls = createControls;\n symbols.createForm = createForm;\n symbols.updateControls = updateControls;\n symbols.updateForm = updateForm;\n symbols.factory = factoryName(entityName);\n\n if (deep) {\n symbols.createDeepControls = createControls;\n symbols.createDeepForm = createForm;\n symbols.updateDeepControls = updateControls;\n symbols.updateDeepForm = updateForm;\n }\n }\n\n if (options.forms.includes('signal')) {\n symbols.createSchema = signalSchemaName(entityName, 'Create');\n symbols.updateSchema = signalSchemaName(entityName, 'Update');\n symbols.createModel = modelFactoryName(entityName, 'Create');\n symbols.updateModel = modelFactoryName(entityName, 'Update');\n symbols.createSignalForm = signalFormFactoryName(entityName, 'Create');\n symbols.updateSignalForm = signalFormFactoryName(entityName, 'Update');\n }\n\n return symbols;\n}\n\nexport function buildArtifact(\n ir: IR,\n zod: GeneratorArtifact,\n options: AngularGeneratorOptions,\n): GeneratorArtifact {\n const entities: Record<string, EntitySymbols> = {};\n for (const { namespace, entity } of iterEntities(ir)) {\n entities[`${namespace}.${entity.name}`] = {\n module: entityModule(namespace, entity.name),\n symbols: entitySymbols(entity.name, options),\n };\n }\n\n const perNamespace: AngularArtifactExtra['perNamespace'] = {};\n for (const namespace of Object.keys(ir.sources)) {\n perNamespace[namespace] = {\n runtimeModule: runtimeModule(namespace),\n barrelModule: barrelModule(namespace),\n };\n }\n\n const extra: AngularArtifactExtra = {\n forms: options.forms,\n relations: options.relations,\n zodVersion: zodExtra(zod).zodVersion,\n perNamespace,\n };\n\n const peerDependencies = options.forms.includes('signal')\n ? { '@angular/core': '>=22', '@angular/forms': '>=22' }\n : { '@angular/core': '>=17', '@angular/forms': '>=17' };\n\n return { entities, peerDependencies, extra };\n}\n","/**\n * Deterministic identifier and module-specifier helpers.\n *\n * Identifiers are never namespace-prefixed (ADR-0004); the namespace only drives\n * the output location. The `angular/` sub-tree segment on every module specifier\n * is the output-modes amendment (one sub-tree per generator).\n */\n\n/** PascalCase form-variant token embedded in an identifier. */\nexport type Variant = 'Create' | 'Update';\n\n/** Relation family token embedded in a control-tree identifier. */\nexport type Family = '' | 'Deep';\n\nfunction lowerFirst(s: string): string {\n return s.length === 0 ? s : s.charAt(0).toLowerCase() + s.slice(1);\n}\n\n/** `${Entity}${Variant}${Family}FormControls`. */\nexport function controlsTypeName(\n entity: string,\n variant: Variant,\n family: Family = '',\n): string {\n return `${entity}${variant}${family}FormControls`;\n}\n\n/** `${Entity}${Variant}${Family}Form` — the `FormGroup<...>` type alias. */\nexport function formTypeName(\n entity: string,\n variant: Variant,\n family: Family = '',\n): string {\n return `${entity}${variant}${family}Form`;\n}\n\n/** `${Entity}FormFactory` — one `@Injectable` service per entity. */\nexport function factoryName(entity: string): string {\n return `${entity}FormFactory`;\n}\n\n/** `create${Variant}Form` — the factory method name. No suffix in deep mode. */\nexport function factoryMethod(variant: Variant): string {\n return `create${variant}Form`;\n}\n\n/**\n * `add${Relation}${Variant}` — the deep-mode nested-control builder method.\n * Variant-suffixed: `UserFormFactory` builds both `Create` and `Update` trees,\n * and a relation's target control type differs between them, so the two\n * variants cannot share one method name (would collide as a duplicate\n * implementation).\n */\nexport function relationBuilderMethod(\n relationName: string,\n variant: Variant,\n): string {\n const cap = `${relationName.charAt(0).toUpperCase()}${relationName.slice(1)}`;\n return `add${cap}${variant}`;\n}\n\n/** `${entity}${Variant}FormSchema`, camelCase — the Signal Forms schema const. */\nexport function signalSchemaName(entity: string, variant: Variant): string {\n return `${lowerFirst(entity)}${variant}FormSchema`;\n}\n\n/** `create${Entity}${Variant}Model` — the Signal Forms model-factory function. */\nexport function modelFactoryName(entity: string, variant: Variant): string {\n return `create${entity}${variant}Model`;\n}\n\n/**\n * `create${Entity}${Variant}Form` — the Signal Forms `form(signal(model), schema)`\n * convenience wrapper. Safe to call from anywhere `inject()` would work (a\n * component field initializer or constructor): `form()` resolves its\n * injector from the ambient injection context when none is passed\n * explicitly, same as calling it inline.\n */\nexport function signalFormFactoryName(\n entity: string,\n variant: Variant,\n): string {\n return `create${entity}${variant}Form`;\n}\n\n// --- module specifiers (POSIX, extension-less) -------------------------------\n\n/** `${ns}/angular/${entity}.form`. */\nexport function entityModule(namespace: string, entity: string): string {\n return `${namespace}/angular/${entity}.form`;\n}\n\n/** `${ns}/angular/zod-forms.runtime`. */\nexport function runtimeModule(namespace: string): string {\n return `${namespace}/angular/zod-forms.runtime`;\n}\n\n/** `${ns}/angular` — this generator's own sub-tree barrel. */\nexport function barrelModule(namespace: string): string {\n return `${namespace}/angular`;\n}\n","/**\n * Typed reader over `ctx.dependencies.zod` (the `GeneratorArtifact` produced by\n * `@kurotako/gen-zod`). `dependsOn: ['zod']` guarantees the entry is present;\n * this module only resolves identifiers + module specifiers, never re-derives a\n * Zod name (`generator-angular/technical.md` §Naming).\n *\n * Role keys consumed here (a subset of `gen-zod`'s full matrix): `createSchema`,\n * `createType`, `updateSchema`, `updateType`, and — in `relations: 'deep'` mode\n * only — `createDeepSchema`, `createDeepType`, `updateDeepSchema`,\n * `updateDeepType`.\n */\nimport type { EntitySymbols, GeneratorArtifact } from '@kurotako/core';\nimport type { ZodArtifactExtra } from '@kurotako/gen-zod';\nimport { MissingZodNamespaceError, MissingZodSymbolError } from './errors.js';\n\nexport type ZodRole =\n | 'createSchema'\n | 'createType'\n | 'updateSchema'\n | 'updateType'\n | 'createDeepSchema'\n | 'createDeepType'\n | 'updateDeepSchema'\n | 'updateDeepType';\n\n/** `${namespace}.${entity}` — the artifact's entity key. */\nexport function entityKey(namespace: string, entity: string): string {\n return `${namespace}.${entity}`;\n}\n\n/** The Zod `{ module, symbols }` entry for an entity, or throw if absent. */\nexport function zodEntity(\n zod: GeneratorArtifact,\n namespace: string,\n entity: string,\n): EntitySymbols {\n const key = entityKey(namespace, entity);\n const entry = zod.entities[key];\n if (entry === undefined) {\n throw new MissingZodSymbolError(key, '<entity>');\n }\n return entry;\n}\n\n/** Resolve one `role` on an entity to its Zod-emitted identifier. */\nexport function zodSymbol(\n zod: GeneratorArtifact,\n namespace: string,\n entity: string,\n role: ZodRole,\n): string {\n const key = entityKey(namespace, entity);\n const entry = zodEntity(zod, namespace, entity);\n const id = entry.symbols[role];\n if (id === undefined) {\n throw new MissingZodSymbolError(key, role);\n }\n return id;\n}\n\n/** The module specifier a sibling generator imports an entity's Zod schema from. */\nexport function zodModule(\n zod: GeneratorArtifact,\n namespace: string,\n entity: string,\n): string {\n return zodEntity(zod, namespace, entity).module;\n}\n\n/** `zod.extra`, cast to the published `ZodArtifactExtra` shape. */\nexport function zodExtra(zod: GeneratorArtifact): ZodArtifactExtra {\n return zod.extra as ZodArtifactExtra;\n}\n\n/** `extra.perNamespace[ns]`, or throw if the Zod artifact never saw that namespace. */\nexport function zodNamespaceExtra(\n zod: GeneratorArtifact,\n namespace: string,\n): ZodArtifactExtra['perNamespace'][string] {\n const per = zodExtra(zod).perNamespace[namespace];\n if (per === undefined) {\n throw new MissingZodNamespaceError(namespace);\n }\n return per;\n}\n\n/** `{ typeName, module }` for an enum ref, resolved via `extra.perNamespace[ns].enums`. */\nexport function zodEnum(\n zod: GeneratorArtifact,\n namespace: string,\n ref: string,\n): { typeName: string; module: string } {\n const per = zodNamespaceExtra(zod, namespace);\n const def = per.enums[ref];\n if (def === undefined) {\n throw new MissingZodSymbolError(`${namespace}.<enum>`, ref);\n }\n return { typeName: def.typeName, module: def.module };\n}\n","/**\n * `<ns>/angular/index.ts` — this generator's own sub-tree barrel. Re-exports\n * `./zod-forms.runtime` (when emitted) and every `./<entity>.form`. A\n * zero-entity source still yields a valid `index.ts`.\n */\nimport type { SourceIR } from '@kurotako/ir';\nimport type { AngularGeneratorOptions } from '../options.js';\n\nexport function emitBarrel(\n source: SourceIR,\n options: AngularGeneratorOptions,\n): string {\n const lines: string[] = [];\n const entities = Object.values(source.entities);\n\n if (entities.length > 0 && options.forms.length > 0) {\n lines.push(\"export * from './zod-forms.runtime';\");\n }\n for (const entity of entities) {\n lines.push(`export * from './${entity.name}.form';`);\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n","/**\n * Import-block accumulator shared by `render/reactive.ts`, `render/signal.ts`\n * and `emit/entity.ts`. Collects the module specifiers + identifiers a rendered\n * entity file needs while it is being assembled, so the final `import` block can\n * be built once, sorted, and split into value vs. type-only lines\n * (`generator-angular/technical.md` §Determinism: import lines sorted by module\n * specifier, named imports sorted).\n */\n\nexport class ImportsRecorder {\n private readonly values = new Map<string, Set<string>>();\n private readonly types = new Map<string, Set<string>>();\n\n value(module: string, name: string): void {\n add(this.values, module, name);\n }\n\n type(module: string, name: string): void {\n add(this.types, module, name);\n }\n\n /** The full `import ...` block text, one statement per line, no trailing blank line. */\n render(): string {\n const lines: { spec: string; rank: 0 | 1; stmt: string }[] = [];\n for (const [spec, names] of this.values) {\n lines.push({ spec, rank: 0, stmt: importStmt(spec, [...names], false) });\n }\n for (const [spec, names] of this.types) {\n lines.push({ spec, rank: 1, stmt: importStmt(spec, [...names], true) });\n }\n lines.sort((a, b) => a.spec.localeCompare(b.spec) || a.rank - b.rank);\n return lines.map((l) => l.stmt).join('\\n');\n }\n}\n\nfunction add(\n map: Map<string, Set<string>>,\n module: string,\n name: string,\n): void {\n const set = map.get(module) ?? new Set<string>();\n set.add(name);\n map.set(module, set);\n}\n\nfunction importStmt(spec: string, names: string[], typeOnly: boolean): string {\n const sorted = [...names].sort((a, b) => a.localeCompare(b)).join(', ');\n const kw = typeOnly ? 'import type' : 'import';\n return `${kw} { ${sorted} } from '${spec}';`;\n}\n","/**\n * `Field` -> typed `FormControl<T>` control-tree text.\n *\n * `T` mirrors the Zod-inferred type of the field, reconstructed from the IR\n * `Field` directly (never by parsing Zod source text) — see\n * `generator-angular/technical.md` §Control type per scalar.\n */\nimport type { Entity, Field, ScalarType, SourceIR } from '@kurotako/ir';\nimport { resolveEnum } from '@kurotako/ir';\nimport type { Variant } from '../names.js';\n\n/** Resolve an enum ref (`FieldType.kind === 'enum'`) to the Zod-emitted union type name. */\nexport type ZodEnumTypeName = (ref: string) => string;\n\nconst SCALAR_BASE: Record<ScalarType, string> = {\n string: 'string',\n uuid: 'string',\n decimal: 'string',\n bytes: 'string',\n int: 'number',\n float: 'number',\n bigint: 'bigint',\n boolean: 'boolean',\n date: 'Date',\n datetime: 'Date',\n json: 'unknown',\n};\n\nfunction baseType(field: Field, zodEnumTypeName: ZodEnumTypeName): string {\n switch (field.type.kind) {\n case 'scalar':\n return SCALAR_BASE[field.type.scalar];\n case 'enum':\n return zodEnumTypeName(field.type.ref);\n case 'unknown':\n return 'unknown';\n }\n}\n\n/** The `FormControl<T>` type argument for a field: `list` wraps, then `nullable`. */\nexport function controlType(\n field: Field,\n zodEnumTypeName: ZodEnumTypeName,\n): string {\n let t = baseType(field, zodEnumTypeName);\n if (field.list) {\n t = `${t}[]`;\n }\n if (field.nullable) {\n t = `${t} | null`;\n }\n return t;\n}\n\n/** Resolve an enum ref to a real member literal for `initExpr`'s enum zero. */\nexport type EnumZero = (ref: string) => string | undefined;\n\n/** `EnumZero` backed by the IR: the enum's first declared member, in source order. */\nexport function enumZeroFromSource(source: SourceIR, entity: Entity): EnumZero {\n return (ref) => resolveEnum(source, entity, ref)?.values[0]?.name;\n}\n\n/**\n * A valid, always-assignable non-null literal for the field's base type. Never\n * `null` — the Zod-inferred DTO type for a field with no literal default is\n * `T` (required) or `T | undefined` (optional), never `T | null`; only a\n * `field.nullable` field's DTO type includes `null`, and `initExpr` handles\n * that case itself rather than folding it in here.\n */\nfunction zeroValue(field: Field, enumZero?: EnumZero): string {\n if (field.type.kind === 'scalar') {\n switch (field.type.scalar) {\n case 'string':\n case 'uuid':\n case 'decimal':\n case 'bytes':\n return \"''\";\n case 'int':\n case 'float':\n return '0';\n case 'bigint':\n return '0n';\n case 'boolean':\n return 'false';\n case 'date':\n case 'datetime':\n return 'new Date(0)';\n case 'json':\n // control type is `unknown`: `| undefined` is trivially assignable.\n return 'undefined';\n }\n }\n if (field.type.kind === 'enum') {\n // Unlike a scalar zero, `x ?? undefined` never actually strips\n // `| undefined` from `x`'s type (TS keeps it, since the fallback's own\n // type still includes it) — so a non-nullable enum control with no\n // literal default needs a *real* member literal, not `undefined`, or\n // `new FormControl(..., { nonNullable: true })` fails to type-check\n // against the field's exact union type.\n const value = enumZero?.(field.type.ref);\n return value === undefined ? 'undefined' : JSON.stringify(value);\n }\n return 'undefined';\n}\n\n/** The control's initial-value expression: a literal default, else the type's zero. */\nexport function initExpr(field: Field, enumZero?: EnumZero): string {\n if (field.list) {\n return field.default?.kind === 'value'\n ? JSON.stringify(field.default.value)\n : '[]';\n }\n if (field.default?.kind === 'value') {\n return JSON.stringify(field.default.value);\n }\n if (field.nullable) {\n return 'null';\n }\n return zeroValue(field, enumZero);\n}\n\n/**\n * `new FormControl(...)` construction expression for a field.\n * `typeArg` is the field's already-resolved `controlType(...)` text; `sourceExpr`\n * is the value expression to seed the control from (an `init?.x ?? <zero>` for\n * `Create`, a bare `value.x` for `Update` — the caller decides). `sourceExpr` is\n * already `null`-inclusive when `field.nullable` (via `initExpr`'s own fallback,\n * or the Update DTO's own field type) — appending another `?? null` here would\n * be provably-redundant code TS flags as an error (`This expression is never\n * nullish`), not just dead weight.\n */\nexport function controlExpr(\n field: Field,\n typeArg: string,\n sourceExpr: string,\n): string {\n if (field.nullable) {\n return `new FormControl<${typeArg}>(${sourceExpr})`;\n }\n return `new FormControl(${sourceExpr}, { nonNullable: true })`;\n}\n\nexport interface ControlEntry {\n name: string;\n /** The full control-tree member type, e.g. `FormControl<string>` or (deep mode) `FormGroup<PostCreateDeepFormControls>`. */\n fullType: string;\n}\n\n/** One `ControlEntry` for a scalar/enum field: `name: FormControl<T>`. */\nexport function fieldControlEntry(\n field: Field,\n zodEnumTypeName: ZodEnumTypeName,\n): ControlEntry {\n return {\n name: field.name,\n fullType: `FormControl<${controlType(field, zodEnumTypeName)}>`,\n };\n}\n\n/** `export interface <Entity><Variant>[Deep]FormControls { ... }` text. */\nexport function controlsInterface(\n interfaceName: string,\n entries: ControlEntry[],\n): string {\n if (entries.length === 0) {\n return `export interface ${interfaceName} {}`;\n }\n const body = entries.map((e) => ` ${e.name}: ${e.fullType};`).join('\\n');\n return `export interface ${interfaceName} {\\n${body}\\n}`;\n}\n\nexport type { Variant };\n","/**\n * `relations: 'deep'` control-tree entries: nested `FormGroup` for a to-one\n * relation, `FormArray` for a to-many one. `relations: 'flat'` (default) emits\n * nothing for relation objects — the caller simply never calls this module\n * (`generator-angular/technical.md` §Relations).\n *\n * Cross-source relations always degrade to flat (FK scalar only) + a `debug`\n * log, consistent with `gen-zod`'s deep family.\n */\nimport type { Logger } from '@kurotako/core';\nimport type { Entity, Relation } from '@kurotako/ir';\nimport { isCrossSource } from '@kurotako/ir';\nimport type { Variant } from '../names.js';\nimport {\n controlsTypeName,\n formTypeName,\n relationBuilderMethod,\n} from '../names.js';\nimport type { ControlEntry } from './controls.js';\n\nexport interface DeepRelation {\n relation: Relation;\n many: boolean;\n /** The `ControlEntry` this relation contributes to the deep control-tree interface. */\n entry: ControlEntry;\n /** `<Target><Variant>DeepForm` — the target's `FormGroup<...>` type alias. */\n targetFormType: string;\n /** `add<Relation><Variant>` — the builder method name on the reactive factory. */\n builderMethod: string;\n}\n\n/**\n * Every non-cross-source relation on `entity`, rendered as a deep control-tree\n * entry. Cross-source relations are skipped (flat degrade) and logged.\n */\nexport function deepRelations(\n entity: Entity,\n variant: Variant,\n namespace: string,\n logger?: Logger,\n): DeepRelation[] {\n const out: DeepRelation[] = [];\n for (const relation of entity.relations) {\n if (isCrossSource(namespace, relation)) {\n logger?.debug(\n `gen-angular: relation '${relation.name}' targets another source ('${relation.target.namespace}.${relation.target.entity}'); degrading to the flat FK scalar in deep mode`,\n );\n continue;\n }\n\n const many = relation.cardinality === 'many';\n const targetControls = controlsTypeName(\n relation.target.entity,\n variant,\n 'Deep',\n );\n const targetFormType = formTypeName(\n relation.target.entity,\n variant,\n 'Deep',\n );\n const groupType = `FormGroup<${targetControls}>`;\n const fullType = many ? `FormArray<${groupType}>` : groupType;\n\n out.push({\n relation,\n many,\n entry: { name: relation.name, fullType },\n targetFormType,\n builderMethod: relationBuilderMethod(relation.name, variant),\n });\n }\n return out;\n}\n","/**\n * Per-entity field-set derivation for the two form variants.\n *\n * The `Create` / `Update` field selection comes from `@kurotako/ir`'s\n * shared-decision helpers (`createFields`, `updateFields`) — the same helpers\n * `gen-zod` calls — so the control tree and the Zod schema it delegates\n * validation to agree by construction, not by two implementations happening to\n * match (`generator-angular/technical.md` §Variant field sets).\n */\nimport type { Entity, Field } from '@kurotako/ir';\nimport { createFields, updateFields } from '@kurotako/ir';\nimport type { Variant } from '../names.js';\n\n/** The scalar/enum field set for a form variant, in IR declaration order. */\nexport function variantFields(entity: Entity, variant: Variant): Field[] {\n return variant === 'Create' ? createFields(entity) : updateFields(entity);\n}\n","/**\n * Reactive typed-forms surface: control-tree interfaces, `FormGroup` type\n * aliases, and one `@Injectable({ providedIn: 'root' })` factory service per\n * entity (`generator-angular/technical.md` §Reactive factory service).\n *\n * `relations: 'deep'`: Angular's `FormGroup<TControl>` requires every control\n * to be a concrete `AbstractControl` — a control key typed `FormGroup<X> |\n * undefined` fails `FormGroup`'s own generic constraint — so a to-one\n * relation's nested group is built eagerly, by delegating to the target\n * entity's own injected `FormFactory`. A to-many relation's `FormArray`\n * starts empty (no eager nested item), which is what keeps a realistic\n * (many-side-breaks-the-cycle) entity graph from recursing forever; a\n * required one-to-one cycle on both sides would still recurse at runtime —\n * accepted, rare/pathological shape, same spirit as `gen-zod`'s deep-family\n * limitations. `add<Relation><Variant>()` methods let the consumer replace a\n * to-one nested group or push a new to-many item after construction.\n */\nimport type { GeneratorArtifact, Logger } from '@kurotako/core';\nimport type { Entity, SourceIR } from '@kurotako/ir';\nimport {\n controlsTypeName,\n factoryMethod,\n factoryName,\n formTypeName,\n type Variant,\n} from '../names.js';\nimport type { AngularGeneratorOptions } from '../options.js';\nimport { zodEnum, zodModule, zodSymbol } from '../zod-artifact.js';\nimport {\n type ControlEntry,\n controlExpr,\n controlsInterface,\n controlType,\n type EnumZero,\n enumZeroFromSource,\n fieldControlEntry,\n initExpr,\n} from './controls.js';\nimport type { ImportsRecorder } from './imports.js';\nimport { deepRelations } from './relations.js';\nimport { variantFields } from './variants.js';\n\nfunction lowerFirst(s: string): string {\n return s.length === 0 ? s : s.charAt(0).toLowerCase() + s.slice(1);\n}\n\nexport function reactiveEntity(\n entity: Entity,\n namespace: string,\n source: SourceIR,\n options: AngularGeneratorOptions,\n zod: GeneratorArtifact,\n imports: ImportsRecorder,\n logger?: Logger,\n): string {\n const deep = options.relations === 'deep';\n const enumZero = enumZeroFromSource(source, entity);\n imports.value('@angular/core', 'Injectable');\n imports.value('@angular/forms', 'FormControl');\n imports.value('@angular/forms', 'FormGroup');\n\n const zodEnumTypeName = (ref: string): string => {\n const e = zodEnum(zod, namespace, ref);\n imports.type(e.module, e.typeName);\n return e.typeName;\n };\n\n const blocks: string[] = [];\n const injectedFactories = new Map<string, string>(); // target entity -> ctor param name\n\n for (const variant of ['Create', 'Update'] as Variant[]) {\n const family = deep ? 'Deep' : '';\n const schemaRole = deep\n ? variant === 'Create'\n ? ('createDeepSchema' as const)\n : ('updateDeepSchema' as const)\n : variant === 'Create'\n ? ('createSchema' as const)\n : ('updateSchema' as const);\n const typeRole = deep\n ? variant === 'Create'\n ? ('createDeepType' as const)\n : ('updateDeepType' as const)\n : variant === 'Create'\n ? ('createType' as const)\n : ('updateType' as const);\n\n const module = zodModule(zod, namespace, entity.name);\n const schemaId = zodSymbol(zod, namespace, entity.name, schemaRole);\n const typeId = zodSymbol(zod, namespace, entity.name, typeRole);\n imports.value(module, schemaId);\n imports.type(module, typeId);\n imports.value(`${namespace}/angular/zod-forms.runtime`, 'zodValidator');\n\n const interfaceName = controlsTypeName(entity.name, variant, family);\n const formType = formTypeName(entity.name, variant, family);\n\n const fieldEntries: ControlEntry[] = variantFields(entity, variant).map(\n (field) => fieldControlEntry(field, zodEnumTypeName),\n );\n\n const relations = deep\n ? deepRelations(entity, variant, namespace, logger)\n : [];\n const manyRelations = relations.filter((r) => r.many);\n if (manyRelations.length > 0) {\n imports.value('@angular/forms', 'FormArray');\n }\n for (const rel of relations) {\n const targetModule = `${namespace}/angular/${rel.relation.target.entity}.form`;\n imports.type(\n targetModule,\n controlsTypeName(rel.relation.target.entity, variant, 'Deep'),\n );\n imports.type(targetModule, rel.targetFormType);\n if (!injectedFactories.has(rel.relation.target.entity)) {\n const paramName = `${lowerFirst(rel.relation.target.entity)}FormFactory`;\n injectedFactories.set(rel.relation.target.entity, paramName);\n imports.value(targetModule, factoryName(rel.relation.target.entity));\n }\n // The `add<Relation><Variant>()` builder (to-many only) takes an\n // `init` / `value` for the *target* entity's own create/update DTO.\n if (rel.many) {\n const targetTypeRole =\n deep && variant === 'Create'\n ? ('createDeepType' as const)\n : deep && variant === 'Update'\n ? ('updateDeepType' as const)\n : variant === 'Create'\n ? ('createType' as const)\n : ('updateType' as const);\n const targetZodModule = zodModule(\n zod,\n namespace,\n rel.relation.target.entity,\n );\n const targetTypeId = zodSymbol(\n zod,\n namespace,\n rel.relation.target.entity,\n targetTypeRole,\n );\n imports.type(targetZodModule, targetTypeId);\n }\n }\n\n blocks.push(\n controlsInterface(interfaceName, [\n ...fieldEntries,\n ...relations.map((r) => r.entry),\n ]),\n );\n blocks.push(`export type ${formType} = FormGroup<${interfaceName}>;`);\n }\n\n blocks.push(\n renderFactoryClass(\n entity,\n namespace,\n options,\n zod,\n injectedFactories,\n enumZero,\n ),\n );\n\n return blocks.join('\\n\\n');\n}\n\nfunction renderFactoryClass(\n entity: Entity,\n namespace: string,\n options: AngularGeneratorOptions,\n zod: GeneratorArtifact,\n injectedFactories: Map<string, string>,\n enumZero: EnumZero,\n): string {\n const deep = options.relations === 'deep';\n const className = factoryName(entity.name);\n\n const ctorParams = [...injectedFactories.entries()]\n .map(\n ([target, param]) => `private readonly ${param}: ${factoryName(target)}`,\n )\n .join(', ');\n const ctor =\n ctorParams.length > 0 ? `\\n constructor(${ctorParams}) {}\\n` : '';\n\n const methods: string[] = [];\n for (const variant of ['Create', 'Update'] as Variant[]) {\n methods.push(\n renderFactoryMethod(\n entity,\n namespace,\n variant,\n options,\n zod,\n injectedFactories,\n enumZero,\n ),\n );\n }\n\n if (deep) {\n for (const variant of ['Create', 'Update'] as Variant[]) {\n // Only the to-many side needs a builder: a to-one nested group is\n // already built eagerly (see the module docstring), and its target\n // factory's Update method requires a value this method has no natural\n // source for.\n const relations = deepRelations(\n entity,\n variant,\n namespace,\n undefined,\n ).filter((r) => r.many);\n for (const rel of relations) {\n methods.push(\n renderBuilderMethod(\n entity,\n namespace,\n variant,\n options,\n zod,\n rel,\n injectedFactories,\n ),\n );\n }\n }\n }\n\n const body = [\n ctor,\n ...methods.map((m) => `\\n ${m.split('\\n').join('\\n ')}\\n`),\n ]\n .join('')\n .trimEnd();\n\n return `@Injectable({ providedIn: 'root' })\\nexport class ${className} {\\n${body}\\n}`;\n}\n\nfunction renderFactoryMethod(\n entity: Entity,\n namespace: string,\n variant: Variant,\n options: AngularGeneratorOptions,\n zod: GeneratorArtifact,\n injectedFactories: Map<string, string>,\n enumZero: EnumZero,\n): string {\n const deep = options.relations === 'deep';\n const family = deep ? 'Deep' : '';\n const typeRole =\n deep && variant === 'Create'\n ? ('createDeepType' as const)\n : deep && variant === 'Update'\n ? ('updateDeepType' as const)\n : variant === 'Create'\n ? ('createType' as const)\n : ('updateType' as const);\n const schemaRole =\n deep && variant === 'Create'\n ? ('createDeepSchema' as const)\n : deep && variant === 'Update'\n ? ('updateDeepSchema' as const)\n : variant === 'Create'\n ? ('createSchema' as const)\n : ('updateSchema' as const);\n\n const typeId = zodSymbol(zod, namespace, entity.name, typeRole);\n const schemaId = zodSymbol(zod, namespace, entity.name, schemaRole);\n const interfaceName = controlsTypeName(entity.name, variant, family);\n const formType = formTypeName(entity.name, variant, family);\n const methodName = factoryMethod(variant);\n\n const zodEnumTypeName = (ref: string): string => ref;\n const fields = variantFields(entity, variant);\n const lines = fields.map((field) => {\n const typeArg = controlType(field, zodEnumTypeName);\n // The Update Zod DTO is a whole-object `.partial()` (gen-zod), so every\n // field — including one that is otherwise required — is `T | undefined`\n // there too; both variants therefore need the same `?? <zero>` fallback.\n const accessor =\n variant === 'Create' ? `init?.${field.name}` : `value.${field.name}`;\n const source = `${accessor} ?? ${initExpr(field, enumZero)}`;\n return ` ${field.name}: ${controlExpr(field, typeArg, source)},`;\n });\n\n const relations = deep\n ? deepRelations(entity, variant, namespace, undefined)\n : [];\n const relationLines = relations.map((r) => {\n if (r.many) {\n const targetControls = controlsTypeName(\n r.relation.target.entity,\n variant,\n 'Deep',\n );\n return ` ${r.entry.name}: new FormArray<FormGroup<${targetControls}>>([]),`;\n }\n const factoryParam =\n injectedFactories.get(r.relation.target.entity) ??\n `${lowerFirst(r.relation.target.entity)}FormFactory`;\n // The Update DTO's whole-object `.partial()` also makes a required\n // relation optional at the type level (same as scalar fields above);\n // `createUpdateForm` itself still requires a concrete value, so the\n // caller is expected to supply the nested relation on a value it read\n // back — asserted here rather than defaulted (there is no meaningful\n // \"empty\" nested entity to fall back to).\n const nestedArg =\n variant === 'Create'\n ? `init?.${r.relation.name}`\n : `value.${r.relation.name}!`;\n return ` ${r.entry.name}: this.${factoryParam}.${factoryMethod(variant)}(${nestedArg}),`;\n });\n\n const groupBody = [...lines, ...relationLines].join('\\n');\n const paramList =\n variant === 'Create' ? `init?: Partial<${typeId}>` : `value: ${typeId}`;\n\n return `${methodName}(${paramList}): ${formType} {\\n return new FormGroup<${interfaceName}>({\\n${groupBody}\\n }, { validators: [zodValidator(${schemaId})] });\\n}`;\n}\n\n/** Only ever called for a to-many relation (see the caller). */\nfunction renderBuilderMethod(\n entity: Entity,\n namespace: string,\n variant: Variant,\n options: AngularGeneratorOptions,\n zod: GeneratorArtifact,\n rel: ReturnType<typeof deepRelations>[number],\n injectedFactories: Map<string, string>,\n): string {\n const deep = options.relations === 'deep';\n const target = rel.relation.target.entity;\n const factoryParam =\n injectedFactories.get(target) ?? `${lowerFirst(target)}FormFactory`;\n const formType = formTypeName(entity.name, variant, 'Deep');\n const targetFormType = rel.targetFormType;\n const method = rel.builderMethod;\n\n const targetTypeRole =\n deep && variant === 'Create'\n ? ('createDeepType' as const)\n : deep && variant === 'Update'\n ? ('updateDeepType' as const)\n : variant === 'Create'\n ? ('createType' as const)\n : ('updateType' as const);\n const targetTypeId = zodSymbol(zod, namespace, target, targetTypeRole);\n\n const param =\n variant === 'Create'\n ? `init?: Partial<${targetTypeId}>`\n : `value: ${targetTypeId}`;\n const createCall = `this.${factoryParam}.${factoryMethod(variant)}(${variant === 'Create' ? 'init' : 'value'})`;\n\n return `${method}(form: ${formType}, ${param}): ${targetFormType} {\\n const group = ${createCall};\\n form.controls.${rel.relation.name}.push(group);\\n return group;\\n}`;\n}\n","/**\n * Signal Forms surface: pure exported `schema` + model-factory functions, no DI\n * wrapper (`generator-angular/technical.md` §Signal Forms schema + model\n * factory), plus a `create<Entity><Variant>Form` convenience wrapper around\n * `form(signal(model), schema)`. Every `@angular/forms/signals` call site\n * lives here and in `emit/runtime.ts` (the `zodTreeValidate` half) so a\n * secondary-API change on that experimental surface is a single-file update.\n *\n * The wrapper is a plain function, not a DI service — `form()` resolves its\n * injector from Angular's ambient injection context when none is passed\n * explicitly (same rule `inject()` follows), so calling the wrapper from a\n * component field initializer or constructor works exactly like calling\n * `form()` inline there.\n */\nimport type { GeneratorArtifact, Logger } from '@kurotako/core';\nimport type { Entity, SourceIR } from '@kurotako/ir';\nimport {\n modelFactoryName,\n signalFormFactoryName,\n signalSchemaName,\n type Variant,\n} from '../names.js';\nimport type { AngularGeneratorOptions } from '../options.js';\nimport { zodModule, zodSymbol } from '../zod-artifact.js';\nimport { enumZeroFromSource, initExpr } from './controls.js';\nimport type { ImportsRecorder } from './imports.js';\nimport { deepRelations } from './relations.js';\nimport { variantFields } from './variants.js';\n\nexport function signalEntity(\n entity: Entity,\n namespace: string,\n source: SourceIR,\n options: AngularGeneratorOptions,\n zod: GeneratorArtifact,\n imports: ImportsRecorder,\n logger?: Logger,\n): string {\n const deep = options.relations === 'deep';\n const enumZero = enumZeroFromSource(source, entity);\n imports.value('@angular/forms/signals', 'schema');\n imports.value('@angular/forms/signals', 'form');\n imports.type('@angular/forms/signals', 'FieldTree');\n imports.value('@angular/core', 'signal');\n\n const blocks: string[] = [];\n for (const variant of ['Create', 'Update'] as Variant[]) {\n const typeRole =\n deep && variant === 'Create'\n ? ('createDeepType' as const)\n : deep && variant === 'Update'\n ? ('updateDeepType' as const)\n : variant === 'Create'\n ? ('createType' as const)\n : ('updateType' as const);\n const schemaRole =\n deep && variant === 'Create'\n ? ('createDeepSchema' as const)\n : deep && variant === 'Update'\n ? ('updateDeepSchema' as const)\n : variant === 'Create'\n ? ('createSchema' as const)\n : ('updateSchema' as const);\n\n const module = zodModule(zod, namespace, entity.name);\n const typeId = zodSymbol(zod, namespace, entity.name, typeRole);\n const schemaId = zodSymbol(zod, namespace, entity.name, schemaRole);\n imports.type(module, typeId);\n imports.value(module, schemaId);\n imports.value(`${namespace}/angular/zod-forms.runtime`, 'zodTreeValidate');\n\n const fields = variantFields(entity, variant);\n const fieldLines = fields.map(\n (field) =>\n ` ${field.name}: init?.${field.name} ?? ${initExpr(field, enumZero)},`,\n );\n\n const relations = deep\n ? deepRelations(entity, variant, namespace, logger)\n : [];\n // A to-one relation the Zod deep DTO marks required (any relation that\n // isn't itself optional, in the Create variant) can't be seeded with\n // `undefined` — build it eagerly via the target's own model factory\n // instead, imported as a value from its `.form` module.\n const relationLines = relations.map((rel) => {\n if (rel.many) {\n return ` ${rel.relation.name}: [],`;\n }\n const targetModule = `${namespace}/angular/${rel.relation.target.entity}.form`;\n const targetModelFactory = modelFactoryName(\n rel.relation.target.entity,\n variant,\n );\n imports.value(targetModule, targetModelFactory);\n return ` ${rel.relation.name}: ${targetModelFactory}(init?.${rel.relation.name}),`;\n });\n\n const modelBody = [...fieldLines, ...relationLines].join('\\n');\n const modelName = modelFactoryName(entity.name, variant);\n blocks.push(\n `export function ${modelName}(init?: Partial<${typeId}>): ${typeId} {\\n return {\\n${modelBody}\\n };\\n}`,\n );\n\n const schemaConst = signalSchemaName(entity.name, variant);\n blocks.push(\n `export const ${schemaConst} = schema<${typeId}>((path) => {\\n zodTreeValidate(path, ${schemaId});\\n});`,\n );\n\n const formFactoryName = signalFormFactoryName(entity.name, variant);\n blocks.push(\n `export function ${formFactoryName}(init?: Partial<${typeId}>): FieldTree<${typeId}> {\\n return form(signal(${modelName}(init)), ${schemaConst});\\n}`,\n );\n }\n\n return blocks.join('\\n\\n');\n}\n","/**\n * One entity -> `<ns>/angular/<entity>.form.ts` source text: a sorted import\n * block, then the reactive block (control-tree interfaces + `@Injectable`\n * factory, when `forms` includes `'reactive'`) and the Signal Forms block\n * (schema + model factory, when `forms` includes `'signal'`)\n * (`generator-angular/technical.md` §File layout).\n */\nimport type { GeneratorArtifact, Logger } from '@kurotako/core';\nimport type { Entity, SourceIR } from '@kurotako/ir';\nimport type { AngularGeneratorOptions } from '../options.js';\nimport { ImportsRecorder } from '../render/imports.js';\nimport { reactiveEntity } from '../render/reactive.js';\nimport { signalEntity } from '../render/signal.js';\n\nexport function emitEntity(\n entity: Entity,\n namespace: string,\n source: SourceIR,\n options: AngularGeneratorOptions,\n zod: GeneratorArtifact,\n logger?: Logger,\n): string {\n const imports = new ImportsRecorder();\n const blocks: string[] = [];\n\n if (options.forms.includes('reactive')) {\n blocks.push(\n reactiveEntity(entity, namespace, source, options, zod, imports, logger),\n );\n }\n if (options.forms.includes('signal')) {\n blocks.push(\n signalEntity(entity, namespace, source, options, zod, imports, logger),\n );\n }\n\n const importBlock = imports.render();\n return `${[importBlock, '', ...blocks].join('\\n').trimEnd()}\\n`;\n}\n","/**\n * `<ns>/angular/zod-forms.runtime.ts` — hand-written, deterministic source (no\n * per-entity content). Emitted once per namespace whenever the source has >= 1\n * entity and `forms` is non-empty (`generator-angular/technical.md` §File\n * layout).\n *\n * `zodValidator` (reactive half): a group-level `ValidatorFn` that\n * `safeParse`s against the Zod schema and distributes each issue onto the\n * matching descendant control by `issue.path`, clearing stale `zod` keys and\n * guarding against a `setErrors`-triggered validation loop\n * (`generator-angular/technical.md` §`zodValidator`).\n *\n * `zodTreeValidate` (Signal Forms half): wraps `@angular/forms/signals`'\n * tree-level validator primitive. This is the *only* file (besides\n * `render/signal.ts`) referencing that experimental surface, so a secondary-API\n * shift on a future Angular minor is a single-file update\n * (`generator-angular/technical.md` §Signal Forms schema + model factory).\n */\nimport type { SourceIR } from '@kurotako/ir';\nimport type { AngularGeneratorOptions } from '../options.js';\n\nconst ZOD_VALIDATOR = `export function zodValidator(schema: ZodType): ValidatorFn {\n return (group: AbstractControl) => {\n const result = schema.safeParse(group.getRawValue());\n const touched = new Set<AbstractControl>();\n const rootIssues: { path: (string | number)[]; message: string }[] = [];\n\n if (!result.success) {\n for (const issue of result.error.issues) {\n const path = issue.path.map(String).join('.');\n const control = path === '' ? null : group.get(path);\n if (control !== null && control !== undefined) {\n setZodError(control, issue.message);\n touched.add(control);\n } else {\n rootIssues.push({ path: issue.path as (string | number)[], message: issue.message });\n }\n }\n }\n\n for (const control of collectControls(group)) {\n if (control !== group && !touched.has(control)) {\n clearZodError(control);\n }\n }\n\n if (rootIssues.length === 0) {\n clearZodError(group);\n return null;\n }\n\n const formErrors: string[] = [];\n const fieldErrors: Record<string, string[]> = {};\n for (const issue of rootIssues) {\n if (issue.path.length === 0) {\n formErrors.push(issue.message);\n } else {\n const key = String(issue.path[0]);\n (fieldErrors[key] ??= []).push(issue.message);\n }\n }\n\n const zodError = { formErrors, fieldErrors };\n setZodError(group, zodError);\n return { zod: zodError };\n };\n}\n\nfunction setZodError(control: AbstractControl, message: unknown): void {\n const current = control.errors;\n if (current !== null && sameZodError(current.zod, message)) {\n return;\n }\n control.setErrors({ ...current, zod: message }, { emitEvent: false });\n}\n\nfunction clearZodError(control: AbstractControl): void {\n const current = control.errors;\n if (current === null || current === undefined || !('zod' in current)) {\n return;\n }\n const { zod: _discard, ...rest } = current;\n control.setErrors(Object.keys(rest).length > 0 ? rest : null, {\n emitEvent: false,\n });\n}\n\nfunction sameZodError(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\nfunction collectControls(control: AbstractControl): AbstractControl[] {\n const out: AbstractControl[] = [control];\n const children = (control as { controls?: unknown }).controls;\n if (children !== null && typeof children === 'object') {\n for (const child of Object.values(children as Record<string, AbstractControl>)) {\n out.push(...collectControls(child));\n }\n }\n return out;\n}`;\n\nconst ZOD_TREE_VALIDATE = `export function zodTreeValidate<T>(\n path: SchemaPath<T>,\n schema: ZodType<T>,\n): void {\n validateTree(path, (ctx) => {\n const result = schema.safeParse(ctx.value());\n if (result.success) {\n return undefined;\n }\n return result.error.issues.map((issue) => ({\n kind: 'custom' as const,\n message: issue.message,\n // Dynamically walked from the Zod issue path against the field tree's\n // runtime shape; ValidationError.fieldTree accepts undefined for a\n // pathless issue, so a same-shaped object (rather than branching on\n // whether one was found) keeps this a single, uniform return type.\n fieldTree: resolveFieldTree(ctx.fieldTree, issue.path) as\n | ReadonlyFieldTree<unknown>\n | undefined,\n }));\n });\n}\n\nfunction resolveFieldTree(root: unknown, path: readonly PropertyKey[]): unknown {\n return path.reduce<unknown>((node, key) => {\n if (node === null || typeof node !== 'object') {\n return undefined;\n }\n return (node as Record<PropertyKey, unknown>)[key];\n }, root);\n}`;\n\nexport function emitRuntime(\n _source: SourceIR,\n options: AngularGeneratorOptions,\n): string {\n const reactive = options.forms.includes('reactive');\n const signal = options.forms.includes('signal');\n\n const imports: string[] = [];\n if (reactive) {\n imports.push(\n \"import type { AbstractControl, ValidatorFn } from '@angular/forms';\",\n );\n }\n if (signal) {\n imports.push(\n \"import type { ReadonlyFieldTree, SchemaPath } from '@angular/forms/signals';\",\n \"import { validateTree } from '@angular/forms/signals';\",\n );\n }\n imports.push(\"import type { ZodType } from 'zod';\");\n\n const blocks: string[] = [];\n if (reactive) {\n blocks.push(ZOD_VALIDATOR);\n }\n if (signal) {\n blocks.push(ZOD_TREE_VALIDATE);\n }\n\n return `${[imports.join('\\n'), '', ...blocks].join('\\n').trimEnd()}\\n`;\n}\n","/**\n * Valibot schema for `@kurotako/gen-angular`'s `options`, plus the inferred type.\n * `@kurotako/config` validates a config entry's `options` against this schema and\n * curries it away before `@kurotako/core` sees the generator.\n */\nimport * as v from 'valibot';\n\nexport const AngularGeneratorOptions = v.object({\n /** Which form surfaces to emit. Default: both. */\n forms: v.optional(v.array(v.picklist(['reactive', 'signal'])), [\n 'reactive',\n 'signal',\n ]),\n /** Relation handling: flat (FK scalars only) or deep (nested FormGroup / FormArray). */\n relations: v.optional(v.picklist(['flat', 'deep']), 'flat'),\n});\n\nexport type AngularGeneratorOptions = v.InferOutput<\n typeof AngularGeneratorOptions\n>;\n"],"mappings":"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","names":["entityKey","lowerFirst"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kurotako/gen-angular",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "kurotako generator that emits Angular reactive forms from the intermediate representation.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"kurotako",
|
|
7
|
+
"codegen",
|
|
8
|
+
"typescript",
|
|
9
|
+
"angular",
|
|
10
|
+
"forms",
|
|
11
|
+
"generator"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Marmotz",
|
|
15
|
+
"homepage": "https://kurotako.marmotz.dev/",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/marmotz/kurotako.git",
|
|
19
|
+
"directory": "packages/gen-angular"
|
|
20
|
+
},
|
|
21
|
+
"bugs": "https://github.com/marmotz/kurotako/issues",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js",
|
|
27
|
+
"require": "./dist/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"main": "./dist/index.cjs",
|
|
31
|
+
"module": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"sideEffects": false,
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"CHANGELOG.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=24"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsup",
|
|
44
|
+
"typecheck": "tsc -b",
|
|
45
|
+
"test": "vitest run"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@kurotako/ir": "^0.1.0",
|
|
52
|
+
"valibot": "1.4.2"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@kurotako/config": "^0.1.0",
|
|
56
|
+
"@kurotako/core": "^0.1.0",
|
|
57
|
+
"@kurotako/gen-zod": "^0.1.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@kurotako/config": "^0.1.0",
|
|
61
|
+
"@kurotako/core": "^0.1.0",
|
|
62
|
+
"@kurotako/gen-zod": "^0.1.0",
|
|
63
|
+
"typescript": "5.9.3"
|
|
64
|
+
}
|
|
65
|
+
}
|