@expressive/mvc 0.51.2 → 0.52.1
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 +29 -35
- package/dist/index.js +143 -137
- package/dist/index.mjs +143 -137
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
type MaybeAsync<T> = T | Promise<T>;
|
|
2
1
|
declare namespace Model {
|
|
3
2
|
/** Any type of Model, using own class constructor as its identifier. */
|
|
4
3
|
type Type<T extends Model = Model> = (abstract new (...args: any[]) => T) & typeof Model;
|
|
@@ -6,16 +5,16 @@ declare namespace Model {
|
|
|
6
5
|
type Init<T extends Model = Model> = (new (...args: Model.Args<T>) => T) & Omit<typeof Model, never>;
|
|
7
6
|
/**
|
|
8
7
|
* Model constructor callback - is called when Model finishes intializing.
|
|
9
|
-
* Returned function will
|
|
8
|
+
* Returned function will run when model is destroyed.
|
|
10
9
|
*/
|
|
11
|
-
type Callback<T extends Model = Model> = (this: T, thisArg: T) =>
|
|
10
|
+
type Callback<T extends Model = Model> = (this: T, thisArg: T) => Promise<void> | (() => void) | Assign<T> | void;
|
|
12
11
|
/** Model constructor argument */
|
|
13
12
|
type Argument<T extends Model = Model> = Assign<T> | Callback<T> | string | void;
|
|
14
13
|
/** Model constructor arguments */
|
|
15
|
-
type Args<T extends Model = any> = Argument<T>[];
|
|
14
|
+
type Args<T extends Model = any> = (Argument<T> | Args<T>)[];
|
|
16
15
|
/** Subset of `keyof T` which are not methods or defined by base Model U. **/
|
|
17
16
|
type Field<T> = Exclude<keyof T, keyof Model>;
|
|
18
|
-
/** Any valid key for
|
|
17
|
+
/** Any valid key for model, including but not limited to Field<T>. */
|
|
19
18
|
type Event<T> = Field<T> | (string & {}) | number | symbol;
|
|
20
19
|
/** Object overlay to override values and methods on a model. */
|
|
21
20
|
type Assign<T> = {
|
|
@@ -25,12 +24,12 @@ declare namespace Model {
|
|
|
25
24
|
type Export<R> = R extends {
|
|
26
25
|
get(): infer T;
|
|
27
26
|
} ? T : R;
|
|
28
|
-
/** Value for a property managed by a
|
|
27
|
+
/** Value for a property managed by a model. */
|
|
29
28
|
type Value<T extends Model, K extends Event<T>> = K extends keyof T ? Export<T[K]> : unknown;
|
|
30
29
|
type OnEvent<T extends Model> = (this: T, key: unknown, source: T) => (() => void) | void | null;
|
|
31
30
|
type OnUpdate<T extends Model, K extends Event<T>> = (this: T, value: Value<T, K>, key: K, thisArg: K) => void;
|
|
32
31
|
/**
|
|
33
|
-
* Values from current state of given
|
|
32
|
+
* Values from current state of given model.
|
|
34
33
|
* Differs from `Values` as values here will drill
|
|
35
34
|
* into "real" values held by exotics like ref.Object.
|
|
36
35
|
*/
|
|
@@ -49,7 +48,7 @@ declare namespace Model {
|
|
|
49
48
|
/**
|
|
50
49
|
* A callback function which is subscribed to parent and updates when accessed properties change.
|
|
51
50
|
*
|
|
52
|
-
* @param current - Current state of this
|
|
51
|
+
* @param current - Current state of this model. This is a proxy which detects properties which
|
|
53
52
|
* where accessed, and thus depended upon to stay current.
|
|
54
53
|
*
|
|
55
54
|
* @param update - Set of properties which have changed, and events fired, since last update.
|
|
@@ -60,7 +59,7 @@ declare namespace Model {
|
|
|
60
59
|
/**
|
|
61
60
|
* A callback function returned by effect. Will be called when effect is stale.
|
|
62
61
|
*
|
|
63
|
-
* @param update - `true` if update is pending, `false` effect has been cancelled, `null` if
|
|
62
|
+
* @param update - `true` if update is pending, `false` effect has been cancelled, `null` if model is destroyed.
|
|
64
63
|
*/
|
|
65
64
|
type EffectCallback = ((update: boolean | null) => void);
|
|
66
65
|
/**
|
|
@@ -86,15 +85,18 @@ interface Model {
|
|
|
86
85
|
}
|
|
87
86
|
declare abstract class Model {
|
|
88
87
|
constructor(...args: Model.Args);
|
|
89
|
-
/**
|
|
88
|
+
/**
|
|
89
|
+
* Pull current values from state. Flattens all models and exotic values recursively.
|
|
90
|
+
*
|
|
91
|
+
* @returns Object with all values from this model.
|
|
92
|
+
**/
|
|
90
93
|
get(): Model.State<this>;
|
|
91
94
|
/**
|
|
92
95
|
* Run a function which will run automatically when accessed values change.
|
|
93
96
|
*
|
|
94
|
-
* @param effect
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
97
|
+
* @param effect Function to run, and again whenever accessed values change.
|
|
98
|
+
* If effect returns a function, it will be called when a change occurs (syncronously),
|
|
99
|
+
* effect is cancelled, or parent model is destroyed.
|
|
98
100
|
* @returns Function to cancel listener.
|
|
99
101
|
*/
|
|
100
102
|
get(effect: Model.Effect<this>): () => void;
|
|
@@ -103,6 +105,7 @@ declare abstract class Model {
|
|
|
103
105
|
*
|
|
104
106
|
* @param key - Property to get value of.
|
|
105
107
|
* @param required - If true, will throw an error if property is not available.
|
|
108
|
+
* @returns Value of property.
|
|
106
109
|
*/
|
|
107
110
|
get<T extends Model.Event<this>>(key: T, required?: boolean): Model.Value<this, T>;
|
|
108
111
|
/**
|
|
@@ -110,11 +113,13 @@ declare abstract class Model {
|
|
|
110
113
|
*
|
|
111
114
|
* @param key - Property to watch for updates.
|
|
112
115
|
* @param callback - Function to call when property is updated.
|
|
116
|
+
* @returns Function to cancel listener.
|
|
113
117
|
*/
|
|
114
118
|
get<T extends Model.Event<this>>(key: T, callback: Model.OnUpdate<this, T>): () => void;
|
|
115
119
|
/**
|
|
116
120
|
* Check if model is expired.
|
|
117
121
|
*
|
|
122
|
+
* @param status - `null` to check if model is expired.
|
|
118
123
|
* @returns `true` if model is expired, `false` otherwise.
|
|
119
124
|
*/
|
|
120
125
|
get(status: null): boolean;
|
|
@@ -147,6 +152,8 @@ declare abstract class Model {
|
|
|
147
152
|
/**
|
|
148
153
|
* Declare an end to updates. This event is final and will freeze state.
|
|
149
154
|
* This event can be watched for as well, to run cleanup logic and internally will remove all listeners.
|
|
155
|
+
*
|
|
156
|
+
* @param status - `null` to end updates.
|
|
150
157
|
*/
|
|
151
158
|
set(status: null): void;
|
|
152
159
|
/**
|
|
@@ -161,12 +168,15 @@ declare abstract class Model {
|
|
|
161
168
|
* to prefix an event with "!" and/or use dash-case. e.g. `set("!event")` or `set("my-event")`.
|
|
162
169
|
*
|
|
163
170
|
* @param key - Property or event to dispatch.
|
|
164
|
-
* @returns Promise
|
|
171
|
+
* @returns Promise resolves an array of keys updated.
|
|
165
172
|
*/
|
|
166
173
|
set(key: Model.Event<this>): PromiseLike<Model.Event<this>[]>;
|
|
167
174
|
/**
|
|
168
175
|
* Update mulitple properties at once. Merges argument with current state.
|
|
169
|
-
* Properties which are not managed by this
|
|
176
|
+
* Properties which are not managed by this model will be ignored.
|
|
177
|
+
*
|
|
178
|
+
* @param assign - Object with properties to update.
|
|
179
|
+
* @returns Promise resolving an array of keys updated, `undefined` (immediately) if a noop.
|
|
170
180
|
*/
|
|
171
181
|
set(assign: Model.Assign<this>): PromiseLike<Model.Event<this>[]> | undefined;
|
|
172
182
|
/**
|
|
@@ -175,15 +185,16 @@ declare abstract class Model {
|
|
|
175
185
|
* @param key - property to update
|
|
176
186
|
* @param value - value to update property with (if the same as current, no update will occur)
|
|
177
187
|
* @param silent - if true, will not notify listeners of an update
|
|
188
|
+
* @returns Promise resolving an array of keys updated, `undefined` (immediately) if a noop.
|
|
178
189
|
*/
|
|
179
|
-
set<K extends string>(key: K, value
|
|
190
|
+
set<K extends string>(key: K, value: Model.Value<this, K>, silent?: boolean): PromiseLike<Model.Event<this>[]> | undefined;
|
|
180
191
|
/**
|
|
181
192
|
* Iterate over managed properties in this instance of Model.
|
|
182
193
|
* Yeilds the key and underlying value for each property.
|
|
183
194
|
*/
|
|
184
195
|
[Symbol.iterator](): Iterator<[string, unknown]>;
|
|
185
196
|
/**
|
|
186
|
-
* Create and activate a new instance of this
|
|
197
|
+
* Create and activate a new instance of this model.
|
|
187
198
|
*
|
|
188
199
|
* **Important** - Unlike `new this(...)` - this method also activates state.
|
|
189
200
|
*
|
|
@@ -390,21 +401,4 @@ declare class Context {
|
|
|
390
401
|
protected add<T extends Model>(input: T | Model.Init<T>, implicit?: boolean): T;
|
|
391
402
|
}
|
|
392
403
|
|
|
393
|
-
declare global {
|
|
394
|
-
/**
|
|
395
|
-
* Defines MVC specific matchers for [Jest](https://jestjs.io/) test suites.
|
|
396
|
-
*
|
|
397
|
-
* For these to work you will need to add `@expressive/mvc/jest`
|
|
398
|
-
* under `setupFilesAfterEnv` in your Jest configuration.
|
|
399
|
-
*/
|
|
400
|
-
namespace jest {
|
|
401
|
-
interface Matchers<R> {
|
|
402
|
-
/** Assert model does have one or more updates pending. */
|
|
403
|
-
toUpdate(timeout?: number): Promise<R>;
|
|
404
|
-
/** Assert model did update with keys specified. */
|
|
405
|
-
toHaveUpdated<R>(...keys: (string | symbol | number)[]): Promise<R>;
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
404
|
export { Context, Model, Model as default, effect, get, has, ref, set, use };
|
package/dist/index.js
CHANGED
|
@@ -42,7 +42,7 @@ function addListener(subject, callback, select) {
|
|
|
42
42
|
if (!subs)
|
|
43
43
|
LISTENER.set(subject, subs = /* @__PURE__ */ new Map([[onReady, false]]));
|
|
44
44
|
const filter = select !== void 0 && /* @__PURE__ */ new Set([select]);
|
|
45
|
-
if (!
|
|
45
|
+
if (!subs.has(onReady) && !filter)
|
|
46
46
|
callback(true, subject);
|
|
47
47
|
subs.set(callback, filter);
|
|
48
48
|
return () => subs.delete(callback);
|
|
@@ -79,19 +79,19 @@ function emit(source, key2) {
|
|
|
79
79
|
});
|
|
80
80
|
PENDING.delete(source);
|
|
81
81
|
}
|
|
82
|
-
function queue(
|
|
82
|
+
function queue(event2) {
|
|
83
83
|
if (!DISPATCH.size)
|
|
84
84
|
setTimeout(() => {
|
|
85
|
-
DISPATCH.forEach((
|
|
85
|
+
DISPATCH.forEach((event3) => {
|
|
86
86
|
try {
|
|
87
|
-
|
|
87
|
+
event3();
|
|
88
88
|
} catch (err) {
|
|
89
89
|
console.error(err);
|
|
90
90
|
}
|
|
91
91
|
});
|
|
92
92
|
DISPATCH.clear();
|
|
93
93
|
}, 0);
|
|
94
|
-
DISPATCH.add(
|
|
94
|
+
DISPATCH.add(event2);
|
|
95
95
|
}
|
|
96
96
|
function effect(target, callback, requireValues) {
|
|
97
97
|
const listeners = LISTENER.get(target);
|
|
@@ -155,78 +155,27 @@ function effect(target, callback, requireValues) {
|
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
// src/model.ts
|
|
158
|
-
var
|
|
158
|
+
var define = Object.defineProperty;
|
|
159
|
+
var ID = /* @__PURE__ */ new WeakMap();
|
|
159
160
|
var STATE = /* @__PURE__ */ new WeakMap();
|
|
160
161
|
var NOTIFY = /* @__PURE__ */ new WeakMap();
|
|
161
162
|
var PENDING2 = /* @__PURE__ */ new WeakMap();
|
|
162
163
|
var PARENT = /* @__PURE__ */ new WeakMap();
|
|
164
|
+
var METHODS = /* @__PURE__ */ new WeakMap();
|
|
163
165
|
var METHOD = /* @__PURE__ */ new WeakMap();
|
|
164
166
|
var EXPORT;
|
|
165
|
-
var define = Object.defineProperty;
|
|
166
167
|
var Model = class _Model {
|
|
167
168
|
constructor(...args) {
|
|
168
|
-
const state = {};
|
|
169
|
-
let Type = this.constructor;
|
|
170
|
-
bindMethods(Type);
|
|
171
169
|
define(this, "is", { value: this });
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
NAMES.set(this, arg);
|
|
177
|
-
while (true) {
|
|
178
|
-
new Set(NOTIFY.get(Type)).forEach((x) => addListener(this, x));
|
|
179
|
-
if (Type === _Model)
|
|
180
|
-
break;
|
|
181
|
-
Type = Object.getPrototypeOf(Type);
|
|
182
|
-
}
|
|
183
|
-
addListener(this, () => {
|
|
184
|
-
let done;
|
|
185
|
-
(async () => {
|
|
186
|
-
const cleanup = /* @__PURE__ */ new Set();
|
|
187
|
-
for (const arg of args) {
|
|
188
|
-
let use2 = typeof arg == "function" ? arg.call(this, this) : arg;
|
|
189
|
-
if (use2 instanceof Promise)
|
|
190
|
-
use2 = await use2.catch((err) => {
|
|
191
|
-
console.error(`Async error in constructor for ${this}:`);
|
|
192
|
-
console.error(err);
|
|
193
|
-
});
|
|
194
|
-
if (typeof use2 == "object")
|
|
195
|
-
assign(this, use2);
|
|
196
|
-
else if (typeof use2 == "function")
|
|
197
|
-
cleanup.add(use2);
|
|
198
|
-
}
|
|
199
|
-
done = cleanup;
|
|
200
|
-
})();
|
|
201
|
-
for (const key2 in this) {
|
|
202
|
-
const desc = Object.getOwnPropertyDescriptor(this, key2);
|
|
203
|
-
if ("value" in desc) {
|
|
204
|
-
update(this, key2, desc.value, true);
|
|
205
|
-
define(this, key2, {
|
|
206
|
-
configurable: false,
|
|
207
|
-
set: (x) => update(this, key2, x),
|
|
208
|
-
get() {
|
|
209
|
-
return watch(this, key2, state[key2]);
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
if (!PARENT.has(this))
|
|
215
|
-
PARENT.set(this, null);
|
|
216
|
-
addListener(this, () => {
|
|
217
|
-
if (!done)
|
|
218
|
-
throw new Error(`Tried to destroy ${this} but not fully initialized.`);
|
|
219
|
-
for (const [_, value] of this)
|
|
220
|
-
if (value instanceof _Model && PARENT.get(value) === this)
|
|
221
|
-
value.set(null);
|
|
222
|
-
done.forEach((x) => x());
|
|
223
|
-
Object.freeze(state);
|
|
224
|
-
}, null);
|
|
225
|
-
return null;
|
|
226
|
-
});
|
|
170
|
+
ID.set(this, `${this.constructor}-${uid()}`);
|
|
171
|
+
STATE.set(this, {});
|
|
172
|
+
prepare(this);
|
|
173
|
+
init(this, args);
|
|
227
174
|
}
|
|
228
175
|
get(arg1, arg2) {
|
|
229
176
|
const self = this.is;
|
|
177
|
+
if (arg1 === void 0)
|
|
178
|
+
return values(self);
|
|
230
179
|
if (typeof arg1 == "function") {
|
|
231
180
|
let pending = /* @__PURE__ */ new Set();
|
|
232
181
|
return effect(self, (state) => {
|
|
@@ -238,20 +187,6 @@ var Model = class _Model {
|
|
|
238
187
|
};
|
|
239
188
|
});
|
|
240
189
|
}
|
|
241
|
-
if (arg1 === void 0) {
|
|
242
|
-
const values = {};
|
|
243
|
-
const current = !EXPORT && (EXPORT = /* @__PURE__ */ new Map([[self, values]]));
|
|
244
|
-
for (let [key2, value] of self) {
|
|
245
|
-
if (EXPORT.has(value))
|
|
246
|
-
value = EXPORT.get(value);
|
|
247
|
-
else if (value && typeof value.get === "function")
|
|
248
|
-
EXPORT.set(value, value = value.get());
|
|
249
|
-
values[key2] = value;
|
|
250
|
-
}
|
|
251
|
-
if (current)
|
|
252
|
-
EXPORT = void 0;
|
|
253
|
-
return Object.freeze(values);
|
|
254
|
-
}
|
|
255
190
|
if (typeof arg2 == "function") {
|
|
256
191
|
if (arg1 === null)
|
|
257
192
|
return addListener(self, arg2.bind(this, this), null);
|
|
@@ -282,7 +217,7 @@ var Model = class _Model {
|
|
|
282
217
|
else if (1 in arguments)
|
|
283
218
|
update(self, arg1, arg2, arg3);
|
|
284
219
|
else
|
|
285
|
-
|
|
220
|
+
event(self, arg1);
|
|
286
221
|
if (PENDING2.has(self))
|
|
287
222
|
return {
|
|
288
223
|
then: (res) => new Promise((res2) => {
|
|
@@ -303,7 +238,7 @@ var Model = class _Model {
|
|
|
303
238
|
return Object.entries(STATE.get(this.is))[Symbol.iterator]();
|
|
304
239
|
}
|
|
305
240
|
/**
|
|
306
|
-
* Create and activate a new instance of this
|
|
241
|
+
* Create and activate a new instance of this model.
|
|
307
242
|
*
|
|
308
243
|
* **Important** - Unlike `new this(...)` - this method also activates state.
|
|
309
244
|
*
|
|
@@ -339,7 +274,7 @@ var Model = class _Model {
|
|
|
339
274
|
};
|
|
340
275
|
define(Model.prototype, "toString", {
|
|
341
276
|
value() {
|
|
342
|
-
return
|
|
277
|
+
return ID.get(this.is);
|
|
343
278
|
}
|
|
344
279
|
});
|
|
345
280
|
define(Model, "toString", {
|
|
@@ -347,6 +282,92 @@ define(Model, "toString", {
|
|
|
347
282
|
return this.name;
|
|
348
283
|
}
|
|
349
284
|
});
|
|
285
|
+
function prepare(model) {
|
|
286
|
+
const chain = [];
|
|
287
|
+
let type = model.constructor;
|
|
288
|
+
let keys2 = /* @__PURE__ */ new Set();
|
|
289
|
+
while (type.name) {
|
|
290
|
+
chain.unshift(type);
|
|
291
|
+
type = Object.getPrototypeOf(type);
|
|
292
|
+
}
|
|
293
|
+
for (const type2 of chain) {
|
|
294
|
+
for (const cb of NOTIFY.get(type2) || [])
|
|
295
|
+
addListener(model, cb);
|
|
296
|
+
if (type2 == Model)
|
|
297
|
+
continue;
|
|
298
|
+
if (METHODS.has(type2)) {
|
|
299
|
+
keys2 = METHODS.get(type2);
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
METHODS.set(type2, keys2 = new Set(keys2));
|
|
303
|
+
for (const [key2, { value }] of Object.entries(
|
|
304
|
+
Object.getOwnPropertyDescriptors(type2.prototype)
|
|
305
|
+
)) {
|
|
306
|
+
let set3 = function(method) {
|
|
307
|
+
const value2 = method.bind(this.is);
|
|
308
|
+
METHOD.set(value2, method);
|
|
309
|
+
define(this.is, key2, { value: value2, writable: true });
|
|
310
|
+
return value2;
|
|
311
|
+
};
|
|
312
|
+
var set2 = set3;
|
|
313
|
+
if (!value || key2 == "constructor")
|
|
314
|
+
continue;
|
|
315
|
+
keys2.add(key2);
|
|
316
|
+
Object.defineProperty(type2.prototype, key2, {
|
|
317
|
+
set: set3,
|
|
318
|
+
get() {
|
|
319
|
+
return this.hasOwnProperty(key2) ? value : set3.call(this, value);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
function init(model, args) {
|
|
326
|
+
const done = /* @__PURE__ */ new Set();
|
|
327
|
+
const state = STATE.get(model);
|
|
328
|
+
args = args.flat().filter((arg) => {
|
|
329
|
+
if (typeof arg != "string")
|
|
330
|
+
return true;
|
|
331
|
+
ID.set(model, arg);
|
|
332
|
+
});
|
|
333
|
+
addListener(model, () => {
|
|
334
|
+
if (!PARENT.has(model))
|
|
335
|
+
PARENT.set(model, null);
|
|
336
|
+
args.forEach((arg) => {
|
|
337
|
+
const use2 = typeof arg == "function" ? arg.call(model, model) : arg;
|
|
338
|
+
if (use2 instanceof Promise)
|
|
339
|
+
use2.catch((err) => {
|
|
340
|
+
console.error(`Async error in constructor for ${model}:`);
|
|
341
|
+
console.error(err);
|
|
342
|
+
});
|
|
343
|
+
else if (typeof use2 == "function")
|
|
344
|
+
done.add(use2);
|
|
345
|
+
else if (typeof use2 == "object")
|
|
346
|
+
assign(model, use2);
|
|
347
|
+
});
|
|
348
|
+
for (const key2 in model) {
|
|
349
|
+
const desc = Object.getOwnPropertyDescriptor(model, key2);
|
|
350
|
+
if ("value" in desc) {
|
|
351
|
+
update(model, key2, desc.value, true);
|
|
352
|
+
define(model, key2, {
|
|
353
|
+
configurable: false,
|
|
354
|
+
set: (x) => update(model, key2, x),
|
|
355
|
+
get() {
|
|
356
|
+
return watch(this, key2, state[key2]);
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return null;
|
|
362
|
+
});
|
|
363
|
+
addListener(model, () => {
|
|
364
|
+
done.forEach((x) => x());
|
|
365
|
+
for (const [_, value] of model)
|
|
366
|
+
if (value instanceof Model && PARENT.get(value) === model)
|
|
367
|
+
value.set(null);
|
|
368
|
+
Object.freeze(state);
|
|
369
|
+
}, null);
|
|
370
|
+
}
|
|
350
371
|
function fetch(subject, property, required) {
|
|
351
372
|
const state = STATE.get(subject);
|
|
352
373
|
if (property in state || required === false) {
|
|
@@ -372,6 +393,20 @@ function fetch(subject, property, required) {
|
|
|
372
393
|
stack: error.stack
|
|
373
394
|
});
|
|
374
395
|
}
|
|
396
|
+
function values(model) {
|
|
397
|
+
const values2 = {};
|
|
398
|
+
const current = !EXPORT && (EXPORT = /* @__PURE__ */ new Map([[model, values2]]));
|
|
399
|
+
for (let [key2, value] of model) {
|
|
400
|
+
if (EXPORT.has(value))
|
|
401
|
+
value = EXPORT.get(value);
|
|
402
|
+
else if (value && typeof value.get === "function")
|
|
403
|
+
EXPORT.set(value, value = value.get());
|
|
404
|
+
values2[key2] = value;
|
|
405
|
+
}
|
|
406
|
+
if (current)
|
|
407
|
+
EXPORT = void 0;
|
|
408
|
+
return Object.freeze(values2);
|
|
409
|
+
}
|
|
375
410
|
function update(subject, key2, value, arg) {
|
|
376
411
|
const state = STATE.get(subject);
|
|
377
412
|
if (Object.isFrozen(state))
|
|
@@ -392,9 +427,9 @@ function update(subject, key2, value, arg) {
|
|
|
392
427
|
}
|
|
393
428
|
state[key2] = value;
|
|
394
429
|
if (arg !== true)
|
|
395
|
-
|
|
430
|
+
event(subject, key2);
|
|
396
431
|
}
|
|
397
|
-
function
|
|
432
|
+
function event(subject, key2, silent) {
|
|
398
433
|
let pending = PENDING2.get(subject);
|
|
399
434
|
if (!pending) {
|
|
400
435
|
PENDING2.set(subject, pending = /* @__PURE__ */ new Set());
|
|
@@ -408,39 +443,11 @@ function push(subject, key2, silent) {
|
|
|
408
443
|
if (!silent)
|
|
409
444
|
emit(subject, key2);
|
|
410
445
|
}
|
|
411
|
-
|
|
412
|
-
function assign(to, values) {
|
|
446
|
+
function assign(to, values2) {
|
|
413
447
|
const methods = METHODS.get(to.constructor);
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
to[key2] = values[key2];
|
|
418
|
-
}
|
|
419
|
-
function bindMethods(type) {
|
|
420
|
-
let keys2 = METHODS.get(type);
|
|
421
|
-
if (!keys2) {
|
|
422
|
-
METHODS.set(type, keys2 = bindMethods(Object.getPrototypeOf(type)).slice());
|
|
423
|
-
const desc = Object.getOwnPropertyDescriptors(type.prototype);
|
|
424
|
-
for (const key2 in desc)
|
|
425
|
-
if (key2 != "constructor" && "value" in desc[key2]) {
|
|
426
|
-
let bind2 = function(method) {
|
|
427
|
-
const value2 = method.bind(this.is);
|
|
428
|
-
METHOD.set(value2, method);
|
|
429
|
-
define(this.is, key2, { value: value2, writable: true });
|
|
430
|
-
return value2;
|
|
431
|
-
};
|
|
432
|
-
var bind = bind2;
|
|
433
|
-
let { value } = desc[key2];
|
|
434
|
-
keys2.push(key2);
|
|
435
|
-
Object.defineProperty(type.prototype, key2, {
|
|
436
|
-
set: bind2,
|
|
437
|
-
get() {
|
|
438
|
-
return this.hasOwnProperty(key2) ? value : bind2.call(this, value);
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
return keys2;
|
|
448
|
+
for (const key2 in values2)
|
|
449
|
+
if (key2 in to || methods.has(key2))
|
|
450
|
+
to[key2] = values2[key2];
|
|
444
451
|
}
|
|
445
452
|
function uid() {
|
|
446
453
|
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
@@ -507,7 +514,7 @@ var Context = class _Context {
|
|
|
507
514
|
this.layer.clear();
|
|
508
515
|
}
|
|
509
516
|
include(inputs, forEach) {
|
|
510
|
-
const
|
|
517
|
+
const init2 = /* @__PURE__ */ new Map();
|
|
511
518
|
Object.entries(inputs).forEach(([K, V]) => {
|
|
512
519
|
if (!(Model.is(V) || V instanceof Model))
|
|
513
520
|
throw new Error(`Context can only include Model or instance but got ${V}${K && " as " + K}.`);
|
|
@@ -518,21 +525,21 @@ var Context = class _Context {
|
|
|
518
525
|
if (!exists) {
|
|
519
526
|
const instance = this.add(input);
|
|
520
527
|
this.layer.set(key2, input);
|
|
521
|
-
|
|
528
|
+
init2.set(instance, true);
|
|
522
529
|
} else if (exists !== input) {
|
|
523
530
|
this.pop();
|
|
524
531
|
this.id = uid();
|
|
525
532
|
this.include(inputs);
|
|
526
533
|
}
|
|
527
534
|
}
|
|
528
|
-
for (const [model, explicit] of
|
|
535
|
+
for (const [model, explicit] of init2) {
|
|
529
536
|
model.set();
|
|
530
537
|
if (forEach)
|
|
531
538
|
forEach(model, explicit);
|
|
532
539
|
for (const [_key, value] of model)
|
|
533
540
|
if (PARENT.get(value) === model) {
|
|
534
541
|
this.add(value, true);
|
|
535
|
-
|
|
542
|
+
init2.set(value, false);
|
|
536
543
|
}
|
|
537
544
|
}
|
|
538
545
|
}
|
|
@@ -597,38 +604,37 @@ function use(arg1, arg2) {
|
|
|
597
604
|
INSTRUCT.set(token, arg1);
|
|
598
605
|
return token;
|
|
599
606
|
}
|
|
600
|
-
Model.on((_,
|
|
601
|
-
const state = STATE.get(
|
|
602
|
-
const
|
|
603
|
-
|
|
604
|
-
const { value } = props[key2];
|
|
607
|
+
Model.on((_, model) => {
|
|
608
|
+
const state = STATE.get(model);
|
|
609
|
+
for (const key2 in model) {
|
|
610
|
+
const { value } = Object.getOwnPropertyDescriptor(model, key2);
|
|
605
611
|
const instruction = INSTRUCT.get(value);
|
|
606
612
|
if (!instruction) {
|
|
607
613
|
if (value instanceof Model && key2 !== "is")
|
|
608
|
-
update(
|
|
614
|
+
update(model, key2, value);
|
|
609
615
|
continue;
|
|
610
616
|
}
|
|
611
617
|
INSTRUCT.delete(value);
|
|
612
|
-
delete
|
|
613
|
-
const output = instruction.call(
|
|
618
|
+
delete model[key2];
|
|
619
|
+
const output = instruction.call(model, key2, model, state);
|
|
614
620
|
if (!output)
|
|
615
621
|
continue;
|
|
616
622
|
const desc = typeof output == "object" ? output : { get: output };
|
|
617
623
|
if ("value" in desc)
|
|
618
624
|
state[key2] = desc.value;
|
|
619
|
-
Object.defineProperty(
|
|
625
|
+
Object.defineProperty(model, key2, {
|
|
620
626
|
enumerable: desc.enumerable !== false,
|
|
621
627
|
get() {
|
|
622
628
|
return watch(
|
|
623
629
|
this,
|
|
624
630
|
key2,
|
|
625
|
-
typeof desc.get == "function" ? desc.get(this) : fetch(
|
|
631
|
+
typeof desc.get == "function" ? desc.get(this) : fetch(model, key2, desc.get)
|
|
626
632
|
);
|
|
627
633
|
},
|
|
628
634
|
set(next) {
|
|
629
635
|
if (desc.set === false)
|
|
630
|
-
throw new Error(`${
|
|
631
|
-
update(
|
|
636
|
+
throw new Error(`${model}.${key2} is read-only.`);
|
|
637
|
+
update(model, key2, next, desc.set);
|
|
632
638
|
}
|
|
633
639
|
});
|
|
634
640
|
}
|
|
@@ -676,7 +682,7 @@ function get(arg0, arg1) {
|
|
|
676
682
|
return (didUpdate) => {
|
|
677
683
|
if (didUpdate) {
|
|
678
684
|
STALE.add(compute2);
|
|
679
|
-
|
|
685
|
+
event(subject, key2, true);
|
|
680
686
|
}
|
|
681
687
|
};
|
|
682
688
|
});
|
|
@@ -768,7 +774,7 @@ function set(value, argument) {
|
|
|
768
774
|
return use((key2, subject) => {
|
|
769
775
|
const output = {};
|
|
770
776
|
if (typeof value == "function" || value instanceof Promise) {
|
|
771
|
-
let
|
|
777
|
+
let init3 = function() {
|
|
772
778
|
if (typeof value == "function")
|
|
773
779
|
try {
|
|
774
780
|
value = attempt(value.bind(subject, key2));
|
|
@@ -792,11 +798,11 @@ function set(value, argument) {
|
|
|
792
798
|
if (0 in arguments)
|
|
793
799
|
return subject[key2];
|
|
794
800
|
};
|
|
795
|
-
var
|
|
801
|
+
var init2 = init3;
|
|
796
802
|
if (argument)
|
|
797
|
-
|
|
803
|
+
init3();
|
|
798
804
|
else
|
|
799
|
-
output.get =
|
|
805
|
+
output.get = init3;
|
|
800
806
|
} else if (value !== void 0)
|
|
801
807
|
output.value = value;
|
|
802
808
|
if (typeof argument == "function") {
|
package/dist/index.mjs
CHANGED
|
@@ -8,7 +8,7 @@ function addListener(subject, callback, select) {
|
|
|
8
8
|
if (!subs)
|
|
9
9
|
LISTENER.set(subject, subs = /* @__PURE__ */ new Map([[onReady, false]]));
|
|
10
10
|
const filter = select !== void 0 && /* @__PURE__ */ new Set([select]);
|
|
11
|
-
if (!
|
|
11
|
+
if (!subs.has(onReady) && !filter)
|
|
12
12
|
callback(true, subject);
|
|
13
13
|
subs.set(callback, filter);
|
|
14
14
|
return () => subs.delete(callback);
|
|
@@ -45,19 +45,19 @@ function emit(source, key2) {
|
|
|
45
45
|
});
|
|
46
46
|
PENDING.delete(source);
|
|
47
47
|
}
|
|
48
|
-
function queue(
|
|
48
|
+
function queue(event2) {
|
|
49
49
|
if (!DISPATCH.size)
|
|
50
50
|
setTimeout(() => {
|
|
51
|
-
DISPATCH.forEach((
|
|
51
|
+
DISPATCH.forEach((event3) => {
|
|
52
52
|
try {
|
|
53
|
-
|
|
53
|
+
event3();
|
|
54
54
|
} catch (err) {
|
|
55
55
|
console.error(err);
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
58
|
DISPATCH.clear();
|
|
59
59
|
}, 0);
|
|
60
|
-
DISPATCH.add(
|
|
60
|
+
DISPATCH.add(event2);
|
|
61
61
|
}
|
|
62
62
|
function effect(target, callback, requireValues) {
|
|
63
63
|
const listeners = LISTENER.get(target);
|
|
@@ -121,78 +121,27 @@ function effect(target, callback, requireValues) {
|
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
// src/model.ts
|
|
124
|
-
var
|
|
124
|
+
var define = Object.defineProperty;
|
|
125
|
+
var ID = /* @__PURE__ */ new WeakMap();
|
|
125
126
|
var STATE = /* @__PURE__ */ new WeakMap();
|
|
126
127
|
var NOTIFY = /* @__PURE__ */ new WeakMap();
|
|
127
128
|
var PENDING2 = /* @__PURE__ */ new WeakMap();
|
|
128
129
|
var PARENT = /* @__PURE__ */ new WeakMap();
|
|
130
|
+
var METHODS = /* @__PURE__ */ new WeakMap();
|
|
129
131
|
var METHOD = /* @__PURE__ */ new WeakMap();
|
|
130
132
|
var EXPORT;
|
|
131
|
-
var define = Object.defineProperty;
|
|
132
133
|
var Model = class _Model {
|
|
133
134
|
constructor(...args) {
|
|
134
|
-
const state = {};
|
|
135
|
-
let Type = this.constructor;
|
|
136
|
-
bindMethods(Type);
|
|
137
135
|
define(this, "is", { value: this });
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
NAMES.set(this, arg);
|
|
143
|
-
while (true) {
|
|
144
|
-
new Set(NOTIFY.get(Type)).forEach((x) => addListener(this, x));
|
|
145
|
-
if (Type === _Model)
|
|
146
|
-
break;
|
|
147
|
-
Type = Object.getPrototypeOf(Type);
|
|
148
|
-
}
|
|
149
|
-
addListener(this, () => {
|
|
150
|
-
let done;
|
|
151
|
-
(async () => {
|
|
152
|
-
const cleanup = /* @__PURE__ */ new Set();
|
|
153
|
-
for (const arg of args) {
|
|
154
|
-
let use2 = typeof arg == "function" ? arg.call(this, this) : arg;
|
|
155
|
-
if (use2 instanceof Promise)
|
|
156
|
-
use2 = await use2.catch((err) => {
|
|
157
|
-
console.error(`Async error in constructor for ${this}:`);
|
|
158
|
-
console.error(err);
|
|
159
|
-
});
|
|
160
|
-
if (typeof use2 == "object")
|
|
161
|
-
assign(this, use2);
|
|
162
|
-
else if (typeof use2 == "function")
|
|
163
|
-
cleanup.add(use2);
|
|
164
|
-
}
|
|
165
|
-
done = cleanup;
|
|
166
|
-
})();
|
|
167
|
-
for (const key2 in this) {
|
|
168
|
-
const desc = Object.getOwnPropertyDescriptor(this, key2);
|
|
169
|
-
if ("value" in desc) {
|
|
170
|
-
update(this, key2, desc.value, true);
|
|
171
|
-
define(this, key2, {
|
|
172
|
-
configurable: false,
|
|
173
|
-
set: (x) => update(this, key2, x),
|
|
174
|
-
get() {
|
|
175
|
-
return watch(this, key2, state[key2]);
|
|
176
|
-
}
|
|
177
|
-
});
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
if (!PARENT.has(this))
|
|
181
|
-
PARENT.set(this, null);
|
|
182
|
-
addListener(this, () => {
|
|
183
|
-
if (!done)
|
|
184
|
-
throw new Error(`Tried to destroy ${this} but not fully initialized.`);
|
|
185
|
-
for (const [_, value] of this)
|
|
186
|
-
if (value instanceof _Model && PARENT.get(value) === this)
|
|
187
|
-
value.set(null);
|
|
188
|
-
done.forEach((x) => x());
|
|
189
|
-
Object.freeze(state);
|
|
190
|
-
}, null);
|
|
191
|
-
return null;
|
|
192
|
-
});
|
|
136
|
+
ID.set(this, `${this.constructor}-${uid()}`);
|
|
137
|
+
STATE.set(this, {});
|
|
138
|
+
prepare(this);
|
|
139
|
+
init(this, args);
|
|
193
140
|
}
|
|
194
141
|
get(arg1, arg2) {
|
|
195
142
|
const self = this.is;
|
|
143
|
+
if (arg1 === void 0)
|
|
144
|
+
return values(self);
|
|
196
145
|
if (typeof arg1 == "function") {
|
|
197
146
|
let pending = /* @__PURE__ */ new Set();
|
|
198
147
|
return effect(self, (state) => {
|
|
@@ -204,20 +153,6 @@ var Model = class _Model {
|
|
|
204
153
|
};
|
|
205
154
|
});
|
|
206
155
|
}
|
|
207
|
-
if (arg1 === void 0) {
|
|
208
|
-
const values = {};
|
|
209
|
-
const current = !EXPORT && (EXPORT = /* @__PURE__ */ new Map([[self, values]]));
|
|
210
|
-
for (let [key2, value] of self) {
|
|
211
|
-
if (EXPORT.has(value))
|
|
212
|
-
value = EXPORT.get(value);
|
|
213
|
-
else if (value && typeof value.get === "function")
|
|
214
|
-
EXPORT.set(value, value = value.get());
|
|
215
|
-
values[key2] = value;
|
|
216
|
-
}
|
|
217
|
-
if (current)
|
|
218
|
-
EXPORT = void 0;
|
|
219
|
-
return Object.freeze(values);
|
|
220
|
-
}
|
|
221
156
|
if (typeof arg2 == "function") {
|
|
222
157
|
if (arg1 === null)
|
|
223
158
|
return addListener(self, arg2.bind(this, this), null);
|
|
@@ -248,7 +183,7 @@ var Model = class _Model {
|
|
|
248
183
|
else if (1 in arguments)
|
|
249
184
|
update(self, arg1, arg2, arg3);
|
|
250
185
|
else
|
|
251
|
-
|
|
186
|
+
event(self, arg1);
|
|
252
187
|
if (PENDING2.has(self))
|
|
253
188
|
return {
|
|
254
189
|
then: (res) => new Promise((res2) => {
|
|
@@ -269,7 +204,7 @@ var Model = class _Model {
|
|
|
269
204
|
return Object.entries(STATE.get(this.is))[Symbol.iterator]();
|
|
270
205
|
}
|
|
271
206
|
/**
|
|
272
|
-
* Create and activate a new instance of this
|
|
207
|
+
* Create and activate a new instance of this model.
|
|
273
208
|
*
|
|
274
209
|
* **Important** - Unlike `new this(...)` - this method also activates state.
|
|
275
210
|
*
|
|
@@ -305,7 +240,7 @@ var Model = class _Model {
|
|
|
305
240
|
};
|
|
306
241
|
define(Model.prototype, "toString", {
|
|
307
242
|
value() {
|
|
308
|
-
return
|
|
243
|
+
return ID.get(this.is);
|
|
309
244
|
}
|
|
310
245
|
});
|
|
311
246
|
define(Model, "toString", {
|
|
@@ -313,6 +248,92 @@ define(Model, "toString", {
|
|
|
313
248
|
return this.name;
|
|
314
249
|
}
|
|
315
250
|
});
|
|
251
|
+
function prepare(model) {
|
|
252
|
+
const chain = [];
|
|
253
|
+
let type = model.constructor;
|
|
254
|
+
let keys2 = /* @__PURE__ */ new Set();
|
|
255
|
+
while (type.name) {
|
|
256
|
+
chain.unshift(type);
|
|
257
|
+
type = Object.getPrototypeOf(type);
|
|
258
|
+
}
|
|
259
|
+
for (const type2 of chain) {
|
|
260
|
+
for (const cb of NOTIFY.get(type2) || [])
|
|
261
|
+
addListener(model, cb);
|
|
262
|
+
if (type2 == Model)
|
|
263
|
+
continue;
|
|
264
|
+
if (METHODS.has(type2)) {
|
|
265
|
+
keys2 = METHODS.get(type2);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
METHODS.set(type2, keys2 = new Set(keys2));
|
|
269
|
+
for (const [key2, { value }] of Object.entries(
|
|
270
|
+
Object.getOwnPropertyDescriptors(type2.prototype)
|
|
271
|
+
)) {
|
|
272
|
+
let set3 = function(method) {
|
|
273
|
+
const value2 = method.bind(this.is);
|
|
274
|
+
METHOD.set(value2, method);
|
|
275
|
+
define(this.is, key2, { value: value2, writable: true });
|
|
276
|
+
return value2;
|
|
277
|
+
};
|
|
278
|
+
var set2 = set3;
|
|
279
|
+
if (!value || key2 == "constructor")
|
|
280
|
+
continue;
|
|
281
|
+
keys2.add(key2);
|
|
282
|
+
Object.defineProperty(type2.prototype, key2, {
|
|
283
|
+
set: set3,
|
|
284
|
+
get() {
|
|
285
|
+
return this.hasOwnProperty(key2) ? value : set3.call(this, value);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function init(model, args) {
|
|
292
|
+
const done = /* @__PURE__ */ new Set();
|
|
293
|
+
const state = STATE.get(model);
|
|
294
|
+
args = args.flat().filter((arg) => {
|
|
295
|
+
if (typeof arg != "string")
|
|
296
|
+
return true;
|
|
297
|
+
ID.set(model, arg);
|
|
298
|
+
});
|
|
299
|
+
addListener(model, () => {
|
|
300
|
+
if (!PARENT.has(model))
|
|
301
|
+
PARENT.set(model, null);
|
|
302
|
+
args.forEach((arg) => {
|
|
303
|
+
const use2 = typeof arg == "function" ? arg.call(model, model) : arg;
|
|
304
|
+
if (use2 instanceof Promise)
|
|
305
|
+
use2.catch((err) => {
|
|
306
|
+
console.error(`Async error in constructor for ${model}:`);
|
|
307
|
+
console.error(err);
|
|
308
|
+
});
|
|
309
|
+
else if (typeof use2 == "function")
|
|
310
|
+
done.add(use2);
|
|
311
|
+
else if (typeof use2 == "object")
|
|
312
|
+
assign(model, use2);
|
|
313
|
+
});
|
|
314
|
+
for (const key2 in model) {
|
|
315
|
+
const desc = Object.getOwnPropertyDescriptor(model, key2);
|
|
316
|
+
if ("value" in desc) {
|
|
317
|
+
update(model, key2, desc.value, true);
|
|
318
|
+
define(model, key2, {
|
|
319
|
+
configurable: false,
|
|
320
|
+
set: (x) => update(model, key2, x),
|
|
321
|
+
get() {
|
|
322
|
+
return watch(this, key2, state[key2]);
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
328
|
+
});
|
|
329
|
+
addListener(model, () => {
|
|
330
|
+
done.forEach((x) => x());
|
|
331
|
+
for (const [_, value] of model)
|
|
332
|
+
if (value instanceof Model && PARENT.get(value) === model)
|
|
333
|
+
value.set(null);
|
|
334
|
+
Object.freeze(state);
|
|
335
|
+
}, null);
|
|
336
|
+
}
|
|
316
337
|
function fetch(subject, property, required) {
|
|
317
338
|
const state = STATE.get(subject);
|
|
318
339
|
if (property in state || required === false) {
|
|
@@ -338,6 +359,20 @@ function fetch(subject, property, required) {
|
|
|
338
359
|
stack: error.stack
|
|
339
360
|
});
|
|
340
361
|
}
|
|
362
|
+
function values(model) {
|
|
363
|
+
const values2 = {};
|
|
364
|
+
const current = !EXPORT && (EXPORT = /* @__PURE__ */ new Map([[model, values2]]));
|
|
365
|
+
for (let [key2, value] of model) {
|
|
366
|
+
if (EXPORT.has(value))
|
|
367
|
+
value = EXPORT.get(value);
|
|
368
|
+
else if (value && typeof value.get === "function")
|
|
369
|
+
EXPORT.set(value, value = value.get());
|
|
370
|
+
values2[key2] = value;
|
|
371
|
+
}
|
|
372
|
+
if (current)
|
|
373
|
+
EXPORT = void 0;
|
|
374
|
+
return Object.freeze(values2);
|
|
375
|
+
}
|
|
341
376
|
function update(subject, key2, value, arg) {
|
|
342
377
|
const state = STATE.get(subject);
|
|
343
378
|
if (Object.isFrozen(state))
|
|
@@ -358,9 +393,9 @@ function update(subject, key2, value, arg) {
|
|
|
358
393
|
}
|
|
359
394
|
state[key2] = value;
|
|
360
395
|
if (arg !== true)
|
|
361
|
-
|
|
396
|
+
event(subject, key2);
|
|
362
397
|
}
|
|
363
|
-
function
|
|
398
|
+
function event(subject, key2, silent) {
|
|
364
399
|
let pending = PENDING2.get(subject);
|
|
365
400
|
if (!pending) {
|
|
366
401
|
PENDING2.set(subject, pending = /* @__PURE__ */ new Set());
|
|
@@ -374,39 +409,11 @@ function push(subject, key2, silent) {
|
|
|
374
409
|
if (!silent)
|
|
375
410
|
emit(subject, key2);
|
|
376
411
|
}
|
|
377
|
-
|
|
378
|
-
function assign(to, values) {
|
|
412
|
+
function assign(to, values2) {
|
|
379
413
|
const methods = METHODS.get(to.constructor);
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
to[key2] = values[key2];
|
|
384
|
-
}
|
|
385
|
-
function bindMethods(type) {
|
|
386
|
-
let keys2 = METHODS.get(type);
|
|
387
|
-
if (!keys2) {
|
|
388
|
-
METHODS.set(type, keys2 = bindMethods(Object.getPrototypeOf(type)).slice());
|
|
389
|
-
const desc = Object.getOwnPropertyDescriptors(type.prototype);
|
|
390
|
-
for (const key2 in desc)
|
|
391
|
-
if (key2 != "constructor" && "value" in desc[key2]) {
|
|
392
|
-
let bind2 = function(method) {
|
|
393
|
-
const value2 = method.bind(this.is);
|
|
394
|
-
METHOD.set(value2, method);
|
|
395
|
-
define(this.is, key2, { value: value2, writable: true });
|
|
396
|
-
return value2;
|
|
397
|
-
};
|
|
398
|
-
var bind = bind2;
|
|
399
|
-
let { value } = desc[key2];
|
|
400
|
-
keys2.push(key2);
|
|
401
|
-
Object.defineProperty(type.prototype, key2, {
|
|
402
|
-
set: bind2,
|
|
403
|
-
get() {
|
|
404
|
-
return this.hasOwnProperty(key2) ? value : bind2.call(this, value);
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
return keys2;
|
|
414
|
+
for (const key2 in values2)
|
|
415
|
+
if (key2 in to || methods.has(key2))
|
|
416
|
+
to[key2] = values2[key2];
|
|
410
417
|
}
|
|
411
418
|
function uid() {
|
|
412
419
|
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
@@ -473,7 +480,7 @@ var Context = class _Context {
|
|
|
473
480
|
this.layer.clear();
|
|
474
481
|
}
|
|
475
482
|
include(inputs, forEach) {
|
|
476
|
-
const
|
|
483
|
+
const init2 = /* @__PURE__ */ new Map();
|
|
477
484
|
Object.entries(inputs).forEach(([K, V]) => {
|
|
478
485
|
if (!(Model.is(V) || V instanceof Model))
|
|
479
486
|
throw new Error(`Context can only include Model or instance but got ${V}${K && " as " + K}.`);
|
|
@@ -484,21 +491,21 @@ var Context = class _Context {
|
|
|
484
491
|
if (!exists) {
|
|
485
492
|
const instance = this.add(input);
|
|
486
493
|
this.layer.set(key2, input);
|
|
487
|
-
|
|
494
|
+
init2.set(instance, true);
|
|
488
495
|
} else if (exists !== input) {
|
|
489
496
|
this.pop();
|
|
490
497
|
this.id = uid();
|
|
491
498
|
this.include(inputs);
|
|
492
499
|
}
|
|
493
500
|
}
|
|
494
|
-
for (const [model, explicit] of
|
|
501
|
+
for (const [model, explicit] of init2) {
|
|
495
502
|
model.set();
|
|
496
503
|
if (forEach)
|
|
497
504
|
forEach(model, explicit);
|
|
498
505
|
for (const [_key, value] of model)
|
|
499
506
|
if (PARENT.get(value) === model) {
|
|
500
507
|
this.add(value, true);
|
|
501
|
-
|
|
508
|
+
init2.set(value, false);
|
|
502
509
|
}
|
|
503
510
|
}
|
|
504
511
|
}
|
|
@@ -563,38 +570,37 @@ function use(arg1, arg2) {
|
|
|
563
570
|
INSTRUCT.set(token, arg1);
|
|
564
571
|
return token;
|
|
565
572
|
}
|
|
566
|
-
Model.on((_,
|
|
567
|
-
const state = STATE.get(
|
|
568
|
-
const
|
|
569
|
-
|
|
570
|
-
const { value } = props[key2];
|
|
573
|
+
Model.on((_, model) => {
|
|
574
|
+
const state = STATE.get(model);
|
|
575
|
+
for (const key2 in model) {
|
|
576
|
+
const { value } = Object.getOwnPropertyDescriptor(model, key2);
|
|
571
577
|
const instruction = INSTRUCT.get(value);
|
|
572
578
|
if (!instruction) {
|
|
573
579
|
if (value instanceof Model && key2 !== "is")
|
|
574
|
-
update(
|
|
580
|
+
update(model, key2, value);
|
|
575
581
|
continue;
|
|
576
582
|
}
|
|
577
583
|
INSTRUCT.delete(value);
|
|
578
|
-
delete
|
|
579
|
-
const output = instruction.call(
|
|
584
|
+
delete model[key2];
|
|
585
|
+
const output = instruction.call(model, key2, model, state);
|
|
580
586
|
if (!output)
|
|
581
587
|
continue;
|
|
582
588
|
const desc = typeof output == "object" ? output : { get: output };
|
|
583
589
|
if ("value" in desc)
|
|
584
590
|
state[key2] = desc.value;
|
|
585
|
-
Object.defineProperty(
|
|
591
|
+
Object.defineProperty(model, key2, {
|
|
586
592
|
enumerable: desc.enumerable !== false,
|
|
587
593
|
get() {
|
|
588
594
|
return watch(
|
|
589
595
|
this,
|
|
590
596
|
key2,
|
|
591
|
-
typeof desc.get == "function" ? desc.get(this) : fetch(
|
|
597
|
+
typeof desc.get == "function" ? desc.get(this) : fetch(model, key2, desc.get)
|
|
592
598
|
);
|
|
593
599
|
},
|
|
594
600
|
set(next) {
|
|
595
601
|
if (desc.set === false)
|
|
596
|
-
throw new Error(`${
|
|
597
|
-
update(
|
|
602
|
+
throw new Error(`${model}.${key2} is read-only.`);
|
|
603
|
+
update(model, key2, next, desc.set);
|
|
598
604
|
}
|
|
599
605
|
});
|
|
600
606
|
}
|
|
@@ -642,7 +648,7 @@ function get(arg0, arg1) {
|
|
|
642
648
|
return (didUpdate) => {
|
|
643
649
|
if (didUpdate) {
|
|
644
650
|
STALE.add(compute2);
|
|
645
|
-
|
|
651
|
+
event(subject, key2, true);
|
|
646
652
|
}
|
|
647
653
|
};
|
|
648
654
|
});
|
|
@@ -734,7 +740,7 @@ function set(value, argument) {
|
|
|
734
740
|
return use((key2, subject) => {
|
|
735
741
|
const output = {};
|
|
736
742
|
if (typeof value == "function" || value instanceof Promise) {
|
|
737
|
-
let
|
|
743
|
+
let init3 = function() {
|
|
738
744
|
if (typeof value == "function")
|
|
739
745
|
try {
|
|
740
746
|
value = attempt(value.bind(subject, key2));
|
|
@@ -758,11 +764,11 @@ function set(value, argument) {
|
|
|
758
764
|
if (0 in arguments)
|
|
759
765
|
return subject[key2];
|
|
760
766
|
};
|
|
761
|
-
var
|
|
767
|
+
var init2 = init3;
|
|
762
768
|
if (argument)
|
|
763
|
-
|
|
769
|
+
init3();
|
|
764
770
|
else
|
|
765
|
-
output.get =
|
|
771
|
+
output.get = init3;
|
|
766
772
|
} else if (value !== void 0)
|
|
767
773
|
output.value = value;
|
|
768
774
|
if (typeof argument == "function") {
|
package/package.json
CHANGED