0.2.0 - Mid migration

This commit is contained in:
Daniel Mason 2022-04-25 14:47:15 +12:00
parent 139e6a915e
commit 7e38fdbd7d
42393 changed files with 5358157 additions and 62 deletions

60
web/node_modules/immer/src/core/current.ts generated vendored Normal file
View file

@ -0,0 +1,60 @@
import {
die,
isDraft,
shallowCopy,
each,
DRAFT_STATE,
get,
set,
ImmerState,
isDraftable,
Archtype,
getArchtype,
getPlugin
} 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(22, value)
return currentImpl(value)
}
function currentImpl(value: any): any {
if (!isDraftable(value)) return value
const state: ImmerState | undefined = value[DRAFT_STATE]
let copy: any
const archType = getArchtype(value)
if (state) {
if (
!state.modified_ &&
(state.type_ < 4 || !getPlugin("ES5").hasChanges_(state as any))
)
return state.base_
// Optimization: avoid generating new drafts during copying
state.finalized_ = true
copy = copyHelper(value, archType)
state.finalized_ = false
} else {
copy = copyHelper(value, archType)
}
each(copy, (key, childValue) => {
if (state && get(state.base_, key) === childValue) return // no need to copy or search in something that didn't change
set(copy, key, currentImpl(childValue))
})
// In the future, we might consider freezing here, based on the current settings
return archType === Archtype.Set ? new Set(copy) : copy
}
function copyHelper(value: any, archType: number): any {
// creates a shallow copy, even if it is a map or set
switch (archType) {
case Archtype.Map:
return new Map(value)
case Archtype.Set:
// Set will be cloned as array temporarily, so that we can replace individual items
return Array.from(value)
}
return shallowCopy(value)
}

159
web/node_modules/immer/src/core/finalize.ts generated vendored Normal file
View file

