mutate-cow 6.0.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mutate-cow",
3
- "version": "6.0.0",
3
+ "version": "7.0.0",
4
4
  "description": "Update immutable objects as if they were mutable with copy-on-write",
5
5
  "keywords": [
6
6
  "immutable",
@@ -8,8 +8,8 @@
8
8
  "copy on write",
9
9
  "state management"
10
10
  ],
11
- "main": "index.js",
12
- "types": "index.d.ts",
11
+ "main": "src/index.js",
12
+ "types": "types/index.d.ts",
13
13
  "license": "MIT",
14
14
  "author": "Michael Wiencek <mwtuea@gmail.com>",
15
15
  "repository": {
@@ -18,13 +18,15 @@
18
18
  },
19
19
  "devDependencies": {
20
20
  "benchmark": "2.1.4",
21
- "flow-bin": "0.273.1",
21
+ "flow-bin": "0.275.0",
22
+ "immer": "10.1.1",
23
+ "mutative": "1.2.0",
22
24
  "tsd": "0.29.0"
23
25
  },
24
26
  "sideEffects": false,
25
27
  "type": "module",
26
28
  "scripts": {
27
- "test": "node --test --experimental-test-coverage"
29
+ "test": "node --test --experimental-test-coverage test/index.js"
28
30
  },
29
31
  "packageManager": "yarn@4.9.2+sha512.1fc009bc09d13cfd0e19efa44cbfc2b9cf6ca61482725eb35bbc5e257e093ebf4130db6dfe15d604ff4b79efd8e1e8e99b25fa7d0a6197c9f9826358d4d65c3c"
30
32
  }
@@ -5,20 +5,130 @@
5
5
  * in the file named "LICENSE" at the root directory of this distribution.
6
6
  */
7
7
 
8
- import clone from './clone.js';
9
- import {
10
- STATUS_CHANGED,
11
- STATUS_NONE,
12
- STATUS_REVOKED,
13
- } from './constants.js';
8
+ const NATIVE_CODE_REGEXP = /^function \w*\(\) \{\s*\[native code\]\s*\}$/m;
14
9
 
15
- const STALE_VALUE = Object.freeze(Object.create(null));
10
+ const STATUS_NONE = 1;
11
+ const STATUS_CHANGED = 2;
12
+ const STATUS_REVOKED = 3;
13
+ const STATUS_STALE = 4;
16
14
 
