expensify-common 2.0.209 → 2.0.211

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
@@ -53,6 +53,126 @@ function resultFn(parameter, ...args) {
53
53
  }
54
54
  return parameter;
55
55
  }
56
+ // Str methods that other Str methods call are plain module-level functions instead of being reached through
57
+ // `this`: react-native-worklets 0.13 no longer keeps an object literal together on a Worklet Runtime, so `this`
58
+ // inside a workletized method does not point to Str there.
59
+ function compare(strA, strB) {
60
+ if (strA < strB) {
61
+ return -1;
62
+ }
63
+ if (strA > strB) {
64
+ return 1;
65
+ }
66
+ return 0;
67
+ }
68
+ function caseInsensitiveCompare(strA, strB) {
69
+ const lowerCaseStrA = strA.toLocaleLowerCase();
70
+ const lowerCaseStrB = strB.toLocaleLowerCase();
71
+ return compare(lowerCaseStrA, lowerCaseStrB);
72
+ }
73
+ function contains(haystack, needle) {
74
+ return haystack.indexOf(needle) !== -1;
75
+ }
76
+ function cutAfter(str, substr) {
77
+ const index = str.indexOf(substr);
78
+ if (index !== -1) {
79
+ return str.substring(0, index);
80
+ }
81
+ return str;
82
+ }
83
+ function cutBefore(str, substr) {
84
+ const index = str.indexOf(substr);
85
+ if (index !== -1) {
86
+ return str.substring(index + substr.length);
87
+ }
88
+ return str;
89
+ }
90
+ function extractEmailDomain(email) {
91
+ return cutBefore(email, '@');
92
+ }
93
+ function getExtension(url) {
94
+ var _a, _b;
95
+ if (typeof url !== 'string') {
96
+ Log_1.default.warn('Str.getExtension: url is not a string', { url });
97
+ return undefined;
98
+ }
99
+ return (_b = (_a = url.split('.').pop()) === null || _a === void 0 ? void 0 : _a.split('?')[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase();
100
+ }
101
+ function getRawByteSize(inputChar) {
102
+ const onlyChar = String(inputChar);
103
+ const c = onlyChar.charCodeAt(0);
104
+ // If we are grabbing the byte size, we need to temporarily diable no-bitwise for linting
105
+ /* eslint-disable no-bitwise */
106
+ if (c < 1 << 7) {
107
+ return 1;
108
+ }
109
+ if (c < 1 << 11) {
110
+ return 2;
111
+ }
112
+ if (c < 1 << 16) {
113
+ return 3;
114
+ }
115
+ if (c < 1 << 21) {
116
+ return 4;
117
+ }
118
+ if (c < 1 << 26) {
119
+ return 5;
120
+ }
121
+ if (c < 1 << 31) {
122
+ return 6;
123
+ }
124
+ /* eslint-enable no-bitwise */
125
+ return Number.NaN;
126
+ }
127
+ function htmlDecode(s) {
128
+ return HtmlEntities.decode(s);
129
+ }
130
+ function htmlEncode(s) {
131
+ return HtmlEntities.encode(s);
132
+ }
133
+ function isTypeOf(obj, type) {
134
+ return Object.prototype.toString.call(obj) === `[object ${type}]`;
135
+ }
136
+ function isNumber(obj) {
137
+ return isTypeOf(obj, 'Number');
138
+ }
139
+ function isString(obj) {
140
+ return isTypeOf(obj, 'String');
141
+ }
142
+ function isUndefined(obj) {
143
+ // eslint-disable-next-line no-void
144
+ return obj === void 0;
145
+ }
146
+ function isValidE164Phone(phone) {
147
+ return Constants.CONST.SMS.E164_REGEX.test(phone);
148
+ }
149
+ function isValidEmail(str) {
150
+ if (!str || typeof str !== 'string') {
151
+ return false;
152
+ }
153
+ const unicodeVersion = punycode_1.default.toUnicode(str);
154
+ if (String(unicodeVersion).match(Constants.CONST.REG_EXP.EMOJI_RULE)) {
155
+ return false;
156
+ }
157
+ return !!String(str).match(Constants.CONST.REG_EXP.EMAIL);
158
+ }
159
+ function maskFirstNCharacters(str, num, mask) {
160
+ // if str is empty, str or mask aren't strings,
161
+ // or n is not a number, do nothing
162
+ if (!isString(str) || !isString(mask) || str.length === 0 || !isNumber(num)) {
163
+ return str;
164
+ }
165
+ return str.substring(0, num).replaceAll(/./g, mask) + str.substring(num);
166
+ }
167
+ function removeSMSDomain(text) {
168
+ return text.replaceAll(REMOVE_SMS_DOMAIN_PATTERN, '');
169
+ }
170
+ function removeTrailingComma(str) {
171
+ return str.trim().replaceAll(/(,$)/g, '');
172
+ }
173
+ function startsWith(haystack, needle) {
174
+ return isString(haystack) && isString(needle) && haystack.substring(0, needle.length) === needle;
175
+ }
56
176
  const Str = {
57
177
  /**
58
178
  * Return true if the string is ending with the provided suffix
@@ -110,18 +230,14 @@ const Str = {
110
230
  * @param s The string to decode.
111
231
  * @returns The decoded string.
112
232
  */
113
- htmlDecode(s) {
114
- return HtmlEntities.decode(s);
115
- },
233
+ htmlDecode,
116
234
  /**
117
235
  * HTML encodes the given string.
118
236
  *
119
237
  * @param s The string to encode.
120
238
  * @return string @p s HTML encoded.
121
239
  */
122
- htmlEncode(s) {
123
- return HtmlEntities.encode(s);
124
- },
240
+ htmlEncode,
125
241
  /**
126
242
  * Decodes the given HTML encoded string.
127
243
  *
@@ -165,7 +281,7 @@ const Str = {
165
281
  * @returns True when first === second, ignoring HTML encoding
166
282
  */
167
283
  htmlEncodingInsensitiveEquals(first, second) {
168
- return first === second || this.htmlDecode(first) === second || this.htmlEncode(first) === second;
284
+ return first === second || htmlDecode(first) === second || htmlEncode(first) === second;
169
285
  },
170
286
  /**
171
287
  * Creates an ID that can be used as an HTML attribute from @p str.
@@ -251,32 +367,7 @@ const Str = {
251
367
  * one.
252
368
  * @returns Byte size of the character
253
369
  */
254
- getRawByteSize(inputChar) {
255
- const onlyChar = String(inputChar);
256
- const c = onlyChar.charCodeAt(0);
257
- // If we are grabbing the byte size, we need to temporarily diable no-bitwise for linting
258
- /* eslint-disable no-bitwise */
259
- if (c < 1 << 7) {
260
- return 1;
261
- }
262
- if (c < 1 << 11) {
263
- return 2;
264
- }
265
- if (c < 1 << 16) {
266
- return 3;
267
- }
268
- if (c < 1 << 21) {
269
- return 4;
270
- }
271
- if (c < 1 << 26) {
272
- return 5;
273
- }
274
- if (c < 1 << 31) {
275
- return 6;
276
- }
277
- /* eslint-enable no-bitwise */
278
- return Number.NaN;
279
- },
370
+ getRawByteSize,
280
371
  /**
281
372
  * Gets the length of a string in bytes, including non-ASCII characters
282
373
  * @returns The number of bytes used by string
@@ -284,7 +375,7 @@ const Str = {
284
375
  getByteLength(input) {
285
376
  // Force string type
286
377
  const stringInput = String(input);
287
- const byteLength = Array.from(stringInput).reduce((acc, char) => acc + this.getRawByteSize(char), 0);
378
+ const byteLength = Array.from(stringInput).reduce((acc, char) => acc + getRawByteSize(char), 0);
288
379
  return byteLength;
289
380
  },
290
381
  /**
@@ -296,7 +387,7 @@ const Str = {
296
387
  const stringInput = String(input);
297
388
  let totalByteLength = 0;
298
389
  for (let i = 0; i < stringInput.length; i++) {
299
- const charByteSize = this.getRawByteSize(stringInput[i]);
390
+ const charByteSize = getRawByteSize(stringInput[i]);
300
391
  if (charByteSize + totalByteLength > maxSize) {
301
392
  // If the next character exceeds the limit, stop and return the truncated string.
302
393
  return `${stringInput.substr(0, i - 3)}...`;
@@ -312,9 +403,7 @@ const Str = {
312
403
  * @param needle The case-sensitive string to search for
313
404
  * @returns True if the haystack starts with the needle.
314
405
  */
315
- startsWith(haystack, needle) {
316
- return this.isString(haystack) && this.isString(needle) && haystack.substring(0, needle.length) === needle;
317
- },
406
+ startsWith,
318
407
  /**
319
408
  * Gets the textual value of the given string.
320
409
  *
@@ -322,7 +411,7 @@ const Str = {
322
411
  * @returns The text from within the HTML string.
323
412
  */
324
413
  stripHTML(str) {
325
- if (!this.isString(str)) {
414
+ if (!isString(str)) {
326
415
  return '';
327
416
  }
328
417
  return str.replaceAll(/<[^>]*>?/gm, '');
@@ -345,13 +434,7 @@ const Str = {
345
434
  * @param substr The substring to search for.
346
435
  * @returns The cut/trimmed string.
347
436
  */
348
- cutAfter(str, substr) {
349
- const index = str.indexOf(substr);
350
- if (index !== -1) {
351
- return str.substring(0, index);
352
- }
353
- return str;
354
- },
437
+ cutAfter,
355
438
  /**
356
439
  * Returns a string containing all the characters str from after the first
357
440
  * occurrence of substr to the end of the string.
@@ -361,13 +444,7 @@ const Str = {
361
444
  * @param substr The substring to search for.
362
445
  * @returns The cut/trimmed string.
363
446
  */
364
- cutBefore(str, substr) {
365
- const index = str.indexOf(substr);
366
- if (index !== -1) {
367
- return str.substring(index + substr.length);
368
- }
369
- return str;
370
- },
447
+ cutBefore,
371
448
  /**
372
449
  * Checks that the string is a domain name (e.g. example.com)
373
450
  *
@@ -394,16 +471,7 @@ const Str = {
394
471
  *
395
472
  * @returns True if the string is an email
396
473
  */
397
- isValidEmail(str) {
398
- if (!str || typeof str !== 'string') {
399
- return false;
400
- }
401
- const unicodeVersion = punycode_1.default.toUnicode(str);
402
- if (String(unicodeVersion).match(Constants.CONST.REG_EXP.EMOJI_RULE)) {
403
- return false;
404
- }
405
- return !!String(str).match(Constants.CONST.REG_EXP.EMAIL);
406
- },
474
+ isValidEmail,
407
475
  /**
408
476
  * Checks if the string is an valid email address formed during comment markdown formation.
409
477
  *
@@ -421,9 +489,7 @@ const Str = {
421
489
  *
422
490
  * @returns string with the trailing comma removed
423
491
  */
424
- removeTrailingComma(str) {
425
- return str.trim().replaceAll(/(,$)/g, '');
426
- },
492
+ removeTrailingComma,
427
493
  /**
428
494
  * Checks that the string is a list of coma separated email addresss.
429
495
  *
@@ -432,12 +498,12 @@ const Str = {
432
498
  * @returns True if all emails are valid or if input is empty
433
499
  */
434
500
  areValidEmails(str) {
435
- const string = this.removeTrailingComma(str);
501
+ const string = removeTrailingComma(str);
436
502
  if (string === '') {
437
503
  return true;
438
504
  }
439
505
  const emails = string.split(',');
440
- const result = emails.every((email) => this.isValidEmail(email.trim()));
506
+ const result = emails.every((email) => isValidEmail(email.trim()));
441
507
  return result;
442
508
  },
443
509
  /**
@@ -454,9 +520,7 @@ const Str = {
454
520
  *
455
521
  * @returns The domain name in the email address.
456
522
  */
457
- extractEmailDomain(email) {
458
- return this.cutBefore(email, '@');
459
- },
523
+ extractEmailDomain,
460
524
  /**
461
525
  * Tries to extract the company name from the given email address
462
526
  * (e.g. "yelp" for "joe@yelp.co.uk").
@@ -466,7 +530,7 @@ const Str = {
466
530
  * @returns The company name in the email address or null.
467
531
  */
468
532
  extractCompanyNameFromEmailDomain(email) {
469
- const domain = this.extractEmailDomain(email);
533
+ const domain = extractEmailDomain(email);
470
534
  if (!domain) {
471
535
  return null;
472
536
  }
@@ -485,7 +549,7 @@ const Str = {
485
549
  * @returns The local part in the email address.
486
550
  */
487
551
  extractEmailLocalPart(email) {
488
- return this.cutAfter(email, '@');
552
+ return cutAfter(email, '@');
489
553
  },
490
554
  /**
491
555
  * Sanitize phone number to return only numbers. Return null if non valid phone number.
@@ -543,13 +607,13 @@ const Str = {
543
607
  * @returns true if the length is in the range, false otherwise
544
608
  */
545
609
  isOfLength(str, minimumLength, maximumLength) {
546
- if (!this.isString(str)) {
610
+ if (!isString(str)) {
547
611
  return false;
548
612
  }
549
613
  if (str.length < minimumLength) {
550
614
  return false;
551
615
  }
552
- if (!this.isUndefined(maximumLength) && str.length > maximumLength) {
616
+ if (!isUndefined(maximumLength) && str.length > maximumLength) {
553
617
  return false;
554
618
  }
555
619
  return true;
@@ -603,9 +667,7 @@ const Str = {
603
667
  *
604
668
  * @returns Returns true if the haystack contains the needle
605
669
  */
606
- contains(haystack, needle) {
607
- return haystack.indexOf(needle) !== -1;
608
- },
670
+ contains,
609
671
  /**
610
672
  * Returns true if the haystack contains the needle, ignoring case
611
673
  *
@@ -615,7 +677,7 @@ const Str = {
615
677
  * @returns Returns true if the haystack contains the needle, ignoring case
616
678
  */
617
679
  caseInsensitiveContains(haystack, needle) {
618
- return this.contains(haystack.toLowerCase(), needle.toLowerCase());
680
+ return contains(haystack.toLowerCase(), needle.toLowerCase());
619
681
  },
620
682
  /**
621
683
  * Case insensitive compare function
@@ -627,11 +689,7 @@ const Str = {
627
689
  * 1 if first string > second string
628
690
  * 0 if first string = second string
629
691
  */
630
- caseInsensitiveCompare(strA, strB) {
631
- const lowerCaseStrA = strA.toLocaleLowerCase();
632
- const lowerCaseStrB = strB.toLocaleLowerCase();
633
- return this.compare(lowerCaseStrA, lowerCaseStrB);
634
- },
692
+ caseInsensitiveCompare,
635
693
  /**
636
694
  * Case insensitive equals
637
695
  *
@@ -640,7 +698,7 @@ const Str = {
640
698
  * @returns true when first == second except for case
641
699
  */
642
700
  caseInsensitiveEquals(strA, strB) {
643
- return this.caseInsensitiveCompare(strA, strB) === 0;
701
+ return caseInsensitiveCompare(strA, strB) === 0;
644
702
  },
645
703
  /**
646
704
  * Compare function
@@ -652,15 +710,7 @@ const Str = {
652
710
  * 1 if first string > second string
653
711
  * 0 if first string = second string
654
712
  */
655
- compare(strA, strB) {
656
- if (strA < strB) {
657
- return -1;
658
- }
659
- if (strA > strB) {
660
- return 1;
661
- }
662
- return 0;
663
- },
713
+ compare,
664
714
  /**
665
715
  * Check if a file extension is supported by SmartReports
666
716
  */
@@ -684,48 +734,39 @@ const Str = {
684
734
  // Hide these numbers completely
685
735
  // We should not be getting account numbers this small or large
686
736
  if (len < 6 || len > 20) {
687
- return this.maskFirstNCharacters(accountNumber, len, 'X');
737
+ return maskFirstNCharacters(accountNumber, len, 'X');
688
738
  }
689
739
  // Can show last 4
690
740
  if (len < 14) {
691
- return this.maskFirstNCharacters(accountNumber, len - 4, 'X');
741
+ return maskFirstNCharacters(accountNumber, len - 4, 'X');
692
742
  }
693
743
  // Can show first 6 and last 4
694
744
  const first = accountNumber.substr(0, 6);
695
745
  const last = accountNumber.substr(7);
696
- const masked = this.maskFirstNCharacters(last, len - 11, 'X');
746
+ const masked = maskFirstNCharacters(last, len - 11, 'X');
697
747
  return `${first}${masked}`;
698
748
  },
699
749
  /**
700
750
  * Checks if something is a string
701
751
  * Stolen from underscore
702
752
  */
703
- isString(obj) {
704
- return this.isTypeOf(obj, 'String');
705
- },
753
+ isString,
706
754
  /**
707
755
  * Checks if something is a number
708
756
  * Stolen from underscore
709
757
  * @param obj
710
758
  */
711
- isNumber(obj) {
712
- return this.isTypeOf(obj, 'Number');
713
- },
759
+ isNumber,
714
760
  /**
715
761
  * Checks if something is a certain type
716
762
  * Stolen from underscore
717
763
  */
718
- isTypeOf(obj, type) {
719
- return Object.prototype.toString.call(obj) === `[object ${type}]`;
720
- },
764
+ isTypeOf,
721
765
  /**
722
766
  * Checks to see if something is undefined
723
767
  * Stolen from underscore
724
768
  */
725
- isUndefined(obj) {
726
- // eslint-disable-next-line no-void
727
- return obj === void 0;
728
- },
769
+ isUndefined,
729
770
  /**
730
771
  * Replace first N characters of the string with maskChar
731
772
  * eg: maskFirstNCharacters( '1234567890', 6, 'X' ) yields XXXXXX7890
@@ -734,14 +775,7 @@ const Str = {
734
775
  * @param mask String we want replace the first N chars with
735
776
  * @returns Masked string
736
777
  */
737
- maskFirstNCharacters(str, num, mask) {
738
- // if str is empty, str or mask aren't strings,
739
- // or n is not a number, do nothing
740
- if (!this.isString(str) || !this.isString(mask) || str.length === 0 || !this.isNumber(num)) {
741
- return str;
742
- }
743
- return str.substring(0, num).replaceAll(/./g, mask) + str.substring(num);
744
- },
778
+ maskFirstNCharacters,
745
779
  /**
746
780
  * Trim a string
747
781
  */
@@ -753,7 +787,7 @@ const Str = {
753
787
  * @param percentageString The percentage as a string
754
788
  */
755
789
  percentageStringToNumber(percentageString) {
756
- return Number(this.cutAfter(percentageString, '%'));
790
+ return Number(cutAfter(percentageString, '%'));
757
791
  },
758
792
  /**
759
793
  * Remove all the spaces from a string
@@ -799,7 +833,7 @@ const Str = {
799
833
  * Converts a value to boolean, case-insensitive.
800
834
  */
801
835
  toBool(value) {
802
- if (this.isString(value)) {
836
+ if (isString(value)) {
803
837
  return value.toLowerCase() === 'true';
804
838
  }
805
839
  return !!value;
@@ -849,9 +883,7 @@ const Str = {
849
883
  /**
850
884
  * Check for whether a phone number is valid according to E.164 standard.
851
885
  */
852
- isValidE164Phone(phone) {
853
- return Constants.CONST.SMS.E164_REGEX.test(phone);
854
- },
886
+ isValidE164Phone,
855
887
  /**
856
888
  * Check for whether a phone number is valid in different formats/standards. For example:
857
889
  * significant: 4404589784
@@ -880,14 +912,12 @@ const Str = {
880
912
  /**
881
913
  * Returns text without our SMS domain
882
914
  */
883
- removeSMSDomain(text) {
884
- return text.replaceAll(REMOVE_SMS_DOMAIN_PATTERN, '');
885
- },
915
+ removeSMSDomain,
886
916
  /**
887
917
  * Returns true if the text is a valid E.164 phone number with our SMS domain removed
888
918
  */
889
919
  isSMSLogin(text) {
890
- return this.isValidE164Phone(this.removeSMSDomain(text));
920
+ return isValidE164Phone(removeSMSDomain(text));
891
921
  },
892
922
  /**
893
923
  * This method will return all matches of a single regex like preg_match_all() in PHP. This is not a common part of
@@ -945,7 +975,7 @@ const Str = {
945
975
  return url;
946
976
  }
947
977
  const website = match[3] ? match[2] : `${defaultScheme}://${match[2]}`;
948
- return website.toLowerCase() + this.cutBefore(match[1], match[2]);
978
+ return website.toLowerCase() + cutBefore(match[1], match[2]);
949
979
  },
950
980
  /**
951
981
  * Checks if parameter is a string or function
@@ -957,14 +987,7 @@ const Str = {
957
987
  * Get file extension for a given url with or
958
988
  * without query parameters
959
989
  */
960
- getExtension(url) {
961
- var _a, _b;
962
- if (typeof url !== 'string') {
963
- Log_1.default.warn('Str.getExtension: url is not a string', { url });
964
- return undefined;
965
- }
966
- return (_b = (_a = url.split('.').pop()) === null || _a === void 0 ? void 0 : _a.split('?')[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase();
967
- },
990
+ getExtension,
968
991
  /**
969
992
  * Takes in a URL and checks if the file extension is PDF
970
993
  *
@@ -972,7 +995,7 @@ const Str = {
972
995
  * @returns Whether file path is PDF or not
973
996
  */
974
997
  isPDF(url) {
975
- return this.getExtension(url) === 'pdf';
998
+ return getExtension(url) === 'pdf';
976
999
  },
977
1000
  /**
978
1001
  * Takes in a URL and checks if the file extension is an image
@@ -983,7 +1006,7 @@ const Str = {
983
1006
  * https://reactnative.dev/docs/image#source
984
1007
  */
985
1008
  isImage(url) {
986
- const extension = this.getExtension(url);
1009
+ const extension = getExtension(url);
987
1010
  if (!extension) {
988
1011
  return false;
989
1012
  }
@@ -999,7 +1022,7 @@ const Str = {
999
1022
  * https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Video_codecs
1000
1023
  */
1001
1024
  isVideo(url) {
1002
- const extension = this.getExtension(url);
1025
+ const extension = getExtension(url);
1003
1026
  if (!extension) {
1004
1027
  return false;
1005
1028
  }
@@ -1012,7 +1035,7 @@ const Str = {
1012
1035
  * @returns True if is a domain account email, otherwise false.
1013
1036
  */
1014
1037
  isDomainEmail(email) {
1015
- return this.startsWith(email, '+@');
1038
+ return startsWith(email, '+@');
1016
1039
  },
1017
1040
  /**
1018
1041
  * Find the minimum indentation of any line in the string,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expensify-common",
3
- "version": "2.0.209",
3
+ "version": "2.0.211",
4
4
  "author": "Expensify, Inc.",
5
5
  "description": "Expensify libraries and components shared across different repos",
6
6
  "homepage": "https://expensify.com",