@expressive/mvc 0.18.1 → 0.19.2
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 +68 -48
- package/lib/index.esm.js +56 -80
- package/lib/index.js +56 -79
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -1,13 +1,43 @@
|
|
|
1
|
-
declare
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
declare namespace Issue {
|
|
2
|
+
type Variable = {} | string | number | boolean | null | undefined;
|
|
3
|
+
type Variables<T> = T extends (...args: infer T) => any ? T : never;
|
|
4
|
+
type Messages = {
|
|
5
|
+
[named: string]: (...args: Variable[]) => string;
|
|
6
|
+
};
|
|
7
|
+
type Output<M extends Messages> = {
|
|
8
|
+
readonly [P in keyof M]: (...args: Variables<M[P]>) => Issue;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
declare class Issue extends Error {
|
|
12
|
+
stack: string;
|
|
13
|
+
warn(): void;
|
|
14
|
+
}
|
|
15
|
+
declare function issues<M extends Issue.Messages>(register: M): Issue.Output<M>;
|
|
16
|
+
|
|
17
|
+
declare const LOCAL = "__local";
|
|
18
|
+
declare const STATE = "__state";
|
|
19
|
+
declare const UPDATE = "__update";
|
|
20
|
+
declare const CONTROL = "__control";
|
|
5
21
|
declare const Debug: {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
22
|
+
/** Use to access Model's local Subscriber (if exists). */
|
|
23
|
+
LOCAL: "__local";
|
|
24
|
+
/** Use to access snapshot of Model's current state. */
|
|
25
|
+
STATE: "__state";
|
|
26
|
+
/**
|
|
27
|
+
* Use to access snapshot of Model's latest update.
|
|
28
|
+
*
|
|
29
|
+
* Note: If used within a Subscriber, update will be narrowed to the specific keys
|
|
30
|
+
* which triggered a refresh (if one did).
|
|
31
|
+
*/
|
|
32
|
+
UPDATE: "__update";
|
|
33
|
+
/** Use to access a Model's controller. */
|
|
34
|
+
CONTROL: "__control";
|
|
10
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* Generic will declare debug properties on a given Model.
|
|
38
|
+
*
|
|
39
|
+
* These properties always exist at runtime, however are hidden unless you cast your Model as `Debug<T>`.
|
|
40
|
+
*/
|
|
11
41
|
type Debug<T extends Model> = T & {
|
|
12
42
|
/** Controller for this instance. */
|
|
13
43
|
[CONTROL]?: Control<T>;
|
|
@@ -28,24 +58,19 @@ type Callback = () => void;
|
|
|
28
58
|
type Class = new (...args: any[]) => any;
|
|
29
59
|
type InstanceOf<T> = T extends { prototype: infer U } ? U : never;
|
|
30
60
|
|
|
61
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
62
|
+
|
|
31
63
|
/** Type may not be undefined - instead will be null. */
|
|
32
64
|
type NoVoid<T> = T extends undefined ? null : T;
|
|
33
65
|
|
|
34
|
-
type OptionalValues<T extends {}> = {
|
|
35
|
-
[P in Model.Key<T>]: T[P] | undefined;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
type NonOptionalValues<T extends {}> = {
|
|
39
|
-
[P in Model.Key<T>]: Exclude<T[P], undefined>;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
66
|
declare namespace Model {
|
|
43
67
|
export { Control };
|
|
44
68
|
export { Subscriber };
|
|
45
69
|
/** Including but not limited to T. */
|
|
46
70
|
type Extends<T> = T | (string & Record<never, never>);
|
|
47
71
|
/** Any typeof Model, using class constructor as the reference. */
|
|
48
|
-
export type Type<T extends Model = Model> =
|
|
72
|
+
export type Type<T extends Model = Model> = abstract new () => T;
|
|
73
|
+
export type Class<T extends Model> = (abstract new () => T) & typeof Model;
|
|
49
74
|
/** A typeof Model, specifically one which may be created without arguments. */
|
|
50
75
|
export type New<T extends Model = Model> = (new () => T) & typeof Model;
|
|
51
76
|
export type Effect<T> = (this: T, argument: T) => Callback | Promise<any> | void;
|
|
@@ -95,7 +120,7 @@ declare namespace Model {
|
|
|
95
120
|
[P in Key<T>]: Value<T[P]>;
|
|
96
121
|
};
|
|
97
122
|
export type FindFunction = <T extends Model>(type: Model.Type<T>, relativeTo: Model, required: boolean) => (_refresh: (x: T) => void) => T | undefined;
|
|
98
|
-
export type
|
|
123
|
+
export type GetCallback<T extends Model, R> = (this: T, model: T, update: ForceUpdate) => R;
|
|
99
124
|
type ForceUpdate = {
|
|
100
125
|
/** Force an update in current component. */
|
|
101
126
|
(): void;
|
|
@@ -119,7 +144,9 @@ declare class Model {
|
|
|
119
144
|
* Use to obtain full reference from a destructure.
|
|
120
145
|
*/
|
|
121
146
|
is: this;
|
|
122
|
-
|
|
147
|
+
/** Unique identifier for Model instance. */
|
|
148
|
+
id: string;
|
|
149
|
+
constructor(id?: string);
|
|
123
150
|
on<P extends Model.Event<this>>(keys?: P | Iterable<P>, timeout?: number): Promise<P[]>;
|
|
124
151
|
on<P extends Model.Event<this>>(keys: P | Iterable<P>, listener: (this: this, keys: Model.Event<this>[]) => void, once?: boolean): Callback;
|
|
125
152
|
on(effect: Model.Effect<this>): Callback;
|
|
@@ -130,15 +157,15 @@ declare class Model {
|
|
|
130
157
|
on(current: true): Promise<Model.Event<this>[]>;
|
|
131
158
|
on(current: null): Promise<null>;
|
|
132
159
|
get(): Model.Export<this>;
|
|
133
|
-
get<P extends Model.Key<this>>(
|
|
134
|
-
get<P extends Model.Key<this>>(property: P, timeout: number): Promise<this[P]>;
|
|
135
|
-
get<P extends Model.Key<this>>(property: P, onChange: true): Promise<this[P]>;
|
|
136
|
-
get<P extends Model.Key<this>>(property: P, onChange: boolean): this[P] | Promise<this[P]>;
|
|
137
|
-
get<P extends Model.Key<this>>(property: P, listener: (this: this, value: this[P], key: P[]) => void): Callback;
|
|
160
|
+
get<P extends Model.Key<this>>(select: P): this[P];
|
|
138
161
|
get<P extends Model.Key<this>>(select: Iterable<P>): Model.Get<this, P>;
|
|
162
|
+
get<P extends Model.Key<this>>(select: P, timeout: number): Promise<this[P]>;
|
|
139
163
|
get<P extends Model.Key<this>>(select: Iterable<P>, timeout: number): Promise<Model.Get<this, P>>;
|
|
164
|
+
get<P extends Model.Key<this>>(select: P, onChange: true): Promise<this[P]>;
|
|
140
165
|
get<P extends Model.Key<this>>(select: Iterable<P>, onChange: true): Promise<Model.Get<this, P>>;
|
|
141
|
-
get<P extends Model.Key<this>>(select:
|
|
166
|
+
get<P extends Model.Key<this>>(select: P, onChange: boolean): MaybePromise<this[P]>;
|
|
167
|
+
get<P extends Model.Key<this>>(select: Iterable<P>, onChange: boolean): MaybePromise<Model.Get<this, P>>;
|
|
168
|
+
get<P extends Model.Key<this>>(select: P, listener: (this: this, value: this[P], key: P[]) => void): Callback;
|
|
142
169
|
get<P extends Model.Key<this>>(select: Iterable<P>, listener: (this: this, value: Model.Get<this, P>, key: P[]) => void): Callback;
|
|
143
170
|
set(key: Model.Event<this>): PromiseLike<readonly Model.Event<this>[]>;
|
|
144
171
|
set<K extends Model.Event<this>>(key: Model.Event<this>, value: Model.ValueOf<this, K>): PromiseLike<readonly Model.Event<this>[]>;
|
|
@@ -154,29 +181,22 @@ declare class Model {
|
|
|
154
181
|
* @param args - arguments sent to constructor
|
|
155
182
|
*/
|
|
156
183
|
static new<T extends Class>(this: T, ...args: ConstructorParameters<T>): InstanceOf<T>;
|
|
184
|
+
static find<T extends Model>(this: Model.Type<T>, required?: boolean): T;
|
|
185
|
+
static find<T extends Model>(this: Model.Type<T>, required: false): T | undefined;
|
|
186
|
+
static get<T extends Model>(this: Model.Type<T>): T;
|
|
187
|
+
static get<T extends Model>(this: Model.Type<T>, passive: true): T;
|
|
188
|
+
static get<T extends Model>(this: Model.Type<T>, required: false): T | undefined;
|
|
189
|
+
static get<T extends Model, R extends []>(this: Model.Type<T>, compute: Model.GetCallback<T, R | (() => R)>, expect?: boolean): R;
|
|
190
|
+
static get<T extends Model, R extends []>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R> | (() => R) | null>, expect?: boolean): R | null;
|
|
191
|
+
static get<T extends Model, R extends []>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R> | R>, expect: true): Exclude<R, undefined>;
|
|
192
|
+
static get<T extends Model, R>(this: Model.Type<T>, init: Model.GetCallback<T, () => R>): NoVoid<R>;
|
|
193
|
+
static get<T extends Model, R>(this: Model.Type<T>, init: Model.GetCallback<T, (() => R) | null>): NoVoid<R> | null;
|
|
194
|
+
static get<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R> | R>, expect: true): Exclude<R, undefined>;
|
|
195
|
+
static get<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, Promise<R>>, expect?: boolean): NoVoid<R> | null;
|
|
196
|
+
static get<T extends Model, R>(this: Model.Type<T>, compute: Model.GetCallback<T, R>, expect?: boolean): NoVoid<R>;
|
|
157
197
|
static use<I extends Model>(this: Model.Type<I>, watch: Model.Key<I>[], callback?: (instance: I) => void): I;
|
|
158
198
|
static use<I extends Model>(this: Model.Type<I>, callback?: (instance: I) => void): I;
|
|
159
199
|
static use<I extends Model>(this: Model.Type<I>, apply: Model.Compat<I>, keys?: Model.Event<I>[]): I;
|
|
160
|
-
static get<T extends Model>(this: Model.Type<T>, required?: boolean): T;
|
|
161
|
-
static get<T extends Model>(this: Model.Type<T>, required: false): T | undefined;
|
|
162
|
-
static tap<T extends Model>(this: Model.Type<T>): T;
|
|
163
|
-
static tap<T extends Model, R extends readonly unknown[] | []>(this: Model.Type<T>, compute: Model.TapCallback<T, R | (() => R)>, expect?: boolean): R;
|
|
164
|
-
static tap<T extends Model, R extends readonly unknown[] | []>(this: Model.Type<T>, compute: Model.TapCallback<T, Promise<R> | (() => R) | null>, expect?: boolean): R | null;
|
|
165
|
-
static tap<T extends Model, R extends readonly unknown[] | []>(this: Model.Type<T>, compute: Model.TapCallback<T, Promise<R> | R>, expect: true): Exclude<R, undefined>;
|
|
166
|
-
static tap<T extends Model, R>(this: Model.Type<T>, init: Model.TapCallback<T, () => R>): NoVoid<R>;
|
|
167
|
-
static tap<T extends Model, R>(this: Model.Type<T>, init: Model.TapCallback<T, (() => R) | null>): NoVoid<R> | null;
|
|
168
|
-
static tap<T extends Model, R>(this: Model.Type<T>, compute: Model.TapCallback<T, Promise<R> | R>, expect: true): Exclude<R, undefined>;
|
|
169
|
-
static tap<T extends Model, R>(this: Model.Type<T>, compute: Model.TapCallback<T, Promise<R>>, expect?: boolean): NoVoid<R> | null;
|
|
170
|
-
static tap<T extends Model, R>(this: Model.Type<T>, compute: Model.TapCallback<T, R>, expect?: boolean): NoVoid<R>;
|
|
171
|
-
static tap<T extends Model>(this: Model.Type<T>, expect: true): NonOptionalValues<T>;
|
|
172
|
-
static tap<T extends Model>(this: Model.Type<T>, expect?: boolean): OptionalValues<T>;
|
|
173
|
-
protected static meta<T extends Class>(this: T): T;
|
|
174
|
-
protected static meta<T extends Class>(this: T, expect: true): NonOptionalValues<T>;
|
|
175
|
-
protected static meta<T extends Class>(this: T, expect?: boolean): OptionalValues<T>;
|
|
176
|
-
protected static meta<T, M extends Class>(this: M, from: (this: M, state: M) => Promise<T>, expect: true): Exclude<T, undefined>;
|
|
177
|
-
protected static meta<T, M extends Class>(this: M, from: (this: M, state: M) => Promise<T>, expect?: boolean): T;
|
|
178
|
-
protected static meta<T, M extends Class>(this: M, from: (this: M, state: M) => T, expect: true): Exclude<T, undefined>;
|
|
179
|
-
protected static meta<T, M extends Class>(this: M, from: (this: M, state: M) => T, expect?: boolean): T;
|
|
180
200
|
/**
|
|
181
201
|
* Static equivalent of `x instanceof this`.
|
|
182
202
|
*
|
|
@@ -272,7 +292,7 @@ declare namespace control {
|
|
|
272
292
|
declare function control<T extends Model>(subject: T): Control<T>;
|
|
273
293
|
declare function control<T extends Model>(subject: T, cb: control.OnReady<T>): Callback;
|
|
274
294
|
|
|
275
|
-
declare function getParent<T extends Model>(from: Model, type?: Model.
|
|
295
|
+
declare function getParent<T extends Model>(from: Model, type?: Model.Class<T>): T;
|
|
276
296
|
|
|
277
297
|
type Async<T = any> = (...args: any[]) => Promise<T>;
|
|
278
298
|
/**
|
|
@@ -295,7 +315,7 @@ declare function run<S>(action: Async<S>): typeof action & {
|
|
|
295
315
|
declare namespace get {
|
|
296
316
|
type Function<T, S = any> = (this: S, on: S) => T;
|
|
297
317
|
type Factory<R, T> = (this: T, property: string, on: T) => Function<R, T>;
|
|
298
|
-
type FindFunction<T extends Model = Model> = (type:
|
|
318
|
+
type FindFunction<T extends Model = Model> = (type: Model.Class<T>, relativeTo: Model, required: boolean) => Source<T>;
|
|
299
319
|
type Source<T extends Model = Model> = (callback: (x: T) => void) => void;
|
|
300
320
|
/** Assign fetch algorithm for get instruction. */
|
|
301
321
|
let using: (fn: FindFunction) => typeof get;
|
|
@@ -479,4 +499,4 @@ declare const Internal: {
|
|
|
479
499
|
getParent: typeof getParent;
|
|
480
500
|
};
|
|
481
501
|
|
|
482
|
-
export { Control, Debug, Internal, Model, Register, Subscriber, add, Model as default, get, ref, run, set, use };
|
|
502
|
+
export { Control, Debug, Internal, Model, Register, Subscriber, add, Model as default, get, issues, ref, run, set, use };
|
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
1
|
+
const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
2
|
+
/** Random alphanumberic of length 6; will always start with a letter. */
|
|
3
|
+
function random() {
|
|
4
|
+
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
5
|
+
}
|
|
2
6
|
|
|
3
7
|
class Issue extends Error {
|
|
4
8
|
constructor() {
|
|
@@ -136,20 +140,17 @@ function createEffect(model, callback, keys) {
|
|
|
136
140
|
return control(model, controller => {
|
|
137
141
|
let unSet;
|
|
138
142
|
let busy = false;
|
|
139
|
-
function effect(value) {
|
|
140
|
-
if (typeof unSet == "function")
|
|
141
|
-
unSet();
|
|
142
|
-
unSet = callback.call(this, value);
|
|
143
|
-
if (unSet instanceof Promise)
|
|
144
|
-
unSet = undefined;
|
|
145
|
-
if (unSet && typeof unSet !== "function")
|
|
146
|
-
throw Oops$7.BadCallback();
|
|
147
|
-
}
|
|
148
143
|
function invoke() {
|
|
149
144
|
if (busy)
|
|
150
145
|
return;
|
|
151
146
|
const output = mayRetry(() => {
|
|
152
|
-
|
|
147
|
+
if (typeof unSet == "function")
|
|
148
|
+
unSet();
|
|
149
|
+
unSet = callback.call(model, model);
|
|
150
|
+
if (unSet instanceof Promise)
|
|
151
|
+
unSet = undefined;
|
|
152
|
+
if (unSet && typeof unSet !== "function")
|
|
153
|
+
throw Oops$7.BadCallback();
|
|
153
154
|
});
|
|
154
155
|
if (output instanceof Promise) {
|
|
155
156
|
output.finally(() => busy = false);
|
|
@@ -281,9 +282,10 @@ const Oops$5 = issues({
|
|
|
281
282
|
NoAdapter: (method) => `Can't call Model.${method} without an adapter.`
|
|
282
283
|
});
|
|
283
284
|
class Model {
|
|
284
|
-
constructor() {
|
|
285
|
+
constructor(id) {
|
|
285
286
|
new Control(this);
|
|
286
287
|
defineProperty(this, "is", { value: this });
|
|
288
|
+
defineProperty(this, "id", { value: id || random() });
|
|
287
289
|
}
|
|
288
290
|
on(arg1, arg2, arg3) {
|
|
289
291
|
if (typeof arg1 == "function")
|
|
@@ -313,14 +315,7 @@ class Model {
|
|
|
313
315
|
set(arg1, arg2) {
|
|
314
316
|
const controller = control(this);
|
|
315
317
|
const { state } = controller;
|
|
316
|
-
if (typeof arg1 == "
|
|
317
|
-
for (const key in arg1) {
|
|
318
|
-
if (arg2 === true || (arg2 ? arg2.includes(key) : state.has(key))) {
|
|
319
|
-
state.set(key, arg1[key]);
|
|
320
|
-
controller.update(key);
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
else if (typeof arg1 == "string") {
|
|
318
|
+
if (typeof arg1 == "string") {
|
|
324
319
|
controller.update(arg1);
|
|
325
320
|
if (1 in arguments) {
|
|
326
321
|
if (state.has(arg1))
|
|
@@ -332,6 +327,12 @@ class Model {
|
|
|
332
327
|
}
|
|
333
328
|
}
|
|
334
329
|
}
|
|
330
|
+
else if (typeof arg1 == "object")
|
|
331
|
+
for (const key in arg1)
|
|
332
|
+
if (arg2 === true || (arg2 ? arg2.includes(key) : state.has(key))) {
|
|
333
|
+
state.set(key, arg1[key]);
|
|
334
|
+
controller.update(key);
|
|
335
|
+
}
|
|
335
336
|
return {
|
|
336
337
|
then: (callback) => {
|
|
337
338
|
if (!callback)
|
|
@@ -356,17 +357,14 @@ class Model {
|
|
|
356
357
|
control(instance);
|
|
357
358
|
return instance;
|
|
358
359
|
}
|
|
359
|
-
static
|
|
360
|
-
throw Oops$5.NoAdapter("
|
|
360
|
+
static find() {
|
|
361
|
+
throw Oops$5.NoAdapter("find");
|
|
361
362
|
}
|
|
362
363
|
static get() {
|
|
363
364
|
throw Oops$5.NoAdapter("get");
|
|
364
365
|
}
|
|
365
|
-
static
|
|
366
|
-
throw Oops$5.NoAdapter("
|
|
367
|
-
}
|
|
368
|
-
static meta() {
|
|
369
|
-
throw Oops$5.NoAdapter("meta");
|
|
366
|
+
static use() {
|
|
367
|
+
throw Oops$5.NoAdapter("use");
|
|
370
368
|
}
|
|
371
369
|
/**
|
|
372
370
|
* Static equivalent of `x instanceof this`.
|
|
@@ -379,8 +377,14 @@ class Model {
|
|
|
379
377
|
}
|
|
380
378
|
}
|
|
381
379
|
defineProperty(Model.prototype, "toString", {
|
|
380
|
+
configurable: true,
|
|
382
381
|
value() {
|
|
383
|
-
return this.constructor.name
|
|
382
|
+
return `${this.constructor.name}-${this.id}`;
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
defineProperty(Model, "toString", {
|
|
386
|
+
value() {
|
|
387
|
+
return this.name;
|
|
384
388
|
}
|
|
385
389
|
});
|
|
386
390
|
|
|
@@ -418,7 +422,7 @@ function add(instruction, label) {
|
|
|
418
422
|
|
|
419
423
|
const Oops$4 = issues({
|
|
420
424
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
421
|
-
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"}
|
|
425
|
+
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} ${parent}.${property}.`,
|
|
422
426
|
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
423
427
|
});
|
|
424
428
|
function get(arg0, arg1) {
|
|
@@ -435,8 +439,8 @@ function get(arg0, arg1) {
|
|
|
435
439
|
else if (typeof arg0 == "function")
|
|
436
440
|
arg1 = arg0.call(subject, key, subject);
|
|
437
441
|
return typeof arg1 == "function"
|
|
438
|
-
?
|
|
439
|
-
:
|
|
442
|
+
? computed(this, key, source, arg1)
|
|
443
|
+
: recursive(this, key, source, arg1);
|
|
440
444
|
});
|
|
441
445
|
}
|
|
442
446
|
function getParentForGetInstruction(type, relativeTo, required) {
|
|
@@ -445,54 +449,26 @@ function getParentForGetInstruction(type, relativeTo, required) {
|
|
|
445
449
|
if (item)
|
|
446
450
|
callback(item);
|
|
447
451
|
else if (required)
|
|
448
|
-
throw Oops$4.Required(type
|
|
452
|
+
throw Oops$4.Required(type, relativeTo.constructor);
|
|
449
453
|
};
|
|
450
454
|
}
|
|
451
|
-
function
|
|
452
|
-
const
|
|
453
|
-
const { state } = parent;
|
|
455
|
+
function recursive(parent, key, source, required) {
|
|
456
|
+
const getter = getRecursive(key, parent);
|
|
454
457
|
let waiting;
|
|
455
458
|
source((got) => {
|
|
456
|
-
state.set(key, got);
|
|
459
|
+
parent.state.set(key, got);
|
|
457
460
|
if (waiting)
|
|
458
461
|
parent.update(key);
|
|
459
462
|
});
|
|
460
463
|
waiting = true;
|
|
461
|
-
function create(local) {
|
|
462
|
-
let reset;
|
|
463
|
-
local.follow(key, init);
|
|
464
|
-
init();
|
|
465
|
-
function init() {
|
|
466
|
-
if (reset)
|
|
467
|
-
reset();
|
|
468
|
-
const value = state.get(key);
|
|
469
|
-
if (value && controller(value)) {
|
|
470
|
-
const child = new Subscriber(value, local.onUpdate);
|
|
471
|
-
if (local.active)
|
|
472
|
-
child.commit();
|
|
473
|
-
local.dependant.add(child);
|
|
474
|
-
context.set(local, child.proxy);
|
|
475
|
-
reset = () => {
|
|
476
|
-
child.release();
|
|
477
|
-
local.dependant.delete(child);
|
|
478
|
-
context.set(local, undefined);
|
|
479
|
-
reset = undefined;
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
464
|
return (local) => {
|
|
485
|
-
const value = state.get(key);
|
|
465
|
+
const value = parent.state.get(key);
|
|
486
466
|
if (!value && required !== false)
|
|
487
467
|
parent.waitFor(key);
|
|
488
|
-
|
|
489
|
-
return value;
|
|
490
|
-
if (!context.has(local))
|
|
491
|
-
create(local);
|
|
492
|
-
return context.get(local);
|
|
468
|
+
return local ? getter(local) : value;
|
|
493
469
|
};
|
|
494
470
|
}
|
|
495
|
-
function
|
|
471
|
+
function computed(parent, key, source, setter) {
|
|
496
472
|
const { state } = parent;
|
|
497
473
|
let local;
|
|
498
474
|
let active;
|
|
@@ -553,7 +529,7 @@ function getComputed(key, parent, source, setter) {
|
|
|
553
529
|
const INFO = new WeakMap();
|
|
554
530
|
const KEYS = new WeakMap();
|
|
555
531
|
const ORDER = new WeakMap();
|
|
556
|
-
function
|
|
532
|
+
function flushComputed(control) {
|
|
557
533
|
const pending = KEYS.get(control);
|
|
558
534
|
if (!pending || !pending.size)
|
|
559
535
|
return;
|
|
@@ -647,7 +623,7 @@ class Control {
|
|
|
647
623
|
return;
|
|
648
624
|
else if (!frame.size)
|
|
649
625
|
setTimeout(() => {
|
|
650
|
-
|
|
626
|
+
flushComputed(this);
|
|
651
627
|
const keys = this.latest = Array.from(frame);
|
|
652
628
|
setTimeout(() => this.latest = undefined, 0);
|
|
653
629
|
frame.clear();
|
|
@@ -706,21 +682,19 @@ function control(subject, cb) {
|
|
|
706
682
|
|
|
707
683
|
const Parent = new WeakMap();
|
|
708
684
|
const Oops$3 = issues({
|
|
709
|
-
BadAssignment: (parent, expected, got) =>
|
|
685
|
+
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
710
686
|
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
711
687
|
});
|
|
712
688
|
function getParent(from, type) {
|
|
713
689
|
const value = Parent.get(from);
|
|
714
690
|
if (value && type && !(value instanceof type))
|
|
715
|
-
throw Oops$3.Unexpected(type
|
|
691
|
+
throw Oops$3.Unexpected(type, from, value);
|
|
716
692
|
return value;
|
|
717
693
|
}
|
|
718
694
|
function getRecursive(key, from) {
|
|
719
695
|
const context = new WeakMap();
|
|
720
696
|
const { state } = from;
|
|
721
697
|
return (local) => {
|
|
722
|
-
if (!local)
|
|
723
|
-
return state.get(key);
|
|
724
698
|
if (!context.has(local)) {
|
|
725
699
|
let reset;
|
|
726
700
|
const init = () => {
|
|
@@ -754,8 +728,9 @@ function setRecursive(controller, key, initial) {
|
|
|
754
728
|
const onUpdate = (next) => {
|
|
755
729
|
state.set(key, next);
|
|
756
730
|
if (!(next instanceof Type))
|
|
757
|
-
throw Oops$3.BadAssignment(`${subject}.${key}`, Type
|
|
758
|
-
|
|
731
|
+
throw Oops$3.BadAssignment(`${subject}.${key}`, Type, String(next));
|
|
732
|
+
const getter = getRecursive(key, controller);
|
|
733
|
+
get = (local) => local ? getter(local) : state.get(key);
|
|
759
734
|
Parent.set(next, subject);
|
|
760
735
|
control(next);
|
|
761
736
|
return true;
|
|
@@ -1107,7 +1082,8 @@ function use(input, argument) {
|
|
|
1107
1082
|
const onUpdate = (next) => {
|
|
1108
1083
|
state.set(key, next);
|
|
1109
1084
|
if (next) {
|
|
1110
|
-
|
|
1085
|
+
const getter = getRecursive(key, this);
|
|
1086
|
+
get = (local) => local ? getter(local) : state.get(key);
|
|
1111
1087
|
Parent.set(next, subject);
|
|
1112
1088
|
control(next);
|
|
1113
1089
|
}
|
|
@@ -1163,10 +1139,10 @@ function use(input, argument) {
|
|
|
1163
1139
|
});
|
|
1164
1140
|
}
|
|
1165
1141
|
|
|
1166
|
-
const LOCAL = "
|
|
1167
|
-
const STATE = "
|
|
1168
|
-
const UPDATE = "
|
|
1169
|
-
const CONTROL = "
|
|
1142
|
+
const LOCAL = "__local";
|
|
1143
|
+
const STATE = "__state";
|
|
1144
|
+
const UPDATE = "__update";
|
|
1145
|
+
const CONTROL = "__control";
|
|
1170
1146
|
defineProperties(Model.prototype, {
|
|
1171
1147
|
[CONTROL]: {
|
|
1172
1148
|
get() {
|
|
@@ -1262,4 +1238,4 @@ const Internal = {
|
|
|
1262
1238
|
getParent
|
|
1263
1239
|
};
|
|
1264
1240
|
|
|
1265
|
-
export { Control, Debug, Internal, Model, Register, Subscriber, add, Model as default, get, ref, run, set, use };
|
|
1241
|
+
export { Control, Debug, Internal, Model, Register, Subscriber, add, Model as default, get, issues, ref, run, set, use };
|
package/lib/index.js
CHANGED
|
@@ -2,7 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
5
|
+
const { assign, create, defineProperties, defineProperty, entries, getPrototypeOf, getOwnPropertyDescriptor, getOwnPropertySymbols, values } = Object;
|
|
6
|
+
/** Random alphanumberic of length 6; will always start with a letter. */
|
|
7
|
+
function random() {
|
|
8
|
+
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
9
|
+
}
|
|
6
10
|
|
|
7
11
|
class Issue extends Error {
|
|
8
12
|
constructor() {
|
|
@@ -140,20 +144,17 @@ function createEffect(model, callback, keys) {
|
|
|
140
144
|
return control(model, controller => {
|
|
141
145
|
let unSet;
|
|
142
146
|
let busy = false;
|
|
143
|
-
function effect(value) {
|
|
144
|
-
if (typeof unSet == "function")
|
|
145
|
-
unSet();
|
|
146
|
-
unSet = callback.call(this, value);
|
|
147
|
-
if (unSet instanceof Promise)
|
|
148
|
-
unSet = undefined;
|
|
149
|
-
if (unSet && typeof unSet !== "function")
|
|
150
|
-
throw Oops$7.BadCallback();
|
|
151
|
-
}
|
|
152
147
|
function invoke() {
|
|
153
148
|
if (busy)
|
|
154
149
|
return;
|
|
155
150
|
const output = mayRetry(() => {
|
|
156
|
-
|
|
151
|
+
if (typeof unSet == "function")
|
|
152
|
+
unSet();
|
|
153
|
+
unSet = callback.call(model, model);
|
|
154
|
+
if (unSet instanceof Promise)
|
|
155
|
+
unSet = undefined;
|
|
156
|
+
if (unSet && typeof unSet !== "function")
|
|
157
|
+
throw Oops$7.BadCallback();
|
|
157
158
|
});
|
|
158
159
|
if (output instanceof Promise) {
|
|
159
160
|
output.finally(() => busy = false);
|
|
@@ -285,9 +286,10 @@ const Oops$5 = issues({
|
|
|
285
286
|
NoAdapter: (method) => `Can't call Model.${method} without an adapter.`
|
|
286
287
|
});
|
|
287
288
|
class Model {
|
|
288
|
-
constructor() {
|
|
289
|
+
constructor(id) {
|
|
289
290
|
new Control(this);
|
|
290
291
|
defineProperty(this, "is", { value: this });
|
|
292
|
+
defineProperty(this, "id", { value: id || random() });
|
|
291
293
|
}
|
|
292
294
|
on(arg1, arg2, arg3) {
|
|
293
295
|
if (typeof arg1 == "function")
|
|
@@ -317,14 +319,7 @@ class Model {
|
|
|
317
319
|
set(arg1, arg2) {
|
|
318
320
|
const controller = control(this);
|
|
319
321
|
const { state } = controller;
|
|
320
|
-
if (typeof arg1 == "
|
|
321
|
-
for (const key in arg1) {
|
|
322
|
-
if (arg2 === true || (arg2 ? arg2.includes(key) : state.has(key))) {
|
|
323
|
-
state.set(key, arg1[key]);
|
|
324
|
-
controller.update(key);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
else if (typeof arg1 == "string") {
|
|
322
|
+
if (typeof arg1 == "string") {
|
|
328
323
|
controller.update(arg1);
|
|
329
324
|
if (1 in arguments) {
|
|
330
325
|
if (state.has(arg1))
|
|
@@ -336,6 +331,12 @@ class Model {
|
|
|
336
331
|
}
|
|
337
332
|
}
|
|
338
333
|
}
|
|
334
|
+
else if (typeof arg1 == "object")
|
|
335
|
+
for (const key in arg1)
|
|
336
|
+
if (arg2 === true || (arg2 ? arg2.includes(key) : state.has(key))) {
|
|
337
|
+
state.set(key, arg1[key]);
|
|
338
|
+
controller.update(key);
|
|
339
|
+
}
|
|
339
340
|
return {
|
|
340
341
|
then: (callback) => {
|
|
341
342
|
if (!callback)
|
|
@@ -360,17 +361,14 @@ class Model {
|
|
|
360
361
|
control(instance);
|
|
361
362
|
return instance;
|
|
362
363
|
}
|
|
363
|
-
static
|
|
364
|
-
throw Oops$5.NoAdapter("
|
|
364
|
+
static find() {
|
|
365
|
+
throw Oops$5.NoAdapter("find");
|
|
365
366
|
}
|
|
366
367
|
static get() {
|
|
367
368
|
throw Oops$5.NoAdapter("get");
|
|
368
369
|
}
|
|
369
|
-
static
|
|
370
|
-
throw Oops$5.NoAdapter("
|
|
371
|
-
}
|
|
372
|
-
static meta() {
|
|
373
|
-
throw Oops$5.NoAdapter("meta");
|
|
370
|
+
static use() {
|
|
371
|
+
throw Oops$5.NoAdapter("use");
|
|
374
372
|
}
|
|
375
373
|
/**
|
|
376
374
|
* Static equivalent of `x instanceof this`.
|
|
@@ -383,8 +381,14 @@ class Model {
|
|
|
383
381
|
}
|
|
384
382
|
}
|
|
385
383
|
defineProperty(Model.prototype, "toString", {
|
|
384
|
+
configurable: true,
|
|
386
385
|
value() {
|
|
387
|
-
return this.constructor.name
|
|
386
|
+
return `${this.constructor.name}-${this.id}`;
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
defineProperty(Model, "toString", {
|
|
390
|
+
value() {
|
|
391
|
+
return this.name;
|
|
388
392
|
}
|
|
389
393
|
});
|
|
390
394
|
|
|
@@ -422,7 +426,7 @@ function add(instruction, label) {
|
|
|
422
426
|
|
|
423
427
|
const Oops$4 = issues({
|
|
424
428
|
PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or get) as computed source for ${model}.${property}. This is not allowed.`,
|
|
425
|
-
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"}
|
|
429
|
+
Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} ${parent}.${property}.`,
|
|
426
430
|
Required: (expects, child) => `New ${child} created standalone but requires parent of type ${expects}. Did you remember to create via use(${child})?`,
|
|
427
431
|
});
|
|
428
432
|
function get(arg0, arg1) {
|
|
@@ -439,8 +443,8 @@ function get(arg0, arg1) {
|
|
|
439
443
|
else if (typeof arg0 == "function")
|
|
440
444
|
arg1 = arg0.call(subject, key, subject);
|
|
441
445
|
return typeof arg1 == "function"
|
|
442
|
-
?
|
|
443
|
-
:
|
|
446
|
+
? computed(this, key, source, arg1)
|
|
447
|
+
: recursive(this, key, source, arg1);
|
|
444
448
|
});
|
|
445
449
|
}
|
|
446
450
|
function getParentForGetInstruction(type, relativeTo, required) {
|
|
@@ -449,54 +453,26 @@ function getParentForGetInstruction(type, relativeTo, required) {
|
|
|
449
453
|
if (item)
|
|
450
454
|
callback(item);
|
|
451
455
|
else if (required)
|
|
452
|
-
throw Oops$4.Required(type
|
|
456
|
+
throw Oops$4.Required(type, relativeTo.constructor);
|
|
453
457
|
};
|
|
454
458
|
}
|
|
455
|
-
function
|
|
456
|
-
const
|
|
457
|
-
const { state } = parent;
|
|
459
|
+
function recursive(parent, key, source, required) {
|
|
460
|
+
const getter = getRecursive(key, parent);
|
|
458
461
|
let waiting;
|
|
459
462
|
source((got) => {
|
|
460
|
-
state.set(key, got);
|
|
463
|
+
parent.state.set(key, got);
|
|
461
464
|
if (waiting)
|
|
462
465
|
parent.update(key);
|
|
463
466
|
});
|
|
464
467
|
waiting = true;
|
|
465
|
-
function create(local) {
|
|
466
|
-
let reset;
|
|
467
|
-
local.follow(key, init);
|
|
468
|
-
init();
|
|
469
|
-
function init() {
|
|
470
|
-
if (reset)
|
|
471
|
-
reset();
|
|
472
|
-
const value = state.get(key);
|
|
473
|
-
if (value && controller(value)) {
|
|
474
|
-
const child = new Subscriber(value, local.onUpdate);
|
|
475
|
-
if (local.active)
|
|
476
|
-
child.commit();
|
|
477
|
-
local.dependant.add(child);
|
|
478
|
-
context.set(local, child.proxy);
|
|
479
|
-
reset = () => {
|
|
480
|
-
child.release();
|
|
481
|
-
local.dependant.delete(child);
|
|
482
|
-
context.set(local, undefined);
|
|
483
|
-
reset = undefined;
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
468
|
return (local) => {
|
|
489
|
-
const value = state.get(key);
|
|
469
|
+
const value = parent.state.get(key);
|
|
490
470
|
if (!value && required !== false)
|
|
491
471
|
parent.waitFor(key);
|
|
492
|
-
|
|
493
|
-
return value;
|
|
494
|
-
if (!context.has(local))
|
|
495
|
-
create(local);
|
|
496
|
-
return context.get(local);
|
|
472
|
+
return local ? getter(local) : value;
|
|
497
473
|
};
|
|
498
474
|
}
|
|
499
|
-
function
|
|
475
|
+
function computed(parent, key, source, setter) {
|
|
500
476
|
const { state } = parent;
|
|
501
477
|
let local;
|
|
502
478
|
let active;
|
|
@@ -557,7 +533,7 @@ function getComputed(key, parent, source, setter) {
|
|
|
557
533
|
const INFO = new WeakMap();
|
|
558
534
|
const KEYS = new WeakMap();
|
|
559
535
|
const ORDER = new WeakMap();
|
|
560
|
-
function
|
|
536
|
+
function flushComputed(control) {
|
|
561
537
|
const pending = KEYS.get(control);
|
|
562
538
|
if (!pending || !pending.size)
|
|
563
539
|
return;
|
|
@@ -651,7 +627,7 @@ class Control {
|
|
|
651
627
|
return;
|
|
652
628
|
else if (!frame.size)
|
|
653
629
|
setTimeout(() => {
|
|
654
|
-
|
|
630
|
+
flushComputed(this);
|
|
655
631
|
const keys = this.latest = Array.from(frame);
|
|
656
632
|
setTimeout(() => this.latest = undefined, 0);
|
|
657
633
|
frame.clear();
|
|
@@ -710,21 +686,19 @@ function control(subject, cb) {
|
|
|
710
686
|
|
|
711
687
|
const Parent = new WeakMap();
|
|
712
688
|
const Oops$3 = issues({
|
|
713
|
-
BadAssignment: (parent, expected, got) =>
|
|
689
|
+
BadAssignment: (parent, expected, got) => `${parent} expected Model of type ${expected} but got ${got}.`,
|
|
714
690
|
Unexpected: (expects, child, got) => `New ${child} created as child of ${got}, but must be instanceof ${expects}.`,
|
|
715
691
|
});
|
|
716
692
|
function getParent(from, type) {
|
|
717
693
|
const value = Parent.get(from);
|
|
718
694
|
if (value && type && !(value instanceof type))
|
|
719
|
-
throw Oops$3.Unexpected(type
|
|
695
|
+
throw Oops$3.Unexpected(type, from, value);
|
|
720
696
|
return value;
|
|
721
697
|
}
|
|
722
698
|
function getRecursive(key, from) {
|
|
723
699
|
const context = new WeakMap();
|
|
724
700
|
const { state } = from;
|
|
725
701
|
return (local) => {
|
|
726
|
-
if (!local)
|
|
727
|
-
return state.get(key);
|
|
728
702
|
if (!context.has(local)) {
|
|
729
703
|
let reset;
|
|
730
704
|
const init = () => {
|
|
@@ -758,8 +732,9 @@ function setRecursive(controller, key, initial) {
|
|
|
758
732
|
const onUpdate = (next) => {
|
|
759
733
|
state.set(key, next);
|
|
760
734
|
if (!(next instanceof Type))
|
|
761
|
-
throw Oops$3.BadAssignment(`${subject}.${key}`, Type
|
|
762
|
-
|
|
735
|
+
throw Oops$3.BadAssignment(`${subject}.${key}`, Type, String(next));
|
|
736
|
+
const getter = getRecursive(key, controller);
|
|
737
|
+
get = (local) => local ? getter(local) : state.get(key);
|
|
763
738
|
Parent.set(next, subject);
|
|
764
739
|
control(next);
|
|
765
740
|
return true;
|
|
@@ -1111,7 +1086,8 @@ function use(input, argument) {
|
|
|
1111
1086
|
const onUpdate = (next) => {
|
|
1112
1087
|
state.set(key, next);
|
|
1113
1088
|
if (next) {
|
|
1114
|
-
|
|
1089
|
+
const getter = getRecursive(key, this);
|
|
1090
|
+
get = (local) => local ? getter(local) : state.get(key);
|
|
1115
1091
|
Parent.set(next, subject);
|
|
1116
1092
|
control(next);
|
|
1117
1093
|
}
|
|
@@ -1167,10 +1143,10 @@ function use(input, argument) {
|
|
|
1167
1143
|
});
|
|
1168
1144
|
}
|
|
1169
1145
|
|
|
1170
|
-
const LOCAL = "
|
|
1171
|
-
const STATE = "
|
|
1172
|
-
const UPDATE = "
|
|
1173
|
-
const CONTROL = "
|
|
1146
|
+
const LOCAL = "__local";
|
|
1147
|
+
const STATE = "__state";
|
|
1148
|
+
const UPDATE = "__update";
|
|
1149
|
+
const CONTROL = "__control";
|
|
1174
1150
|
defineProperties(Model.prototype, {
|
|
1175
1151
|
[CONTROL]: {
|
|
1176
1152
|
get() {
|
|
@@ -1275,6 +1251,7 @@ exports.Subscriber = Subscriber;
|
|
|
1275
1251
|
exports.add = add;
|
|
1276
1252
|
exports["default"] = Model;
|
|
1277
1253
|
exports.get = get;
|
|
1254
|
+
exports.issues = issues;
|
|
1278
1255
|
exports.ref = ref;
|
|
1279
1256
|
exports.run = run;
|
|
1280
1257
|
exports.set = set;
|
package/package.json
CHANGED