@esportsplus/reactivity 0.20.1 → 0.21.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.
@@ -12,5 +12,4 @@ declare const STATE_DIRTY: number;
12
12
  declare const STATE_RECOMPUTING: number;
13
13
  declare const STATE_IN_HEAP: number;
14
14
  declare const STATE_NOTIFY_MASK: number;
15
- declare const TYPE: unique symbol;
16
- export { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL, STABILIZER_IDLE, STATE_NOTIFY_MASK, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING, TYPE };
15
+ export { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL, STABILIZER_IDLE, STATE_NOTIFY_MASK, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING };
@@ -12,5 +12,4 @@ const STATE_DIRTY = 1 << 1;
12
12
  const STATE_RECOMPUTING = 1 << 2;
13
13
  const STATE_IN_HEAP = 1 << 3;
14
14
  const STATE_NOTIFY_MASK = (STATE_CHECK | STATE_DIRTY);
15
- const TYPE = Symbol('reactivity.type');
16
- export { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL, STABILIZER_IDLE, STATE_NOTIFY_MASK, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING, TYPE };
15
+ export { COMPUTED, REACTIVE_ARRAY, REACTIVE_OBJECT, SIGNAL, STABILIZER_IDLE, STATE_NOTIFY_MASK, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING };
@@ -17,7 +17,9 @@ type Events<T> = {
17
17
  shift: {
18
18
  item: T;
19
19
  };
20
- sort: undefined;
20
+ sort: {
21
+ order: number[];
22
+ };
21
23
  splice: {
22
24
  deleteCount: number;
23
25
  items: T[];
@@ -1,5 +1,5 @@
1
1
  import { isArray } from '@esportsplus/utilities';
2
- import { REACTIVE_ARRAY, TYPE } from '../constants.js';
2
+ import { REACTIVE_ARRAY } from '../constants.js';
3
3
  import { isReactiveObject } from './object.js';
4
4
  class ReactiveArray extends Array {
5
5
  listeners = {};
@@ -120,8 +120,32 @@ class ReactiveArray extends Array {
120
120
  return item;
121
121
  }
122
122
  sort(fn) {
123
+ let before = new Array(this.length);
124
+ for (let i = 0, n = before.length; i < n; i++) {
125
+ before[i] = this[i];
126
+ }
123
127
  super.sort(fn);
124
- this.dispatch('sort');
128
+ let buckets = new Map(), cursors = new Map(), order = new Array(this.length);
129
+ for (let i = 0, n = before.length; i < n; i++) {
130
+ let value = before[i], list = buckets.get(value);
131
+ if (!list) {
132
+ buckets.set(value, [i]);
133
+ }
134
+ else {
135
+ list.push(i);
136
+ }
137
+ }
138
+ for (let i = 0, n = this.length; i < n; i++) {
139
+ let value = this[i], list = buckets.get(value);
140
+ if (!list) {
141
+ order[i] = i;
142
+ continue;
143
+ }
144
+ let cursor = cursors.get(value) || 0;
145
+ order[i] = list[cursor];
146
+ cursors.set(value, cursor + 1);
147
+ }
148
+ this.dispatch('sort', { order });
125
149
  return this;
126
150
  }
127
151
  splice(start, deleteCount = this.length, ...items) {
@@ -143,5 +167,5 @@ class ReactiveArray extends Array {
143
167
  return length;
144
168
  }
145
169
  }
146
- Object.defineProperty(ReactiveArray.prototype, TYPE, { value: REACTIVE_ARRAY });
170
+ Object.defineProperty(ReactiveArray.prototype, REACTIVE_ARRAY, { value: true });
147
171
  export { ReactiveArray };
@@ -1,6 +1,6 @@
1
1
  import { defineProperty, isArray, isPromise } from '@esportsplus/utilities';
2
2
  import { computed, dispose, effect, read, root, set, signal } from '../system.js';
3
- import { REACTIVE_OBJECT, TYPE } from '../constants.js';
3
+ import { REACTIVE_OBJECT } from '../constants.js';
4
4
  import { ReactiveArray } from './array.js';
5
5
  class ReactiveObject {
6
6
  disposers = null;
@@ -72,8 +72,8 @@ class ReactiveObject {
72
72
  }
73
73
  }
74
74
  }
75
- Object.defineProperty(ReactiveObject.prototype, TYPE, { value: REACTIVE_OBJECT });
75
+ Object.defineProperty(ReactiveObject.prototype, REACTIVE_OBJECT, { value: true });
76
76
  const isReactiveObject = (value) => {
77
- return typeof value === 'object' && value !== null && value[TYPE] === REACTIVE_OBJECT;
77
+ return typeof value === 'object' && value !== null && value[REACTIVE_OBJECT] === true;
78
78
  };
79
79
  export { isReactiveObject, ReactiveObject };
package/build/system.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { isObject } from '@esportsplus/utilities';
2
- import { COMPUTED, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING, TYPE } from './constants.js';
2
+ import { COMPUTED, SIGNAL, STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING } from './constants.js';
3
3
  let depth = 0, heap = new Array(64), heap_i = 0, heap_n = 0, linkPool = [], linkPoolMax = 1000, microtask = queueMicrotask, notified = false, observer = null, scope = null, stabilizer = STABILIZER_IDLE, version = 0;
4
4
  function cleanup(computed) {
5
5
  if (!computed.cleanup) {
@@ -219,7 +219,7 @@ function unlink(link) {
219
219
  if (prevSub) {
220
220
  prevSub.nextSub = nextSub;
221
221
  }
222
- else if ((dep.subs = nextSub) === null && dep[TYPE] === COMPUTED) {
222
+ else if ((dep.subs = nextSub) === null && dep.type === COMPUTED) {
223
223
  dispose(dep);
224
224
  }
225
225
  if (linkPool.length < linkPoolMax) {
@@ -233,7 +233,7 @@ function update(computed) {
233
233
  if (computed.state & STATE_CHECK) {
234
234
  for (let link = computed.deps; link; link = link.nextDep) {
235
235
  let dep = link.dep;
236
- if (dep[TYPE] === COMPUTED) {
236
+ if (dep.type === COMPUTED) {
237
237
  update(dep);
238
238
  if (computed.state & STATE_DIRTY) {
239
239
  break;
@@ -248,7 +248,6 @@ function update(computed) {
248
248
  }
249
249
  const computed = (fn) => {
250
250
  let self = {
251
- [TYPE]: COMPUTED,
252
251
  cleanup: null,
253
252
  deps: null,
254
253
  depsTail: null,
@@ -259,6 +258,7 @@ const computed = (fn) => {
259
258
  state: STATE_NONE,
260
259
  subs: null,
261
260
  subsTail: null,
261
+ type: COMPUTED,
262
262
  value: undefined,
263
263
  };
264
264
  self.prevHeap = self;
@@ -302,10 +302,10 @@ const effect = (fn) => {
302
302
  };
303
303
  };
304
304
  const isComputed = (value) => {
305
- return isObject(value) && value[TYPE] === COMPUTED;
305
+ return isObject(value) && value.type === COMPUTED;
306
306
  };
307
307
  const isSignal = (value) => {
308
- return isObject(value) && value[TYPE] === SIGNAL;
308
+ return isObject(value) && value.type === SIGNAL;
309
309
  };
310
310
  const onCleanup = (fn) => {
311
311
  let parent = observer || scope;
@@ -327,7 +327,7 @@ const onCleanup = (fn) => {
327
327
  const read = (node) => {
328
328
  if (observer) {
329
329
  link(node, observer);
330
- if (node[TYPE] === COMPUTED) {
330
+ if (node.type === COMPUTED) {
331
331
  let height = node.height;
332
332
  if (height >= observer.height) {
333
333
  observer.height = height + 1;
@@ -384,9 +384,9 @@ const set = (signal, value) => {
384
384
  };
385
385
  const signal = (value) => {
386
386
  return {
387
- [TYPE]: SIGNAL,
388
387
  subs: null,
389
388
  subsTail: null,
389
+ type: SIGNAL,
390
390
  value,
391
391
  };
392
392
  };
package/build/types.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { COMPUTED, SIGNAL, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING, TYPE } from './constants.js';
1
+ import { COMPUTED, SIGNAL, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants.js';
2
2
  import { ReactiveArray } from './reactive/array.js';
3
3
  import { ReactiveObject } from './reactive/object.js';
4
4
  interface Computed<T> {
5
- [TYPE]: typeof COMPUTED;
6
5
  cleanup: VoidFunction | VoidFunction[] | null;
7
6
  deps: Link | null;
8
7
  depsTail: Link | null;
@@ -13,6 +12,7 @@ interface Computed<T> {
13
12
  state: typeof STATE_CHECK | typeof STATE_DIRTY | typeof STATE_IN_HEAP | typeof STATE_NONE | typeof STATE_RECOMPUTING;
14
13
  subs: Link | null;
15
14
  subsTail: Link | null;
15
+ type: typeof COMPUTED;
16
16
  value: T;
17
17
  }
18
18
  interface Link {
@@ -24,9 +24,9 @@ interface Link {
24
24
  version: number;
25
25
  }
26
26
  type Signal<T> = {
27
- [TYPE]: typeof SIGNAL;
28
27
  subs: Link | null;
29
28
  subsTail: Link | null;
29
+ type: typeof SIGNAL;
30
30
  value: T;
31
31
  };
32
32
  export type { Computed, Link, Signal, ReactiveArray, ReactiveObject };
package/build/types.js CHANGED
@@ -1 +1 @@
1
- import { TYPE } from './constants.js';
1
+ export {};
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "type": "module",
18
18
  "types": "build/index.d.ts",
19
- "version": "0.20.1",
19
+ "version": "0.21.0",
20
20
  "scripts": {
21
21
  "build": "tsc && tsc-alias",
22
22
  "-": "-"
package/src/constants.ts CHANGED
@@ -29,9 +29,6 @@ const STATE_IN_HEAP = 1 << 3;
29
29
  const STATE_NOTIFY_MASK = (STATE_CHECK | STATE_DIRTY);
30
30
 
31
31
 
32
- const TYPE = Symbol('reactivity.type');
33
-
34
-
35
32
  export {
36
33
  COMPUTED,
37
34
  REACTIVE_ARRAY,
@@ -46,6 +43,5 @@ export {
46
43
  STATE_DIRTY,
47
44
  STATE_IN_HEAP,
48
45
  STATE_NONE,
49
- STATE_RECOMPUTING,
50
- TYPE
46
+ STATE_RECOMPUTING
51
47
  };
@@ -1,5 +1,5 @@
1
1
  import { isArray } from '@esportsplus/utilities';
2
- import { REACTIVE_ARRAY, TYPE } from '~/constants';
2
+ import { REACTIVE_ARRAY } from '~/constants';
3
3
  import { isReactiveObject } from './object';
4
4
 
5
5
 
@@ -22,7 +22,9 @@ type Events<T> = {
22
22
  shift: {
23
23
  item: T;
24
24
  };
25
- sort: undefined;
25
+ sort: {
26
+ order: number[];
27
+ };
26
28
  splice: {
27
29
  deleteCount: number;
28
30
  items: T[];
@@ -200,8 +202,46 @@ class ReactiveArray<T> extends Array<T> {
200
202
  }
201
203
 
202
204
  sort(fn?: (a: T, b: T) => number) {
205
+ let before = new Array(this.length) as T[];
206
+
207
+ for (let i = 0, n = before.length; i < n; i++) {
208
+ before[i] = this[i];
209
+ }
210
+
203
211
  super.sort(fn);
204
- this.dispatch('sort');
212
+
213
+ let buckets = new Map<any, number[]>(),
214
+ cursors = new Map<any, number>(),
215
+ order = new Array(this.length);
216
+
217
+ for (let i = 0, n = before.length; i < n; i++) {
218
+ let value = before[i],
219
+ list = buckets.get(value);
220
+
221
+ if (!list) {
222
+ buckets.set(value, [i]);
223
+ }
224
+ else {
225
+ list.push(i);
226
+ }
227
+ }
228
+
229
+ for (let i = 0, n = this.length; i < n; i++) {
230
+ let value = this[i],
231
+ list = buckets.get(value);
232
+
233
+ if (!list) {
234
+ order[i] = i;
235
+ continue;
236
+ }
237
+
238
+ let cursor = cursors.get(value) || 0;
239
+
240
+ order[i] = list[cursor];
241
+ cursors.set(value, cursor + 1);
242
+ }
243
+
244
+ this.dispatch('sort', { order });
205
245
 
206
246
  return this;
207
247
  }
@@ -233,7 +273,7 @@ class ReactiveArray<T> extends Array<T> {
233
273
  }
234
274
  }
235
275
 
236
- Object.defineProperty(ReactiveArray.prototype, TYPE, { value: REACTIVE_ARRAY });
276
+ Object.defineProperty(ReactiveArray.prototype, REACTIVE_ARRAY, { value: true });
237
277
 
238
278
 
239
279
  export { ReactiveArray };
@@ -1,7 +1,7 @@
1
1
  import { defineProperty, isArray, isPromise } from '@esportsplus/utilities';
2
2
  import { computed, dispose, effect, read, root, set, signal } from '~/system';
3
3
  import { Computed, Signal } from '~/types';
4
- import { REACTIVE_OBJECT, TYPE } from '~/constants';
4
+ import { REACTIVE_OBJECT } from '~/constants';
5
5
  import { ReactiveArray } from './array';
6
6
 
7
7
 
@@ -105,11 +105,11 @@ class ReactiveObject<T extends Record<PropertyKey, unknown>> {
105
105
  }
106
106
  }
107
107
 
108
- Object.defineProperty(ReactiveObject.prototype, TYPE, { value: REACTIVE_OBJECT });
108
+ Object.defineProperty(ReactiveObject.prototype, REACTIVE_OBJECT, { value: true });
109
109
 
110
110
 
111
111
  const isReactiveObject = (value: any): value is ReactiveObject<any> => {
112
- return typeof value === 'object' && value !== null && value[TYPE] === REACTIVE_OBJECT;
112
+ return typeof value === 'object' && value !== null && value[REACTIVE_OBJECT] === true;
113
113
  };
114
114
 
115
115
 
package/src/system.ts CHANGED
@@ -2,8 +2,7 @@ import { isObject } from '@esportsplus/utilities';
2
2
  import {
3
3
  COMPUTED, SIGNAL,
4
4
  STABILIZER_IDLE, STABILIZER_RESCHEDULE, STABILIZER_RUNNING, STABILIZER_SCHEDULED,
5
- STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING,
6
- TYPE
5
+ STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_NOTIFY_MASK, STATE_RECOMPUTING
7
6
  } from './constants';
8
7
  import { Computed, Link, Signal } from './types';
9
8
 
@@ -322,7 +321,7 @@ function unlink(link: Link): Link | null {
322
321
  if (prevSub) {
323
322
  prevSub.nextSub = nextSub;
324
323
  }
325
- else if ((dep.subs = nextSub) === null && dep[TYPE] === COMPUTED) {
324
+ else if ((dep.subs = nextSub) === null && dep.type === COMPUTED) {
326
325
  dispose(dep);
327
326
  }
328
327
 
@@ -341,7 +340,7 @@ function update<T>(computed: Computed<T>): void {
341
340
  for (let link = computed.deps; link; link = link.nextDep) {
342
341
  let dep = link.dep;
343
342
 
344
- if (dep[TYPE] === COMPUTED) {
343
+ if (dep.type === COMPUTED) {
345
344
  update(dep);
346
345
 
347
346
  if (computed.state & STATE_DIRTY) {
@@ -361,7 +360,6 @@ function update<T>(computed: Computed<T>): void {
361
360
 
362
361
  const computed = <T>(fn: Computed<T>['fn']): Computed<T> => {
363
362
  let self: Computed<T> = {
364
- [TYPE]: COMPUTED,
365
363
  cleanup: null,
366
364
  deps: null,
367
365
  depsTail: null,
@@ -372,6 +370,7 @@ const computed = <T>(fn: Computed<T>['fn']): Computed<T> => {
372
370
  state: STATE_NONE,
373
371
  subs: null,
374
372
  subsTail: null,
373
+ type: COMPUTED,
375
374
  value: undefined as T,
376
375
  };
377
376
 
@@ -428,11 +427,11 @@ const effect = <T>(fn: Computed<T>['fn']) => {
428
427
  };
429
428
 
430
429
  const isComputed = (value: unknown): value is Computed<unknown> => {
431
- return isObject(value) && value[TYPE] === COMPUTED;
430
+ return isObject(value) && value.type === COMPUTED;
432
431
  };
433
432
 
434
433
  const isSignal = (value: unknown): value is Signal<unknown> => {
435
- return isObject(value) && value[TYPE] === SIGNAL;
434
+ return isObject(value) && value.type === SIGNAL;
436
435
  };
437
436
 
438
437
  const onCleanup = (fn: VoidFunction): typeof fn => {
@@ -461,7 +460,7 @@ const read = <T>(node: Signal<T> | Computed<T>): T => {
461
460
  if (observer) {
462
461
  link(node, observer);
463
462
 
464
- if (node[TYPE] === COMPUTED) {
463
+ if (node.type === COMPUTED) {
465
464
  let height = node.height;
466
465
 
467
466
  if (height >= observer.height) {
@@ -542,9 +541,9 @@ const set = <T>(signal: Signal<T>, value: T) => {
542
541
 
543
542
  const signal = <T>(value: T): Signal<T> => {
544
543
  return {
545
- [TYPE]: SIGNAL,
546
544
  subs: null,
547
545
  subsTail: null,
546
+ type: SIGNAL,
548
547
  value,
549
548
  };
550
549
  };
package/src/types.ts CHANGED
@@ -1,10 +1,9 @@
1
- import { COMPUTED, SIGNAL, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING, TYPE } from './constants';
1
+ import { COMPUTED, SIGNAL, STATE_CHECK, STATE_DIRTY, STATE_IN_HEAP, STATE_NONE, STATE_RECOMPUTING } from './constants';
2
2
  import { ReactiveArray } from './reactive/array';
3
3
  import { ReactiveObject } from './reactive/object';
4
4
 
5
5
 
6
6
  interface Computed<T> {
7
- [TYPE]: typeof COMPUTED;
8
7
  cleanup: VoidFunction | VoidFunction[] | null;
9
8
  deps: Link | null;
10
9
  depsTail: Link | null;
@@ -20,6 +19,7 @@ interface Computed<T> {
20
19
  typeof STATE_RECOMPUTING;
21
20
  subs: Link | null;
22
21
  subsTail: Link | null;
22
+ type: typeof COMPUTED;
23
23
  value: T;
24
24
  }
25
25
 
@@ -33,9 +33,9 @@ interface Link {
33
33
  }
34
34
 
35
35
  type Signal<T> = {
36
- [TYPE]: typeof SIGNAL;
37
36
  subs: Link | null;
38
37
  subsTail: Link | null;
38
+ type: typeof SIGNAL;
39
39
  value: T;
40
40
  };
41
41