@ix-xs/node-comfort 1.1.31 → 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/LICENSE +21 -0
- package/README.md +623 -748
- package/index.js +39 -13
- package/package.json +74 -21
- package/src/Arr.js +433 -0
- package/src/Checker.js +547 -188
- package/src/FS.js +127 -1
- package/src/Func.js +375 -0
- package/src/Id.js +235 -0
- package/src/Logger.js +71 -0
- package/src/Num.js +366 -0
- package/src/Obj.js +421 -0
- package/src/SQLite.js +20 -9
- package/src/Str.js +452 -0
- package/src/Time.js +485 -0
- package/types/index.d.ts +406 -0
- package/types/index.d.ts.map +1 -1
- package/types/src/Arr.d.ts +252 -0
- package/types/src/Arr.d.ts.map +1 -0
- package/types/src/Checker.d.ts +292 -30
- package/types/src/Checker.d.ts.map +1 -1
- package/types/src/FS.d.ts +60 -0
- package/types/src/FS.d.ts.map +1 -1
- package/types/src/Func.d.ts +210 -0
- package/types/src/Func.d.ts.map +1 -0
- package/types/src/Id.d.ts +119 -0
- package/types/src/Id.d.ts.map +1 -0
- package/types/src/Logger.d.ts +33 -0
- package/types/src/Logger.d.ts.map +1 -1
- package/types/src/Num.d.ts +242 -0
- package/types/src/Num.d.ts.map +1 -0
- package/types/src/Obj.d.ts +189 -0
- package/types/src/Obj.d.ts.map +1 -0
- package/types/src/SQLite.d.ts +6 -1
- package/types/src/SQLite.d.ts.map +1 -1
- package/types/src/Str.d.ts +293 -0
- package/types/src/Str.d.ts.map +1 -0
- package/types/src/Time.d.ts +205 -0
- package/types/src/Time.d.ts.map +1 -0
- package/tsconfig.json +0 -18
package/src/Str.js
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* String utilities.
|
|
3
|
+
*
|
|
4
|
+
* A curated set of the string helpers you end up rewriting in every project:
|
|
5
|
+
* case conversion, slugs, truncation, padding, template rendering, and more.
|
|
6
|
+
* Zero dependencies, Unicode-aware where it matters.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Splits a string into its "words", handling camelCase, PascalCase,
|
|
11
|
+
* snake_case, kebab-case, spaces and digits.
|
|
12
|
+
* @private
|
|
13
|
+
* @param {string} str
|
|
14
|
+
* @returns {string[]}
|
|
15
|
+
*/
|
|
16
|
+
const _words = (str) => {
|
|
17
|
+
return String(str)
|
|
18
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1 $2")
|
|
19
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
|
|
20
|
+
.replace(/[_\-.]+/g, " ")
|
|
21
|
+
.replace(/[^\p{L}\p{N}]+/gu, " ")
|
|
22
|
+
.trim()
|
|
23
|
+
.split(/\s+/)
|
|
24
|
+
.filter(Boolean);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
/**
|
|
29
|
+
* Capitalizes the first character of a string and lowercases the rest.
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* nodeComfort.str.capitalize("hELLO"); // "Hello"
|
|
33
|
+
*
|
|
34
|
+
* @param {string} str - Input string.
|
|
35
|
+
* @returns {string} The capitalized string.
|
|
36
|
+
*/
|
|
37
|
+
capitalize(str) {
|
|
38
|
+
str = String(str);
|
|
39
|
+
if (!str) return str;
|
|
40
|
+
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
41
|
+
},
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Uppercases the first character of each word (Title Case), leaving the rest untouched.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* nodeComfort.str.titleCase("the quick brown fox"); // "The Quick Brown Fox"
|
|
48
|
+
*
|
|
49
|
+
* @param {string} str - Input string.
|
|
50
|
+
* @returns {string} The title-cased string.
|
|
51
|
+
*/
|
|
52
|
+
titleCase(str) {
|
|
53
|
+
return String(str).replace(/\b\p{L}/gu, (c) => c.toUpperCase());
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Converts a string to `camelCase`.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* nodeComfort.str.camelCase("hello world"); // "helloWorld"
|
|
61
|
+
* nodeComfort.str.camelCase("foo-bar_baz"); // "fooBarBaz"
|
|
62
|
+
*
|
|
63
|
+
* @param {string} str - Input string.
|
|
64
|
+
* @returns {string} The camelCased string.
|
|
65
|
+
*/
|
|
66
|
+
camelCase(str) {
|
|
67
|
+
return _words(str)
|
|
68
|
+
.map((word, i) =>
|
|
69
|
+
i === 0
|
|
70
|
+
? word.toLowerCase()
|
|
71
|
+
: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(),
|
|
72
|
+
)
|
|
73
|
+
.join("");
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Converts a string to `PascalCase`.
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* nodeComfort.str.pascalCase("hello world"); // "HelloWorld"
|
|
81
|
+
*
|
|
82
|
+
* @param {string} str - Input string.
|
|
83
|
+
* @returns {string} The PascalCased string.
|
|
84
|
+
*/
|
|
85
|
+
pascalCase(str) {
|
|
86
|
+
return _words(str)
|
|
87
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
88
|
+
.join("");
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Converts a string to `snake_case`.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* nodeComfort.str.snakeCase("helloWorld"); // "hello_world"
|
|
96
|
+
*
|
|
97
|
+
* @param {string} str - Input string.
|
|
98
|
+
* @returns {string} The snake_cased string.
|
|
99
|
+
*/
|
|
100
|
+
snakeCase(str) {
|
|
101
|
+
return _words(str).map((word) => word.toLowerCase()).join("_");
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Converts a string to `kebab-case`.
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* nodeComfort.str.kebabCase("helloWorld"); // "hello-world"
|
|
109
|
+
*
|
|
110
|
+
* @param {string} str - Input string.
|
|
111
|
+
* @returns {string} The kebab-cased string.
|
|
112
|
+
*/
|
|
113
|
+
kebabCase(str) {
|
|
114
|
+
return _words(str).map((word) => word.toLowerCase()).join("-");
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Converts a string to `CONSTANT_CASE`.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* nodeComfort.str.constantCase("helloWorld"); // "HELLO_WORLD"
|
|
122
|
+
*
|
|
123
|
+
* @param {string} str - Input string.
|
|
124
|
+
* @returns {string} The CONSTANT_CASED string.
|
|
125
|
+
*/
|
|
126
|
+
constantCase(str) {
|
|
127
|
+
return _words(str).map((word) => word.toUpperCase()).join("_");
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Converts a string into a URL-friendly slug.
|
|
132
|
+
*
|
|
133
|
+
* Accents/diacritics are stripped, non-alphanumeric runs become the separator.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* nodeComfort.str.slugify("Héllo, World!"); // "hello-world"
|
|
137
|
+
* nodeComfort.str.slugify("A B C", { separator: "_" }); // "a_b_c"
|
|
138
|
+
*
|
|
139
|
+
* @param {string} str - Input string.
|
|
140
|
+
* @param {{ separator?: string, lower?: boolean }} [options] - Slug options.
|
|
141
|
+
* @returns {string} The slug.
|
|
142
|
+
*/
|
|
143
|
+
slugify(str, options = {}) {
|
|
144
|
+
const separator = options.separator ?? "-";
|
|
145
|
+
const lower = options.lower ?? true;
|
|
146
|
+
const result = String(str)
|
|
147
|
+
.normalize("NFKD")
|
|
148
|
+
.replace(/[̀-ͯ]/g, "")
|
|
149
|
+
.replace(/[^\p{L}\p{N}]+/gu, separator)
|
|
150
|
+
.replace(new RegExp(`\\${separator}{2,}`, "g"), separator)
|
|
151
|
+
.replace(new RegExp(`^\\${separator}|\\${separator}$`, "g"), "");
|
|
152
|
+
return lower ? result.toLowerCase() : result;
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Truncates a string to a maximum length, appending an ellipsis if cut.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* nodeComfort.str.truncate("Hello world", 8); // "Hello…"
|
|
160
|
+
* nodeComfort.str.truncate("Hello world", 8, { omission: "..." }); // "Hello..."
|
|
161
|
+
*
|
|
162
|
+
* @param {string} str - Input string.
|
|
163
|
+
* @param {number} length - Maximum length of the result (including the omission).
|
|
164
|
+
* @param {{ omission?: string, words?: boolean }} [options] - Truncation options.
|
|
165
|
+
* @returns {string} The truncated string.
|
|
166
|
+
*/
|
|
167
|
+
truncate(str, length, options = {}) {
|
|
168
|
+
str = String(str);
|
|
169
|
+
const omission = options.omission ?? "…";
|
|
170
|
+
if (str.length <= length) return str;
|
|
171
|
+
|
|
172
|
+
const cut = Math.max(0, length - omission.length);
|
|
173
|
+
let sliced = str.slice(0, cut);
|
|
174
|
+
|
|
175
|
+
if (options.words) {
|
|
176
|
+
const lastSpace = sliced.lastIndexOf(" ");
|
|
177
|
+
if (lastSpace > 0) sliced = sliced.slice(0, lastSpace);
|
|
178
|
+
}
|
|
179
|
+
return sliced.replace(/\s+$/, "") + omission;
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Pads a string on the left (start) to a target length.
|
|
184
|
+
*
|
|
185
|
+
* @param {string} str - Input string.
|
|
186
|
+
* @param {number} length - Target total length.
|
|
187
|
+
* @param {string} [char=" "] - Padding character(s).
|
|
188
|
+
* @returns {string} The padded string.
|
|
189
|
+
*/
|
|
190
|
+
padStart(str, length, char = " ") {
|
|
191
|
+
return String(str).padStart(length, char);
|
|
192
|
+
},
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Pads a string on the right (end) to a target length.
|
|
196
|
+
*
|
|
197
|
+
* @param {string} str - Input string.
|
|
198
|
+
* @param {number} length - Target total length.
|
|
199
|
+
* @param {string} [char=" "] - Padding character(s).
|
|
200
|
+
* @returns {string} The padded string.
|
|
201
|
+
*/
|
|
202
|
+
padEnd(str, length, char = " ") {
|
|
203
|
+
return String(str).padEnd(length, char);
|
|
204
|
+
},
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Centers a string within a target length by padding both sides.
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* nodeComfort.str.center("hi", 6); // " hi "
|
|
211
|
+
* nodeComfort.str.center("hi", 6, "*"); // "**hi**"
|
|
212
|
+
*
|
|
213
|
+
* @param {string} str - Input string.
|
|
214
|
+
* @param {number} length - Target total length.
|
|
215
|
+
* @param {string} [char=" "] - Padding character.
|
|
216
|
+
* @returns {string} The centered string.
|
|
217
|
+
*/
|
|
218
|
+
center(str, length, char = " ") {
|
|
219
|
+
str = String(str);
|
|
220
|
+
if (str.length >= length) return str;
|
|
221
|
+
const total = length - str.length;
|
|
222
|
+
const left = Math.floor(total / 2);
|
|
223
|
+
const right = total - left;
|
|
224
|
+
return char.repeat(left) + str + char.repeat(right);
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Reverses a string (Unicode code-point aware, so emojis stay intact).
|
|
229
|
+
*
|
|
230
|
+
* @example
|
|
231
|
+
* nodeComfort.str.reverse("abc"); // "cba"
|
|
232
|
+
*
|
|
233
|
+
* @param {string} str - Input string.
|
|
234
|
+
* @returns {string} The reversed string.
|
|
235
|
+
*/
|
|
236
|
+
reverse(str) {
|
|
237
|
+
return [...String(str)].reverse().join("");
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Collapses all runs of whitespace into single spaces and trims the ends.
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* nodeComfort.str.squish(" hello world \n"); // "hello world"
|
|
245
|
+
*
|
|
246
|
+
* @param {string} str - Input string.
|
|
247
|
+
* @returns {string} The normalized string.
|
|
248
|
+
*/
|
|
249
|
+
squish(str) {
|
|
250
|
+
return String(str).replace(/\s+/g, " ").trim();
|
|
251
|
+
},
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Removes all HTML tags from a string.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* nodeComfort.str.stripTags("<b>Hi</b> there"); // "Hi there"
|
|
258
|
+
*
|
|
259
|
+
* @param {string} str - Input string.
|
|
260
|
+
* @returns {string} The string with tags removed.
|
|
261
|
+
*/
|
|
262
|
+
stripTags(str) {
|
|
263
|
+
return String(str).replace(/<\/?[^>]+(>|$)/g, "");
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Escapes HTML-sensitive characters (`& < > " '`).
|
|
268
|
+
*
|
|
269
|
+
* @example
|
|
270
|
+
* nodeComfort.str.escapeHTML('<a href="x">'); // "<a href="x">"
|
|
271
|
+
*
|
|
272
|
+
* @param {string} str - Input string.
|
|
273
|
+
* @returns {string} The escaped string.
|
|
274
|
+
*/
|
|
275
|
+
escapeHTML(str) {
|
|
276
|
+
const map = { "&": "&", "<": "<", ">": ">", "\"": """, "'": "'" };
|
|
277
|
+
return String(str).replace(/[&<>"']/g, (c) => map[c]);
|
|
278
|
+
},
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Reverses {@link escapeHTML}: turns HTML entities back into characters.
|
|
282
|
+
*
|
|
283
|
+
* @param {string} str - Input string.
|
|
284
|
+
* @returns {string} The unescaped string.
|
|
285
|
+
*/
|
|
286
|
+
unescapeHTML(str) {
|
|
287
|
+
const map = { "&": "&", "<": "<", ">": ">", """: "\"", "'": "'", "'": "'" };
|
|
288
|
+
return String(str).replace(/&(amp|lt|gt|quot|#39|#x27);/g, (m) => map[m]);
|
|
289
|
+
},
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Escapes a string for safe use inside a `RegExp`.
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* new RegExp(nodeComfort.str.escapeRegExp("a.b")); // matches literal "a.b"
|
|
296
|
+
*
|
|
297
|
+
* @param {string} str - Input string.
|
|
298
|
+
* @returns {string} The escaped string.
|
|
299
|
+
*/
|
|
300
|
+
escapeRegExp(str) {
|
|
301
|
+
return String(str).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Counts the number of non-overlapping occurrences of a substring.
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* nodeComfort.str.count("banana", "a"); // 3
|
|
309
|
+
*
|
|
310
|
+
* @param {string} str - Input string.
|
|
311
|
+
* @param {string} sub - Substring to count.
|
|
312
|
+
* @returns {number} Number of occurrences.
|
|
313
|
+
*/
|
|
314
|
+
count(str, sub) {
|
|
315
|
+
str = String(str);
|
|
316
|
+
if (!sub) return 0;
|
|
317
|
+
let count = 0;
|
|
318
|
+
let pos = str.indexOf(sub);
|
|
319
|
+
while (pos !== -1) {
|
|
320
|
+
count++;
|
|
321
|
+
pos = str.indexOf(sub, pos + sub.length);
|
|
322
|
+
}
|
|
323
|
+
return count;
|
|
324
|
+
},
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Ensures a string starts with a given prefix (adds it only if missing).
|
|
328
|
+
*
|
|
329
|
+
* @example
|
|
330
|
+
* nodeComfort.str.ensurePrefix("example.com", "https://"); // "https://example.com"
|
|
331
|
+
*
|
|
332
|
+
* @param {string} str - Input string.
|
|
333
|
+
* @param {string} prefix - Prefix to ensure.
|
|
334
|
+
* @returns {string} The string with the prefix guaranteed.
|
|
335
|
+
*/
|
|
336
|
+
ensurePrefix(str, prefix) {
|
|
337
|
+
str = String(str);
|
|
338
|
+
return str.startsWith(prefix) ? str : prefix + str;
|
|
339
|
+
},
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Ensures a string ends with a given suffix (adds it only if missing).
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* nodeComfort.str.ensureSuffix("path", "/"); // "path/"
|
|
346
|
+
*
|
|
347
|
+
* @param {string} str - Input string.
|
|
348
|
+
* @param {string} suffix - Suffix to ensure.
|
|
349
|
+
* @returns {string} The string with the suffix guaranteed.
|
|
350
|
+
*/
|
|
351
|
+
ensureSuffix(str, suffix) {
|
|
352
|
+
str = String(str);
|
|
353
|
+
return str.endsWith(suffix) ? str : str + suffix;
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Removes a prefix from a string if present.
|
|
358
|
+
*
|
|
359
|
+
* @param {string} str - Input string.
|
|
360
|
+
* @param {string} prefix - Prefix to remove.
|
|
361
|
+
* @returns {string} The string without the prefix.
|
|
362
|
+
*/
|
|
363
|
+
removePrefix(str, prefix) {
|
|
364
|
+
str = String(str);
|
|
365
|
+
return str.startsWith(prefix) ? str.slice(prefix.length) : str;
|
|
366
|
+
},
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Removes a suffix from a string if present.
|
|
370
|
+
*
|
|
371
|
+
* @param {string} str - Input string.
|
|
372
|
+
* @param {string} suffix - Suffix to remove.
|
|
373
|
+
* @returns {string} The string without the suffix.
|
|
374
|
+
*/
|
|
375
|
+
removeSuffix(str, suffix) {
|
|
376
|
+
str = String(str);
|
|
377
|
+
return suffix && str.endsWith(suffix) ? str.slice(0, -suffix.length) : str;
|
|
378
|
+
},
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Renders a template, replacing `{key}` placeholders with values from `data`.
|
|
382
|
+
*
|
|
383
|
+
* Missing keys are left as-is by default. Nested paths (`{user.name}`) are supported.
|
|
384
|
+
*
|
|
385
|
+
* @example
|
|
386
|
+
* nodeComfort.str.template("Hi {name}, you have {count} msgs", { name: "Jo", count: 3 });
|
|
387
|
+
* // "Hi Jo, you have 3 msgs"
|
|
388
|
+
*
|
|
389
|
+
* @param {string} str - Template string.
|
|
390
|
+
* @param {Record<string, any>} data - Replacement values.
|
|
391
|
+
* @param {{ open?: string, close?: string, fallback?: string }} [options] - Delimiters / fallback.
|
|
392
|
+
* @returns {string} The rendered string.
|
|
393
|
+
*/
|
|
394
|
+
template(str, data, options = {}) {
|
|
395
|
+
const open = options.open ?? "{";
|
|
396
|
+
const close = options.close ?? "}";
|
|
397
|
+
const esc = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
398
|
+
const regex = new RegExp(`${esc(open)}\\s*([\\w.]+)\\s*${esc(close)}`, "g");
|
|
399
|
+
return String(str).replace(regex, (match, key) => {
|
|
400
|
+
const value = key.split(".").reduce((acc, k) => (acc == null ? acc : acc[k]), data);
|
|
401
|
+
if (value === undefined || value === null) {
|
|
402
|
+
return options.fallback !== undefined ? options.fallback : match;
|
|
403
|
+
}
|
|
404
|
+
return String(value);
|
|
405
|
+
});
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Splits a string into an array of "words" (camelCase / snake / kebab aware).
|
|
410
|
+
*
|
|
411
|
+
* @example
|
|
412
|
+
* nodeComfort.str.words("helloWorld-foo_bar"); // ["hello", "World", "foo", "bar"]
|
|
413
|
+
*
|
|
414
|
+
* @param {string} str - Input string.
|
|
415
|
+
* @returns {string[]} The words.
|
|
416
|
+
*/
|
|
417
|
+
words(str) {
|
|
418
|
+
return _words(str);
|
|
419
|
+
},
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Returns the visible length of a string in code points (emoji-safe).
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* "😀".length; // 2
|
|
426
|
+
* nodeComfort.str.length("😀"); // 1
|
|
427
|
+
*
|
|
428
|
+
* @param {string} str - Input string.
|
|
429
|
+
* @returns {number} The number of code points.
|
|
430
|
+
*/
|
|
431
|
+
length(str) {
|
|
432
|
+
return [...String(str)].length;
|
|
433
|
+
},
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Generates a random alphanumeric string of a given length.
|
|
437
|
+
*
|
|
438
|
+
* Note: uses `Math.random` and is **not** cryptographically secure.
|
|
439
|
+
* For tokens/IDs use `nodeComfort.id.token()` instead.
|
|
440
|
+
*
|
|
441
|
+
* @param {number} [length=16] - Desired length.
|
|
442
|
+
* @param {string} [charset] - Characters to pick from.
|
|
443
|
+
* @returns {string} The random string.
|
|
444
|
+
*/
|
|
445
|
+
random(length = 16, charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") {
|
|
446
|
+
let out = "";
|
|
447
|
+
for (let i = 0; i < length; i++) {
|
|
448
|
+
out += charset.charAt(Math.floor(Math.random() * charset.length));
|
|
449
|
+
}
|
|
450
|
+
return out;
|
|
451
|
+
},
|
|
452
|
+
};
|