17
- export default class CowContext {
18
- constructor(source, prop, root, parent) {
15
+ function isPrimitive(value) {
16
+ if (value === null) {
17
+ return true;
18
+ }
19
+ const type = typeof value;
20
+ return (type !== 'function' && type !== 'object');
21
+ }
22
+
23
+ function getCloneableType(value) {
24
+ if (isPrimitive(value)) {
25
+ return 1;
26
+ }
27
+ if (typeof value !== 'object') {
28
+ return 0;
29
+ }
30
+ let proto = Object.getPrototypeOf(value);
31
+ while (proto) {
32
+ let ctor = proto.constructor;
33
+ // A Generator object's constructor is an object.
34
+ if (ctor && typeof ctor === 'object') {
35
+ ctor = ctor.constructor;
36
+ }
37
+ if (
38
+ typeof ctor === 'function' &&
39
+ ctor.name !== 'Array' &&
40
+ ctor.name !== 'Object' &&
41
+ NATIVE_CODE_REGEXP.test(Function.prototype.toString.call(ctor))
42
+ ) {
43
+ return 0;
44
+ }
45
+ proto = Object.getPrototypeOf(proto);
46
+ }
47
+ return 2;
48
+ }
49
+
50
+ function throwIfTypeNotCloneable(cloneableType) {
51
+ if (cloneableType === 0) {
52
+ throw new Error(
53
+ 'Only plain objects, arrays, and class instances ' +
54
+ 'can be cloned. Primitives, functions, and built-ins ' +
55
+ 'are unsupported.',
56
+ );
57
+ }
58
+ }
59
+
60
+ function restoreDescriptors(copy, changedDescriptors) {
61
+ for (let i = 0; i < changedDescriptors.length; i++) {
62
+ const [name, origDesc] = changedDescriptors[i];
63
+ const descriptor = Object.getOwnPropertyDescriptor(copy, name);
64
+ if (descriptor) {
65
+ Object.assign(descriptor, origDesc);
66
+ Reflect.defineProperty(copy, name, descriptor);
67
+ }
68
+ }
69
+ }
70
+
71
+ function clone(source, callbacks) {
72
+ const cloneableType = getCloneableType(source);
73
+ throwIfTypeNotCloneable(cloneableType);
74
+ if (cloneableType === 1) {
75
+ return source;
76
+ }
77
+ const proto = Object.getPrototypeOf(source);
78
+ let changedDescriptors = [];
79
+ let copy;
80
+ if (Array.isArray(source)) {
81
+ copy = Reflect.construct(Array, source, proto.constructor);
82
+ } else {
83
+ copy = Object.create(proto);
84
+ }
85
+ const ownKeys = Reflect.ownKeys(source);
86
+ for (let i = 0; i < ownKeys.length; i++) {
87
+ const key = ownKeys[i];
88
+ const descriptor = Object.getOwnPropertyDescriptor(source, key);
89
+ let origDesc;
90
+ if (descriptor.configurable === false) {
91
+ descriptor.configurable = true;
92
+ origDesc = {configurable: false};
93
+ }
94
+ if (descriptor.writable === false) {
95
+ descriptor.writable = true;
96
+ origDesc = {...origDesc, writable: false};
97
+ }
98
+ if (origDesc) {
99
+ changedDescriptors.push([key, origDesc]);
100
+ }
101
+ Reflect.defineProperty(copy, key, descriptor);
102
+ }
103
+ if (changedDescriptors.length) {
104
+ callbacks.push({
105
+ func: restoreDescriptors,
106
+ args: [copy, changedDescriptors],
107
+ });
108
+ }
109
+ if (Object.isFrozen(source)) {
110
+ callbacks.push({
111
+ func: Object.freeze,
112
+ args: [copy],
113
+ });
114
+ } else if (Object.isSealed(source)) {
115
+ callbacks.push({
116
+ func: Object.seal,
117
+ args: [copy],
118
+ });
119
+ } else if (!Object.isExtensible(source)) {
120
+ callbacks.push({
121
+ func: Object.preventExtensions,
122
+ args: [copy],
123
+ });
124
+ }
125
+ return copy;
126
+ }
127
+
128
+ export class CowContext {
129
+ constructor(source, prop, parent) {
19
130
  this._source = source;
20
131
  this._prop = prop;
21
- this._root = root || this;
22
132
  this._parent = parent;
23
133
  this._callbacks = [];
24
134
  this._result = null;
@@ -52,8 +162,7 @@ export default class CowContext {
52
162
  }
53
163
  }
54
164
 
55
- _getPropValue(prop) {
56
- const target = this.read();
165
+ _getPropDescriptor(target, prop) {
57
166
  const descriptor = Reflect.getOwnPropertyDescriptor(target, prop);
58
167
  if (descriptor) {
59
168
  if (descriptor.get) {
@@ -62,22 +171,29 @@ export default class CowContext {
62
171
  if (descriptor.set) {
63
172
  throw new Error('Setters are unsupported.');
64
173
  }
174
+ return descriptor;
175
+ }
176
+ }
177
+
178
+ _getPropValue(prop) {
179
+ const target = this.read();
180
+ const descriptor = this._getPropDescriptor(target, prop);
181
+ if (descriptor) {
65
182
  return descriptor.value;
66
183
  }
67
184
  return Reflect.get(target, prop);
68
185
  }
69
186
 
70
187
  _getSource() {
71
- let source = this._source;
72
- if (source === STALE_VALUE) {
188
+ if (this._status === STATUS_STALE) {
73
189
  /*
74
190
  * `this._parent` should always be defined here, because we only
75
- * ever assign `STALE_VALUE` onto child contexts.
191
+ * ever set `STATUS_STALE` onto child contexts.
76
192
  */
77
- source = this._parent._getPropValue(this._prop);
78
- this._source = source;
193
+ this._source = this._parent._getPropValue(this._prop);
194
+ this._status = STATUS_NONE;
79
195
  }
80
- return source;
196
+ return this._source;
81
197
  }
82
198
 
83
199
  _throwIfRevoked() {
@@ -113,7 +229,7 @@ export default class CowContext {
113
229
  return child;
114
230
  }
115
231
 
116
- child = new CowContext(value, prop, this._root, this);
232
+ child = new CowContext(value, prop, this);
117
233
  children.set(prop, child);
118
234
  return child;
119
235
  }
@@ -136,9 +252,8 @@ export default class CowContext {
136
252
  }
137
253
 
138
254
  _set(prop, newValue) {
139
- const origValue = this._getPropValue(prop);
140
-
141
- if (!Object.is(origValue, newValue)) {
255
+ const descriptor = this._getPropDescriptor(this.read(), prop);
256
+ if (descriptor === undefined || !Object.is(descriptor.value, newValue)) {
142
257
  this._copyForWrite();
143
258
  this._result[prop] = newValue;
144
259
 
@@ -148,10 +263,10 @@ export default class CowContext {
148
263
  if (children) {
149
264
  const child = children.get(prop);
150
265
  if (child) {
151
- child._source = STALE_VALUE;
266
+ child._source = null;
152
267
  child._callbacks = [];
153
268
  child._result = null;
154
- child._status = STATUS_NONE;
269
+ child._status = STATUS_STALE;
155
270
  }
156
271
  }
157
272
  }
@@ -186,7 +301,11 @@ export default class CowContext {
186
301
 
187
302
  root() {
188
303
  this._throwIfRevoked();
189
- return this._root;
304
+ let root = this;
305
+ while (root._parent !== null) {
306
+ root = root._parent;
307
+ }
308
+ return root;
190
309
  }
191
310
 
192
311
  revoke() {
@@ -204,7 +323,6 @@ export default class CowContext {
204
323
  }
205
324
  this._source = null;
206
325
  this._prop = null;
207
- this._root = null;
208
326
  this._parent = null;
209
327
  this._callbacks = null;
210
328
  this._result = null;
@@ -236,3 +354,8 @@ export default class CowContext {
236
354
  return this.root().final();
237
355
  }
238
356
  }
357
+
358
+ export default function mutate(source) {
359
+ throwIfTypeNotCloneable(getCloneableType(source));
360
+ return new CowContext(source, null, null);
361
+ }
@@ -1,54 +1,20 @@
1
1
  // @flow strict
2
2
 
3
- export type MutatableObject =
4
- | interface {}
5
- | {__proto__: null, ...};
6
-
7
- export type KeyType<+T: mixed> =
3
+ export type KeyType<+T> =
8
4
  T extends $ReadOnlyArray<mixed> ? number :
9
- T extends {__proto__: null, ...} ? $Keys<T> :
10
- T extends interface {} ? $Keys<T> :
11
- empty;
12
- export type KeyType2<+T, +K1: KeyType<T>> =
13
- PropType<T, K1> extends $ReadOnlyArray<mixed> ? number :
14
- PropType<T, K1> extends {__proto__: null, ...} ? $Keys<PropType<T, K1>> :
15
- PropType<T, K1> extends interface {} ? $Keys<PropType<T, K1>> :
16
- empty;
17
- export type KeyType3<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>> =
18
- PropType2<T, K1, K2> extends $ReadOnlyArray<mixed> ? number :
19
- PropType2<T, K1, K2> extends {__proto__: null, ...} ? $Keys<PropType2<T, K1, K2>> :
20
- PropType2<T, K1, K2> extends interface {} ? $Keys<PropType2<T, K1, K2>> :
21
- empty;
22
- export type KeyType4<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>> =
23
- PropType3<T, K1, K2, K3> extends $ReadOnlyArray<mixed> ? number :
24
- PropType3<T, K1, K2, K3> extends {__proto__: null, ...} ? $Keys<PropType3<T, K1, K2, K3>> :
25
- PropType3<T, K1, K2, K3> extends interface {} ? $Keys<PropType3<T, K1, K2, K3>> :
26
- empty;
27
- export type KeyType5<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>, +K4: KeyType4<T, K1, K2, K3>> =
28
- PropType4<T, K1, K2, K3, K4> extends $ReadOnlyArray<mixed> ? number :
29
- PropType4<T, K1, K2, K3, K4> extends {__proto__: null, ...} ? $Keys<PropType4<T, K1, K2, K3, K4>> :
30
- PropType4<T, K1, K2, K3, K4> extends interface {} ? $Keys<PropType4<T, K1, K2, K3, K4>> :
31
- empty;
32
- export type KeyType6<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>, +K4: KeyType4<T, K1, K2, K3>, +K5: KeyType5<T, K1, K2, K3, K4>> =
33
- PropType5<T, K1, K2, K3, K4, K5> extends $ReadOnlyArray<mixed> ? number :
34
- PropType5<T, K1, K2, K3, K4, K5> extends {__proto__: null, ...} ? $Keys<PropType5<T, K1, K2, K3, K4, K5>> :
35
- PropType5<T, K1, K2, K3, K4, K5> extends interface {} ? $Keys<PropType5<T, K1, K2, K3, K4, K5>> :
36
- empty;
37
- export type KeyType7<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>, +K4: KeyType4<T, K1, K2, K3>, +K5: KeyType5<T, K1, K2, K3, K4>, +K6: KeyType6<T, K1, K2, K3, K4, K5>> =
38
- PropType6<T, K1, K2, K3, K4, K5, K6> extends $ReadOnlyArray<mixed> ? number :
39
- PropType6<T, K1, K2, K3, K4, K5, K6> extends {__proto__: null, ...} ? $Keys<PropType6<T, K1, K2, K3, K4, K5, K6>> :
40
- PropType6<T, K1, K2, K3, K4, K5, K6> extends interface {} ? $Keys<PropType6<T, K1, K2, K3, K4, K5, K6>> :
41
- empty;
42
- export type KeyType8<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>, +K4: KeyType4<T, K1, K2, K3>, +K5: KeyType5<T, K1, K2, K3, K4>, +K6: KeyType6<T, K1, K2, K3, K4, K5>, +K7: KeyType7<T, K1, K2, K3, K4, K5, K6>> =
43
- PropType7<T, K1, K2, K3, K4, K5, K6, K7> extends $ReadOnlyArray<mixed> ? number :
44
- PropType7<T, K1, K2, K3, K4, K5, K6, K7> extends {__proto__: null, ...} ? $Keys<PropType7<T, K1, K2, K3, K4, K5, K6, K7>> :
45
- PropType7<T, K1, K2, K3, K4, K5, K6, K7> extends interface {} ? $Keys<PropType7<T, K1, K2, K3, K4, K5, K6, K7>> :
5
+ T extends ({__proto__: null, ...} | interface {}) ? $Keys<T> :
46
6
  empty;
7
+ export type KeyType2<+T, +K1: KeyType<T>> = KeyType<PropType<T, K1>>;
8
+ export type KeyType3<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>> = KeyType<PropType2<T, K1, K2>>;
9
+ export type KeyType4<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>> = KeyType<PropType3<T, K1, K2, K3>>;
10
+ export type KeyType5<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>, +K4: KeyType4<T, K1, K2, K3>> = KeyType<PropType4<T, K1, K2, K3, K4>>;
11
+ export type KeyType6<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>, +K4: KeyType4<T, K1, K2, K3>, +K5: KeyType5<T, K1, K2, K3, K4>> = KeyType<PropType5<T, K1, K2, K3, K4, K5>>;
12
+ export type KeyType7<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>, +K4: KeyType4<T, K1, K2, K3>, +K5: KeyType5<T, K1, K2, K3, K4>, +K6: KeyType6<T, K1, K2, K3, K4, K5>> = KeyType<PropType6<T, K1, K2, K3, K4, K5, K6>>;
13
+ export type KeyType8<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>, +K3: KeyType3<T, K1, K2>, +K4: KeyType4<T, K1, K2, K3>, +K5: KeyType5<T, K1, K2, K3, K4>, +K6: KeyType6<T, K1, K2, K3, K4, K5>, +K7: KeyType7<T, K1, K2, K3, K4, K5, K6>> = KeyType<PropType7<T, K1, K2, K3, K4, K5, K6, K7>>;
47
14
 
48
- export type PropType<+T: mixed, +K: KeyType<T>> =
15
+ export type PropType<+T, +K: KeyType<T>> =
49
16
  T extends $ReadOnlyArray<infer V> ? V :
50
- T extends {__proto__: null, ...} ? T[K] :
51
- T extends interface {} ? T[K] :
17
+ T extends ({__proto__: null, ...} | interface {}) ? T[K] :
52
18
  empty;
53
19
  export type PropType2<+T, +K1: KeyType<T>, +K2: KeyType2<T, K1>> =
54
20
  PropType<PropType<T, K1>, K2>;
@@ -71,44 +37,52 @@ export type ShallowReadWrite<+T> =
71
37
  T extends {...} ? {...T} :
72
38
  T;
73
39
 
74
- export type CowRootContext<+R> = CowContext<R, R, null>;
40
+ export type CowRootContext<+R> = CowContext<R, null>;
41
+
42
+ export type CowAnyContext = CowContext<mixed, CowAnyContext | null>;
43
+
44
+ type $Get1<+T, +K1, +ThisContext> =
45
+ CowContext<PropType<T, K1>, ThisContext>;
46
+ type $Get2<+T, +K1, +K2, +ThisContext> =
47
+ CowContext<PropType2<T, K1, K2>, $Get1<T, K1, ThisContext>>;
48
+ type $Get3<+T, +K1, +K2, +K3, +ThisContext> =
49
+ CowContext<PropType3<T, K1, K2, K3>, $Get2<T, K1, K2, ThisContext>>;
50
+ type $Get4<+T, +K1, +K2, +K3, +K4, +ThisContext> =
51
+ CowContext<PropType4<T, K1, K2, K3, K4>, $Get3<T, K1, K2, K3, ThisContext>>;
52
+ type $Get5<+T, +K1, +K2, +K3, +K4, +K5, +ThisContext> =
53
+ CowContext<PropType5<T, K1, K2, K3, K4, K5>, $Get4<T, K1, K2, K3, K4, ThisContext>>;
54
+ type $Get6<+T, +K1, +K2, +K3, +K4, +K5, +K6, +ThisContext> =
55
+ CowContext<PropType6<T, K1, K2, K3, K4, K5, K6>, $Get5<T, K1, K2, K3, K4, K5, ThisContext>>;
56
+ type $Get7<+T, +K1, +K2, +K3, +K4, +K5, +K6, +K7, +ThisContext> =
57
+ CowContext<PropType7<T, K1, K2, K3, K4, K5, K6, K7>, $Get6<T, K1, K2, K3, K4, K5, K6, ThisContext>>;
58
+ type $Get8<+T, +K1, +K2, +K3, +K4, +K5, +K6, +K7, +K8, +ThisContext> =
59
+ CowContext<PropType8<T, K1, K2, K3, K4, K5, K6, K7, K8>, $Get7<T, K1, K2, K3, K4, K5, K6, K7, ThisContext>>;
75
60
 
76
- export type CowAnyContext<+R> =
77
- CowContext<mixed, R, CowAnyContext<R> | null>;
61
+ export type GetCowContextSource<+C> =
62
+ C extends CowContext<infer T, mixed>
63
+ ? T
64
+ : empty;
78
65
 
79
- type $Get1<+T, +K1, +R, +ThisContext> =
80
- CowContext<PropType<T, K1>, R, ThisContext>;
81
- type $Get2<+T, +K1, +K2, +R, +ThisContext> =
82
- CowContext<PropType2<T, K1, K2>, R, $Get1<T, K1, R, ThisContext>>;
83
- type $Get3<+T, +K1, +K2, +K3, +R, +ThisContext> =
84
- CowContext<PropType3<T, K1, K2, K3>, R, $Get2<T, K1, K2, R, ThisContext>>;
85
- type $Get4<+T, +K1, +K2, +K3, +K4, +R, +ThisContext> =
86
- CowContext<PropType4<T, K1, K2, K3, K4>, R, $Get3<T, K1, K2, K3, R, ThisContext>>;
87
- type $Get5<+T, +K1, +K2, +K3, +K4, +K5, +R, +ThisContext> =
88
- CowContext<PropType5<T, K1, K2, K3, K4, K5>, R, $Get4<T, K1, K2, K3, K4, R, ThisContext>>;
89
- type $Get6<+T, +K1, +K2, +K3, +K4, +K5, +K6, +R, +ThisContext> =
90
- CowContext<PropType6<T, K1, K2, K3, K4, K5, K6>, R, $Get5<T, K1, K2, K3, K4, K5, R, ThisContext>>;
91
- type $Get7<+T, +K1, +K2, +K3, +K4, +K5, +K6, +K7, +R, +ThisContext> =
92
- CowContext<PropType7<T, K1, K2, K3, K4, K5, K6, K7>, R, $Get6<T, K1, K2, K3, K4, K5, K6, R, ThisContext>>;
93
- type $Get8<+T, +K1, +K2, +K3, +K4, +K5, +K6, +K7, +K8, +R, +ThisContext> =
94
- CowContext<PropType8<T, K1, K2, K3, K4, K5, K6, K7, K8>, R, $Get7<T, K1, K2, K3, K4, K5, K6, K7, R, ThisContext>>;
66
+ export type GetCowContextRoot<+C> =
67
+ C extends CowContext<infer T, infer P>
68
+ ? (P extends null ? C : GetCowContextRoot<P>)
69
+ : empty;
95
70
 
96
- declare export class CowContext<
97
- +T: mixed,
98
- +R: mixed = mixed,
99
- +ParentContext: CowAnyContext<R> | null = CowAnyContext<R> | null,
100
- > {
71
+ declare class CowContext<
72
+ +T,
73
+ +ParentContext: CowAnyContext | null = CowAnyContext | null,
74
+ >{
101
75
  read(): T;
102
76
  write(): ShallowReadWrite<T>;
103
77
  get(): this;
104
- get<const K1: KeyType<T>>(prop1: K1): $Get1<T, K1, R, this>;
105
- get<const K1: KeyType<T>, const K2: KeyType2<T, K1>>(prop1: K1, prop2: K2): $Get2<T, K1, K2, R, this>;
106
- get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>>(prop1: K1, prop2: K2, prop3: K3): $Get3<T, K1, K2, K3, R, this>;
107
- get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4): $Get4<T, K1, K2, K3, K4, R, this>;
108
- get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5): $Get5<T, K1, K2, K3, K4, K5, R, this>;
109
- get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6): $Get6<T, K1, K2, K3, K4, K5, K6, R, this>;
110
- get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7): $Get7<T, K1, K2, K3, K4, K5, K6, K7, R, this>;
111
- get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>, const K8: KeyType8<T, K1, K2, K3, K4, K5, K6, K7>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7, prop8: K8): $Get8<T, K1, K2, K3, K4, K5, K6, K7, K8, R, this>;
78
+ get<const K1: KeyType<T>>(prop1: K1): $Get1<T, K1, this>;
79
+ get<const K1: KeyType<T>, const K2: KeyType2<T, K1>>(prop1: K1, prop2: K2): $Get2<T, K1, K2, this>;
80
+ get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>>(prop1: K1, prop2: K2, prop3: K3): $Get3<T, K1, K2, K3, this>;
81
+ get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4): $Get4<T, K1, K2, K3, K4, this>;
82
+ get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5): $Get5<T, K1, K2, K3, K4, K5, this>;
83
+ get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6): $Get6<T, K1, K2, K3, K4, K5, K6, this>;
84
+ get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7): $Get7<T, K1, K2, K3, K4, K5, K6, K7, this>;
85
+ get<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>, const K8: KeyType8<T, K1, K2, K3, K4, K5, K6, K7>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7, prop8: K8): $Get8<T, K1, K2, K3, K4, K5, K6, K7, K8, this>;
112
86
  set(newValue: T): this;
113
87
  set<const K1: KeyType<T>>(prop1: K1, newValue: PropType<T, K1>): this;
114
88
  set<const K1: KeyType<T>, const K2: KeyType2<T, K1>>(prop1: K1, prop2: K2, newValue: PropType2<T, K1, K2>): this;
@@ -119,22 +93,22 @@ declare export class CowContext<
119
93
  set<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7, newValue: PropType7<T, K1, K2, K3, K4, K5, K6, K7>): this;
120
94
  set<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>, const K8: KeyType8<T, K1, K2, K3, K4, K5, K6, K7>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7, prop8: K8, newValue: PropType8<T, K1, K2, K3, K4, K5, K6, K7, K8>): this;
121
95
  update(updater: (this) => mixed): this;
122
- update<const K1: KeyType<T>>(prop1: K1, updater: ($Get1<T, K1, R, this>) => mixed): this;
123
- update<const K1: KeyType<T>, const K2: KeyType2<T, K1>>(prop1: K1, prop2: K2, updater: ($Get2<T, K1, K2, R, this>) => mixed): this;
124
- update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>>(prop1: K1, prop2: K2, prop3: K3, updater: ($Get3<T, K1, K2, K3, R, this>) => mixed): this;
125
- update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, updater: ($Get4<T, K1, K2, K3, K4, R, this>) => mixed): this;
126
- update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, updater: ($Get5<T, K1, K2, K3, K4, K5, R, this>) => mixed): this;
127
- update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, updater: ($Get6<T, K1, K2, K3, K4, K5, K6, R, this>) => mixed): this;
128
- update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7, updater: ($Get7<T, K1, K2, K3, K4, K5, K6, K7, R, this>) => mixed): this;
129
- update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>, const K8: KeyType8<T, K1, K2, K3, K4, K5, K6, K7>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7, prop8: K8, updater: ($Get8<T, K1, K2, K3, K4, K5, K6, K7, K8, R, this>) => mixed): this;
96
+ update<const K1: KeyType<T>>(prop1: K1, updater: ($Get1<T, K1, this>) => mixed): this;
97
+ update<const K1: KeyType<T>, const K2: KeyType2<T, K1>>(prop1: K1, prop2: K2, updater: ($Get2<T, K1, K2, this>) => mixed): this;
98
+ update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>>(prop1: K1, prop2: K2, prop3: K3, updater: ($Get3<T, K1, K2, K3, this>) => mixed): this;
99
+ update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, updater: ($Get4<T, K1, K2, K3, K4, this>) => mixed): this;
100
+ update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, updater: ($Get5<T, K1, K2, K3, K4, K5, this>) => mixed): this;
101
+ update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, updater: ($Get6<T, K1, K2, K3, K4, K5, K6, this>) => mixed): this;
102
+ update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7, updater: ($Get7<T, K1, K2, K3, K4, K5, K6, K7, this>) => mixed): this;
103
+ update<const K1: KeyType<T>, const K2: KeyType2<T, K1>, const K3: KeyType3<T, K1, K2>, const K4: KeyType4<T, K1, K2, K3>, const K5: KeyType5<T, K1, K2, K3, K4>, const K6: KeyType6<T, K1, K2, K3, K4, K5>, const K7: KeyType7<T, K1, K2, K3, K4, K5, K6>, const K8: KeyType8<T, K1, K2, K3, K4, K5, K6, K7>>(prop1: K1, prop2: K2, prop3: K3, prop4: K4, prop5: K5, prop6: K6, prop7: K7, prop8: K8, updater: ($Get8<T, K1, K2, K3, K4, K5, K6, K7, K8, this>) => mixed): this;
130
104
  parent(): ParentContext;
