first commit
This commit is contained in:
230
node_modules/micro-memoize/CHANGELOG.md
generated
vendored
Normal file
230
node_modules/micro-memoize/CHANGELOG.md
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
# micro-memoize CHANGELOG
|
||||
|
||||
## 4.1.3
|
||||
|
||||
- [#121](https://github.com/planttheidea/micro-memoize/pull/121) - Avoid reference to broken source maps (fix for [#79](https://github.com/planttheidea/micro-memoize/issues/79))
|
||||
|
||||
## 4.1.2
|
||||
|
||||
- Republish of [#102](https://github.com/planttheidea/micro-memoize/pull/102)
|
||||
|
||||
## 4.1.1 (Bad version - do not use)
|
||||
|
||||
- [#102](https://github.com/planttheidea/micro-memoize/pull/102) - avoid publishing development-only files for less `node_modules` bloat
|
||||
|
||||
## 4.1.0
|
||||
|
||||
#### Enhancements
|
||||
|
||||
- Types now have direct exports instead of requiring the `MicroMemoize` namespace. That namespace has been labeled as deprecated, and will be removed in the next major version change in favor of the direct type exports.
|
||||
|
||||
#### Bugfixes
|
||||
|
||||
- [#97](https://github.com/planttheidea/micro-memoize/issues/97) - `src` files included in publish, and referenced from `*.d.ts` files
|
||||
- `mjs/*d.ts` files renamed to `mjs/*.d.mts` to align with NodeJS standard
|
||||
- [#101](https://github.com/planttheidea/micro-memoize/pull/101) - fixed benchmark using `mem` incorrectly for complex object parameters or multiple parameter calls
|
||||
|
||||
## 4.0.15
|
||||
|
||||
- [#99](https://github.com/planttheidea/micro-memoize/issues/99) - `mjs` import does not have typings surfaced
|
||||
|
||||
## 4.0.14
|
||||
|
||||
- Republish of [#87](https://github.com/planttheidea/micro-memoize/pull/87)
|
||||
|
||||
## 4.0.13 (Bad version - do not use)
|
||||
|
||||
- [#87](https://github.com/planttheidea/micro-memoize/pull/87) - Default generic values for exposed types, to avoid unintentional breaking changes from [#85](https://github.com/planttheidea/micro-memoize/pull/85)
|
||||
|
||||
## 4.0.12
|
||||
|
||||
- [#84](https://github.com/planttheidea/micro-memoize/pull/84) - Fix inferred typing of memoized function
|
||||
- [#85](https://github.com/planttheidea/micro-memoize/pull/85) - Follow-up on [#84](https://github.com/planttheidea/micro-memoize/pull/84), further improving inferred typing via pass-throughs.
|
||||
|
||||
## 4.0.11
|
||||
|
||||
- Fix [#79](https://github.com/planttheidea/micro-memoize/issues/79) - Sourcemaps referencing incorrect hierarchy
|
||||
|
||||
## 4.0.10
|
||||
|
||||
- Fix [#76](https://github.com/planttheidea/micro-memoize/issues/76) - `noUncheckedIndexedAccess` support on TS 4.1+
|
||||
|
||||
## 4.0.9
|
||||
|
||||
- Update npm search keywords and documentation
|
||||
|
||||
## 4.0.8
|
||||
|
||||
- Improve typings to support `strict` mode in TypeScript
|
||||
|
||||
## 4.0.7
|
||||
|
||||
- Create more targeted `getKeyIndex` helpers for more speed in each key situation
|
||||
|
||||
## 4.0.6
|
||||
|
||||
- Use standard `then` interface (`.then(onFulfilled, onRejected)`) instead of ES spec (`.then(onFulfilled).catch(onRejected)`) for broader support
|
||||
|
||||
## 4.0.5
|
||||
|
||||
- Fix failure when `getKeyIndex` is used and no keys are in the cache
|
||||
|
||||
## 4.0.4
|
||||
|
||||
- Use `.pop()` to cap cache to `maxSize` when possible (slight performance improvement)
|
||||
|
||||
## 4.0.3
|
||||
|
||||
- Namespace types under `MicroMemoize` namespace (which is how it was for `4.0.0`, but it got lost)
|
||||
|
||||
## 4.0.2
|
||||
|
||||
- Make Cache class consumable in types
|
||||
|
||||
## 4.0.1
|
||||
|
||||
- Fix types for consumption
|
||||
|
||||
## 4.0.0
|
||||
|
||||
- Update to use `Cache` class instead of plain object (~10% performance improvement)
|
||||
|
||||
#### Breaking changes
|
||||
|
||||
- `memoized.cacheSnapshot` has been deprecated in favor of `memoized.cache.snapshot`
|
||||
- Memoizing an already-memoized function no longer returns the function passed (now composes, see [Composition](README.md#composition))
|
||||
|
||||
#### Enhancements
|
||||
|
||||
- You can now compose memoized functions with their options (see [Composition](README.md#composition))
|
||||
|
||||
## 3.0.2
|
||||
|
||||
- Fix types declarations to ensure signature of `fn` passed is retained
|
||||
- Throw an error when the first parameter passed is not a function
|
||||
|
||||
## 3.0.1
|
||||
|
||||
- Fix types declaration for `Options` to allow custom keys / indices
|
||||
|
||||
## 3.0.0
|
||||
|
||||
- Rewrite in TypeScript
|
||||
- Use `rollup` for builds of all packages
|
||||
|
||||
#### BREAKING CHANGES
|
||||
|
||||
- CommonJS `require`s no longer require `.default`
|
||||
- Types contract is much stricter
|
||||
- Utility methods are no longer deep-linkable
|
||||
- Not technically exposed in the API, but was relied upon by other libraries)
|
||||
|
||||
## 2.1.2
|
||||
|
||||
- Fix issue where `isMatchingKey` was not being used with promise updater
|
||||
- Remove requirement of `Object.assign` existing globally
|
||||
- Add common use-case static handlers for up to 3 arguments, falling back to pre-existing dynamic handlers for more (faster comparison / argument cloning)
|
||||
|
||||
## 2.1.1
|
||||
|
||||
- Upgrade to babel 7
|
||||
- Add `"sideEffects": false` for better tree-shaking with webpack
|
||||
|
||||
## 2.1.0
|
||||
|
||||
- Add ESM support for NodeJS with separate [`.mjs` extension](https://nodejs.org/api/esm.html) exports
|
||||
|
||||
## 2.0.4
|
||||
|
||||
- Fix issue with recursive calls to memoized function created discrepancy between `keys` and `values` in cache
|
||||
|
||||
## 2.0.3
|
||||
|
||||
- More TypeScript typings (thanks again [@rtorr](https://github.com/rtorr))
|
||||
|
||||
## 2.0.2
|
||||
|
||||
- Fix TypeScript typings (thanks [@rtorr](https://github.com/rtorr))
|
||||
|
||||
## 2.0.1
|
||||
|
||||
- Fix TypeScript typings (thanks [@Crecket](https://github.com/Crecket))
|
||||
|
||||
## 2.0.0
|
||||
|
||||
- Add [`isMatchingKey`](#ismatchingkey) method to provide match test on entire key vs iterative equality
|
||||
|
||||
**BREAKING CHANGES**
|
||||
|
||||
- The return value from `transformKey` must be an `Array` (would previously coalesce it for you)
|
||||
|
||||
**NEW FEATURES**
|
||||
|
||||
- `isMatchingKey` will matching on entire key vs `isEqual`, which does an iterative comparison of arguments in order
|
||||
- Add `size` property to `cache`
|
||||
|
||||
## 1.8.1
|
||||
|
||||
- Fix `getKeyIndex` being passed as `memoize` for promises
|
||||
|
||||
## 1.8.0
|
||||
|
||||
- Include the memoized function itself as the third parameter to `onCacheAdd`, `onCacheChange`, and `onCacheHit` firings
|
||||
|
||||
## 1.7.0
|
||||
|
||||
- Fire `onCacheHit` and `onCacheChange` when promise functions successfully resolve
|
||||
|
||||
## 1.6.3
|
||||
|
||||
- Replace native `slice` usages with `cloneArray` utility
|
||||
|
||||
## 1.6.2
|
||||
|
||||
- Convert `dist` files to be built using [`rollup`](https://github.com/rollup/rollup) instead of webpack
|
||||
|
||||
## 1.6.1
|
||||
|
||||
- Optimize `slice` calls for key storage (performance)
|
||||
|
||||
## 1.6.0
|
||||
|
||||
- Add [`onCacheAdd`](README.md#oncacheadd) option
|
||||
- Pass through unused properties in `options` for higher-order memoization library usage
|
||||
|
||||
## 1.5.0
|
||||
|
||||
- Add [`onCacheHit`](README.md#oncachehit) option
|
||||
|
||||
## 1.4.0
|
||||
|
||||
- Add `options` as second parameter to `onCacheChanged`
|
||||
|
||||
## 1.3.2
|
||||
|
||||
- Make additional properties (`cache`, `cacheSnapshot`, `isMemoized`, `options`) configurable for higher-order memoization library usage
|
||||
|
||||
## 1.3.1
|
||||
|
||||
- Only reorder keys when matching cache entry is not first key
|
||||
|
||||
## 1.3.0
|
||||
|
||||
- Add [`onCacheChange`](README.md#oncachechange) option
|
||||
|
||||
## 1.2.0
|
||||
|
||||
- Add [`isPromise`](README.md#ispromise) option
|
||||
- Add typings for Flowtype and TypeScript
|
||||
|
||||
## 1.1.0
|
||||
|
||||
- Add [`transformKey`](README.md#transformkey) option
|
||||
|
||||
## 1.0.1
|
||||
|
||||
- Delay argument-to-key generation until stored as new cache value (speed improvement of ~35%)
|
||||
|
||||
## 1.0.0
|
||||
|
||||
- Initial release
|
||||
21
node_modules/micro-memoize/LICENSE
generated
vendored
Normal file
21
node_modules/micro-memoize/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018 Tony Quetano
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
555
node_modules/micro-memoize/README.md
generated
vendored
Normal file
555
node_modules/micro-memoize/README.md
generated
vendored
Normal file
@@ -0,0 +1,555 @@
|
||||
# micro-memoize
|
||||
|
||||
A tiny, crazy [fast](#benchmarks) memoization library for the 95% use-case
|
||||
|
||||
## Table of contents
|
||||
|
||||
- [micro-memoize](#micro-memoize)
|
||||
- [Table of contents](#table-of-contents)
|
||||
- [Summary](#summary)
|
||||
- [Importing](#importing)
|
||||
- [Usage](#usage)
|
||||
- [Types](#types)
|
||||
- [Composition](#composition)
|
||||
- [Options](#options)
|
||||
- [isEqual](#isequal)
|
||||
- [isMatchingKey](#ismatchingkey)
|
||||
- [isPromise](#ispromise)
|
||||
- [maxSize](#maxsize)
|
||||
- [onCacheAdd](#oncacheadd)
|
||||
- [onCacheChange](#oncachechange)
|
||||
- [onCacheHit](#oncachehit)
|
||||
- [transformKey](#transformkey)
|
||||
- [Additional properties](#additional-properties)
|
||||
- [memoized.cache](#memoizedcache)
|
||||
- [memoized.cache.snapshot](#memoizedcachesnapshot)
|
||||
- [memoized.fn](#memoizedfn)
|
||||
- [memoized.isMemoized](#memoizedismemoized)
|
||||
- [memoized.options](#memoizedoptions)
|
||||
- [Benchmarks](#benchmarks)
|
||||
- [Single parameter (primitive only)](#single-parameter-primitive-only)
|
||||
- [Single parameter (complex object)](#single-parameter-complex-object)
|
||||
- [Multiple parameters (primitives only)](#multiple-parameters-primitives-only)
|
||||
- [Multiple parameters (complex objects)](#multiple-parameters-complex-objects)
|
||||
- [Browser support](#browser-support)
|
||||
- [Node support](#node-support)
|
||||
- [Development](#development)
|
||||
|
||||
## Summary
|
||||
|
||||
As the author of [`moize`](https://github.com/planttheidea/moize), I created a consistently fast memoization library, but `moize` has a lot of features to satisfy a large number of edge cases. `micro-memoize` is a simpler approach, focusing on the core feature set with a much smaller footprint (~1.44kB minified+gzipped). Stripping out these edge cases also allows `micro-memoize` to be faster across the board than `moize`.
|
||||
|
||||
## Importing
|
||||
|
||||
ESM in browsers:
|
||||
|
||||
```ts
|
||||
import memoize from 'micro-memoize';
|
||||
```
|
||||
|
||||
ESM in NodeJS:
|
||||
|
||||
```ts
|
||||
import memoize from 'micro-memoize/mjs';
|
||||
```
|
||||
|
||||
CommonJS:
|
||||
|
||||
```ts
|
||||
const memoize = require('micro-memoize');
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
const assembleToObject = (one: string, two: string) => ({ one, two });
|
||||
|
||||
const memoized = memoize(assembleToObject);
|
||||
|
||||
console.log(memoized('one', 'two')); // {one: 'one', two: 'two'}
|
||||
console.log(memoized('one', 'two')); // pulled from cache, {one: 'one', two: 'two'}
|
||||
```
|
||||
|
||||
### Types
|
||||
|
||||
If you need them, all types are available under the `MicroMemoize` namespace.
|
||||
|
||||
```ts
|
||||
import { MicroMemoize } from 'micro-memoize';
|
||||
```
|
||||
|
||||
### Composition
|
||||
|
||||
Starting in `4.0.0`, you can compose memoized functions if you want to have multiple types of memoized versions based on different options.
|
||||
|
||||
```ts
|
||||
const simple = memoized(fn); // { maxSize: 1 }
|
||||
const upToFive = memoized(simple, { maxSize: 5 }); // { maxSize: 5 }
|
||||
const withCustomEquals = memoized(upToFive, { isEqual: deepEqual }); // { maxSize: 5, isEqual: deepEqual }
|
||||
```
|
||||
|
||||
**NOTE**: The original function is the function used in the composition, the composition only applies to the options. In the example above, `upToFive` does not call `simple`, it calls `fn`.
|
||||
|
||||
## Options
|
||||
|
||||
### isEqual
|
||||
|
||||
`function(object1: any, object2: any): boolean`, _defaults to `isSameValueZero`_
|
||||
|
||||
Custom method to compare equality of keys, determining whether to pull from cache or not, by comparing each argument in order.
|
||||
|
||||
Common use-cases:
|
||||
|
||||
- Deep equality comparison
|
||||
- Limiting the arguments compared
|
||||
|
||||
```ts
|
||||
import { deepEqual } from 'fast-equals';
|
||||
|
||||
type ContrivedObject = {
|
||||
deep: string;
|
||||
};
|
||||
|
||||
const deepObject = (object: {
|
||||
foo: ContrivedObject;
|
||||
bar: ContrivedObject;
|
||||
}) => ({
|
||||
foo: object.foo,
|
||||
bar: object.bar,
|
||||
});
|
||||
|
||||
const memoizedDeepObject = memoize(deepObject, { isEqual: deepEqual });
|
||||
|
||||
console.log(
|
||||
memoizedDeepObject({
|
||||
foo: {
|
||||
deep: 'foo',
|
||||
},
|
||||
bar: {
|
||||
deep: 'bar',
|
||||
},
|
||||
baz: {
|
||||
deep: 'baz',
|
||||
},
|
||||
}),
|
||||
); // {foo: {deep: 'foo'}, bar: {deep: 'bar'}}
|
||||
|
||||
console.log(
|
||||
memoizedDeepObject({
|
||||
foo: {
|
||||
deep: 'foo',
|
||||
},
|
||||
bar: {
|
||||
deep: 'bar',
|
||||
},
|
||||
baz: {
|
||||
deep: 'baz',
|
||||
},
|
||||
}),
|
||||
); // pulled from cache
|
||||
```
|
||||
|
||||
**NOTE**: The default method tests for [SameValueZero](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) equality, which is summarized as strictly equal while also considering `NaN` equal to `NaN`.
|
||||
|
||||
### isMatchingKey
|
||||
|
||||
`function(object1: any[], object2: any[]): boolean`
|
||||
|
||||
Custom method to compare equality of keys, determining whether to pull from cache or not, by comparing the entire key.
|
||||
|
||||
Common use-cases:
|
||||
|
||||
- Comparing the shape of the key
|
||||
- Matching on values regardless of order
|
||||
- Serialization of arguments
|
||||
|
||||
```ts
|
||||
import { deepEqual } from 'fast-equals';
|
||||
|
||||
type ContrivedObject = { foo: string; bar: number };
|
||||
|
||||
const deepObject = (object: ContrivedObject) => ({
|
||||
foo: object.foo,
|
||||
bar: object.bar,
|
||||
});
|
||||
|
||||
const memoizedShape = memoize(deepObject, {
|
||||
// receives the full key in cache and the full key of the most recent call
|
||||
isMatchingKey(key1, key2) {
|
||||
const object1 = key1[0];
|
||||
const object2 = key2[0];
|
||||
|
||||
return (
|
||||
object1.hasOwnProperty('foo') &&
|
||||
object2.hasOwnProperty('foo') &&
|
||||
object1.bar === object2.bar
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
console.log(
|
||||
memoizedShape({
|
||||
foo: 'foo',
|
||||
bar: 123,
|
||||
baz: 'baz',
|
||||
}),
|
||||
); // {foo: {deep: 'foo'}, bar: {deep: 'bar'}}
|
||||
|
||||
console.log(
|
||||
memoizedShape({
|
||||
foo: 'not foo',
|
||||
bar: 123,
|
||||
baz: 'baz',
|
||||
}),
|
||||
); // pulled from cache
|
||||
```
|
||||
|
||||
### isPromise
|
||||
|
||||
`boolean`, _defaults to `false`_
|
||||
|
||||
Identifies the value returned from the method as a `Promise`, which will result in one of two possible scenarios:
|
||||
|
||||
- If the promise is resolved, it will fire the `onCacheHit` and `onCacheChange` options
|
||||
- If the promise is rejected, it will trigger auto-removal from cache
|
||||
|
||||
```ts
|
||||
const fn = async (one: string, two: string) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
reject(new Error(JSON.stringify({ one, two })));
|
||||
}, 500);
|
||||
});
|
||||
};
|
||||
|
||||
const memoized = memoize(fn, { isPromise: true });
|
||||
|
||||
memoized('one', 'two');
|
||||
|
||||
console.log(memoized.cache.snapshot.keys); // [['one', 'two']]
|
||||
console.log(memoized.cache.snapshot.values); // [Promise]
|
||||
|
||||
setTimeout(() => {
|
||||
console.log(memoized.cache.snapshot.keys); // []
|
||||
console.log(memoized.cache.snapshot.values); // []
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
**NOTE**: If you don't want rejections to auto-remove the entry from cache, set `isPromise` to `false` (or simply do not set it), but be aware this will also remove the cache listeners that fire on successful resolution.
|
||||
|
||||
### maxSize
|
||||
|
||||
`number`, _defaults to `1`_
|
||||
|
||||
The number of values to store in cache, based on a [Least Recently Used](https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_Recently_Used_.28LRU.29) basis. This operates the same as [`maxSize`](https://github.com/planttheidea/moize#maxsize) on `moize`.
|
||||
|
||||
```ts
|
||||
const manyPossibleArgs = (one: string, two: string) => [one, two];
|
||||
|
||||
const memoized = memoize(manyPossibleArgs, { maxSize: 3 });
|
||||
|
||||
console.log(memoized('one', 'two')); // ['one', 'two']
|
||||
console.log(memoized('two', 'three')); // ['two', 'three']
|
||||
console.log(memoized('three', 'four')); // ['three', 'four']
|
||||
|
||||
console.log(memoized('one', 'two')); // pulled from cache
|
||||
console.log(memoized('two', 'three')); // pulled from cache
|
||||
console.log(memoized('three', 'four')); // pulled from cache
|
||||
|
||||
console.log(memoized('four', 'five')); // ['four', 'five'], drops ['one', 'two'] from cache
|
||||
```
|
||||
|
||||
### onCacheAdd
|
||||
|
||||
`function(cache: Cache, options: Options): void`
|
||||
|
||||
Callback method that executes whenever the cache is added to. This is mainly to allow for higher-order caching managers that use `micro-memoize` to perform superset functionality on the `cache` object.
|
||||
|
||||
```ts
|
||||
const fn = (one: string, two: string) => [one, two];
|
||||
|
||||
const memoized = memoize(fn, {
|
||||
maxSize: 2,
|
||||
onCacheAdd(cache, options) {
|
||||
console.log('cache has been added to: ', cache);
|
||||
console.log('memoized method has the following options applied: ', options);
|
||||
},
|
||||
});
|
||||
|
||||
memoized('foo', 'bar'); // cache has been added to
|
||||
memoized('foo', 'bar');
|
||||
memoized('foo', 'bar');
|
||||
|
||||
memoized('bar', 'foo'); // cache has been added to
|
||||
memoized('bar', 'foo');
|
||||
memoized('bar', 'foo');
|
||||
|
||||
memoized('foo', 'bar');
|
||||
memoized('foo', 'bar');
|
||||
memoized('foo', 'bar');
|
||||
```
|
||||
|
||||
**NOTE**: This method is not executed when the `cache` is manually manipulated, only when changed via calling the memoized method.
|
||||
|
||||
### onCacheChange
|
||||
|
||||
`function(cache: Cache, options: Options): void`
|
||||
|
||||
Callback method that executes whenever the cache is added to or the order is updated. This is mainly to allow for higher-order caching managers that use `micro-memoize` to perform superset functionality on the `cache` object.
|
||||
|
||||
```ts
|
||||
const fn = (one: string, two: string) => [one, two];
|
||||
|
||||
const memoized = memoize(fn, {
|
||||
maxSize: 2,
|
||||
onCacheChange(cache, options) {
|
||||
console.log('cache has changed: ', cache);
|
||||
console.log('memoized method has the following options applied: ', options);
|
||||
},
|
||||
});
|
||||
|
||||
memoized('foo', 'bar'); // cache has changed
|
||||
memoized('foo', 'bar');
|
||||
memoized('foo', 'bar');
|
||||
|
||||
memoized('bar', 'foo'); // cache has changed
|
||||
memoized('bar', 'foo');
|
||||
memoized('bar', 'foo');
|
||||
|
||||
memoized('foo', 'bar'); // cache has changed
|
||||
memoized('foo', 'bar');
|
||||
memoized('foo', 'bar');
|
||||
```
|
||||
|
||||
**NOTE**: This method is not executed when the `cache` is manually manipulated, only when changed via calling the memoized method. When the execution of other cache listeners (`onCacheAdd`, `onCacheHit`) is applicable, this method will execute after those methods.
|
||||
|
||||
### onCacheHit
|
||||
|
||||
`function(cache: Cache, options: Options): void`
|
||||
|
||||
Callback method that executes whenever the cache is hit, whether the order is updated or not. This is mainly to allow for higher-order caching managers that use `micro-memoize` to perform superset functionality on the `cache` object.
|
||||
|
||||
```ts
|
||||
const fn = (one: string, two: string) => [one, two];
|
||||
|
||||
const memoized = memoize(fn, {
|
||||
maxSize: 2,
|
||||
onCacheHit(cache, options) {
|
||||
console.log('cache was hit: ', cache);
|
||||
console.log('memoized method has the following options applied: ', options);
|
||||
},
|
||||
});
|
||||
|
||||
memoized('foo', 'bar');
|
||||
memoized('foo', 'bar'); // cache was hit
|
||||
memoized('foo', 'bar'); // cache was hit
|
||||
|
||||
memoized('bar', 'foo');
|
||||
memoized('bar', 'foo'); // cache was hit
|
||||
memoized('bar', 'foo'); // cache was hit
|
||||
|
||||
memoized('foo', 'bar'); // cache was hit
|
||||
memoized('foo', 'bar'); // cache was hit
|
||||
memoized('foo', 'bar'); // cache was hit
|
||||
```
|
||||
|
||||
**NOTE**: This method is not executed when the `cache` is manually manipulated, only when changed via calling the memoized method.
|
||||
|
||||
### transformKey
|
||||
|
||||
`function(Array<any>): any`
|
||||
|
||||
A method that allows you transform the key that is used for caching, if you want to use something other than the pure arguments.
|
||||
|
||||
```ts
|
||||
const ignoreFunctionArgs = (one: string, two: () => {}) => [one, two];
|
||||
|
||||
const memoized = memoize(ignoreFunctionArgs, {
|
||||
transformKey: (args) => [JSON.stringify(args[0])],
|
||||
});
|
||||
|
||||
console.log(memoized('one', () => {})); // ['one', () => {}]
|
||||
console.log(memoized('one', () => {})); // pulled from cache, ['one', () => {}]
|
||||
```
|
||||
|
||||
If your transformed keys require something other than `SameValueZero` equality, you can combine `transformKey` with [`isEqual`](#isequal) for completely custom key creation and comparison.
|
||||
|
||||
```ts
|
||||
const ignoreFunctionArg = (one: string, two: () => void) => [one, two];
|
||||
|
||||
const memoized = memoize(ignoreFunctionArg, {
|
||||
isMatchingKey: (key1, key2) => key1[0] === key2[0],
|
||||
// Cache based on the serialized first parameter
|
||||
transformKey: (args) => [JSON.stringify(args[0])],
|
||||
});
|
||||
|
||||
console.log(memoized('one', () => {})); // ['one', () => {}]
|
||||
console.log(memoized('one', () => {})); // pulled from cache, ['one', () => {}]
|
||||
```
|
||||
|
||||
## Additional properties
|
||||
|
||||
### memoized.cache
|
||||
|
||||
`Object`
|
||||
|
||||
The `cache` object that is used internally. The shape of this structure:
|
||||
|
||||
```ts
|
||||
{
|
||||
keys: any[][], // available as MicroMemoize.Key[]
|
||||
values: any[] // available as MicroMemoize.Value[]
|
||||
}
|
||||
```
|
||||
|
||||
The exposure of this object is to allow for manual manipulation of keys/values (injection, removal, expiration, etc).
|
||||
|
||||
```ts
|
||||
const method = (one: string, two: string) => ({ one, two });
|
||||
|
||||
const memoized = memoize(method);
|
||||
|
||||
memoized.cache.keys.push(['one', 'two']);
|
||||
memoized.cache.values.push('cached');
|
||||
|
||||
console.log(memoized('one', 'two')); // 'cached'
|
||||
```
|
||||
|
||||
**NOTE**: `moize` offers a variety of convenience methods for this manual `cache` manipulation, and while `micro-memoize` allows all the same capabilities by exposing the `cache`, it does not provide any convenience methods.
|
||||
|
||||
#### memoized.cache.snapshot
|
||||
|
||||
`Object`
|
||||
|
||||
This is identical to the `cache` object referenced above, but it is a deep clone created at request, which will provide a persistent snapshot of the values at that time. This is useful when tracking the cache changes over time, as the `cache` object is mutated internally for performance reasons.
|
||||
|
||||
### memoized.fn
|
||||
|
||||
`function`
|
||||
|
||||
The original function passed to be memoized.
|
||||
|
||||
### memoized.isMemoized
|
||||
|
||||
`boolean`
|
||||
|
||||
Hard-coded to `true` when the function is memoized. This is useful for introspection, to identify if a method has been memoized or not.
|
||||
|
||||
### memoized.options
|
||||
|
||||
`Object`
|
||||
|
||||
The [`options`](#options) passed when creating the memoized method.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
All values provided are the number of operations per second (ops/sec) calculated by the [Benchmark suite](https://benchmarkjs.com/). Note that `underscore`, `lodash`, and `ramda` do not support mulitple-parameter memoization (which is where `micro-memoize` really shines), so they are not included in those benchmarks.
|
||||
|
||||
Benchmarks was performed on an i7 8-core Arch Linux laptop with 16GB of memory using NodeJS version `10.15.0`. The default configuration of each library was tested with a fibonacci calculation based on the following parameters:
|
||||
|
||||
- Single primitive = `35`
|
||||
- Single object = `{number: 35}`
|
||||
- Multiple primitives = `35, true`
|
||||
- Multiple objects = `{number: 35}, {isComplete: true}`
|
||||
|
||||
**NOTE**: Not all libraries tested support multiple parameters out of the box, but support the ability to pass a custom `resolver`. Because these often need to resolve to a string value, [a common suggestion](https://github.com/lodash/lodash/issues/2115) is to just `JSON.stringify` the arguments, so that is what is used when needed.
|
||||
|
||||
### Single parameter (primitive only)
|
||||
|
||||
This is usually what benchmarks target for ... its the least-likely use-case, but the easiest to optimize, often at the expense of more common use-cases.
|
||||
|
||||
| | Operations / second |
|
||||
| ----------------- | ------------------- |
|
||||
| fast-memoize | 59,069,204 |
|
||||
| **micro-memoize** | **48,267,295** |
|
||||
| lru-memoize | 46,781,143 |
|
||||
| Addy Osmani | 32,372,414 |
|
||||
| lodash | 29,297,916 |
|
||||
| ramda | 25,054,838 |
|
||||
| mem | 24,848,072 |
|
||||
| underscore | 24,847,818 |
|
||||
| memoizee | 18,272,987 |
|
||||
| memoizerific | 7,302,835 |
|
||||
|
||||
### Single parameter (complex object)
|
||||
|
||||
This is what most memoization libraries target as the primary use-case, as it removes the complexities of multiple arguments but allows for usage with one to many values.
|
||||
|
||||
| | Operations / second |
|
||||
| ----------------- | ------------------- |
|
||||
| **micro-memoize** | **40,360,621** |
|
||||
| lodash | 30,862,028 |
|
||||
| lru-memoize | 25,740,572 |
|
||||
| memoizee | 12,058,375 |
|
||||
| memoizerific | 6,854,855 |
|
||||
| ramda | 2,287,030 |
|
||||
| underscore | 2,270,574 |
|
||||
| Addy Osmani | 2,076,031 |
|
||||
| mem | 2,001,984 |
|
||||
| fast-memoize | 1,591,019 |
|
||||
|
||||
### Multiple parameters (primitives only)
|
||||
|
||||
This is a very common use-case for function calls, but can be more difficult to optimize because you need to account for multiple possibilities ... did the number of arguments change, are there default arguments, etc.
|
||||
|
||||
| | Operations / second |
|
||||
| ----------------- | ------------------- |
|
||||
| **micro-memoize** | **33,546,353** |
|
||||
| lru-memoize | 20,884,669 |
|
||||
| memoizee | 7,831,161 |
|
||||
| Addy Osmani | 6,447,448 |
|
||||
| memoizerific | 5,587,779 |
|
||||
| mem | 2,620,943 |
|
||||
| underscore | 1,617,687 |
|
||||
| ramda | 1,569,167 |
|
||||
| lodash | 1,512,515 |
|
||||
| fast-memoize | 1,376,665 |
|
||||
|
||||
### Multiple parameters (complex objects)
|
||||
|
||||
This is the most robust use-case, with the same complexities as multiple primitives but managing bulkier objects with additional edge scenarios (destructured with defaults, for example).
|
||||
|
||||
| | Operations / second |
|
||||
| ----------------- | ------------------- |
|
||||
| **micro-memoize** | **34,857,438** |
|
||||
| lru-memoize | 20,838,330 |
|
||||
| memoizee | 7,820,066 |
|
||||
| memoizerific | 5,761,357 |
|
||||
| mem | 1,184,550 |
|
||||
| ramda | 1,034,937 |
|
||||
| underscore | 1,021,480 |
|
||||
| Addy Osmani | 1,014,642 |
|
||||
| lodash | 1,014,060 |
|
||||
| fast-memoize | 949,213 |
|
||||
|
||||
## Browser support
|
||||
|
||||
- Chrome (all versions)
|
||||
- Firefox (all versions)
|
||||
- Edge (all versions)
|
||||
- Opera 15+
|
||||
- IE 9+
|
||||
- Safari 6+
|
||||
- iOS 8+
|
||||
- Android 4+
|
||||
|
||||
## Node support
|
||||
|
||||
- 4+
|
||||
|
||||
## Development
|
||||
|
||||
Standard stuff, clone the repo and `npm install` dependencies. The npm scripts available:
|
||||
|
||||
- `build` => run webpack to build development `dist` file with NODE_ENV=development
|
||||
- `build:minifed` => run webpack to build production `dist` file with NODE_ENV=production
|
||||
- `dev` => run webpack dev server to run example app (playground!)
|
||||
- `dist` => runs `build` and `build-minified`
|
||||
- `lint` => run ESLint against all files in the `src` folder
|
||||
- `prepublish` => runs `compile-for-publish`
|
||||
- `prepublish:compile` => run `lint`, `test`, `transpile:es`, `transpile:lib`, `dist`
|
||||
- `test` => run AVA test functions with `NODE_ENV=test`
|
||||
- `test:coverage` => run `test` but with `nyc` for coverage checker
|
||||
- `test:watch` => run `test`, but with persistent watcher
|
||||
- `transpile:lib` => run babel against all files in `src` to create files in `lib`
|
||||
- `transpile:es` => run babel against all files in `src` to create files in `es`, preserving ES2015 modules (for [`pkg.module`](https://github.com/rollup/rollup/wiki/pkg.module))
|
||||
19
node_modules/micro-memoize/config/tsconfig/tsconfig.base.json
generated
vendored
Normal file
19
node_modules/micro-memoize/config/tsconfig/tsconfig.base.json
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"baseUrl": "src",
|
||||
"esModuleInterop": true,
|
||||
"jsx": "react",
|
||||
"lib": ["dom", "es2015"],
|
||||
"module": "esNext",
|
||||
"moduleResolution": "node",
|
||||
"noImplicitAny": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"outDir": "./dist",
|
||||
"sourceMap": false,
|
||||
"strict": true,
|
||||
"target": "es5"
|
||||
},
|
||||
"exclude": ["node_modules"],
|
||||
"include": ["../../src/*", "../../__tests__/*"]
|
||||
}
|
||||
6
node_modules/micro-memoize/config/tsconfig/tsconfig.dev.json
generated
vendored
Normal file
6
node_modules/micro-memoize/config/tsconfig/tsconfig.dev.json
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "./tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"sourceMap": true
|
||||
}
|
||||
}
|
||||
372
node_modules/micro-memoize/dist/micro-memoize.cjs.js
generated
vendored
Normal file
372
node_modules/micro-memoize/dist/micro-memoize.cjs.js
generated
vendored
Normal file
@@ -0,0 +1,372 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @constant DEFAULT_OPTIONS_KEYS the default options keys
|
||||
*/
|
||||
var DEFAULT_OPTIONS_KEYS = {
|
||||
isEqual: true,
|
||||
isMatchingKey: true,
|
||||
isPromise: true,
|
||||
maxSize: true,
|
||||
onCacheAdd: true,
|
||||
onCacheChange: true,
|
||||
onCacheHit: true,
|
||||
transformKey: true,
|
||||
};
|
||||
/**
|
||||
* @function slice
|
||||
*
|
||||
* @description
|
||||
* slice.call() pre-bound
|
||||
*/
|
||||
var slice = Array.prototype.slice;
|
||||
/**
|
||||
* @function cloneArray
|
||||
*
|
||||
* @description
|
||||
* clone the array-like object and return the new array
|
||||
*
|
||||
* @param arrayLike the array-like object to clone
|
||||
* @returns the clone as an array
|
||||
*/
|
||||
function cloneArray(arrayLike) {
|
||||
var length = arrayLike.length;
|
||||
if (!length) {
|
||||
return [];
|
||||
}
|
||||
if (length === 1) {
|
||||
return [arrayLike[0]];
|
||||
}
|
||||
if (length === 2) {
|
||||
return [arrayLike[0], arrayLike[1]];
|
||||
}
|
||||
if (length === 3) {
|
||||
return [arrayLike[0], arrayLike[1], arrayLike[2]];
|
||||
}
|
||||
return slice.call(arrayLike, 0);
|
||||
}
|
||||
/**
|
||||
* @function getCustomOptions
|
||||
*
|
||||
* @description
|
||||
* get the custom options on the object passed
|
||||
*
|
||||
* @param options the memoization options passed
|
||||
* @returns the custom options passed
|
||||
*/
|
||||
function getCustomOptions(options) {
|
||||
var customOptions = {};
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
for (var key in options) {
|
||||
if (!DEFAULT_OPTIONS_KEYS[key]) {
|
||||
customOptions[key] = options[key];
|
||||
}
|
||||
}
|
||||
/* eslint-enable */
|
||||
return customOptions;
|
||||
}
|
||||
/**
|
||||
* @function isMemoized
|
||||
*
|
||||
* @description
|
||||
* is the function passed already memoized
|
||||
*
|
||||
* @param fn the function to test
|
||||
* @returns is the function already memoized
|
||||
*/
|
||||
function isMemoized(fn) {
|
||||
return typeof fn === 'function' && fn.isMemoized;
|
||||
}
|
||||
/**
|
||||
* @function isSameValueZero
|
||||
*
|
||||
* @description
|
||||
* are the objects equal based on SameValueZero equality
|
||||
*
|
||||
* @param object1 the first object to compare
|
||||
* @param object2 the second object to compare
|
||||
* @returns are the two objects equal
|
||||
*/
|
||||
function isSameValueZero(object1, object2) {
|
||||
// eslint-disable-next-line no-self-compare
|
||||
return object1 === object2 || (object1 !== object1 && object2 !== object2);
|
||||
}
|
||||
/**
|
||||
* @function mergeOptions
|
||||
*
|
||||
* @description
|
||||
* merge the options into the target
|
||||
*
|
||||
* @param existingOptions the options provided
|
||||
* @param newOptions the options to include
|
||||
* @returns the merged options
|
||||
*/
|
||||
function mergeOptions(existingOptions, newOptions) {
|
||||
var target = {};
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
for (var key in existingOptions) {
|
||||
target[key] = existingOptions[key];
|
||||
}
|
||||
for (var key in newOptions) {
|
||||
target[key] = newOptions[key];
|
||||
}
|
||||
/* eslint-enable */
|
||||
return target;
|
||||
}
|
||||
|
||||
// utils
|
||||
var Cache = /** @class */ (function () {
|
||||
function Cache(options) {
|
||||
this.keys = [];
|
||||
this.values = [];
|
||||
this.options = options;
|
||||
var isMatchingKeyFunction = typeof options.isMatchingKey === 'function';
|
||||
if (isMatchingKeyFunction) {
|
||||
this.getKeyIndex = this._getKeyIndexFromMatchingKey;
|
||||
}
|
||||
else if (options.maxSize > 1) {
|
||||
this.getKeyIndex = this._getKeyIndexForMany;
|
||||
}
|
||||
else {
|
||||
this.getKeyIndex = this._getKeyIndexForSingle;
|
||||
}
|
||||
this.canTransformKey = typeof options.transformKey === 'function';
|
||||
this.shouldCloneArguments = this.canTransformKey || isMatchingKeyFunction;
|
||||
this.shouldUpdateOnAdd = typeof options.onCacheAdd === 'function';
|
||||
this.shouldUpdateOnChange = typeof options.onCacheChange === 'function';
|
||||
this.shouldUpdateOnHit = typeof options.onCacheHit === 'function';
|
||||
}
|
||||
Object.defineProperty(Cache.prototype, "size", {
|
||||
/**
|
||||
* The number of cached [key,value] results.
|
||||
*/
|
||||
get: function () {
|
||||
return this.keys.length;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Cache.prototype, "snapshot", {
|
||||
/**
|
||||
* A copy of the cache at a moment in time. This is useful
|
||||
* to compare changes over time, since the cache mutates
|
||||
* internally for performance reasons.
|
||||
*/
|
||||
get: function () {
|
||||
return {
|
||||
keys: cloneArray(this.keys),
|
||||
size: this.size,
|
||||
values: cloneArray(this.values),
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
/**
|
||||
* Gets the matching key index when a custom key matcher is used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexFromMatchingKey = function (keyToMatch) {
|
||||
var _a = this.options, isMatchingKey = _a.isMatchingKey, maxSize = _a.maxSize;
|
||||
var keys = this.keys;
|
||||
var keysLength = keys.length;
|
||||
if (!keysLength) {
|
||||
return -1;
|
||||
}
|
||||
if (isMatchingKey(keys[0], keyToMatch)) {
|
||||
return 0;
|
||||
}
|
||||
if (maxSize > 1) {
|
||||
for (var index = 1; index < keysLength; index++) {
|
||||
if (isMatchingKey(keys[index], keyToMatch)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
/**
|
||||
* Gets the matching key index when multiple keys are used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexForMany = function (keyToMatch) {
|
||||
var isEqual = this.options.isEqual;
|
||||
var keys = this.keys;
|
||||
var keysLength = keys.length;
|
||||
if (!keysLength) {
|
||||
return -1;
|
||||
}
|
||||
if (keysLength === 1) {
|
||||
return this._getKeyIndexForSingle(keyToMatch);
|
||||
}
|
||||
var keyLength = keyToMatch.length;
|
||||
var existingKey;
|
||||
var argIndex;
|
||||
if (keyLength > 1) {
|
||||
for (var index = 0; index < keysLength; index++) {
|
||||
existingKey = keys[index];
|
||||
if (existingKey.length === keyLength) {
|
||||
argIndex = 0;
|
||||
for (; argIndex < keyLength; argIndex++) {
|
||||
if (!isEqual(existingKey[argIndex], keyToMatch[argIndex])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (argIndex === keyLength) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var index = 0; index < keysLength; index++) {
|
||||
existingKey = keys[index];
|
||||
if (existingKey.length === keyLength &&
|
||||
isEqual(existingKey[0], keyToMatch[0])) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
/**
|
||||
* Gets the matching key index when a single key is used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexForSingle = function (keyToMatch) {
|
||||
var keys = this.keys;
|
||||
if (!keys.length) {
|
||||
return -1;
|
||||
}
|
||||
var existingKey = keys[0];
|
||||
var length = existingKey.length;
|
||||
if (keyToMatch.length !== length) {
|
||||
return -1;
|
||||
}
|
||||
var isEqual = this.options.isEqual;
|
||||
if (length > 1) {
|
||||
for (var index = 0; index < length; index++) {
|
||||
if (!isEqual(existingKey[index], keyToMatch[index])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return isEqual(existingKey[0], keyToMatch[0]) ? 0 : -1;
|
||||
};
|
||||
/**
|
||||
* Order the array based on a Least-Recently-Used basis.
|
||||
*/
|
||||
Cache.prototype.orderByLru = function (key, value, startingIndex) {
|
||||
var keys = this.keys;
|
||||
var values = this.values;
|
||||
var currentLength = keys.length;
|
||||
var index = startingIndex;
|
||||
while (index--) {
|
||||
keys[index + 1] = keys[index];
|
||||
values[index + 1] = values[index];
|
||||
}
|
||||
keys[0] = key;
|
||||
values[0] = value;
|
||||
var maxSize = this.options.maxSize;
|
||||
if (currentLength === maxSize && startingIndex === currentLength) {
|
||||
keys.pop();
|
||||
values.pop();
|
||||
}
|
||||
else if (startingIndex >= maxSize) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
keys.length = values.length = maxSize;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Update the promise method to auto-remove from cache if rejected, and
|
||||
* if resolved then fire cache hit / changed.
|
||||
*/
|
||||
Cache.prototype.updateAsyncCache = function (memoized) {
|
||||
var _this = this;
|
||||
var _a = this.options, onCacheChange = _a.onCacheChange, onCacheHit = _a.onCacheHit;
|
||||
var firstKey = this.keys[0];
|
||||
var firstValue = this.values[0];
|
||||
this.values[0] = firstValue.then(function (value) {
|
||||
if (_this.shouldUpdateOnHit) {
|
||||
onCacheHit(_this, _this.options, memoized);
|
||||
}
|
||||
if (_this.shouldUpdateOnChange) {
|
||||
onCacheChange(_this, _this.options, memoized);
|
||||
}
|
||||
return value;
|
||||
}, function (error) {
|
||||
var keyIndex = _this.getKeyIndex(firstKey);
|
||||
if (keyIndex !== -1) {
|
||||
_this.keys.splice(keyIndex, 1);
|
||||
_this.values.splice(keyIndex, 1);
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
return Cache;
|
||||
}());
|
||||
|
||||
function createMemoizedFunction(fn, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
if (isMemoized(fn)) {
|
||||
return createMemoizedFunction(fn.fn, mergeOptions(fn.options, options));
|
||||
}
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('You must pass a function to `memoize`.');
|
||||
}
|
||||
var _a = options.isEqual, isEqual = _a === void 0 ? isSameValueZero : _a, isMatchingKey = options.isMatchingKey, _b = options.isPromise, isPromise = _b === void 0 ? false : _b, _c = options.maxSize, maxSize = _c === void 0 ? 1 : _c, onCacheAdd = options.onCacheAdd, onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit, transformKey = options.transformKey;
|
||||
var normalizedOptions = mergeOptions({
|
||||
isEqual: isEqual,
|
||||
isMatchingKey: isMatchingKey,
|
||||
isPromise: isPromise,
|
||||
maxSize: maxSize,
|
||||
onCacheAdd: onCacheAdd,
|
||||
onCacheChange: onCacheChange,
|
||||
onCacheHit: onCacheHit,
|
||||
transformKey: transformKey,
|
||||
}, getCustomOptions(options));
|
||||
var cache = new Cache(normalizedOptions);
|
||||
var keys = cache.keys, values = cache.values, canTransformKey = cache.canTransformKey, shouldCloneArguments = cache.shouldCloneArguments, shouldUpdateOnAdd = cache.shouldUpdateOnAdd, shouldUpdateOnChange = cache.shouldUpdateOnChange, shouldUpdateOnHit = cache.shouldUpdateOnHit;
|
||||
var memoized = function () {
|
||||
var key = shouldCloneArguments
|
||||
? cloneArray(arguments)
|
||||
: arguments;
|
||||
if (canTransformKey) {
|
||||
key = transformKey(key);
|
||||
}
|
||||
var keyIndex = keys.length ? cache.getKeyIndex(key) : -1;
|
||||
if (keyIndex !== -1) {
|
||||
if (shouldUpdateOnHit) {
|
||||
onCacheHit(cache, normalizedOptions, memoized);
|
||||
}
|
||||
if (keyIndex) {
|
||||
cache.orderByLru(keys[keyIndex], values[keyIndex], keyIndex);
|
||||
if (shouldUpdateOnChange) {
|
||||
onCacheChange(cache, normalizedOptions, memoized);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var newValue = fn.apply(this, arguments);
|
||||
var newKey = shouldCloneArguments
|
||||
? key
|
||||
: cloneArray(arguments);
|
||||
cache.orderByLru(newKey, newValue, keys.length);
|
||||
if (isPromise) {
|
||||
cache.updateAsyncCache(memoized);
|
||||
}
|
||||
if (shouldUpdateOnAdd) {
|
||||
onCacheAdd(cache, normalizedOptions, memoized);
|
||||
}
|
||||
if (shouldUpdateOnChange) {
|
||||
onCacheChange(cache, normalizedOptions, memoized);
|
||||
}
|
||||
}
|
||||
return values[0];
|
||||
};
|
||||
memoized.cache = cache;
|
||||
memoized.fn = fn;
|
||||
memoized.isMemoized = true;
|
||||
memoized.options = normalizedOptions;
|
||||
return memoized;
|
||||
}
|
||||
|
||||
module.exports = createMemoizedFunction;
|
||||
370
node_modules/micro-memoize/dist/micro-memoize.esm.js
generated
vendored
Normal file
370
node_modules/micro-memoize/dist/micro-memoize.esm.js
generated
vendored
Normal file
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
* @constant DEFAULT_OPTIONS_KEYS the default options keys
|
||||
*/
|
||||
var DEFAULT_OPTIONS_KEYS = {
|
||||
isEqual: true,
|
||||
isMatchingKey: true,
|
||||
isPromise: true,
|
||||
maxSize: true,
|
||||
onCacheAdd: true,
|
||||
onCacheChange: true,
|
||||
onCacheHit: true,
|
||||
transformKey: true,
|
||||
};
|
||||
/**
|
||||
* @function slice
|
||||
*
|
||||
* @description
|
||||
* slice.call() pre-bound
|
||||
*/
|
||||
var slice = Array.prototype.slice;
|
||||
/**
|
||||
* @function cloneArray
|
||||
*
|
||||
* @description
|
||||
* clone the array-like object and return the new array
|
||||
*
|
||||
* @param arrayLike the array-like object to clone
|
||||
* @returns the clone as an array
|
||||
*/
|
||||
function cloneArray(arrayLike) {
|
||||
var length = arrayLike.length;
|
||||
if (!length) {
|
||||
return [];
|
||||
}
|
||||
if (length === 1) {
|
||||
return [arrayLike[0]];
|
||||
}
|
||||
if (length === 2) {
|
||||
return [arrayLike[0], arrayLike[1]];
|
||||
}
|
||||
if (length === 3) {
|
||||
return [arrayLike[0], arrayLike[1], arrayLike[2]];
|
||||
}
|
||||
return slice.call(arrayLike, 0);
|
||||
}
|
||||
/**
|
||||
* @function getCustomOptions
|
||||
*
|
||||
* @description
|
||||
* get the custom options on the object passed
|
||||
*
|
||||
* @param options the memoization options passed
|
||||
* @returns the custom options passed
|
||||
*/
|
||||
function getCustomOptions(options) {
|
||||
var customOptions = {};
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
for (var key in options) {
|
||||
if (!DEFAULT_OPTIONS_KEYS[key]) {
|
||||
customOptions[key] = options[key];
|
||||
}
|
||||
}
|
||||
/* eslint-enable */
|
||||
return customOptions;
|
||||
}
|
||||
/**
|
||||
* @function isMemoized
|
||||
*
|
||||
* @description
|
||||
* is the function passed already memoized
|
||||
*
|
||||
* @param fn the function to test
|
||||
* @returns is the function already memoized
|
||||
*/
|
||||
function isMemoized(fn) {
|
||||
return typeof fn === 'function' && fn.isMemoized;
|
||||
}
|
||||
/**
|
||||
* @function isSameValueZero
|
||||
*
|
||||
* @description
|
||||
* are the objects equal based on SameValueZero equality
|
||||
*
|
||||
* @param object1 the first object to compare
|
||||
* @param object2 the second object to compare
|
||||
* @returns are the two objects equal
|
||||
*/
|
||||
function isSameValueZero(object1, object2) {
|
||||
// eslint-disable-next-line no-self-compare
|
||||
return object1 === object2 || (object1 !== object1 && object2 !== object2);
|
||||
}
|
||||
/**
|
||||
* @function mergeOptions
|
||||
*
|
||||
* @description
|
||||
* merge the options into the target
|
||||
*
|
||||
* @param existingOptions the options provided
|
||||
* @param newOptions the options to include
|
||||
* @returns the merged options
|
||||
*/
|
||||
function mergeOptions(existingOptions, newOptions) {
|
||||
var target = {};
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
for (var key in existingOptions) {
|
||||
target[key] = existingOptions[key];
|
||||
}
|
||||
for (var key in newOptions) {
|
||||
target[key] = newOptions[key];
|
||||
}
|
||||
/* eslint-enable */
|
||||
return target;
|
||||
}
|
||||
|
||||
// utils
|
||||
var Cache = /** @class */ (function () {
|
||||
function Cache(options) {
|
||||
this.keys = [];
|
||||
this.values = [];
|
||||
this.options = options;
|
||||
var isMatchingKeyFunction = typeof options.isMatchingKey === 'function';
|
||||
if (isMatchingKeyFunction) {
|
||||
this.getKeyIndex = this._getKeyIndexFromMatchingKey;
|
||||
}
|
||||
else if (options.maxSize > 1) {
|
||||
this.getKeyIndex = this._getKeyIndexForMany;
|
||||
}
|
||||
else {
|
||||
this.getKeyIndex = this._getKeyIndexForSingle;
|
||||
}
|
||||
this.canTransformKey = typeof options.transformKey === 'function';
|
||||
this.shouldCloneArguments = this.canTransformKey || isMatchingKeyFunction;
|
||||
this.shouldUpdateOnAdd = typeof options.onCacheAdd === 'function';
|
||||
this.shouldUpdateOnChange = typeof options.onCacheChange === 'function';
|
||||
this.shouldUpdateOnHit = typeof options.onCacheHit === 'function';
|
||||
}
|
||||
Object.defineProperty(Cache.prototype, "size", {
|
||||
/**
|
||||
* The number of cached [key,value] results.
|
||||
*/
|
||||
get: function () {
|
||||
return this.keys.length;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Cache.prototype, "snapshot", {
|
||||
/**
|
||||
* A copy of the cache at a moment in time. This is useful
|
||||
* to compare changes over time, since the cache mutates
|
||||
* internally for performance reasons.
|
||||
*/
|
||||
get: function () {
|
||||
return {
|
||||
keys: cloneArray(this.keys),
|
||||
size: this.size,
|
||||
values: cloneArray(this.values),
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
/**
|
||||
* Gets the matching key index when a custom key matcher is used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexFromMatchingKey = function (keyToMatch) {
|
||||
var _a = this.options, isMatchingKey = _a.isMatchingKey, maxSize = _a.maxSize;
|
||||
var keys = this.keys;
|
||||
var keysLength = keys.length;
|
||||
if (!keysLength) {
|
||||
return -1;
|
||||
}
|
||||
if (isMatchingKey(keys[0], keyToMatch)) {
|
||||
return 0;
|
||||
}
|
||||
if (maxSize > 1) {
|
||||
for (var index = 1; index < keysLength; index++) {
|
||||
if (isMatchingKey(keys[index], keyToMatch)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
/**
|
||||
* Gets the matching key index when multiple keys are used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexForMany = function (keyToMatch) {
|
||||
var isEqual = this.options.isEqual;
|
||||
var keys = this.keys;
|
||||
var keysLength = keys.length;
|
||||
if (!keysLength) {
|
||||
return -1;
|
||||
}
|
||||
if (keysLength === 1) {
|
||||
return this._getKeyIndexForSingle(keyToMatch);
|
||||
}
|
||||
var keyLength = keyToMatch.length;
|
||||
var existingKey;
|
||||
var argIndex;
|
||||
if (keyLength > 1) {
|
||||
for (var index = 0; index < keysLength; index++) {
|
||||
existingKey = keys[index];
|
||||
if (existingKey.length === keyLength) {
|
||||
argIndex = 0;
|
||||
for (; argIndex < keyLength; argIndex++) {
|
||||
if (!isEqual(existingKey[argIndex], keyToMatch[argIndex])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (argIndex === keyLength) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var index = 0; index < keysLength; index++) {
|
||||
existingKey = keys[index];
|
||||
if (existingKey.length === keyLength &&
|
||||
isEqual(existingKey[0], keyToMatch[0])) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
/**
|
||||
* Gets the matching key index when a single key is used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexForSingle = function (keyToMatch) {
|
||||
var keys = this.keys;
|
||||
if (!keys.length) {
|
||||
return -1;
|
||||
}
|
||||
var existingKey = keys[0];
|
||||
var length = existingKey.length;
|
||||
if (keyToMatch.length !== length) {
|
||||
return -1;
|
||||
}
|
||||
var isEqual = this.options.isEqual;
|
||||
if (length > 1) {
|
||||
for (var index = 0; index < length; index++) {
|
||||
if (!isEqual(existingKey[index], keyToMatch[index])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return isEqual(existingKey[0], keyToMatch[0]) ? 0 : -1;
|
||||
};
|
||||
/**
|
||||
* Order the array based on a Least-Recently-Used basis.
|
||||
*/
|
||||
Cache.prototype.orderByLru = function (key, value, startingIndex) {
|
||||
var keys = this.keys;
|
||||
var values = this.values;
|
||||
var currentLength = keys.length;
|
||||
var index = startingIndex;
|
||||
while (index--) {
|
||||
keys[index + 1] = keys[index];
|
||||
values[index + 1] = values[index];
|
||||
}
|
||||
keys[0] = key;
|
||||
values[0] = value;
|
||||
var maxSize = this.options.maxSize;
|
||||
if (currentLength === maxSize && startingIndex === currentLength) {
|
||||
keys.pop();
|
||||
values.pop();
|
||||
}
|
||||
else if (startingIndex >= maxSize) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
keys.length = values.length = maxSize;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Update the promise method to auto-remove from cache if rejected, and
|
||||
* if resolved then fire cache hit / changed.
|
||||
*/
|
||||
Cache.prototype.updateAsyncCache = function (memoized) {
|
||||
var _this = this;
|
||||
var _a = this.options, onCacheChange = _a.onCacheChange, onCacheHit = _a.onCacheHit;
|
||||
var firstKey = this.keys[0];
|
||||
var firstValue = this.values[0];
|
||||
this.values[0] = firstValue.then(function (value) {
|
||||
if (_this.shouldUpdateOnHit) {
|
||||
onCacheHit(_this, _this.options, memoized);
|
||||
}
|
||||
if (_this.shouldUpdateOnChange) {
|
||||
onCacheChange(_this, _this.options, memoized);
|
||||
}
|
||||
return value;
|
||||
}, function (error) {
|
||||
var keyIndex = _this.getKeyIndex(firstKey);
|
||||
if (keyIndex !== -1) {
|
||||
_this.keys.splice(keyIndex, 1);
|
||||
_this.values.splice(keyIndex, 1);
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
return Cache;
|
||||
}());
|
||||
|
||||
function createMemoizedFunction(fn, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
if (isMemoized(fn)) {
|
||||
return createMemoizedFunction(fn.fn, mergeOptions(fn.options, options));
|
||||
}
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('You must pass a function to `memoize`.');
|
||||
}
|
||||
var _a = options.isEqual, isEqual = _a === void 0 ? isSameValueZero : _a, isMatchingKey = options.isMatchingKey, _b = options.isPromise, isPromise = _b === void 0 ? false : _b, _c = options.maxSize, maxSize = _c === void 0 ? 1 : _c, onCacheAdd = options.onCacheAdd, onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit, transformKey = options.transformKey;
|
||||
var normalizedOptions = mergeOptions({
|
||||
isEqual: isEqual,
|
||||
isMatchingKey: isMatchingKey,
|
||||
isPromise: isPromise,
|
||||
maxSize: maxSize,
|
||||
onCacheAdd: onCacheAdd,
|
||||
onCacheChange: onCacheChange,
|
||||
onCacheHit: onCacheHit,
|
||||
transformKey: transformKey,
|
||||
}, getCustomOptions(options));
|
||||
var cache = new Cache(normalizedOptions);
|
||||
var keys = cache.keys, values = cache.values, canTransformKey = cache.canTransformKey, shouldCloneArguments = cache.shouldCloneArguments, shouldUpdateOnAdd = cache.shouldUpdateOnAdd, shouldUpdateOnChange = cache.shouldUpdateOnChange, shouldUpdateOnHit = cache.shouldUpdateOnHit;
|
||||
var memoized = function () {
|
||||
var key = shouldCloneArguments
|
||||
? cloneArray(arguments)
|
||||
: arguments;
|
||||
if (canTransformKey) {
|
||||
key = transformKey(key);
|
||||
}
|
||||
var keyIndex = keys.length ? cache.getKeyIndex(key) : -1;
|
||||
if (keyIndex !== -1) {
|
||||
if (shouldUpdateOnHit) {
|
||||
onCacheHit(cache, normalizedOptions, memoized);
|
||||
}
|
||||
if (keyIndex) {
|
||||
cache.orderByLru(keys[keyIndex], values[keyIndex], keyIndex);
|
||||
if (shouldUpdateOnChange) {
|
||||
onCacheChange(cache, normalizedOptions, memoized);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var newValue = fn.apply(this, arguments);
|
||||
var newKey = shouldCloneArguments
|
||||
? key
|
||||
: cloneArray(arguments);
|
||||
cache.orderByLru(newKey, newValue, keys.length);
|
||||
if (isPromise) {
|
||||
cache.updateAsyncCache(memoized);
|
||||
}
|
||||
if (shouldUpdateOnAdd) {
|
||||
onCacheAdd(cache, normalizedOptions, memoized);
|
||||
}
|
||||
if (shouldUpdateOnChange) {
|
||||
onCacheChange(cache, normalizedOptions, memoized);
|
||||
}
|
||||
}
|
||||
return values[0];
|
||||
};
|
||||
memoized.cache = cache;
|
||||
memoized.fn = fn;
|
||||
memoized.isMemoized = true;
|
||||
memoized.options = normalizedOptions;
|
||||
return memoized;
|
||||
}
|
||||
|
||||
export { createMemoizedFunction as default };
|
||||
378
node_modules/micro-memoize/dist/micro-memoize.js
generated
vendored
Normal file
378
node_modules/micro-memoize/dist/micro-memoize.js
generated
vendored
Normal file
@@ -0,0 +1,378 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
||||
typeof define === 'function' && define.amd ? define(factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global["micro-memoize"] = factory());
|
||||
})(this, (function () { 'use strict';
|
||||
|
||||
/**
|
||||
* @constant DEFAULT_OPTIONS_KEYS the default options keys
|
||||
*/
|
||||
var DEFAULT_OPTIONS_KEYS = {
|
||||
isEqual: true,
|
||||
isMatchingKey: true,
|
||||
isPromise: true,
|
||||
maxSize: true,
|
||||
onCacheAdd: true,
|
||||
onCacheChange: true,
|
||||
onCacheHit: true,
|
||||
transformKey: true,
|
||||
};
|
||||
/**
|
||||
* @function slice
|
||||
*
|
||||
* @description
|
||||
* slice.call() pre-bound
|
||||
*/
|
||||
var slice = Array.prototype.slice;
|
||||
/**
|
||||
* @function cloneArray
|
||||
*
|
||||
* @description
|
||||
* clone the array-like object and return the new array
|
||||
*
|
||||
* @param arrayLike the array-like object to clone
|
||||
* @returns the clone as an array
|
||||
*/
|
||||
function cloneArray(arrayLike) {
|
||||
var length = arrayLike.length;
|
||||
if (!length) {
|
||||
return [];
|
||||
}
|
||||
if (length === 1) {
|
||||
return [arrayLike[0]];
|
||||
}
|
||||
if (length === 2) {
|
||||
return [arrayLike[0], arrayLike[1]];
|
||||
}
|
||||
if (length === 3) {
|
||||
return [arrayLike[0], arrayLike[1], arrayLike[2]];
|
||||
}
|
||||
return slice.call(arrayLike, 0);
|
||||
}
|
||||
/**
|
||||
* @function getCustomOptions
|
||||
*
|
||||
* @description
|
||||
* get the custom options on the object passed
|
||||
*
|
||||
* @param options the memoization options passed
|
||||
* @returns the custom options passed
|
||||
*/
|
||||
function getCustomOptions(options) {
|
||||
var customOptions = {};
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
for (var key in options) {
|
||||
if (!DEFAULT_OPTIONS_KEYS[key]) {
|
||||
customOptions[key] = options[key];
|
||||
}
|
||||
}
|
||||
/* eslint-enable */
|
||||
return customOptions;
|
||||
}
|
||||
/**
|
||||
* @function isMemoized
|
||||
*
|
||||
* @description
|
||||
* is the function passed already memoized
|
||||
*
|
||||
* @param fn the function to test
|
||||
* @returns is the function already memoized
|
||||
*/
|
||||
function isMemoized(fn) {
|
||||
return typeof fn === 'function' && fn.isMemoized;
|
||||
}
|
||||
/**
|
||||
* @function isSameValueZero
|
||||
*
|
||||
* @description
|
||||
* are the objects equal based on SameValueZero equality
|
||||
*
|
||||
* @param object1 the first object to compare
|
||||
* @param object2 the second object to compare
|
||||
* @returns are the two objects equal
|
||||
*/
|
||||
function isSameValueZero(object1, object2) {
|
||||
// eslint-disable-next-line no-self-compare
|
||||
return object1 === object2 || (object1 !== object1 && object2 !== object2);
|
||||
}
|
||||
/**
|
||||
* @function mergeOptions
|
||||
*
|
||||
* @description
|
||||
* merge the options into the target
|
||||
*
|
||||
* @param existingOptions the options provided
|
||||
* @param newOptions the options to include
|
||||
* @returns the merged options
|
||||
*/
|
||||
function mergeOptions(existingOptions, newOptions) {
|
||||
var target = {};
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
for (var key in existingOptions) {
|
||||
target[key] = existingOptions[key];
|
||||
}
|
||||
for (var key in newOptions) {
|
||||
target[key] = newOptions[key];
|
||||
}
|
||||
/* eslint-enable */
|
||||
return target;
|
||||
}
|
||||
|
||||
// utils
|
||||
var Cache = /** @class */ (function () {
|
||||
function Cache(options) {
|
||||
this.keys = [];
|
||||
this.values = [];
|
||||
this.options = options;
|
||||
var isMatchingKeyFunction = typeof options.isMatchingKey === 'function';
|
||||
if (isMatchingKeyFunction) {
|
||||
this.getKeyIndex = this._getKeyIndexFromMatchingKey;
|
||||
}
|
||||
else if (options.maxSize > 1) {
|
||||
this.getKeyIndex = this._getKeyIndexForMany;
|
||||
}
|
||||
else {
|
||||
this.getKeyIndex = this._getKeyIndexForSingle;
|
||||
}
|
||||
this.canTransformKey = typeof options.transformKey === 'function';
|
||||
this.shouldCloneArguments = this.canTransformKey || isMatchingKeyFunction;
|
||||
this.shouldUpdateOnAdd = typeof options.onCacheAdd === 'function';
|
||||
this.shouldUpdateOnChange = typeof options.onCacheChange === 'function';
|
||||
this.shouldUpdateOnHit = typeof options.onCacheHit === 'function';
|
||||
}
|
||||
Object.defineProperty(Cache.prototype, "size", {
|
||||
/**
|
||||
* The number of cached [key,value] results.
|
||||
*/
|
||||
get: function () {
|
||||
return this.keys.length;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Cache.prototype, "snapshot", {
|
||||
/**
|
||||
* A copy of the cache at a moment in time. This is useful
|
||||
* to compare changes over time, since the cache mutates
|
||||
* internally for performance reasons.
|
||||
*/
|
||||
get: function () {
|
||||
return {
|
||||
keys: cloneArray(this.keys),
|
||||
size: this.size,
|
||||
values: cloneArray(this.values),
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
/**
|
||||
* Gets the matching key index when a custom key matcher is used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexFromMatchingKey = function (keyToMatch) {
|
||||
var _a = this.options, isMatchingKey = _a.isMatchingKey, maxSize = _a.maxSize;
|
||||
var keys = this.keys;
|
||||
var keysLength = keys.length;
|
||||
if (!keysLength) {
|
||||
return -1;
|
||||
}
|
||||
if (isMatchingKey(keys[0], keyToMatch)) {
|
||||
return 0;
|
||||
}
|
||||
if (maxSize > 1) {
|
||||
for (var index = 1; index < keysLength; index++) {
|
||||
if (isMatchingKey(keys[index], keyToMatch)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
/**
|
||||
* Gets the matching key index when multiple keys are used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexForMany = function (keyToMatch) {
|
||||
var isEqual = this.options.isEqual;
|
||||
var keys = this.keys;
|
||||
var keysLength = keys.length;
|
||||
if (!keysLength) {
|
||||
return -1;
|
||||
}
|
||||
if (keysLength === 1) {
|
||||
return this._getKeyIndexForSingle(keyToMatch);
|
||||
}
|
||||
var keyLength = keyToMatch.length;
|
||||
var existingKey;
|
||||
var argIndex;
|
||||
if (keyLength > 1) {
|
||||
for (var index = 0; index < keysLength; index++) {
|
||||
existingKey = keys[index];
|
||||
if (existingKey.length === keyLength) {
|
||||
argIndex = 0;
|
||||
for (; argIndex < keyLength; argIndex++) {
|
||||
if (!isEqual(existingKey[argIndex], keyToMatch[argIndex])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (argIndex === keyLength) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var index = 0; index < keysLength; index++) {
|
||||
existingKey = keys[index];
|
||||
if (existingKey.length === keyLength &&
|
||||
isEqual(existingKey[0], keyToMatch[0])) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
/**
|
||||
* Gets the matching key index when a single key is used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexForSingle = function (keyToMatch) {
|
||||
var keys = this.keys;
|
||||
if (!keys.length) {
|
||||
return -1;
|
||||
}
|
||||
var existingKey = keys[0];
|
||||
var length = existingKey.length;
|
||||
if (keyToMatch.length !== length) {
|
||||
return -1;
|
||||
}
|
||||
var isEqual = this.options.isEqual;
|
||||
if (length > 1) {
|
||||
for (var index = 0; index < length; index++) {
|
||||
if (!isEqual(existingKey[index], keyToMatch[index])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return isEqual(existingKey[0], keyToMatch[0]) ? 0 : -1;
|
||||
};
|
||||
/**
|
||||
* Order the array based on a Least-Recently-Used basis.
|
||||
*/
|
||||
Cache.prototype.orderByLru = function (key, value, startingIndex) {
|
||||
var keys = this.keys;
|
||||
var values = this.values;
|
||||
var currentLength = keys.length;
|
||||
var index = startingIndex;
|
||||
while (index--) {
|
||||
keys[index + 1] = keys[index];
|
||||
values[index + 1] = values[index];
|
||||
}
|
||||
keys[0] = key;
|
||||
values[0] = value;
|
||||
var maxSize = this.options.maxSize;
|
||||
if (currentLength === maxSize && startingIndex === currentLength) {
|
||||
keys.pop();
|
||||
values.pop();
|
||||
}
|
||||
else if (startingIndex >= maxSize) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
keys.length = values.length = maxSize;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Update the promise method to auto-remove from cache if rejected, and
|
||||
* if resolved then fire cache hit / changed.
|
||||
*/
|
||||
Cache.prototype.updateAsyncCache = function (memoized) {
|
||||
var _this = this;
|
||||
var _a = this.options, onCacheChange = _a.onCacheChange, onCacheHit = _a.onCacheHit;
|
||||
var firstKey = this.keys[0];
|
||||
var firstValue = this.values[0];
|
||||
this.values[0] = firstValue.then(function (value) {
|
||||
if (_this.shouldUpdateOnHit) {
|
||||
onCacheHit(_this, _this.options, memoized);
|
||||
}
|
||||
if (_this.shouldUpdateOnChange) {
|
||||
onCacheChange(_this, _this.options, memoized);
|
||||
}
|
||||
return value;
|
||||
}, function (error) {
|
||||
var keyIndex = _this.getKeyIndex(firstKey);
|
||||
if (keyIndex !== -1) {
|
||||
_this.keys.splice(keyIndex, 1);
|
||||
_this.values.splice(keyIndex, 1);
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
return Cache;
|
||||
}());
|
||||
|
||||
function createMemoizedFunction(fn, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
if (isMemoized(fn)) {
|
||||
return createMemoizedFunction(fn.fn, mergeOptions(fn.options, options));
|
||||
}
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('You must pass a function to `memoize`.');
|
||||
}
|
||||
var _a = options.isEqual, isEqual = _a === void 0 ? isSameValueZero : _a, isMatchingKey = options.isMatchingKey, _b = options.isPromise, isPromise = _b === void 0 ? false : _b, _c = options.maxSize, maxSize = _c === void 0 ? 1 : _c, onCacheAdd = options.onCacheAdd, onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit, transformKey = options.transformKey;
|
||||
var normalizedOptions = mergeOptions({
|
||||
isEqual: isEqual,
|
||||
isMatchingKey: isMatchingKey,
|
||||
isPromise: isPromise,
|
||||
maxSize: maxSize,
|
||||
onCacheAdd: onCacheAdd,
|
||||
onCacheChange: onCacheChange,
|
||||
onCacheHit: onCacheHit,
|
||||
transformKey: transformKey,
|
||||
}, getCustomOptions(options));
|
||||
var cache = new Cache(normalizedOptions);
|
||||
var keys = cache.keys, values = cache.values, canTransformKey = cache.canTransformKey, shouldCloneArguments = cache.shouldCloneArguments, shouldUpdateOnAdd = cache.shouldUpdateOnAdd, shouldUpdateOnChange = cache.shouldUpdateOnChange, shouldUpdateOnHit = cache.shouldUpdateOnHit;
|
||||
var memoized = function () {
|
||||
var key = shouldCloneArguments
|
||||
? cloneArray(arguments)
|
||||
: arguments;
|
||||
if (canTransformKey) {
|
||||
key = transformKey(key);
|
||||
}
|
||||
var keyIndex = keys.length ? cache.getKeyIndex(key) : -1;
|
||||
if (keyIndex !== -1) {
|
||||
if (shouldUpdateOnHit) {
|
||||
onCacheHit(cache, normalizedOptions, memoized);
|
||||
}
|
||||
if (keyIndex) {
|
||||
cache.orderByLru(keys[keyIndex], values[keyIndex], keyIndex);
|
||||
if (shouldUpdateOnChange) {
|
||||
onCacheChange(cache, normalizedOptions, memoized);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var newValue = fn.apply(this, arguments);
|
||||
var newKey = shouldCloneArguments
|
||||
? key
|
||||
: cloneArray(arguments);
|
||||
cache.orderByLru(newKey, newValue, keys.length);
|
||||
if (isPromise) {
|
||||
cache.updateAsyncCache(memoized);
|
||||
}
|
||||
if (shouldUpdateOnAdd) {
|
||||
onCacheAdd(cache, normalizedOptions, memoized);
|
||||
}
|
||||
if (shouldUpdateOnChange) {
|
||||
onCacheChange(cache, normalizedOptions, memoized);
|
||||
}
|
||||
}
|
||||
return values[0];
|
||||
};
|
||||
memoized.cache = cache;
|
||||
memoized.fn = fn;
|
||||
memoized.isMemoized = true;
|
||||
memoized.options = normalizedOptions;
|
||||
return memoized;
|
||||
}
|
||||
|
||||
return createMemoizedFunction;
|
||||
|
||||
}));
|
||||
1
node_modules/micro-memoize/dist/micro-memoize.min.js
generated
vendored
Normal file
1
node_modules/micro-memoize/dist/micro-memoize.min.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self)["micro-memoize"]=t()}(this,(function(){"use strict";var e={isEqual:!0,isMatchingKey:!0,isPromise:!0,maxSize:!0,onCacheAdd:!0,onCacheChange:!0,onCacheHit:!0,transformKey:!0},t=Array.prototype.slice;function n(e){var n=e.length;return n?1===n?[e[0]]:2===n?[e[0],e[1]]:3===n?[e[0],e[1],e[2]]:t.call(e,0):[]}function i(e,t){return e===t||e!=e&&t!=t}function o(e,t){var n={};for(var i in e)n[i]=e[i];for(var i in t)n[i]=t[i];return n}var r=function(){function e(e){this.keys=[],this.values=[],this.options=e;var t="function"==typeof e.isMatchingKey;t?this.getKeyIndex=this._getKeyIndexFromMatchingKey:e.maxSize>1?this.getKeyIndex=this._getKeyIndexForMany:this.getKeyIndex=this._getKeyIndexForSingle,this.canTransformKey="function"==typeof e.transformKey,this.shouldCloneArguments=this.canTransformKey||t,this.shouldUpdateOnAdd="function"==typeof e.onCacheAdd,this.shouldUpdateOnChange="function"==typeof e.onCacheChange,this.shouldUpdateOnHit="function"==typeof e.onCacheHit}return Object.defineProperty(e.prototype,"size",{get:function(){return this.keys.length},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"snapshot",{get:function(){return{keys:n(this.keys),size:this.size,values:n(this.values)}},enumerable:!1,configurable:!0}),e.prototype._getKeyIndexFromMatchingKey=function(e){var t=this.options,n=t.isMatchingKey,i=t.maxSize,o=this.keys,r=o.length;if(!r)return-1;if(n(o[0],e))return 0;if(i>1)for(var s=1;s<r;s++)if(n(o[s],e))return s;return-1},e.prototype._getKeyIndexForMany=function(e){var t=this.options.isEqual,n=this.keys,i=n.length;if(!i)return-1;if(1===i)return this._getKeyIndexForSingle(e);var o,r,s=e.length;if(s>1){for(var a=0;a<i;a++)if((o=n[a]).length===s){for(r=0;r<s&&t(o[r],e[r]);r++);if(r===s)return a}}else for(a=0;a<i;a++)if((o=n[a]).length===s&&t(o[0],e[0]))return a;return-1},e.prototype._getKeyIndexForSingle=function(e){var t=this.keys;if(!t.length)return-1;var n=t[0],i=n.length;if(e.length!==i)return-1;var o=this.options.isEqual;if(i>1){for(var r=0;r<i;r++)if(!o(n[r],e[r]))return-1;return 0}return o(n[0],e[0])?0:-1},e.prototype.orderByLru=function(e,t,n){for(var i=this.keys,o=this.values,r=i.length,s=n;s--;)i[s+1]=i[s],o[s+1]=o[s];i[0]=e,o[0]=t;var a=this.options.maxSize;r===a&&n===r?(i.pop(),o.pop()):n>=a&&(i.length=o.length=a)},e.prototype.updateAsyncCache=function(e){var t=this,n=this.options,i=n.onCacheChange,o=n.onCacheHit,r=this.keys[0],s=this.values[0];this.values[0]=s.then((function(n){return t.shouldUpdateOnHit&&o(t,t.options,e),t.shouldUpdateOnChange&&i(t,t.options,e),n}),(function(e){var n=t.getKeyIndex(r);throw-1!==n&&(t.keys.splice(n,1),t.values.splice(n,1)),e}))},e}();return function t(s,a){if(void 0===a&&(a={}),function(e){return"function"==typeof e&&e.isMemoized}(s))return t(s.fn,o(s.options,a));if("function"!=typeof s)throw new TypeError("You must pass a function to `memoize`.");var h=a.isEqual,u=void 0===h?i:h,f=a.isMatchingKey,c=a.isPromise,y=void 0!==c&&c,d=a.maxSize,l=void 0===d?1:d,p=a.onCacheAdd,g=a.onCacheChange,v=a.onCacheHit,m=a.transformKey,C=o({isEqual:u,isMatchingKey:f,isPromise:y,maxSize:l,onCacheAdd:p,onCacheChange:g,onCacheHit:v,transformKey:m},function(t){var n={};for(var i in t)e[i]||(n[i]=t[i]);return n}(a)),K=new r(C),x=K.keys,z=K.values,I=K.canTransformKey,k=K.shouldCloneArguments,A=K.shouldUpdateOnAdd,M=K.shouldUpdateOnChange,O=K.shouldUpdateOnHit,b=function(){var e=k?n(arguments):arguments;I&&(e=m(e));var t=x.length?K.getKeyIndex(e):-1;if(-1!==t)O&&v(K,C,b),t&&(K.orderByLru(x[t],z[t],t),M&&g(K,C,b));else{var i=s.apply(this,arguments),o=k?e:n(arguments);K.orderByLru(o,i,x.length),y&&K.updateAsyncCache(b),A&&p(K,C,b),M&&g(K,C,b)}return z[0]};return b.cache=K,b.fn=s,b.isMemoized=!0,b.options=C,b}}));
|
||||
132
node_modules/micro-memoize/index.d.ts
generated
vendored
Normal file
132
node_modules/micro-memoize/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
export interface Dictionary<Type> {
|
||||
[key: string]: Type;
|
||||
[index: number]: Type;
|
||||
}
|
||||
|
||||
export type AnyFn = (...args: any[]) => any;
|
||||
|
||||
export type Key = any[];
|
||||
export type RawKey = Key | IArguments;
|
||||
export type Value = any;
|
||||
|
||||
export interface CacheSnapshot {
|
||||
keys: Key[];
|
||||
size: number;
|
||||
values: Value[];
|
||||
}
|
||||
|
||||
export class Cache<Fn extends AnyFn> {
|
||||
readonly canTransformKey: boolean;
|
||||
readonly getKeyIndex: KeyIndexGetter;
|
||||
readonly options: NormalizedOptions<Fn>;
|
||||
readonly shouldCloneArguments: boolean;
|
||||
readonly shouldUpdateOnAdd: boolean;
|
||||
readonly shouldUpdateOnChange: boolean;
|
||||
readonly shouldUpdateOnHit: boolean;
|
||||
|
||||
/**
|
||||
* The prevents call arguments which have cached results.
|
||||
*/
|
||||
keys: Key[];
|
||||
/**
|
||||
* The results of previous cached calls.
|
||||
*/
|
||||
values: Value[];
|
||||
|
||||
constructor(options: NormalizedOptions<Fn>);
|
||||
|
||||
/**
|
||||
* The number of cached [key,value] results.
|
||||
*/
|
||||
get size(): number;
|
||||
|
||||
/**
|
||||
* A copy of the cache at a moment in time. This is useful
|
||||
* to compare changes over time, since the cache mutates
|
||||
* internally for performance reasons.
|
||||
*/
|
||||
get snapshot(): CacheSnapshot;
|
||||
|
||||
/**
|
||||
* Order the array based on a Least-Recently-Used basis.
|
||||
*/
|
||||
orderByLru(key: Key, value: Value, startingIndex: number): void;
|
||||
|
||||
/**
|
||||
* Update the promise method to auto-remove from cache if rejected, and
|
||||
* if resolved then fire cache hit / changed.
|
||||
*/
|
||||
updateAsyncCache(memoized: Memoized<Fn>): void;
|
||||
}
|
||||
|
||||
export type EqualityComparator = (object1: any, object2: any) => boolean;
|
||||
|
||||
export type MatchingKeyComparator = (key1: Key, key2: RawKey) => boolean;
|
||||
|
||||
export type CacheModifiedHandler<Fn extends AnyFn> = (
|
||||
cache: Cache<Fn>,
|
||||
options: NormalizedOptions<Fn>,
|
||||
memoized: Memoized<Fn>,
|
||||
) => void;
|
||||
|
||||
export type KeyTransformer = (args: Key) => Key;
|
||||
|
||||
export type KeyIndexGetter = (keyToMatch: RawKey) => number;
|
||||
|
||||
export interface StandardOptions<Fn extends AnyFn> {
|
||||
isEqual?: EqualityComparator;
|
||||
isMatchingKey?: MatchingKeyComparator;
|
||||
isPromise?: boolean;
|
||||
maxSize?: number;
|
||||
onCacheAdd?: CacheModifiedHandler<Fn>;
|
||||
onCacheChange?: CacheModifiedHandler<Fn>;
|
||||
onCacheHit?: CacheModifiedHandler<Fn>;
|
||||
transformKey?: KeyTransformer;
|
||||
}
|
||||
|
||||
export interface Options<Fn extends AnyFn>
|
||||
extends StandardOptions<Fn>,
|
||||
Dictionary<any> {}
|
||||
|
||||
export interface NormalizedOptions<Fn extends AnyFn> extends Options<Fn> {
|
||||
isEqual: EqualityComparator;
|
||||
isPromise: boolean;
|
||||
maxSize: number;
|
||||
}
|
||||
|
||||
export type Memoized<Fn extends AnyFn> = Fn &
|
||||
Dictionary<any> & {
|
||||
cache: Cache<Fn>;
|
||||
fn: Fn;
|
||||
isMemoized: true;
|
||||
options: NormalizedOptions<Fn>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* All types declared on this namespace are available for direct import
|
||||
* from the package. In a future release, this namespace will be removed
|
||||
* in favor of those direct imports.
|
||||
*/
|
||||
export declare namespace MicroMemoize {
|
||||
export type {
|
||||
Cache,
|
||||
CacheModifiedHandler,
|
||||
EqualityComparator,
|
||||
Key,
|
||||
KeyIndexGetter,
|
||||
KeyTransformer,
|
||||
MatchingKeyComparator,
|
||||
Memoized,
|
||||
NormalizedOptions,
|
||||
Options,
|
||||
StandardOptions,
|
||||
RawKey,
|
||||
Value,
|
||||
};
|
||||
}
|
||||
|
||||
export default function memoize<Fn extends AnyFn>(
|
||||
fn: Fn | Memoized<Fn>,
|
||||
options?: Options<Fn>,
|
||||
): Memoized<Fn>;
|
||||
132
node_modules/micro-memoize/mjs/index.d.mts
generated
vendored
Normal file
132
node_modules/micro-memoize/mjs/index.d.mts
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
export interface Dictionary<Type> {
|
||||
[key: string]: Type;
|
||||
[index: number]: Type;
|
||||
}
|
||||
|
||||
export type AnyFn = (...args: any[]) => any;
|
||||
|
||||
export type Key = any[];
|
||||
export type RawKey = Key | IArguments;
|
||||
export type Value = any;
|
||||
|
||||
export interface CacheSnapshot {
|
||||
keys: Key[];
|
||||
size: number;
|
||||
values: Value[];
|
||||
}
|
||||
|
||||
export class Cache<Fn extends AnyFn> {
|
||||
readonly canTransformKey: boolean;
|
||||
readonly getKeyIndex: KeyIndexGetter;
|
||||
readonly options: NormalizedOptions<Fn>;
|
||||
readonly shouldCloneArguments: boolean;
|
||||
readonly shouldUpdateOnAdd: boolean;
|
||||
readonly shouldUpdateOnChange: boolean;
|
||||
readonly shouldUpdateOnHit: boolean;
|
||||
|
||||
/**
|
||||
* The prevents call arguments which have cached results.
|
||||
*/
|
||||
keys: Key[];
|
||||
/**
|
||||
* The results of previous cached calls.
|
||||
*/
|
||||
values: Value[];
|
||||
|
||||
constructor(options: NormalizedOptions<Fn>);
|
||||
|
||||
/**
|
||||
* The number of cached [key,value] results.
|
||||
*/
|
||||
get size(): number;
|
||||
|
||||
/**
|
||||
* A copy of the cache at a moment in time. This is useful
|
||||
* to compare changes over time, since the cache mutates
|
||||
* internally for performance reasons.
|
||||
*/
|
||||
get snapshot(): CacheSnapshot;
|
||||
|
||||
/**
|
||||
* Order the array based on a Least-Recently-Used basis.
|
||||
*/
|
||||
orderByLru(key: Key, value: Value, startingIndex: number): void;
|
||||
|
||||
/**
|
||||
* Update the promise method to auto-remove from cache if rejected, and
|
||||
* if resolved then fire cache hit / changed.
|
||||
*/
|
||||
updateAsyncCache(memoized: Memoized<Fn>): void;
|
||||
}
|
||||
|
||||
export type EqualityComparator = (object1: any, object2: any) => boolean;
|
||||
|
||||
export type MatchingKeyComparator = (key1: Key, key2: RawKey) => boolean;
|
||||
|
||||
export type CacheModifiedHandler<Fn extends AnyFn> = (
|
||||
cache: Cache<Fn>,
|
||||
options: NormalizedOptions<Fn>,
|
||||
memoized: Memoized<Fn>,
|
||||
) => void;
|
||||
|
||||
export type KeyTransformer = (args: Key) => Key;
|
||||
|
||||
export type KeyIndexGetter = (keyToMatch: RawKey) => number;
|
||||
|
||||
export interface StandardOptions<Fn extends AnyFn> {
|
||||
isEqual?: EqualityComparator;
|
||||
isMatchingKey?: MatchingKeyComparator;
|
||||
isPromise?: boolean;
|
||||
maxSize?: number;
|
||||
onCacheAdd?: CacheModifiedHandler<Fn>;
|
||||
onCacheChange?: CacheModifiedHandler<Fn>;
|
||||
onCacheHit?: CacheModifiedHandler<Fn>;
|
||||
transformKey?: KeyTransformer;
|
||||
}
|
||||
|
||||
export interface Options<Fn extends AnyFn>
|
||||
extends StandardOptions<Fn>,
|
||||
Dictionary<any> {}
|
||||
|
||||
export interface NormalizedOptions<Fn extends AnyFn> extends Options<Fn> {
|
||||
isEqual: EqualityComparator;
|
||||
isPromise: boolean;
|
||||
maxSize: number;
|
||||
}
|
||||
|
||||
export type Memoized<Fn extends AnyFn> = Fn &
|
||||
Dictionary<any> & {
|
||||
cache: Cache<Fn>;
|
||||
fn: Fn;
|
||||
isMemoized: true;
|
||||
options: NormalizedOptions<Fn>;
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* All types declared on this namespace are available for direct import
|
||||
* from the package. In a future release, this namespace will be removed
|
||||
* in favor of those direct imports.
|
||||
*/
|
||||
export declare namespace MicroMemoize {
|
||||
export type {
|
||||
Cache,
|
||||
CacheModifiedHandler,
|
||||
EqualityComparator,
|
||||
Key,
|
||||
KeyIndexGetter,
|
||||
KeyTransformer,
|
||||
MatchingKeyComparator,
|
||||
Memoized,
|
||||
NormalizedOptions,
|
||||
Options,
|
||||
StandardOptions,
|
||||
RawKey,
|
||||
Value,
|
||||
};
|
||||
}
|
||||
|
||||
export default function memoize<Fn extends AnyFn>(
|
||||
fn: Fn | Memoized<Fn>,
|
||||
options?: Options<Fn>,
|
||||
): Memoized<Fn>;
|
||||
370
node_modules/micro-memoize/mjs/index.mjs
generated
vendored
Normal file
370
node_modules/micro-memoize/mjs/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,370 @@
|
||||
/**
|
||||
* @constant DEFAULT_OPTIONS_KEYS the default options keys
|
||||
*/
|
||||
var DEFAULT_OPTIONS_KEYS = {
|
||||
isEqual: true,
|
||||
isMatchingKey: true,
|
||||
isPromise: true,
|
||||
maxSize: true,
|
||||
onCacheAdd: true,
|
||||
onCacheChange: true,
|
||||
onCacheHit: true,
|
||||
transformKey: true,
|
||||
};
|
||||
/**
|
||||
* @function slice
|
||||
*
|
||||
* @description
|
||||
* slice.call() pre-bound
|
||||
*/
|
||||
var slice = Array.prototype.slice;
|
||||
/**
|
||||
* @function cloneArray
|
||||
*
|
||||
* @description
|
||||
* clone the array-like object and return the new array
|
||||
*
|
||||
* @param arrayLike the array-like object to clone
|
||||
* @returns the clone as an array
|
||||
*/
|
||||
function cloneArray(arrayLike) {
|
||||
var length = arrayLike.length;
|
||||
if (!length) {
|
||||
return [];
|
||||
}
|
||||
if (length === 1) {
|
||||
return [arrayLike[0]];
|
||||
}
|
||||
if (length === 2) {
|
||||
return [arrayLike[0], arrayLike[1]];
|
||||
}
|
||||
if (length === 3) {
|
||||
return [arrayLike[0], arrayLike[1], arrayLike[2]];
|
||||
}
|
||||
return slice.call(arrayLike, 0);
|
||||
}
|
||||
/**
|
||||
* @function getCustomOptions
|
||||
*
|
||||
* @description
|
||||
* get the custom options on the object passed
|
||||
*
|
||||
* @param options the memoization options passed
|
||||
* @returns the custom options passed
|
||||
*/
|
||||
function getCustomOptions(options) {
|
||||
var customOptions = {};
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
for (var key in options) {
|
||||
if (!DEFAULT_OPTIONS_KEYS[key]) {
|
||||
customOptions[key] = options[key];
|
||||
}
|
||||
}
|
||||
/* eslint-enable */
|
||||
return customOptions;
|
||||
}
|
||||
/**
|
||||
* @function isMemoized
|
||||
*
|
||||
* @description
|
||||
* is the function passed already memoized
|
||||
*
|
||||
* @param fn the function to test
|
||||
* @returns is the function already memoized
|
||||
*/
|
||||
function isMemoized(fn) {
|
||||
return typeof fn === 'function' && fn.isMemoized;
|
||||
}
|
||||
/**
|
||||
* @function isSameValueZero
|
||||
*
|
||||
* @description
|
||||
* are the objects equal based on SameValueZero equality
|
||||
*
|
||||
* @param object1 the first object to compare
|
||||
* @param object2 the second object to compare
|
||||
* @returns are the two objects equal
|
||||
*/
|
||||
function isSameValueZero(object1, object2) {
|
||||
// eslint-disable-next-line no-self-compare
|
||||
return object1 === object2 || (object1 !== object1 && object2 !== object2);
|
||||
}
|
||||
/**
|
||||
* @function mergeOptions
|
||||
*
|
||||
* @description
|
||||
* merge the options into the target
|
||||
*
|
||||
* @param existingOptions the options provided
|
||||
* @param newOptions the options to include
|
||||
* @returns the merged options
|
||||
*/
|
||||
function mergeOptions(existingOptions, newOptions) {
|
||||
var target = {};
|
||||
/* eslint-disable no-restricted-syntax */
|
||||
for (var key in existingOptions) {
|
||||
target[key] = existingOptions[key];
|
||||
}
|
||||
for (var key in newOptions) {
|
||||
target[key] = newOptions[key];
|
||||
}
|
||||
/* eslint-enable */
|
||||
return target;
|
||||
}
|
||||
|
||||
// utils
|
||||
var Cache = /** @class */ (function () {
|
||||
function Cache(options) {
|
||||
this.keys = [];
|
||||
this.values = [];
|
||||
this.options = options;
|
||||
var isMatchingKeyFunction = typeof options.isMatchingKey === 'function';
|
||||
if (isMatchingKeyFunction) {
|
||||
this.getKeyIndex = this._getKeyIndexFromMatchingKey;
|
||||
}
|
||||
else if (options.maxSize > 1) {
|
||||
this.getKeyIndex = this._getKeyIndexForMany;
|
||||
}
|
||||
else {
|
||||
this.getKeyIndex = this._getKeyIndexForSingle;
|
||||
}
|
||||
this.canTransformKey = typeof options.transformKey === 'function';
|
||||
this.shouldCloneArguments = this.canTransformKey || isMatchingKeyFunction;
|
||||
this.shouldUpdateOnAdd = typeof options.onCacheAdd === 'function';
|
||||
this.shouldUpdateOnChange = typeof options.onCacheChange === 'function';
|
||||
this.shouldUpdateOnHit = typeof options.onCacheHit === 'function';
|
||||
}
|
||||
Object.defineProperty(Cache.prototype, "size", {
|
||||
/**
|
||||
* The number of cached [key,value] results.
|
||||
*/
|
||||
get: function () {
|
||||
return this.keys.length;
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
Object.defineProperty(Cache.prototype, "snapshot", {
|
||||
/**
|
||||
* A copy of the cache at a moment in time. This is useful
|
||||
* to compare changes over time, since the cache mutates
|
||||
* internally for performance reasons.
|
||||
*/
|
||||
get: function () {
|
||||
return {
|
||||
keys: cloneArray(this.keys),
|
||||
size: this.size,
|
||||
values: cloneArray(this.values),
|
||||
};
|
||||
},
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
});
|
||||
/**
|
||||
* Gets the matching key index when a custom key matcher is used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexFromMatchingKey = function (keyToMatch) {
|
||||
var _a = this.options, isMatchingKey = _a.isMatchingKey, maxSize = _a.maxSize;
|
||||
var keys = this.keys;
|
||||
var keysLength = keys.length;
|
||||
if (!keysLength) {
|
||||
return -1;
|
||||
}
|
||||
if (isMatchingKey(keys[0], keyToMatch)) {
|
||||
return 0;
|
||||
}
|
||||
if (maxSize > 1) {
|
||||
for (var index = 1; index < keysLength; index++) {
|
||||
if (isMatchingKey(keys[index], keyToMatch)) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
/**
|
||||
* Gets the matching key index when multiple keys are used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexForMany = function (keyToMatch) {
|
||||
var isEqual = this.options.isEqual;
|
||||
var keys = this.keys;
|
||||
var keysLength = keys.length;
|
||||
if (!keysLength) {
|
||||
return -1;
|
||||
}
|
||||
if (keysLength === 1) {
|
||||
return this._getKeyIndexForSingle(keyToMatch);
|
||||
}
|
||||
var keyLength = keyToMatch.length;
|
||||
var existingKey;
|
||||
var argIndex;
|
||||
if (keyLength > 1) {
|
||||
for (var index = 0; index < keysLength; index++) {
|
||||
existingKey = keys[index];
|
||||
if (existingKey.length === keyLength) {
|
||||
argIndex = 0;
|
||||
for (; argIndex < keyLength; argIndex++) {
|
||||
if (!isEqual(existingKey[argIndex], keyToMatch[argIndex])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (argIndex === keyLength) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (var index = 0; index < keysLength; index++) {
|
||||
existingKey = keys[index];
|
||||
if (existingKey.length === keyLength &&
|
||||
isEqual(existingKey[0], keyToMatch[0])) {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
/**
|
||||
* Gets the matching key index when a single key is used.
|
||||
*/
|
||||
Cache.prototype._getKeyIndexForSingle = function (keyToMatch) {
|
||||
var keys = this.keys;
|
||||
if (!keys.length) {
|
||||
return -1;
|
||||
}
|
||||
var existingKey = keys[0];
|
||||
var length = existingKey.length;
|
||||
if (keyToMatch.length !== length) {
|
||||
return -1;
|
||||
}
|
||||
var isEqual = this.options.isEqual;
|
||||
if (length > 1) {
|
||||
for (var index = 0; index < length; index++) {
|
||||
if (!isEqual(existingKey[index], keyToMatch[index])) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return isEqual(existingKey[0], keyToMatch[0]) ? 0 : -1;
|
||||
};
|
||||
/**
|
||||
* Order the array based on a Least-Recently-Used basis.
|
||||
*/
|
||||
Cache.prototype.orderByLru = function (key, value, startingIndex) {
|
||||
var keys = this.keys;
|
||||
var values = this.values;
|
||||
var currentLength = keys.length;
|
||||
var index = startingIndex;
|
||||
while (index--) {
|
||||
keys[index + 1] = keys[index];
|
||||
values[index + 1] = values[index];
|
||||
}
|
||||
keys[0] = key;
|
||||
values[0] = value;
|
||||
var maxSize = this.options.maxSize;
|
||||
if (currentLength === maxSize && startingIndex === currentLength) {
|
||||
keys.pop();
|
||||
values.pop();
|
||||
}
|
||||
else if (startingIndex >= maxSize) {
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
keys.length = values.length = maxSize;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Update the promise method to auto-remove from cache if rejected, and
|
||||
* if resolved then fire cache hit / changed.
|
||||
*/
|
||||
Cache.prototype.updateAsyncCache = function (memoized) {
|
||||
var _this = this;
|
||||
var _a = this.options, onCacheChange = _a.onCacheChange, onCacheHit = _a.onCacheHit;
|
||||
var firstKey = this.keys[0];
|
||||
var firstValue = this.values[0];
|
||||
this.values[0] = firstValue.then(function (value) {
|
||||
if (_this.shouldUpdateOnHit) {
|
||||
onCacheHit(_this, _this.options, memoized);
|
||||
}
|
||||
if (_this.shouldUpdateOnChange) {
|
||||
onCacheChange(_this, _this.options, memoized);
|
||||
}
|
||||
return value;
|
||||
}, function (error) {
|
||||
var keyIndex = _this.getKeyIndex(firstKey);
|
||||
if (keyIndex !== -1) {
|
||||
_this.keys.splice(keyIndex, 1);
|
||||
_this.values.splice(keyIndex, 1);
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
return Cache;
|
||||
}());
|
||||
|
||||
function createMemoizedFunction(fn, options) {
|
||||
if (options === void 0) { options = {}; }
|
||||
if (isMemoized(fn)) {
|
||||
return createMemoizedFunction(fn.fn, mergeOptions(fn.options, options));
|
||||
}
|
||||
if (typeof fn !== 'function') {
|
||||
throw new TypeError('You must pass a function to `memoize`.');
|
||||
}
|
||||
var _a = options.isEqual, isEqual = _a === void 0 ? isSameValueZero : _a, isMatchingKey = options.isMatchingKey, _b = options.isPromise, isPromise = _b === void 0 ? false : _b, _c = options.maxSize, maxSize = _c === void 0 ? 1 : _c, onCacheAdd = options.onCacheAdd, onCacheChange = options.onCacheChange, onCacheHit = options.onCacheHit, transformKey = options.transformKey;
|
||||
var normalizedOptions = mergeOptions({
|
||||
isEqual: isEqual,
|
||||
isMatchingKey: isMatchingKey,
|
||||
isPromise: isPromise,
|
||||
maxSize: maxSize,
|
||||
onCacheAdd: onCacheAdd,
|
||||
onCacheChange: onCacheChange,
|
||||
onCacheHit: onCacheHit,
|
||||
transformKey: transformKey,
|
||||
}, getCustomOptions(options));
|
||||
var cache = new Cache(normalizedOptions);
|
||||
var keys = cache.keys, values = cache.values, canTransformKey = cache.canTransformKey, shouldCloneArguments = cache.shouldCloneArguments, shouldUpdateOnAdd = cache.shouldUpdateOnAdd, shouldUpdateOnChange = cache.shouldUpdateOnChange, shouldUpdateOnHit = cache.shouldUpdateOnHit;
|
||||
var memoized = function () {
|
||||
var key = shouldCloneArguments
|
||||
? cloneArray(arguments)
|
||||
: arguments;
|
||||
if (canTransformKey) {
|
||||
key = transformKey(key);
|
||||
}
|
||||
var keyIndex = keys.length ? cache.getKeyIndex(key) : -1;
|
||||
if (keyIndex !== -1) {
|
||||
if (shouldUpdateOnHit) {
|
||||
onCacheHit(cache, normalizedOptions, memoized);
|
||||
}
|
||||
if (keyIndex) {
|
||||
cache.orderByLru(keys[keyIndex], values[keyIndex], keyIndex);
|
||||
if (shouldUpdateOnChange) {
|
||||
onCacheChange(cache, normalizedOptions, memoized);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
var newValue = fn.apply(this, arguments);
|
||||
var newKey = shouldCloneArguments
|
||||
? key
|
||||
: cloneArray(arguments);
|
||||
cache.orderByLru(newKey, newValue, keys.length);
|
||||
if (isPromise) {
|
||||
cache.updateAsyncCache(memoized);
|
||||
}
|
||||
if (shouldUpdateOnAdd) {
|
||||
onCacheAdd(cache, normalizedOptions, memoized);
|
||||
}
|
||||
if (shouldUpdateOnChange) {
|
||||
onCacheChange(cache, normalizedOptions, memoized);
|
||||
}
|
||||
}
|
||||
return values[0];
|
||||
};
|
||||
memoized.cache = cache;
|
||||
memoized.fn = fn;
|
||||
memoized.isMemoized = true;
|
||||
memoized.options = normalizedOptions;
|
||||
return memoized;
|
||||
}
|
||||
|
||||
export { createMemoizedFunction as default };
|
||||
106
node_modules/micro-memoize/package.json
generated
vendored
Normal file
106
node_modules/micro-memoize/package.json
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"author": "tony.quetano@planttheidea.com",
|
||||
"browser": "dist/micro-memoize.js",
|
||||
"browserslist": [
|
||||
"defaults",
|
||||
"Explorer >= 9",
|
||||
"Safari >= 6",
|
||||
"Opera >= 15",
|
||||
"iOS >= 8",
|
||||
"Android >= 4"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://github.com/planttheidea/micro-memoize/issues"
|
||||
},
|
||||
"description": "A tiny, crazy fast memoization library for the 95% use-case",
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-terser": "^0.4.1",
|
||||
"@rollup/plugin-typescript": "^11.1.0",
|
||||
"@types/bluebird": "^3.5.38",
|
||||
"@types/jest": "^29.5.1",
|
||||
"@types/react": "^18.2.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.2",
|
||||
"@typescript-eslint/parser": "^5.59.2",
|
||||
"benchee": "^1.1.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"bluebird": "^3.7.2",
|
||||
"cli-table2": "^0.2.0",
|
||||
"eslint": "^8.40.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-webpack-plugin": "^4.0.1",
|
||||
"fast-equals": "^5.0.1",
|
||||
"fast-memoize": "^2.5.2",
|
||||
"html-webpack-plugin": "^5.5.1",
|
||||
"in-publish": "^2.0.1",
|
||||
"jest": "^29.5.0",
|
||||
"lodash": "^4.17.21",
|
||||
"lru-memoize": "^1.1.0",
|
||||
"mem": "^8.1.1",
|
||||
"memoizee": "^0.4.15",
|
||||
"memoizerific": "^1.11.3",
|
||||
"mini-bench": "^1.0.0",
|
||||
"ora": "^6.3.0",
|
||||
"performance-now": "^2.1.0",
|
||||
"ramda": "^0.29.0",
|
||||
"react": "^18.2.0",
|
||||
"release-it": "^15.10.3",
|
||||
"rollup": "^3.21.5",
|
||||
"rsvp": "^4.8.5",
|
||||
"simple-statistics": "^7.8.3",
|
||||
"ts-jest": "^29.1.0",
|
||||
"ts-loader": "^9.4.2",
|
||||
"tslib": "^2.5.0",
|
||||
"typescript": "^5.0.4",
|
||||
"underscore": "^1.13.6",
|
||||
"webpack": "^5.82.0",
|
||||
"webpack-cli": "^5.1.0",
|
||||
"webpack-dev-server": "^4.15.0"
|
||||
},
|
||||
"homepage": "https://github.com/planttheidea/micro-memoize#readme",
|
||||
"keywords": [
|
||||
"memoize",
|
||||
"memoized",
|
||||
"memoizer",
|
||||
"memoization",
|
||||
"memo",
|
||||
"cache",
|
||||
"cached",
|
||||
"storage",
|
||||
"memory",
|
||||
"optimize",
|
||||
"performance",
|
||||
"lru",
|
||||
"expire"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "dist/micro-memoize.cjs.js",
|
||||
"module": "dist/micro-memoize.esm.js",
|
||||
"name": "micro-memoize",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/planttheidea/micro-memoize.git"
|
||||
},
|
||||
"scripts": {
|
||||
"benchmark": "npm run dist && NODE_ENV=production node ./benchmarks/index.cjs",
|
||||
"build": "NODE_ENV=production rollup -c config/rollup.config.js --bundleConfigAsCjs",
|
||||
"build:mjs": "node scripts/es-to-mjs.js",
|
||||
"clean": "rimraf dist && rimraf mjs",
|
||||
"dev": "NODE_ENV=development webpack-dev-server --config=webpack/webpack.config.js",
|
||||
"dist": "npm run clean && npm run build && npm run build:mjs",
|
||||
"lint": "NODE_ENV=test eslint src/*.ts",
|
||||
"lint:fix": "npm run lint -- --fix",
|
||||
"prepublish": "if in-publish; then npm run prepublish:compile; fi",
|
||||
"prepublish:compile": "npm run typecheck && npm run lint && npm run test:coverage && npm run dist",
|
||||
"release": "release-it",
|
||||
"release:beta": "release-it --config=.release-it.beta.json",
|
||||
"start": "npm run dev",
|
||||
"test": "NODE_PATH=. jest --config=config/jest.config.js",
|
||||
"test:coverage": "npm run test -- --coverage",
|
||||
"test:watch": "npm run test -- --watch",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"types": "./index.d.ts",
|
||||
"version": "4.1.3"
|
||||
}
|
||||
Reference in New Issue
Block a user