@ -0,0 +1,159 @@
import {
ImmerScope,
DRAFT_STATE,
isDraftable,
NOTHING,
PatchPath,
each,
has,
freeze,
ImmerState,
isDraft,
SetState,
set,
ProxyType,
getPlugin,
die,
revokeScope,
isFrozen,
shallowCopy
} 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 (!scope.immer_.useProxies_)
getPlugin("ES5").willFinalizeES5_(scope, result, isReplaced)
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)
if (!scope.parent_) maybeFreeze(scope, result)
}
if (scope.patches_) {
getPlugin("Patches").generateReplacementPatches_(
baseDraft[DRAFT_STATE],
result,
scope.patches_,
scope.inversePatches_!
)
}
} else {
// Finalize the base draft.
result = finalize(scope, baseDraft, [])
}
revokeScope(scope)
if (scope.patches_) {
scope.patchListener_!(scope.patches_, scope.inversePatches_!)
}
return result !== NOTHING ? result : undefined
}
function finalize(rootScope: ImmerScope, value: any, path?: PatchPath) {
// Don't recurse in tho recursive data structures
if (isFrozen(value)) return value
const state: ImmerState = value[DRAFT_STATE]
// A plain object, might need freezing, might contain drafts
if (!state) {
each(
value,
(key, childValue) =>
finalizeProperty(rootScope, state, value, key, childValue, path),
true // See #590, don't recurse into non-enumarable of non drafted objects
)
return value
}
// Never finalize drafts owned by another scope.
if (state.scope_ !== rootScope) return value
// Unmodified draft, return the (frozen) original
if (!state.modified_) {
maybeFreeze(rootScope, state.base_, true)
return state.base_
}
// Not finalized yet, let's do that now
if (!state.finalized_) {
state.finalized_ = true
state.scope_.unfinalizedDrafts_--
const result =
// For ES5, create a good copy from the draft first, with added keys and without deleted keys.
state.type_ === ProxyType.ES5Object || state.type_ === ProxyType.ES5Array
? (state.copy_ = shallowCopy(state.draft_))
: state.copy_
// Finalize all children of the copy
// For sets we clone before iterating, otherwise we can get in endless loop due to modifying during iteration, see #628
// Although the original test case doesn't seem valid anyway, so if this in the way we can turn the next line
// back to each(result, ....)
each(
state.type_ === ProxyType.Set ? new Set(result) : result,
(key, childValue) =>
finalizeProperty(rootScope, state, result, key, childValue, path)
)
// everything inside is frozen, we can freeze here
maybeFreeze(rootScope, result, false)
// first time finalizing, let's create those patches
if (path && rootScope.patches_) {
getPlugin("Patches").generatePatches_(
state,
path,
rootScope.patches_,
rootScope.inversePatches_!
)
}
}
return state.copy_
}
function finalizeProperty(
rootScope: ImmerScope,
parentState: undefined | ImmerState,
targetObject: any,
prop: string | number,
childValue: any,
rootPath?: PatchPath
) {
if (__DEV__ && childValue === targetObject) die(5)
if (isDraft(childValue)) {
const path =
rootPath &&
parentState &&
parentState!.type_ !== ProxyType.Set && // Set objects are atomic since they have no keys.
!has((parentState as Exclude<ImmerState, SetState>).assigned_!, prop) // Skip deep patches for assigned keys.
? rootPath!.concat(prop)
: undefined
// Drafts owned by `scope` are finalized here.
const res = finalize(rootScope, childValue, path)
set(targetObject, prop, res)
// Drafts from another scope must prevented to be frozen
// if we got a draft back from finalize, we're in a nested produce and shouldn't freeze
if (isDraft(res)) {
rootScope.canAutoFreeze_ = false
} else return
}
// Search new objects for unfinalized drafts. Frozen objects should never contain drafts.
if (isDraftable(childValue) && !isFrozen(childValue)) {
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
}
finalize(rootScope, childValue)
// immer deep freezes plain objects, so if there is no parent state, we freeze as well
if (!parentState || !parentState.scope_.parent_)
maybeFreeze(rootScope, childValue)
}
}
function maybeFreeze(scope: ImmerScope, value: any, deep = false) {
if (scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {
freeze(value, deep)
}
}

229
web/node_modules/immer/src/core/immerClass.ts generated vendored Normal file
View file

@ -0,0 +1,229 @@
import {
IProduceWithPatches,
IProduce,
ImmerState,
Drafted,
isDraftable,
processResult,
Patch,
Objectish,
DRAFT_STATE,
Draft,
PatchListener,
isDraft,
isMap,
isSet,
createProxyProxy,
getPlugin,
die,
hasProxies,
enterScope,
revokeScope,
leaveScope,
usePatchesInScope,
getCurrentScope,
NOTHING,
freeze,
current
} from "../internal"
interface ProducersFns {
produce: IProduce
produceWithPatches: IProduceWithPatches
}
export class Immer implements ProducersFns {
useProxies_: boolean = hasProxies
autoFreeze_: boolean = true
constructor(config?: {useProxies?: boolean; autoFreeze?: boolean}) {
if (typeof config?.useProxies === "boolean")
this.setUseProxies(config!.useProxies)
if (typeof config?.autoFreeze === "boolean")
this.setAutoFreeze(config!.autoFreeze)
}
/**
* 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
*/
produce: IProduce = (base: any, recipe?: any, patchListener?: any) => {
// curried invocation
if (typeof base === "function" && typeof recipe !== "function") {
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 (typeof recipe !== "function") die(6)
if (patchListener !== undefined && typeof patchListener !== "function")
die(7)
let result
// Only plain objects, arrays, and "immerable classes" are drafted.
if (isDraftable(base)) {
const scope = enterScope(this)
const proxy = createProxy(this, 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)
}
if (typeof Promise !== "undefined" && result instanceof Promise) {
return result.then(
result => {
usePatchesInScope(scope, patchListener)
return processResult(result, scope)
},
error => {
revokeScope(scope)
throw error
}
)
}
usePatchesInScope(scope, patchListener)
return processResult(result, scope)
} else if (!base || typeof base !== "object") {
result = recipe(base)
if (result === NOTHING) return undefined
if (result === undefined) result = base
if (this.autoFreeze_) freeze(result, true)
return result
} else die(21, base)
}
produceWithPatches: IProduceWithPatches = (
arg1: any,
arg2?: any,
arg3?: any
): any => {
if (typeof arg1 === "function") {
return (state: any, ...args: any[]) =>
this.produceWithPatches(state, (draft: any) => arg1(draft, ...args))
}
let patches: Patch[], inversePatches: Patch[]
const nextState = this.produce(arg1, arg2, (p: Patch[], ip: Patch[]) => {
patches = p
inversePatches = ip
})
return [nextState, 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(this, 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 (__DEV__) {
if (!state || !state.isManual_) die(9)
if (state.finalized_) die(10)
}
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 use the ES2015 `Proxy` class when creating drafts, which is
* always faster than using ES5 proxies.
*
* By default, feature detection is used, so calling this is rarely necessary.
*/
setUseProxies(value: boolean) {
if (value && !hasProxies) {
die(20)
}
this.useProxies_ = value
}
applyPatches<T extends Objectish>(base: T, patches: 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
}
}
const applyPatchesImpl = getPlugin("Patches").applyPatches_
if (isDraft(base)) {
// N.B: never hits if some patch a replacement, patches are never drafts
return applyPatchesImpl(base, patches) as any
}
// Otherwise, produce a copy of the base state.
return this.produce(base, (draft: Drafted) =>
applyPatchesImpl(draft, patches.slice(i + 1))
) as any
}
}
export function createProxy<T extends Objectish>(
immer: Immer,
value: T,
parent?: ImmerState
): Drafted<T, ImmerState> {
// precondition: createProxy should be guarded by isDraftable, so we know we can safely draft
const draft: Drafted = isMap(value)
? getPlugin("MapSet").proxyMap_(value, parent)
: isSet(value)
? getPlugin("MapSet").proxySet_(value, parent)
: immer.useProxies_
? createProxyProxy(value, parent)
: getPlugin("ES5").createES5Proxy_(value, parent)
const scope = parent ? parent.scope_ : getCurrentScope()
scope.drafts_.push(draft)
return draft
}

279
web/node_modules/immer/src/core/proxy.ts generated vendored Normal file
View file

@ -0,0 +1,279 @@
import {
each,
has,
is,
isDraftable,
shallowCopy,
latest,
ImmerBaseState,
ImmerState,
Drafted,
AnyObject,
AnyArray,
Objectish,
getCurrentScope,
DRAFT_STATE,
die,
createProxy,
ProxyType
} from "../internal"
interface ProxyBaseState extends ImmerBaseState {
assigned_: {
[property: string]: boolean
}
parent_?: ImmerState
revoke_(): void
}
export interface ProxyObjectState extends ProxyBaseState {
type_: ProxyType.ProxyObject
base_: any
copy_: any
draft_: Drafted<AnyObject, ProxyObjectState>
}
export interface ProxyArrayState extends ProxyBaseState {
type_: ProxyType.ProxyArray
base_: AnyArray
copy_: AnyArray | null
draft_: Drafted<AnyArray, ProxyArrayState>
}
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> {
const isArray = Array.isArray(base)
const state: ProxyState = {
type_: isArray ? ProxyType.ProxyArray : (ProxyType.ProxyObject 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).
assigned_: {},
// 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
}
// 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 (isArray) {
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
}
/**
* Object drafts
*/
export const objectTraps: ProxyHandler<ProxyState> = {
get(state, prop) {
if (prop === DRAFT_STATE) return state
const source = latest(state)
if (!has(source, prop)) {
// non-existing or non-own property...
return readPropFromProto(state, source, prop)
}
const value = source[prop]
if (state.finalized_ || !isDraftable(value)) {
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)
return (state.copy_![prop as any] = createProxy(
state.scope_.immer_,
value,
state
))
}
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_[prop] = false
return true
}
if (is(value, current) && (value !== undefined || has(state.base_, prop)))
return true
prepareCopy(state)
markChanged(state)
}
if (
state.copy_![prop] === value &&
// special case: NaN
typeof value !== "number" &&
// special case: handle new props with value 'undefined'
(value !== undefined || prop in state.copy_)
)
return true
// @ts-ignore
state.copy_![prop] = value
state.assigned_[prop] = true
return true
},
deleteProperty(state, prop: string) {
// The `undefined` check is a fast path for pre-existing keys.
if (peek(state.base_, prop) !== undefined || prop in state.base_) {
state.assigned_[prop] = false
prepareCopy(state)
markChanged(state)
} else {
// if an originally not assigned property was deleted
delete state.assigned_[prop]
}
// @ts-ignore
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_ !== ProxyType.ProxyArray || prop !== "length",
enumerable: desc.enumerable,
value: owner[prop]
}
},
defineProperty() {
die(11)
},
getPrototypeOf(state) {
return Object.getPrototypeOf(state.base_)
},
setPrototypeOf() {
die(12)
}
}
/**
* Array drafts
*/
const arrayTraps: ProxyHandler<[ProxyArrayState]> = {}
each(objectTraps, (key, fn) => {
// @ts-ignore
arrayTraps[key] = function() {
arguments[0] = arguments[0][0]
return fn.apply(this, arguments)
}
})
arrayTraps.deleteProperty = function(state, prop) {
if (__DEV__ && isNaN(parseInt(prop as any))) die(13)
return objectTraps.deleteProperty!.call(this, state[0], prop)
}
arrayTraps.set = function(state, prop, value) {
if (__DEV__ && 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 = Object.getPrototypeOf(source)
while (proto) {
const desc = Object.getOwnPropertyDescriptor(proto, prop)
if (desc) return desc
proto = Object.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: {base_: any; copy_: any}) {
if (!state.copy_) {
state.copy_ = shallowCopy(state.base_)
}
}

85
web/node_modules/immer/src/core/scope.ts generated vendored Normal file
View file

@ -0,0 +1,85 @@
import {
Patch,
PatchListener,
Drafted,
Immer,
DRAFT_STATE,
ImmerState,
ProxyType,
getPlugin
} from "../internal"
import {die} from "../utils/errors"
/** Each scope represents a `produce` call. */
export interface ImmerScope {
patches_?: Patch[]
inversePatches_?: Patch[]
canAutoFreeze_: boolean
drafts_: any[]
parent_?: ImmerScope
patchListener_?: PatchListener
immer_: Immer
unfinalizedDrafts_: number
}
let currentScope: ImmerScope | undefined
export function getCurrentScope() {
if (__DEV__ && !currentScope) die(0)
return currentScope!
}
function createScope(
parent_: ImmerScope | undefined,
immer_: Immer
): ImmerScope {
return {
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
}
}
export function usePatchesInScope(
scope: ImmerScope,
patchListener?: PatchListener
) {
if (patchListener) {
getPlugin("Patches") // 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 function enterScope(immer: Immer) {
return (currentScope = createScope(currentScope, immer))
}
function revokeDraft(draft: Drafted) {
const state: ImmerState = draft[DRAFT_STATE]
if (
state.type_ === ProxyType.ProxyObject ||
state.type_ === ProxyType.ProxyArray
)
state.revoke_()
else state.revoked_ = true
}

117
web/node_modules/immer/src/immer.ts generated vendored Normal file
View file

@ -0,0 +1,117 @@
import {
IProduce,
IProduceWithPatches,
Immer,
Draft,
Immutable
} from "./internal"
export {
Draft,
Immutable,
Patch,
PatchListener,
original,
current,
isDraft,
isDraftable,
NOTHING as nothing,
DRAFTABLE as immerable,
freeze
} 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 = immer.produce
export default produce
/**
* Like `produce`, but `produceWithPatches` always returns a tuple
* [nextState, patches, inversePatches] (instead of just the next state)
*/
export const produceWithPatches: IProduceWithPatches = 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 = immer.setAutoFreeze.bind(immer)
/**
* Pass true to use the ES2015 `Proxy` class when creating drafts, which is
* always faster than using ES5 proxies.
*
* By default, feature detection is used, so calling this is rarely necessary.
*/
export const setUseProxies = immer.setUseProxies.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 = 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 = 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 = 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 function castDraft<T>(value: T): Draft<T> {
return 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 function castImmutable<T>(value: T): Immutable<T> {
return value as any
}
export {Immer}
export {enableES5} from "./plugins/es5"
export {enablePatches} from "./plugins/patches"
export {enableMapSet} from "./plugins/mapset"
export {enableAllPlugins} from "./plugins/all"

11
web/node_modules/immer/src/internal.ts generated vendored Normal file
View 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"

9
web/node_modules/immer/src/plugins/all.ts generated vendored Normal file
View file

@ -0,0 +1,9 @@
import {enableES5} from "./es5"
import {enableMapSet} from "./mapset"
import {enablePatches} from "./patches"
export function enableAllPlugins() {
enableES5()
enableMapSet()
enablePatches()
}

269
web/node_modules/immer/src/plugins/es5.ts generated vendored Normal file
View file

@ -0,0 +1,269 @@
import {
ImmerState,
Drafted,
ES5ArrayState,
ES5ObjectState,
each,
has,
isDraft,
latest,
DRAFT_STATE,
is,
loadPlugin,
ImmerScope,
ProxyType,
getCurrentScope,
die,
markChanged,
objectTraps,
ownKeys,
getOwnPropertyDescriptors
} from "../internal"
type ES5State = ES5ArrayState | ES5ObjectState
export function enableES5() {
function willFinalizeES5_(
scope: ImmerScope,
result: any,
isReplaced: boolean
) {
if (!isReplaced) {
if (scope.patches_) {
markChangesRecursively(scope.drafts_![0])
}
// This is faster when we don't care about which attributes changed.
markChangesSweep(scope.drafts_)
}
// When a child draft is returned, look for changes.
else if (
isDraft(result) &&
(result[DRAFT_STATE] as ES5State).scope_ === scope
) {
markChangesSweep(scope.drafts_)
}
}
function createES5Draft(isArray: boolean, base: any) {
if (isArray) {
const draft = new Array(base.length)
for (let i = 0; i < base.length; i++)
Object.defineProperty(draft, "" + i, proxyProperty(i, true))
return draft
} else {
const descriptors = getOwnPropertyDescriptors(base)
delete descriptors[DRAFT_STATE as any]
const keys = ownKeys(descriptors)
for (let i = 0; i < keys.length; i++) {
const key: any = keys[i]
descriptors[key] = proxyProperty(
key,
isArray || !!descriptors[key].enumerable
)
}
return Object.create(Object.getPrototypeOf(base), descriptors)
}
}
function createES5Proxy_<T>(
base: T,
parent?: ImmerState
): Drafted<T, ES5ObjectState | ES5ArrayState> {
const isArray = Array.isArray(base)
const draft = createES5Draft(isArray, base)
const state: ES5ObjectState | ES5ArrayState = {
type_: isArray ? ProxyType.ES5Array : (ProxyType.ES5Object as any),
scope_: parent ? parent.scope_ : getCurrentScope(),
modified_: false,
finalized_: false,
assigned_: {},
parent_: parent,
// base is the object we are drafting
base_: base,
// draft is the draft object itself, that traps all reads and reads from either the base (if unmodified) or copy (if modified)
draft_: draft,
copy_: null,
revoked_: false,
isManual_: false
}
Object.defineProperty(draft, DRAFT_STATE, {
value: state,
// enumerable: false <- the default
writable: true
})
return draft
}
// property descriptors are recycled to make sure we don't create a get and set closure per property,
// but share them all instead
const descriptors: {[prop: string]: PropertyDescriptor} = {}
function proxyProperty(
prop: string | number,
enumerable: boolean
): PropertyDescriptor {
let desc = descriptors[prop]
if (desc) {
desc.enumerable = enumerable
} else {
descriptors[prop] = desc = {
configurable: true,
enumerable,
get(this: any) {
const state = this[DRAFT_STATE]
if (__DEV__) assertUnrevoked(state)
// @ts-ignore
return objectTraps.get(state, prop)
},
set(this: any, value) {
const state = this[DRAFT_STATE]
if (__DEV__) assertUnrevoked(state)
// @ts-ignore
objectTraps.set(state, prop, value)
}
}
}
return desc
}
// This looks expensive, but only proxies are visited, and only objects without known changes are scanned.
function markChangesSweep(drafts: Drafted<any, ImmerState>[]) {
// The natural order of drafts in the `scope` array is based on when they
// were accessed. By processing drafts in reverse natural order, we have a
// better chance of processing leaf nodes first. When a leaf node is known to
// have changed, we can avoid any traversal of its ancestor nodes.
for (let i = drafts.length - 1; i >= 0; i--) {
const state: ES5State = drafts[i][DRAFT_STATE]
if (!state.modified_) {
switch (state.type_) {
case ProxyType.ES5Array:
if (hasArrayChanges(state)) markChanged(state)
break
case ProxyType.ES5Object:
if (hasObjectChanges(state)) markChanged(state)
break
}
}
}
}
function markChangesRecursively(object: any) {
if (!object || typeof object !== "object") return
const state: ES5State | undefined = object[DRAFT_STATE]
if (!state) return
const {base_, draft_, assigned_, type_} = state
if (type_ === ProxyType.ES5Object) {
// Look for added keys.
// probably there is a faster way to detect changes, as sweep + recurse seems to do some
// unnecessary work.
// also: probably we can store the information we detect here, to speed up tree finalization!
each(draft_, key => {
if ((key as any) === DRAFT_STATE) return
// The `undefined` check is a fast path for pre-existing keys.
if ((base_ as any)[key] === undefined && !has(base_, key)) {
assigned_[key] = true
markChanged(state)
} else if (!assigned_[key]) {
// Only untouched properties trigger recursion.
markChangesRecursively(draft_[key])
}
})
// Look for removed keys.
each(base_, key => {
// The `undefined` check is a fast path for pre-existing keys.
if (draft_[key] === undefined && !has(draft_, key)) {
assigned_[key] = false
markChanged(state)
}
})
} else if (type_ === ProxyType.ES5Array) {
if (hasArrayChanges(state as ES5ArrayState)) {
markChanged(state)
assigned_.length = true
}
if (draft_.length < base_.length) {
for (let i = draft_.length; i < base_.length; i++) assigned_[i] = false
} else {
for (let i = base_.length; i < draft_.length; i++) assigned_[i] = true
}
// Minimum count is enough, the other parts has been processed.
const min = Math.min(draft_.length, base_.length)
for (let i = 0; i < min; i++) {
// Only untouched indices trigger recursion.
if (assigned_[i] === undefined) markChangesRecursively(draft_[i])
}
}
}
function hasObjectChanges(state: ES5ObjectState) {
const {base_, draft_} = state
// Search for added keys and changed keys. Start at the back, because
// non-numeric keys are ordered by time of definition on the object.
const keys = ownKeys(draft_)
for (let i = keys.length - 1; i >= 0; i--) {
const key: any = keys[i]
if (key === DRAFT_STATE) continue
const baseValue = base_[key]
// The `undefined` check is a fast path for pre-existing keys.
if (baseValue === undefined && !has(base_, key)) {
return true
}
// Once a base key is deleted, future changes go undetected, because its
// descriptor is erased. This branch detects any missed changes.
else {
const value = draft_[key]
const state: ImmerState = value && value[DRAFT_STATE]
if (state ? state.base_ !== baseValue : !is(value, baseValue)) {
return true
}
}
}
// At this point, no keys were added or changed.
// Compare key count to determine if keys were deleted.
const baseIsDraft = !!base_[DRAFT_STATE as any]
return keys.length !== ownKeys(base_).length + (baseIsDraft ? 0 : 1) // + 1 to correct for DRAFT_STATE
}
function hasArrayChanges(state: ES5ArrayState) {
const {draft_} = state
if (draft_.length !== state.base_.length) return true
// See #116
// If we first shorten the length, our array interceptors will be removed.
// If after that new items are added, result in the same original length,
// those last items will have no intercepting property.
// So if there is no own descriptor on the last position, we know that items were removed and added
// N.B.: splice, unshift, etc only shift values around, but not prop descriptors, so we only have to check
// the last one
const descriptor = Object.getOwnPropertyDescriptor(
draft_,
draft_.length - 1
)
// descriptor can be null, but only for newly created sparse arrays, eg. new Array(10)
if (descriptor && !descriptor.get) return true
// For all other cases, we don't have to compare, as they would have been picked up by the index setters
return false
}
function hasChanges_(state: ES5State) {
return state.type_ === ProxyType.ES5Object
? hasObjectChanges(state)
: hasArrayChanges(state)
}
function assertUnrevoked(state: any /*ES5State | MapState | SetState*/) {
if (state.revoked_) die(3, JSON.stringify(latest(state)))
}
loadPlugin("ES5", {
createES5Proxy_,
willFinalizeES5_,
hasChanges_
})
}

344
web/node_modules/immer/src/plugins/mapset.ts generated vendored Normal file
View file

@ -0,0 +1,344 @@
// types only!
import {
ImmerState,
AnyMap,
AnySet,
MapState,
SetState,
DRAFT_STATE,
getCurrentScope,
latest,
iteratorSymbol,
isDraftable,
createProxy,
loadPlugin,
markChanged,
ProxyType,
die,
each
} from "../internal"
export function enableMapSet() {
/* istanbul ignore next */
var extendStatics = function(d: any, b: any): any {
extendStatics =
Object.setPrototypeOf ||
({__proto__: []} instanceof Array &&
function(d, b) {
d.__proto__ = b
}) ||
function(d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]
}
return extendStatics(d, b)
}
// Ugly hack to resolve #502 and inherit built in Map / Set
function __extends(d: any, b: any): any {
extendStatics(d, b)
function __(this: any): any {
this.constructor = d
}
d.prototype =
// @ts-ignore
((__.prototype = b.prototype), new __())
}
const DraftMap = (function(_super) {
__extends(DraftMap, _super)
// Create class manually, cause #502
function DraftMap(this: any, target: AnyMap, parent?: ImmerState): any {
this[DRAFT_STATE] = {
type_: ProxyType.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
} as MapState
return this
}
const p = DraftMap.prototype
Object.defineProperty(p, "size", {
get: function() {
return latest(this[DRAFT_STATE]).size
}
// enumerable: false,
// configurable: true
})
p.has = function(key: any): boolean {
return latest(this[DRAFT_STATE]).has(key)
}
p.set = function(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)
}
return this
}
p.delete = function(key: any): boolean {
if (!this.has(key)) {
return false
}
const state: MapState = this[DRAFT_STATE]
assertUnrevoked(state)
prepareMapCopy(state)
markChanged(state)
state.assigned_!.set(key, false)
state.copy_!.delete(key)
return true
}
p.clear = function() {
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()
}
}
p.forEach = function(
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)
})
}
p.get = function(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_.immer_, value, state)
prepareMapCopy(state)
state.copy_!.set(key, draft)
return draft
}
p.keys = function(): IterableIterator<any> {
return latest(this[DRAFT_STATE]).keys()
}
p.values = function(): IterableIterator<any> {
const iterator = this.keys()
return {
[iteratorSymbol]: () => 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
}
p.entries = function(): IterableIterator<[any, any]> {
const iterator = this.keys()
return {
[iteratorSymbol]: () => 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
}
p[iteratorSymbol] = function() {
return this.entries()
}
return DraftMap
})(Map)
function proxyMap_<T extends AnyMap>(target: T, parent?: ImmerState): T {
// @ts-ignore
return new DraftMap(target, parent)
}
function prepareMapCopy(state: MapState) {
if (!state.copy_) {
state.assigned_ = new Map()
state.copy_ = new Map(state.base_)
}
}
const DraftSet = (function(_super) {
__extends(DraftSet, _super)
// Create class manually, cause #502
function DraftSet(this: any, target: AnySet, parent?: ImmerState) {
this[DRAFT_STATE] = {
type_: ProxyType.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
} as SetState
return this
}
const p = DraftSet.prototype
Object.defineProperty(p, "size", {
get: function() {
return latest(this[DRAFT_STATE]).size
}
// enumerable: true,
})
p.has = function(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
}
p.add = function(value: any): any {
const state: SetState = this[DRAFT_STATE]
assertUnrevoked(state)
if (!this.has(value)) {
prepareSetCopy(state)
markChanged(state)
state.copy_!.add(value)
}
return this
}
p.delete = function(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)
)
}
p.clear = function() {
const state: SetState = this[DRAFT_STATE]
assertUnrevoked(state)
if (latest(state).size) {
prepareSetCopy(state)
markChanged(state)
state.copy_!.clear()
}
}
p.values = function(): IterableIterator<any> {
const state: SetState = this[DRAFT_STATE]
assertUnrevoked(state)
prepareSetCopy(state)
return state.copy_!.values()
}
p.entries = function entries(): IterableIterator<[any, any]> {
const state: SetState = this[DRAFT_STATE]
assertUnrevoked(state)
prepareSetCopy(state)
return state.copy_!.entries()
}
p.keys = function(): IterableIterator<any> {
return this.values()
}
p[iteratorSymbol] = function() {
return this.values()
}
p.forEach = function 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()
}
}
return DraftSet
})(Set)
function proxySet_<T extends AnySet>(target: T, parent?: ImmerState): T {
// @ts-ignore
return new DraftSet(target, parent)
}
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_.immer_, value, state)
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)))
}
loadPlugin("MapSet", {proxyMap_, proxySet_})
}

