Skip to content

Commit

Permalink
feat: remove lodash as a dependency (#2378)
Browse files Browse the repository at this point in the history
This will reduce the bundle size by ~23%(117kb).

Only 4 methods were used `flatten`, `flatMap`, `omitBy`, and `groupBy`.

`omitBy and `groupBy` were recreated while the es2019 implementations of
`flatten` and `flatMap` are used.

`lodash` is still used in the tests which is fine because it makes the
tests cleaner.

Closes #2118
  • Loading branch information
ckniffen committed Aug 12, 2023
1 parent c36ca7e commit d57183b
Show file tree
Hide file tree
Showing 13 changed files with 353 additions and 285 deletions.
509 changes: 262 additions & 247 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"jest": "^29.3.1",
"jest-mock": "^29.3.1",
"lerna": "^4.0.0",
"lodash": "^4.17.21",
"npm-run-all": "^4.1.5",
"path-browserify": "1.0.1",
"prettier": "^2.3.2",
Expand Down
4 changes: 2 additions & 2 deletions packages/xrpl/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
"bip32": "^2.0.6",
"bip39": "^3.0.4",
"https-proxy-agent": "^5.0.0",
"lodash": "^4.17.4",
"ripple-address-codec": "^4.3.0",
"ripple-binary-codec": "^1.8.0",
"ripple-keypairs": "^1.3.0",
Expand All @@ -43,6 +42,7 @@
"karma-chrome-launcher": "^3.1.1",
"karma-jasmine": "^5.1.0",
"karma-webpack": "^5.0.0",
"lodash": "^4.17.4",
"node-polyfill-webpack-plugin": "^2.0.1",
"react": "^18.2.0",
"typedoc": "^0.24.8"
Expand All @@ -56,7 +56,7 @@
"build:lib": "tsc --build tsconfig.build.json",
"build:web": "webpack",
"build:browserTests": "webpack --config ./test/webpack.config.js",
"analyze": "run-s build:web --analyze",
"analyze": "webpack --analyze",
"watch": "run-s build:lib --watch",
"clean": "rm -rf dist build coverage",
"docgen": "tsc --build tsconfig.docs.json && typedoc && echo js.xrpl.org >> ../../docs/CNAME",
Expand Down
2 changes: 1 addition & 1 deletion packages/xrpl/src/Wallet/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import BigNumber from 'bignumber.js'
import { fromSeed } from 'bip32'
import { mnemonicToSeedSync, validateMnemonic } from 'bip39'
import omitBy from 'lodash/omitBy'
import {
classicAddressToXAddress,
isValidXAddress,
Expand All @@ -26,6 +25,7 @@ import ECDSA from '../ECDSA'
import { ValidationError } from '../errors'
import { Transaction, validate } from '../models/transactions'
import { ensureClassicAddress } from '../sugar/utils'
import { omitBy } from '../utils/collections'
import { hashSignedTx } from '../utils/hashes/hashLedger'

import { rfc1751MnemonicToKey } from './rfc1751'
Expand Down
8 changes: 3 additions & 5 deletions packages/xrpl/src/Wallet/signer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { BigNumber } from 'bignumber.js'
import { flatMap } from 'lodash'
import { decodeAccountID } from 'ripple-address-codec'
import {
decode,
Expand Down Expand Up @@ -128,10 +127,9 @@ function getTransactionWithAllSigners(
transactions: Transaction[],
): Transaction {
// Signers must be sorted in the combined transaction - See compareSigners' documentation for more details
const sortedSigners: Signer[] = flatMap(
transactions,
(tx) => tx.Signers ?? [],
).sort(compareSigners)
const sortedSigners: Signer[] = transactions
.flatMap((tx) => tx.Signers ?? [])
.sort(compareSigners)

return { ...transactions[0], Signers: sortedSigners }
}
Expand Down
2 changes: 1 addition & 1 deletion packages/xrpl/src/client/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import { EventEmitter } from 'events'
import { Agent } from 'http'

import omitBy from 'lodash/omitBy'
import WebSocket from 'ws'

import {
Expand All @@ -12,6 +11,7 @@ import {
XrplError,
} from '../errors'
import { BaseRequest } from '../models/methods/baseMethod'
import { omitBy } from '../utils/collections'

import ConnectionManager from './ConnectionManager'
import ExponentialBackoff from './ExponentialBackoff'
Expand Down
4 changes: 1 addition & 3 deletions packages/xrpl/src/sugar/balances.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import flatMap from 'lodash/flatMap'

import type { Balance, Client } from '..'
import {
AccountLinesRequest,
Expand Down Expand Up @@ -108,7 +106,7 @@ async function getBalances(
// combine results
await Promise.all([xrpPromise, linesPromise]).then(
([xrpBalance, linesResponses]) => {
const accountLinesBalance = flatMap(linesResponses, (response) =>
const accountLinesBalance = linesResponses.flatMap((response) =>
formatBalances(response.result.lines),
)
if (xrpBalance !== '') {
Expand Down
15 changes: 8 additions & 7 deletions packages/xrpl/src/sugar/getOrderbook.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable max-lines-per-function -- Needs to process orderbooks. */
import BigNumber from 'bignumber.js'
import flatMap from 'lodash/flatMap'

import type { Client } from '../client'
import { ValidationError } from '../errors'
Expand All @@ -10,6 +9,7 @@ import {
BookOffer,
BookOfferCurrency,
BookOffersRequest,
BookOffersResponse,
} from '../models/methods/bookOffers'

const DEFAULT_LIMIT = 20
Expand Down Expand Up @@ -112,17 +112,18 @@ async function getOrderbook(
taker: options.taker ? options.taker : undefined,
}
// 2. Make Request
const directOfferResults = await this.requestAll(request)
const directOfferResults: BookOffersResponse[] = await this.requestAll(
request,
)
request.taker_gets = currency1
request.taker_pays = currency2
const reverseOfferResults = await this.requestAll(request)
// 3. Return Formatted Response
const directOffers = flatMap(
directOfferResults,
(directOfferResult) => directOfferResult.result.offers,

const directOffers = directOfferResults.flatMap(
(directOfferResult: BookOffersResponse) => directOfferResult.result.offers,
)
const reverseOffers = flatMap(
reverseOfferResults,
const reverseOffers = reverseOfferResults.flatMap(
(reverseOfferResult) => reverseOfferResult.result.offers,
)

Expand Down
52 changes: 52 additions & 0 deletions packages/xrpl/src/utils/collections.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
type ValueOf<T> = T[keyof T]

/**
* Creates an object composed of keys generated from the results of running each element of collection thru iteratee.
* The order of grouped values is determined by the order they occur in collection.
* The corresponding value of each key is an array of elements responsible for generating the key.
*
* Similar to lodash's groupBy
*
* @param array - array to iterate over
* @param iteratee - function that returns key of the group to place the item
*
* @returns a map of arrays
*/
export function groupBy<T>(
array: T[],
iteratee: (value: T, index: number, array: T[]) => string,
): { [p: string]: T[] } {
// eslint-disable-next-line max-params -- need all the params for the fallback
return array.reduce<{ [key: string]: T[] }>(function predicate(
acc,
value,
index,
arrayReference,
) {
;(acc[iteratee(value, index, arrayReference)] ||= []).push(value)
return acc
},
{})
}

/**
* Creates an object composed of the own and inherited enumerable string keyed properties of object that
* predicate doesn't return truthy for.
*
* @param obj - Object to have properties removed.
* @param predicate - function that returns whether the property should be removed from the obj.
*
* @returns object
*/
export function omitBy<T extends object>(
obj: T,
predicate: (objElement: ValueOf<T>, k: string | number | symbol) => boolean,
): Partial<T> {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions -- We know the keys are properties of T
const keys: Array<keyof T> = Object.keys(obj) as Array<keyof T>
const keysToKeep = keys.filter((kb) => !predicate(obj[kb], kb))
return keysToKeep.reduce((acc: Partial<T>, key: keyof T) => {
acc[key] = obj[key]
return acc
}, {})
}
5 changes: 2 additions & 3 deletions packages/xrpl/src/utils/getBalanceChanges.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import BigNumber from 'bignumber.js'
import flatten from 'lodash/flatten'
import groupBy from 'lodash/groupBy'

import {
Amount,
Expand All @@ -10,6 +8,7 @@ import {
Node,
} from '../models'

import { groupBy } from './collections'
import { dropsToXrp } from './xrpConversion'

interface BalanceChange {
Expand Down Expand Up @@ -182,5 +181,5 @@ export default function getBalanceChanges(
}
return []
})
return groupByAccount(flatten(quantities))
return groupByAccount(quantities.flat())
}
34 changes: 18 additions & 16 deletions packages/xrpl/src/utils/getNFTokenID.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import flatMap from 'lodash/flatMap'
import { decode } from 'ripple-binary-codec'

import { NFToken } from '../models/ledger/NFTokenPage'
Expand Down Expand Up @@ -33,6 +32,7 @@ function ensureDecodedMeta(
* @returns The NFTokenID for the minted NFT.
* @throws if meta is not TransactionMetadata.
*/
// eslint-disable-next-line max-lines-per-function -- This function has a lot of documentation
export default function getNFTokenID(
meta: TransactionMetadata | string | undefined,
): string | undefined {
Expand All @@ -57,7 +57,6 @@ export default function getNFTokenID(
* not changed. Thus why we add the additional condition to check
* if the PreviousFields contains NFTokens
*/

const affectedNodes = decodedMeta.AffectedNodes.filter((node) => {
if (isCreatedNode(node)) {
return node.CreatedNode.LedgerEntryType === 'NFTokenPage'
Expand All @@ -72,25 +71,28 @@ export default function getNFTokenID(
})
/* eslint-disable @typescript-eslint/consistent-type-assertions -- Necessary for parsing metadata */
const previousTokenIDSet = new Set(
flatMap(affectedNodes, (node) => {
const nftokens = isModifiedNode(node)
? (node.ModifiedNode.PreviousFields?.NFTokens as NFToken[])
: []
return nftokens.map((token) => token.NFToken.NFTokenID)
}).filter((id) => Boolean(id)),
affectedNodes
.flatMap((node) => {
const nftokens = isModifiedNode(node)
? (node.ModifiedNode.PreviousFields?.NFTokens as NFToken[])
: []
return nftokens.map((token) => token.NFToken.NFTokenID)
})
.filter((id) => Boolean(id)),
)

/* eslint-disable @typescript-eslint/no-unnecessary-condition -- Cleaner to read */
const finalTokenIDs = flatMap(affectedNodes, (node) =>
(
(((node as ModifiedNode).ModifiedNode?.FinalFields?.NFTokens ??
(node as CreatedNode).CreatedNode?.NewFields?.NFTokens) as NFToken[]) ??
[]
).map((token) => token.NFToken.NFTokenID),
).filter((nftokenID) => Boolean(nftokenID))
const finalTokenIDs = affectedNodes
.flatMap((node) =>
(
(((node as ModifiedNode).ModifiedNode?.FinalFields?.NFTokens ??
(node as CreatedNode).CreatedNode?.NewFields
?.NFTokens) as NFToken[]) ?? []
).map((token) => token.NFToken.NFTokenID),
)
.filter((nftokenID) => Boolean(nftokenID))
/* eslint-enable @typescript-eslint/consistent-type-assertions -- Necessary for parsing metadata */
/* eslint-enable @typescript-eslint/no-unnecessary-condition -- Cleaner to read */

const nftokenID = finalTokenIDs.find((id) => !previousTokenIDSet.has(id))

return nftokenID
Expand Down
1 change: 1 addition & 0 deletions packages/xrpl/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"compilerOptions": {
"pretty": true,
"target": "es6",
"lib": ["es2019", "dom"],
"outDir": "./dist/npm",
"declaration": true,
"declarationMap": true,
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"compilerOptions": {
"composite": true,
"module": "commonjs",
"lib": ["es2019", "dom"],
"moduleResolution": "node",
"esModuleInterop": true,
"sourceMap": true,
Expand Down

0 comments on commit d57183b

Please sign in to comment.