{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["/** Options for the {@link stringify} function */\nexport interface StringifyOptions {\n  /** Separator the querystring should get */\n  separator?: string;\n  /** Equals sign the querystring should use */\n  equals?: string;\n  /** Whether the querystring should be automatically prefixed with a `?` */\n  includeQuestion?: boolean;\n  /**\n   * Whether to use [`encodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent)\n   * on the parameters\n   *\n   * @default true\n   */\n  encodeUriComponents?: boolean;\n}\n\n/** Options for the {@link parse} function */\nexport interface ParseOptions {\n  /** Separator the querystring has */\n  separator?: string;\n  /** Equals sign the querystring has */\n  equals?: string;\n}\n\n/**\n * Checks what kind of primitive type the property is and transforms accordingly\n *\n * @remarks\n * Used for stringify\n *\n * @param v Input to check for primitive type\n */\nexport function stringifyPrimitive<T extends unknown>(v: T, encode: boolean | undefined): string {\n  let primitive: string;\n\n  switch (typeof v) {\n    case 'string':\n      primitive = v;\n      break;\n    case 'boolean':\n      primitive = v ? 'true' : 'false';\n      break;\n    case 'number':\n      primitive = isFinite(v) ? v.toString() : '';\n      break;\n    default:\n      primitive = '';\n  }\n\n  return encode ? encodeURIComponent(primitive) : primitive;\n}\n\n/**\n * Stringifies an object\n *\n * @param obj Object to stringify\n * @param options Options for the stringify, see {@link StringifyOptions}\n * @returns The stringified query object\n * @example\n * ```ts\n * stringify({prop: 'value', prop2: 'value2'})\n * ```\n *\n * @example\n * ```ts\n * stringify({prop: 'value', prop2: 'value2'}, {separator: '&', equals: '=', includeQuestion: false})\n * ```\n *\n * @example\n * ```ts\n * stringify({prop: 'value', prop2: 'value2'}, {separator: '&&', equals: '=', includeQuestion: true})\n * ```\n */\nexport function stringify<I>(\n  obj: I,\n  options: StringifyOptions = { separator: '&', equals: '=', includeQuestion: false, encodeUriComponents: true }\n): string {\n  try {\n    if (!obj || Object.keys(obj).length <= 0) throw new Error('object_is_empty');\n    if (typeof obj !== 'object') throw new Error('input_not_object');\n    if (!Reflect.has(options, 'separator')) options.separator = '&';\n    if (!Reflect.has(options, 'equals')) options.equals = '=';\n    if (!Reflect.has(options, 'includeQuestion')) options.includeQuestion = false;\n    if (!Reflect.has(options, 'encodeUriComponents')) options.encodeUriComponents = true;\n\n    const combinedValues: string[] = [];\n    for (const [key, value] of Object.entries(obj)) {\n      const ks = stringifyPrimitive(key, options.encodeUriComponents) + options.equals!;\n      if (Array.isArray(value)) {\n        const combinedInnerValues: string[] = [];\n        for (const innerValue of value) {\n          combinedInnerValues.push(ks + stringifyPrimitive(innerValue, options.encodeUriComponents));\n        }\n        combinedValues.push(combinedInnerValues.join(options.separator));\n      } else {\n        combinedValues.push(ks + stringifyPrimitive(value, options.encodeUriComponents));\n      }\n    }\n\n    if (options.includeQuestion) combinedValues[0] = `?${combinedValues[0]}`;\n\n    return combinedValues.join(options.separator);\n  } catch (err) {\n    if (/object_is_empty/i.test((err as Error).message)) {\n      return `${options.includeQuestion ? '?' : ''}${encodeURIComponent(stringifyPrimitive(obj, options.encodeUriComponents))}`;\n    }\n    if (/input_not_object/i.test((err as Error).message)) {\n      throw '@Favware/Querystring: Your input was not an object. Please supply an object when using Stringify.';\n    }\n\n    throw err;\n  }\n}\n\n/**\n * Parses a querystring back to an object\n *\n * @param qs Querystring to parse\n * @param options Options for the parse, see {@link IParseOptions}\n * @returns A JavaScript object of the parsed parameters\n * @example\n * ```ts\n * parse('?prop=value&prop2=value2')\n * ```\n *\n * @example\n * ```ts\n * parse('?prop=value&prop2=value2', {separator: '&', equals: '='})\n * ```\n *\n * @example\n * ```ts\n * parse('prop=value&&prop2=value2', {separator: '&&', equals: '='})\n * ```\n */\nexport function parse<R extends Record<PropertyKey, unknown> = Record<PropertyKey, unknown>>(\n  qs = '',\n  options: ParseOptions = { separator: '&', equals: '=' }\n): R {\n  try {\n    if (typeof qs !== 'string') throw new Error('input_not_string');\n    if (qs === '') return {} as R;\n    // eslint-disable-next-line prefer-destructuring\n    if (/^https?:\\/\\//.test(qs)) qs = qs.split('?')[1];\n    if (!options.separator) options.separator = '&';\n    if (!options.equals) options.equals = '=';\n    if (qs.startsWith('?')) qs = qs.slice(1);\n\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const obj = {} as any;\n    const regexp = /\\+/g;\n    const queries: string[] = qs.split(options.separator);\n\n    for (const query of queries) {\n      const x = query.replace(regexp, '%20');\n      const idx = x.indexOf(options.equals);\n      let keyStr;\n      let valueStr;\n\n      if (idx >= 0) {\n        keyStr = x.substr(0, idx);\n        valueStr = x.substr(idx + 1);\n      } else {\n        keyStr = x;\n        valueStr = '';\n      }\n\n      const k = decodeURIComponent(keyStr);\n      const v = decodeURIComponent(valueStr);\n\n      if (!Reflect.has(obj, k)) {\n        obj[k] = v;\n      } else if (Array.isArray(obj[k])) {\n        obj[k].push(v);\n      } else {\n        (obj as Record<PropertyKey, unknown>)[k] = [obj[k], v];\n      }\n    }\n\n    return obj as R;\n  } catch (err) {\n    if (/input_not_string/i.test((err as Error).message)) {\n      throw '@Favware/Querystring: Your input was not an string. Please supply a string when using Parse.';\n    }\n\n    throw err;\n  }\n}\n"],"names":["stringifyPrimitive","v","encode","primitive","isFinite","toString","encodeURIComponent","stringify","obj","options","separator","equals","includeQuestion","encodeUriComponents","Object","keys","length","Error","Reflect","has","combinedValues","key","value","entries","ks","Array","isArray","combinedInnerValues","innerValue","push","join","err","test","message","parse","qs","split","startsWith","slice","regexp","queries","query","x","replace","idx","indexOf","keyStr","valueStr","substr","k","decodeURIComponent"],"mappings":"SAiCgBA,mBAAsCC,EAAMC,GAC1D,IAAIC,EAEJ,cAAeF,GACb,IAAK,SACHE,EAAYF,EACZ,MACF,IAAK,UACHE,EAAYF,EAAI,OAAS,QACzB,MACF,IAAK,SACHE,EAAYC,SAASH,GAAKA,EAAEI,WAAa,GACzC,MACF,QACEF,EAAY,GAGhB,OAAOD,EAASI,mBAAmBH,GAAaA,WAwBlCI,UACdC,EACAC,EAA4B,CAAEC,UAAW,IAAKC,OAAQ,IAAKC,iBAAiB,EAAOC,qBAAqB,IAExG,IACE,IAAKL,GAAOM,OAAOC,KAAKP,GAAKQ,QAAU,EAAG,MAAM,IAAIC,MAAM,mBAC1D,GAAmB,iBAART,EAAkB,MAAM,IAAIS,MAAM,oBACxCC,QAAQC,IAAIV,EAAS,eAAcA,EAAQC,UAAY,KACvDQ,QAAQC,IAAIV,EAAS,YAAWA,EAAQE,OAAS,KACjDO,QAAQC,IAAIV,EAAS,qBAAoBA,EAAQG,iBAAkB,GACnEM,QAAQC,IAAIV,EAAS,yBAAwBA,EAAQI,qBAAsB,GAEhF,MAAMO,EAA2B,GACjC,IAAK,MAAOC,EAAKC,KAAUR,OAAOS,QAAQf,GAAM,CAC9C,MAAMgB,EAAKxB,mBAAmBqB,EAAKZ,EAAQI,qBAAuBJ,EAAQE,OAC1E,GAAIc,MAAMC,QAAQJ,GAAQ,CACxB,MAAMK,EAAgC,GACtC,IAAK,MAAMC,KAAcN,EACvBK,EAAoBE,KAAKL,EAAKxB,mBAAmB4B,EAAYnB,EAAQI,sBAEvEO,EAAeS,KAAKF,EAAoBG,KAAKrB,EAAQC,iBAErDU,EAAeS,KAAKL,EAAKxB,mBAAmBsB,EAAOb,EAAQI,sBAM/D,OAFIJ,EAAQG,kBAAiBQ,EAAe,GAAK,IAAIA,EAAe,MAE7DA,EAAeU,KAAKrB,EAAQC,WACnC,MAAOqB,GACP,GAAI,mBAAmBC,KAAMD,EAAcE,SACzC,MAAO,GAAGxB,EAAQG,gBAAkB,IAAM,KAAKN,mBAAmBN,mBAAmBQ,EAAKC,EAAQI,wBAEpG,GAAI,oBAAoBmB,KAAMD,EAAcE,SAC1C,KAAM,oGAGR,MAAMF,YAyBMG,MACdC,EAAK,GACL1B,EAAwB,CAAEC,UAAW,IAAKC,OAAQ,MAElD,IACE,GAAkB,iBAAPwB,EAAiB,MAAM,IAAIlB,MAAM,oBAC5C,GAAW,KAAPkB,EAAW,MAAO,GAElB,eAAeH,KAAKG,KAAKA,EAAKA,EAAGC,MAAM,KAAK,IAC3C3B,EAAQC,YAAWD,EAAQC,UAAY,KACvCD,EAAQE,SAAQF,EAAQE,OAAS,KAClCwB,EAAGE,WAAW,OAAMF,EAAKA,EAAGG,MAAM,IAGtC,MAAM9B,EAAM,GACN+B,EAAS,MACTC,EAAoBL,EAAGC,MAAM3B,EAAQC,WAE3C,IAAK,MAAM+B,KAASD,EAAS,CAC3B,MAAME,EAAID,EAAME,QAAQJ,EAAQ,OAC1BK,EAAMF,EAAEG,QAAQpC,EAAQE,QAC9B,IAAImC,EACAC,EAEAH,GAAO,GACTE,EAASJ,EAAEM,OAAO,EAAGJ,GACrBG,EAAWL,EAAEM,OAAOJ,EAAM,KAE1BE,EAASJ,EACTK,EAAW,IAGb,MAAME,EAAIC,mBAAmBJ,GACvB7C,EAAIiD,mBAAmBH,GAExB7B,QAAQC,IAAIX,EAAKyC,GAEXxB,MAAMC,QAAQlB,EAAIyC,IAC3BzC,EAAIyC,GAAGpB,KAAK5B,GAEXO,EAAqCyC,GAAK,CAACzC,EAAIyC,GAAIhD,GAJpDO,EAAIyC,GAAKhD,EAQb,OAAOO,EACP,MAAOuB,GACP,GAAI,oBAAoBC,KAAMD,EAAcE,SAC1C,KAAM,+FAGR,MAAMF"}