Initial commit - Dutchie dispensary scraper

This commit is contained in:
Kelly
2025-11-28 19:45:44 -07:00
commit 5757a8e9bd
23375 changed files with 3788799 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
import type { Context } from 'react'
import { React } from '../utils/react'
import type { Action, Store, UnknownAction } from 'redux'
import type { Subscription } from '../utils/Subscription'
import type { ProviderProps } from './Provider'
export interface ReactReduxContextValue<
SS = any,
A extends Action<string> = UnknownAction,
> extends Pick<ProviderProps, 'stabilityCheck' | 'identityFunctionCheck'> {
store: Store<SS, A>
subscription: Subscription
getServerState?: () => SS
}
const ContextKey = /* @__PURE__ */ Symbol.for(`react-redux-context`)
const gT: {
[ContextKey]?: Map<
typeof React.createContext,
Context<ReactReduxContextValue | null>
>
} = (
typeof globalThis !== 'undefined'
? globalThis
: /* fall back to a per-module scope (pre-8.1 behaviour) if `globalThis` is not available */ {}
) as any
function getContext(): Context<ReactReduxContextValue | null> {
if (!React.createContext) return {} as any
const contextMap = (gT[ContextKey] ??= new Map<
typeof React.createContext,
Context<ReactReduxContextValue | null>
>())
let realContext = contextMap.get(React.createContext)
if (!realContext) {
realContext = React.createContext<ReactReduxContextValue | null>(
null as any,
)
if (process.env.NODE_ENV !== 'production') {
realContext.displayName = 'ReactRedux'
}
contextMap.set(React.createContext, realContext)
}
return realContext
}
export const ReactReduxContext = /*#__PURE__*/ getContext()
export type ReactReduxContextInstance = typeof ReactReduxContext

View File

@@ -0,0 +1,105 @@
import type { Context, ReactNode } from 'react'
import { React } from '../utils/react'
import type { Action, Store, UnknownAction } from 'redux'
import type { DevModeCheckFrequency } from '../hooks/useSelector'
import { createSubscription } from '../utils/Subscription'
import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect'
import type { ReactReduxContextValue } from './Context'
import { ReactReduxContext } from './Context'
export interface ProviderProps<
A extends Action<string> = UnknownAction,
S = unknown,
> {
/**
* The single Redux store in your application.
*/
store: Store<S, A>
/**
* An optional server state snapshot. Will be used during initial hydration render if available, to ensure that the UI output is consistent with the HTML generated on the server.
*/
serverState?: S
/**
* Optional context to be used internally in react-redux. Use React.createContext() to create a context to be used.
* If this is used, you'll need to customize `connect` by supplying the same context provided to the Provider.
* Set the initial value to null, and the hooks will error
* if this is not overwritten by Provider.
*/
context?: Context<ReactReduxContextValue<S, A> | null>
/**
* Determines the frequency of stability checks for all selectors.
* This setting overrides the global configuration for
* the `useSelector` stability check, allowing you to specify how often
* these checks should occur in development mode.
*
* @since 8.1.0
*/
stabilityCheck?: DevModeCheckFrequency
/**
* Determines the frequency of identity function checks for all selectors.
* This setting overrides the global configuration for
* the `useSelector` identity function check, allowing you to specify how often
* these checks should occur in development mode.
*
* **Note**: Previously referred to as `noopCheck`.
*
* @since 9.0.0
*/
identityFunctionCheck?: DevModeCheckFrequency
children: ReactNode
}
function Provider<A extends Action<string> = UnknownAction, S = unknown>(
providerProps: ProviderProps<A, S>,
) {
const { children, context, serverState, store } = providerProps
const contextValue = React.useMemo(() => {
const subscription = createSubscription(store)
const baseContextValue = {
store,
subscription,
getServerState: serverState ? () => serverState : undefined,
}
if (process.env.NODE_ENV === 'production') {
return baseContextValue
} else {
const { identityFunctionCheck = 'once', stabilityCheck = 'once' } =
providerProps
return /* @__PURE__ */ Object.assign(baseContextValue, {
stabilityCheck,
identityFunctionCheck,
})
}
}, [store, serverState])
const previousState = React.useMemo(() => store.getState(), [store])
useIsomorphicLayoutEffect(() => {
const { subscription } = contextValue
subscription.onStateChange = subscription.notifyNestedSubs
subscription.trySubscribe()
if (previousState !== store.getState()) {
subscription.notifyNestedSubs()
}
return () => {
subscription.tryUnsubscribe()
subscription.onStateChange = undefined
}
}, [contextValue, previousState])
const Context = context || ReactReduxContext
return <Context.Provider value={contextValue}>{children}</Context.Provider>
}
export default Provider

View File

