npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

friendlyfy-js

v1.0.4

Published

A zero-dependency utility library with 70+ functions for formatting dates, numbers, strings, arrays, objects, and validation. Works in both Node.js and browser environments.

Readme

friendlyfy-js

A zero-dependency utility library with 70+ functions for formatting dates, numbers, strings, arrays, objects, and validation. Works seamlessly in both Node.js and browser environments with pure JavaScript implementation.

✨ Features

  • 📅 Date & Time (10 functions): Human-readable formatting, timezone support, duration formatting
  • 🔢 Numbers & Math (15 functions): Shortening, formatting, validation, statistical analysis
  • 🔤 String Manipulation (15 functions): Text transformation, HTML handling, case conversion
  • 📊 Array Operations (15 functions): Manipulation, set operations, sorting, statistics
  • 🔧 Object Utilities (15 functions): Deep cloning, merging, transformation, validation
  • Validation & Security (13 functions): Email, URL, phone, credit card, password validation
  • 🌍 Full Internationalization: Complete locale support using native Intl APIs
  • ESM Ready: Built for Node.js v20+ with native ES modules
  • 📦 Zero Dependencies: Uses only native JavaScript APIs

🚀 Installation

npm install friendlyfy-js

🎯 Quick Start

import { 
  // Date & Time
  timeAgo, 
  formatDuration,
  
  // Numbers
  shortenNumber, 
  formatFileSize,
  formatOrdinal,
  
  // Strings
  slugify,
  capitalize,
  
  // Arrays
  chunk,
  unique,
  
  // Objects
  deepClone,
  pick,
  
  // Validation
  isValidEmail,
  validatePassword,
  
  // Crypto
  generateUUID,
  hash,
  
  // Files
  getMimeType,
  sanitizeFilename
} from 'friendlyfy-js';

// Date formatting
console.log(timeAgo('2025-10-08T10:00:00Z')); // "3 hours ago"
console.log(formatDuration(3661)); // "1h 1m 1s"

// Number formatting
console.log(shortenNumber(12543)); // "12.5K"
console.log(formatFileSize(1048576)); // "1.05 MB"
console.log(formatOrdinal(21)); // "21st"

// String manipulation
console.log(slugify("Hello World!")); // "hello-world"
console.log(capitalize("hello world")); // "Hello world"

// Array operations
console.log(chunk([1,2,3,4,5,6], 2)); // [[1,2], [3,4], [5,6]]
console.log(unique([1,2,2,3,3,3])); // [1,2,3]

// Object utilities
const cloned = deepClone({user: {name: 'John'}});
const userData = pick({name: 'John', age: 30, city: 'NYC'}, ['name', 'age']);

// Validation
console.log(isValidEmail('[email protected]')); // true
console.log(validatePassword('MySecure123!')); // {valid: true, strength: 'strong'}

// Cryptography
console.log(generateUUID()); // "96cf1769-2655-4880-801d-7062903e9b2b"
console.log(hash('Hello World')); // "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e"

// File operations
console.log(getMimeType('image.jpg')); // "image/jpeg"
console.log(sanitizeFilename('file<>:"|?*.txt')); // "file_______.txt"

📚 API Reference

📅 Date & Time Helpers

timeAgo(date, locale?)

Returns human-readable time ago string.

timeAgo('2024-01-01T00:00:00Z'); // "2 months ago"
timeAgo(new Date(), 'es-ES'); // "hace 2 horas"

timeFromNow(date, locale?)

Returns human-readable time from now string.

timeFromNow('2025-12-25T00:00:00Z'); // "in 8 months"

formatDateWithTimezone(date, timezone?, options?, locale?)

Formats date with timezone support.

formatDateWithTimezone('2024-01-15T14:30:00Z', 'America/New_York');
// "01/15/2024, 09:30:00 AM"

formatDuration(seconds, options?, locale?)

Formats duration in human-readable format.

formatDuration(3661); // "1h 1m 1s"
formatDuration(3661, {compact: true}); // "1h 1m 1s"
formatDuration(3661, {maxUnits: 2}); // "1h 1m"

startOf(date, period) / endOf(date, period)

Get start/end of time periods.

startOf(new Date(), 'week'); // Start of current week
endOf(new Date(), 'month'); // End of current month

🔢 Number Helpers

shortenNumber(num, decimals?)

Shortens numbers with K, M, B, T suffixes.

shortenNumber(12543); // "12.5K"
shortenNumber(1250000); // "1.3M"
shortenNumber(1250000000); // "1.3B"

formatFileSize(bytes, options?, locale?)

Formats file size in human-readable format.

formatFileSize(1024); // "1.02 KB"
formatFileSize(1048576); // "1.05 MB"
formatFileSize(1048576, {binary: true}); // "1.00 MiB"

formatOrdinal(num, locale?)

Formats ordinal numbers.

formatOrdinal(1); // "1st"
formatOrdinal(2); // "2nd"
formatOrdinal(21); // "21st"

