xmlui 0.12.4 → 0.12.6

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.
Files changed (34) hide show
  1. package/dist/bin/index.cjs +2453 -151
  2. package/dist/bin/index.js +2405 -106
  3. package/dist/for-node/vite-xmlui-plugin.cjs +76 -1
  4. package/dist/for-node/vite-xmlui-plugin.js +76 -1
  5. package/dist/lib/{extractParam-GS7LIVZM.js → extractParam-JIDhZ5Xc.js} +30 -3
  6. package/dist/lib/{index-BERG25LO.js → index-CNTDdONe.js} +3945 -3180
  7. package/dist/lib/index.css +2 -2
  8. package/dist/lib/{initMock-tbJIWT5s.js → initMock-CU7EJWWZ.js} +2 -2
  9. package/dist/lib/{parser-C4e5pSIM.js → parser-DhasSn5-.js} +89 -5
  10. package/dist/lib/testing.d.ts +15 -0
  11. package/dist/lib/testing.js +3 -3
  12. package/dist/lib/{xmlui-parser-Dk9Ul7U9.js → xmlui-parser-BJ0vVKbY.js} +1 -1
  13. package/dist/lib/xmlui-parser.d.ts +14 -1
  14. package/dist/lib/xmlui-parser.js +2 -2
  15. package/dist/lib/xmlui.d.ts +27 -3
  16. package/dist/lib/xmlui.js +5 -3
  17. package/dist/metadata/TextBox-DAybtr8B.cjs +1 -0
  18. package/dist/metadata/{TextBox-DNQU3Cnq.js → TextBox-DHL5_vCt.js} +4319 -3539
  19. package/dist/metadata/behaviors.cjs +1 -1
  20. package/dist/metadata/behaviors.js +1 -1
  21. package/dist/metadata/{initMock-CI3hpGyU.js → initMock-BnJbxxe5.js} +1 -1
  22. package/dist/metadata/{initMock-_V-TJBxb.cjs → initMock-CyKzqt1R.cjs} +1 -1
  23. package/dist/metadata/metadata-utils.cjs +1 -1
  24. package/dist/metadata/metadata-utils.js +1 -1
  25. package/dist/metadata/{transform-8Zh9SKvP.js → transform-D3iR12tV.js} +114 -30
  26. package/dist/metadata/transform-RxMduR7r.cjs +1 -0
  27. package/dist/metadata/xmlui-metadata.cjs +1 -1
  28. package/dist/metadata/xmlui-metadata.js +5 -4
  29. package/dist/metadata/xmlui.css +2 -2
  30. package/dist/standalone/xmlui-standalone.es.d.ts +40 -9
  31. package/dist/standalone/xmlui-standalone.umd.js +42 -43
  32. package/package.json +1 -3
  33. package/dist/metadata/TextBox-Ctkog5jq.cjs +0 -1
  34. package/dist/metadata/transform-C6FwhNer.cjs +0 -1
@@ -54,12 +54,19 @@ let path = require("path");
54
54
  path = __toESM(path);
55
55
  let __eslint_community_regexpp = require("@eslint-community/regexpp");
56
56
  __eslint_community_regexpp = __toESM(__eslint_community_regexpp);
57
+ require("react");
58
+ let lodash_es = require("lodash-es");
59
+ lodash_es = __toESM(lodash_es);
57
60
  let node_fs = require("node:fs");
58
61
  node_fs = __toESM(node_fs);
59
62
  let node_url = require("node:url");
60
63
  node_url = __toESM(node_url);
61
64
  let node_path = require("node:path");
62
65
  node_path = __toESM(node_path);
66
+ let node_fs_promises = require("node:fs/promises");
67
+ node_fs_promises = __toESM(node_fs_promises);
68
+ let node_vm = require("node:vm");
69
+ node_vm = __toESM(node_vm);
63
70
  let yargs_yargs = require("yargs/yargs");
64
71
  yargs_yargs = __toESM(yargs_yargs);
65
72
  let yargs_helpers = require("yargs/helpers");
@@ -71,7 +78,7 @@ vite_plugin_lib_inject_css = __toESM(vite_plugin_lib_inject_css);
71
78
 
72
79
  //#region ../node_modules/picomatch/lib/constants.js
