| 1 | import {
|
|---|
| 2 | die,
|
|---|
| 3 | isDraft,
|
|---|
| 4 | shallowCopy,
|
|---|
| 5 | each,
|
|---|
| 6 | DRAFT_STATE,
|
|---|
| 7 | get,
|
|---|
| 8 | set,
|
|---|
| 9 | ImmerState,
|
|---|
| 10 | isDraftable,
|
|---|
| 11 | Archtype,
|
|---|
| 12 | getArchtype,
|
|---|
| 13 | getPlugin
|
|---|
| 14 | } from "../internal"
|
|---|
| 15 |
|
|---|
| 16 | /** 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. */
|
|---|
| 17 | export function current<T>(value: T): T
|
|---|
| 18 | export function current(value: any): any {
|
|---|
| 19 | if (!isDraft(value)) die(22, value)
|
|---|
| 20 | return currentImpl(value)
|
|---|
| 21 | }
|
|---|
| 22 |
|
|---|
| 23 | function currentImpl(value: any): any {
|
|---|
| 24 | if (!isDraftable(value)) return value
|
|---|
| 25 | const state: ImmerState | undefined = value[DRAFT_STATE]
|
|---|
| 26 | let copy: any
|
|---|
| 27 | const archType = getArchtype(value)
|
|---|
| 28 | if (state) {
|
|---|
| 29 | if (
|
|---|
| 30 | !state.modified_ &&
|
|---|
| 31 | (state.type_ < 4 || !getPlugin("ES5").hasChanges_(state as any))
|
|---|
| 32 | )
|
|---|
| 33 | return state.base_
|
|---|
| 34 | // Optimization: avoid generating new drafts during copying
|
|---|
| 35 | state.finalized_ = true
|
|---|
| 36 | copy = copyHelper(value, archType)
|
|---|
| 37 | state.finalized_ = false
|
|---|
| 38 | } else {
|
|---|
| 39 | copy = copyHelper(value, archType)
|
|---|
| 40 | }
|
|---|
| 41 |
|
|---|
| 42 | each(copy, (key, childValue) => {
|
|---|
| 43 | if (state && get(state.base_, key) === childValue) return // no need to copy or search in something that didn't change
|
|---|
| 44 | set(copy, key, currentImpl(childValue))
|
|---|
| 45 | })
|
|---|
| 46 | // In the future, we might consider freezing here, based on the current settings
|
|---|
| 47 | return archType === Archtype.Set ? new Set(copy) : copy
|
|---|
| 48 | }
|
|---|
| 49 |
|
|---|
| 50 | function copyHelper(value: any, archType: number): any {
|
|---|
| 51 | // creates a shallow copy, even if it is a map or set
|
|---|
| 52 | switch (archType) {
|
|---|
| 53 | case Archtype.Map:
|
|---|
| 54 | return new Map(value)
|
|---|
| 55 | case Archtype.Set:
|
|---|
| 56 | // Set will be cloned as array temporarily, so that we can replace individual items
|
|---|
| 57 | return Array.from(value)
|
|---|
| 58 | }
|
|---|
| 59 | return shallowCopy(value)
|
|---|
| 60 | }
|
|---|