This commit is contained in:
21
frontend/node_modules/immer/LICENSE
generated
vendored
Normal file
21
frontend/node_modules/immer/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 Michel Weststrate
|
||||
|
||||
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.
|
||||
1711
frontend/node_modules/immer/dist/cjs/immer.cjs.development.js
generated
vendored
Normal file
1711
frontend/node_modules/immer/dist/cjs/immer.cjs.development.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
frontend/node_modules/immer/dist/cjs/immer.cjs.development.js.map
generated
vendored
Normal file
1
frontend/node_modules/immer/dist/cjs/immer.cjs.development.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
frontend/node_modules/immer/dist/cjs/immer.cjs.production.js
generated
vendored
Normal file
2
frontend/node_modules/immer/dist/cjs/immer.cjs.production.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/immer/dist/cjs/immer.cjs.production.js.map
generated
vendored
Normal file
1
frontend/node_modules/immer/dist/cjs/immer.cjs.production.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
8
frontend/node_modules/immer/dist/cjs/index.js
generated
vendored
Normal file
8
frontend/node_modules/immer/dist/cjs/index.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
'use strict'
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./immer.cjs.production.js')
|
||||
} else {
|
||||
module.exports = require('./immer.cjs.development.js')
|
||||
}
|
||||
112
frontend/node_modules/immer/dist/cjs/index.js.flow
generated
vendored
Normal file
112
frontend/node_modules/immer/dist/cjs/index.js.flow
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// @flow
|
||||
|
||||
export interface Patch {
|
||||
op: "replace" | "remove" | "add";
|
||||
path: (string | number)[];
|
||||
value?: any;
|
||||
}
|
||||
|
||||
export type PatchListener = (patches: Patch[], inversePatches: Patch[]) => void
|
||||
|
||||
type Base = {...} | Array<any>
|
||||
interface IProduce {
|
||||
/**
|
||||
* Immer takes a state, and runs a function against it.
|
||||
* That function can freely mutate the state, as it will create copies-on-write.
|
||||
* This means that the original state will stay unchanged, and once the function finishes, the modified state is returned.
|
||||
*
|
||||
* If the first argument is a function, this is interpreted as the recipe, and will create a curried function that will execute the recipe
|
||||
* any time it is called with the current state.
|
||||
*
|
||||
* @param currentState - the state to start with
|
||||
* @param recipe - function that receives a proxy of the current state as first argument and which can be freely modified
|
||||
* @param initialState - if a curried function is created and this argument was given, it will be used as fallback if the curried function is called with a state of undefined
|
||||
* @returns The next state: a new state, or the current state if nothing was modified
|
||||
*/
|
||||
<S: Base>(
|
||||
currentState: S,
|
||||
recipe: (draftState: S) => S | void,
|
||||
patchListener?: PatchListener
|
||||
): S;
|
||||
// curried invocations with initial state
|
||||
<S: Base, A = void, B = void, C = void>(
|
||||
recipe: (draftState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S | void,
|
||||
initialState: S
|
||||
): (currentState: S | void, a: A, b: B, c: C, ...extraArgs: any[]) => S;
|
||||
// curried invocations without initial state
|
||||
<S: Base, A = void, B = void, C = void>(
|
||||
recipe: (draftState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S | void
|
||||
): (currentState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S;
|
||||
}
|
||||
|
||||
interface IProduceWithPatches {
|
||||
/**
|
||||
* Like `produce`, but instead of just returning the new state,
|
||||
* a tuple is returned with [nextState, patches, inversePatches]
|
||||
*
|
||||
* Like produce, this function supports currying
|
||||
*/
|
||||
<S: Base>(
|
||||
currentState: S,
|
||||
recipe: (draftState: S) => S | void
|
||||
): [S, Patch[], Patch[]];
|
||||
// curried invocations with initial state
|
||||
<S: Base, A = void, B = void, C = void>(
|
||||
recipe: (draftState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S | void,
|
||||
initialState: S
|
||||
): (currentState: S | void, a: A, b: B, c: C, ...extraArgs: any[]) => [S, Patch[], Patch[]];
|
||||
// curried invocations without initial state
|
||||
<S: Base, A = void, B = void, C = void>(
|
||||
recipe: (draftState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S | void
|
||||
): (currentState: S, a: A, b: B, c: C, ...extraArgs: any[]) => [S, Patch[], Patch[]];
|
||||
}
|
||||
|
||||
declare export var produce: IProduce
|
||||
|
||||
declare export var produceWithPatches: IProduceWithPatches
|
||||
|
||||
declare export var nothing: typeof undefined
|
||||
|
||||
declare export var immerable: Symbol
|
||||
|
||||
/**
|
||||
* Automatically freezes any state trees generated by immer.
|
||||
* This protects against accidental modifications of the state tree outside of an immer function.
|
||||
* This comes with a performance impact, so it is recommended to disable this option in production.
|
||||
* By default it is turned on during local development, and turned off in production.
|
||||
*/
|
||||
declare export function setAutoFreeze(autoFreeze: boolean): void
|
||||
|
||||
/**
|
||||
* Pass false to disable strict shallow copy.
|
||||
*
|
||||
* By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
|
||||
*/
|
||||
declare export function setUseStrictShallowCopy(useStrictShallowCopy: boolean): void
|
||||
|
||||
declare export function applyPatches<S>(state: S, patches: Patch[]): S
|
||||
|
||||
declare export function original<S>(value: S): S
|
||||
|
||||
declare export function current<S>(value: S): S
|
||||
|
||||
declare export function isDraft(value: any): boolean
|
||||
|
||||
/**
|
||||
* Creates a mutable draft from an (immutable) object / array.
|
||||
* The draft can be modified until `finishDraft` is called
|
||||
*/
|
||||
declare export function createDraft<T>(base: T): T
|
||||
|
||||
/**
|
||||
* Given a draft that was created using `createDraft`,
|
||||
* finalizes the draft into a new immutable object.
|
||||
* Optionally a patch-listener can be provided to gather the patches that are needed to construct the object.
|
||||
*/
|
||||
declare export function finishDraft<T>(base: T, listener?: PatchListener): T
|
||||
|
||||
declare export function enableMapSet(): void
|
||||
declare export function enablePatches(): void
|
||||
declare export function enableArrayMethods(): void
|
||||
|
||||
declare export function freeze<T>(obj: T, freeze?: boolean): T
|
||||
317
frontend/node_modules/immer/dist/immer.d.ts
generated
vendored
Normal file
317
frontend/node_modules/immer/dist/immer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
/**
|
||||
* The sentinel value returned by producers to replace the draft with undefined.
|
||||
*/
|
||||
declare const NOTHING: unique symbol;
|
||||
/**
|
||||
* To let Immer treat your class instances as plain immutable objects
|
||||
* (albeit with a custom prototype), you must define either an instance property
|
||||
* or a static property on each of your custom classes.
|
||||
*
|
||||
* Otherwise, your class instance will never be drafted, which means it won't be
|
||||
* safe to mutate in a produce callback.
|
||||
*/
|
||||
declare const DRAFTABLE: unique symbol;
|
||||
|
||||
type AnyFunc = (...args: any[]) => any;
|
||||
type PrimitiveType = number | string | boolean;
|
||||
/** Object types that should never be mapped */
|
||||
type AtomicObject = Function | Promise<any> | Date | RegExp;
|
||||
/**
|
||||
* If the lib "ES2015.Collection" is not included in tsconfig.json,
|
||||
* types like ReadonlyArray, WeakMap etc. fall back to `any` (specified nowhere)
|
||||
* or `{}` (from the node types), in both cases entering an infinite recursion in
|
||||
* pattern matching type mappings
|
||||
* This type can be used to cast these types to `void` in these cases.
|
||||
*/
|
||||
type IfAvailable<T, Fallback = void> = true | false extends (T extends never ? true : false) ? Fallback : keyof T extends never ? Fallback : T;
|
||||
/**
|
||||
* These should also never be mapped but must be tested after regular Map and
|
||||
* Set
|
||||
*/
|
||||
type WeakReferences = IfAvailable<WeakMap<any, any>> | IfAvailable<WeakSet<any>>;
|
||||
type WritableDraft<T> = T extends any[] ? number extends T["length"] ? Draft<T[number]>[] : WritableNonArrayDraft<T> : WritableNonArrayDraft<T>;
|
||||
type WritableNonArrayDraft<T> = {
|
||||
-readonly [K in keyof T]: T[K] extends infer V ? V extends object ? Draft<V> : V : never;
|
||||
};
|
||||
/** Convert a readonly type into a mutable type, if possible */
|
||||
type Draft<T> = T extends PrimitiveType ? T : T extends AtomicObject ? T : T extends ReadonlyMap<infer K, infer V> ? Map<Draft<K>, Draft<V>> : T extends ReadonlySet<infer V> ? Set<Draft<V>> : T extends WeakReferences ? T : T extends object ? WritableDraft<T> : T;
|
||||
/** Convert a mutable type into a readonly type */
|
||||
type Immutable<T> = T extends PrimitiveType ? T : T extends AtomicObject ? T : T extends ReadonlyMap<infer K, infer V> ? ReadonlyMap<Immutable<K>, Immutable<V>> : T extends ReadonlySet<infer V> ? ReadonlySet<Immutable<V>> : T extends WeakReferences ? T : T extends object ? {
|
||||
readonly [K in keyof T]: Immutable<T[K]>;
|
||||
} : T;
|
||||
interface Patch {
|
||||
op: "replace" | "remove" | "add";
|
||||
path: (string | number)[];
|
||||
value?: any;
|
||||
}
|
||||
type PatchListener = (patches: Patch[], inversePatches: Patch[]) => void;
|
||||
/**
|
||||
* Utility types
|
||||
*/
|
||||
type PatchesTuple<T> = readonly [T, Patch[], Patch[]];
|
||||
type ValidRecipeReturnType<State> = State | void | undefined | (State extends undefined ? typeof NOTHING : never);
|
||||
type ReturnTypeWithPatchesIfNeeded<State, UsePatches extends boolean> = UsePatches extends true ? PatchesTuple<State> : State;
|
||||
/**
|
||||
* Core Producer inference
|
||||
*/
|
||||
type InferRecipeFromCurried<Curried> = Curried extends (base: infer State, ...rest: infer Args) => any ? ReturnType<Curried> extends State ? (draft: Draft<State>, ...rest: Args) => ValidRecipeReturnType<Draft<State>> : never : never;
|
||||
type InferInitialStateFromCurried<Curried> = Curried extends (base: infer State, ...rest: any[]) => any ? State : never;
|
||||
type InferCurriedFromRecipe<Recipe, UsePatches extends boolean> = Recipe extends (draft: infer DraftState, ...args: infer RestArgs) => any ? ReturnType<Recipe> extends ValidRecipeReturnType<DraftState> ? (base: Immutable<DraftState>, ...args: RestArgs) => ReturnTypeWithPatchesIfNeeded<DraftState, UsePatches> : never : never;
|
||||
type InferCurriedFromInitialStateAndRecipe<State, Recipe, UsePatches extends boolean> = Recipe extends (draft: Draft<State>, ...rest: infer RestArgs) => ValidRecipeReturnType<State> ? (base?: State | undefined, ...args: RestArgs) => ReturnTypeWithPatchesIfNeeded<State, UsePatches> : never;
|
||||
/**
|
||||
* The `produce` function takes a value and a "recipe function" (whose
|
||||
* return value often depends on the base state). The recipe function is
|
||||
* free to mutate its first argument however it wants. All mutations are
|
||||
* only ever applied to a __copy__ of the base state.
|
||||
*
|
||||
* Pass only a function to create a "curried producer" which relieves you
|
||||
* from passing the recipe function every time.
|
||||
*
|
||||
* Only plain objects and arrays are made mutable. All other objects are
|
||||
* considered uncopyable.
|
||||
*
|
||||
* Note: This function is __bound__ to its `Immer` instance.
|
||||
*
|
||||
* @param {any} base - the initial state
|
||||
* @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
|
||||
* @param {Function} patchListener - optional function that will be called with all the patches produced here
|
||||
* @returns {any} a new state, or the initial state if nothing was modified
|
||||
*/
|
||||
interface IProduce {
|
||||
/** Curried producer that infers the recipe from the curried output function (e.g. when passing to setState) */
|
||||
<Curried>(recipe: InferRecipeFromCurried<Curried>, initialState?: InferInitialStateFromCurried<Curried>): Curried;
|
||||
/** Curried producer that infers curried from the recipe */
|
||||
<Recipe extends AnyFunc>(recipe: Recipe): InferCurriedFromRecipe<Recipe, false>;
|
||||
/** Curried producer that infers curried from the State generic, which is explicitly passed in. */
|
||||
<State>(recipe: (state: Draft<State>, initialState: State) => ValidRecipeReturnType<State>): (state?: State) => State;
|
||||
<State, Args extends any[]>(recipe: (state: Draft<State>, ...args: Args) => ValidRecipeReturnType<State>, initialState: State): (state?: State, ...args: Args) => State;
|
||||
<State>(recipe: (state: Draft<State>) => ValidRecipeReturnType<State>): (state: State) => State;
|
||||
<State, Args extends any[]>(recipe: (state: Draft<State>, ...args: Args) => ValidRecipeReturnType<State>): (state: State, ...args: Args) => State;
|
||||
/** Curried producer with initial state, infers recipe from initial state */
|
||||
<State, Recipe extends Function>(recipe: Recipe, initialState: State): InferCurriedFromInitialStateAndRecipe<State, Recipe, false>;
|
||||
/** Normal producer */
|
||||
<Base, D = Draft<Base>>(// By using a default inferred D, rather than Draft<Base> in the recipe, we can override it.
|
||||
base: Base, recipe: (draft: D) => ValidRecipeReturnType<D>, listener?: PatchListener): Base;
|
||||
}
|
||||
/**
|
||||
* Like `produce`, but instead of just returning the new state,
|
||||
* a tuple is returned with [nextState, patches, inversePatches]
|
||||
*
|
||||
* Like produce, this function supports currying
|
||||
*/
|
||||
interface IProduceWithPatches {
|
||||
<Recipe extends AnyFunc>(recipe: Recipe): InferCurriedFromRecipe<Recipe, true>;
|
||||
<State, Recipe extends Function>(recipe: Recipe, initialState: State): InferCurriedFromInitialStateAndRecipe<State, Recipe, true>;
|
||||
<Base, D = Draft<Base>>(base: Base, recipe: (draft: D) => ValidRecipeReturnType<D>, listener?: PatchListener): PatchesTuple<Base>;
|
||||
}
|
||||
/**
|
||||
* The type for `recipe function`
|
||||
*/
|
||||
type Producer<T> = (draft: Draft<T>) => ValidRecipeReturnType<Draft<T>>;
|
||||
|
||||
type Objectish = AnyObject | AnyArray | AnyMap | AnySet;
|
||||
type AnyObject = {
|
||||
[key: string]: any;
|
||||
};
|
||||
type AnyArray = Array<any>;
|
||||
type AnySet = Set<any>;
|
||||
type AnyMap = Map<any, any>;
|
||||
|
||||
/** Returns true if the given value is an Immer draft */
|
||||
declare let isDraft: (value: any) => boolean;
|
||||
/** Returns true if the given value can be drafted by Immer */
|
||||
declare function isDraftable(value: any): boolean;
|
||||
/** Get the underlying object that is represented by the given draft */
|
||||
declare function original<T>(value: T): T | undefined;
|
||||
/**
|
||||
* Freezes draftable objects. Returns the original object.
|
||||
* By default freezes shallowly, but if the second argument is `true` it will freeze recursively.
|
||||
*
|
||||
* @param obj
|
||||
* @param deep
|
||||
*/
|
||||
declare function freeze<T>(obj: T, deep?: boolean): T;
|
||||
|
||||
interface ProducersFns {
|
||||
produce: IProduce;
|
||||
produceWithPatches: IProduceWithPatches;
|
||||
}
|
||||
type StrictMode = boolean | "class_only";
|
||||
declare class Immer implements ProducersFns {
|
||||
autoFreeze_: boolean;
|
||||
useStrictShallowCopy_: StrictMode;
|
||||
useStrictIteration_: boolean;
|
||||
constructor(config?: {
|
||||
autoFreeze?: boolean;
|
||||
useStrictShallowCopy?: StrictMode;
|
||||
useStrictIteration?: boolean;
|
||||
});
|
||||
/**
|
||||
* The `produce` function takes a value and a "recipe function" (whose
|
||||
* return value often depends on the base state). The recipe function is
|
||||
* free to mutate its first argument however it wants. All mutations are
|
||||
* only ever applied to a __copy__ of the base state.
|
||||
*
|
||||
* Pass only a function to create a "curried producer" which relieves you
|
||||
* from passing the recipe function every time.
|
||||
*
|
||||
* Only plain objects and arrays are made mutable. All other objects are
|
||||
* considered uncopyable.
|
||||
*
|
||||
* Note: This function is __bound__ to its `Immer` instance.
|
||||
*
|
||||
* @param {any} base - the initial state
|
||||
* @param {Function} recipe - function that receives a proxy of the base state as first argument and which can be freely modified
|
||||
* @param {Function} patchListener - optional function that will be called with all the patches produced here
|
||||
* @returns {any} a new state, or the initial state if nothing was modified
|
||||
*/
|
||||
produce: IProduce;
|
||||
produceWithPatches: IProduceWithPatches;
|
||||
createDraft<T extends Objectish>(base: T): Draft<T>;
|
||||
finishDraft<D extends Draft<any>>(draft: D, patchListener?: PatchListener): D extends Draft<infer T> ? T : never;
|
||||
/**
|
||||
* Pass true to automatically freeze all copies created by Immer.
|
||||
*
|
||||
* By default, auto-freezing is enabled.
|
||||
*/
|
||||
setAutoFreeze(value: boolean): void;
|
||||
/**
|
||||
* Pass true to enable strict shallow copy.
|
||||
*
|
||||
* By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
|
||||
*/
|
||||
setUseStrictShallowCopy(value: StrictMode): void;
|
||||
/**
|
||||
* Pass false to use faster iteration that skips non-enumerable properties
|
||||
* but still handles symbols for compatibility.
|
||||
*
|
||||
* By default, strict iteration is enabled (includes all own properties).
|
||||
*/
|
||||
setUseStrictIteration(value: boolean): void;
|
||||
shouldUseStrictIteration(): boolean;
|
||||
applyPatches<T extends Objectish>(base: T, patches: readonly Patch[]): T;
|
||||
}
|
||||
|
||||
/** Takes a snapshot of the current state of a draft and finalizes it (but without freezing). This is a great utility to print the current state during debugging (no Proxies in the way). The output of current can also be safely leaked outside the producer. */
|
||||
declare function current<T>(value: T): T;
|
||||
|
||||
declare function enablePatches(): void;
|
||||
|
||||
declare function enableMapSet(): void;
|
||||
|
||||
/**
|
||||
* Enables optimized array method handling for Immer drafts.
|
||||
*
|
||||
* This plugin overrides array methods to avoid unnecessary Proxy creation during iteration,
|
||||
* significantly improving performance for array-heavy operations.
|
||||
*
|
||||
* **Mutating methods** (push, pop, shift, unshift, splice, sort, reverse):
|
||||
* Operate directly on the copy without creating per-element proxies.
|
||||
*
|
||||
* **Non-mutating methods** fall into categories:
|
||||
* - **Subset operations** (filter, slice, find, findLast): Return draft proxies - mutations track
|
||||
* - **Transform operations** (concat, flat): Return base values - mutations don't track
|
||||
* - **Primitive-returning** (indexOf, includes, some, every, etc.): Return primitives
|
||||
*
|
||||
* **Important**: Callbacks for overridden methods receive base values, not drafts.
|
||||
* This is the core performance optimization.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { enableArrayMethods, produce } from "immer"
|
||||
*
|
||||
* enableArrayMethods()
|
||||
*
|
||||
* const next = produce(state, draft => {
|
||||
* // Optimized - no proxy creation per element
|
||||
* draft.items.sort((a, b) => a.value - b.value)
|
||||
*
|
||||
* // filter returns drafts - mutations propagate
|
||||
* const filtered = draft.items.filter(x => x.value > 5)
|
||||
* filtered[0].value = 999 // Affects draft.items[originalIndex]
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @see https://immerjs.github.io/immer/array-methods
|
||||
*/
|
||||
declare function enableArrayMethods(): void;
|
||||
|
||||
/**
|
||||
* The `produce` function takes a value and a "recipe function" (whose
|
||||
* return value often depends on the base state). The recipe function is
|
||||
* free to mutate its first argument however it wants. All mutations are
|
||||
* only ever applied to a __copy__ of the base state.
|
||||
*
|
||||
* Pass only a function to create a "curried producer" which relieves you
|
||||
* from passing the recipe function every time.
|
||||
*
|
||||
* Only plain objects and arrays are made mutable. All other objects are
|
||||
* considered uncopyable.
|
||||
*
|
||||
* Note: This function is __bound__ to its `Immer` instance.
|
||||
*
|
||||
* @param {any} base - the initial state
|
||||
* @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
|
||||
* @param {Function} patchListener - optional function that will be called with all the patches produced here
|
||||
* @returns {any} a new state, or the initial state if nothing was modified
|
||||
*/
|
||||
declare const produce: IProduce;
|
||||
/**
|
||||
* Like `produce`, but `produceWithPatches` always returns a tuple
|
||||
* [nextState, patches, inversePatches] (instead of just the next state)
|
||||
*/
|
||||
declare const produceWithPatches: IProduceWithPatches;
|
||||
/**
|
||||
* Pass true to automatically freeze all copies created by Immer.
|
||||
*
|
||||
* Always freeze by default, even in production mode
|
||||
*/
|
||||
declare const setAutoFreeze: (value: boolean) => void;
|
||||
/**
|
||||
* Pass true to enable strict shallow copy.
|
||||
*
|
||||
* By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
|
||||
*/
|
||||
declare const setUseStrictShallowCopy: (value: StrictMode) => void;
|
||||
/**
|
||||
* Pass false to use loose iteration that only processes enumerable string properties.
|
||||
* This skips symbols and non-enumerable properties for maximum performance.
|
||||
*
|
||||
* By default, strict iteration is enabled (includes all own properties).
|
||||
*/
|
||||
declare const setUseStrictIteration: (value: boolean) => void;
|
||||
/**
|
||||
* Apply an array of Immer patches to the first argument.
|
||||
*
|
||||
* This function is a producer, which means copy-on-write is in effect.
|
||||
*/
|
||||
declare const applyPatches: <T extends Objectish>(base: T, patches: readonly Patch[]) => T;
|
||||
/**
|
||||
* Create an Immer draft from the given base state, which may be a draft itself.
|
||||
* The draft can be modified until you finalize it with the `finishDraft` function.
|
||||
*/
|
||||
declare const createDraft: <T extends Objectish>(base: T) => Draft<T>;
|
||||
/**
|
||||
* Finalize an Immer draft from a `createDraft` call, returning the base state
|
||||
* (if no changes were made) or a modified copy. The draft must *not* be
|
||||
* mutated afterwards.
|
||||
*
|
||||
* Pass a function as the 2nd argument to generate Immer patches based on the
|
||||
* changes that were made.
|
||||
*/
|
||||
declare const finishDraft: <D extends unknown>(draft: D, patchListener?: PatchListener | undefined) => D extends Draft<infer T> ? T : never;
|
||||
/**
|
||||
* This function is actually a no-op, but can be used to cast an immutable type
|
||||
* to an draft type and make TypeScript happy
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
declare let castDraft: <T>(value: T) => Draft<T>;
|
||||
/**
|
||||
* This function is actually a no-op, but can be used to cast a mutable type
|
||||
* to an immutable type and make TypeScript happy
|
||||
* @param value
|
||||
*/
|
||||
declare let castImmutable: <T>(value: T) => Immutable<T>;
|
||||
|
||||
export { Draft, Immer, Immutable, Objectish, Patch, PatchListener, Producer, StrictMode, WritableDraft, applyPatches, castDraft, castImmutable, createDraft, current, enableArrayMethods, enableMapSet, enablePatches, finishDraft, freeze, DRAFTABLE as immerable, isDraft, isDraftable, NOTHING as nothing, original, produce, produceWithPatches, setAutoFreeze, setUseStrictIteration, setUseStrictShallowCopy };
|
||||
1693
frontend/node_modules/immer/dist/immer.legacy-esm.js
generated
vendored
Normal file
1693
frontend/node_modules/immer/dist/immer.legacy-esm.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
frontend/node_modules/immer/dist/immer.legacy-esm.js.map
generated
vendored
Normal file
1
frontend/node_modules/immer/dist/immer.legacy-esm.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1664
frontend/node_modules/immer/dist/immer.mjs
generated
vendored
Normal file
1664
frontend/node_modules/immer/dist/immer.mjs
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
frontend/node_modules/immer/dist/immer.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/immer/dist/immer.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
frontend/node_modules/immer/dist/immer.production.mjs
generated
vendored
Normal file
2
frontend/node_modules/immer/dist/immer.production.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
1
frontend/node_modules/immer/dist/immer.production.mjs.map
generated
vendored
Normal file
1
frontend/node_modules/immer/dist/immer.production.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
97
frontend/node_modules/immer/package.json
generated
vendored
Normal file
97
frontend/node_modules/immer/package.json
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"name": "immer",
|
||||
"version": "11.1.4",
|
||||
"description": "Create your next immutable state by mutating the current one",
|
||||
"main": "./dist/cjs/index.js",
|
||||
"module": "./dist/immer.legacy-esm.js",
|
||||
"exports": {
|
||||
"./package.json": "./package.json",
|
||||
".": {
|
||||
"react-native": {
|
||||
"types": "./dist/immer.d.ts",
|
||||
"default": "./dist/immer.legacy-esm.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/immer.d.ts",
|
||||
"default": "./dist/immer.mjs"
|
||||
},
|
||||
"require": {
|
||||
"types": "./dist/immer.d.ts",
|
||||
"default": "./dist/cjs/index.js"
|
||||
}
|
||||
}
|
||||
},
|
||||
"jsnext:main": "dist/immer.mjs",
|
||||
"source": "src/immer.ts",
|
||||
"types": "./dist/immer.d.ts",
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"test": "vitest run && yarn test:build && yarn test:flow",
|
||||
"test:perf": "cd __performance_tests__ && node add-data.mjs && node todo.mjs && node incremental.mjs && node large-obj.mjs",
|
||||
"test:flow": "yarn flow check __tests__/flow",
|
||||
"test:build": "yarn build && vitest run --config vitest.config.build.ts",
|
||||
"test:src": "vitest run",
|
||||
"watch": "vitest",
|
||||
"coverage": "vitest run --coverage",
|
||||
"coveralls": "vitest run --coverage && cat ./coverage/lcov.info | ./node_modules/.bin/coveralls && rm -rf ./coverage",
|
||||
"build": "tsup",
|
||||
"publish-docs": "cd website && GIT_USER=mweststrate USE_SSH=true yarn docusaurus deploy",
|
||||
"start": "cd website && yarn start",
|
||||
"test:size": "yarn build && yarn import-size --report . produce enableMapSet enablePatches enableArrayMethods",
|
||||
"test:sizequick": "yarn build && yarn import-size . produce"
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "pretty-quick --staged"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/immerjs/immer.git"
|
||||
},
|
||||
"keywords": [
|
||||
"immutable",
|
||||
"mutable",
|
||||
"copy-on-write"
|
||||
],
|
||||
"author": "Michel Weststrate <info@michel.codes>",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/immerjs/immer/issues"
|
||||
},
|
||||
"homepage": "https://github.com/immerjs/immer#readme",
|
||||
"files": [
|
||||
"dist",
|
||||
"compat",
|
||||
"src"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.21.3",
|
||||
"@types/node": "^24.3.1",
|
||||
"@vitest/coverage-v8": "2.1.9",
|
||||
"coveralls": "^3.0.0",
|
||||
"cpx2": "^3.0.0",
|
||||
"deep-freeze": "^0.0.1",
|
||||
"flow-bin": "^0.123.0",
|
||||
"husky": "^1.2.0",
|
||||
"immutable": "^3.8.2",
|
||||
"import-size": "^1.0.2",
|
||||
"lodash": "^4.17.4",
|
||||
"lodash.clonedeep": "^4.5.0",
|
||||
"prettier": "1.19.1",
|
||||
"pretty-quick": "^1.8.0",
|
||||
"redux": "^4.0.5",
|
||||
"rimraf": "^2.6.2",
|
||||
"seamless-immutable": "^7.1.3",
|
||||
"semantic-release": "^17.0.2",
|
||||
"tsup": "^6.7.0",
|
||||
"type-plus": "^7.6.2",
|
||||
"typescript": "^5.0.2",
|
||||
"vite": "^5.4.0",
|
||||
"vitest": "^2.0.0"
|
||||
}
|
||||
}
|
||||
33
frontend/node_modules/immer/readme.md
generated
vendored
Normal file
33
frontend/node_modules/immer/readme.md
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
<img src="images/immer-logo.svg" height="200px" align="right"/>
|
||||
|
||||
# Immer
|
||||
|
||||
[](https://www.npmjs.com/package/immer) [](https://github.com/immerjs/immer/actions?query=branch%3Amain) [](https://coveralls.io/github/immerjs/immer?branch=main) [](https://github.com/prettier/prettier) [](#backers) [](#sponsors) [](https://gitpod.io/#https://github.com/immerjs/immer)
|
||||
|
||||
_Create the next immutable state tree by simply modifying the current tree_
|
||||
|
||||
Winner of the "Breakthrough of the year" [React open source award](https://osawards.com/react/) and "Most impactful contribution" [JavaScript open source award](https://osawards.com/javascript/) in 2019
|
||||
|
||||
## Contribute using one-click online setup
|
||||
|
||||
You can use Gitpod (a free online VSCode like IDE) for contributing online. With a single click it will launch a workspace and automatically:
|
||||
|
||||
- clone the immer repo.
|
||||
- install the dependencies.
|
||||
- run `yarn run start`.
|
||||
|
||||
so that you can start coding straight away.
|
||||
|
||||
[](https://gitpod.io/from-referrer/)
|
||||
|
||||
## Documentation
|
||||
|
||||
The documentation of this package is hosted at https://immerjs.github.io/immer/
|
||||
|
||||
## Support
|
||||
|
||||
Did Immer make a difference to your project? Join the open collective at https://opencollective.com/immer!
|
||||
|
||||
## Release notes
|
||||
|
||||
https://github.com/immerjs/immer/releases
|
||||
46
frontend/node_modules/immer/src/core/current.ts
generated
vendored
Normal file
46
frontend/node_modules/immer/src/core/current.ts
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
import {
|
||||
die,
|
||||
isDraft,
|
||||
shallowCopy,
|
||||
each,
|
||||
DRAFT_STATE,
|
||||
set,
|
||||
ImmerState,
|
||||
isDraftable,
|
||||
isFrozen
|
||||
} from "../internal"
|
||||
|
||||
/** Takes a snapshot of the current state of a draft and finalizes it (but without freezing). This is a great utility to print the current state during debugging (no Proxies in the way). The output of current can also be safely leaked outside the producer. */
|
||||
export function current<T>(value: T): T
|
||||
export function current(value: any): any {
|
||||
if (!isDraft(value)) die(10, value)
|
||||
return currentImpl(value)
|
||||
}
|
||||
|
||||
function currentImpl(value: any): any {
|
||||
if (!isDraftable(value) || isFrozen(value)) return value
|
||||
const state: ImmerState | undefined = value[DRAFT_STATE]
|
||||
let copy: any
|
||||
let strict = true // Default to strict for compatibility
|
||||
if (state) {
|
||||
if (!state.modified_) return state.base_
|
||||
// Optimization: avoid generating new drafts during copying
|
||||
state.finalized_ = true
|
||||
copy = shallowCopy(value, state.scope_.immer_.useStrictShallowCopy_)
|
||||
strict = state.scope_.immer_.shouldUseStrictIteration()
|
||||
} else {
|
||||
copy = shallowCopy(value, true)
|
||||
}
|
||||
// recurse
|
||||
each(
|
||||
copy,
|
||||
(key, childValue) => {
|
||||
set(copy, key, currentImpl(childValue))
|
||||
},
|
||||
strict
|
||||
)
|
||||
if (state) {
|
||||
state.finalized_ = false
|
||||
}
|
||||
return copy
|
||||
}
|
||||
318
frontend/node_modules/immer/src/core/finalize.ts
generated
vendored
Normal file
318
frontend/node_modules/immer/src/core/finalize.ts
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
||||
import {
|
||||
ImmerScope,
|
||||
DRAFT_STATE,
|
||||
isDraftable,
|
||||
NOTHING,
|
||||
PatchPath,
|
||||
each,
|
||||
freeze,
|
||||
ImmerState,
|
||||
isDraft,
|
||||
SetState,
|
||||
set,
|
||||
ArchType,
|
||||
getPlugin,
|
||||
die,
|
||||
revokeScope,
|
||||
isFrozen,
|
||||
get,
|
||||
Patch,
|
||||
latest,
|
||||
prepareCopy,
|
||||
getFinalValue,
|
||||
getValue,
|
||||
ProxyArrayState
|
||||
} from "../internal"
|
||||
|
||||
export function processResult(result: any, scope: ImmerScope) {
|
||||
scope.unfinalizedDrafts_ = scope.drafts_.length
|
||||
const baseDraft = scope.drafts_![0]
|
||||
const isReplaced = result !== undefined && result !== baseDraft
|
||||
|
||||
if (isReplaced) {
|
||||
if (baseDraft[DRAFT_STATE].modified_) {
|
||||
revokeScope(scope)
|
||||
die(4)
|
||||
}
|
||||
if (isDraftable(result)) {
|
||||
// Finalize the result in case it contains (or is) a subset of the draft.
|
||||
result = finalize(scope, result)
|
||||
}
|
||||
const {patchPlugin_} = scope
|
||||
if (patchPlugin_) {
|
||||
patchPlugin_.generateReplacementPatches_(
|
||||
baseDraft[DRAFT_STATE].base_,
|
||||
result,
|
||||
scope
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// Finalize the base draft.
|
||||
result = finalize(scope, baseDraft)
|
||||
}
|
||||
|
||||
maybeFreeze(scope, result, true)
|
||||
|
||||
revokeScope(scope)
|
||||
if (scope.patches_) {
|
||||
scope.patchListener_!(scope.patches_, scope.inversePatches_!)
|
||||
}
|
||||
return result !== NOTHING ? result : undefined
|
||||
}
|
||||
|
||||
function finalize(rootScope: ImmerScope, value: any) {
|
||||
// Don't recurse in tho recursive data structures
|
||||
if (isFrozen(value)) return value
|
||||
|
||||
const state: ImmerState = value[DRAFT_STATE]
|
||||
if (!state) {
|
||||
const finalValue = handleValue(value, rootScope.handledSet_, rootScope)
|
||||
return finalValue
|
||||
}
|
||||
|
||||
// Never finalize drafts owned by another scope
|
||||
if (!isSameScope(state, rootScope)) {
|
||||
return value
|
||||
}
|
||||
|
||||
// Unmodified draft, return the (frozen) original
|
||||
if (!state.modified_) {
|
||||
return state.base_
|
||||
}
|
||||
|
||||
if (!state.finalized_) {
|
||||
// Execute all registered draft finalization callbacks
|
||||
const {callbacks_} = state
|
||||
if (callbacks_) {
|
||||
while (callbacks_.length > 0) {
|
||||
const callback = callbacks_.pop()!
|
||||
callback(rootScope)
|
||||
}
|
||||
}
|
||||
|
||||
generatePatchesAndFinalize(state, rootScope)
|
||||
}
|
||||
|
||||
// By now the root copy has been fully updated throughout its tree
|
||||
return state.copy_
|
||||
}
|
||||
|
||||
function maybeFreeze(scope: ImmerScope, value: any, deep = false) {
|
||||
// we never freeze for a non-root scope; as it would prevent pruning for drafts inside wrapping objects
|
||||
if (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {
|
||||
freeze(value, deep)
|
||||
}
|
||||
}
|
||||
|
||||
function markStateFinalized(state: ImmerState) {
|
||||
state.finalized_ = true
|
||||
state.scope_.unfinalizedDrafts_--
|
||||
}
|
||||
|
||||
let isSameScope = (state: ImmerState, rootScope: ImmerScope) =>
|
||||
state.scope_ === rootScope
|
||||
|
||||
// A reusable empty array to avoid allocations
|
||||
const EMPTY_LOCATIONS_RESULT: (string | symbol | number)[] = []
|
||||
|
||||
// Updates all references to a draft in its parent to the finalized value.
|
||||
// This handles cases where the same draft appears multiple times in the parent, or has been moved around.
|
||||
export function updateDraftInParent(
|
||||
parent: ImmerState,
|
||||
draftValue: any,
|
||||
finalizedValue: any,
|
||||
originalKey?: string | number | symbol
|
||||
): void {
|
||||
const parentCopy = latest(parent)
|
||||
const parentType = parent.type_
|
||||
|
||||
// Fast path: Check if draft is still at original key
|
||||
if (originalKey !== undefined) {
|
||||
const currentValue = get(parentCopy, originalKey, parentType)
|
||||
if (currentValue === draftValue) {
|
||||
// Still at original location, just update it
|
||||
set(parentCopy, originalKey, finalizedValue, parentType)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Slow path: Build reverse mapping of all children
|
||||
// to their indices in the parent, so that we can
|
||||
// replace all locations where this draft appears.
|
||||
// We only have to build this once per parent.
|
||||
if (!parent.draftLocations_) {
|
||||
const draftLocations = (parent.draftLocations_ = new Map())
|
||||
|
||||
// Use `each` which works on Arrays, Maps, and Objects
|
||||
each(parentCopy, (key, value) => {
|
||||
if (isDraft(value)) {
|
||||
const keys = draftLocations.get(value) || []
|
||||
keys.push(key)
|
||||
draftLocations.set(value, keys)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Look up all locations where this draft appears
|
||||
const locations =
|
||||
parent.draftLocations_.get(draftValue) ?? EMPTY_LOCATIONS_RESULT
|
||||
|
||||
// Update all locations
|
||||
for (const location of locations) {
|
||||
set(parentCopy, location, finalizedValue, parentType)
|
||||
}
|
||||
}
|
||||
|
||||
// Register a callback to finalize a child draft when the parent draft is finalized.
|
||||
// This assumes there is a parent -> child relationship between the two drafts,
|
||||
// and we have a key to locate the child in the parent.
|
||||
export function registerChildFinalizationCallback(
|
||||
parent: ImmerState,
|
||||
child: ImmerState,
|
||||
key: string | number | symbol
|
||||
) {
|
||||
parent.callbacks_.push(function childCleanup(rootScope) {
|
||||
const state: ImmerState = child
|
||||
|
||||
// Can only continue if this is a draft owned by this scope
|
||||
if (!state || !isSameScope(state, rootScope)) {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle potential set value finalization first
|
||||
rootScope.mapSetPlugin_?.fixSetContents(state)
|
||||
|
||||
const finalizedValue = getFinalValue(state)
|
||||
|
||||
// Update all locations in the parent that referenced this draft
|
||||
updateDraftInParent(parent, state.draft_ ?? state, finalizedValue, key)
|
||||
|
||||
generatePatchesAndFinalize(state, rootScope)
|
||||
})
|
||||
}
|
||||
|
||||
function generatePatchesAndFinalize(state: ImmerState, rootScope: ImmerScope) {
|
||||
const shouldFinalize =
|
||||
state.modified_ &&
|
||||
!state.finalized_ &&
|
||||
(state.type_ === ArchType.Set ||
|
||||
(state.type_ === ArchType.Array &&
|
||||
(state as ProxyArrayState).allIndicesReassigned_) ||
|
||||
(state.assigned_?.size ?? 0) > 0)
|
||||
|
||||
if (shouldFinalize) {
|
||||
const {patchPlugin_} = rootScope
|
||||
if (patchPlugin_) {
|
||||
const basePath = patchPlugin_!.getPath(state)
|
||||
|
||||
if (basePath) {
|
||||
patchPlugin_!.generatePatches_(state, basePath, rootScope)
|
||||
}
|
||||
}
|
||||
|
||||
markStateFinalized(state)
|
||||
}
|
||||
}
|
||||
|
||||
export function handleCrossReference(
|
||||
target: ImmerState,
|
||||
key: string | number | symbol,
|
||||
value: any
|
||||
) {
|
||||
const {scope_} = target
|
||||
// Check if value is a draft from this scope
|
||||
if (isDraft(value)) {
|
||||
const state: ImmerState = value[DRAFT_STATE]
|
||||
if (isSameScope(state, scope_)) {
|
||||
// Register callback to update this location when the draft finalizes
|
||||
|
||||
state.callbacks_.push(function crossReferenceCleanup() {
|
||||
// Update the target location with finalized value
|
||||
prepareCopy(target)
|
||||
|
||||
const finalizedValue = getFinalValue(state)
|
||||
|
||||
updateDraftInParent(target, value, finalizedValue, key)
|
||||
})
|
||||
}
|
||||
} else if (isDraftable(value)) {
|
||||
// Handle non-draft objects that might contain drafts
|
||||
target.callbacks_.push(function nestedDraftCleanup() {
|
||||
const targetCopy = latest(target)
|
||||
|
||||
// For Sets, check if value is still in the set
|
||||
if (target.type_ === ArchType.Set) {
|
||||
if (targetCopy.has(value)) {
|
||||
// Process the value to replace any nested drafts
|
||||
handleValue(value, scope_.handledSet_, scope_)
|
||||
}
|
||||
} else {
|
||||
// Maps/objects
|
||||
if (get(targetCopy, key, target.type_) === value) {
|
||||
if (
|
||||
scope_.drafts_.length > 1 &&
|
||||
((target as Exclude<ImmerState, SetState>).assigned_!.get(key) ??
|
||||
false) === true &&
|
||||
target.copy_
|
||||
) {
|
||||
// This might be a non-draft value that has drafts
|
||||
// inside. We do need to recurse here to handle those.
|
||||
handleValue(
|
||||
get(target.copy_, key, target.type_),
|
||||
scope_.handledSet_,
|
||||
scope_
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function handleValue(
|
||||
target: any,
|
||||
handledSet: Set<any>,
|
||||
rootScope: ImmerScope
|
||||
) {
|
||||
if (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) {
|
||||
// optimization: if an object is not a draft, and we don't have to
|
||||
// deepfreeze everything, and we are sure that no drafts are left in the remaining object
|
||||
// cause we saw and finalized all drafts already; we can stop visiting the rest of the tree.
|
||||
// This benefits especially adding large data tree's without further processing.
|
||||
// See add-data.js perf test
|
||||
return target
|
||||
}
|
||||
|
||||
// Skip if already handled, frozen, or not draftable
|
||||
if (
|
||||
isDraft(target) ||
|
||||
handledSet.has(target) ||
|
||||
!isDraftable(target) ||
|
||||
isFrozen(target)
|
||||
) {
|
||||
return target
|
||||
}
|
||||
|
||||
handledSet.add(target)
|
||||
|
||||
// Process ALL properties/entries
|
||||
each(target, (key, value) => {
|
||||
if (isDraft(value)) {
|
||||
const state: ImmerState = value[DRAFT_STATE]
|
||||
if (isSameScope(state, rootScope)) {
|
||||
// Replace draft with finalized value
|
||||
|
||||
const updatedValue = getFinalValue(state)
|
||||
|
||||
set(target, key, updatedValue, target.type_)
|
||||
|
||||
markStateFinalized(state)
|
||||
}
|
||||
} else if (isDraftable(value)) {
|
||||
// Recursively handle nested values
|
||||
handleValue(value, handledSet, rootScope)
|
||||
}
|
||||
})
|
||||
|
||||
return target
|
||||
}
|
||||
273
frontend/node_modules/immer/src/core/immerClass.ts
generated
vendored
Normal file
273
frontend/node_modules/immer/src/core/immerClass.ts
generated
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
import {
|
||||
IProduceWithPatches,
|
||||
IProduce,
|
||||
ImmerState,
|
||||
Drafted,
|
||||
isDraftable,
|
||||
processResult,
|
||||
Patch,
|
||||
Objectish,
|
||||
DRAFT_STATE,
|
||||
Draft,
|
||||
PatchListener,
|
||||
isDraft,
|
||||
isMap,
|
||||
isSet,
|
||||
createProxyProxy,
|
||||
getPlugin,
|
||||
die,
|
||||
enterScope,
|
||||
revokeScope,
|
||||
leaveScope,
|
||||
usePatchesInScope,
|
||||
getCurrentScope,
|
||||
NOTHING,
|
||||
freeze,
|
||||
current,
|
||||
ImmerScope,
|
||||
registerChildFinalizationCallback,
|
||||
ArchType,
|
||||
MapSetPlugin,
|
||||
AnyMap,
|
||||
AnySet,
|
||||
isObjectish,
|
||||
isFunction,
|
||||
isBoolean,
|
||||
PluginMapSet,
|
||||
PluginPatches
|
||||
} from "../internal"
|
||||
|
||||
interface ProducersFns {
|
||||
produce: IProduce
|
||||
produceWithPatches: IProduceWithPatches
|
||||
}
|
||||
|
||||
export type StrictMode = boolean | "class_only"
|
||||
|
||||
export class Immer implements ProducersFns {
|
||||
autoFreeze_: boolean = true
|
||||
useStrictShallowCopy_: StrictMode = false
|
||||
useStrictIteration_: boolean = false
|
||||
|
||||
constructor(config?: {
|
||||
autoFreeze?: boolean
|
||||
useStrictShallowCopy?: StrictMode
|
||||
useStrictIteration?: boolean
|
||||
}) {
|
||||
if (isBoolean(config?.autoFreeze)) this.setAutoFreeze(config!.autoFreeze)
|
||||
if (isBoolean(config?.useStrictShallowCopy))
|
||||
this.setUseStrictShallowCopy(config!.useStrictShallowCopy)
|
||||
if (isBoolean(config?.useStrictIteration))
|
||||
this.setUseStrictIteration(config!.useStrictIteration)
|
||||
}
|
||||
|
||||
/**
|
||||
* The `produce` function takes a value and a "recipe function" (whose
|
||||
* return value often depends on the base state). The recipe function is
|
||||
* free to mutate its first argument however it wants. All mutations are
|
||||
* only ever applied to a __copy__ of the base state.
|
||||
*
|
||||
* Pass only a function to create a "curried producer" which relieves you
|
||||
* from passing the recipe function every time.
|
||||
*
|
||||
* Only plain objects and arrays are made mutable. All other objects are
|
||||
* considered uncopyable.
|
||||
*
|
||||
* Note: This function is __bound__ to its `Immer` instance.
|
||||
*
|
||||
* @param {any} base - the initial state
|
||||
* @param {Function} recipe - function that receives a proxy of the base state as first argument and which can be freely modified
|
||||
* @param {Function} patchListener - optional function that will be called with all the patches produced here
|
||||
* @returns {any} a new state, or the initial state if nothing was modified
|
||||
*/
|
||||
produce: IProduce = (base: any, recipe?: any, patchListener?: any) => {
|
||||
// curried invocation
|
||||
if (isFunction(base) && !isFunction(recipe)) {
|
||||
const defaultBase = recipe
|
||||
recipe = base
|
||||
|
||||
const self = this
|
||||
return function curriedProduce(
|
||||
this: any,
|
||||
base = defaultBase,
|
||||
...args: any[]
|
||||
) {
|
||||
return self.produce(base, (draft: Drafted) => recipe.call(this, draft, ...args)) // prettier-ignore
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFunction(recipe)) die(6)
|
||||
if (patchListener !== undefined && !isFunction(patchListener)) die(7)
|
||||
|
||||
let result
|
||||
|
||||
// Only plain objects, arrays, and "immerable classes" are drafted.
|
||||
if (isDraftable(base)) {
|
||||
const scope = enterScope(this)
|
||||
const proxy = createProxy(scope, base, undefined)
|
||||
let hasError = true
|
||||
try {
|
||||
result = recipe(proxy)
|
||||
hasError = false
|
||||
} finally {
|
||||
// finally instead of catch + rethrow better preserves original stack
|
||||
if (hasError) revokeScope(scope)
|
||||
else leaveScope(scope)
|
||||
}
|
||||
usePatchesInScope(scope, patchListener)
|
||||
return processResult(result, scope)
|
||||
} else if (!base || !isObjectish(base)) {
|
||||
result = recipe(base)
|
||||
if (result === undefined) result = base
|
||||
if (result === NOTHING) result = undefined
|
||||
if (this.autoFreeze_) freeze(result, true)
|
||||
if (patchListener) {
|
||||
const p: Patch[] = []
|
||||
const ip: Patch[] = []
|
||||
getPlugin(PluginPatches).generateReplacementPatches_(base, result, {
|
||||
patches_: p,
|
||||
inversePatches_: ip
|
||||
} as ImmerScope) // dummy scope
|
||||
patchListener(p, ip)
|
||||
}
|
||||
return result
|
||||
} else die(1, base)
|
||||
}
|
||||
|
||||
produceWithPatches: IProduceWithPatches = (base: any, recipe?: any): any => {
|
||||
// curried invocation
|
||||
if (isFunction(base)) {
|
||||
return (state: any, ...args: any[]) =>
|
||||
this.produceWithPatches(state, (draft: any) => base(draft, ...args))
|
||||
}
|
||||
|
||||
let patches: Patch[], inversePatches: Patch[]
|
||||
const result = this.produce(base, recipe, (p: Patch[], ip: Patch[]) => {
|
||||
patches = p
|
||||
inversePatches = ip
|
||||
})
|
||||
return [result, patches!, inversePatches!]
|
||||
}
|
||||
|
||||
createDraft<T extends Objectish>(base: T): Draft<T> {
|
||||
if (!isDraftable(base)) die(8)
|
||||
if (isDraft(base)) base = current(base)
|
||||
const scope = enterScope(this)
|
||||
const proxy = createProxy(scope, base, undefined)
|
||||
proxy[DRAFT_STATE].isManual_ = true
|
||||
leaveScope(scope)
|
||||
return proxy as any
|
||||
}
|
||||
|
||||
finishDraft<D extends Draft<any>>(
|
||||
draft: D,
|
||||
patchListener?: PatchListener
|
||||
): D extends Draft<infer T> ? T : never {
|
||||
const state: ImmerState = draft && (draft as any)[DRAFT_STATE]
|
||||
if (!state || !state.isManual_) die(9)
|
||||
const {scope_: scope} = state
|
||||
usePatchesInScope(scope, patchListener)
|
||||
return processResult(undefined, scope)
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass true to automatically freeze all copies created by Immer.
|
||||
*
|
||||
* By default, auto-freezing is enabled.
|
||||
*/
|
||||
setAutoFreeze(value: boolean) {
|
||||
this.autoFreeze_ = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass true to enable strict shallow copy.
|
||||
*
|
||||
* By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
|
||||
*/
|
||||
setUseStrictShallowCopy(value: StrictMode) {
|
||||
this.useStrictShallowCopy_ = value
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass false to use faster iteration that skips non-enumerable properties
|
||||
* but still handles symbols for compatibility.
|
||||
*
|
||||
* By default, strict iteration is enabled (includes all own properties).
|
||||
*/
|
||||
setUseStrictIteration(value: boolean) {
|
||||
this.useStrictIteration_ = value
|
||||
}
|
||||
|
||||
shouldUseStrictIteration(): boolean {
|
||||
return this.useStrictIteration_
|
||||
}
|
||||
|
||||
applyPatches<T extends Objectish>(base: T, patches: readonly Patch[]): T {
|
||||
// If a patch replaces the entire state, take that replacement as base
|
||||
// before applying patches
|
||||
let i: number
|
||||
for (i = patches.length - 1; i >= 0; i--) {
|
||||
const patch = patches[i]
|
||||
if (patch.path.length === 0 && patch.op === "replace") {
|
||||
base = patch.value
|
||||
break
|
||||
}
|
||||
}
|
||||
// If there was a patch that replaced the entire state, start from the
|
||||
// patch after that.
|
||||
if (i > -1) {
|
||||
patches = patches.slice(i + 1)
|
||||
}
|
||||
|
||||
const applyPatchesImpl = getPlugin(PluginPatches).applyPatches_
|
||||
if (isDraft(base)) {
|
||||
// N.B: never hits if some patch a replacement, patches are never drafts
|
||||
return applyPatchesImpl(base, patches)
|
||||
}
|
||||
// Otherwise, produce a copy of the base state.
|
||||
return this.produce(base, (draft: Drafted) =>
|
||||
applyPatchesImpl(draft, patches)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function createProxy<T extends Objectish>(
|
||||
rootScope: ImmerScope,
|
||||
value: T,
|
||||
parent?: ImmerState,
|
||||
key?: string | number | symbol
|
||||
): Drafted<T, ImmerState> {
|
||||
// precondition: createProxy should be guarded by isDraftable, so we know we can safely draft
|
||||
// returning a tuple here lets us skip a proxy access
|
||||
// to DRAFT_STATE later
|
||||
const [draft, state] = isMap(value)
|
||||
? getPlugin(PluginMapSet).proxyMap_(value, parent)
|
||||
: isSet(value)
|
||||
? getPlugin(PluginMapSet).proxySet_(value, parent)
|
||||
: createProxyProxy(value, parent)
|
||||
|
||||
const scope = parent?.scope_ ?? getCurrentScope()
|
||||
scope.drafts_.push(draft)
|
||||
|
||||
// Ensure the parent callbacks are passed down so we actually
|
||||
// track all callbacks added throughout the tree
|
||||
state.callbacks_ = parent?.callbacks_ ?? []
|
||||
state.key_ = key
|
||||
|
||||
if (parent && key !== undefined) {
|
||||
registerChildFinalizationCallback(parent, state, key)
|
||||
} else {
|
||||
// It's a root draft, register it with the scope
|
||||
state.callbacks_.push(function rootDraftCleanup(rootScope) {
|
||||
rootScope.mapSetPlugin_?.fixSetContents(state)
|
||||
|
||||
const {patchPlugin_} = rootScope
|
||||
|
||||
if (state.modified_ && patchPlugin_) {
|
||||
patchPlugin_.generatePatches_(state, [], rootScope)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return draft as any
|
||||
}
|
||||
336
frontend/node_modules/immer/src/core/proxy.ts
generated
vendored
Normal file
336
frontend/node_modules/immer/src/core/proxy.ts
generated
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
import {
|
||||
has,
|
||||
is,
|
||||
isDraftable,
|
||||
shallowCopy,
|
||||
latest,
|
||||
ImmerBaseState,
|
||||
ImmerState,
|
||||
Drafted,
|
||||
AnyObject,
|
||||
AnyArray,
|
||||
Objectish,
|
||||
getCurrentScope,
|
||||
getPrototypeOf,
|
||||
DRAFT_STATE,
|
||||
die,
|
||||
createProxy,
|
||||
ArchType,
|
||||
handleCrossReference,
|
||||
WRITABLE,
|
||||
CONFIGURABLE,
|
||||
ENUMERABLE,
|
||||
VALUE,
|
||||
isArray,
|
||||
isArrayIndex
|
||||
} from "../internal"
|
||||
|
||||
interface ProxyBaseState extends ImmerBaseState {
|
||||
parent_?: ImmerState
|
||||
revoke_(): void
|
||||
}
|
||||
|
||||
export interface ProxyObjectState extends ProxyBaseState {
|
||||
type_: ArchType.Object
|
||||
base_: any
|
||||
copy_: any
|
||||
draft_: Drafted<AnyObject, ProxyObjectState>
|
||||
}
|
||||
|
||||
export interface ProxyArrayState extends ProxyBaseState {
|
||||
type_: ArchType.Array
|
||||
base_: AnyArray
|
||||
copy_: AnyArray | null
|
||||
draft_: Drafted<AnyArray, ProxyArrayState>
|
||||
operationMethod?: string
|
||||
allIndicesReassigned_?: boolean
|
||||
}
|
||||
|
||||
type ProxyState = ProxyObjectState | ProxyArrayState
|
||||
|
||||
/**
|
||||
* Returns a new draft of the `base` object.
|
||||
*
|
||||
* The second argument is the parent draft-state (used internally).
|
||||
*/
|
||||
export function createProxyProxy<T extends Objectish>(
|
||||
base: T,
|
||||
parent?: ImmerState
|
||||
): [Drafted<T, ProxyState>, ProxyState] {
|
||||
const baseIsArray = isArray(base)
|
||||
const state: ProxyState = {
|
||||
type_: baseIsArray ? ArchType.Array : (ArchType.Object as any),
|
||||
// Track which produce call this is associated with.
|
||||
scope_: parent ? parent.scope_ : getCurrentScope()!,
|
||||
// True for both shallow and deep changes.
|
||||
modified_: false,
|
||||
// Used during finalization.
|
||||
finalized_: false,
|
||||
// Track which properties have been assigned (true) or deleted (false).
|
||||
// actually instantiated in `prepareCopy()`
|
||||
assigned_: undefined,
|
||||
// The parent draft state.
|
||||
parent_: parent,
|
||||
// The base state.
|
||||
base_: base,
|
||||
// The base proxy.
|
||||
draft_: null as any, // set below
|
||||
// The base copy with any updated values.
|
||||
copy_: null,
|
||||
// Called by the `produce` function.
|
||||
revoke_: null as any,
|
||||
isManual_: false,
|
||||
// `callbacks` actually gets assigned in `createProxy`
|
||||
callbacks_: undefined as any
|
||||
}
|
||||
|
||||
// the traps must target something, a bit like the 'real' base.
|
||||
// but also, we need to be able to determine from the target what the relevant state is
|
||||
// (to avoid creating traps per instance to capture the state in closure,
|
||||
// and to avoid creating weird hidden properties as well)
|
||||
// So the trick is to use 'state' as the actual 'target'! (and make sure we intercept everything)
|
||||
// Note that in the case of an array, we put the state in an array to have better Reflect defaults ootb
|
||||
let target: T = state as any
|
||||
let traps: ProxyHandler<object | Array<any>> = objectTraps
|
||||
if (baseIsArray) {
|
||||
target = [state] as any
|
||||
traps = arrayTraps
|
||||
}
|
||||
|
||||
const {revoke, proxy} = Proxy.revocable(target, traps)
|
||||
state.draft_ = proxy as any
|
||||
state.revoke_ = revoke
|
||||
return [proxy as any, state]
|
||||
}
|
||||
|
||||
/**
|
||||
* Object drafts
|
||||
*/
|
||||
export const objectTraps: ProxyHandler<ProxyState> = {
|
||||
get(state, prop) {
|
||||
if (prop === DRAFT_STATE) return state
|
||||
|
||||
let arrayPlugin = state.scope_.arrayMethodsPlugin_
|
||||
const isArrayWithStringProp =
|
||||
state.type_ === ArchType.Array && typeof prop === "string"
|
||||
// Intercept array methods so that we can override
|
||||
// behavior and skip proxy creation for perf
|
||||
if (isArrayWithStringProp) {
|
||||
if (arrayPlugin?.isArrayOperationMethod(prop)) {
|
||||
return arrayPlugin.createMethodInterceptor(state, prop)
|
||||
}
|
||||
}
|
||||
|
||||
const source = latest(state)
|
||||
if (!has(source, prop, state.type_)) {
|
||||
// non-existing or non-own property...
|
||||
return readPropFromProto(state, source, prop)
|
||||
}
|
||||
const value = source[prop]
|
||||
if (state.finalized_ || !isDraftable(value)) {
|
||||
return value
|
||||
}
|
||||
|
||||
// During mutating array operations, defer proxy creation for array elements
|
||||
// This optimization avoids creating unnecessary proxies during sort/reverse
|
||||
if (
|
||||
isArrayWithStringProp &&
|
||||
(state as ProxyArrayState).operationMethod &&
|
||||
arrayPlugin?.isMutatingArrayMethod(
|
||||
(state as ProxyArrayState).operationMethod!
|
||||
) &&
|
||||
isArrayIndex(prop)
|
||||
) {
|
||||
// Return raw value during mutating operations, create proxy only if modified
|
||||
return value
|
||||
}
|
||||
// Check for existing draft in modified state.
|
||||
// Assigned values are never drafted. This catches any drafts we created, too.
|
||||
if (value === peek(state.base_, prop)) {
|
||||
prepareCopy(state)
|
||||
// Ensure array keys are always numbers
|
||||
const childKey = state.type_ === ArchType.Array ? +(prop as string) : prop
|
||||
const childDraft = createProxy(state.scope_, value, state, childKey)
|
||||
|
||||
return (state.copy_![childKey] = childDraft)
|
||||
}
|
||||
return value
|
||||
},
|
||||
has(state, prop) {
|
||||
return prop in latest(state)
|
||||
},
|
||||
ownKeys(state) {
|
||||
return Reflect.ownKeys(latest(state))
|
||||
},
|
||||
set(
|
||||
state: ProxyObjectState,
|
||||
prop: string /* strictly not, but helps TS */,
|
||||
value
|
||||
) {
|
||||
const desc = getDescriptorFromProto(latest(state), prop)
|
||||
if (desc?.set) {
|
||||
// special case: if this write is captured by a setter, we have
|
||||
// to trigger it with the correct context
|
||||
desc.set.call(state.draft_, value)
|
||||
return true
|
||||
}
|
||||
if (!state.modified_) {
|
||||
// the last check is because we need to be able to distinguish setting a non-existing to undefined (which is a change)
|
||||
// from setting an existing property with value undefined to undefined (which is not a change)
|
||||
const current = peek(latest(state), prop)
|
||||
// special case, if we assigning the original value to a draft, we can ignore the assignment
|
||||
const currentState: ProxyObjectState = current?.[DRAFT_STATE]
|
||||
if (currentState && currentState.base_ === value) {
|
||||
state.copy_![prop] = value
|
||||
state.assigned_!.set(prop, false)
|
||||
return true
|
||||
}
|
||||
if (
|
||||
is(value, current) &&
|
||||
(value !== undefined || has(state.base_, prop, state.type_))
|
||||
)
|
||||
return true
|
||||
prepareCopy(state)
|
||||
markChanged(state)
|
||||
}
|
||||
|
||||
if (
|
||||
(state.copy_![prop] === value &&
|
||||
// special case: handle new props with value 'undefined'
|
||||
(value !== undefined || prop in state.copy_)) ||
|
||||
// special case: NaN
|
||||
(Number.isNaN(value) && Number.isNaN(state.copy_![prop]))
|
||||
)
|
||||
return true
|
||||
|
||||
// @ts-ignore
|
||||
state.copy_![prop] = value
|
||||
state.assigned_!.set(prop, true)
|
||||
|
||||
handleCrossReference(state, prop, value)
|
||||
return true
|
||||
},
|
||||
deleteProperty(state, prop: string) {
|
||||
prepareCopy(state)
|
||||
// The `undefined` check is a fast path for pre-existing keys.
|
||||
if (peek(state.base_, prop) !== undefined || prop in state.base_) {
|
||||
state.assigned_!.set(prop, false)
|
||||
markChanged(state)
|
||||
} else {
|
||||
// if an originally not assigned property was deleted
|
||||
state.assigned_!.delete(prop)
|
||||
}
|
||||
if (state.copy_) {
|
||||
delete state.copy_[prop]
|
||||
}
|
||||
return true
|
||||
},
|
||||
// Note: We never coerce `desc.value` into an Immer draft, because we can't make
|
||||
// the same guarantee in ES5 mode.
|
||||
getOwnPropertyDescriptor(state, prop) {
|
||||
const owner = latest(state)
|
||||
const desc = Reflect.getOwnPropertyDescriptor(owner, prop)
|
||||
if (!desc) return desc
|
||||
return {
|
||||
[WRITABLE]: true,
|
||||
[CONFIGURABLE]: state.type_ !== ArchType.Array || prop !== "length",
|
||||
[ENUMERABLE]: desc[ENUMERABLE],
|
||||
[VALUE]: owner[prop]
|
||||
}
|
||||
},
|
||||
defineProperty() {
|
||||
die(11)
|
||||
},
|
||||
getPrototypeOf(state) {
|
||||
return getPrototypeOf(state.base_)
|
||||
},
|
||||
setPrototypeOf() {
|
||||
die(12)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Array drafts
|
||||
*/
|
||||
|
||||
const arrayTraps: ProxyHandler<[ProxyArrayState]> = {}
|
||||
// Use `for..in` instead of `each` to work around a weird
|
||||
// prod test suite issue
|
||||
for (let key in objectTraps) {
|
||||
let fn = objectTraps[key as keyof typeof objectTraps] as Function
|
||||
// @ts-ignore
|
||||
arrayTraps[key] = function() {
|
||||
const args = arguments
|
||||
args[0] = args[0][0]
|
||||
return fn.apply(this, args)
|
||||
}
|
||||
}
|
||||
arrayTraps.deleteProperty = function(state, prop) {
|
||||
if (process.env.NODE_ENV !== "production" && isNaN(parseInt(prop as any)))
|
||||
die(13)
|
||||
// @ts-ignore
|
||||
return arrayTraps.set!.call(this, state, prop, undefined)
|
||||
}
|
||||
arrayTraps.set = function(state, prop, value) {
|
||||
if (
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
prop !== "length" &&
|
||||
isNaN(parseInt(prop as any))
|
||||
)
|
||||
die(14)
|
||||
return objectTraps.set!.call(this, state[0], prop, value, state[0])
|
||||
}
|
||||
|
||||
// Access a property without creating an Immer draft.
|
||||
function peek(draft: Drafted, prop: PropertyKey) {
|
||||
const state = draft[DRAFT_STATE]
|
||||
const source = state ? latest(state) : draft
|
||||
return source[prop]
|
||||
}
|
||||
|
||||
function readPropFromProto(state: ImmerState, source: any, prop: PropertyKey) {
|
||||
const desc = getDescriptorFromProto(source, prop)
|
||||
return desc
|
||||
? VALUE in desc
|
||||
? desc[VALUE]
|
||||
: // This is a very special case, if the prop is a getter defined by the
|
||||
// prototype, we should invoke it with the draft as context!
|
||||
desc.get?.call(state.draft_)
|
||||
: undefined
|
||||
}
|
||||
|
||||
function getDescriptorFromProto(
|
||||
source: any,
|
||||
prop: PropertyKey
|
||||
): PropertyDescriptor | undefined {
|
||||
// 'in' checks proto!
|
||||
if (!(prop in source)) return undefined
|
||||
let proto = getPrototypeOf(source)
|
||||
while (proto) {
|
||||
const desc = Object.getOwnPropertyDescriptor(proto, prop)
|
||||
if (desc) return desc
|
||||
proto = getPrototypeOf(proto)
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
export function markChanged(state: ImmerState) {
|
||||
if (!state.modified_) {
|
||||
state.modified_ = true
|
||||
if (state.parent_) {
|
||||
markChanged(state.parent_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function prepareCopy(state: ImmerState) {
|
||||
if (!state.copy_) {
|
||||
// Actually create the `assigned_` map now that we
|
||||
// know this is a modified draft.
|
||||
state.assigned_ = new Map()
|
||||
state.copy_ = shallowCopy(
|
||||
state.base_,
|
||||
state.scope_.immer_.useStrictShallowCopy_
|
||||
)
|
||||
}
|
||||
}
|
||||
95
frontend/node_modules/immer/src/core/scope.ts
generated
vendored
Normal file
95
frontend/node_modules/immer/src/core/scope.ts
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import {
|
||||
Patch,
|
||||
PatchListener,
|
||||
Drafted,
|
||||
Immer,
|
||||
DRAFT_STATE,
|
||||
ImmerState,
|
||||
ArchType,
|
||||
getPlugin,
|
||||
PatchesPlugin,
|
||||
MapSetPlugin,
|
||||
isPluginLoaded,
|
||||
PluginMapSet,
|
||||
PluginPatches,
|
||||
ArrayMethodsPlugin,
|
||||
PluginArrayMethods
|
||||
} from "../internal"
|
||||
|
||||
/** Each scope represents a `produce` call. */
|
||||
|
||||
export interface ImmerScope {
|
||||
patches_?: Patch[]
|
||||
inversePatches_?: Patch[]
|
||||
patchPlugin_?: PatchesPlugin
|
||||
mapSetPlugin_?: MapSetPlugin
|
||||
arrayMethodsPlugin_?: ArrayMethodsPlugin
|
||||
canAutoFreeze_: boolean
|
||||
drafts_: any[]
|
||||
parent_?: ImmerScope
|
||||
patchListener_?: PatchListener
|
||||
immer_: Immer
|
||||
unfinalizedDrafts_: number
|
||||
handledSet_: Set<any>
|
||||
processedForPatches_: Set<any>
|
||||
}
|
||||
|
||||
let currentScope: ImmerScope | undefined
|
||||
|
||||
export let getCurrentScope = () => currentScope!
|
||||
|
||||
let createScope = (
|
||||
parent_: ImmerScope | undefined,
|
||||
immer_: Immer
|
||||
): ImmerScope => ({
|
||||
drafts_: [],
|
||||
parent_,
|
||||
immer_,
|
||||
// Whenever the modified draft contains a draft from another scope, we
|
||||
// need to prevent auto-freezing so the unowned draft can be finalized.
|
||||
canAutoFreeze_: true,
|
||||
unfinalizedDrafts_: 0,
|
||||
handledSet_: new Set(),
|
||||
processedForPatches_: new Set(),
|
||||
mapSetPlugin_: isPluginLoaded(PluginMapSet)
|
||||
? getPlugin(PluginMapSet)
|
||||
: undefined,
|
||||
arrayMethodsPlugin_: isPluginLoaded(PluginArrayMethods)
|
||||
? getPlugin(PluginArrayMethods)
|
||||
: undefined
|
||||
})
|
||||
|
||||
export function usePatchesInScope(
|
||||
scope: ImmerScope,
|
||||
patchListener?: PatchListener
|
||||
) {
|
||||
if (patchListener) {
|
||||
scope.patchPlugin_ = getPlugin(PluginPatches) // assert we have the plugin
|
||||
scope.patches_ = []
|
||||
scope.inversePatches_ = []
|
||||
scope.patchListener_ = patchListener
|
||||
}
|
||||
}
|
||||
|
||||
export function revokeScope(scope: ImmerScope) {
|
||||
leaveScope(scope)
|
||||
scope.drafts_.forEach(revokeDraft)
|
||||
// @ts-ignore
|
||||
scope.drafts_ = null
|
||||
}
|
||||
|
||||
export function leaveScope(scope: ImmerScope) {
|
||||
if (scope === currentScope) {
|
||||
currentScope = scope.parent_
|
||||
}
|
||||
}
|
||||
|
||||
export let enterScope = (immer: Immer) =>
|
||||
(currentScope = createScope(currentScope, immer))
|
||||
|
||||
function revokeDraft(draft: Drafted) {
|
||||
const state: ImmerState = draft[DRAFT_STATE]
|
||||
if (state.type_ === ArchType.Object || state.type_ === ArchType.Array)
|
||||
state.revoke_()
|
||||
else state.revoked_ = true
|
||||
}
|
||||
126
frontend/node_modules/immer/src/immer.ts
generated
vendored
Normal file
126
frontend/node_modules/immer/src/immer.ts
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
import {
|
||||
IProduce,
|
||||
IProduceWithPatches,
|
||||
Immer,
|
||||
Draft,
|
||||
Immutable
|
||||
} from "./internal"
|
||||
|
||||
export {
|
||||
Draft,
|
||||
WritableDraft,
|
||||
Immutable,
|
||||
Patch,
|
||||
PatchListener,
|
||||
Producer,
|
||||
original,
|
||||
current,
|
||||
isDraft,
|
||||
isDraftable,
|
||||
NOTHING as nothing,
|
||||
DRAFTABLE as immerable,
|
||||
freeze,
|
||||
Objectish,
|
||||
StrictMode
|
||||
} from "./internal"
|
||||
|
||||
const immer = new Immer()
|
||||
|
||||
/**
|
||||
* The `produce` function takes a value and a "recipe function" (whose
|
||||
* return value often depends on the base state). The recipe function is
|
||||
* free to mutate its first argument however it wants. All mutations are
|
||||
* only ever applied to a __copy__ of the base state.
|
||||
*
|
||||
* Pass only a function to create a "curried producer" which relieves you
|
||||
* from passing the recipe function every time.
|
||||
*
|
||||
* Only plain objects and arrays are made mutable. All other objects are
|
||||
* considered uncopyable.
|
||||
*
|
||||
* Note: This function is __bound__ to its `Immer` instance.
|
||||
*
|
||||
* @param {any} base - the initial state
|
||||
* @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
|
||||
* @param {Function} patchListener - optional function that will be called with all the patches produced here
|
||||
* @returns {any} a new state, or the initial state if nothing was modified
|
||||
*/
|
||||
export const produce: IProduce = /* @__PURE__ */ immer.produce
|
||||
|
||||
/**
|
||||
* Like `produce`, but `produceWithPatches` always returns a tuple
|
||||
* [nextState, patches, inversePatches] (instead of just the next state)
|
||||
*/
|
||||
export const produceWithPatches: IProduceWithPatches = /* @__PURE__ */ immer.produceWithPatches.bind(
|
||||
immer
|
||||
)
|
||||
|
||||
/**
|
||||
* Pass true to automatically freeze all copies created by Immer.
|
||||
*
|
||||
* Always freeze by default, even in production mode
|
||||
*/
|
||||
export const setAutoFreeze = /* @__PURE__ */ immer.setAutoFreeze.bind(immer)
|
||||
|
||||
/**
|
||||
* Pass true to enable strict shallow copy.
|
||||
*
|
||||
* By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
|
||||
*/
|
||||
export const setUseStrictShallowCopy = /* @__PURE__ */ immer.setUseStrictShallowCopy.bind(
|
||||
immer
|
||||
)
|
||||
|
||||
/**
|
||||
* Pass false to use loose iteration that only processes enumerable string properties.
|
||||
* This skips symbols and non-enumerable properties for maximum performance.
|
||||
*
|
||||
* By default, strict iteration is enabled (includes all own properties).
|
||||
*/
|
||||
export const setUseStrictIteration = /* @__PURE__ */ immer.setUseStrictIteration.bind(
|
||||
immer
|
||||
)
|
||||
|
||||
/**
|
||||
* Apply an array of Immer patches to the first argument.
|
||||
*
|
||||
* This function is a producer, which means copy-on-write is in effect.
|
||||
*/
|
||||
export const applyPatches = /* @__PURE__ */ immer.applyPatches.bind(immer)
|
||||
|
||||
/**
|
||||
* Create an Immer draft from the given base state, which may be a draft itself.
|
||||
* The draft can be modified until you finalize it with the `finishDraft` function.
|
||||
*/
|
||||
export const createDraft = /* @__PURE__ */ immer.createDraft.bind(immer)
|
||||
|
||||
/**
|
||||
* Finalize an Immer draft from a `createDraft` call, returning the base state
|
||||
* (if no changes were made) or a modified copy. The draft must *not* be
|
||||
* mutated afterwards.
|
||||
*
|
||||
* Pass a function as the 2nd argument to generate Immer patches based on the
|
||||
* changes that were made.
|
||||
*/
|
||||
export const finishDraft = /* @__PURE__ */ immer.finishDraft.bind(immer)
|
||||
|
||||
/**
|
||||
* This function is actually a no-op, but can be used to cast an immutable type
|
||||
* to an draft type and make TypeScript happy
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
export let castDraft = <T>(value: T): Draft<T> => value as any
|
||||
|
||||
/**
|
||||
* This function is actually a no-op, but can be used to cast a mutable type
|
||||
* to an immutable type and make TypeScript happy
|
||||
* @param value
|
||||
*/
|
||||
export let castImmutable = <T>(value: T): Immutable<T> => value as any
|
||||
|
||||
export {Immer}
|
||||
|
||||
export {enablePatches} from "./plugins/patches"
|
||||
export {enableMapSet} from "./plugins/mapset"
|
||||
export {enableArrayMethods} from "./plugins/arrayMethods"
|
||||
11
frontend/node_modules/immer/src/internal.ts
generated
vendored
Normal file
11
frontend/node_modules/immer/src/internal.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
export * from "./utils/env"
|
||||
export * from "./utils/errors"
|
||||
export * from "./types/types-external"
|
||||
export * from "./types/types-internal"
|
||||
export * from "./utils/common"
|
||||
export * from "./utils/plugins"
|
||||
export * from "./core/scope"
|
||||
export * from "./core/finalize"
|
||||
export * from "./core/proxy"
|
||||
export * from "./core/immerClass"
|
||||
export * from "./core/current"
|
||||
440
frontend/node_modules/immer/src/plugins/arrayMethods.ts
generated
vendored
Normal file
440
frontend/node_modules/immer/src/plugins/arrayMethods.ts
generated
vendored
Normal file
@@ -0,0 +1,440 @@
|
||||
import {
|
||||
PluginArrayMethods,
|
||||
latest,
|
||||
loadPlugin,
|
||||
markChanged,
|
||||
prepareCopy,
|
||||
handleCrossReference,
|
||||
ProxyArrayState
|
||||
} from "../internal"
|
||||
|
||||
/**
|
||||
* Methods that directly modify the array in place.
|
||||
* These operate on the copy without creating per-element proxies:
|
||||
* - `push`, `pop`: Add/remove from end
|
||||
* - `shift`, `unshift`: Add/remove from start (marks all indices reassigned)
|
||||
* - `splice`: Add/remove at arbitrary position (marks all indices reassigned)
|
||||
* - `reverse`, `sort`: Reorder elements (marks all indices reassigned)
|
||||
*/
|
||||
type MutatingArrayMethod =
|
||||
| "push"
|
||||
| "pop"
|
||||
| "shift"
|
||||
| "unshift"
|
||||
| "splice"
|
||||
| "reverse"
|
||||
| "sort"
|
||||
|
||||
/**
|
||||
* Methods that read from the array without modifying it.
|
||||
* These fall into distinct categories based on return semantics:
|
||||
*
|
||||
* **Subset operations** (return drafts - mutations propagate):
|
||||
* - `filter`, `slice`: Return array of draft proxies
|
||||
* - `find`, `findLast`: Return single draft proxy or undefined
|
||||
*
|
||||
* **Transform operations** (return base values - mutations don't track):
|
||||
* - `concat`, `flat`: Create new structures, not subsets of original
|
||||
*
|
||||
* **Primitive-returning** (no draft needed):
|
||||
* - `findIndex`, `findLastIndex`, `indexOf`, `lastIndexOf`: Return numbers
|
||||
* - `some`, `every`, `includes`: Return booleans
|
||||
* - `join`, `toString`, `toLocaleString`: Return strings
|
||||
*/
|
||||
type NonMutatingArrayMethod =
|
||||
| "filter"
|
||||
| "slice"
|
||||
| "concat"
|
||||
| "flat"
|
||||
| "find"
|
||||
| "findIndex"
|
||||
| "findLast"
|
||||
| "findLastIndex"
|
||||
| "some"
|
||||
| "every"
|
||||
| "indexOf"
|
||||
| "lastIndexOf"
|
||||
| "includes"
|
||||
| "join"
|
||||
| "toString"
|
||||
| "toLocaleString"
|
||||
|
||||
/** Union of all array operation methods handled by the plugin. */
|
||||
export type ArrayOperationMethod = MutatingArrayMethod | NonMutatingArrayMethod
|
||||
|
||||
/**
|
||||
* Enables optimized array method handling for Immer drafts.
|
||||
*
|
||||
* This plugin overrides array methods to avoid unnecessary Proxy creation during iteration,
|
||||
* significantly improving performance for array-heavy operations.
|
||||
*
|
||||
* **Mutating methods** (push, pop, shift, unshift, splice, sort, reverse):
|
||||
* Operate directly on the copy without creating per-element proxies.
|
||||
*
|
||||
* **Non-mutating methods** fall into categories:
|
||||
* - **Subset operations** (filter, slice, find, findLast): Return draft proxies - mutations track
|
||||
* - **Transform operations** (concat, flat): Return base values - mutations don't track
|
||||
* - **Primitive-returning** (indexOf, includes, some, every, etc.): Return primitives
|
||||
*
|
||||
* **Important**: Callbacks for overridden methods receive base values, not drafts.
|
||||
* This is the core performance optimization.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* import { enableArrayMethods, produce } from "immer"
|
||||
*
|
||||
* enableArrayMethods()
|
||||
*
|
||||
* const next = produce(state, draft => {
|
||||
* // Optimized - no proxy creation per element
|
||||
* draft.items.sort((a, b) => a.value - b.value)
|
||||
*
|
||||
* // filter returns drafts - mutations propagate
|
||||
* const filtered = draft.items.filter(x => x.value > 5)
|
||||
* filtered[0].value = 999 // Affects draft.items[originalIndex]
|
||||
* })
|
||||
* ```
|
||||
*
|
||||
* @see https://immerjs.github.io/immer/array-methods
|
||||
*/
|
||||
export function enableArrayMethods() {
|
||||
const SHIFTING_METHODS = new Set<MutatingArrayMethod>(["shift", "unshift"])
|
||||
|
||||
const QUEUE_METHODS = new Set<MutatingArrayMethod>(["push", "pop"])
|
||||
|
||||
const RESULT_RETURNING_METHODS = new Set<MutatingArrayMethod>([
|
||||
...QUEUE_METHODS,
|
||||
...SHIFTING_METHODS
|
||||
])
|
||||
|
||||
const REORDERING_METHODS = new Set<MutatingArrayMethod>(["reverse", "sort"])
|
||||
|
||||
// Optimized method detection using array-based lookup
|
||||
const MUTATING_METHODS = new Set<MutatingArrayMethod>([
|
||||
...RESULT_RETURNING_METHODS,
|
||||
...REORDERING_METHODS,
|
||||
"splice"
|
||||
])
|
||||
|
||||
const FIND_METHODS = new Set<NonMutatingArrayMethod>(["find", "findLast"])
|
||||
|
||||
const NON_MUTATING_METHODS = new Set<NonMutatingArrayMethod>([
|
||||
"filter",
|
||||
"slice",
|
||||
"concat",
|
||||
"flat",
|
||||
...FIND_METHODS,
|
||||
"findIndex",
|
||||
"findLastIndex",
|
||||
"some",
|
||||
"every",
|
||||
"indexOf",
|
||||
"lastIndexOf",
|
||||
"includes",
|
||||
"join",
|
||||
"toString",
|
||||
"toLocaleString"
|
||||
])
|
||||
|
||||
// Type guard for method detection
|
||||
function isMutatingArrayMethod(
|
||||
method: string
|
||||
): method is MutatingArrayMethod {
|
||||
return MUTATING_METHODS.has(method as any)
|
||||
}
|
||||
|
||||
function isNonMutatingArrayMethod(
|
||||
method: string
|
||||
): method is NonMutatingArrayMethod {
|
||||
return NON_MUTATING_METHODS.has(method as any)
|
||||
}
|
||||
|
||||
function isArrayOperationMethod(
|
||||
method: string
|
||||
): method is ArrayOperationMethod {
|
||||
return isMutatingArrayMethod(method) || isNonMutatingArrayMethod(method)
|
||||
}
|
||||
|
||||
function enterOperation(
|
||||
state: ProxyArrayState,
|
||||
method: ArrayOperationMethod
|
||||
) {
|
||||
state.operationMethod = method
|
||||
}
|
||||
|
||||
function exitOperation(state: ProxyArrayState) {
|
||||
state.operationMethod = undefined
|
||||
}
|
||||
|
||||
// Shared utility functions for array method handlers
|
||||
function executeArrayMethod<T>(
|
||||
state: ProxyArrayState,
|
||||
operation: () => T,
|
||||
markLength = true
|
||||
): T {
|
||||
prepareCopy(state)
|
||||
const result = operation()
|
||||
markChanged(state)
|
||||
if (markLength) state.assigned_!.set("length", true)
|
||||
return result
|
||||
}
|
||||
|
||||
function markAllIndicesReassigned(state: ProxyArrayState) {
|
||||
state.allIndicesReassigned_ = true
|
||||
}
|
||||
|
||||
function normalizeSliceIndex(index: number, length: number): number {
|
||||
if (index < 0) {
|
||||
return Math.max(length + index, 0)
|
||||
}
|
||||
return Math.min(index, length)
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls handleCrossReference for each value being inserted into the array,
|
||||
* and marks the corresponding indices as assigned in `assigned_`.
|
||||
*
|
||||
* This ensures nested drafts inside inserted values (e.g. from spreading
|
||||
* a draft object) are properly finalized, matching the behavior of the
|
||||
* proxy set trap which calls handleCrossReference on every assignment.
|
||||
*
|
||||
* Without this, values containing draft proxies (like `{...state[0]}`)
|
||||
* pushed via the array methods plugin would have their nested drafts
|
||||
* revoked during finalization without being replaced by final values.
|
||||
*/
|
||||
function handleInsertedValues(
|
||||
state: ProxyArrayState,
|
||||
startIndex: number,
|
||||
values: any[]
|
||||
) {
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
const index = startIndex + i
|
||||
state.assigned_!.set(index, true)
|
||||
handleCrossReference(state, index, values[i])
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles mutating operations that add/remove elements (push, pop, shift, unshift, splice).
|
||||
*
|
||||
* Operates directly on `state.copy_` without creating per-element proxies.
|
||||
* For shifting methods (shift, unshift), marks all indices as reassigned since
|
||||
* indices shift.
|
||||
*
|
||||
* @returns For push/pop/shift/unshift: the native method result. For others: the draft.
|
||||
*/
|
||||
function handleSimpleOperation(
|
||||
state: ProxyArrayState,
|
||||
method: string,
|
||||
args: any[]
|
||||
) {
|
||||
return executeArrayMethod(state, () => {
|
||||
// For push/unshift, capture the length before the operation
|
||||
// so we can compute insertion indices for handleCrossReference
|
||||
const lengthBefore = state.copy_!.length
|
||||
|
||||
const result = (state.copy_! as any)[method](...args)
|
||||
|
||||
// Handle index reassignment for shifting methods
|
||||
if (SHIFTING_METHODS.has(method as MutatingArrayMethod)) {
|
||||
markAllIndicesReassigned(state)
|
||||
}
|
||||
|
||||
// Handle cross-references for newly inserted values.
|
||||
// push appends at the end, unshift inserts at the beginning.
|
||||
if (method === "push" && args.length > 0) {
|
||||
handleInsertedValues(state, lengthBefore, args)
|
||||
} else if (method === "unshift" && args.length > 0) {
|
||||
handleInsertedValues(state, 0, args)
|
||||
}
|
||||
|
||||
// Return appropriate value based on method
|
||||
return RESULT_RETURNING_METHODS.has(method as MutatingArrayMethod)
|
||||
? result
|
||||
: state.draft_
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles reordering operations (reverse, sort) that change element order.
|
||||
*
|
||||
* Operates directly on `state.copy_` and marks all indices as reassigned
|
||||
* since element positions change. Does not mark length as changed since
|
||||
* these operations preserve array length.
|
||||
*
|
||||
* @returns The draft proxy for method chaining.
|
||||
*/
|
||||
function handleReorderingOperation(
|
||||
state: ProxyArrayState,
|
||||
method: string,
|
||||
args: any[]
|
||||
) {
|
||||
return executeArrayMethod(
|
||||
state,
|
||||
() => {
|
||||
;(state.copy_! as any)[method](...args)
|
||||
markAllIndicesReassigned(state)
|
||||
return state.draft_
|
||||
},
|
||||
false
|
||||
) // Don't mark length as changed
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an interceptor function for a specific array method.
|
||||
*
|
||||
* The interceptor wraps array method calls to:
|
||||
* 1. Set `state.operationMethod` flag during execution (allows proxy `get` trap
|
||||
* to detect we're inside an optimized method and skip proxy creation)
|
||||
* 2. Route to appropriate handler based on method type
|
||||
* 3. Clean up the operation flag in `finally` block
|
||||
*
|
||||
* The `operationMethod` flag is the key mechanism that enables the proxy's `get`
|
||||
* trap to return base values instead of creating nested proxies during iteration.
|
||||
*
|
||||
* @param state - The proxy array state
|
||||
* @param originalMethod - Name of the array method being intercepted
|
||||
* @returns Interceptor function that handles the method call
|
||||
*/
|
||||
function createMethodInterceptor(
|
||||
state: ProxyArrayState,
|
||||
originalMethod: string
|
||||
) {
|
||||
return function interceptedMethod(...args: any[]) {
|
||||
// Enter operation mode - this flag tells the proxy's get trap to return
|
||||
// base values instead of creating nested proxies during iteration
|
||||
const method = originalMethod as ArrayOperationMethod
|
||||
enterOperation(state, method)
|
||||
|
||||
try {
|
||||
// Check if this is a mutating method
|
||||
if (isMutatingArrayMethod(method)) {
|
||||
// Direct method dispatch - no configuration lookup needed
|
||||
if (RESULT_RETURNING_METHODS.has(method)) {
|
||||
return handleSimpleOperation(state, method, args)
|
||||
}
|
||||
if (REORDERING_METHODS.has(method)) {
|
||||
return handleReorderingOperation(state, method, args)
|
||||
}
|
||||
|
||||
if (method === "splice") {
|
||||
const res = executeArrayMethod(state, () =>
|
||||
state.copy_!.splice(...(args as [number, number, ...any[]]))
|
||||
)
|
||||
markAllIndicesReassigned(state)
|
||||
// Handle cross-references for inserted values (args from index 2+)
|
||||
if (args.length > 2) {
|
||||
const startIndex = normalizeSliceIndex(
|
||||
args[0] ?? 0,
|
||||
state.copy_!.length
|
||||
)
|
||||
handleInsertedValues(state, startIndex, args.slice(2))
|
||||
}
|
||||
return res
|
||||
}
|
||||
} else {
|
||||
// Handle non-mutating methods
|
||||
return handleNonMutatingOperation(state, method, args)
|
||||
}
|
||||
} finally {
|
||||
// Always exit operation mode - must be in finally to handle exceptions
|
||||
exitOperation(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles non-mutating array methods with different return semantics.
|
||||
*
|
||||
* **Subset operations** return draft proxies for mutation tracking:
|
||||
* - `filter`, `slice`: Return `state.draft_[i]` for each selected element
|
||||
* - `find`, `findLast`: Return `state.draft_[i]` for the found element
|
||||
*
|
||||
* This allows mutations on returned elements to propagate back to the draft:
|
||||
* ```ts
|
||||
* const filtered = draft.items.filter(x => x.value > 5)
|
||||
* filtered[0].value = 999 // Mutates draft.items[originalIndex]
|
||||
* ```
|
||||
*
|
||||
* **Transform operations** return base values (no draft tracking):
|
||||
* - `concat`, `flat`: These create NEW arrays rather than selecting subsets.
|
||||
* Since the result structure differs from the original, tracking mutations
|
||||
* back to specific draft indices would be impractical/impossible.
|
||||
*
|
||||
* **Primitive operations** return the native result directly:
|
||||
* - `indexOf`, `includes`, `some`, `every`, `join`, etc.
|
||||
*
|
||||
* @param state - The proxy array state
|
||||
* @param method - The non-mutating method name
|
||||
* @param args - Arguments passed to the method
|
||||
* @returns Drafts for subset operations, base values for transforms, primitives otherwise
|
||||
*/
|
||||
function handleNonMutatingOperation(
|
||||
state: ProxyArrayState,
|
||||
method: NonMutatingArrayMethod,
|
||||
args: any[]
|
||||
) {
|
||||
const source = latest(state)
|
||||
|
||||
// Methods that return arrays with selected items - need to return drafts
|
||||
if (method === "filter") {
|
||||
const predicate = args[0]
|
||||
const result: any[] = []
|
||||
|
||||
// First pass: call predicate on base values to determine which items pass
|
||||
for (let i = 0; i < source.length; i++) {
|
||||
if (predicate(source[i], i, source)) {
|
||||
// Only create draft for items that passed the predicate
|
||||
result.push(state.draft_[i])
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
if (FIND_METHODS.has(method)) {
|
||||
const predicate = args[0]
|
||||
const isForward = method === "find"
|
||||
const step = isForward ? 1 : -1
|
||||
const start = isForward ? 0 : source.length - 1
|
||||
|
||||
for (let i = start; i >= 0 && i < source.length; i += step) {
|
||||
if (predicate(source[i], i, source)) {
|
||||
return state.draft_[i]
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (method === "slice") {
|
||||
const rawStart = args[0] ?? 0
|
||||
const rawEnd = args[1] ?? source.length
|
||||
|
||||
// Normalize negative indices
|
||||
const start = normalizeSliceIndex(rawStart, source.length)
|
||||
const end = normalizeSliceIndex(rawEnd, source.length)
|
||||
|
||||
const result: any[] = []
|
||||
|
||||
// Return drafts for items in the slice range
|
||||
for (let i = start; i < end; i++) {
|
||||
result.push(state.draft_[i])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// For other methods, call on base array directly:
|
||||
// - indexOf, includes, join, toString: Return primitives, no draft needed
|
||||
// - concat, flat: Return NEW arrays (not subsets). Elements are base values.
|
||||
// This is intentional - concat/flat create new data structures rather than
|
||||
// selecting subsets of the original, making draft tracking impractical.
|
||||
return source[method as keyof typeof Array.prototype](...args)
|
||||
}
|
||||
|
||||
loadPlugin(PluginArrayMethods, {
|
||||
createMethodInterceptor,
|
||||
isArrayOperationMethod,
|
||||
isMutatingArrayMethod
|
||||
})
|
||||
}
|
||||
332
frontend/node_modules/immer/src/plugins/mapset.ts
generated
vendored
Normal file
332
frontend/node_modules/immer/src/plugins/mapset.ts
generated
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
// types only!
|
||||
import {
|
||||
ImmerState,
|
||||
AnyMap,
|
||||
AnySet,
|
||||
MapState,
|
||||
SetState,
|
||||
DRAFT_STATE,
|
||||
getCurrentScope,
|
||||
latest,
|
||||
isDraftable,
|
||||
createProxy,
|
||||
loadPlugin,
|
||||
markChanged,
|
||||
die,
|
||||
ArchType,
|
||||
each,
|
||||
getValue,
|
||||
PluginMapSet,
|
||||
handleCrossReference
|
||||
} from "../internal"
|
||||
|
||||
export function enableMapSet() {
|
||||
class DraftMap extends Map {
|
||||
[DRAFT_STATE]: MapState
|
||||
|
||||
constructor(target: AnyMap, parent?: ImmerState) {
|
||||
super()
|
||||
this[DRAFT_STATE] = {
|
||||
type_: ArchType.Map,
|
||||
parent_: parent,
|
||||
scope_: parent ? parent.scope_ : getCurrentScope()!,
|
||||
modified_: false,
|
||||
finalized_: false,
|
||||
copy_: undefined,
|
||||
assigned_: undefined,
|
||||
base_: target,
|
||||
draft_: this as any,
|
||||
isManual_: false,
|
||||
revoked_: false,
|
||||
callbacks_: []
|
||||
}
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return latest(this[DRAFT_STATE]).size
|
||||
}
|
||||
|
||||
has(key: any): boolean {
|
||||
return latest(this[DRAFT_STATE]).has(key)
|
||||
}
|
||||
|
||||
set(key: any, value: any) {
|
||||
const state: MapState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
if (!latest(state).has(key) || latest(state).get(key) !== value) {
|
||||
prepareMapCopy(state)
|
||||
markChanged(state)
|
||||
state.assigned_!.set(key, true)
|
||||
state.copy_!.set(key, value)
|
||||
state.assigned_!.set(key, true)
|
||||
handleCrossReference(state, key, value)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
delete(key: any): boolean {
|
||||
if (!this.has(key)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const state: MapState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
prepareMapCopy(state)
|
||||
markChanged(state)
|
||||
if (state.base_.has(key)) {
|
||||
state.assigned_!.set(key, false)
|
||||
} else {
|
||||
state.assigned_!.delete(key)
|
||||
}
|
||||
state.copy_!.delete(key)
|
||||
return true
|
||||
}
|
||||
|
||||
clear() {
|
||||
const state: MapState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
if (latest(state).size) {
|
||||
prepareMapCopy(state)
|
||||
markChanged(state)
|
||||
state.assigned_ = new Map()
|
||||
each(state.base_, key => {
|
||||
state.assigned_!.set(key, false)
|
||||
})
|
||||
state.copy_!.clear()
|
||||
}
|
||||
}
|
||||
|
||||
forEach(cb: (value: any, key: any, self: any) => void, thisArg?: any) {
|
||||
const state: MapState = this[DRAFT_STATE]
|
||||
latest(state).forEach((_value: any, key: any, _map: any) => {
|
||||
cb.call(thisArg, this.get(key), key, this)
|
||||
})
|
||||
}
|
||||
|
||||
get(key: any): any {
|
||||
const state: MapState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
const value = latest(state).get(key)
|
||||
if (state.finalized_ || !isDraftable(value)) {
|
||||
return value
|
||||
}
|
||||
if (value !== state.base_.get(key)) {
|
||||
return value // either already drafted or reassigned
|
||||
}
|
||||
// despite what it looks, this creates a draft only once, see above condition
|
||||
const draft = createProxy(state.scope_, value, state, key)
|
||||
prepareMapCopy(state)
|
||||
state.copy_!.set(key, draft)
|
||||
return draft
|
||||
}
|
||||
|
||||
keys(): IterableIterator<any> {
|
||||
return latest(this[DRAFT_STATE]).keys()
|
||||
}
|
||||
|
||||
values(): IterableIterator<any> {
|
||||
const iterator = this.keys()
|
||||
return {
|
||||
[Symbol.iterator]: () => this.values(),
|
||||
next: () => {
|
||||
const r = iterator.next()
|
||||
/* istanbul ignore next */
|
||||
if (r.done) return r
|
||||
const value = this.get(r.value)
|
||||
return {
|
||||
done: false,
|
||||
value
|
||||
}
|
||||
}
|
||||
} as any
|
||||
}
|
||||
|
||||
entries(): IterableIterator<[any, any]> {
|
||||
const iterator = this.keys()
|
||||
return {
|
||||
[Symbol.iterator]: () => this.entries(),
|
||||
next: () => {
|
||||
const r = iterator.next()
|
||||
/* istanbul ignore next */
|
||||
if (r.done) return r
|
||||
const value = this.get(r.value)
|
||||
return {
|
||||
done: false,
|
||||
value: [r.value, value]
|
||||
}
|
||||
}
|
||||
} as any
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this.entries()
|
||||
}
|
||||
}
|
||||
|
||||
function proxyMap_<T extends AnyMap>(
|
||||
target: T,
|
||||
parent?: ImmerState
|
||||
): [T, MapState] {
|
||||
// @ts-ignore
|
||||
const map = new DraftMap(target, parent)
|
||||
return [map as any, map[DRAFT_STATE]]
|
||||
}
|
||||
|
||||
function prepareMapCopy(state: MapState) {
|
||||
if (!state.copy_) {
|
||||
state.assigned_ = new Map()
|
||||
state.copy_ = new Map(state.base_)
|
||||
}
|
||||
}
|
||||
|
||||
class DraftSet extends Set {
|
||||
[DRAFT_STATE]: SetState
|
||||
constructor(target: AnySet, parent?: ImmerState) {
|
||||
super()
|
||||
this[DRAFT_STATE] = {
|
||||
type_: ArchType.Set,
|
||||
parent_: parent,
|
||||
scope_: parent ? parent.scope_ : getCurrentScope()!,
|
||||
modified_: false,
|
||||
finalized_: false,
|
||||
copy_: undefined,
|
||||
base_: target,
|
||||
draft_: this,
|
||||
drafts_: new Map(),
|
||||
revoked_: false,
|
||||
isManual_: false,
|
||||
assigned_: undefined,
|
||||
callbacks_: []
|
||||
}
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return latest(this[DRAFT_STATE]).size
|
||||
}
|
||||
|
||||
has(value: any): boolean {
|
||||
const state: SetState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
// bit of trickery here, to be able to recognize both the value, and the draft of its value
|
||||
if (!state.copy_) {
|
||||
return state.base_.has(value)
|
||||
}
|
||||
if (state.copy_.has(value)) return true
|
||||
if (state.drafts_.has(value) && state.copy_.has(state.drafts_.get(value)))
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
add(value: any): any {
|
||||
const state: SetState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
if (!this.has(value)) {
|
||||
prepareSetCopy(state)
|
||||
markChanged(state)
|
||||
state.copy_!.add(value)
|
||||
handleCrossReference(state, value, value)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
delete(value: any): any {
|
||||
if (!this.has(value)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const state: SetState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
prepareSetCopy(state)
|
||||
markChanged(state)
|
||||
return (
|
||||
state.copy_!.delete(value) ||
|
||||
(state.drafts_.has(value)
|
||||
? state.copy_!.delete(state.drafts_.get(value))
|
||||
: /* istanbul ignore next */ false)
|
||||
)
|
||||
}
|
||||
|
||||
clear() {
|
||||
const state: SetState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
if (latest(state).size) {
|
||||
prepareSetCopy(state)
|
||||
markChanged(state)
|
||||
state.copy_!.clear()
|
||||
}
|
||||
}
|
||||
|
||||
values(): IterableIterator<any> {
|
||||
const state: SetState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
prepareSetCopy(state)
|
||||
return state.copy_!.values()
|
||||
}
|
||||
|
||||
entries(): IterableIterator<[any, any]> {
|
||||
const state: SetState = this[DRAFT_STATE]
|
||||
assertUnrevoked(state)
|
||||
prepareSetCopy(state)
|
||||
return state.copy_!.entries()
|
||||
}
|
||||
|
||||
keys(): IterableIterator<any> {
|
||||
return this.values()
|
||||
}
|
||||
|
||||
[Symbol.iterator]() {
|
||||
return this.values()
|
||||
}
|
||||
|
||||
forEach(cb: any, thisArg?: any) {
|
||||
const iterator = this.values()
|
||||
let result = iterator.next()
|
||||
while (!result.done) {
|
||||
cb.call(thisArg, result.value, result.value, this)
|
||||
result = iterator.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
function proxySet_<T extends AnySet>(
|
||||
target: T,
|
||||
parent?: ImmerState
|
||||
): [T, SetState] {
|
||||
// @ts-ignore
|
||||
const set = new DraftSet(target, parent)
|
||||
return [set as any, set[DRAFT_STATE]]
|
||||
}
|
||||
|
||||
function prepareSetCopy(state: SetState) {
|
||||
if (!state.copy_) {
|
||||
// create drafts for all entries to preserve insertion order
|
||||
state.copy_ = new Set()
|
||||
state.base_.forEach(value => {
|
||||
if (isDraftable(value)) {
|
||||
const draft = createProxy(state.scope_, value, state, value)
|
||||
state.drafts_.set(value, draft)
|
||||
state.copy_!.add(draft)
|
||||
} else {
|
||||
state.copy_!.add(value)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function assertUnrevoked(state: any /*ES5State | MapState | SetState*/) {
|
||||
if (state.revoked_) die(3, JSON.stringify(latest(state)))
|
||||
}
|
||||
|
||||
function fixSetContents(target: ImmerState) {
|
||||
// For sets we clone before iterating, otherwise we can get in endless loop due to modifying during iteration, see #628
|
||||
// To preserve insertion order in all cases we then clear the set
|
||||
if (target.type_ === ArchType.Set && target.copy_) {
|
||||
const copy = new Set(target.copy_)
|
||||
target.copy_.clear()
|
||||
copy.forEach(value => {
|
||||
target.copy_!.add(getValue(value))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
loadPlugin(PluginMapSet, {proxyMap_, proxySet_, fixSetContents})
|
||||
}
|
||||
431
frontend/node_modules/immer/src/plugins/patches.ts
generated
vendored
Normal file
431
frontend/node_modules/immer/src/plugins/patches.ts
generated
vendored
Normal file
@@ -0,0 +1,431 @@
|
||||
import {immerable} from "../immer"
|
||||
import {
|
||||
ImmerState,
|
||||
Patch,
|
||||
SetState,
|
||||
ProxyArrayState,
|
||||
MapState,
|
||||
ProxyObjectState,
|
||||
PatchPath,
|
||||
get,
|
||||
each,
|
||||
has,
|
||||
getArchtype,
|
||||
getPrototypeOf,
|
||||
isSet,
|
||||
isMap,
|
||||
loadPlugin,
|
||||
ArchType,
|
||||
die,
|
||||
isDraft,
|
||||
isDraftable,
|
||||
NOTHING,
|
||||
errors,
|
||||
DRAFT_STATE,
|
||||
getProxyDraft,
|
||||
ImmerScope,
|
||||
isObjectish,
|
||||
isFunction,
|
||||
CONSTRUCTOR,
|
||||
PluginPatches,
|
||||
isArray,
|
||||
PROTOTYPE
|
||||
} from "../internal"
|
||||
|
||||
export function enablePatches() {
|
||||
const errorOffset = 16
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
errors.push(
|
||||
'Sets cannot have "replace" patches.',
|
||||
function(op: string) {
|
||||
return "Unsupported patch operation: " + op
|
||||
},
|
||||
function(path: string) {
|
||||
return "Cannot apply patch, path doesn't resolve: " + path
|
||||
},
|
||||
"Patching reserved attributes like __proto__, prototype and constructor is not allowed"
|
||||
)
|
||||
}
|
||||
|
||||
function getPath(state: ImmerState, path: PatchPath = []): PatchPath | null {
|
||||
// Step 1: Check if state has a stored key
|
||||
if (state.key_ !== undefined) {
|
||||
// Step 2: Validate the key is still valid in parent
|
||||
|
||||
const parentCopy = state.parent_!.copy_ ?? state.parent_!.base_
|
||||
const proxyDraft = getProxyDraft(get(parentCopy, state.key_!))
|
||||
const valueAtKey = get(parentCopy, state.key_!)
|
||||
|
||||
if (valueAtKey === undefined) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Check if the value at the key is still related to this draft
|
||||
// It should be either the draft itself, the base, or the copy
|
||||
if (
|
||||
valueAtKey !== state.draft_ &&
|
||||
valueAtKey !== state.base_ &&
|
||||
valueAtKey !== state.copy_
|
||||
) {
|
||||
return null // Value was replaced with something else
|
||||
}
|
||||
if (proxyDraft != null && proxyDraft.base_ !== state.base_) {
|
||||
return null // Different draft
|
||||
}
|
||||
|
||||
// Step 3: Handle Set case specially
|
||||
const isSet = state.parent_!.type_ === ArchType.Set
|
||||
let key: string | number
|
||||
|
||||
if (isSet) {
|
||||
// For Sets, find the index in the drafts_ map
|
||||
const setParent = state.parent_ as SetState
|
||||
key = Array.from(setParent.drafts_.keys()).indexOf(state.key_)
|
||||
} else {
|
||||
key = state.key_ as string | number
|
||||
}
|
||||
|
||||
// Step 4: Validate key still exists in parent
|
||||
if (!((isSet && parentCopy.size > key) || has(parentCopy, key))) {
|
||||
return null // Key deleted
|
||||
}
|
||||
|
||||
// Step 5: Add key to path
|
||||
path.push(key)
|
||||
}
|
||||
|
||||
// Step 6: Recurse to parent if exists
|
||||
if (state.parent_) {
|
||||
return getPath(state.parent_, path)
|
||||
}
|
||||
|
||||
// Step 7: At root - reverse path and validate
|
||||
path.reverse()
|
||||
|
||||
try {
|
||||
// Validate path can be resolved from ROOT
|
||||
resolvePath(state.copy_, path)
|
||||
} catch (e) {
|
||||
return null // Path invalid
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
// NEW: Add resolvePath helper function
|
||||
function resolvePath(base: any, path: PatchPath): any {
|
||||
let current = base
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
const key = path[i]
|
||||
current = get(current, key)
|
||||
if (!isObjectish(current) || current === null) {
|
||||
throw new Error(`Cannot resolve path at '${path.join("/")}'`)
|
||||
}
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
const REPLACE = "replace"
|
||||
const ADD = "add"
|
||||
const REMOVE = "remove"
|
||||
|
||||
function generatePatches_(
|
||||
state: ImmerState,
|
||||
basePath: PatchPath,
|
||||
scope: ImmerScope
|
||||
): void {
|
||||
if (state.scope_.processedForPatches_.has(state)) {
|
||||
return
|
||||
}
|
||||
|
||||
state.scope_.processedForPatches_.add(state)
|
||||
|
||||
const {patches_, inversePatches_} = scope
|
||||
|
||||
switch (state.type_) {
|
||||
case ArchType.Object:
|
||||
case ArchType.Map:
|
||||
return generatePatchesFromAssigned(
|
||||
state,
|
||||
basePath,
|
||||
patches_!,
|
||||
inversePatches_!
|
||||
)
|
||||
case ArchType.Array:
|
||||
return generateArrayPatches(
|
||||
state,
|
||||
basePath,
|
||||
patches_!,
|
||||
inversePatches_!
|
||||
)
|
||||
case ArchType.Set:
|
||||
return generateSetPatches(
|
||||
(state as any) as SetState,
|
||||
basePath,
|
||||
patches_!,
|
||||
inversePatches_!
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function generateArrayPatches(
|
||||
state: ProxyArrayState,
|
||||
basePath: PatchPath,
|
||||
patches: Patch[],
|
||||
inversePatches: Patch[]
|
||||
) {
|
||||
let {base_, assigned_} = state
|
||||
let copy_ = state.copy_!
|
||||
|
||||
// Reduce complexity by ensuring `base` is never longer.
|
||||
if (copy_.length < base_.length) {
|
||||
// @ts-ignore
|
||||
;[base_, copy_] = [copy_, base_]
|
||||
;[patches, inversePatches] = [inversePatches, patches]
|
||||
}
|
||||
|
||||
const allReassigned = state.allIndicesReassigned_ === true
|
||||
|
||||
// Process replaced indices.
|
||||
for (let i = 0; i < base_.length; i++) {
|
||||
const copiedItem = copy_[i]
|
||||
const baseItem = base_[i]
|
||||
|
||||
const isAssigned = allReassigned || assigned_?.get(i.toString())
|
||||
if (isAssigned && copiedItem !== baseItem) {
|
||||
const childState = copiedItem?.[DRAFT_STATE]
|
||||
if (childState && childState.modified_) {
|
||||
// Skip - let the child generate its own patches
|
||||
continue
|
||||
}
|
||||
const path = basePath.concat([i])
|
||||
patches.push({
|
||||
op: REPLACE,
|
||||
path,
|
||||
// Need to maybe clone it, as it can in fact be the original value
|
||||
// due to the base/copy inversion at the start of this function
|
||||
value: clonePatchValueIfNeeded(copiedItem)
|
||||
})
|
||||
inversePatches.push({
|
||||
op: REPLACE,
|
||||
path,
|
||||
value: clonePatchValueIfNeeded(baseItem)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Process added indices.
|
||||
for (let i = base_.length; i < copy_.length; i++) {
|
||||
const path = basePath.concat([i])
|
||||
patches.push({
|
||||
op: ADD,
|
||||
path,
|
||||
// Need to maybe clone it, as it can in fact be the original value
|
||||
// due to the base/copy inversion at the start of this function
|
||||
value: clonePatchValueIfNeeded(copy_[i])
|
||||
})
|
||||
}
|
||||
for (let i = copy_.length - 1; base_.length <= i; --i) {
|
||||
const path = basePath.concat([i])
|
||||
inversePatches.push({
|
||||
op: REMOVE,
|
||||
path
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// This is used for both Map objects and normal objects.
|
||||
function generatePatchesFromAssigned(
|
||||
state: MapState | ProxyObjectState,
|
||||
basePath: PatchPath,
|
||||
patches: Patch[],
|
||||
inversePatches: Patch[]
|
||||
) {
|
||||
const {base_, copy_, type_} = state
|
||||
each(state.assigned_!, (key, assignedValue) => {
|
||||
const origValue = get(base_, key, type_)
|
||||
const value = get(copy_!, key, type_)
|
||||
const op = !assignedValue ? REMOVE : has(base_, key) ? REPLACE : ADD
|
||||
if (origValue === value && op === REPLACE) return
|
||||
const path = basePath.concat(key as any)
|
||||
patches.push(
|
||||
op === REMOVE
|
||||
? {op, path}
|
||||
: {op, path, value: clonePatchValueIfNeeded(value)}
|
||||
)
|
||||
inversePatches.push(
|
||||
op === ADD
|
||||
? {op: REMOVE, path}
|
||||
: op === REMOVE
|
||||
? {op: ADD, path, value: clonePatchValueIfNeeded(origValue)}
|
||||
: {op: REPLACE, path, value: clonePatchValueIfNeeded(origValue)}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function generateSetPatches(
|
||||
state: SetState,
|
||||
basePath: PatchPath,
|
||||
patches: Patch[],
|
||||
inversePatches: Patch[]
|
||||
) {
|
||||
let {base_, copy_} = state
|
||||
|
||||
let i = 0
|
||||
base_.forEach((value: any) => {
|
||||
if (!copy_!.has(value)) {
|
||||
const path = basePath.concat([i])
|
||||
patches.push({
|
||||
op: REMOVE,
|
||||
path,
|
||||
value
|
||||
})
|
||||
inversePatches.unshift({
|
||||
op: ADD,
|
||||
path,
|
||||
value
|
||||
})
|
||||
}
|
||||
i++
|
||||
})
|
||||
i = 0
|
||||
copy_!.forEach((value: any) => {
|
||||
if (!base_.has(value)) {
|
||||
const path = basePath.concat([i])
|
||||
patches.push({
|
||||
op: ADD,
|
||||
path,
|
||||
value
|
||||
})
|
||||
inversePatches.unshift({
|
||||
op: REMOVE,
|
||||
path,
|
||||
value
|
||||
})
|
||||
}
|
||||
i++
|
||||
})
|
||||
}
|
||||
|
||||
function generateReplacementPatches_(
|
||||
baseValue: any,
|
||||
replacement: any,
|
||||
scope: ImmerScope
|
||||
): void {
|
||||
const {patches_, inversePatches_} = scope
|
||||
patches_!.push({
|
||||
op: REPLACE,
|
||||
path: [],
|
||||
value: replacement === NOTHING ? undefined : replacement
|
||||
})
|
||||
inversePatches_!.push({
|
||||
op: REPLACE,
|
||||
path: [],
|
||||
value: baseValue
|
||||
})
|
||||
}
|
||||
|
||||
function applyPatches_<T>(draft: T, patches: readonly Patch[]): T {
|
||||
patches.forEach(patch => {
|
||||
const {path, op} = patch
|
||||
|
||||
let base: any = draft
|
||||
for (let i = 0; i < path.length - 1; i++) {
|
||||
const parentType = getArchtype(base)
|
||||
let p = path[i]
|
||||
if (typeof p !== "string" && typeof p !== "number") {
|
||||
p = "" + p
|
||||
}
|
||||
|
||||
// See #738, avoid prototype pollution
|
||||
if (
|
||||
(parentType === ArchType.Object || parentType === ArchType.Array) &&
|
||||
(p === "__proto__" || p === CONSTRUCTOR)
|
||||
)
|
||||
die(errorOffset + 3)
|
||||
if (isFunction(base) && p === PROTOTYPE) die(errorOffset + 3)
|
||||
base = get(base, p)
|
||||
if (!isObjectish(base)) die(errorOffset + 2, path.join("/"))
|
||||
}
|
||||
|
||||
const type = getArchtype(base)
|
||||
const value = deepClonePatchValue(patch.value) // used to clone patch to ensure original patch is not modified, see #411
|
||||
const key = path[path.length - 1]
|
||||
switch (op) {
|
||||
case REPLACE:
|
||||
switch (type) {
|
||||
case ArchType.Map:
|
||||
return base.set(key, value)
|
||||
/* istanbul ignore next */
|
||||
case ArchType.Set:
|
||||
die(errorOffset)
|
||||
default:
|
||||
// if value is an object, then it's assigned by reference
|
||||
// in the following add or remove ops, the value field inside the patch will also be modifyed
|
||||
// so we use value from the cloned patch
|
||||
// @ts-ignore
|
||||
return (base[key] = value)
|
||||
}
|
||||
case ADD:
|
||||
switch (type) {
|
||||
case ArchType.Array:
|
||||
return key === "-"
|
||||
? base.push(value)
|
||||
: base.splice(key as any, 0, value)
|
||||
case ArchType.Map:
|
||||
return base.set(key, value)
|
||||
case ArchType.Set:
|
||||
return base.add(value)
|
||||
default:
|
||||
return (base[key] = value)
|
||||
}
|
||||
case REMOVE:
|
||||
switch (type) {
|
||||
case ArchType.Array:
|
||||
return base.splice(key as any, 1)
|
||||
case ArchType.Map:
|
||||
return base.delete(key)
|
||||
case ArchType.Set:
|
||||
return base.delete(patch.value)
|
||||
default:
|
||||
return delete base[key]
|
||||
}
|
||||
default:
|
||||
die(errorOffset + 1, op)
|
||||
}
|
||||
})
|
||||
|
||||
return draft
|
||||
}
|
||||
|
||||
// optimize: this is quite a performance hit, can we detect intelligently when it is needed?
|
||||
// E.g. auto-draft when new objects from outside are assigned and modified?
|
||||
// (See failing test when deepClone just returns obj)
|
||||
function deepClonePatchValue<T>(obj: T): T
|
||||
function deepClonePatchValue(obj: any) {
|
||||
if (!isDraftable(obj)) return obj
|
||||
if (isArray(obj)) return obj.map(deepClonePatchValue)
|
||||
if (isMap(obj))
|
||||
return new Map(
|
||||
Array.from(obj.entries()).map(([k, v]) => [k, deepClonePatchValue(v)])
|
||||
)
|
||||
if (isSet(obj)) return new Set(Array.from(obj).map(deepClonePatchValue))
|
||||
const cloned = Object.create(getPrototypeOf(obj))
|
||||
for (const key in obj) cloned[key] = deepClonePatchValue(obj[key])
|
||||
if (has(obj, immerable)) cloned[immerable] = obj[immerable]
|
||||
return cloned
|
||||
}
|
||||
|
||||
function clonePatchValueIfNeeded<T>(obj: T): T {
|
||||
if (isDraft(obj)) {
|
||||
return deepClonePatchValue(obj)
|
||||
} else return obj
|
||||
}
|
||||
|
||||
loadPlugin(PluginPatches, {
|
||||
applyPatches_,
|
||||
generatePatches_,
|
||||
generateReplacementPatches_,
|
||||
getPath
|
||||
})
|
||||
}
|
||||
1
frontend/node_modules/immer/src/types/globals.d.ts
generated
vendored
Normal file
1
frontend/node_modules/immer/src/types/globals.d.ts
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
declare const __DEV__: boolean
|
||||
112
frontend/node_modules/immer/src/types/index.js.flow
generated
vendored
Normal file
112
frontend/node_modules/immer/src/types/index.js.flow
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// @flow
|
||||
|
||||
export interface Patch {
|
||||
op: "replace" | "remove" | "add";
|
||||
path: (string | number)[];
|
||||
value?: any;
|
||||
}
|
||||
|
||||
export type PatchListener = (patches: Patch[], inversePatches: Patch[]) => void
|
||||
|
||||
type Base = {...} | Array<any>
|
||||
interface IProduce {
|
||||
/**
|
||||
* Immer takes a state, and runs a function against it.
|
||||
* That function can freely mutate the state, as it will create copies-on-write.
|
||||
* This means that the original state will stay unchanged, and once the function finishes, the modified state is returned.
|
||||
*
|
||||
* If the first argument is a function, this is interpreted as the recipe, and will create a curried function that will execute the recipe
|
||||
* any time it is called with the current state.
|
||||
*
|
||||
* @param currentState - the state to start with
|
||||
* @param recipe - function that receives a proxy of the current state as first argument and which can be freely modified
|
||||
* @param initialState - if a curried function is created and this argument was given, it will be used as fallback if the curried function is called with a state of undefined
|
||||
* @returns The next state: a new state, or the current state if nothing was modified
|
||||
*/
|
||||
<S: Base>(
|
||||
currentState: S,
|
||||
recipe: (draftState: S) => S | void,
|
||||
patchListener?: PatchListener
|
||||
): S;
|
||||
// curried invocations with initial state
|
||||
<S: Base, A = void, B = void, C = void>(
|
||||
recipe: (draftState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S | void,
|
||||
initialState: S
|
||||
): (currentState: S | void, a: A, b: B, c: C, ...extraArgs: any[]) => S;
|
||||
// curried invocations without initial state
|
||||
<S: Base, A = void, B = void, C = void>(
|
||||
recipe: (draftState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S | void
|
||||
): (currentState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S;
|
||||
}
|
||||
|
||||
interface IProduceWithPatches {
|
||||
/**
|
||||
* Like `produce`, but instead of just returning the new state,
|
||||
* a tuple is returned with [nextState, patches, inversePatches]
|
||||
*
|
||||
* Like produce, this function supports currying
|
||||
*/
|
||||
<S: Base>(
|
||||
currentState: S,
|
||||
recipe: (draftState: S) => S | void
|
||||
): [S, Patch[], Patch[]];
|
||||
// curried invocations with initial state
|
||||
<S: Base, A = void, B = void, C = void>(
|
||||
recipe: (draftState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S | void,
|
||||
initialState: S
|
||||
): (currentState: S | void, a: A, b: B, c: C, ...extraArgs: any[]) => [S, Patch[], Patch[]];
|
||||
// curried invocations without initial state
|
||||
<S: Base, A = void, B = void, C = void>(
|
||||
recipe: (draftState: S, a: A, b: B, c: C, ...extraArgs: any[]) => S | void
|
||||
): (currentState: S, a: A, b: B, c: C, ...extraArgs: any[]) => [S, Patch[], Patch[]];
|
||||
}
|
||||
|
||||
declare export var produce: IProduce
|
||||
|
||||
declare export var produceWithPatches: IProduceWithPatches
|
||||
|
||||
declare export var nothing: typeof undefined
|
||||
|
||||
declare export var immerable: Symbol
|
||||
|
||||
/**
|
||||
* Automatically freezes any state trees generated by immer.
|
||||
* This protects against accidental modifications of the state tree outside of an immer function.
|
||||
* This comes with a performance impact, so it is recommended to disable this option in production.
|
||||
* By default it is turned on during local development, and turned off in production.
|
||||
*/
|
||||
declare export function setAutoFreeze(autoFreeze: boolean): void
|
||||
|
||||
/**
|
||||
* Pass false to disable strict shallow copy.
|
||||
*
|
||||
* By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.
|
||||
*/
|
||||
declare export function setUseStrictShallowCopy(useStrictShallowCopy: boolean): void
|
||||
|
||||
declare export function applyPatches<S>(state: S, patches: Patch[]): S
|
||||
|
||||
declare export function original<S>(value: S): S
|
||||
|
||||
declare export function current<S>(value: S): S
|
||||
|
||||
declare export function isDraft(value: any): boolean
|
||||
|
||||
/**
|
||||
* Creates a mutable draft from an (immutable) object / array.
|
||||
* The draft can be modified until `finishDraft` is called
|
||||
*/
|
||||
declare export function createDraft<T>(base: T): T
|
||||
|
||||
/**
|
||||
* Given a draft that was created using `createDraft`,
|
||||
* finalizes the draft into a new immutable object.
|
||||
* Optionally a patch-listener can be provided to gather the patches that are needed to construct the object.
|
||||
*/
|
||||
declare export function finishDraft<T>(base: T, listener?: PatchListener): T
|
||||
|
||||
declare export function enableMapSet(): void
|
||||
declare export function enablePatches(): void
|
||||
declare export function enableArrayMethods(): void
|
||||
|
||||
declare export function freeze<T>(obj: T, freeze?: boolean): T
|
||||
251
frontend/node_modules/immer/src/types/types-external.ts
generated
vendored
Normal file
251
frontend/node_modules/immer/src/types/types-external.ts
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
import {NOTHING} from "../internal"
|
||||
|
||||
type AnyFunc = (...args: any[]) => any
|
||||
|
||||
type PrimitiveType = number | string | boolean
|
||||
|
||||
/** Object types that should never be mapped */
|
||||
type AtomicObject = Function | Promise<any> | Date | RegExp
|
||||
|
||||
/**
|
||||
* If the lib "ES2015.Collection" is not included in tsconfig.json,
|
||||
* types like ReadonlyArray, WeakMap etc. fall back to `any` (specified nowhere)
|
||||
* or `{}` (from the node types), in both cases entering an infinite recursion in
|
||||
* pattern matching type mappings
|
||||
* This type can be used to cast these types to `void` in these cases.
|
||||
*/
|
||||
export type IfAvailable<T, Fallback = void> =
|
||||
// fallback if any
|
||||
true | false extends (T extends never
|
||||
? true
|
||||
: false)
|
||||
? Fallback // fallback if empty type
|
||||
: keyof T extends never
|
||||
? Fallback // original type
|
||||
: T
|
||||
|
||||
/**
|
||||
* These should also never be mapped but must be tested after regular Map and
|
||||
* Set
|
||||
*/
|
||||
type WeakReferences = IfAvailable<WeakMap<any, any>> | IfAvailable<WeakSet<any>>
|
||||
|
||||
export type WritableDraft<T> = T extends any[]
|
||||
? number extends T["length"]
|
||||
? Draft<T[number]>[]
|
||||
: WritableNonArrayDraft<T>
|
||||
: WritableNonArrayDraft<T>
|
||||
|
||||
type WritableNonArrayDraft<T> = {
|
||||
-readonly [K in keyof T]: T[K] extends infer V
|
||||
? V extends object
|
||||
? Draft<V>
|
||||
: V
|
||||
: never
|
||||
}
|
||||
|
||||
/** Convert a readonly type into a mutable type, if possible */
|
||||
export type Draft<T> = T extends PrimitiveType
|
||||
? T
|
||||
: T extends AtomicObject
|
||||
? T
|
||||
: T extends ReadonlyMap<infer K, infer V> // Map extends ReadonlyMap
|
||||
? Map<Draft<K>, Draft<V>>
|
||||
: T extends ReadonlySet<infer V> // Set extends ReadonlySet
|
||||
? Set<Draft<V>>
|
||||
: T extends WeakReferences
|
||||
? T
|
||||
: T extends object
|
||||
? WritableDraft<T>
|
||||
: T
|
||||
|
||||
/** Convert a mutable type into a readonly type */
|
||||
export type Immutable<T> = T extends PrimitiveType
|
||||
? T
|
||||
: T extends AtomicObject
|
||||
? T
|
||||
: T extends ReadonlyMap<infer K, infer V> // Map extends ReadonlyMap
|
||||
? ReadonlyMap<Immutable<K>, Immutable<V>>
|
||||
: T extends ReadonlySet<infer V> // Set extends ReadonlySet
|
||||
? ReadonlySet<Immutable<V>>
|
||||
: T extends WeakReferences
|
||||
? T
|
||||
: T extends object
|
||||
? {readonly [K in keyof T]: Immutable<T[K]>}
|
||||
: T
|
||||
|
||||
export interface Patch {
|
||||
op: "replace" | "remove" | "add"
|
||||
path: (string | number)[]
|
||||
value?: any
|
||||
}
|
||||
|
||||
export type PatchListener = (patches: Patch[], inversePatches: Patch[]) => void
|
||||
|
||||
/** Converts `nothing` into `undefined` */
|
||||
type FromNothing<T> = T extends typeof NOTHING ? undefined : T
|
||||
|
||||
/** The inferred return type of `produce` */
|
||||
export type Produced<Base, Return> = Return extends void
|
||||
? Base
|
||||
: FromNothing<Return>
|
||||
|
||||
/**
|
||||
* Utility types
|
||||
*/
|
||||
type PatchesTuple<T> = readonly [T, Patch[], Patch[]]
|
||||
|
||||
type ValidRecipeReturnType<State> =
|
||||
| State
|
||||
| void
|
||||
| undefined
|
||||
| (State extends undefined ? typeof NOTHING : never)
|
||||
|
||||
type ReturnTypeWithPatchesIfNeeded<
|
||||
State,
|
||||
UsePatches extends boolean
|
||||
> = UsePatches extends true ? PatchesTuple<State> : State
|
||||
|
||||
/**
|
||||
* Core Producer inference
|
||||
*/
|
||||
type InferRecipeFromCurried<Curried> = Curried extends (
|
||||
base: infer State,
|
||||
...rest: infer Args
|
||||
) => any // extra assertion to make sure this is a proper curried function (state, args) => state
|
||||
? ReturnType<Curried> extends State
|
||||
? (
|
||||
draft: Draft<State>,
|
||||
...rest: Args
|
||||
) => ValidRecipeReturnType<Draft<State>>
|
||||
: never
|
||||
: never
|
||||
|
||||
type InferInitialStateFromCurried<Curried> = Curried extends (
|
||||
base: infer State,
|
||||
...rest: any[]
|
||||
) => any // extra assertion to make sure this is a proper curried function (state, args) => state
|
||||
? State
|
||||
: never
|
||||
|
||||
type InferCurriedFromRecipe<
|
||||
Recipe,
|
||||
UsePatches extends boolean
|
||||
> = Recipe extends (draft: infer DraftState, ...args: infer RestArgs) => any // verify return type
|
||||
? ReturnType<Recipe> extends ValidRecipeReturnType<DraftState>
|
||||
? (
|
||||
base: Immutable<DraftState>,
|
||||
...args: RestArgs
|
||||
) => ReturnTypeWithPatchesIfNeeded<DraftState, UsePatches> // N.b. we return mutable draftstate, in case the recipe's first arg isn't read only, and that isn't expected as output either
|
||||
: never // incorrect return type
|
||||
: never // not a function
|
||||
|
||||
type InferCurriedFromInitialStateAndRecipe<
|
||||
State,
|
||||
Recipe,
|
||||
UsePatches extends boolean
|
||||
> = Recipe extends (
|
||||
draft: Draft<State>,
|
||||
...rest: infer RestArgs
|
||||
) => ValidRecipeReturnType<State>
|
||||
? (
|
||||
base?: State | undefined,
|
||||
...args: RestArgs
|
||||
) => ReturnTypeWithPatchesIfNeeded<State, UsePatches>
|
||||
: never // recipe doesn't match initial state
|
||||
|
||||
/**
|
||||
* The `produce` function takes a value and a "recipe function" (whose
|
||||
* return value often depends on the base state). The recipe function is
|
||||
* free to mutate its first argument however it wants. All mutations are
|
||||
* only ever applied to a __copy__ of the base state.
|
||||
*
|
||||
* Pass only a function to create a "curried producer" which relieves you
|
||||
* from passing the recipe function every time.
|
||||
*
|
||||
* Only plain objects and arrays are made mutable. All other objects are
|
||||
* considered uncopyable.
|
||||
*
|
||||
* Note: This function is __bound__ to its `Immer` instance.
|
||||
*
|
||||
* @param {any} base - the initial state
|
||||
* @param {Function} producer - function that receives a proxy of the base state as first argument and which can be freely modified
|
||||
* @param {Function} patchListener - optional function that will be called with all the patches produced here
|
||||
* @returns {any} a new state, or the initial state if nothing was modified
|
||||
*/
|
||||
export interface IProduce {
|
||||
/** Curried producer that infers the recipe from the curried output function (e.g. when passing to setState) */
|
||||
<Curried>(
|
||||
recipe: InferRecipeFromCurried<Curried>,
|
||||
initialState?: InferInitialStateFromCurried<Curried>
|
||||
): Curried
|
||||
|
||||
/** Curried producer that infers curried from the recipe */
|
||||
<Recipe extends AnyFunc>(recipe: Recipe): InferCurriedFromRecipe<
|
||||
Recipe,
|
||||
false
|
||||
>
|
||||
|
||||
/** Curried producer that infers curried from the State generic, which is explicitly passed in. */
|
||||
<State>(
|
||||
recipe: (
|
||||
state: Draft<State>,
|
||||
initialState: State
|
||||
) => ValidRecipeReturnType<State>
|
||||
): (state?: State) => State
|
||||
<State, Args extends any[]>(
|
||||
recipe: (
|
||||
state: Draft<State>,
|
||||
...args: Args
|
||||
) => ValidRecipeReturnType<State>,
|
||||
initialState: State
|
||||
): (state?: State, ...args: Args) => State
|
||||
<State>(recipe: (state: Draft<State>) => ValidRecipeReturnType<State>): (
|
||||
state: State
|
||||
) => State
|
||||
<State, Args extends any[]>(
|
||||
recipe: (state: Draft<State>, ...args: Args) => ValidRecipeReturnType<State>
|
||||
): (state: State, ...args: Args) => State
|
||||
|
||||
/** Curried producer with initial state, infers recipe from initial state */
|
||||
<State, Recipe extends Function>(
|
||||
recipe: Recipe,
|
||||
initialState: State
|
||||
): InferCurriedFromInitialStateAndRecipe<State, Recipe, false>
|
||||
|
||||
/** Normal producer */
|
||||
<Base, D = Draft<Base>>( // By using a default inferred D, rather than Draft<Base> in the recipe, we can override it.
|
||||
base: Base,
|
||||
recipe: (draft: D) => ValidRecipeReturnType<D>,
|
||||
listener?: PatchListener
|
||||
): Base
|
||||
}
|
||||
|
||||
/**
|
||||
* Like `produce`, but instead of just returning the new state,
|
||||
* a tuple is returned with [nextState, patches, inversePatches]
|
||||
*
|
||||
* Like produce, this function supports currying
|
||||
*/
|
||||
export interface IProduceWithPatches {
|
||||
// Types copied from IProduce, wrapped with PatchesTuple
|
||||
<Recipe extends AnyFunc>(recipe: Recipe): InferCurriedFromRecipe<Recipe, true>
|
||||
<State, Recipe extends Function>(
|
||||
recipe: Recipe,
|
||||
initialState: State
|
||||
): InferCurriedFromInitialStateAndRecipe<State, Recipe, true>
|
||||
<Base, D = Draft<Base>>(
|
||||
base: Base,
|
||||
recipe: (draft: D) => ValidRecipeReturnType<D>,
|
||||
listener?: PatchListener
|
||||
): PatchesTuple<Base>
|
||||
}
|
||||
|
||||
/**
|
||||
* The type for `recipe function`
|
||||
*/
|
||||
export type Producer<T> = (draft: Draft<T>) => ValidRecipeReturnType<Draft<T>>
|
||||
|
||||
// Fixes #507: bili doesn't export the types of this file if there is no actual source in it..
|
||||
// hopefully it get's tree-shaken away for everyone :)
|
||||
export function never_used() {}
|
||||
55
frontend/node_modules/immer/src/types/types-internal.ts
generated
vendored
Normal file
55
frontend/node_modules/immer/src/types/types-internal.ts
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
import {
|
||||
SetState,
|
||||
ImmerScope,
|
||||
ProxyObjectState,
|
||||
ProxyArrayState,
|
||||
MapState,
|
||||
DRAFT_STATE,
|
||||
Patch,
|
||||
PatchPath
|
||||
} from "../internal"
|
||||
|
||||
export type Objectish = AnyObject | AnyArray | AnyMap | AnySet
|
||||
export type ObjectishNoSet = AnyObject | AnyArray | AnyMap
|
||||
|
||||
export type AnyObject = {[key: string]: any}
|
||||
export type AnyArray = Array<any>
|
||||
export type AnySet = Set<any>
|
||||
export type AnyMap = Map<any, any>
|
||||
|
||||
export const enum ArchType {
|
||||
Object,
|
||||
Array,
|
||||
Map,
|
||||
Set
|
||||
}
|
||||
|
||||
export interface ImmerBaseState {
|
||||
parent_?: ImmerState
|
||||
scope_: ImmerScope
|
||||
modified_: boolean
|
||||
finalized_: boolean
|
||||
isManual_: boolean
|
||||
assigned_: Map<any, boolean> | undefined
|
||||
key_?: string | number | symbol
|
||||
callbacks_: ((scope: ImmerScope) => void)[]
|
||||
draftLocations_?: Map<any, (string | number | symbol)[]>
|
||||
}
|
||||
|
||||
export type ImmerState =
|
||||
| ProxyObjectState
|
||||
| ProxyArrayState
|
||||
| MapState
|
||||
| SetState
|
||||
|
||||
// The _internal_ type used for drafts (not to be confused with Draft, which is public facing)
|
||||
export type Drafted<Base = any, T extends ImmerState = ImmerState> = {
|
||||
[DRAFT_STATE]: T
|
||||
} & Base
|
||||
|
||||
export type GeneratePatches = (
|
||||
state: ImmerState,
|
||||
basePath: PatchPath,
|
||||
patches: Patch[],
|
||||
inversePatches: Patch[]
|
||||
) => void
|
||||
286
frontend/node_modules/immer/src/utils/common.ts
generated
vendored
Normal file
286
frontend/node_modules/immer/src/utils/common.ts
generated
vendored
Normal file
@@ -0,0 +1,286 @@
|
||||
import {
|
||||
DRAFT_STATE,
|
||||
DRAFTABLE,
|
||||
Objectish,
|
||||
Drafted,
|
||||
AnyObject,
|
||||
AnyMap,
|
||||
AnySet,
|
||||
ImmerState,
|
||||
ArchType,
|
||||
die,
|
||||
StrictMode
|
||||
} from "../internal"
|
||||
|
||||
const O = Object
|
||||
|
||||
export const getPrototypeOf = O.getPrototypeOf
|
||||
|
||||
export const CONSTRUCTOR = "constructor"
|
||||
export const PROTOTYPE = "prototype"
|
||||
|
||||
export const CONFIGURABLE = "configurable"
|
||||
export const ENUMERABLE = "enumerable"
|
||||
export const WRITABLE = "writable"
|
||||
export const VALUE = "value"
|
||||
|
||||
/** Returns true if the given value is an Immer draft */
|
||||
/*#__PURE__*/
|
||||
export let isDraft = (value: any): boolean => !!value && !!value[DRAFT_STATE]
|
||||
|
||||
/** Returns true if the given value can be drafted by Immer */
|
||||
/*#__PURE__*/
|
||||
export function isDraftable(value: any): boolean {
|
||||
if (!value) return false
|
||||
return (
|
||||
isPlainObject(value) ||
|
||||
isArray(value) ||
|
||||
!!value[DRAFTABLE] ||
|
||||
!!value[CONSTRUCTOR]?.[DRAFTABLE] ||
|
||||
isMap(value) ||
|
||||
isSet(value)
|
||||
)
|
||||
}
|
||||
|
||||
const objectCtorString = O[PROTOTYPE][CONSTRUCTOR].toString()
|
||||
const cachedCtorStrings = new WeakMap()
|
||||
/*#__PURE__*/
|
||||
export function isPlainObject(value: any): boolean {
|
||||
if (!value || !isObjectish(value)) return false
|
||||
const proto = getPrototypeOf(value)
|
||||
if (proto === null || proto === O[PROTOTYPE]) return true
|
||||
|
||||
const Ctor = O.hasOwnProperty.call(proto, CONSTRUCTOR) && proto[CONSTRUCTOR]
|
||||
if (Ctor === Object) return true
|
||||
|
||||
if (!isFunction(Ctor)) return false
|
||||
|
||||
let ctorString = cachedCtorStrings.get(Ctor)
|
||||
if (ctorString === undefined) {
|
||||
ctorString = Function.toString.call(Ctor)
|
||||
cachedCtorStrings.set(Ctor, ctorString)
|
||||
}
|
||||
|
||||
return ctorString === objectCtorString
|
||||
}
|
||||
|
||||
/** Get the underlying object that is represented by the given draft */
|
||||
/*#__PURE__*/
|
||||
export function original<T>(value: T): T | undefined
|
||||
export function original(value: Drafted<any>): any {
|
||||
if (!isDraft(value)) die(15, value)
|
||||
return value[DRAFT_STATE].base_
|
||||
}
|
||||
|
||||
/**
|
||||
* Each iterates a map, set or array.
|
||||
* Or, if any other kind of object, all of its own properties.
|
||||
*
|
||||
* @param obj The object to iterate over
|
||||
* @param iter The iterator function
|
||||
* @param strict When true (default), includes symbols and non-enumerable properties.
|
||||
* When false, uses looseiteration over only enumerable string properties.
|
||||
*/
|
||||
export function each<T extends Objectish>(
|
||||
obj: T,
|
||||
iter: (key: string | number, value: any, source: T) => void,
|
||||
strict?: boolean
|
||||
): void
|
||||
export function each(obj: any, iter: any, strict: boolean = true) {
|
||||
if (getArchtype(obj) === ArchType.Object) {
|
||||
// If strict, we do a full iteration including symbols and non-enumerable properties
|
||||
// Otherwise, we only iterate enumerable string properties for performance
|
||||
const keys = strict ? Reflect.ownKeys(obj) : O.keys(obj)
|
||||
keys.forEach(key => {
|
||||
iter(key, obj[key], obj)
|
||||
})
|
||||
} else {
|
||||
obj.forEach((entry: any, index: any) => iter(index, entry, obj))
|
||||
}
|
||||
}
|
||||
|
||||
/*#__PURE__*/
|
||||
export function getArchtype(thing: any): ArchType {
|
||||
const state: undefined | ImmerState = thing[DRAFT_STATE]
|
||||
return state
|
||||
? state.type_
|
||||
: isArray(thing)
|
||||
? ArchType.Array
|
||||
: isMap(thing)
|
||||
? ArchType.Map
|
||||
: isSet(thing)
|
||||
? ArchType.Set
|
||||
: ArchType.Object
|
||||
}
|
||||
|
||||
/*#__PURE__*/
|
||||
export let has = (
|
||||
thing: any,
|
||||
prop: PropertyKey,
|
||||
type = getArchtype(thing)
|
||||
): boolean =>
|
||||
type === ArchType.Map
|
||||
? thing.has(prop)
|
||||
: O[PROTOTYPE].hasOwnProperty.call(thing, prop)
|
||||
|
||||
/*#__PURE__*/
|
||||
export let get = (
|
||||
thing: AnyMap | AnyObject,
|
||||
prop: PropertyKey,
|
||||
type = getArchtype(thing)
|
||||
): any =>
|
||||
// @ts-ignore
|
||||
type === ArchType.Map ? thing.get(prop) : thing[prop]
|
||||
|
||||
/*#__PURE__*/
|
||||
export let set = (
|
||||
thing: any,
|
||||
propOrOldValue: PropertyKey,
|
||||
value: any,
|
||||
type = getArchtype(thing)
|
||||
) => {
|
||||
if (type === ArchType.Map) thing.set(propOrOldValue, value)
|
||||
else if (type === ArchType.Set) {
|
||||
thing.add(value)
|
||||
} else thing[propOrOldValue] = value
|
||||
}
|
||||
|
||||
/*#__PURE__*/
|
||||
export function is(x: any, y: any): boolean {
|
||||
// From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js
|
||||
if (x === y) {
|
||||
return x !== 0 || 1 / x === 1 / y
|
||||
} else {
|
||||
return x !== x && y !== y
|
||||
}
|
||||
}
|
||||
|
||||
export let isArray = Array.isArray
|
||||
|
||||
/*#__PURE__*/
|
||||
export let isMap = (target: any): target is AnyMap => target instanceof Map
|
||||
|
||||
/*#__PURE__*/
|
||||
export let isSet = (target: any): target is AnySet => target instanceof Set
|
||||
|
||||
export let isObjectish = (target: any) => typeof target === "object"
|
||||
|
||||
export let isFunction = (target: any): target is Function =>
|
||||
typeof target === "function"
|
||||
|
||||
export let isBoolean = (target: any): target is boolean =>
|
||||
typeof target === "boolean"
|
||||
|
||||
export function isArrayIndex(value: string | number): value is number | string {
|
||||
const n = +value
|
||||
return Number.isInteger(n) && String(n) === value
|
||||
}
|
||||
|
||||
export let getProxyDraft = <T extends any>(value: T): ImmerState | null => {
|
||||
if (!isObjectish(value)) return null
|
||||
return (value as {[DRAFT_STATE]: any})?.[DRAFT_STATE]
|
||||
}
|
||||
|
||||
/*#__PURE__*/
|
||||
export let latest = (state: ImmerState): any => state.copy_ || state.base_
|
||||
|
||||
export let getValue = <T extends object>(value: T): T => {
|
||||
const proxyDraft = getProxyDraft(value)
|
||||
return proxyDraft ? proxyDraft.copy_ ?? proxyDraft.base_ : value
|
||||
}
|
||||
|
||||
export let getFinalValue = (state: ImmerState): any =>
|
||||
state.modified_ ? state.copy_ : state.base_
|
||||
|
||||
/*#__PURE__*/
|
||||
export function shallowCopy(base: any, strict: StrictMode) {
|
||||
if (isMap(base)) {
|
||||
return new Map(base)
|
||||
}
|
||||
if (isSet(base)) {
|
||||
return new Set(base)
|
||||
}
|
||||
if (isArray(base)) return Array[PROTOTYPE].slice.call(base)
|
||||
|
||||
const isPlain = isPlainObject(base)
|
||||
|
||||
if (strict === true || (strict === "class_only" && !isPlain)) {
|
||||
// Perform a strict copy
|
||||
const descriptors = O.getOwnPropertyDescriptors(base)
|
||||
delete descriptors[DRAFT_STATE as any]
|
||||
let keys = Reflect.ownKeys(descriptors)
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
const key: any = keys[i]
|
||||
const desc = descriptors[key]
|
||||
if (desc[WRITABLE] === false) {
|
||||
desc[WRITABLE] = true
|
||||
desc[CONFIGURABLE] = true
|
||||
}
|
||||
// like object.assign, we will read any _own_, get/set accessors. This helps in dealing
|
||||
// with libraries that trap values, like mobx or vue
|
||||
// unlike object.assign, non-enumerables will be copied as well
|
||||
if (desc.get || desc.set)
|
||||
descriptors[key] = {
|
||||
[CONFIGURABLE]: true,
|
||||
[WRITABLE]: true, // could live with !!desc.set as well here...
|
||||
[ENUMERABLE]: desc[ENUMERABLE],
|
||||
[VALUE]: base[key]
|
||||
}
|
||||
}
|
||||
return O.create(getPrototypeOf(base), descriptors)
|
||||
} else {
|
||||
// perform a sloppy copy
|
||||
const proto = getPrototypeOf(base)
|
||||
if (proto !== null && isPlain) {
|
||||
return {...base} // assumption: better inner class optimization than the assign below
|
||||
}
|
||||
const obj = O.create(proto)
|
||||
return O.assign(obj, base)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Freezes draftable objects. Returns the original object.
|
||||
* By default freezes shallowly, but if the second argument is `true` it will freeze recursively.
|
||||
*
|
||||
* @param obj
|
||||
* @param deep
|
||||
*/
|
||||
export function freeze<T>(obj: T, deep?: boolean): T
|
||||
export function freeze<T>(obj: any, deep: boolean = false): T {
|
||||
if (isFrozen(obj) || isDraft(obj) || !isDraftable(obj)) return obj
|
||||
if (getArchtype(obj) > 1 /* Map or Set */) {
|
||||
O.defineProperties(obj, {
|
||||
set: dontMutateMethodOverride,
|
||||
add: dontMutateMethodOverride,
|
||||
clear: dontMutateMethodOverride,
|
||||
delete: dontMutateMethodOverride
|
||||
})
|
||||
}
|
||||
O.freeze(obj)
|
||||
if (deep)
|
||||
// See #590, don't recurse into non-enumerable / Symbol properties when freezing
|
||||
// So use Object.values (only string-like, enumerables) instead of each()
|
||||
each(
|
||||
obj,
|
||||
(_key, value) => {
|
||||
freeze(value, true)
|
||||
},
|
||||
false
|
||||
)
|
||||
return obj
|
||||
}
|
||||
|
||||
function dontMutateFrozenCollections() {
|
||||
die(2)
|
||||
}
|
||||
|
||||
const dontMutateMethodOverride = {
|
||||
[VALUE]: dontMutateFrozenCollections
|
||||
}
|
||||
|
||||
export function isFrozen(obj: any): boolean {
|
||||
// Fast path: primitives and null/undefined are always "frozen"
|
||||
if (obj === null || !isObjectish(obj)) return true
|
||||
return O.isFrozen(obj)
|
||||
}
|
||||
18
frontend/node_modules/immer/src/utils/env.ts
generated
vendored
Normal file
18
frontend/node_modules/immer/src/utils/env.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
// Should be no imports here!
|
||||
|
||||
/**
|
||||
* The sentinel value returned by producers to replace the draft with undefined.
|
||||
*/
|
||||
export const NOTHING: unique symbol = Symbol.for("immer-nothing")
|
||||
|
||||
/**
|
||||
* To let Immer treat your class instances as plain immutable objects
|
||||
* (albeit with a custom prototype), you must define either an instance property
|
||||
* or a static property on each of your custom classes.
|
||||
*
|
||||
* Otherwise, your class instance will never be drafted, which means it won't be
|
||||
* safe to mutate in a produce callback.
|
||||
*/
|
||||
export const DRAFTABLE: unique symbol = Symbol.for("immer-draftable")
|
||||
|
||||
export const DRAFT_STATE: unique symbol = Symbol.for("immer-state")
|
||||
50
frontend/node_modules/immer/src/utils/errors.ts
generated
vendored
Normal file
50
frontend/node_modules/immer/src/utils/errors.ts
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
import {isFunction} from "../internal"
|
||||
|
||||
export const errors =
|
||||
process.env.NODE_ENV !== "production"
|
||||
? [
|
||||
// All error codes, starting by 0:
|
||||
function(plugin: string) {
|
||||
return `The plugin for '${plugin}' has not been loaded into Immer. To enable the plugin, import and call \`enable${plugin}()\` when initializing your application.`
|
||||
},
|
||||
function(thing: string) {
|
||||
return `produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got '${thing}'`
|
||||
},
|
||||
"This object has been frozen and should not be mutated",
|
||||
function(data: any) {
|
||||
return (
|
||||
"Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? " +
|
||||
data
|
||||
)
|
||||
},
|
||||
"An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.",
|
||||
"Immer forbids circular references",
|
||||
"The first or second argument to `produce` must be a function",
|
||||
"The third argument to `produce` must be a function or undefined",
|
||||
"First argument to `createDraft` must be a plain object, an array, or an immerable object",
|
||||
"First argument to `finishDraft` must be a draft returned by `createDraft`",
|
||||
function(thing: string) {
|
||||
return `'current' expects a draft, got: ${thing}`
|
||||
},
|
||||
"Object.defineProperty() cannot be used on an Immer draft",
|
||||
"Object.setPrototypeOf() cannot be used on an Immer draft",
|
||||
"Immer only supports deleting array indices",
|
||||
"Immer only supports setting array indices and the 'length' property",
|
||||
function(thing: string) {
|
||||
return `'original' expects a draft, got: ${thing}`
|
||||
}
|
||||
// Note: if more errors are added, the errorOffset in Patches.ts should be increased
|
||||
// See Patches.ts for additional errors
|
||||
]
|
||||
: []
|
||||
|
||||
export function die(error: number, ...args: any[]): never {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const e = errors[error]
|
||||
const msg = isFunction(e) ? e.apply(null, args as any) : e
|
||||
throw new Error(`[Immer] ${msg}`)
|
||||
}
|
||||
throw new Error(
|
||||
`[Immer] minified error nr: ${error}. Full error at: https://bit.ly/3cXEKWf`
|
||||
)
|
||||
}
|
||||
99
frontend/node_modules/immer/src/utils/plugins.ts
generated
vendored
Normal file
99
frontend/node_modules/immer/src/utils/plugins.ts
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
import {
|
||||
ImmerState,
|
||||
Patch,
|
||||
Drafted,
|
||||
ImmerBaseState,
|
||||
AnyMap,
|
||||
AnySet,
|
||||
ArchType,
|
||||
die,
|
||||
ImmerScope,
|
||||
ProxyArrayState
|
||||
} from "../internal"
|
||||
|
||||
export const PluginMapSet = "MapSet"
|
||||
export const PluginPatches = "Patches"
|
||||
export const PluginArrayMethods = "ArrayMethods"
|
||||
|
||||
export type PatchesPlugin = {
|
||||
generatePatches_(
|
||||
state: ImmerState,
|
||||
basePath: PatchPath,
|
||||
rootScope: ImmerScope
|
||||
): void
|
||||
generateReplacementPatches_(
|
||||
base: any,
|
||||
replacement: any,
|
||||
rootScope: ImmerScope
|
||||
): void
|
||||
applyPatches_<T>(draft: T, patches: readonly Patch[]): T
|
||||
getPath: (state: ImmerState) => PatchPath | null
|
||||
}
|
||||
|
||||
export type MapSetPlugin = {
|
||||
proxyMap_<T extends AnyMap>(target: T, parent?: ImmerState): [T, ImmerState]
|
||||
proxySet_<T extends AnySet>(target: T, parent?: ImmerState): [T, ImmerState]
|
||||
fixSetContents: (state: ImmerState) => void
|
||||
}
|
||||
|
||||
export type ArrayMethodsPlugin = {
|
||||
createMethodInterceptor: (state: ProxyArrayState, method: string) => Function
|
||||
isArrayOperationMethod: (method: string) => boolean
|
||||
isMutatingArrayMethod: (method: string) => boolean
|
||||
}
|
||||
|
||||
/** Plugin utilities */
|
||||
const plugins: {
|
||||
Patches?: PatchesPlugin
|
||||
MapSet?: MapSetPlugin
|
||||
ArrayMethods?: ArrayMethodsPlugin
|
||||
} = {}
|
||||
|
||||
type Plugins = typeof plugins
|
||||
|
||||
export function getPlugin<K extends keyof Plugins>(
|
||||
pluginKey: K
|
||||
): Exclude<Plugins[K], undefined> {
|
||||
const plugin = plugins[pluginKey]
|
||||
if (!plugin) {
|
||||
die(0, pluginKey)
|
||||
}
|
||||
// @ts-ignore
|
||||
return plugin
|
||||
}
|
||||
|
||||
export let isPluginLoaded = <K extends keyof Plugins>(pluginKey: K): boolean =>
|
||||
!!plugins[pluginKey]
|
||||
|
||||
export let clearPlugin = <K extends keyof Plugins>(pluginKey: K): void => {
|
||||
delete plugins[pluginKey]
|
||||
}
|
||||
|
||||
export function loadPlugin<K extends keyof Plugins>(
|
||||
pluginKey: K,
|
||||
implementation: Plugins[K]
|
||||
): void {
|
||||
if (!plugins[pluginKey]) plugins[pluginKey] = implementation
|
||||
}
|
||||
/** Map / Set plugin */
|
||||
|
||||
export interface MapState extends ImmerBaseState {
|
||||
type_: ArchType.Map
|
||||
copy_: AnyMap | undefined
|
||||
base_: AnyMap
|
||||
revoked_: boolean
|
||||
draft_: Drafted<AnyMap, MapState>
|
||||
}
|
||||
|
||||
export interface SetState extends ImmerBaseState {
|
||||
type_: ArchType.Set
|
||||
copy_: AnySet | undefined
|
||||
base_: AnySet
|
||||
drafts_: Map<any, Drafted> // maps the original value to the draft value in the new set
|
||||
revoked_: boolean
|
||||
draft_: Drafted<AnySet, SetState>
|
||||
}
|
||||
|
||||
/** Patches plugin */
|
||||
|
||||
export type PatchPath = (string | number)[]
|
||||
Reference in New Issue
Block a user