@@ -0,0 +1,813 @@
/* eslint-disable valid-jsdoc, @typescript-eslint/no-unused-vars */
import type { ComponentType } from 'react'
import { React } from '../utils/react'
import { isValidElementType, isContextConsumer } from '../utils/react-is'
import type { Store } from 'redux'
import type {
ConnectedComponent,
InferableComponentEnhancer,
InferableComponentEnhancerWithProps,
ResolveThunks,
DispatchProp,
ConnectPropsMaybeWithoutContext,
} from '../types'
import type {
MapStateToPropsParam,
MapDispatchToPropsParam,
MergeProps,
MapDispatchToPropsNonObject,
SelectorFactoryOptions,
} from '../connect/selectorFactory'
import defaultSelectorFactory from '../connect/selectorFactory'
import { mapDispatchToPropsFactory } from '../connect/mapDispatchToProps'
import { mapStateToPropsFactory } from '../connect/mapStateToProps'
import { mergePropsFactory } from '../connect/mergeProps'
import type { Subscription } from '../utils/Subscription'
import { createSubscription } from '../utils/Subscription'
import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect'
import shallowEqual from '../utils/shallowEqual'
import hoistStatics from '../utils/hoistStatics'
import warning from '../utils/warning'
import type {
ReactReduxContextValue,
ReactReduxContextInstance,
} from './Context'
import { ReactReduxContext } from './Context'
// Define some constant arrays just to avoid re-creating these
const EMPTY_ARRAY: [unknown, number] = [null, 0]
const NO_SUBSCRIPTION_ARRAY = [null, null]
// Attempts to stringify whatever not-really-a-component value we were given
// for logging in an error message
const stringifyComponent = (Comp: unknown) => {
try {
return JSON.stringify(Comp)
} catch (err) {
return String(Comp)
}
}
type EffectFunc = (...args: any[]) => void | ReturnType<React.EffectCallback>
// This is "just" a `useLayoutEffect`, but with two modifications:
// - we need to fall back to `useEffect` in SSR to avoid annoying warnings
// - we extract this to a separate function to avoid closing over values
// and causing memory leaks
function useIsomorphicLayoutEffectWithArgs(
effectFunc: EffectFunc,
effectArgs: any[],
dependencies?: React.DependencyList,
) {
useIsomorphicLayoutEffect(() => effectFunc(...effectArgs), dependencies)
}
// Effect callback, extracted: assign the latest props values to refs for later usage
function captureWrapperProps(
lastWrapperProps: React.MutableRefObject<unknown>,
lastChildProps: React.MutableRefObject<unknown>,
renderIsScheduled: React.MutableRefObject<boolean>,
wrapperProps: unknown,
// actualChildProps: unknown,
childPropsFromStoreUpdate: React.MutableRefObject<unknown>,
notifyNestedSubs: () => void,
) {
// We want to capture the wrapper props and child props we used for later comparisons
lastWrapperProps.current = wrapperProps
renderIsScheduled.current = false
// If the render was from a store update, clear out that reference and cascade the subscriber update
if (childPropsFromStoreUpdate.current) {
childPropsFromStoreUpdate.current = null
notifyNestedSubs()
}
}
// Effect callback, extracted: subscribe to the Redux store or nearest connected ancestor,
// check for updates after dispatched actions, and trigger re-renders.
function subscribeUpdates(
shouldHandleStateChanges: boolean,
store: Store,
subscription: Subscription,
childPropsSelector: (state: unknown, props: unknown) => unknown,
lastWrapperProps: React.MutableRefObject<unknown>,
lastChildProps: React.MutableRefObject<unknown>,
renderIsScheduled: React.MutableRefObject<boolean>,
isMounted: React.MutableRefObject<boolean>,
childPropsFromStoreUpdate: React.MutableRefObject<unknown>,
notifyNestedSubs: () => void,
// forceComponentUpdateDispatch: React.Dispatch<any>,
additionalSubscribeListener: () => void,
) {
// If we're not subscribed to the store, nothing to do here
if (!shouldHandleStateChanges) return () => {}
// Capture values for checking if and when this component unmounts
let didUnsubscribe = false
let lastThrownError: Error | null = null
// We'll run this callback every time a store subscription update propagates to this component
const checkForUpdates = () => {
if (didUnsubscribe || !isMounted.current) {
// Don't run stale listeners.
// Redux doesn't guarantee unsubscriptions happen until next dispatch.
return
}
// TODO We're currently calling getState ourselves here, rather than letting `uSES` do it
const latestStoreState = store.getState()
let newChildProps, error
try {
// Actually run the selector with the most recent store state and wrapper props
// to determine what the child props should be
newChildProps = childPropsSelector(
latestStoreState,
lastWrapperProps.current,
)
} catch (e) {
error = e
lastThrownError = e as Error | null
}
if (!error) {
lastThrownError = null
}
// If the child props haven't changed, nothing to do here - cascade the subscription update
if (newChildProps === lastChildProps.current) {
if (!renderIsScheduled.current) {
notifyNestedSubs()
}
} else {
// Save references to the new child props. Note that we track the "child props from store update"
// as a ref instead of a useState/useReducer because we need a way to determine if that value has
// been processed. If this went into useState/useReducer, we couldn't clear out the value without
// forcing another re-render, which we don't want.
lastChildProps.current = newChildProps
childPropsFromStoreUpdate.current = newChildProps
renderIsScheduled.current = true
// TODO This is hacky and not how `uSES` is meant to be used
// Trigger the React `useSyncExternalStore` subscriber
additionalSubscribeListener()
}
}
// Actually subscribe to the nearest connected ancestor (or store)
subscription.onStateChange = checkForUpdates
subscription.trySubscribe()
// Pull data from the store after first render in case the store has
// changed since we began.
checkForUpdates()
const unsubscribeWrapper = () => {
didUnsubscribe = true
subscription.tryUnsubscribe()
subscription.onStateChange = null
if (lastThrownError) {
// It's possible that we caught an error due to a bad mapState function, but the
// parent re-rendered without this component and we're about to unmount.
// This shouldn't happen as long as we do top-down subscriptions correctly, but
// if we ever do those wrong, this throw will surface the error in our tests.
// In that case, throw the error from here so it doesn't get lost.
throw lastThrownError
}
}
return unsubscribeWrapper
}
// Reducer initial state creation for our update reducer
const initStateUpdates = () => EMPTY_ARRAY
export interface ConnectProps {
/** A custom Context instance that the component can use to access the store from an alternate Provider using that same Context instance */
context?: ReactReduxContextInstance
/** A Redux store instance to be used for subscriptions instead of the store from a Provider */
store?: Store
}
interface InternalConnectProps extends ConnectProps {
reactReduxForwardedRef?: React.ForwardedRef<unknown>
}
function strictEqual(a: unknown, b: unknown) {
return a === b
}
/**
* Infers the type of props that a connector will inject into a component.
*/
export type ConnectedProps<TConnector> =
TConnector extends InferableComponentEnhancerWithProps<
infer TInjectedProps,
any
>
? unknown extends TInjectedProps
? TConnector extends InferableComponentEnhancer<infer TInjectedProps>
? TInjectedProps
: never
: TInjectedProps
: never
export interface ConnectOptions<
State = unknown,
TStateProps = {},
TOwnProps = {},
TMergedProps = {},
> {
forwardRef?: boolean
context?: typeof ReactReduxContext
areStatesEqual?: (
nextState: State,
prevState: State,
nextOwnProps: TOwnProps,
prevOwnProps: TOwnProps,
) => boolean
areOwnPropsEqual?: (
nextOwnProps: TOwnProps,
prevOwnProps: TOwnProps,
) => boolean
areStatePropsEqual?: (
nextStateProps: TStateProps,
prevStateProps: TStateProps,
) => boolean
areMergedPropsEqual?: (
nextMergedProps: TMergedProps,
prevMergedProps: TMergedProps,
) => boolean
}
/**
* Connects a React component to a Redux store.
*
* - Without arguments, just wraps the component, without changing the behavior / props
*
* - If 2 params are passed (3rd param, mergeProps, is skipped), default behavior
* is to override ownProps (as stated in the docs), so what remains is everything that's
* not a state or dispatch prop
*
* - When 3rd param is passed, we don't know if ownProps propagate and whether they
* should be valid component props, because it depends on mergeProps implementation.
* As such, it is the user's responsibility to extend ownProps interface from state or
* dispatch props or both when applicable
*
* @param mapStateToProps
* @param mapDispatchToProps
* @param mergeProps
* @param options
*/
export interface Connect<DefaultState = unknown> {
// tslint:disable:no-unnecessary-generics
(): InferableComponentEnhancer<DispatchProp>
/** mapState only */
<TStateProps = {}, no_dispatch = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
): InferableComponentEnhancerWithProps<TStateProps & DispatchProp, TOwnProps>
/** mapDispatch only (as a function) */
<no_state = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>,
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>
/** mapDispatch only (as an object) */
<no_state = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
): InferableComponentEnhancerWithProps<
ResolveThunks<TDispatchProps>,
TOwnProps
>
/** mapState and mapDispatch (as a function)*/
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>,
): InferableComponentEnhancerWithProps<
TStateProps & TDispatchProps,
TOwnProps
>
/** mapState and mapDispatch (nullish) */
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: null | undefined,
): InferableComponentEnhancerWithProps<TStateProps, TOwnProps>
/** mapState and mapDispatch (as an object) */
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
): InferableComponentEnhancerWithProps<
TStateProps & ResolveThunks<TDispatchProps>,
TOwnProps
>
/** mergeProps only */
<no_state = {}, no_dispatch = {}, TOwnProps = {}, TMergedProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: null | undefined,
mergeProps: MergeProps<undefined, DispatchProp, TOwnProps, TMergedProps>,
): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>
/** mapState and mergeProps */
<
TStateProps = {},
no_dispatch = {},
TOwnProps = {},
TMergedProps = {},
State = DefaultState,
>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: null | undefined,
mergeProps: MergeProps<TStateProps, DispatchProp, TOwnProps, TMergedProps>,
): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>
/** mapDispatch (as a object) and mergeProps */
<no_state = {}, TDispatchProps = {}, TOwnProps = {}, TMergedProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
mergeProps: MergeProps<undefined, TDispatchProps, TOwnProps, TMergedProps>,
): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>
/** mapState and options */
<TStateProps = {}, no_dispatch = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: null | undefined,
mergeProps: null | undefined,
options: ConnectOptions<State, TStateProps, TOwnProps>,
): InferableComponentEnhancerWithProps<DispatchProp & TStateProps, TOwnProps>
/** mapDispatch (as a function) and options */
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>,
mergeProps: null | undefined,
options: ConnectOptions<{}, TStateProps, TOwnProps>,
): InferableComponentEnhancerWithProps<TDispatchProps, TOwnProps>
/** mapDispatch (as an object) and options*/
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}>(
mapStateToProps: null | undefined,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
mergeProps: null | undefined,
options: ConnectOptions<{}, TStateProps, TOwnProps>,
): InferableComponentEnhancerWithProps<
ResolveThunks<TDispatchProps>,
TOwnProps
>
/** mapState, mapDispatch (as a function), and options */
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>,
mergeProps: null | undefined,
options: ConnectOptions<State, TStateProps, TOwnProps>,
): InferableComponentEnhancerWithProps<
TStateProps & TDispatchProps,
TOwnProps
>
/** mapState, mapDispatch (as an object), and options */
<TStateProps = {}, TDispatchProps = {}, TOwnProps = {}, State = DefaultState>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
mergeProps: null | undefined,
options: ConnectOptions<State, TStateProps, TOwnProps>,
): InferableComponentEnhancerWithProps<
TStateProps & ResolveThunks<TDispatchProps>,
TOwnProps
>
/** mapState, mapDispatch, mergeProps, and options */
<
TStateProps = {},
TDispatchProps = {},
TOwnProps = {},
TMergedProps = {},
State = DefaultState,
>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
mergeProps: MergeProps<
TStateProps,
TDispatchProps,
TOwnProps,
TMergedProps
>,
options?: ConnectOptions<State, TStateProps, TOwnProps, TMergedProps>,
): InferableComponentEnhancerWithProps<TMergedProps, TOwnProps>
// tslint:enable:no-unnecessary-generics
}
let hasWarnedAboutDeprecatedPureOption = false
/**
* Connects a React component to a Redux store.
*
* - Without arguments, just wraps the component, without changing the behavior / props
*
* - If 2 params are passed (3rd param, mergeProps, is skipped), default behavior
* is to override ownProps (as stated in the docs), so what remains is everything that's
* not a state or dispatch prop
*
* - When 3rd param is passed, we don't know if ownProps propagate and whether they
* should be valid component props, because it depends on mergeProps implementation.
* As such, it is the user's responsibility to extend ownProps interface from state or
* dispatch props or both when applicable
*
* @param mapStateToProps A function that extracts values from state
* @param mapDispatchToProps Setup for dispatching actions
* @param mergeProps Optional callback to merge state and dispatch props together
* @param options Options for configuring the connection
*
*/
function connect<
TStateProps = {},
TDispatchProps = {},
TOwnProps = {},
TMergedProps = {},
State = unknown,
>(
mapStateToProps?: MapStateToPropsParam<TStateProps, TOwnProps, State>,
mapDispatchToProps?: MapDispatchToPropsParam<TDispatchProps, TOwnProps>,
mergeProps?: MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>,
{
// The `pure` option has been removed, so TS doesn't like us destructuring this to check its existence.
// @ts-ignore
pure,
areStatesEqual = strictEqual,
areOwnPropsEqual = shallowEqual,
areStatePropsEqual = shallowEqual,
areMergedPropsEqual = shallowEqual,
// use React's forwardRef to expose a ref of the wrapped component
forwardRef = false,
// the context consumer to use
context = ReactReduxContext,
}: ConnectOptions<unknown, unknown, unknown, unknown> = {},
): unknown {
if (process.env.NODE_ENV !== 'production') {
if (pure !== undefined && !hasWarnedAboutDeprecatedPureOption) {
hasWarnedAboutDeprecatedPureOption = true
warning(
'The `pure` option has been removed. `connect` is now always a "pure/memoized" component',
)
}
}
const Context = context
const initMapStateToProps = mapStateToPropsFactory(mapStateToProps)
const initMapDispatchToProps = mapDispatchToPropsFactory(mapDispatchToProps)
const initMergeProps = mergePropsFactory(mergeProps)
const shouldHandleStateChanges = Boolean(mapStateToProps)
const wrapWithConnect = <TProps,>(
WrappedComponent: ComponentType<TProps>,
) => {
type WrappedComponentProps = TProps &
ConnectPropsMaybeWithoutContext<TProps>
if (process.env.NODE_ENV !== 'production') {
const isValid = /*#__PURE__*/ isValidElementType(WrappedComponent)
if (!isValid)
throw new Error(
`You must pass a component to the function returned by connect. Instead received ${stringifyComponent(
WrappedComponent,
)}`,
)
}
const wrappedComponentName =
WrappedComponent.displayName || WrappedComponent.name || 'Component'
const displayName = `Connect(${wrappedComponentName})`
const selectorFactoryOptions: SelectorFactoryOptions<
any,
any,
any,
any,
State
> = {
shouldHandleStateChanges,
displayName,
wrappedComponentName,
WrappedComponent,
// @ts-ignore
initMapStateToProps,
initMapDispatchToProps,
initMergeProps,
areStatesEqual,
areStatePropsEqual,
areOwnPropsEqual,
areMergedPropsEqual,
}
function ConnectFunction<TOwnProps>(
props: InternalConnectProps & TOwnProps,
) {
const [propsContext, reactReduxForwardedRef, wrapperProps] =
React.useMemo(() => {
// Distinguish between actual "data" props that were passed to the wrapper component,
// and values needed to control behavior (forwarded refs, alternate context instances).
// To maintain the wrapperProps object reference, memoize this destructuring.
const { reactReduxForwardedRef, ...wrapperProps } = props
return [props.context, reactReduxForwardedRef, wrapperProps]
}, [props])
const ContextToUse: ReactReduxContextInstance = React.useMemo(() => {
// Users may optionally pass in a custom context instance to use instead of our ReactReduxContext.
// Memoize the check that determines which context instance we should use.
let ResultContext = Context
if (propsContext?.Consumer) {
if (process.env.NODE_ENV !== 'production') {
const isValid = /*#__PURE__*/ isContextConsumer(
// @ts-ignore
<propsContext.Consumer />,
)
if (!isValid) {
throw new Error(
'You must pass a valid React context consumer as `props.context`',
)
}
ResultContext = propsContext
}
}
return ResultContext
}, [propsContext, Context])
// Retrieve the store and ancestor subscription via context, if available
const contextValue = React.useContext(ContextToUse)
// The store _must_ exist as either a prop or in context.
// We'll check to see if it _looks_ like a Redux store first.
// This allows us to pass through a `store` prop that is just a plain value.
const didStoreComeFromProps =
Boolean(props.store) &&
Boolean(props.store!.getState) &&
Boolean(props.store!.dispatch)
const didStoreComeFromContext =
Boolean(contextValue) && Boolean(contextValue!.store)
if (
process.env.NODE_ENV !== 'production' &&
!didStoreComeFromProps &&
!didStoreComeFromContext
) {
throw new Error(
`Could not find "store" in the context of ` +
`"${displayName}". Either wrap the root component in a <Provider>, ` +
`or pass a custom React context provider to <Provider> and the corresponding ` +
`React context consumer to ${displayName} in connect options.`,
)
}
// Based on the previous check, one of these must be true
const store: Store = didStoreComeFromProps
? props.store!
: contextValue!.store
const getServerState = didStoreComeFromContext
? contextValue!.getServerState
: store.getState
const childPropsSelector = React.useMemo(() => {
// The child props selector needs the store reference as an input.
// Re-create this selector whenever the store changes.
return defaultSelectorFactory(store.dispatch, selectorFactoryOptions)
}, [store])
const [subscription, notifyNestedSubs] = React.useMemo(() => {
if (!shouldHandleStateChanges) return NO_SUBSCRIPTION_ARRAY
// This Subscription's source should match where store came from: props vs. context. A component
// connected to the store via props shouldn't use subscription from context, or vice versa.
const subscription = createSubscription(
store,
didStoreComeFromProps ? undefined : contextValue!.subscription,
)
// `notifyNestedSubs` is duplicated to handle the case where the component is unmounted in
// the middle of the notification loop, where `subscription` will then be null. This can
// probably be avoided if Subscription's listeners logic is changed to not call listeners
// that have been unsubscribed in the middle of the notification loop.
const notifyNestedSubs =
subscription.notifyNestedSubs.bind(subscription)
return [subscription, notifyNestedSubs]
}, [store, didStoreComeFromProps, contextValue])
// Determine what {store, subscription} value should be put into nested context, if necessary,
// and memoize that value to avoid unnecessary context updates.
const overriddenContextValue = React.useMemo(() => {
if (didStoreComeFromProps) {
// This component is directly subscribed to a store from props.
// We don't want descendants reading from this store - pass down whatever
// the existing context value is from the nearest connected ancestor.
return contextValue!
}
// Otherwise, put this component's subscription instance into context, so that
// connected descendants won't update until after this component is done
return {
...contextValue,
subscription,
} as ReactReduxContextValue
}, [didStoreComeFromProps, contextValue, subscription])
// Set up refs to coordinate values between the subscription effect and the render logic
const lastChildProps = React.useRef<unknown>(undefined)
const lastWrapperProps = React.useRef(wrapperProps)
const childPropsFromStoreUpdate = React.useRef<unknown>(undefined)
const renderIsScheduled = React.useRef(false)
const isMounted = React.useRef(false)
// TODO: Change this to `React.useRef<Error>(undefined)` after upgrading to React 19.
/**
* @todo Change this to `React.useRef<Error>(undefined)` after upgrading to React 19.
*/
const latestSubscriptionCallbackError = React.useRef<Error | undefined>(
undefined,
)
useIsomorphicLayoutEffect(() => {
isMounted.current = true
return () => {
isMounted.current = false
}
}, [])
const actualChildPropsSelector = React.useMemo(() => {
const selector = () => {
// Tricky logic here:
// - This render may have been triggered by a Redux store update that produced new child props
// - However, we may have gotten new wrapper props after that
// If we have new child props, and the same wrapper props, we know we should use the new child props as-is.
// But, if we have new wrapper props, those might change the child props, so we have to recalculate things.
// So, we'll use the child props from store update only if the wrapper props are the same as last time.
if (
childPropsFromStoreUpdate.current &&
wrapperProps === lastWrapperProps.current
) {
return childPropsFromStoreUpdate.current
}
// TODO We're reading the store directly in render() here. Bad idea?
// This will likely cause Bad Things (TM) to happen in Concurrent Mode.
// Note that we do this because on renders _not_ caused by store updates, we need the latest store state
// to determine what the child props should be.
return childPropsSelector(store.getState(), wrapperProps)
}
return selector
}, [store, wrapperProps])
// We need this to execute synchronously every time we re-render. However, React warns
// about useLayoutEffect in SSR, so we try to detect environment and fall back to
// just useEffect instead to avoid the warning, since neither will run anyway.
const subscribeForReact = React.useMemo(() => {
const subscribe = (reactListener: () => void) => {
if (!subscription) {
return () => {}
}
return subscribeUpdates(
shouldHandleStateChanges,
store,
subscription,
// @ts-ignore
childPropsSelector,
lastWrapperProps,
lastChildProps,
renderIsScheduled,
isMounted,
childPropsFromStoreUpdate,
notifyNestedSubs,
reactListener,
)
}
return subscribe
}, [subscription])
useIsomorphicLayoutEffectWithArgs(captureWrapperProps, [
lastWrapperProps,
lastChildProps,
renderIsScheduled,
wrapperProps,
childPropsFromStoreUpdate,
notifyNestedSubs,
])
let actualChildProps: Record<string, unknown>
try {
actualChildProps = React.useSyncExternalStore(
// TODO We're passing through a big wrapper that does a bunch of extra side effects besides subscribing
subscribeForReact,
// TODO This is incredibly hacky. We've already processed the store update and calculated new child props,
// TODO and we're just passing that through so it triggers a re-render for us rather than relying on `uSES`.
actualChildPropsSelector,
getServerState
? () => childPropsSelector(getServerState(), wrapperProps)
: actualChildPropsSelector,
)
} catch (err) {
if (latestSubscriptionCallbackError.current) {
// eslint-disable-next-line no-extra-semi
;(err as Error).message +=
`\nThe error may be correlated with this previous error:\n${latestSubscriptionCallbackError.current.stack}\n\n`
}
throw err
}
useIsomorphicLayoutEffect(() => {
latestSubscriptionCallbackError.current = undefined
childPropsFromStoreUpdate.current = undefined
lastChildProps.current = actualChildProps
})
// Now that all that's done, we can finally try to actually render the child component.
// We memoize the elements for the rendered child component as an optimization.
const renderedWrappedComponent = React.useMemo(() => {
return (
// @ts-ignore
<WrappedComponent
{...actualChildProps}
ref={reactReduxForwardedRef}
/>
)
}, [reactReduxForwardedRef, WrappedComponent, actualChildProps])
// If React sees the exact same element reference as last time, it bails out of re-rendering
// that child, same as if it was wrapped in React.memo() or returned false from shouldComponentUpdate.
const renderedChild = React.useMemo(() => {
if (shouldHandleStateChanges) {
// If this component is subscribed to store updates, we need to pass its own
// subscription instance down to our descendants. That means rendering the same
// Context instance, and putting a different value into the context.
return (
<ContextToUse.Provider value={overriddenContextValue}>
{renderedWrappedComponent}
</ContextToUse.Provider>
)
}
return renderedWrappedComponent
}, [ContextToUse, renderedWrappedComponent, overriddenContextValue])
return renderedChild
}
const _Connect = React.memo(ConnectFunction)
type ConnectedWrapperComponent = typeof _Connect & {
WrappedComponent: typeof WrappedComponent
}
// Add a hacky cast to get the right output type
const Connect = _Connect as unknown as ConnectedComponent<
typeof WrappedComponent,
WrappedComponentProps
>
Connect.WrappedComponent = WrappedComponent
Connect.displayName = ConnectFunction.displayName = displayName
if (forwardRef) {
const _forwarded = React.forwardRef(
function forwardConnectRef(props, ref) {
// @ts-ignore
return <Connect {...props} reactReduxForwardedRef={ref} />
},
)
const forwarded = _forwarded as ConnectedWrapperComponent
forwarded.displayName = displayName
forwarded.WrappedComponent = WrappedComponent
return /*#__PURE__*/ hoistStatics(forwarded, WrappedComponent)
}
return /*#__PURE__*/ hoistStatics(Connect, WrappedComponent)
}
return wrapWithConnect
}
export default connect as Connect