131
- root(): CowRootContext<R>;
105
+ root(): GetCowContextRoot<this>;
132
106
  revoke(): void;
133
107
  isRevoked(): boolean;
134
108
  final(): T;
135
- finalRoot(): R;
109
+ finalRoot(): GetCowContextSource<GetCowContextRoot<this>>;
136
110
  }
137
111
 
138
- declare export default function mutate<T: MutatableObject>(
112
+ declare export default function mutate<T>(
139
113
  source: T,
140
114
  ): CowRootContext<T>;
@@ -7,43 +7,53 @@ type NestedProp<T, Path extends ReadonlyArray<PropertyKey>> =
7
7
  )
8
8
  : T;
9
9
 
10
- type NestedContext<T, R extends object, ParentContext extends CowAnyContext<R> | null, Path extends ReadonlyArray<PropertyKey>> =
10
+ type NestedContext<T, ParentContext extends CowAnyContext | null, Path extends ReadonlyArray<PropertyKey>> =
11
11
  Path extends [infer First, ...infer Rest]
12
12
  ? (
13
13
  First extends keyof T
14
- ? NestedContext<T[First], R, CowContext<T, R, ParentContext>, Extract<Rest, ReadonlyArray<PropertyKey>>>
14
+ ? NestedContext<T[First], CowContext<T, ParentContext>, Extract<Rest, ReadonlyArray<PropertyKey>>>
15
15
  : never
16
16
  )
