@schukai/monster
Version:
Monster is a simple library for creating fast, robust and lightweight websites.
136 lines (121 loc) • 3.6 kB
JavaScript
/**
* Copyright © Volker Schukai 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 Volker Schukai.
*
* SPDX-License-Identifier: AGPL-3.0
*/
import { instanceSymbol } from "../constants.mjs";
export { Base };
/**
* This is the base class from which the most classes are derived.
*
* This class has besides a `toString` which returns the json representation of the object
* also a functionality to check if an object is an instance of a class.
*
* Therefore, the class has a static method <code>[Symbol.hasInstance](that)</code> which returns true if the object
* is an instance of the class.
*
* <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/hasInstance">MDN Symbol.hasInstance</a>
*
* Derived classes should implement a static getter `instanceSymbol` which returns a unique symbol.
*
* <code lang="javascript">
* static get [instanceSymbol]() {
* return Symbol.for("@schukai/monster/types/base");
* }
* </code>
*
* The class was formerly called Object.
*
* @since 1.5.0
* @copyright Volker Schukai
* @summary The base class for the most classes in the monster library
*/
class Base extends Object {
/**
* @return {string}
*/
toString() {
return JSON.stringify(this);
}
/**
* This method is called by the `instanceof` operator.
* @return {symbol}
* @since 2.1.0
*/
static get [instanceSymbol]() {
return Symbol.for("@schukai/monster/types/base");
}
/**
* This method is called by the `instanceof` operator.
* @param that
* @return {boolean}
* @since 2.1.0
*/
static [Symbol.hasInstance](that) {
if (
that === undefined ||
that === null ||
(typeof that !== "object" && typeof that !== "function")
) {
return false;
}
const thatClass = Object.getPrototypeOf(that);
if (
thatClass === undefined ||
thatClass === null ||
(typeof thatClass !== "object" && typeof thatClass !== "function")
) {
return false;
}
if (checkInstanceSymbol.apply(this, [thatClass]) === true) {
return true;
}
// this call the static method of the super class, if there is one
return super[Symbol.hasInstance](that);
}
}
/**
* this function checks if the class has a static getter <code>instanceSymbol</code>,
* and if the value of this getter is equal to the
*
* @private
* @param obj
* @return {boolean|any|boolean}
* @since 2.1.0
*/
function checkInstanceSymbol(obj) {
if (this.hasOwnProperty(instanceSymbol) === false) {
return false;
}
const proto = obj?.constructor;
if (
proto === undefined ||
proto === null ||
(typeof proto !== "object" && typeof proto !== "function")
) {
return false;
}
if (proto.hasOwnProperty(instanceSymbol) !== true) {
return checkInstanceSymbol.apply(this, [obj.__proto__]);
}
const symbol = proto[instanceSymbol];
if (symbol === undefined) {
if (obj.__proto__) {
return checkInstanceSymbol(obj.__proto__);
} else {
return false;
}
}
if (symbol === this[instanceSymbol]) {
return true;
}
return checkInstanceSymbol.apply(this, [obj.__proto__]);
}