@expressive/mvc 0.35.6 → 0.36.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/dist/index.d.ts +18 -1
- package/dist/index.js +49 -34
- package/dist/index.mjs +49 -34
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ interface Model {
|
|
|
54
54
|
is: this;
|
|
55
55
|
}
|
|
56
56
|
declare class Model {
|
|
57
|
-
constructor(id?: string | number);
|
|
57
|
+
constructor(id?: string | number | (() => void | (() => void)));
|
|
58
58
|
/** Pull current values from state. Flattens all models and exotic values recursively. */
|
|
59
59
|
get(): Model.State<this>;
|
|
60
60
|
/** Run a function which will run automatically when accessed values change. */
|
|
@@ -298,4 +298,21 @@ declare class Context {
|
|
|
298
298
|
pop(): void;
|
|
299
299
|
}
|
|
300
300
|
|
|
301
|
+
declare global {
|
|
302
|
+
/**
|
|
303
|
+
* Defines MVC specific matchers for [Jest](https://jestjs.io/) test suites.
|
|
304
|
+
*
|
|
305
|
+
* For these to work you will need to add `@expressive/mvc/jest`
|
|
306
|
+
* under `setupFilesAfterEnv` in your Jest configuration.
|
|
307
|
+
*/
|
|
308
|
+
namespace jest {
|
|
309
|
+
interface Matchers<R> {
|
|
310
|
+
/** Assert model does have one or more updates pending. */
|
|
311
|
+
toUpdate(timeout?: number): Promise<R>;
|
|
312
|
+
/** Assert model did update with keys specified. */
|
|
313
|
+
toHaveUpdated<R>(...keys: (string | symbol | number)[]): Promise<R>;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
301
318
|
export { Context, Model, add, Model as default, get, ref, set, use };
|
package/dist/index.js
CHANGED
|
@@ -38,15 +38,15 @@ var LISTENER = /* @__PURE__ */ new WeakMap();
|
|
|
38
38
|
function onReady() {
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
|
-
function addListener(
|
|
42
|
-
let subs = LISTENER.get(
|
|
41
|
+
function addListener(subject, callback, select) {
|
|
42
|
+
let subs = LISTENER.get(subject);
|
|
43
43
|
if (!subs)
|
|
44
|
-
LISTENER.set(
|
|
44
|
+
LISTENER.set(subject, subs = (/* @__PURE__ */ new Map()).set(onReady, false));
|
|
45
45
|
const filter = 2 in arguments && /* @__PURE__ */ new Set([select]);
|
|
46
46
|
if (!filter && !subs.has(onReady))
|
|
47
|
-
|
|
48
|
-
subs.set(
|
|
49
|
-
return () => subs.delete(
|
|
47
|
+
callback(true, subject);
|
|
48
|
+
subs.set(callback, filter);
|
|
49
|
+
return () => subs.delete(callback);
|
|
50
50
|
}
|
|
51
51
|
function watch(from, key, value) {
|
|
52
52
|
const listeners = LISTENER.get(from);
|
|
@@ -64,17 +64,30 @@ function watch(from, key, value) {
|
|
|
64
64
|
}
|
|
65
65
|
return value;
|
|
66
66
|
}
|
|
67
|
+
var PENDING = /* @__PURE__ */ new WeakMap();
|
|
67
68
|
function event(source, key) {
|
|
68
69
|
const subs = LISTENER.get(source);
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
let pending = PENDING.get(source);
|
|
71
|
+
if (pending) {
|
|
72
|
+
pending.add(key);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
PENDING.set(source, pending = new Set(
|
|
76
|
+
key !== true && subs.has(onReady) ? [true, key] : [key]
|
|
77
|
+
));
|
|
78
|
+
pending.forEach((key2) => {
|
|
79
|
+
pending.delete(key2);
|
|
80
|
+
subs.forEach((select, callback) => {
|
|
81
|
+
let after;
|
|
82
|
+
if (!select || select.has(key2)) {
|
|
83
|
+
if (after = callback.call(source, key2, source))
|
|
84
|
+
queue(after);
|
|
85
|
+
}
|
|
86
|
+
if (after === null || key2 === null)
|
|
87
|
+
subs.delete(callback);
|
|
88
|
+
});
|
|
77
89
|
});
|
|
90
|
+
PENDING.delete(source);
|
|
78
91
|
}
|
|
79
92
|
function queue(event2) {
|
|
80
93
|
if (!DISPATCH.size)
|
|
@@ -143,13 +156,18 @@ var ID = /* @__PURE__ */ new WeakMap();
|
|
|
143
156
|
var PARENT = /* @__PURE__ */ new WeakMap();
|
|
144
157
|
var STATE = /* @__PURE__ */ new WeakMap();
|
|
145
158
|
var NOTIFY = /* @__PURE__ */ new WeakMap();
|
|
146
|
-
var
|
|
159
|
+
var PENDING2 = /* @__PURE__ */ new WeakMap();
|
|
147
160
|
var define = Object.defineProperty;
|
|
148
161
|
var Model = class _Model {
|
|
149
162
|
constructor(id) {
|
|
150
163
|
let Type = this.constructor;
|
|
151
164
|
const state = {};
|
|
152
165
|
define(this, "is", { value: this });
|
|
166
|
+
if (typeof id == "function") {
|
|
167
|
+
const cb = id;
|
|
168
|
+
id = void 0;
|
|
169
|
+
this.get(() => cb());
|
|
170
|
+
}
|
|
153
171
|
STATE.set(this, state);
|
|
154
172
|
ID.set(this, id ? String(id) : `${Type}-${uid()}`);
|
|
155
173
|
while (true) {
|
|
@@ -158,19 +176,16 @@ var Model = class _Model {
|
|
|
158
176
|
break;
|
|
159
177
|
Type = Object.getPrototypeOf(Type);
|
|
160
178
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
event(this, true);
|
|
165
|
-
for (const key2 in this) {
|
|
166
|
-
const desc = Object.getOwnPropertyDescriptor(this, key2);
|
|
179
|
+
addListener(this, () => {
|
|
180
|
+
for (const key in this) {
|
|
181
|
+
const desc = Object.getOwnPropertyDescriptor(this, key);
|
|
167
182
|
if ("value" in desc) {
|
|
168
|
-
state[
|
|
169
|
-
define(this,
|
|
183
|
+
state[key] = desc.value;
|
|
184
|
+
define(this, key, {
|
|
170
185
|
enumerable: true,
|
|
171
|
-
set: (x) => update(this,
|
|
186
|
+
set: (x) => update(this, key, x),
|
|
172
187
|
get() {
|
|
173
|
-
return watch(this,
|
|
188
|
+
return watch(this, key, state[key]);
|
|
174
189
|
}
|
|
175
190
|
});
|
|
176
191
|
}
|
|
@@ -181,6 +196,7 @@ var Model = class _Model {
|
|
|
181
196
|
value.set(null);
|
|
182
197
|
Object.freeze(state);
|
|
183
198
|
}, null);
|
|
199
|
+
return null;
|
|
184
200
|
});
|
|
185
201
|
}
|
|
186
202
|
get(arg1, arg2) {
|
|
@@ -215,13 +231,13 @@ var Model = class _Model {
|
|
|
215
231
|
update(self, arg1, arg2, arg3);
|
|
216
232
|
else
|
|
217
233
|
push(self, arg1);
|
|
218
|
-
if (
|
|
234
|
+
if (PENDING2.has(self))
|
|
219
235
|
return {
|
|
220
236
|
then: (res) => new Promise((res2) => {
|
|
221
237
|
const remove = addListener(self, (key) => {
|
|
222
238
|
if (key !== true) {
|
|
223
239
|
remove();
|
|
224
|
-
return res2.bind(null, Array.from(
|
|
240
|
+
return res2.bind(null, Array.from(PENDING2.get(self)));
|
|
225
241
|
}
|
|
226
242
|
});
|
|
227
243
|
}).then(res)
|
|
@@ -308,12 +324,12 @@ function update(subject, key, value, silent) {
|
|
|
308
324
|
push(subject, key);
|
|
309
325
|
}
|
|
310
326
|
function push(subject, key) {
|
|
311
|
-
let pending =
|
|
327
|
+
let pending = PENDING2.get(subject);
|
|
312
328
|
if (!pending) {
|
|
313
|
-
|
|
329
|
+
PENDING2.set(subject, pending = /* @__PURE__ */ new Set());
|
|
314
330
|
queue(() => {
|
|
315
331
|
event(subject, false);
|
|
316
|
-
|
|
332
|
+
PENDING2.delete(subject);
|
|
317
333
|
});
|
|
318
334
|
}
|
|
319
335
|
pending.add(key);
|
|
@@ -347,11 +363,10 @@ function add(instruction) {
|
|
|
347
363
|
}
|
|
348
364
|
Model.on((_, subject) => {
|
|
349
365
|
const state = STATE.get(subject);
|
|
350
|
-
|
|
351
|
-
const { value } = Object.getOwnPropertyDescriptor(subject, key);
|
|
366
|
+
Object.entries(Object.getOwnPropertyDescriptors(subject)).forEach(([key, { value }]) => {
|
|
352
367
|
const instruction = INSTRUCT.get(value);
|
|
353
368
|
if (!instruction)
|
|
354
|
-
|
|
369
|
+
return;
|
|
355
370
|
INSTRUCT.delete(value);
|
|
356
371
|
delete subject[key];
|
|
357
372
|
const output = instruction.call(subject, key, subject, state);
|
|
@@ -385,7 +400,7 @@ Model.on((_, subject) => {
|
|
|
385
400
|
);
|
|
386
401
|
}
|
|
387
402
|
});
|
|
388
|
-
}
|
|
403
|
+
});
|
|
389
404
|
return null;
|
|
390
405
|
});
|
|
391
406
|
|
package/dist/index.mjs
CHANGED
|
@@ -5,15 +5,15 @@ var LISTENER = /* @__PURE__ */ new WeakMap();
|
|
|
5
5
|
function onReady() {
|
|
6
6
|
return null;
|
|
7
7
|
}
|
|
8
|
-
function addListener(
|
|
9
|
-
let subs = LISTENER.get(
|
|
8
|
+
function addListener(subject, callback, select) {
|
|
9
|
+
let subs = LISTENER.get(subject);
|
|
10
10
|
if (!subs)
|
|
11
|
-
LISTENER.set(
|
|
11
|
+
LISTENER.set(subject, subs = (/* @__PURE__ */ new Map()).set(onReady, false));
|
|
12
12
|
const filter = 2 in arguments && /* @__PURE__ */ new Set([select]);
|
|
13
13
|
if (!filter && !subs.has(onReady))
|
|
14
|
-
|
|
15
|
-
subs.set(
|
|
16
|
-
return () => subs.delete(
|
|
14
|
+
callback(true, subject);
|
|
15
|
+
subs.set(callback, filter);
|
|
16
|
+
return () => subs.delete(callback);
|
|
17
17
|
}
|
|
18
18
|
function watch(from, key, value) {
|
|
19
19
|
const listeners = LISTENER.get(from);
|
|
@@ -31,17 +31,30 @@ function watch(from, key, value) {
|
|
|
31
31
|
}
|
|
32
32
|
return value;
|
|
33
33
|
}
|
|
34
|
+
var PENDING = /* @__PURE__ */ new WeakMap();
|
|
34
35
|
function event(source, key) {
|
|
35
36
|
const subs = LISTENER.get(source);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
let pending = PENDING.get(source);
|
|
38
|
+
if (pending) {
|
|
39
|
+
pending.add(key);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
PENDING.set(source, pending = new Set(
|
|
43
|
+
key !== true && subs.has(onReady) ? [true, key] : [key]
|
|
44
|
+
));
|
|
45
|
+
pending.forEach((key2) => {
|
|
46
|
+
pending.delete(key2);
|
|
47
|
+
subs.forEach((select, callback) => {
|
|
48
|
+
let after;
|
|
49
|
+
if (!select || select.has(key2)) {
|
|
50
|
+
if (after = callback.call(source, key2, source))
|
|
51
|
+
queue(after);
|
|
52
|
+
}
|
|
53
|
+
if (after === null || key2 === null)
|
|
54
|
+
subs.delete(callback);
|
|
55
|
+
});
|
|
44
56
|
});
|
|
57
|
+
PENDING.delete(source);
|
|
45
58
|
}
|
|
46
59
|
function queue(event2) {
|
|
47
60
|
if (!DISPATCH.size)
|
|
@@ -110,13 +123,18 @@ var ID = /* @__PURE__ */ new WeakMap();
|
|
|
110
123
|
var PARENT = /* @__PURE__ */ new WeakMap();
|
|
111
124
|
var STATE = /* @__PURE__ */ new WeakMap();
|
|
112
125
|
var NOTIFY = /* @__PURE__ */ new WeakMap();
|
|
113
|
-
var
|
|
126
|
+
var PENDING2 = /* @__PURE__ */ new WeakMap();
|
|
114
127
|
var define = Object.defineProperty;
|
|
115
128
|
var Model = class _Model {
|
|
116
129
|
constructor(id) {
|
|
117
130
|
let Type = this.constructor;
|
|
118
131
|
const state = {};
|
|
119
132
|
define(this, "is", { value: this });
|
|
133
|
+
if (typeof id == "function") {
|
|
134
|
+
const cb = id;
|
|
135
|
+
id = void 0;
|
|
136
|
+
this.get(() => cb());
|
|
137
|
+
}
|
|
120
138
|
STATE.set(this, state);
|
|
121
139
|
ID.set(this, id ? String(id) : `${Type}-${uid()}`);
|
|
122
140
|
while (true) {
|
|
@@ -125,19 +143,16 @@ var Model = class _Model {
|
|
|
125
143
|
break;
|
|
126
144
|
Type = Object.getPrototypeOf(Type);
|
|
127
145
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
event(this, true);
|
|
132
|
-
for (const key2 in this) {
|
|
133
|
-
const desc = Object.getOwnPropertyDescriptor(this, key2);
|
|
146
|
+
addListener(this, () => {
|
|
147
|
+
for (const key in this) {
|
|
148
|
+
const desc = Object.getOwnPropertyDescriptor(this, key);
|
|
134
149
|
if ("value" in desc) {
|
|
135
|
-
state[
|
|
136
|
-
define(this,
|
|
150
|
+
state[key] = desc.value;
|
|
151
|
+
define(this, key, {
|
|
137
152
|
enumerable: true,
|
|
138
|
-
set: (x) => update(this,
|
|
153
|
+
set: (x) => update(this, key, x),
|
|
139
154
|
get() {
|
|
140
|
-
return watch(this,
|
|
155
|
+
return watch(this, key, state[key]);
|
|
141
156
|
}
|
|
142
157
|
});
|
|
143
158
|
}
|
|
@@ -148,6 +163,7 @@ var Model = class _Model {
|
|
|
148
163
|
value.set(null);
|
|
149
164
|
Object.freeze(state);
|
|
150
165
|
}, null);
|
|
166
|
+
return null;
|
|
151
167
|
});
|
|
152
168
|
}
|
|
153
169
|
get(arg1, arg2) {
|
|
@@ -182,13 +198,13 @@ var Model = class _Model {
|
|
|
182
198
|
update(self, arg1, arg2, arg3);
|
|
183
199
|
else
|
|
184
200
|
push(self, arg1);
|
|
185
|
-
if (
|
|
201
|
+
if (PENDING2.has(self))
|
|
186
202
|
return {
|
|
187
203
|
then: (res) => new Promise((res2) => {
|
|
188
204
|
const remove = addListener(self, (key) => {
|
|
189
205
|
if (key !== true) {
|
|
190
206
|
remove();
|
|
191
|
-
return res2.bind(null, Array.from(
|
|
207
|
+
return res2.bind(null, Array.from(PENDING2.get(self)));
|
|
192
208
|
}
|
|
193
209
|
});
|
|
194
210
|
}).then(res)
|
|
@@ -275,12 +291,12 @@ function update(subject, key, value, silent) {
|
|
|
275
291
|
push(subject, key);
|
|
276
292
|
}
|
|
277
293
|
function push(subject, key) {
|
|
278
|
-
let pending =
|
|
294
|
+
let pending = PENDING2.get(subject);
|
|
279
295
|
if (!pending) {
|
|
280
|
-
|
|
296
|
+
PENDING2.set(subject, pending = /* @__PURE__ */ new Set());
|
|
281
297
|
queue(() => {
|
|
282
298
|
event(subject, false);
|
|
283
|
-
|
|
299
|
+
PENDING2.delete(subject);
|
|
284
300
|
});
|
|
285
301
|
}
|
|
286
302
|
pending.add(key);
|
|
@@ -314,11 +330,10 @@ function add(instruction) {
|
|
|
314
330
|
}
|
|
315
331
|
Model.on((_, subject) => {
|
|
316
332
|
const state = STATE.get(subject);
|
|
317
|
-
|
|
318
|
-
const { value } = Object.getOwnPropertyDescriptor(subject, key);
|
|
333
|
+
Object.entries(Object.getOwnPropertyDescriptors(subject)).forEach(([key, { value }]) => {
|
|
319
334
|
const instruction = INSTRUCT.get(value);
|
|
320
335
|
if (!instruction)
|
|
321
|
-
|
|
336
|
+
return;
|
|
322
337
|
INSTRUCT.delete(value);
|
|
323
338
|
delete subject[key];
|
|
324
339
|
const output = instruction.call(subject, key, subject, state);
|
|
@@ -352,7 +367,7 @@ Model.on((_, subject) => {
|
|
|
352
367
|
);
|
|
353
368
|
}
|
|
354
369
|
});
|
|
355
|
-
}
|
|
370
|
+
});
|
|
356
371
|
return null;
|
|
357
372
|
});
|
|
358
373
|
|
package/package.json
CHANGED