@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 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 & string, output: Control.PropertyDescriptor<any>): void;
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>, callback?: (i: T) => void): 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
- * Create child-instance relationship with provided model.
390
- *
391
- * Note: If `peer` is not already initialized before parent is
392
- * (created with `new` as opposed to create method), that model will
393
- * attach this via `parent()` instruction. It will not, however, if
394
- * already active.
395
- */
396
- declare function use<T extends Model>(peer: T, callback?: (i: T) => void): T;
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$9 = issues({
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$9.NotReady(source.subject, key);
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
- const subs = source.observers.get(key);
53
- const onUpdate = (key) => {
53
+ function onUpdate(key) {
54
54
  if (key)
55
55
  return () => {
56
56
  if (source.state[key] !== undefined) {
57
- subs.delete(onUpdate);
57
+ watch.delete(onUpdate);
58
58
  resolve();
59
59
  }
60
60
  };
61
- reject(Oops$9.Destoryed());
62
- };
63
- subs.add(onUpdate);
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$8 = issues({
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$8.BadCallback();
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$8.BadCallback();
140
+ throw Oops$7.BadCallback();
140
141
  };
141
142
  }
142
143
 
143
- const Oops$7 = issues({
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$7.KeysExpected(select));
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$6 = issues({
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$6.NotFound(this);
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$6.NotFound(this);
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$5 = issues({
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 = INSTRUCTION.get(value);
443
+ const instruction = INSTRUCT.get(value);
443
444
  if (typeof instruction == "function") {
444
- INSTRUCTION.delete(value);
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$5.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
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
- INSTRUCTION.set(placeholder, (onto, key) => {
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$4 = issues({
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$4.DuplicatePending(key));
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$3 = issues({
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$3.PeerNotAllowed(subject, key);
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$3.Required(arg0, subject);
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$3.AmbientRequired(arg0, subject);
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$3.Unexpected(arg0, subject, hasParent);
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$3.Failed(parent.subject, key, initial).warn();
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$2 = issues({
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 required = argument !== false;
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
- state[key] = undefined;
825
- pending = value
826
- .catch(err => error = err)
827
- .then(val => {
828
- state[key] = val;
829
- return val;
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$2.ComputeFailed(subject, key).warn();
844
+ Oops$1.ComputeFailed(subject, key).warn();
858
845
  throw err;
859
846
  }
860
847
  };
861
- if (argument === true)
848
+ if (argument)
862
849
  init();
863
- return () => {
864
- if (!getter)
865
- init();
866
- return getter();
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
- let setter = typeof argument == "function"
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
- else if (setter) {
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
- return {
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
- const required = argument !== false;
901
- if (typeof input === "function") {
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
- 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
- }
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
- const output = { set };
950
- if (required)
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$9 = issues({
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$9.NotReady(source.subject, key);
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
- const subs = source.observers.get(key);
57
- const onUpdate = (key) => {
57
+ function onUpdate(key) {
58
58
  if (key)
59
59
  return () => {
60
60
  if (source.state[key] !== undefined) {
61
- subs.delete(onUpdate);
61
+ watch.delete(onUpdate);
62
62
  resolve();
63
63
  }
64
64
  };
65
- reject(Oops$9.Destoryed());
66
- };
67
- subs.add(onUpdate);
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$8 = issues({
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$8.BadCallback();
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$8.BadCallback();
144
+ throw Oops$7.BadCallback();
144
145
  };
145
146
  }
146
147
 
147
- const Oops$7 = issues({
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$7.KeysExpected(select));
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$6 = issues({
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$6.NotFound(this);
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$6.NotFound(this);
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$5 = issues({
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 = INSTRUCTION.get(value);
447
+ const instruction = INSTRUCT.get(value);
447
448
  if (typeof instruction == "function") {
448
- INSTRUCTION.delete(value);
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$5.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
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
- INSTRUCTION.set(placeholder, (onto, key) => {
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$4 = issues({
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$4.DuplicatePending(key));
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$3 = issues({
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$3.PeerNotAllowed(subject, key);
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$3.Required(arg0, subject);
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$3.AmbientRequired(arg0, subject);
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$3.Unexpected(arg0, subject, hasParent);
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$3.Failed(parent.subject, key, initial).warn();
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$2 = issues({
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 required = argument !== false;
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
- state[key] = undefined;
829
- pending = value
830
- .catch(err => error = err)
831
- .then(val => {
832
- state[key] = val;
833
- return val;
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$2.ComputeFailed(subject, key).warn();
848
+ Oops$1.ComputeFailed(subject, key).warn();
862
849
  throw err;
863
850
  }
864
851
  };
865
- if (argument === true)
852
+ if (argument)
866
853
  init();
867
- return () => {
868
- if (!getter)
869
- init();
870
- return getter();
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
- let setter = typeof argument == "function"
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
- else if (setter) {
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
- return {
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
- const required = argument !== false;
905
- if (typeof input === "function") {
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
- 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
- }
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
- const output = { set };
954
- if (required)
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
@@ -26,6 +26,6 @@
26
26
  "prebuild": "rm -rf lib/",
27
27
  "preversion": "npm run test && npm run build"
28
28
  },
29
- "version": "0.25.0",
30
- "gitHead": "a7c707bf59325bd4bf1388e061f7991acb726a13"
29
+ "version": "0.26.0",
30
+ "gitHead": "195aa8bd3fe81efd5f15a5a188854ab35e211fb9"
31
31
  }