nhb-toolbox
Version:
A versatile collection of smart, efficient, and reusable utility functions, classes and types for everyday development needs.
213 lines (212 loc) • 7.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseJSON = exports.isDeepEqual = void 0;
exports.convertArrayToString = convertArrayToString;
exports.debounceAction = debounceAction;
exports.throttleAction = throttleAction;
exports.getInstanceMethodNames = getInstanceMethodNames;
exports.getStaticMethodNames = getStaticMethodNames;
exports.countInstanceMethods = countInstanceMethods;
exports.countStaticMethods = countStaticMethods;
exports.getInstanceGetterNames = getInstanceGetterNames;
exports.getStaticGetterNames = getStaticGetterNames;
exports.getClassDetails = getClassDetails;
exports.stableStringify = stableStringify;
exports.stripJsonEdgeGarbage = stripJsonEdgeGarbage;
exports.deepParsePrimitives = deepParsePrimitives;
exports.definePrototypeMethod = definePrototypeMethod;
const helpers_1 = require("../array/helpers");
const sort_1 = require("../array/sort");
const guards_1 = require("../date/guards");
const non_primitives_1 = require("../guards/non-primitives");
const primitives_1 = require("../guards/primitives");
const specials_1 = require("../guards/specials");
const isDeepEqual = (a, b) => {
if (a === b)
return true;
if (typeof a !== typeof b)
return false;
if (a === null || b === null)
return a === b;
if ((0, non_primitives_1.isArray)(a) && (0, non_primitives_1.isArray)(b)) {
if (a?.length !== b?.length)
return false;
return a?.every((element, index) => (0, exports.isDeepEqual)(element, b?.[index]));
}
if ((0, non_primitives_1.isObject)(a) && (0, non_primitives_1.isObject)(b)) {
const aKeys = Object.keys(a);
const bKeys = Object.keys(b);
if (aKeys?.length !== bKeys?.length)
return false;
return aKeys?.every((key) => (0, exports.isDeepEqual)(a?.[key], b?.[key]));
}
return false;
};
exports.isDeepEqual = isDeepEqual;
function convertArrayToString(array, options) {
if (!(0, non_primitives_1.isValidArray)(array))
return '';
const { separator = ', ' } = options ?? {};
if ((0, non_primitives_1.isArrayOfType)(array, primitives_1.isPrimitive)) {
return array?.join(separator);
}
else if ((0, non_primitives_1.isArrayOfType)(array, non_primitives_1.isNotEmptyObject)) {
if (options && 'target' in options) {
return array?.map((el) => (0, helpers_1._resolveNestedKey)(el, options?.target))?.join(separator);
}
else {
return '';
}
}
return '';
}
function debounceAction(callback, delay = 300) {
let timeoutId;
return (...args) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
callback(...args);
}, delay);
};
}
function throttleAction(callback, delay = 150) {
let lastCall = 0;
return (...args) => {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
callback(...args);
}
};
}
function getInstanceMethodNames(cls) {
const prototype = cls.prototype;
const methods = Object.getOwnPropertyNames(prototype).filter((method) => {
if (method === 'constructor') {
return false;
}
const descriptor = Object.getOwnPropertyDescriptor(prototype, method);
return (0, non_primitives_1.isMethodDescriptor)(descriptor);
});
return (0, sort_1.sortAnArray)(methods);
}
function getStaticMethodNames(cls) {
const methods = Object.getOwnPropertyNames(cls).filter((method) => {
return method !== 'prototype' && method !== 'name' && method !== 'length';
});
return (0, sort_1.sortAnArray)(methods);
}
function countInstanceMethods(cls) {
return getInstanceMethodNames(cls)?.length;
}
function countStaticMethods(cls) {
return getStaticMethodNames(cls)?.length;
}
function getInstanceGetterNames(cls) {
const descriptors = Object.getOwnPropertyDescriptors(cls.prototype);
const result = Object.entries(descriptors)
.filter(([key, desc]) => typeof desc.get === 'function' && key !== 'constructor')
.map(([key]) => key);
return (0, sort_1.sortAnArray)(result);
}
function getStaticGetterNames(cls) {
const descriptors = Object.getOwnPropertyDescriptors(cls);
const result = Object.entries(descriptors)
.filter(([key, desc]) => typeof desc.get === 'function' && key !== 'prototype')
.map(([key]) => key);
return (0, sort_1.sortAnArray)(result);
}
function getClassDetails(cls) {
const instanceNames = getInstanceMethodNames(cls);
const staticNames = getStaticMethodNames(cls);
const instanceGetters = getInstanceGetterNames(cls);
const staticGetters = getStaticGetterNames(cls);
return {
instanceMethods: instanceNames,
staticMethods: staticNames,
instanceGetters,
staticGetters,
instanceCount: instanceNames?.length,
staticCount: staticNames?.length,
totalGetters: instanceGetters?.length + staticGetters?.length,
totalMethods: instanceNames?.length + staticNames?.length,
};
}
function stableStringify(obj) {
const _replacer = (_, v) => (v === undefined ? null : v);
if ((0, non_primitives_1.isNotEmptyObject)(obj)) {
const keys = Object.keys(obj).sort();
return ('{' +
keys
.map((k) => JSON.stringify(k, _replacer) +
':' +
((0, guards_1.isDateLike)(obj[k]) ? JSON.stringify(obj[k]) : stableStringify(obj[k])))
.join(',') +
'}');
}
if ((0, non_primitives_1.isValidArray)(obj)) {
return '[' + obj.map((v) => stableStringify(v)).join(',') + ']';
}
return JSON.stringify(obj, _replacer);
}
function stripJsonEdgeGarbage(str) {
if (!(0, primitives_1.isNonEmptyString)(str))
return '';
const lastIdx = Math.max(str.lastIndexOf('}'), str.lastIndexOf(']'));
const _idxOf = (sym) => (str.indexOf(sym) !== -1 ? str.indexOf(sym) : Infinity);
const firstIdx = Math.min(_idxOf('{'), _idxOf('['));
if (lastIdx === -1 || firstIdx === Infinity)
return str;
return str.slice(firstIdx, lastIdx + 1);
}
const parseJSON = (value, parsePrimitives = true) => {
try {
const parsed = JSON.parse(value);
return (parsePrimitives ? deepParsePrimitives(parsed) : parsed);
}
catch {
return {};
}
};
exports.parseJSON = parseJSON;
function deepParsePrimitives(input) {
if (Array.isArray(input)) {
return input?.map(deepParsePrimitives);
}
if ((0, non_primitives_1.isObject)(input)) {
const result = {};
for (const [key, value] of Object.entries(input)) {
result[key] = deepParsePrimitives(value);
}
return result;
}
if ((0, primitives_1.isString)(input)) {
if (/^(true|false)$/i.test(input)) {
return (input?.toLowerCase() === 'true');
}
if ((0, specials_1.isNumericString)(input)) {
return Number(input);
}
if (input === 'null') {
return null;
}
if (input === 'undefined') {
return undefined;
}
return input;
}
return input;
}
function definePrototypeMethod(proto, name, impl, options) {
const alreadyExists = Object.hasOwn(proto, name);
if (alreadyExists && !options?.overwrite)
return;
Object.defineProperty(proto, name, {
value: function (...args) {
return impl.apply(this, args);
},
enumerable: options?.enumerable ?? false,
configurable: options?.configurable ?? false,
writable: options?.writable ?? true,
});
}