tutuca 0.9.92 → 0.9.94

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/tutuca.js CHANGED
@@ -7290,36 +7290,81 @@ class Transactor {
7290
7290
  this.transactions = [];
7291
7291
  this.state = new State(rootValue);
7292
7292
  this.onTransactionPushed = () => {};
7293
+ this._inflight = new Set;
7293
7294
  }
7294
7295
  pushTransaction(t) {
7295
7296
  this.transactions.push(t);
7296
7297
  this.onTransactionPushed(t);
7297
7298
  }
7299
+ _link(child, parent) {
7300
+ if (parent) {
7301
+ const release = parent.completion.track();
7302
+ child.completion.whenSubtreeSettled().then(release);
7303
+ }
7304
+ return child;
7305
+ }
7298
7306
  pushSend(path, name, args = [], opts = {}, parent = null) {
7299
- this.pushTransaction(new SendEvent(path, this, name, args, parent, opts));
7307
+ const t = new SendEvent(path, this, name, args, parent, opts);
7308
+ this.pushTransaction(t);
7309
+ return this._link(t, parent);
7310
+ }
7311
+ pushInput(path, name, args = [], opts = {}, parent = null) {
7312
+ const t = new InputDispatchEvent(path, this, name, args, parent, opts);
7313
+ this.pushTransaction(t);
7314
+ return this._link(t, parent);
7300
7315
  }
