@heliomarpm/helpers
Version:
A library with many useful features
401 lines (400 loc) • 17.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Format = void 0;
exports.Format = {
/**
* Formatações em português brasileiro.
*/
ptBr: {
cnpj: (value, fallback = 'CNPJ está incorreto!') => {
const number = exports.Format.onlyNumbers(value);
if (number.length !== 14) {
return fallback;
}
return number.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5');
},
cpf: (value, fallback = 'CPF está incorreto!') => {
const number = exports.Format.onlyNumbers(value);
if (number.length !== 11) {
return fallback;
}
return number.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4');
},
cep: (value, fallback = 'CEP está incorreto!') => {
const number = exports.Format.onlyNumbers(value);
if (number.length !== 8) {
return fallback;
}
return number.replace(/(\d{5})(\d{3})/, '$1-$2');
},
/**
* Formata um número de telefone com DDD.
* Se o valor informado tiver entre 8 e 11 dígitos, ele
* será formatado com DDD.
* Caso o valor tenha 8 ou 9 dígitos, ele usará o DDD
* informado como parâmetro.
* @param {string} value O valor a ser formatado.
* @param {string} [defaultAreaCode=''] DDD padrão a ser usado.
* @param {boolean} [suppressError=false] Se verdadeiro, retorna o valor sem formatação em vez de lançar um erro.
* @returns {string} O valor formatado.
* @throws {Error} Se o valor informado tiver menos de 8 ou mais de 11 dígitos.
*/
telefone: (value, defaultAreaCode = '', fallback = 'Telefone está incorreto!') => {
let number = exports.Format.onlyNumbers(value);
const areaCode = exports.Format.onlyNumbers(defaultAreaCode);
number = number.length < 10 ? `${areaCode}${number}` : number;
if (number.length < 8 || number.length > 11) {
return fallback;
}
if (number.length === 8 || number.length === 9) {
return number.replace(/(\d{4,5})(\d{4})/, '$1-$2');
}
return number.replace(/(\d{2})(\d{4,5})(\d{4})/, '$1 $2-$3');
},
/**
* Converte um valor em uma string escrita por extenso.
*
* @param value O valor a ser convertido.
* @returns Uma string com o valor escrito por extenso.
*
* @example
* ```js
* Format.valorPorExtenso(1000); // Output: "mil"
* Format.valorPorExtenso(1000000); // Output: "um milhão"
* Format.valorPorExtenso(1000000000); // Output: "um bilhão"
* Format.valorPorExtenso(1000000001); // Output: "um bilhão e um"
* Format.valorPorExtenso(2_000_000_000_000_000); // Output: "dois quatrilhões"
* ```
*/
valorPorExtenso: (value) => {
if (value < 0 || value >= Math.pow(1000, 6)) {
throw new Error('O valor deve estar entre 0 e 999.999.999.999.999.999');
}
const units = ['zero', 'um', 'dois', 'três', 'quatro', 'cinco', 'seis', 'sete', 'oito', 'nove'];
const tens = ['', 'dez', 'vinte', 'trinta', 'quarenta', 'cinquenta', 'sessenta', 'setenta', 'oitenta', 'noventa'];
const tensMore = ['onze', 'doze', 'treze', 'quatorze', 'quinze', 'dezesseis', 'dezessete', 'dezoito', 'dezenove'];
const hundreds = ['', 'cento', 'duzentos', 'trezentos', 'quatrocentos', 'quinhentos', 'seiscentos', 'setecentos', 'oitocentos', 'novecentos'];
const scales = ['', 'mil', 'milhão', 'bilhão', 'trilhão', 'quatrilhão'];
// Converte centenas, dezenas e unidades
const convertHundreds = (num) => {
if (num === 0)
return '';
if (num === 100)
return 'cem';
const hundred = Math.floor(num / 100);
const ten = Math.floor((num % 100) / 10);
const unit = num % 10;
let result = '';
if (hundred > 0) {
result += hundreds[hundred] + (ten > 0 || unit > 0 ? ' e ' : '');
}
if (ten === 1 && unit > 0) {
result += tensMore[unit - 1];
}
else {
if (ten > 0) {
result += tens[ten] + (unit > 0 ? ' e ' : '');
}
if (unit > 0) {
result += units[unit];
}
}
return result;
};
if (value === 0)
return units[0];
let result = '';
const parts = [];
for (let i = 0; i < scales.length; i++) {
parts[i] = Math.floor(value / Math.pow(1000, i)) % 1000;
}
for (let i = scales.length - 1; i >= 0; i--) {
if (parts[i] > 0) {
if (result)
result += parts[i] < 101 ? ' e ' : ' ';
if (i === 1 && parts[i] === 1) {
result += 'mil';
}
else {
result += convertHundreds(parts[i]) + (i > 0 ? ` ${scales[i]}` : '');
}
if (parts[i] > 1 && (i === 2 || i === 3 || i === 4 || i === 5)) {
result = result.replace(/ão$/, 'ões');
}
}
}
return result.trim().replace(/\s+/g, ' ');
}
},
/**
* Formats a Date object into a string according to the specified format.
* Supported formats are:
* - 'a': 'am' or 'pm' in lowercase
* - 'A': 'AM' or 'PM' in uppercase
* - 'hh': two-digit hours in 12h format (01-12)
* - 'h': hours in 12h format (1-12)
* - 'HH': two-digit hours in 24h format (00-23)
* - 'H': hours in 24h format (0-23)
* - 'MM': two-digit minutes (00-59)
* - 'ss': two-digit seconds (00-59)
* - 'SSS': three-digit milliseconds (000-999)
* - 'yyyy': four-digit year (2024)
* - 'yy': two-digit year (24)
* - 'mmmm': full month name (January, February, ...)
* - 'mmm': full month name abbreviated month (Jan, Feb, ...)
* - 'mm': two-digit month (01-12)
* - 'dddd': full weekday name (Sun, Mon, ...)
* - 'ddd': abbreviated weekday name (Sun, Mon, ...)
* - 'dd': two-digit day (01-31)
*
* @param {string|Date} date - The date to format.
* @param {string} format - The desired format for the output string.
* @param {string} locale - The locale to use.
* @returns {string} The date formatted as a string.
*
* @example
* ```js
* Format.date('2025-03-02', 'dddd, dd mmmm yyyy', 'en-US'); // Output: 'Sunday, 02 March 2025'
* ```
*
* @see https://www.w3schools.com/jsref/jsref_tolocalestring.asp
*/
date: (date, format, locale = 'default') => {
try {
if (typeof date === 'string') {
date = date.trim().replace(/-/g, '/').replace(/T/g, ' ');
if (!date.endsWith('Z'))
date += 'Z'; // Adiciona o fuso horário UTC se não estiver presente
date = new Date(new Date(date).toISOString());
}
const monthName = new Intl.DateTimeFormat(locale, { month: 'long' }).formatToParts(date).map(part => part.value)[0];
const dayName = new Intl.DateTimeFormat(locale, { weekday: 'long' }).formatToParts(date).map(part => part.value)[0];
const hr24 = date.getHours();
const hr12 = hr24 % 12 || 12;
const ampm = hr24 < 12 ? 'am' : 'pm';
const map = {
a: ampm,
A: ampm.toUpperCase(),
hh: hr12.toString().padStart(2, '0'),
h: hr12.toString(),
HH: hr24.toString().padStart(2, '0'),
H: hr24.toString(),
MM: String(date.getMinutes()).padStart(2, '0'),
ss: String(date.getSeconds()).padStart(2, '0'),
SSS: String(date.getMilliseconds()).padStart(3, '0'),
yyyy: date.getFullYear().toString(),
yy: date.getFullYear().toString().slice(-2),
mmmm: monthName,
mmm: monthName.slice(0, 3),
mm: String(date.getMonth() + 1).padStart(2, '0'),
dddd: dayName,
ddd: dayName.slice(0, 3),
dd: String(date.getDate()).padStart(2, '0')
};
return format.replace(/a|A|hh|h|HH|H|MM|ss|SSS|yyyy|yy|mmmm|mmm|mm|dddd|ddd|dd/g, (matched) => map[matched]);
}
catch (error) {
throw new Error(`Error in Format.date\n${error}`);
}
},
/**
* Formats a number as currency.
* @param value The number to format.
* @param options Options for formatting. These include the locale and currency.
* @returns The formatted string.
*
* @example
* ```js
* Format.currency(123456.78); // 'R$ 123.456,78'Format.currency(1234.56);
* // Output: R$ 1.234,56
* ```
*
* @see https://www.w3schools.com/jsref/jsref_tolocalestring.asp
*/
currency: (value, options = { locale: 'pt-BR', currency: 'BRL' }) => {
const result = value.toLocaleString(options.locale, { style: 'currency', currency: options.currency });
return result.replace(/\u00A0/g, ' '); // Substitui o espaço não quebrável (\u00A0) por um espaço comum
},
/**
* Formats a number according to the given locale.
* @param value The number to format.
* @param locale The locale to use.
* @returns The formatted string.
*
* @example
* ```js
* Format.number(123456.78); // '123.456,78'Format.number(1234.56);
* // Output: 1.234,56
* ```
*
* @see https://www.w3schools.com/jsref/jsref_tolocalestring.asp
*/
number: (value, locale = 'default') => {
return value.toLocaleString(locale, { minimumFractionDigits: 2 });
},
/**
* Abbreviates a number by adding a suffix based on its magnitude.
*
* This function takes a number and returns a string with the number abbreviated
* using metric suffixes (e.g., K for thousand, M for million).
*
* @param value - The number to abbreviate.
* @param options - Options for abbreviation, including:
* - `fractionDigits`: Number of decimal places to include in the abbreviated value.
* - `removeEndZero`: Whether to remove trailing zeros after the decimal point.
* @returns A string representing the abbreviated number with a suffix.
*
* @example
* ```typescript
* abbreviateNumber(1500); // '1.50K'
* abbreviateNumber(2000000); // '2.00M'
* abbreviateNumber(123_456_789); // '123.46M'
* abbreviateNumber(1e33); // '1.00D'
* ```
*/
abbreviateNumber: (value, { fractionDigits = 2, removeEndZero = true } = {}) => {
const abbreviations = [
{ threshold: 1e33, suffix: 'D' }, // 1 decillion
{ threshold: 1e30, suffix: 'N' }, // 1 nonillion
{ threshold: 1e27, suffix: 'O' }, // 1 octillion
{ threshold: 1e24, suffix: 'Se' }, // 1 septillion
{ threshold: 1e21, suffix: 'S' }, // 1 sextillion
{ threshold: 1e18, suffix: 'Qu' }, // 1 quintillion
{ threshold: 1e15, suffix: 'Q' }, // 1 quadrillion
{ threshold: 1e12, suffix: 'T' }, // 1 trillion
{ threshold: 1e9, suffix: 'B' }, // 1 billion
{ threshold: 1e6, suffix: 'M' }, // 1 million
{ threshold: 1e3, suffix: 'K' } // 1 thousand
];
const abbreviation = abbreviations.find(({ threshold }) => value >= threshold);
if (abbreviation) {
let abbreviatedValue = (value / abbreviation.threshold).toFixed(fractionDigits);
// Optionally remove trailing zeros
if (removeEndZero) {
abbreviatedValue = abbreviatedValue.replace(/\.?0*$/, '');
}
return `${abbreviatedValue}${abbreviation.suffix}`;
}
// Return the original number as a string if no abbreviation is applicable
return value.toString();
},
/**
* Removes all non-numeric characters from a string.
*
* @param {string} value The string to remove non-numeric characters from.
* @returns {string} The resulting string with only numeric characters.
*
* @example
* ```js
* onlyNumbers('123abc'); // '123'
* onlyNumbers('abc'); // ''
* ```
*/
onlyNumbers: (value) => value.replace(/\D/g, ''),
/**
* Pads a number with leading zeros to match the number of digits in a given maximum value.
*
* @param {number} value The number to be padded with leading zeros.
* @param {number} refValue The reference value for determining the maximum length for adding leading zeros.
*
* @returns {string} the input number padded with leading zeros to match the number of digits in the maximum value.
*
* @example
* ```js
* Format.padZerosByRef(2, 90); // '02'
* Format.padZerosByRef(12, 110); // '012'
* ```
*/
padZerosByRef(value, refValue) {
const numDigits = Math.floor(Math.log10(refValue) + 1);
return value.toString().padStart(numDigits, '0');
},
/**
* Capitalizes the first letter of the full name
* while maintaining lowercase for specified conjunctions.
*
* @param {string} name - The full name string to format.
* @returns {string} The formatted name in title case.
*
* @example
* ```ts
* titleCase('john doe de souza'); // 'John Doe de Souza'
* titleCase('maria da silva'); // 'Maria da Silva'
* ```
*/
titleCase(name) {
if (!name.trim())
return '';
const conjunctions = new Set(['do', 'da', 'dos', 'das', 'de', 'e']); // Common conjunctions to remain lowercase
return name
.trim()
.toLowerCase()
.split(/\s+/) // Split the name by whitespace
.map((word, index) =>
// Capitalize the first letter of the word if it's the first word or not a conjunction
index === 0 || !conjunctions.has(word) ? word.charAt(0).toUpperCase() + word.slice(1) : word)
.join(' '); // Join the words back into a string with spaces
},
/**
* Masks a substring of a string with a specified character.
*
* @param {string} value - The original string to mask.
* @param {string} [maskChar='*''] - The character to use for masking.
* @param {number} [startIndex=0] - The starting index of the substring to mask (inclusive).
* @param {number | null} [finalIndex=null] - The ending index of the substring to mask (exclusive). If null, masks until the end of the string.
* @returns {string} The masked string.
*
* @example
* ```js
* maskIt('1234567890', '*', 2, 5); // '12*****90'
* maskIt('1234567890', '#', 3); // '123########'
* ```
* @throws {Error} Invalid start or final index.
* @throws {Error} maskChar must be a single character
*/
maskIt(value, maskChar = '*', startIndex = 0, finalIndex = null) {
if (startIndex > value.length)
startIndex = value.length - 1;
if (finalIndex === null || finalIndex > value.length) {
finalIndex = value.length;
}
if (startIndex < 0 || startIndex > finalIndex) {
throw new Error('Invalid start or final index');
}
if (maskChar.length !== 1) {
throw new Error('maskChar must be a single character');
}
const maskedSubstring = maskChar.repeat(finalIndex - startIndex);
return value.slice(0, startIndex) + maskedSubstring + value.slice(finalIndex);
},
/**
* Masks a part of a string with a specified character.
*
* @param {string} text - The original string to mask.
* @param {string} [maskChar='*'] - The character to use for masking.
* @param {number} [visibleChars=1] - The number of visible characters in the masked part.
* @returns {string} The masked string.
*
* @example
* ```js
* maskItParts('Heliomar P. Marques', '*', 1); // 'H******* P. M******'
* maskItParts('+55 (11) 91888-0000', '#', 1); // '+5# (1#) 9####-0###'
* maskItParts('123.444.555-67', '_', 2); // '12_.44_.55_-67'
* ```
* @throws {Error} maskChar must be a single character
*/
maskItParts(text, maskChar = '*', visibleChars = 1) {
if (maskChar.length !== 1) {
throw new Error('maskChar must be a single character');
}
const effectiveVisibleChars = visibleChars <= 0 ? 1 : visibleChars;
return text.replace(/([a-zA-Z0-9]+)/g, match => {
if (match.length <= effectiveVisibleChars) {
return match;
}
const visiblePart = match.substring(0, effectiveVisibleChars);
const maskedPart = maskChar.repeat(match.length - effectiveVisibleChars);
return visiblePart + maskedPart;
});
}
};