View File

@@ -0,0 +1,14 @@
import type { Action, Dispatch } from 'redux'
export function createInvalidArgFactory(arg: unknown, name: string) {
return (
dispatch: Dispatch<Action<string>>,
options: { readonly wrappedComponentName: string },
) => {
throw new Error(
`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${
options.wrappedComponentName
}.`,
)
}
}

View File

@@ -0,0 +1,25 @@
import type { Action, Dispatch } from 'redux'
import bindActionCreators from '../utils/bindActionCreators'
import { wrapMapToPropsConstant, wrapMapToPropsFunc } from './wrapMapToProps'
import { createInvalidArgFactory } from './invalidArgFactory'
import type { MapDispatchToPropsParam } from './selectorFactory'
export function mapDispatchToPropsFactory<TDispatchProps, TOwnProps>(
mapDispatchToProps:
| MapDispatchToPropsParam<TDispatchProps, TOwnProps>
| undefined,
) {
return mapDispatchToProps && typeof mapDispatchToProps === 'object'
? wrapMapToPropsConstant((dispatch: Dispatch<Action<string>>) =>
// @ts-ignore
bindActionCreators(mapDispatchToProps, dispatch),
)
: !mapDispatchToProps
? wrapMapToPropsConstant((dispatch: Dispatch<Action<string>>) => ({
dispatch,
}))
: typeof mapDispatchToProps === 'function'
? // @ts-ignore
wrapMapToPropsFunc(mapDispatchToProps, 'mapDispatchToProps')
: createInvalidArgFactory(mapDispatchToProps, 'mapDispatchToProps')
}

View File

@@ -0,0 +1,14 @@
import { wrapMapToPropsConstant, wrapMapToPropsFunc } from './wrapMapToProps'
import { createInvalidArgFactory } from './invalidArgFactory'
import type { MapStateToPropsParam } from './selectorFactory'
export function mapStateToPropsFactory<TStateProps, TOwnProps, State>(
mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
) {
return !mapStateToProps
? wrapMapToPropsConstant(() => ({}))
: typeof mapStateToProps === 'function'
? // @ts-ignore
wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')
: createInvalidArgFactory(mapStateToProps, 'mapStateToProps')
}

View File

