string-extn 1.0.12 → 1.2.0
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/README.md +174 -1
- package/dist/chain.d.ts +52 -0
- package/dist/chain.d.ts.map +1 -0
- package/dist/chain.js +74 -0
- package/dist/chain.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/intl.d.ts +23 -0
- package/dist/intl.d.ts.map +1 -0
- package/dist/intl.js +27 -0
- package/dist/intl.js.map +1 -0
- package/dist/lazy.d.ts +42 -0
- package/dist/lazy.d.ts.map +1 -0
- package/dist/lazy.js +56 -0
- package/dist/lazy.js.map +1 -0
- package/dist/perf.d.ts +22 -0
- package/dist/perf.d.ts.map +1 -0
- package/dist/perf.js +39 -0
- package/dist/perf.js.map +1 -0
- package/dist/plugin.d.ts +30 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +35 -0
- package/dist/plugin.js.map +1 -0
- package/dist/security.d.ts +28 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +47 -0
- package/dist/security.js.map +1 -0
- package/dist/stream.d.ts +21 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +36 -0
- package/dist/stream.js.map +1 -0
- package/dist/template.d.ts +9 -0
- package/dist/template.d.ts.map +1 -0
- package/dist/template.js +14 -0
- package/dist/template.js.map +1 -0
- package/package.json +19 -10
package/README.md
CHANGED
|
@@ -18,6 +18,14 @@ A lightweight, TypeScript-first library for **safe and functional string manipul
|
|
|
18
18
|
- [URL & Filename Safe Conversion](#url--filename-safe-conversion)
|
|
19
19
|
- [String Validation](#string-validation)
|
|
20
20
|
- [Unicode Operations](#unicode-operations)
|
|
21
|
+
- [Internationalization](#internationalization)
|
|
22
|
+
- [Security & Sanitization](#security--sanitization)
|
|
23
|
+
- [Performance Helpers](#performance-helpers)
|
|
24
|
+
- [Stream Utilities](#stream-utilities)
|
|
25
|
+
- [Chaining & Fluent API](#chaining--fluent-api)
|
|
26
|
+
- [Lazy Evaluation](#lazy-evaluation)
|
|
27
|
+
- [Template Interpolation](#template-interpolation)
|
|
28
|
+
- [Plugin System](#plugin-system)
|
|
21
29
|
- [Examples](#examples)
|
|
22
30
|
- [Testing](#testing)
|
|
23
31
|
- [License](#license)
|
|
@@ -69,6 +77,39 @@ A lightweight, TypeScript-first library for **safe and functional string manipul
|
|
|
69
77
|
- **unicodeSlice** - Slice strings while respecting grapheme boundaries
|
|
70
78
|
- **reverseUnicode** - Reverse strings with proper emoji and combining mark support
|
|
71
79
|
|
|
80
|
+
### 🌐 Internationalization
|
|
81
|
+
- **localeCompare** - Locale-aware string comparison with configurable sensitivity
|
|
82
|
+
- **normalizeUnicode** - Normalize strings to NFC/NFD/NFKC/NFKD
|
|
83
|
+
|
|
84
|
+
### 🔐 Security & Sanitization
|
|
85
|
+
- **escapeHTML** - Escape HTML-reserved characters
|
|
86
|
+
- **escapeSQL** - Escape SQL-sensitive characters
|
|
87
|
+
- **sanitizePath** - Remove traversal and dot segments from paths
|
|
88
|
+
|
|
89
|
+
### ⚡ Performance Helpers
|
|
90
|
+
- **fastRepeat** - Repeat strings using a fast doubling approach
|
|
91
|
+
- **fastPadLeft** - Left-pad strings using fast repeat
|
|
92
|
+
|
|
93
|
+
### 🌊 Stream Utilities
|
|
94
|
+
- **chunkString** - Split strings into fixed-size chunks
|
|
95
|
+
- **streamTransform** - Transform chunks and concatenate results
|
|
96
|
+
|
|
97
|
+
### 🔗 Chaining & Fluent API
|
|
98
|
+
- **chain** - Create chainable string transformations
|
|
99
|
+
- **StringChain** - Fluent wrapper with trim, case, replace, and reverse
|
|
100
|
+
|
|
101
|
+
### 💤 Lazy Evaluation
|
|
102
|
+
- **lazy** - Build lazy transformation pipelines
|
|
103
|
+
- **LazyString** - Deferred execution via `execute()`
|
|
104
|
+
|
|
105
|
+
### 🧩 Template Interpolation
|
|
106
|
+
- **template** - Replace {{key}} placeholders from a variable map
|
|
107
|
+
|
|
108
|
+
### 🧩 Plugin System
|
|
109
|
+
- **registerPlugin** - Register a named string plugin
|
|
110
|
+
- **runPlugin** - Execute a registered plugin
|
|
111
|
+
- **listPlugins** - List registered plugin names
|
|
112
|
+
|
|
72
113
|
---
|
|
73
114
|
|
|
74
115
|
## Installation
|
|
@@ -124,6 +165,48 @@ unicodeSlice(emojiStr, 0, 1); // "👍🏽"
|
|
|
124
165
|
reverseUnicode(emojiStr); // "👍👍🏽"
|
|
125
166
|
```
|
|
126
167
|
|
|
168
|
+
### Chaining & Lazy Evaluation
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import { chain, lazy } from 'string-extn';
|
|
172
|
+
|
|
173
|
+
const chained = chain(' Hello ')
|
|
174
|
+
.trim()
|
|
175
|
+
.toLower()
|
|
176
|
+
.replace('hello', 'hi')
|
|
177
|
+
.reverse()
|
|
178
|
+
.valueOf();
|
|
179
|
+
// "ih"
|
|
180
|
+
|
|
181
|
+
const pipeline = lazy(' Hello ')
|
|
182
|
+
.trim()
|
|
183
|
+
.toUpper();
|
|
184
|
+
|
|
185
|
+
pipeline.execute(); // "HELLO"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Template Interpolation
|
|
189
|
+
|
|
190
|
+
```typescript
|
|
191
|
+
import { template } from 'string-extn';
|
|
192
|
+
|
|
193
|
+
template('Hello {{name}}', { name: 'Ada' }); // "Hello Ada"
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Plugin System
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
import { registerPlugin, runPlugin, listPlugins } from 'string-extn';
|
|
200
|
+
|
|
201
|
+
registerPlugin({
|
|
202
|
+
name: 'wrap',
|
|
203
|
+
fn: (input, left: string, right: string) => `${left}${input}${right}`
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
runPlugin('wrap', 'core', '[', ']'); // "[core]"
|
|
207
|
+
listPlugins(); // ["wrap"]
|
|
208
|
+
```
|
|
209
|
+
|
|
127
210
|
---
|
|
128
211
|
|
|
129
212
|
## API Reference
|
|
@@ -211,6 +294,73 @@ reverseUnicode(emojiStr); // "👍👍🏽"
|
|
|
211
294
|
| `unicodeSlice` | `unicodeSlice(str: string, start: number, end?: number): string` | Slices by grapheme boundaries |
|
|
212
295
|
| `reverseUnicode` | `reverseUnicode(str: string): string` | Reverses with emoji/modifier support |
|
|
213
296
|
|
|
297
|
+
### Internationalization
|
|
298
|
+
|
|
299
|
+
| Function | Signature | Description |
|
|
300
|
+
|----------|-----------|-------------|
|
|
301
|
+
| `localeCompare` | `localeCompare(a: string, b: string, locale?: string, sensitivity?: "base" | "accent" | "case" | "variant"): number` | Locale-aware string comparison |
|
|
302
|
+
| `normalizeUnicode` | `normalizeUnicode(input: string, form?: "NFC" | "NFD" | "NFKC" | "NFKD"): string` | Unicode normalization |
|
|
303
|
+
|
|
304
|
+
### Security & Sanitization
|
|
305
|
+
|
|
306
|
+
| Function | Signature | Description |
|
|
307
|
+
|----------|-----------|-------------|
|
|
308
|
+
| `escapeHTML` | `escapeHTML(input: string): string` | Escapes HTML-reserved characters |
|
|
309
|
+
| `escapeSQL` | `escapeSQL(input: string): string` | Escapes SQL-sensitive characters |
|
|
310
|
+
| `sanitizePath` | `sanitizePath(input: string): string` | Removes traversal and dot segments |
|
|
311
|
+
|
|
312
|
+
### Performance Helpers
|
|
313
|
+
|
|
314
|
+
| Function | Signature | Description |
|
|
315
|
+
|----------|-----------|-------------|
|
|
316
|
+
| `fastRepeat` | `fastRepeat(input: string, count: number): string` | Fast string repetition |
|
|
317
|
+
| `fastPadLeft` | `fastPadLeft(input: string, length: number, char?: string): string` | Fast left padding |
|
|
318
|
+
|
|
319
|
+
### Stream Utilities
|
|
320
|
+
|
|
321
|
+
| Function | Signature | Description |
|
|
322
|
+
|----------|-----------|-------------|
|
|
323
|
+
| `chunkString` | `chunkString(input: string, size: number): string[]` | Split string into chunks |
|
|
324
|
+
| `streamTransform` | `streamTransform(chunks: string[], transformer: (chunk: string) => string): string` | Transform and concatenate |
|
|
325
|
+
|
|
326
|
+
### Chaining & Fluent API
|
|
327
|
+
|
|
328
|
+
| Function | Signature | Description |
|
|
329
|
+
|----------|-----------|-------------|
|
|
330
|
+
| `chain` | `chain(input: string): StringChain` | Create a chainable string wrapper |
|
|
331
|
+
| `StringChain#trim` | `trim(): this` | Trim leading/trailing whitespace |
|
|
332
|
+
| `StringChain#toUpper` | `toUpper(): this` | Uppercase with default locale rules |
|
|
333
|
+
| `StringChain#toLower` | `toLower(): this` | Lowercase with default locale rules |
|
|
334
|
+
| `StringChain#replace` | `replace(search: string | RegExp, replacement: string): this` | Replace with string or RegExp |
|
|
335
|
+
| `StringChain#reverse` | `reverse(): this` | Reverse by Unicode code points |
|
|
336
|
+
| `StringChain#valueOf` | `valueOf(): string` | Get the current value |
|
|
337
|
+
| `StringChain#toString` | `toString(): string` | String coercion output |
|
|
338
|
+
|
|
339
|
+
### Lazy Evaluation
|
|
340
|
+
|
|
341
|
+
| Function | Signature | Description |
|
|
342
|
+
|----------|-----------|-------------|
|
|
343
|
+
| `lazy` | `lazy(input: string): LazyString` | Create a lazy string wrapper |
|
|
344
|
+
| `LazyString#map` | `map(fn: (input: string) => string): this` | Register a deferred transform |
|
|
345
|
+
| `LazyString#trim` | `trim(): this` | Register a trim operation |
|
|
346
|
+
| `LazyString#toUpper` | `toUpper(): this` | Register uppercase conversion |
|
|
347
|
+
| `LazyString#toLower` | `toLower(): this` | Register lowercase conversion |
|
|
348
|
+
| `LazyString#execute` | `execute(): string` | Execute all operations in order |
|
|
349
|
+
|
|
350
|
+
### Template Interpolation
|
|
351
|
+
|
|
352
|
+
| Function | Signature | Description |
|
|
353
|
+
|----------|-----------|-------------|
|
|
354
|
+
| `template` | `template(input: string, variables: Record<string, any>): string` | Replace {{key}} placeholders |
|
|
355
|
+
|
|
356
|
+
### Plugin System
|
|
357
|
+
|
|
358
|
+
| Function | Signature | Description |
|
|
359
|
+
|----------|-----------|-------------|
|
|
360
|
+
| `registerPlugin` | `registerPlugin(plugin: StringExtnPlugin): void` | Register a named plugin |
|
|
361
|
+
| `runPlugin` | `runPlugin(name: string, input: string, ...args: any[]): string` | Execute a plugin by name |
|
|
362
|
+
| `listPlugins` | `listPlugins(): string[]` | List registered plugin names |
|
|
363
|
+
|
|
214
364
|
---
|
|
215
365
|
|
|
216
366
|
## Examples
|
|
@@ -307,7 +457,30 @@ console.log(unicodeSlice(message, 6, 8)); // "👨👩👧👦 "
|
|
|
307
457
|
console.log(reverseUnicode(message)); // Preserves emoji integrity
|
|
308
458
|
```
|
|
309
459
|
|
|
310
|
-
### Example
|
|
460
|
+
### Example 8: Internationalization and Security
|
|
461
|
+
|
|
462
|
+
```typescript
|
|
463
|
+
import { localeCompare, normalizeUnicode, escapeHTML, sanitizePath } from 'string-extn';
|
|
464
|
+
|
|
465
|
+
console.log(localeCompare('resume', 'résumé', 'en', 'accent')); // Non-zero
|
|
466
|
+
console.log(normalizeUnicode('e\u0301', 'NFC')); // "\u00e9"
|
|
467
|
+
console.log(escapeHTML('<script>alert(1)</script>')); // Escaped HTML entities
|
|
468
|
+
console.log(sanitizePath('/var/../tmp')); // "/var/tmp"
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
### Example 9: Performance and Streams
|
|
472
|
+
|
|
473
|
+
```typescript
|
|
474
|
+
import { fastRepeat, fastPadLeft, chunkString, streamTransform } from 'string-extn';
|
|
475
|
+
|
|
476
|
+
console.log(fastRepeat('ab', 4)); // "abababab"
|
|
477
|
+
console.log(fastPadLeft('7', 3, '0')); // "007"
|
|
478
|
+
|
|
479
|
+
const chunks = chunkString('abcdef', 2); // ["ab", "cd", "ef"]
|
|
480
|
+
console.log(streamTransform(chunks, c => c.toUpperCase())); // "ABCDEF"
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Example 10: Function Composition
|
|
311
484
|
|
|
312
485
|
```typescript
|
|
313
486
|
import { compose } from 'string-extn';
|
package/dist/chain.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export declare class StringChain {
|
|
2
|
+
private value;
|
|
3
|
+
/**
|
|
4
|
+
* Create a new chain wrapper for the provided input.
|
|
5
|
+
* @param input The string to wrap for chained operations.
|
|
6
|
+
*/
|
|
7
|
+
constructor(input: string);
|
|
8
|
+
/**
|
|
9
|
+
* Trim leading and trailing whitespace from the current value.
|
|
10
|
+
* @returns The same chain instance for further chaining.
|
|
11
|
+
*/
|
|
12
|
+
trim(): this;
|
|
13
|
+
/**
|
|
14
|
+
* Convert the current value to uppercase using default locale rules.
|
|
15
|
+
* @returns The same chain instance for further chaining.
|
|
16
|
+
*/
|
|
17
|
+
toUpper(): this;
|
|
18
|
+
/**
|
|
19
|
+
* Convert the current value to lowercase using default locale rules.
|
|
20
|
+
* @returns The same chain instance for further chaining.
|
|
21
|
+
*/
|
|
22
|
+
toLower(): this;
|
|
23
|
+
/**
|
|
24
|
+
* Replace a match in the current value using a string or RegExp search.
|
|
25
|
+
* @param search The string or RegExp pattern to search for.
|
|
26
|
+
* @param replacement The replacement string (supports RegExp replacement tokens).
|
|
27
|
+
* @returns The same chain instance for further chaining.
|
|
28
|
+
*/
|
|
29
|
+
replace(search: string | RegExp, replacement: string): this;
|
|
30
|
+
/**
|
|
31
|
+
* Reverse the current value by Unicode code points.
|
|
32
|
+
* @returns The same chain instance for further chaining.
|
|
33
|
+
*/
|
|
34
|
+
reverse(): this;
|
|
35
|
+
/**
|
|
36
|
+
* Get the current value as a string.
|
|
37
|
+
* @returns The current chained value.
|
|
38
|
+
*/
|
|
39
|
+
valueOf(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Convert the chain to a string for coercion or display.
|
|
42
|
+
* @returns The current chained value.
|
|
43
|
+
*/
|
|
44
|
+
toString(): string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Create a new `StringChain` instance for the provided input.
|
|
48
|
+
* @param input The string to wrap for chained operations.
|
|
49
|
+
* @returns A new `StringChain` instance.
|
|
50
|
+
*/
|
|
51
|
+
export declare function chain(input: string): StringChain;
|
|
52
|
+
//# sourceMappingURL=chain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.d.ts","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAS;IAEtB;;;OAGG;gBACS,KAAK,EAAE,MAAM;IAIzB;;;OAGG;IACH,IAAI,IAAI,IAAI;IAKZ;;;OAGG;IACH,OAAO,IAAI,IAAI;IAKf;;;OAGG;IACH,OAAO,IAAI,IAAI;IAKf;;;;;OAKG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI;IAK3D;;;OAGG;IACH,OAAO,IAAI,IAAI;IAKf;;;OAGG;IACH,OAAO,IAAI,MAAM;IAIjB;;;OAGG;IACH,QAAQ,IAAI,MAAM;CAGnB;AAED;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAEhD"}
|
package/dist/chain.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export class StringChain {
|
|
2
|
+
/**
|
|
3
|
+
* Create a new chain wrapper for the provided input.
|
|
4
|
+
* @param input The string to wrap for chained operations.
|
|
5
|
+
*/
|
|
6
|
+
constructor(input) {
|
|
7
|
+
this.value = input;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Trim leading and trailing whitespace from the current value.
|
|
11
|
+
* @returns The same chain instance for further chaining.
|
|
12
|
+
*/
|
|
13
|
+
trim() {
|
|
14
|
+
this.value = this.value.trim();
|
|
15
|
+
return this;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Convert the current value to uppercase using default locale rules.
|
|
19
|
+
* @returns The same chain instance for further chaining.
|
|
20
|
+
*/
|
|
21
|
+
toUpper() {
|
|
22
|
+
this.value = this.value.toUpperCase();
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Convert the current value to lowercase using default locale rules.
|
|
27
|
+
* @returns The same chain instance for further chaining.
|
|
28
|
+
*/
|
|
29
|
+
toLower() {
|
|
30
|
+
this.value = this.value.toLowerCase();
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Replace a match in the current value using a string or RegExp search.
|
|
35
|
+
* @param search The string or RegExp pattern to search for.
|
|
36
|
+
* @param replacement The replacement string (supports RegExp replacement tokens).
|
|
37
|
+
* @returns The same chain instance for further chaining.
|
|
38
|
+
*/
|
|
39
|
+
replace(search, replacement) {
|
|
40
|
+
this.value = this.value.replace(search, replacement);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Reverse the current value by Unicode code points.
|
|
45
|
+
* @returns The same chain instance for further chaining.
|
|
46
|
+
*/
|
|
47
|
+
reverse() {
|
|
48
|
+
this.value = [...this.value].reverse().join("");
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the current value as a string.
|
|
53
|
+
* @returns The current chained value.
|
|
54
|
+
*/
|
|
55
|
+
valueOf() {
|
|
56
|
+
return this.value;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Convert the chain to a string for coercion or display.
|
|
60
|
+
* @returns The current chained value.
|
|
61
|
+
*/
|
|
62
|
+
toString() {
|
|
63
|
+
return this.value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create a new `StringChain` instance for the provided input.
|
|
68
|
+
* @param input The string to wrap for chained operations.
|
|
69
|
+
* @returns A new `StringChain` instance.
|
|
70
|
+
*/
|
|
71
|
+
export function chain(input) {
|
|
72
|
+
return new StringChain(input);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,WAAW;IAGtB;;;OAGG;IACH,YAAY,KAAa;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAC/B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,MAAuB,EAAE,WAAmB;QAClD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED;;;OAGG;IACH,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,KAAK,CAAC,KAAa;IACjC,OAAO,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -7,4 +7,11 @@ export * from './mask.js';
|
|
|
7
7
|
export * from './similarity.js';
|
|
8
8
|
export * from './diff.js';
|
|
9
9
|
export * from './validate.js';
|
|
10
|
+
export * from './intl.js';
|
|
11
|
+
export * from './perf.js';
|
|
12
|
+
export * from './security.js';
|
|
13
|
+
export * from './stream.js';
|
|
14
|
+
export * from './chain.js';
|
|
15
|
+
export * from './lazy.js';
|
|
16
|
+
export * from './plugin.js';
|
|
10
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,4 +7,11 @@ export * from './mask.js';
|
|
|
7
7
|
export * from './similarity.js';
|
|
8
8
|
export * from './diff.js';
|
|
9
9
|
export * from './validate.js';
|
|
10
|
+
export * from './intl.js';
|
|
11
|
+
export * from './perf.js';
|
|
12
|
+
export * from './security.js';
|
|
13
|
+
export * from './stream.js';
|
|
14
|
+
export * from './chain.js';
|
|
15
|
+
export * from './lazy.js';
|
|
16
|
+
export * from './plugin.js';
|
|
10
17
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
|
package/dist/intl.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compares two strings using locale-aware collation rules.
|
|
3
|
+
*
|
|
4
|
+
* @param a - The first string to compare.
|
|
5
|
+
* @param b - The second string to compare.
|
|
6
|
+
* @param locale - BCP 47 locale tag used for collation (defaults to "en").
|
|
7
|
+
* @param sensitivity - Controls how differences in case/diacritics are handled.
|
|
8
|
+
* @returns A negative number if `a` sorts before `b`, positive if after, or 0 if equal.
|
|
9
|
+
*
|
|
10
|
+
* Special behavior: Uses `Intl.Collator`, which provides Unicode-aware comparison.
|
|
11
|
+
*/
|
|
12
|
+
export declare function localeCompare(a: string, b: string, locale?: string, sensitivity?: Intl.CollatorOptions["sensitivity"]): number;
|
|
13
|
+
/**
|
|
14
|
+
* Normalizes a string to the specified Unicode normalization form.
|
|
15
|
+
*
|
|
16
|
+
* @param input - The string to normalize.
|
|
17
|
+
* @param form - The Unicode normalization form (NFC, NFD, NFKC, or NFKD).
|
|
18
|
+
* @returns The normalized string.
|
|
19
|
+
*
|
|
20
|
+
* Special behavior: Preserves Unicode text while normalizing code point sequences.
|
|
21
|
+
*/
|
|
22
|
+
export declare function normalizeUnicode(input: string, form?: "NFC" | "NFD" | "NFKC" | "NFKD"): string;
|
|
23
|
+
//# sourceMappingURL=intl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intl.d.ts","sourceRoot":"","sources":["../src/intl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,MAAM,SAAO,EACb,WAAW,GAAE,IAAI,CAAC,eAAe,CAAC,aAAa,CAAU,GACxD,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,MAAc,GAC5C,MAAM,CAER"}
|
package/dist/intl.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compares two strings using locale-aware collation rules.
|
|
3
|
+
*
|
|
4
|
+
* @param a - The first string to compare.
|
|
5
|
+
* @param b - The second string to compare.
|
|
6
|
+
* @param locale - BCP 47 locale tag used for collation (defaults to "en").
|
|
7
|
+
* @param sensitivity - Controls how differences in case/diacritics are handled.
|
|
8
|
+
* @returns A negative number if `a` sorts before `b`, positive if after, or 0 if equal.
|
|
9
|
+
*
|
|
10
|
+
* Special behavior: Uses `Intl.Collator`, which provides Unicode-aware comparison.
|
|
11
|
+
*/
|
|
12
|
+
export function localeCompare(a, b, locale = "en", sensitivity = "base") {
|
|
13
|
+
return new Intl.Collator(locale, { sensitivity }).compare(a, b);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Normalizes a string to the specified Unicode normalization form.
|
|
17
|
+
*
|
|
18
|
+
* @param input - The string to normalize.
|
|
19
|
+
* @param form - The Unicode normalization form (NFC, NFD, NFKC, or NFKD).
|
|
20
|
+
* @returns The normalized string.
|
|
21
|
+
*
|
|
22
|
+
* Special behavior: Preserves Unicode text while normalizing code point sequences.
|
|
23
|
+
*/
|
|
24
|
+
export function normalizeUnicode(input, form = "NFC") {
|
|
25
|
+
return input.normalize(form);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=intl.js.map
|
package/dist/intl.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intl.js","sourceRoot":"","sources":["../src/intl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,CAAS,EACT,CAAS,EACT,MAAM,GAAG,IAAI,EACb,cAAmD,MAAM;IAEzD,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAC9B,KAAa,EACb,OAAwC,KAAK;IAE7C,OAAO,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AAC/B,CAAC"}
|
package/dist/lazy.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare class LazyString {
|
|
2
|
+
private input;
|
|
3
|
+
private operations;
|
|
4
|
+
/**
|
|
5
|
+
* Create a new lazy wrapper for the provided input.
|
|
6
|
+
* @param input The string to wrap for lazy operations.
|
|
7
|
+
*/
|
|
8
|
+
constructor(input: string);
|
|
9
|
+
/**
|
|
10
|
+
* Register a transformation to run later during execution.
|
|
11
|
+
* @param fn A function that receives the current value and returns the next value.
|
|
12
|
+
* @returns The same lazy instance for further chaining.
|
|
13
|
+
*/
|
|
14
|
+
map(fn: (input: string) => string): this;
|
|
15
|
+
/**
|
|
16
|
+
* Register a trim operation that removes surrounding whitespace.
|
|
17
|
+
* @returns The same lazy instance for further chaining.
|
|
18
|
+
*/
|
|
19
|
+
trim(): this;
|
|
20
|
+
/**
|
|
21
|
+
* Register an uppercase conversion using default locale rules.
|
|
22
|
+
* @returns The same lazy instance for further chaining.
|
|
23
|
+
*/
|
|
24
|
+
toUpper(): this;
|
|
25
|
+
/**
|
|
26
|
+
* Register a lowercase conversion using default locale rules.
|
|
27
|
+
* @returns The same lazy instance for further chaining.
|
|
28
|
+
*/
|
|
29
|
+
toLower(): this;
|
|
30
|
+
/**
|
|
31
|
+
* Execute all registered operations in order and return the result.
|
|
32
|
+
* @returns The final transformed string.
|
|
33
|
+
*/
|
|
34
|
+
execute(): string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a new `LazyString` instance for the provided input.
|
|
38
|
+
* @param input The string to wrap for lazy operations.
|
|
39
|
+
* @returns A new `LazyString` instance.
|
|
40
|
+
*/
|
|
41
|
+
export declare function lazy(input: string): LazyString;
|
|
42
|
+
//# sourceMappingURL=lazy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy.d.ts","sourceRoot":"","sources":["../src/lazy.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAU;IACrB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,UAAU,CAAiC;IAEnD;;;OAGG;gBACS,KAAK,EAAE,MAAM;IAIzB;;;;OAIG;IACH,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI;IAKxC;;;OAGG;IACH,IAAI,IAAI,IAAI;IAIZ;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf;;;OAGG;IACH,OAAO,IAAI,MAAM;CAMlB;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAE9C"}
|
package/dist/lazy.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export class LazyString {
|
|
2
|
+
/**
|
|
3
|
+
* Create a new lazy wrapper for the provided input.
|
|
4
|
+
* @param input The string to wrap for lazy operations.
|
|
5
|
+
*/
|
|
6
|
+
constructor(input) {
|
|
7
|
+
this.operations = [];
|
|
8
|
+
this.input = input;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Register a transformation to run later during execution.
|
|
12
|
+
* @param fn A function that receives the current value and returns the next value.
|
|
13
|
+
* @returns The same lazy instance for further chaining.
|
|
14
|
+
*/
|
|
15
|
+
map(fn) {
|
|
16
|
+
this.operations.push(fn);
|
|
17
|
+
return this;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Register a trim operation that removes surrounding whitespace.
|
|
21
|
+
* @returns The same lazy instance for further chaining.
|
|
22
|
+
*/
|
|
23
|
+
trim() {
|
|
24
|
+
return this.map(s => s.trim());
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Register an uppercase conversion using default locale rules.
|
|
28
|
+
* @returns The same lazy instance for further chaining.
|
|
29
|
+
*/
|
|
30
|
+
toUpper() {
|
|
31
|
+
return this.map(s => s.toUpperCase());
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Register a lowercase conversion using default locale rules.
|
|
35
|
+
* @returns The same lazy instance for further chaining.
|
|
36
|
+
*/
|
|
37
|
+
toLower() {
|
|
38
|
+
return this.map(s => s.toLowerCase());
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Execute all registered operations in order and return the result.
|
|
42
|
+
* @returns The final transformed string.
|
|
43
|
+
*/
|
|
44
|
+
execute() {
|
|
45
|
+
return this.operations.reduce((acc, fn) => fn(acc), this.input);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Create a new `LazyString` instance for the provided input.
|
|
50
|
+
* @param input The string to wrap for lazy operations.
|
|
51
|
+
* @returns A new `LazyString` instance.
|
|
52
|
+
*/
|
|
53
|
+
export function lazy(input) {
|
|
54
|
+
return new LazyString(input);
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=lazy.js.map
|
package/dist/lazy.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lazy.js","sourceRoot":"","sources":["../src/lazy.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,UAAU;IAIrB;;;OAGG;IACH,YAAY,KAAa;QANjB,eAAU,GAA8B,EAAE,CAAC;QAOjD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;IAED;;;;OAIG;IACH,GAAG,CAAC,EAA6B;QAC/B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IACxC,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAC3B,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EACpB,IAAI,CAAC,KAAK,CACX,CAAC;IACJ,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,IAAI,CAAC,KAAa;IAChC,OAAO,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC"}
|
package/dist/perf.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repeats a string using a fast doubling technique.
|
|
3
|
+
*
|
|
4
|
+
* @param input - The string to repeat.
|
|
5
|
+
* @param count - The number of times to repeat the string.
|
|
6
|
+
* @returns The repeated string, or an empty string when count is not positive or not finite.
|
|
7
|
+
*
|
|
8
|
+
* Special behavior: Non-integer counts are floored; non-finite or non-positive counts return "".
|
|
9
|
+
*/
|
|
10
|
+
export declare function fastRepeat(input: string, count: number): string;
|
|
11
|
+
/**
|
|
12
|
+
* Pads the left side of a string to a target length using a fast repeat.
|
|
13
|
+
*
|
|
14
|
+
* @param input - The string to pad.
|
|
15
|
+
* @param length - The desired total length of the result.
|
|
16
|
+
* @param char - The padding character (defaults to a space).
|
|
17
|
+
* @returns The padded string, or the original string if already long enough.
|
|
18
|
+
*
|
|
19
|
+
* Special behavior: Uses code unit length and does not trim or normalize input.
|
|
20
|
+
*/
|
|
21
|
+
export declare function fastPadLeft(input: string, length: number, char?: string): string;
|
|
22
|
+
//# sourceMappingURL=perf.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf.d.ts","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAY/D;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,SAAM,GACT,MAAM,CAGR"}
|
package/dist/perf.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repeats a string using a fast doubling technique.
|
|
3
|
+
*
|
|
4
|
+
* @param input - The string to repeat.
|
|
5
|
+
* @param count - The number of times to repeat the string.
|
|
6
|
+
* @returns The repeated string, or an empty string when count is not positive or not finite.
|
|
7
|
+
*
|
|
8
|
+
* Special behavior: Non-integer counts are floored; non-finite or non-positive counts return "".
|
|
9
|
+
*/
|
|
10
|
+
export function fastRepeat(input, count) {
|
|
11
|
+
if (!Number.isFinite(count) || count <= 0)
|
|
12
|
+
return "";
|
|
13
|
+
let remaining = Math.floor(count);
|
|
14
|
+
let result = "";
|
|
15
|
+
let current = input;
|
|
16
|
+
while (remaining > 0) {
|
|
17
|
+
if (remaining & 1)
|
|
18
|
+
result += current;
|
|
19
|
+
current += current;
|
|
20
|
+
remaining >>= 1;
|
|
21
|
+
}
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Pads the left side of a string to a target length using a fast repeat.
|
|
26
|
+
*
|
|
27
|
+
* @param input - The string to pad.
|
|
28
|
+
* @param length - The desired total length of the result.
|
|
29
|
+
* @param char - The padding character (defaults to a space).
|
|
30
|
+
* @returns The padded string, or the original string if already long enough.
|
|
31
|
+
*
|
|
32
|
+
* Special behavior: Uses code unit length and does not trim or normalize input.
|
|
33
|
+
*/
|
|
34
|
+
export function fastPadLeft(input, length, char = " ") {
|
|
35
|
+
if (input.length >= length)
|
|
36
|
+
return input;
|
|
37
|
+
return fastRepeat(char, length - input.length) + input;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=perf.js.map
|
package/dist/perf.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"perf.js","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,KAAa;IACrD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACrD,IAAI,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAClC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,OAAO,SAAS,GAAG,CAAC,EAAE,CAAC;QACrB,IAAI,SAAS,GAAG,CAAC;YAAE,MAAM,IAAI,OAAO,CAAC;QACrC,OAAO,IAAI,OAAO,CAAC;QACnB,SAAS,KAAK,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CACzB,KAAa,EACb,MAAc,EACd,IAAI,GAAG,GAAG;IAEV,IAAI,KAAK,CAAC,MAAM,IAAI,MAAM;QAAE,OAAO,KAAK,CAAC;IACzC,OAAO,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC;AACzD,CAAC"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin contract for extending string utilities.
|
|
3
|
+
*/
|
|
4
|
+
export type StringExtnPlugin = {
|
|
5
|
+
/** The unique plugin name used for registration and lookup. */
|
|
6
|
+
name: string;
|
|
7
|
+
/** The function invoked when the plugin runs. */
|
|
8
|
+
fn: (input: string, ...args: any[]) => string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Register a plugin for later execution.
|
|
12
|
+
* @param plugin The plugin to register.
|
|
13
|
+
* @throws If a plugin with the same name is already registered.
|
|
14
|
+
*/
|
|
15
|
+
export declare function registerPlugin(plugin: StringExtnPlugin): void;
|
|
16
|
+
/**
|
|
17
|
+
* Execute a registered plugin by name.
|
|
18
|
+
* @param name The plugin name to execute.
|
|
19
|
+
* @param input The input string passed to the plugin.
|
|
20
|
+
* @param args Additional arguments forwarded to the plugin function.
|
|
21
|
+
* @returns The plugin's result string.
|
|
22
|
+
* @throws If the plugin does not exist.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runPlugin(name: string, input: string, ...args: any[]): string;
|
|
25
|
+
/**
|
|
26
|
+
* List all registered plugin names in registration order.
|
|
27
|
+
* @returns An array of plugin names.
|
|
28
|
+
*/
|
|
29
|
+
export declare function listPlugins(): string[];
|
|
30
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC;CAC/C,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAM7D;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,GAAG,IAAI,EAAE,GAAG,EAAE,GACb,MAAM,CAQR;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,EAAE,CAEtC"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const plugins = new Map();
|
|
2
|
+
/**
|
|
3
|
+
* Register a plugin for later execution.
|
|
4
|
+
* @param plugin The plugin to register.
|
|
5
|
+
* @throws If a plugin with the same name is already registered.
|
|
6
|
+
*/
|
|
7
|
+
export function registerPlugin(plugin) {
|
|
8
|
+
if (plugins.has(plugin.name)) {
|
|
9
|
+
throw new Error(`Plugin '${plugin.name}' already exists`);
|
|
10
|
+
}
|
|
11
|
+
plugins.set(plugin.name, plugin);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Execute a registered plugin by name.
|
|
15
|
+
* @param name The plugin name to execute.
|
|
16
|
+
* @param input The input string passed to the plugin.
|
|
17
|
+
* @param args Additional arguments forwarded to the plugin function.
|
|
18
|
+
* @returns The plugin's result string.
|
|
19
|
+
* @throws If the plugin does not exist.
|
|
20
|
+
*/
|
|
21
|
+
export function runPlugin(name, input, ...args) {
|
|
22
|
+
const plugin = plugins.get(name);
|
|
23
|
+
if (!plugin) {
|
|
24
|
+
throw new Error(`Plugin '${name}' not found`);
|
|
25
|
+
}
|
|
26
|
+
return plugin.fn(input, ...args);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* List all registered plugin names in registration order.
|
|
30
|
+
* @returns An array of plugin names.
|
|
31
|
+
*/
|
|
32
|
+
export function listPlugins() {
|
|
33
|
+
return Array.from(plugins.keys());
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAUA,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;AAEpD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAAwB;IACrD,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,WAAW,MAAM,CAAC,IAAI,kBAAkB,CAAC,CAAC;IAC5D,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,KAAa,EACb,GAAG,IAAW;IAEd,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAEjC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,aAAa,CAAC,CAAC;IAChD,CAAC;IAED,OAAO,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Escapes HTML-reserved characters to their entity equivalents.
|
|
3
|
+
*
|
|
4
|
+
* @param input - The string to escape.
|
|
5
|
+
* @returns The escaped string with HTML-sensitive characters replaced.
|
|
6
|
+
*
|
|
7
|
+
* Special behavior: Escapes `&`, `<`, `>`, `"`, and `'` characters; does not decode entities.
|
|
8
|
+
*/
|
|
9
|
+
export declare function escapeHTML(input: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Escapes SQL-sensitive characters by prefixing them with a backslash.
|
|
12
|
+
*
|
|
13
|
+
* @param input - The string to escape.
|
|
14
|
+
* @returns The escaped string with `'`, `"`, `;`, and `\` prefixed by `\`.
|
|
15
|
+
*
|
|
16
|
+
* Special behavior: Simple escaping helper; it does not validate SQL or prevent all injection cases.
|
|
17
|
+
*/
|
|
18
|
+
export declare function escapeSQL(input: string): string;
|
|
19
|
+
/**
|
|
20
|
+
* Sanitizes a path-like string by removing traversal and dot segments.
|
|
21
|
+
*
|
|
22
|
+
* @param input - The path string to sanitize.
|
|
23
|
+
* @returns The sanitized path with `.` and `..` segments removed.
|
|
24
|
+
*
|
|
25
|
+
* Special behavior: Preserves a leading separator and normalizes repeated separators.
|
|
26
|
+
*/
|
|
27
|
+
export declare function sanitizePath(input: string): string;
|
|
28
|
+
//# sourceMappingURL=security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAQA;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASlD"}
|
package/dist/security.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const ESCAPE_MAP = {
|
|
2
|
+
"&": "&",
|
|
3
|
+
"<": "<",
|
|
4
|
+
">": ">",
|
|
5
|
+
'"': """,
|
|
6
|
+
"'": "'"
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Escapes HTML-reserved characters to their entity equivalents.
|
|
10
|
+
*
|
|
11
|
+
* @param input - The string to escape.
|
|
12
|
+
* @returns The escaped string with HTML-sensitive characters replaced.
|
|
13
|
+
*
|
|
14
|
+
* Special behavior: Escapes `&`, `<`, `>`, `"`, and `'` characters; does not decode entities.
|
|
15
|
+
*/
|
|
16
|
+
export function escapeHTML(input) {
|
|
17
|
+
return input.replace(/[&<>"']/g, char => ESCAPE_MAP[char] ?? char);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Escapes SQL-sensitive characters by prefixing them with a backslash.
|
|
21
|
+
*
|
|
22
|
+
* @param input - The string to escape.
|
|
23
|
+
* @returns The escaped string with `'`, `"`, `;`, and `\` prefixed by `\`.
|
|
24
|
+
*
|
|
25
|
+
* Special behavior: Simple escaping helper; it does not validate SQL or prevent all injection cases.
|
|
26
|
+
*/
|
|
27
|
+
export function escapeSQL(input) {
|
|
28
|
+
return input.replace(/['";\\]/g, "\\$&");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Sanitizes a path-like string by removing traversal and dot segments.
|
|
32
|
+
*
|
|
33
|
+
* @param input - The path string to sanitize.
|
|
34
|
+
* @returns The sanitized path with `.` and `..` segments removed.
|
|
35
|
+
*
|
|
36
|
+
* Special behavior: Preserves a leading separator and normalizes repeated separators.
|
|
37
|
+
*/
|
|
38
|
+
export function sanitizePath(input) {
|
|
39
|
+
const separator = input.includes("/") ? "/" : "\\";
|
|
40
|
+
const hasLeadingSeparator = input.startsWith("/") || input.startsWith("\\");
|
|
41
|
+
const parts = input
|
|
42
|
+
.split(/[\\/]+/)
|
|
43
|
+
.filter(part => part !== "" && part !== "." && part !== "..");
|
|
44
|
+
const sanitized = parts.join(separator);
|
|
45
|
+
return hasLeadingSeparator ? `${separator}${sanitized}` : sanitized;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.js","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,GAA2B;IACzC,GAAG,EAAE,OAAO;IACZ,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,MAAM;IACX,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,QAAQ;CACd,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;AACrE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IACnD,MAAM,mBAAmB,GAAG,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC5E,MAAM,KAAK,GAAG,KAAK;SAChB,KAAK,CAAC,QAAQ,CAAC;SACf,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC;IAEhE,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,OAAO,mBAAmB,CAAC,CAAC,CAAC,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AACtE,CAAC"}
|
package/dist/stream.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits a string into an array of fixed-size chunks.
|
|
3
|
+
*
|
|
4
|
+
* @param input - The string to split.
|
|
5
|
+
* @param size - The chunk size in code units; must be a positive, finite number.
|
|
6
|
+
* @returns An array of chunk strings.
|
|
7
|
+
*
|
|
8
|
+
* Special behavior: Throws when size is non-positive or non-finite.
|
|
9
|
+
*/
|
|
10
|
+
export declare function chunkString(input: string, size: number): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Applies a transformer to each chunk and concatenates the results.
|
|
13
|
+
*
|
|
14
|
+
* @param chunks - The list of chunks to transform.
|
|
15
|
+
* @param transformer - The function applied to each chunk.
|
|
16
|
+
* @returns The concatenated transformed result.
|
|
17
|
+
*
|
|
18
|
+
* Special behavior: Preserves chunk order and performs a simple left-to-right join.
|
|
19
|
+
*/
|
|
20
|
+
export declare function streamTransform(chunks: string[], transformer: (chunk: string) => string): string;
|
|
21
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CASjE;AAGD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EAAE,EAChB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GACrC,MAAM,CAMR"}
|
package/dist/stream.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Splits a string into an array of fixed-size chunks.
|
|
3
|
+
*
|
|
4
|
+
* @param input - The string to split.
|
|
5
|
+
* @param size - The chunk size in code units; must be a positive, finite number.
|
|
6
|
+
* @returns An array of chunk strings.
|
|
7
|
+
*
|
|
8
|
+
* Special behavior: Throws when size is non-positive or non-finite.
|
|
9
|
+
*/
|
|
10
|
+
export function chunkString(input, size) {
|
|
11
|
+
if (!Number.isFinite(size) || size <= 0) {
|
|
12
|
+
throw new Error("Chunk size must be a positive number.");
|
|
13
|
+
}
|
|
14
|
+
const result = [];
|
|
15
|
+
for (let i = 0; i < input.length; i += size) {
|
|
16
|
+
result.push(input.slice(i, i + size));
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Applies a transformer to each chunk and concatenates the results.
|
|
22
|
+
*
|
|
23
|
+
* @param chunks - The list of chunks to transform.
|
|
24
|
+
* @param transformer - The function applied to each chunk.
|
|
25
|
+
* @returns The concatenated transformed result.
|
|
26
|
+
*
|
|
27
|
+
* Special behavior: Preserves chunk order and performs a simple left-to-right join.
|
|
28
|
+
*/
|
|
29
|
+
export function streamTransform(chunks, transformer) {
|
|
30
|
+
let result = "";
|
|
31
|
+
for (const chunk of chunks) {
|
|
32
|
+
result += transformer(chunk);
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,IAAY;IACrD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IAC3D,CAAC;IACD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAGD;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAgB,EAChB,WAAsC;IAEtC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replace {{key}} placeholders in a template string with values from a map.
|
|
3
|
+
* @param input The template string containing {{key}} placeholders.
|
|
4
|
+
* @param variables A map of placeholder keys to values.
|
|
5
|
+
* @returns The rendered string with placeholders replaced.
|
|
6
|
+
* @remarks Keys are trimmed inside braces. Missing values (undefined) become an empty string.
|
|
7
|
+
*/
|
|
8
|
+
export declare function template(input: string, variables: Record<string, any>): string;
|
|
9
|
+
//# sourceMappingURL=template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.d.ts","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC7B,MAAM,CAKR"}
|
package/dist/template.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Replace {{key}} placeholders in a template string with values from a map.
|
|
3
|
+
* @param input The template string containing {{key}} placeholders.
|
|
4
|
+
* @param variables A map of placeholder keys to values.
|
|
5
|
+
* @returns The rendered string with placeholders replaced.
|
|
6
|
+
* @remarks Keys are trimmed inside braces. Missing values (undefined) become an empty string.
|
|
7
|
+
*/
|
|
8
|
+
export function template(input, variables) {
|
|
9
|
+
return input.replace(/\{\{(.*?)\}\}/g, (_, key) => {
|
|
10
|
+
const value = variables[key.trim()];
|
|
11
|
+
return value !== undefined ? String(value) : "";
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=template.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../src/template.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CACtB,KAAa,EACb,SAA8B;IAE9B,OAAO,KAAK,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAChD,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QACpC,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "string-extn",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Extended string utility functions for JavaScript and TypeScript.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,6 +16,17 @@
|
|
|
16
16
|
"string",
|
|
17
17
|
"utility",
|
|
18
18
|
"functional",
|
|
19
|
+
"security",
|
|
20
|
+
"html-escape",
|
|
21
|
+
"sql-escape",
|
|
22
|
+
"path-sanitization",
|
|
23
|
+
"performance",
|
|
24
|
+
"fast-repeat",
|
|
25
|
+
"padding",
|
|
26
|
+
"stream",
|
|
27
|
+
"chunk",
|
|
28
|
+
"internationalization",
|
|
29
|
+
"i18n",
|
|
19
30
|
"unicode",
|
|
20
31
|
"typescript",
|
|
21
32
|
"string-manipulation",
|
|
@@ -42,20 +53,18 @@
|
|
|
42
53
|
},
|
|
43
54
|
"homepage": "https://github.com/balaji-kv/string-extn#readme",
|
|
44
55
|
"dependencies": {
|
|
56
|
+
"glob": "^13.0.6",
|
|
45
57
|
"grapheme-splitter": "^1.0.4",
|
|
46
58
|
"typescript": "^5.9.3"
|
|
47
59
|
},
|
|
48
60
|
"devDependencies": {
|
|
49
|
-
"@types/jest": "^
|
|
50
|
-
"jest": "^
|
|
51
|
-
"ts-jest": "^29.
|
|
52
|
-
"ts-node": "^10.9.2"
|
|
53
|
-
"glob": "^10.3.10"
|
|
61
|
+
"@types/jest": "^30.0.0",
|
|
62
|
+
"jest": "^30.2.0",
|
|
63
|
+
"ts-jest": "^29.4.6",
|
|
64
|
+
"ts-node": "^10.9.2"
|
|
54
65
|
},
|
|
55
66
|
"overrides": {
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"glob": "^10.3.10"
|
|
59
|
-
}
|
|
67
|
+
"minimatch": "^10.2.2",
|
|
68
|
+
"glob": "^13.0.6"
|
|
60
69
|
}
|
|
61
70
|
}
|