@esportsplus/reactivity 0.0.2 → 0.0.5

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/index.d.ts CHANGED
@@ -1,4 +1,29 @@
1
- declare const effect: <T>(value: () => T) => void;
2
- declare const reactive: <T>(value: T) => T;
3
- declare const tick: () => void;
4
- export { effect, reactive, tick };
1
+ import { Queue } from './types';
2
+ type Infer<T> = T extends (...args: any[]) => any ? Infer<ReturnType<T>> : T extends Record<string, any> ? {
3
+ [K in keyof T]: Infer<T[K]>;
4
+ } : Reactive<T>;
5
+ declare class Reactive<T> {
6
+ private effect;
7
+ private fn?;
8
+ private observers;
9
+ private queue;
10
+ private sources;
11
+ private state;
12
+ private value;
13
+ cleanup: ((old: T) => void)[] | null;
14
+ constructor(input: ((fn: VoidFunction) => T) | T, queue?: Queue | null, effect?: boolean);
15
+ get(): T;
16
+ set(value: T): void;
17
+ private mark;
18
+ private removeParentObservers;
19
+ private sync;
20
+ private update;
21
+ }
22
+ declare const effect: (queue: Queue) => <T>(value: () => T) => void;
23
+ declare const reactive: <T>(value: T) => Infer<T>;
24
+ declare const _default: {
25
+ effect: (queue: Queue) => <T>(value: () => T) => void;
26
+ reactive: <T_1>(value: T_1) => Infer<T_1>;
27
+ };
28
+ export default _default;
29
+ export { effect, reactive };
package/build/index.js CHANGED
@@ -1,27 +1,29 @@
1
1
  import { CLEAN, CHECK, DIRTY } from './symbols';
2
2
  import obj from './obj';
