UNPKG

immer

Version:

Create your next immutable state by mutating the current one

1 lines 98.3 kB
{"version":3,"sources":["../src/utils/env.ts","../src/utils/errors.ts","../src/utils/common.ts","../src/utils/plugins.ts","../src/core/scope.ts","../src/core/finalize.ts","../src/core/proxy.ts","../src/core/immerClass.ts","../src/core/current.ts","../src/plugins/patches.ts","../src/plugins/mapset.ts","../src/immer.ts"],"sourcesContent":["// Should be no imports here!\n\n/**\n * The sentinel value returned by producers to replace the draft with undefined.\n */\nexport const NOTHING: unique symbol = Symbol.for(\"immer-nothing\")\n\n/**\n * To let Immer treat your class instances as plain immutable objects\n * (albeit with a custom prototype), you must define either an instance property\n * or a static property on each of your custom classes.\n *\n * Otherwise, your class instance will never be drafted, which means it won't be\n * safe to mutate in a produce callback.\n */\nexport const DRAFTABLE: unique symbol = Symbol.for(\"immer-draftable\")\n\nexport const DRAFT_STATE: unique symbol = Symbol.for(\"immer-state\")\n","import {isFunction} from \"../internal\"\n\nexport const errors =\n\tprocess.env.NODE_ENV !== \"production\"\n\t\t? [\n\t\t\t\t// All error codes, starting by 0:\n\t\t\t\tfunction(plugin: string) {\n\t\t\t\t\treturn `The plugin for '${plugin}' has not been loaded into Immer. To enable the plugin, import and call \\`enable${plugin}()\\` when initializing your application.`\n\t\t\t\t},\n\t\t\t\tfunction(thing: string) {\n\t\t\t\t\treturn `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}'`\n\t\t\t\t},\n\t\t\t\t\"This object has been frozen and should not be mutated\",\n\t\t\t\tfunction(data: any) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\t\"Cannot use a proxy that has been revoked. Did you pass an object from inside an immer function to an async process? \" +\n\t\t\t\t\t\tdata\n\t\t\t\t\t)\n\t\t\t\t},\n\t\t\t\t\"An immer producer returned a new value *and* modified its draft. Either return a new value *or* modify the draft.\",\n\t\t\t\t\"Immer forbids circular references\",\n\t\t\t\t\"The first or second argument to `produce` must be a function\",\n\t\t\t\t\"The third argument to `produce` must be a function or undefined\",\n\t\t\t\t\"First argument to `createDraft` must be a plain object, an array, or an immerable object\",\n\t\t\t\t\"First argument to `finishDraft` must be a draft returned by `createDraft`\",\n\t\t\t\tfunction(thing: string) {\n\t\t\t\t\treturn `'current' expects a draft, got: ${thing}`\n\t\t\t\t},\n\t\t\t\t\"Object.defineProperty() cannot be used on an Immer draft\",\n\t\t\t\t\"Object.setPrototypeOf() cannot be used on an Immer draft\",\n\t\t\t\t\"Immer only supports deleting array indices\",\n\t\t\t\t\"Immer only supports setting array indices and the 'length' property\",\n\t\t\t\tfunction(thing: string) {\n\t\t\t\t\treturn `'original' expects a draft, got: ${thing}`\n\t\t\t\t}\n\t\t\t\t// Note: if more errors are added, the errorOffset in Patches.ts should be increased\n\t\t\t\t// See Patches.ts for additional errors\n\t\t ]\n\t\t: []\n\nexport function die(error: number, ...args: any[]): never {\n\tif (process.env.NODE_ENV !== \"production\") {\n\t\tconst e = errors[error]\n\t\tconst msg = isFunction(e) ? e.apply(null, args as any) : e\n\t\tthrow new Error(`[Immer] ${msg}`)\n\t}\n\tthrow new Error(\n\t\t`[Immer] minified error nr: ${error}. Full error at: https://bit.ly/3cXEKWf`\n\t)\n}\n","import {\n\tDRAFT_STATE,\n\tDRAFTABLE,\n\tObjectish,\n\tDrafted,\n\tAnyObject,\n\tAnyMap,\n\tAnySet,\n\tImmerState,\n\tArchType,\n\tdie,\n\tStrictMode\n} from \"../internal\"\n\nconst O = Object\n\nexport const getPrototypeOf = O.getPrototypeOf\n\nexport const CONSTRUCTOR = \"constructor\"\nexport const PROTOTYPE = \"prototype\"\n\nexport const CONFIGURABLE = \"configurable\"\nexport const ENUMERABLE = \"enumerable\"\nexport const WRITABLE = \"writable\"\nexport const VALUE = \"value\"\n\n/** Returns true if the given value is an Immer draft */\n/*#__PURE__*/\nexport let isDraft = (value: any): boolean => !!value && !!value[DRAFT_STATE]\n\n/** Returns true if the given value can be drafted by Immer */\n/*#__PURE__*/\nexport function isDraftable(value: any): boolean {\n\tif (!value) return false\n\treturn (\n\t\tisPlainObject(value) ||\n\t\tisArray(value) ||\n\t\t!!value[DRAFTABLE] ||\n\t\t!!value[CONSTRUCTOR]?.[DRAFTABLE] ||\n\t\tisMap(value) ||\n\t\tisSet(value)\n\t)\n}\n\nconst objectCtorString = O[PROTOTYPE][CONSTRUCTOR].toString()\nconst cachedCtorStrings = new WeakMap()\n/*#__PURE__*/\nexport function isPlainObject(value: any): boolean {\n\tif (!value || !isObjectish(value)) return false\n\tconst proto = getPrototypeOf(value)\n\tif (proto === null || proto === O[PROTOTYPE]) return true\n\n\tconst Ctor = O.hasOwnProperty.call(proto, CONSTRUCTOR) && proto[CONSTRUCTOR]\n\tif (Ctor === Object) return true\n\n\tif (!isFunction(Ctor)) return false\n\n\tlet ctorString = cachedCtorStrings.get(Ctor)\n\tif (ctorString === undefined) {\n\t\tctorString = Function.toString.call(Ctor)\n\t\tcachedCtorStrings.set(Ctor, ctorString)\n\t}\n\n\treturn ctorString === objectCtorString\n}\n\n/** Get the underlying object that is represented by the given draft */\n/*#__PURE__*/\nexport function original<T>(value: T): T | undefined\nexport function original(value: Drafted<any>): any {\n\tif (!isDraft(value)) die(15, value)\n\treturn value[DRAFT_STATE].base_\n}\n\n/**\n * Each iterates a map, set or array.\n * Or, if any other kind of object, all of its own properties.\n *\n * @param obj The object to iterate over\n * @param iter The iterator function\n * @param strict When true (default), includes symbols and non-enumerable properties.\n * When false, uses looseiteration over only enumerable string properties.\n */\nexport function each<T extends Objectish>(\n\tobj: T,\n\titer: (key: string | number, value: any, source: T) => void,\n\tstrict?: boolean\n): void\nexport function each(obj: any, iter: any, strict: boolean = true) {\n\tif (getArchtype(obj) === ArchType.Object) {\n\t\t// If strict, we do a full iteration including symbols and non-enumerable properties\n\t\t// Otherwise, we only iterate enumerable string properties for performance\n\t\tconst keys = strict ? Reflect.ownKeys(obj) : O.keys(obj)\n\t\tkeys.forEach(key => {\n\t\t\titer(key, obj[key], obj)\n\t\t})\n\t} else {\n\t\tobj.forEach((entry: any, index: any) => iter(index, entry, obj))\n\t}\n}\n\n/*#__PURE__*/\nexport function getArchtype(thing: any): ArchType {\n\tconst state: undefined | ImmerState = thing[DRAFT_STATE]\n\treturn state\n\t\t? state.type_\n\t\t: isArray(thing)\n\t\t? ArchType.Array\n\t\t: isMap(thing)\n\t\t? ArchType.Map\n\t\t: isSet(thing)\n\t\t? ArchType.Set\n\t\t: ArchType.Object\n}\n\n/*#__PURE__*/\nexport let has = (\n\tthing: any,\n\tprop: PropertyKey,\n\ttype = getArchtype(thing)\n): boolean =>\n\ttype === ArchType.Map\n\t\t? thing.has(prop)\n\t\t: O[PROTOTYPE].hasOwnProperty.call(thing, prop)\n\n/*#__PURE__*/\nexport let get = (\n\tthing: AnyMap | AnyObject,\n\tprop: PropertyKey,\n\ttype = getArchtype(thing)\n): any =>\n\t// @ts-ignore\n\ttype === ArchType.Map ? thing.get(prop) : thing[prop]\n\n/*#__PURE__*/\nexport let set = (\n\tthing: any,\n\tpropOrOldValue: PropertyKey,\n\tvalue: any,\n\ttype = getArchtype(thing)\n) => {\n\tif (type === ArchType.Map) thing.set(propOrOldValue, value)\n\telse if (type === ArchType.Set) {\n\t\tthing.add(value)\n\t} else thing[propOrOldValue] = value\n}\n\n/*#__PURE__*/\nexport function is(x: any, y: any): boolean {\n\t// From: https://github.com/facebook/fbjs/blob/c69904a511b900266935168223063dd8772dfc40/packages/fbjs/src/core/shallowEqual.js\n\tif (x === y) {\n\t\treturn x !== 0 || 1 / x === 1 / y\n\t} else {\n\t\treturn x !== x && y !== y\n\t}\n}\n\nexport let isArray = Array.isArray\n\n/*#__PURE__*/\nexport let isMap = (target: any): target is AnyMap => target instanceof Map\n\n/*#__PURE__*/\nexport let isSet = (target: any): target is AnySet => target instanceof Set\n\nexport let isObjectish = (target: any) => typeof target === \"object\"\n\nexport let isFunction = (target: any): target is Function =>\n\ttypeof target === \"function\"\n\nexport let isBoolean = (target: any): target is boolean =>\n\ttypeof target === \"boolean\"\n\nexport let getProxyDraft = <T extends any>(value: T): ImmerState | null => {\n\tif (!isObjectish(value)) return null\n\treturn (value as {[DRAFT_STATE]: any})?.[DRAFT_STATE]\n}\n\n/*#__PURE__*/\nexport let latest = (state: ImmerState): any => state.copy_ || state.base_\n\nexport let getValue = <T extends object>(value: T): T => {\n\tconst proxyDraft = getProxyDraft(value)\n\treturn proxyDraft ? proxyDraft.copy_ ?? proxyDraft.base_ : value\n}\n\nexport let getFinalValue = (state: ImmerState): any =>\n\tstate.modified_ ? state.copy_ : state.base_\n\n/*#__PURE__*/\nexport function shallowCopy(base: any, strict: StrictMode) {\n\tif (isMap(base)) {\n\t\treturn new Map(base)\n\t}\n\tif (isSet(base)) {\n\t\treturn new Set(base)\n\t}\n\tif (isArray(base)) return Array[PROTOTYPE].slice.call(base)\n\n\tconst isPlain = isPlainObject(base)\n\n\tif (strict === true || (strict === \"class_only\" && !isPlain)) {\n\t\t// Perform a strict copy\n\t\tconst descriptors = O.getOwnPropertyDescriptors(base)\n\t\tdelete descriptors[DRAFT_STATE as any]\n\t\tlet keys = Reflect.ownKeys(descriptors)\n\t\tfor (let i = 0; i < keys.length; i++) {\n\t\t\tconst key: any = keys[i]\n\t\t\tconst desc = descriptors[key]\n\t\t\tif (desc[WRITABLE] === false) {\n\t\t\t\tdesc[WRITABLE] = true\n\t\t\t\tdesc[CONFIGURABLE] = true\n\t\t\t}\n\t\t\t// like object.assign, we will read any _own_, get/set accessors. This helps in dealing\n\t\t\t// with libraries that trap values, like mobx or vue\n\t\t\t// unlike object.assign, non-enumerables will be copied as well\n\t\t\tif (desc.get || desc.set)\n\t\t\t\tdescriptors[key] = {\n\t\t\t\t\t[CONFIGURABLE]: true,\n\t\t\t\t\t[WRITABLE]: true, // could live with !!desc.set as well here...\n\t\t\t\t\t[ENUMERABLE]: desc[ENUMERABLE],\n\t\t\t\t\t[VALUE]: base[key]\n\t\t\t\t}\n\t\t}\n\t\treturn O.create(getPrototypeOf(base), descriptors)\n\t} else {\n\t\t// perform a sloppy copy\n\t\tconst proto = getPrototypeOf(base)\n\t\tif (proto !== null && isPlain) {\n\t\t\treturn {...base} // assumption: better inner class optimization than the assign below\n\t\t}\n\t\tconst obj = O.create(proto)\n\t\treturn O.assign(obj, base)\n\t}\n}\n\n/**\n * Freezes draftable objects. Returns the original object.\n * By default freezes shallowly, but if the second argument is `true` it will freeze recursively.\n *\n * @param obj\n * @param deep\n */\nexport function freeze<T>(obj: T, deep?: boolean): T\nexport function freeze<T>(obj: any, deep: boolean = false): T {\n\tif (isFrozen(obj) || isDraft(obj) || !isDraftable(obj)) return obj\n\tif (getArchtype(obj) > 1 /* Map or Set */) {\n\t\tO.defineProperties(obj, {\n\t\t\tset: dontMutateMethodOverride,\n\t\t\tadd: dontMutateMethodOverride,\n\t\t\tclear: dontMutateMethodOverride,\n\t\t\tdelete: dontMutateMethodOverride\n\t\t})\n\t}\n\tO.freeze(obj)\n\tif (deep)\n\t\t// See #590, don't recurse into non-enumerable / Symbol properties when freezing\n\t\t// So use Object.values (only string-like, enumerables) instead of each()\n\t\teach(\n\t\t\tobj,\n\t\t\t(_key, value) => {\n\t\t\t\tfreeze(value, true)\n\t\t\t},\n\t\t\tfalse\n\t\t)\n\treturn obj\n}\n\nfunction dontMutateFrozenCollections() {\n\tdie(2)\n}\n\nconst dontMutateMethodOverride = {\n\t[VALUE]: dontMutateFrozenCollections\n}\n\nexport function isFrozen(obj: any): boolean {\n\t// Fast path: primitives and null/undefined are always \"frozen\"\n\tif (obj === null || !isObjectish(obj)) return true\n\treturn O.isFrozen(obj)\n}\n","import {\n\tImmerState,\n\tPatch,\n\tDrafted,\n\tImmerBaseState,\n\tAnyMap,\n\tAnySet,\n\tArchType,\n\tdie,\n\tImmerScope\n} from \"../internal\"\n\nexport const PluginMapSet = \"MapSet\"\nexport const PluginPatches = \"Patches\"\n\nexport type PatchesPlugin = {\n\tgeneratePatches_(\n\t\tstate: ImmerState,\n\t\tbasePath: PatchPath,\n\t\trootScope: ImmerScope\n\t): void\n\tgenerateReplacementPatches_(\n\t\tbase: any,\n\t\treplacement: any,\n\t\trootScope: ImmerScope\n\t): void\n\tapplyPatches_<T>(draft: T, patches: readonly Patch[]): T\n\tgetPath: (state: ImmerState) => PatchPath | null\n}\n\nexport type MapSetPlugin = {\n\tproxyMap_<T extends AnyMap>(target: T, parent?: ImmerState): [T, ImmerState]\n\tproxySet_<T extends AnySet>(target: T, parent?: ImmerState): [T, ImmerState]\n\tfixSetContents: (state: ImmerState) => void\n}\n\n/** Plugin utilities */\nconst plugins: {\n\tPatches?: PatchesPlugin\n\tMapSet?: MapSetPlugin\n} = {}\n\ntype Plugins = typeof plugins\n\nexport function getPlugin<K extends keyof Plugins>(\n\tpluginKey: K\n): Exclude<Plugins[K], undefined> {\n\tconst plugin = plugins[pluginKey]\n\tif (!plugin) {\n\t\tdie(0, pluginKey)\n\t}\n\t// @ts-ignore\n\treturn plugin\n}\n\nexport let isPluginLoaded = <K extends keyof Plugins>(pluginKey: K): boolean =>\n\t!!plugins[pluginKey]\n\nexport function loadPlugin<K extends keyof Plugins>(\n\tpluginKey: K,\n\timplementation: Plugins[K]\n): void {\n\tif (!plugins[pluginKey]) plugins[pluginKey] = implementation\n}\n/** Map / Set plugin */\n\nexport interface MapState extends ImmerBaseState {\n\ttype_: ArchType.Map\n\tcopy_: AnyMap | undefined\n\tbase_: AnyMap\n\trevoked_: boolean\n\tdraft_: Drafted<AnyMap, MapState>\n}\n\nexport interface SetState extends ImmerBaseState {\n\ttype_: ArchType.Set\n\tcopy_: AnySet | undefined\n\tbase_: AnySet\n\tdrafts_: Map<any, Drafted> // maps the original value to the draft value in the new set\n\trevoked_: boolean\n\tdraft_: Drafted<AnySet, SetState>\n}\n\n/** Patches plugin */\n\nexport type PatchPath = (string | number)[]\n","import {\n\tPatch,\n\tPatchListener,\n\tDrafted,\n\tImmer,\n\tDRAFT_STATE,\n\tImmerState,\n\tArchType,\n\tgetPlugin,\n\tPatchesPlugin,\n\tMapSetPlugin,\n\tisPluginLoaded,\n\tPluginMapSet,\n\tPluginPatches\n} from \"../internal\"\n\n/** Each scope represents a `produce` call. */\n\nexport interface ImmerScope {\n\tpatches_?: Patch[]\n\tinversePatches_?: Patch[]\n\tpatchPlugin_?: PatchesPlugin\n\tmapSetPlugin_?: MapSetPlugin\n\tcanAutoFreeze_: boolean\n\tdrafts_: any[]\n\tparent_?: ImmerScope\n\tpatchListener_?: PatchListener\n\timmer_: Immer\n\tunfinalizedDrafts_: number\n\thandledSet_: Set<any>\n\tprocessedForPatches_: Set<any>\n}\n\nlet currentScope: ImmerScope | undefined\n\nexport let getCurrentScope = () => currentScope!\n\nlet createScope = (\n\tparent_: ImmerScope | undefined,\n\timmer_: Immer\n): ImmerScope => ({\n\tdrafts_: [],\n\tparent_,\n\timmer_,\n\t// Whenever the modified draft contains a draft from another scope, we\n\t// need to prevent auto-freezing so the unowned draft can be finalized.\n\tcanAutoFreeze_: true,\n\tunfinalizedDrafts_: 0,\n\thandledSet_: new Set(),\n\tprocessedForPatches_: new Set(),\n\tmapSetPlugin_: isPluginLoaded(PluginMapSet)\n\t\t? getPlugin(PluginMapSet)\n\t\t: undefined\n})\n\nexport function usePatchesInScope(\n\tscope: ImmerScope,\n\tpatchListener?: PatchListener\n) {\n\tif (patchListener) {\n\t\tscope.patchPlugin_ = getPlugin(PluginPatches) // assert we have the plugin\n\t\tscope.patches_ = []\n\t\tscope.inversePatches_ = []\n\t\tscope.patchListener_ = patchListener\n\t}\n}\n\nexport function revokeScope(scope: ImmerScope) {\n\tleaveScope(scope)\n\tscope.drafts_.forEach(revokeDraft)\n\t// @ts-ignore\n\tscope.drafts_ = null\n}\n\nexport function leaveScope(scope: ImmerScope) {\n\tif (scope === currentScope) {\n\t\tcurrentScope = scope.parent_\n\t}\n}\n\nexport let enterScope = (immer: Immer) =>\n\t(currentScope = createScope(currentScope, immer))\n\nfunction revokeDraft(draft: Drafted) {\n\tconst state: ImmerState = draft[DRAFT_STATE]\n\tif (state.type_ === ArchType.Object || state.type_ === ArchType.Array)\n\t\tstate.revoke_()\n\telse state.revoked_ = true\n}\n","import {\n\tImmerScope,\n\tDRAFT_STATE,\n\tisDraftable,\n\tNOTHING,\n\tPatchPath,\n\teach,\n\tfreeze,\n\tImmerState,\n\tisDraft,\n\tSetState,\n\tset,\n\tArchType,\n\tgetPlugin,\n\tdie,\n\trevokeScope,\n\tisFrozen,\n\tget,\n\tPatch,\n\tlatest,\n\tprepareCopy,\n\tgetFinalValue,\n\tgetValue\n} from \"../internal\"\n\nexport function processResult(result: any, scope: ImmerScope) {\n\tscope.unfinalizedDrafts_ = scope.drafts_.length\n\tconst baseDraft = scope.drafts_![0]\n\tconst isReplaced = result !== undefined && result !== baseDraft\n\n\tif (isReplaced) {\n\t\tif (baseDraft[DRAFT_STATE].modified_) {\n\t\t\trevokeScope(scope)\n\t\t\tdie(4)\n\t\t}\n\t\tif (isDraftable(result)) {\n\t\t\t// Finalize the result in case it contains (or is) a subset of the draft.\n\t\t\tresult = finalize(scope, result)\n\t\t}\n\t\tconst {patchPlugin_} = scope\n\t\tif (patchPlugin_) {\n\t\t\tpatchPlugin_.generateReplacementPatches_(\n\t\t\t\tbaseDraft[DRAFT_STATE].base_,\n\t\t\t\tresult,\n\t\t\t\tscope\n\t\t\t)\n\t\t}\n\t} else {\n\t\t// Finalize the base draft.\n\t\tresult = finalize(scope, baseDraft)\n\t}\n\n\tmaybeFreeze(scope, result, true)\n\n\trevokeScope(scope)\n\tif (scope.patches_) {\n\t\tscope.patchListener_!(scope.patches_, scope.inversePatches_!)\n\t}\n\treturn result !== NOTHING ? result : undefined\n}\n\nfunction finalize(rootScope: ImmerScope, value: any) {\n\t// Don't recurse in tho recursive data structures\n\tif (isFrozen(value)) return value\n\n\tconst state: ImmerState = value[DRAFT_STATE]\n\tif (!state) {\n\t\tconst finalValue = handleValue(value, rootScope.handledSet_, rootScope)\n\t\treturn finalValue\n\t}\n\n\t// Never finalize drafts owned by another scope\n\tif (!isSameScope(state, rootScope)) {\n\t\treturn value\n\t}\n\n\t// Unmodified draft, return the (frozen) original\n\tif (!state.modified_) {\n\t\treturn state.base_\n\t}\n\n\tif (!state.finalized_) {\n\t\t// Execute all registered draft finalization callbacks\n\t\tconst {callbacks_} = state\n\t\tif (callbacks_) {\n\t\t\twhile (callbacks_.length > 0) {\n\t\t\t\tconst callback = callbacks_.pop()!\n\t\t\t\tcallback(rootScope)\n\t\t\t}\n\t\t}\n\n\t\tgeneratePatchesAndFinalize(state, rootScope)\n\t}\n\n\t// By now the root copy has been fully updated throughout its tree\n\treturn state.copy_\n}\n\nfunction maybeFreeze(scope: ImmerScope, value: any, deep = false) {\n\t// we never freeze for a non-root scope; as it would prevent pruning for drafts inside wrapping objects\n\tif (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {\n\t\tfreeze(value, deep)\n\t}\n}\n\nfunction markStateFinalized(state: ImmerState) {\n\tstate.finalized_ = true\n\tstate.scope_.unfinalizedDrafts_--\n}\n\nlet isSameScope = (state: ImmerState, rootScope: ImmerScope) =>\n\tstate.scope_ === rootScope\n\n// A reusable empty array to avoid allocations\nconst EMPTY_LOCATIONS_RESULT: (string | symbol | number)[] = []\n\n// Updates all references to a draft in its parent to the finalized value.\n// This handles cases where the same draft appears multiple times in the parent, or has been moved around.\nexport function updateDraftInParent(\n\tparent: ImmerState,\n\tdraftValue: any,\n\tfinalizedValue: any,\n\toriginalKey?: string | number | symbol\n): void {\n\tconst parentCopy = latest(parent)\n\tconst parentType = parent.type_\n\n\t// Fast path: Check if draft is still at original key\n\tif (originalKey !== undefined) {\n\t\tconst currentValue = get(parentCopy, originalKey, parentType)\n\t\tif (currentValue === draftValue) {\n\t\t\t// Still at original location, just update it\n\t\t\tset(parentCopy, originalKey, finalizedValue, parentType)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Slow path: Build reverse mapping of all children\n\t// to their indices in the parent, so that we can\n\t// replace all locations where this draft appears.\n\t// We only have to build this once per parent.\n\tif (!parent.draftLocations_) {\n\t\tconst draftLocations = (parent.draftLocations_ = new Map())\n\n\t\t// Use `each` which works on Arrays, Maps, and Objects\n\t\teach(parentCopy, (key, value) => {\n\t\t\tif (isDraft(value)) {\n\t\t\t\tconst keys = draftLocations.get(value) || []\n\t\t\t\tkeys.push(key)\n\t\t\t\tdraftLocations.set(value, keys)\n\t\t\t}\n\t\t})\n\t}\n\n\t// Look up all locations where this draft appears\n\tconst locations =\n\t\tparent.draftLocations_.get(draftValue) ?? EMPTY_LOCATIONS_RESULT\n\n\t// Update all locations\n\tfor (const location of locations) {\n\t\tset(parentCopy, location, finalizedValue, parentType)\n\t}\n}\n\n// Register a callback to finalize a child draft when the parent draft is finalized.\n// This assumes there is a parent -> child relationship between the two drafts,\n// and we have a key to locate the child in the parent.\nexport function registerChildFinalizationCallback(\n\tparent: ImmerState,\n\tchild: ImmerState,\n\tkey: string | number | symbol\n) {\n\tparent.callbacks_.push(function childCleanup(rootScope) {\n\t\tconst state: ImmerState = child\n\n\t\t// Can only continue if this is a draft owned by this scope\n\t\tif (!state || !isSameScope(state, rootScope)) {\n\t\t\treturn\n\t\t}\n\n\t\t// Handle potential set value finalization first\n\t\trootScope.mapSetPlugin_?.fixSetContents(state)\n\n\t\tconst finalizedValue = getFinalValue(state)\n\n\t\t// Update all locations in the parent that referenced this draft\n\t\tupdateDraftInParent(parent, state.draft_ ?? state, finalizedValue, key)\n\n\t\tgeneratePatchesAndFinalize(state, rootScope)\n\t})\n}\n\nfunction generatePatchesAndFinalize(state: ImmerState, rootScope: ImmerScope) {\n\tconst shouldFinalize =\n\t\tstate.modified_ &&\n\t\t!state.finalized_ &&\n\t\t(state.type_ === ArchType.Set || (state.assigned_?.size ?? 0) > 0)\n\n\tif (shouldFinalize) {\n\t\tconst {patchPlugin_} = rootScope\n\t\tif (patchPlugin_) {\n\t\t\tconst basePath = patchPlugin_!.getPath(state)\n\n\t\t\tif (basePath) {\n\t\t\t\tpatchPlugin_!.generatePatches_(state, basePath, rootScope)\n\t\t\t}\n\t\t}\n\n\t\tmarkStateFinalized(state)\n\t}\n}\n\nexport function handleCrossReference(\n\ttarget: ImmerState,\n\tkey: string | number | symbol,\n\tvalue: any\n) {\n\tconst {scope_} = target\n\t// Check if value is a draft from this scope\n\tif (isDraft(value)) {\n\t\tconst state: ImmerState = value[DRAFT_STATE]\n\t\tif (isSameScope(state, scope_)) {\n\t\t\t// Register callback to update this location when the draft finalizes\n\n\t\t\tstate.callbacks_.push(function crossReferenceCleanup() {\n\t\t\t\t// Update the target location with finalized value\n\t\t\t\tprepareCopy(target)\n\n\t\t\t\tconst finalizedValue = getFinalValue(state)\n\n\t\t\t\tupdateDraftInParent(target, value, finalizedValue, key)\n\t\t\t})\n\t\t}\n\t} else if (isDraftable(value)) {\n\t\t// Handle non-draft objects that might contain drafts\n\t\ttarget.callbacks_.push(function nestedDraftCleanup() {\n\t\t\tconst targetCopy = latest(target)\n\n\t\t\tif (get(targetCopy, key, target.type_) === value) {\n\t\t\t\t// Process the value to replace any nested drafts\n\t\t\t\t// finalizeAssigned(target, key, target.scope_)\n\n\t\t\t\tif (\n\t\t\t\t\tscope_.drafts_.length > 1 &&\n\t\t\t\t\t((target as Exclude<ImmerState, SetState>).assigned_!.get(key) ??\n\t\t\t\t\t\tfalse) === true &&\n\t\t\t\t\ttarget.copy_\n\t\t\t\t) {\n\t\t\t\t\t// This might be a non-draft value that has drafts\n\t\t\t\t\t// inside. We do need to recurse here to handle those.\n\t\t\t\t\thandleValue(\n\t\t\t\t\t\tget(target.copy_, key, target.type_),\n\t\t\t\t\t\tscope_.handledSet_,\n\t\t\t\t\t\tscope_\n\t\t\t\t\t)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n}\n\nexport function handleValue(\n\ttarget: any,\n\thandledSet: Set<any>,\n\trootScope: ImmerScope\n) {\n\tif (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) {\n\t\t// optimization: if an object is not a draft, and we don't have to\n\t\t// deepfreeze everything, and we are sure that no drafts are left in the remaining object\n\t\t// cause we saw and finalized all drafts already; we can stop visiting the rest of the tree.\n\t\t// This benefits especially adding large data tree's without further processing.\n\t\t// See add-data.js perf test\n\t\treturn target\n\t}\n\n\t// Skip if already handled, frozen, or not draftable\n\tif (\n\t\tisDraft(target) ||\n\t\thandledSet.has(target) ||\n\t\t!isDraftable(target) ||\n\t\tisFrozen(target)\n\t) {\n\t\treturn target\n\t}\n\n\thandledSet.add(target)\n\n\t// Process ALL properties/entries\n\teach(target, (key, value) => {\n\t\tif (isDraft(value)) {\n\t\t\tconst state: ImmerState = value[DRAFT_STATE]\n\t\t\tif (isSameScope(state, rootScope)) {\n\t\t\t\t// Replace draft with finalized value\n\n\t\t\t\tconst updatedValue = getFinalValue(state)\n\n\t\t\t\tset(target, key, updatedValue, target.type_)\n\n\t\t\t\tmarkStateFinalized(state)\n\t\t\t}\n\t\t} else if (isDraftable(value)) {\n\t\t\t// Recursively handle nested values\n\t\t\thandleValue(value, handledSet, rootScope)\n\t\t}\n\t})\n\n\treturn target\n}\n","import {\n\teach,\n\thas,\n\tis,\n\tisDraftable,\n\tshallowCopy,\n\tlatest,\n\tImmerBaseState,\n\tImmerState,\n\tDrafted,\n\tAnyObject,\n\tAnyArray,\n\tObjectish,\n\tgetCurrentScope,\n\tgetPrototypeOf,\n\tDRAFT_STATE,\n\tdie,\n\tcreateProxy,\n\tArchType,\n\tImmerScope,\n\thandleCrossReference,\n\tWRITABLE,\n\tCONFIGURABLE,\n\tENUMERABLE,\n\tVALUE,\n\tisArray\n} from \"../internal\"\n\ninterface ProxyBaseState extends ImmerBaseState {\n\tparent_?: ImmerState\n\trevoke_(): void\n}\n\nexport interface ProxyObjectState extends ProxyBaseState {\n\ttype_: ArchType.Object\n\tbase_: any\n\tcopy_: any\n\tdraft_: Drafted<AnyObject, ProxyObjectState>\n}\n\nexport interface ProxyArrayState extends ProxyBaseState {\n\ttype_: ArchType.Array\n\tbase_: AnyArray\n\tcopy_: AnyArray | null\n\tdraft_: Drafted<AnyArray, ProxyArrayState>\n}\n\ntype ProxyState = ProxyObjectState | ProxyArrayState\n\n/**\n * Returns a new draft of the `base` object.\n *\n * The second argument is the parent draft-state (used internally).\n */\nexport function createProxyProxy<T extends Objectish>(\n\tbase: T,\n\tparent?: ImmerState\n): [Drafted<T, ProxyState>, ProxyState] {\n\tconst baseIsArray = isArray(base)\n\tconst state: ProxyState = {\n\t\ttype_: baseIsArray ? ArchType.Array : (ArchType.Object as any),\n\t\t// Track which produce call this is associated with.\n\t\tscope_: parent ? parent.scope_ : getCurrentScope()!,\n\t\t// True for both shallow and deep changes.\n\t\tmodified_: false,\n\t\t// Used during finalization.\n\t\tfinalized_: false,\n\t\t// Track which properties have been assigned (true) or deleted (false).\n\t\t// actually instantiated in `prepareCopy()`\n\t\tassigned_: undefined,\n\t\t// The parent draft state.\n\t\tparent_: parent,\n\t\t// The base state.\n\t\tbase_: base,\n\t\t// The base proxy.\n\t\tdraft_: null as any, // set below\n\t\t// The base copy with any updated values.\n\t\tcopy_: null,\n\t\t// Called by the `produce` function.\n\t\trevoke_: null as any,\n\t\tisManual_: false,\n\t\t// `callbacks` actually gets assigned in `createProxy`\n\t\tcallbacks_: undefined as any\n\t}\n\n\t// the traps must target something, a bit like the 'real' base.\n\t// but also, we need to be able to determine from the target what the relevant state is\n\t// (to avoid creating traps per instance to capture the state in closure,\n\t// and to avoid creating weird hidden properties as well)\n\t// So the trick is to use 'state' as the actual 'target'! (and make sure we intercept everything)\n\t// Note that in the case of an array, we put the state in an array to have better Reflect defaults ootb\n\tlet target: T = state as any\n\tlet traps: ProxyHandler<object | Array<any>> = objectTraps\n\tif (baseIsArray) {\n\t\ttarget = [state] as any\n\t\ttraps = arrayTraps\n\t}\n\n\tconst {revoke, proxy} = Proxy.revocable(target, traps)\n\tstate.draft_ = proxy as any\n\tstate.revoke_ = revoke\n\treturn [proxy as any, state]\n}\n\n/**\n * Object drafts\n */\nexport const objectTraps: ProxyHandler<ProxyState> = {\n\tget(state, prop) {\n\t\tif (prop === DRAFT_STATE) return state\n\n\t\tconst source = latest(state)\n\t\tif (!has(source, prop, state.type_)) {\n\t\t\t// non-existing or non-own property...\n\t\t\treturn readPropFromProto(state, source, prop)\n\t\t}\n\t\tconst value = source[prop]\n\t\tif (state.finalized_ || !isDraftable(value)) {\n\t\t\treturn value\n\t\t}\n\t\t// Check for existing draft in modified state.\n\t\t// Assigned values are never drafted. This catches any drafts we created, too.\n\t\tif (value === peek(state.base_, prop)) {\n\t\t\tprepareCopy(state)\n\t\t\t// Ensure array keys are always numbers\n\t\t\tconst childKey = state.type_ === ArchType.Array ? +(prop as string) : prop\n\t\t\tconst childDraft = createProxy(state.scope_, value, state, childKey)\n\n\t\t\treturn (state.copy_![childKey] = childDraft)\n\t\t}\n\t\treturn value\n\t},\n\thas(state, prop) {\n\t\treturn prop in latest(state)\n\t},\n\townKeys(state) {\n\t\treturn Reflect.ownKeys(latest(state))\n\t},\n\tset(\n\t\tstate: ProxyObjectState,\n\t\tprop: string /* strictly not, but helps TS */,\n\t\tvalue\n\t) {\n\t\tconst desc = getDescriptorFromProto(latest(state), prop)\n\t\tif (desc?.set) {\n\t\t\t// special case: if this write is captured by a setter, we have\n\t\t\t// to trigger it with the correct context\n\t\t\tdesc.set.call(state.draft_, value)\n\t\t\treturn true\n\t\t}\n\t\tif (!state.modified_) {\n\t\t\t// the last check is because we need to be able to distinguish setting a non-existing to undefined (which is a change)\n\t\t\t// from setting an existing property with value undefined to undefined (which is not a change)\n\t\t\tconst current = peek(latest(state), prop)\n\t\t\t// special case, if we assigning the original value to a draft, we can ignore the assignment\n\t\t\tconst currentState: ProxyObjectState = current?.[DRAFT_STATE]\n\t\t\tif (currentState && currentState.base_ === value) {\n\t\t\t\tstate.copy_![prop] = value\n\t\t\t\tstate.assigned_!.set(prop, false)\n\t\t\t\treturn true\n\t\t\t}\n\t\t\tif (\n\t\t\t\tis(value, current) &&\n\t\t\t\t(value !== undefined || has(state.base_, prop, state.type_))\n\t\t\t)\n\t\t\t\treturn true\n\t\t\tprepareCopy(state)\n\t\t\tmarkChanged(state)\n\t\t}\n\n\t\tif (\n\t\t\t(state.copy_![prop] === value &&\n\t\t\t\t// special case: handle new props with value 'undefined'\n\t\t\t\t(value !== undefined || prop in state.copy_)) ||\n\t\t\t// special case: NaN\n\t\t\t(Number.isNaN(value) && Number.isNaN(state.copy_![prop]))\n\t\t)\n\t\t\treturn true\n\n\t\t// @ts-ignore\n\t\tstate.copy_![prop] = value\n\t\tstate.assigned_!.set(prop, true)\n\n\t\thandleCrossReference(state, prop, value)\n\t\treturn true\n\t},\n\tdeleteProperty(state, prop: string) {\n\t\tprepareCopy(state)\n\t\t// The `undefined` check is a fast path for pre-existing keys.\n\t\tif (peek(state.base_, prop) !== undefined || prop in state.base_) {\n\t\t\tstate.assigned_!.set(prop, false)\n\t\t\tmarkChanged(state)\n\t\t} else {\n\t\t\t// if an originally not assigned property was deleted\n\t\t\tstate.assigned_!.delete(prop)\n\t\t}\n\t\tif (state.copy_) {\n\t\t\tdelete state.copy_[prop]\n\t\t}\n\t\treturn true\n\t},\n\t// Note: We never coerce `desc.value` into an Immer draft, because we can't make\n\t// the same guarantee in ES5 mode.\n\tgetOwnPropertyDescriptor(state, prop) {\n\t\tconst owner = latest(state)\n\t\tconst desc = Reflect.getOwnPropertyDescriptor(owner, prop)\n\t\tif (!desc) return desc\n\t\treturn {\n\t\t\t[WRITABLE]: true,\n\t\t\t[CONFIGURABLE]: state.type_ !== ArchType.Array || prop !== \"length\",\n\t\t\t[ENUMERABLE]: desc[ENUMERABLE],\n\t\t\t[VALUE]: owner[prop]\n\t\t}\n\t},\n\tdefineProperty() {\n\t\tdie(11)\n\t},\n\tgetPrototypeOf(state) {\n\t\treturn getPrototypeOf(state.base_)\n\t},\n\tsetPrototypeOf() {\n\t\tdie(12)\n\t}\n}\n\n/**\n * Array drafts\n */\n\nconst arrayTraps: ProxyHandler<[ProxyArrayState]> = {}\neach(objectTraps, (key, fn) => {\n\t// @ts-ignore\n\tarrayTraps[key] = function() {\n\t\tconst args = arguments\n\t\targs[0] = args[0][0]\n\t\treturn fn.apply(this, args)\n\t}\n})\narrayTraps.deleteProperty = function(state, prop) {\n\tif (process.env.NODE_ENV !== \"production\" && isNaN(parseInt(prop as any)))\n\t\tdie(13)\n\t// @ts-ignore\n\treturn arrayTraps.set!.call(this, state, prop, undefined)\n}\narrayTraps.set = function(state, prop, value) {\n\tif (\n\t\tprocess.env.NODE_ENV !== \"production\" &&\n\t\tprop !== \"length\" &&\n\t\tisNaN(parseInt(prop as any))\n\t)\n\t\tdie(14)\n\treturn objectTraps.set!.call(this, state[0], prop, value, state[0])\n}\n\n// Access a property without creating an Immer draft.\nfunction peek(draft: Drafted, prop: PropertyKey) {\n\tconst state = draft[DRAFT_STATE]\n\tconst source = state ? latest(state) : draft\n\treturn source[prop]\n}\n\nfunction readPropFromProto(state: ImmerState, source: any, prop: PropertyKey) {\n\tconst desc = getDescriptorFromProto(source, prop)\n\treturn desc\n\t\t? VALUE in desc\n\t\t\t? desc[VALUE]\n\t\t\t: // This is a very special case, if the prop is a getter defined by the\n\t\t\t // prototype, we should invoke it with the draft as context!\n\t\t\t desc.get?.call(state.draft_)\n\t\t: undefined\n}\n\nfunction getDescriptorFromProto(\n\tsource: any,\n\tprop: PropertyKey\n): PropertyDescriptor | undefined {\n\t// 'in' checks proto!\n\tif (!(prop in source)) return undefined\n\tlet proto = getPrototypeOf(source)\n\twhile (proto) {\n\t\tconst desc = Object.getOwnPropertyDescriptor(proto, prop)\n\t\tif (desc) return desc\n\t\tproto = getPrototypeOf(proto)\n\t}\n\treturn undefined\n}\n\nexport function markChanged(state: ImmerState) {\n\tif (!state.modified_) {\n\t\tstate.modified_ = true\n\t\tif (state.parent_) {\n\t\t\tmarkChanged(state.parent_)\n\t\t}\n\t}\n}\n\nexport function prepareCopy(state: ImmerState) {\n\tif (!state.copy_) {\n\t\t// Actually create the `assigned_` map now that we\n\t\t// know this is a modified draft.\n\t\tstate.assigned_ = new Map()\n\t\tstate.copy_ = shallowCopy(\n\t\t\tstate.base_,\n\t\t\tstate.scope_.immer_.useStrictShallowCopy_\n\t\t)\n\t}\n}\n","import {\n\tIProduceWithPatches,\n\tIProduce,\n\tImmerState,\n\tDrafted,\n\tisDraftable,\n\tprocessResult,\n\tPatch,\n\tObjectish,\n\tDRAFT_STATE,\n\tDraft,\n\tPatchListener,\n\tisDraft,\n\tisMap,\n\tisSet,\n\tcreateProxyProxy,\n\tgetPlugin,\n\tdie,\n\tenterScope,\n\trevokeScope,\n\tleaveScope,\n\tusePatchesInScope,\n\tgetCurrentScope,\n\tNOTHING,\n\tfreeze,\n\tcurrent,\n\tImmerScope,\n\tregisterChildFinalizationCallback,\n\tArchType,\n\tMapSetPlugin,\n\tAnyMap,\n\tAnySet,\n\tisObjectish,\n\tisFunction,\n\tisBoolean,\n\tPluginMapSet,\n\tPluginPatches\n} from \"../internal\"\n\ninterface ProducersFns {\n\tproduce: IProduce\n\tproduceWithPatches: IProduceWithPatches\n}\n\nexport type StrictMode = boolean | \"class_only\"\n\nexport class Immer implements ProducersFns {\n\tautoFreeze_: boolean = true\n\tuseStrictShallowCopy_: StrictMode = false\n\tuseStrictIteration_: boolean = false\n\n\tconstructor(config?: {\n\t\tautoFreeze?: boolean\n\t\tuseStrictShallowCopy?: StrictMode\n\t\tuseStrictIteration?: boolean\n\t}) {\n\t\tif (isBoolean(config?.autoFreeze)) this.setAutoFreeze(config!.autoFreeze)\n\t\tif (isBoolean(config?.useStrictShallowCopy))\n\t\t\tthis.setUseStrictShallowCopy(config!.useStrictShallowCopy)\n\t\tif (isBoolean(config?.useStrictIteration))\n\t\t\tthis.setUseStrictIteration(config!.useStrictIteration)\n\t}\n\n\t/**\n\t * The `produce` function takes a value and a \"recipe function\" (whose\n\t * return value often depends on the base state). The recipe function is\n\t * free to mutate its first argument however it wants. All mutations are\n\t * only ever applied to a __copy__ of the base state.\n\t *\n\t * Pass only a function to create a \"curried producer\" which relieves you\n\t * from passing the recipe function every time.\n\t *\n\t * Only plain objects and arrays are made mutable. All other objects are\n\t * considered uncopyable.\n\t *\n\t * Note: This function is __bound__ to its `Immer` instance.\n\t *\n\t * @param {any} base - the initial state\n\t * @param {Function} recipe - function that receives a proxy of the base state as first argument and which can be freely modified\n\t * @param {Function} patchListener - optional function that will be called with all the patches produced here\n\t * @returns {any} a new state, or the initial state if nothing was modified\n\t */\n\tproduce: IProduce = (base: any, recipe?: any, patchListener?: any) => {\n\t\t// curried invocation\n\t\tif (isFunction(base) && !isFunction(recipe)) {\n\t\t\tconst defaultBase = recipe\n\t\t\trecipe = base\n\n\t\t\tconst self = this\n\t\t\treturn function curriedProduce(\n\t\t\t\tthis: any,\n\t\t\t\tbase = defaultBase,\n\t\t\t\t...args: any[]\n\t\t\t) {\n\t\t\t\treturn self.produce(base, (draft: Drafted) => recipe.call(this, draft, ...args)) // prettier-ignore\n\t\t\t}\n\t\t}\n\n\t\tif (!isFunction(recipe)) die(6)\n\t\tif (patchListener !== undefined && !isFunction(patchListener)) die(7)\n\n\t\tlet result\n\n\t\t// Only plain objects, arrays, and \"immerable classes\" are drafted.\n\t\tif (isDraftable(base)) {\n\t\t\tconst scope = enterScope(this)\n\t\t\tconst proxy = createProxy(scope, base, undefined)\n\t\t\tlet hasError = true\n\t\t\ttry {\n\t\t\t\tresult = recipe(proxy)\n\t\t\t\thasError = false\n\t\t\t} finally {\n\t\t\t\t// finally instead of catch + rethrow better preserves original stack\n\t\t\t\tif (hasError) revokeScope(scope)\n\t\t\t\telse leaveScope(scope)\n\t\t\t}\n\t\t\tusePatchesInScope(scope, patchListener)\n\t\t\treturn processResult(result, scope)\n\t\t} else if (!base || !isObjectish(base)) {\n\t\t\tresult = recipe(base)\n\t\t\tif (result === undefined) result = base\n\t\t\tif (result === NOTHING) result = undefined\n\t\t\tif (this.autoFreeze_) freeze(result, true)\n\t\t\tif (patchListener) {\n\t\t\t\tconst p: Patch[] = []\n\t\t\t\tconst ip: Patch[] = []\n\t\t\t\tgetPlugin(PluginPatches).generateReplacementPatches_(base, result, {\n\t\t\t\t\tpatches_: p,\n\t\t\t\t\tinversePatches_: ip\n\t\t\t\t} as ImmerScope) // dummy scope\n\t\t\t\tpatchListener(p, ip)\n\t\t\t}\n\t\t\treturn result\n\t\t} else die(1, base)\n\t}\n\n\tproduceWithPatches: IProduceWithPatches = (base: any, recipe?: any): any => {\n\t\t// curried invocation\n\t\tif (isFunction(base)) {\n\t\t\treturn (state: any, ...args: any[]) =>\n\t\t\t\tthis.produceWithPatches(state, (draft: any) => base(draft, ...args))\n\t\t}\n\n\t\tlet patches: Patch[], inversePatches: Patch[]\n\t\tconst result = this.produce(base, recipe, (p: Patch[], ip: Patch[]) => {\n\t\t\tpatches = p\n\t\t\tinversePatches = ip\n\t\t})\n\t\treturn [result, patches!, inversePatches!]\n\t}\n\n\tcreateDraft<T extends Objectish>(base: T): Draft<T> {\n\t\tif (!isDraftable(base)) die(8)\n\t\tif (isDraft(base)) base = current(base)\n\t\tconst scope = enterScope(this)\n\t\tconst proxy = createProxy(scope, base, undefined)\n\t\tproxy[DRAFT_STATE].isManual_ = true\n\t\tleaveScope(scope)\n\t\treturn proxy as any\n\t}\n\n\tfinishDraft<D extends Draft<any>>(\n\t\tdraft: D,\n\t\tpatchListener?: PatchListener\n\t): D extends Draft<infer T> ? T : never {\n\t\tconst state: ImmerState = draft && (draft as any)[DRAFT_STATE]\n\t\tif (!state || !state.isManual_) die(9)\n\t\tconst {scope_: scope} = state\n\t\tusePatchesInScope(scope, patchListener)\n\t\treturn processResult(undefined, scope)\n\t}\n\n\t/**\n\t * Pass true to automatically freeze all copies created by Immer.\n\t *\n\t * By default, auto-freezing is enabled.\n\t */\n\tsetAutoFreeze(value: boolean) {\n\t\tthis.autoFreeze_ = value\n\t}\n\n\t/**\n\t * Pass true to enable strict shallow copy.\n\t *\n\t * By default, immer does not copy the object descriptors such as getter, setter and non-enumrable properties.\n\t */\n\tsetUseStrictShallowCopy(value: StrictMode) {\n\t\tthis.useStrictShallowCopy_ = value\n\t}\n\n\t/**\n\t * Pass false to use faster iteration that skips non-enumerable properties\n\t * but still handles symbols for compatibility.\n\t *\n\t * By default, strict iteration is enabled (includes all own properties).\n\t */\n\tsetUseStrictIteration(value: boolean) {\n\t\tthis.useStrictIteration_ = value\n\t}\n\n\tshouldUseStrictIteration(): boolean {\n\t\treturn this.useStrictIteration_\n\t}\n\n\tapplyPatches<T extends Objectish>(base: T, patches: readonly Patch[]): T {\n\t\t// If a patch replaces the entire state, take that replacement as base\n\t\t// before applying patches\n\t\tlet i: number\n\t\tfor (i = patches.length - 1; i >= 0; i--) {\n\t\t\tconst patch = patches[i]\n\t\t\tif (patch.path.length === 0 && patch.op === \"replace\") {\n\t\t\t\tbase = patch.value\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\t// If there was a patch that replaced the entire state, start from the\n\t\t// patch after that.\n\t\tif (i > -1) {\n\t\t\tpatches = patches.slice(i + 1)\n\t\t}\n\n\t\tconst applyPatchesImpl = getPlugin(PluginPatches).applyPatches_\n\t\tif (isDraft(base)) {\n\t\t\t// N.B: never hits if some patch a replacement, patches are never drafts\n\t\t\treturn applyPatchesImpl(base, patches)\n\t\t}\n\t\t// Otherwise, produce a copy of the base state.\n\t\treturn this.produce(base, (draft: Drafted) =>\n\t\t\tapplyPatchesImpl(draft, patches)\n\t\t)\n\t}\n}\n\nexport function createProxy<T extends Objectish>(\n\trootScope: ImmerScope,\n\tvalue: T,\n\tparent?: ImmerState,\n\tkey?: string | number | symbol\n): Drafted<T, ImmerState> {\n\t// precondition: createProxy should be guarded by isDraftable, so we know we can safely draft\n\t// returning a tuple here lets us skip a proxy access\n\t// to DRAFT_STATE later\n\tconst [draft, state] = isMap(value)\n\t\t? getPlugin(PluginMapSet).proxyMap_(value, parent)\n\t\t: isSet(value)\n\t\t? getPlugin(PluginMapSet).proxySet_(value, parent)\n\t\t: createProxyProxy(value, parent)\n\n\tconst scope = parent?.scope_ ?? getCurrentScope()\n\tscope.drafts_.push(draft)\n\n\t// Ensure the parent callbacks are passed down so we actually\n\t// track all callbacks added throughout the tree\n\tstate.callbacks_ = parent?.callbacks_ ?? []\n\tstate.key_ = key\n\n\tif (parent && key !== undefined) {\n\t\tregisterChildFinalizationCallback(parent, state, key)\n\t} else {\n\t\t// It's a root draft, register it with the scope\n\t\tstate.callbacks_.push(function rootDraftCleanup(rootScope) {\n\t\t\trootScope.mapSetPlugin_?.fixSetContents(state)\n\n\t\t\tconst {patchPlugin_} = rootScope\n\n\t\t\tif (state.modified_ && patchPlugin_) {\n\t\t\t\tpatchPlugin_.generatePatches_(state, [], rootScope)\n\t\t\t}\n\t\t})\n\t}\n\n\treturn draft as any\n}\n","import {\n\tdie,\n\tisDraft,\n\tshallowCopy,\n\teach,\n\tDRAFT_STATE,\n\tset,\n\tImmerState,\n\tisDraftable,\n\tisFrozen\n} from \"../internal\"\n\n/** 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. */\nexport function current<T>(value: T): T\nexport function current(value: any): any {\n\tif (!isDraft(value)) die(10, value)\n\treturn currentImpl(value)\n}\n\nfunction currentImpl(value: any): any {\n\tif (!isDraftable(value) || isFrozen(value)) return value\n\tconst state: ImmerState | undefined = value[DRAFT_STATE]\n\tlet copy: any\n\tlet strict = true // Default to strict for compatibility\n\tif (state) {\n\t\tif (!state.modified_) return state.base_\n\t\t// Optimization: avoid generating new drafts during copying\n\t\tstate.finalized_ = true\n\t\tcopy = shallowCopy(value, state.scope_.immer_.useStrictShallowCopy_)\n\t\tstrict = state.scope_.immer_.shouldUseStrictIteration()\n\t} else {\n\t\tcopy = shallowCopy(value, true)\n\t}\n\t// recurse\n\teach(\n\t\tcopy,\n\t\t(key, childValue) => {\n\t\t\tset(copy, key, currentImpl(childValue))\n\t\t},\n\t\tstrict\n\t)\n\tif (state) {\n\t\tstate.finalized_ = false\n\t}\n\treturn copy\n}\n","import {immerable} from \"../immer\"\nimport {\n\tImmerState,\n\tPatch,\n\tSetState,\n\tProxyArrayState,\n\tMapState,\n\tProxyObjectState,\n\tPatchPath,\n\tget,\n\teach,\n\thas,\n\tgetArchtype,\n\tgetPrototypeOf,\n\tisSet,\n\tisMap,\n\tloadPlugin,\n\tArchType,\n\tdie,\n\tisDraft,\n\tisDraftable,\n\tNOTHING,\n\terrors,\n\tDRAFT_STATE,\n\tgetProxyDraft,\n\tImmerScope,\n\tisObjectish,\n\tisFunction,\n\tCONSTRUCTOR,\n\tPluginPatches,\n\tisArray,\n\tPROTOTYPE\n} from \"../internal\"\n\nexport function enablePatches() {\n\tconst errorOffset = 16\n\tif (process.env.NODE_ENV !== \"production\") {\n\t\terrors.push(\n\t\t\t'Sets cannot have \"replace\" patches.',\n\t\t\tfunction(op: string) {\n\t\t\t\treturn \"Unsupported patch operation: \" + op\n\t\t\t},\n\t\t\tfunction(path: string) {\n\t\t\t\treturn \"Cannot apply patch, path doesn't resolve: \" + path\n\t\t\t},\n\t\t\t\"Patching reserved attributes like __proto__, prototype and constructor is not allowed\"\n\t\t)\n\t}\n\n\tfunction getPath(state: ImmerState, path: PatchPath = []): PatchPath | null {\n\t\t// Step 1: Check if state has a stored key\n\t\tif (\"key_\" in state && state.key_ !== undefined) {\n\t\t\t// Step 2: Validate the key is still valid in parent\n\n\t\t\tconst parentCopy = state.parent_!.copy_ ?? state.parent_!.base_\n\t\t\tconst proxyDraft = getProxyDraft(get(parentCopy, state.key_!))\n\t\t\tconst valueAtKey = get(parentCopy, state.key_!)\n\n\t\t\tif (valueAtKey === undefined) {\n\t\t\t\treturn null\n\t\t\t}\n\n\t\t\t// Check if the value at the key is still related to this draft\n\t\t\t// It should be either the draft itself, the base, or the copy\n\t\t\tif (\n\t\t\t\tvalueAtKey !== state.draft_ &&\n\t\t\t\tvalueAtKey !== state.base_ &&\n\t\t\t\tvalueAtKey !== state.copy_\n\t\t\t) {\n\t\t\t\treturn null // Value was replaced with something else\n\t\t\t}\n\t\t\tif (proxyDraft != null && proxyDraft.base_ !== state.base_) {\n\t\t\t\treturn null // Different draft\n\t\t\t}\n\n\t\t\t// Step 3: Handle Set case specially\n\t\t\tconst isSet = state.parent_!.type_ === ArchType.Set\n\t\t\tlet key: string | number\n\n\t\t\tif (isSet) {\n\t\t\t\t// For Sets, find the index in the drafts_ map\n\t\t\t\tconst setParent = state.parent_ as SetState\n\t\t\t\tkey = Array.from(setParent.drafts_.keys()).indexOf(state.key_)\n\t\t\t} else {\n\t\t\t\tkey = state.key_ as string | number\n\t\t\t}\n\n\t\t\t// Step 4: Validate key still exists in parent\n\t\t\tif (!((isSet && parentCopy.size > key) || has(parentCopy, key))) {\n\t\t\t\treturn null // Key deleted\n\t\t\t}\n\n\t\t\t// Step 5: Add key to path\n\t\t\tpath.push(key)\n\t\t}\n\n\t\t// Step 6: Recurse to parent if exists\n\t\tif (state.parent_) {\n\t\t\treturn getPath(state.parent_, path)\n\t\t}\n\n\t\t// Step 7: At root - reverse path and validate\n\t\tpath.reverse()\n\n\t\ttry {\n\t\t\t// Validate path can be resolved from ROOT\n\t\t\tresolvePath(state.copy_, path)\n\t\t} catch (e) {\n\t\t\treturn null // Path invalid\n\t\t}\n\n\t\treturn path\n\t}\n\n\t// NEW: Add resolvePath helper function\n\tfunction resolvePath(base: any, path: PatchPath): any {\n\t\tlet current = base\n\t\tfor (let i = 0; i < path.length - 1; i++) {\n\t\t\tconst key = path[i]\n\t\t\tcurrent = get(current, key)\n\t\t\tif (!isObjectish(current) || current === null) {\n\t\t\t\tthrow new Error(`Cannot resolve path at '${path.join(\"/\")}'`)\n\t\t\t}\n\t\t}\n\t\treturn current\n\t}\n\n\tconst REPLACE = \"replace\"\n\tconst ADD = \"add\"\n\tconst REMOVE = \"remove\"\n\n\tfunction generatePatches_(\n\t\tstate: ImmerState,\n\t\tbasePath: PatchPath,\n\t\tscope: ImmerScope\n\t): void {\n\t\tif (state.scope_.processedForPatches_.has(state)) {\n\t\t\treturn\n\t\t}\n\n\t\tstate.scope_.processedForPatches_.add(state)\n\n\t\tconst {patches_, inversePatches_} = scope\n\n\t\tswitch (state.type_) {\n\t\t\tcase ArchType.Object:\n\t\t\tcase ArchType.Map:\n\t\t\t\treturn generatePatchesFromAssigned(\n\t\t\t\t\tstate,\n\t\t\t\t\tbasePath,\n\t\t\t\t\tpatches_!,\n\t\t\t\t\tinversePatches_!\n\t\t\t\t)\n\t\t\tcase ArchType.Array:\n\t\t\t\treturn generateArrayPatches(\n\t\t\t\t\tstate,\n\t\t\t\t\tbasePath,\n\t\t\t\t\tpatches_!,\n\t\t\t\t\tinversePatches_!\n\t\t\t\t)\n\t\t\tcase ArchType.Set:\n\t\t\t\treturn generateSetPatches(\n\t\t\t\t\t(state as any) as SetState,\n\t\t\t\t\tbasePath,\n\t\t\t\t\tpatches_!,\n\t\t\t\t\tinversePatches_!\n\t\t\t\t)\n\t\t}\n\t}\n\n\tfunction generateArrayPatches(\n\t\tstate: ProxyArrayState,\n\t\tbasePath: PatchPath,\n\t\tpatches: Patch[],\n\t\tinversePatches: Patch[]\n\t) {\n\t\tlet {base_, assigned_} = state\n\t\tlet copy_ = state.copy_!\n\n\t\t// Reduce complexity by ensuring `base` is never longer.\n\t\tif (copy_.length < base_.length) {\n\t\t\t// @ts-ignore\n\t\t\t;[base_, copy_] = [copy_, base_]\n\t\t\t;[patches, inversePatches] = [inversePatches, patches]\n\t\t}\n\n\t\t// Process replaced indices.\n\t\tfor (let i = 0; i < base_.length; i++) {\n\t\t\tconst copiedItem = copy_[i]\n\t\t\tconst baseItem = base_[i]\n\t\t\tif (assigned_?.get(i.toString()) && copiedItem !== baseItem) {\n\t\t\t\tconst childState = copiedItem?.[DRAFT_STATE]\n\t\t\t\tif (childState && childState.modified_) {\n\t\t\t\t\t// Skip - let the child generate its own patches\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tconst path = basePath.concat([i])\n\t\t\t\tpatches.push({\n\t\t\t\t\top: REPLACE,\n\t\t\t\t\tpath,\n\t\t\t\t\t// Need to maybe clone it, as it can in fact be the original value\n\t\t\t\t\t// due to the base/copy inversion at the start of this function\n\t\t\t\t\tvalue: clonePatchValueIfNeeded(copiedItem)\n\t\t\t\t})\n\t\t\t\tinversePatches.push({\n\t\t\t\t\top: REPLACE,\n\t\t\t\t\tpath,\n\t\t\t\t\tvalue: clonePatchValueIfNeeded(baseItem)\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\t// Process added indices.\n\t\tfor (let i = base_.length; i < copy_.length; i++) {\n\t\t\tconst path = basePath.concat([i])\n\t\t\tpatches.push({\n\t\t\t\top: ADD,\n\t\t\t\tpath,\n\t\t\t\t// Need to maybe clone it, as it can in fact be the original value\n\t\t\t\t// due to the base/copy inversion at the start of this function\n\t\t\t\tvalue: clonePatchValueIfNeeded(copy_[i])\n\t\t\t})\n\t\t}\n\t