@expressive/mvc 0.35.2 → 0.35.5-alpha.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/dist/index.d.ts +36 -32
- package/dist/index.js +45 -37
- package/dist/index.mjs +45 -37
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -4,23 +4,23 @@ declare namespace Model {
|
|
|
4
4
|
/** A type of Model which may be created without constructor arguments. */
|
|
5
5
|
type New<T extends Model = Model> = (new () => T) & typeof Model;
|
|
6
6
|
/** Subset of `keyof T` which are not methods or defined by base Model U. **/
|
|
7
|
-
type
|
|
8
|
-
type
|
|
7
|
+
type Field<T> = Exclude<keyof T, keyof Model>;
|
|
8
|
+
type Key<T> = Field<T> | (string & {}) | number | symbol;
|
|
9
9
|
/** Actual value stored in state. */
|
|
10
|
-
type
|
|
11
|
-
type
|
|
12
|
-
type
|
|
10
|
+
type Actual<R> = R extends Ref<infer T> ? T : R extends Model ? State<R> : R;
|
|
11
|
+
type Value<T extends Model, K extends Key<T>> = K extends keyof T ? T[K] extends Ref<infer V> ? V : T[K] : unknown;
|
|
12
|
+
type OnUpdate<T extends Model, K extends Key<T>> = (this: T, value: Value<T, K>, key: K, thisArg: K) => void;
|
|
13
13
|
/**
|
|
14
14
|
* Values from current state of given controller.
|
|
15
15
|
* Differs from `Values` as values here will drill
|
|
16
16
|
* into "real" values held by exotics like ref.
|
|
17
17
|
*/
|
|
18
|
-
type
|
|
19
|
-
[P in
|
|
18
|
+
type State<T> = {
|
|
19
|
+
[P in Field<T>]: Actual<T[P]>;
|
|
20
20
|
};
|
|
21
21
|
/** Object comperable to data found in T. */
|
|
22
22
|
type Values<T> = {
|
|
23
|
-
[P in
|
|
23
|
+
[P in Field<T>]?: Actual<T[P]>;
|
|
24
24
|
};
|
|
25
25
|
/** Exotic value, where actual value is contained within. */
|
|
26
26
|
type Ref<T = any> = {
|
|
@@ -44,7 +44,7 @@ declare namespace Model {
|
|
|
44
44
|
* Property initializer, will run upon instance creation.
|
|
45
45
|
* Optional returned callback will run when once upon first access.
|
|
46
46
|
*/
|
|
47
|
-
type Instruction<T = any, M extends Model = any> = (this: M, key: Model.
|
|
47
|
+
type Instruction<T = any, M extends Model = any> = (this: M, key: Model.Field<M> & string, thisArg: M, state: Model.State<M>) => Instruction.Descriptor<T> | Instruction.Getter<T> | void;
|
|
48
48
|
}
|
|
49
49
|
interface Model {
|
|
50
50
|
/**
|
|
@@ -55,40 +55,44 @@ interface Model {
|
|
|
55
55
|
}
|
|
56
56
|
declare class Model {
|
|
57
57
|
constructor(id?: string | number);
|
|
58
|
-
/** Pull current values from state. Flattens all models and exotic values
|
|
59
|
-
get(): Model.
|
|
58
|
+
/** Pull current values from state. Flattens all models and exotic values recursively. */
|
|
59
|
+
get(): Model.State<this>;
|
|
60
60
|
/** Run a function which will run automatically when accessed values change. */
|
|
61
61
|
get(effect: Model.Effect<this>): () => void;
|
|
62
|
-
|
|
63
|
-
get
|
|
62
|
+
/** Check if model is expired. */
|
|
63
|
+
get(event: null): boolean;
|
|
64
|
+
/** Callback when model is to be destroyed. */
|
|
65
|
+
get(event: null, callback: () => void): () => void;
|
|
66
|
+
get<T extends Model.Key<this>>(key: T, required?: boolean): Model.Value<this, T>;
|
|
67
|
+
get<T extends Model.Key<this>>(key: T, callback: Model.OnUpdate<this, T>): () => void;
|
|
64
68
|
/**
|
|
65
69
|
* Get update in progress.
|
|
66
70
|
*
|
|
67
|
-
* @returns
|
|
71
|
+
* @returns Promise which resolves object with updated values. Is `undefined` if there is no update.
|
|
68
72
|
**/
|
|
69
73
|
set(): Promise<Model.Values<this>> | undefined;
|
|
70
74
|
/**
|
|
71
|
-
* Call a function
|
|
75
|
+
* Call a function when update occurs.
|
|
72
76
|
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* Returning the same function for one or more will ensure it is only called once.
|
|
77
|
+
* Given function is called for every assignment (which changes value) or explicit `set`.
|
|
78
|
+
* To run logic on final value only, callback itself may return a function.
|
|
79
|
+
* Returning the same function for one or more events will ensure a side-effect is called only when settled.
|
|
77
80
|
*
|
|
78
|
-
* @
|
|
81
|
+
* @param callback - Function to call when update occurs.
|
|
82
|
+
* @returns Function to remove listener. Will return `true` if removed, `false` if inactive already.
|
|
79
83
|
*/
|
|
80
84
|
set(callback: Model.Event<this>): () => boolean;
|
|
81
85
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* This is useful where a property value internally has changed, but the object remains the same.
|
|
85
|
-
* For example: An array which has pushed a new value, or a change to nested property.
|
|
86
|
+
* Declare an end to updates. This event is final and will freeze state.
|
|
86
87
|
*/
|
|
87
|
-
set(
|
|
88
|
+
set(event: null): void;
|
|
88
89
|
/**
|
|
89
|
-
*
|
|
90
|
+
* Push an update. This will not change the value of associated property.
|
|
91
|
+
*
|
|
92
|
+
* Useful where a property value internally has changed, but the object is the same.
|
|
93
|
+
* For example: An array has pushed a new value, or a nested property is updated.
|
|
90
94
|
*/
|
|
91
|
-
set(key:
|
|
95
|
+
set(key: Model.Key<this>): void;
|
|
92
96
|
/**
|
|
93
97
|
* Update a property with value.
|
|
94
98
|
*
|
|
@@ -96,13 +100,13 @@ declare class Model {
|
|
|
96
100
|
* @param value - value to update property with (if the same as current, no update will occur)
|
|
97
101
|
* @param silent - if true, will not notify listeners of an update
|
|
98
102
|
*/
|
|
99
|
-
set<K extends string>(key: K, value?: Model.
|
|
103
|
+
set<K extends string>(key: K, value?: Model.Value<this, K>, silent?: boolean): void;
|
|
100
104
|
/** Iterate over managed properties in this instance of Model. */
|
|
101
105
|
[Symbol.iterator](): Iterator<[string, unknown]>;
|
|
102
106
|
/**
|
|
103
107
|
* Creates a new instance of this controller.
|
|
104
108
|
*
|
|
105
|
-
*
|
|
109
|
+
* **Important** - Use instead of `new this(...)` as this method also activates state.
|
|
106
110
|
*
|
|
107
111
|
* @param args - arguments sent to constructor
|
|
108
112
|
*/
|
|
@@ -172,10 +176,10 @@ declare namespace ref {
|
|
|
172
176
|
}
|
|
173
177
|
/** Object with references to all managed values of `T`. */
|
|
174
178
|
type Proxy<T extends Model> = {
|
|
175
|
-
[P in Model.
|
|
179
|
+
[P in Model.Field<T>]-?: Model.Ref<T[P]>;
|
|
176
180
|
};
|
|
177
181
|
type CustomProxy<T extends Model, R> = {
|
|
178
|
-
[P in Model.
|
|
182
|
+
[P in Model.Field<T>]-?: R;
|
|
179
183
|
};
|
|
180
184
|
}
|
|
181
185
|
/**
|
|
@@ -195,7 +199,7 @@ declare function ref<T extends Model>(target: T): ref.Proxy<T>;
|
|
|
195
199
|
* @param target - Source model from which to reference values.
|
|
196
200
|
* @param mapper - Function producing the placeholder value for any given property.
|
|
197
201
|
*/
|
|
198
|
-
declare function ref<O extends Model, R>(target: O, mapper: (key: Model.
|
|
202
|
+
declare function ref<O extends Model, R>(target: O, mapper: (key: Model.Field<O>) => R): ref.CustomProxy<O, R>;
|
|
199
203
|
/**
|
|
200
204
|
* Creates a ref-compatible property.
|
|
201
205
|
* Will persist value, and updates to this are made part of controller event-stream.
|
package/dist/index.js
CHANGED
|
@@ -38,13 +38,14 @@ var LISTENER = /* @__PURE__ */ new WeakMap();
|
|
|
38
38
|
function onReady() {
|
|
39
39
|
return null;
|
|
40
40
|
}
|
|
41
|
-
function addListener(to, fn) {
|
|
41
|
+
function addListener(to, fn, select) {
|
|
42
42
|
let subs = LISTENER.get(to);
|
|
43
43
|
if (!subs)
|
|
44
|
-
LISTENER.set(to, subs = (/* @__PURE__ */ new Map()).set(onReady,
|
|
45
|
-
|
|
44
|
+
LISTENER.set(to, subs = (/* @__PURE__ */ new Map()).set(onReady, false));
|
|
45
|
+
const filter = 2 in arguments && /* @__PURE__ */ new Set([select]);
|
|
46
|
+
if (!filter && !subs.has(onReady))
|
|
46
47
|
fn(true, to);
|
|
47
|
-
subs.set(fn,
|
|
48
|
+
subs.set(fn, filter);
|
|
48
49
|
return () => subs.delete(fn);
|
|
49
50
|
}
|
|
50
51
|
function watch(from, key, value) {
|
|
@@ -148,11 +149,7 @@ var Model = class _Model {
|
|
|
148
149
|
const state = {};
|
|
149
150
|
define(this, "is", { value: this });
|
|
150
151
|
STATE.set(this, state);
|
|
151
|
-
ID.set(this,
|
|
152
|
-
function onNull(key) {
|
|
153
|
-
if (key === null)
|
|
154
|
-
Object.freeze(state);
|
|
155
|
-
}
|
|
152
|
+
ID.set(this, id ? String(id) : `${Type}-${uid()}`);
|
|
156
153
|
while (true) {
|
|
157
154
|
new Set(NOTIFY.get(Type)).forEach((x) => addListener(this, x));
|
|
158
155
|
if (Type === _Model)
|
|
@@ -173,38 +170,49 @@ var Model = class _Model {
|
|
|
173
170
|
});
|
|
174
171
|
}
|
|
175
172
|
}
|
|
176
|
-
addListener(this,
|
|
173
|
+
addListener(this, () => {
|
|
174
|
+
for (const [_, value] of this)
|
|
175
|
+
if (value instanceof _Model && PARENT.get(value) === this)
|
|
176
|
+
value.set(null);
|
|
177
|
+
Object.freeze(state);
|
|
178
|
+
}, null);
|
|
177
179
|
return null;
|
|
178
180
|
});
|
|
179
181
|
}
|
|
180
182
|
get(arg1, arg2) {
|
|
181
183
|
const self = this.is;
|
|
182
|
-
if (typeof arg1 == "
|
|
183
|
-
if (typeof arg2 == "function") {
|
|
184
|
-
const state = STATE.get(self);
|
|
185
|
-
if (arg1 in state)
|
|
186
|
-
arg2.call(this, state[arg1], arg1, this);
|
|
187
|
-
return addListener(self, (key) => {
|
|
188
|
-
if (key === arg1)
|
|
189
|
-
arg2.call(this, arg1 in state ? state[key] : key, key, this);
|
|
190
|
-
});
|
|
191
|
-
} else
|
|
192
|
-
return fetch(self, arg1, arg2);
|
|
193
|
-
if (arg1)
|
|
184
|
+
if (typeof arg1 == "function")
|
|
194
185
|
return effect(self, arg1);
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
186
|
+
if (arg1 === void 0) {
|
|
187
|
+
let get3 = function(value) {
|
|
188
|
+
if (value instanceof _Model) {
|
|
189
|
+
if (cache.has(value))
|
|
190
|
+
return cache.get(value);
|
|
191
|
+
const model = value;
|
|
192
|
+
cache.set(value, value = {});
|
|
193
|
+
for (const [key, val] of model)
|
|
194
|
+
value[key] = get3(val);
|
|
195
|
+
}
|
|
196
|
+
return value;
|
|
197
|
+
};
|
|
198
|
+
var get2 = get3;
|
|
199
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
200
|
+
return get3(self);
|
|
206
201
|
}
|
|
207
|
-
|
|
202
|
+
if (arg1 === null)
|
|
203
|
+
if (typeof arg2 == "function")
|
|
204
|
+
return addListener(self, arg2.bind(this, this), null);
|
|
205
|
+
else
|
|
206
|
+
return Object.isFrozen(STATE.get(self));
|
|
207
|
+
if (typeof arg2 == "function") {
|
|
208
|
+
const state = STATE.get(self);
|
|
209
|
+
if (arg1 in state)
|
|
210
|
+
arg2.call(this, state[arg1], arg1, this);
|
|
211
|
+
return addListener(self, () => {
|
|
212
|
+
arg2.call(this, arg1 in state ? state[arg1] : arg1, arg1, this);
|
|
213
|
+
}, arg1);
|
|
214
|
+
} else
|
|
215
|
+
return fetch(self, arg1, arg2);
|
|
208
216
|
}
|
|
209
217
|
set(arg1, arg2, arg3) {
|
|
210
218
|
const self = this.is;
|
|
@@ -233,7 +241,7 @@ var Model = class _Model {
|
|
|
233
241
|
/**
|
|
234
242
|
* Creates a new instance of this controller.
|
|
235
243
|
*
|
|
236
|
-
*
|
|
244
|
+
* **Important** - Use instead of `new this(...)` as this method also activates state.
|
|
237
245
|
*
|
|
238
246
|
* @param args - arguments sent to constructor
|
|
239
247
|
*/
|
|
@@ -662,6 +670,8 @@ function attempt(fn) {
|
|
|
662
670
|
|
|
663
671
|
// src/instruction/use.ts
|
|
664
672
|
function use(value, argument) {
|
|
673
|
+
if (typeof value === "function")
|
|
674
|
+
value = new value();
|
|
665
675
|
return add((property, subject) => {
|
|
666
676
|
function set2(next) {
|
|
667
677
|
if (value instanceof Model && !(next instanceof value.constructor))
|
|
@@ -687,8 +697,6 @@ function use(value, argument) {
|
|
|
687
697
|
if (typeof argument == "function")
|
|
688
698
|
argument(next);
|
|
689
699
|
}
|
|
690
|
-
if (typeof value === "function")
|
|
691
|
-
value = new value();
|
|
692
700
|
const output = { set: set2, value };
|
|
693
701
|
set2(value);
|
|
694
702
|
return output;
|
package/dist/index.mjs
CHANGED
|
@@ -5,13 +5,14 @@ var LISTENER = /* @__PURE__ */ new WeakMap();
|
|
|
5
5
|
function onReady() {
|
|
6
6
|
return null;
|
|
7
7
|
}
|
|
8
|
-
function addListener(to, fn) {
|
|
8
|
+
function addListener(to, fn, select) {
|
|
9
9
|
let subs = LISTENER.get(to);
|
|
10
10
|
if (!subs)
|
|
11
|
-
LISTENER.set(to, subs = (/* @__PURE__ */ new Map()).set(onReady,
|
|
12
|
-
|
|
11
|
+
LISTENER.set(to, subs = (/* @__PURE__ */ new Map()).set(onReady, false));
|
|
12
|
+
const filter = 2 in arguments && /* @__PURE__ */ new Set([select]);
|
|
13
|
+
if (!filter && !subs.has(onReady))
|
|
13
14
|
fn(true, to);
|
|
14
|
-
subs.set(fn,
|
|
15
|
+
subs.set(fn, filter);
|
|
15
16
|
return () => subs.delete(fn);
|
|
16
17
|
}
|
|
17
18
|
function watch(from, key, value) {
|
|
@@ -115,11 +116,7 @@ var Model = class _Model {
|
|
|
115
116
|
const state = {};
|
|
116
117
|
define(this, "is", { value: this });
|
|
117
118
|
STATE.set(this, state);
|
|
118
|
-
ID.set(this,
|
|
119
|
-
function onNull(key) {
|
|
120
|
-
if (key === null)
|
|
121
|
-
Object.freeze(state);
|
|
122
|
-
}
|
|
119
|
+
ID.set(this, id ? String(id) : `${Type}-${uid()}`);
|
|
123
120
|
while (true) {
|
|
124
121
|
new Set(NOTIFY.get(Type)).forEach((x) => addListener(this, x));
|
|
125
122
|
if (Type === _Model)
|
|
@@ -140,38 +137,49 @@ var Model = class _Model {
|
|
|
140
137
|
});
|
|
141
138
|
}
|
|
142
139
|
}
|
|
143
|
-
addListener(this,
|
|
140
|
+
addListener(this, () => {
|
|
141
|
+
for (const [_, value] of this)
|
|
142
|
+
if (value instanceof _Model && PARENT.get(value) === this)
|
|
143
|
+
value.set(null);
|
|
144
|
+
Object.freeze(state);
|
|
145
|
+
}, null);
|
|
144
146
|
return null;
|
|
145
147
|
});
|
|
146
148
|
}
|
|
147
149
|
get(arg1, arg2) {
|
|
148
150
|
const self = this.is;
|
|
149
|
-
if (typeof arg1 == "
|
|
150
|
-
if (typeof arg2 == "function") {
|
|
151
|
-
const state = STATE.get(self);
|
|
152
|
-
if (arg1 in state)
|
|
153
|
-
arg2.call(this, state[arg1], arg1, this);
|
|
154
|
-
return addListener(self, (key) => {
|
|
155
|
-
if (key === arg1)
|
|
156
|
-
arg2.call(this, arg1 in state ? state[key] : key, key, this);
|
|
157
|
-
});
|
|
158
|
-
} else
|
|
159
|
-
return fetch(self, arg1, arg2);
|
|
160
|
-
if (arg1)
|
|
151
|
+
if (typeof arg1 == "function")
|
|
161
152
|
return effect(self, arg1);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
153
|
+
if (arg1 === void 0) {
|
|
154
|
+
let get3 = function(value) {
|
|
155
|
+
if (value instanceof _Model) {
|
|
156
|
+
if (cache.has(value))
|
|
157
|
+
return cache.get(value);
|
|
158
|
+
const model = value;
|
|
159
|
+
cache.set(value, value = {});
|
|
160
|
+
for (const [key, val] of model)
|
|
161
|
+
value[key] = get3(val);
|
|
162
|
+
}
|
|
163
|
+
return value;
|
|
164
|
+
};
|
|
165
|
+
var get2 = get3;
|
|
166
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
167
|
+
return get3(self);
|
|
173
168
|
}
|
|
174
|
-
|
|
169
|
+
if (arg1 === null)
|
|
170
|
+
if (typeof arg2 == "function")
|
|
171
|
+
return addListener(self, arg2.bind(this, this), null);
|
|
172
|
+
else
|
|
173
|
+
return Object.isFrozen(STATE.get(self));
|
|
174
|
+
if (typeof arg2 == "function") {
|
|
175
|
+
const state = STATE.get(self);
|
|
176
|
+
if (arg1 in state)
|
|
177
|
+
arg2.call(this, state[arg1], arg1, this);
|
|
178
|
+
return addListener(self, () => {
|
|
179
|
+
arg2.call(this, arg1 in state ? state[arg1] : arg1, arg1, this);
|
|
180
|
+
}, arg1);
|
|
181
|
+
} else
|
|
182
|
+
return fetch(self, arg1, arg2);
|
|
175
183
|
}
|
|
176
184
|
set(arg1, arg2, arg3) {
|
|
177
185
|
const self = this.is;
|
|
@@ -200,7 +208,7 @@ var Model = class _Model {
|
|
|
200
208
|
/**
|
|
201
209
|
* Creates a new instance of this controller.
|
|
202
210
|
*
|
|
203
|
-
*
|
|
211
|
+
* **Important** - Use instead of `new this(...)` as this method also activates state.
|
|
204
212
|
*
|
|
205
213
|
* @param args - arguments sent to constructor
|
|
206
214
|
*/
|
|
@@ -629,6 +637,8 @@ function attempt(fn) {
|
|
|
629
637
|
|
|
630
638
|
// src/instruction/use.ts
|
|
631
639
|
function use(value, argument) {
|
|
640
|
+
if (typeof value === "function")
|
|
641
|
+
value = new value();
|
|
632
642
|
return add((property, subject) => {
|
|
633
643
|
function set2(next) {
|
|
634
644
|
if (value instanceof Model && !(next instanceof value.constructor))
|
|
@@ -654,8 +664,6 @@ function use(value, argument) {
|
|
|
654
664
|
if (typeof argument == "function")
|
|
655
665
|
argument(next);
|
|
656
666
|
}
|
|
657
|
-
if (typeof value === "function")
|
|
658
|
-
value = new value();
|
|
659
667
|
const output = { set: set2, value };
|
|
660
668
|
set2(value);
|
|
661
669
|
return output;
|
package/package.json
CHANGED