@hyeonqyu/typed-router-core 1.4.1 → 1.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/index.d.mts CHANGED
@@ -1,13 +1,12 @@
1
- import { P as Paths, a as PathValue } from './routes.types-BOeBykBW.mjs';
2
- export { A as AnyZodSchema, B as BaseMetadata, E as ExtractSearchParams, G as GetRouteNode, c as PartialRouteTree, f as ResolvedRouteTree, R as RouteNode, b as RouteNodeMetadata, e as RoutePathname, d as RouteTree, g as SearchParamsForPath, S as SimplifyPathname } from './routes.types-BOeBykBW.mjs';
3
-
4
- type SearchParamsValue = string | number | boolean | readonly (string | number | boolean)[];
5
- type SearchParams = Record<string, SearchParamsValue>;
1
+ import { P as Paths, a as PathValue, S as SearchParams } from './routes.types-C0cWyXOZ.mjs';
2
+ export { A as AnyZodSchema, B as BaseMetadata, E as ExtractSearchParams, G as GetRouteNode, d as PartialRouteTree, h as ResolvedRouteTree, R as RouteNode, c as RouteNodeMetadata, f as RoutePathname, e as RouteTree, i as SearchParamsForPath, b as SearchParamsValue, g as SimplifyPathname } from './routes.types-C0cWyXOZ.mjs';
6
3
 
7
4
  declare const getSafely: <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(splitter: TSplitter, obj: TObject, path: TPath) => PathValue<TObject, TPath, TSplitter>;
8
5
  type SearchParamsStringOptions = {
9
6
  includeQuestionMark?: boolean;
10
7
  };
11
8
  declare const toSearchParamsString: (searchParams: SearchParams, options?: SearchParamsStringOptions) => string;
9
+ declare const findObjectPath: <T>(root: Record<string, unknown>, target: T, splitter?: string, path?: string) => string | undefined;
10
+ declare const replaceDynamicSegments: (pathname: string, params?: SearchParams) => string;
12
11
 
13
- export { PathValue, Paths, type SearchParams, type SearchParamsStringOptions, type SearchParamsValue, getSafely, toSearchParamsString };
12
+ export { PathValue, Paths, SearchParams, type SearchParamsStringOptions, findObjectPath, getSafely, replaceDynamicSegments, toSearchParamsString };
package/dist/index.d.ts CHANGED
@@ -1,13 +1,12 @@
1
- import { P as Paths, a as PathValue } from './routes.types-BOeBykBW.js';
2
- export { A as AnyZodSchema, B as BaseMetadata, E as ExtractSearchParams, G as GetRouteNode, c as PartialRouteTree, f as ResolvedRouteTree, R as RouteNode, b as RouteNodeMetadata, e as RoutePathname, d as RouteTree, g as SearchParamsForPath, S as SimplifyPathname } from './routes.types-BOeBykBW.js';
3
-
4
- type SearchParamsValue = string | number | boolean | readonly (string | number | boolean)[];
5
- type SearchParams = Record<string, SearchParamsValue>;
1
+ import { P as Paths, a as PathValue, S as SearchParams } from './routes.types-C0cWyXOZ.js';
2
+ export { A as AnyZodSchema, B as BaseMetadata, E as ExtractSearchParams, G as GetRouteNode, d as PartialRouteTree, h as ResolvedRouteTree, R as RouteNode, c as RouteNodeMetadata, f as RoutePathname, e as RouteTree, i as SearchParamsForPath, b as SearchParamsValue, g as SimplifyPathname } from './routes.types-C0cWyXOZ.js';
6
3
 
7
4
  declare const getSafely: <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(splitter: TSplitter, obj: TObject, path: TPath) => PathValue<TObject, TPath, TSplitter>;
8
5
  type SearchParamsStringOptions = {
9
6
  includeQuestionMark?: boolean;
10
7
  };
11
8
  declare const toSearchParamsString: (searchParams: SearchParams, options?: SearchParamsStringOptions) => string;
9
+ declare const findObjectPath: <T>(root: Record<string, unknown>, target: T, splitter?: string, path?: string) => string | undefined;
10
+ declare const replaceDynamicSegments: (pathname: string, params?: SearchParams) => string;
12
11
 
13
- export { PathValue, Paths, type SearchParams, type SearchParamsStringOptions, type SearchParamsValue, getSafely, toSearchParamsString };
12
+ export { PathValue, Paths, SearchParams, type SearchParamsStringOptions, findObjectPath, getSafely, replaceDynamicSegments, toSearchParamsString };
package/dist/index.js CHANGED
@@ -40,8 +40,32 @@ var toSearchParamsString = /* @__PURE__ */ __name((searchParams, options = { inc
40
40
  const searchParamsString = params.join("&");
41
41
  return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;
42
42
  }, "toSearchParamsString");
43
+ var findObjectPath = /* @__PURE__ */ __name((root, target, splitter = "/", path = splitter) => {
44
+ for (const key in root) {
45
+ if (key === "_metadata") {
46
+ continue;
47
+ }
48
+ const current = root[key];
49
+ if (current === target) return path + key;
50
+ if (typeof current === "object" && current !== null) {
51
+ const result = findObjectPath(current, target, splitter, path + key + splitter);
52
+ if (result) return result;
53
+ }
54
+ }
55
+ return void 0;
56
+ }, "findObjectPath");
57
+ var replaceDynamicSegments = /* @__PURE__ */ __name((pathname, params) => {
58
+ if (!params) return pathname;
59
+ return pathname.replace(/\[([^\]]+)\]/g, (_, key) => {
60
+ const value = params[key.toString()];
61
+ if (value === void 0 || value === null) return `[${key}]`;
62
+ return Array.isArray(value) ? value.join(",") : value.toString();
63
+ });
64
+ }, "replaceDynamicSegments");
43
65
 
66
+ exports.findObjectPath = findObjectPath;
44
67
  exports.getSafely = getSafely;
68
+ exports.replaceDynamicSegments = replaceDynamicSegments;
45
69
  exports.toSearchParamsString = toSearchParamsString;
46
70
  //# sourceMappingURL=index.js.map
