@valkyriestudios/utils 12.27.1 → 12.28.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 +43 -3
- package/array/join.d.ts +7 -1
- package/array/join.js +23 -8
- package/caching/LRU.d.ts +55 -0
- package/caching/LRU.js +72 -0
- package/caching/index.d.ts +2 -1
- package/caching/index.js +4 -1
- package/caching/memoize.d.ts +3 -2
- package/caching/memoize.js +23 -29
- package/date/format.js +14 -11
- package/date/isFormat.js +8 -5
- package/index.d.ts +25 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -220,7 +220,7 @@ dedupe(['hello', 'hello', 'world', false, 'world'], {filter_fn: el => isNotEmpty
|
|
|
220
220
|
|
|
221
221
|
Take Note: The filtering is applied while deduping, ensuring O(n) performance, as such this is faster than dedupe(arr.filter(...))
|
|
222
222
|
|
|
223
|
-
### array/join(val:Array, opts:object={delim:' ',trim:true,valtrim:true,innertrim:true,valround:false})
|
|
223
|
+
### array/join(val:Array, opts:object={delim:' ',trim:true,valtrim:true,innertrim:true,valround:false,dedupe:false})
|
|
224
224
|
Concatenate the values within an array into a string, behind the scenes this will automatically filter out any value that is not a string or numerical value. For strings it will automatically trim (and remove if empty after trimming) before joining.
|
|
225
225
|
|
|
226
226
|
```typescript
|
|
@@ -231,6 +231,7 @@ join(['peter ', ' valkyrie '], {delim: '@'}); // 'peter@valkyrie'
|
|
|
231
231
|
join([user.first_name, user.last_name]); // 'John' (where user is {first_name: 'John', last_name: false})
|
|
232
232
|
join([' a', 1], {delim: '', valtrim: false, trim: false}); // ' a1'
|
|
233
233
|
join([' hello world ', 'this is peter '], {valtrim:true, innertrim: true, delim: ' '}); // 'hello world this is peter'
|
|
234
|
+
join([' prop_1 ', 'prop_2', ' prop_1', ' prop_2'], {delim: ',', dedupe: true}); // 'prop_1,prop_2'
|
|
234
235
|
```
|
|
235
236
|
|
|
236
237
|
### array/shuffle(val:Array)
|
|
@@ -365,7 +366,43 @@ isBoolean(false); // TRUE
|
|
|
365
366
|
isBoolean(true); // TRUE
|
|
366
367
|
```
|
|
367
368
|
|
|
368
|
-
### caching/
|
|
369
|
+
### caching/LRU({max_size?:number})
|
|
370
|
+
Class-based LRU (Least Recently Used) cache utility with configurable max_size (defaults to 100). The LRU cache is internally used in `caching/memoize`, `date/format`, `date/isFormat` to reduce setup times and runtime memory usage but can also be used independently.
|
|
371
|
+
|
|
372
|
+
Entries are automatically removed from cache based on the max size of the cache and how recently they were used
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
import LRU from '@valkyriestudios/utils/caching/LRU';
|
|
376
|
+
|
|
377
|
+
const cache = new LRU({max_size: 10});
|
|
378
|
+
|
|
379
|
+
/* .set sets a value */
|
|
380
|
+
cache.set('hello', 'World');
|
|
381
|
+
|
|
382
|
+
/* .has checks if a value exists */
|
|
383
|
+
cache.has('hello'); // true
|
|
384
|
+
cache.has('holle'); // false
|
|
385
|
+
|
|
386
|
+
/* .get retrieves the value */
|
|
387
|
+
console.log(cache.get('hello')); // world
|
|
388
|
+
|
|
389
|
+
/* .del deletes a key */
|
|
390
|
+
cache.del('hello');
|
|
391
|
+
console.log(cache.get('hello')); // undefined
|
|
392
|
+
|
|
393
|
+
/* .clear clears the entire cache */
|
|
394
|
+
cache.clear();
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Take Note: The cache max_size can be reconfigured at runtime, eg:
|
|
398
|
+
```typescript
|
|
399
|
+
import LRU from '@valkyriestudios/utils/caching/LRU';
|
|
400
|
+
|
|
401
|
+
const cache = new LRU({max_size: 10});
|
|
402
|
+
cache.max_size = 20;
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### caching/memoize(fn:Function, resolver:Function=false, cache_duration_ms?:number|false = false, cache_max_size?:number = 100)
|
|
369
406
|
memoize the output of a function. An optional resolver function can be passed which allows custom cache key generation.
|
|
370
407
|
|
|
371
408
|
```typescript
|
|
@@ -390,13 +427,16 @@ await memoized('123456'); /* Original function will be called */
|
|
|
390
427
|
await memoized('123456'); /* Original function will not be called and memoized cache will be returned */
|
|
391
428
|
|
|
392
429
|
/* Async with cache busting after 5 seconds */
|
|
393
|
-
const memoized = memoize(retrieveUser,
|
|
430
|
+
const memoized = memoize(retrieveUser, undefined, 5000);
|
|
394
431
|
await memoized('123456'); /* Original function will be called */
|
|
395
432
|
await memoized('123456'); /* Original function will not be called and memoized cache will be returned */
|
|
396
433
|
|
|
397
434
|
... (some time longer than 5 seconds passes)
|
|
398
435
|
|
|
399
436
|
await memoized('123456'); /* Original function will be called and re-cached */
|
|
437
|
+
|
|
438
|
+
/* Async with cache busting after 60 seconds and a max cache size of 50 entries*/
|
|
439
|
+
const memoized = memoize(retrieveUser, undefined, 60000, 50);
|
|
400
440
|
```
|
|
401
441
|
|
|
402
442
|
### date/is(val:unknown)
|
package/array/join.d.ts
CHANGED
|
@@ -5,6 +5,12 @@ interface joinOptions {
|
|
|
5
5
|
* eg: join(['hello', 'world', {delim: '_'}]) -> 'hello_world'
|
|
6
6
|
*/
|
|
7
7
|
delim?: string;
|
|
8
|
+
/**
|
|
9
|
+
* Dedupe the provided array while joining or not?
|
|
10
|
+
* (default=false)
|
|
11
|
+
* eg: join(['val_a', 'val_b', 'val_'a], {dedupe: true, delim:','}) -> 'val_a,val_b'
|
|
12
|
+
*/
|
|
13
|
+
dedupe?: boolean;
|
|
8
14
|
/**
|
|
9
15
|
* Trim after joining or not
|
|
10
16
|
* (default=true)
|
|
@@ -14,7 +20,7 @@ interface joinOptions {
|
|
|
14
20
|
/**
|
|
15
21
|
* Trim internals of values or not
|
|
16
22
|
* (default=false)
|
|
17
|
-
* eg: join([' hello world', 'this is ', 'Peter'], {
|
|
23
|
+
* eg: join([' hello world', 'this is ', 'Peter'], {innertrim: true, trim: true}) -> 'hello world this is peter'
|
|
18
24
|
*/
|
|
19
25
|
innertrim?: boolean;
|
|
20
26
|
/**
|
package/array/join.js
CHANGED
|
@@ -9,26 +9,41 @@ function join(val, opts) {
|
|
|
9
9
|
if (!Array.isArray(val) || !val.length)
|
|
10
10
|
return '';
|
|
11
11
|
const DELIM = typeof opts?.delim === 'string' ? opts.delim : ' ';
|
|
12
|
-
const
|
|
12
|
+
const DEDUPE = opts?.dedupe === true ? new Set() : null;
|
|
13
13
|
const VALTRIM = opts?.valtrim ?? true;
|
|
14
14
|
const INNERTRIM = opts?.innertrim ?? false;
|
|
15
15
|
const VALROUND = (0, isIntegerAboveOrEqual_1.isIntegerAboveOrEqual)(opts?.valround, 0) ? opts.valround : false;
|
|
16
16
|
let result = '';
|
|
17
|
-
let
|
|
17
|
+
let has_val = false;
|
|
18
18
|
for (let i = 0; i < val.length; i++) {
|
|
19
19
|
const el = val[i];
|
|
20
|
+
let n_el;
|
|
20
21
|
if (typeof el === 'string') {
|
|
21
22
|
const trimmed = el.trim();
|
|
22
23
|
if (!trimmed)
|
|
23
24
|
continue;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
n_el = VALTRIM ? trimmed : el;
|
|
26
|
+
if (INNERTRIM)
|
|
27
|
+
n_el = n_el.replace(SPACE_RGX, ' ');
|
|
27
28
|
}
|
|
28
29
|
else if (Number.isFinite(el)) {
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
n_el = '' + (VALROUND !== false ? (0, round_1.round)(el, VALROUND) : el);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (DEDUPE) {
|
|
36
|
+
if (DEDUPE.has(n_el))
|
|
37
|
+
continue;
|
|
38
|
+
DEDUPE.add(n_el);
|
|
39
|
+
}
|
|
40
|
+
if (has_val) {
|
|
41
|
+
result = result + DELIM + n_el;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
result = n_el;
|
|
45
|
+
has_val = true;
|
|
31
46
|
}
|
|
32
47
|
}
|
|
33
|
-
return
|
|
48
|
+
return opts?.trim ?? true ? result.trim() : result;
|
|
34
49
|
}
|
package/caching/LRU.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export type LRUCacheOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* Maximum amount of entries the cache can have
|
|
4
|
+
* (defaults to 100)
|
|
5
|
+
*/
|
|
6
|
+
max_size?: number;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Least-Recently-Used (LRU) Cache
|
|
10
|
+
*/
|
|
11
|
+
declare class LRUCache<K, V> {
|
|
12
|
+
#private;
|
|
13
|
+
constructor(opts?: LRUCacheOptions);
|
|
14
|
+
/**
|
|
15
|
+
* Get the currently configured max size of the cache
|
|
16
|
+
*/
|
|
17
|
+
get max_size(): number;
|
|
18
|
+
/**
|
|
19
|
+
* Reconfigure the max size of the cache
|
|
20
|
+
*
|
|
21
|
+
* @param {number} max_size - New max size
|
|
22
|
+
*/
|
|
23
|
+
set max_size(max_size: number);
|
|
24
|
+
/**
|
|
25
|
+
* Returns whether or not a key exists in cache
|
|
26
|
+
*
|
|
27
|
+
* @param {K} key - Key to retrieve
|
|
28
|
+
*/
|
|
29
|
+
has(key: K): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Retrieves a value from the cache
|
|
32
|
+
*
|
|
33
|
+
* @param {K} key - Key to retrieve
|
|
34
|
+
* @returns {V | undefined} Either the found value or undefined
|
|
35
|
+
*/
|
|
36
|
+
get(key: K): V | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Sets a value on to the cache
|
|
39
|
+
*
|
|
40
|
+
* @param {K} key - Key to set
|
|
41
|
+
* @param {V} value - Value to set for the key
|
|
42
|
+
*/
|
|
43
|
+
set(key: K, value: V): void;
|
|
44
|
+
/**
|
|
45
|
+
* Removes a single value from the cache
|
|
46
|
+
*
|
|
47
|
+
* @param {K} key - Key to remove
|
|
48
|
+
*/
|
|
49
|
+
del(key: K): void;
|
|
50
|
+
/**
|
|
51
|
+
* Clears all contents of the cache
|
|
52
|
+
*/
|
|
53
|
+
clear(): void;
|
|
54
|
+
}
|
|
55
|
+
export { LRUCache, LRUCache as default };
|
package/caching/LRU.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
3
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
6
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
|
+
};
|
|
13
|
+
var _LRUCache_cache, _LRUCache_max_size;
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.default = exports.LRUCache = void 0;
|
|
16
|
+
const is_1 = require("../object/is");
|
|
17
|
+
const isIntegerAbove_1 = require("../number/isIntegerAbove");
|
|
18
|
+
class LRUCache {
|
|
19
|
+
constructor(opts = {}) {
|
|
20
|
+
_LRUCache_cache.set(this, void 0);
|
|
21
|
+
_LRUCache_max_size.set(this, void 0);
|
|
22
|
+
const { max_size = 100 } = (0, is_1.default)(opts) ? opts : {};
|
|
23
|
+
__classPrivateFieldSet(this, _LRUCache_cache, new Map(), "f");
|
|
24
|
+
__classPrivateFieldSet(this, _LRUCache_max_size, (0, isIntegerAbove_1.default)(max_size, 0) ? max_size : 100, "f");
|
|
25
|
+
}
|
|
26
|
+
get max_size() {
|
|
27
|
+
return __classPrivateFieldGet(this, _LRUCache_max_size, "f");
|
|
28
|
+
}
|
|
29
|
+
set max_size(max_size) {
|
|
30
|
+
if (!(0, isIntegerAbove_1.default)(max_size, 0))
|
|
31
|
+
throw new Error('max_size must be a positive integer');
|
|
32
|
+
__classPrivateFieldSet(this, _LRUCache_max_size, max_size, "f");
|
|
33
|
+
if (__classPrivateFieldGet(this, _LRUCache_cache, "f").size > max_size) {
|
|
34
|
+
const excess = __classPrivateFieldGet(this, _LRUCache_cache, "f").size - max_size;
|
|
35
|
+
const keys = [...__classPrivateFieldGet(this, _LRUCache_cache, "f").keys()];
|
|
36
|
+
for (let i = 0; i < excess; i++) {
|
|
37
|
+
__classPrivateFieldGet(this, _LRUCache_cache, "f").delete(keys[i]);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
has(key) {
|
|
42
|
+
return __classPrivateFieldGet(this, _LRUCache_cache, "f").has(key);
|
|
43
|
+
}
|
|
44
|
+
get(key) {
|
|
45
|
+
const value = __classPrivateFieldGet(this, _LRUCache_cache, "f").get(key);
|
|
46
|
+
if (value === undefined)
|
|
47
|
+
return undefined;
|
|
48
|
+
__classPrivateFieldGet(this, _LRUCache_cache, "f").delete(key);
|
|
49
|
+
__classPrivateFieldGet(this, _LRUCache_cache, "f").set(key, value);
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
set(key, value) {
|
|
53
|
+
if (__classPrivateFieldGet(this, _LRUCache_cache, "f").has(key)) {
|
|
54
|
+
__classPrivateFieldGet(this, _LRUCache_cache, "f").delete(key);
|
|
55
|
+
}
|
|
56
|
+
else if (__classPrivateFieldGet(this, _LRUCache_cache, "f").size >= this.max_size) {
|
|
57
|
+
__classPrivateFieldGet(this, _LRUCache_cache, "f").delete(__classPrivateFieldGet(this, _LRUCache_cache, "f").keys().next().value);
|
|
58
|
+
}
|
|
59
|
+
__classPrivateFieldGet(this, _LRUCache_cache, "f").set(key, value);
|
|
60
|
+
}
|
|
61
|
+
del(key) {
|
|
62
|
+
if (key === undefined || !__classPrivateFieldGet(this, _LRUCache_cache, "f").has(key))
|
|
63
|
+
return;
|
|
64
|
+
__classPrivateFieldGet(this, _LRUCache_cache, "f").delete(key);
|
|
65
|
+
}
|
|
66
|
+
clear() {
|
|
67
|
+
__classPrivateFieldGet(this, _LRUCache_cache, "f").clear();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.LRUCache = LRUCache;
|
|
71
|
+
exports.default = LRUCache;
|
|
72
|
+
_LRUCache_cache = new WeakMap(), _LRUCache_max_size = new WeakMap();
|
package/caching/index.d.ts
CHANGED
package/caching/index.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.memoize = void 0;
|
|
3
|
+
exports.memoize = exports.LRU = exports.LRUCache = void 0;
|
|
4
|
+
const LRU_1 = require("./LRU");
|
|
5
|
+
Object.defineProperty(exports, "LRUCache", { enumerable: true, get: function () { return LRU_1.LRUCache; } });
|
|
6
|
+
Object.defineProperty(exports, "LRU", { enumerable: true, get: function () { return LRU_1.LRUCache; } });
|
|
4
7
|
const memoize_1 = require("./memoize");
|
|
5
8
|
Object.defineProperty(exports, "memoize", { enumerable: true, get: function () { return memoize_1.memoize; } });
|
package/caching/memoize.d.ts
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @param fn - Function to memoize
|
|
8
8
|
* @param resolver - Optional resolver function to generate cache key. If not passed the first argument is used as map key
|
|
9
|
-
* @param {false|number?}
|
|
9
|
+
* @param {false|number?} cache_duration_ms - Memoize for X milliseconds, if passed false will indefinitely memoize (default = false)
|
|
10
|
+
* @param {number?} cache_max_size - Memoize at max X entries, defaults to 100
|
|
10
11
|
*/
|
|
11
|
-
declare function memoize<T extends (...args: any[]) => unknown>(fn: T, resolver?: (...args: Parameters<T>) => any,
|
|
12
|
+
declare function memoize<T extends (...args: any[]) => unknown>(fn: T, resolver?: (...args: Parameters<T>) => any, cache_duration_ms?: number | false, cache_max_size?: number): T;
|
|
12
13
|
export { memoize, memoize as default };
|
package/caching/memoize.js
CHANGED
|
@@ -4,40 +4,34 @@ exports.memoize = memoize;
|
|
|
4
4
|
exports.default = memoize;
|
|
5
5
|
const isAsync_1 = require("../function/isAsync");
|
|
6
6
|
const isIntegerAbove_1 = require("../number/isIntegerAbove");
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
const LRU_1 = require("./LRU");
|
|
8
|
+
function memoize(fn, resolver, cache_duration_ms = false, cache_max_size = 100) {
|
|
9
|
+
const cache_duration = (0, isIntegerAbove_1.default)(cache_duration_ms, 0) ? cache_duration_ms : false;
|
|
10
|
+
const cache = new LRU_1.default({ max_size: cache_max_size });
|
|
11
|
+
const isResolverFn = typeof resolver === 'function';
|
|
12
|
+
const memoized = (0, isAsync_1.default)(fn)
|
|
13
|
+
? async function (...args) {
|
|
14
|
+
const key = isResolverFn ? resolver(...args) : args[0];
|
|
15
|
+
const cached_val = cache.get(key);
|
|
16
|
+
const now = Date.now();
|
|
17
|
+
if (cached_val !== undefined && (cache_duration === false || (now - cached_val.ts) < cache_duration)) {
|
|
18
|
+
return cached_val.r;
|
|
19
19
|
}
|
|
20
20
|
const result = await fn(...args);
|
|
21
|
-
|
|
21
|
+
cache.set(key, { r: result, ts: now });
|
|
22
22
|
return result;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (memoized.cache.has(key)) {
|
|
31
|
-
const cached_val = memoized.cache.get(key);
|
|
32
|
-
if (cache_for === false || (0, diff_1.default)((0, toUTC_1.default)(new Date()), cached_val.d) < cache_for) {
|
|
33
|
-
return cached_val.r;
|
|
34
|
-
}
|
|
23
|
+
}
|
|
24
|
+
: function (...args) {
|
|
25
|
+
const key = isResolverFn ? resolver(...args) : args[0];
|
|
26
|
+
const cached_val = cache.get(key);
|
|
27
|
+
const now = Date.now();
|
|
28
|
+
if (cached_val !== undefined && (cache_duration === false || (now - cached_val.ts) < cache_duration)) {
|
|
29
|
+
return cached_val.r;
|
|
35
30
|
}
|
|
36
31
|
const result = fn(...args);
|
|
37
|
-
|
|
32
|
+
cache.set(key, { r: result, ts: now });
|
|
38
33
|
return result;
|
|
39
34
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
35
|
+
memoized.cache = cache;
|
|
36
|
+
return memoized;
|
|
43
37
|
}
|
package/date/format.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.format = format;
|
|
4
4
|
exports.default = format;
|
|
5
5
|
const convertToDate_1 = require("./convertToDate");
|
|
6
|
+
const LRU_1 = require("../caching/LRU");
|
|
6
7
|
const WEEK_STARTS = {
|
|
7
8
|
mon: 'mon',
|
|
8
9
|
sun: 'sun',
|
|
@@ -21,9 +22,9 @@ finally {
|
|
|
21
22
|
DEFAULT_TZ = 'UTC';
|
|
22
23
|
}
|
|
23
24
|
const ESCAPE_RGX = /\[[\s\S]+?]/g;
|
|
24
|
-
const intl_formatters =
|
|
25
|
-
const spec_cache =
|
|
26
|
-
const zone_offset_cache =
|
|
25
|
+
const intl_formatters = new LRU_1.default({ max_size: 100 });
|
|
26
|
+
const spec_cache = new LRU_1.default({ max_size: 100 });
|
|
27
|
+
const zone_offset_cache = new LRU_1.default({ max_size: 100 });
|
|
27
28
|
function WeekNr(d, sow) {
|
|
28
29
|
switch (sow) {
|
|
29
30
|
case 'sun':
|
|
@@ -55,8 +56,9 @@ function toZone(d, zone) {
|
|
|
55
56
|
for (let i = 0; i <= month; i++)
|
|
56
57
|
doy += daysInMonths[i];
|
|
57
58
|
const ckey = zone + ':' + year + ':' + doy;
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
const cached = zone_offset_cache.get(ckey);
|
|
60
|
+
if (cached !== undefined)
|
|
61
|
+
return new Date(time + cached);
|
|
60
62
|
let zone_time = null;
|
|
61
63
|
try {
|
|
62
64
|
zone_time = new Date(d.toLocaleString(DEFAULT_LOCALE, { timeZone: zone })).getTime() + d.getMilliseconds();
|
|
@@ -65,16 +67,16 @@ function toZone(d, zone) {
|
|
|
65
67
|
throw new Error(`format: Invalid zone passed - ${zone}`);
|
|
66
68
|
}
|
|
67
69
|
const offset = zone_time - time;
|
|
68
|
-
zone_offset_cache
|
|
70
|
+
zone_offset_cache.set(ckey, offset);
|
|
69
71
|
return new Date(time + offset);
|
|
70
72
|
}
|
|
71
73
|
function runIntl(loc, token, props, val) {
|
|
72
74
|
const hash = loc + ':' + token;
|
|
73
|
-
let formatter = intl_formatters
|
|
75
|
+
let formatter = intl_formatters.get(hash);
|
|
74
76
|
if (!formatter) {
|
|
75
77
|
try {
|
|
76
78
|
formatter = new Intl.DateTimeFormat(loc, props);
|
|
77
|
-
intl_formatters
|
|
79
|
+
intl_formatters.set(hash, formatter);
|
|
78
80
|
}
|
|
79
81
|
catch {
|
|
80
82
|
throw new Error(`format: Failed to run conversion for ${token} with locale ${loc}`);
|
|
@@ -142,8 +144,9 @@ const Tokens = [
|
|
|
142
144
|
.map(el => [el[0], el[1], el[0].length])
|
|
143
145
|
.sort((a, b) => a[0].length > b[0].length ? -1 : 1);
|
|
144
146
|
function getSpecChain(spec) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
const cached = spec_cache.get(spec);
|
|
148
|
+
if (cached !== undefined)
|
|
149
|
+
return cached;
|
|
147
150
|
let base = spec;
|
|
148
151
|
const repl = [];
|
|
149
152
|
let repl_len = 0;
|
|
@@ -172,7 +175,7 @@ function getSpecChain(spec) {
|
|
|
172
175
|
}
|
|
173
176
|
const chain_len = chain.length;
|
|
174
177
|
const result = chain_len ? { base, chain, chain_len, repl } : null;
|
|
175
|
-
spec_cache
|
|
178
|
+
spec_cache.set(spec, result);
|
|
176
179
|
return result;
|
|
177
180
|
}
|
|
178
181
|
function format(val, spec, locale = DEFAULT_LOCALE, zone = DEFAULT_TZ, sow = DEFAULT_SOW) {
|
package/date/isFormat.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isDateFormat = isDateFormat;
|
|
4
4
|
exports.default = isDateFormat;
|
|
5
|
+
const LRU_1 = require("../caching/LRU");
|
|
5
6
|
const SPECIAL_CHARS = /[.*+?^${}()|[\]\\]/g;
|
|
6
7
|
const TOKENS = [
|
|
7
8
|
['YYYY', /\d{4}/.source, (raw, context) => {
|
|
@@ -47,10 +48,11 @@ const TOKENS = [
|
|
|
47
48
|
const SPEC_ALIASES = {
|
|
48
49
|
ISO: 'YYYY-MM-DDTHH:mm:ss{.SSS}Z',
|
|
49
50
|
};
|
|
50
|
-
const spec_pat_cache = {};
|
|
51
|
+
const spec_pat_cache = new LRU_1.default({ max_size: 100 });
|
|
51
52
|
function compileSpec(spec, is_chunk = false) {
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
let cached = spec_pat_cache.get(spec);
|
|
54
|
+
if (cached !== undefined)
|
|
55
|
+
return cached;
|
|
54
56
|
const tokens = [];
|
|
55
57
|
let pat = '';
|
|
56
58
|
let cursor = 0;
|
|
@@ -85,8 +87,9 @@ function compileSpec(spec, is_chunk = false) {
|
|
|
85
87
|
}
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
cached = { rgx: is_chunk ? RegExp(pat) : RegExp('^' + pat + '$'), tokens };
|
|
91
|
+
spec_pat_cache.set(spec, cached);
|
|
92
|
+
return cached;
|
|
90
93
|
}
|
|
91
94
|
function isDateFormat(input, spec) {
|
|
92
95
|
if (typeof input !== 'string' || input.trim().length === 0) {
|
package/index.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ declare module "number/isIntegerAboveOrEqual" {
|
|
|
28
28
|
declare module "array/join" {
|
|
29
29
|
interface joinOptions {
|
|
30
30
|
delim?: string;
|
|
31
|
+
dedupe?: boolean;
|
|
31
32
|
trim?: boolean;
|
|
32
33
|
innertrim?: boolean;
|
|
33
34
|
valtrim?: boolean;
|
|
@@ -151,6 +152,27 @@ declare module "date/endOfUTC" {
|
|
|
151
152
|
function endOfUTC(val: Date | string, key?: EndOfUTCKey): Date;
|
|
152
153
|
export { endOfUTC, endOfUTC as default };
|
|
153
154
|
}
|
|
155
|
+
declare module "number/isIntegerAbove" {
|
|
156
|
+
function isIntegerAbove(val: unknown, ref: number): val is number;
|
|
157
|
+
export { isIntegerAbove, isIntegerAbove as default };
|
|
158
|
+
}
|
|
159
|
+
declare module "caching/LRU" {
|
|
160
|
+
export type LRUCacheOptions = {
|
|
161
|
+
max_size?: number;
|
|
162
|
+
};
|
|
163
|
+
class LRUCache<K, V> {
|
|
164
|
+
#private;
|
|
165
|
+
constructor(opts?: LRUCacheOptions);
|
|
166
|
+
get max_size(): number;
|
|
167
|
+
set max_size(max_size: number);
|
|
168
|
+
has(key: K): boolean;
|
|
169
|
+
get(key: K): V | undefined;
|
|
170
|
+
set(key: K, value: V): void;
|
|
171
|
+
del(key: K): void;
|
|
172
|
+
clear(): void;
|
|
173
|
+
}
|
|
174
|
+
export { LRUCache, LRUCache as default };
|
|
175
|
+
}
|
|
154
176
|
declare module "date/format" {
|
|
155
177
|
const WEEK_STARTS: {
|
|
156
178
|
readonly mon: "mon";
|
|
@@ -253,10 +275,6 @@ declare module "function/is" {
|
|
|
253
275
|
function isFunction(val: unknown): val is (...args: unknown[]) => unknown;
|
|
254
276
|
export { isFunction, isFunction as default };
|
|
255
277
|
}
|
|
256
|
-
declare module "number/isIntegerAbove" {
|
|
257
|
-
function isIntegerAbove(val: unknown, ref: number): val is number;
|
|
258
|
-
export { isIntegerAbove, isIntegerAbove as default };
|
|
259
|
-
}
|
|
260
278
|
declare module "function/debounce" {
|
|
261
279
|
function debounce<T extends (...args: any[]) => any>(fn: T, wait: number): T & {
|
|
262
280
|
cancel: () => void;
|
|
@@ -549,12 +567,13 @@ declare module "is" {
|
|
|
549
567
|
export { Is, Is as default };
|
|
550
568
|
}
|
|
551
569
|
declare module "caching/memoize" {
|
|
552
|
-
function memoize<T extends (...args: any[]) => unknown>(fn: T, resolver?: (...args: Parameters<T>) => any,
|
|
570
|
+
function memoize<T extends (...args: any[]) => unknown>(fn: T, resolver?: (...args: Parameters<T>) => any, cache_duration_ms?: number | false, cache_max_size?: number): T;
|
|
553
571
|
export { memoize, memoize as default };
|
|
554
572
|
}
|
|
555
573
|
declare module "caching/index" {
|
|
574
|
+
import { LRUCache } from "caching/LRU";
|
|
556
575
|
import { memoize } from "caching/memoize";
|
|
557
|
-
export { memoize };
|
|
576
|
+
export { LRUCache, LRUCache as LRU, memoize };
|
|
558
577
|
}
|
|
559
578
|
declare module "deep/freeze" {
|
|
560
579
|
type deepInput = {
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "name": "@valkyriestudios/utils", "version": "12.
|
|
1
|
+
{ "name": "@valkyriestudios/utils", "version": "12.28.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" }
|