@expressive/mvc 0.29.2 → 0.31.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
@@ -58,18 +58,20 @@ declare global {
58
58
  }
59
59
  }
60
60
 
61
- type OnValue<T, P extends Model.Key<T>> = (this: T, value: T[P], updated: Model.Event<T>[]) => void;
62
- type OnValues<T, P extends Model.Key<T>> = (this: T, value: Model.Export<T, P>, updated: Model.Event<T>[]) => void;
61
+ type SelectOne<T, K extends Model.Key<T>> = K;
62
+ type SelectFew<T, K extends Model.Key<T>> = K[];
63
+ type Select<T, K extends Model.Key<T> = Model.Key<T>> = K | K[];
64
+ type Export<T, S> = S extends SelectOne<T, infer P> ? T[P] : S extends SelectFew<T, infer P> ? Model.Export<T, P> : never;
65
+ type OnUpdate<T, S> = (this: T, value: Export<T, S>, updated: Model.Event<T>[]) => void;
63
66
  interface Observable {
64
67
  get(): Model.Export<this>;
68
+ get<P extends Select<this>>(select: P): Export<this, P>;
69
+ get<P extends Select<this>>(select: P, onUpdate: OnUpdate<this, P>, once?: true): Callback;
70
+ get<P extends Select<this>>(select: P, onUpdate: OnUpdate<this, P>, initial?: false): Callback;
65
71
  get(effect: Model.Effect<this>): Callback;
66
- get<P extends Model.Key<this>>(select: P): this[P];
67
- get<P extends Model.Key<this>>(select: P, onUpdate: OnValue<this, P>, once?: boolean): Callback;
68
- get<P extends Model.Key<this>>(select: P[]): Model.Export<this, P>;
69
- get<P extends Model.Key<this>>(select: P[], onUpdate: OnValues<this, P>, once?: boolean): Callback;
70
72
  set(): Promise<Model.Event<this>[]>;
71
73
  set(timeout: number): Promise<Model.Event<this>[] | false>;
72
- set<T extends Model.Values<this>>(source: T, only?: (keyof T)[]): Promise<Model.Event<T>[] | false>;
74
+ set<T extends Model.Values<this>>(from: T, only?: (keyof T)[]): Promise<Model.Event<T>[] | false>;
73
75
  set<K extends Model.Key<this>>(key: K, value: Model.Value<this[K]>): Promise<Model.Event<this>[] | false>;
74
76
  set<K extends Model.Event<this>>(key: K): Promise<Model.Event<this>[] | false>;
75
77
  }
@@ -82,34 +84,23 @@ declare namespace Model {
82
84
  type Type<T extends Model = Model> = abstract new (...args: any[]) => T;
83
85
  /** A typeof Model, specifically one which can be created without any arguments. */
84
86
  type New<T extends Model = Model> = (new () => T) & typeof Model;
85
- type Effect<T> = (this: T, argument: T) => Callback | Promise<any> | void;
86
- /** Exotic value, actual value is contained. */
87
- type Ref<T = any> = {
88
- (next: T): void;
89
- current: T | null;
90
- };
91
- /**
92
- * Subset of `keyof T` which are not methods or defined by base Model U.
93
- **/
94
- type Key<T, U = Model> = Extract<Exclude<keyof T, keyof U>, string>;
87
+ /** A callback function which is subscribed to parent and updates when values change. */
88
+ type Effect<T> = (this: T, argument: T) => Callback | Promise<void> | void;
89
+ /** Subset of `keyof T` which are not methods or defined by base Model U. **/
90
+ type Key<T, U = Observable> = Extract<Exclude<keyof T, keyof U>, string>;
95
91
  /** Including but not limited to `keyof T` which are not methods or defined by base Model. */
96
92
  type Event<T> = Key<T> | (string & {});
97
- /** Actual value stored in state. */
98
- type Value<R> = R extends Ref<infer T> ? T : R extends Observable ? Export<R> : R;
99
93
  /** Object comperable to data found in T. */
100
94
  type Values<T> = {
101
95
  [P in Key<T>]?: Value<T[P]>;
102
96
  };
103
97
  /**
104
98
  * Values from current state of given controller.
105
- *
106
- * Differs from `Entries` as values here will drill into "real" values held by exotics like ref.
99
+ * Differs from `Values` as values here will drill into "real" values held by exotics like ref.
107
100
  */
108
101
  type Export<T, K extends Key<T> = Key<T>> = {
109
102
  [P in K]: Value<T[P]>;
110
103
  };
111
- /** Promise thrown by something which is not yet ready. */
112
- type Suspense = Promise<void> & Error;
113
104
  /**
114
105
  * Reference to `this` without a subscription.
115
106
  * Use to obtain full reference from a destructure.
@@ -117,6 +108,13 @@ declare namespace Model {
117
108
  type Focus<T> = T & {
118
109
  is: T;
119
110
  };
111
+ /** Exotic value, actual value is contained. */
112
+ type Ref<T = any> = {
113
+ (next: T): void;
114
+ current: T | null;
115
+ };
116
+ /** Actual value stored in state. */
117
+ type Value<R> = R extends Ref<infer T> ? T : R extends Observable ? Export<R> : R;
120
118
  }
