@sap-ux/fiori-annotation-api 0.1.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.
Files changed (211) hide show
  1. package/LICENSE +201 -0
  2. package/Readme.md +35 -0
  3. package/dist/avt/annotations.d.ts +72 -0
  4. package/dist/avt/annotations.d.ts.map +1 -0
  5. package/dist/avt/annotations.js +508 -0
  6. package/dist/avt/annotations.js.map +1 -0
  7. package/dist/avt/expressions.d.ts +13 -0
  8. package/dist/avt/expressions.d.ts.map +1 -0
  9. package/dist/avt/expressions.js +34 -0
  10. package/dist/avt/expressions.js.map +1 -0
  11. package/dist/avt/find.d.ts +39 -0
  12. package/dist/avt/find.d.ts.map +1 -0
  13. package/dist/avt/find.js +130 -0
  14. package/dist/avt/find.js.map +1 -0
  15. package/dist/avt/index.d.ts +9 -0
  16. package/dist/avt/index.d.ts.map +1 -0
  17. package/dist/avt/index.js +32 -0
  18. package/dist/avt/index.js.map +1 -0
  19. package/dist/avt/metadata.d.ts +10 -0
  20. package/dist/avt/metadata.d.ts.map +1 -0
  21. package/dist/avt/metadata.js +346 -0
  22. package/dist/avt/metadata.js.map +1 -0
  23. package/dist/avt/pointer.d.ts +12 -0
  24. package/dist/avt/pointer.d.ts.map +1 -0
  25. package/dist/avt/pointer.js +188 -0
  26. package/dist/avt/pointer.js.map +1 -0
  27. package/dist/avt/to-internal.d.ts +81 -0
  28. package/dist/avt/to-internal.d.ts.map +1 -0
  29. package/dist/avt/to-internal.js +340 -0
  30. package/dist/avt/to-internal.js.map +1 -0
  31. package/dist/avt/types.d.ts +3 -0
  32. package/dist/avt/types.d.ts.map +1 -0
  33. package/dist/avt/types.js +3 -0
  34. package/dist/avt/types.js.map +1 -0
  35. package/dist/avt/utils.d.ts +61 -0
  36. package/dist/avt/utils.d.ts.map +1 -0
  37. package/dist/avt/utils.js +87 -0
  38. package/dist/avt/utils.js.map +1 -0
  39. package/dist/cds/adapter.d.ts +112 -0
  40. package/dist/cds/adapter.d.ts.map +1 -0
  41. package/dist/cds/adapter.js +703 -0
  42. package/dist/cds/adapter.js.map +1 -0
  43. package/dist/cds/cds-compiler-tokens.d.ts +30 -0
  44. package/dist/cds/cds-compiler-tokens.d.ts.map +1 -0
  45. package/dist/cds/cds-compiler-tokens.js +57 -0
  46. package/dist/cds/cds-compiler-tokens.js.map +1 -0
  47. package/dist/cds/change.d.ts +347 -0
  48. package/dist/cds/change.d.ts.map +1 -0
  49. package/dist/cds/change.js +232 -0
  50. package/dist/cds/change.js.map +1 -0
  51. package/dist/cds/comments.d.ts +15 -0
  52. package/dist/cds/comments.d.ts.map +1 -0
  53. package/dist/cds/comments.js +56 -0
  54. package/dist/cds/comments.js.map +1 -0
  55. package/dist/cds/deletion.d.ts +59 -0
  56. package/dist/cds/deletion.d.ts.map +1 -0
  57. package/dist/cds/deletion.js +821 -0
  58. package/dist/cds/deletion.js.map +1 -0
  59. package/dist/cds/document.d.ts +52 -0
  60. package/dist/cds/document.d.ts.map +1 -0
  61. package/dist/cds/document.js +98 -0
  62. package/dist/cds/document.js.map +1 -0
  63. package/dist/cds/indent.d.ts +20 -0
  64. package/dist/cds/indent.d.ts.map +1 -0
  65. package/dist/cds/indent.js +86 -0
  66. package/dist/cds/indent.js.map +1 -0
  67. package/dist/cds/index.d.ts +3 -0
  68. package/dist/cds/index.d.ts.map +1 -0
  69. package/dist/cds/index.js +21 -0
  70. package/dist/cds/index.js.map +1 -0
  71. package/dist/cds/pointer.d.ts +23 -0
  72. package/dist/cds/pointer.d.ts.map +1 -0
  73. package/dist/cds/pointer.js +438 -0
  74. package/dist/cds/pointer.js.map +1 -0
  75. package/dist/cds/preprocessor.d.ts +12 -0
  76. package/dist/cds/preprocessor.d.ts.map +1 -0
  77. package/dist/cds/preprocessor.js +338 -0
  78. package/dist/cds/preprocessor.js.map +1 -0
  79. package/dist/cds/references.d.ts +35 -0
  80. package/dist/cds/references.d.ts.map +1 -0
  81. package/dist/cds/references.js +413 -0
  82. package/dist/cds/references.js.map +1 -0
  83. package/dist/cds/service.d.ts +11 -0
  84. package/dist/cds/service.d.ts.map +1 -0
  85. package/dist/cds/service.js +37 -0
  86. package/dist/cds/service.js.map +1 -0
  87. package/dist/cds/utils.d.ts +35 -0
  88. package/dist/cds/utils.d.ts.map +1 -0
  89. package/dist/cds/utils.js +75 -0
  90. package/dist/cds/utils.js.map +1 -0
  91. package/dist/cds/writer.d.ts +104 -0
  92. package/dist/cds/writer.d.ts.map +1 -0
  93. package/dist/cds/writer.js +1086 -0
  94. package/dist/cds/writer.js.map +1 -0
  95. package/dist/change-converter.d.ts +54 -0
  96. package/dist/change-converter.d.ts.map +1 -0
  97. package/dist/change-converter.js +639 -0
  98. package/dist/change-converter.js.map +1 -0
  99. package/dist/error.d.ts +35 -0
  100. package/dist/error.d.ts.map +1 -0
  101. package/dist/error.js +64 -0
  102. package/dist/error.js.map +1 -0
  103. package/dist/fiori-service.d.ts +130 -0
  104. package/dist/fiori-service.d.ts.map +1 -0
  105. package/dist/fiori-service.js +362 -0
  106. package/dist/fiori-service.js.map +1 -0
  107. package/dist/index.d.ts +5 -0
  108. package/dist/index.d.ts.map +1 -0
  109. package/dist/index.js +25 -0
  110. package/dist/index.js.map +1 -0
  111. package/dist/protected.d.ts +3 -0
  112. package/dist/protected.d.ts.map +1 -0
  113. package/dist/protected.js +11 -0
  114. package/dist/protected.js.map +1 -0
  115. package/dist/types/adapter.d.ts +46 -0
  116. package/dist/types/adapter.d.ts.map +1 -0
  117. package/dist/types/adapter.js +3 -0
  118. package/dist/types/adapter.js.map +1 -0
  119. package/dist/types/change.d.ts +187 -0
  120. package/dist/types/change.d.ts.map +1 -0
  121. package/dist/types/change.js +52 -0
  122. package/dist/types/change.js.map +1 -0
  123. package/dist/types/index.d.ts +7 -0
  124. package/dist/types/index.d.ts.map +1 -0
  125. package/dist/types/index.js +33 -0
  126. package/dist/types/index.js.map +1 -0
  127. package/dist/types/internal-change.d.ts +98 -0
  128. package/dist/types/internal-change.d.ts.map +1 -0
  129. package/dist/types/internal-change.js +18 -0
  130. package/dist/types/internal-change.js.map +1 -0
  131. package/dist/types/project-info.d.ts +6 -0
  132. package/dist/types/project-info.d.ts.map +1 -0
  133. package/dist/types/project-info.js +3 -0
  134. package/dist/types/project-info.js.map +1 -0
  135. package/dist/types/service.d.ts +27 -0
  136. package/dist/types/service.d.ts.map +1 -0
  137. package/dist/types/service.js +3 -0
  138. package/dist/types/service.js.map +1 -0
  139. package/dist/types/text-file.d.ts +12 -0
  140. package/dist/types/text-file.d.ts.map +1 -0
  141. package/dist/types/text-file.js +3 -0
  142. package/dist/types/text-file.js.map +1 -0
  143. package/dist/utils/constants.d.ts +2 -0
  144. package/dist/utils/constants.d.ts.map +1 -0
  145. package/dist/utils/constants.js +24 -0
  146. package/dist/utils/constants.js.map +1 -0
  147. package/dist/utils/indent.d.ts +10 -0
  148. package/dist/utils/indent.d.ts.map +1 -0
  149. package/dist/utils/indent.js +36 -0
  150. package/dist/utils/indent.js.map +1 -0
  151. package/dist/utils/index.d.ts +7 -0
  152. package/dist/utils/index.d.ts.map +1 -0
  153. package/dist/utils/index.js +16 -0
  154. package/dist/utils/index.js.map +1 -0
  155. package/dist/utils/path.d.ts +8 -0
  156. package/dist/utils/path.d.ts.map +1 -0
  157. package/dist/utils/path.js +31 -0
  158. package/dist/utils/path.js.map +1 -0
  159. package/dist/utils/pointer.d.ts +11 -0
  160. package/dist/utils/pointer.d.ts.map +1 -0
  161. package/dist/utils/pointer.js +26 -0
  162. package/dist/utils/pointer.js.map +1 -0
  163. package/dist/utils/reference.d.ts +10 -0
  164. package/dist/utils/reference.d.ts.map +1 -0
  165. package/dist/utils/reference.js +20 -0
  166. package/dist/utils/reference.js.map +1 -0
  167. package/dist/utils/text-edits.d.ts +12 -0
  168. package/dist/utils/text-edits.d.ts.map +1 -0
  169. package/dist/utils/text-edits.js +29 -0
  170. package/dist/utils/text-edits.js.map +1 -0
  171. package/dist/vocabularies.d.ts +11 -0
  172. package/dist/vocabularies.d.ts.map +1 -0
  173. package/dist/vocabularies.js +26 -0
  174. package/dist/vocabularies.js.map +1 -0
  175. package/dist/xml/adapter.d.ts +85 -0
  176. package/dist/xml/adapter.d.ts.map +1 -0
  177. package/dist/xml/adapter.js +579 -0
  178. package/dist/xml/adapter.js.map +1 -0
  179. package/dist/xml/changes.d.ts +117 -0
  180. package/dist/xml/changes.d.ts.map +1 -0
  181. package/dist/xml/changes.js +34 -0
  182. package/dist/xml/changes.js.map +1 -0
  183. package/dist/xml/comments.d.ts +17 -0
  184. package/dist/xml/comments.d.ts.map +1 -0
  185. package/dist/xml/comments.js +49 -0
  186. package/dist/xml/comments.js.map +1 -0
  187. package/dist/xml/document.d.ts +11 -0
  188. package/dist/xml/document.d.ts.map +1 -0
  189. package/dist/xml/document.js +3 -0
  190. package/dist/xml/document.js.map +1 -0
  191. package/dist/xml/index.d.ts +3 -0
  192. package/dist/xml/index.d.ts.map +1 -0
  193. package/dist/xml/index.js +8 -0
  194. package/dist/xml/index.js.map +1 -0
  195. package/dist/xml/pointer.d.ts +10 -0
  196. package/dist/xml/pointer.d.ts.map +1 -0
  197. package/dist/xml/pointer.js +29 -0
  198. package/dist/xml/pointer.js.map +1 -0
  199. package/dist/xml/references.d.ts +9 -0
  200. package/dist/xml/references.d.ts.map +1 -0
  201. package/dist/xml/references.js +87 -0
  202. package/dist/xml/references.js.map +1 -0
  203. package/dist/xml/service.d.ts +12 -0
  204. package/dist/xml/service.d.ts.map +1 -0
  205. package/dist/xml/service.js +55 -0
  206. package/dist/xml/service.js.map +1 -0
  207. package/dist/xml/writer.d.ts +39 -0
  208. package/dist/xml/writer.d.ts.map +1 -0
  209. package/dist/xml/writer.js +855 -0
  210. package/dist/xml/writer.js.map +1 -0
  211. package/package.json +47 -0
