diff --git a/__tests__/helpers.ts b/__tests__/helpers.ts index df3c154..05ad2a3 100644 --- a/__tests__/helpers.ts +++ b/__tests__/helpers.ts @@ -48,16 +48,16 @@ test("extractParamNameUnion", () => { expect(extractParamNameUnion("foo{}")).toStrictEqual({ name: "foo", - union: [], + union: new Set([]), }); expect(extractParamNameUnion("foo{a}")).toStrictEqual({ name: "foo", - union: ["a"], + union: new Set(["a"]), }); expect(extractParamNameUnion("foo{a|b}")).toStrictEqual({ name: "foo", - union: ["a", "b"], + union: new Set(["a", "b"]), }); }); diff --git a/__tests__/matcher.ts b/__tests__/matcher.ts index 4338617..13792c4 100644 --- a/__tests__/matcher.ts +++ b/__tests__/matcher.ts @@ -45,7 +45,7 @@ test("getMatcher returns a proper matcher structure for paths with params (in pa path: [ "projects", { name: "projectId" }, - { name: "env", union: ["live", "sandbox"] }, + { name: "env", union: new Set(["live", "sandbox"]) }, ], search: undefined, }); @@ -67,8 +67,8 @@ test("getMatcher returns a proper matcher structure for paths with params (in pa ranking: 16, path: ["group", { name: "groupId" }], search: { - foo: { multiple: false, union: ["a", "b"] }, - bar: { multiple: true, union: ["c", "d"] }, + foo: { multiple: false, union: new Set(["a", "b"]) }, + bar: { multiple: true, union: new Set(["c", "d"]) }, }, }); }); @@ -114,11 +114,11 @@ test("getMatcher decrements the ranking by 1 if the path is an area", () => { search: { orderBy: { multiple: false, - union: ["asc", "desc"], + union: new Set(["asc", "desc"]), }, status: { multiple: true, - union: ["disabled", "enabled", "pending"], + union: new Set(["disabled", "enabled", "pending"]), }, }, }, diff --git a/package.json b/package.json index 5cbc3a8..205ea34 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@swan-io/chicane", - "version": "2.2.0", + "version": "2.2.1", "license": "MIT", "packageManager": "pnpm@10.12.1", "description": "A simple and safe router for React and TypeScript", diff --git a/src/createRouter.ts b/src/createRouter.ts index 79670bd..3c37684 100644 --- a/src/createRouter.ts +++ b/src/createRouter.ts @@ -102,10 +102,13 @@ export const createRouter = < const matchersKey = JSON.stringify(routeNames); const matchers = useMemo( - () => - rankedMatchers.filter(({ name }) => - routeNames.includes(name as RouteName), - ), + () => { + const routeNamesSet = new Set(routeNames); + + return rankedMatchers.filter(({ name }) => + routeNamesSet.has(name as RouteName), + ); + }, [matchersKey], // eslint-disable-line react-hooks/exhaustive-deps ); @@ -133,8 +136,10 @@ export const createRouter = < const locationObject = location != null ? decodeLocation(location) : getLocation(); + const routeNamesSet = new Set(routeNames); + const matchers = rankedMatchers.filter(({ name }) => - routeNames.includes(name as RouteName), + routeNamesSet.has(name as RouteName), ); // @ts-expect-error diff --git a/src/helpers.ts b/src/helpers.ts index 14a59ac..0bc81b0 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -40,16 +40,18 @@ export const areRouteEqual = ( export const extractParamNameUnion = ( paramName: string, -): { name: string; union?: string[] } => { +): { name: string; union?: Set } => { const bracketIndex = paramName.indexOf("{"); if (bracketIndex > -1 && paramName.endsWith("}")) { return { name: paramName.substring(0, bracketIndex), - union: paramName - .substring(bracketIndex + 1, paramName.length - 1) - .split("|") - .filter(isNonEmpty), + union: new Set( + paramName + .substring(bracketIndex + 1, paramName.length - 1) + .split("|") + .filter(isNonEmpty), + ), }; } else { return { name: paramName }; diff --git a/src/matcher.ts b/src/matcher.ts index c28b953..4a5b8b1 100644 --- a/src/matcher.ts +++ b/src/matcher.ts @@ -103,7 +103,7 @@ export const getMatchResult = ( const { name, union } = test; - if (union == null || union.includes(part)) { + if (union == null || union.has(part)) { pathParams[name] = part; } else { return; @@ -123,7 +123,7 @@ export const getMatchResult = ( const parts = typeof part === "string" ? [part] : part; const values = - union == null ? parts : parts.filter((item) => union.includes(item)); + union == null ? parts : parts.filter((item) => union.has(item)); if (multiple) { searchParams[key] = values; @@ -185,12 +185,12 @@ export const matchToUrl = (matcher: Matcher, params: Params = {}): string => { const { union } = test; if (typeof param === "string") { - if (union == null || union.includes(param)) { + if (union == null || union.has(param)) { object[key] = param; } } else { object[key] = - union == null ? param : param.filter((item) => union.includes(item)); + union == null ? param : param.filter((item) => union.has(item)); } } diff --git a/src/types.ts b/src/types.ts index 8f90357..138a472 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,8 +9,10 @@ export type Matcher = { name: string; ranking: number; - path: (string | { name: string; union?: string[] })[]; - search: Record | undefined; + path: (string | { name: string; union?: Set })[]; + search: + | Record }> + | undefined; }; export type RouteObject = Readonly<{