@webalternatif/js-core 1.6.0 → 1.6.4

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.
Files changed (67) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/Mouse.js +6 -1
  3. package/dist/cjs/Translator.js +7 -1
  4. package/dist/cjs/array.js +7 -25
  5. package/dist/cjs/dom.js +819 -210
  6. package/dist/cjs/eventDispatcher.js +6 -1
  7. package/dist/cjs/index.js +6 -13
  8. package/dist/cjs/is.js +49 -6
  9. package/dist/cjs/math.js +56 -31
  10. package/dist/cjs/onOff.js +2 -2
  11. package/dist/cjs/random.js +6 -6
  12. package/dist/cjs/string.js +19 -17
  13. package/dist/cjs/traversal.js +1 -2
  14. package/dist/cjs/utils.js +155 -38
  15. package/dist/esm/Mouse.js +8 -2
  16. package/dist/esm/Translator.js +9 -3
  17. package/dist/esm/array.js +10 -29
  18. package/dist/esm/dom.js +821 -211
  19. package/dist/esm/eventDispatcher.js +9 -3
  20. package/dist/esm/index.js +7 -8
  21. package/dist/esm/is.js +49 -6
  22. package/dist/esm/math.js +60 -34
  23. package/dist/esm/onOff.js +6 -6
  24. package/dist/esm/random.js +6 -6
  25. package/dist/esm/string.js +23 -21
  26. package/dist/esm/stringPrototype.js +2 -2
  27. package/dist/esm/traversal.js +2 -3
  28. package/dist/esm/utils.js +158 -41
  29. package/dist/umd/Translator.umd.js +1 -0
  30. package/dist/umd/dom.umd.js +1 -0
  31. package/dist/umd/eventDispatcher.umd.js +1 -0
  32. package/dist/umd/mouse.umd.js +1 -0
  33. package/dist/umd/webf.umd.js +1 -0
  34. package/docs/array.md +90 -0
  35. package/docs/dom.md +1477 -0
  36. package/docs/eventDispatcher.md +15 -0
  37. package/docs/is.md +259 -0
  38. package/docs/math.md +127 -0
  39. package/docs/mouse.md +58 -0
  40. package/docs/random.md +15 -0
  41. package/docs/string.md +145 -0
  42. package/docs/translator.md +95 -0
  43. package/docs/traversal.md +159 -0
  44. package/docs/utils.md +228 -0
  45. package/package.json +37 -5
  46. package/src/Mouse.js +73 -0
  47. package/src/Translator.js +148 -0
  48. package/src/array.js +136 -0
  49. package/src/dom.js +1553 -0
  50. package/src/eventDispatcher.js +118 -0
  51. package/src/index.js +106 -0
  52. package/src/is.js +201 -0
  53. package/src/math.js +113 -0
  54. package/src/onOff.js +313 -0
  55. package/src/random.js +38 -0
  56. package/src/string.js +662 -0
  57. package/src/stringPrototype.js +16 -0
  58. package/src/traversal.js +236 -0
  59. package/src/utils.js +242 -0
  60. package/types/Translator.d.ts +6 -5
  61. package/types/array.d.ts +1 -2
  62. package/types/dom.d.ts +763 -204
  63. package/types/index.d.ts +23 -22
  64. package/types/is.d.ts +3 -0
  65. package/types/math.d.ts +6 -5
  66. package/types/utils.d.ts +4 -4
  67. package/types/i18n.d.ts +0 -4
