A comprehensive JavaScript library for string, number, and array manipulation inspired by Laravel's helper classes. This package provides a wide range of methods for working with strings, numbers, and arrays in a clean and intuitive way.
- Installation
- 🎮 Demo & Playground
- TypeScript Support
- Usage
- Method Overview
- Fluent Strings
- Advanced Usage
- Available Methods
- Number Formatting (NumberClass)
- Array Manipulation (ArrClass)
- Testing
- License
- Credits
- Autocomplete & IntelliSense
npm install stringx-jsTry StringX-JS online without installing anything!
🌐 stringx-js.com - Interactive playground with:
- ✨ Live Editor - Test all Str and Number methods in real-time
- 🔗 Chain Builder - Visual tool to build fluent method chains
- 📚 Interactive Examples - Browse and run code snippets
- 🎯 Method Explorer - Discover all 95+ string methods with live demos
- 💡 TypeScript Support - See type hints and autocomplete in action
Perfect for:
- 🚀 Quick experimentation before installing
- 📖 Learning the API interactively
- 🔍 Discovering new methods
- 🎓 Teaching and demonstrations
StringX-JS includes full TypeScript type definitions out of the box! No need to install separate @types packages.
import Str from 'stringx-js';
// Full type safety and IntelliSense support
const result: string = Str.of('hello_world')
    .camel()
    .append('Test')
    .toString();
// Type inference works automatically
const slug = Str.slug('Hello World'); // Type: string
const isValid = Str.isUuid(value);     // Type: boolean
const matches = Str.matchAll(/\d+/g, text); // Type: string[]TypeScript features:
- ✅ Full type definitions for all methods
- ✅ Generic type support for callbacks
- ✅ Proper return type inference
- ✅ IntelliSense/autocomplete in VS Code
- ✅ Compile-time type checking
See examples/typescript-example.ts for comprehensive TypeScript usage examples.
import Str from 'stringx-js';
// Convert to camelCase
Str.camel('foo_bar'); // 'fooBar'
// Generate a UUID
Str.uuid(); // 'e3c2d7a4-...'
// Limit string length
Str.limit('The quick brown fox', 10); // 'The quick...'StringX-JS supports Laravel-style fluent method chaining using the of() method:
import Str from 'stringx-js';
// Chain multiple methods together
const result = Str.of('  hello world  ')
    .trim()
    .camel()
    .append('Test')
    .slug('-')
    .upper()
    .toString();
// Result: 'HELLO-WORLD-TEST'
// Generate username from email
const username = Str.of('John.Doe@Example.com')
    .lower()
    .before('@')
    .replace('.', '_')
    .toString();
// Result: 'john_doe'
// Format database field to label
const label = Str.of('user_email_address')
    .replace('_', ' ')
    .title()
    .toString();
// Result: 'User Email Address'
// Conditional transformations
const displayName = Str.of('john')
    .when(isPremium, str => str.append(' ⭐'))
    .ucfirst()
    .toString();
// Result: 'John ⭐' (if isPremium is true)
// Using in template literals
const name = Str.of('john doe').title();
console.log(`Hello, ${name}!`); // "Hello, John Doe!"All chainable methods return a Stringable instance, allowing you to chain as many operations as needed. Use .toString() or .valueOf() to get the final string value.
StringX-JS provides 95+ methods organized into the following categories:
| Category | Methods | 
|---|---|
| Case Conversion | camel,kebab,snake,studly,pascal,title,headline,upper,lower,ucfirst,lcfirst,apa,convertCase | 
| String Extraction | after,afterLast,before,beforeLast,between,betweenFirst,charAt,substr,take | 
| String Checking | contains,containsAll,doesntContain,startsWith,doesntStartWith,endsWith,doesntEndWith,is,isAscii,isJson,isUrl,isUuid,isUlid,isMatch | 
| String Manipulation | limit,words,mask,trim,ltrim,rtrim,squish,chopStart,chopEnd,finish,start,wrap,unwrap,reverse,ascii,transliterate,wordWrap | 
| String Replacement | replace,replaceFirst,replaceLast,replaceArray,replaceStart,replaceEnd,replaceMatches,remove,swap,deduplicate,substrReplace | 
| Pattern Matching | match,matchAll,isMatch | 
| Padding | padBoth,padLeft,padRight | 
| String Information | length,wordCount,substrCount,position | 
| String Generation | random,password,uuid,uuid7,ulid | 
| Pluralization | plural,singular,pluralStudly,pluralPascal | 
| Other Utilities | slug,numbers,excerpt,ucsplit,repeat | 
| Encoding | toBase64,fromBase64 | 
| Factories | createUuidsUsing,createUuidsNormally,createUlidsUsing,createUlidsNormally,createRandomStringsUsing,createRandomStringsNormally | 
| Cache Management | flushCache | 
The Str.of() method returns a Stringable instance that allows for fluent method chaining, providing a more fluent, object-oriented interface for working with string values. This mirrors Laravel's Fluent Strings implementation.
const str = Str.of('hello world');All string manipulation methods are available for chaining:
Str.of('  foo bar  ')
    .trim()           // Remove whitespace
    .camel()          // Convert to camelCase: 'fooBar'
    .append('Test')   // Append: 'fooBarTest'
    .slug()           // Convert to slug: 'foo-bar-test'
    .upper();         // Uppercase: 'FOO-BAR-TEST'const stringable = Str.of('hello').upper();
// Get string value
stringable.toString();  // 'HELLO'
stringable.valueOf();   // 'HELLO'
// Use in string contexts
`Result: ${stringable}`  // 'Result: HELLO'
'Value: ' + stringable   // 'Value: HELLO'
// JSON serialization
JSON.stringify({ name: Str.of('john').title() })  // '{"name":"John"}'The Stringable class includes special utility methods for chaining:
Append one or more strings to the end.
Str.of('Hello').append(' ', 'World', '!').toString(); // 'Hello World!'Prepend one or more strings to the beginning.
Str.of('World').prepend('Hello ', '').toString(); // 'Hello World'Pass the string through a callback function.
Str.of('hello')
    .pipe(str => str.toUpperCase())
    .toString(); // 'HELLO'Execute a callback without modifying the string (useful for debugging).
