@jxsuite/runtime 0.28.2 → 0.28.4
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 +536 -329
- package/dist/runtime.js.map +8 -7
- package/package.json +3 -3
- package/src/expression.ts +198 -97
- package/src/runtime.ts +621 -462
- package/src/types.ts +13 -2
package/dist/runtime.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../../node_modules/.bun/@vue+shared@3.5.
|
|
1
|
+
// ../../node_modules/.bun/@vue+shared@3.5.38/node_modules/@vue/shared/dist/shared.esm-bundler.js
|
|
2
2
|
function makeMap(str) {
|
|
3
3
|
const map = /* @__PURE__ */ Object.create(null);
|
|
4
4
|
for (const key of str.split(","))
|
|
@@ -46,7 +46,7 @@ var hasChanged = (value, oldValue) => !Object.is(value, oldValue);
|
|
|
46
46
|
var specialBooleanAttrs = `itemscope,allowfullscreen,formnovalidate,ismap,nomodule,novalidate,readonly`;
|
|
47
47
|
var isBooleanAttr = /* @__PURE__ */ makeMap(specialBooleanAttrs + `,async,autofocus,autoplay,controls,default,defer,disabled,hidden,inert,loop,open,required,reversed,scoped,seamless,checked,muted,multiple,selected`);
|
|
48
48
|
|
|
49
|
-
// ../../node_modules/.bun/@vue+reactivity@3.5.
|
|
49
|
+
// ../../node_modules/.bun/@vue+reactivity@3.5.38/node_modules/@vue/reactivity/dist/reactivity.esm-bundler.js
|
|
50
50
|
function warn(msg, ...args) {
|
|
51
51
|
console.warn(`[Vue warn] ${msg}`, ...args);
|
|
52
52
|
}
|
|
@@ -1259,6 +1259,10 @@ function computed(getterOrOptions, debugOptions, isSSR = false) {
|
|
|
1259
1259
|
}
|
|
1260
1260
|
|
|
1261
1261
|
// src/expression.ts
|
|
1262
|
+
function scopeMap(state) {
|
|
1263
|
+
const map = state.$map;
|
|
1264
|
+
return map && typeof map === "object" ? map : undefined;
|
|
1265
|
+
}
|
|
1262
1266
|
var MUTATING_OPS = new Set([
|
|
1263
1267
|
"=",
|
|
1264
1268
|
"+=",
|
|
@@ -1300,8 +1304,9 @@ function isMutating(op) {
|
|
|
1300
1304
|
return MUTATING_OPS.has(op);
|
|
1301
1305
|
}
|
|
1302
1306
|
function resolveOperand(operand, state, event, iterCtx) {
|
|
1303
|
-
if (operand === null || operand === undefined)
|
|
1307
|
+
if (operand === null || operand === undefined) {
|
|
1304
1308
|
return operand;
|
|
1309
|
+
}
|
|
1305
1310
|
if (typeof operand === "object" && !Array.isArray(operand) && "operator" in operand) {
|
|
1306
1311
|
return evaluateExpression(operand, state, event, iterCtx);
|
|
1307
1312
|
}
|
|
@@ -1326,66 +1331,76 @@ function resolveExprRef(ref2, state, event, iterCtx) {
|
|
|
1326
1331
|
}
|
|
1327
1332
|
if (ref2.startsWith("$map/")) {
|
|
1328
1333
|
const parts = ref2.split("/");
|
|
1329
|
-
const key = parts
|
|
1334
|
+
const [, key] = parts;
|
|
1330
1335
|
let base;
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1336
|
+
const map = scopeMap(state);
|
|
1337
|
+
if (key === "item") {
|
|
1338
|
+
base = iterCtx?.item ?? map?.item ?? state["$map/item"];
|
|
1339
|
+
} else if (key === "index") {
|
|
1340
|
+
base = iterCtx?.index ?? map?.index ?? state["$map/index"];
|
|
1341
|
+
} else {
|
|
1342
|
+
base = map?.[key] ?? state[`$map/${key}`];
|
|
1343
|
+
}
|
|
1337
1344
|
return parts.length > 2 ? getPath(base, parts.slice(2).join("/")) : base;
|
|
1338
1345
|
}
|
|
1339
1346
|
if (ref2.startsWith("#/state/")) {
|
|
1340
1347
|
const sub = ref2.slice("#/state/".length);
|
|
1341
1348
|
const slash = sub.indexOf("/");
|
|
1342
|
-
if (slash
|
|
1349
|
+
if (slash === -1) {
|
|
1343
1350
|
return state[sub];
|
|
1351
|
+
}
|
|
1344
1352
|
return getPath(state[sub.slice(0, slash)], sub.slice(slash + 1));
|
|
1345
1353
|
}
|
|
1346
|
-
if (ref2.startsWith("parent#/"))
|
|
1354
|
+
if (ref2.startsWith("parent#/")) {
|
|
1347
1355
|
return state[ref2.slice("parent#/".length)];
|
|
1348
|
-
|
|
1356
|
+
}
|
|
1357
|
+
if (ref2.startsWith("window#/")) {
|
|
1349
1358
|
return getPath(globalThis.window, ref2.slice("window#/".length));
|
|
1350
|
-
|
|
1359
|
+
}
|
|
1360
|
+
if (ref2.startsWith("document#/")) {
|
|
1351
1361
|
return getPath(globalThis.document, ref2.slice("document#/".length));
|
|
1362
|
+
}
|
|
1352
1363
|
return state[ref2] ?? null;
|
|
1353
1364
|
}
|
|
1354
1365
|
function resolveWritableRef(ref2, state, event, iterCtx) {
|
|
1355
1366
|
if (ref2.startsWith("$map/")) {
|
|
1356
1367
|
const parts = ref2.split("/");
|
|
1357
|
-
const key = parts
|
|
1368
|
+
const [, key] = parts;
|
|
1358
1369
|
let base;
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1370
|
+
const map = scopeMap(state);
|
|
1371
|
+
if (key === "item") {
|
|
1372
|
+
base = iterCtx?.item ?? map?.item ?? state["$map/item"];
|
|
1373
|
+
} else if (key === "index") {
|
|
1374
|
+
base = iterCtx?.index ?? map?.index ?? state["$map/index"];
|
|
1375
|
+
} else {
|
|
1376
|
+
base = map?.[key] ?? state[`$map/${key}`];
|
|
1377
|
+
}
|
|
1365
1378
|
if (parts.length > 2) {
|
|
1366
1379
|
const pathParts = parts.slice(2);
|
|
1367
1380
|
const lastKey = pathParts.pop();
|
|
1368
1381
|
const obj = pathParts.length > 0 ? getPath(base, pathParts.join("/")) : base;
|
|
1369
|
-
return {
|
|
1382
|
+
return { key: lastKey, obj };
|
|
1370
1383
|
}
|
|
1371
1384
|
return {
|
|
1372
|
-
|
|
1373
|
-
|
|
1385
|
+
key: key === "item" ? "$map/item" : "$map/index",
|
|
1386
|
+
obj: scopeMap(state) ?? state
|
|
1374
1387
|
};
|
|
1375
1388
|
}
|
|
1376
1389
|
if (ref2.startsWith("#/state/")) {
|
|
1377
1390
|
const sub = ref2.slice("#/state/".length);
|
|
1378
1391
|
const slash = sub.indexOf("/");
|
|
1379
|
-
if (slash
|
|
1380
|
-
return {
|
|
1392
|
+
if (slash === -1) {
|
|
1393
|
+
return { key: sub, obj: state };
|
|
1394
|
+
}
|
|
1381
1395
|
const parts = sub.split("/");
|
|
1382
1396
|
const lastKey = parts.pop();
|
|
1383
1397
|
let obj = state;
|
|
1384
|
-
for (const p of parts)
|
|
1398
|
+
for (const p of parts) {
|
|
1385
1399
|
obj = obj[p];
|
|
1386
|
-
|
|
1400
|
+
}
|
|
1401
|
+
return { key: lastKey, obj };
|
|
1387
1402
|
}
|
|
1388
|
-
return {
|
|
1403
|
+
return { key: ref2, obj: state };
|
|
1389
1404
|
}
|
|
1390
1405
|
function evaluateExpression(node, state, event, iterCtx) {
|
|
1391
1406
|
const { operator, target, value, initial } = node;
|
|
@@ -1394,117 +1409,200 @@ function evaluateExpression(node, state, event, iterCtx) {
|
|
|
1394
1409
|
}
|
|
1395
1410
|
if (UNARY_OPS.has(operator) && !("value" in node)) {
|
|
1396
1411
|
const operand = resolveOperand(target, state, event, iterCtx);
|
|
1397
|
-
if (operator === "!")
|
|
1412
|
+
if (operator === "!") {
|
|
1398
1413
|
return !operand;
|
|
1399
|
-
|
|
1414
|
+
}
|
|
1415
|
+
if (operator === "-") {
|
|
1400
1416
|
return -operand;
|
|
1417
|
+
}
|
|
1401
1418
|
}
|
|
1402
1419
|
if (BINARY_OPS.has(operator)) {
|
|
1403
1420
|
const left = resolveOperand(target, state, event, iterCtx);
|
|
1404
1421
|
const right = resolveOperand(value, state, event, iterCtx);
|
|
1405
1422
|
switch (operator) {
|
|
1406
|
-
case "+":
|
|
1423
|
+
case "+": {
|
|
1407
1424
|
return left + right;
|
|
1408
|
-
|
|
1425
|
+
}
|
|
1426
|
+
case "-": {
|
|
1409
1427
|
return left - right;
|
|
1410
|
-
|
|
1428
|
+
}
|
|
1429
|
+
case "*": {
|
|
1411
1430
|
return left * right;
|
|
1412
|
-
|
|
1431
|
+
}
|
|
1432
|
+
case "/": {
|
|
1413
1433
|
return left / right;
|
|
1414
|
-
|
|
1434
|
+
}
|
|
1435
|
+
case "%": {
|
|
1415
1436
|
return left % right;
|
|
1416
|
-
|
|
1437
|
+
}
|
|
1438
|
+
case "===": {
|
|
1417
1439
|
return left === right;
|
|
1418
|
-
|
|
1440
|
+
}
|
|
1441
|
+
case "!==": {
|
|
1419
1442
|
return left !== right;
|
|
1420
|
-
|
|
1443
|
+
}
|
|
1444
|
+
case "<": {
|
|
1421
1445
|
return left < right;
|
|
1422
|
-
|
|
1446
|
+
}
|
|
1447
|
+
case "<=": {
|
|
1423
1448
|
return left <= right;
|
|
1424
|
-
|
|
1449
|
+
}
|
|
1450
|
+
case ">": {
|
|
1425
1451
|
return left > right;
|
|
1426
|
-
|
|
1452
|
+
}
|
|
1453
|
+
case ">=": {
|
|
1427
1454
|
return left >= right;
|
|
1428
|
-
|
|
1455
|
+
}
|
|
1456
|
+
case "&&": {
|
|
1429
1457
|
return left && right;
|
|
1430
|
-
|
|
1458
|
+
}
|
|
1459
|
+
case "||": {
|
|
1431
1460
|
return left || right;
|
|
1461
|
+
}
|
|
1462
|
+
default: {
|
|
1463
|
+
break;
|
|
1464
|
+
}
|
|
1432
1465
|
}
|
|
1433
1466
|
}
|
|
1434
1467
|
if (ASSIGNMENT_OPS.has(operator)) {
|
|
1435
1468
|
const rhs = resolveOperand(value, state, event, iterCtx);
|
|
1436
1469
|
const { obj, key } = resolveWritableRef(target.$ref, state, event, iterCtx);
|
|
1437
1470
|
switch (operator) {
|
|
1438
|
-
case "=":
|
|
1471
|
+
case "=": {
|
|
1439
1472
|
obj[key] = rhs;
|
|
1440
1473
|
break;
|
|
1441
|
-
|
|
1442
|
-
|
|
1474
|
+
}
|
|
1475
|
+
case "+=": {
|
|
1476
|
+
const current = obj[key];
|
|
1477
|
+
obj[key] = current + rhs;
|
|
1443
1478
|
break;
|
|
1444
|
-
|
|
1445
|
-
|
|
1479
|
+
}
|
|
1480
|
+
case "-=": {
|
|
1481
|
+
const current = obj[key];
|
|
1482
|
+
obj[key] = current - rhs;
|
|
1446
1483
|
break;
|
|
1447
|
-
|
|
1448
|
-
|
|
1484
|
+
}
|
|
1485
|
+
case "*=": {
|
|
1486
|
+
const current = obj[key];
|
|
1487
|
+
obj[key] = current * rhs;
|
|
1449
1488
|
break;
|
|
1450
|
-
|
|
1451
|
-
|
|
1489
|
+
}
|
|
1490
|
+
case "/=": {
|
|
1491
|
+
const current = obj[key];
|
|
1492
|
+
obj[key] = current / rhs;
|
|
1452
1493
|
break;
|
|
1494
|
+
}
|
|
1495
|
+
default: {
|
|
1496
|
+
break;
|
|
1497
|
+
}
|
|
1453
1498
|
}
|
|
1454
1499
|
return;
|
|
1455
1500
|
}
|
|
1456
1501
|
if (ARRAY_METHOD_OPS.has(operator)) {
|
|
1457
1502
|
const arr = resolveOperand(target, state, event, iterCtx);
|
|
1458
1503
|
switch (operator) {
|
|
1459
|
-
case "push":
|
|
1504
|
+
case "push": {
|
|
1460
1505
|
return arr.push(resolveOperand(value, state, event, iterCtx));
|
|
1461
|
-
|
|
1506
|
+
}
|
|
1507
|
+
case "unshift": {
|
|
1462
1508
|
return arr.unshift(resolveOperand(value, state, event, iterCtx));
|
|
1463
|
-
|
|
1509
|
+
}
|
|
1510
|
+
case "pop": {
|
|
1464
1511
|
return arr.pop();
|
|
1465
|
-
|
|
1512
|
+
}
|
|
1513
|
+
case "shift": {
|
|
1466
1514
|
return arr.shift();
|
|
1515
|
+
}
|
|
1467
1516
|
case "splice": {
|
|
1468
1517
|
const args = resolveOperand(value, state, event, iterCtx);
|
|
1469
1518
|
return arr.splice(...args);
|
|
1470
1519
|
}
|
|
1520
|
+
default: {
|
|
1521
|
+
break;
|
|
1522
|
+
}
|
|
1471
1523
|
}
|
|
1472
1524
|
}
|
|
1473
1525
|
if (AGGREGATE_OPS.has(operator)) {
|
|
1474
1526
|
const arr = resolveOperand(target, state, event, iterCtx);
|
|
1475
1527
|
if (operator === "reduce") {
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1528
|
+
let acc = resolveOperand(initial, state, event, iterCtx);
|
|
1529
|
+
for (const [index, item] of arr.entries()) {
|
|
1530
|
+
acc = evaluateExpression(value, state, event, {
|
|
1479
1531
|
acc,
|
|
1480
|
-
|
|
1481
|
-
|
|
1532
|
+
index,
|
|
1533
|
+
item
|
|
1482
1534
|
});
|
|
1483
|
-
}
|
|
1535
|
+
}
|
|
1536
|
+
return acc;
|
|
1484
1537
|
}
|
|
1485
1538
|
if (operator === "map") {
|
|
1486
|
-
return arr.map((item, index) => {
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
});
|
|
1492
|
-
});
|
|
1539
|
+
return arr.map((item, index) => evaluateExpression(value, state, event, {
|
|
1540
|
+
...iterCtx,
|
|
1541
|
+
index,
|
|
1542
|
+
item
|
|
1543
|
+
}));
|
|
1493
1544
|
}
|
|
1494
1545
|
if (operator === "filter") {
|
|
1495
|
-
return arr.filter((item, index) => {
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
});
|
|
1501
|
-
});
|
|
1546
|
+
return arr.filter((item, index) => evaluateExpression(value, state, event, {
|
|
1547
|
+
...iterCtx,
|
|
1548
|
+
index,
|
|
1549
|
+
item
|
|
1550
|
+
}));
|
|
1502
1551
|
}
|
|
1503
1552
|
}
|
|
1504
1553
|
return;
|
|
1505
1554
|
}
|
|
1506
1555
|
function getPath(obj, path) {
|
|
1507
|
-
|
|
1556
|
+
let current = obj;
|
|
1557
|
+
for (const k of path.split(/[./]/)) {
|
|
1558
|
+
current = current?.[k];
|
|
1559
|
+
}
|
|
1560
|
+
return current;
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
// ../schema/src/guards.ts
|
|
1564
|
+
function isJsonObject(value) {
|
|
1565
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1566
|
+
}
|
|
1567
|
+
function isRef2(value) {
|
|
1568
|
+
return isJsonObject(value) && typeof value.$ref === "string";
|
|
1569
|
+
}
|
|
1570
|
+
function isFunctionDef(value) {
|
|
1571
|
+
return isJsonObject(value) && value.$prototype === "Function";
|
|
1572
|
+
}
|
|
1573
|
+
function isExpressionDef(value) {
|
|
1574
|
+
return isJsonObject(value) && isJsonObject(value.$expression);
|
|
1575
|
+
}
|
|
1576
|
+
function isPrototypeDef(value) {
|
|
1577
|
+
return isJsonObject(value) && typeof value.$prototype === "string" && value.$prototype !== "Function";
|
|
1578
|
+
}
|
|
1579
|
+
function isServerFnDef(value) {
|
|
1580
|
+
return isJsonObject(value) && value.timing === "server" && typeof value.$src === "string" && typeof value.$export === "string" && !value.$prototype;
|
|
1581
|
+
}
|
|
1582
|
+
var SCHEMA_KEYWORDS = new Set([
|
|
1583
|
+
"type",
|
|
1584
|
+
"enum",
|
|
1585
|
+
"minimum",
|
|
1586
|
+
"maximum",
|
|
1587
|
+
"minLength",
|
|
1588
|
+
"maxLength",
|
|
1589
|
+
"pattern",
|
|
1590
|
+
"format",
|
|
1591
|
+
"items",
|
|
1592
|
+
"properties",
|
|
1593
|
+
"required",
|
|
1594
|
+
"description",
|
|
1595
|
+
"title",
|
|
1596
|
+
"$comment"
|
|
1597
|
+
]);
|
|
1598
|
+
function isMappedArray(value) {
|
|
1599
|
+
return isJsonObject(value) && value.$prototype === "Array";
|
|
1600
|
+
}
|
|
1601
|
+
function paramNames(parameters) {
|
|
1602
|
+
if (!parameters) {
|
|
1603
|
+
return [];
|
|
1604
|
+
}
|
|
1605
|
+
return parameters.map((p) => typeof p === "string" ? p : p.name);
|
|
1508
1606
|
}
|
|
1509
1607
|
|
|
1510
1608
|
// src/runtime.ts
|
|
@@ -1521,26 +1619,30 @@ async function Jx(source, target = document.body, options) {
|
|
|
1521
1619
|
_rootMedia = doc.$media;
|
|
1522
1620
|
}
|
|
1523
1621
|
const state = await buildScope(doc, {}, base);
|
|
1524
|
-
target.
|
|
1525
|
-
if (typeof state.onMount === "function")
|
|
1622
|
+
target.append(renderNode(doc, state, options));
|
|
1623
|
+
if (typeof state.onMount === "function") {
|
|
1526
1624
|
state.onMount(state);
|
|
1625
|
+
}
|
|
1527
1626
|
return state;
|
|
1528
1627
|
}
|
|
1529
1628
|
var _resolveCache = new Map;
|
|
1530
1629
|
async function resolve(source) {
|
|
1531
|
-
if (typeof source !== "string")
|
|
1630
|
+
if (typeof source !== "string") {
|
|
1532
1631
|
return source;
|
|
1533
|
-
|
|
1632
|
+
}
|
|
1633
|
+
if (_resolveCache.has(source)) {
|
|
1534
1634
|
return _resolveCache.get(source);
|
|
1635
|
+
}
|
|
1535
1636
|
const p = fetch(source).then((res) => {
|
|
1536
|
-
if (!res.ok)
|
|
1637
|
+
if (!res.ok) {
|
|
1537
1638
|
throw new Error(`Jx: failed to fetch ${source} (${res.status})`);
|
|
1639
|
+
}
|
|
1538
1640
|
return res.json();
|
|
1539
1641
|
});
|
|
1540
1642
|
_resolveCache.set(source, p);
|
|
1541
1643
|
return p;
|
|
1542
1644
|
}
|
|
1543
|
-
var
|
|
1645
|
+
var SCHEMA_KEYWORDS2 = new Set([
|
|
1544
1646
|
"type",
|
|
1545
1647
|
"properties",
|
|
1546
1648
|
"items",
|
|
@@ -1566,10 +1668,10 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1566
1668
|
const defs = doc.state ?? {};
|
|
1567
1669
|
const imports = doc.imports ?? {};
|
|
1568
1670
|
for (const [, def2] of Object.entries(defs)) {
|
|
1569
|
-
if (
|
|
1671
|
+
if (isPrototypeDef(def2) && !def2.$src) {
|
|
1570
1672
|
const mapped = imports[def2.$prototype];
|
|
1571
1673
|
if (mapped) {
|
|
1572
|
-
if (
|
|
1674
|
+
if (!mapped.endsWith(".class.json")) {
|
|
1573
1675
|
console.warn(`Jx: import "${def2.$prototype}" must map to a .class.json path, got "${mapped}"`);
|
|
1574
1676
|
continue;
|
|
1575
1677
|
}
|
|
@@ -1579,8 +1681,9 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1579
1681
|
}
|
|
1580
1682
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1581
1683
|
if (typeof def2 === "string") {
|
|
1582
|
-
if (!def2.includes("${"))
|
|
1684
|
+
if (!def2.includes("${")) {
|
|
1583
1685
|
raw[key] = def2;
|
|
1686
|
+
}
|
|
1584
1687
|
continue;
|
|
1585
1688
|
}
|
|
1586
1689
|
if (typeof def2 === "number" || typeof def2 === "boolean" || def2 === null) {
|
|
@@ -1592,19 +1695,22 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1592
1695
|
continue;
|
|
1593
1696
|
}
|
|
1594
1697
|
if (typeof def2 === "object") {
|
|
1595
|
-
|
|
1596
|
-
if (d.$prototype)
|
|
1698
|
+
if (def2.$prototype) {
|
|
1597
1699
|
continue;
|
|
1598
|
-
|
|
1700
|
+
}
|
|
1701
|
+
if (isExpressionDef(def2)) {
|
|
1599
1702
|
continue;
|
|
1600
|
-
|
|
1703
|
+
}
|
|
1704
|
+
if (isServerFnDef(def2)) {
|
|
1601
1705
|
continue;
|
|
1602
|
-
|
|
1603
|
-
|
|
1706
|
+
}
|
|
1707
|
+
if ("default" in def2) {
|
|
1708
|
+
raw[key] = def2.default;
|
|
1604
1709
|
continue;
|
|
1605
1710
|
}
|
|
1606
|
-
if (hasSchemaKeywords(
|
|
1711
|
+
if (hasSchemaKeywords(def2)) {
|
|
1607
1712
|
continue;
|
|
1713
|
+
}
|
|
1608
1714
|
raw[key] = def2;
|
|
1609
1715
|
}
|
|
1610
1716
|
}
|
|
@@ -1615,28 +1721,29 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1615
1721
|
}
|
|
1616
1722
|
}
|
|
1617
1723
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1618
|
-
if (
|
|
1724
|
+
if (isExpressionDef(def2)) {
|
|
1619
1725
|
const node = def2.$expression;
|
|
1620
1726
|
if (isMutating(node.operator)) {
|
|
1621
|
-
|
|
1727
|
+
const handler = (s, event) => evaluateExpression(node, s, event);
|
|
1728
|
+
state[key] = handler;
|
|
1622
1729
|
} else {
|
|
1623
1730
|
state[key] = computed(() => evaluateExpression(node, state, null));
|
|
1624
1731
|
}
|
|
1625
1732
|
}
|
|
1626
1733
|
}
|
|
1627
1734
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1628
|
-
if (
|
|
1735
|
+
if (isFunctionDef(def2)) {
|
|
1629
1736
|
state[key] = await resolveFunction(def2, state, key, base);
|
|
1630
1737
|
}
|
|
1631
1738
|
}
|
|
1632
1739
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1633
|
-
if (
|
|
1740
|
+
if (isPrototypeDef(def2)) {
|
|
1634
1741
|
state[key] = await resolvePrototype(def2, state, key, base);
|
|
1635
1742
|
}
|
|
1636
1743
|
}
|
|
1637
1744
|
if (!_serverFnConfig.skip) {
|
|
1638
1745
|
for (const [key, def2] of Object.entries(defs)) {
|
|
1639
|
-
if (def2
|
|
1746
|
+
if (isServerFnDef(def2)) {
|
|
1640
1747
|
state[key] = await resolveServerFunction(def2, state, key, base);
|
|
1641
1748
|
}
|
|
1642
1749
|
}
|
|
@@ -1650,8 +1757,9 @@ async function buildScope(doc, parentScope = {}, base = location.href) {
|
|
|
1650
1757
|
}
|
|
1651
1758
|
function hasSchemaKeywords(obj) {
|
|
1652
1759
|
for (const k of Object.keys(obj)) {
|
|
1653
|
-
if (
|
|
1760
|
+
if (SCHEMA_KEYWORDS2.has(k)) {
|
|
1654
1761
|
return true;
|
|
1762
|
+
}
|
|
1655
1763
|
}
|
|
1656
1764
|
return false;
|
|
1657
1765
|
}
|
|
@@ -1669,8 +1777,8 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
1669
1777
|
const params = resolveParamNames(def2);
|
|
1670
1778
|
const noop = new Function(...params, "");
|
|
1671
1779
|
Object.defineProperty(noop, "name", {
|
|
1672
|
-
|
|
1673
|
-
|
|
1780
|
+
configurable: true,
|
|
1781
|
+
value: def2.name ?? key
|
|
1674
1782
|
});
|
|
1675
1783
|
return noop;
|
|
1676
1784
|
}
|
|
@@ -1679,11 +1787,14 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
1679
1787
|
const params = resolveParamNames(def2);
|
|
1680
1788
|
fn = new Function(...params, def2.body);
|
|
1681
1789
|
Object.defineProperty(fn, "name", {
|
|
1682
|
-
|
|
1683
|
-
|
|
1790
|
+
configurable: true,
|
|
1791
|
+
value: def2.name ?? key
|
|
1684
1792
|
});
|
|
1685
1793
|
} else {
|
|
1686
1794
|
const src = def2.$src;
|
|
1795
|
+
if (!src) {
|
|
1796
|
+
throw new Error(`Jx: '${key}' has neither body nor $src`);
|
|
1797
|
+
}
|
|
1687
1798
|
const exportName = def2.$export ?? key;
|
|
1688
1799
|
let mod;
|
|
1689
1800
|
if (_moduleCache.has(src)) {
|
|
@@ -1703,7 +1814,7 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
1703
1814
|
}
|
|
1704
1815
|
fn = mod[exportName] ?? mod.default?.[exportName];
|
|
1705
1816
|
if (typeof fn !== "function") {
|
|
1706
|
-
throw new
|
|
1817
|
+
throw new TypeError(`Jx: export "${exportName}" not found or not a function in "${src}"`);
|
|
1707
1818
|
}
|
|
1708
1819
|
}
|
|
1709
1820
|
const hasParams = (def2.parameters ?? def2.arguments ?? []).length > 0;
|
|
@@ -1721,13 +1832,7 @@ async function resolveFunction(def2, state, key, base) {
|
|
|
1721
1832
|
return fn;
|
|
1722
1833
|
}
|
|
1723
1834
|
function resolveParamNames(def2) {
|
|
1724
|
-
const
|
|
1725
|
-
let names;
|
|
1726
|
-
if (Array.isArray(raw) && raw.length > 0 && typeof raw[0] === "object") {
|
|
1727
|
-
names = raw.map((p) => p.name ?? p.identifier ?? "arg");
|
|
1728
|
-
} else {
|
|
1729
|
-
names = raw;
|
|
1730
|
-
}
|
|
1835
|
+
const names = def2.parameters ? paramNames(def2.parameters) : def2.arguments ?? [];
|
|
1731
1836
|
return names.length > 0 && names[0] === "state" ? names : ["state", ...names];
|
|
1732
1837
|
}
|
|
1733
1838
|
var RESERVED_KEYS = new Set([
|
|
@@ -1778,8 +1883,9 @@ function renderNode(def2, state, options) {
|
|
|
1778
1883
|
let localState = state;
|
|
1779
1884
|
for (const [key, val] of Object.entries(def2)) {
|
|
1780
1885
|
if (key.startsWith("$") && !RESERVED_KEYS.has(key)) {
|
|
1781
|
-
if (localState === state)
|
|
1886
|
+
if (localState === state) {
|
|
1782
1887
|
localState = Object.create(state);
|
|
1888
|
+
}
|
|
1783
1889
|
localState[key] = isRefObj(val) ? resolveRef(val.$ref, state) : val;
|
|
1784
1890
|
}
|
|
1785
1891
|
}
|
|
@@ -1792,20 +1898,23 @@ function renderNode(def2, state, options) {
|
|
|
1792
1898
|
const { $props: _$props, ...rest } = def2;
|
|
1793
1899
|
return renderNode(rest, mergeProps(def2, localState), options);
|
|
1794
1900
|
}
|
|
1795
|
-
if (def2.$switch)
|
|
1901
|
+
if (def2.$switch) {
|
|
1796
1902
|
return renderSwitch(def2, localState, options);
|
|
1797
|
-
|
|
1798
|
-
|
|
1903
|
+
}
|
|
1904
|
+
if (isMappedArray(def2.children)) {
|
|
1905
|
+
return renderMappedArray(def2, def2.children, localState, options);
|
|
1906
|
+
}
|
|
1799
1907
|
const el = document.createElement(tagName);
|
|
1800
|
-
if (options?.onNodeCreated)
|
|
1908
|
+
if (options?.onNodeCreated) {
|
|
1801
1909
|
options.onNodeCreated(el, path, def2);
|
|
1910
|
+
}
|
|
1802
1911
|
applyProperties(el, def2, localState);
|
|
1803
1912
|
applyStyle(el, def2.style ?? {}, localState["$media"] ?? {}, localState);
|
|
1804
1913
|
applyAttributes(el, def2.attributes ?? {}, localState);
|
|
1805
1914
|
const children = Array.isArray(def2.children) ? def2.children : [];
|
|
1806
1915
|
for (let i = 0;i < children.length; i++) {
|
|
1807
1916
|
const childOpts = options ? { ...options, _path: [...path, "children", i] } : undefined;
|
|
1808
|
-
el.
|
|
1917
|
+
el.append(renderNode(children[i], localState, childOpts));
|
|
1809
1918
|
}
|
|
1810
1919
|
return el;
|
|
1811
1920
|
}
|
|
@@ -1814,10 +1923,12 @@ function isTemplateString(val) {
|
|
|
1814
1923
|
}
|
|
1815
1924
|
function applyProperties(el, def2, state) {
|
|
1816
1925
|
for (const [key, val] of Object.entries(def2)) {
|
|
1817
|
-
if (RESERVED_KEYS.has(key))
|
|
1926
|
+
if (RESERVED_KEYS.has(key)) {
|
|
1818
1927
|
continue;
|
|
1819
|
-
|
|
1928
|
+
}
|
|
1929
|
+
if (key.startsWith("$")) {
|
|
1820
1930
|
continue;
|
|
1931
|
+
}
|
|
1821
1932
|
if (key.startsWith("on")) {
|
|
1822
1933
|
if (isRefObj(val)) {
|
|
1823
1934
|
const handler = resolveRef(val.$ref, state);
|
|
@@ -1827,14 +1938,14 @@ function applyProperties(el, def2, state) {
|
|
|
1827
1938
|
}
|
|
1828
1939
|
continue;
|
|
1829
1940
|
}
|
|
1830
|
-
if (val &&
|
|
1941
|
+
if (isFunctionDef(val) && val.body) {
|
|
1831
1942
|
const params = resolveParamNames(val);
|
|
1832
1943
|
const fn = new Function(...params, val.body);
|
|
1833
1944
|
const scope = state;
|
|
1834
1945
|
el.addEventListener(key.slice(2), (e) => fn(scope, e));
|
|
1835
1946
|
continue;
|
|
1836
1947
|
}
|
|
1837
|
-
if (val
|
|
1948
|
+
if (isExpressionDef(val)) {
|
|
1838
1949
|
const node = val.$expression;
|
|
1839
1950
|
const scope = state;
|
|
1840
1951
|
el.addEventListener(key.slice(2), (e) => evaluateExpression(node, scope, e));
|
|
@@ -1880,50 +1991,66 @@ function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
|
|
|
1880
1991
|
}
|
|
1881
1992
|
}
|
|
1882
1993
|
for (const [prop, val] of Object.entries(styleDef)) {
|
|
1883
|
-
if (
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1994
|
+
if (val !== null && typeof val === "object" && !Array.isArray(val)) {
|
|
1995
|
+
if (prop.startsWith("@")) {
|
|
1996
|
+
media[prop] = val;
|
|
1997
|
+
} else {
|
|
1998
|
+
nested[prop] = val;
|
|
1999
|
+
}
|
|
2000
|
+
continue;
|
|
2001
|
+
}
|
|
2002
|
+
if (prop.startsWith("@") || isNestedSelector(prop)) {
|
|
2003
|
+
continue;
|
|
2004
|
+
}
|
|
2005
|
+
if (val === undefined) {
|
|
2006
|
+
continue;
|
|
2007
|
+
}
|
|
2008
|
+
const scalar = String(val);
|
|
2009
|
+
if (prop.startsWith("--")) {
|
|
2010
|
+
if (isTemplateString(val)) {
|
|
1891
2011
|
effect(() => {
|
|
1892
2012
|
el.style.setProperty(prop, evaluateTemplate(val, state));
|
|
1893
2013
|
});
|
|
1894
|
-
else
|
|
1895
|
-
el.style.setProperty(prop,
|
|
1896
|
-
|
|
2014
|
+
} else {
|
|
2015
|
+
el.style.setProperty(prop, scalar);
|
|
2016
|
+
}
|
|
2017
|
+
} else if (isTemplateString(val)) {
|
|
1897
2018
|
effect(() => {
|
|
1898
2019
|
el.style[prop] = evaluateTemplate(val, state);
|
|
1899
2020
|
});
|
|
1900
|
-
else if (mediaOverriddenProps.has(prop))
|
|
1901
|
-
baseDecls[prop] =
|
|
1902
|
-
else
|
|
1903
|
-
el.style[prop] =
|
|
2021
|
+
} else if (mediaOverriddenProps.has(prop)) {
|
|
2022
|
+
baseDecls[prop] = scalar;
|
|
2023
|
+
} else {
|
|
2024
|
+
el.style[prop] = scalar;
|
|
2025
|
+
}
|
|
1904
2026
|
}
|
|
1905
2027
|
const hasNested = Object.keys(nested).length > 0;
|
|
1906
2028
|
const hasMedia = Object.keys(media).length > 0;
|
|
1907
2029
|
const hasBaseDecls = Object.keys(baseDecls).length > 0;
|
|
1908
|
-
if (!hasNested && !hasMedia && !hasBaseDecls)
|
|
2030
|
+
if (!hasNested && !hasMedia && !hasBaseDecls) {
|
|
1909
2031
|
return;
|
|
2032
|
+
}
|
|
1910
2033
|
const uid = `jx-${Math.random().toString(36).slice(2, 7)}`;
|
|
1911
2034
|
el.dataset.jx = uid;
|
|
1912
2035
|
let css = "";
|
|
1913
2036
|
const baseCSS = toCSSText(baseDecls);
|
|
1914
|
-
if (baseCSS)
|
|
2037
|
+
if (baseCSS) {
|
|
1915
2038
|
css += `[data-jx="${uid}"] { ${baseCSS} }
|
|
1916
2039
|
`;
|
|
2040
|
+
}
|
|
1917
2041
|
function emitNested(scope, rules) {
|
|
1918
2042
|
const props = toCSSText(rules);
|
|
1919
|
-
if (props)
|
|
2043
|
+
if (props) {
|
|
1920
2044
|
css += `${scope} { ${props} }
|
|
1921
2045
|
`;
|
|
2046
|
+
}
|
|
1922
2047
|
for (const [sel, sub] of Object.entries(rules)) {
|
|
1923
|
-
if (sub === null || typeof sub !== "object" || Array.isArray(sub))
|
|
2048
|
+
if (sub === null || typeof sub !== "object" || Array.isArray(sub)) {
|
|
1924
2049
|
continue;
|
|
1925
|
-
|
|
2050
|
+
}
|
|
2051
|
+
if (sel.startsWith("@")) {
|
|
1926
2052
|
continue;
|
|
2053
|
+
}
|
|
1927
2054
|
const resolved = sel.startsWith("&") ? sel.replace("&", scope) : sel.startsWith("[") ? `${scope}${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `${scope}${sel}` : `${scope} ${sel}`;
|
|
1928
2055
|
emitNested(resolved, sub);
|
|
1929
2056
|
}
|
|
@@ -1932,32 +2059,36 @@ function applyStyle(el, styleDef, mediaQueries = {}, state = {}) {
|
|
|
1932
2059
|
const resolved = sel.startsWith("&") ? sel.replace("&", `[data-jx="${uid}"]`) : sel.startsWith("[") ? `[data-jx="${uid}"]${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `[data-jx="${uid}"]${sel}` : `[data-jx="${uid}"] ${sel}`;
|
|
1933
2060
|
emitNested(resolved, rules);
|
|
1934
2061
|
}
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
2062
|
+
function emitMediaNested(atRule, parentSel, obj) {
|
|
2063
|
+
for (const [sel, sub] of Object.entries(obj)) {
|
|
2064
|
+
if (sub === null || typeof sub !== "object" || Array.isArray(sub)) {
|
|
2065
|
+
continue;
|
|
2066
|
+
}
|
|
2067
|
+
if (sel.startsWith("@")) {
|
|
2068
|
+
continue;
|
|
2069
|
+
}
|
|
2070
|
+
const resolved = sel.startsWith("&") ? sel.replace("&", parentSel) : sel.startsWith("[") ? `${parentSel}${sel}` : sel.startsWith(":") || sel.startsWith(".") ? `${parentSel}${sel}` : `${parentSel} ${sel}`;
|
|
2071
|
+
const props = toCSSText(sub);
|
|
2072
|
+
if (props) {
|
|
2073
|
+
css += `${atRule} { ${resolved} { ${props} } }
|
|
1946
2074
|
`;
|
|
1947
|
-
emitMediaNested(resolved, sub);
|
|
1948
2075
|
}
|
|
1949
|
-
|
|
1950
|
-
|
|
2076
|
+
emitMediaNested(atRule, resolved, sub);
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
for (const [key, rules] of Object.entries(media)) {
|
|
2080
|
+
if (key === "@--") {
|
|
1951
2081
|
continue;
|
|
2082
|
+
}
|
|
1952
2083
|
const atRule = key.startsWith("@--") ? `@media ${mediaQueries[key.slice(1)] ?? key.slice(1)}` : key.startsWith("@(") ? `@media ${key.slice(1)}` : key;
|
|
1953
2084
|
const scope = `[data-jx="${uid}"]`;
|
|
1954
2085
|
css += `${atRule} { ${scope} { ${toCSSText(rules)} } }
|
|
1955
2086
|
`;
|
|
1956
|
-
emitMediaNested(scope, rules);
|
|
2087
|
+
emitMediaNested(atRule, scope, rules);
|
|
1957
2088
|
}
|
|
1958
2089
|
const tag = document.createElement("style");
|
|
1959
2090
|
tag.textContent = css;
|
|
1960
|
-
document.head.
|
|
2091
|
+
document.head.append(tag);
|
|
1961
2092
|
}
|
|
1962
2093
|
function applyAttributes(el, attrs, state) {
|
|
1963
2094
|
for (const [k, v] of Object.entries(attrs)) {
|
|
@@ -1970,78 +2101,87 @@ function applyAttributes(el, attrs, state) {
|
|
|
1970
2101
|
}
|
|
1971
2102
|
}
|
|
1972
2103
|
}
|
|
1973
|
-
function renderMappedArray(def2, state, options) {
|
|
2104
|
+
function renderMappedArray(def2, arrayDef, state, options) {
|
|
1974
2105
|
const path = options?._path ?? [];
|
|
1975
2106
|
const container = document.createElement(def2.tagName ?? "div");
|
|
1976
|
-
if (options?.onNodeCreated)
|
|
2107
|
+
if (options?.onNodeCreated) {
|
|
1977
2108
|
options.onNodeCreated(container, path, def2);
|
|
2109
|
+
}
|
|
1978
2110
|
applyProperties(container, def2, state);
|
|
1979
2111
|
applyStyle(container, def2.style ?? {}, state["$media"] ?? {}, state);
|
|
1980
2112
|
applyAttributes(container, def2.attributes ?? {}, state);
|
|
1981
|
-
const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef } =
|
|
2113
|
+
const { items: itemsSrc, map: mapDef, filter: filterRef, sort: sortRef } = arrayDef;
|
|
1982
2114
|
effect(() => {
|
|
1983
2115
|
container.innerHTML = "";
|
|
1984
2116
|
let items;
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
} else {
|
|
1988
|
-
items = itemsSrc;
|
|
1989
|
-
}
|
|
1990
|
-
if (!Array.isArray(items))
|
|
2117
|
+
items = isRefObj(itemsSrc) ? resolveRef(itemsSrc.$ref, state) : itemsSrc;
|
|
2118
|
+
if (!Array.isArray(items)) {
|
|
1991
2119
|
return;
|
|
1992
|
-
|
|
2120
|
+
}
|
|
2121
|
+
if (isRefObj(filterRef)) {
|
|
1993
2122
|
const fn = resolveRef(filterRef.$ref, state);
|
|
1994
|
-
if (typeof fn === "function")
|
|
2123
|
+
if (typeof fn === "function") {
|
|
1995
2124
|
items = items.filter(fn);
|
|
2125
|
+
}
|
|
1996
2126
|
}
|
|
1997
|
-
if (sortRef) {
|
|
2127
|
+
if (isRefObj(sortRef)) {
|
|
1998
2128
|
const fn = resolveRef(sortRef.$ref, state);
|
|
1999
|
-
if (typeof fn === "function")
|
|
2000
|
-
items = [...items].
|
|
2129
|
+
if (typeof fn === "function") {
|
|
2130
|
+
items = [...items].toSorted(fn);
|
|
2131
|
+
}
|
|
2001
2132
|
}
|
|
2002
|
-
items.
|
|
2133
|
+
for (const [index, item] of items.entries()) {
|
|
2003
2134
|
const child = Object.create(state);
|
|
2004
|
-
child.$map = {
|
|
2135
|
+
child.$map = { index, item };
|
|
2005
2136
|
child["$map/item"] = item;
|
|
2006
2137
|
child["$map/index"] = index;
|
|
2007
2138
|
const childOpts = options ? { ...options, _path: [...path, "children", "map", index] } : undefined;
|
|
2008
|
-
|
|
2009
|
-
|
|
2139
|
+
if (mapDef) {
|
|
2140
|
+
container.append(renderNode(mapDef, child, childOpts));
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2010
2143
|
});
|
|
2011
2144
|
return container;
|
|
2012
2145
|
}
|
|
2013
2146
|
function renderSwitch(def2, state, options) {
|
|
2014
2147
|
const path = options?._path ?? [];
|
|
2015
2148
|
const container = document.createElement(def2.tagName ?? "div");
|
|
2016
|
-
if (options?.onNodeCreated)
|
|
2149
|
+
if (options?.onNodeCreated) {
|
|
2017
2150
|
options.onNodeCreated(container, path, def2);
|
|
2151
|
+
}
|
|
2018
2152
|
applyProperties(container, def2, state);
|
|
2019
2153
|
applyStyle(container, def2.style ?? {}, state["$media"] ?? {}, state);
|
|
2020
2154
|
applyAttributes(container, def2.attributes ?? {}, state);
|
|
2021
2155
|
let generation = 0;
|
|
2022
2156
|
effect(() => {
|
|
2023
2157
|
container.innerHTML = "";
|
|
2158
|
+
if (!isRefObj(def2.$switch)) {
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2024
2161
|
const key = resolveRef(def2.$switch.$ref, state);
|
|
2025
2162
|
const caseDef = def2.cases?.[key];
|
|
2026
|
-
if (!caseDef)
|
|
2163
|
+
if (!caseDef) {
|
|
2027
2164
|
return;
|
|
2165
|
+
}
|
|
2028
2166
|
if (isRefObj(caseDef)) {
|
|
2029
|
-
const gen =
|
|
2030
|
-
const href = new URL(caseDef.$ref, location.href)
|
|
2167
|
+
const gen = generation += 1;
|
|
2168
|
+
const { href } = new URL(caseDef.$ref, location.href);
|
|
2031
2169
|
resolve(href).then(async (doc) => {
|
|
2032
|
-
if (gen !== generation)
|
|
2170
|
+
if (gen !== generation) {
|
|
2033
2171
|
return;
|
|
2172
|
+
}
|
|
2034
2173
|
const childScope = await buildScope(doc, {}, href);
|
|
2035
|
-
if (gen !== generation)
|
|
2174
|
+
if (gen !== generation) {
|
|
2036
2175
|
return;
|
|
2176
|
+
}
|
|
2037
2177
|
container.innerHTML = "";
|
|
2038
2178
|
const childOpts2 = options ? { ...options, _path: [...path, "cases", key] } : undefined;
|
|
2039
|
-
container.
|
|
2040
|
-
}).catch((
|
|
2179
|
+
container.append(renderNode(doc, childScope, childOpts2));
|
|
2180
|
+
}).catch((error) => console.error("Jx $switch: failed to load external case", caseDef.$ref, error));
|
|
2041
2181
|
return;
|
|
2042
2182
|
}
|
|
2043
2183
|
const childOpts = options ? { ...options, _path: [...path, "cases", key] } : undefined;
|
|
2044
|
-
container.
|
|
2184
|
+
container.append(renderNode(caseDef, state, childOpts));
|
|
2045
2185
|
});
|
|
2046
2186
|
return container;
|
|
2047
2187
|
}
|
|
@@ -2060,28 +2200,31 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
2060
2200
|
if (isTemplateString(def2.url)) {
|
|
2061
2201
|
url = evaluateTemplate(def2.url, state);
|
|
2062
2202
|
} else {
|
|
2063
|
-
url = def2
|
|
2203
|
+
({ url } = def2);
|
|
2064
2204
|
}
|
|
2065
|
-
if (!url || url === "undefined" || url.includes("undefined"))
|
|
2205
|
+
if (!url || url === "undefined" || url.includes("undefined")) {
|
|
2066
2206
|
return;
|
|
2207
|
+
}
|
|
2067
2208
|
const controller = new AbortController;
|
|
2068
2209
|
onEffectCleanup(() => {
|
|
2069
2210
|
controller.abort();
|
|
2070
|
-
if (debounceTimer !== null)
|
|
2211
|
+
if (debounceTimer !== null) {
|
|
2071
2212
|
clearTimeout(debounceTimer);
|
|
2213
|
+
}
|
|
2072
2214
|
});
|
|
2073
2215
|
const doFetch = () => fetch(url, {
|
|
2074
|
-
signal: controller.signal,
|
|
2075
2216
|
method: def2.method ?? "GET",
|
|
2217
|
+
signal: controller.signal,
|
|
2076
2218
|
...def2.headers && { headers: def2.headers },
|
|
2077
2219
|
...def2.body && {
|
|
2078
2220
|
body: typeof def2.body === "object" ? JSON.stringify(def2.body) : def2.body
|
|
2079
2221
|
}
|
|
2080
2222
|
}).then((r) => r.ok ? r.json() : Promise.reject(r.statusText)).then((d) => {
|
|
2081
2223
|
s.value = d;
|
|
2082
|
-
}).catch((
|
|
2083
|
-
if (
|
|
2084
|
-
s.value = { error: String(
|
|
2224
|
+
}).catch((error) => {
|
|
2225
|
+
if (!(error instanceof Error && error.name === "AbortError")) {
|
|
2226
|
+
s.value = { error: String(error) };
|
|
2227
|
+
}
|
|
2085
2228
|
});
|
|
2086
2229
|
if (debounceMs > 0) {
|
|
2087
2230
|
debounceTimer = setTimeout(doFetch, debounceMs);
|
|
@@ -2092,7 +2235,7 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
2092
2235
|
}
|
|
2093
2236
|
return s;
|
|
2094
2237
|
}
|
|
2095
|
-
case "URLSearchParams":
|
|
2238
|
+
case "URLSearchParams": {
|
|
2096
2239
|
return computed(() => {
|
|
2097
2240
|
const p = {};
|
|
2098
2241
|
for (const [k, v] of Object.entries(def2)) {
|
|
@@ -2102,6 +2245,7 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
2102
2245
|
}
|
|
2103
2246
|
return new URLSearchParams(p).toString();
|
|
2104
2247
|
});
|
|
2248
|
+
}
|
|
2105
2249
|
case "LocalStorage":
|
|
2106
2250
|
case "SessionStorage": {
|
|
2107
2251
|
const store = def2.$prototype === "LocalStorage" ? localStorage : sessionStorage;
|
|
@@ -2131,9 +2275,10 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
2131
2275
|
case "Cookie": {
|
|
2132
2276
|
const name = def2.name ?? key;
|
|
2133
2277
|
const read = () => {
|
|
2134
|
-
const m = document.cookie.match(new RegExp(
|
|
2135
|
-
if (!m)
|
|
2278
|
+
const m = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));
|
|
2279
|
+
if (!m) {
|
|
2136
2280
|
return null;
|
|
2281
|
+
}
|
|
2137
2282
|
try {
|
|
2138
2283
|
return JSON.parse(decodeURIComponent(m[1]));
|
|
2139
2284
|
} catch {
|
|
@@ -2144,16 +2289,21 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
2144
2289
|
effect(() => {
|
|
2145
2290
|
const v = cookieState.value;
|
|
2146
2291
|
let s = `${name}=${encodeURIComponent(JSON.stringify(v))}`;
|
|
2147
|
-
if (def2.maxAge !== undefined)
|
|
2292
|
+
if (def2.maxAge !== undefined) {
|
|
2148
2293
|
s += `; Max-Age=${def2.maxAge}`;
|
|
2149
|
-
|
|
2294
|
+
}
|
|
2295
|
+
if (def2.path) {
|
|
2150
2296
|
s += `; Path=${def2.path}`;
|
|
2151
|
-
|
|
2297
|
+
}
|
|
2298
|
+
if (def2.domain) {
|
|
2152
2299
|
s += `; Domain=${def2.domain}`;
|
|
2153
|
-
|
|
2300
|
+
}
|
|
2301
|
+
if (def2.secure) {
|
|
2154
2302
|
s += `; Secure`;
|
|
2155
|
-
|
|
2303
|
+
}
|
|
2304
|
+
if (def2.sameSite) {
|
|
2156
2305
|
s += `; SameSite=${def2.sameSite}`;
|
|
2306
|
+
}
|
|
2157
2307
|
document.cookie = s;
|
|
2158
2308
|
});
|
|
2159
2309
|
return cookieState;
|
|
@@ -2168,47 +2318,59 @@ async function resolvePrototype(def2, state, key, base) {
|
|
|
2168
2318
|
autoIncrement = true,
|
|
2169
2319
|
indexes = []
|
|
2170
2320
|
} = def2;
|
|
2321
|
+
if (!database || !store) {
|
|
2322
|
+
throw new Error(`Jx: IndexedDB entry '${key}' requires database and store`);
|
|
2323
|
+
}
|
|
2171
2324
|
const req = indexedDB.open(database, version);
|
|
2172
|
-
req.
|
|
2325
|
+
req.addEventListener("upgradeneeded", (e) => {
|
|
2173
2326
|
const db = e.target.result;
|
|
2174
2327
|
if (!db.objectStoreNames.contains(store)) {
|
|
2175
|
-
const os = db.createObjectStore(store, {
|
|
2176
|
-
for (const i of indexes)
|
|
2328
|
+
const os = db.createObjectStore(store, { autoIncrement, keyPath });
|
|
2329
|
+
for (const i of indexes) {
|
|
2177
2330
|
os.createIndex(i.name, i.keyPath, { unique: i.unique ?? false });
|
|
2331
|
+
}
|
|
2178
2332
|
}
|
|
2179
|
-
};
|
|
2180
|
-
req.
|
|
2333
|
+
});
|
|
2334
|
+
req.addEventListener("success", (e) => {
|
|
2181
2335
|
const db = e.target.result;
|
|
2182
2336
|
idbState.value = {
|
|
2183
2337
|
database,
|
|
2184
|
-
store,
|
|
2185
|
-
version,
|
|
2338
|
+
getStore: (mode = "readwrite") => Promise.resolve(db.transaction(store, mode).objectStore(store)),
|
|
2186
2339
|
isReady: true,
|
|
2187
|
-
|
|
2340
|
+
store,
|
|
2341
|
+
version
|
|
2188
2342
|
};
|
|
2189
|
-
};
|
|
2190
|
-
req.
|
|
2343
|
+
});
|
|
2344
|
+
req.addEventListener("error", () => {
|
|
2191
2345
|
idbState.value = { error: req.error?.message };
|
|
2192
|
-
};
|
|
2346
|
+
});
|
|
2193
2347
|
return idbState;
|
|
2194
2348
|
}
|
|
2195
|
-
case "Set":
|
|
2196
|
-
return new Set(def2.default
|
|
2197
|
-
|
|
2198
|
-
|
|
2349
|
+
case "Set": {
|
|
2350
|
+
return new Set(Array.isArray(def2.default) ? def2.default : []);
|
|
2351
|
+
}
|
|
2352
|
+
case "Map": {
|
|
2353
|
+
return new Map(Object.entries(isJsonObject(def2.default) ? def2.default : {}));
|
|
2354
|
+
}
|
|
2199
2355
|
case "FormData": {
|
|
2200
2356
|
const fd = new FormData;
|
|
2201
|
-
for (const [k, v] of Object.entries(def2.fields ?? {}))
|
|
2357
|
+
for (const [k, v] of Object.entries(def2.fields ?? {})) {
|
|
2202
2358
|
fd.append(k, v);
|
|
2359
|
+
}
|
|
2203
2360
|
return fd;
|
|
2204
2361
|
}
|
|
2205
|
-
case "Blob":
|
|
2206
|
-
return new Blob(def2.parts ?? [], {
|
|
2207
|
-
|
|
2362
|
+
case "Blob": {
|
|
2363
|
+
return new Blob(def2.parts ?? [], {
|
|
2364
|
+
type: typeof def2.type === "string" ? def2.type : "text/plain"
|
|
2365
|
+
});
|
|
2366
|
+
}
|
|
2367
|
+
case "ReadableStream": {
|
|
2208
2368
|
return null;
|
|
2209
|
-
|
|
2369
|
+
}
|
|
2370
|
+
default: {
|
|
2210
2371
|
console.warn(`Jx: unknown $prototype "${def2.$prototype}" for "${key}". Did you mean to add '$src'?`);
|
|
2211
2372
|
return ref(null);
|
|
2373
|
+
}
|
|
2212
2374
|
}
|
|
2213
2375
|
}
|
|
2214
2376
|
var EXTERNAL_RESERVED = new Set([
|
|
@@ -2225,7 +2387,7 @@ var EXTERNAL_RESERVED = new Set([
|
|
|
2225
2387
|
]);
|
|
2226
2388
|
async function resolveExternalPrototype(def2, state, key, base) {
|
|
2227
2389
|
const src = def2.$src;
|
|
2228
|
-
if (!src.endsWith(".class.json")) {
|
|
2390
|
+
if (!src || !src.endsWith(".class.json")) {
|
|
2229
2391
|
throw new Error(`Jx: $prototype "${def2.$prototype}" requires a .class.json $src, got "${src}". Wrap the class in a .class.json schema with $implementation.`);
|
|
2230
2392
|
}
|
|
2231
2393
|
return resolveClassJson(def2, state, key, base);
|
|
@@ -2252,19 +2414,20 @@ async function importAndInstantiate(def2, src, exportName, base) {
|
|
|
2252
2414
|
throw new Error(`Jx: export "${exportName}" not found in "${src}"`);
|
|
2253
2415
|
}
|
|
2254
2416
|
if (typeof ExportedClass !== "function") {
|
|
2255
|
-
throw new
|
|
2417
|
+
throw new TypeError(`Jx: "${exportName}" from "${src}" is not a class`);
|
|
2256
2418
|
}
|
|
2257
2419
|
const config = {};
|
|
2258
2420
|
for (const [k, v] of Object.entries(def2)) {
|
|
2259
|
-
if (!EXTERNAL_RESERVED.has(k))
|
|
2421
|
+
if (!EXTERNAL_RESERVED.has(k)) {
|
|
2260
2422
|
config[k] = v;
|
|
2423
|
+
}
|
|
2261
2424
|
}
|
|
2262
2425
|
const instance = new ExportedClass(config);
|
|
2263
2426
|
let value;
|
|
2264
2427
|
if (typeof instance.resolve === "function") {
|
|
2265
2428
|
value = await instance.resolve();
|
|
2266
2429
|
} else if ("value" in instance) {
|
|
2267
|
-
value = instance
|
|
2430
|
+
({ value } = instance);
|
|
2268
2431
|
} else {
|
|
2269
2432
|
value = instance;
|
|
2270
2433
|
}
|
|
@@ -2278,6 +2441,9 @@ async function importAndInstantiate(def2, src, exportName, base) {
|
|
|
2278
2441
|
}
|
|
2279
2442
|
async function resolveClassJson(def2, state, key, base) {
|
|
2280
2443
|
const src = def2.$src;
|
|
2444
|
+
if (!src) {
|
|
2445
|
+
throw new Error(`Jx: class entry '${key}' has no $src`);
|
|
2446
|
+
}
|
|
2281
2447
|
let classDef;
|
|
2282
2448
|
const isBareSpecifier = !src.startsWith(".") && !src.startsWith("/") && !src.startsWith("http") && !src.startsWith("file:");
|
|
2283
2449
|
if (isBareSpecifier) {
|
|
@@ -2286,8 +2452,9 @@ async function resolveClassJson(def2, state, key, base) {
|
|
|
2286
2452
|
try {
|
|
2287
2453
|
const url = base ? new URL(src, base).href : src;
|
|
2288
2454
|
const res = await fetch(url);
|
|
2289
|
-
if (!res.ok)
|
|
2455
|
+
if (!res.ok) {
|
|
2290
2456
|
throw new Error(`HTTP ${res.status}`);
|
|
2457
|
+
}
|
|
2291
2458
|
classDef = await res.json();
|
|
2292
2459
|
} catch {
|
|
2293
2460
|
return resolveViaDevProxy(def2, state, key, base);
|
|
@@ -2309,15 +2476,16 @@ async function resolveClassJson(def2, state, key, base) {
|
|
|
2309
2476
|
const DynClass = classFromSchema(classDef);
|
|
2310
2477
|
const config = {};
|
|
2311
2478
|
for (const [k, v] of Object.entries(def2)) {
|
|
2312
|
-
if (!EXTERNAL_RESERVED.has(k))
|
|
2479
|
+
if (!EXTERNAL_RESERVED.has(k)) {
|
|
2313
2480
|
config[k] = v;
|
|
2481
|
+
}
|
|
2314
2482
|
}
|
|
2315
2483
|
const instance = new DynClass(config);
|
|
2316
2484
|
let value;
|
|
2317
2485
|
if (typeof instance.resolve === "function") {
|
|
2318
2486
|
value = await instance.resolve();
|
|
2319
2487
|
} else if ("value" in instance) {
|
|
2320
|
-
value = instance
|
|
2488
|
+
({ value } = instance);
|
|
2321
2489
|
} else {
|
|
2322
2490
|
value = instance;
|
|
2323
2491
|
}
|
|
@@ -2331,23 +2499,24 @@ async function resolveClassJson(def2, state, key, base) {
|
|
|
2331
2499
|
}
|
|
2332
2500
|
function classFromSchema(classDef) {
|
|
2333
2501
|
const fields = classDef.$defs?.fields ?? {};
|
|
2334
|
-
const
|
|
2502
|
+
const rawCtor = classDef.$defs?.constructor;
|
|
2503
|
+
const ctor = typeof rawCtor === "object" ? rawCtor : undefined;
|
|
2335
2504
|
const methods = classDef.$defs?.methods ?? {};
|
|
2336
2505
|
|
|
2337
2506
|
class DynClass {
|
|
2338
2507
|
constructor(config = {}) {
|
|
2339
|
-
for (const [key,
|
|
2340
|
-
const typedField = field;
|
|
2508
|
+
for (const [key, typedField] of Object.entries(fields)) {
|
|
2341
2509
|
const id = typedField.identifier ?? key;
|
|
2342
2510
|
const propName = typedField.access === "private" ? `_${id}` : id;
|
|
2343
|
-
if (config[id] !== undefined)
|
|
2511
|
+
if (config[id] !== undefined) {
|
|
2344
2512
|
this[propName] = config[id];
|
|
2345
|
-
else if (typedField.initializer !== undefined)
|
|
2513
|
+
} else if (typedField.initializer !== undefined) {
|
|
2346
2514
|
this[propName] = typedField.initializer;
|
|
2347
|
-
else if (typedField.default !== undefined)
|
|
2515
|
+
} else if (typedField.default !== undefined) {
|
|
2348
2516
|
this[propName] = structuredClone(typedField.default);
|
|
2349
|
-
else
|
|
2517
|
+
} else {
|
|
2350
2518
|
this[propName] = null;
|
|
2519
|
+
}
|
|
2351
2520
|
}
|
|
2352
2521
|
if (ctor?.body) {
|
|
2353
2522
|
const bodyStr = Array.isArray(ctor.body) ? ctor.body.join(`
|
|
@@ -2356,23 +2525,25 @@ function classFromSchema(classDef) {
|
|
|
2356
2525
|
}
|
|
2357
2526
|
}
|
|
2358
2527
|
}
|
|
2359
|
-
for (const [key,
|
|
2360
|
-
const typedMethod = method;
|
|
2528
|
+
for (const [key, typedMethod] of Object.entries(methods)) {
|
|
2361
2529
|
const name = typedMethod.identifier ?? key;
|
|
2362
2530
|
const params = (typedMethod.parameters ?? []).map((p) => {
|
|
2363
|
-
if (p.$ref)
|
|
2531
|
+
if (p.$ref) {
|
|
2364
2532
|
return p.$ref.split("/").pop();
|
|
2365
|
-
|
|
2533
|
+
}
|
|
2534
|
+
const n = p.identifier ?? p.name;
|
|
2535
|
+
return typeof n === "string" ? n : "arg";
|
|
2366
2536
|
});
|
|
2367
2537
|
const bodyStr = Array.isArray(typedMethod.body) ? typedMethod.body.join(`
|
|
2368
2538
|
`) : typedMethod.body ?? "";
|
|
2369
2539
|
if (typedMethod.role === "accessor") {
|
|
2370
2540
|
const descriptor = {};
|
|
2371
|
-
if (typedMethod.getter)
|
|
2372
|
-
descriptor.get = new Function(typedMethod.getter.body);
|
|
2541
|
+
if (typedMethod.getter) {
|
|
2542
|
+
descriptor.get = new Function(typedMethod.getter.body ?? "");
|
|
2543
|
+
}
|
|
2373
2544
|
if (typedMethod.setter) {
|
|
2374
2545
|
const sp = (typedMethod.setter.parameters ?? []).map((p) => p.$ref?.split("/").pop() ?? "v");
|
|
2375
|
-
descriptor.set = new Function(...sp, typedMethod.setter.body);
|
|
2546
|
+
descriptor.set = new Function(...sp, typedMethod.setter.body ?? "");
|
|
2376
2547
|
}
|
|
2377
2548
|
Object.defineProperty(DynClass.prototype, name, {
|
|
2378
2549
|
...descriptor,
|
|
@@ -2385,8 +2556,8 @@ function classFromSchema(classDef) {
|
|
|
2385
2556
|
}
|
|
2386
2557
|
}
|
|
2387
2558
|
Object.defineProperty(DynClass, "name", {
|
|
2388
|
-
|
|
2389
|
-
|
|
2559
|
+
configurable: true,
|
|
2560
|
+
value: classDef.title
|
|
2390
2561
|
});
|
|
2391
2562
|
const dynCtor = DynClass;
|
|
2392
2563
|
return dynCtor;
|
|
@@ -2394,23 +2565,25 @@ function classFromSchema(classDef) {
|
|
|
2394
2565
|
async function resolveViaDevProxy(def2, state, key, base) {
|
|
2395
2566
|
const config = {};
|
|
2396
2567
|
for (const [k, v] of Object.entries(def2)) {
|
|
2397
|
-
if (!EXTERNAL_RESERVED.has(k))
|
|
2568
|
+
if (!EXTERNAL_RESERVED.has(k)) {
|
|
2398
2569
|
config[k] = v;
|
|
2570
|
+
}
|
|
2399
2571
|
}
|
|
2400
2572
|
const hasTemplates = Object.values(config).some((v) => isTemplateString(v));
|
|
2401
2573
|
const doResolve = (resolvedConfig) => fetch("/__jx_resolve__", {
|
|
2402
|
-
method: "POST",
|
|
2403
|
-
headers: { "Content-Type": "application/json" },
|
|
2404
2574
|
body: JSON.stringify({
|
|
2405
|
-
$src: def2.$src,
|
|
2406
|
-
$prototype: def2.$prototype,
|
|
2407
|
-
$export: def2.$export,
|
|
2408
2575
|
$base: base,
|
|
2576
|
+
$export: def2.$export,
|
|
2577
|
+
$prototype: def2.$prototype,
|
|
2578
|
+
$src: def2.$src,
|
|
2409
2579
|
...resolvedConfig
|
|
2410
|
-
})
|
|
2580
|
+
}),
|
|
2581
|
+
headers: { "Content-Type": "application/json" },
|
|
2582
|
+
method: "POST"
|
|
2411
2583
|
}).then((r) => {
|
|
2412
|
-
if (!r.ok)
|
|
2584
|
+
if (!r.ok) {
|
|
2413
2585
|
throw new Error(`Jx dev proxy ${r.status} for "${key}"`);
|
|
2586
|
+
}
|
|
2414
2587
|
return r.json();
|
|
2415
2588
|
});
|
|
2416
2589
|
const s = ref(null);
|
|
@@ -2422,12 +2595,12 @@ async function resolveViaDevProxy(def2, state, key, base) {
|
|
|
2422
2595
|
}
|
|
2423
2596
|
doResolve(resolvedConfig).then((value) => {
|
|
2424
2597
|
s.value = value;
|
|
2425
|
-
}).catch((
|
|
2598
|
+
}).catch((error) => console.error("Jx dev proxy:", error));
|
|
2426
2599
|
});
|
|
2427
2600
|
} else {
|
|
2428
2601
|
doResolve(config).then((value) => {
|
|
2429
2602
|
s.value = value;
|
|
2430
|
-
}).catch((
|
|
2603
|
+
}).catch((error) => console.error("Jx dev proxy:", error));
|
|
2431
2604
|
}
|
|
2432
2605
|
return s;
|
|
2433
2606
|
}
|
|
@@ -2455,10 +2628,12 @@ async function resolveServerFunction(def2, state, key, base) {
|
|
|
2455
2628
|
_moduleCache.set(src, mod);
|
|
2456
2629
|
}
|
|
2457
2630
|
const fn = mod[exportName] ?? mod.default?.[exportName];
|
|
2458
|
-
if (!fn)
|
|
2631
|
+
if (!fn) {
|
|
2459
2632
|
throw new Error(`Jx: export "${exportName}" not found in "${src}" for "${key}"`);
|
|
2460
|
-
|
|
2461
|
-
|
|
2633
|
+
}
|
|
2634
|
+
if (typeof fn !== "function") {
|
|
2635
|
+
throw new TypeError(`Jx: "${exportName}" from "${src}" is not a function`);
|
|
2636
|
+
}
|
|
2462
2637
|
const rawArgs = def2.arguments ?? {};
|
|
2463
2638
|
const hasReactiveArg = Object.values(rawArgs).some((v) => isRefObj(v));
|
|
2464
2639
|
const resolveArgs = () => {
|
|
@@ -2493,17 +2668,18 @@ async function resolveServerFunctionViaProxy(def2, state, key, base) {
|
|
|
2493
2668
|
return args;
|
|
2494
2669
|
};
|
|
2495
2670
|
const doResolve = (args) => fetch("/__jx_server__", {
|
|
2496
|
-
method: "POST",
|
|
2497
|
-
headers: { "Content-Type": "application/json" },
|
|
2498
2671
|
body: JSON.stringify({
|
|
2499
|
-
$src: def2.$src,
|
|
2500
|
-
$export: def2.$export,
|
|
2501
2672
|
$base: base,
|
|
2673
|
+
$export: def2.$export,
|
|
2674
|
+
$src: def2.$src,
|
|
2502
2675
|
arguments: args
|
|
2503
|
-
})
|
|
2676
|
+
}),
|
|
2677
|
+
headers: { "Content-Type": "application/json" },
|
|
2678
|
+
method: "POST"
|
|
2504
2679
|
}).then((r) => {
|
|
2505
|
-
if (!r.ok)
|
|
2680
|
+
if (!r.ok) {
|
|
2506
2681
|
throw new Error(`Jx server proxy ${r.status} for "${key}"`);
|
|
2682
|
+
}
|
|
2507
2683
|
return r.json();
|
|
2508
2684
|
});
|
|
2509
2685
|
const s = ref(null);
|
|
@@ -2513,50 +2689,60 @@ async function resolveServerFunctionViaProxy(def2, state, key, base) {
|
|
|
2513
2689
|
onEffectCleanup(() => {});
|
|
2514
2690
|
doResolve(args).then((result) => {
|
|
2515
2691
|
s.value = result;
|
|
2516
|
-
}).catch((
|
|
2692
|
+
}).catch((error) => console.error("Jx server proxy:", error));
|
|
2517
2693
|
});
|
|
2518
2694
|
} else {
|
|
2519
2695
|
doResolve(resolveArgs()).then((result) => {
|
|
2520
2696
|
s.value = result;
|
|
2521
|
-
}).catch((
|
|
2697
|
+
}).catch((error) => console.error("Jx server proxy:", error));
|
|
2522
2698
|
}
|
|
2523
2699
|
return s;
|
|
2524
2700
|
}
|
|
2525
|
-
function resolveRef(
|
|
2526
|
-
if (typeof
|
|
2527
|
-
return
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
const
|
|
2531
|
-
const
|
|
2701
|
+
function resolveRef(refPath, state) {
|
|
2702
|
+
if (typeof refPath !== "string") {
|
|
2703
|
+
return refPath;
|
|
2704
|
+
}
|
|
2705
|
+
if (refPath.startsWith("$map/")) {
|
|
2706
|
+
const parts = refPath.split("/");
|
|
2707
|
+
const [, key] = parts;
|
|
2708
|
+
const map = state.$map;
|
|
2709
|
+
const base = map?.[key] ?? state[`$map/${key}`];
|
|
2532
2710
|
return parts.length > 2 ? getPath2(base, parts.slice(2).join("/")) : base;
|
|
2533
2711
|
}
|
|
2534
|
-
if (
|
|
2535
|
-
const sub =
|
|
2712
|
+
if (refPath.startsWith("#/state/")) {
|
|
2713
|
+
const sub = refPath.slice("#/state/".length);
|
|
2536
2714
|
const slash = sub.indexOf("/");
|
|
2537
|
-
if (slash
|
|
2715
|
+
if (slash === -1) {
|
|
2538
2716
|
return state[sub];
|
|
2717
|
+
}
|
|
2539
2718
|
return getPath2(state[sub.slice(0, slash)], sub.slice(slash + 1));
|
|
2540
2719
|
}
|
|
2541
|
-
if (
|
|
2542
|
-
return state[
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2720
|
+
if (refPath.startsWith("parent#/")) {
|
|
2721
|
+
return state[refPath.slice("parent#/".length)];
|
|
2722
|
+
}
|
|
2723
|
+
if (refPath.startsWith("window#/")) {
|
|
2724
|
+
return getPath2(globalThis.window, refPath.slice("window#/".length));
|
|
2725
|
+
}
|
|
2726
|
+
if (refPath.startsWith("document#/")) {
|
|
2727
|
+
return getPath2(globalThis.document, refPath.slice("document#/".length));
|
|
2728
|
+
}
|
|
2729
|
+
return state[refPath] ?? null;
|
|
2548
2730
|
}
|
|
2549
2731
|
function isSignal(v) {
|
|
2550
2732
|
return isRef(v);
|
|
2551
2733
|
}
|
|
2552
2734
|
function isRefObj(v) {
|
|
2553
|
-
return v
|
|
2735
|
+
return isRef2(v);
|
|
2554
2736
|
}
|
|
2555
2737
|
function isNestedSelector(k) {
|
|
2556
2738
|
return k.startsWith(":") || k.startsWith(".") || k.startsWith("&") || k.startsWith("[");
|
|
2557
2739
|
}
|
|
2558
2740
|
function getPath2(obj, path) {
|
|
2559
|
-
|
|
2741
|
+
let current = obj;
|
|
2742
|
+
for (const k of path.split(/[./]/)) {
|
|
2743
|
+
current = current?.[k];
|
|
2744
|
+
}
|
|
2745
|
+
return current;
|
|
2560
2746
|
}
|
|
2561
2747
|
function mergeProps(def2, parentState) {
|
|
2562
2748
|
const child = Object.create(parentState);
|
|
@@ -2566,7 +2752,7 @@ function mergeProps(def2, parentState) {
|
|
|
2566
2752
|
return child;
|
|
2567
2753
|
}
|
|
2568
2754
|
function camelToKebab(s) {
|
|
2569
|
-
return s.
|
|
2755
|
+
return s.replaceAll(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
|
|
2570
2756
|
}
|
|
2571
2757
|
function toCSSText(rules) {
|
|
2572
2758
|
return Object.entries(rules).filter(([k, v]) => !isNestedSelector(k) && (v === null || typeof v !== "object")).map(([p, v]) => `${camelToKebab(p)}: ${v}`).join("; ");
|
|
@@ -2579,19 +2765,22 @@ async function registerElements(elements, base) {
|
|
|
2579
2765
|
try {
|
|
2580
2766
|
const specifier = entry.startsWith("/") || entry.startsWith(".") ? entry : `/node_modules/${entry}`;
|
|
2581
2767
|
await import(specifier);
|
|
2582
|
-
} catch (
|
|
2583
|
-
console.warn(`Jx: failed to import package "${entry}"`,
|
|
2768
|
+
} catch (error) {
|
|
2769
|
+
console.warn(`Jx: failed to import package "${entry}"`, error);
|
|
2584
2770
|
}
|
|
2585
2771
|
continue;
|
|
2586
2772
|
}
|
|
2587
|
-
if (!isRefObj(entry))
|
|
2773
|
+
if (!isRefObj(entry)) {
|
|
2588
2774
|
continue;
|
|
2589
|
-
|
|
2775
|
+
}
|
|
2776
|
+
const { href } = new URL(entry.$ref, base);
|
|
2590
2777
|
const doc = await resolve(href);
|
|
2591
|
-
if (!doc.tagName || !doc.tagName.includes("-"))
|
|
2778
|
+
if (!doc.tagName || !doc.tagName.includes("-")) {
|
|
2592
2779
|
continue;
|
|
2593
|
-
|
|
2780
|
+
}
|
|
2781
|
+
if (customElements.get(doc.tagName)) {
|
|
2594
2782
|
continue;
|
|
2783
|
+
}
|
|
2595
2784
|
if (doc.$elements) {
|
|
2596
2785
|
await registerElements(doc.$elements, href);
|
|
2597
2786
|
}
|
|
@@ -2600,48 +2789,56 @@ async function registerElements(elements, base) {
|
|
|
2600
2789
|
}
|
|
2601
2790
|
function injectHead(entries, _base) {
|
|
2602
2791
|
for (const entry of entries) {
|
|
2603
|
-
if (!entry || !entry.tagName)
|
|
2792
|
+
if (!entry || !entry.tagName) {
|
|
2604
2793
|
continue;
|
|
2794
|
+
}
|
|
2605
2795
|
const tag = entry.tagName.toLowerCase();
|
|
2606
2796
|
const attrs = { ...entry.attributes };
|
|
2607
2797
|
for (const key of ["href", "src"]) {
|
|
2608
|
-
|
|
2609
|
-
|
|
2798
|
+
const v = attrs[key];
|
|
2799
|
+
if (typeof v === "string" && v && !v.startsWith("/") && !v.startsWith(".") && !v.startsWith("http")) {
|
|
2800
|
+
attrs[key] = `/node_modules/${v}`;
|
|
2610
2801
|
}
|
|
2611
2802
|
}
|
|
2612
2803
|
const selector = `${tag}${attrs.href ? `[href="${attrs.href}"]` : ""}${attrs.src ? `[src="${attrs.src}"]` : ""}`;
|
|
2613
|
-
if (selector !== tag && document.head.querySelector(selector))
|
|
2804
|
+
if (selector !== tag && document.head.querySelector(selector)) {
|
|
2614
2805
|
continue;
|
|
2806
|
+
}
|
|
2615
2807
|
const el = document.createElement(tag);
|
|
2616
2808
|
for (const [k, v] of Object.entries(attrs)) {
|
|
2617
|
-
el.setAttribute(k, v);
|
|
2809
|
+
el.setAttribute(k, String(v));
|
|
2618
2810
|
}
|
|
2619
|
-
if (entry.textContent)
|
|
2811
|
+
if (entry.textContent) {
|
|
2620
2812
|
el.textContent = entry.textContent;
|
|
2621
|
-
|
|
2813
|
+
}
|
|
2814
|
+
document.head.append(el);
|
|
2622
2815
|
}
|
|
2623
2816
|
}
|
|
2624
2817
|
var _definedSources = new Set;
|
|
2625
|
-
async function defineElement(source,
|
|
2818
|
+
async function defineElement(source, baseUrl) {
|
|
2819
|
+
let base = baseUrl;
|
|
2820
|
+
let doc = source;
|
|
2626
2821
|
if (typeof source === "string") {
|
|
2627
2822
|
base = new URL(source, base ?? location.href).href;
|
|
2628
|
-
if (_definedSources.has(base))
|
|
2823
|
+
if (_definedSources.has(base)) {
|
|
2629
2824
|
return;
|
|
2825
|
+
}
|
|
2630
2826
|
_definedSources.add(base);
|
|
2631
|
-
|
|
2827
|
+
doc = await resolve(source);
|
|
2632
2828
|
}
|
|
2633
|
-
base
|
|
2634
|
-
const source_ =
|
|
2635
|
-
const tagName = source_
|
|
2829
|
+
base ??= location.href;
|
|
2830
|
+
const source_ = doc;
|
|
2831
|
+
const { tagName } = source_;
|
|
2636
2832
|
if (!tagName || !tagName.includes("-")) {
|
|
2637
2833
|
throw new Error(`Jx defineElement: tagName "${tagName}" must contain a hyphen`);
|
|
2638
2834
|
}
|
|
2639
|
-
if (customElements.get(tagName))
|
|
2835
|
+
if (customElements.get(tagName)) {
|
|
2640
2836
|
return;
|
|
2837
|
+
}
|
|
2641
2838
|
if (source_.$elements) {
|
|
2642
2839
|
await registerElements(source_.$elements, base);
|
|
2643
2840
|
}
|
|
2644
|
-
_elementDefs.set(tagName, { doc: source_
|
|
2841
|
+
_elementDefs.set(tagName, { base, doc: source_ });
|
|
2645
2842
|
const def2 = source_;
|
|
2646
2843
|
const observedAttrs = def2.observedAttributes ?? [];
|
|
2647
2844
|
const ElementClass = class extends HTMLElement {
|
|
@@ -2651,20 +2848,22 @@ async function defineElement(source, base) {
|
|
|
2651
2848
|
return observedAttrs;
|
|
2652
2849
|
}
|
|
2653
2850
|
async connectedCallback() {
|
|
2654
|
-
if (this._jxInitialized)
|
|
2851
|
+
if (this._jxInitialized) {
|
|
2655
2852
|
return;
|
|
2853
|
+
}
|
|
2656
2854
|
this._jxInitialized = true;
|
|
2657
2855
|
const state = await buildScope(def2, {}, base);
|
|
2658
|
-
const propsAttr = this.
|
|
2856
|
+
const propsAttr = this.dataset.jxProps;
|
|
2659
2857
|
if (propsAttr) {
|
|
2660
2858
|
try {
|
|
2661
2859
|
const props = JSON.parse(propsAttr);
|
|
2662
2860
|
for (const [key, val] of Object.entries(props)) {
|
|
2663
|
-
if (key in (def2.state ?? {}))
|
|
2861
|
+
if (key in (def2.state ?? {})) {
|
|
2664
2862
|
state[key] = val;
|
|
2863
|
+
}
|
|
2665
2864
|
}
|
|
2666
2865
|
} catch {}
|
|
2667
|
-
this.
|
|
2866
|
+
delete this.dataset.jxProps;
|
|
2668
2867
|
}
|
|
2669
2868
|
for (const key of Object.keys(def2.state ?? {})) {
|
|
2670
2869
|
if (key in this && this[key] !== undefined) {
|
|
@@ -2674,28 +2873,30 @@ async function defineElement(source, base) {
|
|
|
2674
2873
|
for (const key of Object.keys(def2.state ?? {})) {
|
|
2675
2874
|
if (!(key in HTMLElement.prototype)) {
|
|
2676
2875
|
Object.defineProperty(this, key, {
|
|
2876
|
+
configurable: true,
|
|
2677
2877
|
get: () => state[key],
|
|
2678
2878
|
set: (v) => {
|
|
2679
2879
|
state[key] = v;
|
|
2680
|
-
}
|
|
2681
|
-
configurable: true
|
|
2880
|
+
}
|
|
2682
2881
|
});
|
|
2683
2882
|
}
|
|
2684
2883
|
}
|
|
2685
2884
|
this._state = state;
|
|
2686
|
-
const slottedChildren =
|
|
2885
|
+
const slottedChildren = [...this.childNodes];
|
|
2687
2886
|
this.innerHTML = "";
|
|
2688
|
-
if (!this.style.display)
|
|
2887
|
+
if (!this.style.display) {
|
|
2689
2888
|
this.style.display = "block";
|
|
2889
|
+
}
|
|
2690
2890
|
applyStyle(this, def2.style ?? {}, state["$media"] ?? {}, state);
|
|
2691
2891
|
applyAttributes(this, def2.attributes ?? {}, state);
|
|
2692
2892
|
const children = Array.isArray(def2.children) ? def2.children : [];
|
|
2693
2893
|
for (const childDef of children) {
|
|
2694
|
-
this.
|
|
2894
|
+
this.append(renderNode(childDef, state));
|
|
2695
2895
|
}
|
|
2696
2896
|
distributeSlots(this, slottedChildren);
|
|
2697
|
-
|
|
2698
|
-
|
|
2897
|
+
const { onMount } = state;
|
|
2898
|
+
if (typeof onMount === "function") {
|
|
2899
|
+
queueMicrotask(() => onMount(state));
|
|
2699
2900
|
}
|
|
2700
2901
|
}
|
|
2701
2902
|
disconnectedCallback() {
|
|
@@ -2709,24 +2910,27 @@ async function defineElement(source, base) {
|
|
|
2709
2910
|
}
|
|
2710
2911
|
}
|
|
2711
2912
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
2712
|
-
if (!this._state || oldVal === newVal)
|
|
2913
|
+
if (!this._state || oldVal === newVal) {
|
|
2713
2914
|
return;
|
|
2714
|
-
|
|
2915
|
+
}
|
|
2916
|
+
const camelKey = name.replaceAll(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
2715
2917
|
const current = this._state[camelKey];
|
|
2716
|
-
if (typeof current === "number")
|
|
2918
|
+
if (typeof current === "number") {
|
|
2717
2919
|
this._state[camelKey] = Number(newVal);
|
|
2718
|
-
else if (typeof current === "boolean")
|
|
2920
|
+
} else if (typeof current === "boolean") {
|
|
2719
2921
|
this._state[camelKey] = newVal !== null && newVal !== "false";
|
|
2720
|
-
else
|
|
2922
|
+
} else {
|
|
2721
2923
|
this._state[camelKey] = newVal;
|
|
2924
|
+
}
|
|
2722
2925
|
}
|
|
2723
2926
|
};
|
|
2724
2927
|
customElements.define(tagName, ElementClass);
|
|
2725
2928
|
}
|
|
2726
2929
|
function renderCustomElementWithProps(def2, state, options, path) {
|
|
2727
|
-
const el = document.createElement(def2.tagName);
|
|
2728
|
-
if (options?.onNodeCreated)
|
|
2930
|
+
const el = document.createElement(def2.tagName ?? "div");
|
|
2931
|
+
if (options?.onNodeCreated) {
|
|
2729
2932
|
options.onNodeCreated(el, path ?? [], def2);
|
|
2933
|
+
}
|
|
2730
2934
|
for (const [key, val] of Object.entries(def2.$props ?? {})) {
|
|
2731
2935
|
if (isRefObj(val)) {
|
|
2732
2936
|
const refVal = val;
|
|
@@ -2748,23 +2952,26 @@ function renderCustomElementWithProps(def2, state, options, path) {
|
|
|
2748
2952
|
const children = Array.isArray(def2.children) ? def2.children : [];
|
|
2749
2953
|
for (let i = 0;i < children.length; i++) {
|
|
2750
2954
|
const childOpts = options && path ? { ...options, _path: [...path, "children", i] } : undefined;
|
|
2751
|
-
el.
|
|
2955
|
+
el.append(renderNode(children[i], state, childOpts));
|
|
2752
2956
|
}
|
|
2753
2957
|
return el;
|
|
2754
2958
|
}
|
|
2755
2959
|
function distributeSlots(host, slottedChildren) {
|
|
2756
|
-
if (slottedChildren.length === 0)
|
|
2960
|
+
if (slottedChildren.length === 0) {
|
|
2757
2961
|
return;
|
|
2962
|
+
}
|
|
2758
2963
|
const slots = host.querySelectorAll("slot");
|
|
2759
|
-
if (slots.length === 0)
|
|
2964
|
+
if (slots.length === 0) {
|
|
2760
2965
|
return;
|
|
2966
|
+
}
|
|
2761
2967
|
const named = new Map;
|
|
2762
2968
|
const unnamed = [];
|
|
2763
2969
|
for (const child of slottedChildren) {
|
|
2764
2970
|
if (child.nodeType === Node.ELEMENT_NODE && child.getAttribute("slot")) {
|
|
2765
2971
|
const name = child.getAttribute("slot");
|
|
2766
|
-
if (!named.has(name))
|
|
2972
|
+
if (!named.has(name)) {
|
|
2767
2973
|
named.set(name, []);
|
|
2974
|
+
}
|
|
2768
2975
|
named.get(name).push(child);
|
|
2769
2976
|
} else {
|
|
2770
2977
|
unnamed.push(child);
|
|
@@ -2776,7 +2983,7 @@ function distributeSlots(host, slottedChildren) {
|
|
|
2776
2983
|
if (matches.length > 0) {
|
|
2777
2984
|
slot.innerHTML = "";
|
|
2778
2985
|
for (const child of matches) {
|
|
2779
|
-
slot.
|
|
2986
|
+
slot.append(child);
|
|
2780
2987
|
}
|
|
2781
2988
|
}
|
|
2782
2989
|
}
|
|
@@ -2799,5 +3006,5 @@ export {
|
|
|
2799
3006
|
Jx
|
|
2800
3007
|
};
|
|
2801
3008
|
|
|
2802
|
-
//# debugId=
|
|
3009
|
+
//# debugId=32F6E02650EECC3864756E2164756E21
|
|
2803
3010
|
//# sourceMappingURL=runtime.js.map
|