Skip to content

Commit da2a851

Browse files
authored
Merge pull request #41 from dictor93/feat/differenceWith-matches-uniq
Feat/difference with matches uniq
2 parents c71422a + 0007c39 commit da2a851

14 files changed

+242
-14
lines changed

CHANGELOG

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
#1.21.0
2+
- fix: cloneDeep should not skip nonserializable entities
3+
- feat: add uniq
4+
- feat: add differenceWith
5+
- feat: add matches
6+
17
#1.20.0
28
- feat: add transformKeysToSnake
39
- feat: add sample

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Currently supported utils:
99
- `clone` - Shallow clone the object
1010
- `cloneDeep` - deep clone functionality for objects
1111
- `difference` - creates an array of values from the first argument not included in the second argument
12+
- `differenceWith` - creates an array of values from the first argument not included in the second one using comparator function
1213
- `findLastIndex` - Returns the index of the last element in the array that satisfies the provided testing function.
1314
- `flow` - generate a composite function that returns the result of provided functions called by the chain; each previous function result passes as the argument of the next function in the chain
1415
- `freezeDeep` - deep freezes objects
@@ -31,6 +32,7 @@ Currently supported utils:
3132
- `isUndefined` - checks if an input is undefined
3233
- `mapKeys` - creates new object with the same values but with keys mapped by the provided function
3334
- `mapValues` - Maps the values of an object or array using the provided iteratee function or property path
35+
- `matches` - creates a function that makes a deep partial comparison on a given object with the source
3436
- `max` - computes the maximum value of array. If array is empty or falsey, undefined is returned
3537
- `mean` - Returns the mean of an array of numbers
3638
- `merge` - deep merge functionality for objects
@@ -47,8 +49,10 @@ Currently supported utils:
4749
- `sumBy` - calculate sum of array items using iteratee function or string shortcut
4850
- `transformKeysToSnake` - transform every object key to snake case with option to be recursive
4951
- `union` - Returns the union of the given arrays
52+
- `uniq` - Returns unique values of the array
5053
- `uniqBy` - get unique values of array by the iteratee function or property path
5154
- `uniqWith` - Returns a new array with unique values, using a comparator function
55+
- `unset` - Remove a property by the path in any depth, returns true if succeed, false otherwise
5256
- `update` - Update the object with the updater by path
5357
- `validateInput` - validates the input based on the regex format options: `NUMBER | EMAIL | PATH | NAME | NAME_WITH_DIGITS | INPUT | ADDRESS | PHONE_CODE | PHONE | IMAGE | FILE | FILENAME | PASSWORD`
5458
- `without` - creates an array of values from the first argument excluding all given arguments

index.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export function capitalize (str: string): string
44
export function clone (obj: Object): Object
55
export function cloneDeep (obj: Object): Object
66
export function difference (array: Array<any>, values: Array<any>): Array<any>
7+
export function differenceWith (array: Array<any>, items: Array<any>, comparator: Function): Array<any>
78
export function findLastIndex (array: Array<any>, predicate: Function): number
89
export function flow (funcs: Array<Function>): Function
910
export function freezeDeep (obj: Object): Object
@@ -27,6 +28,7 @@ export function isString (val: any): boolean
2728
export function isUndefined (val: any): boolean
2829
export function mapKeys(obj: Object, mapper: (val: any, key: string) => string): Object
2930
export function mapValues(obj: Object, mapper: (val: any, key: string) => any): Object
31+
export function matches(src: Object): (obj: Object) => boolean
3032
export function max (array: Array<any>): any
3133
export function mean (values: Array<number>): number
3234
export function merge (obj: Object, ...sources: Object[]): Object
@@ -43,8 +45,10 @@ export function sum (values: Array<string>): number
4345
export function sumBy (values: Array, iteratee: Function | string): number
4446
export function transformKeysToSnake (obj: Object, opts?: {recursive?: boolean}) : Object
4547
export function union (...arrays: Array[]): Array
48+
export function uniq (array: Array): Array
4649
export function uniqBy (array: Array, iteratee: Function | string): Array
4750
export function uniqWith (array: Array, comparator: Function): Array
51+
export function unset(object: Object, path: string | Array<string | number>): boolean
4852
export function update (obj: Object, path: string | Array<string | number>, updater: Function): Object
4953
export function validateInput ( input: string, format: 'NUMBER' | 'EMAIL' | 'PATH' | 'NAME' | 'NAME_WITH_DIGITS' | 'INPUT' | 'ADDRESS' | 'PHONE_CODE' | 'PHONE' | 'IMAGE' | 'FILE' | 'FILENAME' | 'PASSWORD' | 'URL' ): Boolean
5054
export function without (array: Array, ...values: Array): Array

index.js

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ const capitalize = require('./src/capitalize')
66
const clone = require('./src/clone')
77
const cloneDeep = require('./src/cloneDeep')
88
const difference = require('./src/difference')
9+
const differenceWith = require('./src/differenceWith')
910
const findLastIndex = require('./src/findLastIndex')
1011
const flow = require('./src/flow')
1112
const freezeDeep = require('./src/freezeDeep')
1213
const get = require('./src/get')
1314
const getArrayHasIntersect = require('./src/getArrayHasIntersect')
1415
const getArrayUniq = require('./src/getArrayUniq')
1516
const getErrorMessage = require('./src/getErrorMessage')
16-
const invert = require('./src/invert')
1717
const groupBy = require('./src/groupBy')
18+
const invert = require('./src/invert')
1819
const isEmpty = require('./src/isEmpty')
1920
const isEqual = require('./src/isEqual')
2021
const isFinite = require('./src/isFinite')
@@ -29,6 +30,7 @@ const isString = require('./src/isString')
2930
const isUndefined = require('./src/isUndefined')
3031
const mapKeys = require('./src/mapKeys')
3132
const mapValues = require('./src/mapValues')
33+
const matches = require('./src/matches')
3234
const max = require('./src/max')
3335
const mean = require('./src/mean')
3436
const merge = require('./src/merge')
@@ -45,12 +47,13 @@ const sum = require('./src/sum')
4547
const sumBy = require('./src/sumBy')
4648
const transformKeysToSnake = require('./src/transformKeysToSnake')
4749
const union = require('./src/union')
50+
const uniq = require('./src/uniq')
4851
const uniqBy = require('./src/uniqBy')
4952
const uniqWith = require('./src/uniqWith')
53+
const unset = require('./src/unset')
5054
const update = require('./src/update')
5155
const validateInput = require('./src/validateInput')
5256
const without = require('./src/without')
53-
const unset = require('./src/unset')
5457

