Created
March 3, 2022 10:00
-
-
Save lupuszr/ff8c3e50893bb7b1732d8c9f72c3ed8b to your computer and use it in GitHub Desktop.
VersionMatch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type SortedArray<T> = Array<T> & {readonly _tag: "SortedArray ${T}"}; | |
type VersionA<T extends string> = T extends `${infer major}.${infer minor}.${infer patch}` ? T : never; | |
type ComparisionRes = 'LT' | 'EQ' | 'GT'; | |
class Version<T extends string> { | |
readonly major: T extends `${infer major}.${infer minor}.${infer patch}` ? major : never; | |
private readonly majorN: number; | |
readonly minor: T extends `${infer major}.${infer minor}.${infer patch}` ? minor : never; | |
private readonly minorN: number; | |
readonly patch: T extends `${infer major}.${infer minor}.${infer patch}` ? patch : never; | |
private readonly patchN: number; | |
public readonly version: T extends `${infer major}.${infer minor}.${infer patch}` ? T : never; | |
constructor(a: T extends `${infer major}.${infer minor}.${infer patch}` ? T : never) { | |
const [major, minor, patch] = a.split(".") as [typeof this.major, typeof this.minor, typeof this.patch]; | |
this.major = major; | |
this.majorN = +major; | |
this.minor = minor; | |
this.minorN = +minor; | |
this.patch = patch; | |
this.patchN = +patch; | |
this.version = a; | |
} | |
compare = <T extends string>(r: Version<T>): ComparisionRes => { | |
switch (true) { | |
case (this.majorN > r.majorN): return 'GT'; | |
case (this.majorN === r.majorN && this.minorN > r.minorN): return 'GT'; | |
case (this.majorN === r.majorN && this.minorN === r.minorN && this.patchN > r.patchN): return 'GT'; | |
case (this.majorN === r.majorN && this.minorN === r.minorN && this.patchN === r.patchN): return 'EQ'; | |
default: return 'LT'; | |
} | |
} | |
static sortString = <T extends string>(xs: Array<VersionA<T>>): SortedArray<VersionA<T>> => { | |
return xs.sort((a, b) => { | |
const v1 = new Version(a); | |
const v2 = new Version(b); | |
switch (v1.compare(v2)) { | |
case 'EQ': return 0; | |
case 'LT': return -1; | |
case 'GT': return 1; | |
} | |
}) as SortedArray<VersionA<T>> | |
} | |
static sort = <U extends string>(xs: Array<Version<U>>): SortedArray<Version<U>> => { | |
return xs.sort((a, b) => { | |
switch (a.compare(b)) { | |
case 'EQ': return 0; | |
case 'LT': return -1; | |
case 'GT': return 1; | |
} | |
}) as SortedArray<Version<U>> | |
} | |
match = <U extends string, R>(ptr: {[a in VersionA<U>]: () => R}) => { | |
const xs = (Object.keys(ptr) as Array<VersionA<U>>).map(a => new Version(a)); | |
const sv1 = Version.sort(xs); | |
// check if the selected version already exists | |
const sel1 = sv1.find(u => u.compare(this) === "EQ"); | |
if (sel1) { | |
return ptr[sel1.version]() | |
} else { | |
// if the version doesn't exist insert then sort again | |
const ys = [...xs, this] as Array<Version<U>>; | |
const sortedVersions = Version.sort(ys); | |
const index = sortedVersions.findIndex(u => u.compare(this) === 'EQ'); | |
// get the sorted element before the specific v | |
const selected = sortedVersions[index - 1]; | |
return ptr[selected.version]() | |
} | |
} | |
} | |
const a = new Version("0.0.0"); | |
console.log(a) | |
a.match({ | |
"0.0.0": () => console.log("dfds"), | |
"1.1.1": () => console.log("1.1.1"), | |
"1.2.1": () => console.log("1.2.1"), | |
"1.3.1": () => console.log("1.3.1"), | |
"1.5.1": () => console.log("1.5.1") | |
}) | |
const b = a.compare(new Version("1.2.3")) | |
const c = a.compare(new Version("1.2.1")) | |
const d = a.compare(new Version("1.2.4")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment