From 0f2003d0bc842b16f5f359da1eb20bd32d3cfd42 Mon Sep 17 00:00:00 2001 From: Philipp Kunz Date: Mon, 7 Mar 2022 15:28:32 +0100 Subject: [PATCH] fix(core): update --- test/test.smartobject.ts | 23 +++ ts/index.ts | 201 +------------------------- ts/smartobject.classes.smartobject.ts | 25 ++++ ts/smartobject.plugins.ts | 1 - ts/tools/compareobjects.ts | 79 ++++++++++ ts/tools/exists.ts | 14 ++ ts/tools/foreachminimatch.ts | 17 +++ ts/tools/index.ts | 5 + ts/tools/smart_add_get.ts | 92 ++++++++++++ ts/tools/toFlatObject.ts | 18 +++ 10 files changed, 275 insertions(+), 200 deletions(-) create mode 100644 test/test.smartobject.ts create mode 100644 ts/smartobject.classes.smartobject.ts create mode 100644 ts/tools/compareobjects.ts create mode 100644 ts/tools/exists.ts create mode 100644 ts/tools/foreachminimatch.ts create mode 100644 ts/tools/index.ts create mode 100644 ts/tools/smart_add_get.ts create mode 100644 ts/tools/toFlatObject.ts diff --git a/test/test.smartobject.ts b/test/test.smartobject.ts new file mode 100644 index 0000000..691a059 --- /dev/null +++ b/test/test.smartobject.ts @@ -0,0 +1,23 @@ +import { expect, expectAsync, tap} from '@pushrocks/tapbundle'; +import * as smartobject from '../ts'; + +let testSmartobject: smartobject.SmartObject; + +tap.test('should create a smartobject', async () => { + const originalObject = { + test: 'hey', + deep: { + yeah: 'so deep', + evendeeper: { + sodeep: 2, + } + } + } + testSmartobject = new smartobject.SmartObject(originalObject); + testSmartobject.addValueAtFlatPathString('deep.nice', 'yeah that has been added'); + console.log(testSmartobject.originalObject); + console.log(testSmartobject.toFlatObject()) + expect(testSmartobject.getValueAtFlatPathString('deep.yeah')).toEqual('so deep'); +}); + +tap.start(); \ No newline at end of file diff --git a/ts/index.ts b/ts/index.ts index e53365d..7419942 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -1,203 +1,6 @@ import * as plugins from './smartobject.plugins'; - const fastDeepEqual = plugins.fastDeepEqual; export { fastDeepEqual }; -export interface IObjectCompareResult { - presentInBothProperties: string[]; - missingProperties: string[]; - additionalProperties: string[]; - nulledProperties: string[]; - undefinedProperties: string[]; - divergingProperties: string[]; - equalProperties: string[]; -} - -export const compareObjects = ( - referenceObjectArg: any, - comparisonObjectArg: any -): IObjectCompareResult => { - const returnComparisonObject = { - missingProperties: [] as string[], - additionalProperties: [] as string[], - presentInBothProperties: [] as string[], - nulledProperties: [] as string[], - undefinedProperties: [] as string[], - divergingProperties: [] as string[], - equalProperties: [] as string[], - }; - - const allProperties = Object.keys(referenceObjectArg).concat(Object.keys(comparisonObjectArg)); - for (const currentProperty of allProperties) { - // lets find presentInBothProperties - if (referenceObjectArg[currentProperty] && comparisonObjectArg[currentProperty]) { - returnComparisonObject.presentInBothProperties.push(currentProperty); - } - - // lets find missingProperties - if (referenceObjectArg[currentProperty] && !comparisonObjectArg[currentProperty]) { - returnComparisonObject.missingProperties.push(currentProperty); - } - - // lets find additionalProperties - if (!referenceObjectArg[currentProperty] && comparisonObjectArg[currentProperty]) { - returnComparisonObject.additionalProperties.push(currentProperty); - } - - // lets find nulledProperties - if (comparisonObjectArg[currentProperty] === null) { - returnComparisonObject.nulledProperties.push(currentProperty); - } - - // lets find undefinedProperties - if (comparisonObjectArg[currentProperty] === undefined) { - returnComparisonObject.undefinedProperties.push(currentProperty); - } - - // lets find divergingProperties - if ( - JSON.stringify(referenceObjectArg[currentProperty]) !== - JSON.stringify(comparisonObjectArg[currentProperty]) - ) { - returnComparisonObject.divergingProperties.push(currentProperty); - } - - // lets find equalProperties - if ( - JSON.stringify(referenceObjectArg[currentProperty]) === - JSON.stringify(comparisonObjectArg[currentProperty]) - ) { - returnComparisonObject.equalProperties.push(currentProperty); - } - } - - for (const currentProperty of Object.keys(returnComparisonObject)) { - const onlyUnique = (value: any, index: number, self: Array) => { - return self.indexOf(value) === index; - }; - const uniqueArray = returnComparisonObject[currentProperty as keyof(typeof returnComparisonObject)].filter(onlyUnique); - returnComparisonObject[currentProperty as keyof(typeof returnComparisonObject)] = uniqueArray; - } - - return returnComparisonObject; -}; - -/** - * adds an object to the parent object if it doesn't exists - * @param parentObject - * @param childParam - * @param logBool - * @returns {boolean} - */ -export const smartAdd = ( - parentObject: object, - childParam: string, - valueArg: any = {}, - optionsArg?: { - interpretDotsAsLevel: boolean; - } -): typeof parentObject & any => { - optionsArg = { - interpretDotsAsLevel: true, - ...optionsArg - }; - - let paramLevels: string[]; - let referencePointer: any = parentObject; - if (optionsArg.interpretDotsAsLevel) { - paramLevels = childParam.split('.'); - } else { - paramLevels = [childParam]; - } - - for (let i = 0; i !== paramLevels.length; i++) { - const varName: string = paramLevels[i]; - - // is there a next variable ? - const varNameNext: string = (() => { - if (paramLevels[i + 1]) { - return paramLevels[i + 1]; - } - return null; - })(); - - // build the tree in parentObject - if (!referencePointer[varName] && !varNameNext) { - referencePointer[varName] = valueArg; - referencePointer = null; - } else if (!referencePointer[varName] && varNameNext) { - referencePointer[varName] = {}; - referencePointer = referencePointer[varName]; - } else if (referencePointer[varName] && varNameNext) { - referencePointer = referencePointer[varName]; - } else { - throw new Error('Something is strange!'); - } - } - return parentObject; -}; - -/** - * gets an object from the parent object using dots as levels by default - * @param parentObject - * @param childParam - * @param optionsArg - */ -export const smartGet = ( - parentObject: object, - childParam: string, - optionsArg?: { - interpretDotsAsLevel: boolean; - } -): T => { - optionsArg = { - interpretDotsAsLevel: true, - ...optionsArg - }; - - let paramLevels: string[]; - if (optionsArg.interpretDotsAsLevel) { - paramLevels = childParam.split('.'); - } else { - paramLevels = [childParam]; - } - - let referencePointer: any = parentObject; - for (const level of paramLevels) { - if (referencePointer[level as any]) { - referencePointer = referencePointer[level as any]; - } else { - return null; - } - } - return referencePointer as T; -}; - -/** - * checks if an object has a parameter with a given key name, returns true if yes. - * @param parentObject - * @param childParam - * @returns {boolean} - */ -export let exists = (parentObject: object, childParam: string): boolean => { - if (parentObject.hasOwnProperty(childParam)) { - return true; - } - return false; -}; - -/** - * runs a function for all properties of an object whose key matches a regex expression - * @param parentObjectArg the parent object - * @param wildcardArg the rege expression to match the property keys against - * @param callbackArg the function to run with those properties - */ -export let forEachMinimatch = async (parentObjectArg: any, wildcardArg: string, callbackArg: (matchedArg: string) => void) => { - let propertyNames = Object.getOwnPropertyNames(parentObjectArg); - let propertyNamesMatched = propertyNames.filter(propertyNameArg => { - return plugins.minimatch(propertyNameArg, wildcardArg); - }); - for (let propertyNameArg of propertyNamesMatched) { - await callbackArg(parentObjectArg[propertyNameArg]); - } -}; +export * from './smartobject.classes.smartobject'; +export * from './tools'; diff --git a/ts/smartobject.classes.smartobject.ts b/ts/smartobject.classes.smartobject.ts new file mode 100644 index 0000000..c870ddd --- /dev/null +++ b/ts/smartobject.classes.smartobject.ts @@ -0,0 +1,25 @@ +import * as tools from './tools'; + +/** + * a smartobject that simplifies accessing objects + */ +export class SmartObject { + + // instance + public originalObject: object; + constructor(originalObjectArg: object) { + this.originalObject = originalObjectArg; + } + + public getValueAtFlatPathString(pathArg: string) { + return tools.smartGet(this.originalObject, pathArg); + } + + public addValueAtFlatPathString(pathArg: string, valueArg: any) { + return tools.smartAdd(this.originalObject, pathArg, valueArg); + } + + public toFlatObject() { + return tools.toFlatObject(this.originalObject); + } +} \ No newline at end of file diff --git a/ts/smartobject.plugins.ts b/ts/smartobject.plugins.ts index 06bff84..ef82d24 100644 --- a/ts/smartobject.plugins.ts +++ b/ts/smartobject.plugins.ts @@ -1,4 +1,3 @@ - // thirdparty scope // tslint:disable-next-line: no-submodule-imports import fastDeepEqual from 'fast-deep-equal/es6'; diff --git a/ts/tools/compareobjects.ts b/ts/tools/compareobjects.ts new file mode 100644 index 0000000..7543ff9 --- /dev/null +++ b/ts/tools/compareobjects.ts @@ -0,0 +1,79 @@ +import * as plugins from '../smartobject.plugins'; + +export interface IObjectCompareResult { + presentInBothProperties: string[]; + missingProperties: string[]; + additionalProperties: string[]; + nulledProperties: string[]; + undefinedProperties: string[]; + divergingProperties: string[]; + equalProperties: string[]; +} + +export const compareObjects = ( + referenceObjectArg: any, + comparisonObjectArg: any +): IObjectCompareResult => { + const returnComparisonObject = { + missingProperties: [] as string[], + additionalProperties: [] as string[], + presentInBothProperties: [] as string[], + nulledProperties: [] as string[], + undefinedProperties: [] as string[], + divergingProperties: [] as string[], + equalProperties: [] as string[], + }; + + const allProperties = Object.keys(referenceObjectArg).concat(Object.keys(comparisonObjectArg)); + for (const currentProperty of allProperties) { + // lets find presentInBothProperties + if (referenceObjectArg[ currentProperty ] && comparisonObjectArg[ currentProperty ]) { + returnComparisonObject.presentInBothProperties.push(currentProperty); + } + + // lets find missingProperties + if (referenceObjectArg[ currentProperty ] && !comparisonObjectArg[ currentProperty ]) { + returnComparisonObject.missingProperties.push(currentProperty); + } + + // lets find additionalProperties + if (!referenceObjectArg[ currentProperty ] && comparisonObjectArg[ currentProperty ]) { + returnComparisonObject.additionalProperties.push(currentProperty); + } + + // lets find nulledProperties + if (comparisonObjectArg[ currentProperty ] === null) { + returnComparisonObject.nulledProperties.push(currentProperty); + } + + // lets find undefinedProperties + if (comparisonObjectArg[ currentProperty ] === undefined) { + returnComparisonObject.undefinedProperties.push(currentProperty); + } + + // lets find divergingProperties + if ( + JSON.stringify(referenceObjectArg[ currentProperty ]) !== + JSON.stringify(comparisonObjectArg[ currentProperty ]) + ) { + returnComparisonObject.divergingProperties.push(currentProperty); + } + + // lets find equalProperties + if ( + plugins.fastDeepEqual(referenceObjectArg[ currentProperty ], comparisonObjectArg[ currentProperty ]) + ) { + returnComparisonObject.equalProperties.push(currentProperty); + } + } + + for (const currentProperty of Object.keys(returnComparisonObject)) { + const onlyUnique = (value: any, index: number, self: Array) => { + return self.indexOf(value) === index; + }; + const uniqueArray = returnComparisonObject[ currentProperty as keyof (typeof returnComparisonObject) ].filter(onlyUnique); + returnComparisonObject[ currentProperty as keyof (typeof returnComparisonObject) ] = uniqueArray; + } + + return returnComparisonObject; +}; \ No newline at end of file diff --git a/ts/tools/exists.ts b/ts/tools/exists.ts new file mode 100644 index 0000000..fd5a4e2 --- /dev/null +++ b/ts/tools/exists.ts @@ -0,0 +1,14 @@ +import * as plugins from '../smartobject.plugins'; + +/** + * checks if an object has a parameter with a given key name, returns true if yes. + * @param parentObject + * @param childParam + * @returns {boolean} + */ + export let exists = (parentObject: object, childParam: string): boolean => { + if (parentObject.hasOwnProperty(childParam)) { + return true; + } + return false; +}; \ No newline at end of file diff --git a/ts/tools/foreachminimatch.ts b/ts/tools/foreachminimatch.ts new file mode 100644 index 0000000..fe36762 --- /dev/null +++ b/ts/tools/foreachminimatch.ts @@ -0,0 +1,17 @@ +import * as plugins from '../smartobject.plugins'; + +/** + * runs a function for all properties of an object whose key matches a regex expression + * @param parentObjectArg the parent object + * @param wildcardArg the rege expression to match the property keys against + * @param callbackArg the function to run with those properties + */ + export let forEachMinimatch = async (parentObjectArg: any, wildcardArg: string, callbackArg: (matchedArg: string) => void) => { + let propertyNames = Object.getOwnPropertyNames(parentObjectArg); + let propertyNamesMatched = propertyNames.filter(propertyNameArg => { + return plugins.minimatch(propertyNameArg, wildcardArg); + }); + for (let propertyNameArg of propertyNamesMatched) { + await callbackArg(parentObjectArg[propertyNameArg]); + } +}; \ No newline at end of file diff --git a/ts/tools/index.ts b/ts/tools/index.ts new file mode 100644 index 0000000..745eb8a --- /dev/null +++ b/ts/tools/index.ts @@ -0,0 +1,5 @@ +export * from './compareobjects'; +export * from './exists'; +export * from './foreachminimatch'; +export * from './smart_add_get'; +export * from './toFlatObject'; diff --git a/ts/tools/smart_add_get.ts b/ts/tools/smart_add_get.ts new file mode 100644 index 0000000..339fb54 --- /dev/null +++ b/ts/tools/smart_add_get.ts @@ -0,0 +1,92 @@ +import * as plugins from '../smartobject.plugins'; + +/** + * adds an object to the parent object if it doesn't exists + * @param parentObject + * @param childParam + * @param logBool + * @returns {boolean} + */ + export const smartAdd = ( + parentObject: object, + childParam: string, + valueArg: any = {}, + optionsArg?: { + interpretDotsAsLevel: boolean; + } +): typeof parentObject & any => { + optionsArg = { + interpretDotsAsLevel: true, + ...optionsArg + }; + + let paramLevels: string[]; + let referencePointer: any = parentObject; + if (optionsArg.interpretDotsAsLevel) { + paramLevels = childParam.split('.'); + } else { + paramLevels = [childParam]; + } + + for (let i = 0; i !== paramLevels.length; i++) { + const varName: string = paramLevels[i]; + + // is there a next variable ? + const varNameNext: string = (() => { + if (paramLevels[i + 1]) { + return paramLevels[i + 1]; + } + return null; + })(); + + // build the tree in parentObject + if (!referencePointer[varName] && !varNameNext) { + referencePointer[varName] = valueArg; + referencePointer = null; + } else if (!referencePointer[varName] && varNameNext) { + referencePointer[varName] = {}; + referencePointer = referencePointer[varName]; + } else if (referencePointer[varName] && varNameNext) { + referencePointer = referencePointer[varName]; + } else { + throw new Error('Something is strange!'); + } + } + return parentObject; +}; + +/** + * gets an object from the parent object using dots as levels by default + * @param parentObject + * @param childParam + * @param optionsArg + */ +export const smartGet = ( + parentObject: object, + childParam: string, + optionsArg?: { + interpretDotsAsLevel: boolean; + } +): T => { + optionsArg = { + interpretDotsAsLevel: true, + ...optionsArg + }; + + let paramLevels: string[]; + if (optionsArg.interpretDotsAsLevel) { + paramLevels = childParam.split('.'); + } else { + paramLevels = [childParam]; + } + + let referencePointer: any = parentObject; + for (const level of paramLevels) { + if (referencePointer[level as any]) { + referencePointer = referencePointer[level as any]; + } else { + return null; + } + } + return referencePointer as T; +}; \ No newline at end of file diff --git a/ts/tools/toFlatObject.ts b/ts/tools/toFlatObject.ts new file mode 100644 index 0000000..b026314 --- /dev/null +++ b/ts/tools/toFlatObject.ts @@ -0,0 +1,18 @@ +export const toFlatObject = (objectArg: object) => { + const returnObject: {[key: string]: any} = {}; + const extractLayer = (subObject: {[key: string]: any}, pathArg: string, loopProtection: object[]) => { + if (subObject) + for (const key of Object.keys(subObject)) { + let localPathArg = pathArg; + if (typeof subObject[ key ] === 'object') { + const newLoopbackArray = loopProtection.slice(); + newLoopbackArray.push(subObject); + extractLayer(subObject[ key ], localPathArg ? localPathArg += `.${key}` : key, newLoopbackArray); + } else { + returnObject[localPathArg ? localPathArg += `.${key}` : key] = subObject[key]; + } + } + } + extractLayer(objectArg, '', []); + return returnObject; +} \ No newline at end of file