@lark.js/mvc 0.0.7 → 0.0.9
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/README.md +147 -120
- package/dist/compiler.cjs +15366 -0
- package/dist/compiler.d.cts +76 -0
- package/dist/compiler.d.ts +76 -0
- package/dist/compiler.js +15353 -0
- package/dist/index.cjs +80 -842
- package/dist/index.d.cts +34 -97
- package/dist/index.d.ts +34 -97
- package/dist/index.js +70 -830
- package/package.json +15 -5
- package/src/client.d.ts +2 -2
package/dist/index.js
CHANGED
|
@@ -6,14 +6,6 @@ var RouterEvents = {
|
|
|
6
6
|
CHANGED: "changed",
|
|
7
7
|
PAGE_UNLOAD: "page_unload"
|
|
8
8
|
};
|
|
9
|
-
var LarkInnerKeys = {
|
|
10
|
-
/** Attribute name: ldk (static key for skipping VDOM diff) */
|
|
11
|
-
DIFF_KEY: "ldk",
|
|
12
|
-
/** Attribute name: lak (static attribute key) */
|
|
13
|
-
ATTR_KEY: "lak",
|
|
14
|
-
/** Attribute name: lvk (view key for assign) */
|
|
15
|
-
VIEW_KEY: "lvk"
|
|
16
|
-
};
|
|
17
9
|
var LARK_VIEW = "v-lark";
|
|
18
10
|
var EVENT_METHOD_REGEXP = new RegExp(
|
|
19
11
|
`(?:([\\w-]+)${SPLITTER})?([^(]+)\\(([\\s\\S]*?)?\\)`
|
|
@@ -795,6 +787,9 @@ function attachViewAndPath(loc) {
|
|
|
795
787
|
if (!loc.view) {
|
|
796
788
|
const rawPath = routeMode === "history" ? loc.query["path"] || loc.hash["path"] : loc.hash["path"];
|
|
797
789
|
let path = rawPath || cachedDefaultPath || "/";
|
|
790
|
+
if (!cachedRoutes[path] && path === "/" && cachedDefaultPath && cachedDefaultPath !== "/") {
|
|
791
|
+
path = cachedDefaultPath;
|
|
792
|
+
}
|
|
798
793
|
if (cachedRewrite) {
|
|
799
794
|
path = cachedRewrite(
|
|
800
795
|
path,
|
|
@@ -863,6 +858,10 @@ function getChanged(oldLoc, newLoc) {
|
|
|
863
858
|
function updateBrowserUrl(path, replace) {
|
|
864
859
|
if (routeMode === "history") {
|
|
865
860
|
const url = path || "/";
|
|
861
|
+
const currentUrl = window.location.pathname + window.location.search;
|
|
862
|
+
if (url === currentUrl) {
|
|
863
|
+
return;
|
|
864
|
+
}
|
|
866
865
|
if (replace) {
|
|
867
866
|
window.history.replaceState(null, "", url);
|
|
868
867
|
} else {
|
|
@@ -884,6 +883,9 @@ function updateUrl(path, params, loc, replace, silentFlag, lQuery) {
|
|
|
884
883
|
if (path !== currentSrc) {
|
|
885
884
|
silent = silentFlag ? 1 : 0;
|
|
886
885
|
updateBrowserUrl(path, replace);
|
|
886
|
+
if (routeMode === "history" && Router.notify) {
|
|
887
|
+
Router.notify();
|
|
888
|
+
}
|
|
887
889
|
}
|
|
888
890
|
}
|
|
889
891
|
var Router = {
|
|
@@ -1363,7 +1365,7 @@ var EventDelegator = {
|
|
|
1363
1365
|
}
|
|
1364
1366
|
};
|
|
1365
1367
|
|
|
1366
|
-
// src/
|
|
1368
|
+
// src/dom.ts
|
|
1367
1369
|
var wrapMeta = {
|
|
1368
1370
|
option: [1, "<select multiple>"],
|
|
1369
1371
|
thead: [1, "<table>"],
|
|
@@ -1383,12 +1385,12 @@ var VDoc = document.implementation.createHTMLDocument("");
|
|
|
1383
1385
|
var VBase = VDoc.createElement("base");
|
|
1384
1386
|
VBase.href = document.location.href;
|
|
1385
1387
|
VDoc.head.appendChild(VBase);
|
|
1386
|
-
var
|
|
1388
|
+
var DomSpecials = {
|
|
1387
1389
|
INPUT: ["value", "checked"],
|
|
1388
1390
|
TEXTAREA: ["value"],
|
|
1389
1391
|
OPTION: ["selected"]
|
|
1390
1392
|
};
|
|
1391
|
-
function
|
|
1393
|
+
function domUnmountFrames(frame, node) {
|
|
1392
1394
|
if (!(node instanceof Element)) return;
|
|
1393
1395
|
const id = node.getAttribute("id");
|
|
1394
1396
|
if (!id) return;
|
|
@@ -1397,7 +1399,7 @@ function vdomUnmountFrames(frame, node) {
|
|
|
1397
1399
|
frame.unmountFrame(id);
|
|
1398
1400
|
}
|
|
1399
1401
|
}
|
|
1400
|
-
function
|
|
1402
|
+
function domGetNode(html, refNode) {
|
|
1401
1403
|
const tmp = VDoc.createElement("div");
|
|
1402
1404
|
const ns = refNode.namespaceURI;
|
|
1403
1405
|
let tag;
|
|
@@ -1418,16 +1420,13 @@ function vdomGetNode(html, refNode) {
|
|
|
1418
1420
|
}
|
|
1419
1421
|
return tmp;
|
|
1420
1422
|
}
|
|
1421
|
-
function
|
|
1423
|
+
function domGetCompareKey(node) {
|
|
1422
1424
|
if (node.nodeType !== 1) return void 0;
|
|
1423
1425
|
const el = node;
|
|
1424
1426
|
if (el.compareKeyCached) {
|
|
1425
1427
|
return el.cachedCompareKey;
|
|
1426
1428
|
}
|
|
1427
1429
|
let key = el.autoId ? "" : el.getAttribute("id") || void 0;
|
|
1428
|
-
if (!key) {
|
|
1429
|
-
key = el.getAttribute(LarkInnerKeys.DIFF_KEY) || void 0;
|
|
1430
|
-
}
|
|
1431
1430
|
if (!key) {
|
|
1432
1431
|
const larkView = el.getAttribute(LARK_VIEW);
|
|
1433
1432
|
if (larkView) {
|
|
@@ -1438,8 +1437,8 @@ function vdomGetCompareKey(node) {
|
|
|
1438
1437
|
el.cachedCompareKey = key || "";
|
|
1439
1438
|
return key;
|
|
1440
1439
|
}
|
|
1441
|
-
function
|
|
1442
|
-
const specials =
|
|
1440
|
+
function domSpecialDiff(oldNode, newNode) {
|
|
1441
|
+
const specials = DomSpecials[oldNode.nodeName];
|
|
1443
1442
|
if (!specials) return 0;
|
|
1444
1443
|
const oldEl = oldNode;
|
|
1445
1444
|
const newEl = newNode;
|
|
@@ -1452,7 +1451,7 @@ function vdomSpecialDiff(oldNode, newNode) {
|
|
|
1452
1451
|
}
|
|
1453
1452
|
return result;
|
|
1454
1453
|
}
|
|
1455
|
-
function
|
|
1454
|
+
function domSetAttributes(oldNode, newNode, ref, keepId) {
|
|
1456
1455
|
const oldEl = oldNode;
|
|
1457
1456
|
Reflect.deleteProperty(oldEl, "compareKeyCached");
|
|
1458
1457
|
const oldAttrs = oldNode.attributes;
|
|
@@ -1484,7 +1483,7 @@ function vdomSetAttributes(oldNode, newNode, ref, keepId) {
|
|
|
1484
1483
|
}
|
|
1485
1484
|
}
|
|
1486
1485
|
}
|
|
1487
|
-
function
|
|
1486
|
+
function domSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
1488
1487
|
let oldNode = oldParent.lastChild;
|
|
1489
1488
|
let newNode = newParent.firstChild;
|
|
1490
1489
|
let extra = 0;
|
|
@@ -1492,7 +1491,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1492
1491
|
const newKeyedNodes = /* @__PURE__ */ new Map();
|
|
1493
1492
|
while (oldNode) {
|
|
1494
1493
|
extra++;
|
|
1495
|
-
const nodeKey =
|
|
1494
|
+
const nodeKey = domGetCompareKey(oldNode);
|
|
1496
1495
|
if (nodeKey) {
|
|
1497
1496
|
let bucket = keyedNodes.get(nodeKey);
|
|
1498
1497
|
if (!bucket) {
|
|
@@ -1504,7 +1503,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1504
1503
|
oldNode = oldNode.previousSibling;
|
|
1505
1504
|
}
|
|
1506
1505
|
while (newNode) {
|
|
1507
|
-
const nodeKey =
|
|
1506
|
+
const nodeKey = domGetCompareKey(newNode);
|
|
1508
1507
|
if (nodeKey) {
|
|
1509
1508
|
newKeyedNodes.set(nodeKey, (newKeyedNodes.get(nodeKey) ?? 0) + 1);
|
|
1510
1509
|
}
|
|
@@ -1516,7 +1515,7 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1516
1515
|
extra--;
|
|
1517
1516
|
const tempNew = newNode;
|
|
1518
1517
|
newNode = newNode.nextSibling;
|
|
1519
|
-
const nodeKey =
|
|
1518
|
+
const nodeKey = domGetCompareKey(tempNew);
|
|
1520
1519
|
let foundNode = nodeKey ? keyedNodes.get(nodeKey) : void 0;
|
|
1521
1520
|
if (foundNode && (foundNode = foundNode.slice()) && foundNode.length) {
|
|
1522
1521
|
const matched = foundNode.pop();
|
|
@@ -1531,17 +1530,17 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1531
1530
|
const c = newKeyedNodes.get(nodeKey);
|
|
1532
1531
|
if (c) newKeyedNodes.set(nodeKey, c - 1);
|
|
1533
1532
|
}
|
|
1534
|
-
|
|
1533
|
+
domSetNode(matched, tempNew, oldParent, ref, frame, keys_);
|
|
1535
1534
|
} else if (oldNode) {
|
|
1536
1535
|
const tempOld2 = oldNode;
|
|
1537
|
-
const oldKey =
|
|
1536
|
+
const oldKey = domGetCompareKey(tempOld2);
|
|
1538
1537
|
if (oldKey && keyedNodes.has(oldKey) && newKeyedNodes.get(oldKey)) {
|
|
1539
1538
|
extra++;
|
|
1540
1539
|
ref.hasChanged = 1;
|
|
1541
1540
|
ref.domOps.push([8, oldParent, tempNew, tempOld2]);
|
|
1542
1541
|
} else {
|
|
1543
1542
|
oldNode = oldNode.nextSibling;
|
|
1544
|
-
|
|
1543
|
+
domSetNode(tempOld2, tempNew, oldParent, ref, frame, keys_);
|
|
1545
1544
|
}
|
|
1546
1545
|
} else {
|
|
1547
1546
|
ref.hasChanged = 1;
|
|
@@ -1551,29 +1550,23 @@ function vdomSetChildNodes(oldParent, newParent, ref, frame, keys_) {
|
|
|
1551
1550
|
let tempOld = oldParent.lastChild;
|
|
1552
1551
|
while (extra-- > 0) {
|
|
1553
1552
|
if (tempOld) {
|
|
1554
|
-
|
|
1553
|
+
domUnmountFrames(frame, tempOld);
|
|
1555
1554
|
ref.domOps.push([2, oldParent, tempOld]);
|
|
1556
1555
|
tempOld = tempOld.previousSibling;
|
|
1557
1556
|
ref.hasChanged = 1;
|
|
1558
1557
|
}
|
|
1559
1558
|
}
|
|
1560
1559
|
}
|
|
1561
|
-
function
|
|
1560
|
+
function domSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
|
|
1562
1561
|
const oldAsEl = oldNode instanceof Element ? oldNode : null;
|
|
1563
1562
|
const newAsEl = newNode instanceof Element ? newNode : null;
|
|
1564
|
-
const hasViewKey = !!oldAsEl?.hasAttribute(LarkInnerKeys.VIEW_KEY);
|
|
1565
1563
|
const equalAsNodes = oldAsEl !== null && newAsEl !== null && oldAsEl.isEqualNode && oldAsEl.isEqualNode(newAsEl);
|
|
1566
|
-
if (
|
|
1564
|
+
if (domSpecialDiff(oldNode, newNode) || !equalAsNodes) {
|
|
1567
1565
|
if (oldNode.nodeType === newNode.nodeType && oldNode.nodeName === newNode.nodeName) {
|
|
1568
1566
|
if (oldAsEl !== null && newAsEl !== null) {
|
|
1569
1567
|
const oldEl = oldAsEl;
|
|
1570
1568
|
const newEl = newAsEl;
|
|
1571
|
-
const staticKey = newEl.getAttribute(LarkInnerKeys.DIFF_KEY);
|
|
1572
|
-
if (staticKey && staticKey === oldEl.getAttribute(LarkInnerKeys.DIFF_KEY)) {
|
|
1573
|
-
return;
|
|
1574
|
-
}
|
|
1575
1569
|
const newLarkView = newEl.getAttribute(LARK_VIEW);
|
|
1576
|
-
const updateAttribute = !newEl.getAttribute(LarkInnerKeys.ATTR_KEY) || newEl.getAttribute(LarkInnerKeys.ATTR_KEY) !== oldEl.getAttribute(LarkInnerKeys.ATTR_KEY);
|
|
1577
1570
|
let updateChildren = true;
|
|
1578
1571
|
if (newLarkView) {
|
|
1579
1572
|
const oldFrameId = oldEl.getAttribute("id") || "";
|
|
@@ -1584,11 +1577,9 @@ function vdomSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
|
|
|
1584
1577
|
updateChildren = false;
|
|
1585
1578
|
}
|
|
1586
1579
|
}
|
|
1587
|
-
|
|
1588
|
-
vdomSetAttributes(oldEl, newEl, ref, !!newLarkView);
|
|
1589
|
-
}
|
|
1580
|
+
domSetAttributes(oldEl, newEl, ref, !!newLarkView);
|
|
1590
1581
|
if (updateChildren) {
|
|
1591
|
-
|
|
1582
|
+
domSetChildNodes(oldEl, newEl, ref, frame, keys_);
|
|
1592
1583
|
}
|
|
1593
1584
|
} else if (oldNode.nodeValue !== newNode.nodeValue) {
|
|
1594
1585
|
ref.hasChanged = 1;
|
|
@@ -1596,12 +1587,12 @@ function vdomSetNode(oldNode, newNode, oldParent, ref, frame, keys_) {
|
|
|
1596
1587
|
}
|
|
1597
1588
|
} else {
|
|
1598
1589
|
ref.hasChanged = 1;
|
|
1599
|
-
|
|
1590
|
+
domUnmountFrames(frame, oldNode);
|
|
1600
1591
|
ref.domOps.push([4, oldParent, newNode, oldNode]);
|
|
1601
1592
|
}
|
|
1602
1593
|
}
|
|
1603
1594
|
}
|
|
1604
|
-
function
|
|
1595
|
+
function createDomRef() {
|
|
1605
1596
|
return {
|
|
1606
1597
|
idUpdates: [],
|
|
1607
1598
|
views: [],
|
|
@@ -1609,7 +1600,7 @@ function createVdomRef() {
|
|
|
1609
1600
|
hasChanged: 0
|
|
1610
1601
|
};
|
|
1611
1602
|
}
|
|
1612
|
-
function
|
|
1603
|
+
function applyDomOps(ops) {
|
|
1613
1604
|
for (const op of ops) {
|
|
1614
1605
|
switch (op[0]) {
|
|
1615
1606
|
case 1:
|
|
@@ -1748,11 +1739,11 @@ var Updater = class {
|
|
|
1748
1739
|
return this;
|
|
1749
1740
|
}
|
|
1750
1741
|
/**
|
|
1751
|
-
* Detect changes and trigger
|
|
1742
|
+
* Detect changes and trigger DOM re-render.
|
|
1752
1743
|
*
|
|
1753
1744
|
* The core rendering pipeline:
|
|
1754
1745
|
* 1. Set data if provided
|
|
1755
|
-
* 2. If changed, run
|
|
1746
|
+
* 2. If changed, run DOM diff (template → new DOM → diff against old DOM)
|
|
1756
1747
|
* 3. Apply DOM operations
|
|
1757
1748
|
* 4. Apply ID updates
|
|
1758
1749
|
* 5. Call endUpdate on views that need re-rendering
|
|
@@ -1797,11 +1788,11 @@ var Updater = class {
|
|
|
1797
1788
|
updaterRef,
|
|
1798
1789
|
encodeQ
|
|
1799
1790
|
);
|
|
1800
|
-
const newDom =
|
|
1801
|
-
const ref =
|
|
1802
|
-
|
|
1791
|
+
const newDom = domGetNode(html, node);
|
|
1792
|
+
const ref = createDomRef();
|
|
1793
|
+
domSetChildNodes(node, newDom, ref, frame, keys2);
|
|
1803
1794
|
applyIdUpdates(ref.idUpdates);
|
|
1804
|
-
|
|
1795
|
+
applyDomOps(ref.domOps);
|
|
1805
1796
|
for (const v of ref.views) {
|
|
1806
1797
|
if (v.render) {
|
|
1807
1798
|
funcWithTry(v.render, [], v, noop);
|
|
@@ -2151,28 +2142,28 @@ var View = class _View {
|
|
|
2151
2142
|
// ============================================================
|
|
2152
2143
|
// Static public methods
|
|
2153
2144
|
// ============================================================
|
|
2154
|
-
/** Collected
|
|
2155
|
-
static
|
|
2145
|
+
/** Collected makes from mixins */
|
|
2146
|
+
static makes;
|
|
2156
2147
|
/**
|
|
2157
2148
|
* Prepare a View subclass by scanning its prototype for event method patterns.
|
|
2158
2149
|
* Pattern: `$?name<eventType1,eventType2>(&modifiers)`
|
|
2159
2150
|
*
|
|
2160
|
-
* Only runs once per View subclass (guarded by
|
|
2151
|
+
* Only runs once per View subclass (guarded by makes marker).
|
|
2161
2152
|
* Called from Frame.mountView before creating the view instance.
|
|
2162
2153
|
*/
|
|
2163
2154
|
static prepare(oView) {
|
|
2164
|
-
if (oView.
|
|
2165
|
-
return oView.
|
|
2155
|
+
if (oView.makes) {
|
|
2156
|
+
return oView.makes;
|
|
2166
2157
|
}
|
|
2167
|
-
const
|
|
2168
|
-
oView.
|
|
2158
|
+
const makes = [];
|
|
2159
|
+
oView.makes = makes;
|
|
2169
2160
|
const proto = oView.prototype;
|
|
2170
2161
|
const eventsObject = {};
|
|
2171
2162
|
const eventsList = [];
|
|
2172
2163
|
const selectorObject = {};
|
|
2173
2164
|
const mixins = proto["mixins"];
|
|
2174
2165
|
if (mixins && Array.isArray(mixins)) {
|
|
2175
|
-
_View.mergeMixins(mixins, oView,
|
|
2166
|
+
_View.mergeMixins(mixins, oView, makes);
|
|
2176
2167
|
}
|
|
2177
2168
|
for (const p in proto) {
|
|
2178
2169
|
if (!hasOwnProperty(proto, p)) continue;
|
|
@@ -2242,7 +2233,7 @@ var View = class _View {
|
|
|
2242
2233
|
proto["$globalEvtList"] = eventsList;
|
|
2243
2234
|
proto["$selMap"] = selectorObject;
|
|
2244
2235
|
proto["$assignFn"] = proto["assign"];
|
|
2245
|
-
return
|
|
2236
|
+
return makes;
|
|
2246
2237
|
}
|
|
2247
2238
|
/**
|
|
2248
2239
|
* Bind or unbind event delegation for a view instance.
|
|
@@ -2367,7 +2358,7 @@ var View = class _View {
|
|
|
2367
2358
|
/**
|
|
2368
2359
|
* Merge an array of mixin objects into the view prototype.
|
|
2369
2360
|
*/
|
|
2370
|
-
static mergeMixins(mixins, viewClass,
|
|
2361
|
+
static mergeMixins(mixins, viewClass, makes) {
|
|
2371
2362
|
const proto = viewClass.prototype;
|
|
2372
2363
|
const temp = {};
|
|
2373
2364
|
for (const node of mixins) {
|
|
@@ -2378,7 +2369,7 @@ var View = class _View {
|
|
|
2378
2369
|
const mixinFn = fn;
|
|
2379
2370
|
const exist = temp[p];
|
|
2380
2371
|
if (p === "make") {
|
|
2381
|
-
|
|
2372
|
+
makes.push(mixinFn);
|
|
2382
2373
|
continue;
|
|
2383
2374
|
}
|
|
2384
2375
|
if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
|
|
@@ -2429,9 +2420,9 @@ var View = class _View {
|
|
|
2429
2420
|
static extend(props, statics) {
|
|
2430
2421
|
const definedProps = props ?? {};
|
|
2431
2422
|
const make = definedProps["make"];
|
|
2432
|
-
const
|
|
2423
|
+
const makes = [];
|
|
2433
2424
|
if (typeof make === "function") {
|
|
2434
|
-
|
|
2425
|
+
makes.push(make);
|
|
2435
2426
|
}
|
|
2436
2427
|
const ParentView = this;
|
|
2437
2428
|
const ChildView = class extends ParentView {
|
|
@@ -2453,7 +2444,7 @@ var View = class _View {
|
|
|
2453
2444
|
deep: !this.template
|
|
2454
2445
|
}
|
|
2455
2446
|
];
|
|
2456
|
-
const concatCtors =
|
|
2447
|
+
const concatCtors = makes.concat(mixinCtors || []);
|
|
2457
2448
|
if (concatCtors.length) {
|
|
2458
2449
|
funcWithTry(concatCtors, params, this, noop);
|
|
2459
2450
|
}
|
|
@@ -2479,7 +2470,7 @@ var View = class _View {
|
|
|
2479
2470
|
* Merge mixins into View prototype.
|
|
2480
2471
|
*/
|
|
2481
2472
|
static merge(...mixins) {
|
|
2482
|
-
const existingCtors = this.
|
|
2473
|
+
const existingCtors = this.makes || [];
|
|
2483
2474
|
_View.mergeMixins(mixins, this, existingCtors);
|
|
2484
2475
|
return this;
|
|
2485
2476
|
}
|
|
@@ -3223,13 +3214,13 @@ var Service = class {
|
|
|
3223
3214
|
* References per-type static state from the current class.
|
|
3224
3215
|
*/
|
|
3225
3216
|
get internals() {
|
|
3226
|
-
const
|
|
3217
|
+
const constructor = this.constructor;
|
|
3227
3218
|
return {
|
|
3228
|
-
metaList:
|
|
3229
|
-
payloadCache:
|
|
3230
|
-
pendingCacheKeys:
|
|
3231
|
-
syncFn:
|
|
3232
|
-
staticEmitter:
|
|
3219
|
+
metaList: constructor._metaList,
|
|
3220
|
+
payloadCache: constructor._payloadCache,
|
|
3221
|
+
pendingCacheKeys: constructor._pendingCacheKeys,
|
|
3222
|
+
syncFn: constructor._syncFn,
|
|
3223
|
+
staticEmitter: constructor._staticEmitter
|
|
3233
3224
|
};
|
|
3234
3225
|
}
|
|
3235
3226
|
/**
|
|
@@ -4224,755 +4215,6 @@ function bindStore(view, store, selector) {
|
|
|
4224
4215
|
return off;
|
|
4225
4216
|
}
|
|
4226
4217
|
var defineStore = create;
|
|
4227
|
-
|
|
4228
|
-
// src/compiler.ts
|
|
4229
|
-
import { parse as babelParse } from "@babel/parser";
|
|
4230
|
-
var SPLITTER2 = String.fromCharCode(30);
|
|
4231
|
-
var VIEW_ID_PLACEHOLDER = String.fromCharCode(31);
|
|
4232
|
-
function jsObjectToUrlParams(paramsStr) {
|
|
4233
|
-
const trimmed = paramsStr.trim();
|
|
4234
|
-
if (!/^[{[]/.test(trimmed) && /=/.test(trimmed)) {
|
|
4235
|
-
return trimmed;
|
|
4236
|
-
}
|
|
4237
|
-
const objMatch = trimmed.match(/^\{(.*)\}$/s);
|
|
4238
|
-
if (objMatch) {
|
|
4239
|
-
const inner = objMatch[1];
|
|
4240
|
-
const pairs = [];
|
|
4241
|
-
const pairRegExp = /(\w+)\s*:\s*(?:'([^']*)'|"([^"]*)"|([^,}]+))/g;
|
|
4242
|
-
let m;
|
|
4243
|
-
while ((m = pairRegExp.exec(inner)) !== null) {
|
|
4244
|
-
const key = m[1];
|
|
4245
|
-
const value = m[2] ?? m[3] ?? m[4]?.trim() ?? "";
|
|
4246
|
-
pairs.push(`${key}=${value}`);
|
|
4247
|
-
}
|
|
4248
|
-
return pairs.join("&");
|
|
4249
|
-
}
|
|
4250
|
-
return trimmed;
|
|
4251
|
-
}
|
|
4252
|
-
function protectComments(source) {
|
|
4253
|
-
const comments = [];
|
|
4254
|
-
const protectedSource = source.replace(/<!--[\s\S]*?-->/g, (match) => {
|
|
4255
|
-
comments.push(match);
|
|
4256
|
-
return `__lark_comment_${comments.length - 1}__`;
|
|
4257
|
-
});
|
|
4258
|
-
return { protectedSource, comments };
|
|
4259
|
-
}
|
|
4260
|
-
function restoreComments(source, comments) {
|
|
4261
|
-
return source.replace(/__lark_comment_(\d+)__/g, (_, index) => {
|
|
4262
|
-
return comments[parseInt(index, 10)];
|
|
4263
|
-
});
|
|
4264
|
-
}
|
|
4265
|
-
function processViewEvents(source) {
|
|
4266
|
-
return source.replace(
|
|
4267
|
-
/@(\w+)="([^"]+)"/g,
|
|
4268
|
-
(fullAttr, eventName, attrValue) => {
|
|
4269
|
-
const eventMatch = attrValue.match(/^(\w+)\((.*)\)$/s);
|
|
4270
|
-
if (!eventMatch) return fullAttr;
|
|
4271
|
-
const handlerName = eventMatch[1];
|
|
4272
|
-
const paramsStr = eventMatch[2].trim();
|
|
4273
|
-
if (!paramsStr) {
|
|
4274
|
-
return `@${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}()"`;
|
|
4275
|
-
}
|
|
4276
|
-
const urlParams = jsObjectToUrlParams(paramsStr);
|
|
4277
|
-
return `@${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}(${urlParams})"`;
|
|
4278
|
-
}
|
|
4279
|
-
);
|
|
4280
|
-
}
|
|
4281
|
-
function addLineMarkers(source) {
|
|
4282
|
-
const lines = source.split(/\r\n?|\n/);
|
|
4283
|
-
const result = [];
|
|
4284
|
-
let lineNo = 0;
|
|
4285
|
-
const openTag = "{{";
|
|
4286
|
-
for (const line of lines) {
|
|
4287
|
-
const parts = line.split(openTag);
|
|
4288
|
-
if (parts.length > 1) {
|
|
4289
|
-
const reconstructed = parts.map((part, i) => {
|
|
4290
|
-
if (i === 0) return part;
|
|
4291
|
-
return openTag + SPLITTER2 + ++lineNo + part;
|
|
4292
|
-
}).join("");
|
|
4293
|
-
result.push(reconstructed);
|
|
4294
|
-
} else {
|
|
4295
|
-
result.push(line);
|
|
4296
|
-
}
|
|
4297
|
-
}
|
|
4298
|
-
return result.join("\n");
|
|
4299
|
-
}
|
|
4300
|
-
function extractArtInfo(art) {
|
|
4301
|
-
const m = art.match(new RegExp(`^${SPLITTER2}(\\d+)([\\s\\S]+)`));
|
|
4302
|
-
if (m) {
|
|
4303
|
-
let code = m[2].trimStart();
|
|
4304
|
-
if (code.startsWith("if(")) {
|
|
4305
|
-
code = code.substring(0, 2) + " " + code.substring(2);
|
|
4306
|
-
} else if (code.startsWith("for(")) {
|
|
4307
|
-
code = code.substring(0, 3) + " " + code.substring(3);
|
|
4308
|
-
}
|
|
4309
|
-
return { line: parseInt(m[1], 10), art: code };
|
|
4310
|
-
}
|
|
4311
|
-
return null;
|
|
4312
|
-
}
|
|
4313
|
-
function convertArtSyntax(source, debug) {
|
|
4314
|
-
const markedSource = debug ? addLineMarkers(source) : source;
|
|
4315
|
-
const openTag = "{{";
|
|
4316
|
-
const parts = markedSource.split(openTag);
|
|
4317
|
-
const result = [parts[0]];
|
|
4318
|
-
const blockStack = [];
|
|
4319
|
-
for (let i = 1; i < parts.length; i++) {
|
|
4320
|
-
const part = parts[i];
|
|
4321
|
-
const closeIdx = findCloseBrace(part);
|
|
4322
|
-
if (closeIdx === -1) {
|
|
4323
|
-
result.push(openTag + part);
|
|
4324
|
-
continue;
|
|
4325
|
-
}
|
|
4326
|
-
const code = part.substring(0, closeIdx);
|
|
4327
|
-
const rest = part.substring(closeIdx + 2);
|
|
4328
|
-
let lineNo = -1;
|
|
4329
|
-
let cleanCode = code;
|
|
4330
|
-
if (debug) {
|
|
4331
|
-
const info = extractArtInfo(code);
|
|
4332
|
-
if (info) {
|
|
4333
|
-
lineNo = info.line;
|
|
4334
|
-
cleanCode = info.art;
|
|
4335
|
-
}
|
|
4336
|
-
} else {
|
|
4337
|
-
cleanCode = code.trim();
|
|
4338
|
-
}
|
|
4339
|
-
const converted = convertArtExpression(
|
|
4340
|
-
cleanCode,
|
|
4341
|
-
debug,
|
|
4342
|
-
lineNo,
|
|
4343
|
-
blockStack
|
|
4344
|
-
);
|
|
4345
|
-
result.push(converted);
|
|
4346
|
-
result.push(rest);
|
|
4347
|
-
}
|
|
4348
|
-
if (blockStack.length > 0) {
|
|
4349
|
-
const unclosed = blockStack.map((b) => `"${b.ctrl}" at line ${b.line}`).join(", ");
|
|
4350
|
-
throw new Error(`[@lark.js/mvc error] unclosed block(s): ${unclosed}`);
|
|
4351
|
-
}
|
|
4352
|
-
return result.join("");
|
|
4353
|
-
}
|
|
4354
|
-
function findCloseBrace(str) {
|
|
4355
|
-
let leftCount = 0;
|
|
4356
|
-
let rightCount = 0;
|
|
4357
|
-
let maybeCount = 0;
|
|
4358
|
-
let maybeAt = -1;
|
|
4359
|
-
for (let i = 0; i < str.length; i++) {
|
|
4360
|
-
const c = str.charAt(i);
|
|
4361
|
-
if (c !== "}") {
|
|
4362
|
-
if (maybeCount >= 2 && maybeAt === -1) {
|
|
4363
|
-
maybeAt = i;
|
|
4364
|
-
}
|
|
4365
|
-
maybeCount = 0;
|
|
4366
|
-
rightCount = 0;
|
|
4367
|
-
}
|
|
4368
|
-
if (c === "{") {
|
|
4369
|
-
leftCount++;
|
|
4370
|
-
} else if (c === "}") {
|
|
4371
|
-
maybeCount++;
|
|
4372
|
-
if (!leftCount) {
|
|
4373
|
-
rightCount++;
|
|
4374
|
-
if (rightCount === 2) {
|
|
4375
|
-
return i - 1;
|
|
4376
|
-
}
|
|
4377
|
-
} else {
|
|
4378
|
-
leftCount--;
|
|
4379
|
-
}
|
|
4380
|
-
}
|
|
4381
|
-
}
|
|
4382
|
-
if (!leftCount && maybeCount >= 2 && maybeAt === -1) {
|
|
4383
|
-
maybeAt = str.length - 2;
|
|
4384
|
-
}
|
|
4385
|
-
if (maybeAt > -1) {
|
|
4386
|
-
return maybeAt - 2;
|
|
4387
|
-
}
|
|
4388
|
-
return -1;
|
|
4389
|
-
}
|
|
4390
|
-
function trimOuterParens(expr) {
|
|
4391
|
-
expr = expr.trim();
|
|
4392
|
-
while (expr.startsWith("(") && expr.endsWith(")")) {
|
|
4393
|
-
let depth = 0;
|
|
4394
|
-
let matched = true;
|
|
4395
|
-
for (let i = 0; i < expr.length - 1; i++) {
|
|
4396
|
-
const c = expr.charAt(i);
|
|
4397
|
-
if (c === "(") depth++;
|
|
4398
|
-
else if (c === ")") depth--;
|
|
4399
|
-
if (depth === 0 && i < expr.length - 1) {
|
|
4400
|
-
matched = false;
|
|
4401
|
-
break;
|
|
4402
|
-
}
|
|
4403
|
-
}
|
|
4404
|
-
if (!matched) break;
|
|
4405
|
-
expr = expr.substring(1, expr.length - 1).trim();
|
|
4406
|
-
}
|
|
4407
|
-
return expr;
|
|
4408
|
-
}
|
|
4409
|
-
function convertArtExpression(code, debug, lineNo, blockStack = []) {
|
|
4410
|
-
code = code.trim();
|
|
4411
|
-
const debugPrefix = debug && lineNo > -1 ? `<%'${lineNo}${code.replace(/\\|'/g, "\\$&").replace(/\r\n?|\n/g, "\\n")}'%>` : "";
|
|
4412
|
-
const ifForMatch = code.match(/^\s*(if|for)\s*\(/);
|
|
4413
|
-
if (ifForMatch) {
|
|
4414
|
-
const keyword2 = ifForMatch[1];
|
|
4415
|
-
const expr = code.substring(ifForMatch[0].length);
|
|
4416
|
-
if (keyword2 === "if") {
|
|
4417
|
-
blockStack.push({ ctrl: "if", line: lineNo });
|
|
4418
|
-
const rawExpr = expr.replace(/\)\s*$/, "");
|
|
4419
|
-
const cleanExpr = trimOuterParens(rawExpr);
|
|
4420
|
-
return `${debugPrefix}<%if(${cleanExpr}){%>`;
|
|
4421
|
-
}
|
|
4422
|
-
blockStack.push({ ctrl: "for", line: lineNo });
|
|
4423
|
-
const forExpr = expr.replace(/\)\s*$/, "");
|
|
4424
|
-
return `${debugPrefix}<%for(${forExpr}){%>`;
|
|
4425
|
-
}
|
|
4426
|
-
const tokens = code.split(/\s+/);
|
|
4427
|
-
const keyword = tokens.shift() ?? "";
|
|
4428
|
-
switch (keyword) {
|
|
4429
|
-
case "if": {
|
|
4430
|
-
blockStack.push({ ctrl: "if", line: lineNo });
|
|
4431
|
-
const rawExpr = tokens.join(" ").trim();
|
|
4432
|
-
const expr = trimOuterParens(rawExpr);
|
|
4433
|
-
return `${debugPrefix}<%if(${expr}){%>`;
|
|
4434
|
-
}
|
|
4435
|
-
case "else": {
|
|
4436
|
-
if (tokens[0] === "if") {
|
|
4437
|
-
tokens.shift();
|
|
4438
|
-
const rawExpr = tokens.join(" ").trim();
|
|
4439
|
-
const expr = trimOuterParens(rawExpr);
|
|
4440
|
-
return `${debugPrefix}<%}else if(${expr}){%>`;
|
|
4441
|
-
}
|
|
4442
|
-
return `${debugPrefix}<%}else{%>`;
|
|
4443
|
-
}
|
|
4444
|
-
case "forOf": {
|
|
4445
|
-
blockStack.push({ ctrl: "forOf", line: lineNo });
|
|
4446
|
-
const object = tokens[0];
|
|
4447
|
-
if (tokens.length > 1 && tokens[1] !== "as") {
|
|
4448
|
-
throw new Error(
|
|
4449
|
-
`[@lark.js/mvc error] bad forOf syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{forOf list as item [index]}}`
|
|
4450
|
-
);
|
|
4451
|
-
}
|
|
4452
|
-
const restTokens = tokens.slice(2);
|
|
4453
|
-
const asValue = restTokens.join(" ");
|
|
4454
|
-
const asExpr = parseAsExpr(asValue);
|
|
4455
|
-
const index = asExpr.key || "_i";
|
|
4456
|
-
const refObj = /[.[\]]/.test(object) ? `_art_obj_${object.replace(/[^\w]/g, "_")}` : object;
|
|
4457
|
-
const refExpr = /[.[\]]/.test(object) ? `,${refObj}=${object}` : "";
|
|
4458
|
-
const refObjCount = "_l";
|
|
4459
|
-
const valueDecl = asExpr.vars ? `let ${asExpr.vars}=${refObj}[${index}]` : "";
|
|
4460
|
-
let firstAndLast = "";
|
|
4461
|
-
let lastCount = "";
|
|
4462
|
-
if (asExpr.first) {
|
|
4463
|
-
firstAndLast += `let ${asExpr.first}=${index}===0;`;
|
|
4464
|
-
}
|
|
4465
|
-
if (asExpr.last) {
|
|
4466
|
-
lastCount = `,_lc=${refObjCount}-1`;
|
|
4467
|
-
firstAndLast += `let ${asExpr.last}=${index}===_lc;`;
|
|
4468
|
-
}
|
|
4469
|
-
return `${debugPrefix}<%for(let ${index}=0${refExpr},${refObjCount}=${refObj}.length${lastCount};${index}<${refObjCount};${index}++){${firstAndLast}${valueDecl}%>`;
|
|
4470
|
-
}
|
|
4471
|
-
case "forIn": {
|
|
4472
|
-
blockStack.push({ ctrl: "forIn", line: lineNo });
|
|
4473
|
-
const object = tokens[0];
|
|
4474
|
-
if (tokens.length > 1 && tokens[1] !== "as") {
|
|
4475
|
-
throw new Error(
|
|
4476
|
-
`[@lark.js/mvc error] bad forIn syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{for-in obj as val [key]}}`
|
|
4477
|
-
);
|
|
4478
|
-
}
|
|
4479
|
-
const restTokens2 = tokens.slice(2);
|
|
4480
|
-
const asValue2 = restTokens2.join(" ");
|
|
4481
|
-
const asExpr2 = parseAsExpr(asValue2);
|
|
4482
|
-
const key1 = asExpr2.key || "_k";
|
|
4483
|
-
const refObj2 = /[.[\]]/.test(object) ? `_art_obj_${object.replace(/[^\w]/g, "_")}` : object;
|
|
4484
|
-
const refExpr2 = /[.[\]]/.test(object) ? `let ${refObj2}=${object};` : "";
|
|
4485
|
-
const valueDecl2 = asExpr2.vars ? `let ${asExpr2.vars}=${refObj2}[${key1}]` : "";
|
|
4486
|
-
return `${debugPrefix}<%${refExpr2}for(let ${key1} in ${refObj2}){${valueDecl2}%>`;
|
|
4487
|
-
}
|
|
4488
|
-
case "for": {
|
|
4489
|
-
blockStack.push({ ctrl: "for", line: lineNo });
|
|
4490
|
-
const expr = tokens.join(" ").trim();
|
|
4491
|
-
return `${debugPrefix}<%for(${expr}){%>`;
|
|
4492
|
-
}
|
|
4493
|
-
case "set":
|
|
4494
|
-
return `${debugPrefix}<%let ${tokens.join(" ")};%>`;
|
|
4495
|
-
case "/if":
|
|
4496
|
-
case "/forOf":
|
|
4497
|
-
case "/forIn":
|
|
4498
|
-
case "/for": {
|
|
4499
|
-
const expectedCtrl = keyword.substring(1);
|
|
4500
|
-
const last = blockStack.pop();
|
|
4501
|
-
if (!last) {
|
|
4502
|
-
throw new Error(
|
|
4503
|
-
`[@lark.js/mvc error] unexpected {{${code}}}: no matching open block`
|
|
4504
|
-
);
|
|
4505
|
-
}
|
|
4506
|
-
if (last.ctrl !== expectedCtrl) {
|
|
4507
|
-
throw new Error(
|
|
4508
|
-
`[@lark.js/mvc error] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
|
|
4509
|
-
);
|
|
4510
|
-
}
|
|
4511
|
-
return `${debugPrefix}<%}%>`;
|
|
4512
|
-
}
|
|
4513
|
-
default:
|
|
4514
|
-
return `${debugPrefix}<%${code}%>`;
|
|
4515
|
-
}
|
|
4516
|
-
}
|
|
4517
|
-
function parseAsExpr(expr) {
|
|
4518
|
-
expr = expr.trim();
|
|
4519
|
-
if (!expr) {
|
|
4520
|
-
return { vars: "", key: "", last: "", first: "", bad: false };
|
|
4521
|
-
}
|
|
4522
|
-
if (expr.startsWith("{") || expr.startsWith("[")) {
|
|
4523
|
-
const stack = [];
|
|
4524
|
-
let vars = "";
|
|
4525
|
-
let key = "";
|
|
4526
|
-
let last = "";
|
|
4527
|
-
let first = "";
|
|
4528
|
-
let pos = 0;
|
|
4529
|
-
let bad = false;
|
|
4530
|
-
for (const c of expr) {
|
|
4531
|
-
if (pos === 0) vars += c;
|
|
4532
|
-
else if (pos === 1) key += c;
|
|
4533
|
-
else if (pos === 2) last += c;
|
|
4534
|
-
else if (pos === 3) first += c;
|
|
4535
|
-
if (c === "{" || c === "[") stack.push(c);
|
|
4536
|
-
else if (c === "}") {
|
|
4537
|
-
if (stack[stack.length - 1] === "{") stack.pop();
|
|
4538
|
-
else {
|
|
4539
|
-
bad = true;
|
|
4540
|
-
break;
|
|
4541
|
-
}
|
|
4542
|
-
} else if (c === "]") {
|
|
4543
|
-
if (stack[stack.length - 1] === "[") stack.pop();
|
|
4544
|
-
else {
|
|
4545
|
-
bad = true;
|
|
4546
|
-
break;
|
|
4547
|
-
}
|
|
4548
|
-
} else if (c === " " && !stack.length) {
|
|
4549
|
-
pos++;
|
|
4550
|
-
}
|
|
4551
|
-
}
|
|
4552
|
-
return {
|
|
4553
|
-
vars: vars.trim(),
|
|
4554
|
-
key: key.trim(),
|
|
4555
|
-
last: last.trim(),
|
|
4556
|
-
first: first.trim(),
|
|
4557
|
-
bad: bad || stack.length > 0
|
|
4558
|
-
};
|
|
4559
|
-
}
|
|
4560
|
-
const parts = expr.split(/\s+/);
|
|
4561
|
-
return {
|
|
4562
|
-
vars: parts[0] || "",
|
|
4563
|
-
key: parts[1] || "",
|
|
4564
|
-
last: parts[2] || "",
|
|
4565
|
-
first: parts[3] || "",
|
|
4566
|
-
bad: false
|
|
4567
|
-
};
|
|
4568
|
-
}
|
|
4569
|
-
function compileToFunction(source, debug, file) {
|
|
4570
|
-
const matcher = /<%([@=!:])?([\s\S]*?)%>|$/g;
|
|
4571
|
-
let index = 0;
|
|
4572
|
-
let funcSource = `$out+='`;
|
|
4573
|
-
let hasAtRule = false;
|
|
4574
|
-
const escapeSlashRegExp = /\\|'/g;
|
|
4575
|
-
const escapeBreakReturnRegExp = /\r|\n/g;
|
|
4576
|
-
source.replace(matcher, (match, operate, content, offset) => {
|
|
4577
|
-
funcSource += source.substring(index, offset).replace(escapeSlashRegExp, "\\$&").replace(escapeBreakReturnRegExp, "\\n");
|
|
4578
|
-
index = offset + match.length;
|
|
4579
|
-
if (debug) {
|
|
4580
|
-
let expr = source.substring(
|
|
4581
|
-
index - match.length + 2 + (operate ? 1 : 0),
|
|
4582
|
-
index - 2
|
|
4583
|
-
);
|
|
4584
|
-
const x11 = String.fromCharCode(17);
|
|
4585
|
-
const artRegExp = new RegExp(`^'(\\d+)${x11}([^${x11}]+)${x11}'$`);
|
|
4586
|
-
const artM = expr.match(artRegExp);
|
|
4587
|
-
let art = "";
|
|
4588
|
-
let line = -1;
|
|
4589
|
-
if (artM) {
|
|
4590
|
-
expr = expr.replace(artRegExp, "");
|
|
4591
|
-
art = artM[2];
|
|
4592
|
-
line = parseInt(artM[1], 10);
|
|
4593
|
-
} else {
|
|
4594
|
-
expr = expr.replace(escapeSlashRegExp, "\\$&").replace(escapeBreakReturnRegExp, "\\n");
|
|
4595
|
-
}
|
|
4596
|
-
if (operate === "@") {
|
|
4597
|
-
hasAtRule = true;
|
|
4598
|
-
funcSource += `'+($dbgExpr='<%${operate + expr}%>',$refFn($refAlt,${content}))+'`;
|
|
4599
|
-
} else if (operate === "=" || operate === ":") {
|
|
4600
|
-
funcSource += `'+($dbgExpr='<%${operate + expr}%>',$encHtml(${content}))+'`;
|
|
4601
|
-
} else if (operate === "!") {
|
|
4602
|
-
if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
|
|
4603
|
-
content = `$strSafe(${content})`;
|
|
4604
|
-
}
|
|
4605
|
-
funcSource += `'+($dbgExpr='<%${operate + expr}%>',${content})+'`;
|
|
4606
|
-
} else if (content) {
|
|
4607
|
-
if (line > -1) {
|
|
4608
|
-
funcSource += `';$dbgLine=${line};$dbgArt='${art}';`;
|
|
4609
|
-
content = "";
|
|
4610
|
-
} else {
|
|
4611
|
-
funcSource += `';`;
|
|
4612
|
-
}
|
|
4613
|
-
if (funcSource.endsWith(`+'';`)) {
|
|
4614
|
-
funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
|
|
4615
|
-
}
|
|
4616
|
-
if (expr) {
|
|
4617
|
-
funcSource += `$dbgExpr='<%${expr}%>';`;
|
|
4618
|
-
}
|
|
4619
|
-
funcSource += content + `;$out+='`;
|
|
4620
|
-
}
|
|
4621
|
-
} else {
|
|
4622
|
-
if (operate === "@") {
|
|
4623
|
-
hasAtRule = true;
|
|
4624
|
-
funcSource += `'+$refFn($refAlt,${content})+'`;
|
|
4625
|
-
} else if (operate === "=" || operate === ":") {
|
|
4626
|
-
funcSource += `'+$encHtml(${content})+'`;
|
|
4627
|
-
} else if (operate === "!") {
|
|
4628
|
-
if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
|
|
4629
|
-
content = `$strSafe(${content})`;
|
|
4630
|
-
}
|
|
4631
|
-
funcSource += `'+${content}+'`;
|
|
4632
|
-
} else if (content) {
|
|
4633
|
-
funcSource += `';`;
|
|
4634
|
-
if (funcSource.endsWith(`+'';`)) {
|
|
4635
|
-
funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
|
|
4636
|
-
}
|
|
4637
|
-
funcSource += `${content};$out+='`;
|
|
4638
|
-
}
|
|
4639
|
-
}
|
|
4640
|
-
return match;
|
|
4641
|
-
});
|
|
4642
|
-
funcSource += `';`;
|
|
4643
|
-
funcSource = funcSource.replace(/\$out\+='';/g, "");
|
|
4644
|
-
funcSource = funcSource.replace(/\$out\+=''\+/g, "$out+=");
|
|
4645
|
-
if (debug) {
|
|
4646
|
-
const filePart = file ? `\\r\\n\\tat file:${file}` : "";
|
|
4647
|
-
funcSource = `let $dbgExpr,$dbgArt,$dbgLine;try{${funcSource}}catch(ex){let msg='render view error:'+(ex.message||ex);if($dbgArt)msg+='\\r\\n\\tsrc art:{{'+$dbgArt+'}}\\r\\n\\tat line:'+$dbgLine;msg+='\\r\\n\\t'+($dbgArt?'translate to:':'expr:');msg+=$dbgExpr+'${filePart}';throw msg;}`;
|
|
4648
|
-
}
|
|
4649
|
-
const viewIdRegExp = new RegExp(String.fromCharCode(31), "g");
|
|
4650
|
-
funcSource = funcSource.replace(viewIdRegExp, `'+$viewId+'`);
|
|
4651
|
-
void hasAtRule;
|
|
4652
|
-
const refFallback = "if(!$refAlt)$refAlt=$data;";
|
|
4653
|
-
const fullSource = `${refFallback}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
|
|
4654
|
-
return `($data,$viewId,$refAlt,$encHtml,$strSafe,$encUri,$refFn,$encQuote)=>{${fullSource}}`;
|
|
4655
|
-
}
|
|
4656
|
-
function compileTemplate(source, options = {}) {
|
|
4657
|
-
const { debug = false, globalVars = [], file } = options;
|
|
4658
|
-
const { protectedSource, comments } = protectComments(source);
|
|
4659
|
-
const converted = convertArtSyntax(protectedSource, debug);
|
|
4660
|
-
const viewEventProcessed = processViewEvents(converted);
|
|
4661
|
-
const finalSource = restoreComments(viewEventProcessed, comments);
|
|
4662
|
-
const funcBody = compileToFunction(finalSource, debug, file);
|
|
4663
|
-
const varDeclarations = globalVars.map((key) => `,${key}=$data.${key}`).join("");
|
|
4664
|
-
const funcWithVars = funcBody.replace("{{VARS}}", () => varDeclarations);
|
|
4665
|
-
return `import { encHtml as __larkEncHtml, strSafe as __larkStrSafe, encUri as __larkEncUri, encQuote as __larkEncQuote, refFn as __larkRefFn } from "@lark.js/mvc/runtime";
|
|
4666
|
-
export default function(data, viewId, refData) {
|
|
4667
|
-
let $data = data || {},
|
|
4668
|
-
$viewId = viewId || '';
|
|
4669
|
-
return (${funcWithVars})($data, $viewId, refData,
|
|
4670
|
-
__larkEncHtml, __larkStrSafe, __larkEncUri, __larkRefFn, __larkEncQuote
|
|
4671
|
-
);
|
|
4672
|
-
}`;
|
|
4673
|
-
}
|
|
4674
|
-
function extractGlobalVars(source) {
|
|
4675
|
-
const { protectedSource, comments: _comments } = protectComments(source);
|
|
4676
|
-
const viewEventProcessed = processViewEvents(protectedSource);
|
|
4677
|
-
const converted = convertArtSyntax(viewEventProcessed, false);
|
|
4678
|
-
const template = restoreComments(converted, _comments);
|
|
4679
|
-
const templateCmdRegExp = /<%([@=!:])?([\s\S]*?)%>|$/g;
|
|
4680
|
-
const fnParts = [];
|
|
4681
|
-
const htmlStore = {};
|
|
4682
|
-
let htmlIndex = 0;
|
|
4683
|
-
let lastIndex = 0;
|
|
4684
|
-
const htmlKey = String.fromCharCode(5);
|
|
4685
|
-
template.replace(
|
|
4686
|
-
templateCmdRegExp,
|
|
4687
|
-
(match, operate, content, offset) => {
|
|
4688
|
-
const start = operate ? 3 : 2;
|
|
4689
|
-
const htmlText = template.substring(lastIndex, offset + start);
|
|
4690
|
-
const key = htmlKey + htmlIndex++ + htmlKey;
|
|
4691
|
-
htmlStore[key] = htmlText;
|
|
4692
|
-
lastIndex = offset + match.length - 2;
|
|
4693
|
-
if (operate && content.trim()) {
|
|
4694
|
-
fnParts.push(';"' + key + '";', "[" + content + "]");
|
|
4695
|
-
} else {
|
|
4696
|
-
fnParts.push(';"' + key + '";', content || "");
|
|
4697
|
-
}
|
|
4698
|
-
return match;
|
|
4699
|
-
}
|
|
4700
|
-
);
|
|
4701
|
-
let fn = fnParts.join("");
|
|
4702
|
-
fn = `(function(){${fn}})`;
|
|
4703
|
-
let ast;
|
|
4704
|
-
try {
|
|
4705
|
-
ast = babelParse(fn, {
|
|
4706
|
-
sourceType: "script",
|
|
4707
|
-
allowReturnOutsideFunction: true,
|
|
4708
|
-
allowAwaitOutsideFunction: true
|
|
4709
|
-
});
|
|
4710
|
-
} catch {
|
|
4711
|
-
return fallbackExtractVariables(source);
|
|
4712
|
-
}
|
|
4713
|
-
const globalExists = { ...BUILTIN_GLOBALS };
|
|
4714
|
-
const globalVars = /* @__PURE__ */ Object.create(null);
|
|
4715
|
-
const fnRange = [];
|
|
4716
|
-
walkAst(ast, {
|
|
4717
|
-
VariableDeclarator(node) {
|
|
4718
|
-
if (node.id.type === "Identifier") {
|
|
4719
|
-
const name = node.id.name;
|
|
4720
|
-
globalExists[name] = node.init ? 3 : 2;
|
|
4721
|
-
}
|
|
4722
|
-
},
|
|
4723
|
-
FunctionDeclaration(node) {
|
|
4724
|
-
if (node.id) {
|
|
4725
|
-
globalExists[node.id.name] = 3;
|
|
4726
|
-
}
|
|
4727
|
-
fnRange.push(node);
|
|
4728
|
-
},
|
|
4729
|
-
FunctionExpression(node) {
|
|
4730
|
-
fnRange.push(node);
|
|
4731
|
-
},
|
|
4732
|
-
ArrowFunctionExpression(node) {
|
|
4733
|
-
fnRange.push(node);
|
|
4734
|
-
},
|
|
4735
|
-
CallExpression(node) {
|
|
4736
|
-
if (node.callee.type === "Identifier") {
|
|
4737
|
-
globalExists[node.callee.name] = 1;
|
|
4738
|
-
}
|
|
4739
|
-
}
|
|
4740
|
-
});
|
|
4741
|
-
const functionParams = /* @__PURE__ */ Object.create(null);
|
|
4742
|
-
for (const fnNode of fnRange) {
|
|
4743
|
-
const params = "params" in fnNode ? fnNode.params : [];
|
|
4744
|
-
for (const p of params) {
|
|
4745
|
-
if (p.type === "Identifier") {
|
|
4746
|
-
functionParams[p.name] = 1;
|
|
4747
|
-
} else if (p.type === "AssignmentPattern" && p.left.type === "Identifier") {
|
|
4748
|
-
functionParams[p.left.name] = 1;
|
|
4749
|
-
} else if (p.type === "RestElement" && p.argument.type === "Identifier") {
|
|
4750
|
-
functionParams[p.argument.name] = 1;
|
|
4751
|
-
}
|
|
4752
|
-
}
|
|
4753
|
-
}
|
|
4754
|
-
walkAst(ast, {
|
|
4755
|
-
Identifier(node) {
|
|
4756
|
-
const name = node.name;
|
|
4757
|
-
if (globalExists[name]) return;
|
|
4758
|
-
if (functionParams[name]) return;
|
|
4759
|
-
globalVars[name] = 1;
|
|
4760
|
-
},
|
|
4761
|
-
AssignmentExpression(node) {
|
|
4762
|
-
if (node.left.type === "Identifier") {
|
|
4763
|
-
const name = node.left.name;
|
|
4764
|
-
if (!globalExists[name] || globalExists[name] === 1) {
|
|
4765
|
-
globalExists[name] = (globalExists[name] || 0) + 1;
|
|
4766
|
-
}
|
|
4767
|
-
}
|
|
4768
|
-
}
|
|
4769
|
-
});
|
|
4770
|
-
return Object.keys(globalVars);
|
|
4771
|
-
}
|
|
4772
|
-
function fallbackExtractVariables(source) {
|
|
4773
|
-
const vars = /* @__PURE__ */ new Set();
|
|
4774
|
-
const outputRegExp = /\{\{[:=!@]\s*([a-zA-Z_$][\w$]*)[^}]*\}\}/g;
|
|
4775
|
-
let m;
|
|
4776
|
-
while ((m = outputRegExp.exec(source)) !== null) {
|
|
4777
|
-
vars.add(m[1]);
|
|
4778
|
-
}
|
|
4779
|
-
const eachRegExp = /\{\{forOf\s+([a-zA-Z_$][\w$]*)\s+as/g;
|
|
4780
|
-
while ((m = eachRegExp.exec(source)) !== null) {
|
|
4781
|
-
vars.add(m[1]);
|
|
4782
|
-
}
|
|
4783
|
-
const ifRegExp = /\{\{(?:else\s+)?if\s+([a-zA-Z_$][\w$]*)[^}]*\}\}/g;
|
|
4784
|
-
while ((m = ifRegExp.exec(source)) !== null) {
|
|
4785
|
-
vars.add(m[1]);
|
|
4786
|
-
}
|
|
4787
|
-
return Array.from(vars).filter((v) => !BUILTIN_GLOBAL_SET.has(v));
|
|
4788
|
-
}
|
|
4789
|
-
function walkAst(ast, visitors) {
|
|
4790
|
-
function visit(node) {
|
|
4791
|
-
const type = node.type;
|
|
4792
|
-
if (visitors[type]) {
|
|
4793
|
-
visitors[type](node);
|
|
4794
|
-
}
|
|
4795
|
-
const bag = node;
|
|
4796
|
-
for (const key of Object.keys(node)) {
|
|
4797
|
-
if (key === "type" || key === "start" || key === "end" || key === "loc" || key === "range")
|
|
4798
|
-
continue;
|
|
4799
|
-
if (type === "MemberExpression" && key === "property") {
|
|
4800
|
-
const me = node;
|
|
4801
|
-
if (!me.computed) continue;
|
|
4802
|
-
}
|
|
4803
|
-
if (type === "ObjectProperty" && key === "key") {
|
|
4804
|
-
const op = node;
|
|
4805
|
-
if (!op.computed) continue;
|
|
4806
|
-
}
|
|
4807
|
-
if (type === "ObjectMethod" && key === "key") {
|
|
4808
|
-
const om = node;
|
|
4809
|
-
if (!om.computed) continue;
|
|
4810
|
-
}
|
|
4811
|
-
const child = bag[key];
|
|
4812
|
-
if (Array.isArray(child)) {
|
|
4813
|
-
for (const item of child) {
|
|
4814
|
-
if (isAstNode(item)) visit(item);
|
|
4815
|
-
}
|
|
4816
|
-
} else if (isAstNode(child)) {
|
|
4817
|
-
visit(child);
|
|
4818
|
-
}
|
|
4819
|
-
}
|
|
4820
|
-
}
|
|
4821
|
-
visit(ast);
|
|
4822
|
-
}
|
|
4823
|
-
function isAstNode(v) {
|
|
4824
|
-
return !!v && typeof v === "object" && typeof v.type === "string";
|
|
4825
|
-
}
|
|
4826
|
-
var BUILTIN_GLOBALS = {
|
|
4827
|
-
// ─── Template runtime helpers (injected by compileToFunction) ───────
|
|
4828
|
-
//
|
|
4829
|
-
// These variables appear in the generated template function signature
|
|
4830
|
-
// or body. They must be excluded from extractGlobalVars() so that
|
|
4831
|
-
// they are not mistaken for user data variables and destructured from $data.
|
|
4832
|
-
// SPLITTER character constant (same as \x1e), used as namespace separator
|
|
4833
|
-
// for refData keys, event attribute encoding, and internal data structures.
|
|
4834
|
-
// Declared as: let $splitter='\x1e'
|
|
4835
|
-
$splitter: 1,
|
|
4836
|
-
// Data — the data object passed from Updater to the template function.
|
|
4837
|
-
// User variables are destructured from $data at the top of the function:
|
|
4838
|
-
// let {name, age} = $data;
|
|
4839
|
-
// This is the first parameter of the generated arrow function.
|
|
4840
|
-
$data: 1,
|
|
4841
|
-
// Null-safe toString: v => '' + (v == null ? '' : v)
|
|
4842
|
-
// Converts null/undefined to empty string, otherwise calls toString().
|
|
4843
|
-
// Wraps every {{!raw}} output to prevent "null" / "undefined" rendering.
|
|
4844
|
-
$strSafe: 1,
|
|
4845
|
-
// HTML entity encoder: v => $strSafe(v).replace(/[&<>"'`]/g, entityMap)
|
|
4846
|
-
// Encodes &, <, >, ", ', ` to HTML entities (& < etc.)
|
|
4847
|
-
// Applied to all {{=escaped}} and {{:binding}} outputs.
|
|
4848
|
-
$encHtml: 1,
|
|
4849
|
-
// HTML entity map — internal object used by $encHtml:
|
|
4850
|
-
// {'&':'amp','<':'gt','>':'gt','"':'#34','\'':'#39','`':'#96'}
|
|
4851
|
-
// Not a standalone function; referenced inside $encHtml's closure.
|
|
4852
|
-
$entMap: 1,
|
|
4853
|
-
// HTML entity RegExp — internal regexp used by $encHtml:
|
|
4854
|
-
// /[&<>"'`]/g
|
|
4855
|
-
$entReg: 1,
|
|
4856
|
-
// HTML entity replacer function — internal helper used by $encHtml:
|
|
4857
|
-
// m => '&' + $entMap[m] + ';'
|
|
4858
|
-
// Maps matched character to its entity string.
|
|
4859
|
-
$entFn: 1,
|
|
4860
|
-
// Output buffer — the string accumulator for rendered HTML.
|
|
4861
|
-
// All template output is appended via $out += '...'.
|
|
4862
|
-
// Declared as: let $out = ''
|
|
4863
|
-
$out: 1,
|
|
4864
|
-
// Reference lookup: (refData, value) => key
|
|
4865
|
-
// Finds or allocates a SPLITTER-prefixed key in refData for a given
|
|
4866
|
-
// object reference. Used by {{@ref}} operator for passing object
|
|
4867
|
-
// references to child views via v-lark attributes.
|
|
4868
|
-
$refFn: 1,
|
|
4869
|
-
// URI encoder: v => encodeURIComponent($strSafe(v)).replace(/[!')(*]/g, extraMap)
|
|
4870
|
-
// Extends encodeURIComponent with encoding of ! ' ( ) *.
|
|
4871
|
-
// Applied to values in @event URL parameters and {{!uri}} contexts.
|
|
4872
|
-
$encUri: 1,
|
|
4873
|
-
// URI encode map — internal object used by $encUri:
|
|
4874
|
-
// {'!':'%21','\'':'%27','(':'%28',')':'%29','*':'%2A'}
|
|
4875
|
-
$uriMap: 1,
|
|
4876
|
-
// URI encode replacer — internal helper used by $encUri:
|
|
4877
|
-
// m => $uriMap[m]
|
|
4878
|
-
$uriFn: 1,
|
|
4879
|
-
// URI encode regexp — internal regexp used by $encUri:
|
|
4880
|
-
// /[!')(*]/g
|
|
4881
|
-
$uriReg: 1,
|
|
4882
|
-
// Quote encoder: v => $strSafe(v).replace(/['"\\]/g, '\\$&')
|
|
4883
|
-
// Escapes quotes and backslashes for safe embedding in HTML attribute
|
|
4884
|
-
// values (e.g. data-json='...').
|
|
4885
|
-
$encQuote: 1,
|
|
4886
|
-
// Quote encode regexp — internal regexp used by $encQuote:
|
|
4887
|
-
// /['"\\]/g
|
|
4888
|
-
$qReg: 1,
|
|
4889
|
-
// View ID — the unique identifier of the owning View instance.
|
|
4890
|
-
// Injected into @event attribute values at render time so that
|
|
4891
|
-
// EventDelegator can dispatch events to the correct View handler.
|
|
4892
|
-
// The \x1f placeholder in compiled output is replaced with '+$viewId+'.
|
|
4893
|
-
$viewId: 1,
|
|
4894
|
-
// Debug: current expression text — stores the template expression being
|
|
4895
|
-
// evaluated, for error reporting. Only present in debug mode.
|
|
4896
|
-
// e.g. $dbgExpr='<%=user.name%>'
|
|
4897
|
-
$dbgExpr: 1,
|
|
4898
|
-
// Debug: original art syntax — stores the {{}} template syntax before
|
|
4899
|
-
// conversion, for error reporting. Only present in debug mode.
|
|
4900
|
-
// e.g. $dbgArt='{{=user.name}}'
|
|
4901
|
-
$dbgArt: 1,
|
|
4902
|
-
// Debug: source line number — tracks the current line in the template
|
|
4903
|
-
// source, for error reporting. Only present in debug mode.
|
|
4904
|
-
$dbgLine: 1,
|
|
4905
|
-
// RefData alias — fallback reference lookup table.
|
|
4906
|
-
// Defaults to $data when no explicit $refAlt is provided.
|
|
4907
|
-
// Ensures $refFn() does not crash when @ operator is used without refData.
|
|
4908
|
-
$refAlt: 1,
|
|
4909
|
-
// Temporary variable — used by the compiler for intermediate
|
|
4910
|
-
// expression results in generated code (e.g. loop variables,
|
|
4911
|
-
// conditional branches). Declared as: let $tmp
|
|
4912
|
-
$tmp: 1,
|
|
4913
|
-
// JS literals
|
|
4914
|
-
undefined: 1,
|
|
4915
|
-
null: 1,
|
|
4916
|
-
true: 1,
|
|
4917
|
-
false: 1,
|
|
4918
|
-
NaN: 1,
|
|
4919
|
-
Infinity: 1,
|
|
4920
|
-
// JS built-in globals
|
|
4921
|
-
window: 1,
|
|
4922
|
-
self: 1,
|
|
4923
|
-
globalThis: 1,
|
|
4924
|
-
document: 1,
|
|
4925
|
-
console: 1,
|
|
4926
|
-
JSON: 1,
|
|
4927
|
-
Math: 1,
|
|
4928
|
-
Intl: 1,
|
|
4929
|
-
Promise: 1,
|
|
4930
|
-
Symbol: 1,
|
|
4931
|
-
Number: 1,
|
|
4932
|
-
String: 1,
|
|
4933
|
-
Boolean: 1,
|
|
4934
|
-
Array: 1,
|
|
4935
|
-
Object: 1,
|
|
4936
|
-
Date: 1,
|
|
4937
|
-
RegExp: 1,
|
|
4938
|
-
Error: 1,
|
|
4939
|
-
TypeError: 1,
|
|
4940
|
-
RangeError: 1,
|
|
4941
|
-
SyntaxError: 1,
|
|
4942
|
-
Map: 1,
|
|
4943
|
-
Set: 1,
|
|
4944
|
-
WeakMap: 1,
|
|
4945
|
-
WeakSet: 1,
|
|
4946
|
-
Proxy: 1,
|
|
4947
|
-
Reflect: 1,
|
|
4948
|
-
ArrayBuffer: 1,
|
|
4949
|
-
DataView: 1,
|
|
4950
|
-
Float32Array: 1,
|
|
4951
|
-
Float64Array: 1,
|
|
4952
|
-
Int8Array: 1,
|
|
4953
|
-
Int16Array: 1,
|
|
4954
|
-
Int32Array: 1,
|
|
4955
|
-
Uint8Array: 1,
|
|
4956
|
-
Uint16Array: 1,
|
|
4957
|
-
Uint32Array: 1,
|
|
4958
|
-
Uint8ClampedArray: 1,
|
|
4959
|
-
// Functions
|
|
4960
|
-
parseInt: 1,
|
|
4961
|
-
parseFloat: 1,
|
|
4962
|
-
isNaN: 1,
|
|
4963
|
-
isFinite: 1,
|
|
4964
|
-
encodeURIComponent: 1,
|
|
4965
|
-
decodeURIComponent: 1,
|
|
4966
|
-
encodeURI: 1,
|
|
4967
|
-
decodeURI: 1,
|
|
4968
|
-
// Babel helpers
|
|
4969
|
-
arguments: 1,
|
|
4970
|
-
this: 1,
|
|
4971
|
-
require: 1,
|
|
4972
|
-
// Lark framework
|
|
4973
|
-
Lark: 1
|
|
4974
|
-
};
|
|
4975
|
-
var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
|
|
4976
4218
|
export {
|
|
4977
4219
|
CALL_BREAK_TIME,
|
|
4978
4220
|
Cache,
|
|
@@ -4994,23 +4236,28 @@ export {
|
|
|
4994
4236
|
Updater,
|
|
4995
4237
|
VIEW_EVENT_METHOD_REGEXP,
|
|
4996
4238
|
View,
|
|
4239
|
+
applyDomOps,
|
|
4997
4240
|
applyIdUpdates,
|
|
4998
4241
|
applyStyle,
|
|
4999
|
-
applyVdomOps,
|
|
5000
4242
|
assign,
|
|
5001
4243
|
bindStore,
|
|
5002
|
-
compileTemplate,
|
|
5003
4244
|
computed,
|
|
5004
4245
|
create,
|
|
5005
|
-
|
|
4246
|
+
createDomRef,
|
|
5006
4247
|
defineStore,
|
|
5007
4248
|
defineView,
|
|
4249
|
+
domGetCompareKey,
|
|
4250
|
+
domGetNode,
|
|
4251
|
+
domSetAttributes,
|
|
4252
|
+
domSetChildNodes,
|
|
4253
|
+
domSetNode,
|
|
4254
|
+
domSpecialDiff,
|
|
4255
|
+
domUnmountFrames,
|
|
5008
4256
|
encodeHTML,
|
|
5009
4257
|
encodeQ,
|
|
5010
4258
|
encodeSafe,
|
|
5011
4259
|
encodeURIExtra,
|
|
5012
4260
|
ensureElementId,
|
|
5013
|
-
extractGlobalVars,
|
|
5014
4261
|
config as frameworkConfig,
|
|
5015
4262
|
funcWithTry,
|
|
5016
4263
|
generateId,
|
|
@@ -5043,12 +4290,5 @@ export {
|
|
|
5043
4290
|
translateData,
|
|
5044
4291
|
unmark,
|
|
5045
4292
|
use,
|
|
5046
|
-
useUrlState
|
|
5047
|
-
vdomGetCompareKey,
|
|
5048
|
-
vdomGetNode,
|
|
5049
|
-
vdomSetAttributes,
|
|
5050
|
-
vdomSetChildNodes,
|
|
5051
|
-
vdomSetNode,
|
|
5052
|
-
vdomSpecialDiff,
|
|
5053
|
-
vdomUnmountFrames
|
|
4293
|
+
useUrlState
|
|
5054
4294
|
};
|