/** * @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, 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' })); }