forked from 1Hive/token-lists
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add some more utility functions (wip)
- Loading branch information
1 parent
50dcd5d
commit d3f8bdd
Showing
6 changed files
with
248 additions
and
19 deletions.
There are no files selected for viewing
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
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, | ||
}; | ||
} |
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
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
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.added.length > 0) return VersionUpgrade.MAJOR; | ||
if (diff.removed.length > 0) return VersionUpgrade.MINOR; | ||
if (Object.keys(diff.changed).length > 0) return VersionUpgrade.PATCH; | ||
return VersionUpgrade.NONE; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { VersionUpgrade } from './getVersionUpgrade'; | ||
import { minVersionBump } from './minVersionBump'; | ||
import { TokenInfo, TokenList, Version } from './types'; | ||
|
||
/** | ||
* Returns the next version of the list given a base list and the updated token list. | ||
* @param base base list | ||
* @param updatedList updated list of tokens for the next list | ||
*/ | ||
export function nextVersion( | ||
base: TokenList, | ||
updatedList: TokenInfo[] | ||
): Version { | ||
const bump = minVersionBump(base.tokens, updatedList); | ||
switch (bump) { | ||
case VersionUpgrade.NONE: | ||
return base.version; | ||
|
||
case VersionUpgrade.MAJOR: | ||
return { major: base.version.major + 1, minor: 0, patch: 0 }; | ||
|
||
case VersionUpgrade.MINOR: | ||
return { | ||
major: base.version.major, | ||
minor: base.version.minor + 1, | ||
patch: 0, | ||
}; | ||
|
||
case VersionUpgrade.PATCH: | ||
return { | ||
major: base.version.major, | ||
minor: base.version.minor, | ||
patch: base.version.patch + 1, | ||
}; | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,31 @@ | ||
export interface TokenInfo { | ||
chainId: number; | ||
address: string; | ||
name: string; | ||
decimals: number; | ||
symbol: string; | ||
logoURI?: string; | ||
tags?: string[]; | ||
readonly chainId: number; | ||
readonly address: string; | ||
readonly name: string; | ||
readonly decimals: number; | ||
readonly symbol: string; | ||
readonly logoURI?: string; | ||
readonly tags?: string[]; | ||
} | ||
|
||
export interface Version { | ||
major: number; | ||
minor: number; | ||
patch: number; | ||
readonly major: number; | ||
readonly minor: number; | ||
readonly patch: number; | ||
} | ||
|
||
export interface Tags { | ||
[tagId: string]: { | ||
name: string; | ||
description: string; | ||
readonly [tagId: string]: { | ||
readonly name: string; | ||
readonly description: string; | ||
}; | ||
} | ||
|
||
export interface TokenList { | ||
name: string; | ||
timestamp: string; | ||
version: Version; | ||
tokens: TokenInfo[]; | ||
keywords?: string[]; | ||
tags?: Tags; | ||
readonly name: string; | ||
readonly timestamp: string; | ||
readonly version: Version; | ||
readonly tokens: TokenInfo[]; | ||
readonly keywords?: string[]; | ||
readonly tags?: Tags; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { diffTokenLists, TokenInfo } from '../src'; | ||
|
||
const tokenA: TokenInfo = { | ||
chainId: 1, | ||
address: '0x0a', | ||
logoURI: 'ipfs://test', | ||
symbol: 'abcd', | ||
name: 'token a', | ||
decimals: 18, | ||
tags: ['hello', 'world'], | ||
}; | ||
const tokenAChanged: TokenInfo = { | ||
...tokenA, | ||
name: 'blah', | ||
decimals: 12, | ||
}; | ||
const tokenB: TokenInfo = { | ||
chainId: 1, | ||
address: '0x0b', | ||
logoURI: 'ipfs://blah', | ||
symbol: 'defg', | ||
name: 'token b', | ||
decimals: 9, | ||
tags: ['hello', 'world'], | ||
}; | ||
|
||
describe('#diffTokenLists', () => { | ||
it('change address', () => { | ||
expect(diffTokenLists([tokenA], [tokenB])).toEqual({ | ||
added: [tokenB], | ||
removed: [tokenA], | ||
changed: {}, | ||
}); | ||
}); | ||
|
||
it('change name', () => { | ||
expect(diffTokenLists([tokenB, tokenA], [tokenB, tokenAChanged])).toEqual({ | ||
added: [], | ||
removed: [], | ||
changed: { | ||
1: { | ||
'0x0a': ['name', 'decimals'], | ||
}, | ||
}, | ||
}); | ||
}); | ||
}); |