Skip to content

Commit 73eb115

Browse files
authored
Add new functions (#36)
1 parent e36dfc6 commit 73eb115

19 files changed

+1871
-80
lines changed

README.md

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ fuzzyMatch("usrctrl", "userController.js"); // { matched: true, score: 0.444 }
177177
fuzzyMatch("of", "openFile"); // { matched: true, score: 0.75 }
178178
```
179179

180-
> 📖 **See all 44 functions in the API Reference below**
180+
> 📖 **See all 45 functions in the API Reference below**
181181
182182
## CLI
183183

@@ -293,7 +293,7 @@ nano-string slugify --help
293293

294294
## API Reference
295295

296-
The library provides 44 string utility functions organized by category. Click on any category to explore the available functions.
296+
The library provides 47 string utility functions organized by category. Click on any category to explore the available functions.
297297

298298
<details>
299299
<summary><b>🔤 Case Conversion Functions (10 functions)</b></summary>
@@ -540,7 +540,7 @@ hashString("world"); // 113318802
540540
</details>
541541

542542
<details>
543-
<summary><b>📝 Text Processing (11 functions)</b></summary>
543+
<summary><b>📝 Text Processing (13 functions)</b></summary>
544544

545545
### Text Processing
546546

@@ -555,6 +555,17 @@ stripHtml("<p>Hello <b>world</b>!</p>"); // 'Hello world!'
555555
stripHtml("<div>Text</div>"); // 'Text'
556556
```
557557

558+
#### `sanitize(str: string, options?: SanitizeOptions): string`
559+
560+
Security-focused string sanitization for safe use in web applications by removing or escaping dangerous content.
561+
562+
```javascript
563+
sanitize("<script>alert('xss')</script>Hello"); // 'Hello'
564+
sanitize("<b>Bold</b> text", { allowedTags: ["b"] }); // '<b>Bold</b> text'
565+
sanitize("javascript:alert(1)"); // ''
566+
sanitize("<div onclick='alert(1)'>Click</div>"); // 'Click'
567+
```
568+
558569
#### `escapeHtml(str: string): string`
559570

560571
Escapes HTML special characters.
@@ -807,6 +818,39 @@ isASCII("abc123!@#"); // true
807818
isASCII(""); // true
808819
```
809820

821+
#### `detectScript(str: string): 'latin' | 'cjk' | 'arabic' | 'cyrillic' | 'hebrew' | 'devanagari' | 'greek' | 'thai' | 'unknown'`
822+
823+
Detects the dominant writing system (script) in a text string.
824+
825+
```javascript
826+
detectScript("Hello World"); // 'latin'
827+
detectScript("你好世界"); // 'cjk'
828+
detectScript("مرحبا بالعالم"); // 'arabic'
829+
detectScript("Привет мир"); // 'cyrillic'
830+
detectScript("שלום עולם"); // 'hebrew'
831+
detectScript("नमस्ते दुनिया"); // 'devanagari'
832+
detectScript("Γειά σου κόσμε"); // 'greek'
833+
detectScript("สวัสดีชาวโลก"); // 'thai'
834+
detectScript(""); // 'unknown'
835+
```
836+
837+
#### `classifyText(str: string): { type: string, confidence: number }`
838+
839+
Classifies text content by type (URL, email, code, JSON, markdown, HTML, question, phone, numeric, or plain text) with confidence scoring.
840+
841+
```javascript
842+
classifyText("https://example.com"); // { type: 'url', confidence: 1 }
843+
classifyText("[email protected]"); // { type: 'email', confidence: 1 }
844+
classifyText("What is TypeScript?"); // { type: 'question', confidence: 1 }
845+
classifyText('{"key": "value"}'); // { type: 'json', confidence: 1 }
846+
classifyText("function hello() { return 42; }"); // { type: 'code', confidence: 0.85 }
847+
classifyText("<div>Hello</div>"); // { type: 'html', confidence: 0.9 }
848+
classifyText("# Title\n\nText"); // { type: 'markdown', confidence: 0.7 }
849+
classifyText("+1-555-123-4567"); // { type: 'phone', confidence: 0.95 }
850+
classifyText("42 + 17 = 59"); // { type: 'numeric', confidence: 0.8 }
851+
classifyText("Just plain text"); // { type: 'text', confidence: 0.7 }
852+
```
853+
810854
</details>
811855

812856
<details>
@@ -1361,6 +1405,7 @@ Each utility is optimized to be as small as possible:
13611405
| capitalize | ~100 bytes |
13621406
| truncate | ~150 bytes |
13631407
| stripHtml | ~120 bytes |
1408+
| sanitize | ~1.2 KB |
13641409
| escapeHtml | ~180 bytes |
13651410
| excerpt | ~220 bytes |
13661411
| randomString | ~200 bytes |
@@ -1392,8 +1437,10 @@ Each utility is optimized to be as small as possible:
13921437
| humanizeList | ~850 bytes |
13931438
| memoize | ~400 bytes |
13941439
| extractEntities | ~1.1KB |
1440+
| detectScript | ~1.1KB |
1441+
| classifyText | ~2.3KB |
13951442

1396-
Total package size: **< 7.5KB** minified + gzipped
1443+
Total package size: **< 8.5KB** minified + gzipped
13971444

13981445
## Requirements
13991446

benchmarks/all-functions.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"codePoints",
55
"constantCase",
66
"deburr",
7+
"detectScript",
78
"diff",
89
"dotCase",
910
"escapeHtml",

benchmarks/bundle-size-results.md

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
## Overview
44

5-
- **Total Functions**: 44
6-
- **Nano Wins**: 37/44
7-
- **Average Size Reduction**: -49%
5+
- **Total Functions**: 46
6+
- **Nano Wins**: 39/46
7+
- **Average Size Reduction**: -48%
88

99
## Detailed Comparison
1010

@@ -14,20 +14,22 @@ Sizes shown are minified (gzipped). For nano-string-utils, tree-shaken size is s
1414
| --------------------- | ----------------- | ------------- | ----------- | ---------- | ------- |
1515
| camelCase | 1.6KB (827B) | 8.3KB (3.4KB) | 367B (273B) | es-toolkit | -203% |
1616
| capitalize | 1.4KB (696B) | 3.7KB (1.7KB) | 97B (107B) | es-toolkit | -550% |
17+
| classifyText | 2.4KB (986B) | - | - | nano 🏆 | - |
1718
| codePoints | 1.4KB (728B) | - | - | nano 🏆 | - |
1819
| constantCase | 1.6KB (805B) | - | - | nano 🏆 | - |
19-
| deburr | 1.6KB (879B) | 4.6KB (1.8KB) | 544B (332B) | es-toolkit | -165% |
20+
| deburr | 1.6KB (880B) | 4.6KB (1.8KB) | 544B (332B) | es-toolkit | -165% |
21+
| detectScript | 2.3KB (1.1KB) | - | - | nano 🏆 | - |
2022
| diff | 1.8KB (863B) | - | - | nano 🏆 | - |
21-
| dotCase | 1.6KB (785B) | - | - | nano 🏆 | - |
23+
| dotCase | 1.6KB (786B) | - | - | nano 🏆 | - |
2224
| escapeHtml | 1.4KB (741B) | - | - | nano 🏆 | - |
23-
| excerpt | 1.6KB (841B) | - | - | nano 🏆 | - |
25+
| excerpt | 1.6KB (840B) | - | - | nano 🏆 | - |
2426
| extractEntities | 2.3KB (1.1KB) | - | - | nano 🏆 | - |
2527
| fuzzyMatch | 2.4KB (1.2KB) | - | - | nano 🏆 | - |
26-
| graphemes | 1.5KB (758B) | - | - | nano 🏆 | - |
28+
| graphemes | 1.5KB (759B) | - | - | nano 🏆 | - |
2729
| hashString | 1.5KB (760B) | - | - | nano 🏆 | - |
2830
| highlight | 1.9KB (1.0KB) | - | - | nano 🏆 | - |
29-
| humanizeList | 1.6KB (856B) | - | - | nano 🏆 | - |
30-
| isASCII | 1.4KB (720B) | - | - | nano 🏆 | - |
31+
| humanizeList | 1.6KB (857B) | - | - | nano 🏆 | - |
32+
| isASCII | 1.4KB (721B) | - | - | nano 🏆 | - |
3133
| isEmail | 1.3KB (665B) | - | - | nano 🏆 | - |
3234
| isUrl | 1.3KB (665B) | - | - | nano 🏆 | - |
3335
| kebabCase | 1.6KB (792B) | 6.7KB (2.8KB) | 238B (197B) | es-toolkit | -302% |
@@ -37,14 +39,14 @@ Sizes shown are minified (gzipped). For nano-string-utils, tree-shaken size is s
3739
| normalizeWhitespace | 1.8KB (860B) | - | - | nano 🏆 | - |
3840
| pad | 1.7KB (895B) | 5.8KB (2.6KB) | 109B (118B) | es-toolkit | -658% |
3941
| padEnd | 1.5KB (788B) | 5.7KB (2.5KB) | - | nano 🏆 | 70% |
40-
| padStart | 1.5KB (784B) | 5.7KB (2.5KB) | - | nano 🏆 | 70% |
42+
| padStart | 1.5KB (785B) | 5.7KB (2.5KB) | - | nano 🏆 | 70% |
4143
| pascalCase | 1.6KB (821B) | - | 299B (231B) | es-toolkit | -255% |
4244
| pathCase | 1.6KB (785B) | - | - | nano 🏆 | - |
4345
| pluralize | 2.2KB (1.0KB) | - | - | nano 🏆 | - |
4446
| randomString | 1.5KB (821B) | - | - | nano 🏆 | - |
4547
| removeNonPrintable | 1.7KB (918B) | - | - | nano 🏆 | - |
4648
| reverse | 1.4KB (687B) | - | - | nano 🏆 | - |
47-
| sentenceCase | 2.1KB (991B) | - | - | nano 🏆 | - |
49+
| sentenceCase | 2.1KB (992B) | - | - | nano 🏆 | - |
4850
| singularize | 2.6KB (1.1KB) | - | - | nano 🏆 | - |
4951
| slugify | 1.3KB (667B) | - | - | nano 🏆 | - |
5052
| smartSplit | 2.3KB (1.1KB) | - | - | nano 🏆 | - |

benchmarks/bundle-sizes.json

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
2-
"generated": "2025-09-22T19:47:40.221Z",
3-
"totalFunctions": 44,
2+
"generated": "2025-09-27T10:16:47.743Z",
3+
"totalFunctions": 45,
44
"functions": [
55
{
66
"name": "camelCase",
@@ -85,11 +85,11 @@
8585
"nano": {
8686
"bundled": {
8787
"raw": 1676,
88-
"gzip": 879
88+
"gzip": 880
8989
},
9090
"treeShaken": {
9191
"raw": 1676,
92-
"gzip": 879
92+
"gzip": 880
9393
}
9494
},
9595
"lodash": {
@@ -103,6 +103,22 @@
103103
"winner": "es-toolkit",
104104
"percentSavings": -165
105105
},
106+
{
107+
"name": "detectScript",
108+
"nano": {
109+
"bundled": {
110+
"raw": 2374,
111+
"gzip": 1161
112+
},
113+
"treeShaken": {
114+
"raw": 2374,
115+
"gzip": 1161
116+
}
117+
},
118+
"lodash": null,
119+
"esToolkit": null,
120+
"winner": "nano"
121+
},
106122
{
107123
"name": "diff",
108124
"nano": {
@@ -124,11 +140,11 @@
124140
"nano": {
125141
"bundled": {
126142
"raw": 1653,
127-
"gzip": 785
143+
"gzip": 786
128144
},
129145
"treeShaken": {
130146
"raw": 1653,
131-
"gzip": 785
147+
"gzip": 786
132148
}
133149
},
134150
"lodash": null,
@@ -156,11 +172,11 @@
156172
"nano": {
157173
"bundled": {
158174
"raw": 1667,
159-
"gzip": 841
175+
"gzip": 840
160176
},
161177
"treeShaken": {
162178
"raw": 1667,
163-
"gzip": 841
179+
"gzip": 840
164180
}
165181
},
166182
"lodash": null,
@@ -188,11 +204,11 @@
188204
"nano": {
189205
"bundled": {
190206
"raw": 2506,
191-
"gzip": 1212
207+
"gzip": 1213
192208
},
193209
"treeShaken": {
194210
"raw": 2506,
195-
"gzip": 1212
211+
"gzip": 1213
196212
}
197213
},
198214
"lodash": null,
@@ -204,11 +220,11 @@
204220
"nano": {
205221
"bundled": {
206222
"raw": 1541,
207-
"gzip": 758
223+
"gzip": 759
208224
},
209225
"treeShaken": {
210226
"raw": 1541,
211-
"gzip": 758
227+
"gzip": 759
212228
}
213229
},
214230
"lodash": null,
@@ -251,12 +267,12 @@
251267
"name": "humanizeList",
252268
"nano": {
253269
"bundled": {
254-
"raw": 1648,
255-
"gzip": 856
270+
"raw": 1652,
271+
"gzip": 857
256272
},
257273
"treeShaken": {
258-
"raw": 1648,
259-
"gzip": 856
274+
"raw": 1652,
275+
"gzip": 857
260276
}
261277
},
262278
"lodash": null,
@@ -268,11 +284,11 @@
268284
"nano": {
269285
"bundled": {
270286
"raw": 1448,
271-
"gzip": 720
287+
"gzip": 721
272288
},
273289
"treeShaken": {
274290
"raw": 1448,
275-
"gzip": 720
291+
"gzip": 721
276292
}
277293
},
278294
"lodash": null,
@@ -339,11 +355,11 @@
339355
"nano": {
340356
"bundled": {
341357
"raw": 2083,
342-
"gzip": 1029
358+
"gzip": 1030
343359
},
344360
"treeShaken": {
345361
"raw": 2083,
346-
"gzip": 1029
362+
"gzip": 1030
347363
}
348364
},
349365
"lodash": null,
@@ -355,11 +371,11 @@
355371
"nano": {
356372
"bundled": {
357373
"raw": 2243,
358-
"gzip": 1085
374+
"gzip": 1086
359375
},
360376
"treeShaken": {
361377
"raw": 2243,
362-
"gzip": 1085
378+
"gzip": 1086
363379
}
364380
},
365381
"lodash": null,
@@ -446,11 +462,11 @@
446462
"nano": {
447463
"bundled": {
448464
"raw": 1545,
449-
"gzip": 784
465+
"gzip": 785
450466
},
451467
"treeShaken": {
452468
"raw": 1545,
453-
"gzip": 784
469+
"gzip": 785
454470
}
455471
},
456472
"lodash": {
@@ -566,11 +582,11 @@
566582
"nano": {
567583
"bundled": {
568584
"raw": 2148,
569-
"gzip": 991
585+
"gzip": 992
570586
},
571587
"treeShaken": {
572588
"raw": 2148,
573-
"gzip": 991
589+
"gzip": 992
574590
}
575591
},
576592
"lodash": null,
@@ -614,11 +630,11 @@
614630
"nano": {
615631
"bundled": {
616632
"raw": 2370,
617-
"gzip": 1153
633+
"gzip": 1152
618634
},
619635
"treeShaken": {
620636
"raw": 2370,
621-
"gzip": 1153
637+
"gzip": 1152
622638
}
623639
},
624640
"lodash": null,
@@ -770,10 +786,10 @@
770786
}
771787
],
772788
"summary": {
773-
"totalNanoWins": 37,
789+
"totalNanoWins": 38,
774790
"totalEsToolkitWins": 7,
775791
"totalLodashWins": 0,
776-
"averageSavings": -49,
792+
"averageSavings": -48,
777793
"smallestFunction": "isEmail",
778794
"largestFunction": "toASCII"
779795
}

0 commit comments

Comments
 (0)