@@ -0,0 +1,78 @@
import type { Action, Dispatch } from 'redux'
import verifyPlainObject from '../utils/verifyPlainObject'
import { createInvalidArgFactory } from './invalidArgFactory'
import type { MergeProps } from './selectorFactory'
import type { EqualityFn } from '../types'
function defaultMergeProps<
TStateProps,
TDispatchProps,
TOwnProps,
TMergedProps,
>(
stateProps: TStateProps,
dispatchProps: TDispatchProps,
ownProps: TOwnProps,
): TMergedProps {
// @ts-ignore
return { ...ownProps, ...stateProps, ...dispatchProps }
}
function wrapMergePropsFunc<
TStateProps,
TDispatchProps,
TOwnProps,
TMergedProps,
>(
mergeProps: MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>,
): (
dispatch: Dispatch<Action<string>>,
options: {
readonly displayName: string
readonly areMergedPropsEqual: EqualityFn<TMergedProps>
},
) => MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps> {
return function initMergePropsProxy(
dispatch,
{ displayName, areMergedPropsEqual },
) {
let hasRunOnce = false
let mergedProps: TMergedProps
return function mergePropsProxy(
stateProps: TStateProps,
dispatchProps: TDispatchProps,
ownProps: TOwnProps,
) {
const nextMergedProps = mergeProps(stateProps, dispatchProps, ownProps)
if (hasRunOnce) {
if (!areMergedPropsEqual(nextMergedProps, mergedProps))
mergedProps = nextMergedProps
} else {
hasRunOnce = true
mergedProps = nextMergedProps
if (process.env.NODE_ENV !== 'production')
verifyPlainObject(mergedProps, displayName, 'mergeProps')
}
return mergedProps
}
}
}
export function mergePropsFactory<
TStateProps,
TDispatchProps,
TOwnProps,
TMergedProps,
>(
mergeProps?: MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>,
) {
return !mergeProps
? () => defaultMergeProps
: typeof mergeProps === 'function'
? wrapMergePropsFunc(mergeProps)
: createInvalidArgFactory(mergeProps, 'mergeProps')
}

View File

