1
0
Fork 0

Added Statistics calculation

Statistics now show calculated values
This commit is contained in:
Techognito 2025-09-04 17:30:00 +02:00
parent fe87374e47
commit fc0f69dacb
2147 changed files with 141321 additions and 39 deletions

21
node_modules/reselect/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015-2018 Reselect Contributors
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.

206
node_modules/reselect/README.md generated vendored Normal file
View file

@ -0,0 +1,206 @@
# Reselect
[![npm package][npm-badge]][npm][![Coveralls][coveralls-badge]][coveralls][![GitHub Workflow Status][build-badge]][build]![TypeScript][typescript-badge]
A library for creating memoized "selector" functions. Commonly used with Redux, but usable with any plain JS immutable data as well.
- Selectors can compute derived data, allowing [Redux] to store the minimal possible state.
- Selectors are efficient. A selector is not recomputed unless one of its arguments changes.
- Selectors are composable. They can be used as input to other selectors.
The **Redux docs usage page on [Deriving Data with Selectors](https://redux.js.org/usage/deriving-data-selectors)** covers the purpose and motivation for selectors, why memoized selectors are useful, typical Reselect usage patterns, and using selectors with [React-Redux].
## Installation
### Redux Toolkit
While Reselect is not exclusive to [Redux], it is already included by default in [the official Redux Toolkit package](https://redux-toolkit.js.org) - no further installation needed.
```ts
import { createSelector } from '@reduxjs/toolkit'
```
### Standalone
For standalone usage, install the `reselect` package:
```bash
# NPM
npm install reselect
# Yarn
yarn add reselect
```
---
## Documentation
The Reselect docs are available at **https://reselect.js.org**, and include usage guides and API references:
- [**Introduction**](#https://reselect.js.org/introduction/getting-started)
- [**How Does Reselect Work?**](#https://reselect.js.org/introduction/how-does-reselect-work)
- **API Reference**:
- **[`createSelector`]**
- **[`createSelectorCreator`]**
- **[`createStructuredSelector`]**
- [**Development-Only Stability Checks**](#https://reselect.js.org/api/development-only-stability-checks)
- **[`lruMemoize`]**
- **[`weakMapMemoize`]**
- [**FAQ**](#https://reselect.js.org/FAQ)
## Basic Usage
Reselect exports a [`createSelector`] API, which generates memoized selector functions. [`createSelector`] accepts one or more [input selectors], which extract values from arguments, and a [result function] function that receives the extracted values and should return a derived value. If the generated [output selector] is called multiple times, the output will only be recalculated when the extracted values have changed.
You can play around with the following **example** in [this CodeSandbox](https://codesandbox.io/s/reselect-example-g3k9gf?file=/src/index.js):
```ts
import { createSelector } from 'reselect'
interface RootState {
todos: { id: number; completed: boolean }[]
alerts: { id: number; read: boolean }[]
}
const state: RootState = {
todos: [
{ id: 0, completed: false },
{ id: 1, completed: true }
],
alerts: [
{ id: 0, read: false },
{ id: 1, read: true }
]
}
const selectCompletedTodos = (state: RootState) => {
console.log('selector ran')
return state.todos.filter(todo => todo.completed === true)
}
selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran
selectCompletedTodos(state) // selector ran
const memoizedSelectCompletedTodos = createSelector(
[(state: RootState) => state.todos],
todos => {
console.log('memoized selector ran')
return todos.filter(todo => todo.completed === true)
}
)
memoizedSelectCompletedTodos(state) // memoized selector ran
memoizedSelectCompletedTodos(state)
memoizedSelectCompletedTodos(state)
console.log(selectCompletedTodos(state) === selectCompletedTodos(state)) //=> false
console.log(
memoizedSelectCompletedTodos(state) === memoizedSelectCompletedTodos(state)
) //=> true
```
As you can see from the example above, `memoizedSelectCompletedTodos` does not run the second or third time, but we still get the same return value as last time.
In addition to skipping unnecessary recalculations, `memoizedSelectCompletedTodos` returns the existing result reference if there is no recalculation. This is important for libraries like [React-Redux] or [React] that often rely on reference equality checks to optimize UI updates.
---
## Terminology
- <a name="selector-function"></a>[**Selector Function**](#selector-function): A function that accepts one or more JavaScript values as arguments, and derives a result. When used with [Redux], the first argument is typically the entire Redux store state.
- <a name="input-selectors"></a>[**input selectors**](#input-selectors): Basic selector functions used as building blocks for creating a memoized selector. They are passed as the first argument(s) to [`createSelector`], and are called with all selector arguments. They are responsible for extracting and providing necessary values to the [result function].
- <a name="output-selector"></a>[**Output Selector**](#output-selector): The actual memoized selectors created by [`createSelector`].
- <a name="result-function"></a>[**Result Function**](#result-function): The function that comes after the [input selectors]. It takes the [input selectors]' return values as arguments and returns a result.
- <a name="dependencies"></a>[**`Dependencies`**](#dependencies): Same as [input selectors]. They are what the [output selector] "depends" on.
The below example serves as a visual aid:
```ts
const outputSelector = createSelector(
[inputSelector1, inputSelector2, inputSelector3], // synonymous with `dependencies`.
resultFunc // Result function
)
```
---
## What's New in 5.0.0?
Version 5.0.0 introduces several new features and improvements:
- **Customization Enhancements**:
- Added the ability to pass an options object to [`createSelectorCreator`], allowing for customized `memoize` and `argsMemoize` functions, alongside their respective options (`memoizeOptions` and `argsMemoizeOptions`).
- The [`createSelector`] function now supports direct customization of `memoize` and `argsMemoize` within its options object.
- **Memoization Functions**:
- Introduced new experimental memoization functions: `weakMapMemoize` and `unstable_autotrackMemoize`.
- Incorporated `memoize` and `argsMemoize` into the [output selector fields] for debugging purposes.
- **TypeScript Support and Performance**:
- Discontinued support for TypeScript versions below 4.7, aligning with modern TypeScript features.
- Significantly improved TypeScript performance for nesting [output selectors][output selector]. The nesting limit has increased from approximately 8 to around 30 [output selectors][output selector], greatly reducing the occurrence of the infamous `Type instantiation is excessively deep and possibly infinite` error.
- **Selector API Enhancements**:
- Removed the second overload of `createStructuredSelector` due to its susceptibility to runtime errors.
- **Additional Functionalities**:
- Added `dependencyRecomputations` and `resetDependencyRecomputations` to the [output selector fields]. These additions provide greater control and insight over [input selectors], complementing the new `argsMemoize` API.
- Introduced `inputStabilityCheck`, a development tool that runs the [input selectors] twice using the same arguments and triggers a warning If they return differing results for the same call.
- Introduced `identityFunctionCheck`, a development tool that checks to see if the [result function] returns its own input.
These updates aim to enhance flexibility, performance, and developer experience. For detailed usage and examples, refer to the updated documentation sections for each feature.
- **Breaking Changes**:
- Removed `ParametricSelector` and `OutputParametricSelector` types. Their functionalities are now integrated into `Selector` and `OutputSelector` respectively, which inherently support additional parameters.
<div align="right">[ <a href="installation">↑ Back to top ↑</a> ]</div>
---
## License
MIT
## References
<details><summary><b>Click to Expand</b></summary>
Originally inspired by getters in [NuclearJS](https://github.com/optimizely/nuclear-js.git), [subscriptions](https://github.com/Day8/re-frame#just-a-read-only-cursor) in [re-frame](https://github.com/Day8/re-frame) and this [proposal](https://github.com/reduxjs/redux/pull/169) from [speedskater](https://github.com/speedskater).
[typescript-badge]: https://img.shields.io/badge/TypeScript-v4%2E7%2B-007ACC?style=for-the-badge&logo=TypeScript&logoColor=black&labelColor=blue&color=gray
[build-badge]: https://img.shields.io/github/actions/workflow/status/reduxjs/reselect/build-and-test-types.yml?branch=master&style=for-the-badge
[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml
[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=for-the-badge
[npm]: https://www.npmjs.org/package/reselect
[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=for-the-badge
[coveralls]: https://coveralls.io/github/reduxjs/reselect
<!-- External Links -->
[Redux]: https://redux.js.org 'Redux'
[React]: https://react.dev 'React'
[React-Redux]: https://react-redux.js.org 'React-Redux'
<!-- Internal Links -->
[selector]: #selector-function 'Selector Function'
[input selectors]: #input-selectors 'Input Selectors'
[output selector]: #output-selector 'Output Selector'
[result function]: #result-function 'Result Function'
[output selector fields]: https://reselect.js.org/api/createSelector#output-selector-fields 'Output Selector Fields'
[`createSelector`]: https://reselect.js.org/api/createSelector 'createSelector'
[`createSelectorCreator`]: https://reselect.js.org/api/createSelectorCreator 'createSelectorCreator'
[`lruMemoize`]: https://reselect.js.org/api/lruMemoize 'lruMemoize'
[`weakMapMemoize`]: https://reselect.js.org/api/weakMapMemoize 'weakMapMemoize'
[`createStructuredSelector`]: https://reselect.js.org/api/createStructuredSelector 'createStructuredSelector'
</details>

777
node_modules/reselect/dist/cjs/reselect.cjs generated vendored Normal file
View file

@ -0,0 +1,777 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
createSelector: () => createSelector,
createSelectorCreator: () => createSelectorCreator,
createStructuredSelector: () => createStructuredSelector,
lruMemoize: () => lruMemoize,
referenceEqualityCheck: () => referenceEqualityCheck,
setGlobalDevModeChecks: () => setGlobalDevModeChecks,
unstable_autotrackMemoize: () => autotrackMemoize,
weakMapMemoize: () => weakMapMemoize
});
module.exports = __toCommonJS(src_exports);
// src/devModeChecks/identityFunctionCheck.ts
var runIdentityFunctionCheck = (resultFunc, inputSelectorsResults, outputSelectorResult) => {
if (inputSelectorsResults.length === 1 && inputSelectorsResults[0] === outputSelectorResult) {
let isInputSameAsOutput = false;
try {
const emptyObject = {};
if (resultFunc(emptyObject) === emptyObject)
isInputSameAsOutput = true;
} catch {
}
if (isInputSameAsOutput) {
let stack = void 0;
try {
throw new Error();
} catch (e) {
;
({ stack } = e);
}
console.warn(
"The result function returned its own inputs without modification. e.g\n`createSelector([state => state.todos], todos => todos)`\nThis could lead to inefficient memoization and unnecessary re-renders.\nEnsure transformation logic is in the result function, and extraction logic is in the input selectors.",
{ stack }
);
}
}
};
// src/devModeChecks/inputStabilityCheck.ts
var runInputStabilityCheck = (inputSelectorResultsObject, options, inputSelectorArgs) => {
const { memoize, memoizeOptions } = options;
const { inputSelectorResults, inputSelectorResultsCopy } = inputSelectorResultsObject;
const createAnEmptyObject = memoize(() => ({}), ...memoizeOptions);
const areInputSelectorResultsEqual = createAnEmptyObject.apply(null, inputSelectorResults) === createAnEmptyObject.apply(null, inputSelectorResultsCopy);
if (!areInputSelectorResultsEqual) {
let stack = void 0;
try {
throw new Error();
} catch (e) {
;
({ stack } = e);
}
console.warn(
"An input selector returned a different result when passed same arguments.\nThis means your output selector will likely run more frequently than intended.\nAvoid returning a new reference inside your input selector, e.g.\n`createSelector([state => state.todos.map(todo => todo.id)], todoIds => todoIds.length)`",
{
arguments: inputSelectorArgs,
firstInputs: inputSelectorResults,
secondInputs: inputSelectorResultsCopy,
stack
}
);
}
};
// src/devModeChecks/setGlobalDevModeChecks.ts
var globalDevModeChecks = {
inputStabilityCheck: "once",
identityFunctionCheck: "once"
};
var setGlobalDevModeChecks = (devModeChecks) => {
Object.assign(globalDevModeChecks, devModeChecks);
};
// src/utils.ts
var NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
function assertIsFunction(func, errorMessage = `expected a function, instead received ${typeof func}`) {
if (typeof func !== "function") {
throw new TypeError(errorMessage);
}
}
function assertIsObject(object, errorMessage = `expected an object, instead received ${typeof object}`) {
if (typeof object !== "object") {
throw new TypeError(errorMessage);
}
}
function assertIsArrayOfFunctions(array, errorMessage = `expected all items to be functions, instead received the following types: `) {
if (!array.every((item) => typeof item === "function")) {
const itemTypes = array.map(
(item) => typeof item === "function" ? `function ${item.name || "unnamed"}()` : typeof item
).join(", ");
throw new TypeError(`${errorMessage}[${itemTypes}]`);
}
}
var ensureIsArray = (item) => {
return Array.isArray(item) ? item : [item];
};
function getDependencies(createSelectorArgs) {
const dependencies = Array.isArray(createSelectorArgs[0]) ? createSelectorArgs[0] : createSelectorArgs;
assertIsArrayOfFunctions(
dependencies,
`createSelector expects all input-selectors to be functions, but received the following types: `
);
return dependencies;
}
function collectInputSelectorResults(dependencies, inputSelectorArgs) {
const inputSelectorResults = [];
const { length } = dependencies;
for (let i = 0; i < length; i++) {
inputSelectorResults.push(dependencies[i].apply(null, inputSelectorArgs));
}
return inputSelectorResults;
}
var getDevModeChecksExecutionInfo = (firstRun, devModeChecks) => {
const { identityFunctionCheck, inputStabilityCheck } = {
...globalDevModeChecks,
...devModeChecks
};
return {
identityFunctionCheck: {
shouldRun: identityFunctionCheck === "always" || identityFunctionCheck === "once" && firstRun,
run: runIdentityFunctionCheck
},
inputStabilityCheck: {
shouldRun: inputStabilityCheck === "always" || inputStabilityCheck === "once" && firstRun,
run: runInputStabilityCheck
}
};
};
// src/autotrackMemoize/autotracking.ts
var $REVISION = 0;
var CURRENT_TRACKER = null;
var Cell = class {
revision = $REVISION;
_value;
_lastValue;
_isEqual = tripleEq;
constructor(initialValue, isEqual = tripleEq) {
this._value = this._lastValue = initialValue;
this._isEqual = isEqual;
}
// Whenever a storage value is read, it'll add itself to the current tracker if
// one exists, entangling its state with that cache.
get value() {
CURRENT_TRACKER?.add(this);
return this._value;
}
// Whenever a storage value is updated, we bump the global revision clock,
// assign the revision for this storage to the new value, _and_ we schedule a
// rerender. This is important, and it's what makes autotracking _pull_
// based. We don't actively tell the caches which depend on the storage that
// anything has happened. Instead, we recompute the caches when needed.
set value(newValue) {
if (this.value === newValue)
return;
this._value = newValue;
this.revision = ++$REVISION;
}
};
function tripleEq(a, b) {
return a === b;
}
var TrackingCache = class {
_cachedValue;
_cachedRevision = -1;
_deps = [];
hits = 0;
fn;
constructor(fn) {
this.fn = fn;
}
clear() {
this._cachedValue = void 0;
this._cachedRevision = -1;
this._deps = [];
this.hits = 0;
}
get value() {
if (this.revision > this._cachedRevision) {
const { fn } = this;
const currentTracker = /* @__PURE__ */ new Set();
const prevTracker = CURRENT_TRACKER;
CURRENT_TRACKER = currentTracker;
this._cachedValue = fn();
CURRENT_TRACKER = prevTracker;
this.hits++;
this._deps = Array.from(currentTracker);
this._cachedRevision = this.revision;
}
CURRENT_TRACKER?.add(this);
return this._cachedValue;
}
get revision() {
return Math.max(...this._deps.map((d) => d.revision), 0);
}
};
function getValue(cell) {
if (!(cell instanceof Cell)) {
console.warn("Not a valid cell! ", cell);
}
return cell.value;
}
function setValue(storage, value) {
if (!(storage instanceof Cell)) {
throw new TypeError(
"setValue must be passed a tracked store created with `createStorage`."
);
}
storage.value = storage._lastValue = value;
}
function createCell(initialValue, isEqual = tripleEq) {
return new Cell(initialValue, isEqual);
}
function createCache(fn) {
assertIsFunction(
fn,
"the first parameter to `createCache` must be a function"
);
return new TrackingCache(fn);
}
// src/autotrackMemoize/tracking.ts
var neverEq = (a, b) => false;
function createTag() {
return createCell(null, neverEq);
}
function dirtyTag(tag, value) {
setValue(tag, value);
}
var consumeCollection = (node) => {
let tag = node.collectionTag;
if (tag === null) {
tag = node.collectionTag = createTag();
}
getValue(tag);
};
var dirtyCollection = (node) => {
const tag = node.collectionTag;
if (tag !== null) {
dirtyTag(tag, null);
}
};
// src/autotrackMemoize/proxy.ts
var REDUX_PROXY_LABEL = Symbol();
var nextId = 0;
var proto = Object.getPrototypeOf({});
var ObjectTreeNode = class {
constructor(value) {
this.value = value;
this.value = value;
this.tag.value = value;
}
proxy = new Proxy(this, objectProxyHandler);
tag = createTag();
tags = {};
children = {};
collectionTag = null;
id = nextId++;
};
var objectProxyHandler = {
get(node, key) {
function calculateResult() {
const { value } = node;
const childValue = Reflect.get(value, key);
if (typeof key === "symbol") {
return childValue;
}
if (key in proto) {
return childValue;
}
if (typeof childValue === "object" && childValue !== null) {
let childNode = node.children[key];
if (childNode === void 0) {
childNode = node.children[key] = createNode(childValue);
}
if (childNode.tag) {
getValue(childNode.tag);
}
return childNode.proxy;
} else {
let tag = node.tags[key];
if (tag === void 0) {
tag = node.tags[key] = createTag();
tag.value = childValue;
}
getValue(tag);
return childValue;
}
}
const res = calculateResult();
return res;
},
ownKeys(node) {
consumeCollection(node);
return Reflect.ownKeys(node.value);
},
getOwnPropertyDescriptor(node, prop) {
return Reflect.getOwnPropertyDescriptor(node.value, prop);
},
has(node, prop) {
return Reflect.has(node.value, prop);
}
};
var ArrayTreeNode = class {
constructor(value) {
this.value = value;
this.value = value;
this.tag.value = value;
}
proxy = new Proxy([this], arrayProxyHandler);
tag = createTag();
tags = {};
children = {};
collectionTag = null;
id = nextId++;
};
var arrayProxyHandler = {
get([node], key) {
if (key === "length") {
consumeCollection(node);
}
return objectProxyHandler.get(node, key);
},
ownKeys([node]) {
return objectProxyHandler.ownKeys(node);
},
getOwnPropertyDescriptor([node], prop) {
return objectProxyHandler.getOwnPropertyDescriptor(node, prop);
},
has([node], prop) {
return objectProxyHandler.has(node, prop);
}
};
function createNode(value) {
if (Array.isArray(value)) {
return new ArrayTreeNode(value);
}
return new ObjectTreeNode(value);
}
function updateNode(node, newValue) {
const { value, tags, children } = node;
node.value = newValue;
if (Array.isArray(value) && Array.isArray(newValue) && value.length !== newValue.length) {
dirtyCollection(node);
} else {
if (value !== newValue) {
let oldKeysSize = 0;
let newKeysSize = 0;
let anyKeysAdded = false;
for (const _key in value) {
oldKeysSize++;
}
for (const key in newValue) {
newKeysSize++;
if (!(key in value)) {
anyKeysAdded = true;
break;
}
}
const isDifferent = anyKeysAdded || oldKeysSize !== newKeysSize;
if (isDifferent) {
dirtyCollection(node);
}
}
}
for (const key in tags) {
const childValue = value[key];
const newChildValue = newValue[key];
if (childValue !== newChildValue) {
dirtyCollection(node);
dirtyTag(tags[key], newChildValue);
}
if (typeof newChildValue === "object" && newChildValue !== null) {
delete tags[key];
}
}
for (const key in children) {
const childNode = children[key];
const newChildValue = newValue[key];
const childValue = childNode.value;
if (childValue === newChildValue) {
continue;
} else if (typeof newChildValue === "object" && newChildValue !== null) {
updateNode(childNode, newChildValue);
} else {
deleteNode(childNode);
delete children[key];
}
}
}
function deleteNode(node) {
if (node.tag) {
dirtyTag(node.tag, null);
}
dirtyCollection(node);
for (const key in node.tags) {
dirtyTag(node.tags[key], null);
}
for (const key in node.children) {
deleteNode(node.children[key]);
}
}
// src/lruMemoize.ts
function createSingletonCache(equals) {
let entry;
return {
get(key) {
if (entry && equals(entry.key, key)) {
return entry.value;
}
return NOT_FOUND;
},
put(key, value) {
entry = { key, value };
},
getEntries() {
return entry ? [entry] : [];
},
clear() {
entry = void 0;
}
};
}
function createLruCache(maxSize, equals) {
let entries = [];
function get(key) {
const cacheIndex = entries.findIndex((entry) => equals(key, entry.key));
if (cacheIndex > -1) {
const entry = entries[cacheIndex];
if (cacheIndex > 0) {
entries.splice(cacheIndex, 1);
entries.unshift(entry);
}
return entry.value;
}
return NOT_FOUND;
}
function put(key, value) {
if (get(key) === NOT_FOUND) {
entries.unshift({ key, value });
if (entries.length > maxSize) {
entries.pop();
}
}
}
function getEntries() {
return entries;
}
function clear() {
entries = [];
}
return { get, put, getEntries, clear };
}
var referenceEqualityCheck = (a, b) => a === b;
function createCacheKeyComparator(equalityCheck) {
return function areArgumentsShallowlyEqual(prev, next) {
if (prev === null || next === null || prev.length !== next.length) {
return false;
}
const { length } = prev;
for (let i = 0; i < length; i++) {
if (!equalityCheck(prev[i], next[i])) {
return false;
}
}
return true;
};
}
function lruMemoize(func, equalityCheckOrOptions) {
const providedOptions = typeof equalityCheckOrOptions === "object" ? equalityCheckOrOptions : { equalityCheck: equalityCheckOrOptions };
const {
equalityCheck = referenceEqualityCheck,
maxSize = 1,
resultEqualityCheck
} = providedOptions;
const comparator = createCacheKeyComparator(equalityCheck);
let resultsCount = 0;
const cache = maxSize <= 1 ? createSingletonCache(comparator) : createLruCache(maxSize, comparator);
function memoized() {
let value = cache.get(arguments);
if (value === NOT_FOUND) {
value = func.apply(null, arguments);
resultsCount++;
if (resultEqualityCheck) {
const entries = cache.getEntries();
const matchingEntry = entries.find(
(entry) => resultEqualityCheck(entry.value, value)
);
if (matchingEntry) {
value = matchingEntry.value;
resultsCount !== 0 && resultsCount--;
}
}
cache.put(arguments, value);
}
return value;
}
memoized.clearCache = () => {
cache.clear();
memoized.resetResultsCount();
};
memoized.resultsCount = () => resultsCount;
memoized.resetResultsCount = () => {
resultsCount = 0;
};
return memoized;
}
// src/autotrackMemoize/autotrackMemoize.ts
function autotrackMemoize(func) {
const node = createNode(
[]
);
let lastArgs = null;
const shallowEqual = createCacheKeyComparator(referenceEqualityCheck);
const cache = createCache(() => {
const res = func.apply(null, node.proxy);
return res;
});
function memoized() {
if (!shallowEqual(lastArgs, arguments)) {
updateNode(node, arguments);
lastArgs = arguments;
}
return cache.value;
}
memoized.clearCache = () => {
return cache.clear();
};
return memoized;
}
// src/weakMapMemoize.ts
var StrongRef = class {
constructor(value) {
this.value = value;
}
deref() {
return this.value;
}
};
var Ref = typeof WeakRef !== "undefined" ? WeakRef : StrongRef;
var UNTERMINATED = 0;
var TERMINATED = 1;
function createCacheNode() {
return {
s: UNTERMINATED,
v: void 0,
o: null,
p: null
};
}
function weakMapMemoize(func, options = {}) {
let fnNode = createCacheNode();
const { resultEqualityCheck } = options;
let lastResult;
let resultsCount = 0;
function memoized() {
let cacheNode = fnNode;
const { length } = arguments;
for (let i = 0, l = length; i < l; i++) {
const arg = arguments[i];
if (typeof arg === "function" || typeof arg === "object" && arg !== null) {
let objectCache = cacheNode.o;
if (objectCache === null) {
cacheNode.o = objectCache = /* @__PURE__ */ new WeakMap();
}
const objectNode = objectCache.get(arg);
if (objectNode === void 0) {
cacheNode = createCacheNode();
objectCache.set(arg, cacheNode);
} else {
cacheNode = objectNode;
}
} else {
let primitiveCache = cacheNode.p;
if (primitiveCache === null) {
cacheNode.p = primitiveCache = /* @__PURE__ */ new Map();
}
const primitiveNode = primitiveCache.get(arg);
if (primitiveNode === void 0) {
cacheNode = createCacheNode();
primitiveCache.set(arg, cacheNode);
} else {
cacheNode = primitiveNode;
}
}
}
const terminatedNode = cacheNode;
let result;
if (cacheNode.s === TERMINATED) {
result = cacheNode.v;
} else {
result = func.apply(null, arguments);
resultsCount++;
if (resultEqualityCheck) {
const lastResultValue = lastResult?.deref?.() ?? lastResult;
if (lastResultValue != null && resultEqualityCheck(lastResultValue, result)) {
result = lastResultValue;
resultsCount !== 0 && resultsCount--;
}
const needsWeakRef = typeof result === "object" && result !== null || typeof result === "function";
lastResult = needsWeakRef ? new Ref(result) : result;
}
}
terminatedNode.s = TERMINATED;
terminatedNode.v = result;
return result;
}
memoized.clearCache = () => {
fnNode = createCacheNode();
memoized.resetResultsCount();
};
memoized.resultsCount = () => resultsCount;
memoized.resetResultsCount = () => {
resultsCount = 0;
};
return memoized;
}
// src/createSelectorCreator.ts
function createSelectorCreator(memoizeOrOptions, ...memoizeOptionsFromArgs) {
const createSelectorCreatorOptions = typeof memoizeOrOptions === "function" ? {
memoize: memoizeOrOptions,
memoizeOptions: memoizeOptionsFromArgs
} : memoizeOrOptions;
const createSelector2 = (...createSelectorArgs) => {
let recomputations = 0;
let dependencyRecomputations = 0;
let lastResult;
let directlyPassedOptions = {};
let resultFunc = createSelectorArgs.pop();
if (typeof resultFunc === "object") {
directlyPassedOptions = resultFunc;
resultFunc = createSelectorArgs.pop();
}
assertIsFunction(
resultFunc,
`createSelector expects an output function after the inputs, but received: [${typeof resultFunc}]`
);
const combinedOptions = {
...createSelectorCreatorOptions,
...directlyPassedOptions
};
const {
memoize,
memoizeOptions = [],
argsMemoize = weakMapMemoize,
argsMemoizeOptions = [],
devModeChecks = {}
} = combinedOptions;
const finalMemoizeOptions = ensureIsArray(memoizeOptions);
const finalArgsMemoizeOptions = ensureIsArray(argsMemoizeOptions);
const dependencies = getDependencies(createSelectorArgs);
const memoizedResultFunc = memoize(function recomputationWrapper() {
recomputations++;
return resultFunc.apply(
null,
arguments
);
}, ...finalMemoizeOptions);
let firstRun = true;
const selector = argsMemoize(function dependenciesChecker() {
dependencyRecomputations++;
const inputSelectorResults = collectInputSelectorResults(
dependencies,
arguments
);
lastResult = memoizedResultFunc.apply(null, inputSelectorResults);
if (process.env.NODE_ENV !== "production") {
const { identityFunctionCheck, inputStabilityCheck } = getDevModeChecksExecutionInfo(firstRun, devModeChecks);
if (identityFunctionCheck.shouldRun) {
identityFunctionCheck.run(
resultFunc,
inputSelectorResults,
lastResult
);
}
if (inputStabilityCheck.shouldRun) {
const inputSelectorResultsCopy = collectInputSelectorResults(
dependencies,
arguments
);
inputStabilityCheck.run(
{ inputSelectorResults, inputSelectorResultsCopy },
{ memoize, memoizeOptions: finalMemoizeOptions },
arguments
);
}
if (firstRun)
firstRun = false;
}
return lastResult;
}, ...finalArgsMemoizeOptions);
return Object.assign(selector, {
resultFunc,
memoizedResultFunc,
dependencies,
dependencyRecomputations: () => dependencyRecomputations,
resetDependencyRecomputations: () => {
dependencyRecomputations = 0;
},
lastResult: () => lastResult,
recomputations: () => recomputations,
resetRecomputations: () => {
recomputations = 0;
},
memoize,
argsMemoize
});
};
Object.assign(createSelector2, {
withTypes: () => createSelector2
});
return createSelector2;
}
var createSelector = /* @__PURE__ */ createSelectorCreator(weakMapMemoize);
// src/createStructuredSelector.ts
var createStructuredSelector = Object.assign(
(inputSelectorsObject, selectorCreator = createSelector) => {
assertIsObject(
inputSelectorsObject,
`createStructuredSelector expects first argument to be an object where each property is a selector, instead received a ${typeof inputSelectorsObject}`
);
const inputSelectorKeys = Object.keys(inputSelectorsObject);
const dependencies = inputSelectorKeys.map(
(key) => inputSelectorsObject[key]
);
const structuredSelector = selectorCreator(
dependencies,
(...inputSelectorResults) => {
return inputSelectorResults.reduce((composition, value, index) => {
composition[inputSelectorKeys[index]] = value;
return composition;
}, {});
}
);
return structuredSelector;
},
{ withTypes: () => createStructuredSelector }
);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
createSelector,
createSelectorCreator,
createStructuredSelector,
lruMemoize,
referenceEqualityCheck,
setGlobalDevModeChecks,
unstable_autotrackMemoize,
weakMapMemoize
});
//# sourceMappingURL=reselect.cjs.map

1
node_modules/reselect/dist/cjs/reselect.cjs.map generated vendored Normal file

File diff suppressed because one or more lines are too long

2
node_modules/reselect/dist/reselect.browser.mjs generated vendored Normal file

File diff suppressed because one or more lines are too long

1
node_modules/reselect/dist/reselect.browser.mjs.map generated vendored Normal file

File diff suppressed because one or more lines are too long

1429
node_modules/reselect/dist/reselect.d.ts generated vendored Normal file

File diff suppressed because it is too large Load diff

759
node_modules/reselect/dist/reselect.legacy-esm.js generated vendored Normal file
View file

@ -0,0 +1,759 @@
var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// src/devModeChecks/identityFunctionCheck.ts
var runIdentityFunctionCheck = (resultFunc, inputSelectorsResults, outputSelectorResult) => {
if (inputSelectorsResults.length === 1 && inputSelectorsResults[0] === outputSelectorResult) {
let isInputSameAsOutput = false;
try {
const emptyObject = {};
if (resultFunc(emptyObject) === emptyObject)
isInputSameAsOutput = true;
} catch (e) {
}
if (isInputSameAsOutput) {
let stack = void 0;
try {
throw new Error();
} catch (e) {
;
({ stack } = e);
}
console.warn(
"The result function returned its own inputs without modification. e.g\n`createSelector([state => state.todos], todos => todos)`\nThis could lead to inefficient memoization and unnecessary re-renders.\nEnsure transformation logic is in the result function, and extraction logic is in the input selectors.",
{ stack }
);
}
}
};
// src/devModeChecks/inputStabilityCheck.ts
var runInputStabilityCheck = (inputSelectorResultsObject, options, inputSelectorArgs) => {
const { memoize, memoizeOptions } = options;
const { inputSelectorResults, inputSelectorResultsCopy } = inputSelectorResultsObject;
const createAnEmptyObject = memoize(() => ({}), ...memoizeOptions);
const areInputSelectorResultsEqual = createAnEmptyObject.apply(null, inputSelectorResults) === createAnEmptyObject.apply(null, inputSelectorResultsCopy);
if (!areInputSelectorResultsEqual) {
let stack = void 0;
try {
throw new Error();
} catch (e) {
;
({ stack } = e);
}
console.warn(
"An input selector returned a different result when passed same arguments.\nThis means your output selector will likely run more frequently than intended.\nAvoid returning a new reference inside your input selector, e.g.\n`createSelector([state => state.todos.map(todo => todo.id)], todoIds => todoIds.length)`",
{
arguments: inputSelectorArgs,
firstInputs: inputSelectorResults,
secondInputs: inputSelectorResultsCopy,
stack
}
);
}
};
// src/devModeChecks/setGlobalDevModeChecks.ts
var globalDevModeChecks = {
inputStabilityCheck: "once",
identityFunctionCheck: "once"
};
var setGlobalDevModeChecks = (devModeChecks) => {
Object.assign(globalDevModeChecks, devModeChecks);
};
// src/utils.ts
var NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
function assertIsFunction(func, errorMessage = `expected a function, instead received ${typeof func}`) {
if (typeof func !== "function") {
throw new TypeError(errorMessage);
}
}
function assertIsObject(object, errorMessage = `expected an object, instead received ${typeof object}`) {
if (typeof object !== "object") {
throw new TypeError(errorMessage);
}
}
function assertIsArrayOfFunctions(array, errorMessage = `expected all items to be functions, instead received the following types: `) {
if (!array.every((item) => typeof item === "function")) {
const itemTypes = array.map(
(item) => typeof item === "function" ? `function ${item.name || "unnamed"}()` : typeof item
).join(", ");
throw new TypeError(`${errorMessage}[${itemTypes}]`);
}
}
var ensureIsArray = (item) => {
return Array.isArray(item) ? item : [item];
};
function getDependencies(createSelectorArgs) {
const dependencies = Array.isArray(createSelectorArgs[0]) ? createSelectorArgs[0] : createSelectorArgs;
assertIsArrayOfFunctions(
dependencies,
`createSelector expects all input-selectors to be functions, but received the following types: `
);
return dependencies;
}
function collectInputSelectorResults(dependencies, inputSelectorArgs) {
const inputSelectorResults = [];
const { length } = dependencies;
for (let i = 0; i < length; i++) {
inputSelectorResults.push(dependencies[i].apply(null, inputSelectorArgs));
}
return inputSelectorResults;
}
var getDevModeChecksExecutionInfo = (firstRun, devModeChecks) => {
const { identityFunctionCheck, inputStabilityCheck } = __spreadValues(__spreadValues({}, globalDevModeChecks), devModeChecks);
return {
identityFunctionCheck: {
shouldRun: identityFunctionCheck === "always" || identityFunctionCheck === "once" && firstRun,
run: runIdentityFunctionCheck
},
inputStabilityCheck: {
shouldRun: inputStabilityCheck === "always" || inputStabilityCheck === "once" && firstRun,
run: runInputStabilityCheck
}
};
};
// src/autotrackMemoize/autotracking.ts
var $REVISION = 0;
var CURRENT_TRACKER = null;
var Cell = class {
constructor(initialValue, isEqual = tripleEq) {
__publicField(this, "revision", $REVISION);
__publicField(this, "_value");
__publicField(this, "_lastValue");
__publicField(this, "_isEqual", tripleEq);
this._value = this._lastValue = initialValue;
this._isEqual = isEqual;
}
// Whenever a storage value is read, it'll add itself to the current tracker if
// one exists, entangling its state with that cache.
get value() {
CURRENT_TRACKER == null ? void 0 : CURRENT_TRACKER.add(this);
return this._value;
}
// Whenever a storage value is updated, we bump the global revision clock,
// assign the revision for this storage to the new value, _and_ we schedule a
// rerender. This is important, and it's what makes autotracking _pull_
// based. We don't actively tell the caches which depend on the storage that
// anything has happened. Instead, we recompute the caches when needed.
set value(newValue) {
if (this.value === newValue)
return;
this._value = newValue;
this.revision = ++$REVISION;
}
};
function tripleEq(a, b) {
return a === b;
}
var TrackingCache = class {
constructor(fn) {
__publicField(this, "_cachedValue");
__publicField(this, "_cachedRevision", -1);
__publicField(this, "_deps", []);
__publicField(this, "hits", 0);
__publicField(this, "fn");
this.fn = fn;
}
clear() {
this._cachedValue = void 0;
this._cachedRevision = -1;
this._deps = [];
this.hits = 0;
}
get value() {
if (this.revision > this._cachedRevision) {
const { fn } = this;
const currentTracker = /* @__PURE__ */ new Set();
const prevTracker = CURRENT_TRACKER;
CURRENT_TRACKER = currentTracker;
this._cachedValue = fn();
CURRENT_TRACKER = prevTracker;
this.hits++;
this._deps = Array.from(currentTracker);
this._cachedRevision = this.revision;
}
CURRENT_TRACKER == null ? void 0 : CURRENT_TRACKER.add(this);
return this._cachedValue;
}
get revision() {
return Math.max(...this._deps.map((d) => d.revision), 0);
}
};
function getValue(cell) {
if (!(cell instanceof Cell)) {
console.warn("Not a valid cell! ", cell);
}
return cell.value;
}
function setValue(storage, value) {
if (!(storage instanceof Cell)) {
throw new TypeError(
"setValue must be passed a tracked store created with `createStorage`."
);
}
storage.value = storage._lastValue = value;
}
function createCell(initialValue, isEqual = tripleEq) {
return new Cell(initialValue, isEqual);
}
function createCache(fn) {
assertIsFunction(
fn,
"the first parameter to `createCache` must be a function"
);
return new TrackingCache(fn);
}
// src/autotrackMemoize/tracking.ts
var neverEq = (a, b) => false;
function createTag() {
return createCell(null, neverEq);
}
function dirtyTag(tag, value) {
setValue(tag, value);
}
var consumeCollection = (node) => {
let tag = node.collectionTag;
if (tag === null) {
tag = node.collectionTag = createTag();
}
getValue(tag);
};
var dirtyCollection = (node) => {
const tag = node.collectionTag;
if (tag !== null) {
dirtyTag(tag, null);
}
};
// src/autotrackMemoize/proxy.ts
var REDUX_PROXY_LABEL = Symbol();
var nextId = 0;
var proto = Object.getPrototypeOf({});
var ObjectTreeNode = class {
constructor(value) {
this.value = value;
__publicField(this, "proxy", new Proxy(this, objectProxyHandler));
__publicField(this, "tag", createTag());
__publicField(this, "tags", {});
__publicField(this, "children", {});
__publicField(this, "collectionTag", null);
__publicField(this, "id", nextId++);
this.value = value;
this.tag.value = value;
}
};
var objectProxyHandler = {
get(node, key) {
function calculateResult() {
const { value } = node;
const childValue = Reflect.get(value, key);
if (typeof key === "symbol") {
return childValue;
}
if (key in proto) {
return childValue;
}
if (typeof childValue === "object" && childValue !== null) {
let childNode = node.children[key];
if (childNode === void 0) {
childNode = node.children[key] = createNode(childValue);
}
if (childNode.tag) {
getValue(childNode.tag);
}
return childNode.proxy;
} else {
let tag = node.tags[key];
if (tag === void 0) {
tag = node.tags[key] = createTag();
tag.value = childValue;
}
getValue(tag);
return childValue;
}
}
const res = calculateResult();
return res;
},
ownKeys(node) {
consumeCollection(node);
return Reflect.ownKeys(node.value);
},
getOwnPropertyDescriptor(node, prop) {
return Reflect.getOwnPropertyDescriptor(node.value, prop);
},
has(node, prop) {
return Reflect.has(node.value, prop);
}
};
var ArrayTreeNode = class {
constructor(value) {
this.value = value;
__publicField(this, "proxy", new Proxy([this], arrayProxyHandler));
__publicField(this, "tag", createTag());
__publicField(this, "tags", {});
__publicField(this, "children", {});
__publicField(this, "collectionTag", null);
__publicField(this, "id", nextId++);
this.value = value;
this.tag.value = value;
}
};
var arrayProxyHandler = {
get([node], key) {
if (key === "length") {
consumeCollection(node);
}
return objectProxyHandler.get(node, key);
},
ownKeys([node]) {
return objectProxyHandler.ownKeys(node);
},
getOwnPropertyDescriptor([node], prop) {
return objectProxyHandler.getOwnPropertyDescriptor(node, prop);
},
has([node], prop) {
return objectProxyHandler.has(node, prop);
}
};
function createNode(value) {
if (Array.isArray(value)) {
return new ArrayTreeNode(value);
}
return new ObjectTreeNode(value);
}
function updateNode(node, newValue) {
const { value, tags, children } = node;
node.value = newValue;
if (Array.isArray(value) && Array.isArray(newValue) && value.length !== newValue.length) {
dirtyCollection(node);
} else {
if (value !== newValue) {
let oldKeysSize = 0;
let newKeysSize = 0;
let anyKeysAdded = false;
for (const _key in value) {
oldKeysSize++;
}
for (const key in newValue) {
newKeysSize++;
if (!(key in value)) {
anyKeysAdded = true;
break;
}
}
const isDifferent = anyKeysAdded || oldKeysSize !== newKeysSize;
if (isDifferent) {
dirtyCollection(node);
}
}
}
for (const key in tags) {
const childValue = value[key];
const newChildValue = newValue[key];
if (childValue !== newChildValue) {
dirtyCollection(node);
dirtyTag(tags[key], newChildValue);
}
if (typeof newChildValue === "object" && newChildValue !== null) {
delete tags[key];
}
}
for (const key in children) {
const childNode = children[key];
const newChildValue = newValue[key];
const childValue = childNode.value;
if (childValue === newChildValue) {
continue;
} else if (typeof newChildValue === "object" && newChildValue !== null) {
updateNode(childNode, newChildValue);
} else {
deleteNode(childNode);
delete children[key];
}
}
}
function deleteNode(node) {
if (node.tag) {
dirtyTag(node.tag, null);
}
dirtyCollection(node);
for (const key in node.tags) {
dirtyTag(node.tags[key], null);
}
for (const key in node.children) {
deleteNode(node.children[key]);
}
}
// src/lruMemoize.ts
function createSingletonCache(equals) {
let entry;
return {
get(key) {
if (entry && equals(entry.key, key)) {
return entry.value;
}
return NOT_FOUND;
},
put(key, value) {
entry = { key, value };
},
getEntries() {
return entry ? [entry] : [];
},
clear() {
entry = void 0;
}
};
}
function createLruCache(maxSize, equals) {
let entries = [];
function get(key) {
const cacheIndex = entries.findIndex((entry) => equals(key, entry.key));
if (cacheIndex > -1) {
const entry = entries[cacheIndex];
if (cacheIndex > 0) {
entries.splice(cacheIndex, 1);
entries.unshift(entry);
}
return entry.value;
}
return NOT_FOUND;
}
function put(key, value) {
if (get(key) === NOT_FOUND) {
entries.unshift({ key, value });
if (entries.length > maxSize) {
entries.pop();
}
}
}
function getEntries() {
return entries;
}
function clear() {
entries = [];
}
return { get, put, getEntries, clear };
}
var referenceEqualityCheck = (a, b) => a === b;
function createCacheKeyComparator(equalityCheck) {
return function areArgumentsShallowlyEqual(prev, next) {
if (prev === null || next === null || prev.length !== next.length) {
return false;
}
const { length } = prev;
for (let i = 0; i < length; i++) {
if (!equalityCheck(prev[i], next[i])) {
return false;
}
}
return true;
};
}
function lruMemoize(func, equalityCheckOrOptions) {
const providedOptions = typeof equalityCheckOrOptions === "object" ? equalityCheckOrOptions : { equalityCheck: equalityCheckOrOptions };
const {
equalityCheck = referenceEqualityCheck,
maxSize = 1,
resultEqualityCheck
} = providedOptions;
const comparator = createCacheKeyComparator(equalityCheck);
let resultsCount = 0;
const cache = maxSize <= 1 ? createSingletonCache(comparator) : createLruCache(maxSize, comparator);
function memoized() {
let value = cache.get(arguments);
if (value === NOT_FOUND) {
value = func.apply(null, arguments);
resultsCount++;
if (resultEqualityCheck) {
const entries = cache.getEntries();
const matchingEntry = entries.find(
(entry) => resultEqualityCheck(entry.value, value)
);
if (matchingEntry) {
value = matchingEntry.value;
resultsCount !== 0 && resultsCount--;
}
}
cache.put(arguments, value);
}
return value;
}
memoized.clearCache = () => {
cache.clear();
memoized.resetResultsCount();
};
memoized.resultsCount = () => resultsCount;
memoized.resetResultsCount = () => {
resultsCount = 0;
};
return memoized;
}
// src/autotrackMemoize/autotrackMemoize.ts
function autotrackMemoize(func) {
const node = createNode(
[]
);
let lastArgs = null;
const shallowEqual = createCacheKeyComparator(referenceEqualityCheck);
const cache = createCache(() => {
const res = func.apply(null, node.proxy);
return res;
});
function memoized() {
if (!shallowEqual(lastArgs, arguments)) {
updateNode(node, arguments);
lastArgs = arguments;
}
return cache.value;
}
memoized.clearCache = () => {
return cache.clear();
};
return memoized;
}
// src/weakMapMemoize.ts
var StrongRef = class {
constructor(value) {
this.value = value;
}
deref() {
return this.value;
}
};
var Ref = typeof WeakRef !== "undefined" ? WeakRef : StrongRef;
var UNTERMINATED = 0;
var TERMINATED = 1;
function createCacheNode() {
return {
s: UNTERMINATED,
v: void 0,
o: null,
p: null
};
}
function weakMapMemoize(func, options = {}) {
let fnNode = createCacheNode();
const { resultEqualityCheck } = options;
let lastResult;
let resultsCount = 0;
function memoized() {
var _a, _b;
let cacheNode = fnNode;
const { length } = arguments;
for (let i = 0, l = length; i < l; i++) {
const arg = arguments[i];
if (typeof arg === "function" || typeof arg === "object" && arg !== null) {
let objectCache = cacheNode.o;
if (objectCache === null) {
cacheNode.o = objectCache = /* @__PURE__ */ new WeakMap();
}
const objectNode = objectCache.get(arg);
if (objectNode === void 0) {
cacheNode = createCacheNode();
objectCache.set(arg, cacheNode);
} else {
cacheNode = objectNode;
}
} else {
let primitiveCache = cacheNode.p;
if (primitiveCache === null) {
cacheNode.p = primitiveCache = /* @__PURE__ */ new Map();
}
const primitiveNode = primitiveCache.get(arg);
if (primitiveNode === void 0) {
cacheNode = createCacheNode();
primitiveCache.set(arg, cacheNode);
} else {
cacheNode = primitiveNode;
}
}
}
const terminatedNode = cacheNode;
let result;
if (cacheNode.s === TERMINATED) {
result = cacheNode.v;
} else {
result = func.apply(null, arguments);
resultsCount++;
if (resultEqualityCheck) {
const lastResultValue = (_b = (_a = lastResult == null ? void 0 : lastResult.deref) == null ? void 0 : _a.call(lastResult)) != null ? _b : lastResult;
if (lastResultValue != null && resultEqualityCheck(lastResultValue, result)) {
result = lastResultValue;
resultsCount !== 0 && resultsCount--;
}
const needsWeakRef = typeof result === "object" && result !== null || typeof result === "function";
lastResult = needsWeakRef ? new Ref(result) : result;
}
}
terminatedNode.s = TERMINATED;
terminatedNode.v = result;
return result;
}
memoized.clearCache = () => {
fnNode = createCacheNode();
memoized.resetResultsCount();
};
memoized.resultsCount = () => resultsCount;
memoized.resetResultsCount = () => {
resultsCount = 0;
};
return memoized;
}
// src/createSelectorCreator.ts
function createSelectorCreator(memoizeOrOptions, ...memoizeOptionsFromArgs) {
const createSelectorCreatorOptions = typeof memoizeOrOptions === "function" ? {
memoize: memoizeOrOptions,
memoizeOptions: memoizeOptionsFromArgs
} : memoizeOrOptions;
const createSelector2 = (...createSelectorArgs) => {
let recomputations = 0;
let dependencyRecomputations = 0;
let lastResult;
let directlyPassedOptions = {};
let resultFunc = createSelectorArgs.pop();
if (typeof resultFunc === "object") {
directlyPassedOptions = resultFunc;
resultFunc = createSelectorArgs.pop();
}
assertIsFunction(
resultFunc,
`createSelector expects an output function after the inputs, but received: [${typeof resultFunc}]`
);
const combinedOptions = __spreadValues(__spreadValues({}, createSelectorCreatorOptions), directlyPassedOptions);
const {
memoize,
memoizeOptions = [],
argsMemoize = weakMapMemoize,
argsMemoizeOptions = [],
devModeChecks = {}
} = combinedOptions;
const finalMemoizeOptions = ensureIsArray(memoizeOptions);
const finalArgsMemoizeOptions = ensureIsArray(argsMemoizeOptions);
const dependencies = getDependencies(createSelectorArgs);
const memoizedResultFunc = memoize(function recomputationWrapper() {
recomputations++;
return resultFunc.apply(
null,
arguments
);
}, ...finalMemoizeOptions);
let firstRun = true;
const selector = argsMemoize(function dependenciesChecker() {
dependencyRecomputations++;
const inputSelectorResults = collectInputSelectorResults(
dependencies,
arguments
);
lastResult = memoizedResultFunc.apply(null, inputSelectorResults);
if (process.env.NODE_ENV !== "production") {
const { identityFunctionCheck, inputStabilityCheck } = getDevModeChecksExecutionInfo(firstRun, devModeChecks);
if (identityFunctionCheck.shouldRun) {
identityFunctionCheck.run(
resultFunc,
inputSelectorResults,
lastResult
);
}
if (inputStabilityCheck.shouldRun) {
const inputSelectorResultsCopy = collectInputSelectorResults(
dependencies,
arguments
);
inputStabilityCheck.run(
{ inputSelectorResults, inputSelectorResultsCopy },
{ memoize, memoizeOptions: finalMemoizeOptions },
arguments
);
}
if (firstRun)
firstRun = false;
}
return lastResult;
}, ...finalArgsMemoizeOptions);
return Object.assign(selector, {
resultFunc,
memoizedResultFunc,
dependencies,
dependencyRecomputations: () => dependencyRecomputations,
resetDependencyRecomputations: () => {
dependencyRecomputations = 0;
},
lastResult: () => lastResult,
recomputations: () => recomputations,
resetRecomputations: () => {
recomputations = 0;
},
memoize,
argsMemoize
});
};
Object.assign(createSelector2, {
withTypes: () => createSelector2
});
return createSelector2;
}
var createSelector = /* @__PURE__ */ createSelectorCreator(weakMapMemoize);
// src/createStructuredSelector.ts
var createStructuredSelector = Object.assign(
(inputSelectorsObject, selectorCreator = createSelector) => {
assertIsObject(
inputSelectorsObject,
`createStructuredSelector expects first argument to be an object where each property is a selector, instead received a ${typeof inputSelectorsObject}`
);
const inputSelectorKeys = Object.keys(inputSelectorsObject);
const dependencies = inputSelectorKeys.map(
(key) => inputSelectorsObject[key]
);
const structuredSelector = selectorCreator(
dependencies,
(...inputSelectorResults) => {
return inputSelectorResults.reduce((composition, value, index) => {
composition[inputSelectorKeys[index]] = value;
return composition;
}, {});
}
);
return structuredSelector;
},
{ withTypes: () => createStructuredSelector }
);
export {
createSelector,
createSelectorCreator,
createStructuredSelector,
lruMemoize,
referenceEqualityCheck,
setGlobalDevModeChecks,
autotrackMemoize as unstable_autotrackMemoize,
weakMapMemoize
};
//# sourceMappingURL=reselect.legacy-esm.js.map

File diff suppressed because one or more lines are too long

743
node_modules/reselect/dist/reselect.mjs generated vendored Normal file
View file

@ -0,0 +1,743 @@
// src/devModeChecks/identityFunctionCheck.ts
var runIdentityFunctionCheck = (resultFunc, inputSelectorsResults, outputSelectorResult) => {
if (inputSelectorsResults.length === 1 && inputSelectorsResults[0] === outputSelectorResult) {
let isInputSameAsOutput = false;
try {
const emptyObject = {};
if (resultFunc(emptyObject) === emptyObject)
isInputSameAsOutput = true;
} catch {
}
if (isInputSameAsOutput) {
let stack = void 0;
try {
throw new Error();
} catch (e) {
;
({ stack } = e);
}
console.warn(
"The result function returned its own inputs without modification. e.g\n`createSelector([state => state.todos], todos => todos)`\nThis could lead to inefficient memoization and unnecessary re-renders.\nEnsure transformation logic is in the result function, and extraction logic is in the input selectors.",
{ stack }
);
}
}
};
// src/devModeChecks/inputStabilityCheck.ts
var runInputStabilityCheck = (inputSelectorResultsObject, options, inputSelectorArgs) => {
const { memoize, memoizeOptions } = options;
const { inputSelectorResults, inputSelectorResultsCopy } = inputSelectorResultsObject;
const createAnEmptyObject = memoize(() => ({}), ...memoizeOptions);
const areInputSelectorResultsEqual = createAnEmptyObject.apply(null, inputSelectorResults) === createAnEmptyObject.apply(null, inputSelectorResultsCopy);
if (!areInputSelectorResultsEqual) {
let stack = void 0;
try {
throw new Error();
} catch (e) {
;
({ stack } = e);
}
console.warn(
"An input selector returned a different result when passed same arguments.\nThis means your output selector will likely run more frequently than intended.\nAvoid returning a new reference inside your input selector, e.g.\n`createSelector([state => state.todos.map(todo => todo.id)], todoIds => todoIds.length)`",
{
arguments: inputSelectorArgs,
firstInputs: inputSelectorResults,
secondInputs: inputSelectorResultsCopy,
stack
}
);
}
};
// src/devModeChecks/setGlobalDevModeChecks.ts
var globalDevModeChecks = {
inputStabilityCheck: "once",
identityFunctionCheck: "once"
};
var setGlobalDevModeChecks = (devModeChecks) => {
Object.assign(globalDevModeChecks, devModeChecks);
};
// src/utils.ts
var NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
function assertIsFunction(func, errorMessage = `expected a function, instead received ${typeof func}`) {
if (typeof func !== "function") {
throw new TypeError(errorMessage);
}
}
function assertIsObject(object, errorMessage = `expected an object, instead received ${typeof object}`) {
if (typeof object !== "object") {
throw new TypeError(errorMessage);
}
}
function assertIsArrayOfFunctions(array, errorMessage = `expected all items to be functions, instead received the following types: `) {
if (!array.every((item) => typeof item === "function")) {
const itemTypes = array.map(
(item) => typeof item === "function" ? `function ${item.name || "unnamed"}()` : typeof item
).join(", ");
throw new TypeError(`${errorMessage}[${itemTypes}]`);
}
}
var ensureIsArray = (item) => {
return Array.isArray(item) ? item : [item];
};
function getDependencies(createSelectorArgs) {
const dependencies = Array.isArray(createSelectorArgs[0]) ? createSelectorArgs[0] : createSelectorArgs;
assertIsArrayOfFunctions(
dependencies,
`createSelector expects all input-selectors to be functions, but received the following types: `
);
return dependencies;
}
function collectInputSelectorResults(dependencies, inputSelectorArgs) {
const inputSelectorResults = [];
const { length } = dependencies;
for (let i = 0; i < length; i++) {
inputSelectorResults.push(dependencies[i].apply(null, inputSelectorArgs));
}
return inputSelectorResults;
}
var getDevModeChecksExecutionInfo = (firstRun, devModeChecks) => {
const { identityFunctionCheck, inputStabilityCheck } = {
...globalDevModeChecks,
...devModeChecks
};
return {
identityFunctionCheck: {
shouldRun: identityFunctionCheck === "always" || identityFunctionCheck === "once" && firstRun,
run: runIdentityFunctionCheck
},
inputStabilityCheck: {
shouldRun: inputStabilityCheck === "always" || inputStabilityCheck === "once" && firstRun,
run: runInputStabilityCheck
}
};
};
// src/autotrackMemoize/autotracking.ts
var $REVISION = 0;
var CURRENT_TRACKER = null;
var Cell = class {
revision = $REVISION;
_value;
_lastValue;
_isEqual = tripleEq;
constructor(initialValue, isEqual = tripleEq) {
this._value = this._lastValue = initialValue;
this._isEqual = isEqual;
}
// Whenever a storage value is read, it'll add itself to the current tracker if
// one exists, entangling its state with that cache.
get value() {
CURRENT_TRACKER?.add(this);
return this._value;
}
// Whenever a storage value is updated, we bump the global revision clock,
// assign the revision for this storage to the new value, _and_ we schedule a
// rerender. This is important, and it's what makes autotracking _pull_
// based. We don't actively tell the caches which depend on the storage that
// anything has happened. Instead, we recompute the caches when needed.
set value(newValue) {
if (this.value === newValue)
return;
this._value = newValue;
this.revision = ++$REVISION;
}
};
function tripleEq(a, b) {
return a === b;
}
var TrackingCache = class {
_cachedValue;
_cachedRevision = -1;
_deps = [];
hits = 0;
fn;
constructor(fn) {
this.fn = fn;
}
clear() {
this._cachedValue = void 0;
this._cachedRevision = -1;
this._deps = [];
this.hits = 0;
}
get value() {
if (this.revision > this._cachedRevision) {
const { fn } = this;
const currentTracker = /* @__PURE__ */ new Set();
const prevTracker = CURRENT_TRACKER;
CURRENT_TRACKER = currentTracker;
this._cachedValue = fn();
CURRENT_TRACKER = prevTracker;
this.hits++;
this._deps = Array.from(currentTracker);
this._cachedRevision = this.revision;
}
CURRENT_TRACKER?.add(this);
return this._cachedValue;
}
get revision() {
return Math.max(...this._deps.map((d) => d.revision), 0);
}
};
function getValue(cell) {
if (!(cell instanceof Cell)) {
console.warn("Not a valid cell! ", cell);
}
return cell.value;
}
function setValue(storage, value) {
if (!(storage instanceof Cell)) {
throw new TypeError(
"setValue must be passed a tracked store created with `createStorage`."
);
}
storage.value = storage._lastValue = value;
}
function createCell(initialValue, isEqual = tripleEq) {
return new Cell(initialValue, isEqual);
}
function createCache(fn) {
assertIsFunction(
fn,
"the first parameter to `createCache` must be a function"
);
return new TrackingCache(fn);
}
// src/autotrackMemoize/tracking.ts
var neverEq = (a, b) => false;
function createTag() {
return createCell(null, neverEq);
}
function dirtyTag(tag, value) {
setValue(tag, value);
}
var consumeCollection = (node) => {
let tag = node.collectionTag;
if (tag === null) {
tag = node.collectionTag = createTag();
}
getValue(tag);
};
var dirtyCollection = (node) => {
const tag = node.collectionTag;
if (tag !== null) {
dirtyTag(tag, null);
}
};
// src/autotrackMemoize/proxy.ts
var REDUX_PROXY_LABEL = Symbol();
var nextId = 0;
var proto = Object.getPrototypeOf({});
var ObjectTreeNode = class {
constructor(value) {
this.value = value;
this.value = value;
this.tag.value = value;
}
proxy = new Proxy(this, objectProxyHandler);
tag = createTag();
tags = {};
children = {};
collectionTag = null;
id = nextId++;
};
var objectProxyHandler = {
get(node, key) {
function calculateResult() {
const { value } = node;
const childValue = Reflect.get(value, key);
if (typeof key === "symbol") {
return childValue;
}
if (key in proto) {
return childValue;
}
if (typeof childValue === "object" && childValue !== null) {
let childNode = node.children[key];
if (childNode === void 0) {
childNode = node.children[key] = createNode(childValue);
}
if (childNode.tag) {
getValue(childNode.tag);
}
return childNode.proxy;
} else {
let tag = node.tags[key];
if (tag === void 0) {
tag = node.tags[key] = createTag();
tag.value = childValue;
}
getValue(tag);
return childValue;
}
}
const res = calculateResult();
return res;
},
ownKeys(node) {
consumeCollection(node);
return Reflect.ownKeys(node.value);
},
getOwnPropertyDescriptor(node, prop) {
return Reflect.getOwnPropertyDescriptor(node.value, prop);
},
has(node, prop) {
return Reflect.has(node.value, prop);
}
};
var ArrayTreeNode = class {
constructor(value) {
this.value = value;
this.value = value;
this.tag.value = value;
}
proxy = new Proxy([this], arrayProxyHandler);
tag = createTag();
tags = {};
children = {};
collectionTag = null;
id = nextId++;
};
var arrayProxyHandler = {
get([node], key) {
if (key === "length") {
consumeCollection(node);
}
return objectProxyHandler.get(node, key);
},
ownKeys([node]) {
return objectProxyHandler.ownKeys(node);
},
getOwnPropertyDescriptor([node], prop) {
return objectProxyHandler.getOwnPropertyDescriptor(node, prop);
},
has([node], prop) {
return objectProxyHandler.has(node, prop);
}
};
function createNode(value) {
if (Array.isArray(value)) {
return new ArrayTreeNode(value);
}
return new ObjectTreeNode(value);
}
function updateNode(node, newValue) {
const { value, tags, children } = node;
node.value = newValue;
if (Array.isArray(value) && Array.isArray(newValue) && value.length !== newValue.length) {
dirtyCollection(node);
} else {
if (value !== newValue) {
let oldKeysSize = 0;
let newKeysSize = 0;
let anyKeysAdded = false;
for (const _key in value) {
oldKeysSize++;
}
for (const key in newValue) {
newKeysSize++;
if (!(key in value)) {
anyKeysAdded = true;
break;
}
}
const isDifferent = anyKeysAdded || oldKeysSize !== newKeysSize;
if (isDifferent) {
dirtyCollection(node);
}
}
}
for (const key in tags) {
const childValue = value[key];
const newChildValue = newValue[key];
if (childValue !== newChildValue) {
dirtyCollection(node);
dirtyTag(tags[key], newChildValue);
}
if (typeof newChildValue === "object" && newChildValue !== null) {
delete tags[key];
}
}
for (const key in children) {
const childNode = children[key];
const newChildValue = newValue[key];
const childValue = childNode.value;
if (childValue === newChildValue) {
continue;
} else if (typeof newChildValue === "object" && newChildValue !== null) {
updateNode(childNode, newChildValue);
} else {
deleteNode(childNode);
delete children[key];
}
}
}
function deleteNode(node) {
if (node.tag) {
dirtyTag(node.tag, null);
}
dirtyCollection(node);
for (const key in node.tags) {
dirtyTag(node.tags[key], null);
}
for (const key in node.children) {
deleteNode(node.children[key]);
}
}
// src/lruMemoize.ts
function createSingletonCache(equals) {
let entry;
return {
get(key) {
if (entry && equals(entry.key, key)) {
return entry.value;
}
return NOT_FOUND;
},
put(key, value) {
entry = { key, value };
},
getEntries() {
return entry ? [entry] : [];
},
clear() {
entry = void 0;
}
};
}
function createLruCache(maxSize, equals) {
let entries = [];
function get(key) {
const cacheIndex = entries.findIndex((entry) => equals(key, entry.key));
if (cacheIndex > -1) {
const entry = entries[cacheIndex];
if (cacheIndex > 0) {
entries.splice(cacheIndex, 1);
entries.unshift(entry);
}
return entry.value;
}
return NOT_FOUND;
}
function put(key, value) {
if (get(key) === NOT_FOUND) {
entries.unshift({ key, value });
if (entries.length > maxSize) {
entries.pop();
}
}
}
function getEntries() {
return entries;
}
function clear() {
entries = [];
}
return { get, put, getEntries, clear };
}
var referenceEqualityCheck = (a, b) => a === b;
function createCacheKeyComparator(equalityCheck) {
return function areArgumentsShallowlyEqual(prev, next) {
if (prev === null || next === null || prev.length !== next.length) {
return false;
}
const { length } = prev;
for (let i = 0; i < length; i++) {
if (!equalityCheck(prev[i], next[i])) {
return false;
}
}
return true;
};
}
function lruMemoize(func, equalityCheckOrOptions) {
const providedOptions = typeof equalityCheckOrOptions === "object" ? equalityCheckOrOptions : { equalityCheck: equalityCheckOrOptions };
const {
equalityCheck = referenceEqualityCheck,
maxSize = 1,
resultEqualityCheck
} = providedOptions;
const comparator = createCacheKeyComparator(equalityCheck);
let resultsCount = 0;
const cache = maxSize <= 1 ? createSingletonCache(comparator) : createLruCache(maxSize, comparator);
function memoized() {
let value = cache.get(arguments);
if (value === NOT_FOUND) {
value = func.apply(null, arguments);
resultsCount++;
if (resultEqualityCheck) {
const entries = cache.getEntries();
const matchingEntry = entries.find(
(entry) => resultEqualityCheck(entry.value, value)
);
if (matchingEntry) {
value = matchingEntry.value;
resultsCount !== 0 && resultsCount--;
}
}
cache.put(arguments, value);
}
return value;
}
memoized.clearCache = () => {
cache.clear();
memoized.resetResultsCount();
};
memoized.resultsCount = () => resultsCount;
memoized.resetResultsCount = () => {
resultsCount = 0;
};
return memoized;
}
// src/autotrackMemoize/autotrackMemoize.ts
function autotrackMemoize(func) {
const node = createNode(
[]
);
let lastArgs = null;
const shallowEqual = createCacheKeyComparator(referenceEqualityCheck);
const cache = createCache(() => {
const res = func.apply(null, node.proxy);
return res;
});
function memoized() {
if (!shallowEqual(lastArgs, arguments)) {
updateNode(node, arguments);
lastArgs = arguments;
}
return cache.value;
}
memoized.clearCache = () => {
return cache.clear();
};
return memoized;
}
// src/weakMapMemoize.ts
var StrongRef = class {
constructor(value) {
this.value = value;
}
deref() {
return this.value;
}
};
var Ref = typeof WeakRef !== "undefined" ? WeakRef : StrongRef;
var UNTERMINATED = 0;
var TERMINATED = 1;
function createCacheNode() {
return {
s: UNTERMINATED,
v: void 0,
o: null,
p: null
};
}
function weakMapMemoize(func, options = {}) {
let fnNode = createCacheNode();
const { resultEqualityCheck } = options;
let lastResult;
let resultsCount = 0;
function memoized() {
let cacheNode = fnNode;
const { length } = arguments;
for (let i = 0, l = length; i < l; i++) {
const arg = arguments[i];
if (typeof arg === "function" || typeof arg === "object" && arg !== null) {
let objectCache = cacheNode.o;
if (objectCache === null) {
cacheNode.o = objectCache = /* @__PURE__ */ new WeakMap();
}
const objectNode = objectCache.get(arg);
if (objectNode === void 0) {
cacheNode = createCacheNode();
objectCache.set(arg, cacheNode);
} else {
cacheNode = objectNode;
}
} else {
let primitiveCache = cacheNode.p;
if (primitiveCache === null) {
cacheNode.p = primitiveCache = /* @__PURE__ */ new Map();
}
const primitiveNode = primitiveCache.get(arg);
if (primitiveNode === void 0) {
cacheNode = createCacheNode();
primitiveCache.set(arg, cacheNode);
} else {
cacheNode = primitiveNode;
}
}
}
const terminatedNode = cacheNode;
let result;
if (cacheNode.s === TERMINATED) {
result = cacheNode.v;
} else {
result = func.apply(null, arguments);
resultsCount++;
if (resultEqualityCheck) {
const lastResultValue = lastResult?.deref?.() ?? lastResult;
if (lastResultValue != null && resultEqualityCheck(lastResultValue, result)) {
result = lastResultValue;
resultsCount !== 0 && resultsCount--;
}
const needsWeakRef = typeof result === "object" && result !== null || typeof result === "function";
lastResult = needsWeakRef ? new Ref(result) : result;
}
}
terminatedNode.s = TERMINATED;
terminatedNode.v = result;
return result;
}
memoized.clearCache = () => {
fnNode = createCacheNode();
memoized.resetResultsCount();
};
memoized.resultsCount = () => resultsCount;
memoized.resetResultsCount = () => {
resultsCount = 0;
};
return memoized;
}
// src/createSelectorCreator.ts
function createSelectorCreator(memoizeOrOptions, ...memoizeOptionsFromArgs) {
const createSelectorCreatorOptions = typeof memoizeOrOptions === "function" ? {
memoize: memoizeOrOptions,
memoizeOptions: memoizeOptionsFromArgs
} : memoizeOrOptions;
const createSelector2 = (...createSelectorArgs) => {
let recomputations = 0;
let dependencyRecomputations = 0;
let lastResult;
let directlyPassedOptions = {};
let resultFunc = createSelectorArgs.pop();
if (typeof resultFunc === "object") {
directlyPassedOptions = resultFunc;
resultFunc = createSelectorArgs.pop();
}
assertIsFunction(
resultFunc,
`createSelector expects an output function after the inputs, but received: [${typeof resultFunc}]`
);
const combinedOptions = {
...createSelectorCreatorOptions,
...directlyPassedOptions
};
const {
memoize,
memoizeOptions = [],
argsMemoize = weakMapMemoize,
argsMemoizeOptions = [],
devModeChecks = {}
} = combinedOptions;
const finalMemoizeOptions = ensureIsArray(memoizeOptions);
const finalArgsMemoizeOptions = ensureIsArray(argsMemoizeOptions);
const dependencies = getDependencies(createSelectorArgs);
const memoizedResultFunc = memoize(function recomputationWrapper() {
recomputations++;
return resultFunc.apply(
null,
arguments
);
}, ...finalMemoizeOptions);
let firstRun = true;
const selector = argsMemoize(function dependenciesChecker() {
dependencyRecomputations++;
const inputSelectorResults = collectInputSelectorResults(
dependencies,
arguments
);
lastResult = memoizedResultFunc.apply(null, inputSelectorResults);
if (process.env.NODE_ENV !== "production") {
const { identityFunctionCheck, inputStabilityCheck } = getDevModeChecksExecutionInfo(firstRun, devModeChecks);
if (identityFunctionCheck.shouldRun) {
identityFunctionCheck.run(
resultFunc,
inputSelectorResults,
lastResult
);
}
if (inputStabilityCheck.shouldRun) {
const inputSelectorResultsCopy = collectInputSelectorResults(
dependencies,
arguments
);
inputStabilityCheck.run(
{ inputSelectorResults, inputSelectorResultsCopy },
{ memoize, memoizeOptions: finalMemoizeOptions },
arguments
);
}
if (firstRun)
firstRun = false;
}
return lastResult;
}, ...finalArgsMemoizeOptions);
return Object.assign(selector, {
resultFunc,
memoizedResultFunc,
dependencies,
dependencyRecomputations: () => dependencyRecomputations,
resetDependencyRecomputations: () => {
dependencyRecomputations = 0;
},
lastResult: () => lastResult,
recomputations: () => recomputations,
resetRecomputations: () => {
recomputations = 0;
},
memoize,
argsMemoize
});
};
Object.assign(createSelector2, {
withTypes: () => createSelector2
});
return createSelector2;
}
var createSelector = /* @__PURE__ */ createSelectorCreator(weakMapMemoize);
// src/createStructuredSelector.ts
var createStructuredSelector = Object.assign(
(inputSelectorsObject, selectorCreator = createSelector) => {
assertIsObject(
inputSelectorsObject,
`createStructuredSelector expects first argument to be an object where each property is a selector, instead received a ${typeof inputSelectorsObject}`
);
const inputSelectorKeys = Object.keys(inputSelectorsObject);
const dependencies = inputSelectorKeys.map(
(key) => inputSelectorsObject[key]
);
const structuredSelector = selectorCreator(
dependencies,
(...inputSelectorResults) => {
return inputSelectorResults.reduce((composition, value, index) => {
composition[inputSelectorKeys[index]] = value;
return composition;
}, {});
}
);
return structuredSelector;
},
{ withTypes: () => createStructuredSelector }
);
export {
createSelector,
createSelectorCreator,
createStructuredSelector,
lruMemoize,
referenceEqualityCheck,
setGlobalDevModeChecks,
autotrackMemoize as unstable_autotrackMemoize,
weakMapMemoize
};
//# sourceMappingURL=reselect.mjs.map

1
node_modules/reselect/dist/reselect.mjs.map generated vendored Normal file

File diff suppressed because one or more lines are too long

88
node_modules/reselect/package.json generated vendored Normal file
View file

@ -0,0 +1,88 @@
{
"name": "reselect",
"version": "5.1.1",
"description": "Selectors for Redux.",
"main": "./dist/cjs/reselect.cjs",
"module": "./dist/reselect.legacy-esm.js",
"types": "./dist/reselect.d.ts",
"exports": {
"./package.json": "./package.json",
".": {
"types": "./dist/reselect.d.ts",
"import": "./dist/reselect.mjs",
"default": "./dist/cjs/reselect.cjs"
}
},
"files": [
"src",
"dist"
],
"sideEffects": false,
"bugs": {
"url": "https://github.com/reduxjs/reselect/issues"
},
"scripts": {
"build": "tsup",
"clean": "rimraf dist",
"format": "prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"",
"lint": "eslint src test",
"prepack": "yarn build",
"bench": "vitest --run bench --mode production",
"test": "node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js --run && vitest --run --typecheck.only",
"test:watch": "node --expose-gc ./node_modules/vitest/dist/cli-wrapper.js --watch",
"test:cov": "vitest run --coverage",
"type-check": "vitest --run --typecheck.only",
"type-check:trace": "vitest --run --typecheck.only && tsc --noEmit -p typescript_test/tsconfig.json --generateTrace trace && npx @typescript/analyze-trace trace && rimraf trace",
"test:typescript": "tsc --noEmit -p typescript_test/tsconfig.json",
"docs:start": "yarn --cwd website start",
"docs:build": "yarn --cwd website build",
"docs:clear": "yarn --cwd website clear",
"docs:serve": "yarn --cwd website serve"
},
"keywords": [
"react",
"redux"
],
"authors": [
"Lee Bannard",
"Robert Binna",
"Martijn Faassen",
"Philip Spitzlinger"
],
"repository": {
"type": "git",
"url": "https://github.com/reduxjs/reselect.git"
},
"license": "MIT",
"devDependencies": {
"@reduxjs/toolkit": "^2.0.1",
"@testing-library/react": "^14.1.2",
"@types/lodash": "^4.14.175",
"@types/react": "^18.2.38",
"@types/react-dom": "^18.2.17",
"@types/shelljs": "^0.8.11",
"@typescript-eslint/eslint-plugin": "^6",
"@typescript-eslint/eslint-plugin-tslint": "^6",
"@typescript-eslint/parser": "^6",
"@typescript/analyze-trace": "^0.10.1",
"eslint": "^8.0.1",
"eslint-plugin-react": "^7.26.1",
"eslint-plugin-typescript": "0.14.0",
"jsdom": "^23.0.0",
"lodash": "^4.17.21",
"lodash.memoize": "^4.1.2",
"memoize-one": "^6.0.0",
"micro-memoize": "^4.0.9",
"netlify-plugin-cache": "^1.0.3",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^9.0.4",
"rimraf": "^3.0.2",
"shelljs": "^0.8.5",
"tsup": "^6.7.0",
"typescript": "^5.4.2",
"vitest": "^1.1.1"
},
"packageManager": "yarn@4.1.0"
}

View file

@ -0,0 +1,100 @@
import { createNode, updateNode } from './proxy'
import type { Node } from './tracking'
import { createCacheKeyComparator, referenceEqualityCheck } from '../lruMemoize'
import type { AnyFunction, DefaultMemoizeFields, Simplify } from '../types'
import { createCache } from './autotracking'
/**
* Uses an "auto-tracking" approach inspired by the work of the Ember Glimmer team.
* It uses a Proxy to wrap arguments and track accesses to nested fields
* in your selector on first read. Later, when the selector is called with
* new arguments, it identifies which accessed fields have changed and
* only recalculates the result if one or more of those accessed fields have changed.
* This allows it to be more precise than the shallow equality checks in `lruMemoize`.
*
* __Design Tradeoffs for `autotrackMemoize`:__
* - Pros:
* - It is likely to avoid excess calculations and recalculate fewer times than `lruMemoize` will,
* which may also result in fewer component re-renders.
* - Cons:
* - It only has a cache size of 1.
* - It is slower than `lruMemoize`, because it has to do more work. (How much slower is dependent on the number of accessed fields in a selector, number of calls, frequency of input changes, etc)
* - It can have some unexpected behavior. Because it tracks nested field accesses,
* cases where you don't access a field will not recalculate properly.
* For example, a badly-written selector like:
* ```ts
* createSelector([state => state.todos], todos => todos)
* ```
* that just immediately returns the extracted value will never update, because it doesn't see any field accesses to check.
*
* __Use Cases for `autotrackMemoize`:__
* - It is likely best used for cases where you need to access specific nested fields
* in data, and avoid recalculating if other fields in the same data objects are immutably updated.
*
* @param func - The function to be memoized.
* @returns A memoized function with a `.clearCache()` method attached.
*
* @example
* <caption>Using `createSelector`</caption>
* ```ts
* import { unstable_autotrackMemoize as autotrackMemoize, createSelector } from 'reselect'
*
* const selectTodoIds = createSelector(
* [(state: RootState) => state.todos],
* (todos) => todos.map(todo => todo.id),
* { memoize: autotrackMemoize }
* )
* ```
*
* @example
* <caption>Using `createSelectorCreator`</caption>
* ```ts
* import { unstable_autotrackMemoize as autotrackMemoize, createSelectorCreator } from 'reselect'
*
* const createSelectorAutotrack = createSelectorCreator({ memoize: autotrackMemoize })
*
* const selectTodoIds = createSelectorAutotrack(
* [(state: RootState) => state.todos],
* (todos) => todos.map(todo => todo.id)
* )
* ```
*
* @template Func - The type of the function that is memoized.
*
* @see {@link https://reselect.js.org/api/unstable_autotrackMemoize autotrackMemoize}
*
* @since 5.0.0
* @public
* @experimental
*/
export function autotrackMemoize<Func extends AnyFunction>(func: Func) {
// we reference arguments instead of spreading them for performance reasons
const node: Node<Record<string, unknown>> = createNode(
[] as unknown as Record<string, unknown>
)
let lastArgs: IArguments | null = null
const shallowEqual = createCacheKeyComparator(referenceEqualityCheck)
const cache = createCache(() => {
const res = func.apply(null, node.proxy as unknown as any[])
return res
})
function memoized() {
if (!shallowEqual(lastArgs, arguments)) {
updateNode(node, arguments as unknown as Record<string, unknown>)
lastArgs = arguments
}
return cache.value
}
memoized.clearCache = () => {
return cache.clear()
}
return memoized as Func & Simplify<DefaultMemoizeFields>
}

View file

@ -0,0 +1,159 @@
// Original autotracking implementation source:
// - https://gist.github.com/pzuraq/79bf862e0f8cd9521b79c4b6eccdc4f9
// Additional references:
// - https://www.pzuraq.com/blog/how-autotracking-works
// - https://v5.chriskrycho.com/journal/autotracking-elegant-dx-via-cutting-edge-cs/
import type { EqualityFn } from '../types'
import { assertIsFunction } from '../utils'
// The global revision clock. Every time state changes, the clock increments.
export let $REVISION = 0
// The current dependency tracker. Whenever we compute a cache, we create a Set
// to track any dependencies that are used while computing. If no cache is
// computing, then the tracker is null.
let CURRENT_TRACKER: Set<Cell<any> | TrackingCache> | null = null
// Storage represents a root value in the system - the actual state of our app.
export class Cell<T> {
revision = $REVISION
_value: T
_lastValue: T
_isEqual: EqualityFn = tripleEq
constructor(initialValue: T, isEqual: EqualityFn = tripleEq) {
this._value = this._lastValue = initialValue
this._isEqual = isEqual
}
// Whenever a storage value is read, it'll add itself to the current tracker if
// one exists, entangling its state with that cache.
get value() {
CURRENT_TRACKER?.add(this)
return this._value
}
// Whenever a storage value is updated, we bump the global revision clock,
// assign the revision for this storage to the new value, _and_ we schedule a
// rerender. This is important, and it's what makes autotracking _pull_
// based. We don't actively tell the caches which depend on the storage that
// anything has happened. Instead, we recompute the caches when needed.
set value(newValue) {
if (this.value === newValue) return
this._value = newValue
this.revision = ++$REVISION
}
}
function tripleEq(a: unknown, b: unknown) {
return a === b
}
// Caches represent derived state in the system. They are ultimately functions
// that are memoized based on what state they use to produce their output,
// meaning they will only rerun IFF a storage value that could affect the output
// has changed. Otherwise, they'll return the cached value.
export class TrackingCache {
_cachedValue: any
_cachedRevision = -1
_deps: any[] = []
hits = 0
fn: () => any
constructor(fn: () => any) {
this.fn = fn
}
clear() {
this._cachedValue = undefined
this._cachedRevision = -1
this._deps = []
this.hits = 0
}
get value() {
// When getting the value for a Cache, first we check all the dependencies of
// the cache to see what their current revision is. If the current revision is
// greater than the cached revision, then something has changed.
if (this.revision > this._cachedRevision) {
const { fn } = this
// We create a new dependency tracker for this cache. As the cache runs
// its function, any Storage or Cache instances which are used while
// computing will be added to this tracker. In the end, it will be the
// full list of dependencies that this Cache depends on.
const currentTracker = new Set<Cell<any>>()
const prevTracker = CURRENT_TRACKER
CURRENT_TRACKER = currentTracker
// try {
this._cachedValue = fn()
// } finally {
CURRENT_TRACKER = prevTracker
this.hits++
this._deps = Array.from(currentTracker)
// Set the cached revision. This is the current clock count of all the
// dependencies. If any dependency changes, this number will be less
// than the new revision.
this._cachedRevision = this.revision
// }
}
// If there is a current tracker, it means another Cache is computing and
// using this one, so we add this one to the tracker.
CURRENT_TRACKER?.add(this)
// Always return the cached value.
return this._cachedValue
}
get revision() {
// The current revision is the max of all the dependencies' revisions.
return Math.max(...this._deps.map(d => d.revision), 0)
}
}
export function getValue<T>(cell: Cell<T>): T {
if (!(cell instanceof Cell)) {
console.warn('Not a valid cell! ', cell)
}
return cell.value
}
type CellValue<T extends Cell<unknown>> = T extends Cell<infer U> ? U : never
export function setValue<T extends Cell<unknown>>(
storage: T,
value: CellValue<T>
): void {
if (!(storage instanceof Cell)) {
throw new TypeError(
'setValue must be passed a tracked store created with `createStorage`.'
)
}
storage.value = storage._lastValue = value
}
export function createCell<T = unknown>(
initialValue: T,
isEqual: EqualityFn = tripleEq
): Cell<T> {
return new Cell(initialValue, isEqual)
}
export function createCache<T = unknown>(fn: () => T): TrackingCache {
assertIsFunction(
fn,
'the first parameter to `createCache` must be a function'
)
return new TrackingCache(fn)
}

230
node_modules/reselect/src/autotrackMemoize/proxy.ts generated vendored Normal file
View file

@ -0,0 +1,230 @@
// Original source:
// - https://github.com/simonihmig/tracked-redux/blob/master/packages/tracked-redux/src/-private/proxy.ts
import type { Node, Tag } from './tracking'
import {
consumeCollection,
consumeTag,
createTag,
dirtyCollection,
dirtyTag
} from './tracking'
export const REDUX_PROXY_LABEL = Symbol()
let nextId = 0
const proto = Object.getPrototypeOf({})
class ObjectTreeNode<T extends Record<string, unknown>> implements Node<T> {
proxy: T = new Proxy(this, objectProxyHandler) as unknown as T
tag = createTag()
tags = {} as Record<string, Tag>
children = {} as Record<string, Node>
collectionTag = null
id = nextId++
constructor(public value: T) {
this.value = value
this.tag.value = value
}
}
const objectProxyHandler = {
get(node: Node, key: string | symbol): unknown {
function calculateResult() {
const { value } = node
const childValue = Reflect.get(value, key)
if (typeof key === 'symbol') {
return childValue
}
if (key in proto) {
return childValue
}
if (typeof childValue === 'object' && childValue !== null) {
let childNode = node.children[key]
if (childNode === undefined) {
childNode = node.children[key] = createNode(childValue)
}
if (childNode.tag) {
consumeTag(childNode.tag)
}
return childNode.proxy
} else {
let tag = node.tags[key]
if (tag === undefined) {
tag = node.tags[key] = createTag()
tag.value = childValue
}
consumeTag(tag)
return childValue
}
}
const res = calculateResult()
return res
},
ownKeys(node: Node): ArrayLike<string | symbol> {
consumeCollection(node)
return Reflect.ownKeys(node.value)
},
getOwnPropertyDescriptor(
node: Node,
prop: string | symbol
): PropertyDescriptor | undefined {
return Reflect.getOwnPropertyDescriptor(node.value, prop)
},
has(node: Node, prop: string | symbol): boolean {
return Reflect.has(node.value, prop)
}
}
class ArrayTreeNode<T extends Array<unknown>> implements Node<T> {
proxy: T = new Proxy([this], arrayProxyHandler) as unknown as T
tag = createTag()
tags = {}
children = {}
collectionTag = null
id = nextId++
constructor(public value: T) {
this.value = value
this.tag.value = value
}
}
const arrayProxyHandler = {
get([node]: [Node], key: string | symbol): unknown {
if (key === 'length') {
consumeCollection(node)
}
return objectProxyHandler.get(node, key)
},
ownKeys([node]: [Node]): ArrayLike<string | symbol> {
return objectProxyHandler.ownKeys(node)
},
getOwnPropertyDescriptor(
[node]: [Node],
prop: string | symbol
): PropertyDescriptor | undefined {
return objectProxyHandler.getOwnPropertyDescriptor(node, prop)
},
has([node]: [Node], prop: string | symbol): boolean {
return objectProxyHandler.has(node, prop)
}
}
export function createNode<T extends Array<unknown> | Record<string, unknown>>(
value: T
): Node<T> {
if (Array.isArray(value)) {
return new ArrayTreeNode(value)
}
return new ObjectTreeNode(value) as Node<T>
}
const keysMap = new WeakMap<
Array<unknown> | Record<string, unknown>,
Set<string>
>()
export function updateNode<T extends Array<unknown> | Record<string, unknown>>(
node: Node<T>,
newValue: T
): void {
const { value, tags, children } = node
node.value = newValue
if (
Array.isArray(value) &&
Array.isArray(newValue) &&
value.length !== newValue.length
) {
dirtyCollection(node)
} else {
if (value !== newValue) {
let oldKeysSize = 0
let newKeysSize = 0
let anyKeysAdded = false
for (const _key in value) {
oldKeysSize++
}
for (const key in newValue) {
newKeysSize++
if (!(key in value)) {
anyKeysAdded = true
break
}
}
const isDifferent = anyKeysAdded || oldKeysSize !== newKeysSize
if (isDifferent) {
dirtyCollection(node)
}
}
}
for (const key in tags) {
const childValue = (value as Record<string, unknown>)[key]
const newChildValue = (newValue as Record<string, unknown>)[key]
if (childValue !== newChildValue) {
dirtyCollection(node)
dirtyTag(tags[key], newChildValue)
}
if (typeof newChildValue === 'object' && newChildValue !== null) {
delete tags[key]
}
}
for (const key in children) {
const childNode = children[key]
const newChildValue = (newValue as Record<string, unknown>)[key]
const childValue = childNode.value
if (childValue === newChildValue) {
continue
} else if (typeof newChildValue === 'object' && newChildValue !== null) {
updateNode(childNode, newChildValue as Record<string, unknown>)
} else {
deleteNode(childNode)
delete children[key]
}
}
}
function deleteNode(node: Node): void {
if (node.tag) {
dirtyTag(node.tag, null)
}
dirtyCollection(node)
for (const key in node.tags) {
dirtyTag(node.tags[key], null)
}
for (const key in node.children) {
deleteNode(node.children[key])
}
}

50
node_modules/reselect/src/autotrackMemoize/tracking.ts generated vendored Normal file
View file

@ -0,0 +1,50 @@
import type { Cell } from './autotracking'
import {
getValue as consumeTag,
createCell as createStorage,
setValue
} from './autotracking'
export type Tag = Cell<unknown>
const neverEq = (a: any, b: any): boolean => false
export function createTag(): Tag {
return createStorage(null, neverEq)
}
export { consumeTag }
export function dirtyTag(tag: Tag, value: any): void {
setValue(tag, value)
}
export interface Node<
T extends Array<unknown> | Record<string, unknown> =
| Array<unknown>
| Record<string, unknown>
> {
collectionTag: Tag | null
tag: Tag | null
tags: Record<string, Tag>
children: Record<string, Node>
proxy: T
value: T
id: number
}
export const consumeCollection = (node: Node): void => {
let tag = node.collectionTag
if (tag === null) {
tag = node.collectionTag = createTag()
}
consumeTag(tag)
}
export const dirtyCollection = (node: Node): void => {
const tag = node.collectionTag
if (tag !== null) {
dirtyTag(tag, null)
}
}

9
node_modules/reselect/src/autotrackMemoize/utils.ts generated vendored Normal file
View file

@ -0,0 +1,9 @@
export function assert(
condition: any,
msg = 'Assertion failed!'
): asserts condition {
if (!condition) {
console.error(msg)
throw new Error(msg)
}
}

493
node_modules/reselect/src/createSelectorCreator.ts generated vendored Normal file
View file

@ -0,0 +1,493 @@
import { weakMapMemoize } from './weakMapMemoize'
import type {
Combiner,
CreateSelectorOptions,
DropFirstParameter,
ExtractMemoizerFields,
GetParamsFromSelectors,
GetStateFromSelectors,
InterruptRecursion,
OutputSelector,
Selector,
SelectorArray,
SetRequired,
Simplify,
UnknownMemoizer
} from './types'
import {
assertIsFunction,
collectInputSelectorResults,
ensureIsArray,
getDependencies,
getDevModeChecksExecutionInfo
} from './utils'
/**
* An instance of `createSelector`, customized with a given memoize implementation.
*
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).
* @template ArgsMemoizeFunction - The type of the optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). If none is explicitly provided, `weakMapMemoize` will be used.
* @template StateType - The type of state that the selectors created with this selector creator will operate on.
*
* @public
*/
export interface CreateSelectorFunction<
MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
StateType = any
> {
/**
* Creates a memoized selector function.
*
* @param createSelectorArgs - An arbitrary number of input selectors as separate inline arguments and a `combiner` function.
* @returns A memoized output selector.
*
* @template InputSelectors - The type of the input selectors as an array.
* @template Result - The return type of the `combiner` as well as the output selector.
* @template OverrideMemoizeFunction - The type of the optional `memoize` function that could be passed into the options object to override the original `memoize` function that was initially passed into `createSelectorCreator`.
* @template OverrideArgsMemoizeFunction - The type of the optional `argsMemoize` function that could be passed into the options object to override the original `argsMemoize` function that was initially passed into `createSelectorCreator`.
*
* @see {@link https://reselect.js.org/api/createselector `createSelector`}
*/
<InputSelectors extends SelectorArray<StateType>, Result>(
...createSelectorArgs: [
...inputSelectors: InputSelectors,
combiner: Combiner<InputSelectors, Result>
]
): OutputSelector<
InputSelectors,
Result,
MemoizeFunction,
ArgsMemoizeFunction
> &
InterruptRecursion
/**
* Creates a memoized selector function.
*
* @param createSelectorArgs - An arbitrary number of input selectors as separate inline arguments, a `combiner` function and an `options` object.
* @returns A memoized output selector.
*
* @template InputSelectors - The type of the input selectors as an array.
* @template Result - The return type of the `combiner` as well as the output selector.
* @template OverrideMemoizeFunction - The type of the optional `memoize` function that could be passed into the options object to override the original `memoize` function that was initially passed into `createSelectorCreator`.
* @template OverrideArgsMemoizeFunction - The type of the optional `argsMemoize` function that could be passed into the options object to override the original `argsMemoize` function that was initially passed into `createSelectorCreator`.
*
* @see {@link https://reselect.js.org/api/createselector `createSelector`}
*/
<
InputSelectors extends SelectorArray<StateType>,
Result,
OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction,
OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction
>(
...createSelectorArgs: [
...inputSelectors: InputSelectors,
combiner: Combiner<InputSelectors, Result>,
createSelectorOptions: Simplify<
CreateSelectorOptions<
MemoizeFunction,
ArgsMemoizeFunction,
OverrideMemoizeFunction,
OverrideArgsMemoizeFunction
>
>
]
): OutputSelector<
InputSelectors,
Result,
OverrideMemoizeFunction,
OverrideArgsMemoizeFunction
> &
InterruptRecursion
/**
* Creates a memoized selector function.
*
* @param inputSelectors - An array of input selectors.
* @param combiner - A function that Combines the input selectors and returns an output selector. Otherwise known as the result function.
* @param createSelectorOptions - An optional options object that allows for further customization per selector.
* @returns A memoized output selector.
*
* @template InputSelectors - The type of the input selectors array.
* @template Result - The return type of the `combiner` as well as the output selector.
* @template OverrideMemoizeFunction - The type of the optional `memoize` function that could be passed into the options object to override the original `memoize` function that was initially passed into `createSelectorCreator`.
* @template OverrideArgsMemoizeFunction - The type of the optional `argsMemoize` function that could be passed into the options object to override the original `argsMemoize` function that was initially passed into `createSelectorCreator`.
*
* @see {@link https://reselect.js.org/api/createselector `createSelector`}
*/
<
InputSelectors extends SelectorArray<StateType>,
Result,
OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction,
OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction
>(
inputSelectors: [...InputSelectors],
combiner: Combiner<InputSelectors, Result>,
createSelectorOptions?: Simplify<
CreateSelectorOptions<
MemoizeFunction,
ArgsMemoizeFunction,
OverrideMemoizeFunction,
OverrideArgsMemoizeFunction
>
>
): OutputSelector<
InputSelectors,
Result,
OverrideMemoizeFunction,
OverrideArgsMemoizeFunction
> &
InterruptRecursion
/**
* Creates a "pre-typed" version of {@linkcode createSelector createSelector}
* where the `state` type is predefined.
*
* This allows you to set the `state` type once, eliminating the need to
* specify it with every {@linkcode createSelector createSelector} call.
*
* @returns A pre-typed `createSelector` with the state type already defined.
*
* @example
* ```ts
* import { createSelector } from 'reselect'
*
* export interface RootState {
* todos: { id: number; completed: boolean }[]
* alerts: { id: number; read: boolean }[]
* }
*
* export const createAppSelector = createSelector.withTypes<RootState>()
*
* const selectTodoIds = createAppSelector(
* [
* // Type of `state` is set to `RootState`, no need to manually set the type
* state => state.todos
* ],
* todos => todos.map(({ id }) => id)
* )
* ```
* @template OverrideStateType - The specific type of state used by all selectors created with this selector creator.
*
* @see {@link https://reselect.js.org/api/createselector#defining-a-pre-typed-createselector `createSelector.withTypes`}
*
* @since 5.1.0
*/
withTypes: <OverrideStateType extends StateType>() => CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction,
OverrideStateType
>
}
/**
* Creates a selector creator function with the specified memoization function
* and options for customizing memoization behavior.
*
* @param options - An options object containing the `memoize` function responsible for memoizing the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). It also provides additional options for customizing memoization. While the `memoize` property is mandatory, the rest are optional.
* @returns A customized `createSelector` function.
*
* @example
* ```ts
* const customCreateSelector = createSelectorCreator({
* memoize: customMemoize, // Function to be used to memoize `resultFunc`
* memoizeOptions: [memoizeOption1, memoizeOption2], // Options passed to `customMemoize` as the second argument onwards
* argsMemoize: customArgsMemoize, // Function to be used to memoize the selector's arguments
* argsMemoizeOptions: [argsMemoizeOption1, argsMemoizeOption2] // Options passed to `customArgsMemoize` as the second argument onwards
* })
*
* const customSelector = customCreateSelector(
* [inputSelector1, inputSelector2],
* resultFunc // `resultFunc` will be passed as the first argument to `customMemoize`
* )
*
* customSelector(
* ...selectorArgs // Will be memoized by `customArgsMemoize`
* )
* ```
*
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).
* @template ArgsMemoizeFunction - The type of the optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). If none is explicitly provided, `weakMapMemoize` will be used.
*
* @see {@link https://reselect.js.org/api/createSelectorCreator#using-options-since-500 `createSelectorCreator`}
*
* @since 5.0.0
* @public
*/
export function createSelectorCreator<
MemoizeFunction extends UnknownMemoizer,
ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
>(
options: Simplify<
SetRequired<
CreateSelectorOptions<
typeof weakMapMemoize,
typeof weakMapMemoize,
MemoizeFunction,
ArgsMemoizeFunction
>,
'memoize'
>
>
): CreateSelectorFunction<MemoizeFunction, ArgsMemoizeFunction>
/**
* Creates a selector creator function with the specified memoization function
* and options for customizing memoization behavior.
*
* @param memoize - The `memoize` function responsible for memoizing the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).
* @param memoizeOptionsFromArgs - Optional configuration options for the memoization function. These options are then passed to the memoize function as the second argument onwards.
* @returns A customized `createSelector` function.
*
* @example
* ```ts
* const customCreateSelector = createSelectorCreator(customMemoize, // Function to be used to memoize `resultFunc`
* option1, // Will be passed as second argument to `customMemoize`
* option2, // Will be passed as third argument to `customMemoize`
* option3 // Will be passed as fourth argument to `customMemoize`
* )
*
* const customSelector = customCreateSelector(
* [inputSelector1, inputSelector2],
* resultFunc // `resultFunc` will be passed as the first argument to `customMemoize`
* )
* ```
*
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).
*
* @see {@link https://reselect.js.org/api/createSelectorCreator#using-memoize-and-memoizeoptions `createSelectorCreator`}
*
* @public
*/
export function createSelectorCreator<MemoizeFunction extends UnknownMemoizer>(
memoize: MemoizeFunction,
...memoizeOptionsFromArgs: DropFirstParameter<MemoizeFunction>
): CreateSelectorFunction<MemoizeFunction>
/**
* Creates a selector creator function with the specified memoization
* function and options for customizing memoization behavior.
*
* @param memoizeOrOptions - Either A `memoize` function or an `options` object containing the `memoize` function.
* @param memoizeOptionsFromArgs - Optional configuration options for the memoization function. These options are then passed to the memoize function as the second argument onwards.
* @returns A customized `createSelector` function.
*
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).
* @template ArgsMemoizeFunction - The type of the optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). If none is explicitly provided, `weakMapMemoize` will be used.
* @template MemoizeOrOptions - The type of the first argument. It can either be a `memoize` function or an `options` object containing the `memoize` function.
*/
export function createSelectorCreator<
MemoizeFunction extends UnknownMemoizer,
ArgsMemoizeFunction extends UnknownMemoizer,
MemoizeOrOptions extends
| MemoizeFunction
| SetRequired<
CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction>,
'memoize'
>
>(
memoizeOrOptions: MemoizeOrOptions,
...memoizeOptionsFromArgs: MemoizeOrOptions extends SetRequired<
CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction>,
'memoize'
>
? never
: DropFirstParameter<MemoizeFunction>
) {
/** options initially passed into `createSelectorCreator`. */
const createSelectorCreatorOptions: SetRequired<
CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction>,
'memoize'
> = typeof memoizeOrOptions === 'function'
? {
memoize: memoizeOrOptions as MemoizeFunction,
memoizeOptions: memoizeOptionsFromArgs
}
: memoizeOrOptions
const createSelector = <
InputSelectors extends SelectorArray,
Result,
OverrideMemoizeFunction extends UnknownMemoizer = MemoizeFunction,
OverrideArgsMemoizeFunction extends UnknownMemoizer = ArgsMemoizeFunction
>(
...createSelectorArgs: [
...inputSelectors: [...InputSelectors],
combiner: Combiner<InputSelectors, Result>,
createSelectorOptions?: CreateSelectorOptions<
MemoizeFunction,
ArgsMemoizeFunction,
OverrideMemoizeFunction,
OverrideArgsMemoizeFunction
>
]
) => {
let recomputations = 0
let dependencyRecomputations = 0
let lastResult: Result
// Due to the intricacies of rest params, we can't do an optional arg after `...createSelectorArgs`.
// So, start by declaring the default value here.
// (And yes, the words 'memoize' and 'options' appear too many times in this next sequence.)
let directlyPassedOptions: CreateSelectorOptions<
MemoizeFunction,
ArgsMemoizeFunction,
OverrideMemoizeFunction,
OverrideArgsMemoizeFunction
> = {}
// Normally, the result func or "combiner" is the last arg
let resultFunc = createSelectorArgs.pop() as
| Combiner<InputSelectors, Result>
| CreateSelectorOptions<
MemoizeFunction,
ArgsMemoizeFunction,
OverrideMemoizeFunction,
OverrideArgsMemoizeFunction
>
// If the result func is actually an _object_, assume it's our options object
if (typeof resultFunc === 'object') {
directlyPassedOptions = resultFunc
// and pop the real result func off
resultFunc = createSelectorArgs.pop() as Combiner<InputSelectors, Result>
}
assertIsFunction(
resultFunc,
`createSelector expects an output function after the inputs, but received: [${typeof resultFunc}]`
)
// Determine which set of options we're using. Prefer options passed directly,
// but fall back to options given to `createSelectorCreator`.
const combinedOptions = {
...createSelectorCreatorOptions,
...directlyPassedOptions
}
const {
memoize,
memoizeOptions = [],
argsMemoize = weakMapMemoize,
argsMemoizeOptions = [],
devModeChecks = {}
} = combinedOptions
// Simplifying assumption: it's unlikely that the first options arg of the provided memoizer
// is an array. In most libs I've looked at, it's an equality function or options object.
// Based on that, if `memoizeOptions` _is_ an array, we assume it's a full
// user-provided array of options. Otherwise, it must be just the _first_ arg, and so
// we wrap it in an array so we can apply it.
const finalMemoizeOptions = ensureIsArray(memoizeOptions)
const finalArgsMemoizeOptions = ensureIsArray(argsMemoizeOptions)
const dependencies = getDependencies(createSelectorArgs) as InputSelectors
const memoizedResultFunc = memoize(function recomputationWrapper() {
recomputations++
// apply arguments instead of spreading for performance.
// @ts-ignore
return (resultFunc as Combiner<InputSelectors, Result>).apply(
null,
arguments as unknown as Parameters<Combiner<InputSelectors, Result>>
)
}, ...finalMemoizeOptions) as Combiner<InputSelectors, Result> &
ExtractMemoizerFields<OverrideMemoizeFunction>
let firstRun = true
// If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
const selector = argsMemoize(function dependenciesChecker() {
dependencyRecomputations++
/** Return values of input selectors which the `resultFunc` takes as arguments. */
const inputSelectorResults = collectInputSelectorResults(
dependencies,
arguments
)
// apply arguments instead of spreading for performance.
// @ts-ignore
lastResult = memoizedResultFunc.apply(null, inputSelectorResults)
if (process.env.NODE_ENV !== 'production') {
const { identityFunctionCheck, inputStabilityCheck } =
getDevModeChecksExecutionInfo(firstRun, devModeChecks)
if (identityFunctionCheck.shouldRun) {
identityFunctionCheck.run(
resultFunc as Combiner<InputSelectors, Result>,
inputSelectorResults,
lastResult
)
}
if (inputStabilityCheck.shouldRun) {
// make a second copy of the params, to check if we got the same results
const inputSelectorResultsCopy = collectInputSelectorResults(
dependencies,
arguments
)
inputStabilityCheck.run(
{ inputSelectorResults, inputSelectorResultsCopy },
{ memoize, memoizeOptions: finalMemoizeOptions },
arguments
)
}
if (firstRun) firstRun = false
}
return lastResult
}, ...finalArgsMemoizeOptions) as unknown as Selector<
GetStateFromSelectors<InputSelectors>,
Result,
GetParamsFromSelectors<InputSelectors>
> &
ExtractMemoizerFields<OverrideArgsMemoizeFunction>
return Object.assign(selector, {
resultFunc,
memoizedResultFunc,
dependencies,
dependencyRecomputations: () => dependencyRecomputations,
resetDependencyRecomputations: () => {
dependencyRecomputations = 0
},
lastResult: () => lastResult,
recomputations: () => recomputations,
resetRecomputations: () => {
recomputations = 0
},
memoize,
argsMemoize
}) as OutputSelector<
InputSelectors,
Result,
OverrideMemoizeFunction,
OverrideArgsMemoizeFunction
>
}
Object.assign(createSelector, {
withTypes: () => createSelector
})
return createSelector as CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction
>
}
/**
* Accepts one or more "input selectors" (either as separate arguments or a single array),
* a single "result function" / "combiner", and an optional options object, and
* generates a memoized selector function.
*
* @see {@link https://reselect.js.org/api/createSelector `createSelector`}
*
* @public
*/
export const createSelector =
/* #__PURE__ */ createSelectorCreator(weakMapMemoize)

454
node_modules/reselect/src/createStructuredSelector.ts generated vendored Normal file
View file

@ -0,0 +1,454 @@
import { createSelector } from './createSelectorCreator'
import type { CreateSelectorFunction } from './createSelectorCreator'
import type {
InterruptRecursion,
ObjectValuesToTuple,
OutputSelector,
Selector,
Simplify,
UnknownMemoizer
} from './types'
import { assertIsObject } from './utils'
import type { weakMapMemoize } from './weakMapMemoize'
/**
* Represents a mapping of selectors to their return types.
*
* @template TObject - An object type where each property is a selector function.
*
* @public
*/
export type SelectorResultsMap<TObject extends SelectorsObject> = {
[Key in keyof TObject]: ReturnType<TObject[Key]>
}
/**
* Represents a mapping of selectors for each key in a given root state.
*
* This type is a utility that takes a root state object type and
* generates a corresponding set of selectors. Each selector is associated
* with a key in the root state, allowing for the selection
* of specific parts of the state.
*
* @template RootState - The type of the root state object.
*
* @since 5.0.0
* @public
*/
export type RootStateSelectors<RootState = any> = {
[Key in keyof RootState]: Selector<RootState, RootState[Key], []>
}
/**
* @deprecated Please use {@linkcode StructuredSelectorCreator.withTypes createStructuredSelector.withTypes<RootState>()} instead. This type will be removed in the future.
* @template RootState - The type of the root state object.
*
* @since 5.0.0
* @public
*/
export type TypedStructuredSelectorCreator<RootState = any> =
/**
* A convenience function that simplifies returning an object
* made up of selector results.
*
* @param inputSelectorsObject - A key value pair consisting of input selectors.
* @param selectorCreator - A custom selector creator function. It defaults to `createSelector`.
* @returns A memoized structured selector.
*
* @example
* <caption>Modern Use Case</caption>
* ```ts
* import { createSelector, createStructuredSelector } from 'reselect'
*
* interface RootState {
* todos: {
* id: number
* completed: boolean
* title: string
* description: string
* }[]
* alerts: { id: number; read: boolean }[]
* }
*
* // This:
* const structuredSelector = createStructuredSelector(
* {
* todos: (state: RootState) => state.todos,
* alerts: (state: RootState) => state.alerts,
* todoById: (state: RootState, id: number) => state.todos[id]
* },
* createSelector
* )
*
* // Is essentially the same as this:
* const selector = createSelector(
* [
* (state: RootState) => state.todos,
* (state: RootState) => state.alerts,
* (state: RootState, id: number) => state.todos[id]
* ],
* (todos, alerts, todoById) => {
* return {
* todos,
* alerts,
* todoById
* }
* }
* )
* ```
*
* @example
* <caption>In your component:</caption>
* ```tsx
* import type { RootState } from 'createStructuredSelector/modernUseCase'
* import { structuredSelector } from 'createStructuredSelector/modernUseCase'
* import type { FC } from 'react'
* import { useSelector } from 'react-redux'
*
* interface Props {
* id: number
* }
*
* const MyComponent: FC<Props> = ({ id }) => {
* const { todos, alerts, todoById } = useSelector((state: RootState) =>
* structuredSelector(state, id)
* )
*
* return (
* <div>
* Next to do is:
* <h2>{todoById.title}</h2>
* <p>Description: {todoById.description}</p>
* <ul>
* <h3>All other to dos:</h3>
* {todos.map(todo => (
* <li key={todo.id}>{todo.title}</li>
* ))}
* </ul>
* </div>
* )
* }
* ```
*
* @example
* <caption>Simple Use Case</caption>
* ```ts
* const selectA = state => state.a
* const selectB = state => state.b
*
* // The result function in the following selector
* // is simply building an object from the input selectors
* const structuredSelector = createSelector(selectA, selectB, (a, b) => ({
* a,
* b
* }))
*
* const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
* ```
*
* @template InputSelectorsObject - The shape of the input selectors object.
* @template MemoizeFunction - The type of the memoize function that is used to create the structured selector. It defaults to `weakMapMemoize`.
* @template ArgsMemoizeFunction - The type of the of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to `weakMapMemoize`.
*
* @see {@link https://reselect.js.org/api/createStructuredSelector `createStructuredSelector`}
*/
<
InputSelectorsObject extends RootStateSelectors<RootState> = RootStateSelectors<RootState>,
MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
>(
inputSelectorsObject: InputSelectorsObject,
selectorCreator?: CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction
>
) => OutputSelector<
ObjectValuesToTuple<InputSelectorsObject>,
Simplify<SelectorResultsMap<InputSelectorsObject>>,
MemoizeFunction,
ArgsMemoizeFunction
> &
InterruptRecursion
/**
* Represents an object where each property is a selector function.
*
* @template StateType - The type of state that all the selectors operate on.
*
* @public
*/
export type SelectorsObject<StateType = any> = Record<
string,
Selector<StateType>
>
/**
* It provides a way to create structured selectors.
* The structured selector can take multiple input selectors
* and map their output to an object with specific keys.
*
* @template StateType - The type of state that the structured selectors created with this structured selector creator will operate on.
*
* @see {@link https://reselect.js.org/api/createStructuredSelector `createStructuredSelector`}
*
* @public
*/
export interface StructuredSelectorCreator<StateType = any> {
/**
* A convenience function that simplifies returning an object
* made up of selector results.
*
* @param inputSelectorsObject - A key value pair consisting of input selectors.
* @param selectorCreator - A custom selector creator function. It defaults to `createSelector`.
* @returns A memoized structured selector.
*
* @example
* <caption>Modern Use Case</caption>
* ```ts
* import { createSelector, createStructuredSelector } from 'reselect'
*
* interface RootState {
* todos: {
* id: number
* completed: boolean
* title: string
* description: string
* }[]
* alerts: { id: number; read: boolean }[]
* }
*
* // This:
* const structuredSelector = createStructuredSelector(
* {
* todos: (state: RootState) => state.todos,
* alerts: (state: RootState) => state.alerts,
* todoById: (state: RootState, id: number) => state.todos[id]
* },
* createSelector
* )
*
* // Is essentially the same as this:
* const selector = createSelector(
* [
* (state: RootState) => state.todos,
* (state: RootState) => state.alerts,
* (state: RootState, id: number) => state.todos[id]
* ],
* (todos, alerts, todoById) => {
* return {
* todos,
* alerts,
* todoById
* }
* }
* )
* ```
*
* @example
* <caption>In your component:</caption>
* ```tsx
* import type { RootState } from 'createStructuredSelector/modernUseCase'
* import { structuredSelector } from 'createStructuredSelector/modernUseCase'
* import type { FC } from 'react'
* import { useSelector } from 'react-redux'
*
* interface Props {
* id: number
* }
*
* const MyComponent: FC<Props> = ({ id }) => {
* const { todos, alerts, todoById } = useSelector((state: RootState) =>
* structuredSelector(state, id)
* )
*
* return (
* <div>
* Next to do is:
* <h2>{todoById.title}</h2>
* <p>Description: {todoById.description}</p>
* <ul>
* <h3>All other to dos:</h3>
* {todos.map(todo => (
* <li key={todo.id}>{todo.title}</li>
* ))}
* </ul>
* </div>
* )
* }
* ```
*
* @example
* <caption>Simple Use Case</caption>
* ```ts
* const selectA = state => state.a
* const selectB = state => state.b
*
* // The result function in the following selector
* // is simply building an object from the input selectors
* const structuredSelector = createSelector(selectA, selectB, (a, b) => ({
* a,
* b
* }))
*
* const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
* ```
*
* @template InputSelectorsObject - The shape of the input selectors object.
* @template MemoizeFunction - The type of the memoize function that is used to create the structured selector. It defaults to `weakMapMemoize`.
* @template ArgsMemoizeFunction - The type of the of the memoize function that is used to memoize the arguments passed into the generated structured selector. It defaults to `weakMapMemoize`.
*
* @see {@link https://reselect.js.org/api/createStructuredSelector `createStructuredSelector`}
*/
<
InputSelectorsObject extends SelectorsObject<StateType>,
MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
>(
inputSelectorsObject: InputSelectorsObject,
selectorCreator?: CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction
>
): OutputSelector<
ObjectValuesToTuple<InputSelectorsObject>,
Simplify<SelectorResultsMap<InputSelectorsObject>>,
MemoizeFunction,
ArgsMemoizeFunction
> &
InterruptRecursion
/**
* Creates a "pre-typed" version of
* {@linkcode createStructuredSelector createStructuredSelector}
* where the `state` type is predefined.
*
* This allows you to set the `state` type once, eliminating the need to
* specify it with every
* {@linkcode createStructuredSelector createStructuredSelector} call.
*
* @returns A pre-typed `createStructuredSelector` with the state type already defined.
*
* @example
* ```ts
* import { createStructuredSelector } from 'reselect'
*
* export interface RootState {
* todos: { id: number; completed: boolean }[]
* alerts: { id: number; read: boolean }[]
* }
*
* export const createStructuredAppSelector =
* createStructuredSelector.withTypes<RootState>()
*
* const structuredAppSelector = createStructuredAppSelector({
* // Type of `state` is set to `RootState`, no need to manually set the type
* todos: state => state.todos,
* alerts: state => state.alerts,
* todoById: (state, id: number) => state.todos[id]
* })
*
* ```
* @template OverrideStateType - The specific type of state used by all structured selectors created with this structured selector creator.
*
* @see {@link https://reselect.js.org/api/createstructuredselector#defining-a-pre-typed-createstructuredselector `createSelector.withTypes`}
*
* @since 5.1.0
*/
withTypes: <
OverrideStateType extends StateType
>() => StructuredSelectorCreator<OverrideStateType>
}
/**
* A convenience function that simplifies returning an object
* made up of selector results.
*
* @param inputSelectorsObject - A key value pair consisting of input selectors.
* @param selectorCreator - A custom selector creator function. It defaults to `createSelector`.
* @returns A memoized structured selector.
*
* @example
* <caption>Modern Use Case</caption>
* ```ts
* import { createSelector, createStructuredSelector } from 'reselect'
*
* interface RootState {
* todos: {
* id: number
* completed: boolean
* title: string
* description: string
* }[]
* alerts: { id: number; read: boolean }[]
* }
*
* // This:
* const structuredSelector = createStructuredSelector(
* {
* todos: (state: RootState) => state.todos,
* alerts: (state: RootState) => state.alerts,
* todoById: (state: RootState, id: number) => state.todos[id]
* },
* createSelector
* )
*
* // Is essentially the same as this:
* const selector = createSelector(
* [
* (state: RootState) => state.todos,
* (state: RootState) => state.alerts,
* (state: RootState, id: number) => state.todos[id]
* ],
* (todos, alerts, todoById) => {
* return {
* todos,
* alerts,
* todoById
* }
* }
* )
* ```
*
* @see {@link https://reselect.js.org/api/createStructuredSelector `createStructuredSelector`}
*
* @public
*/
export const createStructuredSelector: StructuredSelectorCreator =
Object.assign(
<
InputSelectorsObject extends SelectorsObject,
MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
>(
inputSelectorsObject: InputSelectorsObject,
selectorCreator: CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction
> = createSelector as CreateSelectorFunction<
MemoizeFunction,
ArgsMemoizeFunction
>
) => {
assertIsObject(
inputSelectorsObject,
'createStructuredSelector expects first argument to be an object ' +
`where each property is a selector, instead received a ${typeof inputSelectorsObject}`
)
const inputSelectorKeys = Object.keys(inputSelectorsObject)
const dependencies = inputSelectorKeys.map(
key => inputSelectorsObject[key]
)
const structuredSelector = selectorCreator(
dependencies,
(...inputSelectorResults: any[]) => {
return inputSelectorResults.reduce((composition, value, index) => {
composition[inputSelectorKeys[index]] = value
return composition
}, {})
}
)
return structuredSelector
},
{ withTypes: () => createStructuredSelector }
) as StructuredSelectorCreator

View file

@ -0,0 +1,53 @@
import type { AnyFunction } from '../types'
/**
* Runs a check to determine if the given result function behaves as an
* identity function. An identity function is one that returns its
* input unchanged, for example, `x => x`. This check helps ensure
* efficient memoization and prevent unnecessary re-renders by encouraging
* proper use of transformation logic in result functions and
* extraction logic in input selectors.
*
* @param resultFunc - The result function to be checked.
* @param inputSelectorsResults - The results of the input selectors.
* @param outputSelectorResult - The result of the output selector.
*
* @see {@link https://reselect.js.org/api/development-only-stability-checks#identityfunctioncheck `identityFunctionCheck`}
*
* @since 5.0.0
* @internal
*/
export const runIdentityFunctionCheck = (
resultFunc: AnyFunction,
inputSelectorsResults: unknown[],
outputSelectorResult: unknown
) => {
if (
inputSelectorsResults.length === 1 &&
inputSelectorsResults[0] === outputSelectorResult
) {
let isInputSameAsOutput = false
try {
const emptyObject = {}
if (resultFunc(emptyObject) === emptyObject) isInputSameAsOutput = true
} catch {
// Do nothing
}
if (isInputSameAsOutput) {
let stack: string | undefined = undefined
try {
throw new Error()
} catch (e) {
// eslint-disable-next-line @typescript-eslint/no-extra-semi, no-extra-semi
;({ stack } = e as Error)
}
console.warn(
'The result function returned its own inputs without modification. e.g' +
'\n`createSelector([state => state.todos], todos => todos)`' +
'\nThis could lead to inefficient memoization and unnecessary re-renders.' +
'\nEnsure transformation logic is in the result function, and extraction logic is in the input selectors.',
{ stack }
)
}
}
}

View file

@ -0,0 +1,59 @@
import type { CreateSelectorOptions, UnknownMemoizer } from '../types'
/**
* Runs a stability check to ensure the input selector results remain stable
* when provided with the same arguments. This function is designed to detect
* changes in the output of input selectors, which can impact the performance of memoized selectors.
*
* @param inputSelectorResultsObject - An object containing two arrays: `inputSelectorResults` and `inputSelectorResultsCopy`, representing the results of input selectors.
* @param options - Options object consisting of a `memoize` function and a `memoizeOptions` object.
* @param inputSelectorArgs - List of arguments being passed to the input selectors.
*
* @see {@link https://reselect.js.org/api/development-only-stability-checks/#inputstabilitycheck `inputStabilityCheck`}
*
* @since 5.0.0
* @internal
*/
export const runInputStabilityCheck = (
inputSelectorResultsObject: {
inputSelectorResults: unknown[]
inputSelectorResultsCopy: unknown[]
},
options: Required<
Pick<
CreateSelectorOptions<UnknownMemoizer, UnknownMemoizer>,
'memoize' | 'memoizeOptions'
>
>,
inputSelectorArgs: unknown[] | IArguments
) => {
const { memoize, memoizeOptions } = options
const { inputSelectorResults, inputSelectorResultsCopy } =
inputSelectorResultsObject
const createAnEmptyObject = memoize(() => ({}), ...memoizeOptions)
// if the memoize method thinks the parameters are equal, these *should* be the same reference
const areInputSelectorResultsEqual =
createAnEmptyObject.apply(null, inputSelectorResults) ===
createAnEmptyObject.apply(null, inputSelectorResultsCopy)
if (!areInputSelectorResultsEqual) {
let stack: string | undefined = undefined
try {
throw new Error()
} catch (e) {
// eslint-disable-next-line @typescript-eslint/no-extra-semi, no-extra-semi
;({ stack } = e as Error)
}
console.warn(
'An input selector returned a different result when passed same arguments.' +
'\nThis means your output selector will likely run more frequently than intended.' +
'\nAvoid returning a new reference inside your input selector, e.g.' +
'\n`createSelector([state => state.todos.map(todo => todo.id)], todoIds => todoIds.length)`',
{
arguments: inputSelectorArgs,
firstInputs: inputSelectorResults,
secondInputs: inputSelectorResultsCopy,
stack
}
)
}
}

View file

@ -0,0 +1,63 @@
import type { DevModeChecks } from '../types'
/**
* Global configuration for development mode checks. This specifies the default
* frequency at which each development mode check should be performed.
*
* @since 5.0.0
* @internal
*/
export const globalDevModeChecks: DevModeChecks = {
inputStabilityCheck: 'once',
identityFunctionCheck: 'once'
}
/**
* Overrides the development mode checks settings for all selectors.
*
* Reselect performs additional checks in development mode to help identify and
* warn about potential issues in selector behavior. This function allows you to
* customize the behavior of these checks across all selectors in your application.
*
* **Note**: This setting can still be overridden per selector inside `createSelector`'s `options` object.
* See {@link https://github.com/reduxjs/reselect#2-per-selector-by-passing-an-identityfunctioncheck-option-directly-to-createselector per-selector-configuration}
* and {@linkcode CreateSelectorOptions.identityFunctionCheck identityFunctionCheck} for more details.
*
* _The development mode checks do not run in production builds._
*
* @param devModeChecks - An object specifying the desired settings for development mode checks. You can provide partial overrides. Unspecified settings will retain their current values.
*
* @example
* ```ts
* import { setGlobalDevModeChecks } from 'reselect'
* import { DevModeChecks } from '../types'
*
* // Run only the first time the selector is called. (default)
* setGlobalDevModeChecks({ inputStabilityCheck: 'once' })
*
* // Run every time the selector is called.
* setGlobalDevModeChecks({ inputStabilityCheck: 'always' })
*
* // Never run the input stability check.
* setGlobalDevModeChecks({ inputStabilityCheck: 'never' })
*
* // Run only the first time the selector is called. (default)
* setGlobalDevModeChecks({ identityFunctionCheck: 'once' })
*
* // Run every time the selector is called.
* setGlobalDevModeChecks({ identityFunctionCheck: 'always' })
*
* // Never run the identity function check.
* setGlobalDevModeChecks({ identityFunctionCheck: 'never' })
* ```
* @see {@link https://reselect.js.org/api/development-only-stability-checks Development-Only Stability Checks}
* @see {@link https://reselect.js.org/api/development-only-stability-checks#1-globally-through-setglobaldevmodechecks global-configuration}
*
* @since 5.0.0
* @public
*/
export const setGlobalDevModeChecks = (
devModeChecks: Partial<DevModeChecks>
) => {
Object.assign(globalDevModeChecks, devModeChecks)
}

36
node_modules/reselect/src/index.ts generated vendored Normal file
View file

@ -0,0 +1,36 @@
export { autotrackMemoize as unstable_autotrackMemoize } from './autotrackMemoize/autotrackMemoize'
export { createSelector, createSelectorCreator } from './createSelectorCreator'
export type { CreateSelectorFunction } from './createSelectorCreator'
export { createStructuredSelector } from './createStructuredSelector'
export type {
RootStateSelectors,
SelectorResultsMap,
SelectorsObject,
StructuredSelectorCreator,
TypedStructuredSelectorCreator
} from './createStructuredSelector'
export { setGlobalDevModeChecks } from './devModeChecks/setGlobalDevModeChecks'
export { lruMemoize, referenceEqualityCheck } from './lruMemoize'
export type { LruMemoizeOptions } from './lruMemoize'
export type {
Combiner,
CreateSelectorOptions,
DefaultMemoizeFields,
DevModeCheckFrequency,
DevModeChecks,
DevModeChecksExecutionInfo,
EqualityFn,
ExtractMemoizerFields,
GetParamsFromSelectors,
GetStateFromSelectors,
MemoizeOptionsFromParameters,
OutputSelector,
OutputSelectorFields,
OverrideMemoizeOptions,
Selector,
SelectorArray,
SelectorResultArray,
UnknownMemoizer
} from './types'
export { weakMapMemoize } from './weakMapMemoize'
export type { WeakMapMemoizeOptions } from './weakMapMemoize'

249
node_modules/reselect/src/lruMemoize.ts generated vendored Normal file
View file

@ -0,0 +1,249 @@
import type {
AnyFunction,
DefaultMemoizeFields,
EqualityFn,
Simplify
} from './types'
import type { NOT_FOUND_TYPE } from './utils'
import { NOT_FOUND } from './utils'
// Cache implementation based on Erik Rasmussen's `lru-memoize`:
// https://github.com/erikras/lru-memoize
interface Entry {
key: unknown
value: unknown
}
interface Cache {
get(key: unknown): unknown | NOT_FOUND_TYPE
put(key: unknown, value: unknown): void
getEntries(): Entry[]
clear(): void
}
function createSingletonCache(equals: EqualityFn): Cache {
let entry: Entry | undefined
return {
get(key: unknown) {
if (entry && equals(entry.key, key)) {
return entry.value
}
return NOT_FOUND
},
put(key: unknown, value: unknown) {
entry = { key, value }
},
getEntries() {
return entry ? [entry] : []
},
clear() {
entry = undefined
}
}
}
function createLruCache(maxSize: number, equals: EqualityFn): Cache {
let entries: Entry[] = []
function get(key: unknown) {
const cacheIndex = entries.findIndex(entry => equals(key, entry.key))
// We found a cached entry
if (cacheIndex > -1) {
const entry = entries[cacheIndex]
// Cached entry not at top of cache, move it to the top
if (cacheIndex > 0) {
entries.splice(cacheIndex, 1)
entries.unshift(entry)
}
return entry.value
}
// No entry found in cache, return sentinel
return NOT_FOUND
}
function put(key: unknown, value: unknown) {
if (get(key) === NOT_FOUND) {
// TODO Is unshift slow?
entries.unshift({ key, value })
if (entries.length > maxSize) {
entries.pop()
}
}
}
function getEntries() {
return entries
}
function clear() {
entries = []
}
return { get, put, getEntries, clear }
}
/**
* Runs a simple reference equality check.
* What {@linkcode lruMemoize lruMemoize} uses by default.
*
* **Note**: This function was previously known as `defaultEqualityCheck`.
*
* @public
*/
export const referenceEqualityCheck: EqualityFn = (a, b) => a === b
export function createCacheKeyComparator(equalityCheck: EqualityFn) {
return function areArgumentsShallowlyEqual(
prev: unknown[] | IArguments | null,
next: unknown[] | IArguments | null
): boolean {
if (prev === null || next === null || prev.length !== next.length) {
return false
}
// Do this in a for loop (and not a `forEach` or an `every`) so we can determine equality as fast as possible.
const { length } = prev
for (let i = 0; i < length; i++) {
if (!equalityCheck(prev[i], next[i])) {
return false
}
}
return true
}
}
/**
* Options for configuring the behavior of a function memoized with
* LRU (Least Recently Used) caching.
*
* @template Result - The type of the return value of the memoized function.
*
* @public
*/
export interface LruMemoizeOptions<Result = any> {
/**
* Function used to compare the individual arguments of the
* provided calculation function.
*
* @default referenceEqualityCheck
*/
equalityCheck?: EqualityFn
/**
* If provided, used to compare a newly generated output value against
* previous values in the cache. If a match is found,
* the old value is returned. This addresses the common
* ```ts
* todos.map(todo => todo.id)
* ```
* use case, where an update to another field in the original data causes
* a recalculation due to changed references, but the output is still
* effectively the same.
*
* @since 4.1.0
*/
resultEqualityCheck?: EqualityFn<Result>
/**
* The maximum size of the cache used by the selector.
* A size greater than 1 means the selector will use an
* LRU (Least Recently Used) cache, allowing for the caching of multiple
* results based on different sets of arguments.
*
* @default 1
*/
maxSize?: number
}
/**
* Creates a memoized version of a function with an optional
* LRU (Least Recently Used) cache. The memoized function uses a cache to
* store computed values. Depending on the `maxSize` option, it will use
* either a singleton cache (for a single entry) or an
* LRU cache (for multiple entries).
*
* **Note**: This function was previously known as `defaultMemoize`.
*
* @param func - The function to be memoized.
* @param equalityCheckOrOptions - Either an equality check function or an options object.
* @returns A memoized function with a `.clearCache()` method attached.
*
* @template Func - The type of the function that is memoized.
*
* @see {@link https://reselect.js.org/api/lruMemoize `lruMemoize`}
*
* @public
*/
export function lruMemoize<Func extends AnyFunction>(
func: Func,
equalityCheckOrOptions?: EqualityFn | LruMemoizeOptions<ReturnType<Func>>
) {
const providedOptions =
typeof equalityCheckOrOptions === 'object'
? equalityCheckOrOptions
: { equalityCheck: equalityCheckOrOptions }
const {
equalityCheck = referenceEqualityCheck,
maxSize = 1,
resultEqualityCheck
} = providedOptions
const comparator = createCacheKeyComparator(equalityCheck)
let resultsCount = 0
const cache =
maxSize <= 1
? createSingletonCache(comparator)
: createLruCache(maxSize, comparator)
function memoized() {
let value = cache.get(arguments) as ReturnType<Func>
if (value === NOT_FOUND) {
// apply arguments instead of spreading for performance.
// @ts-ignore
value = func.apply(null, arguments) as ReturnType<Func>
resultsCount++
if (resultEqualityCheck) {
const entries = cache.getEntries()
const matchingEntry = entries.find(entry =>
resultEqualityCheck(entry.value as ReturnType<Func>, value)
)
if (matchingEntry) {
value = matchingEntry.value as ReturnType<Func>
resultsCount !== 0 && resultsCount--
}
}
cache.put(arguments, value)
}
return value
}
memoized.clearCache = () => {
cache.clear()
memoized.resetResultsCount()
}
memoized.resultsCount = () => resultsCount
memoized.resetResultsCount = () => {
resultsCount = 0
}
return memoized as Func & Simplify<DefaultMemoizeFields>
}

876
node_modules/reselect/src/types.ts generated vendored Normal file
View file

@ -0,0 +1,876 @@
import type { MergeParameters } from './versionedTypes'
import type { weakMapMemoize } from './weakMapMemoize'
export type { MergeParameters } from './versionedTypes'
/*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
* Reselect Data Types
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*/
/**
* A standard selector function.
* @template State - The first value, often a Redux root state object.
* @template Result - The final result returned by the selector.
* @template Params - All additional arguments passed into the selector.
*
* @public
*/
export type Selector<
State = any,
Result = unknown,
Params extends readonly any[] = any[]
> = Distribute<
/**
* A function that takes a state and returns data that is based on that state.
*
* @param state - The first argument, often a Redux root state object.
* @param params - All additional arguments passed into the selector.
* @returns A derived value from the state.
*/
(state: State, ...params: FallbackIfNever<Params, []>) => Result
>
/**
* An array of input selectors.
*
* @public
*/
export type SelectorArray<State = any> = readonly Selector<State>[]
/**
* Extracts an array of all return types from all input selectors.
*
* @public
*/
export type SelectorResultArray<Selectors extends SelectorArray> =
ExtractReturnType<Selectors>
/**
* The options object used inside `createSelector` and `createSelectorCreator`.
*
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).
* @template ArgsMemoizeFunction - The type of the optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). If none is explicitly provided, `weakMapMemoize` will be used.
* @template OverrideMemoizeFunction - The type of the optional `memoize` function that could be passed into the options object inside `createSelector` to override the original `memoize` function that was initially passed into `createSelectorCreator`.
* @template OverrideArgsMemoizeFunction - The type of the optional `argsMemoize` function that could be passed into the options object inside `createSelector` to override the original `argsMemoize` function that was initially passed into `createSelectorCreator`. If none was initially provided, `weakMapMemoize` will be used.
*
* @public
*/
export interface CreateSelectorOptions<
MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
OverrideMemoizeFunction extends UnknownMemoizer = never,
OverrideArgsMemoizeFunction extends UnknownMemoizer = never
> {
/**
* Reselect performs additional checks in development mode to help identify
* and warn about potential issues in selector behavior. This option
* allows you to customize the behavior of these checks per selector.
*
* @see {@link https://reselect.js.org/api/development-only-stability-checks Development-Only Stability Checks}
*
* @since 5.0.0
*/
devModeChecks?: Partial<DevModeChecks>
/**
* The memoize function that is used to memoize the {@linkcode OutputSelectorFields.resultFunc resultFunc}
* inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the `memoize` function initially passed into `createSelectorCreator`.
*
* @example
* ```ts
* import { createSelector, weakMapMemoize } from 'reselect'
*
* const selectItemsByCategory = createSelector(
* [
* (state: RootState) => state.items,
* (state: RootState, category: string) => category
* ],
* (items, category) => items.filter(item => item.category === category),
* { memoize: weakMapMemoize }
* )
* ```
*
* @since 5.0.0
*/
memoize?: FallbackIfNever<OverrideMemoizeFunction, MemoizeFunction>
/**
* The optional memoize function that is used to memoize the arguments
* passed into the output selector generated by `createSelector`
* (e.g., `lruMemoize` or `weakMapMemoize`).
*
* When passed directly into `createSelector`, it overrides the
* `argsMemoize` function initially passed into `createSelectorCreator`.
* If none was initially provided, `weakMapMemoize` will be used.
*
* @example
* ```ts
* import { createSelector, weakMapMemoize } from 'reselect'
*
* const selectItemsByCategory = createSelector(
* [
* (state: RootState) => state.items,
* (state: RootState, category: string) => category
* ],
* (items, category) => items.filter(item => item.category === category),
* { argsMemoize: weakMapMemoize }
* )
* ```
*
* @default weakMapMemoize
*
* @since 5.0.0
*/
argsMemoize?: FallbackIfNever<
OverrideArgsMemoizeFunction,
ArgsMemoizeFunction
>
/**
* Optional configuration options for the {@linkcode CreateSelectorOptions.memoize memoize} function.
* These options are passed to the {@linkcode CreateSelectorOptions.memoize memoize} function as the second argument.
*
* @since 5.0.0
*/
memoizeOptions?: OverrideMemoizeOptions<
MemoizeFunction,
OverrideMemoizeFunction
>
/**
* Optional configuration options for the {@linkcode CreateSelectorOptions.argsMemoize argsMemoize} function.
* These options are passed to the {@linkcode CreateSelectorOptions.argsMemoize argsMemoize} function as the second argument.
*
* @since 5.0.0
*/
argsMemoizeOptions?: OverrideMemoizeOptions<
ArgsMemoizeFunction,
OverrideArgsMemoizeFunction
>
}
/**
* The additional fields attached to the output selector generated by `createSelector`.
*
* **Note**: Although {@linkcode CreateSelectorOptions.memoize memoize}
* and {@linkcode CreateSelectorOptions.argsMemoize argsMemoize} are included in the attached fields,
* the fields themselves are independent of the type of
* {@linkcode CreateSelectorOptions.memoize memoize} and {@linkcode CreateSelectorOptions.argsMemoize argsMemoize} functions.
* Meaning this type is not going to generate additional fields based on what functions we use to memoize our selectors.
*
* _This type is not to be confused with {@linkcode ExtractMemoizerFields ExtractMemoizerFields}._
*
* @template InputSelectors - The type of the input selectors.
* @template Result - The type of the result returned by the `resultFunc`.
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).
* @template ArgsMemoizeFunction - The type of the optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). If none is explicitly provided, `weakMapMemoize` will be used.
*
* @public
*/
export type OutputSelectorFields<
InputSelectors extends SelectorArray = SelectorArray,
Result = unknown,
MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
> = {
/**
* The final function passed to `createSelector`. Otherwise known as the `combiner`.
*/
resultFunc: Combiner<InputSelectors, Result>
/**
* The memoized version of {@linkcode OutputSelectorFields.resultFunc resultFunc}.
*/
memoizedResultFunc: Combiner<InputSelectors, Result> &
ExtractMemoizerFields<MemoizeFunction>
/**
* @Returns The last result calculated by {@linkcode OutputSelectorFields.memoizedResultFunc memoizedResultFunc}.
*/
lastResult: () => Result
/**
* The array of the input selectors used by `createSelector` to compose the
* combiner ({@linkcode OutputSelectorFields.memoizedResultFunc memoizedResultFunc}).
*/
dependencies: InputSelectors
/**
* Counts the number of times {@linkcode OutputSelectorFields.memoizedResultFunc memoizedResultFunc} has been recalculated.
*/
recomputations: () => number
/**
* Resets the count of {@linkcode OutputSelectorFields.recomputations recomputations} count to 0.
*/
resetRecomputations: () => void
/**
* Counts the number of times the input selectors ({@linkcode OutputSelectorFields.dependencies dependencies})
* have been recalculated. This is distinct from {@linkcode OutputSelectorFields.recomputations recomputations},
* which tracks the recalculations of the result function.
*
* @since 5.0.0
*/
dependencyRecomputations: () => number
/**
* Resets the count {@linkcode OutputSelectorFields.dependencyRecomputations dependencyRecomputations}
* for the input selectors ({@linkcode OutputSelectorFields.dependencies dependencies})
* of a memoized selector.
*
* @since 5.0.0
*/
resetDependencyRecomputations: () => void
} & Simplify<
Required<
Pick<
CreateSelectorOptions<MemoizeFunction, ArgsMemoizeFunction>,
'argsMemoize' | 'memoize'
>
>
>
/**
* Represents the actual selectors generated by `createSelector`.
*
* @template InputSelectors - The type of the input selectors.
* @template Result - The type of the result returned by the `resultFunc`.
* @template MemoizeFunction - The type of the memoize function that is used to memoize the `resultFunc` inside `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`).
* @template ArgsMemoizeFunction - The type of the optional memoize function that is used to memoize the arguments passed into the output selector generated by `createSelector` (e.g., `lruMemoize` or `weakMapMemoize`). If none is explicitly provided, `weakMapMemoize` will be used.
*
* @public
*/
export type OutputSelector<
InputSelectors extends SelectorArray = SelectorArray,
Result = unknown,
MemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize,
ArgsMemoizeFunction extends UnknownMemoizer = typeof weakMapMemoize
> = Selector<
GetStateFromSelectors<InputSelectors>,
Result,
GetParamsFromSelectors<InputSelectors>
> &
ExtractMemoizerFields<ArgsMemoizeFunction> &
OutputSelectorFields<
InputSelectors,
Result,
MemoizeFunction,
ArgsMemoizeFunction
>
/**
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
*
* @template InputSelectors - An array of input selectors.
* @template Result - Result returned by `resultFunc`.
*
* @public
*/
export type Combiner<InputSelectors extends SelectorArray, Result> = Distribute<
/**
* A function that takes input selectors' return values as arguments and returns a result. Otherwise known as `resultFunc`.
*
* @param resultFuncArgs - Return values of input selectors.
* @returns The return value of {@linkcode OutputSelectorFields.resultFunc resultFunc}.
*/
(...resultFuncArgs: SelectorResultArray<InputSelectors>) => Result
>
/**
* A standard function returning true if two values are considered equal.
*
* @public
*/
export type EqualityFn<T = any> = (a: T, b: T) => boolean
/**
* The frequency of development mode checks.
*
* @since 5.0.0
* @public
*/
export type DevModeCheckFrequency = 'always' | 'once' | 'never'
/**
* Represents the configuration for development mode checks.
*
* @since 5.0.0
* @public
*/
export interface DevModeChecks {
/**
* Overrides the global input stability check for the selector.
* - `once` - Run only the first time the selector is called.
* - `always` - Run every time the selector is called.
* - `never` - Never run the input stability check.
*
* @default 'once'
*
* @see {@link https://reselect.js.org/api/development-only-stability-checks Development-Only Stability Checks}
* @see {@link https://reselect.js.org/api/development-only-stability-checks#inputstabilitycheck `inputStabilityCheck`}
* @see {@link https://reselect.js.org/api/development-only-stability-checks#2-per-selector-by-passing-an-inputstabilitycheck-option-directly-to- per-selector-configuration}
*
* @since 5.0.0
*/
inputStabilityCheck: DevModeCheckFrequency
/**
* Overrides the global identity function check for the selector.
* - `once` - Run only the first time the selector is called.
* - `always` - Run every time the selector is called.
* - `never` - Never run the identity function check.
*
* @default 'once'
*
* @see {@link https://reselect.js.org/api/development-only-stability-checks Development-Only Stability Checks}
* @see {@link https://reselect.js.org/api/development-only-stability-checks#identityfunctioncheck `identityFunctionCheck`}
* @see {@link https://reselect.js.org/api/development-only-stability-checks#2-per-selector-by-passing-an-identityfunctioncheck-option-directly-to- per-selector-configuration}
*
* @since 5.0.0
*/
identityFunctionCheck: DevModeCheckFrequency
}
/**
* Represents execution information for development mode checks.
*
* @public
* @since 5.0.0
*/
export type DevModeChecksExecutionInfo = {
[K in keyof DevModeChecks]: {
/**
* A boolean indicating whether the check should be executed.
*/
shouldRun: boolean
/**
* The function to execute for the check.
*/
run: AnyFunction
}
}
/**
* Determines the combined single "State" type (first arg) from all input selectors.
*
* @public
*/
export type GetStateFromSelectors<Selectors extends SelectorArray> =
MergeParameters<Selectors>[0]
/**
* Determines the combined "Params" type (all remaining args) from all input selectors.
*
* @public
*/
export type GetParamsFromSelectors<Selectors extends SelectorArray> = ArrayTail<
MergeParameters<Selectors>
>
/**
* Any Memoizer function. A memoizer is a function that accepts another function and returns it.
*
* @template FunctionType - The type of the function that is memoized.
*
* @public
*/
export type UnknownMemoizer<
FunctionType extends UnknownFunction = UnknownFunction
> = (func: FunctionType, ...options: any[]) => FunctionType
/**
* Extracts the options type for a memoization function based on its parameters.
* The first parameter of the function is expected to be the function to be memoized,
* followed by options for the memoization process.
*
* @template MemoizeFunction - The type of the memoize function to be checked.
*
* @public
*/
export type MemoizeOptionsFromParameters<
MemoizeFunction extends UnknownMemoizer
> =
| (
| NonFunctionType<DropFirstParameter<MemoizeFunction>[0]>
| FunctionType<DropFirstParameter<MemoizeFunction>[0]>
)
| (
| NonFunctionType<DropFirstParameter<MemoizeFunction>[number]>
| FunctionType<DropFirstParameter<MemoizeFunction>[number]>
)[]
/**
* Derive the type of memoize options object based on whether the memoize function itself was overridden.
*
* _This type can be used for both `memoizeOptions` and `argsMemoizeOptions`._
*
* @template MemoizeFunction - The type of the `memoize` or `argsMemoize` function initially passed into `createSelectorCreator`.
* @template OverrideMemoizeFunction - The type of the optional `memoize` or `argsMemoize` function passed directly into `createSelector` which then overrides the original `memoize` or `argsMemoize` function passed into `createSelectorCreator`.
*
* @public
*/
export type OverrideMemoizeOptions<
MemoizeFunction extends UnknownMemoizer,
OverrideMemoizeFunction extends UnknownMemoizer = never
> = IfNever<
OverrideMemoizeFunction,
Simplify<MemoizeOptionsFromParameters<MemoizeFunction>>,
Simplify<MemoizeOptionsFromParameters<OverrideMemoizeFunction>>
>
/**
* Extracts the additional properties or methods that a memoize function attaches to
* the function it memoizes (e.g., `clearCache`).
*
* @template MemoizeFunction - The type of the memoize function to be checked.
*
* @public
*/
export type ExtractMemoizerFields<MemoizeFunction extends UnknownMemoizer> =
Simplify<OmitIndexSignature<ReturnType<MemoizeFunction>>>
/**
* Represents the additional properties attached to a function memoized by `reselect`.
*
* `lruMemoize`, `weakMapMemoize` and `autotrackMemoize` all return these properties.
*
* @see {@linkcode ExtractMemoizerFields ExtractMemoizerFields}
*
* @public
*/
export type DefaultMemoizeFields = {
/**
* Clears the memoization cache associated with a memoized function.
* This method is typically used to reset the state of the cache, allowing
* for the garbage collection of previously memoized results and ensuring
* that future calls to the function recompute the results.
*/
clearCache: () => void
resultsCount: () => number
resetResultsCount: () => void
}
/*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
* Reselect Internal Utility Types
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*/
/**
* Any function with any arguments.
*
* @internal
*/
export type AnyFunction = (...args: any[]) => any
/**
* Any function with unknown arguments.
*
* @internal
*/
export type UnknownFunction = (...args: unknown[]) => unknown
/**
* When a generic type parameter is using its default value of `never`, fallback to a different type.
*
* @template T - Type to be checked.
* @template FallbackTo - Type to fallback to if `T` resolves to `never`.
*
* @internal
*/
export type FallbackIfNever<T, FallbackTo> = IfNever<T, FallbackTo, T>
/**
* Extracts the non-function part of a type.
*
* @template T - The input type to be refined by excluding function types and index signatures.
*
* @internal
*/
export type NonFunctionType<T> = Simplify<
OmitIndexSignature<Exclude<T, AnyFunction>>
>
/**
* Extracts the function part of a type.
*
* @template T - The input type to be refined by extracting function types.
*
* @internal
*/
export type FunctionType<T> = Extract<T, AnyFunction>
/**
* Extracts the return type from all functions as a tuple.
*
* @internal
*/
export type ExtractReturnType<FunctionsArray extends readonly AnyFunction[]> = {
[Index in keyof FunctionsArray]: FunctionsArray[Index] extends FunctionsArray[number]
? FallbackIfUnknown<ReturnType<FunctionsArray[Index]>, any>
: never
}
/**
* Utility type to infer the type of "all params of a function except the first",
* so we can determine what arguments a memoize function accepts.
*
* @internal
*/
export type DropFirstParameter<Func extends AnyFunction> = Func extends (
firstArg: any,
...restArgs: infer Rest
) => any
? Rest
: never
/**
* Distributes over a type. It is used mostly to expand a function type
* in hover previews while preserving their original JSDoc information.
*
* If preserving JSDoc information is not a concern, you can use {@linkcode ExpandFunction ExpandFunction}.
*
* @template T The type to be distributed.
*
* @internal
*/
export type Distribute<T> = T extends T ? T : never
/**
* Extracts the type of the first element of an array or tuple.
*
* @internal
*/
export type FirstArrayElement<ArrayType> = ArrayType extends readonly [
unknown,
...unknown[]
]
? ArrayType[0]
: never
/**
* Extracts the type of an array or tuple minus the first element.
*
* @internal
*/
export type ArrayTail<ArrayType> = ArrayType extends readonly [
unknown,
...infer Tail
]
? Tail
: []
/**
* An alias for type `{}`. Represents any value that is not `null` or `undefined`.
* It is mostly used for semantic purposes to help distinguish between an
* empty object type and `{}` as they are not the same.
*
* @internal
*/
export type AnyNonNullishValue = NonNullable<unknown>
/**
* Same as {@linkcode AnyNonNullishValue AnyNonNullishValue} but aliased
* for semantic purposes. It is intended to be used in scenarios where
* a recursive type definition needs to be interrupted to ensure type safety
* and to avoid excessively deep recursion that could lead to performance issues.
*
* @internal
*/
export type InterruptRecursion = AnyNonNullishValue
/*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
* External/Copied Utility Types
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
*/
/**
* An if-else-like type that resolves depending on whether the given type is `never`.
* This is mainly used to conditionally resolve the type of a `memoizeOptions` object based on whether `memoize` is provided or not.
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/if-never.d.ts Source}
*
* @internal
*/
export type IfNever<T, TypeIfNever, TypeIfNotNever> = [T] extends [never]
? TypeIfNever
: TypeIfNotNever
/**
* Omit any index signatures from the given object type, leaving only explicitly defined properties.
* This is mainly used to remove explicit `any`s from the return type of some memoizers (e.g, `microMemoize`).
*
* __Disclaimer:__ When used on an intersection of a function and an object,
* the function is erased.
*
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/omit-index-signature.d.ts Source}
*
* @internal
*/
export type OmitIndexSignature<ObjectType> = {
[KeyType in keyof ObjectType as {} extends Record<KeyType, unknown>
? never
: KeyType]: ObjectType[KeyType]
}
/**
* The infamous "convert a union type to an intersection type" hack
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts Source}
* @see {@link https://github.com/microsoft/TypeScript/issues/29594 Reference}
*
* @internal
*/
export type UnionToIntersection<Union> =
// `extends unknown` is always going to be the case and is used to convert the
// `Union` into a [distributive conditional
// type](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-8.html#distributive-conditional-types).
(
Union extends unknown
? // The union type is used as the only argument to a function since the union
// of function arguments is an intersection.
(distributedUnion: Union) => void
: // This won't happen.
never
) extends // Infer the `Intersection` type since TypeScript represents the positional
// arguments of unions of functions as an intersection of the union.
(mergedIntersection: infer Intersection) => void
? // The `& Union` is to allow indexing by the resulting type
Intersection & Union
: never
/**
* Code to convert a union of values into a tuple.
* @see {@link https://stackoverflow.com/a/55128956/62937 Source}
*
* @internal
*/
type Push<T extends any[], V> = [...T, V]
/**
* @see {@link https://stackoverflow.com/a/55128956/62937 Source}
*
* @internal
*/
type LastOf<T> = UnionToIntersection<
T extends any ? () => T : never
> extends () => infer R
? R
: never
/**
* TS4.1+
* @see {@link https://stackoverflow.com/a/55128956/62937 Source}
*
* @internal
*/
export type TuplifyUnion<
T,
L = LastOf<T>,
N = [T] extends [never] ? true : false
> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>
/**
* Converts "the values of an object" into a tuple, like a type-level `Object.values()`
* @see {@link https://stackoverflow.com/a/68695508/62937 Source}
*
* @internal
*/
export type ObjectValuesToTuple<
T,
KS extends any[] = TuplifyUnion<keyof T>,
R extends any[] = []
> = KS extends [infer K, ...infer KT]
? ObjectValuesToTuple<T, KT, [...R, T[K & keyof T]]>
: R
/**
* Create a type that makes the given keys required.
* The remaining keys are kept as is.
*
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/set-required.d.ts Source}
*
* @internal
*/
export type SetRequired<BaseType, Keys extends keyof BaseType> = Omit<
BaseType,
Keys
> &
Required<Pick<BaseType, Keys>>
/**
* An if-else-like type that resolves depending on whether the given type is `unknown`.
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/if-unknown.d.ts Source}
*
* @internal
*/
export type IfUnknown<T, TypeIfUnknown, TypeIfNotUnknown> = unknown extends T // `T` can be `unknown` or `any`
? [T] extends [null] // `any` can be `null`, but `unknown` can't be
? TypeIfNotUnknown
: TypeIfUnknown
: TypeIfNotUnknown
/**
* When a type is resolves to `unknown`, fallback to a different type.
*
* @template T - Type to be checked.
* @template FallbackTo - Type to fallback to if `T` resolves to `unknown`.
*
* @internal
*/
export type FallbackIfUnknown<T, FallbackTo> = IfUnknown<T, FallbackTo, T>
/**
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
* Type Expansion Utilities
*
* -----------------------------------------------------------------------------
* -----------------------------------------------------------------------------
*
*/
/**
* Check whether `U` contains `U1`.
* @see {@link https://millsp.github.io/ts-toolbelt/modules/union_has.html Source}
*
* @internal
*/
export type Has<U, U1> = [U1] extends [U] ? 1 : 0
/**
* @internal
*/
export type Boolean2 = 0 | 1
/**
* @internal
*/
export type If2<B extends Boolean2, Then, Else = never> = B extends 1
? Then
: Else
/**
* @internal
*/
export type BuiltIn =
| Function
| Error
| Date
| { readonly [Symbol.toStringTag]: string }
| RegExp
| Generator
/**
* Expand an item a single level.
* @see {@link https://stackoverflow.com/a/69288824/62937 Source}
*
* @internal
*/
export type Expand<T> = T extends (...args: infer A) => infer R
? (...args: Expand<A>) => Expand<R>
: T extends infer O
? { [K in keyof O]: O[K] }
: never
/**
* Expand an item recursively.
* @see {@link https://stackoverflow.com/a/69288824/62937 Source}
*
* @internal
*/
export type ExpandRecursively<T> = T extends (...args: infer A) => infer R
? (...args: ExpandRecursively<A>) => ExpandRecursively<R>
: T extends object
? T extends infer O
? { [K in keyof O]: ExpandRecursively<O[K]> }
: never
: T
/**
* @internal
*/
export type Identity<T> = T
/**
* Another form of type value expansion
* @see {@link https://github.com/microsoft/TypeScript/issues/35247 Source}
*
* @internal
*/
export type Mapped<T> = Identity<{ [k in keyof T]: T[k] }>
/**
* This utility type is primarily used to expand a function type in order to
* improve its visual display in hover previews within IDEs.
*
* __Disclaimer:__ Functions expanded using this type will not display their
* original JSDoc information in hover previews.
*
* @template FunctionType - The type of the function to be expanded.
*
* @internal
*/
export type ExpandFunction<FunctionType extends AnyFunction> =
FunctionType extends FunctionType
? (...args: Parameters<FunctionType>) => ReturnType<FunctionType>
: never
/**
* Useful to flatten the type output to improve type hints shown in editors.
* And also to transform an interface into a type to aide with assignability.
* @see {@link https://github.com/sindresorhus/type-fest/blob/main/source/simplify.d.ts Source}
*
* @internal
*/
export type Simplify<T> = T extends AnyFunction
? T
: {
[KeyType in keyof T]: T[KeyType]
} & AnyNonNullishValue
/**
* Fully expand a type, deeply
* @see {@link https://github.com/millsp/ts-toolbelt Any.Compute}
*
* @internal
*/
export type ComputeDeep<A, Seen = never> = A extends BuiltIn
? A
: If2<
Has<Seen, A>,
A,
A extends any[]
? A extends Record<PropertyKey, any>[]
? ({
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
} & unknown)[]
: A
: A extends readonly any[]
? A extends readonly Record<PropertyKey, any>[]
? readonly ({
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
} & unknown)[]
: A
: { [K in keyof A]: ComputeDeep<A[K], A | Seen> } & unknown
>

156
node_modules/reselect/src/utils.ts generated vendored Normal file
View file

@ -0,0 +1,156 @@
import { runIdentityFunctionCheck } from './devModeChecks/identityFunctionCheck'
import { runInputStabilityCheck } from './devModeChecks/inputStabilityCheck'
import { globalDevModeChecks } from './devModeChecks/setGlobalDevModeChecks'
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
import type {
DevModeChecks,
Selector,
SelectorArray,
DevModeChecksExecutionInfo
} from './types'
export const NOT_FOUND = /* @__PURE__ */ Symbol('NOT_FOUND')
export type NOT_FOUND_TYPE = typeof NOT_FOUND
/**
* Assert that the provided value is a function. If the assertion fails,
* a `TypeError` is thrown with an optional custom error message.
*
* @param func - The value to be checked.
* @param errorMessage - An optional custom error message to use if the assertion fails.
* @throws A `TypeError` if the assertion fails.
*/
export function assertIsFunction<FunctionType extends Function>(
func: unknown,
errorMessage = `expected a function, instead received ${typeof func}`
): asserts func is FunctionType {
if (typeof func !== 'function') {
throw new TypeError(errorMessage)
}
}
/**
* Assert that the provided value is an object. If the assertion fails,
* a `TypeError` is thrown with an optional custom error message.
*
* @param object - The value to be checked.
* @param errorMessage - An optional custom error message to use if the assertion fails.
* @throws A `TypeError` if the assertion fails.
*/
export function assertIsObject<ObjectType extends Record<string, unknown>>(
object: unknown,
errorMessage = `expected an object, instead received ${typeof object}`
): asserts object is ObjectType {
if (typeof object !== 'object') {
throw new TypeError(errorMessage)
}
}
/**
* Assert that the provided array is an array of functions. If the assertion fails,
* a `TypeError` is thrown with an optional custom error message.
*
* @param array - The array to be checked.
* @param errorMessage - An optional custom error message to use if the assertion fails.
* @throws A `TypeError` if the assertion fails.
*/
export function assertIsArrayOfFunctions<FunctionType extends Function>(
array: unknown[],
errorMessage = `expected all items to be functions, instead received the following types: `
): asserts array is FunctionType[] {
if (
!array.every((item): item is FunctionType => typeof item === 'function')
) {
const itemTypes = array
.map(item =>
typeof item === 'function'
? `function ${item.name || 'unnamed'}()`
: typeof item
)
.join(', ')
throw new TypeError(`${errorMessage}[${itemTypes}]`)
}
}
/**
* Ensure that the input is an array. If it's already an array, it's returned as is.
* If it's not an array, it will be wrapped in a new array.
*
* @param item - The item to be checked.
* @returns An array containing the input item. If the input is already an array, it's returned without modification.
*/
export const ensureIsArray = (item: unknown) => {
return Array.isArray(item) ? item : [item]
}
/**
* Extracts the "dependencies" / "input selectors" from the arguments of `createSelector`.
*
* @param createSelectorArgs - Arguments passed to `createSelector` as an array.
* @returns An array of "input selectors" / "dependencies".
* @throws A `TypeError` if any of the input selectors is not function.
*/
export function getDependencies(createSelectorArgs: unknown[]) {
const dependencies = Array.isArray(createSelectorArgs[0])
? createSelectorArgs[0]
: createSelectorArgs
assertIsArrayOfFunctions<Selector>(
dependencies,
`createSelector expects all input-selectors to be functions, but received the following types: `
)
return dependencies as SelectorArray
}
/**
* Runs each input selector and returns their collective results as an array.
*
* @param dependencies - An array of "dependencies" or "input selectors".
* @param inputSelectorArgs - An array of arguments being passed to the input selectors.
* @returns An array of input selector results.
*/
export function collectInputSelectorResults(
dependencies: SelectorArray,
inputSelectorArgs: unknown[] | IArguments
) {
const inputSelectorResults = []
const { length } = dependencies
for (let i = 0; i < length; i++) {
// @ts-ignore
// apply arguments instead of spreading and mutate a local list of params for performance.
inputSelectorResults.push(dependencies[i].apply(null, inputSelectorArgs))
}
return inputSelectorResults
}
/**
* Retrieves execution information for development mode checks.
*
* @param devModeChecks - Custom Settings for development mode checks. These settings will override the global defaults.
* @param firstRun - Indicates whether it is the first time the selector has run.
* @returns An object containing the execution information for each development mode check.
*/
export const getDevModeChecksExecutionInfo = (
firstRun: boolean,
devModeChecks: Partial<DevModeChecks>
) => {
const { identityFunctionCheck, inputStabilityCheck } = {
...globalDevModeChecks,
...devModeChecks
}
return {
identityFunctionCheck: {
shouldRun:
identityFunctionCheck === 'always' ||
(identityFunctionCheck === 'once' && firstRun),
run: runIdentityFunctionCheck
},
inputStabilityCheck: {
shouldRun:
inputStabilityCheck === 'always' ||
(inputStabilityCheck === 'once' && firstRun),
run: runInputStabilityCheck
}
} satisfies DevModeChecksExecutionInfo
}

1
node_modules/reselect/src/versionedTypes/index.ts generated vendored Normal file
View file

@ -0,0 +1 @@
export type { MergeParameters } from './ts47-mergeParameters'

View file

@ -0,0 +1,117 @@
// This entire implementation courtesy of Anders Hjelsberg:
// https://github.com/microsoft/TypeScript/pull/50831#issuecomment-1253830522
import type { AnyFunction } from '../types'
/**
* Represents the longest array within an array of arrays.
*
* @template ArrayOfTuples An array of arrays.
*
* @internal
*/
type LongestTuple<ArrayOfTuples extends readonly unknown[][]> =
ArrayOfTuples extends [infer FirstArray extends unknown[]]
? FirstArray
: ArrayOfTuples extends [
infer FirstArray,
...infer RestArrays extends unknown[][]
]
? LongerOfTwo<FirstArray, LongestTuple<RestArrays>>
: never
/**
* Determines the longer of two array types.
*
* @template ArrayOne First array type.
* @template ArrayTwo Second array type.
*
* @internal
*/
type LongerOfTwo<ArrayOne, ArrayTwo> = keyof ArrayTwo extends keyof ArrayOne
? ArrayOne
: ArrayTwo
/**
* Extracts the element at a specific index in an array.
*
* @template ArrayType The array type.
* @template Index The index type.
*
* @internal
*/
type ElementAt<
ArrayType extends unknown[],
Index extends PropertyKey
> = Index extends keyof ArrayType ? ArrayType[Index] : unknown
/**
* Maps each array in an array of arrays to its element at a given index.
*
* @template ArrayOfTuples An array of arrays.
* @template Index The index to extract from each array.
*
* @internal
*/
type ElementsAtGivenIndex<
ArrayOfTuples extends readonly unknown[][],
Index extends PropertyKey
> = {
[ArrayIndex in keyof ArrayOfTuples]: ElementAt<
ArrayOfTuples[ArrayIndex],
Index
>
}
/**
* Computes the intersection of all types in a tuple.
*
* @template Tuple A tuple of types.
*
* @internal
*/
type Intersect<Tuple extends readonly unknown[]> = Tuple extends []
? unknown
: Tuple extends [infer Head, ...infer Tail]
? Head & Intersect<Tail>
: Tuple[number]
/**
* Merges a tuple of arrays into a single tuple, intersecting types at each index.
*
* @template ArrayOfTuples An array of tuples.
* @template LongestArray The longest array in ArrayOfTuples.
*
* @internal
*/
type MergeTuples<
ArrayOfTuples extends readonly unknown[][],
LongestArray extends unknown[] = LongestTuple<ArrayOfTuples>
> = {
[Index in keyof LongestArray]: Intersect<
ElementsAtGivenIndex<ArrayOfTuples, Index>
>
}
/**
* Extracts the parameter types from a tuple of functions.
*
* @template FunctionsArray An array of function types.
*
* @internal
*/
type ExtractParameters<FunctionsArray extends readonly AnyFunction[]> = {
[Index in keyof FunctionsArray]: Parameters<FunctionsArray[Index]>
}
/**
* Merges the parameters of a tuple of functions into a single tuple.
*
* @template FunctionsArray An array of function types.
*
* @internal
*/
export type MergeParameters<FunctionsArray extends readonly AnyFunction[]> =
'0' extends keyof FunctionsArray
? MergeTuples<ExtractParameters<FunctionsArray>>
: Parameters<FunctionsArray[number]>

269
node_modules/reselect/src/weakMapMemoize.ts generated vendored Normal file
View file

@ -0,0 +1,269 @@
// Original source:
// - https://github.com/facebook/react/blob/0b974418c9a56f6c560298560265dcf4b65784bc/packages/react/src/ReactCache.js
import type {
AnyFunction,
DefaultMemoizeFields,
EqualityFn,
Simplify
} from './types'
class StrongRef<T> {
constructor(private value: T) {}
deref() {
return this.value
}
}
const Ref =
typeof WeakRef !== 'undefined'
? WeakRef
: (StrongRef as unknown as typeof WeakRef)
const UNTERMINATED = 0
const TERMINATED = 1
interface UnterminatedCacheNode<T> {
/**
* Status, represents whether the cached computation returned a value or threw an error.
*/
s: 0
/**
* Value, either the cached result or an error, depending on status.
*/
v: void
/**
* Object cache, a `WeakMap` where non-primitive arguments are stored.
*/
o: null | WeakMap<Function | Object, CacheNode<T>>
/**
* Primitive cache, a regular Map where primitive arguments are stored.
*/
p: null | Map<string | number | null | void | symbol | boolean, CacheNode<T>>
}
interface TerminatedCacheNode<T> {
/**
* Status, represents whether the cached computation returned a value or threw an error.
*/
s: 1
/**
* Value, either the cached result or an error, depending on status.
*/
v: T
/**
* Object cache, a `WeakMap` where non-primitive arguments are stored.
*/
o: null | WeakMap<Function | Object, CacheNode<T>>
/**
* Primitive cache, a regular `Map` where primitive arguments are stored.
*/
p: null | Map<string | number | null | void | symbol | boolean, CacheNode<T>>
}
type CacheNode<T> = TerminatedCacheNode<T> | UnterminatedCacheNode<T>
function createCacheNode<T>(): CacheNode<T> {
return {
s: UNTERMINATED,
v: undefined,
o: null,
p: null
}
}
/**
* Configuration options for a memoization function utilizing `WeakMap` for
* its caching mechanism.
*
* @template Result - The type of the return value of the memoized function.
*
* @since 5.0.0
* @public
*/
export interface WeakMapMemoizeOptions<Result = any> {
/**
* If provided, used to compare a newly generated output value against previous values in the cache.
* If a match is found, the old value is returned. This addresses the common
* ```ts
* todos.map(todo => todo.id)
* ```
* use case, where an update to another field in the original data causes a recalculation
* due to changed references, but the output is still effectively the same.
*
* @since 5.0.0
*/
resultEqualityCheck?: EqualityFn<Result>
}
/**
* Creates a tree of `WeakMap`-based cache nodes based on the identity of the
* arguments it's been called with (in this case, the extracted values from your input selectors).
* This allows `weakMapMemoize` to have an effectively infinite cache size.
* Cache results will be kept in memory as long as references to the arguments still exist,
* and then cleared out as the arguments are garbage-collected.
*
* __Design Tradeoffs for `weakMapMemoize`:__
* - Pros:
* - It has an effectively infinite cache size, but you have no control over
* how long values are kept in cache as it's based on garbage collection and `WeakMap`s.
* - Cons:
* - There's currently no way to alter the argument comparisons.
* They're based on strict reference equality.
* - It's roughly the same speed as `lruMemoize`, although likely a fraction slower.
*
* __Use Cases for `weakMapMemoize`:__
* - This memoizer is likely best used for cases where you need to call the
* same selector instance with many different arguments, such as a single
* selector instance that is used in a list item component and called with
* item IDs like:
* ```ts
* useSelector(state => selectSomeData(state, props.category))
* ```
* @param func - The function to be memoized.
* @returns A memoized function with a `.clearCache()` method attached.
*
* @example
* <caption>Using `createSelector`</caption>
* ```ts
* import { createSelector, weakMapMemoize } from 'reselect'
*
* interface RootState {
* items: { id: number; category: string; name: string }[]
* }
*
* const selectItemsByCategory = createSelector(
* [
* (state: RootState) => state.items,
* (state: RootState, category: string) => category
* ],
* (items, category) => items.filter(item => item.category === category),
* {
* memoize: weakMapMemoize,
* argsMemoize: weakMapMemoize
* }
* )
* ```
*
* @example
* <caption>Using `createSelectorCreator`</caption>
* ```ts
* import { createSelectorCreator, weakMapMemoize } from 'reselect'
*
* const createSelectorWeakMap = createSelectorCreator({ memoize: weakMapMemoize, argsMemoize: weakMapMemoize })
*
* const selectItemsByCategory = createSelectorWeakMap(
* [
* (state: RootState) => state.items,
* (state: RootState, category: string) => category
* ],
* (items, category) => items.filter(item => item.category === category)
* )
* ```
*
* @template Func - The type of the function that is memoized.
*
* @see {@link https://reselect.js.org/api/weakMapMemoize `weakMapMemoize`}
*
* @since 5.0.0
* @public
* @experimental
*/
export function weakMapMemoize<Func extends AnyFunction>(
func: Func,
options: WeakMapMemoizeOptions<ReturnType<Func>> = {}
) {
let fnNode = createCacheNode()
const { resultEqualityCheck } = options
let lastResult: WeakRef<object> | undefined
let resultsCount = 0
function memoized() {
let cacheNode = fnNode
const { length } = arguments
for (let i = 0, l = length; i < l; i++) {
const arg = arguments[i]
if (
typeof arg === 'function' ||
(typeof arg === 'object' && arg !== null)
) {
// Objects go into a WeakMap
let objectCache = cacheNode.o
if (objectCache === null) {
cacheNode.o = objectCache = new WeakMap()
}
const objectNode = objectCache.get(arg)
if (objectNode === undefined) {
cacheNode = createCacheNode()
objectCache.set(arg, cacheNode)
} else {
cacheNode = objectNode
}
} else {
// Primitives go into a regular Map
let primitiveCache = cacheNode.p
if (primitiveCache === null) {
cacheNode.p = primitiveCache = new Map()
}
const primitiveNode = primitiveCache.get(arg)
if (primitiveNode === undefined) {
cacheNode = createCacheNode()
primitiveCache.set(arg, cacheNode)
} else {
cacheNode = primitiveNode
}
}
}
const terminatedNode = cacheNode as unknown as TerminatedCacheNode<any>
let result
if (cacheNode.s === TERMINATED) {
result = cacheNode.v
} else {
// Allow errors to propagate
result = func.apply(null, arguments as unknown as any[])
resultsCount++
if (resultEqualityCheck) {
const lastResultValue = lastResult?.deref?.() ?? lastResult
if (
lastResultValue != null &&
resultEqualityCheck(lastResultValue as ReturnType<Func>, result)
) {
result = lastResultValue
resultsCount !== 0 && resultsCount--
}
const needsWeakRef =
(typeof result === 'object' && result !== null) ||
typeof result === 'function'
lastResult = needsWeakRef ? new Ref(result) : result
}
}
terminatedNode.s = TERMINATED
terminatedNode.v = result
return result
}
memoized.clearCache = () => {
fnNode = createCacheNode()
memoized.resetResultsCount()
}
memoized.resultsCount = () => resultsCount
memoized.resetResultsCount = () => {
resultsCount = 0
}
return memoized as Func & Simplify<DefaultMemoizeFields>
}