@expressive/mvc 0.38.0 → 0.40.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 +35 -15
- package/dist/index.js +197 -112
- package/dist/index.mjs +196 -112
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,13 @@ declare namespace Model {
|
|
|
64
64
|
* Optional returned callback will run when once upon first access.
|
|
65
65
|
*/
|
|
66
66
|
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;
|
|
67
|
+
/**
|
|
68
|
+
* Model constructor callback - is called when Model finishes intializing.
|
|
69
|
+
* Returned function will call when model is destroyed.
|
|
70
|
+
*/
|
|
71
|
+
type Callback = (() => void | (() => void));
|
|
72
|
+
/** Model constructor argument */
|
|
73
|
+
type Argument = string | Callback;
|
|
67
74
|
}
|
|
68
75
|
interface Model {
|
|
69
76
|
/**
|
|
@@ -73,7 +80,7 @@ interface Model {
|
|
|
73
80
|
is: this;
|
|
74
81
|
}
|
|
75
82
|
declare class Model {
|
|
76
|
-
constructor(arg?:
|
|
83
|
+
constructor(arg?: Model.Argument);
|
|
77
84
|
/** Pull current values from state. Flattens all models and exotic values recursively. */
|
|
78
85
|
get(): Model.State<this>;
|
|
79
86
|
/**
|
|
@@ -181,13 +188,14 @@ declare class Model {
|
|
|
181
188
|
* Register a callback to run when any instance of this Model is updated.
|
|
182
189
|
*/
|
|
183
190
|
static on<T extends Model>(this: Model.Type<T>, listener: Model.OnEvent<T>): () => boolean;
|
|
191
|
+
static at<T extends Model>(this: Model.Type<T>, from: Model, cb: (got: T | undefined) => void): void;
|
|
184
192
|
}
|
|
185
193
|
|
|
186
194
|
declare function add<T = any>(instruction: Model.Instruction): T;
|
|
187
195
|
|
|
188
196
|
declare namespace get {
|
|
189
|
-
type Function<T, S = any> = (
|
|
190
|
-
type Factory<
|
|
197
|
+
type Function<T, S = any> = (on: S, key: string) => T;
|
|
198
|
+
type Factory<T, S = any> = (this: S, key: string, thisArg: S) => T;
|
|
191
199
|
type Source<T extends Model = Model> = (resolve: (x: T) => void) => void;
|
|
192
200
|
}
|
|
193
201
|
/**
|
|
@@ -196,9 +204,9 @@ declare namespace get {
|
|
|
196
204
|
* will be made available to child upon this request.
|
|
197
205
|
*
|
|
198
206
|
* @param Type - Type of controller compatible with this class.
|
|
199
|
-
* @param
|
|
207
|
+
* @param expectParent - If true, will throw if Model is created without a parent.
|
|
200
208
|
*/
|
|
201
|
-
declare function get<T extends Model>(Type: Model.Type<T>,
|
|
209
|
+
declare function get<T extends Model>(Type: Model.Type<T>, asParent?: true): T;
|
|
202
210
|
/**
|
|
203
211
|
* Fetches and assigns the controller which spawned this host.
|
|
204
212
|
* When parent assigns an instance via `use()` directive, it
|
|
@@ -207,7 +215,7 @@ declare function get<T extends Model>(Type: Model.Type<T>, required?: true): T;
|
|
|
207
215
|
* @param Type - Type of controller compatible with this class.
|
|
208
216
|
* @param required - If false, property may be undefined. Otherwise will throw suspense.
|
|
209
217
|
*/
|
|
210
|
-
declare function get<T extends Model>(Type: Model.Type<T>, required
|
|
218
|
+
declare function get<T extends Model>(Type: Model.Type<T>, required?: false): T | undefined;
|
|
211
219
|
/**
|
|
212
220
|
* Implement a computed value from a foreign model. Output will be generated by provided function,
|
|
213
221
|
* where the foreign model will be passed to that function.
|
|
@@ -215,20 +223,22 @@ declare function get<T extends Model>(Type: Model.Type<T>, required: boolean): T
|
|
|
215
223
|
* @param source - Type of Model to fetch for computation.
|
|
216
224
|
* @param compute - Compute function. Will update automatically as input values change.
|
|
217
225
|
*/
|
|
218
|
-
declare function get<R, T extends Model>(Type: Model.Type<T>, compute:
|
|
226
|
+
declare function get<R, T extends Model>(Type: Model.Type<T>, compute: get.Function<R, T>): R;
|
|
219
227
|
/**
|
|
220
228
|
* Implement a computed value; output will be generated by provided function.
|
|
221
229
|
*
|
|
222
230
|
* @param source - Source model from which computed value will be a subscriber.
|
|
223
231
|
* @param compute - Compute function. Bound to a subscriber-proxy of source, returns output value. Will update automatically as input values change.
|
|
224
232
|
*/
|
|
225
|
-
declare function get<R, T extends Model>(source: T, compute:
|
|
233
|
+
declare function get<R, T extends Model>(source: T, compute: get.Function<R, T>): R;
|
|
226
234
|
/**
|
|
227
235
|
* Implement a computed value; output is returned by function from provided factory.
|
|
228
236
|
*
|
|
237
|
+
* Factory is bound to owner of property.
|
|
238
|
+
*
|
|
229
239
|
* @param compute - Factory function to generate a getter to subscribe dependancies.
|
|
230
240
|
*/
|
|
231
|
-
declare function get<R, T>(compute:
|
|
241
|
+
declare function get<R, T>(compute: get.Factory<R, T>): R;
|
|
232
242
|
|
|
233
243
|
declare namespace ref {
|
|
234
244
|
type Callback<T> = (argument: T) => ((next: T | null) => void) | Promise<void> | void | boolean;
|
|
@@ -345,19 +355,29 @@ declare function use<T extends Model>(model: T, ready?: (i: T) => void): T;
|
|
|
345
355
|
/** Create a managed object with observable entries. */
|
|
346
356
|
declare function use<T extends {}, O = use.Object<T>>(data: T, ready?: (object: O) => void): O;
|
|
347
357
|
|
|
358
|
+
declare namespace has {
|
|
359
|
+
type Callback<T = any> = (model: T) => void | boolean | (() => void);
|
|
360
|
+
}
|
|
361
|
+
declare function has<T extends Model>(type: Model.Type<T>, one: true): T;
|
|
362
|
+
declare function has<T extends Model>(type: Model.Type<T>, required: boolean): T | undefined;
|
|
363
|
+
declare function has<T extends Model>(type: Model.Type<T>, arg?: has.Callback<T>): Set<T>;
|
|
364
|
+
|
|
348
365
|
declare namespace Context {
|
|
349
366
|
type Input = Model | Model.New<Model> | Record<string | number, Model | Model.New<Model>>;
|
|
350
367
|
}
|
|
351
368
|
declare class Context {
|
|
352
|
-
static
|
|
353
|
-
|
|
354
|
-
protected
|
|
369
|
+
static request<T extends Model>(type: Model.Type<T>, from: Model, callback: (got: T) => void): void;
|
|
370
|
+
id: string;
|
|
371
|
+
protected downstream: WeakMap<Model.Type<Model>, symbol>;
|
|
372
|
+
protected upstream: WeakMap<Model.Type<Model>, symbol>;
|
|
355
373
|
protected layer: Map<string | number, Model | Model.Type<Model>>;
|
|
356
374
|
constructor(inputs?: Context.Input);
|
|
357
|
-
|
|
375
|
+
key(T: Model.Type, upstream?: boolean): keyof this;
|
|
376
|
+
has(model: Model): (() => void) | undefined;
|
|
358
377
|
get<T extends Model>(Type: Model.Type<T>): T | undefined;
|
|
359
378
|
include(inputs: Context.Input): Map<Model, boolean>;
|
|
360
|
-
|
|
379
|
+
put<T extends Model>(T: Model.New<T>, I: T | ((model: T) => void), implicit?: boolean, writable?: boolean): void;
|
|
380
|
+
add<T extends Model>(input: T | Model.New<T>, implicit?: boolean): T;
|
|
361
381
|
push(inputs?: Context.Input): this;
|
|
362
382
|
pop(): void;
|
|
363
383
|
}
|
|
@@ -379,4 +399,4 @@ declare global {
|
|
|
379
399
|
}
|
|
380
400
|
}
|
|
381
401
|
|
|
382
|
-
export { Context, Model, add, Model as default, get, ref, set, use };
|
|
402
|
+
export { Context, Model, add, Model as default, get, has, ref, set, use };
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ __export(src_exports, {
|
|
|
25
25
|
add: () => add,
|
|
26
26
|
default: () => Model,
|
|
27
27
|
get: () => get,
|
|
28
|
+
has: () => has,
|
|
28
29
|
ref: () => ref,
|
|
29
30
|
set: () => set,
|
|
30
31
|
use: () => use
|
|
@@ -153,6 +154,7 @@ var STATE = /* @__PURE__ */ new WeakMap();
|
|
|
153
154
|
var NOTIFY = /* @__PURE__ */ new WeakMap();
|
|
154
155
|
var PENDING2 = /* @__PURE__ */ new WeakMap();
|
|
155
156
|
var PARENT = /* @__PURE__ */ new WeakMap();
|
|
157
|
+
var METHOD = /* @__PURE__ */ new WeakMap();
|
|
156
158
|
var define = Object.defineProperty;
|
|
157
159
|
var Model = class _Model {
|
|
158
160
|
constructor(arg) {
|
|
@@ -165,6 +167,22 @@ var Model = class _Model {
|
|
|
165
167
|
new Set(NOTIFY.get(Type)).forEach((x) => addListener(this, x));
|
|
166
168
|
if (Type === _Model)
|
|
167
169
|
break;
|
|
170
|
+
const desc = Object.getOwnPropertyDescriptors(Type.prototype);
|
|
171
|
+
for (const key in desc) {
|
|
172
|
+
let { value } = desc[key];
|
|
173
|
+
if (typeof value == "function" && key !== "constructor")
|
|
174
|
+
Object.defineProperty(Type.prototype, key, {
|
|
175
|
+
get() {
|
|
176
|
+
const method = value.bind(this.is);
|
|
177
|
+
METHOD.set(method, value);
|
|
178
|
+
define(this.is, key, {
|
|
179
|
+
value: method,
|
|
180
|
+
configurable: false
|
|
181
|
+
});
|
|
182
|
+
return method;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
168
186
|
Type = Object.getPrototypeOf(Type);
|
|
169
187
|
}
|
|
170
188
|
addListener(this, () => {
|
|
@@ -295,6 +313,9 @@ var Model = class _Model {
|
|
|
295
313
|
notify.add(listener);
|
|
296
314
|
return () => notify.delete(listener);
|
|
297
315
|
}
|
|
316
|
+
static at(from, cb) {
|
|
317
|
+
throw new Error(`Using context requires an adapter. If you are only testing, define \`get.context\` to simulate one.`);
|
|
318
|
+
}
|
|
298
319
|
};
|
|
299
320
|
define(Model.prototype, "toString", {
|
|
300
321
|
value() {
|
|
@@ -412,111 +433,6 @@ Model.on((_, subject) => {
|
|
|
412
433
|
return null;
|
|
413
434
|
});
|
|
414
435
|
|
|
415
|
-
// src/context.ts
|
|
416
|
-
var Context = class {
|
|
417
|
-
constructor(inputs) {
|
|
418
|
-
this.table = /* @__PURE__ */ new WeakMap();
|
|
419
|
-
this.layer = /* @__PURE__ */ new Map();
|
|
420
|
-
if (inputs)
|
|
421
|
-
this.include(inputs);
|
|
422
|
-
}
|
|
423
|
-
static get() {
|
|
424
|
-
throw new Error(`Using context requires an adapter. If you are only testing, define \`get.context\` to simulate one.`);
|
|
425
|
-
}
|
|
426
|
-
has(T) {
|
|
427
|
-
let key = this.table.get(T);
|
|
428
|
-
if (!key) {
|
|
429
|
-
key = Symbol(T.name);
|
|
430
|
-
this.table.set(T, key);
|
|
431
|
-
}
|
|
432
|
-
return key;
|
|
433
|
-
}
|
|
434
|
-
get(Type) {
|
|
435
|
-
const result = this[this.has(Type)];
|
|
436
|
-
if (result === null)
|
|
437
|
-
throw new Error(`Did find ${Type} in context, but multiple were defined.`);
|
|
438
|
-
return result;
|
|
439
|
-
}
|
|
440
|
-
include(inputs) {
|
|
441
|
-
const init = /* @__PURE__ */ new Map();
|
|
442
|
-
if (typeof inputs == "function" || inputs instanceof Model)
|
|
443
|
-
inputs = { [0]: inputs };
|
|
444
|
-
else if (!inputs)
|
|
445
|
-
reject(inputs);
|
|
446
|
-
Object.entries(inputs).forEach(([K, V]) => {
|
|
447
|
-
if (!(Model.is(V) || V instanceof Model))
|
|
448
|
-
reject(`${V} as ${K}`);
|
|
449
|
-
});
|
|
450
|
-
for (const key in inputs) {
|
|
451
|
-
const input = inputs[key];
|
|
452
|
-
const exists = this.layer.get(key);
|
|
453
|
-
if (!exists) {
|
|
454
|
-
const instance = this.add(input);
|
|
455
|
-
this.layer.set(key, input);
|
|
456
|
-
init.set(instance, true);
|
|
457
|
-
} else if (exists !== input) {
|
|
458
|
-
this.pop();
|
|
459
|
-
this.key = uid();
|
|
460
|
-
return this.include(inputs);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
for (const [model] of init)
|
|
464
|
-
for (const [_key, value] of model)
|
|
465
|
-
if (PARENT.get(value) === model) {
|
|
466
|
-
this.add(value, true);
|
|
467
|
-
init.set(value, false);
|
|
468
|
-
}
|
|
469
|
-
return init;
|
|
470
|
-
}
|
|
471
|
-
add(input, implicit) {
|
|
472
|
-
let writable = true;
|
|
473
|
-
let T;
|
|
474
|
-
let I;
|
|
475
|
-
if (typeof input == "function") {
|
|
476
|
-
T = input;
|
|
477
|
-
I = input.new();
|
|
478
|
-
} else {
|
|
479
|
-
I = input;
|
|
480
|
-
T = I.constructor;
|
|
481
|
-
writable = false;
|
|
482
|
-
}
|
|
483
|
-
do {
|
|
484
|
-
const key = this.has(T);
|
|
485
|
-
const value = this.hasOwnProperty(key) ? null : I;
|
|
486
|
-
if (value || I !== this[key] && !implicit)
|
|
487
|
-
Object.defineProperty(this, key, {
|
|
488
|
-
configurable: true,
|
|
489
|
-
writable,
|
|
490
|
-
value
|
|
491
|
-
});
|
|
492
|
-
T = Object.getPrototypeOf(T);
|
|
493
|
-
} while (T !== Model);
|
|
494
|
-
return I;
|
|
495
|
-
}
|
|
496
|
-
push(inputs) {
|
|
497
|
-
const next = Object.create(this);
|
|
498
|
-
next.layer = /* @__PURE__ */ new Map();
|
|
499
|
-
if (inputs)
|
|
500
|
-
next.include(inputs);
|
|
501
|
-
return next;
|
|
502
|
-
}
|
|
503
|
-
pop() {
|
|
504
|
-
const items = /* @__PURE__ */ new Set();
|
|
505
|
-
for (const key of Object.getOwnPropertySymbols(this)) {
|
|
506
|
-
const entry = Object.getOwnPropertyDescriptor(this, key);
|
|
507
|
-
if (entry.writable && entry.value)
|
|
508
|
-
items.add(entry.value);
|
|
509
|
-
delete this[key];
|
|
510
|
-
}
|
|
511
|
-
for (const model of items)
|
|
512
|
-
model.set(null);
|
|
513
|
-
this.layer.clear();
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
function reject(argument) {
|
|
517
|
-
throw new Error(`Context can only include Model or instance but got ${argument}.`);
|
|
518
|
-
}
|
|
519
|
-
|
|
520
436
|
// src/instruction/get.ts
|
|
521
437
|
function get(arg0, arg1) {
|
|
522
438
|
return add((key, subject) => {
|
|
@@ -532,10 +448,9 @@ function get(arg0, arg1) {
|
|
|
532
448
|
if (arg1 === true)
|
|
533
449
|
throw new Error(`${from} may only exist as a child of type ${arg0}.`);
|
|
534
450
|
source = (resolve) => {
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
resolve(model);
|
|
451
|
+
arg0.at(from, (got) => {
|
|
452
|
+
if (got)
|
|
453
|
+
resolve(got);
|
|
539
454
|
else if (arg1 !== false)
|
|
540
455
|
throw new Error(`Required ${arg0} not found in context for ${from}.`);
|
|
541
456
|
});
|
|
@@ -544,8 +459,10 @@ function get(arg0, arg1) {
|
|
|
544
459
|
from = hasParent;
|
|
545
460
|
else
|
|
546
461
|
throw new Error(`New ${from} created as child of ${hasParent}, but must be instanceof ${arg0}.`);
|
|
547
|
-
} else if (typeof arg0 == "function")
|
|
548
|
-
|
|
462
|
+
} else if (typeof arg0 == "function") {
|
|
463
|
+
const fn = METHOD.get(arg0) || arg0;
|
|
464
|
+
arg1 = (p, k) => fn.call(p, k, p);
|
|
465
|
+
}
|
|
549
466
|
if (typeof arg1 == "function")
|
|
550
467
|
return compute(subject, key, source, arg1);
|
|
551
468
|
source((got) => subject.set(key, got));
|
|
@@ -575,7 +492,7 @@ function compute(subject, key, source, setter) {
|
|
|
575
492
|
function compute2(initial) {
|
|
576
493
|
let next;
|
|
577
494
|
try {
|
|
578
|
-
next = setter.call(proxy, proxy);
|
|
495
|
+
next = setter.call(proxy, proxy, key);
|
|
579
496
|
} catch (err) {
|
|
580
497
|
console.warn(`An exception was thrown while ${initial ? "initializing" : "refreshing"} ${subject}.${key}.`);
|
|
581
498
|
if (initial)
|
|
@@ -753,12 +670,180 @@ function use(value, argument) {
|
|
|
753
670
|
return output;
|
|
754
671
|
});
|
|
755
672
|
}
|
|
673
|
+
|
|
674
|
+
// src/context.ts
|
|
675
|
+
var Expects = /* @__PURE__ */ new WeakMap();
|
|
676
|
+
var Context = class {
|
|
677
|
+
constructor(inputs) {
|
|
678
|
+
this.downstream = /* @__PURE__ */ new WeakMap();
|
|
679
|
+
this.upstream = /* @__PURE__ */ new WeakMap();
|
|
680
|
+
this.layer = /* @__PURE__ */ new Map();
|
|
681
|
+
if (inputs)
|
|
682
|
+
this.include(inputs);
|
|
683
|
+
}
|
|
684
|
+
static request(type, from, callback) {
|
|
685
|
+
let map = Expects.get(from);
|
|
686
|
+
if (!map)
|
|
687
|
+
Expects.set(from, map = /* @__PURE__ */ new Map());
|
|
688
|
+
map.set(type, callback);
|
|
689
|
+
}
|
|
690
|
+
key(T, upstream) {
|
|
691
|
+
const table = upstream ? this.upstream : this.downstream;
|
|
692
|
+
let key = table.get(T);
|
|
693
|
+
if (!key) {
|
|
694
|
+
key = Symbol(T.name + (upstream ? " request" : ""));
|
|
695
|
+
table.set(T, key);
|
|
696
|
+
}
|
|
697
|
+
return key;
|
|
698
|
+
}
|
|
699
|
+
has(model) {
|
|
700
|
+
const key = this.key(model.constructor, true);
|
|
701
|
+
const result = this[key];
|
|
702
|
+
if (typeof result == "function")
|
|
703
|
+
return result(model);
|
|
704
|
+
}
|
|
705
|
+
get(Type) {
|
|
706
|
+
const result = this[this.key(Type)];
|
|
707
|
+
if (result === null)
|
|
708
|
+
throw new Error(`Did find ${Type} in context, but multiple were defined.`);
|
|
709
|
+
return result;
|
|
710
|
+
}
|
|
711
|
+
include(inputs) {
|
|
712
|
+
const init = /* @__PURE__ */ new Map();
|
|
713
|
+
if (typeof inputs == "function" || inputs instanceof Model)
|
|
714
|
+
inputs = { [0]: inputs };
|
|
715
|
+
else if (!inputs)
|
|
716
|
+
reject(inputs);
|
|
717
|
+
Object.entries(inputs).forEach(([K, V]) => {
|
|
718
|
+
if (!(Model.is(V) || V instanceof Model))
|
|
719
|
+
reject(`${V} as ${K}`);
|
|
720
|
+
});
|
|
721
|
+
for (const key in inputs) {
|
|
722
|
+
const input = inputs[key];
|
|
723
|
+
const exists = this.layer.get(key);
|
|
724
|
+
if (!exists) {
|
|
725
|
+
const instance = this.add(input);
|
|
726
|
+
this.layer.set(key, input);
|
|
727
|
+
init.set(instance, true);
|
|
728
|
+
} else if (exists !== input) {
|
|
729
|
+
this.pop();
|
|
730
|
+
this.id = uid();
|
|
731
|
+
return this.include(inputs);
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
for (const [model] of init) {
|
|
735
|
+
this.has(model);
|
|
736
|
+
const expects = Expects.get(model);
|
|
737
|
+
if (expects)
|
|
738
|
+
for (let [T, callback] of expects)
|
|
739
|
+
this.put(T, callback);
|
|
740
|
+
for (const [_key, value] of model)
|
|
741
|
+
if (PARENT.get(value) === model) {
|
|
742
|
+
this.add(value, true);
|
|
743
|
+
init.set(value, false);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
return init;
|
|
747
|
+
}
|
|
748
|
+
put(T, I, implicit, writable) {
|
|
749
|
+
do {
|
|
750
|
+
const key = this.key(T, typeof I == "function");
|
|
751
|
+
const value = this.hasOwnProperty(key) ? null : I;
|
|
752
|
+
if (value || this[key] !== I && !implicit)
|
|
753
|
+
Object.defineProperty(this, key, {
|
|
754
|
+
configurable: true,
|
|
755
|
+
writable,
|
|
756
|
+
value
|
|
757
|
+
});
|
|
758
|
+
T = Object.getPrototypeOf(T);
|
|
759
|
+
} while (T !== Model);
|
|
760
|
+
}
|
|
761
|
+
add(input, implicit) {
|
|
762
|
+
let writable = true;
|
|
763
|
+
let T;
|
|
764
|
+
let I;
|
|
765
|
+
if (typeof input == "function") {
|
|
766
|
+
T = input;
|
|
767
|
+
I = input.new();
|
|
768
|
+
} else {
|
|
769
|
+
I = input;
|
|
770
|
+
T = I.constructor;
|
|
771
|
+
writable = false;
|
|
772
|
+
}
|
|
773
|
+
this.put(T, I, implicit, writable);
|
|
774
|
+
return I;
|
|
775
|
+
}
|
|
776
|
+
push(inputs) {
|
|
777
|
+
const next = Object.create(this);
|
|
778
|
+
next.layer = /* @__PURE__ */ new Map();
|
|
779
|
+
if (inputs)
|
|
780
|
+
next.include(inputs);
|
|
781
|
+
return next;
|
|
782
|
+
}
|
|
783
|
+
pop() {
|
|
784
|
+
const items = /* @__PURE__ */ new Set();
|
|
785
|
+
for (const key of Object.getOwnPropertySymbols(this)) {
|
|
786
|
+
const entry = Object.getOwnPropertyDescriptor(this, key);
|
|
787
|
+
if (entry.writable && entry.value)
|
|
788
|
+
items.add(entry.value);
|
|
789
|
+
delete this[key];
|
|
790
|
+
}
|
|
791
|
+
for (const model of items)
|
|
792
|
+
model.set(null);
|
|
793
|
+
this.layer.clear();
|
|
794
|
+
}
|
|
795
|
+
};
|
|
796
|
+
function reject(argument) {
|
|
797
|
+
throw new Error(`Context can only include Model or instance but got ${argument}.`);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// src/instruction/has.ts
|
|
801
|
+
function has(type, argument) {
|
|
802
|
+
return add((key, subject, state) => {
|
|
803
|
+
if (typeof argument == "boolean") {
|
|
804
|
+
Context.request(type, subject, (model) => {
|
|
805
|
+
const remove = () => {
|
|
806
|
+
drop();
|
|
807
|
+
if (state[key] === model)
|
|
808
|
+
delete state[key];
|
|
809
|
+
};
|
|
810
|
+
subject.set(key, model);
|
|
811
|
+
const drop = model.get(null, remove);
|
|
812
|
+
return remove;
|
|
813
|
+
});
|
|
814
|
+
return { get: argument };
|
|
815
|
+
}
|
|
816
|
+
const children = /* @__PURE__ */ new Set();
|
|
817
|
+
Context.request(type, subject, (model) => {
|
|
818
|
+
if (children.has(model))
|
|
819
|
+
return;
|
|
820
|
+
const remove = typeof argument == "function" ? argument(model) : void 0;
|
|
821
|
+
if (remove === false)
|
|
822
|
+
return;
|
|
823
|
+
children.add(model);
|
|
824
|
+
subject.set(key);
|
|
825
|
+
const done = () => {
|
|
826
|
+
drop();
|
|
827
|
+
if (typeof remove == "function")
|
|
828
|
+
remove();
|
|
829
|
+
children.delete(model);
|
|
830
|
+
subject.set(key);
|
|
831
|
+
};
|
|
832
|
+
const drop = model.get(null, done);
|
|
833
|
+
return done;
|
|
834
|
+
});
|
|
835
|
+
return {
|
|
836
|
+
value: children
|
|
837
|
+
};
|
|
838
|
+
});
|
|
839
|
+
}
|
|
756
840
|
// Annotate the CommonJS export names for ESM import in node:
|
|
757
841
|
0 && (module.exports = {
|
|
758
842
|
Context,
|
|
759
843
|
Model,
|
|
760
844
|
add,
|
|
761
845
|
get,
|
|
846
|
+
has,
|
|
762
847
|
ref,
|
|
763
848
|
set,
|
|
764
849
|
use
|
package/dist/index.mjs
CHANGED
|
@@ -120,6 +120,7 @@ var STATE = /* @__PURE__ */ new WeakMap();
|
|
|
120
120
|
var NOTIFY = /* @__PURE__ */ new WeakMap();
|
|
121
121
|
var PENDING2 = /* @__PURE__ */ new WeakMap();
|
|
122
122
|
var PARENT = /* @__PURE__ */ new WeakMap();
|
|
123
|
+
var METHOD = /* @__PURE__ */ new WeakMap();
|
|
123
124
|
var define = Object.defineProperty;
|
|
124
125
|
var Model = class _Model {
|
|
125
126
|
constructor(arg) {
|
|
@@ -132,6 +133,22 @@ var Model = class _Model {
|
|
|
132
133
|
new Set(NOTIFY.get(Type)).forEach((x) => addListener(this, x));
|
|
133
134
|
if (Type === _Model)
|
|
134
135
|
break;
|
|
136
|
+
const desc = Object.getOwnPropertyDescriptors(Type.prototype);
|
|
137
|
+
for (const key in desc) {
|
|
138
|
+
let { value } = desc[key];
|
|
139
|
+
if (typeof value == "function" && key !== "constructor")
|
|
140
|
+
Object.defineProperty(Type.prototype, key, {
|
|
141
|
+
get() {
|
|
142
|
+
const method = value.bind(this.is);
|
|
143
|
+
METHOD.set(method, value);
|
|
144
|
+
define(this.is, key, {
|
|
145
|
+
value: method,
|
|
146
|
+
configurable: false
|
|
147
|
+
});
|
|
148
|
+
return method;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
}
|
|
135
152
|
Type = Object.getPrototypeOf(Type);
|
|
136
153
|
}
|
|
137
154
|
addListener(this, () => {
|
|
@@ -262,6 +279,9 @@ var Model = class _Model {
|
|
|
262
279
|
notify.add(listener);
|
|
263
280
|
return () => notify.delete(listener);
|
|
264
281
|
}
|
|
282
|
+
static at(from, cb) {
|
|
283
|
+
throw new Error(`Using context requires an adapter. If you are only testing, define \`get.context\` to simulate one.`);
|
|
284
|
+
}
|
|
265
285
|
};
|
|
266
286
|
define(Model.prototype, "toString", {
|
|
267
287
|
value() {
|
|
@@ -379,111 +399,6 @@ Model.on((_, subject) => {
|
|
|
379
399
|
return null;
|
|
380
400
|
});
|
|
381
401
|
|
|
382
|
-
// src/context.ts
|
|
383
|
-
var Context = class {
|
|
384
|
-
constructor(inputs) {
|
|
385
|
-
this.table = /* @__PURE__ */ new WeakMap();
|
|
386
|
-
this.layer = /* @__PURE__ */ new Map();
|
|
387
|
-
if (inputs)
|
|
388
|
-
this.include(inputs);
|
|
389
|
-
}
|
|
390
|
-
static get() {
|
|
391
|
-
throw new Error(`Using context requires an adapter. If you are only testing, define \`get.context\` to simulate one.`);
|
|
392
|
-
}
|
|
393
|
-
has(T) {
|
|
394
|
-
let key = this.table.get(T);
|
|
395
|
-
if (!key) {
|
|
396
|
-
key = Symbol(T.name);
|
|
397
|
-
this.table.set(T, key);
|
|
398
|
-
}
|
|
399
|
-
return key;
|
|
400
|
-
}
|
|
401
|
-
get(Type) {
|
|
402
|
-
const result = this[this.has(Type)];
|
|
403
|
-
if (result === null)
|
|
404
|
-
throw new Error(`Did find ${Type} in context, but multiple were defined.`);
|
|
405
|
-
return result;
|
|
406
|
-
}
|
|
407
|
-
include(inputs) {
|
|
408
|
-
const init = /* @__PURE__ */ new Map();
|
|
409
|
-
if (typeof inputs == "function" || inputs instanceof Model)
|
|
410
|
-
inputs = { [0]: inputs };
|
|
411
|
-
else if (!inputs)
|
|
412
|
-
reject(inputs);
|
|
413
|
-
Object.entries(inputs).forEach(([K, V]) => {
|
|
414
|
-
if (!(Model.is(V) || V instanceof Model))
|
|
415
|
-
reject(`${V} as ${K}`);
|
|
416
|
-
});
|
|
417
|
-
for (const key in inputs) {
|
|
418
|
-
const input = inputs[key];
|
|
419
|
-
const exists = this.layer.get(key);
|
|
420
|
-
if (!exists) {
|
|
421
|
-
const instance = this.add(input);
|
|
422
|
-
this.layer.set(key, input);
|
|
423
|
-
init.set(instance, true);
|
|
424
|
-
} else if (exists !== input) {
|
|
425
|
-
this.pop();
|
|
426
|
-
this.key = uid();
|
|
427
|
-
return this.include(inputs);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
for (const [model] of init)
|
|
431
|
-
for (const [_key, value] of model)
|
|
432
|
-
if (PARENT.get(value) === model) {
|
|
433
|
-
this.add(value, true);
|
|
434
|
-
init.set(value, false);
|
|
435
|
-
}
|
|
436
|
-
return init;
|
|
437
|
-
}
|
|
438
|
-
add(input, implicit) {
|
|
439
|
-
let writable = true;
|
|
440
|
-
let T;
|
|
441
|
-
let I;
|
|
442
|
-
if (typeof input == "function") {
|
|
443
|
-
T = input;
|
|
444
|
-
I = input.new();
|
|
445
|
-
} else {
|
|
446
|
-
I = input;
|
|
447
|
-
T = I.constructor;
|
|
448
|
-
writable = false;
|
|
449
|
-
}
|
|
450
|
-
do {
|
|
451
|
-
const key = this.has(T);
|
|
452
|
-
const value = this.hasOwnProperty(key) ? null : I;
|
|
453
|
-
if (value || I !== this[key] && !implicit)
|
|
454
|
-
Object.defineProperty(this, key, {
|
|
455
|
-
configurable: true,
|
|
456
|
-
writable,
|
|
457
|
-
value
|
|
458
|
-
});
|
|
459
|
-
T = Object.getPrototypeOf(T);
|
|
460
|
-
} while (T !== Model);
|
|
461
|
-
return I;
|
|
462
|
-
}
|
|
463
|
-
push(inputs) {
|
|
464
|
-
const next = Object.create(this);
|
|
465
|
-
next.layer = /* @__PURE__ */ new Map();
|
|
466
|
-
if (inputs)
|
|
467
|
-
next.include(inputs);
|
|
468
|
-
return next;
|
|
469
|
-
}
|
|
470
|
-
pop() {
|
|
471
|
-
const items = /* @__PURE__ */ new Set();
|
|
472
|
-
for (const key of Object.getOwnPropertySymbols(this)) {
|
|
473
|
-
const entry = Object.getOwnPropertyDescriptor(this, key);
|
|
474
|
-
if (entry.writable && entry.value)
|
|
475
|
-
items.add(entry.value);
|
|
476
|
-
delete this[key];
|
|
477
|
-
}
|
|
478
|
-
for (const model of items)
|
|
479
|
-
model.set(null);
|
|
480
|
-
this.layer.clear();
|
|
481
|
-
}
|
|
482
|
-
};
|
|
483
|
-
function reject(argument) {
|
|
484
|
-
throw new Error(`Context can only include Model or instance but got ${argument}.`);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
402
|
// src/instruction/get.ts
|
|
488
403
|
function get(arg0, arg1) {
|
|
489
404
|
return add((key, subject) => {
|
|
@@ -499,10 +414,9 @@ function get(arg0, arg1) {
|
|
|
499
414
|
if (arg1 === true)
|
|
500
415
|
throw new Error(`${from} may only exist as a child of type ${arg0}.`);
|
|
501
416
|
source = (resolve) => {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
resolve(model);
|
|
417
|
+
arg0.at(from, (got) => {
|
|
418
|
+
if (got)
|
|
419
|
+
resolve(got);
|
|
506
420
|
else if (arg1 !== false)
|
|
507
421
|
throw new Error(`Required ${arg0} not found in context for ${from}.`);
|
|
508
422
|
});
|
|
@@ -511,8 +425,10 @@ function get(arg0, arg1) {
|
|
|
511
425
|
from = hasParent;
|
|
512
426
|
else
|
|
513
427
|
throw new Error(`New ${from} created as child of ${hasParent}, but must be instanceof ${arg0}.`);
|
|
514
|
-
} else if (typeof arg0 == "function")
|
|
515
|
-
|
|
428
|
+
} else if (typeof arg0 == "function") {
|
|
429
|
+
const fn = METHOD.get(arg0) || arg0;
|
|
430
|
+
arg1 = (p, k) => fn.call(p, k, p);
|
|
431
|
+
}
|
|
516
432
|
if (typeof arg1 == "function")
|
|
517
433
|
return compute(subject, key, source, arg1);
|
|
518
434
|
source((got) => subject.set(key, got));
|
|
@@ -542,7 +458,7 @@ function compute(subject, key, source, setter) {
|
|
|
542
458
|
function compute2(initial) {
|
|
543
459
|
let next;
|
|
544
460
|
try {
|
|
545
|
-
next = setter.call(proxy, proxy);
|
|
461
|
+
next = setter.call(proxy, proxy, key);
|
|
546
462
|
} catch (err) {
|
|
547
463
|
console.warn(`An exception was thrown while ${initial ? "initializing" : "refreshing"} ${subject}.${key}.`);
|
|
548
464
|
if (initial)
|
|
@@ -720,12 +636,180 @@ function use(value, argument) {
|
|
|
720
636
|
return output;
|
|
721
637
|
});
|
|
722
638
|
}
|
|
639
|
+
|
|
640
|
+
// src/context.ts
|
|
641
|
+
var Expects = /* @__PURE__ */ new WeakMap();
|
|
642
|
+
var Context = class {
|
|
643
|
+
constructor(inputs) {
|
|
644
|
+
this.downstream = /* @__PURE__ */ new WeakMap();
|
|
645
|
+
this.upstream = /* @__PURE__ */ new WeakMap();
|
|
646
|
+
this.layer = /* @__PURE__ */ new Map();
|
|
647
|
+
if (inputs)
|
|
648
|
+
this.include(inputs);
|
|
649
|
+
}
|
|
650
|
+
static request(type, from, callback) {
|
|
651
|
+
let map = Expects.get(from);
|
|
652
|
+
if (!map)
|
|
653
|
+
Expects.set(from, map = /* @__PURE__ */ new Map());
|
|
654
|
+
map.set(type, callback);
|
|
655
|
+
}
|
|
656
|
+
key(T, upstream) {
|
|
657
|
+
const table = upstream ? this.upstream : this.downstream;
|
|
658
|
+
let key = table.get(T);
|
|
659
|
+
if (!key) {
|
|
660
|
+
key = Symbol(T.name + (upstream ? " request" : ""));
|
|
661
|
+
table.set(T, key);
|
|
662
|
+
}
|
|
663
|
+
return key;
|
|
664
|
+
}
|
|
665
|
+
has(model) {
|
|
666
|
+
const key = this.key(model.constructor, true);
|
|
667
|
+
const result = this[key];
|
|
668
|
+
if (typeof result == "function")
|
|
669
|
+
return result(model);
|
|
670
|
+
}
|
|
671
|
+
get(Type) {
|
|
672
|
+
const result = this[this.key(Type)];
|
|
673
|
+
if (result === null)
|
|
674
|
+
throw new Error(`Did find ${Type} in context, but multiple were defined.`);
|
|
675
|
+
return result;
|
|
676
|
+
}
|
|
677
|
+
include(inputs) {
|
|
678
|
+
const init = /* @__PURE__ */ new Map();
|
|
679
|
+
if (typeof inputs == "function" || inputs instanceof Model)
|
|
680
|
+
inputs = { [0]: inputs };
|
|
681
|
+
else if (!inputs)
|
|
682
|
+
reject(inputs);
|
|
683
|
+
Object.entries(inputs).forEach(([K, V]) => {
|
|
684
|
+
if (!(Model.is(V) || V instanceof Model))
|
|
685
|
+
reject(`${V} as ${K}`);
|
|
686
|
+
});
|
|
687
|
+
for (const key in inputs) {
|
|
688
|
+
const input = inputs[key];
|
|
689
|
+
const exists = this.layer.get(key);
|
|
690
|
+
if (!exists) {
|
|
691
|
+
const instance = this.add(input);
|
|
692
|
+
this.layer.set(key, input);
|
|
693
|
+
init.set(instance, true);
|
|
694
|
+
} else if (exists !== input) {
|
|
695
|
+
this.pop();
|
|
696
|
+
this.id = uid();
|
|
697
|
+
return this.include(inputs);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
for (const [model] of init) {
|
|
701
|
+
this.has(model);
|
|
702
|
+
const expects = Expects.get(model);
|
|
703
|
+
if (expects)
|
|
704
|
+
for (let [T, callback] of expects)
|
|
705
|
+
this.put(T, callback);
|
|
706
|
+
for (const [_key, value] of model)
|
|
707
|
+
if (PARENT.get(value) === model) {
|
|
708
|
+
this.add(value, true);
|
|
709
|
+
init.set(value, false);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return init;
|
|
713
|
+
}
|
|
714
|
+
put(T, I, implicit, writable) {
|
|
715
|
+
do {
|
|
716
|
+
const key = this.key(T, typeof I == "function");
|
|
717
|
+
const value = this.hasOwnProperty(key) ? null : I;
|
|
718
|
+
if (value || this[key] !== I && !implicit)
|
|
719
|
+
Object.defineProperty(this, key, {
|
|
720
|
+
configurable: true,
|
|
721
|
+
writable,
|
|
722
|
+
value
|
|
723
|
+
});
|
|
724
|
+
T = Object.getPrototypeOf(T);
|
|
725
|
+
} while (T !== Model);
|
|
726
|
+
}
|
|
727
|
+
add(input, implicit) {
|
|
728
|
+
let writable = true;
|
|
729
|
+
let T;
|
|
730
|
+
let I;
|
|
731
|
+
if (typeof input == "function") {
|
|
732
|
+
T = input;
|
|
733
|
+
I = input.new();
|
|
734
|
+
} else {
|
|
735
|
+
I = input;
|
|
736
|
+
T = I.constructor;
|
|
737
|
+
writable = false;
|
|
738
|
+
}
|
|
739
|
+
this.put(T, I, implicit, writable);
|
|
740
|
+
return I;
|
|
741
|
+
}
|
|
742
|
+
push(inputs) {
|
|
743
|
+
const next = Object.create(this);
|
|
744
|
+
next.layer = /* @__PURE__ */ new Map();
|
|
745
|
+
if (inputs)
|
|
746
|
+
next.include(inputs);
|
|
747
|
+
return next;
|
|
748
|
+
}
|
|
749
|
+
pop() {
|
|
750
|
+
const items = /* @__PURE__ */ new Set();
|
|
751
|
+
for (const key of Object.getOwnPropertySymbols(this)) {
|
|
752
|
+
const entry = Object.getOwnPropertyDescriptor(this, key);
|
|
753
|
+
if (entry.writable && entry.value)
|
|
754
|
+
items.add(entry.value);
|
|
755
|
+
delete this[key];
|
|
756
|
+
}
|
|
757
|
+
for (const model of items)
|
|
758
|
+
model.set(null);
|
|
759
|
+
this.layer.clear();
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
function reject(argument) {
|
|
763
|
+
throw new Error(`Context can only include Model or instance but got ${argument}.`);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// src/instruction/has.ts
|
|
767
|
+
function has(type, argument) {
|
|
768
|
+
return add((key, subject, state) => {
|
|
769
|
+
if (typeof argument == "boolean") {
|
|
770
|
+
Context.request(type, subject, (model) => {
|
|
771
|
+
const remove = () => {
|
|
772
|
+
drop();
|
|
773
|
+
if (state[key] === model)
|
|
774
|
+
delete state[key];
|
|
775
|
+
};
|
|
776
|
+
subject.set(key, model);
|
|
777
|
+
const drop = model.get(null, remove);
|
|
778
|
+
return remove;
|
|
779
|
+
});
|
|
780
|
+
return { get: argument };
|
|
781
|
+
}
|
|
782
|
+
const children = /* @__PURE__ */ new Set();
|
|
783
|
+
Context.request(type, subject, (model) => {
|
|
784
|
+
if (children.has(model))
|
|
785
|
+
return;
|
|
786
|
+
const remove = typeof argument == "function" ? argument(model) : void 0;
|
|
787
|
+
if (remove === false)
|
|
788
|
+
return;
|
|
789
|
+
children.add(model);
|
|
790
|
+
subject.set(key);
|
|
791
|
+
const done = () => {
|
|
792
|
+
drop();
|
|
793
|
+
if (typeof remove == "function")
|
|
794
|
+
remove();
|
|
795
|
+
children.delete(model);
|
|
796
|
+
subject.set(key);
|
|
797
|
+
};
|
|
798
|
+
const drop = model.get(null, done);
|
|
799
|
+
return done;
|
|
800
|
+
});
|
|
801
|
+
return {
|
|
802
|
+
value: children
|
|
803
|
+
};
|
|
804
|
+
});
|
|
805
|
+
}
|
|
723
806
|
export {
|
|
724
807
|
Context,
|
|
725
808
|
Model,
|
|
726
809
|
add,
|
|
727
810
|
Model as default,
|
|
728
811
|
get,
|
|
812
|
+
has,
|
|
729
813
|
ref,
|
|
730
814
|
set,
|
|
731
815
|
use
|
package/package.json
CHANGED