47
71
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/object.utils.ts"],"names":[],"mappings":";;;;;;AAGO,IAAM,SAAA,mBAAY,MAAA,CAAA,CACvB,QAAA,EACA,GAAA,EACA,IAAA,KACyC;AACzC,EAAA,IAAI,IAAA,KAAS,EAAA,IAAM,IAAA,KAAS,QAAA,EAAU,OAAO,GAAA;AAE7C,EAAA,MAAM,IAAA,GAAQ,KAAgB,KAAA,CAAM,QAAQ,EAAE,MAAA,CAAO,CAAC,QAAQ,GAAG,CAAA;AACjE,EAAA,IAAI,KAAA,GAAiB,GAAA;AAErB,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,EAAO;AAC/D,MAAA,KAAA,GAAS,MAAkC,GAAG,CAAA;AAAA,IAChD,CAAA,MAAO;AACL,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT,CAAA,EAnByB,WAAA;AAyBlB,IAAM,uCAAuB,MAAA,CAAA,CAClC,YAAA,EACA,UAAqC,EAAE,mBAAA,EAAqB,MAAK,KACtD;AACX,EAAA,MAAM,SAAmB,EAAC;AAE1B,EAAA,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM;AACrD,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM;AACzC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,mBAAmB,GAAG,CAAA;AAEzC,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,MAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,IAAA,KAAS;AACtB,QAAA,IAAI,IAAA,KAAS,MAAA,IAAa,IAAA,KAAS,IAAA,EAAM;AACvC,UAAA,MAAA,CAAO,IAAA,CAAK,GAAG,UAAU,CAAA,CAAA,EAAI,mBAAmB,MAAA,CAAO,IAAI,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,QACjE;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,GAAG,UAAU,CAAA,CAAA,EAAI,mBAAmB,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,IAClE;AAAA,EACF,CAAC,CAAA;AAED,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,kBAAA,GAAqB,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA;AAC1C,EAAA,OAAO,OAAA,CAAQ,mBAAA,GAAsB,CAAA,CAAA,EAAI,kBAAkB,CAAA,CAAA,GAAK,kBAAA;AAClE,CAAA,EA9BoC,sBAAA","file":"index.js","sourcesContent":["import { Paths, PathValue } from './path.types';\nimport { SearchParams } from './query.types';\n\nexport const getSafely = <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(\n splitter: TSplitter,\n obj: TObject,\n path: TPath,\n): PathValue<TObject, TPath, TSplitter> => {\n if (path === '' || path === splitter) return obj as PathValue<TObject, TPath, TSplitter>;\n\n const keys = (path as string).split(splitter).filter((key) => key);\n let value: unknown = obj;\n\n for (const key of keys) {\n if (typeof value === 'object' && value !== null && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined as PathValue<TObject, TPath, TSplitter>;\n }\n }\n\n return value as PathValue<TObject, TPath, TSplitter>;\n};\n\nexport type SearchParamsStringOptions = {\n includeQuestionMark?: boolean;\n};\n\nexport const toSearchParamsString = (\n searchParams: SearchParams,\n options: SearchParamsStringOptions = { includeQuestionMark: true },\n): string => {\n const params: string[] = [];\n\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n value.forEach((item) => {\n if (item !== undefined && item !== null) {\n params.push(`${encodedKey}=${encodeURIComponent(String(item))}`);\n }\n });\n } else {\n params.push(`${encodedKey}=${encodeURIComponent(String(value))}`);\n }\n });\n\n if (params.length === 0) {\n return '';\n }\n\n const searchParamsString = params.join('&');\n return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;\n};\n"]}
1
+ {"version":3,"sources":["../src/object.utils.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { Paths, PathValue } from './path.types';\nimport { SearchParams } from './query.types';\n\nexport const getSafely = <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(\n splitter: TSplitter,\n obj: TObject,\n path: TPath,\n): PathValue<TObject, TPath, TSplitter> => {\n if (path === '' || path === splitter) return obj as PathValue<TObject, TPath, TSplitter>;\n\n const keys = (path as string).split(splitter).filter((key) => key);\n let value: unknown = obj;\n\n for (const key of keys) {\n if (typeof value === 'object' && value !== null && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined as PathValue<TObject, TPath, TSplitter>;\n }\n }\n\n return value as PathValue<TObject, TPath, TSplitter>;\n};\n\nexport type SearchParamsStringOptions = {\n includeQuestionMark?: boolean;\n};\n\nexport const toSearchParamsString = (\n searchParams: SearchParams,\n options: SearchParamsStringOptions = { includeQuestionMark: true },\n): string => {\n const params: string[] = [];\n\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n value.forEach((item) => {\n if (item !== undefined && item !== null) {\n params.push(`${encodedKey}=${encodeURIComponent(String(item))}`);\n }\n });\n } else {\n params.push(`${encodedKey}=${encodeURIComponent(String(value))}`);\n }\n });\n\n if (params.length === 0) {\n return '';\n }\n\n const searchParamsString = params.join('&');\n return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;\n};\n\nexport const findObjectPath = <T>(\n root: Record<string, unknown>,\n target: T,\n splitter = '/',\n path = splitter,\n): string | undefined => {\n for (const key in root) {\n // Skip _metadata keys during traversal\n if (key === '_metadata') {\n continue;\n }\n\n const current = root[key];\n\n if (current === target) return path + key;\n\n if (typeof current === 'object' && current !== null) {\n const result = findObjectPath(current as Record<string, unknown>, target, splitter, path + key + splitter);\n if (result) return result;\n }\n }\n\n return undefined;\n};\n\nexport const replaceDynamicSegments = (\n pathname: string,\n params?: SearchParams,\n): string => {\n if (!params) return pathname;\n\n return pathname.replace(/\\[([^\\]]+)\\]/g, (_, key) => {\n const value = params[key.toString()];\n if (value === undefined || value === null) return `[${key}]`;\n return Array.isArray(value) ? value.join(',') : value.toString();\n });\n};\n"]}
package/dist/index.mjs CHANGED
@@ -38,7 +38,29 @@ var toSearchParamsString = /* @__PURE__ */ __name((searchParams, options = { inc
38
38
  const searchParamsString = params.join("&");
39
39
  return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;
40
40
  }, "toSearchParamsString");
41
+ var findObjectPath = /* @__PURE__ */ __name((root, target, splitter = "/", path = splitter) => {
42
+ for (const key in root) {
43
+ if (key === "_metadata") {
44
+ continue;
45
+ }
46
+ const current = root[key];
47
+ if (current === target) return path + key;
48
+ if (typeof current === "object" && current !== null) {
49
+ const result = findObjectPath(current, target, splitter, path + key + splitter);
50
+ if (result) return result;
51
+ }
52
+ }
53
+ return void 0;
54
+ }, "findObjectPath");
55
+ var replaceDynamicSegments = /* @__PURE__ */ __name((pathname, params) => {
56
+ if (!params) return pathname;
57
+ return pathname.replace(/\[([^\]]+)\]/g, (_, key) => {
58
+ const value = params[key.toString()];
59
+ if (value === void 0 || value === null) return `[${key}]`;
60
+ return Array.isArray(value) ? value.join(",") : value.toString();
61
+ });
62
+ }, "replaceDynamicSegments");
41
63
 
42
- export { getSafely, toSearchParamsString };
64
+ export { findObjectPath, getSafely, replaceDynamicSegments, toSearchParamsString };
43
65
  //# sourceMappingURL=index.mjs.map
