@expressive/mvc 0.24.2 → 0.26.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 +50 -34
- package/lib/index.esm.js +140 -175
- package/lib/index.js +140 -175
- package/package.json +2 -2
package/lib/index.d.ts
CHANGED
|
@@ -57,16 +57,17 @@ declare namespace Control {
|
|
|
57
57
|
type Getter<T> = (source: Model) => T;
|
|
58
58
|
type Setter<T> = (value: T) => boolean | void;
|
|
59
59
|
type PropertyDescriptor<T = any> = {
|
|
60
|
-
enumerable?: boolean;
|
|
61
|
-
value?: T;
|
|
62
60
|
get?: Getter<T>;
|
|
63
61
|
set?: Setter<T> | false;
|
|
62
|
+
enumerable?: boolean;
|
|
63
|
+
value?: T;
|
|
64
64
|
};
|
|
65
|
+
type Callback = (control: Control) => void;
|
|
65
66
|
/**
|
|
66
67
|
* Callback for Controller.for() static method.
|
|
67
68
|
* Returned callback is forwarded.
|
|
68
69
|
*/
|
|
69
|
-
type OnReady<T extends {}> = (control: Control<T>) =>
|
|
70
|
+
type OnReady<T extends {}> = (control: Control<T>) => (() => void) | void;
|
|
70
71
|
type RequestRefresh = (update: (tick: number) => number) => void;
|
|
71
72
|
type GetContext = (target: Model) => (callback: (got: Context) => void) => void;
|
|
72
73
|
type GetAdapter<T> = (refresh: RequestRefresh, context: Context) => {
|
|
@@ -75,15 +76,14 @@ declare namespace Control {
|
|
|
75
76
|
} | void;
|
|
76
77
|
type GetHook = <T>(adapter: GetAdapter<T>) => T | null;
|
|
77
78
|
type UseAdapter<T extends Model, R> = (refresh: RequestRefresh) => {
|
|
78
|
-
|
|
79
|
+
instance: T;
|
|
79
80
|
mount: () => (() => void) | void;
|
|
80
81
|
render: R;
|
|
81
82
|
};
|
|
82
83
|
type UseHook = <T extends Model, R>(adapter: UseAdapter<T, R>) => R;
|
|
83
84
|
}
|
|
84
85
|
declare class Control<T extends {} = any> {
|
|
85
|
-
|
|
86
|
-
id: string | number;
|
|
86
|
+
static ready: Set<Control.Callback>;
|
|
87
87
|
static after: Set<Callback>;
|
|
88
88
|
static before: Set<Callback>;
|
|
89
89
|
static pending: Set<Callback>;
|
|
@@ -93,6 +93,8 @@ declare class Control<T extends {} = any> {
|
|
|
93
93
|
static for: typeof control;
|
|
94
94
|
static apply: typeof apply;
|
|
95
95
|
static watch: typeof watch;
|
|
96
|
+
id: string | number;
|
|
97
|
+
subject: T;
|
|
96
98
|
state: {
|
|
97
99
|
[key: string]: any;
|
|
98
100
|
};
|
|
@@ -102,7 +104,7 @@ declare class Control<T extends {} = any> {
|
|
|
102
104
|
observers: Map<string, Set<Observer<any>>>;
|
|
103
105
|
constructor(subject: T, id?: string | number);
|
|
104
106
|
add(key: Extract<keyof T, string>): void;
|
|
105
|
-
watch(key: keyof T
|
|
107
|
+
watch(key: Extract<keyof T, string>, output: Control.PropertyDescriptor<any>): void;
|
|
106
108
|
ref<K extends Model.Key<T>>(key: K, callback?: (this: T, value: T[K]) => boolean | void): (value: any) => void;
|
|
107
109
|
update(key: string): void;
|
|
108
110
|
addListener(fn: Observer): () => boolean;
|
|
@@ -154,19 +156,12 @@ type Debug<T extends Model = Model> = T & {
|
|
|
154
156
|
|
|
155
157
|
/** Type may not be undefined - instead will be null. */
|
|
156
158
|
type NoVoid<T> = T extends undefined | void ? null : T;
|
|
157
|
-
|
|
158
|
-
/** Fetch instance of this class in passive mode. Will not subscribe to events. */
|
|
159
|
+
/** Fetch instance of this class from context. */
|
|
159
160
|
declare function get$1<T extends Model>(this: Model.Type<T>, ignoreUpdates?: true): T;
|
|
160
161
|
/** Fetch instance of this class optionally. May be undefined, but will never subscribe. */
|
|
161
162
|
declare function get$1<T extends Model>(this: Model.Type<T>, required: boolean): T | undefined;
|
|
162
|
-
declare function get$1<T extends Model, R
|
|
163
|
-
declare function get$1<T extends Model, R
|
|
164
|
-
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>;
|
|
165
|
-
declare function get$1<T extends Model, R>(this: Model.Type<T>, init: Model.GetCallback<T, () => R>): NoVoid<R>;
|
|
166
|
-
declare function get$1<T extends Model, R>(this: Model.Type<T>, init: Model.GetCallback<T, (() => R) | null>): NoVoid<R> | null;
|
|
167
|
-
declare function get$1<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R> | R>, expect: true): Exclude<R, undefined>;
|
|
168
|
-
declare function get$1<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R>>, expect?: boolean): NoVoid<R> | null;
|
|
169
|
-
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;
|
|
170
165
|
|
|
171
166
|
declare function use$1<T extends Model>(this: Model.New<T>, callback?: (instance: T) => void, repeat?: boolean): T;
|
|
172
167
|
declare function use$1<T extends Model>(this: Model.New<T>, apply?: Model.Compat<T>, repeat?: boolean): T;
|
|
@@ -251,7 +246,7 @@ declare class Model {
|
|
|
251
246
|
get<P extends Model.Key<this>>(select: Iterable<P>): Model.Get<this, P>;
|
|
252
247
|
get<P extends Model.Key<this>>(select: P, listener: (this: this, value: this[P]) => void): Callback;
|
|
253
248
|
get<P extends Model.Key<this>>(select: Iterable<P>, listener: (this: this, value: Model.Get<this, P>) => void): Callback;
|
|
254
|
-
set<T extends Model.Compat<this>>(source: T,
|
|
249
|
+
set<T extends Model.Compat<this>>(source: T, only?: (keyof T)[]): Promise<Model.Key<T>[]>;
|
|
255
250
|
set<K extends Model.Event<this>>(key: K, value?: Model.ValueOf<this, K>): Promise<Model.Event<this>[] | false>;
|
|
256
251
|
/** Mark this instance for garbage collection. */
|
|
257
252
|
null(): void;
|
|
@@ -379,25 +374,46 @@ declare function set<T>(factory: set.Factory<T> | Promise<T>, required?: boolean
|
|
|
379
374
|
declare function set<T>(value: undefined, onUpdate: set.Callback<T>): T;
|
|
380
375
|
declare function set<T>(value: T, onUpdate: set.Callback<T>): T;
|
|
381
376
|
|
|
377
|
+
type Empty = Record<string, never>;
|
|
378
|
+
declare namespace use {
|
|
379
|
+
type Key<T extends {}> = Extract<keyof T, string>;
|
|
380
|
+
/**
|
|
381
|
+
* Assign value to observable property.
|
|
382
|
+
*
|
|
383
|
+
* If property is not already observed, it will become so.
|
|
384
|
+
*/
|
|
385
|
+
type SetValue<T extends {}> = <K extends Key<T>>(property: K, value: T[K]) => void;
|
|
386
|
+
/**
|
|
387
|
+
* Observe property for updates.
|
|
388
|
+
*
|
|
389
|
+
* If property is not already observed, it will become so.
|
|
390
|
+
*/
|
|
391
|
+
type OnUpdate<T extends {}> = <K extends Key<T>>(property: K, callback: (value: T[K], key: K) => void) => () => void;
|
|
392
|
+
export type Observable<T extends {}> = T & {
|
|
393
|
+
set: SetValue<T>;
|
|
394
|
+
on: OnUpdate<T>;
|
|
395
|
+
};
|
|
396
|
+
export type Collection<T> = Observable<{
|
|
397
|
+
[key: string | number]: T;
|
|
398
|
+
}>;
|
|
399
|
+
export {};
|
|
400
|
+
}
|
|
382
401
|
/** Create a placeholder for specified Model type. */
|
|
383
402
|
declare function use<T extends Model>(): T | undefined;
|
|
384
403
|
/** Create a new child instance of model. */
|
|
385
|
-
declare function use<T extends Model>(Type: Model.New<T>,
|
|
386
|
-
/** Assign the result of a factory as a child model. */
|
|
387
|
-
declare function use<T extends {}>(from: () => Promise<T> | T, required?: true): T;
|
|
388
|
-
/** Assign the result of a factory as a child model. */
|
|
389
|
-
declare function use<T extends {}>(from: () => Promise<T> | T, required: boolean): T | undefined;
|
|
390
|
-
/** Create a managed child from factory function. */
|
|
391
|
-
declare function use<T extends {}>(from: () => Promise<T> | T, callback?: (i: T) => void): T;
|
|
392
|
-
declare function use<T extends {}>(data: T): T;
|
|
404
|
+
declare function use<T extends Model>(Type: Model.New<T>, ready?: (i: T) => void): T;
|
|
393
405
|
/**
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
declare function use<T extends Model>(
|
|
406
|
+
* Use existing model as a child of model assigned to.
|
|
407
|
+
*
|
|
408
|
+
* Note: If `peer` is not already initialized before parent is
|
|
409
|
+
* (created with `new` as opposed to create method), that model will
|
|
410
|
+
* attach this via `parent()` instruction. It will not, however, if
|
|
411
|
+
* already active.
|
|
412
|
+
**/
|
|
413
|
+
declare function use<T extends Model>(model: T, ready?: (i: T) => void): T;
|
|
414
|
+
/** Create a managed record with observable entries. */
|
|
415
|
+
declare function use<T = any, C = use.Collection<T>>(record: Empty, ready?: (object: C) => void): C;
|
|
416
|
+
/** Create a managed object with observable entries. */
|
|
417
|
+
declare function use<T extends {}, O = use.Observable<T>>(data: T, ready?: (object: O) => void): O;
|
|
402
418
|
|
|
403
419
|
export { Context, Control, Debug, Model, Model as default, get, ref, run, set, use };
|
package/lib/index.esm.js
CHANGED
|
@@ -42,25 +42,26 @@ function issues(register) {
|
|
|
42
42
|
|
|
43
43
|
const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
44
44
|
|
|
45
|
-
const Oops$
|
|
45
|
+
const Oops$8 = issues({
|
|
46
46
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
47
47
|
Destoryed: () => "Model is destroyed."
|
|
48
48
|
});
|
|
49
49
|
function suspense(source, key) {
|
|
50
|
-
const error = Oops$
|
|
50
|
+
const error = Oops$8.NotReady(source.subject, key);
|
|
51
|
+
const watch = source.observers.get(key);
|
|
51
52
|
const promise = new Promise((resolve, reject) => {
|
|
52
|
-
|
|
53
|
-
const onUpdate = (key) => {
|
|
53
|
+
function onUpdate(key) {
|
|
54
54
|
if (key)
|
|
55
55
|
return () => {
|
|
56
56
|
if (source.state[key] !== undefined) {
|
|
57
|
-
|
|
57
|
+
watch.delete(onUpdate);
|
|
58
58
|
resolve();
|
|
59
59
|
}
|
|
60
60
|
};
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
if (key === null)
|
|
62
|
+
reject(Oops$8.Destoryed());
|
|
63
|
+
}
|
|
64
|
+
watch.add(onUpdate);
|
|
64
65
|
});
|
|
65
66
|
return assign(promise, {
|
|
66
67
|
toString: () => String(error),
|
|
@@ -90,7 +91,7 @@ function mayRetry(fn) {
|
|
|
90
91
|
return compute();
|
|
91
92
|
}
|
|
92
93
|
|
|
93
|
-
const Oops$
|
|
94
|
+
const Oops$7 = issues({
|
|
94
95
|
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
95
96
|
});
|
|
96
97
|
function createEffect(source, callback) {
|
|
@@ -108,7 +109,7 @@ function createEffect(source, callback) {
|
|
|
108
109
|
if (unSet instanceof Promise)
|
|
109
110
|
unSet = undefined;
|
|
110
111
|
if (unSet && typeof unSet !== "function")
|
|
111
|
-
throw Oops$
|
|
112
|
+
throw Oops$7.BadCallback();
|
|
112
113
|
});
|
|
113
114
|
if (output instanceof Promise) {
|
|
114
115
|
output.finally(() => busy = false);
|
|
@@ -136,11 +137,11 @@ function createValueEffect(callback) {
|
|
|
136
137
|
if (typeof out == "function")
|
|
137
138
|
unSet = out;
|
|
138
139
|
else
|
|
139
|
-
throw Oops$
|
|
140
|
+
throw Oops$7.BadCallback();
|
|
140
141
|
};
|
|
141
142
|
}
|
|
142
143
|
|
|
143
|
-
const Oops$
|
|
144
|
+
const Oops$6 = issues({
|
|
144
145
|
KeysExpected: (key) => `Key "${key}" was expected in current update.`
|
|
145
146
|
});
|
|
146
147
|
function addEventListener(source, select, callback, once) {
|
|
@@ -175,7 +176,7 @@ function awaitUpdate(source, select, timeout) {
|
|
|
175
176
|
if (!self.frame.size)
|
|
176
177
|
resolve(false);
|
|
177
178
|
else if (typeof select == "string" && !self.frame.has(select))
|
|
178
|
-
reject(Oops$
|
|
179
|
+
reject(Oops$6.KeysExpected(select));
|
|
179
180
|
else {
|
|
180
181
|
const remove = self.addListener(() => {
|
|
181
182
|
remove();
|
|
@@ -194,22 +195,22 @@ function awaitUpdate(source, select, timeout) {
|
|
|
194
195
|
});
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
const Oops$
|
|
198
|
+
const Oops$5 = issues({
|
|
198
199
|
NotFound: (name) => `Could not find ${name} in context.`
|
|
199
200
|
});
|
|
200
|
-
function get$1(
|
|
201
|
+
function get$1(argument) {
|
|
201
202
|
return Control.get((dispatch, context) => {
|
|
202
203
|
const refresh = () => dispatch(x => x + 1);
|
|
203
204
|
let onUpdate;
|
|
204
205
|
let value;
|
|
205
|
-
if (typeof
|
|
206
|
+
if (typeof argument !== "function") {
|
|
206
207
|
const got = context.get(this);
|
|
207
208
|
if (got)
|
|
208
|
-
value =
|
|
209
|
+
value = argument === undefined
|
|
209
210
|
? Control.watch(got, k => k ? onUpdate : undefined)
|
|
210
211
|
: got;
|
|
211
|
-
else if (
|
|
212
|
-
throw Oops$
|
|
212
|
+
else if (argument !== false)
|
|
213
|
+
throw Oops$5.NotFound(this);
|
|
213
214
|
return {
|
|
214
215
|
mount() {
|
|
215
216
|
onUpdate = refresh;
|
|
@@ -218,14 +219,14 @@ function get$1(arg1, arg2) {
|
|
|
218
219
|
render: () => value
|
|
219
220
|
};
|
|
220
221
|
}
|
|
221
|
-
let compute =
|
|
222
|
+
let compute = argument;
|
|
222
223
|
let suspense;
|
|
223
224
|
let getValue;
|
|
224
225
|
let factory;
|
|
225
226
|
let proxy;
|
|
226
227
|
const found = context.get(this);
|
|
227
228
|
if (!found)
|
|
228
|
-
throw Oops$
|
|
229
|
+
throw Oops$5.NotFound(this);
|
|
229
230
|
function forceUpdate(action) {
|
|
230
231
|
if (typeof action == "function")
|
|
231
232
|
action = action();
|
|
@@ -268,7 +269,7 @@ function get$1(arg1, arg2) {
|
|
|
268
269
|
else
|
|
269
270
|
onUpdate = () => {
|
|
270
271
|
const next = getValue();
|
|
271
|
-
if (
|
|
272
|
+
if (value !== next)
|
|
272
273
|
didUpdate(next);
|
|
273
274
|
};
|
|
274
275
|
return {
|
|
@@ -278,30 +279,25 @@ function get$1(arg1, arg2) {
|
|
|
278
279
|
render: () => {
|
|
279
280
|
if (value !== undefined)
|
|
280
281
|
return value;
|
|
281
|
-
if (
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
282
|
+
if (onUpdate)
|
|
283
|
+
return null;
|
|
284
|
+
throw new Promise(res => {
|
|
285
|
+
suspense = res;
|
|
286
|
+
});
|
|
286
287
|
}
|
|
287
288
|
};
|
|
288
289
|
});
|
|
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])));
|
|
290
|
+
}
|
|
295
291
|
|
|
296
|
-
function use$1(
|
|
292
|
+
function use$1(apply, repeat) {
|
|
297
293
|
const render = Control.use(dispatch => {
|
|
298
294
|
const instance = this.new();
|
|
299
295
|
const local = Control.watch(instance, () => onUpdate);
|
|
300
296
|
const refresh = () => dispatch(x => x + 1);
|
|
301
297
|
let onUpdate;
|
|
302
|
-
let
|
|
298
|
+
let shouldApply = !!apply;
|
|
303
299
|
return {
|
|
304
|
-
|
|
300
|
+
instance,
|
|
305
301
|
mount() {
|
|
306
302
|
onUpdate = refresh;
|
|
307
303
|
return () => {
|
|
@@ -310,7 +306,7 @@ function use$1(arg1, arg2) {
|
|
|
310
306
|
};
|
|
311
307
|
},
|
|
312
308
|
render(props) {
|
|
313
|
-
if (
|
|
309
|
+
if (shouldApply) {
|
|
314
310
|
onUpdate = undefined;
|
|
315
311
|
if (typeof props == "function")
|
|
316
312
|
props(instance);
|
|
@@ -318,15 +314,15 @@ function use$1(arg1, arg2) {
|
|
|
318
314
|
for (const key in instance)
|
|
319
315
|
if (props.hasOwnProperty(key))
|
|
320
316
|
instance[key] = props[key];
|
|
321
|
-
if (!
|
|
322
|
-
|
|
317
|
+
if (!repeat)
|
|
318
|
+
shouldApply = false;
|
|
323
319
|
instance.on(0).then(() => onUpdate = refresh);
|
|
324
320
|
}
|
|
325
321
|
return local;
|
|
326
322
|
}
|
|
327
323
|
};
|
|
328
324
|
});
|
|
329
|
-
return render(
|
|
325
|
+
return render(apply);
|
|
330
326
|
}
|
|
331
327
|
|
|
332
328
|
class Model {
|
|
@@ -423,27 +419,30 @@ defineProperty(Model, "toString", {
|
|
|
423
419
|
}
|
|
424
420
|
});
|
|
425
421
|
|
|
426
|
-
const Oops$
|
|
422
|
+
const Oops$4 = issues({
|
|
427
423
|
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
428
424
|
});
|
|
429
|
-
const INSTRUCTION = new Map();
|
|
430
425
|
const REGISTER = new WeakMap();
|
|
431
426
|
const OBSERVER = new WeakMap();
|
|
427
|
+
const INSTRUCT = new Map();
|
|
428
|
+
const PENDING$1 = new WeakMap();
|
|
432
429
|
const PARENTS = new WeakMap();
|
|
433
430
|
class Control {
|
|
434
|
-
constructor(subject, id
|
|
435
|
-
this.
|
|
436
|
-
this.id = id;
|
|
431
|
+
constructor(subject, id) {
|
|
432
|
+
this.state = {};
|
|
437
433
|
this.frame = new Set();
|
|
438
434
|
this.followers = new Set();
|
|
439
435
|
this.observers = new Map([["", this.followers]]);
|
|
436
|
+
this.id = typeof id == "undefined" ? uid() : id;
|
|
437
|
+
this.subject = subject;
|
|
440
438
|
REGISTER.set(subject, this);
|
|
439
|
+
PENDING$1.set(this, new Set(Control.ready));
|
|
441
440
|
}
|
|
442
441
|
add(key) {
|
|
443
442
|
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
444
|
-
const instruction =
|
|
443
|
+
const instruction = INSTRUCT.get(value);
|
|
445
444
|
if (typeof instruction == "function") {
|
|
446
|
-
|
|
445
|
+
INSTRUCT.delete(value);
|
|
447
446
|
instruction(this, key);
|
|
448
447
|
}
|
|
449
448
|
else if (value instanceof Model)
|
|
@@ -529,31 +528,30 @@ class Control {
|
|
|
529
528
|
this.observers.clear();
|
|
530
529
|
}
|
|
531
530
|
}
|
|
531
|
+
Control.ready = new Set();
|
|
532
532
|
Control.after = new Set();
|
|
533
533
|
Control.before = new Set();
|
|
534
534
|
Control.pending = new Set();
|
|
535
535
|
Control.for = control;
|
|
536
536
|
Control.apply = apply;
|
|
537
537
|
Control.watch = watch;
|
|
538
|
-
const PENDING_INIT = new WeakMap();
|
|
539
538
|
function control(subject, ready) {
|
|
540
539
|
const control = REGISTER.get(subject.is);
|
|
541
|
-
const
|
|
542
|
-
if (
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
control.state = {};
|
|
540
|
+
const pending = PENDING$1.get(control);
|
|
541
|
+
if (typeof ready == "function") {
|
|
542
|
+
if (!pending)
|
|
543
|
+
return ready(control);
|
|
544
|
+
let done;
|
|
545
|
+
pending.add(() => done = ready(control));
|
|
546
|
+
return () => done && done();
|
|
547
|
+
}
|
|
548
|
+
if (pending && ready) {
|
|
549
|
+
PENDING$1.delete(control);
|
|
552
550
|
for (const key in control.subject)
|
|
553
551
|
control.add(key);
|
|
554
|
-
|
|
552
|
+
pending.forEach(cb => cb(control));
|
|
555
553
|
}
|
|
556
|
-
return
|
|
554
|
+
return control;
|
|
557
555
|
}
|
|
558
556
|
function requestUpdateFrame(event) {
|
|
559
557
|
const { after, before, pending } = Control;
|
|
@@ -581,15 +579,15 @@ function setRecursive(on, key, value) {
|
|
|
581
579
|
control(next, true);
|
|
582
580
|
return true;
|
|
583
581
|
}
|
|
584
|
-
throw Oops$
|
|
582
|
+
throw Oops$4.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
|
|
585
583
|
};
|
|
586
584
|
on.watch(key, { set });
|
|
587
585
|
set(value);
|
|
588
586
|
}
|
|
589
|
-
function parent(child,
|
|
590
|
-
if (!
|
|
587
|
+
function parent(child, assign) {
|
|
588
|
+
if (!assign)
|
|
591
589
|
return PARENTS.get(child);
|
|
592
|
-
PARENTS.set(child,
|
|
590
|
+
PARENTS.set(child, assign);
|
|
593
591
|
}
|
|
594
592
|
function watch(on, cb) {
|
|
595
593
|
if (!on.hasOwnProperty("is"))
|
|
@@ -599,7 +597,7 @@ function watch(on, cb) {
|
|
|
599
597
|
}
|
|
600
598
|
function apply(instruction) {
|
|
601
599
|
const placeholder = Symbol("instruction");
|
|
602
|
-
|
|
600
|
+
INSTRUCT.set(placeholder, (onto, key) => {
|
|
603
601
|
delete onto.subject[key];
|
|
604
602
|
const output = instruction.call(onto, key, onto);
|
|
605
603
|
if (output)
|
|
@@ -612,7 +610,7 @@ function uid() {
|
|
|
612
610
|
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
613
611
|
}
|
|
614
612
|
|
|
615
|
-
const Oops$
|
|
613
|
+
const Oops$3 = issues({
|
|
616
614
|
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
617
615
|
});
|
|
618
616
|
function run(task) {
|
|
@@ -620,7 +618,7 @@ function run(task) {
|
|
|
620
618
|
let pending = false;
|
|
621
619
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
622
620
|
if (pending)
|
|
623
|
-
return Promise.reject(Oops$
|
|
621
|
+
return Promise.reject(Oops$3.DuplicatePending(key));
|
|
624
622
|
pending = true;
|
|
625
623
|
control.update(key);
|
|
626
624
|
try {
|
|
@@ -642,7 +640,7 @@ function run(task) {
|
|
|
642
640
|
});
|
|
643
641
|
}
|
|
644
642
|
|
|
645
|
-
const Oops$
|
|
643
|
+
const Oops$2 = issues({
|
|
646
644
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
647
645
|
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} ${parent}.${property}.`,
|
|
648
646
|
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}.`,
|
|
@@ -653,7 +651,7 @@ function get(arg0, arg1) {
|
|
|
653
651
|
return apply((key, control) => {
|
|
654
652
|
let { subject } = control;
|
|
655
653
|
if (typeof arg0 == "symbol")
|
|
656
|
-
throw Oops$
|
|
654
|
+
throw Oops$2.PeerNotAllowed(subject, key);
|
|
657
655
|
let source = cb => cb(subject);
|
|
658
656
|
if (arg0 instanceof Model)
|
|
659
657
|
subject = arg0;
|
|
@@ -661,7 +659,7 @@ function get(arg0, arg1) {
|
|
|
661
659
|
const hasParent = parent(subject);
|
|
662
660
|
if (!hasParent) {
|
|
663
661
|
if (arg1 === true)
|
|
664
|
-
throw Oops$
|
|
662
|
+
throw Oops$2.Required(arg0, subject);
|
|
665
663
|
const fetch = Control.has(subject);
|
|
666
664
|
source = got => {
|
|
667
665
|
fetch(context => {
|
|
@@ -669,14 +667,14 @@ function get(arg0, arg1) {
|
|
|
669
667
|
if (model)
|
|
670
668
|
got(model);
|
|
671
669
|
else if (arg1 !== false)
|
|
672
|
-
throw Oops$
|
|
670
|
+
throw Oops$2.AmbientRequired(arg0, subject);
|
|
673
671
|
});
|
|
674
672
|
};
|
|
675
673
|
}
|
|
676
674
|
else if (!arg0 || hasParent instanceof arg0)
|
|
677
675
|
subject = hasParent;
|
|
678
676
|
else
|
|
679
|
-
throw Oops$
|
|
677
|
+
throw Oops$2.Unexpected(arg0, subject, hasParent);
|
|
680
678
|
}
|
|
681
679
|
else if (typeof arg0 == "function")
|
|
682
680
|
arg1 = arg0.call(subject, key, subject);
|
|
@@ -719,7 +717,7 @@ function computed(parent, key, source, setter) {
|
|
|
719
717
|
next = setter.call(proxy, proxy);
|
|
720
718
|
}
|
|
721
719
|
catch (err) {
|
|
722
|
-
Oops$
|
|
720
|
+
Oops$2.Failed(parent.subject, key, initial).warn();
|
|
723
721
|
if (initial)
|
|
724
722
|
throw err;
|
|
725
723
|
console.error(err);
|
|
@@ -807,7 +805,7 @@ function createRef(src, key, cb) {
|
|
|
807
805
|
return refObjectFunction;
|
|
808
806
|
}
|
|
809
807
|
|
|
810
|
-
const Oops$
|
|
808
|
+
const Oops$1 = issues({
|
|
811
809
|
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
812
810
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
813
811
|
});
|
|
@@ -815,150 +813,117 @@ function set(value, argument) {
|
|
|
815
813
|
return apply((key, control) => {
|
|
816
814
|
const { state, subject } = control;
|
|
817
815
|
if (typeof value == "function" || value instanceof Promise) {
|
|
818
|
-
const
|
|
819
|
-
let getter;
|
|
816
|
+
const output = {};
|
|
820
817
|
const init = () => {
|
|
821
818
|
try {
|
|
822
819
|
if (typeof value == "function")
|
|
823
820
|
value = mayRetry(value.bind(subject, key, subject));
|
|
824
|
-
let pending;
|
|
825
|
-
let error;
|
|
826
821
|
if (value instanceof Promise) {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
.
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
822
|
+
const pending = value
|
|
823
|
+
.then(value => {
|
|
824
|
+
output.get = undefined;
|
|
825
|
+
state[key] = value;
|
|
826
|
+
return value;
|
|
827
|
+
})
|
|
828
|
+
.catch(err => {
|
|
829
|
+
output.get = () => { throw err; };
|
|
833
830
|
})
|
|
834
831
|
.finally(() => {
|
|
835
|
-
pending = undefined;
|
|
836
832
|
control.update(key);
|
|
837
833
|
});
|
|
834
|
+
if (argument !== false)
|
|
835
|
+
return () => {
|
|
836
|
+
const { message, stack } = Oops$1.NotReady(subject, key);
|
|
837
|
+
throw assign(pending, { message, stack });
|
|
838
|
+
};
|
|
838
839
|
}
|
|
839
840
|
else
|
|
840
841
|
state[key] = value;
|
|
841
|
-
const suspend = () => {
|
|
842
|
-
if (required === false)
|
|
843
|
-
return undefined;
|
|
844
|
-
const issue = Oops$2.NotReady(subject, key);
|
|
845
|
-
assign(pending, {
|
|
846
|
-
message: issue.message,
|
|
847
|
-
stack: issue.stack
|
|
848
|
-
});
|
|
849
|
-
throw pending;
|
|
850
|
-
};
|
|
851
|
-
getter = () => {
|
|
852
|
-
if (error)
|
|
853
|
-
throw error;
|
|
854
|
-
if (pending)
|
|
855
|
-
return suspend();
|
|
856
|
-
return state[key];
|
|
857
|
-
};
|
|
858
842
|
}
|
|
859
843
|
catch (err) {
|
|
860
|
-
Oops$
|
|
844
|
+
Oops$1.ComputeFailed(subject, key).warn();
|
|
861
845
|
throw err;
|
|
862
846
|
}
|
|
863
847
|
};
|
|
864
|
-
if (argument
|
|
848
|
+
if (argument)
|
|
865
849
|
init();
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
850
|
+
else
|
|
851
|
+
output.get = () => {
|
|
852
|
+
const get = output.get =
|
|
853
|
+
key in state ? undefined : init();
|
|
854
|
+
return get ? get() : state[key];
|
|
855
|
+
};
|
|
856
|
+
return output;
|
|
871
857
|
}
|
|
872
|
-
|
|
858
|
+
const set = typeof argument == "function"
|
|
873
859
|
? createValueEffect(argument)
|
|
874
860
|
: undefined;
|
|
875
|
-
if (value !== undefined)
|
|
861
|
+
if (value !== undefined) {
|
|
876
862
|
state[key] = value;
|
|
877
|
-
|
|
878
|
-
const effect = setter;
|
|
879
|
-
setter = function (value) {
|
|
880
|
-
if (!(key in state))
|
|
881
|
-
state[key] = undefined;
|
|
882
|
-
return effect.call(this, value);
|
|
883
|
-
};
|
|
863
|
+
return { set };
|
|
884
864
|
}
|
|
885
|
-
|
|
886
|
-
get
|
|
865
|
+
const output = {
|
|
866
|
+
get() {
|
|
887
867
|
if (key in state)
|
|
888
868
|
return state[key];
|
|
889
869
|
throw suspense(control, key);
|
|
890
|
-
}
|
|
891
|
-
set: setter
|
|
870
|
+
}
|
|
892
871
|
};
|
|
872
|
+
if (set)
|
|
873
|
+
output.set = function (value) {
|
|
874
|
+
output.set = set;
|
|
875
|
+
state[key] = state[key];
|
|
876
|
+
return set.call(this, value);
|
|
877
|
+
};
|
|
878
|
+
return output;
|
|
893
879
|
});
|
|
894
880
|
}
|
|
895
881
|
|
|
896
|
-
const Oops$1 = issues({
|
|
897
|
-
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
898
|
-
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
899
|
-
});
|
|
900
882
|
function use(input, argument) {
|
|
901
883
|
return apply((key, source) => {
|
|
902
884
|
const { state, subject } = source;
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
if ("prototype" in input && input === input.prototype.constructor)
|
|
906
|
-
input = new input();
|
|
907
|
-
}
|
|
908
|
-
else if (input && typeof input !== "object")
|
|
909
|
-
throw Oops$1.BadArgument(typeof input);
|
|
910
|
-
function init() {
|
|
911
|
-
const result = typeof input == "function" ?
|
|
912
|
-
mayRetry(() => input.call(subject, subject)) :
|
|
913
|
-
input;
|
|
914
|
-
if (result instanceof Promise) {
|
|
915
|
-
const pending = result
|
|
916
|
-
.then(value => {
|
|
917
|
-
output.get = undefined;
|
|
918
|
-
set(value);
|
|
919
|
-
return value;
|
|
920
|
-
})
|
|
921
|
-
.catch(err => {
|
|
922
|
-
output.get = () => { throw err; };
|
|
923
|
-
})
|
|
924
|
-
.finally(() => {
|
|
925
|
-
source.update(key);
|
|
926
|
-
});
|
|
927
|
-
if (required !== false)
|
|
928
|
-
output.get = () => {
|
|
929
|
-
throw assign(pending, Oops$1.NotReady(subject, key));
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
else
|
|
933
|
-
set(result);
|
|
934
|
-
}
|
|
885
|
+
if (typeof input === "function")
|
|
886
|
+
input = new input();
|
|
935
887
|
function set(next) {
|
|
936
888
|
if (next instanceof Model) {
|
|
937
889
|
parent(next, subject);
|
|
938
890
|
control(next, true);
|
|
939
891
|
}
|
|
940
|
-
else if (next)
|
|
941
|
-
|
|
942
|
-
control.state = next;
|
|
943
|
-
for (const key in next)
|
|
944
|
-
control.watch(key, {});
|
|
945
|
-
next = control.subject;
|
|
946
|
-
}
|
|
892
|
+
else if (next)
|
|
893
|
+
next = manage(next);
|
|
947
894
|
state[key] = next;
|
|
948
895
|
if (typeof argument == "function")
|
|
949
896
|
argument(next);
|
|
950
897
|
return true;
|
|
951
898
|
}
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
init();
|
|
955
|
-
else
|
|
956
|
-
output.get = () => {
|
|
957
|
-
init();
|
|
958
|
-
return state[key];
|
|
959
|
-
};
|
|
960
|
-
return output;
|
|
899
|
+
set(input);
|
|
900
|
+
return { set };
|
|
961
901
|
});
|
|
902
|
+
}
|
|
903
|
+
function manage(next) {
|
|
904
|
+
const methods = {
|
|
905
|
+
on(key, callback) {
|
|
906
|
+
if (!(key in next))
|
|
907
|
+
control.watch(key, { value: subject[key] });
|
|
908
|
+
return control.addListener(k => {
|
|
909
|
+
if (k === key)
|
|
910
|
+
return () => callback(next[key], key);
|
|
911
|
+
if (typeof k !== "string")
|
|
912
|
+
return k;
|
|
913
|
+
});
|
|
914
|
+
},
|
|
915
|
+
set(key, value) {
|
|
916
|
+
if (key in next)
|
|
917
|
+
subject[key] = value;
|
|
918
|
+
else
|
|
919
|
+
control.watch(key, { value });
|
|
920
|
+
}
|
|
921
|
+
};
|
|
922
|
+
const subject = assign(create(next), methods);
|
|
923
|
+
const control = new Control(subject);
|
|
924
|
+
for (const key in control.state = next)
|
|
925
|
+
control.watch(key, {});
|
|
926
|
+
return subject;
|
|
962
927
|
}
|
|
963
928
|
|
|
964
929
|
const Oops = issues({
|
package/lib/index.js
CHANGED
|
@@ -46,25 +46,26 @@ function issues(register) {
|
|
|
46
46
|
|
|
47
47
|
const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
48
48
|
|
|
49
|
-
const Oops$
|
|
49
|
+
const Oops$8 = issues({
|
|
50
50
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
|
|
51
51
|
Destoryed: () => "Model is destroyed."
|
|
52
52
|
});
|
|
53
53
|
function suspense(source, key) {
|
|
54
|
-
const error = Oops$
|
|
54
|
+
const error = Oops$8.NotReady(source.subject, key);
|
|
55
|
+
const watch = source.observers.get(key);
|
|
55
56
|
const promise = new Promise((resolve, reject) => {
|
|
56
|
-
|
|
57
|
-
const onUpdate = (key) => {
|
|
57
|
+
function onUpdate(key) {
|
|
58
58
|
if (key)
|
|
59
59
|
return () => {
|
|
60
60
|
if (source.state[key] !== undefined) {
|
|
61
|
-
|
|
61
|
+
watch.delete(onUpdate);
|
|
62
62
|
resolve();
|
|
63
63
|
}
|
|
64
64
|
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
if (key === null)
|
|
66
|
+
reject(Oops$8.Destoryed());
|
|
67
|
+
}
|
|
68
|
+
watch.add(onUpdate);
|
|
68
69
|
});
|
|
69
70
|
return assign(promise, {
|
|
70
71
|
toString: () => String(error),
|
|
@@ -94,7 +95,7 @@ function mayRetry(fn) {
|
|
|
94
95
|
return compute();
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
const Oops$
|
|
98
|
+
const Oops$7 = issues({
|
|
98
99
|
BadCallback: () => `Callback for effect-callback may only return a function.`
|
|
99
100
|
});
|
|
100
101
|
function createEffect(source, callback) {
|
|
@@ -112,7 +113,7 @@ function createEffect(source, callback) {
|
|
|
112
113
|
if (unSet instanceof Promise)
|
|
113
114
|
unSet = undefined;
|
|
114
115
|
if (unSet && typeof unSet !== "function")
|
|
115
|
-
throw Oops$
|
|
116
|
+
throw Oops$7.BadCallback();
|
|
116
117
|
});
|
|
117
118
|
if (output instanceof Promise) {
|
|
118
119
|
output.finally(() => busy = false);
|
|
@@ -140,11 +141,11 @@ function createValueEffect(callback) {
|
|
|
140
141
|
if (typeof out == "function")
|
|
141
142
|
unSet = out;
|
|
142
143
|
else
|
|
143
|
-
throw Oops$
|
|
144
|
+
throw Oops$7.BadCallback();
|
|
144
145
|
};
|
|
145
146
|
}
|
|
146
147
|
|
|
147
|
-
const Oops$
|
|
148
|
+
const Oops$6 = issues({
|
|
148
149
|
KeysExpected: (key) => `Key "${key}" was expected in current update.`
|
|
149
150
|
});
|
|
150
151
|
function addEventListener(source, select, callback, once) {
|
|
@@ -179,7 +180,7 @@ function awaitUpdate(source, select, timeout) {
|
|
|
179
180
|
if (!self.frame.size)
|
|
180
181
|
resolve(false);
|
|
181
182
|
else if (typeof select == "string" && !self.frame.has(select))
|
|
182
|
-
reject(Oops$
|
|
183
|
+
reject(Oops$6.KeysExpected(select));
|
|
183
184
|
else {
|
|
184
185
|
const remove = self.addListener(() => {
|
|
185
186
|
remove();
|
|
@@ -198,22 +199,22 @@ function awaitUpdate(source, select, timeout) {
|
|
|
198
199
|
});
|
|
199
200
|
}
|
|
200
201
|
|
|
201
|
-
const Oops$
|
|
202
|
+
const Oops$5 = issues({
|
|
202
203
|
NotFound: (name) => `Could not find ${name} in context.`
|
|
203
204
|
});
|
|
204
|
-
function get$1(
|
|
205
|
+
function get$1(argument) {
|
|
205
206
|
return Control.get((dispatch, context) => {
|
|
206
207
|
const refresh = () => dispatch(x => x + 1);
|
|
207
208
|
let onUpdate;
|
|
208
209
|
let value;
|
|
209
|
-
if (typeof
|
|
210
|
+
if (typeof argument !== "function") {
|
|
210
211
|
const got = context.get(this);
|
|
211
212
|
if (got)
|
|
212
|
-
value =
|
|
213
|
+
value = argument === undefined
|
|
213
214
|
? Control.watch(got, k => k ? onUpdate : undefined)
|
|
214
215
|
: got;
|
|
215
|
-
else if (
|
|
216
|
-
throw Oops$
|
|
216
|
+
else if (argument !== false)
|
|
217
|
+
throw Oops$5.NotFound(this);
|
|
217
218
|
return {
|
|
218
219
|
mount() {
|
|
219
220
|
onUpdate = refresh;
|
|
@@ -222,14 +223,14 @@ function get$1(arg1, arg2) {
|
|
|
222
223
|
render: () => value
|
|
223
224
|
};
|
|
224
225
|
}
|
|
225
|
-
let compute =
|
|
226
|
+
let compute = argument;
|
|
226
227
|
let suspense;
|
|
227
228
|
let getValue;
|
|
228
229
|
let factory;
|
|
229
230
|
let proxy;
|
|
230
231
|
const found = context.get(this);
|
|
231
232
|
if (!found)
|
|
232
|
-
throw Oops$
|
|
233
|
+
throw Oops$5.NotFound(this);
|
|
233
234
|
function forceUpdate(action) {
|
|
234
235
|
if (typeof action == "function")
|
|
235
236
|
action = action();
|
|
@@ -272,7 +273,7 @@ function get$1(arg1, arg2) {
|
|
|
272
273
|
else
|
|
273
274
|
onUpdate = () => {
|
|
274
275
|
const next = getValue();
|
|
275
|
-
if (
|
|
276
|
+
if (value !== next)
|
|
276
277
|
didUpdate(next);
|
|
277
278
|
};
|
|
278
279
|
return {
|
|
@@ -282,30 +283,25 @@ function get$1(arg1, arg2) {
|
|
|
282
283
|
render: () => {
|
|
283
284
|
if (value !== undefined)
|
|
284
285
|
return value;
|
|
285
|
-
if (
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
286
|
+
if (onUpdate)
|
|
287
|
+
return null;
|
|
288
|
+
throw new Promise(res => {
|
|
289
|
+
suspense = res;
|
|
290
|
+
});
|
|
290
291
|
}
|
|
291
292
|
};
|
|
292
293
|
});
|
|
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])));
|
|
294
|
+
}
|
|
299
295
|
|
|
300
|
-
function use$1(
|
|
296
|
+
function use$1(apply, repeat) {
|
|
301
297
|
const render = Control.use(dispatch => {
|
|
302
298
|
const instance = this.new();
|
|
303
299
|
const local = Control.watch(instance, () => onUpdate);
|
|
304
300
|
const refresh = () => dispatch(x => x + 1);
|
|
305
301
|
let onUpdate;
|
|
306
|
-
let
|
|
302
|
+
let shouldApply = !!apply;
|
|
307
303
|
return {
|
|
308
|
-
|
|
304
|
+
instance,
|
|
309
305
|
mount() {
|
|
310
306
|
onUpdate = refresh;
|
|
311
307
|
return () => {
|
|
@@ -314,7 +310,7 @@ function use$1(arg1, arg2) {
|
|
|
314
310
|
};
|
|
315
311
|
},
|
|
316
312
|
render(props) {
|
|
317
|
-
if (
|
|
313
|
+
if (shouldApply) {
|
|
318
314
|
onUpdate = undefined;
|
|
319
315
|
if (typeof props == "function")
|
|
320
316
|
props(instance);
|
|
@@ -322,15 +318,15 @@ function use$1(arg1, arg2) {
|
|
|
322
318
|
for (const key in instance)
|
|
323
319
|
if (props.hasOwnProperty(key))
|
|
324
320
|
instance[key] = props[key];
|
|
325
|
-
if (!
|
|
326
|
-
|
|
321
|
+
if (!repeat)
|
|
322
|
+
shouldApply = false;
|
|
327
323
|
instance.on(0).then(() => onUpdate = refresh);
|
|
328
324
|
}
|
|
329
325
|
return local;
|
|
330
326
|
}
|
|
331
327
|
};
|
|
332
328
|
});
|
|
333
|
-
return render(
|
|
329
|
+
return render(apply);
|
|
334
330
|
}
|
|
335
331
|
|
|
336
332
|
class Model {
|
|
@@ -427,27 +423,30 @@ defineProperty(Model, "toString", {
|
|
|
427
423
|
}
|
|
428
424
|
});
|
|
429
425
|
|
|
430
|
-
const Oops$
|
|
426
|
+
const Oops$4 = issues({
|
|
431
427
|
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
432
428
|
});
|
|
433
|
-
const INSTRUCTION = new Map();
|
|
434
429
|
const REGISTER = new WeakMap();
|
|
435
430
|
const OBSERVER = new WeakMap();
|
|
431
|
+
const INSTRUCT = new Map();
|
|
432
|
+
const PENDING$1 = new WeakMap();
|
|
436
433
|
const PARENTS = new WeakMap();
|
|
437
434
|
class Control {
|
|
438
|
-
constructor(subject, id
|
|
439
|
-
this.
|
|
440
|
-
this.id = id;
|
|
435
|
+
constructor(subject, id) {
|
|
436
|
+
this.state = {};
|
|
441
437
|
this.frame = new Set();
|
|
442
438
|
this.followers = new Set();
|
|
443
439
|
this.observers = new Map([["", this.followers]]);
|
|
440
|
+
this.id = typeof id == "undefined" ? uid() : id;
|
|
441
|
+
this.subject = subject;
|
|
444
442
|
REGISTER.set(subject, this);
|
|
443
|
+
PENDING$1.set(this, new Set(Control.ready));
|
|
445
444
|
}
|
|
446
445
|
add(key) {
|
|
447
446
|
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
448
|
-
const instruction =
|
|
447
|
+
const instruction = INSTRUCT.get(value);
|
|
449
448
|
if (typeof instruction == "function") {
|
|
450
|
-
|
|
449
|
+
INSTRUCT.delete(value);
|
|
451
450
|
instruction(this, key);
|
|
452
451
|
}
|
|
453
452
|
else if (value instanceof Model)
|
|
@@ -533,31 +532,30 @@ class Control {
|
|
|
533
532
|
this.observers.clear();
|
|
534
533
|
}
|
|
535
534
|
}
|
|
535
|
+
Control.ready = new Set();
|
|
536
536
|
Control.after = new Set();
|
|
537
537
|
Control.before = new Set();
|
|
538
538
|
Control.pending = new Set();
|
|
539
539
|
Control.for = control;
|
|
540
540
|
Control.apply = apply;
|
|
541
541
|
Control.watch = watch;
|
|
542
|
-
const PENDING_INIT = new WeakMap();
|
|
543
542
|
function control(subject, ready) {
|
|
544
543
|
const control = REGISTER.get(subject.is);
|
|
545
|
-
const
|
|
546
|
-
if (
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
control.state = {};
|
|
544
|
+
const pending = PENDING$1.get(control);
|
|
545
|
+
if (typeof ready == "function") {
|
|
546
|
+
if (!pending)
|
|
547
|
+
return ready(control);
|
|
548
|
+
let done;
|
|
549
|
+
pending.add(() => done = ready(control));
|
|
550
|
+
return () => done && done();
|
|
551
|
+
}
|
|
552
|
+
if (pending && ready) {
|
|
553
|
+
PENDING$1.delete(control);
|
|
556
554
|
for (const key in control.subject)
|
|
557
555
|
control.add(key);
|
|
558
|
-
|
|
556
|
+
pending.forEach(cb => cb(control));
|
|
559
557
|
}
|
|
560
|
-
return
|
|
558
|
+
return control;
|
|
561
559
|
}
|
|
562
560
|
function requestUpdateFrame(event) {
|
|
563
561
|
const { after, before, pending } = Control;
|
|
@@ -585,15 +583,15 @@ function setRecursive(on, key, value) {
|
|
|
585
583
|
control(next, true);
|
|
586
584
|
return true;
|
|
587
585
|
}
|
|
588
|
-
throw Oops$
|
|
586
|
+
throw Oops$4.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
|
|
589
587
|
};
|
|
590
588
|
on.watch(key, { set });
|
|
591
589
|
set(value);
|
|
592
590
|
}
|
|
593
|
-
function parent(child,
|
|
594
|
-
if (!
|
|
591
|
+
function parent(child, assign) {
|
|
592
|
+
if (!assign)
|
|
595
593
|
return PARENTS.get(child);
|
|
596
|
-
PARENTS.set(child,
|
|
594
|
+
PARENTS.set(child, assign);
|
|
597
595
|
}
|
|
598
596
|
function watch(on, cb) {
|
|
599
597
|
if (!on.hasOwnProperty("is"))
|
|
@@ -603,7 +601,7 @@ function watch(on, cb) {
|
|
|
603
601
|
}
|
|
604
602
|
function apply(instruction) {
|
|
605
603
|
const placeholder = Symbol("instruction");
|
|
606
|
-
|
|
604
|
+
INSTRUCT.set(placeholder, (onto, key) => {
|
|
607
605
|
delete onto.subject[key];
|
|
608
606
|
const output = instruction.call(onto, key, onto);
|
|
609
607
|
if (output)
|
|
@@ -616,7 +614,7 @@ function uid() {
|
|
|
616
614
|
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
617
615
|
}
|
|
618
616
|
|
|
619
|
-
const Oops$
|
|
617
|
+
const Oops$3 = issues({
|
|
620
618
|
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
621
619
|
});
|
|
622
620
|
function run(task) {
|
|
@@ -624,7 +622,7 @@ function run(task) {
|
|
|
624
622
|
let pending = false;
|
|
625
623
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
626
624
|
if (pending)
|
|
627
|
-
return Promise.reject(Oops$
|
|
625
|
+
return Promise.reject(Oops$3.DuplicatePending(key));
|
|
628
626
|
pending = true;
|
|
629
627
|
control.update(key);
|
|
630
628
|
try {
|
|
@@ -646,7 +644,7 @@ function run(task) {
|
|
|
646
644
|
});
|
|
647
645
|
}
|
|
648
646
|
|
|
649
|
-
const Oops$
|
|
647
|
+
const Oops$2 = issues({
|
|
650
648
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
651
649
|
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} ${parent}.${property}.`,
|
|
652
650
|
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}.`,
|
|
@@ -657,7 +655,7 @@ function get(arg0, arg1) {
|
|
|
657
655
|
return apply((key, control) => {
|
|
658
656
|
let { subject } = control;
|
|
659
657
|
if (typeof arg0 == "symbol")
|
|
660
|
-
throw Oops$
|
|
658
|
+
throw Oops$2.PeerNotAllowed(subject, key);
|
|
661
659
|
let source = cb => cb(subject);
|
|
662
660
|
if (arg0 instanceof Model)
|
|
663
661
|
subject = arg0;
|
|
@@ -665,7 +663,7 @@ function get(arg0, arg1) {
|
|
|
665
663
|
const hasParent = parent(subject);
|
|
666
664
|
if (!hasParent) {
|
|
667
665
|
if (arg1 === true)
|
|
668
|
-
throw Oops$
|
|
666
|
+
throw Oops$2.Required(arg0, subject);
|
|
669
667
|
const fetch = Control.has(subject);
|
|
670
668
|
source = got => {
|
|
671
669
|
fetch(context => {
|
|
@@ -673,14 +671,14 @@ function get(arg0, arg1) {
|
|
|
673
671
|
if (model)
|
|
674
672
|
got(model);
|
|
675
673
|
else if (arg1 !== false)
|
|
676
|
-
throw Oops$
|
|
674
|
+
throw Oops$2.AmbientRequired(arg0, subject);
|
|
677
675
|
});
|
|
678
676
|
};
|
|
679
677
|
}
|
|
680
678
|
else if (!arg0 || hasParent instanceof arg0)
|
|
681
679
|
subject = hasParent;
|
|
682
680
|
else
|
|
683
|
-
throw Oops$
|
|
681
|
+
throw Oops$2.Unexpected(arg0, subject, hasParent);
|
|
684
682
|
}
|
|
685
683
|
else if (typeof arg0 == "function")
|
|
686
684
|
arg1 = arg0.call(subject, key, subject);
|
|
@@ -723,7 +721,7 @@ function computed(parent, key, source, setter) {
|
|
|
723
721
|
next = setter.call(proxy, proxy);
|
|
724
722
|
}
|
|
725
723
|
catch (err) {
|
|
726
|
-
Oops$
|
|
724
|
+
Oops$2.Failed(parent.subject, key, initial).warn();
|
|
727
725
|
if (initial)
|
|
728
726
|
throw err;
|
|
729
727
|
console.error(err);
|
|
@@ -811,7 +809,7 @@ function createRef(src, key, cb) {
|
|
|
811
809
|
return refObjectFunction;
|
|
812
810
|
}
|
|
813
811
|
|
|
814
|
-
const Oops$
|
|
812
|
+
const Oops$1 = issues({
|
|
815
813
|
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
816
814
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
817
815
|
});
|
|
@@ -819,150 +817,117 @@ function set(value, argument) {
|
|
|
819
817
|
return apply((key, control) => {
|
|
820
818
|
const { state, subject } = control;
|
|
821
819
|
if (typeof value == "function" || value instanceof Promise) {
|
|
822
|
-
const
|
|
823
|
-
let getter;
|
|
820
|
+
const output = {};
|
|
824
821
|
const init = () => {
|
|
825
822
|
try {
|
|
826
823
|
if (typeof value == "function")
|
|
827
824
|
value = mayRetry(value.bind(subject, key, subject));
|
|
828
|
-
let pending;
|
|
829
|
-
let error;
|
|
830
825
|
if (value instanceof Promise) {
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
.
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
826
|
+
const pending = value
|
|
827
|
+
.then(value => {
|
|
828
|
+
output.get = undefined;
|
|
829
|
+
state[key] = value;
|
|
830
|
+
return value;
|
|
831
|
+
})
|
|
832
|
+
.catch(err => {
|
|
833
|
+
output.get = () => { throw err; };
|
|
837
834
|
})
|
|
838
835
|
.finally(() => {
|
|
839
|
-
pending = undefined;
|
|
840
836
|
control.update(key);
|
|
841
837
|
});
|
|
838
|
+
if (argument !== false)
|
|
839
|
+
return () => {
|
|
840
|
+
const { message, stack } = Oops$1.NotReady(subject, key);
|
|
841
|
+
throw assign(pending, { message, stack });
|
|
842
|
+
};
|
|
842
843
|
}
|
|
843
844
|
else
|
|
844
845
|
state[key] = value;
|
|
845
|
-
const suspend = () => {
|
|
846
|
-
if (required === false)
|
|
847
|
-
return undefined;
|
|
848
|
-
const issue = Oops$2.NotReady(subject, key);
|
|
849
|
-
assign(pending, {
|
|
850
|
-
message: issue.message,
|
|
851
|
-
stack: issue.stack
|
|
852
|
-
});
|
|
853
|
-
throw pending;
|
|
854
|
-
};
|
|
855
|
-
getter = () => {
|
|
856
|
-
if (error)
|
|
857
|
-
throw error;
|
|
858
|
-
if (pending)
|
|
859
|
-
return suspend();
|
|
860
|
-
return state[key];
|
|
861
|
-
};
|
|
862
846
|
}
|
|
863
847
|
catch (err) {
|
|
864
|
-
Oops$
|
|
848
|
+
Oops$1.ComputeFailed(subject, key).warn();
|
|
865
849
|
throw err;
|
|
866
850
|
}
|
|
867
851
|
};
|
|
868
|
-
if (argument
|
|
852
|
+
if (argument)
|
|
869
853
|
init();
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
854
|
+
else
|
|
855
|
+
output.get = () => {
|
|
856
|
+
const get = output.get =
|
|
857
|
+
key in state ? undefined : init();
|
|
858
|
+
return get ? get() : state[key];
|
|
859
|
+
};
|
|
860
|
+
return output;
|
|
875
861
|
}
|
|
876
|
-
|
|
862
|
+
const set = typeof argument == "function"
|
|
877
863
|
? createValueEffect(argument)
|
|
878
864
|
: undefined;
|
|
879
|
-
if (value !== undefined)
|
|
865
|
+
if (value !== undefined) {
|
|
880
866
|
state[key] = value;
|
|
881
|
-
|
|
882
|
-
const effect = setter;
|
|
883
|
-
setter = function (value) {
|
|
884
|
-
if (!(key in state))
|
|
885
|
-
state[key] = undefined;
|
|
886
|
-
return effect.call(this, value);
|
|
887
|
-
};
|
|
867
|
+
return { set };
|
|
888
868
|
}
|
|
889
|
-
|
|
890
|
-
get
|
|
869
|
+
const output = {
|
|
870
|
+
get() {
|
|
891
871
|
if (key in state)
|
|
892
872
|
return state[key];
|
|
893
873
|
throw suspense(control, key);
|
|
894
|
-
}
|
|
895
|
-
set: setter
|
|
874
|
+
}
|
|
896
875
|
};
|
|
876
|
+
if (set)
|
|
877
|
+
output.set = function (value) {
|
|
878
|
+
output.set = set;
|
|
879
|
+
state[key] = state[key];
|
|
880
|
+
return set.call(this, value);
|
|
881
|
+
};
|
|
882
|
+
return output;
|
|
897
883
|
});
|
|
898
884
|
}
|
|
899
885
|
|
|
900
|
-
const Oops$1 = issues({
|
|
901
|
-
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
902
|
-
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
903
|
-
});
|
|
904
886
|
function use(input, argument) {
|
|
905
887
|
return apply((key, source) => {
|
|
906
888
|
const { state, subject } = source;
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
if ("prototype" in input && input === input.prototype.constructor)
|
|
910
|
-
input = new input();
|
|
911
|
-
}
|
|
912
|
-
else if (input && typeof input !== "object")
|
|
913
|
-
throw Oops$1.BadArgument(typeof input);
|
|
914
|
-
function init() {
|
|
915
|
-
const result = typeof input == "function" ?
|
|
916
|
-
mayRetry(() => input.call(subject, subject)) :
|
|
917
|
-
input;
|
|
918
|
-
if (result instanceof Promise) {
|
|
919
|
-
const pending = result
|
|
920
|
-
.then(value => {
|
|
921
|
-
output.get = undefined;
|
|
922
|
-
set(value);
|
|
923
|
-
return value;
|
|
924
|
-
})
|
|
925
|
-
.catch(err => {
|
|
926
|
-
output.get = () => { throw err; };
|
|
927
|
-
})
|
|
928
|
-
.finally(() => {
|
|
929
|
-
source.update(key);
|
|
930
|
-
});
|
|
931
|
-
if (required !== false)
|
|
932
|
-
output.get = () => {
|
|
933
|
-
throw assign(pending, Oops$1.NotReady(subject, key));
|
|
934
|
-
};
|
|
935
|
-
}
|
|
936
|
-
else
|
|
937
|
-
set(result);
|
|
938
|
-
}
|
|
889
|
+
if (typeof input === "function")
|
|
890
|
+
input = new input();
|
|
939
891
|
function set(next) {
|
|
940
892
|
if (next instanceof Model) {
|
|
941
893
|
parent(next, subject);
|
|
942
894
|
control(next, true);
|
|
943
895
|
}
|
|
944
|
-
else if (next)
|
|
945
|
-
|
|
946
|
-
control.state = next;
|
|
947
|
-
for (const key in next)
|
|
948
|
-
control.watch(key, {});
|
|
949
|
-
next = control.subject;
|
|
950
|
-
}
|
|
896
|
+
else if (next)
|
|
897
|
+
next = manage(next);
|
|
951
898
|
state[key] = next;
|
|
952
899
|
if (typeof argument == "function")
|
|
953
900
|
argument(next);
|
|
954
901
|
return true;
|
|
955
902
|
}
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
init();
|
|
959
|
-
else
|
|
960
|
-
output.get = () => {
|
|
961
|
-
init();
|
|
962
|
-
return state[key];
|
|
963
|
-
};
|
|
964
|
-
return output;
|
|
903
|
+
set(input);
|
|
904
|
+
return { set };
|
|
965
905
|
});
|
|
906
|
+
}
|
|
907
|
+
function manage(next) {
|
|
908
|
+
const methods = {
|
|
909
|
+
on(key, callback) {
|
|
910
|
+
if (!(key in next))
|
|
911
|
+
control.watch(key, { value: subject[key] });
|
|
912
|
+
return control.addListener(k => {
|
|
913
|
+
if (k === key)
|
|
914
|
+
return () => callback(next[key], key);
|
|
915
|
+
if (typeof k !== "string")
|
|
916
|
+
return k;
|
|
917
|
+
});
|
|
918
|
+
},
|
|
919
|
+
set(key, value) {
|
|
920
|
+
if (key in next)
|
|
921
|
+
subject[key] = value;
|
|
922
|
+
else
|
|
923
|
+
control.watch(key, { value });
|
|
924
|
+
}
|
|
925
|
+
};
|
|
926
|
+
const subject = assign(create(next), methods);
|
|
927
|
+
const control = new Control(subject);
|
|
928
|
+
for (const key in control.state = next)
|
|
929
|
+
control.watch(key, {});
|
|
930
|
+
return subject;
|
|
966
931
|
}
|
|
967
932
|
|
|
968
933
|
const Oops = issues({
|
package/package.json
CHANGED