@ambitiondev/dynamic-url 0.0.3 → 0.0.5-0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/src/url.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { TParamsObject } from "../types";
1
+ import type { TParamsObject, IStringifyQueryOptions } from "../types";
2
2
  export declare class DynamicURL {
3
3
  private url;
4
4
  constructor(url: string);
@@ -6,6 +6,12 @@ export declare class DynamicURL {
6
6
  * Takes a query object and appends it to the URL as a query string.
7
7
  *
8
8
  * @param query - An object representing the query parameters.
9
+ * @param options - Options for stringifying the query parameters.
10
+ * @param options.prefix - Prefix for the query parameters (default: "").
11
+ * @param options.maxDepth - Maximum depth for nested objects (default: 5).
12
+ * @param options.separator - Separator for the query parameters (default: "&").
13
+ * @param options.skipNulls - Whether to skip null or undefined values (default: true).
14
+ * @see {@link IStringifyQueryOptions}
9
15
  * @returns {DynamicURL}
10
16
  *
11
17
  * @example
@@ -15,7 +21,7 @@ export declare class DynamicURL {
15
21
  * console.log(url.resolve()); // "https://example.com?citizen=robespierre&hero=ironman"
16
22
  * ```
17
23
  */
18
- setQueryParams(query: Record<string, any>): this;
24
+ setQueryParams(query: Record<string, any>, options?: IStringifyQueryOptions): this;
19
25
  /**
20
26
  * Replaces route parameters in the URL with the provided values.
21
27
  *
@@ -1 +1 @@
1
- {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/url.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAS;gBAER,GAAG,EAAE,MAAM;IAIvB;;;;;;;;;;;;OAYG;IAEH,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAazC;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,YAAY,EAAE,aAAa,GAAG,MAAM;IAiBnD;;;;;;;;;;;;;OAaG;IACH,OAAO;CAGR"}
1
+ {"version":3,"file":"url.d.ts","sourceRoot":"","sources":["../../src/url.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAoEtE,qBAAa,UAAU;IACrB,OAAO,CAAC,GAAG,CAAS;gBAER,GAAG,EAAE,MAAM;IAIvB;;;;;;;;;;;;;;;;;;OAkBG;IAEH,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,sBAAsB;IAU3E;;;;;;;;;;;;;;OAcG;IACH,cAAc,CAAC,YAAY,EAAE,aAAa,GAAG,MAAM;IAiBnD;;;;;;;;;;;;;OAaG;IACH,OAAO;CAGR"}
package/dist/src/url.js CHANGED
@@ -1,5 +1,50 @@
1
- // Vendor
2
- import qs from "qs";
1
+ // Defaults
2
+ const MAX_DEPTH_DEFAULT = 5;
3
+ const SEPARATOR_DEFAULT = "&";
4
+ const PREFIX_DEFAULT = "";
5
+ const SKIP_NULLS_DEFAULT = true;
6
+ function stringify(
7
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
8
+ obj, options) {
9
+ const { maxDepth = MAX_DEPTH_DEFAULT, prefix = PREFIX_DEFAULT, separator = SEPARATOR_DEFAULT, skipNulls = SKIP_NULLS_DEFAULT, } = options || {};
10
+ const stringifyRecursive = (
11
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
12
+ obj, prefix, depth = 1) => {
13
+ const result = Object.entries(obj).reduce((queryString, [key, value]) => {
14
+ // Handle skipNulls option
15
+ if (skipNulls && (value === null || value === undefined)) {
16
+ return queryString;
17
+ }
18
+ // Build the unencoded key path first
19
+ const keyPath = prefix ? `${prefix}[${key}]` : key;
20
+ // Check if value is an object and we haven't exceeded max depth
21
+ if (typeof value === "object" && value !== null && depth < maxDepth) {
22
+ // Pass unencoded keyPath as prefix to prevent double encoding in recursive calls
23
+ const nestedQuery = stringifyRecursive(value, keyPath, depth + 1);
24
+ // Only append if nestedQuery has content
25
+ if (!nestedQuery) {
26
+ return queryString;
27
+ }
28
+ return queryString
29
+ ? `${queryString}${separator}${nestedQuery}`
30
+ : nestedQuery;
31
+ }
32
+ else {
33
+ // Encode only once at the leaf level
34
+ const encodedKey = encodeURIComponent(keyPath);
35
+ const encodedValue = typeof value === "object" && value !== null
36
+ ? ""
37
+ : encodeURIComponent(value);
38
+ const keyValueString = `${encodedKey}=${encodedValue}`;
39
+ return queryString
40
+ ? `${queryString}${separator}${keyValueString}`
41
+ : keyValueString;
42
+ }
43
+ }, "");
44
+ return result;
45
+ };
46
+ return stringifyRecursive(obj, prefix);
47
+ }
3
48
  export class DynamicURL {
4
49
  constructor(url) {
5
50
  this.url = url;
@@ -8,6 +53,12 @@ export class DynamicURL {
8
53
  * Takes a query object and appends it to the URL as a query string.
9
54
  *
10
55
  * @param query - An object representing the query parameters.
56
+ * @param options - Options for stringifying the query parameters.
57
+ * @param options.prefix - Prefix for the query parameters (default: "").
58
+ * @param options.maxDepth - Maximum depth for nested objects (default: 5).
59
+ * @param options.separator - Separator for the query parameters (default: "&").
60
+ * @param options.skipNulls - Whether to skip null or undefined values (default: true).
61
+ * @see {@link IStringifyQueryOptions}
11
62
  * @returns {DynamicURL}
12
63
  *
13
64
  * @example
@@ -18,11 +69,8 @@ export class DynamicURL {
18
69
  * ```
19
70
  */
20
71
  /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
21
- setQueryParams(query) {
22
- const queryString = qs.stringify(query, {
23
- skipNulls: true,
24
- encode: true,
25
- });
72
+ setQueryParams(query, options) {
73
+ const queryString = stringify(query, options);
26
74
  if (queryString) {
27
75
  this.url = `${this.url}?${queryString}`;
28
76
  }
@@ -1,2 +1,24 @@
1
1
  export type TParamsObject = Record<string, string | number | boolean>;
2
+ export interface IStringifyQueryOptions {
3
+ /**
4
+ * Prefix for the query parameters.
5
+ * @default ""
6
+ */
7
+ prefix?: string;
8
+ /**
9
+ * Separator for the query parameters.
10
+ * @default "&"
11
+ */
12
+ separator?: string;
13
+ /**
14
+ * Whether to skip null or undefined values.
15
+ * @default true
16
+ */
17
+ skipNulls?: boolean;
18
+ /**
19
+ * Maximum depth for nested objects.
20
+ * @default 5
21
+ */
22
+ maxDepth?: number;
23
+ }
2
24
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../types/index.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;AAEtE,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ambitiondev/dynamic-url",
3
3
  "description": "lightweight util for creating dynamic endpoint strings",
4
- "version": "0.0.3",
4
+ "version": "0.0.5-0",
5
5
  "main": "./dist/src/url.js",
6
6
  "types": "./dist/src/url.d.ts",
7
7
  "repository": "https://github.com/ambitiondev/dynamic-url",
@@ -31,9 +31,6 @@
31
31
  "typescript-eslint": "^8.53.0",
32
32
  "vitest": "^4.0.17"
33
33
  },
34
- "dependencies": {
35
- "qs": "^6.14.1"
36
- },
37
34
  "scripts": {
38
35
  "--- 🎣 Hooks ---": "",
39
36
  "prepare": "husky",