@@ -0,0 +1,242 @@
import type { Dispatch, Action } from 'redux'
import type { ComponentType } from 'react'
import verifySubselectors from './verifySubselectors'
import type { EqualityFn, ExtendedEqualityFn } from '../types'
export type SelectorFactory<S, TProps, TOwnProps, TFactoryOptions> = (
dispatch: Dispatch<Action<string>>,
factoryOptions: TFactoryOptions,
) => Selector<S, TProps, TOwnProps>
export type Selector<S, TProps, TOwnProps = null> = TOwnProps extends
| null
| undefined
? (state: S) => TProps
: (state: S, ownProps: TOwnProps) => TProps
export type MapStateToProps<TStateProps, TOwnProps, State> = (
state: State,
ownProps: TOwnProps,
) => TStateProps
export type MapStateToPropsFactory<TStateProps, TOwnProps, State> = (
initialState: State,
ownProps: TOwnProps,
) => MapStateToProps<TStateProps, TOwnProps, State>
export type MapStateToPropsParam<TStateProps, TOwnProps, State> =
| MapStateToPropsFactory<TStateProps, TOwnProps, State>
| MapStateToProps<TStateProps, TOwnProps, State>
| null
| undefined
export type MapDispatchToPropsFunction<TDispatchProps, TOwnProps> = (
dispatch: Dispatch<Action<string>>,
ownProps: TOwnProps,
) => TDispatchProps
export type MapDispatchToProps<TDispatchProps, TOwnProps> =
| MapDispatchToPropsFunction<TDispatchProps, TOwnProps>
| TDispatchProps
export type MapDispatchToPropsFactory<TDispatchProps, TOwnProps> = (
dispatch: Dispatch<Action<string>>,
ownProps: TOwnProps,
) => MapDispatchToPropsFunction<TDispatchProps, TOwnProps>
export type MapDispatchToPropsParam<TDispatchProps, TOwnProps> =
| MapDispatchToPropsFactory<TDispatchProps, TOwnProps>
| MapDispatchToProps<TDispatchProps, TOwnProps>
export type MapDispatchToPropsNonObject<TDispatchProps, TOwnProps> =
| MapDispatchToPropsFactory<TDispatchProps, TOwnProps>
| MapDispatchToPropsFunction<TDispatchProps, TOwnProps>
export type MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps> = (
stateProps: TStateProps,
dispatchProps: TDispatchProps,
ownProps: TOwnProps,
) => TMergedProps
interface PureSelectorFactoryComparisonOptions<TStateProps, TOwnProps, State> {
readonly areStatesEqual: ExtendedEqualityFn<State, TOwnProps>
readonly areStatePropsEqual: EqualityFn<TStateProps>
readonly areOwnPropsEqual: EqualityFn<TOwnProps>
}
function pureFinalPropsSelectorFactory<
TStateProps,
TOwnProps,
TDispatchProps,
TMergedProps,
State,
>(
mapStateToProps: WrappedMapStateToProps<TStateProps, TOwnProps, State>,
mapDispatchToProps: WrappedMapDispatchToProps<TDispatchProps, TOwnProps>,
mergeProps: MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>,
dispatch: Dispatch<Action<string>>,
{
areStatesEqual,
areOwnPropsEqual,
areStatePropsEqual,
}: PureSelectorFactoryComparisonOptions<TStateProps, TOwnProps, State>,
) {
let hasRunAtLeastOnce = false
let state: State
let ownProps: TOwnProps
let stateProps: TStateProps
let dispatchProps: TDispatchProps
let mergedProps: TMergedProps
function handleFirstCall(firstState: State, firstOwnProps: TOwnProps) {
state = firstState
ownProps = firstOwnProps
stateProps = mapStateToProps(state, ownProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
hasRunAtLeastOnce = true
return mergedProps
}
function handleNewPropsAndNewState() {
stateProps = mapStateToProps(state, ownProps)
if (mapDispatchToProps.dependsOnOwnProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
function handleNewProps() {
if (mapStateToProps.dependsOnOwnProps)
stateProps = mapStateToProps(state, ownProps)
if (mapDispatchToProps.dependsOnOwnProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
function handleNewState() {
const nextStateProps = mapStateToProps(state, ownProps)
const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps)
stateProps = nextStateProps
if (statePropsChanged)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
function handleSubsequentCalls(nextState: State, nextOwnProps: TOwnProps) {
const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps)
const stateChanged = !areStatesEqual(
nextState,
state,
nextOwnProps,
ownProps,
)
state = nextState
ownProps = nextOwnProps
if (propsChanged && stateChanged) return handleNewPropsAndNewState()
if (propsChanged) return handleNewProps()
if (stateChanged) return handleNewState()
return mergedProps
}
return function pureFinalPropsSelector(
nextState: State,
nextOwnProps: TOwnProps,
) {
return hasRunAtLeastOnce
? handleSubsequentCalls(nextState, nextOwnProps)
: handleFirstCall(nextState, nextOwnProps)
}
}
interface WrappedMapStateToProps<TStateProps, TOwnProps, State> {
(state: State, ownProps: TOwnProps): TStateProps
readonly dependsOnOwnProps: boolean
}
interface WrappedMapDispatchToProps<TDispatchProps, TOwnProps> {
(dispatch: Dispatch<Action<string>>, ownProps: TOwnProps): TDispatchProps
readonly dependsOnOwnProps: boolean
}
export interface InitOptions<TStateProps, TOwnProps, TMergedProps, State>
extends PureSelectorFactoryComparisonOptions<TStateProps, TOwnProps, State> {
readonly shouldHandleStateChanges: boolean
readonly displayName: string
readonly wrappedComponentName: string
readonly WrappedComponent: ComponentType<TOwnProps>
readonly areMergedPropsEqual: EqualityFn<TMergedProps>
}
export interface SelectorFactoryOptions<
TStateProps,
TOwnProps,
TDispatchProps,
TMergedProps,
State,
> extends InitOptions<TStateProps, TOwnProps, TMergedProps, State> {
readonly initMapStateToProps: (
dispatch: Dispatch<Action<string>>,
options: InitOptions<TStateProps, TOwnProps, TMergedProps, State>,
) => WrappedMapStateToProps<TStateProps, TOwnProps, State>
readonly initMapDispatchToProps: (
dispatch: Dispatch<Action<string>>,
options: InitOptions<TStateProps, TOwnProps, TMergedProps, State>,
) => WrappedMapDispatchToProps<TDispatchProps, TOwnProps>
readonly initMergeProps: (
dispatch: Dispatch<Action<string>>,
options: InitOptions<TStateProps, TOwnProps, TMergedProps, State>,
) => MergeProps<TStateProps, TDispatchProps, TOwnProps, TMergedProps>
}
// TODO: Add more comments
// The selector returned by selectorFactory will memoize its results,
// allowing connect's shouldComponentUpdate to return false if final
// props have not changed.
export default function finalPropsSelectorFactory<
TStateProps,
TOwnProps,
TDispatchProps,
TMergedProps,
State,
>(
dispatch: Dispatch<Action<string>>,
{
initMapStateToProps,
initMapDispatchToProps,
initMergeProps,
...options
}: SelectorFactoryOptions<
TStateProps,
TOwnProps,
TDispatchProps,
TMergedProps,
State
>,
) {
const mapStateToProps = initMapStateToProps(dispatch, options)
const mapDispatchToProps = initMapDispatchToProps(dispatch, options)
const mergeProps = initMergeProps(dispatch, options)
if (process.env.NODE_ENV !== 'production') {
verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps)
}
return pureFinalPropsSelectorFactory<
TStateProps,
TOwnProps,
TDispatchProps,
TMergedProps,
State
>(mapStateToProps, mapDispatchToProps, mergeProps, dispatch, options)
}

View File

@@ -0,0 +1,26 @@
import warning from '../utils/warning'
function verify(selector: unknown, methodName: string): void {
if (!selector) {
throw new Error(`Unexpected value for ${methodName} in connect.`)
} else if (
methodName === 'mapStateToProps' ||
methodName === 'mapDispatchToProps'
) {
if (!Object.prototype.hasOwnProperty.call(selector, 'dependsOnOwnProps')) {
warning(
`The selector for ${methodName} of connect did not specify a value for dependsOnOwnProps.`,
)
}
}
}
export default function verifySubselectors(
mapStateToProps: unknown,
mapDispatchToProps: unknown,
mergeProps: unknown,
): void {
verify(mapStateToProps, 'mapStateToProps')
verify(mapDispatchToProps, 'mapDispatchToProps')
verify(mergeProps, 'mergeProps')
}

View File

@@ -0,0 +1,110 @@
import type { ActionCreatorsMapObject, Dispatch, ActionCreator } from 'redux'
import type { FixTypeLater } from '../types'
import verifyPlainObject from '../utils/verifyPlainObject'
type AnyState = { [key: string]: any }
type StateOrDispatch<S extends AnyState = AnyState> = S | Dispatch
type AnyProps = { [key: string]: any }
export type MapToProps<P extends AnyProps = AnyProps> = {
// eslint-disable-next-line no-unused-vars
(stateOrDispatch: StateOrDispatch, ownProps?: P): FixTypeLater
dependsOnOwnProps?: boolean
}
export function wrapMapToPropsConstant(
// * Note:
// It seems that the dispatch argument
// could be a dispatch function in some cases (ex: whenMapDispatchToPropsIsMissing)
// and a state object in some others (ex: whenMapStateToPropsIsMissing)
// eslint-disable-next-line no-unused-vars
getConstant: (dispatch: Dispatch) =>
| {
dispatch?: Dispatch
dependsOnOwnProps?: boolean
}
| ActionCreatorsMapObject
| ActionCreator<any>,
) {
return function initConstantSelector(dispatch: Dispatch) {
const constant = getConstant(dispatch)
function constantSelector() {
return constant
}
constantSelector.dependsOnOwnProps = false
return constantSelector
}
}
// dependsOnOwnProps is used by createMapToPropsProxy to determine whether to pass props as args
// to the mapToProps function being wrapped. It is also used by makePurePropsSelector to determine
// whether mapToProps needs to be invoked when props have changed.
//
// A length of one signals that mapToProps does not depend on props from the parent component.
// A length of zero is assumed to mean mapToProps is getting args via arguments or ...args and
// therefore not reporting its length accurately..
// TODO Can this get pulled out so that we can subscribe directly to the store if we don't need ownProps?
function getDependsOnOwnProps(mapToProps: MapToProps) {
return mapToProps.dependsOnOwnProps
? Boolean(mapToProps.dependsOnOwnProps)
: mapToProps.length !== 1
}
// Used by whenMapStateToPropsIsFunction and whenMapDispatchToPropsIsFunction,
// this function wraps mapToProps in a proxy function which does several things:
//
// * Detects whether the mapToProps function being called depends on props, which
// is used by selectorFactory to decide if it should reinvoke on props changes.
//
// * On first call, handles mapToProps if returns another function, and treats that
// new function as the true mapToProps for subsequent calls.
//
// * On first call, verifies the first result is a plain object, in order to warn
// the developer that their mapToProps function is not returning a valid result.
//
export function wrapMapToPropsFunc<P extends AnyProps = AnyProps>(
mapToProps: MapToProps,
methodName: string,
) {
return function initProxySelector(
dispatch: Dispatch,
{ displayName }: { displayName: string },
) {
const proxy = function mapToPropsProxy(
stateOrDispatch: StateOrDispatch,
ownProps?: P,
): MapToProps {
return proxy.dependsOnOwnProps
? proxy.mapToProps(stateOrDispatch, ownProps)
: proxy.mapToProps(stateOrDispatch, undefined)
}
// allow detectFactoryAndVerify to get ownProps
proxy.dependsOnOwnProps = true
proxy.mapToProps = function detectFactoryAndVerify(
stateOrDispatch: StateOrDispatch,
ownProps?: P,
): MapToProps {
proxy.mapToProps = mapToProps
proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps)
let props = proxy(stateOrDispatch, ownProps)
if (typeof props === 'function') {
proxy.mapToProps = props
proxy.dependsOnOwnProps = getDependsOnOwnProps(props)
props = proxy(stateOrDispatch, ownProps)
}
if (process.env.NODE_ENV !== 'production')
verifyPlainObject(props, displayName, methodName)
return props
}
return proxy
}
}

51
frontend/node_modules/react-redux/src/exports.ts generated vendored Normal file
View File

@@ -0,0 +1,51 @@
import connect from './components/connect'
export type {
Connect,
ConnectProps,
ConnectedProps,
} from './components/connect'
import shallowEqual from './utils/shallowEqual'
import Provider from './components/Provider'
import { defaultNoopBatch } from './utils/batch'
export { ReactReduxContext } from './components/Context'
export type { ReactReduxContextValue } from './components/Context'
export type { ProviderProps } from './components/Provider'
export type {
MapDispatchToProps,
MapDispatchToPropsFactory,
MapDispatchToPropsFunction,
MapDispatchToPropsNonObject,
MapDispatchToPropsParam,
MapStateToProps,
MapStateToPropsFactory,
MapStateToPropsParam,
MergeProps,
Selector,
SelectorFactory,
} from './connect/selectorFactory'
export { createDispatchHook, useDispatch } from './hooks/useDispatch'
export type { UseDispatch } from './hooks/useDispatch'
export { createSelectorHook, useSelector } from './hooks/useSelector'
export type { UseSelector } from './hooks/useSelector'
export { createStoreHook, useStore } from './hooks/useStore'
export type { UseStore } from './hooks/useStore'
export type { Subscription } from './utils/Subscription'
export * from './types'
/**
* @deprecated As of React 18, batching is enabled by default for ReactDOM and React Native.
* This is now a no-op that immediately runs the callback.
*/
const batch = defaultNoopBatch
export { Provider, batch, connect, shallowEqual }

View File

@@ -0,0 +1,104 @@
import type { Context } from 'react'
import type { Action, Dispatch, UnknownAction } from 'redux'
import type { ReactReduxContextValue } from '../components/Context'
import { ReactReduxContext } from '../components/Context'
import { createStoreHook, useStore as useDefaultStore } from './useStore'
/**
* Represents a custom hook that provides a dispatch function
* from the Redux store.
*
* @template DispatchType - The specific type of the dispatch function.
*
* @since 9.1.0
* @public
*/
export interface UseDispatch<
DispatchType extends Dispatch<UnknownAction> = Dispatch<UnknownAction>,
> {
/**
* Returns the dispatch function from the Redux store.
*
* @returns The dispatch function from the Redux store.
*
* @template AppDispatch - The specific type of the dispatch function.
*/
<AppDispatch extends DispatchType = DispatchType>(): AppDispatch
/**
* Creates a "pre-typed" version of {@linkcode useDispatch useDispatch}
* where the type of the `dispatch` function is predefined.
*
* This allows you to set the `dispatch` type once, eliminating the need to
* specify it with every {@linkcode useDispatch useDispatch} call.
*
* @returns A pre-typed `useDispatch` with the dispatch type already defined.
*
* @example
* ```ts
* export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
* ```
*
* @template OverrideDispatchType - The specific type of the dispatch function.
*
* @since 9.1.0
*/
withTypes: <
OverrideDispatchType extends DispatchType,
>() => UseDispatch<OverrideDispatchType>
}
/**
* Hook factory, which creates a `useDispatch` hook bound to a given context.
*
* @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
* @returns {Function} A `useDispatch` hook bound to the specified context.
*/
export function createDispatchHook<
StateType = unknown,
ActionType extends Action = UnknownAction,
>(
// @ts-ignore
context?: Context<ReactReduxContextValue<
StateType,
ActionType
> | null> = ReactReduxContext,
) {
const useStore =
context === ReactReduxContext ? useDefaultStore : createStoreHook(context)
const useDispatch = () => {
const store = useStore()
return store.dispatch
}
Object.assign(useDispatch, {
withTypes: () => useDispatch,
})
return useDispatch as UseDispatch<Dispatch<ActionType>>
}
/**
* A hook to access the redux `dispatch` function.
*
* @returns {any|function} redux store's `dispatch` function
*
* @example
*
* import React, { useCallback } from 'react'
* import { useDispatch } from 'react-redux'
*
* export const CounterComponent = ({ value }) => {
* const dispatch = useDispatch()
* const increaseCounter = useCallback(() => dispatch({ type: 'increase-counter' }), [])
* return (
* <div>
* <span>{value}</span>
* <button onClick={increaseCounter}>Increase counter</button>
* </div>
* )
* }
*/
export const useDispatch = /*#__PURE__*/ createDispatchHook()

View File

@@ -0,0 +1,42 @@
import { React } from '../utils/react'
import { ReactReduxContext } from '../components/Context'
import type { ReactReduxContextValue } from '../components/Context'
/**
* Hook factory, which creates a `useReduxContext` hook bound to a given context. This is a low-level
* hook that you should usually not need to call directly.
*
* @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
* @returns {Function} A `useReduxContext` hook bound to the specified context.
*/
export function createReduxContextHook(context = ReactReduxContext) {
return function useReduxContext(): ReactReduxContextValue {
const contextValue = React.useContext(context)
if (process.env.NODE_ENV !== 'production' && !contextValue) {
throw new Error(
'could not find react-redux context value; please ensure the component is wrapped in a <Provider>',
)
}
return contextValue!
}
}
/**
* A hook to access the value of the `ReactReduxContext`. This is a low-level
* hook that you should usually not need to call directly.
*
* @returns {any} the value of the `ReactReduxContext`
*
* @example
*
* import React from 'react'
* import { useReduxContext } from 'react-redux'
*
* export const CounterComponent = () => {
* const { store } = useReduxContext()
* return <div>{store.getState()}</div>
* }
*/
export const useReduxContext = /*#__PURE__*/ createReduxContextHook()

View File

@@ -0,0 +1,286 @@
//import * as React from 'react'
import { React } from '../utils/react'
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector.js'
import type { ReactReduxContextValue } from '../components/Context'
import { ReactReduxContext } from '../components/Context'
import type { EqualityFn, NoInfer } from '../types'
import {
createReduxContextHook,
useReduxContext as useDefaultReduxContext,
} from './useReduxContext'
/**
* The frequency of development mode checks.
*
* @since 8.1.0
* @internal
*/
export type DevModeCheckFrequency = 'never' | 'once' | 'always'
/**
* Represents the configuration for development mode checks.
*
* @since 9.0.0
* @internal
*/
export interface DevModeChecks {
/**
* Overrides the global stability check for the selector.
* - `once` - Run only the first time the selector is called.
* - `always` - Run every time the selector is called.
* - `never` - Never run the stability check.
*
* @default 'once'
*
* @since 8.1.0
*/
stabilityCheck: DevModeCheckFrequency
/**
* Overrides the global identity function check for the selector.
* - `once` - Run only the first time the selector is called.
* - `always` - Run every time the selector is called.
* - `never` - Never run the identity function check.
*
* **Note**: Previously referred to as `noopCheck`.
*
* @default 'once'
*
* @since 9.0.0
*/
identityFunctionCheck: DevModeCheckFrequency
}
export interface UseSelectorOptions<Selected = unknown> {
equalityFn?: EqualityFn<Selected>
/**
* `useSelector` performs additional checks in development mode to help
* identify and warn about potential issues in selector behavior. This
* option allows you to customize the behavior of these checks per selector.
*
* @since 9.0.0
*/
devModeChecks?: Partial<DevModeChecks>
}
/**
* Represents a custom hook that allows you to extract data from the
* Redux store state, using a selector function. The selector function
* takes the current state as an argument and returns a part of the state
* or some derived data. The hook also supports an optional equality
* function or options object to customize its behavior.
*
* @template StateType - The specific type of state this hook operates on.
*
* @public
*/
export interface UseSelector<StateType = unknown> {
/**
* A function that takes a selector function as its first argument.
* The selector function is responsible for selecting a part of
* the Redux store's state or computing derived data.
*
* @param selector - A function that receives the current state and returns a part of the state or some derived data.
* @param equalityFnOrOptions - An optional equality function or options object for customizing the behavior of the selector.
* @returns The selected part of the state or derived data.
*
* @template TState - The specific type of state this hook operates on.
* @template Selected - The type of the value that the selector function will return.
*/
<TState extends StateType = StateType, Selected = unknown>(
selector: (state: TState) => Selected,
equalityFnOrOptions?: EqualityFn<Selected> | UseSelectorOptions<Selected>,
): Selected
/**
* Creates a "pre-typed" version of {@linkcode useSelector useSelector}
* where the `state` type is predefined.
*
* This allows you to set the `state` type once, eliminating the need to
* specify it with every {@linkcode useSelector useSelector} call.
*
* @returns A pre-typed `useSelector` with the state type already defined.
*
* @example
* ```ts
* export const useAppSelector = useSelector.withTypes<RootState>()
* ```
*
* @template OverrideStateType - The specific type of state this hook operates on.
*
* @since 9.1.0
*/
withTypes: <
OverrideStateType extends StateType,
>() => UseSelector<OverrideStateType>
}
const refEquality: EqualityFn<any> = (a, b) => a === b
/**
* Hook factory, which creates a `useSelector` hook bound to a given context.
*
* @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
* @returns {Function} A `useSelector` hook bound to the specified context.
*/
export function createSelectorHook(
context: React.Context<ReactReduxContextValue<
any,
any
> | null> = ReactReduxContext,
): UseSelector {
const useReduxContext =
context === ReactReduxContext
? useDefaultReduxContext
: createReduxContextHook(context)
const useSelector = <TState, Selected>(
selector: (state: TState) => Selected,
equalityFnOrOptions:
| EqualityFn<NoInfer<Selected>>
| UseSelectorOptions<NoInfer<Selected>> = {},
): Selected => {
const { equalityFn = refEquality } =
typeof equalityFnOrOptions === 'function'
? { equalityFn: equalityFnOrOptions }
: equalityFnOrOptions
if (process.env.NODE_ENV !== 'production') {
if (!selector) {
throw new Error(`You must pass a selector to useSelector`)
}
if (typeof selector !== 'function') {
throw new Error(`You must pass a function as a selector to useSelector`)
}
if (typeof equalityFn !== 'function') {
throw new Error(
`You must pass a function as an equality function to useSelector`,
)
}
}
const reduxContext = useReduxContext()
const { store, subscription, getServerState } = reduxContext
const firstRun = React.useRef(true)
const wrappedSelector = React.useCallback<typeof selector>(
{
[selector.name](state: TState) {
const selected = selector(state)
if (process.env.NODE_ENV !== 'production') {
const { devModeChecks = {} } =
typeof equalityFnOrOptions === 'function'
? {}
: equalityFnOrOptions
const { identityFunctionCheck, stabilityCheck } = reduxContext
const {
identityFunctionCheck: finalIdentityFunctionCheck,
stabilityCheck: finalStabilityCheck,
} = {
stabilityCheck,
identityFunctionCheck,
...devModeChecks,
}
if (
finalStabilityCheck === 'always' ||
(finalStabilityCheck === 'once' && firstRun.current)
) {
const toCompare = selector(state)
if (!equalityFn(selected, toCompare)) {
let stack: string | undefined = undefined
try {
throw new Error()
} catch (e) {
// eslint-disable-next-line no-extra-semi
;({ stack } = e as Error)
}
console.warn(
'Selector ' +
(selector.name || 'unknown') +
' returned a different result when called with the same parameters. This can lead to unnecessary rerenders.' +
'\nSelectors that return a new reference (such as an object or an array) should be memoized: https://redux.js.org/usage/deriving-data-selectors#optimizing-selectors-with-memoization',
{
state,
selected,
selected2: toCompare,
stack,
},
)
}
}
if (
finalIdentityFunctionCheck === 'always' ||
(finalIdentityFunctionCheck === 'once' && firstRun.current)
) {
// @ts-ignore
if (selected === state) {
let stack: string | undefined = undefined
try {
throw new Error()
} catch (e) {
// eslint-disable-next-line no-extra-semi
;({ stack } = e as Error)
}
console.warn(
'Selector ' +
(selector.name || 'unknown') +
' returned the root state when called. This can lead to unnecessary rerenders.' +
'\nSelectors that return the entire state are almost certainly a mistake, as they will cause a rerender whenever *anything* in state changes.',
{ stack },
)
}
}
if (firstRun.current) firstRun.current = false
}
return selected
},
}[selector.name],
[selector],
)
const selectedState = useSyncExternalStoreWithSelector(
subscription.addNestedSub,
store.getState,
getServerState || store.getState,
wrappedSelector,
equalityFn,
)
React.useDebugValue(selectedState)
return selectedState
}
Object.assign(useSelector, {
withTypes: () => useSelector,
})
return useSelector as UseSelector
}
/**
* A hook to access the redux store's state. This hook takes a selector function
* as an argument. The selector is called with the store state.
*
* This hook takes an optional equality comparison function as the second parameter
* that allows you to customize the way the selected state is compared to determine
* whether the component needs to be re-rendered.
*
* @param {Function} selector the selector function
* @param {Function=} equalityFn the function that will be used to determine equality
*
* @returns {any} the selected state
*
* @example
*
* import React from 'react'
* import { useSelector } from 'react-redux'
*
* export const CounterComponent = () => {
* const counter = useSelector(state => state.counter)
* return <div>{counter}</div>
* }
*/
export const useSelector = /*#__PURE__*/ createSelectorHook()

123
frontend/node_modules/react-redux/src/hooks/useStore.ts generated vendored Normal file
View File

@@ -0,0 +1,123 @@
import type { Context } from 'react'
import type { Action, Store } from 'redux'
import type { ReactReduxContextValue } from '../components/Context'
import { ReactReduxContext } from '../components/Context'
import {
createReduxContextHook,
useReduxContext as useDefaultReduxContext,
} from './useReduxContext'
/**
* Represents a type that extracts the action type from a given Redux store.
*
* @template StoreType - The specific type of the Redux store.
*
* @since 9.1.0
* @internal
*/
export type ExtractStoreActionType<StoreType extends Store> =
StoreType extends Store<any, infer ActionType> ? ActionType : never
/**
* Represents a custom hook that provides access to the Redux store.
*
* @template StoreType - The specific type of the Redux store that gets returned.
*
* @since 9.1.0
* @public
*/
export interface UseStore<StoreType extends Store> {
/**
* Returns the Redux store instance.
*
* @returns The Redux store instance.
*/
(): StoreType
/**
* Returns the Redux store instance with specific state and action types.
*
* @returns The Redux store with the specified state and action types.
*
* @template StateType - The specific type of the state used in the store.
* @template ActionType - The specific type of the actions used in the store.
*/
<
StateType extends ReturnType<StoreType['getState']> = ReturnType<
StoreType['getState']
>,
ActionType extends Action = ExtractStoreActionType<Store>,
>(): Store<StateType, ActionType>
/**
* Creates a "pre-typed" version of {@linkcode useStore useStore}
* where the type of the Redux `store` is predefined.
*
* This allows you to set the `store` type once, eliminating the need to
* specify it with every {@linkcode useStore useStore} call.
*
* @returns A pre-typed `useStore` with the store type already defined.
*
* @example
* ```ts
* export const useAppStore = useStore.withTypes<AppStore>()
* ```
*
* @template OverrideStoreType - The specific type of the Redux store that gets returned.
*
* @since 9.1.0
*/
withTypes: <
OverrideStoreType extends StoreType,
>() => UseStore<OverrideStoreType>
}
/**
* Hook factory, which creates a `useStore` hook bound to a given context.
*
* @param {React.Context} [context=ReactReduxContext] Context passed to your `<Provider>`.
* @returns {Function} A `useStore` hook bound to the specified context.
*/
export function createStoreHook<
StateType = unknown,
ActionType extends Action = Action,
>(
// @ts-ignore
context?: Context<ReactReduxContextValue<
StateType,
ActionType
> | null> = ReactReduxContext,
) {
const useReduxContext =
context === ReactReduxContext
? useDefaultReduxContext
: // @ts-ignore
createReduxContextHook(context)
const useStore = () => {
const { store } = useReduxContext()
return store
}
Object.assign(useStore, {
withTypes: () => useStore,
})
return useStore as UseStore<Store<StateType, ActionType>>
}
/**
* A hook to access the redux store.
*
* @returns {any} the redux store
*
* @example
*
* import React from 'react'
* import { useStore } from 'react-redux'
*
* export const ExampleComponent = () => {
* const store = useStore()
* return <div>{store.getState()}</div>
* }
*/
export const useStore = /*#__PURE__*/ createStoreHook()

34
frontend/node_modules/react-redux/src/index-rsc.ts generated vendored Normal file
View File

@@ -0,0 +1,34 @@
import type * as normal from './index'
import type * as rsc from './index-rsc'
// checks to make sure we didn't forgot to replicate any exports
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _check: typeof normal = {} as typeof rsc
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _check2: typeof rsc = {} as typeof normal
// -------------------------------------------------------------------------------------
const throwNotSupportedError = ((
// eslint-disable-next-line @typescript-eslint/no-unused-vars
...args: any[]
): any => {
throw new Error(
'This function is not supported in React Server Components. Please only use this export in a Client Component.',
)
}) as any
export {
throwNotSupportedError as Provider,
throwNotSupportedError as batch,
throwNotSupportedError as connect,
throwNotSupportedError as createDispatchHook,
throwNotSupportedError as createSelectorHook,
throwNotSupportedError as createStoreHook,
throwNotSupportedError as useDispatch,
throwNotSupportedError as useSelector,
throwNotSupportedError as useStore,
}
export const ReactReduxContext = {} as any
export { default as shallowEqual } from './utils/shallowEqual'

1
frontend/node_modules/react-redux/src/index.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export * from './exports'

180
frontend/node_modules/react-redux/src/types.ts generated vendored Normal file
View File

@@ -0,0 +1,180 @@
import type {
ClassAttributes,
ComponentClass,
ComponentType,
FunctionComponent,
JSX,
} from 'react'
import type { Action, UnknownAction, Dispatch } from 'redux'
import type { NonReactStatics } from './utils/hoistStatics'
import type { ConnectProps } from './components/connect'
import type { UseSelectorOptions } from './hooks/useSelector'
export type FixTypeLater = any
export type EqualityFn<T> = (a: T, b: T) => boolean
export type ExtendedEqualityFn<T, P> = (a: T, b: T, c: P, d: P) => boolean
export type AnyIfEmpty<T extends object> = keyof T extends never ? any : T
export type DistributiveOmit<T, K extends keyof T> = T extends unknown
? Omit<T, K>
: never
export interface DispatchProp<A extends Action<string> = UnknownAction> {
dispatch: Dispatch<A>
}
/**
* A property P will be present if:
* - it is present in DecorationTargetProps
*
* Its value will be dependent on the following conditions
* - if property P is present in InjectedProps and its definition extends the definition
* in DecorationTargetProps, then its definition will be that of DecorationTargetProps[P]
* - if property P is not present in InjectedProps then its definition will be that of
* DecorationTargetProps[P]
* - if property P is present in InjectedProps but does not extend the
* DecorationTargetProps[P] definition, its definition will be that of InjectedProps[P]
*/
export type Matching<InjectedProps, DecorationTargetProps> = {
[P in keyof DecorationTargetProps]: P extends keyof InjectedProps
? InjectedProps[P] extends DecorationTargetProps[P]
? DecorationTargetProps[P]
: InjectedProps[P]
: DecorationTargetProps[P]
}
/**
* a property P will be present if :
* - it is present in both DecorationTargetProps and InjectedProps
* - InjectedProps[P] can satisfy DecorationTargetProps[P]
* ie: decorated component can accept more types than decorator is injecting
*
* For decoration, inject props or ownProps are all optionally
* required by the decorated (right hand side) component.
* But any property required by the decorated component must be satisfied by the injected property.
*/
export type Shared<InjectedProps, DecorationTargetProps> = {
[P in Extract<
keyof InjectedProps,
keyof DecorationTargetProps
>]?: InjectedProps[P] extends DecorationTargetProps[P]
? DecorationTargetProps[P]
: never
}
// Infers prop type from component C
export type GetProps<C> =
C extends ComponentType<infer P>
? C extends ComponentClass<P>
? ClassAttributes<InstanceType<C>> & P
: P
: never
// Applies LibraryManagedAttributes (proper handling of defaultProps
// and propTypes).
export type GetLibraryManagedProps<C> = JSX.LibraryManagedAttributes<
C,
GetProps<C>
>
// Applies LibraryManagedAttributes (proper handling of defaultProps
// and propTypes), as well as defines WrappedComponent.
export type ConnectedComponent<
C extends ComponentType<any>,
P,
> = FunctionComponent<P> &
NonReactStatics<C> & {
WrappedComponent: C
}
export type ConnectPropsMaybeWithoutContext<TActualOwnProps> =
TActualOwnProps extends { context: any }
? Omit<ConnectProps, 'context'>
: ConnectProps
type Identity<T> = T
export type Mapped<T> = Identity<{ [k in keyof T]: T[k] }>
// Injects props and removes them from the prop requirements.
// Will not pass through the injected props if they are passed in during
// render. Also adds new prop requirements from TNeedsProps.
// Uses distributive omit to preserve discriminated unions part of original prop type.
// Note> Most of the time TNeedsProps is empty, because the overloads in `Connect`
// just pass in `{}`. The real props we need come from the component.
export type InferableComponentEnhancerWithProps<TInjectedProps, TNeedsProps> = <
C extends ComponentType<Matching<TInjectedProps, GetProps<C>>>,
>(
component: C,
) => ConnectedComponent<
C,
Mapped<
DistributiveOmit<
GetLibraryManagedProps<C>,
keyof Shared<TInjectedProps, GetLibraryManagedProps<C>>
> &
TNeedsProps &
ConnectPropsMaybeWithoutContext<TNeedsProps & GetProps<C>>
>
>
// Injects props and removes them from the prop requirements.
// Will not pass through the injected props if they are passed in during
// render.
export type InferableComponentEnhancer<TInjectedProps> =
InferableComponentEnhancerWithProps<TInjectedProps, {}>
export type InferThunkActionCreatorType<
TActionCreator extends (...args: any[]) => any,
> = TActionCreator extends (
...args: infer TParams
) => (...args: any[]) => infer TReturn
? (...args: TParams) => TReturn
: TActionCreator
export type HandleThunkActionCreator<TActionCreator> = TActionCreator extends (
...args: any[]
) => any
? InferThunkActionCreatorType<TActionCreator>
: TActionCreator
// redux-thunk middleware returns thunk's return value from dispatch call
// https://github.com/reduxjs/redux-thunk#composition
export type ResolveThunks<TDispatchProps> = TDispatchProps extends {
[key: string]: any
}
? {
[C in keyof TDispatchProps]: HandleThunkActionCreator<TDispatchProps[C]>
}
: TDispatchProps
/**
* This interface allows you to easily create a hook that is properly typed for your
* store's root state.
*
* @example
*
* interface RootState {
* property: string;
* }
*
* const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
*/
export interface TypedUseSelectorHook<TState> {
<TSelected>(
selector: (state: TState) => TSelected,
equalityFn?: EqualityFn<NoInfer<TSelected>>,
): TSelected
<Selected = unknown>(
selector: (state: TState) => Selected,
options?: UseSelectorOptions<Selected>,
): Selected
}
export type NoInfer<T> = [T][T extends any ? 0 : never]

View File

@@ -0,0 +1,183 @@
import { defaultNoopBatch as batch } from './batch'
// encapsulates the subscription logic for connecting a component to the redux store, as
// well as nesting subscriptions of descendant components, so that we can ensure the
// ancestor components re-render before descendants
type VoidFunc = () => void
type Listener = {
callback: VoidFunc
next: Listener | null
prev: Listener | null
}
function createListenerCollection() {
let first: Listener | null = null
let last: Listener | null = null
return {
clear() {
first = null
last = null
},
notify() {
batch(() => {
let listener = first
while (listener) {
listener.callback()
listener = listener.next
}
})
},
get() {
const listeners: Listener[] = []
let listener = first
while (listener) {
listeners.push(listener)
listener = listener.next
}
return listeners
},
subscribe(callback: () => void) {
let isSubscribed = true
const listener: Listener = (last = {
callback,
next: null,
prev: last,
})
if (listener.prev) {
listener.prev.next = listener
} else {
first = listener
}
return function unsubscribe() {
if (!isSubscribed || first === null) return
isSubscribed = false
if (listener.next) {
listener.next.prev = listener.prev
} else {
last = listener.prev
}
if (listener.prev) {
listener.prev.next = listener.next
} else {
first = listener.next
}
}
},
}
}
type ListenerCollection = ReturnType<typeof createListenerCollection>
export interface Subscription {
addNestedSub: (listener: VoidFunc) => VoidFunc
notifyNestedSubs: VoidFunc
handleChangeWrapper: VoidFunc
isSubscribed: () => boolean
onStateChange?: VoidFunc | null
trySubscribe: VoidFunc
tryUnsubscribe: VoidFunc
getListeners: () => ListenerCollection
}
const nullListeners = {
notify() {},
get: () => [],
} as unknown as ListenerCollection
export function createSubscription(store: any, parentSub?: Subscription) {
let unsubscribe: VoidFunc | undefined
let listeners: ListenerCollection = nullListeners
// Reasons to keep the subscription active
let subscriptionsAmount = 0
// Is this specific subscription subscribed (or only nested ones?)
let selfSubscribed = false
function addNestedSub(listener: () => void) {
trySubscribe()
const cleanupListener = listeners.subscribe(listener)
// cleanup nested sub
let removed = false
return () => {
if (!removed) {
removed = true
cleanupListener()
tryUnsubscribe()
}
}
}
function notifyNestedSubs() {
listeners.notify()
}
function handleChangeWrapper() {
if (subscription.onStateChange) {
subscription.onStateChange()
}
}
function isSubscribed() {
return selfSubscribed
}
function trySubscribe() {
subscriptionsAmount++
if (!unsubscribe) {
unsubscribe = parentSub
? parentSub.addNestedSub(handleChangeWrapper)
: store.subscribe(handleChangeWrapper)
listeners = createListenerCollection()
}
}
function tryUnsubscribe() {
subscriptionsAmount--
if (unsubscribe && subscriptionsAmount === 0) {
unsubscribe()
unsubscribe = undefined
listeners.clear()
listeners = nullListeners
}
}
function trySubscribeSelf() {
if (!selfSubscribed) {
selfSubscribed = true
trySubscribe()
}
}
function tryUnsubscribeSelf() {
if (selfSubscribed) {
selfSubscribed = false
tryUnsubscribe()
}
}
const subscription: Subscription = {
addNestedSub,
notifyNestedSubs,
handleChangeWrapper,
isSubscribed,
trySubscribe: trySubscribeSelf,
tryUnsubscribe: tryUnsubscribeSelf,
getListeners: () => listeners,
}
return subscription
}

4
frontend/node_modules/react-redux/src/utils/batch.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
// Default to a dummy "batch" implementation that just runs the callback
export function defaultNoopBatch(callback: () => void) {
callback()
}

View File

@@ -0,0 +1,16 @@
import type { ActionCreatorsMapObject, Dispatch } from 'redux'
export default function bindActionCreators(
actionCreators: ActionCreatorsMapObject,
dispatch: Dispatch,
): ActionCreatorsMapObject {
const boundActionCreators: ActionCreatorsMapObject = {}
for (const key in actionCreators) {
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = (...args) => dispatch(actionCreator(...args))
}
}
return boundActionCreators
}

View File

@@ -0,0 +1,139 @@
// Copied directly from:
// https://github.com/mridgway/hoist-non-react-statics/blob/main/src/index.js
// https://unpkg.com/browse/@types/hoist-non-react-statics@3.3.6/index.d.ts
/**
* Copyright 2015, Yahoo! Inc.
* Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
*/
import type { ForwardRefExoticComponent, MemoExoticComponent } from 'react'
import { ForwardRef, Memo, isMemo } from '../utils/react-is'
const REACT_STATICS = {
childContextTypes: true,
contextType: true,
contextTypes: true,
defaultProps: true,
displayName: true,
getDefaultProps: true,
getDerivedStateFromError: true,
getDerivedStateFromProps: true,
mixins: true,
propTypes: true,
type: true,
} as const
const KNOWN_STATICS = {
name: true,
length: true,
prototype: true,
caller: true,
callee: true,
arguments: true,
arity: true,
} as const
const FORWARD_REF_STATICS = {
$$typeof: true,
render: true,
defaultProps: true,
displayName: true,
propTypes: true,
} as const
const MEMO_STATICS = {
$$typeof: true,
compare: true,
defaultProps: true,
displayName: true,
propTypes: true,
type: true,
} as const
const TYPE_STATICS = {
[ForwardRef]: FORWARD_REF_STATICS,
[Memo]: MEMO_STATICS,
} as const
function getStatics(component: any) {
// React v16.11 and below
if (isMemo(component)) {
return MEMO_STATICS
}
// React v16.12 and above
return TYPE_STATICS[component['$$typeof']] || REACT_STATICS
}
export type NonReactStatics<
Source,
C extends {
[key: string]: true
} = {},
> = {
[key in Exclude<
keyof Source,
Source extends MemoExoticComponent<any>
? keyof typeof MEMO_STATICS | keyof C
: Source extends ForwardRefExoticComponent<any>
? keyof typeof FORWARD_REF_STATICS | keyof C
: keyof typeof REACT_STATICS | keyof typeof KNOWN_STATICS | keyof C
>]: Source[key]
}
const defineProperty = Object.defineProperty
const getOwnPropertyNames = Object.getOwnPropertyNames
const getOwnPropertySymbols = Object.getOwnPropertySymbols
const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor
const getPrototypeOf = Object.getPrototypeOf
const objectPrototype = Object.prototype
export default function hoistNonReactStatics<
Target,
Source,
CustomStatic extends {
[key: string]: true
} = {},
>(
targetComponent: Target,
sourceComponent: Source,
): Target & NonReactStatics<Source, CustomStatic> {
if (typeof sourceComponent !== 'string') {
// don't hoist over string (html) components
if (objectPrototype) {
const inheritedComponent = getPrototypeOf(sourceComponent)
if (inheritedComponent && inheritedComponent !== objectPrototype) {
hoistNonReactStatics(targetComponent, inheritedComponent)
}
}
let keys: (string | symbol)[] = getOwnPropertyNames(sourceComponent)
if (getOwnPropertySymbols) {
keys = keys.concat(getOwnPropertySymbols(sourceComponent))
}
const targetStatics = getStatics(targetComponent)
const sourceStatics = getStatics(sourceComponent)
for (let i = 0; i < keys.length; ++i) {
const key = keys[i]
if (
!KNOWN_STATICS[key as keyof typeof KNOWN_STATICS] &&
!(sourceStatics && sourceStatics[key as keyof typeof sourceStatics]) &&
!(targetStatics && targetStatics[key as keyof typeof targetStatics])
) {
const descriptor = getOwnPropertyDescriptor(sourceComponent, key)
try {
// Avoid failures from read-only properties
defineProperty(targetComponent, key, descriptor!)
} catch (e) {
// ignore
}
}
}
}
return targetComponent as any
}

View File

@@ -0,0 +1,17 @@
/**
* @param {any} obj The object to inspect.
* @returns {boolean} True if the argument appears to be a plain object.
*/
export default function isPlainObject(obj: unknown) {
if (typeof obj !== 'object' || obj === null) return false
const proto = Object.getPrototypeOf(obj)
if (proto === null) return true
let baseProto = proto
while (Object.getPrototypeOf(baseProto) !== null) {
baseProto = Object.getPrototypeOf(baseProto)
}
return proto === baseProto
}

View File

@@ -0,0 +1,97 @@
import type { ElementType, MemoExoticComponent, ReactElement } from 'react'
import { React } from './react'
// Directly ported from:
// https://unpkg.com/browse/react-is@19.0.0/cjs/react-is.production.js
// It's very possible this could change in the future, but given that
// we only use these in `connect`, this is a low priority.
export const IS_REACT_19 = /* @__PURE__ */ React.version.startsWith('19')
const REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for(
IS_REACT_19 ? 'react.transitional.element' : 'react.element',
)
const REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for('react.portal')
const REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for('react.fragment')
const REACT_STRICT_MODE_TYPE = /* @__PURE__ */ Symbol.for('react.strict_mode')
const REACT_PROFILER_TYPE = /* @__PURE__ */ Symbol.for('react.profiler')
const REACT_CONSUMER_TYPE = /* @__PURE__ */ Symbol.for('react.consumer')
const REACT_CONTEXT_TYPE = /* @__PURE__ */ Symbol.for('react.context')
const REACT_FORWARD_REF_TYPE = /* @__PURE__ */ Symbol.for('react.forward_ref')
const REACT_SUSPENSE_TYPE = /* @__PURE__ */ Symbol.for('react.suspense')
const REACT_SUSPENSE_LIST_TYPE = /* @__PURE__ */ Symbol.for(
'react.suspense_list',
)
const REACT_MEMO_TYPE = /* @__PURE__ */ Symbol.for('react.memo')
const REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for('react.lazy')
const REACT_OFFSCREEN_TYPE = /* @__PURE__ */ Symbol.for('react.offscreen')
const REACT_CLIENT_REFERENCE = /* @__PURE__ */ Symbol.for(
'react.client.reference',
)
export const ForwardRef = REACT_FORWARD_REF_TYPE
export const Memo = REACT_MEMO_TYPE
export function isValidElementType(type: any): type is ElementType {
return typeof type === 'string' ||
typeof type === 'function' ||
type === REACT_FRAGMENT_TYPE ||
type === REACT_PROFILER_TYPE ||
type === REACT_STRICT_MODE_TYPE ||
type === REACT_SUSPENSE_TYPE ||
type === REACT_SUSPENSE_LIST_TYPE ||
type === REACT_OFFSCREEN_TYPE ||
(typeof type === 'object' &&
type !== null &&
(type.$$typeof === REACT_LAZY_TYPE ||
type.$$typeof === REACT_MEMO_TYPE ||
type.$$typeof === REACT_CONTEXT_TYPE ||
type.$$typeof === REACT_CONSUMER_TYPE ||
type.$$typeof === REACT_FORWARD_REF_TYPE ||
type.$$typeof === REACT_CLIENT_REFERENCE ||
type.getModuleId !== undefined))
? !0
: !1
}
function typeOf(object: any): symbol | undefined {
if (typeof object === 'object' && object !== null) {
const { $$typeof } = object
switch ($$typeof) {
case REACT_ELEMENT_TYPE:
switch (((object = object.type), object)) {
case REACT_FRAGMENT_TYPE:
case REACT_PROFILER_TYPE:
case REACT_STRICT_MODE_TYPE:
case REACT_SUSPENSE_TYPE:
case REACT_SUSPENSE_LIST_TYPE:
return object
default:
switch (((object = object && object.$$typeof), object)) {
case REACT_CONTEXT_TYPE:
case REACT_FORWARD_REF_TYPE:
case REACT_LAZY_TYPE:
case REACT_MEMO_TYPE:
return object
case REACT_CONSUMER_TYPE:
return object
default:
return $$typeof
}
}
case REACT_PORTAL_TYPE:
return $$typeof
}
}
}
export function isContextConsumer(object: any): object is ReactElement {
return IS_REACT_19
? typeOf(object) === REACT_CONSUMER_TYPE
: typeOf(object) === REACT_CONTEXT_TYPE
}
export function isMemo(object: any): object is MemoExoticComponent<any> {
return typeOf(object) === REACT_MEMO_TYPE
}

3
frontend/node_modules/react-redux/src/utils/react.ts generated vendored Normal file
View File

@@ -0,0 +1,3 @@
import * as React from 'react'
export { React }

View File

@@ -0,0 +1,36 @@
function is(x: unknown, y: unknown) {
if (x === y) {
return x !== 0 || y !== 0 || 1 / x === 1 / y
} else {
return x !== x && y !== y
}
}
export default function shallowEqual(objA: any, objB: any) {
if (is(objA, objB)) return true
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false
}
const keysA = Object.keys(objA)
const keysB = Object.keys(objB)
if (keysA.length !== keysB.length) return false
for (let i = 0; i < keysA.length; i++) {
if (
!Object.prototype.hasOwnProperty.call(objB, keysA[i]) ||
!is(objA[keysA[i]], objB[keysA[i]])
) {
return false
}
}
return true
}

