@expressive/mvc 1.0.0-beta.43 → 1.0.0-beta.44

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.js CHANGED
@@ -42,9 +42,6 @@ function defineLazy(object, property, init) {
42
42
  }
43
43
  });
44
44
  }
45
- function setAlias(func, displayName) {
46
- assign(func, { displayName });
47
- }
48
45
  function createEffect(callback) {
49
46
  let unSet;
50
47
  return function (value) {
@@ -152,66 +149,7 @@ class Subscriber {
152
149
 
153
150
  const Oops$b = issues({
154
151
  ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
155
- FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
156
152
  });
157
- /**
158
- * Get value, suspend instead if undefined.
159
- *
160
- * Throws suspense promise also interpretable as an error.
161
- * React could handle it but other contexts probably not.
162
- */
163
- function pendingValue(via, key) {
164
- const value = via.state[key];
165
- if (value === undefined)
166
- throw suspend(via, key);
167
- return value;
168
- }
169
- function pendingFactory(parent, key, fn, immediate) {
170
- const { subject, state } = parent;
171
- let pending;
172
- let error;
173
- const init = () => {
174
- const output = suspenseBoundary(() => {
175
- return fn.call(subject, key, subject);
176
- });
177
- if (output instanceof Promise) {
178
- pending = output
179
- .catch(err => error = err)
180
- .then(val => state[key] = val)
181
- .finally(() => {
182
- pending = undefined;
183
- parent.update(key);
184
- });
185
- const issue = Oops$b.ValueNotReady(subject, key);
186
- Object.assign(pending, {
187
- message: issue.message,
188
- stack: issue.stack
189
- });
190
- }
191
- return state[key] = output;
192
- };
193
- if (immediate)
194
- try {
195
- init();
196
- }
197
- catch (err) {
198
- Oops$b.FactoryFailed(subject, key).warn();
199
- throw err;
200
- }
201
- return () => {
202
- if (pending)
203
- throw pending;
204
- if (error)
205
- throw error;
206
- if (key in state)
207
- return state[key];
208
- let output = init();
209
- if (pending)
210
- throw pending;
211
- else
212
- return output;
213
- };
214
- }
215
153
  function suspend(source, key) {
216
154
  const error = Oops$b.ValueNotReady(source.subject, key);
217
155
  const promise = new Promise(resolve => {
@@ -248,9 +186,7 @@ function from(source, arg1, arg2) {
248
186
  const parent = this;
249
187
  const { subject, state } = this;
250
188
  let getSource;
251
- let getter;
252
- if (arg2 === true || arg1 === true)
253
- getter = pendingValue;
189
+ let required = arg2 === true || arg1 === true;
254
190
  if (typeof arg1 == "boolean")
255
191
  arg1 = undefined;
256
192
  // Easy mistake, using a peer, will always be unresolved.
@@ -334,9 +270,6 @@ function from(source, arg1, arg2) {
334
270
  }
335
271
  }
336
272
  }
337
- setAlias(update, `try ${key}`);
338
- setAlias(create, `new ${key}`);
339
- setAlias(setter, `run ${key}`);
340
273
  INIT.add(create);
341
274
  INFO.set(update, info);
342
275
  defineProperty(state, key, {
@@ -344,8 +277,12 @@ function from(source, arg1, arg2) {
344
277
  configurable: true,
345
278
  enumerable: true
346
279
  });
347
- if (getter)
348
- return () => getter(parent, key);
280
+ return () => {
281
+ const value = parent.state[key];
282
+ if (value === undefined && required)
283
+ throw suspend(this, key);
284
+ return value;
285
+ };
349
286
  });
350
287
  }
351
288
  function ensure(on, keys) {
@@ -372,7 +309,7 @@ function flush(on) {
372
309
  }
373
310
 
374
311
  const Oops$9 = issues({
375
- StrictUpdate: (expected) => `Strict update() did ${expected ? "not " : ""}find pending updates.`,
312
+ StrictUpdate: () => `Strict update() did not find pending updates.`,
376
313
  NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
377
314
  });
378
315
  const READY = new WeakSet();
@@ -402,7 +339,9 @@ class Controller {
402
339
  return;
403
340
  let onGet;
404
341
  let onSet;
342
+ let set;
405
343
  let enumerable;
344
+ let suspense;
406
345
  const instruction = Pending.get(entry);
407
346
  if (instruction) {
408
347
  Pending.delete(entry);
@@ -415,31 +354,35 @@ class Controller {
415
354
  state[key] = desc.value;
416
355
  onSet = desc.set;
417
356
  onGet = desc.get;
357
+ suspense = desc.suspense;
418
358
  enumerable = desc.enumerable;
419
359
  }
420
360
  }
421
361
  else
422
362
  state[key] = entry;
423
- const set = onSet !== false
424
- ? this.ref(key, onSet)
425
- : undefined;
426
- function get() {
427
- const local = this[LOCAL];
363
+ if (onSet !== false)
364
+ set = this.ref(key, onSet);
365
+ const get = (local) => {
366
+ if (!(key in state) && suspense)
367
+ throw suspend(this, key);
428
368
  const value = state[key];
429
- if (local && !local.watch[key])
430
- local.watch[key] = true;
431
- return onGet ? onGet(value, local) : value;
432
- }
433
- setAlias(get, `tap ${key}`);
369
+ if (onGet)
370
+ return local
371
+ ? onGet(value, local)
372
+ : onGet(value);
373
+ return value;
374
+ };
434
375
  defineProperty(subject, key, {
435
- enumerable,
436
- set,
437
- get: onGet
438
- ? () => onGet(state[key])
439
- : () => state[key]
376
+ enumerable, set, get
440
377
  });
441
378
  defineProperty(proxy, key, {
442
- enumerable, get, set
379
+ enumerable, set,
380
+ get() {
381
+ const local = this[LOCAL];
382
+ if (local && !local.watch[key])
383
+ local.watch[key] = true;
384
+ return get(local);
385
+ }
443
386
  });
444
387
  }
445
388
  ref(key, handler) {
@@ -499,12 +442,12 @@ class Controller {
499
442
  this.waiting.add(arg);
500
443
  return;
501
444
  }
502
- if (typeof arg == "boolean" && arg !== this.frame.size > 0)
503
- return Promise.reject(Oops$9.StrictUpdate(arg));
445
+ if (arg === true && this.frame.size < 1)
446
+ return Promise.reject(Oops$9.StrictUpdate());
504
447
  return {
505
448
  then: (callback) => {
506
449
  if (callback)
507
- if (this.frame.size)
450
+ if (this.frame.size || arg !== false)
508
451
  this.waiting.add(callback);
509
452
  else
510
453
  callback(false);
@@ -687,17 +630,21 @@ function apply(fn, label) {
687
630
  const placeholder = Symbol(`${name} instruction`);
688
631
  function setup(key) {
689
632
  let output = fn.call(this, key, this);
690
- if (typeof output == "function")
691
- return { get: output };
692
- if (typeof output !== "object")
693
- return output || undefined;
694
- if ("explicit" in output && output.explicit) {
695
- defineProperty(this.subject, key, output);
696
- return false;
633
+ switch (typeof output) {
634
+ case "function":
635
+ return { get: output };
636
+ case "object": {
637
+ if ("explicit" in output && output.explicit) {
638
+ defineProperty(this.subject, key, output);
639
+ return false;
640
+ }
641
+ if ("recursive" in output && output.recursive)
642
+ return Object.assign(Object.assign({}, output), { get: recursive(this, key) });
643
+ }
644
+ case "boolean":
645
+ return output;
697
646
  }
698
- if ("recursive" in output)
699
- output = Object.assign(Object.assign({}, output), { get: recursive(this, key) });
700
- return output;
647
+ return;
701
648
  }
702
649
  Pending.set(placeholder, setup);
703
650
  return placeholder;
@@ -753,7 +700,6 @@ function act(task) {
753
700
  });
754
701
  };
755
702
  this.state[key] = undefined;
756
- setAlias(invoke, `run ${key}`);
757
703
  defineProperty(invoke, "active", {
758
704
  get: () => pending
759
705
  });
@@ -788,20 +734,22 @@ function createRef(key, cb) {
788
734
 
789
735
  const Oops$7 = issues({
790
736
  NonOptional: (Parent, key) => `Property ${Parent}.${key} is marked as required.`,
791
- BadFactory: () => `Set instruction can only accept a factory or undefined.`
737
+ BadFactory: () => `Set instruction can only accept a factory or undefined.`,
738
+ ValueNotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
739
+ FactoryFailed: (model, key) => `Generating initial value for ${model}.${key} failed.`
792
740
  });
793
741
  function set(factory, argument) {
794
742
  return apply(function set(key) {
795
743
  let set;
796
744
  let get;
745
+ let suspense;
797
746
  const required = argument === true || argument === undefined;
798
747
  if (factory === undefined)
799
- get = () => pendingValue(this, key);
800
- else if (typeof factory !== "function")
801
- throw Oops$7.BadFactory();
802
- else {
748
+ suspense = true;
749
+ else if (typeof factory === "function")
803
750
  get = pendingFactory(this, key, factory, required);
804
- }
751
+ else
752
+ throw Oops$7.BadFactory();
805
753
  if (typeof argument == "function")
806
754
  set = createValueEffect(argument);
807
755
  else
@@ -809,8 +757,63 @@ function set(factory, argument) {
809
757
  if (value === undefined && required)
810
758
  throw Oops$7.NonOptional(this.subject, key);
811
759
  };
812
- return { set, get };
760
+ return {
761
+ set,
762
+ get,
763
+ suspense
764
+ };
813
765
  });
766
+ }
767
+ function pendingFactory(parent, key, fn, required) {
768
+ const { subject, state } = parent;
769
+ let pending;
770
+ let error;
771
+ const init = () => {
772
+ const output = suspenseBoundary(() => {
773
+ return fn.call(subject, key, subject);
774
+ });
775
+ if (output instanceof Promise) {
776
+ pending = output
777
+ .catch(err => error = err)
778
+ .then(val => state[key] = val)
779
+ .finally(() => {
780
+ pending = undefined;
781
+ parent.update(key);
782
+ });
783
+ return;
784
+ }
785
+ return state[key] = output;
786
+ };
787
+ const suspend = () => {
788
+ if (required === false)
789
+ return undefined;
790
+ const issue = Oops$7.ValueNotReady(subject, key);
791
+ Object.assign(pending, {
792
+ message: issue.message,
793
+ stack: issue.stack
794
+ });
795
+ throw pending;
796
+ };
797
+ if (required)
798
+ try {
799
+ init();
800
+ }
801
+ catch (err) {
802
+ Oops$7.FactoryFailed(subject, key).warn();
803
+ throw err;
804
+ }
805
+ return () => {
806
+ if (pending)
807
+ return suspend();
808
+ if (error)
809
+ throw error;
810
+ if (key in state)
811
+ return state[key];
812
+ let output = init();
813
+ return pending
814
+ ? suspend()
815
+ : output;
816
+ };
814
817
  }
815
818
 
816
819
  const Parent = new WeakMap();
@@ -953,24 +956,26 @@ const ContextWasUsed = new WeakMap();
953
956
  function tap(type, argument) {
954
957
  return apply(function tap(key) {
955
958
  if ("set" in type)
956
- this.state[key] = type.get();
957
- else {
958
- const { subject } = this;
959
- if ("set" in subject.constructor)
960
- throw Oops$3.CantAttachGlobal(subject, type.name);
961
- getPending(subject).push(context => {
962
- let instance = context.get(type);
963
- if (typeof argument == "function") {
964
- if (argument(instance) === false)
965
- instance = undefined;
966
- }
967
- else if (!instance && argument)
968
- throw Oops$3.AmbientRequired(type.name, subject, key);
969
- this.update(key, instance);
970
- });
971
- }
959
+ return {
960
+ recursive: true,
961
+ value: type.get()
962
+ };
963
+ const { subject } = this;
964
+ if ("set" in subject.constructor)
965
+ throw Oops$3.CantAttachGlobal(subject, type.name);
966
+ getPending(subject).push(context => {
967
+ let instance = context.get(type);
968
+ if (typeof argument == "function") {
969
+ if (argument(instance) === false)
970
+ instance = undefined;
971
+ }
972
+ else if (!instance && argument)
973
+ throw Oops$3.AmbientRequired(type.name, subject, key);
974
+ this.update(key, instance);
975
+ });
972
976
  return {
973
- recursive: true
977
+ recursive: true,
978
+ suspense: true
974
979
  };
975
980
  });
976
981
  }
@@ -1268,7 +1273,7 @@ class Global extends MVC {
1268
1273
  static set(updates) {
1269
1274
  const instance = Active.get(this) || this.create();
1270
1275
  instance.import(updates);
1271
- return instance.update();
1276
+ return instance.update(false);
1272
1277
  }
1273
1278
  static get(arg) {
1274
1279
  const instance = Active.get(this);