mirror of
https://github.com/dzeiocom/libs.git
synced 2025-04-22 10:52:11 +00:00
feat(object-util): add an objectGet function
Signed-off-by: Avior <git@avior.me>
This commit is contained in:
parent
3d74438086
commit
0062c02255
@ -1,6 +1,6 @@
|
|||||||
/// <reference types="jest" />
|
/// <reference types="jest" />
|
||||||
|
|
||||||
import { isObject, objectClean, objectClone, objectEqual, objectFind, objectKeys, objectLoop, objectMap, objectOmit, objectRemap, objectSet, objectSize, objectSort, objectValues } from '../src/ObjectUtil'
|
import { isObject, objectClean, objectClone, objectEqual, objectFind, objectGet, objectKeys, objectLoop, objectMap, objectOmit, objectRemap, objectSet, objectSize, objectSort, objectValues } from '../src/ObjectUtil'
|
||||||
|
|
||||||
describe('Throw if parameter is not an object', () => {
|
describe('Throw if parameter is not an object', () => {
|
||||||
it('should works', () => {
|
it('should works', () => {
|
||||||
@ -486,3 +486,27 @@ describe('object find', () => {
|
|||||||
})).toEqual(undefined)
|
})).toEqual(undefined)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
describe('object get', () => {
|
||||||
|
it('should deeply get an object value', () => {
|
||||||
|
expect(objectGet({a: { b: [{ c: 'pouet' }]}}, ['a', 'b', 0, 'c']))
|
||||||
|
.toEqual('pouet')
|
||||||
|
})
|
||||||
|
it('should deeply get an object value from a string', () => {
|
||||||
|
expect(objectGet({a: { b: [{ c: 'pouet' }]}}, 'a.b.0.c'))
|
||||||
|
.toEqual('pouet')
|
||||||
|
})
|
||||||
|
it('return undefined if key is too profound', () => {
|
||||||
|
expect(objectGet({a: { b: [{ c: 'pouet' }]}}, 'a.b.0.c.d'))
|
||||||
|
.toEqual(undefined)
|
||||||
|
})
|
||||||
|
it('return the object if key is too shallow', () => {
|
||||||
|
expect(objectGet({a: { b: [{ c: 'pouet' }]}}, 'a.b.0'))
|
||||||
|
.toEqual({ c: 'pouet' })
|
||||||
|
})
|
||||||
|
it('return undefined if key is invalid', () => {
|
||||||
|
expect(objectGet({a: { b: [{ c: 'pouet' }]}}, 'a.c.0'))
|
||||||
|
.toEqual(undefined)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
@ -40,15 +40,21 @@ export function objectMap<T = any, J = any, K extends BasicObjectKeys = BasicObj
|
|||||||
export function objectRemap<T = any, J extends BasicObject = BasicObject, K extends BasicObjectKeys = BasicObjectKeys>(
|
export function objectRemap<T = any, J extends BasicObject = BasicObject, K extends BasicObjectKeys = BasicObjectKeys>(
|
||||||
obj: BasicObject<K, T>,
|
obj: BasicObject<K, T>,
|
||||||
fn: (value: T, key: K, index: number) => {key: keyof J, value: J[typeof key]},
|
fn: (value: T, key: K, index: number) => {key: keyof J, value: J[typeof key]},
|
||||||
options?: {strict?: boolean}
|
options?: { strict?: boolean }
|
||||||
): J {
|
): J {
|
||||||
mustBeObject(obj)
|
mustBeObject(obj)
|
||||||
|
|
||||||
|
// create a clone
|
||||||
const clone: J = {} as any
|
const clone: J = {} as any
|
||||||
|
|
||||||
|
// loop through each keys
|
||||||
objectLoop(obj, (item, oldKey, index) => {
|
objectLoop(obj, (item, oldKey, index) => {
|
||||||
const { key, value } = fn(item, oldKey, index)
|
const { key, value } = fn(item, oldKey, index)
|
||||||
if (options?.strict && key in clone) {
|
if (options?.strict && key in clone) {
|
||||||
throw new Error('objectRemap strict mode active, you can\'t remap the same key twice')
|
throw new Error('objectRemap strict mode active, you can\'t remap the same key twice')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set new key pair into the clone
|
||||||
clone[key] = value
|
clone[key] = value
|
||||||
})
|
})
|
||||||
return clone
|
return clone
|
||||||
@ -66,7 +72,11 @@ export function objectLoop<T = any, K extends BasicObjectKeys = BasicObjectKeys>
|
|||||||
fn: (value: T, key: K, index: number) => boolean | void
|
fn: (value: T, key: K, index: number) => boolean | void
|
||||||
): boolean {
|
): boolean {
|
||||||
mustBeObject(obj)
|
mustBeObject(obj)
|
||||||
|
|
||||||
|
// get the object keys
|
||||||
const keys = objectKeys(obj)
|
const keys = objectKeys(obj)
|
||||||
|
|
||||||
|
// loop trough each keys
|
||||||
for (let index = 0; index < keys.length; index++) {
|
for (let index = 0; index < keys.length; index++) {
|
||||||
const key = keys[index]
|
const key = keys[index]
|
||||||
const stop = fn(obj[key] as T, key as K, index)
|
const stop = fn(obj[key] as T, key as K, index)
|
||||||
@ -327,6 +337,49 @@ export function objectFind<T = any, K extends BasicObjectKeys = BasicObjectKeys>
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* go through an object to get a specific value
|
||||||
|
*
|
||||||
|
* note: it will be slower than getting it directly (ex: `obj['pouet']`)
|
||||||
|
*
|
||||||
|
* @param obj the object to go through
|
||||||
|
* @param {Array<string | number | symbol> | string} path the path to follow (if path is a string it will be splitted with `.` and ints will be parsed)
|
||||||
|
*
|
||||||
|
* @returns the value if found or undefined if it was not found
|
||||||
|
*/
|
||||||
|
export function objectGet<T = any>(obj: object, path: Array<string | number | symbol> | string): T | undefined {
|
||||||
|
mustBeObject(obj)
|
||||||
|
|
||||||
|
// transform path into an Array
|
||||||
|
if (typeof path === 'string') {
|
||||||
|
path = path.split('.').map((it) => /^\d+$/g.test(it) ? Number.parseInt(it) : it)
|
||||||
|
}
|
||||||
|
|
||||||
|
// the pointer
|
||||||
|
let pointer: object = obj
|
||||||
|
|
||||||
|
// loop through each keys
|
||||||
|
for (let index = 0; index < path.length; index++) {
|
||||||
|
const key = path[index]
|
||||||
|
const nextIndex = index + 1;
|
||||||
|
|
||||||
|
// handle key being undefined or pointer not having key and not the last key
|
||||||
|
if (typeof key === 'undefined' || !Object.prototype.hasOwnProperty.call(pointer, key) && nextIndex < path.length) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
// if last index
|
||||||
|
if (nextIndex === path.length) {
|
||||||
|
return (pointer as any)[key] as T
|
||||||
|
}
|
||||||
|
|
||||||
|
// move pointer to new key
|
||||||
|
pointer = (pointer as any)[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`it should never be here ! (${JSON.stringify(obj)}, ${path}, ${JSON.stringify(pointer)})`)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return if an item is an object
|
* return if an item is an object
|
||||||
*
|
*
|
||||||
@ -346,28 +399,32 @@ export function isObject(item: any): item is BasicObject {
|
|||||||
* @returns {boolean} true is the item is an object, else throw an error
|
* @returns {boolean} true is the item is an object, else throw an error
|
||||||
*/
|
*/
|
||||||
export function mustBeObject(item: any): item is BasicObject {
|
export function mustBeObject(item: any): item is BasicObject {
|
||||||
if (isObject(item)) {
|
if (!isObject(item)) {
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
throw new Error('Input is not an object!')
|
throw new Error('Input is not an object!')
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
objectMap,
|
objectClean,
|
||||||
objectRemap,
|
objectClone,
|
||||||
objectLoop,
|
objectEqual,
|
||||||
objectToArray,
|
objectFind,
|
||||||
|
objectGet,
|
||||||
objectKeys,
|
objectKeys,
|
||||||
|
objectLoop,
|
||||||
|
objectMap,
|
||||||
|
objectOmit,
|
||||||
|
objectRemap,
|
||||||
|
objectSet,
|
||||||
objectSize,
|
objectSize,
|
||||||
objectSort,
|
objectSort,
|
||||||
cloneObject,
|
|
||||||
objectClone,
|
// helpers
|
||||||
objectSet,
|
|
||||||
objectEqual,
|
|
||||||
objectClean,
|
|
||||||
objectOmit,
|
|
||||||
objectFind,
|
|
||||||
isObject,
|
isObject,
|
||||||
mustBeObject
|
mustBeObject,
|
||||||
|
|
||||||
|
// deprecated
|
||||||
|
objectToArray,
|
||||||
|
cloneObject,
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user