59 lines
1.7 KiB
TypeScript
59 lines
1.7 KiB
TypeScript
import "../core/metadata.ts";
|
|
import { defineMetadata, getMetadata } from "../core/metadata.ts";
|
|
import { callerFile } from "../core/paths.ts";
|
|
import { dirname } from "node:path";
|
|
|
|
/**
|
|
* `@Controller()` groups HTTP handlers under a path prefix.
|
|
*/
|
|
export const CONTROLLER_METADATA_KEY = "muddle:controller";
|
|
|
|
export interface ControllerOptions {
|
|
/** Path prefix of every route of the controller, e.g. `/users`. */
|
|
prefix?: string;
|
|
/** Optional tag used by documentation adapters. */
|
|
tag?: string;
|
|
/** Directory of the file that declares the controller. */
|
|
dir?: string;
|
|
}
|
|
|
|
/** Normalises a prefix to `/segment` shape (no trailing slash). */
|
|
export function normalizePrefix(prefix: string): string {
|
|
if (!prefix || prefix === "/") return "";
|
|
const withLeading = prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
return withLeading.replace(/\/+$/, "");
|
|
}
|
|
|
|
/** Declares a controller. */
|
|
export function Controller(
|
|
prefix?: string | ControllerOptions,
|
|
): ClassDecorator {
|
|
return (target) => {
|
|
const options: ControllerOptions =
|
|
typeof prefix === "string" ? { prefix } : (prefix ?? {});
|
|
const caller = callerFile();
|
|
defineMetadata(
|
|
CONTROLLER_METADATA_KEY,
|
|
{
|
|
...options,
|
|
dir: options.dir ?? (caller ? dirname(caller) : undefined),
|
|
},
|
|
target as object,
|
|
);
|
|
return target;
|
|
};
|
|
}
|
|
|
|
/** Reads the options of a `@Controller()` decorated class. */
|
|
export function getControllerOptions(target: object): ControllerOptions {
|
|
return (
|
|
(getMetadata(CONTROLLER_METADATA_KEY, target) as
|
|
| ControllerOptions
|
|
| undefined) ?? {}
|
|
);
|
|
}
|
|
|
|
/** Reads the normalised path prefix of a controller. */
|
|
export function getControllerPrefix(target: object): string {
|
|
return normalizePrefix(getControllerOptions(target).prefix ?? "");
|
|
}
|