@expressive/mvc 0.25.0 → 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 +38 -17
- package/lib/index.esm.js +100 -132
- package/lib/index.js +100 -132
- package/package.json +2 -2
package/lib/index.d.ts
CHANGED
|
@@ -104,7 +104,7 @@ declare class Control<T extends {} = any> {
|
|
|
104
104
|
observers: Map<string, Set<Observer<any>>>;
|
|
105
105
|
constructor(subject: T, id?: string | number);
|
|
106
106
|
add(key: Extract<keyof T, string>): void;
|
|
107
|
-
watch(key: keyof T
|
|
107
|
+
watch(key: Extract<keyof T, string>, output: Control.PropertyDescriptor<any>): void;
|
|
108
108
|
ref<K extends Model.Key<T>>(key: K, callback?: (this: T, value: T[K]) => boolean | void): (value: any) => void;
|
|
109
109
|
update(key: string): void;
|
|
110
110
|
addListener(fn: Observer): () => boolean;
|
|
@@ -374,25 +374,46 @@ declare function set<T>(factory: set.Factory<T> | Promise<T>, required?: boolean
|
|
|
374
374
|
declare function set<T>(value: undefined, onUpdate: set.Callback<T>): T;
|
|
375
375
|
declare function set<T>(value: T, onUpdate: set.Callback<T>): T;
|
|
376
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
|
+
}
|
|
377
401
|
/** Create a placeholder for specified Model type. */
|
|
378
402
|
declare function use<T extends Model>(): T | undefined;
|
|
379
403
|
/** Create a new child instance of model. */
|
|
380
|
-
declare function use<T extends Model>(Type: Model.New<T>,
|
|
381
|
-
/** Assign the result of a factory as a child model. */
|
|
382
|
-
declare function use<T extends {}>(from: () => Promise<T> | T, required?: true): T;
|
|
383
|
-
/** Assign the result of a factory as a child model. */
|
|
384
|
-
declare function use<T extends {}>(from: () => Promise<T> | T, required: boolean): T | undefined;
|
|
385
|
-
/** Create a managed child from factory function. */
|
|
386
|
-
declare function use<T extends {}>(from: () => Promise<T> | T, callback?: (i: T) => void): T;
|
|
387
|
-
declare function use<T extends {}>(data: T): T;
|
|
404
|
+
declare function use<T extends Model>(Type: Model.New<T>, ready?: (i: T) => void): T;
|
|
388
405
|
/**
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
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;
|
|
397
418
|
|
|
398
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,7 +195,7 @@ 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
201
|
function get$1(argument) {
|
|
@@ -209,7 +210,7 @@ function get$1(argument) {
|
|
|
209
210
|
? Control.watch(got, k => k ? onUpdate : undefined)
|
|
210
211
|
: got;
|
|
211
212
|
else if (argument !== false)
|
|
212
|
-
throw Oops$
|
|
213
|
+
throw Oops$5.NotFound(this);
|
|
213
214
|
return {
|
|
214
215
|
mount() {
|
|
215
216
|
onUpdate = refresh;
|
|
@@ -225,7 +226,7 @@ function get$1(argument) {
|
|
|
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();
|
|
@@ -418,13 +419,13 @@ defineProperty(Model, "toString", {
|
|
|
418
419
|
}
|
|
419
420
|
});
|
|
420
421
|
|
|
421
|
-
const Oops$
|
|
422
|
+
const Oops$4 = issues({
|
|
422
423
|
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
423
424
|
});
|
|
424
|
-
const INSTRUCTION = new Map();
|
|
425
|
-
const PENDING$1 = new WeakMap();
|
|
426
425
|
const REGISTER = new WeakMap();
|
|
427
426
|
const OBSERVER = new WeakMap();
|
|
427
|
+
const INSTRUCT = new Map();
|
|
428
|
+
const PENDING$1 = new WeakMap();
|
|
428
429
|
const PARENTS = new WeakMap();
|
|
429
430
|
class Control {
|
|
430
431
|
constructor(subject, id) {
|
|
@@ -439,9 +440,9 @@ class Control {
|
|
|
439
440
|
}
|
|
440
441
|
add(key) {
|
|
441
442
|
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
442
|
-
const instruction =
|
|
443
|
+
const instruction = INSTRUCT.get(value);
|
|
443
444
|
if (typeof instruction == "function") {
|
|
444
|
-
|
|
445
|
+
INSTRUCT.delete(value);
|
|
445
446
|
instruction(this, key);
|
|
446
447
|
}
|
|
447
448
|
else if (value instanceof Model)
|
|
@@ -578,7 +579,7 @@ function setRecursive(on, key, value) {
|
|
|
578
579
|
control(next, true);
|
|
579
580
|
return true;
|
|
580
581
|
}
|
|
581
|
-
throw Oops$
|
|
582
|
+
throw Oops$4.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
|
|
582
583
|
};
|
|
583
584
|
on.watch(key, { set });
|
|
584
585
|
set(value);
|
|
@@ -596,7 +597,7 @@ function watch(on, cb) {
|
|
|
596
597
|
}
|
|
597
598
|
function apply(instruction) {
|
|
598
599
|
const placeholder = Symbol("instruction");
|
|
599
|
-
|
|
600
|
+
INSTRUCT.set(placeholder, (onto, key) => {
|
|
600
601
|
delete onto.subject[key];
|
|
601
602
|
const output = instruction.call(onto, key, onto);
|
|
602
603
|
if (output)
|
|
@@ -609,7 +610,7 @@ function uid() {
|
|
|
609
610
|
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
610
611
|
}
|
|
611
612
|
|
|
612
|
-
const Oops$
|
|
613
|
+
const Oops$3 = issues({
|
|
613
614
|
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
614
615
|
});
|
|
615
616
|
function run(task) {
|
|
@@ -617,7 +618,7 @@ function run(task) {
|
|
|
617
618
|
let pending = false;
|
|
618
619
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
619
620
|
if (pending)
|
|
620
|
-
return Promise.reject(Oops$
|
|
621
|
+
return Promise.reject(Oops$3.DuplicatePending(key));
|
|
621
622
|
pending = true;
|
|
622
623
|
control.update(key);
|
|
623
624
|
try {
|
|
@@ -639,7 +640,7 @@ function run(task) {
|
|
|
639
640
|
});
|
|
640
641
|
}
|
|
641
642
|
|
|
642
|
-
const Oops$
|
|
643
|
+
const Oops$2 = issues({
|
|
643
644
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
644
645
|
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} ${parent}.${property}.`,
|
|
645
646
|
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}.`,
|
|
@@ -650,7 +651,7 @@ function get(arg0, arg1) {
|
|
|
650
651
|
return apply((key, control) => {
|
|
651
652
|
let { subject } = control;
|
|
652
653
|
if (typeof arg0 == "symbol")
|
|
653
|
-
throw Oops$
|
|
654
|
+
throw Oops$2.PeerNotAllowed(subject, key);
|
|
654
655
|
let source = cb => cb(subject);
|
|
655
656
|
if (arg0 instanceof Model)
|
|
656
657
|
subject = arg0;
|
|
@@ -658,7 +659,7 @@ function get(arg0, arg1) {
|
|
|
658
659
|
const hasParent = parent(subject);
|
|
659
660
|
if (!hasParent) {
|
|
660
661
|
if (arg1 === true)
|
|
661
|
-
throw Oops$
|
|
662
|
+
throw Oops$2.Required(arg0, subject);
|
|
662
663
|
const fetch = Control.has(subject);
|
|
663
664
|
source = got => {
|
|
664
665
|
fetch(context => {
|
|
@@ -666,14 +667,14 @@ function get(arg0, arg1) {
|
|
|
666
667
|
if (model)
|
|
667
668
|
got(model);
|
|
668
669
|
else if (arg1 !== false)
|
|
669
|
-
throw Oops$
|
|
670
|
+
throw Oops$2.AmbientRequired(arg0, subject);
|
|
670
671
|
});
|
|
671
672
|
};
|
|
672
673
|
}
|
|
673
674
|
else if (!arg0 || hasParent instanceof arg0)
|
|
674
675
|
subject = hasParent;
|
|
675
676
|
else
|
|
676
|
-
throw Oops$
|
|
677
|
+
throw Oops$2.Unexpected(arg0, subject, hasParent);
|
|
677
678
|
}
|
|
678
679
|
else if (typeof arg0 == "function")
|
|
679
680
|
arg1 = arg0.call(subject, key, subject);
|
|
@@ -716,7 +717,7 @@ function computed(parent, key, source, setter) {
|
|
|
716
717
|
next = setter.call(proxy, proxy);
|
|
717
718
|
}
|
|
718
719
|
catch (err) {
|
|
719
|
-
Oops$
|
|
720
|
+
Oops$2.Failed(parent.subject, key, initial).warn();
|
|
720
721
|
if (initial)
|
|
721
722
|
throw err;
|
|
722
723
|
console.error(err);
|
|
@@ -804,7 +805,7 @@ function createRef(src, key, cb) {
|
|
|
804
805
|
return refObjectFunction;
|
|
805
806
|
}
|
|
806
807
|
|
|
807
|
-
const Oops$
|
|
808
|
+
const Oops$1 = issues({
|
|
808
809
|
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
809
810
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
810
811
|
});
|
|
@@ -812,150 +813,117 @@ function set(value, argument) {
|
|
|
812
813
|
return apply((key, control) => {
|
|
813
814
|
const { state, subject } = control;
|
|
814
815
|
if (typeof value == "function" || value instanceof Promise) {
|
|
815
|
-
const
|
|
816
|
-
let getter;
|
|
816
|
+
const output = {};
|
|
817
817
|
const init = () => {
|
|
818
818
|
try {
|
|
819
819
|
if (typeof value == "function")
|
|
820
820
|
value = mayRetry(value.bind(subject, key, subject));
|
|
821
|
-
let pending;
|
|
822
|
-
let error;
|
|
823
821
|
if (value instanceof Promise) {
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
.
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
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; };
|
|
830
830
|
})
|
|
831
831
|
.finally(() => {
|
|
832
|
-
pending = undefined;
|
|
833
832
|
control.update(key);
|
|
834
833
|
});
|
|
834
|
+
if (argument !== false)
|
|
835
|
+
return () => {
|
|
836
|
+
const { message, stack } = Oops$1.NotReady(subject, key);
|
|
837
|
+
throw assign(pending, { message, stack });
|
|
838
|
+
};
|
|
835
839
|
}
|
|
836
840
|
else
|
|
837
841
|
state[key] = value;
|
|
838
|
-
const suspend = () => {
|
|
839
|
-
if (required === false)
|
|
840
|
-
return undefined;
|
|
841
|
-
const issue = Oops$2.NotReady(subject, key);
|
|
842
|
-
assign(pending, {
|
|
843
|
-
message: issue.message,
|
|
844
|
-
stack: issue.stack
|
|
845
|
-
});
|
|
846
|
-
throw pending;
|
|
847
|
-
};
|
|
848
|
-
getter = () => {
|
|
849
|
-
if (error)
|
|
850
|
-
throw error;
|
|
851
|
-
if (pending)
|
|
852
|
-
return suspend();
|
|
853
|
-
return state[key];
|
|
854
|
-
};
|
|
855
842
|
}
|
|
856
843
|
catch (err) {
|
|
857
|
-
Oops$
|
|
844
|
+
Oops$1.ComputeFailed(subject, key).warn();
|
|
858
845
|
throw err;
|
|
859
846
|
}
|
|
860
847
|
};
|
|
861
|
-
if (argument
|
|
848
|
+
if (argument)
|
|
862
849
|
init();
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
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;
|
|
868
857
|
}
|
|
869
|
-
|
|
858
|
+
const set = typeof argument == "function"
|
|
870
859
|
? createValueEffect(argument)
|
|
871
860
|
: undefined;
|
|
872
|
-
if (value !== undefined)
|
|
861
|
+
if (value !== undefined) {
|
|
873
862
|
state[key] = value;
|
|
874
|
-
|
|
875
|
-
const effect = setter;
|
|
876
|
-
setter = function (value) {
|
|
877
|
-
if (!(key in state))
|
|
878
|
-
state[key] = undefined;
|
|
879
|
-
return effect.call(this, value);
|
|
880
|
-
};
|
|
863
|
+
return { set };
|
|
881
864
|
}
|
|
882
|
-
|
|
883
|
-
get
|
|
865
|
+
const output = {
|
|
866
|
+
get() {
|
|
884
867
|
if (key in state)
|
|
885
868
|
return state[key];
|
|
886
869
|
throw suspense(control, key);
|
|
887
|
-
}
|
|
888
|
-
set: setter
|
|
870
|
+
}
|
|
889
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;
|
|
890
879
|
});
|
|
891
880
|
}
|
|
892
881
|
|
|
893
|
-
const Oops$1 = issues({
|
|
894
|
-
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
895
|
-
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
896
|
-
});
|
|
897
882
|
function use(input, argument) {
|
|
898
883
|
return apply((key, source) => {
|
|
899
884
|
const { state, subject } = source;
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
if ("prototype" in input && input === input.prototype.constructor)
|
|
903
|
-
input = new input();
|
|
904
|
-
}
|
|
905
|
-
else if (input && typeof input !== "object")
|
|
906
|
-
throw Oops$1.BadArgument(typeof input);
|
|
907
|
-
function init() {
|
|
908
|
-
const result = typeof input == "function" ?
|
|
909
|
-
mayRetry(() => input.call(subject, subject)) :
|
|
910
|
-
input;
|
|
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; };
|
|
920
|
-
})
|
|
921
|
-
.finally(() => {
|
|
922
|
-
source.update(key);
|
|
923
|
-
});
|
|
924
|
-
if (required !== false)
|
|
925
|
-
output.get = () => {
|
|
926
|
-
throw assign(pending, Oops$1.NotReady(subject, key));
|
|
927
|
-
};
|
|
928
|
-
}
|
|
929
|
-
else
|
|
930
|
-
set(result);
|
|
931
|
-
}
|
|
885
|
+
if (typeof input === "function")
|
|
886
|
+
input = new input();
|
|
932
887
|
function set(next) {
|
|
933
888
|
if (next instanceof Model) {
|
|
934
889
|
parent(next, subject);
|
|
935
890
|
control(next, true);
|
|
936
891
|
}
|
|
937
|
-
else if (next)
|
|
938
|
-
|
|
939
|
-
control.state = next;
|
|
940
|
-
for (const key in next)
|
|
941
|
-
control.watch(key, {});
|
|
942
|
-
next = control.subject;
|
|
943
|
-
}
|
|
892
|
+
else if (next)
|
|
893
|
+
next = manage(next);
|
|
944
894
|
state[key] = next;
|
|
945
895
|
if (typeof argument == "function")
|
|
946
896
|
argument(next);
|
|
947
897
|
return true;
|
|
948
898
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
init();
|
|
952
|
-
else
|
|
953
|
-
output.get = () => {
|
|
954
|
-
init();
|
|
955
|
-
return state[key];
|
|
956
|
-
};
|
|
957
|
-
return output;
|
|
899
|
+
set(input);
|
|
900
|
+
return { set };
|
|
958
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;
|
|
959
927
|
}
|
|
960
928
|
|
|
961
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,7 +199,7 @@ 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
205
|
function get$1(argument) {
|
|
@@ -213,7 +214,7 @@ function get$1(argument) {
|
|
|
213
214
|
? Control.watch(got, k => k ? onUpdate : undefined)
|
|
214
215
|
: got;
|
|
215
216
|
else if (argument !== false)
|
|
216
|
-
throw Oops$
|
|
217
|
+
throw Oops$5.NotFound(this);
|
|
217
218
|
return {
|
|
218
219
|
mount() {
|
|
219
220
|
onUpdate = refresh;
|
|
@@ -229,7 +230,7 @@ function get$1(argument) {
|
|
|
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();
|
|
@@ -422,13 +423,13 @@ defineProperty(Model, "toString", {
|
|
|
422
423
|
}
|
|
423
424
|
});
|
|
424
425
|
|
|
425
|
-
const Oops$
|
|
426
|
+
const Oops$4 = issues({
|
|
426
427
|
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
427
428
|
});
|
|
428
|
-
const INSTRUCTION = new Map();
|
|
429
|
-
const PENDING$1 = new WeakMap();
|
|
430
429
|
const REGISTER = new WeakMap();
|
|
431
430
|
const OBSERVER = new WeakMap();
|
|
431
|
+
const INSTRUCT = new Map();
|
|
432
|
+
const PENDING$1 = new WeakMap();
|
|
432
433
|
const PARENTS = new WeakMap();
|
|
433
434
|
class Control {
|
|
434
435
|
constructor(subject, id) {
|
|
@@ -443,9 +444,9 @@ class Control {
|
|
|
443
444
|
}
|
|
444
445
|
add(key) {
|
|
445
446
|
const { value } = getOwnPropertyDescriptor(this.subject, key);
|
|
446
|
-
const instruction =
|
|
447
|
+
const instruction = INSTRUCT.get(value);
|
|
447
448
|
if (typeof instruction == "function") {
|
|
448
|
-
|
|
449
|
+
INSTRUCT.delete(value);
|
|
449
450
|
instruction(this, key);
|
|
450
451
|
}
|
|
451
452
|
else if (value instanceof Model)
|
|
@@ -582,7 +583,7 @@ function setRecursive(on, key, value) {
|
|
|
582
583
|
control(next, true);
|
|
583
584
|
return true;
|
|
584
585
|
}
|
|
585
|
-
throw Oops$
|
|
586
|
+
throw Oops$4.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
|
|
586
587
|
};
|
|
587
588
|
on.watch(key, { set });
|
|
588
589
|
set(value);
|
|
@@ -600,7 +601,7 @@ function watch(on, cb) {
|
|
|
600
601
|
}
|
|
601
602
|
function apply(instruction) {
|
|
602
603
|
const placeholder = Symbol("instruction");
|
|
603
|
-
|
|
604
|
+
INSTRUCT.set(placeholder, (onto, key) => {
|
|
604
605
|
delete onto.subject[key];
|
|
605
606
|
const output = instruction.call(onto, key, onto);
|
|
606
607
|
if (output)
|
|
@@ -613,7 +614,7 @@ function uid() {
|
|
|
613
614
|
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
614
615
|
}
|
|
615
616
|
|
|
616
|
-
const Oops$
|
|
617
|
+
const Oops$3 = issues({
|
|
617
618
|
DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
|
|
618
619
|
});
|
|
619
620
|
function run(task) {
|
|
@@ -621,7 +622,7 @@ function run(task) {
|
|
|
621
622
|
let pending = false;
|
|
622
623
|
const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
|
|
623
624
|
if (pending)
|
|
624
|
-
return Promise.reject(Oops$
|
|
625
|
+
return Promise.reject(Oops$3.DuplicatePending(key));
|
|
625
626
|
pending = true;
|
|
626
627
|
control.update(key);
|
|
627
628
|
try {
|
|
@@ -643,7 +644,7 @@ function run(task) {
|
|
|
643
644
|
});
|
|
644
645
|
}
|
|
645
646
|
|
|
646
|
-
const Oops$
|
|
647
|
+
const Oops$2 = issues({
|
|
647
648
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
648
649
|
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} ${parent}.${property}.`,
|
|
649
650
|
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}.`,
|
|
@@ -654,7 +655,7 @@ function get(arg0, arg1) {
|
|
|
654
655
|
return apply((key, control) => {
|
|
655
656
|
let { subject } = control;
|
|
656
657
|
if (typeof arg0 == "symbol")
|
|
657
|
-
throw Oops$
|
|
658
|
+
throw Oops$2.PeerNotAllowed(subject, key);
|
|
658
659
|
let source = cb => cb(subject);
|
|
659
660
|
if (arg0 instanceof Model)
|
|
660
661
|
subject = arg0;
|
|
@@ -662,7 +663,7 @@ function get(arg0, arg1) {
|
|
|
662
663
|
const hasParent = parent(subject);
|
|
663
664
|
if (!hasParent) {
|
|
664
665
|
if (arg1 === true)
|
|
665
|
-
throw Oops$
|
|
666
|
+
throw Oops$2.Required(arg0, subject);
|
|
666
667
|
const fetch = Control.has(subject);
|
|
667
668
|
source = got => {
|
|
668
669
|
fetch(context => {
|
|
@@ -670,14 +671,14 @@ function get(arg0, arg1) {
|
|
|
670
671
|
if (model)
|
|
671
672
|
got(model);
|
|
672
673
|
else if (arg1 !== false)
|
|
673
|
-
throw Oops$
|
|
674
|
+
throw Oops$2.AmbientRequired(arg0, subject);
|
|
674
675
|
});
|
|
675
676
|
};
|
|
676
677
|
}
|
|
677
678
|
else if (!arg0 || hasParent instanceof arg0)
|
|
678
679
|
subject = hasParent;
|
|
679
680
|
else
|
|
680
|
-
throw Oops$
|
|
681
|
+
throw Oops$2.Unexpected(arg0, subject, hasParent);
|
|
681
682
|
}
|
|
682
683
|
else if (typeof arg0 == "function")
|
|
683
684
|
arg1 = arg0.call(subject, key, subject);
|
|
@@ -720,7 +721,7 @@ function computed(parent, key, source, setter) {
|
|
|
720
721
|
next = setter.call(proxy, proxy);
|
|
721
722
|
}
|
|
722
723
|
catch (err) {
|
|
723
|
-
Oops$
|
|
724
|
+
Oops$2.Failed(parent.subject, key, initial).warn();
|
|
724
725
|
if (initial)
|
|
725
726
|
throw err;
|
|
726
727
|
console.error(err);
|
|
@@ -808,7 +809,7 @@ function createRef(src, key, cb) {
|
|
|
808
809
|
return refObjectFunction;
|
|
809
810
|
}
|
|
810
811
|
|
|
811
|
-
const Oops$
|
|
812
|
+
const Oops$1 = issues({
|
|
812
813
|
ComputeFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`,
|
|
813
814
|
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
814
815
|
});
|
|
@@ -816,150 +817,117 @@ function set(value, argument) {
|
|
|
816
817
|
return apply((key, control) => {
|
|
817
818
|
const { state, subject } = control;
|
|
818
819
|
if (typeof value == "function" || value instanceof Promise) {
|
|
819
|
-
const
|
|
820
|
-
let getter;
|
|
820
|
+
const output = {};
|
|
821
821
|
const init = () => {
|
|
822
822
|
try {
|
|
823
823
|
if (typeof value == "function")
|
|
824
824
|
value = mayRetry(value.bind(subject, key, subject));
|
|
825
|
-
let pending;
|
|
826
|
-
let error;
|
|
827
825
|
if (value instanceof Promise) {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
.
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
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; };
|
|
834
834
|
})
|
|
835
835
|
.finally(() => {
|
|
836
|
-
pending = undefined;
|
|
837
836
|
control.update(key);
|
|
838
837
|
});
|
|
838
|
+
if (argument !== false)
|
|
839
|
+
return () => {
|
|
840
|
+
const { message, stack } = Oops$1.NotReady(subject, key);
|
|
841
|
+
throw assign(pending, { message, stack });
|
|
842
|
+
};
|
|
839
843
|
}
|
|
840
844
|
else
|
|
841
845
|
state[key] = value;
|
|
842
|
-
const suspend = () => {
|
|
843
|
-
if (required === false)
|
|
844
|
-
return undefined;
|
|
845
|
-
const issue = Oops$2.NotReady(subject, key);
|
|
846
|
-
assign(pending, {
|
|
847
|
-
message: issue.message,
|
|
848
|
-
stack: issue.stack
|
|
849
|
-
});
|
|
850
|
-
throw pending;
|
|
851
|
-
};
|
|
852
|
-
getter = () => {
|
|
853
|
-
if (error)
|
|
854
|
-
throw error;
|
|
855
|
-
if (pending)
|
|
856
|
-
return suspend();
|
|
857
|
-
return state[key];
|
|
858
|
-
};
|
|
859
846
|
}
|
|
860
847
|
catch (err) {
|
|
861
|
-
Oops$
|
|
848
|
+
Oops$1.ComputeFailed(subject, key).warn();
|
|
862
849
|
throw err;
|
|
863
850
|
}
|
|
864
851
|
};
|
|
865
|
-
if (argument
|
|
852
|
+
if (argument)
|
|
866
853
|
init();
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
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;
|
|
872
861
|
}
|
|
873
|
-
|
|
862
|
+
const set = typeof argument == "function"
|
|
874
863
|
? createValueEffect(argument)
|
|
875
864
|
: undefined;
|
|
876
|
-
if (value !== undefined)
|
|
865
|
+
if (value !== undefined) {
|
|
877
866
|
state[key] = value;
|
|
878
|
-
|
|
879
|
-
const effect = setter;
|
|
880
|
-
setter = function (value) {
|
|
881
|
-
if (!(key in state))
|
|
882
|
-
state[key] = undefined;
|
|
883
|
-
return effect.call(this, value);
|
|
884
|
-
};
|
|
867
|
+
return { set };
|
|
885
868
|
}
|
|
886
|
-
|
|
887
|
-
get
|
|
869
|
+
const output = {
|
|
870
|
+
get() {
|
|
888
871
|
if (key in state)
|
|
889
872
|
return state[key];
|
|
890
873
|
throw suspense(control, key);
|
|
891
|
-
}
|
|
892
|
-
set: setter
|
|
874
|
+
}
|
|
893
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;
|
|
894
883
|
});
|
|
895
884
|
}
|
|
896
885
|
|
|
897
|
-
const Oops$1 = issues({
|
|
898
|
-
BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
|
|
899
|
-
NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
|
|
900
|
-
});
|
|
901
886
|
function use(input, argument) {
|
|
902
887
|
return apply((key, source) => {
|
|
903
888
|
const { state, subject } = source;
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
if ("prototype" in input && input === input.prototype.constructor)
|
|
907
|
-
input = new input();
|
|
908
|
-
}
|
|
909
|
-
else if (input && typeof input !== "object")
|
|
910
|
-
throw Oops$1.BadArgument(typeof input);
|
|
911
|
-
function init() {
|
|
912
|
-
const result = typeof input == "function" ?
|
|
913
|
-
mayRetry(() => input.call(subject, subject)) :
|
|
914
|
-
input;
|
|
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; };
|
|
924
|
-
})
|
|
925
|
-
.finally(() => {
|
|
926
|
-
source.update(key);
|
|
927
|
-
});
|
|
928
|
-
if (required !== false)
|
|
929
|
-
output.get = () => {
|
|
930
|
-
throw assign(pending, Oops$1.NotReady(subject, key));
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
else
|
|
934
|
-
set(result);
|
|
935
|
-
}
|
|
889
|
+
if (typeof input === "function")
|
|
890
|
+
input = new input();
|
|
936
891
|
function set(next) {
|
|
937
892
|
if (next instanceof Model) {
|
|
938
893
|
parent(next, subject);
|
|
939
894
|
control(next, true);
|
|
940
895
|
}
|
|
941
|
-
else if (next)
|
|
942
|
-
|
|
943
|
-
control.state = next;
|
|
944
|
-
for (const key in next)
|
|
945
|
-
control.watch(key, {});
|
|
946
|
-
next = control.subject;
|
|
947
|
-
}
|
|
896
|
+
else if (next)
|
|
897
|
+
next = manage(next);
|
|
948
898
|
state[key] = next;
|
|
949
899
|
if (typeof argument == "function")
|
|
950
900
|
argument(next);
|
|
951
901
|
return true;
|
|
952
902
|
}
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
init();
|
|
956
|
-
else
|
|
957
|
-
output.get = () => {
|
|
958
|
-
init();
|
|
959
|
-
return state[key];
|
|
960
|
-
};
|
|
961
|
-
return output;
|
|
903
|
+
set(input);
|
|
904
|
+
return { set };
|
|
962
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;
|
|
963
931
|
}
|
|
964
932
|
|
|
965
933
|
const Oops = issues({
|
package/package.json
CHANGED