@sapui5/sap.fe.base 1.142.1 → 1.142.3

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.
@@ -1,10 +1,17 @@
1
1
  import type {
2
2
  ActionParameter,
3
+ AddAnnotationExpression,
4
+ AddConditionalExpression,
3
5
  AndAnnotationExpression,
4
6
  AndConditionalExpression,
5
7
  ApplyAnnotationExpression,
6
8
  Boolean,
7
9
  ConditionalCheckOrValue,
10
+ ConvertedMetadata,
11
+ DivAnnotationExpression,
12
+ DivByAnnotationExpression,
13
+ DivByConditionalExpression,
14
+ DivConditionalExpression,
8
15
  EntitySet,
9
16
  EntityType,
10
17
  EqAnnotationExpression,
@@ -13,14 +20,24 @@ import type {
13
20
  GeConditionalExpression,
14
21
  GtAnnotationExpression,
15
22
  GtConditionalExpression,
23
+ HasAnnotationExpression,
24
+ HasConditionalExpression,
16
25
  IfAnnotationExpression,
17
26
  IfAnnotationExpressionValue,
27
+ InAnnotationExpression,
28
+ InConditionalExpression,
18
29
  LeAnnotationExpression,
19
30
  LeConditionalExpression,
20
31
  LtAnnotationExpression,
21
32
  LtConditionalExpression,
33
+ ModAnnotationExpression,
34
+ ModConditionalExpression,
35
+ MulAnnotationExpression,
36
+ MulConditionalExpression,
22
37
  NeAnnotationExpression,
23
38
  NeConditionalExpression,
39
+ NegAnnotationExpression,
40
+ NegConditionalExpression,
24
41
  NotAnnotationExpression,
25
42
  NotConditionalExpression,
26
43
  OrAnnotationExpression,
@@ -29,6 +46,8 @@ import type {
29
46
  PathConditionExpression,
30
47
  Property,
31
48
  PropertyAnnotationValue,
49
+ SubAnnotationExpression,
50
+ SubConditionalExpression,
32
51
  ConstantExpression as VocabConstantExpression
33
52
  } from "@sap-ux/vocabularies-types";
34
53
  import { CommonAnnotationTerms } from "@sap-ux/vocabularies-types/vocabularies/Common";
@@ -157,7 +176,7 @@ export type EmbeddedUI5ExpressionBindingExpression<T> = BaseExpression<T> & {
157
176
  value: string;
158
177
  };
159
178
 
160
- export type ComparisonOperator = "===" | "!==" | ">=" | ">" | "<=" | "<";
179
+ export type ComparisonOperator = "===" | "!==" | ">=" | ">" | "<=" | "<" | "Has" | "In";
161
180
  export type ComparisonExpression = BaseExpression<boolean> & {
162
181
  _type: "Comparison";
163
182
  operator: ComparisonOperator;
@@ -165,6 +184,13 @@ export type ComparisonExpression = BaseExpression<boolean> & {
165
184
  operand2: BindingToolkitExpression<unknown>;
166
185
  };
167
186
 
187
+ export type ArithmeticOperator = "+" | "-" | "*" | "/" | "%" | "Neg" | "Floor";
188
+ export type ArithmeticExpression = BaseExpression<number> & {
189
+ _type: "Arithmetic";
190
+ operator: ArithmeticOperator;
191
+ operand1: BindingToolkitExpression<unknown>;
192
+ operand2: BindingToolkitExpression<unknown>;
193
+ };
168
194
  export type IfElseExpression<T> = BaseExpression<T> & {
169
195
  _type: "IfElse";
170
196
  condition: BindingToolkitExpression<boolean>;
@@ -198,7 +224,8 @@ export type BindingToolkitExpression<T> =
198
224
  | FormatterExpression<T>
199
225
  | ComplexTypeExpression<T>
200
226
  | ReferenceExpression
201
- | FunctionExpression<T>;
227
+ | FunctionExpression<T>
228
+ | ArithmeticExpression;
202
229
 
203
230
  type TypeMappingDefinition = {
204
231
  type: string;
@@ -296,7 +323,12 @@ export function _checkExpressionsAreEqual<T>(a: BindingToolkitExpression<T>, b:
296
323
  case "EmbeddedBinding":
297
324
  case "EmbeddedExpressionBinding":
298
325
  return a.value === (b as ConstantExpression<T>).value;
299
-
326
+ case "Arithmetic":
327
+ return (
328
+ a.operator === (b as ArithmeticExpression).operator &&
329
+ _checkExpressionsAreEqual(a.operand1, (b as ArithmeticExpression).operand1) &&
330
+ _checkExpressionsAreEqual(a.operand2, (b as ArithmeticExpression).operand2)
331
+ );
300
332
  case "Not":
301
333
  return _checkExpressionsAreEqual(a.operand, (b as NotExpression).operand);
302
334
  case "Truthy":
@@ -502,6 +534,138 @@ export function or(...operands: ExpressionOrPrimitive<boolean>[]): BindingToolki
502
534
  }
503
535
  }
504
536
 
537
+ export function add<T extends PrimitiveType>(
538
+ leftOperand: ExpressionOrPrimitive<T>,
539
+ rightOperand: ExpressionOrPrimitive<T>
540
+ ): BindingToolkitExpression<number> {
541
+ return arithmetic("+", leftOperand, rightOperand);
542
+ }
543
+
544
+ export function subtract<T extends PrimitiveType>(
545
+ leftOperand: ExpressionOrPrimitive<T>,
546
+ rightOperand: ExpressionOrPrimitive<T>
547
+ ): BindingToolkitExpression<number> {
548
+ return arithmetic("-", leftOperand, rightOperand);
549
+ }
550
+
551
+ export function multiply<T extends PrimitiveType>(
552
+ leftOperand: ExpressionOrPrimitive<T>,
553
+ rightOperand: ExpressionOrPrimitive<T>
554
+ ): BindingToolkitExpression<number> {
555
+ return arithmetic("*", leftOperand, rightOperand);
556
+ }
557
+
558
+ export function divide<T extends PrimitiveType>(
559
+ leftOperand: ExpressionOrPrimitive<T>,
560
+ rightOperand: ExpressionOrPrimitive<T>
561
+ ): BindingToolkitExpression<number> {
562
+ return arithmetic("/", leftOperand, rightOperand);
563
+ }
564
+
565
+ export function modulo<T extends PrimitiveType>(
566
+ leftOperand: ExpressionOrPrimitive<T>,
567
+ rightOperand: ExpressionOrPrimitive<T>
568
+ ): BindingToolkitExpression<number> {
569
+ return arithmetic("%", leftOperand, rightOperand);
570
+ }
571
+
572
+ export function negate<T extends PrimitiveType>(operand: ExpressionOrPrimitive<T>): BindingToolkitExpression<number> {
573
+ return arithmetic("Neg", operand, null);
574
+ }
575
+
576
+ export function floor<T extends PrimitiveType>(operand: ExpressionOrPrimitive<T>): BindingToolkitExpression<number> {
577
+ return arithmetic("Floor", operand, null);
578
+ }
579
+
580
+ /**
581
+ * Arithmetic expression.
582
+ * @param operator
583
+ * @param leftOperand
584
+ * @param rightOperand
585
+ * @returns Expression evaluating to number
586
+ */
587
+ export function arithmetic<T extends PrimitiveType>(
588
+ operator: ArithmeticOperator,
589
+ leftOperand: ExpressionOrPrimitive<T>,
590
+ rightOperand: ExpressionOrPrimitive<T>
591
+ ): BindingToolkitExpression<number> {
592
+ const leftExpression = wrapPrimitive(leftOperand);
593
+ const rightExpression = wrapPrimitive(rightOperand);
594
+ if (hasUnresolvableExpression(leftExpression, rightExpression)) {
595
+ return unresolvableExpression;
596
+ }
597
+ if (isConstant(leftExpression) && isConstant(rightExpression)) {
598
+ switch (operator) {
599
+ case "+":
600
+ if (leftExpression.value === null || leftExpression.value === undefined) {
601
+ return constant(rightExpression.value as number);
602
+ } else if (rightExpression.value === null || rightExpression.value === undefined) {
603
+ return constant(leftExpression.value as number);
604
+ }
605
+ const sum = (leftExpression.value as number) + (rightExpression.value as number);
606
+ return constant(sum);
607
+ case "-":
608
+ if (leftExpression.value === null || leftExpression.value === undefined) {
609
+ return constant(rightExpression.value as number);
610
+ } else if (rightExpression.value === null || rightExpression.value === undefined) {
611
+ return constant(leftExpression.value as number);
612
+ }
613
+ const diff = (leftExpression.value as number) - (rightExpression.value as number);
614
+ return constant(diff);
615
+ case "/":
616
+ if (
617
+ leftExpression.value === null ||
618
+ leftExpression.value === undefined ||
619
+ rightExpression.value === null ||
620
+ rightExpression.value === undefined
621
+ ) {
622
+ return constant(0);
623
+ }
624
+ const div = (leftExpression.value as number) / (rightExpression.value as number);
625
+ return constant(div);
626
+ case "Neg":
627
+ if (leftExpression.value === null || leftExpression.value === undefined) {
628
+ return constant(0);
629
+ }
630
+ return constant(-leftExpression.value);
631
+ case "%":
632
+ if (
633
+ leftExpression.value === null ||
634
+ leftExpression.value === undefined ||
635
+ rightExpression.value === null ||
636
+ rightExpression.value === undefined
637
+ ) {
638
+ return constant(0);
639
+ }
640
+ const mod = (leftExpression.value as number) % (rightExpression.value as number);
641
+ return constant(mod);
642
+ case "Floor":
643
+ if (leftExpression.value === null || leftExpression.value === undefined) {
644
+ return constant(0);
645
+ }
646
+ return constant(Math.floor(leftExpression.value as number));
647
+ case "*":
648
+ if (
649
+ leftExpression.value === null ||
650
+ leftExpression.value === undefined ||
651
+ rightExpression.value === null ||
652
+ rightExpression.value === undefined
653
+ ) {
654
+ return constant(0);
655
+ }
656
+ const mult = (leftExpression.value as number) * (rightExpression.value as number);
657
+ return constant(mult);
658
+ }
659
+ } else {
660
+ return {
661
+ _type: "Arithmetic",
662
+ operator: operator,
663
+ operand1: leftExpression,
664
+ operand2: rightExpression
665
+ };
666
+ }
667
+ }
668
+
505
669
  /**
506
670
  * Logical `not` operator.
507
671
  * @param operand The expression to reverse
@@ -542,6 +706,11 @@ export function not(operand: ExpressionOrPrimitive<boolean>): BindingToolkitExpr
542
706
  return { ...operand, operator: "<=" };
543
707
  case ">=":
544
708
  return { ...operand, operator: "<" };
709
+ default:
710
+ return {
711
+ _type: "Not",
712
+ operand: operand
713
+ };
545
714
  }
546
715
  } else if (operand._type === "Not") {
547
716
  return operand.operand;
@@ -852,6 +1021,15 @@ type ComplexAnnotationExpression<P> =
852
1021
  | GeAnnotationExpression<P>
853
1022
  | LeAnnotationExpression<P>
854
1023
  | LtAnnotationExpression<P>
1024
+ | HasAnnotationExpression<P>
1025
+ | InAnnotationExpression<P>
1026
+ | AddAnnotationExpression<P>
1027
+ | SubAnnotationExpression<P>
1028
+ | MulAnnotationExpression<P>
1029
+ | DivAnnotationExpression<P>
1030
+ | ModAnnotationExpression<P>
1031
+ | DivByAnnotationExpression<P>
1032
+ | NegAnnotationExpression<P>
855
1033
  | VocabConstantExpression<P>;
856
1034
 
857
1035
  function isPrimitiveObject(objectType: object): boolean {
@@ -874,6 +1052,11 @@ function isComplexAnnotationExpression<T>(annotationValue: PropertyAnnotationVal
874
1052
  return typeof annotationValue === "object" && !isPrimitiveObject(annotationValue as object);
875
1053
  }
876
1054
 
1055
+ let CONVERTER_ROOT_SYMBOL: symbol | undefined;
1056
+ export function setConverterRootSymbol(converterRootSymbol: symbol): void {
1057
+ CONVERTER_ROOT_SYMBOL = converterRootSymbol;
1058
+ }
1059
+
877
1060
  /**
878
1061
  * Generate the corresponding annotationValue for a given annotation annotationValue.
879
1062
  * @template T The target type
@@ -889,6 +1072,11 @@ export function getExpressionFromAnnotation<T extends PrimitiveType>(
889
1072
  defaultValue?: ExpressionOrPrimitive<T>,
890
1073
  pathVisitor?: Function
891
1074
  ): BindingToolkitExpression<PrimitiveTypeCast<T>> {
1075
+ let converterRoot: ConvertedMetadata | undefined;
1076
+ if (CONVERTER_ROOT_SYMBOL) {
1077
+ converterRoot = (annotationValue?.[CONVERTER_ROOT_SYMBOL as never] as unknown as Function)?.() as ConvertedMetadata | undefined;
1078
+ }
1079
+
892
1080
  if (annotationValue === undefined) {
893
1081
  return wrapPrimitive(defaultValue as PrimitiveTypeCast<T>);
894
1082
  }
@@ -901,55 +1089,106 @@ export function getExpressionFromAnnotation<T extends PrimitiveType>(
901
1089
  case "Path":
902
1090
  return pathInModel(annotationValue.path, undefined, visitedNavigationPaths, pathVisitor);
903
1091
  case "If":
904
- return annotationIfExpression(annotationValue.$If, visitedNavigationPaths, pathVisitor) as BindingToolkitExpression<
905
- PrimitiveTypeCast<T>
906
- >;
1092
+ return annotationIfExpression(
1093
+ annotationValue.$If,
1094
+ visitedNavigationPaths,
1095
+ pathVisitor,
1096
+ converterRoot
1097
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
907
1098
  case "Not":
908
- return not(parseAnnotationCondition(annotationValue.$Not, visitedNavigationPaths, pathVisitor)) as BindingToolkitExpression<
909
- PrimitiveTypeCast<T>
910
- >;
1099
+ return not(
1100
+ parseAnnotationCondition(annotationValue.$Not, visitedNavigationPaths, pathVisitor, converterRoot)
1101
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
911
1102
  case "Eq":
912
1103
  return equal(
913
- parseAnnotationCondition(annotationValue.$Eq[0], visitedNavigationPaths, pathVisitor),
914
- parseAnnotationCondition(annotationValue.$Eq[1], visitedNavigationPaths, pathVisitor)
1104
+ parseAnnotationCondition(annotationValue.$Eq[0], visitedNavigationPaths, pathVisitor, converterRoot),
1105
+ parseAnnotationCondition(annotationValue.$Eq[1], visitedNavigationPaths, pathVisitor, converterRoot)
915
1106
  ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
916
1107
  case "Ne":
917
1108
  return notEqual(
918
- parseAnnotationCondition(annotationValue.$Ne[0], visitedNavigationPaths, pathVisitor),
919
- parseAnnotationCondition(annotationValue.$Ne[1], visitedNavigationPaths, pathVisitor)
1109
+ parseAnnotationCondition(annotationValue.$Ne[0], visitedNavigationPaths, pathVisitor, converterRoot),
1110
+ parseAnnotationCondition(annotationValue.$Ne[1], visitedNavigationPaths, pathVisitor, converterRoot)
920
1111
  ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
921
1112
  case "Gt":
922
1113
  return greaterThan(
923
- parseAnnotationCondition(annotationValue.$Gt[0], visitedNavigationPaths, pathVisitor),
924
- parseAnnotationCondition(annotationValue.$Gt[1], visitedNavigationPaths, pathVisitor)
1114
+ parseAnnotationCondition(annotationValue.$Gt[0], visitedNavigationPaths, pathVisitor, converterRoot),
1115
+ parseAnnotationCondition(annotationValue.$Gt[1], visitedNavigationPaths, pathVisitor, converterRoot)
925
1116
  ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
926
1117
  case "Ge":
927
1118
  return greaterOrEqual(
928
- parseAnnotationCondition(annotationValue.$Ge[0], visitedNavigationPaths, pathVisitor),
929
- parseAnnotationCondition(annotationValue.$Ge[1], visitedNavigationPaths, pathVisitor)
1119
+ parseAnnotationCondition(annotationValue.$Ge[0], visitedNavigationPaths, pathVisitor, converterRoot),
1120
+ parseAnnotationCondition(annotationValue.$Ge[1], visitedNavigationPaths, pathVisitor, converterRoot)
930
1121
  ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
931
1122
  case "Lt":
932
1123
  return lessThan(
933
- parseAnnotationCondition(annotationValue.$Lt[0], visitedNavigationPaths, pathVisitor),
934
- parseAnnotationCondition(annotationValue.$Lt[1], visitedNavigationPaths, pathVisitor)
1124
+ parseAnnotationCondition(annotationValue.$Lt[0], visitedNavigationPaths, pathVisitor, converterRoot),
1125
+ parseAnnotationCondition(annotationValue.$Lt[1], visitedNavigationPaths, pathVisitor, converterRoot)
935
1126
  ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
936
1127
  case "Le":
937
1128
  return lessOrEqual(
938
- parseAnnotationCondition(annotationValue.$Le[0], visitedNavigationPaths, pathVisitor),
939
- parseAnnotationCondition(annotationValue.$Le[1], visitedNavigationPaths, pathVisitor)
1129
+ parseAnnotationCondition(annotationValue.$Le[0], visitedNavigationPaths, pathVisitor, converterRoot),
1130
+ parseAnnotationCondition(annotationValue.$Le[1], visitedNavigationPaths, pathVisitor, converterRoot)
940
1131
  ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
941
1132
  case "Or":
942
1133
  return or(
943
1134
  ...annotationValue.$Or.map(function (orCondition) {
944
- return parseAnnotationCondition<boolean>(orCondition, visitedNavigationPaths, pathVisitor);
1135
+ return parseAnnotationCondition<boolean>(orCondition, visitedNavigationPaths, pathVisitor, converterRoot);
945
1136
  })
946
1137
  ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
947
1138
  case "And":
948
1139
  return and(
949
1140
  ...annotationValue.$And.map(function (andCondition) {
950
- return parseAnnotationCondition<boolean>(andCondition, visitedNavigationPaths, pathVisitor);
1141
+ return parseAnnotationCondition<boolean>(andCondition, visitedNavigationPaths, pathVisitor, converterRoot);
951
1142
  })
952
1143
  ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
1144
+ case "In":
1145
+ return comparison(
1146
+ "In",
1147
+ parseAnnotationCondition(annotationValue.$In[0], visitedNavigationPaths, pathVisitor, converterRoot),
1148
+ parseAnnotationCondition(annotationValue.$In[1], visitedNavigationPaths, pathVisitor, converterRoot)
1149
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
1150
+ case "Has":
1151
+ return comparison(
1152
+ "Has",
1153
+ parseAnnotationCondition(annotationValue.$Has[0], visitedNavigationPaths, pathVisitor, converterRoot),
1154
+ parseAnnotationCondition(annotationValue.$Has[1], visitedNavigationPaths, pathVisitor, converterRoot)
1155
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
1156
+ case "Add":
1157
+ return add(
1158
+ parseAnnotationCondition(annotationValue.$Add[0], visitedNavigationPaths, pathVisitor, converterRoot),
1159
+ parseAnnotationCondition(annotationValue.$Add[1], visitedNavigationPaths, pathVisitor, converterRoot)
1160
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
1161
+ case "Sub":
1162
+ return subtract(
1163
+ parseAnnotationCondition(annotationValue.$Sub[0], visitedNavigationPaths, pathVisitor, converterRoot),
1164
+ parseAnnotationCondition(annotationValue.$Sub[1], visitedNavigationPaths, pathVisitor, converterRoot)
1165
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
1166
+ case "Mul":
1167
+ return multiply(
1168
+ parseAnnotationCondition(annotationValue.$Mul[0], visitedNavigationPaths, pathVisitor, converterRoot),
1169
+ parseAnnotationCondition(annotationValue.$Mul[1], visitedNavigationPaths, pathVisitor, converterRoot)
1170
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
1171
+ case "Div":
1172
+ return floor(
1173
+ divide(
1174
+ parseAnnotationCondition(annotationValue.$Div[0], visitedNavigationPaths, pathVisitor, converterRoot),
1175
+ parseAnnotationCondition(annotationValue.$Div[1], visitedNavigationPaths, pathVisitor, converterRoot)
1176
+ )
1177
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
1178
+ case "DivBy":
1179
+ return divide(
1180
+ parseAnnotationCondition(annotationValue.$DivBy[0], visitedNavigationPaths, pathVisitor, converterRoot),
1181
+ parseAnnotationCondition(annotationValue.$DivBy[1], visitedNavigationPaths, pathVisitor, converterRoot)
1182
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
1183
+ case "Mod":
1184
+ return modulo(
1185
+ parseAnnotationCondition(annotationValue.$Mod[0], visitedNavigationPaths, pathVisitor, converterRoot),
1186
+ parseAnnotationCondition(annotationValue.$Mod[1], visitedNavigationPaths, pathVisitor, converterRoot)
1187
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
1188
+ case "Neg":
1189
+ return negate(
1190
+ parseAnnotationCondition(annotationValue.$Neg[0], visitedNavigationPaths, pathVisitor, converterRoot)
1191
+ ) as BindingToolkitExpression<PrimitiveTypeCast<T>>;
953
1192
  case "Apply":
954
1193
  return annotationApplyExpression(
955
1194
  annotationValue as ApplyAnnotationExpression<string>,
@@ -969,60 +1208,122 @@ export function getExpressionFromAnnotation<T extends PrimitiveType>(
969
1208
  * @param annotationValue The condition or value from the annotation
970
1209
  * @param visitedNavigationPaths The path from the root entity set
971
1210
  * @param pathVisitor A function to modify the resulting path
1211
+ * @param converterRoot The root converted metadata
972
1212
  * @returns An equivalent expression
973
1213
  */
974
1214
  function parseAnnotationCondition<T extends PrimitiveType>(
975
1215
  annotationValue: ConditionalCheckOrValue,
976
1216
  visitedNavigationPaths: string[] = [],
977
- pathVisitor?: Function
1217
+ pathVisitor?: Function,
1218
+ converterRoot?: ConvertedMetadata
978
1219
  ): BindingToolkitExpression<T> {
979
1220
  if (annotationValue === null || typeof annotationValue !== "object") {
980
1221
  return constant(annotationValue as T);
981
1222
  } else if (annotationValue.hasOwnProperty("$Or")) {
982
1223
  return or(
983
1224
  ...((annotationValue as OrConditionalExpression).$Or.map(function (orCondition) {
984
- return parseAnnotationCondition(orCondition, visitedNavigationPaths, pathVisitor);
1225
+ return parseAnnotationCondition(orCondition, visitedNavigationPaths, pathVisitor, converterRoot);
985
1226
  }) as unknown as BindingToolkitExpression<boolean>[])
986
1227
  ) as BindingToolkitExpression<T>;
987
1228
  } else if (annotationValue.hasOwnProperty("$And")) {
988
1229
  return and(
989
1230
  ...((annotationValue as AndConditionalExpression).$And.map(function (andCondition) {
990
- return parseAnnotationCondition(andCondition, visitedNavigationPaths, pathVisitor);
1231
+ return parseAnnotationCondition(andCondition, visitedNavigationPaths, pathVisitor, converterRoot);
991
1232
  }) as unknown as BindingToolkitExpression<boolean>[])
992
1233
  ) as BindingToolkitExpression<T>;
993
1234
  } else if (annotationValue.hasOwnProperty("$Not")) {
994
1235
  return not(
995
- parseAnnotationCondition((annotationValue as NotConditionalExpression).$Not, visitedNavigationPaths, pathVisitor)
1236
+ parseAnnotationCondition((annotationValue as NotConditionalExpression).$Not, visitedNavigationPaths, pathVisitor, converterRoot)
996
1237
  ) as BindingToolkitExpression<T>;
997
1238
  } else if (annotationValue.hasOwnProperty("$Eq")) {
998
1239
  return equal(
999
- parseAnnotationCondition((annotationValue as EqConditionalExpression).$Eq[0], visitedNavigationPaths, pathVisitor),
1000
- parseAnnotationCondition((annotationValue as EqConditionalExpression).$Eq[1], visitedNavigationPaths, pathVisitor)
1240
+ parseAnnotationCondition(
1241
+ (annotationValue as EqConditionalExpression).$Eq[0],
1242
+ visitedNavigationPaths,
1243
+ pathVisitor,
1244
+ converterRoot
1245
+ ),
1246
+ parseAnnotationCondition(
1247
+ (annotationValue as EqConditionalExpression).$Eq[1],
1248
+ visitedNavigationPaths,
1249
+ pathVisitor,
1250
+ converterRoot
1251
+ )
1001
1252
  ) as BindingToolkitExpression<T>;
1002
1253
  } else if (annotationValue.hasOwnProperty("$Ne")) {
1003
1254
  return notEqual(
1004
- parseAnnotationCondition((annotationValue as NeConditionalExpression).$Ne[0], visitedNavigationPaths, pathVisitor),
1005
- parseAnnotationCondition((annotationValue as NeConditionalExpression).$Ne[1], visitedNavigationPaths, pathVisitor)
1255
+ parseAnnotationCondition(
1256
+ (annotationValue as NeConditionalExpression).$Ne[0],
1257
+ visitedNavigationPaths,
1258
+ pathVisitor,
1259
+ converterRoot
1260
+ ),
1261
+ parseAnnotationCondition(
1262
+ (annotationValue as NeConditionalExpression).$Ne[1],
1263
+ visitedNavigationPaths,
1264
+ pathVisitor,
1265
+ converterRoot
1266
+ )
1006
1267
  ) as BindingToolkitExpression<T>;
1007
1268
  } else if (annotationValue.hasOwnProperty("$Gt")) {
1008
1269
  return greaterThan(
1009
- parseAnnotationCondition((annotationValue as GtConditionalExpression).$Gt[0], visitedNavigationPaths, pathVisitor),
1010
- parseAnnotationCondition((annotationValue as GtConditionalExpression).$Gt[1], visitedNavigationPaths, pathVisitor)
1270
+ parseAnnotationCondition(
1271
+ (annotationValue as GtConditionalExpression).$Gt[0],
1272
+ visitedNavigationPaths,
1273
+ pathVisitor,
1274
+ converterRoot
1275
+ ),
1276
+ parseAnnotationCondition(
1277
+ (annotationValue as GtConditionalExpression).$Gt[1],
1278
+ visitedNavigationPaths,
1279
+ pathVisitor,
1280
+ converterRoot
1281
+ )
1011
1282
  ) as BindingToolkitExpression<T>;
1012
1283
  } else if (annotationValue.hasOwnProperty("$Ge")) {
1013
1284
  return greaterOrEqual(
1014
- parseAnnotationCondition((annotationValue as GeConditionalExpression).$Ge[0], visitedNavigationPaths, pathVisitor),
1015
- parseAnnotationCondition((annotationValue as GeConditionalExpression).$Ge[1], visitedNavigationPaths, pathVisitor)
1285
+ parseAnnotationCondition(
1286
+ (annotationValue as GeConditionalExpression).$Ge[0],
1287
+ visitedNavigationPaths,
1288
+ pathVisitor,
1289
+ converterRoot
1290
+ ),
1291
+ parseAnnotationCondition(
1292
+ (annotationValue as GeConditionalExpression).$Ge[1],
1293
+ visitedNavigationPaths,
1294
+ pathVisitor,
1295
+ converterRoot
1296
+ )
1016
1297
  ) as BindingToolkitExpression<T>;
1017
1298
  } else if (annotationValue.hasOwnProperty("$Lt")) {
1018
1299
  return lessThan(
1019
- parseAnnotationCondition((annotationValue as LtConditionalExpression).$Lt[0], visitedNavigationPaths, pathVisitor),
1020
- parseAnnotationCondition((annotationValue as LtConditionalExpression).$Lt[1], visitedNavigationPaths, pathVisitor)
1300
+ parseAnnotationCondition(
1301
+ (annotationValue as LtConditionalExpression).$Lt[0],
1302
+ visitedNavigationPaths,
1303
+ pathVisitor,
1304
+ converterRoot
1305
+ ),
1306
+ parseAnnotationCondition(
1307
+ (annotationValue as LtConditionalExpression).$Lt[1],
1308
+ visitedNavigationPaths,
1309
+ pathVisitor,
1310
+ converterRoot
1311
+ )
1021
1312
  ) as BindingToolkitExpression<T>;
1022
1313
  } else if (annotationValue.hasOwnProperty("$Le")) {
1023
1314
  return lessOrEqual(
1024
- parseAnnotationCondition((annotationValue as LeConditionalExpression).$Le[0], visitedNavigationPaths, pathVisitor),
1025
- parseAnnotationCondition((annotationValue as LeConditionalExpression).$Le[1], visitedNavigationPaths, pathVisitor)
1315
+ parseAnnotationCondition(
1316
+ (annotationValue as LeConditionalExpression).$Le[0],
1317
+ visitedNavigationPaths,
1318
+ pathVisitor,
1319
+ converterRoot
1320
+ ),
1321
+ parseAnnotationCondition(
1322
+ (annotationValue as LeConditionalExpression).$Le[1],
1323
+ visitedNavigationPaths,
1324
+ pathVisitor,
1325
+ converterRoot
1326
+ )
1026
1327
  ) as BindingToolkitExpression<T>;
1027
1328
  } else if (annotationValue.hasOwnProperty("$Path")) {
1028
1329
  return pathInModel((annotationValue as PathConditionExpression<T>).$Path, undefined, visitedNavigationPaths, pathVisitor);
@@ -1048,9 +1349,137 @@ function parseAnnotationCondition<T extends PrimitiveType>(
1048
1349
  pathVisitor
1049
1350
  ) as BindingToolkitExpression<T>;
1050
1351
  } else if (annotationValue.hasOwnProperty("$EnumMember")) {
1051
- return constant(resolveEnumValue((annotationValue as { $EnumMember?: string }).$EnumMember) as T);
1352
+ return constant(resolveEnumValue((annotationValue as { $EnumMember?: string }).$EnumMember, converterRoot) as T);
1353
+ } else if (annotationValue.hasOwnProperty("$In")) {
1354
+ return comparison(
1355
+ "In",
1356
+ parseAnnotationCondition(
1357
+ (annotationValue as InConditionalExpression).$In[0],
1358
+ visitedNavigationPaths,
1359
+ pathVisitor,
1360
+ converterRoot
1361
+ ),
1362
+ parseAnnotationCondition(
1363
+ (annotationValue as InConditionalExpression).$In[1],
1364
+ visitedNavigationPaths,
1365
+ pathVisitor,
1366
+ converterRoot
1367
+ )
1368
+ ) as BindingToolkitExpression<T>;
1369
+ } else if (annotationValue.hasOwnProperty("$Has")) {
1370
+ return comparison(
1371
+ "Has",
1372
+ parseAnnotationCondition(
1373
+ (annotationValue as HasConditionalExpression).$Has[0],
1374
+ visitedNavigationPaths,
1375
+ pathVisitor,
1376
+ converterRoot
1377
+ ),
1378
+ parseAnnotationCondition(
1379
+ (annotationValue as HasConditionalExpression).$Has[1],
1380
+ visitedNavigationPaths,
1381
+ pathVisitor,
1382
+ converterRoot
1383
+ )
1384
+ ) as BindingToolkitExpression<T>;
1385
+ } else if (annotationValue.hasOwnProperty("$Add")) {
1386
+ return add(
1387
+ parseAnnotationCondition(
1388
+ (annotationValue as AddConditionalExpression).$Add[0],
1389
+ visitedNavigationPaths,
1390
+ pathVisitor,
1391
+ converterRoot
1392
+ ),
1393
+ parseAnnotationCondition(
1394
+ (annotationValue as AddConditionalExpression).$Add[1],
1395
+ visitedNavigationPaths,
1396
+ pathVisitor,
1397
+ converterRoot
1398
+ )
1399
+ ) as BindingToolkitExpression<T>;
1400
+ } else if (annotationValue.hasOwnProperty("$Sub")) {
1401
+ return subtract(
1402
+ parseAnnotationCondition(
1403
+ (annotationValue as SubConditionalExpression).$Sub[0],
1404
+ visitedNavigationPaths,
1405
+ pathVisitor,
1406
+ converterRoot
1407
+ ),
1408
+ parseAnnotationCondition(
1409
+ (annotationValue as SubConditionalExpression).$Sub[1],
1410
+ visitedNavigationPaths,
1411
+ pathVisitor,
1412
+ converterRoot
1413
+ )
1414
+ ) as BindingToolkitExpression<T>;
1415
+ } else if (annotationValue.hasOwnProperty("$Mul")) {
1416
+ return multiply(
1417
+ parseAnnotationCondition(
1418
+ (annotationValue as MulConditionalExpression).$Mul[0],
1419
+ visitedNavigationPaths,
1420
+ pathVisitor,
1421
+ converterRoot
1422
+ ),
1423
+ parseAnnotationCondition(
1424
+ (annotationValue as MulConditionalExpression).$Mul[1],
1425
+ visitedNavigationPaths,
1426
+ pathVisitor,
1427
+ converterRoot
1428
+ )
1429
+ ) as BindingToolkitExpression<T>;
1430
+ } else if (annotationValue.hasOwnProperty("$Div")) {
1431
+ return floor(
1432
+ divide(
1433
+ parseAnnotationCondition(
1434
+ (annotationValue as DivConditionalExpression).$Div[0],
1435
+ visitedNavigationPaths,
1436
+ pathVisitor,
1437
+ converterRoot
1438
+ ),
1439
+ parseAnnotationCondition(
1440
+ (annotationValue as DivConditionalExpression).$Div[1],
1441
+ visitedNavigationPaths,
1442
+ pathVisitor,
1443
+ converterRoot
1444
+ )
1445
+ )
1446
+ ) as BindingToolkitExpression<T>;
1447
+ } else if (annotationValue.hasOwnProperty("$DivBy")) {
1448
+ return divide(
1449
+ parseAnnotationCondition(
1450
+ (annotationValue as DivByConditionalExpression).$DivBy[0],
1451
+ visitedNavigationPaths,
1452
+ pathVisitor,
1453
+ converterRoot
1454
+ ),
1455
+ parseAnnotationCondition(
1456
+ (annotationValue as DivByConditionalExpression).$DivBy[1],
1457
+ visitedNavigationPaths,
1458
+ pathVisitor,
1459
+ converterRoot
1460
+ )
1461
+ ) as BindingToolkitExpression<T>;
1462
+ } else if (annotationValue.hasOwnProperty("$Mod")) {
1463
+ return modulo(
1464
+ parseAnnotationCondition(
1465
+ (annotationValue as ModConditionalExpression).$Mod[0],
1466
+ visitedNavigationPaths,
1467
+ pathVisitor,
1468
+ converterRoot
1469
+ ),
1470
+ parseAnnotationCondition(
1471
+ (annotationValue as ModConditionalExpression).$Mod[1],
1472
+ visitedNavigationPaths,
1473
+ pathVisitor,
1474
+ converterRoot
1475
+ )
1476
+ ) as BindingToolkitExpression<T>;
1477
+ } else if (annotationValue.hasOwnProperty("$Neg")) {
1478
+ return negate(
1479
+ parseAnnotationCondition((annotationValue as NegConditionalExpression).$Neg, visitedNavigationPaths, pathVisitor, converterRoot)
1480
+ ) as BindingToolkitExpression<T>;
1052
1481
  }
1053
- return constant(false as T);
1482
+ return constant(annotationValue as T);
1054
1483
  }
1055
1484
 
1056
1485
  /**
@@ -1059,17 +1488,19 @@ function parseAnnotationCondition<T extends PrimitiveType>(
1059
1488
  * @param annotationValue An If expression returning the type T
1060
1489
  * @param visitedNavigationPaths The path from the root entity set
1061
1490
  * @param pathVisitor A function to modify the resulting path
1491
+ * @param converterRoot The root converted metadata
1062
1492
  * @returns The equivalent ifElse expression
1063
1493
  */
1064
1494
  export function annotationIfExpression<T extends PrimitiveType>(
1065
1495
  annotationValue: IfAnnotationExpressionValue<T>,
1066
1496
  visitedNavigationPaths: string[] = [],
1067
- pathVisitor?: Function
1497
+ pathVisitor?: Function,
1498
+ converterRoot?: ConvertedMetadata
1068
1499
  ): BindingToolkitExpression<T> {
1069
1500
  return ifElse(
1070
- parseAnnotationCondition(annotationValue[0], visitedNavigationPaths, pathVisitor),
1071
- parseAnnotationCondition(annotationValue[1] as ConditionalCheckOrValue, visitedNavigationPaths, pathVisitor),
1072
- parseAnnotationCondition(annotationValue[2] as ConditionalCheckOrValue, visitedNavigationPaths, pathVisitor)
1501
+ parseAnnotationCondition(annotationValue[0], visitedNavigationPaths, pathVisitor, converterRoot),
1502
+ parseAnnotationCondition(annotationValue[1] as ConditionalCheckOrValue, visitedNavigationPaths, pathVisitor, converterRoot),
1503
+ parseAnnotationCondition(annotationValue[2] as ConditionalCheckOrValue, visitedNavigationPaths, pathVisitor, converterRoot)
1073
1504
  );
1074
1505
  }
1075
1506
  // This type is not recursively transformed from the metamodel content, as such we have some ugly things there
@@ -1208,6 +1639,43 @@ function comparison<T extends PrimitiveType>(
1208
1639
  return constant(false);
1209
1640
  }
1210
1641
  return constant(leftExpression.value >= rightExpression.value);
1642
+
1643
+ case "Has": {
1644
+ if (
1645
+ leftExpression.value === null ||
1646
+ leftExpression.value === undefined ||
1647
+ rightExpression.value === null ||
1648
+ rightExpression.value === undefined
1649
+ ) {
1650
+ return constant(false);
1651
+ }
1652
+ const leftValueInt = leftExpression.value as number;
1653
+ const rightValueInt = rightExpression.value as number;
1654
+ return constant(!!(leftValueInt & rightValueInt));
1655
+ }
1656
+ case "In": {
1657
+ if (
1658
+ leftExpression.value === null ||
1659
+ leftExpression.value === undefined ||
1660
+ rightExpression.value === null ||
1661
+ rightExpression.value === undefined
1662
+ ) {
1663
+ return constant(false);
1664
+ }
1665
+ // Check all the children of the right expression are constants
1666
+ const allChildrenConstants = (rightExpression.value as T[]).every((item) => isConstant(item));
1667
+ if (allChildrenConstants) {
1668
+ const rightValues = (rightExpression.value as ConstantExpression<T>[]).map((item) => item.value);
1669
+ return constant(rightValues.includes(leftExpression.value));
1670
+ } else {
1671
+ return {
1672
+ _type: "Comparison",
1673
+ operator: operator,
1674
+ operand1: leftExpression,
1675
+ operand2: rightExpression
1676
+ };
1677
+ }
1678
+ }
1211
1679
  }
1212
1680
  } else {
1213
1681
  return {
@@ -1362,6 +1830,20 @@ export function lessThan<T extends DefinedPrimitiveType>(
1362
1830
  return comparison("<", leftOperand, rightOperand);
1363
1831
  }
1364
1832
 
1833
+ /**
1834
+ * Comparison: "Include" (In).
1835
+ * @template T The target type
1836
+ * @param leftOperand The operand on the left side
1837
+ * @param rightOperand The operand on the right side of the comparison
1838
+ * @returns An expression representing the comparison
1839
+ */
1840
+ export function includes<T extends DefinedPrimitiveType>(
1841
+ leftOperand: ExpressionOrPrimitive<T>,
1842
+ rightOperand: ExpressionOrPrimitive<T[]>
1843
+ ): BindingToolkitExpression<boolean> {
1844
+ return comparison("In", leftOperand, rightOperand as ExpressionOrPrimitive<T>);
1845
+ }
1846
+
1365
1847
  /**
1366
1848
  * If-then-else expression.
1367
1849
  *
@@ -1587,7 +2069,7 @@ export function formatResult<T, U extends Fn<T>>(
1587
2069
  }
1588
2070
 
1589
2071
  type BindingConstraints = {
1590
- scale?: number;
2072
+ scale?: number | string;
1591
2073
  precision?: number;
1592
2074
  maxLength?: number;
1593
2075
  nullable?: boolean;
@@ -1909,7 +2391,7 @@ export function isEmpty(expression: BindingToolkitExpression<string>): BindingTo
1909
2391
  * @param exp The expression to evaluate
1910
2392
  * @returns A Boolean evaluating if there is no relative path dependent on the current context
1911
2393
  */
1912
- export function isExpressionStaticallyResolvable(exp: BindingToolkitExpression<boolean>): boolean {
2394
+ export function isExpressionStaticallyResolvable<T extends PrimitiveType>(exp: BindingToolkitExpression<T>): boolean {
1913
2395
  const referencedPaths: string[] = [];
1914
2396
  transformRecursively(
1915
2397
  exp,
@@ -1928,6 +2410,28 @@ export function isExpressionStaticallyResolvable(exp: BindingToolkitExpression<b
1928
2410
  return referencedPaths.every((p) => p.startsWith("/"));
1929
2411
  }
1930
2412
 
2413
+ export function getStaticallyResolvableExpression<T extends PrimitiveType>(
2414
+ exp: BindingToolkitExpression<T>,
2415
+ defaultValue: BindingToolkitExpression<T>
2416
+ ): BindingToolkitExpression<T> {
2417
+ if (exp._type === "Set") {
2418
+ const newOperands = exp.operands.map((operand: BindingToolkitExpression<boolean>) => {
2419
+ if (isExpressionStaticallyResolvable(operand) || isConstant(operand)) {
2420
+ return operand;
2421
+ } else {
2422
+ return defaultValue;
2423
+ }
2424
+ });
2425
+
2426
+ if (exp.operator === "||") {
2427
+ return or(...(newOperands as unknown as BindingToolkitExpression<boolean>[])) as unknown as BindingToolkitExpression<T>;
2428
+ } else {
2429
+ return and(...(newOperands as unknown as BindingToolkitExpression<boolean>[])) as unknown as BindingToolkitExpression<T>;
2430
+ }
2431
+ }
2432
+ return isExpressionStaticallyResolvable(exp) ? exp : defaultValue;
2433
+ }
2434
+
1931
2435
  export function concat(...inExpressions: ExpressionOrPrimitive<string>[]): BindingToolkitExpression<string> {
1932
2436
  const expressions = inExpressions.map(wrapPrimitive);
1933
2437
  if (hasUnresolvableExpression(...expressions)) {
@@ -2076,6 +2580,21 @@ export function transformRecursively<T extends PrimitiveType | unknown, ET exten
2076
2580
  expression = comparison(expression.operator, operand1, operand2) as BindingToolkitExpression<T>;
2077
2581
  }
2078
2582
  break;
2583
+ case "Arithmetic":
2584
+ const operand1 = transformRecursively(
2585
+ expression.operand1 as BindingToolkitExpression<T>,
2586
+ expressionType,
2587
+ transformFunction,
2588
+ includeAllExpression
2589
+ );
2590
+ const operand2 = transformRecursively(
2591
+ expression.operand2 as BindingToolkitExpression<T>,
2592
+ expressionType,
2593
+ transformFunction,
2594
+ includeAllExpression
2595
+ );
2596
+ expression = arithmetic(expression.operator, operand1, operand2) as BindingToolkitExpression<T>;
2597
+ break;
2079
2598
  case "Constant":
2080
2599
  const constantValue: Record<string, BindingToolkitExpression<unknown>> = expression.value as Record<
2081
2600
  string,
@@ -2392,6 +2911,9 @@ export function compileExpression<T extends PrimitiveType>(
2392
2911
  case "Not":
2393
2912
  const notExpression = `!${compileExpression(expr.operand, true)}`;
2394
2913
  return wrapBindingExpression(notExpression, embeddedInBinding);
2914
+ case "Arithmetic":
2915
+ const arithmeticExpression = compileArithmeticExpression(expr);
2916
+ return wrapBindingExpression(arithmeticExpression, embeddedInBinding);
2395
2917
 
2396
2918
  case "Truthy":
2397
2919
  const truthyExpression = `!!${compileExpression(expr.operand, true)}`;
@@ -2410,6 +2932,25 @@ export function compileExpression<T extends PrimitiveType>(
2410
2932
  }
2411
2933
  }
2412
2934
 
2935
+ function compileArithmeticExpression(expression: ArithmeticExpression): string {
2936
+ function compileOperand(operand: BindingToolkitExpression<unknown>): CompiledBindingToolkitExpression {
2937
+ const compiledOperand = compileExpression(operand, true) ?? "undefined";
2938
+ return wrapBindingExpression(compiledOperand, true, needParenthesis(operand));
2939
+ }
2940
+ switch (expression.operator) {
2941
+ case "Neg":
2942
+ return `-(${compileOperand(expression.operand1)})`;
2943
+ case "Floor":
2944
+ return `Math.floor(${compileOperand(expression.operand1)})`;
2945
+ case "%":
2946
+ case "/":
2947
+ case "*":
2948
+ case "+":
2949
+ case "-":
2950
+ return `${compileOperand(expression.operand1)} ${expression.operator} ${compileOperand(expression.operand2)}`;
2951
+ }
2952
+ }
2953
+
2413
2954
  /**
2414
2955
  * Compile a comparison expression.
2415
2956
  * @param expression The comparison expression.
@@ -2420,8 +2961,25 @@ function compileComparisonExpression(expression: ComparisonExpression): string {
2420
2961
  const compiledOperand = compileExpression(operand, true) ?? "undefined";
2421
2962
  return wrapBindingExpression(compiledOperand, true, needParenthesis(operand));
2422
2963
  }
2423
-
2424
- return `${compileOperand(expression.operand1)} ${expression.operator} ${compileOperand(expression.operand2)}`;
2964
+ switch (expression.operator) {
2965
+ case "In": {
2966
+ const path = compileOperand(expression.operand1);
2967
+ const collection = compileOperand(expression.operand2) ?? [];
2968
+ return `${collection}.includes(${path})`;
2969
+ }
2970
+ case "Has": {
2971
+ const path = compileOperand(expression.operand1);
2972
+ const flags = compileOperand(expression.operand2) ?? [];
2973
+ return `(${path} & ${flags}) > 0`;
2974
+ }
2975
+ case "===":
2976
+ case "!==":
2977
+ case ">=":
2978
+ case ">":
2979
+ case "<=":
2980
+ case "<":
2981
+ return `${compileOperand(expression.operand1)} ${expression.operator} ${compileOperand(expression.operand2)}`;
2982
+ }
2425
2983
  }
2426
2984
 
2427
2985
  /**