tutuca 0.12.0 → 0.13.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 +601 -475
- package/dist/tutuca-components.js +6 -6
- package/dist/tutuca-dev.ext.js +563 -491
- package/dist/tutuca-dev.js +564 -492
- package/dist/tutuca-dev.min.js +4 -4
- package/dist/tutuca-extra.ext.js +470 -410
- package/dist/tutuca-extra.js +470 -410
- package/dist/tutuca-extra.min.js +3 -3
- package/dist/tutuca-storybook.js +4 -4
- package/dist/tutuca.ext.js +470 -410
- package/dist/tutuca.js +470 -410
- package/dist/tutuca.min.js +3 -3
- package/package.json +1 -1
- package/skill/tutuca/advanced.md +56 -7
- package/skill/tutuca/core.md +21 -13
- package/skill/tutuca/messages-and-intents.md +17 -0
- package/skill/tutuca/patterns/edit-through-a-dynamic-target.md +1 -1
- package/skill/tutuca/patterns/handle-events.md +3 -2
- package/skill/tutuca/patterns/share-state-across-the-tree.md +1 -1
- package/skill/tutuca/semantics.md +4 -4
- package/skill/tutuca-source/tutuca.ext.js +470 -410
package/dist/tutuca-extra.ext.js
CHANGED
|
@@ -79,9 +79,6 @@ var Step = class {
|
|
|
79
79
|
lookup(_v, dval = null) {
|
|
80
80
|
return dval;
|
|
81
81
|
}
|
|
82
|
-
setValue(root, _v) {
|
|
83
|
-
return root;
|
|
84
|
-
}
|
|
85
82
|
setDraftValue(_root, _v) {
|
|
86
83
|
}
|
|
87
84
|
enterFrame(stack, _prev, next) {
|
|
@@ -110,9 +107,6 @@ var BindStep = class _BindStep extends Step {
|
|
|
110
107
|
lookup(v, _dval) {
|
|
111
108
|
return v;
|
|
112
109
|
}
|
|
113
|
-
setValue(_root, v) {
|
|
114
|
-
return v;
|
|
115
|
-
}
|
|
116
110
|
enterFrame(stack, _prev, next) {
|
|
117
111
|
return stack.enter(next, { ...this.binds }, false);
|
|
118
112
|
}
|
|
@@ -150,9 +144,6 @@ var FieldStep = class extends Step {
|
|
|
150
144
|
lookup(v, dval = null) {
|
|
151
145
|
return readKey(v, this.field, dval);
|
|
152
146
|
}
|
|
153
|
-
setValue(root, v) {
|
|
154
|
-
return (0, immer_exports.produce)(root, (draft) => this.setDraftValue(draft, v));
|
|
155
|
-
}
|
|
156
147
|
setDraftValue(root, v) {
|
|
157
148
|
writeKey(root, this.field, v);
|
|
158
149
|
}
|
|
@@ -175,9 +166,6 @@ var SeqStep = class extends Step {
|
|
|
175
166
|
lookup(v, dval = null) {
|
|
176
167
|
return readSeqKey(readKey(v, this.field, null), this.key, dval);
|
|
177
168
|
}
|
|
178
|
-
setValue(root, v) {
|
|
179
|
-
return (0, immer_exports.produce)(root, (draft) => this.setDraftValue(draft, v));
|
|
180
|
-
}
|
|
181
169
|
setDraftValue(root, v) {
|
|
182
170
|
const seq = readKey(root, this.field, null);
|
|
183
171
|
if (seq != null) writeSeqKey(seq, this.key, v);
|
|
@@ -200,9 +188,6 @@ var SeqAccessStep = class extends Step {
|
|
|
200
188
|
const key = readKey(v, this.keyField, NONE);
|
|
201
189
|
return key !== NONE && seq !== NONE ? readSeqKey(seq, key, dval) : dval;
|
|
202
190
|
}
|
|
203
|
-
setValue(root, v) {
|
|
204
|
-
return (0, immer_exports.produce)(root, (draft) => this.setDraftValue(draft, v));
|
|
205
|
-
}
|
|
206
191
|
setDraftValue(root, v) {
|
|
207
192
|
const seq = readKey(root, this.seqField, NONE);
|
|
208
193
|
const key = readKey(root, this.keyField, NONE);
|
|
@@ -230,9 +215,6 @@ var EachBindStep = class extends Step {
|
|
|
230
215
|
lookup(v, _dval) {
|
|
231
216
|
return v;
|
|
232
217
|
}
|
|
233
|
-
setValue(_root, v) {
|
|
234
|
-
return v;
|
|
235
|
-
}
|
|
236
218
|
// Replay the renderer's per-item binds (key, value + any @enrich-with binds)
|
|
237
219
|
// so a rebuilt stack matches the one @each rendered with.
|
|
238
220
|
enterFrame(stack, _prev, next) {
|
|
@@ -268,10 +250,6 @@ var DynStep = class extends Step {
|
|
|
268
250
|
warnRawDynStep("lookup", this);
|
|
269
251
|
return dval;
|
|
270
252
|
}
|
|
271
|
-
setValue(root, _v) {
|
|
272
|
-
warnRawDynStep("setValue", this);
|
|
273
|
-
return root;
|
|
274
|
-
}
|
|
275
253
|
enterFrame(stack, _prev, _next) {
|
|
276
254
|
warnRawDynStep("enterFrame", this);
|
|
277
255
|
return stack;
|
|
@@ -342,7 +320,7 @@ var Path = class _Path {
|
|
|
342
320
|
}
|
|
343
321
|
// Resolve every field-keyed step (e.g. `SeqAccessStep`) against `root`, freezing the
|
|
344
322
|
// key as it is *now* so a later lookup/setValue lands on the same item even if the
|
|
345
|
-
// keyField changed meanwhile (e.g. the selected tab moved while
|
|
323
|
+
// keyField changed meanwhile (e.g. the selected tab moved while an intent was in
|
|
346
324
|
// flight). Returns a new Path with those steps replaced; `this` if nothing pinned.
|
|
347
325
|
// Must be called on a transaction path (no DynSteps — call toTransactionPath first).
|
|
348
326
|
pinKeys(root) {
|
|
@@ -584,7 +562,6 @@ var K_FIELD = 4;
|
|
|
584
562
|
var K_BIND = 8;
|
|
585
563
|
var K_DYN = 16;
|
|
586
564
|
var K_NAME = 32;
|
|
587
|
-
var K_TYPE = 64;
|
|
588
565
|
var K_SEQ = 256;
|
|
589
566
|
var K_METHOD = 1024;
|
|
590
567
|
var K_EVENT = 2048;
|
|
@@ -594,7 +571,7 @@ var G_COMPONENT = K_FIELD | K_SEQ | K_DYN;
|
|
|
594
571
|
var G_SEQUENCE = K_FIELD | K_DYN;
|
|
595
572
|
var G_PROVIDE = K_FIELD | K_SEQ;
|
|
596
573
|
var G_FIELD = K_FIELD | K_METHOD | K_CONST | K_SEQ;
|
|
597
|
-
var G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME |
|
|
574
|
+
var G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_CONST;
|
|
598
575
|
var G_HANDLER_ARG = G_VALUE & ~K_NAME | K_EVENT;
|
|
599
576
|
var G_ALL = G_VALUE | K_STRTPL | K_SEQ;
|
|
600
577
|
function sizeOf(v) {
|
|
@@ -664,7 +641,6 @@ function parseToken(s, px) {
|
|
|
664
641
|
if (m !== null) return new EventMemberVal(s.split(".").slice(1));
|
|
665
642
|
}
|
|
666
643
|
if (c0 >= 97 && c0 <= 122) return mkVal(s, NameVal);
|
|
667
|
-
if (c0 >= 65 && c0 <= 90) return mkVal(s, TypeVal);
|
|
668
644
|
return null;
|
|
669
645
|
}
|
|
670
646
|
function _parseSeqAccess(s, px) {
|
|
@@ -779,7 +755,6 @@ function kindOf(val) {
|
|
|
779
755
|
if (val instanceof MethodVal) return K_METHOD;
|
|
780
756
|
if (val instanceof BindVal) return K_BIND;
|
|
781
757
|
if (val instanceof DynVal) return K_DYN;
|
|
782
|
-
if (val instanceof TypeVal) return K_TYPE;
|
|
783
758
|
if (val instanceof NameVal) return K_NAME;
|
|
784
759
|
if (val instanceof EventMemberVal) return K_EVENT;
|
|
785
760
|
return 0;
|
|
@@ -893,9 +868,6 @@ var NameVal = class extends VarVal {
|
|
|
893
868
|
super();
|
|
894
869
|
this.name = name;
|
|
895
870
|
}
|
|
896
|
-
eval(stack) {
|
|
897
|
-
return stack.lookupName(this.name);
|
|
898
|
-
}
|
|
899
871
|
toString() {
|
|
900
872
|
return this.name;
|
|
901
873
|
}
|
|
@@ -916,11 +888,6 @@ var mk404Handler = (stack, type, name) => function(...args) {
|
|
|
916
888
|
else console.warn("handler not found", { type, name });
|
|
917
889
|
return this;
|
|
918
890
|
};
|
|
919
|
-
var TypeVal = class extends NameVal {
|
|
920
|
-
eval(stack) {
|
|
921
|
-
return stack.lookupType(this.name);
|
|
922
|
-
}
|
|
923
|
-
};
|
|
924
891
|
var keyIs = (k) => (e) => e.key === k;
|
|
925
892
|
var macCtrl = (e) => isMac && e.metaKey || e.ctrlKey;
|
|
926
893
|
var nullSafe = (fn) => (e, stack) => {
|
|
@@ -1053,9 +1020,6 @@ var Attributes = class {
|
|
|
1053
1020
|
constructor(items) {
|
|
1054
1021
|
this.items = items;
|
|
1055
1022
|
}
|
|
1056
|
-
eval(_stack) {
|
|
1057
|
-
return {};
|
|
1058
|
-
}
|
|
1059
1023
|
static parse(attributes, px, parseAll = false) {
|
|
1060
1024
|
return getAttrParser(px).parse(attributes, parseAll);
|
|
1061
1025
|
}
|
|
@@ -1065,11 +1029,26 @@ var Attributes = class {
|
|
|
1065
1029
|
};
|
|
1066
1030
|
var booleanAttrsRaw = "itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected";
|
|
1067
1031
|
var booleanAttrs = new Set(booleanAttrsRaw.split(","));
|
|
1032
|
+
function parseDirectiveValue(px, directiveName, source, parser) {
|
|
1033
|
+
const val = parser(source, px);
|
|
1034
|
+
if (val === null) {
|
|
1035
|
+
px.onParseIssue("bad-value", {
|
|
1036
|
+
role: "directive",
|
|
1037
|
+
directive: directiveName,
|
|
1038
|
+
value: source
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
return val;
|
|
1042
|
+
}
|
|
1043
|
+
function parseIterationDirectives(attributes, px) {
|
|
1044
|
+
const parseNamed = (name) => {
|
|
1045
|
+
const attr = attributes.getNamedItem(`@${name}`);
|
|
1046
|
+
return attr ? parseDirectiveValue(px, name, attr.value, parseAlterHandler) : null;
|
|
1047
|
+
};
|
|
1048
|
+
return { whenVal: parseNamed("when"), loopWithVal: parseNamed("loop-with") };
|
|
1049
|
+
}
|
|
1068
1050
|
var AttrParser = class {
|
|
1069
1051
|
constructor(px) {
|
|
1070
|
-
this.clear(px);
|
|
1071
|
-
}
|
|
1072
|
-
clear(px) {
|
|
1073
1052
|
this.px = px;
|
|
1074
1053
|
this.attrs = null;
|
|
1075
1054
|
this.hasDynamic = false;
|
|
@@ -1124,12 +1103,7 @@ var AttrParser = class {
|
|
|
1124
1103
|
}
|
|
1125
1104
|
}
|
|
1126
1105
|
_parseDirectiveValue(directiveName, s, parserFn) {
|
|
1127
|
-
|
|
1128
|
-
if (val === null) {
|
|
1129
|
-
const info = { role: "directive", directive: directiveName, value: s };
|
|
1130
|
-
this.px.onParseIssue("bad-value", info);
|
|
1131
|
-
}
|
|
1132
|
-
return val;
|
|
1106
|
+
return parseDirectiveValue(this.px, directiveName, s, parserFn);
|
|
1133
1107
|
}
|
|
1134
1108
|
parseDirective(s, directiveName) {
|
|
1135
1109
|
switch (directiveName) {
|
|
@@ -1293,11 +1267,8 @@ var IfAttr = class extends BaseAttr {
|
|
|
1293
1267
|
return this.condVal.eval(stack) ? this.thenVal.eval(stack) : this.elseVal.eval(stack);
|
|
1294
1268
|
}
|
|
1295
1269
|
};
|
|
1296
|
-
var _attrParser = null;
|
|
1297
1270
|
function getAttrParser(px) {
|
|
1298
|
-
|
|
1299
|
-
_attrParser.clear(px);
|
|
1300
|
-
return _attrParser;
|
|
1271
|
+
return new AttrParser(px);
|
|
1301
1272
|
}
|
|
1302
1273
|
var EventHandler = class _EventHandler {
|
|
1303
1274
|
constructor(handlerVal, args = []) {
|
|
@@ -1321,70 +1292,77 @@ var IntentHandler = class {
|
|
|
1321
1292
|
}
|
|
1322
1293
|
};
|
|
1323
1294
|
|
|
1324
|
-
// src/
|
|
1325
|
-
var
|
|
1326
|
-
var
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
return { hit: 0, miss: 0, badKey: 0 };
|
|
1333
|
-
}
|
|
1295
|
+
// src/iteration.js
|
|
1296
|
+
var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
|
|
1297
|
+
var normalizeRange = (start, end, size) => {
|
|
1298
|
+
let s = start == null ? 0 : start < 0 ? size + start : start;
|
|
1299
|
+
let e = end == null ? size : end < 0 ? size + end : end;
|
|
1300
|
+
s = s < 0 ? 0 : s > size ? size : s;
|
|
1301
|
+
e = e < 0 ? 0 : e > size ? size : e;
|
|
1302
|
+
return [s, e < s ? s : e];
|
|
1334
1303
|
};
|
|
1335
|
-
var
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
const len = keys.length;
|
|
1347
|
-
let cur = this.keysByLen.get(len);
|
|
1348
|
-
if (!cur) return this._returnValue(void 0);
|
|
1349
|
-
for (let i = 0; i < len - 1; i++) {
|
|
1350
|
-
cur = cur.get(keys[i]);
|
|
1351
|
-
if (!cur) return this._returnValue(void 0);
|
|
1352
|
-
}
|
|
1353
|
-
return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
|
|
1354
|
-
}
|
|
1355
|
-
set(keys, cacheKey, v) {
|
|
1356
|
-
const len = keys.length;
|
|
1357
|
-
let cur = this.keysByLen.get(len);
|
|
1358
|
-
if (!cur) {
|
|
1359
|
-
cur = /* @__PURE__ */ new WeakMap();
|
|
1360
|
-
this.keysByLen.set(len, cur);
|
|
1361
|
-
}
|
|
1362
|
-
for (let i = 0; i < len - 1; i++) {
|
|
1363
|
-
const key = keys[i];
|
|
1364
|
-
let next = cur.get(key);
|
|
1365
|
-
if (!next) {
|
|
1366
|
-
if (!isWeakKey(key)) {
|
|
1367
|
-
this.badKey += 1;
|
|
1368
|
-
return;
|
|
1369
|
-
}
|
|
1370
|
-
next = /* @__PURE__ */ new WeakMap();
|
|
1371
|
-
cur.set(key, next);
|
|
1372
|
-
}
|
|
1373
|
-
cur = next;
|
|
1374
|
-
}
|
|
1375
|
-
const lastKey = keys[len - 1];
|
|
1376
|
-
const leaf = cur.get(lastKey);
|
|
1377
|
-
if (leaf) leaf[cacheKey] = v;
|
|
1378
|
-
else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
|
|
1379
|
-
else this.badKey += 1;
|
|
1380
|
-
}
|
|
1381
|
-
evict() {
|
|
1382
|
-
const { hit, miss, badKey } = this;
|
|
1383
|
-
this.hit = this.miss = this.badKey = 0;
|
|
1384
|
-
this.keysByLen = /* @__PURE__ */ new Map();
|
|
1385
|
-
return { hit, miss, badKey };
|
|
1304
|
+
var nativeIndexedIter = (seq, visit, start, end) => {
|
|
1305
|
+
const [s, e] = normalizeRange(start, end, seqSize(seq));
|
|
1306
|
+
for (let i = s; i < e; i++) visit(i, seq[i], "si");
|
|
1307
|
+
};
|
|
1308
|
+
var nativeKeyedIter = (seq, visit, start, end) => {
|
|
1309
|
+
const [s, e] = normalizeRange(start, end, seqSize(seq));
|
|
1310
|
+
let i = 0;
|
|
1311
|
+
for (const [key, value] of seqEntries(seq)) {
|
|
1312
|
+
if (i >= e) break;
|
|
1313
|
+
if (i >= s) visit(key, value, "sk");
|
|
1314
|
+
i++;
|
|
1386
1315
|
}
|
|
1387
1316
|
};
|
|
1317
|
+
var unknownIter = () => {
|
|
1318
|
+
};
|
|
1319
|
+
var getSeqInfo = (seq) => isIndexedSeq(seq) ? nativeIndexedIter : isKeyedSeq(seq) || isSetSeq(seq) ? nativeKeyedIter : seq?.[SEQ_INFO] ?? unknownIter;
|
|
1320
|
+
var filterAlwaysTrue = (_key, _value, _iterData) => true;
|
|
1321
|
+
var nullLoopWith = (seq) => ({ iterData: { seq } });
|
|
1322
|
+
var unpackLoopResult = (result, seq) => {
|
|
1323
|
+
const value = result ?? {};
|
|
1324
|
+
return {
|
|
1325
|
+
iterData: value.iterData ?? { seq },
|
|
1326
|
+
start: value.start,
|
|
1327
|
+
end: value.end,
|
|
1328
|
+
keys: value.keys
|
|
1329
|
+
};
|
|
1330
|
+
};
|
|
1331
|
+
var makeLoopCtx = (stack, filter) => ({
|
|
1332
|
+
lookup: (name) => stack.lookupBind(name),
|
|
1333
|
+
filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
|
|
1334
|
+
});
|
|
1335
|
+
var callEnricher = (enricher, it, binds, key, value, iterData) => {
|
|
1336
|
+
enricher.call(it, binds, key, value, iterData);
|
|
1337
|
+
console.assert(
|
|
1338
|
+
binds.key === key && binds.value === value,
|
|
1339
|
+
"@enrich-with handlers must not overwrite binds.key or binds.value"
|
|
1340
|
+
);
|
|
1341
|
+
binds.key = key;
|
|
1342
|
+
binds.value = value;
|
|
1343
|
+
};
|
|
1344
|
+
var visitKeys = (seq, keys, visit) => {
|
|
1345
|
+
const attrName = isIndexedSeq(seq) ? "si" : "sk";
|
|
1346
|
+
for (const key of keys) visit(key, seqGet(seq, key), attrName);
|
|
1347
|
+
};
|
|
1348
|
+
function walkLoopBindings({ seq, it, filter, loopWith, enricher, ctx }, visit) {
|
|
1349
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, ctx), seq);
|
|
1350
|
+
const visitOne = (key, value, attrName) => {
|
|
1351
|
+
const binds = { key, value };
|
|
1352
|
+
if (enricher) callEnricher(enricher, it, binds, key, value, iterData);
|
|
1353
|
+
visit(key, value, attrName, binds);
|
|
1354
|
+
};
|
|
1355
|
+
if (keys) visitKeys(seq, keys, visitOne);
|
|
1356
|
+
else
|
|
1357
|
+
getSeqInfo(seq)(
|
|
1358
|
+
seq,
|
|
1359
|
+
(key, value, attrName) => {
|
|
1360
|
+
if (filter.call(it, key, value, iterData)) visitOne(key, value, attrName);
|
|
1361
|
+
},
|
|
1362
|
+
start,
|
|
1363
|
+
end
|
|
1364
|
+
);
|
|
1365
|
+
}
|
|
1388
1366
|
|
|
1389
1367
|
// src/vdom.js
|
|
1390
1368
|
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
@@ -1729,189 +1707,11 @@ function h(tagName, properties, children, namespace) {
|
|
|
1729
1707
|
return new VNode(tag, props, normalizedChildren, key, namespace);
|
|
1730
1708
|
}
|
|
1731
1709
|
|
|
1732
|
-
// src/renderer.js
|
|
1733
|
-
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
|
|
1734
|
-
var Renderer = class {
|
|
1735
|
-
constructor(comps) {
|
|
1736
|
-
this.comps = comps;
|
|
1737
|
-
this.cache = new WeakMapDomCache();
|
|
1738
|
-
this.renderTag = h;
|
|
1739
|
-
}
|
|
1740
|
-
renderFragment(childs) {
|
|
1741
|
-
return new VFragment(childs);
|
|
1742
|
-
}
|
|
1743
|
-
renderComment(text) {
|
|
1744
|
-
return new VComment(text);
|
|
1745
|
-
}
|
|
1746
|
-
setNullCache() {
|
|
1747
|
-
this.cache = new NullDomCache();
|
|
1748
|
-
}
|
|
1749
|
-
renderToDOM(stack, val) {
|
|
1750
|
-
const rootNode = document.createElement("div");
|
|
1751
|
-
const rOpts = { document };
|
|
1752
|
-
render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
|
|
1753
|
-
return rootNode.childNodes[0];
|
|
1754
|
-
}
|
|
1755
|
-
renderToString(stack, val, cleanAttrs = true) {
|
|
1756
|
-
const dom = this.renderToDOM(stack, val);
|
|
1757
|
-
if (cleanAttrs) {
|
|
1758
|
-
const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
|
|
1759
|
-
for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
|
|
1760
|
-
}
|
|
1761
|
-
return dom.innerHTML;
|
|
1762
|
-
}
|
|
1763
|
-
renderRoot(stack, val, viewName = null) {
|
|
1764
|
-
const comp = this.comps.getCompFor(val);
|
|
1765
|
-
if (comp === null) return null;
|
|
1766
|
-
return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
|
|
1767
|
-
}
|
|
1768
|
-
renderIt(stack, node, key, viewName) {
|
|
1769
|
-
const comp = this.comps.getCompFor(stack.it);
|
|
1770
|
-
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
|
|
1771
|
-
}
|
|
1772
|
-
// `node` is the parse node of the render site (`<x render>` / `render-it` /
|
|
1773
|
-
// `render-each`, or the view's root anode for the app root). It keys the
|
|
1774
|
-
// cache as a globally-unique object: node ids alone are unique only within a
|
|
1775
|
-
// single view, so the same value rendered by two components (e.g. through a
|
|
1776
|
-
// shared dynamic-var sequence) would otherwise collide in the cache.
|
|
1777
|
-
_rValComp(stack, val, comp, node, key, viewName) {
|
|
1778
|
-
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
|
|
1779
|
-
const cachePath = [node, val];
|
|
1780
|
-
stack._pushDynBindValuesToArray(cachePath, comp);
|
|
1781
|
-
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
1782
|
-
if (cachedNode) return cachedNode;
|
|
1783
|
-
const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
|
|
1784
|
-
const body = this.renderView(view, stack);
|
|
1785
|
-
if (body == null) return null;
|
|
1786
|
-
const meta = this._renderMetadata({
|
|
1787
|
-
$: "Comp",
|
|
1788
|
-
nid: node?.nodeId ?? null,
|
|
1789
|
-
cid: comp.id,
|
|
1790
|
-
vid: view.name
|
|
1791
|
-
});
|
|
1792
|
-
const dom = new VFragment([meta, body]);
|
|
1793
|
-
this.cache.set(cachePath, cacheKey, dom);
|
|
1794
|
-
return dom;
|
|
1795
|
-
}
|
|
1796
|
-
pushEachEntry(r, nid, attrName, key, dom) {
|
|
1797
|
-
r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
|
|
1798
|
-
}
|
|
1799
|
-
renderEachWhen(stack, iterInfo, view, nid) {
|
|
1800
|
-
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
1801
|
-
const r = [];
|
|
1802
|
-
const it = stack.it;
|
|
1803
|
-
const { iterData, start, end, keys } = unpackLoopResult(
|
|
1804
|
-
loopWith.call(it, seq, makeLoopCtx(stack, filter)),
|
|
1805
|
-
seq
|
|
1806
|
-
);
|
|
1807
|
-
const renderOne = (key, value, attrName) => {
|
|
1808
|
-
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
1809
|
-
const binds = { key, value };
|
|
1810
|
-
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
|
|
1811
|
-
if (enricher) callEnricher(enricher, it, binds, key, value, iterData);
|
|
1812
|
-
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
1813
|
-
if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
1814
|
-
else {
|
|
1815
|
-
const dom = this.renderView(view, stack.enter(value, binds, false));
|
|
1816
|
-
if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
|
|
1817
|
-
this.cache.set(cachePath, cacheKey, dom);
|
|
1818
|
-
}
|
|
1819
|
-
};
|
|
1820
|
-
if (keys) keysIter(seq, renderOne, keys);
|
|
1821
|
-
else
|
|
1822
|
-
getSeqInfo(seq)(
|
|
1823
|
-
seq,
|
|
1824
|
-
(key, value, attrName) => {
|
|
1825
|
-
if (filter.call(it, key, value, iterData)) renderOne(key, value, attrName);
|
|
1826
|
-
},
|
|
1827
|
-
start,
|
|
1828
|
-
end
|
|
1829
|
-
);
|
|
1830
|
-
return r;
|
|
1831
|
-
}
|
|
1832
|
-
renderView(view, stack) {
|
|
1833
|
-
let n = stack.binds[1];
|
|
1834
|
-
while (n !== null) {
|
|
1835
|
-
const b = n[0];
|
|
1836
|
-
if (b.isFrame) {
|
|
1837
|
-
if (stack.it !== b.it) break;
|
|
1838
|
-
console.error("recursion detected", stack.it, b.it);
|
|
1839
|
-
return new VComment("RECURSION AVOIDED");
|
|
1840
|
-
}
|
|
1841
|
-
n = n[1];
|
|
1842
|
-
}
|
|
1843
|
-
return view.render(stack, this);
|
|
1844
|
-
}
|
|
1845
|
-
_renderMetadata(info) {
|
|
1846
|
-
return new VComment(`§${JSON.stringify(info)}§`);
|
|
1847
|
-
}
|
|
1848
|
-
// Prefix a loop-less @enrich-with subtree with a boundary meta so event-path
|
|
1849
|
-
// reconstruction replays its binds (mirrors the §Each§ / §Comp§ metas).
|
|
1850
|
-
renderScopeMeta(nid, dom) {
|
|
1851
|
-
return new VFragment([this._renderMetadata({ $: "Scope", nid }), dom]);
|
|
1852
|
-
}
|
|
1853
|
-
};
|
|
1854
|
-
var getSeqInfo = (seq) => isIndexedSeq(seq) ? nativeIndexedIter : isKeyedSeq(seq) || isSetSeq(seq) ? nativeKeyedIter : seq?.[SEQ_INFO] ?? unkIter;
|
|
1855
|
-
var normalizeRange = (start, end, size) => {
|
|
1856
|
-
let s = start == null ? 0 : start < 0 ? size + start : start;
|
|
1857
|
-
let e = end == null ? size : end < 0 ? size + end : end;
|
|
1858
|
-
s = s < 0 ? 0 : s > size ? size : s;
|
|
1859
|
-
e = e < 0 ? 0 : e > size ? size : e;
|
|
1860
|
-
return [s, e < s ? s : e];
|
|
1861
|
-
};
|
|
1862
|
-
var callEnricher = (enricher, it, binds, key, value, iterData) => {
|
|
1863
|
-
enricher.call(it, binds, key, value, iterData);
|
|
1864
|
-
console.assert(
|
|
1865
|
-
binds.key === key && binds.value === value,
|
|
1866
|
-
"@enrich-with handlers must not overwrite binds.key or binds.value"
|
|
1867
|
-
);
|
|
1868
|
-
binds.key = key;
|
|
1869
|
-
binds.value = value;
|
|
1870
|
-
};
|
|
1871
|
-
var filterAlwaysTrue = (_v, _k, _seq) => true;
|
|
1872
|
-
var nullLoopWith = (seq) => ({ iterData: { seq } });
|
|
1873
|
-
var unpackLoopResult = (result, seq) => {
|
|
1874
|
-
const r = result ?? {};
|
|
1875
|
-
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
|
|
1876
|
-
};
|
|
1877
|
-
var keysIter = (seq, visit, keys) => {
|
|
1878
|
-
const attrName = isIndexedSeq(seq) ? "si" : "sk";
|
|
1879
|
-
for (const key of keys) visit(key, seqGet(seq, key), attrName);
|
|
1880
|
-
};
|
|
1881
|
-
var makeLoopCtx = (stack, filter) => ({
|
|
1882
|
-
lookup: (name) => stack.lookupBind(name),
|
|
1883
|
-
filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
|
|
1884
|
-
});
|
|
1885
|
-
var nativeIndexedIter = (seq, visit, start, end) => {
|
|
1886
|
-
const [s, e] = normalizeRange(start, end, seqSize(seq));
|
|
1887
|
-
for (let i = s; i < e; i++) visit(i, seq[i], "si");
|
|
1888
|
-
};
|
|
1889
|
-
var nativeKeyedIter = (seq, visit, start, end) => {
|
|
1890
|
-
const [s, e] = normalizeRange(start, end, seqSize(seq));
|
|
1891
|
-
let i = 0;
|
|
1892
|
-
for (const [k, v] of seqEntries(seq)) {
|
|
1893
|
-
if (i >= e) break;
|
|
1894
|
-
if (i >= s) visit(k, v, "sk");
|
|
1895
|
-
i++;
|
|
1896
|
-
}
|
|
1897
|
-
};
|
|
1898
|
-
var unkIter = () => {
|
|
1899
|
-
};
|
|
1900
|
-
var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
|
|
1901
|
-
|
|
1902
1710
|
// src/anode.js
|
|
1903
1711
|
function resolveDynProducer(comp, name) {
|
|
1904
|
-
|
|
1905
|
-
const
|
|
1906
|
-
|
|
1907
|
-
producerComp = comp.scope?.lookupComponent(lk.compName);
|
|
1908
|
-
producerProvide = producerComp?.provide?.[lk.provideName];
|
|
1909
|
-
} else {
|
|
1910
|
-
const p = comp?.provide?.[name];
|
|
1911
|
-
if (p == null) return null;
|
|
1912
|
-
producerComp = comp;
|
|
1913
|
-
producerProvide = p;
|
|
1914
|
-
}
|
|
1712
|
+
const own = comp?.provide?.[name];
|
|
1713
|
+
const producerComp = own != null ? comp : comp?.scope?.lookupProvider(name) ?? null;
|
|
1714
|
+
const producerProvide = own ?? producerComp?.provide?.[name];
|
|
1915
1715
|
if (producerComp == null || producerProvide == null) return null;
|
|
1916
1716
|
const pi = producerProvide.val?.toPathItem?.() ?? null;
|
|
1917
1717
|
return { producerCompId: producerComp.id, producerSteps: pi ? [pi] : [] };
|
|
@@ -2272,16 +2072,10 @@ function parseRenderEach(px, value, as, attrs) {
|
|
|
2272
2072
|
const seqVal = parseXOpVal("render-each", value, px, parseSequence);
|
|
2273
2073
|
if (seqVal === null) return null;
|
|
2274
2074
|
const renderIt = px.addNode(RenderItNode, as);
|
|
2275
|
-
const
|
|
2276
|
-
const eachAttr = attrParser.pushWrapper("each", value, seqVal);
|
|
2277
|
-
attrParser.eachAttr = eachAttr;
|
|
2278
|
-
const when = attrs.getNamedItem("@when");
|
|
2279
|
-
if (when) attrParser._parseWhen(when.value);
|
|
2280
|
-
const lWith = attrs.getNamedItem("@loop-with");
|
|
2281
|
-
if (lWith) attrParser._parseLoopWith(lWith.value);
|
|
2075
|
+
const { whenVal, loopWithVal } = parseIterationDirectives(attrs, px);
|
|
2282
2076
|
const each = px.addNodeIf(EachNode, seqVal);
|
|
2283
|
-
each.iterInfo.whenVal =
|
|
2284
|
-
each.iterInfo.loopWithVal =
|
|
2077
|
+
each.iterInfo.whenVal = whenVal;
|
|
2078
|
+
each.iterInfo.loopWithVal = loopWithVal;
|
|
2285
2079
|
each.fromRenderEach = true;
|
|
2286
2080
|
each.wrapNode(renderIt);
|
|
2287
2081
|
return each;
|
|
@@ -2670,7 +2464,7 @@ var Components = class {
|
|
|
2670
2464
|
}
|
|
2671
2465
|
compileStyles() {
|
|
2672
2466
|
const styles = [];
|
|
2673
|
-
for (const
|
|
2467
|
+
for (const Comp of this.byId.values()) styles.push(Comp[COMPONENT].compileStyle());
|
|
2674
2468
|
return styles.join("\n");
|
|
2675
2469
|
}
|
|
2676
2470
|
};
|
|
@@ -2729,32 +2523,39 @@ var ComponentStack = class _ComponentStack {
|
|
|
2729
2523
|
lookupComponent(name) {
|
|
2730
2524
|
return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
|
|
2731
2525
|
}
|
|
2526
|
+
// The component in this scope chain that provides `name`, innermost first. A lookup
|
|
2527
|
+
// names a value without naming its producer, so the render-target teleport
|
|
2528
|
+
// (resolveDynProducer) recovers the producer here instead. Sound because
|
|
2529
|
+
// PROVIDE_NAME_COLLISION keeps a provide name to one producer per chain; with two,
|
|
2530
|
+
// this returns the innermost and the linter has already reported the ambiguity.
|
|
2531
|
+
lookupProvider(name) {
|
|
2532
|
+
for (const compName in this.byName) {
|
|
2533
|
+
const Comp = this.byName[compName];
|
|
2534
|
+
if (Comp.provide?.[name] !== void 0) return Comp;
|
|
2535
|
+
}
|
|
2536
|
+
return this.parent?.lookupProvider(name) ?? null;
|
|
2537
|
+
}
|
|
2732
2538
|
lookupMacro(name) {
|
|
2733
2539
|
return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
|
|
2734
2540
|
}
|
|
2735
2541
|
};
|
|
2736
2542
|
var ProvideInfo = class {
|
|
2737
|
-
constructor(name, val
|
|
2543
|
+
constructor(name, val) {
|
|
2738
2544
|
this.name = name;
|
|
2739
2545
|
this.val = val;
|
|
2740
|
-
this.symbol = symbol;
|
|
2741
2546
|
}
|
|
2742
2547
|
};
|
|
2743
2548
|
var LookupInfo = class {
|
|
2744
|
-
constructor(name,
|
|
2549
|
+
constructor(name, val) {
|
|
2745
2550
|
this.name = name;
|
|
2746
|
-
this.compName = compName;
|
|
2747
|
-
this.provideName = provideName;
|
|
2748
2551
|
this.val = val;
|
|
2749
|
-
this._sym = void 0;
|
|
2750
|
-
}
|
|
2751
|
-
getProducerSymbol(stack) {
|
|
2752
|
-
if (this._sym === void 0)
|
|
2753
|
-
this._sym = stack.lookupType(this.compName)?.provide?.[this.provideName]?.symbol ?? null;
|
|
2754
|
-
return this._sym;
|
|
2755
2552
|
}
|
|
2756
2553
|
};
|
|
2757
2554
|
var isString = (v) => typeof v === "string";
|
|
2555
|
+
var isTypeName = (s) => {
|
|
2556
|
+
const c = s.charCodeAt(0);
|
|
2557
|
+
return c >= 65 && c <= 90;
|
|
2558
|
+
};
|
|
2758
2559
|
var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
|
|
2759
2560
|
var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
|
|
2760
2561
|
var _compId = 0;
|
|
@@ -2775,8 +2576,9 @@ var Component = class {
|
|
|
2775
2576
|
this.views[name] = new View(name, view, style);
|
|
2776
2577
|
}
|
|
2777
2578
|
this._rawProvide = o.provide ?? {};
|
|
2778
|
-
this._rawLookup = o.lookup ??
|
|
2579
|
+
this._rawLookup = o.lookup ?? [];
|
|
2779
2580
|
this.provide = {};
|
|
2581
|
+
this.provideType = {};
|
|
2780
2582
|
this.lookup = {};
|
|
2781
2583
|
this.scope = null;
|
|
2782
2584
|
this.spec = o;
|
|
@@ -2788,25 +2590,23 @@ var Component = class {
|
|
|
2788
2590
|
this.views[name].compile(new ParseContext2(), this.scope, this.id);
|
|
2789
2591
|
const ctx = this.views.main.ctx;
|
|
2790
2592
|
for (const key in this._rawProvide) {
|
|
2593
|
+
if (isTypeName(key)) {
|
|
2594
|
+
if (this._rawProvide[key] === "self") this.provideType[key] = this.Class;
|
|
2595
|
+
continue;
|
|
2596
|
+
}
|
|
2791
2597
|
const val = parseProvide(this._rawProvide[key], ctx);
|
|
2792
|
-
if (val) this.provide[key] = new ProvideInfo(key, val
|
|
2598
|
+
if (val) this.provide[key] = new ProvideInfo(key, val);
|
|
2793
2599
|
}
|
|
2794
|
-
for (const
|
|
2795
|
-
const
|
|
2796
|
-
|
|
2797
|
-
const
|
|
2798
|
-
|
|
2799
|
-
const defStr = isString(linfo?.default) ? linfo.default : null;
|
|
2800
|
-
const val = defStr === null ? null : parseField(defStr, ctx);
|
|
2801
|
-
this.lookup[key] = new LookupInfo(key, compName, provideName, val);
|
|
2600
|
+
for (const entry of this._rawLookup) {
|
|
2601
|
+
const name = isString(entry) ? entry : isString(entry?.name) ? entry.name : null;
|
|
2602
|
+
if (name === null) continue;
|
|
2603
|
+
const defStr = isString(entry?.default) ? entry.default : null;
|
|
2604
|
+
this.lookup[name] = new LookupInfo(name, defStr === null ? null : parseField(defStr, ctx));
|
|
2802
2605
|
}
|
|
2803
2606
|
for (const key in this.lookup)
|
|
2804
2607
|
if (this.provide[key] !== void 0)
|
|
2805
2608
|
console.warn("name declared in both provide and lookup", this.name, key);
|
|
2806
2609
|
}
|
|
2807
|
-
make(args, opts) {
|
|
2808
|
-
return this.Class.make(args, opts ?? { scope: this.scope });
|
|
2809
|
-
}
|
|
2810
2610
|
getView(name) {
|
|
2811
2611
|
return this.views[name] ?? this.views.main;
|
|
2812
2612
|
}
|
|
@@ -2831,6 +2631,22 @@ var Component = class {
|
|
|
2831
2631
|
// src/stack.js
|
|
2832
2632
|
var STOP = /* @__PURE__ */ Symbol("STOP");
|
|
2833
2633
|
var NEXT = /* @__PURE__ */ Symbol("NEXT");
|
|
2634
|
+
var DEFAULT_LOOKUP_ROUTE = ["dyn", "lex"];
|
|
2635
|
+
function routeLookup(route, lex, dyn) {
|
|
2636
|
+
for (let i = 0; i < route.length; i++) {
|
|
2637
|
+
const leg = route[i];
|
|
2638
|
+
if (leg === "dyn") {
|
|
2639
|
+
const v = dyn();
|
|
2640
|
+
if (v != null) return v;
|
|
2641
|
+
} else if (leg === "lex") {
|
|
2642
|
+
const v = lex();
|
|
2643
|
+
if (v != null) return v;
|
|
2644
|
+
} else {
|
|
2645
|
+
console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
|
|
2646
|
+
}
|
|
2647
|
+
}
|
|
2648
|
+
return null;
|
|
2649
|
+
}
|
|
2834
2650
|
function lookup(chain, name, dv = null) {
|
|
2835
2651
|
let n = chain;
|
|
2836
2652
|
while (n !== null) {
|
|
@@ -2881,14 +2697,21 @@ var Stack = class _Stack {
|
|
|
2881
2697
|
this.ctx = ctx;
|
|
2882
2698
|
}
|
|
2883
2699
|
// Evaluate every provide the entered component publishes and push them as one
|
|
2884
|
-
// dynBinds frame
|
|
2700
|
+
// dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
|
|
2701
|
+
// starts A-Z and a value name does not, so the two namespaces cannot collide and
|
|
2702
|
+
// nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
|
|
2885
2703
|
_pushProvides() {
|
|
2886
|
-
const
|
|
2887
|
-
if (
|
|
2704
|
+
const comp = this.comps.getCompFor(this.it);
|
|
2705
|
+
if (comp == null) return this;
|
|
2706
|
+
const { provide, provideType } = comp;
|
|
2888
2707
|
const dynObj = {};
|
|
2889
2708
|
let has = false;
|
|
2890
2709
|
for (const k in provide) {
|
|
2891
|
-
dynObj[
|
|
2710
|
+
dynObj[k] = provide[k].val.eval(this);
|
|
2711
|
+
has = true;
|
|
2712
|
+
}
|
|
2713
|
+
for (const k in provideType) {
|
|
2714
|
+
dynObj[k] = provideType[k];
|
|
2892
2715
|
has = true;
|
|
2893
2716
|
}
|
|
2894
2717
|
if (!has) return this;
|
|
@@ -2913,30 +2736,36 @@ var Stack = class _Stack {
|
|
|
2913
2736
|
const newViews = [name, views];
|
|
2914
2737
|
return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
|
|
2915
2738
|
}
|
|
2739
|
+
// Published types are stable per scope and would only churn the render cache, so
|
|
2740
|
+
// the cache key covers values alone.
|
|
2916
2741
|
_pushDynBindValuesToArray(arr, comp) {
|
|
2917
|
-
for (const k in comp.provide) arr.push(this.
|
|
2918
|
-
for (const k in comp.lookup) arr.push(this.
|
|
2919
|
-
}
|
|
2920
|
-
_lookupProvide(p) {
|
|
2921
|
-
return lookup(this.dynBinds, p.symbol) ?? p.val.eval(this) ?? null;
|
|
2922
|
-
}
|
|
2923
|
-
_lookupAlias(lk) {
|
|
2924
|
-
const sym = lk.getProducerSymbol(this);
|
|
2925
|
-
return (sym != null ? lookup(this.dynBinds, sym) : null) ?? lk.val?.eval(this) ?? null;
|
|
2742
|
+
for (const k in comp.provide) arr.push(this.lookupDynamic(k));
|
|
2743
|
+
for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
|
|
2926
2744
|
}
|
|
2745
|
+
// `*name`: the nearest binding above (including this component's own provides,
|
|
2746
|
+
// pushed on entering it), else this component's declared default, else null.
|
|
2927
2747
|
lookupDynamic(name) {
|
|
2748
|
+
const v = lookup(this.dynBinds, name);
|
|
2749
|
+
if (v != null) return v;
|
|
2928
2750
|
const comp = this.comps.getCompFor(this.it);
|
|
2929
|
-
|
|
2930
|
-
const lk = comp.lookup[name];
|
|
2931
|
-
if (lk !== void 0) return this._lookupAlias(lk);
|
|
2932
|
-
const p = comp.provide[name];
|
|
2933
|
-
return p !== void 0 ? this._lookupProvide(p) : null;
|
|
2751
|
+
return comp?.lookup[name]?.val?.eval(this) ?? null;
|
|
2934
2752
|
}
|
|
2935
2753
|
lookupBind(name) {
|
|
2936
2754
|
return lookup(this.binds, name);
|
|
2937
2755
|
}
|
|
2938
|
-
|
|
2939
|
-
|
|
2756
|
+
// The `lex` leg: what a name means in the registration scope of the component being
|
|
2757
|
+
// rendered. The scope chain holds components, so this leg only ever answers for a
|
|
2758
|
+
// type name — for a value name it is a miss, which is why one default route serves
|
|
2759
|
+
// both. Guarded: a non-component `it` has no scope to ask.
|
|
2760
|
+
_lookupLex(name) {
|
|
2761
|
+
return this.comps.getCompFor(this.it)?.scope.lookupComponent(name) ?? null;
|
|
2762
|
+
}
|
|
2763
|
+
lookupRouted(name, route = DEFAULT_LOOKUP_ROUTE) {
|
|
2764
|
+
return routeLookup(
|
|
2765
|
+
route,
|
|
2766
|
+
() => this._lookupLex(name),
|
|
2767
|
+
() => this.lookupDynamic(name)
|
|
2768
|
+
);
|
|
2940
2769
|
}
|
|
2941
2770
|
lookupFieldRaw(name) {
|
|
2942
2771
|
return this.it[name] ?? null;
|
|
@@ -2945,12 +2774,6 @@ var Stack = class _Stack {
|
|
|
2945
2774
|
const fn = this.it[name];
|
|
2946
2775
|
return fn instanceof Function ? fn.call(this.it) : null;
|
|
2947
2776
|
}
|
|
2948
|
-
// Bare implicit event names are gone: a sigil-less word cannot reach a
|
|
2949
|
-
// handler-arg slot anymore, so this only ever serves stale NameVals parsed
|
|
2950
|
-
// before the removal (e.g. macro-attr pass-throughs). Always null.
|
|
2951
|
-
lookupName(_name) {
|
|
2952
|
-
return null;
|
|
2953
|
-
}
|
|
2954
2777
|
// The dispatched DOM event / drag info, read only by EventMemberVal's
|
|
2955
2778
|
// `e.<member>` handler args. Null outside a live event transaction.
|
|
2956
2779
|
lookupEvent() {
|
|
@@ -2976,11 +2799,6 @@ var Stack = class _Stack {
|
|
|
2976
2799
|
// src/oo.js
|
|
2977
2800
|
var BAD_VALUE = /* @__PURE__ */ Symbol("BadValue");
|
|
2978
2801
|
var nullCoercer = (v) => v;
|
|
2979
|
-
var isPlainObject2 = (v) => {
|
|
2980
|
-
if (v === null || typeof v !== "object") return false;
|
|
2981
|
-
const proto = Object.getPrototypeOf(v);
|
|
2982
|
-
return proto === Object.prototype || proto === null;
|
|
2983
|
-
};
|
|
2984
2802
|
function defaultToData(v) {
|
|
2985
2803
|
if (v instanceof Map) return [...v.entries()];
|
|
2986
2804
|
if (v instanceof Set) return [...v.values()];
|
|
@@ -3049,7 +2867,7 @@ var CHECK_TYPE_FLOAT = check(Number.isFinite, "Float expected");
|
|
|
3049
2867
|
var CHECK_TYPE_BOOL = check((v) => typeof v === "boolean", "Boolean expected");
|
|
3050
2868
|
var CHECK_TYPE_STRING = check((v) => typeof v === "string", "String expected");
|
|
3051
2869
|
var CHECK_TYPE_LIST = check(Array.isArray, "Array expected");
|
|
3052
|
-
var CHECK_TYPE_OBJECT = check(
|
|
2870
|
+
var CHECK_TYPE_OBJECT = check(isPlainObject, "Plain object expected");
|
|
3053
2871
|
var CHECK_TYPE_MAP = check((v) => v instanceof Map, "Map expected");
|
|
3054
2872
|
var CHECK_TYPE_SET = check((v) => v instanceof Set, "Set expected");
|
|
3055
2873
|
var FieldBool = class extends Field {
|
|
@@ -3118,7 +2936,7 @@ var FieldObject = class extends Field {
|
|
|
3118
2936
|
"object",
|
|
3119
2937
|
name,
|
|
3120
2938
|
CHECK_TYPE_OBJECT,
|
|
3121
|
-
(v) =>
|
|
2939
|
+
(v) => isPlainObject(v) ? { ...v } : null,
|
|
3122
2940
|
defaultValue
|
|
3123
2941
|
);
|
|
3124
2942
|
}
|
|
@@ -3131,7 +2949,7 @@ var FieldMap = class extends Field {
|
|
|
3131
2949
|
CHECK_TYPE_MAP,
|
|
3132
2950
|
(v) => {
|
|
3133
2951
|
if (v instanceof Map) return new Map(v);
|
|
3134
|
-
if (Array.isArray(v) ||
|
|
2952
|
+
if (Array.isArray(v) || isPlainObject(v))
|
|
3135
2953
|
return new Map(Array.isArray(v) ? v : Object.entries(v));
|
|
3136
2954
|
return null;
|
|
3137
2955
|
},
|
|
@@ -3256,7 +3074,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
|
|
|
3256
3074
|
b.addField(field, dval, FieldCls);
|
|
3257
3075
|
} else if (value?.component && value?.args !== void 0)
|
|
3258
3076
|
b.addCompField(field, value.component, value.args);
|
|
3259
|
-
else if (
|
|
3077
|
+
else if (isPlainObject(value)) b.addField(field, { ...value }, FieldObject);
|
|
3260
3078
|
else {
|
|
3261
3079
|
const FieldCls = value?.[FIELD_CLASS] ?? FieldAny;
|
|
3262
3080
|
b.addField(field, value, FieldCls);
|
|
@@ -3280,10 +3098,24 @@ function validateDraftFields(current, draft) {
|
|
|
3280
3098
|
}
|
|
3281
3099
|
}
|
|
3282
3100
|
}
|
|
3283
|
-
var META_KEYS = "name id fields methods views receive intent alter provide lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
|
|
3101
|
+
var META_KEYS = "name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
|
|
3284
3102
|
" "
|
|
3285
3103
|
);
|
|
3104
|
+
var RESERVED_COMPONENT_STATICS = /* @__PURE__ */ new Set([
|
|
3105
|
+
...META_KEYS,
|
|
3106
|
+
"make",
|
|
3107
|
+
"getMetaClass",
|
|
3108
|
+
...Object.getOwnPropertyNames(Component.prototype)
|
|
3109
|
+
]);
|
|
3110
|
+
function assertNoReservedComponentStatics(statics = {}) {
|
|
3111
|
+
for (const name in statics) {
|
|
3112
|
+
if (RESERVED_COMPONENT_STATICS.has(name)) {
|
|
3113
|
+
throw new TypeError(`component static "${name}" is reserved by the framework`);
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3286
3117
|
Component.fromSpec = (opts) => {
|
|
3118
|
+
assertNoReservedComponentStatics(opts.statics);
|
|
3287
3119
|
const Class = classFromData(opts.name, opts);
|
|
3288
3120
|
const comp = new Component(Class, opts);
|
|
3289
3121
|
const metaClass = Class.getMetaClass();
|
|
@@ -3303,7 +3135,7 @@ Component.fromSpec = (opts) => {
|
|
|
3303
3135
|
configurable: true
|
|
3304
3136
|
});
|
|
3305
3137
|
for (const key of Object.getOwnPropertyNames(Component.prototype))
|
|
3306
|
-
if (key !== "constructor" &&
|
|
3138
|
+
if (key !== "constructor" && !Object.hasOwn(Class, key))
|
|
3307
3139
|
Class[key] = (...args) => comp[key](...args);
|
|
3308
3140
|
return Class;
|
|
3309
3141
|
};
|
|
@@ -3323,9 +3155,6 @@ var State = class {
|
|
|
3323
3155
|
this.val = val;
|
|
3324
3156
|
for (const sub of this.changeSubs) sub({ val, old, info, timestamp: Date.now() });
|
|
3325
3157
|
}
|
|
3326
|
-
update(fn, info) {
|
|
3327
|
-
return this.set(fn(this.val), info);
|
|
3328
|
-
}
|
|
3329
3158
|
};
|
|
3330
3159
|
var Transactor = class {
|
|
3331
3160
|
constructor(comps, rootValue) {
|
|
@@ -3386,7 +3215,7 @@ var Transactor = class {
|
|
|
3386
3215
|
// Build and dispatch the observer record for a settled transaction. The
|
|
3387
3216
|
// resolved handler (`_resolvedHandler`/`_matched`) and per-leaf before/after
|
|
3388
3217
|
// (`_before`/`_after`) were captured while the handler ran (see callHandler /
|
|
3389
|
-
//
|
|
3218
|
+
// Transaction.run). No-op when nobody is observing.
|
|
3390
3219
|
_emitTransaction(transaction, root) {
|
|
3391
3220
|
if (this._observers.length === 0) return;
|
|
3392
3221
|
if (transaction._resolvedHandler === void 0) return;
|
|
@@ -3418,8 +3247,13 @@ var Transactor = class {
|
|
|
3418
3247
|
}
|
|
3419
3248
|
return child;
|
|
3420
3249
|
}
|
|
3421
|
-
|
|
3422
|
-
|
|
3250
|
+
// `origin` is where the message came FROM, pinned now for the same reason an
|
|
3251
|
+
// intent's answerPath is: a reply must reach the sender that asked even if a key
|
|
3252
|
+
// moved while the message was in flight. Null when nobody is waiting — a host
|
|
3253
|
+
// sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
|
|
3254
|
+
pushSend(path, name, args = [], parent = null, origin = null) {
|
|
3255
|
+
const t = new SendEvent(path, this, name, args, parent);
|
|
3256
|
+
t.origin = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
|
|
3423
3257
|
this.pushTransaction(t);
|
|
3424
3258
|
return this._link(t, parent);
|
|
3425
3259
|
}
|
|
@@ -3432,9 +3266,9 @@ var Transactor = class {
|
|
|
3432
3266
|
walk.advance();
|
|
3433
3267
|
return walk;
|
|
3434
3268
|
}
|
|
3435
|
-
// Drain queued transactions and await
|
|
3436
|
-
//
|
|
3437
|
-
//
|
|
3269
|
+
// Drain queued transactions and await async intent handlers until quiescent. A
|
|
3270
|
+
// completed handler may enqueue an answer, which may dispatch more work, so we loop.
|
|
3271
|
+
// `maxTurns` backstops a pathological non-terminating cascade.
|
|
3438
3272
|
async settle(maxTurns = 1e4) {
|
|
3439
3273
|
while ((this.hasPendingTransactions || this._inflight.size) && maxTurns-- > 0) {
|
|
3440
3274
|
while (this.hasPendingTransactions) this.transactNext();
|
|
@@ -3491,9 +3325,6 @@ var Transaction = class {
|
|
|
3491
3325
|
whenSubtreeSettled() {
|
|
3492
3326
|
return this.completion.whenSubtreeSettled();
|
|
3493
3327
|
}
|
|
3494
|
-
run(rootValue, comps) {
|
|
3495
|
-
return this.updateRootValue(rootValue, comps);
|
|
3496
|
-
}
|
|
3497
3328
|
afterTransaction() {
|
|
3498
3329
|
}
|
|
3499
3330
|
// Ending a walk and forwarding belong to the two dispatch buckets; the base warns
|
|
@@ -3505,12 +3336,6 @@ var Transaction = class {
|
|
|
3505
3336
|
forward(_opts) {
|
|
3506
3337
|
console.warn('ctx.forward() needs a "receive" or "intent" handler - ignored');
|
|
3507
3338
|
}
|
|
3508
|
-
buildRootStack(root, comps) {
|
|
3509
|
-
return Stack.root(comps, root);
|
|
3510
|
-
}
|
|
3511
|
-
buildStack(root, comps) {
|
|
3512
|
-
return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
|
|
3513
|
-
}
|
|
3514
3339
|
// The kind reported to observers (see Transactor.observe); null on the base.
|
|
3515
3340
|
get observeKind() {
|
|
3516
3341
|
return null;
|
|
@@ -3530,12 +3355,11 @@ var Transaction = class {
|
|
|
3530
3355
|
return null;
|
|
3531
3356
|
}
|
|
3532
3357
|
// The path used to apply the mutation. Teleports dynamic-var renders so it lands on
|
|
3533
|
-
// the data's real location (the dispatch `this.path` keeps intermediates).
|
|
3534
|
-
// may override to supply a pre-resolved path (see ResponseEvent's pinned keys).
|
|
3358
|
+
// the data's real location (the dispatch `this.path` keeps intermediates).
|
|
3535
3359
|
getTransactionPath() {
|
|
3536
3360
|
return this.path.toTransactionPath().compact();
|
|
3537
3361
|
}
|
|
3538
|
-
|
|
3362
|
+
run(curRoot, comps) {
|
|
3539
3363
|
const txnPath = this.getTransactionPath();
|
|
3540
3364
|
const curLeaf = txnPath.lookup(curRoot);
|
|
3541
3365
|
const newLeaf = (0, immer_exports.produce)(curLeaf, (draft) => {
|
|
@@ -3592,8 +3416,8 @@ var InputEvent = class extends Transaction {
|
|
|
3592
3416
|
}
|
|
3593
3417
|
this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
|
|
3594
3418
|
}
|
|
3595
|
-
|
|
3596
|
-
return Stack.root(comps, root, this);
|
|
3419
|
+
buildStack(root, comps) {
|
|
3420
|
+
return this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
|
|
3597
3421
|
}
|
|
3598
3422
|
getHandlerAndArgs(root, _instance, comps) {
|
|
3599
3423
|
const stack = this.buildStack(root, comps);
|
|
@@ -3611,11 +3435,10 @@ var InputEvent = class extends Transaction {
|
|
|
3611
3435
|
}
|
|
3612
3436
|
};
|
|
3613
3437
|
var NameArgsTransaction = class extends Transaction {
|
|
3614
|
-
constructor(path, transactor, name, args, parentTransaction
|
|
3438
|
+
constructor(path, transactor, name, args, parentTransaction) {
|
|
3615
3439
|
super(path, transactor, parentTransaction);
|
|
3616
3440
|
this.name = name;
|
|
3617
3441
|
this.args = args;
|
|
3618
|
-
this.opts = opts;
|
|
3619
3442
|
this.targetPath = path;
|
|
3620
3443
|
}
|
|
3621
3444
|
handlerProp = null;
|
|
@@ -3674,7 +3497,7 @@ var SendEvent = class extends NameArgsTransaction {
|
|
|
3674
3497
|
var IntentEvent = class extends NameArgsTransaction {
|
|
3675
3498
|
handlerProp = "intent";
|
|
3676
3499
|
constructor(path, transactor, walk) {
|
|
3677
|
-
super(path, transactor, walk.name, walk.args, walk.parent
|
|
3500
|
+
super(path, transactor, walk.name, walk.args, walk.parent);
|
|
3678
3501
|
this.walk = walk;
|
|
3679
3502
|
this.targetPath = walk.origin;
|
|
3680
3503
|
}
|
|
@@ -3774,7 +3597,7 @@ var IntentWalk = class {
|
|
|
3774
3597
|
async _runLex(chain, i) {
|
|
3775
3598
|
if (this.ended) return;
|
|
3776
3599
|
if (i >= chain.length) return this.advance();
|
|
3777
|
-
const ctx = new
|
|
3600
|
+
const ctx = new Dispatcher(this.origin, this.transactor, this.parent);
|
|
3778
3601
|
try {
|
|
3779
3602
|
const res = await chain[i].fn.apply(null, [...this.args, ctx]);
|
|
3780
3603
|
if (res === PASS) return this._runLex(chain, i + 1);
|
|
@@ -3827,7 +3650,7 @@ var IntentWalk = class {
|
|
|
3827
3650
|
this.ended = true;
|
|
3828
3651
|
if (name === null) return this.release?.();
|
|
3829
3652
|
const path = this.answerPath ?? this.origin;
|
|
3830
|
-
const t = new SendEvent(path, this.transactor, name, args, this.parent
|
|
3653
|
+
const t = new SendEvent(path, this.transactor, name, args, this.parent);
|
|
3831
3654
|
t._isAnswer = true;
|
|
3832
3655
|
this.transactor.pushTransaction(t);
|
|
3833
3656
|
if (this.release) t.completion.whenSubtreeSettled().then(this.release);
|
|
@@ -3866,7 +3689,7 @@ var Completion = class {
|
|
|
3866
3689
|
this.val = val;
|
|
3867
3690
|
this._selfResolve?.(val);
|
|
3868
3691
|
}
|
|
3869
|
-
// Settle self even when no handler produced a value (
|
|
3692
|
+
// Settle self even when no handler produced a value (undefined-state / throw paths).
|
|
3870
3693
|
ensureSelfSettled() {
|
|
3871
3694
|
if (!this.selfSettled) this.markSelfSettled(this.val);
|
|
3872
3695
|
}
|
|
@@ -3912,12 +3735,64 @@ var Dispatcher = class {
|
|
|
3912
3735
|
get at() {
|
|
3913
3736
|
return new PathChanges(this);
|
|
3914
3737
|
}
|
|
3738
|
+
// The render-time Stack, rebuilt on demand. A handler does not get one: the stack
|
|
3739
|
+
// that evaluated its arguments is a local in getHandlerAndArgs and is gone by the
|
|
3740
|
+
// time the body runs, and send/intent transactions never build one at all. Both
|
|
3741
|
+
// halves it needs are pinned on this ctx, so the `dyn` leg reconstructs it — and
|
|
3742
|
+
// only the `dyn` leg does, which is why this is lazy rather than eager.
|
|
3743
|
+
//
|
|
3744
|
+
// The path is compacted, so per-item binds (`@each`, `@enrich-with`) are not
|
|
3745
|
+
// replayed; provides are pushed on every component frame either way, so a provide
|
|
3746
|
+
// that reads a loop binding is the one case this cannot reproduce faithfully.
|
|
3747
|
+
_stack() {
|
|
3748
|
+
this._stackMemo ??= this.path.toTransactionPath().buildStack(Stack.root(this.transactor.comps, this.root, this.parent));
|
|
3749
|
+
return this._stackMemo;
|
|
3750
|
+
}
|
|
3751
|
+
// Resolve a name the way the renderer would. `opts.route` takes the same legs in
|
|
3752
|
+
// the same spelling as `ctx.intent` — `["dyn"]` the render ancestry, `["lex"]` the
|
|
3753
|
+
// registration scope, default both.
|
|
3754
|
+
lookup(name, opts) {
|
|
3755
|
+
const route = opts?.route ?? DEFAULT_LOOKUP_ROUTE;
|
|
3756
|
+
return routeLookup(
|
|
3757
|
+
route,
|
|
3758
|
+
() => this._lookupLex(name),
|
|
3759
|
+
() => this._stack()?.lookupDynamic(name) ?? null
|
|
3760
|
+
);
|
|
3761
|
+
}
|
|
3762
|
+
// The `lex` leg without a Stack: the scope of the component whose handler is
|
|
3763
|
+
// running, which is the leaf of this ctx's path.
|
|
3764
|
+
_lookupLex(name) {
|
|
3765
|
+
let Comp = null;
|
|
3766
|
+
this.walkPath((c) => {
|
|
3767
|
+
Comp = c;
|
|
3768
|
+
return false;
|
|
3769
|
+
});
|
|
3770
|
+
return Comp?.scope?.lookupComponent(name) ?? null;
|
|
3771
|
+
}
|
|
3772
|
+
// A component lookup is a value lookup constrained to a component. The `lex` leg
|
|
3773
|
+
// can only ever answer with one; the `dyn` leg reads a binding an ancestor
|
|
3774
|
+
// published, so it is the leg that has to be checked.
|
|
3775
|
+
lookupType(name, opts) {
|
|
3776
|
+
const v = this.lookup(name, opts);
|
|
3777
|
+
if (v == null) {
|
|
3778
|
+
this.transactor.refuse("TYPE_NOT_FOUND", {
|
|
3779
|
+
name,
|
|
3780
|
+
route: opts?.route ?? DEFAULT_LOOKUP_ROUTE
|
|
3781
|
+
});
|
|
3782
|
+
return null;
|
|
3783
|
+
}
|
|
3784
|
+
if (v?.[COMPONENT] == null) {
|
|
3785
|
+
this.transactor.refuse("TYPE_NOT_COMPONENT", { name, got: typeof v });
|
|
3786
|
+
return null;
|
|
3787
|
+
}
|
|
3788
|
+
return v;
|
|
3789
|
+
}
|
|
3915
3790
|
// A message is ADDRESSED: it names one component and stops there.
|
|
3916
|
-
send(name, args
|
|
3917
|
-
return this.sendAtPath(this.path, name, args
|
|
3791
|
+
send(name, args) {
|
|
3792
|
+
return this.sendAtPath(this.path, name, args);
|
|
3918
3793
|
}
|
|
3919
|
-
sendAtPath(path, name, args
|
|
3920
|
-
return this.transactor.pushSend(path, name, args,
|
|
3794
|
+
sendAtPath(path, name, args) {
|
|
3795
|
+
return this.transactor.pushSend(path, name, args, this.parent, this.path);
|
|
3921
3796
|
}
|
|
3922
3797
|
// An intent is ROUTED: it names a job and walks until something answers. The verb
|
|
3923
3798
|
// does not decide which scope answers — `opts.route` does, written here at the call
|
|
@@ -3928,9 +3803,6 @@ var Dispatcher = class {
|
|
|
3928
3803
|
intentAtPath(path, name, args, opts) {
|
|
3929
3804
|
return this.transactor.pushIntent(path, name, args, opts, this.parent);
|
|
3930
3805
|
}
|
|
3931
|
-
lookupTypeFor(name, inst) {
|
|
3932
|
-
return this.transactor.comps.getCompFor(inst).scope.lookupComponent(name);
|
|
3933
|
-
}
|
|
3934
3806
|
};
|
|
3935
3807
|
var EventContext = class extends Dispatcher {
|
|
3936
3808
|
get name() {
|
|
@@ -3947,6 +3819,19 @@ var EventContext = class extends Dispatcher {
|
|
|
3947
3819
|
fail(error) {
|
|
3948
3820
|
return this.parent.walk === void 0 ? warnNotIntent("fail") : this.parent.walk.answer("Error", error);
|
|
3949
3821
|
}
|
|
3822
|
+
// Reply to the sender of the MESSAGE being handled. An intent answers under a name
|
|
3823
|
+
// the runtime derives (`<name>Ok`), because the raiser asked a question and declared
|
|
3824
|
+
// arms for it; a message did not, so the replier names the reply itself and the
|
|
3825
|
+
// sender handles it like any other message. Refuses when nobody sent this — a view's
|
|
3826
|
+
// own `@on.*`, or a host sendAtRoot.
|
|
3827
|
+
sendReply(name, args) {
|
|
3828
|
+
const origin = this.parent?.origin ?? null;
|
|
3829
|
+
if (origin == null) {
|
|
3830
|
+
this.transactor.refuse("NO_SENDER", { name });
|
|
3831
|
+
return null;
|
|
3832
|
+
}
|
|
3833
|
+
return this.sendAtPath(origin, name, args);
|
|
3834
|
+
}
|
|
3950
3835
|
// End the walk answering nothing — "served, and no answer".
|
|
3951
3836
|
stop() {
|
|
3952
3837
|
return this.parent.stop();
|
|
@@ -3958,8 +3843,6 @@ var EventContext = class extends Dispatcher {
|
|
|
3958
3843
|
return this.parent.forward(opts);
|
|
3959
3844
|
}
|
|
3960
3845
|
};
|
|
3961
|
-
var IntentContext = class extends Dispatcher {
|
|
3962
|
-
};
|
|
3963
3846
|
function warnNotIntent(verb) {
|
|
3964
3847
|
console.warn(`ctx.${verb}() is only meaningful in an "intent" handler - ignored`);
|
|
3965
3848
|
}
|
|
@@ -3968,8 +3851,8 @@ var PathChanges = class extends PathBuilder {
|
|
|
3968
3851
|
super();
|
|
3969
3852
|
this.dispatcher = dispatcher;
|
|
3970
3853
|
}
|
|
3971
|
-
send(name, args
|
|
3972
|
-
return this.dispatcher.sendAtPath(this.buildPath(), name, args
|
|
3854
|
+
send(name, args) {
|
|
3855
|
+
return this.dispatcher.sendAtPath(this.buildPath(), name, args);
|
|
3973
3856
|
}
|
|
3974
3857
|
intent(name, args, opts) {
|
|
3975
3858
|
return this.dispatcher.intentAtPath(this.buildPath(), name, args, opts);
|
|
@@ -4126,9 +4009,10 @@ var App = class {
|
|
|
4126
4009
|
}
|
|
4127
4010
|
compile() {
|
|
4128
4011
|
for (const Comp of this.comps.byId.values()) {
|
|
4129
|
-
Comp
|
|
4130
|
-
|
|
4131
|
-
|
|
4012
|
+
const meta = Comp[COMPONENT];
|
|
4013
|
+
meta.compile(this.ParseContext);
|
|
4014
|
+
for (const key in meta.views)
|
|
4015
|
+
for (const name of meta.views[key].ctx.genEventNames()) this._eventNames.add(name);
|
|
4132
4016
|
}
|
|
4133
4017
|
this._compiled = true;
|
|
4134
4018
|
}
|
|
@@ -4154,8 +4038,8 @@ var App = class {
|
|
|
4154
4038
|
for (const name of this._eventNames)
|
|
4155
4039
|
this.rootNode.removeEventListener(name, this, listenerOpts(name));
|
|
4156
4040
|
}
|
|
4157
|
-
sendAtRoot(name, args
|
|
4158
|
-
this.transactor.pushSend(new Path([]), name, args
|
|
4041
|
+
sendAtRoot(name, args) {
|
|
4042
|
+
this.transactor.pushSend(new Path([]), name, args);
|
|
4159
4043
|
}
|
|
4160
4044
|
registerComponents(comps, opts) {
|
|
4161
4045
|
const scope = this.compStack.enter();
|
|
@@ -4309,6 +4193,182 @@ function collectAppClassesInSet(app) {
|
|
|
4309
4193
|
return classes;
|
|
4310
4194
|
}
|
|
4311
4195
|
|
|
4196
|
+
// src/cache.js
|
|
4197
|
+
var isWeakKey = (k) => k !== null && (typeof k === "object" || typeof k === "function");
|
|
4198
|
+
var NullDomCache = class {
|
|
4199
|
+
get(_keys, _cacheKey) {
|
|
4200
|
+
}
|
|
4201
|
+
set(_keys, _cacheKey, _v) {
|
|
4202
|
+
}
|
|
4203
|
+
evict() {
|
|
4204
|
+
return { hit: 0, miss: 0, badKey: 0 };
|
|
4205
|
+
}
|
|
4206
|
+
};
|
|
4207
|
+
var WeakMapDomCache = class {
|
|
4208
|
+
constructor() {
|
|
4209
|
+
this.hit = this.miss = this.badKey = 0;
|
|
4210
|
+
this.keysByLen = /* @__PURE__ */ new Map();
|
|
4211
|
+
}
|
|
4212
|
+
_returnValue(r) {
|
|
4213
|
+
if (r === void 0) this.miss += 1;
|
|
4214
|
+
else this.hit += 1;
|
|
4215
|
+
return r;
|
|
4216
|
+
}
|
|
4217
|
+
get(keys, cacheKey) {
|
|
4218
|
+
const len = keys.length;
|
|
4219
|
+
let cur = this.keysByLen.get(len);
|
|
4220
|
+
if (!cur) return this._returnValue(void 0);
|
|
4221
|
+
for (let i = 0; i < len - 1; i++) {
|
|
4222
|
+
cur = cur.get(keys[i]);
|
|
4223
|
+
if (!cur) return this._returnValue(void 0);
|
|
4224
|
+
}
|
|
4225
|
+
return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
|
|
4226
|
+
}
|
|
4227
|
+
set(keys, cacheKey, v) {
|
|
4228
|
+
const len = keys.length;
|
|
4229
|
+
let cur = this.keysByLen.get(len);
|
|
4230
|
+
if (!cur) {
|
|
4231
|
+
cur = /* @__PURE__ */ new WeakMap();
|
|
4232
|
+
this.keysByLen.set(len, cur);
|
|
4233
|
+
}
|
|
4234
|
+
for (let i = 0; i < len - 1; i++) {
|
|
4235
|
+
const key = keys[i];
|
|
4236
|
+
let next = cur.get(key);
|
|
4237
|
+
if (!next) {
|
|
4238
|
+
if (!isWeakKey(key)) {
|
|
4239
|
+
this.badKey += 1;
|
|
4240
|
+
return;
|
|
4241
|
+
}
|
|
4242
|
+
next = /* @__PURE__ */ new WeakMap();
|
|
4243
|
+
cur.set(key, next);
|
|
4244
|
+
}
|
|
4245
|
+
cur = next;
|
|
4246
|
+
}
|
|
4247
|
+
const lastKey = keys[len - 1];
|
|
4248
|
+
const leaf = cur.get(lastKey);
|
|
4249
|
+
if (leaf) leaf[cacheKey] = v;
|
|
4250
|
+
else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
|
|
4251
|
+
else this.badKey += 1;
|
|
4252
|
+
}
|
|
4253
|
+
evict() {
|
|
4254
|
+
const { hit, miss, badKey } = this;
|
|
4255
|
+
this.hit = this.miss = this.badKey = 0;
|
|
4256
|
+
this.keysByLen = /* @__PURE__ */ new Map();
|
|
4257
|
+
return { hit, miss, badKey };
|
|
4258
|
+
}
|
|
4259
|
+
};
|
|
4260
|
+
|
|
4261
|
+
// src/renderer.js
|
|
4262
|
+
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
|
|
4263
|
+
var Renderer = class {
|
|
4264
|
+
constructor(comps) {
|
|
4265
|
+
this.comps = comps;
|
|
4266
|
+
this.cache = new WeakMapDomCache();
|
|
4267
|
+
this.renderTag = h;
|
|
4268
|
+
}
|
|
4269
|
+
renderFragment(childs) {
|
|
4270
|
+
return new VFragment(childs);
|
|
4271
|
+
}
|
|
4272
|
+
renderComment(text) {
|
|
4273
|
+
return new VComment(text);
|
|
4274
|
+
}
|
|
4275
|
+
setNullCache() {
|
|
4276
|
+
this.cache = new NullDomCache();
|
|
4277
|
+
}
|
|
4278
|
+
renderToDOM(stack, val) {
|
|
4279
|
+
const rootNode = document.createElement("div");
|
|
4280
|
+
const rOpts = { document };
|
|
4281
|
+
render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
|
|
4282
|
+
return rootNode.childNodes[0];
|
|
4283
|
+
}
|
|
4284
|
+
renderToString(stack, val, cleanAttrs = true) {
|
|
4285
|
+
const dom = this.renderToDOM(stack, val);
|
|
4286
|
+
if (cleanAttrs) {
|
|
4287
|
+
const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
|
|
4288
|
+
for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
|
|
4289
|
+
}
|
|
4290
|
+
return dom.innerHTML;
|
|
4291
|
+
}
|
|
4292
|
+
renderRoot(stack, val, viewName = null) {
|
|
4293
|
+
const comp = this.comps.getCompFor(val);
|
|
4294
|
+
if (comp === null) return null;
|
|
4295
|
+
return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
|
|
4296
|
+
}
|
|
4297
|
+
renderIt(stack, node, key, viewName) {
|
|
4298
|
+
const comp = this.comps.getCompFor(stack.it);
|
|
4299
|
+
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
|
|
4300
|
+
}
|
|
4301
|
+
// `node` is the parse node of the render site (`<x render>` / `render-it` /
|
|
4302
|
+
// `render-each`, or the view's root anode for the app root). It keys the
|
|
4303
|
+
// cache as a globally-unique object: node ids alone are unique only within a
|
|
4304
|
+
// single view, so the same value rendered by two components (e.g. through a
|
|
4305
|
+
// shared dynamic-var sequence) would otherwise collide in the cache.
|
|
4306
|
+
_rValComp(stack, val, comp, node, key, viewName) {
|
|
4307
|
+
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
|
|
4308
|
+
const cachePath = [node, val];
|
|
4309
|
+
stack._pushDynBindValuesToArray(cachePath, comp);
|
|
4310
|
+
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
4311
|
+
if (cachedNode) return cachedNode;
|
|
4312
|
+
const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
|
|
4313
|
+
const body = this.renderView(view, stack);
|
|
4314
|
+
if (body == null) return null;
|
|
4315
|
+
const meta = this._renderMetadata({
|
|
4316
|
+
$: "Comp",
|
|
4317
|
+
nid: node?.nodeId ?? null,
|
|
4318
|
+
cid: comp.id,
|
|
4319
|
+
vid: view.name
|
|
4320
|
+
});
|
|
4321
|
+
const dom = new VFragment([meta, body]);
|
|
4322
|
+
this.cache.set(cachePath, cacheKey, dom);
|
|
4323
|
+
return dom;
|
|
4324
|
+
}
|
|
4325
|
+
pushEachEntry(r, nid, attrName, key, dom) {
|
|
4326
|
+
r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
|
|
4327
|
+
}
|
|
4328
|
+
renderEachWhen(stack, iterInfo, view, nid) {
|
|
4329
|
+
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
4330
|
+
const r = [];
|
|
4331
|
+
const it = stack.it;
|
|
4332
|
+
const renderOne = (key, value, attrName, binds) => {
|
|
4333
|
+
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
4334
|
+
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
|
|
4335
|
+
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
4336
|
+
if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
4337
|
+
else {
|
|
4338
|
+
const dom = this.renderView(view, stack.enter(value, binds, false));
|
|
4339
|
+
if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
|
|
4340
|
+
this.cache.set(cachePath, cacheKey, dom);
|
|
4341
|
+
}
|
|
4342
|
+
};
|
|
4343
|
+
walkLoopBindings(
|
|
4344
|
+
{ seq, it, filter, loopWith, enricher, ctx: makeLoopCtx(stack, filter) },
|
|
4345
|
+
renderOne
|
|
4346
|
+
);
|
|
4347
|
+
return r;
|
|
4348
|
+
}
|
|
4349
|
+
renderView(view, stack) {
|
|
4350
|
+
let n = stack.binds[1];
|
|
4351
|
+
while (n !== null) {
|
|
4352
|
+
const b = n[0];
|
|
4353
|
+
if (b.isFrame) {
|
|
4354
|
+
if (stack.it !== b.it) break;
|
|
4355
|
+
console.error("recursion detected", stack.it, b.it);
|
|
4356
|
+
return new VComment("RECURSION AVOIDED");
|
|
4357
|
+
}
|
|
4358
|
+
n = n[1];
|
|
4359
|
+
}
|
|
4360
|
+
return view.render(stack, this);
|
|
4361
|
+
}
|
|
4362
|
+
_renderMetadata(info) {
|
|
4363
|
+
return new VComment(`§${JSON.stringify(info)}§`);
|
|
4364
|
+
}
|
|
4365
|
+
// Prefix a loop-less @enrich-with subtree with a boundary meta so event-path
|
|
4366
|
+
// reconstruction replays its binds (mirrors the §Each§ / §Comp§ metas).
|
|
4367
|
+
renderScopeMeta(nid, dom) {
|
|
4368
|
+
return new VFragment([this._renderMetadata({ $: "Scope", nid }), dom]);
|
|
4369
|
+
}
|
|
4370
|
+
};
|
|
4371
|
+
|
|
4312
4372
|
// src/on.js
|
|
4313
4373
|
var OP_KINDS = ["send", "intent"];
|
|
4314
4374
|
function phaseOps(phase) {
|
|
@@ -4326,7 +4386,7 @@ function dispatchPhase(dispatcher, targetPath, phase, self) {
|
|
|
4326
4386
|
const args = resolveArgs(op.args, self);
|
|
4327
4387
|
switch (op.type) {
|
|
4328
4388
|
case "send":
|
|
4329
|
-
dispatcher.sendAtPath(targetPath, op.name, args
|
|
4389
|
+
dispatcher.sendAtPath(targetPath, op.name, args);
|
|
4330
4390
|
break;
|
|
4331
4391
|
case "intent":
|
|
4332
4392
|
dispatcher.intentAtPath(targetPath, op.name, args, op.opts);
|