@expressive/mvc 0.29.1 → 0.30.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,15 +58,17 @@ 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
74
  set<T extends Model.Values<this>>(source: T, only?: (keyof T)[]): Promise<Model.Event<T>[] | false>;
@@ -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
  }
@@ -346,7 +344,7 @@ declare class Control<T extends {} = any> {
346
344
  static for: typeof control;
347
345
  static apply: typeof apply;
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;
package/lib/index.esm.js CHANGED
@@ -254,11 +254,13 @@ function createEffect(source, callback) {
254
254
  return () => refresh = null;
255
255
  });
256
256
  }
257
- function createValueEffect(callback) {
257
+ function createValueEffect(callback, ignoreNull) {
258
258
  let unSet;
259
259
  return function (value) {
260
260
  if (typeof unSet == "function")
261
- unSet(value);
261
+ unSet = void unSet(value);
262
+ if (value === null && ignoreNull)
263
+ return;
262
264
  const out = callback.call(this, value);
263
265
  if (typeof out == "boolean")
264
266
  return out;
@@ -290,6 +292,7 @@ function getMethod(argument, callback, once) {
290
292
  if (typeof callback != "function")
291
293
  return extract();
292
294
  const select = typeof argument == "string" ? [argument] : argument;
295
+ const invoke = () => callback(extract(), self.latest || []);
293
296
  if (select)
294
297
  for (const key of select)
295
298
  try {
@@ -300,11 +303,13 @@ function getMethod(argument, callback, once) {
300
303
  catch (e) {
301
304
  // TODO: should this be caught?
302
305
  }
306
+ if (once === undefined)
307
+ invoke();
303
308
  const remove = self.addListener(key => {
304
309
  if (!select || select.includes(key)) {
305
310
  if (once)
306
311
  remove();
307
- return () => callback(extract(), self.latest);
312
+ return invoke;
308
313
  }
309
314
  });
310
315
  return remove;
@@ -349,7 +354,7 @@ function setMethod(arg1, arg2) {
349
354
 
350
355
  class Model {
351
356
  constructor(id) {
352
- new Control(this, id);
357
+ new Control(this, id === undefined ? uid() : id);
353
358
  }
354
359
  /** Mark this instance for garbage collection. */
355
360
  null() {
@@ -414,7 +419,11 @@ defineProperties(Model.prototype, {
414
419
  throw new Error("Model.on() is deprecated. Use Model.get or Model.set instead.");
415
420
  }
416
421
  }
417
- });
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
+ }
418
427
 
419
428
  const Oops$4 = issues({
420
429
  BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
@@ -430,12 +439,11 @@ class Control {
430
439
  this.frame = new Set();
431
440
  this.followers = new Set();
432
441
  this.observers = new Map([["", this.followers]]);
442
+ this.id = id;
433
443
  this.subject = subject;
434
444
  REGISTER.set(subject, this);
435
- if (id !== false) {
436
- this.id = id === undefined ? uid() : id;
445
+ if (id !== false)
437
446
  PENDING$1.set(this, new Set(Control.ready));
438
- }
439
447
  }
440
448
  add(key) {
441
449
  const { value } = getOwnPropertyDescriptor(this.subject, key);
@@ -606,10 +614,6 @@ function apply(instruction) {
606
614
  onto.watch(key, typeof output == "function" ? { get: output } : output);
607
615
  });
608
616
  return placeholder;
609
- }
610
- /** Random alphanumberic of length 6; will always start with a letter. */
611
- function uid() {
612
- return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
613
617
  }
614
618
 
615
619
  const Oops$3 = issues({
@@ -775,33 +779,30 @@ function flushComputed() {
775
779
  }
776
780
  Control.before.add(flushComputed);
777
781
 
778
- function ref(arg, mapper) {
782
+ function ref(arg, arg2) {
779
783
  return apply((key, source) => {
780
784
  let value = {};
781
785
  if (typeof arg == "object")
782
- for (const key in control(arg, true).state) {
783
- defineProperty(value, key, typeof mapper == "function" ? {
786
+ for (const key in control(arg, true).state)
787
+ defineProperty(value, key, typeof arg2 == "function" ? {
784
788
  configurable: true,
785
789
  get() {
786
- const out = mapper(key);
790
+ const out = arg2(key);
787
791
  defineProperty(value, key, { value: out });
788
792
  return out;
789
793
  }
790
794
  } : {
791
795
  value: createRef(source, key)
792
796
  });
793
- }
794
797
  else
795
- value = createRef(source, key, arg && mapper !== false
796
- ? (x) => x !== null ? arg(x) : undefined
797
- : arg);
798
+ value = createRef(source, key, arg && createValueEffect(arg, arg2 !== false));
798
799
  source.state[key] = undefined;
799
800
  source.observers.set(key, new Set());
800
801
  defineProperty(source.subject, key, { value });
801
802
  });
802
803
  }
803
804
  function createRef(src, key, cb) {
804
- const refObjectFunction = src.ref(key, cb && createValueEffect(cb));
805
+ const refObjectFunction = src.ref(key, cb);
805
806
  defineProperty(refObjectFunction, "current", {
806
807
  set: refObjectFunction,
807
808
  get: () => src.state[key]
package/lib/index.js CHANGED
@@ -258,11 +258,13 @@ function createEffect(source, callback) {
258
258
  return () => refresh = null;
259
259
  });
260
260
  }
261
- function createValueEffect(callback) {
261
+ function createValueEffect(callback, ignoreNull) {
262
262
  let unSet;
263
263
  return function (value) {
264
264
  if (typeof unSet == "function")
265
- unSet(value);
265
+ unSet = void unSet(value);
266
+ if (value === null && ignoreNull)
267
+ return;
266
268
  const out = callback.call(this, value);
267
269
  if (typeof out == "boolean")
268
270
  return out;
@@ -294,6 +296,7 @@ function getMethod(argument, callback, once) {
294
296
  if (typeof callback != "function")
295
297
  return extract();
296
298
  const select = typeof argument == "string" ? [argument] : argument;
299
+ const invoke = () => callback(extract(), self.latest || []);
297
300
  if (select)
298
301
  for (const key of select)
299
302
  try {
@@ -304,11 +307,13 @@ function getMethod(argument, callback, once) {
304
307
  catch (e) {
305
308
  // TODO: should this be caught?
306
309
  }
310
+ if (once === undefined)
311
+ invoke();
307
312
  const remove = self.addListener(key => {
308
313
  if (!select || select.includes(key)) {
309
314
  if (once)
310
315
  remove();
311
- return () => callback(extract(), self.latest);
316
+ return invoke;
312
317
  }
313
318
  });
314
319
  return remove;
@@ -353,7 +358,7 @@ function setMethod(arg1, arg2) {
353
358
 
354
359
  class Model {
355
360
  constructor(id) {
356
- new Control(this, id);
361
+ new Control(this, id === undefined ? uid() : id);
357
362
  }
358
363
  /** Mark this instance for garbage collection. */
359
364
  null() {
@@ -418,7 +423,11 @@ defineProperties(Model.prototype, {
418
423
  throw new Error("Model.on() is deprecated. Use Model.get or Model.set instead.");
419
424
  }
420
425
  }
421
- });
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
+ }
422
431
 
423
432
  const Oops$4 = issues({
424
433
  BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
@@ -434,12 +443,11 @@ class Control {
434
443
  this.frame = new Set();
435
444
  this.followers = new Set();
436
445
  this.observers = new Map([["", this.followers]]);
446
+ this.id = id;
437
447
  this.subject = subject;
438
448
  REGISTER.set(subject, this);
439
- if (id !== false) {
440
- this.id = id === undefined ? uid() : id;
449
+ if (id !== false)
441
450
  PENDING$1.set(this, new Set(Control.ready));
442
- }
443
451
  }
444
452
  add(key) {
445
453
  const { value } = getOwnPropertyDescriptor(this.subject, key);
@@ -610,10 +618,6 @@ function apply(instruction) {
610
618
  onto.watch(key, typeof output == "function" ? { get: output } : output);
611
619
  });
612
620
  return placeholder;
613
- }
614
- /** Random alphanumberic of length 6; will always start with a letter. */
615
- function uid() {
616
- return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
617
621
  }
618
622
 
619
623
  const Oops$3 = issues({
@@ -779,33 +783,30 @@ function flushComputed() {
779
783
  }
780
784
  Control.before.add(flushComputed);
781
785
 
782
- function ref(arg, mapper) {
786
+ function ref(arg, arg2) {
783
787
  return apply((key, source) => {
784
788
  let value = {};
785
789
  if (typeof arg == "object")
786
- for (const key in control(arg, true).state) {
787
- defineProperty(value, key, typeof mapper == "function" ? {
790
+ for (const key in control(arg, true).state)
791
+ defineProperty(value, key, typeof arg2 == "function" ? {
788
792
  configurable: true,
789
793
  get() {
790
- const out = mapper(key);
794
+ const out = arg2(key);
791
795
  defineProperty(value, key, { value: out });
792
796
  return out;
793
797
  }
794
798
  } : {
795
799
  value: createRef(source, key)
796
800
  });
797
- }
798
801
  else
799
- value = createRef(source, key, arg && mapper !== false
800
- ? (x) => x !== null ? arg(x) : undefined
801
- : arg);
802
+ value = createRef(source, key, arg && createValueEffect(arg, arg2 !== false));
802
803
  source.state[key] = undefined;
803
804
  source.observers.set(key, new Set());
804
805
  defineProperty(source.subject, key, { value });
805
806
  });
806
807
  }
807
808
  function createRef(src, key, cb) {
808
- const refObjectFunction = src.ref(key, cb && createValueEffect(cb));
809
+ const refObjectFunction = src.ref(key, cb);
809
810
  defineProperty(refObjectFunction, "current", {
810
811
  set: refObjectFunction,
811
812
  get: () => src.state[key]
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.1",
30
- "gitHead": "bc5ef985433d6f7d198eda375cda9e8a055ca0d0"
29
+ "version": "0.30.0",
30
+ "gitHead": "8e2ed856c216a18e350494fef186adbee3c20f73"
31
31
  }