- name
- stacks-strings
- description
- Use when working with string utilities in Stacks - case conversion (camelCase, PascalCase, snake_case, kebab-case, CONSTANT_CASE, Train-Case, etc.), pluralization, string validation (email, URL, UUID, credit card, etc.), slug generation, random strings, template interpolation, or the Str facade. Covers @stacksjs/strings.
- license
- MIT
- compatibility
- Bun >= 1.3.0, TypeScript
- allowed-tools
- Read Edit Write Bash Grep Glob
# Stacks Strings
## Key Paths
- Core package: `storage/framework/core/strings/src/`
- Package: `@stacksjs/strings`
- Entry: `storage/framework/core/strings/src/string.ts` (re-exports all submodules)
## Architecture
The package re-exports from these submodules:
- `case.ts` — case conversion functions (camelCase, pascalCase, snakeCase, etc.)
- `pluralize.ts` — English pluralization/singularization with rule engine
- `slug.ts` — URL slug generation with extensive character map
- `utils.ts` — random strings, template interpolation, slash, prefix/suffix, truncate, detect-indent, detect-newline
- `macro.ts` — `Str` and `str` facade objects
- `validators.ts` — re-exports from `is.ts` (native string validators)
- `sponge-case.ts` — random upper/lower case
- `swap-case.ts` — swap upper/lower case
- `title-case.ts` — intelligent title case with small word handling
The top-level `index.ts` does:
```typescript
export * from './string'
export * as string from './string'
```
And `string.ts` does:
```typescript
export * from './case'
export * from './helpers'
export * from './macro'
export * from './pluralize'
export * from './slug'
export * from './utils'
export * from './validators'
```
## Case Conversion Functions
All accept `(input: string, options?: CaseOptions)` and use Unicode-aware word boundary detection via regex patterns (`\p{Ll}`, `\p{Lu}`).
```typescript
interface CaseOptions {
locale?: string[] | string | false | undefined
split?: (value: string) => string[]
delimiter?: string
prefixCharacters?: string // characters to preserve as prefix
suffixCharacters?: string // characters to preserve as suffix
}
interface PascalCaseOptions extends CaseOptions {
mergeAmbiguousCharacters?: boolean
}
```
### Functions
```typescript
camelCase('hello world') // 'helloWorld' — first word lowercase, rest capitalized
pascalCase('hello world') // 'HelloWorld' — all words capitalized
snakeCase('hello world') // 'hello_world' — alias for noCase with '_' delimiter
kebabCase('hello world') // 'hello-world' — alias for noCase with '-' delimiter
constantCase('hello world') // 'HELLO_WORLD' — all uppercase with '_' delimiter
trainCase('hello world') // 'Hello-World' — capitalCase with '-' delimiter
dotCase('hello world') // 'hello.world' — noCase with '.' delimiter
pathCase('hello world') // 'hello/world' — noCase with '/' delimiter
sentenceCase('hello world') // 'Hello world' — first word capitalized, rest lowercase
capitalCase('hello world') // 'Hello World' — all words capitalized, space delimiter
noCase('helloWorld') // 'hello world' — lowercase with space delimiter
pascalSnakeCase('hello world') // 'Hello_World' — capitalCase with '_' delimiter
paramCase('hello world') // 'hello-world' — alias for kebabCase
```
### Special Case Functions
```typescript
spongeCase('hello world') // 'hElLo wOrLd' — random upper/lower per character
spongeCase('hello', 'en') // accepts optional locale
swapCase('Hello') // 'hELLO' — swaps each character's case
swapCase('Hello', 'en') // accepts optional locale
```
### Title Case
```typescript
titleCase('hello world') // 'Hello World'
titleCase('the quick brown fox') // 'The Quick Brown Fox'
titleCase('the quick brown fox', { sentenceCase: true }) // 'The quick brown fox'
interface TitleCaseOptions {
locale?: string | string[]
sentenceCase?: boolean // only capitalize first word + after terminators
sentenceTerminators?: Set<string> // default: '.', '!', '?'
titleTerminators?: Set<string> // default: '.', '!', '?', ':', '"', "'", '"'
smallWords?: Set<string> // words not capitalized (see SMALL_WORDS)
wordSeparators?: Set<string> // default: '---', '--', '-', '---', '/'
}
```
Handles special cases: URLs, email addresses, acronyms (e.g., "U.S.A."), camelCase words (e.g., "iPhone"), and hyphenated compound words.
### Word Splitting
```typescript
split('camelCase') // ['camel', 'Case']
split('hello_world') // ['hello', 'world']
split('HTTPSRequest') // ['HTTPS', 'Request']
splitSeparateNumbers('test123') // ['test', '123']
```
Uses Unicode-aware regex for word boundary detection. Handles camelCase, PascalCase, snake_case, UPPER_CASE, and mixed formats.
## Pluralization
Full English pluralization engine with irregular words, custom rules, and uncountable nouns.
```typescript
import { plural, singular, pluralize } from '@stacksjs/strings'
// Basic usage
plural('person') // 'people'
plural('person', 1) // 'person' (count-aware)
singular('people') // 'person'
// Pluralize function with options
pluralize('mouse') // 'mice'
pluralize('mouse', { count: 1 }) // 'mouse'
pluralize('mouse', { count: 2 }) // 'mice'
pluralize('mouse', { count: 5, inclusive: true }) // '5 mice'
// Boolean checks
pluralize.isPlural('dogs') // true
pluralize.isSingular('dog') // true
// Custom rules
pluralize.addPluralRule(/gex$/i, 'gices')
pluralize.addSingularRule(/gices$/i, 'gex')
pluralize.addIrregularRule('person', 'people')
pluralize.addUncountableRule('sheep')
```
### Built-in Irregular Words
The engine includes 48 irregular word pairs (e.g., ox/oxen, foot/feet, goose/geese, child/children, person/people, die/dice, tooth/teeth, quiz/quizzes, etc.).
### Built-in Uncountable Words
Includes 74 uncountable words (e.g., sheep, fish, moose, aircraft, software, equipment, information, etc.) plus regex patterns for Pokemon, words ending in non-ASCII `ese`, deer, fish, measles, pox, sheep.
### Case Preservation
The pluralization engine preserves the case pattern of the input word:
- `'PERSON'` -> `'PEOPLE'`
- `'Person'` -> `'People'`
- `'person'` -> `'people'`
## Slug Generation
Two slug functions with different defaults:
### `slug(str, options?)` — Simple slug (strict + lowercase by default)
```typescript
slug('Hello World') // 'hello-world'
slug('Hello World', { lower: false }) // 'Hello-World'
```
### `slugify(str, options?)` — Full-featured slug
```typescript
slugify('Hello World!') // 'Hello-World!' (not strict/lowercase by default)
slugify('Hello World!', { lower: true, strict: true }) // 'hello-world'
interface SlugifyOptions {
replacement?: string // default: '-'
remove?: RegExp // chars to remove (default: /[^\w\s$*+~.()'"!\-:@]+/g)
lower?: boolean // default: false
strict?: boolean // strip non-alphanumeric (default: false)
locale?: string // locale-specific char mapping
trim?: boolean // trim result (default: true)
}
```
### Character Map
Extensive built-in character map covering:
- Latin extended (accented chars): A-Z with diacritics
- Greek alphabet
- Cyrillic alphabet
- Armenian alphabet
- Arabic alphabet and numerals
- Georgian alphabet
- Vietnamese diacritics
- Currency symbols ($, EUR, GBP, YEN, etc.)
- Special characters (trademark, copyright, etc.)
### Locale Support
Locale-specific character mappings for: `bg`, `de`, `es`, `fr`, `pt`, `uk`, `vi`, `da`, `nb`, `it`, `nl`, `sv`.
```typescript
slugify('AE', { locale: 'de' }) // 'AE' (German)
slugify('AE') // 'A' (default)
```
### Extending the Character Map
```typescript
extendCharMap({ 'EUR': 'EUR', 'GBP': 'GBP' })
```
## String Utilities
```typescript
capitalize('hello world') // 'Hello world' — first char upper, rest lower
lowercase('HELLO') // 'hello'
slash('path\\to\\file') // 'path/to/file'
ensurePrefix('https://', 'google.com') // 'https://google.com'
ensurePrefix('https://', 'https://x.com') // 'https://x.com' (already has prefix)
ensureSuffix('.ts', 'file') // 'file.ts'
ensureSuffix('.ts', 'file.ts') // 'file.ts' (already has suffix)
template('Hello {0}! My name is {1}.', 'Buddy', 'Chris') // 'Hello Buddy! My name is Chris.'
truncate('long text here', 10, '...') // 'long te...'
truncate('short', 10) // 'short' (no truncation needed)
random() // 16-char random string (nanoid-style)
random(21) // 21-char random string
random(10, 'abc') // 10-char string from custom alphabet
```
### `urlAlphabet` Constant
```typescript
// 64 URL-safe characters used by random() by default
const urlAlphabet = 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict'
```
## String Validators
Native TypeScript implementations (no external validator dependency). All accept a string and return boolean.
### Core Validators
```typescript
isEmail('user@example.com') // true -- regex: /^[^\s@]+@[^\s@]+\.[^\s@]+$/
isStrongPassword('Abc123!@#') // true -- min 8 chars, upper, lower, digit, symbol
isAlphanumeric('abc123') // true -- /^[a-zA-Z0-9]+$/
isAlpha('abcdef') // true -- /^[a-zA-Z]+$/
isNumeric('123') // true -- /^[0-9]+$/ (whole numbers only)
isURL('https://example.com') // true -- uses URL constructor, requires http(s) protocol
```
### Format Validators
```typescript
isHexColor('#ff0000') // true -- 3 or 6 hex digits with #
isHexadecimal('deadbeef') // true -- hex chars only
isBase64('SGVsbG8=') // true -- btoa(atob(x)) === x
isBase32('MFZWI===') // true -- /^[A-Z2-7]+=*$/
isAscii('hello') // true -- /^[\x00-\x7F]*$/
isJSON('{"key":"value"}') // true -- JSON.parse succeeds
isHSL('hsl(0, 100%, 50%)') // true
isMimeType('text/html') // true -- /^[a-z]+\/[a-z0-9\-+.]+$/i
isDataURI('data:text/plain;base64,...') // true
isJWT('eyJhbGciOi...') // true -- 3 dot-separated base64url segments
```
### Network Validators
```typescript
isIP('192.168.1.1') // true -- IPv4 and IPv6
isIPRange('192.168.1.0/24') // true -- CIDR notation (IPv4: 0-32, IPv6: 0-128)
isMACAddress('00:11:22:33:44:55') // true -- colon or hyphen separated
isFQDN('example.com') // true -- fully qualified domain name
```
Ver en GitHub