Skip to content

Commit 0cd38b0

Browse files
authored
Optimize union matching performances (#55)
1 parent 05ffe57 commit 0cd38b0

File tree

7 files changed

+34
-25
lines changed

7 files changed

+34
-25
lines changed

__tests__/helpers.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,16 @@ test("extractParamNameUnion", () => {
4848

4949
expect(extractParamNameUnion("foo{}")).toStrictEqual({
5050
name: "foo",
51-
union: [],
51+
union: new Set([]),
5252
});
5353

5454
expect(extractParamNameUnion("foo{a}")).toStrictEqual({
5555
name: "foo",
56-
union: ["a"],
56+
union: new Set(["a"]),
5757
});
5858

5959
expect(extractParamNameUnion("foo{a|b}")).toStrictEqual({
6060
name: "foo",
61-
union: ["a", "b"],
61+
union: new Set(["a", "b"]),
6262
});
6363
});

__tests__/matcher.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ test("getMatcher returns a proper matcher structure for paths with params (in pa
4545
path: [
4646
"projects",
4747
{ name: "projectId" },
48-
{ name: "env", union: ["live", "sandbox"] },
48+
{ name: "env", union: new Set(["live", "sandbox"]) },
4949
],
5050
search: undefined,
5151
});
@@ -67,8 +67,8 @@ test("getMatcher returns a proper matcher structure for paths with params (in pa
6767
ranking: 16,
6868
path: ["group", { name: "groupId" }],
6969
search: {
70-
foo: { multiple: false, union: ["a", "b"] },
71-
bar: { multiple: true, union: ["c", "d"] },
70+
foo: { multiple: false, union: new Set(["a", "b"]) },
71+
bar: { multiple: true, union: new Set(["c", "d"]) },
7272
},
7373
});
7474
});
@@ -114,11 +114,11 @@ test("getMatcher decrements the ranking by 1 if the path is an area", () => {
114114
search: {
115115
orderBy: {
116116
multiple: false,
117-
union: ["asc", "desc"],
117+
union: new Set(["asc", "desc"]),
118118
},
119119
status: {
120120
multiple: true,
121-
union: ["disabled", "enabled", "pending"],
121+
union: new Set(["disabled", "enabled", "pending"]),
122122
},
123123
},
124124
},

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@swan-io/chicane",
3-
"version": "2.2.0",
3+
"version": "2.2.1",
44
"license": "MIT",
55
"packageManager": "[email protected]",
66
"description": "A simple and safe router for React and TypeScript",

src/createRouter.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,13 @@ export const createRouter = <
102102
const matchersKey = JSON.stringify(routeNames);
103103

104104
const matchers = useMemo(
105-
() =>
106-
rankedMatchers.filter(({ name }) =>
107-
routeNames.includes(name as RouteName),
108-
),
105+
() => {
106+
const routeNamesSet = new Set(routeNames);
107+
108+
return rankedMatchers.filter(({ name }) =>
109+
routeNamesSet.has(name as RouteName),
110+
);
111+
},
109112
[matchersKey], // eslint-disable-line react-hooks/exhaustive-deps
110113
);
111114

@@ -133,8 +136,10 @@ export const createRouter = <
133136
const locationObject =
134137
location != null ? decodeLocation(location) : getLocation();
135138

139+
const routeNamesSet = new Set(routeNames);
140+
136141
const matchers = rankedMatchers.filter(({ name }) =>
137-
routeNames.includes(name as RouteName),
142+
routeNamesSet.has(name as RouteName),
138143
);
139144

140145
// @ts-expect-error

src/helpers.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,18 @@ export const areRouteEqual = (
4040

4141
export const extractParamNameUnion = (
4242
paramName: string,
43-
): { name: string; union?: string[] } => {
43+
): { name: string; union?: Set<string> } => {
4444
const bracketIndex = paramName.indexOf("{");
4545

4646
if (bracketIndex > -1 && paramName.endsWith("}")) {
4747
return {
4848
name: paramName.substring(0, bracketIndex),
49-
union: paramName
50-
.substring(bracketIndex + 1, paramName.length - 1)
51-
.split("|")
52-
.filter(isNonEmpty),
49+
union: new Set(
50+
paramName
51+
.substring(bracketIndex + 1, paramName.length - 1)
52+
.split("|")
53+
.filter(isNonEmpty),
54+
),
5355
};
5456
} else {
5557
return { name: paramName };

src/matcher.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export const getMatchResult = (
103103

104104
const { name, union } = test;
105105

106-
if (union == null || union.includes(part)) {
106+
if (union == null || union.has(part)) {
107107
pathParams[name] = part;
108108
} else {
109109
return;
@@ -123,7 +123,7 @@ export const getMatchResult = (
123123
const parts = typeof part === "string" ? [part] : part;
124124

125125
const values =
126-
union == null ? parts : parts.filter((item) => union.includes(item));
126+
union == null ? parts : parts.filter((item) => union.has(item));
127127

128128
if (multiple) {
129129
searchParams[key] = values;
@@ -185,12 +185,12 @@ export const matchToUrl = (matcher: Matcher, params: Params = {}): string => {
185185
const { union } = test;
186186

187187
if (typeof param === "string") {
188-
if (union == null || union.includes(param)) {
188+
if (union == null || union.has(param)) {
189189
object[key] = param;
190190
}
191191
} else {
192192
object[key] =
193-
union == null ? param : param.filter((item) => union.includes(item));
193+
union == null ? param : param.filter((item) => union.has(item));
194194
}
195195
}
196196

src/types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ export type Matcher = {
99
name: string;
1010
ranking: number;
1111

12-
path: (string | { name: string; union?: string[] })[];
13-
search: Record<string, { multiple: boolean; union?: string[] }> | undefined;
12+
path: (string | { name: string; union?: Set<string> })[];
13+
search:
14+
| Record<string, { multiple: boolean; union?: Set<string> }>
15+
| undefined;
1416
};
1517

1618
export type RouteObject = Readonly<{

0 commit comments

Comments
 (0)