tutuca 0.13.2 → 0.14.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/tutuca-cli.js +611 -458
- package/dist/tutuca-dev.ext.js +642 -486
- package/dist/tutuca-dev.js +653 -497
- package/dist/tutuca-dev.min.js +4 -4
- package/dist/tutuca-extra.ext.js +625 -451
- package/dist/tutuca-extra.js +632 -458
- package/dist/tutuca-extra.min.js +3 -3
- package/dist/tutuca.ext.js +625 -451
- package/dist/tutuca.js +632 -458
- package/dist/tutuca.min.js +3 -3
- package/package.json +1 -1
- package/skill/tutuca/SKILL.md +2 -2
- package/skill/tutuca/advanced.md +48 -17
- package/skill/tutuca/component-design.md +2 -2
- package/skill/tutuca/core.md +7 -1
- package/skill/tutuca/messages-and-intents.md +1 -1
- package/skill/tutuca/patterns/README.md +1 -1
- package/skill/tutuca/patterns/edit-through-a-dynamic-target.md +11 -6
- package/skill/tutuca/patterns/share-state-across-the-tree.md +18 -3
- package/skill/tutuca/semantics.md +43 -28
- package/skill/tutuca-source/tutuca.ext.js +625 -451
package/dist/tutuca-dev.ext.js
CHANGED
|
@@ -128,8 +128,8 @@ function jestMatchers(chai2, utils) {
|
|
|
128
128
|
expected
|
|
129
129
|
);
|
|
130
130
|
});
|
|
131
|
-
m("toHaveProperty", function(
|
|
132
|
-
const keys = Array.isArray(
|
|
131
|
+
m("toHaveProperty", function(path2, ...rest) {
|
|
132
|
+
const keys = Array.isArray(path2) ? path2 : String(path2).split(".");
|
|
133
133
|
let cur = this._obj;
|
|
134
134
|
let found = true;
|
|
135
135
|
for (const k of keys) {
|
|
@@ -144,7 +144,7 @@ function jestMatchers(chai2, utils) {
|
|
|
144
144
|
pass,
|
|
145
145
|
"expected #{this} to have property #{exp}",
|
|
146
146
|
"expected #{this} not to have property #{exp}",
|
|
147
|
-
|
|
147
|
+
path2
|
|
148
148
|
);
|
|
149
149
|
});
|
|
150
150
|
m("toBeInstanceOf", function(ctor) {
|
|
@@ -234,8 +234,11 @@ var Step = class {
|
|
|
234
234
|
}
|
|
235
235
|
setDraftValue(_root, _v) {
|
|
236
236
|
}
|
|
237
|
-
|
|
238
|
-
|
|
237
|
+
// Re-enter this step while rebuilding a stack. `renderPath` is the dispatch
|
|
238
|
+
// position AFTER this step: a rebuilt frame must carry the same render path
|
|
239
|
+
// the renderer had there, or the provides it publishes would be located wrong.
|
|
240
|
+
enterFrame(stack, next, renderPath) {
|
|
241
|
+
return stack.enter(next, {}, true, renderPath);
|
|
239
242
|
}
|
|
240
243
|
toAbstractPathStep() {
|
|
241
244
|
return this;
|
|
@@ -260,8 +263,8 @@ var BindStep = class _BindStep extends Step {
|
|
|
260
263
|
lookup(v, _dval) {
|
|
261
264
|
return v;
|
|
262
265
|
}
|
|
263
|
-
enterFrame(stack, next) {
|
|
264
|
-
return stack.enter(next, { ...this.binds }, false);
|
|
266
|
+
enterFrame(stack, next, renderPath) {
|
|
267
|
+
return stack.enter(next, { ...this.binds }, false, renderPath);
|
|
265
268
|
}
|
|
266
269
|
withIndex(i) {
|
|
267
270
|
return new _BindStep({ ...this.binds, key: i });
|
|
@@ -278,9 +281,9 @@ var ScopeBindStep = class _ScopeBindStep extends BindStep {
|
|
|
278
281
|
super(binds);
|
|
279
282
|
this.val = val;
|
|
280
283
|
}
|
|
281
|
-
enterFrame(stack, next) {
|
|
284
|
+
enterFrame(stack, next, renderPath) {
|
|
282
285
|
const dyn = this.val.evalAsHandler(stack)?.call(stack.it) ?? {};
|
|
283
|
-
return stack.enter(next, { ...this.binds, ...dyn }, false);
|
|
286
|
+
return stack.enter(next, { ...this.binds, ...dyn }, false, renderPath);
|
|
284
287
|
}
|
|
285
288
|
withIndex(i) {
|
|
286
289
|
return new _ScopeBindStep(this.val, { ...this.binds, key: i });
|
|
@@ -323,8 +326,8 @@ var SeqStep = class extends Step {
|
|
|
323
326
|
const seq = readKey(root, this.field, null);
|
|
324
327
|
if (seq != null) writeSeqKey(seq, this.key, v);
|
|
325
328
|
}
|
|
326
|
-
enterFrame(stack, next) {
|
|
327
|
-
return stack.enter(next, { key: this.key }, true);
|
|
329
|
+
enterFrame(stack, next, renderPath) {
|
|
330
|
+
return stack.enter(next, { key: this.key }, true, renderPath);
|
|
328
331
|
}
|
|
329
332
|
toKey() {
|
|
330
333
|
return { field: this.field, key: this.key };
|
|
@@ -370,60 +373,52 @@ var EachBindStep = class extends Step {
|
|
|
370
373
|
}
|
|
371
374
|
// Replay the renderer's per-item binds (key, value + any @enrich-with binds)
|
|
372
375
|
// so a rebuilt stack matches the one @each rendered with.
|
|
373
|
-
enterFrame(stack, next) {
|
|
374
|
-
return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false);
|
|
376
|
+
enterFrame(stack, next, renderPath) {
|
|
377
|
+
return stack.enter(next, this.iterInfo.enrichBinds(stack, this.key), false, renderPath);
|
|
375
378
|
}
|
|
376
379
|
toAbstractPathStep() {
|
|
377
380
|
return null;
|
|
378
381
|
}
|
|
379
382
|
};
|
|
380
383
|
var EachRenderItStep = class extends SeqStep {
|
|
381
|
-
enterFrame(stack, next) {
|
|
382
|
-
return stack.enter(next, { key: this.key, value: next }, false).enter(next, {}, true);
|
|
384
|
+
enterFrame(stack, next, renderPath) {
|
|
385
|
+
return stack.enter(next, { key: this.key, value: next }, false, renderPath).enter(next, {}, true, renderPath);
|
|
383
386
|
}
|
|
384
387
|
toAbstractPathStep() {
|
|
385
388
|
return new SeqStep(this.field, this.key);
|
|
386
389
|
}
|
|
387
390
|
};
|
|
388
|
-
function
|
|
389
|
-
|
|
391
|
+
function stepToJson(step) {
|
|
392
|
+
if (step instanceof SeqStep) return { f: step.field, k: step.key };
|
|
393
|
+
if (step instanceof FieldStep) return { f: step.field };
|
|
394
|
+
if (step instanceof SeqAccessStep) return { f: step.seqField, a: step.keyField };
|
|
395
|
+
return null;
|
|
390
396
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
warnRawDynStep("lookup", this);
|
|
404
|
-
return dval;
|
|
405
|
-
}
|
|
406
|
-
enterFrame(stack, _next) {
|
|
407
|
-
warnRawDynStep("enterFrame", this);
|
|
408
|
-
return stack;
|
|
409
|
-
}
|
|
410
|
-
};
|
|
411
|
-
var DynEachStep = class extends DynStep {
|
|
412
|
-
constructor(producerCompId, producerSteps, key) {
|
|
413
|
-
super(producerCompId, producerSteps);
|
|
414
|
-
this.key = key;
|
|
397
|
+
function stepFromJson(j) {
|
|
398
|
+
if (j == null || typeof j.f !== "string") return null;
|
|
399
|
+
if (j.k !== void 0) return new SeqStep(j.f, j.k);
|
|
400
|
+
if (j.a !== void 0) return new SeqAccessStep(j.f, j.a);
|
|
401
|
+
return new FieldStep(j.f);
|
|
402
|
+
}
|
|
403
|
+
function pathToJson(path2) {
|
|
404
|
+
const out = [];
|
|
405
|
+
for (const step of path2.steps) {
|
|
406
|
+
const j = stepToJson(step);
|
|
407
|
+
if (j === null) return null;
|
|
408
|
+
out.push(j);
|
|
415
409
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
410
|
+
return out;
|
|
411
|
+
}
|
|
412
|
+
function pathFromJson(j) {
|
|
413
|
+
if (!Array.isArray(j)) return null;
|
|
414
|
+
const steps = [];
|
|
415
|
+
for (const item of j) {
|
|
416
|
+
const step = stepFromJson(item);
|
|
417
|
+
if (step === null) return null;
|
|
418
|
+
steps.push(step);
|
|
425
419
|
}
|
|
426
|
-
|
|
420
|
+
return new Path(steps);
|
|
421
|
+
}
|
|
427
422
|
var Path = class _Path {
|
|
428
423
|
constructor(steps = []) {
|
|
429
424
|
this.steps = steps;
|
|
@@ -434,40 +429,13 @@ var Path = class _Path {
|
|
|
434
429
|
popStep() {
|
|
435
430
|
return new _Path(this.steps.slice(0, -1));
|
|
436
431
|
}
|
|
437
|
-
//
|
|
438
|
-
//
|
|
432
|
+
// Frame-only steps removed, one step per crossed component: `popStep` over the
|
|
433
|
+
// result bubbles through every component.
|
|
439
434
|
compact() {
|
|
440
435
|
const out = [];
|
|
441
436
|
for (const step of this.steps) {
|
|
442
437
|
const s = step.toAbstractPathStep();
|
|
443
|
-
if (s !== null)
|
|
444
|
-
if (s !== step) s._originCid = step._originCid;
|
|
445
|
-
out.push(s);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
return new _Path(out);
|
|
449
|
-
}
|
|
450
|
-
// The abstract path used to apply a transaction: every DynStep is teleported —
|
|
451
|
-
// the steps interior to its producer..consumer span are dropped and the
|
|
452
|
-
// producer's own path spliced in — so a mutation lands on the data's real
|
|
453
|
-
// location. A path with no DynStep is returned unchanged.
|
|
454
|
-
toTransactionPath() {
|
|
455
|
-
let hasDyn = false;
|
|
456
|
-
for (const step of this.steps)
|
|
457
|
-
if (step instanceof DynStep) {
|
|
458
|
-
hasDyn = true;
|
|
459
|
-
break;
|
|
460
|
-
}
|
|
461
|
-
if (!hasDyn) return this;
|
|
462
|
-
const out = [];
|
|
463
|
-
for (const step of this.steps) {
|
|
464
|
-
if (step instanceof DynStep) {
|
|
465
|
-
while (out.length > 0 && step.interiorCids.has(out[out.length - 1]._originCid)) out.pop();
|
|
466
|
-
for (const ts of step.teleportSteps()) {
|
|
467
|
-
ts._originCid = step.producerCompId;
|
|
468
|
-
out.push(ts);
|
|
469
|
-
}
|
|
470
|
-
} else out.push(step);
|
|
438
|
+
if (s !== null) out.push(s);
|
|
471
439
|
}
|
|
472
440
|
return new _Path(out);
|
|
473
441
|
}
|
|
@@ -475,7 +443,6 @@ var Path = class _Path {
|
|
|
475
443
|
// key as it is *now* so a later lookup/setValue lands on the same item even if the
|
|
476
444
|
// keyField changed meanwhile (e.g. the selected tab moved while an intent was in
|
|
477
445
|
// flight). Returns a new Path with those steps replaced; `this` if nothing pinned.
|
|
478
|
-
// Must be called on a transaction path (no DynSteps — call toTransactionPath first).
|
|
479
446
|
pinKeys(root) {
|
|
480
447
|
let curVal = root;
|
|
481
448
|
let out = null;
|
|
@@ -498,8 +465,8 @@ var Path = class _Path {
|
|
|
498
465
|
}
|
|
499
466
|
// The values entered along the path, root→leaf (root included): index 0 is `root`,
|
|
500
467
|
// the last entry is the leaf this path resolves to. Stops early at the first
|
|
501
|
-
// unresolvable step.
|
|
502
|
-
//
|
|
468
|
+
// unresolvable step. Used to walk the component instances on a dispatch path
|
|
469
|
+
// (filter via Components.getCompFor).
|
|
503
470
|
resolveChain(root) {
|
|
504
471
|
const out = [root];
|
|
505
472
|
let curVal = root;
|
|
@@ -513,7 +480,7 @@ var Path = class _Path {
|
|
|
513
480
|
// A flat `[{ field, key? }]` list of the addressing steps, skipping frame-only
|
|
514
481
|
// steps (binds). Generic path introspection so tooling (e.g. the storybook
|
|
515
482
|
// activity log) can identify which subtree a transaction touched without
|
|
516
|
-
// depending on Step internals.
|
|
483
|
+
// depending on Step internals.
|
|
517
484
|
toKeys() {
|
|
518
485
|
const out = [];
|
|
519
486
|
for (const step of this.steps) {
|
|
@@ -534,62 +501,147 @@ var Path = class _Path {
|
|
|
534
501
|
});
|
|
535
502
|
}
|
|
536
503
|
buildStack(stack) {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
504
|
+
return walkItems(stack, this.steps, stack.renderPath ?? new DispatchPath(), this)?.[0] ?? null;
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
function walkItems(stack, items, renderPath, path2) {
|
|
508
|
+
let prev = stack.it;
|
|
509
|
+
for (const step of items) {
|
|
510
|
+
const next = step.lookup(prev, NONE);
|
|
511
|
+
if (next === NONE) {
|
|
512
|
+
console.warn("bad PathItem", { root: stack.it, step, path: path2 });
|
|
513
|
+
return null;
|
|
514
|
+
}
|
|
515
|
+
renderPath = renderPath.pushItem(step);
|
|
516
|
+
stack = step.enterFrame(stack, next, renderPath);
|
|
517
|
+
prev = next;
|
|
518
|
+
}
|
|
519
|
+
return [stack, renderPath];
|
|
520
|
+
}
|
|
521
|
+
var EMPTY_PATH = new Path([]);
|
|
522
|
+
var DispatchPath = class _DispatchPath {
|
|
523
|
+
constructor(frames = [{ base: EMPTY_PATH, items: [] }]) {
|
|
524
|
+
this.frames = frames;
|
|
525
|
+
}
|
|
526
|
+
// Plain addressing steps in one frame based at the root: what a caller means
|
|
527
|
+
// by "this position" when it has no continuation of its own.
|
|
528
|
+
static ofSteps(steps) {
|
|
529
|
+
return new _DispatchPath([{ base: EMPTY_PATH, items: steps.slice() }]);
|
|
530
|
+
}
|
|
531
|
+
get top() {
|
|
532
|
+
return this.frames[this.frames.length - 1];
|
|
533
|
+
}
|
|
534
|
+
_withTopItems(items) {
|
|
535
|
+
const frames = this.frames.slice();
|
|
536
|
+
frames[frames.length - 1] = { base: this.top.base, items };
|
|
537
|
+
return new _DispatchPath(frames);
|
|
538
|
+
}
|
|
539
|
+
concat(steps) {
|
|
540
|
+
if (this.frames.length === 0) return _DispatchPath.ofSteps(steps);
|
|
541
|
+
return this._withTopItems(this.top.items.concat(steps));
|
|
542
|
+
}
|
|
543
|
+
pushItem(step) {
|
|
544
|
+
return this.concat([step]);
|
|
545
|
+
}
|
|
546
|
+
pushFrame(base) {
|
|
547
|
+
return new _DispatchPath(this.frames.concat({ base, items: [] }));
|
|
548
|
+
}
|
|
549
|
+
// Whether bubbling has anywhere left to go: another step in this frame, or a
|
|
550
|
+
// visual caller underneath it.
|
|
551
|
+
canPop() {
|
|
552
|
+
const n = this.frames.length;
|
|
553
|
+
return n > 1 || n === 1 && this.frames[0].items.length > 0;
|
|
554
|
+
}
|
|
555
|
+
isRoot() {
|
|
556
|
+
return this.toTransactionPath().steps.length === 0;
|
|
557
|
+
}
|
|
558
|
+
// One component closer to the root. At the top of a frame that is popping back
|
|
559
|
+
// to the visual caller, not to the producer's own parent — the caller is where
|
|
560
|
+
// the `*name` was written, and where an unhandled message should keep going.
|
|
561
|
+
popStep() {
|
|
562
|
+
const n = this.frames.length;
|
|
563
|
+
if (n === 0) return this;
|
|
564
|
+
const top = this.frames[n - 1];
|
|
565
|
+
if (top.items.length > 0) return this._withTopItems(top.items.slice(0, -1));
|
|
566
|
+
if (n > 1) return new _DispatchPath(this.frames.slice(0, -1));
|
|
567
|
+
return this;
|
|
568
|
+
}
|
|
569
|
+
// Drop frame-only steps inside every frame independently; a frame's base is
|
|
570
|
+
// already addressing-only.
|
|
571
|
+
compact() {
|
|
572
|
+
return new _DispatchPath(
|
|
573
|
+
this.frames.map(({ base, items }) => ({ base, items: new Path(items).compact().steps }))
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
// A stable string for the ADDRESS this path denotes, for the render cache. The
|
|
577
|
+
// same immutable value can sit at two places in the tree, and a subtree rendered
|
|
578
|
+
// at one of them bakes that address in — the provides it publishes are located
|
|
579
|
+
// there. Frame-only steps address nothing, so they are compacted out: two sites
|
|
580
|
+
// that differ only in binds do render the same subtree.
|
|
581
|
+
get addressKey() {
|
|
582
|
+
this._addressKey ??= renderPathText(this.toTransactionPath().compact());
|
|
583
|
+
return this._addressKey;
|
|
584
|
+
}
|
|
585
|
+
// The active transaction address: the top frame's absolute base followed by
|
|
586
|
+
// its ordinary descendant steps. This is where a mutation lands.
|
|
587
|
+
toTransactionPath() {
|
|
588
|
+
const top = this.top;
|
|
589
|
+
return top === void 0 ? EMPTY_PATH : top.base.concat(top.items);
|
|
590
|
+
}
|
|
591
|
+
// Rebuild the render stack this path was dispatched from. A frame with a base
|
|
592
|
+
// re-enters at that absolute value first — replaying the resume a `*name`
|
|
593
|
+
// render performed — and then walks its ordinary items.
|
|
594
|
+
buildStack(stack) {
|
|
595
|
+
let renderPath = new _DispatchPath();
|
|
596
|
+
for (let i = 0; i < this.frames.length; i++) {
|
|
597
|
+
const { base, items } = this.frames[i];
|
|
598
|
+
if (i > 0 || base.steps.length > 0) {
|
|
599
|
+
const baseValue = base.lookup(stack.root, NONE);
|
|
600
|
+
if (baseValue === NONE) {
|
|
601
|
+
console.warn("bad frame base", { base, path: this });
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
renderPath = renderPath.pushFrame(base);
|
|
605
|
+
stack = stack.enter(baseValue, {}, true, renderPath);
|
|
543
606
|
}
|
|
544
|
-
|
|
545
|
-
|
|
607
|
+
const walked = walkItems(stack, items, renderPath, this);
|
|
608
|
+
if (walked === null) return null;
|
|
609
|
+
[stack, renderPath] = walked;
|
|
546
610
|
}
|
|
547
611
|
return stack;
|
|
548
612
|
}
|
|
549
613
|
static fromNodeAndEventName(node, eventName, rootNode, maxDepth, comps, stopOnNoEvent = true) {
|
|
550
|
-
const
|
|
551
|
-
const pendingDyns = [];
|
|
614
|
+
const parts = [];
|
|
552
615
|
const bubbles = BUBBLING_EVENTS.has(eventName);
|
|
553
616
|
let depth = 0;
|
|
554
617
|
let eventIds = [];
|
|
555
618
|
let handlers = null;
|
|
556
|
-
let
|
|
619
|
+
let nodeRefs = [];
|
|
557
620
|
let isLeafComponent = true;
|
|
558
621
|
const crossComponent = (cidNum, vid) => {
|
|
559
622
|
const comp = comps.getComponentForId(cidNum);
|
|
560
|
-
let
|
|
623
|
+
let pushPart = true;
|
|
561
624
|
if (handlers === null && (isLeafComponent || bubbles)) {
|
|
562
625
|
handlers = findHandlers(comp, eventIds, vid, eventName);
|
|
563
626
|
if (handlers === null) {
|
|
564
627
|
if (isLeafComponent && stopOnNoEvent && !bubbles) return false;
|
|
565
628
|
} else if (!isLeafComponent) {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
pushStep = false;
|
|
629
|
+
parts.length = 0;
|
|
630
|
+
pushPart = false;
|
|
569
631
|
}
|
|
570
632
|
}
|
|
571
633
|
isLeafComponent = false;
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
if (step) {
|
|
576
|
-
step._originCid = cidNum;
|
|
577
|
-
pathSteps.push(step);
|
|
578
|
-
if (step instanceof DynStep) {
|
|
579
|
-
step.interiorCids.add(cidNum);
|
|
580
|
-
pendingDyns.push(step);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
634
|
+
if (pushPart) {
|
|
635
|
+
const part = resolvePathPart(comp, nodeRefs, vid);
|
|
636
|
+
if (part) parts.push(part);
|
|
583
637
|
}
|
|
584
|
-
for (let i = pendingDyns.length - 1; i >= 0; i--)
|
|
585
|
-
if (pendingDyns[i].producerCompId === cidNum) pendingDyns.splice(i, 1);
|
|
586
638
|
eventIds = [];
|
|
587
|
-
|
|
639
|
+
nodeRefs = [];
|
|
588
640
|
return true;
|
|
589
641
|
};
|
|
590
642
|
while (node && node !== rootNode && depth < maxDepth) {
|
|
591
643
|
if (node?.dataset) {
|
|
592
|
-
const { eid, cid, vid } = node.dataset;
|
|
644
|
+
const { eid, cid, vid, rp } = node.dataset;
|
|
593
645
|
if (eid !== void 0) eventIds.push(eid);
|
|
594
646
|
const metas = metaChain(node.previousSibling);
|
|
595
647
|
let sawComp = false;
|
|
@@ -597,21 +649,47 @@ var Path = class _Path {
|
|
|
597
649
|
if (m.$ === "Comp") {
|
|
598
650
|
sawComp = true;
|
|
599
651
|
if (!crossComponent(m.cid, m.vid)) return NO_EVENT_INFO;
|
|
600
|
-
|
|
652
|
+
nodeRefs.push({ nid: m.nid, base: pathFromJson(m.base) });
|
|
601
653
|
} else {
|
|
602
|
-
|
|
654
|
+
nodeRefs.push({ nid: m.nid, si: m.si, sk: m.sk });
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
if (!sawComp && cid !== void 0) {
|
|
658
|
+
if (!crossComponent(+cid, vid)) return NO_EVENT_INFO;
|
|
659
|
+
if (rp !== void 0) {
|
|
660
|
+
const base = parseRenderPath(rp);
|
|
661
|
+
if (base !== null) nodeRefs.push({ base });
|
|
603
662
|
}
|
|
604
663
|
}
|
|
605
|
-
if (!sawComp && cid !== void 0 && !crossComponent(+cid, vid)) return NO_EVENT_INFO;
|
|
606
664
|
}
|
|
607
665
|
depth += 1;
|
|
608
666
|
node = node.parentNode;
|
|
609
667
|
}
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
668
|
+
parts.reverse();
|
|
669
|
+
let path2 = new _DispatchPath();
|
|
670
|
+
for (const part of parts)
|
|
671
|
+
path2 = part.base !== void 0 ? path2.pushFrame(part.base) : path2.pushItem(part.step);
|
|
672
|
+
return [path2, handlers];
|
|
613
673
|
}
|
|
614
674
|
};
|
|
675
|
+
function keyedPath(path2, key) {
|
|
676
|
+
const steps = path2.steps;
|
|
677
|
+
const last = steps[steps.length - 1];
|
|
678
|
+
if (last instanceof SeqStep || last instanceof FieldStep)
|
|
679
|
+
return new Path(steps.slice(0, -1).concat(new SeqStep(last.field, key)));
|
|
680
|
+
return null;
|
|
681
|
+
}
|
|
682
|
+
function renderPathText(path2) {
|
|
683
|
+
return JSON.stringify(pathToJson(path2));
|
|
684
|
+
}
|
|
685
|
+
function parseRenderPath(text) {
|
|
686
|
+
try {
|
|
687
|
+
return pathFromJson(JSON.parse(text));
|
|
688
|
+
} catch (err) {
|
|
689
|
+
console.warn("bad render path", err, text);
|
|
690
|
+
return null;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
615
693
|
function metaChain(n) {
|
|
616
694
|
const out = [];
|
|
617
695
|
while (n?.nodeType === 8 && n.textContent[0] === "§") {
|
|
@@ -664,20 +742,27 @@ var StepCtx = class _StepCtx {
|
|
|
664
742
|
return pi;
|
|
665
743
|
}
|
|
666
744
|
};
|
|
667
|
-
function
|
|
668
|
-
for (let i = 0; i <
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
if (
|
|
745
|
+
function resolvePathPart(comp, nodeRefs, vid) {
|
|
746
|
+
for (let i = 0; i < nodeRefs.length; i++) {
|
|
747
|
+
const ref = nodeRefs[i];
|
|
748
|
+
if (ref.base != null) return { base: ref.base };
|
|
749
|
+
if (ref.nid === void 0 || ref.nid === null) continue;
|
|
750
|
+
const ctx = new StepCtx(comp, nodeRefs, i, vid);
|
|
751
|
+
const step = ctx.resolveNode()?.toPathStep(ctx) ?? null;
|
|
752
|
+
if (step !== null) return { step };
|
|
672
753
|
}
|
|
673
754
|
return null;
|
|
674
755
|
}
|
|
675
756
|
var NO_EVENT_INFO = [null, null];
|
|
676
757
|
var BUBBLING_EVENTS = /* @__PURE__ */ new Set(["drop"]);
|
|
758
|
+
var path = () => new PathBuilder();
|
|
677
759
|
var PathBuilder = class {
|
|
678
760
|
constructor() {
|
|
679
761
|
this.pathChanges = [];
|
|
680
762
|
}
|
|
763
|
+
toPath() {
|
|
764
|
+
return new Path(this.pathChanges);
|
|
765
|
+
}
|
|
681
766
|
add(pathChange) {
|
|
682
767
|
this.pathChanges.push(pathChange);
|
|
683
768
|
return this;
|
|
@@ -814,31 +899,14 @@ function parseBool(s, px) {
|
|
|
814
899
|
const val = parseToken(tokens[0], px);
|
|
815
900
|
return val !== null && kindOf(val) & G_BOOL ? val : null;
|
|
816
901
|
}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
}
|
|
826
|
-
function parseField(s, px) {
|
|
827
|
-
return _parseSingle(s, px, G_FIELD);
|
|
828
|
-
}
|
|
829
|
-
function parseProvide(s, px) {
|
|
830
|
-
return _parseSingle(s, px, G_PROVIDE);
|
|
831
|
-
}
|
|
832
|
-
function parseMacroAttr(s, px) {
|
|
833
|
-
return _parseSingle(s, px, G_ALL);
|
|
834
|
-
}
|
|
835
|
-
function parseReceiveHandler(s, px) {
|
|
836
|
-
return _parseHandler(s, px, "receive", true, true, false);
|
|
837
|
-
}
|
|
838
|
-
function parseAlterHandler(s, px) {
|
|
839
|
-
const r = _parseHandler(s, px, "alter", false, false, true);
|
|
840
|
-
return r === null ? null : r.handlerVal;
|
|
841
|
-
}
|
|
902
|
+
var parseText = (s, px) => _parseSingle(s, px, G_TEXT);
|
|
903
|
+
var parseComponent = (s, px) => _parseSingle(s, px, G_COMPONENT);
|
|
904
|
+
var parseSequence = (s, px) => _parseSingle(s, px, G_SEQUENCE);
|
|
905
|
+
var parseField = (s, px) => _parseSingle(s, px, G_FIELD);
|
|
906
|
+
var parseProvide = (s, px) => _parseSingle(s, px, G_PROVIDE);
|
|
907
|
+
var parseMacroAttr = (s, px) => _parseSingle(s, px, G_ALL);
|
|
908
|
+
var parseReceiveHandler = (s, px) => _parseHandler(s, px, "receive", true, true, false);
|
|
909
|
+
var parseAlterHandler = (s, px) => _parseHandler(s, px, "alter", false, false, true)?.handlerVal ?? null;
|
|
842
910
|
function _parseHandler(s, px, namespace, allowArgs, report, allowMethod) {
|
|
843
911
|
const tokens = tokenizeValue(s.trim());
|
|
844
912
|
const headTok = tokens[0] ?? "";
|
|
@@ -1527,19 +1595,9 @@ function childOpts(vnode, ns, opts) {
|
|
|
1527
1595
|
const target = ns === SVG_NS && isForeignObject(vnode.tag) ? null : ns;
|
|
1528
1596
|
return target === (opts.namespace ?? null) ? opts : { ...opts, namespace: target };
|
|
1529
1597
|
}
|
|
1530
|
-
var NEVER_ASSIGN =
|
|
1531
|
-
"width"
|
|
1532
|
-
|
|
1533
|
-
"href",
|
|
1534
|
-
"list",
|
|
1535
|
-
"form",
|
|
1536
|
-
"tabIndex",
|
|
1537
|
-
"download",
|
|
1538
|
-
"rowSpan",
|
|
1539
|
-
"colSpan",
|
|
1540
|
-
"role",
|
|
1541
|
-
"popover"
|
|
1542
|
-
]);
|
|
1598
|
+
var NEVER_ASSIGN = new Set(
|
|
1599
|
+
"width height href list form tabIndex download rowSpan colSpan role popover".split(" ")
|
|
1600
|
+
);
|
|
1543
1601
|
var PROP_ATTR_NAME = { className: "class", htmlFor: "for" };
|
|
1544
1602
|
function applyProperties(node, props) {
|
|
1545
1603
|
const namespaced = isNamespaced(node);
|
|
@@ -1818,6 +1876,10 @@ function morphChildren(parentDom, oldChilds, newChilds, opts) {
|
|
|
1818
1876
|
if (!used[i] && domNodes[i].parentNode === parentDom) parentDom.removeChild(domNodes[i]);
|
|
1819
1877
|
}
|
|
1820
1878
|
function render(vnode, container, options, prev) {
|
|
1879
|
+
if (vnode == null) {
|
|
1880
|
+
container.replaceChildren();
|
|
1881
|
+
return { vnode: null, dom: null };
|
|
1882
|
+
}
|
|
1821
1883
|
const isFragment = vnode instanceof VFragment;
|
|
1822
1884
|
if (prev && prev.vnode instanceof VFragment === isFragment) {
|
|
1823
1885
|
const oldDom = isFragment ? container : prev.dom;
|
|
@@ -1857,13 +1919,16 @@ function h(tagName, properties, children, namespace) {
|
|
|
1857
1919
|
}
|
|
1858
1920
|
|
|
1859
1921
|
// src/anode.js
|
|
1860
|
-
function
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1922
|
+
function renderTarget(val, stack) {
|
|
1923
|
+
if (val instanceof DynVal) {
|
|
1924
|
+
const loc = stack.lookupDynamicLocated(val.name);
|
|
1925
|
+
if (loc?.path == null) return [loc?.value ?? null, stack.renderPath, null];
|
|
1926
|
+
return [loc.value, stack.renderPath.pushFrame(loc.path), loc.path];
|
|
1927
|
+
}
|
|
1928
|
+
const step = val.toPathItem?.() ?? null;
|
|
1929
|
+
if (step === null) return [val.eval(stack), stack.renderPath, null];
|
|
1930
|
+
const path2 = stack.renderPath.pushItem(step);
|
|
1931
|
+
return [val.eval(stack), path2, stack.pendingFrame ? path2.toTransactionPath() : null];
|
|
1867
1932
|
}
|
|
1868
1933
|
var BaseNode = class {
|
|
1869
1934
|
render(_stack, _rx) {
|
|
@@ -2185,33 +2250,31 @@ var RenderViewId = class extends ANode {
|
|
|
2185
2250
|
setDataAttr(_key, _val) {
|
|
2186
2251
|
}
|
|
2187
2252
|
};
|
|
2188
|
-
function dynRenderStep(comp, name, key) {
|
|
2189
|
-
const p = resolveDynProducer(comp, name);
|
|
2190
|
-
if (!p) return null;
|
|
2191
|
-
return key === void 0 ? new DynStep(p.producerCompId, p.producerSteps) : new DynEachStep(p.producerCompId, p.producerSteps, key);
|
|
2192
|
-
}
|
|
2193
2253
|
var RenderNode = class extends RenderViewId {
|
|
2194
2254
|
render(stack, rx) {
|
|
2195
|
-
const
|
|
2196
|
-
|
|
2255
|
+
const [value, renderPath, base] = renderTarget(this.val, stack);
|
|
2256
|
+
const newStack = stack.enter(value, {}, true, renderPath, false);
|
|
2257
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
|
|
2197
2258
|
}
|
|
2259
|
+
// A `*name` target contributes no step: the site recorded the absolute base it
|
|
2260
|
+
// resumed at, and event reconstruction turns that into a continuation frame.
|
|
2198
2261
|
toPathStep(ctx) {
|
|
2199
|
-
if (this.val instanceof DynVal) return
|
|
2262
|
+
if (this.val instanceof DynVal) return null;
|
|
2200
2263
|
return super.toPathStep(ctx);
|
|
2201
2264
|
}
|
|
2202
2265
|
};
|
|
2203
2266
|
var RenderItNode = class extends RenderViewId {
|
|
2204
2267
|
render(stack, rx) {
|
|
2205
|
-
const
|
|
2206
|
-
|
|
2268
|
+
const base = stack.pendingFrame ? stack.renderPath.toTransactionPath() : null;
|
|
2269
|
+
const newStack = stack.enter(stack.it, {}, true, stack.renderPath, false);
|
|
2270
|
+
return rx.renderIt(newStack, this, "", this.evalViewName(stack), base);
|
|
2207
2271
|
}
|
|
2208
2272
|
toPathStep(ctx) {
|
|
2209
2273
|
const next = ctx.next();
|
|
2210
2274
|
if (next === null) return null;
|
|
2211
2275
|
const nextNode = next.resolveNode();
|
|
2212
2276
|
if (nextNode instanceof EachNode && next.hasKey) {
|
|
2213
|
-
if (nextNode.val instanceof DynVal)
|
|
2214
|
-
return dynRenderStep(ctx.comp, nextNode.val.name, next.key);
|
|
2277
|
+
if (nextNode.val instanceof DynVal) return null;
|
|
2215
2278
|
return new EachRenderItStep(nextNode.val.name, next.key);
|
|
2216
2279
|
}
|
|
2217
2280
|
return null;
|
|
@@ -2313,11 +2376,19 @@ var EachNode = class extends WrapperNode {
|
|
|
2313
2376
|
this.iterInfo = new IterInfo(val, null, null, null);
|
|
2314
2377
|
}
|
|
2315
2378
|
render(stack, rx) {
|
|
2316
|
-
return rx.renderEachWhen(stack, this
|
|
2379
|
+
return rx.renderEachWhen(stack, this);
|
|
2317
2380
|
}
|
|
2318
2381
|
toPathStep(ctx) {
|
|
2319
2382
|
return ctx.hasKey ? new EachBindStep(this.iterInfo, ctx.key) : null;
|
|
2320
2383
|
}
|
|
2384
|
+
// Where one item lives, for the render path. `@each` re-binds `it` to the item
|
|
2385
|
+
// whether or not the body is a component, so the position moves either way and
|
|
2386
|
+
// the step has to address it — `.rows` iterated at `key` IS `rows[key]`.
|
|
2387
|
+
// Null for a dynamic sequence: `*rows` carries its own absolute path and enters
|
|
2388
|
+
// a continuation frame instead (see Renderer.renderEachWhen).
|
|
2389
|
+
itemStep(key) {
|
|
2390
|
+
return this.val instanceof FieldVal ? new SeqStep(this.val.name, key) : null;
|
|
2391
|
+
}
|
|
2321
2392
|
static register = true;
|
|
2322
2393
|
};
|
|
2323
2394
|
var IterInfo = class {
|
|
@@ -2656,6 +2727,215 @@ function collectAppClassesInSet(app) {
|
|
|
2656
2727
|
return classes;
|
|
2657
2728
|
}
|
|
2658
2729
|
|
|
2730
|
+
// src/stack.js
|
|
2731
|
+
var STOP = /* @__PURE__ */ Symbol("STOP");
|
|
2732
|
+
var NEXT = /* @__PURE__ */ Symbol("NEXT");
|
|
2733
|
+
var DEFAULT_ROUTE = ["dyn", "lex"];
|
|
2734
|
+
function routeLookup(route, lex, dyn) {
|
|
2735
|
+
for (let i = 0; i < route.length; i++) {
|
|
2736
|
+
const leg = route[i];
|
|
2737
|
+
if (leg === "dyn") {
|
|
2738
|
+
const v = dyn();
|
|
2739
|
+
if (v != null) return v;
|
|
2740
|
+
} else if (leg === "lex") {
|
|
2741
|
+
const v = lex();
|
|
2742
|
+
if (v != null) return v;
|
|
2743
|
+
} else {
|
|
2744
|
+
console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
|
|
2745
|
+
}
|
|
2746
|
+
}
|
|
2747
|
+
return null;
|
|
2748
|
+
}
|
|
2749
|
+
var isTypeName = (s) => {
|
|
2750
|
+
const c = s.charCodeAt(0);
|
|
2751
|
+
return c >= 65 && c <= 90;
|
|
2752
|
+
};
|
|
2753
|
+
function lookup(chain, name, dv = null) {
|
|
2754
|
+
let n = chain;
|
|
2755
|
+
while (n !== null) {
|
|
2756
|
+
const r = n[0].lookup(name);
|
|
2757
|
+
if (r === STOP) return dv;
|
|
2758
|
+
if (r !== NEXT) return r;
|
|
2759
|
+
n = n[1];
|
|
2760
|
+
}
|
|
2761
|
+
return dv;
|
|
2762
|
+
}
|
|
2763
|
+
var BindFrame = class {
|
|
2764
|
+
constructor(it, binds, isFrame) {
|
|
2765
|
+
this.it = it;
|
|
2766
|
+
this.binds = binds;
|
|
2767
|
+
this.isFrame = isFrame;
|
|
2768
|
+
}
|
|
2769
|
+
lookup(name) {
|
|
2770
|
+
const v = this.binds[name];
|
|
2771
|
+
return v === void 0 ? this.isFrame ? STOP : NEXT : v;
|
|
2772
|
+
}
|
|
2773
|
+
};
|
|
2774
|
+
var DynFrame = class {
|
|
2775
|
+
constructor(binds, types) {
|
|
2776
|
+
this.binds = binds;
|
|
2777
|
+
this.types = types;
|
|
2778
|
+
}
|
|
2779
|
+
lookup(name) {
|
|
2780
|
+
const v = (isTypeName(name) ? this.types : this.binds)[name];
|
|
2781
|
+
return v === void 0 ? NEXT : v;
|
|
2782
|
+
}
|
|
2783
|
+
};
|
|
2784
|
+
function computeViewsId(views) {
|
|
2785
|
+
let s = "";
|
|
2786
|
+
let n = views;
|
|
2787
|
+
while (n !== null) {
|
|
2788
|
+
s += n[0];
|
|
2789
|
+
n = n[1];
|
|
2790
|
+
}
|
|
2791
|
+
return s === "main" ? "" : s;
|
|
2792
|
+
}
|
|
2793
|
+
var Stack = class _Stack {
|
|
2794
|
+
constructor(fields) {
|
|
2795
|
+
Object.assign(this, fields);
|
|
2796
|
+
}
|
|
2797
|
+
_with(patch) {
|
|
2798
|
+
return new _Stack({ ...this, ...patch });
|
|
2799
|
+
}
|
|
2800
|
+
// Evaluate every provide the entered component publishes and push them as one
|
|
2801
|
+
// dynBinds frame, keyed by NAME. A value is published together with the absolute
|
|
2802
|
+
// path it lives at: the same declaration is read as `*name` AND resumed at by
|
|
2803
|
+
// `<x render="*name">`, so a consumer needs both halves. Types go in the same
|
|
2804
|
+
// frame's other map. No-op with no provides.
|
|
2805
|
+
_pushProvides() {
|
|
2806
|
+
const comp = this.comps.getCompFor(this.it);
|
|
2807
|
+
if (comp == null) return this;
|
|
2808
|
+
const { provide, provideType } = comp;
|
|
2809
|
+
const binds = {};
|
|
2810
|
+
const types = {};
|
|
2811
|
+
let has = false;
|
|
2812
|
+
const base = this._publishBase();
|
|
2813
|
+
for (const k in provide) {
|
|
2814
|
+
const step = provide[k].val.toPathItem?.() ?? null;
|
|
2815
|
+
if (step === null) continue;
|
|
2816
|
+
const value = provide[k].val.eval(this);
|
|
2817
|
+
binds[k] = { value, path: base === null ? null : base.concat([step]) };
|
|
2818
|
+
has = true;
|
|
2819
|
+
}
|
|
2820
|
+
for (const k in provideType) {
|
|
2821
|
+
types[k] = provideType[k];
|
|
2822
|
+
has = true;
|
|
2823
|
+
}
|
|
2824
|
+
if (!has) return this;
|
|
2825
|
+
return this._with({ dynBinds: [new DynFrame(binds, types), this.dynBinds] });
|
|
2826
|
+
}
|
|
2827
|
+
// The absolute address of the component being entered, or null when this
|
|
2828
|
+
// position cannot be written down as one. Frame-only steps carry bindings and
|
|
2829
|
+
// address nothing, so they are compacted away first; what is left is checked
|
|
2830
|
+
// against the value actually being rendered, because a scope CAN move the
|
|
2831
|
+
// render position without contributing an addressing step (a plain `@each`
|
|
2832
|
+
// body re-binds `it` to the item while its rebuild step is an identity).
|
|
2833
|
+
//
|
|
2834
|
+
// A null base still publishes the VALUE — `*name` reads it fine — but there is
|
|
2835
|
+
// nowhere to resume, so `<x render="*name">` renders nothing rather than
|
|
2836
|
+
// editing whatever happens to live at the address we guessed.
|
|
2837
|
+
_publishBase() {
|
|
2838
|
+
const base = this.renderPath.toTransactionPath().compact();
|
|
2839
|
+
return base.lookup(this.root, NOT_FOUND) === this.it ? base : null;
|
|
2840
|
+
}
|
|
2841
|
+
static root(comps, it, ctx = null) {
|
|
2842
|
+
return new _Stack({
|
|
2843
|
+
comps,
|
|
2844
|
+
root: it,
|
|
2845
|
+
it,
|
|
2846
|
+
binds: [new BindFrame(it, {}, true), null],
|
|
2847
|
+
dynBinds: [new DynFrame({}, {}), null],
|
|
2848
|
+
views: ["main", null],
|
|
2849
|
+
viewsId: "",
|
|
2850
|
+
renderPath: new DispatchPath(),
|
|
2851
|
+
pendingFrame: false,
|
|
2852
|
+
ctx
|
|
2853
|
+
})._pushProvides();
|
|
2854
|
+
}
|
|
2855
|
+
// `renderPath` defaults to this stack's own: an ordinary scope does not move.
|
|
2856
|
+
// `pendingFrame` clears on a component frame (which emits the base) and is
|
|
2857
|
+
// inherited by transparent scopes, which have to carry it to the next boundary.
|
|
2858
|
+
enter(it, bindings = {}, isFrame = true, renderPath = this.renderPath, pendingFrame = null) {
|
|
2859
|
+
const stack = this._with({
|
|
2860
|
+
it,
|
|
2861
|
+
binds: [new BindFrame(it, bindings, isFrame), this.binds],
|
|
2862
|
+
renderPath,
|
|
2863
|
+
pendingFrame: pendingFrame ?? (isFrame ? false : this.pendingFrame)
|
|
2864
|
+
});
|
|
2865
|
+
return isFrame ? stack._pushProvides() : stack;
|
|
2866
|
+
}
|
|
2867
|
+
pushViewName(name) {
|
|
2868
|
+
const views = [name, this.views];
|
|
2869
|
+
return this._with({ views, viewsId: computeViewsId(views) });
|
|
2870
|
+
}
|
|
2871
|
+
// Published types are stable per scope and would only churn the render cache, so
|
|
2872
|
+
// the cache key covers values alone.
|
|
2873
|
+
_pushDynBindValuesToArray(arr, comp) {
|
|
2874
|
+
for (const k in comp.provide) arr.push(this.lookupDynamic(k));
|
|
2875
|
+
for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
|
|
2876
|
+
}
|
|
2877
|
+
// `*name`: the nearest binding above (including this component's own provides,
|
|
2878
|
+
// pushed on entering it), else a path registered in the component's lexical
|
|
2879
|
+
// scope, else this component's declared default, else null.
|
|
2880
|
+
//
|
|
2881
|
+
// One chain walk and no producer resolution: a lookup names what it WANTS, so the
|
|
2882
|
+
// frame it wants is keyed by that name. The default belongs to the CONSUMER's
|
|
2883
|
+
// declaration and is evaluated against the consumer's stack, which is why it is
|
|
2884
|
+
// consulted only after the whole chain has missed.
|
|
2885
|
+
lookupDynamicLocated(name) {
|
|
2886
|
+
if (isTypeName(name)) return null;
|
|
2887
|
+
const v = lookup(this.dynBinds, name);
|
|
2888
|
+
if (v != null) return v;
|
|
2889
|
+
const comp = this.comps.getCompFor(this.it);
|
|
2890
|
+
if (comp == null) return null;
|
|
2891
|
+
const path2 = comp.scope?.lookupPath?.(name) ?? null;
|
|
2892
|
+
if (path2 !== null) {
|
|
2893
|
+
const value2 = path2.lookup(this.root, NOT_FOUND);
|
|
2894
|
+
if (value2 !== NOT_FOUND) return { value: value2, path: path2 };
|
|
2895
|
+
}
|
|
2896
|
+
const dval = comp.lookup[name]?.val ?? null;
|
|
2897
|
+
if (dval === null) return null;
|
|
2898
|
+
const step = dval.toPathItem?.() ?? null;
|
|
2899
|
+
const value = dval.eval(this);
|
|
2900
|
+
return step === null ? { value, path: null } : { value, path: this.renderPath.toTransactionPath().concat([step]) };
|
|
2901
|
+
}
|
|
2902
|
+
lookupDynamic(name) {
|
|
2903
|
+
if (isTypeName(name)) return lookup(this.dynBinds, name);
|
|
2904
|
+
return this.lookupDynamicLocated(name)?.value ?? null;
|
|
2905
|
+
}
|
|
2906
|
+
lookupBind(name) {
|
|
2907
|
+
return lookup(this.binds, name);
|
|
2908
|
+
}
|
|
2909
|
+
lookupFieldRaw(name) {
|
|
2910
|
+
return this.it[name] ?? null;
|
|
2911
|
+
}
|
|
2912
|
+
lookupMethod(name) {
|
|
2913
|
+
const fn = this.it[name];
|
|
2914
|
+
return fn instanceof Function ? fn.call(this.it) : null;
|
|
2915
|
+
}
|
|
2916
|
+
// The dispatched DOM event / drag info, read only by EventMemberVal's
|
|
2917
|
+
// `e.<member>` handler args. Null outside a live event transaction.
|
|
2918
|
+
lookupEvent() {
|
|
2919
|
+
return this.ctx?.event ?? null;
|
|
2920
|
+
}
|
|
2921
|
+
lookupDragInfo() {
|
|
2922
|
+
return this.ctx?.dragInfo ?? null;
|
|
2923
|
+
}
|
|
2924
|
+
getHandlerFor(name, key) {
|
|
2925
|
+
return this.comps.getHandlerFor(this.it, name, key);
|
|
2926
|
+
}
|
|
2927
|
+
lookupBestView(views, defaultViewName) {
|
|
2928
|
+
let n = this.views;
|
|
2929
|
+
while (n !== null) {
|
|
2930
|
+
const view = views[n[0]];
|
|
2931
|
+
if (view !== void 0) return view;
|
|
2932
|
+
n = n[1];
|
|
2933
|
+
}
|
|
2934
|
+
return views[defaultViewName];
|
|
2935
|
+
}
|
|
2936
|
+
};
|
|
2937
|
+
var NOT_FOUND = /* @__PURE__ */ Symbol("NOT_FOUND");
|
|
2938
|
+
|
|
2659
2939
|
// src/components.js
|
|
2660
2940
|
var COMPONENT = /* @__PURE__ */ Symbol.for("tutuca.component");
|
|
2661
2941
|
var Components = class {
|
|
@@ -2694,12 +2974,14 @@ var ComponentStack = class _ComponentStack {
|
|
|
2694
2974
|
this.byName = {};
|
|
2695
2975
|
this.intentsByName = {};
|
|
2696
2976
|
this.macros = {};
|
|
2977
|
+
this.paths = {};
|
|
2697
2978
|
}
|
|
2698
2979
|
enter() {
|
|
2699
2980
|
return new _ComponentStack(this.comps, this);
|
|
2700
2981
|
}
|
|
2701
2982
|
registerComponents(comps, opts) {
|
|
2702
|
-
const { aliases = {} } = opts ?? {};
|
|
2983
|
+
const { aliases = {}, paths } = opts ?? {};
|
|
2984
|
+
if (paths) this.registerPaths(paths);
|
|
2703
2985
|
for (let i = 0; i < comps.length; i++) {
|
|
2704
2986
|
const Comp = comps[i];
|
|
2705
2987
|
Comp[COMPONENT].scope = this.enter();
|
|
@@ -2713,6 +2995,27 @@ var ComponentStack = class _ComponentStack {
|
|
|
2713
2995
|
else console.warn("alias", alias, "to inexistent component", aliases[alias]);
|
|
2714
2996
|
}
|
|
2715
2997
|
}
|
|
2998
|
+
// Register lowercase names as absolute paths from the app state root. A
|
|
2999
|
+
// descendant that declares one in its `lookup` reads and renders `*name` without
|
|
3000
|
+
// anything above it publishing one — which is what makes a session, a theme or a
|
|
3001
|
+
// host-owned value available in its natural registration scope, instead of forcing
|
|
3002
|
+
// an application root whose only job is to `provide` it. Register on a nested
|
|
3003
|
+
// scope to narrow a name; nearest registration wins.
|
|
3004
|
+
//
|
|
3005
|
+
// Uppercase names are ignored: a component TYPE is what `lookupComponent` already
|
|
3006
|
+
// answers, and a type has no path.
|
|
3007
|
+
registerPaths(paths) {
|
|
3008
|
+
for (const name in paths) {
|
|
3009
|
+
if (isTypeName(name)) {
|
|
3010
|
+
console.warn("registerPaths: a type name has no path", name);
|
|
3011
|
+
continue;
|
|
3012
|
+
}
|
|
3013
|
+
this.paths[name] = paths[name].toPath?.() ?? paths[name];
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
lookupPath(name) {
|
|
3017
|
+
return this.paths[name] ?? this.parent?.lookupPath(name) ?? null;
|
|
3018
|
+
}
|
|
2716
3019
|
registerMacros(macros) {
|
|
2717
3020
|
for (const key in macros) {
|
|
2718
3021
|
const lower = key.toLowerCase();
|
|
@@ -2744,17 +3047,16 @@ var ComponentStack = class _ComponentStack {
|
|
|
2744
3047
|
lookupComponent(name) {
|
|
2745
3048
|
return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
|
|
2746
3049
|
}
|
|
2747
|
-
//
|
|
2748
|
-
// names
|
|
2749
|
-
//
|
|
2750
|
-
//
|
|
2751
|
-
//
|
|
2752
|
-
|
|
3050
|
+
// Whether anything in this scope chain provides `name`. Existence only: a lookup
|
|
3051
|
+
// names what it WANTS and takes whoever is nearest above it at render time, so
|
|
3052
|
+
// there is no producer to identify — several components may publish one name and
|
|
3053
|
+
// the live render ancestry decides. Used by the linter to tell a lookup that can
|
|
3054
|
+
// be satisfied from one that never will be.
|
|
3055
|
+
hasProvider(name) {
|
|
2753
3056
|
for (const compName in this.byName) {
|
|
2754
|
-
|
|
2755
|
-
if (Comp.provide?.[name] !== void 0) return Comp;
|
|
3057
|
+
if (this.byName[compName].provide?.[name] !== void 0) return true;
|
|
2756
3058
|
}
|
|
2757
|
-
return this.parent?.
|
|
3059
|
+
return this.parent?.hasProvider(name) ?? false;
|
|
2758
3060
|
}
|
|
2759
3061
|
lookupMacro(name) {
|
|
2760
3062
|
return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
|
|
@@ -2771,10 +3073,6 @@ var LookupInfo = class {
|
|
|
2771
3073
|
}
|
|
2772
3074
|
};
|
|
2773
3075
|
var isString = (v) => typeof v === "string";
|
|
2774
|
-
var isTypeName = (s) => {
|
|
2775
|
-
const c = s.charCodeAt(0);
|
|
2776
|
-
return c >= 65 && c <= 90;
|
|
2777
|
-
};
|
|
2778
3076
|
var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
|
|
2779
3077
|
var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
|
|
2780
3078
|
var _compId = 0;
|
|
@@ -5138,7 +5436,6 @@ var DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED";
|
|
|
5138
5436
|
var DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED";
|
|
5139
5437
|
var PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE";
|
|
5140
5438
|
var PROVIDE_TYPE_BAD_SHAPE = "PROVIDE_TYPE_BAD_SHAPE";
|
|
5141
|
-
var PROVIDE_NAME_COLLISION = "PROVIDE_NAME_COLLISION";
|
|
5142
5439
|
var LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE";
|
|
5143
5440
|
var LOOKUP_NO_PROVIDER = "LOOKUP_NO_PROVIDER";
|
|
5144
5441
|
var RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP";
|
|
@@ -5261,7 +5558,6 @@ function checkComponent(Comp, lx = new LintContext(), { wellKnownExtras = EMPTY_
|
|
|
5261
5558
|
checkFieldMethodNameCollisions(lx, Comp);
|
|
5262
5559
|
checkProvidesAreAddressable(lx, Comp);
|
|
5263
5560
|
checkProvidedTypes(lx, Comp);
|
|
5264
|
-
checkProvideNameCollisions(lx, Comp);
|
|
5265
5561
|
checkLookupShapes(lx, Comp);
|
|
5266
5562
|
checkLookupTypesResolve(lx, Comp);
|
|
5267
5563
|
checkLookupsHaveProviders(lx, Comp);
|
|
@@ -5945,19 +6241,6 @@ function checkProvidedTypes(lx, Comp) {
|
|
|
5945
6241
|
if (raw !== "self") lx.error(PROVIDE_TYPE_BAD_SHAPE, { name, value: raw });
|
|
5946
6242
|
}
|
|
5947
6243
|
}
|
|
5948
|
-
function checkProvideNameCollisions(lx, Comp) {
|
|
5949
|
-
const scope = Comp.scope;
|
|
5950
|
-
if (!scope) return;
|
|
5951
|
-
for (const name in Comp.provide) {
|
|
5952
|
-
for (let s = scope; s; s = s.parent) {
|
|
5953
|
-
for (const otherName in s.byName) {
|
|
5954
|
-
const Other = s.byName[otherName];
|
|
5955
|
-
if (Other !== Comp && Other.provide?.[name] !== void 0)
|
|
5956
|
-
lx.error(PROVIDE_NAME_COLLISION, { name, other: Other.name });
|
|
5957
|
-
}
|
|
5958
|
-
}
|
|
5959
|
-
}
|
|
5960
|
-
}
|
|
5961
6244
|
var KNOWN_LOOKUP_KEYS = /* @__PURE__ */ new Set(["name", "default"]);
|
|
5962
6245
|
function checkLookupShapes(lx, Comp) {
|
|
5963
6246
|
const raw = Comp._rawLookup;
|
|
@@ -5999,7 +6282,7 @@ function checkLookupsHaveProviders(lx, Comp) {
|
|
|
5999
6282
|
if (!scope) return;
|
|
6000
6283
|
for (const name in Comp.lookup) {
|
|
6001
6284
|
if (isTypeName2(name)) continue;
|
|
6002
|
-
if (scope.
|
|
6285
|
+
if (scope.hasProvider?.(name) || scope.lookupPath?.(name)) continue;
|
|
6003
6286
|
const info = { name, hasDefault: Comp.lookup[name].val != null };
|
|
6004
6287
|
if (info.hasDefault) lx.hint(LOOKUP_NO_PROVIDER, info);
|
|
6005
6288
|
else lx.error(LOOKUP_NO_PROVIDER, info);
|
|
@@ -6121,9 +6404,22 @@ var CHECK_TYPE_LIST = Array.isArray;
|
|
|
6121
6404
|
var CHECK_TYPE_OBJECT = isPlainObject;
|
|
6122
6405
|
var CHECK_TYPE_MAP = (v) => v instanceof Map;
|
|
6123
6406
|
var CHECK_TYPE_SET = (v) => v instanceof Set;
|
|
6407
|
+
var COERCE_NONE = (_v) => null;
|
|
6408
|
+
var COERCE_BOOL = (v) => !!v;
|
|
6409
|
+
var COERCE_STRING = (v) => v?.toString?.() ?? "";
|
|
6410
|
+
var COERCE_INT = (v) => Number.isFinite(v) ? Math.trunc(v) : null;
|
|
6411
|
+
var COERCE_LIST = (v) => Array.isArray(v) ? [...v] : null;
|
|
6412
|
+
var COERCE_OBJECT = (v) => isPlainObject(v) ? { ...v } : null;
|
|
6413
|
+
var COERCE_MAP = (v) => {
|
|
6414
|
+
if (v instanceof Map) return new Map(v);
|
|
6415
|
+
if (Array.isArray(v) || isPlainObject(v))
|
|
6416
|
+
return new Map(Array.isArray(v) ? v : Object.entries(v));
|
|
6417
|
+
return null;
|
|
6418
|
+
};
|
|
6419
|
+
var COERCE_SET = (v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null;
|
|
6124
6420
|
var FieldBool = class extends Field {
|
|
6125
6421
|
constructor(name, defaultValue = false) {
|
|
6126
|
-
super("bool", name, CHECK_TYPE_BOOL,
|
|
6422
|
+
super("bool", name, CHECK_TYPE_BOOL, COERCE_BOOL, defaultValue);
|
|
6127
6423
|
}
|
|
6128
6424
|
};
|
|
6129
6425
|
var FieldAny = class extends Field {
|
|
@@ -6133,23 +6429,17 @@ var FieldAny = class extends Field {
|
|
|
6133
6429
|
};
|
|
6134
6430
|
var FieldString = class extends Field {
|
|
6135
6431
|
constructor(name, defaultValue = "") {
|
|
6136
|
-
super("text", name, CHECK_TYPE_STRING,
|
|
6432
|
+
super("text", name, CHECK_TYPE_STRING, COERCE_STRING, defaultValue);
|
|
6137
6433
|
}
|
|
6138
6434
|
};
|
|
6139
6435
|
var FieldInt = class extends Field {
|
|
6140
6436
|
constructor(name, defaultValue = 0) {
|
|
6141
|
-
super(
|
|
6142
|
-
"int",
|
|
6143
|
-
name,
|
|
6144
|
-
CHECK_TYPE_INT,
|
|
6145
|
-
(v) => Number.isFinite(v) ? Math.trunc(v) : null,
|
|
6146
|
-
defaultValue
|
|
6147
|
-
);
|
|
6437
|
+
super("int", name, CHECK_TYPE_INT, COERCE_INT, defaultValue);
|
|
6148
6438
|
}
|
|
6149
6439
|
};
|
|
6150
6440
|
var FieldFloat = class extends Field {
|
|
6151
6441
|
constructor(name, defaultValue = 0) {
|
|
6152
|
-
super("float", name, CHECK_TYPE_FLOAT,
|
|
6442
|
+
super("float", name, CHECK_TYPE_FLOAT, COERCE_NONE, defaultValue);
|
|
6153
6443
|
}
|
|
6154
6444
|
};
|
|
6155
6445
|
var metaOf = (v) => v?.constructor?.[COMPONENT] ?? v?.constructor?.getMetaClass?.();
|
|
@@ -6162,45 +6452,22 @@ var FieldComp = class extends Field {
|
|
|
6162
6452
|
};
|
|
6163
6453
|
var FieldList = class extends Field {
|
|
6164
6454
|
constructor(name, defaultValue = []) {
|
|
6165
|
-
super("list", name, CHECK_TYPE_LIST,
|
|
6455
|
+
super("list", name, CHECK_TYPE_LIST, COERCE_LIST, defaultValue);
|
|
6166
6456
|
}
|
|
6167
6457
|
};
|
|
6168
6458
|
var FieldObject = class extends Field {
|
|
6169
6459
|
constructor(name, defaultValue = {}) {
|
|
6170
|
-
super(
|
|
6171
|
-
"object",
|
|
6172
|
-
name,
|
|
6173
|
-
CHECK_TYPE_OBJECT,
|
|
6174
|
-
(v) => isPlainObject(v) ? { ...v } : null,
|
|
6175
|
-
defaultValue
|
|
6176
|
-
);
|
|
6460
|
+
super("object", name, CHECK_TYPE_OBJECT, COERCE_OBJECT, defaultValue);
|
|
6177
6461
|
}
|
|
6178
6462
|
};
|
|
6179
6463
|
var FieldMap = class extends Field {
|
|
6180
6464
|
constructor(name, defaultValue = /* @__PURE__ */ new Map()) {
|
|
6181
|
-
super(
|
|
6182
|
-
"map",
|
|
6183
|
-
name,
|
|
6184
|
-
CHECK_TYPE_MAP,
|
|
6185
|
-
(v) => {
|
|
6186
|
-
if (v instanceof Map) return new Map(v);
|
|
6187
|
-
if (Array.isArray(v) || isPlainObject(v))
|
|
6188
|
-
return new Map(Array.isArray(v) ? v : Object.entries(v));
|
|
6189
|
-
return null;
|
|
6190
|
-
},
|
|
6191
|
-
defaultValue
|
|
6192
|
-
);
|
|
6465
|
+
super("map", name, CHECK_TYPE_MAP, COERCE_MAP, defaultValue);
|
|
6193
6466
|
}
|
|
6194
6467
|
};
|
|
6195
6468
|
var FieldSet = class extends Field {
|
|
6196
6469
|
constructor(name, defaultValue = /* @__PURE__ */ new Set()) {
|
|
6197
|
-
super(
|
|
6198
|
-
"set",
|
|
6199
|
-
name,
|
|
6200
|
-
CHECK_TYPE_SET,
|
|
6201
|
-
(v) => v instanceof Set || Array.isArray(v) ? new Set(v) : null,
|
|
6202
|
-
defaultValue
|
|
6203
|
-
);
|
|
6470
|
+
super("set", name, CHECK_TYPE_SET, COERCE_SET, defaultValue);
|
|
6204
6471
|
}
|
|
6205
6472
|
};
|
|
6206
6473
|
function mkCompField(field, scope, args) {
|
|
@@ -6298,8 +6565,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
|
|
|
6298
6565
|
const value = fields[field];
|
|
6299
6566
|
const type = typeof value;
|
|
6300
6567
|
if (type === "string") b.addField(field, value, FieldString);
|
|
6301
|
-
else if (type === "number")
|
|
6302
|
-
b.addField(field, value, Number.isInteger(value) ? FieldInt : FieldFloat);
|
|
6568
|
+
else if (type === "number") b.addField(field, value, FieldFloat);
|
|
6303
6569
|
else if (type === "boolean") b.addField(field, value, FieldBool);
|
|
6304
6570
|
else if (Array.isArray(value)) b.addField(field, [...value], FieldList);
|
|
6305
6571
|
else if (value instanceof Set) b.addField(field, new Set(value), FieldSet);
|
|
@@ -6376,160 +6642,6 @@ Component.fromSpec = (opts) => {
|
|
|
6376
6642
|
};
|
|
6377
6643
|
var component = (opts) => Component.fromSpec(opts);
|
|
6378
6644
|
|
|
6379
|
-
// src/stack.js
|
|
6380
|
-
var STOP = /* @__PURE__ */ Symbol("STOP");
|
|
6381
|
-
var NEXT = /* @__PURE__ */ Symbol("NEXT");
|
|
6382
|
-
var DEFAULT_ROUTE = ["dyn", "lex"];
|
|
6383
|
-
function routeLookup(route, lex, dyn) {
|
|
6384
|
-
for (let i = 0; i < route.length; i++) {
|
|
6385
|
-
const leg = route[i];
|
|
6386
|
-
if (leg === "dyn") {
|
|
6387
|
-
const v = dyn();
|
|
6388
|
-
if (v != null) return v;
|
|
6389
|
-
} else if (leg === "lex") {
|
|
6390
|
-
const v = lex();
|
|
6391
|
-
if (v != null) return v;
|
|
6392
|
-
} else {
|
|
6393
|
-
console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
|
|
6394
|
-
}
|
|
6395
|
-
}
|
|
6396
|
-
return null;
|
|
6397
|
-
}
|
|
6398
|
-
function lookup(chain, name, dv = null) {
|
|
6399
|
-
let n = chain;
|
|
6400
|
-
while (n !== null) {
|
|
6401
|
-
const r = n[0].lookup(name);
|
|
6402
|
-
if (r === STOP) return dv;
|
|
6403
|
-
if (r !== NEXT) return r;
|
|
6404
|
-
n = n[1];
|
|
6405
|
-
}
|
|
6406
|
-
return dv;
|
|
6407
|
-
}
|
|
6408
|
-
var BindFrame = class {
|
|
6409
|
-
constructor(it, binds, isFrame) {
|
|
6410
|
-
this.it = it;
|
|
6411
|
-
this.binds = binds;
|
|
6412
|
-
this.isFrame = isFrame;
|
|
6413
|
-
}
|
|
6414
|
-
lookup(name) {
|
|
6415
|
-
const v = this.binds[name];
|
|
6416
|
-
return v === void 0 ? this.isFrame ? STOP : NEXT : v;
|
|
6417
|
-
}
|
|
6418
|
-
};
|
|
6419
|
-
var ObjectFrame = class {
|
|
6420
|
-
constructor(binds) {
|
|
6421
|
-
this.binds = binds;
|
|
6422
|
-
}
|
|
6423
|
-
lookup(key) {
|
|
6424
|
-
const v = this.binds[key];
|
|
6425
|
-
return v === void 0 ? NEXT : v;
|
|
6426
|
-
}
|
|
6427
|
-
};
|
|
6428
|
-
function computeViewsId(views) {
|
|
6429
|
-
let s = "";
|
|
6430
|
-
let n = views;
|
|
6431
|
-
while (n !== null) {
|
|
6432
|
-
s += n[0];
|
|
6433
|
-
n = n[1];
|
|
6434
|
-
}
|
|
6435
|
-
return s === "main" ? "" : s;
|
|
6436
|
-
}
|
|
6437
|
-
var Stack = class _Stack {
|
|
6438
|
-
constructor(comps, it, binds, dynBinds, views, viewsId, ctx = null) {
|
|
6439
|
-
this.comps = comps;
|
|
6440
|
-
this.it = it;
|
|
6441
|
-
this.binds = binds;
|
|
6442
|
-
this.dynBinds = dynBinds;
|
|
6443
|
-
this.views = views;
|
|
6444
|
-
this.viewsId = viewsId;
|
|
6445
|
-
this.ctx = ctx;
|
|
6446
|
-
}
|
|
6447
|
-
// Evaluate every provide the entered component publishes and push them as one
|
|
6448
|
-
// dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
|
|
6449
|
-
// starts A-Z and a value name does not, so the two namespaces cannot collide and
|
|
6450
|
-
// nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
|
|
6451
|
-
_pushProvides() {
|
|
6452
|
-
const comp = this.comps.getCompFor(this.it);
|
|
6453
|
-
if (comp == null) return this;
|
|
6454
|
-
const { provide, provideType } = comp;
|
|
6455
|
-
const dynObj = {};
|
|
6456
|
-
let has = false;
|
|
6457
|
-
for (const k in provide) {
|
|
6458
|
-
dynObj[k] = provide[k].val.eval(this);
|
|
6459
|
-
has = true;
|
|
6460
|
-
}
|
|
6461
|
-
for (const k in provideType) {
|
|
6462
|
-
dynObj[k] = provideType[k];
|
|
6463
|
-
has = true;
|
|
6464
|
-
}
|
|
6465
|
-
if (!has) return this;
|
|
6466
|
-
const newDynBinds = [new ObjectFrame(dynObj), this.dynBinds];
|
|
6467
|
-
const { comps, it, binds, views, viewsId, ctx } = this;
|
|
6468
|
-
return new _Stack(comps, it, binds, newDynBinds, views, viewsId, ctx);
|
|
6469
|
-
}
|
|
6470
|
-
static root(comps, it, ctx) {
|
|
6471
|
-
const binds = [new BindFrame(it, {}, true), null];
|
|
6472
|
-
const dynBinds = [new ObjectFrame({}), null];
|
|
6473
|
-
const views = ["main", null];
|
|
6474
|
-
return new _Stack(comps, it, binds, dynBinds, views, "", ctx)._pushProvides();
|
|
6475
|
-
}
|
|
6476
|
-
enter(it, bindings = {}, isFrame = true) {
|
|
6477
|
-
const { comps, binds, dynBinds, views, viewsId, ctx } = this;
|
|
6478
|
-
const newBinds = [new BindFrame(it, bindings, isFrame), binds];
|
|
6479
|
-
const stack = new _Stack(comps, it, newBinds, dynBinds, views, viewsId, ctx);
|
|
6480
|
-
return isFrame ? stack._pushProvides() : stack;
|
|
6481
|
-
}
|
|
6482
|
-
pushViewName(name) {
|
|
6483
|
-
const { comps, it, binds, dynBinds, views, ctx } = this;
|
|
6484
|
-
const newViews = [name, views];
|
|
6485
|
-
return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
|
|
6486
|
-
}
|
|
6487
|
-
// Published types are stable per scope and would only churn the render cache, so
|
|
6488
|
-
// the cache key covers values alone.
|
|
6489
|
-
_pushDynBindValuesToArray(arr, comp) {
|
|
6490
|
-
for (const k in comp.provide) arr.push(this.lookupDynamic(k));
|
|
6491
|
-
for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
|
|
6492
|
-
}
|
|
6493
|
-
// `*name`: the nearest binding above (including this component's own provides,
|
|
6494
|
-
// pushed on entering it), else this component's declared default, else null.
|
|
6495
|
-
lookupDynamic(name) {
|
|
6496
|
-
const v = lookup(this.dynBinds, name);
|
|
6497
|
-
if (v != null) return v;
|
|
6498
|
-
const comp = this.comps.getCompFor(this.it);
|
|
6499
|
-
return comp?.lookup[name]?.val?.eval(this) ?? null;
|
|
6500
|
-
}
|
|
6501
|
-
lookupBind(name) {
|
|
6502
|
-
return lookup(this.binds, name);
|
|
6503
|
-
}
|
|
6504
|
-
lookupFieldRaw(name) {
|
|
6505
|
-
return this.it[name] ?? null;
|
|
6506
|
-
}
|
|
6507
|
-
lookupMethod(name) {
|
|
6508
|
-
const fn = this.it[name];
|
|
6509
|
-
return fn instanceof Function ? fn.call(this.it) : null;
|
|
6510
|
-
}
|
|
6511
|
-
// The dispatched DOM event / drag info, read only by EventMemberVal's
|
|
6512
|
-
// `e.<member>` handler args. Null outside a live event transaction.
|
|
6513
|
-
lookupEvent() {
|
|
6514
|
-
return this.ctx?.event ?? null;
|
|
6515
|
-
}
|
|
6516
|
-
lookupDragInfo() {
|
|
6517
|
-
return this.ctx?.dragInfo ?? null;
|
|
6518
|
-
}
|
|
6519
|
-
getHandlerFor(name, key) {
|
|
6520
|
-
return this.comps.getHandlerFor(this.it, name, key);
|
|
6521
|
-
}
|
|
6522
|
-
lookupBestView(views, defaultViewName) {
|
|
6523
|
-
let n = this.views;
|
|
6524
|
-
while (n !== null) {
|
|
6525
|
-
const view = views[n[0]];
|
|
6526
|
-
if (view !== void 0) return view;
|
|
6527
|
-
n = n[1];
|
|
6528
|
-
}
|
|
6529
|
-
return views[defaultViewName];
|
|
6530
|
-
}
|
|
6531
|
-
};
|
|
6532
|
-
|
|
6533
6645
|
// src/transactor.js
|
|
6534
6646
|
var State2 = class {
|
|
6535
6647
|
constructor(val) {
|
|
@@ -6605,9 +6717,9 @@ var Transactor = class {
|
|
|
6605
6717
|
// `.a[.selId]` render target reconstructed from a DOM event) against the root the
|
|
6606
6718
|
// handler read, so pathKeys carries concrete keys instead of dropping the dynamic
|
|
6607
6719
|
// step. No-op when nobody is observing.
|
|
6608
|
-
_emitRecord(root, { kind, name, args, path, targetPath, handler, handlerName, matched, before, after, parent }) {
|
|
6720
|
+
_emitRecord(root, { kind, name, args, path: path2, targetPath, handler, handlerName, matched, before, after, parent }) {
|
|
6609
6721
|
if (this._observers.length === 0) return;
|
|
6610
|
-
const pinned =
|
|
6722
|
+
const pinned = path2.pinKeys(root);
|
|
6611
6723
|
this._emit({
|
|
6612
6724
|
kind,
|
|
6613
6725
|
name,
|
|
@@ -6658,18 +6770,20 @@ var Transactor = class {
|
|
|
6658
6770
|
// intent's answerPath is: a reply must reach the sender that asked even if a key
|
|
6659
6771
|
// moved while the message was in flight. Null when nobody is waiting — a host
|
|
6660
6772
|
// sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
|
|
6661
|
-
pushSend(
|
|
6662
|
-
const t = new SendEvent(
|
|
6663
|
-
t.
|
|
6773
|
+
pushSend(path2, name, args = [], parent = null, origin = null, txnPath = null) {
|
|
6774
|
+
const t = new SendEvent(path2, this, name, args, parent);
|
|
6775
|
+
t.txnPath = txnPath;
|
|
6776
|
+
t.origin = origin;
|
|
6777
|
+
t.originPinned = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
|
|
6664
6778
|
this.pushTransaction(t);
|
|
6665
6779
|
return this._link(t, parent);
|
|
6666
6780
|
}
|
|
6667
6781
|
// Raise an intent: a job the sender did not address, walked along a route until
|
|
6668
6782
|
// something answers. `opts.route` is a list of legs (see DEFAULT_ROUTE) and
|
|
6669
6783
|
// `opts.livePath` opts out of pinning the answer's destination keys.
|
|
6670
|
-
pushIntent(
|
|
6784
|
+
pushIntent(path2, name, args = [], opts = {}, parent = null) {
|
|
6671
6785
|
const release = parent ? parent.completion.track() : null;
|
|
6672
|
-
const walk = new IntentWalk(this,
|
|
6786
|
+
const walk = new IntentWalk(this, path2, name, args, opts, parent, release);
|
|
6673
6787
|
walk.advance();
|
|
6674
6788
|
return walk;
|
|
6675
6789
|
}
|
|
@@ -6703,16 +6817,17 @@ var Transactor = class {
|
|
|
6703
6817
|
transaction._completion?.releaseSelf();
|
|
6704
6818
|
}
|
|
6705
6819
|
}
|
|
6706
|
-
transactInputNow(
|
|
6707
|
-
this.transact(new InputEvent(
|
|
6820
|
+
transactInputNow(path2, event, eventHandler, dragInfo) {
|
|
6821
|
+
this.transact(new InputEvent(path2, event, eventHandler, this, dragInfo));
|
|
6708
6822
|
}
|
|
6709
6823
|
};
|
|
6710
6824
|
function nullHandler() {
|
|
6711
6825
|
return this;
|
|
6712
6826
|
}
|
|
6713
6827
|
var Transaction = class {
|
|
6714
|
-
constructor(
|
|
6715
|
-
this.path =
|
|
6828
|
+
constructor(path2, transactor, parentTransaction = null) {
|
|
6829
|
+
this.path = path2;
|
|
6830
|
+
this.txnPath = null;
|
|
6716
6831
|
this.transactor = transactor;
|
|
6717
6832
|
this.parentTransaction = parentTransaction;
|
|
6718
6833
|
this._completion = null;
|
|
@@ -6761,9 +6876,11 @@ var Transaction = class {
|
|
|
6761
6876
|
getHandlerAndArgs(_root, _instance, _comps) {
|
|
6762
6877
|
return null;
|
|
6763
6878
|
}
|
|
6764
|
-
// The path used to apply the mutation
|
|
6765
|
-
//
|
|
6879
|
+
// The path used to apply the mutation: the ACTIVE frame of the dispatch path, so
|
|
6880
|
+
// an event inside a `<x render="*name">` subtree updates the value where it
|
|
6881
|
+
// really lives (the dispatch `this.path` keeps the visual callers, for bubbling).
|
|
6766
6882
|
getTransactionPath() {
|
|
6883
|
+
if (this.txnPath !== null) return this.txnPath;
|
|
6767
6884
|
return this.path.toTransactionPath().compact();
|
|
6768
6885
|
}
|
|
6769
6886
|
run(curRoot, comps) {
|
|
@@ -6781,15 +6898,16 @@ var Transaction = class {
|
|
|
6781
6898
|
}
|
|
6782
6899
|
};
|
|
6783
6900
|
var InputEvent = class extends Transaction {
|
|
6784
|
-
constructor(
|
|
6785
|
-
super(
|
|
6901
|
+
constructor(path2, e, handler, transactor, dragInfo) {
|
|
6902
|
+
super(path2, transactor);
|
|
6786
6903
|
this.e = e;
|
|
6787
6904
|
this.handler = handler;
|
|
6788
6905
|
this.dragInfo = dragInfo;
|
|
6789
6906
|
this._dispatchPath = null;
|
|
6790
6907
|
}
|
|
6791
|
-
// Frame steps removed,
|
|
6792
|
-
//
|
|
6908
|
+
// Frame-only steps removed, one step per crossed component kept — inside every
|
|
6909
|
+
// continuation frame independently, so bubbling it visits every component and
|
|
6910
|
+
// then returns to the caller that wrote the `*name`.
|
|
6793
6911
|
get dispatchPath() {
|
|
6794
6912
|
this._dispatchPath ??= this.path.compact();
|
|
6795
6913
|
return this._dispatchPath;
|
|
@@ -6824,11 +6942,11 @@ var InputEvent = class extends Transaction {
|
|
|
6824
6942
|
this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
|
|
6825
6943
|
}
|
|
6826
6944
|
getHandlerAndArgs(root, _instance, comps) {
|
|
6827
|
-
const stack = this.path.
|
|
6945
|
+
const stack = this.path.buildStack(Stack.root(comps, root, this));
|
|
6828
6946
|
const [handler, args] = this.handler.getHandlerAndArgs(stack, this);
|
|
6829
6947
|
this._handlerArgs = [...args];
|
|
6830
|
-
const
|
|
6831
|
-
args.push(new EventContext(
|
|
6948
|
+
const path2 = this.dispatchPath;
|
|
6949
|
+
args.push(new EventContext(path2, this.transactor, this));
|
|
6832
6950
|
return [handler, args];
|
|
6833
6951
|
}
|
|
6834
6952
|
// The dispatched DOM event, read only through `e.<member>` handler args
|
|
@@ -6839,11 +6957,11 @@ var InputEvent = class extends Transaction {
|
|
|
6839
6957
|
}
|
|
6840
6958
|
};
|
|
6841
6959
|
var NameArgsTransaction = class extends Transaction {
|
|
6842
|
-
constructor(
|
|
6843
|
-
super(
|
|
6960
|
+
constructor(path2, transactor, name, args, parentTransaction) {
|
|
6961
|
+
super(path2, transactor, parentTransaction);
|
|
6844
6962
|
this.name = name;
|
|
6845
6963
|
this.args = args;
|
|
6846
|
-
this.targetPath =
|
|
6964
|
+
this.targetPath = path2;
|
|
6847
6965
|
}
|
|
6848
6966
|
handlerProp = null;
|
|
6849
6967
|
// NameArgs verbs map their handler bucket straight to the observed kind:
|
|
@@ -6900,8 +7018,8 @@ var SendEvent = class extends NameArgsTransaction {
|
|
|
6900
7018
|
};
|
|
6901
7019
|
var IntentEvent = class extends NameArgsTransaction {
|
|
6902
7020
|
handlerProp = "intent";
|
|
6903
|
-
constructor(
|
|
6904
|
-
super(
|
|
7021
|
+
constructor(path2, transactor, walk) {
|
|
7022
|
+
super(path2, transactor, walk.name, walk.args, walk.parent);
|
|
6905
7023
|
this.walk = walk;
|
|
6906
7024
|
this.targetPath = walk.origin;
|
|
6907
7025
|
}
|
|
@@ -6928,17 +7046,17 @@ var PASS = /* @__PURE__ */ Symbol.for("tutuca.intent.pass");
|
|
|
6928
7046
|
var REFUSAL_RING_CAP = 200;
|
|
6929
7047
|
var INTENT_DEPTH = 64;
|
|
6930
7048
|
var IntentWalk = class {
|
|
6931
|
-
constructor(transactor,
|
|
7049
|
+
constructor(transactor, path2, name, args, opts, parent, release) {
|
|
6932
7050
|
this.transactor = transactor;
|
|
6933
7051
|
this.name = name;
|
|
6934
7052
|
this.args = args;
|
|
6935
7053
|
this.route = opts?.route ?? DEFAULT_ROUTE;
|
|
6936
7054
|
this.parent = parent;
|
|
6937
7055
|
this.release = release;
|
|
6938
|
-
this.origin =
|
|
6939
|
-
this.answerPath = opts?.livePath ? null :
|
|
7056
|
+
this.origin = path2;
|
|
7057
|
+
this.answerPath = opts?.livePath ? null : path2.toTransactionPath().pinKeys(transactor.state.val);
|
|
6940
7058
|
this.legIndex = 0;
|
|
6941
|
-
this.dynAt =
|
|
7059
|
+
this.dynAt = path2;
|
|
6942
7060
|
this.hops = 0;
|
|
6943
7061
|
this.ended = false;
|
|
6944
7062
|
}
|
|
@@ -6950,7 +7068,7 @@ var IntentWalk = class {
|
|
|
6950
7068
|
while (this.legIndex < this.route.length) {
|
|
6951
7069
|
const leg = this.route[this.legIndex];
|
|
6952
7070
|
if (leg === "dyn") {
|
|
6953
|
-
if (this.dynAt.
|
|
7071
|
+
if (!this.dynAt.canPop()) {
|
|
6954
7072
|
this.legIndex++;
|
|
6955
7073
|
continue;
|
|
6956
7074
|
}
|
|
@@ -7047,8 +7165,8 @@ var IntentWalk = class {
|
|
|
7047
7165
|
if (this.ended) return;
|
|
7048
7166
|
this.ended = true;
|
|
7049
7167
|
if (name === null) return this.release?.();
|
|
7050
|
-
const
|
|
7051
|
-
|
|
7168
|
+
const t = new SendEvent(this.origin, this.transactor, name, args, this.parent);
|
|
7169
|
+
t.txnPath = this.answerPath;
|
|
7052
7170
|
t._isAnswer = true;
|
|
7053
7171
|
this.transactor.pushTransaction(t);
|
|
7054
7172
|
if (this.release) t.completion.whenSubtreeSettled().then(this.release);
|
|
@@ -7114,8 +7232,8 @@ var Completion = class {
|
|
|
7114
7232
|
}
|
|
7115
7233
|
};
|
|
7116
7234
|
var Dispatcher = class {
|
|
7117
|
-
constructor(
|
|
7118
|
-
this.path =
|
|
7235
|
+
constructor(path2, transactor, parentTransaction, root = transactor.state.val) {
|
|
7236
|
+
this.path = path2;
|
|
7119
7237
|
this.transactor = transactor;
|
|
7120
7238
|
this.parent = parentTransaction;
|
|
7121
7239
|
this.root = root;
|
|
@@ -7143,7 +7261,9 @@ var Dispatcher = class {
|
|
|
7143
7261
|
// replayed; provides are pushed on every component frame either way, so a provide
|
|
7144
7262
|
// that reads a loop binding is the one case this cannot reproduce faithfully.
|
|
7145
7263
|
_stack() {
|
|
7146
|
-
this._stackMemo ??= this.path.
|
|
7264
|
+
this._stackMemo ??= this.path.buildStack(
|
|
7265
|
+
Stack.root(this.transactor.comps, this.root, this.parent)
|
|
7266
|
+
);
|
|
7147
7267
|
return this._stackMemo;
|
|
7148
7268
|
}
|
|
7149
7269
|
// Resolve a name the way the renderer would. `opts.route` takes the same legs in
|
|
@@ -7157,14 +7277,19 @@ var Dispatcher = class {
|
|
|
7157
7277
|
);
|
|
7158
7278
|
}
|
|
7159
7279
|
// The `lex` leg without a Stack: the scope of the component whose handler is
|
|
7160
|
-
// running, which is the leaf of this ctx's path.
|
|
7280
|
+
// running, which is the leaf of this ctx's path. A type name resolves to the
|
|
7281
|
+
// component registered under it; a value name to a path registered under it
|
|
7282
|
+
// (see ComponentStack.registerPaths), read against the current root.
|
|
7161
7283
|
_lookupLex(name) {
|
|
7162
7284
|
let Comp = null;
|
|
7163
7285
|
this.walkPath((c) => {
|
|
7164
7286
|
Comp = c;
|
|
7165
7287
|
return false;
|
|
7166
7288
|
});
|
|
7167
|
-
|
|
7289
|
+
const scope = Comp?.scope;
|
|
7290
|
+
if (scope == null) return null;
|
|
7291
|
+
if (isTypeName(name)) return scope.lookupComponent(name) ?? null;
|
|
7292
|
+
return scope.lookupPath(name)?.lookup(this.root) ?? null;
|
|
7168
7293
|
}
|
|
7169
7294
|
// A component lookup is a value lookup constrained to a component. The `lex` leg
|
|
7170
7295
|
// can only ever answer with one; the `dyn` leg reads a binding an ancestor
|
|
@@ -7186,8 +7311,8 @@ var Dispatcher = class {
|
|
|
7186
7311
|
send(name, args) {
|
|
7187
7312
|
return this.sendAtPath(this.path, name, args);
|
|
7188
7313
|
}
|
|
7189
|
-
sendAtPath(
|
|
7190
|
-
return this.transactor.pushSend(
|
|
7314
|
+
sendAtPath(path2, name, args) {
|
|
7315
|
+
return this.transactor.pushSend(path2, name, args, this.parent, this.path);
|
|
7191
7316
|
}
|
|
7192
7317
|
// An intent is ROUTED: it names a job and walks until something answers. The verb
|
|
7193
7318
|
// does not decide which scope answers — `opts.route` does, written here at the call
|
|
@@ -7195,8 +7320,8 @@ var Dispatcher = class {
|
|
|
7195
7320
|
intent(name, args, opts) {
|
|
7196
7321
|
return this.intentAtPath(this.path, name, args, opts);
|
|
7197
7322
|
}
|
|
7198
|
-
intentAtPath(
|
|
7199
|
-
return this.transactor.pushIntent(
|
|
7323
|
+
intentAtPath(path2, name, args, opts) {
|
|
7324
|
+
return this.transactor.pushIntent(path2, name, args, opts, this.parent);
|
|
7200
7325
|
}
|
|
7201
7326
|
};
|
|
7202
7327
|
var EventContext = class extends Dispatcher {
|
|
@@ -7225,7 +7350,14 @@ var EventContext = class extends Dispatcher {
|
|
|
7225
7350
|
this.transactor.refuse("NO_SENDER", { name });
|
|
7226
7351
|
return null;
|
|
7227
7352
|
}
|
|
7228
|
-
return this.
|
|
7353
|
+
return this.transactor.pushSend(
|
|
7354
|
+
origin,
|
|
7355
|
+
name,
|
|
7356
|
+
args,
|
|
7357
|
+
this.parent,
|
|
7358
|
+
this.path,
|
|
7359
|
+
this.parent.originPinned
|
|
7360
|
+
);
|
|
7229
7361
|
}
|
|
7230
7362
|
// End the walk answering nothing — "served, and no answer".
|
|
7231
7363
|
stop() {
|
|
@@ -7257,13 +7389,13 @@ var PathChanges = class extends PathBuilder {
|
|
|
7257
7389
|
}
|
|
7258
7390
|
};
|
|
7259
7391
|
function rootDispatcher(transactor) {
|
|
7260
|
-
return new Dispatcher(new
|
|
7392
|
+
return new Dispatcher(new DispatchPath(), transactor, null);
|
|
7261
7393
|
}
|
|
7262
7394
|
|
|
7263
7395
|
// tools/core/results.js
|
|
7264
7396
|
var ModuleInfo = class {
|
|
7265
|
-
constructor({ path = null, present = /* @__PURE__ */ new Set(), counts = {}, warnings = [] }) {
|
|
7266
|
-
this.path =
|
|
7397
|
+
constructor({ path: path2 = null, present = /* @__PURE__ */ new Set(), counts = {}, warnings = [] }) {
|
|
7398
|
+
this.path = path2;
|
|
7267
7399
|
this.present = present;
|
|
7268
7400
|
this.counts = counts;
|
|
7269
7401
|
this.warnings = warnings;
|
|
@@ -7373,8 +7505,8 @@ var DescribeResult = class {
|
|
|
7373
7505
|
}
|
|
7374
7506
|
};
|
|
7375
7507
|
var ModuleTestReport = class {
|
|
7376
|
-
constructor({ path = null, suites = [], counts = { pass: 0, fail: 0, skip: 0, total: 0 } }) {
|
|
7377
|
-
this.path =
|
|
7508
|
+
constructor({ path: path2 = null, suites = [], counts = { pass: 0, fail: 0, skip: 0, total: 0 } }) {
|
|
7509
|
+
this.path = path2;
|
|
7378
7510
|
this.suites = suites;
|
|
7379
7511
|
this.counts = counts;
|
|
7380
7512
|
}
|
|
@@ -7417,8 +7549,8 @@ var Test = class {
|
|
|
7417
7549
|
}
|
|
7418
7550
|
};
|
|
7419
7551
|
var ModuleTests = class {
|
|
7420
|
-
constructor({ path = null, suites = [] } = {}) {
|
|
7421
|
-
this.path =
|
|
7552
|
+
constructor({ path: path2 = null, suites = [] } = {}) {
|
|
7553
|
+
this.path = path2;
|
|
7422
7554
|
this.suites = suites;
|
|
7423
7555
|
}
|
|
7424
7556
|
};
|
|
@@ -7440,8 +7572,8 @@ function titleFromArg(arg) {
|
|
|
7440
7572
|
if (typeof arg === "function") return arg.name || "(anonymous)";
|
|
7441
7573
|
return String(arg);
|
|
7442
7574
|
}
|
|
7443
|
-
function makeCollector({ path = null, components = [] } = {}) {
|
|
7444
|
-
const moduleTests = new ModuleTests({ path, suites: [] });
|
|
7575
|
+
function makeCollector({ path: path2 = null, components = [] } = {}) {
|
|
7576
|
+
const moduleTests = new ModuleTests({ path: path2, suites: [] });
|
|
7445
7577
|
const stack = [];
|
|
7446
7578
|
function describe(...args) {
|
|
7447
7579
|
let head;
|
|
@@ -7542,7 +7674,7 @@ async function driveStack(stack, value, phase, opts = {}) {
|
|
|
7542
7674
|
val
|
|
7543
7675
|
);
|
|
7544
7676
|
});
|
|
7545
|
-
dispatchPhase(rootDispatcher(transactor), new
|
|
7677
|
+
dispatchPhase(rootDispatcher(transactor), new DispatchPath(), phase, value);
|
|
7546
7678
|
await transactor.settle();
|
|
7547
7679
|
return transactor.state.val;
|
|
7548
7680
|
}
|
|
@@ -7552,7 +7684,7 @@ async function drive(cfg, value, phase, opts = {}) {
|
|
|
7552
7684
|
async function runTests({
|
|
7553
7685
|
getTests,
|
|
7554
7686
|
components = [],
|
|
7555
|
-
path = null,
|
|
7687
|
+
path: path2 = null,
|
|
7556
7688
|
expect: expect3,
|
|
7557
7689
|
name = null,
|
|
7558
7690
|
grep = null,
|
|
@@ -7563,13 +7695,13 @@ async function runTests({
|
|
|
7563
7695
|
const counts = { pass: 0, fail: 0, skip: 0, total: 0 };
|
|
7564
7696
|
if (typeof getTests !== "function") {
|
|
7565
7697
|
return new TestReport({
|
|
7566
|
-
modules: [new ModuleTestReport({ path, suites: [], counts })]
|
|
7698
|
+
modules: [new ModuleTestReport({ path: path2, suites: [], counts })]
|
|
7567
7699
|
});
|
|
7568
7700
|
}
|
|
7569
7701
|
if (typeof expect3 !== "function") {
|
|
7570
7702
|
throw new Error("runTests: expect must be provided (e.g. chai's expect)");
|
|
7571
7703
|
}
|
|
7572
|
-
const { describe, test: test2, moduleTests } = makeCollector({ path, components });
|
|
7704
|
+
const { describe, test: test2, moduleTests } = makeCollector({ path: path2, components });
|
|
7573
7705
|
let _stack = null;
|
|
7574
7706
|
const getStack = () => _stack ??= buildStack({ components, macros, intentHandlers });
|
|
7575
7707
|
const driveLocal = (value, phase, opts = {}) => driveStack(getStack(), value, phase, opts);
|
|
@@ -7632,7 +7764,7 @@ async function runTests({
|
|
|
7632
7764
|
if (r !== null) suiteResults.push(r);
|
|
7633
7765
|
}
|
|
7634
7766
|
return new TestReport({
|
|
7635
|
-
modules: [new ModuleTestReport({ path, suites: suiteResults, counts })]
|
|
7767
|
+
modules: [new ModuleTestReport({ path: path2, suites: suiteResults, counts })]
|
|
7636
7768
|
});
|
|
7637
7769
|
}
|
|
7638
7770
|
|
|
@@ -7801,15 +7933,13 @@ function lintIdToMessage(id, info) {
|
|
|
7801
7933
|
case "DYN_ALIAS_NOT_REFERENCED":
|
|
7802
7934
|
return `Lookup '${info.name}' is defined but never used — remove it or reference it as '*${info.name}' in a view`;
|
|
7803
7935
|
case "PROVIDE_NOT_ADDRESSABLE":
|
|
7804
|
-
return `Provide '${info.name}' value '${info.value}' must be a field ('.f') or seq-access ('.s[.k]') — a
|
|
7936
|
+
return `Provide '${info.name}' value '${info.value}' must be a field ('.f') or seq-access ('.s[.k]') — a provide doubles as the path '<x render="*${info.name}">' resumes at, so this one is dropped and '*${info.name}' resolves to nothing`;
|
|
7805
7937
|
case "LOOKUP_BAD_SHAPE":
|
|
7806
7938
|
return `Lookup '${info.name}' has an invalid shape: ${info.problem}`;
|
|
7807
7939
|
case "LOOKUP_NO_PROVIDER":
|
|
7808
|
-
return info.hasDefault ? `Lookup '${info.name}' is provided by no component in scope, so it always resolves to its default` : `Lookup '${info.name}' is provided by no component in scope — add a 'provide' for it, or give this lookup a default`;
|
|
7940
|
+
return info.hasDefault ? `Lookup '${info.name}' is provided by no component in scope and matches no registered path, so it always resolves to its default` : `Lookup '${info.name}' is provided by no component in scope and matches no registered path — add a 'provide' for it, register a path under that name, or give this lookup a default`;
|
|
7809
7941
|
case "PROVIDE_TYPE_BAD_SHAPE":
|
|
7810
7942
|
return `Provide '${info.name}' starts uppercase, so it publishes a component type — its value must be 'self', not '${info.value}'`;
|
|
7811
|
-
case "PROVIDE_NAME_COLLISION":
|
|
7812
|
-
return `Provide '${info.name}' is also provided by '${info.other}' in the same scope — one name, one provider, so a lookup can find it`;
|
|
7813
7943
|
case "UNKNOWN_MACRO_ARG":
|
|
7814
7944
|
return `Argument '${info.name}' is not declared in macro '${info.macroName}'`;
|
|
7815
7945
|
case "UNKNOWN_DIRECTIVE":
|
|
@@ -7975,7 +8105,7 @@ var App = class {
|
|
|
7975
8105
|
const { type } = e;
|
|
7976
8106
|
const isDrag = type === "dragover" || type === "dragstart" || type === "dragend" || type === "drop";
|
|
7977
8107
|
const { rootNode: root, maxEventNodeDepth: maxDepth, comps, transactor } = this;
|
|
7978
|
-
const [
|
|
8108
|
+
const [path2, handlers] = DispatchPath.fromNodeAndEventName(
|
|
7979
8109
|
e.target,
|
|
7980
8110
|
type,
|
|
7981
8111
|
root,
|
|
@@ -7983,9 +8113,9 @@ var App = class {
|
|
|
7983
8113
|
comps,
|
|
7984
8114
|
!isDrag
|
|
7985
8115
|
);
|
|
7986
|
-
if (isDrag) this._handleDragEvent(e, type,
|
|
7987
|
-
if (
|
|
7988
|
-
for (const handler of handlers) transactor.transactInputNow(
|
|
8116
|
+
if (isDrag) this._handleDragEvent(e, type, path2);
|
|
8117
|
+
if (path2 !== null && handlers !== null)
|
|
8118
|
+
for (const handler of handlers) transactor.transactInputNow(path2, e, handler, this.dragInfo);
|
|
7989
8119
|
}
|
|
7990
8120
|
_handleTouchEvent(e) {
|
|
7991
8121
|
const { type } = e;
|
|
@@ -8028,7 +8158,7 @@ var App = class {
|
|
|
8028
8158
|
this._touch = null;
|
|
8029
8159
|
}
|
|
8030
8160
|
}
|
|
8031
|
-
_handleDragEvent(e, type,
|
|
8161
|
+
_handleDragEvent(e, type, path2) {
|
|
8032
8162
|
if (type === "dragover") {
|
|
8033
8163
|
const dropTarget = getClosestDropTarget(e.target, this.rootNode, Infinity);
|
|
8034
8164
|
if (dropTarget !== null) {
|
|
@@ -8040,10 +8170,10 @@ var App = class {
|
|
|
8040
8170
|
} else if (type === "dragstart") {
|
|
8041
8171
|
e.target.dataset.dragging = 1;
|
|
8042
8172
|
const rootValue = this.state.val;
|
|
8043
|
-
const txnPath =
|
|
8173
|
+
const txnPath = path2.compact().toTransactionPath();
|
|
8044
8174
|
const value = txnPath.lookup(rootValue);
|
|
8045
8175
|
const dragType = e.target.dataset.dragtype ?? "?";
|
|
8046
|
-
const stack =
|
|
8176
|
+
const stack = path2.buildStack(this.makeStack(rootValue));
|
|
8047
8177
|
this.dragInfo = new DragInfo(stack, value, dragType, e.target);
|
|
8048
8178
|
} else if (type === "drop") {
|
|
8049
8179
|
e.preventDefault();
|
|
@@ -8118,7 +8248,7 @@ var App = class {
|
|
|
8118
8248
|
this.rootNode.removeEventListener(name, this, listenerOpts(name));
|
|
8119
8249
|
}
|
|
8120
8250
|
sendAtRoot(name, args) {
|
|
8121
|
-
this.transactor.pushSend(new
|
|
8251
|
+
this.transactor.pushSend(new DispatchPath(), name, args);
|
|
8122
8252
|
}
|
|
8123
8253
|
registerComponents(comps, opts) {
|
|
8124
8254
|
const scope = this.compStack.enter();
|
|
@@ -8258,7 +8388,20 @@ var WeakMapDomCache = class {
|
|
|
8258
8388
|
};
|
|
8259
8389
|
|
|
8260
8390
|
// src/renderer.js
|
|
8261
|
-
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
|
|
8391
|
+
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk", "rp"];
|
|
8392
|
+
function stampRenderBase(vdom, text) {
|
|
8393
|
+
if (vdom instanceof VNode)
|
|
8394
|
+
return new VNode(
|
|
8395
|
+
vdom.tag,
|
|
8396
|
+
{ ...vdom.attrs, "data-rp": text },
|
|
8397
|
+
vdom.childs,
|
|
8398
|
+
vdom.key,
|
|
8399
|
+
vdom.namespace
|
|
8400
|
+
);
|
|
8401
|
+
if (vdom instanceof VFragment)
|
|
8402
|
+
return new VFragment(vdom.childs.map((c) => stampRenderBase(c, text)));
|
|
8403
|
+
return vdom;
|
|
8404
|
+
}
|
|
8262
8405
|
var Renderer = class {
|
|
8263
8406
|
constructor(comps) {
|
|
8264
8407
|
this.comps = comps;
|
|
@@ -8295,17 +8438,17 @@ var Renderer = class {
|
|
|
8295
8438
|
if (comp === null) return null;
|
|
8296
8439
|
return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
|
|
8297
8440
|
}
|
|
8298
|
-
renderIt(stack, node, key, viewName) {
|
|
8441
|
+
renderIt(stack, node, key, viewName, base = null) {
|
|
8299
8442
|
const comp = this.comps.getCompFor(stack.it);
|
|
8300
|
-
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
|
|
8443
|
+
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName, base) : null;
|
|
8301
8444
|
}
|
|
8302
8445
|
// `node` is the parse node of the render site (`<x render>` / `render-it` /
|
|
8303
8446
|
// `render-each`, or the view's root anode for the app root). It keys the
|
|
8304
8447
|
// cache as a globally-unique object: node ids alone are unique only within a
|
|
8305
8448
|
// single view, so the same value rendered by two components (e.g. through a
|
|
8306
8449
|
// shared dynamic-var sequence) would otherwise collide in the cache.
|
|
8307
|
-
_rValComp(stack, val, comp, node, key, viewName) {
|
|
8308
|
-
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
|
|
8450
|
+
_rValComp(stack, val, comp, node, key, viewName, base = null) {
|
|
8451
|
+
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}${stack.renderPath.addressKey}`;
|
|
8309
8452
|
const cachePath = [node, val];
|
|
8310
8453
|
stack._pushDynBindValuesToArray(cachePath, comp);
|
|
8311
8454
|
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
@@ -8313,30 +8456,43 @@ var Renderer = class {
|
|
|
8313
8456
|
const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
|
|
8314
8457
|
const body = this.renderView(view, stack);
|
|
8315
8458
|
if (body == null) return null;
|
|
8459
|
+
const baseJson = base === null ? null : pathToJson(base);
|
|
8316
8460
|
const meta = this._renderMetadata({
|
|
8317
8461
|
$: "Comp",
|
|
8318
8462
|
nid: node?.nodeId ?? null,
|
|
8319
8463
|
cid: comp.id,
|
|
8320
|
-
vid: view.name
|
|
8464
|
+
vid: view.name,
|
|
8465
|
+
...baseJson === null ? null : { base: baseJson }
|
|
8321
8466
|
});
|
|
8322
|
-
const dom = new VFragment([
|
|
8467
|
+
const dom = new VFragment([
|
|
8468
|
+
meta,
|
|
8469
|
+
baseJson === null ? body : stampRenderBase(body, JSON.stringify(baseJson))
|
|
8470
|
+
]);
|
|
8323
8471
|
this.cache.set(cachePath, cacheKey, dom);
|
|
8324
8472
|
return dom;
|
|
8325
8473
|
}
|
|
8326
8474
|
pushEachEntry(r, nid, attrName, key, dom) {
|
|
8327
8475
|
r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
|
|
8328
8476
|
}
|
|
8329
|
-
renderEachWhen(stack,
|
|
8477
|
+
renderEachWhen(stack, each) {
|
|
8478
|
+
const { iterInfo, node: view, nodeId: nid } = each;
|
|
8330
8479
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
8480
|
+
const seqPath = iterInfo.val instanceof DynVal ? stack.lookupDynamicLocated(iterInfo.val.name)?.path ?? null : null;
|
|
8331
8481
|
const r = [];
|
|
8332
8482
|
const it = stack.it;
|
|
8333
8483
|
const renderOne = (key, value, attrName, binds) => {
|
|
8484
|
+
const itemBase = seqPath === null ? null : keyedPath(seqPath, key);
|
|
8485
|
+
const itemStep = itemBase === null ? each.itemStep(key) : null;
|
|
8486
|
+
const itemPath = itemBase !== null ? stack.renderPath.pushFrame(itemBase) : itemStep !== null ? stack.renderPath.pushItem(itemStep) : stack.renderPath;
|
|
8334
8487
|
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
8335
|
-
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
|
|
8488
|
+
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}${itemPath.addressKey}`;
|
|
8336
8489
|
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
8337
8490
|
if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
8338
8491
|
else {
|
|
8339
|
-
const dom = this.renderView(
|
|
8492
|
+
const dom = this.renderView(
|
|
8493
|
+
view,
|
|
8494
|
+
stack.enter(value, binds, false, itemPath, itemBase !== null)
|
|
8495
|
+
);
|
|
8340
8496
|
if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
|
|
8341
8497
|
this.cache.set(cachePath, cacheKey, dom);
|
|
8342
8498
|
}
|
|
@@ -8593,7 +8749,6 @@ export {
|
|
|
8593
8749
|
ModuleTests,
|
|
8594
8750
|
PASS,
|
|
8595
8751
|
PLACEHOLDERLESS_TEMPLATE_STRING,
|
|
8596
|
-
PROVIDE_NAME_COLLISION,
|
|
8597
8752
|
PROVIDE_NOT_ADDRESSABLE,
|
|
8598
8753
|
PROVIDE_TYPE_BAD_SHAPE,
|
|
8599
8754
|
ParseContext,
|
|
@@ -8634,6 +8789,7 @@ export {
|
|
|
8634
8789
|
lintIdToMessage,
|
|
8635
8790
|
macro,
|
|
8636
8791
|
makeCollector,
|
|
8792
|
+
path,
|
|
8637
8793
|
phaseOps,
|
|
8638
8794
|
reportTestReportToConsole,
|
|
8639
8795
|
resolveArgs,
|