142 lines
4.3 KiB
TypeScript
142 lines
4.3 KiB
TypeScript
/**
|
|
* @author Martin Karkowski
|
|
* @email m.karkowski@zema.de
|
|
* @create date 2019-01-16 23:10:38
|
|
* @modify date 2019-01-16 23:10:38
|
|
* @desc [description]
|
|
*/
|
|
|
|
import { IPubSubSystem, ITopic } from '../../ZISS-Publish-And-Subscribe-System/type/interfaces';
|
|
import { rgetattr, rsetattr } from '../../ZISS-TypeScript-Library/src/Object-Methods';
|
|
|
|
export const REF_IDENTIFIER = '$ref';
|
|
|
|
|
|
/**
|
|
* Function scans the Object for Refs.
|
|
*
|
|
* @export
|
|
* @param {*} data
|
|
* @param {{[index: string] : string}} [ret={}]
|
|
* @param {string} [path='']
|
|
* @param {string} [splitchar='.']
|
|
* @returns
|
|
*/
|
|
export function extractRefs(data: any, ret: Array<{ fullpath: string, prepath: string, segment: string, src: string }> = [], path = '', segment = '', splitchar = '.') {
|
|
|
|
if (Array.isArray(data) || (typeof data === 'object')) {
|
|
if (data[REF_IDENTIFIER] !== undefined) {
|
|
ret.push({
|
|
/** Extract the Reference */
|
|
src: data[REF_IDENTIFIER],
|
|
/** Full-Path */
|
|
fullpath: path,
|
|
/** If no splitchar is in the Path => its only the Segment, otherwise remove the Segment and Splitchar */
|
|
prepath: path.includes(splitchar) ? path.slice(0, path.length - (splitchar.length + segment.length)) : '',
|
|
/** Idenfier of the current Attribute */
|
|
segment: segment
|
|
});
|
|
|
|
return ret;
|
|
} else {
|
|
/** Iterate over the Array */
|
|
for (const identifier in data) {
|
|
/** Iterate over the Elements of the Object */
|
|
ret = extractRefs(data[identifier], ret, path !== '' ? path + splitchar + identifier : identifier, identifier, splitchar);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* Function to Figure out, whether an Object has Refs
|
|
*
|
|
* @export
|
|
* @param {*} data
|
|
* @returns {boolean}
|
|
*/
|
|
export function hasRefs(data: any): boolean {
|
|
return Object.getOwnPropertyNames(extractRefs(data)).length > 0;
|
|
}
|
|
|
|
function _updateGetterAndSetter(obj, segment, topic: ITopic<any>, readonly) {
|
|
return Object.defineProperty(obj, segment, {
|
|
get: () => topic.getContent(),
|
|
set: (value) => {
|
|
if (readonly) {
|
|
throw Error('Element is Read-Only');
|
|
} else {
|
|
topic.setContent(value, undefined, undefined, 'direct')
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
export function integrateDataFromRefs(data: any, pubSubSystem: IPubSubSystem, mode: 'static' | 'dynamic' = 'static', readonly = true) {
|
|
|
|
const refs = extractRefs(data)
|
|
|
|
for (const ref of refs) {
|
|
if (ref.prepath == '') {
|
|
if (ref.segment == '') {
|
|
if (mode == 'dynamic') {
|
|
throw Error('Trying to return a dynamic value on a ref-Object. This is not Possible')
|
|
}
|
|
|
|
else {
|
|
return pubSubSystem.getTopic(ref.src).getContent();
|
|
}
|
|
} else {
|
|
data = _updateGetterAndSetter(data, ref.segment, pubSubSystem.getTopic(ref.src), readonly);
|
|
}
|
|
} else {
|
|
const topic = pubSubSystem.getTopic(ref.src);
|
|
|
|
switch (mode) {
|
|
case 'static':
|
|
/** Set the Attribute to a Static Value */
|
|
rsetattr(data, ref.fullpath, topic.getContent());
|
|
break;
|
|
|
|
case 'dynamic':
|
|
/** Extract the Segment and Update it */
|
|
let segment = rgetattr(data, ref.prepath);
|
|
segment = _updateGetterAndSetter(segment, ref.segment, pubSubSystem.getTopic(ref.src), readonly);
|
|
rsetattr(data, ref.prepath, segment);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return data
|
|
}
|
|
|
|
declare const require;
|
|
declare const module;
|
|
|
|
if (require.main === module) {
|
|
|
|
console.log(extractRefs({
|
|
a: {
|
|
b: {
|
|
c: {
|
|
$ref: 'anderer.element'
|
|
}
|
|
},
|
|
c: 'Hier sind normale Daten',
|
|
d: [{
|
|
$ref: 'anderes.array.element'
|
|
}, 1, 2, {
|
|
a: {
|
|
$ref: 'anderes.array.element'
|
|
}
|
|
}]
|
|
}
|
|
}));
|
|
|
|
console.log(extractRefs({ a: { $ref: 'spast' } }));
|
|
|
|
console.log(extractRefs({ $ref: 'spast' }));
|
|
} |