jsm-utilities
Version:
A utilities library.
370 lines (369 loc) • 14.3 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatNotificationSpace = exports.formatAmount = exports.toKebabCase = exports.toSnakeCase = exports.generateSlug = exports.formatBytes = exports.generateStringNgrams = exports.checkSimilarity = exports.createBigram = exports.abbreviateNumber = exports.isNumeric = exports.toPriceAmount = exports.addLeadingZeros = exports.stringToBoolean = exports.splitString = void 0;
exports.capitalizeFirstLetter = capitalizeFirstLetter;
exports.kebabToCamel = kebabToCamel;
exports.camelToKebab = camelToKebab;
exports.camelToWords = camelToWords;
exports.pluralize = pluralize;
exports.singularize = singularize;
exports.replaceAll = replaceAll;
exports.buildUserFullName = buildUserFullName;
exports.generatePinCode = generatePinCode;
exports.getSubstringUntilFirstWhitespaceAfterNChars = getSubstringUntilFirstWhitespaceAfterNChars;
exports.generateItemAlphabetCode = generateItemAlphabetCode;
exports.countCharacterOccurrenceInString = countCharacterOccurrenceInString;
/**
* @generator Jsm
* @author dr. Salmi <reevosolutions@gmail.com>
* @since 24-02-2024 20:47:22
*/
const lodash_1 = require("lodash");
const crypto_1 = require("crypto");
/**
* @description Uses lodash flatten to split a string by , / ; +
* @param str string to split
* @returns {string[]}
*/
const splitString = (str, use_plus_character = true) => {
return (0, lodash_1.flatten)((0, lodash_1.flatten)((0, lodash_1.flatten)(str.split(",").map((v) => v.split("/"))).map((v) => v.split(";"))).map((v) => (use_plus_character ? v.split("+") : v)))
.map((v) => v.trim())
.filter((v) => !!v);
};
exports.splitString = splitString;
const stringToBoolean = (str) => {
if (!str.length)
return false;
str = str.trim().toLowerCase();
if (["1", "true", "yes", "oui", "y"].includes(str))
return true;
return false;
};
exports.stringToBoolean = stringToBoolean;
const addLeadingZeros = (num, totalLength) => {
return String(num).padStart(totalLength, "0");
};
exports.addLeadingZeros = addLeadingZeros;
const toPriceAmount = (str) => {
if (!str.length)
return 0;
const str2 = str
.toLowerCase()
// start excel number format to number
.replace(",", "#")
.replace(".", ",")
.replace("#", ".")
// end excel number format to number
.replace("dza", "")
.replace("dz", "")
.replace("da", "")
.replace(",", "")
.trim();
try {
console.log("EXCEL_NUMBER", str, str2, parseFloat(str2));
if (!str2.length)
return 0;
return parseFloat(str2);
}
catch (error) {
return 0;
}
};
exports.toPriceAmount = toPriceAmount;
const isNumeric = (val) => {
return !isNaN(val);
};
exports.isNumeric = isNumeric;
const abbreviateNumber = (n) => {
function rnd(num, precision) {
const prec = Math.pow(10, precision);
return Math.round(num * prec) / prec;
}
const abbrev = ["K", "M", "B"]; // abbreviations in steps of 1000x; extensible if need to edit
let base = Math.floor(Math.log(Math.abs(n)) / Math.log(1000));
const suffix = abbrev[Math.min(abbrev.length - 1, base - 1)];
base = abbrev.indexOf(suffix) + 1;
return suffix ? `${rnd(n / Math.pow(1000, base), 2)} ${suffix}` : "" + n;
};
exports.abbreviateNumber = abbreviateNumber;
// Similarity
// https://stackoverflow.com/questions/10473745/compare-strings-javascript-return-of-likely
const createBigram = (word) => {
const input = word.toLowerCase();
const vector = [];
for (let i = 0; i < input.length; ++i) {
vector.push(input.slice(i, i + 2));
}
return vector;
};
exports.createBigram = createBigram;
const checkSimilarity = (a, b) => {
if (a.length > 0 && b.length > 0) {
const aBigram = (0, exports.createBigram)(a);
const bBigram = (0, exports.createBigram)(b);
let hits = 0;
for (let x = 0; x < aBigram.length; ++x) {
for (let y = 0; y < bBigram.length; ++y) {
if (aBigram[x] === bBigram[y]) {
hits += 1;
}
}
}
if (hits > 0) {
const union = aBigram.length + bBigram.length;
return (2.0 * hits) / union;
}
}
return 0;
};
exports.checkSimilarity = checkSimilarity;
const generateStringNgrams = (str) => {
// Remove non-alphanumeric characters
if (!str)
return [];
const sanitizedText = str.toLowerCase().replace(/[^a-zA-Z0-9]/g, "");
const ngrams = [];
for (let n = 2; n <= sanitizedText.length; n++) {
for (let i = 0; i <= sanitizedText.length - n; i++) {
ngrams.push(sanitizedText.slice(i, i + n));
}
}
return ngrams;
};
exports.generateStringNgrams = generateStringNgrams;
const formatBytes = (bytes, decimals = 2) => {
if (bytes === 0)
return "0 Byte";
const k = 1024;
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return (parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + " " + sizes[i]);
};
exports.formatBytes = formatBytes;
const generateSlug = (title) => __awaiter(void 0, void 0, void 0, function* () {
return (0, exports.toKebabCase)(title);
// Replace Arabic and other non-ASCII characters with ASCII equivalents if possible
const arabicMap = {
ش: "sh",
س: "s",
ذ: "z",
ز: "z",
ض: "d",
ص: "s",
ث: "t",
ق: "q",
ف: "f",
غ: "gh",
// Add more mappings as needed
};
// const replacedTitle = title.replace(/[\u0621-\u064A]/g, (char) => arabicMap[char] || char);
const replacedTitle = title;
// Convert to lowercase
const lowerCaseTitle = replacedTitle.toLowerCase();
// Remove non-word characters, except for Arabic characters, dashes, and spaces
const cleanedTitle = lowerCaseTitle.replace(/[^\u0621-\u064A\w\s-]/g, "");
// Replace spaces and dashes with a single dash
const dashedTitle = cleanedTitle.replace(/[\s-]+/g, "-");
return dashedTitle;
});
exports.generateSlug = generateSlug;
const toSnakeCase = (str) => {
return str.replace(/([a-z])([A-Z])/g, "$1_$2").toUpperCase();
};
exports.toSnakeCase = toSnakeCase;
const toKebabCase = (input) => {
return (input
.toLowerCase() // Convert to lowercase
.replace(/[^\p{L}\p{N}]+/gu, "-") // Replace non-letter and non-digit characters with a dash
// .replace(/[^a-zA-Z0-9\u00C0-\u024F\u1E00-\u1EFF]+/g, '-') // Replace non-alphanumeric and non-Latin chars with a dash
.replace(/^-+|-+$/g, "") // Remove leading or trailing dashes
.replace(/-{2,}/g, "-")); // Replace multiple dashes with a single dash
};
exports.toKebabCase = toKebabCase;
function capitalizeFirstLetter(str) {
if (str.length === 0)
return str;
return str.charAt(0).toUpperCase() + str.slice(1);
}
function kebabToCamel(kebabString) {
return kebabString.replace(/-([a-z])/g, (_, match) => match.toUpperCase());
}
function camelToKebab(camelCaseString) {
return camelCaseString.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
}
function camelToWords(camelCaseString) {
return camelCaseString.replace(/([a-z])([A-Z])/g, "$1 $2").toLowerCase();
}
function pluralize(word) {
if (word.endsWith("ing")) {
// Words ending with 's' or 'es', return the word as is
return word;
}
else if (word.endsWith("y") &&
!word.endsWith("ay") &&
!word.endsWith("ey") &&
!word.endsWith("oy") &&
!word.endsWith("uy") &&
!word.endsWith("iy")) {
// Words ending with 'y', replace 'y' with 'ies'
return word.slice(0, -1) + "ies";
}
else {
// For other words, simply add 's'
return word + "s";
}
}
function singularize(word) {
if (word.endsWith("ies")) {
// Words ending with 'ies', replace 'ies' with 'y'
return word.slice(0, -3) + "y";
}
else if (word.endsWith("s")) {
// Words ending with 's', remove 's'
return word.slice(0, -1);
}
else {
// For other words, return the word as is
return word;
}
}
function replaceAll(input, search, replace) {
const regex = new RegExp(search, "g");
return input.replace(regex, replace);
}
/**
*
*
* @param { { first_name?: string | null; family_name?: string | null; full_name?: string | null; }} names
* @returns {string}
*/
function buildUserFullName(names) {
if (!names)
return "";
if (names.full_name)
return names.full_name;
return `${names.family_name || ""} ${names.first_name || ""}`.trim();
}
/**
* @description Formats a number or an object containing amount, separator, decimals, and currency into a formatted string.
* @example usage:
* - formatAmount(1234567.89) // "1,234,567.89"
* - formatAmount({ amount: 1234567.89, separator: ".", decimals: 2, currency: "USD" }) // "1.234.567,89 USD"
* - formatAmount({ amount: 1234567.89, separator: ",", decimals: 2 }) // "1,234,567.89"
* - formatAmount(1234567.89, ".", 2, "USD") // "1.234.567,89 USD"
* - formatAmount(1234567.89, { separator: ".", decimals: 2, currency: "USD" }) // "1.234.567,89 USD"
* - formatAmount(1234567.89, { separator: ",", decimals: 2 }) // "1,234,567.89"
* - formatAmount(1234567.89, ",", 2, "USD") // "1,234,567.89 USD"
* @param x - The number or an object containing amount, separator, decimals, and currency.
* @param separator - The separator to use for thousands (default is ",").
* @param decimals - The number of decimal places to display (default is 2).
* @param currency - The currency symbol to append (optional).
* @returns A formatted string representing the amount.
*/
const formatAmount = (x, separator = ",", decimals = 2, currency) => {
if (typeof x === "object") {
separator = x.separator || separator || ",";
decimals = x.decimals || decimals || 2;
currency = x.currency || currency;
x = x.amount;
}
if (typeof separator === "object") {
decimals = separator.decimals || decimals || 2;
currency = separator.currency || currency;
separator = separator.separator || ",";
}
const str = x.toFixed(decimals).split(".");
const part1 = str[0].replace(/\.(.*)|(\d)(?=(?:\d{3})+(?:\.|$))/g, `$2${separator}$1`);
const result = str.length === 2 ? `${part1}.${str[1]}` : part1;
return currency ? `${result} ${currency}` : result;
};
exports.formatAmount = formatAmount;
const formatNotificationSpace = (space, infos) => {
if (!Object.values(infos).reduce((prev, curr) => prev || !!curr, false))
return null;
return space
.replace("[COMPANY]", infos.company || "")
.replace("[OFFICE]", infos.office || "")
.replace("[STORE]", infos.store || "")
.replace("[USER]", infos.user || "")
.replace("[ROLE]", infos.role || "");
};
exports.formatNotificationSpace = formatNotificationSpace;
/**
* @description Generate a random 4-digit pin code between 1000 and 9999 (inclusive)
* @returns {string} a random 4-digit pin code
*/
function generatePinCode() {
const pin = (0, crypto_1.randomInt)(1000, 10000);
return pin.toString();
}
/**
* Function to get a substring from position 0 to the first whitespace after threshold characters
* @param str - The input string
* @param threshold - The threshold number of characters
* @returns - The extracted substring
*/
function getSubstringUntilFirstWhitespaceAfterNChars(str, threshold = 100, dots = " ...") {
// Define the start position and the threshold length
const startPos = 0;
// Find the first whitespace position after the threshold
const substring = str.substring(threshold);
const firstWhitespacePos = substring.search(/\s/);
if (firstWhitespacePos === -1) {
// If no whitespace is found, return the substring from 0 to the end of the string
return str;
}
// Calculate the actual position in the original string
const endPos = threshold + firstWhitespacePos;
// Return the substring from 0 to the first whitespace after the threshold
return str.length > threshold
? `${str.substring(startPos, endPos)}${dots}`
: str;
}
/**
* @generator Jsm
* @author dr. Salmi <reevosolutions@gmail.com>
* @since 23-07-2024 08:43:03
*/
function generateItemAlphabetCode(usedCodes) {
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const base = alphabet.length;
// Converts a number to a base-26 "column name"
const toCode = (number) => {
let code = "";
while (number > 0) {
number -= 1; // Adjust for 0-indexing in modulo calculation
code = alphabet[number % base] + code;
number = Math.floor(number / base);
}
return code || "A"; // Default to "A" if number is 0
};
// Generate a set of used codes for quick lookup
const usedCodesSet = new Set(usedCodes);
let index = 1; // Start from 1 which corresponds to "A"
let code = toCode(index);
// Find the first code that is not used
while (usedCodesSet.has(code)) {
index++;
code = toCode(index);
}
return code;
}
function countCharacterOccurrenceInString(str, character) {
let count = 0;
for (let i = 0; i < str.length; i++) {
if (str.charAt(i) === ".") {
count++;
}
}
return count;
}