@lark.js/mvc 0.0.7 → 0.0.8

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/index.cjs CHANGED
@@ -45,7 +45,6 @@ __export(index_exports, {
45
45
  applyVdomOps: () => applyVdomOps,
46
46
  assign: () => assign,
47
47
  bindStore: () => bindStore,
48
- compileTemplate: () => compileTemplate,
49
48
  computed: () => computed,
50
49
  create: () => create,
51
50
  createVdomRef: () => createVdomRef,
@@ -56,7 +55,6 @@ __export(index_exports, {
56
55
  encodeSafe: () => encodeSafe,
57
56
  encodeURIExtra: () => encodeURIExtra,
58
57
  ensureElementId: () => ensureElementId,
59
- extractGlobalVars: () => extractGlobalVars,
60
58
  frameworkConfig: () => config,
61
59
  funcWithTry: () => funcWithTry,
62
60
  generateId: () => generateId,
@@ -897,6 +895,9 @@ function attachViewAndPath(loc) {
897
895
  if (!loc.view) {
898
896
  const rawPath = routeMode === "history" ? loc.query["path"] || loc.hash["path"] : loc.hash["path"];
899
897
  let path = rawPath || cachedDefaultPath || "/";
898
+ if (!cachedRoutes[path] && path === "/" && cachedDefaultPath && cachedDefaultPath !== "/") {
899
+ path = cachedDefaultPath;
900
+ }
900
901
  if (cachedRewrite) {
901
902
  path = cachedRewrite(
902
903
  path,
@@ -965,6 +966,10 @@ function getChanged(oldLoc, newLoc) {
965
966
  function updateBrowserUrl(path, replace) {
966
967
  if (routeMode === "history") {
967
968
  const url = path || "/";
969
+ const currentUrl = window.location.pathname + window.location.search;
970
+ if (url === currentUrl) {
971
+ return;
972
+ }
968
973
  if (replace) {
969
974
  window.history.replaceState(null, "", url);
970
975
  } else {
@@ -986,6 +991,9 @@ function updateUrl(path, params, loc, replace, silentFlag, lQuery) {
986
991
  if (path !== currentSrc) {
987
992
  silent = silentFlag ? 1 : 0;
988
993
  updateBrowserUrl(path, replace);
994
+ if (routeMode === "history" && Router.notify) {
995
+ Router.notify();
996
+ }
989
997
  }
990
998
  }
991
999
  var Router = {
@@ -2253,28 +2261,28 @@ var View = class _View {
2253
2261
  // ============================================================
2254
2262
  // Static public methods
2255
2263
  // ============================================================
2256
- /** Collected ctors from mixins */
2257
- static ctors;
2264
+ /** Collected makes from mixins */
2265
+ static makes;
2258
2266
  /**
2259
2267
  * Prepare a View subclass by scanning its prototype for event method patterns.
2260
2268
  * Pattern: `$?name<eventType1,eventType2>(&modifiers)`
2261
2269
  *
2262
- * Only runs once per View subclass (guarded by ctors marker).
2270
+ * Only runs once per View subclass (guarded by makes marker).
2263
2271
  * Called from Frame.mountView before creating the view instance.
2264
2272
  */
2265
2273
  static prepare(oView) {
2266
- if (oView.ctors) {
2267
- return oView.ctors;
2274
+ if (oView.makes) {
2275
+ return oView.makes;
2268
2276
  }
2269
- const ctors = [];
2270
- oView.ctors = ctors;
2277
+ const makes = [];
2278
+ oView.makes = makes;
2271
2279
  const proto = oView.prototype;
2272
2280
  const eventsObject = {};
2273
2281
  const eventsList = [];
2274
2282
  const selectorObject = {};
2275
2283
  const mixins = proto["mixins"];
2276
2284
  if (mixins && Array.isArray(mixins)) {
2277
- _View.mergeMixins(mixins, oView, ctors);
2285
+ _View.mergeMixins(mixins, oView, makes);
2278
2286
  }
2279
2287
  for (const p in proto) {
2280
2288
  if (!hasOwnProperty(proto, p)) continue;
@@ -2344,7 +2352,7 @@ var View = class _View {
2344
2352
  proto["$globalEvtList"] = eventsList;
2345
2353
  proto["$selMap"] = selectorObject;
2346
2354
  proto["$assignFn"] = proto["assign"];
2347
- return ctors;
2355
+ return makes;
2348
2356
  }
2349
2357
  /**
2350
2358
  * Bind or unbind event delegation for a view instance.
@@ -2469,7 +2477,7 @@ var View = class _View {
2469
2477
  /**
2470
2478
  * Merge an array of mixin objects into the view prototype.
2471
2479
  */
2472
- static mergeMixins(mixins, viewClass, ctors) {
2480
+ static mergeMixins(mixins, viewClass, makes) {
2473
2481
  const proto = viewClass.prototype;
2474
2482
  const temp = {};
2475
2483
  for (const node of mixins) {
@@ -2480,7 +2488,7 @@ var View = class _View {
2480
2488
  const mixinFn = fn;
2481
2489
  const exist = temp[p];
2482
2490
  if (p === "make") {
2483
- ctors.push(mixinFn);
2491
+ makes.push(mixinFn);
2484
2492
  continue;
2485
2493
  }
2486
2494
  if (VIEW_EVENT_METHOD_REGEXP.test(p)) {
@@ -2531,9 +2539,9 @@ var View = class _View {
2531
2539
  static extend(props, statics) {
2532
2540
  const definedProps = props ?? {};
2533
2541
  const make = definedProps["make"];
2534
- const ctors = [];
2542
+ const makes = [];
2535
2543
  if (typeof make === "function") {
2536
- ctors.push(make);
2544
+ makes.push(make);
2537
2545
  }
2538
2546
  const ParentView = this;
2539
2547
  const ChildView = class extends ParentView {
@@ -2555,7 +2563,7 @@ var View = class _View {
2555
2563
  deep: !this.template
2556
2564
  }
2557
2565
  ];
2558
- const concatCtors = ctors.concat(mixinCtors || []);
2566
+ const concatCtors = makes.concat(mixinCtors || []);
2559
2567
  if (concatCtors.length) {
2560
2568
  funcWithTry(concatCtors, params, this, noop);
2561
2569
  }
@@ -2581,7 +2589,7 @@ var View = class _View {
2581
2589
  * Merge mixins into View prototype.
2582
2590
  */
2583
2591
  static merge(...mixins) {
2584
- const existingCtors = this.ctors || [];
2592
+ const existingCtors = this.makes || [];
2585
2593
  _View.mergeMixins(mixins, this, existingCtors);
2586
2594
  return this;
2587
2595
  }
@@ -3325,13 +3333,13 @@ var Service = class {
3325
3333
  * References per-type static state from the current class.
3326
3334
  */
3327
3335
  get internals() {
3328
- const ctor = this.constructor;
3336
+ const constructor = this.constructor;
3329
3337
  return {
3330
- metaList: ctor._metaList,
3331
- payloadCache: ctor._payloadCache,
3332
- pendingCacheKeys: ctor._pendingCacheKeys,
3333
- syncFn: ctor._syncFn,
3334
- staticEmitter: ctor._staticEmitter
3338
+ metaList: constructor._metaList,
3339
+ payloadCache: constructor._payloadCache,
3340
+ pendingCacheKeys: constructor._pendingCacheKeys,
3341
+ syncFn: constructor._syncFn,
3342
+ staticEmitter: constructor._staticEmitter
3335
3343
  };
3336
3344
  }
3337
3345
  /**
@@ -4326,755 +4334,6 @@ function bindStore(view, store, selector) {
4326
4334
  return off;
4327
4335
  }
4328
4336
  var defineStore = create;
4329
-
4330
- // src/compiler.ts
4331
- var import_parser = require("@babel/parser");
4332
- var SPLITTER2 = String.fromCharCode(30);
4333
- var VIEW_ID_PLACEHOLDER = String.fromCharCode(31);
4334
- function jsObjectToUrlParams(paramsStr) {
4335
- const trimmed = paramsStr.trim();
4336
- if (!/^[{[]/.test(trimmed) && /=/.test(trimmed)) {
4337
- return trimmed;
4338
- }
4339
- const objMatch = trimmed.match(/^\{(.*)\}$/s);
4340
- if (objMatch) {
4341
- const inner = objMatch[1];
4342
- const pairs = [];
4343
- const pairRegExp = /(\w+)\s*:\s*(?:'([^']*)'|"([^"]*)"|([^,}]+))/g;
4344
- let m;
4345
- while ((m = pairRegExp.exec(inner)) !== null) {
4346
- const key = m[1];
4347
- const value = m[2] ?? m[3] ?? m[4]?.trim() ?? "";
4348
- pairs.push(`${key}=${value}`);
4349
- }
4350
- return pairs.join("&");
4351
- }
4352
- return trimmed;
4353
- }
4354
- function protectComments(source) {
4355
- const comments = [];
4356
- const protectedSource = source.replace(/<!--[\s\S]*?-->/g, (match) => {
4357
- comments.push(match);
4358
- return `__lark_comment_${comments.length - 1}__`;
4359
- });
4360
- return { protectedSource, comments };
4361
- }
4362
- function restoreComments(source, comments) {
4363
- return source.replace(/__lark_comment_(\d+)__/g, (_, index) => {
4364
- return comments[parseInt(index, 10)];
4365
- });
4366
- }
4367
- function processViewEvents(source) {
4368
- return source.replace(
4369
- /@(\w+)="([^"]+)"/g,
4370
- (fullAttr, eventName, attrValue) => {
4371
- const eventMatch = attrValue.match(/^(\w+)\((.*)\)$/s);
4372
- if (!eventMatch) return fullAttr;
4373
- const handlerName = eventMatch[1];
4374
- const paramsStr = eventMatch[2].trim();
4375
- if (!paramsStr) {
4376
- return `@${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}()"`;
4377
- }
4378
- const urlParams = jsObjectToUrlParams(paramsStr);
4379
- return `@${eventName}="${VIEW_ID_PLACEHOLDER}${SPLITTER2}${handlerName}(${urlParams})"`;
4380
- }
4381
- );
4382
- }
4383
- function addLineMarkers(source) {
4384
- const lines = source.split(/\r\n?|\n/);
4385
- const result = [];
4386
- let lineNo = 0;
4387
- const openTag = "{{";
4388
- for (const line of lines) {
4389
- const parts = line.split(openTag);
4390
- if (parts.length > 1) {
4391
- const reconstructed = parts.map((part, i) => {
4392
- if (i === 0) return part;
4393
- return openTag + SPLITTER2 + ++lineNo + part;
4394
- }).join("");
4395
- result.push(reconstructed);
4396
- } else {
4397
- result.push(line);
4398
- }
4399
- }
4400
- return result.join("\n");
4401
- }
4402
- function extractArtInfo(art) {
4403
- const m = art.match(new RegExp(`^${SPLITTER2}(\\d+)([\\s\\S]+)`));
4404
- if (m) {
4405
- let code = m[2].trimStart();
4406
- if (code.startsWith("if(")) {
4407
- code = code.substring(0, 2) + " " + code.substring(2);
4408
- } else if (code.startsWith("for(")) {
4409
- code = code.substring(0, 3) + " " + code.substring(3);
4410
- }
4411
- return { line: parseInt(m[1], 10), art: code };
4412
- }
4413
- return null;
4414
- }
4415
- function convertArtSyntax(source, debug) {
4416
- const markedSource = debug ? addLineMarkers(source) : source;
4417
- const openTag = "{{";
4418
- const parts = markedSource.split(openTag);
4419
- const result = [parts[0]];
4420
- const blockStack = [];
4421
- for (let i = 1; i < parts.length; i++) {
4422
- const part = parts[i];
4423
- const closeIdx = findCloseBrace(part);
4424
- if (closeIdx === -1) {
4425
- result.push(openTag + part);
4426
- continue;
4427
- }
4428
- const code = part.substring(0, closeIdx);
4429
- const rest = part.substring(closeIdx + 2);
4430
- let lineNo = -1;
4431
- let cleanCode = code;
4432
- if (debug) {
4433
- const info = extractArtInfo(code);
4434
- if (info) {
4435
- lineNo = info.line;
4436
- cleanCode = info.art;
4437
- }
4438
- } else {
4439
- cleanCode = code.trim();
4440
- }
4441
- const converted = convertArtExpression(
4442
- cleanCode,
4443
- debug,
4444
- lineNo,
4445
- blockStack
4446
- );
4447
- result.push(converted);
4448
- result.push(rest);
4449
- }
4450
- if (blockStack.length > 0) {
4451
- const unclosed = blockStack.map((b) => `"${b.ctrl}" at line ${b.line}`).join(", ");
4452
- throw new Error(`[@lark.js/mvc error] unclosed block(s): ${unclosed}`);
4453
- }
4454
- return result.join("");
4455
- }
4456
- function findCloseBrace(str) {
4457
- let leftCount = 0;
4458
- let rightCount = 0;
4459
- let maybeCount = 0;
4460
- let maybeAt = -1;
4461
- for (let i = 0; i < str.length; i++) {
4462
- const c = str.charAt(i);
4463
- if (c !== "}") {
4464
- if (maybeCount >= 2 && maybeAt === -1) {
4465
- maybeAt = i;
4466
- }
4467
- maybeCount = 0;
4468
- rightCount = 0;
4469
- }
4470
- if (c === "{") {
4471
- leftCount++;
4472
- } else if (c === "}") {
4473
- maybeCount++;
4474
- if (!leftCount) {
4475
- rightCount++;
4476
- if (rightCount === 2) {
4477
- return i - 1;
4478
- }
4479
- } else {
4480
- leftCount--;
4481
- }
4482
- }
4483
- }
4484
- if (!leftCount && maybeCount >= 2 && maybeAt === -1) {
4485
- maybeAt = str.length - 2;
4486
- }
4487
- if (maybeAt > -1) {
4488
- return maybeAt - 2;
4489
- }
4490
- return -1;
4491
- }
4492
- function trimOuterParens(expr) {
4493
- expr = expr.trim();
4494
- while (expr.startsWith("(") && expr.endsWith(")")) {
4495
- let depth = 0;
4496
- let matched = true;
4497
- for (let i = 0; i < expr.length - 1; i++) {
4498
- const c = expr.charAt(i);
4499
- if (c === "(") depth++;
4500
- else if (c === ")") depth--;
4501
- if (depth === 0 && i < expr.length - 1) {
4502
- matched = false;
4503
- break;
4504
- }
4505
- }
4506
- if (!matched) break;
4507
- expr = expr.substring(1, expr.length - 1).trim();
4508
- }
4509
- return expr;
4510
- }
4511
- function convertArtExpression(code, debug, lineNo, blockStack = []) {
4512
- code = code.trim();
4513
- const debugPrefix = debug && lineNo > -1 ? `<%'${lineNo}${code.replace(/\\|'/g, "\\$&").replace(/\r\n?|\n/g, "\\n")}'%>` : "";
4514
- const ifForMatch = code.match(/^\s*(if|for)\s*\(/);
4515
- if (ifForMatch) {
4516
- const keyword2 = ifForMatch[1];
4517
- const expr = code.substring(ifForMatch[0].length);
4518
- if (keyword2 === "if") {
4519
- blockStack.push({ ctrl: "if", line: lineNo });
4520
- const rawExpr = expr.replace(/\)\s*$/, "");
4521
- const cleanExpr = trimOuterParens(rawExpr);
4522
- return `${debugPrefix}<%if(${cleanExpr}){%>`;
4523
- }
4524
- blockStack.push({ ctrl: "for", line: lineNo });
4525
- const forExpr = expr.replace(/\)\s*$/, "");
4526
- return `${debugPrefix}<%for(${forExpr}){%>`;
4527
- }
4528
- const tokens = code.split(/\s+/);
4529
- const keyword = tokens.shift() ?? "";
4530
- switch (keyword) {
4531
- case "if": {
4532
- blockStack.push({ ctrl: "if", line: lineNo });
4533
- const rawExpr = tokens.join(" ").trim();
4534
- const expr = trimOuterParens(rawExpr);
4535
- return `${debugPrefix}<%if(${expr}){%>`;
4536
- }
4537
- case "else": {
4538
- if (tokens[0] === "if") {
4539
- tokens.shift();
4540
- const rawExpr = tokens.join(" ").trim();
4541
- const expr = trimOuterParens(rawExpr);
4542
- return `${debugPrefix}<%}else if(${expr}){%>`;
4543
- }
4544
- return `${debugPrefix}<%}else{%>`;
4545
- }
4546
- case "forOf": {
4547
- blockStack.push({ ctrl: "forOf", line: lineNo });
4548
- const object = tokens[0];
4549
- if (tokens.length > 1 && tokens[1] !== "as") {
4550
- throw new Error(
4551
- `[@lark.js/mvc error] bad forOf syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{forOf list as item [index]}}`
4552
- );
4553
- }
4554
- const restTokens = tokens.slice(2);
4555
- const asValue = restTokens.join(" ");
4556
- const asExpr = parseAsExpr(asValue);
4557
- const index = asExpr.key || "_i";
4558
- const refObj = /[.[\]]/.test(object) ? `_art_obj_${object.replace(/[^\w]/g, "_")}` : object;
4559
- const refExpr = /[.[\]]/.test(object) ? `,${refObj}=${object}` : "";
4560
- const refObjCount = "_l";
4561
- const valueDecl = asExpr.vars ? `let ${asExpr.vars}=${refObj}[${index}]` : "";
4562
- let firstAndLast = "";
4563
- let lastCount = "";
4564
- if (asExpr.first) {
4565
- firstAndLast += `let ${asExpr.first}=${index}===0;`;
4566
- }
4567
- if (asExpr.last) {
4568
- lastCount = `,_lc=${refObjCount}-1`;
4569
- firstAndLast += `let ${asExpr.last}=${index}===_lc;`;
4570
- }
4571
- return `${debugPrefix}<%for(let ${index}=0${refExpr},${refObjCount}=${refObj}.length${lastCount};${index}<${refObjCount};${index}++){${firstAndLast}${valueDecl}%>`;
4572
- }
4573
- case "forIn": {
4574
- blockStack.push({ ctrl: "forIn", line: lineNo });
4575
- const object = tokens[0];
4576
- if (tokens.length > 1 && tokens[1] !== "as") {
4577
- throw new Error(
4578
- `[@lark.js/mvc error] bad forIn syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{for-in obj as val [key]}}`
4579
- );
4580
- }
4581
- const restTokens2 = tokens.slice(2);
4582
- const asValue2 = restTokens2.join(" ");
4583
- const asExpr2 = parseAsExpr(asValue2);
4584
- const key1 = asExpr2.key || "_k";
4585
- const refObj2 = /[.[\]]/.test(object) ? `_art_obj_${object.replace(/[^\w]/g, "_")}` : object;
4586
- const refExpr2 = /[.[\]]/.test(object) ? `let ${refObj2}=${object};` : "";
4587
- const valueDecl2 = asExpr2.vars ? `let ${asExpr2.vars}=${refObj2}[${key1}]` : "";
4588
- return `${debugPrefix}<%${refExpr2}for(let ${key1} in ${refObj2}){${valueDecl2}%>`;
4589
- }
4590
- case "for": {
4591
- blockStack.push({ ctrl: "for", line: lineNo });
4592
- const expr = tokens.join(" ").trim();
4593
- return `${debugPrefix}<%for(${expr}){%>`;
4594
- }
4595
- case "set":
4596
- return `${debugPrefix}<%let ${tokens.join(" ")};%>`;
4597
- case "/if":
4598
- case "/forOf":
4599
- case "/forIn":
4600
- case "/for": {
4601
- const expectedCtrl = keyword.substring(1);
4602
- const last = blockStack.pop();
4603
- if (!last) {
4604
- throw new Error(
4605
- `[@lark.js/mvc error] unexpected {{${code}}}: no matching open block`
4606
- );
4607
- }
4608
- if (last.ctrl !== expectedCtrl) {
4609
- throw new Error(
4610
- `[@lark.js/mvc error] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
4611
- );
4612
- }
4613
- return `${debugPrefix}<%}%>`;
4614
- }
4615
- default:
4616
- return `${debugPrefix}<%${code}%>`;
4617
- }
4618
- }
4619
- function parseAsExpr(expr) {
4620
- expr = expr.trim();
4621
- if (!expr) {
4622
- return { vars: "", key: "", last: "", first: "", bad: false };
4623
- }
4624
- if (expr.startsWith("{") || expr.startsWith("[")) {
4625
- const stack = [];
4626
- let vars = "";
4627
- let key = "";
4628
- let last = "";
4629
- let first = "";
4630
- let pos = 0;
4631
- let bad = false;
4632
- for (const c of expr) {
4633
- if (pos === 0) vars += c;
4634
- else if (pos === 1) key += c;
4635
- else if (pos === 2) last += c;
4636
- else if (pos === 3) first += c;
4637
- if (c === "{" || c === "[") stack.push(c);
4638
- else if (c === "}") {
4639
- if (stack[stack.length - 1] === "{") stack.pop();
4640
- else {
4641
- bad = true;
4642
- break;
4643
- }
4644
- } else if (c === "]") {
4645
- if (stack[stack.length - 1] === "[") stack.pop();
4646
- else {
4647
- bad = true;
4648
- break;
4649
- }
4650
- } else if (c === " " && !stack.length) {
4651
- pos++;
4652
- }
4653
- }
4654
- return {
4655
- vars: vars.trim(),
4656
- key: key.trim(),
4657
- last: last.trim(),
4658
- first: first.trim(),
4659
- bad: bad || stack.length > 0
4660
- };
4661
- }
4662
- const parts = expr.split(/\s+/);
4663
- return {
4664
- vars: parts[0] || "",
4665
- key: parts[1] || "",
4666
- last: parts[2] || "",
4667
- first: parts[3] || "",
4668
- bad: false
4669
- };
4670
- }
4671
- function compileToFunction(source, debug, file) {
4672
- const matcher = /<%([@=!:])?([\s\S]*?)%>|$/g;
4673
- let index = 0;
4674
- let funcSource = `$out+='`;
4675
- let hasAtRule = false;
4676
- const escapeSlashRegExp = /\\|'/g;
4677
- const escapeBreakReturnRegExp = /\r|\n/g;
4678
- source.replace(matcher, (match, operate, content, offset) => {
4679
- funcSource += source.substring(index, offset).replace(escapeSlashRegExp, "\\$&").replace(escapeBreakReturnRegExp, "\\n");
4680
- index = offset + match.length;
4681
- if (debug) {
4682
- let expr = source.substring(
4683
- index - match.length + 2 + (operate ? 1 : 0),
4684
- index - 2
4685
- );
4686
- const x11 = String.fromCharCode(17);
4687
- const artRegExp = new RegExp(`^'(\\d+)${x11}([^${x11}]+)${x11}'$`);
4688
- const artM = expr.match(artRegExp);
4689
- let art = "";
4690
- let line = -1;
4691
- if (artM) {
4692
- expr = expr.replace(artRegExp, "");
4693
- art = artM[2];
4694
- line = parseInt(artM[1], 10);
4695
- } else {
4696
- expr = expr.replace(escapeSlashRegExp, "\\$&").replace(escapeBreakReturnRegExp, "\\n");
4697
- }
4698
- if (operate === "@") {
4699
- hasAtRule = true;
4700
- funcSource += `'+($dbgExpr='<%${operate + expr}%>',$refFn($refAlt,${content}))+'`;
4701
- } else if (operate === "=" || operate === ":") {
4702
- funcSource += `'+($dbgExpr='<%${operate + expr}%>',$encHtml(${content}))+'`;
4703
- } else if (operate === "!") {
4704
- if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
4705
- content = `$strSafe(${content})`;
4706
- }
4707
- funcSource += `'+($dbgExpr='<%${operate + expr}%>',${content})+'`;
4708
- } else if (content) {
4709
- if (line > -1) {
4710
- funcSource += `';$dbgLine=${line};$dbgArt='${art}';`;
4711
- content = "";
4712
- } else {
4713
- funcSource += `';`;
4714
- }
4715
- if (funcSource.endsWith(`+'';`)) {
4716
- funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
4717
- }
4718
- if (expr) {
4719
- funcSource += `$dbgExpr='<%${expr}%>';`;
4720
- }
4721
- funcSource += content + `;$out+='`;
4722
- }
4723
- } else {
4724
- if (operate === "@") {
4725
- hasAtRule = true;
4726
- funcSource += `'+$refFn($refAlt,${content})+'`;
4727
- } else if (operate === "=" || operate === ":") {
4728
- funcSource += `'+$encHtml(${content})+'`;
4729
- } else if (operate === "!") {
4730
- if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
4731
- content = `$strSafe(${content})`;
4732
- }
4733
- funcSource += `'+${content}+'`;
4734
- } else if (content) {
4735
- funcSource += `';`;
4736
- if (funcSource.endsWith(`+'';`)) {
4737
- funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
4738
- }
4739
- funcSource += `${content};$out+='`;
4740
- }
4741
- }
4742
- return match;
4743
- });
4744
- funcSource += `';`;
4745
- funcSource = funcSource.replace(/\$out\+='';/g, "");
4746
- funcSource = funcSource.replace(/\$out\+=''\+/g, "$out+=");
4747
- if (debug) {
4748
- const filePart = file ? `\\r\\n\\tat file:${file}` : "";
4749
- 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;}`;
4750
- }
4751
- const viewIdRegExp = new RegExp(String.fromCharCode(31), "g");
4752
- funcSource = funcSource.replace(viewIdRegExp, `'+$viewId+'`);
4753
- void hasAtRule;
4754
- const refFallback = "if(!$refAlt)$refAlt=$data;";
4755
- const fullSource = `${refFallback}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
4756
- return `($data,$viewId,$refAlt,$encHtml,$strSafe,$encUri,$refFn,$encQuote)=>{${fullSource}}`;
4757
- }
4758
- function compileTemplate(source, options = {}) {
4759
- const { debug = false, globalVars = [], file } = options;
4760
- const { protectedSource, comments } = protectComments(source);
4761
- const converted = convertArtSyntax(protectedSource, debug);
4762
- const viewEventProcessed = processViewEvents(converted);
4763
- const finalSource = restoreComments(viewEventProcessed, comments);
4764
- const funcBody = compileToFunction(finalSource, debug, file);
4765
- const varDeclarations = globalVars.map((key) => `,${key}=$data.${key}`).join("");
4766
- const funcWithVars = funcBody.replace("{{VARS}}", () => varDeclarations);
4767
- return `import { encHtml as __larkEncHtml, strSafe as __larkStrSafe, encUri as __larkEncUri, encQuote as __larkEncQuote, refFn as __larkRefFn } from "@lark.js/mvc/runtime";
4768
- export default function(data, viewId, refData) {
4769
- let $data = data || {},
4770
- $viewId = viewId || '';
4771
- return (${funcWithVars})($data, $viewId, refData,
4772
- __larkEncHtml, __larkStrSafe, __larkEncUri, __larkRefFn, __larkEncQuote
4773
- );
4774
- }`;
4775
- }
4776
- function extractGlobalVars(source) {
4777
- const { protectedSource, comments: _comments } = protectComments(source);
4778
- const viewEventProcessed = processViewEvents(protectedSource);
4779
- const converted = convertArtSyntax(viewEventProcessed, false);
4780
- const template = restoreComments(converted, _comments);
4781
- const templateCmdRegExp = /<%([@=!:])?([\s\S]*?)%>|$/g;
4782
- const fnParts = [];
4783
- const htmlStore = {};
4784
- let htmlIndex = 0;
4785
- let lastIndex = 0;
4786
- const htmlKey = String.fromCharCode(5);
4787
- template.replace(
4788
- templateCmdRegExp,
4789
- (match, operate, content, offset) => {
4790
- const start = operate ? 3 : 2;
4791
- const htmlText = template.substring(lastIndex, offset + start);
4792
- const key = htmlKey + htmlIndex++ + htmlKey;
4793
- htmlStore[key] = htmlText;
4794
- lastIndex = offset + match.length - 2;
4795
- if (operate && content.trim()) {
4796
- fnParts.push(';"' + key + '";', "[" + content + "]");
4797
- } else {
4798
- fnParts.push(';"' + key + '";', content || "");
4799
- }
4800
- return match;
4801
- }
4802
- );
4803
- let fn = fnParts.join("");
4804
- fn = `(function(){${fn}})`;
4805
- let ast;
4806
- try {
4807
- ast = (0, import_parser.parse)(fn, {
4808
- sourceType: "script",
4809
- allowReturnOutsideFunction: true,
4810
- allowAwaitOutsideFunction: true
4811
- });
4812
- } catch {
4813
- return fallbackExtractVariables(source);
4814
- }
4815
- const globalExists = { ...BUILTIN_GLOBALS };
4816
- const globalVars = /* @__PURE__ */ Object.create(null);
4817
- const fnRange = [];
4818
- walkAst(ast, {
4819
- VariableDeclarator(node) {
4820
- if (node.id.type === "Identifier") {
4821
- const name = node.id.name;
4822
- globalExists[name] = node.init ? 3 : 2;
4823
- }
4824
- },
4825
- FunctionDeclaration(node) {
4826
- if (node.id) {
4827
- globalExists[node.id.name] = 3;
4828
- }
4829
- fnRange.push(node);
4830
- },
4831
- FunctionExpression(node) {
4832
- fnRange.push(node);
4833
- },
4834
- ArrowFunctionExpression(node) {
4835
- fnRange.push(node);
4836
- },
4837
- CallExpression(node) {
4838
- if (node.callee.type === "Identifier") {
4839
- globalExists[node.callee.name] = 1;
4840
- }
4841
- }
4842
- });
4843
- const functionParams = /* @__PURE__ */ Object.create(null);
4844
- for (const fnNode of fnRange) {
4845
- const params = "params" in fnNode ? fnNode.params : [];
4846
- for (const p of params) {
4847
- if (p.type === "Identifier") {
4848
- functionParams[p.name] = 1;
4849
- } else if (p.type === "AssignmentPattern" && p.left.type === "Identifier") {
4850
- functionParams[p.left.name] = 1;
4851
- } else if (p.type === "RestElement" && p.argument.type === "Identifier") {
4852
- functionParams[p.argument.name] = 1;
4853
- }
4854
- }
4855
- }
4856
- walkAst(ast, {
4857
- Identifier(node) {
4858
- const name = node.name;
4859
- if (globalExists[name]) return;
4860
- if (functionParams[name]) return;
4861
- globalVars[name] = 1;
4862
- },
4863
- AssignmentExpression(node) {
4864
- if (node.left.type === "Identifier") {
4865
- const name = node.left.name;
4866
- if (!globalExists[name] || globalExists[name] === 1) {
4867
- globalExists[name] = (globalExists[name] || 0) + 1;
4868
- }
4869
- }
4870
- }
4871
- });
4872
- return Object.keys(globalVars);
4873
- }
4874
- function fallbackExtractVariables(source) {
4875
- const vars = /* @__PURE__ */ new Set();
4876
- const outputRegExp = /\{\{[:=!@]\s*([a-zA-Z_$][\w$]*)[^}]*\}\}/g;
4877
- let m;
4878
- while ((m = outputRegExp.exec(source)) !== null) {
4879
- vars.add(m[1]);
4880
- }
4881
- const eachRegExp = /\{\{forOf\s+([a-zA-Z_$][\w$]*)\s+as/g;
4882
- while ((m = eachRegExp.exec(source)) !== null) {
4883
- vars.add(m[1]);
4884
- }
4885
- const ifRegExp = /\{\{(?:else\s+)?if\s+([a-zA-Z_$][\w$]*)[^}]*\}\}/g;
4886
- while ((m = ifRegExp.exec(source)) !== null) {
4887
- vars.add(m[1]);
4888
- }
4889
- return Array.from(vars).filter((v) => !BUILTIN_GLOBAL_SET.has(v));
4890
- }
4891
- function walkAst(ast, visitors) {
4892
- function visit(node) {
4893
- const type = node.type;
4894
- if (visitors[type]) {
4895
- visitors[type](node);
4896
- }
4897
- const bag = node;
4898
- for (const key of Object.keys(node)) {
4899
- if (key === "type" || key === "start" || key === "end" || key === "loc" || key === "range")
4900
- continue;
4901
- if (type === "MemberExpression" && key === "property") {
4902
- const me = node;
4903
- if (!me.computed) continue;
4904
- }
4905
- if (type === "ObjectProperty" && key === "key") {
4906
- const op = node;
4907
- if (!op.computed) continue;
4908
- }
4909
- if (type === "ObjectMethod" && key === "key") {
4910
- const om = node;
4911
- if (!om.computed) continue;
4912
- }
4913
- const child = bag[key];
4914
- if (Array.isArray(child)) {
4915
- for (const item of child) {
4916
- if (isAstNode(item)) visit(item);
4917
- }
4918
- } else if (isAstNode(child)) {
4919
- visit(child);
4920
- }
4921
- }
4922
- }
4923
- visit(ast);
4924
- }
4925
- function isAstNode(v) {
4926
- return !!v && typeof v === "object" && typeof v.type === "string";
4927
- }
4928
- var BUILTIN_GLOBALS = {
4929
- // ─── Template runtime helpers (injected by compileToFunction) ───────
4930
- //
4931
- // These variables appear in the generated template function signature
4932
- // or body. They must be excluded from extractGlobalVars() so that
4933
- // they are not mistaken for user data variables and destructured from $data.
4934
- // SPLITTER character constant (same as \x1e), used as namespace separator
4935
- // for refData keys, event attribute encoding, and internal data structures.
4936
- // Declared as: let $splitter='\x1e'
4937
- $splitter: 1,
4938
- // Data — the data object passed from Updater to the template function.
4939
- // User variables are destructured from $data at the top of the function:
4940
- // let {name, age} = $data;
4941
- // This is the first parameter of the generated arrow function.
4942
- $data: 1,
4943
- // Null-safe toString: v => '' + (v == null ? '' : v)
4944
- // Converts null/undefined to empty string, otherwise calls toString().
4945
- // Wraps every {{!raw}} output to prevent "null" / "undefined" rendering.
4946
- $strSafe: 1,
4947
- // HTML entity encoder: v => $strSafe(v).replace(/[&<>"'`]/g, entityMap)
4948
- // Encodes &, <, >, ", ', ` to HTML entities (&amp; &lt; etc.)
4949
- // Applied to all {{=escaped}} and {{:binding}} outputs.
4950
- $encHtml: 1,
4951
- // HTML entity map — internal object used by $encHtml:
4952
- // {'&':'amp','<':'gt','>':'gt','"':'#34','\'':'#39','`':'#96'}
4953
- // Not a standalone function; referenced inside $encHtml's closure.
4954
- $entMap: 1,
4955
- // HTML entity RegExp — internal regexp used by $encHtml:
4956
- // /[&<>"'`]/g
4957
- $entReg: 1,
4958
- // HTML entity replacer function — internal helper used by $encHtml:
4959
- // m => '&' + $entMap[m] + ';'
4960
- // Maps matched character to its entity string.
4961
- $entFn: 1,
4962
- // Output buffer — the string accumulator for rendered HTML.
4963
- // All template output is appended via $out += '...'.
4964
- // Declared as: let $out = ''
4965
- $out: 1,
4966
- // Reference lookup: (refData, value) => key
4967
- // Finds or allocates a SPLITTER-prefixed key in refData for a given
4968
- // object reference. Used by {{@ref}} operator for passing object
4969
- // references to child views via v-lark attributes.
4970
- $refFn: 1,
4971
- // URI encoder: v => encodeURIComponent($strSafe(v)).replace(/[!')(*]/g, extraMap)
4972
- // Extends encodeURIComponent with encoding of ! ' ( ) *.
4973
- // Applied to values in @event URL parameters and {{!uri}} contexts.
4974
- $encUri: 1,
4975
- // URI encode map — internal object used by $encUri:
4976
- // {'!':'%21','\'':'%27','(':'%28',')':'%29','*':'%2A'}
4977
- $uriMap: 1,
4978
- // URI encode replacer — internal helper used by $encUri:
4979
- // m => $uriMap[m]
4980
- $uriFn: 1,
4981
- // URI encode regexp — internal regexp used by $encUri:
4982
- // /[!')(*]/g
4983
- $uriReg: 1,
4984
- // Quote encoder: v => $strSafe(v).replace(/['"\\]/g, '\\$&')
4985
- // Escapes quotes and backslashes for safe embedding in HTML attribute
4986
- // values (e.g. data-json='...').
4987
- $encQuote: 1,
4988
- // Quote encode regexp — internal regexp used by $encQuote:
4989
- // /['"\\]/g
4990
- $qReg: 1,
4991
- // View ID — the unique identifier of the owning View instance.
4992
- // Injected into @event attribute values at render time so that
4993
- // EventDelegator can dispatch events to the correct View handler.
4994
- // The \x1f placeholder in compiled output is replaced with '+$viewId+'.
4995
- $viewId: 1,
4996
- // Debug: current expression text — stores the template expression being
4997
- // evaluated, for error reporting. Only present in debug mode.
4998
- // e.g. $dbgExpr='<%=user.name%>'
4999
- $dbgExpr: 1,
5000
- // Debug: original art syntax — stores the {{}} template syntax before
5001
- // conversion, for error reporting. Only present in debug mode.
5002
- // e.g. $dbgArt='{{=user.name}}'
5003
- $dbgArt: 1,
5004
- // Debug: source line number — tracks the current line in the template
5005
- // source, for error reporting. Only present in debug mode.
5006
- $dbgLine: 1,
5007
- // RefData alias — fallback reference lookup table.
5008
- // Defaults to $data when no explicit $refAlt is provided.
5009
- // Ensures $refFn() does not crash when @ operator is used without refData.
5010
- $refAlt: 1,
5011
- // Temporary variable — used by the compiler for intermediate
5012
- // expression results in generated code (e.g. loop variables,
5013
- // conditional branches). Declared as: let $tmp
5014
- $tmp: 1,
5015
- // JS literals
5016
- undefined: 1,
5017
- null: 1,
5018
- true: 1,
5019
- false: 1,
5020
- NaN: 1,
5021
- Infinity: 1,
5022
- // JS built-in globals
5023
- window: 1,
5024
- self: 1,
5025
- globalThis: 1,
5026
- document: 1,
5027
- console: 1,
5028
- JSON: 1,
5029
- Math: 1,
5030
- Intl: 1,
5031
- Promise: 1,
5032
- Symbol: 1,
5033
- Number: 1,
5034
- String: 1,
5035
- Boolean: 1,
5036
- Array: 1,
5037
- Object: 1,
5038
- Date: 1,
5039
- RegExp: 1,
5040
- Error: 1,
5041
- TypeError: 1,
5042
- RangeError: 1,
5043
- SyntaxError: 1,
5044
- Map: 1,
5045
- Set: 1,
5046
- WeakMap: 1,
5047
- WeakSet: 1,
5048
- Proxy: 1,
5049
- Reflect: 1,
5050
- ArrayBuffer: 1,
5051
- DataView: 1,
5052
- Float32Array: 1,
5053
- Float64Array: 1,
5054
- Int8Array: 1,
5055
- Int16Array: 1,
5056
- Int32Array: 1,
5057
- Uint8Array: 1,
5058
- Uint16Array: 1,
5059
- Uint32Array: 1,
5060
- Uint8ClampedArray: 1,
5061
- // Functions
5062
- parseInt: 1,
5063
- parseFloat: 1,
5064
- isNaN: 1,
5065
- isFinite: 1,
5066
- encodeURIComponent: 1,
5067
- decodeURIComponent: 1,
5068
- encodeURI: 1,
5069
- decodeURI: 1,
5070
- // Babel helpers
5071
- arguments: 1,
5072
- this: 1,
5073
- require: 1,
5074
- // Lark framework
5075
- Lark: 1
5076
- };
5077
- var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5078
4337
  // Annotate the CommonJS export names for ESM import in node:
5079
4338
  0 && (module.exports = {
5080
4339
  CALL_BREAK_TIME,
@@ -5102,7 +4361,6 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5102
4361
  applyVdomOps,
5103
4362
  assign,
5104
4363
  bindStore,
5105
- compileTemplate,
5106
4364
  computed,
5107
4365
  create,
5108
4366
  createVdomRef,
@@ -5113,7 +4371,6 @@ var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
5113
4371
  encodeSafe,
5114
4372
  encodeURIExtra,
5115
4373
  ensureElementId,
5116
- extractGlobalVars,
5117
4374
  frameworkConfig,
5118
4375
  funcWithTry,
5119
4376
  generateId,