@expressive/mvc 0.24.1 → 0.25.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/lib/index.d.ts +19 -26
- package/lib/index.esm.js +108 -118
- package/lib/index.js +108 -118
- package/package.json +5 -3
package/lib/index.d.ts
CHANGED
|
@@ -22,15 +22,12 @@ declare namespace Context {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
declare class Context {
|
|
25
|
-
/** Use */
|
|
26
25
|
key: string;
|
|
27
26
|
private table;
|
|
28
27
|
private layer;
|
|
29
28
|
private has;
|
|
30
29
|
get<T extends Model>(Type: Model.Type<T>): T | undefined;
|
|
31
30
|
include(inputs: Context.Inputs): Map<Model, boolean>;
|
|
32
|
-
/** Context must force-reset becasue inputs are no longer safe. */
|
|
33
|
-
private bailout;
|
|
34
31
|
add<T extends Model>(input: T | Model.New<T>, implicit?: boolean): T;
|
|
35
32
|
push(): this;
|
|
36
33
|
pop(): void;
|
|
@@ -60,16 +57,17 @@ declare namespace Control {
|
|
|
60
57
|
type Getter<T> = (source: Model) => T;
|
|
61
58
|
type Setter<T> = (value: T) => boolean | void;
|
|
62
59
|
type PropertyDescriptor<T = any> = {
|
|
63
|
-
enumerable?: boolean;
|
|
64
|
-
value?: T;
|
|
65
60
|
get?: Getter<T>;
|
|
66
61
|
set?: Setter<T> | false;
|
|
62
|
+
enumerable?: boolean;
|
|
63
|
+
value?: T;
|
|
67
64
|
};
|
|
65
|
+
type Callback = (control: Control) => void;
|
|
68
66
|
/**
|
|
69
67
|
* Callback for Controller.for() static method.
|
|
70
68
|
* Returned callback is forwarded.
|
|
71
69
|
*/
|
|
72
|
-
type OnReady<T extends
|
|
70
|
+
type OnReady<T extends {}> = (control: Control<T>) => (() => void) | void;
|
|
73
71
|
type RequestRefresh = (update: (tick: number) => number) => void;
|
|
74
72
|
type GetContext = (target: Model) => (callback: (got: Context) => void) => void;
|
|
75
73
|
type GetAdapter<T> = (refresh: RequestRefresh, context: Context) => {
|
|
@@ -78,15 +76,14 @@ declare namespace Control {
|
|
|
78
76
|
} | void;
|
|
79
77
|
type GetHook = <T>(adapter: GetAdapter<T>) => T | null;
|
|
80
78
|
type UseAdapter<T extends Model, R> = (refresh: RequestRefresh) => {
|
|
81
|
-
|
|
79
|
+
instance: T;
|
|
82
80
|
mount: () => (() => void) | void;
|
|
83
81
|
render: R;
|
|
84
82
|
};
|
|
85
83
|
type UseHook = <T extends Model, R>(adapter: UseAdapter<T, R>) => R;
|
|
86
84
|
}
|
|
87
|
-
declare class Control<T extends
|
|
88
|
-
|
|
89
|
-
id: string | number;
|
|
85
|
+
declare class Control<T extends {} = any> {
|
|
86
|
+
static ready: Set<Control.Callback>;
|
|
90
87
|
static after: Set<Callback>;
|
|
91
88
|
static before: Set<Callback>;
|
|
92
89
|
static pending: Set<Callback>;
|
|
@@ -96,6 +93,8 @@ declare class Control<T extends Model = any> {
|
|
|
96
93
|
static for: typeof control;
|
|
97
94
|
static apply: typeof apply;
|
|
98
95
|
static watch: typeof watch;
|
|
96
|
+
id: string | number;
|
|
97
|
+
subject: T;
|
|
99
98
|
state: {
|
|
100
99
|
[key: string]: any;
|
|
101
100
|
};
|
|
@@ -113,7 +112,7 @@ declare class Control<T extends Model = any> {
|
|
|
113
112
|
}
|
|
114
113
|
declare function control<T extends Model>(subject: T, ready: Control.OnReady<T>): Callback;
|
|
115
114
|
declare function control<T extends Model>(subject: T, ready?: boolean): Control<T>;
|
|
116
|
-
declare function watch<T extends
|
|
115
|
+
declare function watch<T extends {}>(on: T, cb: Observer): T;
|
|
117
116
|
declare function apply<T = any>(instruction: Control.Instruction<T>): T;
|
|
118
117
|
|
|
119
118
|
declare const STATE = "__state";
|
|
@@ -156,20 +155,13 @@ type Debug<T extends Model = Model> = T & {
|
|
|
156
155
|
};
|
|
157
156
|
|
|
158
157
|
/** Type may not be undefined - instead will be null. */
|
|
159
|
-
type NoVoid<T> = T extends undefined ? null : T;
|
|
160
|
-
|
|
161
|
-
/** Fetch instance of this class in passive mode. Will not subscribe to events. */
|
|
158
|
+
type NoVoid<T> = T extends undefined | void ? null : T;
|
|
159
|
+
/** Fetch instance of this class from context. */
|
|
162
160
|
declare function get$1<T extends Model>(this: Model.Type<T>, ignoreUpdates?: true): T;
|
|
163
161
|
/** Fetch instance of this class optionally. May be undefined, but will never subscribe. */
|
|
164
162
|
declare function get$1<T extends Model>(this: Model.Type<T>, required: boolean): T | undefined;
|
|
165
|
-
declare function get$1<T extends Model, R
|
|
166
|
-
declare function get$1<T extends Model, R
|
|
167
|
-
declare function get$1<T extends Model, R extends []>(this: Model.Type<T>, factory: Model.GetCallback<T, Promise<R> | R>, expect: true): Exclude<R, undefined>;
|
|
168
|
-
declare function get$1<T extends Model, R>(this: Model.Type<T>, init: Model.GetCallback<T, () => R>): NoVoid<R>;
|
|
169
|
-
declare function get$1<T extends Model, R>(this: Model.Type<T>, init: Model.GetCallback<T, (() => R) | null>): NoVoid<R> | null;
|
|
170
|
-
declare function get$1<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R> | R>, expect: true): Exclude<R, undefined>;
|
|
171
|
-
declare function get$1<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R>>, expect?: boolean): NoVoid<R> | null;
|
|
172
|
-
declare function get$1<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, R>, expect?: boolean): NoVoid<R>;
|
|
163
|
+
declare function get$1<T extends Model, R>(this: Model.Type<T>, factory: Model.GetCallback<T, (() => R) | R | Promise<R>>): NoVoid<R>;
|
|
164
|
+
declare function get$1<T extends Model, R>(this: Model.Type<T>, factory: Model.GetCallback<T, (() => R) | null>): NoVoid<R> | null;
|
|
173
165
|
|
|
174
166
|
declare function use$1<T extends Model>(this: Model.New<T>, callback?: (instance: T) => void, repeat?: boolean): T;
|
|
175
167
|
declare function use$1<T extends Model>(this: Model.New<T>, apply?: Model.Compat<T>, repeat?: boolean): T;
|
|
@@ -254,7 +246,7 @@ declare class Model {
|
|
|
254
246
|
get<P extends Model.Key<this>>(select: Iterable<P>): Model.Get<this, P>;
|
|
255
247
|
get<P extends Model.Key<this>>(select: P, listener: (this: this, value: this[P]) => void): Callback;
|
|
256
248
|
get<P extends Model.Key<this>>(select: Iterable<P>, listener: (this: this, value: Model.Get<this, P>) => void): Callback;
|
|
257
|
-
set<T extends Model.Compat<this>>(source: T,
|
|
249
|
+
set<T extends Model.Compat<this>>(source: T, only?: (keyof T)[]): Promise<Model.Key<T>[]>;
|
|
258
250
|
set<K extends Model.Event<this>>(key: K, value?: Model.ValueOf<this, K>): Promise<Model.Event<this>[] | false>;
|
|
259
251
|
/** Mark this instance for garbage collection. */
|
|
260
252
|
null(): void;
|
|
@@ -387,11 +379,12 @@ declare function use<T extends Model>(): T | undefined;
|
|
|
387
379
|
/** Create a new child instance of model. */
|
|
388
380
|
declare function use<T extends Model>(Type: Model.New<T>, callback?: (i: T) => void): T;
|
|
389
381
|
/** Assign the result of a factory as a child model. */
|
|
390
|
-
declare function use<T extends
|
|
382
|
+
declare function use<T extends {}>(from: () => Promise<T> | T, required?: true): T;
|
|
391
383
|
/** Assign the result of a factory as a child model. */
|
|
392
|
-
declare function use<T extends
|
|
384
|
+
declare function use<T extends {}>(from: () => Promise<T> | T, required: boolean): T | undefined;
|
|
393
385
|
/** Create a managed child from factory function. */
|
|
394
|
-
declare function use<T extends
|
|
386
|
+
declare function use<T extends {}>(from: () => Promise<T> | T, callback?: (i: T) => void): T;
|
|
387
|
+
declare function use<T extends {}>(data: T): T;
|
|
395
388
|
/**
|
|
396
389
|
* Create child-instance relationship with provided model.
|
|
397
390
|
*
|
package/lib/index.esm.js
CHANGED
|
@@ -197,18 +197,18 @@ function awaitUpdate(source, select, timeout) {
|
|
|
197
197
|
const Oops$6 = issues({
|
|
198
198
|
NotFound: (name) => `Could not find ${name} in context.`
|
|
199
199
|
});
|
|
200
|
-
function get$1(
|
|
200
|
+
function get$1(argument) {
|
|
201
201
|
return Control.get((dispatch, context) => {
|
|
202
202
|
const refresh = () => dispatch(x => x + 1);
|
|
203
203
|
let onUpdate;
|
|
204
204
|
let value;
|
|
205
|
-
if (typeof
|
|
205
|
+
if (typeof argument !== "function") {
|
|
206
206
|
const got = context.get(this);
|
|
207
207
|
if (got)
|
|
208
|
-
value =
|
|
208
|
+
value = argument === undefined
|
|
209
209
|
? Control.watch(got, k => k ? onUpdate : undefined)
|
|
210
210
|
: got;
|
|
211
|
-
else if (
|
|
211
|
+
else if (argument !== false)
|
|
212
212
|
throw Oops$6.NotFound(this);
|
|
213
213
|
return {
|
|
214
214
|
mount() {
|
|
@@ -218,7 +218,7 @@ function get$1(arg1, arg2) {
|
|
|
218
218
|
render: () => value
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
|
-
let compute =
|
|
221
|
+
let compute = argument;
|
|
222
222
|
let suspense;
|
|
223
223
|
let getValue;
|
|
224
224
|
let factory;
|
|
@@ -226,9 +226,6 @@ function get$1(arg1, arg2) {
|
|
|
226
226
|
const found = context.get(this);
|
|
227
227
|
if (!found)
|
|
228
228
|
throw Oops$6.NotFound(this);
|
|
229
|
-
proxy = Control.watch(found, () => factory ? null : onUpdate);
|
|
230
|
-
getValue = () => compute.call(proxy, proxy, forceUpdate);
|
|
231
|
-
value = getValue();
|
|
232
229
|
function forceUpdate(action) {
|
|
233
230
|
if (typeof action == "function")
|
|
234
231
|
action = action();
|
|
@@ -239,6 +236,18 @@ function get$1(arg1, arg2) {
|
|
|
239
236
|
if (action)
|
|
240
237
|
return action.finally(refresh);
|
|
241
238
|
}
|
|
239
|
+
function didUpdate(got) {
|
|
240
|
+
value = got;
|
|
241
|
+
if (suspense) {
|
|
242
|
+
suspense();
|
|
243
|
+
suspense = undefined;
|
|
244
|
+
}
|
|
245
|
+
else
|
|
246
|
+
refresh();
|
|
247
|
+
}
|
|
248
|
+
proxy = Control.watch(found, () => factory ? null : onUpdate);
|
|
249
|
+
getValue = () => compute.call(proxy, proxy, forceUpdate);
|
|
250
|
+
value = getValue();
|
|
242
251
|
if (value === null) {
|
|
243
252
|
getValue = undefined;
|
|
244
253
|
onUpdate = null;
|
|
@@ -251,15 +260,6 @@ function get$1(arg1, arg2) {
|
|
|
251
260
|
compute = () => get();
|
|
252
261
|
value = get();
|
|
253
262
|
}
|
|
254
|
-
const didUpdate = (got) => {
|
|
255
|
-
value = got;
|
|
256
|
-
if (suspense) {
|
|
257
|
-
suspense();
|
|
258
|
-
suspense = undefined;
|
|
259
|
-
}
|
|
260
|
-
else
|
|
261
|
-
refresh();
|
|
262
|
-
};
|
|
263
263
|
if (value instanceof Promise) {
|
|
264
264
|
onUpdate = null;
|
|
265
265
|
value.then(didUpdate);
|
|
@@ -268,7 +268,7 @@ function get$1(arg1, arg2) {
|
|
|
268
268
|
else
|
|
269
269
|
onUpdate = () => {
|
|
270
270
|
const next = getValue();
|
|
271
|
-
if (
|
|
271
|
+
if (value !== next)
|
|
272
272
|
didUpdate(next);
|
|
273
273
|
};
|
|
274
274
|
return {
|
|
@@ -278,30 +278,25 @@ function get$1(arg1, arg2) {
|
|
|
278
278
|
render: () => {
|
|
279
279
|
if (value !== undefined)
|
|
280
280
|
return value;
|
|
281
|
-
if (
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
281
|
+
if (onUpdate)
|
|
282
|
+
return null;
|
|
283
|
+
throw new Promise(res => {
|
|
284
|
+
suspense = res;
|
|
285
|
+
});
|
|
286
286
|
}
|
|
287
287
|
};
|
|
288
288
|
});
|
|
289
|
-
}
|
|
290
|
-
/** Values are not equal for purposes of a refresh. */
|
|
291
|
-
const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
|
|
292
|
-
!Array.isArray(b) ||
|
|
293
|
-
a.length !== b.length ||
|
|
294
|
-
a.some((x, i) => x !== b[i])));
|
|
289
|
+
}
|
|
295
290
|
|
|
296
|
-
function use$1(
|
|
291
|
+
function use$1(apply, repeat) {
|
|
297
292
|
const render = Control.use(dispatch => {
|
|
298
293
|
const instance = this.new();
|
|
299
294
|
const local = Control.watch(instance, () => onUpdate);
|
|
300
295
|
const refresh = () => dispatch(x => x + 1);
|
|
301
296
|
let onUpdate;
|
|
302
|
-
let
|
|
297
|
+
let shouldApply = !!apply;
|
|
303
298
|
return {
|
|
304
|
-
|
|
299
|
+
instance,
|
|
305
300
|
mount() {
|
|
306
301
|
onUpdate = refresh;
|
|
307
302
|
return () => {
|
|
@@ -310,7 +305,7 @@ function use$1(arg1, arg2) {
|
|
|
310
305
|
};
|
|
311
306
|
},
|
|
312
307
|
render(props) {
|
|
313
|
-
if (
|
|
308
|
+
if (shouldApply) {
|
|
314
309
|
onUpdate = undefined;
|
|
315
310
|
if (typeof props == "function")
|
|
316
311
|
props(instance);
|
|
@@ -318,15 +313,15 @@ function use$1(arg1, arg2) {
|
|
|
318
313
|
for (const key in instance)
|
|
319
314
|
if (props.hasOwnProperty(key))
|
|
320
315
|
instance[key] = props[key];
|
|
321
|
-
if (!
|
|
322
|
-
|
|
316
|
+
if (!repeat)
|
|
317
|
+
shouldApply = false;
|
|
323
318
|
instance.on(0).then(() => onUpdate = refresh);
|
|
324
319
|
}
|
|
325
320
|
return local;
|
|
326
321
|
}
|
|
327
322
|
};
|
|
328
323
|
});
|
|
329
|
-
return render(
|
|
324
|
+
return render(apply);
|
|
330
325
|
}
|
|
331
326
|
|
|
332
327
|
class Model {
|
|
@@ -427,24 +422,27 @@ const Oops$5 = issues({
|
|
|
427
422
|
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
428
423
|
});
|
|
429
424
|
const INSTRUCTION = new Map();
|
|
425
|
+
const PENDING$1 = new WeakMap();
|
|
430
426
|
const REGISTER = new WeakMap();
|
|
431
427
|
const OBSERVER = new WeakMap();
|
|
432
428
|
const PARENTS = new WeakMap();
|
|
433
429
|
class Control {
|
|
434
|
-
constructor(subject, id
|
|
435
|
-
this.
|
|
436
|
-
this.id = id;
|
|
430
|
+
constructor(subject, id) {
|
|
431
|
+
this.state = {};
|
|
437
432
|
this.frame = new Set();
|
|
438
433
|
this.followers = new Set();
|
|
439
434
|
this.observers = new Map([["", this.followers]]);
|
|
435
|
+
this.id = typeof id == "undefined" ? uid() : id;
|
|
436
|
+
this.subject = subject;
|
|
440
437
|
REGISTER.set(subject, this);
|
|
438
|
+
PENDING$1.set(this, new Set(Control.ready));
|
|
441
439
|
}
|
|
442
440
|
add(key) {
|
|
443
441
|
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
444
442
|
const instruction = INSTRUCTION.get(value);
|
|
445
443
|
if (typeof instruction == "function") {
|
|
446
444
|
INSTRUCTION.delete(value);
|
|
447
|
-
instruction(
|
|
445
|
+
instruction(this, key);
|
|
448
446
|
}
|
|
449
447
|
else if (value instanceof Model)
|
|
450
448
|
setRecursive(this, key, value);
|
|
@@ -453,7 +451,7 @@ class Control {
|
|
|
453
451
|
}
|
|
454
452
|
watch(key, output) {
|
|
455
453
|
const { state } = this;
|
|
456
|
-
const {
|
|
454
|
+
const { set, enumerable = true } = output;
|
|
457
455
|
const subs = new Set();
|
|
458
456
|
this.observers.set(key, subs);
|
|
459
457
|
if ("value" in output)
|
|
@@ -467,8 +465,9 @@ class Control {
|
|
|
467
465
|
const event = OBSERVER.get(this);
|
|
468
466
|
if (event)
|
|
469
467
|
subs.add(event);
|
|
470
|
-
const value = get
|
|
471
|
-
|
|
468
|
+
const value = output.get
|
|
469
|
+
? output.get(this) : state[key];
|
|
470
|
+
return event && REGISTER.has(value)
|
|
472
471
|
? watch(value, event)
|
|
473
472
|
: value;
|
|
474
473
|
}
|
|
@@ -528,31 +527,30 @@ class Control {
|
|
|
528
527
|
this.observers.clear();
|
|
529
528
|
}
|
|
530
529
|
}
|
|
530
|
+
Control.ready = new Set();
|
|
531
531
|
Control.after = new Set();
|
|
532
532
|
Control.before = new Set();
|
|
533
533
|
Control.pending = new Set();
|
|
534
534
|
Control.for = control;
|
|
535
535
|
Control.apply = apply;
|
|
536
536
|
Control.watch = watch;
|
|
537
|
-
const PENDING_INIT = new WeakMap();
|
|
538
537
|
function control(subject, ready) {
|
|
539
538
|
const control = REGISTER.get(subject.is);
|
|
540
|
-
const
|
|
541
|
-
if (
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
control.state = {};
|
|
539
|
+
const pending = PENDING$1.get(control);
|
|
540
|
+
if (typeof ready == "function") {
|
|
541
|
+
if (!pending)
|
|
542
|
+
return ready(control);
|
|
543
|
+
let done;
|
|
544
|
+
pending.add(() => done = ready(control));
|
|
545
|
+
return () => done && done();
|
|
546
|
+
}
|
|
547
|
+
if (pending && ready) {
|
|
548
|
+
PENDING$1.delete(control);
|
|
551
549
|
for (const key in control.subject)
|
|
552
550
|
control.add(key);
|
|
553
|
-
|
|
551
|
+
pending.forEach(cb => cb(control));
|
|
554
552
|
}
|
|
555
|
-
return
|
|
553
|
+
return control;
|
|
556
554
|
}
|
|
557
555
|
function requestUpdateFrame(event) {
|
|
558
556
|
const { after, before, pending } = Control;
|
|
@@ -585,10 +583,10 @@ function setRecursive(on, key, value) {
|
|
|
585
583
|
on.watch(key, { set });
|
|
586
584
|
set(value);
|
|
587
585
|
}
|
|
588
|
-
function parent(child,
|
|
589
|
-
if (!
|
|
586
|
+
function parent(child, assign) {
|
|
587
|
+
if (!assign)
|
|
590
588
|
return PARENTS.get(child);
|
|
591
|
-
PARENTS.set(child,
|
|
589
|
+
PARENTS.set(child, assign);
|
|
592
590
|
}
|
|
593
591
|
function watch(on, cb) {
|
|
594
592
|
if (!on.hasOwnProperty("is"))
|
|
@@ -598,7 +596,7 @@ function watch(on, cb) {
|
|
|
598
596
|
}
|
|
599
597
|
function apply(instruction) {
|
|
600
598
|
const placeholder = Symbol("instruction");
|
|
601
|
-
INSTRUCTION.set(placeholder, (
|
|
599
|
+
INSTRUCTION.set(placeholder, (onto, key) => {
|
|
602
600
|
delete onto.subject[key];
|
|
603
601
|
const output = instruction.call(onto, key, onto);
|
|
604
602
|
if (output)
|
|
@@ -900,69 +898,63 @@ function use(input, argument) {
|
|
|
900
898
|
return apply((key, source) => {
|
|
901
899
|
const { state, subject } = source;
|
|
902
900
|
const required = argument !== false;
|
|
903
|
-
let pending;
|
|
904
|
-
let error;
|
|
905
901
|
if (typeof input === "function") {
|
|
906
902
|
if ("prototype" in input && input === input.prototype.constructor)
|
|
907
903
|
input = new input();
|
|
908
904
|
}
|
|
909
905
|
else if (input && typeof input !== "object")
|
|
910
906
|
throw Oops$1.BadArgument(typeof input);
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
if (next) {
|
|
914
|
-
parent(next, subject);
|
|
915
|
-
control(next, true);
|
|
916
|
-
}
|
|
917
|
-
if (typeof argument == "function")
|
|
918
|
-
argument(next);
|
|
919
|
-
return true;
|
|
920
|
-
};
|
|
921
|
-
const suspend = () => {
|
|
922
|
-
if (required === false)
|
|
923
|
-
return;
|
|
924
|
-
const issue = Oops$1.NotReady(subject, key);
|
|
925
|
-
assign(pending, {
|
|
926
|
-
message: issue.message,
|
|
927
|
-
stack: issue.stack
|
|
928
|
-
});
|
|
929
|
-
throw pending;
|
|
930
|
-
};
|
|
931
|
-
const initialize = () => {
|
|
932
|
-
const output = typeof input == "function" ?
|
|
907
|
+
function init() {
|
|
908
|
+
const result = typeof input == "function" ?
|
|
933
909
|
mayRetry(() => input.call(subject, subject)) :
|
|
934
910
|
input;
|
|
935
|
-
if (
|
|
936
|
-
pending =
|
|
937
|
-
.then(
|
|
938
|
-
|
|
939
|
-
|
|
911
|
+
if (result instanceof Promise) {
|
|
912
|
+
const pending = result
|
|
913
|
+
.then(value => {
|
|
914
|
+
output.get = undefined;
|
|
915
|
+
set(value);
|
|
916
|
+
return value;
|
|
917
|
+
})
|
|
918
|
+
.catch(err => {
|
|
919
|
+
output.get = () => { throw err; };
|
|
940
920
|
})
|
|
941
|
-
.catch(err => error = err)
|
|
942
921
|
.finally(() => {
|
|
943
|
-
pending = undefined;
|
|
944
922
|
source.update(key);
|
|
945
923
|
});
|
|
946
|
-
|
|
924
|
+
if (required !== false)
|
|
925
|
+
output.get = () => {
|
|
926
|
+
throw assign(pending, Oops$1.NotReady(subject, key));
|
|
927
|
+
};
|
|
947
928
|
}
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
if (pending)
|
|
956
|
-
return suspend();
|
|
957
|
-
if (error)
|
|
958
|
-
throw error;
|
|
959
|
-
if (!(key in state))
|
|
960
|
-
initialize();
|
|
961
|
-
if (pending)
|
|
962
|
-
return suspend();
|
|
963
|
-
return state[key];
|
|
929
|
+
else
|
|
930
|
+
set(result);
|
|
931
|
+
}
|
|
932
|
+
function set(next) {
|
|
933
|
+
if (next instanceof Model) {
|
|
934
|
+
parent(next, subject);
|
|
935
|
+
control(next, true);
|
|
964
936
|
}
|
|
965
|
-
|
|
937
|
+
else if (next) {
|
|
938
|
+
const control = new Control(create(next));
|
|
939
|
+
control.state = next;
|
|
940
|
+
for (const key in next)
|
|
941
|
+
control.watch(key, {});
|
|
942
|
+
next = control.subject;
|
|
943
|
+
}
|
|
944
|
+
state[key] = next;
|
|
945
|
+
if (typeof argument == "function")
|
|
946
|
+
argument(next);
|
|
947
|
+
return true;
|
|
948
|
+
}
|
|
949
|
+
const output = { set };
|
|
950
|
+
if (required)
|
|
951
|
+
init();
|
|
952
|
+
else
|
|
953
|
+
output.get = () => {
|
|
954
|
+
init();
|
|
955
|
+
return state[key];
|
|
956
|
+
};
|
|
957
|
+
return output;
|
|
966
958
|
});
|
|
967
959
|
}
|
|
968
960
|
|
|
@@ -998,8 +990,12 @@ class Context {
|
|
|
998
990
|
this.layer.set(key, input);
|
|
999
991
|
init.set(instance, true);
|
|
1000
992
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
993
|
+
// Context must force-reset becasue inputs are no longer safe.
|
|
994
|
+
else if (exists !== input) {
|
|
995
|
+
this.pop();
|
|
996
|
+
this.key = uid();
|
|
997
|
+
return this.include(inputs);
|
|
998
|
+
}
|
|
1003
999
|
}
|
|
1004
1000
|
for (const [model] of init) {
|
|
1005
1001
|
const { state } = control(model, true);
|
|
@@ -1012,12 +1008,6 @@ class Context {
|
|
|
1012
1008
|
}
|
|
1013
1009
|
return init;
|
|
1014
1010
|
}
|
|
1015
|
-
/** Context must force-reset becasue inputs are no longer safe. */
|
|
1016
|
-
bailout(inputs) {
|
|
1017
|
-
this.pop();
|
|
1018
|
-
this.key = uid();
|
|
1019
|
-
return this.include(inputs);
|
|
1020
|
-
}
|
|
1021
1011
|
add(input, implicit) {
|
|
1022
1012
|
let writable = true;
|
|
1023
1013
|
let T;
|
package/lib/index.js
CHANGED
|
@@ -201,18 +201,18 @@ function awaitUpdate(source, select, timeout) {
|
|
|
201
201
|
const Oops$6 = issues({
|
|
202
202
|
NotFound: (name) => `Could not find ${name} in context.`
|
|
203
203
|
});
|
|
204
|
-
function get$1(
|
|
204
|
+
function get$1(argument) {
|
|
205
205
|
return Control.get((dispatch, context) => {
|
|
206
206
|
const refresh = () => dispatch(x => x + 1);
|
|
207
207
|
let onUpdate;
|
|
208
208
|
let value;
|
|
209
|
-
if (typeof
|
|
209
|
+
if (typeof argument !== "function") {
|
|
210
210
|
const got = context.get(this);
|
|
211
211
|
if (got)
|
|
212
|
-
value =
|
|
212
|
+
value = argument === undefined
|
|
213
213
|
? Control.watch(got, k => k ? onUpdate : undefined)
|
|
214
214
|
: got;
|
|
215
|
-
else if (
|
|
215
|
+
else if (argument !== false)
|
|
216
216
|
throw Oops$6.NotFound(this);
|
|
217
217
|
return {
|
|
218
218
|
mount() {
|
|
@@ -222,7 +222,7 @@ function get$1(arg1, arg2) {
|
|
|
222
222
|
render: () => value
|
|
223
223
|
};
|
|
224
224
|
}
|
|
225
|
-
let compute =
|
|
225
|
+
let compute = argument;
|
|
226
226
|
let suspense;
|
|
227
227
|
let getValue;
|
|
228
228
|
let factory;
|
|
@@ -230,9 +230,6 @@ function get$1(arg1, arg2) {
|
|
|
230
230
|
const found = context.get(this);
|
|
231
231
|
if (!found)
|
|
232
232
|
throw Oops$6.NotFound(this);
|
|
233
|
-
proxy = Control.watch(found, () => factory ? null : onUpdate);
|
|
234
|
-
getValue = () => compute.call(proxy, proxy, forceUpdate);
|
|
235
|
-
value = getValue();
|
|
236
233
|
function forceUpdate(action) {
|
|
237
234
|
if (typeof action == "function")
|
|
238
235
|
action = action();
|
|
@@ -243,6 +240,18 @@ function get$1(arg1, arg2) {
|
|
|
243
240
|
if (action)
|
|
244
241
|
return action.finally(refresh);
|
|
245
242
|
}
|
|
243
|
+
function didUpdate(got) {
|
|
244
|
+
value = got;
|
|
245
|
+
if (suspense) {
|
|
246
|
+
suspense();
|
|
247
|
+
suspense = undefined;
|
|
248
|
+
}
|
|
249
|
+
else
|
|
250
|
+
refresh();
|
|
251
|
+
}
|
|
252
|
+
proxy = Control.watch(found, () => factory ? null : onUpdate);
|
|
253
|
+
getValue = () => compute.call(proxy, proxy, forceUpdate);
|
|
254
|
+
value = getValue();
|
|
246
255
|
if (value === null) {
|
|
247
256
|
getValue = undefined;
|
|
248
257
|
onUpdate = null;
|
|
@@ -255,15 +264,6 @@ function get$1(arg1, arg2) {
|
|
|
255
264
|
compute = () => get();
|
|
256
265
|
value = get();
|
|
257
266
|
}
|
|
258
|
-
const didUpdate = (got) => {
|
|
259
|
-
value = got;
|
|
260
|
-
if (suspense) {
|
|
261
|
-
suspense();
|
|
262
|
-
suspense = undefined;
|
|
263
|
-
}
|
|
264
|
-
else
|
|
265
|
-
refresh();
|
|
266
|
-
};
|
|
267
267
|
if (value instanceof Promise) {
|
|
268
268
|
onUpdate = null;
|
|
269
269
|
value.then(didUpdate);
|
|
@@ -272,7 +272,7 @@ function get$1(arg1, arg2) {
|
|
|
272
272
|
else
|
|
273
273
|
onUpdate = () => {
|
|
274
274
|
const next = getValue();
|
|
275
|
-
if (
|
|
275
|
+
if (value !== next)
|
|
276
276
|
didUpdate(next);
|
|
277
277
|
};
|
|
278
278
|
return {
|
|
@@ -282,30 +282,25 @@ function get$1(arg1, arg2) {
|
|
|
282
282
|
render: () => {
|
|
283
283
|
if (value !== undefined)
|
|
284
284
|
return value;
|
|
285
|
-
if (
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
285
|
+
if (onUpdate)
|
|
286
|
+
return null;
|
|
287
|
+
throw new Promise(res => {
|
|
288
|
+
suspense = res;
|
|
289
|
+
});
|
|
290
290
|
}
|
|
291
291
|
};
|
|
292
292
|
});
|
|
293
|
-
}
|
|
294
|
-
/** Values are not equal for purposes of a refresh. */
|
|
295
|
-
const notEqual = (a, b) => (b !== a && (!Array.isArray(a) ||
|
|
296
|
-
!Array.isArray(b) ||
|
|
297
|
-
a.length !== b.length ||
|
|
298
|
-
a.some((x, i) => x !== b[i])));
|
|
293
|
+
}
|
|
299
294
|
|
|
300
|
-
function use$1(
|
|
295
|
+
function use$1(apply, repeat) {
|
|
301
296
|
const render = Control.use(dispatch => {
|
|
302
297
|
const instance = this.new();
|
|
303
298
|
const local = Control.watch(instance, () => onUpdate);
|
|
304
299
|
const refresh = () => dispatch(x => x + 1);
|
|
305
300
|
let onUpdate;
|
|
306
|
-
let
|
|
301
|
+
let shouldApply = !!apply;
|
|
307
302
|
return {
|
|
308
|
-
|
|
303
|
+
instance,
|
|
309
304
|
mount() {
|
|
310
305
|
onUpdate = refresh;
|
|
311
306
|
return () => {
|
|
@@ -314,7 +309,7 @@ function use$1(arg1, arg2) {
|
|
|
314
309
|
};
|
|
315
310
|
},
|
|
316
311
|
render(props) {
|
|
317
|
-
if (
|
|
312
|
+
if (shouldApply) {
|
|
318
313
|
onUpdate = undefined;
|
|
319
314
|
if (typeof props == "function")
|
|
320
315
|
props(instance);
|
|
@@ -322,15 +317,15 @@ function use$1(arg1, arg2) {
|
|
|
322
317
|
for (const key in instance)
|
|
323
318
|
if (props.hasOwnProperty(key))
|
|
324
319
|
instance[key] = props[key];
|
|
325
|
-
if (!
|
|
326
|
-
|
|
320
|
+
if (!repeat)
|
|
321
|
+
shouldApply = false;
|
|
327
322
|
instance.on(0).then(() => onUpdate = refresh);
|
|
328
323
|
}
|
|
329
324
|
return local;
|
|
330
325
|
}
|
|
331
326
|
};
|
|
332
327
|
});
|
|
333
|
-
return render(
|
|
328
|
+
return render(apply);
|
|
334
329
|
}
|
|
335
330
|
|
|
336
331
|
class Model {
|
|
@@ -431,24 +426,27 @@ const Oops$5 = issues({
|
|
|
431
426
|
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
432
427
|
});
|
|
433
428
|
const INSTRUCTION = new Map();
|
|
429
|
+
const PENDING$1 = new WeakMap();
|
|
434
430
|
const REGISTER = new WeakMap();
|
|
435
431
|
const OBSERVER = new WeakMap();
|
|
436
432
|
const PARENTS = new WeakMap();
|
|
437
433
|
class Control {
|
|
438
|
-
constructor(subject, id
|
|
439
|
-
this.
|
|
440
|
-
this.id = id;
|
|
434
|
+
constructor(subject, id) {
|
|
435
|
+
this.state = {};
|
|
441
436
|
this.frame = new Set();
|
|
442
437
|
this.followers = new Set();
|
|
443
438
|
this.observers = new Map([["", this.followers]]);
|
|
439
|
+
this.id = typeof id == "undefined" ? uid() : id;
|
|
440
|
+
this.subject = subject;
|
|
444
441
|
REGISTER.set(subject, this);
|
|
442
|
+
PENDING$1.set(this, new Set(Control.ready));
|
|
445
443
|
}
|
|
446
444
|
add(key) {
|
|
447
445
|
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
448
446
|
const instruction = INSTRUCTION.get(value);
|
|
449
447
|
if (typeof instruction == "function") {
|
|
450
448
|
INSTRUCTION.delete(value);
|
|
451
|
-
instruction(
|
|
449
|
+
instruction(this, key);
|
|
452
450
|
}
|
|
453
451
|
else if (value instanceof Model)
|
|
454
452
|
setRecursive(this, key, value);
|
|
@@ -457,7 +455,7 @@ class Control {
|
|
|
457
455
|
}
|
|
458
456
|
watch(key, output) {
|
|
459
457
|
const { state } = this;
|
|
460
|
-
const {
|
|
458
|
+
const { set, enumerable = true } = output;
|
|
461
459
|
const subs = new Set();
|
|
462
460
|
this.observers.set(key, subs);
|
|
463
461
|
if ("value" in output)
|
|
@@ -471,8 +469,9 @@ class Control {
|
|
|
471
469
|
const event = OBSERVER.get(this);
|
|
472
470
|
if (event)
|
|
473
471
|
subs.add(event);
|
|
474
|
-
const value = get
|
|
475
|
-
|
|
472
|
+
const value = output.get
|
|
473
|
+
? output.get(this) : state[key];
|
|
474
|
+
return event && REGISTER.has(value)
|
|
476
475
|
? watch(value, event)
|
|
477
476
|
: value;
|
|
478
477
|
}
|
|
@@ -532,31 +531,30 @@ class Control {
|
|
|
532
531
|
this.observers.clear();
|
|
533
532
|
}
|
|
534
533
|
}
|
|
534
|
+
Control.ready = new Set();
|
|
535
535
|
Control.after = new Set();
|
|
536
536
|
Control.before = new Set();
|
|
537
537
|
Control.pending = new Set();
|
|
538
538
|
Control.for = control;
|
|
539
539
|
Control.apply = apply;
|
|
540
540
|
Control.watch = watch;
|
|
541
|
-
const PENDING_INIT = new WeakMap();
|
|
542
541
|
function control(subject, ready) {
|
|
543
542
|
const control = REGISTER.get(subject.is);
|
|
544
|
-
const
|
|
545
|
-
if (
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
control.state = {};
|
|
543
|
+
const pending = PENDING$1.get(control);
|
|
544
|
+
if (typeof ready == "function") {
|
|
545
|
+
if (!pending)
|
|
546
|
+
return ready(control);
|
|
547
|
+
let done;
|
|
548
|
+
pending.add(() => done = ready(control));
|
|
549
|
+
return () => done && done();
|
|
550
|
+
}
|
|
551
|
+
if (pending && ready) {
|
|
552
|
+
PENDING$1.delete(control);
|
|
555
553
|
for (const key in control.subject)
|
|
556
554
|
control.add(key);
|
|
557
|
-
|
|
555
|
+
pending.forEach(cb => cb(control));
|
|
558
556
|
}
|
|
559
|
-
return
|
|
557
|
+
return control;
|
|
560
558
|
}
|
|
561
559
|
function requestUpdateFrame(event) {
|
|
562
560
|
const { after, before, pending } = Control;
|
|
@@ -589,10 +587,10 @@ function setRecursive(on, key, value) {
|
|
|
589
587
|
on.watch(key, { set });
|
|
590
588
|
set(value);
|
|
591
589
|
}
|
|
592
|
-
function parent(child,
|
|
593
|
-
if (!
|
|
590
|
+
function parent(child, assign) {
|
|
591
|
+
if (!assign)
|
|
594
592
|
return PARENTS.get(child);
|
|
595
|
-
PARENTS.set(child,
|
|
593
|
+
PARENTS.set(child, assign);
|
|
596
594
|
}
|
|
597
595
|
function watch(on, cb) {
|
|
598
596
|
if (!on.hasOwnProperty("is"))
|
|
@@ -602,7 +600,7 @@ function watch(on, cb) {
|
|
|
602
600
|
}
|
|
603
601
|
function apply(instruction) {
|
|
604
602
|
const placeholder = Symbol("instruction");
|
|
605
|
-
INSTRUCTION.set(placeholder, (
|
|
603
|
+
INSTRUCTION.set(placeholder, (onto, key) => {
|
|
606
604
|
delete onto.subject[key];
|
|
607
605
|
const output = instruction.call(onto, key, onto);
|
|
608
606
|
if (output)
|
|
@@ -904,69 +902,63 @@ function use(input, argument) {
|
|
|
904
902
|
return apply((key, source) => {
|
|
905
903
|
const { state, subject } = source;
|
|
906
904
|
const required = argument !== false;
|
|
907
|
-
let pending;
|
|
908
|
-
let error;
|
|
909
905
|
if (typeof input === "function") {
|
|
910
906
|
if ("prototype" in input && input === input.prototype.constructor)
|
|
911
907
|
input = new input();
|
|
912
908
|
}
|
|
913
909
|
else if (input && typeof input !== "object")
|
|
914
910
|
throw Oops$1.BadArgument(typeof input);
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
if (next) {
|
|
918
|
-
parent(next, subject);
|
|
919
|
-
control(next, true);
|
|
920
|
-
}
|
|
921
|
-
if (typeof argument == "function")
|
|
922
|
-
argument(next);
|
|
923
|
-
return true;
|
|
924
|
-
};
|
|
925
|
-
const suspend = () => {
|
|
926
|
-
if (required === false)
|
|
927
|
-
return;
|
|
928
|
-
const issue = Oops$1.NotReady(subject, key);
|
|
929
|
-
assign(pending, {
|
|
930
|
-
message: issue.message,
|
|
931
|
-
stack: issue.stack
|
|
932
|
-
});
|
|
933
|
-
throw pending;
|
|
934
|
-
};
|
|
935
|
-
const initialize = () => {
|
|
936
|
-
const output = typeof input == "function" ?
|
|
911
|
+
function init() {
|
|
912
|
+
const result = typeof input == "function" ?
|
|
937
913
|
mayRetry(() => input.call(subject, subject)) :
|
|
938
914
|
input;
|
|
939
|
-
if (
|
|
940
|
-
pending =
|
|
941
|
-
.then(
|
|
942
|
-
|
|
943
|
-
|
|
915
|
+
if (result instanceof Promise) {
|
|
916
|
+
const pending = result
|
|
917
|
+
.then(value => {
|
|
918
|
+
output.get = undefined;
|
|
919
|
+
set(value);
|
|
920
|
+
return value;
|
|
921
|
+
})
|
|
922
|
+
.catch(err => {
|
|
923
|
+
output.get = () => { throw err; };
|
|
944
924
|
})
|
|
945
|
-
.catch(err => error = err)
|
|
946
925
|
.finally(() => {
|
|
947
|
-
pending = undefined;
|
|
948
926
|
source.update(key);
|
|
949
927
|
});
|
|
950
|
-
|
|
928
|
+
if (required !== false)
|
|
929
|
+
output.get = () => {
|
|
930
|
+
throw assign(pending, Oops$1.NotReady(subject, key));
|
|
931
|
+
};
|
|
951
932
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
if (pending)
|
|
960
|
-
return suspend();
|
|
961
|
-
if (error)
|
|
962
|
-
throw error;
|
|
963
|
-
if (!(key in state))
|
|
964
|
-
initialize();
|
|
965
|
-
if (pending)
|
|
966
|
-
return suspend();
|
|
967
|
-
return state[key];
|
|
933
|
+
else
|
|
934
|
+
set(result);
|
|
935
|
+
}
|
|
936
|
+
function set(next) {
|
|
937
|
+
if (next instanceof Model) {
|
|
938
|
+
parent(next, subject);
|
|
939
|
+
control(next, true);
|
|
968
940
|
}
|
|
969
|
-
|
|
941
|
+
else if (next) {
|
|
942
|
+
const control = new Control(create(next));
|
|
943
|
+
control.state = next;
|
|
944
|
+
for (const key in next)
|
|
945
|
+
control.watch(key, {});
|
|
946
|
+
next = control.subject;
|
|
947
|
+
}
|
|
948
|
+
state[key] = next;
|
|
949
|
+
if (typeof argument == "function")
|
|
950
|
+
argument(next);
|
|
951
|
+
return true;
|
|
952
|
+
}
|
|
953
|
+
const output = { set };
|
|
954
|
+
if (required)
|
|
955
|
+
init();
|
|
956
|
+
else
|
|
957
|
+
output.get = () => {
|
|
958
|
+
init();
|
|
959
|
+
return state[key];
|
|
960
|
+
};
|
|
961
|
+
return output;
|
|
970
962
|
});
|
|
971
963
|
}
|
|
972
964
|
|
|
@@ -1002,8 +994,12 @@ class Context {
|
|
|
1002
994
|
this.layer.set(key, input);
|
|
1003
995
|
init.set(instance, true);
|
|
1004
996
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
997
|
+
// Context must force-reset becasue inputs are no longer safe.
|
|
998
|
+
else if (exists !== input) {
|
|
999
|
+
this.pop();
|
|
1000
|
+
this.key = uid();
|
|
1001
|
+
return this.include(inputs);
|
|
1002
|
+
}
|
|
1007
1003
|
}
|
|
1008
1004
|
for (const [model] of init) {
|
|
1009
1005
|
const { state } = control(model, true);
|
|
@@ -1016,12 +1012,6 @@ class Context {
|
|
|
1016
1012
|
}
|
|
1017
1013
|
return init;
|
|
1018
1014
|
}
|
|
1019
|
-
/** Context must force-reset becasue inputs are no longer safe. */
|
|
1020
|
-
bailout(inputs) {
|
|
1021
|
-
this.pop();
|
|
1022
|
-
this.key = uid();
|
|
1023
|
-
return this.include(inputs);
|
|
1024
|
-
}
|
|
1025
1015
|
add(input, implicit) {
|
|
1026
1016
|
let writable = true;
|
|
1027
1017
|
let T;
|
package/package.json
CHANGED
|
@@ -22,8 +22,10 @@
|
|
|
22
22
|
"scripts": {
|
|
23
23
|
"build": "rollup --config",
|
|
24
24
|
"watch": "jest --watchAll",
|
|
25
|
-
"test": "jest --collectCoverage"
|
|
25
|
+
"test": "jest --collectCoverage",
|
|
26
|
+
"prebuild": "rm -rf lib/",
|
|
27
|
+
"preversion": "npm run test && npm run build"
|
|
26
28
|
},
|
|
27
|
-
"version": "0.
|
|
28
|
-
"gitHead": "
|
|
29
|
+
"version": "0.25.0",
|
|
30
|
+
"gitHead": "a7c707bf59325bd4bf1388e061f7991acb726a13"
|
|
29
31
|
}
|