tutuca 0.9.88 → 0.9.90

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tutuca",
3
- "version": "0.9.88",
3
+ "version": "0.9.90",
4
4
  "type": "module",
5
5
  "description": "Zero-dependency SPA framework with immutable state and virtual DOM",
6
6
  "main": "./dist/tutuca.js",
@@ -274,7 +274,7 @@ You can also fire several in one handler
274
274
  ### The request-handler contract
275
275
 
276
276
  Registered request handlers run with **no `this`** (they're invoked as
277
- `fn.apply(null, args)`), so they can't read component state — pass
277
+ `fn.apply(null, [...args, ctx])`), so they can't read component state — pass
278
278
  everything they need through `args`
279
279
  (`ctx.request("persistState", [{ key, value }])`). They're plain async
280
280
  functions or closures. Aggregate handlers from sub-modules with spread:
@@ -285,6 +285,15 @@ export function getRequestHandlers() {
285
285
  }
286
286
  ```
287
287
 
288
+ The handler also receives a request context as its **final argument**
289
+ (consistent with `receive`/`input`/`response`, where `ctx` is last) — usually
290
+ ignored, but available when needed. Like every ctx it exposes
291
+ `ctx.walkPath(callback)`, which walks the component instances on the issuing
292
+ path **leaf→root**, calling `callback(Component, instance)` (return `false` to
293
+ stop early). It captures the immutable dispatch root/path, so it may be called
294
+ before or after an `await`. (The storybook uses this to let an example mock the
295
+ request handlers its component triggers — per example, in isolation.)
296
+
288
297
  ### Chaining from a response handler
289
298
 
290
299
  A `response` handler gets the full `ctx`, so it can issue further
@@ -250,6 +250,17 @@ class Path {
250
250
  }
251
251
  return curVal;
252
252
  }
253
+ resolveChain(root) {
254
+ const out = [root];
255
+ let curVal = root;
256
+ for (const step of this.steps) {
257
+ curVal = step.lookup(curVal, NONE);
258
+ if (curVal === NONE)
259
+ break;
260
+ out.push(curVal);
261
+ }
262
+ return out;
263
+ }
253
264
  setValue(root, v) {
254
265
  const intermediates = new Array(this.steps.length);
255
266
  let curVal = root;
@@ -1979,7 +1990,7 @@ class ANode extends BaseNode {
1979
1990
  const isPseudoX = attrs[0]?.name === "@x";
1980
1991
  if (tag === "X" || isPseudoX)
1981
1992
  return parseXOp(attrs, childs, isPseudoX ? 1 : 0, px);
1982
- else if (tag.charCodeAt(1) === 58 && tag.charCodeAt(0) === 88) {
1993
+ else if (tag.charCodeAt(1) === 58 && (tag.charCodeAt(0) === 88 || tag.charCodeAt(0) === 120)) {
1983
1994
  const macroName = tag.slice(2).toLowerCase();
1984
1995
  if (macroName === "slot") {
1985
1996
  const slotName = attrs.getNamedItem("name")?.value ?? "_";
@@ -2926,6 +2937,7 @@ class Transactor {
2926
2937
  const txnPath = path.toTransactionPath();
2927
2938
  const curLeaf = txnPath.lookup(curRoot);
2928
2939
  const handler = this.comps.getRequestFor(curLeaf, name) ?? mkReq404(name);
2940
+ const reqCtx = new RequestContext(path, this, parent, curRoot);
2929
2941
  const resHandlerName = opts?.onResName ?? name;
2930
2942
  const resPath = opts?.livePath ? null : txnPath.pinKeys(curRoot);
2931
2943
  const push = (specificName, baseName, singleArg, result, error) => {
@@ -2934,7 +2946,7 @@ class Transactor {
2934
2946
  this.pushTransaction(t);
2935
2947
  };
2936
2948
  try {
2937
- const result = await handler.fn.apply(null, args);
2949
+ const result = await handler.fn.apply(null, [...args, reqCtx]);
2938
2950
  push(opts?.onOkName, resHandlerName, result, result, null);
2939
2951
  } catch (error) {
2940
2952
  push(opts?.onErrorName, resHandlerName, error, null, error);
@@ -3177,10 +3189,20 @@ class Task {
3177
3189
  }
3178
3190
 
3179
3191
  class Dispatcher {
3180
- constructor(path, transactor, parentTransaction) {
3192
+ constructor(path, transactor, parentTransaction, root = transactor.state.val) {
3181
3193
  this.path = path;
3182
3194
  this.transactor = transactor;
3183
3195
  this.parent = parentTransaction;
3196
+ this.root = root;
3197
+ }
3198
+ walkPath(callback) {
3199
+ const comps = this.transactor.comps;
3200
+ const chain = this.path.toTransactionPath().resolveChain(this.root);
3201
+ for (let i = chain.length - 1;i >= 0; i--) {
3202
+ const comp = comps.getCompFor(chain[i]);
3203
+ if (comp && callback(comp, chain[i]) === false)
3204
+ return;
3205
+ }
3184
3206
  }
3185
3207
  get at() {
3186
3208
  return new PathChanges(this);
@@ -3217,6 +3239,9 @@ class EventContext extends Dispatcher {
3217
3239
  }
3218
3240
  }
3219
3241
 
3242
+ class RequestContext extends Dispatcher {
3243
+ }
3244
+
3220
3245
  class PathChanges extends PathBuilder {
3221
3246
  constructor(dispatcher) {
3222
3247
  super();