@jxsuite/runtime 0.22.1 → 0.23.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 +277 -9
- package/dist/runtime.js.map +5 -4
- package/package.json +3 -2
- package/src/expression.js +469 -0
- package/src/runtime.js +49 -3
package/dist/runtime.js
CHANGED
|
@@ -1258,6 +1258,239 @@ function computed(getterOrOptions, debugOptions, isSSR = false) {
|
|
|
1258
1258
|
return cRef;
|
|
1259
1259
|
}
|
|
1260
1260
|
|
|
1261
|
+
// src/expression.js
|
|
1262
|
+
var MUTATING_OPS = new Set([
|
|
1263
|
+
"=",
|
|
1264
|
+
"+=",
|
|
1265
|
+
"-=",
|
|
1266
|
+
"*=",
|
|
1267
|
+
"/=",
|
|
1268
|
+
"push",
|
|
1269
|
+
"pop",
|
|
1270
|
+
"shift",
|
|
1271
|
+
"unshift",
|
|
1272
|
+
"splice"
|
|
1273
|
+
]);
|
|
1274
|
+
var UNARY_OPS = new Set(["!", "-"]);
|
|
1275
|
+
var BINARY_OPS = new Set([
|
|
1276
|
+
"+",
|
|
1277
|
+
"-",
|
|
1278
|
+
"*",
|
|
1279
|
+
"/",
|
|
1280
|
+
"%",
|
|
1281
|
+
"===",
|
|
1282
|
+
"!==",
|
|
1283
|
+
"<",
|
|
1284
|
+
"<=",
|
|
1285
|
+
">",
|
|
1286
|
+
">=",
|
|
1287
|
+
"&&",
|
|
1288
|
+
"||"
|
|
1289
|
+
]);
|
|
1290
|
+
var ASSIGNMENT_OPS = new Set(["=", "+=", "-=", "*=", "/="]);
|
|
1291
|
+
var ARRAY_METHOD_OPS = new Set(["push", "pop", "shift", "unshift", "splice"]);
|
|
1292
|
+
var AGGREGATE_OPS = new Set(["reduce", "map", "filter"]);
|
|
1293
|
+
var BLESSED_OPERATORS = new Set([
|
|
1294
|
+
...MUTATING_OPS,
|
|
1295
|
+
...UNARY_OPS,
|
|
1296
|
+
...BINARY_OPS,
|
|
1297
|
+
...AGGREGATE_OPS
|
|
1298
|
+
]);
|
|
1299
|
+
function isMutating(op) {
|
|
1300
|
+
return MUTATING_OPS.has(op);
|
|
1301
|
+
}
|
|
1302
|
+
function resolveOperand(operand, state, event, iterCtx) {
|
|
1303
|
+
if (operand === null || operand === undefined)
|
|
1304
|
+
return operand;
|
|
1305
|
+
if (typeof operand === "object" && !Array.isArray(operand) && "operator" in operand) {
|
|
1306
|
+
return evaluateExpression(operand, state, event, iterCtx);
|
|
1307
|
+
}
|
|
1308
|
+
if (typeof operand === "object" && !Array.isArray(operand) && "$ref" in operand) {
|
|
1309
|
+
return resolveExprRef(operand.$ref, state, event, iterCtx);
|
|
1310
|
+
}
|
|
1311
|
+
if (Array.isArray(operand)) {
|
|
1312
|
+
return operand.map((o) => resolveOperand(o, state, event, iterCtx));
|
|
1313
|
+
}
|
|
1314
|
+
return operand;
|
|
1315
|
+
}
|
|
1316
|
+
function resolveExprRef(ref2, state, event, iterCtx) {
|
|
1317
|
+
if (ref2 === "$reduce/acc") {
|
|
1318
|
+
return iterCtx?.acc;
|
|
1319
|
+
}
|
|
1320
|
+
if (ref2.startsWith("$reduce/")) {
|
|
1321
|
+
return iterCtx?.acc;
|
|
1322
|
+
}
|
|
1323
|
+
if (ref2.startsWith("event#/")) {
|
|
1324
|
+
const path = ref2.slice("event#/".length);
|
|
1325
|
+
return getPath(event, path);
|
|
1326
|
+
}
|
|
1327
|
+
if (ref2.startsWith("$map/")) {
|
|
1328
|
+
const parts = ref2.split("/");
|
|
1329
|
+
const key = parts[1];
|
|
1330
|
+
let base;
|
|
1331
|
+
if (key === "item")
|
|
1332
|
+
base = iterCtx?.item ?? state.$map?.item ?? state["$map/item"];
|
|
1333
|
+
else if (key === "index")
|
|
1334
|
+
base = iterCtx?.index ?? state.$map?.index ?? state["$map/index"];
|
|
1335
|
+
else
|
|
1336
|
+
base = state.$map?.[key] ?? state["$map/" + key];
|
|
1337
|
+
return parts.length > 2 ? getPath(base, parts.slice(2).join("/")) : base;
|
|
1338
|
+
}
|
|
1339
|
+
if (ref2.startsWith("#/state/")) {
|
|
1340
|
+
const sub = ref2.slice("#/state/".length);
|
|
1341
|
+
const slash = sub.indexOf("/");
|
|
1342
|
+
if (slash < 0)
|
|
1343
|
+
return state[sub];
|
|
1344
|
+
return getPath(state[sub.slice(0, slash)], sub.slice(slash + 1));
|
|
1345
|
+
}
|
|
1346
|
+
if (ref2.startsWith("parent#/"))
|
|
1347
|
+
return state[ref2.slice("parent#/".length)];
|
|
1348
|
+
if (ref2.startsWith("window#/"))
|
|
1349
|
+
return getPath(globalThis.window, ref2.slice("window#/".length));
|
|
1350
|
+
if (ref2.startsWith("document#/"))
|
|
1351
|
+
return getPath(globalThis.document, ref2.slice("document#/".length));
|
|
1352
|
+
return state[ref2] ?? null;
|
|
1353
|
+
}
|
|
1354
|
+
function resolveWritableRef(ref2, state, event, iterCtx) {
|
|
1355
|
+
if (ref2.startsWith("$map/")) {
|
|
1356
|
+
const parts = ref2.split("/");
|
|
1357
|
+
const key = parts[1];
|
|
1358
|
+
let base;
|
|
1359
|
+
if (key === "item")
|
|
1360
|
+
base = iterCtx?.item ?? state.$map?.item ?? state["$map/item"];
|
|
1361
|
+
else if (key === "index")
|
|
1362
|
+
base = iterCtx?.index ?? state.$map?.index ?? state["$map/index"];
|
|
1363
|
+
else
|
|
1364
|
+
base = state.$map?.[key] ?? state["$map/" + key];
|
|
1365
|
+
if (parts.length > 2) {
|
|
1366
|
+
const pathParts = parts.slice(2);
|
|
1367
|
+
const lastKey = pathParts.pop();
|
|
1368
|
+
const obj = pathParts.length > 0 ? getPath(base, pathParts.join("/")) : base;
|
|
1369
|
+
return { obj, key: lastKey };
|
|
1370
|
+
}
|
|
1371
|
+
return { obj: state.$map ?? state, key: key === "item" ? "$map/item" : "$map/index" };
|
|
1372
|
+
}
|
|
1373
|
+
if (ref2.startsWith("#/state/")) {
|
|
1374
|
+
const sub = ref2.slice("#/state/".length);
|
|
1375
|
+
const slash = sub.indexOf("/");
|
|
1376
|
+
if (slash < 0)
|
|
1377
|
+
return { obj: state, key: sub };
|
|
1378
|
+
const parts = sub.split("/");
|
|
1379
|
+
const lastKey = parts.pop();
|
|
1380
|
+
let obj = state;
|
|
1381
|
+
for (const p of parts)
|
|
1382
|
+
obj = obj[p];
|
|
1383
|
+
return { obj, key: lastKey };
|
|
1384
|
+
}
|
|
1385
|
+
return { obj: state, key: ref2 };
|
|
1386
|
+
}
|
|
1387
|
+
function evaluateExpression(node, state, event, iterCtx) {
|
|
1388
|
+
const { operator, target, value, initial } = node;
|
|
1389
|
+
if (!BLESSED_OPERATORS.has(operator)) {
|
|
1390
|
+
throw new Error(`$expression: unknown operator "${operator}"`);
|
|
1391
|
+
}
|
|
1392
|
+
if (UNARY_OPS.has(operator) && !("value" in node)) {
|
|
1393
|
+
const operand = resolveOperand(target, state, event, iterCtx);
|
|
1394
|
+
if (operator === "!")
|
|
1395
|
+
return !operand;
|
|
1396
|
+
if (operator === "-")
|
|
1397
|
+
return -operand;
|
|
1398
|
+
}
|
|
1399
|
+
if (BINARY_OPS.has(operator)) {
|
|
1400
|
+
const left = resolveOperand(target, state, event, iterCtx);
|
|
1401
|
+
const right = resolveOperand(value, state, event, iterCtx);
|
|
1402
|
+
switch (operator) {
|
|
1403
|
+
case "+":
|
|
1404
|
+
return left + right;
|
|
1405
|
+
case "-":
|
|
1406
|
+
return left - right;
|
|
1407
|
+
case "*":
|
|
1408
|
+
return left * right;
|
|
1409
|
+
case "/":
|
|
1410
|
+
return left / right;
|
|
1411
|
+
case "%":
|
|
1412
|
+
return left % right;
|
|
1413
|
+
case "===":
|
|
1414
|
+
return left === right;
|
|
1415
|
+
case "!==":
|
|
1416
|
+
return left !== right;
|
|
1417
|
+
case "<":
|
|
1418
|
+
return left < right;
|
|
1419
|
+
case "<=":
|
|
1420
|
+
return left <= right;
|
|
1421
|
+
case ">":
|
|
1422
|
+
return left > right;
|
|
1423
|
+
case ">=":
|
|
1424
|
+
return left >= right;
|
|
1425
|
+
case "&&":
|
|
1426
|
+
return left && right;
|
|
1427
|
+
case "||":
|
|
1428
|
+
return left || right;
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
if (ASSIGNMENT_OPS.has(operator)) {
|
|
1432
|
+
const rhs = resolveOperand(value, state, event, iterCtx);
|
|
1433
|
+
const { obj, key } = resolveWritableRef(target.$ref, state, event, iterCtx);
|
|
1434
|
+
switch (operator) {
|
|
1435
|
+
case "=":
|
|
1436
|
+
obj[key] = rhs;
|
|
1437
|
+
break;
|
|
1438
|
+
case "+=":
|
|
1439
|
+
obj[key] += rhs;
|
|
1440
|
+
break;
|
|
1441
|
+
case "-=":
|
|
1442
|
+
obj[key] -= rhs;
|
|
1443
|
+
break;
|
|
1444
|
+
case "*=":
|
|
1445
|
+
obj[key] *= rhs;
|
|
1446
|
+
break;
|
|
1447
|
+
case "/=":
|
|
1448
|
+
obj[key] /= rhs;
|
|
1449
|
+
break;
|
|
1450
|
+
}
|
|
1451
|
+
return;
|
|
1452
|
+
}
|
|
1453
|
+
if (ARRAY_METHOD_OPS.has(operator)) {
|
|
1454
|
+
const arr = resolveOperand(target, state, event, iterCtx);
|
|
1455
|
+
switch (operator) {
|
|
1456
|
+
case "push":
|
|
1457
|
+
return arr.push(resolveOperand(value, state, event, iterCtx));
|
|
1458
|
+
case "unshift":
|
|
1459
|
+
return arr.unshift(resolveOperand(value, state, event, iterCtx));
|
|
1460
|
+
case "pop":
|
|
1461
|
+
return arr.pop();
|
|
1462
|
+
case "shift":
|
|
1463
|
+
return arr.shift();
|
|
1464
|
+
case "splice": {
|
|
1465
|
+
const args = resolveOperand(value, state, event, iterCtx);
|
|
1466
|
+
return arr.splice(...args);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
if (AGGREGATE_OPS.has(operator)) {
|
|
1471
|
+
const arr = resolveOperand(target, state, event, iterCtx);
|
|
1472
|
+
if (operator === "reduce") {
|
|
1473
|
+
const seed = resolveOperand(initial, state, event, iterCtx);
|
|
1474
|
+
return arr.reduce((acc, item, index) => {
|
|
1475
|
+
return evaluateExpression(value, state, event, { acc, item, index });
|
|
1476
|
+
}, seed);
|
|
1477
|
+
}
|
|
1478
|
+
if (operator === "map") {
|
|
1479
|
+
return arr.map((item, index) => {
|
|
1480
|
+
return evaluateExpression(value, state, event, { ...iterCtx, item, index });
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
if (operator === "filter") {
|
|
1484
|
+
return arr.filter((item, index) => {
|
|
1485
|
+
return evaluateExpression(value, state, event, { ...iterCtx, item, index });
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
function getPath(obj, path) {
|
|
1491
|
+
return path.split(/[./]/).reduce((o, k) => o?.[k], obj);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1261
1494
|
// src/runtime.js
|
|
1262
1495
|
async function Jx(source, target = document.body, options) {
|
|
1263
1496
|
const base = typeof source === "string" ? new URL(source, location.href).href : location.href;
|
|
@@ -1339,6 +1572,8 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1339
1572
|
if (typeof def2 === "object") {
|
|
1340
1573
|
if (def2.$prototype)
|
|
1341
1574
|
continue;
|
|
1575
|
+
if ("$expression" in def2)
|
|
1576
|
+
continue;
|
|
1342
1577
|
if (def2.timing === "server" && def2.$src && def2.$export)
|
|
1343
1578
|
continue;
|
|
1344
1579
|
if ("default" in def2) {
|
|
@@ -1356,6 +1591,16 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1356
1591
|
state[key] = computed(() => evaluateTemplate(def2, state));
|
|
1357
1592
|
}
|
|
1358
1593
|
}
|
|
1594
|
+
for (const [key, def2] of Object.entries(defs)) {
|
|
1595
|
+
if (def2 && typeof def2 === "object" && !Array.isArray(def2) && "$expression" in def2) {
|
|
1596
|
+
const node = def2.$expression;
|
|
1597
|
+
if (isMutating(node.operator)) {
|
|
1598
|
+
state[key] = (s, event) => evaluateExpression(node, s, event);
|
|
1599
|
+
} else {
|
|
1600
|
+
state[key] = computed(() => evaluateExpression(node, state, null));
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1359
1604
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1360
1605
|
if (typeof def2 === "object" && def2?.$prototype === "Function") {
|
|
1361
1606
|
state[key] = await resolveFunction(def2, state, key, base);
|
|
@@ -1560,6 +1805,12 @@ function applyProperties(el, def2, state) {
|
|
|
1560
1805
|
el.addEventListener(key.slice(2), (e) => fn(scope, e));
|
|
1561
1806
|
continue;
|
|
1562
1807
|
}
|
|
1808
|
+
if (val && typeof val === "object" && "$expression" in val) {
|
|
1809
|
+
const node = val.$expression;
|
|
1810
|
+
const scope = state;
|
|
1811
|
+
el.addEventListener(key.slice(2), (e) => evaluateExpression(node, scope, e));
|
|
1812
|
+
continue;
|
|
1813
|
+
}
|
|
1563
1814
|
}
|
|
1564
1815
|
bindProperty(el, key, val, state);
|
|
1565
1816
|
}
|
|
@@ -1587,6 +1838,17 @@ function bindProperty(el, key, val, state) {
|
|
|
1587
1838
|
function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
|
|
1588
1839
|
const nested = {};
|
|
1589
1840
|
const media = {};
|
|
1841
|
+
const baseDecls = {};
|
|
1842
|
+
const mediaOverriddenProps = new Set;
|
|
1843
|
+
for (const [prop, val] of Object.entries(styleDef)) {
|
|
1844
|
+
if (prop.startsWith("@") && val && typeof val === "object") {
|
|
1845
|
+
for (const k of Object.keys(val)) {
|
|
1846
|
+
if (!k.startsWith(":") && !k.startsWith(".") && !k.startsWith("&") && !k.startsWith("[") && !k.startsWith("@")) {
|
|
1847
|
+
mediaOverriddenProps.add(k);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1590
1852
|
for (const [prop, val] of Object.entries(styleDef)) {
|
|
1591
1853
|
if (prop.startsWith("@"))
|
|
1592
1854
|
media[prop] = val;
|
|
@@ -1605,16 +1867,23 @@ function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
|
|
|
1605
1867
|
effect(() => {
|
|
1606
1868
|
el.style[prop] = evaluateTemplate(val, state);
|
|
1607
1869
|
});
|
|
1870
|
+
else if (mediaOverriddenProps.has(prop))
|
|
1871
|
+
baseDecls[prop] = val;
|
|
1608
1872
|
else
|
|
1609
1873
|
el.style[prop] = val;
|
|
1610
1874
|
}
|
|
1611
1875
|
const hasNested = Object.keys(nested).length > 0;
|
|
1612
1876
|
const hasMedia = Object.keys(media).length > 0;
|
|
1613
|
-
|
|
1877
|
+
const hasBaseDecls = Object.keys(baseDecls).length > 0;
|
|
1878
|
+
if (!hasNested && !hasMedia && !hasBaseDecls)
|
|
1614
1879
|
return;
|
|
1615
1880
|
const uid = `jx-${Math.random().toString(36).slice(2, 7)}`;
|
|
1616
1881
|
el.dataset.jx = uid;
|
|
1617
1882
|
let css = "";
|
|
1883
|
+
const baseCSS = toCSSText(baseDecls);
|
|
1884
|
+
if (baseCSS)
|
|
1885
|
+
css += `[data-jx="${uid}"] { ${baseCSS} }
|
|
1886
|
+
`;
|
|
1618
1887
|
function emitNested(scope, rules) {
|
|
1619
1888
|
const props = toCSSText(rules);
|
|
1620
1889
|
if (props)
|
|
@@ -1679,8 +1948,7 @@ function renderMappedArray(def2, state, options) {
|
|
|
1679
1948
|
applyProperties(container, def2, state);
|
|
1680
1949
|
applyStyle(container, def2.style ?? {}, state["$media"] ?? {}, state);
|
|
1681
1950
|
applyAttributes(container, def2.attributes ?? {}, state);
|
|
1682
|
-
const { items:
|
|
1683
|
-
const itemsSrc = _items ?? _of;
|
|
1951
|
+
const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef } = def2.children;
|
|
1684
1952
|
effect(() => {
|
|
1685
1953
|
container.innerHTML = "";
|
|
1686
1954
|
let items;
|
|
@@ -2221,21 +2489,21 @@ function resolveRef(ref2, state) {
|
|
|
2221
2489
|
const parts = ref2.split("/");
|
|
2222
2490
|
const key = parts[1];
|
|
2223
2491
|
const base = state.$map?.[key] ?? state["$map/" + key];
|
|
2224
|
-
return parts.length > 2 ?
|
|
2492
|
+
return parts.length > 2 ? getPath2(base, parts.slice(2).join("/")) : base;
|
|
2225
2493
|
}
|
|
2226
2494
|
if (ref2.startsWith("#/state/")) {
|
|
2227
2495
|
const sub = ref2.slice("#/state/".length);
|
|
2228
2496
|
const slash = sub.indexOf("/");
|
|
2229
2497
|
if (slash < 0)
|
|
2230
2498
|
return state[sub];
|
|
2231
|
-
return
|
|
2499
|
+
return getPath2(state[sub.slice(0, slash)], sub.slice(slash + 1));
|
|
2232
2500
|
}
|
|
2233
2501
|
if (ref2.startsWith("parent#/"))
|
|
2234
2502
|
return state[ref2.slice("parent#/".length)];
|
|
2235
2503
|
if (ref2.startsWith("window#/"))
|
|
2236
|
-
return
|
|
2504
|
+
return getPath2(globalThis.window, ref2.slice("window#/".length));
|
|
2237
2505
|
if (ref2.startsWith("document#/"))
|
|
2238
|
-
return
|
|
2506
|
+
return getPath2(globalThis.document, ref2.slice("document#/".length));
|
|
2239
2507
|
return state[ref2] ?? null;
|
|
2240
2508
|
}
|
|
2241
2509
|
function isSignal(v) {
|
|
@@ -2247,7 +2515,7 @@ function isRefObj(v) {
|
|
|
2247
2515
|
function isNestedSelector(k) {
|
|
2248
2516
|
return k.startsWith(":") || k.startsWith(".") || k.startsWith("&") || k.startsWith("[");
|
|
2249
2517
|
}
|
|
2250
|
-
function
|
|
2518
|
+
function getPath2(obj, path) {
|
|
2251
2519
|
return path.split(/[./]/).reduce((o, k) => o?.[k], obj);
|
|
2252
2520
|
}
|
|
2253
2521
|
function mergeProps(def2, parentState) {
|
|
@@ -2487,5 +2755,5 @@ export {
|
|
|
2487
2755
|
Jx
|
|
2488
2756
|
};
|
|
2489
2757
|
|
|
2490
|
-
//# debugId=
|
|
2758
|
+
//# debugId=37F989EF6650619C64756E2164756E21
|
|
2491
2759
|
//# sourceMappingURL=runtime.js.map
|