@react-navigation/core 6.0.2

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.
Files changed (327) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +38 -0
  3. package/lib/commonjs/BaseNavigationContainer.js +393 -0
  4. package/lib/commonjs/BaseNavigationContainer.js.map +1 -0
  5. package/lib/commonjs/CurrentRenderContext.js +21 -0
  6. package/lib/commonjs/CurrentRenderContext.js.map +1 -0
  7. package/lib/commonjs/EnsureSingleNavigator.js +53 -0
  8. package/lib/commonjs/EnsureSingleNavigator.js.map +1 -0
  9. package/lib/commonjs/Group.js +15 -0
  10. package/lib/commonjs/Group.js.map +1 -0
  11. package/lib/commonjs/NavigationBuilderContext.js +23 -0
  12. package/lib/commonjs/NavigationBuilderContext.js.map +1 -0
  13. package/lib/commonjs/NavigationContainerRefContext.js +20 -0
  14. package/lib/commonjs/NavigationContainerRefContext.js.map +1 -0
  15. package/lib/commonjs/NavigationContext.js +20 -0
  16. package/lib/commonjs/NavigationContext.js.map +1 -0
  17. package/lib/commonjs/NavigationHelpersContext.js +21 -0
  18. package/lib/commonjs/NavigationHelpersContext.js.map +1 -0
  19. package/lib/commonjs/NavigationRouteContext.js +20 -0
  20. package/lib/commonjs/NavigationRouteContext.js.map +1 -0
  21. package/lib/commonjs/NavigationStateContext.js +42 -0
  22. package/lib/commonjs/NavigationStateContext.js.map +1 -0
  23. package/lib/commonjs/SceneView.js +97 -0
  24. package/lib/commonjs/SceneView.js.map +1 -0
  25. package/lib/commonjs/Screen.js +15 -0
  26. package/lib/commonjs/Screen.js.map +1 -0
  27. package/lib/commonjs/StaticContainer.js +43 -0
  28. package/lib/commonjs/StaticContainer.js.map +1 -0
  29. package/lib/commonjs/UnhandledActionContext.js +17 -0
  30. package/lib/commonjs/UnhandledActionContext.js.map +1 -0
  31. package/lib/commonjs/checkDuplicateRouteNames.js +31 -0
  32. package/lib/commonjs/checkDuplicateRouteNames.js.map +1 -0
  33. package/lib/commonjs/checkSerializable.js +59 -0
  34. package/lib/commonjs/checkSerializable.js.map +1 -0
  35. package/lib/commonjs/createNavigationContainerRef.js +82 -0
  36. package/lib/commonjs/createNavigationContainerRef.js.map +1 -0
  37. package/lib/commonjs/createNavigatorFactory.js +34 -0
  38. package/lib/commonjs/createNavigatorFactory.js.map +1 -0
  39. package/lib/commonjs/findFocusedRoute.js +22 -0
  40. package/lib/commonjs/findFocusedRoute.js.map +1 -0
  41. package/lib/commonjs/fromEntries.js +19 -0
  42. package/lib/commonjs/fromEntries.js.map +1 -0
  43. package/lib/commonjs/getActionFromState.js +99 -0
  44. package/lib/commonjs/getActionFromState.js.map +1 -0
  45. package/lib/commonjs/getFocusedRouteNameFromRoute.js +23 -0
  46. package/lib/commonjs/getFocusedRouteNameFromRoute.js.map +1 -0
  47. package/lib/commonjs/getPathFromState.js +238 -0
  48. package/lib/commonjs/getPathFromState.js.map +1 -0
  49. package/lib/commonjs/getStateFromPath.js +450 -0
  50. package/lib/commonjs/getStateFromPath.js.map +1 -0
  51. package/lib/commonjs/index.js +227 -0
  52. package/lib/commonjs/index.js.map +1 -0
  53. package/lib/commonjs/isArrayEqual.js +15 -0
  54. package/lib/commonjs/isArrayEqual.js.map +1 -0
  55. package/lib/commonjs/types.js +18 -0
  56. package/lib/commonjs/types.js.map +1 -0
  57. package/lib/commonjs/useChildListeners.js +38 -0
  58. package/lib/commonjs/useChildListeners.js.map +1 -0
  59. package/lib/commonjs/useComponent.js +36 -0
  60. package/lib/commonjs/useComponent.js.map +1 -0
  61. package/lib/commonjs/useCurrentRender.js +33 -0
  62. package/lib/commonjs/useCurrentRender.js.map +1 -0
  63. package/lib/commonjs/useDescriptors.js +141 -0
  64. package/lib/commonjs/useDescriptors.js.map +1 -0
  65. package/lib/commonjs/useEventEmitter.js +118 -0
  66. package/lib/commonjs/useEventEmitter.js.map +1 -0
  67. package/lib/commonjs/useFocusEffect.js +97 -0
  68. package/lib/commonjs/useFocusEffect.js.map +1 -0
  69. package/lib/commonjs/useFocusEvents.js +77 -0
  70. package/lib/commonjs/useFocusEvents.js.map +1 -0
  71. package/lib/commonjs/useFocusedListenersChildrenAdapter.js +57 -0
  72. package/lib/commonjs/useFocusedListenersChildrenAdapter.js.map +1 -0
  73. package/lib/commonjs/useIsFocused.js +47 -0
  74. package/lib/commonjs/useIsFocused.js.map +1 -0
  75. package/lib/commonjs/useKeyedChildListeners.js +35 -0
  76. package/lib/commonjs/useKeyedChildListeners.js.map +1 -0
  77. package/lib/commonjs/useNavigation.js +36 -0
  78. package/lib/commonjs/useNavigation.js.map +1 -0
  79. package/lib/commonjs/useNavigationBuilder.js +480 -0
  80. package/lib/commonjs/useNavigationBuilder.js.map +1 -0
  81. package/lib/commonjs/useNavigationCache.js +122 -0
  82. package/lib/commonjs/useNavigationCache.js.map +1 -0
  83. package/lib/commonjs/useNavigationContainerRef.js +27 -0
  84. package/lib/commonjs/useNavigationContainerRef.js.map +1 -0
  85. package/lib/commonjs/useNavigationHelpers.js +77 -0
  86. package/lib/commonjs/useNavigationHelpers.js.map +1 -0
  87. package/lib/commonjs/useNavigationState.js +41 -0
  88. package/lib/commonjs/useNavigationState.js.map +1 -0
  89. package/lib/commonjs/useOnAction.js +118 -0
  90. package/lib/commonjs/useOnAction.js.map +1 -0
  91. package/lib/commonjs/useOnGetState.js +60 -0
  92. package/lib/commonjs/useOnGetState.js.map +1 -0
  93. package/lib/commonjs/useOnPreventRemove.js +89 -0
  94. package/lib/commonjs/useOnPreventRemove.js.map +1 -0
  95. package/lib/commonjs/useOnRouteFocus.js +45 -0
  96. package/lib/commonjs/useOnRouteFocus.js.map +1 -0
  97. package/lib/commonjs/useOptionsGetters.js +99 -0
  98. package/lib/commonjs/useOptionsGetters.js.map +1 -0
  99. package/lib/commonjs/useRegisterNavigator.js +40 -0
  100. package/lib/commonjs/useRegisterNavigator.js.map +1 -0
  101. package/lib/commonjs/useRoute.js +32 -0
  102. package/lib/commonjs/useRoute.js.map +1 -0
  103. package/lib/commonjs/useRouteCache.js +61 -0
  104. package/lib/commonjs/useRouteCache.js.map +1 -0
  105. package/lib/commonjs/useScheduleUpdate.js +44 -0
  106. package/lib/commonjs/useScheduleUpdate.js.map +1 -0
  107. package/lib/commonjs/useSyncState.js +76 -0
  108. package/lib/commonjs/useSyncState.js.map +1 -0
  109. package/lib/commonjs/validatePathConfig.js +31 -0
  110. package/lib/commonjs/validatePathConfig.js.map +1 -0
  111. package/lib/module/BaseNavigationContainer.js +360 -0
  112. package/lib/module/BaseNavigationContainer.js.map +1 -0
  113. package/lib/module/CurrentRenderContext.js +9 -0
  114. package/lib/module/CurrentRenderContext.js.map +1 -0
  115. package/lib/module/EnsureSingleNavigator.js +38 -0
  116. package/lib/module/EnsureSingleNavigator.js.map +1 -0
  117. package/lib/module/Group.js +8 -0
  118. package/lib/module/Group.js.map +1 -0
  119. package/lib/module/NavigationBuilderContext.js +11 -0
  120. package/lib/module/NavigationBuilderContext.js.map +1 -0
  121. package/lib/module/NavigationContainerRefContext.js +8 -0
  122. package/lib/module/NavigationContainerRefContext.js.map +1 -0
  123. package/lib/module/NavigationContext.js +8 -0
  124. package/lib/module/NavigationContext.js.map +1 -0
  125. package/lib/module/NavigationHelpersContext.js +9 -0
  126. package/lib/module/NavigationHelpersContext.js.map +1 -0
  127. package/lib/module/NavigationRouteContext.js +8 -0
  128. package/lib/module/NavigationRouteContext.js.map +1 -0
  129. package/lib/module/NavigationStateContext.js +27 -0
  130. package/lib/module/NavigationStateContext.js.map +1 -0
  131. package/lib/module/SceneView.js +80 -0
  132. package/lib/module/SceneView.js.map +1 -0
  133. package/lib/module/Screen.js +8 -0
  134. package/lib/module/Screen.js.map +1 -0
  135. package/lib/module/StaticContainer.js +30 -0
  136. package/lib/module/StaticContainer.js.map +1 -0
  137. package/lib/module/UnhandledActionContext.js +4 -0
  138. package/lib/module/UnhandledActionContext.js.map +1 -0
  139. package/lib/module/checkDuplicateRouteNames.js +24 -0
  140. package/lib/module/checkDuplicateRouteNames.js.map +1 -0
  141. package/lib/module/checkSerializable.js +52 -0
  142. package/lib/module/checkSerializable.js.map +1 -0
  143. package/lib/module/createNavigationContainerRef.js +71 -0
  144. package/lib/module/createNavigationContainerRef.js.map +1 -0
  145. package/lib/module/createNavigatorFactory.js +24 -0
  146. package/lib/module/createNavigatorFactory.js.map +1 -0
  147. package/lib/module/findFocusedRoute.js +15 -0
  148. package/lib/module/findFocusedRoute.js.map +1 -0
  149. package/lib/module/fromEntries.js +12 -0
  150. package/lib/module/fromEntries.js.map +1 -0
  151. package/lib/module/getActionFromState.js +92 -0
  152. package/lib/module/getActionFromState.js.map +1 -0
  153. package/lib/module/getFocusedRouteNameFromRoute.js +15 -0
  154. package/lib/module/getFocusedRouteNameFromRoute.js.map +1 -0
  155. package/lib/module/getPathFromState.js +223 -0
  156. package/lib/module/getPathFromState.js.map +1 -0
  157. package/lib/module/getStateFromPath.js +434 -0
  158. package/lib/module/getStateFromPath.js.map +1 -0
  159. package/lib/module/index.js +24 -0
  160. package/lib/module/index.js.map +1 -0
  161. package/lib/module/isArrayEqual.js +8 -0
  162. package/lib/module/isArrayEqual.js.map +1 -0
  163. package/lib/module/types.js +9 -0
  164. package/lib/module/types.js.map +1 -0
  165. package/lib/module/useChildListeners.js +27 -0
  166. package/lib/module/useChildListeners.js.map +1 -0
  167. package/lib/module/useComponent.js +24 -0
  168. package/lib/module/useComponent.js.map +1 -0
  169. package/lib/module/useCurrentRender.js +19 -0
  170. package/lib/module/useCurrentRender.js.map +1 -0
  171. package/lib/module/useDescriptors.js +122 -0
  172. package/lib/module/useDescriptors.js.map +1 -0
  173. package/lib/module/useEventEmitter.js +107 -0
  174. package/lib/module/useEventEmitter.js.map +1 -0
  175. package/lib/module/useFocusEffect.js +83 -0
  176. package/lib/module/useFocusEffect.js.map +1 -0
  177. package/lib/module/useFocusEvents.js +63 -0
  178. package/lib/module/useFocusEvents.js.map +1 -0
  179. package/lib/module/useFocusedListenersChildrenAdapter.js +43 -0
  180. package/lib/module/useFocusedListenersChildrenAdapter.js.map +1 -0
  181. package/lib/module/useIsFocused.js +34 -0
  182. package/lib/module/useIsFocused.js.map +1 -0
  183. package/lib/module/useKeyedChildListeners.js +24 -0
  184. package/lib/module/useKeyedChildListeners.js.map +1 -0
  185. package/lib/module/useNavigation.js +21 -0
  186. package/lib/module/useNavigation.js.map +1 -0
  187. package/lib/module/useNavigationBuilder.js +443 -0
  188. package/lib/module/useNavigationBuilder.js.map +1 -0
  189. package/lib/module/useNavigationCache.js +107 -0
  190. package/lib/module/useNavigationCache.js.map +1 -0
  191. package/lib/module/useNavigationContainerRef.js +12 -0
  192. package/lib/module/useNavigationContainerRef.js.map +1 -0
  193. package/lib/module/useNavigationHelpers.js +59 -0
  194. package/lib/module/useNavigationHelpers.js.map +1 -0
  195. package/lib/module/useNavigationState.js +27 -0
  196. package/lib/module/useNavigationState.js.map +1 -0
  197. package/lib/module/useOnAction.js +103 -0
  198. package/lib/module/useOnAction.js.map +1 -0
  199. package/lib/module/useOnGetState.js +43 -0
  200. package/lib/module/useOnGetState.js.map +1 -0
  201. package/lib/module/useOnPreventRemove.js +68 -0
  202. package/lib/module/useOnPreventRemove.js.map +1 -0
  203. package/lib/module/useOnRouteFocus.js +31 -0
  204. package/lib/module/useOnRouteFocus.js.map +1 -0
  205. package/lib/module/useOptionsGetters.js +83 -0
  206. package/lib/module/useOptionsGetters.js.map +1 -0
  207. package/lib/module/useRegisterNavigator.js +27 -0
  208. package/lib/module/useRegisterNavigator.js.map +1 -0
  209. package/lib/module/useRoute.js +18 -0
  210. package/lib/module/useRoute.js.map +1 -0
  211. package/lib/module/useRouteCache.js +47 -0
  212. package/lib/module/useRouteCache.js.map +1 -0
  213. package/lib/module/useScheduleUpdate.js +29 -0
  214. package/lib/module/useScheduleUpdate.js.map +1 -0
  215. package/lib/module/useSyncState.js +64 -0
  216. package/lib/module/useSyncState.js.map +1 -0
  217. package/lib/module/validatePathConfig.js +24 -0
  218. package/lib/module/validatePathConfig.js.map +1 -0
  219. package/lib/typescript/src/BaseNavigationContainer.d.ts +14 -0
  220. package/lib/typescript/src/CurrentRenderContext.d.ts +9 -0
  221. package/lib/typescript/src/EnsureSingleNavigator.d.ts +13 -0
  222. package/lib/typescript/src/Group.d.ts +6 -0
  223. package/lib/typescript/src/NavigationBuilderContext.d.ts +34 -0
  224. package/lib/typescript/src/NavigationContainerRefContext.d.ts +8 -0
  225. package/lib/typescript/src/NavigationContext.d.ts +24 -0
  226. package/lib/typescript/src/NavigationHelpersContext.d.ts +9 -0
  227. package/lib/typescript/src/NavigationRouteContext.d.ts +7 -0
  228. package/lib/typescript/src/NavigationStateContext.d.ts +45 -0
  229. package/lib/typescript/src/SceneView.d.ts +21 -0
  230. package/lib/typescript/src/Screen.d.ts +6 -0
  231. package/lib/typescript/src/StaticContainer.d.ts +7 -0
  232. package/lib/typescript/src/UnhandledActionContext.d.ts +4 -0
  233. package/lib/typescript/src/checkDuplicateRouteNames.d.ts +2 -0
  234. package/lib/typescript/src/checkSerializable.d.ts +9 -0
  235. package/lib/typescript/src/createNavigationContainerRef.d.ts +3 -0
  236. package/lib/typescript/src/createNavigatorFactory.d.ts +11 -0
  237. package/lib/typescript/src/findFocusedRoute.d.ts +22 -0
  238. package/lib/typescript/src/fromEntries.d.ts +1 -0
  239. package/lib/typescript/src/getActionFromState.d.ts +16 -0
  240. package/lib/typescript/src/getFocusedRouteNameFromRoute.d.ts +2 -0
  241. package/lib/typescript/src/getPathFromState.d.ts +38 -0
  242. package/lib/typescript/src/getStateFromPath.d.ts +32 -0
  243. package/lib/typescript/src/index.d.ts +23 -0
  244. package/lib/typescript/src/isArrayEqual.d.ts +5 -0
  245. package/lib/typescript/src/types.d.ts +485 -0
  246. package/lib/typescript/src/useChildListeners.d.ts +11 -0
  247. package/lib/typescript/src/useComponent.d.ts +2 -0
  248. package/lib/typescript/src/useCurrentRender.d.ts +13 -0
  249. package/lib/typescript/src/useDescriptors.d.ts +89 -0
  250. package/lib/typescript/src/useEventEmitter.d.ts +8 -0
  251. package/lib/typescript/src/useFocusEffect.d.ts +10 -0
  252. package/lib/typescript/src/useFocusEvents.d.ts +12 -0
  253. package/lib/typescript/src/useFocusedListenersChildrenAdapter.d.ts +12 -0
  254. package/lib/typescript/src/useIsFocused.d.ts +5 -0
  255. package/lib/typescript/src/useKeyedChildListeners.d.ts +11 -0
  256. package/lib/typescript/src/useNavigation.d.ts +7 -0
  257. package/lib/typescript/src/useNavigationBuilder.d.ts +223 -0
  258. package/lib/typescript/src/useNavigationCache.d.ts +19 -0
  259. package/lib/typescript/src/useNavigationContainerRef.d.ts +2 -0
  260. package/lib/typescript/src/useNavigationHelpers.d.ts +174 -0
  261. package/lib/typescript/src/useNavigationState.d.ts +9 -0
  262. package/lib/typescript/src/useOnAction.d.ts +25 -0
  263. package/lib/typescript/src/useOnGetState.d.ts +8 -0
  264. package/lib/typescript/src/useOnPreventRemove.d.ts +16 -0
  265. package/lib/typescript/src/useOnRouteFocus.d.ts +14 -0
  266. package/lib/typescript/src/useOptionsGetters.d.ts +12 -0
  267. package/lib/typescript/src/useRegisterNavigator.d.ts +5 -0
  268. package/lib/typescript/src/useRoute.d.ts +8 -0
  269. package/lib/typescript/src/useRouteCache.d.ts +13 -0
  270. package/lib/typescript/src/useScheduleUpdate.d.ts +13 -0
  271. package/lib/typescript/src/useSyncState.d.ts +4 -0
  272. package/lib/typescript/src/validatePathConfig.d.ts +1 -0
  273. package/package.json +73 -0
  274. package/src/BaseNavigationContainer.tsx +453 -0
  275. package/src/CurrentRenderContext.tsx +10 -0
  276. package/src/EnsureSingleNavigator.tsx +53 -0
  277. package/src/Group.tsx +14 -0
  278. package/src/NavigationBuilderContext.tsx +70 -0
  279. package/src/NavigationContainerRefContext.tsx +14 -0
  280. package/src/NavigationContext.tsx +12 -0
  281. package/src/NavigationHelpersContext.tsx +13 -0
  282. package/src/NavigationRouteContext.tsx +10 -0
  283. package/src/NavigationStateContext.tsx +39 -0
  284. package/src/SceneView.tsx +134 -0
  285. package/src/Screen.tsx +17 -0
  286. package/src/StaticContainer.tsx +29 -0
  287. package/src/UnhandledActionContext.tsx +9 -0
  288. package/src/checkDuplicateRouteNames.tsx +33 -0
  289. package/src/checkSerializable.tsx +74 -0
  290. package/src/createNavigationContainerRef.tsx +97 -0
  291. package/src/createNavigatorFactory.tsx +40 -0
  292. package/src/findFocusedRoute.tsx +13 -0
  293. package/src/fromEntries.tsx +13 -0
  294. package/src/getActionFromState.tsx +154 -0
  295. package/src/getFocusedRouteNameFromRoute.tsx +28 -0
  296. package/src/getPathFromState.tsx +297 -0
  297. package/src/getStateFromPath.tsx +575 -0
  298. package/src/index.tsx +23 -0
  299. package/src/isArrayEqual.tsx +7 -0
  300. package/src/types.tsx +645 -0
  301. package/src/useChildListeners.tsx +37 -0
  302. package/src/useComponent.tsx +30 -0
  303. package/src/useCurrentRender.tsx +35 -0
  304. package/src/useDescriptors.tsx +229 -0
  305. package/src/useEventEmitter.tsx +130 -0
  306. package/src/useFocusEffect.tsx +112 -0
  307. package/src/useFocusEvents.tsx +73 -0
  308. package/src/useFocusedListenersChildrenAdapter.tsx +47 -0
  309. package/src/useIsFocused.tsx +43 -0
  310. package/src/useKeyedChildListeners.tsx +40 -0
  311. package/src/useNavigation.tsx +26 -0
  312. package/src/useNavigationBuilder.tsx +640 -0
  313. package/src/useNavigationCache.tsx +159 -0
  314. package/src/useNavigationContainerRef.tsx +17 -0
  315. package/src/useNavigationHelpers.tsx +98 -0
  316. package/src/useNavigationState.tsx +41 -0
  317. package/src/useOnAction.tsx +166 -0
  318. package/src/useOnGetState.tsx +47 -0
  319. package/src/useOnPreventRemove.tsx +99 -0
  320. package/src/useOnRouteFocus.tsx +47 -0
  321. package/src/useOptionsGetters.tsx +98 -0
  322. package/src/useRegisterNavigator.tsx +29 -0
  323. package/src/useRoute.tsx +22 -0
  324. package/src/useRouteCache.tsx +55 -0
  325. package/src/useScheduleUpdate.tsx +32 -0
  326. package/src/useSyncState.tsx +74 -0
  327. package/src/validatePathConfig.tsx +32 -0
