@esportsplus/reactivity 0.0.6 → 0.0.8
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 +9 -25
- package/build/index.js +4 -183
- package/build/methods/effect.d.ts +2 -0
- package/build/methods/effect.js +4 -0
- package/build/methods/index.d.ts +3 -0
- package/build/methods/index.js +3 -0
- package/build/methods/reactive.d.ts +3 -0
- package/{src/obj.ts → build/methods/reactive.js} +22 -28
- package/build/obj.d.ts +1 -1
- package/build/reactive.d.ts +23 -0
- package/build/reactive.js +175 -0
- package/build/types.d.ts +13 -3
- package/package.json +1 -1
- package/src/index.ts +4 -259
- package/src/methods/effect.ts +6 -0
- package/src/methods/index.ts +5 -0
- package/src/methods/reactive.ts +59 -0
- package/src/reactive.ts +245 -0
- package/src/types.ts +24 -3
package/build/index.d.ts
CHANGED
|
@@ -1,28 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type InferValue<T> = T extends Record<string, any> ? T : Reactive<T>;
|
|
4
|
-
declare class Reactive<T> {
|
|
5
|
-
private effect;
|
|
6
|
-
private fn?;
|
|
7
|
-
private observers;
|
|
8
|
-
private queue;
|
|
9
|
-
private sources;
|
|
10
|
-
private state;
|
|
11
|
-
private value;
|
|
12
|
-
cleanup: ((old: T) => void)[] | null;
|
|
13
|
-
constructor(input: ((fn: VoidFunction) => T) | T, queue?: Queue | null, effect?: boolean);
|
|
14
|
-
get(): T;
|
|
15
|
-
set(value: T): void;
|
|
16
|
-
private mark;
|
|
17
|
-
private removeParentObservers;
|
|
18
|
-
private sync;
|
|
19
|
-
private update;
|
|
20
|
-
}
|
|
21
|
-
declare const effect: (queue: Queue) => <T>(value: () => T) => void;
|
|
22
|
-
declare const reactive: <T>(value: T) => Infer<T>;
|
|
1
|
+
import { scheduler } from './reactive';
|
|
2
|
+
import { effect, reactive } from './methods';
|
|
23
3
|
declare const _default: {
|
|
24
|
-
effect:
|
|
25
|
-
reactive: <T_1>(value: T_1) => Infer<T_1>;
|
|
4
|
+
effect: <T>(value: () => T) => void;
|
|
5
|
+
reactive: <T_1>(value: T_1) => import("./types").Infer<T_1>;
|
|
6
|
+
scheduler: {
|
|
7
|
+
add: (scheduler: import("./types").Scheduler) => void;
|
|
8
|
+
delete: (scheduler: import("./types").Scheduler) => void;
|
|
9
|
+
};
|
|
26
10
|
};
|
|
27
11
|
export default _default;
|
|
28
|
-
export { effect, reactive };
|
|
12
|
+
export { effect, reactive, scheduler };
|
package/build/index.js
CHANGED
|
@@ -1,183 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
effect;
|
|
6
|
-
fn;
|
|
7
|
-
observers = null;
|
|
8
|
-
queue = null;
|
|
9
|
-
sources = null;
|
|
10
|
-
state;
|
|
11
|
-
value;
|
|
12
|
-
cleanup = null;
|
|
13
|
-
constructor(input, queue = null, effect = false) {
|
|
14
|
-
this.effect = effect;
|
|
15
|
-
if (typeof input === 'function') {
|
|
16
|
-
this.fn = input;
|
|
17
|
-
this.state = DIRTY;
|
|
18
|
-
this.value = undefined;
|
|
19
|
-
if (effect) {
|
|
20
|
-
this.queue = queue;
|
|
21
|
-
this.update();
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
else {
|
|
25
|
-
this.state = CLEAN;
|
|
26
|
-
this.value = input;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
get() {
|
|
30
|
-
if (reaction) {
|
|
31
|
-
if (!stack && reaction.sources && reaction.sources[index] == this) {
|
|
32
|
-
index++;
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
if (!stack) {
|
|
36
|
-
stack = [this];
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
stack.push(this);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
if (this.fn) {
|
|
44
|
-
this.sync();
|
|
45
|
-
}
|
|
46
|
-
return this.value;
|
|
47
|
-
}
|
|
48
|
-
set(value) {
|
|
49
|
-
if (this.observers && this.value !== value) {
|
|
50
|
-
for (let i = 0; i < this.observers.length; i++) {
|
|
51
|
-
this.observers[i].mark(DIRTY);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
this.value = value;
|
|
55
|
-
}
|
|
56
|
-
mark(state) {
|
|
57
|
-
if (this.state < state) {
|
|
58
|
-
if (this.state === CLEAN && this.effect) {
|
|
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
|
-
});
|
|
65
|
-
}
|
|
66
|
-
this.state = state;
|
|
67
|
-
if (!this.observers) {
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
for (let i = 0; i < this.observers.length; i++) {
|
|
71
|
-
this.observers[i].mark(CHECK);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
removeParentObservers() {
|
|
76
|
-
if (!this.sources) {
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
for (let i = index; i < this.sources.length; i++) {
|
|
80
|
-
let source = this.sources[i];
|
|
81
|
-
source.observers[source.observers.findIndex((v) => v === this)] = source.observers[source.observers.length - 1];
|
|
82
|
-
source.observers.pop();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
sync() {
|
|
86
|
-
if (this.state === CHECK && this.sources) {
|
|
87
|
-
for (let i = 0, n = this.sources.length; i < n; i++) {
|
|
88
|
-
this.sources[i].sync();
|
|
89
|
-
if (this.state === DIRTY) {
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
if (this.state === DIRTY) {
|
|
95
|
-
this.update();
|
|
96
|
-
}
|
|
97
|
-
this.state = CLEAN;
|
|
98
|
-
}
|
|
99
|
-
update() {
|
|
100
|
-
let previous = {
|
|
101
|
-
index: index,
|
|
102
|
-
reaction: reaction,
|
|
103
|
-
stack: stack,
|
|
104
|
-
value: this.value
|
|
105
|
-
};
|
|
106
|
-
index = 0;
|
|
107
|
-
reaction = this;
|
|
108
|
-
stack = [];
|
|
109
|
-
try {
|
|
110
|
-
if (this.cleanup) {
|
|
111
|
-
for (let i = 0, n = this.cleanup.length; i < n; i++) {
|
|
112
|
-
this.cleanup[i](this.value);
|
|
113
|
-
}
|
|
114
|
-
this.cleanup.length = 0;
|
|
115
|
-
}
|
|
116
|
-
this.value = this.fn((fn) => {
|
|
117
|
-
if (!this.cleanup) {
|
|
118
|
-
this.cleanup = [fn];
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
this.cleanup.push(fn);
|
|
122
|
-
}
|
|
123
|
-
});
|
|
124
|
-
if (stack.length) {
|
|
125
|
-
this.removeParentObservers();
|
|
126
|
-
if (this.sources && index > 0) {
|
|
127
|
-
this.sources.length = index + stack.length;
|
|
128
|
-
for (let i = 0; i < stack.length; i++) {
|
|
129
|
-
this.sources[index + i] = stack[i];
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
this.sources = stack;
|
|
134
|
-
}
|
|
135
|
-
for (let i = index; i < this.sources.length; i++) {
|
|
136
|
-
let source = this.sources[i];
|
|
137
|
-
if (!source.observers) {
|
|
138
|
-
source.observers = [this];
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
source.observers.push(this);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
else if (this.sources && index < this.sources.length) {
|
|
146
|
-
this.removeParentObservers();
|
|
147
|
-
this.sources.length = index;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
finally {
|
|
151
|
-
index = previous.index;
|
|
152
|
-
reaction = previous.reaction;
|
|
153
|
-
stack = previous.stack;
|
|
154
|
-
}
|
|
155
|
-
if (this.observers && previous.value !== this.value) {
|
|
156
|
-
for (let i = 0; i < this.observers.length; i++) {
|
|
157
|
-
this.observers[i].state = DIRTY;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
this.state = CLEAN;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
const effect = (queue) => {
|
|
164
|
-
return (value) => {
|
|
165
|
-
new Reactive(value, queue, true);
|
|
166
|
-
};
|
|
167
|
-
};
|
|
168
|
-
const reactive = (value) => {
|
|
169
|
-
let v;
|
|
170
|
-
if (typeof value === 'function') {
|
|
171
|
-
let fn = new Reactive(value);
|
|
172
|
-
v = (...args) => fn.get()(...args);
|
|
173
|
-
}
|
|
174
|
-
else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
175
|
-
v = obj(value);
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
v = new Reactive(value);
|
|
179
|
-
}
|
|
180
|
-
return v;
|
|
181
|
-
};
|
|
182
|
-
export default { effect, reactive };
|
|
183
|
-
export { effect, reactive };
|
|
1
|
+
import { scheduler } from './reactive';
|
|
2
|
+
import { effect, reactive } from './methods';
|
|
3
|
+
export default { effect, reactive, scheduler };
|
|
4
|
+
export { effect, reactive, scheduler };
|
|
@@ -1,45 +1,39 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
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) => {
|
|
19
|
-
let lazy: Record<string, any> = {},
|
|
20
|
-
properties: PropertyDescriptorMap = {};
|
|
21
|
-
|
|
1
|
+
import Reactive from '../reactive';
|
|
2
|
+
function obj(values) {
|
|
3
|
+
let lazy = {}, properties = {};
|
|
22
4
|
for (let key in values) {
|
|
23
5
|
properties[key] = {
|
|
24
6
|
get() {
|
|
25
7
|
if (!lazy[key]) {
|
|
26
8
|
lazy[key] = setup(values[key]);
|
|
27
9
|
}
|
|
28
|
-
|
|
29
10
|
return lazy[key].get();
|
|
30
11
|
},
|
|
31
|
-
set(value
|
|
12
|
+
set(value) {
|
|
32
13
|
if (!lazy[key]) {
|
|
33
14
|
lazy[key] = setup(values[key]);
|
|
34
15
|
}
|
|
35
|
-
|
|
36
16
|
lazy[key].set(value);
|
|
37
17
|
}
|
|
38
18
|
};
|
|
39
19
|
}
|
|
40
|
-
|
|
41
20
|
return Object.defineProperties({}, properties);
|
|
21
|
+
}
|
|
22
|
+
;
|
|
23
|
+
function setup(value) {
|
|
24
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
25
|
+
return obj(value);
|
|
26
|
+
}
|
|
27
|
+
return reactive(value);
|
|
28
|
+
}
|
|
29
|
+
const reactive = (value) => {
|
|
30
|
+
let v;
|
|
31
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
32
|
+
v = obj(value);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
v = new Reactive(value);
|
|
36
|
+
}
|
|
37
|
+
return v;
|
|
42
38
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
export default factory;
|
|
39
|
+
export default reactive;
|
package/build/obj.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const factory: <T
|
|
1
|
+
declare const factory: <T>(values: T) => T;
|
|
2
2
|
export default factory;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Scheduler } from './types';
|
|
2
|
+
declare class Reactive<T> {
|
|
3
|
+
private effect;
|
|
4
|
+
private fn?;
|
|
5
|
+
private observers;
|
|
6
|
+
private sources;
|
|
7
|
+
private state;
|
|
8
|
+
private value;
|
|
9
|
+
cleanup: ((old: T) => void)[] | null;
|
|
10
|
+
constructor(input: ((fn: VoidFunction) => T) | T, effect?: boolean);
|
|
11
|
+
get(): T;
|
|
12
|
+
set(value: T): void;
|
|
13
|
+
private mark;
|
|
14
|
+
private removeParentObservers;
|
|
15
|
+
private sync;
|
|
16
|
+
private update;
|
|
17
|
+
}
|
|
18
|
+
declare const scheduler: {
|
|
19
|
+
add: (scheduler: Scheduler) => void;
|
|
20
|
+
delete: (scheduler: Scheduler) => void;
|
|
21
|
+
};
|
|
22
|
+
export default Reactive;
|
|
23
|
+
export { scheduler };
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { CLEAN, CHECK, DIRTY } from './symbols';
|
|
2
|
+
let index = 0, reaction = null, queue = [], schedulers = new Set, stack = null;
|
|
3
|
+
async function task() {
|
|
4
|
+
for (let i = 0, n = queue.length; i < n; i++) {
|
|
5
|
+
await queue[i].get();
|
|
6
|
+
}
|
|
7
|
+
queue.length = 0;
|
|
8
|
+
}
|
|
9
|
+
class Reactive {
|
|
10
|
+
effect;
|
|
11
|
+
fn;
|
|
12
|
+
observers = null;
|
|
13
|
+
sources = null;
|
|
14
|
+
state;
|
|
15
|
+
value;
|
|
16
|
+
cleanup = null;
|
|
17
|
+
constructor(input, effect = false) {
|
|
18
|
+
this.effect = effect;
|
|
19
|
+
if (typeof input === 'function') {
|
|
20
|
+
this.fn = input;
|
|
21
|
+
this.state = DIRTY;
|
|
22
|
+
this.value = undefined;
|
|
23
|
+
if (effect) {
|
|
24
|
+
this.update();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
this.state = CLEAN;
|
|
29
|
+
this.value = input;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
get() {
|
|
33
|
+
if (reaction) {
|
|
34
|
+
if (!stack && reaction.sources && reaction.sources[index] == this) {
|
|
35
|
+
index++;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
if (!stack) {
|
|
39
|
+
stack = [this];
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
stack.push(this);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (this.fn) {
|
|
47
|
+
this.sync();
|
|
48
|
+
}
|
|
49
|
+
return this.value;
|
|
50
|
+
}
|
|
51
|
+
set(value) {
|
|
52
|
+
if (this.observers && this.value !== value) {
|
|
53
|
+
for (let i = 0; i < this.observers.length; i++) {
|
|
54
|
+
this.observers[i].mark(DIRTY);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
this.value = value;
|
|
58
|
+
}
|
|
59
|
+
mark(state) {
|
|
60
|
+
if (this.state < state) {
|
|
61
|
+
if (this.effect && this.state === CLEAN) {
|
|
62
|
+
queue.push(this);
|
|
63
|
+
for (let scheduler of schedulers) {
|
|
64
|
+
scheduler.schedule();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
this.state = state;
|
|
68
|
+
if (!this.observers) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
for (let i = 0; i < this.observers.length; i++) {
|
|
72
|
+
this.observers[i].mark(CHECK);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
removeParentObservers() {
|
|
77
|
+
if (!this.sources) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
for (let i = index; i < this.sources.length; i++) {
|
|
81
|
+
let source = this.sources[i];
|
|
82
|
+
source.observers[source.observers.findIndex((v) => v === this)] = source.observers[source.observers.length - 1];
|
|
83
|
+
source.observers.pop();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
sync() {
|
|
87
|
+
if (this.state === CHECK && this.sources) {
|
|
88
|
+
for (let i = 0, n = this.sources.length; i < n; i++) {
|
|
89
|
+
this.sources[i].sync();
|
|
90
|
+
if (this.state === DIRTY) {
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (this.state === DIRTY) {
|
|
96
|
+
this.update();
|
|
97
|
+
}
|
|
98
|
+
this.state = CLEAN;
|
|
99
|
+
}
|
|
100
|
+
update() {
|
|
101
|
+
let previous = {
|
|
102
|
+
index: index,
|
|
103
|
+
reaction: reaction,
|
|
104
|
+
stack: stack,
|
|
105
|
+
value: this.value
|
|
106
|
+
};
|
|
107
|
+
index = 0;
|
|
108
|
+
reaction = this;
|
|
109
|
+
stack = [];
|
|
110
|
+
try {
|
|
111
|
+
if (this.cleanup) {
|
|
112
|
+
for (let i = 0, n = this.cleanup.length; i < n; i++) {
|
|
113
|
+
this.cleanup[i](this.value);
|
|
114
|
+
}
|
|
115
|
+
this.cleanup.length = 0;
|
|
116
|
+
}
|
|
117
|
+
this.value = this.fn((fn) => {
|
|
118
|
+
if (!this.cleanup) {
|
|
119
|
+
this.cleanup = [fn];
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
this.cleanup.push(fn);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
if (stack.length) {
|
|
126
|
+
this.removeParentObservers();
|
|
127
|
+
if (this.sources && index > 0) {
|
|
128
|
+
this.sources.length = index + stack.length;
|
|
129
|
+
for (let i = 0; i < stack.length; i++) {
|
|
130
|
+
this.sources[index + i] = stack[i];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
this.sources = stack;
|
|
135
|
+
}
|
|
136
|
+
for (let i = index; i < this.sources.length; i++) {
|
|
137
|
+
let source = this.sources[i];
|
|
138
|
+
if (!source.observers) {
|
|
139
|
+
source.observers = [this];
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
source.observers.push(this);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else if (this.sources && index < this.sources.length) {
|
|
147
|
+
this.removeParentObservers();
|
|
148
|
+
this.sources.length = index;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
finally {
|
|
152
|
+
index = previous.index;
|
|
153
|
+
reaction = previous.reaction;
|
|
154
|
+
stack = previous.stack;
|
|
155
|
+
}
|
|
156
|
+
if (this.observers && previous.value !== this.value) {
|
|
157
|
+
for (let i = 0; i < this.observers.length; i++) {
|
|
158
|
+
this.observers[i].state = DIRTY;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
this.state = CLEAN;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const scheduler = {
|
|
165
|
+
add: (scheduler) => {
|
|
166
|
+
scheduler.tasks.add(task);
|
|
167
|
+
schedulers.add(scheduler);
|
|
168
|
+
},
|
|
169
|
+
delete: (scheduler) => {
|
|
170
|
+
scheduler.tasks.delete(task);
|
|
171
|
+
schedulers.delete(scheduler);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
export default Reactive;
|
|
175
|
+
export { scheduler };
|
package/build/types.d.ts
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { CLEAN, CHECK, DIRTY } from './symbols';
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
import Reactive from './reactive';
|
|
3
|
+
type Fn = () => Promise<unknown> | unknown;
|
|
4
|
+
type Infer<T> = T extends (...args: any[]) => any ? Reactive<T> : T extends Record<string, any> ? InferNested<T> : Reactive<T>;
|
|
5
|
+
type InferNested<T> = T extends (...args: any[]) => any ? ReturnType<T> : T extends Record<string, any> ? {
|
|
6
|
+
[K in keyof T]: InferNested<T[K]>;
|
|
7
|
+
} : T;
|
|
8
|
+
type Scheduler = {
|
|
9
|
+
schedule(): void;
|
|
10
|
+
tasks: {
|
|
11
|
+
add: (fn: Fn) => void;
|
|
12
|
+
delete: (fn: Fn) => void;
|
|
13
|
+
};
|
|
4
14
|
};
|
|
5
15
|
type State = typeof CHECK | typeof CLEAN | typeof DIRTY;
|
|
6
|
-
export {
|
|
16
|
+
export { Infer, Scheduler, State };
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,261 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import obj from './obj';
|
|
1
|
+
import { scheduler } from './reactive';
|
|
2
|
+
import { effect, reactive } from './methods';
|
|
4
3
|
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
T extends (...args: any[]) => any
|
|
9
|
-
? InferValue<ReturnType<T>>
|
|
10
|
-
: InferValue<T>;
|
|
11
|
-
|
|
12
|
-
type InferValue<T> = T extends Record<string, any> ? T : Reactive<T>;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
let index = 0,
|
|
16
|
-
reaction: Reactive<any> | null = null,
|
|
17
|
-
stack: Reactive<any>[] | null = null;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class Reactive<T> {
|
|
21
|
-
private effect: boolean;
|
|
22
|
-
private fn?: (onCleanup: (fn: VoidFunction) => void) => T;
|
|
23
|
-
private observers: Reactive<any>[] | null = null;
|
|
24
|
-
private queue: Queue | null = null;
|
|
25
|
-
private sources: Reactive<any>[] | null = null;
|
|
26
|
-
private state: State;
|
|
27
|
-
private value: T;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
cleanup: ((old: T) => void)[] | null = null;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
constructor(input: ((fn: VoidFunction) => T) | T, queue: Queue | null = null, effect: boolean = false) {
|
|
34
|
-
this.effect = effect;
|
|
35
|
-
|
|
36
|
-
if (typeof input === 'function') {
|
|
37
|
-
this.fn = input as (onCleanup: (fn: VoidFunction) => void) => T;
|
|
38
|
-
this.state = DIRTY;
|
|
39
|
-
this.value = undefined as any;
|
|
40
|
-
|
|
41
|
-
if (effect) {
|
|
42
|
-
this.queue = queue;
|
|
43
|
-
this.update();
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
this.state = CLEAN;
|
|
48
|
-
this.value = input;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
get(): T {
|
|
54
|
-
if (reaction) {
|
|
55
|
-
if (!stack && reaction.sources && reaction.sources[index] == this) {
|
|
56
|
-
index++;
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
if (!stack) {
|
|
60
|
-
stack = [this];
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
stack.push(this);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (this.fn) {
|
|
69
|
-
this.sync();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return this.value;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
set(value: T) {
|
|
76
|
-
if (this.observers && this.value !== value) {
|
|
77
|
-
for (let i = 0; i < this.observers.length; i++) {
|
|
78
|
-
this.observers[i].mark(DIRTY);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
this.value = value;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
private mark(state: typeof CHECK | typeof DIRTY) {
|
|
87
|
-
if (this.state < state) {
|
|
88
|
-
// If previous state was clean we need to update effects
|
|
89
|
-
if (this.state === CLEAN && this.effect) {
|
|
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
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
this.state = state;
|
|
100
|
-
|
|
101
|
-
if (!this.observers) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
for (let i = 0; i < this.observers.length; i++) {
|
|
106
|
-
this.observers[i].mark(CHECK);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// We don't actually delete sources here because we're replacing the entire array soon
|
|
112
|
-
private removeParentObservers() {
|
|
113
|
-
if (!this.sources) {
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
for (let i = index; i < this.sources.length; i++) {
|
|
118
|
-
let source = this.sources[i];
|
|
119
|
-
|
|
120
|
-
source.observers![ source.observers!.findIndex((v) => v === this) ] = source.observers![source.observers!.length - 1];
|
|
121
|
-
source.observers!.pop();
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Update if dirty or if a parent is dirty
|
|
126
|
-
private sync() {
|
|
127
|
-
// If we are potentially dirty, see if we have a parent who has actually changed value
|
|
128
|
-
if (this.state === CHECK && this.sources) {
|
|
129
|
-
for (let i = 0, n = this.sources.length; i < n; i++) {
|
|
130
|
-
this.sources[i].sync();
|
|
131
|
-
|
|
132
|
-
// Stop the loop here so we won't trigger updates on other parents unnecessarily
|
|
133
|
-
// If our computation changes to no longer use some sources, we don't
|
|
134
|
-
// want to update() a source we used last time, but now don't use.
|
|
135
|
-
if ((this.state as State) === DIRTY) {
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// If we were already dirty or marked dirty by the step above, update.
|
|
142
|
-
if (this.state === DIRTY) {
|
|
143
|
-
this.update();
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// By now, we're clean
|
|
147
|
-
this.state = CLEAN;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
private update() {
|
|
151
|
-
let previous = {
|
|
152
|
-
index: index,
|
|
153
|
-
reaction: reaction,
|
|
154
|
-
stack: stack,
|
|
155
|
-
value: this.value
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
index = 0;
|
|
159
|
-
reaction = this;
|
|
160
|
-
stack = [];
|
|
161
|
-
|
|
162
|
-
try {
|
|
163
|
-
if (this.cleanup) {
|
|
164
|
-
for (let i = 0, n = this.cleanup.length; i < n; i++) {
|
|
165
|
-
this.cleanup[i]( this.value );
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
this.cleanup.length = 0;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
this.value = this.fn!(
|
|
172
|
-
(fn: VoidFunction) => {
|
|
173
|
-
if (!this.cleanup) {
|
|
174
|
-
this.cleanup = [fn];
|
|
175
|
-
}
|
|
176
|
-
else {
|
|
177
|
-
this.cleanup.push(fn);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
// If sources have changed, update source & observer links
|
|
183
|
-
if (stack.length) {
|
|
184
|
-
// Remove all old sources' observers links to us
|
|
185
|
-
this.removeParentObservers();
|
|
186
|
-
|
|
187
|
-
// Update source up links
|
|
188
|
-
if (this.sources && index > 0) {
|
|
189
|
-
this.sources.length = index + stack.length;
|
|
190
|
-
|
|
191
|
-
for (let i = 0; i < stack.length; i++) {
|
|
192
|
-
this.sources[index + i] = stack[i];
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
this.sources = stack;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// Add ourselves to the end of the parent observers array
|
|
200
|
-
for (let i = index; i < this.sources.length; i++) {
|
|
201
|
-
let source = this.sources[i];
|
|
202
|
-
|
|
203
|
-
if (!source.observers) {
|
|
204
|
-
source.observers = [this];
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
source.observers.push( this );
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
// Remove all old sources' observers links to us
|
|
212
|
-
else if (this.sources && index < this.sources.length) {
|
|
213
|
-
this.removeParentObservers();
|
|
214
|
-
this.sources.length = index;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
finally {
|
|
218
|
-
index = previous.index;
|
|
219
|
-
reaction = previous.reaction;
|
|
220
|
-
stack = previous.stack;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Handle diamond depenendencies if we're the parent of a diamond.
|
|
224
|
-
if (this.observers && previous.value !== this.value) {
|
|
225
|
-
for (let i = 0; i < this.observers.length; i++) {
|
|
226
|
-
this.observers[i].state = DIRTY;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
this.state = CLEAN;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const effect = (queue: Queue) => {
|
|
236
|
-
return <T>(value: () => T) => {
|
|
237
|
-
new Reactive(value, queue, true);
|
|
238
|
-
};
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
const reactive = <T>(value: T) => {
|
|
242
|
-
let v;
|
|
243
|
-
|
|
244
|
-
if (typeof value === 'function') {
|
|
245
|
-
let fn = new Reactive(value);
|
|
246
|
-
|
|
247
|
-
v = (...args: any[]) => fn.get()(...args);
|
|
248
|
-
}
|
|
249
|
-
else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
250
|
-
v = obj(value);
|
|
251
|
-
}
|
|
252
|
-
else {
|
|
253
|
-
v = new Reactive(value);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return v as Infer<T>;
|
|
257
|
-
};
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
export default { effect, reactive };
|
|
261
|
-
export { effect, reactive };
|
|
5
|
+
export default { effect, reactive, scheduler };
|
|
6
|
+
export { effect, reactive, scheduler };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Infer } from '~/types';
|
|
2
|
+
import Reactive from '~/reactive';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// TODO: Typecheck on `values` to get rid of lazy var
|
|
6
|
+
function obj<T>(values: T) {
|
|
7
|
+
let lazy: Record<string, any> = {},
|
|
8
|
+
properties: PropertyDescriptorMap = {};
|
|
9
|
+
|
|
10
|
+
for (let key in values) {
|
|
11
|
+
properties[key] = {
|
|
12
|
+
get() {
|
|
13
|
+
if (!lazy[key]) {
|
|
14
|
+
lazy[key] = setup(values[key]);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return lazy[key].get();
|
|
18
|
+
},
|
|
19
|
+
set(value: unknown) {
|
|
20
|
+
if (!lazy[key]) {
|
|
21
|
+
lazy[key] = setup(values[key]);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
lazy[key].set(value);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return Object.defineProperties({}, properties) as T;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function setup<T>(value: T) {
|
|
33
|
+
// if (Array.isArray(value)) {
|
|
34
|
+
// TODO
|
|
35
|
+
// }
|
|
36
|
+
// TODO: Can remove isArray implementation is created
|
|
37
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
38
|
+
return obj(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return reactive(value) as T;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
const reactive = <T>(value: T) => {
|
|
46
|
+
let v: unknown;
|
|
47
|
+
|
|
48
|
+
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
49
|
+
v = obj(value);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
v = new Reactive(value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return v as Infer<T>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
export default reactive;
|
package/src/reactive.ts
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { CLEAN, CHECK, DIRTY } from './symbols';
|
|
2
|
+
import { Scheduler, State } from './types';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
let index = 0,
|
|
6
|
+
reaction: Reactive<any> | null = null,
|
|
7
|
+
queue: Reactive<any>[] = [],
|
|
8
|
+
schedulers = new Set<Scheduler>,
|
|
9
|
+
stack: Reactive<any>[] | null = null;
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
async function task() {
|
|
13
|
+
for (let i = 0, n = queue.length; i < n; i++) {
|
|
14
|
+
await queue[i].get();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
queue.length = 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Reactive<T> {
|
|
22
|
+
private effect: boolean;
|
|
23
|
+
private fn?: (onCleanup: (fn: VoidFunction) => void) => T;
|
|
24
|
+
private observers: Reactive<any>[] | null = null;
|
|
25
|
+
private sources: Reactive<any>[] | null = null;
|
|
26
|
+
private state: State;
|
|
27
|
+
private value: T;
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
cleanup: ((old: T) => void)[] | null = null;
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
constructor(input: ((fn: VoidFunction) => T) | T, effect: boolean = false) {
|
|
34
|
+
this.effect = effect;
|
|
35
|
+
|
|
36
|
+
if (typeof input === 'function') {
|
|
37
|
+
this.fn = input as (onCleanup: (fn: VoidFunction) => void) => T;
|
|
38
|
+
this.state = DIRTY;
|
|
39
|
+
this.value = undefined as any;
|
|
40
|
+
|
|
41
|
+
if (effect) {
|
|
42
|
+
this.update();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
this.state = CLEAN;
|
|
47
|
+
this.value = input;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
get(): T {
|
|
53
|
+
if (reaction) {
|
|
54
|
+
if (!stack && reaction.sources && reaction.sources[index] == this) {
|
|
55
|
+
index++;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
if (!stack) {
|
|
59
|
+
stack = [this];
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
stack.push(this);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (this.fn) {
|
|
68
|
+
this.sync();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return this.value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
set(value: T) {
|
|
75
|
+
if (this.observers && this.value !== value) {
|
|
76
|
+
for (let i = 0; i < this.observers.length; i++) {
|
|
77
|
+
this.observers[i].mark(DIRTY);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.value = value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
private mark(state: typeof CHECK | typeof DIRTY) {
|
|
86
|
+
if (this.state < state) {
|
|
87
|
+
// If previous state was clean we need to update effects
|
|
88
|
+
if (this.effect && this.state === CLEAN) {
|
|
89
|
+
queue.push(this);
|
|
90
|
+
|
|
91
|
+
for (let scheduler of schedulers) {
|
|
92
|
+
scheduler.schedule();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this.state = state;
|
|
97
|
+
|
|
98
|
+
if (!this.observers) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (let i = 0; i < this.observers.length; i++) {
|
|
103
|
+
this.observers[i].mark(CHECK);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// We don't actually delete sources here because we're replacing the entire array soon
|
|
109
|
+
private removeParentObservers() {
|
|
110
|
+
if (!this.sources) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
for (let i = index; i < this.sources.length; i++) {
|
|
115
|
+
let source = this.sources[i];
|
|
116
|
+
|
|
117
|
+
source.observers![ source.observers!.findIndex((v) => v === this) ] = source.observers![source.observers!.length - 1];
|
|
118
|
+
source.observers!.pop();
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Update if dirty or if a parent is dirty
|
|
123
|
+
private sync() {
|
|
124
|
+
// If we are potentially dirty, see if we have a parent who has actually changed value
|
|
125
|
+
if (this.state === CHECK && this.sources) {
|
|
126
|
+
for (let i = 0, n = this.sources.length; i < n; i++) {
|
|
127
|
+
this.sources[i].sync();
|
|
128
|
+
|
|
129
|
+
// Stop the loop here so we won't trigger updates on other parents unnecessarily
|
|
130
|
+
// If our computation changes to no longer use some sources, we don't
|
|
131
|
+
// want to update() a source we used last time, but now don't use.
|
|
132
|
+
if ((this.state as State) === DIRTY) {
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// If we were already dirty or marked dirty by the step above, update.
|
|
139
|
+
if (this.state === DIRTY) {
|
|
140
|
+
this.update();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// By now, we're clean
|
|
144
|
+
this.state = CLEAN;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private update() {
|
|
148
|
+
let previous = {
|
|
149
|
+
index: index,
|
|
150
|
+
reaction: reaction,
|
|
151
|
+
stack: stack,
|
|
152
|
+
value: this.value
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
index = 0;
|
|
156
|
+
reaction = this;
|
|
157
|
+
stack = [];
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
if (this.cleanup) {
|
|
161
|
+
for (let i = 0, n = this.cleanup.length; i < n; i++) {
|
|
162
|
+
this.cleanup[i]( this.value );
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
this.cleanup.length = 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
this.value = this.fn!(
|
|
169
|
+
(fn: VoidFunction) => {
|
|
170
|
+
if (!this.cleanup) {
|
|
171
|
+
this.cleanup = [fn];
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this.cleanup.push(fn);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
// If sources have changed, update source & observer links
|
|
180
|
+
if (stack.length) {
|
|
181
|
+
// Remove all old sources' observers links to us
|
|
182
|
+
this.removeParentObservers();
|
|
183
|
+
|
|
184
|
+
// Update source up links
|
|
185
|
+
if (this.sources && index > 0) {
|
|
186
|
+
this.sources.length = index + stack.length;
|
|
187
|
+
|
|
188
|
+
for (let i = 0; i < stack.length; i++) {
|
|
189
|
+
this.sources[index + i] = stack[i];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
this.sources = stack;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Add ourselves to the end of the parent observers array
|
|
197
|
+
for (let i = index; i < this.sources.length; i++) {
|
|
198
|
+
let source = this.sources[i];
|
|
199
|
+
|
|
200
|
+
if (!source.observers) {
|
|
201
|
+
source.observers = [this];
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
source.observers.push( this );
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// Remove all old sources' observers links to us
|
|
209
|
+
else if (this.sources && index < this.sources.length) {
|
|
210
|
+
this.removeParentObservers();
|
|
211
|
+
this.sources.length = index;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
finally {
|
|
215
|
+
index = previous.index;
|
|
216
|
+
reaction = previous.reaction;
|
|
217
|
+
stack = previous.stack;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Handle diamond depenendencies if we're the parent of a diamond.
|
|
221
|
+
if (this.observers && previous.value !== this.value) {
|
|
222
|
+
for (let i = 0; i < this.observers.length; i++) {
|
|
223
|
+
this.observers[i].state = DIRTY;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
this.state = CLEAN;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
const scheduler = {
|
|
233
|
+
add: (scheduler: Scheduler) => {
|
|
234
|
+
scheduler.tasks.add(task);
|
|
235
|
+
schedulers.add(scheduler);
|
|
236
|
+
},
|
|
237
|
+
delete: (scheduler: Scheduler) => {
|
|
238
|
+
scheduler.tasks.delete(task);
|
|
239
|
+
schedulers.delete(scheduler);
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
export default Reactive;
|
|
245
|
+
export { scheduler };
|
package/src/types.ts
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
import { CLEAN, CHECK, DIRTY } from './symbols';
|
|
2
|
+
import Reactive from './reactive';
|
|
2
3
|
|
|
3
4
|
|
|
4
|
-
type
|
|
5
|
-
|
|
5
|
+
type Fn = () => Promise<unknown> | unknown;
|
|
6
|
+
|
|
7
|
+
type Infer<T> =
|
|
8
|
+
T extends (...args: any[]) => any
|
|
9
|
+
? Reactive<T>
|
|
10
|
+
: T extends Record<string, any>
|
|
11
|
+
? InferNested<T>
|
|
12
|
+
: Reactive<T>;
|
|
13
|
+
|
|
14
|
+
type InferNested<T> =
|
|
15
|
+
T extends (...args: any[]) => any
|
|
16
|
+
? ReturnType<T>
|
|
17
|
+
: T extends Record<string, any>
|
|
18
|
+
? { [K in keyof T]: InferNested<T[K]> }
|
|
19
|
+
: T;
|
|
20
|
+
|
|
21
|
+
type Scheduler = {
|
|
22
|
+
schedule(): void;
|
|
23
|
+
tasks: {
|
|
24
|
+
add: (fn: Fn) => void;
|
|
25
|
+
delete: (fn: Fn) => void;
|
|
26
|
+
}
|
|
6
27
|
};
|
|
7
28
|
|
|
8
29
|
type State = typeof CHECK | typeof CLEAN | typeof DIRTY;
|
|
9
30
|
|
|
10
31
|
|
|
11
|
-
export {
|
|
32
|
+
export { Infer, Scheduler, State };
|