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.js
CHANGED
|
@@ -782,9 +782,6 @@ var Step = class {
|
|
|
782
782
|
lookup(_v, dval = null) {
|
|
783
783
|
return dval;
|
|
784
784
|
}
|
|
785
|
-
setValue(root, _v) {
|
|
786
|
-
return root;
|
|
787
|
-
}
|
|
788
785
|
setDraftValue(_root, _v) {
|
|
789
786
|
}
|
|
790
787
|
enterFrame(stack, _prev, next) {
|
|
@@ -813,9 +810,6 @@ var BindStep = class _BindStep extends Step {
|
|
|
813
810
|
lookup(v, _dval) {
|
|
814
811
|
return v;
|
|
815
812
|
}
|
|
816
|
-
setValue(_root, v) {
|
|
817
|
-
return v;
|
|
818
|
-
}
|
|
819
813
|
enterFrame(stack, _prev, next) {
|
|
820
814
|
return stack.enter(next, { ...this.binds }, false);
|
|
821
815
|
}
|
|
@@ -853,9 +847,6 @@ var FieldStep = class extends Step {
|
|
|
853
847
|
lookup(v, dval = null) {
|
|
854
848
|
return readKey(v, this.field, dval);
|
|
855
849
|
}
|
|
856
|
-
setValue(root, v) {
|
|
857
|
-
return produce(root, (draft) => this.setDraftValue(draft, v));
|
|
858
|
-
}
|
|
859
850
|
setDraftValue(root, v) {
|
|
860
851
|
writeKey(root, this.field, v);
|
|
861
852
|
}
|
|
@@ -878,9 +869,6 @@ var SeqStep = class extends Step {
|
|
|
878
869
|
lookup(v, dval = null) {
|
|
879
870
|
return readSeqKey(readKey(v, this.field, null), this.key, dval);
|
|
880
871
|
}
|
|
881
|
-
setValue(root, v) {
|
|
882
|
-
return produce(root, (draft) => this.setDraftValue(draft, v));
|
|
883
|
-
}
|
|
884
872
|
setDraftValue(root, v) {
|
|
885
873
|
const seq = readKey(root, this.field, null);
|
|
886
874
|
if (seq != null) writeSeqKey(seq, this.key, v);
|
|
@@ -903,9 +891,6 @@ var SeqAccessStep = class extends Step {
|
|
|
903
891
|
const key = readKey(v, this.keyField, NONE);
|
|
904
892
|
return key !== NONE && seq !== NONE ? readSeqKey(seq, key, dval) : dval;
|
|
905
893
|
}
|
|
906
|
-
setValue(root, v) {
|
|
907
|
-
return produce(root, (draft) => this.setDraftValue(draft, v));
|
|
908
|
-
}
|
|
909
894
|
setDraftValue(root, v) {
|
|
910
895
|
const seq = readKey(root, this.seqField, NONE);
|
|
911
896
|
const key = readKey(root, this.keyField, NONE);
|
|
@@ -933,9 +918,6 @@ var EachBindStep = class extends Step {
|
|
|
933
918
|
lookup(v, _dval) {
|
|
934
919
|
return v;
|
|
935
920
|
}
|
|
936
|
-
setValue(_root, v) {
|
|
937
|
-
return v;
|
|
938
|
-
}
|
|
939
921
|
// Replay the renderer's per-item binds (key, value + any @enrich-with binds)
|
|
940
922
|
// so a rebuilt stack matches the one @each rendered with.
|
|
941
923
|
enterFrame(stack, _prev, next) {
|
|
@@ -971,10 +953,6 @@ var DynStep = class extends Step {
|
|
|
971
953
|
warnRawDynStep("lookup", this);
|
|
972
954
|
return dval;
|
|
973
955
|
}
|
|
974
|
-
setValue(root, _v) {
|
|
975
|
-
warnRawDynStep("setValue", this);
|
|
976
|
-
return root;
|
|
977
|
-
}
|
|
978
956
|
enterFrame(stack, _prev, _next) {
|
|
979
957
|
warnRawDynStep("enterFrame", this);
|
|
980
958
|
return stack;
|
|
@@ -1045,7 +1023,7 @@ var Path = class _Path {
|
|
|
1045
1023
|
}
|
|
1046
1024
|
// Resolve every field-keyed step (e.g. `SeqAccessStep`) against `root`, freezing the
|
|
1047
1025
|
// key as it is *now* so a later lookup/setValue lands on the same item even if the
|
|
1048
|
-
// keyField changed meanwhile (e.g. the selected tab moved while
|
|
1026
|
+
// keyField changed meanwhile (e.g. the selected tab moved while an intent was in
|
|
1049
1027
|
// flight). Returns a new Path with those steps replaced; `this` if nothing pinned.
|
|
1050
1028
|
// Must be called on a transaction path (no DynSteps — call toTransactionPath first).
|
|
1051
1029
|
pinKeys(root) {
|
|
@@ -1287,7 +1265,6 @@ var K_FIELD = 4;
|
|
|
1287
1265
|
var K_BIND = 8;
|
|
1288
1266
|
var K_DYN = 16;
|
|
1289
1267
|
var K_NAME = 32;
|
|
1290
|
-
var K_TYPE = 64;
|
|
1291
1268
|
var K_SEQ = 256;
|
|
1292
1269
|
var K_METHOD = 1024;
|
|
1293
1270
|
var K_EVENT = 2048;
|
|
@@ -1297,7 +1274,7 @@ var G_COMPONENT = K_FIELD | K_SEQ | K_DYN;
|
|
|
1297
1274
|
var G_SEQUENCE = K_FIELD | K_DYN;
|
|
1298
1275
|
var G_PROVIDE = K_FIELD | K_SEQ;
|
|
1299
1276
|
var G_FIELD = K_FIELD | K_METHOD | K_CONST | K_SEQ;
|
|
1300
|
-
var G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME |
|
|
1277
|
+
var G_VALUE = K_FIELD | K_METHOD | K_BIND | K_DYN | K_NAME | K_CONST;
|
|
1301
1278
|
var G_HANDLER_ARG = G_VALUE & ~K_NAME | K_EVENT;
|
|
1302
1279
|
var G_ALL = G_VALUE | K_STRTPL | K_SEQ;
|
|
1303
1280
|
function sizeOf(v) {
|
|
@@ -1367,7 +1344,6 @@ function parseToken(s, px) {
|
|
|
1367
1344
|
if (m !== null) return new EventMemberVal(s.split(".").slice(1));
|
|
1368
1345
|
}
|
|
1369
1346
|
if (c0 >= 97 && c0 <= 122) return mkVal(s, NameVal);
|
|
1370
|
-
if (c0 >= 65 && c0 <= 90) return mkVal(s, TypeVal);
|
|
1371
1347
|
return null;
|
|
1372
1348
|
}
|
|
1373
1349
|
function _parseSeqAccess(s, px) {
|
|
@@ -1482,7 +1458,6 @@ function kindOf(val) {
|
|
|
1482
1458
|
if (val instanceof MethodVal) return K_METHOD;
|
|
1483
1459
|
if (val instanceof BindVal) return K_BIND;
|
|
1484
1460
|
if (val instanceof DynVal) return K_DYN;
|
|
1485
|
-
if (val instanceof TypeVal) return K_TYPE;
|
|
1486
1461
|
if (val instanceof NameVal) return K_NAME;
|
|
1487
1462
|
if (val instanceof EventMemberVal) return K_EVENT;
|
|
1488
1463
|
return 0;
|
|
@@ -1596,9 +1571,6 @@ var NameVal = class extends VarVal {
|
|
|
1596
1571
|
super();
|
|
1597
1572
|
this.name = name;
|
|
1598
1573
|
}
|
|
1599
|
-
eval(stack) {
|
|
1600
|
-
return stack.lookupName(this.name);
|
|
1601
|
-
}
|
|
1602
1574
|
toString() {
|
|
1603
1575
|
return this.name;
|
|
1604
1576
|
}
|
|
@@ -1619,11 +1591,6 @@ var mk404Handler = (stack, type, name) => function(...args) {
|
|
|
1619
1591
|
else console.warn("handler not found", { type, name });
|
|
1620
1592
|
return this;
|
|
1621
1593
|
};
|
|
1622
|
-
var TypeVal = class extends NameVal {
|
|
1623
|
-
eval(stack) {
|
|
1624
|
-
return stack.lookupType(this.name);
|
|
1625
|
-
}
|
|
1626
|
-
};
|
|
1627
1594
|
var keyIs = (k) => (e) => e.key === k;
|
|
1628
1595
|
var macCtrl = (e) => isMac && e.metaKey || e.ctrlKey;
|
|
1629
1596
|
var nullSafe = (fn) => (e, stack) => {
|
|
@@ -1756,9 +1723,6 @@ var Attributes = class {
|
|
|
1756
1723
|
constructor(items) {
|
|
1757
1724
|
this.items = items;
|
|
1758
1725
|
}
|
|
1759
|
-
eval(_stack) {
|
|
1760
|
-
return {};
|
|
1761
|
-
}
|
|
1762
1726
|
static parse(attributes, px, parseAll = false) {
|
|
1763
1727
|
return getAttrParser(px).parse(attributes, parseAll);
|
|
1764
1728
|
}
|
|
@@ -1768,11 +1732,26 @@ var Attributes = class {
|
|
|
1768
1732
|
};
|
|
1769
1733
|
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";
|
|
1770
1734
|
var booleanAttrs = new Set(booleanAttrsRaw.split(","));
|
|
1735
|
+
function parseDirectiveValue(px, directiveName, source, parser) {
|
|
1736
|
+
const val = parser(source, px);
|
|
1737
|
+
if (val === null) {
|
|
1738
|
+
px.onParseIssue("bad-value", {
|
|
1739
|
+
role: "directive",
|
|
1740
|
+
directive: directiveName,
|
|
1741
|
+
value: source
|
|
1742
|
+
});
|
|
1743
|
+
}
|
|
1744
|
+
return val;
|
|
1745
|
+
}
|
|
1746
|
+
function parseIterationDirectives(attributes, px) {
|
|
1747
|
+
const parseNamed = (name) => {
|
|
1748
|
+
const attr = attributes.getNamedItem(`@${name}`);
|
|
1749
|
+
return attr ? parseDirectiveValue(px, name, attr.value, parseAlterHandler) : null;
|
|
1750
|
+
};
|
|
1751
|
+
return { whenVal: parseNamed("when"), loopWithVal: parseNamed("loop-with") };
|
|
1752
|
+
}
|
|
1771
1753
|
var AttrParser = class {
|
|
1772
1754
|
constructor(px) {
|
|
1773
|
-
this.clear(px);
|
|
1774
|
-
}
|
|
1775
|
-
clear(px) {
|
|
1776
1755
|
this.px = px;
|
|
1777
1756
|
this.attrs = null;
|
|
1778
1757
|
this.hasDynamic = false;
|
|
@@ -1827,12 +1806,7 @@ var AttrParser = class {
|
|
|
1827
1806
|
}
|
|
1828
1807
|
}
|
|
1829
1808
|
_parseDirectiveValue(directiveName, s, parserFn) {
|
|
1830
|
-
|
|
1831
|
-
if (val === null) {
|
|
1832
|
-
const info = { role: "directive", directive: directiveName, value: s };
|
|
1833
|
-
this.px.onParseIssue("bad-value", info);
|
|
1834
|
-
}
|
|
1835
|
-
return val;
|
|
1809
|
+
return parseDirectiveValue(this.px, directiveName, s, parserFn);
|
|
1836
1810
|
}
|
|
1837
1811
|
parseDirective(s, directiveName) {
|
|
1838
1812
|
switch (directiveName) {
|
|
@@ -1996,11 +1970,8 @@ var IfAttr = class extends BaseAttr {
|
|
|
1996
1970
|
return this.condVal.eval(stack) ? this.thenVal.eval(stack) : this.elseVal.eval(stack);
|
|
1997
1971
|
}
|
|
1998
1972
|
};
|
|
1999
|
-
var _attrParser = null;
|
|
2000
1973
|
function getAttrParser(px) {
|
|
2001
|
-
|
|
2002
|
-
_attrParser.clear(px);
|
|
2003
|
-
return _attrParser;
|
|
1974
|
+
return new AttrParser(px);
|
|
2004
1975
|
}
|
|
2005
1976
|
var EventHandler = class _EventHandler {
|
|
2006
1977
|
constructor(handlerVal, args = []) {
|
|
@@ -2024,70 +1995,77 @@ var IntentHandler = class {
|
|
|
2024
1995
|
}
|
|
2025
1996
|
};
|
|
2026
1997
|
|
|
2027
|
-
// src/
|
|
2028
|
-
var
|
|
2029
|
-
var
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
return { hit: 0, miss: 0, badKey: 0 };
|
|
2036
|
-
}
|
|
1998
|
+
// src/iteration.js
|
|
1999
|
+
var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
|
|
2000
|
+
var normalizeRange = (start, end, size) => {
|
|
2001
|
+
let s = start == null ? 0 : start < 0 ? size + start : start;
|
|
2002
|
+
let e = end == null ? size : end < 0 ? size + end : end;
|
|
2003
|
+
s = s < 0 ? 0 : s > size ? size : s;
|
|
2004
|
+
e = e < 0 ? 0 : e > size ? size : e;
|
|
2005
|
+
return [s, e < s ? s : e];
|
|
2037
2006
|
};
|
|
2038
|
-
var
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
const len = keys.length;
|
|
2050
|
-
let cur = this.keysByLen.get(len);
|
|
2051
|
-
if (!cur) return this._returnValue(void 0);
|
|
2052
|
-
for (let i = 0; i < len - 1; i++) {
|
|
2053
|
-
cur = cur.get(keys[i]);
|
|
2054
|
-
if (!cur) return this._returnValue(void 0);
|
|
2055
|
-
}
|
|
2056
|
-
return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
|
|
2057
|
-
}
|
|
2058
|
-
set(keys, cacheKey, v) {
|
|
2059
|
-
const len = keys.length;
|
|
2060
|
-
let cur = this.keysByLen.get(len);
|
|
2061
|
-
if (!cur) {
|
|
2062
|
-
cur = /* @__PURE__ */ new WeakMap();
|
|
2063
|
-
this.keysByLen.set(len, cur);
|
|
2064
|
-
}
|
|
2065
|
-
for (let i = 0; i < len - 1; i++) {
|
|
2066
|
-
const key = keys[i];
|
|
2067
|
-
let next = cur.get(key);
|
|
2068
|
-
if (!next) {
|
|
2069
|
-
if (!isWeakKey(key)) {
|
|
2070
|
-
this.badKey += 1;
|
|
2071
|
-
return;
|
|
2072
|
-
}
|
|
2073
|
-
next = /* @__PURE__ */ new WeakMap();
|
|
2074
|
-
cur.set(key, next);
|
|
2075
|
-
}
|
|
2076
|
-
cur = next;
|
|
2077
|
-
}
|
|
2078
|
-
const lastKey = keys[len - 1];
|
|
2079
|
-
const leaf = cur.get(lastKey);
|
|
2080
|
-
if (leaf) leaf[cacheKey] = v;
|
|
2081
|
-
else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
|
|
2082
|
-
else this.badKey += 1;
|
|
2083
|
-
}
|
|
2084
|
-
evict() {
|
|
2085
|
-
const { hit, miss, badKey } = this;
|
|
2086
|
-
this.hit = this.miss = this.badKey = 0;
|
|
2087
|
-
this.keysByLen = /* @__PURE__ */ new Map();
|
|
2088
|
-
return { hit, miss, badKey };
|
|
2007
|
+
var nativeIndexedIter = (seq, visit, start, end) => {
|
|
2008
|
+
const [s, e] = normalizeRange(start, end, seqSize(seq));
|
|
2009
|
+
for (let i = s; i < e; i++) visit(i, seq[i], "si");
|
|
2010
|
+
};
|
|
2011
|
+
var nativeKeyedIter = (seq, visit, start, end) => {
|
|
2012
|
+
const [s, e] = normalizeRange(start, end, seqSize(seq));
|
|
2013
|
+
let i = 0;
|
|
2014
|
+
for (const [key, value] of seqEntries(seq)) {
|
|
2015
|
+
if (i >= e) break;
|
|
2016
|
+
if (i >= s) visit(key, value, "sk");
|
|
2017
|
+
i++;
|
|
2089
2018
|
}
|
|
2090
2019
|
};
|
|
2020
|
+
var unknownIter = () => {
|
|
2021
|
+
};
|
|
2022
|
+
var getSeqInfo = (seq) => isIndexedSeq(seq) ? nativeIndexedIter : isKeyedSeq(seq) || isSetSeq(seq) ? nativeKeyedIter : seq?.[SEQ_INFO] ?? unknownIter;
|
|
2023
|
+
var filterAlwaysTrue = (_key, _value, _iterData) => true;
|
|
2024
|
+
var nullLoopWith = (seq) => ({ iterData: { seq } });
|
|
2025
|
+
var unpackLoopResult = (result, seq) => {
|
|
2026
|
+
const value = result ?? {};
|
|
2027
|
+
return {
|
|
2028
|
+
iterData: value.iterData ?? { seq },
|
|
2029
|
+
start: value.start,
|
|
2030
|
+
end: value.end,
|
|
2031
|
+
keys: value.keys
|
|
2032
|
+
};
|
|
2033
|
+
};
|
|
2034
|
+
var makeLoopCtx = (stack, filter) => ({
|
|
2035
|
+
lookup: (name) => stack.lookupBind(name),
|
|
2036
|
+
filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
|
|
2037
|
+
});
|
|
2038
|
+
var callEnricher = (enricher, it, binds, key, value, iterData) => {
|
|
2039
|
+
enricher.call(it, binds, key, value, iterData);
|
|
2040
|
+
console.assert(
|
|
2041
|
+
binds.key === key && binds.value === value,
|
|
2042
|
+
"@enrich-with handlers must not overwrite binds.key or binds.value"
|
|
2043
|
+
);
|
|
2044
|
+
binds.key = key;
|
|
2045
|
+
binds.value = value;
|
|
2046
|
+
};
|
|
2047
|
+
var visitKeys = (seq, keys, visit) => {
|
|
2048
|
+
const attrName = isIndexedSeq(seq) ? "si" : "sk";
|
|
2049
|
+
for (const key of keys) visit(key, seqGet(seq, key), attrName);
|
|
2050
|
+
};
|
|
2051
|
+
function walkLoopBindings({ seq, it, filter, loopWith, enricher, ctx }, visit) {
|
|
2052
|
+
const { iterData, start, end, keys } = unpackLoopResult(loopWith.call(it, seq, ctx), seq);
|
|
2053
|
+
const visitOne = (key, value, attrName) => {
|
|
2054
|
+
const binds = { key, value };
|
|
2055
|
+
if (enricher) callEnricher(enricher, it, binds, key, value, iterData);
|
|
2056
|
+
visit(key, value, attrName, binds);
|
|
2057
|
+
};
|
|
2058
|
+
if (keys) visitKeys(seq, keys, visitOne);
|
|
2059
|
+
else
|
|
2060
|
+
getSeqInfo(seq)(
|
|
2061
|
+
seq,
|
|
2062
|
+
(key, value, attrName) => {
|
|
2063
|
+
if (filter.call(it, key, value, iterData)) visitOne(key, value, attrName);
|
|
2064
|
+
},
|
|
2065
|
+
start,
|
|
2066
|
+
end
|
|
2067
|
+
);
|
|
2068
|
+
}
|
|
2091
2069
|
|
|
2092
2070
|
// src/vdom.js
|
|
2093
2071
|
var HTML_NS = "http://www.w3.org/1999/xhtml";
|
|
@@ -2432,189 +2410,11 @@ function h(tagName, properties, children, namespace) {
|
|
|
2432
2410
|
return new VNode(tag, props, normalizedChildren, key, namespace);
|
|
2433
2411
|
}
|
|
2434
2412
|
|
|
2435
|
-
// src/renderer.js
|
|
2436
|
-
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
|
|
2437
|
-
var Renderer = class {
|
|
2438
|
-
constructor(comps) {
|
|
2439
|
-
this.comps = comps;
|
|
2440
|
-
this.cache = new WeakMapDomCache();
|
|
2441
|
-
this.renderTag = h;
|
|
2442
|
-
}
|
|
2443
|
-
renderFragment(childs) {
|
|
2444
|
-
return new VFragment(childs);
|
|
2445
|
-
}
|
|
2446
|
-
renderComment(text) {
|
|
2447
|
-
return new VComment(text);
|
|
2448
|
-
}
|
|
2449
|
-
setNullCache() {
|
|
2450
|
-
this.cache = new NullDomCache();
|
|
2451
|
-
}
|
|
2452
|
-
renderToDOM(stack, val) {
|
|
2453
|
-
const rootNode = document.createElement("div");
|
|
2454
|
-
const rOpts = { document };
|
|
2455
|
-
render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
|
|
2456
|
-
return rootNode.childNodes[0];
|
|
2457
|
-
}
|
|
2458
|
-
renderToString(stack, val, cleanAttrs = true) {
|
|
2459
|
-
const dom = this.renderToDOM(stack, val);
|
|
2460
|
-
if (cleanAttrs) {
|
|
2461
|
-
const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
|
|
2462
|
-
for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
|
|
2463
|
-
}
|
|
2464
|
-
return dom.innerHTML;
|
|
2465
|
-
}
|
|
2466
|
-
renderRoot(stack, val, viewName = null) {
|
|
2467
|
-
const comp = this.comps.getCompFor(val);
|
|
2468
|
-
if (comp === null) return null;
|
|
2469
|
-
return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
|
|
2470
|
-
}
|
|
2471
|
-
renderIt(stack, node, key, viewName) {
|
|
2472
|
-
const comp = this.comps.getCompFor(stack.it);
|
|
2473
|
-
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
|
|
2474
|
-
}
|
|
2475
|
-
// `node` is the parse node of the render site (`<x render>` / `render-it` /
|
|
2476
|
-
// `render-each`, or the view's root anode for the app root). It keys the
|
|
2477
|
-
// cache as a globally-unique object: node ids alone are unique only within a
|
|
2478
|
-
// single view, so the same value rendered by two components (e.g. through a
|
|
2479
|
-
// shared dynamic-var sequence) would otherwise collide in the cache.
|
|
2480
|
-
_rValComp(stack, val, comp, node, key, viewName) {
|
|
2481
|
-
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
|
|
2482
|
-
const cachePath = [node, val];
|
|
2483
|
-
stack._pushDynBindValuesToArray(cachePath, comp);
|
|
2484
|
-
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
2485
|
-
if (cachedNode) return cachedNode;
|
|
2486
|
-
const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
|
|
2487
|
-
const body = this.renderView(view, stack);
|
|
2488
|
-
if (body == null) return null;
|
|
2489
|
-
const meta = this._renderMetadata({
|
|
2490
|
-
$: "Comp",
|
|
2491
|
-
nid: node?.nodeId ?? null,
|
|
2492
|
-
cid: comp.id,
|
|
2493
|
-
vid: view.name
|
|
2494
|
-
});
|
|
2495
|
-
const dom = new VFragment([meta, body]);
|
|
2496
|
-
this.cache.set(cachePath, cacheKey, dom);
|
|
2497
|
-
return dom;
|
|
2498
|
-
}
|
|
2499
|
-
pushEachEntry(r, nid, attrName, key, dom) {
|
|
2500
|
-
r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
|
|
2501
|
-
}
|
|
2502
|
-
renderEachWhen(stack, iterInfo, view, nid) {
|
|
2503
|
-
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
2504
|
-
const r = [];
|
|
2505
|
-
const it = stack.it;
|
|
2506
|
-
const { iterData, start, end, keys } = unpackLoopResult(
|
|
2507
|
-
loopWith.call(it, seq, makeLoopCtx(stack, filter)),
|
|
2508
|
-
seq
|
|
2509
|
-
);
|
|
2510
|
-
const renderOne = (key, value, attrName) => {
|
|
2511
|
-
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
2512
|
-
const binds = { key, value };
|
|
2513
|
-
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
|
|
2514
|
-
if (enricher) callEnricher(enricher, it, binds, key, value, iterData);
|
|
2515
|
-
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
2516
|
-
if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
2517
|
-
else {
|
|
2518
|
-
const dom = this.renderView(view, stack.enter(value, binds, false));
|
|
2519
|
-
if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
|
|
2520
|
-
this.cache.set(cachePath, cacheKey, dom);
|
|
2521
|
-
}
|
|
2522
|
-
};
|
|
2523
|
-
if (keys) keysIter(seq, renderOne, keys);
|
|
2524
|
-
else
|
|
2525
|
-
getSeqInfo(seq)(
|
|
2526
|
-
seq,
|
|
2527
|
-
(key, value, attrName) => {
|
|
2528
|
-
if (filter.call(it, key, value, iterData)) renderOne(key, value, attrName);
|
|
2529
|
-
},
|
|
2530
|
-
start,
|
|
2531
|
-
end
|
|
2532
|
-
);
|
|
2533
|
-
return r;
|
|
2534
|
-
}
|
|
2535
|
-
renderView(view, stack) {
|
|
2536
|
-
let n = stack.binds[1];
|
|
2537
|
-
while (n !== null) {
|
|
2538
|
-
const b = n[0];
|
|
2539
|
-
if (b.isFrame) {
|
|
2540
|
-
if (stack.it !== b.it) break;
|
|
2541
|
-
console.error("recursion detected", stack.it, b.it);
|
|
2542
|
-
return new VComment("RECURSION AVOIDED");
|
|
2543
|
-
}
|
|
2544
|
-
n = n[1];
|
|
2545
|
-
}
|
|
2546
|
-
return view.render(stack, this);
|
|
2547
|
-
}
|
|
2548
|
-
_renderMetadata(info) {
|
|
2549
|
-
return new VComment(`§${JSON.stringify(info)}§`);
|
|
2550
|
-
}
|
|
2551
|
-
// Prefix a loop-less @enrich-with subtree with a boundary meta so event-path
|
|
2552
|
-
// reconstruction replays its binds (mirrors the §Each§ / §Comp§ metas).
|
|
2553
|
-
renderScopeMeta(nid, dom) {
|
|
2554
|
-
return new VFragment([this._renderMetadata({ $: "Scope", nid }), dom]);
|
|
2555
|
-
}
|
|
2556
|
-
};
|
|
2557
|
-
var getSeqInfo = (seq) => isIndexedSeq(seq) ? nativeIndexedIter : isKeyedSeq(seq) || isSetSeq(seq) ? nativeKeyedIter : seq?.[SEQ_INFO] ?? unkIter;
|
|
2558
|
-
var normalizeRange = (start, end, size) => {
|
|
2559
|
-
let s = start == null ? 0 : start < 0 ? size + start : start;
|
|
2560
|
-
let e = end == null ? size : end < 0 ? size + end : end;
|
|
2561
|
-
s = s < 0 ? 0 : s > size ? size : s;
|
|
2562
|
-
e = e < 0 ? 0 : e > size ? size : e;
|
|
2563
|
-
return [s, e < s ? s : e];
|
|
2564
|
-
};
|
|
2565
|
-
var callEnricher = (enricher, it, binds, key, value, iterData) => {
|
|
2566
|
-
enricher.call(it, binds, key, value, iterData);
|
|
2567
|
-
console.assert(
|
|
2568
|
-
binds.key === key && binds.value === value,
|
|
2569
|
-
"@enrich-with handlers must not overwrite binds.key or binds.value"
|
|
2570
|
-
);
|
|
2571
|
-
binds.key = key;
|
|
2572
|
-
binds.value = value;
|
|
2573
|
-
};
|
|
2574
|
-
var filterAlwaysTrue = (_v, _k, _seq) => true;
|
|
2575
|
-
var nullLoopWith = (seq) => ({ iterData: { seq } });
|
|
2576
|
-
var unpackLoopResult = (result, seq) => {
|
|
2577
|
-
const r = result ?? {};
|
|
2578
|
-
return { iterData: r.iterData ?? { seq }, start: r.start, end: r.end, keys: r.keys };
|
|
2579
|
-
};
|
|
2580
|
-
var keysIter = (seq, visit, keys) => {
|
|
2581
|
-
const attrName = isIndexedSeq(seq) ? "si" : "sk";
|
|
2582
|
-
for (const key of keys) visit(key, seqGet(seq, key), attrName);
|
|
2583
|
-
};
|
|
2584
|
-
var makeLoopCtx = (stack, filter) => ({
|
|
2585
|
-
lookup: (name) => stack.lookupBind(name),
|
|
2586
|
-
filter: (key, value, iterData) => filter.call(stack.it, key, value, iterData)
|
|
2587
|
-
});
|
|
2588
|
-
var nativeIndexedIter = (seq, visit, start, end) => {
|
|
2589
|
-
const [s, e] = normalizeRange(start, end, seqSize(seq));
|
|
2590
|
-
for (let i = s; i < e; i++) visit(i, seq[i], "si");
|
|
2591
|
-
};
|
|
2592
|
-
var nativeKeyedIter = (seq, visit, start, end) => {
|
|
2593
|
-
const [s, e] = normalizeRange(start, end, seqSize(seq));
|
|
2594
|
-
let i = 0;
|
|
2595
|
-
for (const [k, v] of seqEntries(seq)) {
|
|
2596
|
-
if (i >= e) break;
|
|
2597
|
-
if (i >= s) visit(k, v, "sk");
|
|
2598
|
-
i++;
|
|
2599
|
-
}
|
|
2600
|
-
};
|
|
2601
|
-
var unkIter = () => {
|
|
2602
|
-
};
|
|
2603
|
-
var SEQ_INFO = /* @__PURE__ */ Symbol.for("tutuca.seqInfo");
|
|
2604
|
-
|
|
2605
2413
|
// src/anode.js
|
|
2606
2414
|
function resolveDynProducer(comp, name) {
|
|
2607
|
-
|
|
2608
|
-
const
|
|
2609
|
-
|
|
2610
|
-
producerComp = comp.scope?.lookupComponent(lk.compName);
|
|
2611
|
-
producerProvide = producerComp?.provide?.[lk.provideName];
|
|
2612
|
-
} else {
|
|
2613
|
-
const p = comp?.provide?.[name];
|
|
2614
|
-
if (p == null) return null;
|
|
2615
|
-
producerComp = comp;
|
|
2616
|
-
producerProvide = p;
|
|
2617
|
-
}
|
|
2415
|
+
const own = comp?.provide?.[name];
|
|
2416
|
+
const producerComp = own != null ? comp : comp?.scope?.lookupProvider(name) ?? null;
|
|
2417
|
+
const producerProvide = own ?? producerComp?.provide?.[name];
|
|
2618
2418
|
if (producerComp == null || producerProvide == null) return null;
|
|
2619
2419
|
const pi = producerProvide.val?.toPathItem?.() ?? null;
|
|
2620
2420
|
return { producerCompId: producerComp.id, producerSteps: pi ? [pi] : [] };
|
|
@@ -2975,16 +2775,10 @@ function parseRenderEach(px, value, as, attrs) {
|
|
|
2975
2775
|
const seqVal = parseXOpVal("render-each", value, px, parseSequence);
|
|
2976
2776
|
if (seqVal === null) return null;
|
|
2977
2777
|
const renderIt = px.addNode(RenderItNode, as);
|
|
2978
|
-
const
|
|
2979
|
-
const eachAttr = attrParser.pushWrapper("each", value, seqVal);
|
|
2980
|
-
attrParser.eachAttr = eachAttr;
|
|
2981
|
-
const when = attrs.getNamedItem("@when");
|
|
2982
|
-
if (when) attrParser._parseWhen(when.value);
|
|
2983
|
-
const lWith = attrs.getNamedItem("@loop-with");
|
|
2984
|
-
if (lWith) attrParser._parseLoopWith(lWith.value);
|
|
2778
|
+
const { whenVal, loopWithVal } = parseIterationDirectives(attrs, px);
|
|
2985
2779
|
const each2 = px.addNodeIf(EachNode, seqVal);
|
|
2986
|
-
each2.iterInfo.whenVal =
|
|
2987
|
-
each2.iterInfo.loopWithVal =
|
|
2780
|
+
each2.iterInfo.whenVal = whenVal;
|
|
2781
|
+
each2.iterInfo.loopWithVal = loopWithVal;
|
|
2988
2782
|
each2.fromRenderEach = true;
|
|
2989
2783
|
each2.wrapNode(renderIt);
|
|
2990
2784
|
return each2;
|
|
@@ -3373,7 +3167,7 @@ var Components = class {
|
|
|
3373
3167
|
}
|
|
3374
3168
|
compileStyles() {
|
|
3375
3169
|
const styles = [];
|
|
3376
|
-
for (const
|
|
3170
|
+
for (const Comp of this.byId.values()) styles.push(Comp[COMPONENT].compileStyle());
|
|
3377
3171
|
return styles.join("\n");
|
|
3378
3172
|
}
|
|
3379
3173
|
};
|
|
@@ -3432,32 +3226,39 @@ var ComponentStack = class _ComponentStack {
|
|
|
3432
3226
|
lookupComponent(name) {
|
|
3433
3227
|
return this.byName[name] ?? this.parent?.lookupComponent(name) ?? null;
|
|
3434
3228
|
}
|
|
3229
|
+
// The component in this scope chain that provides `name`, innermost first. A lookup
|
|
3230
|
+
// names a value without naming its producer, so the render-target teleport
|
|
3231
|
+
// (resolveDynProducer) recovers the producer here instead. Sound because
|
|
3232
|
+
// PROVIDE_NAME_COLLISION keeps a provide name to one producer per chain; with two,
|
|
3233
|
+
// this returns the innermost and the linter has already reported the ambiguity.
|
|
3234
|
+
lookupProvider(name) {
|
|
3235
|
+
for (const compName in this.byName) {
|
|
3236
|
+
const Comp = this.byName[compName];
|
|
3237
|
+
if (Comp.provide?.[name] !== void 0) return Comp;
|
|
3238
|
+
}
|
|
3239
|
+
return this.parent?.lookupProvider(name) ?? null;
|
|
3240
|
+
}
|
|
3435
3241
|
lookupMacro(name) {
|
|
3436
3242
|
return this.macros[name] ?? this.parent?.lookupMacro(name) ?? null;
|
|
3437
3243
|
}
|
|
3438
3244
|
};
|
|
3439
3245
|
var ProvideInfo = class {
|
|
3440
|
-
constructor(name, val
|
|
3246
|
+
constructor(name, val) {
|
|
3441
3247
|
this.name = name;
|
|
3442
3248
|
this.val = val;
|
|
3443
|
-
this.symbol = symbol;
|
|
3444
3249
|
}
|
|
3445
3250
|
};
|
|
3446
3251
|
var LookupInfo = class {
|
|
3447
|
-
constructor(name,
|
|
3252
|
+
constructor(name, val) {
|
|
3448
3253
|
this.name = name;
|
|
3449
|
-
this.compName = compName;
|
|
3450
|
-
this.provideName = provideName;
|
|
3451
3254
|
this.val = val;
|
|
3452
|
-
this._sym = void 0;
|
|
3453
|
-
}
|
|
3454
|
-
getProducerSymbol(stack) {
|
|
3455
|
-
if (this._sym === void 0)
|
|
3456
|
-
this._sym = stack.lookupType(this.compName)?.provide?.[this.provideName]?.symbol ?? null;
|
|
3457
|
-
return this._sym;
|
|
3458
3255
|
}
|
|
3459
3256
|
};
|
|
3460
3257
|
var isString = (v) => typeof v === "string";
|
|
3258
|
+
var isTypeName = (s) => {
|
|
3259
|
+
const c = s.charCodeAt(0);
|
|
3260
|
+
return c >= 65 && c <= 90;
|
|
3261
|
+
};
|
|
3461
3262
|
var _rawSpecKeys = "name view style commonStyle globalStyle receive intent alter views provide lookup fields methods statics";
|
|
3462
3263
|
var KNOWN_SPEC_KEYS = new Set(_rawSpecKeys.split(" "));
|
|
3463
3264
|
var _compId = 0;
|
|
@@ -3478,8 +3279,9 @@ var Component = class {
|
|
|
3478
3279
|
this.views[name] = new View(name, view, style);
|
|
3479
3280
|
}
|
|
3480
3281
|
this._rawProvide = o.provide ?? {};
|
|
3481
|
-
this._rawLookup = o.lookup ??
|
|
3282
|
+
this._rawLookup = o.lookup ?? [];
|
|
3482
3283
|
this.provide = {};
|
|
3284
|
+
this.provideType = {};
|
|
3483
3285
|
this.lookup = {};
|
|
3484
3286
|
this.scope = null;
|
|
3485
3287
|
this.spec = o;
|
|
@@ -3491,25 +3293,23 @@ var Component = class {
|
|
|
3491
3293
|
this.views[name].compile(new ParseContext2(), this.scope, this.id);
|
|
3492
3294
|
const ctx = this.views.main.ctx;
|
|
3493
3295
|
for (const key in this._rawProvide) {
|
|
3296
|
+
if (isTypeName(key)) {
|
|
3297
|
+
if (this._rawProvide[key] === "self") this.provideType[key] = this.Class;
|
|
3298
|
+
continue;
|
|
3299
|
+
}
|
|
3494
3300
|
const val = parseProvide(this._rawProvide[key], ctx);
|
|
3495
|
-
if (val) this.provide[key] = new ProvideInfo(key, val
|
|
3301
|
+
if (val) this.provide[key] = new ProvideInfo(key, val);
|
|
3496
3302
|
}
|
|
3497
|
-
for (const
|
|
3498
|
-
const
|
|
3499
|
-
|
|
3500
|
-
const
|
|
3501
|
-
|
|
3502
|
-
const defStr = isString(linfo?.default) ? linfo.default : null;
|
|
3503
|
-
const val = defStr === null ? null : parseField(defStr, ctx);
|
|
3504
|
-
this.lookup[key] = new LookupInfo(key, compName, provideName, val);
|
|
3303
|
+
for (const entry of this._rawLookup) {
|
|
3304
|
+
const name = isString(entry) ? entry : isString(entry?.name) ? entry.name : null;
|
|
3305
|
+
if (name === null) continue;
|
|
3306
|
+
const defStr = isString(entry?.default) ? entry.default : null;
|
|
3307
|
+
this.lookup[name] = new LookupInfo(name, defStr === null ? null : parseField(defStr, ctx));
|
|
3505
3308
|
}
|
|
3506
3309
|
for (const key in this.lookup)
|
|
3507
3310
|
if (this.provide[key] !== void 0)
|
|
3508
3311
|
console.warn("name declared in both provide and lookup", this.name, key);
|
|
3509
3312
|
}
|
|
3510
|
-
make(args, opts) {
|
|
3511
|
-
return this.Class.make(args, opts ?? { scope: this.scope });
|
|
3512
|
-
}
|
|
3513
3313
|
getView(name) {
|
|
3514
3314
|
return this.views[name] ?? this.views.main;
|
|
3515
3315
|
}
|
|
@@ -3534,6 +3334,22 @@ var Component = class {
|
|
|
3534
3334
|
// src/stack.js
|
|
3535
3335
|
var STOP = /* @__PURE__ */ Symbol("STOP");
|
|
3536
3336
|
var NEXT = /* @__PURE__ */ Symbol("NEXT");
|
|
3337
|
+
var DEFAULT_LOOKUP_ROUTE = ["dyn", "lex"];
|
|
3338
|
+
function routeLookup(route, lex, dyn) {
|
|
3339
|
+
for (let i = 0; i < route.length; i++) {
|
|
3340
|
+
const leg = route[i];
|
|
3341
|
+
if (leg === "dyn") {
|
|
3342
|
+
const v = dyn();
|
|
3343
|
+
if (v != null) return v;
|
|
3344
|
+
} else if (leg === "lex") {
|
|
3345
|
+
const v = lex();
|
|
3346
|
+
if (v != null) return v;
|
|
3347
|
+
} else {
|
|
3348
|
+
console.warn("unknown lookup route leg", leg, '- expected "dyn" or "lex"');
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
return null;
|
|
3352
|
+
}
|
|
3537
3353
|
function lookup(chain, name, dv = null) {
|
|
3538
3354
|
let n = chain;
|
|
3539
3355
|
while (n !== null) {
|
|
@@ -3584,14 +3400,21 @@ var Stack = class _Stack {
|
|
|
3584
3400
|
this.ctx = ctx;
|
|
3585
3401
|
}
|
|
3586
3402
|
// Evaluate every provide the entered component publishes and push them as one
|
|
3587
|
-
// dynBinds frame
|
|
3403
|
+
// dynBinds frame, keyed by NAME. Published types go in the same frame: a type name
|
|
3404
|
+
// starts A-Z and a value name does not, so the two namespaces cannot collide and
|
|
3405
|
+
// nearest-ancestor-wins falls out of frame order for both. No-op with no provides.
|
|
3588
3406
|
_pushProvides() {
|
|
3589
|
-
const
|
|
3590
|
-
if (
|
|
3407
|
+
const comp = this.comps.getCompFor(this.it);
|
|
3408
|
+
if (comp == null) return this;
|
|
3409
|
+
const { provide, provideType } = comp;
|
|
3591
3410
|
const dynObj = {};
|
|
3592
3411
|
let has2 = false;
|
|
3593
3412
|
for (const k in provide) {
|
|
3594
|
-
dynObj[
|
|
3413
|
+
dynObj[k] = provide[k].val.eval(this);
|
|
3414
|
+
has2 = true;
|
|
3415
|
+
}
|
|
3416
|
+
for (const k in provideType) {
|
|
3417
|
+
dynObj[k] = provideType[k];
|
|
3595
3418
|
has2 = true;
|
|
3596
3419
|
}
|
|
3597
3420
|
if (!has2) return this;
|
|
@@ -3616,30 +3439,36 @@ var Stack = class _Stack {
|
|
|
3616
3439
|
const newViews = [name, views];
|
|
3617
3440
|
return new _Stack(comps, it, binds, dynBinds, newViews, computeViewsId(newViews), ctx);
|
|
3618
3441
|
}
|
|
3442
|
+
// Published types are stable per scope and would only churn the render cache, so
|
|
3443
|
+
// the cache key covers values alone.
|
|
3619
3444
|
_pushDynBindValuesToArray(arr, comp) {
|
|
3620
|
-
for (const k in comp.provide) arr.push(this.
|
|
3621
|
-
for (const k in comp.lookup) arr.push(this.
|
|
3622
|
-
}
|
|
3623
|
-
_lookupProvide(p) {
|
|
3624
|
-
return lookup(this.dynBinds, p.symbol) ?? p.val.eval(this) ?? null;
|
|
3625
|
-
}
|
|
3626
|
-
_lookupAlias(lk) {
|
|
3627
|
-
const sym = lk.getProducerSymbol(this);
|
|
3628
|
-
return (sym != null ? lookup(this.dynBinds, sym) : null) ?? lk.val?.eval(this) ?? null;
|
|
3445
|
+
for (const k in comp.provide) arr.push(this.lookupDynamic(k));
|
|
3446
|
+
for (const k in comp.lookup) arr.push(this.lookupDynamic(k));
|
|
3629
3447
|
}
|
|
3448
|
+
// `*name`: the nearest binding above (including this component's own provides,
|
|
3449
|
+
// pushed on entering it), else this component's declared default, else null.
|
|
3630
3450
|
lookupDynamic(name) {
|
|
3451
|
+
const v = lookup(this.dynBinds, name);
|
|
3452
|
+
if (v != null) return v;
|
|
3631
3453
|
const comp = this.comps.getCompFor(this.it);
|
|
3632
|
-
|
|
3633
|
-
const lk = comp.lookup[name];
|
|
3634
|
-
if (lk !== void 0) return this._lookupAlias(lk);
|
|
3635
|
-
const p = comp.provide[name];
|
|
3636
|
-
return p !== void 0 ? this._lookupProvide(p) : null;
|
|
3454
|
+
return comp?.lookup[name]?.val?.eval(this) ?? null;
|
|
3637
3455
|
}
|
|
3638
3456
|
lookupBind(name) {
|
|
3639
3457
|
return lookup(this.binds, name);
|
|
3640
3458
|
}
|
|
3641
|
-
|
|
3642
|
-
|
|
3459
|
+
// The `lex` leg: what a name means in the registration scope of the component being
|
|
3460
|
+
// rendered. The scope chain holds components, so this leg only ever answers for a
|
|
3461
|
+
// type name — for a value name it is a miss, which is why one default route serves
|
|
3462
|
+
// both. Guarded: a non-component `it` has no scope to ask.
|
|
3463
|
+
_lookupLex(name) {
|
|
3464
|
+
return this.comps.getCompFor(this.it)?.scope.lookupComponent(name) ?? null;
|
|
3465
|
+
}
|
|
3466
|
+
lookupRouted(name, route = DEFAULT_LOOKUP_ROUTE) {
|
|
3467
|
+
return routeLookup(
|
|
3468
|
+
route,
|
|
3469
|
+
() => this._lookupLex(name),
|
|
3470
|
+
() => this.lookupDynamic(name)
|
|
3471
|
+
);
|
|
3643
3472
|
}
|
|
3644
3473
|
lookupFieldRaw(name) {
|
|
3645
3474
|
return this.it[name] ?? null;
|
|
@@ -3648,12 +3477,6 @@ var Stack = class _Stack {
|
|
|
3648
3477
|
const fn = this.it[name];
|
|
3649
3478
|
return fn instanceof Function ? fn.call(this.it) : null;
|
|
3650
3479
|
}
|
|
3651
|
-
// Bare implicit event names are gone: a sigil-less word cannot reach a
|
|
3652
|
-
// handler-arg slot anymore, so this only ever serves stale NameVals parsed
|
|
3653
|
-
// before the removal (e.g. macro-attr pass-throughs). Always null.
|
|
3654
|
-
lookupName(_name) {
|
|
3655
|
-
return null;
|
|
3656
|
-
}
|
|
3657
3480
|
// The dispatched DOM event / drag info, read only by EventMemberVal's
|
|
3658
3481
|
// `e.<member>` handler args. Null outside a live event transaction.
|
|
3659
3482
|
lookupEvent() {
|
|
@@ -3679,11 +3502,6 @@ var Stack = class _Stack {
|
|
|
3679
3502
|
// src/oo.js
|
|
3680
3503
|
var BAD_VALUE = /* @__PURE__ */ Symbol("BadValue");
|
|
3681
3504
|
var nullCoercer = (v) => v;
|
|
3682
|
-
var isPlainObject3 = (v) => {
|
|
3683
|
-
if (v === null || typeof v !== "object") return false;
|
|
3684
|
-
const proto = Object.getPrototypeOf(v);
|
|
3685
|
-
return proto === Object.prototype || proto === null;
|
|
3686
|
-
};
|
|
3687
3505
|
function defaultToData(v) {
|
|
3688
3506
|
if (v instanceof Map) return [...v.entries()];
|
|
3689
3507
|
if (v instanceof Set) return [...v.values()];
|
|
@@ -3752,7 +3570,7 @@ var CHECK_TYPE_FLOAT = check(Number.isFinite, "Float expected");
|
|
|
3752
3570
|
var CHECK_TYPE_BOOL = check((v) => typeof v === "boolean", "Boolean expected");
|
|
3753
3571
|
var CHECK_TYPE_STRING = check((v) => typeof v === "string", "String expected");
|
|
3754
3572
|
var CHECK_TYPE_LIST = check(Array.isArray, "Array expected");
|
|
3755
|
-
var CHECK_TYPE_OBJECT = check(
|
|
3573
|
+
var CHECK_TYPE_OBJECT = check(isPlainObject, "Plain object expected");
|
|
3756
3574
|
var CHECK_TYPE_MAP = check((v) => v instanceof Map, "Map expected");
|
|
3757
3575
|
var CHECK_TYPE_SET = check((v) => v instanceof Set, "Set expected");
|
|
3758
3576
|
var FieldBool = class extends Field {
|
|
@@ -3821,7 +3639,7 @@ var FieldObject = class extends Field {
|
|
|
3821
3639
|
"object",
|
|
3822
3640
|
name,
|
|
3823
3641
|
CHECK_TYPE_OBJECT,
|
|
3824
|
-
(v) =>
|
|
3642
|
+
(v) => isPlainObject(v) ? { ...v } : null,
|
|
3825
3643
|
defaultValue
|
|
3826
3644
|
);
|
|
3827
3645
|
}
|
|
@@ -3834,7 +3652,7 @@ var FieldMap = class extends Field {
|
|
|
3834
3652
|
CHECK_TYPE_MAP,
|
|
3835
3653
|
(v) => {
|
|
3836
3654
|
if (v instanceof Map) return new Map(v);
|
|
3837
|
-
if (Array.isArray(v) ||
|
|
3655
|
+
if (Array.isArray(v) || isPlainObject(v))
|
|
3838
3656
|
return new Map(Array.isArray(v) ? v : Object.entries(v));
|
|
3839
3657
|
return null;
|
|
3840
3658
|
},
|
|
@@ -3959,7 +3777,7 @@ function classFromData(name, { fields = {}, methods, statics }) {
|
|
|
3959
3777
|
b.addField(field, dval, FieldCls);
|
|
3960
3778
|
} else if (value?.component && value?.args !== void 0)
|
|
3961
3779
|
b.addCompField(field, value.component, value.args);
|
|
3962
|
-
else if (
|
|
3780
|
+
else if (isPlainObject(value)) b.addField(field, { ...value }, FieldObject);
|
|
3963
3781
|
else {
|
|
3964
3782
|
const FieldCls = value?.[FIELD_CLASS] ?? FieldAny;
|
|
3965
3783
|
b.addField(field, value, FieldCls);
|
|
@@ -3983,10 +3801,24 @@ function validateDraftFields(current2, draft) {
|
|
|
3983
3801
|
}
|
|
3984
3802
|
}
|
|
3985
3803
|
}
|
|
3986
|
-
var META_KEYS = "name id fields methods views receive intent alter provide lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
|
|
3804
|
+
var META_KEYS = "name id fields methods views receive intent alter provide provideType lookup spec extra commonStyle globalStyle scope _rawProvide _rawLookup".split(
|
|
3987
3805
|
" "
|
|
3988
3806
|
);
|
|
3807
|
+
var RESERVED_COMPONENT_STATICS = /* @__PURE__ */ new Set([
|
|
3808
|
+
...META_KEYS,
|
|
3809
|
+
"make",
|
|
3810
|
+
"getMetaClass",
|
|
3811
|
+
...Object.getOwnPropertyNames(Component.prototype)
|
|
3812
|
+
]);
|
|
3813
|
+
function assertNoReservedComponentStatics(statics = {}) {
|
|
3814
|
+
for (const name in statics) {
|
|
3815
|
+
if (RESERVED_COMPONENT_STATICS.has(name)) {
|
|
3816
|
+
throw new TypeError(`component static "${name}" is reserved by the framework`);
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3989
3820
|
Component.fromSpec = (opts) => {
|
|
3821
|
+
assertNoReservedComponentStatics(opts.statics);
|
|
3990
3822
|
const Class = classFromData(opts.name, opts);
|
|
3991
3823
|
const comp = new Component(Class, opts);
|
|
3992
3824
|
const metaClass = Class.getMetaClass();
|
|
@@ -4006,7 +3838,7 @@ Component.fromSpec = (opts) => {
|
|
|
4006
3838
|
configurable: true
|
|
4007
3839
|
});
|
|
4008
3840
|
for (const key of Object.getOwnPropertyNames(Component.prototype))
|
|
4009
|
-
if (key !== "constructor" &&
|
|
3841
|
+
if (key !== "constructor" && !Object.hasOwn(Class, key))
|
|
4010
3842
|
Class[key] = (...args) => comp[key](...args);
|
|
4011
3843
|
return Class;
|
|
4012
3844
|
};
|
|
@@ -4026,9 +3858,6 @@ var State = class {
|
|
|
4026
3858
|
this.val = val;
|
|
4027
3859
|
for (const sub of this.changeSubs) sub({ val, old, info, timestamp: Date.now() });
|
|
4028
3860
|
}
|
|
4029
|
-
update(fn, info) {
|
|
4030
|
-
return this.set(fn(this.val), info);
|
|
4031
|
-
}
|
|
4032
3861
|
};
|
|
4033
3862
|
var Transactor = class {
|
|
4034
3863
|
constructor(comps, rootValue) {
|
|
@@ -4089,7 +3918,7 @@ var Transactor = class {
|
|
|
4089
3918
|
// Build and dispatch the observer record for a settled transaction. The
|
|
4090
3919
|
// resolved handler (`_resolvedHandler`/`_matched`) and per-leaf before/after
|
|
4091
3920
|
// (`_before`/`_after`) were captured while the handler ran (see callHandler /
|
|
4092
|
-
//
|
|
3921
|
+
// Transaction.run). No-op when nobody is observing.
|
|
4093
3922
|
_emitTransaction(transaction, root) {
|
|
4094
3923
|
if (this._observers.length === 0) return;
|
|
4095
3924
|
if (transaction._resolvedHandler === void 0) return;
|
|
@@ -4121,8 +3950,13 @@ var Transactor = class {
|
|
|
4121
3950
|
}
|
|
4122
3951
|
return child;
|
|
4123
3952
|
}
|
|
4124
|
-
|
|
4125
|
-
|
|
3953
|
+
// `origin` is where the message came FROM, pinned now for the same reason an
|
|
3954
|
+
// intent's answerPath is: a reply must reach the sender that asked even if a key
|
|
3955
|
+
// moved while the message was in flight. Null when nobody is waiting — a host
|
|
3956
|
+
// sendAtRoot or a view's own `@on.*` — and ctx.sendReply refuses on that.
|
|
3957
|
+
pushSend(path, name, args = [], parent = null, origin = null) {
|
|
3958
|
+
const t = new SendEvent(path, this, name, args, parent);
|
|
3959
|
+
t.origin = origin === null ? null : origin.toTransactionPath().pinKeys(this.state.val);
|
|
4126
3960
|
this.pushTransaction(t);
|
|
4127
3961
|
return this._link(t, parent);
|
|
4128
3962
|
}
|
|
@@ -4135,9 +3969,9 @@ var Transactor = class {
|
|
|
4135
3969
|
walk.advance();
|
|
4136
3970
|
return walk;
|
|
4137
3971
|
}
|
|
4138
|
-
// Drain queued transactions and await
|
|
4139
|
-
//
|
|
4140
|
-
//
|
|
3972
|
+
// Drain queued transactions and await async intent handlers until quiescent. A
|
|
3973
|
+
// completed handler may enqueue an answer, which may dispatch more work, so we loop.
|
|
3974
|
+
// `maxTurns` backstops a pathological non-terminating cascade.
|
|
4141
3975
|
async settle(maxTurns = 1e4) {
|
|
4142
3976
|
while ((this.hasPendingTransactions || this._inflight.size) && maxTurns-- > 0) {
|
|
4143
3977
|
while (this.hasPendingTransactions) this.transactNext();
|
|
@@ -4194,9 +4028,6 @@ var Transaction = class {
|
|
|
4194
4028
|
whenSubtreeSettled() {
|
|
4195
4029
|
return this.completion.whenSubtreeSettled();
|
|
4196
4030
|
}
|
|
4197
|
-
run(rootValue, comps) {
|
|
4198
|
-
return this.updateRootValue(rootValue, comps);
|
|
4199
|
-
}
|
|
4200
4031
|
afterTransaction() {
|
|
4201
4032
|
}
|
|
4202
4033
|
// Ending a walk and forwarding belong to the two dispatch buckets; the base warns
|
|
@@ -4208,12 +4039,6 @@ var Transaction = class {
|
|
|
4208
4039
|
forward(_opts) {
|
|
4209
4040
|
console.warn('ctx.forward() needs a "receive" or "intent" handler - ignored');
|
|
4210
4041
|
}
|
|
4211
|
-
buildRootStack(root, comps) {
|
|
4212
|
-
return Stack.root(comps, root);
|
|
4213
|
-
}
|
|
4214
|
-
buildStack(root, comps) {
|
|
4215
|
-
return this.path.toTransactionPath().buildStack(this.buildRootStack(root, comps));
|
|
4216
|
-
}
|
|
4217
4042
|
// The kind reported to observers (see Transactor.observe); null on the base.
|
|
4218
4043
|
get observeKind() {
|
|
4219
4044
|
return null;
|
|
@@ -4233,12 +4058,11 @@ var Transaction = class {
|
|
|
4233
4058
|
return null;
|
|
4234
4059
|
}
|
|
4235
4060
|
// The path used to apply the mutation. Teleports dynamic-var renders so it lands on
|
|
4236
|
-
// the data's real location (the dispatch `this.path` keeps intermediates).
|
|
4237
|
-
// may override to supply a pre-resolved path (see ResponseEvent's pinned keys).
|
|
4061
|
+
// the data's real location (the dispatch `this.path` keeps intermediates).
|
|
4238
4062
|
getTransactionPath() {
|
|
4239
4063
|
return this.path.toTransactionPath().compact();
|
|
4240
4064
|
}
|
|
4241
|
-
|
|
4065
|
+
run(curRoot, comps) {
|
|
4242
4066
|
const txnPath = this.getTransactionPath();
|
|
4243
4067
|
const curLeaf = txnPath.lookup(curRoot);
|
|
4244
4068
|
const newLeaf = produce(curLeaf, (draft) => {
|
|
@@ -4295,8 +4119,8 @@ var InputEvent = class extends Transaction {
|
|
|
4295
4119
|
}
|
|
4296
4120
|
this.transactor.pushIntent(this.dispatchPath, name, args, rest, this);
|
|
4297
4121
|
}
|
|
4298
|
-
|
|
4299
|
-
return Stack.root(comps, root, this);
|
|
4122
|
+
buildStack(root, comps) {
|
|
4123
|
+
return this.path.toTransactionPath().buildStack(Stack.root(comps, root, this));
|
|
4300
4124
|
}
|
|
4301
4125
|
getHandlerAndArgs(root, _instance, comps) {
|
|
4302
4126
|
const stack = this.buildStack(root, comps);
|
|
@@ -4314,11 +4138,10 @@ var InputEvent = class extends Transaction {
|
|
|
4314
4138
|
}
|
|
4315
4139
|
};
|
|
4316
4140
|
var NameArgsTransaction = class extends Transaction {
|
|
4317
|
-
constructor(path, transactor, name, args, parentTransaction
|
|
4141
|
+
constructor(path, transactor, name, args, parentTransaction) {
|
|
4318
4142
|
super(path, transactor, parentTransaction);
|
|
4319
4143
|
this.name = name;
|
|
4320
4144
|
this.args = args;
|
|
4321
|
-
this.opts = opts;
|
|
4322
4145
|
this.targetPath = path;
|
|
4323
4146
|
}
|
|
4324
4147
|
handlerProp = null;
|
|
@@ -4377,7 +4200,7 @@ var SendEvent = class extends NameArgsTransaction {
|
|
|
4377
4200
|
var IntentEvent = class extends NameArgsTransaction {
|
|
4378
4201
|
handlerProp = "intent";
|
|
4379
4202
|
constructor(path, transactor, walk) {
|
|
4380
|
-
super(path, transactor, walk.name, walk.args, walk.parent
|
|
4203
|
+
super(path, transactor, walk.name, walk.args, walk.parent);
|
|
4381
4204
|
this.walk = walk;
|
|
4382
4205
|
this.targetPath = walk.origin;
|
|
4383
4206
|
}
|
|
@@ -4477,7 +4300,7 @@ var IntentWalk = class {
|
|
|
4477
4300
|
async _runLex(chain, i) {
|
|
4478
4301
|
if (this.ended) return;
|
|
4479
4302
|
if (i >= chain.length) return this.advance();
|
|
4480
|
-
const ctx = new
|
|
4303
|
+
const ctx = new Dispatcher(this.origin, this.transactor, this.parent);
|
|
4481
4304
|
try {
|
|
4482
4305
|
const res = await chain[i].fn.apply(null, [...this.args, ctx]);
|
|
4483
4306
|
if (res === PASS) return this._runLex(chain, i + 1);
|
|
@@ -4530,7 +4353,7 @@ var IntentWalk = class {
|
|
|
4530
4353
|
this.ended = true;
|
|
4531
4354
|
if (name === null) return this.release?.();
|
|
4532
4355
|
const path = this.answerPath ?? this.origin;
|
|
4533
|
-
const t = new SendEvent(path, this.transactor, name, args, this.parent
|
|
4356
|
+
const t = new SendEvent(path, this.transactor, name, args, this.parent);
|
|
4534
4357
|
t._isAnswer = true;
|
|
4535
4358
|
this.transactor.pushTransaction(t);
|
|
4536
4359
|
if (this.release) t.completion.whenSubtreeSettled().then(this.release);
|
|
@@ -4569,7 +4392,7 @@ var Completion = class {
|
|
|
4569
4392
|
this.val = val;
|
|
4570
4393
|
this._selfResolve?.(val);
|
|
4571
4394
|
}
|
|
4572
|
-
// Settle self even when no handler produced a value (
|
|
4395
|
+
// Settle self even when no handler produced a value (undefined-state / throw paths).
|
|
4573
4396
|
ensureSelfSettled() {
|
|
4574
4397
|
if (!this.selfSettled) this.markSelfSettled(this.val);
|
|
4575
4398
|
}
|
|
@@ -4615,12 +4438,64 @@ var Dispatcher = class {
|
|
|
4615
4438
|
get at() {
|
|
4616
4439
|
return new PathChanges(this);
|
|
4617
4440
|
}
|
|
4441
|
+
// The render-time Stack, rebuilt on demand. A handler does not get one: the stack
|
|
4442
|
+
// that evaluated its arguments is a local in getHandlerAndArgs and is gone by the
|
|
4443
|
+
// time the body runs, and send/intent transactions never build one at all. Both
|
|
4444
|
+
// halves it needs are pinned on this ctx, so the `dyn` leg reconstructs it — and
|
|
4445
|
+
// only the `dyn` leg does, which is why this is lazy rather than eager.
|
|
4446
|
+
//
|
|
4447
|
+
// The path is compacted, so per-item binds (`@each`, `@enrich-with`) are not
|
|
4448
|
+
// replayed; provides are pushed on every component frame either way, so a provide
|
|
4449
|
+
// that reads a loop binding is the one case this cannot reproduce faithfully.
|
|
4450
|
+
_stack() {
|
|
4451
|
+
this._stackMemo ??= this.path.toTransactionPath().buildStack(Stack.root(this.transactor.comps, this.root, this.parent));
|
|
4452
|
+
return this._stackMemo;
|
|
4453
|
+
}
|
|
4454
|
+
// Resolve a name the way the renderer would. `opts.route` takes the same legs in
|
|
4455
|
+
// the same spelling as `ctx.intent` — `["dyn"]` the render ancestry, `["lex"]` the
|
|
4456
|
+
// registration scope, default both.
|
|
4457
|
+
lookup(name, opts) {
|
|
4458
|
+
const route = opts?.route ?? DEFAULT_LOOKUP_ROUTE;
|
|
4459
|
+
return routeLookup(
|
|
4460
|
+
route,
|
|
4461
|
+
() => this._lookupLex(name),
|
|
4462
|
+
() => this._stack()?.lookupDynamic(name) ?? null
|
|
4463
|
+
);
|
|
4464
|
+
}
|
|
4465
|
+
// The `lex` leg without a Stack: the scope of the component whose handler is
|
|
4466
|
+
// running, which is the leaf of this ctx's path.
|
|
4467
|
+
_lookupLex(name) {
|
|
4468
|
+
let Comp = null;
|
|
4469
|
+
this.walkPath((c) => {
|
|
4470
|
+
Comp = c;
|
|
4471
|
+
return false;
|
|
4472
|
+
});
|
|
4473
|
+
return Comp?.scope?.lookupComponent(name) ?? null;
|
|
4474
|
+
}
|
|
4475
|
+
// A component lookup is a value lookup constrained to a component. The `lex` leg
|
|
4476
|
+
// can only ever answer with one; the `dyn` leg reads a binding an ancestor
|
|
4477
|
+
// published, so it is the leg that has to be checked.
|
|
4478
|
+
lookupType(name, opts) {
|
|
4479
|
+
const v = this.lookup(name, opts);
|
|
4480
|
+
if (v == null) {
|
|
4481
|
+
this.transactor.refuse("TYPE_NOT_FOUND", {
|
|
4482
|
+
name,
|
|
4483
|
+
route: opts?.route ?? DEFAULT_LOOKUP_ROUTE
|
|
4484
|
+
});
|
|
4485
|
+
return null;
|
|
4486
|
+
}
|
|
4487
|
+
if (v?.[COMPONENT] == null) {
|
|
4488
|
+
this.transactor.refuse("TYPE_NOT_COMPONENT", { name, got: typeof v });
|
|
4489
|
+
return null;
|
|
4490
|
+
}
|
|
4491
|
+
return v;
|
|
4492
|
+
}
|
|
4618
4493
|
// A message is ADDRESSED: it names one component and stops there.
|
|
4619
|
-
send(name, args
|
|
4620
|
-
return this.sendAtPath(this.path, name, args
|
|
4494
|
+
send(name, args) {
|
|
4495
|
+
return this.sendAtPath(this.path, name, args);
|
|
4621
4496
|
}
|
|
4622
|
-
sendAtPath(path, name, args
|
|
4623
|
-
return this.transactor.pushSend(path, name, args,
|
|
4497
|
+
sendAtPath(path, name, args) {
|
|
4498
|
+
return this.transactor.pushSend(path, name, args, this.parent, this.path);
|
|
4624
4499
|
}
|
|
4625
4500
|
// An intent is ROUTED: it names a job and walks until something answers. The verb
|
|
4626
4501
|
// does not decide which scope answers — `opts.route` does, written here at the call
|
|
@@ -4631,9 +4506,6 @@ var Dispatcher = class {
|
|
|
4631
4506
|
intentAtPath(path, name, args, opts) {
|
|
4632
4507
|
return this.transactor.pushIntent(path, name, args, opts, this.parent);
|
|
4633
4508
|
}
|
|
4634
|
-
lookupTypeFor(name, inst) {
|
|
4635
|
-
return this.transactor.comps.getCompFor(inst).scope.lookupComponent(name);
|
|
4636
|
-
}
|
|
4637
4509
|
};
|
|
4638
4510
|
var EventContext = class extends Dispatcher {
|
|
4639
4511
|
get name() {
|
|
@@ -4650,6 +4522,19 @@ var EventContext = class extends Dispatcher {
|
|
|
4650
4522
|
fail(error) {
|
|
4651
4523
|
return this.parent.walk === void 0 ? warnNotIntent("fail") : this.parent.walk.answer("Error", error);
|
|
4652
4524
|
}
|
|
4525
|
+
// Reply to the sender of the MESSAGE being handled. An intent answers under a name
|
|
4526
|
+
// the runtime derives (`<name>Ok`), because the raiser asked a question and declared
|
|
4527
|
+
// arms for it; a message did not, so the replier names the reply itself and the
|
|
4528
|
+
// sender handles it like any other message. Refuses when nobody sent this — a view's
|
|
4529
|
+
// own `@on.*`, or a host sendAtRoot.
|
|
4530
|
+
sendReply(name, args) {
|
|
4531
|
+
const origin = this.parent?.origin ?? null;
|
|
4532
|
+
if (origin == null) {
|
|
4533
|
+
this.transactor.refuse("NO_SENDER", { name });
|
|
4534
|
+
return null;
|
|
4535
|
+
}
|
|
4536
|
+
return this.sendAtPath(origin, name, args);
|
|
4537
|
+
}
|
|
4653
4538
|
// End the walk answering nothing — "served, and no answer".
|
|
4654
4539
|
stop() {
|
|
4655
4540
|
return this.parent.stop();
|
|
@@ -4661,8 +4546,6 @@ var EventContext = class extends Dispatcher {
|
|
|
4661
4546
|
return this.parent.forward(opts);
|
|
4662
4547
|
}
|
|
4663
4548
|
};
|
|
4664
|
-
var IntentContext = class extends Dispatcher {
|
|
4665
|
-
};
|
|
4666
4549
|
function warnNotIntent(verb) {
|
|
4667
4550
|
console.warn(`ctx.${verb}() is only meaningful in an "intent" handler - ignored`);
|
|
4668
4551
|
}
|
|
@@ -4671,8 +4554,8 @@ var PathChanges = class extends PathBuilder {
|
|
|
4671
4554
|
super();
|
|
4672
4555
|
this.dispatcher = dispatcher;
|
|
4673
4556
|
}
|
|
4674
|
-
send(name, args
|
|
4675
|
-
return this.dispatcher.sendAtPath(this.buildPath(), name, args
|
|
4557
|
+
send(name, args) {
|
|
4558
|
+
return this.dispatcher.sendAtPath(this.buildPath(), name, args);
|
|
4676
4559
|
}
|
|
4677
4560
|
intent(name, args, opts) {
|
|
4678
4561
|
return this.dispatcher.intentAtPath(this.buildPath(), name, args, opts);
|
|
@@ -4829,9 +4712,10 @@ var App = class {
|
|
|
4829
4712
|
}
|
|
4830
4713
|
compile() {
|
|
4831
4714
|
for (const Comp of this.comps.byId.values()) {
|
|
4832
|
-
Comp
|
|
4833
|
-
|
|
4834
|
-
|
|
4715
|
+
const meta = Comp[COMPONENT];
|
|
4716
|
+
meta.compile(this.ParseContext);
|
|
4717
|
+
for (const key in meta.views)
|
|
4718
|
+
for (const name of meta.views[key].ctx.genEventNames()) this._eventNames.add(name);
|
|
4835
4719
|
}
|
|
4836
4720
|
this._compiled = true;
|
|
4837
4721
|
}
|
|
@@ -4857,8 +4741,8 @@ var App = class {
|
|
|
4857
4741
|
for (const name of this._eventNames)
|
|
4858
4742
|
this.rootNode.removeEventListener(name, this, listenerOpts(name));
|
|
4859
4743
|
}
|
|
4860
|
-
sendAtRoot(name, args
|
|
4861
|
-
this.transactor.pushSend(new Path([]), name, args
|
|
4744
|
+
sendAtRoot(name, args) {
|
|
4745
|
+
this.transactor.pushSend(new Path([]), name, args);
|
|
4862
4746
|
}
|
|
4863
4747
|
registerComponents(comps, opts) {
|
|
4864
4748
|
const scope = this.compStack.enter();
|
|
@@ -5012,6 +4896,182 @@ function collectAppClassesInSet(app) {
|
|
|
5012
4896
|
return classes;
|
|
5013
4897
|
}
|
|
5014
4898
|
|
|
4899
|
+
// src/cache.js
|
|
4900
|
+
var isWeakKey = (k) => k !== null && (typeof k === "object" || typeof k === "function");
|
|
4901
|
+
var NullDomCache = class {
|
|
4902
|
+
get(_keys, _cacheKey) {
|
|
4903
|
+
}
|
|
4904
|
+
set(_keys, _cacheKey, _v) {
|
|
4905
|
+
}
|
|
4906
|
+
evict() {
|
|
4907
|
+
return { hit: 0, miss: 0, badKey: 0 };
|
|
4908
|
+
}
|
|
4909
|
+
};
|
|
4910
|
+
var WeakMapDomCache = class {
|
|
4911
|
+
constructor() {
|
|
4912
|
+
this.hit = this.miss = this.badKey = 0;
|
|
4913
|
+
this.keysByLen = /* @__PURE__ */ new Map();
|
|
4914
|
+
}
|
|
4915
|
+
_returnValue(r) {
|
|
4916
|
+
if (r === void 0) this.miss += 1;
|
|
4917
|
+
else this.hit += 1;
|
|
4918
|
+
return r;
|
|
4919
|
+
}
|
|
4920
|
+
get(keys, cacheKey) {
|
|
4921
|
+
const len = keys.length;
|
|
4922
|
+
let cur = this.keysByLen.get(len);
|
|
4923
|
+
if (!cur) return this._returnValue(void 0);
|
|
4924
|
+
for (let i = 0; i < len - 1; i++) {
|
|
4925
|
+
cur = cur.get(keys[i]);
|
|
4926
|
+
if (!cur) return this._returnValue(void 0);
|
|
4927
|
+
}
|
|
4928
|
+
return this._returnValue(cur.get(keys[len - 1])?.[cacheKey]);
|
|
4929
|
+
}
|
|
4930
|
+
set(keys, cacheKey, v) {
|
|
4931
|
+
const len = keys.length;
|
|
4932
|
+
let cur = this.keysByLen.get(len);
|
|
4933
|
+
if (!cur) {
|
|
4934
|
+
cur = /* @__PURE__ */ new WeakMap();
|
|
4935
|
+
this.keysByLen.set(len, cur);
|
|
4936
|
+
}
|
|
4937
|
+
for (let i = 0; i < len - 1; i++) {
|
|
4938
|
+
const key = keys[i];
|
|
4939
|
+
let next = cur.get(key);
|
|
4940
|
+
if (!next) {
|
|
4941
|
+
if (!isWeakKey(key)) {
|
|
4942
|
+
this.badKey += 1;
|
|
4943
|
+
return;
|
|
4944
|
+
}
|
|
4945
|
+
next = /* @__PURE__ */ new WeakMap();
|
|
4946
|
+
cur.set(key, next);
|
|
4947
|
+
}
|
|
4948
|
+
cur = next;
|
|
4949
|
+
}
|
|
4950
|
+
const lastKey = keys[len - 1];
|
|
4951
|
+
const leaf = cur.get(lastKey);
|
|
4952
|
+
if (leaf) leaf[cacheKey] = v;
|
|
4953
|
+
else if (isWeakKey(lastKey)) cur.set(lastKey, { [cacheKey]: v });
|
|
4954
|
+
else this.badKey += 1;
|
|
4955
|
+
}
|
|
4956
|
+
evict() {
|
|
4957
|
+
const { hit, miss, badKey } = this;
|
|
4958
|
+
this.hit = this.miss = this.badKey = 0;
|
|
4959
|
+
this.keysByLen = /* @__PURE__ */ new Map();
|
|
4960
|
+
return { hit, miss, badKey };
|
|
4961
|
+
}
|
|
4962
|
+
};
|
|
4963
|
+
|
|
4964
|
+
// src/renderer.js
|
|
4965
|
+
var DATASET_ATTRS = ["nid", "cid", "eid", "vid", "si", "sk"];
|
|
4966
|
+
var Renderer = class {
|
|
4967
|
+
constructor(comps) {
|
|
4968
|
+
this.comps = comps;
|
|
4969
|
+
this.cache = new WeakMapDomCache();
|
|
4970
|
+
this.renderTag = h;
|
|
4971
|
+
}
|
|
4972
|
+
renderFragment(childs) {
|
|
4973
|
+
return new VFragment(childs);
|
|
4974
|
+
}
|
|
4975
|
+
renderComment(text) {
|
|
4976
|
+
return new VComment(text);
|
|
4977
|
+
}
|
|
4978
|
+
setNullCache() {
|
|
4979
|
+
this.cache = new NullDomCache();
|
|
4980
|
+
}
|
|
4981
|
+
renderToDOM(stack, val) {
|
|
4982
|
+
const rootNode = document.createElement("div");
|
|
4983
|
+
const rOpts = { document };
|
|
4984
|
+
render(h("DIV", null, [this.renderRoot(stack, val)]), rootNode, rOpts);
|
|
4985
|
+
return rootNode.childNodes[0];
|
|
4986
|
+
}
|
|
4987
|
+
renderToString(stack, val, cleanAttrs = true) {
|
|
4988
|
+
const dom = this.renderToDOM(stack, val);
|
|
4989
|
+
if (cleanAttrs) {
|
|
4990
|
+
const nodes = dom.querySelectorAll("[data-nid],[data-cid],[data-eid]");
|
|
4991
|
+
for (const { dataset } of nodes) for (const name of DATASET_ATTRS) delete dataset[name];
|
|
4992
|
+
}
|
|
4993
|
+
return dom.innerHTML;
|
|
4994
|
+
}
|
|
4995
|
+
renderRoot(stack, val, viewName = null) {
|
|
4996
|
+
const comp = this.comps.getCompFor(val);
|
|
4997
|
+
if (comp === null) return null;
|
|
4998
|
+
return this._rValComp(stack, val, comp, comp.getView(viewName).anode, "ROOT", viewName);
|
|
4999
|
+
}
|
|
5000
|
+
renderIt(stack, node, key, viewName) {
|
|
5001
|
+
const comp = this.comps.getCompFor(stack.it);
|
|
5002
|
+
return comp ? this._rValComp(stack, stack.it, comp, node, key, viewName) : null;
|
|
5003
|
+
}
|
|
5004
|
+
// `node` is the parse node of the render site (`<x render>` / `render-it` /
|
|
5005
|
+
// `render-each`, or the view's root anode for the app root). It keys the
|
|
5006
|
+
// cache as a globally-unique object: node ids alone are unique only within a
|
|
5007
|
+
// single view, so the same value rendered by two components (e.g. through a
|
|
5008
|
+
// shared dynamic-var sequence) would otherwise collide in the cache.
|
|
5009
|
+
_rValComp(stack, val, comp, node, key, viewName) {
|
|
5010
|
+
const cacheKey = `${viewName ?? ""}${stack.viewsId ?? ""}${key}`;
|
|
5011
|
+
const cachePath = [node, val];
|
|
5012
|
+
stack._pushDynBindValuesToArray(cachePath, comp);
|
|
5013
|
+
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
5014
|
+
if (cachedNode) return cachedNode;
|
|
5015
|
+
const view = viewName ? comp.getView(viewName) : stack.lookupBestView(comp.views, "main");
|
|
5016
|
+
const body = this.renderView(view, stack);
|
|
5017
|
+
if (body == null) return null;
|
|
5018
|
+
const meta = this._renderMetadata({
|
|
5019
|
+
$: "Comp",
|
|
5020
|
+
nid: node?.nodeId ?? null,
|
|
5021
|
+
cid: comp.id,
|
|
5022
|
+
vid: view.name
|
|
5023
|
+
});
|
|
5024
|
+
const dom = new VFragment([meta, body]);
|
|
5025
|
+
this.cache.set(cachePath, cacheKey, dom);
|
|
5026
|
+
return dom;
|
|
5027
|
+
}
|
|
5028
|
+
pushEachEntry(r, nid, attrName, key, dom) {
|
|
5029
|
+
r.push(this._renderMetadata({ $: "Each", nid, [attrName]: key }), dom);
|
|
5030
|
+
}
|
|
5031
|
+
renderEachWhen(stack, iterInfo, view, nid) {
|
|
5032
|
+
const { seq, filter, loopWith, enricher } = iterInfo.eval(stack);
|
|
5033
|
+
const r = [];
|
|
5034
|
+
const it = stack.it;
|
|
5035
|
+
const renderOne = (key, value, attrName, binds) => {
|
|
5036
|
+
const cachePath = enricher ? [view, it, value] : [view, value];
|
|
5037
|
+
const cacheKey = `${stack.viewsId ?? ""}${nid}${key}`;
|
|
5038
|
+
const cachedNode = this.cache.get(cachePath, cacheKey);
|
|
5039
|
+
if (cachedNode) this.pushEachEntry(r, nid, attrName, key, cachedNode);
|
|
5040
|
+
else {
|
|
5041
|
+
const dom = this.renderView(view, stack.enter(value, binds, false));
|
|
5042
|
+
if (dom != null) this.pushEachEntry(r, nid, attrName, key, dom);
|
|
5043
|
+
this.cache.set(cachePath, cacheKey, dom);
|
|
5044
|
+
}
|
|
5045
|
+
};
|
|
5046
|
+
walkLoopBindings(
|
|
5047
|
+
{ seq, it, filter, loopWith, enricher, ctx: makeLoopCtx(stack, filter) },
|
|
5048
|
+
renderOne
|
|
5049
|
+
);
|
|
5050
|
+
return r;
|
|
5051
|
+
}
|
|
5052
|
+
renderView(view, stack) {
|
|
5053
|
+
let n = stack.binds[1];
|
|
5054
|
+
while (n !== null) {
|
|
5055
|
+
const b = n[0];
|
|
5056
|
+
if (b.isFrame) {
|
|
5057
|
+
if (stack.it !== b.it) break;
|
|
5058
|
+
console.error("recursion detected", stack.it, b.it);
|
|
5059
|
+
return new VComment("RECURSION AVOIDED");
|
|
5060
|
+
}
|
|
5061
|
+
n = n[1];
|
|
5062
|
+
}
|
|
5063
|
+
return view.render(stack, this);
|
|
5064
|
+
}
|
|
5065
|
+
_renderMetadata(info) {
|
|
5066
|
+
return new VComment(`§${JSON.stringify(info)}§`);
|
|
5067
|
+
}
|
|
5068
|
+
// Prefix a loop-less @enrich-with subtree with a boundary meta so event-path
|
|
5069
|
+
// reconstruction replays its binds (mirrors the §Each§ / §Comp§ metas).
|
|
5070
|
+
renderScopeMeta(nid, dom) {
|
|
5071
|
+
return new VFragment([this._renderMetadata({ $: "Scope", nid }), dom]);
|
|
5072
|
+
}
|
|
5073
|
+
};
|
|
5074
|
+
|
|
5015
5075
|
// src/on.js
|
|
5016
5076
|
var OP_KINDS = ["send", "intent"];
|
|
5017
5077
|
function phaseOps(phase) {
|
|
@@ -5029,7 +5089,7 @@ function dispatchPhase(dispatcher, targetPath, phase, self) {
|
|
|
5029
5089
|
const args = resolveArgs(op.args, self);
|
|
5030
5090
|
switch (op.type) {
|
|
5031
5091
|
case "send":
|
|
5032
|
-
dispatcher.sendAtPath(targetPath, op.name, args
|
|
5092
|
+
dispatcher.sendAtPath(targetPath, op.name, args);
|
|
5033
5093
|
break;
|
|
5034
5094
|
case "intent":
|
|
5035
5095
|
dispatcher.intentAtPath(targetPath, op.name, args, op.opts);
|