17
- : CowContext<T, R, ParentContext>;
17
+ : CowContext<T, ParentContext>;
18
18
 
19
19
  type ShallowReadWrite<T> =
20
20
  T extends ReadonlyArray<infer V> ? Array<V> :
21
21
  T extends object ? {-readonly [K in keyof T]: T[K]} : never;
22
22
 
23
- type CowRootContext<R extends object> = CowContext<R, R, null>;
23
+ type CowRootContext<R> = CowContext<R, null>;
24
24
 
25
- type CowAnyContext<R extends object> =
26
- CowContext<unknown, R, CowAnyContext<R> | null>;
25
+ type CowAnyContext =
26
+ CowContext<unknown, CowAnyContext | null>;
27
+
28
+ type GetCowContextSource<C> =
29
+ C extends CowContext<infer T, CowAnyContext | null>
30
+ ? T
31
+ : never;
32
+
33
+ type GetCowContextRoot<C> =
34
+ C extends CowContext<infer T, infer P>
35
+ ? (P extends null ? C : GetCowContextRoot<P>)
36
+ : never;
27
37
 
28
38
  declare class CowContext<
29
39
  out T,
30
- out R extends object,
31
- out ParentContext extends CowAnyContext<R> | null = CowAnyContext<R> | null,
40
+ // @ts-ignore
41
+ out ParentContext extends CowAnyContext | null = CowAnyContext | null,
32
42
  > {
33
43
  read(): T;
34
44
  write(): ShallowReadWrite<T>;
35
- get<Path extends ReadonlyArray<PropertyKey>>(...path: Path): NestedContext<T, R, ParentContext, Path>;
45
+ get<Path extends ReadonlyArray<PropertyKey>>(...path: Path): NestedContext<T, ParentContext, Path>;
36
46
  set<Path extends ReadonlyArray<PropertyKey>>(...args: [...Path, NestedProp<T, Path>]): this;
37
- update<Path extends ReadonlyArray<PropertyKey>>(...args: [...Path, (childContext: NestedContext<T, R, ParentContext, Path>) => unknown]): this;
47
+ update<Path extends ReadonlyArray<PropertyKey>>(...args: [...Path, (childContext: NestedContext<T, ParentContext, Path>) => unknown]): this;
38
48
  parent(): ParentContext;
39
- root(): CowRootContext<R>;
49
+ root(): GetCowContextRoot<this>;
40
50
  revoke(): void;
41
51
  isRevoked(): boolean;
42
52
  final(): T;
43
- finalRoot(): R;
53
+ finalRoot(): GetCowContextSource<GetCowContextRoot<this>>;
44
54
  }
