source: frontend/node_modules/immer/src/core/finalize.ts

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 5.3 KB
Line 
1import {
2 ImmerScope,
3 DRAFT_STATE,
4 isDraftable,
5 NOTHING,
6 PatchPath,
7 each,
8 has,
9 freeze,
10 ImmerState,
11 isDraft,
12 SetState,
13 set,
14 ProxyType,
15 getPlugin,
16 die,
17 revokeScope,
18 isFrozen,
19 shallowCopy
20} from "../internal"
21
22export function processResult(result: any, scope: ImmerScope) {
23 scope.unfinalizedDrafts_ = scope.drafts_.length
24 const baseDraft = scope.drafts_![0]
25 const isReplaced = result !== undefined && result !== baseDraft
26 if (!scope.immer_.useProxies_)
27 getPlugin("ES5").willFinalizeES5_(scope, result, isReplaced)
28 if (isReplaced) {
29 if (baseDraft[DRAFT_STATE].modified_) {
30 revokeScope(scope)
31 die(4)
32 }
33 if (isDraftable(result)) {
34 // Finalize the result in case it contains (or is) a subset of the draft.
35 result = finalize(scope, result)
36 if (!scope.parent_) maybeFreeze(scope, result)
37 }
38 if (scope.patches_) {
39 getPlugin("Patches").generateReplacementPatches_(
40 baseDraft[DRAFT_STATE].base_,
41 result,
42 scope.patches_,
43 scope.inversePatches_!
44 )
45 }
46 } else {
47 // Finalize the base draft.
48 result = finalize(scope, baseDraft, [])
49 }
50 revokeScope(scope)
51 if (scope.patches_) {
52 scope.patchListener_!(scope.patches_, scope.inversePatches_!)
53 }
54 return result !== NOTHING ? result : undefined
55}
56
57function finalize(rootScope: ImmerScope, value: any, path?: PatchPath) {
58 // Don't recurse in tho recursive data structures
59 if (isFrozen(value)) return value
60
61 const state: ImmerState = value[DRAFT_STATE]
62 // A plain object, might need freezing, might contain drafts
63 if (!state) {
64 each(
65 value,
66 (key, childValue) =>
67 finalizeProperty(rootScope, state, value, key, childValue, path),
68 true // See #590, don't recurse into non-enumerable of non drafted objects
69 )
70 return value
71 }
72 // Never finalize drafts owned by another scope.
73 if (state.scope_ !== rootScope) return value
74 // Unmodified draft, return the (frozen) original
75 if (!state.modified_) {
76 maybeFreeze(rootScope, state.base_, true)
77 return state.base_
78 }
79 // Not finalized yet, let's do that now
80 if (!state.finalized_) {
81 state.finalized_ = true
82 state.scope_.unfinalizedDrafts_--
83 const result =
84 // For ES5, create a good copy from the draft first, with added keys and without deleted keys.
85 state.type_ === ProxyType.ES5Object || state.type_ === ProxyType.ES5Array
86 ? (state.copy_ = shallowCopy(state.draft_))
87 : state.copy_
88 // Finalize all children of the copy
89 // For sets we clone before iterating, otherwise we can get in endless loop due to modifying during iteration, see #628
90 // To preserve insertion order in all cases we then clear the set
91 // And we let finalizeProperty know it needs to re-add non-draft children back to the target
92 let resultEach = result
93 let isSet = false
94 if (state.type_ === ProxyType.Set) {
95 resultEach = new Set(result)
96 result.clear()
97 isSet = true
98 }
99 each(resultEach, (key, childValue) =>
100 finalizeProperty(rootScope, state, result, key, childValue, path, isSet)
101 )
102 // everything inside is frozen, we can freeze here
103 maybeFreeze(rootScope, result, false)
104 // first time finalizing, let's create those patches
105 if (path && rootScope.patches_) {
106 getPlugin("Patches").generatePatches_(
107 state,
108 path,
109 rootScope.patches_,
110 rootScope.inversePatches_!
111 )
112 }
113 }
114 return state.copy_
115}
116
117function finalizeProperty(
118 rootScope: ImmerScope,
119 parentState: undefined | ImmerState,
120 targetObject: any,
121 prop: string | number,
122 childValue: any,
123 rootPath?: PatchPath,
124 targetIsSet?: boolean
125) {
126 if (__DEV__ && childValue === targetObject) die(5)
127 if (isDraft(childValue)) {
128 const path =
129 rootPath &&
130 parentState &&
131 parentState!.type_ !== ProxyType.Set && // Set objects are atomic since they have no keys.
132 !has((parentState as Exclude<ImmerState, SetState>).assigned_!, prop) // Skip deep patches for assigned keys.
133 ? rootPath!.concat(prop)
134 : undefined
135 // Drafts owned by `scope` are finalized here.
136 const res = finalize(rootScope, childValue, path)
137 set(targetObject, prop, res)
138 // Drafts from another scope must prevented to be frozen
139 // if we got a draft back from finalize, we're in a nested produce and shouldn't freeze
140 if (isDraft(res)) {
141 rootScope.canAutoFreeze_ = false
142 } else return
143 } else if (targetIsSet) {
144 targetObject.add(childValue)
145 }
146 // Search new objects for unfinalized drafts. Frozen objects should never contain drafts.
147 if (isDraftable(childValue) && !isFrozen(childValue)) {
148 if (!rootScope.immer_.autoFreeze_ && rootScope.unfinalizedDrafts_ < 1) {
149 // optimization: if an object is not a draft, and we don't have to
150 // deepfreeze everything, and we are sure that no drafts are left in the remaining object
151 // cause we saw and finalized all drafts already; we can stop visiting the rest of the tree.
152 // This benefits especially adding large data tree's without further processing.
153 // See add-data.js perf test
154 return
155 }
156 finalize(rootScope, childValue)
157 // immer deep freezes plain objects, so if there is no parent state, we freeze as well
158 if (!parentState || !parentState.scope_.parent_)
159 maybeFreeze(rootScope, childValue)
160 }
161}
162
163function maybeFreeze(scope: ImmerScope, value: any, deep = false) {
164 // we never freeze for a non-root scope; as it would prevent pruning for drafts inside wrapping objects
165 if (!scope.parent_ && scope.immer_.autoFreeze_ && scope.canAutoFreeze_) {
166 freeze(value, deep)
167 }
168}
Note: See TracBrowser for help on using the repository browser.