299
web/node_modules/immer/src/plugins/patches.ts generated vendored Normal file
View file

@ -0,0 +1,299 @@
import {immerable} from "../immer"
import {
ImmerState,
Patch,
SetState,
ES5ArrayState,
ProxyArrayState,
MapState,
ES5ObjectState,
ProxyObjectState,
PatchPath,
get,
each,
has,
getArchtype,
isSet,
isMap,
loadPlugin,
ProxyType,
Archtype,
die,
isDraft,
isDraftable,
NOTHING
} from "../internal"
export function enablePatches() {
const REPLACE = "replace"
const ADD = "add"
const REMOVE = "remove"
function generatePatches_(
state: ImmerState,
basePath: PatchPath,
patches: Patch[],
inversePatches: Patch[]
): void {
switch (state.type_) {
case ProxyType.ProxyObject:
case ProxyType.ES5Object:
case ProxyType.Map:
return generatePatchesFromAssigned(
state,
basePath,
patches,
inversePatches
)
case ProxyType.ES5Array:
case ProxyType.ProxyArray:
return generateArrayPatches(state, basePath, patches, inversePatches)
case ProxyType.Set:
return generateSetPatches(
(state as any) as SetState,
basePath,
patches,
inversePatches
)
}
}
function generateArrayPatches(
state: ES5ArrayState | 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]
}
// Process replaced indices.
for (let i = 0; i < base_.length; i++) {
if (assigned_[i] && copy_[i] !== base_[i]) {
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(copy_[i])
})
inversePatches.push({
op: REPLACE,
path,
value: clonePatchValueIfNeeded(base_[i])
})
}
}
// 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])
})
}
if (base_.length < copy_.length) {
inversePatches.push({
op: REPLACE,
path: basePath.concat(["length"]),
value: base_.length
})
}
}
// This is used for both Map objects and normal objects.
function generatePatchesFromAssigned(
state: MapState | ES5ObjectState | ProxyObjectState,
basePath: PatchPath,
patches: Patch[],
inversePatches: Patch[]
) {
const {base_, copy_} = state
each(state.assigned_!, (key, assignedValue) => {
const origValue = get(base_, key)
const value = get(copy_!, key)
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})
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_(
rootState: ImmerState,
replacement: any,
patches: Patch[],
inversePatches: Patch[]
): void {
patches.push({
op: REPLACE,
path: [],
value: replacement === NOTHING ? undefined : replacement
})
inversePatches.push({
op: REPLACE,
path: [],
value: rootState.base_
})
}
function applyPatches_<T>(draft: T, patches: 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)
const p = path[i]
// See #738, avoid prototype pollution
if (
(parentType === Archtype.Object || parentType === Archtype.Array) &&
(p === "__proto__" || p === "constructor")
)
die(24)
if (typeof base === "function" && p === "prototype") die(24)
base = get(base, p)
if (typeof base !== "object") die(15, 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(16)
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 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(17, 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 (Array.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(Object.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("Patches", {
applyPatches_,
generatePatches_,
generateReplacementPatches_
})
}

1
web/node_modules/immer/src/types/globals.d.ts generated vendored Normal file
View file

@ -0,0 +1 @@
declare const __DEV__: boolean

113
web/node_modules/immer/src/types/index.js.flow generated vendored Normal file
View file

@ -0,0 +1,113 @@
// @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 default 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
/**
* Manually override whether proxies should be used.
* By default done by using feature detection
*/
declare export function setUseProxies(useProxies: 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 enableES5(): void
declare export function enableMapSet(): void
declare export function enablePatches(): void
declare export function enableAllPlugins(): void
declare export function freeze<T>(obj: T, freeze?: boolean): T

256
web/node_modules/immer/src/types/types-external.ts generated vendored Normal file
View file

@ -0,0 +1,256 @@
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 "ES2105.collections" 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 infite 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> = {-readonly [K in keyof T]: Draft<T[K]>}
export type Draft<T> = T extends PrimitiveType
? T
: T extends AtomicObject
? T
: T extends IfAvailable<ReadonlyMap<infer K, infer V>> // Map extends ReadonlyMap
? Map<Draft<K>, Draft<V>>
: T extends IfAvailable<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 IfAvailable<ReadonlyMap<infer K, infer V>> // Map extends ReadonlyMap
? ReadonlyMap<Immutable<K>, Immutable<V>>
: T extends IfAvailable<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 Nothing ? undefined : T
/** The inferred return type of `produce` */
export type Produced<Base, Return> = Return extends void
? Base
: Return extends Promise<infer Result>
? Promise<Result extends void ? Base : FromNothing<Result>>
: FromNothing<Return>
/**
* Utility types
*/
type PatchesTuple<T> = readonly [T, Patch[], Patch[]]
type ValidRecipeReturnType<State> =
| State
| void
| undefined
| (State extends undefined ? Nothing : never)
type ValidRecipeReturnTypePossiblyPromise<State> =
| ValidRecipeReturnType<State>
| Promise<ValidRecipeReturnType<State>>
type PromisifyReturnIfNeeded<
State,
Recipe extends AnyFunc,
UsePatches extends boolean
> = ReturnType<Recipe> extends Promise<any>
? Promise<UsePatches extends true ? PatchesTuple<State> : State>
: 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 ValidRecipeReturnTypePossiblyPromise<DraftState>
? (
base: Immutable<DraftState>,
...args: RestArgs
) => PromisifyReturnIfNeeded<DraftState, Recipe, 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
) => ValidRecipeReturnTypePossiblyPromise<State>
? (
base?: State | undefined,
...args: RestArgs
) => PromisifyReturnIfNeeded<State, Recipe, 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
/** Promisified dormal producer */
<Base, D = Draft<Base>>(
base: Base,
recipe: (draft: D) => Promise<ValidRecipeReturnType<D>>,
listener?: PatchListener
): Promise<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<Base>,
listener?: PatchListener
): PatchesTuple<Immutable<Base>>
<Base, D = Draft<Base>>(
base: Base,
recipe: (draft: D) => Promise<ValidRecipeReturnType<Base>>,
listener?: PatchListener
): PatchesTuple<Promise<Immutable<Base>>>
}
// 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
web/node_modules/immer/src/types/types-internal.ts generated vendored Normal file
View file

@ -0,0 +1,55 @@
import {
SetState,
ImmerScope,
ProxyObjectState,
ProxyArrayState,
ES5ObjectState,
ES5ArrayState,
MapState,
DRAFT_STATE
} 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 const enum ProxyType {
ProxyObject,
ProxyArray,
Map,
Set,
ES5Object,
ES5Array
}
export interface ImmerBaseState {
parent_?: ImmerState
scope_: ImmerScope
modified_: boolean
finalized_: boolean
isManual_: boolean
}
export type ImmerState =
| ProxyObjectState
| ProxyArrayState
| ES5ObjectState
| ES5ArrayState
| 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

217
web/node_modules/immer/src/utils/common.ts generated vendored Normal file
View file

@ -0,0 +1,217 @@
import {
DRAFT_STATE,
DRAFTABLE,
hasSet,
Objectish,
Drafted,
AnyObject,
AnyMap,
AnySet,
ImmerState,
hasMap,
Archtype,
die
} from "../internal"
/** Returns true if the given value is an Immer draft */
/*#__PURE__*/
export function isDraft(value: any): boolean {
return !!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) ||
Array.isArray(value) ||
!!value[DRAFTABLE] ||
!!value.constructor[DRAFTABLE] ||
isMap(value) ||
isSet(value)
)
}
const objectCtorString = Object.prototype.constructor.toString()
/*#__PURE__*/
export function isPlainObject(value: any): boolean {
if (!value || typeof value !== "object") return false
const proto = Object.getPrototypeOf(value)
if (proto === null) {
return true
}
const Ctor =
Object.hasOwnProperty.call(proto, "constructor") && proto.constructor
if (Ctor === Object) return true
return (
typeof Ctor == "function" &&
Function.toString.call(Ctor) === 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(23, value)
return value[DRAFT_STATE].base_
}
/*#__PURE__*/
export const ownKeys: (target: AnyObject) => PropertyKey[] =
typeof Reflect !== "undefined" && Reflect.ownKeys
? Reflect.ownKeys
: typeof Object.getOwnPropertySymbols !== "undefined"
? obj =>
Object.getOwnPropertyNames(obj).concat(
Object.getOwnPropertySymbols(obj) as any
)
: /* istanbul ignore next */ Object.getOwnPropertyNames
export const getOwnPropertyDescriptors =
Object.getOwnPropertyDescriptors ||
function getOwnPropertyDescriptors(target: any) {
// Polyfill needed for Hermes and IE, see https://github.com/facebook/hermes/issues/274
const res: any = {}
ownKeys(target).forEach(key => {
res[key] = Object.getOwnPropertyDescriptor(target, key)
})
return res
}
export function each<T extends Objectish>(
obj: T,
iter: (key: string | number, value: any, source: T) => void,
enumerableOnly?: boolean
): void
export function each(obj: any, iter: any, enumerableOnly = false) {
if (getArchtype(obj) === Archtype.Object) {
;(enumerableOnly ? Object.keys : ownKeys)(obj).forEach(key => {
if (!enumerableOnly || typeof key !== "symbol") iter(key, obj[key], obj)
})
} else {
obj.forEach((entry: any, index: any) => iter(index, entry, obj))
}
}
/*#__PURE__*/
export function getArchtype(thing: any): Archtype {
/* istanbul ignore next */
const state: undefined | ImmerState = thing[DRAFT_STATE]
return state
? state.type_ > 3
? state.type_ - 4 // cause Object and Array map back from 4 and 5
: (state.type_ as any) // others are the same
: Array.isArray(thing)
? Archtype.Array
: isMap(thing)
? Archtype.Map
: isSet(thing)
? Archtype.Set
: Archtype.Object
}
/*#__PURE__*/
export function has(thing: any, prop: PropertyKey): boolean {
return getArchtype(thing) === Archtype.Map
? thing.has(prop)
: Object.prototype.hasOwnProperty.call(thing, prop)
}
/*#__PURE__*/
export function get(thing: AnyMap | AnyObject, prop: PropertyKey): any {
// @ts-ignore
return getArchtype(thing) === Archtype.Map ? thing.get(prop) : thing[prop]
}
/*#__PURE__*/
export function set(thing: any, propOrOldValue: PropertyKey, value: any) {
const t = getArchtype(thing)
if (t === Archtype.Map) thing.set(propOrOldValue, value)
else if (t === Archtype.Set) {
thing.delete(propOrOldValue)
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
}
}
/*#__PURE__*/
export function isMap(target: any): target is AnyMap {
return hasMap && target instanceof Map
}
/*#__PURE__*/
export function isSet(target: any): target is AnySet {
return hasSet && target instanceof Set
}
/*#__PURE__*/
export function latest(state: ImmerState): any {
return state.copy_ || state.base_
}
/*#__PURE__*/
export function shallowCopy(base: any) {
if (Array.isArray(base)) return Array.prototype.slice.call(base)
const descriptors = getOwnPropertyDescriptors(base)
delete descriptors[DRAFT_STATE as any]
let keys = 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 Object.create(Object.getPrototypeOf(base), descriptors)
}
/**
* 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 */) {
obj.set = obj.add = obj.clear = obj.delete = dontMutateFrozenCollections as any
}
Object.freeze(obj)
if (deep) each(obj, (key, value) => freeze(value, true), true)
return obj
}
function dontMutateFrozenCollections() {
die(2)
}
export function isFrozen(obj: any): boolean {
if (obj == null || typeof obj !== "object") return true
// See #600, IE dies on non-objects in Object.isFrozen
return Object.isFrozen(obj)
}