45
55
 
46
- declare function mutate<T extends object>(
56
+ declare function mutate<T>(
47
57
  source: T,
48
58
  ): CowRootContext<T>;
49
59
 
package/canClone.js DELETED
@@ -1,40 +0,0 @@
1
- /*
2
- * Copyright (c) 2023 Michael Wiencek
3
- *
4
- * This source code is licensed under the MIT license. A copy can be found
5
- * in the file named "LICENSE" at the root directory of this distribution.
6
- */
7
-
8
- const funcToString = Function.prototype.toString;
9
-
10
- const nativeCodeRegExp = /^function \w*\(\) \{\s*\[native code\]\s*\}$/m;
11
-
12
- export const CANNOT_CLONE_ERROR =
13
- 'Only plain objects, arrays, and class instances ' +
14
- 'can be cloned. Primitives, functions, and built-ins ' +
15
- 'are unsupported.';
16
-
17
- export default function canClone(object) {
18
- if (!object || typeof object !== 'object') {
19
- throw new Error(CANNOT_CLONE_ERROR);
20
- }
21
-
22
- let proto = Reflect.getPrototypeOf(object);
23
-
24
- while (proto) {
25
- let ctor = proto.constructor;
26
- // A Generator object's constructor is an object.
27
- if (ctor && typeof ctor === 'object') {
28
- ctor = ctor.constructor;
29
- }
30
-
31
- if (typeof ctor === 'function' &&
32
- ctor.name !== 'Array' &&
33
- ctor.name !== 'Object' &&
34
- nativeCodeRegExp.test(funcToString.call(ctor))) {
35
- throw new Error(CANNOT_CLONE_ERROR);
36
- }
37
-
38
- proto = Reflect.getPrototypeOf(proto);
39
- }
40
- }
package/clone.js DELETED
@@ -1,99 +0,0 @@
1
- /*
2
- * Copyright (c) 2023 Michael Wiencek
3
- *
4
- * This source code is licensed under the MIT license. A copy can be found
5
- * in the file named "LICENSE" at the root directory of this distribution.
6
- */
7
-
8
- import canClone from './canClone.js';
9
- import {
10
- NON_CONFIGURABLE,
11
- NON_CONFIGURABLE_AND_WRITABLE,
12
- NON_WRITABLE,
13
- } from './constants.js';
14
-
15
- function isPrimitive(value) {
16
- switch (typeof value) {
17
- case 'bigint':
18
- case 'boolean':
19
- case 'number':
20
- case 'string':
21
- case 'symbol':
22
- case 'undefined':
23
- return true;
24
- default:
25
- return value === null;
26
- }
27
- }
28
-
29
- function restoreDescriptors(copy, changedDescriptors) {
30
- for (let i = 0; i < changedDescriptors.length; i++) {
31
- const [name, origDesc] = changedDescriptors[i];
32
- const descriptor = Reflect.getOwnPropertyDescriptor(copy, name);
33
- if (descriptor) {
34
- Object.assign(descriptor, origDesc);
35
- Reflect.defineProperty(copy, name, descriptor);
36
- }
37
- }
38
- }
39
-
40
- export default function clone(source, callbacks) {
41
- if (isPrimitive(source)) {
42
- return source;
43
- }
44
- canClone(source);
45
- let changedDescriptors;
46
- let copy;
47
- if (Array.isArray(source)) {
48
- copy = new Array(source.length);
49
- } else {
50
- copy = Object.create(Reflect.getPrototypeOf(source));
51
- }
52
- const ownNames = Object.getOwnPropertyNames(source);
53
- for (let i = 0; i < ownNames.length; i++) {
54
- const name = ownNames[i];
55
- const descriptor = Reflect.getOwnPropertyDescriptor(source, name);
56
- const nonConfigurable = descriptor.configurable === false;
57
- let origDesc;
58
- if (nonConfigurable) {
59
- descriptor.configurable = true;
60
- origDesc = NON_CONFIGURABLE;
61
- }
62
- if (descriptor.writable === false) {
63
- descriptor.writable = true;
64
- origDesc = nonConfigurable
65
- ? NON_CONFIGURABLE_AND_WRITABLE
66
- : NON_WRITABLE;
67
- }
68
- if (origDesc) {
69
- if (!changedDescriptors) {
70
- changedDescriptors = [];
71
- }
72
- changedDescriptors.push([name, origDesc]);
73
- }
74
- Reflect.defineProperty(copy, name, descriptor);
75
- }
76
- if (changedDescriptors) {
77
- callbacks.push({
78
- func: restoreDescriptors,
79
- args: [copy, changedDescriptors],
80
- });
81
- }
82
- if (Object.isFrozen(source)) {
83
- callbacks.push({
84
- func: Object.freeze,
85
- args: [copy],
86
- });
87
- } else if (Object.isSealed(source)) {
88
- callbacks.push({
89
- func: Object.seal,
90
- args: [copy],
91
- });
92
- } else if (!Reflect.isExtensible(source)) {
93
- callbacks.push({
94
- func: Reflect.preventExtensions,
95
- args: [copy],
96
- });
97
- }
98
- return copy;
99
- }
package/constants.js DELETED
@@ -1,23 +0,0 @@
1
- export const NON_CONFIGURABLE =
2
- Object.freeze({configurable: false});
3
-
4
- export const NON_WRITABLE =
5
- Object.freeze({writable: false});
6
-
7
- export const NON_CONFIGURABLE_AND_WRITABLE =
8
- Object.freeze({
9
- configurable: false,
10
- writable: false,
11
- });
12
-
13
- export const CONFIGURABLE_AND_WRITABLE =
14
- Object.freeze({
15
- configurable: true,
16
- writable: true,
17
- });
18
-
19
- export const STATUS_NONE = 1;
20
-
21
- export const STATUS_CHANGED = 2;
22
-
23
- export const STATUS_REVOKED = 3;
package/index.js DELETED
@@ -1,14 +0,0 @@
1
- /*
2
- * Copyright (c) 2023 Michael Wiencek
3
- *
4
- * This source code is licensed under the MIT license. A copy can be found
5
- * in the file named "LICENSE" at the root directory of this distribution.
6
- */
7
-
8
- import canClone from './canClone.js';
9
- import CowContext from './CowContext.js';
10
-
11
- export default function mutate(source) {
12
- canClone(source);
13
- return new CowContext(source, null, null, null);
14
- }