Str.of('hello')
    .tap(val => console.log('Current value:', val))
    .upper()
    .toString(); // Logs 'Current value: hello', returns 'HELLO'Conditionally execute a transformation.
Str.of('hello')
    .when(true, str => str.upper())
    .toString(); // 'HELLO'
Str.of('hello')
    .when(false, str => str.upper(), str => str.reverse())
    .toString(); // 'olleh'Execute a transformation unless the condition is true.
Str.of('hello')
    .unless(false, str => str.upper())
    .toString(); // 'HELLO'Execute callback only if the string is empty.
Str.of('')
    .whenEmpty(str => str.append('default'))
    .toString(); // 'default'Execute callback only if the string is not empty.
Str.of('hello')
    .whenNotEmpty(str => str.upper())
    .toString(); // 'HELLO'Check if the string is empty or not.
Str.of('').isEmpty();        // true
Str.of('hello').isNotEmpty(); // trueDump the current value to console and continue chaining.
Str.of('hello')
    .dump()      // Logs: 'hello'
    .upper()
    .dump()      // Logs: 'HELLO'
    .toString(); // 'HELLO'Dump the current value and halt execution (like Laravel's dd()).
Str.of('hello')
    .upper()
    .dd();  // Logs 'HELLO' and throws error// Clean and format user input
const cleanInput = Str.of(userInput)
    .trim()
    .squish()
    .ucfirst()
    .toString();
// Generate SEO-friendly URLs
const url = Str.of(article.title)
    .slug()
    .prepend('/blog/')
    .append('/')
    .append(article.id)
    .toString();
// Format validation messages
const message = Str.of(fieldName)
    .replace('_', ' ')
    .title()
    .prepend('The ')
    .append(' is required')
    .toString();
// Conditional user badges
const displayName = Str.of(user.name)
    .when(user.isPremium, str => str.append(' ⭐'))
    .when(user.isVerified, str => str.append(' ✓'))
    .toString();The pipe() method allows you to pass the string through any custom function, enabling unlimited flexibility:
// Complex email masking
const maskedEmail = Str.of('john.doe@example.com')
    .pipe(email => {
        const [name, domain] = email.split('@');
        const maskedName = name[0] + '*'.repeat(name.length - 1);
        return `${maskedName}@${domain}`;
    })
    .toString(); // 'j*******@example.com'
// Custom business logic
const processedText = Str.of('user_input_123')
    .pipe(str => str.replace(/\d+/g, ''))
    .pipe(str => str.toUpperCase())
    .pipe(str => customBusinessLogic(str))
    .toString();
// Integration with external libraries
import slugify from 'some-slugify-lib';
const slug = Str.of(title)
    .trim()
    .pipe(str => slugify(str, { strict: true }))
    .toString();Debug your transformation chains without breaking the flow:
// Using tap() to inspect values at each step
const result = Str.of('  HELLO_WORLD  ')
    .tap(val => console.log('Original:', val))           // Original:   HELLO_WORLD
    .trim()
    .tap(val => console.log('After trim:', val))         // After trim: HELLO_WORLD
    .lower()
    .tap(val => console.log('After lower:', val))        // After lower: hello_world
    .camel()
    .tap(val => console.log('After camel:', val))        // After camel: helloWorld
    .toString();
// Using dump() for quick logging
const processed = Str.of(userInput)
    .trim()
    .dump()        // Logs the value
    .squish()
    .dump()        // Logs again
    .ucfirst()
    .toString();
// Conditional debugging
const debugMode = process.env.DEBUG === 'true';
const output = Str.of(data)
    .trim()
    .when(debugMode, str => str.dump())  // Only logs in debug mode
    .camel()
    .toString();Build complex conditional transformation chains:
// Multiple conditions with fallbacks
const formatUsername = (name, options = {}) => {
    return Str.of(name)
        .trim()
        .lower()
        .when(options.removeSpaces, str => str.replace(' ', ''))
        .when(options.maxLength, (str) => str.limit(options.maxLength, ''))
        .whenEmpty(str => str.append('anonymous'))
        .unless(options.allowSpecialChars, str => str.replace(/[^a-z0-9]/g, ''))
        .when(
            str => str.length() < 3,
            str => str.padRight(3, 'x'),
            str => str  // else, return unchanged
        )
        .toString();
};
// Nested conditions
const displayPrice = Str.of(price.toString())
    .when(
        currency === 'USD',
        str => str.prepend('$'),
        str => str.append(` ${currency}`)
    )
    .when(
        isDiscounted,
        str => str.append(' (SALE!)').upper()
    )
    .whenNotEmpty(str => str.wrap('<span class="price">', '</span>'))
    .toString();
// Condition based on string content
const processApiResponse = Str.of(response)
    .when(
        str => str.contains('error'),
        str => str.upper().prepend('⚠️ '),
        str => str.prepend('✅ ')
    )
    .when(
        str => str.length() > 100,
        str => str.limit(100)
    )
    .toString();Transform API responses and data structures:
// Transform API error messages
const formatApiError = (errorCode) => {
    return Str.of(errorCode)
        .upper()                                    // ERROR_USER_NOT_FOUND
        .replace('_', ' ')                          // ERROR USER NOT FOUND
        .after('ERROR ')                            // USER NOT FOUND
        .lower()                                    // user not found
        .ucfirst()                                  // User not found
        .append('.')                                // User not found.
        .toString();
};
// Generate API endpoints
const buildEndpoint = (resource, id, action) => {
    return Str.of(resource)
        .plural()                                   // users
        .kebab()                                    // users (already kebab)
        .prepend('/api/v1/')                        // /api/v1/users
        .when(id, str => str.append(`/${id}`))      // /api/v1/users/123
        .when(action, str => str.append(`/${action}`)) // /api/v1/users/123/activate
        .finish('/')                                // /api/v1/users/123/activate/
        .toString();
};
// Parse and format JSON paths
const formatJsonPath = Str.of('data.user.profile.email')
    .explode('.')                                   // Would return array if we had explode()
    .pipe(parts => parts.join('.'))                 // Using pipe as alternative
    .replace('.', ' → ')                            // data → user → profile → email
    .title()                                        // Data → User → Profile → Email
    .toString();Advanced text cleaning and formatting:
