@route-weaver/core
Version:
A typesafe navigation package for creating and managing routes.
120 lines (118 loc) • 4.54 kB
TypeScript
/**
* The basic shape of a navigation item, without the ID.
*/
interface NavItem<TMeta = unknown> {
label: string;
path: string;
meta?: TMeta;
}
/**
* A map of all declared routes, where the key is a unique route ID.
* This will be the single source of truth for all routes.
*/
type RouteDeclarations<TMeta = unknown> = Record<string, string | {
path: string;
meta?: TMeta;
}>;
/**
* Defines the structure for navigation groups and their labels.
*/
type NavDefinitions<T extends string> = Record<string, Partial<Record<T, string>>>;
/**
* Represents a fully resolved and structured navigation item,
* which includes its ID and any potential children.
*/
interface StructuredNavItem<TMeta = unknown> extends NavItem<TMeta> {
id: string;
fullPath: string;
children?: StructuredNavItem<TMeta>[];
}
/**
* The final, structured navigation object, ready to be used in your application.
* The keys are the names of your contextual groups.
*/
type StructuredNavigation<TNavDef, TMeta = unknown> = {
[K in keyof TNavDef]: StructuredNavItem<TMeta>[];
};
/**
* Represents a matched route, including the route definition and any URL parameters.
*/
interface ActiveRoute<TMeta = unknown> {
route: StructuredNavItem<TMeta>;
params: Record<string, any>;
}
/**
* A generic function that takes a string key and returns a translated string.
* This is compatible with common i18n libraries (e.g., the `t` function).
*/
type Translator = (key: string) => string;
/**
* The public interface of the self-contained navigation instance created
* by the `build` method.
*/
interface NavigationInstance<T extends RouteDeclarations<TMeta>, TNavDef, TMeta = unknown> {
navigation: StructuredNavigation<TNavDef, TMeta>;
getActiveRoute: (pathname: string) => ActiveRoute<TMeta> | undefined;
getBreadcrumbs: (pathname: string) => StructuredNavItem<TMeta>[];
filterNavigation: (predicate: (item: StructuredNavItem<TMeta>) => boolean) => StructuredNavigation<TNavDef, TMeta>;
generateSitemap: (options: {
domain: string;
}) => string;
on: (event: 'change', callback: () => void) => () => void;
buildPath: <R extends keyof T>(...args: BuildPathArgs<RoutePath<T[R]>, R>) => string;
}
/**
* A helper type to extract the path from a route definition.
*/
type RoutePath<T> = T extends string ? T : T extends {
path: string;
} ? T['path'] : never;
/**
* A helper type to define the arguments for `buildPath`.
* If the route has no params, the `params` object is optional.
* If the route has params, the `params` object is required.
*/
type BuildPathArgs<TPath extends string, TId> = [
id: TId,
...(ExtractRouteParams<TPath> extends never ? [params?: never] : [params: RouteParams<TPath>])
];
/**
* The public interface of the route-weaver factory instance.
*/
interface RouteWeaverInstance<T extends RouteDeclarations<TMeta>, TMeta = unknown> {
buildNav: <U extends NavDefinitions<keyof T & string>>(definitions: U, options?: {
t?: Translator;
}) => NavigationInstance<T, U, TMeta>;
join: (...parts: string[]) => string;
}
/**
* Extracts parameter names from a route path string.
* @example
* type P = ExtractRouteParams<'/users/:id/posts/:postId'>;
* // P is 'id' | 'postId'
*/
type ExtractRouteParams<T extends string> = string extends T ? string : T extends `${infer _Start}:${infer Param}/${infer Rest}` ? Param | ExtractRouteParams<Rest> : T extends `${infer _Start}:${infer Param}` ? Param : never;
/**
* Creates a record type for the parameters of a given route path.
* If the path has no parameters, it's an empty object.
* @example
* type P1 = RouteParams<'/users/:id'>; // { id: string | number }
* type P2 = RouteParams<'/about'>; // {}
*/
type RouteParams<T extends string> = {
[P in ExtractRouteParams<T>]: string | number;
};
/**
* Describes the shape of a route definition in the nested structure.
*/
interface RouteDefinition<TMeta = unknown> {
path: string;
label: string;
children?: NestedRouteDeclarations<TMeta>;
meta?: TMeta;
}
/**
* A map of all declared routes in a nested structure, where the key is a unique route ID.
*/
type NestedRouteDeclarations<TMeta = unknown> = Record<string, RouteDefinition<TMeta>>;
export type { ActiveRoute, BuildPathArgs, ExtractRouteParams, NavDefinitions, NavItem, NavigationInstance, NestedRouteDeclarations, RouteDeclarations, RouteDefinition, RouteParams, RoutePath, RouteWeaverInstance, StructuredNavItem, StructuredNavigation, Translator };