lightview 2.4.4 → 2.4.7

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.
@@ -0,0 +1,3934 @@
1
+ var LightviewCDOM = function(exports) {
2
+ "use strict";
3
+ const helpers = /* @__PURE__ */ new Map();
4
+ const helperOptions = /* @__PURE__ */ new Map();
5
+ const operators = {
6
+ prefix: /* @__PURE__ */ new Map(),
7
+ // e.g., '++' -> { helper: 'increment', precedence: 70 }
8
+ postfix: /* @__PURE__ */ new Map(),
9
+ // e.g., '++' -> { helper: 'increment', precedence: 70 }
10
+ infix: /* @__PURE__ */ new Map()
11
+ // e.g., '+' -> { helper: 'add', precedence: 50 }
12
+ };
13
+ const DEFAULT_PRECEDENCE = {
14
+ prefix: 80,
15
+ postfix: 80,
16
+ infix: 50
17
+ };
18
+ const registerHelper = (name, fn, options = {}) => {
19
+ helpers.set(name, fn);
20
+ if (globalThis.__LIGHTVIEW_INTERNALS__) {
21
+ globalThis.__LIGHTVIEW_INTERNALS__.helpers.set(name, fn);
22
+ }
23
+ if (options) helperOptions.set(name, options);
24
+ };
25
+ const registerOperator = (helperName, symbol, position, precedence, options = {}) => {
26
+ var _a;
27
+ if (!["prefix", "postfix", "infix"].includes(position)) {
28
+ throw new Error(`Invalid operator position: ${position}. Must be 'prefix', 'postfix', or 'infix'.`);
29
+ }
30
+ if (!helpers.has(helperName)) {
31
+ (_a = globalThis.console) == null ? void 0 : _a.warn(`LightviewCDOM: Operator "${symbol}" registered for helper "${helperName}" which is not yet registered.`);
32
+ }
33
+ const prec = precedence ?? DEFAULT_PRECEDENCE[position];
34
+ operators[position].set(symbol, { helper: helperName, precedence: prec, options });
35
+ };
36
+ const getLV = () => globalThis.Lightview || null;
37
+ const getRegistry = () => {
38
+ var _a;
39
+ return ((_a = getLV()) == null ? void 0 : _a.registry) || null;
40
+ };
41
+ class BindingTarget {
42
+ constructor(parent, key) {
43
+ this.parent = parent;
44
+ this.key = key;
45
+ this.isBindingTarget = true;
46
+ }
47
+ get value() {
48
+ return this.parent[this.key];
49
+ }
50
+ set value(v) {
51
+ this.parent[this.key] = v;
52
+ }
53
+ get __parent__() {
54
+ return this.parent;
55
+ }
56
+ }
57
+ const unwrapSignal = (val) => {
58
+ if (val && typeof val === "function" && "value" in val) {
59
+ return val.value;
60
+ }
61
+ if (val && typeof val === "object" && !(globalThis.Node && val instanceof globalThis.Node) && "value" in val) {
62
+ return val.value;
63
+ }
64
+ return val;
65
+ };
66
+ const traverse = (root, segments) => {
67
+ let current = root;
68
+ for (const segment of segments) {
69
+ if (!segment) continue;
70
+ current = unwrapSignal(current);
71
+ if (current == null) return void 0;
72
+ const key = segment.startsWith("[") ? segment.slice(1, -1) : segment;
73
+ current = current[key];
74
+ }
75
+ return unwrapSignal(current);
76
+ };
77
+ const traverseAsContext = (root, segments) => {
78
+ let current = root;
79
+ for (let i = 0; i < segments.length; i++) {
80
+ const segment = segments[i];
81
+ if (!segment) continue;
82
+ const key = segment.startsWith("[") ? segment.slice(1, -1) : segment;
83
+ const unwrapped = unwrapSignal(current);
84
+ if (unwrapped == null) return void 0;
85
+ if (i === segments.length - 1) {
86
+ return new BindingTarget(unwrapped, key);
87
+ }
88
+ current = unwrapped[key];
89
+ }
90
+ return current;
91
+ };
92
+ const resolvePath = (path, context) => {
93
+ if (typeof path !== "string") return path;
94
+ const registry = getRegistry();
95
+ if (path === ".") return unwrapSignal(context);
96
+ if (path.startsWith("=/") || path.startsWith("/")) {
97
+ const segments = path.startsWith("=/") ? path.slice(2).split("/") : path.slice(1).split("/");
98
+ const rootName = segments.shift();
99
+ const LV = getLV();
100
+ const root = LV ? LV.get(rootName, { scope: (context == null ? void 0 : context.__node__) || context }) : registry == null ? void 0 : registry.get(rootName);
101
+ if (!root) return void 0;
102
+ return traverse(root, segments);
103
+ }
104
+ if (path.startsWith("./")) {
105
+ return traverse(context, path.slice(2).split("/"));
106
+ }
107
+ if (path.startsWith("../")) {
108
+ return traverse(context == null ? void 0 : context.__parent__, path.slice(3).split("/"));
109
+ }
110
+ if (path.includes("/") || path.includes(".")) {
111
+ const unwrapped = unwrapSignal(context);
112
+ if (unwrapped && typeof unwrapped === "object" && path in unwrapped) {
113
+ return unwrapSignal(unwrapped[path]);
114
+ }
115
+ return traverse(context, path.split(/[\/.]/));
116
+ }
117
+ const unwrappedContext = unwrapSignal(context);
118
+ if (unwrappedContext && typeof unwrappedContext === "object") {
119
+ if (path in unwrappedContext || unwrappedContext[path] !== void 0) {
120
+ return traverse(unwrappedContext, [path]);
121
+ }
122
+ }
123
+ return path;
124
+ };
125
+ const resolvePathAsContext = (path, context) => {
126
+ if (typeof path !== "string") return path;
127
+ const registry = getRegistry();
128
+ if (path === ".") return context;
129
+ if (path.startsWith("=/") || path.startsWith("/")) {
130
+ const segments = path.startsWith("=/") ? path.slice(2).split(/[/.]/) : path.slice(1).split(/[/.]/);
131
+ const rootName = segments.shift();
132
+ const LV = getLV();
133
+ const root = LV ? LV.get(rootName, { scope: (context == null ? void 0 : context.__node__) || context }) : registry == null ? void 0 : registry.get(rootName);
134
+ if (!root) return void 0;
135
+ return traverseAsContext(root, segments);
136
+ }
137
+ if (path.startsWith("./")) {
138
+ return traverseAsContext(context, path.slice(2).split(/[\/.]/));
139
+ }
140
+ if (path.startsWith("../")) {
141
+ return traverseAsContext(context == null ? void 0 : context.__parent__, path.slice(3).split(/[\/.]/));
142
+ }
143
+ if (path.includes("/") || path.includes(".")) {
144
+ const unwrapped = unwrapSignal(context);
145
+ if (unwrapped && typeof unwrapped === "object" && path in unwrapped) {
146
+ return new BindingTarget(unwrapped, path);
147
+ }
148
+ return traverseAsContext(context, path.split(/[\/.]/));
149
+ }
150
+ const unwrappedContext = unwrapSignal(context);
151
+ if (unwrappedContext && typeof unwrappedContext === "object") {
152
+ if (/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(path)) {
153
+ return new BindingTarget(unwrappedContext, path);
154
+ }
155
+ }
156
+ return path;
157
+ };
158
+ class LazyValue {
159
+ constructor(fn) {
160
+ this.fn = fn;
161
+ this.isLazy = true;
162
+ }
163
+ resolve(context) {
164
+ return this.fn(context);
165
+ }
166
+ }
167
+ const isNode = (val) => val && typeof val === "object" && globalThis.Node && val instanceof globalThis.Node;
168
+ const resolveArgument = (arg, context, globalMode = false) => {
169
+ if (arg.startsWith("'") && arg.endsWith("'") || arg.startsWith('"') && arg.endsWith('"')) {
170
+ return { value: arg.slice(1, -1), isLiteral: true };
171
+ }
172
+ if (arg !== "" && !isNaN(Number(arg))) {
173
+ return { value: Number(arg), isLiteral: true };
174
+ }
175
+ if (arg === "true") return { value: true, isLiteral: true };
176
+ if (arg === "false") return { value: false, isLiteral: true };
177
+ if (arg === "null") return { value: null, isLiteral: true };
178
+ if (arg === "_" || arg.startsWith("_/") || arg.startsWith("_.")) {
179
+ return {
180
+ value: new LazyValue((item) => {
181
+ if (arg === "_") return item;
182
+ const path = arg.startsWith("_.") ? arg.slice(2) : arg.slice(2);
183
+ return resolvePath(path, item);
184
+ }),
185
+ isLazy: true
186
+ };
187
+ }
188
+ if (arg === "$this" || arg.startsWith("$this/") || arg.startsWith("$this.")) {
189
+ return {
190
+ value: new LazyValue((context2) => {
191
+ const node = (context2 == null ? void 0 : context2.__node__) || context2;
192
+ if (arg === "$this") return node;
193
+ const path = arg.startsWith("$this.") ? arg.slice(6) : arg.slice(6);
194
+ return resolvePath(path, node);
195
+ }),
196
+ isLazy: true
197
+ };
198
+ }
199
+ if (arg === "$event" || arg.startsWith("$event/") || arg.startsWith("$event.")) {
200
+ return {
201
+ value: new LazyValue((context2) => {
202
+ const event = (context2 == null ? void 0 : context2.$event) || (context2 == null ? void 0 : context2.event) || context2;
203
+ if (arg === "$event") return event;
204
+ const path = arg.startsWith("$event.") ? arg.slice(7) : arg.slice(7);
205
+ return resolvePath(path, event);
206
+ }),
207
+ isLazy: true
208
+ };
209
+ }
210
+ if (arg.startsWith("{") || arg.startsWith("[")) {
211
+ try {
212
+ const data = parseJPRX(arg);
213
+ const resolveTemplate = (node, context2) => {
214
+ if (typeof node === "string") {
215
+ if (node.startsWith("=")) {
216
+ const res = resolveExpression$1(node, context2);
217
+ const final = res instanceof LazyValue ? res.resolve(context2) : res;
218
+ return unwrapSignal(final);
219
+ }
220
+ if (node === "$this" || node.startsWith("$this/") || node.startsWith("$this.")) {
221
+ const path = node.startsWith("$this.") || node.startsWith("$this/") ? node.slice(6) : node.slice(6);
222
+ const ctxNode = (context2 == null ? void 0 : context2.__node__) || context2;
223
+ const res = node === "$this" ? ctxNode : resolvePath(path, ctxNode);
224
+ return unwrapSignal(res);
225
+ }
226
+ if (node === "$event" || node.startsWith("$event/") || node.startsWith("$event.")) {
227
+ const path = node.startsWith("$event.") || node.startsWith("$event/") ? node.slice(7) : node.slice(7);
228
+ const event = (context2 == null ? void 0 : context2.$event) || (context2 == null ? void 0 : context2.event) || (context2 && !isNode(context2) ? context2 : null);
229
+ const res = node === "$event" ? event : resolvePath(path, event);
230
+ return unwrapSignal(res);
231
+ }
232
+ if (node === "_" || node.startsWith("_/") || node.startsWith("_.")) {
233
+ const path = node.startsWith("_.") || node.startsWith("_/") ? node.slice(2) : node.slice(2);
234
+ const res = node === "_" ? context2 : resolvePath(path, context2);
235
+ return unwrapSignal(res);
236
+ }
237
+ if (node.startsWith("../")) return unwrapSignal(resolvePath(node, context2));
238
+ }
239
+ if (Array.isArray(node)) return node.map((n) => resolveTemplate(n, context2));
240
+ if (node && typeof node === "object") {
241
+ const res = {};
242
+ for (const k in node) res[k] = resolveTemplate(node[k], context2);
243
+ return res;
244
+ }
245
+ return node;
246
+ };
247
+ const hasReactive = (obj) => {
248
+ if (typeof obj === "string") {
249
+ return obj.startsWith("=") || obj.startsWith("_") || obj.startsWith("../");
250
+ }
251
+ if (Array.isArray(obj)) return obj.some(hasReactive);
252
+ if (obj && typeof obj === "object") return Object.values(obj).some(hasReactive);
253
+ return false;
254
+ };
255
+ if (hasReactive(data)) {
256
+ return {
257
+ value: new LazyValue((context2) => resolveTemplate(data, context2)),
258
+ isLazy: true
259
+ };
260
+ }
261
+ return { value: data, isLiteral: true };
262
+ } catch (e) {
263
+ }
264
+ }
265
+ if (arg.includes("(")) {
266
+ let nestedExpr = arg;
267
+ if (arg.startsWith("/")) {
268
+ nestedExpr = "=" + arg;
269
+ } else if (globalMode && !arg.startsWith("=") && !arg.startsWith("./")) {
270
+ nestedExpr = `=/${arg}`;
271
+ }
272
+ const val = resolveExpression$1(nestedExpr, context);
273
+ if (val instanceof LazyValue) {
274
+ return { value: val, isLazy: true };
275
+ }
276
+ return { value: val, isSignal: false };
277
+ }
278
+ let normalizedPath;
279
+ if (arg.startsWith("/")) {
280
+ normalizedPath = "=" + arg;
281
+ } else if (arg.startsWith("=") || arg.startsWith("./") || arg.startsWith("../")) {
282
+ normalizedPath = arg;
283
+ } else if (globalMode) {
284
+ normalizedPath = `=/${arg}`;
285
+ } else {
286
+ normalizedPath = `./${arg}`;
287
+ }
288
+ const explosionIdx = arg.indexOf("...");
289
+ if (explosionIdx !== -1) {
290
+ const normExplosionIdx = normalizedPath.indexOf("...");
291
+ const pathPart = normalizedPath.slice(0, normExplosionIdx);
292
+ const propName = arg.slice(explosionIdx + 3);
293
+ const parent = resolvePath(pathPart, context);
294
+ const unwrappedParent = unwrapSignal(parent);
295
+ if (Array.isArray(unwrappedParent)) {
296
+ const values = unwrappedParent.map((item) => {
297
+ const unwrappedItem = unwrapSignal(item);
298
+ if (!propName) return unwrappedItem;
299
+ return unwrappedItem && typeof unwrappedItem === "object" ? unwrapSignal(unwrappedItem[propName]) : void 0;
300
+ });
301
+ return { value: values, isExplosion: true };
302
+ } else if (unwrappedParent && typeof unwrappedParent === "object") {
303
+ if (!propName) return { value: unwrappedParent, isExplosion: true };
304
+ const val = unwrappedParent[propName];
305
+ return { value: unwrapSignal(val), isExplosion: true };
306
+ }
307
+ return { value: void 0, isExplosion: true };
308
+ }
309
+ const value = resolvePathAsContext(normalizedPath, context);
310
+ return { value, isExplosion: false };
311
+ };
312
+ const TokenType = {
313
+ PATH: "PATH",
314
+ // $/user/age, ./name, ../parent
315
+ LITERAL: "LITERAL",
316
+ // 123, "hello", true, false, null
317
+ OPERATOR: "OPERATOR",
318
+ // +, -, *, /, ++, --, etc.
319
+ LPAREN: "LPAREN",
320
+ // (
321
+ RPAREN: "RPAREN",
322
+ // )
323
+ COMMA: "COMMA",
324
+ // ,
325
+ EXPLOSION: "EXPLOSION",
326
+ // ... suffix
327
+ PLACEHOLDER: "PLACEHOLDER",
328
+ // _, _/path
329
+ THIS: "THIS",
330
+ // $this
331
+ EVENT: "EVENT",
332
+ // $event, $event.target
333
+ LBRACE: "LBRACE",
334
+ // {
335
+ RBRACE: "RBRACE",
336
+ // }
337
+ LBRACKET: "LBRACKET",
338
+ // [
339
+ RBRACKET: "RBRACKET",
340
+ // ]
341
+ COLON: "COLON",
342
+ // :
343
+ EOF: "EOF"
344
+ };
345
+ const getOperatorSymbols = () => {
346
+ const allOps = /* @__PURE__ */ new Set([
347
+ ...operators.prefix.keys(),
348
+ ...operators.postfix.keys(),
349
+ ...operators.infix.keys()
350
+ ]);
351
+ return [...allOps].sort((a, b) => b.length - a.length);
352
+ };
353
+ const tokenize = (expr) => {
354
+ var _a, _b;
355
+ const tokens = [];
356
+ let i = 0;
357
+ const len2 = expr.length;
358
+ const opSymbols = getOperatorSymbols();
359
+ while (i < len2) {
360
+ if (/\s/.test(expr[i])) {
361
+ i++;
362
+ continue;
363
+ }
364
+ if (expr[i] === "=" && i === 0 && i + 1 < len2) {
365
+ const prefixOps = [...operators.prefix.keys()].sort((a, b) => b.length - a.length);
366
+ let matchedPrefix = null;
367
+ for (const op of prefixOps) {
368
+ if (expr.slice(i + 1, i + 1 + op.length) === op) {
369
+ matchedPrefix = op;
370
+ break;
371
+ }
372
+ }
373
+ if (matchedPrefix) {
374
+ i++;
375
+ continue;
376
+ }
377
+ const next = expr[i + 1];
378
+ if (next === "/" || next === "." || /[a-zA-Z_$]/.test(next)) {
379
+ i++;
380
+ continue;
381
+ }
382
+ }
383
+ if (expr[i] === "(") {
384
+ tokens.push({ type: TokenType.LPAREN, value: "(" });
385
+ i++;
386
+ continue;
387
+ }
388
+ if (expr[i] === ")") {
389
+ tokens.push({ type: TokenType.RPAREN, value: ")" });
390
+ i++;
391
+ continue;
392
+ }
393
+ if (expr[i] === ",") {
394
+ tokens.push({ type: TokenType.COMMA, value: "," });
395
+ i++;
396
+ continue;
397
+ }
398
+ if (expr[i] === "{") {
399
+ tokens.push({ type: TokenType.LBRACE, value: "{" });
400
+ i++;
401
+ continue;
402
+ }
403
+ if (expr[i] === "}") {
404
+ tokens.push({ type: TokenType.RBRACE, value: "}" });
405
+ i++;
406
+ continue;
407
+ }
408
+ if (expr[i] === "[") {
409
+ tokens.push({ type: TokenType.LBRACKET, value: "[" });
410
+ i++;
411
+ continue;
412
+ }
413
+ if (expr[i] === "]") {
414
+ tokens.push({ type: TokenType.RBRACKET, value: "]" });
415
+ i++;
416
+ continue;
417
+ }
418
+ if (expr[i] === ":") {
419
+ tokens.push({ type: TokenType.COLON, value: ":" });
420
+ i++;
421
+ continue;
422
+ }
423
+ let matchedOp = null;
424
+ for (const op of opSymbols) {
425
+ if (expr.slice(i, i + op.length) === op) {
426
+ const before = i > 0 ? expr[i - 1] : " ";
427
+ const after = i + op.length < len2 ? expr[i + op.length] : " ";
428
+ const infixConf = operators.infix.get(op);
429
+ const prefixConf = operators.prefix.get(op);
430
+ const postfixConf = operators.postfix.get(op);
431
+ if ((_a = infixConf == null ? void 0 : infixConf.options) == null ? void 0 : _a.requiresWhitespace) {
432
+ if (!prefixConf && !postfixConf) {
433
+ const isWhitespaceMatch = /\s/.test(before) && /\s/.test(after);
434
+ if (!isWhitespaceMatch) continue;
435
+ }
436
+ }
437
+ if (infixConf) {
438
+ const lastTok = tokens[tokens.length - 1];
439
+ const isValueContext = lastTok && (lastTok.type === TokenType.PATH || lastTok.type === TokenType.LITERAL || lastTok.type === TokenType.RPAREN || lastTok.type === TokenType.PLACEHOLDER || lastTok.type === TokenType.THIS || lastTok.type === TokenType.EVENT);
440
+ if (isValueContext) {
441
+ matchedOp = op;
442
+ break;
443
+ }
444
+ }
445
+ const validBefore = /[\s)]/.test(before) || i === 0 || tokens.length === 0 || tokens[tokens.length - 1].type === TokenType.LPAREN || tokens[tokens.length - 1].type === TokenType.COMMA || tokens[tokens.length - 1].type === TokenType.OPERATOR;
446
+ const validAfter = /[\s(=./'"0-9_]/.test(after) || i + op.length >= len2 || opSymbols.some((o) => expr.slice(i + op.length).startsWith(o));
447
+ if (validBefore || validAfter) {
448
+ matchedOp = op;
449
+ break;
450
+ }
451
+ }
452
+ }
453
+ if (matchedOp) {
454
+ tokens.push({ type: TokenType.OPERATOR, value: matchedOp });
455
+ i += matchedOp.length;
456
+ continue;
457
+ }
458
+ if (expr[i] === '"' || expr[i] === "'") {
459
+ const quote = expr[i];
460
+ let str = "";
461
+ i++;
462
+ while (i < len2 && expr[i] !== quote) {
463
+ if (expr[i] === "\\" && i + 1 < len2) {
464
+ i++;
465
+ if (expr[i] === "n") str += "\n";
466
+ else if (expr[i] === "t") str += " ";
467
+ else str += expr[i];
468
+ } else {
469
+ str += expr[i];
470
+ }
471
+ i++;
472
+ }
473
+ i++;
474
+ tokens.push({ type: TokenType.LITERAL, value: str });
475
+ continue;
476
+ }
477
+ if (/\d/.test(expr[i]) || expr[i] === "-" && /\d/.test(expr[i + 1]) && (tokens.length === 0 || tokens[tokens.length - 1].type === TokenType.OPERATOR || tokens[tokens.length - 1].type === TokenType.LPAREN || tokens[tokens.length - 1].type === TokenType.COMMA)) {
478
+ let num = "";
479
+ if (expr[i] === "-") {
480
+ num = "-";
481
+ i++;
482
+ }
483
+ while (i < len2 && /[\d.]/.test(expr[i])) {
484
+ num += expr[i];
485
+ i++;
486
+ }
487
+ tokens.push({ type: TokenType.LITERAL, value: parseFloat(num) });
488
+ continue;
489
+ }
490
+ if (expr[i] === "_" && (i + 1 >= len2 || !/[a-zA-Z0-9]/.test(expr[i + 1]) || expr[i + 1] === "/" || expr[i + 1] === ".")) {
491
+ let placeholder = "_";
492
+ i++;
493
+ if (i < len2 && (expr[i] === "/" || expr[i] === ".")) {
494
+ while (i < len2 && !/[\s,)(]/.test(expr[i])) {
495
+ placeholder += expr[i];
496
+ i++;
497
+ }
498
+ }
499
+ tokens.push({ type: TokenType.PLACEHOLDER, value: placeholder });
500
+ continue;
501
+ }
502
+ if (expr.slice(i, i + 5) === "$this") {
503
+ let thisPath = "$this";
504
+ i += 5;
505
+ while (i < len2 && /[a-zA-Z0-9_./]/.test(expr[i])) {
506
+ thisPath += expr[i];
507
+ i++;
508
+ }
509
+ tokens.push({ type: TokenType.THIS, value: thisPath });
510
+ continue;
511
+ }
512
+ if (expr.slice(i, i + 6) === "$event") {
513
+ let eventPath = "$event";
514
+ i += 6;
515
+ while (i < len2 && /[a-zA-Z0-9_./]/.test(expr[i])) {
516
+ eventPath += expr[i];
517
+ i++;
518
+ }
519
+ tokens.push({ type: TokenType.EVENT, value: eventPath });
520
+ continue;
521
+ }
522
+ if (expr[i] === "=" || expr[i] === "." || expr[i] === "/") {
523
+ let path = "";
524
+ while (i < len2) {
525
+ let isOp = false;
526
+ for (const op of opSymbols) {
527
+ if (expr.slice(i, i + op.length) === op) {
528
+ const infixConf = operators.infix.get(op);
529
+ const prefixConf = operators.prefix.get(op);
530
+ const postfixConf = operators.postfix.get(op);
531
+ if ((_b = infixConf == null ? void 0 : infixConf.options) == null ? void 0 : _b.requiresWhitespace) {
532
+ if (!prefixConf && !postfixConf) {
533
+ const after = i + op.length < len2 ? expr[i + op.length] : " ";
534
+ if (/\s/.test(expr[i - 1]) && /\s/.test(after)) {
535
+ isOp = true;
536
+ break;
537
+ }
538
+ continue;
539
+ }
540
+ }
541
+ if (path.length > 0 && path[path.length - 1] !== "/") {
542
+ isOp = true;
543
+ break;
544
+ }
545
+ }
546
+ }
547
+ if (isOp) break;
548
+ if (/[\s,()]/.test(expr[i])) break;
549
+ if (expr.slice(i, i + 3) === "...") {
550
+ break;
551
+ }
552
+ path += expr[i];
553
+ i++;
554
+ }
555
+ if (expr.slice(i, i + 3) === "...") {
556
+ tokens.push({ type: TokenType.PATH, value: path });
557
+ tokens.push({ type: TokenType.EXPLOSION, value: "..." });
558
+ i += 3;
559
+ } else {
560
+ tokens.push({ type: TokenType.PATH, value: path });
561
+ }
562
+ continue;
563
+ }
564
+ if (/[a-zA-Z]/.test(expr[i])) {
565
+ let ident = "";
566
+ while (i < len2 && /[a-zA-Z0-9_]/.test(expr[i])) {
567
+ ident += expr[i];
568
+ i++;
569
+ }
570
+ if (ident === "true") tokens.push({ type: TokenType.LITERAL, value: true });
571
+ else if (ident === "false") tokens.push({ type: TokenType.LITERAL, value: false });
572
+ else if (ident === "null") tokens.push({ type: TokenType.LITERAL, value: null });
573
+ else tokens.push({ type: TokenType.PATH, value: ident });
574
+ continue;
575
+ }
576
+ i++;
577
+ }
578
+ tokens.push({ type: TokenType.EOF, value: null });
579
+ return tokens;
580
+ };
581
+ const hasOperatorSyntax = (expr) => {
582
+ if (!expr || typeof expr !== "string") return false;
583
+ if (/^=?(\+\+|--|!!)\/?/.test(expr)) {
584
+ return true;
585
+ }
586
+ if (/(\+\+|--)$/.test(expr)) {
587
+ return true;
588
+ }
589
+ if (/\s+([+\-*/%]|>|<|>=|<=|!=|===|==|=)\s+/.test(expr)) {
590
+ return true;
591
+ }
592
+ if (/[^=\s]([+%=]|==|===|!=|!==|<=|>=|<|>)[^=\s]/.test(expr)) {
593
+ return true;
594
+ }
595
+ return false;
596
+ };
597
+ class PrattParser {
598
+ constructor(tokens, context, isGlobalMode = false) {
599
+ this.tokens = tokens;
600
+ this.pos = 0;
601
+ this.context = context;
602
+ this.isGlobalMode = isGlobalMode;
603
+ }
604
+ peek() {
605
+ return this.tokens[this.pos] || { type: TokenType.EOF, value: null };
606
+ }
607
+ consume() {
608
+ return this.tokens[this.pos++];
609
+ }
610
+ expect(type) {
611
+ const tok = this.consume();
612
+ if (tok.type !== type) {
613
+ throw new Error(`JPRX: Expected ${type} but got ${tok.type}`);
614
+ }
615
+ return tok;
616
+ }
617
+ /**
618
+ * Get binding power (precedence) for an infix or postfix operator.
619
+ */
620
+ getInfixPrecedence(op) {
621
+ const infixInfo = operators.infix.get(op);
622
+ if (infixInfo) return infixInfo.precedence;
623
+ const postfixInfo = operators.postfix.get(op);
624
+ if (postfixInfo) return postfixInfo.precedence;
625
+ return 0;
626
+ }
627
+ /**
628
+ * Parse an expression with given minimum precedence.
629
+ */
630
+ parseExpression(minPrecedence = 0) {
631
+ let left = this.parsePrefix();
632
+ let tok = this.peek();
633
+ while (tok.type === TokenType.OPERATOR) {
634
+ const prec = this.getInfixPrecedence(tok.value);
635
+ if (prec < minPrecedence) break;
636
+ if (operators.postfix.has(tok.value) && !operators.infix.has(tok.value)) {
637
+ this.consume();
638
+ left = { type: "Postfix", operator: tok.value, operand: left };
639
+ tok = this.peek();
640
+ continue;
641
+ }
642
+ if (operators.infix.has(tok.value)) {
643
+ this.consume();
644
+ const right = this.parseExpression(prec + 1);
645
+ left = { type: "Infix", operator: tok.value, left, right };
646
+ tok = this.peek();
647
+ continue;
648
+ }
649
+ if (!operators.postfix.has(tok.value) && !operators.infix.has(tok.value)) {
650
+ break;
651
+ }
652
+ this.consume();
653
+ const nextTok = this.peek();
654
+ if (nextTok.type === TokenType.PATH || nextTok.type === TokenType.LITERAL || nextTok.type === TokenType.LPAREN || nextTok.type === TokenType.PLACEHOLDER || nextTok.type === TokenType.EVENT || nextTok.type === TokenType.OPERATOR && operators.prefix.has(nextTok.value)) {
655
+ const right = this.parseExpression(prec + 1);
656
+ left = { type: "Infix", operator: tok.value, left, right };
657
+ } else {
658
+ left = { type: "Postfix", operator: tok.value, operand: left };
659
+ }
660
+ tok = this.peek();
661
+ }
662
+ return left;
663
+ }
664
+ /**
665
+ * Parse a prefix expression (literals, paths, prefix operators, groups).
666
+ */
667
+ parsePrefix() {
668
+ const tok = this.peek();
669
+ if (tok.type === TokenType.OPERATOR && operators.prefix.has(tok.value)) {
670
+ this.consume();
671
+ const prefixInfo = operators.prefix.get(tok.value);
672
+ const operand = this.parseExpression(prefixInfo.precedence);
673
+ return { type: "Prefix", operator: tok.value, operand };
674
+ }
675
+ if (tok.type === TokenType.LPAREN) {
676
+ this.consume();
677
+ const inner = this.parseExpression(0);
678
+ this.expect(TokenType.RPAREN);
679
+ return inner;
680
+ }
681
+ if (tok.type === TokenType.LITERAL) {
682
+ this.consume();
683
+ return { type: "Literal", value: tok.value };
684
+ }
685
+ if (tok.type === TokenType.PLACEHOLDER) {
686
+ this.consume();
687
+ return { type: "Placeholder", value: tok.value };
688
+ }
689
+ if (tok.type === TokenType.THIS) {
690
+ this.consume();
691
+ return { type: "This", value: tok.value };
692
+ }
693
+ if (tok.type === TokenType.EVENT) {
694
+ this.consume();
695
+ return { type: "Event", value: tok.value };
696
+ }
697
+ if (tok.type === TokenType.PATH) {
698
+ this.consume();
699
+ const nextTok = this.peek();
700
+ if (nextTok.type === TokenType.EXPLOSION) {
701
+ this.consume();
702
+ return { type: "Explosion", path: tok.value };
703
+ }
704
+ if (nextTok.type === TokenType.LPAREN) {
705
+ this.consume();
706
+ const args = [];
707
+ while (this.peek().type !== TokenType.RPAREN && this.peek().type !== TokenType.EOF) {
708
+ args.push(this.parseExpression(0));
709
+ if (this.peek().type === TokenType.COMMA) {
710
+ this.consume();
711
+ }
712
+ }
713
+ this.expect(TokenType.RPAREN);
714
+ return { type: "Call", helper: tok.value, args };
715
+ }
716
+ return { type: "Path", value: tok.value };
717
+ }
718
+ if (tok.type === TokenType.LBRACE) {
719
+ return this.parseObjectLiteral();
720
+ }
721
+ if (tok.type === TokenType.LBRACKET) {
722
+ return this.parseArrayLiteral();
723
+ }
724
+ if (tok.type === TokenType.EOF) {
725
+ return { type: "Literal", value: void 0 };
726
+ }
727
+ throw new Error(`JPRX: Unexpected token ${tok.type}: ${tok.value}`);
728
+ }
729
+ parseObjectLiteral() {
730
+ this.consume();
731
+ const properties = {};
732
+ while (this.peek().type !== TokenType.RBRACE && this.peek().type !== TokenType.EOF) {
733
+ const keyTok = this.consume();
734
+ let key;
735
+ if (keyTok.type === TokenType.LITERAL) key = String(keyTok.value);
736
+ else if (keyTok.type === TokenType.PATH) key = keyTok.value;
737
+ else if (keyTok.type === TokenType.PATH) key = keyTok.value;
738
+ else throw new Error(`JPRX: Expected property name but got ${keyTok.type}`);
739
+ this.expect(TokenType.COLON);
740
+ const value = this.parseExpression(0);
741
+ properties[key] = value;
742
+ if (this.peek().type === TokenType.COMMA) {
743
+ this.consume();
744
+ } else if (this.peek().type !== TokenType.RBRACE) {
745
+ break;
746
+ }
747
+ }
748
+ this.expect(TokenType.RBRACE);
749
+ return { type: "ObjectLiteral", properties };
750
+ }
751
+ parseArrayLiteral() {
752
+ this.consume();
753
+ const elements = [];
754
+ while (this.peek().type !== TokenType.RBRACKET && this.peek().type !== TokenType.EOF) {
755
+ const value = this.parseExpression(0);
756
+ elements.push(value);
757
+ if (this.peek().type === TokenType.COMMA) {
758
+ this.consume();
759
+ } else if (this.peek().type !== TokenType.RBRACKET) {
760
+ break;
761
+ }
762
+ }
763
+ this.expect(TokenType.RBRACKET);
764
+ return { type: "ArrayLiteral", elements };
765
+ }
766
+ }
767
+ const evaluateAST = (ast, context, forMutation = false) => {
768
+ var _a;
769
+ if (!ast) return void 0;
770
+ switch (ast.type) {
771
+ case "Literal":
772
+ return ast.value;
773
+ case "Path": {
774
+ const resolved = forMutation ? resolvePathAsContext(ast.value, context) : resolvePath(ast.value, context);
775
+ return forMutation ? resolved : unwrapSignal(resolved);
776
+ }
777
+ case "Placeholder": {
778
+ return new LazyValue((item) => {
779
+ if (ast.value === "_") return item;
780
+ const path = ast.value.startsWith("_.") ? ast.value.slice(2) : ast.value.slice(2);
781
+ return resolvePath(path, item);
782
+ });
783
+ }
784
+ case "This": {
785
+ return new LazyValue((context2) => {
786
+ const node = (context2 == null ? void 0 : context2.__node__) || context2;
787
+ if (ast.value === "$this") return node;
788
+ const path = ast.value.startsWith("$this.") ? ast.value.slice(6) : ast.value.slice(6);
789
+ return resolvePath(path, node);
790
+ });
791
+ }
792
+ case "Event": {
793
+ return new LazyValue((context2) => {
794
+ const event = (context2 == null ? void 0 : context2.$event) || (context2 == null ? void 0 : context2.event) || context2;
795
+ if (ast.value === "$event") return event;
796
+ const path = ast.value.startsWith("$event.") ? ast.value.slice(7) : ast.value.slice(7);
797
+ return resolvePath(path, event);
798
+ });
799
+ }
800
+ case "ObjectLiteral": {
801
+ const res = {};
802
+ let hasLazy = false;
803
+ for (const key in ast.properties) {
804
+ const val = evaluateAST(ast.properties[key], context, forMutation);
805
+ if (val && val.isLazy) hasLazy = true;
806
+ res[key] = val;
807
+ }
808
+ if (hasLazy) {
809
+ return new LazyValue((ctx) => {
810
+ const resolved = {};
811
+ for (const key in res) {
812
+ resolved[key] = res[key] && res[key].isLazy ? res[key].resolve(ctx) : unwrapSignal(res[key]);
813
+ }
814
+ return resolved;
815
+ });
816
+ }
817
+ return res;
818
+ }
819
+ case "ArrayLiteral": {
820
+ const elements = ast.elements.map((el) => evaluateAST(el, context, forMutation));
821
+ const hasLazy = elements.some((el) => el && el.isLazy);
822
+ if (hasLazy) {
823
+ return new LazyValue((ctx) => {
824
+ return elements.map((el) => el && el.isLazy ? el.resolve(ctx) : unwrapSignal(el));
825
+ });
826
+ }
827
+ return elements.map((el) => unwrapSignal(el));
828
+ }
829
+ case "Prefix": {
830
+ const opInfo = operators.prefix.get(ast.operator);
831
+ if (!opInfo) throw new Error(`JPRX: Unknown prefix operator: ${ast.operator}`);
832
+ const helper = helpers.get(opInfo.helper);
833
+ if (!helper) throw new Error(`JPRX: Helper "${opInfo.helper}" for operator "${ast.operator}" not found.`);
834
+ const opts = helperOptions.get(opInfo.helper) || {};
835
+ const operand = evaluateAST(ast.operand, context, opts.pathAware);
836
+ if (operand && operand.isLazy && !opts.lazyAware) {
837
+ return new LazyValue((ctx) => {
838
+ const resolved = operand.resolve(ctx);
839
+ return helper(opts.pathAware ? resolved : unwrapSignal(resolved));
840
+ });
841
+ }
842
+ return helper(opts.pathAware ? operand : unwrapSignal(operand));
843
+ }
844
+ case "Postfix": {
845
+ const opInfo = operators.postfix.get(ast.operator);
846
+ if (!opInfo) throw new Error(`JPRX: Unknown postfix operator: ${ast.operator}`);
847
+ const helper = helpers.get(opInfo.helper);
848
+ if (!helper) throw new Error(`JPRX: Helper "${opInfo.helper}" for operator "${ast.operator}" not found.`);
849
+ const opts = helperOptions.get(opInfo.helper) || {};
850
+ const operand = evaluateAST(ast.operand, context, opts.pathAware);
851
+ if (operand && operand.isLazy && !opts.lazyAware) {
852
+ return new LazyValue((ctx) => {
853
+ const resolved = operand.resolve(ctx);
854
+ return helper(opts.pathAware ? resolved : unwrapSignal(resolved));
855
+ });
856
+ }
857
+ return helper(opts.pathAware ? operand : unwrapSignal(operand));
858
+ }
859
+ case "Infix": {
860
+ const opInfo = operators.infix.get(ast.operator);
861
+ if (!opInfo) throw new Error(`JPRX: Unknown infix operator: ${ast.operator}`);
862
+ const helper = helpers.get(opInfo.helper);
863
+ if (!helper) throw new Error(`JPRX: Helper "${opInfo.helper}" for operator "${ast.operator}" not found.`);
864
+ const opts = helperOptions.get(opInfo.helper) || {};
865
+ const left = evaluateAST(ast.left, context, opts.pathAware);
866
+ const right = evaluateAST(ast.right, context, false);
867
+ if ((left && left.isLazy || right && right.isLazy) && !opts.lazyAware) {
868
+ return new LazyValue((ctx) => {
869
+ const l = left && left.isLazy ? left.resolve(ctx) : left;
870
+ const r = right && right.isLazy ? right.resolve(ctx) : right;
871
+ return helper(opts.pathAware ? l : unwrapSignal(l), unwrapSignal(r));
872
+ });
873
+ }
874
+ return helper(opts.pathAware ? left : unwrapSignal(left), unwrapSignal(right));
875
+ }
876
+ case "Call": {
877
+ const helperName = ast.helper.replace(/^=/, "");
878
+ const helper = helpers.get(helperName);
879
+ if (!helper) {
880
+ (_a = globalThis.console) == null ? void 0 : _a.warn(`JPRX: Helper "${helperName}" not found.`);
881
+ return void 0;
882
+ }
883
+ const opts = helperOptions.get(helperName) || {};
884
+ const args = ast.args.map((arg, i) => evaluateAST(arg, context, opts.pathAware && i === 0));
885
+ const hasLazy = args.some((arg) => arg && arg.isLazy);
886
+ if (hasLazy && !opts.lazyAware) {
887
+ return new LazyValue((ctx) => {
888
+ const finalArgs2 = args.map((arg, i) => {
889
+ const val = arg && arg.isLazy ? arg.resolve(ctx) : arg;
890
+ if (ast.args[i].type === "Explosion" && Array.isArray(val)) {
891
+ return val.map((v) => unwrapSignal(v));
892
+ }
893
+ return opts.pathAware && i === 0 ? val : unwrapSignal(val);
894
+ });
895
+ const flatArgs = [];
896
+ for (let i = 0; i < finalArgs2.length; i++) {
897
+ if (ast.args[i].type === "Explosion" && Array.isArray(finalArgs2[i])) {
898
+ flatArgs.push(...finalArgs2[i]);
899
+ } else {
900
+ flatArgs.push(finalArgs2[i]);
901
+ }
902
+ }
903
+ return helper.apply((context == null ? void 0 : context.__node__) || null, flatArgs);
904
+ });
905
+ }
906
+ const finalArgs = [];
907
+ for (let i = 0; i < args.length; i++) {
908
+ const arg = args[i];
909
+ if (ast.args[i].type === "Explosion" && Array.isArray(arg)) {
910
+ finalArgs.push(...arg.map((v) => unwrapSignal(v)));
911
+ } else {
912
+ finalArgs.push(opts.pathAware && i === 0 ? arg : unwrapSignal(arg));
913
+ }
914
+ }
915
+ return helper.apply((context == null ? void 0 : context.__node__) || null, finalArgs);
916
+ }
917
+ case "Explosion": {
918
+ const result = resolveArgument(ast.path + "...", context, false);
919
+ return result.value;
920
+ }
921
+ default:
922
+ throw new Error(`JPRX: Unknown AST node type: ${ast.type}`);
923
+ }
924
+ };
925
+ const parseWithPratt = (expr, context) => {
926
+ const tokens = tokenize(expr);
927
+ const parser = new PrattParser(tokens, context);
928
+ const ast = parser.parseExpression(0);
929
+ return evaluateAST(ast, context);
930
+ };
931
+ const resolveExpression$1 = (expr, context) => {
932
+ var _a, _b;
933
+ if (typeof expr !== "string") return expr;
934
+ if (hasOperatorSyntax(expr)) {
935
+ try {
936
+ return parseWithPratt(expr, context);
937
+ } catch (e) {
938
+ (_a = globalThis.console) == null ? void 0 : _a.warn("JPRX: Pratt parser failed, falling back to legacy:", e.message);
939
+ }
940
+ }
941
+ const funcStart = expr.indexOf("(");
942
+ if (funcStart !== -1 && expr.endsWith(")")) {
943
+ const fullPath = expr.slice(0, funcStart).trim();
944
+ const argsStr = expr.slice(funcStart + 1, -1);
945
+ const segments = fullPath.split("/");
946
+ let funcName = segments.pop().replace(/^=/, "");
947
+ if (funcName === "" && (segments.length > 0 || fullPath === "/")) {
948
+ funcName = "/";
949
+ }
950
+ const navPath = segments.join("/");
951
+ const isGlobalExpr = expr.startsWith("=/") || expr.startsWith("=");
952
+ let baseContext = context;
953
+ if (navPath && navPath !== "=") {
954
+ baseContext = resolvePathAsContext(navPath, context);
955
+ }
956
+ const helper = helpers.get(funcName);
957
+ if (!helper) {
958
+ (_b = globalThis.console) == null ? void 0 : _b.warn(`LightviewCDOM: Helper "${funcName}" not found.`);
959
+ return expr;
960
+ }
961
+ const options = helperOptions.get(funcName) || {};
962
+ const argsList = [];
963
+ let current = "", parenDepth = 0, braceDepth = 0, bracketDepth = 0, quote = null;
964
+ for (let i = 0; i < argsStr.length; i++) {
965
+ const char = argsStr[i];
966
+ if (char === quote) quote = null;
967
+ else if (!quote && (char === "'" || char === '"')) quote = char;
968
+ else if (!quote && char === "(") parenDepth++;
969
+ else if (!quote && char === ")") parenDepth--;
970
+ else if (!quote && char === "{") braceDepth++;
971
+ else if (!quote && char === "}") braceDepth--;
972
+ else if (!quote && char === "[") bracketDepth++;
973
+ else if (!quote && char === "]") bracketDepth--;
974
+ else if (!quote && char === "," && parenDepth === 0 && braceDepth === 0 && bracketDepth === 0) {
975
+ argsList.push(current.trim());
976
+ current = "";
977
+ continue;
978
+ }
979
+ current += char;
980
+ }
981
+ if (current) argsList.push(current.trim());
982
+ const resolvedArgs = [];
983
+ let hasLazy = false;
984
+ for (let i = 0; i < argsList.length; i++) {
985
+ const arg = argsList[i];
986
+ const useGlobalMode = isGlobalExpr && (navPath === "=" || !navPath);
987
+ const res = resolveArgument(arg, baseContext, useGlobalMode);
988
+ if (res.isLazy) hasLazy = true;
989
+ const shouldUnwrap = !(options.pathAware && i === 0);
990
+ let val = res.value;
991
+ if (shouldUnwrap && !(val && val.isLazy)) {
992
+ val = unwrapSignal(val);
993
+ }
994
+ if (res.isExplosion && Array.isArray(val)) {
995
+ resolvedArgs.push(...val.map((v) => shouldUnwrap && !(v && v.isLazy) ? unwrapSignal(v) : v));
996
+ } else {
997
+ resolvedArgs.push(val);
998
+ }
999
+ }
1000
+ if (hasLazy && !options.lazyAware) {
1001
+ return new LazyValue((contextOverride) => {
1002
+ const finalArgs = resolvedArgs.map((arg, i) => {
1003
+ const shouldUnwrap = !(options.pathAware && i === 0);
1004
+ const resolved = arg instanceof LazyValue ? arg.resolve(contextOverride) : arg;
1005
+ return shouldUnwrap ? unwrapSignal(resolved) : resolved;
1006
+ });
1007
+ return helper(...finalArgs);
1008
+ });
1009
+ }
1010
+ const result = helper.apply((context == null ? void 0 : context.__node__) || null, resolvedArgs);
1011
+ return unwrapSignal(result);
1012
+ }
1013
+ return unwrapSignal(resolvePath(expr, context));
1014
+ };
1015
+ const parseExpression = (expr, context) => {
1016
+ const LV = getLV();
1017
+ if (!LV || typeof expr !== "string") return expr;
1018
+ return LV.computed(() => resolveExpression$1(expr, context));
1019
+ };
1020
+ const parseCDOMC = (input) => {
1021
+ if (typeof input !== "string") return input;
1022
+ let i = 0;
1023
+ const len2 = input.length;
1024
+ const skipWhitespace = () => {
1025
+ while (i < len2) {
1026
+ const char = input[i];
1027
+ if (/\s/.test(char)) {
1028
+ i++;
1029
+ continue;
1030
+ }
1031
+ if (char === "/") {
1032
+ const next = input[i + 1];
1033
+ if (next === "/") {
1034
+ i += 2;
1035
+ while (i < len2 && input[i] !== "\n" && input[i] !== "\r") i++;
1036
+ continue;
1037
+ } else if (next === "*") {
1038
+ i += 2;
1039
+ while (i < len2) {
1040
+ if (input[i] === "*" && input[i + 1] === "/") {
1041
+ i += 2;
1042
+ break;
1043
+ }
1044
+ i++;
1045
+ }
1046
+ continue;
1047
+ }
1048
+ }
1049
+ break;
1050
+ }
1051
+ };
1052
+ const parseString = () => {
1053
+ const quote = input[i++];
1054
+ let res2 = "";
1055
+ while (i < len2) {
1056
+ const char = input[i++];
1057
+ if (char === quote) return res2;
1058
+ if (char === "\\") {
1059
+ const next = input[i++];
1060
+ if (next === "n") res2 += "\n";
1061
+ else if (next === "t") res2 += " ";
1062
+ else if (next === '"') res2 += '"';
1063
+ else if (next === "'") res2 += "'";
1064
+ else if (next === "\\") res2 += "\\";
1065
+ else res2 += next;
1066
+ } else {
1067
+ res2 += char;
1068
+ }
1069
+ }
1070
+ throw new Error("Unterminated string");
1071
+ };
1072
+ const parseWord = () => {
1073
+ const start = i;
1074
+ let pDepth = 0;
1075
+ let bDepth = 0;
1076
+ let brDepth = 0;
1077
+ let quote = null;
1078
+ const startChar = input[start];
1079
+ const isExpression = startChar === "=" || startChar === "#";
1080
+ while (i < len2) {
1081
+ const char = input[i];
1082
+ if (quote) {
1083
+ if (char === quote && input[i - 1] !== "\\") quote = null;
1084
+ i++;
1085
+ continue;
1086
+ } else if (char === '"' || char === "'" || char === "`") {
1087
+ quote = char;
1088
+ i++;
1089
+ continue;
1090
+ }
1091
+ if (char === "(") {
1092
+ pDepth++;
1093
+ i++;
1094
+ continue;
1095
+ }
1096
+ if (char === "{") {
1097
+ bDepth++;
1098
+ i++;
1099
+ continue;
1100
+ }
1101
+ if (char === "[") {
1102
+ brDepth++;
1103
+ i++;
1104
+ continue;
1105
+ }
1106
+ if (char === ")") {
1107
+ if (pDepth > 0) {
1108
+ pDepth--;
1109
+ i++;
1110
+ continue;
1111
+ }
1112
+ }
1113
+ if (char === "}") {
1114
+ if (bDepth > 0) {
1115
+ bDepth--;
1116
+ i++;
1117
+ continue;
1118
+ }
1119
+ }
1120
+ if (char === "]") {
1121
+ if (brDepth > 0) {
1122
+ brDepth--;
1123
+ i++;
1124
+ continue;
1125
+ }
1126
+ }
1127
+ if (pDepth === 0 && bDepth === 0 && brDepth === 0) {
1128
+ if (isExpression) {
1129
+ if (/[{}[\]"'`()]/.test(char)) {
1130
+ break;
1131
+ }
1132
+ if (char === ",") {
1133
+ break;
1134
+ }
1135
+ if (/[\s:]/.test(char)) {
1136
+ let j = i + 1;
1137
+ while (j < len2 && /\s/.test(input[j])) j++;
1138
+ if (j < len2) {
1139
+ const nextChar = input[j];
1140
+ if (nextChar === "}" || nextChar === ",") {
1141
+ break;
1142
+ }
1143
+ let wordStart = j;
1144
+ while (j < len2 && /[a-zA-Z0-9_$-]/.test(input[j])) j++;
1145
+ if (j > wordStart) {
1146
+ while (j < len2 && /\s/.test(input[j])) j++;
1147
+ if (j < len2 && input[j] === ":") {
1148
+ break;
1149
+ }
1150
+ }
1151
+ }
1152
+ }
1153
+ } else {
1154
+ if (/[:,{}[\]"'`()\s]/.test(char)) {
1155
+ break;
1156
+ }
1157
+ }
1158
+ }
1159
+ i++;
1160
+ }
1161
+ const word = input.slice(start, i);
1162
+ if (word.startsWith("=") || word.startsWith("#")) {
1163
+ return word;
1164
+ }
1165
+ if (word === "true") return true;
1166
+ if (word === "false") return false;
1167
+ if (word === "null") return null;
1168
+ if (word.trim() !== "" && !isNaN(Number(word))) return Number(word);
1169
+ return word;
1170
+ };
1171
+ const parseValue = () => {
1172
+ skipWhitespace();
1173
+ if (i >= len2) return void 0;
1174
+ const char = input[i];
1175
+ if (char === "{") return parseObject();
1176
+ if (char === "[") return parseArray();
1177
+ if (char === '"' || char === "'") return parseString();
1178
+ return parseWord();
1179
+ };
1180
+ const parseObject = () => {
1181
+ i++;
1182
+ const obj = {};
1183
+ skipWhitespace();
1184
+ if (i < len2 && input[i] === "}") {
1185
+ i++;
1186
+ return obj;
1187
+ }
1188
+ while (i < len2) {
1189
+ skipWhitespace();
1190
+ let key;
1191
+ if (input[i] === '"' || input[i] === "'") key = parseString();
1192
+ else key = parseWord();
1193
+ skipWhitespace();
1194
+ if (input[i] !== ":") throw new Error(`Expected ':' at position ${i}, found '${input[i]}'`);
1195
+ i++;
1196
+ const value = parseValue();
1197
+ obj[String(key)] = value;
1198
+ skipWhitespace();
1199
+ if (input[i] === "}") {
1200
+ i++;
1201
+ return obj;
1202
+ }
1203
+ if (input[i] === ",") {
1204
+ i++;
1205
+ skipWhitespace();
1206
+ if (input[i] === "}") {
1207
+ i++;
1208
+ return obj;
1209
+ }
1210
+ continue;
1211
+ }
1212
+ throw new Error(`Expected '}' or ',' at position ${i}, found '${input[i]}'`);
1213
+ }
1214
+ };
1215
+ const parseArray = () => {
1216
+ i++;
1217
+ const arr = [];
1218
+ skipWhitespace();
1219
+ if (i < len2 && input[i] === "]") {
1220
+ i++;
1221
+ return arr;
1222
+ }
1223
+ while (i < len2) {
1224
+ const val = parseValue();
1225
+ arr.push(val);
1226
+ skipWhitespace();
1227
+ if (input[i] === "]") {
1228
+ i++;
1229
+ return arr;
1230
+ }
1231
+ if (input[i] === ",") {
1232
+ i++;
1233
+ skipWhitespace();
1234
+ if (input[i] === "]") {
1235
+ i++;
1236
+ return arr;
1237
+ }
1238
+ continue;
1239
+ }
1240
+ throw new Error(`Expected ']' or ',' at position ${i}, found '${input[i]}'`);
1241
+ }
1242
+ };
1243
+ skipWhitespace();
1244
+ const res = parseValue();
1245
+ return res;
1246
+ };
1247
+ const parseJPRX = (input) => {
1248
+ var _a, _b;
1249
+ if (typeof input !== "string") return input;
1250
+ let result = "";
1251
+ let i = 0;
1252
+ const len2 = input.length;
1253
+ while (i < len2) {
1254
+ const char = input[i];
1255
+ if (char === "/" && input[i + 1] === "/") {
1256
+ while (i < len2 && input[i] !== "\n") i++;
1257
+ continue;
1258
+ }
1259
+ if (char === "/" && input[i + 1] === "*") {
1260
+ i += 2;
1261
+ while (i < len2 && !(input[i] === "*" && input[i + 1] === "/")) i++;
1262
+ i += 2;
1263
+ continue;
1264
+ }
1265
+ if (char === '"' || char === "'") {
1266
+ const quote = char;
1267
+ result += '"';
1268
+ i++;
1269
+ while (i < len2 && input[i] !== quote) {
1270
+ const c = input[i];
1271
+ if (c === "\\") {
1272
+ result += "\\";
1273
+ i++;
1274
+ if (i < len2) {
1275
+ const next = input[i];
1276
+ if (next === '"') result += '\\"';
1277
+ else result += next;
1278
+ i++;
1279
+ }
1280
+ } else if (c === '"') {
1281
+ result += '\\"';
1282
+ i++;
1283
+ } else if (c === "\n") {
1284
+ result += "\\n";
1285
+ i++;
1286
+ } else if (c === "\r") {
1287
+ result += "\\r";
1288
+ i++;
1289
+ } else if (c === " ") {
1290
+ result += "\\t";
1291
+ i++;
1292
+ } else {
1293
+ result += c;
1294
+ i++;
1295
+ }
1296
+ }
1297
+ result += '"';
1298
+ i++;
1299
+ continue;
1300
+ }
1301
+ if (char === "=") {
1302
+ let expr = "";
1303
+ let parenDepth = 0;
1304
+ let braceDepth = 0;
1305
+ let bracketDepth = 0;
1306
+ let inExprQuote = null;
1307
+ while (i < len2) {
1308
+ const c = input[i];
1309
+ if (inExprQuote) {
1310
+ if (c === inExprQuote && input[i - 1] !== "\\") inExprQuote = null;
1311
+ } else if (c === '"' || c === "'") {
1312
+ inExprQuote = c;
1313
+ } else {
1314
+ if (parenDepth === 0 && braceDepth === 0 && bracketDepth === 0) {
1315
+ if (/[}[\]:]/.test(c) && expr.length > 1) break;
1316
+ if (c === ",") break;
1317
+ if (/\s/.test(c)) {
1318
+ let j = i + 1;
1319
+ while (j < len2 && /\s/.test(input[j])) j++;
1320
+ if (j < len2) {
1321
+ const nextChar = input[j];
1322
+ if (nextChar === "}" || nextChar === "," || nextChar === "]") {
1323
+ break;
1324
+ }
1325
+ let wordStart = j;
1326
+ while (j < len2 && /[a-zA-Z0-9_$-]/.test(input[j])) j++;
1327
+ if (j > wordStart) {
1328
+ while (j < len2 && /\s/.test(input[j])) j++;
1329
+ if (j < len2 && input[j] === ":") {
1330
+ break;
1331
+ }
1332
+ }
1333
+ }
1334
+ }
1335
+ }
1336
+ if (c === "(") parenDepth++;
1337
+ else if (c === ")") parenDepth--;
1338
+ else if (c === "{") braceDepth++;
1339
+ else if (c === "}") braceDepth--;
1340
+ else if (c === "[") bracketDepth++;
1341
+ else if (c === "]") bracketDepth--;
1342
+ }
1343
+ expr += c;
1344
+ i++;
1345
+ }
1346
+ result += JSON.stringify(expr);
1347
+ continue;
1348
+ }
1349
+ if (/[a-zA-Z_$\/.\/]/.test(char)) {
1350
+ let word = "";
1351
+ while (i < len2 && /[a-zA-Z0-9_$\/.-]/.test(input[i])) {
1352
+ word += input[i];
1353
+ i++;
1354
+ }
1355
+ let j = i;
1356
+ while (j < len2 && /\s/.test(input[j])) j++;
1357
+ if (input[j] === ":") {
1358
+ result += `"${word}"`;
1359
+ } else if (input[j] === "(") {
1360
+ let expr = word;
1361
+ i = j;
1362
+ let parenDepth = 0;
1363
+ let inQuote = null;
1364
+ while (i < len2) {
1365
+ const c = input[i];
1366
+ if (inQuote) {
1367
+ if (c === inQuote && input[i - 1] !== "\\") inQuote = null;
1368
+ } else if (c === '"' || c === "'") {
1369
+ inQuote = c;
1370
+ } else {
1371
+ if (c === "(") parenDepth++;
1372
+ else if (c === ")") {
1373
+ parenDepth--;
1374
+ if (parenDepth === 0) {
1375
+ expr += c;
1376
+ i++;
1377
+ break;
1378
+ }
1379
+ }
1380
+ }
1381
+ expr += c;
1382
+ i++;
1383
+ }
1384
+ result += JSON.stringify("=" + expr);
1385
+ } else {
1386
+ if (word === "true" || word === "false" || word === "null") {
1387
+ result += word;
1388
+ } else if (!isNaN(Number(word))) {
1389
+ result += word;
1390
+ } else {
1391
+ result += `"${word}"`;
1392
+ }
1393
+ }
1394
+ continue;
1395
+ }
1396
+ if (/[\d]/.test(char) || char === "-" && /\d/.test(input[i + 1])) {
1397
+ let num = "";
1398
+ while (i < len2 && /[\d.\-eE]/.test(input[i])) {
1399
+ num += input[i];
1400
+ i++;
1401
+ }
1402
+ result += num;
1403
+ continue;
1404
+ }
1405
+ result += char;
1406
+ i++;
1407
+ }
1408
+ try {
1409
+ return JSON.parse(result);
1410
+ } catch (e) {
1411
+ (_a = globalThis.console) == null ? void 0 : _a.error("parseJPRX: JSON parse failed", e);
1412
+ (_b = globalThis.console) == null ? void 0 : _b.error("Transformed input:", result);
1413
+ throw e;
1414
+ }
1415
+ };
1416
+ const add$1 = (...args) => args.reduce((a, b) => Number(a) + Number(b), 0);
1417
+ const subtract = (a, b) => Number(a) - Number(b);
1418
+ const multiply = (...args) => args.reduce((a, b) => Number(a) * Number(b), 1);
1419
+ const divide = (a, b) => Number(a) / Number(b);
1420
+ const round = (val, decimals = 0) => Number(Math.round(val + "e" + decimals) + "e-" + decimals);
1421
+ const ceil = (val) => Math.ceil(val);
1422
+ const floor = (val) => Math.floor(val);
1423
+ const abs = (val) => Math.abs(val);
1424
+ const mod$1 = (a, b) => a % b;
1425
+ const pow = (a, b) => Math.pow(a, b);
1426
+ const sqrt = (val) => Math.sqrt(val);
1427
+ const negate = (val) => -Number(val);
1428
+ const toPercent = (val) => Number(val) / 100;
1429
+ const registerMathHelpers = (register) => {
1430
+ register("+", add$1);
1431
+ register("add", add$1);
1432
+ register("-", subtract);
1433
+ register("sub", subtract);
1434
+ register("*", multiply);
1435
+ register("mul", multiply);
1436
+ register("/", divide);
1437
+ register("div", divide);
1438
+ register("round", round);
1439
+ register("ceil", ceil);
1440
+ register("floor", floor);
1441
+ register("abs", abs);
1442
+ register("mod", mod$1);
1443
+ register("pow", pow);
1444
+ register("sqrt", sqrt);
1445
+ register("negate", negate);
1446
+ register("toPercent", toPercent);
1447
+ };
1448
+ const ifHelper = (condition2, thenVal, elseVal) => condition2 ? thenVal : elseVal;
1449
+ const andHelper = (...args) => args.every(Boolean);
1450
+ const orHelper = (...args) => args.some(Boolean);
1451
+ const notHelper = (val) => !val;
1452
+ const eqHelper = (a, b) => a == b;
1453
+ const strictEqHelper = (a, b) => a === b;
1454
+ const neqHelper = (a, b) => a != b;
1455
+ const strictNeqHelper = (a, b) => a !== b;
1456
+ const registerLogicHelpers = (register) => {
1457
+ register("if", ifHelper);
1458
+ register("and", andHelper);
1459
+ register("&&", andHelper);
1460
+ register("or", orHelper);
1461
+ register("||", orHelper);
1462
+ register("not", notHelper);
1463
+ register("!", notHelper);
1464
+ register("eq", eqHelper);
1465
+ register("strictEq", strictEqHelper);
1466
+ register("==", eqHelper);
1467
+ register("===", strictEqHelper);
1468
+ register("neq", neqHelper);
1469
+ register("strictNeq", strictNeqHelper);
1470
+ register("!=", neqHelper);
1471
+ register("!==", strictNeqHelper);
1472
+ };
1473
+ const join$1 = (...args) => {
1474
+ const separator = args[args.length - 1];
1475
+ const items = args.slice(0, -1);
1476
+ return items.join(separator);
1477
+ };
1478
+ const concat$1 = (...args) => args.join("");
1479
+ const upper = (s) => String(s).toUpperCase();
1480
+ const lower = (s) => String(s).toLowerCase();
1481
+ const trim = (s) => String(s).trim();
1482
+ const len = (s) => String(s).length;
1483
+ const replace = (s, search, replacement) => String(s).replace(search, replacement);
1484
+ const split = (s, separator) => String(s).split(separator);
1485
+ const capitalize = (s) => {
1486
+ const str = String(s);
1487
+ return str.charAt(0).toUpperCase() + str.slice(1);
1488
+ };
1489
+ const titleCase = (s) => {
1490
+ return String(s).toLowerCase().split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
1491
+ };
1492
+ const contains$2 = (s, search) => String(s).includes(search);
1493
+ const startsWith = (s, prefix) => String(s).startsWith(prefix);
1494
+ const endsWith = (s, suffix) => String(s).endsWith(suffix);
1495
+ const defaultHelper = (val, fallback) => val !== void 0 && val !== null ? val : fallback;
1496
+ const registerStringHelpers = (register) => {
1497
+ register("join", join$1);
1498
+ register("concat", concat$1);
1499
+ register("upper", upper);
1500
+ register("lower", lower);
1501
+ register("trim", trim);
1502
+ register("len", len);
1503
+ register("replace", replace);
1504
+ register("split", split);
1505
+ register("capitalize", capitalize);
1506
+ register("titleCase", titleCase);
1507
+ register("contains", contains$2);
1508
+ register("startsWith", startsWith);
1509
+ register("endsWith", endsWith);
1510
+ register("default", defaultHelper);
1511
+ };
1512
+ const count = (...args) => args.length;
1513
+ const filter = (arr, predicate) => {
1514
+ if (!Array.isArray(arr)) return [];
1515
+ if (typeof predicate === "function" && predicate.isLazy) {
1516
+ return arr.filter((item) => predicate.resolve(item));
1517
+ }
1518
+ return arr.filter((item) => !!item);
1519
+ };
1520
+ const map = (arr, transform) => {
1521
+ if (!Array.isArray(arr)) return [];
1522
+ if (typeof transform === "string") {
1523
+ return arr.map((item) => item && typeof item === "object" ? item[transform] : item);
1524
+ }
1525
+ if (transform && transform.isLazy && typeof transform.resolve === "function") {
1526
+ return arr.map((item) => transform.resolve(item));
1527
+ }
1528
+ if (typeof transform === "function") {
1529
+ return arr.map(transform);
1530
+ }
1531
+ return arr;
1532
+ };
1533
+ const find = (arr, predicate) => {
1534
+ if (!Array.isArray(arr)) return void 0;
1535
+ if (predicate && predicate.isLazy) {
1536
+ return arr.find((item) => predicate.resolve(item));
1537
+ }
1538
+ return arr.find((item) => !!item);
1539
+ };
1540
+ const unique = (arr) => Array.isArray(arr) ? [...new Set(arr)] : [];
1541
+ const sort = (arr, order = "asc") => {
1542
+ if (!Array.isArray(arr)) return [];
1543
+ const sorted = [...arr];
1544
+ sorted.sort((a, b) => {
1545
+ if (a < b) return order === "asc" ? -1 : 1;
1546
+ if (a > b) return order === "asc" ? 1 : -1;
1547
+ return 0;
1548
+ });
1549
+ return sorted;
1550
+ };
1551
+ const reverse = (arr) => Array.isArray(arr) ? [...arr].reverse() : [];
1552
+ const first = (arr) => Array.isArray(arr) ? arr[0] : void 0;
1553
+ const last = (arr) => Array.isArray(arr) ? arr[arr.length - 1] : void 0;
1554
+ const slice = (arr, start, end) => Array.isArray(arr) ? arr.slice(start, end) : [];
1555
+ const flatten = (arr) => Array.isArray(arr) ? arr.flat(Infinity) : [];
1556
+ const join = (arr, sep = ",") => Array.isArray(arr) ? arr.join(String(sep)) : "";
1557
+ const length = (arg) => Array.isArray(arg) ? arg.length : arg ? String(arg).length : 0;
1558
+ const registerArrayHelpers = (register) => {
1559
+ register("count", count);
1560
+ register("filter", filter, { lazyAware: true });
1561
+ register("map", map, { lazyAware: true });
1562
+ register("find", find, { lazyAware: true });
1563
+ register("unique", unique);
1564
+ register("sort", sort);
1565
+ register("reverse", reverse);
1566
+ register("first", first);
1567
+ register("last", last);
1568
+ register("slice", slice);
1569
+ register("flatten", flatten);
1570
+ register("join", join);
1571
+ register("len", length);
1572
+ register("length", length);
1573
+ };
1574
+ const gt = (a, b) => a > b;
1575
+ const lt = (a, b) => a < b;
1576
+ const gte = (a, b) => a >= b;
1577
+ const lte = (a, b) => a <= b;
1578
+ const neq = (a, b) => a !== b;
1579
+ const between = (val, min2, max2) => val >= min2 && val <= max2;
1580
+ const contains$1 = (arr, val) => Array.isArray(arr) && arr.includes(val);
1581
+ const registerCompareHelpers = (register) => {
1582
+ register("gt", gt);
1583
+ register(">", gt);
1584
+ register("lt", lt);
1585
+ register("<", lt);
1586
+ register("gte", gte);
1587
+ register(">=", gte);
1588
+ register("lte", lte);
1589
+ register("<=", lte);
1590
+ register("neq", neq);
1591
+ register("!=", neq);
1592
+ register("between", between);
1593
+ register("in", contains$1);
1594
+ };
1595
+ const sumIf = (arr, predicate) => {
1596
+ if (!Array.isArray(arr)) return 0;
1597
+ const filtered = predicate && predicate.isLazy ? arr.filter((item) => predicate.resolve(item)) : arr;
1598
+ return filtered.reduce((a, b) => a + (Number(b) || 0), 0);
1599
+ };
1600
+ const countIf = (arr, predicate) => {
1601
+ if (!Array.isArray(arr)) return 0;
1602
+ if (predicate && predicate.isLazy) {
1603
+ return arr.filter((item) => predicate.resolve(item)).length;
1604
+ }
1605
+ return arr.filter((item) => !!item).length;
1606
+ };
1607
+ const avgIf = (arr, predicate) => {
1608
+ if (!Array.isArray(arr)) return 0;
1609
+ const filtered = predicate && predicate.isLazy ? arr.filter((item) => predicate.resolve(item)) : arr;
1610
+ if (filtered.length === 0) return 0;
1611
+ return filtered.reduce((a, b) => a + (Number(b) || 0), 0) / filtered.length;
1612
+ };
1613
+ const registerConditionalHelpers = (register) => {
1614
+ register("sumIf", sumIf);
1615
+ register("countIf", countIf);
1616
+ register("avgIf", avgIf);
1617
+ };
1618
+ const now = () => (/* @__PURE__ */ new Date()).getTime();
1619
+ const today = () => {
1620
+ const d = /* @__PURE__ */ new Date();
1621
+ d.setHours(0, 0, 0, 0);
1622
+ return d.getTime();
1623
+ };
1624
+ const date = (val) => new Date(val).getTime();
1625
+ const formatDate = (val, format) => {
1626
+ const d = new Date(val);
1627
+ if (isNaN(d.getTime())) return "";
1628
+ const options = { year: "numeric", month: "2-digit", day: "2-digit" };
1629
+ if (format === "long") options.month = "long";
1630
+ return d.toLocaleDateString(void 0, options);
1631
+ };
1632
+ const year = (val) => new Date(val).getFullYear();
1633
+ const month = (val) => new Date(val).getMonth() + 1;
1634
+ const day = (val) => new Date(val).getDate();
1635
+ const weekday = (val) => new Date(val).getDay();
1636
+ const addDays = (val, days) => {
1637
+ const d = new Date(val);
1638
+ d.setDate(d.getDate() + Number(days));
1639
+ return d.getTime();
1640
+ };
1641
+ const dateDiff = (d1, d2, unit = "days") => {
1642
+ const diff = Math.abs(new Date(d1) - new Date(d2));
1643
+ if (unit === "seconds") return diff / 1e3;
1644
+ if (unit === "minutes") return diff / (1e3 * 60);
1645
+ if (unit === "hours") return diff / (1e3 * 60 * 60);
1646
+ return diff / (1e3 * 60 * 60 * 24);
1647
+ };
1648
+ const registerDateTimeHelpers = (register) => {
1649
+ register("now", now);
1650
+ register("today", today);
1651
+ register("date", date);
1652
+ register("formatDate", formatDate);
1653
+ register("year", year);
1654
+ register("month", month);
1655
+ register("day", day);
1656
+ register("weekday", weekday);
1657
+ register("addDays", addDays);
1658
+ register("dateDiff", dateDiff);
1659
+ };
1660
+ const number = (val, decimals = 2) => Number(val).toFixed(decimals);
1661
+ const currency = (val, symbol = "$", decimals = 2) => {
1662
+ return symbol + Number(val).toFixed(decimals).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
1663
+ };
1664
+ const percent = (val, decimals = 0) => (Number(val) * 100).toFixed(decimals) + "%";
1665
+ const thousands = (val) => String(val).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
1666
+ const registerFormatHelpers = (register) => {
1667
+ register("number", number);
1668
+ register("currency", currency);
1669
+ register("percent", percent);
1670
+ register("thousands", thousands);
1671
+ };
1672
+ const lookup = (val, searchArr, resultArr) => {
1673
+ if (!Array.isArray(searchArr)) return void 0;
1674
+ const idx = searchArr.indexOf(val);
1675
+ return idx !== -1 && Array.isArray(resultArr) ? resultArr[idx] : void 0;
1676
+ };
1677
+ const vlookup = (val, table, colIdx) => {
1678
+ if (!Array.isArray(table)) return void 0;
1679
+ const row = table.find((r) => Array.isArray(r) && r[0] === val);
1680
+ return row ? row[colIdx - 1] : void 0;
1681
+ };
1682
+ const index = (arr, idx) => Array.isArray(arr) ? arr[idx] : void 0;
1683
+ const match = (val, arr) => Array.isArray(arr) ? arr.indexOf(val) : -1;
1684
+ const pathRef = (path, context) => {
1685
+ if (path && typeof path === "object" && "value" in path) {
1686
+ return unwrapSignal(path.value);
1687
+ }
1688
+ if (typeof path === "string") {
1689
+ const normalized = path.startsWith("=") ? path : "=" + path;
1690
+ const resolved = resolvePath(normalized, context);
1691
+ const value = unwrapSignal(resolved);
1692
+ if (typeof value === "number") return value;
1693
+ if (typeof value === "string" && value !== "" && !isNaN(parseFloat(value)) && isFinite(Number(value))) {
1694
+ return parseFloat(value);
1695
+ }
1696
+ return value;
1697
+ }
1698
+ return unwrapSignal(path);
1699
+ };
1700
+ const registerLookupHelpers = (register) => {
1701
+ register("lookup", lookup);
1702
+ register("vlookup", vlookup);
1703
+ register("index", index);
1704
+ register("match", match);
1705
+ register("$", pathRef, { pathAware: true });
1706
+ register("val", pathRef, { pathAware: true });
1707
+ register("indirect", pathRef, { pathAware: true });
1708
+ };
1709
+ const sum = (...args) => args.reduce((a, b) => a + (Number(b) || 0), 0);
1710
+ const avg = (...args) => args.length === 0 ? 0 : sum(...args) / args.length;
1711
+ const min$1 = (...args) => Math.min(...args);
1712
+ const max$1 = (...args) => Math.max(...args);
1713
+ const median = (...args) => {
1714
+ if (args.length === 0) return 0;
1715
+ const sorted = [...args].sort((a, b) => a - b);
1716
+ const mid = Math.floor(sorted.length / 2);
1717
+ return sorted.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
1718
+ };
1719
+ const stdev = (...args) => {
1720
+ if (args.length === 0) return 0;
1721
+ const mean = avg(...args);
1722
+ const squareDiffs = args.map((value) => Math.pow(value - mean, 2));
1723
+ return Math.sqrt(avg(...squareDiffs));
1724
+ };
1725
+ const variance = (...args) => {
1726
+ if (args.length === 0) return 0;
1727
+ const mean = avg(...args);
1728
+ const squareDiffs = args.map((value) => Math.pow(value - mean, 2));
1729
+ return avg(...squareDiffs);
1730
+ };
1731
+ const registerStatsHelpers = (register) => {
1732
+ register("sum", sum);
1733
+ register("avg", avg);
1734
+ register("min", min$1);
1735
+ register("max", max$1);
1736
+ register("median", median);
1737
+ register("stdev", stdev);
1738
+ register("var", variance);
1739
+ };
1740
+ const set = (target, val) => {
1741
+ if (target && typeof target === "object" && "value" in target) {
1742
+ target.value = val;
1743
+ } else if (target && typeof target === "function" && "value" in target) {
1744
+ target.value = val;
1745
+ } else if (target && typeof target === "object" && val && typeof val === "object") {
1746
+ Object.assign(target, val);
1747
+ }
1748
+ return val;
1749
+ };
1750
+ const increment = (target, by = 1) => {
1751
+ const hasValue = target && (typeof target === "object" || typeof target === "function") && "value" in target;
1752
+ const current = hasValue ? target.value : 0;
1753
+ const next = Number(current) + Number(by);
1754
+ return set(target, next);
1755
+ };
1756
+ const decrement = (target, by = 1) => {
1757
+ const hasValue = target && (typeof target === "object" || typeof target === "function") && "value" in target;
1758
+ const current = hasValue ? target.value : 0;
1759
+ const next = Number(current) - Number(by);
1760
+ return set(target, next);
1761
+ };
1762
+ const toggle = (target) => {
1763
+ const hasValue = target && (typeof target === "object" || typeof target === "function") && "value" in target;
1764
+ const current = hasValue ? target.value : false;
1765
+ return set(target, !current);
1766
+ };
1767
+ const push = (target, item) => {
1768
+ const current = target && typeof target === "object" && "value" in target ? target.value : [];
1769
+ if (Array.isArray(current)) {
1770
+ const next = [...current, item];
1771
+ return set(target, next);
1772
+ }
1773
+ return current;
1774
+ };
1775
+ const pop = (target) => {
1776
+ const current = target && typeof target === "object" && "value" in target ? target.value : [];
1777
+ if (Array.isArray(current) && current.length > 0) {
1778
+ const next = current.slice(0, -1);
1779
+ set(target, next);
1780
+ }
1781
+ return current;
1782
+ };
1783
+ const assign = (target, obj) => {
1784
+ const current = target && typeof target === "object" && "value" in target ? target.value : {};
1785
+ const next = { ...current, ...obj };
1786
+ return set(target, next);
1787
+ };
1788
+ const clear = (target) => {
1789
+ const current = target && typeof target === "object" && "value" in target ? target.value : null;
1790
+ if (Array.isArray(current)) return set(target, []);
1791
+ if (typeof current === "object" && current !== null) return set(target, {});
1792
+ return set(target, null);
1793
+ };
1794
+ function state(val, options) {
1795
+ if (globalThis.Lightview) {
1796
+ const finalOptions = typeof options === "string" ? { name: options } : options;
1797
+ return globalThis.Lightview.state(val, finalOptions);
1798
+ }
1799
+ throw new Error("JPRX: $state requires a UI library implementation.");
1800
+ }
1801
+ function signal(val, options) {
1802
+ if (globalThis.Lightview) {
1803
+ const finalOptions = typeof options === "string" ? { name: options } : options;
1804
+ return globalThis.Lightview.signal(val, finalOptions);
1805
+ }
1806
+ throw new Error("JPRX: $signal requires a UI library implementation.");
1807
+ }
1808
+ const bind = (path, options) => ({ __JPRX_BIND__: true, path, options });
1809
+ const registerStateHelpers = (register) => {
1810
+ const opts = { pathAware: true };
1811
+ register("set", set, opts);
1812
+ register("increment", increment, opts);
1813
+ register("++", increment, opts);
1814
+ register("decrement", decrement, opts);
1815
+ register("--", decrement, opts);
1816
+ register("toggle", toggle, opts);
1817
+ register("!!", toggle, opts);
1818
+ register("push", push, opts);
1819
+ register("pop", pop, opts);
1820
+ register("assign", assign, opts);
1821
+ register("clear", clear, opts);
1822
+ register("state", state);
1823
+ register("signal", signal);
1824
+ register("bind", bind);
1825
+ };
1826
+ const fetchHelper = (url, options = {}) => {
1827
+ const fetchOptions = { ...options };
1828
+ const headers = { ...fetchOptions.headers };
1829
+ let body = fetchOptions.body;
1830
+ if (body !== void 0) {
1831
+ if (body !== null && typeof body === "object") {
1832
+ body = JSON.stringify(body);
1833
+ if (!headers["Content-Type"]) {
1834
+ headers["Content-Type"] = "application/json";
1835
+ }
1836
+ } else {
1837
+ body = String(body);
1838
+ if (!headers["Content-Type"]) {
1839
+ headers["Content-Type"] = "text/plain";
1840
+ }
1841
+ }
1842
+ }
1843
+ fetchOptions.body = body;
1844
+ fetchOptions.headers = headers;
1845
+ return globalThis.fetch(url, fetchOptions);
1846
+ };
1847
+ const registerNetworkHelpers = (register) => {
1848
+ register("fetch", fetchHelper);
1849
+ };
1850
+ var INUMBER = "INUMBER";
1851
+ var IOP1 = "IOP1";
1852
+ var IOP2 = "IOP2";
1853
+ var IOP3 = "IOP3";
1854
+ var IVAR = "IVAR";
1855
+ var IVARNAME = "IVARNAME";
1856
+ var IFUNCALL = "IFUNCALL";
1857
+ var IFUNDEF = "IFUNDEF";
1858
+ var IEXPR = "IEXPR";
1859
+ var IEXPREVAL = "IEXPREVAL";
1860
+ var IMEMBER = "IMEMBER";
1861
+ var IENDSTATEMENT = "IENDSTATEMENT";
1862
+ var IARRAY = "IARRAY";
1863
+ function Instruction(type, value) {
1864
+ this.type = type;
1865
+ this.value = value !== void 0 && value !== null ? value : 0;
1866
+ }
1867
+ Instruction.prototype.toString = function() {
1868
+ switch (this.type) {
1869
+ case INUMBER:
1870
+ case IOP1:
1871
+ case IOP2:
1872
+ case IOP3:
1873
+ case IVAR:
1874
+ case IVARNAME:
1875
+ case IENDSTATEMENT:
1876
+ return this.value;
1877
+ case IFUNCALL:
1878
+ return "CALL " + this.value;
1879
+ case IFUNDEF:
1880
+ return "DEF " + this.value;
1881
+ case IARRAY:
1882
+ return "ARRAY " + this.value;
1883
+ case IMEMBER:
1884
+ return "." + this.value;
1885
+ default:
1886
+ return "Invalid Instruction";
1887
+ }
1888
+ };
1889
+ function unaryInstruction(value) {
1890
+ return new Instruction(IOP1, value);
1891
+ }
1892
+ function binaryInstruction(value) {
1893
+ return new Instruction(IOP2, value);
1894
+ }
1895
+ function ternaryInstruction(value) {
1896
+ return new Instruction(IOP3, value);
1897
+ }
1898
+ function simplify(tokens, unaryOps, binaryOps, ternaryOps, values) {
1899
+ var nstack = [];
1900
+ var newexpression = [];
1901
+ var n1, n2, n3;
1902
+ var f;
1903
+ for (var i = 0; i < tokens.length; i++) {
1904
+ var item = tokens[i];
1905
+ var type = item.type;
1906
+ if (type === INUMBER || type === IVARNAME) {
1907
+ if (Array.isArray(item.value)) {
1908
+ nstack.push.apply(nstack, simplify(item.value.map(function(x) {
1909
+ return new Instruction(INUMBER, x);
1910
+ }).concat(new Instruction(IARRAY, item.value.length)), unaryOps, binaryOps, ternaryOps, values));
1911
+ } else {
1912
+ nstack.push(item);
1913
+ }
1914
+ } else if (type === IVAR && values.hasOwnProperty(item.value)) {
1915
+ item = new Instruction(INUMBER, values[item.value]);
1916
+ nstack.push(item);
1917
+ } else if (type === IOP2 && nstack.length > 1) {
1918
+ n2 = nstack.pop();
1919
+ n1 = nstack.pop();
1920
+ f = binaryOps[item.value];
1921
+ item = new Instruction(INUMBER, f(n1.value, n2.value));
1922
+ nstack.push(item);
1923
+ } else if (type === IOP3 && nstack.length > 2) {
1924
+ n3 = nstack.pop();
1925
+ n2 = nstack.pop();
1926
+ n1 = nstack.pop();
1927
+ if (item.value === "?") {
1928
+ nstack.push(n1.value ? n2.value : n3.value);
1929
+ } else {
1930
+ f = ternaryOps[item.value];
1931
+ item = new Instruction(INUMBER, f(n1.value, n2.value, n3.value));
1932
+ nstack.push(item);
1933
+ }
1934
+ } else if (type === IOP1 && nstack.length > 0) {
1935
+ n1 = nstack.pop();
1936
+ f = unaryOps[item.value];
1937
+ item = new Instruction(INUMBER, f(n1.value));
1938
+ nstack.push(item);
1939
+ } else if (type === IEXPR) {
1940
+ while (nstack.length > 0) {
1941
+ newexpression.push(nstack.shift());
1942
+ }
1943
+ newexpression.push(new Instruction(IEXPR, simplify(item.value, unaryOps, binaryOps, ternaryOps, values)));
1944
+ } else if (type === IMEMBER && nstack.length > 0) {
1945
+ n1 = nstack.pop();
1946
+ nstack.push(new Instruction(INUMBER, n1.value[item.value]));
1947
+ } else {
1948
+ while (nstack.length > 0) {
1949
+ newexpression.push(nstack.shift());
1950
+ }
1951
+ newexpression.push(item);
1952
+ }
1953
+ }
1954
+ while (nstack.length > 0) {
1955
+ newexpression.push(nstack.shift());
1956
+ }
1957
+ return newexpression;
1958
+ }
1959
+ function substitute(tokens, variable, expr) {
1960
+ var newexpression = [];
1961
+ for (var i = 0; i < tokens.length; i++) {
1962
+ var item = tokens[i];
1963
+ var type = item.type;
1964
+ if (type === IVAR && item.value === variable) {
1965
+ for (var j = 0; j < expr.tokens.length; j++) {
1966
+ var expritem = expr.tokens[j];
1967
+ var replitem;
1968
+ if (expritem.type === IOP1) {
1969
+ replitem = unaryInstruction(expritem.value);
1970
+ } else if (expritem.type === IOP2) {
1971
+ replitem = binaryInstruction(expritem.value);
1972
+ } else if (expritem.type === IOP3) {
1973
+ replitem = ternaryInstruction(expritem.value);
1974
+ } else {
1975
+ replitem = new Instruction(expritem.type, expritem.value);
1976
+ }
1977
+ newexpression.push(replitem);
1978
+ }
1979
+ } else if (type === IEXPR) {
1980
+ newexpression.push(new Instruction(IEXPR, substitute(item.value, variable, expr)));
1981
+ } else {
1982
+ newexpression.push(item);
1983
+ }
1984
+ }
1985
+ return newexpression;
1986
+ }
1987
+ function evaluate(tokens, expr, values) {
1988
+ var nstack = [];
1989
+ var n1, n2, n3;
1990
+ var f, args, argCount;
1991
+ if (isExpressionEvaluator(tokens)) {
1992
+ return resolveExpression(tokens, values);
1993
+ }
1994
+ var numTokens = tokens.length;
1995
+ for (var i = 0; i < numTokens; i++) {
1996
+ var item = tokens[i];
1997
+ var type = item.type;
1998
+ if (type === INUMBER || type === IVARNAME) {
1999
+ nstack.push(item.value);
2000
+ } else if (type === IOP2) {
2001
+ n2 = nstack.pop();
2002
+ n1 = nstack.pop();
2003
+ if (item.value === "and") {
2004
+ nstack.push(n1 ? !!evaluate(n2, expr, values) : false);
2005
+ } else if (item.value === "or") {
2006
+ nstack.push(n1 ? true : !!evaluate(n2, expr, values));
2007
+ } else if (item.value === "=") {
2008
+ f = expr.binaryOps[item.value];
2009
+ nstack.push(f(n1, evaluate(n2, expr, values), values));
2010
+ } else {
2011
+ f = expr.binaryOps[item.value];
2012
+ nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values)));
2013
+ }
2014
+ } else if (type === IOP3) {
2015
+ n3 = nstack.pop();
2016
+ n2 = nstack.pop();
2017
+ n1 = nstack.pop();
2018
+ if (item.value === "?") {
2019
+ nstack.push(evaluate(n1 ? n2 : n3, expr, values));
2020
+ } else {
2021
+ f = expr.ternaryOps[item.value];
2022
+ nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values), resolveExpression(n3, values)));
2023
+ }
2024
+ } else if (type === IVAR) {
2025
+ if (item.value in expr.functions) {
2026
+ nstack.push(expr.functions[item.value]);
2027
+ } else if (item.value in expr.unaryOps && expr.parser.isOperatorEnabled(item.value)) {
2028
+ nstack.push(expr.unaryOps[item.value]);
2029
+ } else {
2030
+ var v = values[item.value];
2031
+ if (v !== void 0) {
2032
+ nstack.push(v);
2033
+ } else {
2034
+ throw new Error("undefined variable: " + item.value);
2035
+ }
2036
+ }
2037
+ } else if (type === IOP1) {
2038
+ n1 = nstack.pop();
2039
+ f = expr.unaryOps[item.value];
2040
+ nstack.push(f(resolveExpression(n1, values)));
2041
+ } else if (type === IFUNCALL) {
2042
+ argCount = item.value;
2043
+ args = [];
2044
+ while (argCount-- > 0) {
2045
+ args.unshift(resolveExpression(nstack.pop(), values));
2046
+ }
2047
+ f = nstack.pop();
2048
+ if (f.apply && f.call) {
2049
+ nstack.push(f.apply(void 0, args));
2050
+ } else {
2051
+ throw new Error(f + " is not a function");
2052
+ }
2053
+ } else if (type === IFUNDEF) {
2054
+ nstack.push(function() {
2055
+ var n22 = nstack.pop();
2056
+ var args2 = [];
2057
+ var argCount2 = item.value;
2058
+ while (argCount2-- > 0) {
2059
+ args2.unshift(nstack.pop());
2060
+ }
2061
+ var n12 = nstack.pop();
2062
+ var f2 = function() {
2063
+ var scope = Object.assign({}, values);
2064
+ for (var i2 = 0, len2 = args2.length; i2 < len2; i2++) {
2065
+ scope[args2[i2]] = arguments[i2];
2066
+ }
2067
+ return evaluate(n22, expr, scope);
2068
+ };
2069
+ Object.defineProperty(f2, "name", {
2070
+ value: n12,
2071
+ writable: false
2072
+ });
2073
+ values[n12] = f2;
2074
+ return f2;
2075
+ }());
2076
+ } else if (type === IEXPR) {
2077
+ nstack.push(createExpressionEvaluator(item, expr));
2078
+ } else if (type === IEXPREVAL) {
2079
+ nstack.push(item);
2080
+ } else if (type === IMEMBER) {
2081
+ n1 = nstack.pop();
2082
+ nstack.push(n1[item.value]);
2083
+ } else if (type === IENDSTATEMENT) {
2084
+ nstack.pop();
2085
+ } else if (type === IARRAY) {
2086
+ argCount = item.value;
2087
+ args = [];
2088
+ while (argCount-- > 0) {
2089
+ args.unshift(nstack.pop());
2090
+ }
2091
+ nstack.push(args);
2092
+ } else {
2093
+ throw new Error("invalid Expression");
2094
+ }
2095
+ }
2096
+ if (nstack.length > 1) {
2097
+ throw new Error("invalid Expression (parity)");
2098
+ }
2099
+ return nstack[0] === 0 ? 0 : resolveExpression(nstack[0], values);
2100
+ }
2101
+ function createExpressionEvaluator(token, expr, values) {
2102
+ if (isExpressionEvaluator(token)) return token;
2103
+ return {
2104
+ type: IEXPREVAL,
2105
+ value: function(scope) {
2106
+ return evaluate(token.value, expr, scope);
2107
+ }
2108
+ };
2109
+ }
2110
+ function isExpressionEvaluator(n) {
2111
+ return n && n.type === IEXPREVAL;
2112
+ }
2113
+ function resolveExpression(n, values) {
2114
+ return isExpressionEvaluator(n) ? n.value(values) : n;
2115
+ }
2116
+ function expressionToString(tokens, toJS) {
2117
+ var nstack = [];
2118
+ var n1, n2, n3;
2119
+ var f, args, argCount;
2120
+ for (var i = 0; i < tokens.length; i++) {
2121
+ var item = tokens[i];
2122
+ var type = item.type;
2123
+ if (type === INUMBER) {
2124
+ if (typeof item.value === "number" && item.value < 0) {
2125
+ nstack.push("(" + item.value + ")");
2126
+ } else if (Array.isArray(item.value)) {
2127
+ nstack.push("[" + item.value.map(escapeValue).join(", ") + "]");
2128
+ } else {
2129
+ nstack.push(escapeValue(item.value));
2130
+ }
2131
+ } else if (type === IOP2) {
2132
+ n2 = nstack.pop();
2133
+ n1 = nstack.pop();
2134
+ f = item.value;
2135
+ if (toJS) {
2136
+ if (f === "^") {
2137
+ nstack.push("Math.pow(" + n1 + ", " + n2 + ")");
2138
+ } else if (f === "and") {
2139
+ nstack.push("(!!" + n1 + " && !!" + n2 + ")");
2140
+ } else if (f === "or") {
2141
+ nstack.push("(!!" + n1 + " || !!" + n2 + ")");
2142
+ } else if (f === "||") {
2143
+ nstack.push("(function(a,b){ return Array.isArray(a) && Array.isArray(b) ? a.concat(b) : String(a) + String(b); }((" + n1 + "),(" + n2 + ")))");
2144
+ } else if (f === "==") {
2145
+ nstack.push("(" + n1 + " === " + n2 + ")");
2146
+ } else if (f === "!=") {
2147
+ nstack.push("(" + n1 + " !== " + n2 + ")");
2148
+ } else if (f === "[") {
2149
+ nstack.push(n1 + "[(" + n2 + ") | 0]");
2150
+ } else {
2151
+ nstack.push("(" + n1 + " " + f + " " + n2 + ")");
2152
+ }
2153
+ } else {
2154
+ if (f === "[") {
2155
+ nstack.push(n1 + "[" + n2 + "]");
2156
+ } else {
2157
+ nstack.push("(" + n1 + " " + f + " " + n2 + ")");
2158
+ }
2159
+ }
2160
+ } else if (type === IOP3) {
2161
+ n3 = nstack.pop();
2162
+ n2 = nstack.pop();
2163
+ n1 = nstack.pop();
2164
+ f = item.value;
2165
+ if (f === "?") {
2166
+ nstack.push("(" + n1 + " ? " + n2 + " : " + n3 + ")");
2167
+ } else {
2168
+ throw new Error("invalid Expression");
2169
+ }
2170
+ } else if (type === IVAR || type === IVARNAME) {
2171
+ nstack.push(item.value);
2172
+ } else if (type === IOP1) {
2173
+ n1 = nstack.pop();
2174
+ f = item.value;
2175
+ if (f === "-" || f === "+") {
2176
+ nstack.push("(" + f + n1 + ")");
2177
+ } else if (toJS) {
2178
+ if (f === "not") {
2179
+ nstack.push("(!" + n1 + ")");
2180
+ } else if (f === "!") {
2181
+ nstack.push("fac(" + n1 + ")");
2182
+ } else {
2183
+ nstack.push(f + "(" + n1 + ")");
2184
+ }
2185
+ } else if (f === "!") {
2186
+ nstack.push("(" + n1 + "!)");
2187
+ } else {
2188
+ nstack.push("(" + f + " " + n1 + ")");
2189
+ }
2190
+ } else if (type === IFUNCALL) {
2191
+ argCount = item.value;
2192
+ args = [];
2193
+ while (argCount-- > 0) {
2194
+ args.unshift(nstack.pop());
2195
+ }
2196
+ f = nstack.pop();
2197
+ nstack.push(f + "(" + args.join(", ") + ")");
2198
+ } else if (type === IFUNDEF) {
2199
+ n2 = nstack.pop();
2200
+ argCount = item.value;
2201
+ args = [];
2202
+ while (argCount-- > 0) {
2203
+ args.unshift(nstack.pop());
2204
+ }
2205
+ n1 = nstack.pop();
2206
+ if (toJS) {
2207
+ nstack.push("(" + n1 + " = function(" + args.join(", ") + ") { return " + n2 + " })");
2208
+ } else {
2209
+ nstack.push("(" + n1 + "(" + args.join(", ") + ") = " + n2 + ")");
2210
+ }
2211
+ } else if (type === IMEMBER) {
2212
+ n1 = nstack.pop();
2213
+ nstack.push(n1 + "." + item.value);
2214
+ } else if (type === IARRAY) {
2215
+ argCount = item.value;
2216
+ args = [];
2217
+ while (argCount-- > 0) {
2218
+ args.unshift(nstack.pop());
2219
+ }
2220
+ nstack.push("[" + args.join(", ") + "]");
2221
+ } else if (type === IEXPR) {
2222
+ nstack.push("(" + expressionToString(item.value, toJS) + ")");
2223
+ } else if (type === IENDSTATEMENT) ;
2224
+ else {
2225
+ throw new Error("invalid Expression");
2226
+ }
2227
+ }
2228
+ if (nstack.length > 1) {
2229
+ if (toJS) {
2230
+ nstack = [nstack.join(",")];
2231
+ } else {
2232
+ nstack = [nstack.join(";")];
2233
+ }
2234
+ }
2235
+ return String(nstack[0]);
2236
+ }
2237
+ function escapeValue(v) {
2238
+ if (typeof v === "string") {
2239
+ return JSON.stringify(v).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
2240
+ }
2241
+ return v;
2242
+ }
2243
+ function contains(array, obj) {
2244
+ for (var i = 0; i < array.length; i++) {
2245
+ if (array[i] === obj) {
2246
+ return true;
2247
+ }
2248
+ }
2249
+ return false;
2250
+ }
2251
+ function getSymbols(tokens, symbols, options) {
2252
+ options = options || {};
2253
+ var withMembers = !!options.withMembers;
2254
+ var prevVar = null;
2255
+ for (var i = 0; i < tokens.length; i++) {
2256
+ var item = tokens[i];
2257
+ if (item.type === IVAR || item.type === IVARNAME) {
2258
+ if (!withMembers && !contains(symbols, item.value)) {
2259
+ symbols.push(item.value);
2260
+ } else if (prevVar !== null) {
2261
+ if (!contains(symbols, prevVar)) {
2262
+ symbols.push(prevVar);
2263
+ }
2264
+ prevVar = item.value;
2265
+ } else {
2266
+ prevVar = item.value;
2267
+ }
2268
+ } else if (item.type === IMEMBER && withMembers && prevVar !== null) {
2269
+ prevVar += "." + item.value;
2270
+ } else if (item.type === IEXPR) {
2271
+ getSymbols(item.value, symbols, options);
2272
+ } else if (prevVar !== null) {
2273
+ if (!contains(symbols, prevVar)) {
2274
+ symbols.push(prevVar);
2275
+ }
2276
+ prevVar = null;
2277
+ }
2278
+ }
2279
+ if (prevVar !== null && !contains(symbols, prevVar)) {
2280
+ symbols.push(prevVar);
2281
+ }
2282
+ }
2283
+ function Expression(tokens, parser) {
2284
+ this.tokens = tokens;
2285
+ this.parser = parser;
2286
+ this.unaryOps = parser.unaryOps;
2287
+ this.binaryOps = parser.binaryOps;
2288
+ this.ternaryOps = parser.ternaryOps;
2289
+ this.functions = parser.functions;
2290
+ }
2291
+ Expression.prototype.simplify = function(values) {
2292
+ values = values || {};
2293
+ return new Expression(simplify(this.tokens, this.unaryOps, this.binaryOps, this.ternaryOps, values), this.parser);
2294
+ };
2295
+ Expression.prototype.substitute = function(variable, expr) {
2296
+ if (!(expr instanceof Expression)) {
2297
+ expr = this.parser.parse(String(expr));
2298
+ }
2299
+ return new Expression(substitute(this.tokens, variable, expr), this.parser);
2300
+ };
2301
+ Expression.prototype.evaluate = function(values) {
2302
+ values = values || {};
2303
+ return evaluate(this.tokens, this, values);
2304
+ };
2305
+ Expression.prototype.toString = function() {
2306
+ return expressionToString(this.tokens, false);
2307
+ };
2308
+ Expression.prototype.symbols = function(options) {
2309
+ options = options || {};
2310
+ var vars = [];
2311
+ getSymbols(this.tokens, vars, options);
2312
+ return vars;
2313
+ };
2314
+ Expression.prototype.variables = function(options) {
2315
+ options = options || {};
2316
+ var vars = [];
2317
+ getSymbols(this.tokens, vars, options);
2318
+ var functions = this.functions;
2319
+ return vars.filter(function(name) {
2320
+ return !(name in functions);
2321
+ });
2322
+ };
2323
+ Expression.prototype.toJSFunction = function(param, variables) {
2324
+ var expr = this;
2325
+ var f = new Function(param, "with(this.functions) with (this.ternaryOps) with (this.binaryOps) with (this.unaryOps) { return " + expressionToString(this.simplify(variables).tokens, true) + "; }");
2326
+ return function() {
2327
+ return f.apply(expr, arguments);
2328
+ };
2329
+ };
2330
+ var TEOF = "TEOF";
2331
+ var TOP = "TOP";
2332
+ var TNUMBER = "TNUMBER";
2333
+ var TSTRING = "TSTRING";
2334
+ var TPAREN = "TPAREN";
2335
+ var TBRACKET = "TBRACKET";
2336
+ var TCOMMA = "TCOMMA";
2337
+ var TNAME = "TNAME";
2338
+ var TSEMICOLON = "TSEMICOLON";
2339
+ function Token(type, value, index2) {
2340
+ this.type = type;
2341
+ this.value = value;
2342
+ this.index = index2;
2343
+ }
2344
+ Token.prototype.toString = function() {
2345
+ return this.type + ": " + this.value;
2346
+ };
2347
+ function TokenStream(parser, expression) {
2348
+ this.pos = 0;
2349
+ this.current = null;
2350
+ this.unaryOps = parser.unaryOps;
2351
+ this.binaryOps = parser.binaryOps;
2352
+ this.ternaryOps = parser.ternaryOps;
2353
+ this.consts = parser.consts;
2354
+ this.expression = expression;
2355
+ this.savedPosition = 0;
2356
+ this.savedCurrent = null;
2357
+ this.options = parser.options;
2358
+ this.parser = parser;
2359
+ }
2360
+ TokenStream.prototype.newToken = function(type, value, pos) {
2361
+ return new Token(type, value, pos != null ? pos : this.pos);
2362
+ };
2363
+ TokenStream.prototype.save = function() {
2364
+ this.savedPosition = this.pos;
2365
+ this.savedCurrent = this.current;
2366
+ };
2367
+ TokenStream.prototype.restore = function() {
2368
+ this.pos = this.savedPosition;
2369
+ this.current = this.savedCurrent;
2370
+ };
2371
+ TokenStream.prototype.next = function() {
2372
+ if (this.pos >= this.expression.length) {
2373
+ return this.newToken(TEOF, "EOF");
2374
+ }
2375
+ if (this.isWhitespace() || this.isComment()) {
2376
+ return this.next();
2377
+ } else if (this.isRadixInteger() || this.isNumber() || this.isOperator() || this.isString() || this.isParen() || this.isBracket() || this.isComma() || this.isSemicolon() || this.isNamedOp() || this.isConst() || this.isName()) {
2378
+ return this.current;
2379
+ } else {
2380
+ this.parseError('Unknown character "' + this.expression.charAt(this.pos) + '"');
2381
+ }
2382
+ };
2383
+ TokenStream.prototype.isString = function() {
2384
+ var r = false;
2385
+ var startPos = this.pos;
2386
+ var quote = this.expression.charAt(startPos);
2387
+ if (quote === "'" || quote === '"') {
2388
+ var index2 = this.expression.indexOf(quote, startPos + 1);
2389
+ while (index2 >= 0 && this.pos < this.expression.length) {
2390
+ this.pos = index2 + 1;
2391
+ if (this.expression.charAt(index2 - 1) !== "\\") {
2392
+ var rawString = this.expression.substring(startPos + 1, index2);
2393
+ this.current = this.newToken(TSTRING, this.unescape(rawString), startPos);
2394
+ r = true;
2395
+ break;
2396
+ }
2397
+ index2 = this.expression.indexOf(quote, index2 + 1);
2398
+ }
2399
+ }
2400
+ return r;
2401
+ };
2402
+ TokenStream.prototype.isParen = function() {
2403
+ var c = this.expression.charAt(this.pos);
2404
+ if (c === "(" || c === ")") {
2405
+ this.current = this.newToken(TPAREN, c);
2406
+ this.pos++;
2407
+ return true;
2408
+ }
2409
+ return false;
2410
+ };
2411
+ TokenStream.prototype.isBracket = function() {
2412
+ var c = this.expression.charAt(this.pos);
2413
+ if ((c === "[" || c === "]") && this.isOperatorEnabled("[")) {
2414
+ this.current = this.newToken(TBRACKET, c);
2415
+ this.pos++;
2416
+ return true;
2417
+ }
2418
+ return false;
2419
+ };
2420
+ TokenStream.prototype.isComma = function() {
2421
+ var c = this.expression.charAt(this.pos);
2422
+ if (c === ",") {
2423
+ this.current = this.newToken(TCOMMA, ",");
2424
+ this.pos++;
2425
+ return true;
2426
+ }
2427
+ return false;
2428
+ };
2429
+ TokenStream.prototype.isSemicolon = function() {
2430
+ var c = this.expression.charAt(this.pos);
2431
+ if (c === ";") {
2432
+ this.current = this.newToken(TSEMICOLON, ";");
2433
+ this.pos++;
2434
+ return true;
2435
+ }
2436
+ return false;
2437
+ };
2438
+ TokenStream.prototype.isConst = function() {
2439
+ var startPos = this.pos;
2440
+ var i = startPos;
2441
+ for (; i < this.expression.length; i++) {
2442
+ var c = this.expression.charAt(i);
2443
+ if (c.toUpperCase() === c.toLowerCase()) {
2444
+ if (i === this.pos || c !== "_" && c !== "." && (c < "0" || c > "9")) {
2445
+ break;
2446
+ }
2447
+ }
2448
+ }
2449
+ if (i > startPos) {
2450
+ var str = this.expression.substring(startPos, i);
2451
+ if (str in this.consts) {
2452
+ this.current = this.newToken(TNUMBER, this.consts[str]);
2453
+ this.pos += str.length;
2454
+ return true;
2455
+ }
2456
+ }
2457
+ return false;
2458
+ };
2459
+ TokenStream.prototype.isNamedOp = function() {
2460
+ var startPos = this.pos;
2461
+ var i = startPos;
2462
+ for (; i < this.expression.length; i++) {
2463
+ var c = this.expression.charAt(i);
2464
+ if (c.toUpperCase() === c.toLowerCase()) {
2465
+ if (i === this.pos || c !== "_" && (c < "0" || c > "9")) {
2466
+ break;
2467
+ }
2468
+ }
2469
+ }
2470
+ if (i > startPos) {
2471
+ var str = this.expression.substring(startPos, i);
2472
+ if (this.isOperatorEnabled(str) && (str in this.binaryOps || str in this.unaryOps || str in this.ternaryOps)) {
2473
+ this.current = this.newToken(TOP, str);
2474
+ this.pos += str.length;
2475
+ return true;
2476
+ }
2477
+ }
2478
+ return false;
2479
+ };
2480
+ TokenStream.prototype.isName = function() {
2481
+ var startPos = this.pos;
2482
+ var i = startPos;
2483
+ var hasLetter = false;
2484
+ for (; i < this.expression.length; i++) {
2485
+ var c = this.expression.charAt(i);
2486
+ if (c.toUpperCase() === c.toLowerCase()) {
2487
+ if (i === this.pos && (c === "$" || c === "_")) {
2488
+ if (c === "_") {
2489
+ hasLetter = true;
2490
+ }
2491
+ continue;
2492
+ } else if (i === this.pos || !hasLetter || c !== "_" && (c < "0" || c > "9")) {
2493
+ break;
2494
+ }
2495
+ } else {
2496
+ hasLetter = true;
2497
+ }
2498
+ }
2499
+ if (hasLetter) {
2500
+ var str = this.expression.substring(startPos, i);
2501
+ this.current = this.newToken(TNAME, str);
2502
+ this.pos += str.length;
2503
+ return true;
2504
+ }
2505
+ return false;
2506
+ };
2507
+ TokenStream.prototype.isWhitespace = function() {
2508
+ var r = false;
2509
+ var c = this.expression.charAt(this.pos);
2510
+ while (c === " " || c === " " || c === "\n" || c === "\r") {
2511
+ r = true;
2512
+ this.pos++;
2513
+ if (this.pos >= this.expression.length) {
2514
+ break;
2515
+ }
2516
+ c = this.expression.charAt(this.pos);
2517
+ }
2518
+ return r;
2519
+ };
2520
+ var codePointPattern = /^[0-9a-f]{4}$/i;
2521
+ TokenStream.prototype.unescape = function(v) {
2522
+ var index2 = v.indexOf("\\");
2523
+ if (index2 < 0) {
2524
+ return v;
2525
+ }
2526
+ var buffer = v.substring(0, index2);
2527
+ while (index2 >= 0) {
2528
+ var c = v.charAt(++index2);
2529
+ switch (c) {
2530
+ case "'":
2531
+ buffer += "'";
2532
+ break;
2533
+ case '"':
2534
+ buffer += '"';
2535
+ break;
2536
+ case "\\":
2537
+ buffer += "\\";
2538
+ break;
2539
+ case "/":
2540
+ buffer += "/";
2541
+ break;
2542
+ case "b":
2543
+ buffer += "\b";
2544
+ break;
2545
+ case "f":
2546
+ buffer += "\f";
2547
+ break;
2548
+ case "n":
2549
+ buffer += "\n";
2550
+ break;
2551
+ case "r":
2552
+ buffer += "\r";
2553
+ break;
2554
+ case "t":
2555
+ buffer += " ";
2556
+ break;
2557
+ case "u":
2558
+ var codePoint = v.substring(index2 + 1, index2 + 5);
2559
+ if (!codePointPattern.test(codePoint)) {
2560
+ this.parseError("Illegal escape sequence: \\u" + codePoint);
2561
+ }
2562
+ buffer += String.fromCharCode(parseInt(codePoint, 16));
2563
+ index2 += 4;
2564
+ break;
2565
+ default:
2566
+ throw this.parseError('Illegal escape sequence: "\\' + c + '"');
2567
+ }
2568
+ ++index2;
2569
+ var backslash = v.indexOf("\\", index2);
2570
+ buffer += v.substring(index2, backslash < 0 ? v.length : backslash);
2571
+ index2 = backslash;
2572
+ }
2573
+ return buffer;
2574
+ };
2575
+ TokenStream.prototype.isComment = function() {
2576
+ var c = this.expression.charAt(this.pos);
2577
+ if (c === "/" && this.expression.charAt(this.pos + 1) === "*") {
2578
+ this.pos = this.expression.indexOf("*/", this.pos) + 2;
2579
+ if (this.pos === 1) {
2580
+ this.pos = this.expression.length;
2581
+ }
2582
+ return true;
2583
+ }
2584
+ return false;
2585
+ };
2586
+ TokenStream.prototype.isRadixInteger = function() {
2587
+ var pos = this.pos;
2588
+ if (pos >= this.expression.length - 2 || this.expression.charAt(pos) !== "0") {
2589
+ return false;
2590
+ }
2591
+ ++pos;
2592
+ var radix;
2593
+ var validDigit;
2594
+ if (this.expression.charAt(pos) === "x") {
2595
+ radix = 16;
2596
+ validDigit = /^[0-9a-f]$/i;
2597
+ ++pos;
2598
+ } else if (this.expression.charAt(pos) === "b") {
2599
+ radix = 2;
2600
+ validDigit = /^[01]$/i;
2601
+ ++pos;
2602
+ } else {
2603
+ return false;
2604
+ }
2605
+ var valid = false;
2606
+ var startPos = pos;
2607
+ while (pos < this.expression.length) {
2608
+ var c = this.expression.charAt(pos);
2609
+ if (validDigit.test(c)) {
2610
+ pos++;
2611
+ valid = true;
2612
+ } else {
2613
+ break;
2614
+ }
2615
+ }
2616
+ if (valid) {
2617
+ this.current = this.newToken(TNUMBER, parseInt(this.expression.substring(startPos, pos), radix));
2618
+ this.pos = pos;
2619
+ }
2620
+ return valid;
2621
+ };
2622
+ TokenStream.prototype.isNumber = function() {
2623
+ var valid = false;
2624
+ var pos = this.pos;
2625
+ var startPos = pos;
2626
+ var resetPos = pos;
2627
+ var foundDot = false;
2628
+ var foundDigits = false;
2629
+ var c;
2630
+ while (pos < this.expression.length) {
2631
+ c = this.expression.charAt(pos);
2632
+ if (c >= "0" && c <= "9" || !foundDot && c === ".") {
2633
+ if (c === ".") {
2634
+ foundDot = true;
2635
+ } else {
2636
+ foundDigits = true;
2637
+ }
2638
+ pos++;
2639
+ valid = foundDigits;
2640
+ } else {
2641
+ break;
2642
+ }
2643
+ }
2644
+ if (valid) {
2645
+ resetPos = pos;
2646
+ }
2647
+ if (c === "e" || c === "E") {
2648
+ pos++;
2649
+ var acceptSign = true;
2650
+ var validExponent = false;
2651
+ while (pos < this.expression.length) {
2652
+ c = this.expression.charAt(pos);
2653
+ if (acceptSign && (c === "+" || c === "-")) {
2654
+ acceptSign = false;
2655
+ } else if (c >= "0" && c <= "9") {
2656
+ validExponent = true;
2657
+ acceptSign = false;
2658
+ } else {
2659
+ break;
2660
+ }
2661
+ pos++;
2662
+ }
2663
+ if (!validExponent) {
2664
+ pos = resetPos;
2665
+ }
2666
+ }
2667
+ if (valid) {
2668
+ this.current = this.newToken(TNUMBER, parseFloat(this.expression.substring(startPos, pos)));
2669
+ this.pos = pos;
2670
+ } else {
2671
+ this.pos = resetPos;
2672
+ }
2673
+ return valid;
2674
+ };
2675
+ TokenStream.prototype.isOperator = function() {
2676
+ var startPos = this.pos;
2677
+ var c = this.expression.charAt(this.pos);
2678
+ if (c === "+" || c === "-" || c === "*" || c === "/" || c === "%" || c === "^" || c === "?" || c === ":" || c === ".") {
2679
+ this.current = this.newToken(TOP, c);
2680
+ } else if (c === "∙" || c === "•") {
2681
+ this.current = this.newToken(TOP, "*");
2682
+ } else if (c === ">") {
2683
+ if (this.expression.charAt(this.pos + 1) === "=") {
2684
+ this.current = this.newToken(TOP, ">=");
2685
+ this.pos++;
2686
+ } else {
2687
+ this.current = this.newToken(TOP, ">");
2688
+ }
2689
+ } else if (c === "<") {
2690
+ if (this.expression.charAt(this.pos + 1) === "=") {
2691
+ this.current = this.newToken(TOP, "<=");
2692
+ this.pos++;
2693
+ } else {
2694
+ this.current = this.newToken(TOP, "<");
2695
+ }
2696
+ } else if (c === "|") {
2697
+ if (this.expression.charAt(this.pos + 1) === "|") {
2698
+ this.current = this.newToken(TOP, "||");
2699
+ this.pos++;
2700
+ } else {
2701
+ return false;
2702
+ }
2703
+ } else if (c === "=") {
2704
+ if (this.expression.charAt(this.pos + 1) === "=") {
2705
+ this.current = this.newToken(TOP, "==");
2706
+ this.pos++;
2707
+ } else {
2708
+ this.current = this.newToken(TOP, c);
2709
+ }
2710
+ } else if (c === "!") {
2711
+ if (this.expression.charAt(this.pos + 1) === "=") {
2712
+ this.current = this.newToken(TOP, "!=");
2713
+ this.pos++;
2714
+ } else {
2715
+ this.current = this.newToken(TOP, c);
2716
+ }
2717
+ } else {
2718
+ return false;
2719
+ }
2720
+ this.pos++;
2721
+ if (this.isOperatorEnabled(this.current.value)) {
2722
+ return true;
2723
+ } else {
2724
+ this.pos = startPos;
2725
+ return false;
2726
+ }
2727
+ };
2728
+ TokenStream.prototype.isOperatorEnabled = function(op) {
2729
+ return this.parser.isOperatorEnabled(op);
2730
+ };
2731
+ TokenStream.prototype.getCoordinates = function() {
2732
+ var line = 0;
2733
+ var column;
2734
+ var newline = -1;
2735
+ do {
2736
+ line++;
2737
+ column = this.pos - newline;
2738
+ newline = this.expression.indexOf("\n", newline + 1);
2739
+ } while (newline >= 0 && newline < this.pos);
2740
+ return {
2741
+ line,
2742
+ column
2743
+ };
2744
+ };
2745
+ TokenStream.prototype.parseError = function(msg) {
2746
+ var coords = this.getCoordinates();
2747
+ throw new Error("parse error [" + coords.line + ":" + coords.column + "]: " + msg);
2748
+ };
2749
+ function ParserState(parser, tokenStream, options) {
2750
+ this.parser = parser;
2751
+ this.tokens = tokenStream;
2752
+ this.current = null;
2753
+ this.nextToken = null;
2754
+ this.next();
2755
+ this.savedCurrent = null;
2756
+ this.savedNextToken = null;
2757
+ this.allowMemberAccess = options.allowMemberAccess !== false;
2758
+ }
2759
+ ParserState.prototype.next = function() {
2760
+ this.current = this.nextToken;
2761
+ return this.nextToken = this.tokens.next();
2762
+ };
2763
+ ParserState.prototype.tokenMatches = function(token, value) {
2764
+ if (typeof value === "undefined") {
2765
+ return true;
2766
+ } else if (Array.isArray(value)) {
2767
+ return contains(value, token.value);
2768
+ } else if (typeof value === "function") {
2769
+ return value(token);
2770
+ } else {
2771
+ return token.value === value;
2772
+ }
2773
+ };
2774
+ ParserState.prototype.save = function() {
2775
+ this.savedCurrent = this.current;
2776
+ this.savedNextToken = this.nextToken;
2777
+ this.tokens.save();
2778
+ };
2779
+ ParserState.prototype.restore = function() {
2780
+ this.tokens.restore();
2781
+ this.current = this.savedCurrent;
2782
+ this.nextToken = this.savedNextToken;
2783
+ };
2784
+ ParserState.prototype.accept = function(type, value) {
2785
+ if (this.nextToken.type === type && this.tokenMatches(this.nextToken, value)) {
2786
+ this.next();
2787
+ return true;
2788
+ }
2789
+ return false;
2790
+ };
2791
+ ParserState.prototype.expect = function(type, value) {
2792
+ if (!this.accept(type, value)) {
2793
+ var coords = this.tokens.getCoordinates();
2794
+ throw new Error("parse error [" + coords.line + ":" + coords.column + "]: Expected " + (value || type));
2795
+ }
2796
+ };
2797
+ ParserState.prototype.parseAtom = function(instr) {
2798
+ var unaryOps = this.tokens.unaryOps;
2799
+ function isPrefixOperator(token) {
2800
+ return token.value in unaryOps;
2801
+ }
2802
+ if (this.accept(TNAME) || this.accept(TOP, isPrefixOperator)) {
2803
+ instr.push(new Instruction(IVAR, this.current.value));
2804
+ } else if (this.accept(TNUMBER)) {
2805
+ instr.push(new Instruction(INUMBER, this.current.value));
2806
+ } else if (this.accept(TSTRING)) {
2807
+ instr.push(new Instruction(INUMBER, this.current.value));
2808
+ } else if (this.accept(TPAREN, "(")) {
2809
+ this.parseExpression(instr);
2810
+ this.expect(TPAREN, ")");
2811
+ } else if (this.accept(TBRACKET, "[")) {
2812
+ if (this.accept(TBRACKET, "]")) {
2813
+ instr.push(new Instruction(IARRAY, 0));
2814
+ } else {
2815
+ var argCount = this.parseArrayList(instr);
2816
+ instr.push(new Instruction(IARRAY, argCount));
2817
+ }
2818
+ } else {
2819
+ throw new Error("unexpected " + this.nextToken);
2820
+ }
2821
+ };
2822
+ ParserState.prototype.parseExpression = function(instr) {
2823
+ var exprInstr = [];
2824
+ if (this.parseUntilEndStatement(instr, exprInstr)) {
2825
+ return;
2826
+ }
2827
+ this.parseVariableAssignmentExpression(exprInstr);
2828
+ if (this.parseUntilEndStatement(instr, exprInstr)) {
2829
+ return;
2830
+ }
2831
+ this.pushExpression(instr, exprInstr);
2832
+ };
2833
+ ParserState.prototype.pushExpression = function(instr, exprInstr) {
2834
+ for (var i = 0, len2 = exprInstr.length; i < len2; i++) {
2835
+ instr.push(exprInstr[i]);
2836
+ }
2837
+ };
2838
+ ParserState.prototype.parseUntilEndStatement = function(instr, exprInstr) {
2839
+ if (!this.accept(TSEMICOLON)) return false;
2840
+ if (this.nextToken && this.nextToken.type !== TEOF && !(this.nextToken.type === TPAREN && this.nextToken.value === ")")) {
2841
+ exprInstr.push(new Instruction(IENDSTATEMENT));
2842
+ }
2843
+ if (this.nextToken.type !== TEOF) {
2844
+ this.parseExpression(exprInstr);
2845
+ }
2846
+ instr.push(new Instruction(IEXPR, exprInstr));
2847
+ return true;
2848
+ };
2849
+ ParserState.prototype.parseArrayList = function(instr) {
2850
+ var argCount = 0;
2851
+ while (!this.accept(TBRACKET, "]")) {
2852
+ this.parseExpression(instr);
2853
+ ++argCount;
2854
+ while (this.accept(TCOMMA)) {
2855
+ this.parseExpression(instr);
2856
+ ++argCount;
2857
+ }
2858
+ }
2859
+ return argCount;
2860
+ };
2861
+ ParserState.prototype.parseVariableAssignmentExpression = function(instr) {
2862
+ this.parseConditionalExpression(instr);
2863
+ while (this.accept(TOP, "=")) {
2864
+ var varName = instr.pop();
2865
+ var varValue = [];
2866
+ var lastInstrIndex = instr.length - 1;
2867
+ if (varName.type === IFUNCALL) {
2868
+ if (!this.tokens.isOperatorEnabled("()=")) {
2869
+ throw new Error("function definition is not permitted");
2870
+ }
2871
+ for (var i = 0, len2 = varName.value + 1; i < len2; i++) {
2872
+ var index2 = lastInstrIndex - i;
2873
+ if (instr[index2].type === IVAR) {
2874
+ instr[index2] = new Instruction(IVARNAME, instr[index2].value);
2875
+ }
2876
+ }
2877
+ this.parseVariableAssignmentExpression(varValue);
2878
+ instr.push(new Instruction(IEXPR, varValue));
2879
+ instr.push(new Instruction(IFUNDEF, varName.value));
2880
+ continue;
2881
+ }
2882
+ if (varName.type !== IVAR && varName.type !== IMEMBER) {
2883
+ throw new Error("expected variable for assignment");
2884
+ }
2885
+ this.parseVariableAssignmentExpression(varValue);
2886
+ instr.push(new Instruction(IVARNAME, varName.value));
2887
+ instr.push(new Instruction(IEXPR, varValue));
2888
+ instr.push(binaryInstruction("="));
2889
+ }
2890
+ };
2891
+ ParserState.prototype.parseConditionalExpression = function(instr) {
2892
+ this.parseOrExpression(instr);
2893
+ while (this.accept(TOP, "?")) {
2894
+ var trueBranch = [];
2895
+ var falseBranch = [];
2896
+ this.parseConditionalExpression(trueBranch);
2897
+ this.expect(TOP, ":");
2898
+ this.parseConditionalExpression(falseBranch);
2899
+ instr.push(new Instruction(IEXPR, trueBranch));
2900
+ instr.push(new Instruction(IEXPR, falseBranch));
2901
+ instr.push(ternaryInstruction("?"));
2902
+ }
2903
+ };
2904
+ ParserState.prototype.parseOrExpression = function(instr) {
2905
+ this.parseAndExpression(instr);
2906
+ while (this.accept(TOP, "or")) {
2907
+ var falseBranch = [];
2908
+ this.parseAndExpression(falseBranch);
2909
+ instr.push(new Instruction(IEXPR, falseBranch));
2910
+ instr.push(binaryInstruction("or"));
2911
+ }
2912
+ };
2913
+ ParserState.prototype.parseAndExpression = function(instr) {
2914
+ this.parseComparison(instr);
2915
+ while (this.accept(TOP, "and")) {
2916
+ var trueBranch = [];
2917
+ this.parseComparison(trueBranch);
2918
+ instr.push(new Instruction(IEXPR, trueBranch));
2919
+ instr.push(binaryInstruction("and"));
2920
+ }
2921
+ };
2922
+ var COMPARISON_OPERATORS = ["==", "!=", "<", "<=", ">=", ">", "in"];
2923
+ ParserState.prototype.parseComparison = function(instr) {
2924
+ this.parseAddSub(instr);
2925
+ while (this.accept(TOP, COMPARISON_OPERATORS)) {
2926
+ var op = this.current;
2927
+ this.parseAddSub(instr);
2928
+ instr.push(binaryInstruction(op.value));
2929
+ }
2930
+ };
2931
+ var ADD_SUB_OPERATORS = ["+", "-", "||"];
2932
+ ParserState.prototype.parseAddSub = function(instr) {
2933
+ this.parseTerm(instr);
2934
+ while (this.accept(TOP, ADD_SUB_OPERATORS)) {
2935
+ var op = this.current;
2936
+ this.parseTerm(instr);
2937
+ instr.push(binaryInstruction(op.value));
2938
+ }
2939
+ };
2940
+ var TERM_OPERATORS = ["*", "/", "%"];
2941
+ ParserState.prototype.parseTerm = function(instr) {
2942
+ this.parseFactor(instr);
2943
+ while (this.accept(TOP, TERM_OPERATORS)) {
2944
+ var op = this.current;
2945
+ this.parseFactor(instr);
2946
+ instr.push(binaryInstruction(op.value));
2947
+ }
2948
+ };
2949
+ ParserState.prototype.parseFactor = function(instr) {
2950
+ var unaryOps = this.tokens.unaryOps;
2951
+ function isPrefixOperator(token) {
2952
+ return token.value in unaryOps;
2953
+ }
2954
+ this.save();
2955
+ if (this.accept(TOP, isPrefixOperator)) {
2956
+ if (this.current.value !== "-" && this.current.value !== "+") {
2957
+ if (this.nextToken.type === TPAREN && this.nextToken.value === "(") {
2958
+ this.restore();
2959
+ this.parseExponential(instr);
2960
+ return;
2961
+ } else if (this.nextToken.type === TSEMICOLON || this.nextToken.type === TCOMMA || this.nextToken.type === TEOF || this.nextToken.type === TPAREN && this.nextToken.value === ")") {
2962
+ this.restore();
2963
+ this.parseAtom(instr);
2964
+ return;
2965
+ }
2966
+ }
2967
+ var op = this.current;
2968
+ this.parseFactor(instr);
2969
+ instr.push(unaryInstruction(op.value));
2970
+ } else {
2971
+ this.parseExponential(instr);
2972
+ }
2973
+ };
2974
+ ParserState.prototype.parseExponential = function(instr) {
2975
+ this.parsePostfixExpression(instr);
2976
+ while (this.accept(TOP, "^")) {
2977
+ this.parseFactor(instr);
2978
+ instr.push(binaryInstruction("^"));
2979
+ }
2980
+ };
2981
+ ParserState.prototype.parsePostfixExpression = function(instr) {
2982
+ this.parseFunctionCall(instr);
2983
+ while (this.accept(TOP, "!")) {
2984
+ instr.push(unaryInstruction("!"));
2985
+ }
2986
+ };
2987
+ ParserState.prototype.parseFunctionCall = function(instr) {
2988
+ var unaryOps = this.tokens.unaryOps;
2989
+ function isPrefixOperator(token) {
2990
+ return token.value in unaryOps;
2991
+ }
2992
+ if (this.accept(TOP, isPrefixOperator)) {
2993
+ var op = this.current;
2994
+ this.parseAtom(instr);
2995
+ instr.push(unaryInstruction(op.value));
2996
+ } else {
2997
+ this.parseMemberExpression(instr);
2998
+ while (this.accept(TPAREN, "(")) {
2999
+ if (this.accept(TPAREN, ")")) {
3000
+ instr.push(new Instruction(IFUNCALL, 0));
3001
+ } else {
3002
+ var argCount = this.parseArgumentList(instr);
3003
+ instr.push(new Instruction(IFUNCALL, argCount));
3004
+ }
3005
+ }
3006
+ }
3007
+ };
3008
+ ParserState.prototype.parseArgumentList = function(instr) {
3009
+ var argCount = 0;
3010
+ while (!this.accept(TPAREN, ")")) {
3011
+ this.parseExpression(instr);
3012
+ ++argCount;
3013
+ while (this.accept(TCOMMA)) {
3014
+ this.parseExpression(instr);
3015
+ ++argCount;
3016
+ }
3017
+ }
3018
+ return argCount;
3019
+ };
3020
+ ParserState.prototype.parseMemberExpression = function(instr) {
3021
+ this.parseAtom(instr);
3022
+ while (this.accept(TOP, ".") || this.accept(TBRACKET, "[")) {
3023
+ var op = this.current;
3024
+ if (op.value === ".") {
3025
+ if (!this.allowMemberAccess) {
3026
+ throw new Error('unexpected ".", member access is not permitted');
3027
+ }
3028
+ this.expect(TNAME);
3029
+ instr.push(new Instruction(IMEMBER, this.current.value));
3030
+ } else if (op.value === "[") {
3031
+ if (!this.tokens.isOperatorEnabled("[")) {
3032
+ throw new Error('unexpected "[]", arrays are disabled');
3033
+ }
3034
+ this.parseExpression(instr);
3035
+ this.expect(TBRACKET, "]");
3036
+ instr.push(binaryInstruction("["));
3037
+ } else {
3038
+ throw new Error("unexpected symbol: " + op.value);
3039
+ }
3040
+ }
3041
+ };
3042
+ function add(a, b) {
3043
+ return Number(a) + Number(b);
3044
+ }
3045
+ function sub(a, b) {
3046
+ return a - b;
3047
+ }
3048
+ function mul(a, b) {
3049
+ return a * b;
3050
+ }
3051
+ function div(a, b) {
3052
+ return a / b;
3053
+ }
3054
+ function mod(a, b) {
3055
+ return a % b;
3056
+ }
3057
+ function concat(a, b) {
3058
+ if (Array.isArray(a) && Array.isArray(b)) {
3059
+ return a.concat(b);
3060
+ }
3061
+ return "" + a + b;
3062
+ }
3063
+ function equal(a, b) {
3064
+ return a === b;
3065
+ }
3066
+ function notEqual(a, b) {
3067
+ return a !== b;
3068
+ }
3069
+ function greaterThan(a, b) {
3070
+ return a > b;
3071
+ }
3072
+ function lessThan(a, b) {
3073
+ return a < b;
3074
+ }
3075
+ function greaterThanEqual(a, b) {
3076
+ return a >= b;
3077
+ }
3078
+ function lessThanEqual(a, b) {
3079
+ return a <= b;
3080
+ }
3081
+ function andOperator(a, b) {
3082
+ return Boolean(a && b);
3083
+ }
3084
+ function orOperator(a, b) {
3085
+ return Boolean(a || b);
3086
+ }
3087
+ function inOperator(a, b) {
3088
+ return contains(b, a);
3089
+ }
3090
+ function sinh(a) {
3091
+ return (Math.exp(a) - Math.exp(-a)) / 2;
3092
+ }
3093
+ function cosh(a) {
3094
+ return (Math.exp(a) + Math.exp(-a)) / 2;
3095
+ }
3096
+ function tanh(a) {
3097
+ if (a === Infinity) return 1;
3098
+ if (a === -Infinity) return -1;
3099
+ return (Math.exp(a) - Math.exp(-a)) / (Math.exp(a) + Math.exp(-a));
3100
+ }
3101
+ function asinh(a) {
3102
+ if (a === -Infinity) return a;
3103
+ return Math.log(a + Math.sqrt(a * a + 1));
3104
+ }
3105
+ function acosh(a) {
3106
+ return Math.log(a + Math.sqrt(a * a - 1));
3107
+ }
3108
+ function atanh(a) {
3109
+ return Math.log((1 + a) / (1 - a)) / 2;
3110
+ }
3111
+ function log10(a) {
3112
+ return Math.log(a) * Math.LOG10E;
3113
+ }
3114
+ function neg(a) {
3115
+ return -a;
3116
+ }
3117
+ function not(a) {
3118
+ return !a;
3119
+ }
3120
+ function trunc(a) {
3121
+ return a < 0 ? Math.ceil(a) : Math.floor(a);
3122
+ }
3123
+ function random(a) {
3124
+ return Math.random() * (a || 1);
3125
+ }
3126
+ function factorial(a) {
3127
+ return gamma(a + 1);
3128
+ }
3129
+ function isInteger(value) {
3130
+ return isFinite(value) && value === Math.round(value);
3131
+ }
3132
+ var GAMMA_G = 4.7421875;
3133
+ var GAMMA_P = [
3134
+ 0.9999999999999971,
3135
+ 57.15623566586292,
3136
+ -59.59796035547549,
3137
+ 14.136097974741746,
3138
+ -0.4919138160976202,
3139
+ 3399464998481189e-20,
3140
+ 4652362892704858e-20,
3141
+ -9837447530487956e-20,
3142
+ 1580887032249125e-19,
3143
+ -21026444172410488e-20,
3144
+ 21743961811521265e-20,
3145
+ -1643181065367639e-19,
3146
+ 8441822398385275e-20,
3147
+ -26190838401581408e-21,
3148
+ 36899182659531625e-22
3149
+ ];
3150
+ function gamma(n) {
3151
+ var t, x;
3152
+ if (isInteger(n)) {
3153
+ if (n <= 0) {
3154
+ return isFinite(n) ? Infinity : NaN;
3155
+ }
3156
+ if (n > 171) {
3157
+ return Infinity;
3158
+ }
3159
+ var value = n - 2;
3160
+ var res = n - 1;
3161
+ while (value > 1) {
3162
+ res *= value;
3163
+ value--;
3164
+ }
3165
+ if (res === 0) {
3166
+ res = 1;
3167
+ }
3168
+ return res;
3169
+ }
3170
+ if (n < 0.5) {
3171
+ return Math.PI / (Math.sin(Math.PI * n) * gamma(1 - n));
3172
+ }
3173
+ if (n >= 171.35) {
3174
+ return Infinity;
3175
+ }
3176
+ if (n > 85) {
3177
+ var twoN = n * n;
3178
+ var threeN = twoN * n;
3179
+ var fourN = threeN * n;
3180
+ var fiveN = fourN * n;
3181
+ return Math.sqrt(2 * Math.PI / n) * Math.pow(n / Math.E, n) * (1 + 1 / (12 * n) + 1 / (288 * twoN) - 139 / (51840 * threeN) - 571 / (2488320 * fourN) + 163879 / (209018880 * fiveN) + 5246819 / (75246796800 * fiveN * n));
3182
+ }
3183
+ --n;
3184
+ x = GAMMA_P[0];
3185
+ for (var i = 1; i < GAMMA_P.length; ++i) {
3186
+ x += GAMMA_P[i] / (n + i);
3187
+ }
3188
+ t = n + GAMMA_G + 0.5;
3189
+ return Math.sqrt(2 * Math.PI) * Math.pow(t, n + 0.5) * Math.exp(-t) * x;
3190
+ }
3191
+ function stringOrArrayLength(s) {
3192
+ if (Array.isArray(s)) {
3193
+ return s.length;
3194
+ }
3195
+ return String(s).length;
3196
+ }
3197
+ function hypot() {
3198
+ var sum2 = 0;
3199
+ var larg = 0;
3200
+ for (var i = 0; i < arguments.length; i++) {
3201
+ var arg = Math.abs(arguments[i]);
3202
+ var div2;
3203
+ if (larg < arg) {
3204
+ div2 = larg / arg;
3205
+ sum2 = sum2 * div2 * div2 + 1;
3206
+ larg = arg;
3207
+ } else if (arg > 0) {
3208
+ div2 = arg / larg;
3209
+ sum2 += div2 * div2;
3210
+ } else {
3211
+ sum2 += arg;
3212
+ }
3213
+ }
3214
+ return larg === Infinity ? Infinity : larg * Math.sqrt(sum2);
3215
+ }
3216
+ function condition(cond, yep, nope) {
3217
+ return cond ? yep : nope;
3218
+ }
3219
+ function roundTo(value, exp) {
3220
+ if (typeof exp === "undefined" || +exp === 0) {
3221
+ return Math.round(value);
3222
+ }
3223
+ value = +value;
3224
+ exp = -+exp;
3225
+ if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
3226
+ return NaN;
3227
+ }
3228
+ value = value.toString().split("e");
3229
+ value = Math.round(+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp)));
3230
+ value = value.toString().split("e");
3231
+ return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp));
3232
+ }
3233
+ function setVar(name, value, variables) {
3234
+ if (variables) variables[name] = value;
3235
+ return value;
3236
+ }
3237
+ function arrayIndex(array, index2) {
3238
+ return array[index2 | 0];
3239
+ }
3240
+ function max(array) {
3241
+ if (arguments.length === 1 && Array.isArray(array)) {
3242
+ return Math.max.apply(Math, array);
3243
+ } else {
3244
+ return Math.max.apply(Math, arguments);
3245
+ }
3246
+ }
3247
+ function min(array) {
3248
+ if (arguments.length === 1 && Array.isArray(array)) {
3249
+ return Math.min.apply(Math, array);
3250
+ } else {
3251
+ return Math.min.apply(Math, arguments);
3252
+ }
3253
+ }
3254
+ function arrayMap(f, a) {
3255
+ if (typeof f !== "function") {
3256
+ throw new Error("First argument to map is not a function");
3257
+ }
3258
+ if (!Array.isArray(a)) {
3259
+ throw new Error("Second argument to map is not an array");
3260
+ }
3261
+ return a.map(function(x, i) {
3262
+ return f(x, i);
3263
+ });
3264
+ }
3265
+ function arrayFold(f, init, a) {
3266
+ if (typeof f !== "function") {
3267
+ throw new Error("First argument to fold is not a function");
3268
+ }
3269
+ if (!Array.isArray(a)) {
3270
+ throw new Error("Second argument to fold is not an array");
3271
+ }
3272
+ return a.reduce(function(acc, x, i) {
3273
+ return f(acc, x, i);
3274
+ }, init);
3275
+ }
3276
+ function arrayFilter(f, a) {
3277
+ if (typeof f !== "function") {
3278
+ throw new Error("First argument to filter is not a function");
3279
+ }
3280
+ if (!Array.isArray(a)) {
3281
+ throw new Error("Second argument to filter is not an array");
3282
+ }
3283
+ return a.filter(function(x, i) {
3284
+ return f(x, i);
3285
+ });
3286
+ }
3287
+ function stringOrArrayIndexOf(target, s) {
3288
+ if (!(Array.isArray(s) || typeof s === "string")) {
3289
+ throw new Error("Second argument to indexOf is not a string or array");
3290
+ }
3291
+ return s.indexOf(target);
3292
+ }
3293
+ function arrayJoin(sep, a) {
3294
+ if (!Array.isArray(a)) {
3295
+ throw new Error("Second argument to join is not an array");
3296
+ }
3297
+ return a.join(sep);
3298
+ }
3299
+ function sign(x) {
3300
+ return (x > 0) - (x < 0) || +x;
3301
+ }
3302
+ var ONE_THIRD = 1 / 3;
3303
+ function cbrt(x) {
3304
+ return x < 0 ? -Math.pow(-x, ONE_THIRD) : Math.pow(x, ONE_THIRD);
3305
+ }
3306
+ function expm1(x) {
3307
+ return Math.exp(x) - 1;
3308
+ }
3309
+ function log1p(x) {
3310
+ return Math.log(1 + x);
3311
+ }
3312
+ function log2(x) {
3313
+ return Math.log(x) / Math.LN2;
3314
+ }
3315
+ function Parser(options) {
3316
+ this.options = options || {};
3317
+ this.unaryOps = {
3318
+ sin: Math.sin,
3319
+ cos: Math.cos,
3320
+ tan: Math.tan,
3321
+ asin: Math.asin,
3322
+ acos: Math.acos,
3323
+ atan: Math.atan,
3324
+ sinh: Math.sinh || sinh,
3325
+ cosh: Math.cosh || cosh,
3326
+ tanh: Math.tanh || tanh,
3327
+ asinh: Math.asinh || asinh,
3328
+ acosh: Math.acosh || acosh,
3329
+ atanh: Math.atanh || atanh,
3330
+ sqrt: Math.sqrt,
3331
+ cbrt: Math.cbrt || cbrt,
3332
+ log: Math.log,
3333
+ log2: Math.log2 || log2,
3334
+ ln: Math.log,
3335
+ lg: Math.log10 || log10,
3336
+ log10: Math.log10 || log10,
3337
+ expm1: Math.expm1 || expm1,
3338
+ log1p: Math.log1p || log1p,
3339
+ abs: Math.abs,
3340
+ ceil: Math.ceil,
3341
+ floor: Math.floor,
3342
+ round: Math.round,
3343
+ trunc: Math.trunc || trunc,
3344
+ "-": neg,
3345
+ "+": Number,
3346
+ exp: Math.exp,
3347
+ not,
3348
+ length: stringOrArrayLength,
3349
+ "!": factorial,
3350
+ sign: Math.sign || sign
3351
+ };
3352
+ this.binaryOps = {
3353
+ "+": add,
3354
+ "-": sub,
3355
+ "*": mul,
3356
+ "/": div,
3357
+ "%": mod,
3358
+ "^": Math.pow,
3359
+ "||": concat,
3360
+ "==": equal,
3361
+ "!=": notEqual,
3362
+ ">": greaterThan,
3363
+ "<": lessThan,
3364
+ ">=": greaterThanEqual,
3365
+ "<=": lessThanEqual,
3366
+ and: andOperator,
3367
+ or: orOperator,
3368
+ "in": inOperator,
3369
+ "=": setVar,
3370
+ "[": arrayIndex
3371
+ };
3372
+ this.ternaryOps = {
3373
+ "?": condition
3374
+ };
3375
+ this.functions = {
3376
+ random,
3377
+ fac: factorial,
3378
+ min,
3379
+ max,
3380
+ hypot: Math.hypot || hypot,
3381
+ pyt: Math.hypot || hypot,
3382
+ // backward compat
3383
+ pow: Math.pow,
3384
+ atan2: Math.atan2,
3385
+ "if": condition,
3386
+ gamma,
3387
+ roundTo,
3388
+ map: arrayMap,
3389
+ fold: arrayFold,
3390
+ filter: arrayFilter,
3391
+ indexOf: stringOrArrayIndexOf,
3392
+ join: arrayJoin
3393
+ };
3394
+ this.consts = {
3395
+ E: Math.E,
3396
+ PI: Math.PI,
3397
+ "true": true,
3398
+ "false": false
3399
+ };
3400
+ }
3401
+ Parser.prototype.parse = function(expr) {
3402
+ var instr = [];
3403
+ var parserState = new ParserState(
3404
+ this,
3405
+ new TokenStream(this, expr),
3406
+ { allowMemberAccess: this.options.allowMemberAccess }
3407
+ );
3408
+ parserState.parseExpression(instr);
3409
+ parserState.expect(TEOF, "EOF");
3410
+ return new Expression(instr, this);
3411
+ };
3412
+ Parser.prototype.evaluate = function(expr, variables) {
3413
+ return this.parse(expr).evaluate(variables);
3414
+ };
3415
+ var sharedParser = new Parser();
3416
+ Parser.parse = function(expr) {
3417
+ return sharedParser.parse(expr);
3418
+ };
3419
+ Parser.evaluate = function(expr, variables) {
3420
+ return sharedParser.parse(expr).evaluate(variables);
3421
+ };
3422
+ var optionNameMap = {
3423
+ "+": "add",
3424
+ "-": "subtract",
3425
+ "*": "multiply",
3426
+ "/": "divide",
3427
+ "%": "remainder",
3428
+ "^": "power",
3429
+ "!": "factorial",
3430
+ "<": "comparison",
3431
+ ">": "comparison",
3432
+ "<=": "comparison",
3433
+ ">=": "comparison",
3434
+ "==": "comparison",
3435
+ "!=": "comparison",
3436
+ "||": "concatenate",
3437
+ "and": "logical",
3438
+ "or": "logical",
3439
+ "not": "logical",
3440
+ "?": "conditional",
3441
+ ":": "conditional",
3442
+ "=": "assignment",
3443
+ "[": "array",
3444
+ "()=": "fndef"
3445
+ };
3446
+ function getOptionName(op) {
3447
+ return optionNameMap.hasOwnProperty(op) ? optionNameMap[op] : op;
3448
+ }
3449
+ Parser.prototype.isOperatorEnabled = function(op) {
3450
+ var optionName = getOptionName(op);
3451
+ var operators2 = this.options.operators || {};
3452
+ return !(optionName in operators2) || !!operators2[optionName];
3453
+ };
3454
+ const calc = (expression, context) => {
3455
+ if (typeof expression !== "string") {
3456
+ return expression;
3457
+ }
3458
+ let processedExpression = expression;
3459
+ try {
3460
+ const pathResolver = (path) => {
3461
+ let currentPath = path;
3462
+ let value;
3463
+ let depth = 0;
3464
+ while (typeof currentPath === "string" && (currentPath.startsWith("/") || currentPath.startsWith("=/")) && depth < 5) {
3465
+ const normalizedPath = currentPath.startsWith("/") ? "=" + currentPath : currentPath;
3466
+ const resolved = resolvePath(normalizedPath, context);
3467
+ value = unwrapSignal(resolved);
3468
+ if (typeof value === "string" && (value.startsWith("/") || value.startsWith("=/")) && value !== currentPath) {
3469
+ currentPath = value;
3470
+ depth++;
3471
+ } else {
3472
+ break;
3473
+ }
3474
+ }
3475
+ if (typeof value === "number") return value;
3476
+ if (typeof value === "string") {
3477
+ const num = parseFloat(value);
3478
+ if (!isNaN(num) && isFinite(Number(value))) return num;
3479
+ return value === "" ? 0 : `"${value.replace(/"/g, '\\"')}"`;
3480
+ }
3481
+ return value === void 0 || value === null ? 0 : value;
3482
+ };
3483
+ const pathRegex = /\$\(\s*['"](.*?)['"]\s*\)/g;
3484
+ processedExpression = expression.replace(pathRegex, (match2, path) => {
3485
+ const val = pathResolver(path);
3486
+ return val;
3487
+ });
3488
+ const parser = new Parser();
3489
+ const parsed = parser.parse(processedExpression);
3490
+ return parsed.evaluate();
3491
+ } catch (error) {
3492
+ console.error("JPRX calc error:", error.message);
3493
+ console.error("Original expression:", expression);
3494
+ console.error("Processed expression:", processedExpression);
3495
+ return NaN;
3496
+ }
3497
+ };
3498
+ const registerCalcHelpers = (register) => {
3499
+ register("calc", calc, { pathAware: true });
3500
+ };
3501
+ const registerDOMHelpers = (registerHelper2) => {
3502
+ registerHelper2("xpath", function(expression) {
3503
+ const domNode = this;
3504
+ if (!domNode || !(domNode instanceof Element)) {
3505
+ console.warn("[Lightview-CDOM] xpath() called without valid DOM context");
3506
+ return "";
3507
+ }
3508
+ const forbiddenAxes = /\b(child|descendant|following|following-sibling)::/;
3509
+ if (forbiddenAxes.test(expression)) {
3510
+ console.error(`[Lightview-CDOM] xpath(): Forward-looking axes not allowed: ${expression}`);
3511
+ return "";
3512
+ }
3513
+ const hasShorthandChild = /\/[a-zA-Z]/.test(expression) && !expression.startsWith("/html");
3514
+ if (hasShorthandChild) {
3515
+ console.error(`[Lightview-CDOM] xpath(): Shorthand child axis (/) not allowed: ${expression}`);
3516
+ return "";
3517
+ }
3518
+ const LV = globalThis.Lightview;
3519
+ if (!LV || !LV.computed) {
3520
+ console.warn("[Lightview-CDOM] xpath(): Lightview not available");
3521
+ return "";
3522
+ }
3523
+ return LV.computed(() => {
3524
+ try {
3525
+ const result = document.evaluate(
3526
+ expression,
3527
+ domNode,
3528
+ null,
3529
+ XPathResult.STRING_TYPE,
3530
+ null
3531
+ );
3532
+ return result.stringValue;
3533
+ } catch (e) {
3534
+ console.error(`[Lightview-CDOM] xpath() evaluation failed:`, e.message);
3535
+ return "";
3536
+ }
3537
+ });
3538
+ }, { pathAware: false });
3539
+ };
3540
+ const _LV = globalThis.__LIGHTVIEW_INTERNALS__ || (globalThis.__LIGHTVIEW_INTERNALS__ = {
3541
+ currentEffect: null,
3542
+ registry: /* @__PURE__ */ new Map(),
3543
+ // Global name -> Signal/Proxy
3544
+ localRegistries: /* @__PURE__ */ new WeakMap(),
3545
+ // Object/Element -> Map(name -> Signal/Proxy)
3546
+ futureSignals: /* @__PURE__ */ new Map(),
3547
+ // name -> Set of (signal) => void
3548
+ schemas: /* @__PURE__ */ new Map(),
3549
+ // name -> Schema (Draft 7+ or Shorthand)
3550
+ parents: /* @__PURE__ */ new WeakMap(),
3551
+ // Proxy -> Parent (Proxy/Element)
3552
+ helpers: /* @__PURE__ */ new Map(),
3553
+ // name -> function (used for transforms and expressions)
3554
+ hooks: {
3555
+ validate: (value, schema) => true
3556
+ // Hook for extensions (like JPRX) to provide full validation
3557
+ }
3558
+ });
3559
+ const internals = _LV;
3560
+ const { parents, schemas, hooks } = internals;
3561
+ const protoMethods = (proto, test) => Object.getOwnPropertyNames(proto).filter((k) => typeof proto[k] === "function" && test(k));
3562
+ protoMethods(Date.prototype, (k) => /^(to|get|valueOf)/.test(k));
3563
+ protoMethods(Date.prototype, (k) => /^set/.test(k));
3564
+ registerMathHelpers(registerHelper);
3565
+ registerLogicHelpers(registerHelper);
3566
+ registerStringHelpers(registerHelper);
3567
+ registerArrayHelpers(registerHelper);
3568
+ registerCompareHelpers(registerHelper);
3569
+ registerConditionalHelpers(registerHelper);
3570
+ registerDateTimeHelpers(registerHelper);
3571
+ registerFormatHelpers(registerHelper);
3572
+ registerLookupHelpers(registerHelper);
3573
+ registerStatsHelpers(registerHelper);
3574
+ registerStateHelpers((name, fn) => registerHelper(name, fn, { pathAware: true }));
3575
+ registerNetworkHelpers(registerHelper);
3576
+ registerCalcHelpers(registerHelper);
3577
+ registerDOMHelpers(registerHelper);
3578
+ registerHelper("move", (selector, location = "beforeend") => {
3579
+ return {
3580
+ isLazy: true,
3581
+ resolve: (eventOrNode) => {
3582
+ const isEvent = eventOrNode && typeof eventOrNode === "object" && "target" in eventOrNode;
3583
+ const node = isEvent ? eventOrNode.currentTarget || eventOrNode.target : eventOrNode;
3584
+ if (!(node instanceof Node) || !selector) return;
3585
+ const target = document.querySelector(selector);
3586
+ if (!target) {
3587
+ console.warn(`[Lightview-CDOM] move target not found: ${selector}`);
3588
+ return;
3589
+ }
3590
+ if (node.id) {
3591
+ const escapedId = CSS.escape(node.id);
3592
+ if (target.id === node.id && target !== node) {
3593
+ target.replaceWith(node);
3594
+ return;
3595
+ }
3596
+ const existing = target.querySelector(`#${escapedId}`);
3597
+ if (existing && existing !== node) {
3598
+ existing.replaceWith(node);
3599
+ return;
3600
+ }
3601
+ }
3602
+ globalThis.Lightview.$(target).content(node, location);
3603
+ }
3604
+ };
3605
+ }, { pathAware: true });
3606
+ registerHelper("mount", async (url, options = {}) => {
3607
+ const { target = "body", location = "beforeend" } = options;
3608
+ try {
3609
+ const fetchOptions = { ...options };
3610
+ delete fetchOptions.target;
3611
+ delete fetchOptions.location;
3612
+ const headers = { ...fetchOptions.headers };
3613
+ let body = fetchOptions.body;
3614
+ if (body !== void 0) {
3615
+ if (body !== null && typeof body === "object") {
3616
+ body = JSON.stringify(body);
3617
+ if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
3618
+ } else {
3619
+ body = String(body);
3620
+ if (!headers["Content-Type"]) headers["Content-Type"] = "text/plain";
3621
+ }
3622
+ fetchOptions.body = body;
3623
+ fetchOptions.headers = headers;
3624
+ }
3625
+ const response = await globalThis.fetch(url, fetchOptions);
3626
+ const contentType = response.headers.get("Content-Type") || "";
3627
+ const text = await response.text();
3628
+ let content = text;
3629
+ const isCDOM = contentType.includes("application/cdom") || contentType.includes("application/jprx") || contentType.includes("application/vdom") || contentType.includes("application/odom") || url.endsWith(".cdom") || url.endsWith(".jprx") || url.endsWith(".vdom") || url.endsWith(".odom");
3630
+ if (isCDOM || contentType.includes("application/json") && text.trim().startsWith("{")) {
3631
+ try {
3632
+ content = hydrate(parseCDOMC(text));
3633
+ } catch (e) {
3634
+ }
3635
+ }
3636
+ const targetEl = document.querySelector(target);
3637
+ if (targetEl) {
3638
+ globalThis.Lightview.$(targetEl).content(content, location);
3639
+ } else {
3640
+ console.warn(`[Lightview-CDOM] $mount target not found: ${target}`);
3641
+ }
3642
+ } catch (err) {
3643
+ console.error(`[Lightview-CDOM] $mount failed for ${url}:`, err);
3644
+ }
3645
+ });
3646
+ registerOperator("increment", "++", "prefix", 80);
3647
+ registerOperator("increment", "++", "postfix", 80);
3648
+ registerOperator("decrement", "--", "prefix", 80);
3649
+ registerOperator("decrement", "--", "postfix", 80);
3650
+ registerOperator("toggle", "!!", "prefix", 80);
3651
+ registerOperator("set", "=", "infix", 20);
3652
+ registerOperator("+", "+", "infix", 50);
3653
+ registerOperator("-", "-", "infix", 50, { requiresWhitespace: true });
3654
+ registerOperator("*", "*", "infix", 60, { requiresWhitespace: true });
3655
+ registerOperator("/", "/", "infix", 60, { requiresWhitespace: true });
3656
+ registerOperator("gt", ">", "infix", 40);
3657
+ registerOperator("lt", "<", "infix", 40);
3658
+ registerOperator("gte", ">=", "infix", 40);
3659
+ registerOperator("lte", "<=", "infix", 40);
3660
+ registerOperator("neq", "!=", "infix", 40);
3661
+ registerOperator("strictNeq", "!==", "infix", 40);
3662
+ registerOperator("eq", "==", "infix", 40);
3663
+ registerOperator("strictEq", "===", "infix", 40);
3664
+ const getContext = (node, event = null) => {
3665
+ return new Proxy({}, {
3666
+ get(_, prop) {
3667
+ if (prop === "$event" || prop === "event") return event;
3668
+ if (prop === "$this" || prop === "this" || prop === "__node__") return node;
3669
+ return unwrapSignal(globalThis.Lightview.getState(prop, { scope: node }));
3670
+ },
3671
+ set(_, prop, value) {
3672
+ const res = globalThis.Lightview.getState(prop, { scope: node });
3673
+ if (res && (typeof res === "object" || typeof res === "function") && "value" in res) {
3674
+ res.value = value;
3675
+ return true;
3676
+ }
3677
+ return false;
3678
+ }
3679
+ });
3680
+ };
3681
+ globalThis.Lightview.hooks.processAttribute = (domNode, key, value) => {
3682
+ if (value == null ? void 0 : value.__JPRX_BIND__) {
3683
+ const { path, options } = value;
3684
+ const type = domNode.type || "";
3685
+ const tagName = domNode.tagName.toLowerCase();
3686
+ let prop = "value";
3687
+ let event = "input";
3688
+ if (type === "checkbox" || type === "radio") {
3689
+ prop = "checked";
3690
+ event = "change";
3691
+ } else if (tagName === "select") {
3692
+ event = "change";
3693
+ }
3694
+ const res = globalThis.Lightview.get(path.replace(/^=/, ""), { scope: domNode });
3695
+ const runner = globalThis.Lightview.effect(() => {
3696
+ const val = unwrapSignal(res);
3697
+ if (domNode[prop] !== val) {
3698
+ domNode[prop] = val === void 0 ? "" : val;
3699
+ }
3700
+ });
3701
+ globalThis.Lightview.internals.trackEffect(domNode, runner);
3702
+ domNode.addEventListener(event, () => {
3703
+ if (res && "value" in res) res.value = domNode[prop];
3704
+ });
3705
+ return unwrapSignal(res) ?? domNode[prop];
3706
+ }
3707
+ return void 0;
3708
+ };
3709
+ const activate = (root = document.body) => {
3710
+ };
3711
+ const makeEventHandler = (expr) => (eventOrNode) => {
3712
+ const isEvent = eventOrNode && typeof eventOrNode === "object" && "target" in eventOrNode;
3713
+ const target = isEvent ? eventOrNode.currentTarget || eventOrNode.target : eventOrNode;
3714
+ const context = getContext(target, isEvent ? eventOrNode : null);
3715
+ const result = resolveExpression$1(expr, context);
3716
+ if (result && typeof result === "object" && result.isLazy) return result.resolve(context);
3717
+ return result;
3718
+ };
3719
+ const hydrate = (node, parent = null) => {
3720
+ var _a, _b, _c;
3721
+ if (!node) return node;
3722
+ if (typeof node === "string" && node.startsWith("'=")) {
3723
+ return node.slice(1);
3724
+ }
3725
+ if (typeof node === "string" && node.startsWith("'#")) {
3726
+ return node.slice(1);
3727
+ }
3728
+ if (typeof node === "string" && node.startsWith("#")) {
3729
+ return { __xpath__: node.slice(1), __static__: true };
3730
+ }
3731
+ if (typeof node === "string" && node.startsWith("=")) {
3732
+ return parseExpression(node, parent);
3733
+ }
3734
+ if (typeof node !== "object") return node;
3735
+ if (Array.isArray(node)) {
3736
+ return node.map((item) => hydrate(item, parent));
3737
+ }
3738
+ if (node instanceof String) return node.toString();
3739
+ if (parent && !("__parent__" in node)) {
3740
+ Object.defineProperty(node, "__parent__", { value: parent, enumerable: false, writable: true });
3741
+ (_c = (_b = (_a = globalThis.Lightview) == null ? void 0 : _a.internals) == null ? void 0 : _b.parents) == null ? void 0 : _c.set(node, parent);
3742
+ }
3743
+ if (!node.tag) {
3744
+ let potentialTag = null;
3745
+ const reserved = ["children", "attributes", "tag", "__parent__"];
3746
+ for (const key in node) {
3747
+ if (reserved.includes(key) || key.startsWith("on")) continue;
3748
+ potentialTag = key;
3749
+ break;
3750
+ }
3751
+ if (potentialTag) {
3752
+ const content = node[potentialTag];
3753
+ node.tag = potentialTag;
3754
+ if (Array.isArray(content)) {
3755
+ node.children = content;
3756
+ } else if (typeof content === "object") {
3757
+ node.attributes = node.attributes || {};
3758
+ for (const k in content) {
3759
+ if (k === "children") node.children = content[k];
3760
+ else node.attributes[k] = content[k];
3761
+ }
3762
+ } else node.children = [content];
3763
+ delete node[potentialTag];
3764
+ }
3765
+ }
3766
+ for (const key in node) {
3767
+ if (key === "tag" || key === "__parent__") continue;
3768
+ const value = node[key];
3769
+ if (key === "attributes" && typeof value === "object" && value !== null) {
3770
+ for (const attrKey in value) {
3771
+ const attrVal = value[attrKey];
3772
+ if (typeof attrVal === "string" && attrVal.startsWith("'=")) {
3773
+ value[attrKey] = attrVal.slice(1);
3774
+ } else if (typeof attrVal === "string" && attrVal.startsWith("'#")) {
3775
+ value[attrKey] = attrVal.slice(1);
3776
+ } else if (typeof attrVal === "string" && attrVal.startsWith("#")) {
3777
+ value[attrKey] = { __xpath__: attrVal.slice(1), __static__: true };
3778
+ } else if (typeof attrVal === "string" && attrVal.startsWith("=")) {
3779
+ if (attrKey.startsWith("on")) {
3780
+ value[attrKey] = makeEventHandler(attrVal);
3781
+ } else {
3782
+ value[attrKey] = parseExpression(attrVal, node);
3783
+ }
3784
+ } else if (typeof attrVal === "object" && attrVal !== null) {
3785
+ value[attrKey] = hydrate(attrVal, node);
3786
+ }
3787
+ }
3788
+ continue;
3789
+ }
3790
+ if (typeof value === "string" && value.startsWith("'=")) {
3791
+ node[key] = value.slice(1);
3792
+ } else if (typeof value === "string" && value.startsWith("'#")) {
3793
+ node[key] = value.slice(1);
3794
+ } else if (typeof value === "string" && value.startsWith("#")) {
3795
+ node[key] = { __xpath__: value.slice(1), __static__: true };
3796
+ } else if (typeof value === "string" && value.startsWith("=")) {
3797
+ if (key === "onmount" || key === "onunmount" || key.startsWith("on")) {
3798
+ node[key] = makeEventHandler(value);
3799
+ } else if (key === "children") {
3800
+ node[key] = [parseExpression(value, node)];
3801
+ } else {
3802
+ node[key] = parseExpression(value, node);
3803
+ }
3804
+ } else {
3805
+ node[key] = hydrate(value, node);
3806
+ }
3807
+ }
3808
+ if (!parent && node.tag) {
3809
+ node.attributes = node.attributes || {};
3810
+ const originalOnMount = node.attributes.onmount;
3811
+ node.attributes.onmount = (el) => {
3812
+ if (typeof originalOnMount === "function") originalOnMount(el);
3813
+ resolveStaticXPath(el);
3814
+ };
3815
+ }
3816
+ return node;
3817
+ };
3818
+ const validateXPath = (xpath) => {
3819
+ if (!xpath) return;
3820
+ const forbiddenAxes = /\b(child|descendant|following|following-sibling)::/;
3821
+ if (forbiddenAxes.test(xpath)) {
3822
+ throw new Error(`XPath: Forward-looking axes not allowed during DOM construction: ${xpath}`);
3823
+ }
3824
+ const hasShorthandChild = /\/(?![@.])(?![a-zA-Z0-9_-]+::)[a-zA-Z]/.test(xpath) && !xpath.startsWith("/html");
3825
+ if (hasShorthandChild) {
3826
+ throw new Error(`XPath: Shorthand child axis (/) not allowed during DOM construction: ${xpath}`);
3827
+ }
3828
+ };
3829
+ const resolveAttributeXPaths = (el) => {
3830
+ var _a;
3831
+ const attributes = [...el.attributes];
3832
+ for (const attr of attributes) {
3833
+ if (attr.name.startsWith("data-xpath-")) {
3834
+ const realAttr = attr.name.replace("data-xpath-", "");
3835
+ try {
3836
+ validateXPath(attr.value);
3837
+ const doc = globalThis.document || el.ownerDocument;
3838
+ const result = doc.evaluate(
3839
+ attr.value,
3840
+ el,
3841
+ null,
3842
+ XPathResult.STRING_TYPE,
3843
+ null
3844
+ );
3845
+ el.setAttribute(realAttr, result.stringValue);
3846
+ el.removeAttribute(attr.name);
3847
+ } catch (e) {
3848
+ (_a = globalThis.console) == null ? void 0 : _a.error(`[Lightview-CDOM] XPath attribute error ("${realAttr}") at <${el.tagName.toLowerCase()} id="${el.id}">:`, e.message);
3849
+ }
3850
+ }
3851
+ }
3852
+ };
3853
+ const resolveTextNodeXPath = (node) => {
3854
+ var _a, _b, _c;
3855
+ if (!node.__xpathExpr) return;
3856
+ const xpath = node.__xpathExpr;
3857
+ try {
3858
+ validateXPath(xpath);
3859
+ const doc = globalThis.document || node.ownerDocument;
3860
+ const result = doc.evaluate(
3861
+ xpath,
3862
+ node,
3863
+ null,
3864
+ XPathResult.STRING_TYPE,
3865
+ null
3866
+ );
3867
+ node.textContent = result.stringValue;
3868
+ } catch (e) {
3869
+ (_c = globalThis.console) == null ? void 0 : _c.error(`[Lightview-CDOM] XPath text node error on <${(_a = node.parentNode) == null ? void 0 : _a.tagName.toLowerCase()} id="${(_b = node.parentNode) == null ? void 0 : _b.id}">:`, e.message);
3870
+ } finally {
3871
+ delete node.__xpathExpr;
3872
+ }
3873
+ };
3874
+ const resolveStaticXPath = (rootNode) => {
3875
+ const node = rootNode instanceof Node ? rootNode : (rootNode == null ? void 0 : rootNode.domEl) || rootNode;
3876
+ if (!node || !node.nodeType) return;
3877
+ if (node.nodeType === Node.ELEMENT_NODE) resolveAttributeXPaths(node);
3878
+ resolveTextNodeXPath(node);
3879
+ const doc = globalThis.document || node.ownerDocument;
3880
+ const walker = doc.createTreeWalker(node, NodeFilter.SHOW_ALL);
3881
+ let current = walker.nextNode();
3882
+ while (current) {
3883
+ if (current.nodeType === Node.ELEMENT_NODE) resolveAttributeXPaths(current);
3884
+ resolveTextNodeXPath(current);
3885
+ current = walker.nextNode();
3886
+ }
3887
+ };
3888
+ if (typeof parseCDOMC !== "function") throw new Error("parseCDOMC not found");
3889
+ if (typeof parseJPRX !== "function") throw new Error("oldParseJPRX not found");
3890
+ const LightviewCDOM2 = {
3891
+ registerHelper,
3892
+ registerOperator,
3893
+ parseExpression,
3894
+ resolvePath,
3895
+ resolvePathAsContext,
3896
+ resolveExpression: resolveExpression$1,
3897
+ parseCDOMC,
3898
+ parseJPRX: parseCDOMC,
3899
+ // Alias parseJPRX to the more robust parseCDOMC
3900
+ oldParseJPRX: parseJPRX,
3901
+ unwrapSignal,
3902
+ getContext,
3903
+ handleCDOMState: () => {
3904
+ },
3905
+ handleCDOMBind: () => {
3906
+ },
3907
+ activate,
3908
+ hydrate,
3909
+ resolveStaticXPath,
3910
+ version: "1.1.0"
3911
+ };
3912
+ if (typeof window !== "undefined") {
3913
+ globalThis.LightviewCDOM = {};
3914
+ Object.assign(globalThis.LightviewCDOM, LightviewCDOM2);
3915
+ }
3916
+ exports.BindingTarget = BindingTarget;
3917
+ exports.activate = activate;
3918
+ exports.default = LightviewCDOM2;
3919
+ exports.getContext = getContext;
3920
+ exports.hydrate = hydrate;
3921
+ exports.oldParseJPRX = parseJPRX;
3922
+ exports.parseCDOMC = parseCDOMC;
3923
+ exports.parseExpression = parseExpression;
3924
+ exports.parseJPRX = parseCDOMC;
3925
+ exports.registerHelper = registerHelper;
3926
+ exports.registerOperator = registerOperator;
3927
+ exports.resolveExpression = resolveExpression$1;
3928
+ exports.resolvePath = resolvePath;
3929
+ exports.resolvePathAsContext = resolvePathAsContext;
3930
+ exports.resolveStaticXPath = resolveStaticXPath;
3931
+ exports.unwrapSignal = unwrapSignal;
3932
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3933
+ return exports;
3934
+ }({});