@expressive/mvc 0.35.0-alpha.0 → 0.35.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
@@ -1,19 +1,3 @@
1
- type Async<T = any, Y extends any[] = any> = {
2
- (...args: Y): Promise<T>;
3
- active: boolean;
4
- };
5
- /**
6
- * Sets an exotic method with managed ready-state. Property accepts an async function.
7
- *
8
- * When a run-method is invoked, its `active` property to true for duration of call.
9
- * This is emitted as an update to property, both when called and after returns (or throws).
10
- *
11
- * **Note:** Subsequent calls will immediately throw if one is still pending.
12
- *
13
- * @param action - Action to fire when resulting property is invoked.
14
- */
15
- declare function run<T, Y extends any[]>(action: (...args: Y) => T | Promise<T>): Async<T, Y>;
16
-
17
1
  type Predicate = (key: string) => boolean | void;
18
2
  declare namespace Model {
19
3
  /** Any type of Model, using own class constructor as its identifier. */
@@ -45,7 +29,7 @@ declare namespace Model {
45
29
  };
46
30
  /** A callback function which is subscribed to parent and updates when values change. */
47
31
  type Effect<T> = (this: T, argument: T) => Callback | Promise<void> | null | void;
48
- type Event = (key: string) => Callback | void;
32
+ type Event = (this: Model, key: string, value: unknown) => Callback | void;
49
33
  namespace Instruction {
50
34
  type Getter<T> = (source: Model) => T;
51
35
  type Setter<T> = (value: T, previous: T) => boolean | void | (() => T);
@@ -79,11 +63,11 @@ declare class Model {
79
63
  get<T extends string>(key: T, required?: boolean): Model.ValueOf<this, T>;
80
64
  /**
81
65
  * Check if update is in progress.
82
- * Returns a promise which resolves updated keys. If no update, will resolve `false`.
66
+ * Returns a promise which resolves updated keys. If no update, will resolve to `false`.
83
67
  **/
84
68
  set(): Promise<Model.Values<this> | false>;
85
69
  /**
86
- * Expect an update to state within a set timeout.
70
+ * Expect an update to state within a set time.
87
71
  *
88
72
  * @param timeout - milliseconds to wait for update
89
73
  * @param predicate - optional function to filter for specific updates. If returns true, update is accepted.
@@ -92,26 +76,29 @@ declare class Model {
92
76
  */
93
77
  set(timeout: number, predicate?: Predicate): Promise<Model.Values<this>>;
94
78
  /**
95
- * Call a function whenever an update to state has occured.
79
+ * Call a function whenever an update occurs.
96
80
  *
97
- * @param callback - Function to call when any update occurs.
81
+ * @param callback
98
82
  * Note: This will be called for every assignment which changes the value.
99
83
  * To run logic on final value only, this callback may return a function.
100
- * Returning the same function for the same (or multiple for that matter)
101
- * will ensure it is only called once.
84
+ * Returning the same function for a key will ensure it is only called once.
102
85
  *
103
- * @returns a function to remove listener. Will return true if listener did exist.
86
+ * @returns a function to remove listener. Returns true if listener isn't removed already.
104
87
  */
105
88
  set(callback: Model.Event): () => boolean;
106
89
  /**
107
90
  * Push an update without changing the value of associated property.
108
91
  *
109
92
  * This is useful where a property value internally has changed, but the object remains the same.
110
- * For example: an array which has pushed a new value, or change to nested properties.
93
+ * For example: An array which has pushed a new value, or a change to nested property.
94
+ */
95
+ set(key: string): void;
96
+ /**
97
+ * Declare an end to updates. This event will freeze state.
111
98
  */
112
- set(key: string | null): void;
99
+ set(key: null): void;
113
100
  /**
114
- * Update a property programatically within state.
101
+ * Update a property with value.
115
102
  *
116
103
  * @param key - property to update
117
104
  * @param value - value to update property with (if the same as current, no update will occur)
@@ -136,6 +123,7 @@ declare class Model {
136
123
  */
137
124
  static is<T extends Model.Type>(this: T, maybe: any): maybe is T;
138
125
  }
126
+
139
127
  declare function add<T = any, M extends Model = any>(instruction: Model.Instruction): T;
140
128
 
141
129
  declare namespace get {
@@ -309,4 +297,4 @@ declare class Context {
309
297
  pop(): void;
310
298
  }
311
299
 
312
- export { Context, Model, add, Model as default, get, ref, run, set, use };
300
+ export { Context, Model, add, Model as default, get, ref, set, use };
package/dist/index.js CHANGED
@@ -26,7 +26,6 @@ __export(src_exports, {
26
26
  default: () => Model,
27
27
  get: () => get,
28
28
  ref: () => ref,
29
- run: () => run,
30
29
  set: () => set,
31
30
  use: () => use
32
31
  });
@@ -36,14 +35,13 @@ module.exports = __toCommonJS(src_exports);
36
35
  var DISPATCH = /* @__PURE__ */ new Set();
37
36
  var OBSERVER = /* @__PURE__ */ new WeakMap();
38
37
  var LISTENER = /* @__PURE__ */ new WeakMap();
39
- var EXPIRED = /* @__PURE__ */ new WeakSet();
40
38
  function onReady() {
41
39
  return null;
42
40
  }
43
41
  function addListener(to, fn) {
44
42
  let subs = LISTENER.get(to);
45
43
  if (!subs)
46
- LISTENER.set(to, subs = /* @__PURE__ */ new Map([[onReady, null]]));
44
+ LISTENER.set(to, subs = (/* @__PURE__ */ new Map()).set(onReady, null));
47
45
  if (!subs.has(onReady))
48
46
  fn(true, to);
49
47
  subs.set(fn, null);
@@ -55,7 +53,7 @@ function watch(from, key, value) {
55
53
  if (observer) {
56
54
  listeners.set(
57
55
  observer,
58
- new Set(listeners.get(observer)).add(key)
56
+ (listeners.get(observer) || /* @__PURE__ */ new Set()).add(key)
59
57
  );
60
58
  const nested = LISTENER.get(value);
61
59
  if (nested) {
@@ -66,7 +64,8 @@ function watch(from, key, value) {
66
64
  return value;
67
65
  }
68
66
  function event(source, key) {
69
- LISTENER.get(source).forEach((select, callback, subs) => {
67
+ const subs = LISTENER.get(source);
68
+ subs.forEach((select, callback) => {
70
69
  let after;
71
70
  if (!select || select.has(key)) {
72
71
  if (after = callback.call(source, key, source))
@@ -95,11 +94,12 @@ function effect(target, callback) {
95
94
  let refresh;
96
95
  let unSet;
97
96
  function invoke() {
97
+ let expired;
98
98
  const local = Object.create(target);
99
99
  const update2 = () => {
100
- if (EXPIRED.has(update2))
100
+ if (expired)
101
101
  return null;
102
- EXPIRED.add(update2);
102
+ expired = true;
103
103
  if (refresh && unSet) {
104
104
  unSet();
105
105
  unSet = void 0;
@@ -141,10 +141,11 @@ var PARENT = /* @__PURE__ */ new WeakMap();
141
141
  var INSTRUCT = /* @__PURE__ */ new Map();
142
142
  var PENDING = /* @__PURE__ */ new WeakMap();
143
143
  var STATE = /* @__PURE__ */ new WeakMap();
144
+ var define = Object.defineProperty;
144
145
  var Model = class _Model {
145
146
  constructor(id) {
146
147
  const state = {};
147
- Object.defineProperty(this, "is", { value: this });
148
+ define(this, "is", { value: this });
148
149
  ID.set(this, `${this.constructor}-${id ? String(id) : uid()}`);
149
150
  STATE.set(this, state);
150
151
  function onNull(key) {
@@ -153,23 +154,20 @@ var Model = class _Model {
153
154
  }
154
155
  addListener(this, () => {
155
156
  for (const key in this) {
156
- const { value } = Object.getOwnPropertyDescriptor(this, key);
157
- const instruction = INSTRUCT.get(value);
158
- let desc = {
159
- enumerable: true,
160
- set: (x) => update(this, key, x),
161
- get() {
162
- return watch(this, key, state[key]);
163
- }
164
- };
165
- if (instruction) {
166
- INSTRUCT.delete(value);
167
- delete this[key];
168
- desc = instruction(this, key, state);
169
- } else
170
- state[key] = value;
171
- if (desc)
172
- Object.defineProperty(this, key, desc);
157
+ const property = Object.getOwnPropertyDescriptor(this, key);
158
+ const instruction = INSTRUCT.get(property.value);
159
+ if (instruction)
160
+ instruction(this, key, state);
161
+ else {
162
+ state[key] = property.value;
163
+ define(this, key, {
164
+ enumerable: true,
165
+ set: (x) => update(this, key, x),
166
+ get() {
167
+ return watch(this, key, state[key]);
168
+ }
169
+ });
170
+ }
173
171
  }
174
172
  addListener(this, onNull);
175
173
  return null;
@@ -200,7 +198,7 @@ var Model = class _Model {
200
198
  if (typeof arg1 == "function")
201
199
  return addListener(self, (key) => {
202
200
  if (typeof key == "string")
203
- return arg1(key);
201
+ return arg1.call(this, key, STATE.get(self)[key]);
204
202
  });
205
203
  if (typeof arg1 == "string" || arg1 === null)
206
204
  return 1 in arguments ? update(self, arg1, arg2, arg3) : update(self, arg1);
@@ -249,53 +247,16 @@ var Model = class _Model {
249
247
  return typeof maybe == "function" && maybe.prototype instanceof this;
250
248
  }
251
249
  };
252
- Object.defineProperty(Model.prototype, "toString", {
250
+ define(Model.prototype, "toString", {
253
251
  value() {
254
252
  return ID.get(this.is);
255
253
  }
256
254
  });
257
- Object.defineProperty(Model, "toString", {
255
+ define(Model, "toString", {
258
256
  value() {
259
257
  return this.name;
260
258
  }
261
259
  });
262
- function add(instruction) {
263
- const placeholder = Symbol("instruction");
264
- INSTRUCT.set(placeholder, (subject, key, state) => {
265
- const output = instruction.call(subject, key, subject, state);
266
- if (!output)
267
- return;
268
- const desc = typeof output == "object" ? output : { get: output };
269
- const { enumerable = true } = desc;
270
- if ("value" in desc)
271
- state[key] = desc.value;
272
- return {
273
- enumerable,
274
- set(next) {
275
- let { set: set2 } = desc;
276
- if (set2 === false)
277
- throw new Error(`${subject}.${key} is read-only.`);
278
- if (typeof set2 == "function") {
279
- const result = set2.call(subject, next, state[key]);
280
- if (result === false)
281
- return;
282
- if (typeof result == "function")
283
- next = result();
284
- set2 = false;
285
- }
286
- update(subject, key, next, !!set2);
287
- },
288
- get() {
289
- return watch(
290
- this,
291
- key,
292
- typeof desc.get == "function" ? desc.get(this) : fetch(subject, key, desc.get)
293
- );
294
- }
295
- };
296
- });
297
- return placeholder;
298
- }
299
260
  function fetch(subject, property, required) {
300
261
  const state = STATE.get(subject);
301
262
  if (property in state || required === false) {
@@ -340,10 +301,7 @@ function update(subject, key, value, silent) {
340
301
  PENDING.delete(subject);
341
302
  });
342
303
  }
343
- const skip = key in pending;
344
- pending[key] = state[key];
345
- if (skip)
346
- return;
304
+ pending[key] = value;
347
305
  }
348
306
  event(subject, key);
349
307
  }
@@ -351,49 +309,45 @@ function uid() {
351
309
  return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
352
310
  }
353
311
 
354
- // src/instruction/run.ts
355
- function run(task) {
356
- return add((key, subject) => {
357
- let pending = false;
358
- async function invoke(...args) {
359
- if (pending)
360
- return Promise.reject(
361
- new Error(`Invoked action ${key} but one is already active.`)
312
+ // src/instruction/add.ts
313
+ function add(instruction) {
314
+ const placeholder = Symbol("instruction");
315
+ INSTRUCT.set(placeholder, (subject, key, state) => {
316
+ INSTRUCT.delete(placeholder);
317
+ delete subject[key];
318
+ const output = instruction.call(subject, key, subject, state);
319
+ if (!output)
320
+ return;
321
+ const desc = typeof output == "object" ? output : { get: output };
322
+ const { enumerable = true } = desc;
323
+ if ("value" in desc)
324
+ state[key] = desc.value;
325
+ Object.defineProperty(subject, key, {
326
+ enumerable,
327
+ set(next) {
328
+ let { set: set2 } = desc;
329
+ if (set2 === false)
330
+ throw new Error(`${subject}.${key} is read-only.`);
331
+ if (typeof set2 == "function") {
332
+ const result = set2.call(subject, next, state[key]);
333
+ if (result === false)
334
+ return;
335
+ if (typeof result == "function")
336
+ next = result();
337
+ set2 = false;
338
+ }
339
+ update(subject, key, next, !!set2);
340
+ },
341
+ get() {
342
+ return watch(
343
+ this,
344
+ key,
345
+ typeof desc.get == "function" ? desc.get(this) : fetch(subject, key, desc.get)
362
346
  );
363
- pending = true;
364
- subject.set(key);
365
- try {
366
- return await attempt(() => task.apply(subject, args));
367
- } finally {
368
- pending = false;
369
- subject.set(key);
370
347
  }
371
- }
372
- Object.defineProperty(invoke, "active", {
373
- get: () => pending
374
348
  });
375
- return {
376
- value: invoke,
377
- set: false
378
- };
379
349
  });
380
- }
381
- function attempt(fn) {
382
- function retry(err) {
383
- if (err instanceof Promise)
384
- return err.then(compute2);
385
- else
386
- throw err;
387
- }
388
- function compute2() {
389
- try {
390
- const output = fn();
391
- return output instanceof Promise ? output.catch(retry) : output;
392
- } catch (err) {
393
- return retry(err);
394
- }
395
- }
396
- return compute2();
350
+ return placeholder;
397
351
  }
398
352
 
399
353
  // src/context.ts
@@ -529,7 +483,7 @@ function compute(subject, key, source, setter) {
529
483
  let isAsync;
530
484
  let proxy;
531
485
  function connect(model) {
532
- reset = model.get((current) => {
486
+ reset = effect(model, (current) => {
533
487
  proxy = current;
534
488
  if (!reset)
535
489
  compute2(true);
@@ -565,28 +519,28 @@ function compute(subject, key, source, setter) {
565
519
  }
566
520
 
567
521
  // src/instruction/ref.ts
568
- var define = Object.defineProperty;
522
+ var define2 = Object.defineProperty;
569
523
  function ref(arg, arg2) {
570
524
  return add((key, subject, state) => {
571
525
  let value = {};
572
526
  if (arg === subject)
573
527
  for (const key2 in state)
574
528
  if (typeof arg2 == "function")
575
- define(value, key2, {
529
+ define2(value, key2, {
576
530
  configurable: true,
577
531
  get() {
578
532
  const out = arg2(key2);
579
- define(value, key2, { value: out });
533
+ define2(value, key2, { value: out });
580
534
  return out;
581
535
  }
582
536
  });
583
537
  else {
584
538
  const ref2 = (value2) => subject.set(key2, value2);
585
- define(ref2, "current", {
539
+ define2(ref2, "current", {
586
540
  get: () => state[key2],
587
541
  set: ref2
588
542
  });
589
- define(value, key2, { value: ref2 });
543
+ define2(value, key2, { value: ref2 });
590
544
  }
591
545
  else if (typeof arg == "object")
592
546
  throw new Error("ref instruction does not support object which is not 'this'");
@@ -603,12 +557,12 @@ function ref(arg, arg2) {
603
557
  unSet = out;
604
558
  }
605
559
  };
606
- value = define(set2, "current", {
560
+ value = define2(set2, "current", {
607
561
  get: () => state[key],
608
562
  set: set2
609
563
  });
610
564
  }
611
- define(subject, key, { value });
565
+ define2(subject, key, { value });
612
566
  });
613
567
  }
614
568
 
@@ -667,13 +621,27 @@ function set(value, argument) {
667
621
  return output;
668
622
  });
669
623
  }
624
+ function attempt(fn) {
625
+ function retry(err) {
626
+ if (err instanceof Promise)
627
+ return err.then(compute2);
628
+ else
629
+ throw err;
630
+ }
631
+ function compute2() {
632
+ try {
633
+ const output = fn();
634
+ return output instanceof Promise ? output.catch(retry) : output;
635
+ } catch (err) {
636
+ return retry(err);
637
+ }
638
+ }
639
+ return compute2();
640
+ }
670
641
 
671
642
  // src/instruction/use.ts
672
643
  function use(value, argument) {
673
644
  return add((property, subject) => {
674
- if (typeof value === "function")
675
- value = new value();
676
- const output = { set: set2, value };
677
645
  function set2(next) {
678
646
  if (value instanceof Model && !(next instanceof value.constructor))
679
647
  throw new Error(`${subject}.${property} expected Model of type ${value.constructor} but got ${next}.`);
@@ -698,6 +666,9 @@ function use(value, argument) {
698
666
  if (typeof argument == "function")
699
667
  argument(next);
700
668
  }
669
+ if (typeof value === "function")
670
+ value = new value();
671
+ const output = { set: set2, value };
701
672
  set2(value);
702
673
  return output;
703
674
  });
@@ -709,7 +680,6 @@ function use(value, argument) {
709
680
  add,
710
681
  get,
711
682
  ref,
712
- run,
713
683
  set,
714
684
  use
715
685
  });
package/dist/index.mjs CHANGED
@@ -2,14 +2,13 @@
2
2
  var DISPATCH = /* @__PURE__ */ new Set();
3
3
  var OBSERVER = /* @__PURE__ */ new WeakMap();
4
4
  var LISTENER = /* @__PURE__ */ new WeakMap();
5
- var EXPIRED = /* @__PURE__ */ new WeakSet();
6
5
  function onReady() {
7
6
  return null;
8
7
  }
9
8
  function addListener(to, fn) {
10
9
  let subs = LISTENER.get(to);
11
10
  if (!subs)
12
- LISTENER.set(to, subs = /* @__PURE__ */ new Map([[onReady, null]]));
11
+ LISTENER.set(to, subs = (/* @__PURE__ */ new Map()).set(onReady, null));
13
12
  if (!subs.has(onReady))
14
13
  fn(true, to);
15
14
  subs.set(fn, null);
@@ -21,7 +20,7 @@ function watch(from, key, value) {
21
20
  if (observer) {
22
21
  listeners.set(
23
22
  observer,
24
- new Set(listeners.get(observer)).add(key)
23
+ (listeners.get(observer) || /* @__PURE__ */ new Set()).add(key)
25
24
  );
26
25
  const nested = LISTENER.get(value);
27
26
  if (nested) {
@@ -32,7 +31,8 @@ function watch(from, key, value) {
32
31
  return value;
33
32
  }
34
33
  function event(source, key) {
35
- LISTENER.get(source).forEach((select, callback, subs) => {
34
+ const subs = LISTENER.get(source);
35
+ subs.forEach((select, callback) => {
36
36
  let after;
37
37
  if (!select || select.has(key)) {
38
38
  if (after = callback.call(source, key, source))
@@ -61,11 +61,12 @@ function effect(target, callback) {
61
61
  let refresh;
62
62
  let unSet;
63
63
  function invoke() {
64
+ let expired;
64
65
  const local = Object.create(target);
65
66
  const update2 = () => {
66
- if (EXPIRED.has(update2))
67
+ if (expired)
67
68
  return null;
68
- EXPIRED.add(update2);
69
+ expired = true;
69
70
  if (refresh && unSet) {
70
71
  unSet();
71
72
  unSet = void 0;
@@ -107,10 +108,11 @@ var PARENT = /* @__PURE__ */ new WeakMap();
107
108
  var INSTRUCT = /* @__PURE__ */ new Map();
108
109
  var PENDING = /* @__PURE__ */ new WeakMap();
109
110
  var STATE = /* @__PURE__ */ new WeakMap();
111
+ var define = Object.defineProperty;
110
112
  var Model = class _Model {
111
113
  constructor(id) {
112
114
  const state = {};
113
- Object.defineProperty(this, "is", { value: this });
115
+ define(this, "is", { value: this });
114
116
  ID.set(this, `${this.constructor}-${id ? String(id) : uid()}`);
115
117
  STATE.set(this, state);
116
118
  function onNull(key) {
@@ -119,23 +121,20 @@ var Model = class _Model {
119
121
  }
120
122
  addListener(this, () => {
121
123
  for (const key in this) {
122
- const { value } = Object.getOwnPropertyDescriptor(this, key);
123
- const instruction = INSTRUCT.get(value);
124
- let desc = {
125
- enumerable: true,
126
- set: (x) => update(this, key, x),
127
- get() {
128
- return watch(this, key, state[key]);
129
- }
130
- };
131
- if (instruction) {
132
- INSTRUCT.delete(value);
133
- delete this[key];
134
- desc = instruction(this, key, state);
135
- } else
136
- state[key] = value;
137
- if (desc)
138
- Object.defineProperty(this, key, desc);
124
+ const property = Object.getOwnPropertyDescriptor(this, key);
125
+ const instruction = INSTRUCT.get(property.value);
126
+ if (instruction)
127
+ instruction(this, key, state);
128
+ else {
129
+ state[key] = property.value;
130
+ define(this, key, {
131
+ enumerable: true,
132
+ set: (x) => update(this, key, x),
133
+ get() {
134
+ return watch(this, key, state[key]);
135
+ }
136
+ });
137
+ }
139
138
  }
140
139
  addListener(this, onNull);
141
140
  return null;
@@ -166,7 +165,7 @@ var Model = class _Model {
166
165
  if (typeof arg1 == "function")
167
166
  return addListener(self, (key) => {
168
167
  if (typeof key == "string")
169
- return arg1(key);
168
+ return arg1.call(this, key, STATE.get(self)[key]);
170
169
  });
171
170
  if (typeof arg1 == "string" || arg1 === null)
172
171
  return 1 in arguments ? update(self, arg1, arg2, arg3) : update(self, arg1);
@@ -215,53 +214,16 @@ var Model = class _Model {
215
214
  return typeof maybe == "function" && maybe.prototype instanceof this;
216
215
  }
217
216
  };
218
- Object.defineProperty(Model.prototype, "toString", {
217
+ define(Model.prototype, "toString", {
219
218
  value() {
220
219
  return ID.get(this.is);
221
220
  }
222
221
  });
223
- Object.defineProperty(Model, "toString", {
222
+ define(Model, "toString", {
224
223
  value() {
225
224
  return this.name;
226
225
  }
227
226
  });
228
- function add(instruction) {
229
- const placeholder = Symbol("instruction");
230
- INSTRUCT.set(placeholder, (subject, key, state) => {
231
- const output = instruction.call(subject, key, subject, state);
232
- if (!output)
233
- return;
234
- const desc = typeof output == "object" ? output : { get: output };
235
- const { enumerable = true } = desc;
236
- if ("value" in desc)
237
- state[key] = desc.value;
238
- return {
239
- enumerable,
240
- set(next) {
241
- let { set: set2 } = desc;
242
- if (set2 === false)
243
- throw new Error(`${subject}.${key} is read-only.`);
244
- if (typeof set2 == "function") {
245
- const result = set2.call(subject, next, state[key]);
246
- if (result === false)
247
- return;
248
- if (typeof result == "function")
249
- next = result();
250
- set2 = false;
251
- }
252
- update(subject, key, next, !!set2);
253
- },
254
- get() {
255
- return watch(
256
- this,
257
- key,
258
- typeof desc.get == "function" ? desc.get(this) : fetch(subject, key, desc.get)
259
- );
260
- }
261
- };
262
- });
263
- return placeholder;
264
- }
265
227
  function fetch(subject, property, required) {
266
228
  const state = STATE.get(subject);
267
229
  if (property in state || required === false) {
@@ -306,10 +268,7 @@ function update(subject, key, value, silent) {
306
268
  PENDING.delete(subject);
307
269
  });
308
270
  }
309
- const skip = key in pending;
310
- pending[key] = state[key];
311
- if (skip)
312
- return;
271
+ pending[key] = value;
313
272
  }
314
273
  event(subject, key);
315
274
  }
@@ -317,49 +276,45 @@ function uid() {
317
276
  return (Math.random() * 0.722 + 0.278).toString(36).substring(2, 8).toUpperCase();
318
277
  }
319
278
 
320
- // src/instruction/run.ts
321
- function run(task) {
322
- return add((key, subject) => {
323
- let pending = false;
324
- async function invoke(...args) {
325
- if (pending)
326
- return Promise.reject(
327
- new Error(`Invoked action ${key} but one is already active.`)
279
+ // src/instruction/add.ts
280
+ function add(instruction) {
281
+ const placeholder = Symbol("instruction");
282
+ INSTRUCT.set(placeholder, (subject, key, state) => {
283
+ INSTRUCT.delete(placeholder);
284
+ delete subject[key];
285
+ const output = instruction.call(subject, key, subject, state);
286
+ if (!output)
287
+ return;
288
+ const desc = typeof output == "object" ? output : { get: output };
289
+ const { enumerable = true } = desc;
290
+ if ("value" in desc)
291
+ state[key] = desc.value;
292
+ Object.defineProperty(subject, key, {
293
+ enumerable,
294
+ set(next) {
295
+ let { set: set2 } = desc;
296
+ if (set2 === false)
297
+ throw new Error(`${subject}.${key} is read-only.`);
298
+ if (typeof set2 == "function") {
299
+ const result = set2.call(subject, next, state[key]);
300
+ if (result === false)
301
+ return;
302
+ if (typeof result == "function")
303
+ next = result();
304
+ set2 = false;
305
+ }
306
+ update(subject, key, next, !!set2);
307
+ },
308
+ get() {
309
+ return watch(
310
+ this,
311
+ key,
312
+ typeof desc.get == "function" ? desc.get(this) : fetch(subject, key, desc.get)
328
313
  );
329
- pending = true;
330
- subject.set(key);
331
- try {
332
- return await attempt(() => task.apply(subject, args));
333
- } finally {
334
- pending = false;
335
- subject.set(key);
336
314
  }
337
- }
338
- Object.defineProperty(invoke, "active", {
339
- get: () => pending
340
315
  });
341
- return {
342
- value: invoke,
343
- set: false
344
- };
345
316
  });
346
- }
347
- function attempt(fn) {
348
- function retry(err) {
349
- if (err instanceof Promise)
350
- return err.then(compute2);
351
- else
352
- throw err;
353
- }
354
- function compute2() {
355
- try {
356
- const output = fn();
357
- return output instanceof Promise ? output.catch(retry) : output;
358
- } catch (err) {
359
- return retry(err);
360
- }
361
- }
362
- return compute2();
317
+ return placeholder;
363
318
  }
364
319
 
365
320
  // src/context.ts
@@ -495,7 +450,7 @@ function compute(subject, key, source, setter) {
495
450
  let isAsync;
496
451
  let proxy;
497
452
  function connect(model) {
498
- reset = model.get((current) => {
453
+ reset = effect(model, (current) => {
499
454
  proxy = current;
500
455
  if (!reset)
501
456
  compute2(true);
@@ -531,28 +486,28 @@ function compute(subject, key, source, setter) {
531
486
  }
532
487
 
533
488
  // src/instruction/ref.ts
534
- var define = Object.defineProperty;
489
+ var define2 = Object.defineProperty;
535
490
  function ref(arg, arg2) {
536
491
  return add((key, subject, state) => {
537
492
  let value = {};
538
493
  if (arg === subject)
539
494
  for (const key2 in state)
540
495
  if (typeof arg2 == "function")
541
- define(value, key2, {
496
+ define2(value, key2, {
542
497
  configurable: true,
543
498
  get() {
544
499
  const out = arg2(key2);
545
- define(value, key2, { value: out });
500
+ define2(value, key2, { value: out });
546
501
  return out;
547
502
  }
548
503
  });
549
504
  else {
550
505
  const ref2 = (value2) => subject.set(key2, value2);
551
- define(ref2, "current", {
506
+ define2(ref2, "current", {
552
507
  get: () => state[key2],
553
508
  set: ref2
554
509
  });
555
- define(value, key2, { value: ref2 });
510
+ define2(value, key2, { value: ref2 });
556
511
  }
557
512
  else if (typeof arg == "object")
558
513
  throw new Error("ref instruction does not support object which is not 'this'");
@@ -569,12 +524,12 @@ function ref(arg, arg2) {
569
524
  unSet = out;
570
525
  }
571
526
  };
572
- value = define(set2, "current", {
527
+ value = define2(set2, "current", {
573
528
  get: () => state[key],
574
529
  set: set2
575
530
  });
576
531
  }
577
- define(subject, key, { value });
532
+ define2(subject, key, { value });
578
533
  });
579
534
  }
580
535
 
@@ -633,13 +588,27 @@ function set(value, argument) {
633
588
  return output;
634
589
  });
635
590
  }
591
+ function attempt(fn) {
592
+ function retry(err) {
593
+ if (err instanceof Promise)
594
+ return err.then(compute2);
595
+ else
596
+ throw err;
597
+ }
598
+ function compute2() {
599
+ try {
600
+ const output = fn();
601
+ return output instanceof Promise ? output.catch(retry) : output;
602
+ } catch (err) {
603
+ return retry(err);
604
+ }
605
+ }
606
+ return compute2();
607
+ }
636
608
 
637
609
  // src/instruction/use.ts
638
610
  function use(value, argument) {
639
611
  return add((property, subject) => {
640
- if (typeof value === "function")
641
- value = new value();
642
- const output = { set: set2, value };
643
612
  function set2(next) {
644
613
  if (value instanceof Model && !(next instanceof value.constructor))
645
614
  throw new Error(`${subject}.${property} expected Model of type ${value.constructor} but got ${next}.`);
@@ -664,6 +633,9 @@ function use(value, argument) {
664
633
  if (typeof argument == "function")
665
634
  argument(next);
666
635
  }
636
+ if (typeof value === "function")
637
+ value = new value();
638
+ const output = { set: set2, value };
667
639
  set2(value);
668
640
  return output;
669
641
  });
@@ -675,7 +647,6 @@ export {
675
647
  Model as default,
676
648
  get,
677
649
  ref,
678
- run,
679
650
  set,
680
651
  use
681
652
  };
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.35.0-alpha.0",
32
- "gitHead": "17db508f601400ac08e6f821376e7a9403525d5b"
31
+ "version": "0.35.0",
32
+ "gitHead": "c3be06793fa1f4c61dd54c78dace08c928392d1b"
33
33
  }