string-extn
v1.2.0
Published
Extended string utility functions for JavaScript and TypeScript.
Maintainers
Readme
string-extn
A lightweight, TypeScript-first library for safe and functional string manipulation. It provides core string utilities, functional programming helpers, and Unicode-safe operations, designed for Node.js and browser environments.
Table of Contents
- Features
- Installation
- Quick Start
- API Reference
- Core Functions
- Functional Programming
- Case Conversion
- String Comparison & Similarity
- String Masking & Redaction
- URL & Filename Safe Conversion
- String Validation
- Unicode Operations
- Internationalization
- Security & Sanitization
- Performance Helpers
- Stream Utilities
- Chaining & Fluent API
- Lazy Evaluation
- Template Interpolation
- Plugin System
- Examples
- Testing
- License
Features
✨ Core String Operations
- trim - Remove leading/trailing whitespace
- pad - Pad strings to a fixed length with custom characters
- slice - Extract string substrings with flexible indexing
- repeat - Repeat strings multiple times
- truncate - Truncate strings with ellipsis
- reverse - Reverse string character order
🔧 Functional Programming Helpers
- map - Transform each character with a function
- filter - Keep only characters matching a predicate
- reduce - Accumulate values by processing characters
- compose - Chain multiple functions for complex transformations
🔤 Case Conversion
- toCamelCase - Convert to camelCase from kebab-case, snake_case, or spaces
- toKebabCase - Convert to kebab-case from camelCase, snake_case, or spaces
- toSnakeCase - Convert to snake_case from camelCase, kebab-case, or spaces
- toPascalCase - Convert to PascalCase from any format
🔍 String Comparison & Similarity
- diff - Find character differences between two strings
- similarity - Calculate similarity score (0-1) using Levenshtein distance
🎭 String Masking & Redaction
- mask - Mask sensitive information keeping only last N characters visible
- redact - Redact portions matching regex patterns
🌐 URL & Filename Safe Conversion
- slugify - Convert to URL-friendly slug format
- filenameSafe - Remove invalid filesystem characters
✔️ String Validation (20 validators)
- Email, UUID, Numeric, URL, Hex Color, Phone Number, Date
- Strong Password, JSON, Base64, Alphabetic, Alphanumeric
- Case validators, Whitespace, Palindrome, Hexadecimal, Roman Numeral
- IPv4, IPv6 validation
🌍 Unicode-Safe Operations
- lengthUnicode - Count Unicode grapheme clusters (handles emoji with modifiers)
- unicodeSlice - Slice strings while respecting grapheme boundaries
- reverseUnicode - Reverse strings with proper emoji and combining mark support
🌐 Internationalization
- localeCompare - Locale-aware string comparison with configurable sensitivity
- normalizeUnicode - Normalize strings to NFC/NFD/NFKC/NFKD
🔐 Security & Sanitization
- escapeHTML - Escape HTML-reserved characters
- escapeSQL - Escape SQL-sensitive characters
- sanitizePath - Remove traversal and dot segments from paths
⚡ Performance Helpers
- fastRepeat - Repeat strings using a fast doubling approach
- fastPadLeft - Left-pad strings using fast repeat
🌊 Stream Utilities
- chunkString - Split strings into fixed-size chunks
- streamTransform - Transform chunks and concatenate results
🔗 Chaining & Fluent API
- chain - Create chainable string transformations
- StringChain - Fluent wrapper with trim, case, replace, and reverse
💤 Lazy Evaluation
- lazy - Build lazy transformation pipelines
- LazyString - Deferred execution via
execute()
🧩 Template Interpolation
- template - Replace {{key}} placeholders from a variable map
🧩 Plugin System
- registerPlugin - Register a named string plugin
- runPlugin - Execute a registered plugin
- listPlugins - List registered plugin names
Installation
npm install string-extnOr with Yarn:
yarn add string-extnQuick Start
Core Functions
import { trim, pad, slice, repeat, truncate, reverse } from 'string-extn';
trim(' hello world '); // "hello world"
pad('abc', 5, '-'); // "abc--"
slice('hello', 1, 4); // "ell"
repeat('ha', 3); // "hahaha"
truncate('This is a long string', 10, '...'); // "This is a ..."
reverse('hello'); // "olleh"Functional Programming
import { map, filter, reduce, compose } from 'string-extn';
map('abc', c => c.toUpperCase()); // "ABC"
filter('abcdef', c => 'aeiou'.includes(c)); // "ae"
reduce('abc', (acc, c) => acc + c.charCodeAt(0), 0); // 294
const shout = compose(s => s + '!', s => s.toUpperCase());
shout('hello'); // "HELLO!"Unicode-Safe Operations
import { lengthUnicode, unicodeSlice, reverseUnicode } from 'string-extn';
const emojiStr = '👍🏽👍';
lengthUnicode(emojiStr); // 2 (counts emoji with skin tone as 1)
unicodeSlice(emojiStr, 0, 1); // "👍🏽"
reverseUnicode(emojiStr); // "👍👍🏽"Chaining & Lazy Evaluation
import { chain, lazy } from 'string-extn';
const chained = chain(' Hello ')
.trim()
.toLower()
.replace('hello', 'hi')
.reverse()
.valueOf();
// "ih"
const pipeline = lazy(' Hello ')
.trim()
.toUpper();
pipeline.execute(); // "HELLO"Template Interpolation
import { template } from 'string-extn';
template('Hello {{name}}', { name: 'Ada' }); // "Hello Ada"Plugin System
import { registerPlugin, runPlugin, listPlugins } from 'string-extn';
registerPlugin({
name: 'wrap',
fn: (input, left: string, right: string) => `${left}${input}${right}`
});
runPlugin('wrap', 'core', '[', ']'); // "[core]"
listPlugins(); // ["wrap"]API Reference
Core Functions
| Function | Signature | Description |
|----------|-----------|-------------|
| trim | trim(str: string): string | Removes leading/trailing whitespace |
| pad | pad(str: string, length: number, char?: string): string | Pads string to fixed length |
| slice | slice(str: string, start: number, end?: number): string | Returns substring |
| repeat | repeat(str: string, times: number): string | Repeats string N times |
| truncate | truncate(str: string, max: number): string | Truncates with ellipsis (...) |
| reverse | reverse(str: string): string | Reverses string characters |
Functional Programming
| Function | Signature | Description |
|----------|-----------|-------------|
| map | map(str: string, fn: (c: string) => string): string | Transforms each character |
| filter | filter(str: string, fn: (c: string) => boolean): string | Filters characters by predicate |
| reduce | reduce<T>(str: string, fn: (acc: T, c: string) => T, initial: T): T | Reduces string to accumulator value |
| compose | compose(...fns: Function[]): (value: any) => any | Composes functions right-to-left |
Case Conversion
| Function | Signature | Description |
|----------|-----------|-------------|
| toCamelCase | toCamelCase(input: string): string | Converts to camelCase |
| toKebabCase | toKebabCase(input: string): string | Converts to kebab-case |
| toSnakeCase | toSnakeCase(input: string): string | Converts to snake_case |
| toPascalCase | toPascalCase(input: string): string | Converts to PascalCase |
String Comparison & Similarity
| Function | Signature | Description |
|----------|-----------|-------------|
| diff | diff(a: string, b: string): string[] | Returns character differences between two strings |
| similarity | similarity(a: string, b: string): number | Returns similarity score (0-1) using Levenshtein distance |
String Masking & Redaction
| Function | Signature | Description |
|----------|-----------|-------------|
| mask | mask(input: string, visible?: number, maskChar?: string): string | Masks string keeping last N characters visible |
| redact | redact(input: string, patterns: RegExp[]): string | Redacts portions matching regex patterns |
URL & Filename Safe Conversion
| Function | Signature | Description |
|----------|-----------|-------------|
| slugify | slugify(input: string): string | Converts to URL-friendly slug format |
| filenameSafe | filenameSafe(input: string): string | Removes invalid filesystem characters |
String Validation
| Function | Input | Returns | Purpose |
|----------|-------|---------|---------|
| isEmail | string | boolean | Validates email address format |
| isUUID | string | boolean | Validates UUID format (v1-v5) |
| isNumeric | string | boolean | Validates numeric strings |
| isURL | string | boolean | Validates URL format |
| isHexColor | string | boolean | Validates hex color codes |
| isPhoneNumber | string | boolean | Validates E.164 phone numbers |
| isDate | string | boolean | Validates date strings |
| isStrongPassword | string | boolean | Validates strong password criteria |
| isJSON | string | boolean | Validates JSON format |
| isBase64 | string | boolean | Validates Base64 encoding |
| isAlphabetic | string | boolean | Validates alphabetic strings only |
| isAlphanumeric | string | boolean | Validates alphanumeric strings |
| isLowerCase | string | boolean | Validates lowercase strings |
| isUpperCase | string | boolean | Validates uppercase strings |
| isWhitespace | string | boolean | Validates whitespace-only strings |
| isPalindrome | string | boolean | Validates palindrome strings |
| isHexadecimal | string | boolean | Validates hexadecimal format |
| isRomanNumeral | string | boolean | Validates Roman numeral format |
| isIPv4 | string | boolean | Validates IPv4 addresses |
| isIPv6 | string | boolean | Validates IPv6 addresses |
Unicode Operations
| Function | Signature | Description |
|----------|-----------|-------------|
| lengthUnicode | lengthUnicode(str: string): number | Counts Unicode grapheme clusters |
| unicodeSlice | unicodeSlice(str: string, start: number, end?: number): string | Slices by grapheme boundaries |
| reverseUnicode | reverseUnicode(str: string): string | Reverses with emoji/modifier support |
Internationalization
| Function | Signature | Description |
|----------|-----------|-------------|
| localeCompare | localeCompare(a: string, b: string, locale?: string, sensitivity?: "base" | "accent" | "case" | "variant"): number | Locale-aware string comparison |
| normalizeUnicode | normalizeUnicode(input: string, form?: "NFC" | "NFD" | "NFKC" | "NFKD"): string | Unicode normalization |
Security & Sanitization
| Function | Signature | Description |
|----------|-----------|-------------|
| escapeHTML | escapeHTML(input: string): string | Escapes HTML-reserved characters |
| escapeSQL | escapeSQL(input: string): string | Escapes SQL-sensitive characters |
| sanitizePath | sanitizePath(input: string): string | Removes traversal and dot segments |
Performance Helpers
| Function | Signature | Description |
|----------|-----------|-------------|
| fastRepeat | fastRepeat(input: string, count: number): string | Fast string repetition |
| fastPadLeft | fastPadLeft(input: string, length: number, char?: string): string | Fast left padding |
Stream Utilities
| Function | Signature | Description |
|----------|-----------|-------------|
| chunkString | chunkString(input: string, size: number): string[] | Split string into chunks |
| streamTransform | streamTransform(chunks: string[], transformer: (chunk: string) => string): string | Transform and concatenate |
Chaining & Fluent API
| Function | Signature | Description |
|----------|-----------|-------------|
| chain | chain(input: string): StringChain | Create a chainable string wrapper |
| StringChain#trim | trim(): this | Trim leading/trailing whitespace |
| StringChain#toUpper | toUpper(): this | Uppercase with default locale rules |
| StringChain#toLower | toLower(): this | Lowercase with default locale rules |
| StringChain#replace | replace(search: string | RegExp, replacement: string): this | Replace with string or RegExp |
| StringChain#reverse | reverse(): this | Reverse by Unicode code points |
| StringChain#valueOf | valueOf(): string | Get the current value |
| StringChain#toString | toString(): string | String coercion output |
Lazy Evaluation
| Function | Signature | Description |
|----------|-----------|-------------|
| lazy | lazy(input: string): LazyString | Create a lazy string wrapper |
| LazyString#map | map(fn: (input: string) => string): this | Register a deferred transform |
| LazyString#trim | trim(): this | Register a trim operation |
| LazyString#toUpper | toUpper(): this | Register uppercase conversion |
| LazyString#toLower | toLower(): this | Register lowercase conversion |
| LazyString#execute | execute(): string | Execute all operations in order |
Template Interpolation
| Function | Signature | Description |
|----------|-----------|-------------|
| template | template(input: string, variables: Record<string, any>): string | Replace {{key}} placeholders |
Plugin System
| Function | Signature | Description |
|----------|-----------|-------------|
| registerPlugin | registerPlugin(plugin: StringExtnPlugin): void | Register a named plugin |
| runPlugin | runPlugin(name: string, input: string, ...args: any[]): string | Execute a plugin by name |
| listPlugins | listPlugins(): string[] | List registered plugin names |
Examples
Example 1: Text Processing Pipeline
import { trim, map, filter } from 'string-extn';
const input = ' HELLO WORLD ';
const result = trim(input)
.toLowerCase()
.split(' ')
.map(word => filter(word, c => 'aeiou'.includes(c)))
.join(',');
console.log(result); // "e,o"Example 2: Case Conversion
import { toCamelCase, toKebabCase, toSnakeCase, toPascalCase } from 'string-extn';
const text = 'hello-world-example';
console.log(toCamelCase(text)); // "helloWorldExample"
console.log(toKebabCase('helloWorld')); // "hello-world"
console.log(toSnakeCase('helloWorld')); // "hello_world"
console.log(toPascalCase(text)); // "HelloWorldExample"Example 3: String Similarity & Diff
import { similarity, diff } from 'string-extn';
const str1 = 'hello';
const str2 = 'hallo';
console.log(similarity(str1, str2)); // 0.8 (80% similar - one character different)
console.log(diff('abc', 'bcd')); // ["-a", "+d"]Example 4: Masking Sensitive Data
import { mask, redact } from 'string-extn';
// Mask credit card
const cardNumber = '4532111111111111';
console.log(mask(cardNumber, 4)); // "············1111"
// Redact email patterns
const text = 'Contact [email protected] or [email protected]';
console.log(redact(text, [/@\w+\.\w+/g])); // "Contact [REDACTED] or [REDACTED]"Example 5: URL & Filename Safe Conversion
import { slugify, filenameSafe } from 'string-extn';
console.log(slugify('Hello World! Welcome')); // "hello-world-welcome"
console.log(slugify('Café au Lait')); // "cafe-au-lait"
console.log(filenameSafe('File<>Name?.txt')); // "FileName.txt"Example 6: String Validation
import {
isEmail, isURL, isStrongPassword, isIPv4,
isPalindrome, isJSON
} from 'string-extn';
console.log(isEmail('[email protected]')); // true
console.log(isURL('https://example.com')); // true
console.log(isStrongPassword('MyPass@123')); // true
console.log(isIPv4('192.168.1.1')); // true
console.log(isPalindrome('A man a plan a canal Panama')); // true
console.log(isJSON('{"key":"value"}')); // trueExample 7: Emoji Handling with Unicode
import { lengthUnicode, unicodeSlice, reverseUnicode } from 'string-extn';
const message = 'Hello 👨👩👧👦 World 🇺🇸';
console.log(lengthUnicode(message)); // Correctly counts family emoji as 1
console.log(unicodeSlice(message, 6, 8)); // "👨👩👧👦 "
console.log(reverseUnicode(message)); // Preserves emoji integrityExample 8: Internationalization and Security
import { localeCompare, normalizeUnicode, escapeHTML, sanitizePath } from 'string-extn';
console.log(localeCompare('resume', 'résumé', 'en', 'accent')); // Non-zero
console.log(normalizeUnicode('e\u0301', 'NFC')); // "\u00e9"
console.log(escapeHTML('<script>alert(1)</script>')); // Escaped HTML entities
console.log(sanitizePath('/var/../tmp')); // "/var/tmp"Example 9: Performance and Streams
import { fastRepeat, fastPadLeft, chunkString, streamTransform } from 'string-extn';
console.log(fastRepeat('ab', 4)); // "abababab"
console.log(fastPadLeft('7', 3, '0')); // "007"
const chunks = chunkString('abcdef', 2); // ["ab", "cd", "ef"]
console.log(streamTransform(chunks, c => c.toUpperCase())); // "ABCDEF"Example 10: Function Composition
import { compose } from 'string-extn';
const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
const addPrefix = (s: string) => 'Hello, ' + s;
const addExclamation = (s: string) => s + '!';
const greet = compose(addExclamation, addPrefix, capitalize);
console.log(greet('world')); // "Hello, World!"Testing
Run the Test Suite
npm testBuild the Library
npm run buildThis generates compiled JavaScript in the dist/ folder.
Link Locally for Testing
# In the string-extn folder
npm link
# In your test project folder
npm link string-extnDevelopment Commands
npm install # Install dependencies
npm run build # Build the library
npm test # Run tests
npm link # Link for local testingLicense
MIT © Balaji Katta Venkatarathnam