7301
7316
  pushBubble(path, name, args = [], opts = {}, parent = null, targetPath = null) {
7302
7317
  const newOpts = opts.skipSelf ? { ...opts, skipSelf: false } : opts;
7303
- this.pushTransaction(new BubbleEvent(path, this, name, args, parent, newOpts, targetPath));
7304
- }
7305
- async pushRequest(path, name, args = [], opts = {}, parent = null) {
7306
- const curRoot = this.state.val;
7307
- const txnPath = path.toTransactionPath();
7308
- const curLeaf = txnPath.lookup(curRoot);
7309
- const handler = this.comps.getRequestFor(curLeaf, name) ?? mkReq404(name);
7310
- const reqCtx = new RequestContext(path, this, parent, curRoot);
7311
- const resHandlerName = opts?.onResName ?? name;
7312
- const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
7313
- const push = (specificName, baseName, singleArg, result, error) => {
7314
- const resArgs = specificName ? [singleArg] : [result, error];
7315
- const t = new ResponseEvent(path, this, specificName ?? baseName, resArgs, parent, resPath);
7316
- this.pushTransaction(t);
7318
+ const t = new BubbleEvent(path, this, name, args, parent, newOpts, targetPath);
7319
+ this.pushTransaction(t);
7320
+ return this._link(t, parent);
7321
+ }
7322
+ pushRequest(path, name, args = [], opts = {}, parent = null) {
7323
+ const release = parent ? parent.completion.track() : null;
7324
+ const p = this._runRequest(path, name, args, opts, parent, release);
7325
+ this._inflight.add(p);
7326
+ p.finally(() => this._inflight.delete(p));
7327
+ return p;
7328
+ }
7329
+ async settle(maxTurns = 1e4) {
7330
+ while ((this.hasPendingTransactions || this._inflight.size) && maxTurns-- > 0) {
7331
+ while (this.hasPendingTransactions)
7332
+ this.transactNext();
7333
+ if (this._inflight.size)
7334
+ await Promise.allSettled([...this._inflight]);
7335
+ }
7336
+ }
7337
+ async _runRequest(path, name, args = [], opts = {}, parent = null, release = null) {
7338
+ let released = false;
7339
+ const transfer = (t) => {
7340
+ if (release) {
7341
+ released = true;
7342
+ t.completion.whenSubtreeSettled().then(release);
7343
+ }
7317
7344
  };
7318
7345
  try {
7319
- const result = await handler.fn.apply(null, [...args, reqCtx]);
7320
- push(opts?.onOkName, resHandlerName, result, result, null);
7321
- } catch (error) {
7322
- push(opts?.onErrorName, resHandlerName, error, null, error);
7346
+ const curRoot = this.state.val;
7347
+ const txnPath = path.toTransactionPath();
7348
+ const curLeaf = txnPath.lookup(curRoot);
7349
+ const handler = this.comps.getRequestFor(curLeaf, name) ?? mkReq404(name);
7350
+ const reqCtx = new RequestContext(path, this, parent, curRoot);
7351
+ const resHandlerName = opts?.onResName ?? name;
7352
+ const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
7353
+ const push = (specificName, baseName, singleArg, result, error) => {
7354
+ const resArgs = specificName ? [singleArg] : [result, error];
7355
+ const t = new ResponseEvent(path, this, specificName ?? baseName, resArgs, parent, resPath);
7356
+ transfer(t);
7357
+ this.pushTransaction(t);
7358
+ };
7359
+ try {
7360
+ const result = await handler.fn.apply(null, [...args, reqCtx]);
7361
+ push(opts?.onOkName, resHandlerName, result, result, null);
7362
+ } catch (error) {
7363
+ push(opts?.onErrorName, resHandlerName, error, null, error);
7364
+ }
7365
+ } finally {
7366
+ if (release && !released)
7367
+ release();
7323
7368
  }
7324
7369
  }
7325
7370
  get hasPendingTransactions() {
@@ -7330,13 +7375,18 @@ class Transactor {
7330
7375
  this.transact(this.transactions.shift());
7331
7376
  }
7332
7377
  transact(transaction) {
7333
- const curState = this.state.val;
7334
- const newState = transaction.run(curState, this.comps);
7335
- if (newState !== undefined) {
7336
- this.state.set(newState, { transaction });
7337
- transaction.afterTransaction();
7338
- } else
7339
- console.warn("undefined new state", { curState, transaction });
7378
+ try {
7379
+ const curState = this.state.val;
7380
+ const newState = transaction.run(curState, this.comps);
7381
+ if (newState !== undefined) {
7382
+ this.state.set(newState, { transaction });
7383
+ transaction.afterTransaction();
7384
+ } else
7385
+ console.warn("undefined new state", { curState, transaction });
7386
+ } finally {
7387
+ transaction._completion?.ensureSelfSettled();
7388
+ transaction._completion?.releaseSelf();
7389
+ }
7340
7390
  }
7341
7391
  transactInputNow(path, event, eventHandler, dragInfo) {
7342
7392
  this.transact(new InputEvent(path, event, eventHandler, this, dragInfo));
@@ -7357,18 +7407,17 @@ class Transaction {
7357
7407
  this.path = path;
7358
7408
  this.transactor = transactor;
7359
7409
  this.parentTransaction = parentTransaction;
7360
- this._task = null;
7410
+ this._completion = null;
7361
7411
  }
7362
- get task() {
7363
- this._task ??= new Task;
7364
- return this._task;
7412
+ get completion() {
7413
+ this._completion ??= new Completion;
7414
+ return this._completion;
7365
7415
  }
7366
- getCompletionPromise() {
7367
- return this.task.promise;
7416
+ whenSettled() {
7417
+ return this.completion.whenSettled();
7368
7418
  }
7369
- setParent(parentTransaction) {
7370
- this.parentTransaction = parentTransaction;
7371
- parentTransaction.task.addDep(this.task);
7419
+ whenSubtreeSettled() {
7420
+ return this.completion.whenSubtreeSettled();
7372
7421
  }
7373
7422
  run(rootValue, comps) {
7374
7423
  return this.updateRootValue(rootValue, comps);
@@ -7394,7 +7443,7 @@ class Transaction {
7394
7443
  const txnPath = this.getTransactionPath();
7395
7444
  const curLeaf = txnPath.lookup(curRoot);
7396
7445
  const newLeaf = this.callHandler(curRoot, curLeaf, comps);
7397
- this._task?.complete?.({ value: newLeaf, old: curLeaf });
7446
+ this._completion?.markSelfSettled({ value: newLeaf, old: curLeaf });
7398
7447
  return curLeaf !== newLeaf ? txnPath.setValue(curRoot, newLeaf) : curRoot;
7399
7448
  }
7400
7449
  lookupName(_name) {
@@ -7531,29 +7580,69 @@ class BubbleEvent extends SendEvent {
7531
7580
  }
7532
7581
  }
7533
7582
 
7534
- class Task {
7583
+ class InputDispatchEvent extends NameArgsTransaction {
7584
+ handlerProp = "input";
7585
+ }
7586
+
7587
+ class Completion {
7535
7588
  constructor() {
7536
- this.deps = [];
7537
- this.val = this.resolve = this.reject = null;
7538
- this.promise = new Promise((res, rej) => {
7539
- this.resolve = res;
7540
- this.reject = rej;
7589
+ this.val = undefined;
7590
+ this.selfSettled = false;
7591
+ this.subtreeSettled = false;
7592
+ this.pending = 1;
7593
+ this._selfResolve = null;
7594
+ this._selfPromise = null;
7595
+ this._subtreeResolve = null;
7596
+ this._subtreePromise = null;
7597
+ this._selfReleased = false;
7598
+ }
7599
+ whenSettled() {
7600
+ if (this.selfSettled)
7601
+ return Promise.resolve(this.val);
7602
+ this._selfPromise ??= new Promise((res) => {
7603
+ this._selfResolve = res;
7541
7604
  });
7542
- this.isCompleted = false;
7605
+ return this._selfPromise;
7543
7606
  }
7544
- addDep(task) {
7545
- console.assert(!this.isCompleted, "addDep for completed task", this, task);
7546
- this.deps.push(task);
7547
- task.promise.then((_) => this._check());
7607
+ whenSubtreeSettled() {
7608
+ if (this.subtreeSettled)
7609
+ return Promise.resolve(this.val);
7610
+ this._subtreePromise ??= new Promise((res) => {
7611
+ this._subtreeResolve = res;
7612
+ });
7613
+ return this._subtreePromise;
7548
7614
  }
7549
- complete(val) {
7615
+ markSelfSettled(val) {
7616
+ if (this.selfSettled)
7617
+ return;
7618
+ this.selfSettled = true;
7550
7619
  this.val = val;
7551
- this._check();
7620
+ this._selfResolve?.(val);
7621
+ }
7622
+ ensureSelfSettled() {
7623
+ if (!this.selfSettled)
7624
+ this.markSelfSettled(this.val);
7625
+ }
7626
+ track() {
7627
+ this.pending++;
7628
+ let done = false;
7629
+ return () => {
7630
+ if (done)
7631
+ return;
7632
+ done = true;
7633
+ this._release();
7634
+ };
7552
7635
  }
7553
- _check() {
7554
- if (this.deps.every((task) => task.isCompleted)) {
7555
- this.isCompleted = true;
7556
- this.resolve(this);
7636
+ releaseSelf() {
7637
+ if (this._selfReleased)
7638
+ return;
7639
+ this._selfReleased = true;
7640
+ this._release();
7641
+ }
7642
+ _release() {
7643
+ if (--this.pending === 0) {
7644
+ this.subtreeSettled = true;
7645
+ this._subtreeResolve?.(this.val);
7557
7646
  }
7558
7647
  }
7559
7648
  }
@@ -7592,6 +7681,9 @@ class Dispatcher {
7592
7681
  requestAtPath(path, name, args, opts) {
7593
7682
  return this.transactor.pushRequest(path, name, args, opts, this.parent);
7594
7683
  }
7684
+ inputAtPath(path, name, args, opts) {
7685
+ return this.transactor.pushInput(path, name, args, opts, this.parent);
7686
+ }
7595
7687
  lookupTypeFor(name, inst) {
7596
7688
  return this.transactor.comps.getCompFor(inst).scope.lookupComponent(name);
7597
7689
  }
@@ -7890,6 +7982,45 @@ class DragInfo {
7890
7982
  return this.stack.lookupBind(name);
7891
7983
  }
7892
7984
  }
7985
+ // src/on.js
7986
+ var OP_KINDS = ["send", "bubble", "request", "input"];
7987
+ function phaseOps(phase) {
7988
+ const ops = [];
7989
+ for (const type of OP_KINDS)
7990
+ for (const a of phase[type] ?? [])
7991
+ ops.push({ type, ...a });
7992
+ for (const a of phase.do ?? [])
7993
+ ops.push(a);
7994
+ return ops;
7995
+ }
7996
+ function resolveArgs(args, self) {
7997
+ return typeof args === "function" ? args(self) ?? [] : args ?? [];
7998
+ }
7999
+ function dispatchPhase(dispatcher, targetPath, phase, self) {
8000
+ if (!phase)
8001
+ return;
8002
+ for (const op of phaseOps(phase)) {
8003
+ const args = resolveArgs(op.args, self);
8004
+ switch (op.type) {
8005
+ case "send":
8006
+ dispatcher.sendAtPath(targetPath, op.name, args, op.opts);
8007
+ break;
8008
+ case "bubble":
8009
+ dispatcher.sendAtPath(targetPath, op.name, args, {
8010
+ skipSelf: true,
8011
+ bubbles: true,
8012
+ ...op.opts
8013
+ });
8014
+ break;
8015
+ case "request":
8016
+ dispatcher.requestAtPath(targetPath, op.name, args, op.opts);
8017
+ break;
8018
+ case "input":
8019
+ dispatcher.inputAtPath(targetPath, op.name, args, op.opts);
8020
+ break;
8021
+ }
8022
+ }
8023
+ }
7893
8024
  // src/oo.js
7894
8025
  var BAD_VALUE = Symbol("BadValue");
7895
8026
  var nullCoercer = (v) => v;
@@ -8302,8 +8433,10 @@ export {
8302
8433
  test,
8303
8434
  setIn$1 as setIn,
8304
8435
  set,
8436
+ resolveArgs,
8305
8437
  removeIn,
8306
8438
  remove,
8439
+ phaseOps,
8307
8440
  mergeWith$1 as mergeWith,
8308
8441
  mergeDeepWith$1 as mergeDeepWith,
8309
8442
  mergeDeep$1 as mergeDeep,
@@ -8336,6 +8469,7 @@ export {
8336
8469
  getIn$1 as getIn,
8337
8470
  get,
8338
8471
  fromJS,
8472
+ dispatchPhase,
8339
8473
  css,
8340
8474
  component,
8341
8475
  collectIterBindings,