@aedart/support
Version:
The Ion support package
174 lines (164 loc) • 4.58 kB
JavaScript
/**
* @aedart/support
*
* BSD-3-Clause, Copyright (c) 2023-present Alin Eugen Deac <aedart@gmail.com>.
*/
/**
* Return the default string description of an object
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toStringTag
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
*
* @param {any} value
*
* @returns {string}
*/
function descTag(value /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
return Object.prototype.toString.call(value);
}
/**
* Determine if value is empty
*
* @param {any} value
*
* @returns {boolean}
*/
function empty(value /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
if (value === undefined || value === null) {
return true;
}
switch (typeof value) {
case 'boolean':
return !value;
case 'number':
return value === 0 || isNaN(value);
case 'bigint':
return value === 0n;
case 'string':
return value.length === 0;
case 'object':
// Array or array like
if (Array.isArray(value) || ArrayBuffer.isView(value) || descTag(value) === '[object Arguments]') {
return 'length' in value && value.length === 0;
}
// Map / Set
if (value instanceof Map || value instanceof Set) {
return value.size === 0;
}
// Native object
return value.constructor === Object && Object.keys(value).length === 0;
default:
return false;
}
}
/**
* Determine if given key is a valid property key name
*
* @see {PropertyKey}
*
* @param {any} key
*
* @returns {boolean} True if typeof key is a string, number or symbol
*/
function isPropertyKey(key /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
return ['string', 'number', 'symbol'].includes(typeof key);
}
/**
* Determine if given is a valid {@link import('@aedart/contracts/support').Key}
*
* @see {isPropertyKey}
*
* @param {any} key
*
* @returns {boolean}
*/
function isKey(key /* eslint-disable-line @typescript-eslint/no-explicit-any */) {
if (!Array.isArray(key)) {
key = [key];
}
if (key.length === 0) {
return false;
}
for (const entry of key) {
if (!isPropertyKey(entry)) {
return false;
}
}
return true;
}
/**
* Determine if value is a {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#primitive_values primitive value}.
*
* @param {unknown} value
*
* @returns {boolean}
*/
function isPrimitive(value) {
return value !== Object(value);
}
/**
* Determine if value(s) are different from undefined and null
*
* @param {...any} values
*
* @returns {boolean}
*/
function isset(...values) {
if (arguments.length === 0) {
return false;
}
for (const value of values) {
if (value === undefined || value === null) {
return false;
}
}
return true;
}
/**
* Merge multiple {@link Key}s into a single key
*
* @param {...Key} keys
*
* @return {Key} Merged key. Empty key if no arguments given.
*
* @throws {TypeError} If an argument is not a valid key
*/
function mergeKeys(...keys) {
// Return empty key, when no keys given
if (arguments.length === 0) {
return [];
}
const mapped = keys.map((key, index) => {
let modifiedKey = key;
if (!isKey(modifiedKey)) {
throw new TypeError(`mergeKeys(): Argument #${index} must be a valid "key", ${typeof key} given`);
}
if (!Array.isArray(modifiedKey)) {
modifiedKey = [modifiedKey];
}
return modifiedKey;
});
// @ts-expect-error This should be fine here. TS does not understand this merge...
return [].concat(...mapped);
}
/**
* Wraps target into a {@link WeakRef}, if target is not already a weak reference
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef
*
* @template {WeakKey} T
*
* @param {WeakRef<T> | T | undefined} target
*
* @return {WeakRef<T> | undefined} Returns undefined if given target is undefined
*/
function toWeakRef(target) {
if (!isset(target)) {
return undefined;
}
if (target instanceof WeakRef) {
return target;
}
return new WeakRef(target);
}
export { descTag, empty, isKey, isPrimitive, isPropertyKey, isset, mergeKeys, toWeakRef };