73
80
  var require_constants = /* @__PURE__ */ __commonJS({ "../node_modules/picomatch/lib/constants.js": ((exports, module) => {
74
- const path$5 = require("path");
81
+ const path$7 = require("path");
75
82
  const WIN_SLASH = "\\\\/";
76
83
  const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
77
84
  /**
@@ -196,7 +203,7 @@ var require_constants = /* @__PURE__ */ __commonJS({ "../node_modules/picomatch/
196
203
  CHAR_UNDERSCORE: 95,
197
204
  CHAR_VERTICAL_LINE: 124,
198
205
  CHAR_ZERO_WIDTH_NOBREAK_SPACE: 65279,
199
- SEP: path$5.sep,
206
+ SEP: path$7.sep,
200
207
  extglobChars(chars) {
201
208
  return {
202
209
  "!": {
@@ -235,7 +242,7 @@ var require_constants = /* @__PURE__ */ __commonJS({ "../node_modules/picomatch/
235
242
  //#endregion
236
243
  //#region ../node_modules/picomatch/lib/utils.js
237
244
  var require_utils = /* @__PURE__ */ __commonJS({ "../node_modules/picomatch/lib/utils.js": ((exports) => {
238
- const path$4 = require("path");
245
+ const path$6 = require("path");
239
246
  const win32$1 = process.platform === "win32";
240
247
  const { REGEX_BACKSLASH, REGEX_REMOVE_BACKSLASH, REGEX_SPECIAL_CHARS, REGEX_SPECIAL_CHARS_GLOBAL } = require_constants();
241
248
  exports.isObject = (val) => val !== null && typeof val === "object" && !Array.isArray(val);
@@ -255,7 +262,7 @@ var require_utils = /* @__PURE__ */ __commonJS({ "../node_modules/picomatch/lib/
255
262
  };
256
263
  exports.isWindows = (options) => {
257
264
  if (options && typeof options.windows === "boolean") return options.windows;
258
- return win32$1 === true || path$4.sep === "\\";
265
+ return win32$1 === true || path$6.sep === "\\";
259
266
  };
260
267
  exports.escapeLast = (input, char, lastIdx) => {
261
268
  const idx = input.lastIndexOf(char, lastIdx);
@@ -1431,7 +1438,7 @@ var require_parse = /* @__PURE__ */ __commonJS({ "../node_modules/picomatch/lib/
1431
1438
  //#endregion
1432
1439
  //#region ../node_modules/picomatch/lib/picomatch.js
1433
1440
  var require_picomatch$1 = /* @__PURE__ */ __commonJS({ "../node_modules/picomatch/lib/picomatch.js": ((exports, module) => {
1434
- const path$3 = require("path");
1441
+ const path$5 = require("path");
1435
1442
  const scan = require_scan();
1436
1443
  const parse = require_parse();
1437
1444
  const utils = require_utils();
@@ -1570,7 +1577,7 @@ var require_picomatch$1 = /* @__PURE__ */ __commonJS({ "../node_modules/picomatc
1570
1577
  * @api public
1571
1578
  */
1572
1579
  picomatch.matchBase = (input, glob$2, options, posix$1 = utils.isWindows(options)) => {
1573
- return (glob$2 instanceof RegExp ? glob$2 : picomatch.makeRe(glob$2, options)).test(path$3.basename(input));
1580
+ return (glob$2 instanceof RegExp ? glob$2 : picomatch.makeRe(glob$2, options)).test(path$5.basename(input));
1574
1581
  };
1575
1582
  /**
1576
1583
  * Returns true if **any** of the given glob `patterns` match the specified `string`.
@@ -5198,10 +5205,66 @@ var Parser = class {
5198
5205
  endToken = this._lexer.peek();
5199
5206
  this.expectToken(TokenType.RParent, "W006");
5200
5207
  }
5201
- return this.createExpressionNode(T_NEW_EXPRESSION, {
5208
+ let newExprResult = this.createExpressionNode(T_NEW_EXPRESSION, {
5202
5209
  callee,
5203
5210
  arguments: args
5204
5211
  }, startToken, endToken);
5212
+ let exitMemberLoop = false;
5213
+ do {
5214
+ const currentStart = this._lexer.peek();
5215
+ switch (currentStart.type) {
5216
+ case TokenType.LParent: {
5217
+ this._lexer.get();
5218
+ let invokeArgs = [];
5219
+ if (this._lexer.peek().type !== TokenType.RParent) {
5220
+ const expr = this.parseExpr();
5221
+ if (!expr) {
5222
+ this.reportError("W001");
5223
+ return null;
5224
+ }
5225
+ invokeArgs = expr.type === T_SEQUENCE_EXPRESSION ? expr.exprs : [expr];
5226
+ }
5227
+ const invokeEndToken = this._lexer.peek();
5228
+ this.expectToken(TokenType.RParent, "W006");
5229
+ newExprResult = this.createExpressionNode(T_FUNCTION_INVOCATION_EXPRESSION, {
5230
+ obj: newExprResult,
5231
+ arguments: invokeArgs
5232
+ }, startToken, invokeEndToken);
5233
+ break;
5234
+ }
5235
+ case TokenType.Dot:
5236
+ case TokenType.OptionalChaining: {
5237
+ this._lexer.get();
5238
+ const member = this._lexer.get();
5239
+ if (!tokenTraits[member.type].keywordLike) {
5240
+ this.reportError("W003");
5241
+ return null;
5242
+ }
5243
+ newExprResult = this.createExpressionNode(T_MEMBER_ACCESS_EXPRESSION, {
5244
+ obj: newExprResult,
5245
+ member: member.text,
5246
+ opt: currentStart.type === TokenType.OptionalChaining
5247
+ }, startToken, member);
5248
+ break;
5249
+ }
5250
+ case TokenType.LSquare: {
5251
+ this._lexer.get();
5252
+ const memberExpr = this.getExpression();
5253
+ if (!memberExpr) return null;
5254
+ const calcEndToken = this._lexer.peek();
5255
+ this.expectToken(TokenType.RSquare, "W005");
5256
+ newExprResult = this.createExpressionNode(T_CALCULATED_MEMBER_ACCESS_EXPRESSION, {
5257
+ obj: newExprResult,
5258
+ member: memberExpr
5259
+ }, startToken, calcEndToken);
5260
+ break;
5261
+ }
5262
+ default:
5263
+ exitMemberLoop = true;
5264
+ break;
5265
+ }
5266
+ } while (!exitMemberLoop);
5267
+ return newExprResult;
5205
5268
  }
5206
5269
  if (startToken.type === TokenType.Identifier && startToken.text === "await") {
5207
5270
  this._lexer.get();
@@ -6055,70 +6118,70 @@ var ModuleCache = class {
6055
6118
  * @param path The module path
6056
6119
  * @returns The resolved module or undefined if not cached
6057
6120
  */
6058
- static getResolved(path$6) {
6059
- return this.resolvedModules.get(path$6);
6121
+ static getResolved(path$8) {
6122
+ return this.resolvedModules.get(path$8);
6060
6123
  }
6061
6124
  /**
6062
6125
  * Sets a resolved module in cache
6063
6126
  * @param path The module path
6064
6127
  * @param module The resolved module
6065
6128
  */
6066
- static setResolved(path$6, module$1) {
6067
- this.resolvedModules.set(path$6, module$1);
6129
+ static setResolved(path$8, module$1) {
6130
+ this.resolvedModules.set(path$8, module$1);
6068
6131
  }
6069
6132
  /**
6070
6133
  * Checks if a resolved module is cached
6071
6134
  * @param path The module path
6072
6135
  * @returns True if the module is in cache
6073
6136
  */
6074
- static hasResolved(path$6) {
6075
- return this.resolvedModules.has(path$6);
6137
+ static hasResolved(path$8) {
6138
+ return this.resolvedModules.has(path$8);
6076
6139
  }
6077
6140
  /**
6078
6141
  * Gets a parsed module from cache
6079
6142
  * @param path The module path
6080
6143
  * @returns The parsed module (or promise) or undefined if not cached
6081
6144
  */
6082
- static getParsed(path$6) {
6083
- return this.parsedModules.get(path$6);
6145
+ static getParsed(path$8) {
6146
+ return this.parsedModules.get(path$8);
6084
6147
  }
6085
6148
  /**
6086
6149
  * Sets a parsed module in cache
6087
6150
  * @param path The module path
6088
6151
  * @param module The parsed module or promise
6089
6152
  */
6090
- static setParsed(path$6, module$1) {
6091
- this.parsedModules.set(path$6, module$1);
6153
+ static setParsed(path$8, module$1) {
6154
+ this.parsedModules.set(path$8, module$1);
6092
6155
  }
6093
6156
  /**
6094
6157
  * Checks if a parsed module is cached
6095
6158
  * @param path The module path
6096
6159
  * @returns True if the module is in cache
6097
6160
  */
6098
- static hasParsed(path$6) {
6099
- return this.parsedModules.has(path$6);
6161
+ static hasParsed(path$8) {
6162
+ return this.parsedModules.has(path$8);
6100
6163
  }
6101
6164
  /**
6102
6165
  * Checks if a module is currently being parsed (to detect circular dependencies at parse level)
6103
6166
  * @param path The module path
6104
6167
  * @returns True if the module is currently being parsed
6105
6168
  */
6106
- static isCurrentlyParsing(path$6) {
6107
- return this.currentlyParsing.has(path$6);
6169
+ static isCurrentlyParsing(path$8) {
6170
+ return this.currentlyParsing.has(path$8);
6108
6171
  }
6109
6172
  /**
6110
6173
  * Mark a module as currently being parsed
6111
6174
  * @param path The module path
6112
6175
  */
6113
- static markCurrentlyParsing(path$6) {
6114
- this.currentlyParsing.add(path$6);
6176
+ static markCurrentlyParsing(path$8) {
6177
+ this.currentlyParsing.add(path$8);
6115
6178
  }
6116
6179
  /**
6117
6180
  * Mark a module as no longer being parsed
6118
6181
  * @param path The module path
6119
6182
  */
6120
- static unmarkCurrentlyParsing(path$6) {
6121
- this.currentlyParsing.delete(path$6);
6183
+ static unmarkCurrentlyParsing(path$8) {
6184
+ this.currentlyParsing.delete(path$8);
6122
6185
  }
6123
6186
  /**
6124
6187
  * Clears all caches (both resolved and parsed modules) and resets parsing state
@@ -6187,9 +6250,9 @@ var FilePathResolver = class {
6187
6250
  * @returns The normalized path
6188
6251
  * @throws Error if path tries to go above root
6189
6252
  */
6190
- normalizePath(path$6) {
6191
- const isAbsolute$1 = path$6.startsWith("/");
6192
- const segments = (isAbsolute$1 ? path$6.substring(1) : path$6).split("/").filter((seg) => seg !== "");
6253
+ normalizePath(path$8) {
6254
+ const isAbsolute$1 = path$8.startsWith("/");
6255
+ const segments = (isAbsolute$1 ? path$8.substring(1) : path$8).split("/").filter((seg) => seg !== "");
6193
6256
  const normalized = [];
6194
6257
  for (const segment of segments) if (segment === ".") continue;
6195
6258
  else if (segment === "..") {
@@ -6282,16 +6345,16 @@ var PathResolver = class {
6282
6345
  * @param path The path to check
6283
6346
  * @returns True if the path is a URL
6284
6347
  */
6285
- static isUrl(path$6) {
6286
- return path$6.startsWith("http://") || path$6.startsWith("https://");
6348
+ static isUrl(path$8) {
6349
+ return path$8.startsWith("http://") || path$8.startsWith("https://");
6287
6350
  }
6288
6351
  /**
6289
6352
  * Checks if a given string is a file path
6290
6353
  * @param path The path to check
6291
6354
  * @returns True if the path is a file path
6292
6355
  */
6293
- static isFilePath(path$6) {
6294
- return !this.isUrl(path$6);
6356
+ static isFilePath(path$8) {
6357
+ return !this.isUrl(path$8);
6295
6358
  }
6296
6359
  /**
6297
6360
  * Gets the file name from a path or URL
@@ -6331,9 +6394,9 @@ var PathResolver = class {
6331
6394
  * @returns The normalized path
6332
6395
  * @throws Error if path tries to go above root
6333
6396
  */
6334
- static normalizePath(path$6) {
6335
- if (this.isUrl(path$6)) return path$6;
6336
- return new FilePathResolver()["normalizePath"](path$6);
6397
+ static normalizePath(path$8) {
6398
+ if (this.isUrl(path$8)) return path$8;
6399
+ return new FilePathResolver()["normalizePath"](path$8);
6337
6400
  }
6338
6401
  };
6339
6402
 
@@ -6730,8 +6793,8 @@ async function doParseModule(moduleName, source, moduleFetcher) {
6730
6793
  const resolvedModule = await ModuleResolver.resolveAndFetchModule(importDecl.source.value, moduleName);
6731
6794
  const importedModuleResult = await parseScriptModuleAsync(resolvedModule.path, resolvedModule.content, moduleFetcher);
6732
6795
  if (isModuleErrors(importedModuleResult)) {
6733
- Object.entries(importedModuleResult).forEach(([path$6, errs]) => {
6734
- moduleErrors[path$6] = errs;
6796
+ Object.entries(importedModuleResult).forEach(([path$8, errs]) => {
6797
+ moduleErrors[path$8] = errs;
6735
6798
  if (errs.some((e) => e.code === ErrorCodes.reactiveVarInImportedModule || e.code === ErrorCodes.constLetInImportedModule)) hasValidationErrors = true;
6736
6799
  });
6737
6800
  continue;
@@ -6854,6 +6917,26 @@ const ARROW_EXPR_MARK = "_ARROW_EXPR_";
6854
6917
  * ```
6855
6918
  */
6856
6919
  const PARSED_EVENT_MARK = Symbol.for("__XMLUI_PARSED_EVENT__");
6920
+ /**
6921
+ * Type guard for arrow expression objects.
6922
+ *
6923
+ * Checks if a value is an executable arrow function expression.
6924
+ * These can be called with appropriate context and arguments.
6925
+ *
6926
+ * @param value - The value to check
6927
+ * @returns `true` if the value is an arrow expression object
6928
+ *
6929
+ * @example
6930
+ * ```typescript
6931
+ * const fn = evaluateArrowExpression(node);
6932
+ * if (isArrowExpressionObject(fn)) {
6933
+ * const result = executeFunction(fn, args);
6934
+ * }
6935
+ * ```
6936
+ */
6937
+ function isArrowExpressionObject(value) {
6938
+ return typeof value === "object" && value !== null && ARROW_EXPR_MARK in value && value[ARROW_EXPR_MARK] === true;
6939
+ }
6857
6940
 
6858
6941
  //#endregion
6859
6942
  //#region src/parsers/scripting/types.ts
@@ -6944,11 +7027,11 @@ var ModuleLoader = class {
6944
7027
  * }
6945
7028
  * ```
6946
7029
  */
6947
- static async loadModule(path$6, options = {}) {
7030
+ static async loadModule(path$8, options = {}) {
6948
7031
  const { fetcher, allowImports = true, baseUrl, skipCache = false } = options;
6949
7032
  try {
6950
- let resolvedPath = path$6;
6951
- if (baseUrl && !PathResolver.isUrl(path$6) && !PathResolver.isFilePath(path$6)) resolvedPath = PathResolver.resolve(path$6, baseUrl);
7033
+ let resolvedPath = path$8;
7034
+ if (baseUrl && !PathResolver.isUrl(path$8) && !PathResolver.isFilePath(path$8)) resolvedPath = PathResolver.resolve(path$8, baseUrl);
6952
7035
  if (!skipCache && ModuleCache.hasParsed(resolvedPath)) {
6953
7036
  const cached = ModuleCache.getParsed(resolvedPath);
6954
7037
  if (cached && !(cached instanceof Promise)) return ok(cached);
@@ -6959,7 +7042,7 @@ var ModuleLoader = class {
6959
7042
  return await this.parseWithImports(resolvedPath, content, fetcher);
6960
7043
  } catch (error) {
6961
7044
  const errorMessage = error instanceof Error ? error.message : String(error);
6962
- return err({ [path$6]: [{
7045
+ return err({ [path$8]: [{
6963
7046
  code: "MODULE_LOAD_ERROR",
6964
7047
  text: errorMessage,
6965
7048
  position: 0,
@@ -7012,8 +7095,8 @@ var ModuleLoader = class {
7012
7095
  * @param path The module path to check
7013
7096
  * @returns True if the module is cached
7014
7097
  */
7015
- static isCached(path$6) {
7016
- return ModuleCache.hasParsed(path$6);
7098
+ static isCached(path$8) {
7099
+ return ModuleCache.hasParsed(path$8);
7017
7100
  }
7018
7101
  /**
7019
7102
  * Fetches module content from a resolved path
@@ -7036,8 +7119,8 @@ var ModuleLoader = class {
7036
7119
  * Parses a module with full import support
7037
7120
  */
7038
7121
  static async parseWithImports(moduleName, source, fetcher) {
7039
- const result = await parseScriptModuleAsync(moduleName, source, fetcher || (async (path$6) => {
7040
- return (await ModuleResolver.resolveModule(path$6)).content;
7122
+ const result = await parseScriptModuleAsync(moduleName, source, fetcher || (async (path$8) => {
7123
+ return (await ModuleResolver.resolveModule(path$8)).content;
7041
7124
  }));
7042
7125
  if (this.isModuleErrors(result)) return err(result);
7043
7126
  return ok(result);
@@ -8193,6 +8276,17 @@ function isLineBreak(ch) {
8193
8276
  return ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn || ch === CharacterCodes.lineSeparator || ch === CharacterCodes.paragraphSeparator;
8194
8277
  }
8195
8278
 
8279
+ //#endregion
8280
+ //#region src/abstractions/AppContextDefs.ts
8281
+ const MediaBreakpointKeys = [
8282
+ "xs",
8283
+ "sm",
8284
+ "md",
8285
+ "lg",
8286
+ "xl",
8287
+ "xxl"
8288
+ ];
8289
+
8196
8290
  //#endregion
8197
8291
  //#region src/parsers/xmlui-parser/transform.ts
8198
8292
  const COMPOUND_COMP_ID = "Component";
@@ -8443,6 +8537,14 @@ function nodeToComponentDef(node, originalGetText, fileId, preResolvedImports) {
8443
8537
  comp.uses = splitUsesValue(value);
8444
8538
  return;
8445
8539
  default:
8540
+ if (name.startsWith("when-")) {
8541
+ const bp = name.slice(5);
8542
+ if (MediaBreakpointKeys.includes(bp)) {
8543
+ comp.responsiveWhen ??= {};
8544
+ comp.responsiveWhen[bp] = value;
8545
+ return;
8546
+ }
8547
+ }
8446
8548
  if (startSegment === "var") {
8447
8549
  comp.vars ??= {};
8448
8550
  comp.vars[name] = value;
@@ -9136,124 +9238,1894 @@ function splitUsesValue(value) {
9136
9238
  }
9137
9239
 
9138
9240
  //#endregion
9139
- //#region src/language-server/base/text-document.ts
9140
- var DocumentCursor = class {
9141
- constructor(text) {
9142
- this.text = text;
9143
- this.newlineOffsets = [0];
9144
- for (let i = 0; i < text.length; i++) {
9145
- const ch = text.charCodeAt(i);
9146
- if (isEOL(ch)) {
9147
- if (ch === 13 && i + 1 < text.length && text.charCodeAt(i + 1) === 10) i++;
9148
- this.newlineOffsets.push(i + 1);
9149
- }
9241
+ //#region src/components-core/script-runner/ParameterParser.ts
9242
+ /**
9243
+ * This function parses a parameter string and splits them into string literal and binding expression sections
9244
+ * @param source String to parse
9245
+ * @returns Parameter string sections
9246
+ */
9247
+ function parseParameterString(source) {
9248
+ const result = [];
9249
+ if (source === void 0 || source === null) return result;
9250
+ let phase = ParsePhase.StringLiteral;
9251
+ let section = "";
9252
+ let escape = "";
9253
+ for (let i = 0; i < source.length; i++) {
9254
+ const ch = source[i];
9255
+ switch (phase) {
9256
+ case ParsePhase.StringLiteral:
9257
+ if (ch === "\\") {
9258
+ phase = ParsePhase.Escape;
9259
+ escape = "\\";
9260
+ } else if (ch === "{") {
9261
+ if (section !== "") result.push({
9262
+ type: "literal",
9263
+ value: section
9264
+ });
9265
+ section = "";
9266
+ phase = ParsePhase.ExprStart;
9267
+ } else section += ch;
9268
+ break;
9269
+ case ParsePhase.Escape:
9270
+ if (ch === "\\") {
9271
+ escape += ch;
9272
+ break;
9273
+ }
9274
+ if (ch === "{") section += escape.substring(1) + ch;
9275
+ else section += escape + ch;
9276
+ phase = ParsePhase.StringLiteral;
9277
+ break;
9278
+ case ParsePhase.ExprStart:
9279
+ const exprSource = source.substring(i);
9280
+ const parser = new Parser(source.substring(i));
9281
+ let expr = null;
9282
+ try {
9283
+ expr = parser.parseExpr();
9284
+ } catch (err$1) {
9285
+ throw new Error(`Cannot parse expression: '${exprSource}': ${err$1}`);
9286
+ }
9287
+ const tail = parser.getTail();
9288
+ if (!tail || tail.trim().length < 1 || tail.trim()[0] !== "}") throw new Error(`Unclosed expression: '${source}'\n'${exprSource}'`);
9289
+ else {
9290
+ result.push({
9291
+ type: "expression",
9292
+ value: expr
9293
+ });
9294
+ i = source.length - tail.length;
9295
+ section = "";
9296
+ }
9297
+ phase = ParsePhase.StringLiteral;
9298
+ break;
9150
9299
  }
9151
9300
  }
9152
- get textLength() {
9153
- return this.text.length;
9301
+ switch (phase) {
9302
+ case ParsePhase.StringLiteral:
9303
+ if (section !== "") result.push({
9304
+ type: "literal",
9305
+ value: section
9306
+ });
9307
+ break;
9308
+ case ParsePhase.Escape:
9309
+ result.push({
9310
+ type: "literal",
9311
+ value: section + escape
9312
+ });
9313
+ break;
9314
+ case ParsePhase.ExprStart:
9315
+ result.push({
9316
+ type: "literal",
9317
+ value: section + "{"
9318
+ });
9319
+ break;
9154
9320
  }
9155
- get lineCount() {
9156
- return this.newlineOffsets.length;
9321
+ return result;
9322
+ }
9323
+ var ParsePhase = /* @__PURE__ */ function(ParsePhase$1) {
9324
+ ParsePhase$1[ParsePhase$1["StringLiteral"] = 0] = "StringLiteral";
9325
+ ParsePhase$1[ParsePhase$1["Escape"] = 1] = "Escape";
9326
+ ParsePhase$1[ParsePhase$1["ExprStart"] = 2] = "ExprStart";
9327
+ return ParsePhase$1;
9328
+ }(ParsePhase || {});
9329
+
9330
+ //#endregion
9331
+ //#region src/components-core/script-runner/bannedFunctions.ts
9332
+ /**
9333
+ * Checks if the specified function object is banned from running.
9334
+ * @param func Function to check
9335
+ * @return Information about the banned state, including a helper text
9336
+ */
9337
+ function isBannedFunction(func) {
9338
+ if (func === void 0) return { banned: false };
9339
+ const bannedInfo = bannedFunctions.find((f) => f.func === func);
9340
+ return bannedInfo ? {
9341
+ banned: true,
9342
+ func: bannedInfo.func,
9343
+ help: bannedInfo.help
9344
+ } : { banned: false };
9345
+ }
9346
+ /**
9347
+ * List of global functions we do not allow to call
9348
+ */
9349
+ const bannedFunctions = [
9350
+ { func: globalThis.cancelAnimationFrame },
9351
+ { func: globalThis.cancelIdleCallback },
9352
+ { func: globalThis.clearInterval },
9353
+ { func: globalThis.clearImmediate },
9354
+ { func: globalThis.clearTimeout },
9355
+ { func: globalThis.eval },
9356
+ { func: globalThis.queueMicrotask },
9357
+ { func: globalThis.requestAnimationFrame },
9358
+ { func: globalThis.requestIdleCallback },
9359
+ { func: globalThis.setImmediate },
9360
+ { func: globalThis.setInterval },
9361
+ {
9362
+ func: globalThis.setTimeout,
9363
+ help: "Use 'delay'"
9157
9364
  }
9158
- /**
9159
- * Converts a zero-based offset to a position.
9160
- *
9161
- * @param offset A zero-based offset.
9162
- * @return A valid {@link Position position}.
9163
- * @example The text document "ab\ncd" produces:
9164
- * * position { line: 0, character: 0 } for `offset` 0.
9165
- * * position { line: 0, character: 1 } for `offset` 1.
9166
- * * position { line: 0, character: 2 } for `offset` 2.
9167
- * * position { line: 1, character: 0 } for `offset` 3.
9168
- * * position { line: 1, character: 1 } for `offset` 4.
9169
- */
9170
- positionAt(offset) {
9171
- offset = Math.max(Math.min(offset, this.textLength), 0);
9172
- const lineOffsets = this.newlineOffsets;
9173
- let low = 0, high = lineOffsets.length;
9174
- if (high === 0) return {
9175
- line: 0,
9176
- character: offset
9177
- };
9178
- while (low < high) {
9179
- const mid = Math.floor((low + high) / 2);
9180
- if (lineOffsets[mid] > offset) high = mid;
9181
- else low = mid + 1;
9365
+ ];
9366
+
9367
+ //#endregion
9368
+ //#region src/components-core/script-runner/eval-tree-common.ts
9369
+ function getExprValue(expr, thread) {
9370
+ return thread?.valueCache?.get(expr)?.value;
9371
+ }
9372
+ function setExprValue(expr, value, thread) {
9373
+ thread.valueCache ??= /* @__PURE__ */ new Map();
9374
+ thread.valueCache.set(expr, { value });
9375
+ }
9376
+ function isPromise(obj) {
9377
+ return obj && typeof obj.then === "function";
9378
+ }
9379
+ function evalLiteral(thisStack, expr, thread) {
9380
+ setExprValue(expr, { value: expr.value }, thread);
9381
+ thisStack.push(expr.value);
9382
+ return expr.value;
9383
+ }
9384
+ function getIdentifierScope(expr, evalContext, thread) {
9385
+ let type;
9386
+ let scope;
9387
+ if (expr.isGlobal) {
9388
+ scope = globalThis;
9389
+ type = "global";
9390
+ } else {
9391
+ let currentThread = thread ?? evalContext.mainThread;
9392
+ while (currentThread && !scope) {
9393
+ if (currentThread.blocks) for (let idx = currentThread.blocks.length - 1; idx >= 0; idx--) {
9394
+ const blockContext = currentThread.blocks[idx]?.vars;
9395
+ if (blockContext && expr.name in blockContext) {
9396
+ scope = blockContext;
9397
+ type = "block";
9398
+ break;
9399
+ }
9400
+ }
9401
+ if (scope) break;
9402
+ if (currentThread.closures) for (let idx = currentThread.closures.length - 1; idx >= 0; idx--) {
9403
+ const blockContext = currentThread.closures[idx]?.vars;
9404
+ if (blockContext && expr.name in blockContext) {
9405
+ scope = blockContext;
9406
+ type = "block";
9407
+ break;
9408
+ }
9409
+ }
9410
+ if (scope) break;
9411
+ currentThread = currentThread.parent;
9182
9412
  }
9183
- const line = low - 1;
9184
- return {
9185
- line,
9186
- character: offset - lineOffsets[line]
9187
- };
9188
9413
  }
9189
- /**
9190
- * Converts the position to a zero-based offset.
9191
- * Invalid positions are adjusted as described in {@link Position.line}
9192
- * and {@link Position.character}.
9193
- *
9194
- * @param position A position.
9195
- * @return A valid zero-based offset.
9196
- */
9197
- offsetAt(position) {
9198
- if (position.line >= this.newlineOffsets.length) return this.textLength;
9199
- else if (position.line < 0) return 0;
9200
- const lineOffset = this.newlineOffsets[position.line];
9201
- if (position.character <= 0) return lineOffset;
9202
- const nextLineOffset = position.line + 1 < this.newlineOffsets.length ? this.newlineOffsets[position.line + 1] : this.textLength;
9203
- return Math.min(lineOffset + position.character, nextLineOffset);
9414
+ if (!scope) if (evalContext.localContext && expr.name in evalContext.localContext) {
9415
+ scope = evalContext.localContext;
9416
+ type = "localContext";
9417
+ } else if (evalContext.appContext?.[expr.name] !== void 0) {
9418
+ scope = evalContext.appContext;
9419
+ type = "app";
9420
+ } else {
9421
+ scope = globalThis;
9422
+ type = "global";
9204
9423
  }
9205
- offsetToDisplayPos(offset) {
9206
- const pos = this.positionAt(offset);
9207
- return {
9208
- line: pos.line + 1,
9209
- character: pos.character + 1
9424
+ return {
9425
+ type,
9426
+ scope
9427
+ };
9428
+ }
9429
+ function evalIdentifier(thisStack, expr, evalContext, thread) {
9430
+ let value;
9431
+ const valueScope = getIdentifierScope(expr, evalContext, thread).scope;
9432
+ let valueIndex = expr.name;
9433
+ value = valueScope[valueIndex];
9434
+ setExprValue(expr, {
9435
+ valueScope,
9436
+ valueIndex,
9437
+ value
9438
+ }, thread);
9439
+ thisStack.push(value);
9440
+ return value;
9441
+ }
9442
+ function getRootIdScope(expr, evalContext, thread) {
9443
+ switch (expr.type) {
9444
+ case T_IDENTIFIER: return {
9445
+ type: getIdentifierScope(expr, evalContext, thread).type,
9446
+ name: expr.name
9210
9447
  };
9448
+ case T_MEMBER_ACCESS_EXPRESSION: return getRootIdScope(expr.obj, evalContext, thread);
9449
+ case T_CALCULATED_MEMBER_ACCESS_EXPRESSION: return getRootIdScope(expr.obj, evalContext, thread);
9211
9450
  }
9212
- getSurroundingContext(pos, end, surroundingLines) {
9213
- const startLine = this.positionAt(pos).line;
9214
- const endLine = this.positionAt(end).line;
9215
- const contextStartLine = Math.max(0, startLine - surroundingLines);
9216
- const contextPos = this.newlineOffsets[contextStartLine];
9217
- const nextLineAfterContext = Math.min(this.lineCount - 1, endLine + surroundingLines) + 1;
9218
- let contextEnd;
9219
- if (nextLineAfterContext < this.lineCount) {
9220
- const nextLineStart = this.newlineOffsets[nextLineAfterContext];
9221
- let eolLength = 1;
9222
- if (nextLineStart > 0 && this.text.charCodeAt(nextLineStart - 1) === 10) {
9223
- if (nextLineStart > 1 && this.text.charCodeAt(nextLineStart - 2) === 13) eolLength = 2;
9224
- }
9225
- contextEnd = nextLineStart - eolLength;
9226
- } else contextEnd = this.textLength;
9227
- return {
9228
- contextPos,
9229
- contextEnd
9230
- };
9451
+ return null;
9452
+ }
9453
+ function evalMemberAccessCore(thisStack, expr, evalContext, thread) {
9454
+ const parentObj = getExprValue(expr.obj, thread)?.value;
9455
+ const value = expr.opt || evalContext.options?.defaultToOptionalMemberAccess ? parentObj?.[expr.member] : parentObj[expr.member];
9456
+ setExprValue(expr, {
9457
+ valueScope: parentObj,
9458
+ valueIndex: expr.member,
9459
+ value
9460
+ }, thread);
9461
+ thisStack.push(value);
9462
+ return value;
9463
+ }
9464
+ function evalCalculatedMemberAccessCore(thisStack, expr, evalContext, thread) {
9465
+ const parentObj = getExprValue(expr.obj, thread)?.value;
9466
+ const memberObj = getExprValue(expr.member, thread)?.value;
9467
+ const value = evalContext.options?.defaultToOptionalMemberAccess ? parentObj?.[memberObj] : parentObj[memberObj];
9468
+ setExprValue(expr, {
9469
+ valueScope: parentObj,
9470
+ valueIndex: memberObj,
9471
+ value
9472
+ }, thread);
9473
+ thisStack.push(value);
9474
+ return value;
9475
+ }
9476
+ function evalUnaryCore(expr, thisStack, evalContext, thread) {
9477
+ let value;
9478
+ const operand = getExprValue(expr.expr, thread);
9479
+ const operValue = operand?.value;
9480
+ switch (expr.op) {
9481
+ case "typeof":
9482
+ value = typeof operValue;
9483
+ break;
9484
+ case "delete":
9485
+ if (operand.valueScope && operand.valueIndex) value = delete operand.valueScope[operand.valueIndex];
9486
+ else value = false;
9487
+ break;
9488
+ case "+":
9489
+ value = operValue;
9490
+ break;
9491
+ case "-":
9492
+ value = -operValue;
9493
+ break;
9494
+ case "!":
9495
+ value = !operValue;
9496
+ break;
9497
+ case "~":
9498
+ value = ~operValue;
9499
+ break;
9500
+ default: throw new Error(`Unknown unary operator: ${expr.op}`);
9231
9501
  }
9232
- rangeAt(range) {
9233
- return {
9234
- start: this.positionAt(range.pos),
9235
- end: this.positionAt(range.end)
9236
- };
9502
+ setExprValue(expr, { value }, thread);
9503
+ thisStack.push(value);
9504
+ return value;
9505
+ }
9506
+ function evalBinaryCore(expr, thisStack, evalContext, thread) {
9507
+ let value;
9508
+ const l = getExprValue(expr.left, thread)?.value;
9509
+ const r = getExprValue(expr.right, thread)?.value;
9510
+ switch (expr.op) {
9511
+ case "**":
9512
+ value = l ** r;
9513
+ break;
9514
+ case "*":
9515
+ value = l * r;
9516
+ break;
9517
+ case "/":
9518
+ value = l / r;
9519
+ break;
9520
+ case "%":
9521
+ value = l % r;
9522
+ break;
9523
+ case "+":
9524
+ value = l + r;
9525
+ break;
9526
+ case "-":
9527
+ value = l - r;
9528
+ break;
9529
+ case ">>":
9530
+ value = l >> r;
9531
+ break;
9532
+ case ">>>":
9533
+ value = l >>> r;
9534
+ break;
9535
+ case "<<":
9536
+ value = l << r;
9537
+ break;
9538
+ case "<":
9539
+ value = l < r;
9540
+ break;
9541
+ case "<=":
9542
+ value = l <= r;
9543
+ break;
9544
+ case ">":
9545
+ value = l > r;
9546
+ break;
9547
+ case ">=":
9548
+ value = l >= r;
9549
+ break;
9550
+ case "in":
9551
+ value = l in r;
9552
+ break;
9553
+ case "==":
9554
+ value = l == r;
9555
+ break;
9556
+ case "!=":
9557
+ value = l != r;
9558
+ break;
9559
+ case "===":
9560
+ value = l === r;
9561
+ break;
9562
+ case "!==":
9563
+ value = l !== r;
9564
+ break;
9565
+ case "&":
9566
+ value = l & r;
9567
+ break;
9568
+ case "^":
9569
+ value = l ^ r;
9570
+ break;
9571
+ case "|":
9572
+ value = l | r;
9573
+ break;
9574
+ case "&&":
9575
+ value = l && r;
9576
+ break;
9577
+ case "||":
9578
+ value = l || r;
9579
+ break;
9580
+ case "??":
9581
+ value = l ?? r;
9582
+ break;
9583
+ default: throw new Error(`Unknown binary operator: ${expr.op}`);
9237
9584
  }
9238
- offsetRangeAt(range) {
9239
- return {
9240
- pos: this.offsetAt(range.start),
9241
- end: this.offsetAt(range.end)
9242
- };
9585
+ setExprValue(expr, { value }, thread);
9586
+ thisStack.push(value);
9587
+ return value;
9588
+ }
9589
+ function evalAssignmentCore(thisStack, expr, evalContext, thread) {
9590
+ const leftValue = getExprValue(expr.leftValue, thread);
9591
+ const newValue = getExprValue(expr.expr, thread)?.value;
9592
+ if (!leftValue.valueScope || leftValue.valueIndex === void 0 || leftValue.valueIndex === null) throw new Error(`Evaluation of ${expr.op} requires a left-hand value.`);
9593
+ const leftScope = leftValue.valueScope;
9594
+ const leftIndex = leftValue.valueIndex;
9595
+ if (typeof leftScope !== "object" || leftScope === null) throw new Error(`Unknown left-hand value`);
9596
+ if (expr.leftValue.type === T_IDENTIFIER) {
9597
+ if (isConstVar(expr.leftValue.name, thread)) throw new Error("A const variable cannot be modified");
9598
+ }
9599
+ if (leftScope === globalThis && !(leftIndex in leftScope)) throw new Error(`Left value variable (${leftIndex}) not found in the scope.`);
9600
+ thisStack.pop();
9601
+ switch (expr.op) {
9602
+ case "=":
9603
+ leftScope[leftIndex] = newValue;
9604
+ break;
9605
+ case "+=":
9606
+ leftScope[leftIndex] += newValue;
9607
+ break;
9608
+ case "-=":
9609
+ leftScope[leftIndex] -= newValue;
9610
+ break;
9611
+ case "**=":
9612
+ leftScope[leftIndex] **= newValue;
9613
+ break;
9614
+ case "*=":
9615
+ leftScope[leftIndex] *= newValue;
9616
+ break;
9617
+ case "/=":
9618
+ leftScope[leftIndex] /= newValue;
9619
+ break;
9620
+ case "%=":
9621
+ leftScope[leftIndex] %= newValue;
9622
+ break;
9623
+ case "<<=":
9624
+ leftScope[leftIndex] <<= newValue;
9625
+ break;
9626
+ case ">>=":
9627
+ leftScope[leftIndex] >>= newValue;
9628
+ break;
9629
+ case ">>>=":
9630
+ leftScope[leftIndex] >>>= newValue;
9631
+ break;
9632
+ case "&=":
9633
+ leftScope[leftIndex] &= newValue;
9634
+ break;
9635
+ case "^=":
9636
+ leftScope[leftIndex] ^= newValue;
9637
+ break;
9638
+ case "|=":
9639
+ leftScope[leftIndex] |= newValue;
9640
+ break;
9641
+ case "&&=":
9642
+ leftScope[leftIndex] &&= newValue;
9643
+ break;
9644
+ case "||=":
9645
+ leftScope[leftIndex] ||= newValue;
9646
+ break;
9647
+ case "??=":
9648
+ leftScope[leftIndex] += newValue;
9649
+ break;
9243
9650
  }
9244
- };
9245
- function isEOL(char) {
9246
- return char === 13 || char === 10;
9651
+ const value = leftScope[leftIndex];
9652
+ setExprValue(expr, { value }, thread);
9653
+ thisStack.push(value);
9654
+ return value;
9655
+ }
9656
+ function evalPreOrPostCore(thisStack, expr, evalContext, thread) {
9657
+ const operand = getExprValue(expr.expr, thread);
9658
+ if (!operand.valueScope || operand.valueIndex === void 0) throw new Error(`Evaluation of ${expr.op} requires a left-hand value.`);
9659
+ if (expr.expr.type === T_IDENTIFIER) {
9660
+ if (isConstVar(expr.expr.name, thread)) throw new Error("A const variable cannot be modified");
9661
+ }
9662
+ const value = expr.op === "++" ? expr.type === T_PREFIX_OP_EXPRESSION ? ++operand.valueScope[operand.valueIndex] : operand.valueScope[operand.valueIndex]++ : expr.type === T_PREFIX_OP_EXPRESSION ? --operand.valueScope[operand.valueIndex] : operand.valueScope[operand.valueIndex]--;
9663
+ setExprValue(expr, { value }, thread);
9664
+ thisStack.push(value);
9665
+ return value;
9666
+ }
9667
+ function evalArrow(thisStack, expr, thread) {
9668
+ if (expr.async) throw new Error("XMLUI does not support async arrow functions.");
9669
+ const lazyArrow = {
9670
+ ...expr,
9671
+ _ARROW_EXPR_: true,
9672
+ closureContext: obtainClosures(thread)
9673
+ };
9674
+ setExprValue(expr, { value: lazyArrow }, thread);
9675
+ thisStack.push(lazyArrow);
9676
+ return lazyArrow;
9677
+ }
9678
+ function obtainClosures(thread) {
9679
+ const closures = thread.blocks?.slice(0) ?? [];
9680
+ return thread.parent ? [...obtainClosures(thread.parent), ...closures] : closures;
9681
+ }
9682
+ /**
9683
+ * Gets the context of the variable
9684
+ * @param id Identifier to test
9685
+ * @param thread Thread to use for evaluation
9686
+ */
9687
+ function isConstVar(id, thread) {
9688
+ if (thread.blocks) for (let idx = thread.blocks.length; idx >= 0; idx--) {
9689
+ const constContext = thread.blocks[idx]?.constVars;
9690
+ if (constContext && constContext.has(id)) return true;
9691
+ }
9692
+ return false;
9693
+ }
9694
+ function evalTemplateLiteralCore(segmentValues) {
9695
+ return segmentValues.map((value) => typeof value === "string" ? value : `${value}`).join("");
9247
9696
  }
9248
9697
 
9249
9698
  //#endregion
9250
- //#region src/parsers/xmlui-parser/parser.ts
9251
- const RECOVER_FILE = [
9252
- SyntaxKind.CData,
9253
- SyntaxKind.Script,
9254
- SyntaxKind.OpenNodeStart
9255
- ];
9256
- const RECOVER_OPEN_TAG = [
9699
+ //#region src/components-core/script-runner/statement-queue.ts
9700
+ var StatementQueue = class {
9701
+ constructor() {
9702
+ this.items = [];
9703
+ }
9704
+ get length() {
9705
+ return this.items.length;
9706
+ }
9707
+ peek() {
9708
+ return this.items[0];
9709
+ }
9710
+ dequeue() {
9711
+ return this.items.shift();
9712
+ }
9713
+ push(statements) {
9714
+ this.items.push(...statements);
9715
+ }
9716
+ unshift(statements) {
9717
+ this.items.unshift(...statements);
9718
+ }
9719
+ clearToLabel(label) {
9720
+ while (this.items.length > 0 && this.items[0].label !== label) this.items.shift();
9721
+ }
9722
+ };
9723
+ let nextLabelValue = 1;
9724
+ function mapToItem(statement) {
9725
+ return [{
9726
+ label: nextLabelValue++,
9727
+ statement: { ...statement }
9728
+ }];
9729
+ }
9730
+ function mapStatementToQueueItem(stmt) {
9731
+ return {
9732
+ label: nextLabelValue++,
9733
+ statement: stmt.statement,
9734
+ execInfo: { ...stmt.execInfo }
9735
+ };
9736
+ }
9737
+ function mapStatementsToQueueItems(statements) {
9738
+ return statements.map(mapStatementToQueueItem);
9739
+ }
9740
+
9741
+ //#endregion
9742
+ //#region src/components-core/script-runner/process-statement-common.ts
9743
+ function innermostLoopScope(thread) {
9744
+ if (!thread.loops || thread.loops.length === 0) throw new Error("Missing loop scope");
9745
+ return thread.loops[thread.loops.length - 1];
9746
+ }
9747
+ function innermostBlockScope(thread) {
9748
+ if (!thread.blocks || thread.blocks.length === 0) return void 0;
9749
+ return thread.blocks[thread.blocks.length - 1];
9750
+ }
9751
+ function innermostTryScope(thread) {
9752
+ if (!thread.tryBlocks || thread.tryBlocks.length === 0) throw new Error("Missing try scope");
9753
+ return thread.tryBlocks[thread.tryBlocks.length - 1];
9754
+ }
9755
+ function createLoopScope(thread, continueOffset = 0) {
9756
+ thread.loops ??= [];
9757
+ const breakDepth = thread.blocks?.length ?? 0;
9758
+ const tryDepth = thread.tryBlocks?.length ?? 0;
9759
+ const loopScope = {
9760
+ breakLabel: -1,
9761
+ continueLabel: -1,
9762
+ breakBlockDepth: breakDepth,
9763
+ continueBlockDepth: breakDepth + continueOffset,
9764
+ tryBlockDepth: tryDepth
9765
+ };
9766
+ thread.loops.push(loopScope);
9767
+ return loopScope;
9768
+ }
9769
+ function releaseLoopScope(thread, skipContinuation = true) {
9770
+ const loopScope = innermostLoopScope(thread);
9771
+ if (skipContinuation) thread.loops?.pop();
9772
+ if (thread.blocks) thread.blocks.length = skipContinuation ? loopScope.breakBlockDepth : loopScope.continueBlockDepth;
9773
+ }
9774
+ function toStatementItems(statements) {
9775
+ return statements.map((s) => ({ statement: s }));
9776
+ }
9777
+ function guard(statement) {
9778
+ return {
9779
+ statement,
9780
+ execInfo: { guard: true }
9781
+ };
9782
+ }
9783
+ function closing() {
9784
+ return {
9785
+ statement: {
9786
+ type: T_EMPTY_STATEMENT,
9787
+ nodeId: createXmlUiTreeNodeId()
9788
+ },
9789
+ execInfo: { removeBlockScope: true }
9790
+ };
9791
+ }
9792
+ function provideLoopBody(loopScope, loopStatement, breakLabelValue) {
9793
+ const guardStatement = guard(loopStatement);
9794
+ const toUnshift = mapStatementsToQueueItems([{ statement: loopStatement.body }, guardStatement]);
9795
+ loopScope.breakLabel = breakLabelValue ?? -1;
9796
+ loopScope.continueLabel = toUnshift[1].label;
9797
+ return toUnshift;
9798
+ }
9799
+ function createTryScope(thread, tryStatement) {
9800
+ thread.tryBlocks ??= [];
9801
+ const loopScope = {
9802
+ statement: tryStatement,
9803
+ processingPhase: "try",
9804
+ tryLabel: -1
9805
+ };
9806
+ thread.tryBlocks.push(loopScope);
9807
+ return loopScope;
9808
+ }
9809
+ function provideTryBody(thread, tryScope) {
9810
+ const guardStatement = guard(tryScope.statement);
9811
+ thread.blocks.push({ vars: {} });
9812
+ const toUnshift = mapStatementsToQueueItems([
9813
+ ...toStatementItems(tryScope.statement.tryB.stmts),
9814
+ closing(),
9815
+ guardStatement
9816
+ ]);
9817
+ tryScope.tryLabel = toUnshift[toUnshift.length - 1].label;
9818
+ return toUnshift;
9819
+ }
9820
+ function provideCatchBody(thread, tryScope) {
9821
+ const guardStatement = guard(tryScope.statement);
9822
+ thread.blocks.push({ vars: {} });
9823
+ const toUnshift = mapStatementsToQueueItems([
9824
+ ...toStatementItems(tryScope.statement.catchB.stmts),
9825
+ closing(),
9826
+ guardStatement
9827
+ ]);
9828
+ tryScope.tryLabel = toUnshift[toUnshift.length - 1].label;
9829
+ return toUnshift;
9830
+ }
9831
+ function provideFinallyBody(thread, tryScope) {
9832
+ const guardStatement = guard(tryScope.statement);
9833
+ thread.blocks.push({ vars: {} });
9834
+ const finallyBlock = tryScope.statement.finallyB;
9835
+ const toUnshift = mapStatementsToQueueItems([
9836
+ ...toStatementItems(finallyBlock ? finallyBlock.stmts : []),
9837
+ closing(),
9838
+ guardStatement
9839
+ ]);
9840
+ tryScope.tryLabel = toUnshift[toUnshift.length - 1].label;
9841
+ return toUnshift;
9842
+ }
9843
+ function provideFinallyErrorBody(tryScope) {
9844
+ const toUnshift = mapStatementsToQueueItems([guard(tryScope.statement)]);
9845
+ tryScope.tryLabel = toUnshift[0].label;
9846
+ return toUnshift;
9847
+ }
9848
+ function ensureMainThread(evalContext) {
9849
+ if (!evalContext.mainThread) evalContext.mainThread = {
9850
+ childThreads: [],
9851
+ blocks: [{ vars: {} }],
9852
+ loops: [],
9853
+ breakLabelValue: -1
9854
+ };
9855
+ return evalContext.mainThread;
9856
+ }
9857
+ function hoistFunctionDeclarations(thread, statements) {
9858
+ const block = innermostBlockScope(thread);
9859
+ if (!block) throw new Error("Missing block scope");
9860
+ statements.filter((stmt) => stmt.type === T_FUNCTION_DECLARATION).forEach((stmt) => {
9861
+ const funcDecl = stmt;
9862
+ const arrowExpression = {
9863
+ type: T_ARROW_EXPRESSION,
9864
+ args: funcDecl.args,
9865
+ statement: funcDecl.stmt,
9866
+ closureContext: obtainClosures(thread),
9867
+ _ARROW_EXPR_: true
9868
+ };
9869
+ const id = funcDecl.id.name;
9870
+ if (block.vars[id]) throw new Error(`Variable ${id} is already declared in the current scope.`);
9871
+ block.vars[id] = arrowExpression;
9872
+ block.constVars ??= /* @__PURE__ */ new Set();
9873
+ block.constVars.add(id);
9874
+ });
9875
+ }
9876
+
9877
+ //#endregion
9878
+ //#region src/components-core/EngineError.ts
9879
+ /**
9880
+ * The abstract base class of all UI engine errors
9881
+ */
9882
+ var EngineError = class EngineError extends Error {
9883
+ constructor(message) {
9884
+ super(message);
9885
+ Object.setPrototypeOf(this, EngineError.prototype);
9886
+ }
9887
+ };
9888
+ /**
9889
+ * Custom exception indicating a parser error
9890
+ */
9891
+ var ScriptParseError = class ScriptParseError extends EngineError {
9892
+ constructor(message, source, position) {
9893
+ message = `Parser Error: ${message}`;
9894
+ super(message);
9895
+ this.source = source;
9896
+ this.position = position;
9897
+ this.errorCategory = "ScriptParserError";
9898
+ Object.setPrototypeOf(this, ScriptParseError.prototype);
9899
+ }
9900
+ };
9901
+ /**
9902
+ * Custom exception signing parsing error
9903
+ */
9904
+ var StatementExecutionError = class StatementExecutionError extends EngineError {
9905
+ constructor(message, source) {
9906
+ super(message);
9907
+ this.source = source;
9908
+ this.errorCategory = "StatementExecutionError";
9909
+ Object.setPrototypeOf(this, StatementExecutionError.prototype);
9910
+ }
9911
+ };
9912
+ /**
9913
+ * We throw this error when a throw statement is executed
9914
+ */
9915
+ var ThrowStatementError = class ThrowStatementError extends EngineError {
9916
+ constructor(errorObject) {
9917
+ const message = typeof errorObject === "string" ? errorObject : errorObject?.message || "Error without message";
9918
+ super(message);
9919
+ this.errorObject = errorObject;
9920
+ this.errorCategory = "ThrowStatementError";
9921
+ this.message = message;
9922
+ Object.setPrototypeOf(this, ThrowStatementError.prototype);
9923
+ }
9924
+ };
9925
+
9926
+ //#endregion
9927
+ //#region src/components-core/reportEngineError.ts
9928
+ const appErrors = [];
9929
+ /**
9930
+ * Use this function to report an error
9931
+ * @param error Error or string describing the error to report
9932
+ * @param errorToThrow The error to throw
9933
+ */
9934
+ function reportEngineError(error, errorToThrow) {
9935
+ if (typeof error === "string") error = new Error(error);
9936
+ let helperMessage = "";
9937
+ let colors = [];
9938
+ if (error instanceof ScriptParseError) {
9939
+ let pos = (error?.position ?? 0) - 1;
9940
+ if (error.source) {
9941
+ while (pos < error.source.length - 1 && error.source[pos] === " ") pos++;
9942
+ helperMessage += `%c${error.message}%c\n\n`;
9943
+ helperMessage += `${error.source.substring(0, pos)}%c${error.source[pos]}%c${error.source.substring(pos + 1) ?? ""}\n\n`;
9944
+ }
9945
+ helperMessage += `%cThe error handler associated with the parsed code did not run.%c`;
9946
+ colors = [
9947
+ "color: red",
9948
+ "color: inherited",
9949
+ "color: red",
9950
+ "color: inherited",
9951
+ "color: orange",
9952
+ "color: inherited"
9953
+ ];
9954
+ } else if (error instanceof StatementExecutionError) {
9955
+ helperMessage += `%cError while executing code: ${error.message}%c`;
9956
+ if (error.source) helperMessage += `\n\n${error.source}`;
9957
+ colors = ["color: red", "color: inherited"];
9958
+ } else if (error instanceof ThrowStatementError) {
9959
+ helperMessage += `A 'throw' statement executed:\n\n%c${error.message}%c\n\n${error.errorObject}`;
9960
+ colors = ["color: red", "color: inherited"];
9961
+ }
9962
+ if (helperMessage) console.error(helperMessage, ...colors);
9963
+ appErrors.push({
9964
+ error,
9965
+ helperMessage,
9966
+ colors
9967
+ });
9968
+ throw errorToThrow ?? error;
9969
+ }
9970
+
9971
+ //#endregion
9972
+ //#region src/components-core/script-runner/process-statement-sync.ts
9973
+ const SYNC_EVAL_TIMEOUT = 1e3;
9974
+ function processStatementQueue(statements, evalContext, thread) {
9975
+ if (!thread) thread = ensureMainThread(evalContext);
9976
+ hoistFunctionDeclarations(thread, statements);
9977
+ evalContext.startTick = (/* @__PURE__ */ new Date()).valueOf();
9978
+ const queue = new StatementQueue();
9979
+ queue.push(mapStatementsToQueueItems(toStatementItems(statements)));
9980
+ const diagInfo = {
9981
+ processedStatements: 0,
9982
+ maxQueueLength: queue.length,
9983
+ unshiftedItems: 0,
9984
+ clearToLabels: 0,
9985
+ maxBlocks: 0,
9986
+ maxLoops: 0
9987
+ };
9988
+ while (queue.length > 0) {
9989
+ if (evalContext.startTick !== void 0 && (/* @__PURE__ */ new Date()).valueOf() - evalContext.startTick > SYNC_EVAL_TIMEOUT) throw new Error(`Sync evaluation timeout exceeded ${SYNC_EVAL_TIMEOUT} milliseconds`);
9990
+ const queueItem = queue.dequeue();
9991
+ thread.breakLabelValue = queue.length > 0 ? queue.peek().label : -1;
9992
+ let outcome;
9993
+ try {
9994
+ evalContext?.onStatementStarted?.(evalContext, queueItem.statement);
9995
+ outcome = processStatement(queueItem.statement, queueItem.execInfo ?? {}, evalContext, thread);
9996
+ } catch (err$1) {
9997
+ if (thread.tryBlocks && thread.tryBlocks.length > 0) {
9998
+ const tryScope = thread.tryBlocks[thread.tryBlocks.length - 1];
9999
+ tryScope.errorToThrow = err$1;
10000
+ tryScope.errorSource = tryScope.processingPhase;
10001
+ tryScope.processingPhase = "error";
10002
+ outcome = { clearToLabel: tryScope.tryLabel };
10003
+ } else if (err$1 instanceof ThrowStatementError) reportEngineError(err$1);
10004
+ else reportEngineError(new StatementExecutionError(err$1), err$1);
10005
+ }
10006
+ if (outcome) {
10007
+ if (outcome.toUnshift) {
10008
+ queue.unshift(outcome.toUnshift);
10009
+ diagInfo.unshiftedItems += outcome.toUnshift.length;
10010
+ }
10011
+ if (outcome.clearToLabel !== void 0) {
10012
+ queue.clearToLabel(outcome.clearToLabel);
10013
+ diagInfo.clearToLabels++;
10014
+ }
10015
+ }
10016
+ evalContext?.onStatementCompleted?.(evalContext, queueItem.statement);
10017
+ if (queue.length > diagInfo.maxQueueLength) diagInfo.maxQueueLength = queue.length;
10018
+ if (thread.blocks && thread.blocks.length > diagInfo.maxBlocks) diagInfo.maxBlocks = thread.blocks.length;
10019
+ if (thread.loops && thread.loops.length > diagInfo.maxLoops) diagInfo.maxLoops = thread.loops.length;
10020
+ diagInfo.processedStatements++;
10021
+ }
10022
+ return diagInfo;
10023
+ }
10024
+ /**
10025
+ * Process the specified statement synchronously
10026
+ * @param statement Statement to process
10027
+ * @param evalContext Evaluation context used for processing
10028
+ * @param thread Logical thread to use for statement processing
10029
+ * @returns Items to put back into the queue of statements
10030
+ */
10031
+ function processStatement(statement, execInfo, evalContext, thread) {
10032
+ let toUnshift = [];
10033
+ let clearToLabel;
10034
+ switch (statement.type) {
10035
+ case T_ASYNC_FUNCTION_DECLARATION: throw new Error("XMLUI does not support async function declarations.");
10036
+ case T_FUNCTION_DECLARATION: break;
10037
+ case T_VAR_STATEMENT:
10038
+ if (thread !== evalContext.mainThread) throw new Error("'var' declarations are not allowed within functions");
10039
+ break;
10040
+ case T_EMPTY_STATEMENT: break;
10041
+ case T_BLOCK_STATEMENT:
10042
+ if (statement.stmts.length === 0) break;
10043
+ thread.blocks ??= [];
10044
+ thread.blocks.push({ vars: {} });
10045
+ hoistFunctionDeclarations(thread, statement.stmts);
10046
+ toUnshift = mapStatementsToQueueItems([...toStatementItems(statement.stmts), closing()]);
10047
+ break;
10048
+ case T_EXPRESSION_STATEMENT:
10049
+ const statementValue = evalBinding(statement.expr, evalContext, thread);
10050
+ if (thread.blocks && thread.blocks.length !== 0) thread.blocks[thread.blocks.length - 1].returnValue = statementValue;
10051
+ break;
10052
+ case T_ARROW_EXPRESSION_STATEMENT:
10053
+ const arrowFuncValue = executeArrowExpressionSync(statement.expr, evalContext, thread, ...evalContext.eventArgs ?? []);
10054
+ if (thread.blocks && thread.blocks.length !== 0) thread.blocks[thread.blocks.length - 1].returnValue = arrowFuncValue;
10055
+ break;
10056
+ case T_LET_STATEMENT: {
10057
+ const block = innermostBlockScope(thread);
10058
+ if (!block) throw new Error("Missing block scope");
10059
+ processDeclarations(block, evalContext, thread, statement.decls);
10060
+ break;
10061
+ }
10062
+ case T_CONST_STATEMENT: {
10063
+ const block = innermostBlockScope(thread);
10064
+ if (!block) throw new Error("Missing block scope");
10065
+ processDeclarations(block, evalContext, thread, statement.decls, true);
10066
+ break;
10067
+ }
10068
+ case T_IF_STATEMENT:
10069
+ if (!!evalBinding(statement.cond, evalContext, thread)) toUnshift = mapToItem(statement.thenB);
10070
+ else if (statement.elseB) toUnshift = mapToItem(statement.elseB);
10071
+ break;
10072
+ case T_RETURN_STATEMENT:
10073
+ if (innermostBlockScope(thread) === void 0) throw new Error("Return requires a block scope");
10074
+ thread.returnValue = statement.expr ? evalBinding(statement.expr, evalContext, thread) : void 0;
10075
+ if ((thread.tryBlocks ?? []).length > 0) {
10076
+ for (let i = 0; i < thread.tryBlocks.length; i++) thread.tryBlocks[i].exitType = "return";
10077
+ const tryScope = innermostTryScope(thread);
10078
+ if (tryScope.processingPhase !== "postFinally") thread.blocks.pop();
10079
+ clearToLabel = tryScope.tryLabel;
10080
+ } else clearToLabel = -1;
10081
+ break;
10082
+ case T_WHILE_STATEMENT: {
10083
+ let loopScope = execInfo.guard ? innermostLoopScope(thread) : createLoopScope(thread);
10084
+ if (!!evalBinding(statement.cond, evalContext, thread)) toUnshift = provideLoopBody(loopScope, statement, thread.breakLabelValue);
10085
+ else releaseLoopScope(thread);
10086
+ break;
10087
+ }
10088
+ case T_DO_WHILE_STATEMENT:
10089
+ if (!execInfo.guard) {
10090
+ toUnshift = provideLoopBody(createLoopScope(thread), statement, thread.breakLabelValue);
10091
+ break;
10092
+ }
10093
+ if (!!evalBinding(statement.cond, evalContext, thread)) toUnshift = provideLoopBody(innermostLoopScope(thread), statement, thread.breakLabelValue);
10094
+ else releaseLoopScope(thread);
10095
+ break;
10096
+ case T_CONTINUE_STATEMENT: {
10097
+ if (!thread.loops || thread.loops.length === 0) throw new Error("Missing loop scope");
10098
+ let loopScope;
10099
+ while (thread.loops.length > 0) {
10100
+ loopScope = innermostLoopScope(thread);
10101
+ if (!loopScope.isSwitch) break;
10102
+ thread.loops.pop();
10103
+ }
10104
+ if (!loopScope) throw new Error("Missing loop scope");
10105
+ if (loopScope.tryBlockDepth >= 0 && loopScope.tryBlockDepth < (thread.tryBlocks ?? []).length) {
10106
+ for (let i = loopScope.tryBlockDepth; i < thread.tryBlocks.length; i++) thread.tryBlocks[loopScope.tryBlockDepth].exitType = "continue";
10107
+ clearToLabel = innermostTryScope(thread).tryLabel;
10108
+ } else {
10109
+ clearToLabel = loopScope.continueLabel;
10110
+ releaseLoopScope(thread, false);
10111
+ }
10112
+ break;
10113
+ }
10114
+ case T_BREAK_STATEMENT: {
10115
+ const loopScope = innermostLoopScope(thread);
10116
+ if (loopScope === void 0) throw new Error("Missing loop scope");
10117
+ if (!!loopScope.isSwitch) {
10118
+ clearToLabel = loopScope.breakLabel;
10119
+ break;
10120
+ }
10121
+ if (loopScope.tryBlockDepth >= 0 && loopScope.tryBlockDepth < (thread.tryBlocks ?? []).length) {
10122
+ for (let i = loopScope.tryBlockDepth; i < thread.tryBlocks.length; i++) thread.tryBlocks[loopScope.tryBlockDepth].exitType = "break";
10123
+ clearToLabel = innermostTryScope(thread).tryLabel;
10124
+ } else {
10125
+ clearToLabel = loopScope.breakLabel;
10126
+ releaseLoopScope(thread);
10127
+ }
10128
+ break;
10129
+ }
10130
+ case T_FOR_STATEMENT:
10131
+ if (!execInfo.guard) {
10132
+ createLoopScope(thread, 1);
10133
+ thread.blocks ??= [];
10134
+ thread.blocks.push({ vars: {} });
10135
+ const guardStatement = guard(statement);
10136
+ if (statement.init) toUnshift = mapStatementsToQueueItems([{ statement: statement.init }, guardStatement]);
10137
+ else toUnshift = mapStatementsToQueueItems([guardStatement]);
10138
+ } else if (!statement.cond || evalBinding(statement.cond, evalContext, thread)) {
10139
+ const loopScope = innermostLoopScope(thread);
10140
+ if (statement.upd) {
10141
+ const updateStmt = { statement: {
10142
+ type: T_EXPRESSION_STATEMENT,
10143
+ nodeId: createXmlUiTreeNodeId(),
10144
+ expr: statement.upd
10145
+ } };
10146
+ toUnshift = mapStatementsToQueueItems([
10147
+ { statement: statement.body },
10148
+ updateStmt,
10149
+ {
10150
+ statement,
10151
+ execInfo
10152
+ }
10153
+ ]);
10154
+ } else toUnshift = mapStatementsToQueueItems([{ statement: statement.body }, {
10155
+ statement,
10156
+ execInfo
10157
+ }]);
10158
+ loopScope.breakLabel = thread.breakLabelValue ?? -1;
10159
+ loopScope.continueLabel = toUnshift[1].label;
10160
+ } else releaseLoopScope(thread);
10161
+ break;
10162
+ case T_FOR_IN_STATEMENT:
10163
+ if (!execInfo.guard) {
10164
+ const keyedObject = evalBinding(statement.expr, evalContext, thread);
10165
+ if (keyedObject == void 0) break;
10166
+ createLoopScope(thread, 1);
10167
+ thread.blocks ??= [];
10168
+ thread.blocks.push({ vars: {} });
10169
+ toUnshift = mapStatementsToQueueItems([{
10170
+ statement,
10171
+ execInfo: {
10172
+ guard: true,
10173
+ keys: Object.keys(keyedObject),
10174
+ keyIndex: 0
10175
+ }
10176
+ }]);
10177
+ } else {
10178
+ if (execInfo.keyIndex === void 0 || execInfo.keys === void 0) throw new Error("Keys information expected in for..in loop");
10179
+ if (execInfo.keyIndex < execInfo.keys.length) {
10180
+ const propValue = execInfo.keys[execInfo.keyIndex++];
10181
+ switch (statement.varB) {
10182
+ case "none":
10183
+ evalBinding({
10184
+ type: T_ASSIGNMENT_EXPRESSION,
10185
+ leftValue: {
10186
+ type: T_IDENTIFIER,
10187
+ name: statement.id.name
10188
+ },
10189
+ op: "=",
10190
+ expr: {
10191
+ type: T_LITERAL,
10192
+ value: propValue
10193
+ }
10194
+ }, evalContext, thread);
10195
+ break;
10196
+ case "const":
10197
+ case "let":
10198
+ {
10199
+ const block = innermostBlockScope(thread);
10200
+ if (!block) throw new Error("Missing block scope");
10201
+ block.vars[statement.id.name] = propValue;
10202
+ if (statement.varB === "const") {
10203
+ block.constVars ??= /* @__PURE__ */ new Set();
10204
+ block.constVars.add(statement.id.name);
10205
+ }
10206
+ }
10207
+ break;
10208
+ }
10209
+ const loopScope = innermostLoopScope(thread);
10210
+ toUnshift = mapStatementsToQueueItems([{ statement: statement.body }, {
10211
+ statement,
10212
+ execInfo
10213
+ }]);
10214
+ loopScope.breakLabel = thread.breakLabelValue ?? -1;
10215
+ loopScope.continueLabel = toUnshift[1].label;
10216
+ } else releaseLoopScope(thread);
10217
+ }
10218
+ break;
10219
+ case T_FOR_OF_STATEMENT:
10220
+ if (!execInfo.guard) {
10221
+ const iteratorObject = evalBinding(statement.expr, evalContext, thread);
10222
+ if (iteratorObject == null || typeof iteratorObject[Symbol.iterator] !== "function") throw new Error("Object in for..of is not iterable");
10223
+ createLoopScope(thread, 1);
10224
+ thread.blocks ??= [];
10225
+ thread.blocks.push({ vars: {} });
10226
+ toUnshift = mapStatementsToQueueItems([{
10227
+ statement,
10228
+ execInfo: {
10229
+ guard: true,
10230
+ iterator: iteratorObject[Symbol.iterator]()
10231
+ }
10232
+ }]);
10233
+ } else {
10234
+ if (execInfo.iterator === void 0) throw new Error("Iterator expected in for..of loop");
10235
+ const nextIteration = execInfo.iterator.next();
10236
+ if (nextIteration.done) {
10237
+ releaseLoopScope(thread);
10238
+ break;
10239
+ }
10240
+ const propValue = nextIteration.value;
10241
+ switch (statement.varB) {
10242
+ case "none":
10243
+ evalBinding({
10244
+ type: T_ASSIGNMENT_EXPRESSION,
10245
+ leftValue: {
10246
+ type: T_IDENTIFIER,
10247
+ name: statement.id.name
10248
+ },
10249
+ op: "=",
10250
+ expr: {
10251
+ type: T_LITERAL,
10252
+ value: propValue
10253
+ }
10254
+ }, evalContext, thread);
10255
+ break;
10256
+ case "const":
10257
+ case "let":
10258
+ {
10259
+ const block = innermostBlockScope(thread);
10260
+ if (!block) throw new Error("Missing block scope");
10261
+ block.vars[statement.id.name] = propValue;
10262
+ if (statement.varB === "const") {
10263
+ block.constVars ??= /* @__PURE__ */ new Set();
10264
+ block.constVars.add(statement.id.name);
10265
+ }
10266
+ }
10267
+ break;
10268
+ }
10269
+ const loopScope = innermostLoopScope(thread);
10270
+ toUnshift = mapStatementsToQueueItems([{ statement: statement.body }, {
10271
+ statement,
10272
+ execInfo
10273
+ }]);
10274
+ loopScope.breakLabel = thread.breakLabelValue ?? -1;
10275
+ loopScope.continueLabel = toUnshift[1].label;
10276
+ }
10277
+ break;
10278
+ case T_THROW_STATEMENT: throw new ThrowStatementError(evalBinding(statement.expr, evalContext, thread));
10279
+ case T_TRY_STATEMENT: {
10280
+ if (!execInfo.guard) {
10281
+ toUnshift = provideTryBody(thread, createTryScope(thread, statement));
10282
+ break;
10283
+ }
10284
+ const tryScope = innermostTryScope(thread);
10285
+ switch (tryScope.processingPhase) {
10286
+ case "error":
10287
+ switch (tryScope.errorSource) {
10288
+ case "try":
10289
+ thread.blocks.pop();
10290
+ if (statement.catchB) {
10291
+ if (tryScope.statement.catchV) {
10292
+ const block = innermostBlockScope(thread);
10293
+ block.vars[tryScope.statement.catchV.name] = tryScope.errorToThrow instanceof ThrowStatementError ? tryScope.errorToThrow.errorObject : tryScope.errorToThrow;
10294
+ }
10295
+ delete tryScope.errorToThrow;
10296
+ tryScope.processingPhase = "catch";
10297
+ toUnshift = provideCatchBody(thread, tryScope);
10298
+ } else if (tryScope.statement.finallyB) {
10299
+ tryScope.processingPhase = "finally";
10300
+ toUnshift = provideFinallyBody(thread, tryScope);
10301
+ }
10302
+ break;
10303
+ case "catch":
10304
+ thread.blocks.pop();
10305
+ tryScope.processingPhase = "finally";
10306
+ toUnshift = provideFinallyBody(thread, tryScope);
10307
+ break;
10308
+ case "finally":
10309
+ thread.blocks.pop();
10310
+ tryScope.processingPhase = "postFinally";
10311
+ toUnshift = provideFinallyErrorBody(tryScope);
10312
+ break;
10313
+ }
10314
+ break;
10315
+ case "try":
10316
+ tryScope.processingPhase = "finally";
10317
+ if (statement.finallyB) toUnshift = provideFinallyBody(thread, tryScope);
10318
+ else toUnshift = provideFinallyErrorBody(tryScope);
10319
+ break;
10320
+ case "catch":
10321
+ tryScope.processingPhase = "finally";
10322
+ if (statement.finallyB) toUnshift = provideFinallyBody(thread, tryScope);
10323
+ else toUnshift = provideFinallyErrorBody(tryScope);
10324
+ break;
10325
+ case "finally":
10326
+ tryScope.processingPhase = "postFinally";
10327
+ toUnshift = provideFinallyErrorBody(tryScope);
10328
+ break;
10329
+ case "postFinally":
10330
+ const innermostTry = thread.tryBlocks.pop();
10331
+ switch (innermostTry.exitType) {
10332
+ case "break": {
10333
+ const loopScope = innermostLoopScope(thread);
10334
+ if (loopScope === void 0) throw new Error("Missing loop scope");
10335
+ releaseLoopScope(thread);
10336
+ clearToLabel = loopScope.breakLabel;
10337
+ break;
10338
+ }
10339
+ case "continue": {
10340
+ const loopScope = innermostLoopScope(thread);
10341
+ if (loopScope === void 0) throw new Error("Missing loop scope");
10342
+ clearToLabel = loopScope.continueLabel;
10343
+ releaseLoopScope(thread, false);
10344
+ break;
10345
+ }
10346
+ case "return":
10347
+ if (thread.tryBlocks && thread.tryBlocks.length > 0) {
10348
+ if (thread.blocks && thread.blocks.length > 1) thread.blocks.pop();
10349
+ clearToLabel = thread.tryBlocks[thread.tryBlocks.length - 1].tryLabel;
10350
+ } else clearToLabel = -1;
10351
+ break;
10352
+ }
10353
+ if (innermostTry.errorToThrow) throw innermostTry.errorToThrow;
10354
+ break;
10355
+ }
10356
+ break;
10357
+ }
10358
+ case T_SWITCH_STATEMENT:
10359
+ if (execInfo.guard) releaseLoopScope(thread);
10360
+ else {
10361
+ let loopScope = createLoopScope(thread);
10362
+ loopScope.isSwitch = true;
10363
+ thread.blocks.push({ vars: {} });
10364
+ const switchValue = evalBinding(statement.expr, evalContext, thread);
10365
+ let matchingIndex = -1;
10366
+ for (let i = 0; i < statement.cases.length; i++) {
10367
+ const currentCase = statement.cases[i];
10368
+ if (currentCase.caseE === void 0) {
10369
+ matchingIndex = i;
10370
+ break;
10371
+ }
10372
+ if (evalBinding(currentCase.caseE, evalContext, thread) === switchValue) {
10373
+ matchingIndex = i;
10374
+ break;
10375
+ }
10376
+ }
10377
+ const statementFlow = [];
10378
+ if (matchingIndex >= 0) for (let i = matchingIndex; i < statement.cases.length; i++) statementFlow.push(...statement.cases[i].stmts);
10379
+ toUnshift = mapStatementsToQueueItems([...toStatementItems(statementFlow), guard(statement)]);
10380
+ loopScope.breakLabel = toUnshift[toUnshift.length - 1].label;
10381
+ }
10382
+ break;
10383
+ }
10384
+ if (execInfo.removeBlockScope) {
10385
+ if (thread.blocks && thread.blocks.length > 0) thread.blocks.pop();
10386
+ }
10387
+ return {
10388
+ toUnshift,
10389
+ clearToLabel
10390
+ };
10391
+ }
10392
+ function processDeclarations(block, evalContext, thread, declarations, addConst = false, useValue = false, baseValue = void 0) {
10393
+ for (let i = 0; i < declarations.length; i++) {
10394
+ let value;
10395
+ const decl = declarations[i];
10396
+ if (useValue) value = baseValue;
10397
+ else if (decl.expr) value = evalBinding(decl.expr, evalContext, thread);
10398
+ visitDeclaration(block, decl, value, addConst);
10399
+ }
10400
+ function visitDeclaration(block$1, decl, baseValue$1, addConst$1) {
10401
+ if (decl.id) visitIdDeclaration(block$1, decl.id, baseValue$1, addConst$1);
10402
+ else if (decl.aDestr) visitArrayDestruct(block$1, decl.aDestr, baseValue$1, addConst$1);
10403
+ else if (decl.oDestr) visitObjectDestruct(block$1, decl.oDestr, baseValue$1, addConst$1);
10404
+ else throw new Error("Unknown declaration specifier");
10405
+ }
10406
+ function visitIdDeclaration(block$1, id, baseValue$1, addConst$1) {
10407
+ if (block$1.vars[id]) throw new Error(`Variable ${id} is already declared in the current scope.`);
10408
+ block$1.vars[id] = baseValue$1;
10409
+ if (addConst$1) {
10410
+ block$1.constVars ??= /* @__PURE__ */ new Set();
10411
+ block$1.constVars.add(id);
10412
+ }
10413
+ }
10414
+ function visitArrayDestruct(block$1, arrayD, baseValue$1, addConst$1) {
10415
+ for (let i = 0; i < arrayD.length; i++) {
10416
+ const arrDecl = arrayD[i];
10417
+ const value = baseValue$1?.[i];
10418
+ if (arrDecl.id) visitIdDeclaration(block$1, arrDecl.id, value, addConst$1);
10419
+ else if (arrDecl.aDestr) visitArrayDestruct(block$1, arrDecl.aDestr, value, addConst$1);
10420
+ else if (arrDecl.oDestr) visitObjectDestruct(block$1, arrDecl.oDestr, value, addConst$1);
10421
+ }
10422
+ }
10423
+ function visitObjectDestruct(block$1, objectD, baseValue$1, addConst$1) {
10424
+ for (let i = 0; i < objectD.length; i++) {
10425
+ const objDecl = objectD[i];
10426
+ const value = baseValue$1?.[objDecl.id];
10427
+ if (objDecl.aDestr) visitArrayDestruct(block$1, objDecl.aDestr, value, addConst$1);
10428
+ else if (objDecl.oDestr) visitObjectDestruct(block$1, objDecl.oDestr, value, addConst$1);
10429
+ else visitIdDeclaration(block$1, objDecl.alias ?? objDecl.id, value, addConst$1);
10430
+ }
10431
+ }
10432
+ }
10433
+
10434
+ //#endregion
10435
+ //#region src/components-core/script-runner/eval-tree-sync.ts
10436
+ /**
10437
+ * Evaluates a binding represented by the specified expression
10438
+ * @param expr Expression to evaluate
10439
+ * @param evalContext Evaluation context to use
10440
+ * @param thread The logical thread to use for evaluation
10441
+ */
10442
+ function evalBinding(expr, evalContext, thread) {
10443
+ const thisStack = [];
10444
+ ensureMainThread(evalContext);
10445
+ thread ??= evalContext.mainThread;
10446
+ return evalBindingExpressionTree(thisStack, expr, evalContext, thread ?? evalContext.mainThread);
10447
+ }
10448
+ /**
10449
+ * Executes the specified arrow function
10450
+ * @param expr Arrow function expression to run
10451
+ * @param evalContext Evaluation context to use
10452
+ * @param thread The logical thread to use for evaluation
10453
+ * @param args Arguments of the arrow function to execute
10454
+ */
10455
+ function executeArrowExpressionSync(expr, evalContext, thread, ...args) {
10456
+ if (expr.type !== T_ARROW_EXPRESSION) throw new Error("executeArrowExpression expects an 'ArrowExpression' object.");
10457
+ return createArrowFunction(evalBindingExpressionTree, expr)(expr.args, evalContext, thread ?? evalContext.mainThread, ...args);
10458
+ }
10459
+ /**
10460
+ * Evaluates the specified binding expression tree and retrieves the evaluated value
10461
+ * @param expr Binding tree expression
10462
+ * @param thisStack Stack of "this" object to use with function calls
10463
+ * @param evalContext Evaluation context
10464
+ * @param thread The logical thread to use for evaluation
10465
+ * This code uses the JavaScript semantics and errors when evaluating the code.
10466
+ * We use `thisStack` to keep track of the partial results of the evaluation tree so that we can set
10467
+ * the real `this` context when invoking a function.
10468
+ */
10469
+ function evalBindingExpressionTree(thisStack, expr, evalContext, thread) {
10470
+ if (!evalContext.options) evalContext.options = { defaultToOptionalMemberAccess: true };
10471
+ const evaluator = evalBindingExpressionTree;
10472
+ switch (expr.type) {
10473
+ case T_TEMPLATE_LITERAL_EXPRESSION: return evalTemplateLiteral(evaluator, thisStack, expr, evalContext, thread);
10474
+ case T_LITERAL: return evalLiteral(thisStack, expr, thread);
10475
+ case T_IDENTIFIER: return evalIdentifier(thisStack, expr, evalContext, thread);
10476
+ case T_MEMBER_ACCESS_EXPRESSION: return evalMemberAccess(evaluator, thisStack, expr, evalContext, thread);
10477
+ case T_CALCULATED_MEMBER_ACCESS_EXPRESSION: return evalCalculatedMemberAccess(evaluator, thisStack, expr, evalContext, thread);
10478
+ case T_SEQUENCE_EXPRESSION: return evalSequence(evaluator, thisStack, expr, evalContext, thread);
10479
+ case T_ARRAY_LITERAL: return evalArrayLiteral(evaluator, thisStack, expr, evalContext, thread);
10480
+ case T_OBJECT_LITERAL: return evalObjectLiteral(evaluator, thisStack, expr, evalContext, thread);
10481
+ case T_UNARY_EXPRESSION: return evalUnary(evaluator, thisStack, expr, evalContext, thread);
10482
+ case T_BINARY_EXPRESSION: return evalBinary(evaluator, thisStack, expr, evalContext, thread);
10483
+ case T_CONDITIONAL_EXPRESSION: return evalConditional(evaluator, thisStack, expr, evalContext, thread);
10484
+ case T_ASSIGNMENT_EXPRESSION: return evalAssignment(evaluator, thisStack, expr, evalContext, thread);
10485
+ case T_PREFIX_OP_EXPRESSION:
10486
+ case T_POSTFIX_OP_EXPRESSION: return evalPreOrPost(evaluator, thisStack, expr, evalContext, thread);
10487
+ case T_FUNCTION_INVOCATION_EXPRESSION:
10488
+ const funcResult = evalFunctionInvocation(evaluator, thisStack, expr, evalContext, thread);
10489
+ if (isPromise(funcResult)) throw new Error("Promises (async function calls) are not allowed in binding expressions.");
10490
+ return funcResult;
10491
+ case T_ARROW_EXPRESSION: return evalArrow(thisStack, expr, thread);
10492
+ case T_SPREAD_EXPRESSION: throw new Error("Cannot use spread expression (...) with the current intermediate value.");
10493
+ case T_AWAIT_EXPRESSION: throw new Error("XMLUI does not support the await operator.");
10494
+ case T_NEW_EXPRESSION: return evalNewExpression(evaluator, thisStack, expr, evalContext, thread);
10495
+ default: throw new Error(`Unknown expression tree node: ${expr.type}`);
10496
+ }
10497
+ }
10498
+ function evalTemplateLiteral(evaluator, thisStack, expr, evalContext, thread) {
10499
+ const value = evalTemplateLiteralCore(expr.segments.map((s) => {
10500
+ const evaledValue = evaluator(thisStack, s, evalContext, thread);
10501
+ thisStack.pop();
10502
+ return evaledValue;
10503
+ }));
10504
+ setExprValue(expr, { value }, thread);
10505
+ thisStack.push(value);
10506
+ return value;
10507
+ }
10508
+ function evalMemberAccess(evaluator, thisStack, expr, evalContext, thread) {
10509
+ evaluator(thisStack, expr.obj, evalContext, thread);
10510
+ return evalMemberAccessCore(thisStack, expr, evalContext, thread);
10511
+ }
10512
+ function evalCalculatedMemberAccess(evaluator, thisStack, expr, evalContext, thread) {
10513
+ evaluator(thisStack, expr.obj, evalContext, thread);
10514
+ evaluator(thisStack, expr.member, evalContext, thread);
10515
+ thisStack.pop();
10516
+ return evalCalculatedMemberAccessCore(thisStack, expr, evalContext, thread);
10517
+ }
10518
+ function evalSequence(evaluator, thisStack, expr, evalContext, thread) {
10519
+ if (!expr.exprs || expr.exprs.length === 0) throw new Error(`Missing expression sequence`);
10520
+ const result = expr.exprs.map((e) => {
10521
+ const value = evaluator(thisStack, e, evalContext, thread);
10522
+ setExprValue(e, { value }, thread);
10523
+ thisStack.pop();
10524
+ return value;
10525
+ });
10526
+ const lastObj = result[result.length - 1];
10527
+ thisStack.push(lastObj);
10528
+ return lastObj;
10529
+ }
10530
+ function evalArrayLiteral(evaluator, thisStack, expr, evalContext, thread) {
10531
+ const value = [];
10532
+ for (const item of expr.items) if (item.type === T_SPREAD_EXPRESSION) {
10533
+ const spreadArray = evaluator(thisStack, item.expr, evalContext, thread);
10534
+ thisStack.pop();
10535
+ if (!Array.isArray(spreadArray)) throw new Error("Spread operator within an array literal expects an array operand.");
10536
+ value.push(...spreadArray);
10537
+ } else {
10538
+ value.push(evaluator(thisStack, item, evalContext, thread));
10539
+ thisStack.pop();
10540
+ thisStack.push(value);
10541
+ }
10542
+ setExprValue(expr, { value }, thread);
10543
+ thisStack.push(value);
10544
+ return value;
10545
+ }
10546
+ function evalObjectLiteral(evaluator, thisStack, expr, evalContext, thread) {
10547
+ const objectHash = {};
10548
+ for (const prop of expr.props) {
10549
+ if (!Array.isArray(prop)) {
10550
+ const spreadItems = evaluator(thisStack, prop.expr, evalContext, thread);
10551
+ thisStack.pop();
10552
+ if (Array.isArray(spreadItems)) for (let i = 0; i < spreadItems.length; i++) objectHash[i] = spreadItems[i];
10553
+ else if (typeof spreadItems === "object") for (const [key$1, value] of Object.entries(spreadItems)) objectHash[key$1] = value;
10554
+ continue;
10555
+ }
10556
+ let key;
10557
+ switch (prop[0].type) {
10558
+ case T_LITERAL:
10559
+ key = prop[0].value;
10560
+ break;
10561
+ case T_IDENTIFIER:
10562
+ key = prop[0].name;
10563
+ break;
10564
+ default:
10565
+ key = evaluator(thisStack, prop[0], evalContext, thread);
10566
+ thisStack.pop();
10567
+ break;
10568
+ }
10569
+ objectHash[key] = evaluator(thisStack, prop[1], evalContext, thread);
10570
+ thisStack.pop();
10571
+ }
10572
+ setExprValue(expr, { value: objectHash }, thread);
10573
+ thisStack.push(objectHash);
10574
+ return objectHash;
10575
+ }
10576
+ function evalUnary(evaluator, thisStack, expr, evalContext, thread) {
10577
+ evaluator(thisStack, expr.expr, evalContext, thread);
10578
+ thisStack.pop();
10579
+ return evalUnaryCore(expr, thisStack, evalContext, thread);
10580
+ }
10581
+ function evalBinary(evaluator, thisStack, expr, evalContext, thread) {
10582
+ evaluator(thisStack, expr.left, evalContext, thread);
10583
+ thisStack.pop();
10584
+ const l = getExprValue(expr.left, thread)?.value;
10585
+ if (expr.op === "&&" && !l) {
10586
+ setExprValue(expr, { value: l }, thread);
10587
+ thisStack.push(l);
10588
+ return l;
10589
+ }
10590
+ if (expr.op === "||" && l) {
10591
+ setExprValue(expr, { value: l }, thread);
10592
+ thisStack.push(l);
10593
+ return l;
10594
+ }
10595
+ if (expr.op === "??" && l !== null && l !== void 0) {
10596
+ setExprValue(expr, { value: l }, thread);
10597
+ thisStack.push(l);
10598
+ return l;
10599
+ }
10600
+ evaluator(thisStack, expr.right, evalContext, thread);
10601
+ thisStack.pop();
10602
+ return evalBinaryCore(expr, thisStack, evalContext, thread);
10603
+ }
10604
+ function evalConditional(evaluator, thisStack, expr, evalContext, thread) {
10605
+ const condition = evaluator(thisStack, expr.cond, evalContext, thread);
10606
+ thisStack.pop();
10607
+ const value = evaluator(thisStack, condition ? expr.thenE : expr.elseE, evalContext, thread);
10608
+ setExprValue(expr, { value }, thread);
10609
+ return value;
10610
+ }
10611
+ function evalAssignment(evaluator, thisStack, expr, evalContext, thread) {
10612
+ const leftValue = expr.leftValue;
10613
+ const rootScope = getRootIdScope(leftValue, evalContext, thread);
10614
+ const updatesState = rootScope && rootScope.type !== "block";
10615
+ if (updatesState && evalContext.onWillUpdate) evalContext.onWillUpdate(rootScope, rootScope.name, "assignment");
10616
+ evaluator(thisStack, leftValue, evalContext, thread);
10617
+ thisStack.pop();
10618
+ evaluator(thisStack, expr.expr, evalContext, thread);
10619
+ thisStack.pop();
10620
+ const value = evalAssignmentCore(thisStack, expr, evalContext, thread);
10621
+ if (updatesState && evalContext.onDidUpdate) evalContext.onDidUpdate(rootScope, rootScope.name, "assignment");
10622
+ return value;
10623
+ }
10624
+ function evalPreOrPost(evaluator, thisStack, expr, evalContext, thread) {
10625
+ const rootScope = getRootIdScope(expr.expr, evalContext, thread);
10626
+ const updatesState = rootScope && rootScope.type !== "block";
10627
+ if (updatesState && evalContext.onWillUpdate) evalContext.onWillUpdate(rootScope, rootScope.name, "pre-post");
10628
+ evaluator(thisStack, expr.expr, evalContext, thread);
10629
+ thisStack.pop();
10630
+ const value = evalPreOrPostCore(thisStack, expr, evalContext, thread);
10631
+ if (updatesState && evalContext.onDidUpdate) evalContext.onDidUpdate(rootScope, rootScope.name, "pre-post");
10632
+ return value;
10633
+ }
10634
+ function evalFunctionInvocation(evaluator, thisStack, expr, evalContext, thread) {
10635
+ let functionObj;
10636
+ let implicitContextObject = null;
10637
+ if (expr.obj.type === T_MEMBER_ACCESS_EXPRESSION) {
10638
+ const hostObject = evaluator(thisStack, expr.obj.obj, evalContext, thread);
10639
+ functionObj = evalMemberAccessCore(thisStack, expr.obj, evalContext, thread);
10640
+ if (expr.obj.obj.type === T_IDENTIFIER && hostObject?._SUPPORT_IMPLICIT_CONTEXT) implicitContextObject = hostObject;
10641
+ } else functionObj = evaluator(thisStack, expr.obj, evalContext, thread);
10642
+ thisStack.pop();
10643
+ const functionArgs = [];
10644
+ if (isArrowExpressionObject(functionObj)) {
10645
+ functionArgs.push(functionObj.args, evalContext, thread, ...expr.arguments.map((a) => ({
10646
+ ...a,
10647
+ _EXPRESSION_: true
10648
+ })));
10649
+ functionObj = createArrowFunction(evaluator, functionObj);
10650
+ } else if (expr.obj.type === T_ARROW_EXPRESSION) functionArgs.push(expr.obj.args, evalContext, thread, ...expr.arguments.map((a) => ({
10651
+ ...a,
10652
+ _EXPRESSION_: true
10653
+ })));
10654
+ else {
10655
+ for (let i = 0; i < expr.arguments.length; i++) {
10656
+ const arg = expr.arguments[i];
10657
+ if (arg.type === T_SPREAD_EXPRESSION) {
10658
+ const funcArg = evaluator([], arg.expr, evalContext, thread);
10659
+ if (!Array.isArray(funcArg)) throw new Error("Spread operator within a function invocation expects an array operand.");
10660
+ functionArgs.push(...funcArg);
10661
+ } else if (arg.type === T_ARROW_EXPRESSION) {
10662
+ const funcArg = createArrowFunction(evaluator, arg);
10663
+ const wrappedFunc = (...args) => funcArg(arg.args, evalContext, thread, ...args);
10664
+ functionArgs.push(wrappedFunc);
10665
+ } else {
10666
+ const funcArg = evaluator([], arg, evalContext, thread);
10667
+ if (isArrowExpressionObject(funcArg)) {
10668
+ const wrappedFuncArg = createArrowFunction(evaluator, funcArg);
10669
+ const wrappedFunc = (...args) => wrappedFuncArg(funcArg.args, evalContext, thread, ...args);
10670
+ functionArgs.push(wrappedFunc);
10671
+ } else functionArgs.push(funcArg);
10672
+ }
10673
+ }
10674
+ if (implicitContextObject) if (evalContext.implicitContextGetter) {
10675
+ const implicitContext = evalContext.implicitContextGetter(implicitContextObject);
10676
+ functionArgs.unshift(implicitContext);
10677
+ } else throw new Error("Cannot use implicitContextGetter, it is undefined");
10678
+ }
10679
+ const bannedInfo = isBannedFunction(functionObj);
10680
+ if (bannedInfo.banned) throw new Error(`Function ${bannedInfo.func?.name ?? "unknown"} is not allowed to call. ${bannedInfo?.help ?? ""}`);
10681
+ const currentContext = thisStack.length > 0 ? thisStack.pop() : evalContext.localContext;
10682
+ const rootScope = getRootIdScope(expr.obj, evalContext, thread);
10683
+ const updatesState = rootScope && rootScope.type !== "block";
10684
+ if (updatesState && evalContext.onWillUpdate) evalContext.onWillUpdate(rootScope, rootScope.name, "function-call");
10685
+ const value = evalContext.options?.defaultToOptionalMemberAccess ? functionObj?.call(currentContext, ...functionArgs) : functionObj.call(currentContext, ...functionArgs);
10686
+ if (updatesState && evalContext.onDidUpdate) evalContext.onDidUpdate(rootScope, rootScope.name, "function-call");
10687
+ setExprValue(expr, { value }, thread);
10688
+ thisStack.push(value);
10689
+ return value;
10690
+ }
10691
+ function evalNewExpression(evaluator, thisStack, expr, evalContext, thread) {
10692
+ const allowedConstructors = new Map([
10693
+ ["String", String],
10694
+ ["Date", Date],
10695
+ ["Blob", Blob]
10696
+ ]);
10697
+ const constructorObj = evaluator(thisStack, expr.callee, evalContext, thread);
10698
+ thisStack.pop();
10699
+ let allowedConstructor = null;
10700
+ for (const [name, ctor] of allowedConstructors) if (constructorObj === ctor) {
10701
+ allowedConstructor = ctor;
10702
+ break;
10703
+ }
10704
+ if (!allowedConstructor) {
10705
+ const constructorName = constructorObj?.name || "unknown";
10706
+ throw new Error(`XMLUI does not support the new operator with constructor '${constructorName}'. Only String, Date, and Blob are allowed.`);
10707
+ }
10708
+ const constructorArgs = [];
10709
+ for (let i = 0; i < expr.arguments.length; i++) {
10710
+ const arg = expr.arguments[i];
10711
+ if (arg.type === T_SPREAD_EXPRESSION) {
10712
+ const funcArg = evaluator([], arg.expr, evalContext, thread);
10713
+ if (!Array.isArray(funcArg)) throw new Error("Spread operator within a new expression expects an array operand.");
10714
+ constructorArgs.push(...funcArg);
10715
+ } else {
10716
+ const funcArg = evaluator([], arg, evalContext, thread);
10717
+ constructorArgs.push(funcArg);
10718
+ }
10719
+ }
10720
+ const value = new allowedConstructor(...constructorArgs);
10721
+ setExprValue(expr, { value }, thread);
10722
+ thisStack.push(value);
10723
+ return value;
10724
+ }
10725
+ function createArrowFunction(evaluator, expr) {
10726
+ return (...args) => {
10727
+ const runTimeEvalContext = args[1];
10728
+ const runtimeThread = args[2];
10729
+ const workingThread = {
10730
+ parent: runtimeThread,
10731
+ childThreads: [],
10732
+ blocks: [{ vars: {} }],
10733
+ loops: [],
10734
+ breakLabelValue: -1,
10735
+ closures: expr.closureContext
10736
+ };
10737
+ runtimeThread.childThreads.push(workingThread);
10738
+ if (expr.name) {
10739
+ const functionBlock = { vars: {} };
10740
+ workingThread.blocks ??= [];
10741
+ workingThread.blocks.push(functionBlock);
10742
+ functionBlock.vars[expr.name] = expr;
10743
+ functionBlock.constVars = new Set([expr.name]);
10744
+ }
10745
+ const arrowBlock = { vars: {} };
10746
+ workingThread.blocks ??= [];
10747
+ workingThread.blocks.push(arrowBlock);
10748
+ const argSpecs = args[0];
10749
+ let restFound = false;
10750
+ for (let i = 0; i < argSpecs.length; i++) {
10751
+ const argSpec = argSpecs[i];
10752
+ let decl;
10753
+ switch (argSpec.type) {
10754
+ case T_IDENTIFIER:
10755
+ decl = {
10756
+ type: T_VAR_DECLARATION,
10757
+ id: argSpec.name
10758
+ };
10759
+ break;
10760
+ case T_DESTRUCTURE:
10761
+ decl = {
10762
+ type: T_VAR_DECLARATION,
10763
+ id: argSpec.id,
10764
+ aDestr: argSpec.aDestr,
10765
+ oDestr: argSpec.oDestr
10766
+ };
10767
+ break;
10768
+ case T_SPREAD_EXPRESSION:
10769
+ restFound = true;
10770
+ decl = {
10771
+ type: T_VAR_DECLARATION,
10772
+ id: argSpec.expr.name
10773
+ };
10774
+ break;
10775
+ default: throw new Error("Unexpected arrow argument specification");
10776
+ }
10777
+ if (decl) if (restFound) {
10778
+ const restArgs = args.slice(i + 3);
10779
+ let argVals = [];
10780
+ for (const arg of restArgs) if (arg?._EXPRESSION_) argVals.push(evaluator([], arg, runTimeEvalContext, runtimeThread));
10781
+ else argVals.push(arg);
10782
+ processDeclarations(arrowBlock, runTimeEvalContext, runtimeThread, [decl], false, true, argVals);
10783
+ } else {
10784
+ let argVal = args[i + 3];
10785
+ if (argVal?._EXPRESSION_) argVal = evaluator([], argVal, runTimeEvalContext, runtimeThread);
10786
+ processDeclarations(arrowBlock, runTimeEvalContext, runtimeThread, [decl], false, true, argVal);
10787
+ }
10788
+ }
10789
+ let returnValue;
10790
+ let statements;
10791
+ switch (expr.statement.type) {
10792
+ case T_EMPTY_STATEMENT:
10793
+ statements = [];
10794
+ break;
10795
+ case T_EXPRESSION_STATEMENT:
10796
+ statements = [{
10797
+ type: T_RETURN_STATEMENT,
10798
+ nodeId: createXmlUiTreeNodeId(),
10799
+ expr: expr.statement.expr
10800
+ }];
10801
+ break;
10802
+ case T_BLOCK_STATEMENT:
10803
+ statements = expr.statement.stmts;
10804
+ break;
10805
+ default: throw new Error(`Arrow expression with a body of '${expr.statement.type}' is not supported yet.`);
10806
+ }
10807
+ processStatementQueue(statements, runTimeEvalContext, workingThread);
10808
+ returnValue = workingThread.returnValue;
10809
+ const workingIndex = runtimeThread.childThreads.indexOf(workingThread);
10810
+ if (workingIndex < 0) throw new Error("Cannot find thread to remove.");
10811
+ runtimeThread.childThreads.splice(workingIndex, 1);
10812
+ workingThread.blocks.pop();
10813
+ return returnValue;
10814
+ };
10815
+ }
10816
+
10817
+ //#endregion
10818
+ //#region src/components-core/utils/LruCache.ts
10819
+ /**
10820
+ * A single node of the LRU cache
10821
+ */
10822
+ var DoublyLinkedNode = class {
10823
+ constructor(value, key) {
10824
+ this.value = value;
10825
+ this.key = key;
10826
+ this.next = void 0;
10827
+ this.prev = void 0;
10828
+ }
10829
+ };
10830
+ /**
10831
+ * We keep values in the LRU cache in a doubly linked list
10832
+ */
10833
+ var DoublyLinkedList = class {
10834
+ constructor() {
10835
+ this.size = 0;
10836
+ this.head = void 0;
10837
+ this.tail = void 0;
10838
+ this.size = 0;
10839
+ }
10840
+ /**
10841
+ * Adds a new node to the head of the list
10842
+ * @param node The node to add to head of list
10843
+ */
10844
+ unshift(node) {
10845
+ if (this.size === 0) {
10846
+ this.head = node;
10847
+ this.tail = node;
10848
+ this.size++;
10849
+ } else {
10850
+ this.head.prev = node;
10851
+ node.next = this.head;
10852
+ node.prev = void 0;
10853
+ this.head = node;
10854
+ this.size++;
10855
+ }
10856
+ }
10857
+ /**
10858
+ * Remove least recently used node from tail
10859
+ */
10860
+ pop() {
10861
+ const node = this.tail;
10862
+ if (!node) return;
10863
+ else if (this.head === this.tail) {
10864
+ this.head = void 0;
10865
+ this.tail = void 0;
10866
+ } else this.tail.prev.next = void 0;
10867
+ this.tail = node.prev;
10868
+ this.size--;
10869
+ return node;
10870
+ }
10871
+ /**
10872
+ * Moves the specified node to the head
10873
+ */
10874
+ moveToHead(node) {
10875
+ if (node === this.head) return;
10876
+ if (node === this.head && node === this.tail) return;
10877
+ if (node === this.tail) {
10878
+ this.tail = this.tail.prev;
10879
+ this.tail.next = void 0;
10880
+ node.next = this.head;
10881
+ this.head.prev = node;
10882
+ this.head = node;
10883
+ node.prev = void 0;
10884
+ } else {
10885
+ node.prev.next = node.next;
10886
+ node.next.prev = node.prev;
10887
+ node.next = this.head;
10888
+ this.head.prev = node;
10889
+ this.head = node;
10890
+ node.prev = void 0;
10891
+ }
10892
+ }
10893
+ };
10894
+ /**
10895
+ * This class implements the LRU cache
10896
+ */
10897
+ var LRUCache = class {
10898
+ constructor(maxSize) {
10899
+ this.maxSize = maxSize;
10900
+ this.store = {};
10901
+ this.list = new DoublyLinkedList();
10902
+ }
10903
+ /**
10904
+ * Gets the number of items stored in the cache
10905
+ */
10906
+ get length() {
10907
+ return this.list.size;
10908
+ }
10909
+ /**
10910
+ * Gets the value with the specified key
10911
+ * @param key
10912
+ */
10913
+ get(key) {
10914
+ const existingNode = this.store[key];
10915
+ if (existingNode) this.list.moveToHead(existingNode);
10916
+ return existingNode?.value;
10917
+ }
10918
+ /**
10919
+ * Sets the value for a particular key within the cache
10920
+ * @param key Cache item key
10921
+ * @param value Cache item value
10922
+ */
10923
+ set(key, value) {
10924
+ const existingNode = this.get(key);
10925
+ if (existingNode) existingNode.value = value;
10926
+ const newNode = new DoublyLinkedNode(value, key);
10927
+ this.store[key] = newNode;
10928
+ this.list.unshift(newNode);
10929
+ if (this.hasReachedMaxSize()) this.evictLeastRecentlyUsed();
10930
+ }
10931
+ hasReachedMaxSize() {
10932
+ return this.list.size === this.maxSize + 1;
10933
+ }
10934
+ evictLeastRecentlyUsed() {
10935
+ const evictedNode = this.list.pop();
10936
+ delete this.store[evictedNode.key];
10937
+ }
10938
+ };
10939
+
10940
+ //#endregion
10941
+ //#region src/components-core/utils/extractParam.ts
10942
+ /**
10943
+ * Extract the value of the specified parameter from the given view container state
10944
+ * @param state The state of the view container
10945
+ * @param param Parameter to extract
10946
+ * @param appContext Application context to use
10947
+ * @param strict Strict evaluation?
10948
+ * @param extractContext
10949
+ * @returns
10950
+ */
10951
+ function extractParam(state, param, appContext = void 0, strict = false, extractContext = { didResolve: false }) {
10952
+ if (typeof param === "string") {
10953
+ const paramSegments = parseParameterString(param);
10954
+ if (paramSegments.length === 0) return param;
10955
+ if (paramSegments[0].type === "literal" && paramSegments[0].value.trim() === "") paramSegments.shift();
10956
+ if (paramSegments.length === 0) return param;
10957
+ const lastSegment = paramSegments[paramSegments.length - 1];
10958
+ if (lastSegment.type === "literal" && lastSegment.value.trim() === "") paramSegments.pop();
10959
+ if (paramSegments.length === 0) return param;
10960
+ if (paramSegments.length === 1) if (paramSegments[0].type === "literal") return paramSegments[0].value;
10961
+ else {
10962
+ extractContext.didResolve = true;
10963
+ return evalBinding(paramSegments[0].value, {
10964
+ localContext: state,
10965
+ appContext,
10966
+ options: { defaultToOptionalMemberAccess: true }
10967
+ });
10968
+ }
10969
+ let result = "";
10970
+ paramSegments.forEach((ps) => {
10971
+ if (ps.type === "literal") result += ps.value;
10972
+ else {
10973
+ extractContext.didResolve = true;
10974
+ const exprValue = evalBinding(ps.value, {
10975
+ localContext: state,
10976
+ appContext,
10977
+ options: { defaultToOptionalMemberAccess: true }
10978
+ });
10979
+ if (exprValue?.toString) result += exprValue.toString();
10980
+ }
10981
+ });
10982
+ return result;
10983
+ }
10984
+ if (strict) return param;
10985
+ if (Array.isArray(param)) {
10986
+ const arrayExtractContext = { didResolve: false };
10987
+ let resolvedChildren = param.map((childParam) => extractParam(state, childParam, appContext, false, arrayExtractContext));
10988
+ if (arrayExtractContext.didResolve) {
10989
+ extractContext.didResolve = true;
10990
+ return resolvedChildren;
10991
+ }
10992
+ return param;
10993
+ }
10994
+ if ((0, lodash_es.isPlainObject)(param)) {
10995
+ const objectExtractContext = { didResolve: false };
10996
+ const substitutedObject = {};
10997
+ Object.entries(param).forEach(([key, value]) => {
10998
+ substitutedObject[key] = extractParam(state, value, appContext, false, objectExtractContext);
10999
+ });
11000
+ if (objectExtractContext.didResolve) {
11001
+ extractContext.didResolve = true;
11002
+ return substitutedObject;
11003
+ }
11004
+ return param;
11005
+ }
11006
+ return param;
11007
+ }
11008
+ const extractedObjectCache = new LRUCache(1024 * 10);
11009
+
11010
+ //#endregion
11011
+ //#region src/language-server/base/text-document.ts
11012
+ var DocumentCursor = class {
11013
+ constructor(text) {
11014
+ this.text = text;
11015
+ this.newlineOffsets = [0];
11016
+ for (let i = 0; i < text.length; i++) {
11017
+ const ch = text.charCodeAt(i);
11018
+ if (isEOL(ch)) {
11019
+ if (ch === 13 && i + 1 < text.length && text.charCodeAt(i + 1) === 10) i++;
11020
+ this.newlineOffsets.push(i + 1);
11021
+ }
11022
+ }
11023
+ }
11024
+ get textLength() {
11025
+ return this.text.length;
11026
+ }
11027
+ get lineCount() {
11028
+ return this.newlineOffsets.length;
11029
+ }
11030
+ /**
11031
+ * Converts a zero-based offset to a position.
11032
+ *
11033
+ * @param offset A zero-based offset.
11034
+ * @return A valid {@link Position position}.
11035
+ * @example The text document "ab\ncd" produces:
11036
+ * * position { line: 0, character: 0 } for `offset` 0.
11037
+ * * position { line: 0, character: 1 } for `offset` 1.
11038
+ * * position { line: 0, character: 2 } for `offset` 2.
11039
+ * * position { line: 1, character: 0 } for `offset` 3.
11040
+ * * position { line: 1, character: 1 } for `offset` 4.
11041
+ */
11042
+ positionAt(offset) {
11043
+ offset = Math.max(Math.min(offset, this.textLength), 0);
11044
+ const lineOffsets = this.newlineOffsets;
11045
+ let low = 0, high = lineOffsets.length;
11046
+ if (high === 0) return {
11047
+ line: 0,
11048
+ character: offset
11049
+ };
11050
+ while (low < high) {
11051
+ const mid = Math.floor((low + high) / 2);
11052
+ if (lineOffsets[mid] > offset) high = mid;
11053
+ else low = mid + 1;
11054
+ }
11055
+ const line = low - 1;
11056
+ return {
11057
+ line,
11058
+ character: offset - lineOffsets[line]
11059
+ };
11060
+ }
11061
+ /**
11062
+ * Converts the position to a zero-based offset.
11063
+ * Invalid positions are adjusted as described in {@link Position.line}
11064
+ * and {@link Position.character}.
11065
+ *
11066
+ * @param position A position.
11067
+ * @return A valid zero-based offset.
11068
+ */
11069
+ offsetAt(position) {
11070
+ if (position.line >= this.newlineOffsets.length) return this.textLength;
11071
+ else if (position.line < 0) return 0;
11072
+ const lineOffset = this.newlineOffsets[position.line];
11073
+ if (position.character <= 0) return lineOffset;
11074
+ const nextLineOffset = position.line + 1 < this.newlineOffsets.length ? this.newlineOffsets[position.line + 1] : this.textLength;
11075
+ return Math.min(lineOffset + position.character, nextLineOffset);
11076
+ }
11077
+ offsetToDisplayPos(offset) {
11078
+ const pos = this.positionAt(offset);
11079
+ return {
11080
+ line: pos.line + 1,
11081
+ character: pos.character + 1
11082
+ };
11083
+ }
11084
+ getSurroundingContext(pos, end, surroundingLines) {
11085
+ const startLine = this.positionAt(pos).line;
11086
+ const endLine = this.positionAt(end).line;
11087
+ const contextStartLine = Math.max(0, startLine - surroundingLines);
11088
+ const contextPos = this.newlineOffsets[contextStartLine];
11089
+ const nextLineAfterContext = Math.min(this.lineCount - 1, endLine + surroundingLines) + 1;
11090
+ let contextEnd;
11091
+ if (nextLineAfterContext < this.lineCount) {
11092
+ const nextLineStart = this.newlineOffsets[nextLineAfterContext];
11093
+ let eolLength = 1;
11094
+ if (nextLineStart > 0 && this.text.charCodeAt(nextLineStart - 1) === 10) {
11095
+ if (nextLineStart > 1 && this.text.charCodeAt(nextLineStart - 2) === 13) eolLength = 2;
11096
+ }
11097
+ contextEnd = nextLineStart - eolLength;
11098
+ } else contextEnd = this.textLength;
11099
+ return {
11100
+ contextPos,
11101
+ contextEnd
11102
+ };
11103
+ }
11104
+ rangeAt(range) {
11105
+ return {
11106
+ start: this.positionAt(range.pos),
11107
+ end: this.positionAt(range.end)
11108
+ };
11109
+ }
11110
+ offsetRangeAt(range) {
11111
+ return {
11112
+ pos: this.offsetAt(range.start),
11113
+ end: this.offsetAt(range.end)
11114
+ };
11115
+ }
11116
+ };
11117
+ function isEOL(char) {
11118
+ return char === 13 || char === 10;
11119
+ }
11120
+
11121
+ //#endregion
11122
+ //#region src/parsers/xmlui-parser/parser.ts
11123
+ const RECOVER_FILE = [
11124
+ SyntaxKind.CData,
11125
+ SyntaxKind.Script,
11126
+ SyntaxKind.OpenNodeStart
11127
+ ];
11128
+ const RECOVER_OPEN_TAG = [
9257
11129
  SyntaxKind.OpenNodeStart,
9258
11130
  SyntaxKind.NodeEnd,
9259
11131
  SyntaxKind.NodeClose,
@@ -10220,9 +12092,9 @@ async function convertResourcesDir(distRoot, flatDist, filePrefix) {
10220
12092
  }
10221
12093
  return ret;
10222
12094
  }
10223
- function removeLeadingSlashForPath(path$6) {
10224
- if (path$6.startsWith("/")) return path$6.substring(1);
10225
- return path$6;
12095
+ function removeLeadingSlashForPath(path$8) {
12096
+ if (path$8.startsWith("/")) return path$8.substring(1);
12097
+ return path$8;
10226
12098
  }
10227
12099
  const build = async ({ buildMode = "CONFIG_ONLY", flatDist = false, withMock = false, withHostingMetaFiles = false, withRelativeRoot = false }) => {
10228
12100
  const flatDistUiPrefix = "ui_";
@@ -10411,6 +12283,420 @@ const preview = async ({ proxy }) => {
10411
12283
  }
10412
12284
  };
10413
12285
 
12286
+ //#endregion
12287
+ //#region bin/ssg/discoverPaths.ts
12288
+ function getPagesComponent(comp) {
12289
+ if (!comp) return null;
12290
+ if (comp.type === "Pages") return comp;
12291
+ if (Array.isArray(comp.children)) for (const child of comp.children) {
12292
+ const result = getPagesComponent(child);
12293
+ if (result) return result;
12294
+ }
12295
+ return null;
12296
+ }
12297
+ function substituteParams(url, params) {
12298
+ let variants = [url];
12299
+ for (const [key, value] of Object.entries(params)) {
12300
+ if (!variants.some((variant) => variant.includes(`:${key}`))) continue;
12301
+ const values = Array.isArray(value) ? value : [value];
12302
+ const next = [];
12303
+ for (const variant of variants) {
12304
+ if (!variant.includes(`:${key}`)) {
12305
+ next.push(variant);
12306
+ continue;
12307
+ }
12308
+ for (const paramValue of values) {
12309
+ if (paramValue === null || paramValue === void 0) continue;
12310
+ next.push(variant.split(`:${key}`).join(String(paramValue)));
12311
+ }
12312
+ }
12313
+ variants = next;
12314
+ }
12315
+ return variants.filter((variant) => !variant.includes(":"));
12316
+ }
12317
+ function normalizeRoute$1(pathname) {
12318
+ let route = pathname.trim();
12319
+ if (route.length === 0) return "/";
12320
+ if (!route.startsWith("/")) route = `/${route}`;
12321
+ if (route !== "/" && route.endsWith("/")) route = route.slice(0, -1);
12322
+ return route;
12323
+ }
12324
+ async function readAllFilesRecursive(dir) {
12325
+ const files = [];
12326
+ let entries;
12327
+ try {
12328
+ entries = await (0, node_fs_promises.readdir)(dir, { withFileTypes: true });
12329
+ } catch {
12330
+ return files;
12331
+ }
12332
+ for (const entry of entries) {
12333
+ const fullPath = node_path.default.join(dir, entry.name);
12334
+ if (entry.isDirectory()) {
12335
+ files.push(...await readAllFilesRecursive(fullPath));
12336
+ continue;
12337
+ }
12338
+ files.push(fullPath);
12339
+ }
12340
+ return files;
12341
+ }
12342
+ async function discoverPaths(cwd) {
12343
+ const mainXmluiPath = node_path.default.resolve(cwd, "src", "Main.xmlui");
12344
+ const discovered = /* @__PURE__ */ new Set();
12345
+ let mainXmluiTextContent;
12346
+ try {
12347
+ mainXmluiTextContent = await (0, node_fs_promises.readFile)(mainXmluiPath, "utf-8");
12348
+ } catch {
12349
+ return ["/"];
12350
+ }
12351
+ const { parse: parse$2, getText } = createXmlUiParser(mainXmluiTextContent);
12352
+ const pagesComp = getPagesComponent(nodeToComponentDef(parse$2().node, getText, 0));
12353
+ if (pagesComp?.children) for (const page of pagesComp.children) {
12354
+ const url = page.props?.url;
12355
+ if (typeof url !== "string" || url.trim().length === 0) continue;
12356
+ if (page.props?.staticPaths) try {
12357
+ const staticPaths = extractParam({}, page.props.staticPaths, void 0, true);
12358
+ if (Array.isArray(staticPaths)) for (const entry of staticPaths) {
12359
+ if (!entry || typeof entry !== "object") continue;
12360
+ const params = entry.params;
12361
+ if (!params || typeof params !== "object") continue;
12362
+ for (const resolved of substituteParams(url, params)) discovered.add(normalizeRoute$1(resolved));
12363
+ }
12364
+ } catch (error) {
12365
+ console.warn(`Failed to evaluate staticPaths for '${url}'`, error);
12366
+ }
12367
+ if (!url.includes(":") && !url.includes("*")) discovered.add(normalizeRoute$1(url));
12368
+ }
12369
+ const contentDir = node_path.default.resolve(cwd, "content");
12370
+ const contentFiles = await readAllFilesRecursive(contentDir);
12371
+ for (const filePath of contentFiles) {
12372
+ if (!filePath.endsWith(".md")) continue;
12373
+ const relative = node_path.default.relative(contentDir, filePath).replace(/\\/g, "/");
12374
+ if (relative.startsWith("pages/") || relative.includes("/pages/")) continue;
12375
+ discovered.add(normalizeRoute$1(`/${relative.replace(/\.md$/, "")}`));
12376
+ }
12377
+ if (discovered.size === 0) return ["/"];
12378
+ return [...discovered];
12379
+ }
12380
+ async function pathExists(targetPath) {
12381
+ try {
12382
+ await (0, node_fs_promises.stat)(targetPath);
12383
+ return true;
12384
+ } catch {
12385
+ return false;
12386
+ }
12387
+ }
12388
+
12389
+ //#endregion
12390
+ //#region bin/ssg.ts
12391
+ const TEMP_ENTRY_FILE_NAME = ".xmlui-ssg-entry.tsx";
12392
+ const EXTENSION_FILE_CANDIDATES = [
12393
+ "extensions.ts",
12394
+ "extensions.tsx",
12395
+ "extensions.mts",
12396
+ "extensions.mjs",
12397
+ "extensions.cjs",
12398
+ "extensions.js"
12399
+ ];
12400
+ function log(message) {
12401
+ console.log(`[xmlui ssg] ${message}`);
12402
+ }
12403
+ function normalizeRoute(pathname) {
12404
+ let normalized = new URL(pathname, "http://localhost").pathname;
12405
+ if (!normalized.startsWith("/")) normalized = `/${normalized}`;
12406
+ if (normalized !== "/" && normalized.endsWith("/")) normalized = normalized.slice(0, -1);
12407
+ return normalized || "/";
12408
+ }
12409
+ function getOutputHtmlPath(outDir, routePath) {
12410
+ if (routePath === "/") return node_path.default.join(outDir, "index.html");
12411
+ return node_path.default.join(outDir, routePath.slice(1), "index.html");
12412
+ }
12413
+ function executeInlineScripts(html) {
12414
+ const scriptRegex = /<script\b([^>]*)>([\s\S]*?)<\/script>/gi;
12415
+ let match;
12416
+ while ((match = scriptRegex.exec(html)) !== null) {
12417
+ const attrs = match[1] || "";
12418
+ const content = (match[2] || "").trim();
12419
+ if (/\bsrc\s*=/.test(attrs) || !content) continue;
12420
+ try {
12421
+ node_vm.default.runInThisContext(content);
12422
+ } catch (error) {
12423
+ log(`inline script execution warning: ${content.slice(0, 500)}`);
12424
+ console.error(error);
12425
+ }
12426
+ }
12427
+ }
12428
+ function mergeHtmlClasses(shellHtml, htmlClasses) {
12429
+ if (!htmlClasses.trim()) return shellHtml;
12430
+ return shellHtml.replace(/<html([^>]*?)>/i, (full, attributes) => {
12431
+ const classMatch = /class=["']([^"']*)["']/.exec(attributes);
12432
+ if (!classMatch) return `<html${attributes} class="${htmlClasses}">`;
12433
+ const merged = `${classMatch[1].trim()} ${htmlClasses}`.trim();
12434
+ return `<html${attributes.replace(classMatch[0], `class="${merged}"`)}>`;
12435
+ });
12436
+ }
12437
+ function injectStylesIntoHead(shellHtml, ssrStyles, ssrHashes) {
12438
+ if (!ssrStyles.trim()) return shellHtml;
12439
+ const styleTag = `<style data-style-registry="true" data-ssr-hashes="${ssrHashes}">${ssrStyles}</style>`;
12440
+ if (shellHtml.includes("</head>")) return shellHtml.replace("</head>", `${styleTag}</head>`);
12441
+ return `${styleTag}${shellHtml}`;
12442
+ }
12443
+ function injectMarkup(shellHtml, markup) {
12444
+ const rootRegex = /<div([^>]*\bid=["']root["'][^>]*)>[\s\S]*?<\/div>/i;
12445
+ if (rootRegex.test(shellHtml)) return shellHtml.replace(rootRegex, `<div$1>${markup}</div>`);
12446
+ if (shellHtml.includes("</body>")) return shellHtml.replace("</body>", `${markup}</body>`);
12447
+ return `${shellHtml}${markup}`;
12448
+ }
12449
+ function applyRenderToShell(shellHtml, renderResult) {
12450
+ let html = shellHtml;
12451
+ html = mergeHtmlClasses(html, renderResult.htmlClasses);
12452
+ html = injectStylesIntoHead(html, renderResult.ssrStyles, renderResult.ssrHashes);
12453
+ html = injectMarkup(html, renderResult.markup);
12454
+ if (!html.toLowerCase().startsWith("<!doctype")) return `<!DOCTYPE html>${html}`;
12455
+ return html;
12456
+ }
12457
+ function getSsgEntrySource(extensionImportSpecifiers) {
12458
+ return `
12459
+ import React from "react";
12460
+ import { renderToString } from "react-dom/server";
12461
+ import { StaticRouter } from "react-router-dom/server";
12462
+ import {
12463
+ StandaloneApp,
12464
+ StandaloneExtensionManager as ExtMgr,
12465
+ StyleProvider,
12466
+ StyleRegistry,
12467
+ } from "xmlui";
12468
+
12469
+ const runtime = import.meta.glob("./src/**", { eager: true });
12470
+
12471
+ const loadedExtensions: any[] = [];
12472
+ async function loadExtensions() {
12473
+ const extensions: any[] = [];
12474
+ ${extensionImportSpecifiers.map((spec, index) => {
12475
+ return ` try {\n const m${index} = await import(${JSON.stringify(spec)});\n extensions.push(m${index}.default ?? m${index});\n } catch (error) {\n console.warn(\"[xmlui ssg] failed to load extension ${spec}\");\n console.error(error);\n }`;
12476
+ }).join("\n")}
12477
+ return extensions;
12478
+ }
12479
+
12480
+ loadedExtensions.push(...(await loadExtensions()));
12481
+
12482
+ function createExtensionManager() {
12483
+ const extensionManager = new ExtMgr();
12484
+ extensionManager.registerExtension(loadedExtensions || []);
12485
+ return extensionManager;
12486
+ }
12487
+
12488
+ export function renderPath(pathname: string) {
12489
+ if (typeof globalThis !== "undefined") {
12490
+ globalThis.location = new URL(pathname, "http://localhost") as unknown as Location;
12491
+ }
12492
+
12493
+ const registry = new StyleRegistry();
12494
+ const app = (
12495
+ <StyleProvider styleRegistry={registry}>
12496
+ <StaticRouter location={pathname}>
12497
+ <StandaloneApp runtime={runtime} extensionManager={createExtensionManager()} />
12498
+ </StaticRouter>
12499
+ </StyleProvider>
12500
+ );
12501
+
12502
+ const markup = renderToString(app);
12503
+ return {
12504
+ markup,
12505
+ ssrStyles: registry.getSsrStyles(),
12506
+ ssrHashes: Array.from(registry.cache.keys()).join(","),
12507
+ htmlClasses: registry.getRootClasses(),
12508
+ };
12509
+ }
12510
+ `;
12511
+ }
12512
+ async function findMonorepoRoot(startDir) {
12513
+ let currentDir = startDir;
12514
+ for (let depth$1 = 0; depth$1 < 12; depth$1++) {
12515
+ const packageJsonPath = node_path.default.join(currentDir, "package.json");
12516
+ if (await pathExists(packageJsonPath)) try {
12517
+ if (JSON.parse(await (0, node_fs_promises.readFile)(packageJsonPath, "utf-8")).workspaces) return currentDir;
12518
+ } catch {}
12519
+ const parent = node_path.default.dirname(currentDir);
12520
+ if (parent === currentDir) break;
12521
+ currentDir = parent;
12522
+ }
12523
+ return null;
12524
+ }
12525
+ async function getWorkspacePatterns(monorepoRoot) {
12526
+ const packageJsonPath = node_path.default.join(monorepoRoot, "package.json");
12527
+ const pkg = JSON.parse(await (0, node_fs_promises.readFile)(packageJsonPath, "utf-8"));
12528
+ if (Array.isArray(pkg.workspaces)) return pkg.workspaces;
12529
+ if (Array.isArray(pkg.workspaces?.packages)) return pkg.workspaces.packages;
12530
+ return [];
12531
+ }
12532
+ async function getExtensionImportSpecifiers(cwd) {
12533
+ for (const fileName of EXTENSION_FILE_CANDIDATES) {
12534
+ const filePath = node_path.default.join(cwd, fileName);
12535
+ if (!await pathExists(filePath)) continue;
12536
+ const matches = (await (0, node_fs_promises.readFile)(filePath, "utf-8")).matchAll(/from\s+["']([^"']+)["']/g);
12537
+ const result = [];
12538
+ for (const match of matches) {
12539
+ const spec = match[1];
12540
+ if (!result.includes(spec)) result.push(spec);
12541
+ }
12542
+ return result;
12543
+ }
12544
+ return [];
12545
+ }
12546
+ async function getWorkspaceExtensionAliases(cwd) {
12547
+ const extensionSpecs = new Set((await getExtensionImportSpecifiers(cwd)).filter((spec) => !spec.startsWith(".") && !spec.startsWith("/")));
12548
+ if (extensionSpecs.size === 0) return {};
12549
+ const monorepoRoot = await findMonorepoRoot(cwd);
12550
+ if (!monorepoRoot) return {};
12551
+ const patterns = await getWorkspacePatterns(monorepoRoot);
12552
+ const aliases = {};
12553
+ for (const pattern of patterns) {
12554
+ if (!pattern.endsWith("/*")) continue;
12555
+ const patternBase = node_path.default.join(monorepoRoot, pattern.slice(0, -2));
12556
+ if (!await pathExists(patternBase)) continue;
12557
+ const entries = await (0, node_fs_promises.readdir)(patternBase, { withFileTypes: true });
12558
+ for (const entry of entries) {
12559
+ if (!entry.isDirectory()) continue;
12560
+ const packageDir = node_path.default.join(patternBase, entry.name);
12561
+ const packageJsonPath = node_path.default.join(packageDir, "package.json");
12562
+ if (!await pathExists(packageJsonPath)) continue;
12563
+ try {
12564
+ const packageName = JSON.parse(await (0, node_fs_promises.readFile)(packageJsonPath, "utf-8")).name;
12565
+ if (!packageName || !extensionSpecs.has(packageName)) continue;
12566
+ const sourceEntryCandidates = [
12567
+ node_path.default.join(packageDir, "src", "index.tsx"),
12568
+ node_path.default.join(packageDir, "src", "index.ts"),
12569
+ node_path.default.join(packageDir, "src", "index.js")
12570
+ ];
12571
+ for (const candidate of sourceEntryCandidates) if (await pathExists(candidate)) {
12572
+ aliases[packageName] = candidate;
12573
+ break;
12574
+ }
12575
+ } catch {}
12576
+ }
12577
+ }
12578
+ return aliases;
12579
+ }
12580
+ const ssg = async ({ outDir = "dist-ssg", fallbackFile = "200" } = {}) => {
12581
+ const cwd = process.cwd();
12582
+ const outPath = node_path.default.resolve(cwd, outDir);
12583
+ const distPath = node_path.default.resolve(cwd, "dist");
12584
+ const ssrBuildPath = node_path.default.resolve(cwd, ".xmlui-ssg-ssr");
12585
+ const ssrBundlePath = node_path.default.join(ssrBuildPath, "render.mjs");
12586
+ const builtIndexPath = node_path.default.join(outPath, "index.html");
12587
+ const sourceIndexPath = node_path.default.resolve(cwd, "index.html");
12588
+ const tempEntryPath = node_path.default.resolve(cwd, TEMP_ENTRY_FILE_NAME);
12589
+ log(`starting in ${cwd}`);
12590
+ log(`cleaning output directory ${outPath}`);
12591
+ await (0, node_fs_promises.rm)(outPath, {
12592
+ recursive: true,
12593
+ force: true
12594
+ });
12595
+ await (0, node_fs_promises.mkdir)(outPath, { recursive: true });
12596
+ log("building project assets");
12597
+ await build({
12598
+ buildMode: "INLINE_ALL",
12599
+ withMock: false,
12600
+ withHostingMetaFiles: false,
12601
+ withRelativeRoot: false,
12602
+ flatDist: false
12603
+ });
12604
+ if (!await pathExists(distPath)) throw new Error(`dist folder was not generated: ${distPath}`);
12605
+ log(`copying dist to ${outPath}`);
12606
+ await (0, node_fs_promises.cp)(distPath, outPath, { recursive: true });
12607
+ executeInlineScripts(await (0, node_fs_promises.readFile)(sourceIndexPath, "utf-8"));
12608
+ const shellHtml = await (0, node_fs_promises.readFile)(builtIndexPath, "utf-8");
12609
+ const pathsToRender = (await discoverPaths(cwd)).map(normalizeRoute);
12610
+ const fallbackBaseName = fallbackFile.replace(/\.html$/i, "");
12611
+ const fallbackRoute = normalizeRoute(`/${fallbackBaseName}`);
12612
+ if (pathsToRender.includes(fallbackRoute)) throw new Error(`A discovered page route "${fallbackRoute}" conflicts with the fallback file name "${fallbackBaseName}.html". Use --fallback to specify a different name.`);
12613
+ log(`discovered ${pathsToRender.length} route(s)`);
12614
+ for (const route of pathsToRender) log(`route: ${route}`);
12615
+ const extensionImportSpecifiers = await getExtensionImportSpecifiers(cwd);
12616
+ if (extensionImportSpecifiers.length > 0) log(`detected extensions: ${extensionImportSpecifiers.join(", ")}`);
12617
+ log("creating SSR module");
12618
+ await (0, node_fs_promises.writeFile)(tempEntryPath, getSsgEntrySource(extensionImportSpecifiers), "utf-8");
12619
+ const viteConfig = await getViteConfig({});
12620
+ const extensionAliases = await getWorkspaceExtensionAliases(cwd);
12621
+ if (Object.keys(extensionAliases).length > 0) log(`using workspace extension aliases: ${Object.keys(extensionAliases).join(", ")}`);
12622
+ const existingAlias = viteConfig.resolve?.alias;
12623
+ const mergedAlias = Array.isArray(existingAlias) ? [...existingAlias, ...Object.entries(extensionAliases).map(([find, replacement]) => ({
12624
+ find,
12625
+ replacement
12626
+ }))] : {
12627
+ ...existingAlias || {},
12628
+ ...extensionAliases
12629
+ };
12630
+ try {
12631
+ log("building SSR module");
12632
+ await (0, node_fs_promises.rm)(ssrBuildPath, {
12633
+ recursive: true,
12634
+ force: true
12635
+ });
12636
+ await (0, vite.build)({
12637
+ ...viteConfig,
12638
+ resolve: {
12639
+ ...viteConfig.resolve || {},
12640
+ alias: mergedAlias
12641
+ },
12642
+ define: {
12643
+ ...viteConfig.define || {},
12644
+ "process.env.VITE_BUILD_MODE": JSON.stringify("INLINE_ALL"),
12645
+ "process.env.VITE_DEV_MODE": false,
12646
+ "process.env.VITE_MOCK_ENABLED": false,
12647
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "production")
12648
+ },
12649
+ build: {
12650
+ ...viteConfig.build || {},
12651
+ ssr: tempEntryPath,
12652
+ outDir: ssrBuildPath,
12653
+ emptyOutDir: true,
12654
+ minify: false,
12655
+ rollupOptions: {
12656
+ ...viteConfig.build?.rollupOptions || {},
12657
+ input: void 0,
12658
+ output: {
12659
+ ...viteConfig.build?.rollupOptions?.output || {},
12660
+ entryFileNames: "render.mjs",
12661
+ inlineDynamicImports: true
12662
+ }
12663
+ }
12664
+ }
12665
+ });
12666
+ if (!await pathExists(ssrBundlePath)) throw new Error(`failed to build SSR bundle: ${ssrBundlePath}`);
12667
+ const renderModule = await import(`${(0, node_url.pathToFileURL)(ssrBundlePath).href}?t=${Date.now()}`);
12668
+ if (!renderModule?.renderPath) throw new Error("failed to load renderPath from temporary SSG entry module");
12669
+ const writePromises = [];
12670
+ for (const route of pathsToRender) {
12671
+ log(`rendering ${route}`);
12672
+ const finalHtml = applyRenderToShell(shellHtml, renderModule.renderPath(route));
12673
+ const outputFile = getOutputHtmlPath(outPath, route);
12674
+ const dir = node_path.default.dirname(outputFile);
12675
+ const writePromise = (async () => {
12676
+ await (0, node_fs_promises.mkdir)(dir, { recursive: true });
12677
+ await (0, node_fs_promises.writeFile)(outputFile, finalHtml, "utf-8");
12678
+ log(`wrote ${outputFile}`);
12679
+ })();
12680
+ writePromises.push(writePromise);
12681
+ }
12682
+ log("waiting for all writes to complete...");
12683
+ await Promise.all(writePromises);
12684
+ const fallbackRendered = renderModule.renderPath(fallbackFile);
12685
+ log(`rendering fallback shell at synthetic route ${fallbackRoute}`);
12686
+ const fallbackHtml = applyRenderToShell(shellHtml, fallbackRendered);
12687
+ const fallbackOutputFile = node_path.default.join(outPath, `${fallbackBaseName}.html`);
12688
+ await (0, node_fs_promises.writeFile)(fallbackOutputFile, fallbackHtml, "utf-8");
12689
+ log(`wrote ${fallbackOutputFile}`);
12690
+ } finally {
12691
+ await (0, node_fs_promises.rm)(tempEntryPath, { force: true });
12692
+ await (0, node_fs_promises.rm)(ssrBuildPath, {
12693
+ recursive: true,
12694
+ force: true
12695
+ });
12696
+ }
12697
+ log(`completed. static files are in ${outPath}`);
12698
+ };
12699
+
10414
12700
  //#endregion
10415
12701
  //#region bin/build-lib.ts
10416
12702
  const buildLib = async ({ watchMode, mode = "production" }) => {
@@ -10590,6 +12876,22 @@ function getStringArg(arg, defaultValue) {
10590
12876
  target,
10591
12877
  source
10592
12878
  });
12879
+ }).command("ssg", "Generate static pages", (yargs$1) => {
12880
+ return yargs$1.option("outDir", {
12881
+ type: "string",
12882
+ default: "dist-ssg",
12883
+ description: "SSG output directory"
12884
+ }).option("fallback", {
12885
+ type: "string",
12886
+ default: "200",
12887
+ description: "Base name for the fallback HTML file served for unknown routes"
12888
+ });
12889
+ }, (argv) => {
12890
+ const { outDir, fallback } = argv;
12891
+ ssg({
12892
+ outDir: getStringArg(outDir, "dist-ssg"),
12893
+ fallbackFile: getStringArg(fallback, "200")
12894
+ });
10593
12895
  }).strict().demandCommand(1, "You need to provide a command").help().parse();
10594
12896
 
10595
12897
  //#endregion