UNPKG

@autobe/agent

Version:

AI backend server code generator

171 lines (160 loc) 5.73 kB
import { AutoBeOpenApi, AutoBeProgressEventBase, AutoBeTestGenerateFunction, AutoBeTestPrepareFunction, AutoBeTestValidateEvent, IAutoBeCompiler, } from "@autobe/interface"; import { StringUtil } from "@autobe/utils"; import { NamingConvention } from "@typia/utils"; import path from "path"; import { IValidation } from "typia"; import { validateEmptyCode } from "../../../utils/validateEmptyCode"; import { IAutoBeTestArtifacts } from "../structures/IAutoBeTestArtifacts"; import { IAutoBeTestGenerateProcedure } from "../structures/IAutoBeTestGenerateProcedure"; import { AutoBeTestFunctionProgrammer } from "./AutoBeTestFunctionProgrammer"; import { AutoBeTestPrepareProgrammer } from "./AutoBeTestPrepareProgrammer"; export namespace AutoBeTestGenerateProgrammer { /* ---------------------------------------------------------------- GETTERS ---------------------------------------------------------------- */ export function is( document: AutoBeOpenApi.IDocument, operation: AutoBeOpenApi.IOperation, ): boolean { if (operation.requestBody === null) return false; const schema: AutoBeOpenApi.IJsonSchema | undefined = document.components.schemas[operation.requestBody.typeName]; if (schema === undefined) return false; return AutoBeTestPrepareProgrammer.is( operation.requestBody.typeName, schema, ); } export function size(document: AutoBeOpenApi.IDocument): number { return document.operations.filter((operation) => AutoBeTestGenerateProgrammer.is(document, operation), ).length; } export function getFunctionName(operation: AutoBeOpenApi.IOperation): string { const accessor: string[] = operation.accessor!.map(NamingConvention.snake); return `generate_random_${accessor.join("_")}`; } /* ---------------------------------------------------------------- WRITERS ---------------------------------------------------------------- */ export function writeTemplateCode(props: { operation: AutoBeOpenApi.IOperation; prepare: AutoBeTestPrepareFunction; }): string { const functionName: string = getFunctionName(props.operation); const input: string = props.operation.requestBody?.typeName ?? "unknown"; const output: string = props.operation.responseBody?.typeName ?? "void"; return StringUtil.trim` export async function ${functionName}( connection: api.IConnection, props: { body?: DeepPartial<${input}> | undefined; ${writeParameterDeclarations(props.operation)} } ): Promise<${output}> { const prepared: ${input} = ${props.prepare.name}( props.body ); return await api.functional.${props.operation.accessor!.join(".")}( connection, { body: prepared, ${writeParameterArguments(props.operation)} }, ); } `; } function writeParameterDeclarations( operation: AutoBeOpenApi.IOperation, ): string { if (operation.parameters.length === 0) return ""; return StringUtil.trim` params: { ${operation.parameters.map((p) => ` ${p.name}: ${p.schema.type};`).join("\n")} }; ` .split("\n") .filter((line) => line.length !== 0) .map((line) => ` ${line.trim()}`) .join("\n"); } function writeParameterArguments( operation: AutoBeOpenApi.IOperation, ): string { if (operation.parameters.length === 0) return ""; return operation.parameters .map((p) => ` ${p.name}: props.params.${p.name},`) .join("\n"); } /* ---------------------------------------------------------------- COMPILERS ---------------------------------------------------------------- */ export function compile(props: { compiler: IAutoBeCompiler; procedure: IAutoBeTestGenerateProcedure; progress: AutoBeProgressEventBase; step: number; }): Promise<AutoBeTestValidateEvent<AutoBeTestGenerateFunction>> { return AutoBeTestFunctionProgrammer.compile({ compiler: props.compiler, document: props.procedure.artifacts.document, function: props.procedure.function, files: { [props.procedure.function.location]: props.procedure.function.content, [props.procedure.prepare.location]: props.procedure.prepare.content, }, progress: props.progress, step: props.step, }); } export async function replaceImportStatements(props: { compiler: IAutoBeCompiler; artifacts: IAutoBeTestArtifacts; prepare: AutoBeTestPrepareFunction; location: string; content: string; }): Promise<string> { let code: string = await props.compiler.typescript.removeImportStatements( props.content, ); const imports: string[] = [ ...AutoBeTestFunctionProgrammer.writeImportStatements( props.artifacts.document.components.schemas, ), `import { ${props.prepare.name} } from "${path .relative( path.dirname(props.location), props.prepare.location.replace(".ts", ""), ) .replaceAll(path.sep, "/")}";`, ]; code = [...imports, code].join("\n"); return await props.compiler.typescript.beautify(code); } /* ---------------------------------------------------------------- VALIDATE ---------------------------------------------------------------- */ export function validate(props: { procedure: IAutoBeTestGenerateProcedure; draft: string; revise: { final: string | null; }; }): IValidation.IError[] { return validateEmptyCode({ path: "$input", asynchronous: true, name: props.procedure.function.name, draft: props.draft, revise: props.revise, }); } }