Skip to content

Commit

Permalink
Add utility functions from upstream dependency (#563)
Browse files Browse the repository at this point in the history
  • Loading branch information
JO-OLADEJI committed Aug 30, 2022
1 parent 1cb1ba0 commit 98dde95
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 0 deletions.
124 changes: 124 additions & 0 deletions src/diffTokenLists.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { TokenInfo } from "./types";

export type TokenInfoChangeKey = Exclude<
keyof TokenInfo,
"address" | "chainId"
>;
export type TokenInfoChanges = Array<TokenInfoChangeKey>;

/**
* compares two token info key values
* this subset of full deep equal functionality does not work on objects or object arrays
* @param a comparison item a
* @param b comparison item b
*/
function compareTokenInfoProperty(a: unknown, b: unknown): boolean {
if (a === b) return true;
if (typeof a !== typeof b) return false;
if (Array.isArray(a) && Array.isArray(b)) {
return a.every((el, i) => b[i] === el);
}
return false;
}

/**
* Differences between a base list and an updated list.
*/
export interface TokenListDiff {
/**
* Tokens from updated with chainId/address not present in base list
*/
readonly added: TokenInfo[];
/**
* Tokens from base with chainId/address not present in the updated list
*/
readonly removed: TokenInfo[];
/**
* The token info that changed
*/
readonly changed: {
[chainId: number]: {
[address: string]: TokenInfoChanges;
};
};
}

/**
* Computes the diff of a token list where the first argument is the base and the second argument is the updated list.
* @param base base list
* @param update updated list
*/
export function diffTokenLists(
base: TokenInfo[],
update: TokenInfo[]
): TokenListDiff {
const indexedBase = base.reduce<{
[chainId: number]: { [address: string]: TokenInfo };
}>((memo, tokenInfo) => {
if (!memo[tokenInfo.chainId]) memo[tokenInfo.chainId] = {};
memo[tokenInfo.chainId][tokenInfo.address] = tokenInfo;
return memo;
}, {});

const newListUpdates = update.reduce<{
added: TokenInfo[];
changed: {
[chainId: number]: {
[address: string]: TokenInfoChanges;
};
};
index: {
[chainId: number]: {
[address: string]: true;
};
};
}>(
(memo, tokenInfo) => {
const baseToken = indexedBase[tokenInfo.chainId]?.[tokenInfo.address];
if (!baseToken) {
memo.added.push(tokenInfo);
} else {
const changes: TokenInfoChanges = Object.keys(tokenInfo)
.filter(
(s): s is TokenInfoChangeKey => s !== "address" && s !== "chainId"
)
.filter((s) => {
return !compareTokenInfoProperty(tokenInfo[s], baseToken[s]);
});
if (changes.length > 0) {
if (!memo.changed[tokenInfo.chainId]) {
memo.changed[tokenInfo.chainId] = {};
}
memo.changed[tokenInfo.chainId][tokenInfo.address] = changes;
}
}

if (!memo.index[tokenInfo.chainId]) {
memo.index[tokenInfo.chainId] = {
[tokenInfo.address]: true,
};
} else {
memo.index[tokenInfo.chainId][tokenInfo.address] = true;
}

return memo;
},
{ added: [], changed: {}, index: {} }
);

const removed = base.reduce<TokenInfo[]>((list, curr) => {
if (
!newListUpdates.index[curr.chainId] ||
!newListUpdates.index[curr.chainId][curr.address]
) {
list.push(curr);
}
return list;
}, []);

return {
added: newListUpdates.added,
changed: newListUpdates.changed,
removed,
};
}
36 changes: 36 additions & 0 deletions src/getVersionUpgrade.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Version } from "./types";

/**
* Enum describing types of version differences
*/
export enum VersionUpgrade {
NONE,
PATCH,
MINOR,
MAJOR,
}

/**
* Return the upgrade type from the base version to the update version.
* Note that downgrades and equivalent versions are both treated as `NONE`.
* @param base base list
* @param update update to the list
*/
export function getVersionUpgrade(
base: Version,
update: Version
): VersionUpgrade {
if (update.major > base.major) {
return VersionUpgrade.MAJOR;
}
if (update.major < base.major) {
return VersionUpgrade.NONE;
}
if (update.minor > base.minor) {
return VersionUpgrade.MINOR;
}
if (update.minor < base.minor) {
return VersionUpgrade.NONE;
}
return update.patch > base.patch ? VersionUpgrade.PATCH : VersionUpgrade.NONE;
}
6 changes: 6 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@ import tokenlist from "./joe.tokenlist-v2.json";
import schema from "./schema.tokenlist-v2.json";

export * from "./types";
export * from './isVersionUpdate';
export * from './getVersionUpgrade';
export * from './diffTokenLists';
export * from './minVersionBump';
export * from './nextVersion';
export * from './versionComparator';
export { schema, tokenlist };
9 changes: 9 additions & 0 deletions src/isVersionUpdate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { versionComparator } from './versionComparator';
import { Version } from './types';

/**
* Returns true if versionB is an update over versionA
*/
export function isVersionUpdate(base: Version, update: Version): boolean {
return versionComparator(base, update) < 0;
}
19 changes: 19 additions & 0 deletions src/minVersionBump.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { diffTokenLists } from "./diffTokenLists";
import { VersionUpgrade } from "./getVersionUpgrade";
import { TokenInfo } from "./types";

/**
* Returns the minimum version bump for the given list
* @param baseList the base list of tokens
* @param updatedList the updated list of tokens
*/
export function minVersionBump(
baseList: TokenInfo[],
updatedList: TokenInfo[]
): VersionUpgrade {
const diff = diffTokenLists(baseList, updatedList);
if (diff.removed.length > 0) return VersionUpgrade.MAJOR;
if (diff.added.length > 0) return VersionUpgrade.MINOR;
if (Object.keys(diff.changed).length > 0) return VersionUpgrade.PATCH;
return VersionUpgrade.NONE;
}
31 changes: 31 additions & 0 deletions src/nextVersion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { VersionUpgrade } from "./getVersionUpgrade";
import { Version } from "./types";

/**
* Returns the next version of the list given a base version and the upgrade type
* @param base current version
* @param bump the upgrade type
*/
export function nextVersion(base: Version, bump: VersionUpgrade): Version {
switch (bump) {
case VersionUpgrade.NONE:
return base;

case VersionUpgrade.MAJOR:
return { major: base.major + 1, minor: 0, patch: 0 };

case VersionUpgrade.MINOR:
return {
major: base.major,
minor: base.minor + 1,
patch: 0,
};

case VersionUpgrade.PATCH:
return {
major: base.major,
minor: base.minor,
patch: base.patch + 1,
};
}
}
28 changes: 28 additions & 0 deletions src/versionComparator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Version } from "./types";

/**
* Comparator function that allows sorting version from lowest to highest
* @param versionA version A to compare
* @param versionB version B to compare
* @returns -1 if versionA comes before versionB, 0 if versionA is equal to version B, and 1 if version A comes after version B
*/
export function versionComparator(
versionA: Version,
versionB: Version
): -1 | 0 | 1 {
if (versionA.major < versionB.major) {
return -1;
} else if (versionA.major > versionB.major) {
return 1;
} else if (versionA.minor < versionB.minor) {
return -1;
} else if (versionA.minor > versionB.minor) {
return 1;
} else if (versionA.patch < versionB.patch) {
return -1;
} else if (versionA.patch > versionB.patch) {
return 1;
} else {
return 0;
}
}

0 comments on commit 98dde95

Please sign in to comment.