@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
185 lines (162 loc) • 4.13 kB
JavaScript
/**
* 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);
}