formatRange(start, end, options?, locale?)

Formats number ranges.

formatRange(1, 5); // "1-5"
formatRange(1000, 2000); // "1,000-2,000"
formatRange(1, 5, {separator: ' to '}); // "1 to 5"

pluralize(count, singular, plural?, locale?)

Pluralizes words based on count.

pluralize(1, 'item'); // "1 item"
pluralize(5, 'item'); // "5 items"
pluralize(1, 'child', 'children'); // "1 child"

🔤 String Helpers

slugify(str, options?)

Converts string to URL-friendly slug.

slugify("Hello World! 123"); // "hello-world-123"
slugify("Hello World!", {separator: '_'}); // "hello_world_123"

truncate(str, length, options?)

Truncates string with ellipsis.

truncate("This is a long text", 10); // "This is a ..."
truncate("This is a long text", 10, {wordBoundary: true}); // "This is..."

capitalize(str, lowerRest?)

Capitalizes first letter.

capitalize("hello world"); // "Hello world"
capitalize("hello world", true); // "Hello world"

camelToKebab(str) / kebabToCamel(str)

Converts between camelCase and kebab-case.

camelToKebab("camelCaseString"); // "camel-case-string"
kebabToCamel("kebab-case-string"); // "kebabCaseString"

stripHtml(str) / escapeHtml(str)

Handles HTML content.

stripHtml("<p>Hello <b>World</b></p>"); // "Hello World"
escapeHtml("<script>alert('xss')</script>"); // "&lt;script&gt;alert(&#39;xss&#39;)&lt;/script&gt;"

maskString(str, options?)

Masks sensitive strings.

maskString("1234567890"); // "12******90"
maskString("1234567890", {visibleStart: 3, visibleEnd: 3}); // "123****890"

📊 Array Helpers

chunk(arr, size)

Chunks array into smaller arrays.

chunk([1,2,3,4,5,6,7,8,9,10], 3); // [[1,2,3], [4,5,6], [7,8,9], [10]]

unique(arr, keyFn?)

Removes duplicates from array.

unique([1,2,2,3,3,3,4,5]); // [1,2,3,4,5]
unique(users, user => user.city); // Unique users by city

shuffle(arr, inPlace?)

Shuffles array randomly.

shuffle([1,2,3,4,5]); // [3,2,4,1,5]

groupBy(arr, key)

Groups array items by key.

groupBy(users, 'city'); // { 'New York': [...], 'London': [...] }
groupBy(users, user => user.age > 25 ? 'adult' : 'young'); // { 'adult': [...], 'young': [...] }

intersection(arr1, arr2) / difference(arr1, arr2) / union(arr1, arr2)

Set operations on arrays.

intersection([1,2,3,4], [3,4,5,6]); // [3,4]
difference([1,2,3,4], [3,4,5,6]); // [1,2]
union([1,2,3,4], [3,4,5,6]); // [1,2,3,4,5,6]

arrayStats(arr)

Gets array statistics.

arrayStats([1,2,3,4,5]); // {length: 5, sum: 15, average: 3, min: 1, max: 5, median: 3}

🔧 Object Helpers

deepClone(obj)

Deep clones an object.

const cloned = deepClone({user: {profile: {name: 'John'}}});

deepMerge(target, ...sources)

Deep merges objects.

deepMerge({a: 1, b: {c: 2}}, {b: {d: 3}}); // {a: 1, b: {c: 2, d: 3}}

pick(obj, keys) / omit(obj, keys)

Selects/removes object properties.

pick({name: 'John', age: 30, city: 'NYC'}, ['name', 'age']); // {name: 'John', age: 30}
omit({name: 'John', age: 30, city: 'NYC'}, ['age']); // {name: 'John', city: 'NYC'}

get(obj, path, defaultValue?) / set(obj, path, value)

Gets/sets nested object properties.

get({user: {profile: {name: 'John'}}}, 'user.profile.name'); // "John"
set(obj, 'user.profile.settings.theme', 'dark');

transformKeys(obj, transformFn) / transformValues(obj, transformFn)

Transforms object keys/values.

transformKeys({firstName: 'John', lastName: 'Doe'}, k => k.toUpperCase()); // {FIRSTNAME: 'John', LASTNAME: 'Doe'}
transformValues({a: 1, b: 2}, v => v * 2); // {a: 2, b: 4}

✅ Validation Helpers

isValidEmail(email)

Validates email addresses.

isValidEmail('[email protected]'); // true
isValidEmail('invalid-email'); // false

isValidUrl(url, options?)

Validates URLs.

isValidUrl('https://example.com'); // true
isValidUrl('ftp://example.com', {protocols: ['ftp:']}); // true

isValidPhone(phone, country?)

Validates phone numbers.

isValidPhone('+1234567890', 'US'); // true
isValidPhone('+44123456789', 'UK'); // true

isValidCreditCard(cardNumber)

Validates credit card numbers.