View File

@@ -0,0 +1,40 @@
import { React } from '../utils/react'
// React currently throws a warning when using useLayoutEffect on the server.
// To get around it, we can conditionally useEffect on the server (no-op) and
// useLayoutEffect in the browser. We need useLayoutEffect to ensure the store
// subscription callback always has the selector from the latest render commit
// available, otherwise a store update may happen between render and the effect,
// which may cause missed updates; we also must ensure the store subscription
// is created synchronously, otherwise a store update may occur before the
// subscription is created and an inconsistent state may be observed
// Matches logic in React's `shared/ExecutionEnvironment` file
const canUseDOM = () =>
!!(
typeof window !== 'undefined' &&
typeof window.document !== 'undefined' &&
typeof window.document.createElement !== 'undefined'
)
const isDOM = /* @__PURE__ */ canUseDOM()
// Under React Native, we know that we always want to use useLayoutEffect
/**
* Checks if the code is running in a React Native environment.
*
* @returns Whether the code is running in a React Native environment.
*
* @see {@link https://github.com/facebook/react-native/issues/1331 Reference}
*/
const isRunningInReactNative = () =>
typeof navigator !== 'undefined' && navigator.product === 'ReactNative'
const isReactNative = /* @__PURE__ */ isRunningInReactNative()
const getUseIsomorphicLayoutEffect = () =>
isDOM || isReactNative ? React.useLayoutEffect : React.useEffect
export const useIsomorphicLayoutEffect =
/* @__PURE__ */ getUseIsomorphicLayoutEffect()