47
web/node_modules/immer/src/utils/env.ts generated vendored Normal file
View file

@ -0,0 +1,47 @@
// Should be no imports here!
// Some things that should be evaluated before all else...
// We only want to know if non-polyfilled symbols are available
const hasSymbol =
typeof Symbol !== "undefined" && typeof Symbol("x") === "symbol"
export const hasMap = typeof Map !== "undefined"
export const hasSet = typeof Set !== "undefined"
export const hasProxies =
typeof Proxy !== "undefined" &&
typeof Proxy.revocable !== "undefined" &&
typeof Reflect !== "undefined"
/**
* The sentinel value returned by producers to replace the draft with undefined.
*/
export const NOTHING: Nothing = hasSymbol
? Symbol.for("immer-nothing")
: ({["immer-nothing"]: true} as any)
/**
* 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 = hasSymbol
? Symbol.for("immer-draftable")
: ("__$immer_draftable" as any)
export const DRAFT_STATE: unique symbol = hasSymbol
? Symbol.for("immer-state")
: ("__$immer_state" as any)
// Even a polyfilled Symbol might provide Symbol.iterator
export const iteratorSymbol: typeof Symbol.iterator =
(typeof Symbol != "undefined" && Symbol.iterator) || ("@@iterator" as any)
/** Use a class type for `nothing` so its type is unique */
export class Nothing {
// This lets us do `Exclude<T, Nothing>`
// @ts-ignore
private _!: unique symbol
}

