url.builder.ts•3.53 kB
/**
 * URL Builder Utility for JIRA API
 *
 * Handles URL construction with proper slash handling and query parameters
 */
/**
 * Utility class for building JIRA API URLs
 */
export class JiraUrlBuilder {
  private readonly baseUrl: string;
  /**
   * Create a new URL builder with the base URL
   *
   * @param hostUrl - The JIRA host URL
   */
  constructor(hostUrl: string) {
    this.baseUrl = this.buildBaseUrl(hostUrl);
  }
  /**
   * Build a complete URL for an API endpoint
   *
   * @param endpoint - The API endpoint path
   * @param queryParams - Optional query parameters
   * @returns The complete URL
   */
  public buildUrl(
    endpoint: string,
    queryParams?: Record<string, string | number | boolean | undefined>,
  ): string {
    const url = this.buildEndpointUrl(endpoint);
    return this.appendQueryParams(url, queryParams);
  }
  /**
   * Get the base URL
   *
   * @returns The base URL
   */
  public getBaseUrl(): string {
    return this.baseUrl;
  }
  /**
   * Build the base URL from host URL
   *
   * @param hostUrl - The JIRA host URL
   * @returns The base URL with proper formatting
   */
  private buildBaseUrl(hostUrl: string): string {
    const normalizedHostUrl = this.normalizeHostUrl(hostUrl);
    return `${normalizedHostUrl}rest/api/3`;
  }
  /**
   * Normalize host URL to ensure proper trailing slash
   *
   * @param hostUrl - The host URL to normalize
   * @returns Normalized host URL with trailing slash
   */
  private normalizeHostUrl(hostUrl: string): string {
    return hostUrl.endsWith("/") ? hostUrl : `${hostUrl}/`;
  }
  /**
   * Build URL for a specific endpoint
   *
   * @param endpoint - The API endpoint
   * @returns URL with endpoint appended
   */
  private buildEndpointUrl(endpoint: string): string {
    const cleanEndpoint = this.normalizeEndpoint(endpoint);
    const cleanBaseUrl = this.normalizeBaseUrl();
    return `${cleanBaseUrl}/${cleanEndpoint}`;
  }
  /**
   * Normalize endpoint to remove leading slashes
   *
   * @param endpoint - The endpoint to normalize
   * @returns Normalized endpoint without leading slashes
   */
  private normalizeEndpoint(endpoint: string): string {
    return endpoint.replace(/^\/+/, "");
  }
  /**
   * Normalize base URL to remove trailing slash
   *
   * @returns Base URL without trailing slash
   */
  private normalizeBaseUrl(): string {
    return this.baseUrl.endsWith("/")
      ? this.baseUrl.slice(0, -1)
      : this.baseUrl;
  }
  /**
   * Append query parameters to URL
   *
   * @param url - The base URL
   * @param queryParams - Query parameters to append
   * @returns URL with query parameters
   */
  private appendQueryParams(
    url: string,
    queryParams?: Record<string, string | number | boolean | undefined>,
  ): string {
    if (!queryParams || Object.keys(queryParams).length === 0) {
      return url;
    }
    const params = this.buildQueryParams(queryParams);
    const paramString = params.toString();
    return paramString ? `${url}?${paramString}` : url;
  }
  /**
   * Build URLSearchParams from query parameters object
   *
   * @param queryParams - Query parameters object
   * @returns URLSearchParams instance
   */
  private buildQueryParams(
    queryParams: Record<string, string | number | boolean | undefined>,
  ): URLSearchParams {
    const params = new URLSearchParams();
    for (const [key, value] of Object.entries(queryParams)) {
      if (value !== undefined) {
        params.append(key, String(value));
      }
    }
    return params;
  }
}