This commit is contained in:
21
node_modules/reselect/LICENSE
generated
vendored
Normal file
21
node_modules/reselect/LICENSE
generated
vendored
Normal 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.
|
||||
658
node_modules/reselect/README.md
generated
vendored
Normal file
658
node_modules/reselect/README.md
generated
vendored
Normal file
@@ -0,0 +1,658 @@
|
||||
# Reselect
|
||||
|
||||
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.
|
||||
|
||||
[![GitHub Workflow Status][build-badge]][build]
|
||||
[![npm package][npm-badge]][npm]
|
||||
[![Coveralls][coveralls-badge]][coveralls]
|
||||
|
||||
## 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.
|
||||
|
||||
```js
|
||||
import { createSelector } from '@reduxjs/toolkit'
|
||||
```
|
||||
|
||||
### Standalone
|
||||
|
||||
For standalone usage, install the `reselect` package:
|
||||
|
||||
```bash
|
||||
npm install reselect
|
||||
|
||||
yarn add reselect
|
||||
```
|
||||
|
||||
## 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 an "output" selector that receives the extracted values and should return a derived value. If the generated 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/objective-waterfall-1z5y8?file=/src/index.js):
|
||||
|
||||
```js
|
||||
import { createSelector } from 'reselect'
|
||||
|
||||
const selectShopItems = state => state.shop.items
|
||||
const selectTaxPercent = state => state.shop.taxPercent
|
||||
|
||||
const selectSubtotal = createSelector(selectShopItems, items =>
|
||||
items.reduce((subtotal, item) => subtotal + item.value, 0)
|
||||
)
|
||||
|
||||
const selectTax = createSelector(
|
||||
selectSubtotal,
|
||||
selectTaxPercent,
|
||||
(subtotal, taxPercent) => subtotal * (taxPercent / 100)
|
||||
)
|
||||
|
||||
const selectTotal = createSelector(
|
||||
selectSubtotal,
|
||||
selectTax,
|
||||
(subtotal, tax) => ({ total: subtotal + tax })
|
||||
)
|
||||
|
||||
const exampleState = {
|
||||
shop: {
|
||||
taxPercent: 8,
|
||||
items: [
|
||||
{ name: 'apple', value: 1.2 },
|
||||
{ name: 'orange', value: 0.95 }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
console.log(selectSubtotal(exampleState)) // 2.15
|
||||
console.log(selectTax(exampleState)) // 0.172
|
||||
console.log(selectTotal(exampleState)) // { total: 2.322 }
|
||||
```
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Installation](#installation)
|
||||
- [Redux Toolkit](#redux-toolkit)
|
||||
- [Standalone](#standalone)
|
||||
- [Basic Usage](#basic-usage)
|
||||
- [API](#api)
|
||||
- [createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)](#createselectorinputselectors--inputselectors-resultfunc-selectoroptions)
|
||||
- [defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)](#defaultmemoizefunc-equalitycheckoroptions--defaultequalitycheck)
|
||||
- [createSelectorCreator(memoize, ...memoizeOptions)](#createselectorcreatormemoize-memoizeoptions)
|
||||
- [Customize `equalityCheck` for `defaultMemoize`](#customize-equalitycheck-for-defaultmemoize)
|
||||
- [Use memoize function from Lodash for an unbounded cache](#use-memoize-function-from-lodash-for-an-unbounded-cache)
|
||||
- [createStructuredSelector({inputSelectors}, selectorCreator = createSelector)](#createstructuredselectorinputselectors-selectorcreator--createselector)
|
||||
- [FAQ](#faq)
|
||||
- [Q: Why isn’t my selector recomputing when the input state changes?](#q-why-isnt-my-selector-recomputing-when-the-input-state-changes)
|
||||
- [Q: Why is my selector recomputing when the input state stays the same?](#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same)
|
||||
- [Q: Can I use Reselect without Redux?](#q-can-i-use-reselect-without-redux)
|
||||
- [Q: How do I create a selector that takes an argument?](#q-how-do-i-create-a-selector-that-takes-an-argument)
|
||||
- [Q: The default memoization function is no good, can I use a different one?](#q-the-default-memoization-function-is-no-good-can-i-use-a-different-one)
|
||||
- [Q: How do I test a selector?](#q-how-do-i-test-a-selector)
|
||||
- [Q: Can I share a selector across multiple component instances?](#q-can-i-share-a-selector-across-multiple-component-instances)
|
||||
- [Q: Are there TypeScript Typings?](#q-are-there-typescript-typings)
|
||||
- [Q: How can I make a curried selector?](#q-how-can-i-make-a-curried-selector)
|
||||
- [Related Projects](#related-projects)
|
||||
- [re-reselect](#re-reselect)
|
||||
- [reselect-tools](#reselect-tools)
|
||||
- [reselect-debugger](#reselect-debugger)
|
||||
- [License](#license)
|
||||
- [Prior Art and Inspiration](#prior-art-and-inspiration)
|
||||
|
||||
## API
|
||||
|
||||
### createSelector(...inputSelectors | [inputSelectors], resultFunc, selectorOptions?)
|
||||
|
||||
Accepts one or more "input selectors" (either as separate arguments or a single array), a single "output selector" / "result function", and an optional options object, and generates a memoized selector function.
|
||||
|
||||
When the selector is called, each input selector will be called with all of the provided arguments. The extracted values are then passed as separate arguments to the output selector, which should calculate and return a final result. The inputs and result are cached for later use.
|
||||
|
||||
If the selector is called again with the same arguments, the previously cached result is returned instead of recalculating a new result.
|
||||
|
||||
`createSelector` determines if the value returned by an input-selector has changed between calls using reference equality (`===`). Inputs to selectors created with `createSelector` should be immutable.
|
||||
|
||||
By default, selectors created with `createSelector` have a cache size of 1. This means they always recalculate when the value of an input-selector changes, as a selector only stores the preceding value of each input-selector. This can be customized by passing a `selectorOptions` object with a `memoizeOptions` field containing options for the built-in `defaultMemoize` memoization function .
|
||||
|
||||
```js
|
||||
const selectValue = createSelector(
|
||||
state => state.values.value1,
|
||||
state => state.values.value2,
|
||||
(value1, value2) => value1 + value2
|
||||
)
|
||||
|
||||
// You can also pass an array of selectors
|
||||
const selectTotal = createSelector(
|
||||
[state => state.values.value1, state => state.values.value2],
|
||||
(value1, value2) => value1 + value2
|
||||
)
|
||||
|
||||
// Selector behavior can be customized
|
||||
const customizedSelector = createSelector(
|
||||
state => state.a,
|
||||
state => state.b,
|
||||
(a, b) => a + b,
|
||||
{
|
||||
// New in 4.1: Pass options through to the built-in `defaultMemoize` function
|
||||
memoizeOptions: {
|
||||
equalityCheck: (a, b) => a === b,
|
||||
maxSize: 10,
|
||||
resultEqualityCheck: shallowEqual
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
Selectors are typically called with a Redux `state` value as the first argument, and the input selectors extract pieces of the `state` object for use in calculations. However, it's also common to want to pass additional arguments, such as a value to filter by. Since input selectors are given all arguments, they can extract the additional arguments and pass them to the output selector:
|
||||
|
||||
```js
|
||||
const selectItemsByCategory = createSelector(
|
||||
[
|
||||
// Usual first input - extract value from `state`
|
||||
state => state.items,
|
||||
// Take the second arg, `category`, and forward to the output selector
|
||||
(state, category) => category
|
||||
],
|
||||
// Output selector gets (`items, category)` as args
|
||||
(items, category) => items.filter(item => item.category === category)
|
||||
)
|
||||
```
|
||||
|
||||
### defaultMemoize(func, equalityCheckOrOptions = defaultEqualityCheck)
|
||||
|
||||
`defaultMemoize` memoizes the function passed in the func parameter. It is the standard memoize function used by `createSelector`.
|
||||
|
||||
`defaultMemoize` has a default cache size of 1. This means it always recalculates when the value of an argument changes. However, this can be customized as needed with a specific max cache size (new in 4.1).
|
||||
|
||||
`defaultMemoize` determines if an argument has changed by calling the `equalityCheck` function. As `defaultMemoize` is designed to be used with immutable data, the default `equalityCheck` function checks for changes using reference equality:
|
||||
|
||||
```js
|
||||
function defaultEqualityCheck(previousVal, currentVal) {
|
||||
return currentVal === previousVal
|
||||
}
|
||||
```
|
||||
|
||||
As of Reselect 4.1, `defaultMemoize` also accepts an options object as its first argument instead of `equalityCheck`. The options object may contain:
|
||||
|
||||
```ts
|
||||
interface DefaultMemoizeOptions {
|
||||
equalityCheck?: EqualityFn
|
||||
resultEqualityCheck?: EqualityFn
|
||||
maxSize?: number
|
||||
}
|
||||
```
|
||||
|
||||
Available options are:
|
||||
|
||||
- `equalityCheck`: used to compare the individual arguments of the provided calculation function
|
||||
- `resultEqualityCheck`: 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 address the common `todos.map(todo => todo.id)` use case, where an update to another field in the original data causes a recalculate due to changed references, but the output is still effectively the same.
|
||||
- `maxSize`: the cache size for the selector. If `maxSize` is greater than 1, the selector will use an LRU cache internally
|
||||
|
||||
The returned memoized function will have a `.clearCache()` method attached.
|
||||
|
||||
`defaultMemoize` can also be used with `createSelectorCreator` to create a new selector factory that always has the same settings for each selector.
|
||||
|
||||
### createSelectorCreator(memoize, ...memoizeOptions)
|
||||
|
||||
`createSelectorCreator` can be used to make a customized version of `createSelector`.
|
||||
|
||||
The `memoize` argument is a memoization function to replace `defaultMemoize`.
|
||||
|
||||
The `...memoizeOptions` rest parameters are zero or more configuration options to be passed to `memoizeFunc`. The selectors `resultFunc` is passed as the first argument to `memoize` and the `memoizeOptions` are passed as the second argument onwards:
|
||||
|
||||
```js
|
||||
const customSelectorCreator = createSelectorCreator(
|
||||
customMemoize, // function to be used to memoize resultFunc
|
||||
option1, // option1 will be passed as second argument to customMemoize
|
||||
option2, // option2 will be passed as third argument to customMemoize
|
||||
option3 // option3 will be passed as fourth argument to customMemoize
|
||||
)
|
||||
|
||||
const customSelector = customSelectorCreator(
|
||||
input1,
|
||||
input2,
|
||||
resultFunc // resultFunc will be passed as first argument to customMemoize
|
||||
)
|
||||
```
|
||||
|
||||
Internally `customSelector` calls the memoize function as follows:
|
||||
|
||||
```js
|
||||
customMemoize(resultFunc, option1, option2, option3)
|
||||
```
|
||||
|
||||
Here are some examples of how you might use `createSelectorCreator`:
|
||||
|
||||
#### Customize `equalityCheck` for `defaultMemoize`
|
||||
|
||||
```js
|
||||
import { createSelectorCreator, defaultMemoize } from 'reselect'
|
||||
import isEqual from 'lodash.isequal'
|
||||
|
||||
// create a "selector creator" that uses lodash.isequal instead of ===
|
||||
const createDeepEqualSelector = createSelectorCreator(defaultMemoize, isEqual)
|
||||
|
||||
// use the new "selector creator" to create a selector
|
||||
const selectSum = createDeepEqualSelector(
|
||||
state => state.values.filter(val => val < 5),
|
||||
values => values.reduce((acc, val) => acc + val, 0)
|
||||
)
|
||||
```
|
||||
|
||||
#### Use memoize function from Lodash for an unbounded cache
|
||||
|
||||
```js
|
||||
import { createSelectorCreator } from 'reselect'
|
||||
import memoize from 'lodash.memoize'
|
||||
|
||||
let called = 0
|
||||
const hashFn = (...args) =>
|
||||
args.reduce((acc, val) => acc + '-' + JSON.stringify(val), '')
|
||||
const customSelectorCreator = createSelectorCreator(memoize, hashFn)
|
||||
const selector = customSelectorCreator(
|
||||
state => state.a,
|
||||
state => state.b,
|
||||
(a, b) => {
|
||||
called++
|
||||
return a + b
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### createStructuredSelector({inputSelectors}, selectorCreator = createSelector)
|
||||
|
||||
`createStructuredSelector` is a convenience function for a common pattern that arises when using Reselect. The selector passed to a `connect` decorator often just takes the values of its input-selectors and maps them to keys in an object:
|
||||
|
||||
```js
|
||||
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
|
||||
}))
|
||||
```
|
||||
|
||||
`createStructuredSelector` takes an object whose properties are input-selectors and returns a structured selector. The structured selector returns an object with the same keys as the `inputSelectors` argument, but with the selectors replaced with their values.
|
||||
|
||||
```js
|
||||
const selectA = state => state.a
|
||||
const selectB = state => state.b
|
||||
|
||||
const structuredSelector = createStructuredSelector({
|
||||
x: selectA,
|
||||
y: selectB
|
||||
})
|
||||
|
||||
const result = structuredSelector({ a: 1, b: 2 }) // will produce { x: 1, y: 2 }
|
||||
```
|
||||
|
||||
Structured selectors can be nested:
|
||||
|
||||
```js
|
||||
const nestedSelector = createStructuredSelector({
|
||||
subA: createStructuredSelector({
|
||||
selectorA,
|
||||
selectorB
|
||||
}),
|
||||
subB: createStructuredSelector({
|
||||
selectorC,
|
||||
selectorD
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
### Q: Why isn’t my selector recomputing when the input state changes?
|
||||
|
||||
A: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` will not work with a state update function that mutates an existing object instead of creating a new one each time. `createSelector` uses an identity check (`===`) to detect that an input has changed, so mutating an existing object will not trigger the selector to recompute because mutating an object does not change its identity. Note that if you are using Redux, mutating the state object is [almost certainly a mistake](http://redux.js.org/docs/Troubleshooting.html).
|
||||
|
||||
The following example defines a simple selector that determines if the first todo item in an array of todos has been completed:
|
||||
|
||||
```js
|
||||
const selectIsFirstTodoComplete = createSelector(
|
||||
state => state.todos[0],
|
||||
todo => todo && todo.completed
|
||||
)
|
||||
```
|
||||
|
||||
The following state update function **will not** work with `selectIsFirstTodoComplete`:
|
||||
|
||||
```js
|
||||
export default function todos(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case COMPLETE_ALL:
|
||||
const areAllMarked = state.every(todo => todo.completed)
|
||||
// BAD: mutating an existing object
|
||||
return state.map(todo => {
|
||||
todo.completed = !areAllMarked
|
||||
return todo
|
||||
})
|
||||
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The following state update function **will** work with `selectIsFirstTodoComplete`:
|
||||
|
||||
```js
|
||||
export default function todos(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case COMPLETE_ALL:
|
||||
const areAllMarked = state.every(todo => todo.completed)
|
||||
// GOOD: returning a new object each time with Object.assign
|
||||
return state.map(todo =>
|
||||
Object.assign({}, todo, {
|
||||
completed: !areAllMarked
|
||||
})
|
||||
)
|
||||
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you are not using Redux and have a requirement to work with mutable data, you can use `createSelectorCreator` to replace the default memoization function and/or use a different equality check function. See [here](#use-memoize-function-from-lodash-for-an-unbounded-cache) and [here](#customize-equalitycheck-for-defaultmemoize) for examples.
|
||||
|
||||
### Q: Why is my selector recomputing when the input state stays the same?
|
||||
|
||||
A: Check that your memoization function is compatible with your state update function (i.e. the reducer if you are using Redux). For example, a selector created with `createSelector` that recomputes unexpectedly may be receiving a new object on each update whether the values it contains have changed or not. `createSelector` uses an identity check (`===`) to detect that an input has changed, so returning a new object on each update means that the selector will recompute on each update.
|
||||
|
||||
```js
|
||||
import { REMOVE_OLD } from '../constants/ActionTypes'
|
||||
|
||||
const initialState = [
|
||||
{
|
||||
text: 'Use Redux',
|
||||
completed: false,
|
||||
id: 0,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
]
|
||||
|
||||
export default function todos(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case REMOVE_OLD:
|
||||
return state.filter(todo => {
|
||||
return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()
|
||||
})
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The following selector is going to recompute every time REMOVE_OLD is invoked because Array.filter always returns a new object. However, in the majority of cases the REMOVE_OLD action will not change the list of todos so the recomputation is unnecessary.
|
||||
|
||||
```js
|
||||
import { createSelector } from 'reselect'
|
||||
|
||||
const todosSelector = state => state.todos
|
||||
|
||||
export const selectVisibleTodos = createSelector(
|
||||
todosSelector,
|
||||
(todos) => {
|
||||
...
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
You can eliminate unnecessary recomputations by returning a new object from the state update function only when a deep equality check has found that the list of todos has actually changed:
|
||||
|
||||
```js
|
||||
import { REMOVE_OLD } from '../constants/ActionTypes'
|
||||
import isEqual from 'lodash.isequal'
|
||||
|
||||
const initialState = [
|
||||
{
|
||||
text: 'Use Redux',
|
||||
completed: false,
|
||||
id: 0,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
]
|
||||
|
||||
export default function todos(state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case REMOVE_OLD:
|
||||
const updatedState = state.filter(todo => {
|
||||
return todo.timestamp + 30 * 24 * 60 * 60 * 1000 > Date.now()
|
||||
})
|
||||
return isEqual(updatedState, state) ? state : updatedState
|
||||
default:
|
||||
return state
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively, the default `equalityCheck` function in the selector can be replaced by a deep equality check:
|
||||
|
||||
```js
|
||||
import { createSelectorCreator, defaultMemoize } from 'reselect'
|
||||
import isEqual from 'lodash.isequal'
|
||||
|
||||
const selectTodos = state => state.todos
|
||||
|
||||
// create a "selector creator" that uses lodash.isequal instead of ===
|
||||
const createDeepEqualSelector = createSelectorCreator(
|
||||
defaultMemoize,
|
||||
isEqual
|
||||
)
|
||||
|
||||
// use the new "selector creator" to create a selector
|
||||
const mySelector = createDeepEqualSelector(
|
||||
todosSelector,
|
||||
(todos) => {
|
||||
...
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
Always check that the cost of an alternative `equalityCheck` function or deep equality check in the state update function is not greater than the cost of recomputing every time. If recomputing every time does work out to be the cheaper option, it may be that for this case Reselect is not giving you any benefit over passing a plain `mapStateToProps` function to `connect`.
|
||||
|
||||
### Q: Can I use Reselect without Redux?
|
||||
|
||||
A: Yes. Reselect has no dependencies on any other package, so although it was designed to be used with Redux it can be used independently. It can be used with any plain JS data, such as typical React state values, as long as that data is being updated immutably.
|
||||
|
||||
### Q: How do I create a selector that takes an argument?
|
||||
|
||||
As shown in the API reference section above, provide input selectors that extract the arguments and forward them to the output selector for calculation:
|
||||
|
||||
```js
|
||||
const selectItemsByCategory = createSelector(
|
||||
[
|
||||
// Usual first input - extract value from `state`
|
||||
state => state.items,
|
||||
// Take the second arg, `category`, and forward to the output selector
|
||||
(state, category) => category
|
||||
],
|
||||
// Output selector gets (`items, category)` as args
|
||||
(items, category) => items.filter(item => item.category === category)
|
||||
)
|
||||
```
|
||||
|
||||
### Q: The default memoization function is no good, can I use a different one?
|
||||
|
||||
A: We think it works great for a lot of use cases, but sure. See [these examples](#customize-equalitycheck-for-defaultmemoize).
|
||||
|
||||
### Q: How do I test a selector?
|
||||
|
||||
A: For a given input, a selector should always produce the same output. For this reason they are simple to unit test.
|
||||
|
||||
```js
|
||||
const selector = createSelector(
|
||||
state => state.a,
|
||||
state => state.b,
|
||||
(a, b) => ({
|
||||
c: a * 2,
|
||||
d: b * 3
|
||||
})
|
||||
)
|
||||
|
||||
test('selector unit test', () => {
|
||||
assert.deepEqual(selector({ a: 1, b: 2 }), { c: 2, d: 6 })
|
||||
assert.deepEqual(selector({ a: 2, b: 3 }), { c: 4, d: 9 })
|
||||
})
|
||||
```
|
||||
|
||||
It may also be useful to check that the memoization function for a selector works correctly with the state update function (i.e. the reducer if you are using Redux). Each selector has a `recomputations` method that will return the number of times it has been recomputed:
|
||||
|
||||
```js
|
||||
suite('selector', () => {
|
||||
let state = { a: 1, b: 2 }
|
||||
|
||||
const reducer = (state, action) => ({
|
||||
a: action(state.a),
|
||||
b: action(state.b)
|
||||
})
|
||||
|
||||
const selector = createSelector(
|
||||
state => state.a,
|
||||
state => state.b,
|
||||
(a, b) => ({
|
||||
c: a * 2,
|
||||
d: b * 3
|
||||
})
|
||||
)
|
||||
|
||||
const plusOne = x => x + 1
|
||||
const id = x => x
|
||||
|
||||
test('selector unit test', () => {
|
||||
state = reducer(state, plusOne)
|
||||
assert.deepEqual(selector(state), { c: 4, d: 9 })
|
||||
state = reducer(state, id)
|
||||
assert.deepEqual(selector(state), { c: 4, d: 9 })
|
||||
assert.equal(selector.recomputations(), 1)
|
||||
state = reducer(state, plusOne)
|
||||
assert.deepEqual(selector(state), { c: 6, d: 12 })
|
||||
assert.equal(selector.recomputations(), 2)
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
Additionally, selectors keep a reference to the last result function as `.resultFunc`. If you have selectors composed of many other selectors this can help you test each selector without coupling all of your tests to the shape of your state.
|
||||
|
||||
For example if you have a set of selectors like this:
|
||||
|
||||
**selectors.js**
|
||||
|
||||
```js
|
||||
export const selectFirst = createSelector( ... )
|
||||
export const selectSecond = createSelector( ... )
|
||||
export const selectThird = createSelector( ... )
|
||||
|
||||
export const myComposedSelector = createSelector(
|
||||
selectFirst,
|
||||
selectSecond,
|
||||
selectThird,
|
||||
(first, second, third) => first * second < third
|
||||
)
|
||||
```
|
||||
|
||||
And then a set of unit tests like this:
|
||||
|
||||
**test/selectors.js**
|
||||
|
||||
```js
|
||||
// tests for the first three selectors...
|
||||
test("selectFirst unit test", () => { ... })
|
||||
test("selectSecond unit test", () => { ... })
|
||||
test("selectThird unit test", () => { ... })
|
||||
|
||||
// We have already tested the previous
|
||||
// three selector outputs so we can just call `.resultFunc`
|
||||
// with the values we want to test directly:
|
||||
test("myComposedSelector unit test", () => {
|
||||
// here instead of calling selector()
|
||||
// we just call selector.resultFunc()
|
||||
assert(myComposedSelector.resultFunc(1, 2, 3), true)
|
||||
assert(myComposedSelector.resultFunc(2, 2, 1), false)
|
||||
})
|
||||
```
|
||||
|
||||
Finally, each selector has a `resetRecomputations` method that sets
|
||||
recomputations back to 0. The intended use is for a complex selector that may
|
||||
have many independent tests and you don't want to manually manage the
|
||||
computation count or create a "dummy" selector for each test.
|
||||
|
||||
### Q: Can I share a selector across multiple component instances?
|
||||
|
||||
A: Yes, although it requires some planning.
|
||||
|
||||
As of Reselect 4.1, you can create a selector with a cache size greater than one by passing in a `maxSize` option under `memoizeOptions` for use with the built-in `defaultMemoize`.
|
||||
|
||||
Otherwise, selectors created using `createSelector` only have a cache size of one. This can make them unsuitable for sharing across multiple instances if the arguments to the selector are different for each instance of the component. There are a couple of ways to get around this:
|
||||
|
||||
- Create a factory function which returns a new selector for each instance of the component. This can be called in a React component inside the `useMemo` hook to generate a unique selector instance per component.
|
||||
- Create a custom selector with a cache size greater than one using `createSelectorCreator`
|
||||
|
||||
### Q: Are there TypeScript Typings?
|
||||
|
||||
A: Yes! Reselect is now written in TS itself, so they should Just Work™.
|
||||
|
||||
### Q: I am seeing a TypeScript error: `Type instantiation is excessively deep and possibly infinite`
|
||||
|
||||
A: This can often occur with deeply recursive types, which occur in this library. Please see [this
|
||||
comment](https://github.com/reduxjs/reselect/issues/534#issuecomment-956708953) for a discussion of the problem, as
|
||||
relating to nested selectors.
|
||||
|
||||
### Q: How can I make a [curried](https://github.com/hemanth/functional-programming-jargon#currying) selector?
|
||||
|
||||
A: Try these [helper functions](https://github.com/reduxjs/reselect/issues/159#issuecomment-238724788) courtesy of [MattSPalmer](https://github.com/MattSPalmer)
|
||||
|
||||
## Related Projects
|
||||
|
||||
### [re-reselect](https://github.com/toomuchdesign/re-reselect)
|
||||
|
||||
Enhances Reselect selectors by wrapping `createSelector` and returning a memoized collection of selectors indexed with the cache key returned by a custom resolver function.
|
||||
|
||||
Useful to reduce selectors recalculation when the same selector is repeatedly called with one/few different arguments.
|
||||
|
||||
### [reselect-tools](https://github.com/skortchmark9/reselect-tools)
|
||||
|
||||
[Chrome extension](https://chrome.google.com/webstore/detail/reselect-devtools/cjmaipngmabglflfeepmdiffcijhjlbb?hl=en) and [companion lib](https://github.com/skortchmark9/reselect-tools) for debugging selectors.
|
||||
|
||||
- Measure selector recomputations across the app and identify performance bottlenecks
|
||||
- Check selector dependencies, inputs, outputs, and recomputations at any time with the chrome extension
|
||||
- Statically export a JSON representation of your selector graph for further analysis
|
||||
|
||||
### [reselect-debugger](https://github.com/vlanemcev/reselect-debugger-flipper)
|
||||
|
||||
[Flipper plugin](https://github.com/vlanemcev/flipper-plugin-reselect-debugger) and [and the connect app](https://github.com/vlanemcev/reselect-debugger-flipper) for debugging selectors in **React Native Apps**.
|
||||
|
||||
Inspired by Reselect Tools, so it also has all functionality from this library and more, but only for React Native and Flipper.
|
||||
|
||||
- Selectors Recomputations count in live time across the App for identify performance bottlenecks
|
||||
- Highlight most recomputed selectors
|
||||
- Dependency Graph
|
||||
- Search by Selectors Graph
|
||||
- Selectors Inputs
|
||||
- Selectors Output (In case if selector not dependent from external arguments)
|
||||
- Shows "Not Memoized (NM)" selectors
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## Prior Art and Inspiration
|
||||
|
||||
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).
|
||||
|
||||
[build-badge]: https://img.shields.io/github/workflow/status/reduxjs/redux-thunk/Tests
|
||||
[build]: https://github.com/reduxjs/reselect/actions/workflows/build-and-test-types.yml
|
||||
[npm-badge]: https://img.shields.io/npm/v/reselect.svg?style=flat-square
|
||||
[npm]: https://www.npmjs.org/package/reselect
|
||||
[coveralls-badge]: https://img.shields.io/coveralls/reduxjs/reselect/master.svg?style=flat-square
|
||||
[coveralls]: https://coveralls.io/github/reduxjs/reselect
|
||||
291
node_modules/reselect/dist/reselect.js
generated
vendored
Normal file
291
node_modules/reselect/dist/reselect.js
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
|
||||
typeof define === 'function' && define.amd ? define(['exports'], factory) :
|
||||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Reselect = {}));
|
||||
})(this, (function (exports) { 'use strict';
|
||||
|
||||
// Cache implementation based on Erik Rasmussen's `lru-memoize`:
|
||||
// https://github.com/erikras/lru-memoize
|
||||
var NOT_FOUND = 'NOT_FOUND';
|
||||
|
||||
function createSingletonCache(equals) {
|
||||
var entry;
|
||||
return {
|
||||
get: function get(key) {
|
||||
if (entry && equals(entry.key, key)) {
|
||||
return entry.value;
|
||||
}
|
||||
|
||||
return NOT_FOUND;
|
||||
},
|
||||
put: function put(key, value) {
|
||||
entry = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
},
|
||||
getEntries: function getEntries() {
|
||||
return entry ? [entry] : [];
|
||||
},
|
||||
clear: function clear() {
|
||||
entry = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createLruCache(maxSize, equals) {
|
||||
var entries = [];
|
||||
|
||||
function get(key) {
|
||||
var cacheIndex = entries.findIndex(function (entry) {
|
||||
return equals(key, entry.key);
|
||||
}); // We found a cached entry
|
||||
|
||||
if (cacheIndex > -1) {
|
||||
var 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, value) {
|
||||
if (get(key) === NOT_FOUND) {
|
||||
// TODO Is unshift slow?
|
||||
entries.unshift({
|
||||
key: key,
|
||||
value: value
|
||||
});
|
||||
|
||||
if (entries.length > maxSize) {
|
||||
entries.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
entries = [];
|
||||
}
|
||||
|
||||
return {
|
||||
get: get,
|
||||
put: put,
|
||||
getEntries: getEntries,
|
||||
clear: clear
|
||||
};
|
||||
}
|
||||
|
||||
var defaultEqualityCheck = function defaultEqualityCheck(a, b) {
|
||||
return a === b;
|
||||
};
|
||||
function createCacheKeyComparator(equalityCheck) {
|
||||
return function areArgumentsShallowlyEqual(prev, next) {
|
||||
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.
|
||||
|
||||
|
||||
var length = prev.length;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (!equalityCheck(prev[i], next[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
// defaultMemoize now supports a configurable cache size with LRU behavior,
|
||||
// and optional comparison of the result value with existing values
|
||||
function defaultMemoize(func, equalityCheckOrOptions) {
|
||||
var providedOptions = typeof equalityCheckOrOptions === 'object' ? equalityCheckOrOptions : {
|
||||
equalityCheck: equalityCheckOrOptions
|
||||
};
|
||||
var _providedOptions$equa = providedOptions.equalityCheck,
|
||||
equalityCheck = _providedOptions$equa === void 0 ? defaultEqualityCheck : _providedOptions$equa,
|
||||
_providedOptions$maxS = providedOptions.maxSize,
|
||||
maxSize = _providedOptions$maxS === void 0 ? 1 : _providedOptions$maxS,
|
||||
resultEqualityCheck = providedOptions.resultEqualityCheck;
|
||||
var comparator = createCacheKeyComparator(equalityCheck);
|
||||
var cache = maxSize === 1 ? createSingletonCache(comparator) : createLruCache(maxSize, comparator); // we reference arguments instead of spreading them for performance reasons
|
||||
|
||||
function memoized() {
|
||||
var value = cache.get(arguments);
|
||||
|
||||
if (value === NOT_FOUND) {
|
||||
// @ts-ignore
|
||||
value = func.apply(null, arguments);
|
||||
|
||||
if (resultEqualityCheck) {
|
||||
var entries = cache.getEntries();
|
||||
var matchingEntry = entries.find(function (entry) {
|
||||
return resultEqualityCheck(entry.value, value);
|
||||
});
|
||||
|
||||
if (matchingEntry) {
|
||||
value = matchingEntry.value;
|
||||
}
|
||||
}
|
||||
|
||||
cache.put(arguments, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
memoized.clearCache = function () {
|
||||
return cache.clear();
|
||||
};
|
||||
|
||||
return memoized;
|
||||
}
|
||||
|
||||
function getDependencies(funcs) {
|
||||
var dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs;
|
||||
|
||||
if (!dependencies.every(function (dep) {
|
||||
return typeof dep === 'function';
|
||||
})) {
|
||||
var dependencyTypes = dependencies.map(function (dep) {
|
||||
return typeof dep === 'function' ? "function " + (dep.name || 'unnamed') + "()" : typeof dep;
|
||||
}).join(', ');
|
||||
throw new Error("createSelector expects all input-selectors to be functions, but received the following types: [" + dependencyTypes + "]");
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
function createSelectorCreator(memoize) {
|
||||
for (var _len = arguments.length, memoizeOptionsFromArgs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
memoizeOptionsFromArgs[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
var createSelector = function createSelector() {
|
||||
for (var _len2 = arguments.length, funcs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
||||
funcs[_key2] = arguments[_key2];
|
||||
}
|
||||
|
||||
var _recomputations = 0;
|
||||
|
||||
var _lastResult; // Due to the intricacies of rest params, we can't do an optional arg after `...funcs`.
|
||||
// So, start by declaring the default value here.
|
||||
// (And yes, the words 'memoize' and 'options' appear too many times in this next sequence.)
|
||||
|
||||
|
||||
var directlyPassedOptions = {
|
||||
memoizeOptions: undefined
|
||||
}; // Normally, the result func or "output selector" is the last arg
|
||||
|
||||
var resultFunc = funcs.pop(); // 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 = funcs.pop();
|
||||
}
|
||||
|
||||
if (typeof resultFunc !== 'function') {
|
||||
throw new Error("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.
|
||||
|
||||
|
||||
var _directlyPassedOption = directlyPassedOptions,
|
||||
_directlyPassedOption2 = _directlyPassedOption.memoizeOptions,
|
||||
memoizeOptions = _directlyPassedOption2 === void 0 ? memoizeOptionsFromArgs : _directlyPassedOption2; // 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.
|
||||
|
||||
var finalMemoizeOptions = Array.isArray(memoizeOptions) ? memoizeOptions : [memoizeOptions];
|
||||
var dependencies = getDependencies(funcs);
|
||||
var memoizedResultFunc = memoize.apply(void 0, [function recomputationWrapper() {
|
||||
_recomputations++; // apply arguments instead of spreading for performance.
|
||||
|
||||
return resultFunc.apply(null, arguments);
|
||||
}].concat(finalMemoizeOptions)); // If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
|
||||
|
||||
var selector = memoize(function dependenciesChecker() {
|
||||
var params = [];
|
||||
var length = dependencies.length;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
// apply arguments instead of spreading and mutate a local list of params for performance.
|
||||
// @ts-ignore
|
||||
params.push(dependencies[i].apply(null, arguments));
|
||||
} // apply arguments instead of spreading for performance.
|
||||
|
||||
|
||||
_lastResult = memoizedResultFunc.apply(null, params);
|
||||
return _lastResult;
|
||||
});
|
||||
Object.assign(selector, {
|
||||
resultFunc: resultFunc,
|
||||
memoizedResultFunc: memoizedResultFunc,
|
||||
dependencies: dependencies,
|
||||
lastResult: function lastResult() {
|
||||
return _lastResult;
|
||||
},
|
||||
recomputations: function recomputations() {
|
||||
return _recomputations;
|
||||
},
|
||||
resetRecomputations: function resetRecomputations() {
|
||||
return _recomputations = 0;
|
||||
}
|
||||
});
|
||||
return selector;
|
||||
}; // @ts-ignore
|
||||
|
||||
|
||||
return createSelector;
|
||||
}
|
||||
var createSelector = /* #__PURE__ */createSelectorCreator(defaultMemoize);
|
||||
// Manual definition of state and output arguments
|
||||
var createStructuredSelector = function createStructuredSelector(selectors, selectorCreator) {
|
||||
if (selectorCreator === void 0) {
|
||||
selectorCreator = createSelector;
|
||||
}
|
||||
|
||||
if (typeof selectors !== 'object') {
|
||||
throw new Error('createStructuredSelector expects first argument to be an object ' + ("where each property is a selector, instead received a " + typeof selectors));
|
||||
}
|
||||
|
||||
var objectKeys = Object.keys(selectors);
|
||||
var resultSelector = selectorCreator( // @ts-ignore
|
||||
objectKeys.map(function (key) {
|
||||
return selectors[key];
|
||||
}), function () {
|
||||
for (var _len3 = arguments.length, values = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
||||
values[_key3] = arguments[_key3];
|
||||
}
|
||||
|
||||
return values.reduce(function (composition, value, index) {
|
||||
composition[objectKeys[index]] = value;
|
||||
return composition;
|
||||
}, {});
|
||||
});
|
||||
return resultSelector;
|
||||
};
|
||||
|
||||
exports.createSelector = createSelector;
|
||||
exports.createSelectorCreator = createSelectorCreator;
|
||||
exports.createStructuredSelector = createStructuredSelector;
|
||||
exports.defaultEqualityCheck = defaultEqualityCheck;
|
||||
exports.defaultMemoize = defaultMemoize;
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
}));
|
||||
1
node_modules/reselect/dist/reselect.min.js
generated
vendored
Normal file
1
node_modules/reselect/dist/reselect.min.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Reselect={})}(this,(function(e){"use strict";var t="NOT_FOUND";var n=function(e,t){return e===t};function r(e,r){var u,o,i="object"==typeof r?r:{equalityCheck:r},c=i.equalityCheck,f=i.maxSize,a=void 0===f?1:f,l=i.resultEqualityCheck,p=function(e){return function(t,n){if(null===t||null===n||t.length!==n.length)return!1;for(var r=t.length,u=0;r>u;u++)if(!e(t[u],n[u]))return!1;return!0}}(void 0===c?n:c),s=1===a?(u=p,{get:function(e){return o&&u(o.key,e)?o.value:t},put:function(e,t){o={key:e,value:t}},getEntries:function(){return o?[o]:[]},clear:function(){o=void 0}}):function(e,n){var r=[];function u(e){var u=r.findIndex((function(t){return n(e,t.key)}));if(u>-1){var o=r[u];return u>0&&(r.splice(u,1),r.unshift(o)),o.value}return t}return{get:u,put:function(n,o){u(n)===t&&(r.unshift({key:n,value:o}),r.length>e&&r.pop())},getEntries:function(){return r},clear:function(){r=[]}}}(a,p);function v(){var n=s.get(arguments);if(n===t){if(n=e.apply(null,arguments),l){var r=s.getEntries(),u=r.find((function(e){return l(e.value,n)}));u&&(n=u.value)}s.put(arguments,n)}return n}return v.clearCache=function(){return s.clear()},v}function u(e){var t=Array.isArray(e[0])?e[0]:e;if(!t.every((function(e){return"function"==typeof e}))){var n=t.map((function(e){return"function"==typeof e?"function "+(e.name||"unnamed")+"()":typeof e})).join(", ");throw Error("createSelector expects all input-selectors to be functions, but received the following types: ["+n+"]")}return t}function o(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;t>r;r++)n[r-1]=arguments[r];var o=function(){for(var t=arguments.length,r=Array(t),o=0;t>o;o++)r[o]=arguments[o];var i,c=0,f={memoizeOptions:void 0},a=r.pop();if("object"==typeof a&&(f=a,a=r.pop()),"function"!=typeof a)throw Error("createSelector expects an output function after the inputs, but received: ["+typeof a+"]");var l=f,p=l.memoizeOptions,s=void 0===p?n:p,v=Array.isArray(s)?s:[s],y=u(r),d=e.apply(void 0,[function(){return c++,a.apply(null,arguments)}].concat(v)),h=e((function(){for(var e=[],t=y.length,n=0;t>n;n++)e.push(y[n].apply(null,arguments));return i=d.apply(null,e)}));return Object.assign(h,{resultFunc:a,memoizedResultFunc:d,dependencies:y,lastResult:function(){return i},recomputations:function(){return c},resetRecomputations:function(){return c=0}}),h};return o}var i=o(r);e.createSelector=i,e.createSelectorCreator=o,e.createStructuredSelector=function(e,t){if(void 0===t&&(t=i),"object"!=typeof e)throw Error("createStructuredSelector expects first argument to be an object where each property is a selector, instead received a "+typeof e);var n=Object.keys(e),r=t(n.map((function(t){return e[t]})),(function(){for(var e=arguments.length,t=Array(e),r=0;e>r;r++)t[r]=arguments[r];return t.reduce((function(e,t,r){return e[n[r]]=t,e}),{})}));return r},e.defaultEqualityCheck=n,e.defaultMemoize=r,Object.defineProperty(e,"__esModule",{value:!0})}));
|
||||
11
node_modules/reselect/es/defaultMemoize.d.ts
generated
vendored
Normal file
11
node_modules/reselect/es/defaultMemoize.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { EqualityFn } from './types';
|
||||
export declare const defaultEqualityCheck: EqualityFn;
|
||||
export declare function createCacheKeyComparator(equalityCheck: EqualityFn): (prev: unknown[] | IArguments | null, next: unknown[] | IArguments | null) => boolean;
|
||||
export interface DefaultMemoizeOptions {
|
||||
equalityCheck?: EqualityFn;
|
||||
resultEqualityCheck?: EqualityFn;
|
||||
maxSize?: number;
|
||||
}
|
||||
export declare function defaultMemoize<F extends (...args: any[]) => any>(func: F, equalityCheckOrOptions?: EqualityFn | DefaultMemoizeOptions): F & {
|
||||
clearCache: () => void;
|
||||
};
|
||||
147
node_modules/reselect/es/defaultMemoize.js
generated
vendored
Normal file
147
node_modules/reselect/es/defaultMemoize.js
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
// Cache implementation based on Erik Rasmussen's `lru-memoize`:
|
||||
// https://github.com/erikras/lru-memoize
|
||||
var NOT_FOUND = 'NOT_FOUND';
|
||||
|
||||
function createSingletonCache(equals) {
|
||||
var entry;
|
||||
return {
|
||||
get: function get(key) {
|
||||
if (entry && equals(entry.key, key)) {
|
||||
return entry.value;
|
||||
}
|
||||
|
||||
return NOT_FOUND;
|
||||
},
|
||||
put: function put(key, value) {
|
||||
entry = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
},
|
||||
getEntries: function getEntries() {
|
||||
return entry ? [entry] : [];
|
||||
},
|
||||
clear: function clear() {
|
||||
entry = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createLruCache(maxSize, equals) {
|
||||
var entries = [];
|
||||
|
||||
function get(key) {
|
||||
var cacheIndex = entries.findIndex(function (entry) {
|
||||
return equals(key, entry.key);
|
||||
}); // We found a cached entry
|
||||
|
||||
if (cacheIndex > -1) {
|
||||
var 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, value) {
|
||||
if (get(key) === NOT_FOUND) {
|
||||
// TODO Is unshift slow?
|
||||
entries.unshift({
|
||||
key: key,
|
||||
value: value
|
||||
});
|
||||
|
||||
if (entries.length > maxSize) {
|
||||
entries.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
entries = [];
|
||||
}
|
||||
|
||||
return {
|
||||
get: get,
|
||||
put: put,
|
||||
getEntries: getEntries,
|
||||
clear: clear
|
||||
};
|
||||
}
|
||||
|
||||
export var defaultEqualityCheck = function defaultEqualityCheck(a, b) {
|
||||
return a === b;
|
||||
};
|
||||
export function createCacheKeyComparator(equalityCheck) {
|
||||
return function areArgumentsShallowlyEqual(prev, next) {
|
||||
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.
|
||||
|
||||
|
||||
var length = prev.length;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (!equalityCheck(prev[i], next[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
// defaultMemoize now supports a configurable cache size with LRU behavior,
|
||||
// and optional comparison of the result value with existing values
|
||||
export function defaultMemoize(func, equalityCheckOrOptions) {
|
||||
var providedOptions = typeof equalityCheckOrOptions === 'object' ? equalityCheckOrOptions : {
|
||||
equalityCheck: equalityCheckOrOptions
|
||||
};
|
||||
var _providedOptions$equa = providedOptions.equalityCheck,
|
||||
equalityCheck = _providedOptions$equa === void 0 ? defaultEqualityCheck : _providedOptions$equa,
|
||||
_providedOptions$maxS = providedOptions.maxSize,
|
||||
maxSize = _providedOptions$maxS === void 0 ? 1 : _providedOptions$maxS,
|
||||
resultEqualityCheck = providedOptions.resultEqualityCheck;
|
||||
var comparator = createCacheKeyComparator(equalityCheck);
|
||||
var cache = maxSize === 1 ? createSingletonCache(comparator) : createLruCache(maxSize, comparator); // we reference arguments instead of spreading them for performance reasons
|
||||
|
||||
function memoized() {
|
||||
var value = cache.get(arguments);
|
||||
|
||||
if (value === NOT_FOUND) {
|
||||
// @ts-ignore
|
||||
value = func.apply(null, arguments);
|
||||
|
||||
if (resultEqualityCheck) {
|
||||
var entries = cache.getEntries();
|
||||
var matchingEntry = entries.find(function (entry) {
|
||||
return resultEqualityCheck(entry.value, value);
|
||||
});
|
||||
|
||||
if (matchingEntry) {
|
||||
value = matchingEntry.value;
|
||||
}
|
||||
}
|
||||
|
||||
cache.put(arguments, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
memoized.clearCache = function () {
|
||||
return cache.clear();
|
||||
};
|
||||
|
||||
return memoized;
|
||||
}
|
||||
48
node_modules/reselect/es/index.d.ts
generated
vendored
Normal file
48
node_modules/reselect/es/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
import type { Selector, GetParamsFromSelectors, OutputSelector, SelectorArray, SelectorResultArray, DropFirst, MergeParameters, Expand, ObjValueTuple, Head, Tail } from './types';
|
||||
export type { Selector, GetParamsFromSelectors, GetStateFromSelectors, OutputSelector, EqualityFn, SelectorArray, SelectorResultArray, ParametricSelector, OutputParametricSelector, OutputSelectorFields } from './types';
|
||||
import { defaultMemoize, defaultEqualityCheck, DefaultMemoizeOptions } from './defaultMemoize';
|
||||
export { defaultMemoize, defaultEqualityCheck };
|
||||
export type { DefaultMemoizeOptions };
|
||||
export declare function createSelectorCreator<
|
||||
/** Selectors will eventually accept some function to be memoized */
|
||||
F extends (...args: unknown[]) => unknown,
|
||||
/** A memoizer such as defaultMemoize that accepts a function + some possible options */
|
||||
MemoizeFunction extends (func: F, ...options: any[]) => F,
|
||||
/** The additional options arguments to the memoizer */
|
||||
MemoizeOptions extends unknown[] = DropFirst<Parameters<MemoizeFunction>>>(memoize: MemoizeFunction, ...memoizeOptionsFromArgs: DropFirst<Parameters<MemoizeFunction>>): CreateSelectorFunction<F, MemoizeFunction, MemoizeOptions, Expand<Pick<ReturnType<MemoizeFunction>, keyof ReturnType<MemoizeFunction>>>>;
|
||||
export interface CreateSelectorOptions<MemoizeOptions extends unknown[]> {
|
||||
memoizeOptions: MemoizeOptions[0] | MemoizeOptions;
|
||||
}
|
||||
/**
|
||||
* An instance of createSelector, customized with a given memoize implementation
|
||||
*/
|
||||
export interface CreateSelectorFunction<F extends (...args: unknown[]) => unknown, MemoizeFunction extends (func: F, ...options: any[]) => F, MemoizeOptions extends unknown[] = DropFirst<Parameters<MemoizeFunction>>, Keys = Expand<Pick<ReturnType<MemoizeFunction>, keyof ReturnType<MemoizeFunction>>>> {
|
||||
/** Input selectors as separate inline arguments */
|
||||
<Selectors extends SelectorArray, Result>(...items: [
|
||||
...Selectors,
|
||||
(...args: SelectorResultArray<Selectors>) => Result
|
||||
]): OutputSelector<Selectors, Result, (...args: SelectorResultArray<Selectors>) => Result, GetParamsFromSelectors<Selectors>, Keys> & Keys;
|
||||
/** Input selectors as separate inline arguments with memoizeOptions passed */
|
||||
<Selectors extends SelectorArray, Result>(...items: [
|
||||
...Selectors,
|
||||
(...args: SelectorResultArray<Selectors>) => Result,
|
||||
CreateSelectorOptions<MemoizeOptions>
|
||||
]): OutputSelector<Selectors, Result, ((...args: SelectorResultArray<Selectors>) => Result), GetParamsFromSelectors<Selectors>, Keys> & Keys;
|
||||
/** Input selectors as a separate array */
|
||||
<Selectors extends SelectorArray, Result>(selectors: [...Selectors], combiner: (...args: SelectorResultArray<Selectors>) => Result, options?: CreateSelectorOptions<MemoizeOptions>): OutputSelector<Selectors, Result, (...args: SelectorResultArray<Selectors>) => Result, GetParamsFromSelectors<Selectors>, Keys> & Keys;
|
||||
}
|
||||
export declare const createSelector: CreateSelectorFunction<(...args: unknown[]) => unknown, typeof defaultMemoize, [equalityCheckOrOptions?: import("./types").EqualityFn | DefaultMemoizeOptions | undefined], {
|
||||
clearCache: () => void;
|
||||
}>;
|
||||
type SelectorsObject = {
|
||||
[key: string]: (...args: any[]) => any;
|
||||
};
|
||||
export interface StructuredSelectorCreator {
|
||||
<SelectorMap extends SelectorsObject, SelectorParams = MergeParameters<ObjValueTuple<SelectorMap>>>(selectorMap: SelectorMap, selectorCreator?: CreateSelectorFunction<any, any, any>): (state: Head<SelectorParams>, ...params: Tail<SelectorParams>) => {
|
||||
[Key in keyof SelectorMap]: ReturnType<SelectorMap[Key]>;
|
||||
};
|
||||
<State, Result = State>(selectors: {
|
||||
[K in keyof Result]: Selector<State, Result[K], never>;
|
||||
}, selectorCreator?: CreateSelectorFunction<any, any, any>): Selector<State, Result, never>;
|
||||
}
|
||||
export declare const createStructuredSelector: StructuredSelectorCreator;
|
||||
130
node_modules/reselect/es/index.js
generated
vendored
Normal file
130
node_modules/reselect/es/index.js
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
import { defaultMemoize, defaultEqualityCheck } from './defaultMemoize';
|
||||
export { defaultMemoize, defaultEqualityCheck };
|
||||
|
||||
function getDependencies(funcs) {
|
||||
var dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs;
|
||||
|
||||
if (!dependencies.every(function (dep) {
|
||||
return typeof dep === 'function';
|
||||
})) {
|
||||
var dependencyTypes = dependencies.map(function (dep) {
|
||||
return typeof dep === 'function' ? "function " + (dep.name || 'unnamed') + "()" : typeof dep;
|
||||
}).join(', ');
|
||||
throw new Error("createSelector expects all input-selectors to be functions, but received the following types: [" + dependencyTypes + "]");
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
export function createSelectorCreator(memoize) {
|
||||
for (var _len = arguments.length, memoizeOptionsFromArgs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
memoizeOptionsFromArgs[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
var createSelector = function createSelector() {
|
||||
for (var _len2 = arguments.length, funcs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
||||
funcs[_key2] = arguments[_key2];
|
||||
}
|
||||
|
||||
var _recomputations = 0;
|
||||
|
||||
var _lastResult; // Due to the intricacies of rest params, we can't do an optional arg after `...funcs`.
|
||||
// So, start by declaring the default value here.
|
||||
// (And yes, the words 'memoize' and 'options' appear too many times in this next sequence.)
|
||||
|
||||
|
||||
var directlyPassedOptions = {
|
||||
memoizeOptions: undefined
|
||||
}; // Normally, the result func or "output selector" is the last arg
|
||||
|
||||
var resultFunc = funcs.pop(); // 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 = funcs.pop();
|
||||
}
|
||||
|
||||
if (typeof resultFunc !== 'function') {
|
||||
throw new Error("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.
|
||||
|
||||
|
||||
var _directlyPassedOption = directlyPassedOptions,
|
||||
_directlyPassedOption2 = _directlyPassedOption.memoizeOptions,
|
||||
memoizeOptions = _directlyPassedOption2 === void 0 ? memoizeOptionsFromArgs : _directlyPassedOption2; // 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.
|
||||
|
||||
var finalMemoizeOptions = Array.isArray(memoizeOptions) ? memoizeOptions : [memoizeOptions];
|
||||
var dependencies = getDependencies(funcs);
|
||||
var memoizedResultFunc = memoize.apply(void 0, [function recomputationWrapper() {
|
||||
_recomputations++; // apply arguments instead of spreading for performance.
|
||||
|
||||
return resultFunc.apply(null, arguments);
|
||||
}].concat(finalMemoizeOptions)); // If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
|
||||
|
||||
var selector = memoize(function dependenciesChecker() {
|
||||
var params = [];
|
||||
var length = dependencies.length;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
// apply arguments instead of spreading and mutate a local list of params for performance.
|
||||
// @ts-ignore
|
||||
params.push(dependencies[i].apply(null, arguments));
|
||||
} // apply arguments instead of spreading for performance.
|
||||
|
||||
|
||||
_lastResult = memoizedResultFunc.apply(null, params);
|
||||
return _lastResult;
|
||||
});
|
||||
Object.assign(selector, {
|
||||
resultFunc: resultFunc,
|
||||
memoizedResultFunc: memoizedResultFunc,
|
||||
dependencies: dependencies,
|
||||
lastResult: function lastResult() {
|
||||
return _lastResult;
|
||||
},
|
||||
recomputations: function recomputations() {
|
||||
return _recomputations;
|
||||
},
|
||||
resetRecomputations: function resetRecomputations() {
|
||||
return _recomputations = 0;
|
||||
}
|
||||
});
|
||||
return selector;
|
||||
}; // @ts-ignore
|
||||
|
||||
|
||||
return createSelector;
|
||||
}
|
||||
export var createSelector = /* #__PURE__ */createSelectorCreator(defaultMemoize);
|
||||
// Manual definition of state and output arguments
|
||||
export var createStructuredSelector = function createStructuredSelector(selectors, selectorCreator) {
|
||||
if (selectorCreator === void 0) {
|
||||
selectorCreator = createSelector;
|
||||
}
|
||||
|
||||
if (typeof selectors !== 'object') {
|
||||
throw new Error('createStructuredSelector expects first argument to be an object ' + ("where each property is a selector, instead received a " + typeof selectors));
|
||||
}
|
||||
|
||||
var objectKeys = Object.keys(selectors);
|
||||
var resultSelector = selectorCreator( // @ts-ignore
|
||||
objectKeys.map(function (key) {
|
||||
return selectors[key];
|
||||
}), function () {
|
||||
for (var _len3 = arguments.length, values = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
||||
values[_key3] = arguments[_key3];
|
||||
}
|
||||
|
||||
return values.reduce(function (composition, value, index) {
|
||||
composition[objectKeys[index]] = value;
|
||||
return composition;
|
||||
}, {});
|
||||
});
|
||||
return resultSelector;
|
||||
};
|
||||
142
node_modules/reselect/es/types.d.ts
generated
vendored
Normal file
142
node_modules/reselect/es/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
import type { MergeParameters } from './versionedTypes';
|
||||
export type { MergeParameters } from './versionedTypes';
|
||||
/** A standard selector function, which takes three generic type arguments:
|
||||
* @param State The first value, often a Redux root state object
|
||||
* @param Result The final result returned by the selector
|
||||
* @param Params All additional arguments passed into the selector
|
||||
*/
|
||||
export type Selector<State = any, Result = unknown, Params extends never | readonly any[] = any[]> = [Params] extends [never] ? (state: State) => Result : (state: State, ...params: Params) => Result;
|
||||
/** Selectors generated by Reselect have several additional fields attached: */
|
||||
export interface OutputSelectorFields<Combiner extends UnknownFunction, Keys> {
|
||||
/** The final function passed to `createSelector` */
|
||||
resultFunc: Combiner;
|
||||
/** The same function, memoized */
|
||||
memoizedResultFunc: Combiner & Keys;
|
||||
/** Returns the last result calculated by the selector */
|
||||
lastResult: () => ReturnType<Combiner>;
|
||||
/** An array of the input selectors */
|
||||
dependencies: SelectorArray;
|
||||
/** Counts the number of times the output has been recalculated */
|
||||
recomputations: () => number;
|
||||
/** Resets the count of recomputations count to 0 */
|
||||
resetRecomputations: () => number;
|
||||
}
|
||||
/** Represents the actual selectors generated by `createSelector`.
|
||||
* The selector is:
|
||||
* - "a function that takes this state + params and returns a result"
|
||||
* - plus the attached additional fields
|
||||
*/
|
||||
export type OutputSelector<S extends SelectorArray, Result, Combiner extends UnknownFunction, Params extends readonly any[] = never, // MergeParameters<S>
|
||||
Keys = {}> = Selector<GetStateFromSelectors<S>, Result, Params> & OutputSelectorFields<Combiner, Keys>;
|
||||
/** A selector that is assumed to have one additional argument, such as
|
||||
* the props from a React component
|
||||
*/
|
||||
export type ParametricSelector<State, Props, Result> = Selector<State, Result, [
|
||||
Props,
|
||||
...any
|
||||
]>;
|
||||
/** A generated selector that is assumed to have one additional argument */
|
||||
export type OutputParametricSelector<State, Props, Result, Combiner extends UnknownFunction, Keys = {}> = ParametricSelector<State, Props, Result> & OutputSelectorFields<Combiner, Keys>;
|
||||
/** An array of input selectors */
|
||||
export type SelectorArray = ReadonlyArray<Selector>;
|
||||
/** A standard function returning true if two values are considered equal */
|
||||
export type EqualityFn = (a: any, b: any) => boolean;
|
||||
/** Extracts an array of all return types from all input selectors */
|
||||
export type SelectorResultArray<Selectors extends SelectorArray> = ExtractReturnType<Selectors>;
|
||||
/** Determines the combined single "State" type (first arg) from all input selectors */
|
||||
export type GetStateFromSelectors<S extends SelectorArray> = MergeParameters<S>[0];
|
||||
/** Determines the combined "Params" type (all remaining args) from all input selectors */
|
||||
export type GetParamsFromSelectors<S extends SelectorArray, RemainingItems extends readonly unknown[] = Tail<MergeParameters<S>>> = RemainingItems;
|
||||
/** Any function with arguments */
|
||||
export type UnknownFunction = (...args: any[]) => any;
|
||||
/** Extract the return type from all functions as a tuple */
|
||||
export type ExtractReturnType<T extends readonly UnknownFunction[]> = {
|
||||
[index in keyof T]: T[index] extends T[number] ? ReturnType<T[index]> : never;
|
||||
};
|
||||
/** First item in an array */
|
||||
export type Head<T> = T extends [any, ...any[]] ? T[0] : never;
|
||||
/** All other items in an array */
|
||||
export type Tail<A> = A extends [any, ...infer Rest] ? Rest : never;
|
||||
/** Last item in an array. Recursion also enables this to work with rest syntax - where the type of rest is extracted */
|
||||
export type ReverseHead<S extends readonly unknown[][]> = Tail<S> extends [
|
||||
unknown
|
||||
] ? S : Tail<S> extends readonly unknown[][] ? ReverseHead<Tail<S>> : never;
|
||||
/** All elements in array except last
|
||||
*
|
||||
* Recursion makes this work also when rest syntax has been used
|
||||
* Runs _ReverseTail twice, because first pass turns last element into "never", and second pass removes it.
|
||||
**/
|
||||
export type ReverseTail<S> = _ReverseTail<_ReverseTail<S>>;
|
||||
type _ReverseTail<S> = Tail<S> extends [unknown] ? [Head<S>] : Tail<S> extends unknown[] ? [Head<S>, ..._ReverseTail<Tail<S>>] : never;
|
||||
/** Extract only numeric keys from an array type */
|
||||
export type AllArrayKeys<A extends readonly any[]> = A extends any ? {
|
||||
[K in keyof A]: K;
|
||||
}[number] : never;
|
||||
export type List<A = any> = ReadonlyArray<A>;
|
||||
export type Has<U, U1> = [U1] extends [U] ? 1 : 0;
|
||||
/** The infamous "convert a union type to an intersection type" hack
|
||||
* Source: https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts
|
||||
* Reference: https://github.com/microsoft/TypeScript/issues/29594
|
||||
*/
|
||||
export type UnionToIntersection<Union> = (Union extends unknown ? (distributedUnion: Union) => void : never) extends (mergedIntersection: infer Intersection) => void ? Intersection : never;
|
||||
/**
|
||||
* Assorted util types for type-level conditional logic
|
||||
* Source: https://github.com/KiaraGrouwstra/typical
|
||||
*/
|
||||
export type Bool = '0' | '1';
|
||||
export type Obj<T> = {
|
||||
[k: string]: T;
|
||||
};
|
||||
export type And<A extends Bool, B extends Bool> = ({
|
||||
1: {
|
||||
1: '1';
|
||||
} & Obj<'0'>;
|
||||
} & Obj<Obj<'0'>>)[A][B];
|
||||
export type Matches<V, T> = V extends T ? '1' : '0';
|
||||
export type IsArrayType<T> = Matches<T, any[]>;
|
||||
export type Not<T extends Bool> = {
|
||||
'1': '0';
|
||||
'0': '1';
|
||||
}[T];
|
||||
export type InstanceOf<V, T> = And<Matches<V, T>, Not<Matches<T, V>>>;
|
||||
export type IsTuple<T extends {
|
||||
length: number;
|
||||
}> = And<IsArrayType<T>, InstanceOf<T['length'], number>>;
|
||||
/**
|
||||
* Code to convert a union of values into a tuple.
|
||||
* Source: https://stackoverflow.com/a/55128956/62937
|
||||
*/
|
||||
type Push<T extends any[], V> = [...T, V];
|
||||
type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R : never;
|
||||
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()`
|
||||
* Source: https://stackoverflow.com/a/68695508/62937
|
||||
*/
|
||||
export type ObjValueTuple<T, KS extends any[] = TuplifyUnion<keyof T>, R extends any[] = []> = KS extends [infer K, ...infer KT] ? ObjValueTuple<T, KT, [...R, T[K & keyof T]]> : R;
|
||||
/** 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 */
|
||||
export type DropFirst<T extends unknown[]> = T extends [unknown, ...infer U] ? U : never;
|
||||
/**
|
||||
* Expand an item a single level, or recursively.
|
||||
* Source: https://stackoverflow.com/a/69288824/62937
|
||||
*/
|
||||
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;
|
||||
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;
|
||||
type Identity<T> = T;
|
||||
/**
|
||||
* Another form of type value expansion
|
||||
* Source: https://github.com/microsoft/TypeScript/issues/35247
|
||||
*/
|
||||
export type Mapped<T> = Identity<{
|
||||
[k in keyof T]: T[k];
|
||||
}>;
|
||||
export type If2<B extends Boolean2, Then, Else = never> = B extends 1 ? Then : Else;
|
||||
export type Boolean2 = 0 | 1;
|
||||
export type Key = string | number | symbol;
|
||||
export type BuiltIn = Function | Error | Date | {
|
||||
readonly [Symbol.toStringTag]: string;
|
||||
} | RegExp | Generator;
|
||||
1
node_modules/reselect/es/versionedTypes/index.d.ts
generated
vendored
Normal file
1
node_modules/reselect/es/versionedTypes/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { MergeParameters } from './ts47-mergeParameters';
|
||||
14
node_modules/reselect/es/versionedTypes/package.json
generated
vendored
Normal file
14
node_modules/reselect/es/versionedTypes/package.json
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"typesVersions": {
|
||||
">=4.7": {
|
||||
"index": [
|
||||
"./ts47-mergeParameters.d.ts"
|
||||
]
|
||||
},
|
||||
"<4.7": {
|
||||
"index": [
|
||||
"./ts46-mergeParameters.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
61
node_modules/reselect/es/versionedTypes/ts46-mergeParameters.d.ts
generated
vendored
Normal file
61
node_modules/reselect/es/versionedTypes/ts46-mergeParameters.d.ts
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
import type { UnknownFunction, Expand, TuplifyUnion, Has, List, IsTuple } from '../types';
|
||||
/** Given a set of input selectors, extracts the intersected parameters to determine
|
||||
* what values can actually be passed to all of the input selectors at once
|
||||
* WARNING: "you are not expected to understand this" :)
|
||||
*/
|
||||
export type MergeParameters<T extends readonly UnknownFunction[], ParamsArrays extends readonly any[][] = ExtractParams<T>, TransposedArrays = Transpose<ParamsArrays>, TuplifiedArrays extends any[] = TuplifyUnion<TransposedArrays>, LongestParamsArray extends readonly any[] = LongestArray<TuplifiedArrays>> = ExpandItems<RemoveNames<{
|
||||
[index in keyof LongestParamsArray]: LongestParamsArray[index] extends LongestParamsArray[number] ? IgnoreInvalidIntersections<IntersectAll<LongestParamsArray[index]>> : never;
|
||||
}>>;
|
||||
/** An object with no fields */
|
||||
type EmptyObject = {
|
||||
[K in any]: never;
|
||||
};
|
||||
type IgnoreInvalidIntersections<T> = T extends EmptyObject ? never : T;
|
||||
/** Extract the parameters from all functions as a tuple */
|
||||
export type ExtractParams<T extends readonly UnknownFunction[]> = {
|
||||
[index in keyof T]: T[index] extends T[number] ? Parameters<T[index]> : never;
|
||||
};
|
||||
/** Recursively expand all fields in an object for easier reading */
|
||||
export type ExpandItems<T extends readonly unknown[]> = {
|
||||
[index in keyof T]: T[index] extends T[number] ? Expand<T[index]> : never;
|
||||
};
|
||||
/** Select the longer of two arrays */
|
||||
export type Longest<L extends List, L1 extends List> = L extends unknown ? L1 extends unknown ? {
|
||||
0: L1;
|
||||
1: L;
|
||||
}[Has<keyof L, keyof L1>] : never : never;
|
||||
/** Recurse over a nested array to locate the longest one.
|
||||
* Acts like a type-level `reduce()`
|
||||
*/
|
||||
export type LongestArray<S extends readonly any[][]> = IsTuple<S> extends '0' ? S[0] : S extends [any[], any[]] ? Longest<S[0], S[1]> : S extends [any[], any[], ...infer Rest] ? Longest<Longest<S[0], S[1]>, Rest extends any[][] ? LongestArray<Rest> : []> : S extends [any[]] ? S[0] : never;
|
||||
/** Recursive type for intersecting together all items in a tuple, to determine
|
||||
* the final parameter type at a given argument index in the generated selector. */
|
||||
export type IntersectAll<T extends any[]> = IsTuple<T> extends '0' ? T[0] : _IntersectAll<T>;
|
||||
type IfJustNullish<T, True, False> = [T] extends [undefined | null] ? True : False;
|
||||
/** Intersect a pair of types together, for use in parameter type calculation.
|
||||
* This is made much more complex because we need to correctly handle cases
|
||||
* where a function has fewer parameters and the type is `undefined`, as well as
|
||||
* optional params or params that have `null` or `undefined` as part of a union.
|
||||
*
|
||||
* If the next type by itself is `null` or `undefined`, we exclude it and return
|
||||
* the other type. Otherwise, intersect them together.
|
||||
*/
|
||||
type _IntersectAll<T, R = unknown> = T extends [infer First, ...infer Rest] ? _IntersectAll<Rest, IfJustNullish<First, R, R & First>> : R;
|
||||
/**
|
||||
* Removes field names from a tuple
|
||||
* Source: https://stackoverflow.com/a/63571175/62937
|
||||
*/
|
||||
type RemoveNames<T extends readonly any[]> = [any, ...T] extends [
|
||||
any,
|
||||
...infer U
|
||||
] ? U : never;
|
||||
/**
|
||||
* Transposes nested arrays
|
||||
* Source: https://stackoverflow.com/a/66303933/62937
|
||||
*/
|
||||
type Transpose<T> = T[Extract<keyof T, T extends readonly any[] ? number : unknown>] extends infer V ? {
|
||||
[K in keyof V]: {
|
||||
[L in keyof T]: K extends keyof T[L] ? T[L][K] : undefined;
|
||||
};
|
||||
} : never;
|
||||
export {};
|
||||
24
node_modules/reselect/es/versionedTypes/ts47-mergeParameters.d.ts
generated
vendored
Normal file
24
node_modules/reselect/es/versionedTypes/ts47-mergeParameters.d.ts
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
import { ReverseHead, ReverseTail } from '../types';
|
||||
type UnknownFunction = (...args: any[]) => any;
|
||||
type LongestTuple<T> = T extends [infer U extends unknown[]] ? U : T extends [infer U, ...infer R extends unknown[][]] ? MostProperties<U, LongestTuple<R>> : never;
|
||||
type MostProperties<T, U> = keyof U extends keyof T ? T : U;
|
||||
type ElementAt<T, N extends keyof any> = N extends keyof T ? T[N] : unknown;
|
||||
type ElementsAt<T, N extends keyof any> = {
|
||||
[K in keyof T]: ElementAt<T[K], N>;
|
||||
};
|
||||
type Intersect<T extends readonly unknown[]> = T extends [] ? unknown : T extends [infer H, ...infer T] ? H & Intersect<T> : T[number];
|
||||
type MergeTuples<T, L extends unknown[] = LongestTuple<T>> = {
|
||||
[K in keyof L]: Intersect<ElementsAt<T, K> extends readonly unknown[] ? ElementsAt<T, K> : never>;
|
||||
};
|
||||
type ExtractParameters<T extends readonly UnknownFunction[]> = {
|
||||
[K in keyof T]: Parameters<T[K]>;
|
||||
};
|
||||
export type MergeParameters<T extends readonly UnknownFunction[]> = '0' extends keyof T ? MergeTuples<MakeRestExplicit<ExtractParameters<T>>> : Parameters<T[number]>;
|
||||
type HasRest<S extends readonly unknown[]> = number extends S['length'] ? true : false;
|
||||
type HasExplicit<S extends readonly unknown[]> = '0' extends keyof S ? true : false;
|
||||
type HasCombined<S extends readonly unknown[]> = true extends HasExplicit<S> & HasRest<S> ? true : false;
|
||||
type MakeRestExplicit<T extends readonly unknown[][]> = true extends HasCombined<T> ? [
|
||||
...ReverseTail<T>,
|
||||
ReverseHead<T> extends readonly unknown[] ? ReverseHead<T>[number] : never
|
||||
] : true extends HasRest<T> ? [...T] : T;
|
||||
export {};
|
||||
159
node_modules/reselect/lib/defaultMemoize.js
generated
vendored
Normal file
159
node_modules/reselect/lib/defaultMemoize.js
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.createCacheKeyComparator = createCacheKeyComparator;
|
||||
exports.defaultEqualityCheck = void 0;
|
||||
exports.defaultMemoize = defaultMemoize;
|
||||
// Cache implementation based on Erik Rasmussen's `lru-memoize`:
|
||||
// https://github.com/erikras/lru-memoize
|
||||
var NOT_FOUND = 'NOT_FOUND';
|
||||
|
||||
function createSingletonCache(equals) {
|
||||
var entry;
|
||||
return {
|
||||
get: function get(key) {
|
||||
if (entry && equals(entry.key, key)) {
|
||||
return entry.value;
|
||||
}
|
||||
|
||||
return NOT_FOUND;
|
||||
},
|
||||
put: function put(key, value) {
|
||||
entry = {
|
||||
key: key,
|
||||
value: value
|
||||
};
|
||||
},
|
||||
getEntries: function getEntries() {
|
||||
return entry ? [entry] : [];
|
||||
},
|
||||
clear: function clear() {
|
||||
entry = undefined;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createLruCache(maxSize, equals) {
|
||||
var entries = [];
|
||||
|
||||
function get(key) {
|
||||
var cacheIndex = entries.findIndex(function (entry) {
|
||||
return equals(key, entry.key);
|
||||
}); // We found a cached entry
|
||||
|
||||
if (cacheIndex > -1) {
|
||||
var 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, value) {
|
||||
if (get(key) === NOT_FOUND) {
|
||||
// TODO Is unshift slow?
|
||||
entries.unshift({
|
||||
key: key,
|
||||
value: value
|
||||
});
|
||||
|
||||
if (entries.length > maxSize) {
|
||||
entries.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
entries = [];
|
||||
}
|
||||
|
||||
return {
|
||||
get: get,
|
||||
put: put,
|
||||
getEntries: getEntries,
|
||||
clear: clear
|
||||
};
|
||||
}
|
||||
|
||||
var defaultEqualityCheck = function defaultEqualityCheck(a, b) {
|
||||
return a === b;
|
||||
};
|
||||
|
||||
exports.defaultEqualityCheck = defaultEqualityCheck;
|
||||
|
||||
function createCacheKeyComparator(equalityCheck) {
|
||||
return function areArgumentsShallowlyEqual(prev, next) {
|
||||
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.
|
||||
|
||||
|
||||
var length = prev.length;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
if (!equalityCheck(prev[i], next[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
// defaultMemoize now supports a configurable cache size with LRU behavior,
|
||||
// and optional comparison of the result value with existing values
|
||||
function defaultMemoize(func, equalityCheckOrOptions) {
|
||||
var providedOptions = typeof equalityCheckOrOptions === 'object' ? equalityCheckOrOptions : {
|
||||
equalityCheck: equalityCheckOrOptions
|
||||
};
|
||||
var _providedOptions$equa = providedOptions.equalityCheck,
|
||||
equalityCheck = _providedOptions$equa === void 0 ? defaultEqualityCheck : _providedOptions$equa,
|
||||
_providedOptions$maxS = providedOptions.maxSize,
|
||||
maxSize = _providedOptions$maxS === void 0 ? 1 : _providedOptions$maxS,
|
||||
resultEqualityCheck = providedOptions.resultEqualityCheck;
|
||||
var comparator = createCacheKeyComparator(equalityCheck);
|
||||
var cache = maxSize === 1 ? createSingletonCache(comparator) : createLruCache(maxSize, comparator); // we reference arguments instead of spreading them for performance reasons
|
||||
|
||||
function memoized() {
|
||||
var value = cache.get(arguments);
|
||||
|
||||
if (value === NOT_FOUND) {
|
||||
// @ts-ignore
|
||||
value = func.apply(null, arguments);
|
||||
|
||||
if (resultEqualityCheck) {
|
||||
var entries = cache.getEntries();
|
||||
var matchingEntry = entries.find(function (entry) {
|
||||
return resultEqualityCheck(entry.value, value);
|
||||
});
|
||||
|
||||
if (matchingEntry) {
|
||||
value = matchingEntry.value;
|
||||
}
|
||||
}
|
||||
|
||||
cache.put(arguments, value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
memoized.clearCache = function () {
|
||||
return cache.clear();
|
||||
};
|
||||
|
||||
return memoized;
|
||||
}
|
||||
155
node_modules/reselect/lib/index.js
generated
vendored
Normal file
155
node_modules/reselect/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,155 @@
|
||||
"use strict";
|
||||
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.createSelector = void 0;
|
||||
exports.createSelectorCreator = createSelectorCreator;
|
||||
exports.createStructuredSelector = void 0;
|
||||
Object.defineProperty(exports, "defaultEqualityCheck", {
|
||||
enumerable: true,
|
||||
get: function get() {
|
||||
return _defaultMemoize.defaultEqualityCheck;
|
||||
}
|
||||
});
|
||||
Object.defineProperty(exports, "defaultMemoize", {
|
||||
enumerable: true,
|
||||
get: function get() {
|
||||
return _defaultMemoize.defaultMemoize;
|
||||
}
|
||||
});
|
||||
|
||||
var _defaultMemoize = require("./defaultMemoize");
|
||||
|
||||
function getDependencies(funcs) {
|
||||
var dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs;
|
||||
|
||||
if (!dependencies.every(function (dep) {
|
||||
return typeof dep === 'function';
|
||||
})) {
|
||||
var dependencyTypes = dependencies.map(function (dep) {
|
||||
return typeof dep === 'function' ? "function " + (dep.name || 'unnamed') + "()" : typeof dep;
|
||||
}).join(', ');
|
||||
throw new Error("createSelector expects all input-selectors to be functions, but received the following types: [" + dependencyTypes + "]");
|
||||
}
|
||||
|
||||
return dependencies;
|
||||
}
|
||||
|
||||
function createSelectorCreator(memoize) {
|
||||
for (var _len = arguments.length, memoizeOptionsFromArgs = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
memoizeOptionsFromArgs[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
var createSelector = function createSelector() {
|
||||
for (var _len2 = arguments.length, funcs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
||||
funcs[_key2] = arguments[_key2];
|
||||
}
|
||||
|
||||
var _recomputations = 0;
|
||||
|
||||
var _lastResult; // Due to the intricacies of rest params, we can't do an optional arg after `...funcs`.
|
||||
// So, start by declaring the default value here.
|
||||
// (And yes, the words 'memoize' and 'options' appear too many times in this next sequence.)
|
||||
|
||||
|
||||
var directlyPassedOptions = {
|
||||
memoizeOptions: undefined
|
||||
}; // Normally, the result func or "output selector" is the last arg
|
||||
|
||||
var resultFunc = funcs.pop(); // 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 = funcs.pop();
|
||||
}
|
||||
|
||||
if (typeof resultFunc !== 'function') {
|
||||
throw new Error("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.
|
||||
|
||||
|
||||
var _directlyPassedOption = directlyPassedOptions,
|
||||
_directlyPassedOption2 = _directlyPassedOption.memoizeOptions,
|
||||
memoizeOptions = _directlyPassedOption2 === void 0 ? memoizeOptionsFromArgs : _directlyPassedOption2; // 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.
|
||||
|
||||
var finalMemoizeOptions = Array.isArray(memoizeOptions) ? memoizeOptions : [memoizeOptions];
|
||||
var dependencies = getDependencies(funcs);
|
||||
var memoizedResultFunc = memoize.apply(void 0, [function recomputationWrapper() {
|
||||
_recomputations++; // apply arguments instead of spreading for performance.
|
||||
|
||||
return resultFunc.apply(null, arguments);
|
||||
}].concat(finalMemoizeOptions)); // If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
|
||||
|
||||
var selector = memoize(function dependenciesChecker() {
|
||||
var params = [];
|
||||
var length = dependencies.length;
|
||||
|
||||
for (var i = 0; i < length; i++) {
|
||||
// apply arguments instead of spreading and mutate a local list of params for performance.
|
||||
// @ts-ignore
|
||||
params.push(dependencies[i].apply(null, arguments));
|
||||
} // apply arguments instead of spreading for performance.
|
||||
|
||||
|
||||
_lastResult = memoizedResultFunc.apply(null, params);
|
||||
return _lastResult;
|
||||
});
|
||||
Object.assign(selector, {
|
||||
resultFunc: resultFunc,
|
||||
memoizedResultFunc: memoizedResultFunc,
|
||||
dependencies: dependencies,
|
||||
lastResult: function lastResult() {
|
||||
return _lastResult;
|
||||
},
|
||||
recomputations: function recomputations() {
|
||||
return _recomputations;
|
||||
},
|
||||
resetRecomputations: function resetRecomputations() {
|
||||
return _recomputations = 0;
|
||||
}
|
||||
});
|
||||
return selector;
|
||||
}; // @ts-ignore
|
||||
|
||||
|
||||
return createSelector;
|
||||
}
|
||||
|
||||
var createSelector = /* #__PURE__ */createSelectorCreator(_defaultMemoize.defaultMemoize);
|
||||
exports.createSelector = createSelector;
|
||||
|
||||
// Manual definition of state and output arguments
|
||||
var createStructuredSelector = function createStructuredSelector(selectors, selectorCreator) {
|
||||
if (selectorCreator === void 0) {
|
||||
selectorCreator = createSelector;
|
||||
}
|
||||
|
||||
if (typeof selectors !== 'object') {
|
||||
throw new Error('createStructuredSelector expects first argument to be an object ' + ("where each property is a selector, instead received a " + typeof selectors));
|
||||
}
|
||||
|
||||
var objectKeys = Object.keys(selectors);
|
||||
var resultSelector = selectorCreator( // @ts-ignore
|
||||
objectKeys.map(function (key) {
|
||||
return selectors[key];
|
||||
}), function () {
|
||||
for (var _len3 = arguments.length, values = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
|
||||
values[_key3] = arguments[_key3];
|
||||
}
|
||||
|
||||
return values.reduce(function (composition, value, index) {
|
||||
composition[objectKeys[index]] = value;
|
||||
return composition;
|
||||
}, {});
|
||||
});
|
||||
return resultSelector;
|
||||
};
|
||||
|
||||
exports.createStructuredSelector = createStructuredSelector;
|
||||
94
node_modules/reselect/package.json
generated
vendored
Normal file
94
node_modules/reselect/package.json
generated
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
{
|
||||
"name": "reselect",
|
||||
"version": "4.1.8",
|
||||
"description": "Selectors for Redux.",
|
||||
"main": "./lib/index.js",
|
||||
"jsnext:main": "./es/index.js",
|
||||
"module": "./es/index.js",
|
||||
"types": "./es/index.d.ts",
|
||||
"unpkg": "./dist/reselect.js",
|
||||
"typesVersions": {
|
||||
"<4.2": {
|
||||
"*": [
|
||||
"./src/legacyTypes/ts4.1/index.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"lib",
|
||||
"src",
|
||||
"dist",
|
||||
"es"
|
||||
],
|
||||
"sideEffects": false,
|
||||
"bugs": {
|
||||
"url": "https://github.com/reduxjs/reselect/issues"
|
||||
},
|
||||
"scripts": {
|
||||
"build:commonjs": "cross-env BABEL_ENV=commonjs babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir lib ",
|
||||
"build:es": "babel src/*.ts --ignore src/types.ts --extensions .ts --out-dir es && cp src/versionedTypes/package.dist.json es/versionedTypes/package.json",
|
||||
"build:umd": "cross-env NODE_ENV=development rollup -c -o dist/reselect.js",
|
||||
"build:umd:min": "cross-env NODE_ENV=production rollup -c -o dist/reselect.min.js",
|
||||
"build:types": "tsc",
|
||||
"build": "rimraf dist lib es && yarn build:types && yarn build:commonjs && yarn build:es && yarn build:umd && yarn build:umd:min",
|
||||
"clean": "rimraf lib dist es coverage",
|
||||
"api-types": "api-extractor run --local",
|
||||
"format": "prettier --write \"{src,test}/**/*.{js,ts}\" \"docs/**/*.md\"",
|
||||
"lint": "eslint src test",
|
||||
"prepack": "yarn build",
|
||||
"test": "vitest run",
|
||||
"test:cov": "vitest run --coverage",
|
||||
"test:typescript": "tsc --noEmit -p typescript_test/tsconfig.json"
|
||||
},
|
||||
"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": {
|
||||
"@babel/cli": "^7.15.7",
|
||||
"@babel/core": "^7.15.8",
|
||||
"@babel/preset-env": "^7.15.8",
|
||||
"@babel/preset-typescript": "^7.15.0",
|
||||
"@babel/register": "^7.15.3",
|
||||
"@reduxjs/toolkit": "^1.9.3",
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-commonjs": "^21.0.1",
|
||||
"@rollup/plugin-node-resolve": "^13.0.6",
|
||||
"@rollup/plugin-replace": "^3.0.0",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/lodash": "^4.14.175",
|
||||
"@typescript-eslint/eslint-plugin": "5.1.0",
|
||||
"@typescript-eslint/eslint-plugin-tslint": "5.1.0",
|
||||
"@typescript-eslint/parser": "5.1.0",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-plugin-react": "^7.26.1",
|
||||
"eslint-plugin-typescript": "0.14.0",
|
||||
"jest": "^27.3.1",
|
||||
"lodash.memoize": "^4.1.2",
|
||||
"memoize-one": "^6.0.0",
|
||||
"micro-memoize": "^4.0.9",
|
||||
"mkdirp": "^1.0.4",
|
||||
"ncp": "^2.0.0",
|
||||
"nyc": "^15.1.0",
|
||||
"prettier": "^2.7.1",
|
||||
"react-redux": "^7.2.6",
|
||||
"rimraf": "^3.0.2",
|
||||
"rollup": "^2.58.0",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"tslint": "6.1.3",
|
||||
"typescript": "^4.9",
|
||||
"vitest": "^0.29.8"
|
||||
}
|
||||
}
|
||||
171
node_modules/reselect/src/defaultMemoize.ts
generated
vendored
Normal file
171
node_modules/reselect/src/defaultMemoize.ts
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
import type { EqualityFn } from './types'
|
||||
|
||||
// Cache implementation based on Erik Rasmussen's `lru-memoize`:
|
||||
// https://github.com/erikras/lru-memoize
|
||||
|
||||
const NOT_FOUND = 'NOT_FOUND'
|
||||
type NOT_FOUND_TYPE = typeof NOT_FOUND
|
||||
|
||||
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 }
|
||||
}
|
||||
|
||||
export const defaultEqualityCheck: EqualityFn = (a, b): boolean => {
|
||||
return 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.length
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (!equalityCheck(prev[i], next[i])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
export interface DefaultMemoizeOptions {
|
||||
equalityCheck?: EqualityFn
|
||||
resultEqualityCheck?: EqualityFn
|
||||
maxSize?: number
|
||||
}
|
||||
|
||||
// defaultMemoize now supports a configurable cache size with LRU behavior,
|
||||
// and optional comparison of the result value with existing values
|
||||
export function defaultMemoize<F extends (...args: any[]) => any>(
|
||||
func: F,
|
||||
equalityCheckOrOptions?: EqualityFn | DefaultMemoizeOptions
|
||||
) {
|
||||
const providedOptions =
|
||||
typeof equalityCheckOrOptions === 'object'
|
||||
? equalityCheckOrOptions
|
||||
: { equalityCheck: equalityCheckOrOptions }
|
||||
|
||||
const {
|
||||
equalityCheck = defaultEqualityCheck,
|
||||
maxSize = 1,
|
||||
resultEqualityCheck
|
||||
} = providedOptions
|
||||
|
||||
const comparator = createCacheKeyComparator(equalityCheck)
|
||||
|
||||
const cache =
|
||||
maxSize === 1
|
||||
? createSingletonCache(comparator)
|
||||
: createLruCache(maxSize, comparator)
|
||||
|
||||
// we reference arguments instead of spreading them for performance reasons
|
||||
function memoized() {
|
||||
let value = cache.get(arguments)
|
||||
if (value === NOT_FOUND) {
|
||||
// @ts-ignore
|
||||
value = func.apply(null, arguments)
|
||||
|
||||
if (resultEqualityCheck) {
|
||||
const entries = cache.getEntries()
|
||||
const matchingEntry = entries.find(entry =>
|
||||
resultEqualityCheck(entry.value, value)
|
||||
)
|
||||
|
||||
if (matchingEntry) {
|
||||
value = matchingEntry.value
|
||||
}
|
||||
}
|
||||
|
||||
cache.put(arguments, value)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
memoized.clearCache = () => cache.clear()
|
||||
|
||||
return memoized as F & { clearCache: () => void }
|
||||
}
|
||||
268
node_modules/reselect/src/index.ts
generated
vendored
Normal file
268
node_modules/reselect/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,268 @@
|
||||
import type {
|
||||
Selector,
|
||||
GetParamsFromSelectors,
|
||||
OutputSelector,
|
||||
SelectorArray,
|
||||
SelectorResultArray,
|
||||
DropFirst,
|
||||
MergeParameters,
|
||||
Expand,
|
||||
ObjValueTuple,
|
||||
Head,
|
||||
Tail
|
||||
} from './types'
|
||||
|
||||
export type {
|
||||
Selector,
|
||||
GetParamsFromSelectors,
|
||||
GetStateFromSelectors,
|
||||
OutputSelector,
|
||||
EqualityFn,
|
||||
SelectorArray,
|
||||
SelectorResultArray,
|
||||
ParametricSelector,
|
||||
OutputParametricSelector,
|
||||
OutputSelectorFields
|
||||
} from './types'
|
||||
|
||||
import {
|
||||
defaultMemoize,
|
||||
defaultEqualityCheck,
|
||||
DefaultMemoizeOptions
|
||||
} from './defaultMemoize'
|
||||
|
||||
export { defaultMemoize, defaultEqualityCheck }
|
||||
|
||||
export type { DefaultMemoizeOptions }
|
||||
|
||||
function getDependencies(funcs: unknown[]) {
|
||||
const dependencies = Array.isArray(funcs[0]) ? funcs[0] : funcs
|
||||
|
||||
if (!dependencies.every(dep => typeof dep === 'function')) {
|
||||
const dependencyTypes = dependencies
|
||||
.map(dep =>
|
||||
typeof dep === 'function'
|
||||
? `function ${dep.name || 'unnamed'}()`
|
||||
: typeof dep
|
||||
)
|
||||
.join(', ')
|
||||
|
||||
throw new Error(
|
||||
`createSelector expects all input-selectors to be functions, but received the following types: [${dependencyTypes}]`
|
||||
)
|
||||
}
|
||||
|
||||
return dependencies as SelectorArray
|
||||
}
|
||||
|
||||
export function createSelectorCreator<
|
||||
/** Selectors will eventually accept some function to be memoized */
|
||||
F extends (...args: unknown[]) => unknown,
|
||||
/** A memoizer such as defaultMemoize that accepts a function + some possible options */
|
||||
MemoizeFunction extends (func: F, ...options: any[]) => F,
|
||||
/** The additional options arguments to the memoizer */
|
||||
MemoizeOptions extends unknown[] = DropFirst<Parameters<MemoizeFunction>>
|
||||
>(
|
||||
memoize: MemoizeFunction,
|
||||
...memoizeOptionsFromArgs: DropFirst<Parameters<MemoizeFunction>>
|
||||
) {
|
||||
const createSelector = (...funcs: Function[]) => {
|
||||
let recomputations = 0
|
||||
let lastResult: unknown
|
||||
|
||||
// Due to the intricacies of rest params, we can't do an optional arg after `...funcs`.
|
||||
// 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<MemoizeOptions> = {
|
||||
memoizeOptions: undefined
|
||||
}
|
||||
|
||||
// Normally, the result func or "output selector" is the last arg
|
||||
let resultFunc = funcs.pop()
|
||||
|
||||
// If the result func is actually an _object_, assume it's our options object
|
||||
if (typeof resultFunc === 'object') {
|
||||
directlyPassedOptions = resultFunc as any
|
||||
// and pop the real result func off
|
||||
resultFunc = funcs.pop()
|
||||
}
|
||||
|
||||
if (typeof resultFunc !== 'function') {
|
||||
throw new Error(
|
||||
`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 { memoizeOptions = memoizeOptionsFromArgs } = directlyPassedOptions
|
||||
|
||||
// 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 = Array.isArray(memoizeOptions)
|
||||
? memoizeOptions
|
||||
: ([memoizeOptions] as MemoizeOptions)
|
||||
|
||||
const dependencies = getDependencies(funcs)
|
||||
|
||||
const memoizedResultFunc = memoize(
|
||||
function recomputationWrapper() {
|
||||
recomputations++
|
||||
// apply arguments instead of spreading for performance.
|
||||
return resultFunc!.apply(null, arguments)
|
||||
} as F,
|
||||
...finalMemoizeOptions
|
||||
)
|
||||
|
||||
// If a selector is called with the exact same arguments we don't need to traverse our dependencies again.
|
||||
const selector = memoize(function dependenciesChecker() {
|
||||
const params = []
|
||||
const length = dependencies.length
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
// apply arguments instead of spreading and mutate a local list of params for performance.
|
||||
// @ts-ignore
|
||||
params.push(dependencies[i].apply(null, arguments))
|
||||
}
|
||||
|
||||
// apply arguments instead of spreading for performance.
|
||||
lastResult = memoizedResultFunc.apply(null, params)
|
||||
return lastResult
|
||||
} as F)
|
||||
|
||||
Object.assign(selector, {
|
||||
resultFunc,
|
||||
memoizedResultFunc,
|
||||
dependencies,
|
||||
lastResult: () => lastResult,
|
||||
recomputations: () => recomputations,
|
||||
resetRecomputations: () => (recomputations = 0)
|
||||
})
|
||||
|
||||
return selector
|
||||
}
|
||||
// @ts-ignore
|
||||
return createSelector as CreateSelectorFunction<
|
||||
F,
|
||||
MemoizeFunction,
|
||||
MemoizeOptions
|
||||
>
|
||||
}
|
||||
|
||||
export interface CreateSelectorOptions<MemoizeOptions extends unknown[]> {
|
||||
memoizeOptions: MemoizeOptions[0] | MemoizeOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* An instance of createSelector, customized with a given memoize implementation
|
||||
*/
|
||||
export interface CreateSelectorFunction<
|
||||
F extends (...args: unknown[]) => unknown,
|
||||
MemoizeFunction extends (func: F, ...options: any[]) => F,
|
||||
MemoizeOptions extends unknown[] = DropFirst<Parameters<MemoizeFunction>>,
|
||||
Keys = Expand<
|
||||
Pick<ReturnType<MemoizeFunction>, keyof ReturnType<MemoizeFunction>>
|
||||
>
|
||||
> {
|
||||
/** Input selectors as separate inline arguments */
|
||||
<Selectors extends SelectorArray, Result>(
|
||||
...items: [
|
||||
...Selectors,
|
||||
(...args: SelectorResultArray<Selectors>) => Result
|
||||
]
|
||||
): OutputSelector<
|
||||
Selectors,
|
||||
Result,
|
||||
(...args: SelectorResultArray<Selectors>) => Result,
|
||||
GetParamsFromSelectors<Selectors>,
|
||||
Keys
|
||||
> &
|
||||
Keys
|
||||
|
||||
/** Input selectors as separate inline arguments with memoizeOptions passed */
|
||||
<Selectors extends SelectorArray, Result>(
|
||||
...items: [
|
||||
...Selectors,
|
||||
(...args: SelectorResultArray<Selectors>) => Result,
|
||||
CreateSelectorOptions<MemoizeOptions>
|
||||
]
|
||||
): OutputSelector<
|
||||
Selectors,
|
||||
Result,
|
||||
((...args: SelectorResultArray<Selectors>) => Result),
|
||||
GetParamsFromSelectors<Selectors>,
|
||||
Keys
|
||||
> &
|
||||
Keys
|
||||
|
||||
/** Input selectors as a separate array */
|
||||
<Selectors extends SelectorArray, Result>(
|
||||
selectors: [...Selectors],
|
||||
combiner: (...args: SelectorResultArray<Selectors>) => Result,
|
||||
options?: CreateSelectorOptions<MemoizeOptions>
|
||||
): OutputSelector<
|
||||
Selectors,
|
||||
Result,
|
||||
(...args: SelectorResultArray<Selectors>) => Result,
|
||||
GetParamsFromSelectors<Selectors>,
|
||||
Keys
|
||||
> &
|
||||
Keys
|
||||
}
|
||||
|
||||
export const createSelector =
|
||||
/* #__PURE__ */ createSelectorCreator(defaultMemoize)
|
||||
|
||||
type SelectorsObject = { [key: string]: (...args: any[]) => any }
|
||||
|
||||
export interface StructuredSelectorCreator {
|
||||
<
|
||||
SelectorMap extends SelectorsObject,
|
||||
SelectorParams = MergeParameters<ObjValueTuple<SelectorMap>>
|
||||
>(
|
||||
selectorMap: SelectorMap,
|
||||
selectorCreator?: CreateSelectorFunction<any, any, any>
|
||||
): (
|
||||
// Accept an arbitrary number of parameters for all selectors
|
||||
// The annoying head/tail bit here is because TS isn't convinced that
|
||||
// the `SelectorParams` type is really an array, so we launder things.
|
||||
// Plus it matches common usage anyway.
|
||||
state: Head<SelectorParams>,
|
||||
...params: Tail<SelectorParams>
|
||||
) => {
|
||||
[Key in keyof SelectorMap]: ReturnType<SelectorMap[Key]>
|
||||
}
|
||||
|
||||
<State, Result = State>(
|
||||
selectors: { [K in keyof Result]: Selector<State, Result[K], never> },
|
||||
selectorCreator?: CreateSelectorFunction<any, any, any>
|
||||
): Selector<State, Result, never>
|
||||
}
|
||||
|
||||
// Manual definition of state and output arguments
|
||||
export const createStructuredSelector = ((
|
||||
selectors: SelectorsObject,
|
||||
selectorCreator = createSelector
|
||||
) => {
|
||||
if (typeof selectors !== 'object') {
|
||||
throw new Error(
|
||||
'createStructuredSelector expects first argument to be an object ' +
|
||||
`where each property is a selector, instead received a ${typeof selectors}`
|
||||
)
|
||||
}
|
||||
const objectKeys = Object.keys(selectors)
|
||||
const resultSelector = selectorCreator(
|
||||
// @ts-ignore
|
||||
objectKeys.map(key => selectors[key]),
|
||||
(...values: any[]) => {
|
||||
return values.reduce((composition, value, index) => {
|
||||
composition[objectKeys[index]] = value
|
||||
return composition
|
||||
}, {})
|
||||
}
|
||||
)
|
||||
return resultSelector
|
||||
}) as unknown as StructuredSelectorCreator
|
||||
3325
node_modules/reselect/src/legacyTypes/ts4.1/index.d.ts
generated
vendored
Normal file
3325
node_modules/reselect/src/legacyTypes/ts4.1/index.d.ts
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
305
node_modules/reselect/src/types.ts
generated
vendored
Normal file
305
node_modules/reselect/src/types.ts
generated
vendored
Normal file
@@ -0,0 +1,305 @@
|
||||
import type { MergeParameters } from './versionedTypes'
|
||||
export type { MergeParameters } from './versionedTypes'
|
||||
|
||||
/*
|
||||
*
|
||||
* Reselect Data Types
|
||||
*
|
||||
*/
|
||||
|
||||
/** A standard selector function, which takes three generic type arguments:
|
||||
* @param State The first value, often a Redux root state object
|
||||
* @param Result The final result returned by the selector
|
||||
* @param Params All additional arguments passed into the selector
|
||||
*/
|
||||
export type Selector<
|
||||
// The state can be anything
|
||||
State = any,
|
||||
// The result will be inferred
|
||||
Result = unknown,
|
||||
// There are either 0 params, or N params
|
||||
Params extends never | readonly any[] = any[]
|
||||
// If there are 0 params, type the function as just State in, Result out.
|
||||
// Otherwise, type it as State + Params in, Result out.
|
||||
> = [Params] extends [never]
|
||||
? (state: State) => Result
|
||||
: (state: State, ...params: Params) => Result
|
||||
|
||||
/** Selectors generated by Reselect have several additional fields attached: */
|
||||
export interface OutputSelectorFields<Combiner extends UnknownFunction, Keys> {
|
||||
/** The final function passed to `createSelector` */
|
||||
resultFunc: Combiner
|
||||
/** The same function, memoized */
|
||||
memoizedResultFunc: Combiner & Keys
|
||||
/** Returns the last result calculated by the selector */
|
||||
lastResult: () => ReturnType<Combiner>
|
||||
/** An array of the input selectors */
|
||||
dependencies: SelectorArray
|
||||
/** Counts the number of times the output has been recalculated */
|
||||
recomputations: () => number
|
||||
/** Resets the count of recomputations count to 0 */
|
||||
resetRecomputations: () => number
|
||||
}
|
||||
|
||||
/** Represents the actual selectors generated by `createSelector`.
|
||||
* The selector is:
|
||||
* - "a function that takes this state + params and returns a result"
|
||||
* - plus the attached additional fields
|
||||
*/
|
||||
export type OutputSelector<
|
||||
S extends SelectorArray,
|
||||
Result,
|
||||
Combiner extends UnknownFunction,
|
||||
Params extends readonly any[] = never, // MergeParameters<S>
|
||||
Keys = {}
|
||||
> = Selector<GetStateFromSelectors<S>, Result, Params> &
|
||||
OutputSelectorFields<Combiner, Keys>
|
||||
|
||||
/** A selector that is assumed to have one additional argument, such as
|
||||
* the props from a React component
|
||||
*/
|
||||
export type ParametricSelector<State, Props, Result> = Selector<
|
||||
State,
|
||||
Result,
|
||||
[Props, ...any]
|
||||
>
|
||||
|
||||
/** A generated selector that is assumed to have one additional argument */
|
||||
export type OutputParametricSelector<
|
||||
State,
|
||||
Props,
|
||||
Result,
|
||||
Combiner extends UnknownFunction,
|
||||
Keys = {}
|
||||
> = ParametricSelector<State, Props, Result> &
|
||||
OutputSelectorFields<Combiner, Keys>
|
||||
|
||||
/** An array of input selectors */
|
||||
export type SelectorArray = ReadonlyArray<Selector>
|
||||
|
||||
/** A standard function returning true if two values are considered equal */
|
||||
export type EqualityFn = (a: any, b: any) => boolean
|
||||
|
||||
/*
|
||||
*
|
||||
* Reselect Internal Types
|
||||
*
|
||||
*/
|
||||
|
||||
/** Extracts an array of all return types from all input selectors */
|
||||
export type SelectorResultArray<Selectors extends SelectorArray> =
|
||||
ExtractReturnType<Selectors>
|
||||
|
||||
/** Determines the combined single "State" type (first arg) from all input selectors */
|
||||
export type GetStateFromSelectors<S extends SelectorArray> =
|
||||
MergeParameters<S>[0]
|
||||
|
||||
/** Determines the combined "Params" type (all remaining args) from all input selectors */
|
||||
export type GetParamsFromSelectors<
|
||||
S extends SelectorArray,
|
||||
RemainingItems extends readonly unknown[] = Tail<MergeParameters<S>>
|
||||
> = RemainingItems
|
||||
|
||||
/*
|
||||
*
|
||||
* Reselect Internal Utility Types
|
||||
*
|
||||
*/
|
||||
|
||||
/** Any function with arguments */
|
||||
export type UnknownFunction = (...args: any[]) => any
|
||||
|
||||
/** Extract the return type from all functions as a tuple */
|
||||
export type ExtractReturnType<T extends readonly UnknownFunction[]> = {
|
||||
[index in keyof T]: T[index] extends T[number] ? ReturnType<T[index]> : never
|
||||
}
|
||||
|
||||
/** First item in an array */
|
||||
export type Head<T> = T extends [any, ...any[]] ? T[0] : never
|
||||
/** All other items in an array */
|
||||
export type Tail<A> = A extends [any, ...infer Rest] ? Rest : never
|
||||
|
||||
/** Last item in an array. Recursion also enables this to work with rest syntax - where the type of rest is extracted */
|
||||
export type ReverseHead<S extends readonly unknown[][]> = Tail<S> extends [
|
||||
unknown
|
||||
]
|
||||
? S
|
||||
: Tail<S> extends readonly unknown[][]
|
||||
? ReverseHead<Tail<S>>
|
||||
: never
|
||||
|
||||
/** All elements in array except last
|
||||
*
|
||||
* Recursion makes this work also when rest syntax has been used
|
||||
* Runs _ReverseTail twice, because first pass turns last element into "never", and second pass removes it.
|
||||
**/
|
||||
export type ReverseTail<S> = _ReverseTail<_ReverseTail<S>>
|
||||
type _ReverseTail<S> = Tail<S> extends [unknown]
|
||||
? [Head<S>]
|
||||
: Tail<S> extends unknown[]
|
||||
? [Head<S>, ..._ReverseTail<Tail<S>>]
|
||||
: never
|
||||
|
||||
/** Extract only numeric keys from an array type */
|
||||
export type AllArrayKeys<A extends readonly any[]> = A extends any
|
||||
? {
|
||||
[K in keyof A]: K
|
||||
}[number]
|
||||
: never
|
||||
|
||||
export type List<A = any> = ReadonlyArray<A>
|
||||
|
||||
export type Has<U, U1> = [U1] extends [U] ? 1 : 0
|
||||
|
||||
/*
|
||||
*
|
||||
* External/Copied Utility Types
|
||||
*
|
||||
*/
|
||||
|
||||
/** The infamous "convert a union type to an intersection type" hack
|
||||
* Source: https://github.com/sindresorhus/type-fest/blob/main/source/union-to-intersection.d.ts
|
||||
* Reference: https://github.com/microsoft/TypeScript/issues/29594
|
||||
*/
|
||||
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
|
||||
? Intersection
|
||||
: never
|
||||
|
||||
/**
|
||||
* Assorted util types for type-level conditional logic
|
||||
* Source: https://github.com/KiaraGrouwstra/typical
|
||||
*/
|
||||
export type Bool = '0' | '1'
|
||||
export type Obj<T> = { [k: string]: T }
|
||||
export type And<A extends Bool, B extends Bool> = ({
|
||||
1: { 1: '1' } & Obj<'0'>
|
||||
} & Obj<Obj<'0'>>)[A][B]
|
||||
|
||||
export type Matches<V, T> = V extends T ? '1' : '0'
|
||||
export type IsArrayType<T> = Matches<T, any[]>
|
||||
|
||||
export type Not<T extends Bool> = { '1': '0'; '0': '1' }[T]
|
||||
export type InstanceOf<V, T> = And<Matches<V, T>, Not<Matches<T, V>>>
|
||||
export type IsTuple<T extends { length: number }> = And<
|
||||
IsArrayType<T>,
|
||||
InstanceOf<T['length'], number>
|
||||
>
|
||||
|
||||
/**
|
||||
* Code to convert a union of values into a tuple.
|
||||
* Source: https://stackoverflow.com/a/55128956/62937
|
||||
*/
|
||||
type Push<T extends any[], V> = [...T, V]
|
||||
|
||||
type LastOf<T> = UnionToIntersection<
|
||||
T extends any ? () => T : never
|
||||
> extends () => infer R
|
||||
? R
|
||||
: never
|
||||
|
||||
// TS4.1+
|
||||
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()`
|
||||
* Source: https://stackoverflow.com/a/68695508/62937
|
||||
*/
|
||||
export type ObjValueTuple<
|
||||
T,
|
||||
KS extends any[] = TuplifyUnion<keyof T>,
|
||||
R extends any[] = []
|
||||
> = KS extends [infer K, ...infer KT]
|
||||
? ObjValueTuple<T, KT, [...R, T[K & keyof T]]>
|
||||
: R
|
||||
|
||||
/** 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 */
|
||||
export type DropFirst<T extends unknown[]> = T extends [unknown, ...infer U]
|
||||
? U
|
||||
: never
|
||||
|
||||
/**
|
||||
* Expand an item a single level, or recursively.
|
||||
* Source: https://stackoverflow.com/a/69288824/62937
|
||||
*/
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
type Identity<T> = T
|
||||
/**
|
||||
* Another form of type value expansion
|
||||
* Source: https://github.com/microsoft/TypeScript/issues/35247
|
||||
*/
|
||||
export type Mapped<T> = Identity<{ [k in keyof T]: T[k] }>
|
||||
|
||||
/**
|
||||
* Fully expand a type, deeply
|
||||
* Source: https://github.com/millsp/ts-toolbelt (`Any.Compute`)
|
||||
*/
|
||||
|
||||
type ComputeDeep<A, Seen = never> = A extends BuiltIn
|
||||
? A
|
||||
: If2<
|
||||
Has<Seen, A>,
|
||||
A,
|
||||
A extends Array<any>
|
||||
? A extends Array<Record<Key, any>>
|
||||
? Array<
|
||||
{
|
||||
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
|
||||
} & unknown
|
||||
>
|
||||
: A
|
||||
: A extends ReadonlyArray<any>
|
||||
? A extends ReadonlyArray<Record<Key, any>>
|
||||
? ReadonlyArray<
|
||||
{
|
||||
[K in keyof A[number]]: ComputeDeep<A[number][K], A | Seen>
|
||||
} & unknown
|
||||
>
|
||||
: A
|
||||
: { [K in keyof A]: ComputeDeep<A[K], A | Seen> } & unknown
|
||||
>
|
||||
|
||||
export type If2<B extends Boolean2, Then, Else = never> = B extends 1
|
||||
? Then
|
||||
: Else
|
||||
|
||||
export type Boolean2 = 0 | 1
|
||||
|
||||
export type Key = string | number | symbol
|
||||
|
||||
export type BuiltIn =
|
||||
| Function
|
||||
| Error
|
||||
| Date
|
||||
| { readonly [Symbol.toStringTag]: string }
|
||||
| RegExp
|
||||
| Generator
|
||||
1
node_modules/reselect/src/versionedTypes/index.ts
generated
vendored
Normal file
1
node_modules/reselect/src/versionedTypes/index.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
export { MergeParameters } from './ts47-mergeParameters'
|
||||
14
node_modules/reselect/src/versionedTypes/package.dist.json
generated
vendored
Normal file
14
node_modules/reselect/src/versionedTypes/package.dist.json
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"typesVersions": {
|
||||
">=4.7": {
|
||||
"index": [
|
||||
"./ts47-mergeParameters.d.ts"
|
||||
]
|
||||
},
|
||||
"<4.7": {
|
||||
"index": [
|
||||
"./ts46-mergeParameters.d.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
171
node_modules/reselect/src/versionedTypes/ts46-mergeParameters.ts
generated
vendored
Normal file
171
node_modules/reselect/src/versionedTypes/ts46-mergeParameters.ts
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
import type {
|
||||
UnknownFunction,
|
||||
Expand,
|
||||
TuplifyUnion,
|
||||
Has,
|
||||
List,
|
||||
IsTuple
|
||||
} from '../types'
|
||||
|
||||
/** Given a set of input selectors, extracts the intersected parameters to determine
|
||||
* what values can actually be passed to all of the input selectors at once
|
||||
* WARNING: "you are not expected to understand this" :)
|
||||
*/
|
||||
export type MergeParameters<
|
||||
// The actual array of input selectors
|
||||
T extends readonly UnknownFunction[],
|
||||
// Given those selectors, we do several transformations on the types in sequence:
|
||||
// 1) Extract "the type of parameters" for each input selector, so that we now have
|
||||
// a tuple of all those parameters
|
||||
ParamsArrays extends readonly any[][] = ExtractParams<T>,
|
||||
// 2) Transpose the parameter tuples.
|
||||
// Originally, we have nested arrays with "all params from input", "from input 2", etc:
|
||||
// `[ [i1a, i1b, i1c], [i2a, i2b, i2c], [i3a, i3b, i3c] ],
|
||||
// In order to intersect the params at each index, we need to transpose them so that
|
||||
// we have "all the first args", "all the second args", and so on:
|
||||
// `[ [i1a, i2a, i3a], [i1b, i2b, i3b], [i1c, i2c, i3c] ]
|
||||
// Unfortunately, this step also turns the arrays into a union, and weirder, it is
|
||||
// a union of all possible combinations for all input functions, so there's duplicates.
|
||||
TransposedArrays = Transpose<ParamsArrays>,
|
||||
// 3) Turn the union of arrays back into a nested tuple. Order does not matter here.
|
||||
TuplifiedArrays extends any[] = TuplifyUnion<TransposedArrays>,
|
||||
// 4) Find the longest params array out of the ones we have.
|
||||
// Note that this is actually the _nested_ data we wanted out of the transpose step,
|
||||
// so it has all the right pieces we need.
|
||||
LongestParamsArray extends readonly any[] = LongestArray<TuplifiedArrays>
|
||||
> =
|
||||
// After all that preparation work, we can actually do parameter extraction.
|
||||
// These steps work somewhat inside out (jump ahead to the middle):
|
||||
// 11) Finally, after all that, run a shallow expansion on the values to make the user-visible
|
||||
// field details more readable when viewing the selector's type in a hover box.
|
||||
ExpandItems<
|
||||
// 10) Tuples can have field names attached, and it seems to work better to remove those
|
||||
RemoveNames<{
|
||||
// 5) We know the longest params array has N args. Loop over the indices of that array.
|
||||
// 6) For each index, do a check to ensure that we're _only_ checking numeric indices,
|
||||
// not any field names for array functions like `slice()`
|
||||
[index in keyof LongestParamsArray]: LongestParamsArray[index] extends LongestParamsArray[number]
|
||||
? // 9) Any object types that were intersected may have had
|
||||
IgnoreInvalidIntersections<
|
||||
// 8) Then, intersect all of the parameters for this arg together.
|
||||
IntersectAll<
|
||||
// 7) Since this is a _nested_ array, extract the right sub-array for this index
|
||||
LongestParamsArray[index]
|
||||
>
|
||||
>
|
||||
: never
|
||||
}>
|
||||
>
|
||||
|
||||
/*
|
||||
*
|
||||
* Reselect Internal Utility Types
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* Reselect Internal Utility Types
|
||||
*
|
||||
*/
|
||||
|
||||
/** An object with no fields */
|
||||
type EmptyObject = {
|
||||
[K in any]: never
|
||||
}
|
||||
|
||||
type IgnoreInvalidIntersections<T> = T extends EmptyObject ? never : T
|
||||
|
||||
/** Extract the parameters from all functions as a tuple */
|
||||
export type ExtractParams<T extends readonly UnknownFunction[]> = {
|
||||
[index in keyof T]: T[index] extends T[number] ? Parameters<T[index]> : never
|
||||
}
|
||||
|
||||
/** Recursively expand all fields in an object for easier reading */
|
||||
export type ExpandItems<T extends readonly unknown[]> = {
|
||||
[index in keyof T]: T[index] extends T[number] ? Expand<T[index]> : never
|
||||
}
|
||||
|
||||
/** Select the longer of two arrays */
|
||||
export type Longest<L extends List, L1 extends List> = L extends unknown
|
||||
? L1 extends unknown
|
||||
? { 0: L1; 1: L }[Has<keyof L, keyof L1>]
|
||||
: never
|
||||
: never
|
||||
|
||||
/** Recurse over a nested array to locate the longest one.
|
||||
* Acts like a type-level `reduce()`
|
||||
*/
|
||||
export type LongestArray<S extends readonly any[][]> =
|
||||
// If this isn't a tuple, all indices are the same, we can't tell a difference
|
||||
IsTuple<S> extends '0'
|
||||
? // so just return the type of the first item
|
||||
S[0]
|
||||
: // If there's two nested arrays remaining, compare them
|
||||
S extends [any[], any[]]
|
||||
? Longest<S[0], S[1]>
|
||||
: // If there's more than two, extract their types, treat the remainder as a smaller array
|
||||
S extends [any[], any[], ...infer Rest]
|
||||
? // then compare those two, recurse through the smaller array, and compare vs its result
|
||||
Longest<
|
||||
Longest<S[0], S[1]>,
|
||||
Rest extends any[][] ? LongestArray<Rest> : []
|
||||
>
|
||||
: // If there's one item left, return it
|
||||
S extends [any[]]
|
||||
? S[0]
|
||||
: never
|
||||
|
||||
/** Recursive type for intersecting together all items in a tuple, to determine
|
||||
* the final parameter type at a given argument index in the generated selector. */
|
||||
export type IntersectAll<T extends any[]> = IsTuple<T> extends '0'
|
||||
? T[0]
|
||||
: _IntersectAll<T>
|
||||
|
||||
type IfJustNullish<T, True, False> = [T] extends [undefined | null]
|
||||
? True
|
||||
: False
|
||||
|
||||
/** Intersect a pair of types together, for use in parameter type calculation.
|
||||
* This is made much more complex because we need to correctly handle cases
|
||||
* where a function has fewer parameters and the type is `undefined`, as well as
|
||||
* optional params or params that have `null` or `undefined` as part of a union.
|
||||
*
|
||||
* If the next type by itself is `null` or `undefined`, we exclude it and return
|
||||
* the other type. Otherwise, intersect them together.
|
||||
*/
|
||||
type _IntersectAll<T, R = unknown> = T extends [infer First, ...infer Rest]
|
||||
? _IntersectAll<Rest, IfJustNullish<First, R, R & First>>
|
||||
: R
|
||||
|
||||
/*
|
||||
*
|
||||
* External/Copied Utility Types
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Removes field names from a tuple
|
||||
* Source: https://stackoverflow.com/a/63571175/62937
|
||||
*/
|
||||
type RemoveNames<T extends readonly any[]> = [any, ...T] extends [
|
||||
any,
|
||||
...infer U
|
||||
]
|
||||
? U
|
||||
: never
|
||||
|
||||
/**
|
||||
* Transposes nested arrays
|
||||
* Source: https://stackoverflow.com/a/66303933/62937
|
||||
*/
|
||||
type Transpose<T> = T[Extract<
|
||||
keyof T,
|
||||
T extends readonly any[] ? number : unknown
|
||||
>] extends infer V
|
||||
? {
|
||||
[K in keyof V]: {
|
||||
[L in keyof T]: K extends keyof T[L] ? T[L][K] : undefined
|
||||
}
|
||||
}
|
||||
: never
|
||||
66
node_modules/reselect/src/versionedTypes/ts47-mergeParameters.ts
generated
vendored
Normal file
66
node_modules/reselect/src/versionedTypes/ts47-mergeParameters.ts
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// This entire implementation courtesy of Anders Hjelsberg:
|
||||
// https://github.com/microsoft/TypeScript/pull/50831#issuecomment-1253830522
|
||||
|
||||
import { ReverseHead, ReverseTail } from '../types'
|
||||
|
||||
type UnknownFunction = (...args: any[]) => any
|
||||
|
||||
type LongestTuple<T> = T extends [infer U extends unknown[]]
|
||||
? U
|
||||
: T extends [infer U, ...infer R extends unknown[][]]
|
||||
? MostProperties<U, LongestTuple<R>>
|
||||
: never
|
||||
|
||||
type MostProperties<T, U> = keyof U extends keyof T ? T : U
|
||||
|
||||
type ElementAt<T, N extends keyof any> = N extends keyof T ? T[N] : unknown
|
||||
|
||||
type ElementsAt<T, N extends keyof any> = {
|
||||
[K in keyof T]: ElementAt<T[K], N>
|
||||
}
|
||||
|
||||
type Intersect<T extends readonly unknown[]> = T extends []
|
||||
? unknown
|
||||
: T extends [infer H, ...infer T]
|
||||
? H & Intersect<T>
|
||||
: T[number]
|
||||
|
||||
type MergeTuples<T, L extends unknown[] = LongestTuple<T>> = {
|
||||
[K in keyof L]: Intersect<
|
||||
ElementsAt<T, K> extends readonly unknown[] ? ElementsAt<T, K> : never
|
||||
>
|
||||
}
|
||||
|
||||
type ExtractParameters<T extends readonly UnknownFunction[]> = {
|
||||
[K in keyof T]: Parameters<T[K]>
|
||||
}
|
||||
|
||||
export type MergeParameters<T extends readonly UnknownFunction[]> =
|
||||
'0' extends keyof T
|
||||
? MergeTuples<MakeRestExplicit<ExtractParameters<T>>>
|
||||
: Parameters<T[number]>
|
||||
|
||||
type HasRest<S extends readonly unknown[]> = number extends S['length']
|
||||
? true
|
||||
: false
|
||||
|
||||
type HasExplicit<S extends readonly unknown[]> = '0' extends keyof S
|
||||
? true
|
||||
: false
|
||||
|
||||
type HasCombined<S extends readonly unknown[]> = true extends HasExplicit<S> &
|
||||
HasRest<S>
|
||||
? true
|
||||
: false
|
||||
|
||||
type MakeRestExplicit<T extends readonly unknown[][]> =
|
||||
true extends HasCombined<T>
|
||||
? [
|
||||
...ReverseTail<T>,
|
||||
ReverseHead<T> extends readonly unknown[]
|
||||
? ReverseHead<T>[number]
|
||||
: never
|
||||
]
|
||||
: true extends HasRest<T>
|
||||
? [...T]
|
||||
: T
|
||||
Reference in New Issue
Block a user