@rzl-zone/utils-js
Version:
A modern, lightweight set of JavaScript utility functions with TypeScript support for everyday development, crafted to enhance code readability and maintainability.
553 lines (537 loc) • 22.2 kB
JavaScript
/*!
* ====================================================
* Rzl Utils-JS.
* ----------------------------------------------------
* Version: 3.11.0.
* Author: Rizalvin Dwiky.
* Repository: https://github.com/rzl-zone/utils-js.
* ====================================================
*/
import { isNonEmptyValue, isTypedArray } from './chunk-TJHGRQ4P.js';
import { filterNilArray } from './chunk-22V4WP3H.js';
import { isEmptyString } from './chunk-ULQPCIA2.js';
import { assertIsString } from './chunk-3T6VSWYX.js';
import { isRegExp, isEqual } from './chunk-GXKQ3LHF.js';
import { isEmptyObject, isEmptyArray } from './chunk-GOFINGT6.js';
import { assertIsArray } from './chunk-RZOGBYIS.js';
import { safeStableStringify, isDate, isMap } from './chunk-AXDYWO67.js';
import { isBigInt } from './chunk-QNKGP5DY.js';
import { assertIsPlainObject, hasOwnProp, assertIsBoolean, isArray, isNull, getPreciseType, isNaN, isString, isNumber, isBoolean, isNil, isNumberObject, isBooleanObject, isStringObject, isSymbol, isFunction, isObjectOrArray, isError, isSet, isObject, isNonEmptyString, isPlainObject, isUndefined, isInfinityNumber, isBuffer } from './chunk-MSUW5VHZ.js';
function toNumberArrayUnRecursive(array, options = {}) {
assertIsPlainObject(options, {
message: ({ currentType, validType }) => `Second parameter (\`options\`) must be of type \`${validType}\`, but received: \`${currentType}\`.`
});
const riv = hasOwnProp(options, "removeInvalidValueNumber") ? options.removeInvalidValueNumber : true;
assertIsBoolean(riv, {
message: ({ currentType, validType }) => `Parameter \`removeInvalidValueNumber\` property of the \`options\` (second parameter) must be of type \`${validType}\`, but received: \`${currentType}\`.`
});
if (isArray(array)) {
const result = Array.from(array, (x) => {
if (isBigInt(x)) return Number(x);
const str = String(x).trim();
const match = str.match(/-?\d+(\.\d+)?/);
return match ? Number(match[0]) : isNull(x) ? null : void 0;
});
return riv ? filterNilArray(result) : result;
}
return void 0;
}
function toStringDeepForce(value, forceToString) {
if (!(forceToString === false || forceToString === "stringOrNumber" || forceToString === "primitives" || forceToString === "all")) {
throw new TypeError(
`Second parameter \`forceToString\` must be of type \`false\` or \`string\` with value one of "stringOrNumber" | "primitives" | "all", but received: \`${getPreciseType(
forceToString
)}\`, with value: \`${safeStableStringify(forceToString, {
keepUndefined: true
})}\`.`
);
}
if (isNaN(value)) {
return forceToString === "primitives" || forceToString === "all" ? "NaN" : NaN;
}
if (isString(value) || isNumber(value)) {
return forceToString === "stringOrNumber" || forceToString === "primitives" || forceToString === "all" ? String(value) : value;
}
if (isBoolean(value) || isBigInt(value) || isNil(value)) {
return forceToString === "primitives" || forceToString === "all" ? String(value) : value;
}
if (isNumberObject(value) || isBooleanObject(value) || isStringObject(value)) {
return forceToString === "all" ? value.valueOf().toString() : value;
}
if (isSymbol(value)) {
return forceToString === "all" ? value.toString() : value;
}
if (isFunction(value)) {
return forceToString === "all" ? value.toString() : value;
}
if (isArray(value)) {
return value.map((v) => toStringDeepForce(v, forceToString));
}
if (isObjectOrArray(value)) {
if (isDate(value)) {
return forceToString === "all" ? value.toISOString() : value;
}
if (isRegExp(value)) {
return forceToString === "all" ? value.toString() : value;
}
if (isError(value) || value instanceof Promise) {
return forceToString === "all" ? value.toString() : value;
}
if (isSet(value)) {
return forceToString === "all" ? [...value].map((v) => toStringDeepForce(v, forceToString)) : value;
}
if (isMap(value)) {
return forceToString === "all" ? [...value.entries()].map(([k, v]) => [
toStringDeepForce(k, forceToString),
toStringDeepForce(v, forceToString)
]) : value;
}
const result = {};
if (isObject(value)) {
for (const key of Object.keys(value)) {
result[key] = toStringDeepForce(value[key], forceToString);
}
}
return result;
}
return value;
}
var dedupeArray = (inputArray, options = {}) => {
assertIsArray(inputArray, {
message: ({ currentType, validType }) => `First parameter (\`inputArray\`) must be of type \`${validType}\` (array literal or instance), but received: \`${currentType}\`.`
});
assertIsPlainObject(options, {
message: ({ currentType, validType }) => `Second parameter (\`options\`) must be of type \`${validType}\`, but received: \`${currentType}\`.`
});
const flatten = hasOwnProp(options, "flatten") ? options.flatten : false;
const forceToString = hasOwnProp(options, "forceToString") ? options.forceToString : false;
if (!(forceToString === false || forceToString === "stringOrNumber" || forceToString === "primitives" || forceToString === "all")) {
throw new TypeError(
`Parameter \`forceToString\` property of the \`options\` (second parameter) must be of type \`false\` or \`string\` with value one of "stringOrNumber" | "primitives" | "all", but received: \`${getPreciseType(
forceToString
)}\`, with value: \`${safeStableStringify(forceToString, {
keepUndefined: true
})}\`.`
);
}
assertIsBoolean(flatten, {
message: ({ currentType, validType }) => `Parameter \`flatten\` property of the \`options\` (second parameter) must be of type \`${validType}\`, but received: \`${currentType}\`.`
});
const process = (arr) => {
const seen = [];
return arr.reduce((acc, item) => {
const value = isArray(item) ? process(item) : toStringDeepForce(item, forceToString);
if (!seen.some((s) => isEqual(s, value))) {
seen.push(value);
acc.push(value);
}
return acc;
}, []);
};
const deepFlatten = (value) => {
if (isArray(value)) {
return value.flatMap(deepFlatten);
}
if (isSet(value)) {
return [...value].flatMap(deepFlatten);
}
if (isMap(value)) {
return [...value.values()].flatMap(deepFlatten);
}
return [value];
};
return flatten ? process(deepFlatten(inputArray)) : process(inputArray);
};
var toBooleanContent = (value) => {
if (isNil(value)) return false;
if (isString(value)) return isNonEmptyString(value);
if (isBoolean(value)) return value;
if (isNumber(value, { includeNaN: true })) return value !== 0;
if (isArray(value) || isObject(value)) return isNonEmptyValue(value);
return Boolean(value);
};
var toBooleanContentDeep = (value) => {
if (isNil(value)) return false;
if (isString(value)) return isNonEmptyString(value);
if (isBoolean(value)) return value;
if (isNumber(value, { includeNaN: true })) return value !== 0;
if (isArray(value)) return value.some(toBooleanContentDeep);
if (isObject(value)) return Object.values(value).some(toBooleanContentDeep);
return false;
};
var toBooleanExplicit = (value, options = {}) => {
if (isNil(value)) return false;
if (!isPlainObject(options)) options = {};
const ci = hasOwnProp(options, "caseInsensitive") ? options.caseInsensitive : false;
const ts = hasOwnProp(options, "trimString") ? options.trimString : true;
const incInd = hasOwnProp(options, "includeIndeterminate") ? options.includeIndeterminate : false;
if (!isBoolean(ci) || !isBoolean(ts) || !isBoolean(incInd)) {
throw new TypeError(
`Parameters \`caseInsensitive\`, \`trimString\` and \`includeIndeterminate\` property of the \`options\` (second parameter) expected to be a \`boolean\` type, but received: ['caseInsensitive': \`${getPreciseType(
ci
)}\`, 'trimString': \`${getPreciseType(
ts
)}\`, 'includeIndeterminate': \`${getPreciseType(incInd)}\`].`
);
}
if (isString(value)) {
let normalized = value;
if (ts) normalized = normalized.trim();
if (ci) normalized = normalized.toLowerCase();
const validTrueStrings = ["true", "on", "yes", "1"];
if (incInd) validTrueStrings.push("indeterminate");
return validTrueStrings.includes(normalized);
}
if (isNumber(value)) return value === 1;
if (isBoolean(value)) return value;
return false;
};
var toBooleanLoose = (value) => {
if (isNil(value)) return false;
if (isString(value)) return !isEmptyString(value);
if (isBoolean(value)) return value;
if (isNumber(value, { includeNaN: true })) return value !== 0;
if (isArray(value)) return value.length > 0;
return Boolean(value);
};
var convertType = (value) => {
const predefinedValues = {
undefined: void 0,
null: null,
nan: NaN,
true: true,
false: false,
yes: true,
no: false
};
if (isString(value)) {
const normalized = value.trim().toLowerCase();
if (Object.prototype.hasOwnProperty.call(predefinedValues, normalized)) {
return predefinedValues[normalized];
}
const numericString = normalized.replace(/,/g, "");
const numberString = Number(numericString);
if (!isNaN(numberString) && isNonEmptyString(numericString)) {
return numberString;
}
return value.trim();
}
return value;
};
var deepCloneSafe = (obj) => {
try {
if (isFunction(structuredClone)) {
return structuredClone(obj);
}
} catch {
}
return JSON.parse(JSON.stringify(obj));
};
var deleteNestedKey = (obj, path) => {
if (!isObjectOrArray(obj)) return obj;
const [currentKey, ...rest] = path;
if (isArray(obj)) {
for (const item of obj) {
if (isObjectOrArray(item)) deleteNestedKey(item, path);
}
} else if (isEmptyArray(rest)) {
if (isPlainObject(obj)) delete obj[currentKey];
} else if (isPlainObject(obj) && isObjectOrArray(obj[currentKey])) {
deleteNestedKey(obj[currentKey], rest);
}
return obj;
};
var deleteExactPathOnce = (obj, path) => {
if (!isPlainObject(obj)) return obj;
const [currentKey, ...rest] = path;
if (rest.length === 0) {
if (isPlainObject(obj)) delete obj[currentKey];
} else if (isPlainObject(obj[currentKey])) {
deleteExactPathOnce(obj[currentKey], rest);
}
return obj;
};
function removeObjectPaths(object, keysToDelete, deepClone = true) {
if (isEmptyObject(object, { checkSymbols: true }))
return {};
assertIsArray(keysToDelete, {
message: ({ currentType, validType }) => `Second parameter (\`keysToDelete\`) must be of type \`${validType}\` with value of { key: string, deep?: boolean } plain-object, but received: \`${currentType}\`, with value: \`${safeStableStringify(
keysToDelete,
{
keepUndefined: true
}
)}\`.`
});
if (!keysToDelete.every((k) => isPlainObject(k) && "key" in k)) {
throw new TypeError(
`Each element in Second Parameter (\`keysToDelete\`) must be of type \`plain-object\` with at least a "key" property (optionally "deep"), but received: \`${safeStableStringify(
keysToDelete,
{
keepUndefined: true
}
)}\`.`
);
}
let result = deepClone ? deepCloneSafe(object) : object;
for (const { key, deep } of keysToDelete) {
assertIsString(key, {
message: ({ currentType, validType }) => `Parameter \`key\` at Second Parameter (\`keysToDelete\`) must be of type \`${validType}\`, but received: \`${currentType}\`.`
});
if (!isUndefined(deep) && !isBoolean(deep)) {
throw new TypeError(
`Parameter \`deep\` at Second Parameter (\`keysToDelete\`) \u2794 (key: "${key}", deep: ${deep}) must be of type \`boolean\` or \`undefined\`, but received: \`${getPreciseType(
deep
)}\`.`
);
}
const path = key.split(".");
result = deep ? deleteNestedKey(result, path) : deleteExactPathOnce(result, path);
}
return result;
}
function toNumberDeep(input, options = {}) {
assertIsPlainObject(options, {
message: ({ currentType, validType }) => `Second parameter (\`options\`) must be of type \`${validType}\`, but received: \`${currentType}\`.`
});
const removeEmptyObjects = hasOwnProp(options, "removeEmptyObjects") ? options.removeEmptyObjects : false;
const removeEmptyArrays = hasOwnProp(options, "removeEmptyArrays") ? options.removeEmptyArrays : false;
function _internal(input2, options2) {
if (isNil(input2) || isRegExp(input2)) return void 0;
const { removeEmptyArrays: removeEmptyArrays2, removeEmptyObjects: removeEmptyObjects2, isRoot } = options2;
if (!isBoolean(removeEmptyObjects2) || !isBoolean(removeEmptyArrays2)) {
throw new TypeError(
`Parameters \`removeEmptyObjects\` and \`removeEmptyArrays\` property of the \`options\` (second parameter) must be of type \`boolean\`, but received: ['removeEmptyObjects': \`${getPreciseType(
removeEmptyObjects2
)}\`, 'removeEmptyArrays': \`${getPreciseType(removeEmptyArrays2)}\`].`
);
}
if (isNumber(input2) || isBoolean(input2) || isNonEmptyString(input2)) {
const num = Number(input2);
return isInfinityNumber(num) || isNaN(num) ? void 0 : num;
}
if (isNumberObject(input2) || isStringObject(input2) || isBooleanObject(input2)) {
const valOf = Number(input2.valueOf());
return isInfinityNumber(valOf) || isNaN(valOf) ? void 0 : valOf;
}
if (isDate(input2, { skipInvalidDate: true })) {
try {
return !isNaN(input2.getTime()) ? input2.getTime() : 0;
} catch {
return 0;
}
}
if (isBuffer(input2)) {
const arr = Array.from(input2).map(
(n) => _internal(n, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
})
).filter((item) => !isUndefined(item));
if (removeEmptyArrays2 && isEmptyArray(arr)) return void 0;
return arr;
}
if (isTypedArray(input2)) {
if (input2 instanceof BigInt64Array || input2 instanceof BigUint64Array) {
const newArray = Array.from(input2).map(
(item) => _internal(item, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
})
).filter((item) => !isUndefined(item));
if (removeEmptyArrays2 && isEmptyArray(newArray)) return void 0;
return newArray;
} else {
const newArray = Array.from(input2).map(
(item) => _internal(item, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
})
).filter((item) => !isUndefined(item));
if (removeEmptyArrays2 && isEmptyArray(newArray)) return void 0;
return newArray;
}
}
if (isSet(input2)) {
const newArray = Array.from(input2).map(
(item) => _internal(item, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
})
).filter((item) => !isUndefined(item));
if (removeEmptyArrays2 && isEmptyArray(newArray)) return void 0;
return newArray;
}
if (isMap(input2)) {
let newArray = Array.from(input2.entries()).map(([k, v]) => {
const key = _internal(k, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
});
const value = _internal(v, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
});
return !isUndefined(key) && !isUndefined(value) ? [key, value] : void 0;
}).filter((item) => !isUndefined(item));
if (removeEmptyArrays2) {
newArray = newArray.filter((v) => !isEmptyArray(v));
}
if (removeEmptyArrays2 && isEmptyArray(newArray)) return void 0;
return newArray;
}
if (isArray(input2)) {
const newArray = input2.map(
(item) => _internal(item, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
})
).filter((item) => !isUndefined(item));
if (removeEmptyArrays2 && isEmptyArray(newArray)) return void 0;
return newArray;
}
if (isObject(input2)) {
const newObject = {};
for (const [key, value] of Object.entries(input2)) {
const convertedValue = _internal(value, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
});
if (!isUndefined(convertedValue)) {
newObject[key] = convertedValue;
}
}
if (removeEmptyObjects2 && isEmptyObject(newObject)) {
return isRoot ? {} : void 0;
}
return newObject;
}
return void 0;
}
return _internal(input, {
removeEmptyObjects,
removeEmptyArrays,
isRoot: true
});
}
function toStringDeep(input, options = {}) {
assertIsPlainObject(options, {
message: ({ currentType, validType }) => `Second parameter (\`options\`) must be of type \`${validType}\`, but received: \`${currentType}\`.`
});
const removeEmptyObjects = hasOwnProp(options, "removeEmptyObjects") ? options.removeEmptyObjects : false;
const removeEmptyArrays = hasOwnProp(options, "removeEmptyArrays") ? options.removeEmptyArrays : false;
function _internal(input2, options2) {
if (isNil(input2) || isInfinityNumber(input2)) return void 0;
const { removeEmptyArrays: removeEmptyArrays2, removeEmptyObjects: removeEmptyObjects2, isRoot } = options2;
if (!isBoolean(removeEmptyObjects2) || !isBoolean(removeEmptyArrays2)) {
throw new TypeError(
`Parameters \`removeEmptyObjects\` and \`removeEmptyArrays\` property of the \`options\` (second parameter) must be of type \`boolean\`, but received: ['removeEmptyObjects': \`${getPreciseType(
removeEmptyObjects2
)}\`, 'removeEmptyArrays': \`${getPreciseType(removeEmptyArrays2)}\`].`
);
}
if (isNumber(input2) || isString(input2) || isBoolean(input2)) return String(input2);
if (isNumberObject(input2)) {
const valOf = input2.valueOf();
return isInfinityNumber(valOf) || isNaN(valOf) ? void 0 : valOf.toString();
}
if (isStringObject(input2)) return input2.valueOf();
if (isBooleanObject(input2)) return input2.valueOf().toString();
if (isDate(input2, { skipInvalidDate: true })) {
try {
return input2.toISOString();
} catch {
return input2.toString();
}
}
if (isRegExp(input2)) return input2.toString();
if (isBuffer(input2)) {
return Array.from(input2).map((v) => String(v)).filter((v) => !isUndefined(v));
}
if (isTypedArray(input2)) {
if (input2 instanceof BigInt64Array || input2 instanceof BigUint64Array) {
const newArray = Array.from(input2).map(
(item) => _internal(item, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
})
).map((v) => String(v)).filter((item) => !isUndefined(item));
if (removeEmptyArrays2 && isEmptyArray(newArray)) return void 0;
return newArray;
} else {
const newArray = Array.from(input2).map(
(item) => _internal(item, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
})
).map((v) => String(v)).filter((item) => !isUndefined(item));
if (removeEmptyArrays2 && isEmptyArray(newArray)) return void 0;
return newArray;
}
}
if (isSet(input2)) {
const arr = Array.from(input2).map(
(v) => _internal(v, { removeEmptyObjects: removeEmptyObjects2, removeEmptyArrays: removeEmptyArrays2, isRoot: false })
).filter((v) => !isUndefined(v));
if (removeEmptyArrays2 && isEmptyArray(arr)) return void 0;
return arr;
}
if (isMap(input2)) {
const arr = Array.from(input2.entries()).map(([k, v]) => [
_internal(k, { removeEmptyObjects: removeEmptyObjects2, removeEmptyArrays: removeEmptyArrays2, isRoot: false }),
_internal(v, { removeEmptyObjects: removeEmptyObjects2, removeEmptyArrays: removeEmptyArrays2, isRoot: false })
]).filter(([k, v]) => !isUndefined(k) && !isUndefined(v));
if (removeEmptyArrays2 && isEmptyArray(arr)) return void 0;
return arr;
}
if (isArray(input2)) {
let newArray = input2.map(
(item) => _internal(item, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
})
).filter((item) => !isUndefined(item));
if (removeEmptyArrays2) {
newArray = newArray.filter((v) => !(isArray(v) && v.length === 0));
}
if (removeEmptyArrays2 && isEmptyArray(newArray)) return void 0;
return newArray;
}
if (isObject(input2)) {
const newObject = {};
for (const [key, value] of Object.entries(input2)) {
const convertedValue = _internal(value, {
removeEmptyObjects: removeEmptyObjects2,
removeEmptyArrays: removeEmptyArrays2,
isRoot: false
});
if (!isUndefined(convertedValue)) {
newObject[key] = convertedValue;
} else if (isArray(value) && !removeEmptyArrays2) {
newObject[key] = [];
}
}
if (removeEmptyObjects2 && Object.keys(newObject).length === 0) {
return isRoot ? {} : void 0;
}
return newObject;
}
return void 0;
}
return _internal(input, {
removeEmptyObjects,
removeEmptyArrays,
isRoot: true
});
}
export { convertType, dedupeArray, removeObjectPaths, toBooleanContent, toBooleanContentDeep, toBooleanExplicit, toBooleanLoose, toNumberArrayUnRecursive, toNumberDeep, toStringDeep, toStringDeepForce };