tutuca 0.9.96 → 0.9.98
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 +193 -61
- package/dist/tutuca-dev.ext.js +80 -31
- package/dist/tutuca-dev.js +80 -31
- package/dist/tutuca-dev.min.js +2 -2
- package/dist/tutuca-extra.ext.js +60 -30
- package/dist/tutuca-extra.js +60 -30
- package/dist/tutuca-extra.min.js +2 -2
- package/dist/tutuca-storybook.js +11 -4
- package/dist/tutuca.ext.js +60 -30
- package/dist/tutuca.js +60 -30
- package/dist/tutuca.min.js +2 -2
- package/package.json +3 -3
- package/skill/tutuca/advanced.md +14 -5
- package/skill/tutuca/core.md +78 -15
- package/skill/tutuca/margaui.md +25 -13
- package/skill/tutuca/patterns/README.md +1 -0
- package/skill/tutuca/patterns/filter-a-list.md +3 -1
- package/skill/tutuca/patterns/filter-and-paginate.md +116 -0
- package/skill/tutuca/patterns/paginate-a-list.md +3 -1
- package/skill/tutuca/storybook.md +7 -2
- package/skill/tutuca/testing.md +11 -0
- package/skill/tutuca-source/tutuca.ext.js +60 -30
package/dist/tutuca-dev.js
CHANGED
|
@@ -8973,6 +8973,8 @@ class RequestHandler {
|
|
|
8973
8973
|
}
|
|
8974
8974
|
|
|
8975
8975
|
// src/cache.js
|
|
8976
|
+
var isWeakKey = (k) => k !== null && (typeof k === "object" || typeof k === "function");
|
|
8977
|
+
|
|
8976
8978
|
class NullDomCache {
|
|
8977
8979
|
get(_keys, _cacheKey) {}
|
|
8978
8980
|
set(_keys, _cacheKey, _v) {}
|
|
@@ -9016,7 +9018,7 @@ class WeakMapDomCache {
|
|
|
9016
9018
|
const key = keys[i];
|
|
9017
9019
|
let next = cur.get(key);
|
|
9018
9020
|
if (!next) {
|
|
9019
|
-
if (
|
|
9021
|
+
if (!isWeakKey(key)) {
|
|
9020
9022
|
this.badKey += 1;
|
|
9021
9023
|
return;
|
|
9022
9024
|
}
|
|
@@ -9029,7 +9031,7 @@ class WeakMapDomCache {
|
|
|
9029
9031
|
const leaf = cur.get(lastKey);
|
|
9030
9032
|
if (leaf)
|
|
9031
9033
|
leaf[cacheKey] = v;
|
|
9032
|
-
else if (
|
|
9034
|
+
else if (isWeakKey(lastKey))
|
|
9033
9035
|
cur.set(lastKey, { [cacheKey]: v });
|
|
9034
9036
|
else
|
|
9035
9037
|
this.badKey += 1;
|
|
@@ -9491,37 +9493,47 @@ class Renderer {
|
|
|
9491
9493
|
renderEach(stack, iterInfo, node, viewName) {
|
|
9492
9494
|
const { seq, filter, loopWith } = iterInfo.eval(stack);
|
|
9493
9495
|
const r = [];
|
|
9494
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
9495
|
-
|
|
9496
|
-
|
|
9497
|
-
|
|
9498
|
-
|
|
9499
|
-
|
|
9500
|
-
|
|
9496
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
9497
|
+
const renderOne = (key, value, attrName) => {
|
|
9498
|
+
const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
|
|
9499
|
+
this.pushEachEntry(r, node.nodeId, attrName, key, dom);
|
|
9500
|
+
};
|
|
9501
|
+
if (keys)
|
|
9502
|
+
imKeysIter(seq, renderOne, keys);
|
|
9503
|
+
else
|
|
9504
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
9505
|
+
if (filter.call(stack.it, key, value, iterData))
|
|
9506
|
+
renderOne(key, value, attrName);
|
|
9507
|
+
}, start, end);
|
|
9501
9508
|
return r;
|
|
9502
9509
|
}
|
|
9503
9510
|
renderEachWhen(stack, iterInfo, view, nid) {
|
|
9504
9511
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
9505
9512
|
const r = [];
|
|
9506
9513
|
const it = stack.it;
|
|
9507
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(it, seq), seq);
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
this.cache.set(cachePath, cacheKey, dom);
|
|
9522
|
-
}
|
|
9514
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, makeLoopCtx(stack, filter)), seq);
|
|
9515
|
+
const renderOne = (key, value, attrName) => {
|
|
9516
|
+
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
9517
|
+
const binds = { key, value };
|
|
9518
|
+
const cacheKey = `${nid}-${key}`;
|
|
9519
|
+
if (enricher)
|
|
9520
|
+
enricher.call(it, binds, key, value, iterData);
|
|
9521
|
+
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
9522
|
+
if (cachedNode)
|
|
9523
|
+
this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
9524
|
+
else {
|
|
9525
|
+
const dom = this.renderView(view, stack.enter(value, binds, false));
|
|
9526
|
+
this.pushEachEntry(r, nid, attrName, key, dom);
|
|
9527
|
+
this.cache.set(cachePath, cacheKey, dom);
|
|
9523
9528
|
}
|
|
9524
|
-
}
|
|
9529
|
+
};
|
|
9530
|
+
if (keys)
|
|
9531
|
+
imKeysIter(seq, renderOne, keys);
|
|
9532
|
+
else
|
|
9533
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
9534
|
+
if (filter.call(it, key, value, iterData))
|
|
9535
|
+
renderOne(key, value, attrName);
|
|
9536
|
+
}, start, end);
|
|
9525
9537
|
return r;
|
|
9526
9538
|
}
|
|
9527
9539
|
renderView(view, stack) {
|
|
@@ -9557,8 +9569,17 @@ var filterAlwaysTrue = (_v, _k, _seq) => true;
|
|
|
9557
9569
|
var nullLoopWith = (seq) => ({ iterData: { seq } });
|
|
9558
9570
|
var unpackLoopResult = (result, seq) => {
|
|
9559
9571
|
const r = result ?? {};
|
|
9560
|
-
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end };
|
|
9572
|
+
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
|
|
9573
|
+
};
|
|
9574
|
+
var imKeysIter = (seq, visit, keys) => {
|
|
9575
|
+
const attrName = isIndexed(seq) ? "si" : "sk";
|
|
9576
|
+
for (const key of keys)
|
|
9577
|
+
visit(key, seq.get(key), attrName);
|
|
9561
9578
|
};
|
|
9579
|
+
var makeLoopCtx = (stack, filter) => ({
|
|
9580
|
+
lookup: (name) => stack.lookupBind(name),
|
|
9581
|
+
filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
|
|
9582
|
+
});
|
|
9562
9583
|
var imIndexedIter = (seq, visit, start, end) => {
|
|
9563
9584
|
const [s, e] = normalizeRange(start, end, seq.size);
|
|
9564
9585
|
for (let i = s;i < e; i++)
|
|
@@ -10106,11 +10127,11 @@ class IterInfo {
|
|
|
10106
10127
|
return { seq, filter, loopWith, enricher };
|
|
10107
10128
|
}
|
|
10108
10129
|
enrichBinds(stack, key) {
|
|
10109
|
-
const { seq, loopWith, enricher } = this.eval(stack);
|
|
10130
|
+
const { seq, filter, loopWith, enricher } = this.eval(stack);
|
|
10110
10131
|
const value = seq?.get ? seq.get(key, null) : null;
|
|
10111
10132
|
const binds = { key, value };
|
|
10112
10133
|
if (enricher) {
|
|
10113
|
-
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
10134
|
+
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
10114
10135
|
enricher.call(stack.it, binds, key, value, iterData);
|
|
10115
10136
|
}
|
|
10116
10137
|
return binds;
|
|
@@ -13689,6 +13710,13 @@ function phaseOps(phase) {
|
|
|
13689
13710
|
function resolveArgs(args, self) {
|
|
13690
13711
|
return typeof args === "function" ? args(self) ?? [] : args ?? [];
|
|
13691
13712
|
}
|
|
13713
|
+
function phaseHasBubble(phase) {
|
|
13714
|
+
if (!phase)
|
|
13715
|
+
return false;
|
|
13716
|
+
if (phase.bubble?.length)
|
|
13717
|
+
return true;
|
|
13718
|
+
return (phase.do ?? []).some((op) => op.type === "bubble");
|
|
13719
|
+
}
|
|
13692
13720
|
function dispatchPhase(dispatcher, targetPath, phase, self) {
|
|
13693
13721
|
if (!phase)
|
|
13694
13722
|
return;
|
|
@@ -14625,6 +14653,8 @@ async function driveStack(stack, value, phase, opts = {}) {
|
|
|
14625
14653
|
const t = info?.transaction;
|
|
14626
14654
|
opts.onMessage({ kind: t?.handlerProp ?? "input", name: t?.name, args: t?.args, path: t?.path }, old, val);
|
|
14627
14655
|
});
|
|
14656
|
+
if (phaseHasBubble(phase))
|
|
14657
|
+
console.warn("drive(): a `bubble` action is a no-op here — drive originates at the root and bubbles travel child→parent, so there is no ancestor to receive it (and the root's own bubble handler is skipped). To exercise a bubble handler, call it directly.");
|
|
14628
14658
|
dispatchPhase(rootDispatcher(transactor), new Path([]), phase, value);
|
|
14629
14659
|
await transactor.settle();
|
|
14630
14660
|
return transactor.state.val;
|
|
@@ -15556,7 +15586,8 @@ class FieldSet extends Field {
|
|
|
15556
15586
|
}
|
|
15557
15587
|
function mkCompField(field, scope, args) {
|
|
15558
15588
|
const Comp = scope?.lookupComponent(field.type) ?? null;
|
|
15559
|
-
|
|
15589
|
+
if (Comp === null)
|
|
15590
|
+
console.warn(scope ? `component field "${field.name}": component "${field.type}" not found in scope` : `component field "${field.name}": cannot resolve component "${field.type}" — built without a registered scope (use ${field.type}.make({}) as the default, or build via a registered component)`);
|
|
15560
15591
|
return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
|
|
15561
15592
|
}
|
|
15562
15593
|
|
|
@@ -15730,13 +15761,30 @@ function resolveAlter(Comp, name) {
|
|
|
15730
15761
|
}
|
|
15731
15762
|
return fn;
|
|
15732
15763
|
}
|
|
15764
|
+
var seqGet = (seq, key) => Array.isArray(seq) ? seq[key] : seq.get ? seq.get(key) : seq[key];
|
|
15733
15765
|
function collectIterBindings(Comp, compInstance, seq, opts = {}) {
|
|
15734
15766
|
const whenFn = resolveAlter(Comp, opts.when) ?? filterAlwaysTrue;
|
|
15735
15767
|
const loopWithFn = resolveAlter(Comp, opts.loopWith) ?? nullLoopWith;
|
|
15736
15768
|
const enrichFn = resolveAlter(Comp, opts.enrichWith);
|
|
15769
|
+
const scopeEnrichFn = resolveAlter(Comp, opts.scopeEnrich);
|
|
15737
15770
|
const it = compInstance;
|
|
15738
|
-
const
|
|
15771
|
+
const scope = scopeEnrichFn ? scopeEnrichFn.call(it) ?? {} : opts.scope ?? {};
|
|
15772
|
+
const ctx = {
|
|
15773
|
+
lookup: (name) => scope[name],
|
|
15774
|
+
filter: (key, value, iterData2) => whenFn.call(it, key, value, iterData2)
|
|
15775
|
+
};
|
|
15776
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWithFn.call(it, seq, ctx), seq);
|
|
15739
15777
|
const out = [];
|
|
15778
|
+
if (keys) {
|
|
15779
|
+
for (const key of keys) {
|
|
15780
|
+
const value = seqGet(seq, key);
|
|
15781
|
+
const binds = { key, value };
|
|
15782
|
+
if (enrichFn)
|
|
15783
|
+
enrichFn.call(it, binds, key, value, iterData);
|
|
15784
|
+
out.push(binds);
|
|
15785
|
+
}
|
|
15786
|
+
return out;
|
|
15787
|
+
}
|
|
15740
15788
|
const iter = pickIter(seq);
|
|
15741
15789
|
iter(seq, (key, value) => {
|
|
15742
15790
|
if (!whenFn.call(it, key, value, iterData))
|
|
@@ -16000,6 +16048,7 @@ export {
|
|
|
16000
16048
|
removeIn,
|
|
16001
16049
|
remove,
|
|
16002
16050
|
phaseOps,
|
|
16051
|
+
phaseHasBubble,
|
|
16003
16052
|
mergeWith$1 as mergeWith,
|
|
16004
16053
|
mergeDeepWith$1 as mergeDeepWith,
|
|
16005
16054
|
mergeDeep$1 as mergeDeep,
|