stringx-js
Advanced tools
+14
| /** | ||
| * StringX-JS - Main Type Definitions | ||
| * A comprehensive JavaScript string manipulation library inspired by Laravel's Str helper | ||
| * | ||
| * @version 1.0.1 | ||
| * @author Ayman Atmeh | ||
| * @license MIT | ||
| */ | ||
| import Str from './src/Str'; | ||
| import { Stringable } from './src/Stringable'; | ||
| export { Stringable }; | ||
| export default Str; |
+195
| /** | ||
| * StringX-JS - TypeScript Type Definitions | ||
| * A comprehensive JavaScript string manipulation library inspired by Laravel's Str helper | ||
| */ | ||
| import { Stringable } from './Stringable'; | ||
| /** | ||
| * Main Str class with static methods for string manipulation | ||
| */ | ||
| declare class Str { | ||
| /** | ||
| * Create a new Stringable instance for fluent method chaining | ||
| * @param string - The string value to wrap | ||
| * @returns A Stringable instance for chaining | ||
| * @example | ||
| * Str.of('hello').upper().toString() // 'HELLO' | ||
| */ | ||
| static of(string: string): Stringable; | ||
| // Case Conversion | ||
| /** | ||
| * Convert a value to camelCase | ||
| * @param value - The string to convert | ||
| * @returns The camelCase string | ||
| * @example | ||
| * Str.camel('foo_bar') // 'fooBar' | ||
| */ | ||
| static camel(value: string): string; | ||
| /** | ||
| * Convert a string to kebab-case | ||
| * @param value - The string to convert | ||
| * @returns The kebab-case string | ||
| * @example | ||
| * Str.kebab('fooBar') // 'foo-bar' | ||
| */ | ||
| static kebab(value: string): string; | ||
| /** | ||
| * Convert a string to snake_case | ||
| * @param value - The string to convert | ||
| * @param delimiter - The delimiter to use (default: '_') | ||
| * @returns The snake_case string | ||
| * @example | ||
| * Str.snake('fooBar') // 'foo_bar' | ||
| */ | ||
| static snake(value: string, delimiter?: string): string; | ||
| /** | ||
| * Convert a value to StudlyCase (PascalCase) | ||
| * @param value - The string to convert | ||
| * @returns The StudlyCase string | ||
| * @example | ||
| * Str.studly('foo_bar') // 'FooBar' | ||
| */ | ||
| static studly(value: string): string; | ||
| /** | ||
| * Convert a value to PascalCase (alias for studly) | ||
| * @param value - The string to convert | ||
| * @returns The PascalCase string | ||
| * @example | ||
| * Str.pascal('foo_bar') // 'FooBar' | ||
| */ | ||
| static pascal(value: string): string; | ||
| static title(value: string): string; | ||
| static headline(value: string): string; | ||
| static upper(value: string): string; | ||
| static lower(value: string): string; | ||
| static ucfirst(string: string): string; | ||
| static lcfirst(string: string): string; | ||
| static apa(value: string): string; | ||
| static convertCase(string: string, mode?: 'lower' | 'upper' | 'title', encoding?: string): string; | ||
| // String Extraction | ||
| static after(subject: string, search: string): string; | ||
| static afterLast(subject: string, search: string): string; | ||
| static before(subject: string, search: string): string; | ||
| static beforeLast(subject: string, search: string): string; | ||
| static between(subject: string, from: string, to: string): string; | ||
| static betweenFirst(subject: string, from: string, to: string): string; | ||
| static charAt(subject: string, index: number): string; | ||
| static substr(string: string, start: number, length?: number | null): string; | ||
| static take(string: string, limit: number): string; | ||
| // String Checking | ||
| static contains(haystack: string, needles: string | string[], ignoreCase?: boolean): boolean; | ||
| static containsAll(haystack: string, needles: string[], ignoreCase?: boolean): boolean; | ||
| static doesntContain(haystack: string, needles: string | string[], ignoreCase?: boolean): boolean; | ||
| static startsWith(haystack: string, needles: string | string[]): boolean; | ||
| static doesntStartWith(haystack: string, needles: string | string[]): boolean; | ||
| static endsWith(haystack: string, needles: string | string[]): boolean; | ||
| static doesntEndWith(haystack: string, needles: string | string[]): boolean; | ||
| static is(pattern: string | string[], value: string, ignoreCase?: boolean): boolean; | ||
| static isAscii(value: string): boolean; | ||
| static isJson(value: string): boolean; | ||
| static isUrl(value: string, protocols?: string[]): boolean; | ||
| static isUuid(value: string): boolean; | ||
| static isUlid(value: string): boolean; | ||
| static isMatch(pattern: RegExp | string, value: string): boolean; | ||
| // String Manipulation | ||
| static limit(value: string, limit?: number, end?: string): string; | ||
| static words(value: string, words?: number, end?: string): string; | ||
| static mask(string: string, character: string, index: number, length?: number | null): string; | ||
| static trim(value: string, charlist?: string | null): string; | ||
| static ltrim(value: string, charlist?: string | null): string; | ||
| static rtrim(value: string, charlist?: string | null): string; | ||
| static squish(value: string): string; | ||
| static chopStart(subject: string, needle: string | string[]): string; | ||
| static chopEnd(subject: string, needle: string | string[]): string; | ||
| static finish(value: string, cap: string): string; | ||
| static start(value: string, prefix: string): string; | ||
| static wrap(value: string, before: string, after?: string | null): string; | ||
| static unwrap(value: string, before: string, after?: string | null): string; | ||
| static reverse(value: string): string; | ||
| static ascii(value: string, language?: string): string; | ||
| static transliterate(string: string, unknown?: string, strict?: boolean): string; | ||
| static wordWrap(string: string, characters?: number, breakStr?: string, cutLongWords?: boolean): string; | ||
| // String Replacement | ||
| static replace(search: string | string[], replace: string | string[], subject: string, caseSensitive?: boolean): string; | ||
| static replaceFirst(search: string, replace: string, subject: string): string; | ||
| static replaceLast(search: string, replace: string, subject: string): string; | ||
| static replaceArray(search: string, replace: string[], subject: string): string; | ||
| static replaceStart(search: string, replace: string, subject: string): string; | ||
| static replaceEnd(search: string, replace: string, subject: string): string; | ||
| static replaceMatches(pattern: RegExp | string, replace: string, subject: string, limit?: number): string; | ||
| static remove(search: string | string[], subject: string, caseSensitive?: boolean): string; | ||
| static swap(map: Record<string, string>, subject: string): string; | ||
| static deduplicate(string: string, characters?: string | string[]): string; | ||
| static substrReplace(string: string, replace: string, offset?: number, length?: number | null): string; | ||
| // Pattern Matching | ||
| static match(pattern: RegExp | string, subject: string): string | null; | ||
| static matchAll(pattern: RegExp | string, subject: string): string[]; | ||
| // Padding | ||
| static padBoth(value: string, length: number, pad?: string): string; | ||
| static padLeft(value: string, length: number, pad?: string): string; | ||
| static padRight(value: string, length: number, pad?: string): string; | ||
| // String Information | ||
| static length(value: string): number; | ||
| static wordCount(string: string): number; | ||
| static substrCount(haystack: string, needle: string, offset?: number, length?: number | null): number; | ||
| static position(haystack: string, needle: string, offset?: number): number | false; | ||
| // String Generation | ||
| static random(length?: number): string; | ||
| static password(length?: number, letters?: boolean, numbers?: boolean, symbols?: boolean, spaces?: boolean): string; | ||
| static uuid(): string; | ||
| static uuid7(): string; | ||
| static ulid(): string; | ||
| // Pluralization | ||
| static plural(value: string, count?: number): string; | ||
| static singular(value: string): string; | ||
| static pluralStudly(value: string, count?: number): string; | ||
| static pluralPascal(value: string, count?: number): string; | ||
| // Other Utilities | ||
| static slug(title: string, separator?: string): string; | ||
| static numbers(value: string): string; | ||
| static excerpt(text: string, phrase?: string, options?: ExcerptOptions): string; | ||
| static ucsplit(string: string): string[]; | ||
| static repeat(string: string, times: number): string; | ||
| // Encoding | ||
| static toBase64(string: string): string; | ||
| static fromBase64(string: string, strict?: boolean): string; | ||
| // Factories | ||
| static createUuidsUsing(factory: (() => string) | null): void; | ||
| static createUuidsNormally(): void; | ||
| static createUlidsUsing(factory: (() => string) | null): void; | ||
| static createUlidsNormally(): void; | ||
| static createRandomStringsUsing(factory: ((length: number) => string) | null): void; | ||
| static createRandomStringsNormally(): void; | ||
| // Cache Management | ||
| static flushCache(): void; | ||
| } | ||
| /** | ||
| * Options for the excerpt method | ||
| */ | ||
| export interface ExcerptOptions { | ||
| radius?: number; | ||
| omission?: string; | ||
| } | ||
| export default Str; |
| /** | ||
| * Stringable - TypeScript Type Definitions | ||
| * Fluent interface for string manipulation with method chaining | ||
| */ | ||
| /** | ||
| * Stringable class for fluent string manipulation | ||
| */ | ||
| export declare class Stringable { | ||
| /** The underlying string value */ | ||
| protected value: string; | ||
| /** | ||
| * Create a new Stringable instance | ||
| */ | ||
| constructor(value?: string); | ||
| // Value Extraction | ||
| toString(): string; | ||
| valueOf(): string; | ||
| toJSON(): string; | ||
| // Utility Methods | ||
| append(...values: string[]): this; | ||
| prepend(...values: string[]): this; | ||
| pipe(callback: (value: string) => string): this; | ||
| tap(callback: (value: string) => void): this; | ||
| // Conditional Methods | ||
| when(condition: boolean | ((str: this) => boolean), callback: (str: this, condition?: any) => this | void, defaultCallback?: ((str: this) => this | void) | null): this; | ||
| unless(condition: boolean | ((str: this) => boolean), callback: (str: this) => this | void, defaultCallback?: ((str: this) => this | void) | null): this; | ||
| whenEmpty(callback: (str: this) => this | void): this; | ||
| whenNotEmpty(callback: (str: this) => this | void): this; | ||
| // Debugging | ||
| dump(): this; | ||
| dd(): never; | ||
| // Checking Methods | ||
| isEmpty(): boolean; | ||
| isNotEmpty(): boolean; | ||
| test(pattern: RegExp | string): boolean; | ||
| // String Extraction | ||
| after(search: string): this; | ||
| afterLast(search: string): this; | ||
| before(search: string): this; | ||
| beforeLast(search: string): this; | ||
| between(from: string, to: string): this; | ||
| betweenFirst(from: string, to: string): this; | ||
| charAt(index: number): string; | ||
| substr(start: number, length?: number | null): this; | ||
| take(limit: number): this; | ||
| // Case Conversion | ||
| camel(): this; | ||
| kebab(): this; | ||
| snake(delimiter?: string): this; | ||
| studly(): this; | ||
| pascal(): this; | ||
| title(): this; | ||
| headline(): this; | ||
| upper(): this; | ||
| lower(): this; | ||
| ucfirst(): this; | ||
| lcfirst(): this; | ||
| apa(): this; | ||
| convertCase(mode?: 'lower' | 'upper' | 'title', encoding?: string): this; | ||
| // String Checking (returns boolean, not chainable) | ||
| contains(needles: string | string[], ignoreCase?: boolean): boolean; | ||
| containsAll(needles: string[], ignoreCase?: boolean): boolean; | ||
| doesntContain(needles: string | string[], ignoreCase?: boolean): boolean; | ||
| startsWith(needles: string | string[]): boolean; | ||
| doesntStartWith(needles: string | string[]): boolean; | ||
| endsWith(needles: string | string[]): boolean; | ||
| doesntEndWith(needles: string | string[]): boolean; | ||
| is(pattern: string | string[], ignoreCase?: boolean): boolean; | ||
| isAscii(): boolean; | ||
| isJson(): boolean; | ||
| isUrl(protocols?: string[]): boolean; | ||
| isUuid(): boolean; | ||
| isUlid(): boolean; | ||
| isMatch(pattern: RegExp | string): boolean; | ||
| // String Manipulation | ||
| limit(limit?: number, end?: string): this; | ||
| words(words?: number, end?: string): this; | ||
| mask(character: string, index: number, length?: number | null): this; | ||
| trim(charlist?: string | null): this; | ||
| ltrim(charlist?: string | null): this; | ||
| rtrim(charlist?: string | null): this; | ||
| squish(): this; | ||
| chopStart(needle: string | string[]): this; | ||
| chopEnd(needle: string | string[]): this; | ||
| finish(cap: string): this; | ||
| start(prefix: string): this; | ||
| wrap(before: string, after?: string | null): this; | ||
| unwrap(before: string, after?: string | null): this; | ||
| reverse(): this; | ||
| ascii(language?: string): this; | ||
| transliterate(unknown?: string, strict?: boolean): this; | ||
| wordWrap(characters?: number, breakStr?: string, cutLongWords?: boolean): this; | ||
| // String Replacement | ||
| replace(search: string | string[], replace: string | string[], caseSensitive?: boolean): this; | ||
| replaceFirst(search: string, replace: string): this; | ||
| replaceLast(search: string, replace: string): this; | ||
| replaceArray(search: string, replace: string[]): this; | ||
| replaceStart(search: string, replace: string): this; | ||
| replaceEnd(search: string, replace: string): this; | ||
| replaceMatches(pattern: RegExp | string, replace: string, limit?: number): this; | ||
| remove(search: string | string[], caseSensitive?: boolean): this; | ||
| swap(map: Record<string, string>): this; | ||
| deduplicate(characters?: string | string[]): this; | ||
| substrReplace(replace: string, offset?: number, length?: number | null): this; | ||
| // Pattern Matching (returns values, not chainable) | ||
| match(pattern: RegExp | string): string | null; | ||
| matchAll(pattern: RegExp | string): string[]; | ||
| // Padding | ||
| padBoth(length: number, pad?: string): this; | ||
| padLeft(length: number, pad?: string): this; | ||
| padRight(length: number, pad?: string): this; | ||
| // String Information (returns values, not chainable) | ||
| length(): number; | ||
| wordCount(): number; | ||
| substrCount(needle: string, offset?: number, length?: number | null): number; | ||
| position(needle: string, offset?: number): number | false; | ||
| // Pluralization | ||
| plural(count?: number): this; | ||
| singular(): this; | ||
| pluralStudly(count?: number): this; | ||
| // Other Utilities | ||
| slug(separator?: string): this; | ||
| numbers(): this; | ||
| excerpt(phrase?: string, options?: { radius?: number; omission?: string }): this; | ||
| ucsplit(): string[]; | ||
| repeat(times: number): this; | ||
| // Encoding | ||
| toBase64(): this; | ||
| fromBase64(strict?: boolean): this; | ||
| // Additional utilities | ||
| substring(start: number, length: number): this; | ||
| } | ||
| export default Stringable; |
+44
-0
@@ -8,2 +8,45 @@ # Changelog | ||
| ## [1.0.2] - 2024-10-28 | ||
| ### Added | ||
| - **🎯 Full TypeScript support with complete type definitions** | ||
| - `index.d.ts` - Main entry point type definitions | ||
| - `src/Str.d.ts` - Complete types for all 95+ static methods | ||
| - `src/Stringable.d.ts` - Complete types for all 95+ fluent methods | ||
| - Added `"types": "index.d.ts"` to package.json | ||
| - **✨ IDE Autocomplete & IntelliSense support** | ||
| - Full autocomplete when typing `Str.` (shows all 95+ methods) | ||
| - Parameter hints with type information | ||
| - Return type inference | ||
| - Hover documentation with JSDoc comments | ||
| - Works in JavaScript (.js) and TypeScript (.ts) files | ||
| - Zero configuration required - works automatically after npm install | ||
| - **📁 Better project organization** | ||
| - Created `examples/` folder for all example files | ||
| - Moved `examples.js` → `examples/examples.js` | ||
| - Moved `chaining-examples.js` → `examples/chaining-examples.js` | ||
| - Added `examples/typescript-example.ts` with comprehensive TypeScript examples | ||
| - Updated `.npmignore` to exclude examples folder | ||
| ### Changed | ||
| - **Updated terminology to match Laravel** | ||
| - Changed "Stringable API" to "Fluent Strings" in README | ||
| - Aligned documentation with Laravel's official terminology | ||
| - **Enhanced type definitions** | ||
| - Added JSDoc comments to key methods for better IDE hover documentation | ||
| - Improved parameter descriptions and examples | ||
| - **Package metadata** | ||
| - Added "typescript" keyword for better npm discoverability | ||
| - Updated files array to include all TypeScript definition files | ||
| ### Developer Experience | ||
| - ✅ Full IntelliSense in VS Code | ||
| - ✅ Smart autocomplete in WebStorm/PhpStorm | ||
| - ✅ Type checking in TypeScript projects | ||
| - ✅ Parameter hints in all modern IDEs | ||
| - ✅ Hover documentation with examples | ||
| - ✅ Go to definition support | ||
| - ✅ Works in both .js and .ts files | ||
| ## [1.0.1] - 2024-10-27 | ||
@@ -75,3 +118,4 @@ | ||
| [1.0.2]: https://github.com/yourusername/stringx-js/compare/v1.0.1...v1.0.2 | ||
| [1.0.1]: https://github.com/yourusername/stringx-js/compare/v1.0.0...v1.0.1 | ||
| [1.0.0]: https://github.com/yourusername/stringx-js/releases/tag/v1.0.0 |
+6
-1
| { | ||
| "name": "stringx-js", | ||
| "version": "1.0.1", | ||
| "version": "1.0.2", | ||
| "description": "A comprehensive JavaScript string manipulation library inspired by Laravel's Str helper class with 95+ methods for case conversion, validation, manipulation, and generation. Now with fluent method chaining!", | ||
| "type": "module", | ||
| "main": "index.js", | ||
| "types": "index.d.ts", | ||
| "scripts": { | ||
@@ -19,2 +20,3 @@ "test": "node --test src/tests/*.test.js", | ||
| "javascript", | ||
| "typescript", | ||
| "es6", | ||
@@ -55,4 +57,7 @@ "string-manipulation", | ||
| "index.js", | ||
| "index.d.ts", | ||
| "src/Str.js", | ||
| "src/Str.d.ts", | ||
| "src/Stringable.js", | ||
| "src/Stringable.d.ts", | ||
| "src/helpers.js", | ||
@@ -59,0 +64,0 @@ "README.md", |
+368
-0
@@ -11,2 +11,30 @@ # StringX-JS | ||
| ## TypeScript Support | ||
| StringX-JS includes full TypeScript type definitions out of the box! No need to install separate `@types` packages. | ||
| ```typescript | ||
| 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](examples/typescript-example.ts) for comprehensive TypeScript usage examples. | ||
| ## Usage | ||
@@ -276,2 +304,298 @@ | ||
| ## Advanced Usage | ||
| ### Custom Transformations with `pipe()` | ||
| The `pipe()` method allows you to pass the string through any custom function, enabling unlimited flexibility: | ||
| ```javascript | ||
| // 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(); | ||
| ``` | ||
| ### Debugging with `tap()` and `dump()` | ||
| Debug your transformation chains without breaking the flow: | ||
| ```javascript | ||
| // 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(); | ||
| ``` | ||
| ### Advanced Conditional Logic | ||
| Build complex conditional transformation chains: | ||
| ```javascript | ||
| // 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(); | ||
| ``` | ||
| ### Working with APIs and Data Transformation | ||
| Transform API responses and data structures: | ||
| ```javascript | ||
| // 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(); | ||
| ``` | ||
| ### Text Processing and Sanitization | ||
| Advanced text cleaning and formatting: | ||
| ```javascript | ||
| // 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' | ||
| }; | ||
| ``` | ||
| ### Combining Static and Fluent Methods | ||
| Mix both approaches for optimal code: | ||
| ```javascript | ||
| // 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' | ||
| ``` | ||
| ### Error Handling Patterns | ||
| Handle edge cases gracefully: | ||
| ```javascript | ||
| // 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); | ||
| } | ||
| ``` | ||
| ### Performance Optimization | ||
| Tips for optimal performance: | ||
| ```javascript | ||
| // 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(); | ||
| ``` | ||
| ## Available Methods | ||
@@ -1070,1 +1394,45 @@ | ||
| Inspired by Laravel's [Str helper](https://laravel.com/docs/strings). | ||
| ## Autocomplete & IntelliSense | ||
| StringX-JS includes full autocomplete support in all modern IDEs! 🎯 | ||
| ### What You Get | ||
| When you type `Str.` you'll see **all 95+ methods** with: | ||
| - ✅ Method names and descriptions | ||
| - ✅ Parameter types and hints | ||
| - ✅ Return type information | ||
| - ✅ Inline documentation | ||
| ```javascript | ||
| 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 | ||
| ``` | ||
| ### Fluent Chaining Autocomplete | ||
| ```javascript | ||
| // Type ".of('text')." to see all chainable methods: | ||
| Str.of('hello') | ||
| .upper() // ← Autocomplete shows this | ||
| .trim() // ← And this | ||
| .camel() // ← And this | ||
| .toString(); // ← And this | ||
| ``` | ||
| ### Works Everywhere | ||
| - ✅ **VS Code** - Full IntelliSense support | ||
| - ✅ **WebStorm/PhpStorm** - Smart autocomplete | ||
| - ✅ **JavaScript files** - JSDoc-based autocomplete | ||
| - ✅ **TypeScript files** - Full type checking | ||
| - ✅ **Zero configuration** - Works automatically | ||
| See [AUTOCOMPLETE-GUIDE.md](AUTOCOMPLETE-GUIDE.md) for details and [autocomplete-demo.js](autocomplete-demo.js) for a hands-on demonstration. | ||
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
113111
30.58%11
37.5%2065
18.14%1436
34.46%