@react-navigation/core 8.0.0-alpha.23 → 8.0.0-alpha.25
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/lib/module/BaseNavigationContainer.js +5 -2
- package/lib/module/BaseNavigationContainer.js.map +1 -1
- package/lib/module/DataLoading.js +102 -0
- package/lib/module/DataLoading.js.map +1 -0
- package/lib/module/NavigationBuilderContext.js.map +1 -1
- package/lib/module/NavigationIndependentTree.js +7 -6
- package/lib/module/NavigationIndependentTree.js.map +1 -1
- package/lib/module/NavigationProvider.js +12 -12
- package/lib/module/NavigationProvider.js.map +1 -1
- package/lib/module/PreventRemoveContext.js.map +1 -1
- package/lib/module/PreventRemoveProvider.js +34 -24
- package/lib/module/PreventRemoveProvider.js.map +1 -1
- package/lib/module/StaticNavigation.js +15 -7
- package/lib/module/StaticNavigation.js.map +1 -1
- package/lib/module/StaticTreeContext.js +5 -0
- package/lib/module/StaticTreeContext.js.map +1 -0
- package/lib/module/checkSerializable.js +7 -9
- package/lib/module/checkSerializable.js.map +1 -1
- package/lib/module/createNavigationContainerRef.js +6 -8
- package/lib/module/createNavigationContainerRef.js.map +1 -1
- package/lib/module/createNavigatorFactory.js.map +1 -1
- package/lib/module/getActionFromState.js +11 -11
- package/lib/module/getActionFromState.js.map +1 -1
- package/lib/module/getPathFromState.js +125 -96
- package/lib/module/getPathFromState.js.map +1 -1
- package/lib/module/getPatternParts.js +2 -2
- package/lib/module/getPatternParts.js.map +1 -1
- package/lib/module/getStateFromPath.js +136 -78
- package/lib/module/getStateFromPath.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +13 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/useEventEmitter.js +5 -2
- package/lib/module/useEventEmitter.js.map +1 -1
- package/lib/module/useKeyedChildListeners.js +4 -2
- package/lib/module/useKeyedChildListeners.js.map +1 -1
- package/lib/module/useNavigation.js +2 -15
- package/lib/module/useNavigation.js.map +1 -1
- package/lib/module/useNavigationBuilder.js +5 -21
- package/lib/module/useNavigationBuilder.js.map +1 -1
- package/lib/module/useNavigationCache.js +19 -14
- package/lib/module/useNavigationCache.js.map +1 -1
- package/lib/module/useNavigationHelpers.js +27 -9
- package/lib/module/useNavigationHelpers.js.map +1 -1
- package/lib/module/useNavigationState.js +69 -36
- package/lib/module/useNavigationState.js.map +1 -1
- package/lib/module/useOnAction.js +25 -3
- package/lib/module/useOnAction.js.map +1 -1
- package/lib/module/useOnPreventRemove.js +35 -24
- package/lib/module/useOnPreventRemove.js.map +1 -1
- package/lib/module/useOptionsGetters.js +3 -1
- package/lib/module/useOptionsGetters.js.map +1 -1
- package/lib/module/usePreventRemove.js +9 -2
- package/lib/module/usePreventRemove.js.map +1 -1
- package/lib/module/useRoute.js.map +1 -1
- package/lib/module/useRouteCache.js +14 -7
- package/lib/module/useRouteCache.js.map +1 -1
- package/lib/module/useScheduleUpdate.js +8 -8
- package/lib/module/useScheduleUpdate.js.map +1 -1
- package/lib/module/useSyncState.js +4 -1
- package/lib/module/useSyncState.js.map +1 -1
- package/lib/module/validatePathConfig.js +50 -37
- package/lib/module/validatePathConfig.js.map +1 -1
- package/lib/typescript/src/BaseNavigationContainer.d.ts.map +1 -1
- package/lib/typescript/src/DataLoading.d.ts +20 -0
- package/lib/typescript/src/DataLoading.d.ts.map +1 -0
- package/lib/typescript/src/NavigationBuilderContext.d.ts +2 -2
- package/lib/typescript/src/NavigationBuilderContext.d.ts.map +1 -1
- package/lib/typescript/src/NavigationProvider.d.ts +0 -1
- package/lib/typescript/src/NavigationProvider.d.ts.map +1 -1
- package/lib/typescript/src/PreventRemoveContext.d.ts +1 -0
- package/lib/typescript/src/PreventRemoveContext.d.ts.map +1 -1
- package/lib/typescript/src/PreventRemoveProvider.d.ts.map +1 -1
- package/lib/typescript/src/StaticNavigation.d.ts +68 -42
- package/lib/typescript/src/StaticNavigation.d.ts.map +1 -1
- package/lib/typescript/src/StaticTreeContext.d.ts +4 -0
- package/lib/typescript/src/StaticTreeContext.d.ts.map +1 -0
- package/lib/typescript/src/checkSerializable.d.ts +4 -2
- package/lib/typescript/src/checkSerializable.d.ts.map +1 -1
- package/lib/typescript/src/createNavigationContainerRef.d.ts.map +1 -1
- package/lib/typescript/src/createNavigatorFactory.d.ts +11 -5
- package/lib/typescript/src/createNavigatorFactory.d.ts.map +1 -1
- package/lib/typescript/src/getActionFromState.d.ts.map +1 -1
- package/lib/typescript/src/getPathFromState.d.ts.map +1 -1
- package/lib/typescript/src/getStateFromPath.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +84 -29
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/useEventEmitter.d.ts +1 -1
- package/lib/typescript/src/useEventEmitter.d.ts.map +1 -1
- package/lib/typescript/src/useKeyedChildListeners.d.ts.map +1 -1
- package/lib/typescript/src/useNavigation.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts +1 -1
- package/lib/typescript/src/useNavigationBuilder.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationCache.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationHelpers.d.ts +3 -4
- package/lib/typescript/src/useNavigationHelpers.d.ts.map +1 -1
- package/lib/typescript/src/useNavigationState.d.ts +11 -1
- package/lib/typescript/src/useNavigationState.d.ts.map +1 -1
- package/lib/typescript/src/useOnAction.d.ts.map +1 -1
- package/lib/typescript/src/useOnPreventRemove.d.ts +2 -6
- package/lib/typescript/src/useOnPreventRemove.d.ts.map +1 -1
- package/lib/typescript/src/useOptionsGetters.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemove.d.ts.map +1 -1
- package/lib/typescript/src/usePreventRemoveContext.d.ts +1 -0
- package/lib/typescript/src/usePreventRemoveContext.d.ts.map +1 -1
- package/lib/typescript/src/useRoute.d.ts +1 -1
- package/lib/typescript/src/useRoute.d.ts.map +1 -1
- package/lib/typescript/src/useRouteCache.d.ts.map +1 -1
- package/lib/typescript/src/useScheduleUpdate.d.ts +5 -4
- package/lib/typescript/src/useScheduleUpdate.d.ts.map +1 -1
- package/lib/typescript/src/useSyncState.d.ts.map +1 -1
- package/lib/typescript/src/utilities.d.ts +21 -38
- package/lib/typescript/src/utilities.d.ts.map +1 -1
- package/lib/typescript/src/validatePathConfig.d.ts.map +1 -1
- package/package.json +6 -8
- package/src/BaseNavigationContainer.tsx +9 -2
- package/src/DataLoading.tsx +139 -0
- package/src/NavigationBuilderContext.tsx +5 -1
- package/src/NavigationIndependentTree.tsx +11 -11
- package/src/NavigationProvider.tsx +13 -16
- package/src/PreventRemoveContext.tsx +1 -0
- package/src/PreventRemoveProvider.tsx +48 -43
- package/src/StaticNavigation.tsx +164 -99
- package/src/StaticTreeContext.tsx +7 -0
- package/src/checkSerializable.tsx +20 -14
- package/src/createNavigationContainerRef.tsx +12 -9
- package/src/createNavigatorFactory.tsx +27 -18
- package/src/getActionFromState.tsx +18 -16
- package/src/getPathFromState.tsx +167 -132
- package/src/getPatternParts.tsx +2 -2
- package/src/getStateFromPath.tsx +260 -193
- package/src/index.tsx +3 -0
- package/src/types.tsx +298 -62
- package/src/useEventEmitter.tsx +7 -2
- package/src/useKeyedChildListeners.tsx +4 -2
- package/src/useNavigation.tsx +2 -21
- package/src/useNavigationBuilder.tsx +7 -24
- package/src/useNavigationCache.tsx +26 -19
- package/src/useNavigationHelpers.tsx +26 -9
- package/src/useNavigationState.tsx +90 -60
- package/src/useOnAction.tsx +55 -3
- package/src/useOnPreventRemove.tsx +68 -36
- package/src/useOptionsGetters.tsx +4 -1
- package/src/usePreventRemove.tsx +11 -2
- package/src/useRoute.tsx +3 -5
- package/src/useRouteCache.tsx +19 -11
- package/src/useScheduleUpdate.tsx +8 -7
- package/src/useSyncState.tsx +5 -1
- package/src/utilities.tsx +36 -41
- package/src/validatePathConfig.tsx +86 -58
|
@@ -31,8 +31,11 @@ export function useOptionsGetters({ key, options, navigation }: Options) {
|
|
|
31
31
|
}
|
|
32
32
|
}, [navigation, onOptionsChange]);
|
|
33
33
|
|
|
34
|
-
React.
|
|
34
|
+
React.useInsertionEffect(() => {
|
|
35
35
|
optionsRef.current = options;
|
|
36
|
+
}, [options]);
|
|
37
|
+
|
|
38
|
+
React.useEffect(() => {
|
|
36
39
|
optionsChangeListener();
|
|
37
40
|
|
|
38
41
|
return navigation?.addListener('focus', optionsChangeListener);
|
package/src/usePreventRemove.tsx
CHANGED
|
@@ -23,15 +23,24 @@ export function usePreventRemove(
|
|
|
23
23
|
const navigation = useNavigation();
|
|
24
24
|
const { key: routeKey } = useRoute();
|
|
25
25
|
|
|
26
|
-
const { setPreventRemove } = usePreventRemoveContext();
|
|
26
|
+
const { setPreventRemove, notifyPreventRemove } = usePreventRemoveContext();
|
|
27
27
|
|
|
28
|
-
React.
|
|
28
|
+
React.useInsertionEffect(() => {
|
|
29
29
|
setPreventRemove(id, routeKey, preventRemove);
|
|
30
|
+
|
|
30
31
|
return () => {
|
|
31
32
|
setPreventRemove(id, routeKey, false);
|
|
32
33
|
};
|
|
33
34
|
}, [setPreventRemove, id, routeKey, preventRemove]);
|
|
34
35
|
|
|
36
|
+
React.useEffect(() => {
|
|
37
|
+
notifyPreventRemove();
|
|
38
|
+
|
|
39
|
+
return () => {
|
|
40
|
+
notifyPreventRemove();
|
|
41
|
+
};
|
|
42
|
+
}, [id, routeKey, preventRemove, notifyPreventRemove]);
|
|
43
|
+
|
|
35
44
|
const beforeRemoveListener = useLatestCallback<
|
|
36
45
|
EventListenerCallback<EventMapCore<any>, 'beforeRemove'>
|
|
37
46
|
>((e) => {
|
package/src/useRoute.tsx
CHANGED
|
@@ -22,11 +22,9 @@ type AllRouteNames<ParamList extends {}> =
|
|
|
22
22
|
| KeyOf<ParamList>
|
|
23
23
|
| AllNestedRouteNames<NestedParamLists<ParamList>>;
|
|
24
24
|
|
|
25
|
-
type AllNestedRouteNames<ParamLists> =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
? AllRouteNames<ParamList>
|
|
29
|
-
: never;
|
|
25
|
+
type AllNestedRouteNames<ParamLists> = ParamLists extends {}
|
|
26
|
+
? AllRouteNames<ParamLists>
|
|
27
|
+
: never;
|
|
30
28
|
|
|
31
29
|
/**
|
|
32
30
|
* Hook to access the route prop of the parent screen anywhere.
|
package/src/useRouteCache.tsx
CHANGED
|
@@ -4,8 +4,6 @@ import * as React from 'react';
|
|
|
4
4
|
import { isRecordEqual } from './isRecordEqual';
|
|
5
5
|
import type { RouteProp } from './types';
|
|
6
6
|
|
|
7
|
-
type RouteCache = Map<string, RouteProp<ParamListBase>>;
|
|
8
|
-
|
|
9
7
|
/**
|
|
10
8
|
* Utilities such as `getFocusedRouteNameFromRoute` need to access state.
|
|
11
9
|
* So we need a way to suppress the warning for those use cases.
|
|
@@ -21,9 +19,12 @@ export function useRouteCache<State extends NavigationState>(
|
|
|
21
19
|
routes: State['routes']
|
|
22
20
|
) {
|
|
23
21
|
// Cache object which holds route objects for each screen
|
|
24
|
-
const cache = React.useMemo(
|
|
22
|
+
const cache = React.useMemo(
|
|
23
|
+
() => ({ current: new Map<string, RouteProp<ParamListBase>>() }),
|
|
24
|
+
[]
|
|
25
|
+
);
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
const next = routes.reduce((acc, route) => {
|
|
27
28
|
const previous = cache.current.get(route.key);
|
|
28
29
|
const { state, ...routeWithoutState } = route;
|
|
29
30
|
|
|
@@ -53,16 +54,23 @@ export function useRouteCache<State extends NavigationState>(
|
|
|
53
54
|
}
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
// @ts-expect-error: this isn't in type definitions coz we want this private
|
|
58
|
+
if (proxy[CHILD_STATE] !== state) {
|
|
59
|
+
Object.defineProperty(proxy, CHILD_STATE, {
|
|
60
|
+
enumerable: false,
|
|
61
|
+
configurable: true,
|
|
62
|
+
value: state,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
61
65
|
|
|
62
66
|
acc.set(route.key, proxy);
|
|
63
67
|
|
|
64
68
|
return acc;
|
|
65
|
-
}, new Map()
|
|
69
|
+
}, new Map<string, RouteProp<ParamListBase>>());
|
|
70
|
+
|
|
71
|
+
React.useInsertionEffect(() => {
|
|
72
|
+
cache.current = next;
|
|
73
|
+
});
|
|
66
74
|
|
|
67
|
-
return Array.from(
|
|
75
|
+
return Array.from(next.values());
|
|
68
76
|
}
|
|
@@ -4,17 +4,18 @@ import { NavigationBuilderContext } from './NavigationBuilderContext';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* When screen config changes, we want to update the navigator in the same update phase.
|
|
7
|
-
* However, navigation state is in the root component and React won't let us update it from a child.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* However, navigation state is in the root component and React won't let us update it from a child during render.
|
|
8
|
+
* The render could also be interrupted in concurrent mode, so we need to update after commit.
|
|
9
|
+
* So we queue the update in an insertion effect and flush it in a layout effect.
|
|
10
|
+
* Insertion effects run before layout effects, so every navigator in the tree has queued its update before we flush.
|
|
11
|
+
* This lets nested updates be applied from the root down without clobbering each other.
|
|
11
12
|
*/
|
|
12
13
|
export function useScheduleUpdate(callback: () => void) {
|
|
13
14
|
const { scheduleUpdate, flushUpdates } = React.use(NavigationBuilderContext);
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
React.useInsertionEffect(() => {
|
|
17
|
+
scheduleUpdate(callback);
|
|
18
|
+
});
|
|
18
19
|
|
|
19
20
|
React.useLayoutEffect(flushUpdates);
|
|
20
21
|
}
|
package/src/useSyncState.tsx
CHANGED
|
@@ -100,7 +100,11 @@ export function useSyncState<T>(getInitialState: () => T) {
|
|
|
100
100
|
|
|
101
101
|
if (pendingUpdates.length !== 0) {
|
|
102
102
|
store.batchUpdates(() => {
|
|
103
|
-
//
|
|
103
|
+
// Updates are queued child-first as insertion effects run bottom-up.
|
|
104
|
+
// The root navigator replaces the whole state while nested navigators merge into it.
|
|
105
|
+
// So we apply them root-first to avoid the root clobbering nested updates.
|
|
106
|
+
pendingUpdates.reverse();
|
|
107
|
+
|
|
104
108
|
for (const update of pendingUpdates) {
|
|
105
109
|
update();
|
|
106
110
|
}
|
package/src/utilities.tsx
CHANGED
|
@@ -15,6 +15,17 @@ export type KeysOf<T> = T extends {} ? keyof T : never;
|
|
|
15
15
|
*/
|
|
16
16
|
export type KeyOf<T extends {}> = Extract<keyof T, string>;
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* TS only checks object literals for excess properties when they are not generic.
|
|
20
|
+
* When an object is captured as a generic type, unknown keys are not caught.
|
|
21
|
+
* This builds a type from the provided object where any key not in the allowed type has the type `never`.
|
|
22
|
+
* Checking the provided object against this type then produces an error for each unknown key.
|
|
23
|
+
*/
|
|
24
|
+
export type NoExcessObject<Provided, Allowed> = Record<
|
|
25
|
+
Exclude<keyof Provided, keyof Allowed>,
|
|
26
|
+
never
|
|
27
|
+
>;
|
|
28
|
+
|
|
18
29
|
/**
|
|
19
30
|
* We get a union type when using keyof, but we want an intersection instead.
|
|
20
31
|
* https://stackoverflow.com/a/50375286/1665026
|
|
@@ -25,8 +36,6 @@ export type UnionToIntersection<U> = (
|
|
|
25
36
|
? I
|
|
26
37
|
: never;
|
|
27
38
|
|
|
28
|
-
export type UnknownToUndefined<T> = unknown extends T ? undefined : T;
|
|
29
|
-
|
|
30
39
|
/**
|
|
31
40
|
* Exclude undefined from a type.
|
|
32
41
|
* Similar to NonNullable but only excludes undefined, not null.
|
|
@@ -39,6 +48,23 @@ export type RequiredKeys<T extends object> = {
|
|
|
39
48
|
[K in keyof T]-?: {} extends Pick<T, K> ? never : K;
|
|
40
49
|
}[keyof T];
|
|
41
50
|
|
|
51
|
+
type OptionalKeys<T extends object> = Exclude<keyof T, RequiredKeys<T>>;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Remove `| undefined` from the object type,
|
|
55
|
+
* and adjust the optionality of the keys based on the original type.
|
|
56
|
+
*/
|
|
57
|
+
export type NotUndefinedObject<
|
|
58
|
+
T extends object | undefined,
|
|
59
|
+
O extends object = NotUndefined<T>,
|
|
60
|
+
> = undefined extends T
|
|
61
|
+
? {
|
|
62
|
+
[K in RequiredKeys<O>]: O[K];
|
|
63
|
+
} & {
|
|
64
|
+
[K in OptionalKeys<O>]?: O[K] | undefined;
|
|
65
|
+
}
|
|
66
|
+
: T;
|
|
67
|
+
|
|
42
68
|
export type UndefinedIfAllOptional<T> = T extends object
|
|
43
69
|
? RequiredKeys<T> extends never
|
|
44
70
|
? T | undefined
|
|
@@ -173,46 +199,15 @@ type QueryParamRequiredKeys<Params, Parse> = Exclude<
|
|
|
173
199
|
QueryParamOptionalKeys<Params, Parse>
|
|
174
200
|
>;
|
|
175
201
|
|
|
176
|
-
/**
|
|
177
|
-
* Infer the path string from a linking config.
|
|
178
|
-
*/
|
|
179
|
-
export type InferPath<T> = T extends { path: infer P extends string }
|
|
180
|
-
? P
|
|
181
|
-
: never;
|
|
182
|
-
|
|
183
|
-
/**
|
|
184
|
-
* Infer the parse functions from a linking config.
|
|
185
|
-
*/
|
|
186
|
-
export type InferParse<T> = T extends { parse: infer P } ? P : {};
|
|
187
|
-
|
|
188
202
|
export type InferParamsFromLinking<T> = T extends {
|
|
189
203
|
path: infer P extends string;
|
|
204
|
+
parse: infer Parse;
|
|
190
205
|
}
|
|
191
|
-
? UndefinedIfAllOptional<
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
? UndefinedIfAllOptional<
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
: undefined;
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Infer the params type from a screen component or nested navigator.
|
|
202
|
-
*/
|
|
203
|
-
export type InferScreenParams<T> =
|
|
204
|
-
T extends React.ComponentType<{ route: { params: infer P } }>
|
|
205
|
-
? P
|
|
206
|
-
: T extends { config: { screens: infer Screens } }
|
|
207
|
-
? import('./types').NavigatorScreenParams<{
|
|
208
|
-
[K in keyof Screens]: Screens[K] extends React.ComponentType<{
|
|
209
|
-
route: { params: infer P };
|
|
210
|
-
}>
|
|
211
|
-
? P
|
|
212
|
-
: Screens[K] extends { screen: infer S }
|
|
213
|
-
? S extends React.ComponentType<{ route: { params: infer P } }>
|
|
214
|
-
? P
|
|
215
|
-
: undefined
|
|
216
|
-
: undefined;
|
|
217
|
-
}>
|
|
206
|
+
? UndefinedIfAllOptional<ExtractParamsType<ExtractParamStrings<P>, Parse>>
|
|
207
|
+
: T extends {
|
|
208
|
+
path: infer P extends string;
|
|
209
|
+
}
|
|
210
|
+
? UndefinedIfAllOptional<ExtractParamStrings<P>>
|
|
211
|
+
: T extends string
|
|
212
|
+
? UndefinedIfAllOptional<ExtractParamStrings<T>>
|
|
218
213
|
: undefined;
|
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
const
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
const ROOT_VALIDATION_LIST = [
|
|
2
|
+
'- path (string)',
|
|
3
|
+
'- initialRouteName (string)',
|
|
4
|
+
'- screens (object)',
|
|
5
|
+
].join('\n');
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
7
|
+
const NESTED_VALIDATION_LIST = [
|
|
8
|
+
ROOT_VALIDATION_LIST,
|
|
9
|
+
'- alias (array)',
|
|
10
|
+
'- exact (boolean)',
|
|
11
|
+
'- stringify (object)',
|
|
12
|
+
'- parse (object)',
|
|
13
|
+
'- shared (boolean)',
|
|
14
|
+
].join('\n');
|
|
15
|
+
|
|
16
|
+
const getValidationType = (key: string, root: boolean) => {
|
|
17
|
+
switch (key) {
|
|
18
|
+
case 'path':
|
|
19
|
+
case 'initialRouteName':
|
|
20
|
+
return 'string';
|
|
21
|
+
case 'screens':
|
|
22
|
+
return 'object';
|
|
23
|
+
case 'alias':
|
|
24
|
+
return root ? undefined : 'array';
|
|
25
|
+
case 'exact':
|
|
26
|
+
case 'shared':
|
|
27
|
+
return root ? undefined : 'boolean';
|
|
28
|
+
case 'stringify':
|
|
29
|
+
case 'parse':
|
|
30
|
+
return root ? undefined : 'object';
|
|
31
|
+
default:
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
21
35
|
|
|
36
|
+
export function validatePathConfig(config: unknown, root = true) {
|
|
22
37
|
if (typeof config !== 'object' || config === null) {
|
|
23
38
|
throw new Error(
|
|
24
39
|
`Expected the configuration to be an object, but got ${JSON.stringify(
|
|
@@ -27,58 +42,71 @@ export function validatePathConfig(config: unknown, root = true) {
|
|
|
27
42
|
);
|
|
28
43
|
}
|
|
29
44
|
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
45
|
+
const pathConfig = config as Record<string, unknown>;
|
|
46
|
+
|
|
47
|
+
let validationErrors: string[] | undefined;
|
|
48
|
+
|
|
49
|
+
for (const key in pathConfig) {
|
|
50
|
+
const type = getValidationType(key, root);
|
|
51
|
+
|
|
52
|
+
if (type === undefined) {
|
|
53
|
+
(validationErrors ??= []).push(`- ${key} (extraneous)`);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const value = pathConfig[key];
|
|
58
|
+
|
|
59
|
+
if (value === undefined) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (type === 'array') {
|
|
64
|
+
if (!Array.isArray(value)) {
|
|
65
|
+
(validationErrors ??= []).push(
|
|
66
|
+
`- ${key} (expected 'Array', got '${typeof value}')`
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
} else if (typeof value !== type) {
|
|
70
|
+
(validationErrors ??= []).push(
|
|
71
|
+
`- ${key} (expected '${type}', got '${typeof value}')`
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (validationErrors) {
|
|
57
77
|
throw new Error(
|
|
58
|
-
`Found invalid properties in the configuration:\n${
|
|
59
|
-
|
|
60
|
-
)}\n\nYou can only specify the following properties:\n${
|
|
61
|
-
|
|
62
|
-
|
|
78
|
+
`Found invalid properties in the configuration:\n${validationErrors.join(
|
|
79
|
+
'\n'
|
|
80
|
+
)}\n\nYou can only specify the following properties:\n${
|
|
81
|
+
root ? ROOT_VALIDATION_LIST : NESTED_VALIDATION_LIST
|
|
82
|
+
}\n\nIf you want to specify configuration for screens, you need to specify them under a 'screens' property.\n\nSee https://reactnavigation.org/docs/configuring-links for more details on how to specify a linking configuration.`
|
|
63
83
|
);
|
|
64
84
|
}
|
|
65
85
|
|
|
86
|
+
const path = pathConfig.path;
|
|
87
|
+
|
|
66
88
|
if (
|
|
67
89
|
root &&
|
|
68
|
-
'path' in
|
|
69
|
-
typeof
|
|
70
|
-
|
|
90
|
+
'path' in pathConfig &&
|
|
91
|
+
typeof path === 'string' &&
|
|
92
|
+
path.includes(':')
|
|
71
93
|
) {
|
|
72
94
|
throw new Error(
|
|
73
|
-
`Found invalid path '${
|
|
95
|
+
`Found invalid path '${path}'. The 'path' in the top-level configuration cannot contain patterns for params.`
|
|
74
96
|
);
|
|
75
97
|
}
|
|
76
98
|
|
|
77
|
-
|
|
78
|
-
|
|
99
|
+
const screens = pathConfig.screens;
|
|
100
|
+
|
|
101
|
+
if (screens && typeof screens === 'object') {
|
|
102
|
+
const screenConfig = screens as Record<string, unknown>;
|
|
103
|
+
|
|
104
|
+
for (const name in screenConfig) {
|
|
105
|
+
const value = screenConfig[name];
|
|
106
|
+
|
|
79
107
|
if (typeof value !== 'string') {
|
|
80
108
|
validatePathConfig(value, false);
|
|
81
109
|
}
|
|
82
|
-
}
|
|
110
|
+
}
|
|
83
111
|
}
|
|
84
112
|
}
|