import { type AnyObject, type EmptyObject, type IsEqual, type PartialWithUndefined, type RemoveLastTupleEntry, type Values } from '@augment-vir/common'; /** * Shared options for {@link BasePathTree}. * * @category Internal */ export type SharedPathTreeOptions = { /** Set to true to disable this route in sanitization. */ disable?: boolean | undefined; /** * If set, sanitization will always set this path part to the value provided. All other path * parts (ancestors and children) will not be changed. This should be the name of a sibling tree * path. * * Note that at the top level of a path tree, this does nothing. */ redirectTo?: string | undefined; /** * If set, sanitization will accept any of these path parts as an alias for this path. Each * entry is a single segment (an optional leading slash is allowed) that may be suffixed with * `/*` to also redirect descendants. The matched path part is rewritten to this node's own path * name. * * - `'old'` matches only the exact path `/old` (no descendants). * - `'old/*'` matches `/old/` and forwards the remaining segments unchanged. It does * not match the bare `/old`. * * Both forms can be combined (e.g. `redirectFrom: ['old', 'old/*']`) to redirect both the bare * path and all descendants. */ redirectFrom?: ReadonlyArray | undefined; }; /** * Base type for the constructor parameter tree in {@link PathTree}. * * @category Internal */ export type BasePathTree = ({ /** Set true to allow this path as a bare path (without any children). */ allowBare: boolean; children?: { [Path in string]: BasePathTree /** * If a child path is an empty object, that means that it has no children * and `allowBare` is set to `true`. */ | EmptyObject; } | undefined; anyChildren?: never; } & SharedPathTreeOptions) | ({ allowBare?: never; /** Set this to `true` to allow any nested paths (string[]). */ anyChildren: true; children?: never; } & SharedPathTreeOptions); /** * Converts a {@link PathTree} tree to a union of possible path arrays. * * @category Internal */ export type TreePaths | EmptyObject> = EmptyObject extends Tree ? Readonly<[]> : IsEqual['anyChildren'], true> extends true ? Readonly : Exclude['allowBare'] extends true ? Readonly<[]> | NestedTreePaths> : NestedTreePaths>; /** * Nested part of {@link TreePaths}. * * @category Internal */ export type NestedTreePaths = NestedTree['children'] extends infer Children extends NonNullable ? Values<{ [Path in keyof Children]: Readonly<[ Path extends `:${string}` ? string : Path, ...TreePaths ]>; }> : Readonly<[]>; /** * {@link RuntimeTreePaths} but only for sub-trees of path-param paths. * * @category Internal */ export type TreeWithParams, OriginalTree extends Readonly, CurrentPaths extends PropertyKey[], PathParam extends string> = EmptyObject extends Tree ? Readonly<{ path: PathParam; fullPaths: Readonly<[ ...RemoveLastTupleEntry, PathParam ]>; PathsType: Readonly, PathParam ]>>; }> : Tree extends { anyChildren: true; } ? Readonly<{ path: PathParam; fullPaths: Readonly<[ ...RemoveLastTupleEntry, PathParam ]>; PathsType: Readonly, PathParam ]>>; }> : Readonly<{ path: PathParam; fullPaths: Readonly<[ ...RemoveLastTupleEntry, PathParam ]>; PathsType: Readonly, PathParam ]>>; children: Readonly<{ [ChildPath in keyof Exclude['children']]: RuntimeTreePaths['children'], AnyObject>[ChildPath], OriginalTree, [ ...RemoveLastTupleEntry, PathParam, ChildPath ], ChildPath>; }>; }>; /** * Converts a path tree into a nested object type. * * The `root` property represents the current path when it is valid as a bare path. The `children` * property contains entries for each known child path. * * @category Internal */ export type MappedPathTree> = EmptyObject extends Tree ? Readonly<{ root: LeafValue; }> : Tree extends Readonly<{ children: infer Children extends object; }> ? keyof Children extends never ? Tree extends Readonly<{ allowBare: true; }> ? Readonly<{ root: LeafValue; }> : EmptyObject : Tree extends Readonly<{ allowBare: true; }> ? Readonly<{ root: LeafValue; children: MappedPathTreeChildren; }> : Readonly<{ children: MappedPathTreeChildren; }> : Tree extends Readonly<{ allowBare: true; }> ? Readonly<{ root: LeafValue; }> : EmptyObject; /** * Helper for {@link MappedPathTree}. * * @category Internal */ export type MappedPathTreeChildren = Readonly<{ [Path in keyof Children]: MappedPathTree>>; }>; /** * A generic mapped path tree that can represent a mapped tree from any path-tree definition. * * @category Internal */ export type GenericMappedPathTree = Readonly>>; }>>; /** * Creates a {@link MappedPathTree} value for the given path tree. * * @category Main */ export declare function mapPathTree(): >(tree: Tree, mappedTree: MappedPathTree) => MappedPathTree; /** * Gets the root value in a mapped path tree that exactly matches the given paths. * * @category Main */ export declare function getMappedPathTreeValue(currentPaths: ReadonlyArray, mappedPathTree: Readonly>): LeafValue | undefined; /** * Generates the types for {@link PathTree.paths}. * * @category Internal */ export type RuntimeTreePaths, OriginalTree extends Readonly = Tree, CurrentPaths extends PropertyKey[] = [], CurrentPath extends PropertyKey = ''> = CurrentPath extends `:${string}` ? TreeWithParams & { /** Fill the path param with a value. */ fill: (pathParam: PathParam) => TreeWithParams; } : EmptyObject extends Tree ? Readonly<{ path: CurrentPath; fullPaths: Readonly; PathsType: Readonly>; children: EmptyObject; }> : Tree extends { anyChildren: true; } ? Readonly<{ path: CurrentPath; fullPaths: Readonly; PathsType: Readonly>; children: EmptyObject; }> : Readonly<{ path: CurrentPath; fullPaths: Readonly; PathsType: Readonly>; children: 'children' extends keyof Tree ? Tree['children'] extends object ? Readonly<{ [ChildPath in keyof Exclude['children']]: RuntimeTreePaths['children'], AnyObject>[ChildPath], OriginalTree, [ ...CurrentPaths, ChildPath ], ChildPath>; }> : EmptyObject : EmptyObject; }>; /** * A generic version of {@link RuntimeTreePaths} that any {@link PathTree.paths} value can be assigned * to. * * @category Internal */ export type GenericTreePaths = Readonly<{ /** Fills a path that has a path param. */ fill?: (pathParam: string) => GenericTreePaths; path: string; fullPaths: ReadonlyArray; PathsType: ReadonlyArray; children?: Readonly> | undefined; }>; /** * Remove all `PathsType` properties from a path tree. * * @category Internal */ export type RemovePathsTypes = Paths extends ReadonlyArray ? Paths : Paths extends (pathParam: string) => infer ReturnValue ? (pathParam: string) => RemovePathsTypes : Paths extends Readonly ? Omit; }>, 'PathsType'> : Paths; /** * Extract all valid path string arrays for the current path. * * @category Internal */ export type ValidPaths | EmptyObject, CurrentPaths extends PropertyKey[] = []> = Extract, Readonly<[ ...CurrentPaths, ...string[] ]>>; /** * Easily create a tree of valid paths. Use {@link PathTree.sanitizePaths} in your router sanitizer * to verify paths. * * Note that a path tree can never have `allowBare: false` _and_ no children (`children: {}`) in the * same path. Doing so will throw an error in this class's constructor. * * @category Main * @example * * ```ts * import {SpaRouter, PathTree} from 'spa-router-vir'; * * const myPathTree = new PathTree({ * allowBare: true, * children: { * 'path-a': {}, * 'path-b': {}, * }, * }); * * export const myRouter = new SpaRouter({ * sanitizeRoute(rawRoute) { * return { * paths: myPathTree.sanitizePaths(rawRoute.paths), * hash: undefined, * search: undefined, * }; * }, * }); * ``` */ export declare class PathTree> { readonly tree: Readonly; /** * A paths object for accessing the paths tree at runtime. * * @example * * ```ts * router.setRoute(myPathTree.paths['path-a'].fullPaths); * ``` */ readonly paths: RuntimeTreePaths; readonly pathsWithoutTypes: RemovePathsTypes>; constructor(tree: Readonly); /** * The `route.paths` type for this tree. Do not access this value at runtime (it will throw an * error), only use it as a type. * * @throws Any time its accessed as a runtime value. */ get PathsType(): TreePaths; /** Sanitize the given paths to match this path tree. */ sanitizePaths(rawPaths: ReadonlyArray): TreePaths; } /** * Sanitize a set of paths based on a given tree. This is used internally by {@link PathTree}. * * @category Internal */ export declare function sanitizeTreePaths(rawPaths: ReadonlyArray, tree: Readonly): ReadonlyArray;