{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * `build-url-ts` — a small, fast, zero-dependency library for composing URLs\n * from their parts (path, query string, and hash fragment).\n *\n * It runs anywhere JavaScript does (Node.js, Bun, Deno, edge runtimes, and\n * browsers) and ships both ESM and CommonJS builds with full type definitions.\n *\n * @packageDocumentation\n * @example\n * ```ts\n * import { buildUrl } from 'build-url-ts';\n *\n * buildUrl('https://api.example.com', {\n *   path: 'users/123',\n *   queryParams: { tab: 'profile', limit: 10 },\n *   hash: 'summary',\n * });\n * // → https://api.example.com/users/123?tab=profile&limit=10#summary\n * ```\n */\n\n/**\n * A value accepted for a single query parameter.\n *\n * - `string` / `number` / `boolean` are stringified as-is.\n * - `null` becomes an empty value (`key=`).\n * - `undefined` is omitted entirely.\n * - An array is rendered as a comma-separated list by default, or as repeated /\n *   indexed keys via {@link IBuildUrlOptions.disableCSV}.\n * - A `Date` is serialized with `Date.prototype.toString()`.\n * - Any other `object` is serialized with `JSON.stringify()`.\n */\nexport type QueryParamValue =\n  | null\n  | undefined\n  | string\n  | number\n  | boolean\n  | (string | number | boolean | null | undefined)[]\n  | Date\n  | object;\n\n/** A map of query parameter names to {@link QueryParamValue}s. */\nexport type IQueryParams = Record<string, QueryParamValue>;\n\n/**\n * How array query parameters are serialized when CSV joining is disabled.\n *\n * - `'array'` → `key[]=a&key[]=b`\n * - `'order_asc'` → `key[0]=a&key[1]=b`\n * - `'order_desc'` → `key[1]=a&key[0]=b`\n *\n * The boolean `true` (see {@link IBuildUrlOptions.disableCSV}) produces repeated\n * keys without brackets: `key=a&key=b`.\n */\nexport type IDisableCsvType = 'array' | 'order_asc' | 'order_desc';\n\n/** Options describing the parts of the URL to build. */\nexport interface IBuildUrlOptions {\n  /**\n   * A single path segment appended to the URL. Leading, trailing, and duplicate\n   * slashes are normalized.\n   *\n   * @example 'about/me' // → /about/me\n   */\n  path?: string | number;\n  /**\n   * Multiple path segments appended in order. Use this instead of (or in\n   * addition to) {@link IBuildUrlOptions.path}; when both are given, `path` is\n   * applied first, then each entry of `paths`.\n   *\n   * @example ['about', '/my/', '/cat'] // → /about/my/cat\n   */\n  paths?: (string | number)[];\n  /** Lowercase the generated path, query string, and hash. Defaults to `false`. */\n  lowerCase?: boolean;\n  /** Query parameters to append, merged on top of any already present on the URL. */\n  queryParams?: IQueryParams;\n  /**\n   * Control how array query parameters are rendered. `false`/omitted joins them\n   * into a comma-separated list; `true` repeats the key; a {@link IDisableCsvType}\n   * selects a bracketed format.\n   */\n  disableCSV?: boolean | IDisableCsvType;\n  /** Hash/fragment identifier to append (without the leading `#`). */\n  hash?: string | number;\n}\n\n/**\n * Encodes a string with `encodeURIComponent`, additionally escaping the\n * single quote (`'`) and backtick (`` ` ``) which `encodeURIComponent` leaves\n * untouched but which can be ambiguous inside a URL.\n */\nfunction customEncodeURIComponent(str: string): string {\n  return encodeURIComponent(str).replace(/'/g, '%27').replace(/`/g, '%60');\n}\n\n/**\n * Builds a query string (including the leading `?`) from a parameters object.\n *\n * @param queryParams - The parameters to serialize.\n * @param lowerCase - Lowercase keys and values. Defaults to `false`.\n * @param disableCSV - How to render array values. See {@link IDisableCsvType}.\n * @param useCustomEncoding - Use {@link customEncodeURIComponent} (escapes `'`\n *   and `` ` ``) instead of plain `encodeURIComponent`. Defaults to `true`.\n *   {@link buildUrl} passes `false` because it encodes values itself.\n * @returns The query string (e.g. `?foo=bar&bar=baz`), or `''` when empty.\n *\n * @example\n * ```ts\n * buildQueryString({ foo: 'bar', ids: [1, 2, 3] });\n * // → ?foo=bar&ids=1%2C2%2C3\n * ```\n */\nexport function buildQueryString(\n  queryParams: IQueryParams,\n  lowerCase?: boolean,\n  disableCSV?: boolean | IDisableCsvType,\n  useCustomEncoding: boolean = true\n): string {\n  const encode = (input: string): string =>\n    useCustomEncoding ? customEncodeURIComponent(input) : encodeURIComponent(input);\n  const queryParts: string[] = [];\n\n  for (const [key, value] of Object.entries(queryParams)) {\n    // `undefined` means \"omit this parameter entirely\".\n    if (value === undefined) continue;\n\n    const encodedKey = encode(lowerCase ? key.toLowerCase() : key);\n\n    if (!Array.isArray(value)) {\n      queryParts.push(`${encodedKey}=${encode(formatValue(value, lowerCase))}`);\n      continue;\n    }\n\n    // Drop `undefined` array items, then skip the parameter if nothing remains.\n    const items = value.filter((item) => item !== undefined);\n    if (items.length === 0) continue;\n\n    if (!disableCSV) {\n      // Default: join into a single comma-separated value.\n      const csvValue = items.map((item) => formatValue(item, lowerCase)).join(',');\n      queryParts.push(`${encodedKey}=${encode(csvValue)}`);\n      continue;\n    }\n\n    // Otherwise render one entry per item, in the requested key format.\n    let index = disableCSV === 'order_desc' ? items.length - 1 : 0;\n    for (const item of items) {\n      const encodedValue = encode(formatValue(item, lowerCase));\n      switch (disableCSV) {\n        case 'array':\n          queryParts.push(`${encodedKey}[]=${encodedValue}`);\n          break;\n        case 'order_asc':\n          queryParts.push(`${encodedKey}[${index++}]=${encodedValue}`);\n          break;\n        case 'order_desc':\n          queryParts.push(`${encodedKey}[${index--}]=${encodedValue}`);\n          break;\n        default:\n          queryParts.push(`${encodedKey}=${encodedValue}`);\n          break;\n      }\n    }\n  }\n\n  return queryParts.length > 0 ? `?${queryParts.join('&')}` : '';\n}\n\n/**\n * Converts a single query value into its string form, before URL encoding.\n * `null`/`undefined`/empty become `''`; `Date` and plain objects are\n * serialized; everything else is stringified and trimmed.\n */\nfunction formatValue(value: QueryParamValue, lowerCase?: boolean): string {\n  if (value === null || value === undefined) return '';\n  if (typeof value === 'boolean') return value.toString();\n  // Guard `0` before the falsy check below so it is not treated as empty.\n  if (value === 0) return '0';\n  if (typeof value === 'number' && Number.isNaN(value)) return 'NaN';\n  if (!value) return '';\n\n  const stringValue =\n    value instanceof Date\n      ? value.toString()\n      : typeof value === 'object' && !Array.isArray(value)\n        ? JSON.stringify(value)\n        : String(value).trim();\n\n  return lowerCase ? stringValue.toLowerCase() : stringValue;\n}\n\n/**\n * Appends a single path segment to a URL, normalizing slashes so there are no\n * empty or doubled segments while any meaningful trailing slash is preserved.\n *\n * @param path - The segment to append.\n * @param builtUrl - The URL built so far.\n * @param lowerCase - Lowercase the segment. Defaults to `false`.\n * @returns The URL with the segment appended.\n *\n * @example\n * ```ts\n * appendPath('users/123', 'https://api.example.com');\n * // → https://api.example.com/users/123\n * ```\n */\nexport function appendPath(path: string | number, builtUrl: string, lowerCase?: boolean): string {\n  const url = builtUrl ?? '';\n  const trimmedPath = String(path).trim();\n  const pathString = lowerCase ? trimmedPath.toLowerCase() : trimmedPath;\n\n  if (!pathString) return url;\n\n  // A lone '/' only ensures a single trailing slash.\n  if (pathString === '/') {\n    return url.endsWith('/') ? url : `${url}/`;\n  }\n\n  // Collapse repeated slashes within the segment while keeping a trailing one.\n  const hasTrailingSlash = pathString.endsWith('/');\n  const cleanedPath = pathString\n    .split('/')\n    .filter((segment) => segment.length > 0)\n    .join('/');\n  const finalPath = hasTrailingSlash && cleanedPath ? `${cleanedPath}/` : cleanedPath;\n\n  // Strip trailing slashes from the base before joining with a single '/'.\n  const baseUrl = url.replace(/\\/+$/, '');\n  return finalPath ? `${baseUrl}/${finalPath}` : baseUrl;\n}\n\n/**\n * Builds a hash fragment (including the leading `#`) from a value.\n *\n * @param hash - The fragment text (without `#`).\n * @param lowerCase - Lowercase the fragment. Defaults to `false`.\n * @returns The hash fragment (e.g. `#section`), or `''` when empty.\n *\n * @example\n * ```ts\n * buildHash('Section-1', true); // → #section-1\n * ```\n */\nexport function buildHash(hash: string | number, lowerCase?: boolean): string {\n  const trimmedHash = String(hash).trim();\n  if (!trimmedHash) return '';\n\n  const hashString = `#${trimmedHash}`;\n  return lowerCase ? hashString.toLowerCase() : hashString;\n}\n\n/**\n * Splits an existing URL into its base, query parameters, and hash so new\n * options can be merged on top of what is already present.\n */\nfunction parseUrl(url: string): { baseUrl: string; queryParams: IQueryParams; hash: string } {\n  const queryParams: IQueryParams = {};\n\n  // Split off the hash first; everything after the first '#' is the fragment.\n  const hashIndex = url.indexOf('#');\n  const hash = hashIndex === -1 ? '' : url.substring(hashIndex + 1);\n  const withoutHash = hashIndex === -1 ? url : url.substring(0, hashIndex);\n\n  // Then split off the query string at the first '?'.\n  const queryIndex = withoutHash.indexOf('?');\n  if (queryIndex === -1) {\n    return { baseUrl: withoutHash, queryParams, hash };\n  }\n\n  const baseUrl = withoutHash.substring(0, queryIndex);\n  const queryString = withoutHash.substring(queryIndex + 1);\n\n  for (const pair of queryString.split('&')) {\n    if (!pair) continue;\n    // Split on the first '=' only so values may themselves contain '='.\n    const eqIndex = pair.indexOf('=');\n    const rawKey = eqIndex === -1 ? pair : pair.substring(0, eqIndex);\n    const rawValue = eqIndex === -1 ? '' : pair.substring(eqIndex + 1);\n    if (rawKey) {\n      queryParams[decodeURIComponent(rawKey)] = rawValue ? decodeURIComponent(rawValue) : '';\n    }\n  }\n\n  return { baseUrl, queryParams, hash };\n}\n\n/**\n * Builds a complete URL from a base URL and/or a set of options.\n *\n * Query parameters and hash already present on the base URL are preserved and\n * merged with the supplied options (options take precedence on conflicts).\n *\n * @param url - The base URL, or — when called with a single argument — the\n *   options object itself. `null`/`undefined` builds a relative URL.\n * @param options - The parts to add. See {@link IBuildUrlOptions}.\n * @returns The constructed URL string.\n *\n * @example\n * ```ts\n * // Base URL plus options\n * buildUrl('https://example.com', { path: 'about', hash: 'team' });\n * // → https://example.com/about#team\n *\n * // Options only (relative URL)\n * buildUrl({ path: 'api/v2', queryParams: { format: 'json' } });\n * // → /api/v2?format=json\n *\n * // Multiple path segments\n * buildUrl('https://example.com', { paths: ['about', '/my/', '/cat'] });\n * // → https://example.com/about/my/cat\n * ```\n */\nfunction buildUrl(url?: string | null | IBuildUrlOptions, options?: IBuildUrlOptions): string {\n  // Resolve the overloaded first argument into a base URL + options, capturing\n  // any query/hash already present on a string URL so they can be merged.\n  const hasStringUrl = typeof url === 'string';\n  const parsed = hasStringUrl ? parseUrl(url) : null;\n  const buildOptions = url !== null && typeof url === 'object' ? url : options;\n\n  let result = parsed?.baseUrl ?? '';\n\n  // 1. Path — the single `path` (applied first, for backward compatibility),\n  //    then each segment of `paths`, in order.\n  const segments: (string | number)[] = [];\n  if (buildOptions?.path) segments.push(buildOptions.path);\n  if (buildOptions?.paths) segments.push(...buildOptions.paths);\n  for (const segment of segments) {\n    result = appendPath(segment, result, buildOptions?.lowerCase);\n  }\n\n  // 2. Query string — merge existing params with the supplied ones.\n  const allQueryParams = { ...parsed?.queryParams, ...buildOptions?.queryParams };\n  if (Object.keys(allQueryParams).length > 0) {\n    // Values are already decoded here, so skip the extra custom encoding pass.\n    result += buildQueryString(allQueryParams, buildOptions?.lowerCase, buildOptions?.disableCSV, false);\n  }\n\n  // 3. Hash — a supplied hash wins, otherwise keep the URL's existing one.\n  const finalHash = buildOptions?.hash !== undefined ? buildOptions.hash : (parsed?.hash ?? '');\n  if (finalHash) {\n    result += buildHash(finalHash, buildOptions?.lowerCase);\n  }\n\n  return result;\n}\n\nexport { buildUrl };\nexport default buildUrl;\n"],"names":[],"mappings":"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"}