3
- let index = 0, queue = [], reaction = null, running = false, stack = null;
3
+ let index = 0, reaction = null, stack = null;
4
4
  class Reactive {
5
5
  effect;
6
6
  fn;
7
7
  observers = null;
8
+ queue = null;
8
9
  sources = null;
9
10
  state;
10
11
  value;
11
12
  cleanup = null;
12
- constructor(_, effect = false) {
13
+ constructor(input, queue = null, effect = false) {
13
14
  this.effect = effect;
14
- if (typeof _ === 'function') {
15
- this.fn = _;
15
+ if (typeof input === 'function') {
16
+ this.fn = input;
16
17
  this.state = DIRTY;
17
18
  this.value = undefined;
18
19
  if (effect) {
20
+ this.queue = queue;
19
21
  this.update();
20
22
  }
21
23
  }
22
24
  else {
23
25
  this.state = CLEAN;
24
- this.value = _;
26
+ this.value = input;
25
27
  }
26
28
  }
27
29
  get() {
@@ -54,7 +56,12 @@ class Reactive {
54
56
  mark(state) {
55
57
  if (this.state < state) {
56
58
  if (this.state === CLEAN && this.effect) {
57
- queue.push(this);
59
+ if (!this.queue) {
60
+ throw new Error('Effects cannot be updated without a queue');
61
+ }
62
+ this.queue.add(async () => {
63
+ await this.get();
64
+ });
58
65
  }
59
66
  this.state = state;
60
67
  if (!this.observers) {
@@ -153,24 +160,20 @@ class Reactive {
153
160
  this.state = CLEAN;
154
161
  }
155
162
  }
156
- const effect = (value) => {
157
- new Reactive(value, true);
163
+ const effect = (queue) => {
164
+ return (value) => {
165
+ new Reactive(value, queue, true);
166
+ };
158
167
  };
159
168
  const reactive = (value) => {
169
+ let v;
160
170
  if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
161
- return obj(value);
162
- }
163
- return new Reactive(value);
164
- };
165
- const tick = () => {
166
- if (running) {
167
- return;
171
+ v = obj(value);
168
172
  }
169
- running = true;
170
- for (let i = 0, n = queue.length; i < n; i++) {
171
- queue[i].get();
173
+ else {
174
+ v = new Reactive(value);
172
175
  }
173
- queue.length = 0;
174
- running = false;
176
+ return v;
175
177
  };
176
- export { effect, reactive, tick };
178
+ export default { effect, reactive };
179
+ export { effect, reactive };
package/build/obj.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- declare const factory: <T>(values: T) => T;
1
+ declare const factory: <T extends Record<string, any>>(values: T) => {};
2
2
  export default factory;
package/build/obj.js CHANGED
@@ -1,21 +1,24 @@
1
1
  import { reactive } from './index';
2
+ function setup(value) {
3
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
4
+ return factory(value);
5
+ }
6
+ return reactive(value);
7
+ }
2
8
  const factory = (values) => {
3
9
  let lazy = {}, properties = {};
4
10
  for (let key in values) {
5
11
  properties[key] = {
6
12
  get() {
7
13
  if (!lazy[key]) {
8
- let value = values[key];
9
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
10
- lazy[key] = factory(value);
11
- }
12
- else {
13
- lazy[key] = reactive(value);
14
- }
14
+ lazy[key] = setup(values[key]);
15
15
  }
16
- return lazy[key]?.get() || lazy[key];
16
+ return lazy[key].get();
17
17
  },
18
18
  set(value) {
19
+ if (!lazy[key]) {
20
+ lazy[key] = setup(values[key]);
21
+ }
19
22
  lazy[key].set(value);
20
23
  }
21
24
  };
package/build/types.d.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  import { CLEAN, CHECK, DIRTY } from './symbols';
2
+ type Queue = {
3
+ add: (fn: () => Promise<void> | void) => void;
4
+ };
2
5
  type State = typeof CHECK | typeof CLEAN | typeof DIRTY;
3
- export { State };
6
+ export { Queue, State };
package/package.json CHANGED
@@ -2,8 +2,8 @@
2
2
  "author": "ICJR",
3
3
  "description": "Reactivity",
4
4
  "devDependencies": {
5
- "tsc-alias": "^1.8.1",
6
- "typescript": "^4.9.3"
5
+ "tsc-alias": "^1.8.2",
6
+ "typescript": "^4.9.4"
7
7
  },
8
8
  "main": "./build/index.js",
9
9
  "name": "@esportsplus/reactivity",
@@ -15,5 +15,5 @@
15
15
  "prepublishOnly": "npm run build"
16
16
  },
17
17
  "types": "./build/index.d.ts",
18
- "version": "0.0.2"
18
+ "version": "0.0.5"
19
19
  }
package/src/index.ts CHANGED
@@ -1,12 +1,19 @@
1
1
  import { CLEAN, CHECK, DIRTY } from './symbols';
2
- import { State } from './types';
2
+ import { Queue, State } from './types';
3
3
  import obj from './obj';
4
4
 
5
5
 
6
+ type Infer<T> =
7
+ T extends (...args: any[]) => any
8
+ ? Infer<ReturnType<T>>
9
+ : T extends Record<string, any>
10
+ ? { [K in keyof T]: Infer<T[K]> }
11
+ // Requires class type
12
+ : Reactive<T>;
13
+
14
+
6
15
  let index = 0,
7
- queue: Reactive<any>[] = [],
8
16
  reaction: Reactive<any> | null = null,
9
- running: boolean = false,
10
17
  stack: Reactive<any>[] | null = null;
11
18
 
12
19
 
@@ -14,6 +21,7 @@ class Reactive<T> {
14
21
  private effect: boolean;
15
22
  private fn?: (onCleanup: (fn: VoidFunction) => void) => T;
16
23
  private observers: Reactive<any>[] | null = null;
24
+ private queue: Queue | null = null;
17
25
  private sources: Reactive<any>[] | null = null;
18
26
  private state: State;
19
27
  private value: T;
@@ -22,21 +30,22 @@ class Reactive<T> {
22
30
  cleanup: ((old: T) => void)[] | null = null;
23
31
 
24
32
 
25
- constructor(_: ((fn: VoidFunction) => T) | T, effect: boolean = false) {
33
+ constructor(input: ((fn: VoidFunction) => T) | T, queue: Queue | null = null, effect: boolean = false) {
26
34
  this.effect = effect;
27
35
 
28
- if (typeof _ === 'function') {
29
- this.fn = _ as (onCleanup: (fn: VoidFunction) => void) => T;
36
+ if (typeof input === 'function') {
37
+ this.fn = input as (onCleanup: (fn: VoidFunction) => void) => T;
30
38
  this.state = DIRTY;
31
39
  this.value = undefined as any;
32
40
 
33
41
  if (effect) {
42
+ this.queue = queue;
34
43
  this.update();
35
44
  }
36
45
  }
37
46
  else {
38
47
  this.state = CLEAN;
39
- this.value = _;
48
+ this.value = input;
40
49
  }
41
50
  }
42
51
 
@@ -63,7 +72,7 @@ class Reactive<T> {
63
72
  return this.value;
64
73
  }
65
74
 
66
- set(value: T): void {
75
+ set(value: T) {
67
76
  if (this.observers && this.value !== value) {
68
77
  for (let i = 0; i < this.observers.length; i++) {
69
78
  this.observers[i].mark(DIRTY);
@@ -74,11 +83,17 @@ class Reactive<T> {
74
83
  }
75
84
 
76
85
 
77
- private mark(state: typeof CHECK | typeof DIRTY): void {
86
+ private mark(state: typeof CHECK | typeof DIRTY) {
78
87
  if (this.state < state) {
79
88
  // If previous state was clean we need to update effects
80
89
  if (this.state === CLEAN && this.effect) {
81
- queue.push(this);
90
+ if (!this.queue) {
91
+ throw new Error('Effects cannot be updated without a queue');
92
+ }
93
+
94
+ this.queue.add(async () => {
95
+ await this.get();
96
+ });
82
97
  }
83
98
 
84
99
  this.state = state;
@@ -94,7 +109,7 @@ class Reactive<T> {
94
109
  }
95
110
 
96
111
  // We don't actually delete sources here because we're replacing the entire array soon
97
- private removeParentObservers(): void {
112
+ private removeParentObservers() {
98
113
  if (!this.sources) {
99
114
  return;
100
115
  }
@@ -108,7 +123,7 @@ class Reactive<T> {
108
123
  }
109
124
 
110
125
  // Update if dirty or if a parent is dirty
111
- private sync(): void {
126
+ private sync() {
112
127
  // If we are potentially dirty, see if we have a parent who has actually changed value
113
128
  if (this.state === CHECK && this.sources) {
114
129
  for (let i = 0, n = this.sources.length; i < n; i++) {
@@ -132,7 +147,7 @@ class Reactive<T> {
132
147
  this.state = CLEAN;
133
148
  }
134
149
 
135
- private update(): void {
150
+ private update() {
136
151
  let previous = {
137
152
  index: index,
138
153
  reaction: reaction,
@@ -217,35 +232,25 @@ class Reactive<T> {
217
232
  }
218
233
 
219
234
 
220
-
221
- const effect = <T>(value: () => T) => {
222
- new Reactive(value, true);
235
+ const effect = (queue: Queue) => {
236
+ return <T>(value: () => T) => {
237
+ new Reactive(value, queue, true);
238
+ };
223
239
  };
224
240
 
225
- const reactive = <T>(value: T): T => {
226
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
227
- return obj(value);
228
- }
229
-
230
- return new Reactive(value) as T;
231
- };
241
+ const reactive = <T>(value: T) => {
242
+ let v;
232
243
 
233
- const tick = () => {
234
- if (running) {
235
- return;
244
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
245
+ v = obj(value);
236
246
  }
237
-
238
- running = true;
239
-
240
- for (let i = 0, n = queue.length; i < n; i++) {
241
- queue[i].get();
247
+ else {
248
+ v = new Reactive(value);
242
249
  }
243
250
 
244
- queue.length = 0;
245
- running = false;
251
+ return v as Infer<T>;
246
252
  };
247
253
 
248
254
 
249
- export { effect, reactive, tick };
250
-
251
-
255
+ export default { effect, reactive };
256
+ export { effect, reactive };
package/src/obj.ts CHANGED
@@ -1,7 +1,21 @@
1
1
  import { reactive } from './index';
2
2
 
3
3
 
4
- const factory = <T>(values: T) => {
4
+ function setup(value: unknown) {
5
+ // if (Array.isArray(value)) {
6
+ // TODO: Need a solution
7
+ // }
8
+ // TODO: Can remove isArray once solution is found ^
9
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
10
+ return factory(value);
11
+ }
12
+
13
+ return reactive(value);
14
+ }
15
+
16
+
17
+ // TODO: Typecheck on values tro get rid of lazy var
18
+ const factory = <T extends Record<string, any>>(values: T) => {
5
19
  let lazy: Record<string, any> = {},
6
20
  properties: PropertyDescriptorMap = {};
7
21
 
@@ -9,29 +23,22 @@ const factory = <T>(values: T) => {
9
23
  properties[key] = {
10
24
  get() {
11
25
  if (!lazy[key]) {
12
- let value = values[key];
13
-
14
- // if (Array.isArray(value)) {
15
- // TODO: Need a solution
16
- // }
17
- // TODO: Can remove isArray once solution is found ^
18
- if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
19
- lazy[key] = factory(value as Record<string, unknown>);
20
- }
21
- else {
22
- lazy[key] = reactive(value);
23
- }
26
+ lazy[key] = setup(values[key]);
24
27
  }
25
28
 
26
- return lazy[key]?.get() || lazy[key];
29
+ return lazy[key].get();
27
30
  },
28
31
  set(value: unknown) {
32
+ if (!lazy[key]) {
33
+ lazy[key] = setup(values[key]);
34
+ }
35
+
29
36
  lazy[key].set(value);
30
37
  }
31
38
  };
32
39
  }
33
40
 
34
- return Object.defineProperties({}, properties) as T;
41
+ return Object.defineProperties({}, properties);
35
42
  };
36
43
 
37
44
 
package/src/types.ts CHANGED
@@ -1,7 +1,11 @@
1
1
  import { CLEAN, CHECK, DIRTY } from './symbols';
2
2
 
3
3
 
4
+ type Queue = {
5
+ add: (fn: () => Promise<void> | void) => void;
6
+ };
7
+
4
8
  type State = typeof CHECK | typeof CLEAN | typeof DIRTY;
5
9
 
6
10
 
7
- export { State };
11
+ export { Queue, State };