@expressive/mvc 0.51.2 → 0.52.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 +17 -7
- package/dist/index.js +143 -133
- package/dist/index.mjs +143 -133
- 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;
|
|
@@ -8,7 +7,7 @@ declare namespace Model {
|
|
|
8
7
|
* Model constructor callback - is called when Model finishes intializing.
|
|
9
8
|
* Returned function will call 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 */
|
|
@@ -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 controller.
|
|
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 controller 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
|
/**
|
|
@@ -167,6 +174,9 @@ declare abstract class Model {
|
|
|
167
174
|
/**
|
|
168
175
|
* Update mulitple properties at once. Merges argument with current state.
|
|
169
176
|
* Properties which are not managed by this controller will be ignored.
|
|
177
|
+
*
|
|
178
|
+
* @param assign - Object with properties to update.
|
|
179
|
+
* @returns Promise which resolves an array of keys which were updated.
|
|
170
180
|
*/
|
|
171
181
|
set(assign: Model.Assign<this>): PromiseLike<Model.Event<this>[]> | undefined;
|
|
172
182
|
/**
|
package/dist/index.js
CHANGED
|
@@ -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
|
-
|
|
169
|
-
|
|
170
|
-
|
|
169
|
+
ID.set(this, `${this.constructor}-${uid()}`);
|
|
170
|
+
STATE.set(this, {});
|
|
171
|
+
prepare(this);
|
|
171
172
|
define(this, "is", { value: this });
|
|
172
|
-
|
|
173
|
-
NAMES.set(this, `${Type}-${uid()}`);
|
|
174
|
-
for (const arg of args)
|
|
175
|
-
if (typeof arg == "string")
|
|
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
|
-
});
|
|
173
|
+
apply(this, [...args, init]);
|
|
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) => {
|
|
@@ -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 { key: key2, value } of entries(type2.prototype)) {
|
|
304
|
+
let set3 = function(method) {
|
|
305
|
+
const value2 = method.bind(this.is);
|
|
306
|
+
METHOD.set(value2, method);
|
|
307
|
+
define(this.is, key2, { value: value2, writable: true });
|
|
308
|
+
return value2;
|
|
309
|
+
};
|
|
310
|
+
var set2 = set3;
|
|
311
|
+
if (!value || key2 == "constructor")
|
|
312
|
+
continue;
|
|
313
|
+
keys2.add(key2);
|
|
314
|
+
Object.defineProperty(type2.prototype, key2, {
|
|
315
|
+
set: set3,
|
|
316
|
+
get() {
|
|
317
|
+
return this.hasOwnProperty(key2) ? value : set3.call(this, value);
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function apply(model, args) {
|
|
324
|
+
for (const arg of args)
|
|
325
|
+
if (typeof arg == "string")
|
|
326
|
+
ID.set(model, arg);
|
|
327
|
+
addListener(model, () => {
|
|
328
|
+
const done = /* @__PURE__ */ new Set();
|
|
329
|
+
for (const arg of args) {
|
|
330
|
+
const use2 = typeof arg == "function" ? arg.call(model, model) : arg;
|
|
331
|
+
if (use2 instanceof Promise)
|
|
332
|
+
use2.catch((err) => {
|
|
333
|
+
console.error(`Async error in constructor for ${model}:`);
|
|
334
|
+
console.error(err);
|
|
335
|
+
});
|
|
336
|
+
else if (typeof use2 == "object")
|
|
337
|
+
assign(model, use2);
|
|
338
|
+
else if (typeof use2 == "function")
|
|
339
|
+
done.add(use2);
|
|
340
|
+
}
|
|
341
|
+
addListener(model, () => {
|
|
342
|
+
done.forEach((x) => x());
|
|
343
|
+
}, null);
|
|
344
|
+
return null;
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
function init(model) {
|
|
348
|
+
const state = STATE.get(model);
|
|
349
|
+
if (!PARENT.has(model))
|
|
350
|
+
PARENT.set(model, null);
|
|
351
|
+
for (const key2 in model) {
|
|
352
|
+
const desc = Object.getOwnPropertyDescriptor(model, key2);
|
|
353
|
+
if ("value" in desc) {
|
|
354
|
+
update(model, key2, desc.value, true);
|
|
355
|
+
define(model, key2, {
|
|
356
|
+
configurable: false,
|
|
357
|
+
set: (x) => update(model, key2, x),
|
|
358
|
+
get() {
|
|
359
|
+
return watch(this, key2, state[key2]);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return () => {
|
|
365
|
+
for (const [_, value] of model)
|
|
366
|
+
if (value instanceof Model && PARENT.get(value) === model)
|
|
367
|
+
value.set(null);
|
|
368
|
+
Object.freeze(state);
|
|
369
|
+
};
|
|
370
|
+
}
|
|
350
371
|
function fetch(subject, property, required) {
|
|
351
372
|
const state = STATE.get(subject);
|
|
352
373
|
if (property in state || required === false) {
|
|
@@ -392,9 +413,9 @@ function update(subject, key2, value, arg) {
|
|
|
392
413
|
}
|
|
393
414
|
state[key2] = value;
|
|
394
415
|
if (arg !== true)
|
|
395
|
-
|
|
416
|
+
event(subject, key2);
|
|
396
417
|
}
|
|
397
|
-
function
|
|
418
|
+
function event(subject, key2, silent) {
|
|
398
419
|
let pending = PENDING2.get(subject);
|
|
399
420
|
if (!pending) {
|
|
400
421
|
PENDING2.set(subject, pending = /* @__PURE__ */ new Set());
|
|
@@ -408,43 +429,34 @@ function push(subject, key2, silent) {
|
|
|
408
429
|
if (!silent)
|
|
409
430
|
emit(subject, key2);
|
|
410
431
|
}
|
|
411
|
-
|
|
412
|
-
function assign(to, values) {
|
|
432
|
+
function assign(to, values2) {
|
|
413
433
|
const methods = METHODS.get(to.constructor);
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
to[key2] = values[key2];
|
|
434
|
+
for (const key2 in values2)
|
|
435
|
+
if (key2 in to || methods.has(key2))
|
|
436
|
+
to[key2] = values2[key2];
|
|
418
437
|
}
|
|
419
|
-
function
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
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
|
-
}
|
|
438
|
+
function values(model) {
|
|
439
|
+
const values2 = {};
|
|
440
|
+
const current = !EXPORT && (EXPORT = /* @__PURE__ */ new Map([[model, values2]]));
|
|
441
|
+
for (let [key2, value] of model) {
|
|
442
|
+
if (EXPORT.has(value))
|
|
443
|
+
value = EXPORT.get(value);
|
|
444
|
+
else if (value && typeof value.get === "function")
|
|
445
|
+
EXPORT.set(value, value = value.get());
|
|
446
|
+
values2[key2] = value;
|
|
442
447
|
}
|
|
443
|
-
|
|
448
|
+
if (current)
|
|
449
|
+
EXPORT = void 0;
|
|
450
|
+
return Object.freeze(values2);
|
|
444
451
|
}
|
|
445
452
|
function uid() {
|
|
446
453
|
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
447
454
|
}
|
|
455
|
+
function entries(object) {
|
|
456
|
+
return Object.entries(
|
|
457
|
+
Object.getOwnPropertyDescriptors(object)
|
|
458
|
+
).map(([key2, desc]) => ({ key: key2, ...desc }));
|
|
459
|
+
}
|
|
448
460
|
|
|
449
461
|
// src/context.ts
|
|
450
462
|
var Register = /* @__PURE__ */ new WeakMap();
|
|
@@ -507,7 +519,7 @@ var Context = class _Context {
|
|
|
507
519
|
this.layer.clear();
|
|
508
520
|
}
|
|
509
521
|
include(inputs, forEach) {
|
|
510
|
-
const
|
|
522
|
+
const init2 = /* @__PURE__ */ new Map();
|
|
511
523
|
Object.entries(inputs).forEach(([K, V]) => {
|
|
512
524
|
if (!(Model.is(V) || V instanceof Model))
|
|
513
525
|
throw new Error(`Context can only include Model or instance but got ${V}${K && " as " + K}.`);
|
|
@@ -518,21 +530,21 @@ var Context = class _Context {
|
|
|
518
530
|
if (!exists) {
|
|
519
531
|
const instance = this.add(input);
|
|
520
532
|
this.layer.set(key2, input);
|
|
521
|
-
|
|
533
|
+
init2.set(instance, true);
|
|
522
534
|
} else if (exists !== input) {
|
|
523
535
|
this.pop();
|
|
524
536
|
this.id = uid();
|
|
525
537
|
this.include(inputs);
|
|
526
538
|
}
|
|
527
539
|
}
|
|
528
|
-
for (const [model, explicit] of
|
|
540
|
+
for (const [model, explicit] of init2) {
|
|
529
541
|
model.set();
|
|
530
542
|
if (forEach)
|
|
531
543
|
forEach(model, explicit);
|
|
532
544
|
for (const [_key, value] of model)
|
|
533
545
|
if (PARENT.get(value) === model) {
|
|
534
546
|
this.add(value, true);
|
|
535
|
-
|
|
547
|
+
init2.set(value, false);
|
|
536
548
|
}
|
|
537
549
|
}
|
|
538
550
|
}
|
|
@@ -597,38 +609,36 @@ function use(arg1, arg2) {
|
|
|
597
609
|
INSTRUCT.set(token, arg1);
|
|
598
610
|
return token;
|
|
599
611
|
}
|
|
600
|
-
Model.on((_,
|
|
601
|
-
const state = STATE.get(
|
|
602
|
-
const
|
|
603
|
-
for (const key2 in props) {
|
|
604
|
-
const { value } = props[key2];
|
|
612
|
+
Model.on((_, model) => {
|
|
613
|
+
const state = STATE.get(model);
|
|
614
|
+
for (const { key: key2, value } of entries(model)) {
|
|
605
615
|
const instruction = INSTRUCT.get(value);
|
|
606
616
|
if (!instruction) {
|
|
607
617
|
if (value instanceof Model && key2 !== "is")
|
|
608
|
-
update(
|
|
618
|
+
update(model, key2, value);
|
|
609
619
|
continue;
|
|
610
620
|
}
|
|
611
621
|
INSTRUCT.delete(value);
|
|
612
|
-
delete
|
|
613
|
-
const output = instruction.call(
|
|
622
|
+
delete model[key2];
|
|
623
|
+
const output = instruction.call(model, key2, model, state);
|
|
614
624
|
if (!output)
|
|
615
625
|
continue;
|
|
616
626
|
const desc = typeof output == "object" ? output : { get: output };
|
|
617
627
|
if ("value" in desc)
|
|
618
628
|
state[key2] = desc.value;
|
|
619
|
-
Object.defineProperty(
|
|
629
|
+
Object.defineProperty(model, key2, {
|
|
620
630
|
enumerable: desc.enumerable !== false,
|
|
621
631
|
get() {
|
|
622
632
|
return watch(
|
|
623
633
|
this,
|
|
624
634
|
key2,
|
|
625
|
-
typeof desc.get == "function" ? desc.get(this) : fetch(
|
|
635
|
+
typeof desc.get == "function" ? desc.get(this) : fetch(model, key2, desc.get)
|
|
626
636
|
);
|
|
627
637
|
},
|
|
628
638
|
set(next) {
|
|
629
639
|
if (desc.set === false)
|
|
630
|
-
throw new Error(`${
|
|
631
|
-
update(
|
|
640
|
+
throw new Error(`${model}.${key2} is read-only.`);
|
|
641
|
+
update(model, key2, next, desc.set);
|
|
632
642
|
}
|
|
633
643
|
});
|
|
634
644
|
}
|
|
@@ -676,7 +686,7 @@ function get(arg0, arg1) {
|
|
|
676
686
|
return (didUpdate) => {
|
|
677
687
|
if (didUpdate) {
|
|
678
688
|
STALE.add(compute2);
|
|
679
|
-
|
|
689
|
+
event(subject, key2, true);
|
|
680
690
|
}
|
|
681
691
|
};
|
|
682
692
|
});
|
|
@@ -768,7 +778,7 @@ function set(value, argument) {
|
|
|
768
778
|
return use((key2, subject) => {
|
|
769
779
|
const output = {};
|
|
770
780
|
if (typeof value == "function" || value instanceof Promise) {
|
|
771
|
-
let
|
|
781
|
+
let init3 = function() {
|
|
772
782
|
if (typeof value == "function")
|
|
773
783
|
try {
|
|
774
784
|
value = attempt(value.bind(subject, key2));
|
|
@@ -792,11 +802,11 @@ function set(value, argument) {
|
|
|
792
802
|
if (0 in arguments)
|
|
793
803
|
return subject[key2];
|
|
794
804
|
};
|
|
795
|
-
var
|
|
805
|
+
var init2 = init3;
|
|
796
806
|
if (argument)
|
|
797
|
-
|
|
807
|
+
init3();
|
|
798
808
|
else
|
|
799
|
-
output.get =
|
|
809
|
+
output.get = init3;
|
|
800
810
|
} else if (value !== void 0)
|
|
801
811
|
output.value = value;
|
|
802
812
|
if (typeof argument == "function") {
|
package/dist/index.mjs
CHANGED
|
@@ -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
|
-
|
|
135
|
-
|
|
136
|
-
|
|
135
|
+
ID.set(this, `${this.constructor}-${uid()}`);
|
|
136
|
+
STATE.set(this, {});
|
|
137
|
+
prepare(this);
|
|
137
138
|
define(this, "is", { value: this });
|
|
138
|
-
|
|
139
|
-
NAMES.set(this, `${Type}-${uid()}`);
|
|
140
|
-
for (const arg of args)
|
|
141
|
-
if (typeof arg == "string")
|
|
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
|
-
});
|
|
139
|
+
apply(this, [...args, init]);
|
|
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) => {
|
|
@@ -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 { key: key2, value } of entries(type2.prototype)) {
|
|
270
|
+
let set3 = function(method) {
|
|
271
|
+
const value2 = method.bind(this.is);
|
|
272
|
+
METHOD.set(value2, method);
|
|
273
|
+
define(this.is, key2, { value: value2, writable: true });
|
|
274
|
+
return value2;
|
|
275
|
+
};
|
|
276
|
+
var set2 = set3;
|
|
277
|
+
if (!value || key2 == "constructor")
|
|
278
|
+
continue;
|
|
279
|
+
keys2.add(key2);
|
|
280
|
+
Object.defineProperty(type2.prototype, key2, {
|
|
281
|
+
set: set3,
|
|
282
|
+
get() {
|
|
283
|
+
return this.hasOwnProperty(key2) ? value : set3.call(this, value);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function apply(model, args) {
|
|
290
|
+
for (const arg of args)
|
|
291
|
+
if (typeof arg == "string")
|
|
292
|
+
ID.set(model, arg);
|
|
293
|
+
addListener(model, () => {
|
|
294
|
+
const done = /* @__PURE__ */ new Set();
|
|
295
|
+
for (const arg of args) {
|
|
296
|
+
const use2 = typeof arg == "function" ? arg.call(model, model) : arg;
|
|
297
|
+
if (use2 instanceof Promise)
|
|
298
|
+
use2.catch((err) => {
|
|
299
|
+
console.error(`Async error in constructor for ${model}:`);
|
|
300
|
+
console.error(err);
|
|
301
|
+
});
|
|
302
|
+
else if (typeof use2 == "object")
|
|
303
|
+
assign(model, use2);
|
|
304
|
+
else if (typeof use2 == "function")
|
|
305
|
+
done.add(use2);
|
|
306
|
+
}
|
|
307
|
+
addListener(model, () => {
|
|
308
|
+
done.forEach((x) => x());
|
|
309
|
+
}, null);
|
|
310
|
+
return null;
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
function init(model) {
|
|
314
|
+
const state = STATE.get(model);
|
|
315
|
+
if (!PARENT.has(model))
|
|
316
|
+
PARENT.set(model, null);
|
|
317
|
+
for (const key2 in model) {
|
|
318
|
+
const desc = Object.getOwnPropertyDescriptor(model, key2);
|
|
319
|
+
if ("value" in desc) {
|
|
320
|
+
update(model, key2, desc.value, true);
|
|
321
|
+
define(model, key2, {
|
|
322
|
+
configurable: false,
|
|
323
|
+
set: (x) => update(model, key2, x),
|
|
324
|
+
get() {
|
|
325
|
+
return watch(this, key2, state[key2]);
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return () => {
|
|
331
|
+
for (const [_, value] of model)
|
|
332
|
+
if (value instanceof Model && PARENT.get(value) === model)
|
|
333
|
+
value.set(null);
|
|
334
|
+
Object.freeze(state);
|
|
335
|
+
};
|
|
336
|
+
}
|
|
316
337
|
function fetch(subject, property, required) {
|
|
317
338
|
const state = STATE.get(subject);
|
|
318
339
|
if (property in state || required === false) {
|
|
@@ -358,9 +379,9 @@ function update(subject, key2, value, arg) {
|
|
|
358
379
|
}
|
|
359
380
|
state[key2] = value;
|
|
360
381
|
if (arg !== true)
|
|
361
|
-
|
|
382
|
+
event(subject, key2);
|
|
362
383
|
}
|
|
363
|
-
function
|
|
384
|
+
function event(subject, key2, silent) {
|
|
364
385
|
let pending = PENDING2.get(subject);
|
|
365
386
|
if (!pending) {
|
|
366
387
|
PENDING2.set(subject, pending = /* @__PURE__ */ new Set());
|
|
@@ -374,43 +395,34 @@ function push(subject, key2, silent) {
|
|
|
374
395
|
if (!silent)
|
|
375
396
|
emit(subject, key2);
|
|
376
397
|
}
|
|
377
|
-
|
|
378
|
-
function assign(to, values) {
|
|
398
|
+
function assign(to, values2) {
|
|
379
399
|
const methods = METHODS.get(to.constructor);
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
to[key2] = values[key2];
|
|
400
|
+
for (const key2 in values2)
|
|
401
|
+
if (key2 in to || methods.has(key2))
|
|
402
|
+
to[key2] = values2[key2];
|
|
384
403
|
}
|
|
385
|
-
function
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
}
|
|
404
|
+
function values(model) {
|
|
405
|
+
const values2 = {};
|
|
406
|
+
const current = !EXPORT && (EXPORT = /* @__PURE__ */ new Map([[model, values2]]));
|
|
407
|
+
for (let [key2, value] of model) {
|
|
408
|
+
if (EXPORT.has(value))
|
|
409
|
+
value = EXPORT.get(value);
|
|
410
|
+
else if (value && typeof value.get === "function")
|
|
411
|
+
EXPORT.set(value, value = value.get());
|
|
412
|
+
values2[key2] = value;
|
|
408
413
|
}
|
|
409
|
-
|
|
414
|
+
if (current)
|
|
415
|
+
EXPORT = void 0;
|
|
416
|
+
return Object.freeze(values2);
|
|
410
417
|
}
|
|
411
418
|
function uid() {
|
|
412
419
|
return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
|
|
413
420
|
}
|
|
421
|
+
function entries(object) {
|
|
422
|
+
return Object.entries(
|
|
423
|
+
Object.getOwnPropertyDescriptors(object)
|
|
424
|
+
).map(([key2, desc]) => ({ key: key2, ...desc }));
|
|
425
|
+
}
|
|
414
426
|
|
|
415
427
|
// src/context.ts
|
|
416
428
|
var Register = /* @__PURE__ */ new WeakMap();
|
|
@@ -473,7 +485,7 @@ var Context = class _Context {
|
|
|
473
485
|
this.layer.clear();
|
|
474
486
|
}
|
|
475
487
|
include(inputs, forEach) {
|
|
476
|
-
const
|
|
488
|
+
const init2 = /* @__PURE__ */ new Map();
|
|
477
489
|
Object.entries(inputs).forEach(([K, V]) => {
|
|
478
490
|
if (!(Model.is(V) || V instanceof Model))
|
|
479
491
|
throw new Error(`Context can only include Model or instance but got ${V}${K && " as " + K}.`);
|
|
@@ -484,21 +496,21 @@ var Context = class _Context {
|
|
|
484
496
|
if (!exists) {
|
|
485
497
|
const instance = this.add(input);
|
|
486
498
|
this.layer.set(key2, input);
|
|
487
|
-
|
|
499
|
+
init2.set(instance, true);
|
|
488
500
|
} else if (exists !== input) {
|
|
489
501
|
this.pop();
|
|
490
502
|
this.id = uid();
|
|
491
503
|
this.include(inputs);
|
|
492
504
|
}
|
|
493
505
|
}
|
|
494
|
-
for (const [model, explicit] of
|
|
506
|
+
for (const [model, explicit] of init2) {
|
|
495
507
|
model.set();
|
|
496
508
|
if (forEach)
|
|
497
509
|
forEach(model, explicit);
|
|
498
510
|
for (const [_key, value] of model)
|
|
499
511
|
if (PARENT.get(value) === model) {
|
|
500
512
|
this.add(value, true);
|
|
501
|
-
|
|
513
|
+
init2.set(value, false);
|
|
502
514
|
}
|
|
503
515
|
}
|
|
504
516
|
}
|
|
@@ -563,38 +575,36 @@ function use(arg1, arg2) {
|
|
|
563
575
|
INSTRUCT.set(token, arg1);
|
|
564
576
|
return token;
|
|
565
577
|
}
|
|
566
|
-
Model.on((_,
|
|
567
|
-
const state = STATE.get(
|
|
568
|
-
const
|
|
569
|
-
for (const key2 in props) {
|
|
570
|
-
const { value } = props[key2];
|
|
578
|
+
Model.on((_, model) => {
|
|
579
|
+
const state = STATE.get(model);
|
|
580
|
+
for (const { key: key2, value } of entries(model)) {
|
|
571
581
|
const instruction = INSTRUCT.get(value);
|
|
572
582
|
if (!instruction) {
|
|
573
583
|
if (value instanceof Model && key2 !== "is")
|
|
574
|
-
update(
|
|
584
|
+
update(model, key2, value);
|
|
575
585
|
continue;
|
|
576
586
|
}
|
|
577
587
|
INSTRUCT.delete(value);
|
|
578
|
-
delete
|
|
579
|
-
const output = instruction.call(
|
|
588
|
+
delete model[key2];
|
|
589
|
+
const output = instruction.call(model, key2, model, state);
|
|
580
590
|
if (!output)
|
|
581
591
|
continue;
|
|
582
592
|
const desc = typeof output == "object" ? output : { get: output };
|
|
583
593
|
if ("value" in desc)
|
|
584
594
|
state[key2] = desc.value;
|
|
585
|
-
Object.defineProperty(
|
|
595
|
+
Object.defineProperty(model, key2, {
|
|
586
596
|
enumerable: desc.enumerable !== false,
|
|
587
597
|
get() {
|
|
588
598
|
return watch(
|
|
589
599
|
this,
|
|
590
600
|
key2,
|
|
591
|
-
typeof desc.get == "function" ? desc.get(this) : fetch(
|
|
601
|
+
typeof desc.get == "function" ? desc.get(this) : fetch(model, key2, desc.get)
|
|
592
602
|
);
|
|
593
603
|
},
|
|
594
604
|
set(next) {
|
|
595
605
|
if (desc.set === false)
|
|
596
|
-
throw new Error(`${
|
|
597
|
-
update(
|
|
606
|
+
throw new Error(`${model}.${key2} is read-only.`);
|
|
607
|
+
update(model, key2, next, desc.set);
|
|
598
608
|
}
|
|
599
609
|
});
|
|
600
610
|
}
|
|
@@ -642,7 +652,7 @@ function get(arg0, arg1) {
|
|
|
642
652
|
return (didUpdate) => {
|
|
643
653
|
if (didUpdate) {
|
|
644
654
|
STALE.add(compute2);
|
|
645
|
-
|
|
655
|
+
event(subject, key2, true);
|
|
646
656
|
}
|
|
647
657
|
};
|
|
648
658
|
});
|
|
@@ -734,7 +744,7 @@ function set(value, argument) {
|
|
|
734
744
|
return use((key2, subject) => {
|
|
735
745
|
const output = {};
|
|
736
746
|
if (typeof value == "function" || value instanceof Promise) {
|
|
737
|
-
let
|
|
747
|
+
let init3 = function() {
|
|
738
748
|
if (typeof value == "function")
|
|
739
749
|
try {
|
|
740
750
|
value = attempt(value.bind(subject, key2));
|
|
@@ -758,11 +768,11 @@ function set(value, argument) {
|
|
|
758
768
|
if (0 in arguments)
|
|
759
769
|
return subject[key2];
|
|
760
770
|
};
|
|
761
|
-
var
|
|
771
|
+
var init2 = init3;
|
|
762
772
|
if (argument)
|
|
763
|
-
|
|
773
|
+
init3();
|
|
764
774
|
else
|
|
765
|
-
output.get =
|
|
775
|
+
output.get = init3;
|
|
766
776
|
} else if (value !== void 0)
|
|
767
777
|
output.value = value;
|
|
768
778
|
if (typeof argument == "function") {
|
package/package.json
CHANGED