@xpell/core 2.0.0-alpha.10

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 (69) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/LICENSE +21 -0
  3. package/README.md +96 -0
  4. package/dist/XCommand.d.ts +84 -0
  5. package/dist/XConst.d.ts +28 -0
  6. package/dist/XData.d.ts +51 -0
  7. package/dist/XError.d.ts +34 -0
  8. package/dist/XEventManager.d.ts +57 -0
  9. package/dist/XLogger.d.ts +32 -0
  10. package/dist/XModule.d.ts +161 -0
  11. package/dist/XNanoCommands.d.ts +42 -0
  12. package/dist/XObject.d.ts +287 -0
  13. package/dist/XObjectManager.d.ts +96 -0
  14. package/dist/XParams.d.ts +60 -0
  15. package/dist/XParser.d.ts +77 -0
  16. package/dist/XProtocol.d.ts +56 -0
  17. package/dist/XUtils.d.ts +100 -0
  18. package/dist/Xpell.d.ts +142 -0
  19. package/dist/index.d.ts +9 -0
  20. package/dist/xpell-core.cjs.js +3 -0
  21. package/dist/xpell-core.es.js +1428 -0
  22. package/docs/Codex.md +138 -0
  23. package/docs/XData 2.md +209 -0
  24. package/docs/api/.nojekyll +1 -0
  25. package/docs/api/assets/hierarchy.js +1 -0
  26. package/docs/api/assets/highlight.css +71 -0
  27. package/docs/api/assets/icons.js +18 -0
  28. package/docs/api/assets/icons.svg +1 -0
  29. package/docs/api/assets/main.js +60 -0
  30. package/docs/api/assets/navigation.js +1 -0
  31. package/docs/api/assets/search.js +1 -0
  32. package/docs/api/assets/style.css +1611 -0
  33. package/docs/api/classes/XCommand.html +23 -0
  34. package/docs/api/classes/XModule.html +57 -0
  35. package/docs/api/classes/XObject.html +133 -0
  36. package/docs/api/classes/XObjectManager.html +36 -0
  37. package/docs/api/classes/XObjectPack.html +6 -0
  38. package/docs/api/classes/XParams.html +8 -0
  39. package/docs/api/classes/XParser.html +21 -0
  40. package/docs/api/classes/XUtils.html +29 -0
  41. package/docs/api/classes/XpellEngine.html +36 -0
  42. package/docs/api/classes/_XData.html +23 -0
  43. package/docs/api/classes/_XEventManager.html +37 -0
  44. package/docs/api/classes/_XLogger.html +17 -0
  45. package/docs/api/hierarchy.html +1 -0
  46. package/docs/api/index.html +3 -0
  47. package/docs/api/interfaces/IXData.html +1 -0
  48. package/docs/api/interfaces/IXObjectData.html +17 -0
  49. package/docs/api/interfaces/XDataXporterHandler.html +1 -0
  50. package/docs/api/interfaces/XEventListener.html +6 -0
  51. package/docs/api/interfaces/XNanoCommand.html +2 -0
  52. package/docs/api/interfaces/XObjectOnEventIndex.html +1 -0
  53. package/docs/api/types/HTMLEventListenersIndex.html +1 -0
  54. package/docs/api/types/XCommandData.html +1 -0
  55. package/docs/api/types/XDataObject.html +1 -0
  56. package/docs/api/types/XDataVariable.html +1 -0
  57. package/docs/api/types/XDataXporter.html +1 -0
  58. package/docs/api/types/XEvent.html +1 -0
  59. package/docs/api/types/XEventListenerOptions.html +1 -0
  60. package/docs/api/types/XModuleData.html +1 -0
  61. package/docs/api/types/XNanoCommandPack.html +2 -0
  62. package/docs/api/types/XObjectData.html +1 -0
  63. package/docs/api/types/XObjectOnEventHandler.html +1 -0
  64. package/docs/api/variables/XData.html +1 -0
  65. package/docs/api/variables/XEventManager.html +1 -0
  66. package/docs/api/variables/XLogger.html +1 -0
  67. package/docs/api/variables/Xpell.html +3 -0
  68. package/docs/architecture/overview.md +190 -0
  69. package/package.json +66 -0