// Clean and format user-generated content
const sanitizeContent = (content) => {
    return Str.of(content)
        .trim()
        .squish()                                   // Remove extra whitespace
        .replace(/[<>]/g, '')                       // Remove potential HTML
        .deduplicate(['.', '!', '?'])               // Remove duplicate punctuation
        .limit(500)                                 // Limit length
        .when(
            str => !str.test(/[.!?]$/),
            str => str.append('...')                // Add ellipsis if needed
        )
        .toString();
};
// Extract and format hashtags
const formatHashtags = (text) => {
    return Str.of(text)
        .matchAll(/#\w+/g)
        .pipe(tags => tags.map(tag =>
            Str.of(tag)
                .chopStart('#')
                .lower()
                .toString()
        ))
        .pipe(tags => tags.join(', '));
};
// Generate readable IDs
const generateReadableId = (text) => {
    return Str.of(text)
        .slug()
        .append('-')
        .append(Str.random(8).lower())
        .toString(); // 'my-awesome-post-a3f7d9e2'
};Mix both approaches for optimal code:
// Use static methods for simple checks
if (Str.contains(email, '@')) {
    // Use fluent for complex transformations
    const formatted = Str.of(email)
        .lower()
        .trim()
        .before('@')
        .toString();
}
// Static for generation, fluent for formatting
const userId = Str.uuid();
const formattedId = Str.of(userId)
    .upper()
    .replace(/-/g, '')
    .limit(12)
    .toString();
// Create reusable transformation functions
const toSlug = (text) => Str.of(text).slug().toString();
const toHandle = (name) => Str.of(name).lower().replace(' ', '').prepend('@').toString();
const slug = toSlug('Hello World');      // 'hello-world'
const handle = toHandle('John Doe');     // '@johndoe'Handle edge cases gracefully:
// Safe transformations with fallbacks
const safeFormat = (input, fallback = 'N/A') => {
    return Str.of(input ?? '')
        .whenEmpty(str => str.append(fallback))
        .trim()
        .toString();
};
// Validate and transform
const processUsername = (username) => {
    const processed = Str.of(username)
        .trim()
        .lower()
        .toString();
    // Validate using static methods
    if (!Str.isMatch(/^[a-z0-9_]{3,20}$/, processed)) {
        throw new Error('Invalid username format');
    }
    return processed;
};
// Try-catch with fluent chains
try {
    const result = Str.of(jsonString)
        .pipe(str => {
            if (!Str.isJson(str)) throw new Error('Invalid JSON');
            return JSON.parse(str);
        })
        .pipe(obj => obj.data.value)
        .toString();
} catch (error) {
    console.error('Processing failed:', error.message);
}Tips for optimal performance:
// Cache Stringable instances for repeated use
const formatter = Str.of(template);
const results = data.map(item =>
    formatter.replace('{name}', item.name).toString()
);
// Use static methods for single operations
const lower = Str.lower(text);  // Faster than Str.of(text).lower().toString()
// Chain when doing multiple operations
const processed = Str.of(text)  // Better than multiple Str calls
    .trim()
    .lower()
    .camel()
    .toString();
// Clear caches if processing lots of unique strings
Str.flushCache();Return the remainder of a string after the first occurrence of a given value.
Str.after('This is my name', 'This is'); // ' my name'Return the remainder of a string after the last occurrence of a given value.
Str.afterLast('App\\Http\\Controllers\\Controller', '\\'); // 'Controller'Get the portion of a string before the first occurrence of a given value.
Str.before('This is my name', 'my name'); // 'This is 'Get the portion of a string before the last occurrence of a given value.
Str.beforeLast('This is my name', 'is'); // 'This 'Get the portion of a string between two given values.
Str.between('This is my name', 'This', 'name'); // ' is my 'Get the smallest possible portion of a string between two given values.
Str.betweenFirst('[a] bc [d]', '[', ']'); // 'a'Convert a value to camelCase.
Str.camel('foo_bar'); // 'fooBar'
Str.camel('foo-bar'); // 'fooBar'Convert a string to kebab-case.
Str.kebab('fooBar'); // 'foo-bar'Convert a string to snake_case.
Str.snake('fooBar'); // 'foo_bar'
Str.snake('fooBar', '-'); // 'foo-bar'Convert a value to StudlyCase (PascalCase).
Str.studly('foo_bar'); // 'FooBar'
Str.pascal('foo_bar'); // 'FooBar'Convert the given string to title case.
Str.title('hello world'); // 'Hello World'Convert the given string to title case for each word.
Str.headline('hello_world'); // 'Hello World'
Str.headline('hello-world'); // 'Hello World'Convert the given string to lower-case.
Str.lower('HELLO'); // 'hello'Convert the given string to upper-case.
Str.upper('hello'); // 'HELLO'Make a string's first character uppercase.
Str.ucfirst('hello'); // 'Hello'Make a string's first character lowercase.
Str.lcfirst('Hello'); // 'hello'Convert the given string to APA-style title case.
Str.apa('the quick brown fox'); // 'The Quick Brown Fox'
Str.apa('a guide to javascript'); // 'A Guide to JavaScript'Convert case of a string using different modes.
Str.convertCase('Hello', 'upper'); // 'HELLO'
Str.convertCase('HELLO', 'lower'); // 'hello'
Str.convertCase('hello world', 'title'); // 'Hello World'Limit the number of characters in a string.
Str.limit('The quick brown fox', 10); // 'The quick...'
Str.limit('The quick brown fox', 10, ' >'); // 'The quick >'Limit the number of words in a string.
Str.words('The quick brown fox jumps', 3); // 'The quick brown...'Masks a portion of a string with a repeated character.
Str.mask('email@example.com', '*', 5); // 'email************'
Str.mask('1234567890', '*', 0, 4); // '****567890'Remove whitespace (or other characters) from both ends of a string.
Str.trim('  hello  '); // 'hello'
Str.trim('/hello/', '/'); // 'hello'Remove whitespace (or other characters) from the beginning of a string.
Str.ltrim('  hello  '); // 'hello  'Remove whitespace (or other characters) from the end of a string.
Str.rtrim('  hello  '); // '  hello'Remove all "extra" blank space from the given string.
Str.squish('  hello   world  '); // 'hello world'Remove the given string(s) if it exists at the start of the haystack.
Str.chopStart('Hello World', 'Hello '); // 'World'
Str.chopStart('Hello World', ['Hi ', 'Hello ']); // 'World'Remove the given string(s) if it exists at the end of the haystack.
Str.chopEnd('Hello World', ' World'); // 'Hello'Cap a string with a single instance of a given value.
Str.finish('this/string', '/'); // 'this/string/'
Str.finish('this/string/', '/'); // 'this/string/'Begin a string with a single instance of a given value.
Str.start('this/string', '/'); // '/this/string'
Str.start('/this/string', '/'); // '/this/string'Wrap the string with the given strings.
Str.wrap('Hello', '"'); // '"Hello"'
Str.wrap('Hello', '<', '>'); // '<Hello>'Unwrap the string with the given strings.
Str.unwrap('"Hello"', '"'); // 'Hello'
Str.unwrap('<Hello>', '<', '>'); // 'Hello'Transliterate a string to its closest ASCII representation.
Str.ascii('café'); // 'cafe'
Str.ascii('über'); // 'uber'Transliterate a string to its closest ASCII representation with control over unknown characters. Handles accents, diacritics, and special ligatures (ß, æ, Æ, œ, Œ).
// Remove accents and diacritics
Str.transliterate('café'); // 'cafe'
Str.transliterate('naïve'); // 'naive'
Str.transliterate('Übermensch'); // 'Ubermensch'
// Handle German sharp s and Latin ligatures
Str.transliterate('straße'); // 'strasse'
Str.transliterate('Æon'); // 'AEon'
Str.transliterate("hors d'œuvre"); // "hors d'oeuvre"
// Strict mode replaces non-ASCII characters
Str.transliterate('Hello 世界', '?', true); // 'Hello ??'Wrap a string to a given number of characters.
Str.wordWrap('This is a very long sentence', 20);
// 'This is a very long\nsentence'
Str.wordWrap('Short text', 20); // 'Short text'Replace the given value in the given string.
Str.replace('foo', 'bar', 'foo foo'); // 'bar bar'
Str.replace(['foo', 'bar'], 'baz', 'foo bar'); // 'baz baz'Replace the first occurrence of a given value in the string.
Str.replaceFirst('foo', 'bar', 'foo foo'); // 'bar foo'Replace the last occurrence of a given value in the string.
Str.replaceLast('foo', 'bar', 'foo foo'); // 'foo bar'Remove any occurrence of the given string in the subject.
Str.remove('foo', 'foo bar foo'); // ' bar 'Replace consecutive instances of a given character with a single character.
Str.deduplicate('hello  world'); // 'hello world'
Str.deduplicate('foo---bar', '-'); // 'foo-bar'
Str.deduplicate('foo  --  bar', [' ', '-']); // 'foo - bar'Replace a given value in the string sequentially with an array.
Str.replaceArray('?', ['foo', 'bar'], '? ?'); // 'foo bar'
Str.replaceArray('?', ['8:30', '9:00'], 'The event runs from ? to ?');
// 'The event runs from 8:30 to 9:00'Replace the first occurrence of the given value if it appears at the start.
Str.replaceStart('Hello', 'Hi', 'Hello World'); // 'Hi World'
Str.replaceStart('Hello', 'Hi', 'World Hello'); // 'World Hello'Replace the last occurrence of a given value if it appears at the end.
Str.replaceEnd('World', 'Universe', 'Hello World'); // 'Hello Universe'
Str.replaceEnd('World', 'Universe', 'World Hello'); // 'World Hello'Replace the patterns matching the given regular expression.
Str.replaceMatches(/\d+/, 'X', 'Order 123'); // 'Order X'
Str.replaceMatches(/\d+/g, 'X', 'Order 123 and 456'); // 'Order X and X'
Str.replaceMatches(/\d+/g, 'X', 'a1 b2 c3', 2); // 'aX bX c3'Swap multiple keywords in a string with other keywords.
Str.swap({foo: 'bar', bar: 'baz'}, 'foo bar'); // 'bar baz'
Str.swap({Hello: 'Hi', World: 'Universe'}, 'Hello World'); // 'Hi Universe'Replace text within a portion of a string.
Str.substrReplace('Hello World', 'Goodbye', 0, 5); // 'Goodbye World'
Str.substrReplace('1234567890', 'xxx', 3, 3); // '123xxx7890'Determine if a given string contains a given substring.
Str.contains('This is my name', 'my'); // true
Str.contains('This is my name', ['my', 'name']); // true
Str.contains('This is my name', 'MY', true); // trueDetermine if a given string contains all array values.
Str.containsAll('This is my name', ['my', 'name']); // true
Str.containsAll('This is my name', ['my', 'foo']); // falseDetermine if a given string doesn't contain a given substring.
Str.doesntContain('This is my name', 'foo'); // trueDetermine if a given string starts with a given substring.
Str.startsWith('Hello World', 'Hello'); // true
Str.startsWith('Hello World', ['Hello', 'Hi']); // trueDetermine if a given string doesn't start with a given substring.
Str.doesntStartWith('Hello World', 'Hi'); // trueDetermine if a given string ends with a given substring.
Str.endsWith('Hello World', 'World'); // true
Str.endsWith('Hello World', ['World', 'Earth']); // trueDetermine if a given string doesn't end with a given substring.
Str.doesntEndWith('Hello World', 'Earth'); // trueDetermine if a given string matches a given pattern.
Str.is('*', 'foo'); // true
Str.is('foo*', 'foobar'); // true
Str.is(['foo', 'bar'], 'foo'); // trueDetermine if a given string is 7 bit ASCII.
Str.isAscii('Hello World'); // true
Str.isAscii('Hello 世界'); // falseDetermine if a given value is valid JSON.
Str.isJson('{"name":"John"}'); // true
Str.isJson('not json'); // falseDetermine if a given value is a valid URL.
Str.isUrl('https://example.com'); // true
Str.isUrl('http://example.com', ['https']); // falseDetermine if a given value is a valid UUID.
const uuid = Str.uuid();
Str.isUuid(uuid); // true
Str.isUuid('not-a-uuid'); // falseDetermine if a given value is a valid ULID.
const ulid = Str.ulid();
Str.isUlid(ulid); // trueReturn the length of the given string.
Str.length('Hello'); // 5
Str.length('👍'); // 1 (handles Unicode correctly)Get the number of words a string contains.
Str.wordCount('Hello World'); // 2Returns the number of substring occurrences.
Str.substrCount('foo foo foo', 'foo'); // 3Get the string matching the given pattern.
Str.match(/(\d+)/, 'Order 123'); // '123'Determine if a given string matches a given pattern.
Str.isMatch(/\d+/, '123'); // trueGet all strings matching the given pattern.
Str.matchAll(/\d+/g, 'Order 123 and 456'); // ['123', '456']Pad both sides of a string with another.
Str.padBoth('James', 10, '_'); // '__James___'Pad the left side of a string with another.
Str.padLeft('James', 10, '-'); // '-----James'Pad the right side of a string with another.
Str.padRight('James', 10, '-'); // 'James-----'Get the character at the specified index.
Str.charAt('Hello', 0); // 'H'
Str.charAt('Hello', -1); // 'o'Get the plural form of an English word.
Str.plural('car'); // 'cars'
Str.plural('car', 1); // 'car'
Str.plural('city'); // 'cities'Get the singular form of an English word.
Str.singular('cars'); // 'car'
Str.singular('cities'); // 'city'Generate a URL friendly "slug" from a given string.
Str.slug('Hello World'); // 'hello-world'
Str.slug('Hello World', '_'); // 'hello_world'Generate a random, secure string.
Str.random(); // 'aB3dE5fG7hI9jK1L'
Str.random(32); // 32 character random stringRemove all non-numeric characters from a string.
Str.numbers('abc123def456'); // '123456'
Str.numbers('Price: $19.99'); // '1999'Reverse the given string.
Str.reverse('Hello'); // 'olleH'Returns the portion of the string specified by the start and length parameters.
Str.substr('Hello World', 0, 5); // 'Hello'
Str.substr('Hello World', 6); // 'World'
Str.substr('Hello World', -5); // 'World'Take the first or last {limit} characters of a string.
Str.take('Hello World', 5); // 'Hello'
Str.take('Hello World', -5); // 'World'Repeat the given string.
Str.repeat('a', 3); // 'aaa'Split a string into pieces by uppercase characters.
Str.ucsplit('FooBar'); // ['Foo', 'Bar']Extracts an excerpt from text that matches the first instance of a phrase.
Str.excerpt('This is a long text with the word Laravel', 'Laravel');
// '...with the word Laravel'
Str.excerpt('This is my name', 'my', {radius: 3});
// '...is my na...'
Str.excerpt('This is my name', '', {radius: 4});
// 'This...'Generate a secure password.
Str.password(); // 'aB3!dE5@fG7#hI9$'
Str.password(16); // 16 character password
Str.password(12, true, true, false); // Letters and numbers only
Str.password(8, true, false, false); // Letters onlyFind the position of the first occurrence of a substring.
Str.position('Hello World', 'World'); // 6
Str.position('Hello World', 'o'); // 4
Str.position('Hello World', 'o', 5); // 7
Str.position('Hello World', 'xyz'); // falsePluralize the last word of an English, studly caps case string.
Str.pluralStudly('UserProfile'); // 'UserProfiles'
Str.pluralStudly('VerifiedHuman'); // 'VerifiedHumans'
Str.pluralStudly('Child', 1); // 'Child'Pluralize the last word of an English, Pascal case string (alias for pluralStudly).
Str.pluralPascal('UserProfile'); // 'UserProfiles'
Str.pluralPascal('Child', 1); // 'Child'Convert the given string to Base64 encoding.
Str.toBase64('Hello World'); // 'SGVsbG8gV29ybGQ='Decode the given Base64 encoded string.
Str.fromBase64('SGVsbG8gV29ybGQ='); // 'Hello World'Generate a UUID (version 4).
Str.uuid(); // 'e3c2d7a4-5c8e-4b2f-a1d3-9e7f6c5b4a3d'Generate a UUID (version 7).
Str.uuid7(); // '018f4f9e-5c8e-7b2f-a1d3-9e7f6c5b4a3d'Generate a ULID.
Str.ulid(); // '01HQXYZ123ABC456DEF789GHJ'You can customize the behavior of UUID, ULID, and random string generation:
Set the callable that will be used to generate UUIDs.
Str.createUuidsUsing(() => 'custom-uuid');
Str.uuid(); // 'custom-uuid'Indicate that UUIDs should be created normally (reset to default).
Str.createUuidsNormally();
Str.uuid(); // Regular UUID generation resumesSet the callable that will be used to generate ULIDs.
Str.createUlidsUsing(() => 'custom-ulid');
Str.ulid(); // 'custom-ulid'Indicate that ULIDs should be created normally (reset to default).
Str.createUlidsNormally();
Str.ulid(); // Regular ULID generation resumesSet the callable that will be used to generate random strings.
Str.createRandomStringsUsing((length) => 'x'.repeat(length));
Str.random(5); // 'xxxxx'Indicate that random strings should be created normally (reset to default).
Str.createRandomStringsNormally();
Str.random(16); // Regular random string generation resumesRemove all strings from the casing caches.
Str.flushCache();StringX-JS includes a powerful Number class for formatting and manipulating numbers, inspired by Laravel's Number helper. All methods are static and can be used directly.
import { Number } from 'stringx-js';Format numbers with thousand separators according to the current locale.
Number.format(1234.567);        // "1,234.567"
Number.format(1234.567, 2);     // "1,234.57"
Number.format(1234.5, null, 2); // "1,234.5" (max 2 decimals)Convert numbers to percentage format.
Number.percentage(50);          // "50%"
Number.percentage(66.666, 2);   // "66.67%"
Number.percentage(33.333, 1);   // "33.3%"Format numbers as currency.
Number.currency(1234.56);             // "$1,234.56"
Number.currency(1234.56, 'EUR');      // "€1,234.56"
Number.currency(1234.5, 'USD', null, 2); // "$1,234.50"Convert bytes to human-readable file sizes.
Number.fileSize(1024);              // "1 KB"
Number.fileSize(1536, 2);           // "1.50 KB"
Number.fileSize(1024 * 1024 * 5);   // "5 MB"
Number.fileSize(1024 * 1024 * 1024); // "1 GB"Convert numbers to human-readable format.
Number.forHumans(1000);              // "1 thousand"
Number.forHumans(1500000);           // "1.5 million"
Number.forHumans(1000000000);        // "1 billion"
Number.forHumans(1000, 0, null, true); // "1K" (abbreviated)Abbreviate large numbers (K, M, B, T, Q).
Number.abbreviate(1000);        // "1K"
Number.abbreviate(1500000);     // "2M"
Number.abbreviate(1500000, 1);  // "1.5M"
Number.abbreviate(2500000000);  // "3B"Spell out numbers in words with multi-language support (powered by n2words).
// English (default)
Number.spell(42);               // "forty-two"
Number.spell(123);              // "one hundred and twenty-three"
// French
Number.spell(42, 'fr');         // "quarante-deux"
Number.spell(100, 'fr');        // "cent"
// Spanish
Number.spell(42, 'es');         // "cuarenta y dos"
Number.spell(100, 'es');        // "cien"
// German
Number.spell(42, 'de');         // "zweiundvierzig"
Number.spell(100, 'de');        // "einhundert"
// Supported languages: en, fr, es, de, ar, pt, it, ru, pl, uk, tr, nl, id, ko, vi, zh
// Thresholds
Number.spell(5, null, 10);      // "5" (don't spell, 5 <= 10)
Number.spell(15, null, 10);     // "fifteen" (spell, 15 > 10)Convert numbers to ordinal format (1st, 2nd, 3rd, etc.).
Number.ordinal(1);    // "1st"
Number.ordinal(22);   // "22nd"
Number.ordinal(103);  // "103rd"Spell out ordinal numbers.
Number.spellOrdinal(1);   // "first"
Number.spellOrdinal(22);  // "twenty-second"
Number.spellOrdinal(42);  // "forty-second"Parse formatted number strings with locale-aware decimal and thousands separators.
// English (default): period=decimal, comma=thousands
Number.parse("1,234.56");       // 1234.56
Number.parse("1 234.56");       // 1234.56
// French: comma=decimal, space=thousands
Number.parse("10,123", "fr");   // 10.123
Number.parse("1 234,56", "fr"); // 1234.56
// German: comma=decimal, period=thousands
Number.parse("1.234,56", "de"); // 1234.56
Number.parse("invalid");        // nullParse strings to integers with locale support.
Number.parseInt("1,234");          // 1234 (en)
Number.parseInt("123.99");         // 123
Number.parseInt("10,123", "fr");   // 10 (comma is decimal in French)Parse strings to floats with locale support.
Number.parseFloat("1,234.56");        // 1234.56 (en)
Number.parseFloat("10,123", "fr");    // 10.123 (fr)
Number.parseFloat("1.234,56", "de");  // 1234.56 (de)Clamp a number between min and max values.
Number.clamp(5, 1, 10);   // 5
Number.clamp(0, 1, 10);   // 1
Number.clamp(15, 1, 10);  // 10Generate pairs of min/max values for pagination or ranges.
Number.pairs(10, 3);
// [[0, 2], [3, 5], [6, 8], [9, 10]]
Number.pairs(10, 3, 1);
// [[1, 3], [4, 6], [7, 9], [10, 10]]Remove trailing zeros from decimals.
Number.trim(1.50);   // 1.5
Number.trim(1.00);   // 1
Number.trim(1.230);  // 1.23Set or get the default locale.
Number.useLocale('de-DE');
Number.format(1234.56); // "1.234,56" (German format)
Number.defaultLocale(); // "de-DE"Set or get the default currency.
Number.useCurrency('EUR');
Number.currency(1234.56); // "€1,234.56"
Number.defaultCurrency(); // "EUR"Temporarily use a different locale or currency for a callback.
// Temporarily use German locale
Number.withLocale('de-DE', () => {
    return Number.format(1234.56); // "1.234,56"
});
// Locale reverts to previous after callback
// Temporarily use Euro currency
Number.withCurrency('EUR', () => {
    return Number.currency(100); // "€100.00"
});
// Currency reverts to previous after callbackThe Number class includes full TypeScript support with comprehensive type definitions:
import { Number } from 'stringx-js';
const formatted: string = Number.format(1234.567, 2);
const parsed: number | null = Number.parse("1,234");
const pairs: Array<[number, number]> = Number.pairs(10, 3);StringX-JS includes a comprehensive Arr class for array and object manipulation, inspired by Laravel's Arr helper. All methods are static and provide powerful utilities for working with arrays and nested data structures.
import { Arr } from 'stringx-js';The Arr class excels at working with nested arrays and objects using dot notation:
Get an item from an array using "dot" notation.
const data = { user: { name: 'John', address: { city: 'NYC' } } };
Arr.get(data, 'user.name');           // 'John'
Arr.get(data, 'user.address.city');   // 'NYC'
Arr.get(data, 'user.age', 25);        // 25 (default)Set an array item using "dot" notation.
const obj = {};
Arr.set(obj, 'user.name', 'John');
// { user: { name: 'John' } }
Arr.set(obj, 'user.age', 30);
// { user: { name: 'John', age: 30 } }Check if keys exist using "dot" notation.
const data = { user: { name: 'John' } };
Arr.has(data, 'user.name');              // true
Arr.has(data, ['user.name', 'user.age']); // falseFlatten a multi-dimensional array with dots.
const nested = { user: { name: 'John', address: { city: 'NYC' } } };
Arr.dot(nested);
// { 'user.name': 'John', 'user.address.city': 'NYC' }Convert flattened "dot" notation back to expanded array.
const flat = { 'user.name': 'John', 'user.age': 30 };
Arr.undot(flat);
// { user: { name: 'John', age: 30 } }Filter the array using a callback.
const users = [
    { name: 'John', age: 30 },
    { name: 'Jane', age: 25 }
];
Arr.where(users, user => user.age > 26);
// [{ name: 'John', age: 30 }]Filter using the negation of the callback.
Arr.reject([1, 2, 3, 4], x => x > 2);
// [1, 2]Filter items where the value is not null or undefined.
Arr.whereNotNull([1, null, 2, undefined, 3]);
// [1, 2, 3]Return the first element passing a test.
Arr.first([1, 2, 3, 4]);              // 1
Arr.first([1, 2, 3, 4], x => x > 2);  // 3
Arr.first([], null, 'default');        // 'default'Return the last element passing a test.
Arr.last([1, 2, 3, 4]);              // 4
Arr.last([1, 2, 3, 4], x => x < 3);  // 2Get the sole item passing a test, or throw if not exactly one.
Arr.sole([1, 2, 3], x => x === 2);  // 2
// Throws on multiple matches
Arr.sole([1, 2, 3, 2], x => x === 2);  // Error: Multiple items found
// Throws on no matches
Arr.sole([1, 2, 3], x => x === 5);     // Error: Item not foundTake the first or last N items.
Arr.take([1, 2, 3, 4, 5], 3);    // [1, 2, 3]
Arr.take([1, 2, 3, 4, 5], -2);   // [4, 5] (from end)Get a subset of items by keys.
const data = { a: 1, b: 2, c: 3 };
Arr.only(data, ['a', 'c']);
// { a: 1, c: 3 }Get all items except specified keys.
const data = { a: 1, b: 2, c: 3 };
Arr.except(data, ['b']);
// { a: 1, c: 3 }Pluck values from an array of objects.
const users = [
    { name: 'John', age: 30 },
    { name: 'Jane', age: 25 }
];
Arr.pluck(users, 'name');
// ['John', 'Jane']
Arr.pluck(users, 'age', 'name');
// { John: 30, Jane: 25 }Select specific fields from array of objects.
const users = [
    { id: 1, name: 'John', age: 30, email: 'john@example.com' }
];
Arr.select(users, ['id', 'name']);
// [{ id: 1, name: 'John' }]Transform array elements.
Arr.map([1, 2, 3], x => x * 2);
// [2, 4, 6]
Arr.map({ a: 1, b: 2 }, (v, k) => v * 2);
// { a: 2, b: 4 }Create an associative array from a callback.
const users = [{ id: 1, name: 'John' }];
Arr.mapWithKeys(users, user => ({ [user.name]: user }));
// { John: { id: 1, name: 'John' } }Key an array by a field or callback.
const users = [
    { id: 1, name: 'John' },
    { id: 2, name: 'Jane' }
];
Arr.keyBy(users, 'id');
// { 1: { id: 1, name: 'John' }, 2: { id: 2, name: 'Jane' } }Flatten a multi-dimensional array.
Arr.flatten([1, [2, [3, 4]]], 1);
// [1, 2, [3, 4]]
Arr.flatten([1, [2, [3, 4]]]);
// [1, 2, 3, 4]Collapse an array of arrays into a single array.
Arr.collapse([[1, 2], [3, 4], [5]]);
// [1, 2, 3, 4, 5]Split array into two arrays based on a condition.
const [even, odd] = Arr.partition([1, 2, 3, 4], x => x % 2 === 0);
// even: [2, 4], odd: [1, 3]Divide into keys and values.
Arr.divide({ a: 1, b: 2 });
// [['a', 'b'], [1, 2]]Create all possible permutations.
Arr.crossJoin([1, 2], ['a', 'b']);
// [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]Randomly shuffle an array.
Arr.shuffle([1, 2, 3, 4, 5]);
// [3, 1, 5, 2, 4] (random order)Get random items from an array.
Arr.random([1, 2, 3, 4, 5]);      // 3 (single item)
Arr.random([1, 2, 3, 4, 5], 2);   // [4, 1] (multiple items)Sort the array.
Arr.sort([3, 1, 2]);
// [1, 2, 3]
const users = [{ age: 30 }, { age: 20 }];
Arr.sort(users, 'age');
// [{ age: 20 }, { age: 30 }]Sort in descending order.
Arr.sortDesc([1, 2, 3]);
// [3, 2, 1]Recursively sort arrays and objects.
Arr.sortRecursive({ b: 2, a: 1, c: { z: 26, x: 24 } });
// { a: 1, b: 2, c: { x: 24, z: 26 } }Check if key exists in array.
Arr.exists({ a: 1, b: 2 }, 'a');    // true
Arr.exists([1, 2, 3], 1);            // trueCheck if all items pass a test.
Arr.every([2, 4, 6], x => x % 2 === 0);
// trueCheck if any items pass a test.
Arr.some([1, 2, 3], x => x > 2);
// trueCheck if array is associative (object-like).
Arr.isAssoc({ a: 1, b: 2 });    // true
Arr.isAssoc([1, 2, 3]);          // falseCheck if array has sequential integer keys.
Arr.isList([1, 2, 3]);    // trueGet values with type validation - throws error if type doesn't match:
const data = {
    active: true,
    count: 42,
    price: 99.99,
    name: 'Product',
    tags: ['a', 'b']
};
Arr.boolean(data, 'active');    // true
Arr.integer(data, 'count');     // 42
Arr.float(data, 'price');       // 99.99
Arr.string(data, 'name');       // 'Product'
Arr.array(data, 'tags');        // ['a', 'b']
// Throws error if type mismatch
Arr.boolean(data, 'count');  // Error: must be a booleanJoin array items with optional final separator.
Arr.join(['a', 'b', 'c'], ', ');
// 'a, b, c'
Arr.join(['a', 'b', 'c'], ', ', ' and ');
// 'a, b and c' (Oxford comma style)Convert object to query string.
Arr.query({ page: 1, limit: 10, sort: 'name' });
// 'page=1&limit=10&sort=name'Compile to CSS classes.
Arr.toCssClasses(['btn', { active: true, disabled: false }]);
// 'btn active'Compile to CSS styles.
Arr.toCssStyles(['color: red', { 'font-size: 14px': true }]);
// 'color: red; font-size: 14px;'Wrap non-arrays in an array.
Arr.wrap('hello');     // ['hello']
Arr.wrap([1, 2]);      // [1, 2]
Arr.wrap(null);        // []Convert various types to arrays (iterables, objects with toArray(), plain objects).
Arr.from([1, 2, 3]);            // [1, 2, 3]
Arr.from(new Set([1, 2, 3]));   // [1, 2, 3]
Arr.from(new Map([['a', 1]]));  // [['a', 1]]
Arr.from({a: 1, b: 2});         // [1, 2] (values)
// Throws on scalar values
Arr.from('hello');  // Error
Arr.from(42);       // ErrorAdd element if key doesn't exist.
const obj = { a: 1 };
Arr.add(obj, 'b', 2);  // { a: 1, b: 2 }
Arr.add(obj, 'b', 3);  // { a: 1, b: 2 } (unchanged)Remove items using dot notation.
const obj = { a: 1, b: { c: 2, d: 3 } };
Arr.forget(obj, 'b.c');
// { a: 1, b: { d: 3 } }Get and remove a value.
const obj = { a: 1, b: 2 };
const value = Arr.pull(obj, 'a');  // 1
// obj is now { b: 2 }Add item to beginning.
Arr.prepend([2, 3], 1);
// [1, 2, 3]Push items onto an array using dot notation.
const data = { products: { items: [1, 2] } };
Arr.push(data, 'products.items', 3, 4);
// { products: { items: [1, 2, 3, 4] } }
// Creates array if doesn't exist
Arr.push({}, 'cart.items', 'apple');
// { cart: { items: ['apple'] } }// E-commerce order processing
const orders = [
    { id: 1, customer: 'John', total: 150, status: 'completed' },
    { id: 2, customer: 'Jane', total: 89.99, status: 'pending' }
];
// Get completed orders
const completed = Arr.where(orders, o => o.status === 'completed');
// Calculate revenue
const revenue = Arr.pluck(completed, 'total').reduce((a, b) => a + b, 0);
// Group by customer
const byCustomer = Arr.keyBy(orders, 'customer');
// Form data handling with dot notation
const formData = {
    'user.name': 'John',
    'user.email': 'john@example.com',
    'user.address.city': 'NYC'
};
const userData = Arr.undot(formData);
// { user: { name: 'John', email: 'john@example.com', address: { city: 'NYC' } } }
// Data analytics - flatten nested metrics
const analytics = {
    users: { total: 10000, active: 7500 },
    revenue: { daily: 15000, monthly: 450000 }
};
const flatMetrics = Arr.dot(analytics);
// { 'users.total': 10000, 'users.active': 7500, ... }
// CSS class management
const buttonClasses = Arr.toCssClasses([
    'btn',
    { 'btn-primary': isPrimary, 'btn-disabled': isDisabled }
]);Full TypeScript support with comprehensive type definitions:
import { Arr } from 'stringx-js';
const data = Arr.get<string>({ user: { name: 'John' } }, 'user.name');
const users = Arr.where<User>(userList, u => u.active);
const names = Arr.pluck<User, string>(users, 'name');Run the test suite:
npm testWatch mode for tests:
npm run test:watchMIT
- Inspired by Laravel's Str helper and Number helper
- Multi-language number spelling powered by n2words - Supports 16+ languages for converting numbers to words
StringX-JS includes full autocomplete support in all modern IDEs! 🎯
When you type Str. you'll see all 95+ methods with:
- ✅ Method names and descriptions
- ✅ Parameter types and hints
- ✅ Return type information
- ✅ Inline documentation
import Str from 'stringx-js';
// Type "Str." and see autocomplete:
Str.camel()      // ← Shows: (value: string): string
Str.contains()   // ← Shows: (haystack: string, needles: string | string[]): boolean
Str.uuid()       // ← Shows: (): string
// ... 92+ more methods with autocomplete// Type ".of('text')." to see all chainable methods:
Str.of('hello')
    .upper()     // ← Autocomplete shows this
    .trim()      // ← And this
    .camel()     // ← And this
    .toString(); // ← And this- ✅ VS Code - Full IntelliSense support
- ✅ WebStorm/PhpStorm - Smart autocomplete
- ✅ JavaScript files - JSDoc-based autocomplete
- ✅ TypeScript files - Full type checking
- ✅ Zero configuration - Works automatically