isValidCreditCard('4111111111111111'); // {valid: true, type: 'visa'}

validatePassword(password, options?)

Validates password strength.

validatePassword('MySecure123!'); // {valid: true, score: 6, strength: 'strong', feedback: []}

isValidIP(ip, version?)

Validates IP addresses.

isValidIP('192.168.1.1'); // true
isValidIP('2001:db8::1', 'v6'); // true

isValidUUID(uuid, version?)

Validates UUIDs.

isValidUUID('550e8400-e29b-41d4-a716-446655440000'); // true

🔐 Crypto Helpers

hash(data, algorithm?, encoding?)

Generates hash using specified algorithm.

hash('Hello World'); // "a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e"
hash('Hello World', 'md5', 'hex'); // "b10a8db164e0754105b7a99be72e3fe5"

hmac(data, secret, algorithm?, encoding?)

Generates HMAC.

hmac('Hello World', 'secret'); // "82ce0d2f821fa0ce5447b21306f214c99240fecc6387779d7515148bbdd0c415"

generateUUID()

Generates UUID v4.

generateUUID(); // "96cf1769-2655-4880-801d-7062903e9b2b"

generateToken(length?, options?)

Generates secure tokens.

generateToken(16); // "qRWt7ncmhhwy8FNK"
generateToken(32, {includeSymbols: true}); // "K#m9@vL2$nP8&qR5!"

hashPassword(password, options?)

Hashes passwords securely.

const hashed = await hashPassword('MyPassword123');
const isValid = await verifyPassword('MyPassword123', hashed); // true

generateApiKey(options?)

Generates API keys.

generateApiKey(); // "ak_fvtqhqwlhicphwgyazvrq"
generateApiKey({prefix: 'sk', includeTimestamp: true}); // "sk_1j8k9l2m_fvtqhqwlhicphwgyazvrq"

📁 File Helpers

getFileExtension(filename) / getFilenameWithoutExtension(filename)

Gets file extension or name without extension.

getFileExtension('document.pdf'); // "pdf"
getFilenameWithoutExtension('document.pdf'); // "document"

normalizePath(filePath) / joinPaths(...paths)

Path manipulation.

normalizePath('./folder/../file.txt'); // "file.txt"
joinPaths('folder', 'subfolder', 'file.txt'); // "folder/subfolder/file.txt"

getMimeType(filename)

Gets MIME type from filename.

getMimeType('image.jpg'); // "image/jpeg"
getMimeType('document.pdf'); // "application/pdf"
getMimeType('script.js'); // "application/javascript"

sanitizeFilename(filename, options?)

Sanitizes filenames for safe storage.

sanitizeFilename('file<>:"|?*.txt'); // "file_______.txt"
sanitizeFilename('My File (1).pdf', {replacement: '-'}); // "My-File-1-.pdf"

fileExists(filePath) / dirExists(dirPath)

Checks file/directory existence.

await fileExists('/path/to/file.txt'); // true/false
await dirExists('/path/to/directory'); // true/false

getFileStats(filePath)

Gets file statistics.

await getFileStats('/path/to/file.txt'); // {size: 1024, isFile: true, createdAt: Date, modifiedAt: Date, ...}

🌍 Internationalization

All functions support locale-specific formatting:

import { timeAgo, formatWithCommas, formatCurrency, formatOrdinal } from 'friendlyfy-js';

// Spanish
timeAgo(date, 'es-ES'); // "hace 2 horas"
formatWithCommas(1234567, 'es-ES'); // "1.234.567"

// German
formatCurrency(1234.56, 'EUR', 'de-DE'); // "1.234,56 €"

// French
formatOrdinal(1, 'fr-FR'); // "1er"

🧪 Examples

Run the comprehensive examples:

npm start
# or
node example.js

📋 Requirements

  • Node.js v20.0.0 or higher
  • ESM support (use import syntax)

📄 License

MIT License - see LICENSE file for details.

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📈 Changelog

1.0.1

  • Added comprehensive utility functions (100+ functions)
  • String manipulation helpers (15 functions)
  • Array operation helpers (15 functions)
  • Object utility helpers (15 functions)
  • Validation and security helpers (13 functions)
  • Cryptography helpers (15 functions)
  • File system helpers (20 functions)
  • Complete examples and documentation
  • Full internationalization support

1.0.0

  • Initial release
  • Date helper functions with Intl.RelativeTimeFormat
  • Number helper functions with various formatting options
  • Full internationalization support
  • ESM module support

🎯 Use Cases

Frontend Development

  • String manipulation and formatting
  • Date/time display
  • Form validation
  • Data transformation

Backend Development

  • API response formatting
  • Data validation
  • File handling
  • Security utilities

Full-Stack Applications

  • Complete utility coverage
  • Consistent formatting across frontend/backend
  • Internationalization support
  • Performance optimization

🔗 Related Packages

⭐ Star History

Star History Chart


Made with ❤️ by Vinay Kumar