package/src/string.js ADDED
@@ -0,0 +1,662 @@
1
+ import { isArray, isFloat, isInteger, isPlainObject, isString, isUndefined } from './is.js'
2
+ import { dec2hex, hex2dec, round } from './math.js'
3
+ import { inArray } from './array.js'
4
+ import { each, map } from './traversal.js'
5
+ // import {translate} from "./Translator.js";
6
+
7
+ export const trim = function (str, char = '\\s') {
8
+ return ltrim(rtrim(str, char), char)
9
+ }
10
+
11
+ export const ltrim = function (str, char = '\\s') {
12
+ return str.replace(new RegExp(`^${char}+`, 'g'), '')
13
+ }
14
+
15
+ export const rtrim = function (str, char = '\\s') {
16
+ return str.replace(new RegExp(`${char}+$`, 'g'), '')
17
+ }
18
+
19
+ export const stripMultipleSpaces = function (str) {
20
+ return str.trim().replace(/ +/g, ' ')
21
+ }
22
+
23
+ export const noAccent = function (str) {
24
+ return str
25
+ .replace(/[àäâ]/g, 'a')
26
+ .replace(/[èéêë]/g, 'e')
27
+ .replace(/[îïí]/g, 'i')
28
+ .replace(/[öô]/g, 'o')
29
+ .replace(/[üù]/g, 'u')
30
+ .replace(/ç/g, 'c')
31
+ .replace(/ÿ/g, 'y')
32
+ .replace(/[ÀÄÂ]/g, 'A')
33
+ .replace(/[ÈÉÊË]/g, 'E')
34
+ .replace(/[ÎÏÍ]/g, 'I')
35
+ .replace(/[ÖÔ]/g, 'O')
36
+ .replace(/[ÜÙ]/g, 'U')
37
+ .replace(/Ç/g, 'C')
38
+ .replace(/Ÿ/g, 'Y')
39
+ }
40
+
41
+ export const br2nl = function (str) {
42
+ return str.split(/<br\s*\/*>/).join('\n')
43
+ }
44
+
45
+ export const nl2br = function (str) {
46
+ return str.split('\n').join('<br>')
47
+ }
48
+
49
+ export const ucfirst = function (str) {
50
+ return str.charAt(0).toUpperCase() + str.slice(1)
51
+ }
52
+
53
+ export const lcfirst = function (str) {
54
+ return str.charAt(0).toLowerCase() + str.slice(1)
55
+ }
56
+
57
+ export const insertTag = function (str, tag, position = 0, length = 0) {
58
+ let startTag = `<${tag}>`
59
+ let endTag = `</${tag}>`
60
+
61
+ if (['br', 'hr', 'img', 'link', 'input'].includes(tag)) {
62
+ startTag = `<${tag}/>`
63
+ endTag = ''
64
+ }
65
+
66
+ return (
67
+ str.slice(0, position) +
68
+ startTag +
69
+ str.slice(position, position + length) +
70
+ endTag +
71
+ str.slice(position + length)
72
+ )
73
+ }
74
+
75
+ export const substringIndex = function (str, delimiter, index) {
76
+ let input = str + '',
77
+ arr = input.split(delimiter)
78
+
79
+ if (index > 0) {
80
+ arr.splice(index, arr.length - index)
81
+ } else if (index < 0) {
82
+ arr.splice(0, arr.length + index)
83
+ }
84
+
85
+ return arr.join(delimiter)
86
+ }
87
+
88
+ export const insert = (str, ins, n) => {
89
+ if (n >= str.length) {
90
+ return str
91
+ }
92
+
93
+ return [...str].reduce((newStr, char, index) => {
94
+ if (index > 0 && index % n === 0) {
95
+ return newStr + ins + char
96
+ }
97
+
98
+ return newStr + char
99
+ }, '')
100
+ }
101
+
102
+ export const reverse = function (str) {
103
+ let res = []
104
+
105
+ for (let i = 0; i < str.length; i++) {
106
+ res.unshift(str[i])
107
+ }
108
+
109
+ return res.join('')
110
+ }
111
+
112
+ export const thousandSeparator = function (value, separator = '.', pointDecimal = '.') {
113
+ if (isUndefined(value) || null === value) {
114
+ return value
115
+ }
116
+
117
+ value = (value + '').replace(',', '.')
118
+
119
+ if (Math.abs(value) >= 1000) {
120
+ let intval = Math[value >= 1000 ? 'floor' : 'ceil'](value) + ''
121
+ let newval = reverse(insert(reverse(intval), reverse(separator), 3))
122
+
123
+ return value.indexOf('.') > 0
124
+ ? newval + pointDecimal + substringIndex(value, '.', -1)
125
+ : newval
126
+ }
127
+
128
+ return (value + '').replace('.', pointDecimal)
129
+ }
130
+
131
+ export const numberFormat = function (
132
+ number,
133
+ decimals = 2,
134
+ forceCentimes = false,
135
+ thousandSep = '',
136
+ pointDecimal = '.',
137
+ ) {
138
+ number = number ? number + '' : '0'
139
+ number = round(parseFloat(number.replace(',', '.')), decimals) + ''
140
+
141
+ if (decimals === 0) {
142
+ return thousandSeparator(number, thousandSep, pointDecimal)
143
+ }
144
+
145
+ const pos = number.lastIndexOf('.')
146
+
147
+ if (-1 === pos) {
148
+ if (true === forceCentimes) {
149
+ number += pointDecimal + repeat('0', decimals)
150
+ }
151
+
152
+ return thousandSeparator(number, thousandSep, pointDecimal)
153
+ }
154
+
155
+ const digits = number.slice(pos + 1)
156
+ const nbDigits = digits.length
157
+ if (decimals > nbDigits) {
158
+ return thousandSeparator(
159
+ number + '0'.repeat(decimals - nbDigits),
160
+ thousandSep,
161
+ pointDecimal,
162
+ )
163
+ }
164
+
165
+ return thousandSeparator(number.slice(0, pos + 1 + decimals), thousandSep, pointDecimal)
166
+ }
167
+
168
+ export const toPrice = numberFormat
169
+
170
+ /**
171
+ * Pads a string to a specified length with a specified string and padding type
172
+ *
173
+ * @param {string} str
174
+ * @param {number} pad_length
175
+ * @param {string} [pad_str]
176
+ * @param {string} [pad_type]
177
+ * @returns {string}
178
+ */
179
+ export const pad = function (str, pad_length, pad_str = ' ', pad_type = 'left') {
180
+ if (
181
+ isUndefined(pad_length) ||
182
+ str.length >= pad_length ||
183
+ !inArray(pad_type, ['left', 'right'])
184
+ ) {
185
+ return str
186
+ }
187
+
188
+ if (pad_type === 'left') {
189
+ return (
190
+ pad_str
191
+ .repeat(Math.ceil(pad_length / pad_str.length))
192
+ .slice(0, pad_length - str.length) + str
193
+ )
194
+ }
195
+
196
+ return (
197
+ str +
198
+ pad_str.repeat(Math.ceil(pad_length / pad_str.length)).slice(0, pad_length - str.length)
199
+ )
200
+ }
201
+
202
+ /**
203
+ * Converts RGB values to a hexadecimal color string.
204
+ *
205
+ * @param {number|number[]} r - Either an array representing a RGB color (e.g. [255, 0, 0]) or the red component as a
206
+ * number (0-255).
207
+ * @param {number} [g] - The green component (0-255). Required if `r` is a number.
208
+ * @param {number} [b] - The blue component (0-255). Required if `r` is a number.
209
+ * @returns {string} The hexadecimal color string (e.g., 'FF0000').
210
+ *
211
+ * @example
212
+ * // Using separate RGB components
213
+ * rgb2hex(255, 0, 0); // Returns 'FF0000'
214
+ *
215
+ * @example
216
+ * // Using an array of RGB components
217
+ * rgb2hex([255, 0, 0]); // Returns 'FF0000'
218
+ */
219
+ export const rgb2hex = function (r, g, b) {
220
+ if (isArray(r)) {
221
+ return rgb2hex(...r)
222
+ }
223
+
224
+ if (!isInteger(r) || !isInteger(g) || !isInteger(b)) return ''
225
+
226
+ return [
227
+ pad(dec2hex(parseInt(r)), 2, '0').toUpperCase(),
228
+ pad(dec2hex(parseInt(g)), 2, '0').toUpperCase(),
229
+ pad(dec2hex(parseInt(b)), 2, '0').toUpperCase(),
230
+ ].join('')
231
+ }
232
+
233
+ export const rgbtohex = rgb2hex
234
+
235
+ /**
236
+ * Converts a hexadecimal color to RGB values.
237
+ *
238
+ * @param {string} hex - The hexadecimal value (e.g #FF0000)
239
+ * @returns {number[]} The RGB color array (e.g [255, 0, 0]).
240
+ */
241
+ export const hex2rgb = function (hex) {
242
+ if (!isString(hex) || !hex.length) return []
243
+
244
+ hex = hex.slice(-6).toUpperCase()
245
+
246
+ if (hex.length < 6) {
247
+ hex = map(hex.slice(-3), (i, h) => h + '' + h).join('')
248
+ }
249
+
250
+ for (let i = 0; i < hex.length; i++) {
251
+ if (-1 === '0123456789ABCDEF'.indexOf(hex[i])) {
252
+ return []
253
+ }
254
+ }
255
+
256
+ return map(insert(hex, ',', 2).split(','), (i, h) => hex2dec(h))
257
+ }
258
+
259
+ export const hextorgb = hex2rgb
260
+
261
+ /**
262
+ * Parses a URL string into its components.
263
+ *
264
+ * @param {string} str - The URL string to be parsed.
265
+ * @returns {Object} An object containing the parsed components of the URL.
266
+ *
267
+ * @property {string} [scheme] - The scheme (protocol) of the URL (e.g., `http`, `https`).
268
+ * @property {string} [authority] - The authority part of the URL.
269
+ * @property {string} [userInfo] - The user information (e.g., `user:pass`).
270
+ * @property {string} [user] - The username from the user information.
271
+ * @property {string} [pass] - The password from the user information.
272
+ * @property {string} [host] - The host of the URL (e.g., `example.com`).
273
+ * @property {string} [port] - The port of the URL (e.g., `8080`).
274
+ * @property {string} [relative] - The relative URL.
275
+ * @property {string} [path] - The path of the URL (e.g., `/path/to/resource`).
276
+ * @property {string} [directory] - The directory of the URL path.
277
+ * @property {string} [file] - The file name from the path, if applicable.
278
+ * @property {string} [query] - The query string (e.g., `key=value&key2=value2`).
279
+ * @property {string} [fragment] - The fragment (hash) of the URL (e.g., `#section`).
280
+ */
281
+ export const parse_url = function (str) {
282
+ const key = [
283
+ 'source',
284
+ 'scheme',
285
+ 'authority',
286
+ 'userInfo',
287
+ 'user',
288
+ 'pass',
289
+ 'host',
290
+ 'port',
291
+ 'relative',
292
+ 'path',
293
+ 'directory',
294
+ 'file',
295
+ 'query',
296
+ 'fragment',
297
+ ],
298
+ parser =
299
+ // eslint-disable-next-line no-useless-escape
300
+ /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\?([^#]*))?(?:#(.*))?)/
301
+
302
+ const m = parser.exec(str)
303
+ let uri = {},
304
+ i = 14
305
+
306
+ while (i--) {
307
+ if (m[i]) {
308
+ uri[key[i]] = m[i]
309
+ }
310
+ }
311
+
312
+ delete uri.source
313
+ return uri
314
+ }
315
+
316
+ /**
317
+ * Adds or updates one or more query parameters to a given URL.
318
+ *
319
+ * @param {string} url - The URL to which the parameters should be added.
320
+ * @param {string|Object} param - The key of the parameter to add, or an object containing multiple key-value pairs to add.
321
+ * @param {string|null} [value=null] - The value of the parameter to add. Ignored if `param` is an object.
322
+ * @returns {string} The updated URL with the new query parameters.
323
+ *
324
+ * @example <caption>Add a single parameter to a URL without a query string</caption>
325
+ * addUrlParam('https://example.com', 'key', 'value');
326
+ * // Returns: 'https://example.com?key=value'
327
+ *
328
+ * @example <caption>Add multiple parameters to a URL</caption>
329
+ * addUrlParam('https://example.com', { key1: 'value1', key2: 'value2' });
330
+ * // Returns: 'https://example.com?key1=value1&key2=value2'
331
+ */
332
+ export const addUrlParam = function (url, param, value = null) {
333
+ if (isPlainObject(param)) {
334
+ each(param, (key, val) => {
335
+ url = addUrlParam(url, key, val)
336
+ })
337
+
338
+ return url
339
+ }
340
+
341
+ let parseUrl = parse_url(url),
342
+ pos,
343
+ hash = ''
344
+
345
+ if ((pos = url.indexOf('#')) > -1) {
346
+ hash = url.slice(pos)
347
+ url = url.slice(0, pos)
348
+ }
349
+
350
+ const key = encodeURIComponent(param)
351
+ const val = value === null ? '' : encodeURIComponent(value)
352
+
353
+ if (!parseUrl.query) {
354
+ return url + '?' + key + '=' + val + hash
355
+ }
356
+
357
+ const params = parseUrl.query.split('&')
358
+ let param_exists = false
359
+
360
+ for (let i = 0; i < params.length; i++) {
361
+ if (params[i].startsWith(key + '=')) {
362
+ params[i] = key + '=' + val
363
+ param_exists = true
364
+ break
365
+ }
366
+ }
367
+
368
+ if (!param_exists) {
369
+ params.push(key + '=' + val)
370
+ }
371
+
372
+ if (parseUrl.scheme && parseUrl.host) {
373
+ return (
374
+ parseUrl.scheme +
375
+ '://' +
376
+ parseUrl.host +
377
+ (parseUrl.path || '') +
378
+ '?' +
379
+ params.join('&') +
380
+ hash
381
+ )
382
+ }
383
+
384
+ return (parseUrl.host || '') + parseUrl.path + '?' + params.join('&') + hash
385
+ }
386
+
387
+ export const decodeHtml = function (str) {
388
+ if (!isString(str)) return ''
389
+
390
+ return str
391
+ .replace(/&amp;/g, '&')
392
+ .replace(/&lt;/g, '<')
393
+ .replace(/&gt;/g, '>')
394
+ .replace(/&quot;/g, '"')
395
+ .replace(/&#039;/g, "'")
396
+ }
397
+
398
+ export const htmlquotes = function (str) {
399
+ if (!isString(str)) return ''
400
+
401
+ return str.replace(/"/g, '&quot;').replace(/'/g, '&#039;')
402
+ }
403
+
404
+ export const htmlsimplequotes = function (str) {
405
+ if (!isString(str)) return ''
406
+
407
+ return str.replace(/'/g, '&#039;')
408
+ }
409
+
410
+ export const repeat = function (str, n) {
411
+ if (!isString(str) || !isFloat(n)) return ''
412
+
413
+ return new Array(Math.floor(n) + 1).join(str)
414
+ }
415
+
416
+ export const stripTags = function (str, tag) {
417
+ if (isString(tag)) {
418
+ const rStripTags = new RegExp(`<${tag}[^>]*>(.*?)</${tag}>|<${tag}[^>]*/>`, 'ig')
419
+
420
+ while (rStripTags.test(str)) str = str.replace(rStripTags, '$1')
421
+
422
+ return str
423
+ }
424
+
425
+ return str.replace(/(<([^>]+)>)/gi, '')
426
+ }
427
+
428
+ export const toUrl = function (str) {
429
+ return trim(
430
+ noAccent(str)
431
+ .toLowerCase()
432
+ .replace(/[^a-z0-9]/g, '-')
433
+ .replace(/-{2,}/g, '-'),
434
+ '-',
435
+ )
436
+ }
437
+
438
+ /**
439
+ * @see http://stackoverflow.com/questions/3115150/how-to-escape-regular-expression-special-characters-using-javascript
440
+ */
441
+ export const escapeRegex = function (str) {
442
+ return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&').replace(/[\n\t]/g, ' ')
443
+ }
444
+
445
+ export const camelCase = function (str) {
446
+ if (!str) return ''
447
+
448
+ let prev = ''
449
+ let prevReplaced = false
450
+ let prevIsSeparator = false
451
+ let prevIsUpperCase = false
452
+
453
+ str = trim(str)
454
+ str = trim(str, '_')
455
+ str = trim(str, '-')
456
+
457
+ const isUpperCase = (c) => c === c.toUpperCase() && c !== c.toLowerCase()
458
+ const isSeparator = (c) => c === '-' || c === '_' || c === ' '
459
+
460
+ return map(str, (i, c) => {
461
+ prevIsSeparator = isSeparator(prev)
462
+ prevIsUpperCase = isUpperCase(prev)
463
+ prev = c
464
+
465
+ if (isSeparator(c)) {
466
+ return null
467
+ } else if (prevIsSeparator) {
468
+ c = c.toUpperCase()
469
+ prevReplaced = true
470
+ } else if (isUpperCase(c)) {
471
+ if (i === 0) {
472
+ c = c.toLowerCase()
473
+ } else if (prevIsUpperCase && !prevReplaced) {
474
+ c = c.toLowerCase()
475
+ }
476
+
477
+ prevReplaced = false
478
+ } else {
479
+ prevReplaced = false
480
+ }
481
+
482
+ return c
483
+ }).join('')
484
+ }
485
+
486
+ export const format = function (str, ...args) {
487
+ if (args.length) {
488
+ each(args, (i, arg) => {
489
+ if (isString(arg)) {
490
+ const o = {}
491
+ o[i] = arg
492
+ arg = o
493
+ }
494
+
495
+ each(arg, (placeholder, replacement) => {
496
+ str = str.replace(new RegExp('\\{' + placeholder + '\\}', 'gm'), (match) =>
497
+ isUndefined(replacement) ? match : replacement,
498
+ )
499
+ })
500
+ })
501
+ }
502
+
503
+ return str
504
+ }
505
+
506
+ export const f = format
507
+
508
+ /**
509
+ * @see https://stackoverflow.com/questions/7627000/javascript-convert-string-to-safe-class-name-for-css
510
+ */
511
+ export const toCssClassName = function (str) {
512
+ return str.replace(/[^a-z0-9_-]/gi, (s) => {
513
+ const c = s.charCodeAt(0)
514
+ if (c === 32) return '-'
515
+ return '__' + ('000' + c.toString(16)).slice(-4)
516
+ })
517
+ }
518
+
519
+ export const hilite = function (str, req, tag = 'strong') {
520
+ str = decodeHtml(str)
521
+ let str_folded = noAccent(str)
522
+ .toLowerCase()
523
+ .replace(/[[\]]+/g, '')
524
+ let q_folded,
525
+ re,
526
+ hilite_hints = ''
527
+
528
+ if (!isArray(req)) {
529
+ req = [req]
530
+ }
531
+
532
+ each(req, (i, q) => {
533
+ if (q.length) {
534
+ q = decodeHtml(q)
535
+ q_folded = noAccent(q)
536
+ .toLowerCase()
537
+ .replace(/[[\]]+/g, '')
538
+
539
+ re = new RegExp(escapeRegex(q_folded), 'g')
540
+ hilite_hints = str_folded.replace(re, `[${q_folded}]`)
541
+
542
+ str_folded = hilite_hints
543
+ }
544
+ })
545
+
546
+ if (!hilite_hints.length) {
547
+ return str
548
+ }
549
+
550
+ let spos = 0
551
+ let highlighted = ''
552
+ let dirHook = 'end'
553
+
554
+ each(hilite_hints, (i, hint) => {
555
+ const c = str.charAt(spos)
556
+
557
+ if (hint === '[' && dirHook === 'end') {
558
+ highlighted += `<${tag}>`
559
+ dirHook = 'start'
560
+ } else if (hint === ']' && dirHook === 'start') {
561
+ highlighted += `</${tag}>`
562
+ dirHook = 'end'
563
+ } else {
564
+ spos += 1
565
+ highlighted += c
566
+ }
567
+ })
568
+
569
+ return highlighted
570
+ .replace(/</g, '&lt;')
571
+ .replace(/>/g, '&gt;')
572
+ .replace(new RegExp(`&lt;${tag}&gt;`, 'g'), `<${tag}>`)
573
+ .replace(new RegExp(`&lt;/${tag}&gt;`, 'g'), `</${tag}>`)
574
+ .replace(new RegExp('&lt;br&gt;', 'g'), '<br>')
575
+ }
576
+
577
+ export const formatSize = function (bytes, decimalPoint = ',') {
578
+ let i = -1,
579
+ decimals = 0
580
+
581
+ do {
582
+ bytes /= 1024
583
+ i++
584
+ } while (bytes > 999)
585
+
586
+ if (!isInteger(bytes)) {
587
+ decimals = 1
588
+ }
589
+
590
+ const units = map(['k', 'M', 'G', 'T', 'P', 'E'], (i, prefix) => {
591
+ return prefix + 'B'
592
+ })
593
+
594
+ return numberFormat(Math.max(bytes, 0), decimals, true, '', decimalPoint) + ' ' + units[i]
595
+ }
596
+
597
+ export const compareMixAlphaDigits = (a, b) => {
598
+ if (a === b) return 0
599
+
600
+ if (isInteger(a) && isInteger(b)) {
601
+ return Math.sign(a - b)
602
+ }
603
+
604
+ let startEq = ''
605
+
606
+ for (let i = 0; i < Math.min(a.length, b.length); i++) {
607
+ if (a.charAt(i) === b.charAt(i) && !isInteger(a)) {
608
+ startEq += a.charAt(i)
609
+ } else {
610
+ break
611
+ }
612
+ }
613
+
614
+ a = a.slice(startEq.length)
615
+ b = b.slice(startEq.length)
616
+
617
+ let nbA = ''
618
+ let idxDigitA = null
619
+
620
+ each(a, (i, c) => {
621
+ if (!nbA) {
622
+ idxDigitA = i
623
+ if (c >= '0' && c <= '9') {
624
+ nbA += c
625
+ }
626
+ } else {
627
+ if (c >= '0' && c <= '9') {
628
+ nbA += c
629
+ return true
630
+ }
631
+
632
+ return false
633
+ }
634
+ })
635
+
636
+ let nbB = ''
637
+ let idxDigitB = null
638
+
639
+ each(b, (i, c) => {
640
+ if (!nbB) {
641
+ idxDigitB = i
642
+ if (c >= '0' && c <= '9') {
643
+ nbB += c
644
+ }
645
+ } else {
646
+ if (c >= '0' && c <= '9') {
647
+ nbB += c
648
+ return true
649
+ }
650
+
651
+ return false
652
+ }
653
+ })
654
+
655
+ if (nbA.length && nbB.length && idxDigitA === idxDigitB) {
656
+ if (a.substring(0, idxDigitA) === b.substring(0, idxDigitB)) {
657
+ return Math.sign(nbA - nbB)
658
+ }
659
+ }
660
+
661
+ return a > b ? 1 : -1
662
+ }
@@ -0,0 +1,16 @@
1
+ import { foreach } from './traversal.js'
2
+ import * as stringFunctions from './string.js'
3
+
4
+ foreach(Object.keys(stringFunctions), (name) => {
5
+ const f = stringFunctions[name],
6
+ p = String.prototype
7
+
8
+ const origSF = p[name]
9
+ p[name] = function (...args) {
10
+ if (origSF && args.length === origSF.length) {
11
+ return origSF.apply(this, args)
12
+ }
13
+
14
+ return f(this, ...args)
15
+ }
16
+ })