Skip to content

Commit a712cee

Browse files
committed
fix(array): update
1 parent aa048b2 commit a712cee

File tree

8 files changed

+4415
-65
lines changed

8 files changed

+4415
-65
lines changed

src/draft.ts

+39-18
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import {
33
Finalities,
44
Patches,
55
ProxyDraft,
6-
Options,
76
Operation,
7+
DraftOptions,
88
} from './interface';
99
import { dataTypes, PROXY_DRAFT } from './constant';
1010
import { mapHandler, mapHandlerKeys } from './map';
@@ -38,7 +38,7 @@ const draftsCache = new WeakSet<object>();
3838

3939
let arrayHandling = false;
4040

41-
const proxyArrayMethods = ['splice', 'shift', 'unshift', 'reverse'];
41+
const proxyArrayMethods = ['splice', 'shift', 'unshift'];
4242

4343
const proxyHandler: ProxyHandler<ProxyDraft> = {
4444
get(target: ProxyDraft, key: string | number | symbol, receiver: any) {
@@ -94,19 +94,39 @@ const proxyHandler: ProxyHandler<ProxyDraft> = {
9494
if (!has(source, key)) {
9595
const desc = getDescriptor(source, key);
9696
const value = desc?.value;
97-
if (target.type === DraftType.Array) {
98-
if (proxyArrayMethods.includes(key as string)) {
99-
return function (this: any, ...args: any[]) {
100-
let returnValue: any;
101-
arrayHandling = true;
102-
try {
103-
returnValue = value.apply(this, args);
104-
} finally {
105-
arrayHandling = false;
97+
if (
98+
target.type === DraftType.Array &&
99+
proxyArrayMethods.includes(key as string)
100+
) {
101+
const handleItem = (item: any) => {
102+
if (!isDraftable(item)) return item;
103+
ensureShallowCopy(target);
104+
const draft = createDraft({
105+
original: item,
106+
parentDraft: target,
107+
key: undefined,
108+
finalities: target.finalities,
109+
options: target.options,
110+
});
111+
// TODO: support for custom shallow copy function
112+
return draft;
113+
};
114+
return function (this: any, ...args: any[]) {
115+
let returnValue: any;
116+
arrayHandling = true;
117+
try {
118+
returnValue = value.apply(this, args);
119+
if (key === 'splice' && returnValue.length > 0) {
120+
returnValue = returnValue.map(handleItem);
121+
}
122+
if (key === 'shift' && typeof returnValue === 'object') {
123+
returnValue = handleItem(returnValue);
106124
}
107125
return returnValue;
108-
};
109-
}
126+
} finally {
127+
arrayHandling = false;
128+
}
129+
};
110130
}
111131
return desc
112132
? `value` in desc
@@ -126,11 +146,11 @@ const proxyHandler: ProxyHandler<ProxyDraft> = {
126146
if (
127147
!arrayHandling &&
128148
(value === peek(target.original, key) ||
129-
target.options.skipFinalization!.has(value))
149+
target.options.skipFinalization.has(value))
130150
) {
131-
const shouldSkip = target.options.skipFinalization!.has(value);
151+
const shouldSkip = target.options.skipFinalization.has(value);
132152
if (shouldSkip) {
133-
target.options.skipFinalization!.delete(value);
153+
target.options.skipFinalization.delete(value);
134154
}
135155
ensureShallowCopy(target);
136156
target.copy![key] = createDraft({
@@ -151,7 +171,8 @@ const proxyHandler: ProxyHandler<ProxyDraft> = {
151171
return target.copy![key];
152172
}
153173
if (arrayHandling && !isDraft(value) && isDraftable(value)) {
154-
target.options.skipFinalization!.add(value);
174+
// !case: handle the case of assigning the original array item via array methods(`splice`, `shift``, `unshift`, `reverse`)
175+
target.options.skipFinalization.add(value);
155176
}
156177
return value;
157178
},
@@ -258,7 +279,7 @@ export function createDraft<T extends object>(createDraftOptions: {
258279
parentDraft?: ProxyDraft | null;
259280
key?: string | number | symbol;
260281
finalities: Finalities;
261-
options: Options<any, any>;
282+
options: DraftOptions;
262283
}): T {
263284
const { original, parentDraft, key, finalities, options } =
264285
createDraftOptions;

src/draftify.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {
2+
DraftOptions,
23
Finalities,
3-
Options,
44
Patches,
55
PatchesOptions,
66
Result,
@@ -15,7 +15,7 @@ export function draftify<
1515
F extends boolean = false,
1616
>(
1717
baseState: T,
18-
options: Options<O, F>
18+
options: DraftOptions
1919
): [T, (returnedValue: [T] | []) => Result<T, O, F>] {
2020
const finalities: Finalities = {
2121
draft: [],

src/interface.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,7 @@ export interface ProxyDraft<T = any> {
4242
copy: T | null;
4343
proxy: T | null;
4444
finalities: Finalities;
45-
options: Options<any, any> & {
46-
updatedValues?: WeakMap<any, any>;
47-
skipFinalization?: WeakSet<any>;
48-
};
45+
options: DraftOptions;
4946
parent?: ProxyDraft | null;
5047
key?: string | number | symbol;
5148
setMap?: Map<any, ProxyDraft>;
@@ -125,6 +122,17 @@ export interface Options<O extends PatchesOptions, F extends boolean> {
125122
mark?: Mark<O, F>;
126123
}
127124

125+
export type DraftOptions = Options<any, any> & {
126+
/**
127+
* a collection for circular reference check
128+
*/
129+
updatedValues?: WeakMap<any, any>;
130+
/**
131+
* a collection for array item skip deep check
132+
*/
133+
skipFinalization: WeakSet<any>;
134+
};
135+
128136
export interface ExternalOptions<O extends PatchesOptions, F extends boolean> {
129137
/**
130138
* In strict mode, Forbid accessing non-draftable values and forbid returning a non-draft value.

src/makeCreator.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
ExternalOptions,
77
PatchesOptions,
88
Result,
9+
DraftOptions,
910
} from './interface';
1011
import { draftify } from './draftify';
1112
import {
@@ -143,9 +144,7 @@ export const makeCreator: MakeCreator = (arg) => {
143144
const enablePatches = options.enablePatches ?? false;
144145
const strict = options.strict ?? false;
145146
const enableAutoFreeze = options.enableAutoFreeze ?? false;
146-
const _options: Options<any, any> & {
147-
skipFinalization: WeakSet<any>;
148-
} = {
147+
const _options: DraftOptions = {
149148
enableAutoFreeze,
150149
mark,
151150
strict,

src/utils/finalize.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ export function handleValue(
2222
!isDraftable(target, options) ||
2323
handledSet.has(target) ||
2424
Object.isFrozen(target) ||
25-
(options!.skipFinalization!.has(target))
25+
options!.skipFinalization!.has(target)
26+
// It should skip the finalization process
27+
// This can avoid unnecessary deep traversal, as these objects are non-draft and do not contain draft in their deep object.
2628
)
2729
return;
2830
const isSet = target instanceof Set;

0 commit comments

Comments
 (0)