44
66
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/object.utils.ts"],"names":[],"mappings":";;;;AAGO,IAAM,SAAA,mBAAY,MAAA,CAAA,CACvB,QAAA,EACA,GAAA,EACA,IAAA,KACyC;AACzC,EAAA,IAAI,IAAA,KAAS,EAAA,IAAM,IAAA,KAAS,QAAA,EAAU,OAAO,GAAA;AAE7C,EAAA,MAAM,IAAA,GAAQ,KAAgB,KAAA,CAAM,QAAQ,EAAE,MAAA,CAAO,CAAC,QAAQ,GAAG,CAAA;AACjE,EAAA,IAAI,KAAA,GAAiB,GAAA;AAErB,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,EAAO;AAC/D,MAAA,KAAA,GAAS,MAAkC,GAAG,CAAA;AAAA,IAChD,CAAA,MAAO;AACL,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT,CAAA,EAnByB,WAAA;AAyBlB,IAAM,uCAAuB,MAAA,CAAA,CAClC,YAAA,EACA,UAAqC,EAAE,mBAAA,EAAqB,MAAK,KACtD;AACX,EAAA,MAAM,SAAmB,EAAC;AAE1B,EAAA,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM;AACrD,IAAA,IAAI,KAAA,KAAU,MAAA,IAAa,KAAA,KAAU,IAAA,EAAM;AACzC,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,UAAA,GAAa,mBAAmB,GAAG,CAAA;AAEzC,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,MAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,IAAA,KAAS;AACtB,QAAA,IAAI,IAAA,KAAS,MAAA,IAAa,IAAA,KAAS,IAAA,EAAM;AACvC,UAAA,MAAA,CAAO,IAAA,CAAK,GAAG,UAAU,CAAA,CAAA,EAAI,mBAAmB,MAAA,CAAO,IAAI,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,QACjE;AAAA,MACF,CAAC,CAAA;AAAA,IACH,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,GAAG,UAAU,CAAA,CAAA,EAAI,mBAAmB,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA,CAAE,CAAA;AAAA,IAClE;AAAA,EACF,CAAC,CAAA;AAED,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,OAAO,EAAA;AAAA,EACT;AAEA,EAAA,MAAM,kBAAA,GAAqB,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA;AAC1C,EAAA,OAAO,OAAA,CAAQ,mBAAA,GAAsB,CAAA,CAAA,EAAI,kBAAkB,CAAA,CAAA,GAAK,kBAAA;AAClE,CAAA,EA9BoC,sBAAA","file":"index.mjs","sourcesContent":["import { Paths, PathValue } from './path.types';\nimport { SearchParams } from './query.types';\n\nexport const getSafely = <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(\n splitter: TSplitter,\n obj: TObject,\n path: TPath,\n): PathValue<TObject, TPath, TSplitter> => {\n if (path === '' || path === splitter) return obj as PathValue<TObject, TPath, TSplitter>;\n\n const keys = (path as string).split(splitter).filter((key) => key);\n let value: unknown = obj;\n\n for (const key of keys) {\n if (typeof value === 'object' && value !== null && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined as PathValue<TObject, TPath, TSplitter>;\n }\n }\n\n return value as PathValue<TObject, TPath, TSplitter>;\n};\n\nexport type SearchParamsStringOptions = {\n includeQuestionMark?: boolean;\n};\n\nexport const toSearchParamsString = (\n searchParams: SearchParams,\n options: SearchParamsStringOptions = { includeQuestionMark: true },\n): string => {\n const params: string[] = [];\n\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n value.forEach((item) => {\n if (item !== undefined && item !== null) {\n params.push(`${encodedKey}=${encodeURIComponent(String(item))}`);\n }\n });\n } else {\n params.push(`${encodedKey}=${encodeURIComponent(String(value))}`);\n }\n });\n\n if (params.length === 0) {\n return '';\n }\n\n const searchParamsString = params.join('&');\n return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;\n};\n"]}
1
+ {"version":3,"sources":["../src/object.utils.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["import { Paths, PathValue } from './path.types';\nimport { SearchParams } from './query.types';\n\nexport const getSafely = <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(\n splitter: TSplitter,\n obj: TObject,\n path: TPath,\n): PathValue<TObject, TPath, TSplitter> => {\n if (path === '' || path === splitter) return obj as PathValue<TObject, TPath, TSplitter>;\n\n const keys = (path as string).split(splitter).filter((key) => key);\n let value: unknown = obj;\n\n for (const key of keys) {\n if (typeof value === 'object' && value !== null && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined as PathValue<TObject, TPath, TSplitter>;\n }\n }\n\n return value as PathValue<TObject, TPath, TSplitter>;\n};\n\nexport type SearchParamsStringOptions = {\n includeQuestionMark?: boolean;\n};\n\nexport const toSearchParamsString = (\n searchParams: SearchParams,\n options: SearchParamsStringOptions = { includeQuestionMark: true },\n): string => {\n const params: string[] = [];\n\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n value.forEach((item) => {\n if (item !== undefined && item !== null) {\n params.push(`${encodedKey}=${encodeURIComponent(String(item))}`);\n }\n });\n } else {\n params.push(`${encodedKey}=${encodeURIComponent(String(value))}`);\n }\n });\n\n if (params.length === 0) {\n return '';\n }\n\n const searchParamsString = params.join('&');\n return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;\n};\n\nexport const findObjectPath = <T>(\n root: Record<string, unknown>,\n target: T,\n splitter = '/',\n path = splitter,\n): string | undefined => {\n for (const key in root) {\n // Skip _metadata keys during traversal\n if (key === '_metadata') {\n continue;\n }\n\n const current = root[key];\n\n if (current === target) return path + key;\n\n if (typeof current === 'object' && current !== null) {\n const result = findObjectPath(current as Record<string, unknown>, target, splitter, path + key + splitter);\n if (result) return result;\n }\n }\n\n return undefined;\n};\n\nexport const replaceDynamicSegments = (\n pathname: string,\n params?: SearchParams,\n): string => {\n if (!params) return pathname;\n\n return pathname.replace(/\\[([^\\]]+)\\]/g, (_, key) => {\n const value = params[key.toString()];\n if (value === undefined || value === null) return `[${key}]`;\n return Array.isArray(value) ? value.join(',') : value.toString();\n });\n};\n"]}
@@ -3,6 +3,9 @@ type Paths<TObject, TSplitter extends string, TPrev extends string = '', TMaxDep
3
3
  }[keyof TObject & string];
4
4
  type PathValue<T, P extends string, S extends string, TMaxDepth extends number = 10, TDepth extends unknown[] = []> = TDepth['length'] extends TMaxDepth ? never : P extends S ? T : P extends `${S}${infer Rest}` ? Rest extends `${infer K}${S}${infer R}` ? K extends keyof T ? PathValue<T[K], `${S}${R}`, S, TMaxDepth, [...TDepth, 1]> : never : Rest extends keyof T ? T[Rest] : never : never;
5
5
 
6
+ type SearchParamsValue = string | number | boolean | readonly (string | number | boolean)[];
7
+ type SearchParams = Record<string, SearchParamsValue>;
8
+
6
9
  type BaseMetadata = NonNullable<unknown>;
7
10
  type AnyZodSchema = {
8
11
  _input: any;
@@ -43,4 +46,4 @@ type ExtractSearchParams<TNode> = TNode extends {
43
46
  type GetRouteNode<TRouteTree, TPath extends string> = TPath extends `/${infer First}/${infer Rest}` ? First extends keyof TRouteTree ? GetRouteNode<TRouteTree[First], `/${Rest}`> : never : TPath extends `/${infer Key}` ? Key extends keyof TRouteTree ? TRouteTree[Key] : never : TRouteTree;
44
47
  type SearchParamsForPath<TRouteTree, TPath extends string> = ExtractSearchParams<GetRouteNode<TRouteTree, TPath>>;
45
48
 
46
- export type { AnyZodSchema as A, BaseMetadata as B, ExtractSearchParams as E, GetRouteNode as G, Paths as P, RouteNode as R, SimplifyPathname as S, PathValue as a, RouteNodeMetadata as b, PartialRouteTree as c, RouteTree as d, RoutePathname as e, ResolvedRouteTree as f, SearchParamsForPath as g };
49
+ export type { AnyZodSchema as A, BaseMetadata as B, ExtractSearchParams as E, GetRouteNode as G, Paths as P, RouteNode as R, SearchParams as S, PathValue as a, SearchParamsValue as b, RouteNodeMetadata as c, PartialRouteTree as d, RouteTree as e, RoutePathname as f, SimplifyPathname as g, ResolvedRouteTree as h, SearchParamsForPath as i };
@@ -3,6 +3,9 @@ type Paths<TObject, TSplitter extends string, TPrev extends string = '', TMaxDep
3
3
  }[keyof TObject & string];
4
4
  type PathValue<T, P extends string, S extends string, TMaxDepth extends number = 10, TDepth extends unknown[] = []> = TDepth['length'] extends TMaxDepth ? never : P extends S ? T : P extends `${S}${infer Rest}` ? Rest extends `${infer K}${S}${infer R}` ? K extends keyof T ? PathValue<T[K], `${S}${R}`, S, TMaxDepth, [...TDepth, 1]> : never : Rest extends keyof T ? T[Rest] : never : never;
5
5
 
6
+ type SearchParamsValue = string | number | boolean | readonly (string | number | boolean)[];
7
+ type SearchParams = Record<string, SearchParamsValue>;
8
+
6
9
  type BaseMetadata = NonNullable<unknown>;
7
10
  type AnyZodSchema = {
8
11
  _input: any;
@@ -43,4 +46,4 @@ type ExtractSearchParams<TNode> = TNode extends {
43
46
  type GetRouteNode<TRouteTree, TPath extends string> = TPath extends `/${infer First}/${infer Rest}` ? First extends keyof TRouteTree ? GetRouteNode<TRouteTree[First], `/${Rest}`> : never : TPath extends `/${infer Key}` ? Key extends keyof TRouteTree ? TRouteTree[Key] : never : TRouteTree;
44
47
  type SearchParamsForPath<TRouteTree, TPath extends string> = ExtractSearchParams<GetRouteNode<TRouteTree, TPath>>;
45
48
 
46
- export type { AnyZodSchema as A, BaseMetadata as B, ExtractSearchParams as E, GetRouteNode as G, Paths as P, RouteNode as R, SimplifyPathname as S, PathValue as a, RouteNodeMetadata as b, PartialRouteTree as c, RouteTree as d, RoutePathname as e, ResolvedRouteTree as f, SearchParamsForPath as g };
49
+ export type { AnyZodSchema as A, BaseMetadata as B, ExtractSearchParams as E, GetRouteNode as G, Paths as P, RouteNode as R, SearchParams as S, PathValue as a, SearchParamsValue as b, RouteNodeMetadata as c, PartialRouteTree as d, RouteTree as e, RoutePathname as f, SimplifyPathname as g, ResolvedRouteTree as h, SearchParamsForPath as i };
@@ -1,17 +1,20 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { B as BaseMetadata, c as PartialRouteTree, d as RouteTree, f as ResolvedRouteTree, e as RoutePathname, a as PathValue } from './routes.types-BOeBykBW.mjs';
3
+ import { B as BaseMetadata, d as PartialRouteTree, e as RouteTree, h as ResolvedRouteTree, f as RoutePathname, R as RouteNode, S as SearchParams } from './routes.types-C0cWyXOZ.mjs';
4
4
 
5
5
  declare const createAppRoutes: <TMetadata extends BaseMetadata, TContext>() => <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {
6
6
  AppRoutesProvider: ({ children }: {
7
7
  children: ReactNode;
8
8
  }) => react_jsx_runtime.JSX.Element;
9
9
  useAppRoutes: () => ResolvedRouteTree<TMetadata, TContext, TRouteTree>;
10
- useCurrentRouteNode: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(pathname: TPath) => PathValue<TRouteTree, TPath, "/">;
10
+ useCurrentRouteNode: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(pathname: TPath) => RouteNode<TMetadata, TContext>;
11
+ getPathnameFromNode: (targetNode: RouteNode<TMetadata, TContext>, params?: SearchParams) => string | undefined;
12
+ freezeAppRoutes: () => ResolvedRouteTree<TMetadata, TContext, TRouteTree>;
11
13
  _types: {
12
14
  AppRoutesMetadata: TMetadata;
13
15
  AppRoutesContext: TContext;
14
16
  AppRoutesPathname: RoutePathname<TMetadata, TContext, TRouteTree>;
17
+ AppRouteNode: RouteNode<TMetadata, TContext>;
15
18
  };
16
19
  };
17
20
 
@@ -1,17 +1,20 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import { ReactNode } from 'react';
3
- import { B as BaseMetadata, c as PartialRouteTree, d as RouteTree, f as ResolvedRouteTree, e as RoutePathname, a as PathValue } from './routes.types-BOeBykBW.js';
3
+ import { B as BaseMetadata, d as PartialRouteTree, e as RouteTree, h as ResolvedRouteTree, f as RoutePathname, R as RouteNode, S as SearchParams } from './routes.types-C0cWyXOZ.js';
4
4
 
5
5
  declare const createAppRoutes: <TMetadata extends BaseMetadata, TContext>() => <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {
6
6
  AppRoutesProvider: ({ children }: {
7
7
  children: ReactNode;
8
8
  }) => react_jsx_runtime.JSX.Element;
9
9
  useAppRoutes: () => ResolvedRouteTree<TMetadata, TContext, TRouteTree>;
10
- useCurrentRouteNode: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(pathname: TPath) => PathValue<TRouteTree, TPath, "/">;
10
+ useCurrentRouteNode: <TPath extends RoutePathname<TMetadata, TContext, TRouteTree>>(pathname: TPath) => RouteNode<TMetadata, TContext>;
11
+ getPathnameFromNode: (targetNode: RouteNode<TMetadata, TContext>, params?: SearchParams) => string | undefined;
12
+ freezeAppRoutes: () => ResolvedRouteTree<TMetadata, TContext, TRouteTree>;
11
13
  _types: {
12
14
  AppRoutesMetadata: TMetadata;
13
15
  AppRoutesContext: TContext;
14
16
  AppRoutesPathname: RoutePathname<TMetadata, TContext, TRouteTree>;
17
+ AppRouteNode: RouteNode<TMetadata, TContext>;
15
18
  };
16
19
  };
17
20
 
@@ -20,8 +20,49 @@ var getSafely = /* @__PURE__ */ __name((splitter, obj, path) => {
20
20
  }
21
21
  return value;
22
22
  }, "getSafely");
23
+ var findObjectPath = /* @__PURE__ */ __name((root, target, splitter = "/", path = splitter) => {
24
+ for (const key in root) {
25
+ if (key === "_metadata") {
26
+ continue;
27
+ }
28
+ const current = root[key];
29
+ if (current === target) return path + key;
30
+ if (typeof current === "object" && current !== null) {
31
+ const result = findObjectPath(current, target, splitter, path + key + splitter);
32
+ if (result) return result;
33
+ }
34
+ }
35
+ return void 0;
36
+ }, "findObjectPath");
37
+ var replaceDynamicSegments = /* @__PURE__ */ __name((pathname, params) => {
38
+ if (!params) return pathname;
39
+ return pathname.replace(/\[([^\]]+)\]/g, (_, key) => {
40
+ const value = params[key.toString()];
41
+ if (value === void 0 || value === null) return `[${key}]`;
42
+ return Array.isArray(value) ? value.join(",") : value.toString();
43
+ });
44
+ }, "replaceDynamicSegments");
23
45
  var createAppRoutes = /* @__PURE__ */ __name(() => (appRoutes) => {
24
- const Context = react.createContext(appRoutes);
46
+ const ROUTE_NODE_COMMON_KEY = "_metadata";
47
+ const freezeAppRoutes = /* @__PURE__ */ __name(() => {
48
+ const copiedAppRoutes = { ...appRoutes };
49
+ const freeze = /* @__PURE__ */ __name((obj) => {
50
+ Object.entries(obj).forEach(([key, value]) => {
51
+ Object.defineProperty(obj, key, {
52
+ writable: false,
53
+ enumerable: key !== ROUTE_NODE_COMMON_KEY,
54
+ configurable: false
55
+ });
56
+ if (typeof value === "object" && value !== null) {
57
+ freeze(value);
58
+ }
59
+ });
60
+ }, "freeze");
61
+ freeze(copiedAppRoutes);
62
+ return copiedAppRoutes;
63
+ }, "freezeAppRoutes");
64
+ const frozenAppRoutes = freezeAppRoutes();
65
+ const Context = react.createContext(frozenAppRoutes);
25
66
  const useAppRoutes = /* @__PURE__ */ __name(() => {
26
67
  return react.useContext(Context);
27
68
  }, "useAppRoutes");
@@ -30,12 +71,19 @@ var createAppRoutes = /* @__PURE__ */ __name(() => (appRoutes) => {
30
71
  return getSafely("/", routes, pathname);
31
72
  }, "useCurrentRouteNode");
32
73
  const AppRoutesProvider = /* @__PURE__ */ __name(({ children }) => {
33
- return /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value: appRoutes, children });
74
+ return /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value: frozenAppRoutes, children });
34
75
  }, "AppRoutesProvider");
