UNPKG

@autobe/agent

Version:

AI backend server code generator

156 lines (145 loc) 5.34 kB
import { AutoBeAnalyze, AutoBeInterfaceEndpointDesign, } from "@autobe/interface"; import { StringUtil } from "@autobe/utils"; import { LlmTypeChecker, NamingConvention } from "@typia/utils"; import { singular } from "pluralize"; import typia, { ILlmApplication, ILlmSchema, IValidation } from "typia"; export namespace AutoBeInterfaceEndpointProgrammer { /** * Filter endpoint designs: * * - For base: Remove guest actors and login/join/refresh/session * authorizationType * - For action: Remove all non-null authorizationType (action endpoints must be * null only) */ export const filter = (props: { kind: "base" | "action"; design: AutoBeInterfaceEndpointDesign; actors: AutoBeAnalyze.IActor[]; }): boolean => { // Action endpoints: only allow authorizationType: null if (props.kind === "action") return props.design.authorizationType === null; else if ( props.design.endpoint.path === "/auth" || props.design.endpoint.path.startsWith("/auth/") ) return false; // remove specific auth types if ( props.design.authorizationType === "login" || props.design.authorizationType === "join" || props.design.authorizationType === "refresh" || props.design.authorizationType === "withdraw" ) return false; else if (props.design.authorizationType === "session") { props.design.authorizationActors = props.design.authorizationActors.filter((name) => { const actor: AutoBeAnalyze.IActor | undefined = props.actors.find( (a) => a.name === name, ); if (actor === undefined) return false; return actor.kind !== "guest"; }); if (props.design.authorizationActors.length === 0) return false; else if ( props.design.endpoint.method !== "get" && props.design.endpoint.method !== "patch" ) return false; return true; } return true; }; export const fixDesign = (props: { actors: AutoBeAnalyze.IActor[]; design: AutoBeInterfaceEndpointDesign; }): AutoBeInterfaceEndpointDesign => { props.design.endpoint.path = fixPath(props.design.endpoint.path); if (props.design.authorizationActors.length === 1) { const actor: AutoBeAnalyze.IActor | undefined = props.actors.find( (a) => a.name === props.design.authorizationActors[0], ); if (actor !== undefined && actor.kind !== "admin") { const param: string = NamingConvention.camel(singular(actor.name)) + "Id"; const bracket: string = `{${param}}`; if (props.design.endpoint.path.includes(bracket) === true) props.design.endpoint.path = props.design.endpoint.path.replace( bracket, "", ); } } else if ( props.design.authorizationActors.length > 1 && props.design.endpoint.path.includes("{actorId}") ) { props.design.endpoint.path = props.design.endpoint.path.replace( "{actorId}", "", ); } return props.design; }; export const fixPath = (path: string): string => { return path .split("/") .map((s) => s.startsWith("{") && s.endsWith("}") ? `{${NamingConvention.camel(s.slice(1, -1).replace(/-/g, "_"))}}` : s, ) .join("/"); }; export const fixApplication = (props: { application: ILlmApplication; actors: AutoBeAnalyze.IActor[]; }): void => { const $defs: Record<string, ILlmSchema> = props.application.functions[0].parameters.$defs; const design: ILlmSchema | undefined = $defs[typia.reflect.name<AutoBeInterfaceEndpointDesign>()]; if (design === undefined) throw new Error("AutoBeInterfaceEndpointDesign is undefined"); else if (LlmTypeChecker.isObject(design) === false) throw new Error("AutoBeInterfaceEndpointDesign is not object type"); const property: ILlmSchema | undefined = design.properties["authorizationActors"]; if (property === undefined) throw new Error( "AutoBeInterfaceEndpointDesign.authorizationActors is undefined", ); else if (LlmTypeChecker.isArray(property) === false) throw new Error( "AutoBeInterfaceEndpointDesign.authorizationActors is not array type", ); property.items = { type: "string", enum: props.actors.map((actor) => actor.name), }; }; export const validateDesign = (props: { design: AutoBeInterfaceEndpointDesign; actors: AutoBeAnalyze.IActor[]; path: string; errors: IValidation.IError[]; }): void => { // if (props.actors.length === 0) props.design.authorizationActors = []; props.design.authorizationActors.forEach((actorName, i) => { if (props.actors.find((actor) => actor.name === actorName) === undefined) props.errors.push({ path: `${props.path}.authorizationActors[${i}]`, expected: props.actors.map((a) => JSON.stringify(a.name)).join(" | "), value: actorName, description: StringUtil.trim` Actor "${actorName}" is not defined in the roles list. Please select one of them below, or do not define (\`null\`): ${props.actors.map((actor) => `- ${actor.name}`).join("\n")} `, }); }); }; }