import type { Dislike, Extension, Follow, FollowAccept, FollowReject, Like, Note, Patch, ServerMetadata, Undo, User, } from "../schemas"; import type { EntityValidator } from "../validator/index"; type MaybePromise = T | Promise; type ParserCallbacks = { note: (note: Note) => MaybePromise; follow: (follow: Follow) => MaybePromise; followAccept: (followAccept: FollowAccept) => MaybePromise; followReject: (followReject: FollowReject) => MaybePromise; user: (user: User) => MaybePromise; like: (like: Like) => MaybePromise; dislike: (dislike: Dislike) => MaybePromise; undo: (undo: Undo) => MaybePromise; serverMetadata: (serverMetadata: ServerMetadata) => MaybePromise; extension: (extension: Extension) => MaybePromise; patch: (patch: Patch) => MaybePromise; }; /** * A class to parse the body of a request and call the appropriate callback. * @example * const parser = new RequestParserHandler(body, validator); * * await parser.parseBody({ * note: (note) => { * console.log(note); * }, * follow: (follow) => { * console.log(follow); * }, * ... * }); */ export class RequestParserHandler { constructor( private readonly body: Record< string, string | number | object | boolean | null >, private readonly validator: EntityValidator, ) {} /** * Parse the body of the request and call the appropriate callback. * To change the return type, edit the ReturnType generic parameter. * const parser = new RequestParserHandler(body, validator); * @param callbacks The callbacks to call when a specific entity is found. * @returns A promise that resolves when the body has been parsed, and the callbacks have finished executing. * @throws If the type field is missing or invalid * @example * await parser.parseBody({ * note: (note) => { * console.log(note); * }, * follow: (follow) => { * console.log(follow); * }, * ... * }); */ public async parseBody( callbacks: Partial>, ): Promise { if (!this.body.type) { throw new Error("Missing type field in body"); } switch (this.body.type) { case "Note": { const note = await this.validator.Note(this.body); if (callbacks.note) { return await callbacks.note(note); } break; } case "Patch": { const patch = await this.validator.Patch(this.body); if (callbacks.patch) { return await callbacks.patch(patch); } break; } case "Follow": { const follow = await this.validator.Follow(this.body); if (callbacks.follow) { return await callbacks.follow(follow); } break; } case "FollowAccept": { const followAccept = await this.validator.FollowAccept( this.body, ); if (callbacks.followAccept) { return await callbacks.followAccept(followAccept); } break; } case "FollowReject": { const followReject = await this.validator.FollowReject( this.body, ); if (callbacks.followReject) { return await callbacks.followReject(followReject); } break; } case "User": { const user = await this.validator.User(this.body); if (callbacks.user) { return await callbacks.user(user); } break; } case "Like": { const like = await this.validator.Like(this.body); if (callbacks.like) { return await callbacks.like(like); } break; } case "Dislike": { const dislike = await this.validator.Dislike(this.body); if (callbacks.dislike) { return await callbacks.dislike(dislike); } break; } case "Undo": { const undo = await this.validator.Undo(this.body); if (callbacks.undo) { return await callbacks.undo(undo); } break; } case "ServerMetadata": { const serverMetadata = await this.validator.ServerMetadata( this.body, ); if (callbacks.serverMetadata) { return await callbacks.serverMetadata(serverMetadata); } break; } case "Extension": { const extension = await this.validator.Extension(this.body); if (callbacks.extension) { return await callbacks.extension(extension); } break; } default: throw new Error( `Invalid type field in body: ${this.body.type}`, ); } throw new Error(`Invalid type field in body: ${this.body.type}`); } }