Skip to content

Commit

Permalink
docs: improve jsdocs (#574)
Browse files Browse the repository at this point in the history
  • Loading branch information
TheAlexLichter authored Nov 20, 2023
1 parent e5e577e commit c67121d
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 10 deletions.
13 changes: 13 additions & 0 deletions src/event/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,23 @@ export class H3Event<
}
}

/**
* Checks if the input is an H3Event object.
* @param input - The input to check.
* @returns True if the input is an H3Event object, false otherwise.
* @see H3Event
*/
export function isEvent(input: any): input is H3Event {
return hasProp(input, "__is_event__");
}

/**
* Creates a new H3Event instance from the given Node.js request and response objects.
* @param req - The NodeIncomingMessage object.
* @param res - The NodeServerResponse object.
* @returns A new H3Event instance.
* @see H3Event
*/
export function createEvent(
req: NodeIncomingMessage,
res: NodeServerResponse,
Expand Down
5 changes: 5 additions & 0 deletions src/event/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ export function defineResponseMiddleware<
return fn;
}

/**
* Checks if any kind of input is an event handler.
* @param input The input to check.
* @returns True if the input is an event handler, false otherwise.
*/
export function isEventHandler(input: any): input is EventHandler {
return hasProp(input, "__is_handler__");
}
Expand Down
66 changes: 58 additions & 8 deletions src/utils/body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ import destr from "destr";
import type { Encoding, HTTPMethod, InferEventInput } from "../types";
import type { H3Event } from "../event";
import { createError } from "../error";
import { parse as parseMultipartData } from "./internal/multipart";
import {
type MultiPartData,
parse as parseMultipartData,
} from "./internal/multipart";
import { assertMethod, getRequestHeader, toWebRequest } from "./request";
import { ValidateFunction, validateData } from "./internal/validate";
import { hasProp } from "./internal/object";
Expand Down Expand Up @@ -117,8 +120,8 @@ export function readRawBody<E extends Encoding = "utf8">(

/**
* Reads request body and tries to safely parse using [destr](https://github.com/unjs/destr).
* @param event {H3Event} H3 event passed by h3 handler
* @param encoding {Encoding} encoding="utf-8" - The character encoding to use.
* @param event H3 event passed by h3 handler
* @param encoding The character encoding to use, defaults to 'utf-8'.
*
* @return {*} The `Object`, `Array`, `String`, `Number`, `Boolean`, or `null` value corresponding to the request JSON body
*
Expand Down Expand Up @@ -157,6 +160,26 @@ export async function readBody<
return parsed as unknown as _T;
}

/**
* Tries to read the request body via `readBody`, then uses the provided validation function and either throws a validation error or returns the result.
* @param event The H3Event passed by the handler.
* @param validate The function to use for body validation. It will be called passing the read request body. If the result is not false, the parsed body will be returned.
* @throws If the validation function returns `false` or throws, a validation error will be thrown.
* @return {*} The `Object`, `Array`, `String`, `Number`, `Boolean`, or `null` value corresponding to the request JSON body.
* @see {readBody}
*
* ```ts
* // With a custom validation function
* const body = await readValidatedBody(event, (body) => {
* return typeof body === "object" && body !== null
* })
*
* // With a zod schema
* import { z } from 'zod'
* const objectSchema = z.object()
* const body = await readValidatedBody(event, objectSchema.safeParse)
* ```
*/
export async function readValidatedBody<
T,
Event extends H3Event = H3Event,
Expand All @@ -166,7 +189,30 @@ export async function readValidatedBody<
return validateData(_body, validate);
}

export async function readMultipartFormData(event: H3Event) {
/**
* Tries to read and parse the body of a an H3Event as multipart form.
* @param event The H3Event object to read multipart form from.
*
* @return The parsed form data. If no form could be detected because the content type is not multipart/form-data or no boundary could be found.
*
* ```ts
* const formData = await readMultipartFormData(event)
* // The result could look like:
* // [
* // {
* // "data": "other",
* // "name": "baz",
* // },
* // {
* // "data": "something",
* // "name": "some-other-data",
* // },
* // ]
* ```
*/
export async function readMultipartFormData(
event: H3Event,
): Promise<MultiPartData[] | undefined> {
const contentType = getRequestHeader(event, "content-type");
if (!contentType || !contentType.startsWith("multipart/form-data")) {
return;
Expand All @@ -183,9 +229,8 @@ export async function readMultipartFormData(event: H3Event) {
}

/**
* Constructs a FormData object from an event.
* @param event {H3Event}
* @returns {FormData}
* Constructs a FormData object from an event, after converting it to a a web request.
* @param event The H3Event object to read the form data from.
*
* ```ts
* const eventHandler = event => {
Expand All @@ -195,10 +240,15 @@ export async function readMultipartFormData(event: H3Event) {
* }
* ```
*/
export async function readFormData(event: H3Event) {
export async function readFormData(event: H3Event): Promise<FormData> {
return await toWebRequest(event).formData();
}

/**
* Captures a stream from a request.
* @param event The H3Event object containing the request information.
* @returns Undefined if the request can't transport a payload, otherwise a ReadableStream of the request body.
*/
export function getRequestWebStream(
event: H3Event,
): undefined | ReadableStream {
Expand Down
9 changes: 8 additions & 1 deletion src/utils/internal/object.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
// TODO: Benchmark typeof vs try/catch (i guess try/catch is faster in non-edge cases!)
export function hasProp(obj: object, prop: string | symbol) {

/**
* Checks if a certain input has a given property.
* @param obj - The input to check.
* @param prop - The property to check for.
* @returns A boolean indicating whether the input is an object and has the property.
*/
export function hasProp(obj: any, prop: string | symbol) {
try {
return prop in obj;
} catch {
Expand Down
8 changes: 8 additions & 0 deletions src/utils/internal/validate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,14 @@ export type ValidateFunction<T> = (
data: unknown,
) => ValidateResult<T> | Promise<ValidateResult<T>>;

/**
* Validates the given data using the provided validation function.
* @template T The expected type of the validated data.
* @param data The data to validate.
* @param fn The validation function to use - can be async.
* @returns A Promise that resolves with the validated data if it passes validation, meaning the validation function does not throw and returns a value other than false.
* @throws {ValidationError} If the validation function returns false or throws an error.
*/
export async function validateData<T>(
data: unknown,
fn: ValidateFunction<T>,
Expand Down
7 changes: 6 additions & 1 deletion src/utils/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ import { withoutTrailingSlash, withoutBase } from "ufo";
import { EventHandler } from "../types";
import { eventHandler } from "../event";

/**
* Prefixes and executes a handler with a base path.
* @param base The base path to prefix. When set to an empty string, the handler will be run as is.
* @param handler The event handler to use with the adapted path.
*/
export function useBase(base: string, handler: EventHandler): EventHandler {
base = withoutTrailingSlash(base);

Expand All @@ -10,7 +15,7 @@ export function useBase(base: string, handler: EventHandler): EventHandler {
}

return eventHandler(async (event) => {
// Keep original incoming url accessable
// Keep original incoming url accessible
event.node.req.originalUrl =
event.node.req.originalUrl || event.node.req.url || "/";

Expand Down

0 comments on commit c67121d

Please sign in to comment.