View File

@@ -0,0 +1,9 @@
import type { useSyncExternalStore } from 'use-sync-external-store'
import type { useSyncExternalStoreWithSelector } from 'use-sync-external-store/with-selector'
export const notInitialized = () => {
throw new Error('uSES not initialized!')
}
export type uSES = typeof useSyncExternalStore
export type uSESWS = typeof useSyncExternalStoreWithSelector

View File

@@ -0,0 +1,14 @@
import isPlainObject from './isPlainObject'
import warning from './warning'
export default function verifyPlainObject(
value: unknown,
displayName: string,
methodName: string,
) {
if (!isPlainObject(value)) {
warning(
`${methodName}() in ${displayName} must return a plain object. Instead received ${value}.`,
)
}
}

21
frontend/node_modules/react-redux/src/utils/warning.ts generated vendored Normal file
View File

@@ -0,0 +1,21 @@
/**
* Prints a warning in the console if it exists.
*
* @param {String} message The warning message.
* @returns {void}
*/
export default function warning(message: string) {
/* eslint-disable no-console */
if (typeof console !== 'undefined' && typeof console.error === 'function') {
console.error(message)
}
/* eslint-enable no-console */
try {
// This error was thrown as a convenience so that if you enable
// "break on all exceptions" in your console,
// it would pause the execution at this line.
throw new Error(message)
/* eslint-disable no-empty */
} catch (e) {}
/* eslint-enable no-empty */
}