
Security News
Axios Maintainer Confirms Social Engineering Attack Behind npm Compromise
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.
stringx-js
Advanced tools
A comprehensive JavaScript library for string, number, and array manipulation inspired by Laravel. Includes 95+ string methods, 25+ number formatters, and 60 array utilities with fluent chaining, dot notation, and TypeScript support.
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.
Number Class)
Arr Class)
npm install stringx-js
Try StringX-JS online without installing anything!
๐ stringx-js.com - Interactive playground with:
Perfect for:
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:
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...'
of()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(...values)Append one or more strings to the end.
Str.of('Hello').append(' ', 'World', '!').toString(); // 'Hello World!'
prepend(...values)Prepend one or more strings to the beginning.
Str.of('World').prepend('Hello ', '').toString(); // 'Hello World'
pipe(callback)Pass the string through a callback function.
Str.of('hello')
.pipe(str => str.toUpperCase())
.toString(); // 'HELLO'
tap(callback)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'
when(condition, callback, defaultCallback)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'
unless(condition, callback, defaultCallback)Execute a transformation unless the condition is true.
Str.of('hello')
.unless(false, str => str.upper())
.toString(); // 'HELLO'
whenEmpty(callback)Execute callback only if the string is empty.
Str.of('')
.whenEmpty(str => str.append('default'))
.toString(); // 'default'
whenNotEmpty(callback)Execute callback only if the string is not empty.
Str.of('hello')
.whenNotEmpty(str => str.upper())
.toString(); // 'HELLO'
isEmpty() / isNotEmpty()Check if the string is empty or not.
Str.of('').isEmpty(); // true
Str.of('hello').isNotEmpty(); // true
dump()Dump the current value to console and continue chaining.
Str.of('hello')
.dump() // Logs: 'hello'
.upper()
.dump() // Logs: 'HELLO'
.toString(); // 'HELLO'
dd()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();
pipe()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();
tap() and dump()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();
after(subject, search)Return the remainder of a string after the first occurrence of a given value.
Str.after('This is my name', 'This is'); // ' my name'
afterLast(subject, search)Return the remainder of a string after the last occurrence of a given value.
Str.afterLast('App\\Http\\Controllers\\Controller', '\\'); // 'Controller'
before(subject, search)Get the portion of a string before the first occurrence of a given value.
Str.before('This is my name', 'my name'); // 'This is '
beforeLast(subject, search)Get the portion of a string before the last occurrence of a given value.
Str.beforeLast('This is my name', 'is'); // 'This '
between(subject, from, to)Get the portion of a string between two given values.
Str.between('This is my name', 'This', 'name'); // ' is my '
betweenFirst(subject, from, to)Get the smallest possible portion of a string between two given values.
Str.betweenFirst('[a] bc [d]', '[', ']'); // 'a'
camel(value)Convert a value to camelCase.
Str.camel('foo_bar'); // 'fooBar'
Str.camel('foo-bar'); // 'fooBar'
kebab(value)Convert a string to kebab-case.
Str.kebab('fooBar'); // 'foo-bar'
snake(value, delimiter = '_')Convert a string to snake_case.
Str.snake('fooBar'); // 'foo_bar'
Str.snake('fooBar', '-'); // 'foo-bar'
studly(value) / pascal(value)Convert a value to StudlyCase (PascalCase).
Str.studly('foo_bar'); // 'FooBar'
Str.pascal('foo_bar'); // 'FooBar'
title(value)Convert the given string to title case.
Str.title('hello world'); // 'Hello World'
headline(value)Convert the given string to title case for each word.
Str.headline('hello_world'); // 'Hello World'
Str.headline('hello-world'); // 'Hello World'
lower(value)Convert the given string to lower-case.
Str.lower('HELLO'); // 'hello'
upper(value)Convert the given string to upper-case.
Str.upper('hello'); // 'HELLO'
ucfirst(string)Make a string's first character uppercase.
Str.ucfirst('hello'); // 'Hello'
lcfirst(string)Make a string's first character lowercase.
Str.lcfirst('Hello'); // 'hello'
apa(value)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'
convertCase(string, mode = 'lower', encoding = 'UTF-8')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(value, limit = 100, end = '...')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 >'
words(value, words = 100, end = '...')Limit the number of words in a string.
Str.words('The quick brown fox jumps', 3); // 'The quick brown...'
mask(string, character, index, length = null)Masks a portion of a string with a repeated character.
Str.mask('email@example.com', '*', 5); // 'email************'
Str.mask('1234567890', '*', 0, 4); // '****567890'
trim(value, charlist = null)Remove whitespace (or other characters) from both ends of a string.
Str.trim(' hello '); // 'hello'
Str.trim('/hello/', '/'); // 'hello'
ltrim(value, charlist = null)Remove whitespace (or other characters) from the beginning of a string.
Str.ltrim(' hello '); // 'hello '
rtrim(value, charlist = null)Remove whitespace (or other characters) from the end of a string.
Str.rtrim(' hello '); // ' hello'
squish(value)Remove all "extra" blank space from the given string.
Str.squish(' hello world '); // 'hello world'
chopStart(subject, needle)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'
chopEnd(subject, needle)Remove the given string(s) if it exists at the end of the haystack.
Str.chopEnd('Hello World', ' World'); // 'Hello'
finish(value, cap)Cap a string with a single instance of a given value.
Str.finish('this/string', '/'); // 'this/string/'
Str.finish('this/string/', '/'); // 'this/string/'
start(value, prefix)Begin a string with a single instance of a given value.
Str.start('this/string', '/'); // '/this/string'
Str.start('/this/string', '/'); // '/this/string'
wrap(value, before, after = null)Wrap the string with the given strings.
Str.wrap('Hello', '"'); // '"Hello"'
Str.wrap('Hello', '<', '>'); // '<Hello>'
unwrap(value, before, after = null)Unwrap the string with the given strings.
Str.unwrap('"Hello"', '"'); // 'Hello'
Str.unwrap('<Hello>', '<', '>'); // 'Hello'
ascii(value, language = 'en')Transliterate a string to its closest ASCII representation.
Str.ascii('cafรฉ'); // 'cafe'
Str.ascii('รผber'); // 'uber'
transliterate(string, unknown = '?', strict = false)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 ??'
wordWrap(string, characters = 75, breakStr = '\n', cutLongWords = false)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(search, replace, subject, caseSensitive = true)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'
replaceFirst(search, replace, subject)Replace the first occurrence of a given value in the string.
Str.replaceFirst('foo', 'bar', 'foo foo'); // 'bar foo'
replaceLast(search, replace, subject)Replace the last occurrence of a given value in the string.
Str.replaceLast('foo', 'bar', 'foo foo'); // 'foo bar'
remove(search, subject, caseSensitive = true)Remove any occurrence of the given string in the subject.
Str.remove('foo', 'foo bar foo'); // ' bar '
deduplicate(string, characters = ' ')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'
replaceArray(search, replace, subject)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'
replaceStart(search, replace, subject)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'
replaceEnd(search, replace, subject)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'
replaceMatches(pattern, replace, subject, limit = -1)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(map, subject)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'
substrReplace(string, replace, offset = 0, length = null)Replace text within a portion of a string.
Str.substrReplace('Hello World', 'Goodbye', 0, 5); // 'Goodbye World'
Str.substrReplace('1234567890', 'xxx', 3, 3); // '123xxx7890'
contains(haystack, needles, ignoreCase = false)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); // true
containsAll(haystack, needles, ignoreCase = false)Determine 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']); // false
doesntContain(haystack, needles, ignoreCase = false)Determine if a given string doesn't contain a given substring.
Str.doesntContain('This is my name', 'foo'); // true
startsWith(haystack, needles)Determine if a given string starts with a given substring.
Str.startsWith('Hello World', 'Hello'); // true
Str.startsWith('Hello World', ['Hello', 'Hi']); // true
doesntStartWith(haystack, needles)Determine if a given string doesn't start with a given substring.
Str.doesntStartWith('Hello World', 'Hi'); // true
endsWith(haystack, needles)Determine if a given string ends with a given substring.
Str.endsWith('Hello World', 'World'); // true
Str.endsWith('Hello World', ['World', 'Earth']); // true
doesntEndWith(haystack, needles)Determine if a given string doesn't end with a given substring.
Str.doesntEndWith('Hello World', 'Earth'); // true
is(pattern, value, ignoreCase = false)Determine if a given string matches a given pattern.
Str.is('*', 'foo'); // true
Str.is('foo*', 'foobar'); // true
Str.is(['foo', 'bar'], 'foo'); // true
isAscii(value)Determine if a given string is 7 bit ASCII.
Str.isAscii('Hello World'); // true
Str.isAscii('Hello ไธ็'); // false
isJson(value)Determine if a given value is valid JSON.
Str.isJson('{"name":"John"}'); // true
Str.isJson('not json'); // false
isUrl(value, protocols = [])Determine if a given value is a valid URL.
Str.isUrl('https://example.com'); // true
Str.isUrl('http://example.com', ['https']); // false
isUuid(value)Determine if a given value is a valid UUID.
const uuid = Str.uuid();
Str.isUuid(uuid); // true
Str.isUuid('not-a-uuid'); // false
isUlid(value)Determine if a given value is a valid ULID.
const ulid = Str.ulid();
Str.isUlid(ulid); // true
length(value)Return the length of the given string.
Str.length('Hello'); // 5
Str.length('๐'); // 1 (handles Unicode correctly)
wordCount(string)Get the number of words a string contains.
Str.wordCount('Hello World'); // 2
substrCount(haystack, needle, offset = 0, length = null)Returns the number of substring occurrences.
Str.substrCount('foo foo foo', 'foo'); // 3
match(pattern, subject)Get the string matching the given pattern.
Str.match(/(\d+)/, 'Order 123'); // '123'
isMatch(pattern, value)Determine if a given string matches a given pattern.
Str.isMatch(/\d+/, '123'); // true
matchAll(pattern, subject)Get all strings matching the given pattern.
Str.matchAll(/\d+/g, 'Order 123 and 456'); // ['123', '456']
padBoth(value, length, pad = ' ')Pad both sides of a string with another.
Str.padBoth('James', 10, '_'); // '__James___'
padLeft(value, length, pad = ' ')Pad the left side of a string with another.
Str.padLeft('James', 10, '-'); // '-----James'
padRight(value, length, pad = ' ')Pad the right side of a string with another.
Str.padRight('James', 10, '-'); // 'James-----'
charAt(subject, index)Get the character at the specified index.
Str.charAt('Hello', 0); // 'H'
Str.charAt('Hello', -1); // 'o'
plural(value, count = 2)Get the plural form of an English word.
Str.plural('car'); // 'cars'
Str.plural('car', 1); // 'car'
Str.plural('city'); // 'cities'
singular(value)Get the singular form of an English word.
Str.singular('cars'); // 'car'
Str.singular('cities'); // 'city'
slug(title, separator = '-')Generate a URL friendly "slug" from a given string.
Str.slug('Hello World'); // 'hello-world'
Str.slug('Hello World', '_'); // 'hello_world'
random(length = 16)Generate a random, secure string.
Str.random(); // 'aB3dE5fG7hI9jK1L'
Str.random(32); // 32 character random string
numbers(value)Remove all non-numeric characters from a string.
Str.numbers('abc123def456'); // '123456'
Str.numbers('Price: $19.99'); // '1999'
reverse(value)Reverse the given string.
Str.reverse('Hello'); // 'olleH'
substr(string, start, length = null)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(string, limit)Take the first or last {limit} characters of a string.
Str.take('Hello World', 5); // 'Hello'
Str.take('Hello World', -5); // 'World'
repeat(string, times)Repeat the given string.
Str.repeat('a', 3); // 'aaa'
ucsplit(string)Split a string into pieces by uppercase characters.
Str.ucsplit('FooBar'); // ['Foo', 'Bar']
excerpt(text, phrase = '', options = {})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...'
password(length = 32, letters = true, numbers = true, symbols = true, spaces = false)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 only
position(haystack, needle, offset = 0)Find 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'); // false
pluralStudly(value, count = 2)Pluralize the last word of an English, studly caps case string.
Str.pluralStudly('UserProfile'); // 'UserProfiles'
Str.pluralStudly('VerifiedHuman'); // 'VerifiedHumans'
Str.pluralStudly('Child', 1); // 'Child'
pluralPascal(value, count = 2)Pluralize the last word of an English, Pascal case string (alias for pluralStudly).
Str.pluralPascal('UserProfile'); // 'UserProfiles'
Str.pluralPascal('Child', 1); // 'Child'
toBase64(string)Convert the given string to Base64 encoding.
Str.toBase64('Hello World'); // 'SGVsbG8gV29ybGQ='
fromBase64(string, strict = false)Decode the given Base64 encoded string.
Str.fromBase64('SGVsbG8gV29ybGQ='); // 'Hello World'
uuid()Generate a UUID (version 4).
Str.uuid(); // 'e3c2d7a4-5c8e-4b2f-a1d3-9e7f6c5b4a3d'
uuid7()Generate a UUID (version 7).
Str.uuid7(); // '018f4f9e-5c8e-7b2f-a1d3-9e7f6c5b4a3d'
ulid()Generate a ULID.
Str.ulid(); // '01HQXYZ123ABC456DEF789GHJ'
You can customize the behavior of UUID, ULID, and random string generation:
createUuidsUsing(factory = null)Set the callable that will be used to generate UUIDs.
Str.createUuidsUsing(() => 'custom-uuid');
Str.uuid(); // 'custom-uuid'
createUuidsNormally()Indicate that UUIDs should be created normally (reset to default).
Str.createUuidsNormally();
Str.uuid(); // Regular UUID generation resumes
createUlidsUsing(factory = null)Set the callable that will be used to generate ULIDs.
Str.createUlidsUsing(() => 'custom-ulid');
Str.ulid(); // 'custom-ulid'
createUlidsNormally()Indicate that ULIDs should be created normally (reset to default).
Str.createUlidsNormally();
Str.ulid(); // Regular ULID generation resumes
createRandomStringsUsing(factory = null)Set the callable that will be used to generate random strings.
Str.createRandomStringsUsing((length) => 'x'.repeat(length));
Str.random(5); // 'xxxxx'
createRandomStringsNormally()Indicate that random strings should be created normally (reset to default).
Str.createRandomStringsNormally();
Str.random(16); // Regular random string generation resumes
flushCache()Remove all strings from the casing caches.
Str.flushCache();
Number Class)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(number, precision?, maxPrecision?, locale?)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)
percentage(number, precision?, maxPrecision?, locale?)Convert numbers to percentage format.
Number.percentage(50); // "50%"
Number.percentage(66.666, 2); // "66.67%"
Number.percentage(33.333, 1); // "33.3%"
currency(number, currency?, locale?, precision?)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"
fileSize(bytes, precision?, maxPrecision?)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"
forHumans(number, precision?, maxPrecision?, abbreviate?)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(number, precision?, maxPrecision?)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(number, locale?, after?, until?)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)
ordinal(number, locale?)Convert numbers to ordinal format (1st, 2nd, 3rd, etc.).
Number.ordinal(1); // "1st"
Number.ordinal(22); // "22nd"
Number.ordinal(103); // "103rd"
spellOrdinal(number, locale?)Spell out ordinal numbers.
Number.spellOrdinal(1); // "first"
Number.spellOrdinal(22); // "twenty-second"
Number.spellOrdinal(42); // "forty-second"
parse(string, locale?)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"); // null
parseInt(string, locale?)Parse 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)
parseFloat(string, locale?)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(number, min, max)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); // 10
pairs(to, by, start?, offset?)Generate 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]]
trim(number)Remove trailing zeros from decimals.
Number.trim(1.50); // 1.5
Number.trim(1.00); // 1
Number.trim(1.230); // 1.23
useLocale(locale) / defaultLocale()Set or get the default locale.
Number.useLocale('de-DE');
Number.format(1234.56); // "1.234,56" (German format)
Number.defaultLocale(); // "de-DE"
useCurrency(currency) / defaultCurrency()Set or get the default currency.
Number.useCurrency('EUR');
Number.currency(1234.56); // "โฌ1,234.56"
Number.defaultCurrency(); // "EUR"
withLocale(locale, callback) / withCurrency(currency, callback)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 callback
The 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);
Arr Class)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(array, key?, defaultValue?)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(array, key, value)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 } }
has(array, keys)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']); // false
dot(array, prepend?)Flatten a multi-dimensional array with dots.
const nested = { user: { name: 'John', address: { city: 'NYC' } } };
Arr.dot(nested);
// { 'user.name': 'John', 'user.address.city': 'NYC' }
undot(array)Convert flattened "dot" notation back to expanded array.
const flat = { 'user.name': 'John', 'user.age': 30 };
Arr.undot(flat);
// { user: { name: 'John', age: 30 } }
where(array, callback)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 }]
reject(array, callback)Filter using the negation of the callback.
Arr.reject([1, 2, 3, 4], x => x > 2);
// [1, 2]
whereNotNull(array)Filter items where the value is not null or undefined.
Arr.whereNotNull([1, null, 2, undefined, 3]);
// [1, 2, 3]
first(array, callback?, defaultValue?)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'
last(array, callback?, defaultValue?)Return the last element passing a test.
Arr.last([1, 2, 3, 4]); // 4
Arr.last([1, 2, 3, 4], x => x < 3); // 2
sole(array, callback?)Get 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 found
take(array, limit)Take 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)
only(array, keys)Get a subset of items by keys.
const data = { a: 1, b: 2, c: 3 };
Arr.only(data, ['a', 'c']);
// { a: 1, c: 3 }
except(array, keys)Get all items except specified keys.
const data = { a: 1, b: 2, c: 3 };
Arr.except(data, ['b']);
// { a: 1, c: 3 }
pluck(array, value, key?)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(array, keys)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' }]
map(array, callback)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 }
mapWithKeys(array, callback)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' } }
keyBy(array, key)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(array, depth?)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(array)Collapse an array of arrays into a single array.
Arr.collapse([[1, 2], [3, 4], [5]]);
// [1, 2, 3, 4, 5]
partition(array, callback)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(array)Divide into keys and values.
Arr.divide({ a: 1, b: 2 });
// [['a', 'b'], [1, 2]]
crossJoin(...arrays)Create all possible permutations.
Arr.crossJoin([1, 2], ['a', 'b']);
// [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']]
shuffle(array)Randomly shuffle an array.
Arr.shuffle([1, 2, 3, 4, 5]);
// [3, 1, 5, 2, 4] (random order)
random(array, number?, preserveKeys?)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(array, callback?)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 }]
sortDesc(array, callback?)Sort in descending order.
Arr.sortDesc([1, 2, 3]);
// [3, 2, 1]
sortRecursive(array, descending?)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 } }
exists(array, key)Check if key exists in array.
Arr.exists({ a: 1, b: 2 }, 'a'); // true
Arr.exists([1, 2, 3], 1); // true
every(array, callback)Check if all items pass a test.
Arr.every([2, 4, 6], x => x % 2 === 0);
// true
some(array, callback)Check if any items pass a test.
Arr.some([1, 2, 3], x => x > 2);
// true
isAssoc(array)Check if array is associative (object-like).
Arr.isAssoc({ a: 1, b: 2 }); // true
Arr.isAssoc([1, 2, 3]); // false
isList(array)Check if array has sequential integer keys.
Arr.isList([1, 2, 3]); // true
Get 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 boolean
join(array, glue, finalGlue?)Join 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)
query(array)Convert object to query string.
Arr.query({ page: 1, limit: 10, sort: 'name' });
// 'page=1&limit=10&sort=name'
toCssClasses(array)Compile to CSS classes.
Arr.toCssClasses(['btn', { active: true, disabled: false }]);
// 'btn active'
toCssStyles(array)Compile to CSS styles.
Arr.toCssStyles(['color: red', { 'font-size: 14px': true }]);
// 'color: red; font-size: 14px;'
wrap(value)Wrap non-arrays in an array.
Arr.wrap('hello'); // ['hello']
Arr.wrap([1, 2]); // [1, 2]
Arr.wrap(null); // []
from(items)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); // Error
add(array, key, value)Add 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)
forget(array, keys)Remove items using dot notation.
const obj = { a: 1, b: { c: 2, d: 3 } };
Arr.forget(obj, 'b.c');
// { a: 1, b: { d: 3 } }
pull(array, key, defaultValue?)Get and remove a value.
const obj = { a: 1, b: 2 };
const value = Arr.pull(obj, 'a'); // 1
// obj is now { b: 2 }
prepend(array, value, key?)Add item to beginning.
Arr.prepend([2, 3], 1);
// [1, 2, 3]
push(array, key, ...values)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 test
Watch mode for tests:
npm run test:watch
MIT
StringX-JS includes full autocomplete support in all modern IDEs! ๐ฏ
When you type Str. you'll see all 95+ methods with:
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
FAQs
A comprehensive JavaScript library for string, number, and array manipulation inspired by Laravel. Includes 95+ string methods, 25+ number formatters, and 60 array utilities with fluent chaining, dot notation, and TypeScript support.
We found that stringx-js demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.ย It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.