60
web/node_modules/immer/src/utils/errors.ts generated vendored Normal file
View file

@ -0,0 +1,60 @@
const errors = {
0: "Illegal state",
1: "Immer drafts cannot have computed properties",
2: "This object has been frozen and should not be mutated",
3(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
)
},
4: "An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.",
5: "Immer forbids circular references",
6: "The first or second argument to `produce` must be a function",
7: "The third argument to `produce` must be a function or undefined",
8: "First argument to `createDraft` must be a plain object, an array, or an immerable object",
9: "First argument to `finishDraft` must be a draft returned by `createDraft`",
10: "The given draft is already finalized",
11: "Object.defineProperty() cannot be used on an Immer draft",
12: "Object.setPrototypeOf() cannot be used on an Immer draft",
13: "Immer only supports deleting array indices",
14: "Immer only supports setting array indices and the 'length' property",
15(path: string) {
return "Cannot apply patch, path doesn't resolve: " + path
},
16: 'Sets cannot have "replace" patches.',
17(op: string) {
return "Unsupported patch operation: " + op
},
18(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.`
},
20: "Cannot use proxies if Proxy, Proxy.revocable or Reflect are not available",
21(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}'`
},
22(thing: string) {
return `'current' expects a draft, got: ${thing}`
},
23(thing: string) {
return `'original' expects a draft, got: ${thing}`
},
24: "Patching reserved attributes like __proto__, prototype and constructor is not allowed"
} as const
export function die(error: keyof typeof errors, ...args: any[]): never {
if (__DEV__) {
const e = errors[error]
const msg = !e
? "unknown error nr: " + error
: typeof e === "function"
? e.apply(null, args as any)
: e
throw new Error(`[Immer] ${msg}`)
}
throw new Error(
`[Immer] minified error nr: ${error}${
args.length ? " " + args.map(s => `'${s}'`).join(",") : ""
}. Find the full error at: https://bit.ly/3cXEKWf`
)
}