76
+ const getPathnameFromNode = /* @__PURE__ */ __name((targetNode, params) => {
77
+ const pathname = findObjectPath(appRoutes, targetNode);
78
+ if (!pathname) return void 0;
79
+ return replaceDynamicSegments(pathname, params);
80
+ }, "getPathnameFromNode");
35
81
  return {
36
82
  AppRoutesProvider,
37
83
  useAppRoutes,
38
84
  useCurrentRouteNode,
85
+ getPathnameFromNode,
86
+ freezeAppRoutes,
39
87
  _types: {}
40
88
  };
41
89
  }, "createAppRoutes");
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/object.utils.ts","../src/routes.utils.tsx"],"names":["createContext","useContext"],"mappings":";;;;;;;;;AAGO,IAAM,SAAA,mBAAY,MAAA,CAAA,CACvB,QAAA,EACA,GAAA,EACA,IAAA,KACyC;AACzC,EAAA,IAAI,IAAA,KAAS,EAAA,IAAM,IAAA,KAAS,QAAA,EAAU,OAAO,GAAA;AAE7C,EAAA,MAAM,IAAA,GAAQ,KAAgB,KAAA,CAAM,QAAQ,EAAE,MAAA,CAAO,CAAC,QAAQ,GAAG,CAAA;AACjE,EAAA,IAAI,KAAA,GAAiB,GAAA;AAErB,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,EAAO;AAC/D,MAAA,KAAA,GAAS,MAAkC,GAAG,CAAA;AAAA,IAChD,CAAA,MAAO;AACL,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT,CAAA,EAnByB,WAAA,CAAA;ACElB,IAAM,eAAA,mBACX,MAAA,CAAA,MACA,CAA2D,SAAA,KAAuE;AAIhI,EAAA,MAAM,OAAA,GAAUA,oBAAsB,SAAmB,CAAA;AAEzD,EAAA,MAAM,+BAAe,MAAA,CAAA,MAAc;AACjC,IAAA,OAAOC,iBAAW,OAAO,CAAA;AAAA,EAC3B,CAAA,EAFqB,cAAA,CAAA;AAIrB,EAAA,MAAM,mBAAA,2BAA+C,QAAA,KAAuD;AAC1G,IAAA,MAAM,MAAA,GAASA,iBAAW,OAAO,CAAA;AACjC,IAAA,OAAO,SAAA,CAAU,GAAA,EAAK,MAAA,EAAQ,QAAQ,CAAA;AAAA,EACxC,CAAA,EAH4B,qBAAA,CAAA;AAK5B,EAAA,MAAM,iBAAA,mBAAoB,MAAA,CAAA,CAAC,EAAE,QAAA,EAAS,KAA+B;AACnE,IAAA,sCAAQ,OAAA,CAAQ,QAAA,EAAR,EAAiB,KAAA,EAAO,WAAsB,QAAA,EAAS,CAAA;AAAA,EACjE,CAAA,EAF0B,mBAAA,CAAA;AAI1B,EAAA,OAAO;AAAA,IACL,iBAAA;AAAA,IACA,YAAA;AAAA,IACA,mBAAA;AAAA,IACA,QAAQ;AAAC,GAKX;AACF,CAAA,EA9BA,iBAAA","file":"routes.utils.js","sourcesContent":["import { Paths, PathValue } from './path.types';\nimport { SearchParams } from './query.types';\n\nexport const getSafely = <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(\n splitter: TSplitter,\n obj: TObject,\n path: TPath,\n): PathValue<TObject, TPath, TSplitter> => {\n if (path === '' || path === splitter) return obj as PathValue<TObject, TPath, TSplitter>;\n\n const keys = (path as string).split(splitter).filter((key) => key);\n let value: unknown = obj;\n\n for (const key of keys) {\n if (typeof value === 'object' && value !== null && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined as PathValue<TObject, TPath, TSplitter>;\n }\n }\n\n return value as PathValue<TObject, TPath, TSplitter>;\n};\n\nexport type SearchParamsStringOptions = {\n includeQuestionMark?: boolean;\n};\n\nexport const toSearchParamsString = (\n searchParams: SearchParams,\n options: SearchParamsStringOptions = { includeQuestionMark: true },\n): string => {\n const params: string[] = [];\n\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n value.forEach((item) => {\n if (item !== undefined && item !== null) {\n params.push(`${encodedKey}=${encodeURIComponent(String(item))}`);\n }\n });\n } else {\n params.push(`${encodedKey}=${encodeURIComponent(String(value))}`);\n }\n });\n\n if (params.length === 0) {\n return '';\n }\n\n const searchParamsString = params.join('&');\n return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;\n};\n","import { createContext, ReactNode, useContext } from 'react';\nimport { getSafely } from './object.utils';\nimport { PathValue } from './path.types';\nimport { BaseMetadata, PartialRouteTree, ResolvedRouteTree, RoutePathname, RouteTree } from './routes.types';\n\nexport const createAppRoutes =\n <TMetadata extends BaseMetadata, TContext>() =>\n <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n\n const Context = createContext<Routes>(appRoutes as Routes);\n\n const useAppRoutes = (): Routes => {\n return useContext(Context);\n };\n\n const useCurrentRouteNode = <TPath extends Pathname>(pathname: TPath): PathValue<TRouteTree, TPath, '/'> => {\n const routes = useContext(Context);\n return getSafely('/', routes, pathname) as PathValue<TRouteTree, TPath, '/'>;\n };\n\n const AppRoutesProvider = ({ children }: { children: ReactNode }) => {\n return <Context.Provider value={appRoutes as Routes}>{children}</Context.Provider>;\n };\n\n return {\n AppRoutesProvider,\n useAppRoutes,\n useCurrentRouteNode,\n _types: {} as {\n AppRoutesMetadata: TMetadata;\n AppRoutesContext: TContext;\n AppRoutesPathname: Pathname;\n },\n };\n };\n"]}
1
+ {"version":3,"sources":["../src/object.utils.ts","../src/routes.utils.tsx"],"names":["createContext","useContext"],"mappings":"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","file":"routes.utils.js","sourcesContent":["import { Paths, PathValue } from './path.types';\nimport { SearchParams } from './query.types';\n\nexport const getSafely = <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(\n splitter: TSplitter,\n obj: TObject,\n path: TPath,\n): PathValue<TObject, TPath, TSplitter> => {\n if (path === '' || path === splitter) return obj as PathValue<TObject, TPath, TSplitter>;\n\n const keys = (path as string).split(splitter).filter((key) => key);\n let value: unknown = obj;\n\n for (const key of keys) {\n if (typeof value === 'object' && value !== null && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined as PathValue<TObject, TPath, TSplitter>;\n }\n }\n\n return value as PathValue<TObject, TPath, TSplitter>;\n};\n\nexport type SearchParamsStringOptions = {\n includeQuestionMark?: boolean;\n};\n\nexport const toSearchParamsString = (\n searchParams: SearchParams,\n options: SearchParamsStringOptions = { includeQuestionMark: true },\n): string => {\n const params: string[] = [];\n\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n value.forEach((item) => {\n if (item !== undefined && item !== null) {\n params.push(`${encodedKey}=${encodeURIComponent(String(item))}`);\n }\n });\n } else {\n params.push(`${encodedKey}=${encodeURIComponent(String(value))}`);\n }\n });\n\n if (params.length === 0) {\n return '';\n }\n\n const searchParamsString = params.join('&');\n return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;\n};\n\nexport const findObjectPath = <T>(\n root: Record<string, unknown>,\n target: T,\n splitter = '/',\n path = splitter,\n): string | undefined => {\n for (const key in root) {\n // Skip _metadata keys during traversal\n if (key === '_metadata') {\n continue;\n }\n\n const current = root[key];\n\n if (current === target) return path + key;\n\n if (typeof current === 'object' && current !== null) {\n const result = findObjectPath(current as Record<string, unknown>, target, splitter, path + key + splitter);\n if (result) return result;\n }\n }\n\n return undefined;\n};\n\nexport const replaceDynamicSegments = (\n pathname: string,\n params?: SearchParams,\n): string => {\n if (!params) return pathname;\n\n return pathname.replace(/\\[([^\\]]+)\\]/g, (_, key) => {\n const value = params[key.toString()];\n if (value === undefined || value === null) return `[${key}]`;\n return Array.isArray(value) ? value.join(',') : value.toString();\n });\n};\n","import { createContext, ReactNode, useContext } from 'react';\nimport { findObjectPath, getSafely, replaceDynamicSegments } from './object.utils';\nimport { SearchParams } from './query.types';\nimport { BaseMetadata, PartialRouteTree, ResolvedRouteTree, RouteNode, RoutePathname, RouteTree } from './routes.types';\n\nexport const createAppRoutes =\n <TMetadata extends BaseMetadata, TContext>() =>\n <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n type AppRouteNode = RouteNode<TMetadata, TContext>;\n\n const ROUTE_NODE_COMMON_KEY: keyof AppRouteNode = '_metadata';\n\n const freezeAppRoutes = () => {\n const copiedAppRoutes = { ...appRoutes };\n\n const freeze = (obj: Record<string, unknown>) => {\n Object.entries(obj).forEach(([key, value]) => {\n Object.defineProperty(obj, key, {\n writable: false,\n enumerable: key !== ROUTE_NODE_COMMON_KEY,\n configurable: false,\n });\n\n if (typeof value === 'object' && value !== null) {\n freeze(value as Record<string, unknown>);\n }\n });\n };\n\n freeze(copiedAppRoutes as Record<string, unknown>);\n return copiedAppRoutes as Routes;\n };\n\n const frozenAppRoutes = freezeAppRoutes();\n\n const Context = createContext<Routes>(frozenAppRoutes);\n\n const useAppRoutes = (): Routes => {\n return useContext(Context);\n };\n\n const useCurrentRouteNode = <TPath extends Pathname>(pathname: TPath) => {\n const routes = useContext(Context);\n return getSafely('/', routes, pathname) as RouteNode<TMetadata, TContext>;\n };\n\n const AppRoutesProvider = ({ children }: { children: ReactNode }) => {\n return <Context.Provider value={frozenAppRoutes}>{children}</Context.Provider>;\n };\n\n const getPathnameFromNode = (targetNode: AppRouteNode, params?: SearchParams): string | undefined => {\n const pathname = findObjectPath(appRoutes, targetNode);\n if (!pathname) return undefined;\n return replaceDynamicSegments(pathname, params);\n };\n\n return {\n AppRoutesProvider,\n useAppRoutes,\n useCurrentRouteNode,\n getPathnameFromNode,\n freezeAppRoutes,\n _types: {} as {\n AppRoutesMetadata: TMetadata;\n AppRoutesContext: TContext;\n AppRoutesPathname: Pathname;\n AppRouteNode: AppRouteNode;\n },\n };\n };\n"]}
@@ -18,8 +18,49 @@ var getSafely = /* @__PURE__ */ __name((splitter, obj, path) => {
18
18
  }
19
19
  return value;
20
20
  }, "getSafely");
