@constela/runtime 5.0.5 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -9
- package/dist/index.js +45 -618
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -108,16 +108,10 @@ declare function createTypedStateStore<T extends Record<string, unknown>>(defini
|
|
|
108
108
|
}): TypedStateStore<T>;
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
|
-
* Expression Evaluator -
|
|
111
|
+
* Expression Evaluator - CSR wrapper around unified @constela/core evaluate
|
|
112
112
|
*
|
|
113
|
-
*
|
|
114
|
-
* -
|
|
115
|
-
* - State reads (state)
|
|
116
|
-
* - Variable reads (var)
|
|
117
|
-
* - Binary operations (bin)
|
|
118
|
-
* - Not operation (not)
|
|
119
|
-
* - Conditional expressions (cond)
|
|
120
|
-
* - Property access (get)
|
|
113
|
+
* Delegates all expression evaluation to the core module,
|
|
114
|
+
* providing a CSR-specific EnvironmentAdapter for DOM refs, validity, and globals.
|
|
121
115
|
*/
|
|
122
116
|
|
|
123
117
|
/**
|
|
@@ -155,6 +149,10 @@ interface StyleExprInput {
|
|
|
155
149
|
/**
|
|
156
150
|
* Evaluates a style expression to produce CSS class names
|
|
157
151
|
*
|
|
152
|
+
* CSR wrapper: delegates to core evaluateStyle, converting '' to undefined
|
|
153
|
+
* for backward compatibility (core returns '' when preset not found,
|
|
154
|
+
* CSR returns undefined).
|
|
155
|
+
*
|
|
158
156
|
* @param expr - The style expression to evaluate
|
|
159
157
|
* @param ctx - The evaluation context containing styles presets
|
|
160
158
|
* @returns The computed CSS class string, or undefined if preset not found
|
package/dist/index.js
CHANGED
|
@@ -376,504 +376,55 @@ function createTypedStateStore(definitions) {
|
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
// src/expression/evaluator.ts
|
|
379
|
-
import {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
"indexOf",
|
|
386
|
-
"join",
|
|
387
|
-
"filter",
|
|
388
|
-
"map",
|
|
389
|
-
"find",
|
|
390
|
-
"findIndex",
|
|
391
|
-
"some",
|
|
392
|
-
"every"
|
|
393
|
-
]);
|
|
394
|
-
var SAFE_STRING_METHODS = /* @__PURE__ */ new Set([
|
|
395
|
-
"length",
|
|
396
|
-
"charAt",
|
|
397
|
-
"substring",
|
|
398
|
-
"slice",
|
|
399
|
-
"split",
|
|
400
|
-
"trim",
|
|
401
|
-
"toUpperCase",
|
|
402
|
-
"toLowerCase",
|
|
403
|
-
"replace",
|
|
404
|
-
"includes",
|
|
405
|
-
"startsWith",
|
|
406
|
-
"endsWith",
|
|
407
|
-
"indexOf"
|
|
408
|
-
]);
|
|
409
|
-
var SAFE_MATH_METHODS = /* @__PURE__ */ new Set([
|
|
410
|
-
"min",
|
|
411
|
-
"max",
|
|
412
|
-
"round",
|
|
413
|
-
"floor",
|
|
414
|
-
"ceil",
|
|
415
|
-
"abs",
|
|
416
|
-
"sqrt",
|
|
417
|
-
"pow",
|
|
418
|
-
"random",
|
|
419
|
-
"sin",
|
|
420
|
-
"cos",
|
|
421
|
-
"tan"
|
|
422
|
-
]);
|
|
423
|
-
var SAFE_DATE_STATIC_METHODS = /* @__PURE__ */ new Set([
|
|
424
|
-
"now",
|
|
425
|
-
"parse"
|
|
426
|
-
]);
|
|
427
|
-
var SAFE_DATE_INSTANCE_METHODS = /* @__PURE__ */ new Set([
|
|
428
|
-
"toISOString",
|
|
429
|
-
"toDateString",
|
|
430
|
-
"toTimeString",
|
|
431
|
-
"getTime",
|
|
432
|
-
"getFullYear",
|
|
433
|
-
"getMonth",
|
|
434
|
-
"getDate",
|
|
435
|
-
"getHours",
|
|
436
|
-
"getMinutes",
|
|
437
|
-
"getSeconds",
|
|
438
|
-
"getMilliseconds"
|
|
439
|
-
]);
|
|
440
|
-
function createLambdaFunction(lambda, ctx) {
|
|
441
|
-
return (item, index) => {
|
|
442
|
-
const lambdaLocals = {
|
|
443
|
-
...ctx.locals,
|
|
444
|
-
[lambda.param]: item
|
|
445
|
-
};
|
|
446
|
-
if (lambda.index !== void 0) {
|
|
447
|
-
lambdaLocals[lambda.index] = index;
|
|
448
|
-
}
|
|
449
|
-
return evaluate(lambda.body, { ...ctx, locals: lambdaLocals });
|
|
450
|
-
};
|
|
451
|
-
}
|
|
452
|
-
function callArrayMethod(target, method, args, ctx, rawArgs) {
|
|
453
|
-
if (!SAFE_ARRAY_METHODS.has(method)) {
|
|
454
|
-
return void 0;
|
|
455
|
-
}
|
|
456
|
-
switch (method) {
|
|
457
|
-
case "length":
|
|
458
|
-
return target.length;
|
|
459
|
-
case "at": {
|
|
460
|
-
const index = typeof args[0] === "number" ? args[0] : 0;
|
|
461
|
-
return target.at(index);
|
|
462
|
-
}
|
|
463
|
-
case "includes": {
|
|
464
|
-
const searchElement = args[0];
|
|
465
|
-
const fromIndex = typeof args[1] === "number" ? args[1] : void 0;
|
|
466
|
-
return target.includes(searchElement, fromIndex);
|
|
467
|
-
}
|
|
468
|
-
case "slice": {
|
|
469
|
-
const start = typeof args[0] === "number" ? args[0] : void 0;
|
|
470
|
-
const end = typeof args[1] === "number" ? args[1] : void 0;
|
|
471
|
-
return target.slice(start, end);
|
|
472
|
-
}
|
|
473
|
-
case "indexOf": {
|
|
474
|
-
const searchElement = args[0];
|
|
475
|
-
const fromIndex = typeof args[1] === "number" ? args[1] : void 0;
|
|
476
|
-
return target.indexOf(searchElement, fromIndex);
|
|
477
|
-
}
|
|
478
|
-
case "join": {
|
|
479
|
-
const separator = typeof args[0] === "string" ? args[0] : ",";
|
|
480
|
-
return target.join(separator);
|
|
481
|
-
}
|
|
482
|
-
case "filter": {
|
|
483
|
-
const lambdaExpr = rawArgs?.[0];
|
|
484
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
485
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
486
|
-
return target.filter((item, index) => !!fn(item, index));
|
|
487
|
-
}
|
|
488
|
-
case "map": {
|
|
489
|
-
const lambdaExpr = rawArgs?.[0];
|
|
490
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
491
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
492
|
-
return target.map((item, index) => fn(item, index));
|
|
493
|
-
}
|
|
494
|
-
case "find": {
|
|
495
|
-
const lambdaExpr = rawArgs?.[0];
|
|
496
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
497
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
498
|
-
return target.find((item, index) => !!fn(item, index));
|
|
499
|
-
}
|
|
500
|
-
case "findIndex": {
|
|
501
|
-
const lambdaExpr = rawArgs?.[0];
|
|
502
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
503
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
504
|
-
return target.findIndex((item, index) => !!fn(item, index));
|
|
505
|
-
}
|
|
506
|
-
case "some": {
|
|
507
|
-
const lambdaExpr = rawArgs?.[0];
|
|
508
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
509
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
510
|
-
return target.some((item, index) => !!fn(item, index));
|
|
511
|
-
}
|
|
512
|
-
case "every": {
|
|
513
|
-
const lambdaExpr = rawArgs?.[0];
|
|
514
|
-
if (!lambdaExpr || lambdaExpr.expr !== "lambda") return void 0;
|
|
515
|
-
const fn = createLambdaFunction(lambdaExpr, ctx);
|
|
516
|
-
return target.every((item, index) => !!fn(item, index));
|
|
517
|
-
}
|
|
518
|
-
default:
|
|
519
|
-
return void 0;
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
function callStringMethod(target, method, args) {
|
|
523
|
-
if (!SAFE_STRING_METHODS.has(method)) {
|
|
524
|
-
return void 0;
|
|
525
|
-
}
|
|
526
|
-
switch (method) {
|
|
527
|
-
case "length":
|
|
528
|
-
return target.length;
|
|
529
|
-
case "charAt": {
|
|
530
|
-
const index = typeof args[0] === "number" ? args[0] : 0;
|
|
531
|
-
return target.charAt(index);
|
|
532
|
-
}
|
|
533
|
-
case "substring": {
|
|
534
|
-
const start = typeof args[0] === "number" ? args[0] : 0;
|
|
535
|
-
const end = typeof args[1] === "number" ? args[1] : void 0;
|
|
536
|
-
return target.substring(start, end);
|
|
537
|
-
}
|
|
538
|
-
case "slice": {
|
|
539
|
-
const start = typeof args[0] === "number" ? args[0] : void 0;
|
|
540
|
-
const end = typeof args[1] === "number" ? args[1] : void 0;
|
|
541
|
-
return target.slice(start, end);
|
|
542
|
-
}
|
|
543
|
-
case "split": {
|
|
544
|
-
const separator = typeof args[0] === "string" ? args[0] : "";
|
|
545
|
-
return target.split(separator);
|
|
546
|
-
}
|
|
547
|
-
case "trim":
|
|
548
|
-
return target.trim();
|
|
549
|
-
case "toUpperCase":
|
|
550
|
-
return target.toUpperCase();
|
|
551
|
-
case "toLowerCase":
|
|
552
|
-
return target.toLowerCase();
|
|
553
|
-
case "replace": {
|
|
554
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
555
|
-
const replace = typeof args[1] === "string" ? args[1] : "";
|
|
556
|
-
return target.replace(search, replace);
|
|
557
|
-
}
|
|
558
|
-
case "includes": {
|
|
559
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
560
|
-
const position = typeof args[1] === "number" ? args[1] : void 0;
|
|
561
|
-
return target.includes(search, position);
|
|
562
|
-
}
|
|
563
|
-
case "startsWith": {
|
|
564
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
565
|
-
const position = typeof args[1] === "number" ? args[1] : void 0;
|
|
566
|
-
return target.startsWith(search, position);
|
|
567
|
-
}
|
|
568
|
-
case "endsWith": {
|
|
569
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
570
|
-
const length = typeof args[1] === "number" ? args[1] : void 0;
|
|
571
|
-
return target.endsWith(search, length);
|
|
572
|
-
}
|
|
573
|
-
case "indexOf": {
|
|
574
|
-
const search = typeof args[0] === "string" ? args[0] : "";
|
|
575
|
-
const position = typeof args[1] === "number" ? args[1] : void 0;
|
|
576
|
-
return target.indexOf(search, position);
|
|
577
|
-
}
|
|
578
|
-
default:
|
|
579
|
-
return void 0;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
function callMathMethod(method, args) {
|
|
583
|
-
if (!SAFE_MATH_METHODS.has(method)) {
|
|
584
|
-
return void 0;
|
|
585
|
-
}
|
|
586
|
-
const numbers = args.filter((a) => typeof a === "number");
|
|
587
|
-
switch (method) {
|
|
588
|
-
case "min":
|
|
589
|
-
return numbers.length > 0 ? Math.min(...numbers) : void 0;
|
|
590
|
-
case "max":
|
|
591
|
-
return numbers.length > 0 ? Math.max(...numbers) : void 0;
|
|
592
|
-
case "round": {
|
|
593
|
-
const num = numbers[0];
|
|
594
|
-
return num !== void 0 ? Math.round(num) : void 0;
|
|
595
|
-
}
|
|
596
|
-
case "floor": {
|
|
597
|
-
const num = numbers[0];
|
|
598
|
-
return num !== void 0 ? Math.floor(num) : void 0;
|
|
599
|
-
}
|
|
600
|
-
case "ceil": {
|
|
601
|
-
const num = numbers[0];
|
|
602
|
-
return num !== void 0 ? Math.ceil(num) : void 0;
|
|
603
|
-
}
|
|
604
|
-
case "abs": {
|
|
605
|
-
const num = numbers[0];
|
|
606
|
-
return num !== void 0 ? Math.abs(num) : void 0;
|
|
607
|
-
}
|
|
608
|
-
case "sqrt": {
|
|
609
|
-
const num = numbers[0];
|
|
610
|
-
return num !== void 0 ? Math.sqrt(num) : void 0;
|
|
611
|
-
}
|
|
612
|
-
case "pow": {
|
|
613
|
-
const base = numbers[0];
|
|
614
|
-
const exponent = numbers[1];
|
|
615
|
-
return base !== void 0 && exponent !== void 0 ? Math.pow(base, exponent) : void 0;
|
|
616
|
-
}
|
|
617
|
-
case "random":
|
|
618
|
-
return Math.random();
|
|
619
|
-
case "sin": {
|
|
620
|
-
const num = numbers[0];
|
|
621
|
-
return num !== void 0 ? Math.sin(num) : void 0;
|
|
622
|
-
}
|
|
623
|
-
case "cos": {
|
|
624
|
-
const num = numbers[0];
|
|
625
|
-
return num !== void 0 ? Math.cos(num) : void 0;
|
|
626
|
-
}
|
|
627
|
-
case "tan": {
|
|
628
|
-
const num = numbers[0];
|
|
629
|
-
return num !== void 0 ? Math.tan(num) : void 0;
|
|
630
|
-
}
|
|
631
|
-
default:
|
|
632
|
-
return void 0;
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
function callDateStaticMethod(method, args) {
|
|
636
|
-
if (!SAFE_DATE_STATIC_METHODS.has(method)) {
|
|
637
|
-
return void 0;
|
|
638
|
-
}
|
|
639
|
-
switch (method) {
|
|
640
|
-
case "now":
|
|
641
|
-
return Date.now();
|
|
642
|
-
case "parse": {
|
|
643
|
-
const dateString = args[0];
|
|
644
|
-
return typeof dateString === "string" ? Date.parse(dateString) : void 0;
|
|
645
|
-
}
|
|
646
|
-
default:
|
|
647
|
-
return void 0;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
function callDateInstanceMethod(target, method) {
|
|
651
|
-
if (!SAFE_DATE_INSTANCE_METHODS.has(method)) {
|
|
652
|
-
return void 0;
|
|
653
|
-
}
|
|
654
|
-
switch (method) {
|
|
655
|
-
case "toISOString":
|
|
656
|
-
return target.toISOString();
|
|
657
|
-
case "toDateString":
|
|
658
|
-
return target.toDateString();
|
|
659
|
-
case "toTimeString":
|
|
660
|
-
return target.toTimeString();
|
|
661
|
-
case "getTime":
|
|
662
|
-
return target.getTime();
|
|
663
|
-
case "getFullYear":
|
|
664
|
-
return target.getFullYear();
|
|
665
|
-
case "getMonth":
|
|
666
|
-
return target.getMonth();
|
|
667
|
-
case "getDate":
|
|
668
|
-
return target.getDate();
|
|
669
|
-
case "getHours":
|
|
670
|
-
return target.getHours();
|
|
671
|
-
case "getMinutes":
|
|
672
|
-
return target.getMinutes();
|
|
673
|
-
case "getSeconds":
|
|
674
|
-
return target.getSeconds();
|
|
675
|
-
case "getMilliseconds":
|
|
676
|
-
return target.getMilliseconds();
|
|
677
|
-
default:
|
|
678
|
-
return void 0;
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
function evaluate(expr, ctx) {
|
|
682
|
-
switch (expr.expr) {
|
|
683
|
-
case "lit":
|
|
684
|
-
return expr.value;
|
|
685
|
-
case "state": {
|
|
686
|
-
const stateValue = ctx.state.get(expr.name);
|
|
687
|
-
if (expr.path && stateValue != null) {
|
|
688
|
-
return getNestedValue(stateValue, expr.path);
|
|
689
|
-
}
|
|
690
|
-
return stateValue;
|
|
691
|
-
}
|
|
692
|
-
case "local":
|
|
693
|
-
return ctx.locals[expr.name];
|
|
694
|
-
case "var": {
|
|
695
|
-
let varName = expr.name;
|
|
696
|
-
let pathParts = [];
|
|
697
|
-
if (varName.includes(".")) {
|
|
698
|
-
const parts = varName.split(".");
|
|
699
|
-
varName = parts[0];
|
|
700
|
-
pathParts = parts.slice(1);
|
|
701
|
-
}
|
|
702
|
-
if (expr.path) {
|
|
703
|
-
pathParts = pathParts.concat(expr.path.split("."));
|
|
704
|
-
}
|
|
705
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
706
|
-
for (const part of pathParts) {
|
|
707
|
-
if (forbiddenKeys.has(part)) {
|
|
708
|
-
return void 0;
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
let value = ctx.locals[varName];
|
|
712
|
-
if (value === void 0) {
|
|
713
|
-
const safeGlobals = {
|
|
714
|
-
JSON,
|
|
715
|
-
Math,
|
|
716
|
-
Date,
|
|
717
|
-
Object,
|
|
718
|
-
Array,
|
|
719
|
-
String,
|
|
720
|
-
Number,
|
|
721
|
-
Boolean,
|
|
722
|
-
console,
|
|
723
|
-
...GLOBAL_FUNCTIONS
|
|
724
|
-
};
|
|
725
|
-
value = safeGlobals[varName];
|
|
726
|
-
}
|
|
727
|
-
for (const part of pathParts) {
|
|
728
|
-
if (value == null) break;
|
|
729
|
-
value = value[part];
|
|
730
|
-
}
|
|
731
|
-
if (typeof value === "function" && pathParts.length > 0) {
|
|
732
|
-
let parent = ctx.locals[varName];
|
|
733
|
-
if (parent === void 0) {
|
|
734
|
-
const safeGlobals = { JSON, Math, Date, Object, Array, String, Number, Boolean, console, ...GLOBAL_FUNCTIONS };
|
|
735
|
-
parent = safeGlobals[varName];
|
|
736
|
-
}
|
|
737
|
-
for (let i = 0; i < pathParts.length - 1; i++) {
|
|
738
|
-
if (parent == null) break;
|
|
739
|
-
parent = parent[pathParts[i]];
|
|
740
|
-
}
|
|
741
|
-
if (parent != null) {
|
|
742
|
-
return value.bind(parent);
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
return value;
|
|
746
|
-
}
|
|
747
|
-
case "bin":
|
|
748
|
-
return evaluateBinary(expr.op, expr.left, expr.right, ctx);
|
|
749
|
-
case "not":
|
|
750
|
-
return !evaluate(expr.operand, ctx);
|
|
751
|
-
case "cond":
|
|
752
|
-
return evaluate(expr.if, ctx) ? evaluate(expr.then, ctx) : evaluate(expr.else, ctx);
|
|
753
|
-
case "get": {
|
|
754
|
-
const baseValue = evaluate(expr.base, ctx);
|
|
755
|
-
if (baseValue == null) return void 0;
|
|
756
|
-
const pathParts = expr.path.split(".");
|
|
757
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
758
|
-
let value = baseValue;
|
|
759
|
-
for (const part of pathParts) {
|
|
760
|
-
if (forbiddenKeys.has(part)) return void 0;
|
|
761
|
-
if (value == null) return void 0;
|
|
762
|
-
value = value[part];
|
|
763
|
-
}
|
|
764
|
-
return value;
|
|
765
|
-
}
|
|
766
|
-
case "route": {
|
|
767
|
-
const source = expr.source ?? "param";
|
|
768
|
-
const routeCtx = ctx.route;
|
|
769
|
-
if (!routeCtx) return "";
|
|
770
|
-
switch (source) {
|
|
771
|
-
case "param":
|
|
772
|
-
return routeCtx.params[expr.name] ?? "";
|
|
773
|
-
case "query":
|
|
774
|
-
return routeCtx.query[expr.name] ?? "";
|
|
775
|
-
case "path":
|
|
776
|
-
return routeCtx.path;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
case "import": {
|
|
780
|
-
const importData = ctx.imports?.[expr.name];
|
|
781
|
-
if (importData === void 0) return void 0;
|
|
782
|
-
if (expr.path) {
|
|
783
|
-
return getNestedValue(importData, expr.path);
|
|
784
|
-
}
|
|
785
|
-
return importData;
|
|
786
|
-
}
|
|
787
|
-
case "ref":
|
|
788
|
-
return ctx.refs?.[expr.name] ?? null;
|
|
789
|
-
case "index": {
|
|
790
|
-
const base = evaluate(expr.base, ctx);
|
|
791
|
-
const key2 = evaluate(expr.key, ctx);
|
|
792
|
-
if (base == null || key2 == null) return void 0;
|
|
793
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
794
|
-
if (typeof key2 === "string" && forbiddenKeys.has(key2)) return void 0;
|
|
795
|
-
return base[key2];
|
|
796
|
-
}
|
|
797
|
-
case "data": {
|
|
798
|
-
const dataValue = ctx.imports?.[expr.name];
|
|
799
|
-
if (dataValue === void 0) return void 0;
|
|
800
|
-
if (expr.path) {
|
|
801
|
-
return getNestedValue(dataValue, expr.path);
|
|
802
|
-
}
|
|
803
|
-
return dataValue;
|
|
804
|
-
}
|
|
805
|
-
case "param": {
|
|
806
|
-
return void 0;
|
|
807
|
-
}
|
|
808
|
-
case "style":
|
|
809
|
-
return evaluateStyle(expr, ctx);
|
|
810
|
-
case "concat": {
|
|
811
|
-
return expr.items.map((item) => {
|
|
812
|
-
const val = evaluate(item, ctx);
|
|
813
|
-
return val == null ? "" : String(val);
|
|
814
|
-
}).join("");
|
|
815
|
-
}
|
|
816
|
-
case "validity": {
|
|
817
|
-
const element2 = ctx.refs?.[expr.ref];
|
|
379
|
+
import { evaluate as coreEvaluate, evaluateStyle as coreEvaluateStyle, GLOBAL_FUNCTIONS, FORBIDDEN_KEYS } from "@constela/core";
|
|
380
|
+
function createCSRAdapter(refs) {
|
|
381
|
+
return {
|
|
382
|
+
resolveRef: (name) => refs?.[name] ?? null,
|
|
383
|
+
resolveValidity(ref, property) {
|
|
384
|
+
const element2 = refs?.[ref];
|
|
818
385
|
if (!element2) return null;
|
|
819
386
|
const formElement = element2;
|
|
820
387
|
if (!formElement.validity) return null;
|
|
821
388
|
const validity = formElement.validity;
|
|
822
|
-
const
|
|
823
|
-
if (
|
|
389
|
+
const prop = property || "valid";
|
|
390
|
+
if (prop === "message") {
|
|
824
391
|
return formElement.validationMessage || "";
|
|
825
392
|
}
|
|
826
|
-
return validity[
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
const
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
const arrayExpr = expr;
|
|
862
|
-
return arrayExpr.elements.map((elem) => evaluate(elem, ctx));
|
|
863
|
-
}
|
|
864
|
-
case "obj": {
|
|
865
|
-
const objExpr = expr;
|
|
866
|
-
const result = {};
|
|
867
|
-
for (const [key2, value] of Object.entries(objExpr.props)) {
|
|
868
|
-
result[key2] = evaluate(value, ctx);
|
|
869
|
-
}
|
|
870
|
-
return result;
|
|
871
|
-
}
|
|
872
|
-
default: {
|
|
873
|
-
const _exhaustiveCheck = expr;
|
|
874
|
-
throw new Error(`Unknown expression type: ${JSON.stringify(_exhaustiveCheck)}`);
|
|
875
|
-
}
|
|
876
|
-
}
|
|
393
|
+
return validity[prop] ?? null;
|
|
394
|
+
},
|
|
395
|
+
resolveGlobal(name) {
|
|
396
|
+
const safeGlobals = {
|
|
397
|
+
JSON,
|
|
398
|
+
Math,
|
|
399
|
+
Date,
|
|
400
|
+
Object,
|
|
401
|
+
Array,
|
|
402
|
+
String,
|
|
403
|
+
Number,
|
|
404
|
+
Boolean,
|
|
405
|
+
console,
|
|
406
|
+
...GLOBAL_FUNCTIONS
|
|
407
|
+
};
|
|
408
|
+
return safeGlobals[name];
|
|
409
|
+
},
|
|
410
|
+
bindFunction: (fn, parent) => fn.bind(parent),
|
|
411
|
+
callFunction: (fn, args) => fn(...args)
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function toCoreContext(ctx) {
|
|
415
|
+
const core2 = {
|
|
416
|
+
state: ctx.state,
|
|
417
|
+
// StateStore has get(), satisfies StateReader
|
|
418
|
+
locals: ctx.locals,
|
|
419
|
+
env: createCSRAdapter(ctx.refs)
|
|
420
|
+
};
|
|
421
|
+
if (ctx.route !== void 0) core2.route = ctx.route;
|
|
422
|
+
if (ctx.imports !== void 0) core2.imports = ctx.imports;
|
|
423
|
+
if (ctx.styles !== void 0) core2.styles = ctx.styles;
|
|
424
|
+
return core2;
|
|
425
|
+
}
|
|
426
|
+
function evaluate(expr, ctx) {
|
|
427
|
+
return coreEvaluate(expr, toCoreContext(ctx));
|
|
877
428
|
}
|
|
878
429
|
function isExpression(value) {
|
|
879
430
|
return typeof value === "object" && value !== null && Object.prototype.hasOwnProperty.call(value, "expr") && typeof value.expr === "string";
|
|
@@ -883,10 +434,9 @@ function evaluatePayload(payload, ctx) {
|
|
|
883
434
|
return evaluate(payload, ctx);
|
|
884
435
|
}
|
|
885
436
|
if (typeof payload === "object" && payload !== null) {
|
|
886
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
887
437
|
const result = {};
|
|
888
438
|
for (const [key2, value] of Object.entries(payload)) {
|
|
889
|
-
if (
|
|
439
|
+
if (FORBIDDEN_KEYS.has(key2)) continue;
|
|
890
440
|
if (isExpression(value)) {
|
|
891
441
|
result[key2] = evaluate(value, ctx);
|
|
892
442
|
} else {
|
|
@@ -897,133 +447,10 @@ function evaluatePayload(payload, ctx) {
|
|
|
897
447
|
}
|
|
898
448
|
return payload;
|
|
899
449
|
}
|
|
900
|
-
function getNestedValue(obj, path) {
|
|
901
|
-
const forbiddenKeys = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
902
|
-
const parts = path.split(".");
|
|
903
|
-
let value = obj;
|
|
904
|
-
let parent = null;
|
|
905
|
-
for (const part of parts) {
|
|
906
|
-
if (forbiddenKeys.has(part)) {
|
|
907
|
-
return void 0;
|
|
908
|
-
}
|
|
909
|
-
if (value == null) {
|
|
910
|
-
return void 0;
|
|
911
|
-
}
|
|
912
|
-
parent = value;
|
|
913
|
-
if (Array.isArray(value)) {
|
|
914
|
-
const index = Number(part);
|
|
915
|
-
if (Number.isInteger(index) && index >= 0) {
|
|
916
|
-
value = value[index];
|
|
917
|
-
} else {
|
|
918
|
-
value = value[part];
|
|
919
|
-
}
|
|
920
|
-
} else if (typeof value === "object") {
|
|
921
|
-
value = value[part];
|
|
922
|
-
} else {
|
|
923
|
-
return void 0;
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
if (typeof value === "function" && parent != null) {
|
|
927
|
-
return value.bind(parent);
|
|
928
|
-
}
|
|
929
|
-
return value;
|
|
930
|
-
}
|
|
931
|
-
function evaluateBinary(op, left, right, ctx) {
|
|
932
|
-
if (op === "&&") {
|
|
933
|
-
const leftVal2 = evaluate(left, ctx);
|
|
934
|
-
if (!leftVal2) return leftVal2;
|
|
935
|
-
return evaluate(right, ctx);
|
|
936
|
-
}
|
|
937
|
-
if (op === "||") {
|
|
938
|
-
const leftVal2 = evaluate(left, ctx);
|
|
939
|
-
if (leftVal2) return leftVal2;
|
|
940
|
-
return evaluate(right, ctx);
|
|
941
|
-
}
|
|
942
|
-
const leftVal = evaluate(left, ctx);
|
|
943
|
-
const rightVal = evaluate(right, ctx);
|
|
944
|
-
switch (op) {
|
|
945
|
-
// Arithmetic
|
|
946
|
-
case "+":
|
|
947
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
948
|
-
return leftVal + rightVal;
|
|
949
|
-
}
|
|
950
|
-
return String(leftVal) + String(rightVal);
|
|
951
|
-
case "-":
|
|
952
|
-
return (typeof leftVal === "number" ? leftVal : 0) - (typeof rightVal === "number" ? rightVal : 0);
|
|
953
|
-
case "*":
|
|
954
|
-
return (typeof leftVal === "number" ? leftVal : 0) * (typeof rightVal === "number" ? rightVal : 0);
|
|
955
|
-
case "/": {
|
|
956
|
-
const dividend = typeof leftVal === "number" ? leftVal : 0;
|
|
957
|
-
const divisor = typeof rightVal === "number" ? rightVal : 0;
|
|
958
|
-
if (divisor === 0) {
|
|
959
|
-
return dividend === 0 ? NaN : dividend > 0 ? Infinity : -Infinity;
|
|
960
|
-
}
|
|
961
|
-
return dividend / divisor;
|
|
962
|
-
}
|
|
963
|
-
case "%": {
|
|
964
|
-
const dividend = typeof leftVal === "number" ? leftVal : 0;
|
|
965
|
-
const divisor = typeof rightVal === "number" ? rightVal : 0;
|
|
966
|
-
if (divisor === 0) return NaN;
|
|
967
|
-
return dividend % divisor;
|
|
968
|
-
}
|
|
969
|
-
// Comparison (using strict equality)
|
|
970
|
-
case "==":
|
|
971
|
-
return leftVal === rightVal;
|
|
972
|
-
case "!=":
|
|
973
|
-
return leftVal !== rightVal;
|
|
974
|
-
case "<":
|
|
975
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
976
|
-
return leftVal < rightVal;
|
|
977
|
-
}
|
|
978
|
-
return String(leftVal) < String(rightVal);
|
|
979
|
-
case "<=":
|
|
980
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
981
|
-
return leftVal <= rightVal;
|
|
982
|
-
}
|
|
983
|
-
return String(leftVal) <= String(rightVal);
|
|
984
|
-
case ">":
|
|
985
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
986
|
-
return leftVal > rightVal;
|
|
987
|
-
}
|
|
988
|
-
return String(leftVal) > String(rightVal);
|
|
989
|
-
case ">=":
|
|
990
|
-
if (typeof leftVal === "number" && typeof rightVal === "number") {
|
|
991
|
-
return leftVal >= rightVal;
|
|
992
|
-
}
|
|
993
|
-
return String(leftVal) >= String(rightVal);
|
|
994
|
-
default:
|
|
995
|
-
throw new Error("Unknown binary operator: " + op);
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
450
|
function evaluateStyle(expr, ctx) {
|
|
999
451
|
const preset = ctx.styles?.[expr.name];
|
|
1000
452
|
if (!preset) return void 0;
|
|
1001
|
-
|
|
1002
|
-
if (preset.variants) {
|
|
1003
|
-
for (const variantKey of Object.keys(preset.variants)) {
|
|
1004
|
-
let variantValueStr = null;
|
|
1005
|
-
if (expr.variants?.[variantKey]) {
|
|
1006
|
-
let variantValue;
|
|
1007
|
-
try {
|
|
1008
|
-
variantValue = evaluate(expr.variants[variantKey], ctx);
|
|
1009
|
-
} catch {
|
|
1010
|
-
continue;
|
|
1011
|
-
}
|
|
1012
|
-
if (variantValue != null) {
|
|
1013
|
-
variantValueStr = String(variantValue);
|
|
1014
|
-
}
|
|
1015
|
-
} else if (preset.defaultVariants?.[variantKey] !== void 0) {
|
|
1016
|
-
variantValueStr = preset.defaultVariants[variantKey];
|
|
1017
|
-
}
|
|
1018
|
-
if (variantValueStr !== null) {
|
|
1019
|
-
const variantClasses = preset.variants[variantKey]?.[variantValueStr];
|
|
1020
|
-
if (variantClasses) {
|
|
1021
|
-
classes += " " + variantClasses;
|
|
1022
|
-
}
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
return classes.trim();
|
|
453
|
+
return coreEvaluateStyle(expr, toCoreContext(ctx));
|
|
1027
454
|
}
|
|
1028
455
|
|
|
1029
456
|
// src/connection/sse.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/runtime",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Runtime DOM renderer for Constela UI framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"dompurify": "^3.3.1",
|
|
19
19
|
"marked": "^17.0.1",
|
|
20
20
|
"shiki": "^3.20.0",
|
|
21
|
-
"@constela/compiler": "0.15.
|
|
22
|
-
"@constela/core": "0.
|
|
21
|
+
"@constela/compiler": "0.15.21",
|
|
22
|
+
"@constela/core": "0.22.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/dompurify": "^3.2.0",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"tsup": "^8.0.0",
|
|
30
30
|
"typescript": "^5.3.0",
|
|
31
31
|
"vitest": "^2.0.0",
|
|
32
|
-
"@constela/server": "
|
|
32
|
+
"@constela/server": "18.0.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@constela/ai": "
|
|
35
|
+
"@constela/ai": "7.0.0"
|
|
36
36
|
},
|
|
37
37
|
"peerDependenciesMeta": {
|
|
38
38
|
"@constela/ai": {
|