@esportsplus/reactivity 0.1.14 → 0.1.17

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/build/macro.d.ts CHANGED
@@ -6,5 +6,5 @@ declare class Macro<A extends unknown[], R> extends CustomFunction {
6
6
  constructor(fn: Function<A, R>, options?: Options);
7
7
  dispose(): void;
8
8
  }
9
- declare const _default: <A extends unknown[], R>(fn: () => (...args: A) => R, options?: Options) => Macro<A, R>;
9
+ declare const _default: <A extends unknown[], R>(fn: (instance: Computed<(...args: A) => R>) => (...args: A) => R, options?: Options) => Macro<A, R>;
10
10
  export default _default;
@@ -1,6 +1,6 @@
1
1
  import { Computed, Object, Options, Signal } from '../types';
2
2
  import { ReactiveArray, ReactiveObjectArray } from './array';
3
- type Node = Computed<unknown> | ReactiveArray<unknown> | ReactiveObjectArray<Object> | Signal<unknown>;
3
+ type Node = Computed<any> | ReactiveArray<any> | ReactiveObjectArray<Object> | Signal<any>;
4
4
  declare class ReactiveObject<T extends Object> {
5
5
  nodes: Record<PropertyKey, Node>;
6
6
  constructor(data: T, options?: Options);
package/build/signal.d.ts CHANGED
@@ -20,12 +20,12 @@ declare class Reactive<T> {
20
20
  once<T>(event: Event, listener: Listener<T>): void;
21
21
  set(value: T): T;
22
22
  }
23
- declare const computed: <T>(fn: () => T extends unknown ? T : NeverAsync<T>, options?: Options) => Computed<T>;
23
+ declare const computed: <T>(fn: (instance: Computed<T>) => T, options?: Options) => Computed<T>;
24
24
  declare const dispose: <T extends {
25
25
  dispose: VoidFunction;
26
26
  }>(dispose?: T | T[] | null | undefined) => T | T[] | null | undefined;
27
27
  declare const effect: (fn: Effect['fn']) => Effect;
28
- declare const root: <T>(fn: (root: Root) => T, scheduler?: Scheduler | null) => T;
28
+ declare const root: <T>(fn: (instance: Root) => T, scheduler?: Scheduler) => T;
29
29
  declare const signal: <T>(value: T, options?: Options) => Signal<T>;
30
30
  export { computed, dispose, effect, root, signal };
31
31
  export { Reactive };
package/build/signal.js CHANGED
@@ -65,6 +65,7 @@ class Reactive {
65
65
  if (this.state === DISPOSED) {
66
66
  return;
67
67
  }
68
+ this.dispatch('cleanup', this);
68
69
  this.dispatch('dispose', this);
69
70
  removeSourceObservers(this, 0);
70
71
  this.listeners = null;
@@ -96,7 +97,10 @@ class Reactive {
96
97
  }
97
98
  on(event, listener) {
98
99
  if (this.state === DIRTY) {
99
- return;
100
+ if (event !== 'cleanup') {
101
+ throw new Error(`Reactivity: events set within computed or effects must use the 'cleanup' event name`);
102
+ }
103
+ listener.once = true;
100
104
  }
101
105
  if (this.listeners === null) {
102
106
  this.listeners = { [event]: [listener] };
@@ -155,12 +159,12 @@ function removeSourceObservers(node, start) {
155
159
  return;
156
160
  }
157
161
  for (let i = start, n = node.sources.length; i < n; i++) {
158
- let source = node.sources[i];
159
- if (source.observers === null) {
162
+ let observers = node.sources[i].observers;
163
+ if (observers === null) {
160
164
  continue;
161
165
  }
162
- source.observers[source.observers.indexOf(node)] = source.observers[source.observers.length - 1];
163
- source.observers.pop();
166
+ observers[observers.indexOf(node)] = observers[observers.length - 1];
167
+ observers.pop();
164
168
  }
165
169
  }
166
170
  function sync(node) {
@@ -185,8 +189,9 @@ function update(node) {
185
189
  observer = node;
186
190
  observers = null;
187
191
  try {
192
+ node.dispatch('cleanup');
188
193
  node.dispatch('update');
189
- let value = node.fn.call(node);
194
+ let value = node.fn.call(null, node);
190
195
  if (observers) {
191
196
  removeSourceObservers(node, index);
192
197
  if (node.sources !== null && index > 0) {
@@ -200,7 +205,7 @@ function update(node) {
200
205
  }
201
206
  for (let i = index, n = node.sources.length; i < n; i++) {
202
207
  let source = node.sources[i];
203
- if (!source.observers) {
208
+ if (source.observers === null) {
204
209
  source.observers = [node];
205
210
  }
206
211
  else {
@@ -249,9 +254,9 @@ const effect = (fn) => {
249
254
  update(instance);
250
255
  return instance;
251
256
  };
252
- const root = (fn, scheduler = null) => {
257
+ const root = (fn, scheduler) => {
253
258
  let o = observer, s = scope;
254
- if (scheduler === null) {
259
+ if (scheduler === undefined) {
255
260
  if (scope === null) {
256
261
  throw new Error('Reactivity: `root` cannot be created without a task scheduler');
257
262
  }
@@ -261,7 +266,7 @@ const root = (fn, scheduler = null) => {
261
266
  scope = new Reactive(CLEAN, ROOT, null);
262
267
  scope.scheduler = scheduler;
263
268
  scope.tracking = fn.length > 0;
264
- let result = fn(scope);
269
+ let result = fn.call(null, scope);
265
270
  observer = o;
266
271
  scope = s;
267
272
  return result;
package/build/types.d.ts CHANGED
@@ -1,14 +1,15 @@
1
1
  import { Function, NeverAsync, Prettify } from '@esportsplus/typescript';
2
2
  import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT, ROOT, SIGNAL } from './constants';
3
3
  import { Reactive } from './signal';
4
- type Base<T> = Omit<Reactive<T>, 'changed' | 'fn' | 'scheduler' | 'task' | 'tracking'>;
4
+ type Base<T> = Omit<Reactive<T>, 'changed' | 'fn' | 'get' | 'scheduler' | 'set' | 'task' | 'tracking'>;
5
5
  type Changed = (a: unknown, b: unknown) => boolean;
6
6
  type Computed<T> = {
7
7
  changed: Changed;
8
- fn: NeverAsync<() => T>;
8
+ fn: NeverAsync<(instance: Computed<T>) => T>;
9
+ get(): T;
9
10
  } & Base<T>;
10
11
  type Effect = {
11
- fn: NeverAsync<(node: Effect) => void>;
12
+ fn: NeverAsync<(instance: Effect) => void>;
12
13
  root: Root;
13
14
  task: Function;
14
15
  } & Omit<Base<void>, 'value'>;
@@ -28,10 +29,12 @@ type Root = {
28
29
  scheduler: Scheduler;
29
30
  tracking: boolean;
30
31
  value: void;
31
- } & Omit<Reactive<void>, 'changed' | 'fn' | 'root' | 'task'>;
32
+ } & Omit<Reactive<void>, 'root'>;
32
33
  type Scheduler = (fn: Function) => unknown;
33
34
  type Signal<T> = {
34
35
  changed: Changed;
36
+ get(): T;
37
+ set(value: T): T;
35
38
  } & Base<T>;
36
39
  type State = typeof CHECK | typeof CLEAN | typeof DIRTY | typeof DISPOSED;
37
40
  type Type = typeof COMPUTED | typeof EFFECT | typeof ROOT | typeof SIGNAL;
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "@esportsplus/custom-function": "^0.0.1"
5
5
  },
6
6
  "devDependencies": {
7
- "@esportsplus/typescript": "^0.0.13"
7
+ "@esportsplus/typescript": "^0.0.15"
8
8
  },
9
9
  "main": "build/index.js",
10
10
  "name": "@esportsplus/reactivity",
@@ -16,5 +16,5 @@
16
16
  "prepublishOnly": "npm run build"
17
17
  },
18
18
  "types": "build/index.d.ts",
19
- "version": "0.1.14"
19
+ "version": "0.1.17"
20
20
  }
@@ -4,7 +4,7 @@ import { defineProperty, isArray } from '~/utilities';
4
4
  import { ReactiveArray, ReactiveObjectArray } from './array';
5
5
 
6
6
 
7
- type Node = Computed<unknown> | ReactiveArray<unknown> | ReactiveObjectArray<Object> | Signal<unknown>;
7
+ type Node = Computed<any> | ReactiveArray<any> | ReactiveObjectArray<Object> | Signal<any>;
8
8
 
9
9
 
10
10
  class ReactiveObject<T extends Object> {
package/src/signal.ts CHANGED
@@ -88,6 +88,7 @@ class Reactive<T> {
88
88
  return;
89
89
  }
90
90
 
91
+ this.dispatch('cleanup', this);
91
92
  this.dispatch('dispose', this);
92
93
 
93
94
  removeSourceObservers(this, 0);
@@ -125,9 +126,12 @@ class Reactive<T> {
125
126
  }
126
127
 
127
128
  on<T>(event: Event, listener: Listener<T>) {
128
- // Events cannot be set within effects or computed's
129
129
  if (this.state === DIRTY) {
130
- return;
130
+ if (event !== 'cleanup') {
131
+ throw new Error(`Reactivity: events set within computed or effects must use the 'cleanup' event name`);
132
+ }
133
+
134
+ listener.once = true;
131
135
  }
132
136
 
133
137
  if (this.listeners === null) {
@@ -186,7 +190,7 @@ function notify<T>(nodes: Reactive<T>[] | null, state: typeof CHECK | typeof DIR
186
190
 
187
191
  if (node.state < state) {
188
192
  if (node.type === EFFECT && node.state === CLEAN) {
189
- node.root!.scheduler((node as any as Effect).task);
193
+ (node as Effect).root.scheduler((node as Effect).task);
190
194
  }
191
195
 
192
196
  node.state = state;
@@ -201,14 +205,14 @@ function removeSourceObservers<T>(node: Reactive<T>, start: number) {
201
205
  }
202
206
 
203
207
  for (let i = start, n = node.sources.length; i < n; i++) {
204
- let source = node.sources[i];
208
+ let observers = node.sources[i].observers;
205
209
 
206
- if (source.observers === null) {
210
+ if (observers === null) {
207
211
  continue;
208
212
  }
209
213
 
210
- source.observers[source.observers.indexOf(node)] = source.observers[source.observers.length - 1];
211
- source.observers.pop();
214
+ observers[observers.indexOf(node)] = observers[observers.length - 1];
215
+ observers.pop();
212
216
  }
213
217
  }
214
218
 
@@ -244,10 +248,11 @@ function update<T>(node: Reactive<T>) {
244
248
  observers = null as typeof observers;
245
249
 
246
250
  try {
251
+ node.dispatch('cleanup');
247
252
  node.dispatch('update');
248
253
 
249
254
  // @ts-ignore
250
- let value = node.fn.call(node);
255
+ let value = node.fn.call(null, node);
251
256
 
252
257
  if (observers) {
253
258
  removeSourceObservers(node, index);
@@ -266,7 +271,7 @@ function update<T>(node: Reactive<T>) {
266
271
  for (let i = index, n = node.sources.length; i < n; i++) {
267
272
  let source = node.sources[i];
268
273
 
269
- if (!source.observers) {
274
+ if (source.observers === null) {
270
275
  source.observers = [node];
271
276
  }
272
277
  else {
@@ -294,12 +299,12 @@ function update<T>(node: Reactive<T>) {
294
299
 
295
300
 
296
301
  const computed = <T>(fn: Computed<T>['fn'], options?: Options) => {
297
- let instance = new Reactive(DIRTY, COMPUTED, undefined as T) as any as Computed<T>;
302
+ let instance = new Reactive(DIRTY, COMPUTED, undefined as T);
298
303
 
299
304
  instance.changed = options?.changed || changed;
300
305
  instance.fn = fn;
301
306
 
302
- return instance;
307
+ return instance as Computed<T>;
303
308
  };
304
309
 
305
310
  const dispose = <T extends { dispose: VoidFunction }>(dispose?: T[] | T | null) => {
@@ -318,21 +323,21 @@ const dispose = <T extends { dispose: VoidFunction }>(dispose?: T[] | T | null)
318
323
  };
319
324
 
320
325
  const effect = (fn: Effect['fn']) => {
321
- let instance = new Reactive(DIRTY, EFFECT, null) as any as Effect;
326
+ let instance = new Reactive(DIRTY, EFFECT, null);
322
327
 
323
328
  instance.fn = fn;
324
329
  instance.task = () => instance.get();
325
330
 
326
- update(instance as any as Reactive<void>);
331
+ update(instance);
327
332
 
328
- return instance;
333
+ return instance as Effect;
329
334
  };
330
335
 
331
- const root = <T>(fn: NeverAsync<(root: Root) => T>, scheduler: Scheduler | null = null) => {
336
+ const root = <T>(fn: NeverAsync<(instance: Root) => T>, scheduler?: Scheduler) => {
332
337
  let o = observer,
333
338
  s = scope;
334
339
 
335
- if (scheduler === null) {
340
+ if (scheduler === undefined) {
336
341
  if (scope === null) {
337
342
  throw new Error('Reactivity: `root` cannot be created without a task scheduler');
338
343
  }
@@ -343,10 +348,10 @@ const root = <T>(fn: NeverAsync<(root: Root) => T>, scheduler: Scheduler | null
343
348
  observer = null;
344
349
 
345
350
  scope = new Reactive(CLEAN, ROOT, null) as any as Root;
346
- scope.scheduler = scheduler as Scheduler;
351
+ scope.scheduler = scheduler;
347
352
  scope.tracking = fn.length > 0;
348
353
 
349
- let result = fn(scope);
354
+ let result = fn.call(null, scope);
350
355
 
351
356
  observer = o;
352
357
  scope = s;
@@ -355,11 +360,11 @@ const root = <T>(fn: NeverAsync<(root: Root) => T>, scheduler: Scheduler | null
355
360
  };
356
361
 
357
362
  const signal = <T>(value: T, options?: Options) => {
358
- let instance = new Reactive(CLEAN, SIGNAL, value) as any as Signal<T>;
363
+ let instance = new Reactive(CLEAN, SIGNAL, value);
359
364
 
360
365
  instance.changed = options?.changed || changed;
361
366
 
362
- return instance;
367
+ return instance as Signal<T>;
363
368
  };
364
369
 
365
370
 
package/src/types.ts CHANGED
@@ -3,17 +3,18 @@ import { CHECK, CLEAN, COMPUTED, DIRTY, DISPOSED, EFFECT, ROOT, SIGNAL } from '.
3
3
  import { Reactive } from './signal';
4
4
 
5
5
 
6
- type Base<T> = Omit<Reactive<T>, 'changed' | 'fn' | 'scheduler' | 'task' | 'tracking'>;
6
+ type Base<T> = Omit<Reactive<T>, 'changed' | 'fn' | 'get' | 'scheduler' | 'set' | 'task' | 'tracking'>;
7
7
 
8
8
  type Changed = (a: unknown, b: unknown) => boolean;
9
9
 
10
10
  type Computed<T> = {
11
11
  changed: Changed;
12
- fn: NeverAsync<() => T>;
12
+ fn: NeverAsync<(instance: Computed<T>) => T>;
13
+ get(): T;
13
14
  } & Base<T>;
14
15
 
15
16
  type Effect = {
16
- fn: NeverAsync<(node: Effect) => void>;
17
+ fn: NeverAsync<(instance: Effect) => void>;
17
18
  root: Root;
18
19
  task: Function;
19
20
  } & Omit<Base<void>, 'value'>;
@@ -36,12 +37,14 @@ type Root = {
36
37
  scheduler: Scheduler;
37
38
  tracking: boolean;
38
39
  value: void;
39
- } & Omit<Reactive<void>, 'changed' | 'fn' | 'root' | 'task'>;
40
+ } & Omit<Reactive<void>, 'root'>;
40
41
 
41
42
  type Scheduler = (fn: Function) => unknown;
42
43
 
43
44
  type Signal<T> = {
44
45
  changed: Changed;
46
+ get(): T;
47
+ set(value: T): T;
45
48
  } & Base<T>;
46
49
 
47
50
  type State = typeof CHECK | typeof CLEAN | typeof DIRTY | typeof DISPOSED;