expo-router 1.4.2 → 1.4.3
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/build/loadStaticParamsAsync.d.ts.map +1 -1
- package/build/static/renderStaticContent.d.ts.map +1 -1
- package/build/static/useServerState.d.ts.map +1 -1
- package/build/views/Screen.d.ts.map +1 -1
- package/build/views/Unmatched.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/loadStaticParamsAsync.ts +51 -24
- package/src/static/renderStaticContent.tsx +5 -1
- package/src/static/useServerState.ts +4 -1
- package/src/views/Screen.tsx +4 -1
- package/src/views/Unmatched.tsx +17 -3
- package/src/__tests__/LocationProvider.test.node.ts +0 -55
- package/src/__tests__/Route.test.node.ts +0 -70
- package/src/__tests__/getReactNavigationConfig.test.node.ts +0 -138
- package/src/__tests__/getRoutes.test.node.ts +0 -486
- package/src/__tests__/loadStaticParamsAsync.test.node.ts +0 -413
- package/src/__tests__/matchers.test.node.ts +0 -59
- package/src/__tests__/useNavigation.test.node.ts +0 -24
- package/src/__tests__/useScreens.test.node.tsx +0 -66
- package/src/fork/__tests__/__snapshots__/extractPathFromURL.test.ios.ts.snap +0 -97
- package/src/fork/__tests__/extractPathFromURL.test.ios.ts +0 -76
- package/src/fork/__tests__/getPathFromState-upstream.test.node.ts +0 -1981
- package/src/fork/__tests__/getStateFromPath-upstream.test.node.ts +0 -2570
- package/src/fork/__tests__/getStateFromPath.test.node.ts +0 -131
- package/src/link/__tests__/href.test.node.ts +0 -57
- package/src/link/__tests__/stateOperations.test.node.ts +0 -373
- package/src/link/__tests__/useLinkToPath.test.node.ts +0 -53
- package/src/utils/__tests__/mockState.test.node.ts +0 -119
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loadStaticParamsAsync.d.ts","sourceRoot":"","sources":["../src/loadStaticParamsAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"loadStaticParamsAsync.d.ts","sourceRoot":"","sources":["../src/loadStaticParamsAsync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,SAAS,EAAE,MAAM,SAAS,CAAC;AAW5D,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,SAAS,GACf,OAAO,CAAC,SAAS,CAAC,CAWpB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderStaticContent.d.ts","sourceRoot":"","sources":["../../src/static/renderStaticContent.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"renderStaticContent.d.ts","sourceRoot":"","sources":["../../src/static/renderStaticContent.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,OAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAUtD,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,GAAG,GAAG,MAAM,CA6CtD;AA0BD,OAAO,EAAE,WAAW,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useServerState.d.ts","sourceRoot":"","sources":["../../src/static/useServerState.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useServerState.d.ts","sourceRoot":"","sources":["../../src/static/useServerState.ts"],"names":[],"mappings":"AAiCA,wBAAgB,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;eAO7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Screen.d.ts","sourceRoot":"","sources":["../../src/views/Screen.tsx"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,CACrB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IACxD;IACF;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,aAAa,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IACvC,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC;
|
|
1
|
+
{"version":3,"file":"Screen.d.ts","sourceRoot":"","sources":["../../src/views/Screen.tsx"],"names":[],"mappings":"AAIA,MAAM,MAAM,WAAW,CACrB,QAAQ,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IACxD;IACF;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,aAAa,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;KAAE,CAAC;IACvC,OAAO,CAAC,EAAE,QAAQ,CAAC;CACpB,CAAC;AAKF,sEAAsE;AACtE,wBAAgB,MAAM,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,EAAE,EACvD,IAAI,EACJ,QAAQ,EACR,OAAO,GACR,EAAE,WAAW,CAAC,QAAQ,CAAC,QAmBvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Unmatched.d.ts","sourceRoot":"","sources":["../../src/views/Unmatched.tsx"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"Unmatched.d.ts","sourceRoot":"","sources":["../../src/views/Unmatched.tsx"],"names":[],"mappings":";AAYA,2CAA2C;AAC3C,wBAAgB,SAAS,gBAkDxB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-router",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.3",
|
|
4
4
|
"main": "src/index.tsx",
|
|
5
5
|
"types": "build/index.d.ts",
|
|
6
6
|
"files": [
|
|
@@ -19,7 +19,8 @@
|
|
|
19
19
|
"src",
|
|
20
20
|
"stack.ts",
|
|
21
21
|
"tabs.ts",
|
|
22
|
-
"types"
|
|
22
|
+
"types",
|
|
23
|
+
"!**/__tests__"
|
|
23
24
|
],
|
|
24
25
|
"repository": {
|
|
25
26
|
"url": "https://github.com/expo/router.git",
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
"expo-constants": "*",
|
|
57
58
|
"expo-linking": "*",
|
|
58
59
|
"expo-status-bar": "*",
|
|
59
|
-
"metro": "~0.
|
|
60
|
+
"metro": "~0.76.0",
|
|
60
61
|
"react-native-gesture-handler": "*",
|
|
61
62
|
"react-native-reanimated": "*",
|
|
62
63
|
"react-native-safe-area-context": "*",
|
|
@@ -91,7 +92,7 @@
|
|
|
91
92
|
},
|
|
92
93
|
"dependencies": {
|
|
93
94
|
"@bacons/react-views": "^1.1.3",
|
|
94
|
-
"@expo/metro-runtime": "2.0.
|
|
95
|
+
"@expo/metro-runtime": "2.0.3",
|
|
95
96
|
"@radix-ui/react-slot": "^1.0.0",
|
|
96
97
|
"@react-navigation/bottom-tabs": "~6.5.7",
|
|
97
98
|
"@react-navigation/native": "~6.1.6",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RouteNode } from "./Route";
|
|
1
|
+
import type { DynamicConvention, RouteNode } from "./Route";
|
|
2
2
|
|
|
3
3
|
async function recurseAndFlattenNodes<
|
|
4
4
|
T,
|
|
@@ -24,7 +24,10 @@ export async function loadStaticParamsAsync(
|
|
|
24
24
|
return route;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
function assertStaticParams(
|
|
27
|
+
function assertStaticParams(
|
|
28
|
+
route: RouteNode,
|
|
29
|
+
params: Record<string, string | string[]>
|
|
30
|
+
) {
|
|
28
31
|
const matches = route.dynamic!.every((dynamic) => {
|
|
29
32
|
const value = params[dynamic.name];
|
|
30
33
|
return value !== undefined && value !== null;
|
|
@@ -37,20 +40,44 @@ function assertStaticParams(route: RouteNode, params: any) {
|
|
|
37
40
|
);
|
|
38
41
|
}
|
|
39
42
|
|
|
43
|
+
const validateSingleParam = (
|
|
44
|
+
dynamic: DynamicConvention,
|
|
45
|
+
value: any,
|
|
46
|
+
allowMultipleSegments?: boolean
|
|
47
|
+
) => {
|
|
48
|
+
if (typeof value !== "string") {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`generateStaticParams() for route "${
|
|
51
|
+
route.contextKey
|
|
52
|
+
}" expected param "${
|
|
53
|
+
dynamic.name
|
|
54
|
+
}" to be of type string, instead found "${typeof value}" while parsing "${value}".`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
const parts = value.split("/").filter(Boolean);
|
|
58
|
+
if (parts.length > 1 && !allowMultipleSegments) {
|
|
59
|
+
throw new Error(
|
|
60
|
+
`generateStaticParams() for route "${route.contextKey}" expected param "${dynamic.name}" to not contain "/" (multiple segments) while parsing "${value}".`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
if (parts.length === 0) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`generateStaticParams() for route "${route.contextKey}" expected param "${dynamic.name}" not to be empty while parsing "${value}".`
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
40
70
|
route.dynamic!.forEach((dynamic) => {
|
|
41
71
|
const value = params[dynamic.name];
|
|
42
72
|
if (dynamic.deep) {
|
|
73
|
+
// TODO: We could split strings by `/` and use that too.
|
|
43
74
|
if (!Array.isArray(value)) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
75
|
+
validateSingleParam(dynamic, value, true);
|
|
76
|
+
} else {
|
|
77
|
+
validateSingleParam(dynamic, value.filter(Boolean).join("/"), true);
|
|
47
78
|
}
|
|
48
79
|
} else {
|
|
49
|
-
|
|
50
|
-
throw new Error(
|
|
51
|
-
`generateStaticParams() for route "${route.contextKey}" expected param "${dynamic.name}" to not be of type Array.`
|
|
52
|
-
);
|
|
53
|
-
}
|
|
80
|
+
validateSingleParam(dynamic, value);
|
|
54
81
|
}
|
|
55
82
|
return value !== undefined && value !== null;
|
|
56
83
|
});
|
|
@@ -73,27 +100,27 @@ async function loadStaticParamsRecursive(
|
|
|
73
100
|
route: RouteNode,
|
|
74
101
|
props: { parentParams: any }
|
|
75
102
|
): Promise<RouteNode[]> {
|
|
76
|
-
if (!route?.dynamic) {
|
|
103
|
+
if (!route?.dynamic && !route?.children?.length) {
|
|
77
104
|
return [route];
|
|
78
105
|
}
|
|
79
106
|
|
|
80
107
|
const loaded = await route.loadRoute();
|
|
81
|
-
if (!loaded.generateStaticParams) {
|
|
82
|
-
return [route];
|
|
83
|
-
}
|
|
84
108
|
|
|
85
|
-
|
|
86
|
-
params: props.parentParams || {},
|
|
87
|
-
});
|
|
109
|
+
let staticParams: Record<string, string | string[]>[] = [];
|
|
88
110
|
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
);
|
|
93
|
-
|
|
111
|
+
if (loaded.generateStaticParams) {
|
|
112
|
+
staticParams = await loaded.generateStaticParams({
|
|
113
|
+
params: props.parentParams || {},
|
|
114
|
+
});
|
|
115
|
+
if (!Array.isArray(staticParams)) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`generateStaticParams() must return an array of params, received ${staticParams}`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
94
120
|
|
|
95
|
-
|
|
96
|
-
|
|
121
|
+
// Assert that at least one param from each matches the dynamic route.
|
|
122
|
+
staticParams.forEach((params) => assertStaticParams(route, params));
|
|
123
|
+
}
|
|
97
124
|
|
|
98
125
|
route.children = uniqBy(
|
|
99
126
|
(
|
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { ServerContainerRef } from "@react-navigation/native";
|
|
9
|
-
|
|
9
|
+
// We use the value from `main` in the `package.json` since this
|
|
10
|
+
// should only be accessed from processes that are running in Node.js and
|
|
11
|
+
// conform to using `mainFields: ['main']` in their bundler config.
|
|
12
|
+
// @ts-expect-error
|
|
13
|
+
import ServerContainer from "@react-navigation/native/lib/commonjs/ServerContainer";
|
|
10
14
|
import App, { getManifest } from "expo-router/_entry";
|
|
11
15
|
import React from "react";
|
|
12
16
|
import ReactDOMServer from "react-dom/server";
|
|
@@ -6,7 +6,10 @@ import { useLinkingContext } from "../link/useLinkingContext";
|
|
|
6
6
|
function useServerStateNode() {
|
|
7
7
|
// TODO: Expose this from React Navigation
|
|
8
8
|
const ServerContext =
|
|
9
|
-
|
|
9
|
+
// We use the value from `main` in the `package.json` since this
|
|
10
|
+
// should only be accessed from processes that are running in Node.js and
|
|
11
|
+
// conform to using `mainFields: ['main']` in their bundler config.
|
|
12
|
+
require("@react-navigation/native/lib/commonjs/ServerContext").default;
|
|
10
13
|
const getStateFromPath = useGetStateFromPath();
|
|
11
14
|
const server = React.useContext<any>(ServerContext);
|
|
12
15
|
const pathname = React.useMemo<string>(() => {
|
package/src/views/Screen.tsx
CHANGED
|
@@ -21,6 +21,9 @@ export type ScreenProps<
|
|
|
21
21
|
options?: TOptions;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
const useLayoutEffect =
|
|
25
|
+
typeof window !== "undefined" ? React.useLayoutEffect : function () {};
|
|
26
|
+
|
|
24
27
|
/** Component for setting the current screen's options dynamically. */
|
|
25
28
|
export function Screen<TOptions extends object = object>({
|
|
26
29
|
name,
|
|
@@ -29,7 +32,7 @@ export function Screen<TOptions extends object = object>({
|
|
|
29
32
|
}: ScreenProps<TOptions>) {
|
|
30
33
|
const navigation = useNavigation(name);
|
|
31
34
|
|
|
32
|
-
|
|
35
|
+
useLayoutEffect(() => {
|
|
33
36
|
navigation.setOptions(options ?? {});
|
|
34
37
|
}, [navigation, options]);
|
|
35
38
|
|
package/src/views/Unmatched.tsx
CHANGED
|
@@ -4,15 +4,20 @@ import React from "react";
|
|
|
4
4
|
|
|
5
5
|
import { usePathname } from "../LocationProvider";
|
|
6
6
|
import { Link } from "../link/Link";
|
|
7
|
+
import { useRouter } from "../link/useRouter";
|
|
7
8
|
import { useNavigation } from "../useNavigation";
|
|
8
9
|
|
|
10
|
+
const useLayoutEffect =
|
|
11
|
+
typeof window !== "undefined" ? React.useLayoutEffect : function () {};
|
|
12
|
+
|
|
9
13
|
/** Default screen for unmatched routes. */
|
|
10
14
|
export function Unmatched() {
|
|
15
|
+
const router = useRouter();
|
|
11
16
|
const navigation = useNavigation();
|
|
12
17
|
const pathname = usePathname();
|
|
13
18
|
const url = createURL(pathname);
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
useLayoutEffect(() => {
|
|
16
21
|
navigation.setOptions({
|
|
17
22
|
title: "Not Found",
|
|
18
23
|
});
|
|
@@ -33,9 +38,18 @@ export function Unmatched() {
|
|
|
33
38
|
style={styles.subtitle}
|
|
34
39
|
>
|
|
35
40
|
Page could not be found.{" "}
|
|
36
|
-
<
|
|
41
|
+
<Text
|
|
42
|
+
onPress={() => {
|
|
43
|
+
if (navigation.canGoBack()) {
|
|
44
|
+
navigation.goBack();
|
|
45
|
+
} else {
|
|
46
|
+
router.replace("/");
|
|
47
|
+
}
|
|
48
|
+
}}
|
|
49
|
+
style={styles.link}
|
|
50
|
+
>
|
|
37
51
|
Go back.
|
|
38
|
-
</
|
|
52
|
+
</Text>
|
|
39
53
|
</Text>
|
|
40
54
|
|
|
41
55
|
<Link href={pathname} replace style={styles.link}>
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getNormalizedStatePath,
|
|
3
|
-
compareUrlSearchParams,
|
|
4
|
-
} from "../LocationProvider";
|
|
5
|
-
|
|
6
|
-
describe(getNormalizedStatePath, () => {
|
|
7
|
-
// Ensure all values are correctly decoded
|
|
8
|
-
it(`returns the normalized path`, () => {
|
|
9
|
-
expect(
|
|
10
|
-
getNormalizedStatePath({
|
|
11
|
-
path: "/foo/bar%20baz?alpha=beta",
|
|
12
|
-
params: {
|
|
13
|
-
alpha: "beta other",
|
|
14
|
-
beta: "gamma",
|
|
15
|
-
charlie: "delta%20echo",
|
|
16
|
-
delta: ["evan", "foxtrot%20gamma", "hotel india"],
|
|
17
|
-
},
|
|
18
|
-
})
|
|
19
|
-
).toEqual({
|
|
20
|
-
segments: ["foo", "bar baz"],
|
|
21
|
-
params: {
|
|
22
|
-
alpha: "beta other",
|
|
23
|
-
beta: "gamma",
|
|
24
|
-
charlie: "delta echo",
|
|
25
|
-
// Ensure arrays are preserved (rest params).
|
|
26
|
-
delta: ["evan", "foxtrot gamma", "hotel india"],
|
|
27
|
-
},
|
|
28
|
-
});
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
describe(compareUrlSearchParams, () => {
|
|
33
|
-
it("compares search params", () => {
|
|
34
|
-
expect(
|
|
35
|
-
compareUrlSearchParams(
|
|
36
|
-
{ one: "two", three: ["four"] },
|
|
37
|
-
{ one: "two", three: ["four"] }
|
|
38
|
-
)
|
|
39
|
-
).toBe(true);
|
|
40
|
-
|
|
41
|
-
expect(
|
|
42
|
-
compareUrlSearchParams(
|
|
43
|
-
{ one: "two", three: ["four"], five: "six", seven: "eight" },
|
|
44
|
-
{ one: "two", three: ["four"], five: "six", seven: "eight" }
|
|
45
|
-
)
|
|
46
|
-
).toBe(true);
|
|
47
|
-
|
|
48
|
-
expect(
|
|
49
|
-
compareUrlSearchParams(
|
|
50
|
-
{ six: "seven", eight: ["nine"] },
|
|
51
|
-
{ one: "two", three: ["four"] }
|
|
52
|
-
)
|
|
53
|
-
).toBe(false);
|
|
54
|
-
});
|
|
55
|
-
});
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { RouteNode, sortRoutes } from "../Route";
|
|
2
|
-
import { generateDynamic } from "../getRoutes";
|
|
3
|
-
|
|
4
|
-
const asRouteNode = (route: string) =>
|
|
5
|
-
({
|
|
6
|
-
children: [],
|
|
7
|
-
dynamic: generateDynamic(route),
|
|
8
|
-
loadRoute(): any {
|
|
9
|
-
return {
|
|
10
|
-
default() {
|
|
11
|
-
return null;
|
|
12
|
-
},
|
|
13
|
-
};
|
|
14
|
-
},
|
|
15
|
-
route,
|
|
16
|
-
contextKey: "INVALID_TEST_VALUE",
|
|
17
|
-
} as RouteNode);
|
|
18
|
-
|
|
19
|
-
describe(sortRoutes, () => {
|
|
20
|
-
it(`sorts index routes by priority`, () => {
|
|
21
|
-
// Index before deep dynamic
|
|
22
|
-
expect(sortRoutes(asRouteNode("index"), asRouteNode("[...a]"))).toBe(-1);
|
|
23
|
-
// Index before dynamic
|
|
24
|
-
expect(sortRoutes(asRouteNode("index"), asRouteNode("[a]"))).toBe(-1);
|
|
25
|
-
// Index before named
|
|
26
|
-
expect(sortRoutes(asRouteNode("index"), asRouteNode("a"))).toBe(-1);
|
|
27
|
-
expect(sortRoutes(asRouteNode("index"), asRouteNode("z"))).toBe(-1);
|
|
28
|
-
|
|
29
|
-
// Index tied with group
|
|
30
|
-
expect(sortRoutes(asRouteNode("index"), asRouteNode("(z)"))).toBe(2);
|
|
31
|
-
});
|
|
32
|
-
it(`sorts group routes by priority`, () => {
|
|
33
|
-
expect(sortRoutes(asRouteNode("(zzz)"), asRouteNode("[...a]"))).toBe(-1);
|
|
34
|
-
expect(sortRoutes(asRouteNode("(zzz)"), asRouteNode("[a]"))).toBe(-1);
|
|
35
|
-
expect(sortRoutes(asRouteNode("(zzz)"), asRouteNode("a"))).toBe(-1);
|
|
36
|
-
expect(sortRoutes(asRouteNode("(zzz)"), asRouteNode("z"))).toBe(-1);
|
|
37
|
-
expect(sortRoutes(asRouteNode("(zzz)"), asRouteNode("index"))).toBe(0);
|
|
38
|
-
});
|
|
39
|
-
it(`sorts multiple dynamic routes higher than a single deep dynamic route`, () => {
|
|
40
|
-
// dynamic before deep dynamic
|
|
41
|
-
expect(sortRoutes(asRouteNode("[a]/[b]"), asRouteNode("[...a]"))).toBe(-1);
|
|
42
|
-
expect(sortRoutes(asRouteNode("[...a]"), asRouteNode("[a]/[b]"))).toBe(1);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it(`sorts dynamic routes by priority`, () => {
|
|
46
|
-
// dynamic before deep dynamic
|
|
47
|
-
expect(sortRoutes(asRouteNode("[a]"), asRouteNode("[...a]"))).toBe(-1);
|
|
48
|
-
// tied with two dynamic routes
|
|
49
|
-
expect(sortRoutes(asRouteNode("[a]"), asRouteNode("[b]"))).toBe(0);
|
|
50
|
-
expect(sortRoutes(asRouteNode("[a]/[b]"), asRouteNode("[b]/[a]"))).toBe(0);
|
|
51
|
-
// Lower priority
|
|
52
|
-
expect(sortRoutes(asRouteNode("[a]"), asRouteNode("index"))).toBe(1);
|
|
53
|
-
expect(sortRoutes(asRouteNode("[a]"), asRouteNode("a"))).toBe(1);
|
|
54
|
-
expect(sortRoutes(asRouteNode("[a]"), asRouteNode("(a)"))).toBe(1);
|
|
55
|
-
});
|
|
56
|
-
it(`sorts deep dynamic routes by priority`, () => {
|
|
57
|
-
expect(sortRoutes(asRouteNode("[...a]"), asRouteNode("[...beta]"))).toBe(0);
|
|
58
|
-
expect(
|
|
59
|
-
sortRoutes(asRouteNode("[...a]/[b]"), asRouteNode("[...beta]/[c]"))
|
|
60
|
-
).toBe(0);
|
|
61
|
-
// Lower priority
|
|
62
|
-
expect(sortRoutes(asRouteNode("[...a]"), asRouteNode("[b]"))).toBe(1);
|
|
63
|
-
expect(sortRoutes(asRouteNode("[...a]/[a]"), asRouteNode("[b]/[c]"))).toBe(
|
|
64
|
-
1
|
|
65
|
-
);
|
|
66
|
-
expect(sortRoutes(asRouteNode("[...a]"), asRouteNode("index"))).toBe(1);
|
|
67
|
-
expect(sortRoutes(asRouteNode("[...a]"), asRouteNode("a"))).toBe(1);
|
|
68
|
-
expect(sortRoutes(asRouteNode("[...a]"), asRouteNode("(a)"))).toBe(1);
|
|
69
|
-
});
|
|
70
|
-
});
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import { getReactNavigationScreensConfig } from "../getReactNavigationConfig";
|
|
2
|
-
|
|
3
|
-
const mockRoutes = [
|
|
4
|
-
{
|
|
5
|
-
children: [
|
|
6
|
-
{
|
|
7
|
-
children: [],
|
|
8
|
-
dynamic: null,
|
|
9
|
-
route: "people",
|
|
10
|
-
contextKey: "./(second-group)/people.tsx",
|
|
11
|
-
},
|
|
12
|
-
],
|
|
13
|
-
dynamic: null,
|
|
14
|
-
route: "(second-group)",
|
|
15
|
-
contextKey: "./(second-group)/_layout.tsx",
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
children: [
|
|
19
|
-
{
|
|
20
|
-
children: [],
|
|
21
|
-
dynamic: [
|
|
22
|
-
{
|
|
23
|
-
name: "deep",
|
|
24
|
-
deep: true,
|
|
25
|
-
},
|
|
26
|
-
],
|
|
27
|
-
route: "[...deep]",
|
|
28
|
-
contextKey: "./(group)/[...deep].tsx",
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
children: [],
|
|
32
|
-
dynamic: [
|
|
33
|
-
{
|
|
34
|
-
name: "dynamic",
|
|
35
|
-
deep: false,
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
route: "[dynamic]",
|
|
39
|
-
contextKey: "./(group)/[dynamic].tsx",
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
children: [],
|
|
43
|
-
dynamic: null,
|
|
44
|
-
route: "index",
|
|
45
|
-
contextKey: "./(group)/index.tsx",
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
dynamic: null,
|
|
49
|
-
route: "(group)",
|
|
50
|
-
contextKey: "./(group)/_layout.tsx",
|
|
51
|
-
},
|
|
52
|
-
{
|
|
53
|
-
children: [],
|
|
54
|
-
dynamic: [
|
|
55
|
-
{
|
|
56
|
-
name: "screen",
|
|
57
|
-
deep: true,
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
route: "other/nested/[...screen]",
|
|
61
|
-
contextKey: "./other/nested/[...screen].js",
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
children: [],
|
|
65
|
-
dynamic: null,
|
|
66
|
-
route: "_sitemap",
|
|
67
|
-
contextKey: "./_sitemap.tsx",
|
|
68
|
-
generated: true,
|
|
69
|
-
internal: true,
|
|
70
|
-
},
|
|
71
|
-
];
|
|
72
|
-
|
|
73
|
-
describe(getReactNavigationScreensConfig, () => {
|
|
74
|
-
it("should return a valid linking config", () => {
|
|
75
|
-
expect(
|
|
76
|
-
getReactNavigationScreensConfig(
|
|
77
|
-
// @ts-expect-error
|
|
78
|
-
mockRoutes,
|
|
79
|
-
true
|
|
80
|
-
)
|
|
81
|
-
).toEqual({
|
|
82
|
-
"(group)": {
|
|
83
|
-
initialRouteName: undefined,
|
|
84
|
-
path: "(group)",
|
|
85
|
-
screens: { "[...deep]": "*deep", "[dynamic]": ":dynamic", index: "" },
|
|
86
|
-
},
|
|
87
|
-
"(second-group)": {
|
|
88
|
-
initialRouteName: undefined,
|
|
89
|
-
path: "(second-group)",
|
|
90
|
-
screens: { people: "people" },
|
|
91
|
-
},
|
|
92
|
-
_sitemap: "_sitemap",
|
|
93
|
-
"other/nested/[...screen]": "other/nested/*screen",
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
it("should return a valid linking config with route nodes", () => {
|
|
97
|
-
expect(
|
|
98
|
-
getReactNavigationScreensConfig(
|
|
99
|
-
// @ts-expect-error
|
|
100
|
-
mockRoutes,
|
|
101
|
-
false
|
|
102
|
-
)
|
|
103
|
-
).toEqual({
|
|
104
|
-
"(group)": {
|
|
105
|
-
initialRouteName: undefined,
|
|
106
|
-
path: "(group)",
|
|
107
|
-
_route: expect.anything(),
|
|
108
|
-
screens: {
|
|
109
|
-
"[...deep]": {
|
|
110
|
-
path: "*deep",
|
|
111
|
-
screens: {},
|
|
112
|
-
_route: expect.anything(),
|
|
113
|
-
},
|
|
114
|
-
"[dynamic]": {
|
|
115
|
-
path: ":dynamic",
|
|
116
|
-
screens: {},
|
|
117
|
-
_route: expect.anything(),
|
|
118
|
-
},
|
|
119
|
-
index: { path: "", screens: {}, _route: expect.anything() },
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
"(second-group)": {
|
|
123
|
-
initialRouteName: undefined,
|
|
124
|
-
path: "(second-group)",
|
|
125
|
-
_route: expect.anything(),
|
|
126
|
-
screens: {
|
|
127
|
-
people: { path: "people", screens: {}, _route: expect.anything() },
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
_sitemap: { path: "_sitemap", screens: {}, _route: expect.anything() },
|
|
131
|
-
"other/nested/[...screen]": {
|
|
132
|
-
path: "other/nested/*screen",
|
|
133
|
-
screens: {},
|
|
134
|
-
_route: expect.anything(),
|
|
135
|
-
},
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
});
|