mirror of
https://github.com/dzeiocom/libs.git
synced 2025-06-07 08:39:56 +00:00
Added Tests and Documentation
Signed-off-by: Florian Bouillon <florian.bouillon@delta-wings.net>
This commit is contained in:
parent
f5b54f1816
commit
5c230d74e5
5
packages/object-util/.eslintrc.js
Normal file
5
packages/object-util/.eslintrc.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
"parserOptions": {
|
||||||
|
"project": __dirname + "/tsconfig.json"
|
||||||
|
}
|
||||||
|
}
|
65
packages/object-util/README.md
Normal file
65
packages/object-util/README.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# URL Manager
|
||||||
|
|
||||||
|
simple to use yet powerful Urls parser and formatter
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
- Import URLManager
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import ObjectUtil from '@dzeio/object-util'
|
||||||
|
// or
|
||||||
|
const ObjectUtil = require('@dzeio/object-util').default
|
||||||
|
|
||||||
|
// or you can import each funcitons individually
|
||||||
|
```
|
||||||
|
|
||||||
|
- or import it from the browser
|
||||||
|
|
||||||
|
```html
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/@dzeio/object-util@1/dist/browser.js"></script>
|
||||||
|
<!-- It will be available as the same variable -->
|
||||||
|
```
|
||||||
|
|
||||||
|
- Create a new instance
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Create a new instance
|
||||||
|
const url = new URLManager() // you can have an URL, URLSearchParams Objects or a string as parameter
|
||||||
|
// or
|
||||||
|
const url = URLManager.fromLocation() // Browser only return a new instance from the current location
|
||||||
|
```
|
||||||
|
|
||||||
|
- explore !
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
|
||||||
|
// Does the same as Array.map
|
||||||
|
objectMap(object, (value, key) => {value + "pouet"})
|
||||||
|
|
||||||
|
// does the same as Array.forEach with the addon of stopping if false is returned (like break)
|
||||||
|
// and return if loop was finished or not
|
||||||
|
objectLoop(object, (value, key) => {})
|
||||||
|
|
||||||
|
// return the values of an object as an array
|
||||||
|
objectToArray(object)
|
||||||
|
|
||||||
|
// return the keys of an object as an array
|
||||||
|
ObjectKeys(object)
|
||||||
|
|
||||||
|
// return the count of an object keys
|
||||||
|
objectSize(object)
|
||||||
|
|
||||||
|
// like Array.sort it sort and return an ordered object
|
||||||
|
objectSort(object, /*optionnal*/ (key1, key2) => key1 - key2)
|
||||||
|
|
||||||
|
// deeply clone an object
|
||||||
|
cloneObject(object)
|
||||||
|
|
||||||
|
// deeply set an object value while creating empty childs if necessary
|
||||||
|
//ex: this will return {path1, [{path3: 'value'}]} if object is an empty object
|
||||||
|
objectSet(object, ['path1', 0, 'path3'], 'value')
|
||||||
|
|
||||||
|
// deeply compare two objects
|
||||||
|
objectEqual(object, object2)
|
||||||
|
```
|
@ -1,9 +1,58 @@
|
|||||||
/// <reference types="jest" />
|
/// <reference types="jest" />
|
||||||
|
|
||||||
import { objectSize, objectToArray, objectMap, objectSort, cloneObject, objectEqual } from '../src/ObjectUtil'
|
import { objectSize, objectToArray, objectMap, objectSort, cloneObject, objectEqual, objectKeys, objectSet, objectLoop } from '../src/ObjectUtil'
|
||||||
|
|
||||||
|
describe('Object Map tests', () => {
|
||||||
|
it('should works', () => {
|
||||||
|
const obj = {
|
||||||
|
pouet: 'first',
|
||||||
|
toto: 'second'
|
||||||
|
}
|
||||||
|
expect(objectMap(obj, (value, index) => {
|
||||||
|
return [index, value]
|
||||||
|
})).toEqual([['pouet', 'first'],['toto','second']])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('Basic tests', () => {
|
describe('Object Loop Tests', () => {
|
||||||
|
it('Should works', () => {
|
||||||
|
const obj = {
|
||||||
|
pouet: true,
|
||||||
|
toto: 'object-util'
|
||||||
|
}
|
||||||
|
objectLoop(obj, (value, key) => {
|
||||||
|
if (key === 'pouet') {
|
||||||
|
expect(value).toBe(true)
|
||||||
|
} else if (key === 'toto') {
|
||||||
|
expect(value).toBe('object-util')
|
||||||
|
} else {
|
||||||
|
throw "it should not come here"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Object To Array Tests', () => {
|
||||||
|
it('Should Works', () => {
|
||||||
|
const obj = {
|
||||||
|
pouet: 'first',
|
||||||
|
toto: 'second'
|
||||||
|
}
|
||||||
|
expect(objectToArray(obj)).toEqual(['first', 'second'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Object Keys Tests', () => {
|
||||||
|
it('Should Works', () => {
|
||||||
|
const obj = {
|
||||||
|
pouet: 'first',
|
||||||
|
toto: 'second'
|
||||||
|
}
|
||||||
|
expect(objectKeys(obj)).toEqual(['pouet', 'toto'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Object Sort Tests', () => {
|
||||||
it('shoud return length of the object', () => {
|
it('shoud return length of the object', () => {
|
||||||
const obj = {
|
const obj = {
|
||||||
index0: true,
|
index0: true,
|
||||||
@ -20,25 +69,9 @@ describe('Basic tests', () => {
|
|||||||
}
|
}
|
||||||
expect(objectSize(obj)).toBe(11)
|
expect(objectSize(obj)).toBe(11)
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('should convert the object to an array', () => {
|
describe('Object sort Tests', () => {
|
||||||
const obj = {
|
|
||||||
pouet: 'first',
|
|
||||||
toto: 'second'
|
|
||||||
}
|
|
||||||
expect(objectToArray(obj)).toEqual(['first', 'second'])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should run through the object', () => {
|
|
||||||
const obj = {
|
|
||||||
pouet: 'first',
|
|
||||||
toto: 'second'
|
|
||||||
}
|
|
||||||
expect(objectMap(obj, (value, index) => {
|
|
||||||
return [index, value]
|
|
||||||
})).toEqual([['pouet', 'first'],['toto','second']])
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should sort the object', () => {
|
it('should sort the object', () => {
|
||||||
const obj = {
|
const obj = {
|
||||||
b: 'first',
|
b: 'first',
|
||||||
@ -49,7 +82,9 @@ describe('Basic tests', () => {
|
|||||||
b: 'first'
|
b: 'first'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Object Clone Tests', () => {
|
||||||
it('should clone the object', () => {
|
it('should clone the object', () => {
|
||||||
const obj = {
|
const obj = {
|
||||||
pouet: 'first',
|
pouet: 'first',
|
||||||
@ -71,7 +106,39 @@ describe('Basic tests', () => {
|
|||||||
clone.toto = 'third'
|
clone.toto = 'third'
|
||||||
expect(clone).not.toEqual(obj)
|
expect(clone).not.toEqual(obj)
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
|
describe('Object Set Tests', () => {
|
||||||
|
it('set the value of an empty object', () => {
|
||||||
|
const obj = {}
|
||||||
|
objectSet(obj, ['test'], true)
|
||||||
|
expect(obj).toEqual({test: true})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('set the deep value of an empty object', () => {
|
||||||
|
const obj = {}
|
||||||
|
objectSet(obj, ['test', 'pouet'], true)
|
||||||
|
expect(obj).toEqual({test: {'pouet': true}})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('set the deep first array value of an empty object', () => {
|
||||||
|
const obj = {}
|
||||||
|
objectSet(obj, ['test', 0], true)
|
||||||
|
expect(obj).toEqual({test: [true]})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('set the deep any array value of an empty object', () => {
|
||||||
|
const obj = {}
|
||||||
|
objectSet(obj, ['test', 2], true)
|
||||||
|
expect(obj).toEqual({test: [undefined, undefined, true]})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('delete the deep value of an object', () => {
|
||||||
|
const obj = {test: {pouet: true}}
|
||||||
|
objectSet(obj, ['test', 'pouet'], undefined)
|
||||||
|
expect(obj).toEqual({test: {}})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('Object Equal Test', () => {
|
describe('Object Equal Test', () => {
|
||||||
it('should be equal', () => {
|
it('should be equal', () => {
|
||||||
@ -83,6 +150,13 @@ describe('Object Equal Test', () => {
|
|||||||
it('should be deeply equal', () => {
|
it('should be deeply equal', () => {
|
||||||
expect(objectEqual({pouet: {is: true}}, {pouet: {is: true}})).toBe(true)
|
expect(objectEqual({pouet: {is: true}}, {pouet: {is: true}})).toBe(true)
|
||||||
})
|
})
|
||||||
|
it('should not be equal if lengths are differents', () => {
|
||||||
|
expect(objectEqual({pouet: true, added: true }, {pouet: true})).toBe(false)
|
||||||
|
expect(objectEqual({pouet: true }, {pouet: true, added: true})).toBe(false)
|
||||||
|
})
|
||||||
|
it('should not be equal if lengths are equal but content different', () => {
|
||||||
|
expect(objectEqual({pouet: true, added: true }, {pouet: true, removed: true})).toBe(false)
|
||||||
|
})
|
||||||
it('should not be deeply equal', () => {
|
it('should not be deeply equal', () => {
|
||||||
expect(objectEqual({pouet: {is: true}}, {pouet: {is: false}})).toBe(false)
|
expect(objectEqual({pouet: {is: true}}, {pouet: {is: false}})).toBe(false)
|
||||||
})
|
})
|
||||||
|
@ -1,43 +1,84 @@
|
|||||||
export const objectMap = <T = any, J = any>(items: Record<string, T>, fn: (el: T, key: string) => J) => {
|
/**
|
||||||
|
* Remap an object to an array through a function
|
||||||
|
*
|
||||||
|
* (Same as Array.map)
|
||||||
|
* @param obj the object to remap
|
||||||
|
* @param fn the fn to run
|
||||||
|
*/
|
||||||
|
export function objectMap<T = any, J = any>(obj: Record<string, T>, fn: (value: T, key: string) => J): Array<J> {
|
||||||
const list: Array<J> = []
|
const list: Array<J> = []
|
||||||
objectLoop(items, (item, key) => {
|
objectLoop(obj, (item, key) => {
|
||||||
list.push(fn(item, key))
|
list.push(fn(item, key))
|
||||||
})
|
})
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
export const objectLoop = <T = any>(items: Record<string, T>, fn: (el: T, key: string) => void | boolean) => {
|
/**
|
||||||
let res: void | boolean
|
* Loop through the object
|
||||||
for (const key in items) {
|
* @param obj the object to loop through
|
||||||
if (!Object.prototype.hasOwnProperty.call(items, key)) {
|
* @param fn the function to run for each childs
|
||||||
|
*/
|
||||||
|
export function objectLoop<T = any>(obj: Record<string, T>, fn: (value: T, key: string) => boolean | void): boolean {
|
||||||
|
for (const key in obj) {
|
||||||
|
if (!Object.prototype.hasOwnProperty.call(obj, key)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
res = fn(items[key], key)
|
const stop = fn(obj[key], key)
|
||||||
if (typeof res === 'boolean' && !res) {
|
if (stop === false) {
|
||||||
return res
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform an object to an array removing the keys
|
||||||
|
* @param obj the object to transform
|
||||||
|
*/
|
||||||
export function objectToArray<T = any>(obj: Record<string, T>): Array<T> {
|
export function objectToArray<T = any>(obj: Record<string, T>): Array<T> {
|
||||||
return Object.values(obj)
|
return Object.values(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function objectSize(obj: Record<string, any>) {
|
/**
|
||||||
return Object.keys(obj).length
|
* return the keys of th object
|
||||||
|
* @param obj the object
|
||||||
|
*/
|
||||||
|
export function objectKeys(obj: Record<string, any>): Array<string> {
|
||||||
|
return Object.keys(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function objectSort<T = Record<string, any>>(obj: Record<string, any>, fn?: (a: string, b: string) => number): T {
|
/**
|
||||||
const ordered: any = {};
|
* return the length of an object
|
||||||
for (const key of Object.keys(obj).sort(fn)) {
|
* @param obj the object
|
||||||
|
*/
|
||||||
|
export function objectSize(obj: Record<string, any>): number {
|
||||||
|
return objectKeys(obj).length
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort an object by its keys
|
||||||
|
*
|
||||||
|
* Same as Array.sort
|
||||||
|
* @param obj the object to sort
|
||||||
|
* @param fn (Optionnal) the function to run to sort
|
||||||
|
*/
|
||||||
|
export function objectSort<T = Record<string, any>>(
|
||||||
|
obj: Record<string, any>,
|
||||||
|
fn?: (a: string, b: string) => number
|
||||||
|
): T {
|
||||||
|
const ordered: any = {}
|
||||||
|
for (const key of objectKeys(obj).sort(fn)) {
|
||||||
ordered[key] = obj[key]
|
ordered[key] = obj[key]
|
||||||
}
|
}
|
||||||
return ordered
|
return ordered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deeply clone an object
|
||||||
|
* @param obj the object to clone
|
||||||
|
*/
|
||||||
export function cloneObject<T = Record<string, any>>(obj: T): T {
|
export function cloneObject<T = Record<string, any>>(obj: T): T {
|
||||||
const clone: T = {} as any
|
const clone: Partial<T> = {}
|
||||||
objectLoop(obj, (value, key) => {
|
objectLoop(obj, (value, key) => {
|
||||||
if (typeof value === 'object' && value != null) {
|
if (typeof value === 'object' && value != null) {
|
||||||
clone[key as Extract<keyof T, string>] = cloneObject(value)
|
clone[key as Extract<keyof T, string>] = cloneObject(value)
|
||||||
@ -45,10 +86,20 @@ export function cloneObject<T = Record<string, any>>(obj: T): T {
|
|||||||
}
|
}
|
||||||
clone[key as Extract<keyof T, string>] = value
|
clone[key as Extract<keyof T, string>] = value
|
||||||
})
|
})
|
||||||
return clone
|
return clone as T
|
||||||
}
|
}
|
||||||
|
|
||||||
export function objectSet(obj: Record<string, any>, path: Array<string | number>, value: any) {
|
/**
|
||||||
|
* deeply set the value at the path given
|
||||||
|
*
|
||||||
|
* (Create sub object/array if not made)
|
||||||
|
*
|
||||||
|
* _NOTE: it is way quicker to use obj[path][path]... = value_
|
||||||
|
* @param obj the object to set the value
|
||||||
|
* @param path the path
|
||||||
|
* @param value the value
|
||||||
|
*/
|
||||||
|
export function objectSet(obj: Record<string, any>, path: Array<string | number>, value: any): void {
|
||||||
let pointer = obj
|
let pointer = obj
|
||||||
for (let index = 0; index < path.length; index++) {
|
for (let index = 0; index < path.length; index++) {
|
||||||
const key = path[index]
|
const key = path[index]
|
||||||
@ -74,7 +125,15 @@ export function objectSet(obj: Record<string, any>, path: Array<string | number>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* deeply compare objects and return if they are equal or not
|
||||||
|
* @param x the first object
|
||||||
|
* @param y the second object
|
||||||
|
*/
|
||||||
export function objectEqual(x: Record<string, any>, y: Record<string, any>): boolean {
|
export function objectEqual(x: Record<string, any>, y: Record<string, any>): boolean {
|
||||||
|
if (objectSize(x) !== objectSize(y)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
const res = objectLoop(x, (item, key) => {
|
const res = objectLoop(x, (item, key) => {
|
||||||
if (!(key in y)) {
|
if (!(key in y)) {
|
||||||
return false
|
return false
|
||||||
@ -85,9 +144,6 @@ export function objectEqual(x: Record<string, any>, y: Record<string, any>): boo
|
|||||||
}
|
}
|
||||||
return item === item2
|
return item === item2
|
||||||
})
|
})
|
||||||
if (typeof res !== 'boolean') {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +151,7 @@ export default {
|
|||||||
objectMap,
|
objectMap,
|
||||||
objectLoop,
|
objectLoop,
|
||||||
objectToArray,
|
objectToArray,
|
||||||
|
objectKeys,
|
||||||
objectSize,
|
objectSize,
|
||||||
objectSort,
|
objectSort,
|
||||||
cloneObject,
|
cloneObject,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user