@@ -0,0 +1,223 @@
1
+ import * as queryString from 'query-string';
2
+ import fromEntries from './fromEntries';
3
+ import validatePathConfig from './validatePathConfig';
4
+
5
+ const getActiveRoute = state => {
6
+ const route = typeof state.index === 'number' ? state.routes[state.index] : state.routes[state.routes.length - 1];
7
+
8
+ if (route.state) {
9
+ return getActiveRoute(route.state);
10
+ }
11
+
12
+ return route;
13
+ };
14
+ /**
15
+ * Utility to serialize a navigation state object to a path string.
16
+ *
17
+ * @example
18
+ * ```js
19
+ * getPathFromState(
20
+ * {
21
+ * routes: [
22
+ * {
23
+ * name: 'Chat',
24
+ * params: { author: 'Jane', id: 42 },
25
+ * },
26
+ * ],
27
+ * },
28
+ * {
29
+ * screens: {
30
+ * Chat: {
31
+ * path: 'chat/:author/:id',
32
+ * stringify: { author: author => author.toLowerCase() }
33
+ * }
34
+ * }
35
+ * }
36
+ * )
37
+ * ```
38
+ *
39
+ * @param state Navigation state to serialize.
40
+ * @param options Extra options to fine-tune how to serialize the path.
41
+ * @returns Path representing the state, e.g. /foo/bar?count=42.
42
+ */
43
+
44
+
45
+ export default function getPathFromState(state, options) {
46
+ if (state == null) {
47
+ throw Error("Got 'undefined' for the navigation state. You must pass a valid state object.");
48
+ }
49
+
50
+ if (options) {
51
+ validatePathConfig(options);
52
+ } // Create a normalized configs object which will be easier to use
53
+
54
+
55
+ const configs = options !== null && options !== void 0 && options.screens ? createNormalizedConfigs(options === null || options === void 0 ? void 0 : options.screens) : {};
56
+ let path = '/';
57
+ let current = state;
58
+ const allParams = {};
59
+
60
+ while (current) {
61
+ let index = typeof current.index === 'number' ? current.index : 0;
62
+ let route = current.routes[index];
63
+ let pattern;
64
+ let focusedParams;
65
+ let focusedRoute = getActiveRoute(state);
66
+ let currentOptions = configs; // Keep all the route names that appeared during going deeper in config in case the pattern is resolved to undefined
67
+
68
+ let nestedRouteNames = [];
69
+ let hasNext = true;
70
+
71
+ while (route.name in currentOptions && hasNext) {
72
+ pattern = currentOptions[route.name].pattern;
73
+ nestedRouteNames.push(route.name);
74
+
75
+ if (route.params) {
76
+ var _currentOptions$route;
77
+
78
+ const stringify = (_currentOptions$route = currentOptions[route.name]) === null || _currentOptions$route === void 0 ? void 0 : _currentOptions$route.stringify;
79
+ const currentParams = fromEntries(Object.entries(route.params).map(([key, value]) => [key, stringify !== null && stringify !== void 0 && stringify[key] ? stringify[key](value) : String(value)]));
80
+
81
+ if (pattern) {
82
+ Object.assign(allParams, currentParams);
83
+ }
84
+
85
+ if (focusedRoute === route) {
86
+ var _pattern;
87
+
88
+ // If this is the focused route, keep the params for later use
89
+ // We save it here since it's been stringified already
90
+ focusedParams = { ...currentParams
91
+ };
92
+ (_pattern = pattern) === null || _pattern === void 0 ? void 0 : _pattern.split('/').filter(p => p.startsWith(':')) // eslint-disable-next-line no-loop-func
93
+ .forEach(p => {
94
+ const name = getParamName(p); // Remove the params present in the pattern since we'll only use the rest for query string
95
+
96
+ if (focusedParams) {
97
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
98
+ delete focusedParams[name];
99
+ }
100
+ });
101
+ }
102
+ } // If there is no `screens` property or no nested state, we return pattern
103
+
104
+
105
+ if (!currentOptions[route.name].screens || route.state === undefined) {
106
+ hasNext = false;
107
+ } else {
108
+ index = typeof route.state.index === 'number' ? route.state.index : route.state.routes.length - 1;
109
+ const nextRoute = route.state.routes[index];
110
+ const nestedConfig = currentOptions[route.name].screens; // if there is config for next route name, we go deeper
111
+
112
+ if (nestedConfig && nextRoute.name in nestedConfig) {
113
+ route = nextRoute;
114
+ currentOptions = nestedConfig;
115
+ } else {
116
+ // If not, there is no sense in going deeper in config
117
+ hasNext = false;
118
+ }
119
+ }
120
+ }
121
+
122
+ if (pattern === undefined) {
123
+ pattern = nestedRouteNames.join('/');
124
+ }
125
+
126
+ if (currentOptions[route.name] !== undefined) {
127
+ path += pattern.split('/').map(p => {
128
+ const name = getParamName(p); // We don't know what to show for wildcard patterns
129
+ // Showing the route name seems ok, though whatever we show here will be incorrect
130
+ // Since the page doesn't actually exist
131
+
132
+ if (p === '*') {
133
+ return route.name;
134
+ } // If the path has a pattern for a param, put the param in the path
135
+
136
+
137
+ if (p.startsWith(':')) {
138
+ const value = allParams[name];
139
+
140
+ if (value === undefined && p.endsWith('?')) {
141
+ // Optional params without value assigned in route.params should be ignored
142
+ return '';
143
+ }
144
+
145
+ return encodeURIComponent(value);
146
+ }
147
+
148
+ return encodeURIComponent(p);
149
+ }).join('/');
150
+ } else {
151
+ path += encodeURIComponent(route.name);
152
+ }
153
+
154
+ if (!focusedParams) {
155
+ focusedParams = focusedRoute.params;
156
+ }
157
+
158
+ if (route.state) {
159
+ path += '/';
160
+ } else if (focusedParams) {
161
+ for (let param in focusedParams) {
162
+ if (focusedParams[param] === 'undefined') {
163
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
164
+ delete focusedParams[param];
165
+ }
166
+ }
167
+
168
+ const query = queryString.stringify(focusedParams, {
169
+ sort: false
170
+ });
171
+
172
+ if (query) {
173
+ path += `?${query}`;
174
+ }
175
+ }
176
+
177
+ current = route.state;
178
+ } // Remove multiple as well as trailing slashes
179
+
180
+
181
+ path = path.replace(/\/+/g, '/');
182
+ path = path.length > 1 ? path.replace(/\/$/, '') : path;
183
+ return path;
184
+ }
185
+
186
+ const getParamName = pattern => pattern.replace(/^:/, '').replace(/\?$/, '');
187
+
188
+ const joinPaths = (...paths) => [].concat(...paths.map(p => p.split('/'))).filter(Boolean).join('/');
189
+
190
+ const createConfigItem = (config, parentPattern) => {
191
+ var _pattern2;
192
+
193
+ if (typeof config === 'string') {
194
+ // If a string is specified as the value of the key(e.g. Foo: '/path'), use it as the pattern
195
+ const pattern = parentPattern ? joinPaths(parentPattern, config) : config;
196
+ return {
197
+ pattern
198
+ };
199
+ } // If an object is specified as the value (e.g. Foo: { ... }),
200
+ // It can have `path` property and `screens` prop which has nested configs
201
+
202
+
203
+ let pattern;
204
+
205
+ if (config.exact && config.path === undefined) {
206
+ throw new Error("A 'path' needs to be specified when specifying 'exact: true'. If you don't want this screen in the URL, specify it as empty string, e.g. `path: ''`.");
207
+ }
208
+
209
+ pattern = config.exact !== true ? joinPaths(parentPattern || '', config.path || '') : config.path || '';
210
+ const screens = config.screens ? createNormalizedConfigs(config.screens, pattern) : undefined;
211
+ return {
212
+ // Normalize pattern to remove any leading, trailing slashes, duplicate slashes etc.
213
+ pattern: (_pattern2 = pattern) === null || _pattern2 === void 0 ? void 0 : _pattern2.split('/').filter(Boolean).join('/'),
214
+ stringify: config.stringify,
215
+ screens
216
+ };
217
+ };
218
+
219
+ const createNormalizedConfigs = (options, pattern) => fromEntries(Object.entries(options).map(([name, c]) => {
220
+ const result = createConfigItem(c, pattern);
221
+ return [name, result];
222
+ }));
223
+ //# sourceMappingURL=getPathFromState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["getPathFromState.tsx"],"names":["queryString","fromEntries","validatePathConfig","getActiveRoute","state","route","index","routes","length","getPathFromState","options","Error","configs","screens","createNormalizedConfigs","path","current","allParams","pattern","focusedParams","focusedRoute","currentOptions","nestedRouteNames","hasNext","name","push","params","stringify","currentParams","Object","entries","map","key","value","String","assign","split","filter","p","startsWith","forEach","getParamName","undefined","nextRoute","nestedConfig","join","endsWith","encodeURIComponent","param","query","sort","replace","joinPaths","paths","concat","Boolean","createConfigItem","config","parentPattern","exact","c","result"],"mappings":"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","sourcesContent":["import type {\n NavigationState,\n PartialState,\n Route,\n} from '@react-navigation/routers';\nimport * as queryString from 'query-string';\n\nimport fromEntries from './fromEntries';\nimport type { PathConfig, PathConfigMap } from './types';\nimport validatePathConfig from './validatePathConfig';\n\ntype Options<ParamList> = {\n initialRouteName?: string;\n screens: PathConfigMap<ParamList>;\n};\n\ntype State = NavigationState | Omit<PartialState<NavigationState>, 'stale'>;\n\ntype StringifyConfig = Record<string, (value: any) => string>;\n\ntype ConfigItem = {\n pattern?: string;\n stringify?: StringifyConfig;\n screens?: Record<string, ConfigItem>;\n};\n\nconst getActiveRoute = (state: State): { name: string; params?: object } => {\n const route =\n typeof state.index === 'number'\n ? state.routes[state.index]\n : state.routes[state.routes.length - 1];\n\n if (route.state) {\n return getActiveRoute(route.state);\n }\n\n return route;\n};\n\n/**\n * Utility to serialize a navigation state object to a path string.\n *\n * @example\n * ```js\n * getPathFromState(\n * {\n * routes: [\n * {\n * name: 'Chat',\n * params: { author: 'Jane', id: 42 },\n * },\n * ],\n * },\n * {\n * screens: {\n * Chat: {\n * path: 'chat/:author/:id',\n * stringify: { author: author => author.toLowerCase() }\n * }\n * }\n * }\n * )\n * ```\n *\n * @param state Navigation state to serialize.\n * @param options Extra options to fine-tune how to serialize the path.\n * @returns Path representing the state, e.g. /foo/bar?count=42.\n */\nexport default function getPathFromState<ParamList extends {}>(\n state: State,\n options?: Options<ParamList>\n): string {\n if (state == null) {\n throw Error(\n \"Got 'undefined' for the navigation state. You must pass a valid state object.\"\n );\n }\n\n if (options) {\n validatePathConfig(options);\n }\n\n // Create a normalized configs object which will be easier to use\n const configs: Record<string, ConfigItem> = options?.screens\n ? createNormalizedConfigs(options?.screens)\n : {};\n\n let path = '/';\n let current: State | undefined = state;\n\n const allParams: Record<string, any> = {};\n\n while (current) {\n let index = typeof current.index === 'number' ? current.index : 0;\n let route = current.routes[index] as Route<string> & {\n state?: State;\n };\n\n let pattern: string | undefined;\n\n let focusedParams: Record<string, any> | undefined;\n let focusedRoute = getActiveRoute(state);\n let currentOptions = configs;\n\n // Keep all the route names that appeared during going deeper in config in case the pattern is resolved to undefined\n let nestedRouteNames = [];\n\n let hasNext = true;\n\n while (route.name in currentOptions && hasNext) {\n pattern = currentOptions[route.name].pattern;\n\n nestedRouteNames.push(route.name);\n\n if (route.params) {\n const stringify = currentOptions[route.name]?.stringify;\n\n const currentParams = fromEntries(\n Object.entries(route.params).map(([key, value]) => [\n key,\n stringify?.[key] ? stringify[key](value) : String(value),\n ])\n );\n\n if (pattern) {\n Object.assign(allParams, currentParams);\n }\n\n if (focusedRoute === route) {\n // If this is the focused route, keep the params for later use\n // We save it here since it's been stringified already\n focusedParams = { ...currentParams };\n\n pattern\n ?.split('/')\n .filter((p) => p.startsWith(':'))\n // eslint-disable-next-line no-loop-func\n .forEach((p) => {\n const name = getParamName(p);\n\n // Remove the params present in the pattern since we'll only use the rest for query string\n if (focusedParams) {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete focusedParams[name];\n }\n });\n }\n }\n\n // If there is no `screens` property or no nested state, we return pattern\n if (!currentOptions[route.name].screens || route.state === undefined) {\n hasNext = false;\n } else {\n index =\n typeof route.state.index === 'number'\n ? route.state.index\n : route.state.routes.length - 1;\n\n const nextRoute = route.state.routes[index];\n const nestedConfig = currentOptions[route.name].screens;\n\n // if there is config for next route name, we go deeper\n if (nestedConfig && nextRoute.name in nestedConfig) {\n route = nextRoute as Route<string> & { state?: State };\n currentOptions = nestedConfig;\n } else {\n // If not, there is no sense in going deeper in config\n hasNext = false;\n }\n }\n }\n\n if (pattern === undefined) {\n pattern = nestedRouteNames.join('/');\n }\n\n if (currentOptions[route.name] !== undefined) {\n path += pattern\n .split('/')\n .map((p) => {\n const name = getParamName(p);\n\n // We don't know what to show for wildcard patterns\n // Showing the route name seems ok, though whatever we show here will be incorrect\n // Since the page doesn't actually exist\n if (p === '*') {\n return route.name;\n }\n\n // If the path has a pattern for a param, put the param in the path\n if (p.startsWith(':')) {\n const value = allParams[name];\n\n if (value === undefined && p.endsWith('?')) {\n // Optional params without value assigned in route.params should be ignored\n return '';\n }\n\n return encodeURIComponent(value);\n }\n\n return encodeURIComponent(p);\n })\n .join('/');\n } else {\n path += encodeURIComponent(route.name);\n }\n\n if (!focusedParams) {\n focusedParams = focusedRoute.params;\n }\n\n if (route.state) {\n path += '/';\n } else if (focusedParams) {\n for (let param in focusedParams) {\n if (focusedParams[param] === 'undefined') {\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete focusedParams[param];\n }\n }\n\n const query = queryString.stringify(focusedParams, { sort: false });\n\n if (query) {\n path += `?${query}`;\n }\n }\n\n current = route.state;\n }\n\n // Remove multiple as well as trailing slashes\n path = path.replace(/\\/+/g, '/');\n path = path.length > 1 ? path.replace(/\\/$/, '') : path;\n\n return path;\n}\n\nconst getParamName = (pattern: string) =>\n pattern.replace(/^:/, '').replace(/\\?$/, '');\n\nconst joinPaths = (...paths: string[]): string =>\n ([] as string[])\n .concat(...paths.map((p) => p.split('/')))\n .filter(Boolean)\n .join('/');\n\nconst createConfigItem = (\n config: PathConfig<object> | string,\n parentPattern?: string\n): ConfigItem => {\n if (typeof config === 'string') {\n // If a string is specified as the value of the key(e.g. Foo: '/path'), use it as the pattern\n const pattern = parentPattern ? joinPaths(parentPattern, config) : config;\n\n return { pattern };\n }\n\n // If an object is specified as the value (e.g. Foo: { ... }),\n // It can have `path` property and `screens` prop which has nested configs\n let pattern: string | undefined;\n\n if (config.exact && config.path === undefined) {\n throw new Error(\n \"A 'path' needs to be specified when specifying 'exact: true'. If you don't want this screen in the URL, specify it as empty string, e.g. `path: ''`.\"\n );\n }\n\n pattern =\n config.exact !== true\n ? joinPaths(parentPattern || '', config.path || '')\n : config.path || '';\n\n const screens = config.screens\n ? createNormalizedConfigs(config.screens, pattern)\n : undefined;\n\n return {\n // Normalize pattern to remove any leading, trailing slashes, duplicate slashes etc.\n pattern: pattern?.split('/').filter(Boolean).join('/'),\n stringify: config.stringify,\n screens,\n };\n};\n\nconst createNormalizedConfigs = (\n options: PathConfigMap<object>,\n pattern?: string\n): Record<string, ConfigItem> =>\n fromEntries(\n Object.entries(options).map(([name, c]) => {\n const result = createConfigItem(c, pattern);\n\n return [name, result];\n })\n );\n"]}
@@ -0,0 +1,434 @@
1
+ import escape from 'escape-string-regexp';
2
+ import * as queryString from 'query-string';
3
+ import findFocusedRoute from './findFocusedRoute';
4
+ import validatePathConfig from './validatePathConfig';
5
+
6
+ /**
7
+ * Utility to parse a path string to initial state object accepted by the container.
8
+ * This is useful for deep linking when we need to handle the incoming URL.
9
+ *
10
+ * @example
11
+ * ```js
12
+ * getStateFromPath(
13
+ * '/chat/jane/42',
14
+ * {
15
+ * screens: {
16
+ * Chat: {
17
+ * path: 'chat/:author/:id',
18
+ * parse: { id: Number }
19
+ * }
20
+ * }
21
+ * }
22
+ * )
23
+ * ```
24
+ * @param path Path string to parse and convert, e.g. /foo/bar?count=42.
25
+ * @param options Extra options to fine-tune how to parse the path.
26
+ */
27
+ export default function getStateFromPath(path, options) {
28
+ if (options) {
29
+ validatePathConfig(options);
30
+ }
31
+
32
+ let initialRoutes = [];
33
+
34
+ if (options !== null && options !== void 0 && options.initialRouteName) {
35
+ initialRoutes.push({
36
+ initialRouteName: options.initialRouteName,
37
+ parentScreens: []
38
+ });
39
+ }
40
+
41
+ const screens = options === null || options === void 0 ? void 0 : options.screens;
42
+ let remaining = path.replace(/\/+/g, '/') // Replace multiple slash (//) with single ones
43
+ .replace(/^\//, '') // Remove extra leading slash
44
+ .replace(/\?.*$/, ''); // Remove query params which we will handle later
45
+ // Make sure there is a trailing slash
46
+
47
+ remaining = remaining.endsWith('/') ? remaining : `${remaining}/`;
48
+
49
+ if (screens === undefined) {
50
+ // When no config is specified, use the path segments as route names
51
+ const routes = remaining.split('/').filter(Boolean).map(segment => {
52
+ const name = decodeURIComponent(segment);
53
+ return {
54
+ name
55
+ };
56
+ });
57
+
58
+ if (routes.length) {
59
+ return createNestedStateObject(path, routes, initialRoutes);
60
+ }
61
+
62
+ return undefined;
63
+ } // Create a normalized configs array which will be easier to use
64
+
65
+
66
+ const configs = [].concat(...Object.keys(screens).map(key => createNormalizedConfigs(key, screens, [], initialRoutes, []))).sort((a, b) => {
67
+ // Sort config so that:
68
+ // - the most exhaustive ones are always at the beginning
69
+ // - patterns with wildcard are always at the end
70
+ // If 2 patterns are same, move the one with less route names up
71
+ // This is an error state, so it's only useful for consistent error messages
72
+ if (a.pattern === b.pattern) {
73
+ return b.routeNames.join('>').localeCompare(a.routeNames.join('>'));
74
+ } // If one of the patterns starts with the other, it's more exhaustive
75
+ // So move it up
76
+
77
+
78
+ if (a.pattern.startsWith(b.pattern)) {
79
+ return -1;
80
+ }
81
+
82
+ if (b.pattern.startsWith(a.pattern)) {
83
+ return 1;
84
+ }
85
+
86
+ const aParts = a.pattern.split('/');
87
+ const bParts = b.pattern.split('/');
88
+
89
+ for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
90
+ // if b is longer, b get higher priority
91
+ if (aParts[i] == null) {
92
+ return 1;
93
+ } // if a is longer, a get higher priority
94
+
95
+
96
+ if (bParts[i] == null) {
97
+ return -1;
98
+ }
99
+
100
+ const aWildCard = aParts[i] === '*' || aParts[i].startsWith(':');
101
+ const bWildCard = bParts[i] === '*' || bParts[i].startsWith(':'); // if both are wildcard we compare next component
102
+
103
+ if (aWildCard && bWildCard) {
104
+ continue;
105
+ } // if only a is wild card, b get higher priority
106
+
107
+
108
+ if (aWildCard) {
109
+ return 1;
110
+ } // if only b is wild card, a get higher priority
111
+
112
+
113
+ if (bWildCard) {
114
+ return -1;
115
+ }
116
+ }
117
+
118
+ return bParts.length - aParts.length;
119
+ }); // Check for duplicate patterns in the config
120
+
121
+ configs.reduce((acc, config) => {
122
+ if (acc[config.pattern]) {
123
+ const a = acc[config.pattern].routeNames;
124
+ const b = config.routeNames; // It's not a problem if the path string omitted from a inner most screen
125
+ // For example, it's ok if a path resolves to `A > B > C` or `A > B`
126
+
127
+ const intersects = a.length > b.length ? b.every((it, i) => a[i] === it) : a.every((it, i) => b[i] === it);
128
+
129
+ if (!intersects) {
130
+ throw new Error(`Found conflicting screens with the same pattern. The pattern '${config.pattern}' resolves to both '${a.join(' > ')}' and '${b.join(' > ')}'. Patterns must be unique and cannot resolve to more than one screen.`);
131
+ }
132
+ }
133
+
134
+ return Object.assign(acc, {
135
+ [config.pattern]: config
136
+ });
137
+ }, {});
138
+
139
+ if (remaining === '/') {
140
+ // We need to add special handling of empty path so navigation to empty path also works
141
+ // When handling empty path, we should only look at the root level config
142
+ const match = configs.find(config => config.path === '' && config.routeNames.every( // Make sure that none of the parent configs have a non-empty path defined
143
+ name => {
144
+ var _configs$find;
145
+
146
+ return !((_configs$find = configs.find(c => c.screen === name)) !== null && _configs$find !== void 0 && _configs$find.path);
147
+ }));
148
+
149
+ if (match) {
150
+ return createNestedStateObject(path, match.routeNames.map(name => ({
151
+ name
152
+ })), initialRoutes, configs);
153
+ }
154
+
155
+ return undefined;
156
+ }
157
+
158
+ let result;
159
+ let current; // We match the whole path against the regex instead of segments
160
+ // This makes sure matches such as wildcard will catch any unmatched routes, even if nested
161
+
162
+ const {
163
+ routes,
164
+ remainingPath
165
+ } = matchAgainstConfigs(remaining, configs.map(c => ({ ...c,
166
+ // Add `$` to the regex to make sure it matches till end of the path and not just beginning
167
+ regex: c.regex ? new RegExp(c.regex.source + '$') : undefined
168
+ })));
169
+
170
+ if (routes !== undefined) {
171
+ // This will always be empty if full path matched
172
+ current = createNestedStateObject(path, routes, initialRoutes, configs);
173
+ remaining = remainingPath;
174
+ result = current;
175
+ }
176
+
177
+ if (current == null || result == null) {
178
+ return undefined;
179
+ }
180
+
181
+ return result;
182
+ }
183
+
184
+ const joinPaths = (...paths) => [].concat(...paths.map(p => p.split('/'))).filter(Boolean).join('/');
185
+
186
+ const matchAgainstConfigs = (remaining, configs) => {
187
+ let routes;
188
+ let remainingPath = remaining; // Go through all configs, and see if the next path segment matches our regex
189
+
190
+ for (const config of configs) {
191
+ if (!config.regex) {
192
+ continue;
193
+ }
194
+
195
+ const match = remainingPath.match(config.regex); // If our regex matches, we need to extract params from the path
196
+
197
+ if (match) {
198
+ var _config$pattern;
199
+
200
+ const matchedParams = (_config$pattern = config.pattern) === null || _config$pattern === void 0 ? void 0 : _config$pattern.split('/').filter(p => p.startsWith(':')).reduce((acc, p, i) => Object.assign(acc, {
201
+ // The param segments appear every second item starting from 2 in the regex match result
202
+ [p]: match[(i + 1) * 2].replace(/\//, '')
203
+ }), {});
204
+ routes = config.routeNames.map(name => {
205
+ var _config$path;
206
+
207
+ const config = configs.find(c => c.screen === name);
208
+ const params = config === null || config === void 0 ? void 0 : (_config$path = config.path) === null || _config$path === void 0 ? void 0 : _config$path.split('/').filter(p => p.startsWith(':')).reduce((acc, p) => {
209
+ const value = matchedParams[p];
210
+
211
+ if (value) {
212
+ var _config$parse;
213
+
214
+ const key = p.replace(/^:/, '').replace(/\?$/, '');
215
+ acc[key] = (_config$parse = config.parse) !== null && _config$parse !== void 0 && _config$parse[key] ? config.parse[key](value) : value;
216
+ }
217
+
218
+ return acc;
219
+ }, {});
220
+
221
+ if (params && Object.keys(params).length) {
222
+ return {
223
+ name,
224
+ params
225
+ };
226
+ }
227
+
228
+ return {
229
+ name
230
+ };
231
+ });
232
+ remainingPath = remainingPath.replace(match[1], '');
233
+ break;
234
+ }
235
+ }
236
+
237
+ return {
238
+ routes,
239
+ remainingPath
240
+ };
241
+ };
242
+
243
+ const createNormalizedConfigs = (screen, routeConfig, routeNames = [], initials, parentScreens, parentPattern) => {
244
+ const configs = [];
245
+ routeNames.push(screen);
246
+ parentScreens.push(screen); // @ts-expect-error: we can't strongly typecheck this for now
247
+
248
+ const config = routeConfig[screen];
249
+
250
+ if (typeof config === 'string') {
251
+ // If a string is specified as the value of the key(e.g. Foo: '/path'), use it as the pattern
252
+ const pattern = parentPattern ? joinPaths(parentPattern, config) : config;
253
+ configs.push(createConfigItem(screen, routeNames, pattern, config));
254
+ } else if (typeof config === 'object') {
255
+ let pattern; // if an object is specified as the value (e.g. Foo: { ... }),
256
+ // it can have `path` property and
257
+ // it could have `screens` prop which has nested configs
258
+
259
+ if (typeof config.path === 'string') {
260
+ if (config.exact && config.path === undefined) {
261
+ throw new Error("A 'path' needs to be specified when specifying 'exact: true'. If you don't want this screen in the URL, specify it as empty string, e.g. `path: ''`.");
262
+ }
263
+
264
+ pattern = config.exact !== true ? joinPaths(parentPattern || '', config.path || '') : config.path || '';
265
+ configs.push(createConfigItem(screen, routeNames, pattern, config.path, config.parse));
266
+ }
267
+
268
+ if (config.screens) {
269
+ // property `initialRouteName` without `screens` has no purpose
270
+ if (config.initialRouteName) {
271
+ initials.push({
272
+ initialRouteName: config.initialRouteName,
273
+ parentScreens
274
+ });
275
+ }
276
+
277
+ Object.keys(config.screens).forEach(nestedConfig => {
278
+ var _pattern;
279
+
280
+ const result = createNormalizedConfigs(nestedConfig, config.screens, routeNames, initials, [...parentScreens], (_pattern = pattern) !== null && _pattern !== void 0 ? _pattern : parentPattern);
281
+ configs.push(...result);
282
+ });
283
+ }
284
+ }
285
+
286
+ routeNames.pop();
287
+ return configs;
288
+ };
289
+
290
+ const createConfigItem = (screen, routeNames, pattern, path, parse) => {
291
+ // Normalize pattern to remove any leading, trailing slashes, duplicate slashes etc.
292
+ pattern = pattern.split('/').filter(Boolean).join('/');
293
+ const regex = pattern ? new RegExp(`^(${pattern.split('/').map(it => {
294
+ if (it.startsWith(':')) {
295
+ return `(([^/]+\\/)${it.endsWith('?') ? '?' : ''})`;
296
+ }
297
+
298
+ return `${it === '*' ? '.*' : escape(it)}\\/`;
299
+ }).join('')})`) : undefined;
300
+ return {
301
+ screen,
302
+ regex,
303
+ pattern,
304
+ path,
305
+ // The routeNames array is mutated, so copy it to keep the current state
306
+ routeNames: [...routeNames],
307
+ parse
308
+ };
309
+ };
310
+
311
+ const findParseConfigForRoute = (routeName, flatConfig) => {
312
+ for (const config of flatConfig) {
313
+ if (routeName === config.routeNames[config.routeNames.length - 1]) {
314
+ return config.parse;
315
+ }
316
+ }
317
+
318
+ return undefined;
319
+ }; // Try to find an initial route connected with the one passed
320
+
321
+
322
+ const findInitialRoute = (routeName, parentScreens, initialRoutes) => {
323
+ for (const config of initialRoutes) {
324
+ if (parentScreens.length === config.parentScreens.length) {
325
+ let sameParents = true;
326
+
327
+ for (let i = 0; i < parentScreens.length; i++) {
328
+ if (parentScreens[i].localeCompare(config.parentScreens[i]) !== 0) {
329
+ sameParents = false;
330
+ break;
331
+ }
332
+ }
333
+
334
+ if (sameParents) {
335
+ return routeName !== config.initialRouteName ? config.initialRouteName : undefined;
336
+ }
337
+ }
338
+ }
339
+
340
+ return undefined;
341
+ }; // returns state object with values depending on whether
342
+ // it is the end of state and if there is initialRoute for this level
343
+
344
+
345
+ const createStateObject = (initialRoute, route, isEmpty) => {
346
+ if (isEmpty) {
347
+ if (initialRoute) {
348
+ return {
349
+ index: 1,
350
+ routes: [{
351
+ name: initialRoute
352
+ }, route]
353
+ };
354
+ } else {
355
+ return {
356
+ routes: [route]
357
+ };
358
+ }
359
+ } else {
360
+ if (initialRoute) {
361
+ return {
362
+ index: 1,
363
+ routes: [{
364
+ name: initialRoute
365
+ }, { ...route,
366
+ state: {
367
+ routes: []
368
+ }
369
+ }]
370
+ };
371
+ } else {
372
+ return {
373
+ routes: [{ ...route,
374
+ state: {
375
+ routes: []
376
+ }
377
+ }]
378
+ };
379
+ }
380
+ }
381
+ };
382
+
383
+ const createNestedStateObject = (path, routes, initialRoutes, flatConfig) => {
384
+ let state;
385
+ let route = routes.shift();
386
+ const parentScreens = [];
387
+ let initialRoute = findInitialRoute(route.name, parentScreens, initialRoutes);
388
+ parentScreens.push(route.name);
389
+ state = createStateObject(initialRoute, route, routes.length === 0);
390
+
391
+ if (routes.length > 0) {
392
+ let nestedState = state;
393
+
394
+ while (route = routes.shift()) {
395
+ initialRoute = findInitialRoute(route.name, parentScreens, initialRoutes);
396
+ const nestedStateIndex = nestedState.index || nestedState.routes.length - 1;
397
+ nestedState.routes[nestedStateIndex].state = createStateObject(initialRoute, route, routes.length === 0);
398
+
399
+ if (routes.length > 0) {
400
+ nestedState = nestedState.routes[nestedStateIndex].state;
401
+ }
402
+
403
+ parentScreens.push(route.name);
404
+ }
405
+ }
406
+
407
+ route = findFocusedRoute(state);
408
+ route.path = path;
409
+ const params = parseQueryParams(path, flatConfig ? findParseConfigForRoute(route.name, flatConfig) : undefined);
410
+
411
+ if (params) {
412
+ route.params = { ...route.params,
413
+ ...params
414
+ };
415
+ }
416
+
417
+ return state;
418
+ };
419
+
420
+ const parseQueryParams = (path, parseConfig) => {
421
+ const query = path.split('?')[1];
422
+ const params = queryString.parse(query);
423
+
424
+ if (parseConfig) {
425
+ Object.keys(params).forEach(name => {
426
+ if (parseConfig[name] && typeof params[name] === 'string') {
427
+ params[name] = parseConfig[name](params[name]);
428
+ }
429
+ });
430
+ }
431
+
432
+ return Object.keys(params).length ? params : undefined;
433
+ };
434
+ //# sourceMappingURL=getStateFromPath.js.map