@arkyn/shared
v3.0.2
Published
Comprehensive collection of reusable utilities for data formatting, validation, generation, and manipulation, featuring Brazilian document validators and financial tools.
Maintainers
Readme
@arkyn/shared
Comprehensive collection of reusable utilities for data formatting, validation, generation, and manipulation, featuring Brazilian document validators and financial tools.
π― What it solves
@arkyn/shared is a dependency-light, framework-agnostic toolkit for formatting, validating, generating, and parsing common data types in JavaScript/TypeScript applications. It has strong support for Brazilian documents (CPF, CNPJ, CEP) and locale-aware financial formatting, alongside general-purpose helpers for dates, JSON, strings, IDs, and sensitive-data masking. Because it has no framework assumptions, the same functions run identically on the client and the server β it's the shared foundation used by both @arkyn/components and @arkyn/server.
β¨ Features
- π Date formatting & parsing β configurable input/output formats with timezone shifting
- π° Currency & financial formatting β locale-aware currency strings and card installment math
- π Text formatting β capitalization, ellipsis truncation, digit masking
- π§π· Brazilian document formatting β CPF, CNPJ, CEP
- π Phone formatting β country-mask-aware phone number formatting via
libphonenumber-js - π§ Generators β UUID (v4/v7) IDs, URL-friendly slugs, deterministic colors from strings
- π§© JSON parsers β pretty-printing, large-field truncation, sensitive-key masking
- π‘οΈ Sensitive-data masking β hide digits/fields in strings and JSON payloads
- π HTML utilities β detect and strip HTML markup
- π§Ή String/number utilities β strip non-numeric characters, strip currency symbols, ensure quoting
π Prerequisites
- Node.js
>=18.0.0 - Bun
>=1.0.0 libphonenumber-js>=1.13.7β optional peer dependency, required only if you useformatToPhoneorfindCountryMask
π¦ Installation
ESM only. This package ships as native ES modules with no CommonJS build β use
import, notrequire().
npm install @arkyn/sharedIf you plan to use formatToPhone or findCountryMask, also install the peer dependency:
npm install libphonenumber-jsπ Quick Start
import {
formatToCpf,
formatToCurrency,
generateId,
generateSlug,
} from "@arkyn/shared";
// Format a raw CPF string (throws if it doesn't have 11 digits)
const cpf = formatToCpf("12345678909");
// "123.456.789-09"
// Format currency using a currency code from @arkyn/templates
const price = formatToCurrency(1234.56, "BRL");
// "R$ 1.234,56"
// Generate a UUID v4
const id = generateId("text", "v4");
// "550e8400-e29b-41d4-a716-446655440000"
// Generate a URL-friendly slug
const slug = generateSlug("Hello, World! This is a Test.");
// "hello-world-this-is-a-test"π API Reference
Formats
formatDate
Formats a date (and optional time) string into a custom output format. Calculations are done in UTC+0; use the timezone parameter to shift the result. Throws Error if the resulting date is invalid or inputFormat is not recognized.
import { formatDate } from "@arkyn/shared";
formatDate(["25/12/2023", "15:30:00"], "brazilianDate", "YYYY-MM-DD hh:mm");
// "2023-12-25 15:30"
formatDate(["2023-12-25", "15:30:00"], "timestamp", "DD/MM/YYYY hh:mm", -3);
// "2023-12-25 12:30"formatJsonObject
Formats a JSON-compatible value (object, array, string, or primitive) into a human-readable, indented string. Strings that parse as JSON are recursively formatted.
import { formatJsonObject } from "@arkyn/shared";
const obj = { name: "John", age: 30, hobbies: ["reading", "gaming"] };
formatJsonObject(obj, 0);
// {
// "name": "John",
// "age": 30,
// "hobbies": [
// "reading",
// "gaming"
// ]
// }formatJsonString
Parses a JSON string and returns a pretty-printed representation. Throws Error if the input is not valid JSON.
import { formatJsonString } from "@arkyn/shared";
formatJsonString('{"name":"John","hobbies":["reading","gaming"]}');
// {
// "name": "John",
// "hobbies": [
// "reading",
// "gaming"
// ]
// }formatToCapitalizeFirstWordLetter
Capitalizes the first letter of each space-separated word and lowercases the rest.
import { formatToCapitalizeFirstWordLetter } from "@arkyn/shared";
formatToCapitalizeFirstWordLetter("HELLO WORLD"); // "Hello World"formatToCep
Formats a string into the Brazilian postal code (CEP) pattern XXXXX-XXX. Throws Error if the cleaned input doesn't contain exactly 8 numeric digits.
import { formatToCep } from "@arkyn/shared";
formatToCep("12345678"); // "12345-678"formatToCnpj
Formats a string into the CNPJ pattern XX.XXX.XXX/XXXX-XX. Throws Error if the cleaned input doesn't contain exactly 14 numeric digits.
import { formatToCnpj } from "@arkyn/shared";
formatToCnpj("12345678000195"); // "12.345.678/0001-95"formatToCpf
Formats a string into the CPF pattern XXX.XXX.XXX-XX. Throws Error if the cleaned input doesn't contain exactly 11 numeric digits.
import { formatToCpf } from "@arkyn/shared";
formatToCpf("12345678909"); // "123.456.789-09"formatToCurrency
Formats a number into a locale-aware currency string using Intl.NumberFormat, based on a currency code from @arkyn/templates. Set config.showPrefix to false to omit the currency symbol. Throws Error for unsupported currency codes.
import { formatToCurrency } from "@arkyn/shared";
formatToCurrency(1234.56, "BRL"); // "R$ 1.234,56"
formatToCurrency(1234.56, "USD", { showPrefix: false }); // "1,234.56"formatToEllipsis
Truncates a string to maxLength, avoiding breaking mid-word, and appends "..." if truncation occurred.
import { formatToEllipsis } from "@arkyn/shared";
formatToEllipsis("Hello, world!", 5); // "Hello..."formatToHiddenDigits
Replaces specific digit positions in a string with a masking character, leaving non-digit characters unchanged. options.range can be a positive number (first N digits), a negative number (last N digits), or a [start, end] tuple (1-indexed, inclusive). Defaults to hiding the first 3 digits with "*".
import { formatToHiddenDigits } from "@arkyn/shared";
formatToHiddenDigits("123-456-7890", { range: 3 }); // "***-456-7890"
formatToHiddenDigits("123-456-7890", { range: [4, 6], hider: "#" });
// "123-###-7890"formatToPhone
Formats a phone number according to the country mask defined in @arkyn/templates, parsing it with libphonenumber-js. Throws Error if the number is invalid or no country mask is found. Requires the libphonenumber-js peer dependency.
import { formatToPhone } from "@arkyn/shared";
formatToPhone("+5534920524282"); // "(34) 92052-4282"
formatToPhone("+12125550199"); // "(212) 555-0199"Generators
generateColorByString
Generates a deterministic hexadecimal color code from a hash of the input string β the same input always produces the same color.
import { generateColorByString } from "@arkyn/shared";
generateColorByString("example"); // "#5e8f9a" (consistent for the same input)generateId
Generates a UUID in the requested version ("v4" random or "v7" time-ordered) and representation ("text" string or "binary" Uint8Array). Throws Error for an invalid type/format combination.
import { generateId } from "@arkyn/shared";
generateId("text", "v4"); // "550e8400-e29b-41d4-a716-446655440000"
generateId("binary", "v7"); // Uint8Array([...])generateSlug
Converts a string into a URL-friendly slug: strips accents, removes non-alphanumeric characters (except spaces/hyphens), lowercases, replaces spaces with hyphens, and trims/collapses hyphens.
import { generateSlug } from "@arkyn/shared";
generateSlug("Hello, World! This is a Test.");
// "hello-world-this-is-a-test"Parsers
parseLargeFields
Parses a JSON string and truncates string fields exceeding maxLength (default 1000), replacing them with a message indicating the original length. Traverses nested objects/arrays. Throws Error if the input is not valid JSON.
import { parseLargeFields } from "@arkyn/shared";
const json = JSON.stringify({
name: "John",
description: "A very long description that exceeds the maximum length...",
});
parseLargeFields(json, 50);
// '{"name":"John","description":"To large information: field as 57 characters"}'parseSensitiveData
Parses a JSON string and replaces the values of the given keys with "****", recursively, including JSON-encoded string values. Defaults to masking password, confirmPassword, and creditCard. Returns the original string unchanged if it is not valid JSON (does not throw).
import { parseSensitiveData } from "@arkyn/shared";
const jsonString = JSON.stringify({
username: "user123",
password: "secret",
profile: { creditCard: "1234-5678-9012-3456" },
});
parseSensitiveData(jsonString, ["password", "creditCard"]);
// '{"username":"user123","password":"****","profile":{"creditCard":"****"}}'parseToDate
Parses a date (and optional time) string into a Date object. Calculations are done in UTC+0; use timezone to shift the result. Throws Error if the resulting date is invalid or inputFormat is not recognized.
import { parseToDate } from "@arkyn/shared";
parseToDate(["25/12/2023", "15:30:00"], "brazilianDate", -3);
// Date: 2023-12-25T12:30:00.000Z
parseToDate(["2023-12-25"], "timestamp");
// Date: 2023-12-25T00:00:00.000ZServices
ValidateDateService
Class used internally by formatDate and parseToDate to validate date components and input-format strings β enforces 4-digit years, month/day ranges, month-specific day counts, and leap-year rules. validateDateParts and validateInputFormat both throw Error on invalid input.
import { ValidateDateService } from "@arkyn/shared";
const service = new ValidateDateService();
service.validateDateParts(2024, 2, 29); // OK β leap year
service.validateDateParts(2023, 2, 29); // throws β not a leap year
service.validateInputFormat("brazilianDate"); // OK
service.validateInputFormat("custom"); // throwsUtilities
calculateCardInstallment
Calculates the total price and per-installment price for a card payment plan with compound interest. No interest is applied when fees is 0 or numberInstallments is 1. Throws Error if numberInstallments <= 0 or fees < 0.
import { calculateCardInstallment } from "@arkyn/shared";
calculateCardInstallment({ cashPrice: 1000, numberInstallments: 12, fees: 0.02 });
// { totalPrice: 1124.62, installmentPrice: 93.72 }ensureQuotes
Wraps a string in double quotes unless it is already enclosed in single or double quotes.
import { ensureQuotes } from "@arkyn/shared";
ensureQuotes("example"); // '"example"'
ensureQuotes('"already quoted"'); // '"already quoted"'findCountryMask
Resolves the matching phone mask (using "_" as digit placeholders) and country metadata for an E.164 phone number, using libphonenumber-js and @arkyn/templates. For countries with multiple mask lengths (e.g. Brazil with/without the ninth digit), the mask matching the number's digit count is returned. Throws Error if the number is invalid or no mask is found. Requires the libphonenumber-js peer dependency.
import { findCountryMask } from "@arkyn/shared";
const [mask, country] = findCountryMask("+5511999999999");
// mask: "(__) _____-____"
// country.name: "Brazil"isHtml
Checks whether a string contains HTML markup (opening or closing tags), case-insensitively.
import { isHtml } from "@arkyn/shared";
isHtml("<p>Hello world</p>"); // true
isHtml("Plain text"); // falseremoveCurrencySymbols
Removes currency symbols (R$, $, β¬, Β₯, Β£, and other Unicode currency symbols) from a string and trims whitespace.
import { removeCurrencySymbols } from "@arkyn/shared";
removeCurrencySymbols("R$13,45"); // "13,45"
removeCurrencySymbols("β¬99.99"); // "99.99"removeNonNumeric
Strips all non-numeric characters from a string.
import { removeNonNumeric } from "@arkyn/shared";
removeNonNumeric("abc123def456"); // "123456"stripHtmlTags
Removes HTML tags from a string, including <script> and <style> blocks and HTML comments.
import { stripHtmlTags } from "@arkyn/shared";
stripHtmlTags("<p>Hello <strong>World</strong></p>"); // "Hello World"π Documentation
Full documentation: https://docs.arkyn.dev/docs/shared/introduction
π License
This project is licensed under the Apache 2.0 License - see the LICENSE file for details.