@valkyriestudios/utils 12.18.0 → 12.20.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/README.md +58 -19
- package/array/dedupe.d.ts +3 -0
- package/date/format.js +82 -48
- package/date/index.d.ts +2 -1
- package/date/index.js +4 -1
- package/date/isFormat.d.ts +12 -0
- package/date/isFormat.js +110 -0
- package/deep/freeze.js +2 -2
- package/deep/get.d.ts +14 -13
- package/deep/get.js +38 -16
- package/deep/seal.js +2 -2
- package/equal.js +6 -4
- package/hash/fnv1A.js +2 -2
- package/index.d.ts +28 -21
- package/object/merge.d.ts +8 -7
- package/object/merge.js +24 -10
- package/object/pick.d.ts +7 -3
- package/object/pick.js +11 -4
- package/package.json +1 -1
- package/string/humanizeBytes.js +5 -11
- package/string/humanizeNumber.js +11 -13
- package/string/shorten.js +0 -3
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# @valkyriestudios/utils
|
|
2
2
|
|
|
3
|
-
[](https://codecov.io/gh/ValkyrieStudios/utils)
|
|
4
|
+
[](https://github.com/ValkyrieStudios/utils/actions/workflows/test.yml)
|
|
5
|
+
[](https://github.com/ValkyrieStudios/utils/actions/workflows/lint.yml)
|
|
6
|
+
[](https://github.com/ValkyrieStudios/utils/actions/workflows/github-code-scanning/codeql)
|
|
7
7
|
[](https://www.npmjs.com/package/@valkyriestudios/utils)
|
|
8
8
|
[](https://www.npmjs.com/package/@valkyriestudios/utils)
|
|
9
9
|
|
|
@@ -15,14 +15,14 @@ Zero-dependency collection of single-function utilities for common tasks
|
|
|
15
15
|
## Available Functions
|
|
16
16
|
|
|
17
17
|
### array
|
|
18
|
-
- **isArray(val:
|
|
18
|
+
- **isArray(val:unknown)**
|
|
19
19
|
Check if a variable is of type Array
|
|
20
20
|
```typescript
|
|
21
21
|
isArray({a:1}); // FALSE
|
|
22
22
|
isArray([]); // TRUE
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
- **isNotEmptyArray(val:
|
|
25
|
+
- **isNotEmptyArray(val:unknown)**
|
|
26
26
|
Check if a variable a non-empty array
|
|
27
27
|
```typescript
|
|
28
28
|
isNotEmptyArray({a:1}); // FALSE
|
|
@@ -365,13 +365,44 @@ await memoized('123456'); /* Original function will be called and re-cached */
|
|
|
365
365
|
```
|
|
366
366
|
|
|
367
367
|
### date
|
|
368
|
-
- **isDate(val:
|
|
368
|
+
- **isDate(val:unknown)**
|
|
369
369
|
Check if a variable is of type Date
|
|
370
370
|
```typescript
|
|
371
371
|
isDate(new Date('December 17, 1995 03:24:00')); // TRUE
|
|
372
372
|
isDate('December 17, 1995 03:24:00'); // FALSE
|
|
373
373
|
```
|
|
374
374
|
|
|
375
|
+
- **isFormat(val:unknown, spec:string)**
|
|
376
|
+
Check if a variable is a string in a particular date format
|
|
377
|
+
```typescript
|
|
378
|
+
isFormat('2024-02-07', 'YYYY-MM-DD'); // TRUE
|
|
379
|
+
isFormat('2024-2-07', 'YYYY-MM-DD'); // FALSE
|
|
380
|
+
isFormat('12:30 AM', 'HH:mm A'); // TRUE
|
|
381
|
+
isFormat('2024-Q4', 'YYYY-[Q]Q'); // TRUE
|
|
382
|
+
isFormat('2024-Q5', 'YYYY-[Q]Q'); // FALSE (there is no such thing as a fifth quarter)
|
|
383
|
+
isFormat('2024-02-29T12:30:00.000Z', 'ISO'); // TRUE
|
|
384
|
+
isFormat('2023-02-29T12:30:00.000Z', 'ISO'); // FALSE (leap year)
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
Available tokens for usage in spec:
|
|
388
|
+
| Token | Description | Example |
|
|
389
|
+
|:---------|:--------------------------|:---------------|
|
|
390
|
+
| `YYYY` | Full Year | 2021 |
|
|
391
|
+
| `Q` | Quarters of the year | 1 2 3 4 |
|
|
392
|
+
| `MM` | Month as 2 char | 01 02 .. 11 12 |
|
|
393
|
+
| `DD` | Day of month as 2 char | 01 02 .. 30 31 |
|
|
394
|
+
| `HH` | Hours as 2-char | 00 01 .. 22 23 |
|
|
395
|
+
| `mm` | Minutes as 2-char | 00 01 .. 58 59 |
|
|
396
|
+
| `ss` | Seconds as 2-char | 00 01 .. 58 59 |
|
|
397
|
+
| `SSS` | Milliseconds as 3-digit | 000 001 ... 998 999 |
|
|
398
|
+
| `A` | Uppercase AM/PM | AM ... PM |
|
|
399
|
+
| `a` | Lowercase AM/PM | am ... pm |
|
|
400
|
+
| `Z` | Zone, does not allow full zone names, only Z or offsets | `Z` `+02:00` |
|
|
401
|
+
| `ISO` | Check for full iso date format, take note this enforces milliseconds as a requirement | 2024-02-03T10:28:30.000Z |
|
|
402
|
+
|
|
403
|
+
Note: The `ISO` token is a shorthand for `YYYY-MM-DDTHH:mm:ss.SSSZ`
|
|
404
|
+
Note: You can escape characters by surrounding them with `[...]` in your spec, eg: `YYYY-[Q]Q` would check for example `2024-Q1`
|
|
405
|
+
|
|
375
406
|
- **diff(val_a:Date, val_b:Date, key:string)**
|
|
376
407
|
Take two incoming dates and return the difference between them in a certain unit. Possible key options(week,day,hour,minute,second,millisecond).
|
|
377
408
|
|
|
@@ -385,6 +416,7 @@ diff(new Date("2022-10-05T13:12:11+02:00"), new Date("2022-10-05T17:43:09.344+06
|
|
|
385
416
|
diff(new Date("2022-10-05T13:12:11+02:00"), new Date("2022-10-05T17:43:09.344+06:00"), 'millisecond'); // -1858344
|
|
386
417
|
diff(new Date("2022-11-05T13:12:11+06:00"), new Date("2022-10-05T13:25:43.898+02:00")); // 2663187102
|
|
387
418
|
```
|
|
419
|
+
|
|
388
420
|
- **format(val:Date, spec:string, locale?:string, zone?:string):string**
|
|
389
421
|
Format a date according to a spec/locale and zone
|
|
390
422
|
|
|
@@ -392,6 +424,8 @@ Note: The locale is by default set to 'en-US'
|
|
|
392
424
|
|
|
393
425
|
Note: The zone is by default detected as the zone of the client
|
|
394
426
|
|
|
427
|
+
Note: You can escape characters by surrounding them with `[...]` in your spec, eg: `YYYY-[Q]Q` would for example become `2024-Q1`
|
|
428
|
+
|
|
395
429
|
Available tokens for usage in spec:
|
|
396
430
|
| Token | Description | Example |
|
|
397
431
|
|:---------|:--------------------------|:---------------|
|
|
@@ -670,7 +704,7 @@ Generate a unique identifier (guid) according to RFC4122
|
|
|
670
704
|
guid(); // 245caf1a-86af-11e7-bb31-be2e44b06b34
|
|
671
705
|
```
|
|
672
706
|
|
|
673
|
-
- **fnv1A(val:
|
|
707
|
+
- **fnv1A(val:unknown)**
|
|
674
708
|
Generate a fnv1A hash from an object, using a 32-bit prime/offset
|
|
675
709
|
```typescript
|
|
676
710
|
fnv1A('hello world'); // -2023343616
|
|
@@ -681,7 +715,7 @@ fnv1A(new Date('2012-02-02')); // 1655579136
|
|
|
681
715
|
```
|
|
682
716
|
|
|
683
717
|
### number
|
|
684
|
-
- **isNumber(val:
|
|
718
|
+
- **isNumber(val:unknown)**
|
|
685
719
|
Check if a variable is a number
|
|
686
720
|
```typescript
|
|
687
721
|
isNumber('foo'); // FALSE
|
|
@@ -735,7 +769,7 @@ isNumberBetween(0, 0, 1); // TRUE
|
|
|
735
769
|
isNumberBetween(-1, 0, 1); // FALSE
|
|
736
770
|
```
|
|
737
771
|
|
|
738
|
-
- **isInteger(val:
|
|
772
|
+
- **isInteger(val:unknown)**
|
|
739
773
|
Check if a variable is an integer
|
|
740
774
|
```typescript
|
|
741
775
|
isInteger('foo'); // FALSE
|
|
@@ -791,7 +825,7 @@ isIntegerBetween(0, 0, 1); // TRUE
|
|
|
791
825
|
isIntegerBetween(-1, 0, 1); // FALSE
|
|
792
826
|
```
|
|
793
827
|
|
|
794
|
-
- **isNumericalNaN(val:
|
|
828
|
+
- **isNumericalNaN(val:unknown)**
|
|
795
829
|
Check if a variable is a numerical nan ( a number that is a NaN, this distinguishment is made since both a string or a number can be NaN)
|
|
796
830
|
```typescript
|
|
797
831
|
isNumericalNaN('foo'); // FALSE
|
|
@@ -829,14 +863,14 @@ randomIntBetween(25, 100); // Will generate a random between 25 and 100 (100 not
|
|
|
829
863
|
```
|
|
830
864
|
|
|
831
865
|
### object
|
|
832
|
-
- **isObject(val:
|
|
866
|
+
- **isObject(val:unknown)**
|
|
833
867
|
Check if a variable is of type Object
|
|
834
868
|
```typescript
|
|
835
869
|
isObject({a: 1}); // TRUE
|
|
836
870
|
isObject(1); // FALSE
|
|
837
871
|
```
|
|
838
872
|
|
|
839
|
-
- **isNotEmptyObject(val:
|
|
873
|
+
- **isNotEmptyObject(val:unknown)**
|
|
840
874
|
Check if a variable a non-empty object
|
|
841
875
|
```typescript
|
|
842
876
|
isNotEmptyObject({a:1}); // TRUE
|
|
@@ -851,12 +885,17 @@ Copies the keys passed in the 'keys' array from the passed object to a new objec
|
|
|
851
885
|
pick({a: 1, b: 2, c: 3}, ['a','b']); // {a: 1, b: 2}
|
|
852
886
|
```
|
|
853
887
|
|
|
854
|
-
- **merge(target:Object={},obj:Object={})**
|
|
888
|
+
- **merge(target:Object={},obj:Object|Object[]={}, opts?:{union?:boolean})**
|
|
855
889
|
Merges two objects together, with the preference over the second object.
|
|
856
890
|
```typescript
|
|
857
|
-
merge({a: 1, b: false}, {a: 900, c: 50}); // {a: 900, b: false, c: 50}
|
|
891
|
+
merge({a: 1, b: false}, {a: 900, c: 50}, {union: true}); // {a: 900, b: false, c: 50}
|
|
892
|
+
merge({a: 1, b: false}, {a: 900, c: 50}, {union: false}); // {a: 900, b: false}
|
|
893
|
+
merge({a: 1, c: {bar: 'foo'}}, [{b: 2}, {c: {foo: 'bar'}}], {union: true}); // {a: 1, b: 2, c: {bar: 'foo', foo: 'bar'}}
|
|
858
894
|
```
|
|
859
895
|
|
|
896
|
+
Take Note: The default behavior is to not have union, this means that ONLY the keys in the target object
|
|
897
|
+
are going to be available in the response of this function.
|
|
898
|
+
|
|
860
899
|
- **define(props:Object, obj:Object={})**
|
|
861
900
|
Creates an object with the passed accessors set on it
|
|
862
901
|
```typescript
|
|
@@ -882,7 +921,7 @@ define({
|
|
|
882
921
|
```
|
|
883
922
|
|
|
884
923
|
### regexp
|
|
885
|
-
- **isRegExp(val:
|
|
924
|
+
- **isRegExp(val:unknown)**
|
|
886
925
|
Check if a variable is an instance of RegExp
|
|
887
926
|
```typescript
|
|
888
927
|
isRegExp('foo'); // FALSE
|
|
@@ -898,7 +937,7 @@ sanitizeRegExp('contact@valkyriestudios.be'); // contact@valkyriestudios\\.be
|
|
|
898
937
|
```
|
|
899
938
|
|
|
900
939
|
### string
|
|
901
|
-
- **isString(val:
|
|
940
|
+
- **isString(val:unknown)**
|
|
902
941
|
Check if a variable is a string
|
|
903
942
|
```typescript
|
|
904
943
|
isString('foo'); // TRUE
|
|
@@ -916,7 +955,7 @@ isStringBetween(' Joe', 1, 3); // TRUE
|
|
|
916
955
|
isStringBetween(' Joe', 1, 3, false); // FALSE
|
|
917
956
|
```
|
|
918
957
|
|
|
919
|
-
- **isNotEmptyString(val:
|
|
958
|
+
- **isNotEmptyString(val:unknown, trimmed:boolean=true)**
|
|
920
959
|
Check if a variable a non-empty string
|
|
921
960
|
```typescript
|
|
922
961
|
isNotEmptyString({a:1}); // FALSE
|
|
@@ -926,7 +965,7 @@ isNotEmptyString(' ', false); // TRUE
|
|
|
926
965
|
isNotEmptyString('Hi'); // TRUE
|
|
927
966
|
```
|
|
928
967
|
|
|
929
|
-
- **shorten(val:
|
|
968
|
+
- **shorten(val:string, length:integer, postfix:string=..., truncate_words=true)**
|
|
930
969
|
Shorten a string and add a postfix if string went over length
|
|
931
970
|
```typescript
|
|
932
971
|
shorten('To the moon and beyond', 11, '..'); // 'To the moon..'
|
package/array/dedupe.d.ts
CHANGED
package/date/format.js
CHANGED
|
@@ -15,36 +15,35 @@ finally {
|
|
|
15
15
|
DEFAULT_TZ = 'UTC';
|
|
16
16
|
}
|
|
17
17
|
const escape_rgx = /\[[\s\S]+?]/g;
|
|
18
|
-
const intl_formatters =
|
|
19
|
-
const spec_cache =
|
|
20
|
-
const zone_offset_cache =
|
|
18
|
+
const intl_formatters = Object.create(null);
|
|
19
|
+
const spec_cache = Object.create(null);
|
|
20
|
+
const zone_offset_cache = Object.create(null);
|
|
21
21
|
function DOY(d) {
|
|
22
22
|
return ((d - new Date(d.getFullYear(), 0, 0)) / 86400000) | 0;
|
|
23
23
|
}
|
|
24
24
|
function toZone(date, zone) {
|
|
25
25
|
const ckey = `${zone}:${date.getUTCFullYear()}${DOY(date)}`;
|
|
26
|
-
if (zone_offset_cache
|
|
27
|
-
return new Date(date.getTime() + zone_offset_cache
|
|
26
|
+
if (zone_offset_cache[ckey] !== undefined)
|
|
27
|
+
return new Date(date.getTime() + zone_offset_cache[ckey]);
|
|
28
28
|
const client_time = date.getTime();
|
|
29
|
-
let zone_time =
|
|
29
|
+
let zone_time = null;
|
|
30
30
|
try {
|
|
31
31
|
zone_time = new Date(date.toLocaleString(DEFAULT_LOCALE, { timeZone: zone })).getTime();
|
|
32
32
|
}
|
|
33
33
|
catch (err) {
|
|
34
|
-
}
|
|
35
|
-
if (!Number.isInteger(zone_time))
|
|
36
34
|
throw new Error(`format: Invalid zone passed - ${zone}`);
|
|
35
|
+
}
|
|
37
36
|
const offset = zone_time - client_time;
|
|
38
|
-
zone_offset_cache
|
|
37
|
+
zone_offset_cache[ckey] = offset;
|
|
39
38
|
return new Date(client_time + offset);
|
|
40
39
|
}
|
|
41
40
|
function runIntl(loc, token, props, val) {
|
|
42
|
-
const hash =
|
|
43
|
-
let formatter = intl_formatters
|
|
41
|
+
const hash = loc + ':' + token;
|
|
42
|
+
let formatter = intl_formatters[hash];
|
|
44
43
|
if (!formatter) {
|
|
45
44
|
try {
|
|
46
45
|
formatter = new Intl.DateTimeFormat(loc, props);
|
|
47
|
-
intl_formatters
|
|
46
|
+
intl_formatters[hash] = formatter;
|
|
48
47
|
}
|
|
49
48
|
catch (err) {
|
|
50
49
|
throw new Error(`format: Failed to run conversion for ${token} with locale ${loc}`);
|
|
@@ -57,21 +56,46 @@ const Tokens = [
|
|
|
57
56
|
['Q', d => ((d.getMonth() + 3) / 3) | 0],
|
|
58
57
|
['MMMM', (d, loc) => runIntl(loc, 'MMMM', { month: 'long' }, d)],
|
|
59
58
|
['MMM', (d, loc) => runIntl(loc, 'MMM', { month: 'short' }, d)],
|
|
60
|
-
['MM', d =>
|
|
59
|
+
['MM', d => {
|
|
60
|
+
const val = d.getMonth() + 1;
|
|
61
|
+
return (val < 10 ? '0' : '') + val;
|
|
62
|
+
}],
|
|
61
63
|
['M', d => d.getMonth() + 1],
|
|
62
|
-
['DD', d =>
|
|
64
|
+
['DD', d => {
|
|
65
|
+
const val = d.getDate();
|
|
66
|
+
return (val < 10 ? '0' : '') + val;
|
|
67
|
+
}],
|
|
63
68
|
['D', d => d.getDate()],
|
|
64
69
|
['dddd', (d, loc) => runIntl(loc, 'dddd', { weekday: 'long' }, d)],
|
|
65
70
|
['ddd', (d, loc) => runIntl(loc, 'ddd', { weekday: 'short' }, d)],
|
|
66
|
-
['HH', d =>
|
|
71
|
+
['HH', d => {
|
|
72
|
+
const val = d.getHours();
|
|
73
|
+
return (val < 10 ? '0' : '') + val;
|
|
74
|
+
}],
|
|
67
75
|
['H', d => d.getHours()],
|
|
68
|
-
['hh', d =>
|
|
76
|
+
['hh', d => {
|
|
77
|
+
const val = ((d.getHours() + 11) % 12) + 1;
|
|
78
|
+
return (val < 10 ? '0' : '') + val;
|
|
79
|
+
}],
|
|
69
80
|
['h', d => ((d.getHours() + 11) % 12) + 1],
|
|
70
|
-
['mm', d =>
|
|
81
|
+
['mm', d => {
|
|
82
|
+
const val = d.getMinutes();
|
|
83
|
+
return (val < 10 ? '0' : '') + val;
|
|
84
|
+
}],
|
|
71
85
|
['m', d => d.getMinutes()],
|
|
72
|
-
['ss', d =>
|
|
86
|
+
['ss', d => {
|
|
87
|
+
const val = d.getSeconds();
|
|
88
|
+
return (val < 10 ? '0' : '') + val;
|
|
89
|
+
}],
|
|
73
90
|
['s', d => d.getSeconds()],
|
|
74
|
-
['SSS', d =>
|
|
91
|
+
['SSS', d => {
|
|
92
|
+
const val = d.getMilliseconds();
|
|
93
|
+
return val < 10
|
|
94
|
+
? '00' + val
|
|
95
|
+
: val < 100
|
|
96
|
+
? '0' + val
|
|
97
|
+
: val;
|
|
98
|
+
}],
|
|
75
99
|
['A', d => d.getHours() < 12 ? 'AM' : 'PM'],
|
|
76
100
|
['a', d => d.getHours() < 12 ? 'am' : 'pm'],
|
|
77
101
|
['l', (d, loc) => runIntl(loc, 'l', { dateStyle: 'short' }, d)],
|
|
@@ -79,42 +103,46 @@ const Tokens = [
|
|
|
79
103
|
['t', (d, loc) => runIntl(loc, 't', { timeStyle: 'short' }, d)],
|
|
80
104
|
['T', (d, loc) => runIntl(loc, 'T', { timeStyle: 'medium' }, d)],
|
|
81
105
|
]
|
|
82
|
-
.sort((a, b) => a[0].length > b[0].length ? -1 : 1)
|
|
83
|
-
.map((el) => [el[0], new RegExp(el[0], 'g'), el[1]]);
|
|
106
|
+
.sort((a, b) => a[0].length > b[0].length ? -1 : 1);
|
|
84
107
|
function getSpecChain(spec) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
let cursor;
|
|
90
|
-
let spec_cursor = spec;
|
|
108
|
+
if (spec_cache[spec] !== undefined)
|
|
109
|
+
return spec_cache[spec];
|
|
110
|
+
const spec_chain = [];
|
|
111
|
+
const matched_positions = new Set();
|
|
91
112
|
for (let i = 0; i < Tokens.length; i++) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
113
|
+
const [token] = Tokens[i];
|
|
114
|
+
let pos = spec.indexOf(token);
|
|
115
|
+
const token_len = token.length;
|
|
116
|
+
while (pos !== -1) {
|
|
117
|
+
if (!matched_positions.has(pos)) {
|
|
118
|
+
spec_chain.push(Tokens[i]);
|
|
119
|
+
for (let j = 0; j < token_len; j++) {
|
|
120
|
+
matched_positions.add(pos + j);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
pos = spec.indexOf(token, pos + 1);
|
|
124
|
+
}
|
|
97
125
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
return spec_chain;
|
|
126
|
+
const result = spec_chain.length ? spec_chain : null;
|
|
127
|
+
spec_cache[spec] = result;
|
|
128
|
+
return result;
|
|
102
129
|
}
|
|
103
130
|
function format(val, spec, locale = DEFAULT_LOCALE, zone = DEFAULT_TZ) {
|
|
104
131
|
if (!(0, is_1.isDate)(val))
|
|
105
132
|
throw new TypeError('format: val must be a Date');
|
|
106
|
-
if (typeof spec !== 'string'
|
|
107
|
-
throw new TypeError('format: spec must be a
|
|
108
|
-
if (typeof locale !== 'string'
|
|
109
|
-
throw new TypeError('format: locale must be a
|
|
110
|
-
if (typeof zone !== 'string'
|
|
111
|
-
throw new TypeError('format: zone must be a
|
|
133
|
+
if (typeof spec !== 'string')
|
|
134
|
+
throw new TypeError('format: spec must be a string');
|
|
135
|
+
if (typeof locale !== 'string')
|
|
136
|
+
throw new TypeError('format: locale must be a string');
|
|
137
|
+
if (typeof zone !== 'string')
|
|
138
|
+
throw new TypeError('format: zone must be a string');
|
|
112
139
|
let formatted_string = spec;
|
|
113
140
|
const escaped_acc = [];
|
|
141
|
+
let escaped_count = 0;
|
|
114
142
|
if (formatted_string.indexOf('[') >= 0) {
|
|
115
143
|
formatted_string = formatted_string.replace(escape_rgx, match => {
|
|
116
|
-
const escape_token =
|
|
117
|
-
escaped_acc.push([escape_token, match.
|
|
144
|
+
const escape_token = '$R' + escaped_count++ + '$';
|
|
145
|
+
escaped_acc.push([escape_token, match.slice(1, -1)]);
|
|
118
146
|
return escape_token;
|
|
119
147
|
});
|
|
120
148
|
}
|
|
@@ -123,11 +151,17 @@ function format(val, spec, locale = DEFAULT_LOCALE, zone = DEFAULT_TZ) {
|
|
|
123
151
|
return val.toISOString();
|
|
124
152
|
const d = toZone(val, zone);
|
|
125
153
|
for (let i = 0; i < spec_chain.length; i++) {
|
|
126
|
-
const
|
|
127
|
-
|
|
154
|
+
const [token, formatter] = spec_chain[i];
|
|
155
|
+
let pos = formatted_string.indexOf(token);
|
|
156
|
+
while (pos !== -1) {
|
|
157
|
+
formatted_string = formatted_string.slice(0, pos) +
|
|
158
|
+
formatter(d, locale) +
|
|
159
|
+
formatted_string.slice(pos + token.length);
|
|
160
|
+
pos = formatted_string.indexOf(token, pos + token.length);
|
|
161
|
+
}
|
|
128
162
|
}
|
|
129
|
-
if (
|
|
130
|
-
for (let i = 0; i <
|
|
163
|
+
if (escaped_count) {
|
|
164
|
+
for (let i = 0; i < escaped_count; i++) {
|
|
131
165
|
const escape_token = escaped_acc[i];
|
|
132
166
|
formatted_string = formatted_string.replace(escape_token[0], escape_token[1]);
|
|
133
167
|
}
|
package/date/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { addUTC } from './addUTC';
|
|
|
2
2
|
import { diff } from './diff';
|
|
3
3
|
import { endOfUTC } from './endOfUTC';
|
|
4
4
|
import { format } from './format';
|
|
5
|
+
import { isDateFormat } from './isFormat';
|
|
5
6
|
import { isDate } from './is';
|
|
6
7
|
import { nowUnix } from './nowUnix';
|
|
7
8
|
import { nowUnixMs } from './nowUnixMs';
|
|
@@ -9,4 +10,4 @@ import { setTimeUTC } from './setTimeUTC';
|
|
|
9
10
|
import { startOfUTC } from './startOfUTC';
|
|
10
11
|
import { toUnix } from './toUnix';
|
|
11
12
|
import { toUTC } from './toUTC';
|
|
12
|
-
export { addUTC, diff, endOfUTC, format, isDate, isDate as is, nowUnix, nowUnixMs, setTimeUTC, startOfUTC, toUnix, toUTC };
|
|
13
|
+
export { addUTC, diff, endOfUTC, format, isDateFormat as isFormat, isDateFormat, isDate, isDate as is, nowUnix, nowUnixMs, setTimeUTC, startOfUTC, toUnix, toUTC };
|
package/date/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.toUTC = exports.toUnix = exports.startOfUTC = exports.setTimeUTC = exports.nowUnixMs = exports.nowUnix = exports.is = exports.isDate = exports.format = exports.endOfUTC = exports.diff = exports.addUTC = void 0;
|
|
3
|
+
exports.toUTC = exports.toUnix = exports.startOfUTC = exports.setTimeUTC = exports.nowUnixMs = exports.nowUnix = exports.is = exports.isDate = exports.isDateFormat = exports.isFormat = exports.format = exports.endOfUTC = exports.diff = exports.addUTC = void 0;
|
|
4
4
|
const addUTC_1 = require("./addUTC");
|
|
5
5
|
Object.defineProperty(exports, "addUTC", { enumerable: true, get: function () { return addUTC_1.addUTC; } });
|
|
6
6
|
const diff_1 = require("./diff");
|
|
@@ -9,6 +9,9 @@ const endOfUTC_1 = require("./endOfUTC");
|
|
|
9
9
|
Object.defineProperty(exports, "endOfUTC", { enumerable: true, get: function () { return endOfUTC_1.endOfUTC; } });
|
|
10
10
|
const format_1 = require("./format");
|
|
11
11
|
Object.defineProperty(exports, "format", { enumerable: true, get: function () { return format_1.format; } });
|
|
12
|
+
const isFormat_1 = require("./isFormat");
|
|
13
|
+
Object.defineProperty(exports, "isFormat", { enumerable: true, get: function () { return isFormat_1.isDateFormat; } });
|
|
14
|
+
Object.defineProperty(exports, "isDateFormat", { enumerable: true, get: function () { return isFormat_1.isDateFormat; } });
|
|
12
15
|
const is_1 = require("./is");
|
|
13
16
|
Object.defineProperty(exports, "isDate", { enumerable: true, get: function () { return is_1.isDate; } });
|
|
14
17
|
Object.defineProperty(exports, "is", { enumerable: true, get: function () { return is_1.isDate; } });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if a given string is in a particular format
|
|
3
|
+
* Eg:
|
|
4
|
+
* isDateFormat('2024-02-09', 'YYYY-MM-DD'); // true
|
|
5
|
+
* isDateFormat('2024-02-09T14:30', 'YYYY-MM-DD'); // false
|
|
6
|
+
*
|
|
7
|
+
* @param {unknown} input - String to format (eg: '2024-08-01')
|
|
8
|
+
* @param {string} spec - Spec to validate (Eg: 'YYYY-MM-DD')
|
|
9
|
+
* @returns {boolean} Whether or not the input is valid according to the spec
|
|
10
|
+
*/
|
|
11
|
+
declare function isDateFormat(input: unknown, spec: string): input is string;
|
|
12
|
+
export { isDateFormat, isDateFormat as default };
|
package/date/isFormat.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isDateFormat = isDateFormat;
|
|
4
|
+
exports.default = isDateFormat;
|
|
5
|
+
const SPECIAL_CHARS = /[.*+?^${}()|[\]\\]/g;
|
|
6
|
+
const TOKENS = [
|
|
7
|
+
['YYYY', /\d{4}/.source, (raw, context) => {
|
|
8
|
+
context.year = parseInt(raw, 10);
|
|
9
|
+
return context.year > 0;
|
|
10
|
+
}],
|
|
11
|
+
['MM', /(?:0[1-9]|1[0-2])/.source, (raw, context) => {
|
|
12
|
+
context.month = parseInt(raw, 10);
|
|
13
|
+
return context.month >= 1 && context.month <= 12;
|
|
14
|
+
}],
|
|
15
|
+
['DD', /(?:0[1-9]|[12][0-9]|3[01])/.source, (raw, context) => {
|
|
16
|
+
context.day = parseInt(raw, 10);
|
|
17
|
+
return context.day >= 1 && context.day <= 31;
|
|
18
|
+
}],
|
|
19
|
+
['HH', /(?:[01][0-9]|2[0-3])/.source, (raw, context) => {
|
|
20
|
+
context.hour = parseInt(raw, 10);
|
|
21
|
+
return context.hour >= 0 && context.hour <= 23;
|
|
22
|
+
}],
|
|
23
|
+
['mm', /[0-5][0-9]/.source, () => true],
|
|
24
|
+
['ss', /[0-5][0-9]/.source, () => true],
|
|
25
|
+
['SSS', /\d{3}/.source, () => true],
|
|
26
|
+
['Q', /[1-4]/.source, () => true],
|
|
27
|
+
['A', /(?:AM|PM)/.source, (raw, context) => {
|
|
28
|
+
context.is12 = 1;
|
|
29
|
+
return raw === 'AM' || raw === 'PM';
|
|
30
|
+
}],
|
|
31
|
+
['a', /(?:am|pm)/.source, (raw, context) => {
|
|
32
|
+
context.is12 = 1;
|
|
33
|
+
return raw === 'am' || raw === 'pm';
|
|
34
|
+
}],
|
|
35
|
+
['Z', /Z|[+-](?:0[0-9]|1[0-4]):[0-5][0-9]/.source, raw => {
|
|
36
|
+
if (raw === 'Z')
|
|
37
|
+
return true;
|
|
38
|
+
let hour = parseInt(raw[1] + raw[2], 10);
|
|
39
|
+
if (raw[0] === '-')
|
|
40
|
+
hour = -hour;
|
|
41
|
+
const minutes = parseInt(raw[4] + raw[5], 10);
|
|
42
|
+
if (hour === 14 || hour === -12)
|
|
43
|
+
return minutes === 0;
|
|
44
|
+
return hour >= -11 && hour < 14 && [0, 15, 30, 45].indexOf(minutes) >= 0;
|
|
45
|
+
}],
|
|
46
|
+
];
|
|
47
|
+
const SPEC_ALIASES = {
|
|
48
|
+
ISO: 'YYYY-MM-DDTHH:mm:ss.SSSZ',
|
|
49
|
+
};
|
|
50
|
+
const spec_pat_cache = {};
|
|
51
|
+
function compileSpec(spec) {
|
|
52
|
+
if (spec in spec_pat_cache)
|
|
53
|
+
return spec_pat_cache[spec];
|
|
54
|
+
const tokens = [];
|
|
55
|
+
let pat = '';
|
|
56
|
+
let cursor = 0;
|
|
57
|
+
while (cursor < spec.length) {
|
|
58
|
+
if (spec[cursor] === '[') {
|
|
59
|
+
const end_idx = spec.indexOf(']', cursor);
|
|
60
|
+
if (end_idx === -1)
|
|
61
|
+
throw new Error('isDateFormat: Unmatched [ in format string');
|
|
62
|
+
pat += spec.slice(cursor + 1, end_idx).replace(SPECIAL_CHARS, '\\$&');
|
|
63
|
+
cursor = end_idx + 1;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
const token_idx = TOKENS.findIndex(([token_key]) => spec.startsWith(token_key, cursor));
|
|
67
|
+
if (token_idx >= 0) {
|
|
68
|
+
const [token_key, token_rgx] = TOKENS[token_idx];
|
|
69
|
+
pat += '(' + token_rgx + ')';
|
|
70
|
+
tokens.push(token_idx);
|
|
71
|
+
cursor += token_key.length;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
pat += spec[cursor].replace(SPECIAL_CHARS, '\\$&');
|
|
75
|
+
cursor++;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
spec_pat_cache[spec] = { rgx: RegExp('^' + pat + '$'), tokens };
|
|
80
|
+
return spec_pat_cache[spec];
|
|
81
|
+
}
|
|
82
|
+
function isDateFormat(input, spec) {
|
|
83
|
+
if (typeof input !== 'string' || input.trim().length === 0) {
|
|
84
|
+
throw new TypeError('isDateFormat: input must be a non-empty string');
|
|
85
|
+
}
|
|
86
|
+
if (typeof spec !== 'string') {
|
|
87
|
+
throw new TypeError('isDateFormat: spec must be a string');
|
|
88
|
+
}
|
|
89
|
+
const { tokens, rgx } = compileSpec(SPEC_ALIASES[spec] || spec);
|
|
90
|
+
if (!tokens.length)
|
|
91
|
+
return false;
|
|
92
|
+
const patMatch = rgx.exec(input);
|
|
93
|
+
if (!patMatch)
|
|
94
|
+
return false;
|
|
95
|
+
const matches = patMatch.slice(1);
|
|
96
|
+
const context = {};
|
|
97
|
+
for (let i = 0; i < matches.length; i++) {
|
|
98
|
+
if (!TOKENS[tokens[i]][2](matches[i], context))
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
const { is12, day, month, year } = context;
|
|
102
|
+
if (day && month) {
|
|
103
|
+
const date = new Date(year || 2024, month - 1, day);
|
|
104
|
+
if (date.getDate() !== day || date.getMonth() !== month - 1)
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
if (is12 && 'hour' in context && context.hour > 11)
|
|
108
|
+
return false;
|
|
109
|
+
return true;
|
|
110
|
+
}
|
package/deep/freeze.js
CHANGED
package/deep/get.d.ts
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
* Get a property's value deep inside the structure of an array/object
|
|
3
3
|
*
|
|
4
4
|
* Example:
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
5
|
+
* const myObj = {
|
|
6
|
+
* a: 2,
|
|
7
|
+
* b: [
|
|
8
|
+
* {price : 2},
|
|
9
|
+
* {price : 4},
|
|
10
|
+
* ],
|
|
11
|
+
* };
|
|
12
|
+
* deepGet(myObj, 'b[0].price');
|
|
13
13
|
* Output:
|
|
14
|
-
*
|
|
14
|
+
* 2
|
|
15
15
|
*
|
|
16
16
|
* @param val - Object/Array to get the value from
|
|
17
17
|
* @param path - Path string to deeply get the value at
|
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
* @returns Value stored at property or undefined
|
|
21
21
|
* @throws {TypeError}
|
|
22
22
|
*/
|
|
23
|
-
|
|
23
|
+
type ObjectType = {
|
|
24
24
|
[key: string]: any;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
}[] |
|
|
25
|
+
};
|
|
26
|
+
type ArrayType = any[];
|
|
27
|
+
type DeepGetResult<T extends ObjectType | ArrayType, P extends string> = P extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends ObjectType | ArrayType ? DeepGetResult<T[Key], Rest> : undefined : T extends ArrayType ? number extends keyof T ? DeepGetResult<T[number], Rest> : undefined : undefined : P extends `${infer Key}[${infer Index}]` ? Key extends keyof T ? T[Key] extends ArrayType ? Index extends `${number}` ? DeepGetResult<T[Key][number], ''> : undefined : undefined : T extends ArrayType ? number extends keyof T ? DeepGetResult<T[number], `[${Index}]`> : undefined : undefined : P extends keyof T ? T[P] : T extends ArrayType ? number extends keyof T ? T[number] : undefined : undefined;
|
|
28
|
+
declare function deepGet<T extends ObjectType | ArrayType, P extends string>(obj: T, path: P, get_parent?: boolean): DeepGetResult<T, P> | undefined;
|
|
28
29
|
export { deepGet, deepGet as default };
|
package/deep/get.js
CHANGED
|
@@ -9,34 +9,56 @@ function deepGet(obj, path, get_parent = false) {
|
|
|
9
9
|
if (typeof path !== 'string')
|
|
10
10
|
throw new TypeError('No path was given');
|
|
11
11
|
const path_s = path.trim();
|
|
12
|
-
|
|
12
|
+
const path_len = path_s.length;
|
|
13
|
+
if (!path_len)
|
|
13
14
|
throw new TypeError('No path was given');
|
|
14
|
-
const parts =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
const parts = [];
|
|
16
|
+
let cursor_part = '';
|
|
17
|
+
let in_bracket = false;
|
|
18
|
+
for (let i = 0; i < path_len; i++) {
|
|
19
|
+
const char = path_s[i];
|
|
20
|
+
if (char === '[' || char === ']') {
|
|
21
|
+
in_bracket = !in_bracket;
|
|
22
|
+
if (cursor_part) {
|
|
23
|
+
parts.push(cursor_part);
|
|
24
|
+
cursor_part = '';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else if (char === '.' && !in_bracket) {
|
|
28
|
+
if (cursor_part) {
|
|
29
|
+
parts.push(cursor_part);
|
|
30
|
+
cursor_part = '';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
cursor_part += char;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (cursor_part)
|
|
38
|
+
parts.push(cursor_part);
|
|
39
|
+
let len = parts.length;
|
|
40
|
+
if (!len || (len === 1 && get_parent))
|
|
20
41
|
return obj;
|
|
21
|
-
if (get_parent)
|
|
42
|
+
if (get_parent) {
|
|
22
43
|
parts.pop();
|
|
44
|
+
len -= 1;
|
|
45
|
+
}
|
|
23
46
|
let cursor = obj;
|
|
24
|
-
|
|
47
|
+
for (let i = 0; i < len; i++) {
|
|
25
48
|
if (Array.isArray(cursor)) {
|
|
26
|
-
const ix = parseInt(parts
|
|
27
|
-
if (
|
|
49
|
+
const ix = parseInt(parts[i], 10);
|
|
50
|
+
if (ix < 0 || ix > cursor.length - 1)
|
|
28
51
|
return undefined;
|
|
29
52
|
cursor = cursor[ix];
|
|
30
53
|
}
|
|
31
54
|
else if (Object.prototype.toString.call(cursor) === '[object Object]') {
|
|
32
|
-
|
|
33
|
-
if (cursor
|
|
55
|
+
cursor = cursor[parts[i]];
|
|
56
|
+
if (cursor === undefined)
|
|
34
57
|
return undefined;
|
|
35
|
-
cursor = cursor[key];
|
|
36
58
|
}
|
|
37
|
-
|
|
38
|
-
parts.length)
|
|
59
|
+
else {
|
|
39
60
|
return undefined;
|
|
61
|
+
}
|
|
40
62
|
}
|
|
41
63
|
return cursor;
|
|
42
64
|
}
|
package/deep/seal.js
CHANGED
package/equal.js
CHANGED
|
@@ -4,9 +4,10 @@ exports.equal = equal;
|
|
|
4
4
|
exports.default = equal;
|
|
5
5
|
const isNumericalNaN_1 = require("./number/isNumericalNaN");
|
|
6
6
|
function isArrayEqual(a, b) {
|
|
7
|
-
|
|
7
|
+
const a_len = a.length;
|
|
8
|
+
if (a_len !== b.length)
|
|
8
9
|
return false;
|
|
9
|
-
for (let i =
|
|
10
|
+
for (let i = a_len - 1; i >= 0; i--) {
|
|
10
11
|
if (equal(a[i], b[i]))
|
|
11
12
|
continue;
|
|
12
13
|
return false;
|
|
@@ -15,9 +16,10 @@ function isArrayEqual(a, b) {
|
|
|
15
16
|
}
|
|
16
17
|
function isObjectEqual(a, b) {
|
|
17
18
|
const keys_a = Object.keys(a);
|
|
18
|
-
|
|
19
|
+
const keys_a_len = keys_a.length;
|
|
20
|
+
if (keys_a_len !== Object.keys(b).length)
|
|
19
21
|
return false;
|
|
20
|
-
for (let i =
|
|
22
|
+
for (let i = keys_a_len - 1; i >= 0; i--) {
|
|
21
23
|
if (equal(a[keys_a[i]], b[keys_a[i]]))
|
|
22
24
|
continue;
|
|
23
25
|
return false;
|
package/hash/fnv1A.js
CHANGED
|
@@ -28,11 +28,11 @@ function fnv1A(data, offset = FNV_32) {
|
|
|
28
28
|
if (data === null) {
|
|
29
29
|
sanitized = REPL_NULL;
|
|
30
30
|
}
|
|
31
|
-
else if (Array.isArray(data) ||
|
|
31
|
+
else if (Array.isArray(data) || Object.prototype.toString.call(data) === '[object Object]') {
|
|
32
32
|
sanitized = JSON.stringify(data);
|
|
33
33
|
}
|
|
34
34
|
else if (data instanceof RegExp) {
|
|
35
|
-
sanitized = data
|
|
35
|
+
sanitized = String(data);
|
|
36
36
|
}
|
|
37
37
|
else if (data instanceof Date) {
|
|
38
38
|
sanitized = String(data.getTime());
|
package/index.d.ts
CHANGED
|
@@ -147,6 +147,10 @@ declare module "date/format" {
|
|
|
147
147
|
function format(val: Date, spec: string, locale?: string, zone?: string): string;
|
|
148
148
|
export { format, format as default };
|
|
149
149
|
}
|
|
150
|
+
declare module "date/isFormat" {
|
|
151
|
+
function isDateFormat(input: unknown, spec: string): input is string;
|
|
152
|
+
export { isDateFormat, isDateFormat as default };
|
|
153
|
+
}
|
|
150
154
|
declare module "date/nowUnix" {
|
|
151
155
|
function nowUnix(): number;
|
|
152
156
|
export { nowUnix, nowUnix as default };
|
|
@@ -186,6 +190,7 @@ declare module "date/index" {
|
|
|
186
190
|
import { diff } from "date/diff";
|
|
187
191
|
import { endOfUTC } from "date/endOfUTC";
|
|
188
192
|
import { format } from "date/format";
|
|
193
|
+
import { isDateFormat } from "date/isFormat";
|
|
189
194
|
import { isDate } from "date/is";
|
|
190
195
|
import { nowUnix } from "date/nowUnix";
|
|
191
196
|
import { nowUnixMs } from "date/nowUnixMs";
|
|
@@ -193,7 +198,7 @@ declare module "date/index" {
|
|
|
193
198
|
import { startOfUTC } from "date/startOfUTC";
|
|
194
199
|
import { toUnix } from "date/toUnix";
|
|
195
200
|
import { toUTC } from "date/toUTC";
|
|
196
|
-
export { addUTC, diff, endOfUTC, format, isDate, isDate as is, nowUnix, nowUnixMs, setTimeUTC, startOfUTC, toUnix, toUTC };
|
|
201
|
+
export { addUTC, diff, endOfUTC, format, isDateFormat as isFormat, isDateFormat, isDate, isDate as is, nowUnix, nowUnixMs, setTimeUTC, startOfUTC, toUnix, toUTC };
|
|
197
202
|
}
|
|
198
203
|
declare module "formdata/is" {
|
|
199
204
|
function isFormData(val: unknown): val is FormData;
|
|
@@ -272,35 +277,29 @@ declare module "object/define" {
|
|
|
272
277
|
export { define, define as default };
|
|
273
278
|
}
|
|
274
279
|
declare module "object/merge" {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}, source?: {
|
|
278
|
-
[key: string]: any;
|
|
279
|
-
}): {
|
|
280
|
-
[key: string]: any;
|
|
280
|
+
type MergeOptions = {
|
|
281
|
+
union?: boolean;
|
|
281
282
|
};
|
|
283
|
+
function merge(target: Record<string, any>, source?: Record<string, any> | Record<string, any>[], opts?: MergeOptions): Record<string, any>;
|
|
282
284
|
export { merge, merge as default };
|
|
283
285
|
}
|
|
284
286
|
declare module "deep/get" {
|
|
285
|
-
|
|
286
|
-
[key: string]: any;
|
|
287
|
-
} | {
|
|
287
|
+
type ObjectType = {
|
|
288
288
|
[key: string]: any;
|
|
289
|
-
}
|
|
289
|
+
};
|
|
290
|
+
type ArrayType = any[];
|
|
291
|
+
type DeepGetResult<T extends ObjectType | ArrayType, P extends string> = P extends `${infer Key}.${infer Rest}` ? Key extends keyof T ? T[Key] extends ObjectType | ArrayType ? DeepGetResult<T[Key], Rest> : undefined : T extends ArrayType ? number extends keyof T ? DeepGetResult<T[number], Rest> : undefined : undefined : P extends `${infer Key}[${infer Index}]` ? Key extends keyof T ? T[Key] extends ArrayType ? Index extends `${number}` ? DeepGetResult<T[Key][number], ''> : undefined : undefined : T extends ArrayType ? number extends keyof T ? DeepGetResult<T[number], `[${Index}]`> : undefined : undefined : P extends keyof T ? T[P] : T extends ArrayType ? number extends keyof T ? T[number] : undefined : undefined;
|
|
292
|
+
function deepGet<T extends ObjectType | ArrayType, P extends string>(obj: T, path: P, get_parent?: boolean): DeepGetResult<T, P> | undefined;
|
|
290
293
|
export { deepGet, deepGet as default };
|
|
291
294
|
}
|
|
292
|
-
declare module "deep/set" {
|
|
293
|
-
function deepSet(obj: {
|
|
294
|
-
[key: string]: any;
|
|
295
|
-
} | {
|
|
296
|
-
[key: string]: any;
|
|
297
|
-
}[] | any[], path: string, value: any, define?: boolean): boolean;
|
|
298
|
-
export { deepSet, deepSet as default };
|
|
299
|
-
}
|
|
300
295
|
declare module "object/pick" {
|
|
301
|
-
|
|
296
|
+
type ObjectType = {
|
|
302
297
|
[key: string]: any;
|
|
303
|
-
}
|
|
298
|
+
};
|
|
299
|
+
type DottedKeys<T> = (T extends ObjectType ? {
|
|
300
|
+
[K in keyof T & string]: T[K] extends ObjectType ? K | `${K}.${DottedKeys<T[K]>}` : K;
|
|
301
|
+
}[keyof T & string] : string) & string;
|
|
302
|
+
function pick<T extends Record<string, any>, K extends DottedKeys<T>>(obj: T, keys: K[]): {
|
|
304
303
|
[key: string]: any;
|
|
305
304
|
};
|
|
306
305
|
export { pick, pick as default };
|
|
@@ -525,6 +524,14 @@ declare module "deep/seal" {
|
|
|
525
524
|
function deepSeal<T extends deepInput>(obj: T): Sealed<T>;
|
|
526
525
|
export { deepSeal, deepSeal as default };
|
|
527
526
|
}
|
|
527
|
+
declare module "deep/set" {
|
|
528
|
+
function deepSet(obj: {
|
|
529
|
+
[key: string]: any;
|
|
530
|
+
} | {
|
|
531
|
+
[key: string]: any;
|
|
532
|
+
}[] | any[], path: string, value: any, define?: boolean): boolean;
|
|
533
|
+
export { deepSet, deepSet as default };
|
|
534
|
+
}
|
|
528
535
|
declare module "deep/index" {
|
|
529
536
|
import { deepFreeze } from "deep/freeze";
|
|
530
537
|
import { deepGet } from "deep/get";
|
package/object/merge.d.ts
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
type MergeOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* Defaults to false, when passed as true it ensures all keys from both objects
|
|
4
|
+
* are available in the merged object
|
|
5
|
+
*/
|
|
6
|
+
union?: boolean;
|
|
7
|
+
};
|
|
1
8
|
/**
|
|
2
9
|
* Deep merge two objects together while ensuring nested objects also get merged,
|
|
3
10
|
* take note: this does not merge onto passed objects by reference but instead
|
|
@@ -8,11 +15,5 @@
|
|
|
8
15
|
*
|
|
9
16
|
* @returns Combined target and source objects
|
|
10
17
|
*/
|
|
11
|
-
declare function merge(target:
|
|
12
|
-
[key: string]: any;
|
|
13
|
-
}, source?: {
|
|
14
|
-
[key: string]: any;
|
|
15
|
-
}): {
|
|
16
|
-
[key: string]: any;
|
|
17
|
-
};
|
|
18
|
+
declare function merge(target: Record<string, any>, source?: Record<string, any> | Record<string, any>[], opts?: MergeOptions): Record<string, any>;
|
|
18
19
|
export { merge, merge as default };
|
package/object/merge.js
CHANGED
|
@@ -3,19 +3,33 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.merge = merge;
|
|
4
4
|
exports.default = merge;
|
|
5
5
|
const PROTO_OBJ = '[object Object]';
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
acc[key] = merge(target[key], source[key]);
|
|
6
|
+
function innerMerge(target, source, UNION) {
|
|
7
|
+
const origin = UNION ? source : target;
|
|
8
|
+
for (const key in origin) {
|
|
9
|
+
const t_key = target[key];
|
|
10
|
+
const s_key = source[key];
|
|
11
|
+
if (Object.prototype.toString.call(t_key) === PROTO_OBJ &&
|
|
12
|
+
Object.prototype.toString.call(s_key) === PROTO_OBJ) {
|
|
13
|
+
target[key] = innerMerge({ ...t_key }, s_key, UNION);
|
|
15
14
|
}
|
|
16
15
|
else {
|
|
17
|
-
|
|
16
|
+
target[key] = s_key !== undefined ? s_key : t_key;
|
|
18
17
|
}
|
|
19
18
|
}
|
|
19
|
+
return target;
|
|
20
|
+
}
|
|
21
|
+
function merge(target, source = {}, opts = {}) {
|
|
22
|
+
if (Object.prototype.toString.call(target) !== PROTO_OBJ)
|
|
23
|
+
throw new Error('object/merge: Please ensure valid target/source is passed');
|
|
24
|
+
const union = opts?.union === true;
|
|
25
|
+
const sources = Array.isArray(source) ? source : [source];
|
|
26
|
+
let acc = { ...target };
|
|
27
|
+
for (let i = 0; i < sources.length; i++) {
|
|
28
|
+
const el = sources[i];
|
|
29
|
+
if (Object.prototype.toString.call(el) !== PROTO_OBJ) {
|
|
30
|
+
throw new Error('object/merge: Please ensure valid target/source is passed');
|
|
31
|
+
}
|
|
32
|
+
acc = innerMerge(acc, el, union);
|
|
33
|
+
}
|
|
20
34
|
return acc;
|
|
21
35
|
}
|
package/object/pick.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
type ObjectType = {
|
|
2
|
+
[key: string]: any;
|
|
3
|
+
};
|
|
4
|
+
type DottedKeys<T> = (T extends ObjectType ? {
|
|
5
|
+
[K in keyof T & string]: T[K] extends ObjectType ? K | `${K}.${DottedKeys<T[K]>}` : K;
|
|
6
|
+
}[keyof T & string] : string) & string;
|
|
1
7
|
/**
|
|
2
8
|
* Returns a new object with the keys picked from the passed object
|
|
3
9
|
*
|
|
@@ -6,9 +12,7 @@
|
|
|
6
12
|
*
|
|
7
13
|
* @returns Object containing the picked keys from source object
|
|
8
14
|
*/
|
|
9
|
-
declare function pick(obj: {
|
|
10
|
-
[key: string]: any;
|
|
11
|
-
}, keys: string[]): {
|
|
15
|
+
declare function pick<T extends Record<string, any>, K extends DottedKeys<T>>(obj: T, keys: K[]): {
|
|
12
16
|
[key: string]: any;
|
|
13
17
|
};
|
|
14
18
|
export { pick, pick as default };
|
package/object/pick.js
CHANGED
|
@@ -3,8 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.pick = pick;
|
|
4
4
|
exports.default = pick;
|
|
5
5
|
const get_1 = require("../deep/get");
|
|
6
|
-
const set_1 = require("../deep/set");
|
|
7
|
-
const RGX_DEEP = /(\.|\[)/;
|
|
8
6
|
function pick(obj, keys) {
|
|
9
7
|
if (Object.prototype.toString.call(obj) !== '[object Object]' ||
|
|
10
8
|
!Array.isArray(keys) ||
|
|
@@ -20,11 +18,20 @@ function pick(obj, keys) {
|
|
|
20
18
|
sanitized = key.trim();
|
|
21
19
|
if (!sanitized.length)
|
|
22
20
|
continue;
|
|
23
|
-
if (
|
|
21
|
+
if (sanitized.indexOf('.') >= 0) {
|
|
24
22
|
val = (0, get_1.deepGet)(obj, sanitized);
|
|
25
23
|
if (val === undefined)
|
|
26
24
|
continue;
|
|
27
|
-
|
|
25
|
+
const parts = key.split('.');
|
|
26
|
+
const parts_len = parts.length;
|
|
27
|
+
let cursor = map;
|
|
28
|
+
for (let y = 0; y < parts_len - 1; y++) {
|
|
29
|
+
const part = parts[y].trim();
|
|
30
|
+
if (!cursor[part])
|
|
31
|
+
cursor[part] = {};
|
|
32
|
+
cursor = cursor[part];
|
|
33
|
+
}
|
|
34
|
+
cursor[parts[parts_len - 1].trim()] = val;
|
|
28
35
|
}
|
|
29
36
|
else if (obj[sanitized] !== undefined) {
|
|
30
37
|
map[sanitized] = obj[sanitized];
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "name": "@valkyriestudios/utils", "version": "12.
|
|
1
|
+
{ "name": "@valkyriestudios/utils", "version": "12.20.0", "description": "A collection of single-function utilities for common tasks", "author": { "name": "Peter Vermeulen", "url": "https://www.linkedin.com/in/petervermeulen1/" }, "keywords": [ "utility", "library", "javascript", "js", "node", "bun" ], "license": "MIT", "repository": { "type": "git", "url": "git+https://github.com/ValkyrieStudios/utils.git" }, "bugs": { "url": "https://github.com/ValkyrieStudios/utils/issues" }, "homepage": "https://github.com/ValkyrieStudios/utils#readme", "types": "index.d.ts" }
|
package/string/humanizeBytes.js
CHANGED
|
@@ -3,21 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.humanizeBytes = humanizeBytes;
|
|
4
4
|
exports.default = humanizeBytes;
|
|
5
5
|
const humanizeNumber_1 = require("./humanizeNumber");
|
|
6
|
-
const
|
|
6
|
+
const DEFAULT_UNITS = [' bytes', ' KB', ' MB', ' GB', ' TB', ' PB', ' EB', ' ZB', ' YB'];
|
|
7
7
|
function humanizeBytes(val, options = {}) {
|
|
8
8
|
return (0, humanizeNumber_1.humanizeNumber)(val, {
|
|
9
|
-
delim:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
separator: typeof options?.separator === 'string' && options.separator.trim().length
|
|
13
|
-
? options.separator
|
|
14
|
-
: '.',
|
|
15
|
-
precision: (0, isIntegerAboveOrEqual_1.isIntegerAboveOrEqual)(options?.precision, 0)
|
|
16
|
-
? options.precision
|
|
17
|
-
: 2,
|
|
9
|
+
delim: 'delim' in options ? options.delim : ',',
|
|
10
|
+
separator: 'separator' in options ? options.separator : '.',
|
|
11
|
+
precision: 'precision' in options ? options.precision : 2,
|
|
18
12
|
units: Array.isArray(options?.units) && options.units.length
|
|
19
13
|
? options.units
|
|
20
|
-
:
|
|
14
|
+
: DEFAULT_UNITS,
|
|
21
15
|
divider: 1024,
|
|
22
16
|
real: true,
|
|
23
17
|
});
|
package/string/humanizeNumber.js
CHANGED
|
@@ -16,31 +16,29 @@ function humanizeNumber(val, options = {}) {
|
|
|
16
16
|
: options?.units === false
|
|
17
17
|
? false
|
|
18
18
|
: DEFAULT_UNITS;
|
|
19
|
-
let normalized =
|
|
20
|
-
if (typeof val === 'string') {
|
|
21
|
-
normalized = REAL ? parseInt(val.trim(), 10) : parseFloat(val);
|
|
22
|
-
}
|
|
23
|
-
else if (Number.isFinite(val)) {
|
|
24
|
-
normalized = REAL ? Math.round(val) : val;
|
|
25
|
-
}
|
|
19
|
+
let normalized = typeof val === 'string' ? parseFloat(val.trim()) : val;
|
|
26
20
|
if (!Number.isFinite(normalized) || normalized === 0)
|
|
27
21
|
return UNITS ? `0${UNITS[0]}` : '0';
|
|
22
|
+
if (REAL)
|
|
23
|
+
normalized = Math.round(normalized);
|
|
28
24
|
const sign = normalized < 0 ? '-' : '';
|
|
29
25
|
normalized = Math.abs(normalized);
|
|
30
26
|
let unit_ix = 0;
|
|
31
27
|
if (UNITS) {
|
|
32
|
-
|
|
28
|
+
while (normalized >= DIVIDER && unit_ix < UNITS.length - 1) {
|
|
33
29
|
normalized /= DIVIDER;
|
|
30
|
+
unit_ix++;
|
|
34
31
|
}
|
|
35
32
|
}
|
|
36
33
|
const humanized = `${(0, round_1.round)(normalized, PRECISION)}`.split('.', 2);
|
|
37
|
-
const
|
|
34
|
+
const integer_part = humanized[0];
|
|
35
|
+
const integer_part_len = integer_part.length;
|
|
38
36
|
let formattedIntegerPart = '';
|
|
39
|
-
for (let i = 0; i <
|
|
40
|
-
if (i > 0 && (
|
|
37
|
+
for (let i = 0; i < integer_part_len; i++) {
|
|
38
|
+
if (i > 0 && (integer_part_len - i) % 3 === 0) {
|
|
41
39
|
formattedIntegerPart += DELIM;
|
|
42
40
|
}
|
|
43
|
-
formattedIntegerPart +=
|
|
41
|
+
formattedIntegerPart += integer_part[i];
|
|
44
42
|
}
|
|
45
|
-
return
|
|
43
|
+
return sign + formattedIntegerPart + (humanized[1] ? SEPARATOR + humanized[1] : '') + (UNITS ? UNITS[unit_ix] : '');
|
|
46
44
|
}
|
package/string/shorten.js
CHANGED
|
@@ -17,8 +17,5 @@ function shorten(val, length, postfix = '...', truncate_words = true) {
|
|
|
17
17
|
while (end > 0 && sanitized[end] !== ' ' && sanitized[end - 1] !== ' ') {
|
|
18
18
|
end--;
|
|
19
19
|
}
|
|
20
|
-
if (end === 0) {
|
|
21
|
-
return sanitized.substring(0, length) + postfix;
|
|
22
|
-
}
|
|
23
20
|
return sanitized.substring(0, end).trim() + postfix;
|
|
24
21
|
}
|