109
web/node_modules/immer/src/utils/plugins.ts generated vendored Normal file
View file

@ -0,0 +1,109 @@
import {
ImmerState,
Patch,
ImmerScope,
Drafted,
AnyObject,
ImmerBaseState,
AnyMap,
AnySet,
ProxyType,
die
} from "../internal"
/** Plugin utilities */
const plugins: {
Patches?: {
generatePatches_(
state: ImmerState,
basePath: PatchPath,
patches: Patch[],
inversePatches: Patch[]
): void
generateReplacementPatches_(
rootState: ImmerState,
replacement: any,
patches: Patch[],
inversePatches: Patch[]
): void
applyPatches_<T>(draft: T, patches: Patch[]): T
}
ES5?: {
willFinalizeES5_(scope: ImmerScope, result: any, isReplaced: boolean): void
createES5Proxy_<T>(
base: T,
parent?: ImmerState
): Drafted<T, ES5ObjectState | ES5ArrayState>
hasChanges_(state: ES5ArrayState | ES5ObjectState): boolean
}
MapSet?: {
proxyMap_<T extends AnyMap>(target: T, parent?: ImmerState): T
proxySet_<T extends AnySet>(target: T, parent?: ImmerState): T
}
} = {}
type Plugins = typeof plugins
export function getPlugin<K extends keyof Plugins>(
pluginKey: K
): Exclude<Plugins[K], undefined> {
const plugin = plugins[pluginKey]
if (!plugin) {
die(18, pluginKey)
}
// @ts-ignore
return plugin
}
export function loadPlugin<K extends keyof Plugins>(
pluginKey: K,
implementation: Plugins[K]
): void {
if (!plugins[pluginKey]) plugins[pluginKey] = implementation
}
/** ES5 Plugin */
interface ES5BaseState extends ImmerBaseState {
assigned_: {[key: string]: any}
parent_?: ImmerState
revoked_: boolean
}
export interface ES5ObjectState extends ES5BaseState {
type_: ProxyType.ES5Object
draft_: Drafted<AnyObject, ES5ObjectState>
base_: AnyObject
copy_: AnyObject | null
}
export interface ES5ArrayState extends ES5BaseState {
type_: ProxyType.ES5Array
draft_: Drafted<AnyObject, ES5ArrayState>
base_: any
copy_: any
}
/** Map / Set plugin */
export interface MapState extends ImmerBaseState {
type_: ProxyType.Map
copy_: AnyMap | undefined
assigned_: Map<any, boolean> | undefined
base_: AnyMap
revoked_: boolean
draft_: Drafted<AnyMap, MapState>
}
export interface SetState extends ImmerBaseState {
type_: ProxyType.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)[]