@lark.js/mvc 0.0.9 → 0.0.11

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/compiler.js CHANGED
@@ -14512,7 +14512,7 @@ var require_lib = __commonJS({
14512
14512
  options = Object.assign({}, options);
14513
14513
  try {
14514
14514
  options.sourceType = "module";
14515
- const parser = getParser(options, input);
14515
+ const parser = getParser2(options, input);
14516
14516
  const ast = parser.parse();
14517
14517
  if (parser.sawUnambiguousESM) {
14518
14518
  return ast;
@@ -14520,7 +14520,7 @@ var require_lib = __commonJS({
14520
14520
  if (parser.ambiguousScriptDifferentAst) {
14521
14521
  try {
14522
14522
  options.sourceType = "script";
14523
- return getParser(options, input).parse();
14523
+ return getParser2(options, input).parse();
14524
14524
  } catch (_unused) {
14525
14525
  }
14526
14526
  } else {
@@ -14530,17 +14530,17 @@ var require_lib = __commonJS({
14530
14530
  } catch (moduleError) {
14531
14531
  try {
14532
14532
  options.sourceType = "script";
14533
- return getParser(options, input).parse();
14533
+ return getParser2(options, input).parse();
14534
14534
  } catch (_unused2) {
14535
14535
  }
14536
14536
  throw moduleError;
14537
14537
  }
14538
14538
  } else {
14539
- return getParser(options, input).parse();
14539
+ return getParser2(options, input).parse();
14540
14540
  }
14541
14541
  }
14542
14542
  function parseExpression(input, options) {
14543
- const parser = getParser(options, input);
14543
+ const parser = getParser2(options, input);
14544
14544
  if (parser.options.strictMode) {
14545
14545
  parser.state.strict = true;
14546
14546
  }
@@ -14554,7 +14554,7 @@ var require_lib = __commonJS({
14554
14554
  return tokenTypes2;
14555
14555
  }
14556
14556
  var tokTypes = generateExportedTokenTypes(tt);
14557
- function getParser(options, input) {
14557
+ function getParser2(options, input) {
14558
14558
  let cls = Parser;
14559
14559
  const pluginsMap = /* @__PURE__ */ new Map();
14560
14560
  if (options != null && options.plugins) {
@@ -14599,8 +14599,7 @@ var require_lib = __commonJS({
14599
14599
  }
14600
14600
  });
14601
14601
 
14602
- // src/compiler.ts
14603
- var import_parser = __toESM(require_lib(), 1);
14602
+ // src/compiler/template-syntax.ts
14604
14603
  var SPLITTER = String.fromCharCode(30);
14605
14604
  var VIEW_ID_PLACEHOLDER = String.fromCharCode(31);
14606
14605
  function jsObjectToUrlParams(paramsStr) {
@@ -14721,7 +14720,7 @@ function convertArtSyntax(source, debug) {
14721
14720
  }
14722
14721
  if (blockStack.length > 0) {
14723
14722
  const unclosed = blockStack.map((b) => `"${b.ctrl}" at line ${b.line}`).join(", ");
14724
- throw new Error(`[@lark.js/mvc error] unclosed block(s): ${unclosed}`);
14723
+ throw new Error(`Unclosed block(s): ${unclosed}`);
14725
14724
  }
14726
14725
  return result.join("");
14727
14726
  }
@@ -14820,7 +14819,7 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
14820
14819
  const object = tokens[0];
14821
14820
  if (tokens.length > 1 && tokens[1] !== "as") {
14822
14821
  throw new Error(
14823
- `[@lark.js/mvc error] bad forOf syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{forOf list as item [index]}}`
14822
+ `Bad forOf syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{forOf list as item [index]}}`
14824
14823
  );
14825
14824
  }
14826
14825
  const restTokens = tokens.slice(2);
@@ -14847,7 +14846,7 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
14847
14846
  const object = tokens[0];
14848
14847
  if (tokens.length > 1 && tokens[1] !== "as") {
14849
14848
  throw new Error(
14850
- `[@lark.js/mvc error] bad forIn syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{for-in obj as val [key]}}`
14849
+ `Bad forIn syntax: {{${code}}}. Expected "as" keyword, got "${tokens[1]}". Usage: {{forIn obj as val [key]}}`
14851
14850
  );
14852
14851
  }
14853
14852
  const restTokens2 = tokens.slice(2);
@@ -14873,13 +14872,11 @@ function convertArtExpression(code, debug, lineNo, blockStack = []) {
14873
14872
  const expectedCtrl = keyword.substring(1);
14874
14873
  const last = blockStack.pop();
14875
14874
  if (!last) {
14876
- throw new Error(
14877
- `[@lark.js/mvc error] unexpected {{${code}}}: no matching open block`
14878
- );
14875
+ throw new Error(`Unexpected {{${code}}}: no matching open block`);
14879
14876
  }
14880
14877
  if (last.ctrl !== expectedCtrl) {
14881
14878
  throw new Error(
14882
- `[@lark.js/mvc error] unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
14879
+ `Unexpected {{${code}}}: expected {{/${last.ctrl}}} to close block opened at line ${last.line}`
14883
14880
  );
14884
14881
  }
14885
14882
  return `${debugPrefix}<%}%>`;
@@ -14940,112 +14937,529 @@ function parseAsExpr(expr) {
14940
14937
  bad: false
14941
14938
  };
14942
14939
  }
14943
- function compileToFunction(source, debug, file) {
14944
- const matcher = /<%([@=!:])?([\s\S]*?)%>|$/g;
14945
- let index = 0;
14946
- let funcSource = `$out+='`;
14947
- let hasAtRule = false;
14948
- const escapeSlashRegExp = /\\|'/g;
14949
- const escapeBreakReturnRegExp = /\r|\n/g;
14950
- source.replace(matcher, (match, operate, content, offset) => {
14951
- funcSource += source.substring(index, offset).replace(escapeSlashRegExp, "\\$&").replace(escapeBreakReturnRegExp, "\\n");
14952
- index = offset + match.length;
14953
- if (debug) {
14954
- let expr = source.substring(
14955
- index - match.length + 2 + (operate ? 1 : 0),
14956
- index - 2
14957
- );
14958
- const x11 = String.fromCharCode(17);
14959
- const artRegExp = new RegExp(`^'(\\d+)${x11}([^${x11}]+)${x11}'$`);
14960
- const artM = expr.match(artRegExp);
14961
- let art = "";
14962
- let line = -1;
14963
- if (artM) {
14964
- expr = expr.replace(artRegExp, "");
14965
- art = artM[2];
14966
- line = parseInt(artM[1], 10);
14967
- } else {
14968
- expr = expr.replace(escapeSlashRegExp, "\\$&").replace(escapeBreakReturnRegExp, "\\n");
14940
+
14941
+ // src/compiler/compile-to-vdom-function.ts
14942
+ import { parseDocument } from "htmlparser2";
14943
+ var VOID_ELEMENTS = /* @__PURE__ */ new Set([
14944
+ "area",
14945
+ "base",
14946
+ "br",
14947
+ "col",
14948
+ "embed",
14949
+ "hr",
14950
+ "img",
14951
+ "input",
14952
+ "link",
14953
+ "meta",
14954
+ "param",
14955
+ "source",
14956
+ "track",
14957
+ "wbr"
14958
+ ]);
14959
+ function vdomEscapeStr(s) {
14960
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\x1e/g, "\\x1e");
14961
+ }
14962
+ function vdomResolveAttrValue(rawValue, exprStore) {
14963
+ const hasPlaceholders = rawValue.includes("\0");
14964
+ const hasViewId = rawValue.includes("");
14965
+ if (!hasPlaceholders && !hasViewId) {
14966
+ return `'${vdomEscapeStr(rawValue)}'`;
14967
+ }
14968
+ const segments = [];
14969
+ let remaining = rawValue;
14970
+ while (remaining.length > 0) {
14971
+ const phIdx = remaining.indexOf("\0");
14972
+ const viIdx = remaining.indexOf("");
14973
+ let nextSpecial = -1;
14974
+ let specialType = null;
14975
+ if (phIdx >= 0 && (viIdx < 0 || phIdx <= viIdx)) {
14976
+ nextSpecial = phIdx;
14977
+ specialType = "ph";
14978
+ } else if (viIdx >= 0) {
14979
+ nextSpecial = viIdx;
14980
+ specialType = "vi";
14981
+ }
14982
+ if (nextSpecial === -1) {
14983
+ if (remaining) segments.push(`'${vdomEscapeStr(remaining)}'`);
14984
+ break;
14985
+ }
14986
+ if (nextSpecial > 0) {
14987
+ segments.push(`'${vdomEscapeStr(remaining.substring(0, nextSpecial))}'`);
14988
+ }
14989
+ if (specialType === "vi") {
14990
+ segments.push("$viewId");
14991
+ remaining = remaining.substring(nextSpecial + 1);
14992
+ } else {
14993
+ const closeIdx = remaining.indexOf("\0", nextSpecial + 1);
14994
+ if (closeIdx === -1) {
14995
+ segments.push(`'${vdomEscapeStr(remaining.substring(nextSpecial))}'`);
14996
+ break;
14969
14997
  }
14970
- if (operate === "@") {
14971
- hasAtRule = true;
14972
- funcSource += `'+($dbgExpr='<%${operate + expr}%>',$refFn($refAlt,${content}))+'`;
14973
- } else if (operate === "=" || operate === ":") {
14974
- funcSource += `'+($dbgExpr='<%${operate + expr}%>',$encHtml(${content}))+'`;
14975
- } else if (operate === "!") {
14976
- if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
14977
- content = `$strSafe(${content})`;
14978
- }
14979
- funcSource += `'+($dbgExpr='<%${operate + expr}%>',${content})+'`;
14980
- } else if (content) {
14981
- if (line > -1) {
14982
- funcSource += `';$dbgLine=${line};$dbgArt='${art}';`;
14983
- content = "";
14998
+ const idx = parseInt(remaining.substring(nextSpecial + 1, closeIdx));
14999
+ const expr = exprStore[idx];
15000
+ if (expr.op === "=" || expr.op === ":") {
15001
+ segments.push(`$n(${expr.content})`);
15002
+ } else if (expr.op === "!") {
15003
+ if (expr.content.startsWith("$encUri(") && expr.content.endsWith(")")) {
15004
+ segments.push(expr.content);
14984
15005
  } else {
14985
- funcSource += `';`;
14986
- }
14987
- if (funcSource.endsWith(`+'';`)) {
14988
- funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
15006
+ segments.push(`$n(${expr.content})`);
14989
15007
  }
14990
- if (expr) {
14991
- funcSource += `$dbgExpr='<%${expr}%>';`;
14992
- }
14993
- funcSource += content + `;$out+='`;
15008
+ } else if (expr.op === "@") {
15009
+ segments.push(`$refFn($refAlt,${expr.content})`);
15010
+ } else {
15011
+ segments.push(`$n(${expr.content})`);
14994
15012
  }
14995
- } else {
14996
- if (operate === "@") {
14997
- hasAtRule = true;
14998
- funcSource += `'+$refFn($refAlt,${content})+'`;
14999
- } else if (operate === "=" || operate === ":") {
15000
- funcSource += `'+$encHtml(${content})+'`;
15001
- } else if (operate === "!") {
15002
- if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
15003
- content = `$strSafe(${content})`;
15004
- }
15005
- funcSource += `'+${content}+'`;
15006
- } else if (content) {
15007
- funcSource += `';`;
15008
- if (funcSource.endsWith(`+'';`)) {
15009
- funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
15013
+ remaining = remaining.substring(closeIdx + 1);
15014
+ }
15015
+ }
15016
+ if (segments.length === 0) return "''";
15017
+ if (segments.length === 1) return segments[0];
15018
+ return segments.join("+");
15019
+ }
15020
+ function vdomBuildPropsFromAttribs(attribs, exprStore) {
15021
+ if (!attribs) return "null";
15022
+ const keys = Object.keys(attribs);
15023
+ if (keys.length === 0) return "null";
15024
+ const entries = [];
15025
+ for (const name of keys) {
15026
+ const value = attribs[name];
15027
+ const valueExpr = vdomResolveAttrValue(value, exprStore);
15028
+ entries.push(`'${vdomEscapeStr(name)}':${valueExpr}`);
15029
+ }
15030
+ return `{${entries.join(",")}}`;
15031
+ }
15032
+ function compileToVDomFunction(source, debug, file) {
15033
+ const lines = [];
15034
+ let varCounter = 0;
15035
+ let propsCounter = 0;
15036
+ const exprStore = [];
15037
+ const protectedSource = source.replace(
15038
+ /<%([@=!:])?([\s\S]*?)%>/g,
15039
+ (_, op, content) => {
15040
+ const idx = exprStore.length;
15041
+ exprStore.push({ op: op || "", content: (content || "").trim() });
15042
+ return `\0${idx}\0`;
15043
+ }
15044
+ );
15045
+ const doc = parseDocument(protectedSource, {
15046
+ recognizeSelfClosing: true,
15047
+ lowerCaseTags: false,
15048
+ lowerCaseAttributeNames: false,
15049
+ decodeEntities: false
15050
+ });
15051
+ const rootVar = `$v${varCounter++}`;
15052
+ lines.push(`let ${rootVar}=[]`);
15053
+ const maxVars = 30;
15054
+ const varDecls = [];
15055
+ for (let i = 1; i < maxVars; i++) {
15056
+ varDecls.push(`$v${i}`);
15057
+ }
15058
+ lines.push(`let ${varDecls.join(",")}`);
15059
+ function allocVar() {
15060
+ if (varCounter >= maxVars) return `$v${maxVars - 1}`;
15061
+ return `$v${varCounter++}`;
15062
+ }
15063
+ function emitNode(node, parentVar) {
15064
+ const type = node.type;
15065
+ if (type === "text") {
15066
+ emitText(node.data || "", parentVar);
15067
+ } else if (type === "tag" || type === "script" || type === "style") {
15068
+ emitElement(node, parentVar);
15069
+ }
15070
+ }
15071
+ function emitText(text, parentVar) {
15072
+ const parts = text.split(/\x00(\d+)\x00/);
15073
+ for (let i = 0; i < parts.length; i++) {
15074
+ if (i % 2 === 0) {
15075
+ const trimmed = parts[i];
15076
+ if (trimmed.trim()) {
15077
+ lines.push(`${parentVar}.push($c(0,'${vdomEscapeStr(trimmed)}'))`);
15010
15078
  }
15011
- funcSource += `${content};$out+='`;
15079
+ } else {
15080
+ const idx = parseInt(parts[i]);
15081
+ const expr = exprStore[idx];
15082
+ emitExpr(expr, parentVar);
15012
15083
  }
15013
15084
  }
15014
- return match;
15015
- });
15016
- funcSource += `';`;
15017
- funcSource = funcSource.replace(/\$out\+='';/g, "");
15018
- funcSource = funcSource.replace(/\$out\+=''\+/g, "$out+=");
15085
+ }
15086
+ function emitExpr(expr, parentVar) {
15087
+ if (expr.op === "=" || expr.op === ":") {
15088
+ lines.push(`${parentVar}.push($c(0,$n(${expr.content})))`);
15089
+ } else if (expr.op === "!") {
15090
+ if (expr.content.startsWith("$encUri(") && expr.content.endsWith(")")) {
15091
+ lines.push(`${parentVar}.push($c(0,${expr.content}))`);
15092
+ } else {
15093
+ lines.push(`${parentVar}.push($c(0,$n(${expr.content})))`);
15094
+ }
15095
+ } else if (expr.op === "@") {
15096
+ lines.push(`${parentVar}.push($c(0,$refFn($refAlt,${expr.content})))`);
15097
+ } else if (expr.content) {
15098
+ lines.push(expr.content);
15099
+ }
15100
+ }
15101
+ function emitElement(node, parentVar) {
15102
+ const tagName = node.name || "";
15103
+ const children = node.children || [];
15104
+ const childVar = allocVar();
15105
+ const propsKey = `__p${propsCounter++}`;
15106
+ const props = vdomBuildPropsFromAttribs(node.attribs, exprStore);
15107
+ lines.push(`let ${propsKey}=${props}`);
15108
+ lines.push(`${childVar}=[]`);
15109
+ for (const child of children) {
15110
+ emitNode(child, childVar);
15111
+ }
15112
+ const isVoid = VOID_ELEMENTS.has(tagName) && children.length === 0;
15113
+ const childrenArg = isVoid ? "1" : childVar;
15114
+ lines.push(
15115
+ `${parentVar}.push($c('${tagName}',${propsKey},${childrenArg}))`
15116
+ );
15117
+ }
15118
+ for (const child of doc.children) {
15119
+ emitNode(child, rootVar);
15120
+ }
15121
+ lines.push(`return $c($viewId,0,${rootVar})`);
15122
+ const body = lines.join(";");
15123
+ let funcBody = body;
15019
15124
  if (debug) {
15020
15125
  const filePart = file ? `\\r\\n\\tat file:${file}` : "";
15021
- 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;}`;
15126
+ funcBody = `let $dbgExpr,$dbgArt,$dbgLine;try{${body}}catch(ex){let msg='render view error:'+(ex.message||ex);msg+='${filePart}';throw msg;}`;
15022
15127
  }
15023
15128
  const viewIdRegExp = new RegExp(String.fromCharCode(31), "g");
15024
- funcSource = funcSource.replace(viewIdRegExp, `'+$viewId+'`);
15025
- void hasAtRule;
15129
+ funcBody = funcBody.replace(viewIdRegExp, `'+$viewId+'`);
15026
15130
  const refFallback = "if(!$refAlt)$refAlt=$data;";
15027
- const fullSource = `${refFallback}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
15028
- return `($data,$viewId,$refAlt,$encHtml,$strSafe,$encUri,$refFn,$encQuote)=>{${fullSource}}`;
15131
+ const fullSource = `${refFallback}let $splitter='\\x1e'{{VARS}};${funcBody}`;
15132
+ return `($data,$viewId,$refAlt,$n,$refFn,$encUri,$encQuote)=>{${fullSource}}`;
15029
15133
  }
15030
- function compileTemplate(source, options = {}) {
15031
- const { debug = false, globalVars = [], file } = options;
15032
- const { protectedSource, comments } = protectComments(source);
15033
- const converted = convertArtSyntax(protectedSource, debug);
15034
- const viewEventProcessed = processViewEvents(converted);
15035
- const finalSource = restoreComments(viewEventProcessed, comments);
15036
- const funcBody = compileToFunction(finalSource, debug, file);
15037
- const varDeclarations = globalVars.map((key) => `,${key}=$data.${key}`).join("");
15038
- const funcWithVars = funcBody.replace("{{VARS}}", () => varDeclarations);
15039
- return `import { encHtml as __larkEncHtml, strSafe as __larkStrSafe, encUri as __larkEncUri, encQuote as __larkEncQuote, refFn as __larkRefFn } from "@lark.js/mvc/runtime";
15040
- export default function(data, viewId, refData) {
15041
- let $data = data || {},
15042
- $viewId = viewId || '';
15043
- return (${funcWithVars})($data, $viewId, refData,
15044
- __larkEncHtml, __larkStrSafe, __larkEncUri, __larkRefFn, __larkEncQuote
15134
+
15135
+ // src/compiler/swc/extract-global-vars.ts
15136
+ var parseSyncFn = null;
15137
+ var parseSyncLoadAttempted = false;
15138
+ async function getParser() {
15139
+ if (!parseSyncLoadAttempted) {
15140
+ parseSyncLoadAttempted = true;
15141
+ try {
15142
+ const swc = await import("@swc/core");
15143
+ parseSyncFn = swc.parseSync;
15144
+ } catch (err) {
15145
+ console.error("failed to load @swc/core", err);
15146
+ }
15147
+ }
15148
+ return parseSyncFn;
15149
+ }
15150
+ async function extractGlobalVars(source) {
15151
+ const { protectedSource, comments: _comments } = protectComments(source);
15152
+ const viewEventProcessed = processViewEvents(protectedSource);
15153
+ const converted = convertArtSyntax(viewEventProcessed, false);
15154
+ const template = restoreComments(converted, _comments);
15155
+ const templateCmdRegExp = /<%([@=!:])?([\s\S]*?)%>|$/g;
15156
+ const fnParts = [];
15157
+ const htmlStore = {};
15158
+ let htmlIndex = 0;
15159
+ let lastIndex = 0;
15160
+ const htmlKey = String.fromCharCode(5);
15161
+ template.replace(
15162
+ templateCmdRegExp,
15163
+ (match, operate, content, offset) => {
15164
+ const start = operate ? 3 : 2;
15165
+ const htmlText = template.substring(lastIndex, offset + start);
15166
+ const key = htmlKey + htmlIndex++ + htmlKey;
15167
+ htmlStore[key] = htmlText;
15168
+ lastIndex = offset + match.length - 2;
15169
+ if (operate && content.trim()) {
15170
+ fnParts.push(';"' + key + '";', "[" + content + "]");
15171
+ } else {
15172
+ fnParts.push(';"' + key + '";', content || "");
15173
+ }
15174
+ return match;
15175
+ }
15045
15176
  );
15046
- }`;
15177
+ let fn = fnParts.join("");
15178
+ fn = `(function(){${fn}})`;
15179
+ const parseSync = await getParser();
15180
+ if (!parseSync) {
15181
+ return fallbackExtractVariables(source);
15182
+ }
15183
+ let ast;
15184
+ try {
15185
+ ast = parseSync(fn, {
15186
+ syntax: "ecmascript",
15187
+ target: "es2022"
15188
+ });
15189
+ } catch {
15190
+ return fallbackExtractVariables(source);
15191
+ }
15192
+ const globalExists = {};
15193
+ for (const name of BUILTIN_GLOBALS) globalExists[name] = 1;
15194
+ const globalVars = /* @__PURE__ */ Object.create(null);
15195
+ const fnNodes = [];
15196
+ walkSwcAst(ast, {
15197
+ VariableDeclarator(node) {
15198
+ if (node.id.type === "Identifier") {
15199
+ const name = node.id.value;
15200
+ globalExists[name] = node.init ? 3 : 2;
15201
+ }
15202
+ },
15203
+ FunctionDeclaration(node) {
15204
+ if (node.identifier) {
15205
+ globalExists[node.identifier.value] = 3;
15206
+ }
15207
+ fnNodes.push(node);
15208
+ },
15209
+ FunctionExpression(node) {
15210
+ fnNodes.push(node);
15211
+ },
15212
+ ArrowFunctionExpression(node) {
15213
+ fnNodes.push(node);
15214
+ },
15215
+ CallExpression(node) {
15216
+ if (node.callee.type === "Identifier") {
15217
+ globalExists[node.callee.value] = 1;
15218
+ }
15219
+ }
15220
+ });
15221
+ const functionParams = /* @__PURE__ */ Object.create(null);
15222
+ for (const fnNode of fnNodes) {
15223
+ const patterns = getParamPatterns(fnNode);
15224
+ for (const pat of patterns) {
15225
+ if (pat.type === "Identifier") {
15226
+ functionParams[pat.value] = 1;
15227
+ } else if (pat.type === "AssignmentPattern" && pat.left.type === "Identifier") {
15228
+ functionParams[pat.left.value] = 1;
15229
+ } else if (pat.type === "RestElement" && pat.argument.type === "Identifier") {
15230
+ functionParams[pat.argument.value] = 1;
15231
+ }
15232
+ }
15233
+ }
15234
+ walkSwcAst(ast, {
15235
+ Identifier(node) {
15236
+ const name = node.value;
15237
+ if (globalExists[name]) return;
15238
+ if (functionParams[name]) return;
15239
+ globalVars[name] = 1;
15240
+ },
15241
+ AssignmentExpression(node) {
15242
+ if (node.left.type === "Identifier") {
15243
+ const name = node.left.value;
15244
+ if (!globalExists[name] || globalExists[name] === 1) {
15245
+ globalExists[name] = (globalExists[name] || 0) + 1;
15246
+ }
15247
+ }
15248
+ }
15249
+ });
15250
+ return Object.keys(globalVars);
15047
15251
  }
15048
- function extractGlobalVars(source) {
15252
+ function getParamPatterns(fnNode) {
15253
+ if (fnNode.type === "ArrowFunctionExpression") {
15254
+ return fnNode.params;
15255
+ }
15256
+ return fnNode.params.map((p) => p.pat);
15257
+ }
15258
+ function fallbackExtractVariables(source) {
15259
+ const vars = /* @__PURE__ */ new Set();
15260
+ const outputRegExp = /\{\{[:=!@]\s*([a-zA-Z_$][\w$]*)[^}]*\}\}/g;
15261
+ let m;
15262
+ while ((m = outputRegExp.exec(source)) !== null) {
15263
+ vars.add(m[1]);
15264
+ }
15265
+ const eachRegExp = /\{\{forOf\s+([a-zA-Z_$][\w$]*)\s+as/g;
15266
+ while ((m = eachRegExp.exec(source)) !== null) {
15267
+ vars.add(m[1]);
15268
+ }
15269
+ const ifRegExp = /\{\{(?:else\s+)?if\s+([a-zA-Z_$][\w$]*)[^}]*\}\}/g;
15270
+ while ((m = ifRegExp.exec(source)) !== null) {
15271
+ vars.add(m[1]);
15272
+ }
15273
+ return Array.from(vars).filter((v) => !BUILTIN_GLOBALS.has(v));
15274
+ }
15275
+ function walkSwcAst(ast, visitors) {
15276
+ function visit(node) {
15277
+ const type = node.type;
15278
+ if (visitors[type]) {
15279
+ visitors[type](node);
15280
+ }
15281
+ for (const key of Object.keys(node)) {
15282
+ if (key === "type" || key === "span" || key === "ctxt") continue;
15283
+ if (type === "MemberExpression" && key === "property") {
15284
+ const me = node;
15285
+ if (me.property.type !== "Computed") continue;
15286
+ }
15287
+ if (type === "KeyValueProperty" && key === "key") {
15288
+ const kv = node;
15289
+ if (kv.key.type !== "Computed") continue;
15290
+ }
15291
+ if (type === "MethodProperty" && key === "key") {
15292
+ const mp = node;
15293
+ if (mp.key.type !== "Computed") continue;
15294
+ }
15295
+ const child = Reflect.get(node, key);
15296
+ if (Array.isArray(child)) {
15297
+ for (const item of child) {
15298
+ if (isSwcNode(item)) visit(item);
15299
+ }
15300
+ } else if (isSwcNode(child)) {
15301
+ visit(child);
15302
+ }
15303
+ }
15304
+ }
15305
+ visit(ast);
15306
+ }
15307
+ function isSwcNode(v) {
15308
+ return !!v && typeof v === "object" && typeof v.type === "string";
15309
+ }
15310
+ var BUILTIN_GLOBALS = /* @__PURE__ */ new Set([
15311
+ // ─── Template runtime helpers (injected by compileToFunction) ───────
15312
+ //
15313
+ // These variables appear in the generated template function signature
15314
+ // or body. They must be excluded from extractGlobalVars() so that
15315
+ // they are not mistaken for user data variables and destructured from $data.
15316
+ // SPLITTER character constant (same as \x1e), used as namespace separator
15317
+ // for refData keys, event attribute encoding, and internal data structures.
15318
+ // Declared as: let $splitter='\x1e'
15319
+ "$splitter",
15320
+ // Data — the data object passed from Updater to the template function.
15321
+ // User variables are destructured from $data at the top of the function:
15322
+ // let {name, age} = $data;
15323
+ // This is the first parameter of the generated arrow function.
15324
+ "$data",
15325
+ // Null-safe toString: v => '' + (v == null ? '' : v)
15326
+ // Converts null/undefined to empty string, otherwise calls toString().
15327
+ // Wraps every {{!raw}} output to prevent "null" / "undefined" rendering.
15328
+ "$strSafe",
15329
+ // HTML entity encoder: v => $strSafe(v).replace(/[&<>"'`]/g, entityMap)
15330
+ // Encodes &, <, >, ", ', ` to HTML entities (&amp; &lt; etc.)
15331
+ // Applied to all {{=escaped}} and {{:binding}} outputs.
15332
+ "$encHtml",
15333
+ // HTML entity map — internal object used by $encHtml:
15334
+ // {'&':'amp','<':'gt','>':'gt','"':'#34','\'':'#39','`':'#96'}
15335
+ // Not a standalone function; referenced inside $encHtml's closure.
15336
+ "$entMap",
15337
+ // HTML entity RegExp — internal regexp used by $encHtml:
15338
+ // /[&<>"'`]/g
15339
+ "$entReg",
15340
+ // HTML entity replacer function — internal helper used by $encHtml:
15341
+ // m => '&' + $entMap[m] + ';'
15342
+ // Maps matched character to its entity string.
15343
+ "$entFn",
15344
+ // Output buffer — the string accumulator for rendered HTML.
15345
+ // All template output is appended via $out += '...'.
15346
+ // Declared as: let $out = ''
15347
+ "$out",
15348
+ // Reference lookup: (refData, value) => key
15349
+ // Finds or allocates a SPLITTER-prefixed key in refData for a given
15350
+ // object reference. Used by {{@ref}} operator for passing object
15351
+ // references to child views via v-lark attributes.
15352
+ "$refFn",
15353
+ // URI encoder: v => encodeURIComponent($strSafe(v)).replace(/[!')(*]/g, extraMap)
15354
+ // Extends encodeURIComponent with encoding of ! ' ( ) *.
15355
+ // Applied to values in @event URL parameters and {{!uri}} contexts.
15356
+ "$encUri",
15357
+ // URI encode map — internal object used by $encUri:
15358
+ // {'!':'%21','\'':'%27','(':'%28',')':'%29','*':'%2A'}
15359
+ "$uriMap",
15360
+ // URI encode replacer — internal helper used by $encUri:
15361
+ // m => $uriMap[m]
15362
+ "$uriFn",
15363
+ // URI encode regexp — internal regexp used by $encUri:
15364
+ // /[!')(*]/g
15365
+ "$uriReg",
15366
+ // Quote encoder: v => $strSafe(v).replace(/['"\\]/g, '\\$&')
15367
+ // Escapes quotes and backslashes for safe embedding in HTML attribute
15368
+ // values (e.g. data-json='...').
15369
+ "$encQuote",
15370
+ // Quote encode regexp — internal regexp used by $encQuote:
15371
+ // /['"\\]/g
15372
+ "$qReg",
15373
+ // View ID — the unique identifier of the owning View instance.
15374
+ // Injected into @event attribute values at render time so that
15375
+ // EventDelegator can dispatch events to the correct View handler.
15376
+ // The \x1f placeholder in compiled output is replaced with '+$viewId+'.
15377
+ "$viewId",
15378
+ // Debug: current expression text — stores the template expression being
15379
+ // evaluated, for error reporting. Only present in debug mode.
15380
+ // e.g. $dbgExpr='<%=user.name%>'
15381
+ "$dbgExpr",
15382
+ // Debug: original art syntax — stores the {{}} template syntax before
15383
+ // conversion, for error reporting. Only present in debug mode.
15384
+ // e.g. $dbgArt='{{=user.name}}'
15385
+ "$dbgArt",
15386
+ // Debug: source line number — tracks the current line in the template
15387
+ // source, for error reporting. Only present in debug mode.
15388
+ "$dbgLine",
15389
+ // RefData alias — fallback reference lookup table.
15390
+ // Defaults to $data when no explicit $refAlt is provided.
15391
+ // Ensures $refFn() does not crash when @ operator is used without refData.
15392
+ "$refAlt",
15393
+ // Temporary variable — used by the compiler for intermediate
15394
+ // expression results in generated code (e.g. loop variables,
15395
+ // conditional branches). Declared as: let $tmp
15396
+ "$tmp",
15397
+ // JS literals
15398
+ "undefined",
15399
+ "null",
15400
+ "true",
15401
+ "false",
15402
+ "NaN",
15403
+ "Infinity",
15404
+ // JS built-in globals
15405
+ "window",
15406
+ "self",
15407
+ "globalThis",
15408
+ "document",
15409
+ "console",
15410
+ "JSON",
15411
+ "Math",
15412
+ "Intl",
15413
+ "Promise",
15414
+ "Symbol",
15415
+ "Number",
15416
+ "String",
15417
+ "Boolean",
15418
+ "Array",
15419
+ "Object",
15420
+ "Date",
15421
+ "RegExp",
15422
+ "Error",
15423
+ "TypeError",
15424
+ "RangeError",
15425
+ "SyntaxError",
15426
+ "Map",
15427
+ "Set",
15428
+ "WeakMap",
15429
+ "WeakSet",
15430
+ "Proxy",
15431
+ "Reflect",
15432
+ "ArrayBuffer",
15433
+ "DataView",
15434
+ "Float32Array",
15435
+ "Float64Array",
15436
+ "Int8Array",
15437
+ "Int16Array",
15438
+ "Int32Array",
15439
+ "Uint8Array",
15440
+ "Uint16Array",
15441
+ "Uint32Array",
15442
+ "Uint8ClampedArray",
15443
+ // Functions
15444
+ "parseInt",
15445
+ "parseFloat",
15446
+ "isNaN",
15447
+ "isFinite",
15448
+ "encodeURIComponent",
15449
+ "decodeURIComponent",
15450
+ "encodeURI",
15451
+ "decodeURI",
15452
+ // SWC helpers
15453
+ "arguments",
15454
+ "this",
15455
+ "require",
15456
+ // Lark framework
15457
+ "Lark"
15458
+ ]);
15459
+
15460
+ // src/compiler/extract-global-vars.ts
15461
+ var import_parser = __toESM(require_lib(), 1);
15462
+ async function extractGlobalVars2(source) {
15049
15463
  const { protectedSource, comments: _comments } = protectComments(source);
15050
15464
  const viewEventProcessed = processViewEvents(protectedSource);
15051
15465
  const converted = convertArtSyntax(viewEventProcessed, false);
@@ -15082,9 +15496,10 @@ function extractGlobalVars(source) {
15082
15496
  allowAwaitOutsideFunction: true
15083
15497
  });
15084
15498
  } catch {
15085
- return fallbackExtractVariables(source);
15499
+ return fallbackExtractVariables2(source);
15086
15500
  }
15087
- const globalExists = { ...BUILTIN_GLOBALS };
15501
+ const globalExists = {};
15502
+ for (const name of BUILTIN_GLOBALS2) globalExists[name] = 1;
15088
15503
  const globalVars = /* @__PURE__ */ Object.create(null);
15089
15504
  const fnRange = [];
15090
15505
  walkAst(ast, {
@@ -15143,7 +15558,7 @@ function extractGlobalVars(source) {
15143
15558
  });
15144
15559
  return Object.keys(globalVars);
15145
15560
  }
15146
- function fallbackExtractVariables(source) {
15561
+ function fallbackExtractVariables2(source) {
15147
15562
  const vars = /* @__PURE__ */ new Set();
15148
15563
  const outputRegExp = /\{\{[:=!@]\s*([a-zA-Z_$][\w$]*)[^}]*\}\}/g;
15149
15564
  let m;
@@ -15158,7 +15573,7 @@ function fallbackExtractVariables(source) {
15158
15573
  while ((m = ifRegExp.exec(source)) !== null) {
15159
15574
  vars.add(m[1]);
15160
15575
  }
15161
- return Array.from(vars).filter((v) => !BUILTIN_GLOBAL_SET.has(v));
15576
+ return Array.from(vars).filter((v) => !BUILTIN_GLOBALS2.has(v));
15162
15577
  }
15163
15578
  function walkAst(ast, visitors) {
15164
15579
  function visit(node) {
@@ -15166,7 +15581,6 @@ function walkAst(ast, visitors) {
15166
15581
  if (visitors[type]) {
15167
15582
  visitors[type](node);
15168
15583
  }
15169
- const bag = node;
15170
15584
  for (const key of Object.keys(node)) {
15171
15585
  if (key === "type" || key === "start" || key === "end" || key === "loc" || key === "range")
15172
15586
  continue;
@@ -15182,7 +15596,7 @@ function walkAst(ast, visitors) {
15182
15596
  const om = node;
15183
15597
  if (!om.computed) continue;
15184
15598
  }
15185
- const child = bag[key];
15599
+ const child = Reflect.get(node, key);
15186
15600
  if (Array.isArray(child)) {
15187
15601
  for (const item of child) {
15188
15602
  if (isAstNode(item)) visit(item);
@@ -15197,7 +15611,7 @@ function walkAst(ast, visitors) {
15197
15611
  function isAstNode(v) {
15198
15612
  return !!v && typeof v === "object" && typeof v.type === "string";
15199
15613
  }
15200
- var BUILTIN_GLOBALS = {
15614
+ var BUILTIN_GLOBALS2 = /* @__PURE__ */ new Set([
15201
15615
  // ─── Template runtime helpers (injected by compileToFunction) ───────
15202
15616
  //
15203
15617
  // These variables appear in the generated template function signature
@@ -15206,148 +15620,271 @@ var BUILTIN_GLOBALS = {
15206
15620
  // SPLITTER character constant (same as \x1e), used as namespace separator
15207
15621
  // for refData keys, event attribute encoding, and internal data structures.
15208
15622
  // Declared as: let $splitter='\x1e'
15209
- $splitter: 1,
15623
+ "$splitter",
15210
15624
  // Data — the data object passed from Updater to the template function.
15211
15625
  // User variables are destructured from $data at the top of the function:
15212
15626
  // let {name, age} = $data;
15213
15627
  // This is the first parameter of the generated arrow function.
15214
- $data: 1,
15628
+ "$data",
15215
15629
  // Null-safe toString: v => '' + (v == null ? '' : v)
15216
15630
  // Converts null/undefined to empty string, otherwise calls toString().
15217
15631
  // Wraps every {{!raw}} output to prevent "null" / "undefined" rendering.
15218
- $strSafe: 1,
15632
+ "$strSafe",
15219
15633
  // HTML entity encoder: v => $strSafe(v).replace(/[&<>"'`]/g, entityMap)
15220
15634
  // Encodes &, <, >, ", ', ` to HTML entities (&amp; &lt; etc.)
15221
15635
  // Applied to all {{=escaped}} and {{:binding}} outputs.
15222
- $encHtml: 1,
15636
+ "$encHtml",
15223
15637
  // HTML entity map — internal object used by $encHtml:
15224
15638
  // {'&':'amp','<':'gt','>':'gt','"':'#34','\'':'#39','`':'#96'}
15225
15639
  // Not a standalone function; referenced inside $encHtml's closure.
15226
- $entMap: 1,
15640
+ "$entMap",
15227
15641
  // HTML entity RegExp — internal regexp used by $encHtml:
15228
15642
  // /[&<>"'`]/g
15229
- $entReg: 1,
15643
+ "$entReg",
15230
15644
  // HTML entity replacer function — internal helper used by $encHtml:
15231
15645
  // m => '&' + $entMap[m] + ';'
15232
15646
  // Maps matched character to its entity string.
15233
- $entFn: 1,
15647
+ "$entFn",
15234
15648
  // Output buffer — the string accumulator for rendered HTML.
15235
15649
  // All template output is appended via $out += '...'.
15236
15650
  // Declared as: let $out = ''
15237
- $out: 1,
15651
+ "$out",
15238
15652
  // Reference lookup: (refData, value) => key
15239
15653
  // Finds or allocates a SPLITTER-prefixed key in refData for a given
15240
15654
  // object reference. Used by {{@ref}} operator for passing object
15241
15655
  // references to child views via v-lark attributes.
15242
- $refFn: 1,
15656
+ "$refFn",
15243
15657
  // URI encoder: v => encodeURIComponent($strSafe(v)).replace(/[!')(*]/g, extraMap)
15244
15658
  // Extends encodeURIComponent with encoding of ! ' ( ) *.
15245
15659
  // Applied to values in @event URL parameters and {{!uri}} contexts.
15246
- $encUri: 1,
15660
+ "$encUri",
15247
15661
  // URI encode map — internal object used by $encUri:
15248
15662
  // {'!':'%21','\'':'%27','(':'%28',')':'%29','*':'%2A'}
15249
- $uriMap: 1,
15663
+ "$uriMap",
15250
15664
  // URI encode replacer — internal helper used by $encUri:
15251
15665
  // m => $uriMap[m]
15252
- $uriFn: 1,
15666
+ "$uriFn",
15253
15667
  // URI encode regexp — internal regexp used by $encUri:
15254
15668
  // /[!')(*]/g
15255
- $uriReg: 1,
15669
+ "$uriReg",
15256
15670
  // Quote encoder: v => $strSafe(v).replace(/['"\\]/g, '\\$&')
15257
15671
  // Escapes quotes and backslashes for safe embedding in HTML attribute
15258
15672
  // values (e.g. data-json='...').
15259
- $encQuote: 1,
15673
+ "$encQuote",
15260
15674
  // Quote encode regexp — internal regexp used by $encQuote:
15261
15675
  // /['"\\]/g
15262
- $qReg: 1,
15676
+ "$qReg",
15263
15677
  // View ID — the unique identifier of the owning View instance.
15264
15678
  // Injected into @event attribute values at render time so that
15265
15679
  // EventDelegator can dispatch events to the correct View handler.
15266
15680
  // The \x1f placeholder in compiled output is replaced with '+$viewId+'.
15267
- $viewId: 1,
15681
+ "$viewId",
15268
15682
  // Debug: current expression text — stores the template expression being
15269
15683
  // evaluated, for error reporting. Only present in debug mode.
15270
15684
  // e.g. $dbgExpr='<%=user.name%>'
15271
- $dbgExpr: 1,
15685
+ "$dbgExpr",
15272
15686
  // Debug: original art syntax — stores the {{}} template syntax before
15273
15687
  // conversion, for error reporting. Only present in debug mode.
15274
15688
  // e.g. $dbgArt='{{=user.name}}'
15275
- $dbgArt: 1,
15689
+ "$dbgArt",
15276
15690
  // Debug: source line number — tracks the current line in the template
15277
15691
  // source, for error reporting. Only present in debug mode.
15278
- $dbgLine: 1,
15692
+ "$dbgLine",
15279
15693
  // RefData alias — fallback reference lookup table.
15280
15694
  // Defaults to $data when no explicit $refAlt is provided.
15281
15695
  // Ensures $refFn() does not crash when @ operator is used without refData.
15282
- $refAlt: 1,
15696
+ "$refAlt",
15283
15697
  // Temporary variable — used by the compiler for intermediate
15284
15698
  // expression results in generated code (e.g. loop variables,
15285
15699
  // conditional branches). Declared as: let $tmp
15286
- $tmp: 1,
15700
+ "$tmp",
15287
15701
  // JS literals
15288
- undefined: 1,
15289
- null: 1,
15290
- true: 1,
15291
- false: 1,
15292
- NaN: 1,
15293
- Infinity: 1,
15702
+ "undefined",
15703
+ "null",
15704
+ "true",
15705
+ "false",
15706
+ "NaN",
15707
+ "Infinity",
15294
15708
  // JS built-in globals
15295
- window: 1,
15296
- self: 1,
15297
- globalThis: 1,
15298
- document: 1,
15299
- console: 1,
15300
- JSON: 1,
15301
- Math: 1,
15302
- Intl: 1,
15303
- Promise: 1,
15304
- Symbol: 1,
15305
- Number: 1,
15306
- String: 1,
15307
- Boolean: 1,
15308
- Array: 1,
15309
- Object: 1,
15310
- Date: 1,
15311
- RegExp: 1,
15312
- Error: 1,
15313
- TypeError: 1,
15314
- RangeError: 1,
15315
- SyntaxError: 1,
15316
- Map: 1,
15317
- Set: 1,
15318
- WeakMap: 1,
15319
- WeakSet: 1,
15320
- Proxy: 1,
15321
- Reflect: 1,
15322
- ArrayBuffer: 1,
15323
- DataView: 1,
15324
- Float32Array: 1,
15325
- Float64Array: 1,
15326
- Int8Array: 1,
15327
- Int16Array: 1,
15328
- Int32Array: 1,
15329
- Uint8Array: 1,
15330
- Uint16Array: 1,
15331
- Uint32Array: 1,
15332
- Uint8ClampedArray: 1,
15709
+ "window",
15710
+ "self",
15711
+ "globalThis",
15712
+ "document",
15713
+ "console",
15714
+ "JSON",
15715
+ "Math",
15716
+ "Intl",
15717
+ "Promise",
15718
+ "Symbol",
15719
+ "Number",
15720
+ "String",
15721
+ "Boolean",
15722
+ "Array",
15723
+ "Object",
15724
+ "Date",
15725
+ "RegExp",
15726
+ "Error",
15727
+ "TypeError",
15728
+ "RangeError",
15729
+ "SyntaxError",
15730
+ "Map",
15731
+ "Set",
15732
+ "WeakMap",
15733
+ "WeakSet",
15734
+ "Proxy",
15735
+ "Reflect",
15736
+ "ArrayBuffer",
15737
+ "DataView",
15738
+ "Float32Array",
15739
+ "Float64Array",
15740
+ "Int8Array",
15741
+ "Int16Array",
15742
+ "Int32Array",
15743
+ "Uint8Array",
15744
+ "Uint16Array",
15745
+ "Uint32Array",
15746
+ "Uint8ClampedArray",
15333
15747
  // Functions
15334
- parseInt: 1,
15335
- parseFloat: 1,
15336
- isNaN: 1,
15337
- isFinite: 1,
15338
- encodeURIComponent: 1,
15339
- decodeURIComponent: 1,
15340
- encodeURI: 1,
15341
- decodeURI: 1,
15748
+ "parseInt",
15749
+ "parseFloat",
15750
+ "isNaN",
15751
+ "isFinite",
15752
+ "encodeURIComponent",
15753
+ "decodeURIComponent",
15754
+ "encodeURI",
15755
+ "decodeURI",
15342
15756
  // Babel helpers
15343
- arguments: 1,
15344
- this: 1,
15345
- require: 1,
15757
+ "arguments",
15758
+ "this",
15759
+ "require",
15346
15760
  // Lark framework
15347
- Lark: 1
15348
- };
15349
- var BUILTIN_GLOBAL_SET = new Set(Object.keys(BUILTIN_GLOBALS));
15761
+ "Lark"
15762
+ ]);
15763
+
15764
+ // src/compiler/compile-template.ts
15765
+ function compileToFunction(source, debug, file) {
15766
+ const matcher = /<%([@=!:])?([\s\S]*?)%>|$/g;
15767
+ let index = 0;
15768
+ let funcSource = `$out+='`;
15769
+ let hasAtRule = false;
15770
+ const escapeSlashRegExp = /\\|'/g;
15771
+ const escapeBreakReturnRegExp = /\r|\n/g;
15772
+ source.replace(matcher, (match, operate, content, offset) => {
15773
+ funcSource += source.substring(index, offset).replace(escapeSlashRegExp, "\\$&").replace(escapeBreakReturnRegExp, "\\n");
15774
+ index = offset + match.length;
15775
+ if (debug) {
15776
+ let expr = source.substring(
15777
+ index - match.length + 2 + (operate ? 1 : 0),
15778
+ index - 2
15779
+ );
15780
+ const x11 = String.fromCharCode(17);
15781
+ const artRegExp = new RegExp(`^'(\\d+)${x11}([^${x11}]+)${x11}'$`);
15782
+ const artM = expr.match(artRegExp);
15783
+ let art = "";
15784
+ let line = -1;
15785
+ if (artM) {
15786
+ expr = expr.replace(artRegExp, "");
15787
+ art = artM[2];
15788
+ line = parseInt(artM[1], 10);
15789
+ } else {
15790
+ expr = expr.replace(escapeSlashRegExp, "\\$&").replace(escapeBreakReturnRegExp, "\\n");
15791
+ }
15792
+ if (operate === "@") {
15793
+ hasAtRule = true;
15794
+ funcSource += `'+($dbgExpr='<%${operate + expr}%>',$refFn($refAlt,${content}))+'`;
15795
+ } else if (operate === "=" || operate === ":") {
15796
+ funcSource += `'+($dbgExpr='<%${operate + expr}%>',$encHtml(${content}))+'`;
15797
+ } else if (operate === "!") {
15798
+ if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
15799
+ content = `$strSafe(${content})`;
15800
+ }
15801
+ funcSource += `'+($dbgExpr='<%${operate + expr}%>',${content})+'`;
15802
+ } else if (content) {
15803
+ if (line > -1) {
15804
+ funcSource += `';$dbgLine=${line};$dbgArt='${art}';`;
15805
+ content = "";
15806
+ } else {
15807
+ funcSource += `';`;
15808
+ }
15809
+ if (funcSource.endsWith(`+'';`)) {
15810
+ funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
15811
+ }
15812
+ if (expr) {
15813
+ funcSource += `$dbgExpr='<%${expr}%>';`;
15814
+ }
15815
+ funcSource += content + `;$out+='`;
15816
+ }
15817
+ } else {
15818
+ if (operate === "@") {
15819
+ hasAtRule = true;
15820
+ funcSource += `'+$refFn($refAlt,${content})+'`;
15821
+ } else if (operate === "=" || operate === ":") {
15822
+ funcSource += `'+$encHtml(${content})+'`;
15823
+ } else if (operate === "!") {
15824
+ if (!content.startsWith("$encUri(") || !content.endsWith(")")) {
15825
+ content = `$strSafe(${content})`;
15826
+ }
15827
+ funcSource += `'+${content}+'`;
15828
+ } else if (content) {
15829
+ funcSource += `';`;
15830
+ if (funcSource.endsWith(`+'';`)) {
15831
+ funcSource = funcSource.substring(0, funcSource.length - 4) + ";";
15832
+ }
15833
+ funcSource += `${content};$out+='`;
15834
+ }
15835
+ }
15836
+ return match;
15837
+ });
15838
+ funcSource += `';`;
15839
+ funcSource = funcSource.replace(/\$out\+='';/g, "");
15840
+ funcSource = funcSource.replace(/\$out\+=''\+/g, "$out+=");
15841
+ if (debug) {
15842
+ const filePart = file ? `\\r\\n\\tat file:${file}` : "";
15843
+ 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;}`;
15844
+ }
15845
+ const viewIdRegExp = new RegExp(String.fromCharCode(31), "g");
15846
+ funcSource = funcSource.replace(viewIdRegExp, `'+$viewId+'`);
15847
+ void hasAtRule;
15848
+ const refFallback = "if(!$refAlt)$refAlt=$data;";
15849
+ const fullSource = `${refFallback}let $splitter='\\x1e',$tmp,$out=''{{VARS}};${funcSource}return $out`;
15850
+ return `($data,$viewId,$refAlt,$encHtml,$strSafe,$encUri,$refFn,$encQuote)=>{${fullSource}}`;
15851
+ }
15852
+ async function compileTemplate(source, options = {}) {
15853
+ const { debug = false, file, virtualDom = false, useSwc = false } = options;
15854
+ const globalVars = options.globalVars ?? await (useSwc ? extractGlobalVars(source) : extractGlobalVars2(source));
15855
+ const { protectedSource, comments } = protectComments(source);
15856
+ const converted = convertArtSyntax(protectedSource, debug);
15857
+ const viewEventProcessed = processViewEvents(converted);
15858
+ const finalSource = restoreComments(viewEventProcessed, comments);
15859
+ const varDeclarations = globalVars.map((key) => `,${key}=$data.${key}`).join("");
15860
+ if (virtualDom) {
15861
+ const funcBody2 = compileToVDomFunction(finalSource, debug, file);
15862
+ const funcWithVars2 = funcBody2.replace("{{VARS}}", () => varDeclarations);
15863
+ return `import { vdomCreate as __larkC } from "@lark.js/mvc";
15864
+ import { strSafe as __larkStrSafe, encUri as __larkEncUri, encQuote as __larkEncQuote, refFn as __larkRefFn } from "@lark.js/mvc/runtime";
15865
+ export default function(data, viewId, refData) {
15866
+ let $data = data || {},
15867
+ $viewId = viewId || '',
15868
+ $c = __larkC,
15869
+ $n = __larkStrSafe;
15870
+ return (${funcWithVars2})($data, $viewId, refData,
15871
+ $n, __larkRefFn, __larkEncUri, __larkEncQuote
15872
+ );
15873
+ }`;
15874
+ }
15875
+ const funcBody = compileToFunction(finalSource, debug, file);
15876
+ const funcWithVars = funcBody.replace("{{VARS}}", () => varDeclarations);
15877
+ return `import { encHtml as __larkEncHtml, strSafe as __larkStrSafe, encUri as __larkEncUri, encQuote as __larkEncQuote, refFn as __larkRefFn } from "@lark.js/mvc/runtime";
15878
+ export default function(data, viewId, refData) {
15879
+ let $data = data || {},
15880
+ $viewId = viewId || '';
15881
+ return (${funcWithVars})($data, $viewId, refData,
15882
+ __larkEncHtml, __larkStrSafe, __larkEncUri, __larkRefFn, __larkEncQuote
15883
+ );
15884
+ }`;
15885
+ }
15350
15886
  export {
15351
15887
  compileTemplate,
15352
- extractGlobalVars
15888
+ extractGlobalVars2 as extractGlobalVars,
15889
+ extractGlobalVars as extractGlobalVarsSwc
15353
15890
  };