pax_global_header00006660000000000000000000000064144652534760014532gustar00rootroot0000000000000052 comment=870a66deb10fb1a8ecd242ea960465fd3232bac9 node-lru-cache-10.0.1/000077500000000000000000000000001446525347600143775ustar00rootroot00000000000000node-lru-cache-10.0.1/.github/000077500000000000000000000000001446525347600157375ustar00rootroot00000000000000node-lru-cache-10.0.1/.github/workflows/000077500000000000000000000000001446525347600177745ustar00rootroot00000000000000node-lru-cache-10.0.1/.github/workflows/benchmark.yml000066400000000000000000000015331446525347600224530ustar00rootroot00000000000000name: Benchmarks on: [push, pull_request] jobs: build: strategy: matrix: node-version: [16.x, 18.x, 19.x] platform: - os: ubuntu-latest shell: bash - os: macos-latest shell: bash - os: windows-latest shell: bash fail-fast: false runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - name: Checkout Repository uses: actions/checkout@v3 - name: Use Nodejs ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - name: Use latest npm run: npm i -g npm@latest - name: Install dependencies run: npm install - name: Run Benchmarks run: npm run benchmark node-lru-cache-10.0.1/.github/workflows/ci.yml000066400000000000000000000036041446525347600211150ustar00rootroot00000000000000name: CI on: [push, pull_request] jobs: build: strategy: matrix: node-version: [16.x, 18.x, 20.x] platform: - os: ubuntu-latest shell: bash - os: macos-latest shell: bash - os: windows-latest shell: bash - os: windows-latest shell: powershell fail-fast: false runs-on: ${{ matrix.platform.os }} defaults: run: shell: ${{ matrix.platform.shell }} steps: - name: Checkout Repository if: ${{ (matrix.node-version == '16.x') || (matrix.node-version == '18.x') || (matrix.node-version == '19.x') || (matrix.platform.os != 'windows-latest') }} uses: actions/checkout@v3 - name: Use Nodejs ${{ matrix.node-version }} if: ${{ (matrix.node-version == '16.x') || (matrix.node-version == '18.x') || (matrix.node-version == '19.x') || (matrix.platform.os != 'windows-latest') }} uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - name: debugging run: echo NODEVERSION=[${{ matrix.node-version }}] OS=[${{ matrix.platform.os }}] # skip tests on node <16 on Windows, because npm install npm -g fails - name: Use latest npm if: ${{ (matrix.node-version == '16.x') || (matrix.node-version == '18.x') || (matrix.node-version == '19.x') || (matrix.platform.os != 'windows-latest') }} run: npm i -g npm@latest - name: Install dependencies if: ${{ (matrix.node-version == '16.x') || (matrix.node-version == '18.x') || (matrix.node-version == '19.x') || (matrix.platform.os != 'windows-latest') }} run: npm install - name: Run Tests if: ${{ (matrix.node-version == '16.x') || (matrix.node-version == '18.x') || (matrix.node-version == '19.x') || (matrix.platform.os != 'windows-latest') }} run: npm test -- -c -t0 node-lru-cache-10.0.1/.github/workflows/commit-if-modified.sh000066400000000000000000000004321446525347600237710ustar00rootroot00000000000000#!/usr/bin/env bash git config --global user.email "$1" shift git config --global user.name "$1" shift message="$1" shift if [ $(git status --porcelain "$@" | egrep '^ M' | wc -l) -gt 0 ]; then git add "$@" git commit -m "$message" git push || git pull --rebase git push fi node-lru-cache-10.0.1/.github/workflows/copyright-year.sh000066400000000000000000000010011446525347600232660ustar00rootroot00000000000000#!/usr/bin/env bash dir=${1:-$PWD} dates=($(git log --date=format:%Y --pretty=format:'%ad' --reverse | sort | uniq)) if [ "${#dates[@]}" -eq 1 ]; then datestr="${dates}" else datestr="${dates}-${dates[${#dates[@]}-1]}" fi stripDate='s/^((.*)Copyright\b(.*?))((?:,\s*)?(([0-9]{4}\s*-\s*[0-9]{4})|(([0-9]{4},\s*)*[0-9]{4})))(?:,)?\s*(.*)\n$/$1$9\n/g' addDate='s/^.*Copyright(?:\s*\(c\))? /Copyright \(c\) '$datestr' /g' for l in $dir/LICENSE*; do perl -pi -e "$stripDate" $l perl -pi -e "$addDate" $l done node-lru-cache-10.0.1/.github/workflows/isaacs-makework.yml000066400000000000000000000021461446525347600236030ustar00rootroot00000000000000name: "various tidying up tasks to silence nagging" on: push: branches: - main workflow_dispatch: jobs: makework: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - name: Use Node.js uses: actions/setup-node@v2.1.4 with: node-version: 16.x - name: put repo in package.json run: node .github/workflows/package-json-repo.js - name: check in package.json if modified run: | bash -x .github/workflows/commit-if-modified.sh \ "package-json-repo-bot@example.com" \ "package.json Repo Bot" \ "chore: add repo to package.json" \ package.json package-lock.json - name: put all dates in license copyright line run: bash .github/workflows/copyright-year.sh - name: check in licenses if modified run: | bash .github/workflows/commit-if-modified.sh \ "license-year-bot@example.com" \ "License Year Bot" \ "chore: add copyright year to license" \ LICENSE* node-lru-cache-10.0.1/.github/workflows/package-json-repo.js000066400000000000000000000010561446525347600236410ustar00rootroot00000000000000#!/usr/bin/env node const pf = require.resolve(`${process.cwd()}/package.json`) const pj = require(pf) if (!pj.repository && process.env.GITHUB_REPOSITORY) { const fs = require('fs') const server = process.env.GITHUB_SERVER_URL || 'https://github.com' const repo = `${server}/${process.env.GITHUB_REPOSITORY}` pj.repository = repo const json = fs.readFileSync(pf, 'utf8') const match = json.match(/^\s*\{[\r\n]+([ \t]*)"/) const indent = match[1] const output = JSON.stringify(pj, null, indent || 2) + '\n' fs.writeFileSync(pf, output) } node-lru-cache-10.0.1/.github/workflows/size-limit.yml000066400000000000000000000006431446525347600226100ustar00rootroot00000000000000name: "size" on: pull_request: branches: - main jobs: size: runs-on: ubuntu-latest env: CI_JOB_NUMBER: 1 steps: - uses: actions/checkout@v1 - name: Use Nodejs ${{ matrix.node-version }} uses: actions/setup-node@v1 with: node-version: 16.x - uses: andresz1/size-limit-action@v1 with: github_token: ${{ secrets.GITHUB_TOKEN }} node-lru-cache-10.0.1/.github/workflows/typedoc.yml000066400000000000000000000026411446525347600221710ustar00rootroot00000000000000# Simple workflow for deploying static content to GitHub Pages name: Deploy static content to Pages on: # Runs on pushes targeting the default branch push: branches: ["main"] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write # Allow one concurrent deployment concurrency: group: "pages" cancel-in-progress: true jobs: # Single deploy job since we're just deploying deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Use Nodejs ${{ matrix.node-version }} uses: actions/setup-node@v3 with: node-version: 18.x - name: Install dependencies run: npm install - name: Generate typedocs run: npm run typedoc - name: Generate Benchmarks run: npm run benchmark - name: Copy Benchmarks to Docs run: npm run benchmark-results-typedoc - name: Setup Pages uses: actions/configure-pages@v3 - name: Upload artifact uses: actions/upload-pages-artifact@v1 with: path: './docs' - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v1 node-lru-cache-10.0.1/.gitignore000066400000000000000000000001121446525347600163610ustar00rootroot00000000000000/node_modules /.nyc_output /nyc_output /coverage /bundle /index.mjs /dist node-lru-cache-10.0.1/.prettierignore000066400000000000000000000001531446525347600174410ustar00rootroot00000000000000/node_modules /tap-snapshots /coverage /.nyc_output /benchmark /.github /scripts /CHANGELOG.md /docs /dist node-lru-cache-10.0.1/CHANGELOG.md000066400000000000000000000130511446525347600162100ustar00rootroot00000000000000# cringe lorg ## 10.0.0 - `cache.fetch()` return type is now `Promise` instead of `Promise`. This is an irrelevant change practically speaking, but can require changes for TypeScript users. ## 9.1.0 - `cache.set(key, undefined)` is now an alias for `cache.delete(key)` ## 9.0.0 - Use named export only, no default export. - Bring back minimal polyfill. If this polyfill ends up being used, then a warning is printed, as it is not safe for use outside of LRUCache. ## 8.0.0 - The `fetchContext` option was renamed to `context`, and may no longer be set on the cache instance itself. - Rewritten in TypeScript, so pretty much all the types moved around a lot. - The AbortController/AbortSignal polyfill is removed. For this reason, **Node version 16.14.0 or higher is now required**. - Internal properties were moved to actual private class properties. - Keys and values must not be `null` or `undefined`. - Minified export available at `'lru-cache/min'`, for both CJS and MJS builds. ## 7.18.0 - Add support for internal state investigation through the use of a `status` option to `has()`, `set()`, `get()`, and `fetch()`. ## 7.17.0 - Add `signal` option for `fetch` to pass a user-supplied AbortSignal - Add `ignoreFetchAbort` and `allowStaleOnFetchAbort` options ## 7.16.2 - Fail fetch() promises when they are aborted ## 7.16.0 - Add `allowStaleOnFetchRejection` option ## 7.15.0 - Provide both ESM and CommonJS exports ## 7.14.0 - Add `maxEntrySize` option to prevent caching items above a given calculated size. ## 7.13.0 - Add `forceRefresh` option to trigger a call to the `fetchMethod` even if the item is found in cache, and not older than its `ttl`. ## 7.12.0 - Add `fetchContext` option to provide additional information to the `fetchMethod` - 7.12.1: Fix bug where adding an item with size greater than `maxSize` would cause bizarre behavior. ## 7.11.0 - Add 'noDeleteOnStaleGet' option, to suppress behavior where a `get()` of a stale item would remove it from the cache. ## 7.10.0 - Add `noDeleteOnFetchRejection` option, to suppress behavior where a failed `fetch` will delete a previous stale value. - Ship types along with the package, rather than relying on out of date types coming from DefinitelyTyped. ## 7.9.0 - Better AbortController polyfill, supporting `signal.addEventListener('abort')` and `signal.onabort`. - (7.9.1) Drop item from cache instead of crashing with an `unhandledRejection` when the `fetchMethod` throws an error or returns a rejected Promise. ## 7.8.0 - add `updateAgeOnHas` option - warnings sent to `console.error` if `process.emitWarning` unavailable ## 7.7.0 - fetch: provide options and abort signal ## 7.6.0 - add cache.getRemainingTTL(key) - Add async cache.fetch() method, fetchMethod option - Allow unbounded storage if maxSize or ttl set ## 7.5.0 - defend against mutation while iterating - Add rentries, rkeys, rvalues - remove bundler and unnecessary package.json fields ## 7.4.0 - Add browser optimized webpack bundle, exposed as `'lru-cache/browser'` - Track size of compiled bundle in CI ([@SuperOleg39](https://github.com/SuperOleg39)) - Add `noUpdateTTL` option for `set()` ## 7.3.0 - Add `disposeAfter()` - `set()` returns the cache object - `delete()` returns boolean indicating whether anything was deleted ## 7.2.0 - Add reason to dispose() calls. ## 7.1.0 - Add `ttlResolution` option - Add `ttlAutopurge` option ## v7 - 2022-02 This library changed to a different algorithm and internal data structure in version 7, yielding significantly better performance, albeit with some subtle changes as a result. If you were relying on the internals of LRUCache in version 6 or before, it probably will not work in version 7 and above. ### Specific API Changes For the most part, the feature set has been maintained as much as possible. However, some other cleanup and refactoring changes were made in v7 as well. - The `set()`, `get()`, and `has()` functions take options objects instead of positional booleans/integers for optional parameters. - `size` can be set explicitly on `set()`. - `cache.length` was renamed to the more fitting `cache.size`. - Deprecations: - `stale` option -> `allowStale` - `maxAge` option -> `ttl` - `length` option -> `sizeCalculation` - `length` property -> `size` - `del()` method -> `delete()` - `prune()` method -> `purgeStale()` - `reset()` method -> `clear()` - The objects used by `cache.load()` and `cache.dump()` are incompatible with previous versions. - `max` and `maxSize` are now two separate options. (Previously, they were a single `max` option, which would be based on either count or computed size.) - The function assigned to the `dispose` option is now expected to have signature `(value, key, reason)` rather than `(key, value)`, reversing the order of `value` and `key`. ## v6 - 2020-07 - Drop support for node v8 and earlier ## v5 - 2018-11 - Add updateAgeOnGet option - Guards around setting max/maxAge to non-numbers - Use classes, drop support for old nodes ## v4 - 2015-12 - Improve performance - add noDisposeOnSet option - feat(prune): allow users to proactively prune old entries - Use Symbols for private members - Add maxAge setter/getter ## v3 - 2015-11 - Add cache.rforEach - Allow non-string keys ## v2 - 2012-08 - add cache.pop() - add cache.peek() - add cache.keys() - add cache.values() - fix memory leak - add `stale` option to return stale values before deleting - use null-prototype object to avoid hazards - make options argument an object ## v1 - 2010-05 - initial implementation node-lru-cache-10.0.1/CONTRIBUTING.md000066400000000000000000000001161446525347600166260ustar00rootroot00000000000000Please consider signing [the neveragain.tech pledge](http://neveragain.tech/) node-lru-cache-10.0.1/CONTRIBUTORS000066400000000000000000000010141446525347600162530ustar00rootroot00000000000000# Authors, sorted by whether or not they are me Isaac Z. Schlueter Brian Cottingham Carlos Brito Lage Jesse Dailey Kevin O'Hara Marco Rogers Mark Cavage Marko Mikulicic Nathan Rajlich Satheesh Natesan Trent Mick ashleybrener n4kz node-lru-cache-10.0.1/LICENSE000066400000000000000000000014071446525347600154060ustar00rootroot00000000000000The ISC License Copyright (c) 2010-2023 Isaac Z. Schlueter and Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. node-lru-cache-10.0.1/README.md000066400000000000000000001136431446525347600156660ustar00rootroot00000000000000# lru-cache A cache object that deletes the least-recently-used items. Specify a max number of the most recently used items that you want to keep, and this cache will keep that many of the most recently accessed items. This is not primarily a TTL cache, and does not make strong TTL guarantees. There is no preemptive pruning of expired items by default, but you _may_ set a TTL on the cache or on a single `set`. If you do so, it will treat expired items as missing, and delete them when fetched. If you are more interested in TTL caching than LRU caching, check out [@isaacs/ttlcache](http://npm.im/@isaacs/ttlcache). As of version 7, this is one of the most performant LRU implementations available in JavaScript, and supports a wide diversity of use cases. However, note that using some of the features will necessarily impact performance, by causing the cache to have to do more work. See the "Performance" section below. ## Installation ```bash npm install lru-cache --save ``` ## Usage ```js // hybrid module, either works import { LRUCache } from 'lru-cache' // or: const { LRUCache } = require('lru-cache') // or in minified form for web browsers: import { LRUCache } from 'http://unpkg.com/lru-cache@9/dist/mjs/index.min.mjs' // At least one of 'max', 'ttl', or 'maxSize' is required, to prevent // unsafe unbounded storage. // // In most cases, it's best to specify a max for performance, so all // the required memory allocation is done up-front. // // All the other options are optional, see the sections below for // documentation on what each one does. Most of them can be // overridden for specific items in get()/set() const options = { max: 500, // for use with tracking overall storage size maxSize: 5000, sizeCalculation: (value, key) => { return 1 }, // for use when you need to clean up something when objects // are evicted from the cache dispose: (value, key) => { freeFromMemoryOrWhatever(value) }, // how long to live in ms ttl: 1000 * 60 * 5, // return stale items before removing from cache? allowStale: false, updateAgeOnGet: false, updateAgeOnHas: false, // async method to use for cache.fetch(), for // stale-while-revalidate type of behavior fetchMethod: async ( key, staleValue, { options, signal, context } ) => {}, } const cache = new LRUCache(options) cache.set('key', 'value') cache.get('key') // "value" // non-string keys ARE fully supported // but note that it must be THE SAME object, not // just a JSON-equivalent object. var someObject = { a: 1 } cache.set(someObject, 'a value') // Object keys are not toString()-ed cache.set('[object Object]', 'a different value') assert.equal(cache.get(someObject), 'a value') // A similar object with same keys/values won't work, // because it's a different object identity assert.equal(cache.get({ a: 1 }), undefined) cache.clear() // empty the cache ``` If you put more stuff in the cache, then less recently used items will fall out. That's what an LRU cache is. ## `class LRUCache(options)` Create a new `LRUCache` object. When using TypeScript, set the `K` and `V` types to the `key` and `value` types, respectively. The `FC` ("fetch context") generic type defaults to `unknown`. If set to a value other than `void` or `undefined`, then any calls to `cache.fetch()` _must_ provide a `context` option matching the `FC` type. If `FC` is set to `void` or `undefined`, then `cache.fetch()` _must not_ provide a `context` option. See the documentation on `async fetch()` below. ## Options All options are available on the LRUCache instance, making it safe to pass an LRUCache instance as the options argument to make another empty cache of the same type. Some options are marked read-only because changing them after instantiation is not safe. Changing any of the other options will of course only have an effect on subsequent method calls. ### `max` (read only) The maximum number of items that remain in the cache (assuming no TTL pruning or explicit deletions). Note that fewer items may be stored if size calculation is used, and `maxSize` is exceeded. This must be a positive finite intger. At least one of `max`, `maxSize`, or `TTL` is required. This must be a positive integer if set. **It is strongly recommended to set a `max` to prevent unbounded growth of the cache.** See "Storage Bounds Safety" below. ### `maxSize` (read only) Set to a positive integer to track the sizes of items added to the cache, and automatically evict items in order to stay below this size. Note that this may result in fewer than `max` items being stored. Attempting to add an item to the cache whose calculated size is greater that this amount will be a no-op. The item will not be cached, and no other items will be evicted. Optional, must be a positive integer if provided. Sets `maxEntrySize` to the same value, unless a different value is provided for `maxEntrySize`. At least one of `max`, `maxSize`, or `TTL` is required. This must be a positive integer if set. Even if size tracking is enabled, **it is strongly recommended to set a `max` to prevent unbounded growth of the cache.** See "Storage Bounds Safety" below. ### `maxEntrySize` Set to a positive integer to track the sizes of items added to the cache, and prevent caching any item over a given size. Attempting to add an item whose calculated size is greater than this amount will be a no-op. The item will not be cached, and no other items will be evicted. Optional, must be a positive integer if provided. Defaults to the value of `maxSize` if provided. ### `sizeCalculation` Function used to calculate the size of stored items. If you're storing strings or buffers, then you probably want to do something like `n => n.length`. The item is passed as the first argument, and the key is passed as the second argument. This may be overridden by passing an options object to `cache.set()`. Requires `maxSize` to be set. If the `size` (or return value of `sizeCalculation`) for a given entry is greater than `maxEntrySize`, then the item will not be added to the cache. ### `fetchMethod` (read only) Function that is used to make background asynchronous fetches. Called with `fetchMethod(key, staleValue, { signal, options, context })`. May return a Promise. If `fetchMethod` is not provided, then `cache.fetch(key)` is equivalent to `Promise.resolve(cache.get(key))`. If at any time, `signal.aborted` is set to `true`, or if the `signal.onabort` method is called, or if it emits an `'abort'` event which you can listen to with `addEventListener`, then that means that the fetch should be abandoned. This may be passed along to async functions aware of AbortController/AbortSignal behavior. The `fetchMethod` should **only** return `undefined` or a Promise resolving to `undefined` if the AbortController signaled an `abort` event. In all other cases, it should return or resolve to a value suitable for adding to the cache. The `options` object is a union of the options that may be provided to `set()` and `get()`. If they are modified, then that will result in modifying the settings to `cache.set()` when the value is resolved, and in the case of `noDeleteOnFetchRejection` and `allowStaleOnFetchRejection`, the handling of `fetchMethod` failures. For example, a DNS cache may update the TTL based on the value returned from a remote DNS server by changing `options.ttl` in the `fetchMethod`. ### `noDeleteOnFetchRejection` If a `fetchMethod` throws an error or returns a rejected promise, then by default, any existing stale value will be removed from the cache. If `noDeleteOnFetchRejection` is set to `true`, then this behavior is suppressed, and the stale value remains in the cache in the case of a rejected `fetchMethod`. This is important in cases where a `fetchMethod` is _only_ called as a background update while the stale value is returned, when `allowStale` is used. This is implicitly in effect when `allowStaleOnFetchRejection` is set. This may be set in calls to `fetch()`, or defaulted on the constructor, or overridden by modifying the options object in the `fetchMethod`. ### `allowStaleOnFetchRejection` Set to true to return a stale value from the cache when a `fetchMethod` throws an error or returns a rejected Promise. If a `fetchMethod` fails, and there is no stale value available, the `fetch()` will resolve to `undefined`. Ie, all `fetchMethod` errors are suppressed. Implies `noDeleteOnFetchRejection`. This may be set in calls to `fetch()`, or defaulted on the constructor, or overridden by modifying the options object in the `fetchMethod`. ### `allowStaleOnFetchAbort` Set to true to return a stale value from the cache when the `AbortSignal` passed to the `fetchMethod` dispatches an `'abort'` event, whether user-triggered, or due to internal cache behavior. Unless `ignoreFetchAbort` is also set, the underlying `fetchMethod` will still be considered canceled, and any value it returns will be ignored and not cached. Caveat: since fetches are aborted when a new value is explicitly set in the cache, this can lead to fetch returning a stale value, since that was the fallback value _at the moment the `fetch()` was initiated_, even though the new updated value is now present in the cache. For example: ```ts const cache = new LRUCache({ ttl: 100, fetchMethod: async (url, oldValue, { signal }) => { const res = await fetch(url, { signal }) return await res.json() } }) cache.set('https://example.com/', { some: 'data' }) // 100ms go by... const result = cache.fetch('https://example.com/') cache.set('https://example.com/', { other: 'thing' }) console.log(await result) // { some: 'data' } console.log(cache.get('https://example.com/')) // { other: 'thing' } ``` ### `ignoreFetchAbort` Set to true to ignore the `abort` event emitted by the `AbortSignal` object passed to `fetchMethod`, and still cache the resulting resolution value, as long as it is not `undefined`. When used on its own, this means aborted `fetch()` calls are not immediately resolved or rejected when they are aborted, and instead take the full time to await. When used with `allowStaleOnFetchAbort`, aborted `fetch()` calls will resolve immediately to their stale cached value or `undefined`, and will continue to process and eventually update the cache when they resolve, as long as the resulting value is not `undefined`, thus supporting a "return stale on timeout while refreshing" mechanism by passing `AbortSignal.timeout(n)` as the signal. For example: ```js const c = new LRUCache({ ttl: 100, ignoreFetchAbort: true, allowStaleOnFetchAbort: true, fetchMethod: async (key, oldValue, { signal }) => { // note: do NOT pass the signal to fetch()! // let's say this fetch can take a long time. const res = await fetch(`https://slow-backend-server/${key}`) return await res.json() }, }) // this will return the stale value after 100ms, while still // updating in the background for next time. const val = await c.fetch('key', { signal: AbortSignal.timeout(100) }) ``` **Note**: regardless of this setting, an `abort` event _is still emitted on the `AbortSignal` object_, so may result in invalid results when passed to other underlying APIs that use AbortSignals. This may be overridden on the `fetch()` call or in the `fetchMethod` itself. ### `dispose` (read only) Function that is called on items when they are dropped from the cache, as `this.dispose(value, key, reason)`. This can be handy if you want to close file descriptors or do other cleanup tasks when items are no longer stored in the cache. **NOTE**: It is called _before_ the item has been fully removed from the cache, so if you want to put it right back in, you need to wait until the next tick. If you try to add it back in during the `dispose()` function call, it will break things in subtle and weird ways. Unlike several other options, this may _not_ be overridden by passing an option to `set()`, for performance reasons. The `reason` will be one of the following strings, corresponding to the reason for the item's deletion: - `evict` Item was evicted to make space for a new addition - `set` Item was overwritten by a new value - `delete` Item was removed by explicit `cache.delete(key)` or by calling `cache.clear()`, which deletes everything. The `dispose()` method is _not_ called for canceled calls to `fetchMethod()`. If you wish to handle evictions, overwrites, and deletes of in-flight asynchronous fetches, you must use the `AbortSignal` provided. Optional, must be a function. ### `disposeAfter` (read only) The same as `dispose`, but called _after_ the entry is completely removed and the cache is once again in a clean state. It is safe to add an item right back into the cache at this point. However, note that it is _very_ easy to inadvertently create infinite recursion in this way. The `disposeAfter()` method is _not_ called for canceled calls to `fetchMethod()`. If you wish to handle evictions, overwrites, and deletes of in-flight asynchronous fetches, you must use the `AbortSignal` provided. ### `noDisposeOnSet` Set to `true` to suppress calling the `dispose()` function if the entry key is still accessible within the cache. This may be overridden by passing an options object to `cache.set()`. Boolean, default `false`. Only relevant if `dispose` or `disposeAfter` options are set. ### `ttl` Max time to live for items before they are considered stale. Note that stale items are NOT preemptively removed by default, and MAY live in the cache, contributing to its LRU max, long after they have expired. Also, as this cache is optimized for LRU/MRU operations, some of the staleness/TTL checks will reduce performance. This is not primarily a TTL cache, and does not make strong TTL guarantees. There is no pre-emptive pruning of expired items, but you _may_ set a TTL on the cache, and it will treat expired items as missing when they are fetched, and delete them. Optional, but must be a positive integer in ms if specified. This may be overridden by passing an options object to `cache.set()`. At least one of `max`, `maxSize`, or `TTL` is required. This must be a positive integer if set. Even if ttl tracking is enabled, **it is strongly recommended to set a `max` to prevent unbounded growth of the cache.** See "Storage Bounds Safety" below. If ttl tracking is enabled, and `max` and `maxSize` are not set, and `ttlAutopurge` is not set, then a warning will be emitted cautioning about the potential for unbounded memory consumption. (The TypeScript definitions will also discourage this.) ### `noUpdateTTL` Boolean flag to tell the cache to not update the TTL when setting a new value for an existing key (ie, when updating a value rather than inserting a new value). Note that the TTL value is _always_ set (if provided) when adding a new entry into the cache. This may be passed as an option to `cache.set()`. Boolean, default false. ### `ttlResolution` Minimum amount of time in ms in which to check for staleness. Defaults to `1`, which means that the current time is checked at most once per millisecond. Set to `0` to check the current time every time staleness is tested. Note that setting this to a higher value _will_ improve performance somewhat while using ttl tracking, albeit at the expense of keeping stale items around a bit longer than intended. ### `ttlAutopurge` Preemptively remove stale items from the cache. Note that this may _significantly_ degrade performance, especially if the cache is storing a large number of items. It is almost always best to just leave the stale items in the cache, and let them fall out as new items are added. Note that this means that `allowStale` is a bit pointless, as stale items will be deleted almost as soon as they expire. Use with caution! Boolean, default `false` ### `allowStale` By default, if you set `ttl`, it'll only delete stale items from the cache when you `get(key)`. That is, it's not preemptively pruning items. If you set `allowStale:true`, it'll return the stale value as well as deleting it. If you don't set this, then it'll return `undefined` when you try to get a stale entry. Note that when a stale entry is fetched, _even if it is returned due to `allowStale` being set_, it is removed from the cache immediately. You can immediately put it back in the cache if you wish, thus resetting the TTL. This may be overridden by passing an options object to `cache.get()`. The `cache.has()` method will always return `false` for stale items. Boolean, default false, only relevant if `ttl` is set. ### `noDeleteOnStaleGet` When using time-expiring entries with `ttl`, by default stale items will be removed from the cache when the key is accessed with `cache.get()`. Setting `noDeleteOnStaleGet` to `true` will cause stale items to remain in the cache, until they are explicitly deleted with `cache.delete(key)`, or retrieved with `noDeleteOnStaleGet` set to `false`. This may be overridden by passing an options object to `cache.get()`. Boolean, default false, only relevant if `ttl` is set. ### `updateAgeOnGet` When using time-expiring entries with `ttl`, setting this to `true` will make each item's age reset to 0 whenever it is retrieved from cache with `get()`, causing it to not expire. (It can still fall out of cache based on recency of use, of course.) This may be overridden by passing an options object to `cache.get()`. Boolean, default false, only relevant if `ttl` is set. ### `updateAgeOnHas` When using time-expiring entries with `ttl`, setting this to `true` will make each item's age reset to 0 whenever its presence in the cache is checked with `has()`, causing it to not expire. (It can still fall out of cache based on recency of use, of course.) This may be overridden by passing an options object to `cache.has()`. Boolean, default false, only relevant if `ttl` is set. ## API ### `new LRUCache(options)` Create a new LRUCache. All options are documented above, and are on the cache as public members. The `K` and `V` types define the key and value types, respectively. The optional `FC` type defines the type of the `context` object passed to `cache.fetch()`. Keys and values **must not** be `null` or `undefined`. ### `cache.max`, `cache.maxSize`, `cache.allowStale`, `cache.noDisposeOnSet`, `cache.sizeCalculation`, `cache.dispose`, `cache.maxSize`, `cache.ttl`, `cache.updateAgeOnGet`, `cache.updateAgeOnHas` All option names are exposed as public members on the cache object. These are intended for read access only. Changing them during program operation can cause undefined behavior. ### `cache.size` The total number of items held in the cache at the current moment. ### `cache.calculatedSize` The total size of items in cache when using size tracking. ### `set(key, value, [{ size, sizeCalculation, ttl, noDisposeOnSet, start, status }])` Add a value to the cache. Optional options object may contain `ttl` and `sizeCalculation` as described above, which default to the settings on the cache object. If `start` is provided, then that will set the effective start time for the TTL calculation. Note that this must be a previous value of `performance.now()` if supported, or a previous value of `Date.now()` if not. Options object may also include `size`, which will prevent calling the `sizeCalculation` function and just use the specified number if it is a positive integer, and `noDisposeOnSet` which will prevent calling a `dispose` function in the case of overwrites. If the `size` (or return value of `sizeCalculation`) for a given entry is greater than `maxEntrySize`, then the item will not be added to the cache. Will update the recency of the entry. Returns the cache object. For the usage of the `status` option, see **Status Tracking** below. If the value is `undefined`, then this is an alias for `cache.delete(key)`. `undefined` is never stored in the cache. See **Storing Undefined Values** below. ### `get(key, { updateAgeOnGet, allowStale, status } = {}) => value` Return a value from the cache. Will update the recency of the cache entry found. If the key is not found, `get()` will return `undefined`. For the usage of the `status` option, see **Status Tracking** below. ### `async fetch(key, options = {}) => Promise` The following options are supported: - `updateAgeOnGet` - `allowStale` - `size` - `sizeCalculation` - `ttl` - `noDisposeOnSet` - `forceRefresh` - `status` - See **Status Tracking** below. - `signal` - AbortSignal can be used to cancel the `fetch()`. Note that the `signal` option provided to the `fetchMethod` is a different object, because it must also respond to internal cache state changes, but aborting this signal will abort the one passed to `fetchMethod` as well. - `context` - sets the `context` option passed to the underlying `fetchMethod`. If the value is in the cache and not stale, then the returned Promise resolves to the value. If not in the cache, or beyond its TTL staleness, then `fetchMethod(key, staleValue, { options, signal, context })` is called, and the value returned will be added to the cache once resolved. If called with `allowStale`, and an asynchronous fetch is currently in progress to reload a stale value, then the former stale value will be returned. If called with `forceRefresh`, then the cached item will be re-fetched, even if it is not stale. However, if `allowStale` is set, then the old value will still be returned. This is useful in cases where you want to force a reload of a cached value. If a background fetch is already in progress, then `forceRefresh` has no effect. Multiple fetches for the same `key` will only call `fetchMethod` a single time, and all will be resolved when the value is resolved, even if different options are used. If `fetchMethod` is not specified, then this is effectively an alias for `Promise.resolve(cache.get(key))`. When the fetch method resolves to a value, if the fetch has not been aborted due to deletion, eviction, or being overwritten, then it is added to the cache using the options provided. If the key is evicted or deleted before the `fetchMethod` resolves, then the AbortSignal passed to the `fetchMethod` will receive an `abort` event, and the promise returned by `fetch()` will reject with the reason for the abort. If a `signal` is passed to the `fetch()` call, then aborting the signal will abort the fetch and cause the `fetch()` promise to reject with the reason provided. #### Setting `context` If an `FC` type is set to a type other than `unknown`, `void`, or `undefined` in the LRUCache constructor, then all calls to `cache.fetch()` _must_ provide a `context` option. If set to `undefined` or `void`, then calls to fetch _must not_ provide a `context` option. The `context` param allows you to provide arbitrary data that might be relevant in the course of fetching the data. It is only relevant for the course of a single `fetch()` operation, and discarded afterwards. #### Note: `fetch()` calls are inflight-unique If you call `fetch()` multiple times with the same key value, then every call after the first will resolve on the same promise1, _even if they have different settings that would otherwise change the behvavior of the fetch_, such as `noDeleteOnFetchRejection` or `ignoreFetchAbort`. In most cases, this is not a problem (in fact, only fetching something once is what you probably want, if you're caching in the first place). If you are changing the fetch() options dramatically between runs, there's a good chance that you might be trying to fit divergent semantics into a single object, and would be better off with multiple cache instances. **1**: Ie, they're not the "same Promise", but they resolve at the same time, because they're both waiting on the same underlying fetchMethod response. ### `peek(key, { allowStale } = {}) => value` Like `get()` but doesn't update recency or delete stale items. Returns `undefined` if the item is stale, unless `allowStale` is set either on the cache or in the options object. ### `has(key, { updateAgeOnHas, status } = {}) => Boolean` Check if a key is in the cache, without updating the recency of use. Age is updated if `updateAgeOnHas` is set to `true` in either the options or the constructor. Will return `false` if the item is stale, even though it is technically in the cache. The difference can be determined (if it matters) by using a `status` argument, and inspecting the `has` field. For the usage of the `status` option, see **Status Tracking** below. ### `delete(key)` Deletes a key out of the cache. Returns `true` if the key was deleted, `false` otherwise. ### `clear()` Clear the cache entirely, throwing away all values. ### `keys()` Return a generator yielding the keys in the cache, in order from most recently used to least recently used. ### `rkeys()` Return a generator yielding the keys in the cache, in order from least recently used to most recently used. ### `values()` Return a generator yielding the values in the cache, in order from most recently used to least recently used. ### `rvalues()` Return a generator yielding the values in the cache, in order from least recently used to most recently used. ### `entries()` Return a generator yielding `[key, value]` pairs, in order from most recently used to least recently used. ### `rentries()` Return a generator yielding `[key, value]` pairs, in order from least recently used to most recently used. ### `find(fn, [getOptions])` Find a value for which the supplied `fn` method returns a truthy value, similar to `Array.find()`. `fn` is called as `fn(value, key, cache)`. The optional `getOptions` are applied to the resulting `get()` of the item found. ### `dump()` Return an array of `[key, entry]` objects which can be passed to `cache.load()` The `start` fields are calculated relative to a portable `Date.now()` timestamp, even if `performance.now()` is available. Stale entries are always included in the `dump`, even if `allowStale` is false. Note: this returns an actual array, not a generator, so it can be more easily passed around. ### `load(entries)` Reset the cache and load in the items in `entries` in the order listed. Note that the shape of the resulting cache may be different if the same options are not used in both caches. The `start` fields are assumed to be calculated relative to a portable `Date.now()` timestamp, even if `performance.now()` is available. ### `purgeStale()` Delete any stale entries. Returns `true` if anything was removed, `false` otherwise. ### `getRemainingTTL(key)` Return the number of ms left in the item's TTL. If item is not in cache, returns `0`. Returns `Infinity` if item is in cache without a defined TTL. ### `forEach(fn, [thisp])` Call the `fn` function with each set of `fn(value, key, cache)` in the LRU cache, from most recent to least recently used. Does not affect recency of use. If `thisp` is provided, function will be called in the `this`-context of the provided object. ### `rforEach(fn, [thisp])` Same as `cache.forEach(fn, thisp)`, but in order from least recently used to most recently used. ### `pop()` Evict the least recently used item, returning its value. Returns `undefined` if cache is empty. ## Status Tracking Occasionally, it may be useful to track the internal behavior of the cache, particularly for logging, debugging, or for behavior within the `fetchMethod`. To do this, you can pass a `status` object to the `get()`, `set()`, `has()`, and `fetch()` methods. The `status` option should be a plain JavaScript object. The following fields will be set appropriately: ```ts interface Status { /** * The status of a set() operation. * * - add: the item was not found in the cache, and was added * - update: the item was in the cache, with the same value provided * - replace: the item was in the cache, and replaced * - miss: the item was not added to the cache for some reason */ set?: 'add' | 'update' | 'replace' | 'miss' /** * the ttl stored for the item, or undefined if ttls are not used. */ ttl?: LRUMilliseconds /** * the start time for the item, or undefined if ttls are not used. */ start?: LRUMilliseconds /** * The timestamp used for TTL calculation */ now?: LRUMilliseconds /** * the remaining ttl for the item, or undefined if ttls are not used. */ remainingTTL?: LRUMilliseconds /** * The calculated size for the item, if sizes are used. */ size?: LRUSize /** * A flag indicating that the item was not stored, due to exceeding the * {@link maxEntrySize} */ maxEntrySizeExceeded?: true /** * The old value, specified in the case of `set:'update'` or * `set:'replace'` */ oldValue?: V /** * The results of a {@link has} operation * * - hit: the item was found in the cache * - stale: the item was found in the cache, but is stale * - miss: the item was not found in the cache */ has?: 'hit' | 'stale' | 'miss' /** * The status of a {@link fetch} operation. * Note that this can change as the underlying fetch() moves through * various states. * * - inflight: there is another fetch() for this key which is in process * - get: there is no fetchMethod, so {@link get} was called. * - miss: the item is not in cache, and will be fetched. * - hit: the item is in the cache, and was resolved immediately. * - stale: the item is in the cache, but stale. * - refresh: the item is in the cache, and not stale, but * {@link forceRefresh} was specified. */ fetch?: 'get' | 'inflight' | 'miss' | 'hit' | 'stale' | 'refresh' /** * The {@link fetchMethod} was called */ fetchDispatched?: true /** * The cached value was updated after a successful call to fetchMethod */ fetchUpdated?: true /** * The reason for a fetch() rejection. Either the error raised by the * {@link fetchMethod}, or the reason for an AbortSignal. */ fetchError?: Error /** * The fetch received an abort signal */ fetchAborted?: true /** * The abort signal received was ignored, and the fetch was allowed to * continue. */ fetchAbortIgnored?: true /** * The fetchMethod promise resolved successfully */ fetchResolved?: true /** * The results of the fetchMethod promise were stored in the cache */ fetchUpdated?: true /** * The fetchMethod promise was rejected */ fetchRejected?: true /** * The status of a {@link get} operation. * * - fetching: The item is currently being fetched. If a previous value is * present and allowed, that will be returned. * - stale: The item is in the cache, and is stale. * - hit: the item is in the cache * - miss: the item is not in the cache */ get?: 'stale' | 'hit' | 'miss' /** * A fetch or get operation returned a stale value. */ returnedStale?: true } ``` ## Storage Bounds Safety This implementation aims to be as flexible as possible, within the limits of safe memory consumption and optimal performance. At initial object creation, storage is allocated for `max` items. If `max` is set to zero, then some performance is lost, and item count is unbounded. Either `maxSize` or `ttl` _must_ be set if `max` is not specified. If `maxSize` is set, then this creates a safe limit on the maximum storage consumed, but without the performance benefits of pre-allocation. When `maxSize` is set, every item _must_ provide a size, either via the `sizeCalculation` method provided to the constructor, or via a `size` or `sizeCalculation` option provided to `cache.set()`. The size of every item _must_ be a positive integer. If neither `max` nor `maxSize` are set, then `ttl` tracking must be enabled. Note that, even when tracking item `ttl`, items are _not_ preemptively deleted when they become stale, unless `ttlAutopurge` is enabled. Instead, they are only purged the next time the key is requested. Thus, if `ttlAutopurge`, `max`, and `maxSize` are all not set, then the cache will potentially grow unbounded. In this case, a warning is printed to standard error. Future versions may require the use of `ttlAutopurge` if `max` and `maxSize` are not specified. If you truly wish to use a cache that is bound _only_ by TTL expiration, consider using a `Map` object, and calling `setTimeout` to delete entries when they expire. It will perform much better than an LRU cache. Here is an implementation you may use, under the same [license](./LICENSE) as this package: ```js // a storage-unbounded ttl cache that is not an lru-cache const cache = { data: new Map(), timers: new Map(), set: (k, v, ttl) => { if (cache.timers.has(k)) { clearTimeout(cache.timers.get(k)) } cache.timers.set( k, setTimeout(() => cache.delete(k), ttl) ) cache.data.set(k, v) }, get: k => cache.data.get(k), has: k => cache.data.has(k), delete: k => { if (cache.timers.has(k)) { clearTimeout(cache.timers.get(k)) } cache.timers.delete(k) return cache.data.delete(k) }, clear: () => { cache.data.clear() for (const v of cache.timers.values()) { clearTimeout(v) } cache.timers.clear() }, } ``` If that isn't to your liking, check out [@isaacs/ttlcache](http://npm.im/@isaacs/ttlcache). ## Storing Undefined Values This cache never stores undefined values, as `undefined` is used internally in a few places to indicate that a key is not in the cache. You may call `cache.set(key, undefined)`, but this is just an an alias for `cache.delete(key)`. Note that this has the effect that `cache.has(key)` will return _false_ after setting it to undefined. ```js cache.set(myKey, undefined) cache.has(myKey) // false! ``` If you need to track `undefined` values, and still note that the key is in the cache, an easy workaround is to use a sigil object of your own. ```js import { LRUCache } from 'lru-cache' const undefinedValue = Symbol('undefined') const cache = new LRUCache(...) const mySet = (key, value) => cache.set(key, value === undefined ? undefinedValue : value) const myGet = (key, value) => { const v = cache.get(key) return v === undefinedValue ? undefined : v } ``` ## Performance As of January 2022, version 7 of this library is one of the most performant LRU cache implementations in JavaScript. Benchmarks can be extremely difficult to get right. In particular, the performance of set/get/delete operations on objects will vary _wildly_ depending on the type of key used. V8 is highly optimized for objects with keys that are short strings, especially integer numeric strings. Thus any benchmark which tests _solely_ using numbers as keys will tend to find that an object-based approach performs the best. Note that coercing _anything_ to strings to use as object keys is unsafe, unless you can be 100% certain that no other type of value will be used. For example: ```js const myCache = {} const set = (k, v) => (myCache[k] = v) const get = k => myCache[k] set({}, 'please hang onto this for me') set('[object Object]', 'oopsie') ``` Also beware of "Just So" stories regarding performance. Garbage collection of large (especially: deep) object graphs can be incredibly costly, with several "tipping points" where it increases exponentially. As a result, putting that off until later can make it much worse, and less predictable. If a library performs well, but only in a scenario where the object graph is kept shallow, then that won't help you if you are using large objects as keys. In general, when attempting to use a library to improve performance (such as a cache like this one), it's best to choose an option that will perform well in the sorts of scenarios where you'll actually use it. This library is optimized for repeated gets and minimizing eviction time, since that is the expected need of a LRU. Set operations are somewhat slower on average than a few other options, in part because of that optimization. It is assumed that you'll be caching some costly operation, ideally as rarely as possible, so optimizing set over get would be unwise. If performance matters to you: 1. If it's at all possible to use small integer values as keys, and you can guarantee that no other types of values will be used as keys, then do that, and use a cache such as [lru-fast](https://npmjs.com/package/lru-fast), or [mnemonist's LRUCache](https://yomguithereal.github.io/mnemonist/lru-cache) which uses an Object as its data store. 2. Failing that, if at all possible, use short non-numeric strings (ie, less than 256 characters) as your keys, and use [mnemonist's LRUCache](https://yomguithereal.github.io/mnemonist/lru-cache). 3. If the types of your keys will be anything else, especially long strings, strings that look like floats, objects, or some mix of types, or if you aren't sure, then this library will work well for you. If you do not need the features that this library provides (like asynchronous fetching, a variety of TTL staleness options, and so on), then [mnemonist's LRUMap](https://yomguithereal.github.io/mnemonist/lru-map) is a very good option, and just slightly faster than this module (since it does considerably less). 4. Do not use a `dispose` function, size tracking, or especially ttl behavior, unless absolutely needed. These features are convenient, and necessary in some use cases, and every attempt has been made to make the performance impact minimal, but it isn't nothing. ## Breaking Changes in Version 7 This library changed to a different algorithm and internal data structure in version 7, yielding significantly better performance, albeit with some subtle changes as a result. If you were relying on the internals of LRUCache in version 6 or before, it probably will not work in version 7 and above. ## Breaking Changes in Version 8 - The `fetchContext` option was renamed to `context`, and may no longer be set on the cache instance itself. - Rewritten in TypeScript, so pretty much all the types moved around a lot. - The AbortController/AbortSignal polyfill was removed. For this reason, **Node version 16.14.0 or higher is now required**. - Internal properties were moved to actual private class properties. - Keys and values must not be `null` or `undefined`. - Minified export available at `'lru-cache/min'`, for both CJS and MJS builds. ## Changes in Version 9 - Named export only, no default export. - AbortController polyfill returned, albeit with a warning when used. For more info, see the [change log](CHANGELOG.md). node-lru-cache-10.0.1/benchmark/000077500000000000000000000000001446525347600163315ustar00rootroot00000000000000node-lru-cache-10.0.1/benchmark/.gitignore000066400000000000000000000001761446525347600203250ustar00rootroot00000000000000.DS_Store /node_modules /package.json /package-lock.json /impls.txt /results /results.md /profiles /profile.txt /isolate*.log node-lru-cache-10.0.1/benchmark/CHANGELOG.md000066400000000000000000000053251446525347600201470ustar00rootroot00000000000000 # 1.1.0 (2017-10-02) * 1.0.0 ([4b43691](https://github.com/dominictarr/bench-lru/commit/4b43691)) * Add bench specification ([c55b726](https://github.com/dominictarr/bench-lru/commit/c55b726)) * add hashlru ([09e99a0](https://github.com/dominictarr/bench-lru/commit/09e99a0)) * Add ignore ([4f8b103](https://github.com/dominictarr/bench-lru/commit/4f8b103)) * Add linter and changelog automatization ([8eadb2d](https://github.com/dominictarr/bench-lru/commit/8eadb2d)) * Add UI feedback ([d4a7977](https://github.com/dominictarr/bench-lru/commit/d4a7977)) * Avoid store data ([bf49f44](https://github.com/dominictarr/bench-lru/commit/bf49f44)) * Calculate bundle size ([685dbfa](https://github.com/dominictarr/bench-lru/commit/685dbfa)) * deps ([4c8f827](https://github.com/dominictarr/bench-lru/commit/4c8f827)) * Fix find ([f8c979e](https://github.com/dominictarr/bench-lru/commit/f8c979e)) * Fix scope ([2be6027](https://github.com/dominictarr/bench-lru/commit/2be6027)) * fix typo @chentsulin found ([46eead9](https://github.com/dominictarr/bench-lru/commit/46eead9)) * Improve format ([7dec452](https://github.com/dominictarr/bench-lru/commit/7dec452)) * initial ([e945b02](https://github.com/dominictarr/bench-lru/commit/e945b02)) * Moar runs ([00133bd](https://github.com/dominictarr/bench-lru/commit/00133bd)) * Move round inside bench ([ba91f0c](https://github.com/dominictarr/bench-lru/commit/ba91f0c)) * new results ([cf2a362](https://github.com/dominictarr/bench-lru/commit/cf2a362)) * Re-testing with `tiny-lru`, fixes #4 ([8130d27](https://github.com/dominictarr/bench-lru/commit/8130d27)), closes [#4](https://github.com/dominictarr/bench-lru/issues/4) * results and discussion ([f566cd2](https://github.com/dominictarr/bench-lru/commit/f566cd2)) * Sort by name ([9c85fb2](https://github.com/dominictarr/bench-lru/commit/9c85fb2)) * Sort results ([60dbed3](https://github.com/dominictarr/bench-lru/commit/60dbed3)) * Sort results ([f294ccc](https://github.com/dominictarr/bench-lru/commit/f294ccc)) * Update ([5c244a6](https://github.com/dominictarr/bench-lru/commit/5c244a6)) * Update deps ([35ac9f7](https://github.com/dominictarr/bench-lru/commit/35ac9f7)) * update readme ([df5c278](https://github.com/dominictarr/bench-lru/commit/df5c278)) * Update README.md ([f5e6dd4](https://github.com/dominictarr/bench-lru/commit/f5e6dd4)) * Updating `data.csv` ([6103c7c](https://github.com/dominictarr/bench-lru/commit/6103c7c)) * Updating a typo ([8286afa](https://github.com/dominictarr/bench-lru/commit/8286afa)) * Updating tiny-lru & re-enabling it's test ([954e28a](https://github.com/dominictarr/bench-lru/commit/954e28a)) * use hashlru, and benchmark reads also ([6fea600](https://github.com/dominictarr/bench-lru/commit/6fea600)) node-lru-cache-10.0.1/benchmark/LICENSE000066400000000000000000000020611446525347600173350ustar00rootroot00000000000000Copyright (c) 2016 'Dominic Tarr' 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. node-lru-cache-10.0.1/benchmark/Makefile000066400000000000000000000003631446525347600177730ustar00rootroot00000000000000all: package.json index.js worker.js rm -rf results.txt results npm run benchmark | tee results.md impls.txt: fetch-impls.sh bash fetch-impls.sh profile: worker.js bash profile.sh package.json: make-deps.sh impls.txt bash make-deps.sh node-lru-cache-10.0.1/benchmark/README.md000066400000000000000000001174621446525347600176230ustar00rootroot00000000000000# bench-lru benchmark the least-recently-used caches which are available on npm. ## Update: March, 2023 Forked and ported over to be used within the lru-cache project directly. Made a bunch of changes to make it easier to run this on an ongoing basis and detect regressions. More implementations can be added by adding them to the list in the `make-deps.sh` script, but for my purposes, the only decently fast and reasonably correct LRU implementations apart from this one are hashlru, lru-fast, and especially, mnemonist. My purpose is not to win a contest, it's to easily track and debug performance characteristics of this library. Run the tests by running `make` in this directory. ## Update: January, 2022 This is a fork of Dominc Tarr's original `bench-lru` script. I've made the following modifications. First, I noted that cache performance and correctness in JavaScript is highly dependent on the types of keys used to store items in the cache. Specifically: 1. When using keys that aren't strings or symbols, it's possible for keys to collide if using an `Object` as the backing store rather than a `Map`. 2. When using integer numbers as object keys, V8 is extremely optimized for `Object` data storage, especially if the values are also integers. However, if the values are numeric strings but numeric _float_ strings, performance goes out the window. 3. Long strings are much slower Object keys than long strings. In the real world, it's quite rare to store 200k integers using the exact same 200k integers as keys. This iteration of the benchmark uses a variety of integers, floats, numeric integer strings, numeric float strings, long strings, strings and integers that collide, objects, and so on, and disqualifies caches that don't pass a basic correctness smoke test. Next, the weighting of scores doesn't much match real world use cases either. In observing several production use cases of LRU caches, the some consistent patterns can be observed. Typically, an LRUCache is being used (if it is actually needed) for a case where: 1. The total data corpus is _very large_, and cannot comfortably fit in memory. (If it isn't large, just save it all, don't bother with an LRU.) 2. The time required to fetch any given item is significant. (If it isn't, just fetch it each time, don't bother with an LRU.) 3. The time over which the data will be accessed is significant, and thus the subset of the corpus of data which will _eventually_ need to be accessed is by the process is more than can comfortably fit in memory. 4. Items tend to spike in popularity for a while, then become less frequenty accessed. If these criteria are met, an LRUCache is a good fit. If a few of them are likely, and the others _might_ be true, then it might still be a good fit to be safe. It's a fairly common need, if somewhat specific. Given this behavior pattern, the weights in the benchmark were off. Simply reporting updates per ms next to evictions per ms is a bit unhelpful. Dominic was correct that evictions are important. However, an eviction _can only happen_ at the time of making a `set()` call, which means that you just performed some expensive upstream action to get the thing that you're caching from its origin. `update`s (that is, setting a key which is already in the cache) are extremely rare in normal LRU-friendly workloads. If you already have it in the cache, don't fetch it upstream or write it again, use the cached one. That's the whole point! The _most_ frequent operations an LRUCache is normally called upon for is: "fetching an item from the queue again". That is to say, to the greatest extent possible, `get()` performance should be roughly equivalent, regardless of where in the heirarchy of recency a given item is found. If fetching the most recently used item is fast, but fetching the item 50% most recently used, or even least recently used, is slow, then the cache will perform poorly (and unpredictably!) under real workloads. To account for the priorities (and the fact that eviction is much slower in every cache measured), the following weights are applied to form a final "score", which is used to sort the list: 1. `evict * 5` 2. `get2 * 5` 3. `get1 * 3` 4. `set * 2` 5. `update * 1` Note that since `get2` tends to be much faster than `evict` in all caches tested, this ends up being the most important metric. Also, I observed that some caches perform very well when `get()` calls are made in the order in which they were inserted into the cache, but much more poorly when `get()` calls are made out of order. Under real workloads, a cache is rarely called upon to list its contents in insertion order, but instead is used in an unpredictable order. To accomplish this, the ordering of the data used in the `update` and `get2` benchmarks is randomized, so that the items need to be constantly reshuffled, as they would be in a real use case. ### Conclusions from this new approach, and my attempts to make lru-cache perform well 1. Only caches with `Map`-based key stores are capable of handling keys that are long string, numeric float strings, or `Symbol` objects with adequate performance. This was surprising to me! I expected that `Symbol` objects would perform well in an `Object` key store, and I suspect that future versions of V8 may optimize this code path if more people use it. The performance gains on long strings (and especially numeric float strings) in `Map` key stores was somewhat surprising as well, but this just shows the hazard of optimizing for a benchmark instead of making a benchmark match real workloads. 2. Only caches with `Map`-based key stores are capable of handling non-string/symbol keys correctly. 3. The garbage-collection penalty for throwing away an object (the approach advocated below) is very low for an object full of integer keys and numeric values. However, it rises dramatically for almost any other shape of data, making linked-list style approaches more effective. 4. Similarly, the gc penalty for object-based linked list approaches makes them perform significantly worse than pointer-based linked list approaches. That is, it's much faster to implement the linked list as two arrays of integers and do `this.next[index]` and `this.previous[index]` rather than an array of node objects and `node.next` and `node.previous`. No amount of object optimization (reusing objects from a pool, etc.) seemed able to get around this. This wasn't surprising, but it was disappointing. `node.next.value` is much more ergonomic and readable than `this.valueList[this.next[index]]`. Almost any of these cache implementations will perform well enough in any situation where you find yourself with a problem that needs a cache. But as always, if you are optimizing a hot path and performance matters, make sure to test it against your actual scenario. If you are strictly using integers as keys, it's worth using one of the "worse" caches on this list. ## Results ``` int: just an integer | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|-------|-------|--------|-------|-------|--------| | [lru-fast](https://npmjs.com/package/lru-fast) | 27663 | 63492 | 8780 | 59880 | 6425 | 586107 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 22396 | 55096 | 9639 | 51282 | 6359 | 507924 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 37736 | 36765 | 15674 | 35778 | 15974 | 460201 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 15723 | 46083 | 6388 | 44346 | 12225 | 458938 | | [hashlru](https://npmjs.com/package/hashlru) | 29112 | 31696 | 12747 | 34130 | 12666 | 400039 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 7313 | 30395 | 8547 | 25445 | 6398 | 273573 | | [lru-cache-7](https://npmjs.com/package/lru-cache) | 10655 | 20471 | 6796 | 19084 | 5244 | 211159 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 10395 | 20141 | 6662 | 18727 | 5417 | 208595 | | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 9790 | 20346 | 4652 | 17809 | 5180 | 200215 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 12547 | 16488 | 8921 | 16000 | 6002 | 193489 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 7605 | 17513 | 4121 | 15911 | 4558 | 174215 | | [lru](https://www.npmjs.com/package/lru) | 11779 | 14194 | 5732 | 14914 | 4168 | 167282 | | [js-lru](https://www.npmjs.com/package/js-lru) | 8107 | 15373 | 7460 | 14296 | 3853 | 160538 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 9195 | 11179 | 5258 | 15962 | 3995 | 156970 | | [lru-cache](https://npmjs.com/package/lru-cache) | 5218 | 12247 | 4380 | 10422 | 3341 | 120372 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 4985 | 11534 | 4858 | 11001 | 2582 | 117345 | | [modern-lru](https://npmjs.com/package/modern-lru) | 7027 | 9896 | 4308 | 8803 | 2876 | 106445 | strint: stringified integer | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|-------|-------|--------|-------|-------|--------| | [hashlru](https://npmjs.com/package/hashlru) | 42373 | 37383 | 14025 | 37383 | 13889 | 467280 | | [lru-cache-7](https://npmjs.com/package/lru-cache) | 18709 | 42105 | 7505 | 41322 | 17094 | 463318 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 18570 | 42373 | 7767 | 40984 | 16807 | 460981 | | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 16625 | 41408 | 7189 | 40486 | 16026 | 447223 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 28050 | 42644 | 8120 | 40241 | 6020 | 423457 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 26702 | 35273 | 11111 | 35273 | 14738 | 420389 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 20222 | 33389 | 10352 | 32787 | 17969 | 404743 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 12895 | 36166 | 7933 | 36496 | 10995 | 379676 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 11587 | 36232 | 4918 | 36697 | 11461 | 377578 | | [lru-fast](https://npmjs.com/package/lru-fast) | 23095 | 4836 | 8150 | 54795 | 6141 | 373528 | | [js-lru](https://www.npmjs.com/package/js-lru) | 10554 | 29197 | 7719 | 28777 | 7669 | 298648 | | [lru](https://www.npmjs.com/package/lru) | 20964 | 28818 | 5132 | 27894 | 4749 | 296729 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 7997 | 29240 | 5983 | 28249 | 5267 | 277277 | | [lru-cache](https://npmjs.com/package/lru-cache) | 6570 | 26774 | 5072 | 26385 | 6693 | 263924 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 6037 | 22396 | 6244 | 20263 | 5520 | 214421 | | [modern-lru](https://npmjs.com/package/modern-lru) | 8197 | 17668 | 6470 | 19436 | 6234 | 204218 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 7496 | 15760 | 4614 | 13643 | 3716 | 153681 | str: string that is not a number | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|------|-------|--------|-------|-------|--------| | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 7449 | 17637 | 7321 | 16260 | 5587 | 184365 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 6691 | 12788 | 5349 | 11396 | 3661 | 132380 | | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 6466 | 12821 | 3752 | 11409 | 3662 | 130502 | | [lru-cache-7](https://npmjs.com/package/lru-cache) | 6568 | 12547 | 5362 | 11142 | 3604 | 129869 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 7095 | 12531 | 6250 | 10256 | 3142 | 125023 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 7278 | 10341 | 5919 | 9341 | 3801 | 117208 | | [hashlru](https://npmjs.com/package/hashlru) | 9311 | 6517 | 4614 | 6307 | 8478 | 116712 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 4241 | 9302 | 5745 | 8772 | 4632 | 109153 | | [lru](https://www.npmjs.com/package/lru) | 6711 | 10449 | 5947 | 8937 | 2120 | 106001 | | [lru-fast](https://npmjs.com/package/lru-fast) | 4379 | 9770 | 5583 | 9350 | 2702 | 103911 | | [js-lru](https://www.npmjs.com/package/js-lru) | 5259 | 9315 | 4915 | 9166 | 2539 | 101903 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 5302 | 8897 | 3049 | 8241 | 3269 | 97894 | | [lru-cache](https://npmjs.com/package/lru-cache) | 4028 | 8214 | 3213 | 7339 | 2219 | 83701 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 3716 | 7321 | 3600 | 7110 | 2236 | 79725 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 3512 | 7800 | 3361 | 6698 | 2057 | 77560 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 4660 | 6616 | 2740 | 4827 | 1910 | 65593 | | [modern-lru](https://npmjs.com/package/modern-lru) | 4360 | 5792 | 2826 | 5330 | 1956 | 65352 | numstr: a mix of integers and strings that look like them ⠴ Benchmarking 1 of 17 caches [hashlru] failed correctness check at key="2" ⠧ Benchmarking 3 of 17 caches [hyperlru-object] failed correctness check at key="2" ⠋ Benchmarking 5 of 17 caches [lru] failed correctness check at key="2" ⠋ Benchmarking 11 of 17 caches [lru-fast] failed correctness check at key="2" ⠦ Benchmarking 13 of 17 caches [secondary-cache] failed correctness check at key="2" ⠹ Benchmarking 14 of 17 caches [simple-lru-cache] failed correctness check at key="2" ⠇ Benchmarking 15 of 17 caches [tiny-lru] failed correctness check at key="2" ⠼ Benchmarking 16 of 17 caches [mnemonist-object] failed correctness check at key="2" | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|-------|-------|--------|-------|-------|--------| | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 10309 | 18519 | 6470 | 16736 | 6105 | 196850 | | [lru-cache-7](https://npmjs.com/package/lru-cache) | 10194 | 18587 | 6112 | 16327 | 5863 | 193211 | | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 9281 | 18382 | 5215 | 16779 | 5757 | 191603 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 11211 | 17483 | 5025 | 15552 | 6085 | 188081 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 7257 | 13996 | 3567 | 13477 | 4880 | 151854 | | [js-lru](https://www.npmjs.com/package/js-lru) | 7070 | 13803 | 6260 | 12469 | 3387 | 141089 | | [lru-cache](https://npmjs.com/package/lru-cache) | 5044 | 12682 | 3731 | 10667 | 3192 | 121160 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 4302 | 11461 | 3851 | 9901 | 2620 | 109443 | | [modern-lru](https://npmjs.com/package/modern-lru) | 6510 | 9276 | 4511 | 8969 | 3217 | 106289 | | [hashlru](https://npmjs.com/package/hashlru) | 0 | 0 | 0 | 0 | 0 | 0 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 0 | 0 | 0 | 0 | 0 | 0 | | [lru](https://www.npmjs.com/package/lru) | 0 | 0 | 0 | 0 | 0 | 0 | | [lru-fast](https://npmjs.com/package/lru-fast) | 0 | 0 | 0 | 0 | 0 | 0 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 0 | 0 | 0 | 0 | 0 | 0 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 0 | 0 | 0 | 0 | 0 | 0 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 0 | 0 | 0 | 0 | 0 | 0 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 0 | 0 | 0 | 0 | 0 | 0 | pi: multiples of pi | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|------|-------|--------|-------|-------|--------| | [lru-cache-7](https://npmjs.com/package/lru-cache) | 5588 | 11891 | 4519 | 10905 | 3064 | 121213 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 7457 | 9980 | 5838 | 9579 | 3842 | 117797 | | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 4700 | 10096 | 2950 | 11148 | 2719 | 111973 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 5372 | 10256 | 4248 | 10262 | 2951 | 111825 | | [js-lru](https://www.npmjs.com/package/js-lru) | 3807 | 8893 | 5237 | 8058 | 2400 | 91820 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 3269 | 5313 | 3204 | 7968 | 2526 | 78151 | | [lru-cache](https://npmjs.com/package/lru-cache) | 3309 | 6709 | 3230 | 6861 | 1837 | 73465 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 3152 | 6234 | 3444 | 6246 | 1694 | 68150 | | [modern-lru](https://npmjs.com/package/modern-lru) | 2642 | 4103 | 2452 | 4190 | 1508 | 48535 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 1643 | 2244 | 2016 | 2315 | 836 | 27789 | | [lru](https://www.npmjs.com/package/lru) | 1688 | 1980 | 1744 | 1891 | 1277 | 26900 | | [hashlru](https://npmjs.com/package/hashlru) | 1801 | 1599 | 1362 | 1545 | 1655 | 25761 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 1358 | 1948 | 1803 | 1998 | 789 | 24298 | | [lru-fast](https://npmjs.com/package/lru-fast) | 1326 | 1944 | 1590 | 1994 | 681 | 23449 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 1542 | 1917 | 1484 | 1803 | 749 | 23079 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 1304 | 1755 | 1473 | 1871 | 663 | 22016 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 1336 | 1597 | 1162 | 1661 | 610 | 19980 | float: floating point values | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|------|-------|--------|-------|-------|--------| | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 5420 | 10493 | 3197 | 12255 | 3091 | 122246 | | [lru-cache-7](https://npmjs.com/package/lru-cache) | 5478 | 11827 | 4633 | 10858 | 3048 | 120600 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 7582 | 10325 | 6209 | 9766 | 3849 | 120423 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 5318 | 8150 | 3664 | 11912 | 3293 | 114775 | | [js-lru](https://www.npmjs.com/package/js-lru) | 4004 | 8610 | 5488 | 8407 | 2555 | 94136 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 3327 | 7067 | 3033 | 7776 | 2532 | 82428 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 3077 | 6609 | 3506 | 6414 | 1681 | 69962 | | [lru-cache](https://npmjs.com/package/lru-cache) | 3151 | 6279 | 3212 | 6623 | 1698 | 69956 | | [modern-lru](https://npmjs.com/package/modern-lru) | 2964 | 4551 | 2616 | 4665 | 1701 | 54027 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 1657 | 2376 | 2028 | 2448 | 846 | 28940 | | [lru](https://www.npmjs.com/package/lru) | 1749 | 2181 | 1821 | 1985 | 1207 | 27822 | | [hashlru](https://npmjs.com/package/hashlru) | 1784 | 1675 | 1456 | 1604 | 1639 | 26264 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 1662 | 2006 | 1612 | 1917 | 840 | 24739 | | [lru-fast](https://npmjs.com/package/lru-fast) | 1367 | 2018 | 1788 | 2071 | 703 | 24446 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 1368 | 1919 | 1880 | 1975 | 797 | 24233 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 1305 | 1866 | 1515 | 1886 | 684 | 22573 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 1323 | 1662 | 1232 | 1690 | 634 | 20484 | obj: an object with a single key ⠴ Benchmarking 1 of 17 caches [hashlru] failed correctness check at key={"z":0} ⠧ Benchmarking 3 of 17 caches [hyperlru-object] failed correctness check at key={"z":0} ⠇ Benchmarking 5 of 17 caches [lru] failed correctness check at key={"z":0} ⠼ Benchmarking 11 of 17 caches [lru-fast] failed correctness check at key={"z":0} ⠋ Benchmarking 13 of 17 caches [secondary-cache] failed correctness check at key={"z":0} ⠴ Benchmarking 14 of 17 caches [simple-lru-cache] failed correctness check at key={"z":0} ⠙ Benchmarking 15 of 17 caches [tiny-lru] failed correctness check at key={"z":0} ⠧ Benchmarking 16 of 17 caches [mnemonist-object] failed correctness check at key={"z":0} | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|-------|-------|--------|-------|-------|--------| | [lru-cache-7](https://npmjs.com/package/lru-cache) | 10215 | 19822 | 6581 | 19157 | 5623 | 210377 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 9921 | 20429 | 6718 | 18349 | 5548 | 207332 | | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 8913 | 20387 | 5954 | 18639 | 5366 | 204966 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 11710 | 18100 | 5161 | 16273 | 5700 | 192746 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 7055 | 17227 | 3566 | 16064 | 4551 | 172432 | | [js-lru](https://www.npmjs.com/package/js-lru) | 7613 | 14286 | 6892 | 12723 | 3630 | 146741 | | [lru-cache](https://npmjs.com/package/lru-cache) | 5061 | 12158 | 4043 | 10655 | 3644 | 122134 | | [modern-lru](https://npmjs.com/package/modern-lru) | 6129 | 10616 | 5444 | 10304 | 2957 | 115855 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 4537 | 11056 | 3974 | 9128 | 2557 | 104641 | | [hashlru](https://npmjs.com/package/hashlru) | 0 | 0 | 0 | 0 | 0 | 0 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 0 | 0 | 0 | 0 | 0 | 0 | | [lru](https://www.npmjs.com/package/lru) | 0 | 0 | 0 | 0 | 0 | 0 | | [lru-fast](https://npmjs.com/package/lru-fast) | 0 | 0 | 0 | 0 | 0 | 0 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 0 | 0 | 0 | 0 | 0 | 0 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 0 | 0 | 0 | 0 | 0 | 0 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 0 | 0 | 0 | 0 | 0 | 0 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 0 | 0 | 0 | 0 | 0 | 0 | rand: random floating point number | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|------|-------|--------|-------|-------|--------| | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 4912 | 10644 | 3218 | 11744 | 3027 | 118829 | | [lru-cache-7](https://npmjs.com/package/lru-cache) | 5789 | 11013 | 4197 | 10834 | 3099 | 118479 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 7524 | 10050 | 5936 | 9398 | 3826 | 117254 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 5640 | 9217 | 3837 | 10846 | 3061 | 112303 | | [js-lru](https://www.npmjs.com/package/js-lru) | 3982 | 8052 | 5155 | 8651 | 2431 | 92685 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 3176 | 7246 | 2881 | 7070 | 2488 | 78761 | | [lru-cache](https://npmjs.com/package/lru-cache) | 3071 | 6810 | 3150 | 6481 | 1812 | 71187 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 3175 | 6295 | 3386 | 6109 | 1712 | 67726 | | [modern-lru](https://npmjs.com/package/modern-lru) | 3341 | 4206 | 2594 | 4619 | 1653 | 53254 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 1669 | 2380 | 1984 | 2350 | 859 | 28507 | | [lru](https://www.npmjs.com/package/lru) | 1723 | 1866 | 1668 | 1829 | 1265 | 26182 | | [hashlru](https://npmjs.com/package/hashlru) | 1790 | 1610 | 1402 | 1546 | 1613 | 25607 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 1667 | 2060 | 1572 | 1946 | 809 | 24861 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 1368 | 1958 | 1791 | 1999 | 768 | 24236 | | [lru-fast](https://npmjs.com/package/lru-fast) | 1360 | 1952 | 1760 | 1987 | 696 | 23751 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 1205 | 1815 | 1509 | 1949 | 682 | 22519 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 1391 | 1665 | 1217 | 1740 | 645 | 20919 | sym: a Symbol object ⠼ Benchmarking 5 of 17 caches [lru] failed correctness check TypeError: Cannot convert a Symbol value to a string at LRU.set (/Users/isaacs/dev/isaacs/lru-cache/bench-lru/node_modules/lru/index.js:69:41) at self.onmessage (evalmachine.:116:38) at process. (/Users/isaacs/dev/isaacs/lru-cache/bench-lru/node_modules/tiny-worker/lib/worker.js:60:55) at process.emit (node:events:520:28) at emit (node:internal/child_process:936:14) at processTicksAndRejections (node:internal/process/task_queues:84:21) | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|-------|-------|--------|-------|-------|--------| | [lru-cache-7](https://npmjs.com/package/lru-cache) | 9886 | 19361 | 6991 | 17809 | 5445 | 201116 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 9809 | 19455 | 6258 | 17794 | 5430 | 200361 | | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 9074 | 19417 | 6450 | 17953 | 5359 | 199409 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 7776 | 20492 | 6831 | 17391 | 5593 | 198779 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 10893 | 17652 | 5375 | 15540 | 5616 | 185897 | | [js-lru](https://www.npmjs.com/package/js-lru) | 7297 | 14399 | 6925 | 12650 | 3591 | 145921 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 7174 | 14124 | 3938 | 12300 | 4535 | 144833 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 7758 | 12845 | 6824 | 11682 | 3125 | 134910 | | [lru-fast](https://npmjs.com/package/lru-fast) | 6028 | 3537 | 6916 | 16340 | 2874 | 125653 | | [hashlru](https://npmjs.com/package/hashlru) | 9602 | 7148 | 5144 | 6761 | 8264 | 120917 | | [lru-cache](https://npmjs.com/package/lru-cache) | 5179 | 12114 | 3814 | 10846 | 3207 | 120779 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 4636 | 8957 | 6044 | 8981 | 4601 | 110097 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 4540 | 10959 | 4344 | 8799 | 2696 | 103776 | | [modern-lru](https://npmjs.com/package/modern-lru) | 6129 | 8421 | 5045 | 8460 | 2817 | 98951 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 3577 | 7533 | 3856 | 6349 | 2258 | 76644 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 5319 | 7573 | 3177 | 5238 | 2055 | 72999 | | [lru](https://www.npmjs.com/package/lru) | 0 | 0 | 0 | 0 | 0 | 0 | longstr: a very long string | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|------|-------|--------|-------|-------|--------| | [lru-cache-7](https://npmjs.com/package/lru-cache) | 5882 | 11044 | 5009 | 10147 | 3107 | 116175 | | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 5828 | 11287 | 4102 | 10320 | 2738 | 114909 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 5936 | 9960 | 4827 | 10020 | 3224 | 112799 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 6464 | 9264 | 6291 | 8396 | 3193 | 104956 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 4900 | 8834 | 3499 | 8094 | 2759 | 94066 | | [js-lru](https://www.npmjs.com/package/js-lru) | 4700 | 8316 | 5185 | 7997 | 2298 | 91008 | | [lru-cache](https://npmjs.com/package/lru-cache) | 3666 | 7862 | 3514 | 6991 | 2044 | 79607 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 2949 | 6658 | 4930 | 6640 | 2690 | 77452 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 3377 | 7283 | 3492 | 6607 | 1856 | 74410 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 2248 | 4006 | 4218 | 3946 | 2547 | 53197 | | [hashlru](https://npmjs.com/package/hashlru) | 4003 | 3281 | 2791 | 3078 | 3169 | 51875 | | [lru-fast](https://npmjs.com/package/lru-fast) | 2261 | 4432 | 3907 | 4352 | 1616 | 51565 | | [modern-lru](https://npmjs.com/package/modern-lru) | 3132 | 4287 | 2691 | 4307 | 1282 | 49761 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 2502 | 3859 | 3854 | 3752 | 1826 | 48325 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 1989 | 3715 | 2690 | 3430 | 1235 | 41138 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 2500 | 3394 | 2086 | 2845 | 1148 | 37233 | | [lru](https://www.npmjs.com/package/lru) | 2345 | 3073 | 2714 | 2903 | 1042 | 36348 | mix: a mix of all the types ⠦ Benchmarking 1 of 17 caches [hashlru] failed correctness check at key={"z":3} ⠧ Benchmarking 3 of 17 caches [hyperlru-object] failed correctness check at key={"z":3} ⠏ Benchmarking 5 of 17 caches [lru] failed correctness check TypeError: Cannot convert a Symbol value to a string at LRU.set (/Users/isaacs/dev/isaacs/lru-cache/bench-lru/node_modules/lru/index.js:69:41) at self.onmessage (evalmachine.:116:38) at process. (/Users/isaacs/dev/isaacs/lru-cache/bench-lru/node_modules/tiny-worker/lib/worker.js:60:55) at process.emit (node:events:520:28) at emit (node:internal/child_process:936:14) at processTicksAndRejections (node:internal/process/task_queues:84:21) ⠼ Benchmarking 11 of 17 caches [lru-fast] failed correctness check at key={"z":3} ⠴ Benchmarking 13 of 17 caches [secondary-cache] failed correctness check at key={"z":3} ⠙ Benchmarking 14 of 17 caches [simple-lru-cache] failed correctness check at key={"z":3} ⠧ Benchmarking 15 of 17 caches [tiny-lru] failed correctness check at key={"z":3} ⠸ Benchmarking 16 of 17 caches [mnemonist-object] failed correctness check at key={"z":3} | name | set | get1 | update | get2 | evict | score | |----------------------------------------------------------------|------|-------|--------|-------|-------|--------| | [lru-cache-7](https://npmjs.com/package/lru-cache) | 7457 | 13342 | 5802 | 12195 | 3979 | 141612 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 8061 | 14015 | 6369 | 11312 | 3975 | 140971 | | [lru-cache-7-dispose](https://npmjs.com/package/lru-cache) | 7138 | 13271 | 5321 | 12210 | 3953 | 140225 | | [lru-cache-7-size](https://npmjs.com/package/lru-cache) | 6847 | 13405 | 4351 | 12070 | 3757 | 137395 | | [js-lru](https://www.npmjs.com/package/js-lru) | 5316 | 9676 | 4381 | 9170 | 2900 | 104391 | | [lru-cache-7-ttl](https://npmjs.com/package/lru-cache) | 5708 | 9833 | 3164 | 8333 | 3419 | 102839 | | [lru-cache](https://npmjs.com/package/lru-cache) | 4165 | 8624 | 3328 | 7890 | 2557 | 89765 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 3875 | 7758 | 3351 | 7179 | 2017 | 80355 | | [modern-lru](https://npmjs.com/package/modern-lru) | 4919 | 6256 | 3227 | 6129 | 2147 | 73213 | | [hashlru](https://npmjs.com/package/hashlru) | 0 | 0 | 0 | 0 | 0 | 0 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 0 | 0 | 0 | 0 | 0 | 0 | | [lru](https://www.npmjs.com/package/lru) | 0 | 0 | 0 | 0 | 0 | 0 | | [lru-fast](https://npmjs.com/package/lru-fast) | 0 | 0 | 0 | 0 | 0 | 0 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 0 | 0 | 0 | 0 | 0 | 0 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 0 | 0 | 0 | 0 | 0 | 0 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 0 | 0 | 0 | 0 | 0 | 0 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 0 | 0 | 0 | 0 | 0 | 0 | ``` The best performers are `lru-cache` version 7 and `mnemonist`'s `LRUMap`, across most categories. `mnemonist-map` seems to consistently have slightly better eviction and set performance, and slightly worse get performance, for many key types. The difference is small enough to be negligible, which is to be expected. For object-friendly key spaces (strictly integers or strictly short strings), `mnemonist`'s `LRUCache` and `hashlru` seem to do the best. For strictly integer key sets, `lru-fast` lives up to its name, blowing the other implementations out of the water, but did not perform nearly as well with other types of keys. --- What follows below is Dominic Tarr's original discussion from 2016. _[@isaacs](https://github.com/isaacs)_ --- ## Introduction An LRU cache is a cache with bounded memory use. The point of a cache is to improve performance, so how performant are the available implementations? LRUs achive bounded memory use by removing the oldest items when a threashold number of items is reached. We measure 3 cases, adding an item, updating an item, and adding items which push other items out of the LRU. There is a [previous benchmark](https://www.npmjs.com/package/bench-cache) but it did not describe it's methodology. (and since it measures the memory used, but tests everything in the same process, it does not get clear results) ## Benchmark I run a very simple multi-process benchmark, with 5 iterations to get a median of ops/ms: 1. Set the LRU to fit max N=200,000 items. 2. Add N random numbers to the cache, with keys 0-N. 3. Then update those keys with new random numbers. 4. Then _evict_ those keys, by adding keys N-2N. ### Results Operations per millisecond (_higher is better_): | name | set | get1 | update | get2 | evict | | -------------------------------------------------------------- | ----- | ----- | ------ | ----- | ----- | | [hashlru](https://npmjs.com/package/hashlru) | 18536 | 17590 | 17794 | 18332 | 9381 | | [mnemonist-object](https://www.npmjs.com/package/mnemonist) | 15314 | 69444 | 35026 | 68966 | 7949 | | [quick-lru](https://npmjs.com/package/quick-lru) | 8214 | 4572 | 6777 | 4608 | 6345 | | [tiny-lru](https://npmjs.com/package/tiny-lru) | 6530 | 46296 | 37244 | 42017 | 5961 | | [lru-fast](https://npmjs.com/package/lru-fast) | 5979 | 36832 | 32626 | 40900 | 5929 | | [mnemonist-map](https://www.npmjs.com/package/mnemonist) | 6272 | 15785 | 10923 | 16077 | 3738 | | [lru](https://www.npmjs.com/package/lru) | 3927 | 5454 | 5001 | 5366 | 2827 | | [simple-lru-cache](https://npmjs.com/package/simple-lru-cache) | 3393 | 3855 | 3701 | 3899 | 2496 | | [hyperlru-object](https://npmjs.com/package/hyperlru-object) | 3515 | 3953 | 4044 | 4102 | 2495 | | [js-lru](https://www.npmjs.com/package/js-lru) | 3813 | 10010 | 9246 | 10309 | 1843 | | [secondary-cache](https://npmjs.com/package/secondary-cache) | 2780 | 5705 | 5790 | 10549 | 1727 | | [lru-cache](https://npmjs.com/package/lru-cache) | 2275 | 3388 | 3334 | 3301 | 1593 | | [hyperlru-map](https://npmjs.com/package/hyperlru-map) | 2424 | 2508 | 2443 | 2540 | 1552 | | [modern-lru](https://npmjs.com/package/modern-lru) | 2710 | 3946 | 3581 | 4021 | 1327 | | [mkc](https://npmjs.com/packacge/package/mkc) | 1559 | 2044 | 1178 | 2161 | 1037 | We can group the results in a few categories: - all rounders (mnemonist, lru_cache, tiny-lru, simple-lru-cache, lru-fast) where the performance to add update and evict are comparable. - fast-write, slow-evict (lru, hashlru, lru-native, modern-lru) these have better set/update times, but for some reason are quite slow to evict items! - slow in at least 2 categories (lru-cache, mkc, faster-lru-cache, secondary-cache) ## Discussion It appears that all-round performance is the most difficult to achive, in particular, performance on eviction is difficult to achive. I think eviction performance is the most important consideration, because once the cache is _warm_ each subsequent addition causes an eviction, and actively used, _hot_, cache will run close to it's eviction performance. Also, some have faster add than update, and some faster update than add. `modern-lru` gets pretty close to `lru-native` perf. I wrote `hashlru` after my seeing the other results from this benchmark, it's important to point out that it does not use the classic LRU algorithm, but has the important properties of the LRU (bounded memory use and O(1) time complexity) Splitting the benchmark into multiple processes helps minimize JIT state pollution (gc, turbofan opt/deopt, etc.), and we see a much clearer picture of performance per library. ## Future work This is still pretty early results, take any difference smaller than an order of magnitude with a grain of salt. It is necessary to measure the statistical significance of the results to know accurately the relative performance of two closely matched implementations. I also didn't test the memory usage. This should be done running the benchmarks each in a separate process, so that the memory used by each run is not left over while the next is running. ## Conclusion Javascript is generally slow, so one of the best ways to make it fast is to write less of it. LRUs are also quite difficult to implement (linked lists!). In trying to come up with a faster LRU implementation I realized that something far simpler could do the same job. Especially given the strengths and weaknesses of javascript, this is significantly faster than any of the other implementations, _including_ the C implementation. Likely, the overhead of the C<->js boundry is partly to blame here. ## License MIT node-lru-cache-10.0.1/benchmark/fetch-impls.sh000066400000000000000000000005561446525347600211060ustar00rootroot00000000000000#!/usr/bin/env bash # get the latest patch in each lru-cache 7.x and up, # plus mnemonist, hashlru, and lru-fast nvs=($( npm view 'lru-cache@>=7' name | awk -F. '{print $1 "." $2}' | sort -r -V | uniq ) 'mnemonist@0.39' 'hashlru@2' 'lru-fast@0.2') echo "lru-cache_CURRENT" > impls.txt for dep in "${nvs[@]}"; do name=${dep/@/_} echo $name >> impls.txt done node-lru-cache-10.0.1/benchmark/impls.js000066400000000000000000000022171446525347600200150ustar00rootroot00000000000000const { readFileSync } = require('fs') const impls = readFileSync(__dirname + '/impls.txt', 'utf8') .trim() .split('\n') for (const impl of impls) { if (impl.startsWith('lru-cache_')) { const LRUCache = require(impl) exports[impl] = max => new LRUCache({ max }) } else if (impl.startsWith('mnemonist_')) { MnemonistLRUMap = require(impl + '/lru-map-with-delete') MnemonistLRUCache = require(impl + '/lru-cache-with-delete') exports[impl + '_obj'] = max => new MnemonistLRUCache(max) exports[impl + '_map'] = max => new MnemonistLRUMap(max) } else if (impl.startsWith('hashlru_')) { exports[impl] = require(impl) } else if (impl.startsWith('lru-fast_')) { const { LRUCache } = require(impl) exports[impl] = max => new LRUCache(max) } else { throw new Error( 'found an impl i dont know how to create: ' + impl ) } } exports['just a Map'] = _ => new Map() exports['just a null obj'] = _ => { const data = Object.create(null) return { set: (k, v) => (data[k] = v), get: k => data[k] } } exports['just a {}'] = _ => { const data = {} return { set: (k, v) => (data[k] = v), get: k => data[k] } } node-lru-cache-10.0.1/benchmark/index.js000066400000000000000000000055361446525347600200070ustar00rootroot00000000000000'use strict' process.env.__LRU_BENCH_DIR = __dirname require('mkdirp').sync(__dirname + '/results') const Worker = require('tiny-worker') const ora = require('ora') const caches = Object.keys(require('./impls.js')) const nth = caches.length const { writeFileSync } = require('fs') const types = { int: 'just an integer', strint: 'stringified integer', str: 'string that is not a number', numstr: 'a mix of integers and strings that look like them', pi: 'multiples of pi', float: 'floating point values', obj: 'an object with a single key', rand: 'random floating point number', sym: 'a Symbol object', longstr: 'a very long string', mix: 'a mix of all the types', } if (!process.env.TYPE) { const spawn = require('child_process').spawn const todo = Object.keys(types) const run = () => new Promise(res => { const TYPE = todo.shift() if (!TYPE) return res() console.log(`${TYPE}: ${types[TYPE]}`) const child = spawn(process.execPath, [__filename], { env: { TYPE }, stdio: 'inherit', }) child.on('close', () => res(run())) }) run() } else { const spinner = ora(`Starting benchmark of ${nth} caches`).start(), promises = [] caches.forEach((i, idx) => { promises.push( new Promise((resolve, reject) => { return (idx === 0 ? Promise.resolve() : promises[idx - 1]) .then(() => { const worker = new Worker('worker.js') worker.onmessage = ev => { resolve(ev.data) worker.terminate() } worker.onerror = err => { reject(err) worker.terminate() } spinner.text = `Benchmarking ${ idx + 1 } of ${nth} caches [${i}]` worker.postMessage(i) }) .catch(reject) }) ) }) Promise.all(promises) .then(results => { const toMD = require('markdown-tables') const keysort = require('keysort') spinner.stop() const data = keysort( results.map(i => { const obj = JSON.parse(i) obj.score = obj.evict * 5 + obj.get2 * 5 + obj.get1 * 3 + obj.set * 2 + obj.update return obj }), 'score desc' ) const heading = 'name,set,get1,update,get2,evict,score' const csv = [heading] .concat( data.map( i => `${i.name},${i.set},${i.get1},${i.update},${i.get2},${i.evict},${i.score}` ) ) .join('\n') + '\n' const resultsFile = `${__dirname}/results/${process.env.TYPE}.csv` writeFileSync(resultsFile, csv, 'utf8') console.log(toMD(csv)) }) .catch(err => { console.error(err.stack || err.message || err) process.exit(1) }) } node-lru-cache-10.0.1/benchmark/make-deps.sh000066400000000000000000000015121446525347600205320ustar00rootroot00000000000000#!/usr/bin/env bash deps="" install=() for name in $(cat impls.txt); do if [ "$name" = "lru-cache_CURRENT" ]; then continue fi dep=${name/_/@} deps="${deps}"' "'"$name"'": "'"npm:$dep"$'",\n' done cat >package.json < $d ln ${PWD}/$d profile.txt cat profile.txt node-lru-cache-10.0.1/benchmark/worker.js000066400000000000000000000113301446525347600201760ustar00rootroot00000000000000'use strict' const precise = require('precise') const retsu = require('retsu') const dir = process.env.__LRU_BENCH_DIR || __dirname const caches = require(dir + '/impls.js') const num = +process.env.N || 10_000 const evict = num * 2 const times = 10 const x = 1e6 const dataOrder = [] const data1 = new Array(evict) const data2 = new Array(evict) const data3 = new Array(evict) const typeGen = { numstr: z => (z % 2 === 0 ? z : String(z + 1)), pi: z => z * Math.PI, float: z => z + z / (evict + 1), obj: z => ({ z }), strint: z => String(z), str: z => 'foo' + z + 'bar', rand: z => z * Math.random(), sym: z => Symbol(String(z)), longstr: z => z + 'z'.repeat(1024 * 4), int: z => z, mix: z => typeGen[typeKeys[z % (typeKeys.length - 1)]](z), } const typeKeys = Object.keys(typeGen) ;(function seed() { let z = -1 const t = process.env.TYPE || 'mix' while (++z < evict) { const x = typeGen[t](z) data1[z] = [x, Math.floor(Math.random() * 1e7)] dataOrder.push(z) } // shuffle up the key orders, so we're not just walking down the list. for (const key of dataOrder.sort(() => Math.random() - 0.5)) { data2[key] = [data1[key][0], Math.random() * 1e7] } for (const key of dataOrder.sort(() => Math.random() - 0.5)) { data3[key] = data1[key] } })() const runTest = id => { const time = { set: [], get1: [], update: [], get2: [], evict: [], } const results = { name: id, set: 0, get1: 0, update: 0, get2: 0, evict: 0, } let n = -1 // super rudimentary correctness check // make sure that 5 puts get back the same 5 items we put // ignore stderr, some caches are complainy about some keys let error = console.error console.error = () => {} try { const s = Math.max(5, Math.min(Math.floor(num / 2), 50)) const m = Math.min(s * 5, num) const lru = caches[id](s) for (let i = 0; i < s; i++) lru.set(data1[i][0], data1[i][1]) for (let i = 0; i < s; i++) { if (lru.get(data1[i][0]) !== data1[i][1]) { if (!process.stdout.isTTY) process.stderr.write(id) error(' failed correctness check at key=%j', data1[i][0]) postMessage( JSON.stringify({ name: id, set: 0, get1: 0, update: 0, get2: 0, evict: 0, }) ) process.exit(1) } } if (!/^just a/.test(id) && !/unbounded$/.test(id)) { for (let i = s + 1; i < m; i++) lru.set(data1[i][0], data1[i][1]) if (lru.get(data1[0][0])) { if (!process.stdout.isTTY) process.stderr.write(id) error(' failed eviction correctness check') postMessage( JSON.stringify({ name: id, set: 0, get1: 0, update: 0, get2: 0, evict: 0, }) ) process.exit(1) } } lru.set('__proto__', { [__filename]: 'pwned' }) if (lru.get(__filename)) { error(' failed prototype pollution check') if (!/^just a/.test(id)) { postMessage( JSON.stringify({ name: id, set: 0, get1: 0, update: 0, get2: 0, evict: 0, }) ) process.exit(1) } } } catch (er) { if (!process.stdout.isTTY) process.stderr.write(id) error(' failed correctness check', er.stack) postMessage( JSON.stringify({ name: id, set: 0, get1: 0, update: 0, get2: 0, evict: 0, }) ) process.exit(1) } console.error = error while (++n < times) { const lru = caches[id](num) const stimer = precise().start() for (let i = 0; i < num; i++) lru.set(data1[i][0], data1[i][1]) time.set.push(stimer.stop().diff() / x) const gtimer = precise().start() for (let i = 0; i < num; i++) lru.get(data1[i][0]) time.get1.push(gtimer.stop().diff() / x) const utimer = precise().start() for (let i = 0; i < num; i++) lru.set(data2[i][0], data2[i][1]) time.update.push(utimer.stop().diff() / x) const g2timer = precise().start() for (let i = 0; i < num; i++) lru.get(data3[i][0]) time.get2.push(g2timer.stop().diff() / x) const etimer = precise().start() for (let i = num; i < evict; i++) lru.set(data1[i][0], data1[i][1]) time.evict.push(etimer.stop().diff() / x) } ;['set', 'get1', 'update', 'get2', 'evict'].forEach(i => { results[i] = Number( (num / retsu.median(time[i]).toFixed(2)).toFixed(0) ) }) postMessage(JSON.stringify(results)) } if (typeof self !== 'undefined') { self.onmessage = ev => runTest(ev.data) } else { global.postMessage = console.log runTest('lru-cache_CURRENT') } node-lru-cache-10.0.1/fixup.sh000066400000000000000000000006001446525347600160620ustar00rootroot00000000000000#!/usr/bin/env bash esbuild --minify \ --sourcemap \ --bundle dist/cjs/index.js \ --outfile=dist/cjs/index.min.js \ --format=cjs esbuild --minify \ --sourcemap \ --bundle dist/mjs/index.js \ --outfile=dist/mjs/index.min.js \ --format=esm cat >dist/cjs/package.json <dist/mjs/package.json < 'index.js' node-lru-cache-10.0.1/package-lock.json000066400000000000000000006417601446525347600176310ustar00rootroot00000000000000{ "name": "lru-cache", "version": "10.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "lru-cache", "version": "10.0.1", "license": "ISC", "devDependencies": { "@size-limit/preset-small-lib": "^7.0.8", "@types/node": "^20.2.5", "@types/tap": "^15.0.6", "benchmark": "^2.1.4", "c8": "^7.11.2", "clock-mock": "^1.0.6", "esbuild": "^0.17.11", "eslint-config-prettier": "^8.5.0", "marked": "^4.2.12", "mkdirp": "^2.1.5", "prettier": "^2.6.2", "size-limit": "^7.0.8", "tap": "^16.3.4", "ts-node": "^10.9.1", "tslib": "^2.4.0", "typedoc": "^0.24.6", "typescript": "^5.0.4" }, "engines": { "node": "14 || >=16.14" } }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", "dev": true, "dependencies": { "@babel/highlight": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz", "integrity": "sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.0.tgz", "integrity": "sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.18.6", "@babel/generator": "^7.21.0", "@babel/helper-compilation-targets": "^7.20.7", "@babel/helper-module-transforms": "^7.21.0", "@babel/helpers": "^7.21.0", "@babel/parser": "^7.21.0", "@babel/template": "^7.20.7", "@babel/traverse": "^7.21.0", "@babel/types": "^7.21.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.2", "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/babel" } }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { "version": "7.21.1", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.1.tgz", "integrity": "sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==", "dev": true, "dependencies": { "@babel/types": "^7.21.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/helper-compilation-targets": { "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", "dev": true, "dependencies": { "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", "lru-cache": "^5.1.1", "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "dependencies": { "yallist": "^3.0.2" } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, "node_modules/@babel/helper-environment-visitor": { "version": "7.18.9", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", "dev": true, "dependencies": { "@babel/template": "^7.20.7", "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", "dev": true, "dependencies": { "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", "dev": true, "dependencies": { "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { "version": "7.21.2", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", "@babel/template": "^7.20.7", "@babel/traverse": "^7.21.2", "@babel/types": "^7.21.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { "version": "7.20.2", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", "dev": true, "dependencies": { "@babel/types": "^7.20.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", "dev": true, "dependencies": { "@babel/types": "^7.18.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { "version": "7.19.4", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.19.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { "version": "7.21.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", "dev": true, "dependencies": { "@babel/template": "^7.20.7", "@babel/traverse": "^7.21.0", "@babel/types": "^7.21.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight/node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, "dependencies": { "color-convert": "^1.9.0" }, "engines": { "node": ">=4" } }, "node_modules/@babel/highlight/node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" }, "engines": { "node": ">=4" } }, "node_modules/@babel/highlight/node_modules/color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, "dependencies": { "color-name": "1.1.3" } }, "node_modules/@babel/highlight/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, "node_modules/@babel/highlight/node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { "node": ">=0.8.0" } }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/@babel/highlight/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, "dependencies": { "has-flag": "^3.0.0" }, "engines": { "node": ">=4" } }, "node_modules/@babel/parser": { "version": "7.21.2", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.2.tgz", "integrity": "sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/template": { "version": "7.20.7", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { "version": "7.21.2", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.2.tgz", "integrity": "sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", "@babel/generator": "^7.21.1", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/parser": "^7.21.2", "@babel/types": "^7.21.2", "debug": "^4.1.0", "globals": "^11.1.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse/node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/@babel/types": { "version": "7.21.2", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.2.tgz", "integrity": "sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", "to-fast-properties": "^2.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, "engines": { "node": ">=12" } }, "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@esbuild/android-arm": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.11.tgz", "integrity": "sha512-CdyX6sRVh1NzFCsf5vw3kULwlAhfy9wVt8SZlrhQ7eL2qBjGbFhRBWkkAzuZm9IIEOCKJw4DXA6R85g+qc8RDw==", "cpu": [ "arm" ], "dev": true, "optional": true, "os": [ "android" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/android-arm64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.11.tgz", "integrity": "sha512-QnK4d/zhVTuV4/pRM4HUjcsbl43POALU2zvBynmrrqZt9LPcLA3x1fTZPBg2RRguBQnJcnU059yKr+bydkntjg==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "android" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/android-x64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.11.tgz", "integrity": "sha512-3PL3HKtsDIXGQcSCKtWD/dy+mgc4p2Tvo2qKgKHj9Yf+eniwFnuoQ0OUhlSfAEpKAFzF9N21Nwgnap6zy3L3MQ==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "android" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/darwin-arm64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.11.tgz", "integrity": "sha512-pJ950bNKgzhkGNO3Z9TeHzIFtEyC2GDQL3wxkMApDEghYx5Qers84UTNc1bAxWbRkuJOgmOha5V0WUeh8G+YGw==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "darwin" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/darwin-x64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.11.tgz", "integrity": "sha512-iB0dQkIHXyczK3BZtzw1tqegf0F0Ab5texX2TvMQjiJIWXAfM4FQl7D909YfXWnB92OQz4ivBYQ2RlxBJrMJOw==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "darwin" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/freebsd-arm64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.11.tgz", "integrity": "sha512-7EFzUADmI1jCHeDRGKgbnF5sDIceZsQGapoO6dmw7r/ZBEKX7CCDnIz8m9yEclzr7mFsd+DyasHzpjfJnmBB1Q==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "freebsd" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/freebsd-x64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.11.tgz", "integrity": "sha512-iPgenptC8i8pdvkHQvXJFzc1eVMR7W2lBPrTE6GbhR54sLcF42mk3zBOjKPOodezzuAz/KSu8CPyFSjcBMkE9g==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "freebsd" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-arm": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.11.tgz", "integrity": "sha512-M9iK/d4lgZH0U5M1R2p2gqhPV/7JPJcRz+8O8GBKVgqndTzydQ7B2XGDbxtbvFkvIs53uXTobOhv+RyaqhUiMg==", "cpu": [ "arm" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-arm64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.11.tgz", "integrity": "sha512-Qxth3gsWWGKz2/qG2d5DsW/57SeA2AmpSMhdg9TSB5Svn2KDob3qxfQSkdnWjSd42kqoxIPy3EJFs+6w1+6Qjg==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-ia32": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.11.tgz", "integrity": "sha512-dB1nGaVWtUlb/rRDHmuDQhfqazWE0LMro/AIbT2lWM3CDMHJNpLckH+gCddQyhhcLac2OYw69ikUMO34JLt3wA==", "cpu": [ "ia32" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-loong64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.11.tgz", "integrity": "sha512-aCWlq70Q7Nc9WDnormntGS1ar6ZFvUpqr8gXtO+HRejRYPweAFQN615PcgaSJkZjhHp61+MNLhzyVALSF2/Q0g==", "cpu": [ "loong64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-mips64el": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.11.tgz", "integrity": "sha512-cGeGNdQxqY8qJwlYH1BP6rjIIiEcrM05H7k3tR7WxOLmD1ZxRMd6/QIOWMb8mD2s2YJFNRuNQ+wjMhgEL2oCEw==", "cpu": [ "mips64el" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-ppc64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.11.tgz", "integrity": "sha512-BdlziJQPW/bNe0E8eYsHB40mYOluS+jULPCjlWiHzDgr+ZBRXPtgMV1nkLEGdpjrwgmtkZHEGEPaKdS/8faLDA==", "cpu": [ "ppc64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-riscv64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.11.tgz", "integrity": "sha512-MDLwQbtF+83oJCI1Cixn68Et/ME6gelmhssPebC40RdJaect+IM+l7o/CuG0ZlDs6tZTEIoxUe53H3GmMn8oMA==", "cpu": [ "riscv64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-s390x": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.11.tgz", "integrity": "sha512-4N5EMESvws0Ozr2J94VoUD8HIRi7X0uvUv4c0wpTHZyZY9qpaaN7THjosdiW56irQ4qnJ6Lsc+i+5zGWnyqWqQ==", "cpu": [ "s390x" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/linux-x64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.11.tgz", "integrity": "sha512-rM/v8UlluxpytFSmVdbCe1yyKQd/e+FmIJE2oPJvbBo+D0XVWi1y/NQ4iTNx+436WmDHQBjVLrbnAQLQ6U7wlw==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/netbsd-x64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.11.tgz", "integrity": "sha512-4WaAhuz5f91h3/g43VBGdto1Q+X7VEZfpcWGtOFXnggEuLvjV+cP6DyLRU15IjiU9fKLLk41OoJfBFN5DhPvag==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "netbsd" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/openbsd-x64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.11.tgz", "integrity": "sha512-UBj135Nx4FpnvtE+C8TWGp98oUgBcmNmdYgl5ToKc0mBHxVVqVE7FUS5/ELMImOp205qDAittL6Ezhasc2Ev/w==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "openbsd" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/sunos-x64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.11.tgz", "integrity": "sha512-1/gxTifDC9aXbV2xOfCbOceh5AlIidUrPsMpivgzo8P8zUtczlq1ncFpeN1ZyQJ9lVs2hILy1PG5KPp+w8QPPg==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "sunos" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/win32-arm64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.11.tgz", "integrity": "sha512-vtSfyx5yRdpiOW9yp6Ax0zyNOv9HjOAw8WaZg3dF5djEHKKm3UnoohftVvIJtRh0Ec7Hso0RIdTqZvPXJ7FdvQ==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "win32" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/win32-ia32": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.11.tgz", "integrity": "sha512-GFPSLEGQr4wHFTiIUJQrnJKZhZjjq4Sphf+mM76nQR6WkQn73vm7IsacmBRPkALfpOCHsopSvLgqdd4iUW2mYw==", "cpu": [ "ia32" ], "dev": true, "optional": true, "os": [ "win32" ], "engines": { "node": ">=12" } }, "node_modules/@esbuild/win32-x64": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.11.tgz", "integrity": "sha512-N9vXqLP3eRL8BqSy8yn4Y98cZI2pZ8fyuHx6lKjiG2WABpT2l01TXdzq5Ma2ZUBzfB7tx5dXVhge8X9u0S70ZQ==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "win32" ], "engines": { "node": ">=12" } }, "node_modules/@eslint/eslintrc": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.0.tgz", "integrity": "sha512-fluIaaV+GyV24CCu/ggiHdV+j4RNh85yQnAYS/G2mZODZgGmmlrgCydjUcV3YvxCm9x8nMAfThsqTni4KiXT4A==", "dev": true, "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/@eslint/js": { "version": "8.35.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.35.0.tgz", "integrity": "sha512-JXdzbRiWclLVoD8sNUjR443VVlYqiYmDVT6rGUEIEHU5YJW0gaVZwV2xgM7D4arkvASqD0IlLUVjHiFuxaftRw==", "dev": true, "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "peer": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "peer": true, "engines": { "node": ">=12.22" }, "funding": { "type": "github", "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true, "peer": true }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", "get-package-type": "^0.1.0", "js-yaml": "^3.13.1", "resolve-from": "^5.0.0" }, "engines": { "node": ">=8" } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, "dependencies": { "sprintf-js": "~1.0.2" } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { "p-locate": "^4.1.0" }, "engines": { "node": ">=8" } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { "p-try": "^2.0.0" }, "engines": { "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { "p-limit": "^2.2.0" }, "engines": { "node": ">=8" } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", "dev": true, "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.17", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" } }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" }, "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" }, "engines": { "node": ">= 8" } }, "node_modules/@size-limit/esbuild": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/@size-limit/esbuild/-/esbuild-7.0.8.tgz", "integrity": "sha512-AzCrxJJThDvHrBNoolebYVgXu46c6HuS3fOxoXr3V0YWNM0qz81z5F3j7RruzboZnls8ZgME4WrH6GM5rB9gtA==", "dev": true, "dependencies": { "esbuild": "^0.14.18", "nanoid": "^3.2.0" }, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" }, "peerDependencies": { "size-limit": "7.0.8" } }, "node_modules/@size-limit/esbuild/node_modules/@esbuild/linux-loong64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz", "integrity": "sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==", "cpu": [ "loong64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/@size-limit/esbuild/node_modules/esbuild": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.54.tgz", "integrity": "sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==", "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" }, "engines": { "node": ">=12" }, "optionalDependencies": { "@esbuild/linux-loong64": "0.14.54", "esbuild-android-64": "0.14.54", "esbuild-android-arm64": "0.14.54", "esbuild-darwin-64": "0.14.54", "esbuild-darwin-arm64": "0.14.54", "esbuild-freebsd-64": "0.14.54", "esbuild-freebsd-arm64": "0.14.54", "esbuild-linux-32": "0.14.54", "esbuild-linux-64": "0.14.54", "esbuild-linux-arm": "0.14.54", "esbuild-linux-arm64": "0.14.54", "esbuild-linux-mips64le": "0.14.54", "esbuild-linux-ppc64le": "0.14.54", "esbuild-linux-riscv64": "0.14.54", "esbuild-linux-s390x": "0.14.54", "esbuild-netbsd-64": "0.14.54", "esbuild-openbsd-64": "0.14.54", "esbuild-sunos-64": "0.14.54", "esbuild-windows-32": "0.14.54", "esbuild-windows-64": "0.14.54", "esbuild-windows-arm64": "0.14.54" } }, "node_modules/@size-limit/file": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/@size-limit/file/-/file-7.0.8.tgz", "integrity": "sha512-1KeFQuMXIXAH/iELqIX7x+YNYDFvzIvmxcp9PrdwEoSNL0dXdaDIo9WE/yz8xvOmUcKaLfqbWkL75DM0k91WHQ==", "dev": true, "dependencies": { "semver": "7.3.5" }, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" }, "peerDependencies": { "size-limit": "7.0.8" } }, "node_modules/@size-limit/preset-small-lib": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/@size-limit/preset-small-lib/-/preset-small-lib-7.0.8.tgz", "integrity": "sha512-CT8nIYA/c2CSD+X4rAUgwqYccQMahJ6rBnaZxvi3YKFdkXIbuGNXHNjHsYaFksgwG9P4UjG/unyO5L73f3zQBw==", "dev": true, "dependencies": { "@size-limit/esbuild": "7.0.8", "@size-limit/file": "7.0.8" }, "peerDependencies": { "size-limit": "7.0.8" } }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", "dev": true }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", "dev": true }, "node_modules/@types/node": { "version": "20.2.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", "integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==", "dev": true }, "node_modules/@types/tap": { "version": "15.0.8", "resolved": "https://registry.npmjs.org/@types/tap/-/tap-15.0.8.tgz", "integrity": "sha512-ZfeoiZlLIaFi4t6wccwbTEicrHREkP0bOq8dZVi/nWvG5F8O7LlS2cSUZBiOW/D4cgWS/p2uhM3lJoyzFAl80w==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/acorn": { "version": "8.8.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true, "bin": { "acorn": "bin/acorn" }, "engines": { "node": ">=0.4.0" } }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "peer": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/acorn-walk": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, "engines": { "node": ">=0.4.0" } }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" }, "funding": { "type": "github", "url": "https://github.com/sponsors/epoberezkin" } }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/ansi-sequence-parser": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.0.tgz", "integrity": "sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==", "dev": true }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" }, "engines": { "node": ">= 8" } }, "node_modules/append-transform": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", "dev": true, "dependencies": { "default-require-extensions": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/archy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, "node_modules/arg": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, "peer": true }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/async-hook-domain": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/async-hook-domain/-/async-hook-domain-2.0.4.tgz", "integrity": "sha512-14LjCmlK1PK8eDtTezR6WX8TMaYNIzBIsd2D1sGoGjgx0BuNMMoSdk7i/drlbtamy0AWv9yv2tkB+ASdmeqFIw==", "dev": true, "engines": { "node": ">=10" } }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "node_modules/benchmark": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", "dev": true, "dependencies": { "lodash": "^4.17.4", "platform": "^1.3.3" } }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/bind-obj-methods": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-3.0.0.tgz", "integrity": "sha512-nLEaaz3/sEzNSyPWRsN9HNsqwk1AUyECtGj+XwGdIi3xABnEqecvXtIJ0wehQXuuER5uZ/5fTs2usONgYjG+iw==", "dev": true, "engines": { "node": ">=10" } }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "dependencies": { "fill-range": "^7.0.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { "version": "4.21.5", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" } ], "dependencies": { "caniuse-lite": "^1.0.30001449", "electron-to-chromium": "^1.4.284", "node-releases": "^2.0.8", "update-browserslist-db": "^1.0.10" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, "node_modules/bytes-iec": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/bytes-iec/-/bytes-iec-3.1.1.tgz", "integrity": "sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA==", "dev": true, "engines": { "node": ">= 0.8" } }, "node_modules/c8": { "version": "7.13.0", "resolved": "https://registry.npmjs.org/c8/-/c8-7.13.0.tgz", "integrity": "sha512-/NL4hQTv1gBL6J6ei80zu3IiTrmePDKXKXOTLpHvcIWZTVYQlDhVWjjWvkhICylE8EwwnMVzDZugCvdx0/DIIA==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@istanbuljs/schema": "^0.1.3", "find-up": "^5.0.0", "foreground-child": "^2.0.0", "istanbul-lib-coverage": "^3.2.0", "istanbul-lib-report": "^3.0.0", "istanbul-reports": "^3.1.4", "rimraf": "^3.0.2", "test-exclude": "^6.0.0", "v8-to-istanbul": "^9.0.0", "yargs": "^16.2.0", "yargs-parser": "^20.2.9" }, "bin": { "c8": "bin/c8.js" }, "engines": { "node": ">=10.12.0" } }, "node_modules/caching-transform": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", "dev": true, "dependencies": { "hasha": "^5.0.0", "make-dir": "^3.0.0", "package-hash": "^4.0.0", "write-file-atomic": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "peer": true, "engines": { "node": ">=6" } }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { "version": "1.0.30001460", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz", "integrity": "sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" } ] }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, "funding": [ { "type": "individual", "url": "https://paulmillr.com/funding/" } ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "engines": { "node": ">= 8.10.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "node_modules/chokidar/node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { "is-glob": "^4.0.1" }, "engines": { "node": ">= 6" } }, "node_modules/ci-job-number": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ci-job-number/-/ci-job-number-1.2.2.tgz", "integrity": "sha512-CLOGsVDrVamzv8sXJGaILUVI6dsuAkouJP/n6t+OxLPeeA4DDby7zn9SB6EUpa1H7oIKoE+rMmkW80zYsFfUjA==", "dev": true }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^7.0.0" } }, "node_modules/clock-mock": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/clock-mock/-/clock-mock-1.1.0.tgz", "integrity": "sha512-YL1fqZqrdZ9jHzBvwcuG2oFdfJ4Mkh4H8t+ue3ZIdKmWUWkkUMMNUnZ1akLyfC1rFwdVt0lVE0llDh742K0fcg==", "dev": true, "engines": { "node": ">= 12" } }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { "color-name": "~1.1.4" }, "engines": { "node": ">=7.0.0" } }, "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true, "bin": { "color-support": "bin.js" } }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", "dev": true }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "node_modules/convert-source-map": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" }, "engines": { "node": ">= 8" } }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "peer": true }, "node_modules/default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", "dev": true, "dependencies": { "strip-bom": "^4.0.0" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, "engines": { "node": ">=0.3.1" } }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, "dependencies": { "path-type": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, "peer": true, "dependencies": { "esutils": "^2.0.2" }, "engines": { "node": ">=6.0.0" } }, "node_modules/electron-to-chromium": { "version": "1.4.320", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.320.tgz", "integrity": "sha512-h70iRscrNluMZPVICXYl5SSB+rBKo22XfuIS1ER0OQxQZpKTnFpuS6coj7wY9M/3trv7OR88rRMOlKmRvDty7Q==", "dev": true }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "node_modules/es6-error": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, "node_modules/esbuild": { "version": "0.17.11", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.11.tgz", "integrity": "sha512-pAMImyokbWDtnA/ufPxjQg0fYo2DDuzAlqwnDvbXqHLphe+m80eF++perYKVm8LeTuj2zUuFXC+xgSVxyoHUdg==", "dev": true, "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" }, "engines": { "node": ">=12" }, "optionalDependencies": { "@esbuild/android-arm": "0.17.11", "@esbuild/android-arm64": "0.17.11", "@esbuild/android-x64": "0.17.11", "@esbuild/darwin-arm64": "0.17.11", "@esbuild/darwin-x64": "0.17.11", "@esbuild/freebsd-arm64": "0.17.11", "@esbuild/freebsd-x64": "0.17.11", "@esbuild/linux-arm": "0.17.11", "@esbuild/linux-arm64": "0.17.11", "@esbuild/linux-ia32": "0.17.11", "@esbuild/linux-loong64": "0.17.11", "@esbuild/linux-mips64el": "0.17.11", "@esbuild/linux-ppc64": "0.17.11", "@esbuild/linux-riscv64": "0.17.11", "@esbuild/linux-s390x": "0.17.11", "@esbuild/linux-x64": "0.17.11", "@esbuild/netbsd-x64": "0.17.11", "@esbuild/openbsd-x64": "0.17.11", "@esbuild/sunos-x64": "0.17.11", "@esbuild/win32-arm64": "0.17.11", "@esbuild/win32-ia32": "0.17.11", "@esbuild/win32-x64": "0.17.11" } }, "node_modules/esbuild-android-64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz", "integrity": "sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "android" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-android-arm64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz", "integrity": "sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "android" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-darwin-64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz", "integrity": "sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "darwin" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-darwin-arm64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz", "integrity": "sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "darwin" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-freebsd-64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz", "integrity": "sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "freebsd" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-freebsd-arm64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz", "integrity": "sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "freebsd" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-linux-32": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz", "integrity": "sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==", "cpu": [ "ia32" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-linux-64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz", "integrity": "sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-linux-arm": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz", "integrity": "sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==", "cpu": [ "arm" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-linux-arm64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz", "integrity": "sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-linux-mips64le": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz", "integrity": "sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==", "cpu": [ "mips64el" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-linux-ppc64le": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz", "integrity": "sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==", "cpu": [ "ppc64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-linux-riscv64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz", "integrity": "sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==", "cpu": [ "riscv64" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-linux-s390x": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz", "integrity": "sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==", "cpu": [ "s390x" ], "dev": true, "optional": true, "os": [ "linux" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-netbsd-64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz", "integrity": "sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "netbsd" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-openbsd-64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz", "integrity": "sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "openbsd" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-sunos-64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz", "integrity": "sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "sunos" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-windows-32": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz", "integrity": "sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==", "cpu": [ "ia32" ], "dev": true, "optional": true, "os": [ "win32" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-windows-64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz", "integrity": "sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==", "cpu": [ "x64" ], "dev": true, "optional": true, "os": [ "win32" ], "engines": { "node": ">=12" } }, "node_modules/esbuild-windows-arm64": { "version": "0.14.54", "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz", "integrity": "sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==", "cpu": [ "arm64" ], "dev": true, "optional": true, "os": [ "win32" ], "engines": { "node": ">=12" } }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "peer": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { "version": "8.35.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz", "integrity": "sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==", "dev": true, "peer": true, "dependencies": { "@eslint/eslintrc": "^2.0.0", "@eslint/js": "8.35.0", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", "espree": "^9.4.0", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-config-prettier": { "version": "8.6.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, "peerDependencies": { "eslint": ">=7.0.0" } }, "node_modules/eslint-scope": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/eslint-utils": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "peer": true, "dependencies": { "eslint-visitor-keys": "^2.0.0" }, "engines": { "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" }, "funding": { "url": "https://github.com/sponsors/mysticatea" }, "peerDependencies": { "eslint": ">=5" } }, "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, "peer": true, "engines": { "node": ">=10" } }, "node_modules/eslint-visitor-keys": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, "peer": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/espree": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", "dev": true, "peer": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" }, "engines": { "node": ">=4" } }, "node_modules/esquery": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, "peer": true, "dependencies": { "estraverse": "^5.1.0" }, "engines": { "node": ">=0.10" } }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "peer": true, "dependencies": { "estraverse": "^5.2.0" }, "engines": { "node": ">=4.0" } }, "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "peer": true, "engines": { "node": ">=4.0" } }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "peer": true, "engines": { "node": ">=0.10.0" } }, "node_modules/events-to-array": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", "integrity": "sha512-inRWzRY7nG+aXZxBzEqYKB3HPgwflZRopAjDCHv0whhRx+MTUr1ei0ICZUypdyE0HRm4L2d5VEcIqLD6yl+BFA==", "dev": true }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, "peer": true }, "node_modules/fast-glob": { "version": "3.2.12", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" }, "engines": { "node": ">=8.6.0" } }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { "is-glob": "^4.0.1" }, "engines": { "node": ">= 6" } }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, "peer": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, "peer": true }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", "dev": true, "dependencies": { "reusify": "^1.0.4" } }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "peer": true, "dependencies": { "flat-cache": "^3.0.4" }, "engines": { "node": "^10.12.0 || >=12.0.0" } }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/find-cache-dir": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "dev": true, "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/findit": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/findit/-/findit-2.0.0.tgz", "integrity": "sha512-ENZS237/Hr8bjczn5eKuBohLgaD0JyUd0arxretR1f9RO46vZHA1b2y0VorgGV3WaOT3c+78P8h7v4JGJ1i/rg==", "dev": true }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "peer": true, "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" }, "engines": { "node": "^10.12.0 || >=12.0.0" } }, "node_modules/flatted": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true, "peer": true }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^3.0.2" }, "engines": { "node": ">=8.0.0" } }, "node_modules/fromentries": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/feross" }, { "type": "patreon", "url": "https://www.patreon.com/feross" }, { "type": "consulting", "url": "https://feross.org/support" } ] }, "node_modules/fs-exists-cached": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz", "integrity": "sha512-kSxoARUDn4F2RPXX48UXnaFKwVU7Ivd/6qpzZL29MCDmr9sTvybv4gFCp+qaI4fM9m0z9fgz/yJvi56GAz+BZg==", "dev": true }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, "node_modules/fsevents": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, "optional": true, "os": [ "darwin" ], "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/function-loop": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-2.0.1.tgz", "integrity": "sha512-ktIR+O6i/4h+j/ZhZJNdzeI4i9lEPeEK6UPR2EVyTVBqOwcU3Za9xYKLH64ZR9HmcROyRrOkizNyjjtWJzDDkQ==", "dev": true }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, "engines": { "node": ">=8.0.0" } }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, "engines": { "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "peer": true, "dependencies": { "is-glob": "^4.0.3" }, "engines": { "node": ">=10.13.0" } }, "node_modules/globals": { "version": "13.20.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "peer": true, "dependencies": { "type-fest": "^0.20.2" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "node_modules/grapheme-splitter": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true, "peer": true }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", "dev": true, "dependencies": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/hasha/node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" } }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "peer": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" }, "engines": { "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "engines": { "node": ">=0.8.19" } }, "node_modules/indent-string": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, "engines": { "node": ">=8" } }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, "engines": { "node": ">=0.10.0" } }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "engines": { "node": ">=0.12.0" } }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, "peer": true, "engines": { "node": ">=8" } }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-hook": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", "dev": true, "dependencies": { "append-transform": "^2.0.0" }, "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", "dev": true, "dependencies": { "@babel/core": "^7.7.5", "@istanbuljs/schema": "^0.1.2", "istanbul-lib-coverage": "^3.0.0", "semver": "^6.3.0" }, "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/istanbul-lib-processinfo": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", "dev": true, "dependencies": { "archy": "^1.0.0", "cross-spawn": "^7.0.3", "istanbul-lib-coverage": "^3.2.0", "p-map": "^3.0.0", "rimraf": "^3.0.0", "uuid": "^8.3.2" }, "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-report": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", "supports-color": "^7.1.0" }, "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", "source-map": "^0.6.1" }, "engines": { "node": ">=10" } }, "node_modules/istanbul-reports": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/jackspeak": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-1.4.2.tgz", "integrity": "sha512-GHeGTmnuaHnvS+ZctRB01bfxARuu9wW83ENbuiweu07SFcVlZrJpcshSre/keGT7YGBhLHg/+rXCNSrsEHKU4Q==", "dev": true, "dependencies": { "cliui": "^7.0.4" }, "engines": { "node": ">=8" } }, "node_modules/js-sdsl": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz", "integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==", "dev": true, "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/js-sdsl" } }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "peer": true, "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, "bin": { "jsesc": "bin/jsesc" }, "engines": { "node": ">=4" } }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "peer": true }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, "peer": true }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" }, "engines": { "node": ">=6" } }, "node_modules/jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "peer": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/libtap": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/libtap/-/libtap-1.4.0.tgz", "integrity": "sha512-STLFynswQ2A6W14JkabgGetBNk6INL1REgJ9UeNKw5llXroC2cGLgKTqavv0sl8OLVztLLipVKMcQ7yeUcqpmg==", "dev": true, "dependencies": { "async-hook-domain": "^2.0.4", "bind-obj-methods": "^3.0.0", "diff": "^4.0.2", "function-loop": "^2.0.1", "minipass": "^3.1.5", "own-or": "^1.0.0", "own-or-env": "^1.0.2", "signal-exit": "^3.0.4", "stack-utils": "^2.0.4", "tap-parser": "^11.0.0", "tap-yaml": "^1.0.0", "tcompare": "^5.0.6", "trivial-deferred": "^1.0.1" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true, "engines": { "node": ">=10" } }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { "p-locate": "^5.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "node_modules/lodash.flattendeep": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, "peer": true }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { "yallist": "^4.0.0" }, "engines": { "node": ">=10" } }, "node_modules/lunr": { "version": "2.3.9", "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", "dev": true }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, "dependencies": { "semver": "^6.0.0" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/make-dir/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, "node_modules/marked": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "dev": true, "bin": { "marked": "bin/marked.js" }, "engines": { "node": ">= 12" } }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, "engines": { "node": ">= 8" } }, "node_modules/micromatch": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, "engines": { "node": "*" } }, "node_modules/minipass": { "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { "yallist": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/mkdirp": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.5.tgz", "integrity": "sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w==", "dev": true, "bin": { "mkdirp": "dist/cjs/src/bin.js" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "node_modules/nanoid": { "version": "3.3.4", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" }, "engines": { "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/nanospinner": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/nanospinner/-/nanospinner-1.1.0.tgz", "integrity": "sha512-yFvNYMig4AthKYfHFl1sLj7B2nkHL4lzdig4osvl9/LdGbXwrdFRoqBS98gsEsOakr0yH+r5NZ/1Y9gdVB8trA==", "dev": true, "dependencies": { "picocolors": "^1.0.0" } }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, "peer": true }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", "dev": true, "dependencies": { "process-on-spawn": "^1.0.0" }, "engines": { "node": ">=8" } }, "node_modules/node-releases": { "version": "2.0.10", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", "dev": true }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/nyc": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", "dev": true, "dependencies": { "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", "caching-transform": "^4.0.0", "convert-source-map": "^1.7.0", "decamelize": "^1.2.0", "find-cache-dir": "^3.2.0", "find-up": "^4.1.0", "foreground-child": "^2.0.0", "get-package-type": "^0.1.0", "glob": "^7.1.6", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-hook": "^3.0.0", "istanbul-lib-instrument": "^4.0.0", "istanbul-lib-processinfo": "^2.0.2", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", "make-dir": "^3.0.0", "node-preload": "^0.2.1", "p-map": "^3.0.0", "process-on-spawn": "^1.0.0", "resolve-from": "^5.0.0", "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "spawn-wrap": "^2.0.0", "test-exclude": "^6.0.0", "yargs": "^15.0.2" }, "bin": { "nyc": "bin/nyc.js" }, "engines": { "node": ">=8.9" } }, "node_modules/nyc/node_modules/cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, "node_modules/nyc/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/nyc/node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { "p-locate": "^4.1.0" }, "engines": { "node": ">=8" } }, "node_modules/nyc/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { "p-try": "^2.0.0" }, "engines": { "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/nyc/node_modules/p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { "p-limit": "^2.2.0" }, "engines": { "node": ">=8" } }, "node_modules/nyc/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/nyc/node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, "engines": { "node": ">=8" } }, "node_modules/nyc/node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "node_modules/nyc/node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" }, "engines": { "node": ">=8" } }, "node_modules/nyc/node_modules/yargs-parser": { "version": "18.1.3", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" }, "engines": { "node": ">=6" } }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "dependencies": { "wrappy": "1" } }, "node_modules/opener": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", "dev": true, "bin": { "opener": "bin/opener-bin.js" } }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "peer": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.3" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/own-or": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz", "integrity": "sha512-NfZr5+Tdf6MB8UI9GLvKRs4cXY8/yB0w3xtt84xFdWy8hkGjn+JFc60VhzS/hFRfbyxFcGYMTjnF4Me+RbbqrA==", "dev": true }, "node_modules/own-or-env": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.2.tgz", "integrity": "sha512-NQ7v0fliWtK7Lkb+WdFqe6ky9XAzYmlkXthQrBbzlYbmFKoAYbDDcwmOm6q8kOuwSRXW8bdL5ORksploUJmWgw==", "dev": true, "dependencies": { "own-or": "^1.0.0" } }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { "p-limit": "^3.0.2" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-map": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", "dev": true, "dependencies": { "aggregate-error": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/package-hash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", "dev": true, "dependencies": { "graceful-fs": "^4.1.15", "hasha": "^5.0.0", "lodash.flattendeep": "^4.4.0", "release-zalgo": "^1.0.0" }, "engines": { "node": ">=8" } }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "peer": true, "dependencies": { "callsites": "^3.0.0" }, "engines": { "node": ">=6" } }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/pkg-dir": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "dependencies": { "find-up": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/pkg-dir/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/pkg-dir/node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "dependencies": { "p-locate": "^4.1.0" }, "engines": { "node": ">=8" } }, "node_modules/pkg-dir/node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "dependencies": { "p-try": "^2.0.0" }, "engines": { "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pkg-dir/node_modules/p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { "p-limit": "^2.2.0" }, "engines": { "node": ">=8" } }, "node_modules/platform": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", "dev": true }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "peer": true, "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { "version": "2.8.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "dev": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { "node": ">=10.13.0" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", "dev": true, "dependencies": { "fromentries": "^1.2.0" }, "engines": { "node": ">=8" } }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/feross" }, { "type": "patreon", "url": "https://www.patreon.com/feross" }, { "type": "consulting", "url": "https://feross.org/support" } ] }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "dependencies": { "picomatch": "^2.2.1" }, "engines": { "node": ">=8.10.0" } }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, "peer": true, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/mysticatea" } }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", "dev": true, "dependencies": { "es6-error": "^4.0.1" }, "engines": { "node": ">=4" } }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "peer": true, "engines": { "node": ">=4" } }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/feross" }, { "type": "patreon", "url": "https://www.patreon.com/feross" }, { "type": "consulting", "url": "https://feross.org/support" } ], "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, "bin": { "semver": "bin/semver.js" }, "engines": { "node": ">=10" } }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/shiki": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.1.tgz", "integrity": "sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw==", "dev": true, "dependencies": { "ansi-sequence-parser": "^1.1.0", "jsonc-parser": "^3.2.0", "vscode-oniguruma": "^1.7.0", "vscode-textmate": "^8.0.0" } }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, "node_modules/size-limit": { "version": "7.0.8", "resolved": "https://registry.npmjs.org/size-limit/-/size-limit-7.0.8.tgz", "integrity": "sha512-3h76c9E0e/nNhYLSR7IBI/bSoXICeo7EYkYjlyVqNIsu7KvN/PQmMbIXeyd2QKIF8iZKhaiZQoXLkGWbyPDtvQ==", "dev": true, "dependencies": { "bytes-iec": "^3.1.1", "chokidar": "^3.5.3", "ci-job-number": "^1.2.2", "globby": "^11.1.0", "lilconfig": "^2.0.4", "mkdirp": "^1.0.4", "nanospinner": "^1.0.0", "picocolors": "^1.0.0" }, "bin": { "size-limit": "bin.js" }, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/size-limit/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, "bin": { "mkdirp": "bin/cmd.js" }, "engines": { "node": ">=10" } }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "node_modules/spawn-wrap": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", "dev": true, "dependencies": { "foreground-child": "^2.0.0", "is-windows": "^1.0.2", "make-dir": "^3.0.0", "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "which": "^2.0.1" }, "engines": { "node": ">=8" } }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, "dependencies": { "escape-string-regexp": "^2.0.0" }, "engines": { "node": ">=10" } }, "node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "peer": true, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tap": { "version": "16.3.4", "resolved": "https://registry.npmjs.org/tap/-/tap-16.3.4.tgz", "integrity": "sha512-SAexdt2ZF4XBgye6TPucFI2y7VE0qeFXlXucJIV1XDPCs+iJodk0MYacr1zR6Ycltzz7PYg8zrblDXKbAZM2LQ==", "bundleDependencies": [ "ink", "treport", "@types/react", "@isaacs/import-jsx", "react" ], "dev": true, "dependencies": { "@isaacs/import-jsx": "^4.0.1", "@types/react": "^17.0.52", "chokidar": "^3.3.0", "findit": "^2.0.0", "foreground-child": "^2.0.0", "fs-exists-cached": "^1.0.0", "glob": "^7.2.3", "ink": "^3.2.0", "isexe": "^2.0.0", "istanbul-lib-processinfo": "^2.0.3", "jackspeak": "^1.4.2", "libtap": "^1.4.0", "minipass": "^3.3.4", "mkdirp": "^1.0.4", "nyc": "^15.1.0", "opener": "^1.5.1", "react": "^17.0.2", "rimraf": "^3.0.0", "signal-exit": "^3.0.6", "source-map-support": "^0.5.16", "tap-mocha-reporter": "^5.0.3", "tap-parser": "^11.0.2", "tap-yaml": "^1.0.2", "tcompare": "^5.0.7", "treport": "^3.0.4", "which": "^2.0.2" }, "bin": { "tap": "bin/run.js" }, "engines": { "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/isaacs" }, "peerDependencies": { "coveralls": "^3.1.1", "flow-remove-types": ">=2.112.0", "ts-node": ">=8.5.2", "typescript": ">=3.7.2" }, "peerDependenciesMeta": { "coveralls": { "optional": true }, "flow-remove-types": { "optional": true }, "ts-node": { "optional": true }, "typescript": { "optional": true } } }, "node_modules/tap-mocha-reporter": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-5.0.3.tgz", "integrity": "sha512-6zlGkaV4J+XMRFkN0X+yuw6xHbE9jyCZ3WUKfw4KxMyRGOpYSRuuQTRJyWX88WWuLdVTuFbxzwXhXuS2XE6o0g==", "dev": true, "dependencies": { "color-support": "^1.1.0", "debug": "^4.1.1", "diff": "^4.0.1", "escape-string-regexp": "^2.0.0", "glob": "^7.0.5", "tap-parser": "^11.0.0", "tap-yaml": "^1.0.0", "unicode-length": "^2.0.2" }, "bin": { "tap-mocha-reporter": "index.js" }, "engines": { "node": ">= 8" } }, "node_modules/tap-mocha-reporter/node_modules/escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/tap-parser": { "version": "11.0.2", "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-11.0.2.tgz", "integrity": "sha512-6qGlC956rcORw+fg7Fv1iCRAY8/bU9UabUAhs3mXRH6eRmVZcNPLheSXCYaVaYeSwx5xa/1HXZb1537YSvwDZg==", "dev": true, "dependencies": { "events-to-array": "^1.0.1", "minipass": "^3.1.6", "tap-yaml": "^1.0.0" }, "bin": { "tap-parser": "bin/cmd.js" }, "engines": { "node": ">= 8" } }, "node_modules/tap-yaml": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tap-yaml/-/tap-yaml-1.0.2.tgz", "integrity": "sha512-GegASpuqBnRNdT1U+yuUPZ8rEU64pL35WPBpCISWwff4dErS2/438barz7WFJl4Nzh3Y05tfPidZnH+GaV1wMg==", "dev": true, "dependencies": { "yaml": "^1.10.2" } }, "node_modules/tap/node_modules/@ampproject/remapping": { "version": "2.1.2", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/trace-mapping": "^0.3.0" }, "engines": { "node": ">=6.0.0" } }, "node_modules/tap/node_modules/@babel/code-frame": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/highlight": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/compat-data": { "version": "7.17.7", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/core": { "version": "7.17.8", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.17.7", "@babel/helper-compilation-targets": "^7.17.7", "@babel/helper-module-transforms": "^7.17.7", "@babel/helpers": "^7.17.8", "@babel/parser": "^7.17.8", "@babel/template": "^7.16.7", "@babel/traverse": "^7.17.3", "@babel/types": "^7.17.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/babel" } }, "node_modules/tap/node_modules/@babel/generator": { "version": "7.17.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/types": "^7.17.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-annotate-as-pure": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-compilation-targets": { "version": "7.17.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.17.7", "@babel/helper-validator-option": "^7.16.7", "browserslist": "^4.17.5", "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/tap/node_modules/@babel/helper-environment-visitor": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-function-name": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-get-function-arity": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-hoist-variables": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-module-imports": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-module-transforms": { "version": "7.17.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", "@babel/helper-simple-access": "^7.17.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", "@babel/traverse": "^7.17.3", "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-plugin-utils": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-simple-access": { "version": "7.17.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-split-export-declaration": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-validator-identifier": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helper-validator-option": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/helpers": { "version": "7.17.8", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/template": "^7.16.7", "@babel/traverse": "^7.17.3", "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/highlight": { "version": "7.16.10", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/parser": { "version": "7.17.8", "dev": true, "inBundle": true, "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, "engines": { "node": ">=6.0.0" } }, "node_modules/tap/node_modules/@babel/plugin-proposal-object-rest-spread": { "version": "7.17.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.17.0", "@babel/helper-compilation-targets": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-transform-parameters": "^7.16.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/tap/node_modules/@babel/plugin-syntax-jsx": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/tap/node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/tap/node_modules/@babel/plugin-transform-destructuring": { "version": "7.17.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/tap/node_modules/@babel/plugin-transform-parameters": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/tap/node_modules/@babel/plugin-transform-react-jsx": { "version": "7.17.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7", "@babel/plugin-syntax-jsx": "^7.16.7", "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" }, "peerDependencies": { "@babel/core": "^7.0.0-0" } }, "node_modules/tap/node_modules/@babel/template": { "version": "7.16.7", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/parser": "^7.16.7", "@babel/types": "^7.16.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/traverse": { "version": "7.17.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.16.7", "@babel/generator": "^7.17.3", "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-function-name": "^7.16.7", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/parser": "^7.17.3", "@babel/types": "^7.17.0", "debug": "^4.1.0", "globals": "^11.1.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@babel/types": { "version": "7.17.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/@isaacs/import-jsx": { "version": "4.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@babel/core": "^7.5.5", "@babel/plugin-proposal-object-rest-spread": "^7.5.5", "@babel/plugin-transform-destructuring": "^7.5.0", "@babel/plugin-transform-react-jsx": "^7.3.0", "caller-path": "^3.0.1", "find-cache-dir": "^3.2.0", "make-dir": "^3.0.2", "resolve-from": "^3.0.0", "rimraf": "^3.0.0" }, "engines": { "node": ">=10" } }, "node_modules/tap/node_modules/@jridgewell/resolve-uri": { "version": "3.0.5", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/tap/node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.11", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/@jridgewell/trace-mapping": { "version": "0.3.4", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/tap/node_modules/@types/prop-types": { "version": "15.7.4", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/@types/react": { "version": "17.0.52", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/tap/node_modules/@types/scheduler": { "version": "0.16.2", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/@types/yoga-layout": { "version": "1.9.2", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/ansi-escapes": { "version": "4.3.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tap/node_modules/ansi-escapes/node_modules/type-fest": { "version": "0.21.3", "dev": true, "inBundle": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tap/node_modules/ansi-regex": { "version": "5.0.1", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/ansi-styles": { "version": "3.2.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, "engines": { "node": ">=4" } }, "node_modules/tap/node_modules/ansicolors": { "version": "0.3.2", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/astral-regex": { "version": "2.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/auto-bind": { "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tap/node_modules/balanced-match": { "version": "1.0.2", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/brace-expansion": { "version": "1.1.11", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/tap/node_modules/browserslist": { "version": "4.20.2", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" } ], "inBundle": true, "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001317", "electron-to-chromium": "^1.4.84", "escalade": "^3.1.1", "node-releases": "^2.0.2", "picocolors": "^1.0.0" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, "node_modules/tap/node_modules/caller-callsite": { "version": "4.1.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "callsites": "^3.1.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/caller-path": { "version": "3.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "caller-callsite": "^4.1.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/callsites": { "version": "3.1.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/tap/node_modules/caniuse-lite": { "version": "1.0.30001319", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" } ], "inBundle": true, "license": "CC-BY-4.0" }, "node_modules/tap/node_modules/cardinal": { "version": "2.1.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ansicolors": "~0.3.2", "redeyed": "~2.1.0" }, "bin": { "cdl": "bin/cdl.js" } }, "node_modules/tap/node_modules/chalk": { "version": "2.4.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" }, "engines": { "node": ">=4" } }, "node_modules/tap/node_modules/ci-info": { "version": "2.0.0", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/cli-boxes": { "version": "2.2.1", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tap/node_modules/cli-cursor": { "version": "3.1.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/cli-truncate": { "version": "2.1.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tap/node_modules/code-excerpt": { "version": "3.0.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "convert-to-spaces": "^1.0.1" }, "engines": { "node": ">=10" } }, "node_modules/tap/node_modules/color-convert": { "version": "1.9.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-name": "1.1.3" } }, "node_modules/tap/node_modules/color-name": { "version": "1.1.3", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/commondir": { "version": "1.0.1", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/concat-map": { "version": "0.0.1", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/convert-source-map": { "version": "1.8.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "safe-buffer": "~5.1.1" } }, "node_modules/tap/node_modules/convert-to-spaces": { "version": "1.0.2", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/tap/node_modules/csstype": { "version": "3.0.11", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/debug": { "version": "4.3.4", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ms": "2.1.2" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/tap/node_modules/electron-to-chromium": { "version": "1.4.89", "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/tap/node_modules/emoji-regex": { "version": "8.0.0", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/escalade": { "version": "3.1.1", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/tap/node_modules/escape-string-regexp": { "version": "1.0.5", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/tap/node_modules/esprima": { "version": "4.0.1", "dev": true, "inBundle": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" }, "engines": { "node": ">=4" } }, "node_modules/tap/node_modules/events-to-array": { "version": "1.1.2", "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/tap/node_modules/find-cache-dir": { "version": "3.3.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", "pkg-dir": "^4.1.0" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, "node_modules/tap/node_modules/find-up": { "version": "4.1.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/fs.realpath": { "version": "1.0.0", "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/tap/node_modules/gensync": { "version": "1.0.0-beta.2", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/tap/node_modules/glob": { "version": "7.2.3", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, "engines": { "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/tap/node_modules/globals": { "version": "11.12.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/tap/node_modules/has-flag": { "version": "3.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/tap/node_modules/indent-string": { "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/inflight": { "version": "1.0.6", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "node_modules/tap/node_modules/inherits": { "version": "2.0.4", "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/tap/node_modules/ink": { "version": "3.2.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "auto-bind": "4.0.0", "chalk": "^4.1.0", "cli-boxes": "^2.2.0", "cli-cursor": "^3.1.0", "cli-truncate": "^2.1.0", "code-excerpt": "^3.0.0", "indent-string": "^4.0.0", "is-ci": "^2.0.0", "lodash": "^4.17.20", "patch-console": "^1.0.0", "react-devtools-core": "^4.19.1", "react-reconciler": "^0.26.2", "scheduler": "^0.20.2", "signal-exit": "^3.0.2", "slice-ansi": "^3.0.0", "stack-utils": "^2.0.2", "string-width": "^4.2.2", "type-fest": "^0.12.0", "widest-line": "^3.1.0", "wrap-ansi": "^6.2.0", "ws": "^7.5.5", "yoga-layout-prebuilt": "^1.9.6" }, "engines": { "node": ">=10" }, "peerDependencies": { "@types/react": ">=16.8.0", "react": ">=16.8.0" }, "peerDependenciesMeta": { "@types/react": { "optional": true } } }, "node_modules/tap/node_modules/ink/node_modules/ansi-styles": { "version": "4.3.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/tap/node_modules/ink/node_modules/chalk": { "version": "4.1.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/tap/node_modules/ink/node_modules/color-convert": { "version": "2.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, "engines": { "node": ">=7.0.0" } }, "node_modules/tap/node_modules/ink/node_modules/color-name": { "version": "1.1.4", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/ink/node_modules/has-flag": { "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/ink/node_modules/supports-color": { "version": "7.2.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/is-ci": { "version": "2.0.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ci-info": "^2.0.0" }, "bin": { "is-ci": "bin.js" } }, "node_modules/tap/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/js-tokens": { "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/jsesc": { "version": "2.5.2", "dev": true, "inBundle": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, "engines": { "node": ">=4" } }, "node_modules/tap/node_modules/json5": { "version": "2.2.3", "dev": true, "inBundle": true, "license": "MIT", "bin": { "json5": "lib/cli.js" }, "engines": { "node": ">=6" } }, "node_modules/tap/node_modules/locate-path": { "version": "5.0.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/lodash": { "version": "4.17.21", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/loose-envify": { "version": "1.4.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "node_modules/tap/node_modules/make-dir": { "version": "3.1.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "semver": "^6.0.0" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tap/node_modules/mimic-fn": { "version": "2.1.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/tap/node_modules/minimatch": { "version": "3.1.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, "engines": { "node": "*" } }, "node_modules/tap/node_modules/minipass": { "version": "3.3.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, "bin": { "mkdirp": "bin/cmd.js" }, "engines": { "node": ">=10" } }, "node_modules/tap/node_modules/ms": { "version": "2.1.2", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/node-releases": { "version": "2.0.2", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/object-assign": { "version": "4.1.1", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/tap/node_modules/once": { "version": "1.4.0", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/tap/node_modules/onetime": { "version": "5.1.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, "engines": { "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tap/node_modules/p-limit": { "version": "2.3.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, "engines": { "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tap/node_modules/p-locate": { "version": "4.1.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/p-try": { "version": "2.2.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/tap/node_modules/patch-console": { "version": "1.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/tap/node_modules/path-exists": { "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/path-is-absolute": { "version": "1.0.1", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/tap/node_modules/picocolors": { "version": "1.0.0", "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/tap/node_modules/pkg-dir": { "version": "4.2.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/punycode": { "version": "2.1.1", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/tap/node_modules/react": { "version": "17.0.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" }, "engines": { "node": ">=0.10.0" } }, "node_modules/tap/node_modules/react-devtools-core": { "version": "4.24.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" } }, "node_modules/tap/node_modules/react-reconciler": { "version": "0.26.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1", "scheduler": "^0.20.2" }, "engines": { "node": ">=0.10.0" }, "peerDependencies": { "react": "^17.0.2" } }, "node_modules/tap/node_modules/redeyed": { "version": "2.1.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "esprima": "~4.0.0" } }, "node_modules/tap/node_modules/resolve-from": { "version": "3.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/tap/node_modules/restore-cursor": { "version": "3.1.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/rimraf": { "version": "3.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/tap/node_modules/safe-buffer": { "version": "5.1.2", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/scheduler": { "version": "0.20.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", "object-assign": "^4.1.1" } }, "node_modules/tap/node_modules/semver": { "version": "6.3.0", "dev": true, "inBundle": true, "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/tap/node_modules/shell-quote": { "version": "1.7.3", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/signal-exit": { "version": "3.0.7", "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/tap/node_modules/slice-ansi": { "version": "3.0.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", "is-fullwidth-code-point": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/slice-ansi/node_modules/ansi-styles": { "version": "4.3.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/tap/node_modules/slice-ansi/node_modules/color-convert": { "version": "2.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, "engines": { "node": ">=7.0.0" } }, "node_modules/tap/node_modules/slice-ansi/node_modules/color-name": { "version": "1.1.4", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/source-map": { "version": "0.5.7", "dev": true, "inBundle": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/tap/node_modules/stack-utils": { "version": "2.0.5", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, "engines": { "node": ">=10" } }, "node_modules/tap/node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/string-width": { "version": "4.2.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/strip-ansi": { "version": "6.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/supports-color": { "version": "5.5.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, "engines": { "node": ">=4" } }, "node_modules/tap/node_modules/tap-parser": { "version": "11.0.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "events-to-array": "^1.0.1", "minipass": "^3.1.6", "tap-yaml": "^1.0.0" }, "bin": { "tap-parser": "bin/cmd.js" }, "engines": { "node": ">= 8" } }, "node_modules/tap/node_modules/tap-yaml": { "version": "1.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "yaml": "^1.10.2" } }, "node_modules/tap/node_modules/to-fast-properties": { "version": "2.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/tap/node_modules/treport": { "version": "3.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@isaacs/import-jsx": "^4.0.1", "cardinal": "^2.1.1", "chalk": "^3.0.0", "ink": "^3.2.0", "ms": "^2.1.2", "tap-parser": "^11.0.0", "tap-yaml": "^1.0.0", "unicode-length": "^2.0.2" }, "peerDependencies": { "react": "^17.0.2" } }, "node_modules/tap/node_modules/treport/node_modules/ansi-styles": { "version": "4.3.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/tap/node_modules/treport/node_modules/chalk": { "version": "3.0.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/treport/node_modules/color-convert": { "version": "2.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, "engines": { "node": ">=7.0.0" } }, "node_modules/tap/node_modules/treport/node_modules/color-name": { "version": "1.1.4", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/treport/node_modules/has-flag": { "version": "4.0.0", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/treport/node_modules/supports-color": { "version": "7.2.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/type-fest": { "version": "0.12.0", "dev": true, "inBundle": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/tap/node_modules/unicode-length": { "version": "2.0.2", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "punycode": "^2.0.0", "strip-ansi": "^3.0.1" } }, "node_modules/tap/node_modules/unicode-length/node_modules/ansi-regex": { "version": "2.1.1", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/tap/node_modules/unicode-length/node_modules/strip-ansi": { "version": "3.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ansi-regex": "^2.0.0" }, "engines": { "node": ">=0.10.0" } }, "node_modules/tap/node_modules/widest-line": { "version": "3.1.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "string-width": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/wrap-ansi": { "version": "6.2.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tap/node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/tap/node_modules/wrap-ansi/node_modules/color-convert": { "version": "2.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, "engines": { "node": ">=7.0.0" } }, "node_modules/tap/node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/tap/node_modules/wrappy": { "version": "1.0.2", "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/tap/node_modules/ws": { "version": "7.5.7", "dev": true, "inBundle": true, "license": "MIT", "engines": { "node": ">=8.3.0" }, "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "peerDependenciesMeta": { "bufferutil": { "optional": true }, "utf-8-validate": { "optional": true } } }, "node_modules/tap/node_modules/yallist": { "version": "4.0.0", "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/tap/node_modules/yaml": { "version": "1.10.2", "dev": true, "inBundle": true, "license": "ISC", "engines": { "node": ">= 6" } }, "node_modules/tap/node_modules/yoga-layout-prebuilt": { "version": "1.10.0", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { "@types/yoga-layout": "1.9.2" }, "engines": { "node": ">=8" } }, "node_modules/tcompare": { "version": "5.0.7", "resolved": "https://registry.npmjs.org/tcompare/-/tcompare-5.0.7.tgz", "integrity": "sha512-d9iddt6YYGgyxJw5bjsN7UJUO1kGOtjSlNy/4PoGYAjQS5pAT/hzIoLf1bZCw+uUxRmZJh7Yy1aA7xKVRT9B4w==", "dev": true, "dependencies": { "diff": "^4.0.2" }, "engines": { "node": ">=10" } }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", "minimatch": "^3.0.4" }, "engines": { "node": ">=8" } }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, "peer": true }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, "engines": { "node": ">=4" } }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "dependencies": { "is-number": "^7.0.0" }, "engines": { "node": ">=8.0" } }, "node_modules/trivial-deferred": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.0.1.tgz", "integrity": "sha512-dagAKX7vaesNNAwOc9Np9C2mJ+7YopF4lk+jE2JML9ta4kZ91Y6UruJNH65bLRYoUROD8EY+Pmi44qQWwXR7sw==", "dev": true }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", "@tsconfig/node12": "^1.0.7", "@tsconfig/node14": "^1.0.0", "@tsconfig/node16": "^1.0.2", "acorn": "^8.4.1", "acorn-walk": "^8.1.1", "arg": "^4.1.0", "create-require": "^1.1.0", "diff": "^4.0.1", "make-error": "^1.1.1", "v8-compile-cache-lib": "^3.0.1", "yn": "3.1.1" }, "bin": { "ts-node": "dist/bin.js", "ts-node-cwd": "dist/bin-cwd.js", "ts-node-esm": "dist/bin-esm.js", "ts-node-script": "dist/bin-script.js", "ts-node-transpile-only": "dist/bin-transpile.js", "ts-script": "dist/bin-script-deprecated.js" }, "peerDependencies": { "@swc/core": ">=1.2.50", "@swc/wasm": ">=1.2.50", "@types/node": "*", "typescript": ">=2.7" }, "peerDependenciesMeta": { "@swc/core": { "optional": true }, "@swc/wasm": { "optional": true } } }, "node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", "dev": true }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "peer": true, "dependencies": { "prelude-ls": "^1.2.1" }, "engines": { "node": ">= 0.8.0" } }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "peer": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, "dependencies": { "is-typedarray": "^1.0.0" } }, "node_modules/typedoc": { "version": "0.24.6", "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.6.tgz", "integrity": "sha512-c3y3h45xJv3qYwKDAwU6Cl+26CjT0ZvblHzfHJ+SjQDM4p1mZxtgHky4lhmG0+nNarRht8kADfZlbspJWdZarQ==", "dev": true, "dependencies": { "lunr": "^2.3.9", "marked": "^4.3.0", "minimatch": "^9.0.0", "shiki": "^0.14.1" }, "bin": { "typedoc": "bin/typedoc" }, "engines": { "node": ">= 14.14" }, "peerDependencies": { "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x" } }, "node_modules/typedoc/node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/typedoc/node_modules/minimatch": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/typescript": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { "node": ">=12.20" } }, "node_modules/unicode-length": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/unicode-length/-/unicode-length-2.1.0.tgz", "integrity": "sha512-4bV582zTV9Q02RXBxSUMiuN/KHo5w4aTojuKTNT96DIKps/SIawFp7cS5Mu25VuY1AioGXrmYyzKZUzh8OqoUw==", "dev": true, "dependencies": { "punycode": "^2.0.0" } }, "node_modules/update-browserslist-db": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" } ], "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" }, "bin": { "browserslist-lint": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" } }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "peer": true, "dependencies": { "punycode": "^2.1.0" } }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, "node_modules/v8-to-istanbul": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0" }, "engines": { "node": ">=10.12.0" } }, "node_modules/vscode-oniguruma": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", "dev": true }, "node_modules/vscode-textmate": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" }, "engines": { "node": ">= 8" } }, "node_modules/which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha512-B+enWhmw6cjfVC7kS8Pj9pCrKSc5txArRyaYGe088shv/FGWH+0Rjx/xPgtsWfsUtS27FkP697E4DDhgrgoc0Q==", "dev": true }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true, "peer": true, "engines": { "node": ">=0.10.0" } }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "node_modules/write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, "dependencies": { "imurmurhash": "^0.1.4", "is-typedarray": "^1.0.0", "signal-exit": "^3.0.2", "typedarray-to-buffer": "^3.1.5" } }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "engines": { "node": ">=10" } }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, "engines": { "node": ">= 6" } }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.0", "y18n": "^5.0.5", "yargs-parser": "^20.2.2" }, "engines": { "node": ">=10" } }, "node_modules/yargs-parser": { "version": "20.2.9", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "engines": { "node": ">=10" } }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } } } } node-lru-cache-10.0.1/package.json000066400000000000000000000052021446525347600166640ustar00rootroot00000000000000{ "name": "lru-cache", "description": "A cache object that deletes the least-recently-used items.", "version": "10.0.1", "author": "Isaac Z. Schlueter ", "keywords": [ "mru", "lru", "cache" ], "sideEffects": false, "scripts": { "build": "npm run prepare", "preprepare": "rm -rf dist", "prepare": "tsc -p tsconfig.json && tsc -p tsconfig-esm.json", "postprepare": "bash fixup.sh", "pretest": "npm run prepare", "presnap": "npm run prepare", "test": "c8 tap", "snap": "c8 tap", "preversion": "npm test", "postversion": "npm publish", "prepublishOnly": "git push origin --follow-tags", "format": "prettier --write .", "typedoc": "typedoc --tsconfig tsconfig-esm.json ./src/*.ts", "benchmark-results-typedoc": "bash scripts/benchmark-results-typedoc.sh", "prebenchmark": "npm run prepare", "benchmark": "make -C benchmark", "preprofile": "npm run prepare", "profile": "make -C benchmark profile" }, "main": "./dist/cjs/index.js", "module": "./dist/mjs/index.js", "exports": { "./min": { "import": { "types": "./dist/mjs/index.d.ts", "default": "./dist/mjs/index.min.js" }, "require": { "types": "./dist/cjs/index.d.ts", "default": "./dist/cjs/index.min.js" } }, ".": { "import": { "types": "./dist/mjs/index.d.ts", "default": "./dist/mjs/index.js" }, "require": { "types": "./dist/cjs/index.d.ts", "default": "./dist/cjs/index.js" } } }, "repository": "git://github.com/isaacs/node-lru-cache.git", "devDependencies": { "@size-limit/preset-small-lib": "^7.0.8", "@types/node": "^20.2.5", "@types/tap": "^15.0.6", "benchmark": "^2.1.4", "c8": "^7.11.2", "clock-mock": "^1.0.6", "esbuild": "^0.17.11", "eslint-config-prettier": "^8.5.0", "marked": "^4.2.12", "mkdirp": "^2.1.5", "prettier": "^2.6.2", "size-limit": "^7.0.8", "tap": "^16.3.4", "ts-node": "^10.9.1", "tslib": "^2.4.0", "typedoc": "^0.24.6", "typescript": "^5.0.4" }, "license": "ISC", "files": [ "dist" ], "engines": { "node": "14 || >=16.14" }, "prettier": { "semi": false, "printWidth": 70, "tabWidth": 2, "useTabs": false, "singleQuote": true, "jsxSingleQuote": false, "bracketSameLine": true, "arrowParens": "avoid", "endOfLine": "lf" }, "tap": { "coverage": false, "node-arg": [ "--expose-gc", "-r", "ts-node/register" ], "ts": false }, "size-limit": [ { "path": "./dist/mjs/index.js" } ] } node-lru-cache-10.0.1/scripts/000077500000000000000000000000001446525347600160665ustar00rootroot00000000000000node-lru-cache-10.0.1/scripts/.gitignore000066400000000000000000000000301446525347600200470ustar00rootroot00000000000000heapdump-* node_modules node-lru-cache-10.0.1/scripts/benchmark-results-typedoc.sh000066400000000000000000000014251446525347600235220ustar00rootroot00000000000000#!/usr/bin/env bash set -x set -e mkdir -p docs/benchmark/results cp -r benchmark/results/* docs/benchmark/results/ echo 'benchmark results overview' > docs/benchmark/index.html echo '' >> docs/benchmark/index.html echo '

raw CSV results

' >> docs/benchmark/index.html marked < benchmark/results.md >> docs/benchmark/index.html echo '' > docs/benchmark/results/index.html echo 'benchmark results' >> docs/benchmark/results/index.html echo '
    ' >> docs/benchmark/results/index.html ls docs/benchmark/results | while read p; do f=$(basename "$p") echo '
  • '$f'
  • ' >> docs/benchmark/results/index.html done echo '
' >> docs/benchmark/results/index.html node-lru-cache-10.0.1/scripts/max-size-test.js000077500000000000000000000042011446525347600211360ustar00rootroot00000000000000#!/usr/bin/env node --max_old_space_size=400 --expose_gc // https://github.com/isaacs/node-lru-cache/issues/227 if (typeof gc !== 'function') { throw new Error('run with --expose-gc') } let heapdump try { heapdump = require('heapdump') } catch (e) { const {spawnSync} = require('child_process') spawnSync('npm', ['install'], { cwd: __dirname, stdio: 'inherit' }) heapdump = require('heapdump') } const LRU = require('../') const maxSize = 1_000_000 const itemSize = 1_000 const expectItemCount = Math.floor(maxSize / itemSize) const profEvery = 100_000 const n = 10_000_000 const sizeCalculation = s => s.length || 1 const max = expectItemCount + 1 const keyRange = expectItemCount * 2 const makeItem = () => Buffer.alloc(itemSize) const v8 = require('v8') const prof = async (i, cache, name) => { // run gc so that we know if we're actually leaking memory, or just // that the gc is being lazy and not responding until there's memory // pressure. gc() const file = `${__dirname}/heapdump-${name}-${i}.heapsnapshot` await new Promise((res, rej) => heapdump.writeSnapshot(file, er => er ? rej(er) : res())) if (!cache || i === 0) { console.log(i, v8.getHeapStatistics(), file) } if (cache && i === 0) { console.log(max, cache.valList.length, cache.free.length) } } const test = async (name, cache) => { console.log(name) for (let i = 0; i < n; i++) { if ((i % profEvery) === 0) { await prof(i, cache, name) } // add items within a range of 2x the expected item count, // so we get evictions happening const item = makeItem() cache.set(i % keyRange, item) // get some random item, too, to keep the list a bit shuffled. // often these will be missing, of course, but expectItemCount/keyRange // times they'll be a hit, once the cache is full. const j = Math.floor(Math.random() * keyRange) cache.get(j) } cache = null prof(n, null, name) } const main = async () => { await test('max-no-maxSize', new LRU({ max })) await test('max-maxSize', new LRU({ max, maxSize, sizeCalculation })) await test('no-max-maxSize', new LRU({ maxSize, sizeCalculation })) } main() node-lru-cache-10.0.1/scripts/package-lock.json000066400000000000000000000025421446525347600213050ustar00rootroot00000000000000{ "name": "scripts", "lockfileVersion": 2, "requires": true, "packages": { "": { "dependencies": { "heapdump": "^0.3.15" } }, "node_modules/heapdump": { "version": "0.3.15", "resolved": "https://registry.npmjs.org/heapdump/-/heapdump-0.3.15.tgz", "integrity": "sha512-n8aSFscI9r3gfhOcAECAtXFaQ1uy4QSke6bnaL+iymYZ/dWs9cqDqHM+rALfsHUwukUbxsdlECZ0pKmJdQ/4OA==", "hasInstallScript": true, "dependencies": { "nan": "^2.13.2" }, "engines": { "node": ">=0.10.0" } }, "node_modules/nan": { "version": "2.15.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" } }, "dependencies": { "heapdump": { "version": "0.3.15", "resolved": "https://registry.npmjs.org/heapdump/-/heapdump-0.3.15.tgz", "integrity": "sha512-n8aSFscI9r3gfhOcAECAtXFaQ1uy4QSke6bnaL+iymYZ/dWs9cqDqHM+rALfsHUwukUbxsdlECZ0pKmJdQ/4OA==", "requires": { "nan": "^2.13.2" } }, "nan": { "version": "2.15.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==" } } } node-lru-cache-10.0.1/scripts/package.json000066400000000000000000000000661446525347600203560ustar00rootroot00000000000000{ "dependencies": { "heapdump": "^0.3.15" } } node-lru-cache-10.0.1/scripts/transpile-to-esm.js000066400000000000000000000004661446525347600216350ustar00rootroot00000000000000#!/usr/bin/env node const { readFileSync, writeFileSync } = require('fs') const { resolve } = require('path') const cjs = readFileSync(resolve(__dirname, '../index.js'), 'utf8') const esm = cjs.replace(/module.exports\s*=\s*/, 'export default ') writeFileSync(resolve(__dirname, '../index.mjs'), esm, 'utf8') node-lru-cache-10.0.1/src/000077500000000000000000000000001446525347600151665ustar00rootroot00000000000000node-lru-cache-10.0.1/src/index.ts000066400000000000000000002045551446525347600166600ustar00rootroot00000000000000/** * @module LRUCache */ // module-private names and types type Perf = { now: () => number } const perf: Perf = typeof performance === 'object' && performance && typeof performance.now === 'function' ? performance : Date const warned = new Set() // either a function or a class type ForC = ((...a: any[]) => any) | { new (...a: any[]): any } /* c8 ignore start */ const PROCESS = ( typeof process === 'object' && !!process ? process : {} ) as { [k: string]: any } /* c8 ignore start */ const emitWarning = ( msg: string, type: string, code: string, fn: ForC ) => { typeof PROCESS.emitWarning === 'function' ? PROCESS.emitWarning(msg, type, code, fn) : console.error(`[${code}] ${type}: ${msg}`) } let AC = globalThis.AbortController let AS = globalThis.AbortSignal /* c8 ignore start */ if (typeof AC === 'undefined') { //@ts-ignore AS = class AbortSignal { onabort?: (...a: any[]) => any _onabort: ((...a: any[]) => any)[] = [] reason?: any aborted: boolean = false addEventListener(_: string, fn: (...a: any[]) => any) { this._onabort.push(fn) } } //@ts-ignore AC = class AbortController { constructor() { warnACPolyfill() } signal = new AS() abort(reason: any) { if (this.signal.aborted) return //@ts-ignore this.signal.reason = reason //@ts-ignore this.signal.aborted = true //@ts-ignore for (const fn of this.signal._onabort) { fn(reason) } this.signal.onabort?.(reason) } } let printACPolyfillWarning = PROCESS.env?.LRU_CACHE_IGNORE_AC_WARNING !== '1' const warnACPolyfill = () => { if (!printACPolyfillWarning) return printACPolyfillWarning = false emitWarning( 'AbortController is not defined. If using lru-cache in ' + 'node 14, load an AbortController polyfill from the ' + '`node-abort-controller` package. A minimal polyfill is ' + 'provided for use by LRUCache.fetch(), but it should not be ' + 'relied upon in other contexts (eg, passing it to other APIs that ' + 'use AbortController/AbortSignal might have undesirable effects). ' + 'You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.', 'NO_ABORT_CONTROLLER', 'ENOTSUP', warnACPolyfill ) } } /* c8 ignore stop */ const shouldWarn = (code: string) => !warned.has(code) const TYPE = Symbol('type') type PosInt = number & { [TYPE]: 'Positive Integer' } type Index = number & { [TYPE]: 'LRUCache Index' } const isPosInt = (n: any): n is PosInt => n && n === Math.floor(n) && n > 0 && isFinite(n) type UintArray = Uint8Array | Uint16Array | Uint32Array type NumberArray = UintArray | number[] /* c8 ignore start */ // This is a little bit ridiculous, tbh. // The maximum array length is 2^32-1 or thereabouts on most JS impls. // And well before that point, you're caching the entire world, I mean, // that's ~32GB of just integers for the next/prev links, plus whatever // else to hold that many keys and values. Just filling the memory with // zeroes at init time is brutal when you get that big. // But why not be complete? // Maybe in the future, these limits will have expanded. const getUintArray = (max: number) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null /* c8 ignore stop */ class ZeroArray extends Array { constructor(size: number) { super(size) this.fill(0) } } type StackLike = Stack | Index[] class Stack { heap: NumberArray length: number // private constructor static #constructing: boolean = false static create(max: number): StackLike { const HeapCls = getUintArray(max) if (!HeapCls) return [] Stack.#constructing = true const s = new Stack(max, HeapCls) Stack.#constructing = false return s } constructor( max: number, HeapCls: { new (n: number): NumberArray } ) { /* c8 ignore start */ if (!Stack.#constructing) { throw new TypeError('instantiate Stack using Stack.create(n)') } /* c8 ignore stop */ this.heap = new HeapCls(max) this.length = 0 } push(n: Index) { this.heap[this.length++] = n } pop(): Index { return this.heap[--this.length] as Index } } /** * Promise representing an in-progress {@link LRUCache#fetch} call */ export type BackgroundFetch = Promise & { __returned: BackgroundFetch | undefined __abortController: AbortController __staleWhileFetching: V | undefined } type DisposeTask = [ value: V, key: K, reason: LRUCache.DisposeReason ] export namespace LRUCache { /** * An integer greater than 0, reflecting the calculated size of items */ export type Size = number /** * Integer greater than 0, representing some number of milliseconds, or the * time at which a TTL started counting from. */ export type Milliseconds = number /** * An integer greater than 0, reflecting a number of items */ export type Count = number /** * The reason why an item was removed from the cache, passed * to the {@link Disposer} methods. */ export type DisposeReason = 'evict' | 'set' | 'delete' /** * A method called upon item removal, passed as the * {@link OptionsBase.dispose} and/or * {@link OptionsBase.disposeAfter} options. */ export type Disposer = ( value: V, key: K, reason: DisposeReason ) => void /** * A function that returns the effective calculated size * of an entry in the cache. */ export type SizeCalculator = (value: V, key: K) => Size /** * Options provided to the * {@link OptionsBase.fetchMethod} function. */ export interface FetcherOptions { signal: AbortSignal options: FetcherFetchOptions /** * Object provided in the {@link FetchOptions.context} option to * {@link LRUCache#fetch} */ context: FC } /** * Status object that may be passed to {@link LRUCache#fetch}, * {@link LRUCache#get}, {@link LRUCache#set}, and {@link LRUCache#has}. */ export interface Status { /** * The status of a set() operation. * * - add: the item was not found in the cache, and was added * - update: the item was in the cache, with the same value provided * - replace: the item was in the cache, and replaced * - miss: the item was not added to the cache for some reason */ set?: 'add' | 'update' | 'replace' | 'miss' /** * the ttl stored for the item, or undefined if ttls are not used. */ ttl?: Milliseconds /** * the start time for the item, or undefined if ttls are not used. */ start?: Milliseconds /** * The timestamp used for TTL calculation */ now?: Milliseconds /** * the remaining ttl for the item, or undefined if ttls are not used. */ remainingTTL?: Milliseconds /** * The calculated size for the item, if sizes are used. */ entrySize?: Size /** * The total calculated size of the cache, if sizes are used. */ totalCalculatedSize?: Size /** * A flag indicating that the item was not stored, due to exceeding the * {@link OptionsBase.maxEntrySize} */ maxEntrySizeExceeded?: true /** * The old value, specified in the case of `set:'update'` or * `set:'replace'` */ oldValue?: V /** * The results of a {@link LRUCache#has} operation * * - hit: the item was found in the cache * - stale: the item was found in the cache, but is stale * - miss: the item was not found in the cache */ has?: 'hit' | 'stale' | 'miss' /** * The status of a {@link LRUCache#fetch} operation. * Note that this can change as the underlying fetch() moves through * various states. * * - inflight: there is another fetch() for this key which is in process * - get: there is no fetchMethod, so {@link LRUCache#get} was called. * - miss: the item is not in cache, and will be fetched. * - hit: the item is in the cache, and was resolved immediately. * - stale: the item is in the cache, but stale. * - refresh: the item is in the cache, and not stale, but * {@link FetchOptions.forceRefresh} was specified. */ fetch?: 'get' | 'inflight' | 'miss' | 'hit' | 'stale' | 'refresh' /** * The {@link OptionsBase.fetchMethod} was called */ fetchDispatched?: true /** * The cached value was updated after a successful call to * {@link OptionsBase.fetchMethod} */ fetchUpdated?: true /** * The reason for a fetch() rejection. Either the error raised by the * {@link OptionsBase.fetchMethod}, or the reason for an * AbortSignal. */ fetchError?: Error /** * The fetch received an abort signal */ fetchAborted?: true /** * The abort signal received was ignored, and the fetch was allowed to * continue. */ fetchAbortIgnored?: true /** * The fetchMethod promise resolved successfully */ fetchResolved?: true /** * The fetchMethod promise was rejected */ fetchRejected?: true /** * The status of a {@link LRUCache#get} operation. * * - fetching: The item is currently being fetched. If a previous value * is present and allowed, that will be returned. * - stale: The item is in the cache, and is stale. * - hit: the item is in the cache * - miss: the item is not in the cache */ get?: 'stale' | 'hit' | 'miss' /** * A fetch or get operation returned a stale value. */ returnedStale?: true } /** * options which override the options set in the LRUCache constructor * when calling {@link LRUCache#fetch}. * * This is the union of {@link GetOptions} and {@link SetOptions}, plus * {@link OptionsBase.noDeleteOnFetchRejection}, * {@link OptionsBase.allowStaleOnFetchRejection}, * {@link FetchOptions.forceRefresh}, and * {@link OptionsBase.context} * * Any of these may be modified in the {@link OptionsBase.fetchMethod} * function, but the {@link GetOptions} fields will of course have no * effect, as the {@link LRUCache#get} call already happened by the time * the fetchMethod is called. */ export interface FetcherFetchOptions extends Pick< OptionsBase, | 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet' | 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL' | 'noDeleteOnFetchRejection' | 'allowStaleOnFetchRejection' | 'ignoreFetchAbort' | 'allowStaleOnFetchAbort' > { status?: Status size?: Size } /** * Options that may be passed to the {@link LRUCache#fetch} method. */ export interface FetchOptions extends FetcherFetchOptions { /** * Set to true to force a re-load of the existing data, even if it * is not yet stale. */ forceRefresh?: boolean /** * Context provided to the {@link OptionsBase.fetchMethod} as * the {@link FetcherOptions.context} param. * * If the FC type is specified as unknown (the default), * undefined or void, then this is optional. Otherwise, it will * be required. */ context?: FC signal?: AbortSignal status?: Status } /** * Options provided to {@link LRUCache#fetch} when the FC type is something * other than `unknown`, `undefined`, or `void` */ export interface FetchOptionsWithContext extends FetchOptions { context: FC } /** * Options provided to {@link LRUCache#fetch} when the FC type is * `undefined` or `void` */ export interface FetchOptionsNoContext extends FetchOptions { context?: undefined } /** * Options that may be passed to the {@link LRUCache#has} method. */ export interface HasOptions extends Pick, 'updateAgeOnHas'> { status?: Status } /** * Options that may be passed to the {@link LRUCache#get} method. */ export interface GetOptions extends Pick< OptionsBase, 'allowStale' | 'updateAgeOnGet' | 'noDeleteOnStaleGet' > { status?: Status } /** * Options that may be passed to the {@link LRUCache#peek} method. */ export interface PeekOptions extends Pick, 'allowStale'> {} /** * Options that may be passed to the {@link LRUCache#set} method. */ export interface SetOptions extends Pick< OptionsBase, 'sizeCalculation' | 'ttl' | 'noDisposeOnSet' | 'noUpdateTTL' > { /** * If size tracking is enabled, then setting an explicit size * in the {@link LRUCache#set} call will prevent calling the * {@link OptionsBase.sizeCalculation} function. */ size?: Size /** * If TTL tracking is enabled, then setting an explicit start * time in the {@link LRUCache#set} call will override the * default time from `performance.now()` or `Date.now()`. * * Note that it must be a valid value for whichever time-tracking * method is in use. */ start?: Milliseconds status?: Status } /** * The type signature for the {@link OptionsBase.fetchMethod} option. */ export type Fetcher = ( key: K, staleValue: V | undefined, options: FetcherOptions ) => Promise | V | undefined | void /** * Options which may be passed to the {@link LRUCache} constructor. * * Most of these may be overridden in the various options that use * them. * * Despite all being technically optional, the constructor requires that * a cache is at minimum limited by one or more of {@link OptionsBase.max}, * {@link OptionsBase.ttl}, or {@link OptionsBase.maxSize}. * * If {@link OptionsBase.ttl} is used alone, then it is strongly advised * (and in fact required by the type definitions here) that the cache * also set {@link OptionsBase.ttlAutopurge}, to prevent potentially * unbounded storage. */ export interface OptionsBase { /** * The maximum number of items to store in the cache before evicting * old entries. This is read-only on the {@link LRUCache} instance, * and may not be overridden. * * If set, then storage space will be pre-allocated at construction * time, and the cache will perform significantly faster. * * Note that significantly fewer items may be stored, if * {@link OptionsBase.maxSize} and/or {@link OptionsBase.ttl} are also * set. */ max?: Count /** * Max time in milliseconds for items to live in cache before they are * considered stale. Note that stale items are NOT preemptively removed * by default, and MAY live in the cache long after they have expired. * * Also, as this cache is optimized for LRU/MRU operations, some of * the staleness/TTL checks will reduce performance, as they will incur * overhead by deleting items. * * Must be an integer number of ms. If set to 0, this indicates "no TTL" * * @default 0 */ ttl?: Milliseconds /** * Minimum amount of time in ms in which to check for staleness. * Defaults to 1, which means that the current time is checked * at most once per millisecond. * * Set to 0 to check the current time every time staleness is tested. * (This reduces performance, and is theoretically unnecessary.) * * Setting this to a higher value will improve performance somewhat * while using ttl tracking, albeit at the expense of keeping stale * items around a bit longer than their TTLs would indicate. * * @default 1 */ ttlResolution?: Milliseconds /** * Preemptively remove stale items from the cache. * Note that this may significantly degrade performance, * especially if the cache is storing a large number of items. * It is almost always best to just leave the stale items in * the cache, and let them fall out as new items are added. * * Note that this means that {@link OptionsBase.allowStale} is a bit * pointless, as stale items will be deleted almost as soon as they * expire. * * @default false */ ttlAutopurge?: boolean /** * Update the age of items on {@link LRUCache#get}, renewing their TTL * * Has no effect if {@link OptionsBase.ttl} is not set. * * @default false */ updateAgeOnGet?: boolean /** * Update the age of items on {@link LRUCache#has}, renewing their TTL * * Has no effect if {@link OptionsBase.ttl} is not set. * * @default false */ updateAgeOnHas?: boolean /** * Allow {@link LRUCache#get} and {@link LRUCache#fetch} calls to return * stale data, if available. */ allowStale?: boolean /** * Function that is called on items when they are dropped from the cache. * This can be handy if you want to close file descriptors or do other * cleanup tasks when items are no longer accessible. Called with `key, * value`. It's called before actually removing the item from the * internal cache, so it is *NOT* safe to re-add them. * * Use {@link OptionsBase.disposeAfter} if you wish to dispose items after * they have been full removed, when it is safe to add them back to the * cache. */ dispose?: Disposer /** * The same as {@link OptionsBase.dispose}, but called *after* the entry * is completely removed and the cache is once again in a clean state. * It is safe to add an item right back into the cache at this point. * However, note that it is *very* easy to inadvertently create infinite * recursion this way. */ disposeAfter?: Disposer /** * Set to true to suppress calling the * {@link OptionsBase.dispose} function if the entry key is * still accessible within the cache. * This may be overridden by passing an options object to * {@link LRUCache#set}. */ noDisposeOnSet?: boolean /** * Boolean flag to tell the cache to not update the TTL when * setting a new value for an existing key (ie, when updating a value * rather than inserting a new value). Note that the TTL value is * _always_ set (if provided) when adding a new entry into the cache. * * Has no effect if a {@link OptionsBase.ttl} is not set. */ noUpdateTTL?: boolean /** * If you wish to track item size, you must provide a maxSize * note that we still will only keep up to max *actual items*, * if max is set, so size tracking may cause fewer than max items * to be stored. At the extreme, a single item of maxSize size * will cause everything else in the cache to be dropped when it * is added. Use with caution! * * Note also that size tracking can negatively impact performance, * though for most cases, only minimally. */ maxSize?: Size /** * The maximum allowed size for any single item in the cache. * * If a larger item is passed to {@link LRUCache#set} or returned by a * {@link OptionsBase.fetchMethod}, then it will not be stored in the * cache. */ maxEntrySize?: Size /** * A function that returns a number indicating the item's size. * * If not provided, and {@link OptionsBase.maxSize} or * {@link OptionsBase.maxEntrySize} are set, then all * {@link LRUCache#set} calls **must** provide an explicit * {@link SetOptions.size} or sizeCalculation param. */ sizeCalculation?: SizeCalculator /** * Method that provides the implementation for {@link LRUCache#fetch} */ fetchMethod?: Fetcher /** * Set to true to suppress the deletion of stale data when a * {@link OptionsBase.fetchMethod} returns a rejected promise. */ noDeleteOnFetchRejection?: boolean /** * Do not delete stale items when they are retrieved with * {@link LRUCache#get}. * * Note that the `get` return value will still be `undefined` * unless {@link OptionsBase.allowStale} is true. */ noDeleteOnStaleGet?: boolean /** * Set to true to allow returning stale data when a * {@link OptionsBase.fetchMethod} throws an error or returns a rejected * promise. * * This differs from using {@link OptionsBase.allowStale} in that stale * data will ONLY be returned in the case that the * {@link LRUCache#fetch} fails, not any other times. */ allowStaleOnFetchRejection?: boolean /** * Set to true to return a stale value from the cache when the * `AbortSignal` passed to the {@link OptionsBase.fetchMethod} dispatches an `'abort'` * event, whether user-triggered, or due to internal cache behavior. * * Unless {@link OptionsBase.ignoreFetchAbort} is also set, the underlying * {@link OptionsBase.fetchMethod} will still be considered canceled, and * any value it returns will be ignored and not cached. * * Caveat: since fetches are aborted when a new value is explicitly * set in the cache, this can lead to fetch returning a stale value, * since that was the fallback value _at the moment the `fetch()` was * initiated_, even though the new updated value is now present in * the cache. * * For example: * * ```ts * const cache = new LRUCache({ * ttl: 100, * fetchMethod: async (url, oldValue, { signal }) => { * const res = await fetch(url, { signal }) * return await res.json() * } * }) * cache.set('https://example.com/', { some: 'data' }) * // 100ms go by... * const result = cache.fetch('https://example.com/') * cache.set('https://example.com/', { other: 'thing' }) * console.log(await result) // { some: 'data' } * console.log(cache.get('https://example.com/')) // { other: 'thing' } * ``` */ allowStaleOnFetchAbort?: boolean /** * Set to true to ignore the `abort` event emitted by the `AbortSignal` * object passed to {@link OptionsBase.fetchMethod}, and still cache the * resulting resolution value, as long as it is not `undefined`. * * When used on its own, this means aborted {@link LRUCache#fetch} calls are not * immediately resolved or rejected when they are aborted, and instead * take the full time to await. * * When used with {@link OptionsBase.allowStaleOnFetchAbort}, aborted * {@link LRUCache#fetch} calls will resolve immediately to their stale * cached value or `undefined`, and will continue to process and eventually * update the cache when they resolve, as long as the resulting value is * not `undefined`, thus supporting a "return stale on timeout while * refreshing" mechanism by passing `AbortSignal.timeout(n)` as the signal. * * **Note**: regardless of this setting, an `abort` event _is still * emitted on the `AbortSignal` object_, so may result in invalid results * when passed to other underlying APIs that use AbortSignals. * * This may be overridden in the {@link OptionsBase.fetchMethod} or the * call to {@link LRUCache#fetch}. */ ignoreFetchAbort?: boolean } export interface OptionsMaxLimit extends OptionsBase { max: Count } export interface OptionsTTLLimit extends OptionsBase { ttl: Milliseconds ttlAutopurge: boolean } export interface OptionsSizeLimit extends OptionsBase { maxSize: Size } /** * The valid safe options for the {@link LRUCache} constructor */ export type Options = | OptionsMaxLimit | OptionsSizeLimit | OptionsTTLLimit /** * Entry objects used by {@link LRUCache#load} and {@link LRUCache#dump} */ export interface Entry { value: V ttl?: Milliseconds size?: Size start?: Milliseconds } } /** * Default export, the thing you're using this module to get. * * All properties from the options object (with the exception of * {@link OptionsBase.max} and {@link OptionsBase.maxSize}) are added as * normal public members. (`max` and `maxBase` are read-only getters.) * Changing any of these will alter the defaults for subsequent method calls, * but is otherwise safe. */ export class LRUCache { // properties coming in from the options of these, only max and maxSize // really *need* to be protected. The rest can be modified, as they just // set defaults for various methods. readonly #max: LRUCache.Count readonly #maxSize: LRUCache.Size readonly #dispose?: LRUCache.Disposer readonly #disposeAfter?: LRUCache.Disposer readonly #fetchMethod?: LRUCache.Fetcher /** * {@link LRUCache.OptionsBase.ttl} */ ttl: LRUCache.Milliseconds /** * {@link LRUCache.OptionsBase.ttlResolution} */ ttlResolution: LRUCache.Milliseconds /** * {@link LRUCache.OptionsBase.ttlAutopurge} */ ttlAutopurge: boolean /** * {@link LRUCache.OptionsBase.updateAgeOnGet} */ updateAgeOnGet: boolean /** * {@link LRUCache.OptionsBase.updateAgeOnHas} */ updateAgeOnHas: boolean /** * {@link LRUCache.OptionsBase.allowStale} */ allowStale: boolean /** * {@link LRUCache.OptionsBase.noDisposeOnSet} */ noDisposeOnSet: boolean /** * {@link LRUCache.OptionsBase.noUpdateTTL} */ noUpdateTTL: boolean /** * {@link LRUCache.OptionsBase.maxEntrySize} */ maxEntrySize: LRUCache.Size /** * {@link LRUCache.OptionsBase.sizeCalculation} */ sizeCalculation?: LRUCache.SizeCalculator /** * {@link LRUCache.OptionsBase.noDeleteOnFetchRejection} */ noDeleteOnFetchRejection: boolean /** * {@link LRUCache.OptionsBase.noDeleteOnStaleGet} */ noDeleteOnStaleGet: boolean /** * {@link LRUCache.OptionsBase.allowStaleOnFetchAbort} */ allowStaleOnFetchAbort: boolean /** * {@link LRUCache.OptionsBase.allowStaleOnFetchRejection} */ allowStaleOnFetchRejection: boolean /** * {@link LRUCache.OptionsBase.ignoreFetchAbort} */ ignoreFetchAbort: boolean // computed properties #size: LRUCache.Count #calculatedSize: LRUCache.Size #keyMap: Map #keyList: (K | undefined)[] #valList: (V | BackgroundFetch | undefined)[] #next: NumberArray #prev: NumberArray #head: Index #tail: Index #free: StackLike #disposed?: DisposeTask[] #sizes?: ZeroArray #starts?: ZeroArray #ttls?: ZeroArray #hasDispose: boolean #hasFetchMethod: boolean #hasDisposeAfter: boolean /** * Do not call this method unless you need to inspect the * inner workings of the cache. If anything returned by this * object is modified in any way, strange breakage may occur. * * These fields are private for a reason! * * @internal */ static unsafeExposeInternals< K extends {}, V extends {}, FC extends unknown = unknown >(c: LRUCache) { return { // properties starts: c.#starts, ttls: c.#ttls, sizes: c.#sizes, keyMap: c.#keyMap as Map, keyList: c.#keyList, valList: c.#valList, next: c.#next, prev: c.#prev, get head() { return c.#head }, get tail() { return c.#tail }, free: c.#free, // methods isBackgroundFetch: (p: any) => c.#isBackgroundFetch(p), backgroundFetch: ( k: K, index: number | undefined, options: LRUCache.FetchOptions, context: any ): BackgroundFetch => c.#backgroundFetch( k, index as Index | undefined, options, context ), moveToTail: (index: number): void => c.#moveToTail(index as Index), indexes: (options?: { allowStale: boolean }) => c.#indexes(options), rindexes: (options?: { allowStale: boolean }) => c.#rindexes(options), isStale: (index: number | undefined) => c.#isStale(index as Index), } } // Protected read-only members /** * {@link LRUCache.OptionsBase.max} (read-only) */ get max(): LRUCache.Count { return this.#max } /** * {@link LRUCache.OptionsBase.maxSize} (read-only) */ get maxSize(): LRUCache.Count { return this.#maxSize } /** * The total computed size of items in the cache (read-only) */ get calculatedSize(): LRUCache.Size { return this.#calculatedSize } /** * The number of items stored in the cache (read-only) */ get size(): LRUCache.Count { return this.#size } /** * {@link LRUCache.OptionsBase.fetchMethod} (read-only) */ get fetchMethod(): LRUCache.Fetcher | undefined { return this.#fetchMethod } /** * {@link LRUCache.OptionsBase.dispose} (read-only) */ get dispose() { return this.#dispose } /** * {@link LRUCache.OptionsBase.disposeAfter} (read-only) */ get disposeAfter() { return this.#disposeAfter } constructor( options: LRUCache.Options | LRUCache ) { const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, } = options if (max !== 0 && !isPosInt(max)) { throw new TypeError('max option must be a nonnegative integer') } const UintArray = max ? getUintArray(max) : Array if (!UintArray) { throw new Error('invalid max value: ' + max) } this.#max = max this.#maxSize = maxSize this.maxEntrySize = maxEntrySize || this.#maxSize this.sizeCalculation = sizeCalculation if (this.sizeCalculation) { if (!this.#maxSize && !this.maxEntrySize) { throw new TypeError( 'cannot set sizeCalculation without setting maxSize or maxEntrySize' ) } if (typeof this.sizeCalculation !== 'function') { throw new TypeError('sizeCalculation set to non-function') } } if ( fetchMethod !== undefined && typeof fetchMethod !== 'function' ) { throw new TypeError( 'fetchMethod must be a function if specified' ) } this.#fetchMethod = fetchMethod this.#hasFetchMethod = !!fetchMethod this.#keyMap = new Map() this.#keyList = new Array(max).fill(undefined) this.#valList = new Array(max).fill(undefined) this.#next = new UintArray(max) this.#prev = new UintArray(max) this.#head = 0 as Index this.#tail = 0 as Index this.#free = Stack.create(max) this.#size = 0 this.#calculatedSize = 0 if (typeof dispose === 'function') { this.#dispose = dispose } if (typeof disposeAfter === 'function') { this.#disposeAfter = disposeAfter this.#disposed = [] } else { this.#disposeAfter = undefined this.#disposed = undefined } this.#hasDispose = !!this.#dispose this.#hasDisposeAfter = !!this.#disposeAfter this.noDisposeOnSet = !!noDisposeOnSet this.noUpdateTTL = !!noUpdateTTL this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection this.allowStaleOnFetchRejection = !!allowStaleOnFetchRejection this.allowStaleOnFetchAbort = !!allowStaleOnFetchAbort this.ignoreFetchAbort = !!ignoreFetchAbort // NB: maxEntrySize is set to maxSize if it's set if (this.maxEntrySize !== 0) { if (this.#maxSize !== 0) { if (!isPosInt(this.#maxSize)) { throw new TypeError( 'maxSize must be a positive integer if specified' ) } } if (!isPosInt(this.maxEntrySize)) { throw new TypeError( 'maxEntrySize must be a positive integer if specified' ) } this.#initializeSizeTracking() } this.allowStale = !!allowStale this.noDeleteOnStaleGet = !!noDeleteOnStaleGet this.updateAgeOnGet = !!updateAgeOnGet this.updateAgeOnHas = !!updateAgeOnHas this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1 this.ttlAutopurge = !!ttlAutopurge this.ttl = ttl || 0 if (this.ttl) { if (!isPosInt(this.ttl)) { throw new TypeError( 'ttl must be a positive integer if specified' ) } this.#initializeTTLTracking() } // do not allow completely unbounded caches if (this.#max === 0 && this.ttl === 0 && this.#maxSize === 0) { throw new TypeError( 'At least one of max, maxSize, or ttl is required' ) } if (!this.ttlAutopurge && !this.#max && !this.#maxSize) { const code = 'LRU_CACHE_UNBOUNDED' if (shouldWarn(code)) { warned.add(code) const msg = 'TTL caching without ttlAutopurge, max, or maxSize can ' + 'result in unbounded memory consumption.' emitWarning(msg, 'UnboundedCacheWarning', code, LRUCache) } } } /** * Return the remaining TTL time for a given entry key */ getRemainingTTL(key: K) { return this.#keyMap.has(key) ? Infinity : 0 } #initializeTTLTracking() { const ttls = new ZeroArray(this.#max) const starts = new ZeroArray(this.#max) this.#ttls = ttls this.#starts = starts this.#setItemTTL = (index, ttl, start = perf.now()) => { starts[index] = ttl !== 0 ? start : 0 ttls[index] = ttl if (ttl !== 0 && this.ttlAutopurge) { const t = setTimeout(() => { if (this.#isStale(index)) { this.delete(this.#keyList[index] as K) } }, ttl + 1) // unref() not supported on all platforms /* c8 ignore start */ if (t.unref) { t.unref() } /* c8 ignore stop */ } } this.#updateItemAge = index => { starts[index] = ttls[index] !== 0 ? perf.now() : 0 } this.#statusTTL = (status, index) => { if (ttls[index]) { const ttl = ttls[index] const start = starts[index] status.ttl = ttl status.start = start status.now = cachedNow || getNow() const age = status.now - start status.remainingTTL = ttl - age } } // debounce calls to perf.now() to 1s so we're not hitting // that costly call repeatedly. let cachedNow = 0 const getNow = () => { const n = perf.now() if (this.ttlResolution > 0) { cachedNow = n const t = setTimeout( () => (cachedNow = 0), this.ttlResolution ) // not available on all platforms /* c8 ignore start */ if (t.unref) { t.unref() } /* c8 ignore stop */ } return n } this.getRemainingTTL = key => { const index = this.#keyMap.get(key) if (index === undefined) { return 0 } const ttl = ttls[index] const start = starts[index] if (ttl === 0 || start === 0) { return Infinity } const age = (cachedNow || getNow()) - start return ttl - age } this.#isStale = index => { return ( ttls[index] !== 0 && starts[index] !== 0 && (cachedNow || getNow()) - starts[index] > ttls[index] ) } } // conditionally set private methods related to TTL #updateItemAge: (index: Index) => void = () => {} #statusTTL: (status: LRUCache.Status, index: Index) => void = () => {} #setItemTTL: ( index: Index, ttl: LRUCache.Milliseconds, start?: LRUCache.Milliseconds // ignore because we never call this if we're not already in TTL mode /* c8 ignore start */ ) => void = () => {} /* c8 ignore stop */ #isStale: (index: Index) => boolean = () => false #initializeSizeTracking() { const sizes = new ZeroArray(this.#max) this.#calculatedSize = 0 this.#sizes = sizes this.#removeItemSize = index => { this.#calculatedSize -= sizes[index] sizes[index] = 0 } this.#requireSize = (k, v, size, sizeCalculation) => { // provisionally accept background fetches. // actual value size will be checked when they return. if (this.#isBackgroundFetch(v)) { return 0 } if (!isPosInt(size)) { if (sizeCalculation) { if (typeof sizeCalculation !== 'function') { throw new TypeError('sizeCalculation must be a function') } size = sizeCalculation(v, k) if (!isPosInt(size)) { throw new TypeError( 'sizeCalculation return invalid (expect positive integer)' ) } } else { throw new TypeError( 'invalid size value (must be positive integer). ' + 'When maxSize or maxEntrySize is used, sizeCalculation ' + 'or size must be set.' ) } } return size } this.#addItemSize = ( index: Index, size: LRUCache.Size, status?: LRUCache.Status ) => { sizes[index] = size if (this.#maxSize) { const maxSize = this.#maxSize - sizes[index] while (this.#calculatedSize > maxSize) { this.#evict(true) } } this.#calculatedSize += sizes[index] if (status) { status.entrySize = size status.totalCalculatedSize = this.#calculatedSize } } } #removeItemSize: (index: Index) => void = _i => {} #addItemSize: ( index: Index, size: LRUCache.Size, status?: LRUCache.Status ) => void = (_i, _s, _st) => {} #requireSize: ( k: K, v: V | BackgroundFetch, size?: LRUCache.Size, sizeCalculation?: LRUCache.SizeCalculator ) => LRUCache.Size = ( _k: K, _v: V | BackgroundFetch, size?: LRUCache.Size, sizeCalculation?: LRUCache.SizeCalculator ) => { if (size || sizeCalculation) { throw new TypeError( 'cannot set size without setting maxSize or maxEntrySize on cache' ) } return 0 }; *#indexes({ allowStale = this.allowStale } = {}) { if (this.#size) { for (let i = this.#tail; true; ) { if (!this.#isValidIndex(i)) { break } if (allowStale || !this.#isStale(i)) { yield i } if (i === this.#head) { break } else { i = this.#prev[i] as Index } } } } *#rindexes({ allowStale = this.allowStale } = {}) { if (this.#size) { for (let i = this.#head; true; ) { if (!this.#isValidIndex(i)) { break } if (allowStale || !this.#isStale(i)) { yield i } if (i === this.#tail) { break } else { i = this.#next[i] as Index } } } } #isValidIndex(index: Index) { return ( index !== undefined && this.#keyMap.get(this.#keyList[index] as K) === index ) } /** * Return a generator yielding `[key, value]` pairs, * in order from most recently used to least recently used. */ *entries() { for (const i of this.#indexes()) { if ( this.#valList[i] !== undefined && this.#keyList[i] !== undefined && !this.#isBackgroundFetch(this.#valList[i]) ) { yield [this.#keyList[i], this.#valList[i]] } } } /** * Inverse order version of {@link LRUCache.entries} * * Return a generator yielding `[key, value]` pairs, * in order from least recently used to most recently used. */ *rentries() { for (const i of this.#rindexes()) { if ( this.#valList[i] !== undefined && this.#keyList[i] !== undefined && !this.#isBackgroundFetch(this.#valList[i]) ) { yield [this.#keyList[i], this.#valList[i]] } } } /** * Return a generator yielding the keys in the cache, * in order from most recently used to least recently used. */ *keys() { for (const i of this.#indexes()) { const k = this.#keyList[i] if ( k !== undefined && !this.#isBackgroundFetch(this.#valList[i]) ) { yield k } } } /** * Inverse order version of {@link LRUCache.keys} * * Return a generator yielding the keys in the cache, * in order from least recently used to most recently used. */ *rkeys() { for (const i of this.#rindexes()) { const k = this.#keyList[i] if ( k !== undefined && !this.#isBackgroundFetch(this.#valList[i]) ) { yield k } } } /** * Return a generator yielding the values in the cache, * in order from most recently used to least recently used. */ *values() { for (const i of this.#indexes()) { const v = this.#valList[i] if ( v !== undefined && !this.#isBackgroundFetch(this.#valList[i]) ) { yield this.#valList[i] } } } /** * Inverse order version of {@link LRUCache.values} * * Return a generator yielding the values in the cache, * in order from least recently used to most recently used. */ *rvalues() { for (const i of this.#rindexes()) { const v = this.#valList[i] if ( v !== undefined && !this.#isBackgroundFetch(this.#valList[i]) ) { yield this.#valList[i] } } } /** * Iterating over the cache itself yields the same results as * {@link LRUCache.entries} */ [Symbol.iterator]() { return this.entries() } /** * Find a value for which the supplied fn method returns a truthy value, * similar to Array.find(). fn is called as fn(value, key, cache). */ find( fn: (v: V, k: K, self: LRUCache) => boolean, getOptions: LRUCache.GetOptions = {} ) { for (const i of this.#indexes()) { const v = this.#valList[i] const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v if (value === undefined) continue if (fn(value, this.#keyList[i] as K, this)) { return this.get(this.#keyList[i] as K, getOptions) } } } /** * Call the supplied function on each item in the cache, in order from * most recently used to least recently used. fn is called as * fn(value, key, cache). Does not update age or recenty of use. * Does not iterate over stale values. */ forEach( fn: (v: V, k: K, self: LRUCache) => any, thisp: any = this ) { for (const i of this.#indexes()) { const v = this.#valList[i] const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v if (value === undefined) continue fn.call(thisp, value, this.#keyList[i] as K, this) } } /** * The same as {@link LRUCache.forEach} but items are iterated over in * reverse order. (ie, less recently used items are iterated over first.) */ rforEach( fn: (v: V, k: K, self: LRUCache) => any, thisp: any = this ) { for (const i of this.#rindexes()) { const v = this.#valList[i] const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v if (value === undefined) continue fn.call(thisp, value, this.#keyList[i] as K, this) } } /** * Delete any stale entries. Returns true if anything was removed, * false otherwise. */ purgeStale() { let deleted = false for (const i of this.#rindexes({ allowStale: true })) { if (this.#isStale(i)) { this.delete(this.#keyList[i] as K) deleted = true } } return deleted } /** * Return an array of [key, {@link LRUCache.Entry}] tuples which can be * passed to cache.load() */ dump() { const arr: [K, LRUCache.Entry][] = [] for (const i of this.#indexes({ allowStale: true })) { const key = this.#keyList[i] const v = this.#valList[i] const value: V | undefined = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v if (value === undefined || key === undefined) continue const entry: LRUCache.Entry = { value } if (this.#ttls && this.#starts) { entry.ttl = this.#ttls[i] // always dump the start relative to a portable timestamp // it's ok for this to be a bit slow, it's a rare operation. const age = perf.now() - this.#starts[i] entry.start = Math.floor(Date.now() - age) } if (this.#sizes) { entry.size = this.#sizes[i] } arr.unshift([key, entry]) } return arr } /** * Reset the cache and load in the items in entries in the order listed. * Note that the shape of the resulting cache may be different if the * same options are not used in both caches. */ load(arr: [K, LRUCache.Entry][]) { this.clear() for (const [key, entry] of arr) { if (entry.start) { // entry.start is a portable timestamp, but we may be using // node's performance.now(), so calculate the offset, so that // we get the intended remaining TTL, no matter how long it's // been on ice. // // it's ok for this to be a bit slow, it's a rare operation. const age = Date.now() - entry.start entry.start = perf.now() - age } this.set(key, entry.value, entry) } } /** * Add a value to the cache. * * Note: if `undefined` is specified as a value, this is an alias for * {@link LRUCache#delete} */ set( k: K, v: V | BackgroundFetch | undefined, setOptions: LRUCache.SetOptions = {} ) { if (v === undefined) { this.delete(k) return this } const { ttl = this.ttl, start, noDisposeOnSet = this.noDisposeOnSet, sizeCalculation = this.sizeCalculation, status, } = setOptions let { noUpdateTTL = this.noUpdateTTL } = setOptions const size = this.#requireSize( k, v, setOptions.size || 0, sizeCalculation ) // if the item doesn't fit, don't do anything // NB: maxEntrySize set to maxSize by default if (this.maxEntrySize && size > this.maxEntrySize) { if (status) { status.set = 'miss' status.maxEntrySizeExceeded = true } // have to delete, in case something is there already. this.delete(k) return this } let index = this.#size === 0 ? undefined : this.#keyMap.get(k) if (index === undefined) { // addition index = ( this.#size === 0 ? this.#tail : this.#free.length !== 0 ? this.#free.pop() : this.#size === this.#max ? this.#evict(false) : this.#size ) as Index this.#keyList[index] = k this.#valList[index] = v this.#keyMap.set(k, index) this.#next[this.#tail] = index this.#prev[index] = this.#tail this.#tail = index this.#size++ this.#addItemSize(index, size, status) if (status) status.set = 'add' noUpdateTTL = false } else { // update this.#moveToTail(index) const oldVal = this.#valList[index] as V | BackgroundFetch if (v !== oldVal) { if (this.#hasFetchMethod && this.#isBackgroundFetch(oldVal)) { oldVal.__abortController.abort(new Error('replaced')) const { __staleWhileFetching: s } = oldVal if (s !== undefined && !noDisposeOnSet) { if (this.#hasDispose) { this.#dispose?.(s as V, k, 'set') } if (this.#hasDisposeAfter) { this.#disposed?.push([s as V, k, 'set']) } } } else if (!noDisposeOnSet) { if (this.#hasDispose) { this.#dispose?.(oldVal as V, k, 'set') } if (this.#hasDisposeAfter) { this.#disposed?.push([oldVal as V, k, 'set']) } } this.#removeItemSize(index) this.#addItemSize(index, size, status) this.#valList[index] = v if (status) { status.set = 'replace' const oldValue = oldVal && this.#isBackgroundFetch(oldVal) ? oldVal.__staleWhileFetching : oldVal if (oldValue !== undefined) status.oldValue = oldValue } } else if (status) { status.set = 'update' } } if (ttl !== 0 && !this.#ttls) { this.#initializeTTLTracking() } if (this.#ttls) { if (!noUpdateTTL) { this.#setItemTTL(index, ttl, start) } if (status) this.#statusTTL(status, index) } if (!noDisposeOnSet && this.#hasDisposeAfter && this.#disposed) { const dt = this.#disposed let task: DisposeTask | undefined while ((task = dt?.shift())) { this.#disposeAfter?.(...task) } } return this } /** * Evict the least recently used item, returning its value or * `undefined` if cache is empty. */ pop(): V | undefined { try { while (this.#size) { const val = this.#valList[this.#head] this.#evict(true) if (this.#isBackgroundFetch(val)) { if (val.__staleWhileFetching) { return val.__staleWhileFetching } } else if (val !== undefined) { return val } } } finally { if (this.#hasDisposeAfter && this.#disposed) { const dt = this.#disposed let task: DisposeTask | undefined while ((task = dt?.shift())) { this.#disposeAfter?.(...task) } } } } #evict(free: boolean) { const head = this.#head const k = this.#keyList[head] as K const v = this.#valList[head] as V if (this.#hasFetchMethod && this.#isBackgroundFetch(v)) { v.__abortController.abort(new Error('evicted')) } else if (this.#hasDispose || this.#hasDisposeAfter) { if (this.#hasDispose) { this.#dispose?.(v, k, 'evict') } if (this.#hasDisposeAfter) { this.#disposed?.push([v, k, 'evict']) } } this.#removeItemSize(head) // if we aren't about to use the index, then null these out if (free) { this.#keyList[head] = undefined this.#valList[head] = undefined this.#free.push(head) } if (this.#size === 1) { this.#head = this.#tail = 0 as Index this.#free.length = 0 } else { this.#head = this.#next[head] as Index } this.#keyMap.delete(k) this.#size-- return head } /** * Check if a key is in the cache, without updating the recency of use. * Will return false if the item is stale, even though it is technically * in the cache. * * Will not update item age unless * {@link LRUCache.OptionsBase.updateAgeOnHas} is set. */ has(k: K, hasOptions: LRUCache.HasOptions = {}) { const { updateAgeOnHas = this.updateAgeOnHas, status } = hasOptions const index = this.#keyMap.get(k) if (index !== undefined) { const v = this.#valList[index] if ( this.#isBackgroundFetch(v) && v.__staleWhileFetching === undefined ) { return false } if (!this.#isStale(index)) { if (updateAgeOnHas) { this.#updateItemAge(index) } if (status) { status.has = 'hit' this.#statusTTL(status, index) } return true } else if (status) { status.has = 'stale' this.#statusTTL(status, index) } } else if (status) { status.has = 'miss' } return false } /** * Like {@link LRUCache#get} but doesn't update recency or delete stale * items. * * Returns `undefined` if the item is stale, unless * {@link LRUCache.OptionsBase.allowStale} is set. */ peek(k: K, peekOptions: LRUCache.PeekOptions = {}) { const { allowStale = this.allowStale } = peekOptions const index = this.#keyMap.get(k) if ( index !== undefined && (allowStale || !this.#isStale(index)) ) { const v = this.#valList[index] // either stale and allowed, or forcing a refresh of non-stale value return this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v } } #backgroundFetch( k: K, index: Index | undefined, options: LRUCache.FetchOptions, context: any ): BackgroundFetch { const v = index === undefined ? undefined : this.#valList[index] if (this.#isBackgroundFetch(v)) { return v } const ac = new AC() const { signal } = options // when/if our AC signals, then stop listening to theirs. signal?.addEventListener('abort', () => ac.abort(signal.reason), { signal: ac.signal, }) const fetchOpts = { signal: ac.signal, options, context, } const cb = ( v: V | undefined, updateCache = false ): V | undefined => { const { aborted } = ac.signal const ignoreAbort = options.ignoreFetchAbort && v !== undefined if (options.status) { if (aborted && !updateCache) { options.status.fetchAborted = true options.status.fetchError = ac.signal.reason if (ignoreAbort) options.status.fetchAbortIgnored = true } else { options.status.fetchResolved = true } } if (aborted && !ignoreAbort && !updateCache) { return fetchFail(ac.signal.reason) } // either we didn't abort, and are still here, or we did, and ignored const bf = p as BackgroundFetch if (this.#valList[index as Index] === p) { if (v === undefined) { if (bf.__staleWhileFetching) { this.#valList[index as Index] = bf.__staleWhileFetching } else { this.delete(k) } } else { if (options.status) options.status.fetchUpdated = true this.set(k, v, fetchOpts.options) } } return v } const eb = (er: any) => { if (options.status) { options.status.fetchRejected = true options.status.fetchError = er } return fetchFail(er) } const fetchFail = (er: any): V | undefined => { const { aborted } = ac.signal const allowStaleAborted = aborted && options.allowStaleOnFetchAbort const allowStale = allowStaleAborted || options.allowStaleOnFetchRejection const noDelete = allowStale || options.noDeleteOnFetchRejection const bf = p as BackgroundFetch if (this.#valList[index as Index] === p) { // if we allow stale on fetch rejections, then we need to ensure that // the stale value is not removed from the cache when the fetch fails. const del = !noDelete || bf.__staleWhileFetching === undefined if (del) { this.delete(k) } else if (!allowStaleAborted) { // still replace the *promise* with the stale value, // since we are done with the promise at this point. // leave it untouched if we're still waiting for an // aborted background fetch that hasn't yet returned. this.#valList[index as Index] = bf.__staleWhileFetching } } if (allowStale) { if (options.status && bf.__staleWhileFetching !== undefined) { options.status.returnedStale = true } return bf.__staleWhileFetching } else if (bf.__returned === bf) { throw er } } const pcall = ( res: (v: V | undefined) => void, rej: (e: any) => void ) => { const fmp = this.#fetchMethod?.(k, v, fetchOpts) if (fmp && fmp instanceof Promise) { fmp.then(v => res(v === undefined ? undefined : v), rej) } // ignored, we go until we finish, regardless. // defer check until we are actually aborting, // so fetchMethod can override. ac.signal.addEventListener('abort', () => { if ( !options.ignoreFetchAbort || options.allowStaleOnFetchAbort ) { res(undefined) // when it eventually resolves, update the cache. if (options.allowStaleOnFetchAbort) { res = v => cb(v, true) } } }) } if (options.status) options.status.fetchDispatched = true const p = new Promise(pcall).then(cb, eb) const bf: BackgroundFetch = Object.assign(p, { __abortController: ac, __staleWhileFetching: v, __returned: undefined, }) if (index === undefined) { // internal, don't expose status. this.set(k, bf, { ...fetchOpts.options, status: undefined }) index = this.#keyMap.get(k) } else { this.#valList[index] = bf } return bf } #isBackgroundFetch(p: any): p is BackgroundFetch { if (!this.#hasFetchMethod) return false const b = p as BackgroundFetch return ( !!b && b instanceof Promise && b.hasOwnProperty('__staleWhileFetching') && b.__abortController instanceof AC ) } /** * Make an asynchronous cached fetch using the * {@link LRUCache.OptionsBase.fetchMethod} function. * * If multiple fetches for the same key are issued, then they will all be * coalesced into a single call to fetchMethod. * * Note that this means that handling options such as * {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}, * {@link LRUCache.FetchOptions.signal}, * and {@link LRUCache.OptionsBase.allowStaleOnFetchRejection} will be * determined by the FIRST fetch() call for a given key. * * This is a known (fixable) shortcoming which will be addresed on when * someone complains about it, as the fix would involve added complexity and * may not be worth the costs for this edge case. */ fetch( k: K, fetchOptions: unknown extends FC ? LRUCache.FetchOptions : FC extends undefined | void ? LRUCache.FetchOptionsNoContext : LRUCache.FetchOptionsWithContext ): Promise // this overload not allowed if context is required fetch( k: unknown extends FC ? K : FC extends undefined | void ? K : never, fetchOptions?: unknown extends FC ? LRUCache.FetchOptions : FC extends undefined | void ? LRUCache.FetchOptionsNoContext : never ): Promise async fetch( k: K, fetchOptions: LRUCache.FetchOptions = {} ): Promise { const { // get options allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, // set options ttl = this.ttl, noDisposeOnSet = this.noDisposeOnSet, size = 0, sizeCalculation = this.sizeCalculation, noUpdateTTL = this.noUpdateTTL, // fetch exclusive options noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, ignoreFetchAbort = this.ignoreFetchAbort, allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, context, forceRefresh = false, status, signal, } = fetchOptions if (!this.#hasFetchMethod) { if (status) status.fetch = 'get' return this.get(k, { allowStale, updateAgeOnGet, noDeleteOnStaleGet, status, }) } const options = { allowStale, updateAgeOnGet, noDeleteOnStaleGet, ttl, noDisposeOnSet, size, sizeCalculation, noUpdateTTL, noDeleteOnFetchRejection, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort, status, signal, } let index = this.#keyMap.get(k) if (index === undefined) { if (status) status.fetch = 'miss' const p = this.#backgroundFetch(k, index, options, context) return (p.__returned = p) } else { // in cache, maybe already fetching const v = this.#valList[index] if (this.#isBackgroundFetch(v)) { const stale = allowStale && v.__staleWhileFetching !== undefined if (status) { status.fetch = 'inflight' if (stale) status.returnedStale = true } return stale ? v.__staleWhileFetching : (v.__returned = v) } // if we force a refresh, that means do NOT serve the cached value, // unless we are already in the process of refreshing the cache. const isStale = this.#isStale(index) if (!forceRefresh && !isStale) { if (status) status.fetch = 'hit' this.#moveToTail(index) if (updateAgeOnGet) { this.#updateItemAge(index) } if (status) this.#statusTTL(status, index) return v } // ok, it is stale or a forced refresh, and not already fetching. // refresh the cache. const p = this.#backgroundFetch(k, index, options, context) const hasStale = p.__staleWhileFetching !== undefined const staleVal = hasStale && allowStale if (status) { status.fetch = isStale ? 'stale' : 'refresh' if (staleVal && isStale) status.returnedStale = true } return staleVal ? p.__staleWhileFetching : (p.__returned = p) } } /** * Return a value from the cache. Will update the recency of the cache * entry found. * * If the key is not found, get() will return `undefined`. */ get(k: K, getOptions: LRUCache.GetOptions = {}) { const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, status, } = getOptions const index = this.#keyMap.get(k) if (index !== undefined) { const value = this.#valList[index] const fetching = this.#isBackgroundFetch(value) if (status) this.#statusTTL(status, index) if (this.#isStale(index)) { if (status) status.get = 'stale' // delete only if not an in-flight background fetch if (!fetching) { if (!noDeleteOnStaleGet) { this.delete(k) } if (status && allowStale) status.returnedStale = true return allowStale ? value : undefined } else { if ( status && allowStale && value.__staleWhileFetching !== undefined ) { status.returnedStale = true } return allowStale ? value.__staleWhileFetching : undefined } } else { if (status) status.get = 'hit' // if we're currently fetching it, we don't actually have it yet // it's not stale, which means this isn't a staleWhileRefetching. // If it's not stale, and fetching, AND has a __staleWhileFetching // value, then that means the user fetched with {forceRefresh:true}, // so it's safe to return that value. if (fetching) { return value.__staleWhileFetching } this.#moveToTail(index) if (updateAgeOnGet) { this.#updateItemAge(index) } return value } } else if (status) { status.get = 'miss' } } #connect(p: Index, n: Index) { this.#prev[n] = p this.#next[p] = n } #moveToTail(index: Index): void { // if tail already, nothing to do // if head, move head to next[index] // else // move next[prev[index]] to next[index] (head has no prev) // move prev[next[index]] to prev[index] // prev[index] = tail // next[tail] = index // tail = index if (index !== this.#tail) { if (index === this.#head) { this.#head = this.#next[index] as Index } else { this.#connect( this.#prev[index] as Index, this.#next[index] as Index ) } this.#connect(this.#tail, index) this.#tail = index } } /** * Deletes a key out of the cache. * Returns true if the key was deleted, false otherwise. */ delete(k: K) { let deleted = false if (this.#size !== 0) { const index = this.#keyMap.get(k) if (index !== undefined) { deleted = true if (this.#size === 1) { this.clear() } else { this.#removeItemSize(index) const v = this.#valList[index] if (this.#isBackgroundFetch(v)) { v.__abortController.abort(new Error('deleted')) } else if (this.#hasDispose || this.#hasDisposeAfter) { if (this.#hasDispose) { this.#dispose?.(v as V, k, 'delete') } if (this.#hasDisposeAfter) { this.#disposed?.push([v as V, k, 'delete']) } } this.#keyMap.delete(k) this.#keyList[index] = undefined this.#valList[index] = undefined if (index === this.#tail) { this.#tail = this.#prev[index] as Index } else if (index === this.#head) { this.#head = this.#next[index] as Index } else { this.#next[this.#prev[index]] = this.#next[index] this.#prev[this.#next[index]] = this.#prev[index] } this.#size-- this.#free.push(index) } } } if (this.#hasDisposeAfter && this.#disposed?.length) { const dt = this.#disposed let task: DisposeTask | undefined while ((task = dt?.shift())) { this.#disposeAfter?.(...task) } } return deleted } /** * Clear the cache entirely, throwing away all values. */ clear() { for (const index of this.#rindexes({ allowStale: true })) { const v = this.#valList[index] if (this.#isBackgroundFetch(v)) { v.__abortController.abort(new Error('deleted')) } else { const k = this.#keyList[index] if (this.#hasDispose) { this.#dispose?.(v as V, k as K, 'delete') } if (this.#hasDisposeAfter) { this.#disposed?.push([v as V, k as K, 'delete']) } } } this.#keyMap.clear() this.#valList.fill(undefined) this.#keyList.fill(undefined) if (this.#ttls && this.#starts) { this.#ttls.fill(0) this.#starts.fill(0) } if (this.#sizes) { this.#sizes.fill(0) } this.#head = 0 as Index this.#tail = 0 as Index this.#free.length = 0 this.#calculatedSize = 0 this.#size = 0 if (this.#hasDisposeAfter && this.#disposed) { const dt = this.#disposed let task: DisposeTask | undefined while ((task = dt?.shift())) { this.#disposeAfter?.(...task) } } } } node-lru-cache-10.0.1/tap-snapshots/000077500000000000000000000000001446525347600172035ustar00rootroot00000000000000node-lru-cache-10.0.1/tap-snapshots/test/000077500000000000000000000000001446525347600201625ustar00rootroot00000000000000node-lru-cache-10.0.1/tap-snapshots/test/basic.ts.test.cjs000066400000000000000000000120111446525347600233420ustar00rootroot00000000000000/* IMPORTANT * This snapshot file is auto-generated, but designed for humans. * It should be checked into source control and tracked carefully. * Re-generate by setting TAP_SNAPSHOT=1 and running tests. * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' exports[`test/basic.ts TAP basic operation > must match snapshot 1`] = ` Generator [ Array [ 4, 4, ], Array [ 3, 3, ], Array [ 2, 2, ], Array [ 1, 1, ], Array [ 0, 0, ], ] ` exports[`test/basic.ts TAP basic operation > must match snapshot 2`] = ` Generator [ Array [ 9, 9, ], Array [ 8, 8, ], Array [ 7, 7, ], Array [ 6, 6, ], Array [ 5, 5, ], Array [ 4, 4, ], Array [ 3, 3, ], Array [ 2, 2, ], Array [ 1, 1, ], Array [ 0, 0, ], ] ` exports[`test/basic.ts TAP basic operation > must match snapshot 3`] = ` Generator [ Array [ 4, 4, ], Array [ 3, 3, ], Array [ 2, 2, ], Array [ 1, 1, ], Array [ 0, 0, ], Array [ 9, 9, ], Array [ 8, 8, ], Array [ 7, 7, ], Array [ 6, 6, ], Array [ 5, 5, ], ] ` exports[`test/basic.ts TAP basic operation > must match snapshot 4`] = ` Generator [ Array [ 14, 14, ], Array [ 13, 13, ], Array [ 12, 12, ], Array [ 11, 11, ], Array [ 10, 10, ], Array [ 9, 9, ], Array [ 8, 8, ], Array [ 7, 7, ], Array [ 6, 6, ], Array [ 5, 5, ], ] ` exports[`test/basic.ts TAP basic operation > must match snapshot 5`] = ` Generator [ Array [ 19, 19, ], Array [ 18, 18, ], Array [ 17, 17, ], Array [ 16, 16, ], Array [ 15, 15, ], Array [ 14, 14, ], Array [ 13, 13, ], Array [ 12, 12, ], Array [ 11, 11, ], Array [ 10, 10, ], ] ` exports[`test/basic.ts TAP basic operation > must match snapshot 6`] = ` Generator [ Array [ 19, 19, ], Array [ 18, 18, ], Array [ 17, 17, ], Array [ 16, 16, ], Array [ 15, 15, ], Array [ 14, 14, ], Array [ 13, 13, ], Array [ 12, 12, ], Array [ 11, 11, ], Array [ 10, 10, ], ] ` exports[`test/basic.ts TAP basic operation > status tracking 1`] = ` Array [ Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "update", }, Object { "set": "update", }, Object { "set": "update", }, Object { "set": "update", }, Object { "set": "update", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "get": "hit", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "get": "miss", }, Object { "get": "miss", }, Object { "get": "miss", }, Object { "get": "miss", }, Object { "get": "miss", }, Object { "get": "miss", }, Object { "get": "miss", }, Object { "get": "miss", }, Object { "get": "miss", }, Object { "get": "miss", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "has": "hit", }, Object { "set": "add", }, Object { "has": "hit", }, Object { "get": "hit", }, Object { "has": "miss", }, ] ` exports[`test/basic.ts TAP re-use key before initial fill completed > must match snapshot 1`] = ` Array [ Object { "set": "add", }, Object { "set": "add", }, Object { "set": "add", }, Object { "oldValue": 1, "set": "replace", }, Object { "set": "add", }, ] ` node-lru-cache-10.0.1/tap-snapshots/test/deprecations.ts.test.cjs000066400000000000000000000062671446525347600247610ustar00rootroot00000000000000/* IMPORTANT * This snapshot file is auto-generated, but designed for humans. * It should be checked into source control and tracked carefully. * Re-generate by setting TAP_SNAPSHOT=1 and running tests. * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' exports[`test/deprecations.ts TAP does not do deprecation warning without process object > warnings sent to console.error 1`] = ` Array [ Array [ "The stale option is deprecated. Please use options.allowStale instead.", "DeprecationWarning", "LRU_CACHE_OPTION_stale", Function LRUCache(classLRUCache), ], Array [ "The maxAge option is deprecated. Please use options.ttl instead.", "DeprecationWarning", "LRU_CACHE_OPTION_maxAge", Function LRUCache(classLRUCache), ], Array [ "The length option is deprecated. Please use options.sizeCalculation instead.", "DeprecationWarning", "LRU_CACHE_OPTION_length", Function LRUCache(classLRUCache), ], Array [ "The reset method is deprecated. Please use cache.clear() instead.", "DeprecationWarning", "LRU_CACHE_METHOD_reset", Function get reset(), ], Array [ "The length property is deprecated. Please use cache.size instead.", "DeprecationWarning", "LRU_CACHE_PROPERTY_length", Function get length(), ], Array [ "The prune method is deprecated. Please use cache.purgeStale() instead.", "DeprecationWarning", "LRU_CACHE_METHOD_prune", Function get prune(), ], Array [ "The del method is deprecated. Please use cache.delete() instead.", "DeprecationWarning", "LRU_CACHE_METHOD_del", Function get del(), ], ] ` exports[`test/deprecations.ts TAP warns exactly once for a given deprecation > must match snapshot 1`] = ` Array [ Array [ "The stale option is deprecated. Please use options.allowStale instead.", "DeprecationWarning", "LRU_CACHE_OPTION_stale", Function LRUCache(classLRUCache), ], Array [ "The maxAge option is deprecated. Please use options.ttl instead.", "DeprecationWarning", "LRU_CACHE_OPTION_maxAge", Function LRUCache(classLRUCache), ], Array [ "The length option is deprecated. Please use options.sizeCalculation instead.", "DeprecationWarning", "LRU_CACHE_OPTION_length", Function LRUCache(classLRUCache), ], Array [ "The reset method is deprecated. Please use cache.clear() instead.", "DeprecationWarning", "LRU_CACHE_METHOD_reset", Function get reset(), ], Array [ "The length property is deprecated. Please use cache.size instead.", "DeprecationWarning", "LRU_CACHE_PROPERTY_length", Function get length(), ], Array [ "The prune method is deprecated. Please use cache.purgeStale() instead.", "DeprecationWarning", "LRU_CACHE_METHOD_prune", Function get prune(), ], Array [ "The del method is deprecated. Please use cache.delete() instead.", "DeprecationWarning", "LRU_CACHE_METHOD_del", Function get del(), ], Array [ "TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.", "UnboundedCacheWarning", "LRU_CACHE_UNBOUNDED", Function LRUCache(classLRUCache), ], ] ` node-lru-cache-10.0.1/tap-snapshots/test/fetch.ts.test.cjs000066400000000000000000000123141446525347600233600ustar00rootroot00000000000000/* IMPORTANT * This snapshot file is auto-generated, but designed for humans. * It should be checked into source control and tracked carefully. * Re-generate by setting TAP_SNAPSHOT=1 and running tests. * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' exports[`test/fetch.ts TAP asynchronous fetching > safe to stringify dump 1`] = ` [["key",{"value":1,"ttl":5,"start":11}]] ` exports[`test/fetch.ts TAP asynchronous fetching > status 1 1`] = ` Object { "fetch": "miss", "fetchDispatched": true, "fetchResolved": true, "fetchUpdated": true, "now": 1, "remainingTTL": 5, "set": "replace", "start": 1, "ttl": 5, } ` exports[`test/fetch.ts TAP asynchronous fetching > status 2 1`] = ` Object { "fetch": "hit", "now": 1, "remainingTTL": 5, "start": 1, "ttl": 5, } ` exports[`test/fetch.ts TAP asynchronous fetching > status 3 1`] = ` Object { "fetch": "stale", "fetchDispatched": true, "returnedStale": true, } ` exports[`test/fetch.ts TAP asynchronous fetching > status 3.1 1`] = ` Object { "fetch": "inflight", "returnedStale": true, } ` exports[`test/fetch.ts TAP asynchronous fetching > status 4 1`] = ` Object { "fetch": "inflight", } ` exports[`test/fetch.ts TAP asynchronous fetching > status 5 1`] = ` Object { "fetch": "hit", "now": 11, "remainingTTL": 5, "start": 11, "ttl": 5, } ` exports[`test/fetch.ts TAP fetch options, signal > status updates 1`] = ` Array [ Object { "fetch": "miss", "fetchAborted": true, "fetchDispatched": true, "fetchError": Error: deleted { "name": "Error", }, }, Object { "fetch": "miss", "fetchAborted": true, "fetchDispatched": true, "fetchError": Error: replaced { "name": "Error", }, }, Object { "fetch": "miss", "fetchAborted": true, "fetchDispatched": true, "fetchError": Error: evicted { "name": "Error", }, }, Object { "now": 721, "remainingTTL": 100, "set": "add", "start": 721, "ttl": 100, }, Object { "now": 721, "remainingTTL": 100, "set": "add", "start": 721, "ttl": 100, }, Object { "now": 721, "remainingTTL": 100, "set": "add", "start": 721, "ttl": 100, }, Object { "fetch": "miss", "fetchDispatched": true, "fetchResolved": true, "fetchUpdated": true, "now": 721, "remainingTTL": 1000, "set": "replace", "start": 721, "ttl": 1000, }, Object { "fetch": "miss", "fetchDispatched": true, "fetchResolved": true, "fetchUpdated": true, "now": 721, "remainingTTL": 25, "set": "replace", "start": 721, "ttl": 25, }, ] ` exports[`test/fetch.ts TAP fetch without fetch method > status update 1`] = ` Object { "fetch": "get", "get": "hit", } ` exports[`test/fetch.ts TAP fetchMethod throws > status updates 1`] = ` Array [ Object { "now": 721, "remainingTTL": 10, "set": "add", "start": 721, "ttl": 10, }, Object { "now": 721, "remainingTTL": 10, "set": "add", "start": 721, "ttl": 10, }, Object { "fetch": "stale", "fetchDispatched": true, "fetchError": Error: fetch failure, "fetchRejected": true, "returnedStale": true, }, Object { "fetch": "inflight", "returnedStale": true, }, Object { "fetch": "inflight", "returnedStale": true, }, Object { "get": "miss", }, Object { "fetch": "stale", "fetchDispatched": true, "fetchError": Error: fetch failure, "fetchRejected": true, "returnedStale": true, }, Object { "fetch": "inflight", "returnedStale": true, }, Object { "fetch": "inflight", "returnedStale": true, }, Object { "get": "miss", }, Object { "fetch": "miss", "fetchAborted": true, "fetchDispatched": true, "fetchError": Error: replaced { "name": "Error", }, }, Object { "now": 781, "remainingTTL": 10, "set": "replace", "start": 781, "ttl": 10, }, Object { "get": "hit", "now": 781, "remainingTTL": 10, "start": 781, "ttl": 10, }, Object { "fetch": "miss", "fetchDispatched": true, }, ] ` exports[`test/fetch.ts TAP forceRefresh > status updates 1`] = ` Array [ Object { "fetch": "refresh", "fetchDispatched": true, "fetchResolved": true, "fetchUpdated": true, "now": 941, "oldValue": 2, "remainingTTL": 100, "set": "replace", "start": 941, "ttl": 100, }, Object { "fetch": "inflight", }, Object { "fetch": "refresh", "fetchDispatched": true, "fetchResolved": true, "fetchUpdated": true, "now": 941, "oldValue": 100, "remainingTTL": 100, "set": "replace", "start": 941, "ttl": 100, }, ] ` exports[`test/fetch.ts TAP send a signal > status updates 1`] = ` Array [ Object { "fetch": "miss", "fetchAborted": true, "fetchDispatched": true, "fetchError": Error: custom abort signal { "name": "Error", }, }, Object { "get": "miss", }, ] ` exports[`test/fetch.ts TAP verify inflight works as expected > status updates 1`] = ` Array [ Object { "fetch": "inflight", }, Object { "fetch": "inflight", }, Object { "get": "hit", }, ] ` node-lru-cache-10.0.1/tap-snapshots/test/map-like.ts.test.cjs000066400000000000000000000264721446525347600240000ustar00rootroot00000000000000/* IMPORTANT * This snapshot file is auto-generated, but designed for humans. * It should be checked into source control and tracked carefully. * Re-generate by setting TAP_SNAPSHOT=1 and running tests. * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' exports[`test/map-like.ts TAP bunch of iteration things > dump 1`] = ` Array [ Array [ 3, Object { "size": 1, "value": "3", }, ], Array [ 4, Object { "size": 1, "value": "4", }, ], Array [ 5, Object { "size": 1, "value": "5", }, ], Array [ 6, Object { "size": 1, "value": "6", }, ], Array [ 7, Object { "size": 1, "value": "7", }, ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > dump, 7 stale 1`] = ` Array [ Array [ 3, Object { "size": 1, "start": 0, "ttl": 0, "value": "3", }, ], Array [ 5, Object { "size": 1, "start": 0, "ttl": 0, "value": "5", }, ], Array [ 6, Object { "size": 1, "start": 0, "ttl": 0, "value": "6", }, ], Array [ 4, Object { "size": 1, "start": 0, "ttl": 0, "value": "new value 4", }, ], Array [ 7, Object { "size": 1, "start": -10000, "ttl": 1, "value": "stale", }, ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > dump, new value 4 1`] = ` Array [ Array [ 3, Object { "size": 1, "value": "3", }, ], Array [ 5, Object { "size": 1, "value": "5", }, ], Array [ 6, Object { "size": 1, "value": "6", }, ], Array [ 7, Object { "size": 1, "value": "7", }, ], Array [ 4, Object { "size": 1, "value": "new value 4", }, ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > dump, resolved fetch 99 too late 1`] = ` Array [ Array [ 3, Object { "size": 1, "value": "3", }, ], Array [ 5, Object { "size": 1, "value": "5", }, ], Array [ 6, Object { "size": 1, "value": "6", }, ], Array [ 7, Object { "size": 1, "value": "7", }, ], Array [ 4, Object { "size": 1, "value": "new value 4", }, ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > empty, dump 1`] = ` Array [] ` exports[`test/map-like.ts TAP bunch of iteration things > empty, entries 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > empty, foreach 1`] = ` Array [] ` exports[`test/map-like.ts TAP bunch of iteration things > empty, keys 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > empty, rentries 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > empty, rforeach 1`] = ` Array [] ` exports[`test/map-like.ts TAP bunch of iteration things > empty, rkeys 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > empty, rvalues 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > empty, values 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > entries 1`] = ` Generator [ Array [ 7, "7", ], Array [ 6, "6", ], Array [ 5, "5", ], Array [ 4, "4", ], Array [ 3, "3", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > entries, 7 stale 1`] = ` Generator [ Array [ 4, "new value 4", ], Array [ 6, "6", ], Array [ 5, "5", ], Array [ 3, "3", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > entries, new value 4 1`] = ` Generator [ Array [ 4, "new value 4", ], Array [ 7, "7", ], Array [ 6, "6", ], Array [ 5, "5", ], Array [ 3, "3", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > entries, resolved fetch 99 too late 1`] = ` Generator [ Array [ 4, "new value 4", ], Array [ 7, "7", ], Array [ 6, "6", ], Array [ 5, "5", ], Array [ 3, "3", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > fetch 123 resolved, dump 1`] = ` Array [ Array [ 0, Object { "size": 1, "value": "0", }, ], Array [ 1, Object { "size": 1, "value": "1", }, ], Array [ 2, Object { "size": 1, "value": "2", }, ], Array [ 123, Object { "size": 1, "value": "123", }, ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > fetch 123 resolved, entries 1`] = ` Generator [ Array [ 123, "123", ], Array [ 2, "2", ], Array [ 1, "1", ], Array [ 0, "0", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > fetch 123 resolved, foreach 1`] = ` Array [ Array [ 123, "123", ], Array [ 2, "2", ], Array [ 1, "1", ], Array [ 0, "0", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > fetch 123 resolved, keys 1`] = ` Generator [ 123, 2, 1, 0, ] ` exports[`test/map-like.ts TAP bunch of iteration things > fetch 123 resolved, rentries 1`] = ` Generator [ Array [ 0, "0", ], Array [ 1, "1", ], Array [ 2, "2", ], Array [ 123, "123", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > fetch 123 resolved, rforeach 1`] = ` Array [ Array [ 0, "0", ], Array [ 1, "1", ], Array [ 2, "2", ], Array [ 123, "123", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > fetch 123 resolved, rkeys 1`] = ` Generator [ 0, 1, 2, 123, ] ` exports[`test/map-like.ts TAP bunch of iteration things > fetch 123 resolved, rvalues 1`] = ` Generator [ "0", "1", "2", "123", ] ` exports[`test/map-like.ts TAP bunch of iteration things > fetch 123 resolved, values 1`] = ` Generator [ "123", "2", "1", "0", ] ` exports[`test/map-like.ts TAP bunch of iteration things > forEach, no thisp 1`] = ` Array [ Array [ "new value 4", 4, ], Array [ "6", 6, ], Array [ "5", 5, ], Array [ "3", 3, ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > forEach, with thisp 1`] = ` Array [ Array [ "new value 4", 4, Object { "a": 1, }, ], Array [ "6", 6, Object { "a": 1, }, ], Array [ "5", 5, Object { "a": 1, }, ], Array [ "3", 3, Object { "a": 1, }, ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > forEach, with thisp 2`] = ` Array [ Array [ "3", 3, Object { "r": 1, }, ], Array [ "5", 5, Object { "r": 1, }, ], Array [ "6", 6, Object { "r": 1, }, ], Array [ "new value 4", 4, Object { "r": 1, }, ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > keys 1`] = ` Generator [ 7, 6, 5, 4, 3, ] ` exports[`test/map-like.ts TAP bunch of iteration things > keys, 7 stale 1`] = ` Generator [ 4, 6, 5, 3, ] ` exports[`test/map-like.ts TAP bunch of iteration things > keys, new value 4 1`] = ` Generator [ 4, 7, 6, 5, 3, ] ` exports[`test/map-like.ts TAP bunch of iteration things > keys, resolved fetch 99 too late 1`] = ` Generator [ 4, 7, 6, 5, 3, ] ` exports[`test/map-like.ts TAP bunch of iteration things > pending fetch, dump 1`] = ` Array [] ` exports[`test/map-like.ts TAP bunch of iteration things > pending fetch, entries 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > pending fetch, foreach 1`] = ` Array [] ` exports[`test/map-like.ts TAP bunch of iteration things > pending fetch, keys 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > pending fetch, rentries 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > pending fetch, rforeach 1`] = ` Array [] ` exports[`test/map-like.ts TAP bunch of iteration things > pending fetch, rkeys 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > pending fetch, rvalues 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > pending fetch, values 1`] = ` Generator [] ` exports[`test/map-like.ts TAP bunch of iteration things > rentries 1`] = ` Generator [ Array [ 3, "3", ], Array [ 4, "4", ], Array [ 5, "5", ], Array [ 6, "6", ], Array [ 7, "7", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > rentries, 7 stale 1`] = ` Generator [ Array [ 3, "3", ], Array [ 5, "5", ], Array [ 6, "6", ], Array [ 4, "new value 4", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > rentries, new value 4 1`] = ` Generator [ Array [ 3, "3", ], Array [ 5, "5", ], Array [ 6, "6", ], Array [ 7, "7", ], Array [ 4, "new value 4", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > rentries, resolved fetch 99 too late 1`] = ` Generator [ Array [ 3, "3", ], Array [ 5, "5", ], Array [ 6, "6", ], Array [ 7, "7", ], Array [ 4, "new value 4", ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > rforEach, no thisp 1`] = ` Array [ Array [ "3", 3, ], Array [ "5", 5, ], Array [ "6", 6, ], Array [ "new value 4", 4, ], ] ` exports[`test/map-like.ts TAP bunch of iteration things > rkeys 1`] = ` Generator [ 3, 4, 5, 6, 7, ] ` exports[`test/map-like.ts TAP bunch of iteration things > rkeys, 7 stale 1`] = ` Generator [ 3, 5, 6, 4, ] ` exports[`test/map-like.ts TAP bunch of iteration things > rkeys, new value 4 1`] = ` Generator [ 3, 5, 6, 7, 4, ] ` exports[`test/map-like.ts TAP bunch of iteration things > rkeys, resolved fetch 99 too late 1`] = ` Generator [ 3, 5, 6, 7, 4, ] ` exports[`test/map-like.ts TAP bunch of iteration things > rvalues 1`] = ` Generator [ "3", "4", "5", "6", "7", ] ` exports[`test/map-like.ts TAP bunch of iteration things > rvalues, 7 stale 1`] = ` Generator [ "3", "5", "6", "new value 4", ] ` exports[`test/map-like.ts TAP bunch of iteration things > rvalues, new value 4 1`] = ` Generator [ "3", "5", "6", "7", "new value 4", ] ` exports[`test/map-like.ts TAP bunch of iteration things > rvalues, resolved fetch 99 too late 1`] = ` Generator [ "3", "5", "6", "7", "new value 4", ] ` exports[`test/map-like.ts TAP bunch of iteration things > values 1`] = ` Generator [ "7", "6", "5", "4", "3", ] ` exports[`test/map-like.ts TAP bunch of iteration things > values, 7 stale 1`] = ` Generator [ "new value 4", "6", "5", "3", ] ` exports[`test/map-like.ts TAP bunch of iteration things > values, new value 4 1`] = ` Generator [ "new value 4", "7", "6", "5", "3", ] ` exports[`test/map-like.ts TAP bunch of iteration things > values, resolved fetch 99 too late 1`] = ` Generator [ "new value 4", "7", "6", "5", "3", ] ` node-lru-cache-10.0.1/tap-snapshots/test/move-to-tail.ts.test.cjs000066400000000000000000000041661446525347600246120ustar00rootroot00000000000000/* IMPORTANT * This snapshot file is auto-generated, but designed for humans. * It should be checked into source control and tracked carefully. * Re-generate by setting TAP_SNAPSHOT=1 and running tests. * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' exports[`test/move-to-tail.ts TAP list integrity > list after initial fill 1`] = ` Array [ Object { "_": "H", "head": 0, "index": 0, "next": 1, "prev": 0, "tail": 4, }, Object { "_": "1", "head": 0, "index": 1, "next": 2, "prev": 0, "tail": 4, }, Object { "_": "2", "head": 0, "index": 2, "next": 3, "prev": 1, "tail": 4, }, Object { "_": "3", "head": 0, "index": 3, "next": 4, "prev": 2, "tail": 4, }, Object { "_": "T", "head": 0, "index": 4, "next": 0, "prev": 3, "tail": 4, }, ] ` exports[`test/move-to-tail.ts TAP list integrity > list after moveToTail 2 1`] = ` Array [ Object { "_": "H", "head": 0, "index": 0, "next": 1, "prev": 0, "tail": 2, }, Object { "_": "1", "head": 0, "index": 1, "next": 3, "prev": 0, "tail": 2, }, Object { "_": "T", "head": 0, "index": 2, "next": 3, "prev": 4, "tail": 2, }, Object { "_": "3", "head": 0, "index": 3, "next": 4, "prev": 1, "tail": 2, }, Object { "_": "4", "head": 0, "index": 4, "next": 2, "prev": 3, "tail": 2, }, ] ` exports[`test/move-to-tail.ts TAP list integrity > list after moveToTail 4 1`] = ` Array [ Object { "_": "H", "head": 0, "index": 0, "next": 1, "prev": 0, "tail": 4, }, Object { "_": "1", "head": 0, "index": 1, "next": 3, "prev": 0, "tail": 4, }, Object { "_": "2", "head": 0, "index": 2, "next": 4, "prev": 3, "tail": 4, }, Object { "_": "3", "head": 0, "index": 3, "next": 2, "prev": 1, "tail": 4, }, Object { "_": "T", "head": 0, "index": 4, "next": 2, "prev": 2, "tail": 4, }, ] ` node-lru-cache-10.0.1/tap-snapshots/test/size-calculation.ts.test.cjs000066400000000000000000000025061446525347600255370ustar00rootroot00000000000000/* IMPORTANT * This snapshot file is auto-generated, but designed for humans. * It should be checked into source control and tracked carefully. * Re-generate by setting TAP_SNAPSHOT=1 and running tests. * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' exports[`test/size-calculation.ts TAP large item falls out of cache because maxEntrySize > status updates 1`] = ` Array [ Object { "entrySize": 2, "set": "add", "totalCalculatedSize": 2, }, Object { "maxEntrySizeExceeded": true, "set": "miss", }, Object { "entrySize": 3, "set": "add", "totalCalculatedSize": 3, }, Object { "maxEntrySizeExceeded": true, "set": "miss", }, ] ` exports[`test/size-calculation.ts TAP large item falls out of cache, sizes are kept correct > status updates 1`] = ` Array [ Object { "entrySize": 2, "set": "add", "totalCalculatedSize": 2, }, Object { "maxEntrySizeExceeded": true, "set": "miss", }, Object { "entrySize": 3, "set": "add", "totalCalculatedSize": 3, }, Object { "maxEntrySizeExceeded": true, "set": "miss", }, ] ` exports[`test/size-calculation.ts TAP store strings, size = length > dump 1`] = ` Array [ Array [ "repeated", Object { "size": 10, "value": "jjjjjjjjjj", }, ], ] ` node-lru-cache-10.0.1/tap-snapshots/test/ttl.ts.test.cjs000066400000000000000000000323351446525347600230770ustar00rootroot00000000000000/* IMPORTANT * This snapshot file is auto-generated, but designed for humans. * It should be checked into source control and tracked carefully. * Re-generate by setting TAP_SNAPSHOT=1 and running tests. * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' exports[`test/ttl.ts TAP tests using Date.now() set item pre-stale > dump with stale values 1`] = ` Array [ Array [ 1, Object { "start": 3021, "ttl": 10, "value": 1, }, ], Array [ 2, Object { "start": 3010, "ttl": 10, "value": 2, }, ], ] ` exports[`test/ttl.ts TAP tests using Date.now() ttl on set, not on cache > status updates 1`] = ` Array [ Object { "now": 1964, "remainingTTL": 10, "set": "add", "start": 1964, "ttl": 10, }, Object { "get": "hit", "now": 1964, "remainingTTL": 10, "start": 1964, "ttl": 10, }, Object { "get": "hit", "now": 1969, "remainingTTL": 5, "start": 1964, "ttl": 10, }, Object { "get": "hit", "now": 1974, "remainingTTL": 0, "start": 1964, "ttl": 10, }, Object { "has": "stale", "now": 1975, "remainingTTL": -1, "start": 1964, "ttl": 10, }, Object { "get": "stale", "now": 1975, "remainingTTL": -1, "start": 1964, "ttl": 10, }, Object { "now": 1975, "remainingTTL": 100, "set": "add", "start": 1975, "ttl": 100, }, Object { "has": "hit", "now": 2025, "remainingTTL": 50, "start": 1975, "ttl": 100, }, Object { "get": "hit", "now": 2025, "remainingTTL": 50, "start": 1975, "ttl": 100, }, Object { "has": "stale", "now": 2076, "remainingTTL": -1, "start": 1975, "ttl": 100, }, Object { "get": "stale", "now": 2076, "remainingTTL": -1, "start": 1975, "ttl": 100, }, Object { "now": 2076, "remainingTTL": 10, "set": "add", "start": 2076, "ttl": 10, }, Object { "now": 2076, "remainingTTL": 10, "set": "add", "start": 2076, "ttl": 10, }, Object { "now": 2076, "remainingTTL": 10, "set": "add", "start": 2076, "ttl": 10, }, Object { "now": 2076, "remainingTTL": 10, "set": "add", "start": 2076, "ttl": 10, }, Object { "now": 2076, "remainingTTL": 10, "set": "add", "start": 2076, "ttl": 10, }, Object { "now": 2076, "remainingTTL": 10, "set": "add", "start": 2076, "ttl": 10, }, Object { "now": 2076, "remainingTTL": 10, "set": "add", "start": 2076, "ttl": 10, }, Object { "now": 2076, "remainingTTL": 10, "set": "add", "start": 2076, "ttl": 10, }, Object { "now": 2076, "remainingTTL": 10, "set": "add", "start": 2076, "ttl": 10, }, Object { "has": "stale", "now": 2087, "remainingTTL": -1, "start": 2076, "ttl": 10, }, Object { "get": "stale", "now": 2087, "remainingTTL": -1, "start": 2076, "ttl": 10, }, ] ` exports[`test/ttl.ts TAP tests using Date.now() ttl tests defaults > status updates 1`] = ` Array [ Object { "now": 1517, "remainingTTL": 10, "set": "add", "start": 1517, "ttl": 10, }, Object { "get": "hit", "now": 1517, "remainingTTL": 10, "start": 1517, "ttl": 10, }, Object { "get": "hit", "now": 1522, "remainingTTL": 5, "start": 1517, "ttl": 10, }, Object { "get": "hit", "now": 1527, "remainingTTL": 0, "start": 1517, "ttl": 10, }, Object { "has": "stale", "now": 1529, "remainingTTL": -2, "start": 1517, "ttl": 10, }, Object { "get": "stale", "now": 1529, "remainingTTL": -2, "start": 1517, "ttl": 10, }, Object { "has": "hit", "now": 1579, "remainingTTL": 50, "start": 1529, "ttl": 100, }, Object { "get": "hit", "now": 1579, "remainingTTL": 50, "start": 1529, "ttl": 100, }, Object { "get": "stale", "now": 1630, "remainingTTL": -1, "start": 1529, "ttl": 100, }, Object { "now": 1630, "remainingTTL": 10, "set": "add", "start": 1630, "ttl": 10, }, Object { "now": 1630, "remainingTTL": 10, "set": "add", "start": 1630, "ttl": 10, }, Object { "now": 1630, "remainingTTL": 10, "set": "add", "start": 1630, "ttl": 10, }, Object { "now": 1630, "remainingTTL": 10, "set": "add", "start": 1630, "ttl": 10, }, Object { "now": 1630, "remainingTTL": 10, "set": "add", "start": 1630, "ttl": 10, }, Object { "now": 1630, "remainingTTL": 10, "set": "add", "start": 1630, "ttl": 10, }, Object { "now": 1630, "remainingTTL": 10, "set": "add", "start": 1630, "ttl": 10, }, Object { "now": 1630, "remainingTTL": 10, "set": "add", "start": 1630, "ttl": 10, }, Object { "now": 1630, "remainingTTL": 10, "set": "add", "start": 1630, "ttl": 10, }, Object { "has": "stale", "now": 1641, "remainingTTL": -1, "start": 1630, "ttl": 10, }, Object { "get": "stale", "now": 1641, "remainingTTL": -1, "start": 1630, "ttl": 10, }, Object { "get": "hit", }, Object { "get": "hit", }, ] ` exports[`test/ttl.ts TAP tests using Date.now() ttl tests with ttlResolution=100 > status updates 1`] = ` Array [ Object { "now": 1841, "remainingTTL": 10, "set": "add", "start": 1841, "ttl": 10, }, Object { "get": "hit", "now": 1841, "remainingTTL": 10, "start": 1841, "ttl": 10, }, Object { "get": "hit", "now": 1841, "remainingTTL": 10, "start": 1841, "ttl": 10, }, Object { "get": "hit", "now": 1841, "remainingTTL": 10, "start": 1841, "ttl": 10, }, Object { "has": "hit", "now": 1841, "remainingTTL": 10, "start": 1841, "ttl": 10, }, Object { "get": "hit", "now": 1841, "remainingTTL": 10, "start": 1841, "ttl": 10, }, Object { "has": "stale", "now": 1952, "remainingTTL": -101, "start": 1841, "ttl": 10, }, Object { "get": "stale", "now": 1952, "remainingTTL": -101, "start": 1841, "ttl": 10, }, ] ` exports[`test/ttl.ts TAP tests using Date.now() ttlAutopurge > status updates 1`] = ` Array [ Object { "now": 1952, "remainingTTL": 10, "set": "add", "start": 1952, "ttl": 10, }, Object { "now": 1952, "remainingTTL": 10, "set": "add", "start": 1952, "ttl": 10, }, Object { "now": 1952, "oldValue": 2, "remainingTTL": 11, "set": "replace", "start": 1952, "ttl": 11, }, ] ` exports[`test/ttl.ts TAP tests with perf_hooks.performance.now() set item pre-stale > dump with stale values 1`] = ` Array [ Array [ 1, Object { "start": 1505, "ttl": 10, "value": 1, }, ], Array [ 2, Object { "start": 1494, "ttl": 10, "value": 2, }, ], ] ` exports[`test/ttl.ts TAP tests with perf_hooks.performance.now() ttl on set, not on cache > status updates 1`] = ` Array [ Object { "now": 448, "remainingTTL": 10, "set": "add", "start": 448, "ttl": 10, }, Object { "get": "hit", "now": 448, "remainingTTL": 10, "start": 448, "ttl": 10, }, Object { "get": "hit", "now": 453, "remainingTTL": 5, "start": 448, "ttl": 10, }, Object { "get": "hit", "now": 458, "remainingTTL": 0, "start": 448, "ttl": 10, }, Object { "has": "stale", "now": 459, "remainingTTL": -1, "start": 448, "ttl": 10, }, Object { "get": "stale", "now": 459, "remainingTTL": -1, "start": 448, "ttl": 10, }, Object { "now": 459, "remainingTTL": 100, "set": "add", "start": 459, "ttl": 100, }, Object { "has": "hit", "now": 509, "remainingTTL": 50, "start": 459, "ttl": 100, }, Object { "get": "hit", "now": 509, "remainingTTL": 50, "start": 459, "ttl": 100, }, Object { "has": "stale", "now": 560, "remainingTTL": -1, "start": 459, "ttl": 100, }, Object { "get": "stale", "now": 560, "remainingTTL": -1, "start": 459, "ttl": 100, }, Object { "now": 560, "remainingTTL": 10, "set": "add", "start": 560, "ttl": 10, }, Object { "now": 560, "remainingTTL": 10, "set": "add", "start": 560, "ttl": 10, }, Object { "now": 560, "remainingTTL": 10, "set": "add", "start": 560, "ttl": 10, }, Object { "now": 560, "remainingTTL": 10, "set": "add", "start": 560, "ttl": 10, }, Object { "now": 560, "remainingTTL": 10, "set": "add", "start": 560, "ttl": 10, }, Object { "now": 560, "remainingTTL": 10, "set": "add", "start": 560, "ttl": 10, }, Object { "now": 560, "remainingTTL": 10, "set": "add", "start": 560, "ttl": 10, }, Object { "now": 560, "remainingTTL": 10, "set": "add", "start": 560, "ttl": 10, }, Object { "now": 560, "remainingTTL": 10, "set": "add", "start": 560, "ttl": 10, }, Object { "has": "stale", "now": 571, "remainingTTL": -1, "start": 560, "ttl": 10, }, Object { "get": "stale", "now": 571, "remainingTTL": -1, "start": 560, "ttl": 10, }, ] ` exports[`test/ttl.ts TAP tests with perf_hooks.performance.now() ttl tests defaults > status updates 1`] = ` Array [ Object { "now": 1, "remainingTTL": 10, "set": "add", "start": 1, "ttl": 10, }, Object { "get": "hit", "now": 1, "remainingTTL": 10, "start": 1, "ttl": 10, }, Object { "get": "hit", "now": 6, "remainingTTL": 5, "start": 1, "ttl": 10, }, Object { "get": "hit", "now": 11, "remainingTTL": 0, "start": 1, "ttl": 10, }, Object { "has": "stale", "now": 13, "remainingTTL": -2, "start": 1, "ttl": 10, }, Object { "get": "stale", "now": 13, "remainingTTL": -2, "start": 1, "ttl": 10, }, Object { "has": "hit", "now": 63, "remainingTTL": 50, "start": 13, "ttl": 100, }, Object { "get": "hit", "now": 63, "remainingTTL": 50, "start": 13, "ttl": 100, }, Object { "get": "stale", "now": 114, "remainingTTL": -1, "start": 13, "ttl": 100, }, Object { "now": 114, "remainingTTL": 10, "set": "add", "start": 114, "ttl": 10, }, Object { "now": 114, "remainingTTL": 10, "set": "add", "start": 114, "ttl": 10, }, Object { "now": 114, "remainingTTL": 10, "set": "add", "start": 114, "ttl": 10, }, Object { "now": 114, "remainingTTL": 10, "set": "add", "start": 114, "ttl": 10, }, Object { "now": 114, "remainingTTL": 10, "set": "add", "start": 114, "ttl": 10, }, Object { "now": 114, "remainingTTL": 10, "set": "add", "start": 114, "ttl": 10, }, Object { "now": 114, "remainingTTL": 10, "set": "add", "start": 114, "ttl": 10, }, Object { "now": 114, "remainingTTL": 10, "set": "add", "start": 114, "ttl": 10, }, Object { "now": 114, "remainingTTL": 10, "set": "add", "start": 114, "ttl": 10, }, Object { "has": "stale", "now": 125, "remainingTTL": -1, "start": 114, "ttl": 10, }, Object { "get": "stale", "now": 125, "remainingTTL": -1, "start": 114, "ttl": 10, }, Object { "get": "hit", }, Object { "get": "hit", }, ] ` exports[`test/ttl.ts TAP tests with perf_hooks.performance.now() ttl tests with ttlResolution=100 > status updates 1`] = ` Array [ Object { "now": 325, "remainingTTL": 10, "set": "add", "start": 325, "ttl": 10, }, Object { "get": "hit", "now": 325, "remainingTTL": 10, "start": 325, "ttl": 10, }, Object { "get": "hit", "now": 325, "remainingTTL": 10, "start": 325, "ttl": 10, }, Object { "get": "hit", "now": 325, "remainingTTL": 10, "start": 325, "ttl": 10, }, Object { "has": "hit", "now": 325, "remainingTTL": 10, "start": 325, "ttl": 10, }, Object { "get": "hit", "now": 325, "remainingTTL": 10, "start": 325, "ttl": 10, }, Object { "has": "stale", "now": 436, "remainingTTL": -101, "start": 325, "ttl": 10, }, Object { "get": "stale", "now": 436, "remainingTTL": -101, "start": 325, "ttl": 10, }, ] ` exports[`test/ttl.ts TAP tests with perf_hooks.performance.now() ttlAutopurge > status updates 1`] = ` Array [ Object { "now": 436, "remainingTTL": 10, "set": "add", "start": 436, "ttl": 10, }, Object { "now": 436, "remainingTTL": 10, "set": "add", "start": 436, "ttl": 10, }, Object { "now": 436, "oldValue": 2, "remainingTTL": 11, "set": "replace", "start": 436, "ttl": 11, }, ] ` node-lru-cache-10.0.1/test/000077500000000000000000000000001446525347600153565ustar00rootroot00000000000000node-lru-cache-10.0.1/test/avoid-memory-leak.ts000066400000000000000000000067371446525347600212650ustar00rootroot00000000000000#!/usr/bin/env node --no-warnings --loader=ts-node/esm --expose-gc // https://github.com/isaacs/node-lru-cache/issues/227 import t from 'tap' import { expose } from './fixtures/expose' const maxSize = 100_000 const itemSize = 1_000 const profEvery = 10_000 const n = 1_000_000 if (typeof gc !== 'function') { t.plan(0, 'run with --expose-gc') process.exit(0) } const tryReq = (mod: string) => { try { return require(mod) } catch (er) { t.plan(0, `need ${mod} module`) process.exit(0) } } const v8 = tryReq('v8') import { LRUCache } from '../' const expectItemCount = Math.ceil(maxSize / itemSize) const max = expectItemCount + 1 const keyRange = expectItemCount * 2 // fine to alloc unsafe, we don't ever look at the data const makeItem = () => Buffer.allocUnsafe(itemSize) const prof = (i: number, cache: LRUCache) => { // run gc so that we know if we're actually leaking memory, or just // that the gc is being lazy and not responding until there's memory // pressure. // @ts-ignore gc() return { i, ...v8.getHeapStatistics(), valListLength: expose(cache).valList.length, freeLength: expose(cache).free.length, } } const runTest = async (t: Tap.Test, cache: LRUCache) => { // first, fill to expected size for (let i = 0; i < expectItemCount; i++) { cache.set(i, makeItem()) } // now start the setting and profiling const profiles: ReturnType[] = [] for (let i = 0; i < n; i++) { if (i % profEvery === 0) { const profile = prof(i, cache) t.ok( profile.valListLength <= max, `expect valList to have fewer than ${max} items`, { found: profile.valListLength } ) t.ok( profile.freeLength <= 1, 'expect free stack to have <= 1 item', { found: profile.freeLength } ) t.ok( profile.number_of_native_contexts <= 2, 'expect only 1 or 2 native contexts', { found: profile.number_of_native_contexts } ) t.equal( profile.number_of_detached_contexts, 0, '0 detached contexts' ) profiles.push(profile) } const item = makeItem() cache.set(i % keyRange, item) } const profile = prof(n, cache) profiles.push(profile) // Warning: kludgey inexact test! // memory leaks can be hard to catch deterministically. // The first few items will tend to be lower, and we'll see // *some* modest increase in heap usage from tap itself as it // runs the test and builds up its internal results data. // But, after the initial few profiles, it should be modest. // Considering that the reported bug showed a 10x increase in // memory in this reproduction case, 2x is still pretty aggressive, // without risking false hits from other node or tap stuff. const start = Math.floor(profiles.length / 2) const initial = profiles[start] for (let i = start; i < profiles.length; i++) { const current = profiles[i] const delta = current.total_heap_size / initial.total_heap_size t.ok(delta < 2, 'memory growth should not be unbounded', { delta, current, initial, }) } } t.test('both max and maxSize', t => runTest( t, new LRUCache({ maxSize, sizeCalculation: s => s.length, max, }) ) ) t.test('no max, only maxSize', t => runTest( t, new LRUCache({ maxSize, sizeCalculation: s => s.length, }) ) ) t.test('only max, no maxSize', t => runTest(t, new LRUCache({ max }))) node-lru-cache-10.0.1/test/basic.ts000066400000000000000000000144611446525347600170150ustar00rootroot00000000000000if (typeof performance === 'undefined') { global.performance = require('perf_hooks').performance } import t from 'tap' import { LRUCache as LRU } from '../' import { expose } from './fixtures/expose' t.test('verify require works as expected', t => { t.equal( require.resolve('../'), require.resolve('../dist/cjs/index.js'), 'require resolves to expected module' ) const { LRUCache } = t.mock('../dist/cjs/index.js', {}) t.equal( LRUCache.toString().split(/\r?\n/)[0].trim(), 'class LRUCache {' ) t.end() }) t.test('basic operation', t => { const statuses: LRU.Status[] = [] const s = (): LRU.Status => { const status: LRU.Status = {} statuses.push(status) return status } const c = new LRU({ max: 10 }) for (let i = 0; i < 5; i++) { t.equal(c.set(i, i, { status: s() }), c) } for (let i = 0; i < 5; i++) { t.equal(c.get(i, { status: s() }), i) } t.equal(c.size, 5) t.matchSnapshot(c.entries()) t.equal( c.getRemainingTTL(1), Infinity, 'no ttl, so returns Infinity' ) t.equal( c.getRemainingTTL('not in cache'), 0, 'not in cache, no ttl' ) for (let i = 5; i < 10; i++) { c.set(i, i, { status: s() }) } // second time to get the update statuses for (let i = 5; i < 10; i++) { c.set(i, i, { status: s() }) } t.equal(c.size, 10) t.matchSnapshot(c.entries()) for (let i = 0; i < 5; i++) { // this doesn't do anything, but shouldn't be a problem. c.get(i, { updateAgeOnGet: true, status: s() }) } t.equal(c.size, 10) t.matchSnapshot(c.entries()) for (let i = 5; i < 10; i++) { c.get(i, { status: s() }) } for (let i = 10; i < 15; i++) { c.set(i, i, { status: s() }) } t.equal(c.size, 10) t.matchSnapshot(c.entries()) for (let i = 15; i < 20; i++) { c.set(i, i, { status: s() }) } // got pruned and replaced t.equal(c.size, 10) t.matchSnapshot(c.entries()) for (let i = 0; i < 10; i++) { t.equal(c.get(i, { status: s() }), undefined) } t.matchSnapshot(c.entries()) for (let i = 0; i < 9; i++) { c.set(i, i) } t.equal(c.size, 10) t.equal(c.delete(19), true) t.equal(c.delete(19), false) t.equal(c.size, 9) c.set(10, 10, { status: s() }) t.equal(c.size, 10) c.clear() t.equal(c.size, 0) for (let i = 0; i < 10; i++) { c.set(i, i, { status: s() }) } t.equal(c.size, 10) t.equal(c.has(0, { status: s() }), true) t.equal(c.size, 10) c.set(true, 'true', { status: s() }) t.equal(c.has(true, { status: s() }), true) t.equal(c.get(true, { status: s() }), 'true') c.set(true, undefined) t.equal(c.has(true, { status: s() }), false) t.matchSnapshot(statuses, 'status tracking') t.end() }) t.test('bad max values', t => { // @ts-expect-error t.throws(() => new LRU()) // @ts-expect-error t.throws(() => new LRU(123)) // @ts-expect-error t.throws(() => new LRU({})) // @ts-expect-error t.throws(() => new LRU(null)) t.throws(() => new LRU({ max: -123 })) t.throws(() => new LRU({ max: 0 })) t.throws(() => new LRU({ max: 2.5 })) t.throws(() => new LRU({ max: Infinity })) t.throws(() => new LRU({ max: Number.MAX_SAFE_INTEGER * 2 })) // ok to have a max of 0 if maxSize or ttl are set const sizeOnly = new LRU({ maxSize: 100 }) // setting the size to invalid values t.throws(() => sizeOnly.set('foo', 'bar'), TypeError) t.throws(() => sizeOnly.set('foo', 'bar', { size: 0 }), TypeError) t.throws(() => sizeOnly.set('foo', 'bar', { size: -1 }), TypeError) t.throws( () => sizeOnly.set('foo', 'bar', { sizeCalculation: () => -1, }), TypeError ) t.throws( () => sizeOnly.set('foo', 'bar', { sizeCalculation: () => 0, }), TypeError ) const ttlOnly = new LRU({ ttl: 1000, ttlAutopurge: true }) // cannot set size when not tracking size t.throws(() => ttlOnly.set('foo', 'bar', { size: 1 }), TypeError) t.throws(() => ttlOnly.set('foo', 'bar', { size: 1 }), TypeError) const sizeTTL = new LRU({ maxSize: 100, ttl: 1000 }) t.type(sizeTTL, LRU) t.end() }) t.test('setting ttl with non-integer values', t => { t.throws(() => new LRU({ max: 10, ttl: 10.5 }), TypeError) t.throws(() => new LRU({ max: 10, ttl: -10 }), TypeError) // @ts-expect-error t.throws(() => new LRU({ max: 10, ttl: 'banana' }), TypeError) t.throws(() => new LRU({ max: 10, ttl: Infinity }), TypeError) t.end() }) t.test('setting maxSize with non-integer values', t => { t.throws(() => new LRU({ max: 10, maxSize: 10.5 }), TypeError) t.throws(() => new LRU({ max: 10, maxSize: -10 }), TypeError) t.throws(() => new LRU({ max: 10, maxEntrySize: 10.5 }), TypeError) t.throws(() => new LRU({ max: 10, maxEntrySize: -10 }), TypeError) t.throws( // @ts-expect-error () => new LRU({ max: 10, maxEntrySize: 'banana' }), TypeError ) t.throws( () => new LRU({ max: 10, maxEntrySize: Infinity }), TypeError ) // @ts-expect-error t.throws(() => new LRU({ max: 10, maxSize: 'banana' }), TypeError) t.throws(() => new LRU({ max: 10, maxSize: Infinity }), TypeError) t.end() }) t.test('bad sizeCalculation', t => { t.throws(() => { // @ts-expect-error new LRU({ max: 1, sizeCalculation: true }) }, TypeError) t.throws(() => { // @ts-expect-error new LRU({ max: 1, maxSize: 1, sizeCalculation: true }) }, TypeError) t.end() }) t.test('delete from middle, reuses that index', t => { const c = new LRU({ max: 5 }) for (let i = 0; i < 5; i++) { c.set(i, i) } c.delete(2) c.set(5, 5) t.strictSame(expose(c).valList, [0, 1, 5, 3, 4]) t.end() }) t.test('peek does not disturb order', t => { const c = new LRU({ max: 5 }) for (let i = 0; i < 5; i++) { c.set(i, i) } t.equal(c.peek(2), 2) t.strictSame([...c.values()], [4, 3, 2, 1, 0]) t.end() }) t.test('re-use key before initial fill completed', t => { const statuses: LRU.Status[] = [] const s = (): LRU.Status => { const status: LRU.Status = {} statuses.push(status) return status } const c = new LRU({ max: 5 }) c.set(0, 0, { status: s() }) c.set(1, 1, { status: s() }) c.set(2, 2, { status: s() }) c.set(1, 2, { status: s() }) c.set(3, 3, { status: s() }) t.same( [...c.entries()], [ [3, 3], [1, 2], [2, 2], [0, 0], ] ) t.matchSnapshot(statuses) t.end() }) node-lru-cache-10.0.1/test/delete-while-iterating.ts000066400000000000000000000032401446525347600222610ustar00rootroot00000000000000import t from 'tap' import { LRUCache as LRU } from '../' t.beforeEach(t => { const c = new LRU({ max: 5 }) c.set(0, 0) c.set(1, 1) c.set(2, 2) c.set(3, 3) c.set(4, 4) t.context = c }) t.test('delete evens', t => { const c = t.context t.same([...c.keys()], [4, 3, 2, 1, 0]) for (const k of c.keys()) { if (k % 2 === 0) { c.delete(k) } } t.same([...c.keys()], [3, 1]) t.end() }) t.test('delete odds', t => { const c = t.context t.same([...c.keys()], [4, 3, 2, 1, 0]) for (const k of c.keys()) { if (k % 2 === 1) { c.delete(k) } } t.same([...c.keys()], [4, 2, 0]) t.end() }) t.test('rdelete evens', t => { const c = t.context t.same([...c.keys()], [4, 3, 2, 1, 0]) for (const k of c.rkeys()) { if (k % 2 === 0) { c.delete(k) } } t.same([...c.keys()], [3, 1]) t.end() }) t.test('rdelete odds', t => { const c = t.context t.same([...c.keys()], [4, 3, 2, 1, 0]) for (const k of c.rkeys()) { if (k % 2 === 1) { c.delete(k) } } t.same([...c.keys()], [4, 2, 0]) t.end() }) t.test('delete two of them', t => { const c = t.context t.same([...c.keys()], [4, 3, 2, 1, 0]) for (const k of c.keys()) { if (k === 3) { c.delete(3) c.delete(4) } else if (k === 1) { c.delete(1) c.delete(0) } } t.same([...c.keys()], [2]) t.end() }) t.test('rdelete two of them', t => { const c = t.context t.same([...c.keys()], [4, 3, 2, 1, 0]) for (const k of c.rkeys()) { if (k === 3) { c.delete(3) c.delete(4) } else if (k === 1) { c.delete(1) c.delete(0) } } t.same([...c.keys()], [2]) t.end() }) node-lru-cache-10.0.1/test/dispose.ts000066400000000000000000000072701446525347600174020ustar00rootroot00000000000000import t from 'tap' import { LRUCache as LRU } from '../' t.test('disposal', t => { const disposed: any[] = [] const c = new LRU({ max: 5, dispose: (k, v, r) => disposed.push([k, v, r]), }) for (let i = 0; i < 9; i++) { c.set(i, i) } t.strictSame(disposed, [ [0, 0, 'evict'], [1, 1, 'evict'], [2, 2, 'evict'], [3, 3, 'evict'], ]) t.equal(c.size, 5) c.set(9, 9) t.strictSame(disposed, [ [0, 0, 'evict'], [1, 1, 'evict'], [2, 2, 'evict'], [3, 3, 'evict'], [4, 4, 'evict'], ]) disposed.length = 0 c.set('asdf', 'foo') c.set('asdf', 'asdf') t.strictSame(disposed, [ [5, 5, 'evict'], ['foo', 'asdf', 'set'], ]) disposed.length = 0 for (let i = 0; i < 5; i++) { c.set(i, i) } t.strictSame(disposed, [ [6, 6, 'evict'], [7, 7, 'evict'], [8, 8, 'evict'], [9, 9, 'evict'], ['asdf', 'asdf', 'evict'], ]) // dispose both old and current disposed.length = 0 c.set('asdf', 'foo') c.delete('asdf') t.strictSame(disposed, [ [0, 0, 'evict'], ['foo', 'asdf', 'delete'], ]) // delete non-existing key, no disposal disposed.length = 0 c.delete('asdf') t.strictSame(disposed, []) // delete via clear() disposed.length = 0 c.clear() t.strictSame(disposed, [ [1, 1, 'delete'], [2, 2, 'delete'], [3, 3, 'delete'], [4, 4, 'delete'], ]) disposed.length = 0 c.set(3, 3) t.equal(c.get(3), 3) c.delete(3) t.strictSame(disposed, [[3, 3, 'delete']]) // disposed because of being overwritten c.clear() disposed.length = 0 for (let i = 0; i < 5; i++) { c.set(i, i) } c.set(2, 'two') t.strictSame(disposed, [[2, 2, 'set']]) for (let i = 0; i < 5; i++) { t.equal(c.get(i), i === 2 ? 'two' : i) } t.strictSame(disposed, [[2, 2, 'set']]) c.noDisposeOnSet = true c.clear() disposed.length = 0 for (let i = 0; i < 5; i++) { c.set(i, i) } c.set(2, 'two') for (let i = 0; i < 5; i++) { t.equal(c.get(i), i === 2 ? 'two' : i) } t.strictSame(disposed, []) t.end() }) t.test('noDisposeOnSet with delete()', t => { const disposed: [any, any][] = [] const dispose = (v: any, k: any) => disposed.push([v, k]) const c = new LRU({ max: 5, dispose, noDisposeOnSet: true }) for (let i = 0; i < 5; i++) { c.set(i, i) } for (let i = 0; i < 4; i++) { c.set(i, `new ${i}`) } t.strictSame(disposed, []) c.delete(0) c.delete(4) t.strictSame(disposed, [ ['new 0', 0], [4, 4], ]) disposed.length = 0 const d = new LRU({ max: 5, dispose }) for (let i = 0; i < 5; i++) { d.set(i, i) } for (let i = 0; i < 4; i++) { d.set(i, `new ${i}`) } t.strictSame(disposed, [ [0, 0], [1, 1], [2, 2], [3, 3], ]) d.delete(0) d.delete(4) t.strictSame(disposed, [ [0, 0], [1, 1], [2, 2], [3, 3], ['new 0', 0], [4, 4], ]) t.end() }) t.test('disposeAfter', t => { const c = new LRU({ max: 5, disposeAfter: (v, k) => { if (k === 2) { // increment it every time it gets disposed, but only one time c.set(k, (v as number) + 1, { noDisposeOnSet: true }) } }, }) for (let i = 0; i < 100; i++) { c.set(i, i) } t.same( [...c.entries()], [ [99, 99], [98, 98], [2, 21], [97, 97], [96, 96], ] ) c.delete(2) t.same( [...c.entries()], [ [2, 22], [99, 99], [98, 98], [97, 97], [96, 96], ] ) for (let i = 96; i < 100; i++) { c.set(i, i + 1) } t.same( [...c.entries()], [ [99, 100], [98, 99], [97, 98], [96, 97], [2, 22], ] ) c.clear() t.same([...c.entries()], [[2, 23]]) t.end() }) node-lru-cache-10.0.1/test/esm-load.mjs000066400000000000000000000003461446525347600175750ustar00rootroot00000000000000import t from 'tap' import { LRUCache } from '../dist/mjs/index.js' const c = new LRUCache({ max: 2 }) t.type(c, LRUCache) c.set(1, 1) c.set(2, 2) c.set(3, 3) t.equal(c.get(1), undefined) t.equal(c.get(2), 2) t.equal(c.get(3), 3) node-lru-cache-10.0.1/test/fetch.ts000066400000000000000000000571061446525347600170300ustar00rootroot00000000000000if (typeof performance === 'undefined') { global.performance = require('perf_hooks').performance } import t from 'tap' import { BackgroundFetch, LRUCache } from '../' import { expose } from './fixtures/expose' const fn: LRUCache.Fetcher = async (_, v) => new Promise(res => setImmediate(() => res(v === undefined ? 0 : v + 1)) ) import Clock from 'clock-mock' const clock = new Clock() t.teardown(clock.enter()) clock.advance(1) let LRU = LRUCache const c = new LRU({ fetchMethod: fn, max: 5, ttl: 5, }) const getStatusObj = (): LRUCache.Status => ({}) t.test('asynchronous fetching', async t => { const s1 = getStatusObj() const v1 = await c.fetch('key', { status: s1 }) t.equal(v1, 0, 'first fetch, no stale data, wait for initial value') t.matchSnapshot(s1, 'status 1') const s2 = getStatusObj() const v2 = await c.fetch('key', { status: s2 }) t.equal(v2, 0, 'got same cached value') t.matchSnapshot(s2, 'status 2') clock.advance(10) const s3 = getStatusObj() const v3 = await c.fetch('key', { allowStale: true, status: s3 }) t.equal(v3, 0, 'fetch while stale, allowStale, get stale data') t.matchSnapshot(s3, 'status 3') const s31 = getStatusObj() t.equal( await c.fetch('key', { allowStale: true, status: s31 }), 0, 'get stale data again while re-fetching because stale previously' ) t.matchSnapshot(s31, 'status 3.1') const s4 = getStatusObj() const v4 = await c.fetch('key', { status: s4 }) t.equal(v4, 1, 'no allow stale, wait until fresh data available') t.matchSnapshot(s4, 'status 4') const s5 = getStatusObj() const v5 = await c.fetch('key', { status: s5 }) t.equal(v5, 1, 'fetch while not stale, just get from cache') t.matchSnapshot(s5, 'status 5') clock.advance(10) const v6 = await c.fetch('key', { allowStale: true }) t.equal( v6, 1, 'fetch while stale, starts new fetch, return stale data' ) const e = expose(c) const v = e.valList[0] // should not have any promises or cycles in the dump const dump = c.dump() for (const [_, entry] of dump) { t.type(entry.value, 'number') } t.matchSnapshot(JSON.stringify(dump), 'safe to stringify dump') t.equal(e.isBackgroundFetch(v), true) t.equal(e.backgroundFetch('key', 0, {}, undefined), v) await v const v7 = await c.fetch('key', { allowStale: true, updateAgeOnGet: true, }) t.equal(v7, 2, 'fetch completed, so get new data') clock.advance(100) const v8 = await c.fetch('key', { allowStale: true }) const v9 = c.get('key', { allowStale: true }) t.equal(v8, 2, 'fetch returned stale while fetching') t.equal(v9, 2, 'get() returned stale while fetching') const v10 = c.fetch('key2') const v11 = c.get('key2') t.equal(v11, undefined, 'get while fetching but not yet returned') t.equal(await v10, 0, 'eventually 0 is returned') const v12 = c.get('key2') t.equal(v12, 0, 'get cached value after fetch') const v13 = c.fetch('key3') c.delete('key3') await t.rejects(v13, 'rejects, because it was deleted') t.equal(c.has('key3'), false, 'not inserted into cache') c.fetch('key4') clock.advance(100) const v15 = await c.fetch('key4', { allowStale: true }) t.equal( v15, 0, 'there was no stale data, even though we were ok with that' ) c.set('key5', 0) clock.advance(100) const v16 = await c.fetch('key5') t.equal(v16, 1, 'waited for new data, data in cache was stale') c.fetch('key4') await Promise.resolve().then(() => {}) clock.advance(100) const v18 = c.get('key4') t.equal( v18, undefined, 'get while fetching, but did not want stale data' ) const p6 = c.fetch('key6') await Promise.resolve().then(() => {}) clock.advance(100) const v20 = c.get('key6', { allowStale: true }) t.equal( v20, undefined, 'get while fetching, but no stale data to return' ) t.equal(await p6, 0) clock.advance(100) const p7 = c.fetch('key6') const status: LRUCache.Status = {} const v21 = c.get('key6', { allowStale: true, status }) t.equal(v21, 0, 'allowStale, got stale data while fetching') t.equal( status.returnedStale, true, 'status reflects stale data returned' ) clock.advance(100) t.equal(await p7, 1, 'eventually updated') }) t.test('fetchMethod must be a function', async t => { // @ts-expect-error t.throws(() => new LRU({ fetchMethod: true, max: 2 })) }) t.test('fetch without fetch method', async t => { const c = new LRU({ max: 3 }) c.set(0, 0) c.set(1, 1) const status: LRUCache.Status = {} t.same( await Promise.all([c.fetch(0, { status }), c.fetch(1)]), [0, 1] ) t.matchSnapshot(status, 'status update') }) t.test('fetch options, signal', async t => { const statuses: LRUCache.Status[] = [] const s = (): LRUCache.Status => { const status: LRUCache.Status = {} statuses.push(status) return status } let aborted = false const disposed: any[] = [] const disposedAfter: any[] = [] const c = new LRU({ max: 3, ttl: 100, fetchMethod: async (k, oldVal, { signal, options }) => { t.ok(options.status, 'received status object') // do something async await new Promise(res => setImmediate(res)) if (signal.aborted) { aborted = true return } if (k === 2) { options.ttl = 25 } return (oldVal || 0) + 1 }, dispose: (v, k, reason) => { disposed.push([v, k, reason]) }, disposeAfter: (v, k, reason) => { disposedAfter.push([v, k, reason]) }, }) const v1 = c.fetch(2, { status: s() }) const testp1 = t.rejects(v1, 'aborted by clearing the cache') c.delete(2) await testp1 await new Promise(res => setImmediate(res)) t.equal(aborted, true) t.same(disposed, [], 'no disposals for aborted promises') t.same(disposedAfter, [], 'no disposals for aborted promises') aborted = false const v2 = c.fetch(2, { status: s() }) const testp2 = t.rejects(v2, 'rejected, replaced') c.set(2, 2) await testp2 await new Promise(res => setImmediate(res)) t.equal(aborted, true) t.same(disposed, [], 'no disposals for aborted promises') t.same(disposedAfter, [], 'no disposals for aborted promises') c.delete(2) disposed.length = 0 disposedAfter.length = 0 aborted = false const v3 = c.fetch(2, { status: s() }) const testp3 = t.rejects(v3, 'rejected, aborted by evict') c.set(3, 3, { status: s() }) c.set(4, 4, { status: s() }) c.set(5, 5, { status: s() }) await testp3 await new Promise(res => setImmediate(res)) t.equal(aborted, true) t.same(disposed, [], 'no disposals for aborted promises') t.same(disposedAfter, [], 'no disposals for aborted promises') aborted = false await c.fetch(6, { ttl: 1000, status: s() }) t.equal( c.getRemainingTTL(6), 1000, 'overridden ttl in fetch() opts' ) await c.fetch(2, { ttl: 1, status: s() }) t.equal(c.getRemainingTTL(2), 25, 'overridden ttl in fetchMethod') t.matchSnapshot(statuses, 'status updates') }) t.test('fetchMethod throws', async t => { const statuses: LRUCache.Status[] = [] const s = (): LRUCache.Status => { const status: LRUCache.Status = {} statuses.push(status) return status } // make sure that even if there's no one to sit around and wait for it, // the background fetch throwing doesn't blow anything up. const cache = new LRU({ max: 10, ttl: 10, allowStale: true, fetchMethod: async () => { throw new Error('fetch failure') }, }) // seed the cache, and make the values stale. // this simulates the case where the fetch() DID work, // and replaced the promise with the resolution, but // then they got stale. cache.set('a', 1, { status: s() }) cache.set('b', 2, { status: s() }) clock.advance(20) await Promise.resolve().then(() => {}) const a = await Promise.all([ cache.fetch('a', { status: s() }), cache.fetch('a', { status: s() }), cache.fetch('a', { status: s() }), ]) t.strictSame(a, [1, 1, 1]) // clock advances, promise rejects clock.advance(20) await Promise.resolve().then(() => {}) t.equal( cache.get('a', { status: s() }), undefined, 'removed from cache' ) const b = await Promise.all([ cache.fetch('b', { status: s() }), cache.fetch('b', { status: s() }), cache.fetch('b', { status: s() }), ]) t.strictSame(b, [2, 2, 2]) clock.advance(20) await Promise.resolve().then(() => {}) t.equal( cache.get('b', { status: s() }), undefined, 'removed from cache' ) const ap = cache.fetch('a', { status: s() }) const testap = t.rejects(ap, 'aborted by replace') cache.set('a', 99, { status: s() }) await testap t.equal( cache.get('a', { status: s() }), 99, 'did not delete new value' ) t.rejects(cache.fetch('b', { status: s() }), { message: 'fetch failure', }) t.matchSnapshot(statuses, 'status updates') }) t.test( 'fetchMethod throws, noDeleteOnFetchRejection option', async t => { // make sure that even if there's no one to sit around and wait for it, // the background fetch throwing doesn't blow anything up. let fetchFail = true const cache = new LRU({ max: 10, ttl: 10, allowStale: true, noDeleteOnFetchRejection: true, fetchMethod: async () => { if (fetchFail) { throw new Error('fetch failure') } else { return 1 } }, }) // seed the cache, and make the values stale. // this simulates the case where the fetch() DID work, // and replaced the promise with the resolution, but // then they got stale. cache.set('a', 1) cache.set('b', 2) clock.advance(20) await Promise.resolve().then(() => {}) const a = await Promise.all([ cache.fetch('a'), cache.fetch('a'), cache.fetch('a'), ]) t.strictSame(a, [1, 1, 1]) // clock advances, promise rejects clock.advance(20) await Promise.resolve().then(() => {}) const e = expose(cache) t.equal(e.keyMap.get('a'), 0) t.equal(e.valList[0], 1, 'promise replaced with stale value') const b = await Promise.all([ cache.fetch('b'), cache.fetch('b'), cache.fetch('b'), ]) t.strictSame(b, [2, 2, 2]) clock.advance(20) await Promise.resolve().then(() => {}) t.equal(e.keyMap.get('b'), 1) t.equal(e.valList[1], 2, 'promise replaced with stale value') cache.delete('a') cache.delete('b') // even though we don't noDeleteOnFetchRejection, // if there's no stale, we still remove the *promise*. const ap = cache.fetch('a') const testap = t.rejects(ap, 'aborted by replace') cache.set('a', 99) await testap t.equal(cache.get('a'), 99, 'did not delete, was replaced') await t.rejects(cache.fetch('b'), { message: 'fetch failure' }) t.equal(e.keyMap.get('b'), undefined, 'not in cache') t.equal(e.valList[1], undefined, 'not in cache') } ) t.test('fetch context', async t => { const cache = new LRU({ max: 10, ttl: 10, allowStale: true, noDeleteOnFetchRejection: true, fetchMethod: async (k, _, { context, options }) => { //@ts-expect-error t.equal(options.context, undefined) t.equal(context, expectContext) return [k, context] }, }) let expectContext = 'overridden' t.strictSame(await cache.fetch('y', { context: 'overridden' }), [ 'y', 'overridden', ]) expectContext = 'first context' t.strictSame(await cache.fetch('x', { context: 'first context' }), [ 'x', 'first context', ]) // if still in cache, doesn't call fetchMethod again t.strictSame(await cache.fetch('x', { context: 'ignored' }), [ 'x', 'first context', ]) }) t.test('forceRefresh', async t => { const statuses: LRUCache.Status[] = [] const s = (): LRUCache.Status => { const status: LRUCache.Status = {} statuses.push(status) return status } const cache = new LRU({ max: 10, allowStale: true, ttl: 100, fetchMethod: async (k, _, { options }) => { t.equal( //@ts-expect-error options.forceRefresh, undefined, 'do not expose forceRefresh' ) return new Promise(res => setImmediate(() => res(k))) }, }) // put in some values that don't match what fetchMethod returns cache.set(1, 100) cache.set(2, 200) t.equal(await cache.fetch(1), 100) // still there, because we're allowing stale, and it's not stale const status: LRUCache.Status = {} t.equal( await cache.fetch(2, { forceRefresh: true, allowStale: false, status, }), 2 ) t.equal(status.fetch, 'refresh', 'status reflects forced refresh') t.equal(await cache.fetch(1, { forceRefresh: true }), 100) clock.advance(100) t.equal( await cache.fetch(2, { forceRefresh: true, status: s() }), 2 ) t.equal(cache.peek(1), 100) // if we don't allow stale though, then that means that we wait // for the background fetch to complete, so we get the updated value. t.equal(await cache.fetch(1, { allowStale: false, status: s() }), 1) cache.set(1, 100) t.equal(await cache.fetch(1, { allowStale: false }), 100) t.equal( await cache.fetch(1, { forceRefresh: true, allowStale: false, status: s(), }), 1 ) t.matchSnapshot(statuses, 'status updates') }) t.test('allowStaleOnFetchRejection', async t => { let fetchFail = false const c = new LRU({ ttl: 10, max: 10, allowStaleOnFetchRejection: true, fetchMethod: async k => { if (fetchFail) throw new Error('fetch rejection') return k }, }) t.equal(await c.fetch(1), 1) clock.advance(11) fetchFail = true const status: LRUCache.Status = {} t.equal(await c.fetch(1, { status }), 1) t.equal( status.returnedStale, true, 'status reflects returned stale value' ) t.equal(await c.fetch(1), 1) // if we override it, no go await t.rejects(c.fetch(1, { allowStaleOnFetchRejection: false })) // that also deletes from the cache t.equal(c.get(1), undefined) }) t.test( 'placeholder promise is not removed when resolving', async t => { const resolves: Record void> = {} const c = new LRU({ maxSize: 10, sizeCalculation(v) { return v }, fetchMethod: k => { return new Promise(resolve => (resolves[k] = resolve)) }, }) const p3 = c.fetch(3) const p4 = c.fetch(4) const p5 = c.fetch(5) resolves[4](4) await p4 t.match([...c], [[4, 4]]) resolves[5](5) await p5 t.match( [...c], [ [5, 5], [4, 4], ] ) resolves[3](3) await p3 t.same( [...c], [ [3, 3], [5, 5], ] ) t.equal(c.size, 2) t.equal([...c].length, 2) } ) t.test('send a signal', async t => { const statuses: LRUCache.Status[] = [] const s = (): LRUCache.Status => { const status: LRUCache.Status = {} statuses.push(status) return status } let aborted: Error | undefined = undefined let resolved: boolean = false const c = new LRU({ max: 10, fetchMethod: async (k, _, { signal, options }) => { t.ok(options.status, 'has a status object') signal.addEventListener('abort', () => { aborted = signal.reason }) return new Promise(res => setTimeout(() => { resolved = true res(k) }, 100) ) }, }) const ac = new AbortController() const p = c.fetch(1, { signal: ac.signal, status: s() }) const er = new Error('custom abort signal') const testp = t.rejects(p, er) ac.abort(er) await testp t.equal( resolved, false, 'should have aborted before fetchMethod resolved' ) t.equal(aborted, er) t.equal(ac.signal.reason, er) t.equal(c.get(1, { status: s() }), undefined) t.matchSnapshot(statuses, 'status updates') }) t.test('verify inflight works as expected', async t => { const statuses: LRUCache.Status[] = [] const s = (): LRUCache.Status => { const status: LRUCache.Status = {} statuses.push(status) return status } let called = 0 const c = new LRUCache({ max: 5, fetchMethod: async () => { called++ await new Promise(res => setImmediate(res)) return {} }, }) const e = expose(c) c.fetch(1) const promises: Promise[] = [ c.fetch(1, { status: s() }), c.fetch(1), c.fetch(1, { status: s() }), c.fetch(1), ] t.match(e.valList, [Promise, null, null, null, null]) t.equal( e.isBackgroundFetch(e.valList[0]), true, 'is background fetch' ) t.equal(c.get(1, { status: s() }), undefined, 'get while fetching') const a = await Promise.all(promises) for (let i = 1; i < a.length; i++) { t.equal(a[i], a[0], `index ${i} equal to first returned value`) } t.equal(called, 1, 'called one time') t.matchSnapshot(statuses, 'status updates') }) t.test('abort, but then keep on fetching anyway', async t => { let aborted: Error | undefined = undefined let resolved: boolean = false let returnUndefined: boolean = false const cache = new LRU({ max: 10, ignoreFetchAbort: true, fetchMethod: async (k, _, { signal, options }) => { t.equal(options.ignoreFetchAbort, true, 'aborts ignored') signal.addEventListener('abort', () => { aborted = signal.reason }) return new Promise(res => setTimeout(() => { resolved = true if (returnUndefined) res() else res(k) }, 100) ) }, }) const ac = new AbortController() const status: LRUCache.Status = {} const p = cache.fetch(1, { signal: ac.signal, status }) const er = new Error('ignored abort signal') ac.abort(er) clock.advance(100) t.equal(await p, 1) t.equal( status.fetchAbortIgnored, true, 'status reflects ignored abort' ) t.equal(status.fetchError, er) t.equal(status.fetchUpdated, true) t.equal(resolved, true, 'aborted, but resolved anyway') t.equal(aborted, er) t.equal(ac.signal.reason, er) t.equal(cache.get(1), 1) const p2 = cache.fetch(2) t.equal(cache.get(2), undefined) cache.delete(2) t.equal(cache.get(2), undefined) clock.advance(100) t.equal(await p2, 2) t.equal(cache.get(2), undefined) // if aborted for cause, we don't save the fetched value const p3 = cache.fetch(3) t.equal(cache.get(3), undefined) cache.set(3, 33) t.equal(cache.get(3), 33) clock.advance(100) t.equal(await p3, 3) t.equal(cache.get(3), 33) const e = expose(cache) returnUndefined = true const before = e.valList.slice() const p4 = cache.fetch(4) clock.advance(100) t.equal(await p4, undefined) t.same(e.valList, before, 'did not update values with undefined') }) t.test('allowStaleOnFetchAbort', async t => { const c = new LRUCache({ ttl: 10, max: 10, allowStaleOnFetchAbort: true, fetchMethod: async (k, _, { signal }) => { return new Promise(res => { const t = setTimeout(() => res(k), 100) signal.addEventListener('abort', () => { clearTimeout(t) res() }) }) }, }) c.set(1, 10) clock.advance(100) const ac = new AbortController() const p = c.fetch(1, { signal: ac.signal }) ac.abort(new Error('gimme the stale value')) t.equal(await p, 10) t.equal( c.get(1, { allowStale: true, noDeleteOnStaleGet: true }), 10 ) const p2 = c.fetch(1) c.set(1, 100) t.equal(await p2, 10) t.equal(c.get(1), 100) }) t.test('background update on timeout, return stale', async t => { let returnUndefined = false const c = new LRUCache({ ttl: 10, max: 10, ignoreFetchAbort: true, allowStaleOnFetchAbort: true, fetchMethod: async k => { return new Promise(res => { setTimeout(() => { res(returnUndefined ? undefined : k) }, 100) }) }, }) const e = expose(c) c.set(1, 10) clock.advance(100) const ac = new AbortController() const p = c.fetch(1, { signal: ac.signal }) await new Promise(res => setImmediate(res)) t.match(e.valList[0], { __staleWhileFetching: 10 }) ac.abort(new Error('gimme the stale value')) t.equal(await p, 10) t.equal(c.get(1, { allowStale: true }), 10) clock.advance(200) await new Promise(res => setImmediate(res)).then(() => {}) t.equal(e.valList[0], 1, 'got updated value later') c.set(1, 99) clock.advance(100) returnUndefined = true const ac2 = new AbortController() const p2 = c.fetch(1, { signal: ac2.signal }) await new Promise(res => setImmediate(res)) t.match(e.valList[0], { __staleWhileFetching: 99 }) ac2.abort(new Error('gimme stale 99')) t.equal(await p2, 99) t.match(e.valList[0], { __staleWhileFetching: 99 }) t.equal(c.get(1, { allowStale: true }), 99) t.match(e.valList[0], { __staleWhileFetching: 99 }) clock.advance(200) await new Promise(res => setImmediate(res)) t.equal(e.valList[0], 99) }) t.test('fetch context required if set in ctor type', async t => { const c = new LRUCache({ max: 5, fetchMethod: async (k, _, { context }) => { if (k === 'y') t.equal(context, undefined) else if (k === 'z') t.same(context, { x: 1 }) else t.same(context, { a: 1 }) return k }, }) c.fetch('x', { context: { a: 1 } }) //@ts-expect-error c.fetch('y') //@ts-expect-error c.fetch('z', { context: { x: 1 } }) const c2 = new LRUCache({ max: 5, fetchMethod: async (k, _, { context }) => { if (k === 'y') t.equal(context, undefined) else if (k === 'z') t.same(context, { x: 1 }) else t.same(context, { a: 1 }) return k }, }) //@ts-expect-error c2.fetch('x', { context: { a: 1 } }) c2.fetch('y') c2.fetch('y', { allowStale: true }) //@ts-expect-error c2.fetch('z', { context: { x: 1 } }) t.end() }) t.test('has false for pending fetch without stale val', async t => { const c = new LRUCache({ max: 10, fetchMethod: async (key: number) => new Promise(r => setTimeout(() => r(key), 10)), }) const e = expose(c) { const p = c.fetch(1) const index = e.keyMap.get(1) as number t.not(index, undefined) const bf = e.valList[index] as BackgroundFetch t.type(bf, Promise, 'pending fetch') t.equal(bf.hasOwnProperty('__staleWhileFetching'), true) t.equal(c.has(1), false) clock.advance(10) const res = await p t.equal(res, 1) t.equal(c.has(1), true) } { // background fetch that DOES have a __staleWhileFetching value const p = c.fetch(1, { forceRefresh: true }) const index = e.keyMap.get(1) as number t.not(index, undefined) const bf = e.valList[index] as BackgroundFetch t.type(bf, Promise, 'pending fetch') t.equal(bf.__staleWhileFetching, 1) t.equal(c.has(1), true) clock.advance(10) const res = await p t.equal(res, 1) t.equal(c.has(1), true) } }) t.test('properly dispose when using fetch', async t => { const disposes: [number, number, string][] = [] const disposeAfters: [number, number, string][] = [] let i = 0 const c = new LRUCache({ max: 3, ttl: 10, dispose: (key, val, reason) => disposes.push([key, val, reason]), disposeAfter: (key, val, reason) => disposeAfters.push([key, val, reason]), fetchMethod: async () => Promise.resolve(i++), }) t.equal(await c.fetch(1), 0) clock.advance(20) t.equal(await c.fetch(1), 1) t.strictSame(disposes, [[0, 1, 'set']]) t.strictSame(disposeAfters, [[0, 1, 'set']]) }) node-lru-cache-10.0.1/test/find.ts000066400000000000000000000022121446525347600166430ustar00rootroot00000000000000import t from 'tap' import { LRUCache as LRU } from '../' const resolves: Record< number, (v: { value: number } | Promise<{ value: number }>) => void > = {} const c = new LRU({ max: 5, ttl: 1, fetchMethod: k => new Promise<{ value: number }>(res => (resolves[k] = res)), allowStale: true, noDeleteOnStaleGet: true, }) for (let i = 0; i < 9; i++) { c.set(i, { value: i }) } const p = c.fetch(8, { forceRefresh: true }) t.equal( c.find(o => o.value === 4), c.get(4) ) t.equal( c.find(o => o.value === 9), undefined ) t.same( c.find(o => o.value === 8), { value: 8 } ) resolves[8]({ value: 10 }) new Promise(setImmediate) .then(() => p) .then(() => { t.same( c.find(o => o.value === 10), c.get(8) ) }) const p99 = c.fetch(99) t.equal( c.find(o => o.value === 99), undefined ) resolves[99]({ value: 99 }) t.equal( c.find(o => o.value === 99), undefined ) new Promise(setImmediate) .then(() => p99) .then(() => { t.same( c.find(o => o.value === 99), { value: 99 } ) t.equal( c.find(o => o.value === 99), c.get(99) ) }) node-lru-cache-10.0.1/test/fixtures/000077500000000000000000000000001446525347600172275ustar00rootroot00000000000000node-lru-cache-10.0.1/test/fixtures/expose.ts000066400000000000000000000003631446525347600211040ustar00rootroot00000000000000import { LRUCache } from '../../' export const expose = < K extends {}, V extends {}, FC extends unknown = unknown >( cache: LRUCache, LRU = LRUCache ) => { return Object.assign(LRU.unsafeExposeInternals(cache), cache) } node-lru-cache-10.0.1/test/import.mjs000066400000000000000000000005451446525347600174070ustar00rootroot00000000000000import t from 'tap' t.test('import', async t => { const imp = await import('../dist/mjs/index.js') t.equal(Object.getPrototypeOf(imp), null, 'import returns null obj') t.equal( typeof imp.LRUCache, 'function', 'LRUCache export is function' ) t.equal( imp.LRUCache.toString().split(/\r?\n/)[0].trim(), 'class LRUCache {' ) }) node-lru-cache-10.0.1/test/load-check.ts000066400000000000000000000027761446525347600177340ustar00rootroot00000000000000process.env.TAP_BAIL = '1' import t from 'tap' import { LRUCache as LRU } from '../' import { expose } from './fixtures/expose' const max = 10000 const cache = new LRU({ max }) import crypto from 'crypto' const getVal = () => [ crypto.randomBytes(12).toString('hex'), crypto.randomBytes(12).toString('hex'), crypto.randomBytes(12).toString('hex'), crypto.randomBytes(12).toString('hex'), ] const seeds = new Array(max * 3) // fill up the cache to start for (let i = 0; i < max * 3; i++) { const v = getVal() seeds[i] = [v.join(':'), v] } t.pass('generated seed data') const verifyCache = () => { // walk down the internal list ensuring that every key is the key to that // index in the keyMap, and the value matches. const e = expose(cache) for (const [k, i] of e.keyMap.entries()) { const v = e.valList[i] as number[] const key = e.keyList[i] if (k !== key) { t.equal(k, key, 'key at proper index', { k, i }) } if (v.join(':') !== k) { t.equal(k, v.join(':'), 'proper value at index', { v, i }) } } } let cycles = 0 const cycleLength = Math.floor(max / 100) while (cycles < max * 5) { const r = Math.floor(Math.random() * seeds.length) const seed = seeds[r] const v = cache.get(seed[0]) if (v === undefined) { cache.set(seed[0], seed[1]) } else { t.equal(v.join(':'), seed[0], 'correct get ' + cycles, { seed, v, }) } if (++cycles % cycleLength === 0) { verifyCache() t.pass('cycle check ' + cycles) } } node-lru-cache-10.0.1/test/load.ts000066400000000000000000000003221446525347600166420ustar00rootroot00000000000000import t from 'tap' import { LRUCache as LRU } from '../' const c = new LRU({ max: 5 }) for (let i = 0; i < 9; i++) { c.set(i, i) } const d = new LRU(c) d.load(c.dump()) t.strictSame(d, c) node-lru-cache-10.0.1/test/map-like.ts000066400000000000000000000135451446525347600174350ustar00rootroot00000000000000if (typeof global.performance === 'undefined') { global.performance = require('perf_hooks').performance } import t from 'tap' import Clock from 'clock-mock' const clock = new Clock() const { performance, Date } = global // @ts-ignore t.teardown(() => Object.assign(global, { performance, Date })) //@ts-ignore global.Date = clock.Date //@ts-ignore global.performance = clock import { LRUCache as LRU } from '../' import { expose } from './fixtures/expose' const entriesFromForeach = ( c: LRU ): [k: K, v: V][] => { const e: [k: K, v: V][] = [] c.forEach((v, k) => e.push([k, v])) return e } const entriesFromRForeach = ( c: LRU ): [k: K, v: V][] => { const e: [k: K, v: V][] = [] c.rforEach((v, k) => e.push([k, v])) return e } t.test('bunch of iteration things', async t => { const resolves: Record void> = {} const c = new LRU({ max: 5, maxSize: 5, sizeCalculation: () => 1, fetchMethod: k => new Promise(resolve => (resolves[k] = resolve)), }) t.matchSnapshot(c.keys(), 'empty, keys') t.matchSnapshot(c.values(), 'empty, values') t.matchSnapshot(c.entries(), 'empty, entries') t.matchSnapshot(entriesFromForeach(c), 'empty, foreach') t.matchSnapshot(c.rkeys(), 'empty, rkeys') t.matchSnapshot(c.rvalues(), 'empty, rvalues') t.matchSnapshot(c.rentries(), 'empty, rentries') t.matchSnapshot(entriesFromRForeach(c), 'empty, rforeach') t.matchSnapshot(c.dump(), 'empty, dump') const p99 = c.fetch(99) const testp99 = t.rejects(p99, 'aborted by eviction') const p123 = c.fetch(123) t.matchSnapshot(c.keys(), 'pending fetch, keys') t.matchSnapshot(c.values(), 'pending fetch, values') t.matchSnapshot(c.entries(), 'pending fetch, entries') t.matchSnapshot(entriesFromForeach(c), 'pending fetch, foreach') t.matchSnapshot(c.rkeys(), 'pending fetch, rkeys') t.matchSnapshot(c.rvalues(), 'pending fetch, rvalues') t.matchSnapshot(c.rentries(), 'pending fetch, rentries') t.matchSnapshot(entriesFromRForeach(c), 'pending fetch, rforeach') t.matchSnapshot(c.dump(), 'pending fetch, dump') for (let i = 0; i < 3; i++) { c.set(i, String(i)) } resolves[123]('123') t.equal(await p123, '123') t.matchSnapshot(c.keys(), 'fetch 123 resolved, keys') t.matchSnapshot(c.values(), 'fetch 123 resolved, values') t.matchSnapshot(c.entries(), 'fetch 123 resolved, entries') t.matchSnapshot( entriesFromForeach(c), 'fetch 123 resolved, foreach' ) t.matchSnapshot(c.rkeys(), 'fetch 123 resolved, rkeys') t.matchSnapshot(c.rvalues(), 'fetch 123 resolved, rvalues') t.matchSnapshot(c.rentries(), 'fetch 123 resolved, rentries') t.matchSnapshot( entriesFromRForeach(c), 'fetch 123 resolved, rforeach' ) t.matchSnapshot(c.dump(), 'fetch 123 resolved, dump') for (let i = 3; i < 8; i++) { c.set(i, String(i)) } t.matchSnapshot(c.keys(), 'keys') t.matchSnapshot(c.values(), 'values') t.matchSnapshot(c.entries(), 'entries') t.matchSnapshot(c.rkeys(), 'rkeys') t.matchSnapshot(c.rvalues(), 'rvalues') t.matchSnapshot(c.rentries(), 'rentries') t.matchSnapshot(c.dump(), 'dump') c.set(4, 'new value 4') t.matchSnapshot(c.keys(), 'keys, new value 4') t.matchSnapshot(c.values(), 'values, new value 4') t.matchSnapshot(c.entries(), 'entries, new value 4') t.matchSnapshot(c.rkeys(), 'rkeys, new value 4') t.matchSnapshot(c.rvalues(), 'rvalues, new value 4') t.matchSnapshot(c.rentries(), 'rentries, new value 4') t.matchSnapshot(c.dump(), 'dump, new value 4') resolves[99]('99') await testp99 t.matchSnapshot(c.keys(), 'keys, resolved fetch 99 too late') t.matchSnapshot(c.values(), 'values, resolved fetch 99 too late') t.matchSnapshot(c.entries(), 'entries, resolved fetch 99 too late') t.matchSnapshot(c.rkeys(), 'rkeys, resolved fetch 99 too late') t.matchSnapshot(c.rvalues(), 'rvalues, resolved fetch 99 too late') t.matchSnapshot( c.rentries(), 'rentries, resolved fetch 99 too late' ) t.matchSnapshot(c.dump(), 'dump, resolved fetch 99 too late') // pretend an entry is stale for some reason c.set(7, 'stale', { ttl: 1, size: 1 }) const e = expose(c) const idx = e.keyMap.get(7) if (!e.starts) throw new Error('no starts??') e.starts[idx as number] = clock.now() - 10000 const seen: number[] = [] for (const i of e.indexes()) { seen[i] = seen[i] || 0 seen[i]++ if (seen[i] > 2) { throw new Error('cycle on ' + i) } } seen.length = 0 for (const i of e.rindexes()) { seen[i] = seen[i] || 0 seen[i]++ if (seen[i] > 2) { throw new Error('cycle on ' + i) } } t.matchSnapshot(c.keys(), 'keys, 7 stale') t.matchSnapshot(c.values(), 'values, 7 stale') t.matchSnapshot(c.entries(), 'entries, 7 stale') t.matchSnapshot(c.rkeys(), 'rkeys, 7 stale') t.matchSnapshot(c.rvalues(), 'rvalues, 7 stale') t.matchSnapshot(c.rentries(), 'rentries, 7 stale') t.matchSnapshot(c.dump(), 'dump, 7 stale') const feArr: any[] = [] c.forEach((value, key) => feArr.push([value, key])) t.matchSnapshot(feArr, 'forEach, no thisp') const rfeArr: any[] = [] c.rforEach((value, key) => rfeArr.push([value, key])) t.matchSnapshot(rfeArr, 'rforEach, no thisp') const feArrThisp: any[] = [] const thisp = { a: 1 } c.forEach(function (this: typeof thisp, value, key) { feArrThisp.push([value, key, this]) }, thisp) t.matchSnapshot(feArrThisp, 'forEach, with thisp') const rfeArrThisp: any[] = [] const rthisp = { r: 1 } c.rforEach(function (this: typeof thisp, value, key) { rfeArrThisp.push([value, key, this]) }, rthisp) t.matchSnapshot(rfeArrThisp, 'forEach, with thisp') // when cache is empty, these should do nothing const empty = new LRU({ max: 10 }) empty.forEach(() => { throw new Error('fail empty forEach') }) empty.rforEach(() => { throw new Error('fail empty rforEach') }) }) node-lru-cache-10.0.1/test/move-to-tail.ts000066400000000000000000000024511446525347600202450ustar00rootroot00000000000000import t from 'tap' import { LRUCache as LRU } from '../' import { expose } from './fixtures/expose' const c = new LRU({ max: 5 }) const exp = expose(c) t.test('list integrity', { bail: true }, t => { const e = (index: number) => ({ index, prev: exp.prev[index], _: index === exp.tail ? 'T' : index === exp.head ? 'H' : '' + index, next: exp.next[index], head: exp.head, tail: exp.tail, }) const snap = () => { const a: ReturnType[] = [] for (let i = 0; i < 5; i++) { a.push(e(i)) } return a } const integrity = (msg: string) => { t.test(msg, { bail: false }, t => { for (let i = 0; i < c.max; i++) { if (i !== exp.head) { t.equal(exp.next[exp.prev[i]], i, 'n[p[i]] === i') } if (i !== exp.tail) { t.equal(exp.prev[exp.next[i]], i, 'p[n[i]] === i') } } t.end() }) } for (let i = 0; i < 5; i++) { c.set(i, i) } t.matchSnapshot(snap(), 'list after initial fill') integrity('after initial fill') exp.moveToTail(2) t.matchSnapshot(snap(), 'list after moveToTail 2') integrity('after moveToTail 2') exp.moveToTail(4) t.matchSnapshot(snap(), 'list after moveToTail 4') integrity('after moveToTail 4') t.end() }) node-lru-cache-10.0.1/test/pop.ts000066400000000000000000000034501446525347600165260ustar00rootroot00000000000000import t from 'tap' import { LRUCache as LRU } from '../' const cache = new LRU({ max: 5 }) for (let i = 0; i < 5; i++) { cache.set(i, i) } cache.get(2) const popped: (number | undefined)[] = [] let p: number | undefined do { p = cache.pop() popped.push(p) } while (p !== undefined) t.same(popped, [0, 1, 3, 4, 2, undefined]) t.test('pop with background fetches', async t => { const resolves: Record void> = {} let aborted = false const f = new LRU({ max: 5, ttl: 10, fetchMethod: (k: number, _v, { signal }) => { signal.addEventListener('abort', () => (aborted = true)) return new Promise(res => (resolves[k] = res)) }, }) // a fetch that's in progress with no stale val gets popped // without returning anything f.set(0, 0) let pf = f.fetch(1) f.set(2, 2) t.equal(f.size, 3) t.equal(f.pop(), 0) t.equal(f.size, 2) t.equal(f.pop(), 2) t.equal(f.size, 0) t.equal(aborted, true) resolves[1](1) await t.rejects(pf) f.set(0, 0, { ttl: 0 }) f.set(1, 111) await new Promise(r => setTimeout(r, 20)) pf = f.fetch(1) f.set(2, 2, { ttl: 0 }) t.equal(f.size, 3) t.equal(f.pop(), 0) t.equal(f.size, 2) t.equal(f.pop(), 111) t.equal(f.size, 1) t.equal(f.pop(), 2) t.equal(f.size, 0) resolves[1](1) await t.rejects(pf) }) t.test('pop calls dispose and disposeAfter', t => { let disposeCalled = 0 let disposeAfterCalled = 0 const c = new LRU({ max: 5, dispose: () => disposeCalled++, disposeAfter: () => disposeAfterCalled++, }) c.set(0, 0) c.set(1, 1) c.set(2, 2) t.equal(c.pop(), 0) t.equal(c.pop(), 1) t.equal(c.pop(), 2) t.equal(c.pop(), undefined) t.equal(c.size, 0) t.equal(disposeCalled, 3) t.equal(disposeAfterCalled, 3) t.end() }) node-lru-cache-10.0.1/test/purge-stale-exhaustive.ts000066400000000000000000000051611446525347600223440ustar00rootroot00000000000000if (typeof performance === 'undefined') { global.performance = require('perf_hooks').performance } import t from 'tap' import { LRUCache as LRU } from '../' import { expose } from './fixtures/expose' const Clock = require('clock-mock') const clock = new Clock() clock.advance(1) const boolOpts = (n: number): number[][] => { const mask = Math.pow(2, n) const arr: number[][] = [] for (let i = 0; i < mask; i++) { arr.push( (mask + i) .toString(2) .slice(1) .split('') .map(n => +n) ) } return arr } const permute = (arr: number[] | number): number[][] => { if (typeof arr === 'number') { return permute(Object.keys(new Array(arr).fill('')).map(n => +n)) } if (arr.length === 1) { return [arr] } const permutations = [] // recurse over selecting any of the items for (let i = 0; i < arr.length; i++) { const items = arr.slice(0) const item = items.splice(i, 1) permutations.push( ...permute(items).map(perm => item.concat(perm)) ) } return permutations } const runTestStep = ({ order, stales = -1, len, }: { order: number[] stales?: number[] | -1 len: number }) => { // generate stales at this level because it's faster that way, // fewer tap pieces to prop it all up. if (stales === -1) { for (const stales of boolOpts(len)) { runTestStep({ order, stales, len }) } return true } clock.enter() const assert = require('assert') const c = new LRU({ max: len, ttl: 100 }) const e = expose(c) // fill the array with index matching k/v for (let i = 0; i < len; i++) { if (stales[i]) { c.set(i, i, { ttl: 1 }) } else { c.set(i, i) } } // now get() items to reorder for (const index of order) { c.get(index) } assert.deepEqual([...e.rindexes()], order, 'got expected ordering') // advance clock so masked go stale clock.advance(10) c.purgeStale() assert.deepEqual( [...e.rindexes()], [...e.rindexes({ allowStale: true })] ) // make all go stale clock.advance(100) c.purgeStale() assert.deepEqual([...e.rindexes({ allowStale: true })], []) clock.exit() return true } t.test('exhaustive tests', t => { // this is a brutal test. // Generate every possible ordering of indexes. // then for each ordering, generate every possible arrangement of staleness // Verify that purgeStale produces the correct result every time. const len = 5 for (const order of permute(len)) { const name = `order=${order.join('')}` t.test(name, t => { t.plan(1) runTestStep({ order, len }) t.pass('no problems') }) } t.end() }) node-lru-cache-10.0.1/test/reverse-iterate-delete-all.ts000066400000000000000000000004621446525347600230440ustar00rootroot00000000000000// https://github.com/isaacs/node-lru-cache/issues/278 import t from 'tap' import { LRUCache as LRU } from '../' const lru = new LRU({ maxSize: 2, sizeCalculation: () => 1, }) lru.set('x', 'x') lru.set('y', 'y') for (const key of lru.rkeys()) { lru.delete(key) } t.equal(lru.size, 0) node-lru-cache-10.0.1/test/size-calculation.ts000066400000000000000000000143241446525347600212000ustar00rootroot00000000000000import t from 'tap' import { LRUCache as LRU } from '../' import { expose } from './fixtures/expose' const checkSize = (c: LRU) => { const e = expose(c) const sizes = e.sizes if (!sizes) throw new Error('no sizes??') const { calculatedSize, maxSize } = c const sum = [...sizes].reduce((a, b) => a + b, 0) if (sum !== calculatedSize) { console.error({ sum, calculatedSize, sizes }, c, e) throw new Error('calculatedSize does not equal sum of sizes') } if (calculatedSize > maxSize) { throw new Error('max size exceeded') } } t.test('store strings, size = length', t => { const c = new LRU({ max: 100, maxSize: 100, sizeCalculation: n => n.length, }) checkSize(c) c.set(5, 'x'.repeat(5)) checkSize(c) c.set(10, 'x'.repeat(10)) checkSize(c) c.set(20, 'x'.repeat(20)) checkSize(c) t.equal(c.calculatedSize, 35) c.delete(20) checkSize(c) t.equal(c.calculatedSize, 15) c.delete(5) checkSize(c) t.equal(c.calculatedSize, 10) c.clear() checkSize(c) t.equal(c.calculatedSize, 0) const s = 'x'.repeat(10) for (let i = 0; i < 5; i++) { c.set(i, s) checkSize(c) } t.equal(c.calculatedSize, 50) // the big item goes in, but triggers a prune // we don't preemptively prune until we *cross* the max c.set('big', 'x'.repeat(100)) checkSize(c) t.equal(c.calculatedSize, 100) // override the size on set c.set('big', 'y'.repeat(100), { sizeCalculation: () => 10 }) checkSize(c) t.equal(c.size, 1) checkSize(c) t.equal(c.calculatedSize, 10) checkSize(c) c.delete('big') checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) c.set('repeated', 'i'.repeat(10)) checkSize(c) c.set('repeated', 'j'.repeat(10)) checkSize(c) c.set('repeated', 'i'.repeat(10)) checkSize(c) c.set('repeated', 'j'.repeat(10)) checkSize(c) c.set('repeated', 'i'.repeat(10)) checkSize(c) c.set('repeated', 'j'.repeat(10)) checkSize(c) c.set('repeated', 'i'.repeat(10)) checkSize(c) c.set('repeated', 'j'.repeat(10)) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 10) t.equal(c.get('repeated'), 'j'.repeat(10)) t.matchSnapshot(c.dump(), 'dump') t.end() }) t.test('bad size calculation fn throws on set()', t => { const c = new LRU({ max: 5, maxSize: 5, // @ts-expect-error sizeCalculation: () => { return 'asdf' }, }) t.throws( () => c.set(1, '1'.repeat(100)), new TypeError( 'sizeCalculation return invalid (expect positive integer)' ) ) t.throws(() => { // @ts-expect-error c.set(1, '1', { size: 'asdf', sizeCalculation: null }) }, new TypeError('invalid size value (must be positive integer)')) t.throws(() => { // @ts-expect-error c.set(1, '1', { sizeCalculation: 'asdf' }) }, new TypeError('sizeCalculation must be a function')) t.end() }) t.test('delete while empty, or missing key, is no-op', t => { const c = new LRU({ max: 5, maxSize: 10, sizeCalculation: () => 2 }) checkSize(c) c.set(1, 1) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 2) c.clear() checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) c.delete(1) checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) c.set(1, 1) checkSize(c) c.set(1, 1) checkSize(c) c.set(1, 1) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 2) c.delete(99) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 2) c.delete(1) checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) c.delete(1) checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) t.end() }) t.test('large item falls out of cache, sizes are kept correct', t => { const statuses: LRU.Status[] = [] const s = (): LRU.Status => { const status: LRU.Status = {} statuses.push(status) return status } const c = new LRU({ maxSize: 10, sizeCalculation: () => 100, }) const sizes = expose(c).sizes checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) t.same(sizes, []) c.set(2, 2, { size: 2, status: s() }) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 2) t.same(sizes, [2]) c.delete(2) checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) t.same(sizes, [0]) c.set(1, 1, { status: s() }) checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) t.same(sizes, [0]) c.set(3, 3, { size: 3, status: s() }) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 3) t.same(sizes, [3]) c.set(4, 4, { status: s() }) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 3) t.same(sizes, [3]) t.matchSnapshot(statuses, 'status updates') t.end() }) t.test('large item falls out of cache because maxEntrySize', t => { const statuses: LRU.Status[] = [] const s = (): LRU.Status => { const status: LRU.Status = {} statuses.push(status) return status } const c = new LRU({ maxSize: 1000, maxEntrySize: 10, sizeCalculation: () => 100, }) const sizes = expose(c).sizes checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) t.same(sizes, []) c.set(2, 2, { size: 2, status: s() }) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 2) t.same(sizes, [2]) c.delete(2) checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) t.same(sizes, [0]) c.set(1, 1, { status: s() }) checkSize(c) t.equal(c.size, 0) t.equal(c.calculatedSize, 0) t.same(sizes, [0]) c.set(3, 3, { size: 3, status: s() }) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 3) t.same(sizes, [3]) c.set(4, 4, { status: s() }) checkSize(c) t.equal(c.size, 1) t.equal(c.calculatedSize, 3) t.same(sizes, [3]) t.matchSnapshot(statuses, 'status updates') t.end() }) t.test('maxEntrySize, no maxSize', async t => { const c = new LRU({ max: 10, maxEntrySize: 10, sizeCalculation: s => s.length, fetchMethod: async n => 'x'.repeat(n), }) t.equal(await c.fetch(2), 'xx') t.equal(c.size, 1) t.equal(await c.fetch(3), 'xxx') t.equal(c.size, 2) t.equal(await c.fetch(11), 'x'.repeat(11)) t.equal(c.size, 2) t.equal(c.has(11), false) }) node-lru-cache-10.0.1/test/ttl.ts000066400000000000000000000324471446525347600165430ustar00rootroot00000000000000if (typeof performance === 'undefined') { global.performance = require('perf_hooks').performance } import t from 'tap' import { LRUCache } from '../' import { expose } from './fixtures/expose' import Clock from 'clock-mock' const clock = new Clock() const runTests = (LRU: typeof LRUCache, t: Tap.Test) => { const statuses: LRUCache.Status[] = [] const s = (): LRUCache.Status => { const status: LRUCache.Status = {} statuses.push(status) return status } const { setTimeout, clearTimeout } = global t.teardown(() => // @ts-ignore Object.assign(global, { setTimeout, clearTimeout }) ) //@ts-ignore global.setTimeout = clock.setTimeout.bind(clock) //@ts-ignore global.clearTimeout = clock.clearTimeout.bind(clock) t.test('ttl tests defaults', t => { statuses.length = 0 // have to advance it 1 so we don't start with 0 // NB: this module will misbehave if you create an entry at a // clock time of 0, for example if you are filling an LRU cache // in a node lacking perf_hooks, at midnight UTC on 1970-01-01. // This is a known bug that I am ok with. clock.advance(1) const c = new LRU({ max: 5, ttl: 10, ttlResolution: 0 }) const e = expose(c, LRU) c.set(1, 1, { status: s() }) t.equal(c.get(1, { status: s() }), 1, '1 get not stale', { now: clock._now, }) clock.advance(5) t.equal(c.get(1, { status: s() }), 1, '1 get not stale', { now: clock._now, }) t.equal(c.getRemainingTTL(1), 5, '5ms left to live') t.equal( c.getRemainingTTL('not in cache'), 0, 'thing doesnt exist' ) clock.advance(5) t.equal(c.get(1, { status: s() }), 1, '1 get not stale', { now: clock._now, }) t.equal(c.getRemainingTTL(1), 0, 'almost stale') clock.advance(1) t.equal(c.getRemainingTTL(1), -1, 'gone stale') clock.advance(1) t.equal(c.getRemainingTTL(1), -2, 'even more stale') t.equal(c.size, 1, 'still there though') t.equal(c.has(1, { status: s() }), false, '1 has stale', { now: clock._now, index: e.keyMap.get(1), stale: e.isStale(e.keyMap.get(1)), }) t.equal(c.get(1, { status: s() }), undefined) t.equal(c.size, 0) c.set(2, 2, { ttl: 100 }) clock.advance(50) t.equal(c.has(2, { status: s() }), true) t.equal(c.get(2, { status: s() }), 2) clock.advance(51) t.equal(c.has(2), false) t.equal(c.get(2, { status: s() }), undefined) c.clear() for (let i = 0; i < 9; i++) { c.set(i, i, { status: s() }) } // now we have 9 items // get an expired item from old set clock.advance(11) t.equal(c.peek(4), undefined) t.equal(c.has(4, { status: s() }), false) t.equal(c.get(4, { status: s() }), undefined) // set an item WITHOUT a ttl on it c.set('immortal', true, { ttl: 0 }) clock.advance(100) t.equal(c.getRemainingTTL('immortal'), Infinity) t.equal(c.get('immortal', { status: s() }), true) c.get('immortal', { updateAgeOnGet: true }) clock.advance(100) t.equal(c.get('immortal', { status: s() }), true) t.matchSnapshot(statuses, 'status updates') t.end() }) t.test('ttl tests with ttlResolution=100', t => { statuses.length = 0 const c = new LRU({ ttl: 10, ttlResolution: 100, max: 10 }) const e = expose(c, LRU) c.set(1, 1, { status: s() }) t.equal(c.get(1, { status: s() }), 1, '1 get not stale', { now: clock._now, }) clock.advance(5) t.equal(c.get(1, { status: s() }), 1, '1 get not stale', { now: clock._now, }) clock.advance(5) t.equal(c.get(1, { status: s() }), 1, '1 get not stale', { now: clock._now, }) clock.advance(1) t.equal(c.has(1, { status: s() }), true, '1 has stale', { now: clock._now, ttls: e.ttls, starts: e.starts, index: e.keyMap.get(1), stale: e.isStale(e.keyMap.get(1)), }) t.equal(c.get(1, { status: s() }), 1) clock.advance(100) t.equal(c.has(1, { status: s() }), false, '1 has stale', { now: clock._now, ttls: e.ttls, starts: e.starts, index: e.keyMap.get(1), stale: e.isStale(e.keyMap.get(1)), }) t.equal(c.get(1, { status: s() }), undefined) t.equal(c.size, 0) t.matchSnapshot(statuses, 'status updates') t.end() }) t.test( 'ttlResolution only respected if non-negative integer', t => { const invalids = [-1, null, undefined, 'banana', {}] for (const i of invalids) { //@ts-expect-error const c = new LRU({ ttl: 5, ttlResolution: i, max: 5 }) t.not(c.ttlResolution, i) t.equal(c.ttlResolution, Math.floor(c.ttlResolution)) t.ok(c.ttlResolution >= 0) } t.end() } ) t.test('ttlAutopurge', t => { statuses.length = 0 const c = new LRU({ ttl: 10, ttlAutopurge: true, ttlResolution: 0, }) c.set(1, 1, { status: s() }) c.set(2, 2, { status: s() }) t.equal(c.size, 2) c.set(2, 3, { ttl: 11, status: s() }) clock.advance(11) t.equal(c.size, 1) clock.advance(1) t.equal(c.size, 0) t.matchSnapshot(statuses, 'status updates') t.end() }) t.test('ttl on set, not on cache', t => { statuses.length = 0 const c = new LRU({ max: 5, ttlResolution: 0 }) c.set(1, 1, { ttl: 10, status: s() }) t.equal(c.get(1, { status: s() }), 1) clock.advance(5) t.equal(c.get(1, { status: s() }), 1) clock.advance(5) t.equal(c.get(1, { status: s() }), 1) clock.advance(1) t.equal(c.has(1, { status: s() }), false) t.equal(c.get(1, { status: s() }), undefined) t.equal(c.size, 0) c.set(2, 2, { ttl: 100, status: s() }) clock.advance(50) t.equal(c.has(2, { status: s() }), true) t.equal(c.get(2, { status: s() }), 2) clock.advance(51) t.equal(c.has(2, { status: s() }), false) t.equal(c.get(2, { status: s() }), undefined) c.clear() for (let i = 0; i < 9; i++) { c.set(i, i, { ttl: 10, status: s() }) } // now we have 9 items // get an expired item from old set clock.advance(11) t.equal(c.has(4, { status: s() }), false) t.equal(c.get(4, { status: s() }), undefined) t.matchSnapshot(statuses, 'status updates') t.end() }) t.test('ttl with allowStale', t => { const c = new LRU({ max: 5, ttl: 10, allowStale: true, ttlResolution: 0, }) c.set(1, 1) t.equal(c.get(1), 1) clock.advance(5) t.equal(c.get(1), 1) clock.advance(5) t.equal(c.get(1), 1) clock.advance(1) t.equal(c.has(1), false) t.equal(c.get(1, { status: s(), noDeleteOnStaleGet: true }), 1) t.equal(c.get(1), 1) t.equal(c.get(1), undefined) t.equal(c.size, 0) c.set(2, 2, { ttl: 100 }) clock.advance(50) t.equal(c.has(2), true) t.equal(c.get(2), 2) clock.advance(51) t.equal(c.has(2), false) t.equal(c.get(2), 2) t.equal(c.get(2), undefined) c.clear() for (let i = 0; i < 9; i++) { c.set(i, i) } // now we have 9 items // get an expired item from old set clock.advance(11) t.equal(c.has(4), false) t.equal(c.get(4), 4) t.equal(c.get(4), undefined) t.end() }) t.test('ttl with updateAgeOnGet/updateAgeOnHas', t => { const c = new LRU({ max: 5, ttl: 10, updateAgeOnGet: true, updateAgeOnHas: true, ttlResolution: 0, }) c.set(1, 1) t.equal(c.get(1), 1) clock.advance(5) t.equal(c.has(1), true) clock.advance(5) t.equal(c.get(1), 1) clock.advance(1) t.equal(c.getRemainingTTL(1), 9) t.equal(c.has(1), true) t.equal(c.getRemainingTTL(1), 10) t.equal(c.get(1), 1) t.equal(c.size, 1) c.clear() c.set(2, 2, { ttl: 100 }) for (let i = 0; i < 10; i++) { clock.advance(50) t.equal(c.has(2), true) t.equal(c.get(2), 2) } clock.advance(101) t.equal(c.has(2), false) t.equal(c.get(2), undefined) c.clear() for (let i = 0; i < 9; i++) { c.set(i, i) } // now we have 9 items // get an expired item t.equal(c.has(3), false) t.equal(c.get(3), undefined) clock.advance(11) t.equal(c.has(4), false) t.equal(c.get(4), undefined) t.end() }) t.test('purge stale items', t => { const c = new LRU({ max: 10, ttlResolution: 0 }) for (let i = 0; i < 10; i++) { c.set(i, i, { ttl: i + 1 }) } clock.advance(3) t.equal(c.size, 10) t.equal(c.purgeStale(), true) t.equal(c.size, 8) t.equal(c.purgeStale(), false) clock.advance(100) t.equal(c.size, 8) t.equal(c.purgeStale(), true) t.equal(c.size, 0) t.equal(c.purgeStale(), false) t.equal(c.size, 0) t.end() }) t.test('no update ttl', t => { const statuses: LRUCache.Status[] = [] const s = (): LRUCache.Status => { const status: LRUCache.Status = {} statuses.push(status) return status } const c = new LRU({ max: 10, ttlResolution: 0, noUpdateTTL: true, ttl: 10, }) for (let i = 0; i < 3; i++) { c.set(i, i) } clock.advance(9) // set, but do not update ttl. this will fall out. c.set(0, 0, { status: s() }) // set, but update the TTL c.set(1, 1, { noUpdateTTL: false, status: s() }) clock.advance(9) c.purgeStale() t.equal( c.get(2, { status: s() }), undefined, 'fell out of cache normally' ) t.equal( c.get(1, { status: s() }), 1, 'still in cache, ttl updated' ) t.equal( c.get(0, { status: s() }), undefined, 'fell out of cache, despite update' ) clock.advance(9) c.purgeStale() t.equal( c.get(1, { status: s() }), undefined, 'fell out of cache after ttl update' ) t.end() }) // https://github.com/isaacs/node-lru-cache/issues/203 t.test('indexes/rindexes can walk over stale entries', t => { const c = new LRU({ max: 10, ttl: 10 }) const e = expose(c, LRU) for (let i = 0; i < 3; i++) { c.set(i, i) } clock.advance(9) for (let i = 3; i < 10; i++) { c.set(i, i) } c.get(1) c.get(3) clock.advance(9) const indexes = [...e.indexes()] const indexesStale = [...e.indexes({ allowStale: true })] const rindexes = [...e.rindexes()] const rindexesStale = [...e.rindexes({ allowStale: true })] t.same( { indexes, indexesStale, rindexes, rindexesStale, }, { indexes: [3, 9, 8, 7, 6, 5, 4], indexesStale: [3, 1, 9, 8, 7, 6, 5, 4, 2, 0], rindexes: [4, 5, 6, 7, 8, 9, 3], rindexesStale: [0, 2, 4, 5, 6, 7, 8, 9, 1, 3], } ) t.end() }) // https://github.com/isaacs/node-lru-cache/issues/203 t.test('clear() disposes stale entries', t => { const disposed: any[] = [] const disposedAfter: any[] = [] const c = new LRU({ max: 3, ttl: 10, dispose: (v: any, k: any) => disposed.push([v, k]), disposeAfter: (v: any, k: any) => disposedAfter.push([v, k]), }) for (let i = 0; i < 4; i++) { c.set(i, i) } t.same(disposed, [[0, 0]]) t.same(disposedAfter, [[0, 0]]) clock.advance(20) c.clear() t.same(disposed, [ [0, 0], [1, 1], [2, 2], [3, 3], ]) t.same(disposedAfter, [ [0, 0], [1, 1], [2, 2], [3, 3], ]) t.end() }) t.test('purgeStale() lockup', t => { const c = new LRU({ max: 3, ttl: 10, updateAgeOnGet: true, }) c.set(1, 1) c.set(2, 2) c.set(3, 3) clock.advance(5) c.get(2) clock.advance(15) c.purgeStale() t.pass('did not get locked up') t.end() }) t.test('set item pre-stale', t => { const c = new LRU({ max: 3, ttl: 10, allowStale: true, }) c.set(1, 1) t.equal(c.has(1), true) t.equal(c.get(1), 1) c.set(2, 2, { start: clock.now() - 11 }) t.equal(c.has(2), false) t.equal(c.get(2), 2) t.equal(c.get(2), undefined) c.set(2, 2, { start: clock.now() - 11 }) const dump = c.dump() t.matchSnapshot(dump, 'dump with stale values') const d = new LRU({ max: 3, ttl: 10, allowStale: true }) d.load(dump) t.equal(d.has(2), false) t.equal(d.get(2), 2) t.equal(d.get(2), undefined) t.end() }) t.test('no delete on stale get', t => { const c = new LRU({ noDeleteOnStaleGet: true, ttl: 10, max: 3, }) c.set(1, 1) clock.advance(11) t.equal(c.has(1), false) t.equal(c.get(1), undefined) t.equal(c.get(1, { allowStale: true }), 1) t.equal( c.get(1, { allowStale: true, noDeleteOnStaleGet: false }), 1 ) t.equal(c.get(1, { allowStale: true }), undefined) t.end() }) t.end() } t.test('tests with perf_hooks.performance.now()', t => { const { performance, Date } = global // @ts-ignore t.teardown(() => Object.assign(global, { performance, Date })) // @ts-ignore global.Date = clock.Date // @ts-ignore global.performance = clock const { LRUCache: LRU } = t.mock('../', {}) runTests(LRU, t) }) t.test('tests using Date.now()', t => { const { performance, Date } = global // @ts-ignore t.teardown(() => Object.assign(global, { performance, Date })) // @ts-ignore global.Date = clock.Date // @ts-ignore global.performance = null const { LRUCache: LRU } = t.mock('../', {}) runTests(LRU, t) }) node-lru-cache-10.0.1/test/unbounded-warning.ts000066400000000000000000000031241446525347600213540ustar00rootroot00000000000000import t from 'tap' import { LRUCache } from '../' t.test('emits warning', t => { const { emitWarning } = process t.teardown(() => { process.emitWarning = emitWarning }) const warnings: [string, string, string][] = [] Object.defineProperty(process, 'emitWarning', { value: (msg: string, type: string, code: string) => { warnings.push([msg, type, code]) }, configurable: true, writable: true, }) //@ts-expect-error new LRUCache({ ttl: 100, }) t.same(warnings, [ [ 'TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.', 'UnboundedCacheWarning', 'LRU_CACHE_UNBOUNDED', ], ]) t.end() }) t.test('prints to stderr if no process.emitWarning', t => { const { LRUCache: LRU } = t.mock('../', {}) as { LRUCache: typeof LRUCache } const { error } = console const { emitWarning } = process t.teardown(() => { console.error = error process.emitWarning = emitWarning }) const warnings: [string][] = [] Object.defineProperty(console, 'error', { value: (msg: string) => { warnings.push([msg]) }, configurable: true, writable: true, }) Object.defineProperty(process, 'emitWarning', { value: undefined, configurable: true, writable: true, }) //@ts-expect-error new LRU({ ttl: 100, }) //@ts-expect-error new LRU({ ttl: 100, }) t.same(warnings, [ [ '[LRU_CACHE_UNBOUNDED] UnboundedCacheWarning: TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.', ], ]) t.end() }) node-lru-cache-10.0.1/test/warn-missing-ac.ts000066400000000000000000000040501446525347600207240ustar00rootroot00000000000000export {} const main = async () => { const { default: t } = await import('tap') const { spawn } = await import('child_process') // need to run both tests in parallel so we don't miss the close event t.jobs = 3 const tsNode = process.platform === 'win32' ? 'ts-node.cmd' : 'ts-node' const warn = spawn(tsNode, [__filename, 'child']) const warnErr: Buffer[] = [] warn.stderr.on('data', c => warnErr.push(c)) const noWarn = spawn(tsNode, [__filename, 'child'], { env: { ...process.env, LRU_CACHE_IGNORE_AC_WARNING: '1', }, }) const noWarnErr: Buffer[] = [] noWarn.stderr.on('data', c => noWarnErr.push(c)) const noFetch = spawn(tsNode, [__filename, 'child-no-fetch']) const noFetchErr: Buffer[] = [] noFetch.stderr.on('data', c => noFetchErr.push(c)) t.test('no warning', async t => { await new Promise(r => noWarn.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) r() }) ) t.equal(Buffer.concat(noWarnErr).toString().trim(), '') }) t.test('no warning (because no fetch)', async t => { await new Promise(r => noFetch.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) r() }) ) t.equal(Buffer.concat(noFetchErr).toString().trim(), '') }) t.test('warning', async t => { await new Promise(r => warn.on('close', (code, signal) => { t.equal(code, 0) t.equal(signal, null) r() }) ) t.not(Buffer.concat(warnErr).toString().trim(), '') }) } switch (process.argv[2]) { case 'child': //@ts-ignore globalThis.AbortController = undefined //@ts-ignore globalThis.AbortSignal = undefined import('../').then(({ LRUCache }) => { new LRUCache({ max: 1, fetchMethod: async () => 1 }).fetch(1) }) break case 'child-no-fetch': //@ts-ignore globalThis.AbortController = undefined //@ts-ignore globalThis.AbortSignal = undefined import('../') break default: main() } node-lru-cache-10.0.1/tsconfig-base.json000066400000000000000000000006401446525347600200160ustar00rootroot00000000000000{ "include": ["src/**/*.ts"], "compilerOptions": { "allowSyntheticDefaultImports": true, "declaration": true, "declarationMap": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "isolatedModules": true, "moduleResolution": "node", "resolveJsonModule": true, "sourceMap": true, "inlineSources": true, "strict": true, "target": "es2022" } } node-lru-cache-10.0.1/tsconfig-esm.json000066400000000000000000000001651446525347600176720ustar00rootroot00000000000000{ "extends": "./tsconfig-base.json", "compilerOptions": { "module": "esnext", "outDir": "dist/mjs" } } node-lru-cache-10.0.1/tsconfig.json000066400000000000000000000002271446525347600171070ustar00rootroot00000000000000{ "extends": "./tsconfig-base.json", "compilerOptions": { "module": "commonjs", "outDir": "dist/cjs", "moduleResolution": "Node" } } node-lru-cache-10.0.1/typedoc.json000066400000000000000000000003701446525347600167410ustar00rootroot00000000000000{ "navigationLinks": { "isaacs projects": "https://isaacs.github.io/", "benchmark summary": "https://isaacs.github.io/node-lru-cache/benchmark/", "benchmark details": "https://isaacs.github.io/node-lru-cache/benchmark/results/" } }