/** * @author Martin Karkowski * @email m.karkowski@zema.de * @create date 2020-08-25 23:01:24 * @modify date 2020-11-07 00:35:49 * @desc [description] */ /** * Function to get a singleton. To create the singleton, the parameter *create* is used. This will be called once. * The singleton will be stored as *global* variable and can be accessed by the identifier * * @author M.Karkowski * @export * @template T The Type of the singleton * @param {string} identifier Identifier to access the singleton * @param {() => T} create The Callback which is used to create the instance. * @return An object, containing the key **instances**, where you'll find the instance and an helper function **setInstance** to redefine the instance */ export function getSingleton( identifier: string, create: () => T ): { instance: T; setInstance: (value: T) => void; } { // Extract all const globalSymbols = Object.getOwnPropertySymbols(global); // create a unique, global symbol name // ----------------------------------- const IDENTIFIER_DISPATCHER_CONTAINER = Symbol.for(identifier); // check if the global object has this symbol // add it if it does not have the symbol, yet // ------------------------------------------ const hasContainer = globalSymbols.indexOf(IDENTIFIER_DISPATCHER_CONTAINER) > -1; if (!hasContainer) { global[IDENTIFIER_DISPATCHER_CONTAINER] = create(); } const ret: { instance: T; setInstance: (value: T) => void; } = { instance: global[IDENTIFIER_DISPATCHER_CONTAINER], setInstance: (value: T) => { global[IDENTIFIER_DISPATCHER_CONTAINER] = value; }, }; // define the singleton API // ------------------------ Object.defineProperty(ret, "instance", { get: function () { return global[IDENTIFIER_DISPATCHER_CONTAINER]; }, }); // ensure the API is never changed // ------------------------------- Object.freeze(ret); return ret; }