21
+ var findObjectPath = /* @__PURE__ */ __name((root, target, splitter = "/", path = splitter) => {
22
+ for (const key in root) {
23
+ if (key === "_metadata") {
24
+ continue;
25
+ }
26
+ const current = root[key];
27
+ if (current === target) return path + key;
28
+ if (typeof current === "object" && current !== null) {
29
+ const result = findObjectPath(current, target, splitter, path + key + splitter);
30
+ if (result) return result;
31
+ }
32
+ }
33
+ return void 0;
34
+ }, "findObjectPath");
35
+ var replaceDynamicSegments = /* @__PURE__ */ __name((pathname, params) => {
36
+ if (!params) return pathname;
37
+ return pathname.replace(/\[([^\]]+)\]/g, (_, key) => {
38
+ const value = params[key.toString()];
39
+ if (value === void 0 || value === null) return `[${key}]`;
40
+ return Array.isArray(value) ? value.join(",") : value.toString();
41
+ });
42
+ }, "replaceDynamicSegments");
21
43
  var createAppRoutes = /* @__PURE__ */ __name(() => (appRoutes) => {
22
- const Context = createContext(appRoutes);
44
+ const ROUTE_NODE_COMMON_KEY = "_metadata";
45
+ const freezeAppRoutes = /* @__PURE__ */ __name(() => {
46
+ const copiedAppRoutes = { ...appRoutes };
47
+ const freeze = /* @__PURE__ */ __name((obj) => {
48
+ Object.entries(obj).forEach(([key, value]) => {
49
+ Object.defineProperty(obj, key, {
50
+ writable: false,
51
+ enumerable: key !== ROUTE_NODE_COMMON_KEY,
52
+ configurable: false
53
+ });
54
+ if (typeof value === "object" && value !== null) {
55
+ freeze(value);
56
+ }
57
+ });
58
+ }, "freeze");
59
+ freeze(copiedAppRoutes);
60
+ return copiedAppRoutes;
61
+ }, "freezeAppRoutes");
62
+ const frozenAppRoutes = freezeAppRoutes();
63
+ const Context = createContext(frozenAppRoutes);
23
64
  const useAppRoutes = /* @__PURE__ */ __name(() => {
24
65
  return useContext(Context);
25
66
  }, "useAppRoutes");
@@ -28,12 +69,19 @@ var createAppRoutes = /* @__PURE__ */ __name(() => (appRoutes) => {
28
69
  return getSafely("/", routes, pathname);
29
70
  }, "useCurrentRouteNode");
30
71
  const AppRoutesProvider = /* @__PURE__ */ __name(({ children }) => {
31
- return /* @__PURE__ */ jsx(Context.Provider, { value: appRoutes, children });
72
+ return /* @__PURE__ */ jsx(Context.Provider, { value: frozenAppRoutes, children });
32
73
  }, "AppRoutesProvider");
74
+ const getPathnameFromNode = /* @__PURE__ */ __name((targetNode, params) => {
75
+ const pathname = findObjectPath(appRoutes, targetNode);
76
+ if (!pathname) return void 0;
77
+ return replaceDynamicSegments(pathname, params);
78
+ }, "getPathnameFromNode");
33
79
  return {
34
80
  AppRoutesProvider,
35
81
  useAppRoutes,
36
82
  useCurrentRouteNode,
83
+ getPathnameFromNode,
84
+ freezeAppRoutes,
37
85
  _types: {}
38
86
  };
39
87
  }, "createAppRoutes");
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/object.utils.ts","../src/routes.utils.tsx"],"names":[],"mappings":";;;;;;;AAGO,IAAM,SAAA,mBAAY,MAAA,CAAA,CACvB,QAAA,EACA,GAAA,EACA,IAAA,KACyC;AACzC,EAAA,IAAI,IAAA,KAAS,EAAA,IAAM,IAAA,KAAS,QAAA,EAAU,OAAO,GAAA;AAE7C,EAAA,MAAM,IAAA,GAAQ,KAAgB,KAAA,CAAM,QAAQ,EAAE,MAAA,CAAO,CAAC,QAAQ,GAAG,CAAA;AACjE,EAAA,IAAI,KAAA,GAAiB,GAAA;AAErB,EAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,IAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,EAAO;AAC/D,MAAA,KAAA,GAAS,MAAkC,GAAG,CAAA;AAAA,IAChD,CAAA,MAAO;AACL,MAAA,OAAO,MAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT,CAAA,EAnByB,WAAA,CAAA;ACElB,IAAM,eAAA,mBACX,MAAA,CAAA,MACA,CAA2D,SAAA,KAAuE;AAIhI,EAAA,MAAM,OAAA,GAAU,cAAsB,SAAmB,CAAA;AAEzD,EAAA,MAAM,+BAAe,MAAA,CAAA,MAAc;AACjC,IAAA,OAAO,WAAW,OAAO,CAAA;AAAA,EAC3B,CAAA,EAFqB,cAAA,CAAA;AAIrB,EAAA,MAAM,mBAAA,2BAA+C,QAAA,KAAuD;AAC1G,IAAA,MAAM,MAAA,GAAS,WAAW,OAAO,CAAA;AACjC,IAAA,OAAO,SAAA,CAAU,GAAA,EAAK,MAAA,EAAQ,QAAQ,CAAA;AAAA,EACxC,CAAA,EAH4B,qBAAA,CAAA;AAK5B,EAAA,MAAM,iBAAA,mBAAoB,MAAA,CAAA,CAAC,EAAE,QAAA,EAAS,KAA+B;AACnE,IAAA,2BAAQ,OAAA,CAAQ,QAAA,EAAR,EAAiB,KAAA,EAAO,WAAsB,QAAA,EAAS,CAAA;AAAA,EACjE,CAAA,EAF0B,mBAAA,CAAA;AAI1B,EAAA,OAAO;AAAA,IACL,iBAAA;AAAA,IACA,YAAA;AAAA,IACA,mBAAA;AAAA,IACA,QAAQ;AAAC,GAKX;AACF,CAAA,EA9BA,iBAAA","file":"routes.utils.mjs","sourcesContent":["import { Paths, PathValue } from './path.types';\nimport { SearchParams } from './query.types';\n\nexport const getSafely = <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(\n splitter: TSplitter,\n obj: TObject,\n path: TPath,\n): PathValue<TObject, TPath, TSplitter> => {\n if (path === '' || path === splitter) return obj as PathValue<TObject, TPath, TSplitter>;\n\n const keys = (path as string).split(splitter).filter((key) => key);\n let value: unknown = obj;\n\n for (const key of keys) {\n if (typeof value === 'object' && value !== null && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined as PathValue<TObject, TPath, TSplitter>;\n }\n }\n\n return value as PathValue<TObject, TPath, TSplitter>;\n};\n\nexport type SearchParamsStringOptions = {\n includeQuestionMark?: boolean;\n};\n\nexport const toSearchParamsString = (\n searchParams: SearchParams,\n options: SearchParamsStringOptions = { includeQuestionMark: true },\n): string => {\n const params: string[] = [];\n\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n value.forEach((item) => {\n if (item !== undefined && item !== null) {\n params.push(`${encodedKey}=${encodeURIComponent(String(item))}`);\n }\n });\n } else {\n params.push(`${encodedKey}=${encodeURIComponent(String(value))}`);\n }\n });\n\n if (params.length === 0) {\n return '';\n }\n\n const searchParamsString = params.join('&');\n return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;\n};\n","import { createContext, ReactNode, useContext } from 'react';\nimport { getSafely } from './object.utils';\nimport { PathValue } from './path.types';\nimport { BaseMetadata, PartialRouteTree, ResolvedRouteTree, RoutePathname, RouteTree } from './routes.types';\n\nexport const createAppRoutes =\n <TMetadata extends BaseMetadata, TContext>() =>\n <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n\n const Context = createContext<Routes>(appRoutes as Routes);\n\n const useAppRoutes = (): Routes => {\n return useContext(Context);\n };\n\n const useCurrentRouteNode = <TPath extends Pathname>(pathname: TPath): PathValue<TRouteTree, TPath, '/'> => {\n const routes = useContext(Context);\n return getSafely('/', routes, pathname) as PathValue<TRouteTree, TPath, '/'>;\n };\n\n const AppRoutesProvider = ({ children }: { children: ReactNode }) => {\n return <Context.Provider value={appRoutes as Routes}>{children}</Context.Provider>;\n };\n\n return {\n AppRoutesProvider,\n useAppRoutes,\n useCurrentRouteNode,\n _types: {} as {\n AppRoutesMetadata: TMetadata;\n AppRoutesContext: TContext;\n AppRoutesPathname: Pathname;\n },\n };\n };\n"]}
1
+ {"version":3,"sources":["../src/object.utils.ts","../src/routes.utils.tsx"],"names":[],"mappings":"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","file":"routes.utils.mjs","sourcesContent":["import { Paths, PathValue } from './path.types';\nimport { SearchParams } from './query.types';\n\nexport const getSafely = <TObject, TSplitter extends string, TPath extends string & Paths<TObject, TSplitter>>(\n splitter: TSplitter,\n obj: TObject,\n path: TPath,\n): PathValue<TObject, TPath, TSplitter> => {\n if (path === '' || path === splitter) return obj as PathValue<TObject, TPath, TSplitter>;\n\n const keys = (path as string).split(splitter).filter((key) => key);\n let value: unknown = obj;\n\n for (const key of keys) {\n if (typeof value === 'object' && value !== null && key in value) {\n value = (value as Record<string, unknown>)[key];\n } else {\n return undefined as PathValue<TObject, TPath, TSplitter>;\n }\n }\n\n return value as PathValue<TObject, TPath, TSplitter>;\n};\n\nexport type SearchParamsStringOptions = {\n includeQuestionMark?: boolean;\n};\n\nexport const toSearchParamsString = (\n searchParams: SearchParams,\n options: SearchParamsStringOptions = { includeQuestionMark: true },\n): string => {\n const params: string[] = [];\n\n Object.entries(searchParams).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n return;\n }\n\n const encodedKey = encodeURIComponent(key);\n\n if (Array.isArray(value)) {\n value.forEach((item) => {\n if (item !== undefined && item !== null) {\n params.push(`${encodedKey}=${encodeURIComponent(String(item))}`);\n }\n });\n } else {\n params.push(`${encodedKey}=${encodeURIComponent(String(value))}`);\n }\n });\n\n if (params.length === 0) {\n return '';\n }\n\n const searchParamsString = params.join('&');\n return options.includeQuestionMark ? `?${searchParamsString}` : searchParamsString;\n};\n\nexport const findObjectPath = <T>(\n root: Record<string, unknown>,\n target: T,\n splitter = '/',\n path = splitter,\n): string | undefined => {\n for (const key in root) {\n // Skip _metadata keys during traversal\n if (key === '_metadata') {\n continue;\n }\n\n const current = root[key];\n\n if (current === target) return path + key;\n\n if (typeof current === 'object' && current !== null) {\n const result = findObjectPath(current as Record<string, unknown>, target, splitter, path + key + splitter);\n if (result) return result;\n }\n }\n\n return undefined;\n};\n\nexport const replaceDynamicSegments = (\n pathname: string,\n params?: SearchParams,\n): string => {\n if (!params) return pathname;\n\n return pathname.replace(/\\[([^\\]]+)\\]/g, (_, key) => {\n const value = params[key.toString()];\n if (value === undefined || value === null) return `[${key}]`;\n return Array.isArray(value) ? value.join(',') : value.toString();\n });\n};\n","import { createContext, ReactNode, useContext } from 'react';\nimport { findObjectPath, getSafely, replaceDynamicSegments } from './object.utils';\nimport { SearchParams } from './query.types';\nimport { BaseMetadata, PartialRouteTree, ResolvedRouteTree, RouteNode, RoutePathname, RouteTree } from './routes.types';\n\nexport const createAppRoutes =\n <TMetadata extends BaseMetadata, TContext>() =>\n <TRouteTree extends PartialRouteTree<TMetadata, TContext>>(appRoutes: TRouteTree & RouteTree<TMetadata, TContext, TRouteTree>) => {\n type Routes = ResolvedRouteTree<TMetadata, TContext, TRouteTree>;\n type Pathname = RoutePathname<TMetadata, TContext, TRouteTree>;\n type AppRouteNode = RouteNode<TMetadata, TContext>;\n\n const ROUTE_NODE_COMMON_KEY: keyof AppRouteNode = '_metadata';\n\n const freezeAppRoutes = () => {\n const copiedAppRoutes = { ...appRoutes };\n\n const freeze = (obj: Record<string, unknown>) => {\n Object.entries(obj).forEach(([key, value]) => {\n Object.defineProperty(obj, key, {\n writable: false,\n enumerable: key !== ROUTE_NODE_COMMON_KEY,\n configurable: false,\n });\n\n if (typeof value === 'object' && value !== null) {\n freeze(value as Record<string, unknown>);\n }\n });\n };\n\n freeze(copiedAppRoutes as Record<string, unknown>);\n return copiedAppRoutes as Routes;\n };\n\n const frozenAppRoutes = freezeAppRoutes();\n\n const Context = createContext<Routes>(frozenAppRoutes);\n\n const useAppRoutes = (): Routes => {\n return useContext(Context);\n };\n\n const useCurrentRouteNode = <TPath extends Pathname>(pathname: TPath) => {\n const routes = useContext(Context);\n return getSafely('/', routes, pathname) as RouteNode<TMetadata, TContext>;\n };\n\n const AppRoutesProvider = ({ children }: { children: ReactNode }) => {\n return <Context.Provider value={frozenAppRoutes}>{children}</Context.Provider>;\n };\n\n const getPathnameFromNode = (targetNode: AppRouteNode, params?: SearchParams): string | undefined => {\n const pathname = findObjectPath(appRoutes, targetNode);\n if (!pathname) return undefined;\n return replaceDynamicSegments(pathname, params);\n };\n\n return {\n AppRoutesProvider,\n useAppRoutes,\n useCurrentRouteNode,\n getPathnameFromNode,\n freezeAppRoutes,\n _types: {} as {\n AppRoutesMetadata: TMetadata;\n AppRoutesContext: TContext;\n AppRoutesPathname: Pathname;\n AppRouteNode: AppRouteNode;\n },\n };\n };\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyeonqyu/typed-router-core",
3
- "version": "1.4.1",
3
+ "version": "1.5.0",
4
4
  "description": "Core types and utilities for typed-router",
5
5
  "author": "hyeonQyu <dhk0561@naver.com>",
6
6
  "license": "MIT",