expensify-common 2.0.8 → 2.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/str.js CHANGED
@@ -27,19 +27,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  /* eslint-disable no-control-regex */
30
- const underscore_1 = __importDefault(require("underscore"));
30
+ const escape_1 = __importDefault(require("lodash/escape"));
31
+ const unescape_1 = __importDefault(require("lodash/unescape"));
31
32
  const awesome_phonenumber_1 = require("awesome-phonenumber");
32
33
  const HtmlEntities = __importStar(require("html-entities"));
33
34
  const Constants = __importStar(require("./CONST"));
34
35
  const UrlPatterns = __importStar(require("./Url"));
35
36
  const REMOVE_SMS_DOMAIN_PATTERN = /@expensify\.sms/gi;
37
+ function resultFn(parameter, ...args) {
38
+ if (typeof parameter === 'function') {
39
+ return parameter(...args);
40
+ }
41
+ return parameter;
42
+ }
36
43
  const Str = {
37
44
  /**
38
45
  * Return true if the string is ending with the provided suffix
39
46
  *
40
- * @param {String} str String ot search in
41
- * @param {String} suffix What to look for
42
- * @return {Boolean}
47
+ * @param str String ot search in
48
+ * @param suffix What to look for
43
49
  */
44
50
  endsWith(str, suffix) {
45
51
  if (!str || !suffix) {
@@ -50,11 +56,11 @@ const Str = {
50
56
  /**
51
57
  * Converts a USD string into th number of cents it represents.
52
58
  *
53
- * @param {String} amountStr A string representing a USD value.
54
- * @param {Boolean} allowFraction Flag indicating if fractions of cents should be
59
+ * @param amountStr A string representing a USD value.
60
+ * @param allowFraction Flag indicating if fractions of cents should be
55
61
  * allowed in the output.
56
62
  *
57
- * @return {Number} The cent value of the @p amountStr.
63
+ * @returns The cent value of the @p amountStr.
58
64
  */
59
65
  fromUSDToNumber(amountStr, allowFraction) {
60
66
  let amount = String(amountStr).replace(/[^\d.\-()]+/g, '');
@@ -63,20 +69,11 @@ const Str = {
63
69
  amount = `-${modifiedAmount}`;
64
70
  }
65
71
  amount = Number(amount) * 100;
66
- // We round it here to a precision of 3 because some floating point numbers, when multiplied by 100
67
- // don't give us a very pretty result. Try this in the JS console:
68
- // 0.678 * 100
69
- // 67.80000000000001
70
- // 0.679 * 100
71
- // 67.9
72
72
  amount = Math.round(amount * 1e3) / 1e3;
73
73
  return allowFraction ? amount : Math.round(amount);
74
74
  },
75
75
  /**
76
76
  * Truncates the middle section of a string based on the max allowed length
77
- * @param {string} fullStr
78
- * @param {int} maxLength
79
- * @returns {string}
80
77
  */
81
78
  truncateInMiddle(fullStr, maxLength) {
82
79
  if (fullStr.length <= maxLength) {
@@ -90,9 +87,6 @@ const Str = {
90
87
  },
91
88
  /**
92
89
  * Convert new line to <br />
93
- *
94
- * @param {String} str
95
- * @returns {string}
96
90
  */
97
91
  nl2br(str) {
98
92
  return str.replace(/\n/g, '<br />');
@@ -100,8 +94,8 @@ const Str = {
100
94
  /**
101
95
  * Decodes the given HTML encoded string.
102
96
  *
103
- * @param {String} s The string to decode.
104
- * @return {String} The decoded string.
97
+ * @param s The string to decode.
98
+ * @returns The decoded string.
105
99
  */
106
100
  htmlDecode(s) {
107
101
  // Use jQuery if it exists or else use html-entities
@@ -113,8 +107,8 @@ const Str = {
113
107
  /**
114
108
  * HTML encodes the given string.
115
109
  *
116
- * @param {String} s The string to encode.
117
- * @return {String} @p s HTML encoded.
110
+ * @param s The string to encode.
111
+ * @return string @p s HTML encoded.
118
112
  */
119
113
  htmlEncode(s) {
120
114
  // Use jQuery if it exists or else use html-entities
@@ -126,18 +120,18 @@ const Str = {
126
120
  /**
127
121
  * Escape text while preventing any sort of double escape, so 'X & Y' -> 'X &amp; Y' and 'X &amp; Y' -> 'X &amp; Y'
128
122
  *
129
- * @param {String} s the string to escape
130
- * @return {String} the escaped string
123
+ * @param s The string to escape
124
+ * @returns The escaped string
131
125
  */
132
126
  safeEscape(s) {
133
- return underscore_1.default.escape(underscore_1.default.unescape(s));
127
+ return (0, escape_1.default)((0, unescape_1.default)(s));
134
128
  },
135
129
  /**
136
130
  * HTML encoding insensitive equals.
137
131
  *
138
- * @param {String} first string to compare
139
- * @param {String} second string to compare
140
- * @return {Boolean} true when first === second, ignoring HTML encoding
132
+ * @param first string to compare
133
+ * @param second string to compare
134
+ * @returns True when first === second, ignoring HTML encoding
141
135
  */
142
136
  htmlEncodingInsensitiveEquals(first, second) {
143
137
  return first === second || this.htmlDecode(first) === second || this.htmlEncode(first) === second;
@@ -145,8 +139,8 @@ const Str = {
145
139
  /**
146
140
  * Creates an ID that can be used as an HTML attribute from @p str.
147
141
  *
148
- * @param {String} str A string to create an ID from.
149
- * @return {String} The ID string made from @p str.
142
+ * @param str A string to create an ID from.
143
+ * @returns The ID string made from @p str.
150
144
  */
151
145
  makeID(str) {
152
146
  const modifiedString = String(str)
@@ -157,19 +151,18 @@ const Str = {
157
151
  /**
158
152
  * Extracts an ID made with Str.makeID from a larger string.
159
153
  *
160
- * @param {String} str A string containing an id made with Str.makeID
161
- * @return {String|null} The ID string.
154
+ * @param str A string containing an id made with Str.makeID
155
+ * @returns The ID string.
162
156
  */
163
157
  extractID(str) {
164
158
  const matches = str.match(/id[A-Z0-9_]+/);
165
- return matches.length > 0 ? matches[0] : null;
159
+ return matches && matches.length > 0 ? matches[0] : null;
166
160
  },
167
161
  /**
168
162
  * Modifies the string so the first letter of each word is capitalized and the
169
163
  * rest lowercased.
170
164
  *
171
- * @param {String} val The string to modify
172
- * @return {String}
165
+ * @param val The string to modify
173
166
  */
174
167
  recapitalize(val) {
175
168
  // First replace every letter with its lowercase equivalent
@@ -188,26 +181,19 @@ const Str = {
188
181
  },
189
182
  /**
190
183
  * Replace all the non alphanumerical character by _
191
- *
192
- * @param {String} input
193
- * @returns {String}
194
184
  */
195
185
  sanitizeToAlphaNumeric(input) {
196
186
  return String(input).replace(/[^\d\w]/g, '_');
197
187
  },
198
188
  /**
199
189
  * Strip out all the non numerical characters
200
- *
201
- * @param {String} input
202
- * @returns {String}
203
190
  */
204
191
  stripNonNumeric(input) {
205
192
  return String(input).replace(/[^\d]/g, '');
206
193
  },
207
194
  /**
208
195
  * Strips all non ascii characters from a string
209
- * @param {String} input
210
- * @returns {String} The ascii version of the string.
196
+ * @returns The ascii version of the string.
211
197
  */
212
198
  stripNonASCIICharacters(input) {
213
199
  return String(input).replace(/[\u0000-\u0019\u0080-\uffff]/g, '');
@@ -218,9 +204,9 @@ const Str = {
218
204
  * The ellipses will only be appended if @p text is longer than the @p length
219
205
  * given.
220
206
  *
221
- * @param {String} val The string to reduce in size.
222
- * @param {Number} length The maximal length desired.
223
- * @return {String} The shortened @p text.
207
+ * @param val The string to reduce in size.
208
+ * @param length The maximal length desired.
209
+ * @returns The shortened @p text.
224
210
  */
225
211
  shortenText(val, length) {
226
212
  // Remove extra spaces because they don't show up in html anyway.
@@ -230,13 +216,13 @@ const Str = {
230
216
  },
231
217
  /**
232
218
  * Returns the byte size of a character
233
- * @param {String} inputChar You can input more than one character, but it will only return the size of the first
219
+ * @param inputChar You can input more than one character, but it will only return the size of the first
234
220
  * one.
235
- * @returns {Number} Byte size of the character
221
+ * @returns Byte size of the character
236
222
  */
237
223
  getRawByteSize(inputChar) {
238
224
  const onlyChar = String(inputChar);
239
- const c = onlyChar.charCodeAt();
225
+ const c = onlyChar.charCodeAt(0);
240
226
  // If we are grabbing the byte size, we need to temporarily diable no-bitwise for linting
241
227
  /* eslint-disable no-bitwise */
242
228
  if (c < 1 << 7) {
@@ -262,23 +248,18 @@ const Str = {
262
248
  },
263
249
  /**
264
250
  * Gets the length of a string in bytes, including non-ASCII characters
265
- * @param {String} input
266
- * @returns {Number} The number of bytes used by string
251
+ * @returns The number of bytes used by string
267
252
  */
268
253
  getByteLength(input) {
269
254
  // Force string type
270
255
  const stringInput = String(input);
271
- let byteLength = 0;
272
- for (let i = 0; i < stringInput.length; i++) {
273
- byteLength += this.getRawByteSize(stringInput[i]);
274
- }
256
+ const byteLength = Array.from(stringInput).reduce((acc, char) => acc + this.getRawByteSize(char), 0);
275
257
  return byteLength;
276
258
  },
277
259
  /**
278
260
  * Shortens the input by max byte size instead of by character length
279
- * @param {String} input
280
- * @param {Number} maxSize The max size in bytes, e.g. 256
281
- * @returns {String} Returns a shorted input if the input size exceeds the max
261
+ * @param maxSize The max size in bytes, e.g. 256
262
+ * @returns Returns a shorted input if the input size exceeds the max
282
263
  */
283
264
  shortenByByte(input, maxSize) {
284
265
  const stringInput = String(input);
@@ -296,9 +277,9 @@ const Str = {
296
277
  /**
297
278
  * Returns true if the haystack begins with the needle
298
279
  *
299
- * @param {String} haystack The full string to be searched
300
- * @param {String} needle The case-sensitive string to search for
301
- * @return {Boolean} Retruns true if the haystack starts with the needle.
280
+ * @param haystack The full string to be searched
281
+ * @param needle The case-sensitive string to search for
282
+ * @returns True if the haystack starts with the needle.
302
283
  */
303
284
  startsWith(haystack, needle) {
304
285
  return this.isString(haystack) && this.isString(needle) && haystack.substring(0, needle.length) === needle;
@@ -306,8 +287,8 @@ const Str = {
306
287
  /**
307
288
  * Gets the textual value of the given string.
308
289
  *
309
- * @param {String} str The string to fetch the text value from.
310
- * @return {String} The text from within the HTML string.
290
+ * @param str The string to fetch the text value from.
291
+ * @returns The text from within the HTML string.
311
292
  */
312
293
  stripHTML(str) {
313
294
  if (!this.isString(str)) {
@@ -318,8 +299,8 @@ const Str = {
318
299
  /**
319
300
  * Modifies the string so the first letter of the string is capitalized
320
301
  *
321
- * @param {String} str The string to modify.
322
- * @return {String} The recapitalized string.
302
+ * @param str The string to modify.
303
+ * @returns The recapitalized string.
323
304
  */
324
305
  UCFirst(str) {
325
306
  return str.substr(0, 1).toUpperCase() + str.substr(1);
@@ -329,9 +310,9 @@ const Str = {
329
310
  * of str to the first occurrence of substr.
330
311
  * Example: Str.cutAfter( 'hello$%world', '$%' ) // returns 'hello'
331
312
  *
332
- * @param {String} str The string to modify.
333
- * @param {String} substr The substring to search for.
334
- * @return {String} The cut/trimmed string.
313
+ * @param str The string to modify.
314
+ * @param substr The substring to search for.
315
+ * @returns The cut/trimmed string.
335
316
  */
336
317
  cutAfter(str, substr) {
337
318
  const index = str.indexOf(substr);
@@ -345,9 +326,9 @@ const Str = {
345
326
  * occurrence of substr to the end of the string.
346
327
  * Example: Str.cutBefore( 'hello$%world', '$%' ) // returns 'world'
347
328
  *
348
- * @param {String} str The string to modify.
349
- * @param {String} substr The substring to search for.
350
- * @return {String} The cut/trimmed string.
329
+ * @param str The string to modify.
330
+ * @param substr The substring to search for.
331
+ * @returns The cut/trimmed string.
351
332
  */
352
333
  cutBefore(str, substr) {
353
334
  const index = str.indexOf(substr);
@@ -359,60 +340,58 @@ const Str = {
359
340
  /**
360
341
  * Checks that the string is a domain name (e.g. example.com)
361
342
  *
362
- * @param {String} string The string to check for domainnameness.
343
+ * @param str The string to check for domainnameness.
363
344
  *
364
- * @returns {Boolean} True iff the string is a domain name
345
+ * @returns True if the string is a domain name
365
346
  */
366
- isValidDomainName(string) {
367
- return Boolean(String(string).match(Constants.CONST.REG_EXP.DOMAIN));
347
+ isValidDomainName(str) {
348
+ return Boolean(String(str).match(Constants.CONST.REG_EXP.DOMAIN));
368
349
  },
369
350
  /**
370
351
  * Checks that the string is a valid url
371
352
  *
372
- * @param {String} string
373
- *
374
- * @returns {Boolean} True if the string is a valid hyperlink
353
+ * @returns True if the string is a valid hyperlink
375
354
  */
376
- isValidURL(string) {
377
- return Boolean(String(string).match(Constants.CONST.REG_EXP.HYPERLINK));
355
+ isValidURL(str) {
356
+ return Boolean(String(str).match(Constants.CONST.REG_EXP.HYPERLINK));
378
357
  },
379
358
  /**
380
359
  * Checks that the string is an email address.
381
360
  * NOTE: TLDs are not just 2-4 characters. Keep this in sync with _inputrules.php
382
361
  *
383
- * @param {String} string The string to check for email validity.
362
+ * @param str The string to check for email validity.
384
363
  *
385
- * @returns {Boolean} True iff the string is an email
364
+ * @returns True if the string is an email
386
365
  */
387
- isValidEmail(string) {
388
- return Boolean(String(string).match(Constants.CONST.REG_EXP.EMAIL));
366
+ isValidEmail(str) {
367
+ return Boolean(String(str).match(Constants.CONST.REG_EXP.EMAIL));
389
368
  },
390
369
  /**
391
370
  * Checks if the string is an valid email address formed during comment markdown formation.
392
371
  *
393
- * @param {String} string The string to check for email validity.
372
+ * @param str The string to check for email validity.
394
373
  *
395
- * @returns {Boolean} True if the string is an valid email created by comment markdown.
374
+ * @returns True if the string is an valid email created by comment markdown.
396
375
  */
397
- isValidEmailMarkdown(string) {
398
- return Boolean(String(string).match(`^${Constants.CONST.REG_EXP.MARKDOWN_EMAIL}$`));
376
+ isValidEmailMarkdown(str) {
377
+ return Boolean(String(str).match(`^${Constants.CONST.REG_EXP.MARKDOWN_EMAIL}$`));
399
378
  },
400
379
  /**
401
380
  * Remove trailing comma from a string.
402
381
  *
403
- * @param {String} string The string with any trailing comma to be removed.
382
+ * @param str The string with any trailing comma to be removed.
404
383
  *
405
- * @returns {String} string with the trailing comma removed
384
+ * @returns string with the trailing comma removed
406
385
  */
407
- removeTrailingComma(string) {
408
- return string.trim().replace(/(,$)/g, '');
386
+ removeTrailingComma(str) {
387
+ return str.trim().replace(/(,$)/g, '');
409
388
  },
410
389
  /**
411
390
  * Checks that the string is a list of coma separated email addresss.
412
391
  *
413
- * @param {String} str The string to check for emails validity.
392
+ * @param str The string to check for emails validity.
414
393
  *
415
- * @returns {Boolean} True if all emails are valid or if input is empty
394
+ * @returns True if all emails are valid or if input is empty
416
395
  */
417
396
  areValidEmails(str) {
418
397
  const string = this.removeTrailingComma(str);
@@ -420,30 +399,22 @@ const Str = {
420
399
  return true;
421
400
  }
422
401
  const emails = string.split(',');
423
- let result = true;
424
- for (let i = 0; i < emails.length; i += 1) {
425
- if (!this.isValidEmail(emails[i].trim())) {
426
- result = false;
427
- }
428
- }
402
+ const result = emails.every((email) => this.isValidEmail(email.trim()));
429
403
  return result;
430
404
  },
431
405
  /**
432
406
  * Extract the email addresses from a string
433
- *
434
- * @param {String} string
435
- * @returns {String[]|null}
436
407
  */
437
- extractEmail(string) {
438
- return String(string).match(Constants.CONST.REG_EXP.EMAIL_SEARCH);
408
+ extractEmail(str) {
409
+ return String(str).match(Constants.CONST.REG_EXP.EMAIL_SEARCH);
439
410
  },
440
411
  /**
441
412
  * Extracts the domain name from the given email address
442
413
  * (e.g. "domain.com" for "joe@domain.com").
443
414
  *
444
- * @param {String} email The email address.
415
+ * @param email The email address.
445
416
  *
446
- * @returns {String} The domain name in the email address.
417
+ * @returns The domain name in the email address.
447
418
  */
448
419
  extractEmailDomain(email) {
449
420
  return this.cutBefore(email, '@');
@@ -452,9 +423,9 @@ const Str = {
452
423
  * Tries to extract the company name from the given email address
453
424
  * (e.g. "yelp" for "joe@yelp.co.uk").
454
425
  *
455
- * @param {String} email The email address.
426
+ * @param email The email address.
456
427
  *
457
- * @returns {String|null} The company name in the email address or null.
428
+ * @returns The company name in the email address or null.
458
429
  */
459
430
  extractCompanyNameFromEmailDomain(email) {
460
431
  const domain = this.extractEmailDomain(email);
@@ -471,18 +442,15 @@ const Str = {
471
442
  * Extracts the local part from the given email address
472
443
  * (e.g. "joe" for "joe@domain.com").
473
444
  *
474
- * @param {String} email The email address.
445
+ * @param email The email address.
475
446
  *
476
- * @returns {String} The local part in the email address.
447
+ * @returns The local part in the email address.
477
448
  */
478
449
  extractEmailLocalPart(email) {
479
450
  return this.cutAfter(email, '@');
480
451
  },
481
452
  /**
482
453
  * Sanitize phone number to return only numbers. Return null if non valid phone number.
483
- *
484
- * @param {String} str
485
- * @returns {String|null}
486
454
  */
487
455
  sanitizePhoneNumber(str) {
488
456
  const string = str.replace(/(?!^\+)\D/g, '');
@@ -490,9 +458,6 @@ const Str = {
490
458
  },
491
459
  /**
492
460
  * Sanitize email. Return null if non valid email.
493
- *
494
- * @param {String} str
495
- * @returns {String|null}
496
461
  */
497
462
  sanitizeEmail(str) {
498
463
  const string = str.toLowerCase().trim();
@@ -501,59 +466,52 @@ const Str = {
501
466
  /**
502
467
  * Escapes all special RegExp characters from a string
503
468
  *
504
- * @param {String} string The subject
469
+ * @param str The subject
505
470
  *
506
- * @returns {String} The escaped string
471
+ * @returns The escaped string
507
472
  */
508
- escapeForRegExp(string) {
509
- return string.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
473
+ escapeForRegExp(str) {
474
+ return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
510
475
  },
511
476
  /**
512
477
  * Escapes all special RegExp characters from a string except for the period
513
478
  *
514
- * @param {String} string The subject
515
- * @returns {String} The escaped string
479
+ * @param str The subject
480
+ * @returns The escaped string
516
481
  */
517
- escapeForExpenseRule(string) {
518
- return string.replace(/[-[\]/{}()*+?\\^$|]/g, '\\$&');
482
+ escapeForExpenseRule(str) {
483
+ return str.replace(/[-[\]/{}()*+?\\^$|]/g, '\\$&');
519
484
  },
520
485
  /**
521
486
  * Adds a backslash in front of each of colon
522
487
  * if they don't already have a backslash in front of them
523
488
  *
524
- * @param {String} string The subject
525
- * @returns {String} The escaped string
489
+ * @param str The subject
490
+ * @returns The escaped string
526
491
  */
527
- addBackslashBeforeColonsForTagNamesComingFromQBD(string) {
528
- return string.replace(/([^\\]):/g, '$1\\:');
492
+ addBackslashBeforeColonsForTagNamesComingFromQBD(str) {
493
+ return str.replace(/([^\\]):/g, '$1\\:');
529
494
  },
530
495
  /**
531
496
  * Removes backslashes from string
532
497
  * eg: myString\[\]\* -> myString[]*
533
- *
534
- * @param {String} string
535
- * @returns {String}
536
498
  */
537
- stripBackslashes(string) {
538
- return string.replace(/\\/g, '');
499
+ stripBackslashes(str) {
500
+ return str.replace(/\\/g, '');
539
501
  },
540
502
  /**
541
503
  * Checks if a string's length is in the specified range
542
504
  *
543
- * @param {String} string The subject
544
- * @param {Number} minimumLength
545
- * @param {Number} [maximumLength]
546
- *
547
- * @returns {Boolean} true if the length is in the range, false otherwise
505
+ * @returns true if the length is in the range, false otherwise
548
506
  */
549
- isOfLength(string, minimumLength, maximumLength) {
550
- if (!this.isString(string)) {
507
+ isOfLength(str, minimumLength, maximumLength) {
508
+ if (!this.isString(str)) {
551
509
  return false;
552
510
  }
553
- if (string.length < minimumLength) {
511
+ if (str.length < minimumLength) {
554
512
  return false;
555
513
  }
556
- if (!this.isUndefined(maximumLength) && string.length > maximumLength) {
514
+ if (!this.isUndefined(maximumLength) && str.length > maximumLength) {
557
515
  return false;
558
516
  }
559
517
  return true;
@@ -563,11 +521,11 @@ const Str = {
563
521
  * This is faster than counting the results of haystack.match( /needle/g )
564
522
  * via http://stackoverflow.com/questions/4009756/how-to-count-string-occurrence-in-string
565
523
  *
566
- * @param {String} haystack The string to look inside of
567
- * @param {String} needle What we're looking for
568
- * @param {Boolean} allowOverlapping Defaults to false
524
+ * @param haystack The string to look inside of
525
+ * @param needle What we're looking for
526
+ * @param allowOverlapping Defaults to false
569
527
  *
570
- * @returns {Integer} The number of times needle is in haystack.
528
+ * @returns The number of times needle is in haystack.
571
529
  */
572
530
  occurences(haystack, needle, allowOverlapping) {
573
531
  let count = 0;
@@ -592,8 +550,8 @@ const Str = {
592
550
  * Uppercases the first letter of each word
593
551
  * via https://github.com/kvz/phpjs/blob/master/functions/strings/ucwords.js
594
552
  *
595
- * @param {String} str to uppercase words
596
- * @returns {String} Uppercase worded string
553
+ * @param str to uppercase words
554
+ * @returns Uppercase worded string
597
555
  */
598
556
  ucwords(str) {
599
557
  const capitalize = ($1) => $1.toUpperCase();
@@ -602,10 +560,10 @@ const Str = {
602
560
  /**
603
561
  * Returns true if the haystack contains the needle
604
562
  *
605
- * @param {String} haystack The full string to be searched
606
- * @param {String} needle The case-sensitive string to search for
563
+ * @param haystack The full string to be searched
564
+ * @param needle The case-sensitive string to search for
607
565
  *
608
- * @return {Boolean} Retruns true if the haystack contains the needle
566
+ * @returns Returns true if the haystack contains the needle
609
567
  */
610
568
  contains(haystack, needle) {
611
569
  return haystack.indexOf(needle) !== -1;
@@ -613,10 +571,10 @@ const Str = {
613
571
  /**
614
572
  * Returns true if the haystack contains the needle, ignoring case
615
573
  *
616
- * @param {String} haystack The full string to be searched
617
- * @param {String} needle The case-insensitive string to search for
574
+ * @param haystack The full string to be searched
575
+ * @param needle The case-insensitive string to search for
618
576
  *
619
- * @return {Boolean} Retruns true if the haystack contains the needle, ignoring case
577
+ * @returns Returns true if the haystack contains the needle, ignoring case
620
578
  */
621
579
  caseInsensitiveContains(haystack, needle) {
622
580
  return this.contains(haystack.toLowerCase(), needle.toLowerCase());
@@ -624,67 +582,66 @@ const Str = {
624
582
  /**
625
583
  * Case insensitive compare function
626
584
  *
627
- * @param {String} string1 string to compare
628
- * @param {String} string2 string to compare
585
+ * @param strA string to compare
586
+ * @param strB string to compare
629
587
  *
630
- * @return {Number} -1 if first string < second string
588
+ * @returns -1 if first string < second string
631
589
  * 1 if first string > second string
632
590
  * 0 if first string = second string
633
591
  */
634
- caseInsensitiveCompare(string1, string2) {
635
- const lowerCase1 = string1.toLocaleLowerCase();
636
- const lowerCase2 = string2.toLocaleLowerCase();
637
- return this.compare(lowerCase1, lowerCase2);
592
+ caseInsensitiveCompare(strA, strB) {
593
+ const lowerCaseStrA = strA.toLocaleLowerCase();
594
+ const lowerCaseStrB = strB.toLocaleLowerCase();
595
+ return this.compare(lowerCaseStrA, lowerCaseStrB);
638
596
  },
639
597
  /**
640
598
  * Case insensitive equals
641
599
  *
642
- * @param {String} first string to compare
643
- * @param {String} second string to compare
644
- * @return {Boolean} true when first == second except for case
600
+ * @param strA string to compare
601
+ * @param strB string to compare
602
+ * @returns true when first == second except for case
645
603
  */
646
- caseInsensitiveEquals(first, second) {
647
- return this.caseInsensitiveCompare(first, second) === 0;
604
+ caseInsensitiveEquals(strA, strB) {
605
+ return this.caseInsensitiveCompare(strA, strB) === 0;
648
606
  },
649
607
  /**
650
608
  * Compare function
651
609
  *
652
- * @param {String} string1 string to compare
653
- * @param {String} string2 string to compare
610
+ * @param strA string to compare
611
+ * @param strB string to compare
654
612
  *
655
- * @return {Number} -1 if first string < second string
613
+ * @returns -1 if first string < second string
656
614
  * 1 if first string > second string
657
615
  * 0 if first string = second string
658
616
  */
659
- compare(string1, string2) {
660
- if (string1 < string2) {
617
+ compare(strA, strB) {
618
+ if (strA < strB) {
661
619
  return -1;
662
620
  }
663
- if (string1 > string2) {
621
+ if (strA > strB) {
664
622
  return 1;
665
623
  }
666
624
  return 0;
667
625
  },
668
626
  /**
669
627
  * Check if a file extension is supported by SmartReports
670
- * @param {String} filename
671
- * @return {Boolean}
672
628
  */
673
629
  isFileExtensionSmartReportsValid(filename) {
630
+ var _a;
674
631
  // Allowed extensions. Make sure to keep them in sync with those defined
675
632
  // in SmartReport_Utils::templateFileUploadCheck()
676
633
  const allowedExtensions = ['xls', 'xlsx', 'xlsm', 'xltm'];
677
- const extension = filename.split('.').pop().toLowerCase();
678
- return allowedExtensions.indexOf(extension) > -1;
634
+ const extension = (_a = filename.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
635
+ return !!extension && allowedExtensions.indexOf(extension) > -1;
679
636
  },
680
637
  /**
681
638
  * Mask Permanent Account Number (PAN) the same way Auth does
682
- * @param {Number|String} number account number
683
- * @return {String} masked account number
639
+ * @param num account number
640
+ * @returns masked account number
684
641
  */
685
- maskPAN(number) {
642
+ maskPAN(num) {
686
643
  // cast to string
687
- const accountNumber = String(number);
644
+ const accountNumber = String(num);
688
645
  const len = accountNumber.length;
689
646
  // Hide these numbers completely
690
647
  // We should not be getting account numbers this small or large
@@ -704,8 +661,6 @@ const Str = {
704
661
  /**
705
662
  * Checks if something is a string
706
663
  * Stolen from underscore
707
- * @param {Mixed} obj
708
- * @return {Boolean}
709
664
  */
710
665
  isString(obj) {
711
666
  return this.isTypeOf(obj, 'String');
@@ -713,8 +668,7 @@ const Str = {
713
668
  /**
714
669
  * Checks if something is a number
715
670
  * Stolen from underscore
716
- * @param {Mixed} obj
717
- * @return {Boolean}
671
+ * @param obj
718
672
  */
719
673
  isNumber(obj) {
720
674
  return this.isTypeOf(obj, 'Number');
@@ -722,10 +676,6 @@ const Str = {
722
676
  /**
723
677
  * Checks if something is a certain type
724
678
  * Stolen from underscore
725
- * @param {Mixed} obj
726
- * @param {String} type one of ['Arguments', 'Function', 'String', 'Number', 'Date',
727
- * 'RegExp', 'Error', 'Symbol', 'Map', 'WeakMap', 'Set', 'WeakSet']
728
- * @return {Boolean}
729
679
  */
730
680
  isTypeOf(obj, type) {
731
681
  return Object.prototype.toString.call(obj) === `[object ${type}]`;
@@ -733,8 +683,6 @@ const Str = {
733
683
  /**
734
684
  * Checks to see if something is undefined
735
685
  * Stolen from underscore
736
- * @param {Mixed} obj
737
- * @return {Boolean}
738
686
  */
739
687
  isUndefined(obj) {
740
688
  // eslint-disable-next-line no-void
@@ -743,40 +691,34 @@ const Str = {
743
691
  /**
744
692
  * Replace first N characters of the string with maskChar
745
693
  * eg: maskFirstNCharacters( '1234567890', 6, 'X' ) yields XXXXXX7890
746
- * @param {String} str string to mask
747
- * @param {Number} n number of characters we want to mask from the string
748
- * @param {String} mask string we want replace the first N chars with
749
- * @return {String} masked string
694
+ * @param str String to mask
695
+ * @param num Number of characters we want to mask from the string
696
+ * @param mask String we want replace the first N chars with
697
+ * @returns Masked string
750
698
  */
751
- maskFirstNCharacters(str, n, mask) {
699
+ maskFirstNCharacters(str, num, mask) {
752
700
  // if str is empty, str or mask aren't strings,
753
701
  // or n is not a number, do nothing
754
- if (!this.isString(str) || !this.isString(mask) || str.length === 0 || !this.isNumber(n)) {
702
+ if (!this.isString(str) || !this.isString(mask) || str.length === 0 || !this.isNumber(num)) {
755
703
  return str;
756
704
  }
757
- return str.substring(0, n).replace(/./g, mask) + str.substring(n);
705
+ return str.substring(0, num).replace(/./g, mask) + str.substring(num);
758
706
  },
759
707
  /**
760
708
  * Trim a string
761
- *
762
- * @param {String} str
763
- * @returns {string}
764
709
  */
765
710
  trim(str) {
766
711
  return $.trim(str);
767
712
  },
768
713
  /**
769
714
  * Convert a percentage string like '25%' to 25/
770
- * @param {String} percentageString The percentage as a string
771
- * @returns {Number}
715
+ * @param percentageString The percentage as a string
772
716
  */
773
717
  percentageStringToNumber(percentageString) {
774
718
  return Number(this.cutAfter(percentageString, '%'));
775
719
  },
776
720
  /**
777
- * Remoce all the spaces from a string
778
- * @param {string} input
779
- * @returns {string}
721
+ * Remove all the spaces from a string
780
722
  */
781
723
  removeSpaces(input) {
782
724
  return String(input).replace(' ', '');
@@ -784,17 +726,15 @@ const Str = {
784
726
  /**
785
727
  * Returns the proper phrase depending on the count that is passed.
786
728
  * Example:
787
- * console.log(Str.pluralize('puppy', 'puppies', 1)); // puppy
788
- * console.log(Str.pluralize('puppy', 'puppies', 3)); // puppies
789
- *
790
- * @param {String} singular form of the phrase
791
- * @param {String} plural form of the phrase
792
- * @param {Number} n the count which determines the plurality
729
+ * console.log(Str.pluralize('puppy', 'puppies', 1)) { // puppy
730
+ * console.log(Str.pluralize('puppy', 'puppies', 3)) { // puppies
793
731
  *
794
- * @return {String}
732
+ * @param singular form of the phrase
733
+ * @param plural form of the phrase
734
+ * @param num the count which determines the plurality
795
735
  */
796
- pluralize(singular, plural, n) {
797
- if (!n || n > 1) {
736
+ pluralize(singular, plural, num) {
737
+ if (!num || num > 1) {
798
738
  return plural;
799
739
  }
800
740
  return singular;
@@ -802,25 +742,23 @@ const Str = {
802
742
  /**
803
743
  * Returns whether or not a string is an encrypted number or not.
804
744
  *
805
- * @param {String} number that we want to see if its encrypted or not
745
+ * @param num that we want to see if its encrypted or not
806
746
  *
807
- * @return {Boolean} Whether or not this string is an encrpypted number
747
+ * @returns Whether or not this string is an encrpypted number
808
748
  */
809
- isEncryptedCardNumber(number) {
749
+ isEncryptedCardNumber(num) {
810
750
  // Older encrypted versioning.
811
- if (/^[\da-fA-F]+$/.test(number)) {
812
- return number.length % 32 === 0;
751
+ if (/^[\da-fA-F]+$/.test(num)) {
752
+ return num.length % 32 === 0;
813
753
  }
814
754
  // Check with the new versioning.
815
- if (/^[vV][\d]+:[\da-fA-F]+$/.test(number)) {
816
- return number.split(':')[1].length % 32 === 0;
755
+ if (/^[vV][\d]+:[\da-fA-F]+$/.test(num)) {
756
+ return num.split(':')[1].length % 32 === 0;
817
757
  }
818
758
  return false;
819
759
  },
820
760
  /**
821
761
  * Converts a value to boolean, case-insensitive.
822
- * @param {mixed} value
823
- * @return {Boolean}
824
762
  */
825
763
  toBool(value) {
826
764
  if (this.isString(value)) {
@@ -831,14 +769,15 @@ const Str = {
831
769
  /**
832
770
  * Checks if a string could be the masked version of another one.
833
771
  *
834
- * @param {String} first string to compare
835
- * @param {String} second string to compare
836
- * @param {String} [mask] defaults to X
837
- * @return {Boolean} true when first could be the masked version of second
838
- */
839
- maskedEquals(first, second, mask) {
840
- const firsts = first.match(/.{1,1}/g);
841
- const seconds = second.match(/.{1,1}/g);
772
+ * @param strA String to compare
773
+ * @param strB String to compare
774
+ * @param [mask] Defaults to X
775
+ * @returns True when first could be the masked version of second
776
+ */
777
+ maskedEquals(strA, strB, mask) {
778
+ var _a, _b;
779
+ const firsts = (_a = strA.match(/.{1,1}/g)) !== null && _a !== void 0 ? _a : [];
780
+ const seconds = (_b = strB.match(/.{1,1}/g)) !== null && _b !== void 0 ? _b : [];
842
781
  const defaultMask = mask || 'X';
843
782
  if (firsts.length !== seconds.length) {
844
783
  return false;
@@ -852,18 +791,12 @@ const Str = {
852
791
  },
853
792
  /**
854
793
  * Bold any word matching the regexp in the text.
855
- * @param {string} text, htmlEncoded
856
- * @param {RegExp} regexp
857
- * @return {string}
858
794
  */
859
795
  boldify(text, regexp) {
860
796
  return text.replace(regexp, '<strong>$1</strong>');
861
797
  },
862
798
  /**
863
799
  * Check for whether a phone number is valid.
864
- * @param {String} phone
865
- *
866
- * @return {bool}
867
800
  * @deprecated use isValidE164Phone to validate E.164 phone numbers or isValidPhoneFormat to validate phone numbers in general
868
801
  */
869
802
  isValidPhone(phone) {
@@ -871,18 +804,12 @@ const Str = {
871
804
  },
872
805
  /**
873
806
  * Check for whether a phone number is valid.
874
- * @param {String} phone
875
- *
876
- * @return {bool}
877
807
  */
878
808
  isValidPhoneNumber(phone) {
879
809
  return (0, awesome_phonenumber_1.parsePhoneNumber)(phone).possible;
880
810
  },
881
811
  /**
882
812
  * Check for whether a phone number is valid according to E.164 standard.
883
- * @param {String} phone
884
- *
885
- * @return {bool}
886
813
  */
887
814
  isValidE164Phone(phone) {
888
815
  return Constants.CONST.SMS.E164_REGEX.test(phone);
@@ -894,18 +821,12 @@ const Str = {
894
821
  * e164: +14404589784
895
822
  * national: (440) 458-9784
896
823
  * 123.456.7890
897
- * @param {String} phone
898
- *
899
- * @return {bool}
900
824
  */
901
825
  isValidPhoneFormat(phone) {
902
826
  return Constants.CONST.REG_EXP.GENERAL_PHONE_PART.test(phone);
903
827
  },
904
828
  /**
905
829
  * We validate mentions by checking if it's first character is an allowed character.
906
- *
907
- * @param {String} mention
908
- * @returns {bool}
909
830
  */
910
831
  isValidMention(mention) {
911
832
  // Mentions can start @ proceeded by a space, eg "ping @user@domain.tld"
@@ -920,18 +841,12 @@ const Str = {
920
841
  },
921
842
  /**
922
843
  * Returns text without our SMS domain
923
- *
924
- * @param {String} text
925
- * @return {String}
926
844
  */
927
845
  removeSMSDomain(text) {
928
846
  return text.replace(REMOVE_SMS_DOMAIN_PATTERN, '');
929
847
  },
930
848
  /**
931
849
  * Returns true if the text is a valid E.164 phone number with our SMS domain removed
932
- *
933
- * @param {String} text
934
- * @return {String}
935
850
  */
936
851
  isSMSLogin(text) {
937
852
  return this.isValidE164Phone(this.removeSMSDomain(text));
@@ -941,28 +856,25 @@ const Str = {
941
856
  * JS yet, so this is a good way of doing it according to
942
857
  * https://github.com/airbnb/javascript/issues/1439#issuecomment-306297399 and doesn't get us in trouble with
943
858
  * linting rules.
944
- *
945
- * @param {String} str
946
- * @param {RegExp} regex
947
- *
948
- * @returns {Array}
949
859
  */
950
860
  matchAll(str, regex) {
951
861
  const matches = [];
862
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
952
863
  const collectMatches = (...args) => {
864
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
953
865
  const match = Array.prototype.slice.call(args, 0, -2);
954
866
  match.input = args[args.length - 1];
955
867
  match.index = args[args.length - 2];
956
868
  matches.push(match);
957
869
  };
870
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
958
871
  str.replace(regex, collectMatches);
959
872
  return matches;
960
873
  },
961
874
  /**
962
875
  * A simple GUID generator taken from https://stackoverflow.com/a/32760401/9114791
963
876
  *
964
- * @param {String} [prefix] an optional prefix to put in front of the guid
965
- * @returns {String}
877
+ * @param [prefix] an optional prefix to put in front of the guid
966
878
  */
967
879
  guid(prefix = '') {
968
880
  function s4() {
@@ -975,8 +887,8 @@ const Str = {
975
887
  /**
976
888
  * Takes in a URL and returns it with a leading '/'
977
889
  *
978
- * @param {mixed} url The URL to be formatted
979
- * @returns {String} The formatted URL
890
+ * @param url The URL to be formatted
891
+ * @returns The formatted URL
980
892
  */
981
893
  normalizeUrl(url) {
982
894
  return typeof url === 'string' && url.startsWith('/') ? url : `/${url}`;
@@ -984,8 +896,8 @@ const Str = {
984
896
  /**
985
897
  * Formats a URL by converting the domain name to lowercase and adding the missing 'https://' protocol.
986
898
  *
987
- * @param {url} url The URL to be formatted
988
- * @returns {String} The formatted URL
899
+ * @param url The URL to be formatted
900
+ * @returns The formatted URL
989
901
  */
990
902
  sanitizeURL(url) {
991
903
  const regex = new RegExp(`^${UrlPatterns.URL_REGEX}$`, 'i');
@@ -1000,28 +912,21 @@ const Str = {
1000
912
  * Checks if parameter is a string or function
1001
913
  * if it is a function then we will call it with
1002
914
  * any additional arguments.
1003
- *
1004
- * @param {String|Function} parameter
1005
- * @returns {String}
1006
915
  */
1007
- result(parameter, ...args) {
1008
- return underscore_1.default.isFunction(parameter) ? parameter(...args) : parameter;
1009
- },
916
+ result: resultFn,
1010
917
  /**
1011
918
  * Get file extension for a given url with or
1012
919
  * without query parameters
1013
- *
1014
- * @param {String} url
1015
- * @returns {String|undefined}
1016
920
  */
1017
921
  getExtension(url) {
1018
- return underscore_1.default.first(underscore_1.default.last(url.split('.')).split('?')).toLowerCase();
922
+ var _a, _b;
923
+ return (_b = (_a = url.split('.').pop()) === null || _a === void 0 ? void 0 : _a.split('?')[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase();
1019
924
  },
1020
925
  /**
1021
926
  * Takes in a URL and checks if the file extension is PDF
1022
927
  *
1023
- * @param {String} url The URL to be checked
1024
- * @returns {Boolean} Whether file path is PDF or not
928
+ * @param url The URL to be checked
929
+ * @returns Whether file path is PDF or not
1025
930
  */
1026
931
  isPDF(url) {
1027
932
  return this.getExtension(url) === 'pdf';
@@ -1033,12 +938,13 @@ const Str = {
1033
938
  * supported by all platforms.
1034
939
  *
1035
940
  * https://reactnative.dev/docs/image#source
1036
- *
1037
- * @param {String} url
1038
- * @returns {Boolean}
1039
941
  */
1040
942
  isImage(url) {
1041
- return underscore_1.default.contains(['jpeg', 'jpg', 'gif', 'png', 'bmp', 'webp'], this.getExtension(url));
943
+ const extension = this.getExtension(url);
944
+ if (!extension) {
945
+ return false;
946
+ }
947
+ return ['jpeg', 'jpg', 'gif', 'png', 'bmp', 'webp'].includes(extension);
1042
948
  },
1043
949
  /**
1044
950
  * Takes in a URL and checks if the file extension is a video
@@ -1048,30 +954,25 @@ const Str = {
1048
954
  * https://developer.android.com/media/platform/supported-formats#video-formats
1049
955
  * https://developer.apple.com/documentation/coremedia/1564239-video_codec_constants
1050
956
  * https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs
1051
- *
1052
- * @param {String} url
1053
- * @returns {Boolean}
1054
957
  */
1055
958
  isVideo(url) {
1056
- return underscore_1.default.contains(['mov', 'mp4', 'webm', 'mkv'], this.getExtension(url));
959
+ const extension = this.getExtension(url);
960
+ if (!extension) {
961
+ return false;
962
+ }
963
+ return ['mov', 'mp4', 'webm', 'mkv'].includes(extension);
1057
964
  },
1058
965
  /**
1059
966
  * Checks whether the given string is a +@ domain email account, such as
1060
967
  * +@domain.com
1061
968
  *
1062
- * @param {String} email
1063
- * @return {Boolean} True if is a domain account email, otherwise false.
969
+ * @returns True if is a domain account email, otherwise false.
1064
970
  */
1065
971
  isDomainEmail(email) {
1066
972
  return this.startsWith(email, '+@');
1067
973
  },
1068
974
  /**
1069
975
  * Polyfill for String.prototype.replaceAll
1070
- *
1071
- * @param {String} text
1072
- * @param {String|RegExp} searchValue
1073
- * @param {String|Function} replaceValue
1074
- * @returns {String}
1075
976
  */
1076
977
  replaceAll(text, searchValue, replaceValue) {
1077
978
  return String.prototype.replaceAll.call(text, searchValue, replaceValue);