All files buildUrl.ts

0% Statements 0/58
0% Branches 0/1
0% Functions 0/1
0% Lines 0/58

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59                                                                                                                     
/**
 * Copyright (c) OpenLens Authors. All rights reserved.
 * Licensed under MIT License. See LICENSE in root directory for more information.
 */

import { compile } from "path-to-regexp";
import type { RouteProps } from "react-router";
import { isDefined } from "./type-narrowing";

export interface UrlRouteProps extends RouteProps {
  path: string;
}

export interface URLParams<P extends object = {}, Q extends object = {}> {
  params?: P;
  query?: Q;
  fragment?: string;
}

export function buildURL<P extends object = {}, Q extends object = {}>(path: string, { params, query, fragment }: URLParams<P, Q> = {}) {
  const pathBuilder = compile(String(path));

  const queryParams = query ? new URLSearchParams(Object.entries(query)).toString() : "";
  const parts = [
    pathBuilder(params),
    queryParams && `?${queryParams}`,
    fragment && `#${fragment}`,
  ];

  return parts.filter(isDefined).join("");
}

export function buildURLPositional<P extends object = {}, Q extends object = {}>(path: string) {
  return function (params?: P, query?: Q, fragment?: string): string {
    return buildURL(path, { params, query, fragment });
  };
}

export type UrlParamsFor<Pathname extends string> =
  Pathname extends `${string}/:${infer A}?/${infer Tail}`
    ? Partial<Record<A, string>> & UrlParamsFor<`/${Tail}`>
    : Pathname extends `${string}/:${infer A}/${infer Tail}`
      ? Record<A, string> & UrlParamsFor<`/${Tail}`>
      : Pathname extends `${string}/:${infer A}?`
        ? Partial<Record<A, string>>
        : Pathname extends `${string}/:${infer A}`
          ? Record<A, string>
          : {};

export interface UrlBuilder<Pathname extends string> {
  compile(params: UrlParamsFor<Pathname>, query?: object, fragment?: string): string;
}

export function urlBuilderFor<Pathname extends string>(pathname: Pathname): UrlBuilder<Pathname> {
  return {
    compile: buildURLPositional(pathname),
  };
}