@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 +23 -25
- package/lib/index.esm.js +22 -21
- package/lib/index.js +22 -21
- package/package.json +2 -2
package/lib/index.d.ts
CHANGED
|
@@ -58,15 +58,17 @@ declare global {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
type
|
|
62
|
-
type
|
|
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
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
|
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
|
|
359
|
-
add(key:
|
|
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
|
|
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,
|
|
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
|
|
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 =
|
|
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 &&
|
|
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
|
|
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
|
|
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,
|
|
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
|
|
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 =
|
|
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 &&
|
|
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
|
|
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