@@ -0,0 +1,639 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChangeConverter = void 0;
4
+ const odata_annotation_core_types_1 = require("@sap-ux/odata-annotation-core-types");
5
+ const odata_annotation_core_1 = require("@sap-ux/odata-annotation-core");
6
+ const avt_1 = require("./avt");
7
+ const vocabularies_1 = require("./vocabularies");
8
+ const types_1 = require("./types");
9
+ const utils_1 = require("./utils");
10
+ const error_1 = require("./error");
11
+ /**
12
+ * Converts changes to the internal change format.
13
+ */
14
+ class ChangeConverter {
15
+ /**
16
+ *
17
+ * @param serviceName Name of the service.
18
+ * @param vocabularyAPI Vocabulary API instance.
19
+ * @param metadataService Metadata service.
20
+ * @param splitAnnotationSupport Flag indicating if partial annotation definitions are supported.
21
+ */
22
+ constructor(serviceName, vocabularyAPI, metadataService, splitAnnotationSupport) {
23
+ this.serviceName = serviceName;
24
+ this.vocabularyAPI = vocabularyAPI;
25
+ this.metadataService = metadataService;
26
+ this.splitAnnotationSupport = splitAnnotationSupport;
27
+ this.aliasInfoCache = {};
28
+ this.newTargetChanges = new Map();
29
+ this.annotationFileChanges = [];
30
+ }
31
+ /**
32
+ * Converts changes to the internal change format.
33
+ *
34
+ * @param compiledService Service in internal format.
35
+ * @param fileMergeMaps Maps containing references of merged split annotations.
36
+ * @param schemaProvider Function which returns current service RawMetadata.
37
+ * @param changes AVT changes to be converted.
38
+ * @returns Annotation file changes.
39
+ */
40
+ convert(compiledService, fileMergeMaps, schemaProvider, changes) {
41
+ this.reset();
42
+ const mergedChanges = mergeChanges(changes);
43
+ for (const change of mergedChanges) {
44
+ const file = compiledService.annotationFiles.find((file) => file.uri === change.uri);
45
+ if (!file) {
46
+ throw new Error(`Invalid change. File ${change.uri} does not exist.`);
47
+ }
48
+ const aliasInfoMod = this.getAliasInformation(file);
49
+ if (change.kind === types_1.ChangeType.InsertAnnotation) {
50
+ this.insertAnnotation(compiledService, aliasInfoMod, change);
51
+ }
52
+ else if (change.kind === types_1.ChangeType.InsertEmbeddedAnnotation) {
53
+ this.insertEmbeddedAnnotation(file, fileMergeMaps, aliasInfoMod, change);
54
+ }
55
+ else if (change.kind === types_1.ChangeType.Insert) {
56
+ this.convertInsert(file, fileMergeMaps, aliasInfoMod, change);
57
+ }
58
+ else if (change.kind === types_1.ChangeType.Delete) {
59
+ this.convertDelete(file, fileMergeMaps, aliasInfoMod, change);
60
+ }
61
+ else if (change.kind === types_1.ChangeType.Update) {
62
+ this.convertUpdate(file, fileMergeMaps, aliasInfoMod, schemaProvider, change);
63
+ }
64
+ else if (change.kind === types_1.ChangeType.Move) {
65
+ this.convertMove(file, fileMergeMaps, aliasInfoMod, change);
66
+ }
67
+ }
68
+ this.addTargetChanges(compiledService);
69
+ return this.annotationFileChanges;
70
+ }
71
+ insertAnnotation(compiledService, aliasInfo, change) {
72
+ const annotationFile = compiledService.annotationFiles.find((file) => file.uri === change.uri);
73
+ const targetName = (0, odata_annotation_core_1.toAliasQualifiedName)(change.content.target, aliasInfo);
74
+ const targetIndex = annotationFile === null || annotationFile === void 0 ? void 0 : annotationFile.targets.findIndex((target) => (0, odata_annotation_core_1.toAliasQualifiedName)(target.name, aliasInfo) === targetName);
75
+ if (targetIndex === -1) {
76
+ // no existing target found, we need to create one
77
+ const changesForUri = this.newTargetChanges.get(change.uri);
78
+ if (!changesForUri) {
79
+ this.newTargetChanges.set(change.uri, new Map([[targetName, [change]]]));
80
+ }
81
+ else {
82
+ const changesForTarget = changesForUri.get(targetName);
83
+ if (changesForTarget) {
84
+ changesForTarget.push(change);
85
+ }
86
+ else {
87
+ changesForUri.set(targetName, [change]);
88
+ }
89
+ }
90
+ }
91
+ else {
92
+ // add annotation to existing target
93
+ const internal = {
94
+ type: types_1.INSERT_ELEMENT,
95
+ uri: change.uri,
96
+ target: targetName,
97
+ pointer: `/targets/${targetIndex}`,
98
+ element: (0, avt_1.convertAnnotationToInternal)(change.content.value, aliasInfo)
99
+ };
100
+ this.annotationFileChanges.push(internal);
101
+ }
102
+ }
103
+ insertEmbeddedAnnotation(file, fileMergeMaps, aliasInfo, change) {
104
+ const { reference, content } = change;
105
+ const { targetPointer, internalPointer } = (0, avt_1.findAnnotationByReference)(aliasInfo, file, fileMergeMaps[change.uri], reference, change.pointer, this.splitAnnotationSupport);
106
+ const internal = {
107
+ type: types_1.INSERT_ELEMENT,
108
+ uri: change.uri,
109
+ target: change.reference.target,
110
+ element: (0, avt_1.convertAnnotationToInternal)(content.value, aliasInfo),
111
+ pointer: targetPointer + internalPointer
112
+ };
113
+ this.annotationFileChanges.push(internal);
114
+ }
115
+ convertInsert(file, fileMergeMaps, aliasInfoMod, change) {
116
+ const { reference, content } = change;
117
+ const { element, targetPointer: pointer, internalPointer } = (0, avt_1.findAnnotationByReference)(aliasInfoMod, file, fileMergeMaps[change.uri], reference, change.pointer, this.splitAnnotationSupport);
118
+ if (content.type === 'record') {
119
+ const internal = {
120
+ type: types_1.INSERT_ELEMENT,
121
+ uri: change.uri,
122
+ target: change.reference.target,
123
+ pointer: pointer + internalPointer,
124
+ element: (0, avt_1.convertRecordToInternal)(aliasInfoMod, content.value),
125
+ index: change.kind === types_1.ChangeType.Insert ? change.index : undefined
126
+ };
127
+ this.annotationFileChanges.push(internal);
128
+ }
129
+ else if (content.type === 'property-value') {
130
+ const internal = {
131
+ type: types_1.INSERT_ELEMENT,
132
+ uri: change.uri,
133
+ target: change.reference.target,
134
+ pointer: pointer + internalPointer,
135
+ element: (0, avt_1.convertPropertyValueToInternal)(aliasInfoMod, content.value),
136
+ index: change.kind === types_1.ChangeType.Insert ? change.index : undefined
137
+ };
138
+ this.annotationFileChanges.push(internal);
139
+ }
140
+ else if (content.type === 'collection') {
141
+ const internal = {
142
+ type: types_1.INSERT_ELEMENT,
143
+ uri: change.uri,
144
+ target: change.reference.target,
145
+ pointer: pointer + internalPointer,
146
+ element: (0, avt_1.convertCollectionToInternal)(aliasInfoMod, content.value),
147
+ index: change.kind === types_1.ChangeType.Insert ? change.index : undefined
148
+ };
149
+ this.annotationFileChanges.push(internal);
150
+ }
151
+ else if (content.type === 'expression') {
152
+ this.convertInsertExpression(file, aliasInfoMod, pointer + internalPointer, change, content);
153
+ }
154
+ else if (content.type === 'primitive') {
155
+ this.convertInsertPrimitive(element, aliasInfoMod, pointer, internalPointer, change, content);
156
+ }
157
+ }
158
+ convertInsertExpression(file, aliasInfoMod, pointer, change, content) {
159
+ const node = (0, utils_1.getGenericNodeFromPointer)(file, pointer);
160
+ if ((node === null || node === void 0 ? void 0 : node.type) === odata_annotation_core_types_1.ELEMENT_TYPE && node.name === "Collection" /* Edm.Collection */) {
161
+ const expression = (0, avt_1.convertExpressionToInternal)(aliasInfoMod, content.value);
162
+ if (expression) {
163
+ const internal = {
164
+ type: types_1.INSERT_ELEMENT,
165
+ uri: change.uri,
166
+ target: change.reference.target,
167
+ pointer: pointer,
168
+ element: expression
169
+ };
170
+ this.annotationFileChanges.push(internal);
171
+ }
172
+ }
173
+ else {
174
+ const container = (0, avt_1.convertExpressionToInternal)(aliasInfoMod, content.value, (0, odata_annotation_core_types_1.createElementNode)({ name: 'placeholder' }));
175
+ if (container) {
176
+ const expression = container.content[0];
177
+ if ((expression === null || expression === void 0 ? void 0 : expression.type) === odata_annotation_core_types_1.ELEMENT_TYPE) {
178
+ const internal = {
179
+ type: types_1.INSERT_ELEMENT,
180
+ uri: change.uri,
181
+ target: change.reference.target,
182
+ pointer: pointer,
183
+ element: expression
184
+ };
185
+ this.annotationFileChanges.push(internal);
186
+ return;
187
+ }
188
+ else if (Object.keys(container.attributes).length > 0) {
189
+ const attribute = container.attributes[Object.keys(container.attributes)[0]];
190
+ const internal = {
191
+ type: types_1.INSERT_ATTRIBUTE,
192
+ uri: change.uri,
193
+ pointer: pointer,
194
+ name: attribute.name,
195
+ value: attribute.value
196
+ };
197
+ this.annotationFileChanges.push(internal);
198
+ return;
199
+ }
200
+ }
201
+ }
202
+ }
203
+ convertInsertPrimitive(element, aliasInfoMod, pointer, internalPointer, change, content) {
204
+ if (content.expressionType === types_1.ExpressionType.Unknown) {
205
+ const attributePointer = (0, avt_1.convertPointerInAnnotationToInternal)(element,
206
+ // last segment is used to determine attribute name
207
+ change.pointer.split('/').slice(0, -1).join('/'));
208
+ const attributeName = getAttributeNameFromPointer(change.pointer);
209
+ if (attributeName) {
210
+ const value = (0, avt_1.convertPrimitiveValueToInternal)(attributeName, content.value, aliasInfoMod);
211
+ const internal = {
212
+ type: types_1.INSERT_ATTRIBUTE,
213
+ uri: change.uri,
214
+ pointer: pointer + attributePointer,
215
+ name: attributeName,
216
+ value: value
217
+ };
218
+ this.annotationFileChanges.push(internal);
219
+ }
220
+ }
221
+ else if (content.expressionType === types_1.ExpressionType.Null) {
222
+ const internal = {
223
+ type: types_1.INSERT_ELEMENT,
224
+ uri: change.uri,
225
+ target: change.reference.target,
226
+ pointer: pointer + internalPointer,
227
+ element: (0, odata_annotation_core_types_1.createElementNode)({ name: "Null" /* Edm.Null */ })
228
+ };
229
+ this.annotationFileChanges.push(internal);
230
+ }
231
+ else if (typeof content.expressionType === 'string') {
232
+ const internal = {
233
+ type: types_1.INSERT_ATTRIBUTE,
234
+ uri: change.uri,
235
+ pointer: pointer + internalPointer,
236
+ name: content.expressionType,
237
+ value: content.value.toString()
238
+ };
239
+ this.annotationFileChanges.push(internal);
240
+ }
241
+ }
242
+ convertDelete(file, fileMergeMaps, aliasInfo, change) {
243
+ const { reference } = change;
244
+ const { target, targetPointer: pointer, internalPointer } = (0, avt_1.findAnnotationByReference)(aliasInfo, file, fileMergeMaps[change.uri], reference, change.pointer, this.splitAnnotationSupport);
245
+ // look for attribute pointer suffix e.g attributes/Qualifier/value
246
+ const suffix = internalPointer.split('/').slice(-3);
247
+ if (suffix[0] === 'attributes' && suffix.length === 3) {
248
+ // its an attribute change
249
+ const [, , property] = suffix;
250
+ if (property === 'value') {
251
+ const internal = {
252
+ type: types_1.DELETE_ATTRIBUTE,
253
+ uri: change.uri,
254
+ pointer: pointer + internalPointer.split('/').slice(0, -1).join('/')
255
+ };
256
+ this.annotationFileChanges.push(internal);
257
+ }
258
+ }
259
+ else if (change.pointer === '') {
260
+ const internal = {
261
+ type: types_1.DELETE_ELEMENT,
262
+ target: target.name,
263
+ uri: change.uri,
264
+ pointer: pointer
265
+ };
266
+ this.annotationFileChanges.push(internal);
267
+ }
268
+ else if (internalPointer !== '') {
269
+ const internal = {
270
+ type: types_1.DELETE_ELEMENT,
271
+ uri: change.uri,
272
+ target: target.name,
273
+ pointer: pointer + internalPointer
274
+ };
275
+ this.annotationFileChanges.push(internal);
276
+ }
277
+ }
278
+ convertUpdate(file, fileMergeMaps, aliasInfo, schemaProvider, change) {
279
+ var _a;
280
+ const { reference, content } = change;
281
+ const valueType = this.getValueType(schemaProvider, change);
282
+ const { element, targetPointer: pointer, internalPointer } = (0, avt_1.findAnnotationByReference)(aliasInfo, file, fileMergeMaps[change.uri], reference, change.pointer, this.splitAnnotationSupport, valueType);
283
+ if (internalPointer === '') {
284
+ // value does not exist, treat this as insert
285
+ this.convertInsert(file, fileMergeMaps, aliasInfo, change);
286
+ return;
287
+ }
288
+ // look for attribute pointer suffix e.g attributes/Qualifier/value
289
+ const suffix = internalPointer.split('/').slice(-3);
290
+ if (suffix[0] === 'attributes' && suffix.length === 3) {
291
+ // its an attribute change
292
+ const [, attributeName, property] = suffix;
293
+ this.convertUpdateAttribute(aliasInfo, attributeName, property, pointer, internalPointer, change);
294
+ }
295
+ else if (content.type === 'expression' && content.value.type === 'Collection') {
296
+ const node = (0, utils_1.getGenericNodeFromPointer)(file, pointer + internalPointer);
297
+ const newElement = (0, avt_1.convertExpressionToInternal)(aliasInfo, content.value);
298
+ if ((node === null || node === void 0 ? void 0 : node.type) === odata_annotation_core_types_1.ELEMENT_TYPE && newElement) {
299
+ const internalChange = {
300
+ type: types_1.REPLACE_ELEMENT,
301
+ uri: change.uri,
302
+ pointer: pointer + internalPointer,
303
+ newElement
304
+ };
305
+ this.annotationFileChanges.push(internalChange);
306
+ }
307
+ }
308
+ else if (content.type === 'expression') {
309
+ this.convertUpdateExpression(file, aliasInfo, content, pointer + internalPointer, valueType);
310
+ }
311
+ else if (content.type === 'primitive' && content.value !== undefined) {
312
+ const internalPointerForPrimitiveValues = (0, avt_1.convertPointerInAnnotationToInternal)(element, change.pointer, content.expressionType);
313
+ const newValue = (0, avt_1.convertPrimitiveValueToInternal)((_a = content.expressionType) !== null && _a !== void 0 ? _a : '', content.value, aliasInfo);
314
+ const internal = {
315
+ type: types_1.REPLACE_TEXT,
316
+ uri: change.uri,
317
+ pointer: pointer + internalPointerForPrimitiveValues + '/text',
318
+ text: (0, odata_annotation_core_types_1.createTextNode)(newValue)
319
+ };
320
+ this.annotationFileChanges.push(internal);
321
+ }
322
+ else {
323
+ const element = convertChangeToElement(aliasInfo, file, change);
324
+ if (element) {
325
+ const internal = {
326
+ type: types_1.REPLACE_ELEMENT,
327
+ uri: change.uri,
328
+ pointer: pointer + internalPointer,
329
+ newElement: element
330
+ };
331
+ this.annotationFileChanges.push(internal);
332
+ }
333
+ }
334
+ }
335
+ convertUpdateAttribute(aliasInfo, attributeName, property, pointer, internalPointer, change) {
336
+ var _a;
337
+ const value = this.getAttributeValue(change.content);
338
+ if (property === 'value' && value !== undefined) {
339
+ const type = (_a = this.getPrimitiveValueType(change.content)) !== null && _a !== void 0 ? _a : attributeName;
340
+ const newValue = (0, avt_1.convertPrimitiveValueToInternal)(type, value, aliasInfo);
341
+ const internal = {
342
+ type: types_1.UPDATE_ATTRIBUTE_VALUE,
343
+ uri: change.uri,
344
+ pointer: pointer + internalPointer.split('/').slice(0, -1).join('/'),
345
+ newValue
346
+ };
347
+ this.annotationFileChanges.push(internal);
348
+ }
349
+ }
350
+ getPrimitiveValueType(content) {
351
+ if (content.type === 'primitive') {
352
+ if (content.expressionType === types_1.ExpressionType.Unknown) {
353
+ return undefined;
354
+ }
355
+ return content.expressionType;
356
+ }
357
+ if (content.type === 'expression') {
358
+ if (content.value.type === types_1.ExpressionType.Unknown) {
359
+ return undefined;
360
+ }
361
+ return content.value.type;
362
+ }
363
+ return undefined;
364
+ }
365
+ getAttributeValue(content) {
366
+ if (content.type === 'primitive') {
367
+ return content.value;
368
+ }
369
+ if (content.type === 'expression') {
370
+ return this.getExpressionValue(content);
371
+ }
372
+ return undefined;
373
+ }
374
+ getExpressionValue(content) {
375
+ return content.value[content.value.type]; // There is always a property with on the object as type name, Typescript does not infer this case as expected
376
+ }
377
+ convertUpdateExpression(file, aliasInfo, content, pointer, valueType) {
378
+ const rawPrimitiveValue = this.getExpressionValue(content);
379
+ const newValue = (0, avt_1.convertPrimitiveValueToInternal)(content.value.type, rawPrimitiveValue, aliasInfo);
380
+ const type = valueType !== null && valueType !== void 0 ? valueType : content.value.type;
381
+ const node = (0, utils_1.getGenericNodeFromPointer)(file, pointer);
382
+ if ((node === null || node === void 0 ? void 0 : node.type) === odata_annotation_core_types_1.ELEMENT_TYPE) {
383
+ const onlyChangeValue = content.previousType === undefined && content.value.type === valueType;
384
+ if (onlyChangeValue && node.attributes[type]) {
385
+ // attribute notation
386
+ const internalChange = {
387
+ type: types_1.UPDATE_ATTRIBUTE_VALUE,
388
+ uri: file.uri,
389
+ pointer: pointer + `/attributes/${type}`,
390
+ newValue
391
+ };
392
+ this.annotationFileChanges.push(internalChange);
393
+ }
394
+ else if (onlyChangeValue && node.name === valueType) {
395
+ // element notation
396
+ const internalChange = {
397
+ type: types_1.REPLACE_ELEMENT_CONTENT,
398
+ uri: file.uri,
399
+ pointer: pointer,
400
+ newValue: [(0, odata_annotation_core_types_1.createTextNode)(newValue)]
401
+ };
402
+ this.annotationFileChanges.push(internalChange);
403
+ }
404
+ else if (node.attributes[type]) {
405
+ // attribute notation
406
+ const internalChange = {
407
+ type: types_1.REPLACE_ATTRIBUTE,
408
+ uri: file.uri,
409
+ pointer: pointer + `/attributes/${type}`,
410
+ newAttributeName: content.value.type,
411
+ newAttributeValue: newValue
412
+ };
413
+ this.annotationFileChanges.push(internalChange);
414
+ }
415
+ else if (node.name === valueType) {
416
+ // element notation
417
+ const internalChange = {
418
+ type: types_1.REPLACE_ELEMENT,
419
+ uri: file.uri,
420
+ pointer: pointer,
421
+ newElement: (0, odata_annotation_core_types_1.createElementNode)({
422
+ name: content.value.type,
423
+ content: [(0, odata_annotation_core_types_1.createTextNode)(newValue)]
424
+ })
425
+ };
426
+ this.annotationFileChanges.push(internalChange);
427
+ }
428
+ }
429
+ else if ((node === null || node === void 0 ? void 0 : node.type) === odata_annotation_core_types_1.ATTRIBUTE_TYPE) {
430
+ if (content.previousType === undefined && content.value.type === valueType) {
431
+ // attribute notation
432
+ const internalChange = {
433
+ type: types_1.UPDATE_ATTRIBUTE_VALUE,
434
+ uri: file.uri,
435
+ pointer: pointer,
436
+ newValue
437
+ };
438
+ this.annotationFileChanges.push(internalChange);
439
+ }
440
+ else {
441
+ // attribute notation
442
+ const internalChange = {
443
+ type: types_1.REPLACE_ATTRIBUTE,
444
+ uri: file.uri,
445
+ pointer: pointer,
446
+ newAttributeName: content.value.type,
447
+ newAttributeValue: newValue
448
+ };
449
+ this.annotationFileChanges.push(internalChange);
450
+ }
451
+ }
452
+ }
453
+ convertMove(file, fileMergeMaps, aliasInfo, change) {
454
+ const { reference, index, moveReference } = change;
455
+ const { targetPointer: pointer, internalPointer } = (0, avt_1.findAnnotationByReference)(aliasInfo, file, fileMergeMaps[change.uri], reference, change.pointer, this.splitAnnotationSupport);
456
+ const internal = {
457
+ type: types_1.MOVE_ELEMENT,
458
+ uri: change.uri,
459
+ pointer: pointer + internalPointer,
460
+ index: index,
461
+ fromPointers: moveReference.reduce((acc, moveRef) => {
462
+ acc.push(...moveRef.fromPointer.map((fromPointer) => {
463
+ var _a;
464
+ const { targetPointer: fromTargetPointer, internalPointer: internalFromPointer } = (0, avt_1.findAnnotationByReference)(aliasInfo, file, fileMergeMaps[change.uri], (_a = moveRef.reference) !== null && _a !== void 0 ? _a : change.reference, fromPointer, this.splitAnnotationSupport);
465
+ return fromTargetPointer + internalFromPointer;
466
+ }));
467
+ return acc;
468
+ }, new Array())
469
+ };
470
+ this.annotationFileChanges.push(internal);
471
+ }
472
+ addTargetChanges(compiledService) {
473
+ const insertTargetChanges = [];
474
+ for (const [uri, changesForUri] of this.newTargetChanges) {
475
+ const file = compiledService.annotationFiles.find((file) => file.uri === uri);
476
+ if (!file) {
477
+ throw new Error(`Invalid change. File ${uri} does not exist.`);
478
+ }
479
+ const aliasInfoMod = this.getAliasInformation(file);
480
+ for (const [targetName, inserts] of changesForUri) {
481
+ const target = (0, odata_annotation_core_types_1.createTarget)(targetName);
482
+ target.terms = inserts.map((change) => (0, avt_1.convertAnnotationToInternal)(change.content.value, aliasInfoMod));
483
+ const internal = {
484
+ type: types_1.INSERT_TARGET,
485
+ uri: uri,
486
+ target
487
+ };
488
+ insertTargetChanges.push(internal);
489
+ }
490
+ }
491
+ this.annotationFileChanges.unshift(...insertTargetChanges);
492
+ }
493
+ getValueType(schemaProvider, change) {
494
+ var _a;
495
+ const { reference, content, uri, pointer } = change;
496
+ if (content.type === 'expression') {
497
+ if (content.previousType) {
498
+ return content.previousType;
499
+ }
500
+ const annotationLists = (_a = schemaProvider().schema.annotations[uri]) !== null && _a !== void 0 ? _a : [];
501
+ const annotation = (0, avt_1.findAnnotation)(annotationLists, reference);
502
+ if (!annotation) {
503
+ const refString = (0, utils_1.annotationReferenceToString)(reference, uri);
504
+ throw new error_1.ApiError(`Could not find annotation '${refString}' in file '${uri}'.`, error_1.ApiErrorCode.General);
505
+ }
506
+ const node = (0, avt_1.getAvtNodeFromPointer)(annotation, pointer);
507
+ if (!node) {
508
+ const refString = (0, utils_1.annotationReferenceToString)(reference, uri);
509
+ throw new error_1.ApiError(`Could not resolve pointer '${pointer}' from annotation '${refString}'.`, error_1.ApiErrorCode.General);
510
+ }
511
+ if (this.isExpression(node)) {
512
+ return node.type;
513
+ }
514
+ }
515
+ return undefined;
516
+ }
517
+ isExpression(node) {
518
+ return typeof node.type !== 'undefined' && typeof node.propertyValues === 'undefined';
519
+ }
520
+ getAliasInformation(file) {
521
+ var _a;
522
+ const cachedValue = this.aliasInfoCache[file.uri];
523
+ if (cachedValue) {
524
+ return cachedValue;
525
+ }
526
+ const namespaces = (0, odata_annotation_core_1.getAllNamespacesAndReferences)((_a = file.namespace) !== null && _a !== void 0 ? _a : { name: this.serviceName, type: 'namespace' }, file.references);
527
+ const aliasInfo = (0, odata_annotation_core_1.getAliasInformation)(namespaces, this.metadataService.getNamespaces());
528
+ const aliasInfoWithAllVocabularies = (0, vocabularies_1.addAllVocabulariesToAliasInformation)(aliasInfo, this.vocabularyAPI.getVocabularies());
529
+ this.aliasInfoCache[file.uri] = aliasInfoWithAllVocabularies;
530
+ return aliasInfoWithAllVocabularies;
531
+ }
532
+ reset() {
533
+ this.aliasInfoCache = {};
534
+ this.newTargetChanges = new Map();
535
+ this.annotationFileChanges = [];
536
+ }
537
+ }
538
+ exports.ChangeConverter = ChangeConverter;
539
+ function mergeChanges(changes) {
540
+ const result = [];
541
+ const inserts = changes
542
+ .filter((change) => change.kind === types_1.ChangeType.InsertAnnotation)
543
+ .reduce((acc, change) => {
544
+ const reference = {
545
+ target: change.content.target,
546
+ term: change.content.value.term,
547
+ qualifier: change.content.value.qualifier
548
+ };
549
+ const key = (0, utils_1.annotationReferenceToString)(reference, change.uri);
550
+ acc.set(key, change);
551
+ return acc;
552
+ }, new Map());
553
+ for (const change of changes) {
554
+ if (change.kind === types_1.ChangeType.InsertAnnotation) {
555
+ // don't do anything with annotation inserts
556
+ result.push(change);
557
+ continue;
558
+ }
559
+ const key = (0, utils_1.annotationReferenceToString)(change.reference, change.uri);
560
+ const insert = inserts.get(key);
561
+ if (!insert) {
562
+ // reference should exist -> continue normally
563
+ result.push(change);
564
+ continue;
565
+ }
566
+ // new annotation should exist only in memory -> merge changes
567
+ mergeChange(insert, change);
568
+ }
569
+ return result;
570
+ }
571
+ function mergeChange(target, source) {
572
+ const reference = (0, utils_1.annotationReferenceToString)(source.reference, source.uri);
573
+ switch (source.kind) {
574
+ case types_1.ChangeType.InsertEmbeddedAnnotation: {
575
+ if (target.content.value.annotations) {
576
+ target.content.value.annotations.push(source.content.value);
577
+ }
578
+ else {
579
+ target.content.value.annotations = [source.content.value];
580
+ }
581
+ return;
582
+ }
583
+ case types_1.ChangeType.Insert: {
584
+ const node = (0, avt_1.getAvtNodeFromPointer)(target.content.value, source.pointer);
585
+ if (!node) {
586
+ throw new error_1.ApiError(`Change merge for '${reference}' failed! Could not resolve '${source.pointer}'.`, error_1.ApiErrorCode.General);
587
+ }
588
+ if (Array.isArray(node) && source.content.type === 'record') {
589
+ if (source.index === undefined || source.index >= node.length) {
590
+ node.push(source.content.value);
591
+ }
592
+ else {
593
+ node.splice(source.index, 0, source.content.value);
594
+ }
595
+ return;
596
+ }
597
+ throw new error_1.ApiError(`Change merge for '${reference}' failed! Change value type '${source.content.type}' is not supported.`, error_1.ApiErrorCode.General);
598
+ }
599
+ default:
600
+ break;
601
+ }
602
+ throw new error_1.ApiError(`Change merge for '${reference}' failed! Change type '${source.kind}' is not supported.`, error_1.ApiErrorCode.General);
603
+ }
604
+ function convertChangeToElement(aliasInfoMod, file, change) {
605
+ if (change.content.type === 'record') {
606
+ const { content } = change;
607
+ return (0, avt_1.convertRecordToInternal)(aliasInfoMod, content.value);
608
+ }
609
+ else if (change.content.type === 'property-value') {
610
+ const { content } = change;
611
+ return (0, avt_1.convertPropertyValueToInternal)(aliasInfoMod, content.value);
612
+ }
613
+ else if (change.content.type === 'collection') {
614
+ const { content } = change;
615
+ return (0, avt_1.convertCollectionToInternal)(aliasInfoMod, content.value);
616
+ }
617
+ else if (change.content.type === 'expression') {
618
+ const { content } = change;
619
+ return (0, avt_1.convertExpressionToInternal)(aliasInfoMod, content.value);
620
+ }
621
+ else if (change.content.type === 'primitive') {
622
+ const { content } = change;
623
+ if (content.expressionType === types_1.ExpressionType.Null) {
624
+ return (0, odata_annotation_core_types_1.createElementNode)({ name: "Null" /* Edm.Null */ });
625
+ }
626
+ }
627
+ return undefined;
628
+ }
629
+ function getAttributeNameFromPointer(pointer) {
630
+ const lastSegment = pointer.split('/').slice(-1)[0];
631
+ // new primitive value: can always be added as attributes, namespaces are already replaced
632
+ if (lastSegment === null || lastSegment === void 0 ? void 0 : lastSegment.length) {
633
+ // convert property names used in AVT types to attribute names (e.g. 'type', 'term' and 'qualifier')
634
+ // (EDMX Attribute names always start with upper case letter)
635
+ return lastSegment.substring(0, 1).toUpperCase() + lastSegment.substring(1);
636
+ }
637
+ return undefined;
638
+ }
639
+ //# sourceMappingURL=change-converter.js.map