UNPKG

@schukai/monster

Version:

Monster is a simple library for creating fast, robust and lightweight websites.

185 lines (162 loc) 4.13 kB
/** * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved. * Node module: @schukai/monster * * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3). * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html * * For those who do not wish to adhere to the AGPLv3, a commercial license is available. * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms. * For more information about purchasing a commercial license, please contact schukai GmbH. * * SPDX-License-Identifier: AGPL-3.0 */ import { internalSymbol } from "../constants.mjs"; import { extend } from "../data/extend.mjs"; import { Pathfinder } from "../data/pathfinder.mjs"; import { parseDataURL } from "./dataurl.mjs"; import { isString } from "./is.mjs"; import { Observer } from "./observer.mjs"; import { ProxyObserver } from "./proxyobserver.mjs"; import { validateObject } from "./validate.mjs"; import { isObject } from "./is.mjs"; export { equipWithInternal }; /** * @private * @type {string} */ const propertyName = "internalDefaults"; /** * This function extends the given object with the following methods: * * - attachInternalObserver * - detachInternalObserver * - containsInternalObserver * - setInternal * - setInternals * - getInternal * * @license AGPLv3 * @since 3.15.0 * @copyright schukai GmbH */ function equipWithInternal() { validateObject(this); if (!hasGetter(this, propertyName)) { Object.defineProperty(this, propertyName, { get: function () { return {}; }, }); } const defaults = extend({}, this[propertyName] || {}); this[internalSymbol] = new ProxyObserver(defaults); /** * Attach a new observer * * @param {Observer} observer * @return {ProxyObserver} */ this["attachInternalObserver"] = (observer) => { this[internalSymbol].attachObserver(observer); return this; }; /** * Detach a observer * * @param {Observer} observer * @return {ProxyObserver} */ this["detachInternalObserver"] = (observer) => { this[internalSymbol].detachObserver(observer); return this; }; /** * Check if a observer is attached * * @param {Observer} observer * @return {boolean} */ this["containsInternalObserver"] = (observer) => { return this[internalSymbol].containsObserver(observer); }; /** * Set an internal value, nested internals can be specified by path `a.b.c` * * @param {string} path * @param {*} value * @return {Datasource} */ this["setInternal"] = (path, value) => { new Pathfinder(this[internalSymbol].getSubject()).setVia(path, value); return this; }; /** * set multiple internals at once * * @param {string|object} options * @return {Datasource} * @throws {Error} the options does not contain a valid json definition */ this["setInternals"] = (options) => { if (isString(options)) { options = parseOptionsJSON(options); } extend(this[internalSymbol].getSubject(), defaults, options); return this; }; /** * path 'a.b.c can specify nested internals` * * @param {string} path * @param {*} defaultValue * @return {*} */ this["getInternal"] = (path, defaultValue) => { let value; try { value = new Pathfinder(this[internalSymbol].getRealSubject()).getVia( path, ); } catch (e) {} if (value === undefined) return defaultValue; return value; }; } /** * @private * @param obj * @param prop * @return {boolean} */ function hasGetter(obj, prop) { while (isObject(obj)) { if (Object.getOwnPropertyDescriptor(obj, prop)?.["get"]) { return true; } obj = Object.getPrototypeOf(obj); } return false; } /** * @private * @param data * @return {Object} */ function parseOptionsJSON(data) { let obj = {}; if (!isString(data)) { return obj; } // the configuration can be specified as a data url. try { const dataUrl = parseDataURL(data); data = dataUrl.content; } catch (e) {} try { obj = JSON.parse(data); } catch (e) { throw e; } return validateObject(obj); }