@expressive/mvc 0.53.6 → 0.54.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/esm/context.mjs +141 -0
- package/dist/esm/control.mjs +189 -0
- package/dist/esm/index.mjs +22 -0
- package/dist/esm/instruction/get.mjs +87 -0
- package/dist/esm/instruction/has.mjs +76 -0
- package/dist/esm/instruction/ref.mjs +62 -0
- package/dist/esm/instruction/set.mjs +83 -0
- package/dist/esm/instruction/use.mjs +65 -0
- package/dist/esm/model.mjs +274 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -0
- package/package.json +3 -3
- package/dist/esm/context.js +0 -137
- package/dist/esm/context.test.js +0 -211
- package/dist/esm/control.js +0 -182
- package/dist/esm/control.test.js +0 -183
- package/dist/esm/index.js +0 -8
- package/dist/esm/instruction/get.js +0 -87
- package/dist/esm/instruction/get.test.js +0 -645
- package/dist/esm/instruction/has.js +0 -73
- package/dist/esm/instruction/has.test.js +0 -354
- package/dist/esm/instruction/ref.js +0 -59
- package/dist/esm/instruction/ref.test.js +0 -281
- package/dist/esm/instruction/set.js +0 -86
- package/dist/esm/instruction/set.test.js +0 -527
- package/dist/esm/instruction/use.js +0 -60
- package/dist/esm/instruction/use.test.js +0 -305
- package/dist/esm/mocks.js +0 -20
- package/dist/esm/model.js +0 -278
- package/dist/esm/model.test.js +0 -1541
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { Context } from '../context';
|
|
2
|
-
import { Model, update } from '../model';
|
|
3
|
-
import { use } from './use';
|
|
4
|
-
const APPLY = new WeakMap();
|
|
5
|
-
function has(arg1, arg2) {
|
|
6
|
-
return use((key, subject) => {
|
|
7
|
-
const applied = new Set();
|
|
8
|
-
const apply = () => {
|
|
9
|
-
update(subject, key, Object.freeze(Array.from(applied)));
|
|
10
|
-
};
|
|
11
|
-
if (Model.is(arg1))
|
|
12
|
-
Context.get(subject, context => {
|
|
13
|
-
context.has(arg1, model => {
|
|
14
|
-
let remove;
|
|
15
|
-
let disconnect;
|
|
16
|
-
if (applied.has(model))
|
|
17
|
-
return;
|
|
18
|
-
const callback = APPLY.get(model);
|
|
19
|
-
if (callback) {
|
|
20
|
-
const after = callback(subject);
|
|
21
|
-
if (after === false)
|
|
22
|
-
return;
|
|
23
|
-
if (typeof after == "function")
|
|
24
|
-
disconnect = after;
|
|
25
|
-
}
|
|
26
|
-
if (typeof arg2 == "function") {
|
|
27
|
-
const done = arg2(model, subject);
|
|
28
|
-
if (done === false)
|
|
29
|
-
return false;
|
|
30
|
-
remove = () => {
|
|
31
|
-
if (typeof done == "function")
|
|
32
|
-
done();
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
applied.add(model);
|
|
36
|
-
apply();
|
|
37
|
-
const done = () => {
|
|
38
|
-
ignore();
|
|
39
|
-
applied.delete(model);
|
|
40
|
-
apply();
|
|
41
|
-
if (disconnect)
|
|
42
|
-
disconnect();
|
|
43
|
-
if (typeof remove == "function")
|
|
44
|
-
remove();
|
|
45
|
-
};
|
|
46
|
-
const ignore = model.get(null, done);
|
|
47
|
-
return done;
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
else {
|
|
51
|
-
if (APPLY.has(subject))
|
|
52
|
-
throw new Error(`'has' callback can only be used once per model.`);
|
|
53
|
-
APPLY.set(subject, recipient => {
|
|
54
|
-
let remove;
|
|
55
|
-
if (arg1) {
|
|
56
|
-
remove = arg1(recipient, subject);
|
|
57
|
-
if (remove === false)
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
applied.add(recipient);
|
|
61
|
-
apply();
|
|
62
|
-
return () => {
|
|
63
|
-
applied.delete(recipient);
|
|
64
|
-
apply();
|
|
65
|
-
if (typeof remove == "function")
|
|
66
|
-
remove();
|
|
67
|
-
};
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
return { value: [] };
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
export { has };
|
|
@@ -1,354 +0,0 @@
|
|
|
1
|
-
import { Context } from '../context';
|
|
2
|
-
import { Model } from '../model';
|
|
3
|
-
import { has } from './has';
|
|
4
|
-
describe("recipient", () => {
|
|
5
|
-
it("will register child", () => {
|
|
6
|
-
class Child extends Model {
|
|
7
|
-
}
|
|
8
|
-
class Parent extends Model {
|
|
9
|
-
constructor() {
|
|
10
|
-
super(...arguments);
|
|
11
|
-
this.children = has(Child);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
const parent = Parent.new();
|
|
15
|
-
const child = Child.new();
|
|
16
|
-
new Context({ parent }).push({ child });
|
|
17
|
-
expect(parent.children).toEqual([child]);
|
|
18
|
-
});
|
|
19
|
-
it("will register a subclass", () => {
|
|
20
|
-
class Child extends Model {
|
|
21
|
-
}
|
|
22
|
-
class Child2 extends Child {
|
|
23
|
-
}
|
|
24
|
-
class Parent extends Model {
|
|
25
|
-
constructor() {
|
|
26
|
-
super(...arguments);
|
|
27
|
-
this.children = has(Child);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
const parent = Parent.new();
|
|
31
|
-
const child = Child2.new();
|
|
32
|
-
new Context({ parent }).push({ child });
|
|
33
|
-
expect(parent.children).toEqual([child]);
|
|
34
|
-
});
|
|
35
|
-
it("will not register superclass", () => {
|
|
36
|
-
class Child extends Model {
|
|
37
|
-
}
|
|
38
|
-
class Child2 extends Child {
|
|
39
|
-
}
|
|
40
|
-
class Parent extends Model {
|
|
41
|
-
constructor() {
|
|
42
|
-
super(...arguments);
|
|
43
|
-
this.children = has(Child2);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const parent = Parent.new();
|
|
47
|
-
new Context({ parent }).push({ Child });
|
|
48
|
-
expect(parent.children.length).toBe(0);
|
|
49
|
-
});
|
|
50
|
-
it("will run callback on register", () => {
|
|
51
|
-
class Child extends Model {
|
|
52
|
-
}
|
|
53
|
-
class Parent extends Model {
|
|
54
|
-
constructor() {
|
|
55
|
-
super(...arguments);
|
|
56
|
-
this.children = has(Child, gotChild);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
const gotChild = jest.fn();
|
|
60
|
-
const parent = Parent.new();
|
|
61
|
-
const child = Child.new();
|
|
62
|
-
new Context({ parent }).push({ child });
|
|
63
|
-
expect(gotChild).toHaveBeenCalledWith(child, parent);
|
|
64
|
-
});
|
|
65
|
-
it("will register multiple children", () => {
|
|
66
|
-
class Child extends Model {
|
|
67
|
-
}
|
|
68
|
-
class Parent extends Model {
|
|
69
|
-
constructor() {
|
|
70
|
-
super(...arguments);
|
|
71
|
-
this.children = has(Child, hasChild);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
const hasChild = jest.fn();
|
|
75
|
-
const parent = Parent.new();
|
|
76
|
-
const child1 = Child.new();
|
|
77
|
-
const child2 = Child.new();
|
|
78
|
-
new Context({ parent }).push({ child1, child2 });
|
|
79
|
-
expect(hasChild).toHaveBeenCalledTimes(2);
|
|
80
|
-
expect(parent.children).toEqual([child1, child2]);
|
|
81
|
-
});
|
|
82
|
-
it("will remove children which unmount", async () => {
|
|
83
|
-
const didRemove = jest.fn();
|
|
84
|
-
const didAdd = jest.fn(() => didRemove);
|
|
85
|
-
class Child extends Model {
|
|
86
|
-
constructor() {
|
|
87
|
-
super(...arguments);
|
|
88
|
-
this.value = 0;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
class Parent extends Model {
|
|
92
|
-
constructor() {
|
|
93
|
-
super(...arguments);
|
|
94
|
-
this.children = has(Child, didAdd);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
const parent = Parent.new();
|
|
98
|
-
const child1 = Child.new();
|
|
99
|
-
const child2 = Child.new();
|
|
100
|
-
const context = new Context({ parent });
|
|
101
|
-
const context2 = context.push({ child1, child2 });
|
|
102
|
-
expect(didAdd).toHaveBeenCalledTimes(2);
|
|
103
|
-
expect(parent.children).toEqual([child1, child2]);
|
|
104
|
-
context2.pop();
|
|
105
|
-
await expect(parent).toHaveUpdated();
|
|
106
|
-
expect(didRemove).toHaveBeenCalledTimes(2);
|
|
107
|
-
const child3 = Child.new();
|
|
108
|
-
const context2b = context.push({ child3 });
|
|
109
|
-
expect(parent.children).toEqual([child3]);
|
|
110
|
-
context2b.pop();
|
|
111
|
-
await expect(parent).toHaveUpdated();
|
|
112
|
-
expect(didRemove).toHaveBeenCalledTimes(3);
|
|
113
|
-
expect(parent.children.length).toBe(0);
|
|
114
|
-
});
|
|
115
|
-
it("will not register if returns false", async () => {
|
|
116
|
-
class Child extends Model {
|
|
117
|
-
}
|
|
118
|
-
class Parent extends Model {
|
|
119
|
-
constructor() {
|
|
120
|
-
super(...arguments);
|
|
121
|
-
this.children = has(Child, hasChild);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const hasChild = jest.fn(() => false);
|
|
125
|
-
const parent = Parent.new();
|
|
126
|
-
const context = new Context({ parent });
|
|
127
|
-
context.push({
|
|
128
|
-
child: Child.new(),
|
|
129
|
-
child2: Child.new()
|
|
130
|
-
});
|
|
131
|
-
expect(hasChild).toHaveBeenCalledTimes(2);
|
|
132
|
-
expect(parent.children.length).toBe(0);
|
|
133
|
-
context.push({ child: Child.new() });
|
|
134
|
-
await expect(parent).not.toUpdate();
|
|
135
|
-
expect(hasChild).toHaveBeenCalledTimes(3);
|
|
136
|
-
expect(parent.children.length).toBe(0);
|
|
137
|
-
});
|
|
138
|
-
it("will ignore redundant child", async () => {
|
|
139
|
-
class Child extends Model {
|
|
140
|
-
}
|
|
141
|
-
class Parent extends Model {
|
|
142
|
-
constructor() {
|
|
143
|
-
super(...arguments);
|
|
144
|
-
this.child = has(Child, gotChild);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
const gotChild = jest.fn();
|
|
148
|
-
const parent = Parent.new();
|
|
149
|
-
const child = Child.new();
|
|
150
|
-
new Context({ parent })
|
|
151
|
-
.push({ child })
|
|
152
|
-
.push({ child });
|
|
153
|
-
expect(gotChild).toHaveBeenCalledTimes(1);
|
|
154
|
-
});
|
|
155
|
-
it("will register own type", async () => {
|
|
156
|
-
class Test extends Model {
|
|
157
|
-
constructor() {
|
|
158
|
-
super(...arguments);
|
|
159
|
-
this.tests = has(Test, (got, self) => {
|
|
160
|
-
gotTest(got.toString(), self.toString());
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
const gotTest = jest.fn();
|
|
165
|
-
const test = Test.new("1");
|
|
166
|
-
const test2 = Test.new("2");
|
|
167
|
-
const test3 = Test.new("3");
|
|
168
|
-
new Context({ test }).push({ test2 }).push({ test3 });
|
|
169
|
-
expect(gotTest).toBeCalledWith("2", "1");
|
|
170
|
-
expect(gotTest).toBeCalledWith("3", "2");
|
|
171
|
-
expect(gotTest).toBeCalledTimes(2);
|
|
172
|
-
});
|
|
173
|
-
it("will register implicit", () => {
|
|
174
|
-
class Baz extends Model {
|
|
175
|
-
}
|
|
176
|
-
class Foo extends Model {
|
|
177
|
-
constructor() {
|
|
178
|
-
super(...arguments);
|
|
179
|
-
this.bar = new Bar();
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
class Bar extends Model {
|
|
183
|
-
constructor() {
|
|
184
|
-
super(...arguments);
|
|
185
|
-
this.baz = has(Baz, gotBaz);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
const gotBaz = jest.fn();
|
|
189
|
-
const foo = Foo.new();
|
|
190
|
-
const baz = Baz.new();
|
|
191
|
-
new Context({ foo }).push({ baz });
|
|
192
|
-
expect(gotBaz).toBeCalledWith(baz, foo.bar);
|
|
193
|
-
});
|
|
194
|
-
it("will register for implicit", () => {
|
|
195
|
-
class Baz extends Model {
|
|
196
|
-
}
|
|
197
|
-
class Foo extends Model {
|
|
198
|
-
constructor() {
|
|
199
|
-
super(...arguments);
|
|
200
|
-
this.baz = has(Baz);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
class Bar extends Model {
|
|
204
|
-
constructor() {
|
|
205
|
-
super(...arguments);
|
|
206
|
-
this.baz = new Baz();
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
const foo = Foo.new();
|
|
210
|
-
const bar = Bar.new();
|
|
211
|
-
new Context({ foo }).push({ bar });
|
|
212
|
-
expect(foo.baz).toEqual([bar.baz]);
|
|
213
|
-
});
|
|
214
|
-
it.todo("will unwrap children on export");
|
|
215
|
-
});
|
|
216
|
-
describe("target", () => {
|
|
217
|
-
it("will register recipients", () => {
|
|
218
|
-
class Child extends Model {
|
|
219
|
-
constructor() {
|
|
220
|
-
super(...arguments);
|
|
221
|
-
this.parents = has();
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
class Parent extends Model {
|
|
225
|
-
constructor() {
|
|
226
|
-
super(...arguments);
|
|
227
|
-
this.child = has(Child);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
const parent = Parent.new();
|
|
231
|
-
const child = Child.new();
|
|
232
|
-
const context = new Context({ parent }).push({ child });
|
|
233
|
-
expect(child.parents).toEqual([parent]);
|
|
234
|
-
context.pop();
|
|
235
|
-
});
|
|
236
|
-
it("will register multiple", () => {
|
|
237
|
-
class Child extends Model {
|
|
238
|
-
constructor() {
|
|
239
|
-
super(...arguments);
|
|
240
|
-
this.parents = has();
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
class Parent extends Model {
|
|
244
|
-
constructor() {
|
|
245
|
-
super(...arguments);
|
|
246
|
-
this.child = has(Child);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
const child = Child.new();
|
|
250
|
-
const parent = Parent.new();
|
|
251
|
-
const parent2 = Parent.new();
|
|
252
|
-
const context = new Context({ parent }).push({ child });
|
|
253
|
-
const context2 = new Context({ parent2 }).push({ child });
|
|
254
|
-
expect(child.parents).toEqual([parent, parent2]);
|
|
255
|
-
context.pop();
|
|
256
|
-
context2.pop();
|
|
257
|
-
});
|
|
258
|
-
it("will callback on register", () => {
|
|
259
|
-
class Child extends Model {
|
|
260
|
-
constructor() {
|
|
261
|
-
super(...arguments);
|
|
262
|
-
this.parents = has(gotParent);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
class Parent extends Model {
|
|
266
|
-
constructor() {
|
|
267
|
-
super(...arguments);
|
|
268
|
-
this.child = has(Child);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
const gotParent = jest.fn();
|
|
272
|
-
const parent = Parent.new();
|
|
273
|
-
const child = Child.new();
|
|
274
|
-
new Context({ parent }).push({ child });
|
|
275
|
-
expect(gotParent).toHaveBeenCalledWith(parent, child);
|
|
276
|
-
});
|
|
277
|
-
it("will callback before recipient does", () => {
|
|
278
|
-
class Child extends Model {
|
|
279
|
-
constructor() {
|
|
280
|
-
super(...arguments);
|
|
281
|
-
this.parents = has(gotParent);
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
class Parent extends Model {
|
|
285
|
-
constructor() {
|
|
286
|
-
super(...arguments);
|
|
287
|
-
this.children = has(Child, gotChild);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
const gotChild = jest.fn();
|
|
291
|
-
const gotParent = jest.fn(() => {
|
|
292
|
-
expect(gotChild).not.toHaveBeenCalled();
|
|
293
|
-
});
|
|
294
|
-
const parent = Parent.new();
|
|
295
|
-
const child = Child.new();
|
|
296
|
-
new Context({ parent }).push({ child });
|
|
297
|
-
expect(gotChild).toHaveBeenCalled();
|
|
298
|
-
expect(gotParent).toHaveBeenCalled();
|
|
299
|
-
});
|
|
300
|
-
it("will prevent register", () => {
|
|
301
|
-
class Child extends Model {
|
|
302
|
-
constructor() {
|
|
303
|
-
super(...arguments);
|
|
304
|
-
this.parents = has(gotParent);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
class Parent extends Model {
|
|
308
|
-
constructor() {
|
|
309
|
-
super(...arguments);
|
|
310
|
-
this.children = has(Child, gotChild);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
const gotChild = jest.fn();
|
|
314
|
-
const gotParent = jest.fn(() => false);
|
|
315
|
-
const parent = Parent.new();
|
|
316
|
-
const child = Child.new();
|
|
317
|
-
new Context({ parent }).push({ child });
|
|
318
|
-
expect(gotParent).toHaveBeenCalled();
|
|
319
|
-
expect(gotChild).not.toHaveBeenCalled();
|
|
320
|
-
});
|
|
321
|
-
it("will callback on removal", async () => {
|
|
322
|
-
class Child extends Model {
|
|
323
|
-
constructor() {
|
|
324
|
-
super(...arguments);
|
|
325
|
-
this.parents = has(() => {
|
|
326
|
-
return removedParent;
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
class Parent extends Model {
|
|
331
|
-
constructor() {
|
|
332
|
-
super(...arguments);
|
|
333
|
-
this.children = has(Child);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
const removedParent = jest.fn();
|
|
337
|
-
const parent = Parent.new();
|
|
338
|
-
const child = Child.new();
|
|
339
|
-
const context = new Context({ parent }).push({ child });
|
|
340
|
-
context.pop();
|
|
341
|
-
expect(removedParent).toHaveBeenCalledTimes(1);
|
|
342
|
-
});
|
|
343
|
-
it("will complain if used more than once", () => {
|
|
344
|
-
class Child extends Model {
|
|
345
|
-
constructor() {
|
|
346
|
-
super(...arguments);
|
|
347
|
-
this.parents = has();
|
|
348
|
-
this.parents2 = has();
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
expect(() => Child.new()).toThrowError(`'has' callback can only be used once per model.`);
|
|
352
|
-
});
|
|
353
|
-
});
|
|
354
|
-
it.todo("will require values as props if has-instruction");
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { context } from '../control';
|
|
2
|
-
import { define, update } from '../model';
|
|
3
|
-
import { use } from './use';
|
|
4
|
-
function ref(arg, arg2) {
|
|
5
|
-
return use((key, subject, state) => {
|
|
6
|
-
let value = {};
|
|
7
|
-
if (arg === subject)
|
|
8
|
-
subject.get(() => {
|
|
9
|
-
for (const key in state)
|
|
10
|
-
if (typeof arg2 == "function")
|
|
11
|
-
define(value, key, {
|
|
12
|
-
configurable: true,
|
|
13
|
-
get() {
|
|
14
|
-
const out = arg2(key);
|
|
15
|
-
define(value, key, { value: out });
|
|
16
|
-
return out;
|
|
17
|
-
}
|
|
18
|
-
});
|
|
19
|
-
else {
|
|
20
|
-
const get = () => state[key];
|
|
21
|
-
const set = (value) => {
|
|
22
|
-
update(subject, key, value);
|
|
23
|
-
};
|
|
24
|
-
define(set, "current", { get, set });
|
|
25
|
-
define(set, "get", { value: get });
|
|
26
|
-
define(value, key, { value: set });
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
else if (typeof arg == "object")
|
|
30
|
-
throw new Error("ref instruction does not support object which is not 'this'");
|
|
31
|
-
else {
|
|
32
|
-
let unset;
|
|
33
|
-
const get = () => state[key];
|
|
34
|
-
const set = (value) => {
|
|
35
|
-
if (!update(subject, key, value) || !arg)
|
|
36
|
-
return;
|
|
37
|
-
if (unset)
|
|
38
|
-
unset = void unset(value);
|
|
39
|
-
if (value === null && arg2 !== false)
|
|
40
|
-
return;
|
|
41
|
-
const ctx = context();
|
|
42
|
-
const out = arg.call(subject, value);
|
|
43
|
-
const flush = ctx();
|
|
44
|
-
unset = key => {
|
|
45
|
-
if (typeof out == "function")
|
|
46
|
-
out(key);
|
|
47
|
-
flush();
|
|
48
|
-
};
|
|
49
|
-
};
|
|
50
|
-
state[key] = null;
|
|
51
|
-
value = Object.defineProperties(set, {
|
|
52
|
-
current: { get, set },
|
|
53
|
-
get: { value: get }
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
define(subject, key, { value });
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
export { ref };
|