From 82a3dd031024fe025e8a92e2c2d29ac5a074d92b Mon Sep 17 00:00:00 2001 From: MOZGIII Date: Wed, 9 Apr 2025 11:20:31 -0300 Subject: [PATCH] Refactor the order validation machinery to avoid generating permutation of tuples --- src/data/stages.derived.ts | 6 +++--- src/data/stages.ts | 15 ++++++++------- src/types/IsExactPermutation.ts | 23 +++++++++++++++++++++++ src/types/defineOrder.ts | 7 +++++++ src/types/unionToTuple.ts | 32 -------------------------------- 5 files changed, 41 insertions(+), 42 deletions(-) create mode 100644 src/types/IsExactPermutation.ts create mode 100644 src/types/defineOrder.ts delete mode 100644 src/types/unionToTuple.ts diff --git a/src/data/stages.derived.ts b/src/data/stages.derived.ts index 589e451..f5cf116 100644 --- a/src/data/stages.derived.ts +++ b/src/data/stages.derived.ts @@ -2,18 +2,18 @@ // It contains mainly the support types and values that are derived from // the manually entered values. +import defineOrderFor from "../types/defineOrder"; import { NeverForEmpty } from "../types/NeverForEmpty"; -import { TuplifyUnionAnyOrder } from "../types/unionToTuple"; import { bridgedChains, stages } from "./stages"; export type Stages = typeof stages; export type StageId = keyof Stages; -export type StageIdsOrder = TuplifyUnionAnyOrder; +export const defineStageIdsOrder = defineOrderFor(); export type BridgedChains = typeof bridgedChains; export type BridgedChainId = NeverForEmpty; -export type BridgedChainIdsOrder = TuplifyUnionAnyOrder; +export const defineBridgedChainIdsOrder = defineOrderFor(); diff --git a/src/data/stages.ts b/src/data/stages.ts index 9bd7148..50116b2 100644 --- a/src/data/stages.ts +++ b/src/data/stages.ts @@ -1,4 +1,8 @@ -import { BridgedChainIdsOrder, StageId, StageIdsOrder } from "./stages.derived"; +import { + StageId, + defineStageIdsOrder, + defineBridgedChainIdsOrder, +} from "./stages.derived"; import { BridgedChainsShape, StagesShape } from "./stages.internal"; // Wait for announcements! @@ -149,12 +153,9 @@ export const stages = { export const mainStageId = "mainnet" as const satisfies StageId; -export const stagesDisplayOrder = [ - "mainnet", - "testnet5", -] as const satisfies StageIdsOrder; +export const stagesDisplayOrder = defineStageIdsOrder(["mainnet", "testnet5"]); -export const bridgedChainsDisplayOrder = [ +export const bridgedChainsDisplayOrder = defineBridgedChainIdsOrder([ "avalanche", "base", "filecoin", @@ -163,4 +164,4 @@ export const bridgedChainsDisplayOrder = [ "hyperliquid", "story", "janction", -] as const satisfies BridgedChainIdsOrder; +]); diff --git a/src/types/IsExactPermutation.ts b/src/types/IsExactPermutation.ts new file mode 100644 index 0000000..fc625b8 --- /dev/null +++ b/src/types/IsExactPermutation.ts @@ -0,0 +1,23 @@ +// Checks whether a tuple T contains only unique items. +type IsUnique = T extends readonly [ + infer F, + ...infer R, +] + ? F extends R[number] + ? false + : IsUnique + : true; + +// Checks that T is an exact permutation of U (i.e. it contains each element of U exactly once). +type IsExactPermutation = + // First check that the union of T’s elements equals U. + [T[number]] extends [U] + ? [U] extends [T[number]] + ? // Then check that T has no duplicates. + IsUnique extends true + ? T + : never + : never + : never; + +export default IsExactPermutation; diff --git a/src/types/defineOrder.ts b/src/types/defineOrder.ts new file mode 100644 index 0000000..6cead40 --- /dev/null +++ b/src/types/defineOrder.ts @@ -0,0 +1,7 @@ +import IsExactPermutation from "./IsExactPermutation"; + +function defineOrderFor() { + return (order: IsExactPermutation) => order; +} + +export default defineOrderFor; diff --git a/src/types/unionToTuple.ts b/src/types/unionToTuple.ts deleted file mode 100644 index 7a5be3b..0000000 --- a/src/types/unionToTuple.ts +++ /dev/null @@ -1,32 +0,0 @@ -// Fixed order. - -type UnionToIntersection = (U extends any ? (k: U) => void : never) extends ( - k: infer I, -) => void - ? I - : never; - -type LastOf = - UnionToIntersection T : never> extends () => infer R - ? R - : never; - -type Push = [...T, V]; - -export type TuplifyUnionFixedOrder< - T, - L = LastOf, - N = [T] extends [never] ? true : false, -> = true extends N ? [] : Push>, L>; - -// Any order. - -type TuplifyUnionAnyOrderRecurse = { - [S in U]: Exclude extends never - ? [S] - : [...TuplifyUnionAnyOrderRecurse>, S]; -}[U]; - -export type TuplifyUnionAnyOrder = [U] extends [never] - ? [] - : TuplifyUnionAnyOrderRecurse;