@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 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>) => Callback | void;
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
- local: T;
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
- subject: T;
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 & string, output: Control.PropertyDescriptor<any>): void;
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
- declare function get$1<T extends Model>(this: Model.Type<T>): T;
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 extends []>(this: Model.Type<T>, factory: Model.GetCallback<T, R | (() => R)>, expect?: boolean): R;
163
- declare function get$1<T extends Model, R extends []>(this: Model.Type<T>, factory: Model.GetCallback<T, Promise<R> | (() => R) | null>, expect?: boolean): R | null;
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, select?: (keyof T)[]): Promise<Model.Key<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>, callback?: (i: T) => void): 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
- * Create child-instance relationship with provided model.
395
- *
396
- * Note: If `peer` is not already initialized before parent is
397
- * (created with `new` as opposed to create method), that model will
398
- * attach this via `parent()` instruction. It will not, however, if
399
- * already active.
400
- */
401
- 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;
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$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,22 +195,22 @@ 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
- function get$1(arg1, arg2) {
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 arg1 !== "function") {
206
+ if (typeof argument !== "function") {
206
207
  const got = context.get(this);
207
208
  if (got)
208
- value = arg1 === undefined
209
+ value = argument === undefined
209
210
  ? Control.watch(got, k => k ? onUpdate : undefined)
210
211
  : got;
211
- else if (arg1 !== false)
212
- throw Oops$6.NotFound(this);
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 = arg1;
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$6.NotFound(this);
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 (notEqual(value, next))
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 (arg2)
282
- throw new Promise(res => {
283
- suspense = res;
284
- });
285
- return null;
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(arg1, arg2) {
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 apply = !!arg1;
298
+ let shouldApply = !!apply;
303
299
  return {
304
- local,
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 (apply) {
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 (!arg2)
322
- apply = false;
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(arg1);
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$5 = issues({
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 = uid()) {
435
- this.subject = subject;
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 = INSTRUCTION.get(value);
443
+ const instruction = INSTRUCT.get(value);
445
444
  if (typeof instruction == "function") {
446
- INSTRUCTION.delete(value);
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 onReady = typeof ready == "function" && ready;
542
- if (!control.state && ready) {
543
- let waiting = PENDING_INIT.get(control);
544
- if (!waiting)
545
- PENDING_INIT.set(control, waiting = new Set());
546
- if (onReady) {
547
- let callback;
548
- waiting.add(() => callback = onReady(control));
549
- return () => callback && callback();
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
- waiting.forEach(cb => cb());
552
+ pending.forEach(cb => cb(control));
555
553
  }
556
- return onReady ? onReady(control) : control;
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$5.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
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, register) {
590
- if (!register)
587
+ function parent(child, assign) {
588
+ if (!assign)
591
589
  return PARENTS.get(child);
592
- PARENTS.set(child, register);
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
- INSTRUCTION.set(placeholder, (onto, key) => {
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$4 = issues({
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$4.DuplicatePending(key));
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$3 = issues({
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$3.PeerNotAllowed(subject, key);
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$3.Required(arg0, subject);
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$3.AmbientRequired(arg0, subject);
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$3.Unexpected(arg0, subject, hasParent);
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$3.Failed(parent.subject, key, initial).warn();
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$2 = issues({
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 required = argument !== false;
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
- state[key] = undefined;
828
- pending = value
829
- .catch(err => error = err)
830
- .then(val => {
831
- state[key] = val;
832
- 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; };
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$2.ComputeFailed(subject, key).warn();
844
+ Oops$1.ComputeFailed(subject, key).warn();
861
845
  throw err;
862
846
  }
863
847
  };
864
- if (argument === true)
848
+ if (argument)
865
849
  init();
866
- return () => {
867
- if (!getter)
868
- init();
869
- return getter();
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
- let setter = typeof argument == "function"
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
- else if (setter) {
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
- return {
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
- const required = argument !== false;
904
- if (typeof input === "function") {
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
- const control = new Control(create(next));
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
- const output = { set };
953
- if (required)
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$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,22 +199,22 @@ 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
- function get$1(arg1, arg2) {
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 arg1 !== "function") {
210
+ if (typeof argument !== "function") {
210
211
  const got = context.get(this);
211
212
  if (got)
212
- value = arg1 === undefined
213
+ value = argument === undefined
213
214
  ? Control.watch(got, k => k ? onUpdate : undefined)
214
215
  : got;
215
- else if (arg1 !== false)
216
- throw Oops$6.NotFound(this);
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 = arg1;
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$6.NotFound(this);
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 (notEqual(value, next))
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 (arg2)
286
- throw new Promise(res => {
287
- suspense = res;
288
- });
289
- return null;
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(arg1, arg2) {
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 apply = !!arg1;
302
+ let shouldApply = !!apply;
307
303
  return {
308
- local,
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 (apply) {
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 (!arg2)
326
- apply = false;
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(arg1);
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$5 = issues({
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 = uid()) {
439
- this.subject = subject;
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 = INSTRUCTION.get(value);
447
+ const instruction = INSTRUCT.get(value);
449
448
  if (typeof instruction == "function") {
450
- INSTRUCTION.delete(value);
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 onReady = typeof ready == "function" && ready;
546
- if (!control.state && ready) {
547
- let waiting = PENDING_INIT.get(control);
548
- if (!waiting)
549
- PENDING_INIT.set(control, waiting = new Set());
550
- if (onReady) {
551
- let callback;
552
- waiting.add(() => callback = onReady(control));
553
- return () => callback && callback();
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
- waiting.forEach(cb => cb());
556
+ pending.forEach(cb => cb(control));
559
557
  }
560
- return onReady ? onReady(control) : control;
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$5.BadAssignment(`${on.subject}.${key}`, value.constructor, next);
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, register) {
594
- if (!register)
591
+ function parent(child, assign) {
592
+ if (!assign)
595
593
  return PARENTS.get(child);
596
- PARENTS.set(child, register);
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
- INSTRUCTION.set(placeholder, (onto, key) => {
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$4 = issues({
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$4.DuplicatePending(key));
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$3 = issues({
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$3.PeerNotAllowed(subject, key);
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$3.Required(arg0, subject);
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$3.AmbientRequired(arg0, subject);
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$3.Unexpected(arg0, subject, hasParent);
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$3.Failed(parent.subject, key, initial).warn();
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$2 = issues({
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 required = argument !== false;
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
- state[key] = undefined;
832
- pending = value
833
- .catch(err => error = err)
834
- .then(val => {
835
- state[key] = val;
836
- 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; };
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$2.ComputeFailed(subject, key).warn();
848
+ Oops$1.ComputeFailed(subject, key).warn();
865
849
  throw err;
866
850
  }
867
851
  };
868
- if (argument === true)
852
+ if (argument)
869
853
  init();
870
- return () => {
871
- if (!getter)
872
- init();
873
- return getter();
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
- let setter = typeof argument == "function"
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
- else if (setter) {
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
- return {
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
- const required = argument !== false;
908
- if (typeof input === "function") {
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
- const control = new Control(create(next));
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
- const output = { set };
957
- if (required)
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
@@ -26,6 +26,6 @@
26
26
  "prebuild": "rm -rf lib/",
27
27
  "preversion": "npm run test && npm run build"
28
28
  },
29
- "version": "0.24.2",
30
- "gitHead": "97e6daffcf793d8aa1152d553b4c427546e90dbc"
29
+ "version": "0.26.0",
30
+ "gitHead": "195aa8bd3fe81efd5f15a5a188854ab35e211fb9"
31
31
  }