121
119
  interface Model extends Observable {
122
120
  }
@@ -344,9 +342,9 @@ declare class Control<T extends {} = any> {
344
342
  static use: Control.UseHook;
345
343
  static has: Control.GetContext;
346
344
  static for: typeof control;
347
- static apply: typeof apply;
345
+ static does: typeof does;
348
346
  static watch: typeof watch;
349
- id?: string | number;
347
+ id: string | number | false;
350
348
  subject: T;
351
349
  state: {
352
350
  [key: string]: any;
@@ -355,8 +353,8 @@ declare class Control<T extends {} = any> {
355
353
  frame: Set<string>;
356
354
  followers: Set<Observer<any>>;
357
355
  observers: Map<string, Set<Observer<any>>>;
358
- constructor(subject: T, id?: string | number | false);
359
- add(key: Extract<keyof T, string>): void;
356
+ constructor(subject: T, id: string | number | false);
357
+ add(key: string): void;
360
358
  watch(key: string, output: Control.PropertyDescriptor<any>): void;
361
359
  ref<K extends Model.Key<T>>(key: K, callback?: (this: T, value: T[K]) => boolean | void): (value: any) => void;
362
360
  update(key: string): void;
@@ -369,7 +367,7 @@ type Focus<T extends {}> = T & {
369
367
  is: T;
370
368
  };
371
369
  declare function watch<T extends {}>(value: T, cb: Observer): Focus<T>;
372
- declare function apply<T = any>(instruction: Control.Instruction<T>): T;
370
+ declare function does<T = any>(instruction: Control.Instruction<T>): T;
373
371
 
374
372
  declare const STATE = "__state";
375
373
  declare const UPDATE = "__update";
package/lib/index.esm.js CHANGED
@@ -292,6 +292,7 @@ function getMethod(argument, callback, once) {
292
292
  if (typeof callback != "function")
293
293
  return extract();
294
294
  const select = typeof argument == "string" ? [argument] : argument;
295
+ const invoke = () => callback(extract(), self.latest || []);
295
296
  if (select)
296
297
  for (const key of select)
297
298
  try {
@@ -302,11 +303,13 @@ function getMethod(argument, callback, once) {
302
303
  catch (e) {
303
304
  // TODO: should this be caught?
304
305
  }
306
+ if (once === undefined)
307
+ invoke();
305
308
  const remove = self.addListener(key => {
306
309
  if (!select || select.includes(key)) {
307
310
  if (once)
308
311
  remove();
309
- return () => callback(extract(), self.latest);
312
+ return invoke;
310
313
  }
311
314
  });
312
315
  return remove;
@@ -351,7 +354,7 @@ function setMethod(arg1, arg2) {
351
354
 
352
355
  class Model {
353
356
  constructor(id) {
354
- new Control(this, id);
357
+ new Control(this, id === undefined ? uid() : id);
355
358
  }
356
359
  /** Mark this instance for garbage collection. */
357
360
  null() {
@@ -416,7 +419,11 @@ defineProperties(Model.prototype, {
416
419
  throw new Error("Model.on() is deprecated. Use Model.get or Model.set instead.");
417
420
  }
418
421
  }
419
- });
422
+ });
423
+ /** Random alphanumberic of length 6. Will always start with a letter. */
424
+ function uid() {
425
+ return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
426
+ }
420
427
 
421
428
  const Oops$4 = issues({
422
429
  BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
@@ -432,12 +439,11 @@ class Control {
432
439
  this.frame = new Set();
433
440
  this.followers = new Set();
434
441
  this.observers = new Map([["", this.followers]]);
442
+ this.id = id;
435
443
  this.subject = subject;
436
444
  REGISTER.set(subject, this);
437
- if (id !== false) {
438
- this.id = id === undefined ? uid() : id;
445
+ if (id !== false)
439
446
  PENDING$1.set(this, new Set(Control.ready));
440
- }
441
447
  }
442
448
  add(key) {
443
449
  const { value } = getOwnPropertyDescriptor(this.subject, key);
@@ -534,7 +540,7 @@ Control.after = new Set();
534
540
  Control.before = new Set();
535
541
  Control.pending = new Set();
536
542
  Control.for = control;
537
- Control.apply = apply;
543
+ Control.does = does;
538
544
  Control.watch = watch;
539
545
  function control(subject, ready) {
540
546
  const control = REGISTER.get(subject);
@@ -599,7 +605,7 @@ function watch(value, cb) {
599
605
  OBSERVER.set(value, cb);
600
606
  return value;
601
607
  }
602
- function apply(instruction) {
608
+ function does(instruction) {
603
609
  const placeholder = Symbol("instruction");
604
610
  INSTRUCT.set(placeholder, (onto, key) => {
605
611
  delete onto.subject[key];
@@ -608,17 +614,13 @@ function apply(instruction) {
608
614
  onto.watch(key, typeof output == "function" ? { get: output } : output);
609
615
  });
610
616
  return placeholder;
611
- }
612
- /** Random alphanumberic of length 6; will always start with a letter. */
613
- function uid() {
614
- return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
615
617
  }
616
618
 
617
619
  const Oops$3 = issues({
618
620
  DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
619
621
  });
620
622
  function run(task) {
621
- return apply((key, control) => {
623
+ return does((key, control) => {
622
624
  let pending = false;
623
625
  const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
624
626
  if (pending)
@@ -652,7 +654,7 @@ const Oops$2 = issues({
652
654
  AmbientRequired: (requested, requester) => `Attempted to find an instance of ${requested} in context. It is required by ${requester}, but one could not be found.`
653
655
  });
654
656
  function get(arg0, arg1) {
655
- return apply((key, control) => {
657
+ return does((key, control) => {
656
658
  let { subject } = control;
657
659
  if (typeof arg0 == "symbol")
658
660
  throw Oops$2.PeerNotAllowed(subject, key);
@@ -778,7 +780,7 @@ function flushComputed() {
778
780
  Control.before.add(flushComputed);
779
781
 
780
782
  function ref(arg, arg2) {
781
- return apply((key, source) => {
783
+ return does((key, source) => {
782
784
  let value = {};
783
785
  if (typeof arg == "object")
784
786
  for (const key in control(arg, true).state)
@@ -813,7 +815,7 @@ const Oops$1 = issues({
813
815
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
814
816
  });
815
817
  function set(value, argument) {
816
- return apply((key, control) => {
818
+ return does((key, control) => {
817
819
  const { state, subject } = control;
818
820
  if (typeof value == "function" || value instanceof Promise) {
819
821
  const output = {};
@@ -883,7 +885,7 @@ function set(value, argument) {
883
885
  }
884
886
 
885
887
  function use(input, argument) {
886
- return apply((key, source) => {
888
+ return does((key, source) => {
887
889
  const { state, subject } = source;
888
890
  if (typeof input === "function")
889
891
  input = new input();
package/lib/index.js CHANGED
@@ -296,6 +296,7 @@ function getMethod(argument, callback, once) {
296
296
  if (typeof callback != "function")
297
297
  return extract();
298
298
  const select = typeof argument == "string" ? [argument] : argument;
299
+ const invoke = () => callback(extract(), self.latest || []);
299
300
  if (select)
300
301
  for (const key of select)
301
302
  try {
@@ -306,11 +307,13 @@ function getMethod(argument, callback, once) {
306
307
  catch (e) {
307
308
  // TODO: should this be caught?
308
309
  }
310
+ if (once === undefined)
311
+ invoke();
309
312
  const remove = self.addListener(key => {
310
313
  if (!select || select.includes(key)) {
311
314
  if (once)
312
315
  remove();
313
- return () => callback(extract(), self.latest);
316
+ return invoke;
314
317
  }
315
318
  });
316
319
  return remove;
@@ -355,7 +358,7 @@ function setMethod(arg1, arg2) {
355
358
 
356
359
  class Model {
357
360
  constructor(id) {
358
- new Control(this, id);
361
+ new Control(this, id === undefined ? uid() : id);
359
362
  }
360
363
  /** Mark this instance for garbage collection. */
361
364
  null() {
@@ -420,7 +423,11 @@ defineProperties(Model.prototype, {
420
423
  throw new Error("Model.on() is deprecated. Use Model.get or Model.set instead.");
421
424
  }
422
425
  }
423
- });
426
+ });
427
+ /** Random alphanumberic of length 6. Will always start with a letter. */
428
+ function uid() {
429
+ return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
430
+ }
424
431
 
425
432
  const Oops$4 = issues({
426
433
  BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
@@ -436,12 +443,11 @@ class Control {
436
443
  this.frame = new Set();
437
444
  this.followers = new Set();
438
445
  this.observers = new Map([["", this.followers]]);
446
+ this.id = id;
439
447
  this.subject = subject;
440
448
  REGISTER.set(subject, this);
441
- if (id !== false) {
442
- this.id = id === undefined ? uid() : id;
449
+ if (id !== false)
443
450
  PENDING$1.set(this, new Set(Control.ready));
444
- }
445
451
  }
446
452
  add(key) {
447
453
  const { value } = getOwnPropertyDescriptor(this.subject, key);
@@ -538,7 +544,7 @@ Control.after = new Set();
538
544
  Control.before = new Set();
539
545
  Control.pending = new Set();
540
546
  Control.for = control;
541
- Control.apply = apply;
547
+ Control.does = does;
542
548
  Control.watch = watch;
543
549
  function control(subject, ready) {
544
550
  const control = REGISTER.get(subject);
@@ -603,7 +609,7 @@ function watch(value, cb) {
603
609
  OBSERVER.set(value, cb);
604
610
  return value;
605
611
  }
606
- function apply(instruction) {
612
+ function does(instruction) {
607
613
  const placeholder = Symbol("instruction");
608
614
  INSTRUCT.set(placeholder, (onto, key) => {
609
615
  delete onto.subject[key];
@@ -612,17 +618,13 @@ function apply(instruction) {
612
618
  onto.watch(key, typeof output == "function" ? { get: output } : output);
613
619
  });
614
620
  return placeholder;
615
- }
616
- /** Random alphanumberic of length 6; will always start with a letter. */
617
- function uid() {
618
- return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
619
621
  }
620
622
 
621
623
  const Oops$3 = issues({
622
624
  DuplicatePending: (key) => `Invoked action ${key} but one is already active.`
623
625
  });
624
626
  function run(task) {
625
- return apply((key, control) => {
627
+ return does((key, control) => {
626
628
  let pending = false;
627
629
  const invoke = (...args) => __awaiter(this, void 0, void 0, function* () {
628
630
  if (pending)
@@ -656,7 +658,7 @@ const Oops$2 = issues({
656
658
  AmbientRequired: (requested, requester) => `Attempted to find an instance of ${requested} in context. It is required by ${requester}, but one could not be found.`
657
659
  });
658
660
  function get(arg0, arg1) {
659
- return apply((key, control) => {
661
+ return does((key, control) => {
660
662
  let { subject } = control;
661
663
  if (typeof arg0 == "symbol")
662
664
  throw Oops$2.PeerNotAllowed(subject, key);
@@ -782,7 +784,7 @@ function flushComputed() {
782
784
  Control.before.add(flushComputed);
783
785
 
784
786
  function ref(arg, arg2) {
785
- return apply((key, source) => {
787
+ return does((key, source) => {
786
788
  let value = {};
787
789
  if (typeof arg == "object")
788
790
  for (const key in control(arg, true).state)
@@ -817,7 +819,7 @@ const Oops$1 = issues({
817
819
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`
818
820
  });
819
821
  function set(value, argument) {
820
- return apply((key, control) => {
822
+ return does((key, control) => {
821
823
  const { state, subject } = control;
822
824
  if (typeof value == "function" || value instanceof Promise) {
823
825
  const output = {};
@@ -887,7 +889,7 @@ function set(value, argument) {
887
889
  }
888
890
 
889
891
  function use(input, argument) {
890
- return apply((key, source) => {
892
+ return does((key, source) => {
891
893
  const { state, subject } = source;
892
894
  if (typeof input === "function")
893
895
  input = new input();
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.29.2",
30
- "gitHead": "a10efcc0deba6e634d9b194ceda506573e981719"
29
+ "version": "0.31.0",
30
+ "gitHead": "63fd9a26371cb53d00ff2e3f5f2673660c6213de"
31
31
  }