string-extn 1.0.0 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +367 -367
- package/package.json +61 -58
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Balaji Katta Venkatarathnam
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Balaji Katta Venkatarathnam
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,367 +1,367 @@
|
|
|
1
|
-
# string-extn
|
|
2
|
-
|
|
3
|
-
A lightweight, TypeScript-first library for **safe and functional string manipulation**. It provides **core string utilities, functional programming helpers, and Unicode-safe operations**, designed for **Node.js and browser environments**.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Table of Contents
|
|
8
|
-
|
|
9
|
-
- [Features](#features)
|
|
10
|
-
- [Installation](#installation)
|
|
11
|
-
- [Quick Start](#quick-start)
|
|
12
|
-
- [API Reference](#api-reference)
|
|
13
|
-
- [Core Functions](#core-functions)
|
|
14
|
-
- [Functional Programming](#functional-programming)
|
|
15
|
-
- [Case Conversion](#case-conversion)
|
|
16
|
-
- [String Comparison & Similarity](#string-comparison--similarity)
|
|
17
|
-
- [String Masking & Redaction](#string-masking--redaction)
|
|
18
|
-
- [URL & Filename Safe Conversion](#url--filename-safe-conversion)
|
|
19
|
-
- [String Validation](#string-validation)
|
|
20
|
-
- [Unicode Operations](#unicode-operations)
|
|
21
|
-
- [Examples](#examples)
|
|
22
|
-
- [Testing](#testing)
|
|
23
|
-
- [License](#license)
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## Features
|
|
28
|
-
|
|
29
|
-
### ✨ Core String Operations
|
|
30
|
-
- **trim** - Remove leading/trailing whitespace
|
|
31
|
-
- **pad** - Pad strings to a fixed length with custom characters
|
|
32
|
-
- **slice** - Extract string substrings with flexible indexing
|
|
33
|
-
- **repeat** - Repeat strings multiple times
|
|
34
|
-
- **truncate** - Truncate strings with ellipsis
|
|
35
|
-
- **reverse** - Reverse string character order
|
|
36
|
-
|
|
37
|
-
### 🔧 Functional Programming Helpers
|
|
38
|
-
- **map** - Transform each character with a function
|
|
39
|
-
- **filter** - Keep only characters matching a predicate
|
|
40
|
-
- **reduce** - Accumulate values by processing characters
|
|
41
|
-
- **compose** - Chain multiple functions for complex transformations
|
|
42
|
-
|
|
43
|
-
### 🔤 Case Conversion
|
|
44
|
-
- **toCamelCase** - Convert to camelCase from kebab-case, snake_case, or spaces
|
|
45
|
-
- **toKebabCase** - Convert to kebab-case from camelCase, snake_case, or spaces
|
|
46
|
-
- **toSnakeCase** - Convert to snake_case from camelCase, kebab-case, or spaces
|
|
47
|
-
- **toPascalCase** - Convert to PascalCase from any format
|
|
48
|
-
|
|
49
|
-
### 🔍 String Comparison & Similarity
|
|
50
|
-
- **diff** - Find character differences between two strings
|
|
51
|
-
- **similarity** - Calculate similarity score (0-1) using Levenshtein distance
|
|
52
|
-
|
|
53
|
-
### 🎭 String Masking & Redaction
|
|
54
|
-
- **mask** - Mask sensitive information keeping only last N characters visible
|
|
55
|
-
- **redact** - Redact portions matching regex patterns
|
|
56
|
-
|
|
57
|
-
### 🌐 URL & Filename Safe Conversion
|
|
58
|
-
- **slugify** - Convert to URL-friendly slug format
|
|
59
|
-
- **filenameSafe** - Remove invalid filesystem characters
|
|
60
|
-
|
|
61
|
-
### ✔️ String Validation (20 validators)
|
|
62
|
-
- Email, UUID, Numeric, URL, Hex Color, Phone Number, Date
|
|
63
|
-
- Strong Password, JSON, Base64, Alphabetic, Alphanumeric
|
|
64
|
-
- Case validators, Whitespace, Palindrome, Hexadecimal, Roman Numeral
|
|
65
|
-
- IPv4, IPv6 validation
|
|
66
|
-
|
|
67
|
-
### 🌍 Unicode-Safe Operations
|
|
68
|
-
- **lengthUnicode** - Count Unicode grapheme clusters (handles emoji with modifiers)
|
|
69
|
-
- **unicodeSlice** - Slice strings while respecting grapheme boundaries
|
|
70
|
-
- **reverseUnicode** - Reverse strings with proper emoji and combining mark support
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## Installation
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
npm install string-extn
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Or with Yarn:
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
yarn add string-extn
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## Quick Start
|
|
89
|
-
|
|
90
|
-
### Core Functions
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
import { trim, pad, slice, repeat, truncate, reverse } from 'string-extn';
|
|
94
|
-
|
|
95
|
-
trim(' hello world '); // "hello world"
|
|
96
|
-
pad('abc', 5, '-'); // "abc--"
|
|
97
|
-
slice('hello', 1, 4); // "ell"
|
|
98
|
-
repeat('ha', 3); // "hahaha"
|
|
99
|
-
truncate('This is a long string', 10, '...'); // "This is a ..."
|
|
100
|
-
reverse('hello'); // "olleh"
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Functional Programming
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
import { map, filter, reduce, compose } from 'string-extn';
|
|
107
|
-
|
|
108
|
-
map('abc', c => c.toUpperCase()); // "ABC"
|
|
109
|
-
filter('abcdef', c => 'aeiou'.includes(c)); // "ae"
|
|
110
|
-
reduce('abc', (acc, c) => acc + c.charCodeAt(0), 0); // 294
|
|
111
|
-
|
|
112
|
-
const shout = compose(s => s + '!', s => s.toUpperCase());
|
|
113
|
-
shout('hello'); // "HELLO!"
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### Unicode-Safe Operations
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
import { lengthUnicode, unicodeSlice, reverseUnicode } from 'string-extn';
|
|
120
|
-
|
|
121
|
-
const emojiStr = '👍🏽👍';
|
|
122
|
-
lengthUnicode(emojiStr); // 2 (counts emoji with skin tone as 1)
|
|
123
|
-
unicodeSlice(emojiStr, 0, 1); // "👍🏽"
|
|
124
|
-
reverseUnicode(emojiStr); // "👍👍🏽"
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## API Reference
|
|
130
|
-
|
|
131
|
-
### Core Functions
|
|
132
|
-
|
|
133
|
-
| Function | Signature | Description |
|
|
134
|
-
|----------|-----------|-------------|
|
|
135
|
-
| `trim` | `trim(str: string): string` | Removes leading/trailing whitespace |
|
|
136
|
-
| `pad` | `pad(str: string, length: number, char?: string): string` | Pads string to fixed length |
|
|
137
|
-
| `slice` | `slice(str: string, start: number, end?: number): string` | Returns substring |
|
|
138
|
-
| `repeat` | `repeat(str: string, times: number): string` | Repeats string N times |
|
|
139
|
-
| `truncate` | `truncate(str: string, max: number): string` | Truncates with ellipsis (...) |
|
|
140
|
-
| `reverse` | `reverse(str: string): string` | Reverses string characters |
|
|
141
|
-
|
|
142
|
-
### Functional Programming
|
|
143
|
-
|
|
144
|
-
| Function | Signature | Description |
|
|
145
|
-
|----------|-----------|-------------|
|
|
146
|
-
| `map` | `map(str: string, fn: (c: string) => string): string` | Transforms each character |
|
|
147
|
-
| `filter` | `filter(str: string, fn: (c: string) => boolean): string` | Filters characters by predicate |
|
|
148
|
-
| `reduce` | `reduce<T>(str: string, fn: (acc: T, c: string) => T, initial: T): T` | Reduces string to accumulator value |
|
|
149
|
-
| `compose` | `compose(...fns: Function[]): (value: any) => any` | Composes functions right-to-left |
|
|
150
|
-
|
|
151
|
-
### Case Conversion
|
|
152
|
-
|
|
153
|
-
| Function | Signature | Description |
|
|
154
|
-
|----------|-----------|-------------|
|
|
155
|
-
| `toCamelCase` | `toCamelCase(input: string): string` | Converts to camelCase |
|
|
156
|
-
| `toKebabCase` | `toKebabCase(input: string): string` | Converts to kebab-case |
|
|
157
|
-
| `toSnakeCase` | `toSnakeCase(input: string): string` | Converts to snake_case |
|
|
158
|
-
| `toPascalCase` | `toPascalCase(input: string): string` | Converts to PascalCase |
|
|
159
|
-
|
|
160
|
-
### String Comparison & Similarity
|
|
161
|
-
|
|
162
|
-
| Function | Signature | Description |
|
|
163
|
-
|----------|-----------|-------------|
|
|
164
|
-
| `diff` | `diff(a: string, b: string): string[]` | Returns character differences between two strings |
|
|
165
|
-
| `similarity` | `similarity(a: string, b: string): number` | Returns similarity score (0-1) using Levenshtein distance |
|
|
166
|
-
|
|
167
|
-
### String Masking & Redaction
|
|
168
|
-
|
|
169
|
-
| Function | Signature | Description |
|
|
170
|
-
|----------|-----------|-------------|
|
|
171
|
-
| `mask` | `mask(input: string, visible?: number, maskChar?: string): string` | Masks string keeping last N characters visible |
|
|
172
|
-
| `redact` | `redact(input: string, patterns: RegExp[]): string` | Redacts portions matching regex patterns |
|
|
173
|
-
|
|
174
|
-
### URL & Filename Safe Conversion
|
|
175
|
-
|
|
176
|
-
| Function | Signature | Description |
|
|
177
|
-
|----------|-----------|-------------|
|
|
178
|
-
| `slugify` | `slugify(input: string): string` | Converts to URL-friendly slug format |
|
|
179
|
-
| `filenameSafe` | `filenameSafe(input: string): string` | Removes invalid filesystem characters |
|
|
180
|
-
|
|
181
|
-
### String Validation
|
|
182
|
-
|
|
183
|
-
| Function | Input | Returns | Purpose |
|
|
184
|
-
|----------|-------|---------|---------|
|
|
185
|
-
| `isEmail` | string | boolean | Validates email address format |
|
|
186
|
-
| `isUUID` | string | boolean | Validates UUID format (v1-v5) |
|
|
187
|
-
| `isNumeric` | string | boolean | Validates numeric strings |
|
|
188
|
-
| `isURL` | string | boolean | Validates URL format |
|
|
189
|
-
| `isHexColor` | string | boolean | Validates hex color codes |
|
|
190
|
-
| `isPhoneNumber` | string | boolean | Validates E.164 phone numbers |
|
|
191
|
-
| `isDate` | string | boolean | Validates date strings |
|
|
192
|
-
| `isStrongPassword` | string | boolean | Validates strong password criteria |
|
|
193
|
-
| `isJSON` | string | boolean | Validates JSON format |
|
|
194
|
-
| `isBase64` | string | boolean | Validates Base64 encoding |
|
|
195
|
-
| `isAlphabetic` | string | boolean | Validates alphabetic strings only |
|
|
196
|
-
| `isAlphanumeric` | string | boolean | Validates alphanumeric strings |
|
|
197
|
-
| `isLowerCase` | string | boolean | Validates lowercase strings |
|
|
198
|
-
| `isUpperCase` | string | boolean | Validates uppercase strings |
|
|
199
|
-
| `isWhitespace` | string | boolean | Validates whitespace-only strings |
|
|
200
|
-
| `isPalindrome` | string | boolean | Validates palindrome strings |
|
|
201
|
-
| `isHexadecimal` | string | boolean | Validates hexadecimal format |
|
|
202
|
-
| `isRomanNumeral` | string | boolean | Validates Roman numeral format |
|
|
203
|
-
| `isIPv4` | string | boolean | Validates IPv4 addresses |
|
|
204
|
-
| `isIPv6` | string | boolean | Validates IPv6 addresses |
|
|
205
|
-
|
|
206
|
-
### Unicode Operations
|
|
207
|
-
|
|
208
|
-
| Function | Signature | Description |
|
|
209
|
-
|----------|-----------|-------------|
|
|
210
|
-
| `lengthUnicode` | `lengthUnicode(str: string): number` | Counts Unicode grapheme clusters |
|
|
211
|
-
| `unicodeSlice` | `unicodeSlice(str: string, start: number, end?: number): string` | Slices by grapheme boundaries |
|
|
212
|
-
| `reverseUnicode` | `reverseUnicode(str: string): string` | Reverses with emoji/modifier support |
|
|
213
|
-
|
|
214
|
-
---
|
|
215
|
-
|
|
216
|
-
## Examples
|
|
217
|
-
|
|
218
|
-
### Example 1: Text Processing Pipeline
|
|
219
|
-
|
|
220
|
-
```typescript
|
|
221
|
-
import { trim, map, filter } from 'string-extn';
|
|
222
|
-
|
|
223
|
-
const input = ' HELLO WORLD ';
|
|
224
|
-
const result = trim(input)
|
|
225
|
-
.toLowerCase()
|
|
226
|
-
.split(' ')
|
|
227
|
-
.map(word => filter(word, c => 'aeiou'.includes(c)))
|
|
228
|
-
.join(',');
|
|
229
|
-
|
|
230
|
-
console.log(result); // "e,o"
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
### Example 2: Case Conversion
|
|
234
|
-
|
|
235
|
-
```typescript
|
|
236
|
-
import { toCamelCase, toKebabCase, toSnakeCase, toPascalCase } from 'string-extn';
|
|
237
|
-
|
|
238
|
-
const text = 'hello-world-example';
|
|
239
|
-
|
|
240
|
-
console.log(toCamelCase(text)); // "helloWorldExample"
|
|
241
|
-
console.log(toKebabCase('helloWorld')); // "hello-world"
|
|
242
|
-
console.log(toSnakeCase('helloWorld')); // "hello_world"
|
|
243
|
-
console.log(toPascalCase(text)); // "HelloWorldExample"
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Example 3: String Similarity & Diff
|
|
247
|
-
|
|
248
|
-
```typescript
|
|
249
|
-
import { similarity, diff } from 'string-extn';
|
|
250
|
-
|
|
251
|
-
const str1 = 'hello';
|
|
252
|
-
const str2 = 'hallo';
|
|
253
|
-
|
|
254
|
-
console.log(similarity(str1, str2)); // 0.8 (80% similar - one character different)
|
|
255
|
-
console.log(diff('abc', 'bcd')); // ["-a", "+d"]
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Example 4: Masking Sensitive Data
|
|
259
|
-
|
|
260
|
-
```typescript
|
|
261
|
-
import { mask, redact } from 'string-extn';
|
|
262
|
-
|
|
263
|
-
// Mask credit card
|
|
264
|
-
const cardNumber = '4532111111111111';
|
|
265
|
-
console.log(mask(cardNumber, 4)); // "············1111"
|
|
266
|
-
|
|
267
|
-
// Redact email patterns
|
|
268
|
-
const text = 'Contact john@example.com or jane@test.org';
|
|
269
|
-
console.log(redact(text, [/@\w+\.\w+/g])); // "Contact [REDACTED] or [REDACTED]"
|
|
270
|
-
```
|
|
271
|
-
|
|
272
|
-
### Example 5: URL & Filename Safe Conversion
|
|
273
|
-
|
|
274
|
-
```typescript
|
|
275
|
-
import { slugify, filenameSafe } from 'string-extn';
|
|
276
|
-
|
|
277
|
-
console.log(slugify('Hello World! Welcome')); // "hello-world-welcome"
|
|
278
|
-
console.log(slugify('Café au Lait')); // "cafe-au-lait"
|
|
279
|
-
console.log(filenameSafe('File<>Name?.txt')); // "FileName.txt"
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
### Example 6: String Validation
|
|
283
|
-
|
|
284
|
-
```typescript
|
|
285
|
-
import {
|
|
286
|
-
isEmail, isURL, isStrongPassword, isIPv4,
|
|
287
|
-
isPalindrome, isJSON
|
|
288
|
-
} from 'string-extn';
|
|
289
|
-
|
|
290
|
-
console.log(isEmail('user@example.com')); // true
|
|
291
|
-
console.log(isURL('https://example.com')); // true
|
|
292
|
-
console.log(isStrongPassword('MyPass@123')); // true
|
|
293
|
-
console.log(isIPv4('192.168.1.1')); // true
|
|
294
|
-
console.log(isPalindrome('A man a plan a canal Panama')); // true
|
|
295
|
-
console.log(isJSON('{"key":"value"}')); // true
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
### Example 7: Emoji Handling with Unicode
|
|
299
|
-
|
|
300
|
-
```typescript
|
|
301
|
-
import { lengthUnicode, unicodeSlice, reverseUnicode } from 'string-extn';
|
|
302
|
-
|
|
303
|
-
const message = 'Hello 👨👩👧👦 World 🇺🇸';
|
|
304
|
-
|
|
305
|
-
console.log(lengthUnicode(message)); // Correctly counts family emoji as 1
|
|
306
|
-
console.log(unicodeSlice(message, 6, 8)); // "👨👩👧👦 "
|
|
307
|
-
console.log(reverseUnicode(message)); // Preserves emoji integrity
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
### Example 3: Function Composition
|
|
311
|
-
|
|
312
|
-
```typescript
|
|
313
|
-
import { compose } from 'string-extn';
|
|
314
|
-
|
|
315
|
-
const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
316
|
-
const addPrefix = (s: string) => 'Hello, ' + s;
|
|
317
|
-
const addExclamation = (s: string) => s + '!';
|
|
318
|
-
|
|
319
|
-
const greet = compose(addExclamation, addPrefix, capitalize);
|
|
320
|
-
console.log(greet('world')); // "Hello, World!"
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
---
|
|
324
|
-
|
|
325
|
-
## Testing
|
|
326
|
-
|
|
327
|
-
### Run the Test Suite
|
|
328
|
-
|
|
329
|
-
```bash
|
|
330
|
-
npm test
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
### Build the Library
|
|
334
|
-
|
|
335
|
-
```bash
|
|
336
|
-
npm run build
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
This generates compiled JavaScript in the `dist/` folder.
|
|
340
|
-
|
|
341
|
-
### Link Locally for Testing
|
|
342
|
-
|
|
343
|
-
```bash
|
|
344
|
-
# In the string-extn folder
|
|
345
|
-
npm link
|
|
346
|
-
|
|
347
|
-
# In your test project folder
|
|
348
|
-
npm link string-extn
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
---
|
|
352
|
-
|
|
353
|
-
### Development Commands
|
|
354
|
-
|
|
355
|
-
```bash
|
|
356
|
-
npm install # Install dependencies
|
|
357
|
-
npm run build # Build the library
|
|
358
|
-
npm test # Run tests
|
|
359
|
-
npm link # Link for local testing
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
---
|
|
363
|
-
|
|
364
|
-
## License
|
|
365
|
-
|
|
366
|
-
MIT © Balaji Katta Venkatarathnam
|
|
367
|
-
|
|
1
|
+
# string-extn
|
|
2
|
+
|
|
3
|
+
A lightweight, TypeScript-first library for **safe and functional string manipulation**. It provides **core string utilities, functional programming helpers, and Unicode-safe operations**, designed for **Node.js and browser environments**.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Features](#features)
|
|
10
|
+
- [Installation](#installation)
|
|
11
|
+
- [Quick Start](#quick-start)
|
|
12
|
+
- [API Reference](#api-reference)
|
|
13
|
+
- [Core Functions](#core-functions)
|
|
14
|
+
- [Functional Programming](#functional-programming)
|
|
15
|
+
- [Case Conversion](#case-conversion)
|
|
16
|
+
- [String Comparison & Similarity](#string-comparison--similarity)
|
|
17
|
+
- [String Masking & Redaction](#string-masking--redaction)
|
|
18
|
+
- [URL & Filename Safe Conversion](#url--filename-safe-conversion)
|
|
19
|
+
- [String Validation](#string-validation)
|
|
20
|
+
- [Unicode Operations](#unicode-operations)
|
|
21
|
+
- [Examples](#examples)
|
|
22
|
+
- [Testing](#testing)
|
|
23
|
+
- [License](#license)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
### ✨ Core String Operations
|
|
30
|
+
- **trim** - Remove leading/trailing whitespace
|
|
31
|
+
- **pad** - Pad strings to a fixed length with custom characters
|
|
32
|
+
- **slice** - Extract string substrings with flexible indexing
|
|
33
|
+
- **repeat** - Repeat strings multiple times
|
|
34
|
+
- **truncate** - Truncate strings with ellipsis
|
|
35
|
+
- **reverse** - Reverse string character order
|
|
36
|
+
|
|
37
|
+
### 🔧 Functional Programming Helpers
|
|
38
|
+
- **map** - Transform each character with a function
|
|
39
|
+
- **filter** - Keep only characters matching a predicate
|
|
40
|
+
- **reduce** - Accumulate values by processing characters
|
|
41
|
+
- **compose** - Chain multiple functions for complex transformations
|
|
42
|
+
|
|
43
|
+
### 🔤 Case Conversion
|
|
44
|
+
- **toCamelCase** - Convert to camelCase from kebab-case, snake_case, or spaces
|
|
45
|
+
- **toKebabCase** - Convert to kebab-case from camelCase, snake_case, or spaces
|
|
46
|
+
- **toSnakeCase** - Convert to snake_case from camelCase, kebab-case, or spaces
|
|
47
|
+
- **toPascalCase** - Convert to PascalCase from any format
|
|
48
|
+
|
|
49
|
+
### 🔍 String Comparison & Similarity
|
|
50
|
+
- **diff** - Find character differences between two strings
|
|
51
|
+
- **similarity** - Calculate similarity score (0-1) using Levenshtein distance
|
|
52
|
+
|
|
53
|
+
### 🎭 String Masking & Redaction
|
|
54
|
+
- **mask** - Mask sensitive information keeping only last N characters visible
|
|
55
|
+
- **redact** - Redact portions matching regex patterns
|
|
56
|
+
|
|
57
|
+
### 🌐 URL & Filename Safe Conversion
|
|
58
|
+
- **slugify** - Convert to URL-friendly slug format
|
|
59
|
+
- **filenameSafe** - Remove invalid filesystem characters
|
|
60
|
+
|
|
61
|
+
### ✔️ String Validation (20 validators)
|
|
62
|
+
- Email, UUID, Numeric, URL, Hex Color, Phone Number, Date
|
|
63
|
+
- Strong Password, JSON, Base64, Alphabetic, Alphanumeric
|
|
64
|
+
- Case validators, Whitespace, Palindrome, Hexadecimal, Roman Numeral
|
|
65
|
+
- IPv4, IPv6 validation
|
|
66
|
+
|
|
67
|
+
### 🌍 Unicode-Safe Operations
|
|
68
|
+
- **lengthUnicode** - Count Unicode grapheme clusters (handles emoji with modifiers)
|
|
69
|
+
- **unicodeSlice** - Slice strings while respecting grapheme boundaries
|
|
70
|
+
- **reverseUnicode** - Reverse strings with proper emoji and combining mark support
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Installation
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm install string-extn
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Or with Yarn:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
yarn add string-extn
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Quick Start
|
|
89
|
+
|
|
90
|
+
### Core Functions
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { trim, pad, slice, repeat, truncate, reverse } from 'string-extn';
|
|
94
|
+
|
|
95
|
+
trim(' hello world '); // "hello world"
|
|
96
|
+
pad('abc', 5, '-'); // "abc--"
|
|
97
|
+
slice('hello', 1, 4); // "ell"
|
|
98
|
+
repeat('ha', 3); // "hahaha"
|
|
99
|
+
truncate('This is a long string', 10, '...'); // "This is a ..."
|
|
100
|
+
reverse('hello'); // "olleh"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Functional Programming
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
import { map, filter, reduce, compose } from 'string-extn';
|
|
107
|
+
|
|
108
|
+
map('abc', c => c.toUpperCase()); // "ABC"
|
|
109
|
+
filter('abcdef', c => 'aeiou'.includes(c)); // "ae"
|
|
110
|
+
reduce('abc', (acc, c) => acc + c.charCodeAt(0), 0); // 294
|
|
111
|
+
|
|
112
|
+
const shout = compose(s => s + '!', s => s.toUpperCase());
|
|
113
|
+
shout('hello'); // "HELLO!"
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Unicode-Safe Operations
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
import { lengthUnicode, unicodeSlice, reverseUnicode } from 'string-extn';
|
|
120
|
+
|
|
121
|
+
const emojiStr = '👍🏽👍';
|
|
122
|
+
lengthUnicode(emojiStr); // 2 (counts emoji with skin tone as 1)
|
|
123
|
+
unicodeSlice(emojiStr, 0, 1); // "👍🏽"
|
|
124
|
+
reverseUnicode(emojiStr); // "👍👍🏽"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## API Reference
|
|
130
|
+
|
|
131
|
+
### Core Functions
|
|
132
|
+
|
|
133
|
+
| Function | Signature | Description |
|
|
134
|
+
|----------|-----------|-------------|
|
|
135
|
+
| `trim` | `trim(str: string): string` | Removes leading/trailing whitespace |
|
|
136
|
+
| `pad` | `pad(str: string, length: number, char?: string): string` | Pads string to fixed length |
|
|
137
|
+
| `slice` | `slice(str: string, start: number, end?: number): string` | Returns substring |
|
|
138
|
+
| `repeat` | `repeat(str: string, times: number): string` | Repeats string N times |
|
|
139
|
+
| `truncate` | `truncate(str: string, max: number): string` | Truncates with ellipsis (...) |
|
|
140
|
+
| `reverse` | `reverse(str: string): string` | Reverses string characters |
|
|
141
|
+
|
|
142
|
+
### Functional Programming
|
|
143
|
+
|
|
144
|
+
| Function | Signature | Description |
|
|
145
|
+
|----------|-----------|-------------|
|
|
146
|
+
| `map` | `map(str: string, fn: (c: string) => string): string` | Transforms each character |
|
|
147
|
+
| `filter` | `filter(str: string, fn: (c: string) => boolean): string` | Filters characters by predicate |
|
|
148
|
+
| `reduce` | `reduce<T>(str: string, fn: (acc: T, c: string) => T, initial: T): T` | Reduces string to accumulator value |
|
|
149
|
+
| `compose` | `compose(...fns: Function[]): (value: any) => any` | Composes functions right-to-left |
|
|
150
|
+
|
|
151
|
+
### Case Conversion
|
|
152
|
+
|
|
153
|
+
| Function | Signature | Description |
|
|
154
|
+
|----------|-----------|-------------|
|
|
155
|
+
| `toCamelCase` | `toCamelCase(input: string): string` | Converts to camelCase |
|
|
156
|
+
| `toKebabCase` | `toKebabCase(input: string): string` | Converts to kebab-case |
|
|
157
|
+
| `toSnakeCase` | `toSnakeCase(input: string): string` | Converts to snake_case |
|
|
158
|
+
| `toPascalCase` | `toPascalCase(input: string): string` | Converts to PascalCase |
|
|
159
|
+
|
|
160
|
+
### String Comparison & Similarity
|
|
161
|
+
|
|
162
|
+
| Function | Signature | Description |
|
|
163
|
+
|----------|-----------|-------------|
|
|
164
|
+
| `diff` | `diff(a: string, b: string): string[]` | Returns character differences between two strings |
|
|
165
|
+
| `similarity` | `similarity(a: string, b: string): number` | Returns similarity score (0-1) using Levenshtein distance |
|
|
166
|
+
|
|
167
|
+
### String Masking & Redaction
|
|
168
|
+
|
|
169
|
+
| Function | Signature | Description |
|
|
170
|
+
|----------|-----------|-------------|
|
|
171
|
+
| `mask` | `mask(input: string, visible?: number, maskChar?: string): string` | Masks string keeping last N characters visible |
|
|
172
|
+
| `redact` | `redact(input: string, patterns: RegExp[]): string` | Redacts portions matching regex patterns |
|
|
173
|
+
|
|
174
|
+
### URL & Filename Safe Conversion
|
|
175
|
+
|
|
176
|
+
| Function | Signature | Description |
|
|
177
|
+
|----------|-----------|-------------|
|
|
178
|
+
| `slugify` | `slugify(input: string): string` | Converts to URL-friendly slug format |
|
|
179
|
+
| `filenameSafe` | `filenameSafe(input: string): string` | Removes invalid filesystem characters |
|
|
180
|
+
|
|
181
|
+
### String Validation
|
|
182
|
+
|
|
183
|
+
| Function | Input | Returns | Purpose |
|
|
184
|
+
|----------|-------|---------|---------|
|
|
185
|
+
| `isEmail` | string | boolean | Validates email address format |
|
|
186
|
+
| `isUUID` | string | boolean | Validates UUID format (v1-v5) |
|
|
187
|
+
| `isNumeric` | string | boolean | Validates numeric strings |
|
|
188
|
+
| `isURL` | string | boolean | Validates URL format |
|
|
189
|
+
| `isHexColor` | string | boolean | Validates hex color codes |
|
|
190
|
+
| `isPhoneNumber` | string | boolean | Validates E.164 phone numbers |
|
|
191
|
+
| `isDate` | string | boolean | Validates date strings |
|
|
192
|
+
| `isStrongPassword` | string | boolean | Validates strong password criteria |
|
|
193
|
+
| `isJSON` | string | boolean | Validates JSON format |
|
|
194
|
+
| `isBase64` | string | boolean | Validates Base64 encoding |
|
|
195
|
+
| `isAlphabetic` | string | boolean | Validates alphabetic strings only |
|
|
196
|
+
| `isAlphanumeric` | string | boolean | Validates alphanumeric strings |
|
|
197
|
+
| `isLowerCase` | string | boolean | Validates lowercase strings |
|
|
198
|
+
| `isUpperCase` | string | boolean | Validates uppercase strings |
|
|
199
|
+
| `isWhitespace` | string | boolean | Validates whitespace-only strings |
|
|
200
|
+
| `isPalindrome` | string | boolean | Validates palindrome strings |
|
|
201
|
+
| `isHexadecimal` | string | boolean | Validates hexadecimal format |
|
|
202
|
+
| `isRomanNumeral` | string | boolean | Validates Roman numeral format |
|
|
203
|
+
| `isIPv4` | string | boolean | Validates IPv4 addresses |
|
|
204
|
+
| `isIPv6` | string | boolean | Validates IPv6 addresses |
|
|
205
|
+
|
|
206
|
+
### Unicode Operations
|
|
207
|
+
|
|
208
|
+
| Function | Signature | Description |
|
|
209
|
+
|----------|-----------|-------------|
|
|
210
|
+
| `lengthUnicode` | `lengthUnicode(str: string): number` | Counts Unicode grapheme clusters |
|
|
211
|
+
| `unicodeSlice` | `unicodeSlice(str: string, start: number, end?: number): string` | Slices by grapheme boundaries |
|
|
212
|
+
| `reverseUnicode` | `reverseUnicode(str: string): string` | Reverses with emoji/modifier support |
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Examples
|
|
217
|
+
|
|
218
|
+
### Example 1: Text Processing Pipeline
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
import { trim, map, filter } from 'string-extn';
|
|
222
|
+
|
|
223
|
+
const input = ' HELLO WORLD ';
|
|
224
|
+
const result = trim(input)
|
|
225
|
+
.toLowerCase()
|
|
226
|
+
.split(' ')
|
|
227
|
+
.map(word => filter(word, c => 'aeiou'.includes(c)))
|
|
228
|
+
.join(',');
|
|
229
|
+
|
|
230
|
+
console.log(result); // "e,o"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Example 2: Case Conversion
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
import { toCamelCase, toKebabCase, toSnakeCase, toPascalCase } from 'string-extn';
|
|
237
|
+
|
|
238
|
+
const text = 'hello-world-example';
|
|
239
|
+
|
|
240
|
+
console.log(toCamelCase(text)); // "helloWorldExample"
|
|
241
|
+
console.log(toKebabCase('helloWorld')); // "hello-world"
|
|
242
|
+
console.log(toSnakeCase('helloWorld')); // "hello_world"
|
|
243
|
+
console.log(toPascalCase(text)); // "HelloWorldExample"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Example 3: String Similarity & Diff
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import { similarity, diff } from 'string-extn';
|
|
250
|
+
|
|
251
|
+
const str1 = 'hello';
|
|
252
|
+
const str2 = 'hallo';
|
|
253
|
+
|
|
254
|
+
console.log(similarity(str1, str2)); // 0.8 (80% similar - one character different)
|
|
255
|
+
console.log(diff('abc', 'bcd')); // ["-a", "+d"]
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Example 4: Masking Sensitive Data
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import { mask, redact } from 'string-extn';
|
|
262
|
+
|
|
263
|
+
// Mask credit card
|
|
264
|
+
const cardNumber = '4532111111111111';
|
|
265
|
+
console.log(mask(cardNumber, 4)); // "············1111"
|
|
266
|
+
|
|
267
|
+
// Redact email patterns
|
|
268
|
+
const text = 'Contact john@example.com or jane@test.org';
|
|
269
|
+
console.log(redact(text, [/@\w+\.\w+/g])); // "Contact [REDACTED] or [REDACTED]"
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Example 5: URL & Filename Safe Conversion
|
|
273
|
+
|
|
274
|
+
```typescript
|
|
275
|
+
import { slugify, filenameSafe } from 'string-extn';
|
|
276
|
+
|
|
277
|
+
console.log(slugify('Hello World! Welcome')); // "hello-world-welcome"
|
|
278
|
+
console.log(slugify('Café au Lait')); // "cafe-au-lait"
|
|
279
|
+
console.log(filenameSafe('File<>Name?.txt')); // "FileName.txt"
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Example 6: String Validation
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import {
|
|
286
|
+
isEmail, isURL, isStrongPassword, isIPv4,
|
|
287
|
+
isPalindrome, isJSON
|
|
288
|
+
} from 'string-extn';
|
|
289
|
+
|
|
290
|
+
console.log(isEmail('user@example.com')); // true
|
|
291
|
+
console.log(isURL('https://example.com')); // true
|
|
292
|
+
console.log(isStrongPassword('MyPass@123')); // true
|
|
293
|
+
console.log(isIPv4('192.168.1.1')); // true
|
|
294
|
+
console.log(isPalindrome('A man a plan a canal Panama')); // true
|
|
295
|
+
console.log(isJSON('{"key":"value"}')); // true
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Example 7: Emoji Handling with Unicode
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
import { lengthUnicode, unicodeSlice, reverseUnicode } from 'string-extn';
|
|
302
|
+
|
|
303
|
+
const message = 'Hello 👨👩👧👦 World 🇺🇸';
|
|
304
|
+
|
|
305
|
+
console.log(lengthUnicode(message)); // Correctly counts family emoji as 1
|
|
306
|
+
console.log(unicodeSlice(message, 6, 8)); // "👨👩👧👦 "
|
|
307
|
+
console.log(reverseUnicode(message)); // Preserves emoji integrity
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Example 3: Function Composition
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
import { compose } from 'string-extn';
|
|
314
|
+
|
|
315
|
+
const capitalize = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
316
|
+
const addPrefix = (s: string) => 'Hello, ' + s;
|
|
317
|
+
const addExclamation = (s: string) => s + '!';
|
|
318
|
+
|
|
319
|
+
const greet = compose(addExclamation, addPrefix, capitalize);
|
|
320
|
+
console.log(greet('world')); // "Hello, World!"
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Testing
|
|
326
|
+
|
|
327
|
+
### Run the Test Suite
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
npm test
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### Build the Library
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
npm run build
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
This generates compiled JavaScript in the `dist/` folder.
|
|
340
|
+
|
|
341
|
+
### Link Locally for Testing
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
# In the string-extn folder
|
|
345
|
+
npm link
|
|
346
|
+
|
|
347
|
+
# In your test project folder
|
|
348
|
+
npm link string-extn
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
---
|
|
352
|
+
|
|
353
|
+
### Development Commands
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
npm install # Install dependencies
|
|
357
|
+
npm run build # Build the library
|
|
358
|
+
npm test # Run tests
|
|
359
|
+
npm link # Link for local testing
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## License
|
|
365
|
+
|
|
366
|
+
MIT © Balaji Katta Venkatarathnam
|
|
367
|
+
|
package/package.json
CHANGED
|
@@ -1,58 +1,61 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "string-extn",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"types": "dist/index.d.ts",
|
|
7
|
-
"scripts": {
|
|
8
|
-
"build": "tsc",
|
|
9
|
-
"test": "jest",
|
|
10
|
-
"prepublishOnly": "npm run build && npm test"
|
|
11
|
-
},
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"url": "https://github.com/balaji-kv/string-extn
|
|
39
|
-
},
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
"glob": "^10.3.10"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "string-extn",
|
|
3
|
+
"version": "1.0.10",
|
|
4
|
+
"description": "Extended string utility functions for JavaScript and TypeScript.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"test": "jest",
|
|
10
|
+
"prepublishOnly": "npm run build && npm test"
|
|
11
|
+
},
|
|
12
|
+
"publishConfig": {
|
|
13
|
+
"access": "public"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"string",
|
|
17
|
+
"utility",
|
|
18
|
+
"functional",
|
|
19
|
+
"unicode",
|
|
20
|
+
"typescript",
|
|
21
|
+
"string-manipulation",
|
|
22
|
+
"validation",
|
|
23
|
+
"slug",
|
|
24
|
+
"case-conversion",
|
|
25
|
+
"string-masking"
|
|
26
|
+
],
|
|
27
|
+
"author": "Balaji Katta Venkatarathnam",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"type": "module",
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"package.json",
|
|
33
|
+
"README.md",
|
|
34
|
+
"LICENSE"
|
|
35
|
+
],
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "https://github.com/balaji-kv/string-extn.git"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/balaji-kv/string-extn/issues"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/balaji-kv/string-extn#readme",
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"grapheme-splitter": "^1.0.4",
|
|
46
|
+
"typescript": "^5.9.3"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/jest": "^29.5.14",
|
|
50
|
+
"jest": "^29.7.0",
|
|
51
|
+
"ts-jest": "^29.1.2",
|
|
52
|
+
"ts-node": "^10.9.2",
|
|
53
|
+
"glob": "^10.3.10"
|
|
54
|
+
},
|
|
55
|
+
"overrides": {
|
|
56
|
+
"glob": "^10.3.10",
|
|
57
|
+
"inflight": {
|
|
58
|
+
"glob": "^10.3.10"
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|