@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 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?: string | (() => void | (() => void)));
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> = (this: S, on: S) => T;
190
- type Factory<R, T> = (this: T, property: string, on: T) => Function<R, T>;
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 required - If true, will throw if Model is created without a parent.
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>, required?: true): 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: boolean): T | undefined;
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: (this: T, on: T) => R): R;
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: (this: T, on: T) => R): R;
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: (property: string, on: T) => (this: T, state: T) => R): R;
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 get(from: Model, callback: (context: Context) => void): void;
353
- key: string;
354
- protected table: WeakMap<Model.Type<Model>, symbol>;
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
- protected has(T: Model.Type): keyof this;
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
- protected add<T extends Model>(input: T | Model.New<T>, implicit?: boolean): T;
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
- Context.get(from, (context) => {
536
- const model = context.get(arg0);
537
- if (model)
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
- arg1 = arg0.call(from, key, from);
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
- Context.get(from, (context) => {
503
- const model = context.get(arg0);
504
- if (model)
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
- arg1 = arg0.call(from, key, from);
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
@@ -28,6 +28,6 @@
28
28
  "prebuild": "rm -rf dist",
29
29
  "preversion": "npm run test && npm run build"
30
30
  },
31
- "version": "0.38.0",
32
- "gitHead": "8f3d4c7939e483043de4391ee0edb877bb7da63c"
31
+ "version": "0.40.0",
32
+ "gitHead": "1eb515499dc2d6571d0cc97406192ce8eb0714d2"
33
33
  }