@valkyriestudios/utils 12.27.0 → 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 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/memoize(fn:Function, resolver:Function=false, memoize_for:number|false)
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, null, 5000);
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'], {trimBetween: true, trim: true}) -> '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 TRIM = opts?.trim ?? true;
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 hasVal = false;
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
- const n_el = VALTRIM ? trimmed : el;
25
- result = result + (hasVal ? DELIM : '') + (INNERTRIM ? n_el.replace(SPACE_RGX, ' ') : n_el);
26
- hasVal = true;
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
- result = result + (hasVal ? DELIM : '') + (VALROUND !== false ? (0, round_1.round)(el, VALROUND) : el);
30
- hasVal = true;
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 TRIM ? result.trim() : result;
48
+ return opts?.trim ?? true ? result.trim() : result;
34
49
  }
@@ -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();
@@ -1,2 +1,3 @@
1
+ import { LRUCache } from './LRU';
1
2
  import { memoize } from './memoize';
2
- export { memoize };
3
+ export { LRUCache, LRUCache as LRU, memoize };
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; } });
@@ -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?} memoize_for - Memoize for X milliseconds, if passed false will indefinitely memoize (default = false)
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, memoize_for?: number | false): T;
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 };
@@ -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 toUTC_1 = require("../date/toUTC");
8
- const diff_1 = require("../date/diff");
9
- function memoize(fn, resolver, memoize_for = false) {
10
- const cache_for = (0, isIntegerAbove_1.default)(memoize_for, 0) ? memoize_for : false;
11
- if ((0, isAsync_1.default)(fn)) {
12
- const memoized = async function (...args) {
13
- const key = typeof resolver === 'function' ? resolver(...args) : args[0];
14
- if (memoized.cache.has(key)) {
15
- const cached_val = memoized.cache.get(key);
16
- if (cache_for === false || (0, diff_1.default)((0, toUTC_1.default)(new Date()), cached_val.d) < cache_for) {
17
- return cached_val.r;
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
- memoized.cache.set(key, { r: result, d: (0, toUTC_1.default)(new Date()) });
21
+ cache.set(key, { r: result, ts: now });
22
22
  return result;
23
- };
24
- memoized.cache = new Map();
25
- return memoized;
26
- }
27
- else {
28
- const memoized = function (...args) {
29
- const key = typeof resolver === 'function' ? resolver(...args) : args[0];
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
- memoized.cache.set(key, { r: result, d: (0, toUTC_1.default)(new Date()) });
32
+ cache.set(key, { r: result, ts: now });
38
33
  return result;
39
34
  };
40
- memoized.cache = new Map();
41
- return memoized;
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 = Object.create(null);
25
- const spec_cache = Object.create(null);
26
- const zone_offset_cache = Object.create(null);
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
- if (zone_offset_cache[ckey] !== undefined)
59
- return new Date(time + zone_offset_cache[ckey]);
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[ckey] = offset;
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[hash];
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[hash] = formatter;
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
- if (spec_cache[spec] !== undefined)
146
- return spec_cache[spec];
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[spec] = result;
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
- if (spec in spec_pat_cache)
53
- return spec_pat_cache[spec];
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
- spec_pat_cache[spec] = { rgx: is_chunk ? RegExp(pat) : RegExp('^' + pat + '$'), tokens };
89
- return spec_pat_cache[spec];
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, memoize_for?: number | false): T;
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/object/omit.js CHANGED
@@ -9,11 +9,11 @@ function innerOmit(obj, keys) {
9
9
  const key = keys[i];
10
10
  if (typeof key !== 'string')
11
11
  continue;
12
- const [root, path] = key.trim().split('.', 2);
13
- if (path) {
12
+ const [root, ...rest] = key.trim().split('.');
13
+ if (rest.length) {
14
14
  if (!groups[root])
15
15
  groups[root] = [];
16
- groups[root].push(path);
16
+ groups[root].push(rest.join('.'));
17
17
  }
18
18
  else {
19
19
  delete result[root];
package/package.json CHANGED
@@ -1 +1 @@
1
- { "name": "@valkyriestudios/utils", "version": "12.27.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" }
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" }