@jxsuite/runtime 1.0.0 → 1.2.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/runtime.js +429 -50
- package/dist/runtime.js.map +9 -8
- package/package.json +4 -3
- package/src/expression.ts +523 -28
- package/src/runtime.ts +189 -11
- package/src/statements.ts +212 -0
package/dist/runtime.js
CHANGED
|
@@ -80,8 +80,9 @@ class EffectScope {
|
|
|
80
80
|
this._isPaused = true;
|
|
81
81
|
let i, l;
|
|
82
82
|
if (this.scopes) {
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
const scopes = this.scopes.slice();
|
|
84
|
+
for (i = 0, l = scopes.length;i < l; i++) {
|
|
85
|
+
scopes[i].pause();
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
for (i = 0, l = this.effects.length;i < l; i++) {
|
|
@@ -95,12 +96,14 @@ class EffectScope {
|
|
|
95
96
|
this._isPaused = false;
|
|
96
97
|
let i, l;
|
|
97
98
|
if (this.scopes) {
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
const scopes = this.scopes.slice();
|
|
100
|
+
for (i = 0, l = scopes.length;i < l; i++) {
|
|
101
|
+
scopes[i].resume();
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
const effects = this.effects.slice();
|
|
105
|
+
for (i = 0, l = effects.length;i < l; i++) {
|
|
106
|
+
effects[i].resume();
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
109
|
}
|
|
@@ -154,8 +157,9 @@ class EffectScope {
|
|
|
154
157
|
}
|
|
155
158
|
this.cleanups.length = 0;
|
|
156
159
|
if (this.scopes) {
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
const scopes = this.scopes.slice();
|
|
161
|
+
for (i = 0, l = scopes.length;i < l; i++) {
|
|
162
|
+
scopes[i].stop(true);
|
|
159
163
|
}
|
|
160
164
|
this.scopes.length = 0;
|
|
161
165
|
}
|
|
@@ -1411,33 +1415,142 @@ var BINARY_OPS = new Set([
|
|
|
1411
1415
|
">",
|
|
1412
1416
|
">=",
|
|
1413
1417
|
"&&",
|
|
1414
|
-
"||"
|
|
1418
|
+
"||",
|
|
1419
|
+
"??"
|
|
1415
1420
|
]);
|
|
1416
1421
|
var ASSIGNMENT_OPS = new Set(["=", "+=", "-=", "*=", "/="]);
|
|
1417
1422
|
var ARRAY_METHOD_OPS = new Set(["push", "pop", "shift", "unshift", "splice"]);
|
|
1418
1423
|
var AGGREGATE_OPS = new Set(["reduce", "map", "filter"]);
|
|
1424
|
+
var CONDITIONAL_OPS = new Set(["?:", "switch"]);
|
|
1425
|
+
var PURE_METHOD_OPS = new Set([
|
|
1426
|
+
"includes",
|
|
1427
|
+
"indexOf",
|
|
1428
|
+
"lastIndexOf",
|
|
1429
|
+
"join",
|
|
1430
|
+
"slice",
|
|
1431
|
+
"concat",
|
|
1432
|
+
"at",
|
|
1433
|
+
"flat",
|
|
1434
|
+
"toSorted",
|
|
1435
|
+
"toReversed",
|
|
1436
|
+
"toSpliced",
|
|
1437
|
+
"with",
|
|
1438
|
+
"toUpperCase",
|
|
1439
|
+
"toLowerCase",
|
|
1440
|
+
"trim",
|
|
1441
|
+
"trimStart",
|
|
1442
|
+
"trimEnd",
|
|
1443
|
+
"split",
|
|
1444
|
+
"startsWith",
|
|
1445
|
+
"endsWith",
|
|
1446
|
+
"padStart",
|
|
1447
|
+
"padEnd",
|
|
1448
|
+
"replaceAll",
|
|
1449
|
+
"repeat",
|
|
1450
|
+
"charAt",
|
|
1451
|
+
"normalize",
|
|
1452
|
+
"toLocaleUpperCase",
|
|
1453
|
+
"toLocaleLowerCase",
|
|
1454
|
+
"toFixed",
|
|
1455
|
+
"toPrecision",
|
|
1456
|
+
"toLocaleString"
|
|
1457
|
+
]);
|
|
1419
1458
|
var BLESSED_OPERATORS = new Set([
|
|
1420
1459
|
...MUTATING_OPS,
|
|
1421
1460
|
...UNARY_OPS,
|
|
1422
1461
|
...BINARY_OPS,
|
|
1423
|
-
...AGGREGATE_OPS
|
|
1462
|
+
...AGGREGATE_OPS,
|
|
1463
|
+
...CONDITIONAL_OPS,
|
|
1464
|
+
...PURE_METHOD_OPS,
|
|
1465
|
+
"call"
|
|
1466
|
+
]);
|
|
1467
|
+
var BLESSED_GLOBALS = new Set([
|
|
1468
|
+
"isNaN",
|
|
1469
|
+
"isFinite",
|
|
1470
|
+
"parseFloat",
|
|
1471
|
+
"parseInt",
|
|
1472
|
+
"encodeURIComponent",
|
|
1473
|
+
"decodeURIComponent",
|
|
1474
|
+
"structuredClone",
|
|
1475
|
+
"Math/abs",
|
|
1476
|
+
"Math/ceil",
|
|
1477
|
+
"Math/floor",
|
|
1478
|
+
"Math/round",
|
|
1479
|
+
"Math/trunc",
|
|
1480
|
+
"Math/sign",
|
|
1481
|
+
"Math/sqrt",
|
|
1482
|
+
"Math/cbrt",
|
|
1483
|
+
"Math/pow",
|
|
1484
|
+
"Math/exp",
|
|
1485
|
+
"Math/log",
|
|
1486
|
+
"Math/log2",
|
|
1487
|
+
"Math/log10",
|
|
1488
|
+
"Math/min",
|
|
1489
|
+
"Math/max",
|
|
1490
|
+
"Math/hypot",
|
|
1491
|
+
"Number/isInteger",
|
|
1492
|
+
"Number/isFinite",
|
|
1493
|
+
"Number/isNaN",
|
|
1494
|
+
"Number/parseFloat",
|
|
1495
|
+
"Number/parseInt",
|
|
1496
|
+
"JSON/parse",
|
|
1497
|
+
"JSON/stringify",
|
|
1498
|
+
"Object/keys",
|
|
1499
|
+
"Object/values",
|
|
1500
|
+
"Object/entries",
|
|
1501
|
+
"Object/fromEntries",
|
|
1502
|
+
"Array/from",
|
|
1503
|
+
"Array/isArray",
|
|
1504
|
+
"Array/of",
|
|
1505
|
+
"String/fromCharCode",
|
|
1506
|
+
"String/fromCodePoint",
|
|
1507
|
+
"Intl/formatNumber",
|
|
1508
|
+
"Intl/formatDate",
|
|
1509
|
+
"Intl/formatRelativeTime"
|
|
1424
1510
|
]);
|
|
1511
|
+
var BLESSED_HELPERS = {
|
|
1512
|
+
"Intl/formatDate": (value, locale, options) => new Intl.DateTimeFormat(locale, options).format(new Date(value)),
|
|
1513
|
+
"Intl/formatNumber": (value, locale, options) => new Intl.NumberFormat(locale, options).format(value),
|
|
1514
|
+
"Intl/formatRelativeTime": (value, unit, locale, options) => new Intl.RelativeTimeFormat(locale, options).format(value, unit)
|
|
1515
|
+
};
|
|
1516
|
+
function isBlessedGlobal(ref2) {
|
|
1517
|
+
return ref2.startsWith("window#/") && BLESSED_GLOBALS.has(ref2.slice("window#/".length));
|
|
1518
|
+
}
|
|
1425
1519
|
function isMutating(op) {
|
|
1426
1520
|
return MUTATING_OPS.has(op);
|
|
1427
1521
|
}
|
|
1428
|
-
|
|
1522
|
+
var MAX_CALL_DEPTH = 64;
|
|
1523
|
+
var MAX_REPORT_DEPTH = 64;
|
|
1524
|
+
function subTrace(trace, seg) {
|
|
1525
|
+
if (!trace) {
|
|
1526
|
+
return;
|
|
1527
|
+
}
|
|
1528
|
+
const depth = (trace.depth ?? 0) + 1;
|
|
1529
|
+
if (depth > MAX_REPORT_DEPTH) {
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
return {
|
|
1533
|
+
depth,
|
|
1534
|
+
path: [...trace.path ?? [], ...Array.isArray(seg) ? seg : [seg]],
|
|
1535
|
+
report: trace.report
|
|
1536
|
+
};
|
|
1537
|
+
}
|
|
1538
|
+
function resolveOperand(operand, state, event, iterCtx, trace) {
|
|
1429
1539
|
if (operand === null || operand === undefined) {
|
|
1430
1540
|
return operand;
|
|
1431
1541
|
}
|
|
1432
1542
|
if (typeof operand === "object" && !Array.isArray(operand) && "operator" in operand) {
|
|
1433
|
-
return evaluateExpression(operand, state, event, iterCtx);
|
|
1543
|
+
return evaluateExpression(operand, state, event, iterCtx, trace);
|
|
1434
1544
|
}
|
|
1435
1545
|
if (typeof operand === "object" && !Array.isArray(operand) && "$ref" in operand) {
|
|
1436
|
-
|
|
1546
|
+
const resolved = resolveExprRef(operand.$ref, state, event, iterCtx);
|
|
1547
|
+
trace?.report(trace.path ?? [], resolved);
|
|
1548
|
+
return resolved;
|
|
1437
1549
|
}
|
|
1438
1550
|
if (Array.isArray(operand)) {
|
|
1439
|
-
return operand.map((o) => resolveOperand(o, state, event, iterCtx));
|
|
1551
|
+
return operand.map((o, i) => resolveOperand(o, state, event, iterCtx, subTrace(trace, i)));
|
|
1440
1552
|
}
|
|
1553
|
+
trace?.report(trace.path ?? [], operand);
|
|
1441
1554
|
return operand;
|
|
1442
1555
|
}
|
|
1443
1556
|
function resolveExprRef(ref2, state, event, iterCtx) {
|
|
@@ -1447,6 +1560,11 @@ function resolveExprRef(ref2, state, event, iterCtx) {
|
|
|
1447
1560
|
if (ref2.startsWith("$reduce/")) {
|
|
1448
1561
|
return iterCtx?.acc;
|
|
1449
1562
|
}
|
|
1563
|
+
if (ref2.startsWith("$args/")) {
|
|
1564
|
+
const parts = ref2.slice("$args/".length).split("/");
|
|
1565
|
+
const base = iterCtx?.args?.[parts[0]];
|
|
1566
|
+
return parts.length > 1 ? getPath(base, parts.slice(1).join("/")) : base;
|
|
1567
|
+
}
|
|
1450
1568
|
if (ref2.startsWith("event#/")) {
|
|
1451
1569
|
const path = ref2.slice("event#/".length);
|
|
1452
1570
|
return getPath(event, path);
|
|
@@ -1524,13 +1642,18 @@ function resolveWritableRef(ref2, state, _event, iterCtx) {
|
|
|
1524
1642
|
}
|
|
1525
1643
|
return { key: ref2, obj: state };
|
|
1526
1644
|
}
|
|
1527
|
-
function evaluateExpression(node, state, event, iterCtx) {
|
|
1645
|
+
function evaluateExpression(node, state, event, iterCtx, trace) {
|
|
1646
|
+
const result = evaluateNode(node, state, event, iterCtx, trace);
|
|
1647
|
+
trace?.report(trace.path ?? [], result);
|
|
1648
|
+
return result;
|
|
1649
|
+
}
|
|
1650
|
+
function evaluateNode(node, state, event, iterCtx, trace) {
|
|
1528
1651
|
const { operator, target, value, initial } = node;
|
|
1529
1652
|
if (!BLESSED_OPERATORS.has(operator)) {
|
|
1530
1653
|
throw new Error(`$expression: unknown operator "${operator}"`);
|
|
1531
1654
|
}
|
|
1532
1655
|
if (UNARY_OPS.has(operator) && !("value" in node)) {
|
|
1533
|
-
const operand = resolveOperand(target, state, event, iterCtx);
|
|
1656
|
+
const operand = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1534
1657
|
if (operator === "!") {
|
|
1535
1658
|
return !operand;
|
|
1536
1659
|
}
|
|
@@ -1538,9 +1661,78 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1538
1661
|
return -operand;
|
|
1539
1662
|
}
|
|
1540
1663
|
}
|
|
1664
|
+
if (operator === "call") {
|
|
1665
|
+
const calleeRef = target?.$ref;
|
|
1666
|
+
if (typeof calleeRef !== "string") {
|
|
1667
|
+
throw new TypeError("$expression: call target must be a $ref pointer");
|
|
1668
|
+
}
|
|
1669
|
+
const callDepth = (iterCtx?.callDepth ?? 0) + 1;
|
|
1670
|
+
if (callDepth > MAX_CALL_DEPTH) {
|
|
1671
|
+
throw new Error(`$expression: call depth exceeded (${MAX_CALL_DEPTH})`);
|
|
1672
|
+
}
|
|
1673
|
+
const argValues = Array.isArray(value) ? value.map((o, i) => resolveOperand(o, state, event, iterCtx, subTrace(trace, ["value", i]))) : [];
|
|
1674
|
+
if (calleeRef.startsWith("window#/")) {
|
|
1675
|
+
if (!isBlessedGlobal(calleeRef)) {
|
|
1676
|
+
throw new Error(`$expression: "${calleeRef}" is not a blessed pure global`);
|
|
1677
|
+
}
|
|
1678
|
+
const globalPath = calleeRef.slice("window#/".length);
|
|
1679
|
+
const helper = BLESSED_HELPERS[globalPath];
|
|
1680
|
+
if (helper) {
|
|
1681
|
+
return helper(...argValues);
|
|
1682
|
+
}
|
|
1683
|
+
const fn = getPath(globalThis.window, globalPath);
|
|
1684
|
+
const lastSlash = globalPath.lastIndexOf("/");
|
|
1685
|
+
const thisArg = lastSlash === -1 ? globalThis.window : getPath(globalThis.window, globalPath.slice(0, lastSlash));
|
|
1686
|
+
return fn.apply(thisArg, argValues);
|
|
1687
|
+
}
|
|
1688
|
+
const callee = resolveExprRef(calleeRef, state, event, iterCtx);
|
|
1689
|
+
if (typeof callee === "function") {
|
|
1690
|
+
return callee(...argValues);
|
|
1691
|
+
}
|
|
1692
|
+
if (callee && typeof callee === "object" && "$expression" in callee) {
|
|
1693
|
+
const def2 = callee;
|
|
1694
|
+
const args = {};
|
|
1695
|
+
for (const [i, p] of (def2.parameters ?? []).entries()) {
|
|
1696
|
+
const name = typeof p === "string" ? p : p?.name ?? "";
|
|
1697
|
+
if (!name) {
|
|
1698
|
+
continue;
|
|
1699
|
+
}
|
|
1700
|
+
args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
|
|
1701
|
+
}
|
|
1702
|
+
return evaluateExpression(def2.$expression, state, event, { args, callDepth });
|
|
1703
|
+
}
|
|
1704
|
+
throw new TypeError(`$expression: call target "${calleeRef}" is not callable`);
|
|
1705
|
+
}
|
|
1706
|
+
if (CONDITIONAL_OPS.has(operator)) {
|
|
1707
|
+
if (operator === "?:") {
|
|
1708
|
+
const test = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1709
|
+
if (trace) {
|
|
1710
|
+
const consequent = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
|
|
1711
|
+
const alternate = resolveOperand(initial, state, event, iterCtx, subTrace(trace, "initial"));
|
|
1712
|
+
return test ? consequent : alternate;
|
|
1713
|
+
}
|
|
1714
|
+
return test ? resolveOperand(value, state, event, iterCtx) : resolveOperand(initial, state, event, iterCtx);
|
|
1715
|
+
}
|
|
1716
|
+
const discriminant = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1717
|
+
const key = String(discriminant);
|
|
1718
|
+
const cases = node.cases ?? {};
|
|
1719
|
+
const matched = Object.hasOwn(cases, key);
|
|
1720
|
+
if (trace) {
|
|
1721
|
+
let result;
|
|
1722
|
+
for (const [k, caseOperand] of Object.entries(cases)) {
|
|
1723
|
+
const v = resolveOperand(caseOperand, state, event, iterCtx, subTrace(trace, ["cases", k]));
|
|
1724
|
+
if (k === key) {
|
|
1725
|
+
result = v;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
const fallback = resolveOperand(node.default, state, event, iterCtx, subTrace(trace, "default"));
|
|
1729
|
+
return matched ? result : fallback;
|
|
1730
|
+
}
|
|
1731
|
+
return matched ? resolveOperand(cases[key], state, event, iterCtx) : resolveOperand(node.default, state, event, iterCtx);
|
|
1732
|
+
}
|
|
1541
1733
|
if (BINARY_OPS.has(operator)) {
|
|
1542
|
-
const left = resolveOperand(target, state, event, iterCtx);
|
|
1543
|
-
const right = resolveOperand(value, state, event, iterCtx);
|
|
1734
|
+
const left = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1735
|
+
const right = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
|
|
1544
1736
|
switch (operator) {
|
|
1545
1737
|
case "+": {
|
|
1546
1738
|
return left + right;
|
|
@@ -1581,13 +1773,16 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1581
1773
|
case "||": {
|
|
1582
1774
|
return left || right;
|
|
1583
1775
|
}
|
|
1776
|
+
case "??": {
|
|
1777
|
+
return left ?? right;
|
|
1778
|
+
}
|
|
1584
1779
|
default: {
|
|
1585
1780
|
break;
|
|
1586
1781
|
}
|
|
1587
1782
|
}
|
|
1588
1783
|
}
|
|
1589
1784
|
if (ASSIGNMENT_OPS.has(operator)) {
|
|
1590
|
-
const rhs = resolveOperand(value, state, event, iterCtx);
|
|
1785
|
+
const rhs = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
|
|
1591
1786
|
const { obj, key } = resolveWritableRef(target.$ref, state, event, iterCtx);
|
|
1592
1787
|
switch (operator) {
|
|
1593
1788
|
case "=": {
|
|
@@ -1621,13 +1816,13 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1621
1816
|
return;
|
|
1622
1817
|
}
|
|
1623
1818
|
if (ARRAY_METHOD_OPS.has(operator)) {
|
|
1624
|
-
const arr = resolveOperand(target, state, event, iterCtx);
|
|
1819
|
+
const arr = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1625
1820
|
switch (operator) {
|
|
1626
1821
|
case "push": {
|
|
1627
|
-
return arr.push(resolveOperand(value, state, event, iterCtx));
|
|
1822
|
+
return arr.push(resolveOperand(value, state, event, iterCtx, subTrace(trace, "value")));
|
|
1628
1823
|
}
|
|
1629
1824
|
case "unshift": {
|
|
1630
|
-
return arr.unshift(resolveOperand(value, state, event, iterCtx));
|
|
1825
|
+
return arr.unshift(resolveOperand(value, state, event, iterCtx, subTrace(trace, "value")));
|
|
1631
1826
|
}
|
|
1632
1827
|
case "pop": {
|
|
1633
1828
|
return arr.pop();
|
|
@@ -1636,7 +1831,7 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1636
1831
|
return arr.shift();
|
|
1637
1832
|
}
|
|
1638
1833
|
case "splice": {
|
|
1639
|
-
const args = resolveOperand(value, state, event, iterCtx);
|
|
1834
|
+
const args = resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"));
|
|
1640
1835
|
return arr.splice(...args);
|
|
1641
1836
|
}
|
|
1642
1837
|
default: {
|
|
@@ -1644,32 +1839,29 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1644
1839
|
}
|
|
1645
1840
|
}
|
|
1646
1841
|
}
|
|
1842
|
+
if (PURE_METHOD_OPS.has(operator)) {
|
|
1843
|
+
const receiver = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1844
|
+
const args = value === undefined ? [] : Array.isArray(value) ? resolveOperand(value, state, event, iterCtx, subTrace(trace, "value")) : [resolveOperand(value, state, event, iterCtx, subTrace(trace, "value"))];
|
|
1845
|
+
const method = receiver?.[operator];
|
|
1846
|
+
if (typeof method !== "function") {
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
return method.apply(receiver, args);
|
|
1850
|
+
}
|
|
1647
1851
|
if (AGGREGATE_OPS.has(operator)) {
|
|
1648
|
-
const arr = resolveOperand(target, state, event, iterCtx);
|
|
1852
|
+
const arr = resolveOperand(target, state, event, iterCtx, subTrace(trace, "target"));
|
|
1649
1853
|
if (operator === "reduce") {
|
|
1650
|
-
let acc = resolveOperand(initial, state, event, iterCtx);
|
|
1854
|
+
let acc = resolveOperand(initial, state, event, iterCtx, subTrace(trace, "initial"));
|
|
1651
1855
|
for (const [index, item] of arr.entries()) {
|
|
1652
|
-
acc = evaluateExpression(value, state, event, {
|
|
1653
|
-
acc,
|
|
1654
|
-
index,
|
|
1655
|
-
item
|
|
1656
|
-
});
|
|
1856
|
+
acc = evaluateExpression(value, state, event, { acc, index, item }, index === 0 ? subTrace(trace, "value") : undefined);
|
|
1657
1857
|
}
|
|
1658
1858
|
return acc;
|
|
1659
1859
|
}
|
|
1660
1860
|
if (operator === "map") {
|
|
1661
|
-
return arr.map((item, index) => evaluateExpression(value, state, event, {
|
|
1662
|
-
...iterCtx,
|
|
1663
|
-
index,
|
|
1664
|
-
item
|
|
1665
|
-
}));
|
|
1861
|
+
return arr.map((item, index) => evaluateExpression(value, state, event, { ...iterCtx, index, item }, index === 0 ? subTrace(trace, "value") : undefined));
|
|
1666
1862
|
}
|
|
1667
1863
|
if (operator === "filter") {
|
|
1668
|
-
return arr.filter((item, index) => evaluateExpression(value, state, event, {
|
|
1669
|
-
...iterCtx,
|
|
1670
|
-
index,
|
|
1671
|
-
item
|
|
1672
|
-
}));
|
|
1864
|
+
return arr.filter((item, index) => evaluateExpression(value, state, event, { ...iterCtx, index, item }, index === 0 ? subTrace(trace, "value") : undefined));
|
|
1673
1865
|
}
|
|
1674
1866
|
}
|
|
1675
1867
|
return;
|
|
@@ -1681,6 +1873,9 @@ function getPath(obj, path) {
|
|
|
1681
1873
|
}
|
|
1682
1874
|
return current;
|
|
1683
1875
|
}
|
|
1876
|
+
function evaluateOperand(operand, state, event, iterCtx) {
|
|
1877
|
+
return resolveOperand(operand, state, event, iterCtx);
|
|
1878
|
+
}
|
|
1684
1879
|
|
|
1685
1880
|
// ../schema/src/guards.ts
|
|
1686
1881
|
function isJsonObject(value) {
|
|
@@ -1695,6 +1890,12 @@ function isFunctionDef(value) {
|
|
|
1695
1890
|
function isExpressionDef(value) {
|
|
1696
1891
|
return isJsonObject(value) && isJsonObject(value.$expression);
|
|
1697
1892
|
}
|
|
1893
|
+
function isNamedFormulaDef(value) {
|
|
1894
|
+
return isExpressionDef(value) && Array.isArray(value.parameters) && value.parameters.length > 0;
|
|
1895
|
+
}
|
|
1896
|
+
function hasStructuredBody(value) {
|
|
1897
|
+
return isFunctionDef(value) && Array.isArray(value.body);
|
|
1898
|
+
}
|
|
1698
1899
|
function isPrototypeDef(value) {
|
|
1699
1900
|
return isJsonObject(value) && typeof value.$prototype === "string" && value.$prototype !== "Function";
|
|
1700
1901
|
}
|
|
@@ -1727,6 +1928,74 @@ function paramNames(parameters) {
|
|
|
1727
1928
|
return parameters.map((p) => typeof p === "string" ? p : p.name);
|
|
1728
1929
|
}
|
|
1729
1930
|
|
|
1931
|
+
// src/statements.ts
|
|
1932
|
+
function statementKind(statement) {
|
|
1933
|
+
if ("operator" in statement) {
|
|
1934
|
+
return "expression";
|
|
1935
|
+
}
|
|
1936
|
+
if ("if" in statement) {
|
|
1937
|
+
return "if";
|
|
1938
|
+
}
|
|
1939
|
+
if ("$switch" in statement) {
|
|
1940
|
+
return "switch";
|
|
1941
|
+
}
|
|
1942
|
+
return "dispatch";
|
|
1943
|
+
}
|
|
1944
|
+
async function runStatements(statements, state, event, opts = {}) {
|
|
1945
|
+
const iterCtx = opts.args ? { args: opts.args } : undefined;
|
|
1946
|
+
for (const statement of statements) {
|
|
1947
|
+
switch (statementKind(statement)) {
|
|
1948
|
+
case "expression": {
|
|
1949
|
+
const result = evaluateExpression(statement, state, event, iterCtx);
|
|
1950
|
+
if (result && typeof result.then === "function") {
|
|
1951
|
+
await result;
|
|
1952
|
+
}
|
|
1953
|
+
break;
|
|
1954
|
+
}
|
|
1955
|
+
case "if": {
|
|
1956
|
+
const branch = statement;
|
|
1957
|
+
const taken = evaluateOperand(branch.if, state, event, iterCtx) ? branch.then : branch.else;
|
|
1958
|
+
if (Array.isArray(taken)) {
|
|
1959
|
+
await runStatements(taken, state, event, opts);
|
|
1960
|
+
}
|
|
1961
|
+
break;
|
|
1962
|
+
}
|
|
1963
|
+
case "switch": {
|
|
1964
|
+
const branch = statement;
|
|
1965
|
+
const key = String(evaluateOperand(branch.$switch, state, event, iterCtx));
|
|
1966
|
+
const cases = branch.cases ?? {};
|
|
1967
|
+
const taken = Object.hasOwn(cases, key) ? cases[key] : branch.default;
|
|
1968
|
+
if (Array.isArray(taken)) {
|
|
1969
|
+
await runStatements(taken, state, event, opts);
|
|
1970
|
+
}
|
|
1971
|
+
break;
|
|
1972
|
+
}
|
|
1973
|
+
case "dispatch": {
|
|
1974
|
+
const dispatch = statement;
|
|
1975
|
+
const target = opts.target ?? event?.currentTarget;
|
|
1976
|
+
if (!target) {
|
|
1977
|
+
break;
|
|
1978
|
+
}
|
|
1979
|
+
const init = {};
|
|
1980
|
+
if ("detail" in dispatch) {
|
|
1981
|
+
init.detail = evaluateOperand(dispatch.detail, state, event, iterCtx);
|
|
1982
|
+
}
|
|
1983
|
+
if (dispatch.bubbles !== undefined) {
|
|
1984
|
+
init.bubbles = dispatch.bubbles;
|
|
1985
|
+
}
|
|
1986
|
+
if (dispatch.composed !== undefined) {
|
|
1987
|
+
init.composed = dispatch.composed;
|
|
1988
|
+
}
|
|
1989
|
+
target.dispatchEvent(new CustomEvent(dispatch.dispatchEvent, init));
|
|
1990
|
+
break;
|
|
1991
|
+
}
|
|
1992
|
+
default: {
|
|
1993
|
+
break;
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1730
1999
|
// src/runtime.ts
|
|
1731
2000
|
async function Jx(source, target = document.body, options) {
|
|
1732
2001
|
const base = typeof source === "string" ? new URL(source, location.href).href : location.href;
|
|
@@ -1835,6 +2104,37 @@ function canvasAttrName(el, key) {
|
|
|
1835
2104
|
}
|
|
1836
2105
|
return key;
|
|
1837
2106
|
}
|
|
2107
|
+
var _stampPropBindings = false;
|
|
2108
|
+
function setStampPropBindings(on) {
|
|
2109
|
+
_stampPropBindings = on;
|
|
2110
|
+
}
|
|
2111
|
+
var PURE_STATE_TEMPLATE = /^\s*\$\{\s*state\.(\w+)\s*\}\s*$/;
|
|
2112
|
+
function boundPropKey(key, val, state) {
|
|
2113
|
+
if (!_stampPropBindings || key !== "textContent") {
|
|
2114
|
+
return null;
|
|
2115
|
+
}
|
|
2116
|
+
let sub = null;
|
|
2117
|
+
if (isRefObj(val)) {
|
|
2118
|
+
if (!val.$ref.startsWith("#/state/")) {
|
|
2119
|
+
return null;
|
|
2120
|
+
}
|
|
2121
|
+
const rest = val.$ref.slice("#/state/".length);
|
|
2122
|
+
sub = rest && !rest.includes("/") ? rest : null;
|
|
2123
|
+
} else if (typeof val === "string") {
|
|
2124
|
+
sub = PURE_STATE_TEMPLATE.exec(val)?.[1] ?? null;
|
|
2125
|
+
}
|
|
2126
|
+
if (!sub) {
|
|
2127
|
+
return null;
|
|
2128
|
+
}
|
|
2129
|
+
const stored = toRaw(state)[sub];
|
|
2130
|
+
if (isRef(stored) || typeof stored === "function") {
|
|
2131
|
+
return null;
|
|
2132
|
+
}
|
|
2133
|
+
if (typeof stored === "object" && stored !== null) {
|
|
2134
|
+
return null;
|
|
2135
|
+
}
|
|
2136
|
+
return sub;
|
|
2137
|
+
}
|
|
1838
2138
|
async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
1839
2139
|
const raw = {};
|
|
1840
2140
|
for (const [key, val] of Object.entries(parentScope)) {
|
|
@@ -1898,7 +2198,20 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1898
2198
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1899
2199
|
if (isExpressionDef(def2)) {
|
|
1900
2200
|
const node = def2.$expression;
|
|
1901
|
-
if (
|
|
2201
|
+
if (isNamedFormulaDef(def2)) {
|
|
2202
|
+
const params = def2.parameters;
|
|
2203
|
+
state[key] = (...argValues) => {
|
|
2204
|
+
const args = {};
|
|
2205
|
+
for (const [i, p] of params.entries()) {
|
|
2206
|
+
const name = typeof p === "string" ? p : p?.name ?? "";
|
|
2207
|
+
if (!name) {
|
|
2208
|
+
continue;
|
|
2209
|
+
}
|
|
2210
|
+
args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
|
|
2211
|
+
}
|
|
2212
|
+
return evaluateExpression(node, state, null, { args });
|
|
2213
|
+
};
|
|
2214
|
+
} else if (isMutating(node.operator)) {
|
|
1902
2215
|
const handler = (s, event) => evaluateExpression(node, s, event);
|
|
1903
2216
|
state[key] = handler;
|
|
1904
2217
|
} else {
|
|
@@ -1907,7 +2220,28 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1907
2220
|
}
|
|
1908
2221
|
}
|
|
1909
2222
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1910
|
-
if (
|
|
2223
|
+
if (hasStructuredBody(def2)) {
|
|
2224
|
+
const { body } = def2;
|
|
2225
|
+
if (Array.isArray(def2.parameters) && def2.parameters.length > 0) {
|
|
2226
|
+
const params = def2.parameters;
|
|
2227
|
+
state[key] = (...argValues) => {
|
|
2228
|
+
const args = {};
|
|
2229
|
+
for (const [i, p] of params.entries()) {
|
|
2230
|
+
const name = typeof p === "string" ? p : p?.name ?? "";
|
|
2231
|
+
if (!name) {
|
|
2232
|
+
continue;
|
|
2233
|
+
}
|
|
2234
|
+
args[name] = argValues[i] === undefined && typeof p === "object" && p !== null && "default" in p ? p.default : argValues[i];
|
|
2235
|
+
}
|
|
2236
|
+
return runStatements(body, state, null, { args });
|
|
2237
|
+
};
|
|
2238
|
+
} else {
|
|
2239
|
+
const handler = (s, event) => {
|
|
2240
|
+
runStatements(body, s, event ?? null);
|
|
2241
|
+
};
|
|
2242
|
+
state[key] = handler;
|
|
2243
|
+
}
|
|
2244
|
+
} else if (isFunctionDef(def2)) {
|
|
1911
2245
|
state[key] = await resolveFunction(def2, state, key, base);
|
|
1912
2246
|
}
|
|
1913
2247
|
}
|
|
@@ -1958,7 +2292,7 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
1958
2292
|
return noop;
|
|
1959
2293
|
}
|
|
1960
2294
|
let fn;
|
|
1961
|
-
if (def2.body) {
|
|
2295
|
+
if (typeof def2.body === "string") {
|
|
1962
2296
|
const params = resolveParamNames(def2);
|
|
1963
2297
|
fn = new Function(...params, def2.body);
|
|
1964
2298
|
Object.defineProperty(fn, "name", {
|
|
@@ -1996,7 +2330,7 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
1996
2330
|
const hasParams = (def2.parameters ?? def2.arguments ?? []).length > 0;
|
|
1997
2331
|
let isComputed = false;
|
|
1998
2332
|
if (!hasParams) {
|
|
1999
|
-
if (def2.body) {
|
|
2333
|
+
if (typeof def2.body === "string") {
|
|
2000
2334
|
isComputed = /\breturn\b/.test(def2.body);
|
|
2001
2335
|
} else if (fn) {
|
|
2002
2336
|
isComputed = fn.length <= 1 && /\breturn\b/.test(fn.toString());
|
|
@@ -2122,7 +2456,15 @@ function applyProperties(el, def2, state) {
|
|
|
2122
2456
|
}
|
|
2123
2457
|
continue;
|
|
2124
2458
|
}
|
|
2125
|
-
if (
|
|
2459
|
+
if (hasStructuredBody(val)) {
|
|
2460
|
+
const { body } = val;
|
|
2461
|
+
const scope = state;
|
|
2462
|
+
el.addEventListener(key.slice(2), (e) => {
|
|
2463
|
+
runStatements(body, scope, e);
|
|
2464
|
+
});
|
|
2465
|
+
continue;
|
|
2466
|
+
}
|
|
2467
|
+
if (isFunctionDef(val) && typeof val.body === "string") {
|
|
2126
2468
|
const params = resolveParamNames(val);
|
|
2127
2469
|
const fn = new Function(...params, val.body);
|
|
2128
2470
|
const scope = state;
|
|
@@ -2141,6 +2483,10 @@ function applyProperties(el, def2, state) {
|
|
|
2141
2483
|
}
|
|
2142
2484
|
function bindProperty(el, key, val, state) {
|
|
2143
2485
|
const target = el;
|
|
2486
|
+
const boundProp = boundPropKey(key, val, state);
|
|
2487
|
+
if (boundProp) {
|
|
2488
|
+
el.dataset.jxBoundProp = boundProp;
|
|
2489
|
+
}
|
|
2144
2490
|
if (isRefObj(val)) {
|
|
2145
2491
|
const refVal = val;
|
|
2146
2492
|
if (key === "id") {
|
|
@@ -2264,11 +2610,21 @@ function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
|
|
|
2264
2610
|
if (key === "@--") {
|
|
2265
2611
|
continue;
|
|
2266
2612
|
}
|
|
2267
|
-
const
|
|
2613
|
+
const query = key.startsWith("@--") ? mediaQueries[key.slice(1)] ?? key.slice(1) : key.startsWith("@(") ? key.slice(1) : null;
|
|
2614
|
+
const atRule = query === null ? key : `@media ${query}`;
|
|
2268
2615
|
const scope = `[data-jx="${uid}"]`;
|
|
2269
|
-
|
|
2616
|
+
const scheme = query === null ? null : pureSchemeOf(query);
|
|
2617
|
+
if (scheme) {
|
|
2618
|
+
const { auto, forced } = schemeSelectors(scope, scheme);
|
|
2619
|
+
css += `${atRule} { ${auto} { ${toCSSText(rules)} } }
|
|
2620
|
+
`;
|
|
2621
|
+
emitMediaNested(atRule, auto, rules);
|
|
2622
|
+
emitNested(forced, rules);
|
|
2623
|
+
} else {
|
|
2624
|
+
css += `${atRule} { ${scope} { ${toCSSText(rules)} } }
|
|
2270
2625
|
`;
|
|
2271
|
-
|
|
2626
|
+
emitMediaNested(atRule, scope, rules);
|
|
2627
|
+
}
|
|
2272
2628
|
}
|
|
2273
2629
|
const tag = document.createElement("style");
|
|
2274
2630
|
tag.textContent = css;
|
|
@@ -2959,6 +3315,24 @@ function camelToKebab(s) {
|
|
|
2959
3315
|
function toCSSText(rules) {
|
|
2960
3316
|
return Object.entries(rules).filter(([k, v]) => !isNestedSelector(k) && (v === null || typeof v !== "object")).map(([p, v]) => `${camelToKebab(p)}: ${transposeCanvasUnits(String(v))}`).join("; ");
|
|
2961
3317
|
}
|
|
3318
|
+
var COLOR_SCHEME_ATTR = "data-color-scheme";
|
|
3319
|
+
var COLOR_SCHEME_STORAGE_KEY = "jx-color-scheme";
|
|
3320
|
+
function pureSchemeOf(query) {
|
|
3321
|
+
const m = /^\(\s*prefers-color-scheme\s*:\s*(light|dark)\s*\)$/.exec(query.trim());
|
|
3322
|
+
return m?.[1] ?? null;
|
|
3323
|
+
}
|
|
3324
|
+
function schemeSelectors(selector, scheme) {
|
|
3325
|
+
if (selector === ":root" || selector === "html") {
|
|
3326
|
+
return {
|
|
3327
|
+
auto: `${selector}:where(:not([${COLOR_SCHEME_ATTR}]))`,
|
|
3328
|
+
forced: `${selector}:where([${COLOR_SCHEME_ATTR}="${scheme}"])`
|
|
3329
|
+
};
|
|
3330
|
+
}
|
|
3331
|
+
return {
|
|
3332
|
+
auto: `:where(:root:not([${COLOR_SCHEME_ATTR}])) ${selector}`,
|
|
3333
|
+
forced: `:where(:root[${COLOR_SCHEME_ATTR}="${scheme}"]) ${selector}`
|
|
3334
|
+
};
|
|
3335
|
+
}
|
|
2962
3336
|
var _rootMedia = {};
|
|
2963
3337
|
var _elementDefs = new Map;
|
|
2964
3338
|
function setRootMedia(map) {
|
|
@@ -3207,18 +3581,21 @@ function distributeSlots(host, slottedChildren) {
|
|
|
3207
3581
|
export {
|
|
3208
3582
|
transposeCanvasUnits,
|
|
3209
3583
|
toCSSText,
|
|
3584
|
+
setStampPropBindings,
|
|
3210
3585
|
setSkipServerFunctions,
|
|
3211
3586
|
setSkipContentResolution,
|
|
3212
3587
|
setRootMedia,
|
|
3213
3588
|
setResolveToken,
|
|
3214
3589
|
setCanvasViewportTranspose,
|
|
3215
3590
|
setCanvasDelinkAnchors,
|
|
3591
|
+
schemeSelectors,
|
|
3216
3592
|
runScoped,
|
|
3217
3593
|
resolveRef,
|
|
3218
3594
|
resolvePrototype,
|
|
3219
3595
|
resolve,
|
|
3220
3596
|
renderNode,
|
|
3221
3597
|
reapplyStyle,
|
|
3598
|
+
pureSchemeOf,
|
|
3222
3599
|
observeScope,
|
|
3223
3600
|
isSignal,
|
|
3224
3601
|
hasSchemaKeywords,
|
|
@@ -3228,8 +3605,10 @@ export {
|
|
|
3228
3605
|
buildScope,
|
|
3229
3606
|
applyStyle,
|
|
3230
3607
|
RESERVED_KEYS,
|
|
3231
|
-
Jx
|
|
3608
|
+
Jx,
|
|
3609
|
+
COLOR_SCHEME_STORAGE_KEY,
|
|
3610
|
+
COLOR_SCHEME_ATTR
|
|
3232
3611
|
};
|
|
3233
3612
|
|
|
3234
|
-
//# debugId=
|
|
3613
|
+
//# debugId=3EA9DEC405191B1B64756E2164756E21
|
|
3235
3614
|
//# sourceMappingURL=runtime.js.map
|