@@ -0,0 +1,1428 @@
1
+ class X {
2
+ /**
3
+ * Create ignore list for parser to ignore spell words
4
+ * @param list - comma-separated list of words
5
+ * @param reservedWords - base reserved words map (mutated)
6
+ */
7
+ createIgnoreList(t, e) {
8
+ if (!t) return e;
9
+ const s = t.split(",").map((i) => i.trim()).filter(Boolean);
10
+ for (const i of s) e[i] = "";
11
+ return e;
12
+ }
13
+ /**
14
+ * GUID / UUID v4 (cross-platform)
15
+ *
16
+ * Preference order:
17
+ * 1) globalThis.crypto.randomUUID()
18
+ * 2) globalThis.crypto.getRandomValues() (RFC4122 v4)
19
+ * 3) Math.random() fallback (NOT crypto-secure, legacy fallback only)
20
+ */
21
+ guid() {
22
+ const e = globalThis.crypto;
23
+ if (e && typeof e.randomUUID == "function")
24
+ return e.randomUUID();
25
+ if (e && typeof e.getRandomValues == "function") {
26
+ const r = new Uint8Array(16);
27
+ e.getRandomValues(r), r[6] = r[6] & 15 | 64, r[8] = r[8] & 63 | 128;
28
+ const a = Array.from(r, (c) => c.toString(16).padStart(2, "0"));
29
+ return a.slice(0, 4).join("") + "-" + a.slice(4, 6).join("") + "-" + a.slice(6, 8).join("") + "-" + a.slice(8, 10).join("") + "-" + a.slice(10, 16).join("");
30
+ }
31
+ const s = "0123456789abcdef".split(""), i = [];
32
+ let n;
33
+ i[8] = i[13] = i[18] = i[23] = "-", i[14] = "4";
34
+ for (let r = 0; r < 36; r++)
35
+ i[r] || (n = (0 | Math.random() * 16) >>> 0, i[r] = s[r === 19 ? n & 3 | 8 : n & 15]);
36
+ return i.join("");
37
+ }
38
+ /**
39
+ * Merge defaults into data object (mutates data)
40
+ * @param data - target data
41
+ * @param defaults - defaults object
42
+ * @param force - overwrite existing values
43
+ */
44
+ mergeDefaultsWithData(t, e, s = !1) {
45
+ if (!t) return e;
46
+ t._id || (t._id = t.id ?? this.guid());
47
+ for (const i of Object.keys(e))
48
+ (!(i in t) || s) && (t[i] = e[i]);
49
+ return t;
50
+ }
51
+ /**
52
+ * Encode string to Base64 (UTF-8 safe, cross-platform)
53
+ */
54
+ encode(t) {
55
+ const e = globalThis;
56
+ if (typeof e.btoa == "function") {
57
+ const s = encodeURIComponent(String(t)).replace(
58
+ /%([0-9A-F]{2})/g,
59
+ (i, n) => String.fromCharCode(parseInt(n, 16))
60
+ );
61
+ return e.btoa(s);
62
+ }
63
+ if (e.Buffer && typeof e.Buffer.from == "function")
64
+ return e.Buffer.from(String(t), "utf8").toString("base64");
65
+ throw new Error("Base64 encode not supported in this environment");
66
+ }
67
+ /**
68
+ * Decode Base64 string to UTF-8 (cross-platform)
69
+ */
70
+ decode(t) {
71
+ const e = globalThis;
72
+ if (typeof e.atob == "function") {
73
+ const s = e.atob(String(t)), i = Array.prototype.map.call(s, (n) => "%" + n.charCodeAt(0).toString(16).padStart(2, "0")).join("");
74
+ return decodeURIComponent(i);
75
+ }
76
+ if (e.Buffer && typeof e.Buffer.from == "function")
77
+ return e.Buffer.from(String(t), "base64").toString("utf8");
78
+ throw new Error("Base64 decode not supported in this environment");
79
+ }
80
+ /**
81
+ * Returns a random integer between min and max (inclusive)
82
+ * NOTE: Not cryptographically secure (OK for UI, NOT for IDs)
83
+ */
84
+ getRandomInt(t, e) {
85
+ return t = Math.ceil(t), e = Math.floor(e), Math.floor(Math.random() * (e - t + 1)) + t;
86
+ }
87
+ /**
88
+ * Extract parameter from XCommand
89
+ */
90
+ getParam(t, e, s = 0) {
91
+ return t?._params?.[e] ?? s;
92
+ }
93
+ /**
94
+ * Default frame scheduler (cross-platform)
95
+ * - Browser: requestAnimationFrame
96
+ * - Node / non-DOM: setImmediate (fast) or setTimeout (paced by target fps)
97
+ */
98
+ createDefaultScheduler(t) {
99
+ const e = globalThis;
100
+ if (typeof e.requestAnimationFrame == "function")
101
+ return (n) => e.requestAnimationFrame(n);
102
+ const s = typeof t == "number" && isFinite(t) && t > 0 ? t : 60;
103
+ if (typeof e.setImmediate == "function" && (!t || t >= 60))
104
+ return (n) => e.setImmediate(n);
105
+ const i = Math.max(1, Math.round(1e3 / s));
106
+ return (n) => e.setTimeout(n, i);
107
+ }
108
+ }
109
+ const p = new X();
110
+ class k {
111
+ #t = 0;
112
+ // displayed fps (stable)
113
+ #e = 0;
114
+ // EMA of ms/frame
115
+ #s = 0;
116
+ #i;
117
+ // weight of new samples (0..1)
118
+ #n;
119
+ // minimum integer change to update displayed fps
120
+ constructor(t = 0.05, e = 1) {
121
+ const s = Number(t);
122
+ this.#i = Number.isFinite(s) ? Math.min(1, Math.max(1e-3, s)) : 0.05;
123
+ const i = Number(e);
124
+ this.#n = Number.isFinite(i) ? Math.max(0, Math.floor(i)) : 1;
125
+ }
126
+ now() {
127
+ const t = globalThis.performance;
128
+ return t && typeof t.now == "function" ? t.now() : Date.now();
129
+ }
130
+ calc() {
131
+ const t = this.now();
132
+ if (this.#s === 0)
133
+ return this.#s = t, this.#t;
134
+ const e = t - this.#s;
135
+ if (this.#s = t, !Number.isFinite(e) || e <= 0) return this.#t;
136
+ this.#e === 0 ? this.#e = e : this.#e = (1 - this.#i) * this.#e + this.#i * e;
137
+ const s = 1e3 / this.#e;
138
+ if (!Number.isFinite(s) || s <= 0) return this.#t;
139
+ const i = Math.round(s);
140
+ return this.#t !== 0 && this.#n > 0 && Math.abs(i - this.#t) < this.#n ? this.#t : (this.#t = i, this.#t);
141
+ }
142
+ reset() {
143
+ this.#t = 0, this.#e = 0, this.#s = 0;
144
+ }
145
+ }
146
+ class F {
147
+ constructor(t) {
148
+ this._enabled = !0, this._show_date = !1, this._show_time = !0, this._debug = !1, t && this.configure(t);
149
+ }
150
+ configure(t) {
151
+ typeof t._enabled == "boolean" && (this._enabled = t._enabled), typeof t._show_date == "boolean" && (this._show_date = t._show_date), typeof t._show_time == "boolean" && (this._show_time = t._show_time), typeof t._debug == "boolean" && (this._debug = t._debug);
152
+ }
153
+ _dt() {
154
+ const t = /* @__PURE__ */ new Date(), e = this._show_date ? `${t.getDate()}.${t.getMonth()}.${t.getFullYear()} ` : "", s = this._show_time ? `${t.getHours()}:${t.getMinutes()}:${t.getSeconds()}.${t.getMilliseconds()}|` : "";
155
+ return e + s;
156
+ }
157
+ log(t, ...e) {
158
+ this._enabled && console.log(this._dt(), t, ...e);
159
+ }
160
+ warn(t, ...e) {
161
+ this._enabled && console.warn(this._dt(), t, ...e);
162
+ }
163
+ error(t, ...e) {
164
+ this._enabled && console.error(this._dt(), t, ...e);
165
+ }
166
+ debug(t, ...e) {
167
+ !this._enabled || !this._debug || console.debug(this._dt(), t, ...e);
168
+ }
169
+ }
170
+ const _ = new F(), x = typeof process < "u" && !!process?.env && process.env.NODE_ENV === "production";
171
+ x || console.info(
172
+ "[Xpell] _xlog is redirected to console in development mode. Tip: enable 'Show timestamps' in DevTools → Console for timed logs."
173
+ );
174
+ const y = x ? _ : console;
175
+ class S {
176
+ constructor() {
177
+ this._objects = {}, this._listeners = /* @__PURE__ */ new Map(), this._any_listeners = /* @__PURE__ */ new Set(), this._compat_writes = !0, this._warn_legacy_writes = !0, this._verbose = !1, this._compat_legacy_keys = !0, this._o_proxy = null, this._objects = {};
178
+ }
179
+ /**
180
+ * Shared memory view.
181
+ * Reads are always supported.
182
+ * Writes are supported in compat mode (optional) and should be migrated to set()/delete()/touch().
183
+ */
184
+ get _o() {
185
+ return !this._compat_writes && !this._warn_legacy_writes ? this._objects : (this._o_proxy || (this._o_proxy = new Proxy(this._objects, {
186
+ set: (t, e, s) => {
187
+ const i = String(e);
188
+ return this._warn_legacy_writes && console.warn(
189
+ `[XData] Legacy write: _o["${i}"] = ... ; prefer XData.set("${i}", value).`
190
+ ), this._compat_writes ? this.set(i, s, { source: "legacy:_o" }) : t[i] = s, !0;
191
+ },
192
+ deleteProperty: (t, e) => {
193
+ const s = String(e);
194
+ return this._warn_legacy_writes && console.warn(
195
+ `[XData] Legacy delete: delete _o["${s}"] ; prefer XData.delete("${s}").`
196
+ ), this._compat_writes ? this.delete(s, { source: "legacy:_o" }) : delete t[s], !0;
197
+ }
198
+ })), this._o_proxy);
199
+ }
200
+ /** Preferred read API */
201
+ get(t) {
202
+ return this._objects[t];
203
+ }
204
+ /** Preferred write API */
205
+ set(t, e, s) {
206
+ const i = this._objects[t];
207
+ this._objects[t] = e, this._emit({ key: t, value: e, prev: i, ts: Date.now(), op: "set", meta: s });
208
+ }
209
+ /** Shallow merge helper (nice for state objects) */
210
+ patch(t, e, s) {
211
+ const i = this._objects[t], r = { ...i && typeof i == "object" ? i : {}, ...e };
212
+ this._objects[t] = r, this._emit({ key: t, value: r, prev: i, ts: Date.now(), op: "patch", meta: s });
213
+ }
214
+ /** In-place mutation notifier */
215
+ touch(t, e) {
216
+ const s = this._objects[t];
217
+ this._emit({ key: t, value: s, prev: s, ts: Date.now(), op: "touch", meta: e });
218
+ }
219
+ has(t) {
220
+ return Object.prototype.hasOwnProperty.call(this._objects, t);
221
+ }
222
+ delete(t, e) {
223
+ const s = this._objects[t];
224
+ delete this._objects[t], this._emit({ key: t, value: void 0, prev: s, ts: Date.now(), op: "delete", meta: e });
225
+ }
226
+ pick(t, e) {
227
+ const s = this._objects[t];
228
+ return this.delete(t, e), s;
229
+ }
230
+ clean() {
231
+ this._objects = {};
232
+ }
233
+ // ----------------------------
234
+ // Subscriptions
235
+ // ----------------------------
236
+ on(t, e) {
237
+ let s = this._listeners.get(t);
238
+ return s || this._listeners.set(t, s = /* @__PURE__ */ new Set()), s.add(e), () => this.off(t, e);
239
+ }
240
+ off(t, e) {
241
+ const s = this._listeners.get(t);
242
+ s && (s.delete(e), s.size === 0 && this._listeners.delete(t));
243
+ }
244
+ onAny(t) {
245
+ return this._any_listeners.add(t), () => this._any_listeners.delete(t);
246
+ }
247
+ // ----------------------------
248
+ // Emit
249
+ // ----------------------------
250
+ _emit(t) {
251
+ this._verbose && t.meta?.trace && (t.stack = new Error().stack);
252
+ const e = this._listeners.get(t.key);
253
+ if (e) for (const s of e) s(t);
254
+ for (const s of this._any_listeners) s(t);
255
+ }
256
+ }
257
+ const u = new S();
258
+ class M {
259
+ constructor(t) {
260
+ t && Object.keys(t).forEach((e) => {
261
+ this[e] = t[e];
262
+ }), this.d || (this.d = Date.now());
263
+ }
264
+ /**
265
+ * Gets th parameter value from the XCommand whether it has a name or just a position
266
+ * There are 2 ways to send XCommand with parameters:
267
+ * 1. <module> <op> <param-0> <param-1> <param-2> // position is for this case
268
+ * 2. <module> <op> param-name:param-value // name is for this case
269
+ * @param position the position of the parameter if no name is send
270
+ * @param name the name of the parameter
271
+ * @param defaultValue the default value if none above exists
272
+ * @returns {any} the actual parameter value
273
+ */
274
+ getParam(t, e, s) {
275
+ return this._params?.hasOwnProperty(e) ? this._params[e] : this._params?.hasOwnProperty(t) ? this._params[t] : s;
276
+ }
277
+ }
278
+ const w = {
279
+ type: "_type",
280
+ children: "_children"
281
+ }, f = class f {
282
+ /**
283
+ * Adds HTML-Xpell Mapping item
284
+ * @param htmlElement HTML element to change from
285
+ * @param xpellElement Xpell element to change to
286
+ */
287
+ static addHtml2XpellMapItem(t, e) {
288
+ f.html2XMap.elements[t] = e;
289
+ }
290
+ /**
291
+ * convert text command to Xpell json command
292
+ * @param {string} txt
293
+ */
294
+ static parse(t, e) {
295
+ const s = t.split(" ");
296
+ let i = new M();
297
+ if (e ? (i._module = e, i._op = s[0]) : (i._module = s[0], i._op = s[1]), i._params = {}, s.length > 1)
298
+ for (let n = 2; n < s.length; ++n) {
299
+ const r = s[n];
300
+ if (r.indexOf(":") > -1) {
301
+ const c = r.split(":");
302
+ i._params[c[0]] = c[1];
303
+ } else
304
+ i._params[n - 1] = s[n];
305
+ }
306
+ return i;
307
+ }
308
+ static replaceSpacesInQuotes(t, e = "_%20_") {
309
+ return t.replace(/(['"])(.*?)\1/g, (s, i, n) => {
310
+ const r = String(n).replace(/\s/g, e);
311
+ return `${i}${r}${i}`;
312
+ });
313
+ }
314
+ static parseObjectCommand(t, e) {
315
+ t = f.replaceSpacesInQuotes(t);
316
+ const s = t.trim().split(/\s+/), i = e || s.shift();
317
+ if (!i) throw new Error("Missing module name");
318
+ let n;
319
+ if (s[0]?.startsWith("#") && (n = s.shift().slice(1), !n))
320
+ throw new Error("Invalid object selector '#'. Use '#<id>'");
321
+ const r = s.shift();
322
+ if (!r) throw new Error("Missing operation");
323
+ const a = {};
324
+ let c = null, h = null;
325
+ if (s.forEach((l) => {
326
+ if (h) {
327
+ if (h += ` ${l}`, l.endsWith(h[0])) {
328
+ const m = h.slice(1, -1).replace(/_%20_/g, " ");
329
+ a[c] = m, h = null;
330
+ }
331
+ return;
332
+ }
333
+ if (l.startsWith('"') || l.startsWith("'")) {
334
+ if (h = l, l.endsWith(l[0]) && l.length > 1) {
335
+ const m = l.slice(1, -1).replace(/_%20_/g, " ");
336
+ a[c] = m, h = null;
337
+ }
338
+ return;
339
+ }
340
+ if (l.includes(":")) {
341
+ const m = l.split(":"), D = m[0], E = m.slice(1).join(":").replace(/_%20_/g, " ");
342
+ a[D] = E, c = null;
343
+ return;
344
+ }
345
+ c = l.replace(/_%20_/g, " ");
346
+ }), h) throw new Error("Unclosed quoted parameter value");
347
+ return {
348
+ _module: i,
349
+ _object: n,
350
+ _op: r,
351
+ _params: a
352
+ };
353
+ }
354
+ /**
355
+ * Converts XML/HTML string to XCommand
356
+ * @param xmlString XML string
357
+ * @returns
358
+ */
359
+ static xmlString2Xpell(t) {
360
+ const s = new DOMParser().parseFromString(t, "text/xml");
361
+ return s.childNodes.length > 0 ? f.xml2Xpell(s.childNodes[0]) : {};
362
+ }
363
+ /**
364
+ * Converts XML/HTML Document to Xpell JSON
365
+ * @param xmlNode XML Document Node
366
+ * @param forceXhtml force Xpell XHTML for every unknown object
367
+ * @returns {} Xpell JSON
368
+ */
369
+ static xml2Xpell(t, e) {
370
+ const s = f.html2XMap;
371
+ let i = {};
372
+ i._children = [];
373
+ const n = t.nodeName, r = t.nodeName;
374
+ let a = e;
375
+ if (e ? (i[w.type] = "xhtml", i._html_ns = "http://www.w3.org/2000/svg") : i._type = s.elements[n] ? s.elements[n] : n, t.attributes)
376
+ for (let c = 0; c < t.attributes.length; ++c) {
377
+ const h = t.attributes[c], l = s.attributes[h.name] ? s.attributes[h.name] : h.name;
378
+ i[l] = h.value;
379
+ }
380
+ if (t?.firstChild?.nodeValue && (i.text = t?.firstChild.nodeValue.trim()), i[w.type] == "xhtml" ? i._html_tag = r : i[w.type] == "svg" && (a = !0, i._html_ns = "http://www.w3.org/2000/svg"), t?.childNodes.length > 0)
381
+ for (let c = 0; c < t.childNodes.length; ++c) {
382
+ const h = t.childNodes[c];
383
+ h.nodeName.startsWith("#") || i[w.children].push(f.xml2Xpell(h, a));
384
+ }
385
+ return i;
386
+ }
387
+ };
388
+ f.html2XMap = {
389
+ elements: {
390
+ div: "view",
391
+ a: "link",
392
+ b: "xhtml",
393
+ h1: "xhtml",
394
+ h2: "xhtml",
395
+ h3: "xhtml",
396
+ h4: "xhtml",
397
+ h5: "xhtml",
398
+ p: "xhtml",
399
+ small: "xhtml",
400
+ aside: "xhtml",
401
+ span: "xhtml",
402
+ table: "xhtml",
403
+ th: "xhtml",
404
+ td: "xhtml",
405
+ tr: "xhtml",
406
+ thead: "xhtml",
407
+ tbody: "xhtml",
408
+ ul: "xhtml",
409
+ li: "xhtml",
410
+ ol: "xhtml",
411
+ canvas: "xhtml",
412
+ img: "image"
413
+ },
414
+ attributes: {
415
+ id: "_id"
416
+ }
417
+ };
418
+ let g = f;
419
+ class I {
420
+ constructor() {
421
+ this._log_rules = {
422
+ register: !1,
423
+ remove: !1,
424
+ fire: !1
425
+ }, this._events = {}, this._listener_index = {};
426
+ }
427
+ /**
428
+ * Register a listener on an event name (runtime bus only).
429
+ *
430
+ * Backward compatible:
431
+ * - Canonical: on(name, cb, { _once, _owner, _tag })
432
+ * - Legacy: on(name, cb, { _once }, owner)
433
+ */
434
+ on(t, e, s = {}, i) {
435
+ this._events[t] || (this._events[t] = []);
436
+ const n = s?._owner ?? i, r = p.guid(), a = {
437
+ _id: r,
438
+ _callback: e,
439
+ _options: s,
440
+ _owner: n,
441
+ _tag: s?._tag
442
+ };
443
+ return this._events[t].push(a), this._listener_index[r] = t, this._log_rules.register && y.log("XEM Register", t, r), r;
444
+ }
445
+ /**
446
+ * Register a listener that will be removed after first fire.
447
+ */
448
+ once(t, e, s) {
449
+ return this.on(t, e, { _once: !0, _owner: s });
450
+ }
451
+ /**
452
+ * Fire an event with optional payload.
453
+ */
454
+ async fire(t, e) {
455
+ const s = this._events[t];
456
+ if (!s || s.length === 0) return;
457
+ this._log_rules.fire && y.log("XEM Fire", t, e);
458
+ const i = s.slice(), n = [];
459
+ for (const r of i) {
460
+ try {
461
+ r && r._callback && r._callback(e);
462
+ } catch (a) {
463
+ y.error(a);
464
+ }
465
+ r?._options?._once && n.push(r._id);
466
+ }
467
+ for (const r of n) this.remove(r);
468
+ }
469
+ /**
470
+ * Remove a listener by id.
471
+ */
472
+ remove(t) {
473
+ const e = this._listener_index[t];
474
+ if (!e) return;
475
+ const s = this._events[e];
476
+ if (s && s.length) {
477
+ const i = s.findIndex((n) => n?._id === t);
478
+ i >= 0 && s.splice(i, 1), s.length === 0 && delete this._events[e];
479
+ }
480
+ delete this._listener_index[t], this._log_rules.remove && y.log("XEM Remove", e, t);
481
+ }
482
+ /**
483
+ * Remove all listeners for a given owner reference.
484
+ */
485
+ removeOwner(t) {
486
+ if (!t) return;
487
+ const e = [];
488
+ for (const s of Object.values(this._events))
489
+ for (const i of s)
490
+ (i?._owner ?? i?._options?._owner) === t && e.push(i._id);
491
+ e.forEach((s) => this.remove(s));
492
+ }
493
+ /**
494
+ * Clear the entire event bus (mostly for tests / hard reset).
495
+ */
496
+ clear() {
497
+ this._events = {}, this._listener_index = {};
498
+ }
499
+ }
500
+ const b = new I();
501
+ class P {
502
+ #t;
503
+ #e;
504
+ #s;
505
+ constructor() {
506
+ this.#t = {}, this.#e = {}, this.#s = {};
507
+ }
508
+ get _objects() {
509
+ return this.#e;
510
+ }
511
+ /**
512
+ * Checks if an object is found in the object manager
513
+ * @param xObjectId
514
+ * @returns
515
+ */
516
+ hasObject(t) {
517
+ return this.#e.hasOwnProperty(t);
518
+ }
519
+ /**
520
+ * Register multiple classes dictionary into the object manager
521
+ * @param xObjects - key value list -> \{"view":XView,...\}
522
+ */
523
+ registerObjects(t) {
524
+ Object.keys(t).forEach((s) => this.registerObject(s, t[s]));
525
+ }
526
+ /**
527
+ * Registers single XObject
528
+ * @param name - name of the object
529
+ * @param xObjects The object class
530
+ */
531
+ registerObject(t, e) {
532
+ this.#t[t] = e;
533
+ }
534
+ /**
535
+ * Checks if a class (name) is found in the object manager classes dictionary
536
+ * @param name - class name
537
+ * @returns {boolean}
538
+ */
539
+ hasObjectClass(t) {
540
+ return this.#t.hasOwnProperty(t);
541
+ }
542
+ /**
543
+ * Retrieves XObject class instance
544
+ * @param name class name
545
+ * @returns {XObject}
546
+ */
547
+ getObjectClass(t) {
548
+ return this.#t[t];
549
+ }
550
+ /**
551
+ * Retrieves all the classes dictionary
552
+ * @returns XObjectManagerIndex
553
+ */
554
+ getAllClasses() {
555
+ return this.#t;
556
+ }
557
+ get _classes() {
558
+ return this.#t;
559
+ }
560
+ /**
561
+ * Add XObject instance to the manager
562
+ * @param xObject XObject to maintain
563
+ */
564
+ addObject(t) {
565
+ t && t._id ? (this.#e[t._id] = t, (!t._name || t._name.length == 0) && (t._name = t._id), this.#s[t._name] = t._id) : _.log("unable to add object");
566
+ }
567
+ /**
568
+ * Remove XObject from the manager
569
+ * @param xObjectId object id to remove
570
+ */
571
+ removeObject(t) {
572
+ const e = this.#e[t];
573
+ e && (delete this.#s[e?._name], delete this.#e[t]);
574
+ }
575
+ /**
576
+ * Retrieves XObject instance
577
+ * @param xObjectId XObject id
578
+ * @returns {XObject}
579
+ */
580
+ getObject(t) {
581
+ return this.#e[t];
582
+ }
583
+ /**
584
+ * alias to getObject
585
+ * @param id
586
+ * @returns
587
+ */
588
+ go(t) {
589
+ return this.getObject(t);
590
+ }
591
+ /**
592
+ * Retrieves XObject instance
593
+ * @param objectName XObject name
594
+ * @returns {XObject}
595
+ */
596
+ getObjectByName(t) {
597
+ return this.#s[t] ? this.getObject(this.#s[t]) : null;
598
+ }
599
+ }
600
+ const A = {
601
+ info: (o, t) => {
602
+ _.log("XObject id " + t?._id);
603
+ },
604
+ log: (o, t) => {
605
+ o._params && o._params[1] ? _.log(o._params[1]) : _.log(t);
606
+ },
607
+ fire: (o, t) => {
608
+ o._params && o._params[1] ? b.fire(o._params[1], o._params[2]) : o._params && o._params.event && b.fire(o._params.event, o._params.data);
609
+ }
610
+ }, j = { _children: "child nodes" };
611
+ class v {
612
+ /**
613
+ * XObject constructor is creating the object and adding all the data keys to the XObject instance
614
+ * @param data constructor input data (object)
615
+ * @param defaults - defaults to merge with data
616
+ * @param skipParse - skip data parsing
617
+ * if override this method make sure to call super.init(data,skipParse) and to set skipParse to true
618
+ */
619
+ constructor(t, e, s) {
620
+ this._children = [], this._parent = null, this._on = {}, this._once = {}, this._process_frame = !0, this._process_data = !0, this._nano_commands = {}, this._event_listeners_ids = {}, this._event_parsed = !1, this._mounted = !1, this._xporter = {
621
+ _ignore_fields: [
622
+ "_to_xdata_ignore_fields",
623
+ "_xporter",
624
+ "_children",
625
+ "_on",
626
+ "_once",
627
+ "_on_create",
628
+ "_on_mount",
629
+ "_on_frame",
630
+ "_on_data",
631
+ "_process_frame",
632
+ "_process_data",
633
+ "_parent",
634
+ "_event_listeners_ids",
635
+ "_event_parsed",
636
+ "_mounted",
637
+ "_debug"
638
+ ],
639
+ _instance_xporters: {}
640
+ }, e && p.mergeDefaultsWithData(t, e), this._id = t && t._id ? t._id : "xo-" + p.guid(), this._type = "object", this._children = [], this._nano_commands = {}, this.addNanoCommandPack(A), t && t.hasOwnProperty("_nano_commands") && t._nano_commands && (this.addNanoCommandPack(t._nano_commands), delete t._nano_commands), this.addXporterDataIgnoreFields(["_nano_commands"]), this.addXporterInstanceXporter(v, (i) => i.toXData()), this._xem_options = {
641
+ // _instance:_xem
642
+ // _object: this
643
+ // _support_html: true
644
+ }, !s && t && this.parse(t, j);
645
+ }
646
+ log(t, ...e) {
647
+ this._debug && t && _.log(this._type + "->" + this._id + "]", t, ...e);
648
+ }
649
+ /**
650
+ * Initialize the XObject
651
+ * @param data - data to parse (XObjectData)
652
+ * @param skipParse - skip data parsing
653
+ * @deprecated - use parse method instead
654
+ */
655
+ init(t, e) {
656
+ !e && t && this.parse(t, j);
657
+ }
658
+ parseEvents(t) {
659
+ if (!this._event_parsed) {
660
+ t || (t = this._xem_options), Object.keys(this._on).forEach((s) => {
661
+ this.addEventListener(s, this._on[s], t);
662
+ });
663
+ const e = {};
664
+ Object.assign(e, t), e._once = !0, Object.keys(this._once).forEach((s) => {
665
+ this.addEventListener(s, this._once[s], e);
666
+ }), this._event_parsed = !0;
667
+ }
668
+ }
669
+ addEventListener(t, e, s) {
670
+ s || (s = this._xem_options);
671
+ let i;
672
+ if (typeof e == "function")
673
+ i = async (r) => {
674
+ e(this, r);
675
+ };
676
+ else if (typeof e == "string")
677
+ i = async (r) => {
678
+ const a = this._id + " " + e + " event-data='" + JSON.stringify(r).replace(/'/g, "\\'") + "'";
679
+ await this.run(a);
680
+ };
681
+ else
682
+ throw new Error("event handler must be a function");
683
+ const n = b.on(t, i, s, this);
684
+ this._event_listeners_ids[t] || (this._event_listeners_ids[t] = []), this._event_listeners_ids[t].push(n);
685
+ }
686
+ removeEventListener(t) {
687
+ const e = this._event_listeners_ids[t];
688
+ e && e.length && (e.forEach((s) => {
689
+ b.remove(s);
690
+ }), delete this._event_listeners_ids[t]);
691
+ }
692
+ removeAllEventListeners() {
693
+ Object.keys(this._event_listeners_ids).forEach((e) => this.removeEventListener(e));
694
+ }
695
+ /**
696
+ * Append a child XObject to this XObject
697
+ * @param xobject
698
+ */
699
+ append(t) {
700
+ this._children?.push(t), t._parent = this;
701
+ }
702
+ /**
703
+ * Add single nano command to the object
704
+ * @param commandName - the nano command name
705
+ * @param nanoCommandFunction
706
+ */
707
+ addNanoCommand(t, e) {
708
+ typeof e == "function" && (this._nano_commands[t] = e);
709
+ }
710
+ addNanoCommandPack(t) {
711
+ t && Object.keys(t).forEach((e) => {
712
+ this.addNanoCommand(e, t[e]);
713
+ });
714
+ }
715
+ /**
716
+ * List of fields to ignore when exporting the xobject to XData or string format
717
+ * @param <string[]> ignoreFields - an array with all the fields to ignore
718
+ */
719
+ addXporterDataIgnoreFields(t) {
720
+ this._xporter._ignore_fields = this._xporter._ignore_fields.concat(t);
721
+ }
722
+ /**
723
+ * Add XData Xporter instance handler
724
+ * @param <XDataInstanceXporter> ie - the instance exporter object
725
+ */
726
+ addXporterInstanceXporter(t, e) {
727
+ const s = p.guid();
728
+ this._xporter._instance_xporters[s] = {
729
+ cls: t,
730
+ handler: e
731
+ };
732
+ }
733
+ /**
734
+ * Parse data to the XObject
735
+ * @param data data to parse
736
+ * @param ignore - lis of words to ignore in the parse process
737
+ */
738
+ parse(t, e = j) {
739
+ Object.keys(t).forEach((i) => {
740
+ !e.hasOwnProperty(i) && t.hasOwnProperty(i) && (this[i] = t[i]);
741
+ });
742
+ }
743
+ /**
744
+ * Parse data to the XObject
745
+ * @param data data to parse
746
+ * @param {object} fields- object with fields and default values (IXData format)
747
+ *
748
+ * fields example = {
749
+ * _name : "default-name",
750
+ * ...
751
+ * }
752
+ */
753
+ parseFieldsFromXDataObject(t, e) {
754
+ Object.keys(e).forEach((i) => {
755
+ t.hasOwnProperty(i) ? this[i] = t[i] : this[i] = e[i];
756
+ });
757
+ }
758
+ /**
759
+ * Parse list of fields from IXObjectData to the class
760
+ * @param {IXObjectData} data - the data
761
+ * @param {Array<string>} fields - array of field names (string)
762
+ * @param checkNonXParams - also check non Xpell fields (fields that not starting with "_" sign)
763
+ */
764
+ parseFields(t, e, s) {
765
+ e.forEach((i) => {
766
+ if (t.hasOwnProperty(i))
767
+ this[i] = t[i];
768
+ else if (s && i.startsWith("_")) {
769
+ const n = i.substring(1);
770
+ t.hasOwnProperty(n) && (this[i] = t[n], this[n] = t[n]);
771
+ }
772
+ });
773
+ }
774
+ /**
775
+ * this method triggered after the HTML DOM object has been created and added to the parent element
776
+ * support external _on_create anonymous function in the , example:
777
+ * _on_create: async (xObject) => {
778
+ * // xObject -> The XObject parent of the _on_create function, use instead of this keyword
779
+ * // write code that will be executed each frame.
780
+ * // make sure to write async anonymous function.
781
+ * }
782
+ *
783
+ */
784
+ async onCreate() {
785
+ this._on_create ? this.checkAndRunInternalFunction(this._on_create) : this._on && this._on.create ? this.checkAndRunInternalFunction(this._on.create) : this._once && this._once.create && this.checkAndRunInternalFunction(this._once.create);
786
+ }
787
+ async checkAndRunInternalFunction(t, ...e) {
788
+ if (typeof t == "function")
789
+ await t(this, ...e);
790
+ else if (typeof t == "string")
791
+ if (e.length > 0) {
792
+ const s = e[0], i = JSON.stringify(s).replace(/'/g, "\\'");
793
+ await this.run(`${this._id} ${t} data:'${i}'`);
794
+ } else
795
+ await this.run(`${this._id} ${t}`);
796
+ }
797
+ /**
798
+ * Triggers when the object is being mounted to other element
799
+ * support external _on_create anonymous function in the , example:
800
+ * _on_mount: async (xObject) => {
801
+ * // xObject -> The XObject parent of the _on_mount function, use instead of this keyword
802
+ * // write code that will be executed each frame.
803
+ * // make sure to write async anonymous function.
804
+ * }
805
+ */
806
+ async onMount() {
807
+ if (!this._mounted) {
808
+ this.parseEvents(this._xem_options), this._process_data && typeof this._data_source == "string" && this._data_source.length > 0 && this.bindDataSource(this._data_source, { initial: !0 }), this._on_mount ? await this.checkAndRunInternalFunction(this._on_mount) : this._on && this._on.mount ? await this.checkAndRunInternalFunction(this._on.mount) : this._once && this._once.mount && await this.checkAndRunInternalFunction(this._once.mount), this._mounted = !0;
809
+ for (const t of this._children)
810
+ t.onMount && typeof t.onMount == "function" && t.onMount();
811
+ }
812
+ }
813
+ emptyDataSource() {
814
+ const t = this._data_source;
815
+ if (typeof t != "string" || t.length === 0) return;
816
+ const e = this._type ?? this.constructor.name, s = this._id ?? "no-id";
817
+ u.delete(t, { source: `${e}#${s}.emptyDataSource` });
818
+ }
819
+ /**
820
+ * Triggers when new data is being received from the data source
821
+ * @param data - the data
822
+ * if override this method make sure to call super.onData(data) to run the _on_data attribute
823
+ */
824
+ async onData(t) {
825
+ this._process_data && (this._on_data ? this.checkAndRunInternalFunction(this._on_data, t) : this._on && this._on.data ? this.checkAndRunInternalFunction(this._on.data, t) : this._once && this._once.data && this.checkAndRunInternalFunction(this._once.data, t));
826
+ }
827
+ /**
828
+ * Triggers from Xpell frame every frame
829
+ * Support _on_frame atrribute that can be XCommand string or function
830
+ * @param {number} frameNumber
831
+ *
832
+ * XObject supports
833
+ * 1. External _on_frame anonymous function in the , example:
834
+ * _on_frame: async (xObject,frameNumber) => {
835
+ * // xObject -> The XObject parent of the _on_frame function, use instead of this keyword
836
+ * // frameNumber = Xpell current frame number
837
+ * // write code that will be executed each frame.
838
+ * // make sure to write async anonymous function.
839
+ * // be wise with the function execution and try to keep it in the 15ms running time to support 60 FPS
840
+ * }
841
+ *
842
+ * 2. String execution of nano commands
843
+ *
844
+ * _on_frame: "nano command text"
845
+ *
846
+ */
847
+ async onFrame(t) {
848
+ this._process_frame && (this._on_frame ? this.checkAndRunInternalFunction(this._on_frame, t) : this._on && this._on.frame ? this.checkAndRunInternalFunction(this._on.frame, t) : this._once && this._once.frame && this.checkAndRunInternalFunction(this._once.frame, t));
849
+ for (const e of this._children)
850
+ e.onFrame && typeof e.onFrame == "function" && e.onFrame(t);
851
+ }
852
+ /**
853
+ * Runs object nano commands
854
+ * @param nanoCommand - object nano command (string)
855
+ * @param cache - cache last command to prevent multiple parsing on the same command
856
+ */
857
+ async run(t, e = !0) {
858
+ let s = this._cache_cmd_txt && this._cache_cmd_txt == t ? this._cache_jcmd : g.parseObjectCommand(t);
859
+ e && (this._cache_cmd_txt = t, this._cache_jcmd = s), await this.execute(s);
860
+ }
861
+ /**
862
+ * Execute XCommand within the XObject Nano Commands
863
+ * @param xCommand XCommand to execute
864
+ *
865
+ * Nano command example:
866
+ *
867
+ * "set-text" : (xCommand,xObject) => {
868
+ * xObject.setText(xCommands.params.text)
869
+ * }
870
+ *
871
+ */
872
+ async execute(t) {
873
+ if (t._op && this._nano_commands[t._op])
874
+ try {
875
+ await this._nano_commands[t._op](t, this);
876
+ } catch (e) {
877
+ _.error(this._id + " has error with command name " + t._op + " " + e);
878
+ }
879
+ else
880
+ _.error(this._id + " has no command name " + t._op);
881
+ }
882
+ /**
883
+ * Return an IXObjectData JSON representation of the XObject
884
+ * @returns IXObjectData
885
+ */
886
+ toXData() {
887
+ const t = {};
888
+ return Object.keys(this).forEach((e) => {
889
+ if (!this._xporter._ignore_fields.includes(e) && this.hasOwnProperty(e) && this[e] !== void 0) {
890
+ const s = this[e];
891
+ if (typeof s == "function")
892
+ return;
893
+ if (typeof s == "object") {
894
+ const i = Object.keys(this._xporter._instance_xporters);
895
+ let n = !0;
896
+ i.forEach((r) => {
897
+ this._xporter._instance_xporters[r], s instanceof this._xporter._instance_xporters[r].cls && (t[e] = this._xporter._instance_xporters[r].handler(s), n = !1);
898
+ }), n && (t[e] = s);
899
+ } else
900
+ t[e] = s;
901
+ }
902
+ }), t._children = [], this._children.length > 0 && this._children.forEach((e) => {
903
+ typeof e.toXData == "function" && t._children?.push(e.toXData());
904
+ }), t;
905
+ }
906
+ /**
907
+ * Return a string representation of the XObject
908
+ * @returns string
909
+ */
910
+ toString() {
911
+ return JSON.stringify(this.toXData());
912
+ }
913
+ clearAttributes(t) {
914
+ t.forEach((e) => {
915
+ this.hasOwnProperty(e) && (this[e] = null, delete this[e]);
916
+ });
917
+ }
918
+ bindDataSource(t, e) {
919
+ const s = e?.initial ?? !0, i = t ?? this._data_source;
920
+ typeof i != "string" || i.length === 0 || this._process_data && (this._xd_bound_key === i && this._xd_unsub || (this.unbindDataSource(), this._data_source = i, this._xd_bound_key = i, this._type ?? this.constructor.name, this._id, this._xd_unsub = u.on(i, async (n) => {
921
+ await this.onData(n.value);
922
+ }), s && u.has(i) && this.onData(u.get(i))));
923
+ }
924
+ unbindDataSource() {
925
+ this._xd_unsub?.(), this._xd_unsub = void 0, this._xd_bound_key = void 0;
926
+ }
927
+ /**
928
+ * Dispose the XObject and all its children
929
+ */
930
+ async dispose() {
931
+ if (this.unbindDataSource(), this._parent) {
932
+ const t = this._parent._children.indexOf(this);
933
+ t > -1 && this._parent._children.splice(t, 1);
934
+ }
935
+ this._process_data = !1, this._process_frame = !1, this.removeAllEventListeners(), this.clearAttributes(["_cache_cmd_txt", "_cache_jcmd", "_nano_commands", "_event_listeners_ids", "_parent", "_on", "_once", "_xem_options", "_xporter"]), this._children && this._children.forEach((t) => {
936
+ typeof t.dispose == "function" && t.dispose();
937
+ }), this._children = [];
938
+ }
939
+ /**
940
+ * Remove a child from the XObject )
941
+ * @param child - the child to
942
+ * @returns void
943
+ */
944
+ removeChild(t, e = !1) {
945
+ if (e)
946
+ t.dispose();
947
+ else {
948
+ const s = this._children.indexOf(t);
949
+ s > -1 && this._children.splice(s, 1), t._parent = null;
950
+ }
951
+ }
952
+ /**
953
+ * @param child - the child to add
954
+ * @deprecated use append method instead
955
+ */
956
+ addChild(t) {
957
+ this.append(t);
958
+ }
959
+ }
960
+ class B {
961
+ /**
962
+ * Get all registered object in this ObjectPack
963
+ * @returns XObject dictionary
964
+ */
965
+ static getObjects() {
966
+ return {
967
+ object: v
968
+ };
969
+ }
970
+ }
971
+ const $ = "engine:module:num-of-objects:";
972
+ class C {
973
+ //engine: any; //deprecated remove after spell3d
974
+ constructor(t) {
975
+ this._log_rules = {
976
+ createObject: !1,
977
+ removeObject: !1
978
+ }, this.#t = new P(), this._name = t._name, this._id = p.guid();
979
+ }
980
+ #t;
981
+ load() {
982
+ _.log("Module " + this._name + " loaded");
983
+ }
984
+ /**
985
+ * Creates new XObject from data object
986
+ * @param data - The data of the new object (JSON)
987
+ * @return {XObject|*}
988
+ */
989
+ create(t) {
990
+ let e;
991
+ if (t.hasOwnProperty("_type"))
992
+ if (this.#t.hasObjectClass(t._type)) {
993
+ let s = this.#t.getObjectClass(t._type);
994
+ s.hasOwnProperty("defaults") && p.mergeDefaultsWithData(t, s.defaults), e = new s(t);
995
+ } else
996
+ throw "Xpell object '" + t._type + "' not found";
997
+ else
998
+ e = new v(t);
999
+ return this.#t.addObject(e), t._children && t._children.forEach((s) => {
1000
+ const i = this.create(s);
1001
+ e.append(i);
1002
+ }), e.onCreate(), e;
1003
+ }
1004
+ /**
1005
+ * removes and XObject from the object manager
1006
+ * @param objectId op
1007
+ */
1008
+ remove(t) {
1009
+ const e = this.#t.getObject(t);
1010
+ if (!e) return;
1011
+ const s = [], i = (n) => {
1012
+ n?._id && (s.push(n._id), (n._children ?? []).forEach((r) => i(r)));
1013
+ };
1014
+ i(e), typeof e.dispose == "function" && e.dispose(), s.reverse().forEach((n) => this.#t.removeObject(n));
1015
+ }
1016
+ _info(t) {
1017
+ _.log("module info");
1018
+ }
1019
+ //xpell interpreter
1020
+ /**
1021
+ * Run xpell command -
1022
+ * CLI mode, parse the command to XCommand JSON format and call execute method
1023
+ * @param {string} XCommand input - text
1024
+ * @returns command execution result
1025
+ */
1026
+ async run(t) {
1027
+ if (t) {
1028
+ let e = t.trim();
1029
+ e.startsWith(this._name) || (e = this._name + " " + e);
1030
+ let s = g.parse(e);
1031
+ return await this.execute(s);
1032
+ } else
1033
+ throw "Unable to parse Xpell Command";
1034
+ }
1035
+ /**
1036
+ * execute xpell command - CLI mode
1037
+ * @param {XCommand} XCommand input (JSON)
1038
+ * @returns command execution result
1039
+ */
1040
+ // inside XModule class
1041
+ async execute(t) {
1042
+ if (!t || !t._op)
1043
+ throw new Error(`Invalid XCommand: missing _op (module: ${this._name})`);
1044
+ const e = t._object;
1045
+ if (e) {
1046
+ const n = this.#t.getObject(e);
1047
+ if (!n)
1048
+ throw new Error(`Module '${this._name}' cant find object id: ${e}`);
1049
+ return await n.execute(t);
1050
+ }
1051
+ const s = "_" + t._op.replaceAll("-", "_"), i = this[s];
1052
+ if (typeof i == "function")
1053
+ return await i.call(this, t);
1054
+ throw new Error(`Module '${this._name}' cant find op: ${t._op}`);
1055
+ }
1056
+ /**
1057
+ * This method triggers every frame from the Xpell engine.
1058
+ * The method can be override by the extending module to support extended onFrame functionality
1059
+ * @param frameNumber Current frame number
1060
+ */
1061
+ async onFrame(t) {
1062
+ const e = this.#t._objects, s = Object.keys(e);
1063
+ s.forEach((i) => {
1064
+ const n = e[i];
1065
+ n && n.onFrame && typeof n.onFrame == "function" && n?.onFrame(t);
1066
+ }), u.set($ + this._id, s.length, {
1067
+ source: "xmodule"
1068
+ });
1069
+ }
1070
+ /**
1071
+ * X Object Manager
1072
+ */
1073
+ /**
1074
+ * getter for om (object manager) instance
1075
+ * @returns {XObjectManager}
1076
+ * @deprecated - use _object_manager instead
1077
+ * If you wish to get an object from the object manager use
1078
+ * getObject directly on the module instead of om.getObject
1079
+ */
1080
+ get om() {
1081
+ return this.#t;
1082
+ }
1083
+ get _object_manager() {
1084
+ return this.#t;
1085
+ }
1086
+ /**
1087
+ * Returns the XObject instance from the module Object Manager
1088
+ * @param objectId
1089
+ * @returns XObject
1090
+ */
1091
+ getObject(t) {
1092
+ return this.#t.getObject(t);
1093
+ }
1094
+ /**
1095
+ * Returns the XObject instance from the module Object Manager
1096
+ * Usage:
1097
+ * xmodule._o["object-id"] is equivalent to xmodule.getObject("object-id")
1098
+ */
1099
+ get _o() {
1100
+ return this.#t._objects;
1101
+ }
1102
+ /**
1103
+ * Imports external object pack to the engine
1104
+ * The object class should be like XObjects with static implementation of getObjects() method
1105
+ * @param {XObjects} xObjectPack
1106
+ */
1107
+ importObjectPack(t) {
1108
+ this.#t.registerObjects(t.getObjects());
1109
+ }
1110
+ /**
1111
+ * Imports external object pack to the engine
1112
+ * @deprecated - use importObjectPack instead
1113
+ * @param xObjectPack
1114
+ */
1115
+ importObjects(t) {
1116
+ this.importObjectPack(t);
1117
+ }
1118
+ /**
1119
+ * Imports external objects to the engine
1120
+ * The object class should be like XObjects with static implementation of getObjects() method
1121
+ * @param xObjectName
1122
+ * @param xObject
1123
+ */
1124
+ importObject(t, e) {
1125
+ this.#t.registerObject(t, e);
1126
+ }
1127
+ // In XModule
1128
+ async _help(t) {
1129
+ const e = t?._params?._op ?? t?._params?._command ?? "";
1130
+ return this.help(e);
1131
+ }
1132
+ /**
1133
+ * Override in modules to provide help text.
1134
+ * @param op optional: specific command name (e.g. "navigate")
1135
+ */
1136
+ help(t) {
1137
+ return {
1138
+ module: this._name,
1139
+ usage: `${this._name} help`,
1140
+ ops: ["help"],
1141
+ note: "No help() implemented for this module."
1142
+ };
1143
+ }
1144
+ }
1145
+ class L {
1146
+ /* -------------------------------------------------- */
1147
+ /* core helpers */
1148
+ /* -------------------------------------------------- */
1149
+ static get(t, e, s) {
1150
+ if (!t?._params) return s;
1151
+ const i = t._params[e];
1152
+ return i !== void 0 ? i : s;
1153
+ }
1154
+ static has(t, e) {
1155
+ return t?._params && t._params[e] !== void 0;
1156
+ }
1157
+ static str(t, ...e) {
1158
+ for (const s of e) {
1159
+ const i = t?._params?.[s];
1160
+ if (i != null)
1161
+ return String(i);
1162
+ }
1163
+ }
1164
+ /* -------------------------------------------------- */
1165
+ /* typed params */
1166
+ /* -------------------------------------------------- */
1167
+ static bool(t, e, s = !1) {
1168
+ const i = this.get(t, e, s);
1169
+ if (typeof i == "boolean") return i;
1170
+ if (typeof i == "number") return i !== 0;
1171
+ if (typeof i == "string") {
1172
+ const n = i.toLowerCase();
1173
+ if (["1", "true", "yes", "on"].includes(n)) return !0;
1174
+ if (["0", "false", "no", "off"].includes(n)) return !1;
1175
+ }
1176
+ return !!i;
1177
+ }
1178
+ static int(t, e, s = 0) {
1179
+ const i = this.get(t, e, s), n = parseInt(String(i), 10);
1180
+ return Number.isFinite(n) ? n : s;
1181
+ }
1182
+ static json(t, e, s) {
1183
+ const i = this.get(t, e, s);
1184
+ if (i == null) return s;
1185
+ if (typeof i == "object") return i;
1186
+ if (typeof i == "string")
1187
+ try {
1188
+ return JSON.parse(i);
1189
+ } catch {
1190
+ return s;
1191
+ }
1192
+ return s;
1193
+ }
1194
+ }
1195
+ class O extends Error {
1196
+ constructor(t, e, s) {
1197
+ super(e), this.name = "XError", this._code = t, this._level = s?._level ?? "error", this._meta = s?._meta, this._cause = s?._cause;
1198
+ }
1199
+ toXData() {
1200
+ return {
1201
+ _code: this._code,
1202
+ _level: this._level,
1203
+ _meta: this._meta,
1204
+ _cause: this._cause,
1205
+ // optional: include name/message if you want them in protocol too
1206
+ name: this.name,
1207
+ message: this.message
1208
+ };
1209
+ }
1210
+ toJSON() {
1211
+ return {
1212
+ ...this.toXData(),
1213
+ stack: this.stack
1214
+ // debug-only
1215
+ };
1216
+ }
1217
+ }
1218
+ class d {
1219
+ constructor(t) {
1220
+ this._ok = !1, this._ts = Date.now(), this._pt = 0, t && this.setXData(t);
1221
+ }
1222
+ // ---------------------------------------------------------------------------
1223
+ // Factories
1224
+ // ---------------------------------------------------------------------------
1225
+ static create(t) {
1226
+ return new d(t);
1227
+ }
1228
+ static ok(t) {
1229
+ return new d({ _ok: !0, _result: t });
1230
+ }
1231
+ static error(t) {
1232
+ if (t instanceof O)
1233
+ return new d({
1234
+ _ok: !1,
1235
+ _result: t.toXData()
1236
+ });
1237
+ const e = new O(
1238
+ "E_INTERNAL",
1239
+ t?.message ?? String(t),
1240
+ { _cause: t }
1241
+ );
1242
+ return new d({
1243
+ _ok: !1,
1244
+ _result: e.toXData()
1245
+ });
1246
+ }
1247
+ // ---------------------------------------------------------------------------
1248
+ // Lifecycle
1249
+ // ---------------------------------------------------------------------------
1250
+ stopProcessTimeCounter() {
1251
+ this._pt = Date.now() - this._ts;
1252
+ }
1253
+ // ---------------------------------------------------------------------------
1254
+ // Protocol
1255
+ // ---------------------------------------------------------------------------
1256
+ /**
1257
+ * Convert to wire-safe object.
1258
+ * NOTE: serialize == finalize timing
1259
+ */
1260
+ toXData() {
1261
+ return this.stopProcessTimeCounter(), {
1262
+ _ok: this._ok,
1263
+ _ts: this._ts,
1264
+ _pt: this._pt,
1265
+ _result: this._result
1266
+ };
1267
+ }
1268
+ toString() {
1269
+ return JSON.stringify(this.toXData());
1270
+ }
1271
+ setXData(t) {
1272
+ t && ("_ok" in t && (this._ok = !!t._ok), "_ts" in t && typeof t._ts == "number" && (this._ts = t._ts), "_pt" in t && typeof t._pt == "number" && (this._pt = t._pt), "_result" in t && (this._result = t._result));
1273
+ }
1274
+ }
1275
+ class T extends d {
1276
+ constructor(t) {
1277
+ super(d.error(t).toXData());
1278
+ }
1279
+ }
1280
+ class W extends d {
1281
+ constructor(t) {
1282
+ super({ _ok: !0, _result: t });
1283
+ }
1284
+ }
1285
+ const R = "engine:frame-number", N = "engine:fps";
1286
+ class U {
1287
+ constructor(t) {
1288
+ this._log_rules = {}, this._modules = {}, this._schedule_frame = t?._schedule_frame ?? p.createDefaultScheduler(t?._target_fps), this._version = "0.0.1", this._engine_id = p.guid(), this._frame_number = 0, this._fps_calc = new k(), this.parser = g, this._modules = {}, b.fire("xpell-init"), _._enabled = !1;
1289
+ }
1290
+ /**
1291
+ * @deprecated use _verbose instead
1292
+ * Enable Xpell logs to console
1293
+ */
1294
+ set verbose(t) {
1295
+ _._enabled = t;
1296
+ }
1297
+ /**
1298
+ * Enable Xpell logs to console
1299
+ */
1300
+ set _verbose(t) {
1301
+ _._enabled = t;
1302
+ }
1303
+ /**
1304
+ * Logs message to console using Xpell logger
1305
+ * make sure to enable verbose mode to see the logs
1306
+ * this method is a wrapper for XLogger.log
1307
+ * @param msg
1308
+ * @param optionalParams
1309
+ */
1310
+ log(t, ...e) {
1311
+ _.log(t, ...e);
1312
+ }
1313
+ /**
1314
+ * Delay the execution of the next command
1315
+ * @param ms - delay in milliseconds
1316
+ * @returns
1317
+ */
1318
+ async delay(t) {
1319
+ return new Promise((e) => setTimeout(e, t));
1320
+ }
1321
+ /**
1322
+ * Loads Xpell module into the engine
1323
+ * @param {XModule} xModule
1324
+ */
1325
+ loadModule(t) {
1326
+ this._modules.hasOwnProperty(t._name) ? _.log("Module " + t._name + " already loaded") : (this._modules[t._name] = t, t.load());
1327
+ }
1328
+ /**
1329
+ * Loads multiple module at ones
1330
+ * @param {Array<XModule>} xModulesArray
1331
+ */
1332
+ loadModules(...t) {
1333
+ t.forEach((e) => this.loadModule(e));
1334
+ }
1335
+ /**
1336
+ * Display information about the Xpell engine to the console
1337
+ */
1338
+ info() {
1339
+ _.log(`Xpell information:
1340
+ - Engine Id: ` + this._engine_id + `
1341
+ - Version ` + this._version);
1342
+ }
1343
+ /**
1344
+ * Run textual xCommand -
1345
+ * @param {cmd} - text command
1346
+ */
1347
+ run(t) {
1348
+ if (t?.length > 2) {
1349
+ let e = g.parse(t);
1350
+ return this.execute(e);
1351
+ } else
1352
+ throw "Unable to parse Xpell command";
1353
+ }
1354
+ /**
1355
+ * Execute Xpell Command
1356
+ * @param {XCommand}
1357
+ */
1358
+ execute(t) {
1359
+ if (t && t._module && this._modules[t._module])
1360
+ return this._modules[t._module].execute(t);
1361
+ throw "Xpell module " + t._module + " not loaded";
1362
+ }
1363
+ /**
1364
+ * Main onFrame method
1365
+ * calls all the sub-modules onFrame methods (if implemented)
1366
+ */
1367
+ onFrame() {
1368
+ this._frame_number++;
1369
+ for (const e of Object.keys(this._modules)) {
1370
+ const s = this._modules[e];
1371
+ s?.onFrame && typeof s.onFrame == "function" && s.onFrame(this._frame_number);
1372
+ }
1373
+ const t = this._fps_calc.calc();
1374
+ u.set(R, this._frame_number, { source: "engine" }), u.set(N, t, { source: "engine" }), u._compat_legacy_keys && (u.set("frame-number", this._frame_number, { source: "engine:legacy" }), u.set("fps", t, { source: "engine:legacy" })), this._schedule_frame(() => this.onFrame());
1375
+ }
1376
+ /**
1377
+ * Gets Xpell module by name
1378
+ * @param {string} moduleName - name of the loaded module
1379
+ * @returns {XModule}
1380
+ */
1381
+ getModule(t) {
1382
+ return this._modules[t];
1383
+ }
1384
+ /**
1385
+ * Start Xpell engine for web browsers using requestAnimationFrame
1386
+ */
1387
+ start() {
1388
+ _.log("Starting Xpell"), this.onFrame();
1389
+ }
1390
+ /**
1391
+ * deprecated - use XData._o directly
1392
+ */
1393
+ getParam(t, e) {
1394
+ return t in u._o ? u._o[t] : e;
1395
+ }
1396
+ }
1397
+ const J = new U();
1398
+ export {
1399
+ M as XCommand,
1400
+ N as XD_FPS,
1401
+ R as XD_FRAME_NUMBER,
1402
+ u as XData,
1403
+ O as XError,
1404
+ b as XEventManager,
1405
+ _ as XLogger,
1406
+ C as XModule,
1407
+ v as XObject,
1408
+ P as XObjectManager,
1409
+ B as XObjectPack,
1410
+ L as XParams,
1411
+ g as XParser,
1412
+ d as XResponse,
1413
+ T as XResponseError,
1414
+ W as XResponseOK,
1415
+ p as XUtils,
1416
+ J as Xpell,
1417
+ U as XpellEngine,
1418
+ S as _XData,
1419
+ I as _XEventManager,
1420
+ F as _XLogger,
1421
+ X as _XUtils,
1422
+ J as _x,
1423
+ u as _xd,
1424
+ b as _xem,
1425
+ _ as _xlog,
1426
+ p as _xu,
1427
+ J as default
1428
+ };