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-extra.ext.js
CHANGED
|
@@ -1224,6 +1224,8 @@ class RequestHandler {
|
|
|
1224
1224
|
import { isIndexed, isKeyed } from "immutable";
|
|
1225
1225
|
|
|
1226
1226
|
// src/cache.js
|
|
1227
|
+
var isWeakKey = (k) => k !== null && (typeof k === "object" || typeof k === "function");
|
|
1228
|
+
|
|
1227
1229
|
class NullDomCache {
|
|
1228
1230
|
get(_keys, _cacheKey) {}
|
|
1229
1231
|
set(_keys, _cacheKey, _v) {}
|
|
@@ -1267,7 +1269,7 @@ class WeakMapDomCache {
|
|
|
1267
1269
|
const key = keys[i];
|
|
1268
1270
|
let next = cur.get(key);
|
|
1269
1271
|
if (!next) {
|
|
1270
|
-
if (
|
|
1272
|
+
if (!isWeakKey(key)) {
|
|
1271
1273
|
this.badKey += 1;
|
|
1272
1274
|
return;
|
|
1273
1275
|
}
|
|
@@ -1280,7 +1282,7 @@ class WeakMapDomCache {
|
|
|
1280
1282
|
const leaf = cur.get(lastKey);
|
|
1281
1283
|
if (leaf)
|
|
1282
1284
|
leaf[cacheKey] = v;
|
|
1283
|
-
else if (
|
|
1285
|
+
else if (isWeakKey(lastKey))
|
|
1284
1286
|
cur.set(lastKey, { [cacheKey]: v });
|
|
1285
1287
|
else
|
|
1286
1288
|
this.badKey += 1;
|
|
@@ -1742,37 +1744,47 @@ class Renderer {
|
|
|
1742
1744
|
renderEach(stack, iterInfo, node, viewName) {
|
|
1743
1745
|
const { seq, filter, loopWith } = iterInfo.eval(stack);
|
|
1744
1746
|
const r = [];
|
|
1745
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1747
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
1748
|
+
const renderOne = (key, value, attrName) => {
|
|
1749
|
+
const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
|
|
1750
|
+
this.pushEachEntry(r, node.nodeId, attrName, key, dom);
|
|
1751
|
+
};
|
|
1752
|
+
if (keys)
|
|
1753
|
+
imKeysIter(seq, renderOne, keys);
|
|
1754
|
+
else
|
|
1755
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
1756
|
+
if (filter.call(stack.it, key, value, iterData))
|
|
1757
|
+
renderOne(key, value, attrName);
|
|
1758
|
+
}, start, end);
|
|
1752
1759
|
return r;
|
|
1753
1760
|
}
|
|
1754
1761
|
renderEachWhen(stack, iterInfo, view, nid) {
|
|
1755
1762
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
1756
1763
|
const r = [];
|
|
1757
1764
|
const it = stack.it;
|
|
1758
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(it, seq), seq);
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
this.cache.set(cachePath, cacheKey, dom);
|
|
1773
|
-
}
|
|
1765
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, makeLoopCtx(stack, filter)), seq);
|
|
1766
|
+
const renderOne = (key, value, attrName) => {
|
|
1767
|
+
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
1768
|
+
const binds = { key, value };
|
|
1769
|
+
const cacheKey = `${nid}-${key}`;
|
|
1770
|
+
if (enricher)
|
|
1771
|
+
enricher.call(it, binds, key, value, iterData);
|
|
1772
|
+
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
1773
|
+
if (cachedNode)
|
|
1774
|
+
this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
1775
|
+
else {
|
|
1776
|
+
const dom = this.renderView(view, stack.enter(value, binds, false));
|
|
1777
|
+
this.pushEachEntry(r, nid, attrName, key, dom);
|
|
1778
|
+
this.cache.set(cachePath, cacheKey, dom);
|
|
1774
1779
|
}
|
|
1775
|
-
}
|
|
1780
|
+
};
|
|
1781
|
+
if (keys)
|
|
1782
|
+
imKeysIter(seq, renderOne, keys);
|
|
1783
|
+
else
|
|
1784
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
1785
|
+
if (filter.call(it, key, value, iterData))
|
|
1786
|
+
renderOne(key, value, attrName);
|
|
1787
|
+
}, start, end);
|
|
1776
1788
|
return r;
|
|
1777
1789
|
}
|
|
1778
1790
|
renderView(view, stack) {
|
|
@@ -1808,8 +1820,17 @@ var filterAlwaysTrue = (_v, _k, _seq) => true;
|
|
|
1808
1820
|
var nullLoopWith = (seq) => ({ iterData: { seq } });
|
|
1809
1821
|
var unpackLoopResult = (result, seq) => {
|
|
1810
1822
|
const r = result ?? {};
|
|
1811
|
-
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end };
|
|
1823
|
+
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
|
|
1824
|
+
};
|
|
1825
|
+
var imKeysIter = (seq, visit, keys) => {
|
|
1826
|
+
const attrName = isIndexed(seq) ? "si" : "sk";
|
|
1827
|
+
for (const key of keys)
|
|
1828
|
+
visit(key, seq.get(key), attrName);
|
|
1812
1829
|
};
|
|
1830
|
+
var makeLoopCtx = (stack, filter) => ({
|
|
1831
|
+
lookup: (name) => stack.lookupBind(name),
|
|
1832
|
+
filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
|
|
1833
|
+
});
|
|
1813
1834
|
var imIndexedIter = (seq, visit, start, end) => {
|
|
1814
1835
|
const [s, e] = normalizeRange(start, end, seq.size);
|
|
1815
1836
|
for (let i = s;i < e; i++)
|
|
@@ -2357,11 +2378,11 @@ class IterInfo {
|
|
|
2357
2378
|
return { seq, filter, loopWith, enricher };
|
|
2358
2379
|
}
|
|
2359
2380
|
enrichBinds(stack, key) {
|
|
2360
|
-
const { seq, loopWith, enricher } = this.eval(stack);
|
|
2381
|
+
const { seq, filter, loopWith, enricher } = this.eval(stack);
|
|
2361
2382
|
const value = seq?.get ? seq.get(key, null) : null;
|
|
2362
2383
|
const binds = { key, value };
|
|
2363
2384
|
if (enricher) {
|
|
2364
|
-
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
2385
|
+
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
2365
2386
|
enricher.call(stack.it, binds, key, value, iterData);
|
|
2366
2387
|
}
|
|
2367
2388
|
return binds;
|
|
@@ -3781,6 +3802,13 @@ function phaseOps(phase) {
|
|
|
3781
3802
|
function resolveArgs(args, self) {
|
|
3782
3803
|
return typeof args === "function" ? args(self) ?? [] : args ?? [];
|
|
3783
3804
|
}
|
|
3805
|
+
function phaseHasBubble(phase) {
|
|
3806
|
+
if (!phase)
|
|
3807
|
+
return false;
|
|
3808
|
+
if (phase.bubble?.length)
|
|
3809
|
+
return true;
|
|
3810
|
+
return (phase.do ?? []).some((op) => op.type === "bubble");
|
|
3811
|
+
}
|
|
3784
3812
|
function dispatchPhase(dispatcher, targetPath, phase, self) {
|
|
3785
3813
|
if (!phase)
|
|
3786
3814
|
return;
|
|
@@ -4074,7 +4102,8 @@ class FieldSet extends Field {
|
|
|
4074
4102
|
}
|
|
4075
4103
|
function mkCompField(field, scope, args) {
|
|
4076
4104
|
const Comp = scope?.lookupComponent(field.type) ?? null;
|
|
4077
|
-
|
|
4105
|
+
if (Comp === null)
|
|
4106
|
+
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)`);
|
|
4078
4107
|
return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
|
|
4079
4108
|
}
|
|
4080
4109
|
|
|
@@ -4237,6 +4266,7 @@ export {
|
|
|
4237
4266
|
removeIn,
|
|
4238
4267
|
remove,
|
|
4239
4268
|
phaseOps,
|
|
4269
|
+
phaseHasBubble,
|
|
4240
4270
|
mergeWith,
|
|
4241
4271
|
mergeDeepWith,
|
|
4242
4272
|
mergeDeep,
|
package/dist/tutuca-extra.js
CHANGED
|
@@ -5594,6 +5594,8 @@ class RequestHandler {
|
|
|
5594
5594
|
}
|
|
5595
5595
|
|
|
5596
5596
|
// src/cache.js
|
|
5597
|
+
var isWeakKey = (k) => k !== null && (typeof k === "object" || typeof k === "function");
|
|
5598
|
+
|
|
5597
5599
|
class NullDomCache {
|
|
5598
5600
|
get(_keys, _cacheKey) {}
|
|
5599
5601
|
set(_keys, _cacheKey, _v) {}
|
|
@@ -5637,7 +5639,7 @@ class WeakMapDomCache {
|
|
|
5637
5639
|
const key = keys[i];
|
|
5638
5640
|
let next = cur.get(key);
|
|
5639
5641
|
if (!next) {
|
|
5640
|
-
if (
|
|
5642
|
+
if (!isWeakKey(key)) {
|
|
5641
5643
|
this.badKey += 1;
|
|
5642
5644
|
return;
|
|
5643
5645
|
}
|
|
@@ -5650,7 +5652,7 @@ class WeakMapDomCache {
|
|
|
5650
5652
|
const leaf = cur.get(lastKey);
|
|
5651
5653
|
if (leaf)
|
|
5652
5654
|
leaf[cacheKey] = v;
|
|
5653
|
-
else if (
|
|
5655
|
+
else if (isWeakKey(lastKey))
|
|
5654
5656
|
cur.set(lastKey, { [cacheKey]: v });
|
|
5655
5657
|
else
|
|
5656
5658
|
this.badKey += 1;
|
|
@@ -6112,37 +6114,47 @@ class Renderer {
|
|
|
6112
6114
|
renderEach(stack, iterInfo, node, viewName) {
|
|
6113
6115
|
const { seq, filter, loopWith } = iterInfo.eval(stack);
|
|
6114
6116
|
const r = [];
|
|
6115
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6117
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
6118
|
+
const renderOne = (key, value, attrName) => {
|
|
6119
|
+
const dom = this.renderIt(stack.enter(value, { key }, true), node, key, viewName);
|
|
6120
|
+
this.pushEachEntry(r, node.nodeId, attrName, key, dom);
|
|
6121
|
+
};
|
|
6122
|
+
if (keys)
|
|
6123
|
+
imKeysIter(seq, renderOne, keys);
|
|
6124
|
+
else
|
|
6125
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
6126
|
+
if (filter.call(stack.it, key, value, iterData))
|
|
6127
|
+
renderOne(key, value, attrName);
|
|
6128
|
+
}, start, end);
|
|
6122
6129
|
return r;
|
|
6123
6130
|
}
|
|
6124
6131
|
renderEachWhen(stack, iterInfo, view, nid) {
|
|
6125
6132
|
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
6126
6133
|
const r = [];
|
|
6127
6134
|
const it = stack.it;
|
|
6128
|
-
const { iterData, start, end } = unpackLoopResult(loopWith.call(it, seq), seq);
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
this.cache.set(cachePath, cacheKey, dom);
|
|
6143
|
-
}
|
|
6135
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, makeLoopCtx(stack, filter)), seq);
|
|
6136
|
+
const renderOne = (key, value, attrName) => {
|
|
6137
|
+
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
6138
|
+
const binds = { key, value };
|
|
6139
|
+
const cacheKey = `${nid}-${key}`;
|
|
6140
|
+
if (enricher)
|
|
6141
|
+
enricher.call(it, binds, key, value, iterData);
|
|
6142
|
+
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
6143
|
+
if (cachedNode)
|
|
6144
|
+
this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
6145
|
+
else {
|
|
6146
|
+
const dom = this.renderView(view, stack.enter(value, binds, false));
|
|
6147
|
+
this.pushEachEntry(r, nid, attrName, key, dom);
|
|
6148
|
+
this.cache.set(cachePath, cacheKey, dom);
|
|
6144
6149
|
}
|
|
6145
|
-
}
|
|
6150
|
+
};
|
|
6151
|
+
if (keys)
|
|
6152
|
+
imKeysIter(seq, renderOne, keys);
|
|
6153
|
+
else
|
|
6154
|
+
getSeqInfo(seq)(seq, (key, value, attrName) => {
|
|
6155
|
+
if (filter.call(it, key, value, iterData))
|
|
6156
|
+
renderOne(key, value, attrName);
|
|
6157
|
+
}, start, end);
|
|
6146
6158
|
return r;
|
|
6147
6159
|
}
|
|
6148
6160
|
renderView(view, stack) {
|
|
@@ -6178,8 +6190,17 @@ var filterAlwaysTrue = (_v, _k, _seq) => true;
|
|
|
6178
6190
|
var nullLoopWith = (seq) => ({ iterData: { seq } });
|
|
6179
6191
|
var unpackLoopResult = (result, seq) => {
|
|
6180
6192
|
const r = result ?? {};
|
|
6181
|
-
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end };
|
|
6193
|
+
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
|
|
6194
|
+
};
|
|
6195
|
+
var imKeysIter = (seq, visit, keys) => {
|
|
6196
|
+
const attrName = isIndexed(seq) ? "si" : "sk";
|
|
6197
|
+
for (const key of keys)
|
|
6198
|
+
visit(key, seq.get(key), attrName);
|
|
6182
6199
|
};
|
|
6200
|
+
var makeLoopCtx = (stack, filter) => ({
|
|
6201
|
+
lookup: (name) => stack.lookupBind(name),
|
|
6202
|
+
filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
|
|
6203
|
+
});
|
|
6183
6204
|
var imIndexedIter = (seq, visit, start, end) => {
|
|
6184
6205
|
const [s, e] = normalizeRange(start, end, seq.size);
|
|
6185
6206
|
for (let i = s;i < e; i++)
|
|
@@ -6727,11 +6748,11 @@ class IterInfo {
|
|
|
6727
6748
|
return { seq, filter, loopWith, enricher };
|
|
6728
6749
|
}
|
|
6729
6750
|
enrichBinds(stack, key) {
|
|
6730
|
-
const { seq, loopWith, enricher } = this.eval(stack);
|
|
6751
|
+
const { seq, filter, loopWith, enricher } = this.eval(stack);
|
|
6731
6752
|
const value = seq?.get ? seq.get(key, null) : null;
|
|
6732
6753
|
const binds = { key, value };
|
|
6733
6754
|
if (enricher) {
|
|
6734
|
-
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq), seq);
|
|
6755
|
+
const { iterData } = unpackLoopResult(loopWith.call(stack.it, seq, makeLoopCtx(stack, filter)), seq);
|
|
6735
6756
|
enricher.call(stack.it, binds, key, value, iterData);
|
|
6736
6757
|
}
|
|
6737
6758
|
return binds;
|
|
@@ -8095,6 +8116,13 @@ function phaseOps(phase) {
|
|
|
8095
8116
|
function resolveArgs(args, self) {
|
|
8096
8117
|
return typeof args === "function" ? args(self) ?? [] : args ?? [];
|
|
8097
8118
|
}
|
|
8119
|
+
function phaseHasBubble(phase) {
|
|
8120
|
+
if (!phase)
|
|
8121
|
+
return false;
|
|
8122
|
+
if (phase.bubble?.length)
|
|
8123
|
+
return true;
|
|
8124
|
+
return (phase.do ?? []).some((op) => op.type === "bubble");
|
|
8125
|
+
}
|
|
8098
8126
|
function dispatchPhase(dispatcher, targetPath, phase, self) {
|
|
8099
8127
|
if (!phase)
|
|
8100
8128
|
return;
|
|
@@ -8387,7 +8415,8 @@ class FieldSet extends Field {
|
|
|
8387
8415
|
}
|
|
8388
8416
|
function mkCompField(field, scope, args) {
|
|
8389
8417
|
const Comp = scope?.lookupComponent(field.type) ?? null;
|
|
8390
|
-
|
|
8418
|
+
if (Comp === null)
|
|
8419
|
+
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)`);
|
|
8391
8420
|
return Comp?.make({ ...field.args, ...args }, { scope }) ?? null;
|
|
8392
8421
|
}
|
|
8393
8422
|
|
|
@@ -8550,6 +8579,7 @@ export {
|
|
|
8550
8579
|
removeIn,
|
|
8551
8580
|
remove,
|
|
8552
8581
|
phaseOps,
|
|
8582
|
+
phaseHasBubble,
|
|
8553
8583
|
mergeWith$1 as mergeWith,
|
|
8554
8584
|
mergeDeepWith$1 as mergeDeepWith,
|
|
8555
8585
|
mergeDeep$1 as mergeDeep,
|