Skip to content

Instantly share code, notes, and snippets.

@lupuszr
Created March 3, 2022 10:00
Show Gist options
  • Save lupuszr/ff8c3e50893bb7b1732d8c9f72c3ed8b to your computer and use it in GitHub Desktop.
Save lupuszr/ff8c3e50893bb7b1732d8c9f72c3ed8b to your computer and use it in GitHub Desktop.
VersionMatch
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