lightview 2.3.4 → 2.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gemini/XPATH_IMPLEMENTATION.md +190 -0
- package/_headers +5 -0
- package/_routes.json +7 -0
- package/build-bundles.mjs +10 -0
- package/docs/articles/calculator-no-javascript-hackernoon.md +283 -0
- package/docs/articles/calculator-no-javascript.md +290 -0
- package/docs/articles/part1-reference.md +236 -0
- package/docs/calculator.cdomc +77 -0
- package/docs/calculator.css +316 -0
- package/docs/calculator.html +22 -0
- package/docs/cdom-nav.html +1 -1
- package/docs/cdom.html +2 -2
- package/functions/_middleware.js +20 -3
- package/jprx/README.md +1 -1
- package/jprx/helpers/calc.js +82 -0
- package/jprx/helpers/dom.js +69 -0
- package/jprx/helpers/logic.js +9 -3
- package/jprx/helpers/lookup.js +39 -0
- package/jprx/helpers/math.js +4 -0
- package/jprx/index.js +4 -0
- package/jprx/package.json +2 -2
- package/jprx/parser.js +394 -83
- package/lightview-all.js +2256 -168
- package/lightview-cdom.js +2176 -92
- package/lightview-x.js +4 -3
- package/lightview.js +14 -0
- package/package.json +3 -2
- package/src/lightview-cdom.js +153 -8
- package/src/lightview-x.js +5 -2
- package/src/lightview.js +19 -0
- package/test-xpath-preprocess.js +18 -0
- package/test-xpath.html +63 -0
- package/test_error.txt +0 -0
- package/test_output.txt +0 -0
- package/test_output_full.txt +0 -0
- package/tests/cdom/operators.test.js +141 -0
- package/wrangler.toml +1 -0
- package/cDOMIntro.md +0 -279
- package/start-dev.js +0 -93
package/lightview-all.js
CHANGED
|
@@ -587,6 +587,11 @@
|
|
|
587
587
|
const makeReactiveAttributes = (attributes, domNode) => {
|
|
588
588
|
const reactiveAttrs = {};
|
|
589
589
|
for (let [key, value] of Object.entries(attributes)) {
|
|
590
|
+
if (value && typeof value === "object" && value.__xpath__ && value.__static__) {
|
|
591
|
+
domNode.setAttribute(`data-xpath-${key}`, value.__xpath__);
|
|
592
|
+
reactiveAttrs[key] = value;
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
590
595
|
if (key === "onmount" || key === "onunmount") {
|
|
591
596
|
const state2 = getOrSet(nodeState, domNode, nodeStateFactory);
|
|
592
597
|
state2[key] = value;
|
|
@@ -640,6 +645,7 @@
|
|
|
640
645
|
return reactiveAttrs;
|
|
641
646
|
};
|
|
642
647
|
const processChildren = (children, targetNode, clearExisting = true) => {
|
|
648
|
+
var _a2;
|
|
643
649
|
if (clearExisting && targetNode.innerHTML !== void 0) {
|
|
644
650
|
targetNode.innerHTML = "";
|
|
645
651
|
}
|
|
@@ -688,6 +694,11 @@
|
|
|
688
694
|
runner = effect(update);
|
|
689
695
|
trackEffect(startMarker, runner);
|
|
690
696
|
childElements.push(child);
|
|
697
|
+
} else if (child && typeof child === "object" && child.__xpath__ && child.__static__) {
|
|
698
|
+
const textNode = document.createTextNode("");
|
|
699
|
+
textNode.__xpathExpr = child.__xpath__;
|
|
700
|
+
targetNode.appendChild(textNode);
|
|
701
|
+
childElements.push(child);
|
|
691
702
|
} else if (["string", "number", "boolean", "symbol"].includes(type) || child && type === "object" && child instanceof String) {
|
|
692
703
|
targetNode.appendChild(document.createTextNode(child));
|
|
693
704
|
childElements.push(child);
|
|
@@ -707,6 +718,9 @@
|
|
|
707
718
|
childElements.push(childEl);
|
|
708
719
|
}
|
|
709
720
|
}
|
|
721
|
+
if (typeof ((_a2 = globalThis.LightviewCDOM) == null ? void 0 : _a2.resolveStaticXPath) === "function") {
|
|
722
|
+
globalThis.LightviewCDOM.resolveStaticXPath(targetNode);
|
|
723
|
+
}
|
|
710
724
|
return childElements;
|
|
711
725
|
};
|
|
712
726
|
const setupChildrenInTarget = (children, targetNode) => {
|
|
@@ -1297,14 +1311,15 @@
|
|
|
1297
1311
|
}
|
|
1298
1312
|
};
|
|
1299
1313
|
const parseElements = (content, isJson, isHtml, el, element2, isCdom = false, ext = "") => {
|
|
1300
|
-
var _a2;
|
|
1301
1314
|
if (isJson) return Array.isArray(content) ? content : [content];
|
|
1302
1315
|
if (isCdom && ext === "cdomc") {
|
|
1303
|
-
const
|
|
1316
|
+
const CDOM = globalThis.LightviewCDOM;
|
|
1317
|
+
const parser = CDOM == null ? void 0 : CDOM.parseCDOMC;
|
|
1304
1318
|
if (parser) {
|
|
1305
1319
|
try {
|
|
1306
1320
|
const obj = parser(content);
|
|
1307
|
-
|
|
1321
|
+
const hydrated = CDOM.hydrate ? CDOM.hydrate(obj) : obj;
|
|
1322
|
+
return Array.isArray(hydrated) ? hydrated : [hydrated];
|
|
1308
1323
|
} catch (e) {
|
|
1309
1324
|
console.warn("LightviewX: Failed to parse .cdomc:", e);
|
|
1310
1325
|
return [];
|
|
@@ -2189,7 +2204,7 @@
|
|
|
2189
2204
|
}
|
|
2190
2205
|
if (options) helperOptions.set(name, options);
|
|
2191
2206
|
};
|
|
2192
|
-
const registerOperator = (helperName, symbol, position, precedence) => {
|
|
2207
|
+
const registerOperator = (helperName, symbol, position, precedence, options = {}) => {
|
|
2193
2208
|
var _a2;
|
|
2194
2209
|
if (!["prefix", "postfix", "infix"].includes(position)) {
|
|
2195
2210
|
throw new Error(`Invalid operator position: ${position}. Must be 'prefix', 'postfix', or 'infix'.`);
|
|
@@ -2198,7 +2213,7 @@
|
|
|
2198
2213
|
(_a2 = globalThis.console) == null ? void 0 : _a2.warn(`LightviewCDOM: Operator "${symbol}" registered for helper "${helperName}" which is not yet registered.`);
|
|
2199
2214
|
}
|
|
2200
2215
|
const prec = precedence ?? DEFAULT_PRECEDENCE[position];
|
|
2201
|
-
operators[position].set(symbol, { helper: helperName, precedence: prec });
|
|
2216
|
+
operators[position].set(symbol, { helper: helperName, precedence: prec, options });
|
|
2202
2217
|
};
|
|
2203
2218
|
const getLV = () => globalThis.Lightview || null;
|
|
2204
2219
|
const getRegistry = () => {
|
|
@@ -2260,12 +2275,13 @@
|
|
|
2260
2275
|
if (typeof path !== "string") return path;
|
|
2261
2276
|
const registry2 = getRegistry();
|
|
2262
2277
|
if (path === ".") return unwrapSignal(context);
|
|
2263
|
-
if (path.startsWith("=/")) {
|
|
2264
|
-
const
|
|
2278
|
+
if (path.startsWith("=/") || path.startsWith("/")) {
|
|
2279
|
+
const segments = path.startsWith("=/") ? path.slice(2).split("/") : path.slice(1).split("/");
|
|
2280
|
+
const rootName = segments.shift();
|
|
2265
2281
|
const LV = getLV();
|
|
2266
2282
|
const root = LV ? LV.get(rootName, { scope: (context == null ? void 0 : context.__node__) || context }) : registry2 == null ? void 0 : registry2.get(rootName);
|
|
2267
2283
|
if (!root) return void 0;
|
|
2268
|
-
return traverse(root,
|
|
2284
|
+
return traverse(root, segments);
|
|
2269
2285
|
}
|
|
2270
2286
|
if (path.startsWith("./")) {
|
|
2271
2287
|
return traverse(context, path.slice(2).split("/"));
|
|
@@ -2274,6 +2290,10 @@
|
|
|
2274
2290
|
return traverse(context == null ? void 0 : context.__parent__, path.slice(3).split("/"));
|
|
2275
2291
|
}
|
|
2276
2292
|
if (path.includes("/") || path.includes(".")) {
|
|
2293
|
+
const unwrapped = unwrapSignal(context);
|
|
2294
|
+
if (unwrapped && typeof unwrapped === "object" && path in unwrapped) {
|
|
2295
|
+
return unwrapSignal(unwrapped[path]);
|
|
2296
|
+
}
|
|
2277
2297
|
return traverse(context, path.split(/[\/.]/));
|
|
2278
2298
|
}
|
|
2279
2299
|
const unwrappedContext = unwrapSignal(context);
|
|
@@ -2288,8 +2308,8 @@
|
|
|
2288
2308
|
if (typeof path !== "string") return path;
|
|
2289
2309
|
const registry2 = getRegistry();
|
|
2290
2310
|
if (path === ".") return context;
|
|
2291
|
-
if (path.startsWith("=/")) {
|
|
2292
|
-
const segments = path.slice(2).split(/[/.]/);
|
|
2311
|
+
if (path.startsWith("=/") || path.startsWith("/")) {
|
|
2312
|
+
const segments = path.startsWith("=/") ? path.slice(2).split(/[/.]/) : path.slice(1).split(/[/.]/);
|
|
2293
2313
|
const rootName = segments.shift();
|
|
2294
2314
|
const LV = getLV();
|
|
2295
2315
|
const root = LV ? LV.get(rootName, { scope: (context == null ? void 0 : context.__node__) || context }) : registry2 == null ? void 0 : registry2.get(rootName);
|
|
@@ -2303,6 +2323,10 @@
|
|
|
2303
2323
|
return traverseAsContext(context == null ? void 0 : context.__parent__, path.slice(3).split(/[\/.]/));
|
|
2304
2324
|
}
|
|
2305
2325
|
if (path.includes("/") || path.includes(".")) {
|
|
2326
|
+
const unwrapped = unwrapSignal(context);
|
|
2327
|
+
if (unwrapped && typeof unwrapped === "object" && path in unwrapped) {
|
|
2328
|
+
return new BindingTarget(unwrapped, path);
|
|
2329
|
+
}
|
|
2306
2330
|
return traverseAsContext(context, path.split(/[\/.]/));
|
|
2307
2331
|
}
|
|
2308
2332
|
const unwrappedContext = unwrapSignal(context);
|
|
@@ -2371,7 +2395,7 @@
|
|
|
2371
2395
|
const resolveTemplate = (node, context2) => {
|
|
2372
2396
|
if (typeof node === "string") {
|
|
2373
2397
|
if (node.startsWith("=")) {
|
|
2374
|
-
const res = resolveExpression(node, context2);
|
|
2398
|
+
const res = resolveExpression$1(node, context2);
|
|
2375
2399
|
const final = res instanceof LazyValue ? res.resolve(context2) : res;
|
|
2376
2400
|
return unwrapSignal(final);
|
|
2377
2401
|
}
|
|
@@ -2427,7 +2451,7 @@
|
|
|
2427
2451
|
} else if (globalMode && !arg.startsWith("=") && !arg.startsWith("./")) {
|
|
2428
2452
|
nestedExpr = `=/${arg}`;
|
|
2429
2453
|
}
|
|
2430
|
-
const val = resolveExpression(nestedExpr, context);
|
|
2454
|
+
const val = resolveExpression$1(nestedExpr, context);
|
|
2431
2455
|
if (val instanceof LazyValue) {
|
|
2432
2456
|
return { value: val, isLazy: true };
|
|
2433
2457
|
}
|
|
@@ -2488,6 +2512,16 @@
|
|
|
2488
2512
|
// $this
|
|
2489
2513
|
EVENT: "EVENT",
|
|
2490
2514
|
// $event, $event.target
|
|
2515
|
+
LBRACE: "LBRACE",
|
|
2516
|
+
// {
|
|
2517
|
+
RBRACE: "RBRACE",
|
|
2518
|
+
// }
|
|
2519
|
+
LBRACKET: "LBRACKET",
|
|
2520
|
+
// [
|
|
2521
|
+
RBRACKET: "RBRACKET",
|
|
2522
|
+
// ]
|
|
2523
|
+
COLON: "COLON",
|
|
2524
|
+
// :
|
|
2491
2525
|
EOF: "EOF"
|
|
2492
2526
|
};
|
|
2493
2527
|
const getOperatorSymbols = () => {
|
|
@@ -2499,6 +2533,7 @@
|
|
|
2499
2533
|
return [...allOps].sort((a, b) => b.length - a.length);
|
|
2500
2534
|
};
|
|
2501
2535
|
const tokenize = (expr) => {
|
|
2536
|
+
var _a2, _b2;
|
|
2502
2537
|
const tokens = [];
|
|
2503
2538
|
let i = 0;
|
|
2504
2539
|
const len2 = expr.length;
|
|
@@ -2508,16 +2543,21 @@
|
|
|
2508
2543
|
i++;
|
|
2509
2544
|
continue;
|
|
2510
2545
|
}
|
|
2511
|
-
if (expr[i] === "=" && i + 1 < len2) {
|
|
2546
|
+
if (expr[i] === "=" && i === 0 && i + 1 < len2) {
|
|
2512
2547
|
const prefixOps = [...operators.prefix.keys()].sort((a, b) => b.length - a.length);
|
|
2513
|
-
let
|
|
2548
|
+
let matchedPrefix = null;
|
|
2514
2549
|
for (const op of prefixOps) {
|
|
2515
2550
|
if (expr.slice(i + 1, i + 1 + op.length) === op) {
|
|
2516
|
-
|
|
2551
|
+
matchedPrefix = op;
|
|
2517
2552
|
break;
|
|
2518
2553
|
}
|
|
2519
2554
|
}
|
|
2520
|
-
if (
|
|
2555
|
+
if (matchedPrefix) {
|
|
2556
|
+
i++;
|
|
2557
|
+
continue;
|
|
2558
|
+
}
|
|
2559
|
+
const next = expr[i + 1];
|
|
2560
|
+
if (next === "/" || next === "." || /[a-zA-Z_$]/.test(next)) {
|
|
2521
2561
|
i++;
|
|
2522
2562
|
continue;
|
|
2523
2563
|
}
|
|
@@ -2537,20 +2577,52 @@
|
|
|
2537
2577
|
i++;
|
|
2538
2578
|
continue;
|
|
2539
2579
|
}
|
|
2580
|
+
if (expr[i] === "{") {
|
|
2581
|
+
tokens.push({ type: TokenType.LBRACE, value: "{" });
|
|
2582
|
+
i++;
|
|
2583
|
+
continue;
|
|
2584
|
+
}
|
|
2585
|
+
if (expr[i] === "}") {
|
|
2586
|
+
tokens.push({ type: TokenType.RBRACE, value: "}" });
|
|
2587
|
+
i++;
|
|
2588
|
+
continue;
|
|
2589
|
+
}
|
|
2590
|
+
if (expr[i] === "[") {
|
|
2591
|
+
tokens.push({ type: TokenType.LBRACKET, value: "[" });
|
|
2592
|
+
i++;
|
|
2593
|
+
continue;
|
|
2594
|
+
}
|
|
2595
|
+
if (expr[i] === "]") {
|
|
2596
|
+
tokens.push({ type: TokenType.RBRACKET, value: "]" });
|
|
2597
|
+
i++;
|
|
2598
|
+
continue;
|
|
2599
|
+
}
|
|
2600
|
+
if (expr[i] === ":") {
|
|
2601
|
+
tokens.push({ type: TokenType.COLON, value: ":" });
|
|
2602
|
+
i++;
|
|
2603
|
+
continue;
|
|
2604
|
+
}
|
|
2540
2605
|
let matchedOp = null;
|
|
2541
2606
|
for (const op of opSymbols) {
|
|
2542
2607
|
if (expr.slice(i, i + op.length) === op) {
|
|
2543
2608
|
const before = i > 0 ? expr[i - 1] : " ";
|
|
2544
2609
|
const after = i + op.length < len2 ? expr[i + op.length] : " ";
|
|
2545
|
-
const
|
|
2546
|
-
const
|
|
2547
|
-
const
|
|
2548
|
-
if (
|
|
2549
|
-
if (
|
|
2610
|
+
const infixConf = operators.infix.get(op);
|
|
2611
|
+
const prefixConf = operators.prefix.get(op);
|
|
2612
|
+
const postfixConf = operators.postfix.get(op);
|
|
2613
|
+
if ((_a2 = infixConf == null ? void 0 : infixConf.options) == null ? void 0 : _a2.requiresWhitespace) {
|
|
2614
|
+
if (!prefixConf && !postfixConf) {
|
|
2615
|
+
const isWhitespaceMatch = /\s/.test(before) && /\s/.test(after);
|
|
2616
|
+
if (!isWhitespaceMatch) continue;
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
if (infixConf) {
|
|
2620
|
+
const lastTok = tokens[tokens.length - 1];
|
|
2621
|
+
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);
|
|
2622
|
+
if (isValueContext) {
|
|
2550
2623
|
matchedOp = op;
|
|
2551
2624
|
break;
|
|
2552
2625
|
}
|
|
2553
|
-
continue;
|
|
2554
2626
|
}
|
|
2555
2627
|
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;
|
|
2556
2628
|
const validAfter = /[\s(=./'"0-9_]/.test(after) || i + op.length >= len2 || opSymbols.some((o) => expr.slice(i + op.length).startsWith(o));
|
|
@@ -2635,16 +2707,18 @@
|
|
|
2635
2707
|
let isOp = false;
|
|
2636
2708
|
for (const op of opSymbols) {
|
|
2637
2709
|
if (expr.slice(i, i + op.length) === op) {
|
|
2638
|
-
const
|
|
2639
|
-
const
|
|
2640
|
-
const
|
|
2641
|
-
if (
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2710
|
+
const infixConf = operators.infix.get(op);
|
|
2711
|
+
const prefixConf = operators.prefix.get(op);
|
|
2712
|
+
const postfixConf = operators.postfix.get(op);
|
|
2713
|
+
if ((_b2 = infixConf == null ? void 0 : infixConf.options) == null ? void 0 : _b2.requiresWhitespace) {
|
|
2714
|
+
if (!prefixConf && !postfixConf) {
|
|
2715
|
+
const after = i + op.length < len2 ? expr[i + op.length] : " ";
|
|
2716
|
+
if (/\s/.test(expr[i - 1]) && /\s/.test(after)) {
|
|
2717
|
+
isOp = true;
|
|
2718
|
+
break;
|
|
2719
|
+
}
|
|
2720
|
+
continue;
|
|
2646
2721
|
}
|
|
2647
|
-
continue;
|
|
2648
2722
|
}
|
|
2649
2723
|
if (path.length > 0 && path[path.length - 1] !== "/") {
|
|
2650
2724
|
isOp = true;
|
|
@@ -2688,14 +2762,16 @@
|
|
|
2688
2762
|
};
|
|
2689
2763
|
const hasOperatorSyntax = (expr) => {
|
|
2690
2764
|
if (!expr || typeof expr !== "string") return false;
|
|
2691
|
-
if (
|
|
2692
|
-
if (/^=(\+\+|--|!!)\/?/.test(expr)) {
|
|
2765
|
+
if (/^=?(\+\+|--|!!)\/?/.test(expr)) {
|
|
2693
2766
|
return true;
|
|
2694
2767
|
}
|
|
2695
2768
|
if (/(\+\+|--)$/.test(expr)) {
|
|
2696
2769
|
return true;
|
|
2697
2770
|
}
|
|
2698
|
-
if (/\s+([
|
|
2771
|
+
if (/\s+([+\-*/%]|>|<|>=|<=|!=|===|==|=)\s+/.test(expr)) {
|
|
2772
|
+
return true;
|
|
2773
|
+
}
|
|
2774
|
+
if (/[^=\s]([+%=]|==|===|!=|!==|<=|>=|<|>)[^=\s]/.test(expr)) {
|
|
2699
2775
|
return true;
|
|
2700
2776
|
}
|
|
2701
2777
|
return false;
|
|
@@ -2807,15 +2883,71 @@
|
|
|
2807
2883
|
this.consume();
|
|
2808
2884
|
return { type: "Explosion", path: tok.value };
|
|
2809
2885
|
}
|
|
2886
|
+
if (nextTok.type === TokenType.LPAREN) {
|
|
2887
|
+
this.consume();
|
|
2888
|
+
const args = [];
|
|
2889
|
+
while (this.peek().type !== TokenType.RPAREN && this.peek().type !== TokenType.EOF) {
|
|
2890
|
+
args.push(this.parseExpression(0));
|
|
2891
|
+
if (this.peek().type === TokenType.COMMA) {
|
|
2892
|
+
this.consume();
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
this.expect(TokenType.RPAREN);
|
|
2896
|
+
return { type: "Call", helper: tok.value, args };
|
|
2897
|
+
}
|
|
2810
2898
|
return { type: "Path", value: tok.value };
|
|
2811
2899
|
}
|
|
2900
|
+
if (tok.type === TokenType.LBRACE) {
|
|
2901
|
+
return this.parseObjectLiteral();
|
|
2902
|
+
}
|
|
2903
|
+
if (tok.type === TokenType.LBRACKET) {
|
|
2904
|
+
return this.parseArrayLiteral();
|
|
2905
|
+
}
|
|
2812
2906
|
if (tok.type === TokenType.EOF) {
|
|
2813
2907
|
return { type: "Literal", value: void 0 };
|
|
2814
2908
|
}
|
|
2815
2909
|
throw new Error(`JPRX: Unexpected token ${tok.type}: ${tok.value}`);
|
|
2816
2910
|
}
|
|
2911
|
+
parseObjectLiteral() {
|
|
2912
|
+
this.consume();
|
|
2913
|
+
const properties = {};
|
|
2914
|
+
while (this.peek().type !== TokenType.RBRACE && this.peek().type !== TokenType.EOF) {
|
|
2915
|
+
const keyTok = this.consume();
|
|
2916
|
+
let key;
|
|
2917
|
+
if (keyTok.type === TokenType.LITERAL) key = String(keyTok.value);
|
|
2918
|
+
else if (keyTok.type === TokenType.PATH) key = keyTok.value;
|
|
2919
|
+
else if (keyTok.type === TokenType.PATH) key = keyTok.value;
|
|
2920
|
+
else throw new Error(`JPRX: Expected property name but got ${keyTok.type}`);
|
|
2921
|
+
this.expect(TokenType.COLON);
|
|
2922
|
+
const value = this.parseExpression(0);
|
|
2923
|
+
properties[key] = value;
|
|
2924
|
+
if (this.peek().type === TokenType.COMMA) {
|
|
2925
|
+
this.consume();
|
|
2926
|
+
} else if (this.peek().type !== TokenType.RBRACE) {
|
|
2927
|
+
break;
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
this.expect(TokenType.RBRACE);
|
|
2931
|
+
return { type: "ObjectLiteral", properties };
|
|
2932
|
+
}
|
|
2933
|
+
parseArrayLiteral() {
|
|
2934
|
+
this.consume();
|
|
2935
|
+
const elements = [];
|
|
2936
|
+
while (this.peek().type !== TokenType.RBRACKET && this.peek().type !== TokenType.EOF) {
|
|
2937
|
+
const value = this.parseExpression(0);
|
|
2938
|
+
elements.push(value);
|
|
2939
|
+
if (this.peek().type === TokenType.COMMA) {
|
|
2940
|
+
this.consume();
|
|
2941
|
+
} else if (this.peek().type !== TokenType.RBRACKET) {
|
|
2942
|
+
break;
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
this.expect(TokenType.RBRACKET);
|
|
2946
|
+
return { type: "ArrayLiteral", elements };
|
|
2947
|
+
}
|
|
2817
2948
|
}
|
|
2818
2949
|
const evaluateAST = (ast, context, forMutation = false) => {
|
|
2950
|
+
var _a2;
|
|
2819
2951
|
if (!ast) return void 0;
|
|
2820
2952
|
switch (ast.type) {
|
|
2821
2953
|
case "Literal":
|
|
@@ -2847,54 +2979,126 @@
|
|
|
2847
2979
|
return resolvePath(path, event);
|
|
2848
2980
|
});
|
|
2849
2981
|
}
|
|
2850
|
-
case "
|
|
2851
|
-
const
|
|
2852
|
-
|
|
2982
|
+
case "ObjectLiteral": {
|
|
2983
|
+
const res = {};
|
|
2984
|
+
let hasLazy = false;
|
|
2985
|
+
for (const key in ast.properties) {
|
|
2986
|
+
const val = evaluateAST(ast.properties[key], context, forMutation);
|
|
2987
|
+
if (val && val.isLazy) hasLazy = true;
|
|
2988
|
+
res[key] = val;
|
|
2989
|
+
}
|
|
2990
|
+
if (hasLazy) {
|
|
2991
|
+
return new LazyValue((ctx) => {
|
|
2992
|
+
const resolved = {};
|
|
2993
|
+
for (const key in res) {
|
|
2994
|
+
resolved[key] = res[key] && res[key].isLazy ? res[key].resolve(ctx) : unwrapSignal(res[key]);
|
|
2995
|
+
}
|
|
2996
|
+
return resolved;
|
|
2997
|
+
});
|
|
2998
|
+
}
|
|
2999
|
+
return res;
|
|
3000
|
+
}
|
|
3001
|
+
case "ArrayLiteral": {
|
|
3002
|
+
const elements = ast.elements.map((el) => evaluateAST(el, context, forMutation));
|
|
3003
|
+
const hasLazy = elements.some((el) => el && el.isLazy);
|
|
3004
|
+
if (hasLazy) {
|
|
3005
|
+
return new LazyValue((ctx) => {
|
|
3006
|
+
return elements.map((el) => el && el.isLazy ? el.resolve(ctx) : unwrapSignal(el));
|
|
3007
|
+
});
|
|
3008
|
+
}
|
|
3009
|
+
return elements.map((el) => unwrapSignal(el));
|
|
2853
3010
|
}
|
|
2854
3011
|
case "Prefix": {
|
|
2855
3012
|
const opInfo = operators.prefix.get(ast.operator);
|
|
2856
|
-
if (!opInfo) {
|
|
2857
|
-
throw new Error(`JPRX: Unknown prefix operator: ${ast.operator}`);
|
|
2858
|
-
}
|
|
3013
|
+
if (!opInfo) throw new Error(`JPRX: Unknown prefix operator: ${ast.operator}`);
|
|
2859
3014
|
const helper = helpers.get(opInfo.helper);
|
|
2860
|
-
if (!helper) {
|
|
2861
|
-
throw new Error(`JPRX: Helper "${opInfo.helper}" for operator "${ast.operator}" not found.`);
|
|
2862
|
-
}
|
|
3015
|
+
if (!helper) throw new Error(`JPRX: Helper "${opInfo.helper}" for operator "${ast.operator}" not found.`);
|
|
2863
3016
|
const opts = helperOptions.get(opInfo.helper) || {};
|
|
2864
3017
|
const operand = evaluateAST(ast.operand, context, opts.pathAware);
|
|
2865
|
-
|
|
3018
|
+
if (operand && operand.isLazy && !opts.lazyAware) {
|
|
3019
|
+
return new LazyValue((ctx) => {
|
|
3020
|
+
const resolved = operand.resolve(ctx);
|
|
3021
|
+
return helper(opts.pathAware ? resolved : unwrapSignal(resolved));
|
|
3022
|
+
});
|
|
3023
|
+
}
|
|
3024
|
+
return helper(opts.pathAware ? operand : unwrapSignal(operand));
|
|
2866
3025
|
}
|
|
2867
3026
|
case "Postfix": {
|
|
2868
3027
|
const opInfo = operators.postfix.get(ast.operator);
|
|
2869
|
-
if (!opInfo) {
|
|
2870
|
-
throw new Error(`JPRX: Unknown postfix operator: ${ast.operator}`);
|
|
2871
|
-
}
|
|
3028
|
+
if (!opInfo) throw new Error(`JPRX: Unknown postfix operator: ${ast.operator}`);
|
|
2872
3029
|
const helper = helpers.get(opInfo.helper);
|
|
2873
|
-
if (!helper) {
|
|
2874
|
-
throw new Error(`JPRX: Helper "${opInfo.helper}" for operator "${ast.operator}" not found.`);
|
|
2875
|
-
}
|
|
3030
|
+
if (!helper) throw new Error(`JPRX: Helper "${opInfo.helper}" for operator "${ast.operator}" not found.`);
|
|
2876
3031
|
const opts = helperOptions.get(opInfo.helper) || {};
|
|
2877
3032
|
const operand = evaluateAST(ast.operand, context, opts.pathAware);
|
|
2878
|
-
|
|
3033
|
+
if (operand && operand.isLazy && !opts.lazyAware) {
|
|
3034
|
+
return new LazyValue((ctx) => {
|
|
3035
|
+
const resolved = operand.resolve(ctx);
|
|
3036
|
+
return helper(opts.pathAware ? resolved : unwrapSignal(resolved));
|
|
3037
|
+
});
|
|
3038
|
+
}
|
|
3039
|
+
return helper(opts.pathAware ? operand : unwrapSignal(operand));
|
|
2879
3040
|
}
|
|
2880
3041
|
case "Infix": {
|
|
2881
3042
|
const opInfo = operators.infix.get(ast.operator);
|
|
2882
|
-
if (!opInfo) {
|
|
2883
|
-
throw new Error(`JPRX: Unknown infix operator: ${ast.operator}`);
|
|
2884
|
-
}
|
|
3043
|
+
if (!opInfo) throw new Error(`JPRX: Unknown infix operator: ${ast.operator}`);
|
|
2885
3044
|
const helper = helpers.get(opInfo.helper);
|
|
2886
|
-
if (!helper) {
|
|
2887
|
-
throw new Error(`JPRX: Helper "${opInfo.helper}" for operator "${ast.operator}" not found.`);
|
|
2888
|
-
}
|
|
3045
|
+
if (!helper) throw new Error(`JPRX: Helper "${opInfo.helper}" for operator "${ast.operator}" not found.`);
|
|
2889
3046
|
const opts = helperOptions.get(opInfo.helper) || {};
|
|
2890
3047
|
const left = evaluateAST(ast.left, context, opts.pathAware);
|
|
2891
3048
|
const right = evaluateAST(ast.right, context, false);
|
|
3049
|
+
if ((left && left.isLazy || right && right.isLazy) && !opts.lazyAware) {
|
|
3050
|
+
return new LazyValue((ctx) => {
|
|
3051
|
+
const l = left && left.isLazy ? left.resolve(ctx) : left;
|
|
3052
|
+
const r = right && right.isLazy ? right.resolve(ctx) : right;
|
|
3053
|
+
return helper(opts.pathAware ? l : unwrapSignal(l), unwrapSignal(r));
|
|
3054
|
+
});
|
|
3055
|
+
}
|
|
3056
|
+
return helper(opts.pathAware ? left : unwrapSignal(left), unwrapSignal(right));
|
|
3057
|
+
}
|
|
3058
|
+
case "Call": {
|
|
3059
|
+
const helperName = ast.helper.replace(/^=/, "");
|
|
3060
|
+
const helper = helpers.get(helperName);
|
|
3061
|
+
if (!helper) {
|
|
3062
|
+
(_a2 = globalThis.console) == null ? void 0 : _a2.warn(`JPRX: Helper "${helperName}" not found.`);
|
|
3063
|
+
return void 0;
|
|
3064
|
+
}
|
|
3065
|
+
const opts = helperOptions.get(helperName) || {};
|
|
3066
|
+
const args = ast.args.map((arg, i) => evaluateAST(arg, context, opts.pathAware && i === 0));
|
|
3067
|
+
const hasLazy = args.some((arg) => arg && arg.isLazy);
|
|
3068
|
+
if (hasLazy && !opts.lazyAware) {
|
|
3069
|
+
return new LazyValue((ctx) => {
|
|
3070
|
+
const finalArgs2 = args.map((arg, i) => {
|
|
3071
|
+
const val = arg && arg.isLazy ? arg.resolve(ctx) : arg;
|
|
3072
|
+
if (ast.args[i].type === "Explosion" && Array.isArray(val)) {
|
|
3073
|
+
return val.map((v) => unwrapSignal(v));
|
|
3074
|
+
}
|
|
3075
|
+
return opts.pathAware && i === 0 ? val : unwrapSignal(val);
|
|
3076
|
+
});
|
|
3077
|
+
const flatArgs = [];
|
|
3078
|
+
for (let i = 0; i < finalArgs2.length; i++) {
|
|
3079
|
+
if (ast.args[i].type === "Explosion" && Array.isArray(finalArgs2[i])) {
|
|
3080
|
+
flatArgs.push(...finalArgs2[i]);
|
|
3081
|
+
} else {
|
|
3082
|
+
flatArgs.push(finalArgs2[i]);
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
return helper.apply((context == null ? void 0 : context.__node__) || null, flatArgs);
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
2892
3088
|
const finalArgs = [];
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
3089
|
+
for (let i = 0; i < args.length; i++) {
|
|
3090
|
+
const arg = args[i];
|
|
3091
|
+
if (ast.args[i].type === "Explosion" && Array.isArray(arg)) {
|
|
3092
|
+
finalArgs.push(...arg.map((v) => unwrapSignal(v)));
|
|
3093
|
+
} else {
|
|
3094
|
+
finalArgs.push(opts.pathAware && i === 0 ? arg : unwrapSignal(arg));
|
|
3095
|
+
}
|
|
3096
|
+
}
|
|
3097
|
+
return helper.apply((context == null ? void 0 : context.__node__) || null, finalArgs);
|
|
3098
|
+
}
|
|
3099
|
+
case "Explosion": {
|
|
3100
|
+
const result = resolveArgument(ast.path + "...", context, false);
|
|
3101
|
+
return result.value;
|
|
2898
3102
|
}
|
|
2899
3103
|
default:
|
|
2900
3104
|
throw new Error(`JPRX: Unknown AST node type: ${ast.type}`);
|
|
@@ -2906,7 +3110,7 @@
|
|
|
2906
3110
|
const ast = parser.parseExpression(0);
|
|
2907
3111
|
return evaluateAST(ast, context);
|
|
2908
3112
|
};
|
|
2909
|
-
const resolveExpression = (expr, context) => {
|
|
3113
|
+
const resolveExpression$1 = (expr, context) => {
|
|
2910
3114
|
var _a2, _b2;
|
|
2911
3115
|
if (typeof expr !== "string") return expr;
|
|
2912
3116
|
if (hasOperatorSyntax(expr)) {
|
|
@@ -2993,7 +3197,7 @@
|
|
|
2993
3197
|
const parseExpression = (expr, context) => {
|
|
2994
3198
|
const LV = getLV();
|
|
2995
3199
|
if (!LV || typeof expr !== "string") return expr;
|
|
2996
|
-
return LV.computed(() => resolveExpression(expr, context));
|
|
3200
|
+
return LV.computed(() => resolveExpression$1(expr, context));
|
|
2997
3201
|
};
|
|
2998
3202
|
const parseCDOMC = (input) => {
|
|
2999
3203
|
let i = 0;
|
|
@@ -3052,10 +3256,12 @@
|
|
|
3052
3256
|
let bDepth = 0;
|
|
3053
3257
|
let brDepth = 0;
|
|
3054
3258
|
let quote = null;
|
|
3259
|
+
const startChar = input[start];
|
|
3260
|
+
const isExpression = startChar === "=" || startChar === "#";
|
|
3055
3261
|
while (i < len2) {
|
|
3056
3262
|
const char = input[i];
|
|
3057
3263
|
if (quote) {
|
|
3058
|
-
if (char === quote) quote = null;
|
|
3264
|
+
if (char === quote && input[i - 1] !== "\\") quote = null;
|
|
3059
3265
|
i++;
|
|
3060
3266
|
continue;
|
|
3061
3267
|
} else if (char === '"' || char === "'" || char === "`") {
|
|
@@ -3100,14 +3306,41 @@
|
|
|
3100
3306
|
}
|
|
3101
3307
|
}
|
|
3102
3308
|
if (pDepth === 0 && bDepth === 0 && brDepth === 0) {
|
|
3103
|
-
if (
|
|
3104
|
-
|
|
3309
|
+
if (isExpression) {
|
|
3310
|
+
if (/[{}[\]"'`()]/.test(char)) {
|
|
3311
|
+
break;
|
|
3312
|
+
}
|
|
3313
|
+
if (char === ",") {
|
|
3314
|
+
break;
|
|
3315
|
+
}
|
|
3316
|
+
if (/[\s:]/.test(char)) {
|
|
3317
|
+
let j = i + 1;
|
|
3318
|
+
while (j < len2 && /\s/.test(input[j])) j++;
|
|
3319
|
+
if (j < len2) {
|
|
3320
|
+
const nextChar = input[j];
|
|
3321
|
+
if (nextChar === "}" || nextChar === ",") {
|
|
3322
|
+
break;
|
|
3323
|
+
}
|
|
3324
|
+
let wordStart = j;
|
|
3325
|
+
while (j < len2 && /[a-zA-Z0-9_$-]/.test(input[j])) j++;
|
|
3326
|
+
if (j > wordStart) {
|
|
3327
|
+
while (j < len2 && /\s/.test(input[j])) j++;
|
|
3328
|
+
if (j < len2 && input[j] === ":") {
|
|
3329
|
+
break;
|
|
3330
|
+
}
|
|
3331
|
+
}
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
} else {
|
|
3335
|
+
if (/[:,{}[\]"'`()\s]/.test(char)) {
|
|
3336
|
+
break;
|
|
3337
|
+
}
|
|
3105
3338
|
}
|
|
3106
3339
|
}
|
|
3107
3340
|
i++;
|
|
3108
3341
|
}
|
|
3109
3342
|
const word = input.slice(start, i);
|
|
3110
|
-
if (word.startsWith("=")) {
|
|
3343
|
+
if (word.startsWith("=") || word.startsWith("#")) {
|
|
3111
3344
|
return word;
|
|
3112
3345
|
}
|
|
3113
3346
|
if (word === "true") return true;
|
|
@@ -3259,7 +3492,26 @@
|
|
|
3259
3492
|
inExprQuote = c;
|
|
3260
3493
|
} else {
|
|
3261
3494
|
if (parenDepth === 0 && braceDepth === 0 && bracketDepth === 0) {
|
|
3262
|
-
if (/[
|
|
3495
|
+
if (/[}[\]:]/.test(c) && expr.length > 1) break;
|
|
3496
|
+
if (c === ",") break;
|
|
3497
|
+
if (/\s/.test(c)) {
|
|
3498
|
+
let j = i + 1;
|
|
3499
|
+
while (j < len2 && /\s/.test(input[j])) j++;
|
|
3500
|
+
if (j < len2) {
|
|
3501
|
+
const nextChar = input[j];
|
|
3502
|
+
if (nextChar === "}" || nextChar === "," || nextChar === "]") {
|
|
3503
|
+
break;
|
|
3504
|
+
}
|
|
3505
|
+
let wordStart = j;
|
|
3506
|
+
while (j < len2 && /[a-zA-Z0-9_$-]/.test(input[j])) j++;
|
|
3507
|
+
if (j > wordStart) {
|
|
3508
|
+
while (j < len2 && /\s/.test(input[j])) j++;
|
|
3509
|
+
if (j < len2 && input[j] === ":") {
|
|
3510
|
+
break;
|
|
3511
|
+
}
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3263
3515
|
}
|
|
3264
3516
|
if (c === "(") parenDepth++;
|
|
3265
3517
|
else if (c === ")") parenDepth--;
|
|
@@ -3284,6 +3536,32 @@
|
|
|
3284
3536
|
while (j < len2 && /\s/.test(input[j])) j++;
|
|
3285
3537
|
if (input[j] === ":") {
|
|
3286
3538
|
result += `"${word}"`;
|
|
3539
|
+
} else if (input[j] === "(") {
|
|
3540
|
+
let expr = word;
|
|
3541
|
+
i = j;
|
|
3542
|
+
let parenDepth = 0;
|
|
3543
|
+
let inQuote = null;
|
|
3544
|
+
while (i < len2) {
|
|
3545
|
+
const c = input[i];
|
|
3546
|
+
if (inQuote) {
|
|
3547
|
+
if (c === inQuote && input[i - 1] !== "\\") inQuote = null;
|
|
3548
|
+
} else if (c === '"' || c === "'") {
|
|
3549
|
+
inQuote = c;
|
|
3550
|
+
} else {
|
|
3551
|
+
if (c === "(") parenDepth++;
|
|
3552
|
+
else if (c === ")") {
|
|
3553
|
+
parenDepth--;
|
|
3554
|
+
if (parenDepth === 0) {
|
|
3555
|
+
expr += c;
|
|
3556
|
+
i++;
|
|
3557
|
+
break;
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
expr += c;
|
|
3562
|
+
i++;
|
|
3563
|
+
}
|
|
3564
|
+
result += JSON.stringify("=" + expr);
|
|
3287
3565
|
} else {
|
|
3288
3566
|
if (word === "true" || word === "false" || word === "null") {
|
|
3289
3567
|
result += word;
|
|
@@ -3315,7 +3593,7 @@
|
|
|
3315
3593
|
throw e;
|
|
3316
3594
|
}
|
|
3317
3595
|
};
|
|
3318
|
-
const add = (...args) => args.reduce((a, b) => Number(a) + Number(b), 0);
|
|
3596
|
+
const add$1 = (...args) => args.reduce((a, b) => Number(a) + Number(b), 0);
|
|
3319
3597
|
const subtract = (a, b) => Number(a) - Number(b);
|
|
3320
3598
|
const multiply = (...args) => args.reduce((a, b) => Number(a) * Number(b), 1);
|
|
3321
3599
|
const divide = (a, b) => Number(a) / Number(b);
|
|
@@ -3323,12 +3601,14 @@
|
|
|
3323
3601
|
const ceil = (val) => Math.ceil(val);
|
|
3324
3602
|
const floor = (val) => Math.floor(val);
|
|
3325
3603
|
const abs = (val) => Math.abs(val);
|
|
3326
|
-
const mod = (a, b) => a % b;
|
|
3604
|
+
const mod$1 = (a, b) => a % b;
|
|
3327
3605
|
const pow = (a, b) => Math.pow(a, b);
|
|
3328
3606
|
const sqrt = (val) => Math.sqrt(val);
|
|
3607
|
+
const negate = (val) => -Number(val);
|
|
3608
|
+
const toPercent = (val) => Number(val) / 100;
|
|
3329
3609
|
const registerMathHelpers = (register) => {
|
|
3330
|
-
register("+", add);
|
|
3331
|
-
register("add", add);
|
|
3610
|
+
register("+", add$1);
|
|
3611
|
+
register("add", add$1);
|
|
3332
3612
|
register("-", subtract);
|
|
3333
3613
|
register("sub", subtract);
|
|
3334
3614
|
register("*", multiply);
|
|
@@ -3339,16 +3619,20 @@
|
|
|
3339
3619
|
register("ceil", ceil);
|
|
3340
3620
|
register("floor", floor);
|
|
3341
3621
|
register("abs", abs);
|
|
3342
|
-
register("mod", mod);
|
|
3622
|
+
register("mod", mod$1);
|
|
3343
3623
|
register("pow", pow);
|
|
3344
3624
|
register("sqrt", sqrt);
|
|
3625
|
+
register("negate", negate);
|
|
3626
|
+
register("toPercent", toPercent);
|
|
3345
3627
|
};
|
|
3346
|
-
const ifHelper = (
|
|
3628
|
+
const ifHelper = (condition2, thenVal, elseVal) => condition2 ? thenVal : elseVal;
|
|
3347
3629
|
const andHelper = (...args) => args.every(Boolean);
|
|
3348
3630
|
const orHelper = (...args) => args.some(Boolean);
|
|
3349
3631
|
const notHelper = (val) => !val;
|
|
3350
|
-
const eqHelper = (a, b) => a
|
|
3351
|
-
const
|
|
3632
|
+
const eqHelper = (a, b) => a == b;
|
|
3633
|
+
const strictEqHelper = (a, b) => a === b;
|
|
3634
|
+
const neqHelper = (a, b) => a != b;
|
|
3635
|
+
const strictNeqHelper = (a, b) => a !== b;
|
|
3352
3636
|
const registerLogicHelpers = (register) => {
|
|
3353
3637
|
register("if", ifHelper);
|
|
3354
3638
|
register("and", andHelper);
|
|
@@ -3358,16 +3642,20 @@
|
|
|
3358
3642
|
register("not", notHelper);
|
|
3359
3643
|
register("!", notHelper);
|
|
3360
3644
|
register("eq", eqHelper);
|
|
3645
|
+
register("strictEq", strictEqHelper);
|
|
3361
3646
|
register("==", eqHelper);
|
|
3362
|
-
register("===",
|
|
3647
|
+
register("===", strictEqHelper);
|
|
3363
3648
|
register("neq", neqHelper);
|
|
3649
|
+
register("strictNeq", strictNeqHelper);
|
|
3650
|
+
register("!=", neqHelper);
|
|
3651
|
+
register("!==", strictNeqHelper);
|
|
3364
3652
|
};
|
|
3365
3653
|
const join$1 = (...args) => {
|
|
3366
3654
|
const separator = args[args.length - 1];
|
|
3367
3655
|
const items = args.slice(0, -1);
|
|
3368
3656
|
return items.join(separator);
|
|
3369
3657
|
};
|
|
3370
|
-
const concat = (...args) => args.join("");
|
|
3658
|
+
const concat$1 = (...args) => args.join("");
|
|
3371
3659
|
const upper = (s) => String(s).toUpperCase();
|
|
3372
3660
|
const lower = (s) => String(s).toLowerCase();
|
|
3373
3661
|
const trim = (s) => String(s).trim();
|
|
@@ -3381,13 +3669,13 @@
|
|
|
3381
3669
|
const titleCase = (s) => {
|
|
3382
3670
|
return String(s).toLowerCase().split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3383
3671
|
};
|
|
3384
|
-
const contains$
|
|
3672
|
+
const contains$2 = (s, search) => String(s).includes(search);
|
|
3385
3673
|
const startsWith = (s, prefix) => String(s).startsWith(prefix);
|
|
3386
3674
|
const endsWith = (s, suffix) => String(s).endsWith(suffix);
|
|
3387
3675
|
const defaultHelper = (val, fallback) => val !== void 0 && val !== null ? val : fallback;
|
|
3388
3676
|
const registerStringHelpers = (register) => {
|
|
3389
3677
|
register("join", join$1);
|
|
3390
|
-
register("concat", concat);
|
|
3678
|
+
register("concat", concat$1);
|
|
3391
3679
|
register("upper", upper);
|
|
3392
3680
|
register("lower", lower);
|
|
3393
3681
|
register("trim", trim);
|
|
@@ -3396,7 +3684,7 @@
|
|
|
3396
3684
|
register("split", split);
|
|
3397
3685
|
register("capitalize", capitalize);
|
|
3398
3686
|
register("titleCase", titleCase);
|
|
3399
|
-
register("contains", contains$
|
|
3687
|
+
register("contains", contains$2);
|
|
3400
3688
|
register("startsWith", startsWith);
|
|
3401
3689
|
register("endsWith", endsWith);
|
|
3402
3690
|
register("default", defaultHelper);
|
|
@@ -3469,7 +3757,7 @@
|
|
|
3469
3757
|
const lte = (a, b) => a <= b;
|
|
3470
3758
|
const neq = (a, b) => a !== b;
|
|
3471
3759
|
const between = (val, min2, max2) => val >= min2 && val <= max2;
|
|
3472
|
-
const contains = (arr, val) => Array.isArray(arr) && arr.includes(val);
|
|
3760
|
+
const contains$1 = (arr, val) => Array.isArray(arr) && arr.includes(val);
|
|
3473
3761
|
const registerCompareHelpers = (register) => {
|
|
3474
3762
|
register("gt", gt);
|
|
3475
3763
|
register(">", gt);
|
|
@@ -3482,7 +3770,7 @@
|
|
|
3482
3770
|
register("neq", neq);
|
|
3483
3771
|
register("!=", neq);
|
|
3484
3772
|
register("between", between);
|
|
3485
|
-
register("in", contains);
|
|
3773
|
+
register("in", contains$1);
|
|
3486
3774
|
};
|
|
3487
3775
|
const sumIf = (arr, predicate) => {
|
|
3488
3776
|
if (!Array.isArray(arr)) return 0;
|
|
@@ -3573,16 +3861,35 @@
|
|
|
3573
3861
|
};
|
|
3574
3862
|
const index = (arr, idx) => Array.isArray(arr) ? arr[idx] : void 0;
|
|
3575
3863
|
const match = (val, arr) => Array.isArray(arr) ? arr.indexOf(val) : -1;
|
|
3864
|
+
const pathRef = (path, context) => {
|
|
3865
|
+
if (path && typeof path === "object" && "value" in path) {
|
|
3866
|
+
return unwrapSignal(path.value);
|
|
3867
|
+
}
|
|
3868
|
+
if (typeof path === "string") {
|
|
3869
|
+
const normalized = path.startsWith("=") ? path : "=" + path;
|
|
3870
|
+
const resolved = resolvePath(normalized, context);
|
|
3871
|
+
const value = unwrapSignal(resolved);
|
|
3872
|
+
if (typeof value === "number") return value;
|
|
3873
|
+
if (typeof value === "string" && value !== "" && !isNaN(parseFloat(value)) && isFinite(Number(value))) {
|
|
3874
|
+
return parseFloat(value);
|
|
3875
|
+
}
|
|
3876
|
+
return value;
|
|
3877
|
+
}
|
|
3878
|
+
return unwrapSignal(path);
|
|
3879
|
+
};
|
|
3576
3880
|
const registerLookupHelpers = (register) => {
|
|
3577
3881
|
register("lookup", lookup);
|
|
3578
3882
|
register("vlookup", vlookup);
|
|
3579
3883
|
register("index", index);
|
|
3580
3884
|
register("match", match);
|
|
3885
|
+
register("$", pathRef, { pathAware: true });
|
|
3886
|
+
register("val", pathRef, { pathAware: true });
|
|
3887
|
+
register("indirect", pathRef, { pathAware: true });
|
|
3581
3888
|
};
|
|
3582
3889
|
const sum = (...args) => args.reduce((a, b) => a + (Number(b) || 0), 0);
|
|
3583
3890
|
const avg = (...args) => args.length === 0 ? 0 : sum(...args) / args.length;
|
|
3584
|
-
const min = (...args) => Math.min(...args);
|
|
3585
|
-
const max = (...args) => Math.max(...args);
|
|
3891
|
+
const min$1 = (...args) => Math.min(...args);
|
|
3892
|
+
const max$1 = (...args) => Math.max(...args);
|
|
3586
3893
|
const median = (...args) => {
|
|
3587
3894
|
if (args.length === 0) return 0;
|
|
3588
3895
|
const sorted = [...args].sort((a, b) => a - b);
|
|
@@ -3604,8 +3911,8 @@
|
|
|
3604
3911
|
const registerStatsHelpers = (register) => {
|
|
3605
3912
|
register("sum", sum);
|
|
3606
3913
|
register("avg", avg);
|
|
3607
|
-
register("min", min);
|
|
3608
|
-
register("max", max);
|
|
3914
|
+
register("min", min$1);
|
|
3915
|
+
register("max", max$1);
|
|
3609
3916
|
register("median", median);
|
|
3610
3917
|
register("stdev", stdev);
|
|
3611
3918
|
register("var", variance);
|
|
@@ -3720,100 +4027,1796 @@
|
|
|
3720
4027
|
const registerNetworkHelpers = (register) => {
|
|
3721
4028
|
register("fetch", fetchHelper);
|
|
3722
4029
|
};
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
4030
|
+
var INUMBER = "INUMBER";
|
|
4031
|
+
var IOP1 = "IOP1";
|
|
4032
|
+
var IOP2 = "IOP2";
|
|
4033
|
+
var IOP3 = "IOP3";
|
|
4034
|
+
var IVAR = "IVAR";
|
|
4035
|
+
var IVARNAME = "IVARNAME";
|
|
4036
|
+
var IFUNCALL = "IFUNCALL";
|
|
4037
|
+
var IFUNDEF = "IFUNDEF";
|
|
4038
|
+
var IEXPR = "IEXPR";
|
|
4039
|
+
var IEXPREVAL = "IEXPREVAL";
|
|
4040
|
+
var IMEMBER = "IMEMBER";
|
|
4041
|
+
var IENDSTATEMENT = "IENDSTATEMENT";
|
|
4042
|
+
var IARRAY = "IARRAY";
|
|
4043
|
+
function Instruction(type, value) {
|
|
4044
|
+
this.type = type;
|
|
4045
|
+
this.value = value !== void 0 && value !== null ? value : 0;
|
|
4046
|
+
}
|
|
4047
|
+
Instruction.prototype.toString = function() {
|
|
4048
|
+
switch (this.type) {
|
|
4049
|
+
case INUMBER:
|
|
4050
|
+
case IOP1:
|
|
4051
|
+
case IOP2:
|
|
4052
|
+
case IOP3:
|
|
4053
|
+
case IVAR:
|
|
4054
|
+
case IVARNAME:
|
|
4055
|
+
case IENDSTATEMENT:
|
|
4056
|
+
return this.value;
|
|
4057
|
+
case IFUNCALL:
|
|
4058
|
+
return "CALL " + this.value;
|
|
4059
|
+
case IFUNDEF:
|
|
4060
|
+
return "DEF " + this.value;
|
|
4061
|
+
case IARRAY:
|
|
4062
|
+
return "ARRAY " + this.value;
|
|
4063
|
+
case IMEMBER:
|
|
4064
|
+
return "." + this.value;
|
|
4065
|
+
default:
|
|
4066
|
+
return "Invalid Instruction";
|
|
4067
|
+
}
|
|
4068
|
+
};
|
|
4069
|
+
function unaryInstruction(value) {
|
|
4070
|
+
return new Instruction(IOP1, value);
|
|
4071
|
+
}
|
|
4072
|
+
function binaryInstruction(value) {
|
|
4073
|
+
return new Instruction(IOP2, value);
|
|
4074
|
+
}
|
|
4075
|
+
function ternaryInstruction(value) {
|
|
4076
|
+
return new Instruction(IOP3, value);
|
|
4077
|
+
}
|
|
4078
|
+
function simplify(tokens, unaryOps, binaryOps, ternaryOps, values) {
|
|
4079
|
+
var nstack = [];
|
|
4080
|
+
var newexpression = [];
|
|
4081
|
+
var n1, n2, n3;
|
|
4082
|
+
var f;
|
|
4083
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
4084
|
+
var item = tokens[i];
|
|
4085
|
+
var type = item.type;
|
|
4086
|
+
if (type === INUMBER || type === IVARNAME) {
|
|
4087
|
+
if (Array.isArray(item.value)) {
|
|
4088
|
+
nstack.push.apply(nstack, simplify(item.value.map(function(x) {
|
|
4089
|
+
return new Instruction(INUMBER, x);
|
|
4090
|
+
}).concat(new Instruction(IARRAY, item.value.length)), unaryOps, binaryOps, ternaryOps, values));
|
|
4091
|
+
} else {
|
|
4092
|
+
nstack.push(item);
|
|
3746
4093
|
}
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
4094
|
+
} else if (type === IVAR && values.hasOwnProperty(item.value)) {
|
|
4095
|
+
item = new Instruction(INUMBER, values[item.value]);
|
|
4096
|
+
nstack.push(item);
|
|
4097
|
+
} else if (type === IOP2 && nstack.length > 1) {
|
|
4098
|
+
n2 = nstack.pop();
|
|
4099
|
+
n1 = nstack.pop();
|
|
4100
|
+
f = binaryOps[item.value];
|
|
4101
|
+
item = new Instruction(INUMBER, f(n1.value, n2.value));
|
|
4102
|
+
nstack.push(item);
|
|
4103
|
+
} else if (type === IOP3 && nstack.length > 2) {
|
|
4104
|
+
n3 = nstack.pop();
|
|
4105
|
+
n2 = nstack.pop();
|
|
4106
|
+
n1 = nstack.pop();
|
|
4107
|
+
if (item.value === "?") {
|
|
4108
|
+
nstack.push(n1.value ? n2.value : n3.value);
|
|
4109
|
+
} else {
|
|
4110
|
+
f = ternaryOps[item.value];
|
|
4111
|
+
item = new Instruction(INUMBER, f(n1.value, n2.value, n3.value));
|
|
4112
|
+
nstack.push(item);
|
|
4113
|
+
}
|
|
4114
|
+
} else if (type === IOP1 && nstack.length > 0) {
|
|
4115
|
+
n1 = nstack.pop();
|
|
4116
|
+
f = unaryOps[item.value];
|
|
4117
|
+
item = new Instruction(INUMBER, f(n1.value));
|
|
4118
|
+
nstack.push(item);
|
|
4119
|
+
} else if (type === IEXPR) {
|
|
4120
|
+
while (nstack.length > 0) {
|
|
4121
|
+
newexpression.push(nstack.shift());
|
|
4122
|
+
}
|
|
4123
|
+
newexpression.push(new Instruction(IEXPR, simplify(item.value, unaryOps, binaryOps, ternaryOps, values)));
|
|
4124
|
+
} else if (type === IMEMBER && nstack.length > 0) {
|
|
4125
|
+
n1 = nstack.pop();
|
|
4126
|
+
nstack.push(new Instruction(INUMBER, n1.value[item.value]));
|
|
4127
|
+
} else {
|
|
4128
|
+
while (nstack.length > 0) {
|
|
4129
|
+
newexpression.push(nstack.shift());
|
|
4130
|
+
}
|
|
4131
|
+
newexpression.push(item);
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
while (nstack.length > 0) {
|
|
4135
|
+
newexpression.push(nstack.shift());
|
|
4136
|
+
}
|
|
4137
|
+
return newexpression;
|
|
4138
|
+
}
|
|
4139
|
+
function substitute(tokens, variable, expr) {
|
|
4140
|
+
var newexpression = [];
|
|
4141
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
4142
|
+
var item = tokens[i];
|
|
4143
|
+
var type = item.type;
|
|
4144
|
+
if (type === IVAR && item.value === variable) {
|
|
4145
|
+
for (var j = 0; j < expr.tokens.length; j++) {
|
|
4146
|
+
var expritem = expr.tokens[j];
|
|
4147
|
+
var replitem;
|
|
4148
|
+
if (expritem.type === IOP1) {
|
|
4149
|
+
replitem = unaryInstruction(expritem.value);
|
|
4150
|
+
} else if (expritem.type === IOP2) {
|
|
4151
|
+
replitem = binaryInstruction(expritem.value);
|
|
4152
|
+
} else if (expritem.type === IOP3) {
|
|
4153
|
+
replitem = ternaryInstruction(expritem.value);
|
|
4154
|
+
} else {
|
|
4155
|
+
replitem = new Instruction(expritem.type, expritem.value);
|
|
3752
4156
|
}
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
4157
|
+
newexpression.push(replitem);
|
|
4158
|
+
}
|
|
4159
|
+
} else if (type === IEXPR) {
|
|
4160
|
+
newexpression.push(new Instruction(IEXPR, substitute(item.value, variable, expr)));
|
|
4161
|
+
} else {
|
|
4162
|
+
newexpression.push(item);
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
return newexpression;
|
|
4166
|
+
}
|
|
4167
|
+
function evaluate(tokens, expr, values) {
|
|
4168
|
+
var nstack = [];
|
|
4169
|
+
var n1, n2, n3;
|
|
4170
|
+
var f, args, argCount;
|
|
4171
|
+
if (isExpressionEvaluator(tokens)) {
|
|
4172
|
+
return resolveExpression(tokens, values);
|
|
4173
|
+
}
|
|
4174
|
+
var numTokens = tokens.length;
|
|
4175
|
+
for (var i = 0; i < numTokens; i++) {
|
|
4176
|
+
var item = tokens[i];
|
|
4177
|
+
var type = item.type;
|
|
4178
|
+
if (type === INUMBER || type === IVARNAME) {
|
|
4179
|
+
nstack.push(item.value);
|
|
4180
|
+
} else if (type === IOP2) {
|
|
4181
|
+
n2 = nstack.pop();
|
|
4182
|
+
n1 = nstack.pop();
|
|
4183
|
+
if (item.value === "and") {
|
|
4184
|
+
nstack.push(n1 ? !!evaluate(n2, expr, values) : false);
|
|
4185
|
+
} else if (item.value === "or") {
|
|
4186
|
+
nstack.push(n1 ? true : !!evaluate(n2, expr, values));
|
|
4187
|
+
} else if (item.value === "=") {
|
|
4188
|
+
f = expr.binaryOps[item.value];
|
|
4189
|
+
nstack.push(f(n1, evaluate(n2, expr, values), values));
|
|
4190
|
+
} else {
|
|
4191
|
+
f = expr.binaryOps[item.value];
|
|
4192
|
+
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values)));
|
|
4193
|
+
}
|
|
4194
|
+
} else if (type === IOP3) {
|
|
4195
|
+
n3 = nstack.pop();
|
|
4196
|
+
n2 = nstack.pop();
|
|
4197
|
+
n1 = nstack.pop();
|
|
4198
|
+
if (item.value === "?") {
|
|
4199
|
+
nstack.push(evaluate(n1 ? n2 : n3, expr, values));
|
|
4200
|
+
} else {
|
|
4201
|
+
f = expr.ternaryOps[item.value];
|
|
4202
|
+
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values), resolveExpression(n3, values)));
|
|
4203
|
+
}
|
|
4204
|
+
} else if (type === IVAR) {
|
|
4205
|
+
if (item.value in expr.functions) {
|
|
4206
|
+
nstack.push(expr.functions[item.value]);
|
|
4207
|
+
} else if (item.value in expr.unaryOps && expr.parser.isOperatorEnabled(item.value)) {
|
|
4208
|
+
nstack.push(expr.unaryOps[item.value]);
|
|
4209
|
+
} else {
|
|
4210
|
+
var v = values[item.value];
|
|
4211
|
+
if (v !== void 0) {
|
|
4212
|
+
nstack.push(v);
|
|
4213
|
+
} else {
|
|
4214
|
+
throw new Error("undefined variable: " + item.value);
|
|
3757
4215
|
}
|
|
3758
4216
|
}
|
|
3759
|
-
|
|
4217
|
+
} else if (type === IOP1) {
|
|
4218
|
+
n1 = nstack.pop();
|
|
4219
|
+
f = expr.unaryOps[item.value];
|
|
4220
|
+
nstack.push(f(resolveExpression(n1, values)));
|
|
4221
|
+
} else if (type === IFUNCALL) {
|
|
4222
|
+
argCount = item.value;
|
|
4223
|
+
args = [];
|
|
4224
|
+
while (argCount-- > 0) {
|
|
4225
|
+
args.unshift(resolveExpression(nstack.pop(), values));
|
|
4226
|
+
}
|
|
4227
|
+
f = nstack.pop();
|
|
4228
|
+
if (f.apply && f.call) {
|
|
4229
|
+
nstack.push(f.apply(void 0, args));
|
|
4230
|
+
} else {
|
|
4231
|
+
throw new Error(f + " is not a function");
|
|
4232
|
+
}
|
|
4233
|
+
} else if (type === IFUNDEF) {
|
|
4234
|
+
nstack.push(function() {
|
|
4235
|
+
var n22 = nstack.pop();
|
|
4236
|
+
var args2 = [];
|
|
4237
|
+
var argCount2 = item.value;
|
|
4238
|
+
while (argCount2-- > 0) {
|
|
4239
|
+
args2.unshift(nstack.pop());
|
|
4240
|
+
}
|
|
4241
|
+
var n12 = nstack.pop();
|
|
4242
|
+
var f2 = function() {
|
|
4243
|
+
var scope = Object.assign({}, values);
|
|
4244
|
+
for (var i2 = 0, len2 = args2.length; i2 < len2; i2++) {
|
|
4245
|
+
scope[args2[i2]] = arguments[i2];
|
|
4246
|
+
}
|
|
4247
|
+
return evaluate(n22, expr, scope);
|
|
4248
|
+
};
|
|
4249
|
+
Object.defineProperty(f2, "name", {
|
|
4250
|
+
value: n12,
|
|
4251
|
+
writable: false
|
|
4252
|
+
});
|
|
4253
|
+
values[n12] = f2;
|
|
4254
|
+
return f2;
|
|
4255
|
+
}());
|
|
4256
|
+
} else if (type === IEXPR) {
|
|
4257
|
+
nstack.push(createExpressionEvaluator(item, expr));
|
|
4258
|
+
} else if (type === IEXPREVAL) {
|
|
4259
|
+
nstack.push(item);
|
|
4260
|
+
} else if (type === IMEMBER) {
|
|
4261
|
+
n1 = nstack.pop();
|
|
4262
|
+
nstack.push(n1[item.value]);
|
|
4263
|
+
} else if (type === IENDSTATEMENT) {
|
|
4264
|
+
nstack.pop();
|
|
4265
|
+
} else if (type === IARRAY) {
|
|
4266
|
+
argCount = item.value;
|
|
4267
|
+
args = [];
|
|
4268
|
+
while (argCount-- > 0) {
|
|
4269
|
+
args.unshift(nstack.pop());
|
|
4270
|
+
}
|
|
4271
|
+
nstack.push(args);
|
|
4272
|
+
} else {
|
|
4273
|
+
throw new Error("invalid Expression");
|
|
4274
|
+
}
|
|
4275
|
+
}
|
|
4276
|
+
if (nstack.length > 1) {
|
|
4277
|
+
throw new Error("invalid Expression (parity)");
|
|
4278
|
+
}
|
|
4279
|
+
return nstack[0] === 0 ? 0 : resolveExpression(nstack[0], values);
|
|
4280
|
+
}
|
|
4281
|
+
function createExpressionEvaluator(token, expr, values) {
|
|
4282
|
+
if (isExpressionEvaluator(token)) return token;
|
|
4283
|
+
return {
|
|
4284
|
+
type: IEXPREVAL,
|
|
4285
|
+
value: function(scope) {
|
|
4286
|
+
return evaluate(token.value, expr, scope);
|
|
3760
4287
|
}
|
|
3761
4288
|
};
|
|
3762
|
-
}
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
4289
|
+
}
|
|
4290
|
+
function isExpressionEvaluator(n) {
|
|
4291
|
+
return n && n.type === IEXPREVAL;
|
|
4292
|
+
}
|
|
4293
|
+
function resolveExpression(n, values) {
|
|
4294
|
+
return isExpressionEvaluator(n) ? n.value(values) : n;
|
|
4295
|
+
}
|
|
4296
|
+
function expressionToString(tokens, toJS) {
|
|
4297
|
+
var nstack = [];
|
|
4298
|
+
var n1, n2, n3;
|
|
4299
|
+
var f, args, argCount;
|
|
4300
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
4301
|
+
var item = tokens[i];
|
|
4302
|
+
var type = item.type;
|
|
4303
|
+
if (type === INUMBER) {
|
|
4304
|
+
if (typeof item.value === "number" && item.value < 0) {
|
|
4305
|
+
nstack.push("(" + item.value + ")");
|
|
4306
|
+
} else if (Array.isArray(item.value)) {
|
|
4307
|
+
nstack.push("[" + item.value.map(escapeValue).join(", ") + "]");
|
|
3775
4308
|
} else {
|
|
3776
|
-
|
|
3777
|
-
if (!headers["Content-Type"]) headers["Content-Type"] = "text/plain";
|
|
4309
|
+
nstack.push(escapeValue(item.value));
|
|
3778
4310
|
}
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
4311
|
+
} else if (type === IOP2) {
|
|
4312
|
+
n2 = nstack.pop();
|
|
4313
|
+
n1 = nstack.pop();
|
|
4314
|
+
f = item.value;
|
|
4315
|
+
if (toJS) {
|
|
4316
|
+
if (f === "^") {
|
|
4317
|
+
nstack.push("Math.pow(" + n1 + ", " + n2 + ")");
|
|
4318
|
+
} else if (f === "and") {
|
|
4319
|
+
nstack.push("(!!" + n1 + " && !!" + n2 + ")");
|
|
4320
|
+
} else if (f === "or") {
|
|
4321
|
+
nstack.push("(!!" + n1 + " || !!" + n2 + ")");
|
|
4322
|
+
} else if (f === "||") {
|
|
4323
|
+
nstack.push("(function(a,b){ return Array.isArray(a) && Array.isArray(b) ? a.concat(b) : String(a) + String(b); }((" + n1 + "),(" + n2 + ")))");
|
|
4324
|
+
} else if (f === "==") {
|
|
4325
|
+
nstack.push("(" + n1 + " === " + n2 + ")");
|
|
4326
|
+
} else if (f === "!=") {
|
|
4327
|
+
nstack.push("(" + n1 + " !== " + n2 + ")");
|
|
4328
|
+
} else if (f === "[") {
|
|
4329
|
+
nstack.push(n1 + "[(" + n2 + ") | 0]");
|
|
4330
|
+
} else {
|
|
4331
|
+
nstack.push("(" + n1 + " " + f + " " + n2 + ")");
|
|
4332
|
+
}
|
|
4333
|
+
} else {
|
|
4334
|
+
if (f === "[") {
|
|
4335
|
+
nstack.push(n1 + "[" + n2 + "]");
|
|
4336
|
+
} else {
|
|
4337
|
+
nstack.push("(" + n1 + " " + f + " " + n2 + ")");
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4340
|
+
} else if (type === IOP3) {
|
|
4341
|
+
n3 = nstack.pop();
|
|
4342
|
+
n2 = nstack.pop();
|
|
4343
|
+
n1 = nstack.pop();
|
|
4344
|
+
f = item.value;
|
|
4345
|
+
if (f === "?") {
|
|
4346
|
+
nstack.push("(" + n1 + " ? " + n2 + " : " + n3 + ")");
|
|
4347
|
+
} else {
|
|
4348
|
+
throw new Error("invalid Expression");
|
|
4349
|
+
}
|
|
4350
|
+
} else if (type === IVAR || type === IVARNAME) {
|
|
4351
|
+
nstack.push(item.value);
|
|
4352
|
+
} else if (type === IOP1) {
|
|
4353
|
+
n1 = nstack.pop();
|
|
4354
|
+
f = item.value;
|
|
4355
|
+
if (f === "-" || f === "+") {
|
|
4356
|
+
nstack.push("(" + f + n1 + ")");
|
|
4357
|
+
} else if (toJS) {
|
|
4358
|
+
if (f === "not") {
|
|
4359
|
+
nstack.push("(!" + n1 + ")");
|
|
4360
|
+
} else if (f === "!") {
|
|
4361
|
+
nstack.push("fac(" + n1 + ")");
|
|
4362
|
+
} else {
|
|
4363
|
+
nstack.push(f + "(" + n1 + ")");
|
|
4364
|
+
}
|
|
4365
|
+
} else if (f === "!") {
|
|
4366
|
+
nstack.push("(" + n1 + "!)");
|
|
4367
|
+
} else {
|
|
4368
|
+
nstack.push("(" + f + " " + n1 + ")");
|
|
4369
|
+
}
|
|
4370
|
+
} else if (type === IFUNCALL) {
|
|
4371
|
+
argCount = item.value;
|
|
4372
|
+
args = [];
|
|
4373
|
+
while (argCount-- > 0) {
|
|
4374
|
+
args.unshift(nstack.pop());
|
|
4375
|
+
}
|
|
4376
|
+
f = nstack.pop();
|
|
4377
|
+
nstack.push(f + "(" + args.join(", ") + ")");
|
|
4378
|
+
} else if (type === IFUNDEF) {
|
|
4379
|
+
n2 = nstack.pop();
|
|
4380
|
+
argCount = item.value;
|
|
4381
|
+
args = [];
|
|
4382
|
+
while (argCount-- > 0) {
|
|
4383
|
+
args.unshift(nstack.pop());
|
|
4384
|
+
}
|
|
4385
|
+
n1 = nstack.pop();
|
|
4386
|
+
if (toJS) {
|
|
4387
|
+
nstack.push("(" + n1 + " = function(" + args.join(", ") + ") { return " + n2 + " })");
|
|
4388
|
+
} else {
|
|
4389
|
+
nstack.push("(" + n1 + "(" + args.join(", ") + ") = " + n2 + ")");
|
|
3791
4390
|
}
|
|
4391
|
+
} else if (type === IMEMBER) {
|
|
4392
|
+
n1 = nstack.pop();
|
|
4393
|
+
nstack.push(n1 + "." + item.value);
|
|
4394
|
+
} else if (type === IARRAY) {
|
|
4395
|
+
argCount = item.value;
|
|
4396
|
+
args = [];
|
|
4397
|
+
while (argCount-- > 0) {
|
|
4398
|
+
args.unshift(nstack.pop());
|
|
4399
|
+
}
|
|
4400
|
+
nstack.push("[" + args.join(", ") + "]");
|
|
4401
|
+
} else if (type === IEXPR) {
|
|
4402
|
+
nstack.push("(" + expressionToString(item.value, toJS) + ")");
|
|
4403
|
+
} else if (type === IENDSTATEMENT) ;
|
|
4404
|
+
else {
|
|
4405
|
+
throw new Error("invalid Expression");
|
|
3792
4406
|
}
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
4407
|
+
}
|
|
4408
|
+
if (nstack.length > 1) {
|
|
4409
|
+
if (toJS) {
|
|
4410
|
+
nstack = [nstack.join(",")];
|
|
3796
4411
|
} else {
|
|
3797
|
-
|
|
4412
|
+
nstack = [nstack.join(";")];
|
|
3798
4413
|
}
|
|
3799
|
-
} catch (err) {
|
|
3800
|
-
console.error(`[Lightview-CDOM] $mount failed for ${url}:`, err);
|
|
3801
4414
|
}
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
4415
|
+
return String(nstack[0]);
|
|
4416
|
+
}
|
|
4417
|
+
function escapeValue(v) {
|
|
4418
|
+
if (typeof v === "string") {
|
|
4419
|
+
return JSON.stringify(v).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
4420
|
+
}
|
|
4421
|
+
return v;
|
|
4422
|
+
}
|
|
4423
|
+
function contains(array, obj) {
|
|
4424
|
+
for (var i = 0; i < array.length; i++) {
|
|
4425
|
+
if (array[i] === obj) {
|
|
4426
|
+
return true;
|
|
4427
|
+
}
|
|
4428
|
+
}
|
|
4429
|
+
return false;
|
|
4430
|
+
}
|
|
4431
|
+
function getSymbols(tokens, symbols, options) {
|
|
4432
|
+
options = options || {};
|
|
4433
|
+
var withMembers = !!options.withMembers;
|
|
4434
|
+
var prevVar = null;
|
|
4435
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
4436
|
+
var item = tokens[i];
|
|
4437
|
+
if (item.type === IVAR || item.type === IVARNAME) {
|
|
4438
|
+
if (!withMembers && !contains(symbols, item.value)) {
|
|
4439
|
+
symbols.push(item.value);
|
|
4440
|
+
} else if (prevVar !== null) {
|
|
4441
|
+
if (!contains(symbols, prevVar)) {
|
|
4442
|
+
symbols.push(prevVar);
|
|
4443
|
+
}
|
|
4444
|
+
prevVar = item.value;
|
|
4445
|
+
} else {
|
|
4446
|
+
prevVar = item.value;
|
|
4447
|
+
}
|
|
4448
|
+
} else if (item.type === IMEMBER && withMembers && prevVar !== null) {
|
|
4449
|
+
prevVar += "." + item.value;
|
|
4450
|
+
} else if (item.type === IEXPR) {
|
|
4451
|
+
getSymbols(item.value, symbols, options);
|
|
4452
|
+
} else if (prevVar !== null) {
|
|
4453
|
+
if (!contains(symbols, prevVar)) {
|
|
4454
|
+
symbols.push(prevVar);
|
|
4455
|
+
}
|
|
4456
|
+
prevVar = null;
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
if (prevVar !== null && !contains(symbols, prevVar)) {
|
|
4460
|
+
symbols.push(prevVar);
|
|
4461
|
+
}
|
|
4462
|
+
}
|
|
4463
|
+
function Expression(tokens, parser) {
|
|
4464
|
+
this.tokens = tokens;
|
|
4465
|
+
this.parser = parser;
|
|
4466
|
+
this.unaryOps = parser.unaryOps;
|
|
4467
|
+
this.binaryOps = parser.binaryOps;
|
|
4468
|
+
this.ternaryOps = parser.ternaryOps;
|
|
4469
|
+
this.functions = parser.functions;
|
|
4470
|
+
}
|
|
4471
|
+
Expression.prototype.simplify = function(values) {
|
|
4472
|
+
values = values || {};
|
|
4473
|
+
return new Expression(simplify(this.tokens, this.unaryOps, this.binaryOps, this.ternaryOps, values), this.parser);
|
|
4474
|
+
};
|
|
4475
|
+
Expression.prototype.substitute = function(variable, expr) {
|
|
4476
|
+
if (!(expr instanceof Expression)) {
|
|
4477
|
+
expr = this.parser.parse(String(expr));
|
|
4478
|
+
}
|
|
4479
|
+
return new Expression(substitute(this.tokens, variable, expr), this.parser);
|
|
4480
|
+
};
|
|
4481
|
+
Expression.prototype.evaluate = function(values) {
|
|
4482
|
+
values = values || {};
|
|
4483
|
+
return evaluate(this.tokens, this, values);
|
|
4484
|
+
};
|
|
4485
|
+
Expression.prototype.toString = function() {
|
|
4486
|
+
return expressionToString(this.tokens, false);
|
|
4487
|
+
};
|
|
4488
|
+
Expression.prototype.symbols = function(options) {
|
|
4489
|
+
options = options || {};
|
|
4490
|
+
var vars = [];
|
|
4491
|
+
getSymbols(this.tokens, vars, options);
|
|
4492
|
+
return vars;
|
|
4493
|
+
};
|
|
4494
|
+
Expression.prototype.variables = function(options) {
|
|
4495
|
+
options = options || {};
|
|
4496
|
+
var vars = [];
|
|
4497
|
+
getSymbols(this.tokens, vars, options);
|
|
4498
|
+
var functions = this.functions;
|
|
4499
|
+
return vars.filter(function(name) {
|
|
4500
|
+
return !(name in functions);
|
|
4501
|
+
});
|
|
4502
|
+
};
|
|
4503
|
+
Expression.prototype.toJSFunction = function(param, variables) {
|
|
4504
|
+
var expr = this;
|
|
4505
|
+
var f = new Function(param, "with(this.functions) with (this.ternaryOps) with (this.binaryOps) with (this.unaryOps) { return " + expressionToString(this.simplify(variables).tokens, true) + "; }");
|
|
4506
|
+
return function() {
|
|
4507
|
+
return f.apply(expr, arguments);
|
|
4508
|
+
};
|
|
4509
|
+
};
|
|
4510
|
+
var TEOF = "TEOF";
|
|
4511
|
+
var TOP = "TOP";
|
|
4512
|
+
var TNUMBER = "TNUMBER";
|
|
4513
|
+
var TSTRING = "TSTRING";
|
|
4514
|
+
var TPAREN = "TPAREN";
|
|
4515
|
+
var TBRACKET = "TBRACKET";
|
|
4516
|
+
var TCOMMA = "TCOMMA";
|
|
4517
|
+
var TNAME = "TNAME";
|
|
4518
|
+
var TSEMICOLON = "TSEMICOLON";
|
|
4519
|
+
function Token(type, value, index2) {
|
|
4520
|
+
this.type = type;
|
|
4521
|
+
this.value = value;
|
|
4522
|
+
this.index = index2;
|
|
4523
|
+
}
|
|
4524
|
+
Token.prototype.toString = function() {
|
|
4525
|
+
return this.type + ": " + this.value;
|
|
4526
|
+
};
|
|
4527
|
+
function TokenStream(parser, expression) {
|
|
4528
|
+
this.pos = 0;
|
|
4529
|
+
this.current = null;
|
|
4530
|
+
this.unaryOps = parser.unaryOps;
|
|
4531
|
+
this.binaryOps = parser.binaryOps;
|
|
4532
|
+
this.ternaryOps = parser.ternaryOps;
|
|
4533
|
+
this.consts = parser.consts;
|
|
4534
|
+
this.expression = expression;
|
|
4535
|
+
this.savedPosition = 0;
|
|
4536
|
+
this.savedCurrent = null;
|
|
4537
|
+
this.options = parser.options;
|
|
4538
|
+
this.parser = parser;
|
|
4539
|
+
}
|
|
4540
|
+
TokenStream.prototype.newToken = function(type, value, pos) {
|
|
4541
|
+
return new Token(type, value, pos != null ? pos : this.pos);
|
|
4542
|
+
};
|
|
4543
|
+
TokenStream.prototype.save = function() {
|
|
4544
|
+
this.savedPosition = this.pos;
|
|
4545
|
+
this.savedCurrent = this.current;
|
|
4546
|
+
};
|
|
4547
|
+
TokenStream.prototype.restore = function() {
|
|
4548
|
+
this.pos = this.savedPosition;
|
|
4549
|
+
this.current = this.savedCurrent;
|
|
4550
|
+
};
|
|
4551
|
+
TokenStream.prototype.next = function() {
|
|
4552
|
+
if (this.pos >= this.expression.length) {
|
|
4553
|
+
return this.newToken(TEOF, "EOF");
|
|
4554
|
+
}
|
|
4555
|
+
if (this.isWhitespace() || this.isComment()) {
|
|
4556
|
+
return this.next();
|
|
4557
|
+
} else if (this.isRadixInteger() || this.isNumber() || this.isOperator() || this.isString() || this.isParen() || this.isBracket() || this.isComma() || this.isSemicolon() || this.isNamedOp() || this.isConst() || this.isName()) {
|
|
4558
|
+
return this.current;
|
|
4559
|
+
} else {
|
|
4560
|
+
this.parseError('Unknown character "' + this.expression.charAt(this.pos) + '"');
|
|
4561
|
+
}
|
|
4562
|
+
};
|
|
4563
|
+
TokenStream.prototype.isString = function() {
|
|
4564
|
+
var r = false;
|
|
4565
|
+
var startPos = this.pos;
|
|
4566
|
+
var quote = this.expression.charAt(startPos);
|
|
4567
|
+
if (quote === "'" || quote === '"') {
|
|
4568
|
+
var index2 = this.expression.indexOf(quote, startPos + 1);
|
|
4569
|
+
while (index2 >= 0 && this.pos < this.expression.length) {
|
|
4570
|
+
this.pos = index2 + 1;
|
|
4571
|
+
if (this.expression.charAt(index2 - 1) !== "\\") {
|
|
4572
|
+
var rawString = this.expression.substring(startPos + 1, index2);
|
|
4573
|
+
this.current = this.newToken(TSTRING, this.unescape(rawString), startPos);
|
|
4574
|
+
r = true;
|
|
4575
|
+
break;
|
|
4576
|
+
}
|
|
4577
|
+
index2 = this.expression.indexOf(quote, index2 + 1);
|
|
4578
|
+
}
|
|
4579
|
+
}
|
|
4580
|
+
return r;
|
|
4581
|
+
};
|
|
4582
|
+
TokenStream.prototype.isParen = function() {
|
|
4583
|
+
var c = this.expression.charAt(this.pos);
|
|
4584
|
+
if (c === "(" || c === ")") {
|
|
4585
|
+
this.current = this.newToken(TPAREN, c);
|
|
4586
|
+
this.pos++;
|
|
4587
|
+
return true;
|
|
4588
|
+
}
|
|
4589
|
+
return false;
|
|
4590
|
+
};
|
|
4591
|
+
TokenStream.prototype.isBracket = function() {
|
|
4592
|
+
var c = this.expression.charAt(this.pos);
|
|
4593
|
+
if ((c === "[" || c === "]") && this.isOperatorEnabled("[")) {
|
|
4594
|
+
this.current = this.newToken(TBRACKET, c);
|
|
4595
|
+
this.pos++;
|
|
4596
|
+
return true;
|
|
4597
|
+
}
|
|
4598
|
+
return false;
|
|
4599
|
+
};
|
|
4600
|
+
TokenStream.prototype.isComma = function() {
|
|
4601
|
+
var c = this.expression.charAt(this.pos);
|
|
4602
|
+
if (c === ",") {
|
|
4603
|
+
this.current = this.newToken(TCOMMA, ",");
|
|
4604
|
+
this.pos++;
|
|
4605
|
+
return true;
|
|
4606
|
+
}
|
|
4607
|
+
return false;
|
|
4608
|
+
};
|
|
4609
|
+
TokenStream.prototype.isSemicolon = function() {
|
|
4610
|
+
var c = this.expression.charAt(this.pos);
|
|
4611
|
+
if (c === ";") {
|
|
4612
|
+
this.current = this.newToken(TSEMICOLON, ";");
|
|
4613
|
+
this.pos++;
|
|
4614
|
+
return true;
|
|
4615
|
+
}
|
|
4616
|
+
return false;
|
|
4617
|
+
};
|
|
4618
|
+
TokenStream.prototype.isConst = function() {
|
|
4619
|
+
var startPos = this.pos;
|
|
4620
|
+
var i = startPos;
|
|
4621
|
+
for (; i < this.expression.length; i++) {
|
|
4622
|
+
var c = this.expression.charAt(i);
|
|
4623
|
+
if (c.toUpperCase() === c.toLowerCase()) {
|
|
4624
|
+
if (i === this.pos || c !== "_" && c !== "." && (c < "0" || c > "9")) {
|
|
4625
|
+
break;
|
|
4626
|
+
}
|
|
4627
|
+
}
|
|
4628
|
+
}
|
|
4629
|
+
if (i > startPos) {
|
|
4630
|
+
var str = this.expression.substring(startPos, i);
|
|
4631
|
+
if (str in this.consts) {
|
|
4632
|
+
this.current = this.newToken(TNUMBER, this.consts[str]);
|
|
4633
|
+
this.pos += str.length;
|
|
4634
|
+
return true;
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
return false;
|
|
4638
|
+
};
|
|
4639
|
+
TokenStream.prototype.isNamedOp = function() {
|
|
4640
|
+
var startPos = this.pos;
|
|
4641
|
+
var i = startPos;
|
|
4642
|
+
for (; i < this.expression.length; i++) {
|
|
4643
|
+
var c = this.expression.charAt(i);
|
|
4644
|
+
if (c.toUpperCase() === c.toLowerCase()) {
|
|
4645
|
+
if (i === this.pos || c !== "_" && (c < "0" || c > "9")) {
|
|
4646
|
+
break;
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
if (i > startPos) {
|
|
4651
|
+
var str = this.expression.substring(startPos, i);
|
|
4652
|
+
if (this.isOperatorEnabled(str) && (str in this.binaryOps || str in this.unaryOps || str in this.ternaryOps)) {
|
|
4653
|
+
this.current = this.newToken(TOP, str);
|
|
4654
|
+
this.pos += str.length;
|
|
4655
|
+
return true;
|
|
4656
|
+
}
|
|
4657
|
+
}
|
|
4658
|
+
return false;
|
|
4659
|
+
};
|
|
4660
|
+
TokenStream.prototype.isName = function() {
|
|
4661
|
+
var startPos = this.pos;
|
|
4662
|
+
var i = startPos;
|
|
4663
|
+
var hasLetter = false;
|
|
4664
|
+
for (; i < this.expression.length; i++) {
|
|
4665
|
+
var c = this.expression.charAt(i);
|
|
4666
|
+
if (c.toUpperCase() === c.toLowerCase()) {
|
|
4667
|
+
if (i === this.pos && (c === "$" || c === "_")) {
|
|
4668
|
+
if (c === "_") {
|
|
4669
|
+
hasLetter = true;
|
|
4670
|
+
}
|
|
4671
|
+
continue;
|
|
4672
|
+
} else if (i === this.pos || !hasLetter || c !== "_" && (c < "0" || c > "9")) {
|
|
4673
|
+
break;
|
|
4674
|
+
}
|
|
4675
|
+
} else {
|
|
4676
|
+
hasLetter = true;
|
|
4677
|
+
}
|
|
4678
|
+
}
|
|
4679
|
+
if (hasLetter) {
|
|
4680
|
+
var str = this.expression.substring(startPos, i);
|
|
4681
|
+
this.current = this.newToken(TNAME, str);
|
|
4682
|
+
this.pos += str.length;
|
|
4683
|
+
return true;
|
|
4684
|
+
}
|
|
4685
|
+
return false;
|
|
4686
|
+
};
|
|
4687
|
+
TokenStream.prototype.isWhitespace = function() {
|
|
4688
|
+
var r = false;
|
|
4689
|
+
var c = this.expression.charAt(this.pos);
|
|
4690
|
+
while (c === " " || c === " " || c === "\n" || c === "\r") {
|
|
4691
|
+
r = true;
|
|
4692
|
+
this.pos++;
|
|
4693
|
+
if (this.pos >= this.expression.length) {
|
|
4694
|
+
break;
|
|
4695
|
+
}
|
|
4696
|
+
c = this.expression.charAt(this.pos);
|
|
4697
|
+
}
|
|
4698
|
+
return r;
|
|
4699
|
+
};
|
|
4700
|
+
var codePointPattern = /^[0-9a-f]{4}$/i;
|
|
4701
|
+
TokenStream.prototype.unescape = function(v) {
|
|
4702
|
+
var index2 = v.indexOf("\\");
|
|
4703
|
+
if (index2 < 0) {
|
|
4704
|
+
return v;
|
|
4705
|
+
}
|
|
4706
|
+
var buffer = v.substring(0, index2);
|
|
4707
|
+
while (index2 >= 0) {
|
|
4708
|
+
var c = v.charAt(++index2);
|
|
4709
|
+
switch (c) {
|
|
4710
|
+
case "'":
|
|
4711
|
+
buffer += "'";
|
|
4712
|
+
break;
|
|
4713
|
+
case '"':
|
|
4714
|
+
buffer += '"';
|
|
4715
|
+
break;
|
|
4716
|
+
case "\\":
|
|
4717
|
+
buffer += "\\";
|
|
4718
|
+
break;
|
|
4719
|
+
case "/":
|
|
4720
|
+
buffer += "/";
|
|
4721
|
+
break;
|
|
4722
|
+
case "b":
|
|
4723
|
+
buffer += "\b";
|
|
4724
|
+
break;
|
|
4725
|
+
case "f":
|
|
4726
|
+
buffer += "\f";
|
|
4727
|
+
break;
|
|
4728
|
+
case "n":
|
|
4729
|
+
buffer += "\n";
|
|
4730
|
+
break;
|
|
4731
|
+
case "r":
|
|
4732
|
+
buffer += "\r";
|
|
4733
|
+
break;
|
|
4734
|
+
case "t":
|
|
4735
|
+
buffer += " ";
|
|
4736
|
+
break;
|
|
4737
|
+
case "u":
|
|
4738
|
+
var codePoint = v.substring(index2 + 1, index2 + 5);
|
|
4739
|
+
if (!codePointPattern.test(codePoint)) {
|
|
4740
|
+
this.parseError("Illegal escape sequence: \\u" + codePoint);
|
|
4741
|
+
}
|
|
4742
|
+
buffer += String.fromCharCode(parseInt(codePoint, 16));
|
|
4743
|
+
index2 += 4;
|
|
4744
|
+
break;
|
|
4745
|
+
default:
|
|
4746
|
+
throw this.parseError('Illegal escape sequence: "\\' + c + '"');
|
|
4747
|
+
}
|
|
4748
|
+
++index2;
|
|
4749
|
+
var backslash = v.indexOf("\\", index2);
|
|
4750
|
+
buffer += v.substring(index2, backslash < 0 ? v.length : backslash);
|
|
4751
|
+
index2 = backslash;
|
|
4752
|
+
}
|
|
4753
|
+
return buffer;
|
|
4754
|
+
};
|
|
4755
|
+
TokenStream.prototype.isComment = function() {
|
|
4756
|
+
var c = this.expression.charAt(this.pos);
|
|
4757
|
+
if (c === "/" && this.expression.charAt(this.pos + 1) === "*") {
|
|
4758
|
+
this.pos = this.expression.indexOf("*/", this.pos) + 2;
|
|
4759
|
+
if (this.pos === 1) {
|
|
4760
|
+
this.pos = this.expression.length;
|
|
4761
|
+
}
|
|
4762
|
+
return true;
|
|
4763
|
+
}
|
|
4764
|
+
return false;
|
|
4765
|
+
};
|
|
4766
|
+
TokenStream.prototype.isRadixInteger = function() {
|
|
4767
|
+
var pos = this.pos;
|
|
4768
|
+
if (pos >= this.expression.length - 2 || this.expression.charAt(pos) !== "0") {
|
|
4769
|
+
return false;
|
|
4770
|
+
}
|
|
4771
|
+
++pos;
|
|
4772
|
+
var radix;
|
|
4773
|
+
var validDigit;
|
|
4774
|
+
if (this.expression.charAt(pos) === "x") {
|
|
4775
|
+
radix = 16;
|
|
4776
|
+
validDigit = /^[0-9a-f]$/i;
|
|
4777
|
+
++pos;
|
|
4778
|
+
} else if (this.expression.charAt(pos) === "b") {
|
|
4779
|
+
radix = 2;
|
|
4780
|
+
validDigit = /^[01]$/i;
|
|
4781
|
+
++pos;
|
|
4782
|
+
} else {
|
|
4783
|
+
return false;
|
|
4784
|
+
}
|
|
4785
|
+
var valid = false;
|
|
4786
|
+
var startPos = pos;
|
|
4787
|
+
while (pos < this.expression.length) {
|
|
4788
|
+
var c = this.expression.charAt(pos);
|
|
4789
|
+
if (validDigit.test(c)) {
|
|
4790
|
+
pos++;
|
|
4791
|
+
valid = true;
|
|
4792
|
+
} else {
|
|
4793
|
+
break;
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
if (valid) {
|
|
4797
|
+
this.current = this.newToken(TNUMBER, parseInt(this.expression.substring(startPos, pos), radix));
|
|
4798
|
+
this.pos = pos;
|
|
4799
|
+
}
|
|
4800
|
+
return valid;
|
|
4801
|
+
};
|
|
4802
|
+
TokenStream.prototype.isNumber = function() {
|
|
4803
|
+
var valid = false;
|
|
4804
|
+
var pos = this.pos;
|
|
4805
|
+
var startPos = pos;
|
|
4806
|
+
var resetPos = pos;
|
|
4807
|
+
var foundDot = false;
|
|
4808
|
+
var foundDigits = false;
|
|
4809
|
+
var c;
|
|
4810
|
+
while (pos < this.expression.length) {
|
|
4811
|
+
c = this.expression.charAt(pos);
|
|
4812
|
+
if (c >= "0" && c <= "9" || !foundDot && c === ".") {
|
|
4813
|
+
if (c === ".") {
|
|
4814
|
+
foundDot = true;
|
|
4815
|
+
} else {
|
|
4816
|
+
foundDigits = true;
|
|
4817
|
+
}
|
|
4818
|
+
pos++;
|
|
4819
|
+
valid = foundDigits;
|
|
4820
|
+
} else {
|
|
4821
|
+
break;
|
|
4822
|
+
}
|
|
4823
|
+
}
|
|
4824
|
+
if (valid) {
|
|
4825
|
+
resetPos = pos;
|
|
4826
|
+
}
|
|
4827
|
+
if (c === "e" || c === "E") {
|
|
4828
|
+
pos++;
|
|
4829
|
+
var acceptSign = true;
|
|
4830
|
+
var validExponent = false;
|
|
4831
|
+
while (pos < this.expression.length) {
|
|
4832
|
+
c = this.expression.charAt(pos);
|
|
4833
|
+
if (acceptSign && (c === "+" || c === "-")) {
|
|
4834
|
+
acceptSign = false;
|
|
4835
|
+
} else if (c >= "0" && c <= "9") {
|
|
4836
|
+
validExponent = true;
|
|
4837
|
+
acceptSign = false;
|
|
4838
|
+
} else {
|
|
4839
|
+
break;
|
|
4840
|
+
}
|
|
4841
|
+
pos++;
|
|
4842
|
+
}
|
|
4843
|
+
if (!validExponent) {
|
|
4844
|
+
pos = resetPos;
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4847
|
+
if (valid) {
|
|
4848
|
+
this.current = this.newToken(TNUMBER, parseFloat(this.expression.substring(startPos, pos)));
|
|
4849
|
+
this.pos = pos;
|
|
4850
|
+
} else {
|
|
4851
|
+
this.pos = resetPos;
|
|
4852
|
+
}
|
|
4853
|
+
return valid;
|
|
4854
|
+
};
|
|
4855
|
+
TokenStream.prototype.isOperator = function() {
|
|
4856
|
+
var startPos = this.pos;
|
|
4857
|
+
var c = this.expression.charAt(this.pos);
|
|
4858
|
+
if (c === "+" || c === "-" || c === "*" || c === "/" || c === "%" || c === "^" || c === "?" || c === ":" || c === ".") {
|
|
4859
|
+
this.current = this.newToken(TOP, c);
|
|
4860
|
+
} else if (c === "∙" || c === "•") {
|
|
4861
|
+
this.current = this.newToken(TOP, "*");
|
|
4862
|
+
} else if (c === ">") {
|
|
4863
|
+
if (this.expression.charAt(this.pos + 1) === "=") {
|
|
4864
|
+
this.current = this.newToken(TOP, ">=");
|
|
4865
|
+
this.pos++;
|
|
4866
|
+
} else {
|
|
4867
|
+
this.current = this.newToken(TOP, ">");
|
|
4868
|
+
}
|
|
4869
|
+
} else if (c === "<") {
|
|
4870
|
+
if (this.expression.charAt(this.pos + 1) === "=") {
|
|
4871
|
+
this.current = this.newToken(TOP, "<=");
|
|
4872
|
+
this.pos++;
|
|
4873
|
+
} else {
|
|
4874
|
+
this.current = this.newToken(TOP, "<");
|
|
4875
|
+
}
|
|
4876
|
+
} else if (c === "|") {
|
|
4877
|
+
if (this.expression.charAt(this.pos + 1) === "|") {
|
|
4878
|
+
this.current = this.newToken(TOP, "||");
|
|
4879
|
+
this.pos++;
|
|
4880
|
+
} else {
|
|
4881
|
+
return false;
|
|
4882
|
+
}
|
|
4883
|
+
} else if (c === "=") {
|
|
4884
|
+
if (this.expression.charAt(this.pos + 1) === "=") {
|
|
4885
|
+
this.current = this.newToken(TOP, "==");
|
|
4886
|
+
this.pos++;
|
|
4887
|
+
} else {
|
|
4888
|
+
this.current = this.newToken(TOP, c);
|
|
4889
|
+
}
|
|
4890
|
+
} else if (c === "!") {
|
|
4891
|
+
if (this.expression.charAt(this.pos + 1) === "=") {
|
|
4892
|
+
this.current = this.newToken(TOP, "!=");
|
|
4893
|
+
this.pos++;
|
|
4894
|
+
} else {
|
|
4895
|
+
this.current = this.newToken(TOP, c);
|
|
4896
|
+
}
|
|
4897
|
+
} else {
|
|
4898
|
+
return false;
|
|
4899
|
+
}
|
|
4900
|
+
this.pos++;
|
|
4901
|
+
if (this.isOperatorEnabled(this.current.value)) {
|
|
4902
|
+
return true;
|
|
4903
|
+
} else {
|
|
4904
|
+
this.pos = startPos;
|
|
4905
|
+
return false;
|
|
4906
|
+
}
|
|
4907
|
+
};
|
|
4908
|
+
TokenStream.prototype.isOperatorEnabled = function(op) {
|
|
4909
|
+
return this.parser.isOperatorEnabled(op);
|
|
4910
|
+
};
|
|
4911
|
+
TokenStream.prototype.getCoordinates = function() {
|
|
4912
|
+
var line = 0;
|
|
4913
|
+
var column;
|
|
4914
|
+
var newline = -1;
|
|
4915
|
+
do {
|
|
4916
|
+
line++;
|
|
4917
|
+
column = this.pos - newline;
|
|
4918
|
+
newline = this.expression.indexOf("\n", newline + 1);
|
|
4919
|
+
} while (newline >= 0 && newline < this.pos);
|
|
4920
|
+
return {
|
|
4921
|
+
line,
|
|
4922
|
+
column
|
|
4923
|
+
};
|
|
4924
|
+
};
|
|
4925
|
+
TokenStream.prototype.parseError = function(msg) {
|
|
4926
|
+
var coords = this.getCoordinates();
|
|
4927
|
+
throw new Error("parse error [" + coords.line + ":" + coords.column + "]: " + msg);
|
|
4928
|
+
};
|
|
4929
|
+
function ParserState(parser, tokenStream, options) {
|
|
4930
|
+
this.parser = parser;
|
|
4931
|
+
this.tokens = tokenStream;
|
|
4932
|
+
this.current = null;
|
|
4933
|
+
this.nextToken = null;
|
|
4934
|
+
this.next();
|
|
4935
|
+
this.savedCurrent = null;
|
|
4936
|
+
this.savedNextToken = null;
|
|
4937
|
+
this.allowMemberAccess = options.allowMemberAccess !== false;
|
|
4938
|
+
}
|
|
4939
|
+
ParserState.prototype.next = function() {
|
|
4940
|
+
this.current = this.nextToken;
|
|
4941
|
+
return this.nextToken = this.tokens.next();
|
|
4942
|
+
};
|
|
4943
|
+
ParserState.prototype.tokenMatches = function(token, value) {
|
|
4944
|
+
if (typeof value === "undefined") {
|
|
4945
|
+
return true;
|
|
4946
|
+
} else if (Array.isArray(value)) {
|
|
4947
|
+
return contains(value, token.value);
|
|
4948
|
+
} else if (typeof value === "function") {
|
|
4949
|
+
return value(token);
|
|
4950
|
+
} else {
|
|
4951
|
+
return token.value === value;
|
|
4952
|
+
}
|
|
4953
|
+
};
|
|
4954
|
+
ParserState.prototype.save = function() {
|
|
4955
|
+
this.savedCurrent = this.current;
|
|
4956
|
+
this.savedNextToken = this.nextToken;
|
|
4957
|
+
this.tokens.save();
|
|
4958
|
+
};
|
|
4959
|
+
ParserState.prototype.restore = function() {
|
|
4960
|
+
this.tokens.restore();
|
|
4961
|
+
this.current = this.savedCurrent;
|
|
4962
|
+
this.nextToken = this.savedNextToken;
|
|
4963
|
+
};
|
|
4964
|
+
ParserState.prototype.accept = function(type, value) {
|
|
4965
|
+
if (this.nextToken.type === type && this.tokenMatches(this.nextToken, value)) {
|
|
4966
|
+
this.next();
|
|
4967
|
+
return true;
|
|
4968
|
+
}
|
|
4969
|
+
return false;
|
|
4970
|
+
};
|
|
4971
|
+
ParserState.prototype.expect = function(type, value) {
|
|
4972
|
+
if (!this.accept(type, value)) {
|
|
4973
|
+
var coords = this.tokens.getCoordinates();
|
|
4974
|
+
throw new Error("parse error [" + coords.line + ":" + coords.column + "]: Expected " + (value || type));
|
|
4975
|
+
}
|
|
4976
|
+
};
|
|
4977
|
+
ParserState.prototype.parseAtom = function(instr) {
|
|
4978
|
+
var unaryOps = this.tokens.unaryOps;
|
|
4979
|
+
function isPrefixOperator(token) {
|
|
4980
|
+
return token.value in unaryOps;
|
|
4981
|
+
}
|
|
4982
|
+
if (this.accept(TNAME) || this.accept(TOP, isPrefixOperator)) {
|
|
4983
|
+
instr.push(new Instruction(IVAR, this.current.value));
|
|
4984
|
+
} else if (this.accept(TNUMBER)) {
|
|
4985
|
+
instr.push(new Instruction(INUMBER, this.current.value));
|
|
4986
|
+
} else if (this.accept(TSTRING)) {
|
|
4987
|
+
instr.push(new Instruction(INUMBER, this.current.value));
|
|
4988
|
+
} else if (this.accept(TPAREN, "(")) {
|
|
4989
|
+
this.parseExpression(instr);
|
|
4990
|
+
this.expect(TPAREN, ")");
|
|
4991
|
+
} else if (this.accept(TBRACKET, "[")) {
|
|
4992
|
+
if (this.accept(TBRACKET, "]")) {
|
|
4993
|
+
instr.push(new Instruction(IARRAY, 0));
|
|
4994
|
+
} else {
|
|
4995
|
+
var argCount = this.parseArrayList(instr);
|
|
4996
|
+
instr.push(new Instruction(IARRAY, argCount));
|
|
4997
|
+
}
|
|
4998
|
+
} else {
|
|
4999
|
+
throw new Error("unexpected " + this.nextToken);
|
|
5000
|
+
}
|
|
5001
|
+
};
|
|
5002
|
+
ParserState.prototype.parseExpression = function(instr) {
|
|
5003
|
+
var exprInstr = [];
|
|
5004
|
+
if (this.parseUntilEndStatement(instr, exprInstr)) {
|
|
5005
|
+
return;
|
|
5006
|
+
}
|
|
5007
|
+
this.parseVariableAssignmentExpression(exprInstr);
|
|
5008
|
+
if (this.parseUntilEndStatement(instr, exprInstr)) {
|
|
5009
|
+
return;
|
|
5010
|
+
}
|
|
5011
|
+
this.pushExpression(instr, exprInstr);
|
|
5012
|
+
};
|
|
5013
|
+
ParserState.prototype.pushExpression = function(instr, exprInstr) {
|
|
5014
|
+
for (var i = 0, len2 = exprInstr.length; i < len2; i++) {
|
|
5015
|
+
instr.push(exprInstr[i]);
|
|
5016
|
+
}
|
|
5017
|
+
};
|
|
5018
|
+
ParserState.prototype.parseUntilEndStatement = function(instr, exprInstr) {
|
|
5019
|
+
if (!this.accept(TSEMICOLON)) return false;
|
|
5020
|
+
if (this.nextToken && this.nextToken.type !== TEOF && !(this.nextToken.type === TPAREN && this.nextToken.value === ")")) {
|
|
5021
|
+
exprInstr.push(new Instruction(IENDSTATEMENT));
|
|
5022
|
+
}
|
|
5023
|
+
if (this.nextToken.type !== TEOF) {
|
|
5024
|
+
this.parseExpression(exprInstr);
|
|
5025
|
+
}
|
|
5026
|
+
instr.push(new Instruction(IEXPR, exprInstr));
|
|
5027
|
+
return true;
|
|
5028
|
+
};
|
|
5029
|
+
ParserState.prototype.parseArrayList = function(instr) {
|
|
5030
|
+
var argCount = 0;
|
|
5031
|
+
while (!this.accept(TBRACKET, "]")) {
|
|
5032
|
+
this.parseExpression(instr);
|
|
5033
|
+
++argCount;
|
|
5034
|
+
while (this.accept(TCOMMA)) {
|
|
5035
|
+
this.parseExpression(instr);
|
|
5036
|
+
++argCount;
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
return argCount;
|
|
5040
|
+
};
|
|
5041
|
+
ParserState.prototype.parseVariableAssignmentExpression = function(instr) {
|
|
5042
|
+
this.parseConditionalExpression(instr);
|
|
5043
|
+
while (this.accept(TOP, "=")) {
|
|
5044
|
+
var varName = instr.pop();
|
|
5045
|
+
var varValue = [];
|
|
5046
|
+
var lastInstrIndex = instr.length - 1;
|
|
5047
|
+
if (varName.type === IFUNCALL) {
|
|
5048
|
+
if (!this.tokens.isOperatorEnabled("()=")) {
|
|
5049
|
+
throw new Error("function definition is not permitted");
|
|
5050
|
+
}
|
|
5051
|
+
for (var i = 0, len2 = varName.value + 1; i < len2; i++) {
|
|
5052
|
+
var index2 = lastInstrIndex - i;
|
|
5053
|
+
if (instr[index2].type === IVAR) {
|
|
5054
|
+
instr[index2] = new Instruction(IVARNAME, instr[index2].value);
|
|
5055
|
+
}
|
|
5056
|
+
}
|
|
5057
|
+
this.parseVariableAssignmentExpression(varValue);
|
|
5058
|
+
instr.push(new Instruction(IEXPR, varValue));
|
|
5059
|
+
instr.push(new Instruction(IFUNDEF, varName.value));
|
|
5060
|
+
continue;
|
|
5061
|
+
}
|
|
5062
|
+
if (varName.type !== IVAR && varName.type !== IMEMBER) {
|
|
5063
|
+
throw new Error("expected variable for assignment");
|
|
5064
|
+
}
|
|
5065
|
+
this.parseVariableAssignmentExpression(varValue);
|
|
5066
|
+
instr.push(new Instruction(IVARNAME, varName.value));
|
|
5067
|
+
instr.push(new Instruction(IEXPR, varValue));
|
|
5068
|
+
instr.push(binaryInstruction("="));
|
|
5069
|
+
}
|
|
5070
|
+
};
|
|
5071
|
+
ParserState.prototype.parseConditionalExpression = function(instr) {
|
|
5072
|
+
this.parseOrExpression(instr);
|
|
5073
|
+
while (this.accept(TOP, "?")) {
|
|
5074
|
+
var trueBranch = [];
|
|
5075
|
+
var falseBranch = [];
|
|
5076
|
+
this.parseConditionalExpression(trueBranch);
|
|
5077
|
+
this.expect(TOP, ":");
|
|
5078
|
+
this.parseConditionalExpression(falseBranch);
|
|
5079
|
+
instr.push(new Instruction(IEXPR, trueBranch));
|
|
5080
|
+
instr.push(new Instruction(IEXPR, falseBranch));
|
|
5081
|
+
instr.push(ternaryInstruction("?"));
|
|
5082
|
+
}
|
|
5083
|
+
};
|
|
5084
|
+
ParserState.prototype.parseOrExpression = function(instr) {
|
|
5085
|
+
this.parseAndExpression(instr);
|
|
5086
|
+
while (this.accept(TOP, "or")) {
|
|
5087
|
+
var falseBranch = [];
|
|
5088
|
+
this.parseAndExpression(falseBranch);
|
|
5089
|
+
instr.push(new Instruction(IEXPR, falseBranch));
|
|
5090
|
+
instr.push(binaryInstruction("or"));
|
|
5091
|
+
}
|
|
5092
|
+
};
|
|
5093
|
+
ParserState.prototype.parseAndExpression = function(instr) {
|
|
5094
|
+
this.parseComparison(instr);
|
|
5095
|
+
while (this.accept(TOP, "and")) {
|
|
5096
|
+
var trueBranch = [];
|
|
5097
|
+
this.parseComparison(trueBranch);
|
|
5098
|
+
instr.push(new Instruction(IEXPR, trueBranch));
|
|
5099
|
+
instr.push(binaryInstruction("and"));
|
|
5100
|
+
}
|
|
5101
|
+
};
|
|
5102
|
+
var COMPARISON_OPERATORS = ["==", "!=", "<", "<=", ">=", ">", "in"];
|
|
5103
|
+
ParserState.prototype.parseComparison = function(instr) {
|
|
5104
|
+
this.parseAddSub(instr);
|
|
5105
|
+
while (this.accept(TOP, COMPARISON_OPERATORS)) {
|
|
5106
|
+
var op = this.current;
|
|
5107
|
+
this.parseAddSub(instr);
|
|
5108
|
+
instr.push(binaryInstruction(op.value));
|
|
5109
|
+
}
|
|
5110
|
+
};
|
|
5111
|
+
var ADD_SUB_OPERATORS = ["+", "-", "||"];
|
|
5112
|
+
ParserState.prototype.parseAddSub = function(instr) {
|
|
5113
|
+
this.parseTerm(instr);
|
|
5114
|
+
while (this.accept(TOP, ADD_SUB_OPERATORS)) {
|
|
5115
|
+
var op = this.current;
|
|
5116
|
+
this.parseTerm(instr);
|
|
5117
|
+
instr.push(binaryInstruction(op.value));
|
|
5118
|
+
}
|
|
5119
|
+
};
|
|
5120
|
+
var TERM_OPERATORS = ["*", "/", "%"];
|
|
5121
|
+
ParserState.prototype.parseTerm = function(instr) {
|
|
5122
|
+
this.parseFactor(instr);
|
|
5123
|
+
while (this.accept(TOP, TERM_OPERATORS)) {
|
|
5124
|
+
var op = this.current;
|
|
5125
|
+
this.parseFactor(instr);
|
|
5126
|
+
instr.push(binaryInstruction(op.value));
|
|
5127
|
+
}
|
|
5128
|
+
};
|
|
5129
|
+
ParserState.prototype.parseFactor = function(instr) {
|
|
5130
|
+
var unaryOps = this.tokens.unaryOps;
|
|
5131
|
+
function isPrefixOperator(token) {
|
|
5132
|
+
return token.value in unaryOps;
|
|
5133
|
+
}
|
|
5134
|
+
this.save();
|
|
5135
|
+
if (this.accept(TOP, isPrefixOperator)) {
|
|
5136
|
+
if (this.current.value !== "-" && this.current.value !== "+") {
|
|
5137
|
+
if (this.nextToken.type === TPAREN && this.nextToken.value === "(") {
|
|
5138
|
+
this.restore();
|
|
5139
|
+
this.parseExponential(instr);
|
|
5140
|
+
return;
|
|
5141
|
+
} else if (this.nextToken.type === TSEMICOLON || this.nextToken.type === TCOMMA || this.nextToken.type === TEOF || this.nextToken.type === TPAREN && this.nextToken.value === ")") {
|
|
5142
|
+
this.restore();
|
|
5143
|
+
this.parseAtom(instr);
|
|
5144
|
+
return;
|
|
5145
|
+
}
|
|
5146
|
+
}
|
|
5147
|
+
var op = this.current;
|
|
5148
|
+
this.parseFactor(instr);
|
|
5149
|
+
instr.push(unaryInstruction(op.value));
|
|
5150
|
+
} else {
|
|
5151
|
+
this.parseExponential(instr);
|
|
5152
|
+
}
|
|
5153
|
+
};
|
|
5154
|
+
ParserState.prototype.parseExponential = function(instr) {
|
|
5155
|
+
this.parsePostfixExpression(instr);
|
|
5156
|
+
while (this.accept(TOP, "^")) {
|
|
5157
|
+
this.parseFactor(instr);
|
|
5158
|
+
instr.push(binaryInstruction("^"));
|
|
5159
|
+
}
|
|
5160
|
+
};
|
|
5161
|
+
ParserState.prototype.parsePostfixExpression = function(instr) {
|
|
5162
|
+
this.parseFunctionCall(instr);
|
|
5163
|
+
while (this.accept(TOP, "!")) {
|
|
5164
|
+
instr.push(unaryInstruction("!"));
|
|
5165
|
+
}
|
|
5166
|
+
};
|
|
5167
|
+
ParserState.prototype.parseFunctionCall = function(instr) {
|
|
5168
|
+
var unaryOps = this.tokens.unaryOps;
|
|
5169
|
+
function isPrefixOperator(token) {
|
|
5170
|
+
return token.value in unaryOps;
|
|
5171
|
+
}
|
|
5172
|
+
if (this.accept(TOP, isPrefixOperator)) {
|
|
5173
|
+
var op = this.current;
|
|
5174
|
+
this.parseAtom(instr);
|
|
5175
|
+
instr.push(unaryInstruction(op.value));
|
|
5176
|
+
} else {
|
|
5177
|
+
this.parseMemberExpression(instr);
|
|
5178
|
+
while (this.accept(TPAREN, "(")) {
|
|
5179
|
+
if (this.accept(TPAREN, ")")) {
|
|
5180
|
+
instr.push(new Instruction(IFUNCALL, 0));
|
|
5181
|
+
} else {
|
|
5182
|
+
var argCount = this.parseArgumentList(instr);
|
|
5183
|
+
instr.push(new Instruction(IFUNCALL, argCount));
|
|
5184
|
+
}
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
};
|
|
5188
|
+
ParserState.prototype.parseArgumentList = function(instr) {
|
|
5189
|
+
var argCount = 0;
|
|
5190
|
+
while (!this.accept(TPAREN, ")")) {
|
|
5191
|
+
this.parseExpression(instr);
|
|
5192
|
+
++argCount;
|
|
5193
|
+
while (this.accept(TCOMMA)) {
|
|
5194
|
+
this.parseExpression(instr);
|
|
5195
|
+
++argCount;
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5198
|
+
return argCount;
|
|
5199
|
+
};
|
|
5200
|
+
ParserState.prototype.parseMemberExpression = function(instr) {
|
|
5201
|
+
this.parseAtom(instr);
|
|
5202
|
+
while (this.accept(TOP, ".") || this.accept(TBRACKET, "[")) {
|
|
5203
|
+
var op = this.current;
|
|
5204
|
+
if (op.value === ".") {
|
|
5205
|
+
if (!this.allowMemberAccess) {
|
|
5206
|
+
throw new Error('unexpected ".", member access is not permitted');
|
|
5207
|
+
}
|
|
5208
|
+
this.expect(TNAME);
|
|
5209
|
+
instr.push(new Instruction(IMEMBER, this.current.value));
|
|
5210
|
+
} else if (op.value === "[") {
|
|
5211
|
+
if (!this.tokens.isOperatorEnabled("[")) {
|
|
5212
|
+
throw new Error('unexpected "[]", arrays are disabled');
|
|
5213
|
+
}
|
|
5214
|
+
this.parseExpression(instr);
|
|
5215
|
+
this.expect(TBRACKET, "]");
|
|
5216
|
+
instr.push(binaryInstruction("["));
|
|
5217
|
+
} else {
|
|
5218
|
+
throw new Error("unexpected symbol: " + op.value);
|
|
5219
|
+
}
|
|
5220
|
+
}
|
|
5221
|
+
};
|
|
5222
|
+
function add(a, b) {
|
|
5223
|
+
return Number(a) + Number(b);
|
|
5224
|
+
}
|
|
5225
|
+
function sub(a, b) {
|
|
5226
|
+
return a - b;
|
|
5227
|
+
}
|
|
5228
|
+
function mul(a, b) {
|
|
5229
|
+
return a * b;
|
|
5230
|
+
}
|
|
5231
|
+
function div(a, b) {
|
|
5232
|
+
return a / b;
|
|
5233
|
+
}
|
|
5234
|
+
function mod(a, b) {
|
|
5235
|
+
return a % b;
|
|
5236
|
+
}
|
|
5237
|
+
function concat(a, b) {
|
|
5238
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
5239
|
+
return a.concat(b);
|
|
5240
|
+
}
|
|
5241
|
+
return "" + a + b;
|
|
5242
|
+
}
|
|
5243
|
+
function equal(a, b) {
|
|
5244
|
+
return a === b;
|
|
5245
|
+
}
|
|
5246
|
+
function notEqual(a, b) {
|
|
5247
|
+
return a !== b;
|
|
5248
|
+
}
|
|
5249
|
+
function greaterThan(a, b) {
|
|
5250
|
+
return a > b;
|
|
5251
|
+
}
|
|
5252
|
+
function lessThan(a, b) {
|
|
5253
|
+
return a < b;
|
|
5254
|
+
}
|
|
5255
|
+
function greaterThanEqual(a, b) {
|
|
5256
|
+
return a >= b;
|
|
5257
|
+
}
|
|
5258
|
+
function lessThanEqual(a, b) {
|
|
5259
|
+
return a <= b;
|
|
5260
|
+
}
|
|
5261
|
+
function andOperator(a, b) {
|
|
5262
|
+
return Boolean(a && b);
|
|
5263
|
+
}
|
|
5264
|
+
function orOperator(a, b) {
|
|
5265
|
+
return Boolean(a || b);
|
|
5266
|
+
}
|
|
5267
|
+
function inOperator(a, b) {
|
|
5268
|
+
return contains(b, a);
|
|
5269
|
+
}
|
|
5270
|
+
function sinh(a) {
|
|
5271
|
+
return (Math.exp(a) - Math.exp(-a)) / 2;
|
|
5272
|
+
}
|
|
5273
|
+
function cosh(a) {
|
|
5274
|
+
return (Math.exp(a) + Math.exp(-a)) / 2;
|
|
5275
|
+
}
|
|
5276
|
+
function tanh(a) {
|
|
5277
|
+
if (a === Infinity) return 1;
|
|
5278
|
+
if (a === -Infinity) return -1;
|
|
5279
|
+
return (Math.exp(a) - Math.exp(-a)) / (Math.exp(a) + Math.exp(-a));
|
|
5280
|
+
}
|
|
5281
|
+
function asinh(a) {
|
|
5282
|
+
if (a === -Infinity) return a;
|
|
5283
|
+
return Math.log(a + Math.sqrt(a * a + 1));
|
|
5284
|
+
}
|
|
5285
|
+
function acosh(a) {
|
|
5286
|
+
return Math.log(a + Math.sqrt(a * a - 1));
|
|
5287
|
+
}
|
|
5288
|
+
function atanh(a) {
|
|
5289
|
+
return Math.log((1 + a) / (1 - a)) / 2;
|
|
5290
|
+
}
|
|
5291
|
+
function log10(a) {
|
|
5292
|
+
return Math.log(a) * Math.LOG10E;
|
|
5293
|
+
}
|
|
5294
|
+
function neg(a) {
|
|
5295
|
+
return -a;
|
|
5296
|
+
}
|
|
5297
|
+
function not(a) {
|
|
5298
|
+
return !a;
|
|
5299
|
+
}
|
|
5300
|
+
function trunc(a) {
|
|
5301
|
+
return a < 0 ? Math.ceil(a) : Math.floor(a);
|
|
5302
|
+
}
|
|
5303
|
+
function random(a) {
|
|
5304
|
+
return Math.random() * (a || 1);
|
|
5305
|
+
}
|
|
5306
|
+
function factorial(a) {
|
|
5307
|
+
return gamma(a + 1);
|
|
5308
|
+
}
|
|
5309
|
+
function isInteger(value) {
|
|
5310
|
+
return isFinite(value) && value === Math.round(value);
|
|
5311
|
+
}
|
|
5312
|
+
var GAMMA_G = 4.7421875;
|
|
5313
|
+
var GAMMA_P = [
|
|
5314
|
+
0.9999999999999971,
|
|
5315
|
+
57.15623566586292,
|
|
5316
|
+
-59.59796035547549,
|
|
5317
|
+
14.136097974741746,
|
|
5318
|
+
-0.4919138160976202,
|
|
5319
|
+
3399464998481189e-20,
|
|
5320
|
+
4652362892704858e-20,
|
|
5321
|
+
-9837447530487956e-20,
|
|
5322
|
+
1580887032249125e-19,
|
|
5323
|
+
-21026444172410488e-20,
|
|
5324
|
+
21743961811521265e-20,
|
|
5325
|
+
-1643181065367639e-19,
|
|
5326
|
+
8441822398385275e-20,
|
|
5327
|
+
-26190838401581408e-21,
|
|
5328
|
+
36899182659531625e-22
|
|
5329
|
+
];
|
|
5330
|
+
function gamma(n) {
|
|
5331
|
+
var t, x;
|
|
5332
|
+
if (isInteger(n)) {
|
|
5333
|
+
if (n <= 0) {
|
|
5334
|
+
return isFinite(n) ? Infinity : NaN;
|
|
5335
|
+
}
|
|
5336
|
+
if (n > 171) {
|
|
5337
|
+
return Infinity;
|
|
5338
|
+
}
|
|
5339
|
+
var value = n - 2;
|
|
5340
|
+
var res = n - 1;
|
|
5341
|
+
while (value > 1) {
|
|
5342
|
+
res *= value;
|
|
5343
|
+
value--;
|
|
5344
|
+
}
|
|
5345
|
+
if (res === 0) {
|
|
5346
|
+
res = 1;
|
|
5347
|
+
}
|
|
5348
|
+
return res;
|
|
5349
|
+
}
|
|
5350
|
+
if (n < 0.5) {
|
|
5351
|
+
return Math.PI / (Math.sin(Math.PI * n) * gamma(1 - n));
|
|
5352
|
+
}
|
|
5353
|
+
if (n >= 171.35) {
|
|
5354
|
+
return Infinity;
|
|
5355
|
+
}
|
|
5356
|
+
if (n > 85) {
|
|
5357
|
+
var twoN = n * n;
|
|
5358
|
+
var threeN = twoN * n;
|
|
5359
|
+
var fourN = threeN * n;
|
|
5360
|
+
var fiveN = fourN * n;
|
|
5361
|
+
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));
|
|
5362
|
+
}
|
|
5363
|
+
--n;
|
|
5364
|
+
x = GAMMA_P[0];
|
|
5365
|
+
for (var i = 1; i < GAMMA_P.length; ++i) {
|
|
5366
|
+
x += GAMMA_P[i] / (n + i);
|
|
5367
|
+
}
|
|
5368
|
+
t = n + GAMMA_G + 0.5;
|
|
5369
|
+
return Math.sqrt(2 * Math.PI) * Math.pow(t, n + 0.5) * Math.exp(-t) * x;
|
|
5370
|
+
}
|
|
5371
|
+
function stringOrArrayLength(s) {
|
|
5372
|
+
if (Array.isArray(s)) {
|
|
5373
|
+
return s.length;
|
|
5374
|
+
}
|
|
5375
|
+
return String(s).length;
|
|
5376
|
+
}
|
|
5377
|
+
function hypot() {
|
|
5378
|
+
var sum2 = 0;
|
|
5379
|
+
var larg = 0;
|
|
5380
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
5381
|
+
var arg = Math.abs(arguments[i]);
|
|
5382
|
+
var div2;
|
|
5383
|
+
if (larg < arg) {
|
|
5384
|
+
div2 = larg / arg;
|
|
5385
|
+
sum2 = sum2 * div2 * div2 + 1;
|
|
5386
|
+
larg = arg;
|
|
5387
|
+
} else if (arg > 0) {
|
|
5388
|
+
div2 = arg / larg;
|
|
5389
|
+
sum2 += div2 * div2;
|
|
5390
|
+
} else {
|
|
5391
|
+
sum2 += arg;
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
return larg === Infinity ? Infinity : larg * Math.sqrt(sum2);
|
|
5395
|
+
}
|
|
5396
|
+
function condition(cond, yep, nope) {
|
|
5397
|
+
return cond ? yep : nope;
|
|
5398
|
+
}
|
|
5399
|
+
function roundTo(value, exp) {
|
|
5400
|
+
if (typeof exp === "undefined" || +exp === 0) {
|
|
5401
|
+
return Math.round(value);
|
|
5402
|
+
}
|
|
5403
|
+
value = +value;
|
|
5404
|
+
exp = -+exp;
|
|
5405
|
+
if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
|
|
5406
|
+
return NaN;
|
|
5407
|
+
}
|
|
5408
|
+
value = value.toString().split("e");
|
|
5409
|
+
value = Math.round(+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp)));
|
|
5410
|
+
value = value.toString().split("e");
|
|
5411
|
+
return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp));
|
|
5412
|
+
}
|
|
5413
|
+
function setVar(name, value, variables) {
|
|
5414
|
+
if (variables) variables[name] = value;
|
|
5415
|
+
return value;
|
|
5416
|
+
}
|
|
5417
|
+
function arrayIndex(array, index2) {
|
|
5418
|
+
return array[index2 | 0];
|
|
5419
|
+
}
|
|
5420
|
+
function max(array) {
|
|
5421
|
+
if (arguments.length === 1 && Array.isArray(array)) {
|
|
5422
|
+
return Math.max.apply(Math, array);
|
|
5423
|
+
} else {
|
|
5424
|
+
return Math.max.apply(Math, arguments);
|
|
5425
|
+
}
|
|
5426
|
+
}
|
|
5427
|
+
function min(array) {
|
|
5428
|
+
if (arguments.length === 1 && Array.isArray(array)) {
|
|
5429
|
+
return Math.min.apply(Math, array);
|
|
5430
|
+
} else {
|
|
5431
|
+
return Math.min.apply(Math, arguments);
|
|
5432
|
+
}
|
|
5433
|
+
}
|
|
5434
|
+
function arrayMap(f, a) {
|
|
5435
|
+
if (typeof f !== "function") {
|
|
5436
|
+
throw new Error("First argument to map is not a function");
|
|
5437
|
+
}
|
|
5438
|
+
if (!Array.isArray(a)) {
|
|
5439
|
+
throw new Error("Second argument to map is not an array");
|
|
5440
|
+
}
|
|
5441
|
+
return a.map(function(x, i) {
|
|
5442
|
+
return f(x, i);
|
|
5443
|
+
});
|
|
5444
|
+
}
|
|
5445
|
+
function arrayFold(f, init, a) {
|
|
5446
|
+
if (typeof f !== "function") {
|
|
5447
|
+
throw new Error("First argument to fold is not a function");
|
|
5448
|
+
}
|
|
5449
|
+
if (!Array.isArray(a)) {
|
|
5450
|
+
throw new Error("Second argument to fold is not an array");
|
|
5451
|
+
}
|
|
5452
|
+
return a.reduce(function(acc, x, i) {
|
|
5453
|
+
return f(acc, x, i);
|
|
5454
|
+
}, init);
|
|
5455
|
+
}
|
|
5456
|
+
function arrayFilter(f, a) {
|
|
5457
|
+
if (typeof f !== "function") {
|
|
5458
|
+
throw new Error("First argument to filter is not a function");
|
|
5459
|
+
}
|
|
5460
|
+
if (!Array.isArray(a)) {
|
|
5461
|
+
throw new Error("Second argument to filter is not an array");
|
|
5462
|
+
}
|
|
5463
|
+
return a.filter(function(x, i) {
|
|
5464
|
+
return f(x, i);
|
|
5465
|
+
});
|
|
5466
|
+
}
|
|
5467
|
+
function stringOrArrayIndexOf(target, s) {
|
|
5468
|
+
if (!(Array.isArray(s) || typeof s === "string")) {
|
|
5469
|
+
throw new Error("Second argument to indexOf is not a string or array");
|
|
5470
|
+
}
|
|
5471
|
+
return s.indexOf(target);
|
|
5472
|
+
}
|
|
5473
|
+
function arrayJoin(sep, a) {
|
|
5474
|
+
if (!Array.isArray(a)) {
|
|
5475
|
+
throw new Error("Second argument to join is not an array");
|
|
5476
|
+
}
|
|
5477
|
+
return a.join(sep);
|
|
5478
|
+
}
|
|
5479
|
+
function sign(x) {
|
|
5480
|
+
return (x > 0) - (x < 0) || +x;
|
|
5481
|
+
}
|
|
5482
|
+
var ONE_THIRD = 1 / 3;
|
|
5483
|
+
function cbrt(x) {
|
|
5484
|
+
return x < 0 ? -Math.pow(-x, ONE_THIRD) : Math.pow(x, ONE_THIRD);
|
|
5485
|
+
}
|
|
5486
|
+
function expm1(x) {
|
|
5487
|
+
return Math.exp(x) - 1;
|
|
5488
|
+
}
|
|
5489
|
+
function log1p(x) {
|
|
5490
|
+
return Math.log(1 + x);
|
|
5491
|
+
}
|
|
5492
|
+
function log2(x) {
|
|
5493
|
+
return Math.log(x) / Math.LN2;
|
|
5494
|
+
}
|
|
5495
|
+
function Parser(options) {
|
|
5496
|
+
this.options = options || {};
|
|
5497
|
+
this.unaryOps = {
|
|
5498
|
+
sin: Math.sin,
|
|
5499
|
+
cos: Math.cos,
|
|
5500
|
+
tan: Math.tan,
|
|
5501
|
+
asin: Math.asin,
|
|
5502
|
+
acos: Math.acos,
|
|
5503
|
+
atan: Math.atan,
|
|
5504
|
+
sinh: Math.sinh || sinh,
|
|
5505
|
+
cosh: Math.cosh || cosh,
|
|
5506
|
+
tanh: Math.tanh || tanh,
|
|
5507
|
+
asinh: Math.asinh || asinh,
|
|
5508
|
+
acosh: Math.acosh || acosh,
|
|
5509
|
+
atanh: Math.atanh || atanh,
|
|
5510
|
+
sqrt: Math.sqrt,
|
|
5511
|
+
cbrt: Math.cbrt || cbrt,
|
|
5512
|
+
log: Math.log,
|
|
5513
|
+
log2: Math.log2 || log2,
|
|
5514
|
+
ln: Math.log,
|
|
5515
|
+
lg: Math.log10 || log10,
|
|
5516
|
+
log10: Math.log10 || log10,
|
|
5517
|
+
expm1: Math.expm1 || expm1,
|
|
5518
|
+
log1p: Math.log1p || log1p,
|
|
5519
|
+
abs: Math.abs,
|
|
5520
|
+
ceil: Math.ceil,
|
|
5521
|
+
floor: Math.floor,
|
|
5522
|
+
round: Math.round,
|
|
5523
|
+
trunc: Math.trunc || trunc,
|
|
5524
|
+
"-": neg,
|
|
5525
|
+
"+": Number,
|
|
5526
|
+
exp: Math.exp,
|
|
5527
|
+
not,
|
|
5528
|
+
length: stringOrArrayLength,
|
|
5529
|
+
"!": factorial,
|
|
5530
|
+
sign: Math.sign || sign
|
|
5531
|
+
};
|
|
5532
|
+
this.binaryOps = {
|
|
5533
|
+
"+": add,
|
|
5534
|
+
"-": sub,
|
|
5535
|
+
"*": mul,
|
|
5536
|
+
"/": div,
|
|
5537
|
+
"%": mod,
|
|
5538
|
+
"^": Math.pow,
|
|
5539
|
+
"||": concat,
|
|
5540
|
+
"==": equal,
|
|
5541
|
+
"!=": notEqual,
|
|
5542
|
+
">": greaterThan,
|
|
5543
|
+
"<": lessThan,
|
|
5544
|
+
">=": greaterThanEqual,
|
|
5545
|
+
"<=": lessThanEqual,
|
|
5546
|
+
and: andOperator,
|
|
5547
|
+
or: orOperator,
|
|
5548
|
+
"in": inOperator,
|
|
5549
|
+
"=": setVar,
|
|
5550
|
+
"[": arrayIndex
|
|
5551
|
+
};
|
|
5552
|
+
this.ternaryOps = {
|
|
5553
|
+
"?": condition
|
|
5554
|
+
};
|
|
5555
|
+
this.functions = {
|
|
5556
|
+
random,
|
|
5557
|
+
fac: factorial,
|
|
5558
|
+
min,
|
|
5559
|
+
max,
|
|
5560
|
+
hypot: Math.hypot || hypot,
|
|
5561
|
+
pyt: Math.hypot || hypot,
|
|
5562
|
+
// backward compat
|
|
5563
|
+
pow: Math.pow,
|
|
5564
|
+
atan2: Math.atan2,
|
|
5565
|
+
"if": condition,
|
|
5566
|
+
gamma,
|
|
5567
|
+
roundTo,
|
|
5568
|
+
map: arrayMap,
|
|
5569
|
+
fold: arrayFold,
|
|
5570
|
+
filter: arrayFilter,
|
|
5571
|
+
indexOf: stringOrArrayIndexOf,
|
|
5572
|
+
join: arrayJoin
|
|
5573
|
+
};
|
|
5574
|
+
this.consts = {
|
|
5575
|
+
E: Math.E,
|
|
5576
|
+
PI: Math.PI,
|
|
5577
|
+
"true": true,
|
|
5578
|
+
"false": false
|
|
5579
|
+
};
|
|
5580
|
+
}
|
|
5581
|
+
Parser.prototype.parse = function(expr) {
|
|
5582
|
+
var instr = [];
|
|
5583
|
+
var parserState = new ParserState(
|
|
5584
|
+
this,
|
|
5585
|
+
new TokenStream(this, expr),
|
|
5586
|
+
{ allowMemberAccess: this.options.allowMemberAccess }
|
|
5587
|
+
);
|
|
5588
|
+
parserState.parseExpression(instr);
|
|
5589
|
+
parserState.expect(TEOF, "EOF");
|
|
5590
|
+
return new Expression(instr, this);
|
|
5591
|
+
};
|
|
5592
|
+
Parser.prototype.evaluate = function(expr, variables) {
|
|
5593
|
+
return this.parse(expr).evaluate(variables);
|
|
5594
|
+
};
|
|
5595
|
+
var sharedParser = new Parser();
|
|
5596
|
+
Parser.parse = function(expr) {
|
|
5597
|
+
return sharedParser.parse(expr);
|
|
5598
|
+
};
|
|
5599
|
+
Parser.evaluate = function(expr, variables) {
|
|
5600
|
+
return sharedParser.parse(expr).evaluate(variables);
|
|
5601
|
+
};
|
|
5602
|
+
var optionNameMap = {
|
|
5603
|
+
"+": "add",
|
|
5604
|
+
"-": "subtract",
|
|
5605
|
+
"*": "multiply",
|
|
5606
|
+
"/": "divide",
|
|
5607
|
+
"%": "remainder",
|
|
5608
|
+
"^": "power",
|
|
5609
|
+
"!": "factorial",
|
|
5610
|
+
"<": "comparison",
|
|
5611
|
+
">": "comparison",
|
|
5612
|
+
"<=": "comparison",
|
|
5613
|
+
">=": "comparison",
|
|
5614
|
+
"==": "comparison",
|
|
5615
|
+
"!=": "comparison",
|
|
5616
|
+
"||": "concatenate",
|
|
5617
|
+
"and": "logical",
|
|
5618
|
+
"or": "logical",
|
|
5619
|
+
"not": "logical",
|
|
5620
|
+
"?": "conditional",
|
|
5621
|
+
":": "conditional",
|
|
5622
|
+
"=": "assignment",
|
|
5623
|
+
"[": "array",
|
|
5624
|
+
"()=": "fndef"
|
|
5625
|
+
};
|
|
5626
|
+
function getOptionName(op) {
|
|
5627
|
+
return optionNameMap.hasOwnProperty(op) ? optionNameMap[op] : op;
|
|
5628
|
+
}
|
|
5629
|
+
Parser.prototype.isOperatorEnabled = function(op) {
|
|
5630
|
+
var optionName = getOptionName(op);
|
|
5631
|
+
var operators2 = this.options.operators || {};
|
|
5632
|
+
return !(optionName in operators2) || !!operators2[optionName];
|
|
5633
|
+
};
|
|
5634
|
+
const calc = (expression, context) => {
|
|
5635
|
+
if (typeof expression !== "string") {
|
|
5636
|
+
return expression;
|
|
5637
|
+
}
|
|
5638
|
+
let processedExpression = expression;
|
|
5639
|
+
try {
|
|
5640
|
+
const pathResolver = (path) => {
|
|
5641
|
+
let currentPath = path;
|
|
5642
|
+
let value;
|
|
5643
|
+
let depth = 0;
|
|
5644
|
+
while (typeof currentPath === "string" && (currentPath.startsWith("/") || currentPath.startsWith("=/")) && depth < 5) {
|
|
5645
|
+
const normalizedPath = currentPath.startsWith("/") ? "=" + currentPath : currentPath;
|
|
5646
|
+
const resolved = resolvePath(normalizedPath, context);
|
|
5647
|
+
value = unwrapSignal(resolved);
|
|
5648
|
+
if (typeof value === "string" && (value.startsWith("/") || value.startsWith("=/")) && value !== currentPath) {
|
|
5649
|
+
currentPath = value;
|
|
5650
|
+
depth++;
|
|
5651
|
+
} else {
|
|
5652
|
+
break;
|
|
5653
|
+
}
|
|
5654
|
+
}
|
|
5655
|
+
if (typeof value === "number") return value;
|
|
5656
|
+
if (typeof value === "string") {
|
|
5657
|
+
const num = parseFloat(value);
|
|
5658
|
+
if (!isNaN(num) && isFinite(Number(value))) return num;
|
|
5659
|
+
return value === "" ? 0 : `"${value.replace(/"/g, '\\"')}"`;
|
|
5660
|
+
}
|
|
5661
|
+
return value === void 0 || value === null ? 0 : value;
|
|
5662
|
+
};
|
|
5663
|
+
const pathRegex = /\$\(\s*['"](.*?)['"]\s*\)/g;
|
|
5664
|
+
processedExpression = expression.replace(pathRegex, (match2, path) => {
|
|
5665
|
+
const val = pathResolver(path);
|
|
5666
|
+
return val;
|
|
5667
|
+
});
|
|
5668
|
+
const parser = new Parser();
|
|
5669
|
+
const parsed = parser.parse(processedExpression);
|
|
5670
|
+
return parsed.evaluate();
|
|
5671
|
+
} catch (error) {
|
|
5672
|
+
console.error("JPRX calc error:", error.message);
|
|
5673
|
+
console.error("Original expression:", expression);
|
|
5674
|
+
console.error("Processed expression:", processedExpression);
|
|
5675
|
+
return NaN;
|
|
5676
|
+
}
|
|
5677
|
+
};
|
|
5678
|
+
const registerCalcHelpers = (register) => {
|
|
5679
|
+
register("calc", calc, { pathAware: true });
|
|
5680
|
+
};
|
|
5681
|
+
const registerDOMHelpers = (registerHelper2) => {
|
|
5682
|
+
registerHelper2("xpath", function(expression) {
|
|
5683
|
+
const domNode = this;
|
|
5684
|
+
if (!domNode || !(domNode instanceof Element)) {
|
|
5685
|
+
console.warn("[Lightview-CDOM] xpath() called without valid DOM context");
|
|
5686
|
+
return "";
|
|
5687
|
+
}
|
|
5688
|
+
const forbiddenAxes = /\b(child|descendant|following|following-sibling)::/;
|
|
5689
|
+
if (forbiddenAxes.test(expression)) {
|
|
5690
|
+
console.error(`[Lightview-CDOM] xpath(): Forward-looking axes not allowed: ${expression}`);
|
|
5691
|
+
return "";
|
|
5692
|
+
}
|
|
5693
|
+
const hasShorthandChild = /\/[a-zA-Z]/.test(expression) && !expression.startsWith("/html");
|
|
5694
|
+
if (hasShorthandChild) {
|
|
5695
|
+
console.error(`[Lightview-CDOM] xpath(): Shorthand child axis (/) not allowed: ${expression}`);
|
|
5696
|
+
return "";
|
|
5697
|
+
}
|
|
5698
|
+
const LV = globalThis.Lightview;
|
|
5699
|
+
if (!LV || !LV.computed) {
|
|
5700
|
+
console.warn("[Lightview-CDOM] xpath(): Lightview not available");
|
|
5701
|
+
return "";
|
|
5702
|
+
}
|
|
5703
|
+
return LV.computed(() => {
|
|
5704
|
+
try {
|
|
5705
|
+
const result = document.evaluate(
|
|
5706
|
+
expression,
|
|
5707
|
+
domNode,
|
|
5708
|
+
null,
|
|
5709
|
+
XPathResult.STRING_TYPE,
|
|
5710
|
+
null
|
|
5711
|
+
);
|
|
5712
|
+
return result.stringValue;
|
|
5713
|
+
} catch (e) {
|
|
5714
|
+
console.error(`[Lightview-CDOM] xpath() evaluation failed:`, e.message);
|
|
5715
|
+
return "";
|
|
5716
|
+
}
|
|
5717
|
+
});
|
|
5718
|
+
}, { pathAware: false });
|
|
5719
|
+
};
|
|
5720
|
+
registerMathHelpers(registerHelper);
|
|
5721
|
+
registerLogicHelpers(registerHelper);
|
|
5722
|
+
registerStringHelpers(registerHelper);
|
|
5723
|
+
registerArrayHelpers(registerHelper);
|
|
5724
|
+
registerCompareHelpers(registerHelper);
|
|
5725
|
+
registerConditionalHelpers(registerHelper);
|
|
5726
|
+
registerDateTimeHelpers(registerHelper);
|
|
5727
|
+
registerFormatHelpers(registerHelper);
|
|
5728
|
+
registerLookupHelpers(registerHelper);
|
|
5729
|
+
registerStatsHelpers(registerHelper);
|
|
5730
|
+
registerStateHelpers((name, fn) => registerHelper(name, fn, { pathAware: true }));
|
|
5731
|
+
registerNetworkHelpers(registerHelper);
|
|
5732
|
+
registerCalcHelpers(registerHelper);
|
|
5733
|
+
registerDOMHelpers(registerHelper);
|
|
5734
|
+
registerHelper("move", (selector, location = "beforeend") => {
|
|
5735
|
+
return {
|
|
5736
|
+
isLazy: true,
|
|
5737
|
+
resolve: (eventOrNode) => {
|
|
5738
|
+
const isEvent = eventOrNode && typeof eventOrNode === "object" && "target" in eventOrNode;
|
|
5739
|
+
const node = isEvent ? eventOrNode.currentTarget || eventOrNode.target : eventOrNode;
|
|
5740
|
+
if (!(node instanceof Node) || !selector) return;
|
|
5741
|
+
const target = document.querySelector(selector);
|
|
5742
|
+
if (!target) {
|
|
5743
|
+
console.warn(`[Lightview-CDOM] move target not found: ${selector}`);
|
|
5744
|
+
return;
|
|
5745
|
+
}
|
|
5746
|
+
if (node.id) {
|
|
5747
|
+
const escapedId = CSS.escape(node.id);
|
|
5748
|
+
if (target.id === node.id && target !== node) {
|
|
5749
|
+
target.replaceWith(node);
|
|
5750
|
+
return;
|
|
5751
|
+
}
|
|
5752
|
+
const existing = target.querySelector(`#${escapedId}`);
|
|
5753
|
+
if (existing && existing !== node) {
|
|
5754
|
+
existing.replaceWith(node);
|
|
5755
|
+
return;
|
|
5756
|
+
}
|
|
5757
|
+
}
|
|
5758
|
+
globalThis.Lightview.$(target).content(node, location);
|
|
5759
|
+
}
|
|
5760
|
+
};
|
|
5761
|
+
}, { pathAware: true });
|
|
5762
|
+
registerHelper("mount", async (url, options = {}) => {
|
|
5763
|
+
const { target = "body", location = "beforeend" } = options;
|
|
5764
|
+
try {
|
|
5765
|
+
const fetchOptions = { ...options };
|
|
5766
|
+
delete fetchOptions.target;
|
|
5767
|
+
delete fetchOptions.location;
|
|
5768
|
+
const headers = { ...fetchOptions.headers };
|
|
5769
|
+
let body = fetchOptions.body;
|
|
5770
|
+
if (body !== void 0) {
|
|
5771
|
+
if (body !== null && typeof body === "object") {
|
|
5772
|
+
body = JSON.stringify(body);
|
|
5773
|
+
if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
|
|
5774
|
+
} else {
|
|
5775
|
+
body = String(body);
|
|
5776
|
+
if (!headers["Content-Type"]) headers["Content-Type"] = "text/plain";
|
|
5777
|
+
}
|
|
5778
|
+
fetchOptions.body = body;
|
|
5779
|
+
fetchOptions.headers = headers;
|
|
5780
|
+
}
|
|
5781
|
+
const response = await globalThis.fetch(url, fetchOptions);
|
|
5782
|
+
const contentType = response.headers.get("Content-Type") || "";
|
|
5783
|
+
const text = await response.text();
|
|
5784
|
+
let content = text;
|
|
5785
|
+
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");
|
|
5786
|
+
if (isCDOM || contentType.includes("application/json") && text.trim().startsWith("{")) {
|
|
5787
|
+
try {
|
|
5788
|
+
content = hydrate(parseJPRX(text));
|
|
5789
|
+
} catch (e) {
|
|
5790
|
+
}
|
|
5791
|
+
}
|
|
5792
|
+
const targetEl = document.querySelector(target);
|
|
5793
|
+
if (targetEl) {
|
|
5794
|
+
globalThis.Lightview.$(targetEl).content(content, location);
|
|
5795
|
+
} else {
|
|
5796
|
+
console.warn(`[Lightview-CDOM] $mount target not found: ${target}`);
|
|
5797
|
+
}
|
|
5798
|
+
} catch (err) {
|
|
5799
|
+
console.error(`[Lightview-CDOM] $mount failed for ${url}:`, err);
|
|
5800
|
+
}
|
|
5801
|
+
});
|
|
5802
|
+
registerOperator("increment", "++", "prefix", 80);
|
|
5803
|
+
registerOperator("increment", "++", "postfix", 80);
|
|
5804
|
+
registerOperator("decrement", "--", "prefix", 80);
|
|
5805
|
+
registerOperator("decrement", "--", "postfix", 80);
|
|
5806
|
+
registerOperator("toggle", "!!", "prefix", 80);
|
|
5807
|
+
registerOperator("set", "=", "infix", 20);
|
|
5808
|
+
registerOperator("+", "+", "infix", 50);
|
|
5809
|
+
registerOperator("-", "-", "infix", 50, { requiresWhitespace: true });
|
|
5810
|
+
registerOperator("*", "*", "infix", 60, { requiresWhitespace: true });
|
|
5811
|
+
registerOperator("/", "/", "infix", 60, { requiresWhitespace: true });
|
|
3812
5812
|
registerOperator("gt", ">", "infix", 40);
|
|
3813
5813
|
registerOperator("lt", "<", "infix", 40);
|
|
3814
5814
|
registerOperator("gte", ">=", "infix", 40);
|
|
3815
5815
|
registerOperator("lte", "<=", "infix", 40);
|
|
3816
5816
|
registerOperator("neq", "!=", "infix", 40);
|
|
5817
|
+
registerOperator("strictNeq", "!==", "infix", 40);
|
|
5818
|
+
registerOperator("eq", "==", "infix", 40);
|
|
5819
|
+
registerOperator("strictEq", "===", "infix", 40);
|
|
3817
5820
|
const getContext = (node, event = null) => {
|
|
3818
5821
|
return new Proxy({}, {
|
|
3819
5822
|
get(_, prop) {
|
|
@@ -3865,8 +5868,8 @@
|
|
|
3865
5868
|
const isEvent = eventOrNode && typeof eventOrNode === "object" && "target" in eventOrNode;
|
|
3866
5869
|
const target = isEvent ? eventOrNode.currentTarget || eventOrNode.target : eventOrNode;
|
|
3867
5870
|
const context = getContext(target, isEvent ? eventOrNode : null);
|
|
3868
|
-
const result = resolveExpression(expr, context);
|
|
3869
|
-
if (result && typeof result === "object" && result.isLazy) return result.resolve(
|
|
5871
|
+
const result = resolveExpression$1(expr, context);
|
|
5872
|
+
if (result && typeof result === "object" && result.isLazy) return result.resolve(context);
|
|
3870
5873
|
return result;
|
|
3871
5874
|
};
|
|
3872
5875
|
const hydrate = (node, parent = null) => {
|
|
@@ -3875,6 +5878,12 @@
|
|
|
3875
5878
|
if (typeof node === "string" && node.startsWith("'=")) {
|
|
3876
5879
|
return node.slice(1);
|
|
3877
5880
|
}
|
|
5881
|
+
if (typeof node === "string" && node.startsWith("'#")) {
|
|
5882
|
+
return node.slice(1);
|
|
5883
|
+
}
|
|
5884
|
+
if (typeof node === "string" && node.startsWith("#")) {
|
|
5885
|
+
return { __xpath__: node.slice(1), __static__: true };
|
|
5886
|
+
}
|
|
3878
5887
|
if (typeof node === "string" && node.startsWith("=")) {
|
|
3879
5888
|
return parseExpression(node, parent);
|
|
3880
5889
|
}
|
|
@@ -3918,6 +5927,10 @@
|
|
|
3918
5927
|
const attrVal = value[attrKey];
|
|
3919
5928
|
if (typeof attrVal === "string" && attrVal.startsWith("'=")) {
|
|
3920
5929
|
value[attrKey] = attrVal.slice(1);
|
|
5930
|
+
} else if (typeof attrVal === "string" && attrVal.startsWith("'#")) {
|
|
5931
|
+
value[attrKey] = attrVal.slice(1);
|
|
5932
|
+
} else if (typeof attrVal === "string" && attrVal.startsWith("#")) {
|
|
5933
|
+
value[attrKey] = { __xpath__: attrVal.slice(1), __static__: true };
|
|
3921
5934
|
} else if (typeof attrVal === "string" && attrVal.startsWith("=")) {
|
|
3922
5935
|
if (attrKey.startsWith("on")) {
|
|
3923
5936
|
value[attrKey] = makeEventHandler(attrVal);
|
|
@@ -3932,6 +5945,10 @@
|
|
|
3932
5945
|
}
|
|
3933
5946
|
if (typeof value === "string" && value.startsWith("'=")) {
|
|
3934
5947
|
node[key] = value.slice(1);
|
|
5948
|
+
} else if (typeof value === "string" && value.startsWith("'#")) {
|
|
5949
|
+
node[key] = value.slice(1);
|
|
5950
|
+
} else if (typeof value === "string" && value.startsWith("#")) {
|
|
5951
|
+
node[key] = { __xpath__: value.slice(1), __static__: true };
|
|
3935
5952
|
} else if (typeof value === "string" && value.startsWith("=")) {
|
|
3936
5953
|
if (key === "onmount" || key === "onunmount" || key.startsWith("on")) {
|
|
3937
5954
|
node[key] = makeEventHandler(value);
|
|
@@ -3946,13 +5963,82 @@
|
|
|
3946
5963
|
}
|
|
3947
5964
|
return node;
|
|
3948
5965
|
};
|
|
5966
|
+
const validateXPath = (xpath) => {
|
|
5967
|
+
const forbiddenAxes = /\b(child|descendant|following|following-sibling)::/;
|
|
5968
|
+
if (forbiddenAxes.test(xpath)) {
|
|
5969
|
+
throw new Error(`XPath: Forward-looking axes not allowed during DOM construction: ${xpath}`);
|
|
5970
|
+
}
|
|
5971
|
+
const hasShorthandChild = /\/[a-zA-Z]/.test(xpath) && !xpath.startsWith("/html");
|
|
5972
|
+
if (hasShorthandChild) {
|
|
5973
|
+
throw new Error(`XPath: Shorthand child axis (/) not allowed during DOM construction: ${xpath}`);
|
|
5974
|
+
}
|
|
5975
|
+
};
|
|
5976
|
+
const resolveStaticXPath = (rootNode) => {
|
|
5977
|
+
var _a2, _b2;
|
|
5978
|
+
if (!rootNode || !rootNode.nodeType) return;
|
|
5979
|
+
const walker = document.createTreeWalker(
|
|
5980
|
+
rootNode,
|
|
5981
|
+
NodeFilter.SHOW_ALL
|
|
5982
|
+
);
|
|
5983
|
+
const nodesToProcess = [];
|
|
5984
|
+
let node = walker.nextNode();
|
|
5985
|
+
while (node) {
|
|
5986
|
+
nodesToProcess.push(node);
|
|
5987
|
+
node = walker.nextNode();
|
|
5988
|
+
}
|
|
5989
|
+
for (const node2 of nodesToProcess) {
|
|
5990
|
+
if (node2.nodeType === Node.ELEMENT_NODE) {
|
|
5991
|
+
const attributes = [...node2.attributes];
|
|
5992
|
+
for (const attr of attributes) {
|
|
5993
|
+
if (attr.name.startsWith("data-xpath-")) {
|
|
5994
|
+
const realAttr = attr.name.replace("data-xpath-", "");
|
|
5995
|
+
const xpath = attr.value;
|
|
5996
|
+
try {
|
|
5997
|
+
validateXPath(xpath);
|
|
5998
|
+
const result = document.evaluate(
|
|
5999
|
+
xpath,
|
|
6000
|
+
node2,
|
|
6001
|
+
null,
|
|
6002
|
+
XPathResult.STRING_TYPE,
|
|
6003
|
+
null
|
|
6004
|
+
);
|
|
6005
|
+
node2.setAttribute(realAttr, result.stringValue);
|
|
6006
|
+
node2.removeAttribute(attr.name);
|
|
6007
|
+
} catch (e) {
|
|
6008
|
+
(_a2 = globalThis.console) == null ? void 0 : _a2.error(`[Lightview-CDOM] XPath resolution failed for attribute "${realAttr}":`, e.message);
|
|
6009
|
+
}
|
|
6010
|
+
}
|
|
6011
|
+
}
|
|
6012
|
+
}
|
|
6013
|
+
if (node2.__xpathExpr) {
|
|
6014
|
+
const xpath = node2.__xpathExpr;
|
|
6015
|
+
try {
|
|
6016
|
+
validateXPath(xpath);
|
|
6017
|
+
const result = document.evaluate(
|
|
6018
|
+
xpath,
|
|
6019
|
+
node2,
|
|
6020
|
+
// Use text node as context, not its parent!
|
|
6021
|
+
null,
|
|
6022
|
+
XPathResult.STRING_TYPE,
|
|
6023
|
+
null
|
|
6024
|
+
);
|
|
6025
|
+
node2.textContent = result.stringValue;
|
|
6026
|
+
delete node2.__xpathExpr;
|
|
6027
|
+
} catch (e) {
|
|
6028
|
+
(_b2 = globalThis.console) == null ? void 0 : _b2.error(`[Lightview-CDOM] XPath resolution failed for text node:`, e.message);
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
6031
|
+
}
|
|
6032
|
+
};
|
|
6033
|
+
if (typeof parseCDOMC !== "function") throw new Error("parseCDOMC not found");
|
|
6034
|
+
if (typeof parseJPRX !== "function") throw new Error("parseJPRX not found");
|
|
3949
6035
|
const LightviewCDOM = {
|
|
3950
6036
|
registerHelper,
|
|
3951
6037
|
registerOperator,
|
|
3952
6038
|
parseExpression,
|
|
3953
6039
|
resolvePath,
|
|
3954
6040
|
resolvePathAsContext,
|
|
3955
|
-
resolveExpression,
|
|
6041
|
+
resolveExpression: resolveExpression$1,
|
|
3956
6042
|
parseCDOMC,
|
|
3957
6043
|
parseJPRX,
|
|
3958
6044
|
unwrapSignal,
|
|
@@ -3963,10 +6049,12 @@
|
|
|
3963
6049
|
},
|
|
3964
6050
|
activate,
|
|
3965
6051
|
hydrate,
|
|
6052
|
+
resolveStaticXPath,
|
|
3966
6053
|
version: "1.0.0"
|
|
3967
6054
|
};
|
|
3968
6055
|
if (typeof window !== "undefined") {
|
|
3969
|
-
globalThis.LightviewCDOM =
|
|
6056
|
+
globalThis.LightviewCDOM = {};
|
|
6057
|
+
Object.assign(globalThis.LightviewCDOM, LightviewCDOM);
|
|
3970
6058
|
}
|
|
3971
6059
|
console.log("Lightview Full Bundle Loaded");
|
|
3972
6060
|
})();
|