@manifesto-ai/codegen 0.1.0 → 0.1.2
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 +2 -2
- package/dist/index.d.ts +114 -10
- package/dist/index.js +543 -13
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/header.d.ts +0 -13
- package/dist/header.d.ts.map +0 -1
- package/dist/header.js +0 -18
- package/dist/header.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/path-safety.d.ts +0 -16
- package/dist/path-safety.d.ts.map +0 -1
- package/dist/path-safety.js +0 -47
- package/dist/path-safety.js.map +0 -1
- package/dist/plugins/index.d.ts +0 -5
- package/dist/plugins/index.d.ts.map +0 -1
- package/dist/plugins/index.js +0 -3
- package/dist/plugins/index.js.map +0 -1
- package/dist/plugins/ts-plugin.d.ts +0 -11
- package/dist/plugins/ts-plugin.d.ts.map +0 -1
- package/dist/plugins/ts-plugin.js +0 -202
- package/dist/plugins/ts-plugin.js.map +0 -1
- package/dist/plugins/zod-plugin.d.ts +0 -6
- package/dist/plugins/zod-plugin.d.ts.map +0 -1
- package/dist/plugins/zod-plugin.js +0 -138
- package/dist/plugins/zod-plugin.js.map +0 -1
- package/dist/runner.d.ts +0 -13
- package/dist/runner.d.ts.map +0 -1
- package/dist/runner.js +0 -126
- package/dist/runner.js.map +0 -1
- package/dist/stable-hash.d.ts +0 -7
- package/dist/stable-hash.d.ts.map +0 -1
- package/dist/stable-hash.js +0 -11
- package/dist/stable-hash.js.map +0 -1
- package/dist/types.d.ts +0 -50
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- package/dist/virtual-fs.d.ts +0 -27
- package/dist/virtual-fs.d.ts.map +0 -1
- package/dist/virtual-fs.js +0 -74
- package/dist/virtual-fs.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,iDAAiD;AACjD,EAAE;AACF,6CAA6C;AAC7C,0DAA0D;AAc1D,SAAS;AACT,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,UAAU;AACV,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAGrE,wCAAwC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"sources":["../src/runner.ts","../src/virtual-fs.ts","../src/path-safety.ts","../src/stable-hash.ts","../src/header.ts","../src/plugins/ts-plugin.ts","../src/plugins/zod-plugin.ts"],"sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as nodePath from \"node:path\";\n\nimport type {\n CodegenContext,\n CodegenPlugin,\n Diagnostic,\n GenerateOptions,\n GenerateResult,\n} from \"./types.js\";\nimport { VirtualFS } from \"./virtual-fs.js\";\nimport { validatePath } from \"./path-safety.js\";\nimport { stableHash } from \"./stable-hash.js\";\nimport { generateHeader } from \"./header.js\";\n\n/**\n * Generate typed artifacts from a DomainSchema using plugins.\n *\n * This is the sole entry point for codegen. It orchestrates:\n * - Plugin name uniqueness validation (GEN-2)\n * - Sequential plugin execution (GEN-3, GEN-7)\n * - FilePatch composition with collision detection\n * - Error gating (GEN-5, GEN-8)\n * - outDir clean + file flush (GEN-1)\n */\nexport async function generate(opts: GenerateOptions): Promise<GenerateResult> {\n const diagnostics: Diagnostic[] = [];\n const allArtifacts: Record<string, unknown> = {};\n const vfs = new VirtualFS();\n\n // GEN-2: Validate plugin name uniqueness\n const nameError = validatePluginNames(opts.plugins);\n if (nameError) {\n return {\n files: [],\n artifacts: {},\n diagnostics: [nameError],\n };\n }\n\n // GEN-3, GEN-7: Execute plugins sequentially in array order\n for (const plugin of opts.plugins) {\n const ctx: CodegenContext = {\n schema: opts.schema,\n sourceId: opts.sourceId,\n outDir: opts.outDir,\n artifacts: Object.freeze({ ...allArtifacts }), // PLG-9: frozen snapshot\n helpers: { stableHash },\n };\n\n let output;\n try {\n output = await plugin.generate(ctx);\n } catch (err) {\n // Convert plugin exceptions to error diagnostics (errors as values)\n diagnostics.push({\n level: \"error\",\n plugin: plugin.name,\n message: `Plugin threw: ${err instanceof Error ? err.message : String(err)}`,\n });\n continue;\n }\n\n // GEN-4: Merge plugin diagnostics\n if (output.diagnostics) {\n diagnostics.push(...output.diagnostics);\n }\n\n // Validate and apply patches\n for (const patch of output.patches) {\n const validation = validatePath(patch.path);\n if (!validation.valid) {\n diagnostics.push({\n level: \"error\",\n plugin: plugin.name,\n message: `Invalid path \"${patch.path}\": ${validation.reason}`,\n });\n continue;\n }\n\n // Apply with normalized path\n const normalizedPatch =\n patch.op === \"set\"\n ? { op: \"set\" as const, path: validation.normalized, content: patch.content }\n : { op: \"delete\" as const, path: validation.normalized };\n\n const collision = vfs.applyPatch(normalizedPatch, plugin.name);\n if (collision) {\n diagnostics.push(collision);\n }\n }\n\n // PLG-8: Store artifacts at allArtifacts[plugin.name]\n if (output.artifacts) {\n allArtifacts[plugin.name] = output.artifacts;\n }\n }\n\n // Collect files from VFS\n const files = vfs.getFiles();\n\n // GEN-5, GEN-8: Error gate — no disk mutation on error\n const hasErrors = diagnostics.some((d) => d.level === \"error\");\n if (hasErrors) {\n return { files, artifacts: allArtifacts, diagnostics };\n }\n\n // GEN-1: Clean outDir before write\n await fs.rm(opts.outDir, { recursive: true, force: true });\n\n // Build header\n const header = generateHeader({\n sourceId: opts.sourceId,\n schemaHash: opts.schema.hash,\n stamp: opts.stamp,\n });\n\n // Flush files to disk (GEN-6: OS path conversion only at write time)\n for (const file of files) {\n const absPath = nodePath.join(opts.outDir, ...file.path.split(\"/\"));\n const dir = nodePath.dirname(absPath);\n await fs.mkdir(dir, { recursive: true });\n await fs.writeFile(absPath, header + file.content, \"utf-8\");\n }\n\n return { files, artifacts: allArtifacts, diagnostics };\n}\n\nfunction validatePluginNames(\n plugins: readonly CodegenPlugin[]\n): Diagnostic | undefined {\n const seen = new Set<string>();\n for (const plugin of plugins) {\n if (!plugin.name) {\n return {\n level: \"error\",\n plugin: \"\",\n message: \"Plugin name must not be empty (PLG-1)\",\n };\n }\n if (seen.has(plugin.name)) {\n return {\n level: \"error\",\n plugin: plugin.name,\n message: `Duplicate plugin name \"${plugin.name}\" (GEN-2)`,\n };\n }\n seen.add(plugin.name);\n }\n return undefined;\n}\n","import type { Diagnostic, FilePatch } from \"./types.js\";\n\ntype FileEntry = {\n content: string;\n source: string; // plugin name that set the file\n};\n\n/**\n * Virtual filesystem for composing FilePatch operations.\n *\n * Maintains an in-memory FS and detects collisions per FP-5, FP-6, FP-7.\n * Paths are assumed to be already validated/normalized.\n */\nexport class VirtualFS {\n private readonly files = new Map<string, FileEntry>();\n private readonly deleted = new Set<string>();\n\n /**\n * Apply a FilePatch to the virtual FS.\n * Returns a Diagnostic if a collision/warning condition is detected.\n */\n applyPatch(patch: FilePatch, pluginName: string): Diagnostic | undefined {\n if (patch.op === \"set\") {\n return this.applySet(patch.path, patch.content, pluginName);\n }\n return this.applyDelete(patch.path, pluginName);\n }\n\n private applySet(path: string, content: string, pluginName: string): Diagnostic | undefined {\n const existing = this.files.get(path);\n\n if (existing) {\n // FP-5: Duplicate set on same path -> error\n const samePlugin = existing.source === pluginName;\n return {\n level: \"error\",\n plugin: pluginName,\n message: samePlugin\n ? `Duplicate set on \"${path}\" within plugin \"${pluginName}\"`\n : `File \"${path}\" already set by plugin \"${existing.source}\", cannot be set again by \"${pluginName}\"`,\n };\n }\n\n // delete-then-set is allowed (intentional regeneration)\n this.deleted.delete(path);\n this.files.set(path, { content, source: pluginName });\n return undefined;\n }\n\n private applyDelete(path: string, pluginName: string): Diagnostic | undefined {\n const existing = this.files.get(path);\n\n if (!existing && !this.deleted.has(path)) {\n // FP-7: Delete on nonexistent path -> warn\n return {\n level: \"warn\",\n plugin: pluginName,\n message: `Delete on nonexistent path \"${path}\"`,\n };\n }\n\n if (existing) {\n // FP-6: set-then-delete -> allowed with warning\n this.files.delete(path);\n this.deleted.add(path);\n return {\n level: \"warn\",\n plugin: pluginName,\n message: `File \"${path}\" set by plugin \"${existing.source}\" is being deleted by \"${pluginName}\". Prior work is voided.`,\n };\n }\n\n // Already deleted - just track it\n this.deleted.add(path);\n return undefined;\n }\n\n /**\n * Get all files in deterministic (lexicographic) order (DET-5).\n */\n getFiles(): Array<{ path: string; content: string }> {\n const entries = Array.from(this.files.entries());\n entries.sort(([a], [b]) => a.localeCompare(b));\n return entries.map(([path, { content }]) => ({ path, content }));\n }\n\n has(path: string): boolean {\n return this.files.has(path);\n }\n}\n","export type PathValidationResult =\n | { valid: true; normalized: string }\n | { valid: false; reason: string };\n\n/**\n * Validate and normalize a file path per FP-1, FP-2, GEN-6.\n *\n * - MUST be a POSIX relative path\n * - MUST NOT contain `..`, absolute prefixes, drive letters, or null bytes\n * - Normalizes backslashes, multiple slashes, and leading `./`\n */\nexport function validatePath(path: string): PathValidationResult {\n if (!path) {\n return { valid: false, reason: \"Path must not be empty\" };\n }\n\n if (path.includes(\"\\0\")) {\n return { valid: false, reason: \"Path must not contain null bytes\" };\n }\n\n // Normalize backslashes to forward slashes (GEN-6)\n let normalized = path.replace(/\\\\/g, \"/\");\n\n // Check for drive letters (e.g., C:/)\n if (/^[a-zA-Z]:/.test(normalized)) {\n return { valid: false, reason: \"Path must not contain drive letters\" };\n }\n\n // Check for absolute path\n if (normalized.startsWith(\"/\")) {\n return { valid: false, reason: \"Path must be relative, not absolute\" };\n }\n\n // Collapse multiple slashes\n normalized = normalized.replace(/\\/+/g, \"/\");\n\n // Remove leading ./\n if (normalized.startsWith(\"./\")) {\n normalized = normalized.slice(2);\n }\n\n // Remove trailing slash\n if (normalized.endsWith(\"/\") && normalized.length > 1) {\n normalized = normalized.slice(0, -1);\n }\n\n // Check for .. traversal (after normalization)\n const segments = normalized.split(\"/\");\n for (const segment of segments) {\n if (segment === \"..\") {\n return { valid: false, reason: \"Path must not contain '..' traversal\" };\n }\n }\n\n if (!normalized) {\n return { valid: false, reason: \"Path resolves to empty after normalization\" };\n }\n\n return { valid: true, normalized };\n}\n","import { toCanonical, sha256Sync } from \"@manifesto-ai/core\";\n\n/**\n * Deterministic hash function (DET-1).\n * Same input always produces the same output.\n * Uses Core's canonical form (sorted keys, no undefined) + SHA-256.\n */\nexport function stableHash(input: unknown): string {\n const canonical = toCanonical(input);\n return sha256Sync(canonical);\n}\n","export interface HeaderOptions {\n readonly sourceId?: string;\n readonly schemaHash: string;\n readonly stamp?: boolean;\n}\n\n/**\n * Generate the @generated file header (DET-2, DET-3, DET-4).\n *\n * Default mode: no timestamp (deterministic).\n * With stamp=true: appends ISO 8601 timestamp line.\n */\nexport function generateHeader(options: HeaderOptions): string {\n const source = options.sourceId ?? \"unknown\";\n const lines = [\n \"// @generated by @manifesto-ai/codegen \\u2014 DO NOT EDIT\",\n `// Source: ${source} | Schema hash: ${options.schemaHash}`,\n ];\n\n if (options.stamp) {\n lines.push(`// Generated at: ${new Date().toISOString()}`);\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n","import type {\n TypeDefinition,\n TypeSpec,\n ActionSpec,\n FieldSpec,\n FieldType,\n} from \"@manifesto-ai/core\";\nimport type {\n CodegenContext,\n CodegenOutput,\n CodegenPlugin,\n Diagnostic,\n} from \"../types.js\";\n\nconst PLUGIN_NAME = \"codegen-plugin-ts\";\n\nexport interface TsPluginOptions {\n readonly typesFile?: string;\n readonly actionsFile?: string;\n}\n\nexport interface TsPluginArtifacts {\n readonly typeNames: string[];\n readonly typeImportPath: string;\n}\n\nexport function createTsPlugin(options?: TsPluginOptions): CodegenPlugin {\n const typesFile = options?.typesFile ?? \"types.ts\";\n const actionsFile = options?.actionsFile ?? \"actions.ts\";\n\n return {\n name: PLUGIN_NAME,\n generate(ctx: CodegenContext): CodegenOutput {\n const diagnostics: Diagnostic[] = [];\n const typeNames: string[] = [];\n\n // Generate types from schema.types (GEN-10, TS-6: lexicographic order)\n const sortedTypeNames = Object.keys(ctx.schema.types).sort();\n const typeDecls: string[] = [];\n\n for (const name of sortedTypeNames) {\n const spec = ctx.schema.types[name];\n typeNames.push(name);\n typeDecls.push(renderNamedType(name, spec, diagnostics));\n }\n\n const typesContent = typeDecls.join(\"\\n\\n\") + \"\\n\";\n\n // Generate action input types\n const sortedActionNames = Object.keys(ctx.schema.actions).sort();\n const actionDecls: string[] = [];\n\n for (const actionName of sortedActionNames) {\n const spec = ctx.schema.actions[actionName];\n if (spec.input) {\n const typeName = pascalCase(actionName) + \"Input\";\n actionDecls.push(renderActionInputType(typeName, spec, diagnostics));\n }\n }\n\n const patches = [\n { op: \"set\" as const, path: typesFile, content: typesContent },\n ];\n\n if (actionDecls.length > 0) {\n const actionsContent = actionDecls.join(\"\\n\\n\") + \"\\n\";\n patches.push({ op: \"set\" as const, path: actionsFile, content: actionsContent });\n }\n\n const artifacts: TsPluginArtifacts = {\n typeNames,\n typeImportPath: `./${typesFile.replace(/\\.ts$/, \"\")}`,\n };\n\n return { patches, artifacts: artifacts as unknown as Record<string, unknown>, diagnostics };\n },\n };\n}\n\n// --- Type rendering ---\n\nfunction renderNamedType(\n name: string,\n spec: TypeSpec,\n diagnostics: Diagnostic[]\n): string {\n const def = spec.definition;\n\n // TS-3: top-level named object -> export interface\n if (def.kind === \"object\") {\n return renderInterface(name, def.fields, diagnostics);\n }\n\n // TS-3: all other named types -> export type\n const tsType = mapTypeDefinition(def, diagnostics);\n return `export type ${name} = ${tsType};`;\n}\n\nfunction renderInterface(\n name: string,\n fields: Record<string, { type: TypeDefinition; optional: boolean }>,\n diagnostics: Diagnostic[]\n): string {\n const sortedFields = Object.keys(fields).sort();\n const lines: string[] = [];\n\n for (const fieldName of sortedFields) {\n const field = fields[fieldName];\n const tsType = mapTypeDefinition(field.type, diagnostics);\n // TS-5: optional -> ?\n const opt = field.optional ? \"?\" : \"\";\n lines.push(` ${fieldName}${opt}: ${tsType};`);\n }\n\n return `export interface ${name} {\\n${lines.join(\"\\n\")}\\n}`;\n}\n\nfunction mapTypeDefinition(\n def: TypeDefinition,\n diagnostics: Diagnostic[]\n): string {\n switch (def.kind) {\n case \"primitive\":\n return mapPrimitive(def.type);\n\n case \"literal\":\n return renderLiteral(def.value);\n\n case \"array\":\n return `${wrapComplex(mapTypeDefinition(def.element, diagnostics), def.element)}[]`;\n\n case \"record\":\n return `Record<${mapTypeDefinition(def.key, diagnostics)}, ${mapTypeDefinition(def.value, diagnostics)}>`;\n\n case \"object\": {\n const sortedFields = Object.keys(def.fields).sort();\n const parts: string[] = [];\n for (const fieldName of sortedFields) {\n const field = def.fields[fieldName];\n const tsType = mapTypeDefinition(field.type, diagnostics);\n const opt = field.optional ? \"?\" : \"\";\n parts.push(`${fieldName}${opt}: ${tsType}`);\n }\n return `{ ${parts.join(\"; \")} }`;\n }\n\n case \"union\":\n // TS-2: nullable uses T | null\n return def.types.map((t) => mapTypeDefinition(t, diagnostics)).join(\" | \");\n\n case \"ref\":\n return def.name;\n\n default: {\n // PLG-3, TS-1: unknown kind fallback\n diagnostics.push({\n level: \"warn\",\n plugin: PLUGIN_NAME,\n message: `Unknown TypeDefinition kind: \"${(def as Record<string, unknown>).kind}\". Emitting \"unknown\".`,\n });\n return \"unknown\";\n }\n }\n}\n\nfunction mapPrimitive(type: string): string {\n switch (type) {\n case \"string\":\n return \"string\";\n case \"number\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"null\":\n return \"null\";\n default:\n return \"unknown\";\n }\n}\n\nfunction renderLiteral(value: string | number | boolean | null): string {\n if (typeof value === \"string\") {\n return JSON.stringify(value);\n }\n return String(value);\n}\n\n/** Wrap union types in parens when used as array element */\nfunction wrapComplex(tsType: string, def: TypeDefinition): string {\n if (def.kind === \"union\") {\n return `(${tsType})`;\n }\n return tsType;\n}\n\n// --- Action input rendering ---\n\nfunction renderActionInputType(\n typeName: string,\n spec: ActionSpec,\n diagnostics: Diagnostic[]\n): string {\n if (!spec.input) {\n return \"\";\n }\n const tsType = mapFieldSpec(spec.input, diagnostics);\n return `export type ${typeName} = ${tsType};`;\n}\n\nfunction mapFieldSpec(\n spec: FieldSpec,\n diagnostics: Diagnostic[]\n): string {\n const baseType = mapFieldType(spec.type, spec, diagnostics);\n\n // GEN-12: degrade for unknown structures\n if (!spec.required && baseType !== \"unknown\") {\n return `${baseType} | null`;\n }\n return baseType;\n}\n\nfunction mapFieldType(\n type: FieldType,\n spec: FieldSpec,\n diagnostics: Diagnostic[]\n): string {\n if (typeof type === \"object\" && \"enum\" in type) {\n // Enum -> union of literals\n return type.enum.map((v) => renderLiteral(v as string | number | boolean | null)).join(\" | \");\n }\n\n switch (type) {\n case \"string\":\n return \"string\";\n case \"number\":\n return \"number\";\n case \"boolean\":\n return \"boolean\";\n case \"null\":\n return \"null\";\n case \"object\": {\n if (spec.fields) {\n const sortedFields = Object.keys(spec.fields).sort();\n const parts: string[] = [];\n for (const name of sortedFields) {\n const field = spec.fields[name];\n const fieldType = mapFieldSpec(field, diagnostics);\n const opt = field.required ? \"\" : \"?\";\n parts.push(`${name}${opt}: ${fieldType}`);\n }\n return `{ ${parts.join(\"; \")} }`;\n }\n // GEN-12: unstructured object -> unknown\n diagnostics.push({\n level: \"warn\",\n plugin: PLUGIN_NAME,\n message: \"Object field without fields spec, degrading to Record<string, unknown>\",\n });\n return \"Record<string, unknown>\";\n }\n case \"array\": {\n if (spec.items) {\n return `${mapFieldSpec(spec.items, diagnostics)}[]`;\n }\n diagnostics.push({\n level: \"warn\",\n plugin: PLUGIN_NAME,\n message: \"Array field without items spec, degrading to unknown[]\",\n });\n return \"unknown[]\";\n }\n default:\n return \"unknown\";\n }\n}\n\nfunction pascalCase(str: string): string {\n return str\n .split(/[-_\\s]+/)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\"\");\n}\n","import type { TypeDefinition, TypeSpec } from \"@manifesto-ai/core\";\nimport type {\n CodegenContext,\n CodegenOutput,\n CodegenPlugin,\n Diagnostic,\n} from \"../types.js\";\nimport type { TsPluginArtifacts } from \"./ts-plugin.js\";\n\nconst PLUGIN_NAME = \"codegen-plugin-zod\";\nconst TS_PLUGIN_NAME = \"codegen-plugin-ts\";\n\nexport interface ZodPluginOptions {\n readonly schemasFile?: string;\n}\n\nexport function createZodPlugin(options?: ZodPluginOptions): CodegenPlugin {\n const schemasFile = options?.schemasFile ?? \"base.ts\";\n\n return {\n name: PLUGIN_NAME,\n generate(ctx: CodegenContext): CodegenOutput {\n const diagnostics: Diagnostic[] = [];\n\n // PLG-11: Optional TS artifacts dependency\n const tsArtifacts = ctx.artifacts[TS_PLUGIN_NAME] as TsPluginArtifacts | undefined;\n\n const sortedTypeNames = Object.keys(ctx.schema.types).sort();\n const schemaDecls: string[] = [];\n\n // Collect all type names for forward declarations with z.lazy\n const allTypeNames = new Set(sortedTypeNames);\n\n for (const name of sortedTypeNames) {\n const spec = ctx.schema.types[name];\n schemaDecls.push(renderNamedSchema(name, spec, allTypeNames, tsArtifacts, diagnostics));\n }\n\n // Build imports\n const imports: string[] = ['import { z } from \"zod\";'];\n\n // ZOD-4: Import TS types for annotations when available\n if (tsArtifacts && tsArtifacts.typeNames.length > 0) {\n const typeImports = sortedTypeNames\n .filter((n) => tsArtifacts.typeNames.includes(n))\n .join(\", \");\n if (typeImports) {\n imports.push(`import type { ${typeImports} } from \"${tsArtifacts.typeImportPath}\";`);\n }\n }\n\n const content = imports.join(\"\\n\") + \"\\n\\n\" + schemaDecls.join(\"\\n\\n\") + \"\\n\";\n\n return {\n patches: [{ op: \"set\", path: schemasFile, content }],\n diagnostics,\n };\n },\n };\n}\n\n// --- Schema rendering ---\n\nfunction renderNamedSchema(\n name: string,\n spec: TypeSpec,\n allTypeNames: Set<string>,\n tsArtifacts: TsPluginArtifacts | undefined,\n diagnostics: Diagnostic[]\n): string {\n const schemaName = `${name}Schema`;\n const zodExpr = mapTypeDefinition(spec.definition, allTypeNames, diagnostics);\n\n // ZOD-4/ZOD-5: Type annotation when TS artifacts available\n const hasTypeAnnotation = tsArtifacts && tsArtifacts.typeNames.includes(name);\n const annotation = hasTypeAnnotation ? `: z.ZodType<${name}>` : \"\";\n\n return `export const ${schemaName}${annotation} = ${zodExpr};`;\n}\n\nfunction mapTypeDefinition(\n def: TypeDefinition,\n allTypeNames: Set<string>,\n diagnostics: Diagnostic[]\n): string {\n switch (def.kind) {\n case \"primitive\":\n return mapPrimitiveZod(def.type);\n\n case \"literal\":\n return `z.literal(${renderLiteralValue(def.value)})`;\n\n case \"array\":\n return `z.array(${mapTypeDefinition(def.element, allTypeNames, diagnostics)})`;\n\n case \"record\":\n return handleRecord(def, allTypeNames, diagnostics);\n\n case \"object\":\n return renderZodObject(def.fields, allTypeNames, diagnostics);\n\n case \"union\":\n return handleUnion(def.types, allTypeNames, diagnostics);\n\n case \"ref\":\n // ZOD-2: Always z.lazy for circular reference support\n return `z.lazy(() => ${def.name}Schema)`;\n\n default: {\n // ZOD-1: Unknown kind fallback\n diagnostics.push({\n level: \"warn\",\n plugin: PLUGIN_NAME,\n message: `Unknown TypeDefinition kind: \"${(def as Record<string, unknown>).kind}\". Emitting \"z.unknown()\".`,\n });\n return \"z.unknown()\";\n }\n }\n}\n\nfunction mapPrimitiveZod(type: string): string {\n switch (type) {\n case \"string\":\n return \"z.string()\";\n case \"number\":\n return \"z.number()\";\n case \"boolean\":\n return \"z.boolean()\";\n case \"null\":\n return \"z.null()\";\n default:\n return \"z.unknown()\";\n }\n}\n\nfunction renderLiteralValue(value: string | number | boolean | null): string {\n if (typeof value === \"string\") {\n return JSON.stringify(value);\n }\n if (value === null) {\n return \"null\";\n }\n return String(value);\n}\n\nfunction handleRecord(\n def: Extract<TypeDefinition, { kind: \"record\" }>,\n allTypeNames: Set<string>,\n diagnostics: Diagnostic[]\n): string {\n const valueSchema = mapTypeDefinition(def.value, allTypeNames, diagnostics);\n\n // ZOD-7: Non-string record key -> degrade to z.record(z.string(), ...)\n if (def.key.kind !== \"primitive\" || def.key.type !== \"string\") {\n diagnostics.push({\n level: \"warn\",\n plugin: PLUGIN_NAME,\n message: `Record key type is not string (got ${JSON.stringify(def.key)}). Degrading to z.record(z.string(), ...).`,\n });\n return `z.record(z.string(), ${valueSchema})`;\n }\n\n return `z.record(z.string(), ${valueSchema})`;\n}\n\nfunction renderZodObject(\n fields: Record<string, { type: TypeDefinition; optional: boolean }>,\n allTypeNames: Set<string>,\n diagnostics: Diagnostic[]\n): string {\n const sortedFields = Object.keys(fields).sort();\n const parts: string[] = [];\n\n for (const fieldName of sortedFields) {\n const field = fields[fieldName];\n let zodType = mapTypeDefinition(field.type, allTypeNames, diagnostics);\n\n // ZOD-6: optional -> .optional()\n if (field.optional) {\n zodType += \".optional()\";\n }\n\n parts.push(` ${fieldName}: ${zodType},`);\n }\n\n return `z.object({\\n${parts.join(\"\\n\")}\\n})`;\n}\n\nfunction handleUnion(\n types: TypeDefinition[],\n allTypeNames: Set<string>,\n diagnostics: Diagnostic[]\n): string {\n // ZOD-3: 2-variant union with null -> z.nullable(T)\n if (types.length === 2) {\n const nullIdx = types.findIndex(\n (t) => t.kind === \"primitive\" && t.type === \"null\"\n );\n if (nullIdx !== -1) {\n const otherIdx = nullIdx === 0 ? 1 : 0;\n const otherSchema = mapTypeDefinition(types[otherIdx], allTypeNames, diagnostics);\n return `z.nullable(${otherSchema})`;\n }\n }\n\n const schemas = types.map((t) => mapTypeDefinition(t, allTypeNames, diagnostics));\n return `z.union([${schemas.join(\", \")}])`;\n}\n"],"mappings":"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","names":["PLUGIN_NAME","mapTypeDefinition"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@manifesto-ai/codegen",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Manifesto Codegen - Plugin-based code generation from DomainSchema",
|
|
5
5
|
"author": "eggplantiny <eggplantiny@gmail.com>",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,13 +36,13 @@
|
|
|
36
36
|
"@manifesto-ai/core": "~2.0.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/node": "^25.
|
|
39
|
+
"@types/node": "^25.3.3",
|
|
40
40
|
"typescript": "^5.9.3",
|
|
41
41
|
"vitest": "^4.0.18",
|
|
42
|
-
"@manifesto-ai/core": "2.
|
|
42
|
+
"@manifesto-ai/core": "2.6.1"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
|
-
"build": "
|
|
45
|
+
"build": "tsup",
|
|
46
46
|
"dev": "tsc --watch",
|
|
47
47
|
"clean": "rm -rf dist",
|
|
48
48
|
"test": "vitest run",
|
package/dist/header.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export interface HeaderOptions {
|
|
2
|
-
readonly sourceId?: string;
|
|
3
|
-
readonly schemaHash: string;
|
|
4
|
-
readonly stamp?: boolean;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Generate the @generated file header (DET-2, DET-3, DET-4).
|
|
8
|
-
*
|
|
9
|
-
* Default mode: no timestamp (deterministic).
|
|
10
|
-
* With stamp=true: appends ISO 8601 timestamp line.
|
|
11
|
-
*/
|
|
12
|
-
export declare function generateHeader(options: HeaderOptions): string;
|
|
13
|
-
//# sourceMappingURL=header.d.ts.map
|
package/dist/header.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../src/header.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAY7D"}
|
package/dist/header.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generate the @generated file header (DET-2, DET-3, DET-4).
|
|
3
|
-
*
|
|
4
|
-
* Default mode: no timestamp (deterministic).
|
|
5
|
-
* With stamp=true: appends ISO 8601 timestamp line.
|
|
6
|
-
*/
|
|
7
|
-
export function generateHeader(options) {
|
|
8
|
-
const source = options.sourceId ?? "unknown";
|
|
9
|
-
const lines = [
|
|
10
|
-
"// @generated by @manifesto-ai/codegen \u2014 DO NOT EDIT",
|
|
11
|
-
`// Source: ${source} | Schema hash: ${options.schemaHash}`,
|
|
12
|
-
];
|
|
13
|
-
if (options.stamp) {
|
|
14
|
-
lines.push(`// Generated at: ${new Date().toISOString()}`);
|
|
15
|
-
}
|
|
16
|
-
return lines.join("\n") + "\n";
|
|
17
|
-
}
|
|
18
|
-
//# sourceMappingURL=header.js.map
|
package/dist/header.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"header.js","sourceRoot":"","sources":["../src/header.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,OAAsB;IACnD,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,IAAI,SAAS,CAAC;IAC7C,MAAM,KAAK,GAAG;QACZ,2DAA2D;QAC3D,cAAc,MAAM,mBAAmB,OAAO,CAAC,UAAU,EAAE;KAC5D,CAAC;IAEF,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,oBAAoB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACjC,CAAC"}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,YAAY,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,cAAc,EACd,aAAa,EACb,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrE,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG/F,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,YAAY,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/path-safety.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export type PathValidationResult = {
|
|
2
|
-
valid: true;
|
|
3
|
-
normalized: string;
|
|
4
|
-
} | {
|
|
5
|
-
valid: false;
|
|
6
|
-
reason: string;
|
|
7
|
-
};
|
|
8
|
-
/**
|
|
9
|
-
* Validate and normalize a file path per FP-1, FP-2, GEN-6.
|
|
10
|
-
*
|
|
11
|
-
* - MUST be a POSIX relative path
|
|
12
|
-
* - MUST NOT contain `..`, absolute prefixes, drive letters, or null bytes
|
|
13
|
-
* - Normalizes backslashes, multiple slashes, and leading `./`
|
|
14
|
-
*/
|
|
15
|
-
export declare function validatePath(path: string): PathValidationResult;
|
|
16
|
-
//# sourceMappingURL=path-safety.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"path-safety.d.ts","sourceRoot":"","sources":["../src/path-safety.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,oBAAoB,GAC5B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,CAgD/D"}
|
package/dist/path-safety.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Validate and normalize a file path per FP-1, FP-2, GEN-6.
|
|
3
|
-
*
|
|
4
|
-
* - MUST be a POSIX relative path
|
|
5
|
-
* - MUST NOT contain `..`, absolute prefixes, drive letters, or null bytes
|
|
6
|
-
* - Normalizes backslashes, multiple slashes, and leading `./`
|
|
7
|
-
*/
|
|
8
|
-
export function validatePath(path) {
|
|
9
|
-
if (!path) {
|
|
10
|
-
return { valid: false, reason: "Path must not be empty" };
|
|
11
|
-
}
|
|
12
|
-
if (path.includes("\0")) {
|
|
13
|
-
return { valid: false, reason: "Path must not contain null bytes" };
|
|
14
|
-
}
|
|
15
|
-
// Normalize backslashes to forward slashes (GEN-6)
|
|
16
|
-
let normalized = path.replace(/\\/g, "/");
|
|
17
|
-
// Check for drive letters (e.g., C:/)
|
|
18
|
-
if (/^[a-zA-Z]:/.test(normalized)) {
|
|
19
|
-
return { valid: false, reason: "Path must not contain drive letters" };
|
|
20
|
-
}
|
|
21
|
-
// Check for absolute path
|
|
22
|
-
if (normalized.startsWith("/")) {
|
|
23
|
-
return { valid: false, reason: "Path must be relative, not absolute" };
|
|
24
|
-
}
|
|
25
|
-
// Collapse multiple slashes
|
|
26
|
-
normalized = normalized.replace(/\/+/g, "/");
|
|
27
|
-
// Remove leading ./
|
|
28
|
-
if (normalized.startsWith("./")) {
|
|
29
|
-
normalized = normalized.slice(2);
|
|
30
|
-
}
|
|
31
|
-
// Remove trailing slash
|
|
32
|
-
if (normalized.endsWith("/") && normalized.length > 1) {
|
|
33
|
-
normalized = normalized.slice(0, -1);
|
|
34
|
-
}
|
|
35
|
-
// Check for .. traversal (after normalization)
|
|
36
|
-
const segments = normalized.split("/");
|
|
37
|
-
for (const segment of segments) {
|
|
38
|
-
if (segment === "..") {
|
|
39
|
-
return { valid: false, reason: "Path must not contain '..' traversal" };
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
if (!normalized) {
|
|
43
|
-
return { valid: false, reason: "Path resolves to empty after normalization" };
|
|
44
|
-
}
|
|
45
|
-
return { valid: true, normalized };
|
|
46
|
-
}
|
|
47
|
-
//# sourceMappingURL=path-safety.js.map
|
package/dist/path-safety.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"path-safety.js","sourceRoot":"","sources":["../src/path-safety.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,wBAAwB,EAAE,CAAC;IAC5D,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,kCAAkC,EAAE,CAAC;IACtE,CAAC;IAED,mDAAmD;IACnD,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAE1C,sCAAsC;IACtC,IAAI,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,qCAAqC,EAAE,CAAC;IACzE,CAAC;IAED,0BAA0B;IAC1B,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,qCAAqC,EAAE,CAAC;IACzE,CAAC;IAED,4BAA4B;IAC5B,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE7C,oBAAoB;IACpB,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,wBAAwB;IACxB,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtD,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,+CAA+C;IAC/C,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,sCAAsC,EAAE,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,4CAA4C,EAAE,CAAC;IAChF,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;AACrC,CAAC"}
|
package/dist/plugins/index.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { createTsPlugin } from "./ts-plugin.js";
|
|
2
|
-
export type { TsPluginOptions, TsPluginArtifacts } from "./ts-plugin.js";
|
|
3
|
-
export { createZodPlugin } from "./zod-plugin.js";
|
|
4
|
-
export type { ZodPluginOptions } from "./zod-plugin.js";
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/plugins/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugins/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import type { CodegenPlugin } from "../types.js";
|
|
2
|
-
export interface TsPluginOptions {
|
|
3
|
-
readonly typesFile?: string;
|
|
4
|
-
readonly actionsFile?: string;
|
|
5
|
-
}
|
|
6
|
-
export interface TsPluginArtifacts {
|
|
7
|
-
readonly typeNames: string[];
|
|
8
|
-
readonly typeImportPath: string;
|
|
9
|
-
}
|
|
10
|
-
export declare function createTsPlugin(options?: TsPluginOptions): CodegenPlugin;
|
|
11
|
-
//# sourceMappingURL=ts-plugin.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ts-plugin.d.ts","sourceRoot":"","sources":["../../src/plugins/ts-plugin.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAGV,aAAa,EAEd,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAC7B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,wBAAgB,cAAc,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,aAAa,CAmDvE"}
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
const PLUGIN_NAME = "codegen-plugin-ts";
|
|
2
|
-
export function createTsPlugin(options) {
|
|
3
|
-
const typesFile = options?.typesFile ?? "types.ts";
|
|
4
|
-
const actionsFile = options?.actionsFile ?? "actions.ts";
|
|
5
|
-
return {
|
|
6
|
-
name: PLUGIN_NAME,
|
|
7
|
-
generate(ctx) {
|
|
8
|
-
const diagnostics = [];
|
|
9
|
-
const typeNames = [];
|
|
10
|
-
// Generate types from schema.types (GEN-10, TS-6: lexicographic order)
|
|
11
|
-
const sortedTypeNames = Object.keys(ctx.schema.types).sort();
|
|
12
|
-
const typeDecls = [];
|
|
13
|
-
for (const name of sortedTypeNames) {
|
|
14
|
-
const spec = ctx.schema.types[name];
|
|
15
|
-
typeNames.push(name);
|
|
16
|
-
typeDecls.push(renderNamedType(name, spec, diagnostics));
|
|
17
|
-
}
|
|
18
|
-
const typesContent = typeDecls.join("\n\n") + "\n";
|
|
19
|
-
// Generate action input types
|
|
20
|
-
const sortedActionNames = Object.keys(ctx.schema.actions).sort();
|
|
21
|
-
const actionDecls = [];
|
|
22
|
-
for (const actionName of sortedActionNames) {
|
|
23
|
-
const spec = ctx.schema.actions[actionName];
|
|
24
|
-
if (spec.input) {
|
|
25
|
-
const typeName = pascalCase(actionName) + "Input";
|
|
26
|
-
actionDecls.push(renderActionInputType(typeName, spec, diagnostics));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
const patches = [
|
|
30
|
-
{ op: "set", path: typesFile, content: typesContent },
|
|
31
|
-
];
|
|
32
|
-
if (actionDecls.length > 0) {
|
|
33
|
-
const actionsContent = actionDecls.join("\n\n") + "\n";
|
|
34
|
-
patches.push({ op: "set", path: actionsFile, content: actionsContent });
|
|
35
|
-
}
|
|
36
|
-
const artifacts = {
|
|
37
|
-
typeNames,
|
|
38
|
-
typeImportPath: `./${typesFile.replace(/\.ts$/, "")}`,
|
|
39
|
-
};
|
|
40
|
-
return { patches, artifacts: artifacts, diagnostics };
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
// --- Type rendering ---
|
|
45
|
-
function renderNamedType(name, spec, diagnostics) {
|
|
46
|
-
const def = spec.definition;
|
|
47
|
-
// TS-3: top-level named object -> export interface
|
|
48
|
-
if (def.kind === "object") {
|
|
49
|
-
return renderInterface(name, def.fields, diagnostics);
|
|
50
|
-
}
|
|
51
|
-
// TS-3: all other named types -> export type
|
|
52
|
-
const tsType = mapTypeDefinition(def, diagnostics);
|
|
53
|
-
return `export type ${name} = ${tsType};`;
|
|
54
|
-
}
|
|
55
|
-
function renderInterface(name, fields, diagnostics) {
|
|
56
|
-
const sortedFields = Object.keys(fields).sort();
|
|
57
|
-
const lines = [];
|
|
58
|
-
for (const fieldName of sortedFields) {
|
|
59
|
-
const field = fields[fieldName];
|
|
60
|
-
const tsType = mapTypeDefinition(field.type, diagnostics);
|
|
61
|
-
// TS-5: optional -> ?
|
|
62
|
-
const opt = field.optional ? "?" : "";
|
|
63
|
-
lines.push(` ${fieldName}${opt}: ${tsType};`);
|
|
64
|
-
}
|
|
65
|
-
return `export interface ${name} {\n${lines.join("\n")}\n}`;
|
|
66
|
-
}
|
|
67
|
-
function mapTypeDefinition(def, diagnostics) {
|
|
68
|
-
switch (def.kind) {
|
|
69
|
-
case "primitive":
|
|
70
|
-
return mapPrimitive(def.type);
|
|
71
|
-
case "literal":
|
|
72
|
-
return renderLiteral(def.value);
|
|
73
|
-
case "array":
|
|
74
|
-
return `${wrapComplex(mapTypeDefinition(def.element, diagnostics), def.element)}[]`;
|
|
75
|
-
case "record":
|
|
76
|
-
return `Record<${mapTypeDefinition(def.key, diagnostics)}, ${mapTypeDefinition(def.value, diagnostics)}>`;
|
|
77
|
-
case "object": {
|
|
78
|
-
const sortedFields = Object.keys(def.fields).sort();
|
|
79
|
-
const parts = [];
|
|
80
|
-
for (const fieldName of sortedFields) {
|
|
81
|
-
const field = def.fields[fieldName];
|
|
82
|
-
const tsType = mapTypeDefinition(field.type, diagnostics);
|
|
83
|
-
const opt = field.optional ? "?" : "";
|
|
84
|
-
parts.push(`${fieldName}${opt}: ${tsType}`);
|
|
85
|
-
}
|
|
86
|
-
return `{ ${parts.join("; ")} }`;
|
|
87
|
-
}
|
|
88
|
-
case "union":
|
|
89
|
-
// TS-2: nullable uses T | null
|
|
90
|
-
return def.types.map((t) => mapTypeDefinition(t, diagnostics)).join(" | ");
|
|
91
|
-
case "ref":
|
|
92
|
-
return def.name;
|
|
93
|
-
default: {
|
|
94
|
-
// PLG-3, TS-1: unknown kind fallback
|
|
95
|
-
diagnostics.push({
|
|
96
|
-
level: "warn",
|
|
97
|
-
plugin: PLUGIN_NAME,
|
|
98
|
-
message: `Unknown TypeDefinition kind: "${def.kind}". Emitting "unknown".`,
|
|
99
|
-
});
|
|
100
|
-
return "unknown";
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
function mapPrimitive(type) {
|
|
105
|
-
switch (type) {
|
|
106
|
-
case "string":
|
|
107
|
-
return "string";
|
|
108
|
-
case "number":
|
|
109
|
-
return "number";
|
|
110
|
-
case "boolean":
|
|
111
|
-
return "boolean";
|
|
112
|
-
case "null":
|
|
113
|
-
return "null";
|
|
114
|
-
default:
|
|
115
|
-
return "unknown";
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
function renderLiteral(value) {
|
|
119
|
-
if (typeof value === "string") {
|
|
120
|
-
return JSON.stringify(value);
|
|
121
|
-
}
|
|
122
|
-
return String(value);
|
|
123
|
-
}
|
|
124
|
-
/** Wrap union types in parens when used as array element */
|
|
125
|
-
function wrapComplex(tsType, def) {
|
|
126
|
-
if (def.kind === "union") {
|
|
127
|
-
return `(${tsType})`;
|
|
128
|
-
}
|
|
129
|
-
return tsType;
|
|
130
|
-
}
|
|
131
|
-
// --- Action input rendering ---
|
|
132
|
-
function renderActionInputType(typeName, spec, diagnostics) {
|
|
133
|
-
if (!spec.input) {
|
|
134
|
-
return "";
|
|
135
|
-
}
|
|
136
|
-
const tsType = mapFieldSpec(spec.input, diagnostics);
|
|
137
|
-
return `export type ${typeName} = ${tsType};`;
|
|
138
|
-
}
|
|
139
|
-
function mapFieldSpec(spec, diagnostics) {
|
|
140
|
-
const baseType = mapFieldType(spec.type, spec, diagnostics);
|
|
141
|
-
// GEN-12: degrade for unknown structures
|
|
142
|
-
if (!spec.required && baseType !== "unknown") {
|
|
143
|
-
return `${baseType} | null`;
|
|
144
|
-
}
|
|
145
|
-
return baseType;
|
|
146
|
-
}
|
|
147
|
-
function mapFieldType(type, spec, diagnostics) {
|
|
148
|
-
if (typeof type === "object" && "enum" in type) {
|
|
149
|
-
// Enum -> union of literals
|
|
150
|
-
return type.enum.map((v) => renderLiteral(v)).join(" | ");
|
|
151
|
-
}
|
|
152
|
-
switch (type) {
|
|
153
|
-
case "string":
|
|
154
|
-
return "string";
|
|
155
|
-
case "number":
|
|
156
|
-
return "number";
|
|
157
|
-
case "boolean":
|
|
158
|
-
return "boolean";
|
|
159
|
-
case "null":
|
|
160
|
-
return "null";
|
|
161
|
-
case "object": {
|
|
162
|
-
if (spec.fields) {
|
|
163
|
-
const sortedFields = Object.keys(spec.fields).sort();
|
|
164
|
-
const parts = [];
|
|
165
|
-
for (const name of sortedFields) {
|
|
166
|
-
const field = spec.fields[name];
|
|
167
|
-
const fieldType = mapFieldSpec(field, diagnostics);
|
|
168
|
-
const opt = field.required ? "" : "?";
|
|
169
|
-
parts.push(`${name}${opt}: ${fieldType}`);
|
|
170
|
-
}
|
|
171
|
-
return `{ ${parts.join("; ")} }`;
|
|
172
|
-
}
|
|
173
|
-
// GEN-12: unstructured object -> unknown
|
|
174
|
-
diagnostics.push({
|
|
175
|
-
level: "warn",
|
|
176
|
-
plugin: PLUGIN_NAME,
|
|
177
|
-
message: "Object field without fields spec, degrading to Record<string, unknown>",
|
|
178
|
-
});
|
|
179
|
-
return "Record<string, unknown>";
|
|
180
|
-
}
|
|
181
|
-
case "array": {
|
|
182
|
-
if (spec.items) {
|
|
183
|
-
return `${mapFieldSpec(spec.items, diagnostics)}[]`;
|
|
184
|
-
}
|
|
185
|
-
diagnostics.push({
|
|
186
|
-
level: "warn",
|
|
187
|
-
plugin: PLUGIN_NAME,
|
|
188
|
-
message: "Array field without items spec, degrading to unknown[]",
|
|
189
|
-
});
|
|
190
|
-
return "unknown[]";
|
|
191
|
-
}
|
|
192
|
-
default:
|
|
193
|
-
return "unknown";
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
function pascalCase(str) {
|
|
197
|
-
return str
|
|
198
|
-
.split(/[-_\s]+/)
|
|
199
|
-
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
200
|
-
.join("");
|
|
201
|
-
}
|
|
202
|
-
//# sourceMappingURL=ts-plugin.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ts-plugin.js","sourceRoot":"","sources":["../../src/plugins/ts-plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"zod-plugin.d.ts","sourceRoot":"","sources":["../../src/plugins/zod-plugin.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,aAAa,EAEd,MAAM,aAAa,CAAC;AAMrB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,gBAAgB,GAAG,aAAa,CA2CzE"}
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
const PLUGIN_NAME = "codegen-plugin-zod";
|
|
2
|
-
const TS_PLUGIN_NAME = "codegen-plugin-ts";
|
|
3
|
-
export function createZodPlugin(options) {
|
|
4
|
-
const schemasFile = options?.schemasFile ?? "base.ts";
|
|
5
|
-
return {
|
|
6
|
-
name: PLUGIN_NAME,
|
|
7
|
-
generate(ctx) {
|
|
8
|
-
const diagnostics = [];
|
|
9
|
-
// PLG-11: Optional TS artifacts dependency
|
|
10
|
-
const tsArtifacts = ctx.artifacts[TS_PLUGIN_NAME];
|
|
11
|
-
const sortedTypeNames = Object.keys(ctx.schema.types).sort();
|
|
12
|
-
const schemaDecls = [];
|
|
13
|
-
// Collect all type names for forward declarations with z.lazy
|
|
14
|
-
const allTypeNames = new Set(sortedTypeNames);
|
|
15
|
-
for (const name of sortedTypeNames) {
|
|
16
|
-
const spec = ctx.schema.types[name];
|
|
17
|
-
schemaDecls.push(renderNamedSchema(name, spec, allTypeNames, tsArtifacts, diagnostics));
|
|
18
|
-
}
|
|
19
|
-
// Build imports
|
|
20
|
-
const imports = ['import { z } from "zod";'];
|
|
21
|
-
// ZOD-4: Import TS types for annotations when available
|
|
22
|
-
if (tsArtifacts && tsArtifacts.typeNames.length > 0) {
|
|
23
|
-
const typeImports = sortedTypeNames
|
|
24
|
-
.filter((n) => tsArtifacts.typeNames.includes(n))
|
|
25
|
-
.join(", ");
|
|
26
|
-
if (typeImports) {
|
|
27
|
-
imports.push(`import type { ${typeImports} } from "${tsArtifacts.typeImportPath}";`);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
const content = imports.join("\n") + "\n\n" + schemaDecls.join("\n\n") + "\n";
|
|
31
|
-
return {
|
|
32
|
-
patches: [{ op: "set", path: schemasFile, content }],
|
|
33
|
-
diagnostics,
|
|
34
|
-
};
|
|
35
|
-
},
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
// --- Schema rendering ---
|
|
39
|
-
function renderNamedSchema(name, spec, allTypeNames, tsArtifacts, diagnostics) {
|
|
40
|
-
const schemaName = `${name}Schema`;
|
|
41
|
-
const zodExpr = mapTypeDefinition(spec.definition, allTypeNames, diagnostics);
|
|
42
|
-
// ZOD-4/ZOD-5: Type annotation when TS artifacts available
|
|
43
|
-
const hasTypeAnnotation = tsArtifacts && tsArtifacts.typeNames.includes(name);
|
|
44
|
-
const annotation = hasTypeAnnotation ? `: z.ZodType<${name}>` : "";
|
|
45
|
-
return `export const ${schemaName}${annotation} = ${zodExpr};`;
|
|
46
|
-
}
|
|
47
|
-
function mapTypeDefinition(def, allTypeNames, diagnostics) {
|
|
48
|
-
switch (def.kind) {
|
|
49
|
-
case "primitive":
|
|
50
|
-
return mapPrimitiveZod(def.type);
|
|
51
|
-
case "literal":
|
|
52
|
-
return `z.literal(${renderLiteralValue(def.value)})`;
|
|
53
|
-
case "array":
|
|
54
|
-
return `z.array(${mapTypeDefinition(def.element, allTypeNames, diagnostics)})`;
|
|
55
|
-
case "record":
|
|
56
|
-
return handleRecord(def, allTypeNames, diagnostics);
|
|
57
|
-
case "object":
|
|
58
|
-
return renderZodObject(def.fields, allTypeNames, diagnostics);
|
|
59
|
-
case "union":
|
|
60
|
-
return handleUnion(def.types, allTypeNames, diagnostics);
|
|
61
|
-
case "ref":
|
|
62
|
-
// ZOD-2: Always z.lazy for circular reference support
|
|
63
|
-
return `z.lazy(() => ${def.name}Schema)`;
|
|
64
|
-
default: {
|
|
65
|
-
// ZOD-1: Unknown kind fallback
|
|
66
|
-
diagnostics.push({
|
|
67
|
-
level: "warn",
|
|
68
|
-
plugin: PLUGIN_NAME,
|
|
69
|
-
message: `Unknown TypeDefinition kind: "${def.kind}". Emitting "z.unknown()".`,
|
|
70
|
-
});
|
|
71
|
-
return "z.unknown()";
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
function mapPrimitiveZod(type) {
|
|
76
|
-
switch (type) {
|
|
77
|
-
case "string":
|
|
78
|
-
return "z.string()";
|
|
79
|
-
case "number":
|
|
80
|
-
return "z.number()";
|
|
81
|
-
case "boolean":
|
|
82
|
-
return "z.boolean()";
|
|
83
|
-
case "null":
|
|
84
|
-
return "z.null()";
|
|
85
|
-
default:
|
|
86
|
-
return "z.unknown()";
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
function renderLiteralValue(value) {
|
|
90
|
-
if (typeof value === "string") {
|
|
91
|
-
return JSON.stringify(value);
|
|
92
|
-
}
|
|
93
|
-
if (value === null) {
|
|
94
|
-
return "null";
|
|
95
|
-
}
|
|
96
|
-
return String(value);
|
|
97
|
-
}
|
|
98
|
-
function handleRecord(def, allTypeNames, diagnostics) {
|
|
99
|
-
const valueSchema = mapTypeDefinition(def.value, allTypeNames, diagnostics);
|
|
100
|
-
// ZOD-7: Non-string record key -> degrade to z.record(z.string(), ...)
|
|
101
|
-
if (def.key.kind !== "primitive" || def.key.type !== "string") {
|
|
102
|
-
diagnostics.push({
|
|
103
|
-
level: "warn",
|
|
104
|
-
plugin: PLUGIN_NAME,
|
|
105
|
-
message: `Record key type is not string (got ${JSON.stringify(def.key)}). Degrading to z.record(z.string(), ...).`,
|
|
106
|
-
});
|
|
107
|
-
return `z.record(z.string(), ${valueSchema})`;
|
|
108
|
-
}
|
|
109
|
-
return `z.record(z.string(), ${valueSchema})`;
|
|
110
|
-
}
|
|
111
|
-
function renderZodObject(fields, allTypeNames, diagnostics) {
|
|
112
|
-
const sortedFields = Object.keys(fields).sort();
|
|
113
|
-
const parts = [];
|
|
114
|
-
for (const fieldName of sortedFields) {
|
|
115
|
-
const field = fields[fieldName];
|
|
116
|
-
let zodType = mapTypeDefinition(field.type, allTypeNames, diagnostics);
|
|
117
|
-
// ZOD-6: optional -> .optional()
|
|
118
|
-
if (field.optional) {
|
|
119
|
-
zodType += ".optional()";
|
|
120
|
-
}
|
|
121
|
-
parts.push(` ${fieldName}: ${zodType},`);
|
|
122
|
-
}
|
|
123
|
-
return `z.object({\n${parts.join("\n")}\n})`;
|
|
124
|
-
}
|
|
125
|
-
function handleUnion(types, allTypeNames, diagnostics) {
|
|
126
|
-
// ZOD-3: 2-variant union with null -> z.nullable(T)
|
|
127
|
-
if (types.length === 2) {
|
|
128
|
-
const nullIdx = types.findIndex((t) => t.kind === "primitive" && t.type === "null");
|
|
129
|
-
if (nullIdx !== -1) {
|
|
130
|
-
const otherIdx = nullIdx === 0 ? 1 : 0;
|
|
131
|
-
const otherSchema = mapTypeDefinition(types[otherIdx], allTypeNames, diagnostics);
|
|
132
|
-
return `z.nullable(${otherSchema})`;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
const schemas = types.map((t) => mapTypeDefinition(t, allTypeNames, diagnostics));
|
|
136
|
-
return `z.union([${schemas.join(", ")}])`;
|
|
137
|
-
}
|
|
138
|
-
//# sourceMappingURL=zod-plugin.js.map
|