5558
module.exports = {
5659
assignInWith,
@@ -59,15 +62,16 @@ module.exports = {
5962
clone,
6063
cloneDeep,
6164
difference,
65+
differenceWith,
6266
findLastIndex,
6367
flow,
6468
freezeDeep,
6569
get,
6670
getArrayHasIntersect,
6771
getArrayUniq,
6872
getErrorMessage,
69-
invert,
7073
groupBy,
74+
invert,
7175
isEmpty,
7276
isEqual,
7377
isFinite,
@@ -82,6 +86,7 @@ module.exports = {
8286
isUndefined,
8387
mapKeys,
8488
mapValues,
89+
matches,
8590
max,
8691
mean,
8792
merge,
@@ -98,10 +103,11 @@ module.exports = {
98103
sumBy,
99104
transformKeysToSnake,
100105
union,
106+
uniq,
101107
uniqBy,
102108
uniqWith,
109+
unset,
103110
update,
104111
validateInput,
105-
without,
106-
unset
112+
without
107113
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@bitfinexcom/lib-js-util-base",
3-
"version": "1.20.0",
3+
"version": "1.21.0",
44
"description": "general utils",
55
"main": "index.js",
66
"scripts": {

src/cloneDeep.js

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,46 @@
1+
/* eslint-disable no-prototype-builtins */
2+
13
'use strict'
24

35
const isObject = require('./isObject')
46

5-
const cloneDeep = (obj) => {
6-
if (obj instanceof Function) {
7-
return {}
7+
const cloneDeep = (obj, clones = new WeakMap()) => {
8+
if (obj instanceof Function) return {}
9+
if (!isObject(obj)) return obj
10+
11+
if (clones.has(obj)) return clones.get(obj)
12+
if (obj instanceof Date) return new Date(obj.getTime())
13+
if (obj instanceof RegExp) return new RegExp(obj)
14+
if (obj instanceof Map) {
15+
const newMap = new Map()
16+
clones.set(obj, newMap)
17+
obj.forEach((value, key) => {
18+
newMap.set(cloneDeep(key, clones), cloneDeep(value, clones))
19+
})
20+
return newMap
21+
}
22+
if (obj instanceof Set) {
23+
const newSet = new Set()
24+
clones.set(obj, newSet)
25+
obj.forEach(value => {
26+
newSet.add(cloneDeep(value, clones))
27+
})
28+
return newSet
829
}
9-
if (!isObject(obj)) {
10-
return obj
30+
if (Buffer.isBuffer(obj)) return Buffer.from(obj)
31+
if (ArrayBuffer.isView(obj) && !(obj instanceof DataView)) {
32+
return new obj.constructor(obj)
33+
}
34+
35+
const clonedObj = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj))
36+
clones.set(obj, clonedObj)
37+
Object.defineProperties(clonedObj, Object.getOwnPropertyDescriptors(obj))
38+
39+
for (const key of Object.keys(clonedObj)) {
40+
clonedObj[key] = cloneDeep(clonedObj[key], clones)
1141
}
1242

13-
return JSON.parse(JSON.stringify(obj))
43+
return clonedObj
1444
}
1545

1646
module.exports = cloneDeep

src/differenceWith.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
'use strict'
2+
3+
/**
4+
* @callback IComparator
5+
* @param {any} attrItem
6+
* @param {any} valuesItem
7+
* @returns {boolean}
8+
*/
9+
10+
/**
11+
* Returns the elements of `array` that are not present in other array
12+
* using a comparator function or strict equality.
13+
*
14+
* @param {Array<any>} arr
15+
* @param {Array<any>} items
16+
* @param {IComparator} comparator
17+
* @returns
18+
*/
19+
const differenceWith = (arr, items, comparator) => {
20+
if (!Array.isArray(arr)) {
21+
return []
22+
}
23+
if (!Array.isArray(items) || items.length === 0) {
24+
return arr
25+
}
26+
const _comparator = typeof comparator !== 'function' ? (arrItem, valuesItem) => arrItem === valuesItem : comparator
27+
28+
return arr.filter(el => !items.find(value => _comparator(el, value)))
29+
}
30+
31+
module.exports = differenceWith

src/matches.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict'
2+
3+
const isMatch = require('./isMatch')
4+
5+
/**
6+
* Generates a function that makes a deep partial comparison on a given object with the source
7+
*
8+
* @param {object} src
9+
* @returns {boolean}
10+
*/
11+
const matches = (src) => (obj) => {
12+
return isMatch(obj, src)
13+
}
14+
15+
module.exports = matches

src/uniq.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
'use strict'
2+
3+
/**
4+
* Returns a new array with unique values from the argument array using strict equality.
5+
*
6+
* @param {array<T>} array
7+
* @returns {array<T>}
8+
*/
9+
const uniq = (array) => {
10+
return Array.from(new Set(array))
11+
}
12+
13+
module.exports = uniq

0 commit comments

Comments
 (0)