@constela/runtime 5.0.6 → 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 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 - Evaluates compiled expressions
111
+ * Expression Evaluator - CSR wrapper around unified @constela/core evaluate
112
112
  *
113
- * Supports:
114
- * - Literal values (lit)
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 { callGlobalFunction, GLOBAL_FUNCTIONS } from "@constela/core";
380
- var SAFE_ARRAY_METHODS = /* @__PURE__ */ new Set([
381
- "length",
382
- "at",
383
- "includes",
384
- "slice",
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 property = expr.property || "valid";
823
- if (property === "message") {
389
+ const prop = property || "valid";
390
+ if (prop === "message") {
824
391
  return formElement.validationMessage || "";
825
392
  }
826
- return validity[property] ?? null;
827
- }
828
- case "call": {
829
- const callExpr = expr;
830
- const target = callExpr.target != null ? evaluate(callExpr.target, ctx) : null;
831
- const args = callExpr.args?.map((arg) => {
832
- if (arg.expr === "lambda") return arg;
833
- return evaluate(arg, ctx);
834
- }) ?? [];
835
- if (target === null) {
836
- return callGlobalFunction(callExpr.method, args);
837
- }
838
- if (Array.isArray(target)) {
839
- return callArrayMethod(target, callExpr.method, args, ctx, callExpr.args);
840
- }
841
- if (typeof target === "string") {
842
- return callStringMethod(target, callExpr.method, args);
843
- }
844
- if (target === Math) {
845
- return callMathMethod(callExpr.method, args);
846
- }
847
- if (target === Date) {
848
- return callDateStaticMethod(callExpr.method, args);
849
- }
850
- if (target instanceof Date) {
851
- return callDateInstanceMethod(target, callExpr.method);
852
- }
853
- if (typeof target === "function" && callExpr.method === "call") {
854
- return target(...args);
855
- }
856
- return void 0;
857
- }
858
- case "lambda":
859
- return void 0;
860
- case "array": {
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 (forbiddenKeys.has(key2)) continue;
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
- let classes = preset.base;
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": "5.0.6",
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.20",
22
- "@constela/core": "0.21.4"
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": "17.0.1"
32
+ "@constela/server": "18.0.0"
33
33
  },
34
34
  "peerDependencies": {
35
- "@constela/ai": "6.0.4"
35
+ "@constela/ai": "7.0.0"
36
36
  },
37
37
  "peerDependenciesMeta": {
38
38
  "@constela/ai": {