@expressive/mvc 0.2.5 → 0.4.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/lib/index.js CHANGED
@@ -59,7 +59,7 @@ function suspend(source, key) {
59
59
  const release = source.addListener(forKey => {
60
60
  if (forKey == key)
61
61
  return () => {
62
- if (source.state[key] !== undefined) {
62
+ if (source.state.get(key) !== undefined) {
63
63
  release();
64
64
  resolve();
65
65
  }
@@ -140,225 +140,37 @@ function createValueEffect(callback) {
140
140
  };
141
141
  }
142
142
 
143
- const UPDATE = new WeakMap();
144
- function applyUpdate(subject, keys) {
145
- UPDATE.set(subject, keys);
146
- return () => {
147
- setTimeout(() => {
148
- UPDATE.delete(subject);
149
- }, 0);
150
- };
151
- }
152
-
153
- const CONTROL = Symbol("CONTROL");
154
- const WHY = Symbol("UPDATE");
155
- const LOCAL = Symbol("LOCAL");
156
- const STATE = Symbol("STATE");
157
- class Model {
158
- constructor() {
159
- define(this, CONTROL, new Controller(this));
160
- define(this, "get", this);
161
- define(this, "is", this);
162
- defineLazy(this, "set", () => {
163
- const controller = control(this);
164
- const assign = (key, value) => {
165
- controller.update(key, value);
166
- };
167
- for (const key of getOwnPropertyNames(controller.proxy))
168
- define(assign, key, controller.ref(key));
169
- return assign;
170
- });
171
- }
172
- get [STATE]() {
173
- return this[CONTROL].state;
174
- }
175
- get [WHY]() {
176
- return UPDATE.get(this);
177
- }
178
- on(select, handler, squash, once) {
179
- return control(this, control => {
180
- if (typeof select == "function")
181
- return control.addListener(select);
182
- const keys = typeof select == "string" ? [select] :
183
- !select.length ? getOwnPropertyNames(control.state) :
184
- select;
185
- ensure(control, keys);
186
- const callback = squash
187
- ? handler.bind(this)
188
- : frame => frame
189
- .filter(k => keys.includes(k))
190
- .forEach(k => handler.call(this, control.state[k], k));
191
- const trigger = once
192
- ? frame => { remove(); callback(frame); }
193
- : callback;
194
- const remove = control.addListener(key => {
195
- if (keys.includes(key))
196
- return trigger;
197
- });
198
- return remove;
199
- });
200
- }
201
- once(select, callback, squash) {
202
- if (callback)
203
- return this.on(select, callback, squash, true);
204
- return new Promise(resolve => {
205
- this.on(select, resolve, true, true);
206
- });
143
+ function ensure(subject, cb) {
144
+ let control = subject[CONTROL];
145
+ if (!control) {
146
+ control = new Controller(subject);
147
+ define(subject, CONTROL, control);
207
148
  }
208
- effect(callback, select) {
209
- const effect = createEffect(callback);
210
- return control(this, control => {
211
- let busy = false;
212
- let inject = this.get;
213
- const invoke = () => {
214
- if (busy)
215
- return;
216
- const output = mayRetry(() => {
217
- effect.call(inject, inject);
218
- });
219
- if (output instanceof Promise) {
220
- output.finally(() => busy = false);
221
- busy = true;
222
- }
223
- };
224
- if (!select) {
225
- const sub = new Subscriber(control, () => invoke);
226
- inject = sub.proxy;
227
- invoke();
228
- return sub.commit();
229
- }
230
- invoke();
231
- if (!select.length) {
232
- control.onDestroy.add(invoke);
233
- return () => {
234
- control.onDestroy.delete(invoke);
235
- };
236
- }
237
- return control.addListener(key => {
238
- if (select.includes(key))
239
- return invoke;
149
+ if (!control.state) {
150
+ const { waiting } = control;
151
+ if (cb) {
152
+ let done;
153
+ waiting.add(() => {
154
+ done = cb(control);
240
155
  });
241
- });
242
- }
243
- // TODO: account for exotic properties
244
- import(source, select) {
245
- const { subject } = control(this);
246
- if (!select)
247
- select = getOwnPropertyNames(subject);
248
- for (const key of select)
249
- if (key in source)
250
- this[key] = source[key];
251
- }
252
- export(subset) {
253
- const { state } = control(this);
254
- const output = {};
255
- if (!subset)
256
- subset = getOwnPropertyNames(state);
257
- for (const key of subset)
258
- output[key] = state[key];
259
- return output;
260
- }
261
- update(arg, tag) {
262
- const target = control(this);
263
- if (typeof arg == "string") {
264
- target.update(arg);
265
- if (1 in arguments && arg in this) {
266
- const method = this[arg];
267
- if (typeof method == "function")
268
- if (typeof tag != "boolean")
269
- method.call(this, tag);
270
- else if (tag)
271
- method.call(this);
272
- }
273
- arg = undefined;
156
+ return () => done && done();
274
157
  }
275
- return target.requestUpdate(arg);
276
- }
277
- /**
278
- * Mark this instance for garbage-collection and send `willDestroy` event to all listeners.
279
- */
280
- destroy() {
281
- control(this).stop();
282
- }
283
- toString() {
284
- return this.constructor.name;
285
- }
286
- /**
287
- * Creates a new instance of this controller.
288
- *
289
- * Beyond `new this(...)`, method will activate managed-state.
290
- *
291
- * @param args - arguments sent to constructor
292
- */
293
- static create(...args) {
294
- const instance = new this(...args);
295
- control(instance);
296
- return instance;
297
- }
298
- /**
299
- * Static equivalent of `x instanceof this`.
300
- *
301
- * Will determine if provided class is a subtype of this one.
302
- */
303
- static isTypeof(maybe) {
304
- return (typeof maybe == "function" &&
305
- maybe.prototype instanceof this);
306
- }
307
- }
308
-
309
- class Subscriber {
310
- constructor(target, onUpdate) {
311
- this.onUpdate = onUpdate;
312
- this.active = false;
313
- this.dependant = new Set();
314
- this.watch = {};
315
- const parent = target instanceof Controller
316
- ? target : control(target);
317
- const proxy = create(parent.proxy);
318
- let reset;
319
- define(proxy, LOCAL, this);
320
- defineProperty(this, "proxy", {
321
- configurable: true,
322
- get() {
323
- if (reset)
324
- setTimeout(reset, 0);
325
- return proxy;
326
- }
327
- });
328
- const release = parent.addListener(key => {
329
- const handler = this.watch[key];
330
- if (!handler || !this.active)
331
- return;
332
- if (typeof handler == "function")
333
- handler();
334
- const notify = this.onUpdate(key, parent);
335
- const getWhy = (keys) => {
336
- reset = applyUpdate(proxy, keys.filter(k => k in this.watch));
337
- };
338
- if (notify) {
339
- parent.requestUpdate(getWhy);
340
- parent.requestUpdate(notify);
341
- }
342
- });
343
- this.commit = () => {
344
- this.active = true;
345
- this.dependant.forEach(x => x.commit());
346
- return this.release;
347
- };
348
- this.release = () => {
349
- this.dependant.forEach(x => x.release());
350
- release();
351
- };
158
+ control.state = new Map();
159
+ for (const key in subject)
160
+ control.add(key);
161
+ const callback = Array.from(waiting);
162
+ waiting.clear();
163
+ for (const cb of callback)
164
+ cb();
352
165
  }
166
+ return cb ? cb(control) : control;
353
167
  }
354
168
 
355
169
  const Oops$a = issues({
356
170
  BadSource: (model, property, got) => `Bad from-instruction provided to ${model}.${property}. Expects an arrow-function or a Model as source. Got ${got}.`,
357
171
  PeerNotAllowed: (model, property) => `Attempted to use an instruction result (probably use or tap) as computed source for ${model}.${property}. This is not possible.`,
358
- Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`,
359
- Early: (property) => `Note: Computed values don't run until accessed, except when subscribed to. '${property}' getter may have run earlier than intended.`
172
+ Failed: (parent, property, initial) => `An exception was thrown while ${initial ? "initializing" : "refreshing"} [${parent}.${property}].`
360
173
  });
361
- const INIT = new WeakSet();
362
174
  const INFO = new WeakMap();
363
175
  const USED = new WeakMap();
364
176
  const KEYS = new WeakMap();
@@ -366,8 +178,8 @@ function from(source, arg1, arg2) {
366
178
  return apply(function from(key) {
367
179
  const parent = this;
368
180
  const { subject, state } = this;
181
+ const required = arg2 === true || arg1 === true;
369
182
  let getSource;
370
- let required = arg2 === true || arg1 === true;
371
183
  if (typeof arg1 == "boolean")
372
184
  arg1 = undefined;
373
185
  // Easy mistake, using a peer, will always be unresolved.
@@ -375,7 +187,7 @@ function from(source, arg1, arg2) {
375
187
  throw Oops$a.PeerNotAllowed(subject, key);
376
188
  // replace source controller in-case it is different
377
189
  if (typeof source == "object")
378
- getSource = () => control(source);
190
+ getSource = () => ensure(source);
379
191
  // specifically an arrow function (getter factory)
380
192
  else if (!source.prototype) {
381
193
  arg1 = source.call(subject, key);
@@ -384,21 +196,20 @@ function from(source, arg1, arg2) {
384
196
  // Regular function is too ambiguous so not allowed.
385
197
  else
386
198
  throw Oops$a.BadSource(subject, key, source);
387
- let sub;
388
199
  const setter = arg1;
389
200
  const info = { key, parent, priority: 1 };
201
+ let sub;
390
202
  let register = USED.get(parent);
391
- if (!register) {
392
- register = new Map();
393
- USED.set(parent, register);
394
- }
203
+ if (!register)
204
+ USED.set(parent, register = new Map());
205
+ state.set(key, undefined);
395
206
  register.set(key, info);
396
207
  function compute(initial) {
397
208
  try {
398
209
  return setter.call(sub.proxy, sub.proxy);
399
210
  }
400
211
  catch (err) {
401
- Oops$a.Failed(subject, key, !!initial).warn();
212
+ Oops$a.Failed(subject, key, initial).warn();
402
213
  throw err;
403
214
  }
404
215
  }
@@ -411,8 +222,9 @@ function from(source, arg1, arg2) {
411
222
  console.error(e);
412
223
  }
413
224
  finally {
414
- if (state[key] !== value) {
415
- parent.update(key, value);
225
+ if (state.get(key) !== value) {
226
+ parent.state.set(key, value);
227
+ parent.update(key);
416
228
  return value;
417
229
  }
418
230
  }
@@ -428,218 +240,410 @@ function from(source, arg1, arg2) {
428
240
  pending.splice(after + 1, 0, update);
429
241
  }
430
242
  }
431
- function create(early) {
432
- sub = new Subscriber(getSource(), defer);
433
- defineProperty(state, key, {
434
- value: undefined,
435
- writable: true
436
- });
243
+ function create() {
244
+ const control = getSource();
245
+ sub = control.subscribe(defer);
437
246
  try {
438
- return state[key] = compute(true);
247
+ const value = compute(true);
248
+ state.set(key, value);
249
+ return value;
439
250
  }
440
251
  catch (e) {
441
- if (early)
442
- Oops$a.Early(key).warn();
443
252
  throw e;
444
253
  }
445
254
  finally {
446
255
  sub.commit();
447
- for (const key in sub.watch) {
256
+ for (const key of control.state.keys()) {
448
257
  const peer = register.get(key);
449
258
  if (peer && peer.priority >= info.priority)
450
259
  info.priority = peer.priority + 1;
451
260
  }
452
261
  }
453
262
  }
454
- INIT.add(create);
455
263
  INFO.set(update, info);
456
- defineProperty(state, key, {
457
- get: create,
458
- configurable: true,
459
- enumerable: true
460
- });
461
264
  return () => {
462
- const value = parent.state[key];
265
+ const value = sub ? state.get(key) : create();
463
266
  if (value === undefined && required)
464
267
  throw suspend(this, key);
465
268
  return value;
466
269
  };
467
270
  });
468
271
  }
469
- function ensure(on, keys) {
470
- for (const key of keys) {
471
- const desc = getOwnPropertyDescriptor(on.state, key);
472
- const getter = desc && desc.get;
473
- if (INIT.has(getter))
474
- getter(true);
475
- }
476
- }
477
- function flush(on) {
478
- const handled = on.frame;
479
- const pending = KEYS.get(on);
272
+ function flush(control) {
273
+ const pending = KEYS.get(control);
480
274
  if (!pending)
481
275
  return;
482
276
  while (pending.length) {
483
- const why = [...handled];
484
277
  const compute = pending.shift();
485
278
  const { key } = INFO.get(compute);
486
- if (!handled.has(key))
487
- compute(why);
279
+ if (!control.frame.has(key))
280
+ compute();
488
281
  }
489
- KEYS.delete(on);
282
+ KEYS.delete(control);
490
283
  }
491
284
 
492
- const Oops$9 = issues({
493
- StrictUpdate: () => `Strict update() did not find pending updates.`,
494
- NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
495
- });
496
- const PENDING = new Map();
497
- const READY = new WeakSet();
285
+ class Subscriber {
286
+ constructor(parent, onUpdate) {
287
+ this.onUpdate = onUpdate;
288
+ this.active = false;
289
+ this.dependant = new Set();
290
+ const proxy = create(parent.subject);
291
+ const using = new Map();
292
+ define(proxy, LOCAL, this);
293
+ defineProperty(this, "proxy", {
294
+ configurable: true,
295
+ get() {
296
+ if (UPDATE.has(proxy))
297
+ setTimeout(() => UPDATE.delete(proxy), 0);
298
+ return proxy;
299
+ }
300
+ });
301
+ const release = parent.addListener(key => {
302
+ if (!this.active || !using.has(key))
303
+ return;
304
+ const handler = using.get(key);
305
+ if (typeof handler == "function")
306
+ if (handler() !== true)
307
+ return;
308
+ const notify = this.onUpdate(key, parent);
309
+ const getWhy = () => {
310
+ const update = getUpdate(parent.subject);
311
+ const applicable = update.filter(k => using.has(k));
312
+ UPDATE.set(proxy, applicable);
313
+ };
314
+ if (notify) {
315
+ parent.waiting.add(getWhy);
316
+ parent.waiting.add(notify);
317
+ }
318
+ });
319
+ this.commit = () => {
320
+ this.active = true;
321
+ this.dependant.forEach(x => x.commit());
322
+ return this.release;
323
+ };
324
+ this.release = () => {
325
+ this.dependant.forEach(x => x.release());
326
+ release();
327
+ };
328
+ this.add = (key, value) => {
329
+ if (value)
330
+ using.set(key, value);
331
+ else if (!using.has(key))
332
+ using.set(key, true);
333
+ };
334
+ }
335
+ }
336
+
337
+ const UPDATE = new WeakMap();
338
+ function getUpdate(subject) {
339
+ return UPDATE.get(subject);
340
+ }
498
341
  class Controller {
499
342
  constructor(subject) {
500
343
  this.subject = subject;
501
- this.state = {};
502
344
  this.frame = new Set();
503
345
  this.waiting = new Set();
504
- this.onDestroy = new Set();
505
346
  this.followers = new Set();
506
- this.proxy = Object.create(subject);
507
- }
508
- start() {
509
- READY.add(this);
510
- for (const key in this.subject) {
511
- const { value: entry } = getOwnPropertyDescriptor(this.subject, key);
512
- if (typeof entry == "function")
513
- continue;
514
- if (typeof entry == "symbol") {
515
- const instruction = PENDING.get(entry);
516
- if (instruction)
517
- instruction.call(this, key, this);
518
- continue;
519
- }
520
- this.manage(key, entry);
521
- }
522
- this.emit([]);
523
347
  }
524
- stop() {
525
- this.followers.clear();
526
- this.onDestroy.forEach(x => x());
348
+ subscribe(callback) {
349
+ return new Subscriber(this, callback);
527
350
  }
528
- manage(key, value) {
529
- const { proxy, state, subject } = this;
530
- state[key] = value;
531
- const set = this.ref(key);
351
+ add(key) {
352
+ const { subject, state } = this;
353
+ const { value } = getOwnPropertyDescriptor(subject, key);
354
+ if (typeof value == "function")
355
+ return;
356
+ if (typeof value == "symbol") {
357
+ const instruction = PENDING.get(value);
358
+ if (instruction)
359
+ instruction.call(this, key, this);
360
+ return;
361
+ }
362
+ state.set(key, value);
532
363
  defineProperty(subject, key, {
533
364
  enumerable: false,
534
- get: () => state[key],
535
- set
536
- });
537
- defineProperty(proxy, key, {
538
- enumerable: false,
365
+ set: this.ref(key),
539
366
  get() {
540
367
  const local = this[LOCAL];
541
- if (local && !local.watch[key])
542
- local.watch[key] = true;
543
- return state[key];
544
- },
545
- set
368
+ if (local)
369
+ local.add(key);
370
+ return state.get(key);
371
+ }
546
372
  });
547
373
  }
374
+ addListener(listener) {
375
+ this.followers.add(listener);
376
+ return () => {
377
+ this.followers.delete(listener);
378
+ };
379
+ }
548
380
  ref(key, handler) {
549
- const { state, subject } = this;
381
+ const { subject, state } = this;
550
382
  return (value) => {
551
- if (state[key] == value)
383
+ if (state.get(key) == value)
552
384
  return;
553
385
  if (handler)
554
- switch (handler.call(subject, value, state)) {
386
+ switch (handler.call(subject, value)) {
555
387
  case true:
556
388
  this.update(key);
557
389
  case false:
558
390
  return;
559
391
  }
560
- this.update(key, value);
561
- };
562
- }
563
- addListener(listener) {
564
- this.followers.add(listener);
565
- return () => {
566
- this.followers.delete(listener);
392
+ state.set(key, value);
393
+ this.update(key);
567
394
  };
568
395
  }
569
- emit(keys) {
570
- const waiting = [...this.waiting];
571
- this.waiting.clear();
572
- applyUpdate(this.subject, keys)();
573
- for (const callback of waiting)
574
- try {
575
- callback(keys);
576
- }
577
- catch (err) {
578
- console.error(err);
579
- }
580
- }
581
- update(key, value) {
582
- if (1 in arguments)
583
- this.state[key] = value;
584
- if (this.frame.has(key))
396
+ update(key) {
397
+ const { followers, frame, subject, waiting } = this;
398
+ if (frame.has(key))
585
399
  return;
586
- if (!this.frame.size)
400
+ else if (!frame.size)
587
401
  setTimeout(() => {
588
402
  flush(this);
589
- const keys = Object.freeze([...this.frame]);
590
- this.frame.clear();
591
- this.emit(keys);
403
+ const callback = Array.from(waiting);
404
+ const keys = Array.from(frame);
405
+ frame.clear();
406
+ waiting.clear();
407
+ UPDATE.set(subject, keys);
408
+ setTimeout(() => {
409
+ UPDATE.delete(subject);
410
+ }, 0);
411
+ for (const cb of callback)
412
+ try {
413
+ cb();
414
+ }
415
+ catch (err) {
416
+ console.error(err);
417
+ }
592
418
  }, 0);
593
- this.frame.add(key);
594
- for (const callback of this.followers) {
419
+ frame.add(key);
420
+ for (const callback of followers) {
595
421
  const event = callback(key, this);
596
422
  if (typeof event == "function")
597
- this.waiting.add(event);
423
+ waiting.add(event);
598
424
  }
599
425
  }
600
- requestUpdate(arg) {
601
- if (typeof arg == "function") {
602
- this.waiting.add(arg);
603
- return;
426
+ clear() {
427
+ const listeners = [...this.followers];
428
+ this.followers.clear();
429
+ listeners.forEach(x => x(null, this));
430
+ }
431
+ }
432
+
433
+ const Oops$9 = issues({
434
+ Timeout: (keys, timeout) => `No update for [${keys}] within ${timeout}.`,
435
+ StrictUpdate: () => `Strict update() did not find pending updates.`,
436
+ NoChaining: () => `Then called with undefined; update promise will never catch nor supports chaining.`
437
+ });
438
+ const CONTROL = Symbol("CONTROL");
439
+ const WHY = Symbol("UPDATE");
440
+ const LOCAL = Symbol("LOCAL");
441
+ const STATE = Symbol("STATE");
442
+ class Model {
443
+ constructor() {
444
+ define(this, CONTROL, new Controller(this));
445
+ define(this, "get", this);
446
+ define(this, "is", this);
447
+ defineLazy(this, "set", () => {
448
+ const controller = ensure(this);
449
+ const assign = (key, value) => {
450
+ controller.state.set(key, value);
451
+ controller.update(key);
452
+ };
453
+ for (const key of controller.state.keys())
454
+ define(assign, key, controller.ref(key));
455
+ return assign;
456
+ });
457
+ }
458
+ get [STATE]() {
459
+ return this.export();
460
+ }
461
+ get [WHY]() {
462
+ return UPDATE.get(this);
463
+ }
464
+ on(select, handler, squash, once) {
465
+ return ensure(this, control => {
466
+ if (typeof select == "function")
467
+ return control.addListener(select);
468
+ const keys = typeof select == "string" ? [select] :
469
+ select.length ? select : [...control.state.keys()];
470
+ for (const key of keys)
471
+ try {
472
+ void this[key];
473
+ }
474
+ catch (e) { }
475
+ const callback = squash
476
+ ? () => {
477
+ handler.call(this, getUpdate(this));
478
+ }
479
+ : () => {
480
+ getUpdate(this)
481
+ .filter(k => keys.includes(k))
482
+ .forEach(k => {
483
+ handler.call(this, control.state.get(k), k);
484
+ });
485
+ };
486
+ const onEvent = once
487
+ ? () => {
488
+ remove();
489
+ callback();
490
+ }
491
+ : callback;
492
+ const remove = control.addListener(key => {
493
+ if (keys.includes(key))
494
+ return onEvent;
495
+ });
496
+ return remove;
497
+ });
498
+ }
499
+ once(select, argument, squash) {
500
+ if (typeof argument == "function")
501
+ return this.on(select, argument, squash, true);
502
+ if (typeof select == "string")
503
+ select = [select];
504
+ return new Promise((resolve, reject) => {
505
+ const invoke = (key) => {
506
+ if (!key) {
507
+ clear();
508
+ reject(Oops$9.Timeout(select, typeof argument == "number"
509
+ ? `${argument}ms`
510
+ : `lifetime of ${this}`));
511
+ }
512
+ else if (select.includes(key)) {
513
+ clear();
514
+ return resolve;
515
+ }
516
+ };
517
+ const clear = ensure(this, x => {
518
+ for (const key of select)
519
+ try {
520
+ void this[key];
521
+ }
522
+ catch (e) { }
523
+ return x.addListener(invoke);
524
+ });
525
+ if (typeof argument == "number")
526
+ setTimeout(invoke, argument);
527
+ });
528
+ }
529
+ effect(callback, select) {
530
+ const effect = createEffect(callback);
531
+ return ensure(this, control => {
532
+ let busy = false;
533
+ let inject = this.is;
534
+ const invoke = () => {
535
+ if (busy)
536
+ return;
537
+ const output = mayRetry(() => {
538
+ effect.call(inject, inject);
539
+ });
540
+ if (output instanceof Promise) {
541
+ output.finally(() => busy = false);
542
+ busy = true;
543
+ }
544
+ };
545
+ if (!select) {
546
+ const sub = control.subscribe(() => invoke);
547
+ inject = sub.proxy;
548
+ invoke();
549
+ return sub.commit();
550
+ }
551
+ invoke();
552
+ return control.addListener(key => {
553
+ if (key === null) {
554
+ if (!select.length)
555
+ invoke();
556
+ }
557
+ else if (select.includes(key))
558
+ return invoke;
559
+ });
560
+ });
561
+ }
562
+ // TODO: account for exotic properties
563
+ import(source, select) {
564
+ const { subject } = ensure(this);
565
+ if (!select)
566
+ select = getOwnPropertyNames(subject);
567
+ for (const key of select)
568
+ if (key in source)
569
+ this[key] = source[key];
570
+ }
571
+ export(subset) {
572
+ const { state } = ensure(this);
573
+ const output = {};
574
+ const keys = subset || state.keys();
575
+ for (const key of keys)
576
+ output[key] = state.get(key);
577
+ return output;
578
+ }
579
+ update(arg, tag) {
580
+ const target = ensure(this);
581
+ const { frame, waiting } = target;
582
+ if (typeof arg == "string") {
583
+ target.update(arg);
584
+ if (1 in arguments && arg in this) {
585
+ const method = this[arg];
586
+ if (typeof method == "function")
587
+ if (typeof tag != "boolean")
588
+ method.call(this, tag);
589
+ else if (tag)
590
+ method.call(this);
591
+ }
592
+ arg = undefined;
604
593
  }
605
- if (arg === true && this.frame.size < 1)
594
+ if (!frame.size && arg === true)
606
595
  return Promise.reject(Oops$9.StrictUpdate());
607
596
  return {
608
597
  then: (callback) => {
609
- if (callback)
610
- if (this.frame.size || arg !== false)
611
- this.waiting.add(callback);
612
- else
613
- callback(false);
614
- else
598
+ if (!callback)
615
599
  throw Oops$9.NoChaining();
600
+ if (frame.size || arg !== false)
601
+ waiting.add(() => {
602
+ callback(getUpdate(this));
603
+ });
604
+ else
605
+ callback(false);
616
606
  }
617
607
  };
618
608
  }
619
- }
620
- function control(subject, cb) {
621
- let control = subject[CONTROL];
622
- if (!control) {
623
- control = new Controller(subject);
624
- define(subject, CONTROL, control);
609
+ /**
610
+ * Mark this instance for garbage-collection and send `willDestroy` event to all listeners.
611
+ */
612
+ destroy() {
613
+ ensure(this).clear();
625
614
  }
626
- const ready = READY.has(control);
627
- if (!ready) {
628
- if (cb) {
629
- let done;
630
- control.requestUpdate(() => done = cb(control));
631
- return () => done && done();
632
- }
633
- control.start();
615
+ toString() {
616
+ return this.constructor.name;
617
+ }
618
+ /**
619
+ * Creates a new instance of this controller.
620
+ *
621
+ * Beyond `new this(...)`, method will activate managed-state.
622
+ *
623
+ * @param args - arguments sent to constructor
624
+ */
625
+ static create(...args) {
626
+ const instance = new this(...args);
627
+ ensure(instance);
628
+ return instance;
629
+ }
630
+ /**
631
+ * Static equivalent of `x instanceof this`.
632
+ *
633
+ * Will determine if provided class is a subtype of this one.
634
+ */
635
+ static isTypeof(maybe) {
636
+ return (typeof maybe == "function" &&
637
+ maybe.prototype instanceof this);
634
638
  }
635
- return cb ? cb(control) : control;
636
639
  }
637
640
 
641
+ const PENDING = new Map();
638
642
  function apply(fn, label) {
639
643
  const name = label || fn.name || "pending";
640
644
  const placeholder = Symbol(`${name} instruction`);
641
645
  function setup(key) {
642
- const { proxy, state, subject } = this;
646
+ const { subject, state } = this;
643
647
  const control = this;
644
648
  PENDING.delete(placeholder);
645
649
  delete subject[key];
@@ -653,67 +657,56 @@ function apply(fn, label) {
653
657
  return false;
654
658
  }
655
659
  if ("recursive" in output && output.recursive)
656
- output = Object.assign(Object.assign({}, output), { get: recursive(this, key) });
660
+ output = Object.assign(Object.assign({}, output), { get: getRecursive(key, this) });
657
661
  const desc = output;
658
662
  if ("value" in desc)
659
- state[key] = desc.value;
663
+ state.set(key, desc.value);
660
664
  const { get: onGet, set: onSet, enumerable, suspense } = desc;
661
- let set = onSet === false
662
- ? undefined
663
- : this.ref(key, onSet);
665
+ const set = onSet !== false
666
+ ? this.ref(key, onSet)
667
+ : undefined;
664
668
  function get() {
665
- if (!(key in state) && suspense)
669
+ if (!state.has(key) && suspense)
666
670
  throw suspend(control, key);
667
671
  const local = this[LOCAL];
668
- if (local && !(key in local.watch))
669
- local.watch[key] = true;
670
- const value = state[key];
671
- if (!onGet)
672
- return value;
673
- return local
674
- ? onGet(value, local)
675
- : onGet(value);
672
+ if (local)
673
+ local.add(key);
674
+ return onGet
675
+ ? onGet(local)
676
+ : state.get(key);
676
677
  }
677
- for (const x of [subject, proxy])
678
- defineProperty(x, key, { enumerable, get, set });
678
+ defineProperty(subject, key, { enumerable, get, set });
679
679
  }
680
680
  PENDING.set(placeholder, setup);
681
681
  return placeholder;
682
682
  }
683
- function recursive(source, key) {
684
- return forSubscriber((parent, context) => {
685
- let child;
686
- function init() {
687
- if (child) {
688
- child.release();
689
- parent.dependant.delete(child);
690
- context.set(parent, undefined);
691
- child = undefined;
692
- }
693
- const value = source.state[key];
694
- if (value && CONTROL in value) {
695
- child = new Subscriber(value, parent.onUpdate);
696
- if (parent.active)
697
- child.commit();
698
- parent.dependant.add(child);
699
- context.set(parent, child.proxy);
700
- }
701
- }
702
- init();
703
- parent.watch[key] = init;
704
- });
705
- }
706
- function forSubscriber(fn) {
683
+ function getRecursive(key, from) {
707
684
  const context = new WeakMap();
708
- return (value, local) => {
685
+ const { state } = from;
686
+ return (local) => {
709
687
  if (!local)
710
- return value;
688
+ return state.get(key);
711
689
  if (!context.has(local)) {
712
- const output = fn(local, context);
713
- if (output) {
714
- context.set(local, output);
715
- return output;
716
- }
690
+ let child;
691
+ const init = () => {
692
+ if (child) {
693
+ child.release();
694
+ local.dependant.delete(child);
695
+ context.set(local, undefined);
696
+ child = undefined;
697
+ }
698
+ const value = state.get(key);
699
+ if (value && CONTROL in value) {
700
+ child = ensure(value).subscribe(local.onUpdate);
701
+ if (local.active)
702
+ child.commit();
703
+ local.dependant.add(child);
704
+ context.set(local, child.proxy);
705
+ }
706
+ return true;
707
+ };
708
+ init();
709
+ local.add(key, init);
717
710
  }
718
711
  return context.get(local);
719
712
  };
@@ -738,7 +731,7 @@ function act(task) {
738
731
  this.update(key);
739
732
  }
740
733
  });
741
- this.state[key] = undefined;
734
+ this.state.set(key, undefined);
742
735
  defineProperty(invoke, "active", {
743
736
  get: () => pending
744
737
  });
@@ -759,7 +752,7 @@ class Managed extends Array {
759
752
  };
760
753
  }
761
754
  push(...items) {
762
- const length = this.length;
755
+ const { length } = this;
763
756
  const end = super.push(...items);
764
757
  this.update(length, end);
765
758
  return end;
@@ -770,64 +763,65 @@ class Managed extends Array {
770
763
  return end;
771
764
  }
772
765
  splice(start, deleteCount, ...rest) {
773
- this.update(start, deleteCount !== rest.length ? Infinity : deleteCount);
766
+ const end = deleteCount !== rest.length ? Infinity : deleteCount;
767
+ this.update(start, end);
774
768
  return super.splice(start, deleteCount, ...rest);
775
769
  }
776
770
  }
777
771
  function array() {
778
772
  return apply(function array(key) {
773
+ const context = new WeakMap();
779
774
  const array = new Managed(() => this.update(key));
780
- const access = forSubscriber(context => {
781
- const local = Object.create(array);
782
- const update = context.onUpdate(key, this);
775
+ const getLocal = (context) => {
776
+ const proxy = Object.create(array);
783
777
  let rangeA = 0;
784
778
  let rangeB = 0;
785
- function onUpdate() {
779
+ const onUpdate = () => {
786
780
  const [lastA, lastB] = array.lastUpdate;
787
781
  if (rangeA <= lastB && rangeB >= lastA)
788
- return update;
789
- }
790
- function listen(eventA, eventB) {
782
+ return true;
783
+ };
784
+ const listen = (eventA, eventB) => {
791
785
  if (context.active)
792
786
  return;
793
- context.watch[key] = onUpdate;
787
+ context.add(key, onUpdate);
794
788
  rangeA = Math.min(rangeA, eventA);
795
789
  rangeB = Math.max(rangeB, eventB);
796
- }
797
- local[Symbol.iterator] = () => {
790
+ };
791
+ proxy[Symbol.iterator] = () => {
798
792
  listen(0, Infinity);
799
793
  return array[Symbol.iterator]();
800
794
  };
801
- return local;
802
- });
795
+ return proxy;
796
+ };
803
797
  return {
804
- get: access,
798
+ value: array,
805
799
  set: false,
806
- value: array
800
+ get: (local) => {
801
+ if (!local)
802
+ return this.state.get(key);
803
+ if (context.has(local))
804
+ return context.get(local);
805
+ const output = getLocal(local);
806
+ context.set(local, output);
807
+ return output;
808
+ }
807
809
  };
808
810
  });
809
811
  }
810
812
 
811
- function ref(arg) {
813
+ function ref(callback) {
812
814
  return apply(function ref(key) {
813
- let value = {};
814
- if (typeof arg == "object") {
815
- const source = control(arg);
816
- for (const key in source.state)
817
- defineLazy(value, key, createRef.bind(source, key));
818
- }
819
- else
820
- value = createRef.call(this, key, arg);
821
- return { value, explicit: true };
822
- });
823
- }
824
- function createRef(key, cb) {
825
- const refObjectFunction = this.ref(key, cb && createValueEffect(cb));
826
- defineProperty(refObjectFunction, "current", {
827
- set: refObjectFunction,
828
- get: () => this.state[key]
815
+ const value = this.ref(key, callback && createValueEffect(callback));
816
+ defineProperty(value, "current", {
817
+ set: value,
818
+ get: () => this.state.get(key)
819
+ });
820
+ return {
821
+ value,
822
+ explicit: true
823
+ };
829
824
  });
830
- return refObjectFunction;
831
825
  }
832
826
 
833
827
  const Oops$7 = issues({
@@ -835,65 +829,64 @@ const Oops$7 = issues({
835
829
  NotReady: (model, key) => `Value ${model}.${key} value is not yet available.`,
836
830
  Failed: (model, key) => `Generating initial value for ${model}.${key} failed.`
837
831
  });
838
- function set(factory, argument) {
832
+ function put(factory, argument) {
839
833
  return apply(function set(key) {
840
834
  const { subject, state } = this;
841
835
  const required = argument === true || argument === undefined;
842
836
  let set;
843
837
  let get;
844
- let suspense;
845
- if (factory === undefined)
846
- suspense = true;
847
- else {
848
- let pending;
849
- let error;
850
- const init = () => {
851
- const output = typeof factory == "function" ?
852
- mayRetry(() => factory.call(subject, key, subject)) :
853
- factory;
854
- if (output instanceof Promise) {
855
- pending = output
856
- .catch(err => error = err)
857
- .then(val => state[key] = val)
858
- .finally(() => {
859
- pending = undefined;
860
- this.update(key);
861
- });
862
- return;
863
- }
864
- return state[key] = output;
865
- };
866
- const suspend = () => {
867
- if (required === false)
868
- return undefined;
869
- const issue = Oops$7.NotReady(subject, key);
870
- Object.assign(pending, {
871
- message: issue.message,
872
- stack: issue.stack
838
+ let pending;
839
+ let error;
840
+ const init = () => {
841
+ const output = typeof factory == "function" ?
842
+ mayRetry(() => factory.call(subject, key, subject)) :
843
+ factory;
844
+ if (output instanceof Promise) {
845
+ pending = output
846
+ .catch(err => error = err)
847
+ .then(val => {
848
+ state.set(key, val);
849
+ return val;
850
+ })
851
+ .finally(() => {
852
+ pending = undefined;
853
+ this.update(key);
873
854
  });
874
- throw pending;
875
- };
876
- if (required)
877
- try {
878
- init();
879
- }
880
- catch (err) {
881
- Oops$7.Failed(subject, key).warn();
882
- throw err;
883
- }
884
- get = () => {
885
- if (pending)
886
- return suspend();
887
- if (error)
888
- throw error;
889
- if (key in state)
890
- return state[key];
891
- let output = init();
892
- return pending
893
- ? suspend()
894
- : output;
895
- };
896
- }
855
+ return;
856
+ }
857
+ state.set(key, output);
858
+ return output;
859
+ };
860
+ const suspend = () => {
861
+ if (required === false)
862
+ return undefined;
863
+ const issue = Oops$7.NotReady(subject, key);
864
+ Object.assign(pending, {
865
+ message: issue.message,
866
+ stack: issue.stack
867
+ });
868
+ throw pending;
869
+ };
870
+ if (required)
871
+ try {
872
+ init();
873
+ }
874
+ catch (err) {
875
+ Oops$7.Failed(subject, key).warn();
876
+ throw err;
877
+ }
878
+ get = () => {
879
+ if (pending)
880
+ return suspend();
881
+ if (error)
882
+ throw error;
883
+ if (state.has(key))
884
+ return state.get(key);
885
+ let output = init();
886
+ return pending
887
+ ? suspend()
888
+ : output;
889
+ };
897
890
  if (typeof argument == "function")
898
891
  set = createValueEffect(argument);
899
892
  else
@@ -903,8 +896,24 @@ function set(factory, argument) {
903
896
  };
904
897
  return {
905
898
  set,
906
- get,
907
- suspense
899
+ get
900
+ };
901
+ });
902
+ }
903
+
904
+ function set(value, argument) {
905
+ if (!(1 in arguments)) {
906
+ argument = value;
907
+ value = undefined;
908
+ }
909
+ return apply(function set(key) {
910
+ if (value !== undefined)
911
+ this.state.set(key, value);
912
+ return {
913
+ suspense: true,
914
+ set: typeof argument == "function"
915
+ ? createValueEffect(argument)
916
+ : undefined
908
917
  };
909
918
  });
910
919
  }
@@ -929,35 +938,212 @@ function parent(Expects, required) {
929
938
  });
930
939
  }
931
940
 
941
+ const ANY$1 = Symbol("any");
942
+ function managedMap(control, property, initial) {
943
+ const context = new WeakMap();
944
+ const lastUpdate = new Set();
945
+ let managed;
946
+ let value;
947
+ function reset() {
948
+ lastUpdate.clear();
949
+ }
950
+ function emit(key) {
951
+ lastUpdate.add(key);
952
+ control.update(property);
953
+ control.waiting.add(reset);
954
+ }
955
+ function setValue(next, initial) {
956
+ value = next;
957
+ managed = create(next);
958
+ control.state.set(property, next);
959
+ if (!initial)
960
+ emit(ANY$1);
961
+ managed.set = (k, v) => {
962
+ emit(k);
963
+ return value.set(k, v);
964
+ };
965
+ managed.delete = (k) => {
966
+ emit(k);
967
+ return value.delete(k);
968
+ };
969
+ managed.clear = () => {
970
+ emit(ANY$1);
971
+ value.clear();
972
+ };
973
+ }
974
+ function getValue(local) {
975
+ if (!local)
976
+ return managed;
977
+ if (context.has(local))
978
+ return context.get(local);
979
+ const proxy = Object.create(managed);
980
+ const using = new Set();
981
+ context.set(local, proxy);
982
+ local.add(property, () => {
983
+ if (using.has(ANY$1) || lastUpdate.has(ANY$1) && using.size)
984
+ return true;
985
+ for (const key of lastUpdate)
986
+ if (using.has(key))
987
+ return true;
988
+ });
989
+ const watch = (key) => {
990
+ if (!local.active)
991
+ using.add(key);
992
+ };
993
+ proxy.get = (key) => {
994
+ watch(key);
995
+ return value.get(key);
996
+ };
997
+ proxy.has = (key) => {
998
+ watch(key);
999
+ return value.has(key);
1000
+ };
1001
+ proxy.values = () => {
1002
+ watch(ANY$1);
1003
+ return value.values();
1004
+ };
1005
+ proxy.keys = () => {
1006
+ watch(ANY$1);
1007
+ return value.keys();
1008
+ };
1009
+ proxy.entries = () => {
1010
+ watch(ANY$1);
1011
+ return value.entries();
1012
+ };
1013
+ proxy[Symbol.iterator] = () => {
1014
+ watch(ANY$1);
1015
+ return value[Symbol.iterator]();
1016
+ };
1017
+ defineProperty(proxy, "size", {
1018
+ get() {
1019
+ watch(ANY$1);
1020
+ return value.size;
1021
+ }
1022
+ });
1023
+ return proxy;
1024
+ }
1025
+ setValue(initial, true);
1026
+ return {
1027
+ set: setValue,
1028
+ get: getValue
1029
+ };
1030
+ }
1031
+
1032
+ const ANY = Symbol("any");
1033
+ function managedSet(control, property, initial) {
1034
+ const context = new WeakMap();
1035
+ const lastUpdate = new Set();
1036
+ let managed;
1037
+ let value;
1038
+ function reset() {
1039
+ lastUpdate.clear();
1040
+ }
1041
+ function emit(key) {
1042
+ lastUpdate.add(key);
1043
+ control.update(property);
1044
+ control.waiting.add(reset);
1045
+ }
1046
+ function setValue(next, initial) {
1047
+ value = next;
1048
+ managed = create(next);
1049
+ control.state.set(property, next);
1050
+ if (!initial)
1051
+ emit(ANY);
1052
+ managed.add = (k) => {
1053
+ emit(k);
1054
+ return value.add(k);
1055
+ };
1056
+ managed.delete = (k) => {
1057
+ emit(k);
1058
+ return value.delete(k);
1059
+ };
1060
+ managed.clear = () => {
1061
+ emit(ANY);
1062
+ value.clear();
1063
+ };
1064
+ }
1065
+ function getValue(local) {
1066
+ if (!local)
1067
+ return managed;
1068
+ if (context.has(local))
1069
+ return context.get(local);
1070
+ const proxy = Object.create(managed);
1071
+ const using = new Set();
1072
+ context.set(local, proxy);
1073
+ local.add(property, () => {
1074
+ if (using.has(ANY) || lastUpdate.has(ANY) && using.size)
1075
+ return true;
1076
+ for (const key of lastUpdate)
1077
+ if (using.has(key))
1078
+ return true;
1079
+ });
1080
+ const watch = (key) => {
1081
+ if (!local.active)
1082
+ using.add(key);
1083
+ };
1084
+ proxy.has = (key) => {
1085
+ watch(key);
1086
+ return value.has(key);
1087
+ };
1088
+ proxy.values = () => {
1089
+ watch(ANY);
1090
+ return value.values();
1091
+ };
1092
+ proxy.keys = () => {
1093
+ watch(ANY);
1094
+ return value.keys();
1095
+ };
1096
+ proxy.entries = () => {
1097
+ watch(ANY);
1098
+ return value.entries();
1099
+ };
1100
+ proxy[Symbol.iterator] = () => {
1101
+ watch(ANY);
1102
+ return value[Symbol.iterator]();
1103
+ };
1104
+ defineProperty(proxy, "size", {
1105
+ get() {
1106
+ watch(ANY);
1107
+ return value.size;
1108
+ }
1109
+ });
1110
+ return proxy;
1111
+ }
1112
+ setValue(initial, true);
1113
+ return {
1114
+ set: setValue,
1115
+ get: getValue
1116
+ };
1117
+ }
1118
+
932
1119
  const Oops$5 = issues({
933
1120
  BadArgument: (type) => `Instruction \`use\` cannot accept argument type of ${type}.`,
934
1121
  });
935
1122
  function use$1(input, argument) {
936
1123
  return apply(function use(key) {
937
- const { subject } = this;
938
- const onUpdate = (next) => {
939
- this.state[key] = next;
1124
+ const { state, subject } = this;
1125
+ if (typeof input === "function")
1126
+ input = Model.isTypeof(input)
1127
+ ? new input()
1128
+ : input();
1129
+ else if (input && typeof input !== "object")
1130
+ throw Oops$5.BadArgument(typeof input);
1131
+ if (input instanceof Map)
1132
+ return managedMap(this, key, input);
1133
+ if (input instanceof Set)
1134
+ return managedSet(this, key, input);
1135
+ function onUpdate(next) {
1136
+ state.set(key, next);
940
1137
  if (next) {
941
1138
  Parent.set(next, subject);
942
- control(next);
1139
+ ensure(next);
943
1140
  }
944
1141
  if (typeof argument == "function")
945
1142
  argument(next);
946
1143
  return true;
947
- };
948
- if (input) {
949
- const value = Model.isTypeof(input)
950
- ? new input() :
951
- typeof input === "object"
952
- ? input :
953
- typeof input === "function"
954
- ? input()
955
- : null;
956
- if (value === null)
957
- throw Oops$5.BadArgument(typeof input);
958
- if (value)
959
- onUpdate(value);
960
1144
  }
1145
+ if (input)
1146
+ onUpdate(input);
961
1147
  return {
962
1148
  set: onUpdate,
963
1149
  recursive: true
@@ -1069,7 +1255,8 @@ function tap(type, argument) {
1069
1255
  }
1070
1256
  else if (!instance && argument)
1071
1257
  throw Oops$3.AmbientRequired(type.name, subject, key);
1072
- this.update(key, instance);
1258
+ this.state.set(key, instance);
1259
+ this.update(key);
1073
1260
  });
1074
1261
  return {
1075
1262
  recursive: true,
@@ -1114,7 +1301,7 @@ function useModel(source, arg, arg2) {
1114
1301
  new source() :
1115
1302
  source() :
1116
1303
  source;
1117
- control(instance);
1304
+ ensure(instance);
1118
1305
  if (typeof cb == "function")
1119
1306
  cb(instance);
1120
1307
  return instance;
@@ -1132,7 +1319,7 @@ function useModel(source, arg, arg2) {
1132
1319
  return instance;
1133
1320
  }
1134
1321
  else {
1135
- const local = use(refresh => (new Subscriber(instance, () => refresh)));
1322
+ const local = use(refresh => (ensure(instance).subscribe(() => refresh)));
1136
1323
  if (typeof arg == "object") {
1137
1324
  local.active = false;
1138
1325
  if (typeof arg2 !== "object")
@@ -1158,7 +1345,7 @@ function useModel(source, arg, arg2) {
1158
1345
 
1159
1346
  function useFrom(target, compute, suspend) {
1160
1347
  const local = use(refresh => {
1161
- const sub = new Subscriber(target, () => update);
1348
+ const sub = ensure(target).subscribe(() => update);
1162
1349
  const spy = sub.proxy;
1163
1350
  let value = compute.call(spy, spy);
1164
1351
  let update;
@@ -1210,23 +1397,14 @@ function useTap(source, path, expect) {
1210
1397
  }, [])();
1211
1398
  if (typeof path == "function")
1212
1399
  return useFrom(instance, path, expect);
1213
- const local = use(refresh => {
1214
- const parent = control(instance);
1215
- const sub = new Subscriber(parent, () => refresh);
1216
- if (typeof path == "string") {
1217
- const source = sub.proxy;
1218
- defineProperty(sub, "proxy", {
1219
- get() {
1220
- const value = source[path];
1221
- if (value === undefined && expect)
1222
- throw suspend(parent, path);
1223
- return value;
1224
- }
1225
- });
1226
- }
1227
- return sub;
1228
- });
1400
+ const local = use(refresh => (ensure(instance).subscribe(() => refresh)));
1229
1401
  React__default["default"].useLayoutEffect(local.commit, []);
1402
+ if (typeof path !== "undefined") {
1403
+ const value = local.proxy[path];
1404
+ if (value === undefined && expect)
1405
+ throw suspend(ensure(instance), path);
1406
+ return value;
1407
+ }
1230
1408
  return local.proxy;
1231
1409
  }
1232
1410
 
@@ -1247,7 +1425,7 @@ class MVC extends Model {
1247
1425
  static new(arg) {
1248
1426
  const instance = React__default["default"].useMemo(() => {
1249
1427
  const instance = new this();
1250
- control(instance);
1428
+ ensure(instance);
1251
1429
  if (typeof arg == "function")
1252
1430
  arg(instance);
1253
1431
  else if (arg)
@@ -1332,7 +1510,7 @@ function useAppliedProps(within, props) {
1332
1510
  const targets = within.local;
1333
1511
  return function integrate(props) {
1334
1512
  for (const [key, value] of entries(props))
1335
- if (["of", "for", "children"].indexOf(key) < 0)
1513
+ if (!["of", "for", "children"].includes(key))
1336
1514
  for (const into of targets)
1337
1515
  if (into && key in into)
1338
1516
  into[key] = value;
@@ -1344,7 +1522,7 @@ function RenderFunction(props) {
1344
1522
  const hook = use(refresh => {
1345
1523
  const targets = props.context.local;
1346
1524
  if (targets.length == 1)
1347
- return new Subscriber(targets[0], () => refresh);
1525
+ return ensure(targets[0]).subscribe(() => refresh);
1348
1526
  return {};
1349
1527
  });
1350
1528
  if (hook.commit)
@@ -1410,6 +1588,7 @@ exports.array = array;
1410
1588
  exports["default"] = MVC;
1411
1589
  exports.from = from;
1412
1590
  exports.parent = parent;
1591
+ exports.put = put;
1413
1592
  exports.ref = ref;
1414
1593
  exports.set = set;
1415
1594
  exports.tap = tap;