@sapui5/sap.fe.core 1.96.4 → 1.99.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/package.json +6 -5
- package/src/sap/fe/core/.library +1 -1
- package/src/sap/fe/core/AnnotationHelper.js +377 -405
- package/src/sap/fe/core/AnnotationHelper.ts +385 -0
- package/src/sap/fe/core/AppComponent.js +5 -3
- package/src/sap/fe/core/AppStateHandler.js +229 -195
- package/src/sap/fe/core/AppStateHandler.ts +171 -0
- package/src/sap/fe/core/BaseController.js +3 -2
- package/src/sap/fe/core/BusyLocker.js +105 -121
- package/src/sap/fe/core/BusyLocker.ts +98 -0
- package/src/sap/fe/core/CommonUtils.js +2073 -2606
- package/src/sap/fe/core/CommonUtils.ts +2078 -0
- package/src/sap/fe/core/ExtensionAPI.js +16 -7
- package/src/sap/fe/core/PageController.js +84 -119
- package/src/sap/fe/core/PageController.ts +101 -0
- package/src/sap/fe/core/RouterProxy.js +986 -809
- package/src/sap/fe/core/RouterProxy.ts +838 -0
- package/src/sap/fe/core/Synchronization.js +51 -35
- package/src/sap/fe/core/Synchronization.ts +29 -0
- package/src/sap/fe/core/TemplateComponent.js +173 -155
- package/src/sap/fe/core/TemplateComponent.ts +166 -0
- package/src/sap/fe/core/TemplateModel.js +97 -54
- package/src/sap/fe/core/TemplateModel.ts +63 -0
- package/src/sap/fe/core/TransactionHelper.js +1576 -1627
- package/src/sap/fe/core/TransactionHelper.ts +1706 -0
- package/src/sap/fe/core/actions/draft.js +559 -581
- package/src/sap/fe/core/actions/draft.ts +593 -0
- package/src/sap/fe/core/actions/messageHandling.js +545 -435
- package/src/sap/fe/core/actions/messageHandling.ts +532 -0
- package/src/sap/fe/core/actions/nonDraft.js +17 -19
- package/src/sap/fe/core/actions/nonDraft.ts +12 -0
- package/src/sap/fe/core/actions/operations.js +1074 -1192
- package/src/sap/fe/core/actions/operations.ts +1162 -0
- package/src/sap/fe/core/actions/sticky.js +102 -105
- package/src/sap/fe/core/actions/sticky.ts +102 -0
- package/src/sap/fe/core/controllerextensions/ControllerExtensionMetadata.js +3 -2
- package/src/sap/fe/core/controllerextensions/EditFlow.js +235 -264
- package/src/sap/fe/core/controllerextensions/IntentBasedNavigation.js +3 -2
- package/src/sap/fe/core/controllerextensions/InternalEditFlow.js +288 -13
- package/src/sap/fe/core/controllerextensions/InternalIntentBasedNavigation.js +35 -25
- package/src/sap/fe/core/controllerextensions/InternalRouting.js +79 -46
- package/src/sap/fe/core/controllerextensions/KPIManagement.js +86 -10
- package/src/sap/fe/core/controllerextensions/KPIManagement.ts +109 -31
- package/src/sap/fe/core/controllerextensions/MassEdit.js +172 -0
- package/src/sap/fe/core/controllerextensions/MessageHandler.js +237 -104
- package/src/sap/fe/core/controllerextensions/PageReady.js +3 -3
- package/src/sap/fe/core/controllerextensions/PageReady.ts +12 -8
- package/src/sap/fe/core/controllerextensions/Paginator.js +37 -9
- package/src/sap/fe/core/controllerextensions/Placeholder.js +8 -4
- package/src/sap/fe/core/controllerextensions/Routing.js +25 -5
- package/src/sap/fe/core/controllerextensions/RoutingListener.js +3 -2
- package/src/sap/fe/core/controllerextensions/Share.js +3 -2
- package/src/sap/fe/core/controllerextensions/SideEffects.js +9 -9
- package/src/sap/fe/core/controllerextensions/SideEffects.ts +22 -21
- package/src/sap/fe/core/controllerextensions/ViewState.js +36 -8
- package/src/sap/fe/core/controls/ActionParameterDialog.fragment.xml +2 -1
- package/src/sap/fe/core/controls/CommandExecution.js +3 -2
- package/src/sap/fe/core/controls/ConditionalWrapper.js +3 -2
- package/src/sap/fe/core/controls/CustomQuickViewPage.js +112 -113
- package/src/sap/fe/core/controls/DataLossOrDraftDiscard/DataLossOrDraftDiscardHandler.js +9 -5
- package/src/sap/fe/core/controls/FieldWrapper.js +18 -23
- package/src/sap/fe/core/controls/FilterBar.js +3 -2
- package/src/sap/fe/core/controls/FormElementWrapper.js +3 -7
- package/src/sap/fe/core/controls/MultiValueParameterDelegate.js +3 -2
- package/src/sap/fe/core/controls/NonComputedVisibleKeyFieldsDialog.fragment.xml +2 -1
- package/src/sap/fe/core/controls/filterbar/FilterContainer.js +3 -2
- package/src/sap/fe/core/controls/filterbar/VisualFilter.js +5 -4
- package/src/sap/fe/core/controls/filterbar/VisualFilterContainer.js +3 -2
- package/src/sap/fe/core/controls/filterbar/utils/VisualFilterUtils.js +3 -2
- package/src/sap/fe/core/controls/massEdit/MassEditDialog.fragment.xml +106 -0
- package/src/sap/fe/core/controls/massEdit/MassEditHandlers.js +79 -0
- package/src/sap/fe/core/converters/ConverterContext.js +14 -2
- package/src/sap/fe/core/converters/ConverterContext.ts +14 -3
- package/src/sap/fe/core/converters/ManifestSettings.js +2 -1
- package/src/sap/fe/core/converters/ManifestSettings.ts +8 -1
- package/src/sap/fe/core/converters/ManifestWrapper.js +56 -32
- package/src/sap/fe/core/converters/ManifestWrapper.ts +24 -6
- package/src/sap/fe/core/converters/MetaModelConverter.js +76 -6
- package/src/sap/fe/core/converters/MetaModelConverter.ts +79 -15
- package/src/sap/fe/core/converters/TemplateConverter.js +1 -1
- package/src/sap/fe/core/converters/TemplateConverter.ts +2 -2
- package/src/sap/fe/core/converters/annotations/DataField.js +3 -3
- package/src/sap/fe/core/converters/annotations/DataField.ts +1 -1
- package/src/sap/fe/core/converters/common/AnnotationConverter.js +85 -46
- package/src/sap/fe/core/converters/controls/Common/Action.js +16 -4
- package/src/sap/fe/core/converters/controls/Common/Action.ts +14 -5
- package/src/sap/fe/core/converters/controls/Common/Chart.js +5 -3
- package/src/sap/fe/core/converters/controls/Common/Chart.ts +11 -3
- package/src/sap/fe/core/converters/controls/Common/DataVisualization.js +3 -3
- package/src/sap/fe/core/converters/controls/Common/DataVisualization.ts +2 -2
- package/src/sap/fe/core/converters/controls/Common/Form.js +60 -19
- package/src/sap/fe/core/converters/controls/Common/Form.ts +66 -14
- package/src/sap/fe/core/converters/controls/Common/KPI.js +69 -4
- package/src/sap/fe/core/converters/controls/Common/KPI.ts +72 -0
- package/src/sap/fe/core/converters/controls/Common/Table.js +503 -399
- package/src/sap/fe/core/converters/controls/Common/Table.ts +615 -480
- package/src/sap/fe/core/converters/controls/Common/table/StandardActions.js +527 -0
- package/src/sap/fe/core/converters/controls/Common/table/StandardActions.ts +655 -0
- package/src/sap/fe/core/converters/controls/ListReport/FilterBar.js +489 -37
- package/src/sap/fe/core/converters/controls/ListReport/FilterBar.ts +506 -58
- package/src/sap/fe/core/converters/controls/ListReport/VisualFilters.js +2 -2
- package/src/sap/fe/core/converters/controls/ListReport/VisualFilters.ts +1 -1
- package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.js +6 -6
- package/src/sap/fe/core/converters/controls/ObjectPage/SubSection.ts +9 -15
- package/src/sap/fe/core/converters/helpers/Aggregation.js +18 -3
- package/src/sap/fe/core/converters/helpers/Aggregation.ts +28 -5
- package/src/sap/fe/core/converters/helpers/ID.js +9 -1
- package/src/sap/fe/core/converters/helpers/ID.ts +4 -0
- package/src/sap/fe/core/converters/helpers/IssueManager.js +7 -1
- package/src/sap/fe/core/converters/helpers/IssueManager.ts +6 -0
- package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.js +4 -4
- package/src/sap/fe/core/converters/objectPage/HeaderAndFooterAction.ts +3 -3
- package/src/sap/fe/core/converters/templates/ListReportConverter.js +29 -11
- package/src/sap/fe/core/converters/templates/ListReportConverter.ts +36 -20
- package/src/sap/fe/core/designtime/AppComponent.designtime.js +13 -3
- package/src/sap/fe/core/formatters/CriticalityFormatter.js +1 -1
- package/src/sap/fe/core/formatters/CriticalityFormatter.ts +1 -1
- package/src/sap/fe/core/formatters/FPMFormatter.js +1 -1
- package/src/sap/fe/core/formatters/FPMFormatter.ts +4 -10
- package/src/sap/fe/core/formatters/KPIFormatter.js +1 -1
- package/src/sap/fe/core/formatters/KPIFormatter.ts +3 -1
- package/src/sap/fe/core/formatters/TableFormatter.js +65 -31
- package/src/sap/fe/core/formatters/TableFormatter.ts +62 -30
- package/src/sap/fe/core/formatters/ValueFormatter.js +30 -5
- package/src/sap/fe/core/formatters/ValueFormatter.ts +30 -7
- package/src/sap/fe/core/fpm/Component.js +3 -2
- package/src/sap/fe/core/helpers/AppStartupHelper.js +359 -0
- package/src/sap/fe/core/helpers/AppStartupHelper.ts +391 -0
- package/src/sap/fe/core/helpers/BindingExpression.js +479 -464
- package/src/sap/fe/core/helpers/BindingExpression.ts +477 -483
- package/src/sap/fe/core/helpers/ClassSupport.js +27 -15
- package/src/sap/fe/core/helpers/ClassSupport.ts +31 -20
- package/src/sap/fe/core/helpers/DynamicAnnotationPathHelper.js +63 -59
- package/src/sap/fe/core/helpers/DynamicAnnotationPathHelper.ts +56 -0
- package/src/sap/fe/core/helpers/EditState.js +81 -84
- package/src/sap/fe/core/helpers/EditState.ts +81 -0
- package/src/sap/fe/core/helpers/ExcelFormatHelper.js +62 -48
- package/src/sap/fe/core/helpers/ExcelFormatHelper.ts +49 -0
- package/src/sap/fe/core/helpers/FPMHelper.js +52 -56
- package/src/sap/fe/core/helpers/FPMHelper.ts +62 -0
- package/src/sap/fe/core/helpers/KeepAliveHelper.js +210 -0
- package/src/sap/fe/core/helpers/KeepAliveHelper.ts +202 -0
- package/src/sap/fe/core/helpers/KeepAliveRefreshTypes.js +32 -0
- package/src/sap/fe/core/helpers/KeepAliveRefreshTypes.ts +36 -0
- package/src/sap/fe/core/helpers/MassEditHelper.js +687 -0
- package/src/sap/fe/core/helpers/ModelHelper.js +229 -174
- package/src/sap/fe/core/helpers/ModelHelper.ts +227 -0
- package/src/sap/fe/core/helpers/PasteHelper.js +210 -132
- package/src/sap/fe/core/helpers/PasteHelper.ts +196 -0
- package/src/sap/fe/core/helpers/SemanticDateOperators.js +332 -313
- package/src/sap/fe/core/helpers/SemanticDateOperators.ts +330 -0
- package/src/sap/fe/core/helpers/SemanticKeyHelper.js +66 -67
- package/src/sap/fe/core/helpers/SemanticKeyHelper.ts +73 -0
- package/src/sap/fe/core/helpers/StableIdHelper.js +4 -7
- package/src/sap/fe/core/helpers/StableIdHelper.ts +2 -6
- package/src/sap/fe/core/jsx-runtime/jsx.js +1 -1
- package/src/sap/fe/core/jsx-runtime/jsx.ts +1 -1
- package/src/sap/fe/core/library.js +30 -3
- package/src/sap/fe/core/library.support.js +12 -5
- package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.js +62 -0
- package/src/sap/fe/core/manifestMerger/ChangePageConfiguration.ts +66 -0
- package/src/sap/fe/core/messagebundle.properties +72 -10
- package/src/sap/fe/core/messagebundle_ar.properties +41 -0
- package/src/sap/fe/core/messagebundle_bg.properties +41 -0
- package/src/sap/fe/core/messagebundle_ca.properties +41 -0
- package/src/sap/fe/core/messagebundle_cs.properties +42 -1
- package/src/sap/fe/core/messagebundle_cy.properties +41 -0
- package/src/sap/fe/core/messagebundle_da.properties +41 -0
- package/src/sap/fe/core/messagebundle_de.properties +41 -0
- package/src/sap/fe/core/messagebundle_el.properties +41 -0
- package/src/sap/fe/core/messagebundle_en.properties +41 -0
- package/src/sap/fe/core/messagebundle_en_GB.properties +41 -0
- package/src/sap/fe/core/messagebundle_en_US_sappsd.properties +41 -0
- package/src/sap/fe/core/messagebundle_en_US_saprigi.properties +35 -0
- package/src/sap/fe/core/messagebundle_en_US_saptrc.properties +41 -0
- package/src/sap/fe/core/messagebundle_es.properties +41 -0
- package/src/sap/fe/core/messagebundle_es_MX.properties +41 -0
- package/src/sap/fe/core/messagebundle_et.properties +41 -0
- package/src/sap/fe/core/messagebundle_fi.properties +41 -0
- package/src/sap/fe/core/messagebundle_fr.properties +46 -5
- package/src/sap/fe/core/messagebundle_fr_CA.properties +41 -0
- package/src/sap/fe/core/messagebundle_hi.properties +41 -0
- package/src/sap/fe/core/messagebundle_hr.properties +41 -0
- package/src/sap/fe/core/messagebundle_hu.properties +42 -1
- package/src/sap/fe/core/messagebundle_id.properties +45 -4
- package/src/sap/fe/core/messagebundle_it.properties +41 -0
- package/src/sap/fe/core/messagebundle_iw.properties +41 -0
- package/src/sap/fe/core/messagebundle_ja.properties +50 -9
- package/src/sap/fe/core/messagebundle_kk.properties +41 -0
- package/src/sap/fe/core/messagebundle_ko.properties +41 -0
- package/src/sap/fe/core/messagebundle_lt.properties +41 -0
- package/src/sap/fe/core/messagebundle_lv.properties +41 -0
- package/src/sap/fe/core/messagebundle_ms.properties +41 -0
- package/src/sap/fe/core/messagebundle_nl.properties +41 -0
- package/src/sap/fe/core/messagebundle_no.properties +41 -0
- package/src/sap/fe/core/messagebundle_pl.properties +41 -0
- package/src/sap/fe/core/messagebundle_pt.properties +43 -2
- package/src/sap/fe/core/messagebundle_pt_PT.properties +41 -0
- package/src/sap/fe/core/messagebundle_ro.properties +41 -0
- package/src/sap/fe/core/messagebundle_ru.properties +41 -0
- package/src/sap/fe/core/messagebundle_sh.properties +41 -0
- package/src/sap/fe/core/messagebundle_sk.properties +41 -0
- package/src/sap/fe/core/messagebundle_sl.properties +41 -0
- package/src/sap/fe/core/messagebundle_sv.properties +42 -1
- package/src/sap/fe/core/messagebundle_th.properties +41 -0
- package/src/sap/fe/core/messagebundle_tr.properties +41 -0
- package/src/sap/fe/core/messagebundle_uk.properties +41 -0
- package/src/sap/fe/core/messagebundle_vi.properties +41 -0
- package/src/sap/fe/core/messagebundle_zh_CN.properties +41 -0
- package/src/sap/fe/core/messagebundle_zh_TW.properties +41 -0
- package/src/sap/fe/core/services/AsyncComponentServiceFactory.js +2 -2
- package/src/sap/fe/core/services/AsyncComponentServiceFactory.ts +3 -1
- package/src/sap/fe/core/services/CacheHandlerServiceFactory.js +269 -202
- package/src/sap/fe/core/services/CacheHandlerServiceFactory.ts +212 -0
- package/src/sap/fe/core/services/EnvironmentServiceFactory.js +4 -3
- package/src/sap/fe/core/services/EnvironmentServiceFactory.ts +9 -5
- package/src/sap/fe/core/services/NavigationServiceFactory.js +406 -300
- package/src/sap/fe/core/services/NavigationServiceFactory.ts +316 -0
- package/src/sap/fe/core/services/ResourceModelServiceFactory.js +149 -81
- package/src/sap/fe/core/services/ResourceModelServiceFactory.ts +80 -0
- package/src/sap/fe/core/services/RoutingServiceFactory.js +987 -1166
- package/src/sap/fe/core/services/RoutingServiceFactory.ts +898 -0
- package/src/sap/fe/core/services/ShellServicesFactory.js +31 -2
- package/src/sap/fe/core/services/ShellServicesFactory.ts +45 -11
- package/src/sap/fe/core/services/SideEffectsServiceFactory.js +41 -84
- package/src/sap/fe/core/services/SideEffectsServiceFactory.ts +56 -99
- package/src/sap/fe/core/services/TemplatedViewServiceFactory.js +461 -478
- package/src/sap/fe/core/services/TemplatedViewServiceFactory.ts +453 -0
- package/src/sap/fe/core/services/view/TemplatingErrorPage.controller.js +10 -8
- package/src/sap/fe/core/services/view/TemplatingErrorPage.controller.ts +8 -0
- package/src/sap/fe/core/support/AnnotationIssue.support.js +15 -3
- package/src/sap/fe/core/support/AnnotationIssue.support.ts +16 -2
- package/src/sap/fe/core/support/CollectionFacetUnsupportedLevel.support.js +2 -2
- package/src/sap/fe/core/support/CollectionFacetUnsupportedLevel.support.ts +1 -1
- package/src/sap/fe/core/support/InvalidAnnotationColumnKey.support.js +38 -0
- package/src/sap/fe/core/support/InvalidAnnotationColumnKey.support.ts +18 -0
- package/src/sap/fe/core/templating/DataModelPathHelper.js +6 -24
- package/src/sap/fe/core/templating/DataModelPathHelper.ts +10 -23
- package/src/sap/fe/core/templating/DisplayModeFormatter.js +114 -0
- package/src/sap/fe/core/templating/DisplayModeFormatter.ts +86 -0
- package/src/sap/fe/core/templating/EntitySetHelper.js +80 -7
- package/src/sap/fe/core/templating/EntitySetHelper.ts +42 -2
- package/src/sap/fe/core/templating/FieldControlHelper.js +8 -8
- package/src/sap/fe/core/templating/FieldControlHelper.ts +25 -7
- package/src/sap/fe/core/templating/FilterHelper.js +139 -70
- package/src/sap/fe/core/templating/FilterHelper.ts +140 -70
- package/src/sap/fe/core/templating/PropertyHelper.js +2 -2
- package/src/sap/fe/core/templating/PropertyHelper.ts +1 -1
- package/src/sap/fe/core/templating/UIFormatters.js +45 -113
- package/src/sap/fe/core/templating/UIFormatters.ts +39 -76
- package/src/sap/fe/core/type/Email.js +1 -1
- package/src/sap/fe/core/type/Email.ts +4 -6
- package/ui5.yaml +0 -3
|
@@ -28,7 +28,7 @@ import { ApplyAnnotationExpression, PathAnnotationExpression } from "@sap-ux/voc
|
|
|
28
28
|
import { EntitySet } from "@sap-ux/vocabularies-types/dist/Converter";
|
|
29
29
|
import { resolveEnumValue } from "./AnnotationEnum";
|
|
30
30
|
|
|
31
|
-
type PrimitiveType = string | number | boolean | object | null | undefined;
|
|
31
|
+
type PrimitiveType = string | number | bigint | boolean | object | null | undefined;
|
|
32
32
|
|
|
33
33
|
type BaseExpression<T> = {
|
|
34
34
|
_type: string;
|
|
@@ -87,6 +87,11 @@ export type ConcatExpression = BaseExpression<string> & {
|
|
|
87
87
|
expressions: Expression<string>[];
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
+
export type LengthExpression = BaseExpression<string> & {
|
|
91
|
+
_type: "Length";
|
|
92
|
+
bindingExpression: BindingExpressionExpression<any>;
|
|
93
|
+
};
|
|
94
|
+
|
|
90
95
|
export type UnresolveableBindingExpression = BaseExpression<string> & {
|
|
91
96
|
_type: "Unresolveable";
|
|
92
97
|
};
|
|
@@ -154,6 +159,7 @@ export type Expression<T> =
|
|
|
154
159
|
| NotExpression
|
|
155
160
|
| TruthyExpression
|
|
156
161
|
| ConcatExpression
|
|
162
|
+
| LengthExpression
|
|
157
163
|
| BindingExpressionExpression<T>
|
|
158
164
|
| EmbeddedBindingExpression<T>
|
|
159
165
|
| EmbeddedExpressionBindingExpression<T>
|
|
@@ -175,14 +181,7 @@ export const unresolveableExpression: UnresolveableBindingExpression = {
|
|
|
175
181
|
};
|
|
176
182
|
|
|
177
183
|
function escapeXmlAttribute(inputString: string) {
|
|
178
|
-
return inputString.replace(/
|
|
179
|
-
switch (c) {
|
|
180
|
-
case "'":
|
|
181
|
-
return "\\'";
|
|
182
|
-
default:
|
|
183
|
-
return c;
|
|
184
|
-
}
|
|
185
|
-
});
|
|
184
|
+
return inputString.replace(/'/g, "\\'");
|
|
186
185
|
}
|
|
187
186
|
|
|
188
187
|
export function hasUnresolveableExpression(...expressions: Expression<any>[]): boolean {
|
|
@@ -230,7 +229,7 @@ export function _checkExpressionsAreEqual<T>(a: Expression<T>, b: Expression<T>)
|
|
|
230
229
|
|
|
231
230
|
case "Comparison":
|
|
232
231
|
return (
|
|
233
|
-
a.operator
|
|
232
|
+
a.operator === (b as ComparisonExpression).operator &&
|
|
234
233
|
_checkExpressionsAreEqual(a.operand1, (b as ComparisonExpression).operand1) &&
|
|
235
234
|
_checkExpressionsAreEqual(a.operand2, (b as ComparisonExpression).operand2)
|
|
236
235
|
);
|
|
@@ -245,6 +244,9 @@ export function _checkExpressionsAreEqual<T>(a: Expression<T>, b: Expression<T>)
|
|
|
245
244
|
return _checkExpressionsAreEqual(expression, bExpressions[index]);
|
|
246
245
|
});
|
|
247
246
|
|
|
247
|
+
case "Length":
|
|
248
|
+
return _checkExpressionsAreEqual(a.bindingExpression, (b as LengthExpression).bindingExpression);
|
|
249
|
+
|
|
248
250
|
case "Binding":
|
|
249
251
|
return (
|
|
250
252
|
a.modelName === (b as BindingExpressionExpression<T>).modelName &&
|
|
@@ -288,6 +290,7 @@ export function _checkExpressionsAreEqual<T>(a: Expression<T>, b: Expression<T>)
|
|
|
288
290
|
case "Ref":
|
|
289
291
|
return a.ref === (b as ReferenceExpression).ref;
|
|
290
292
|
}
|
|
293
|
+
return false;
|
|
291
294
|
}
|
|
292
295
|
|
|
293
296
|
/**
|
|
@@ -319,21 +322,15 @@ function flattenSetExpression(expression: SetExpression): SetExpression {
|
|
|
319
322
|
* @returns {boolean} `true` if the set of expressions contains an expression and its negation
|
|
320
323
|
*/
|
|
321
324
|
function hasOppositeExpressions(expressions: Expression<boolean>[]): boolean {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
let i = expressions.length;
|
|
327
|
-
while (i--) {
|
|
328
|
-
const expression = expressions[i];
|
|
329
|
-
const negatedExpression = not(expression);
|
|
330
|
-
for (let j = 0; j < i; j++) {
|
|
331
|
-
if (_checkExpressionsAreEqual(expressions[j], negatedExpression)) {
|
|
325
|
+
const negatedExpressions = expressions.map(not);
|
|
326
|
+
return expressions.some((expression, index) => {
|
|
327
|
+
for (let i = index + 1; i < negatedExpressions.length; i++) {
|
|
328
|
+
if (_checkExpressionsAreEqual(expression, negatedExpressions[i])) {
|
|
332
329
|
return true;
|
|
333
330
|
}
|
|
334
331
|
}
|
|
335
|
-
|
|
336
|
-
|
|
332
|
+
return false;
|
|
333
|
+
});
|
|
337
334
|
}
|
|
338
335
|
|
|
339
336
|
/**
|
|
@@ -355,9 +352,9 @@ export function and(...operands: ExpressionOrPrimitive<boolean>[]): Expression<b
|
|
|
355
352
|
if (hasUnresolveableExpression(...expressions)) {
|
|
356
353
|
return unresolveableExpression;
|
|
357
354
|
}
|
|
358
|
-
let isStaticFalse
|
|
355
|
+
let isStaticFalse = false;
|
|
359
356
|
const nonTrivialExpression = expressions.filter(expression => {
|
|
360
|
-
if (
|
|
357
|
+
if (isFalse(expression)) {
|
|
361
358
|
isStaticFalse = true;
|
|
362
359
|
}
|
|
363
360
|
return !isConstant(expression);
|
|
@@ -366,9 +363,7 @@ export function and(...operands: ExpressionOrPrimitive<boolean>[]): Expression<b
|
|
|
366
363
|
return constant(false);
|
|
367
364
|
} else if (nonTrivialExpression.length === 0) {
|
|
368
365
|
// Resolve the constant then
|
|
369
|
-
const isValid = expressions.reduce((
|
|
370
|
-
return isValid && isConstant(expression) && expression.value;
|
|
371
|
-
}, true);
|
|
366
|
+
const isValid = expressions.reduce((result, expression) => result && isTrue(expression), true);
|
|
372
367
|
return constant(isValid);
|
|
373
368
|
} else if (nonTrivialExpression.length === 1) {
|
|
374
369
|
return nonTrivialExpression[0];
|
|
@@ -401,9 +396,9 @@ export function or(...operands: ExpressionOrPrimitive<boolean>[]): Expression<bo
|
|
|
401
396
|
if (hasUnresolveableExpression(...expressions)) {
|
|
402
397
|
return unresolveableExpression;
|
|
403
398
|
}
|
|
404
|
-
let isStaticTrue
|
|
399
|
+
let isStaticTrue = false;
|
|
405
400
|
const nonTrivialExpression = expressions.filter(expression => {
|
|
406
|
-
if (
|
|
401
|
+
if (isTrue(expression)) {
|
|
407
402
|
isStaticTrue = true;
|
|
408
403
|
}
|
|
409
404
|
return !isConstant(expression) || expression.value;
|
|
@@ -412,9 +407,7 @@ export function or(...operands: ExpressionOrPrimitive<boolean>[]): Expression<bo
|
|
|
412
407
|
return constant(true);
|
|
413
408
|
} else if (nonTrivialExpression.length === 0) {
|
|
414
409
|
// Resolve the constant then
|
|
415
|
-
const isValid = expressions.reduce((
|
|
416
|
-
return isValid && isConstant(expression) && expression.value;
|
|
417
|
-
}, true);
|
|
410
|
+
const isValid = expressions.reduce((result, expression) => result && isTrue(expression), true);
|
|
418
411
|
return constant(isValid);
|
|
419
412
|
} else if (nonTrivialExpression.length === 1) {
|
|
420
413
|
return nonTrivialExpression[0];
|
|
@@ -459,26 +452,26 @@ export function not(operand: ExpressionOrPrimitive<boolean>): Expression<boolean
|
|
|
459
452
|
// Create the reverse comparison
|
|
460
453
|
switch (operand.operator) {
|
|
461
454
|
case "!==":
|
|
462
|
-
return
|
|
455
|
+
return { ...operand, operator: "===" };
|
|
463
456
|
case "<":
|
|
464
|
-
return
|
|
457
|
+
return { ...operand, operator: ">=" };
|
|
465
458
|
case "<=":
|
|
466
|
-
return
|
|
459
|
+
return { ...operand, operator: ">" };
|
|
467
460
|
case "===":
|
|
468
|
-
return
|
|
461
|
+
return { ...operand, operator: "!==" };
|
|
469
462
|
case ">":
|
|
470
|
-
return
|
|
463
|
+
return { ...operand, operator: "<=" };
|
|
471
464
|
case ">=":
|
|
472
|
-
return
|
|
465
|
+
return { ...operand, operator: "<" };
|
|
473
466
|
}
|
|
474
467
|
} else if (operand._type === "Not") {
|
|
475
468
|
return operand.operand;
|
|
476
|
-
} else {
|
|
477
|
-
return {
|
|
478
|
-
_type: "Not",
|
|
479
|
-
operand: operand
|
|
480
|
-
};
|
|
481
469
|
}
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
_type: "Not",
|
|
473
|
+
operand: operand
|
|
474
|
+
};
|
|
482
475
|
}
|
|
483
476
|
|
|
484
477
|
/**
|
|
@@ -550,19 +543,16 @@ export function constant<T extends PrimitiveType>(value: T): ConstantExpression<
|
|
|
550
543
|
if (typeof value === "object" && value !== null && value !== undefined) {
|
|
551
544
|
if (Array.isArray(value)) {
|
|
552
545
|
constantValue = value.map(wrapPrimitive) as T;
|
|
553
|
-
} else if (isPrimitiveObject(value
|
|
546
|
+
} else if (isPrimitiveObject(value)) {
|
|
554
547
|
constantValue = value.valueOf() as T;
|
|
555
548
|
} else {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
obj[key] = value;
|
|
549
|
+
constantValue = Object.entries(value).reduce((plainExpression, [key, val]) => {
|
|
550
|
+
const wrappedValue = wrapPrimitive(val);
|
|
551
|
+
if (wrappedValue._type !== "Constant" || wrappedValue.value !== undefined) {
|
|
552
|
+
plainExpression[key] = wrappedValue;
|
|
561
553
|
}
|
|
562
|
-
return
|
|
563
|
-
}, {} as PlainExpressionObject);
|
|
564
|
-
|
|
565
|
-
constantValue = obj as T;
|
|
554
|
+
return plainExpression;
|
|
555
|
+
}, {} as PlainExpressionObject) as T;
|
|
566
556
|
}
|
|
567
557
|
} else {
|
|
568
558
|
constantValue = value;
|
|
@@ -589,16 +579,10 @@ export function resolveBindingString<T extends PrimitiveType>(
|
|
|
589
579
|
value: value
|
|
590
580
|
};
|
|
591
581
|
}
|
|
582
|
+
} else if (targetType === "boolean" && typeof value === "string" && (value === "true" || value === "false")) {
|
|
583
|
+
return constant(value === "true") as ConstantExpression<T>;
|
|
592
584
|
} else {
|
|
593
|
-
|
|
594
|
-
case "boolean":
|
|
595
|
-
if (typeof value === "string" && (value === "true" || value === "false")) {
|
|
596
|
-
return constant(value === "true") as ConstantExpression<T>;
|
|
597
|
-
}
|
|
598
|
-
return constant(value) as ConstantExpression<T>;
|
|
599
|
-
default:
|
|
600
|
-
return constant(value) as ConstantExpression<T>;
|
|
601
|
-
}
|
|
585
|
+
return constant(value) as ConstantExpression<T>;
|
|
602
586
|
}
|
|
603
587
|
}
|
|
604
588
|
|
|
@@ -607,11 +591,11 @@ export function resolveBindingString<T extends PrimitiveType>(
|
|
|
607
591
|
*
|
|
608
592
|
* @see fn
|
|
609
593
|
*
|
|
610
|
-
* @param
|
|
594
|
+
* @param reference Reference
|
|
611
595
|
* @returns {ReferenceExpression} The object reference binding part
|
|
612
596
|
*/
|
|
613
|
-
export function ref(
|
|
614
|
-
return { _type: "Ref", ref };
|
|
597
|
+
export function ref(reference: string | null): ReferenceExpression {
|
|
598
|
+
return { _type: "Ref", ref: reference };
|
|
615
599
|
}
|
|
616
600
|
|
|
617
601
|
/**
|
|
@@ -653,6 +637,14 @@ export function isConstant<T extends PrimitiveType>(maybeConstant: ExpressionOrP
|
|
|
653
637
|
return typeof maybeConstant !== "object" || (maybeConstant as BaseExpression<T>)._type === "Constant";
|
|
654
638
|
}
|
|
655
639
|
|
|
640
|
+
function isTrue(expression: Expression<PrimitiveType>) {
|
|
641
|
+
return isConstant(expression) && expression.value === true;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function isFalse(expression: Expression<PrimitiveType>) {
|
|
645
|
+
return isConstant(expression) && expression.value === false;
|
|
646
|
+
}
|
|
647
|
+
|
|
656
648
|
/**
|
|
657
649
|
* Checks if the expression or value provided is binding or not.
|
|
658
650
|
*
|
|
@@ -700,97 +692,97 @@ function isPrimitiveObject(objectType: object): boolean {
|
|
|
700
692
|
}
|
|
701
693
|
}
|
|
702
694
|
/**
|
|
703
|
-
* Check if the passed annotation
|
|
695
|
+
* Check if the passed annotation annotationValue is a ComplexAnnotationExpression.
|
|
704
696
|
*
|
|
705
697
|
* @template T The target type
|
|
706
|
-
* @param
|
|
698
|
+
* @param annotationValue The annotation annotationValue to evaluate
|
|
707
699
|
* @returns {boolean} `true` if the object is a {ComplexAnnotationExpression}
|
|
708
700
|
*/
|
|
709
|
-
function isComplexAnnotationExpression<T>(
|
|
710
|
-
|
|
711
|
-
): annotationExpression is ComplexAnnotationExpression<T> {
|
|
712
|
-
return typeof annotationExpression === "object" && !isPrimitiveObject(annotationExpression as object);
|
|
701
|
+
function isComplexAnnotationExpression<T>(annotationValue: PropertyAnnotationValue<T>): annotationValue is ComplexAnnotationExpression<T> {
|
|
702
|
+
return typeof annotationValue === "object" && !isPrimitiveObject(annotationValue as object);
|
|
713
703
|
}
|
|
714
704
|
|
|
715
705
|
/**
|
|
716
|
-
* Generate the corresponding
|
|
706
|
+
* Generate the corresponding annotationValue for a given annotation annotationValue.
|
|
717
707
|
*
|
|
718
708
|
* @template T The target type
|
|
719
|
-
* @param
|
|
709
|
+
* @param annotationValue The source annotation annotationValue
|
|
720
710
|
* @param visitedNavigationPaths The path from the root entity set
|
|
721
|
-
* @param defaultValue Default value if the
|
|
711
|
+
* @param defaultValue Default value if the annotationValue is undefined
|
|
722
712
|
* @param pathVisitor A function to modify the resulting path
|
|
723
|
-
* @returns {Expression<T>} The
|
|
713
|
+
* @returns {Expression<T>} The annotationValue equivalent to that annotation annotationValue
|
|
724
714
|
*/
|
|
725
715
|
export function annotationExpression<T extends PrimitiveType>(
|
|
726
|
-
|
|
716
|
+
annotationValue: PropertyAnnotationValue<T>,
|
|
727
717
|
visitedNavigationPaths: string[] = [],
|
|
728
718
|
defaultValue?: ExpressionOrPrimitive<T>,
|
|
729
719
|
pathVisitor?: Function
|
|
730
720
|
): Expression<T> {
|
|
731
|
-
if (
|
|
721
|
+
if (annotationValue === undefined) {
|
|
732
722
|
return wrapPrimitive(defaultValue as T);
|
|
733
723
|
}
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
724
|
+
|
|
725
|
+
if (!isComplexAnnotationExpression(annotationValue)) {
|
|
726
|
+
return constant(annotationValue);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
switch (annotationValue.type) {
|
|
730
|
+
case "Path":
|
|
731
|
+
return bindingExpression(annotationValue.path, undefined, visitedNavigationPaths, pathVisitor);
|
|
732
|
+
case "If":
|
|
733
|
+
return annotationIfExpression(annotationValue.If, visitedNavigationPaths, pathVisitor);
|
|
734
|
+
case "Not":
|
|
735
|
+
return not(parseAnnotationCondition(annotationValue.Not, visitedNavigationPaths, pathVisitor)) as Expression<T>;
|
|
736
|
+
case "Eq":
|
|
737
|
+
return equal(
|
|
738
|
+
parseAnnotationCondition(annotationValue.Eq[0], visitedNavigationPaths, pathVisitor),
|
|
739
|
+
parseAnnotationCondition(annotationValue.Eq[1], visitedNavigationPaths, pathVisitor)
|
|
740
|
+
) as Expression<T>;
|
|
741
|
+
case "Ne":
|
|
742
|
+
return notEqual(
|
|
743
|
+
parseAnnotationCondition(annotationValue.Ne[0], visitedNavigationPaths, pathVisitor),
|
|
744
|
+
parseAnnotationCondition(annotationValue.Ne[1], visitedNavigationPaths, pathVisitor)
|
|
745
|
+
) as Expression<T>;
|
|
746
|
+
case "Gt":
|
|
747
|
+
return greaterThan(
|
|
748
|
+
parseAnnotationCondition(annotationValue.Gt[0], visitedNavigationPaths, pathVisitor),
|
|
749
|
+
parseAnnotationCondition(annotationValue.Gt[1], visitedNavigationPaths, pathVisitor)
|
|
750
|
+
) as Expression<T>;
|
|
751
|
+
case "Ge":
|
|
752
|
+
return greaterOrEqual(
|
|
753
|
+
parseAnnotationCondition(annotationValue.Ge[0], visitedNavigationPaths, pathVisitor),
|
|
754
|
+
parseAnnotationCondition(annotationValue.Ge[1], visitedNavigationPaths, pathVisitor)
|
|
755
|
+
) as Expression<T>;
|
|
756
|
+
case "Lt":
|
|
757
|
+
return lessThan(
|
|
758
|
+
parseAnnotationCondition(annotationValue.Lt[0], visitedNavigationPaths, pathVisitor),
|
|
759
|
+
parseAnnotationCondition(annotationValue.Lt[1], visitedNavigationPaths, pathVisitor)
|
|
760
|
+
) as Expression<T>;
|
|
761
|
+
case "Le":
|
|
762
|
+
return lessOrEqual(
|
|
763
|
+
parseAnnotationCondition(annotationValue.Le[0], visitedNavigationPaths, pathVisitor),
|
|
764
|
+
parseAnnotationCondition(annotationValue.Le[1], visitedNavigationPaths, pathVisitor)
|
|
765
|
+
) as Expression<T>;
|
|
766
|
+
case "Or":
|
|
767
|
+
return or(
|
|
768
|
+
...(annotationValue.Or.map(function(orCondition) {
|
|
769
|
+
return parseAnnotationCondition(orCondition, visitedNavigationPaths, pathVisitor);
|
|
770
|
+
}) as Expression<boolean>[])
|
|
771
|
+
) as Expression<T>;
|
|
772
|
+
case "And":
|
|
773
|
+
return and(
|
|
774
|
+
...(annotationValue.And.map(function(andCondition) {
|
|
775
|
+
return parseAnnotationCondition(andCondition, visitedNavigationPaths, pathVisitor);
|
|
776
|
+
}) as Expression<boolean>[])
|
|
777
|
+
) as Expression<T>;
|
|
778
|
+
case "Apply":
|
|
779
|
+
return annotationApplyExpression(
|
|
780
|
+
annotationValue as ApplyAnnotationExpression<string>,
|
|
781
|
+
visitedNavigationPaths,
|
|
782
|
+
pathVisitor
|
|
783
|
+
) as Expression<T>;
|
|
793
784
|
}
|
|
785
|
+
return unresolveableExpression;
|
|
794
786
|
}
|
|
795
787
|
|
|
796
788
|
/**
|
|
@@ -880,41 +872,40 @@ function parseAnnotationCondition<T extends PrimitiveType>(
|
|
|
880
872
|
);
|
|
881
873
|
} else if (annotationValue.hasOwnProperty("$EnumMember")) {
|
|
882
874
|
return constant(resolveEnumValue((annotationValue as any).$EnumMember) as T);
|
|
883
|
-
} else {
|
|
884
|
-
return constant(false as T);
|
|
885
875
|
}
|
|
876
|
+
return constant(false as T);
|
|
886
877
|
}
|
|
887
878
|
|
|
888
879
|
/**
|
|
889
880
|
* Process the {IfAnnotationExpressionValue} into an expression.
|
|
890
881
|
*
|
|
891
882
|
* @template T The target type
|
|
892
|
-
* @param
|
|
883
|
+
* @param annotationValue An If expression returning the type T
|
|
893
884
|
* @param visitedNavigationPaths The path from the root entity set
|
|
894
885
|
* @param pathVisitor A function to modify the resulting path
|
|
895
886
|
* @returns {Expression<T>} The equivalent ifElse expression
|
|
896
887
|
*/
|
|
897
888
|
export function annotationIfExpression<T extends PrimitiveType>(
|
|
898
|
-
|
|
889
|
+
annotationValue: IfAnnotationExpressionValue<T>,
|
|
899
890
|
visitedNavigationPaths: string[] = [],
|
|
900
891
|
pathVisitor?: Function
|
|
901
892
|
): Expression<T> {
|
|
902
893
|
return ifElse(
|
|
903
|
-
parseAnnotationCondition(
|
|
904
|
-
parseAnnotationCondition(
|
|
905
|
-
parseAnnotationCondition(
|
|
894
|
+
parseAnnotationCondition(annotationValue[0], visitedNavigationPaths, pathVisitor),
|
|
895
|
+
parseAnnotationCondition(annotationValue[1] as any, visitedNavigationPaths, pathVisitor),
|
|
896
|
+
parseAnnotationCondition(annotationValue[2] as any, visitedNavigationPaths, pathVisitor)
|
|
906
897
|
);
|
|
907
898
|
}
|
|
908
899
|
|
|
909
900
|
export function annotationApplyExpression(
|
|
910
|
-
|
|
901
|
+
applyExpression: ApplyAnnotationExpression<string>,
|
|
911
902
|
visitedNavigationPaths: string[] = [],
|
|
912
903
|
pathVisitor?: Function
|
|
913
904
|
): Expression<string> {
|
|
914
|
-
switch (
|
|
905
|
+
switch (applyExpression.Function) {
|
|
915
906
|
case "odata.concat":
|
|
916
907
|
return concat(
|
|
917
|
-
...
|
|
908
|
+
...applyExpression.Apply.map((applyParam: any) => {
|
|
918
909
|
let applyParamConverted = applyParam;
|
|
919
910
|
if (applyParam.hasOwnProperty("$Path")) {
|
|
920
911
|
applyParamConverted = {
|
|
@@ -936,8 +927,8 @@ export function annotationApplyExpression(
|
|
|
936
927
|
return annotationExpression(applyParamConverted, visitedNavigationPaths, undefined, pathVisitor);
|
|
937
928
|
})
|
|
938
929
|
);
|
|
939
|
-
break;
|
|
940
930
|
}
|
|
931
|
+
return unresolveableExpression;
|
|
941
932
|
}
|
|
942
933
|
|
|
943
934
|
/**
|
|
@@ -960,10 +951,6 @@ function comparison<T extends PrimitiveType>(
|
|
|
960
951
|
return unresolveableExpression;
|
|
961
952
|
}
|
|
962
953
|
if (isConstant(leftExpression) && isConstant(rightExpression)) {
|
|
963
|
-
if (leftExpression.value === undefined || rightExpression.value === undefined) {
|
|
964
|
-
return constant(leftExpression.value === rightExpression.value);
|
|
965
|
-
}
|
|
966
|
-
|
|
967
954
|
switch (operator) {
|
|
968
955
|
case "!==":
|
|
969
956
|
return constant(leftExpression.value !== rightExpression.value);
|
|
@@ -976,7 +963,6 @@ function comparison<T extends PrimitiveType>(
|
|
|
976
963
|
case ">=":
|
|
977
964
|
return constant(leftExpression.value >= rightExpression.value);
|
|
978
965
|
case "===":
|
|
979
|
-
default:
|
|
980
966
|
return constant(leftExpression.value === rightExpression.value);
|
|
981
967
|
}
|
|
982
968
|
} else {
|
|
@@ -989,6 +975,16 @@ function comparison<T extends PrimitiveType>(
|
|
|
989
975
|
}
|
|
990
976
|
}
|
|
991
977
|
|
|
978
|
+
export function length(expression: BindingExpressionExpression<any> | UnresolveableBindingExpression): Expression<number> {
|
|
979
|
+
if (expression._type === "Unresolveable") {
|
|
980
|
+
return expression;
|
|
981
|
+
}
|
|
982
|
+
return {
|
|
983
|
+
_type: "Length",
|
|
984
|
+
bindingExpression: expression
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
|
|
992
988
|
/**
|
|
993
989
|
* Comparison: "equal" (===).
|
|
994
990
|
*
|
|
@@ -1010,32 +1006,35 @@ export function equal<T extends PrimitiveType>(
|
|
|
1010
1006
|
return constant(true);
|
|
1011
1007
|
}
|
|
1012
1008
|
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1009
|
+
function reduce(left: Expression<T>, right: Expression<T>) {
|
|
1010
|
+
if (left._type === "Comparison" && isTrue(right)) {
|
|
1011
|
+
// compare(a, b) === true ~~> compare(a, b)
|
|
1012
|
+
return left;
|
|
1013
|
+
} else if (left._type === "Comparison" && isFalse(right)) {
|
|
1014
|
+
// compare(a, b) === false ~~> !compare(a, b)
|
|
1015
|
+
return not(left);
|
|
1016
|
+
} else if (left._type === "IfElse" && _checkExpressionsAreEqual(left.onTrue, right)) {
|
|
1017
|
+
// (if (x) { a } else { b }) === a ~~> x || (b === a)
|
|
1018
|
+
return or(left.condition, equal(left.onFalse, right));
|
|
1019
|
+
} else if (left._type === "IfElse" && _checkExpressionsAreEqual(left.onFalse, right)) {
|
|
1020
|
+
// (if (x) { a } else { b }) === b ~~> !x || (a === b)
|
|
1021
|
+
return or(not(left.condition), equal(left.onTrue, right));
|
|
1022
|
+
} else if (
|
|
1023
|
+
left._type === "IfElse" &&
|
|
1024
|
+
isConstant(left.onTrue) &&
|
|
1025
|
+
isConstant(left.onFalse) &&
|
|
1026
|
+
isConstant(right) &&
|
|
1027
|
+
!_checkExpressionsAreEqual(left.onTrue, right) &&
|
|
1028
|
+
!_checkExpressionsAreEqual(left.onFalse, right)
|
|
1029
|
+
) {
|
|
1030
|
+
return constant(false);
|
|
1031
|
+
}
|
|
1032
|
+
return undefined;
|
|
1036
1033
|
}
|
|
1037
1034
|
|
|
1038
|
-
|
|
1035
|
+
// exploit symmetry: a === b <~> b === a
|
|
1036
|
+
const reduced = reduce(leftExpression, rightExpression) ?? reduce(rightExpression, leftExpression);
|
|
1037
|
+
return reduced ?? comparison("===", leftExpression, rightExpression);
|
|
1039
1038
|
}
|
|
1040
1039
|
|
|
1041
1040
|
/**
|
|
@@ -1050,36 +1049,7 @@ export function notEqual<T extends PrimitiveType>(
|
|
|
1050
1049
|
leftOperand: ExpressionOrPrimitive<T>,
|
|
1051
1050
|
rightOperand: ExpressionOrPrimitive<T>
|
|
1052
1051
|
): Expression<boolean> {
|
|
1053
|
-
|
|
1054
|
-
const rightExpression = wrapPrimitive(rightOperand);
|
|
1055
|
-
|
|
1056
|
-
if (_checkExpressionsAreEqual(leftExpression, rightExpression)) {
|
|
1057
|
-
return constant(false);
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
// ((a === c) !== true) => !(a === c)
|
|
1061
|
-
if (leftExpression._type === "Comparison" && isConstant(rightExpression) && rightExpression.value === true) {
|
|
1062
|
-
return not(leftExpression);
|
|
1063
|
-
} else if (leftExpression._type === "Comparison" && isConstant(rightExpression) && rightExpression.value === true) {
|
|
1064
|
-
// ((a === c) !== false) => (a === c)
|
|
1065
|
-
return leftExpression;
|
|
1066
|
-
} else if (leftExpression._type === "IfElse" && _checkExpressionsAreEqual(leftExpression.onTrue, rightExpression)) {
|
|
1067
|
-
return and(not(leftExpression.condition), notEqual(leftExpression.onFalse, rightExpression));
|
|
1068
|
-
} else if (leftExpression._type === "IfElse" && _checkExpressionsAreEqual(leftExpression.onFalse, rightExpression)) {
|
|
1069
|
-
return and(leftExpression.condition, notEqual(leftExpression.onTrue, rightExpression));
|
|
1070
|
-
} else if (
|
|
1071
|
-
leftExpression._type === "IfElse" &&
|
|
1072
|
-
isConstant(leftExpression.onTrue) &&
|
|
1073
|
-
isConstant(rightExpression) &&
|
|
1074
|
-
isConstant(leftExpression.onFalse) &&
|
|
1075
|
-
!_checkExpressionsAreEqual(leftExpression.onTrue, rightExpression) &&
|
|
1076
|
-
!_checkExpressionsAreEqual(leftExpression.onFalse, rightExpression)
|
|
1077
|
-
) {
|
|
1078
|
-
// If the left expression is an if else where both onTrue and onFalse are not equals to the right expression -> simplify as true
|
|
1079
|
-
return constant(true);
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
return comparison("!==", leftExpression, rightExpression);
|
|
1052
|
+
return not(equal(leftOperand, rightOperand));
|
|
1083
1053
|
}
|
|
1084
1054
|
|
|
1085
1055
|
/**
|
|
@@ -1184,61 +1154,40 @@ export function ifElse<T extends PrimitiveType>(
|
|
|
1184
1154
|
onFalseExpression = onFalseExpression.onFalse;
|
|
1185
1155
|
}
|
|
1186
1156
|
|
|
1187
|
-
//
|
|
1188
|
-
|
|
1189
|
-
if (
|
|
1190
|
-
isConstant(conditionExpression.onFalse) &&
|
|
1191
|
-
!conditionExpression.onFalse.value &&
|
|
1192
|
-
isConstant(conditionExpression.onTrue) &&
|
|
1193
|
-
conditionExpression.onTrue.value
|
|
1194
|
-
) {
|
|
1195
|
-
// ifElse(ifElse(X, true, false), a, b) ==> ifElse(X, a, b)
|
|
1196
|
-
conditionExpression = conditionExpression.condition;
|
|
1197
|
-
} else if (
|
|
1198
|
-
isConstant(conditionExpression.onFalse) &&
|
|
1199
|
-
conditionExpression.onFalse.value &&
|
|
1200
|
-
isConstant(conditionExpression.onTrue) &&
|
|
1201
|
-
!conditionExpression.onTrue.value
|
|
1202
|
-
) {
|
|
1203
|
-
// ifElse(ifElse(X, false, true), a, b) ==> ifElse(not(X), a, b)
|
|
1204
|
-
conditionExpression = not(conditionExpression.condition);
|
|
1205
|
-
} else if (
|
|
1206
|
-
isConstant(conditionExpression.onTrue) &&
|
|
1207
|
-
!conditionExpression.onTrue.value &&
|
|
1208
|
-
!isConstant(conditionExpression.onFalse)
|
|
1209
|
-
) {
|
|
1210
|
-
// ifElse(ifElse(X, false, a), b, c) ==> ifElse(and(not(X), a), b, c)
|
|
1211
|
-
conditionExpression = and(not(conditionExpression.condition), conditionExpression.onFalse);
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
// again swap branches if needed (in case one of the optimizations above led to a negated condition)
|
|
1216
|
-
if (conditionExpression._type === "Not") {
|
|
1217
|
-
// ifElse(not(X), a, b) --> ifElse(X, b, a)
|
|
1218
|
-
[onTrueExpression, onFalseExpression] = [onFalseExpression, onTrueExpression];
|
|
1219
|
-
conditionExpression = not(conditionExpression);
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
// compute expression result for constant conditions
|
|
1157
|
+
// (if true then a else b) ~~> a
|
|
1158
|
+
// (if false then a else b) ~~> b
|
|
1223
1159
|
if (isConstant(conditionExpression)) {
|
|
1224
1160
|
return conditionExpression.value ? onTrueExpression : onFalseExpression;
|
|
1225
1161
|
}
|
|
1226
1162
|
|
|
1227
|
-
//
|
|
1163
|
+
// if (isConstantBoolean(onTrueExpression) || isConstantBoolean(onFalseExpression)) {
|
|
1164
|
+
// return or(and(condition, onTrueExpression as Expression<boolean>), and(not(condition), onFalseExpression as Expression<boolean>)) as Expression<T>
|
|
1165
|
+
// }
|
|
1166
|
+
// (if X then a else a) ~~> a
|
|
1228
1167
|
if (_checkExpressionsAreEqual(onTrueExpression, onFalseExpression)) {
|
|
1229
1168
|
return onTrueExpression;
|
|
1230
1169
|
}
|
|
1231
1170
|
|
|
1232
|
-
//
|
|
1233
|
-
|
|
1234
|
-
if (isConstant(onFalseExpression) && onFalseExpression.value === false) {
|
|
1171
|
+
// if X then a else false ~~> X && a
|
|
1172
|
+
if (isFalse(onFalseExpression)) {
|
|
1235
1173
|
return and(conditionExpression, onTrueExpression as Expression<boolean>) as Expression<T>;
|
|
1236
1174
|
}
|
|
1237
|
-
|
|
1238
|
-
if
|
|
1175
|
+
|
|
1176
|
+
// if X then a else true ~~> !X || a
|
|
1177
|
+
if (isTrue(onFalseExpression)) {
|
|
1178
|
+
return or(not(conditionExpression), onTrueExpression as Expression<boolean>) as Expression<T>;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
// if X then false else a ~~> !X && a
|
|
1182
|
+
if (isFalse(onTrueExpression)) {
|
|
1239
1183
|
return and(not(conditionExpression), onFalseExpression as Expression<boolean>) as Expression<T>;
|
|
1240
1184
|
}
|
|
1241
1185
|
|
|
1186
|
+
// if X then true else a ~~> X || a
|
|
1187
|
+
if (isTrue(onTrueExpression)) {
|
|
1188
|
+
return or(conditionExpression, onFalseExpression as Expression<boolean>) as Expression<T>;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1242
1191
|
return {
|
|
1243
1192
|
_type: "IfElse",
|
|
1244
1193
|
condition: conditionExpression,
|
|
@@ -1389,17 +1338,17 @@ export function addTypeInformation<T, U extends Fn<T>>(
|
|
|
1389
1338
|
/**
|
|
1390
1339
|
* Function call, optionally with arguments.
|
|
1391
1340
|
*
|
|
1392
|
-
* @param
|
|
1341
|
+
* @param func Function name or reference to function
|
|
1393
1342
|
* @param parameters Arguments
|
|
1394
1343
|
* @param on Object to call the function on
|
|
1395
1344
|
* @returns {FunctionExpression<T>} Expression representing the function call (not the result of the function call!)
|
|
1396
1345
|
*/
|
|
1397
1346
|
export function fn<T, U extends FunctionOrName<T>>(
|
|
1398
|
-
|
|
1347
|
+
func: U,
|
|
1399
1348
|
parameters: WrappedTuple<FunctionParameters<T, U>>,
|
|
1400
1349
|
on?: ExpressionOrPrimitive<object>
|
|
1401
1350
|
): FunctionExpression<T> {
|
|
1402
|
-
const functionName = typeof
|
|
1351
|
+
const functionName = typeof func === "string" ? func : (func as Fn<T>).__functionName;
|
|
1403
1352
|
return {
|
|
1404
1353
|
_type: "Function",
|
|
1405
1354
|
obj: on !== undefined ? wrapPrimitive(on) : undefined,
|
|
@@ -1445,31 +1394,26 @@ export function transformRecursively<T extends PrimitiveType | unknown>(
|
|
|
1445
1394
|
inExpression: Expression<T>,
|
|
1446
1395
|
expressionType: ExpressionType,
|
|
1447
1396
|
transformFunction: TransformFunction,
|
|
1448
|
-
includeAllExpression
|
|
1397
|
+
includeAllExpression = false
|
|
1449
1398
|
): Expression<T> {
|
|
1450
1399
|
let expression = inExpression;
|
|
1451
1400
|
switch (expression._type) {
|
|
1452
1401
|
case "Function":
|
|
1453
|
-
|
|
1454
|
-
|
|
1402
|
+
case "Formatter":
|
|
1403
|
+
expression.parameters = expression.parameters.map(parameter =>
|
|
1404
|
+
transformRecursively(parameter, expressionType, transformFunction, includeAllExpression)
|
|
1455
1405
|
);
|
|
1456
1406
|
break;
|
|
1457
1407
|
case "Concat":
|
|
1458
|
-
expression.expressions = expression.expressions.map(
|
|
1459
|
-
transformRecursively(
|
|
1408
|
+
expression.expressions = expression.expressions.map(subExpression =>
|
|
1409
|
+
transformRecursively(subExpression, expressionType, transformFunction, includeAllExpression)
|
|
1460
1410
|
);
|
|
1461
1411
|
break;
|
|
1462
1412
|
case "ComplexType":
|
|
1463
|
-
expression.bindingParameters = expression.bindingParameters.map(
|
|
1464
|
-
transformRecursively(
|
|
1413
|
+
expression.bindingParameters = expression.bindingParameters.map(bindingParameter =>
|
|
1414
|
+
transformRecursively(bindingParameter, expressionType, transformFunction, includeAllExpression)
|
|
1465
1415
|
);
|
|
1466
1416
|
break;
|
|
1467
|
-
case "Formatter":
|
|
1468
|
-
expression.parameters = expression.parameters.map(expression =>
|
|
1469
|
-
transformRecursively(expression, expressionType, transformFunction, includeAllExpression)
|
|
1470
|
-
);
|
|
1471
|
-
break;
|
|
1472
|
-
|
|
1473
1417
|
case "IfElse":
|
|
1474
1418
|
const onTrue = transformRecursively(expression.onTrue, expressionType, transformFunction, includeAllExpression);
|
|
1475
1419
|
const onFalse = transformRecursively(expression.onFalse, expressionType, transformFunction, includeAllExpression);
|
|
@@ -1489,8 +1433,8 @@ export function transformRecursively<T extends PrimitiveType | unknown>(
|
|
|
1489
1433
|
break;
|
|
1490
1434
|
case "Set":
|
|
1491
1435
|
if (includeAllExpression) {
|
|
1492
|
-
expression.operands = expression.operands.map(
|
|
1493
|
-
transformRecursively(
|
|
1436
|
+
expression.operands = expression.operands.map(operand =>
|
|
1437
|
+
transformRecursively(operand, expressionType, transformFunction, includeAllExpression)
|
|
1494
1438
|
);
|
|
1495
1439
|
}
|
|
1496
1440
|
break;
|
|
@@ -1503,6 +1447,7 @@ export function transformRecursively<T extends PrimitiveType | unknown>(
|
|
|
1503
1447
|
break;
|
|
1504
1448
|
case "DefaultBinding":
|
|
1505
1449
|
case "Ref":
|
|
1450
|
+
case "Length":
|
|
1506
1451
|
case "Binding":
|
|
1507
1452
|
case "Constant":
|
|
1508
1453
|
// Do nothing
|
|
@@ -1519,6 +1464,158 @@ export type BindingExpression<T> = T | string | undefined;
|
|
|
1519
1464
|
const needParenthesis = function<T extends PrimitiveType>(expr: ExpressionOrPrimitive<T>): boolean {
|
|
1520
1465
|
return !isConstant(expr) && !isBinding(expr) && isExpression(expr) && expr._type !== "IfElse" && expr._type !== "Function";
|
|
1521
1466
|
};
|
|
1467
|
+
|
|
1468
|
+
/**
|
|
1469
|
+
* Compiles a constant object to a string.
|
|
1470
|
+
* @param expr
|
|
1471
|
+
* @param isNullable
|
|
1472
|
+
* @returns {string} The compiled string
|
|
1473
|
+
*/
|
|
1474
|
+
function compileConstantObject<T>(expr: ConstantExpression<object>, isNullable = false) {
|
|
1475
|
+
if (isNullable && Object.keys(expr.value).length === 0) {
|
|
1476
|
+
return "";
|
|
1477
|
+
}
|
|
1478
|
+
// Objects
|
|
1479
|
+
const o = expr.value as PlainExpressionObject;
|
|
1480
|
+
const properties: string[] = [];
|
|
1481
|
+
Object.keys(o).forEach(key => {
|
|
1482
|
+
const value = o[key];
|
|
1483
|
+
const childResult = compileBinding(value, true, false, true);
|
|
1484
|
+
if (childResult && childResult.length > 0) {
|
|
1485
|
+
properties.push(`${key}: ${childResult}`);
|
|
1486
|
+
}
|
|
1487
|
+
});
|
|
1488
|
+
return `{${properties.join(", ")}}`;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
/**
|
|
1492
|
+
* Compiles a Constant Binding Expression.
|
|
1493
|
+
* @param expr
|
|
1494
|
+
* @param embeddedInBinding
|
|
1495
|
+
* @param isNullable
|
|
1496
|
+
* @returns {string} The compiled string
|
|
1497
|
+
*/
|
|
1498
|
+
function compileConstant<T extends PrimitiveType>(expr: ConstantExpression<T>, embeddedInBinding: boolean, isNullable = false) {
|
|
1499
|
+
if (expr.value === null) {
|
|
1500
|
+
return "null";
|
|
1501
|
+
}
|
|
1502
|
+
if (expr.value === undefined) {
|
|
1503
|
+
return "undefined";
|
|
1504
|
+
}
|
|
1505
|
+
if (typeof expr.value === "object") {
|
|
1506
|
+
if (Array.isArray(expr.value)) {
|
|
1507
|
+
const entries = expr.value.map(expression => compileBinding(expression, true));
|
|
1508
|
+
return `[${entries.join(", ")}]`;
|
|
1509
|
+
} else {
|
|
1510
|
+
return compileConstantObject(expr as ConstantExpression<object>, isNullable);
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
if (embeddedInBinding) {
|
|
1515
|
+
switch (typeof expr.value) {
|
|
1516
|
+
case "number":
|
|
1517
|
+
case "bigint":
|
|
1518
|
+
case "boolean":
|
|
1519
|
+
return expr.value.toString();
|
|
1520
|
+
case "string":
|
|
1521
|
+
return `'${escapeXmlAttribute(expr.value.toString())}'`;
|
|
1522
|
+
default:
|
|
1523
|
+
return "";
|
|
1524
|
+
}
|
|
1525
|
+
} else {
|
|
1526
|
+
return expr.value.toString();
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
/**
|
|
1531
|
+
* Generates the binding string for a Binding expression.
|
|
1532
|
+
*
|
|
1533
|
+
* @param expressionForBinding The expression to compile
|
|
1534
|
+
* @param embeddedInBinding Whether the expression to compile is embedded into another expression
|
|
1535
|
+
* @param embeddedSeparator The binding value evaluator ($ or % depending on whether we want to force the type or not)
|
|
1536
|
+
* @returns {BindingExpression<T>} The corresponding expression binding
|
|
1537
|
+
*/
|
|
1538
|
+
function compileBindingForBinding<T extends PrimitiveType>(
|
|
1539
|
+
expressionForBinding: BindingExpressionExpression<T> | DefaultBindingExpressionExpression<T>,
|
|
1540
|
+
embeddedInBinding: boolean,
|
|
1541
|
+
embeddedSeparator: string
|
|
1542
|
+
) {
|
|
1543
|
+
if (
|
|
1544
|
+
expressionForBinding.type ||
|
|
1545
|
+
expressionForBinding.parameters ||
|
|
1546
|
+
expressionForBinding.targetType ||
|
|
1547
|
+
expressionForBinding.formatOptions ||
|
|
1548
|
+
expressionForBinding.constraints
|
|
1549
|
+
) {
|
|
1550
|
+
// This is now a complex binding definition, let's prepare for it
|
|
1551
|
+
const complexBindingDefinition = {
|
|
1552
|
+
path: compileBindingPath(expressionForBinding),
|
|
1553
|
+
type: expressionForBinding.type,
|
|
1554
|
+
targetType: expressionForBinding.targetType,
|
|
1555
|
+
parameters: expressionForBinding.parameters,
|
|
1556
|
+
formatOptions: expressionForBinding.formatOptions,
|
|
1557
|
+
constraints: expressionForBinding.constraints
|
|
1558
|
+
};
|
|
1559
|
+
let outBinding = compileBinding(complexBindingDefinition);
|
|
1560
|
+
if (embeddedInBinding) {
|
|
1561
|
+
outBinding = `${embeddedSeparator}` + outBinding;
|
|
1562
|
+
}
|
|
1563
|
+
return outBinding;
|
|
1564
|
+
} else if (embeddedInBinding) {
|
|
1565
|
+
return `${embeddedSeparator}{${compileBindingPath(expressionForBinding)}}`;
|
|
1566
|
+
} else {
|
|
1567
|
+
return `{${compileBindingPath(expressionForBinding)}}`;
|
|
1568
|
+
}
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
function compileComplexTypeExpression<T extends PrimitiveType>(expression: ComplexTypeExpression<T>) {
|
|
1572
|
+
if (expression.bindingParameters.length === 1) {
|
|
1573
|
+
return `{${compilePathParameter(expression.bindingParameters[0], true)}, type: '${expression.type}'}`;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
let outputEnd;
|
|
1577
|
+
// this code is based on sap.ui.model.odata.v4._AnnotationHelperExpression.fetchCurrencyOrUnit
|
|
1578
|
+
switch (expression.type) {
|
|
1579
|
+
case "sap.ui.model.odata.type.Unit":
|
|
1580
|
+
outputEnd = `,{mode:'OneTime',path:'/##@@requestUnitsOfMeasure',targetType:'any'}],type:'sap.ui.model.odata.type.Unit'`;
|
|
1581
|
+
break;
|
|
1582
|
+
case "sap.ui.model.odata.type.Currency":
|
|
1583
|
+
outputEnd = `,{mode:'OneTime',path:'/##@@requestCurrencyCodes',targetType:'any'}],type:'sap.ui.model.odata.type.Currency'`;
|
|
1584
|
+
break;
|
|
1585
|
+
default:
|
|
1586
|
+
outputEnd = `], type: '${expression.type}'`;
|
|
1587
|
+
}
|
|
1588
|
+
if (hasElements(expression.formatOptions)) {
|
|
1589
|
+
outputEnd += `, formatOptions: ${compileBinding(expression.formatOptions)}`;
|
|
1590
|
+
}
|
|
1591
|
+
if (hasElements(expression.parameters)) {
|
|
1592
|
+
outputEnd += `, parameters: ${compileBinding(expression.parameters)}`;
|
|
1593
|
+
}
|
|
1594
|
+
outputEnd += "}";
|
|
1595
|
+
|
|
1596
|
+
return `{mode:'TwoWay', parts:[${expression.bindingParameters.map((param: any) => compilePathParameter(param)).join(",")}${outputEnd}`;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
/**
|
|
1600
|
+
* Wrap the compiled binding string as required dependening on its context.
|
|
1601
|
+
*
|
|
1602
|
+
* @param expression The compiled expression
|
|
1603
|
+
* @param embeddedInBinding True if the compiled expression is to be embedded in a binding
|
|
1604
|
+
* @param parenthesisRequired True if the embedded binding needs to be wrapped in parethesis so that it is evaluated as one
|
|
1605
|
+
* @returns {BindingExpression<string>} Finalized compiled expression
|
|
1606
|
+
*/
|
|
1607
|
+
function wrapBindingExpression(expression: string, embeddedInBinding: boolean, parenthesisRequired = false): BindingExpression<string> {
|
|
1608
|
+
if (embeddedInBinding) {
|
|
1609
|
+
if (parenthesisRequired) {
|
|
1610
|
+
return `(${expression})`;
|
|
1611
|
+
} else {
|
|
1612
|
+
return expression;
|
|
1613
|
+
}
|
|
1614
|
+
} else {
|
|
1615
|
+
return `{= ${expression}}`;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1522
1619
|
/**
|
|
1523
1620
|
* Compile an expression into an expression binding.
|
|
1524
1621
|
*
|
|
@@ -1526,55 +1623,24 @@ const needParenthesis = function<T extends PrimitiveType>(expr: ExpressionOrPrim
|
|
|
1526
1623
|
* @param expression The expression to compile
|
|
1527
1624
|
* @param embeddedInBinding Whether the expression to compile is embedded into another expression
|
|
1528
1625
|
* @param keepTargetType Keep the target type of the embedded bindings instead of casting them to any
|
|
1626
|
+
* @param isNullable Whether binding expression can resolve to empty string or not
|
|
1529
1627
|
* @returns {BindingExpression<T>} The corresponding expression binding
|
|
1530
1628
|
*/
|
|
1531
1629
|
export function compileBinding<T extends PrimitiveType>(
|
|
1532
1630
|
expression: ExpressionOrPrimitive<T>,
|
|
1533
|
-
embeddedInBinding
|
|
1534
|
-
keepTargetType
|
|
1631
|
+
embeddedInBinding = false,
|
|
1632
|
+
keepTargetType = false,
|
|
1633
|
+
isNullable = false
|
|
1535
1634
|
): BindingExpression<string> {
|
|
1536
1635
|
const expr = wrapPrimitive(expression);
|
|
1537
1636
|
const embeddedSeparator = keepTargetType ? "$" : "%";
|
|
1538
|
-
|
|
1637
|
+
|
|
1539
1638
|
switch (expr._type) {
|
|
1540
1639
|
case "Unresolveable":
|
|
1541
1640
|
return undefined;
|
|
1542
|
-
case "Constant":
|
|
1543
|
-
if (expr.value === null) {
|
|
1544
|
-
return "null";
|
|
1545
|
-
}
|
|
1546
|
-
if (expr.value === undefined) {
|
|
1547
|
-
return "undefined";
|
|
1548
|
-
}
|
|
1549
|
-
if (typeof expr.value === "object") {
|
|
1550
|
-
if (Array.isArray(expr.value)) {
|
|
1551
|
-
const entries = expr.value.map(expression => compileBinding(expression, true));
|
|
1552
|
-
return `[${entries.join(", ")}]`;
|
|
1553
|
-
} else {
|
|
1554
|
-
// Objects
|
|
1555
|
-
const o = expr.value as PlainExpressionObject;
|
|
1556
|
-
const properties = Object.keys(o).map(key => {
|
|
1557
|
-
const value = o[key];
|
|
1558
|
-
return `${key}: ${compileBinding(value, true)}`;
|
|
1559
|
-
});
|
|
1560
|
-
return `{${properties.join(", ")}}`;
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
1641
|
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
case "number":
|
|
1567
|
-
case "bigint":
|
|
1568
|
-
case "boolean":
|
|
1569
|
-
return expr.value.toString();
|
|
1570
|
-
case "string":
|
|
1571
|
-
return `'${escapeXmlAttribute(expr.value.toString())}'`;
|
|
1572
|
-
default:
|
|
1573
|
-
return "";
|
|
1574
|
-
}
|
|
1575
|
-
} else {
|
|
1576
|
-
return expr.value.toString();
|
|
1577
|
-
}
|
|
1642
|
+
case "Constant":
|
|
1643
|
+
return compileConstant(expr, embeddedInBinding, isNullable);
|
|
1578
1644
|
|
|
1579
1645
|
case "Ref":
|
|
1580
1646
|
return expr.ref || "null";
|
|
@@ -1584,164 +1650,91 @@ export function compileBinding<T extends PrimitiveType>(
|
|
|
1584
1650
|
return expr.obj === undefined
|
|
1585
1651
|
? `${expr.fn}(${argumentString})`
|
|
1586
1652
|
: `${compileBinding(expr.obj, true)}.${expr.fn}(${argumentString})`;
|
|
1653
|
+
|
|
1587
1654
|
case "EmbeddedExpressionBinding":
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
} else {
|
|
1591
|
-
return `${expr.value}`;
|
|
1592
|
-
}
|
|
1655
|
+
return embeddedInBinding ? `(${expr.value.substr(2, expr.value.length - 3)})` : `${expr.value}`;
|
|
1656
|
+
|
|
1593
1657
|
case "EmbeddedBinding":
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
} else {
|
|
1597
|
-
return `${expr.value}`;
|
|
1598
|
-
}
|
|
1658
|
+
return embeddedInBinding ? `${embeddedSeparator}${expr.value}` : `${expr.value}`;
|
|
1659
|
+
|
|
1599
1660
|
case "DefaultBinding":
|
|
1600
1661
|
case "Binding":
|
|
1601
|
-
|
|
1602
|
-
let outBinding = "";
|
|
1603
|
-
if (embeddedInBinding) {
|
|
1604
|
-
outBinding += `${embeddedSeparator}`;
|
|
1605
|
-
}
|
|
1606
|
-
outBinding += `{path:'${expr.modelName ? `${expr.modelName}>` : ""}${expr.path}'`;
|
|
1607
|
-
if (expr.type) {
|
|
1608
|
-
outBinding += `, type: '${expr.type}'`;
|
|
1609
|
-
}
|
|
1610
|
-
if (expr.constraints && Object.keys(expr.constraints).length > 0) {
|
|
1611
|
-
outBinding += `, constraints: ${compileBinding(expr.constraints)}`;
|
|
1612
|
-
}
|
|
1613
|
-
if (expr.formatOptions) {
|
|
1614
|
-
outBinding += `, formatOptions: ${compileBinding(expr.formatOptions)}`;
|
|
1615
|
-
}
|
|
1616
|
-
if (expr.parameters && Object.keys(expr.parameters).length > 0) {
|
|
1617
|
-
outBinding += `, parameters: ${compileBinding(expr.parameters)}`;
|
|
1618
|
-
}
|
|
1619
|
-
if (expr.targetType) {
|
|
1620
|
-
outBinding += `, targetType: '${expr.targetType}'`;
|
|
1621
|
-
}
|
|
1622
|
-
outBinding += "}";
|
|
1623
|
-
return outBinding;
|
|
1624
|
-
} else {
|
|
1625
|
-
if (embeddedInBinding) {
|
|
1626
|
-
return `${embeddedSeparator}{${expr.modelName ? `${expr.modelName}>` : ""}${expr.path}}`;
|
|
1627
|
-
} else {
|
|
1628
|
-
return `{${expr.modelName ? `${expr.modelName}>` : ""}${expr.path}}`;
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1662
|
+
return compileBindingForBinding(expr, embeddedInBinding, embeddedSeparator);
|
|
1631
1663
|
|
|
1632
1664
|
case "Comparison":
|
|
1633
|
-
const
|
|
1634
|
-
|
|
1635
|
-
let comparisonPart = "";
|
|
1636
|
-
if (isOperand1Complex) {
|
|
1637
|
-
comparisonPart += "(";
|
|
1638
|
-
}
|
|
1639
|
-
comparisonPart += `${compileBinding(expr.operand1, true)}`;
|
|
1640
|
-
if (isOperand1Complex) {
|
|
1641
|
-
comparisonPart += ")";
|
|
1642
|
-
}
|
|
1643
|
-
comparisonPart += ` ${expr.operator} `;
|
|
1644
|
-
if (isOperand2Complex) {
|
|
1645
|
-
comparisonPart += "(";
|
|
1646
|
-
}
|
|
1647
|
-
comparisonPart += `${compileBinding(expr.operand2, true)}`;
|
|
1648
|
-
if (isOperand2Complex) {
|
|
1649
|
-
comparisonPart += ")";
|
|
1650
|
-
}
|
|
1651
|
-
if (embeddedInBinding) {
|
|
1652
|
-
return comparisonPart;
|
|
1653
|
-
}
|
|
1654
|
-
return `{= ${comparisonPart}}`;
|
|
1665
|
+
const comparisonExpression = compileComparisonExpression(expr);
|
|
1666
|
+
return wrapBindingExpression(comparisonExpression, embeddedInBinding);
|
|
1655
1667
|
|
|
1656
1668
|
case "IfElse":
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
} else {
|
|
1663
|
-
return `{= ${compileBinding(expr.condition, true)} ? ${compileBinding(expr.onTrue, true)} : ${compileBinding(
|
|
1664
|
-
expr.onFalse,
|
|
1665
|
-
true
|
|
1666
|
-
)}}`;
|
|
1667
|
-
}
|
|
1669
|
+
const ifElseExpression = `${compileBinding(expr.condition, true)} ? ${compileBinding(expr.onTrue, true)} : ${compileBinding(
|
|
1670
|
+
expr.onFalse,
|
|
1671
|
+
true
|
|
1672
|
+
)}`;
|
|
1673
|
+
return wrapBindingExpression(ifElseExpression, embeddedInBinding, true);
|
|
1668
1674
|
|
|
1669
1675
|
case "Set":
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
} else {
|
|
1673
|
-
return `{= (${expr.operands.map(expression => compileBinding(expression, true)).join(` ${expr.operator} `)})}`;
|
|
1674
|
-
}
|
|
1676
|
+
const setExpression = expr.operands.map(operand => compileBinding(operand, true)).join(` ${expr.operator} `);
|
|
1677
|
+
return wrapBindingExpression(setExpression, embeddedInBinding, true);
|
|
1675
1678
|
|
|
1676
1679
|
case "Concat":
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
}
|
|
1680
|
+
const concatExpression = expr.expressions.map(nestedExpression => compileBinding(nestedExpression, true, true)).join(" + ");
|
|
1681
|
+
return wrapBindingExpression(concatExpression, embeddedInBinding);
|
|
1682
|
+
|
|
1683
|
+
case "Length":
|
|
1684
|
+
const lengthExpression = `${compileBinding(expr.bindingExpression, true)}.length`;
|
|
1685
|
+
return wrapBindingExpression(lengthExpression, embeddedInBinding);
|
|
1682
1686
|
|
|
1683
1687
|
case "Not":
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
} else {
|
|
1687
|
-
return `{= !${compileBinding(expr.operand, true)}}`;
|
|
1688
|
-
}
|
|
1688
|
+
const notExpression = `!${compileBinding(expr.operand, true)}`;
|
|
1689
|
+
return wrapBindingExpression(notExpression, embeddedInBinding);
|
|
1689
1690
|
|
|
1690
1691
|
case "Truthy":
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
} else {
|
|
1694
|
-
return `{= !!${compileBinding(expr.operand, true)}}`;
|
|
1695
|
-
}
|
|
1692
|
+
const truthyExpression = `!!${compileBinding(expr.operand, true)}`;
|
|
1693
|
+
return wrapBindingExpression(truthyExpression, embeddedInBinding);
|
|
1696
1694
|
|
|
1697
1695
|
case "Formatter":
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
outProperty += `{parts:[${expr.parameters.map((param: any) => compilePathParameter(param)).join(",")}], formatter: '${
|
|
1702
|
-
expr.fn
|
|
1703
|
-
}'}`;
|
|
1704
|
-
}
|
|
1705
|
-
if (embeddedInBinding) {
|
|
1706
|
-
outProperty = `\$${outProperty}`;
|
|
1707
|
-
}
|
|
1708
|
-
return outProperty;
|
|
1696
|
+
const formatterExpression = compileFormatterExpression(expr);
|
|
1697
|
+
return embeddedInBinding ? `\$${formatterExpression}` : formatterExpression;
|
|
1698
|
+
|
|
1709
1699
|
case "ComplexType":
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
let outputEnd;
|
|
1714
|
-
// this code is based on sap.ui.model.odata.v4._AnnotationHelperExpression.fetchCurrencyOrUnit
|
|
1715
|
-
switch (expr.type) {
|
|
1716
|
-
case "sap.ui.model.odata.type.Unit":
|
|
1717
|
-
outputEnd = `,{mode:'OneTime',path:'/##@@requestUnitsOfMeasure',targetType:'any'}],type:'sap.ui.model.odata.type.Unit'`;
|
|
1718
|
-
break;
|
|
1719
|
-
case "sap.ui.model.odata.type.Currency":
|
|
1720
|
-
outputEnd = `,{mode:'OneTime',path:'/##@@requestCurrencyCodes',targetType:'any'}],type:'sap.ui.model.odata.type.Currency'`;
|
|
1721
|
-
break;
|
|
1722
|
-
default:
|
|
1723
|
-
outputEnd = `], type: '${expr.type}'`;
|
|
1724
|
-
}
|
|
1725
|
-
if (expr.formatOptions && Object.keys(expr.formatOptions).length > 0) {
|
|
1726
|
-
outputEnd += `, formatOptions: ${compileBinding(expr.formatOptions)}`;
|
|
1727
|
-
}
|
|
1728
|
-
if (expr.parameters && Object.keys(expr.parameters).length > 0) {
|
|
1729
|
-
outputEnd += `, parameters: ${compileBinding(expr.parameters)}`;
|
|
1730
|
-
}
|
|
1731
|
-
outputEnd += "}";
|
|
1732
|
-
outProperty += `{mode:'TwoWay', parts:[${expr.bindingParameters
|
|
1733
|
-
.map((param: any) => compilePathParameter(param))
|
|
1734
|
-
.join(",")}${outputEnd}`;
|
|
1735
|
-
}
|
|
1736
|
-
if (embeddedInBinding) {
|
|
1737
|
-
outProperty = `\$${outProperty}`;
|
|
1738
|
-
}
|
|
1739
|
-
return outProperty;
|
|
1700
|
+
const complexTypeExpression = compileComplexTypeExpression(expr);
|
|
1701
|
+
return embeddedInBinding ? `\$${complexTypeExpression}` : complexTypeExpression;
|
|
1702
|
+
|
|
1740
1703
|
default:
|
|
1741
1704
|
return "";
|
|
1742
1705
|
}
|
|
1743
1706
|
}
|
|
1744
1707
|
|
|
1708
|
+
/**
|
|
1709
|
+
* Compile a comparison expression.
|
|
1710
|
+
*
|
|
1711
|
+
* @param expression The comparison expression.
|
|
1712
|
+
* @returns The compiled expression. Needs wrapping before it can be used as an expression binding.
|
|
1713
|
+
*/
|
|
1714
|
+
function compileComparisonExpression(expression: ComparisonExpression) {
|
|
1715
|
+
function compileOperand(operand: Expression<any>) {
|
|
1716
|
+
const compiledOperand = compileBinding(operand, true) ?? "undefined";
|
|
1717
|
+
return wrapBindingExpression(compiledOperand, true, needParenthesis(operand));
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
return `${compileOperand(expression.operand1)} ${expression.operator} ${compileOperand(expression.operand2)}`;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
/**
|
|
1724
|
+
* Compile a formatter expression.
|
|
1725
|
+
*
|
|
1726
|
+
* @param expression The formatter expression.
|
|
1727
|
+
* @returns The compiled expression.
|
|
1728
|
+
*/
|
|
1729
|
+
function compileFormatterExpression<T extends PrimitiveType>(expression: FormatterExpression<T>) {
|
|
1730
|
+
if (expression.parameters.length === 1) {
|
|
1731
|
+
return `{${compilePathParameter(expression.parameters[0], true)}, formatter: '${expression.fn}'}`;
|
|
1732
|
+
} else {
|
|
1733
|
+
const parts = expression.parameters.map(param => compilePathParameter(param));
|
|
1734
|
+
return `{parts: [${parts.join(", ")}], formatter: '${expression.fn}'}`;
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1745
1738
|
/**
|
|
1746
1739
|
* Compile the path parameter of a formatter call.
|
|
1747
1740
|
*
|
|
@@ -1749,53 +1742,54 @@ export function compileBinding<T extends PrimitiveType>(
|
|
|
1749
1742
|
* @param singlePath Whether there is one or multiple path to consider
|
|
1750
1743
|
* @returns {string} The string snippet to include in the overall binding definition
|
|
1751
1744
|
*/
|
|
1752
|
-
function compilePathParameter(expression: Expression<any>, singlePath
|
|
1745
|
+
function compilePathParameter(expression: Expression<any>, singlePath = false): string {
|
|
1753
1746
|
let outValue = "";
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
return outValue;
|
|
1773
|
-
}
|
|
1774
|
-
return `{${outValue}}`;
|
|
1747
|
+
if (expression._type === "Constant") {
|
|
1748
|
+
switch (typeof expression.value) {
|
|
1749
|
+
case "number":
|
|
1750
|
+
case "bigint":
|
|
1751
|
+
outValue = `value: ${expression.value.toString()}`;
|
|
1752
|
+
break;
|
|
1753
|
+
case "string":
|
|
1754
|
+
outValue = `value: '${escapeXmlAttribute(expression.value.toString())}'`;
|
|
1755
|
+
break;
|
|
1756
|
+
case "boolean":
|
|
1757
|
+
outValue = `value: '${expression.value.toString()}'`;
|
|
1758
|
+
break;
|
|
1759
|
+
default:
|
|
1760
|
+
outValue = "value: ''";
|
|
1761
|
+
break;
|
|
1762
|
+
}
|
|
1763
|
+
} else if (expression._type === "DefaultBinding" || expression._type === "Binding") {
|
|
1764
|
+
outValue = `path: '${compileBindingPath(expression)}'`;
|
|
1775
1765
|
|
|
1776
|
-
|
|
1777
|
-
case "Binding":
|
|
1778
|
-
outValue = `path:'${expression.modelName ? `${expression.modelName}>` : ""}${expression.path}'`;
|
|
1766
|
+
outValue += expression.type ? `, type: '${expression.type}'` : `, targetType: 'any'`;
|
|
1779
1767
|
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
}
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
if (expression.parameters && Object.keys(expression.parameters).length > 0) {
|
|
1792
|
-
outValue += `, parameters: ${compileBinding(expression.parameters)}`;
|
|
1793
|
-
}
|
|
1794
|
-
if (singlePath) {
|
|
1795
|
-
return outValue;
|
|
1796
|
-
}
|
|
1797
|
-
return `{${outValue}}`;
|
|
1798
|
-
default:
|
|
1799
|
-
return "";
|
|
1768
|
+
if (hasElements(expression.constraints)) {
|
|
1769
|
+
outValue += `, constraints: ${compileBinding(expression.constraints)}`;
|
|
1770
|
+
}
|
|
1771
|
+
if (hasElements(expression.formatOptions)) {
|
|
1772
|
+
outValue += `, formatOptions: ${compileBinding(expression.formatOptions)}`;
|
|
1773
|
+
}
|
|
1774
|
+
if (hasElements(expression.parameters)) {
|
|
1775
|
+
outValue += `, parameters: ${compileBinding(expression.parameters)}`;
|
|
1776
|
+
}
|
|
1777
|
+
} else {
|
|
1778
|
+
return "";
|
|
1800
1779
|
}
|
|
1780
|
+
return singlePath ? outValue : `{${outValue}}`;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
function hasElements(obj: any) {
|
|
1784
|
+
return obj && Object.keys(obj).length > 0;
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1787
|
+
/**
|
|
1788
|
+
* Compile a binding expression path.
|
|
1789
|
+
*
|
|
1790
|
+
* @param expression The expression to compile.
|
|
1791
|
+
* @returns The compiled path.
|
|
1792
|
+
*/
|
|
1793
|
+
function compileBindingPath<T extends PrimitiveType>(expression: BindingExpressionExpression<T> | DefaultBindingExpressionExpression<T>) {
|
|
1794
|
+
return `${expression.modelName ? expression.modelName + ">" : ""}${expression.path}`;
|
|
1801
1795
|
}
|