sat-utils
Version:
420 lines • 17.1 kB
JavaScript
/* eslint-disable sonarjs/cognitive-complexity, unicorn/no-object-as-default-parameter, unicorn/prefer-string-replace-all*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.toArray = toArray;
exports.prettifyCamelCase = prettifyCamelCase;
exports.execNumberExpression = execNumberExpression;
exports.camelize = camelize;
exports.safeJSONstringify = safeJSONstringify;
exports.shuffleArrMutable = shuffleArrMutable;
exports.safeHasOwnPropery = safeHasOwnPropery;
exports.shuffleArr = shuffleArr;
exports.chunkArr = chunkArr;
exports.lengthToIndexesArray = lengthToIndexesArray;
exports.getRandomNumberFromRange = getRandomNumberFromRange;
exports.getStringifyReadyData = getStringifyReadyData;
exports.canBeStringified = canBeStringified;
exports.safeJSONparse = safeJSONparse;
exports.stringifyData = stringifyData;
exports.getStringEqualtyPersentage = getStringEqualtyPersentage;
const types_1 = require("./types");
/**
* Converts a value or an array of values to an array.
*
* @template T
* @param {T | T[]} anyArgument - The value or array to convert.
* @param {T | T[]} undefinedIsFine - Return arr with undefined member is argument is undefined
* @returns {T[]} An array containing the input value(s).
*/
function toArray(anyArgument, undefinedIsFine = false) {
if (anyArgument === undefined) {
return (undefinedIsFine ? [anyArgument] : []);
}
return Array.isArray(anyArgument) ? Array.from(anyArgument) : [anyArgument];
}
/**
* Splits an array into multiple smaller arrays.
*
* @template T
* @param {T[]} arr - The input array.
* @param {number} chunksAmount - The number of smaller arrays to create.
* @param {boolean} [followIndex=false] - If true, chunks will have approximately equal lengths; otherwise, they will be balanced.
* @returns {Array<T[]>} An array of smaller arrays.
* @throws {TypeError} If the input is not an array or the chunk size is not a number.
*/
function chunkArr(arr, chunksAmount, followIndex = false) {
if (!Array.isArray(arr)) {
throw new TypeError(`chunkArr(): first argument should be an array, current arg is ${(0, types_1.getType)(arr)}`);
}
if (!(0, types_1.isNumber)(chunksAmount)) {
throw new TypeError(`chunkArr(): second argument should be a number, current arg is ${(0, types_1.getType)(chunksAmount)}`);
}
if (!(0, types_1.isBoolean)(followIndex)) {
throw new TypeError(`chunkArr(): third argument should be a boolean, current arg is ${(0, types_1.getType)(followIndex)}`);
}
const copied = toArray(arr);
if (followIndex) {
const chunkMax = Math.ceil(copied.length / chunksAmount);
const chunkReg = Math.floor(copied.length / chunksAmount);
const chunked = [];
for (let i = 0; i < chunksAmount; i++) {
chunked.push(copied.splice(0, i ? chunkReg : chunkMax));
}
return chunked.filter(chunk => chunk.length);
}
else {
const chunked = Array.from({ length: chunksAmount }).map(() => []);
let index = 0;
for (const item of copied) {
chunked[index].push(item);
index++;
if (index === chunked.length) {
index = 0;
}
}
return chunked.filter(chunk => chunk.length);
}
}
/**
* Shuffles an array in place.
*
* @template T
* @param {T[]} arr - The array to shuffle.
* @throws {TypeError} If the input is not an array.
*/
function shuffleArrMutable(arr) {
if (!Array.isArray(arr)) {
throw new TypeError(`shuffleArrMutable(): first argument should be an array, current arg is ${(0, types_1.getType)(arr)}`);
}
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
}
/**
* Shuffles a copy of an array.
*
* @template T
* @param {T[]} arr - The input array.
* @returns {T[]} A shuffled copy of the input array.
* @throws {TypeError} If the input is not an array.
*/
function shuffleArr(arr) {
if (!Array.isArray(arr)) {
throw new TypeError(`shuffleArr(): first argument should be an array, current arg is ${(0, types_1.getType)(arr)}`);
}
const newArr = Array.from(arr);
shuffleArrMutable(newArr);
return newArr;
}
/**
* Options for the prettifyCamelCase function.
*
* @typedef {Object} TcamelCase
* @property {boolean} [firstWordUpperCase=false] - If true, the first word will start with an uppercase letter.
* @property {boolean} [allUpperCase=false] - If true, the entire string will be in uppercase.
* @property {string} [joinWords=' '] - The string to use for joining words.
*/
/**
* Prettifies a camelCase string.
*
* @param {string} camelCaseString - The camelCase string to prettify.
* @param {TcamelCase} [_opts] - Options for prettifying the string.
* @returns {string} The prettified string.
* @throws {TypeError} If the input is not a string or the options are not valid.
*/
function prettifyCamelCase(camelCaseString, _opts = { firstWordUpperCase: false, joinWords: ' ' }) {
const defaultOpts = { firstWordUpperCase: false, joinWords: ' ', allUpperCase: false };
if (!(0, types_1.isString)(camelCaseString)) {
throw new TypeError(`prettifyCamelCase(): first argument should be a string, current arg is ${(0, types_1.getType)(camelCaseString)}`);
}
if (!(0, types_1.isObject)(_opts)) {
throw new TypeError(`prettifyCamelCase(): second argument should be an object, current arg is ${(0, types_1.getType)(_opts)}`);
}
const opts = { ...defaultOpts, ..._opts };
if (!(0, types_1.isBoolean)(opts.firstWordUpperCase)) {
throw new TypeError(`prettifyCamelCase(): second argument "firstWordUpperCase" property should be a boolean, current arg is ${(0, types_1.getType)(opts.firstWordUpperCase)}`);
}
if (!(0, types_1.isBoolean)(opts.allUpperCase)) {
throw new TypeError(`prettifyCamelCase(): second argument "allUpperCase" property should be a boolean, current arg is ${(0, types_1.getType)(opts.firstWordUpperCase)}`);
}
if (!(0, types_1.isString)(opts.joinWords)) {
throw new TypeError(`prettifyCamelCase(): second argument "joinWords" property should be a string, current arg is ${(0, types_1.getType)(opts.joinWords)}`);
}
const { firstWordUpperCase, joinWords, allUpperCase } = opts;
let humanReadableString = '';
for (let index = 0; index < camelCaseString.length; index++) {
const char = camelCaseString.charAt(index);
if (index === 0) {
humanReadableString += char.toUpperCase();
}
else if (char !== char.toLowerCase() && char === char.toUpperCase()) {
humanReadableString += `${joinWords}${char}`;
}
else {
humanReadableString += char;
}
}
const firstWordUp = firstWordUpperCase
? humanReadableString
.split(' ')
.map((word, index) => (index === 0 ? word : word.toLocaleLowerCase()))
.join(' ')
: humanReadableString;
return allUpperCase ? firstWordUp.toUpperCase() : firstWordUp;
}
/**
* Checks if a mathematical expression is true for a given number.
*
* @param {string} expression - The mathematical expression to evaluate.
* @param {number} numberArg - The number to use in the expression.
* @returns {boolean} True if the expression is true for the given number; otherwise, false.
* @throws {TypeError} If the expression is not a string or the number is not a number.
*/
function execNumberExpression(expression, numberArg) {
if (!(0, types_1.isString)(expression)) {
throw new TypeError(`checkNumberExpression(): first argument should be a string, current arg is ${(0, types_1.getType)(numberArg)}`);
}
if (!(0, types_1.isNumber)(numberArg)) {
throw new TypeError(`checkNumberExpression(): second argument should be a number, current arg is ${(0, types_1.getType)(numberArg)}`);
}
try {
const expressions = expression.toLowerCase().split('and');
return expressions.every(expressionPart => eval(`${numberArg} ${expressionPart}`));
}
catch {
return false;
}
}
/**
* Converts a string to camelCase.
*
* @param {string} str - The input string.
* @returns {string} The string in camelCase.
* @throws {TypeError} If the input is not a string.
*/
function camelize(str) {
if (!(0, types_1.isString)(str)) {
throw new TypeError(`camelize(): first argument should be a string, current arg is ${(0, types_1.getType)(str)}`);
}
return str
.replace(/^\w|[A-Z]|\b\w/g, function (word, index) {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
})
.replace(/\s+/g, '');
}
/**
* Safely converts an object to a JSON string.
*
* @param {*} data - The data to stringify.
* @param {boolean} [inline=false] - If true, the resulting JSON will be on a single line.
* @param {*} [returnIfError=''] - The value to return if an error occurs during stringification.
* @returns {string} The JSON string or the specified return value if an error occurs.
*/
function safeJSONstringify(data, inline = false, returnIfError = '') {
try {
const shouldBeStringified = inline ? [data] : [data, null, '\t'];
return JSON.stringify.apply(global, shouldBeStringified);
}
catch {
return returnIfError;
}
}
/**
* Safely parses a JSON string.
*
* @param {*} data - The JSON string to parse.
* @param {*} [returnIfError={}] - The value to return if an error occurs during parsing.
* @returns {*} The parsed JSON object or the specified return value if an error occurs.
*/
function safeJSONparse(data, returnIfError = {}) {
try {
return JSON.parse(data);
}
catch {
return returnIfError;
}
}
/**
* Checks if an object has a specified property.
*
* @param {*} item - The object to check.
* @param {string} key - The property key to check for.
* @returns {boolean} True if the object has the property; otherwise, false.
* @throws {TypeError} If the key is not a string.
*/
function safeHasOwnPropery(item, key) {
if (!(0, types_1.isString)(key) && !(0, types_1.isSymbol)(key)) {
throw new TypeError(`safeHasOwnPropery(): second argument should be a string or symbol, current arg is ${(0, types_1.getType)(key)}`);
}
if ((0, types_1.isUndefined)(item) || (0, types_1.isNull)(item)) {
return false;
}
return Object.prototype.hasOwnProperty.call(item, key);
}
/**
* Generates an array of indexes from 0 to a specified length.
*
* @param {number} length - The length of the resulting array.
* @returns {number[]} An array of indexes.
* @throws {TypeError} If the length is not a number.
*/
function lengthToIndexesArray(length) {
if (!(0, types_1.isNumber)(length)) {
throw new TypeError(`lengthToIndexes(): first argument should be a number, current arg is ${(0, types_1.getType)(length)}`);
}
return Array.from({ length }, (_item, index) => index);
}
/**
* Generates a random number within a specified range.
*
* @param {number} min - The minimum value of the range (inclusive).
* @param {number} max - The maximum value of the range (exclusive).
* @returns {number} A random number within the specified range.
* @throws {TypeError} If the min or max values are not numbers.
*/
function getRandomNumberFromRange(min, max) {
if (!(0, types_1.isNumber)(min)) {
throw new TypeError(`getRandomNumberFromRange(): first argument should be a number, current arg is ${(0, types_1.getType)(min)}`);
}
if (!(0, types_1.isNumber)(max)) {
throw new TypeError(`getRandomNumberFromRange(): second argument should be a number, current arg is ${(0, types_1.getType)(min)}`);
}
return Math.floor(Math.random() * (max - min)) + min;
}
/**
* Checks if an object can be safely converted to a JSON string.
*
* @param {*} item - The object to check.
* @returns {boolean} True if the object can be converted to JSON; otherwise, false.
*/
function canBeStringified(item) {
try {
JSON.stringify(item);
return true;
}
catch {
return false;
}
}
/**
* Filters and returns an object with only stringifiable values.
*
* @param {*} data - The input data.
* @returns {*} An object with only stringifiable values or an empty string if none are found.
*/
function getStringifyReadyData(data) {
if ((0, types_1.isObject)(data)) {
const copied = {};
for (const key of Object.keys(data)) {
if (canBeStringified(data[key])) {
copied[key] = data[key];
}
}
return copied;
}
if ((0, types_1.isArray)(data)) {
return data.map(data_item => getStringifyReadyData(data_item));
}
if ((0, types_1.isPrimitive)(data) && canBeStringified(data)) {
return data;
}
return '';
}
/**
* Converts an object to a string.
*
* @param {*} obj - The object to convert.
* @param {TstringifyDataConfig} [config] - Configuration options.
* @returns {string} The string representation of the object.
*/
function stringifyData(obj, config) {
if ((0, types_1.isPrimitive)(obj)) {
return String(obj);
}
if ((0, types_1.isFunction)(obj) || (0, types_1.isAsyncFunction)(obj)) {
return config?.ignoreFunctions ? 'function' : obj.toString();
}
if ((0, types_1.isArray)(obj)) {
const arrString = obj.map(item => stringifyData(item, config)).join(', ');
return `[${arrString}]`;
}
const objString = Object.keys(obj)
.map(key => `${key}: ${stringifyData(obj[key], config)}`)
.join(', ');
return `{${objString}}`;
}
/**
* @param {string} str string to check percentage of the equality
* @param {string} inStr string to check how many pecent is in str
* @param {object} opts strings modification options
* @returns {number} percentage of the equality
*/
function getStringEqualtyPersentage(str, inStr, opts) {
const defaultOpts = {
ignoreSpaces: false,
toLowerCase: false,
ignorePunctuation: false,
};
if (!(0, types_1.isString)(str)) {
throw new TypeError(`getStringEqualtyPersentage(): first argument should be a string, current arg is ${(0, types_1.getType)(str)}`);
}
if (!(0, types_1.isString)(inStr)) {
throw new TypeError(`getStringEqualtyPersentage(): second argument should be a string, current arg is ${(0, types_1.getType)(inStr)}`);
}
if (!(0, types_1.isObject)(opts) && !(0, types_1.isUndefined)(opts)) {
throw new TypeError(`getStringEqualtyPersentage(): third argument should be an object, current arg is ${(0, types_1.getType)(opts)}`);
}
const options = { ...defaultOpts, ...opts };
if (!(0, types_1.isBoolean)(options.ignoreSpaces)) {
throw new TypeError(`getStringEqualtyPersentage(): third argument "ignoreSpaces" property should be a boolean, current arg is ${(0, types_1.getType)(options.ignoreSpaces)}`);
}
if (!(0, types_1.isBoolean)(options.toLowerCase)) {
throw new TypeError(`getStringEqualtyPersentage(): third argument "toLowerCase" property should be a boolean, current arg is ${(0, types_1.getType)(options.toLowerCase)}`);
}
if (!(0, types_1.isBoolean)(options.ignorePunctuation)) {
throw new TypeError(`getStringEqualtyPersentage(): third argument "ignorePunctuation" property should be a boolean, current arg is ${(0, types_1.getType)(options.ignorePunctuation)}`);
}
let str1 = str;
let str2 = inStr;
if (options.ignoreSpaces) {
str1 = str1.replace(/\s/g, '');
str2 = str2.replace(/\s/g, '');
}
if (options.toLowerCase) {
str1 = str1.toLowerCase();
str2 = str2.toLowerCase();
}
if (options.ignorePunctuation) {
const punctuationRegex = /[!#$%&()*,./:;=^_`{}~\-]/g;
str1 = str1.replace(punctuationRegex, '');
str2 = str2.replace(punctuationRegex, '');
}
const str1Arr = str1.split('');
const str2Arr = str2.split('');
const comparisonResults = [0];
for (let i = 0; i < str1Arr.length; i++) {
const charInStr = str1Arr[i];
const slicedStr = str1Arr.slice(i);
const indexInComarisonStr = str2Arr.indexOf(charInStr);
// if the char is not in the comparison string, we can skip it
if (indexInComarisonStr === -1 && i === 0) {
return 0;
}
const sliced = str2Arr.slice(indexInComarisonStr);
let equaltyCount = 0;
for (const [j, element] of sliced.entries()) {
if (element === slicedStr[j]) {
equaltyCount++;
}
else {
comparisonResults.push(equaltyCount);
break;
}
comparisonResults.push(equaltyCount);
}
}
const bigest = comparisonResults.sort()[comparisonResults.length - 1];
return Number(((bigest / str2.length) * 100).toFixed(1));
}
//# sourceMappingURL=utils.js.map
;