@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,855 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XMLWriter = void 0;
4
+ const odata_annotation_core_1 = require("@sap-ux/odata-annotation-core");
5
+ const cds_annotation_parser_1 = require("@sap-ux/cds-annotation-parser");
6
+ const odata_annotation_core_types_1 = require("@sap-ux/odata-annotation-core-types");
7
+ const xml_odata_annotation_converter_1 = require("@sap-ux/xml-odata-annotation-converter");
8
+ const ast_1 = require("@xml-tools/ast");
9
+ const utils_1 = require("../utils");
10
+ const changes_1 = require("./changes");
11
+ const pointer_1 = require("./pointer");
12
+ const printOptions = Object.assign(Object.assign({}, odata_annotation_core_types_1.printOptions), { useSnippetSyntax: false });
13
+ /**
14
+ * Translates changes objects to XML text edits.
15
+ */
16
+ class XMLWriter {
17
+ /**
18
+ *
19
+ * @param document - XMLDocument AST node.
20
+ * @param comments - Array of all the comments in the document.
21
+ * @param textDocument - TextDocument instance.
22
+ */
23
+ constructor(document, comments, textDocument) {
24
+ this.document = document;
25
+ this.comments = comments;
26
+ this.textDocument = textDocument;
27
+ this.changes = [];
28
+ this.elementContentCache = new Map();
29
+ }
30
+ /**
31
+ * Adds a new change to the change stack.
32
+ *
33
+ * @param change - Change to be added to the stack.
34
+ */
35
+ addChange(change) {
36
+ this.changes.push(change);
37
+ }
38
+ /**
39
+ * Transforms changes in the stack to text edits.
40
+ *
41
+ * @returns TextEdits.
42
+ */
43
+ getTextEdits() {
44
+ const edits = [];
45
+ const changes = preprocessChanges(this.changes, this.document);
46
+ const batches = getBatches(changes);
47
+ for (const pointer of Object.keys(batches)) {
48
+ edits.push(...this.getTextEditsForPointer(pointer, batches[pointer]));
49
+ }
50
+ edits.sort(utils_1.compareTextEdits);
51
+ return edits;
52
+ }
53
+ getContent(element) {
54
+ let content = this.elementContentCache.get(element);
55
+ if (!content) {
56
+ content = getElementContent(element, this.comments);
57
+ this.elementContentCache.set(element, content);
58
+ }
59
+ return content;
60
+ }
61
+ getTextEditsForPointer(pointer, byType) {
62
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
63
+ const edits = [];
64
+ const element = (0, pointer_1.getNodeFromPointer)(this.document, pointer);
65
+ const childIndentLevel = getIndentFromElement(element);
66
+ const inserts = ((_a = byType.get('insert-element')) !== null && _a !== void 0 ? _a : []);
67
+ const insertEdits = convertInsertElementToTextEdits(this.comments, element, inserts, childIndentLevel);
68
+ edits.push(...insertEdits);
69
+ const elementNameUpdates = ((_b = byType.get('update-element-name')) !== null && _b !== void 0 ? _b : []);
70
+ edits.push(...convertUpdateElementNameToTextEdits(elementNameUpdates, element));
71
+ switch (element === null || element === void 0 ? void 0 : element.type) {
72
+ case 'XMLElement': {
73
+ const elementChanges = {
74
+ replacements: ((_c = byType.get('replace-element')) !== null && _c !== void 0 ? _c : []),
75
+ contentReplacements: ((_d = byType.get(changes_1.REPLACE_ELEMENT_CONTENT)) !== null && _d !== void 0 ? _d : []),
76
+ elementDeletions: ((_e = byType.get('delete-element')) !== null && _e !== void 0 ? _e : []),
77
+ attributeInserts: ((_f = byType.get('insert-attribute')) !== null && _f !== void 0 ? _f : []),
78
+ moveInCollection: ((_g = byType.get('move-collection-value')) !== null && _g !== void 0 ? _g : [])
79
+ };
80
+ edits.push(...this.handleXmlElementChanges(elementChanges, element, pointer, childIndentLevel));
81
+ break;
82
+ }
83
+ case 'XMLAttribute': {
84
+ const attributeChanges = {
85
+ attributeDeletions: ((_h = byType.get('delete-attribute')) !== null && _h !== void 0 ? _h : []),
86
+ attributeNameUpdates: ((_j = byType.get('update-attribute-name')) !== null && _j !== void 0 ? _j : []),
87
+ attributeValueUpdates: ((_k = byType.get('update-attribute-value')) !== null && _k !== void 0 ? _k : [])
88
+ };
89
+ edits.push(...handleXmlAttributeChanges(attributeChanges, element));
90
+ break;
91
+ }
92
+ default:
93
+ break;
94
+ }
95
+ return edits;
96
+ }
97
+ handleXmlElementChanges(elementChanges, element, pointer, childIndentLevel) {
98
+ const edits = [];
99
+ const { replacements, contentReplacements, elementDeletions, attributeInserts, moveInCollection } = elementChanges;
100
+ if (elementDeletions.length > 0) {
101
+ const parent = element.parent;
102
+ const content = parent.type === 'XMLElement' ? this.getContent(parent) : [];
103
+ edits.push(...handleXmlElementDeletions(parent, pointer, content, element));
104
+ }
105
+ else if (replacements.length > 0) {
106
+ edits.push(...handleXmlElementReplacements(element, replacements, childIndentLevel));
107
+ }
108
+ else if (contentReplacements.length > 0) {
109
+ edits.push(...handleXmlElementContentReplacements(element, contentReplacements, childIndentLevel));
110
+ }
111
+ else if (moveInCollection.length > 0) {
112
+ for (const moveChange of moveInCollection) {
113
+ const insertPosition = findInsertPositionForMove(moveChange.index, element, this.comments);
114
+ if (!insertPosition) {
115
+ continue;
116
+ }
117
+ const { textEdits, text } = this.prepareXmlElementMoveChange(moveChange);
118
+ edits.push(...textEdits);
119
+ edits.push(...handleXmlElementMoveChange(element, childIndentLevel, text, insertPosition));
120
+ }
121
+ }
122
+ else {
123
+ edits.push(...handleXmlElementAttributeInserts(element, attributeInserts));
124
+ }
125
+ return edits;
126
+ }
127
+ prepareXmlElementMoveChange(moveChange) {
128
+ const textEdits = [];
129
+ const ranges = createElementRanges(this.document, moveChange.fromPointers);
130
+ const text = [];
131
+ for (const { parent, start, end } of ranges) {
132
+ const content = this.getContent(parent);
133
+ const range = getRangeForMove(content, parent, start, end);
134
+ if (!range) {
135
+ continue;
136
+ }
137
+ text.push(this.textDocument.getText(range));
138
+ textEdits.push(odata_annotation_core_types_1.TextEdit.del(range));
139
+ }
140
+ return { textEdits, text };
141
+ }
142
+ }
143
+ exports.XMLWriter = XMLWriter;
144
+ function handleXmlAttributeChanges(attributeChanges, element) {
145
+ const edits = [];
146
+ const { attributeDeletions, attributeNameUpdates, attributeValueUpdates } = attributeChanges;
147
+ if (attributeDeletions.length > 0) {
148
+ const attributeRange = (0, xml_odata_annotation_converter_1.transformRange)(element.position);
149
+ if (attributeRange) {
150
+ // There must be a space character before attribute and we should remove it with attribute.
151
+ attributeRange.start.character--;
152
+ edits.push(odata_annotation_core_types_1.TextEdit.del(attributeRange));
153
+ }
154
+ }
155
+ else {
156
+ // if attribute is deleted, then we can ignore updates
157
+ const nameRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.key);
158
+ if (nameRange && attributeNameUpdates.length > 0) {
159
+ const newName = attributeNameUpdates[attributeNameUpdates.length - 1].newName;
160
+ edits.push(odata_annotation_core_types_1.TextEdit.replace(nameRange, newName));
161
+ }
162
+ const valueRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.value);
163
+ if (valueRange && attributeValueUpdates.length > 0) {
164
+ const newValue = attributeValueUpdates[attributeValueUpdates.length - 1].newValue;
165
+ // shift from start quote
166
+ valueRange.start.character++;
167
+ // shift from end quote
168
+ valueRange.end.character--;
169
+ edits.push(odata_annotation_core_types_1.TextEdit.replace(valueRange, newValue));
170
+ }
171
+ }
172
+ return edits;
173
+ }
174
+ function handleXmlElementAttributeInserts(element, attributeInserts) {
175
+ const openTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.openBody);
176
+ if (!openTagRange) {
177
+ return [];
178
+ }
179
+ const edits = [];
180
+ const byIndex = new Map();
181
+ for (const change of attributeInserts) {
182
+ let insertsAtIndex = byIndex.get(change.index);
183
+ if (!insertsAtIndex) {
184
+ insertsAtIndex = [];
185
+ byIndex.set(change.index, insertsAtIndex);
186
+ }
187
+ insertsAtIndex.push(change);
188
+ }
189
+ for (const [key, inserts] of byIndex.entries()) {
190
+ const attributes = [];
191
+ const position = getAttributeInsertPosition(element, openTagRange, key);
192
+ if (!position) {
193
+ // TODO: report error
194
+ continue;
195
+ }
196
+ for (const attributeInsert of inserts) {
197
+ // insert before open tag
198
+ attributes.push(`${attributeInsert.name}="${(0, xml_odata_annotation_converter_1.escapeAttribute)(attributeInsert.value)}"`);
199
+ }
200
+ if (attributes.length > 0) {
201
+ const text = ` ${attributes.join(' ')}`;
202
+ edits.push(odata_annotation_core_types_1.TextEdit.insert(position, text));
203
+ }
204
+ }
205
+ return edits;
206
+ }
207
+ function handleXmlElementMoveChange(element, childIndentLevel, text, insertPosition) {
208
+ const edits = [];
209
+ const openTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.openBody);
210
+ if (element.syntax.isSelfClosing && openTagRange) {
211
+ const indent = ' '.repeat(childIndentLevel - 1);
212
+ edits.push(odata_annotation_core_types_1.TextEdit.replace(odata_annotation_core_types_1.Range.create(openTagRange.end.line, openTagRange.end.character - 2, openTagRange.end.line, openTagRange.end.character), `>${text.join('')}\n${indent}</${element.name}>`));
213
+ }
214
+ else {
215
+ edits.push(odata_annotation_core_types_1.TextEdit.insert(insertPosition, text.join('')));
216
+ }
217
+ return edits;
218
+ }
219
+ function handleXmlElementContentReplacements(element, contentReplacements, childIndentLevel) {
220
+ const edits = [];
221
+ const openTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.openBody);
222
+ const closeTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.closeBody);
223
+ const lastChange = contentReplacements.slice(-1)[0];
224
+ const namespaceMap = getNamespaceMap(element);
225
+ const text = replaceElementContentToText(lastChange, childIndentLevel - 1, namespaceMap);
226
+ if (element.syntax.isSelfClosing && openTagRange) {
227
+ edits.push(odata_annotation_core_types_1.TextEdit.replace(odata_annotation_core_types_1.Range.create(openTagRange.end.line, openTagRange.end.character - 2, openTagRange.end.line, openTagRange.end.character), `>${text}</${element.name}>`));
228
+ }
229
+ else if (openTagRange && closeTagRange) {
230
+ edits.push(odata_annotation_core_types_1.TextEdit.replace(odata_annotation_core_types_1.Range.create(openTagRange.end, closeTagRange.start), text));
231
+ }
232
+ return edits;
233
+ }
234
+ function handleXmlElementReplacements(element, replacements, childIndentLevel) {
235
+ const edits = [];
236
+ const openTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.openBody);
237
+ const closeTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.closeBody);
238
+ const lastChange = replacements.slice(-1)[0];
239
+ const namespaceMap = getNamespaceMap(element);
240
+ const text = replaceElementToText(lastChange, childIndentLevel - 1, namespaceMap);
241
+ if (element.syntax.isSelfClosing && openTagRange) {
242
+ edits.push(odata_annotation_core_types_1.TextEdit.replace(openTagRange, text));
243
+ }
244
+ else if (openTagRange && closeTagRange) {
245
+ edits.push(odata_annotation_core_types_1.TextEdit.replace(odata_annotation_core_types_1.Range.create(openTagRange.start, closeTagRange.end), text));
246
+ }
247
+ return edits;
248
+ }
249
+ function handleXmlElementDeletions(parent, pointer, content, element) {
250
+ const edits = [];
251
+ const openTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.openBody);
252
+ if (parent.type === 'XMLElement') {
253
+ const index = parseInt(pointer.split('/').slice(-1)[0], 10);
254
+ const { previousContentIndex, startContentIndex } = findContentIndices(index, index, content);
255
+ const anchor = getStartAnchor(content, parent, previousContentIndex, startContentIndex);
256
+ if (anchor) {
257
+ const previousElement = content[previousContentIndex];
258
+ const nextElement = content.find((item, i) => item.type === 'element' && i > startContentIndex);
259
+ const parentCloseTagRange = (0, xml_odata_annotation_converter_1.transformRange)(parent.syntax.closeBody);
260
+ if (!nextElement && !previousElement && parentCloseTagRange) {
261
+ updatePosition(anchor.end, parentCloseTagRange.start);
262
+ }
263
+ edits.push(odata_annotation_core_types_1.TextEdit.del(anchor));
264
+ }
265
+ }
266
+ else if (element.syntax.isSelfClosing && openTagRange) {
267
+ // empty root element
268
+ edits.push(odata_annotation_core_types_1.TextEdit.del(openTagRange));
269
+ }
270
+ else {
271
+ // root element with content
272
+ const closeTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.closeBody);
273
+ if (openTagRange && closeTagRange) {
274
+ edits.push(odata_annotation_core_types_1.TextEdit.del(odata_annotation_core_types_1.Range.create(openTagRange.start, closeTagRange.end)));
275
+ }
276
+ }
277
+ return edits;
278
+ }
279
+ function convertUpdateElementNameToTextEdits(elementNameUpdates, element) {
280
+ var _a, _b;
281
+ const edits = [];
282
+ if (elementNameUpdates.length > 0 && (element === null || element === void 0 ? void 0 : element.type) === 'XMLElement') {
283
+ const newName = elementNameUpdates[elementNameUpdates.length - 1].newName;
284
+ const openTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.openBody);
285
+ const closeTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.closeBody);
286
+ if (openTagRange) {
287
+ const nameLength = (_b = (_a = element.name) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
288
+ openTagRange.start.character++; // <
289
+ openTagRange.end.character = openTagRange.start.character + nameLength;
290
+ edits.push(odata_annotation_core_types_1.TextEdit.replace(openTagRange, newName));
291
+ if (closeTagRange) {
292
+ closeTagRange.start.character += 2; // </
293
+ closeTagRange.end.character--; // >
294
+ edits.push(odata_annotation_core_types_1.TextEdit.replace(closeTagRange, newName));
295
+ }
296
+ }
297
+ }
298
+ return edits;
299
+ }
300
+ function getBatches(changes) {
301
+ const batches = {};
302
+ for (const change of changes) {
303
+ let byTypeMap = batches[change.pointer];
304
+ if (!byTypeMap) {
305
+ byTypeMap = new Map();
306
+ batches[change.pointer] = byTypeMap;
307
+ }
308
+ let batch = byTypeMap.get(change.type);
309
+ if (!batch) {
310
+ batch = [];
311
+ byTypeMap.set(change.type, batch);
312
+ }
313
+ batch.push(change);
314
+ }
315
+ return batches;
316
+ }
317
+ function getAttributeInsertPosition(element, openTagRange, index) {
318
+ if (index === undefined) {
319
+ // /> or >
320
+ const characterOffset = element.syntax.isSelfClosing === true ? 2 : 1;
321
+ return odata_annotation_core_types_1.Position.create(openTagRange.end.line, openTagRange.end.character - characterOffset);
322
+ }
323
+ const attribute = element.attributes[index];
324
+ if (!attribute) {
325
+ return undefined;
326
+ }
327
+ const range = (0, xml_odata_annotation_converter_1.transformRange)(attribute.position);
328
+ if (!range) {
329
+ return undefined;
330
+ }
331
+ // There must be a space character before attribute and the insert position should be before it
332
+ return odata_annotation_core_types_1.Position.create(range.start.line, range.start.character - 1);
333
+ }
334
+ function convertInsertElementToTextEdits(comments, element, changes, childIndentLevel) {
335
+ if (!(element === undefined || element.type === 'XMLElement')) {
336
+ return [];
337
+ }
338
+ if (changes.length === 0) {
339
+ return [];
340
+ }
341
+ if (!element) {
342
+ const change = changes.slice(-1)[0];
343
+ const namespaceMap = getNamespaceMapForNewRootNode(change.element);
344
+ const newElements = insertElementToText([change], childIndentLevel, namespaceMap);
345
+ return [odata_annotation_core_types_1.TextEdit.insert(odata_annotation_core_types_1.Position.create(0, 0), newElements)];
346
+ }
347
+ else {
348
+ const namespaceMap = getNamespaceMap(element);
349
+ const openTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.openBody);
350
+ if (element.syntax.isSelfClosing && openTagRange) {
351
+ const newElements = insertElementToText(changes, childIndentLevel, namespaceMap);
352
+ const fragments = ['>', '\n', newElements];
353
+ fragments.push('\n');
354
+ const indentLevel = childIndentLevel > 0 ? childIndentLevel - 1 : 0;
355
+ const indent = ' '.repeat(indentLevel);
356
+ fragments.push(`${indent}</${element.name}>`);
357
+ return [
358
+ odata_annotation_core_types_1.TextEdit.replace(odata_annotation_core_types_1.Range.create(openTagRange.end.line, openTagRange.end.character - 2, openTagRange.end.line, openTagRange.end.character), fragments.join(''))
359
+ ];
360
+ }
361
+ else {
362
+ return insertIntoElementWithContent(comments, element, changes, childIndentLevel, namespaceMap);
363
+ }
364
+ }
365
+ }
366
+ function insertIntoElementWithContent(comments, element, changes, childIndentLevel, namespaceMap) {
367
+ var _a, _b;
368
+ const edits = [];
369
+ const [indices, changesByIndex] = indexInserts(changes);
370
+ for (const index of indices) {
371
+ const changeSet = changesByIndex.get(index);
372
+ if (!changeSet) {
373
+ continue;
374
+ }
375
+ const anchor = findInsertPosition(comments, element, index !== null && index !== void 0 ? index : -1);
376
+ if (anchor.type === 'none') {
377
+ continue;
378
+ }
379
+ const fragments = [];
380
+ if (((_a = element.syntax.openBody) === null || _a === void 0 ? void 0 : _a.endLine) === ((_b = element.syntax.closeBody) === null || _b === void 0 ? void 0 : _b.startLine) && !anchor.requiresNewLine) {
381
+ fragments.push('\n');
382
+ }
383
+ const newElements = insertElementToText(changeSet, childIndentLevel, namespaceMap) + '\n';
384
+ if (anchor.requiresNewLine) {
385
+ fragments.push('\n');
386
+ }
387
+ fragments.push(newElements);
388
+ if (!anchor.requiresNewLine) {
389
+ edits.push(odata_annotation_core_types_1.TextEdit.insert(anchor.position, fragments.join('')));
390
+ continue;
391
+ }
392
+ const childIndent = (0, odata_annotation_core_1.indent)(printOptions.tabWidth, printOptions.useTabs, childIndentLevel);
393
+ fragments.push(childIndent);
394
+ if (anchor.redundantWhitespace) {
395
+ edits.push(odata_annotation_core_types_1.TextEdit.del(anchor.redundantWhitespace));
396
+ }
397
+ edits.push(odata_annotation_core_types_1.TextEdit.insert(anchor.position, fragments.join('')));
398
+ }
399
+ return edits;
400
+ }
401
+ function indexInserts(changes) {
402
+ const changesByIndex = new Map();
403
+ const indices = [];
404
+ for (const change of changes) {
405
+ let changeSet = changesByIndex.get(change.index);
406
+ if (!changeSet) {
407
+ changeSet = [];
408
+ indices.push(change.index);
409
+ changesByIndex.set(change.index, changeSet);
410
+ }
411
+ changeSet.push(change);
412
+ }
413
+ return [indices, changesByIndex];
414
+ }
415
+ function insertElementToText(inserts, childIndentLevel, namespaceMap) {
416
+ return inserts
417
+ .map((change) => (0, xml_odata_annotation_converter_1.printCsdlNodeToXmlString)((0, odata_annotation_core_types_1.createElementNode)(change.element), printOptions, {
418
+ namespaces: namespaceMap,
419
+ cursorIndentLevel: childIndentLevel
420
+ }))
421
+ .join('\n');
422
+ }
423
+ function replaceElementToText(change, childIndentLevel, namespaceMap) {
424
+ return (0, xml_odata_annotation_converter_1.printCsdlNodeToXmlString)((0, odata_annotation_core_types_1.createElementNode)(change.newElement), printOptions, {
425
+ namespaces: namespaceMap,
426
+ cursorIndentLevel: childIndentLevel
427
+ }).trim();
428
+ }
429
+ function replaceElementContentToText(change, childIndentLevel, namespaceMap) {
430
+ return (0, xml_odata_annotation_converter_1.printCsdlNodeToXmlString)(change.newValue, printOptions, {
431
+ namespaces: namespaceMap,
432
+ cursorIndentLevel: childIndentLevel
433
+ }).trim();
434
+ }
435
+ function findInsertPosition(comments, element, index = -1) {
436
+ const child = index !== -1 ? element.subElements[index] : undefined;
437
+ if (child) {
438
+ const childRange = sourcePositionToRange(child.position);
439
+ // keep associated comments with element together
440
+ const comment = findComment(comments, childRange);
441
+ const startAnchorRange = findStartAnchorRange(element, index);
442
+ if (!startAnchorRange) {
443
+ return { type: 'none' };
444
+ }
445
+ const anchorPosition = comment ? comment.range.start : childRange.start;
446
+ const requiresNewLine = anchorPosition.line === startAnchorRange.end.line;
447
+ // If we are not on the same line as the starting anchor,
448
+ // then it means there should be only whitespace until the start of the line
449
+ // and we can insert the snippet there
450
+ const position = requiresNewLine ? anchorPosition : odata_annotation_core_types_1.Position.create(anchorPosition.line, 0);
451
+ const redundantWhitespace = requiresNewLine ? odata_annotation_core_types_1.Range.create(startAnchorRange.end, anchorPosition) : undefined;
452
+ return { type: 'child', position, requiresNewLine, redundantWhitespace };
453
+ }
454
+ const closeTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.closeBody);
455
+ const startAnchorRange = findStartAnchorRange(element, element.subElements.length);
456
+ if (closeTagRange && startAnchorRange) {
457
+ const anchorPosition = closeTagRange.start;
458
+ const requiresNewLine = anchorPosition.line === startAnchorRange.end.line;
459
+ const position = requiresNewLine ? anchorPosition : odata_annotation_core_types_1.Position.create(anchorPosition.line, 0);
460
+ return { type: 'parent', position, requiresNewLine: false };
461
+ }
462
+ return { type: 'none' };
463
+ }
464
+ /**
465
+ * Finds a closest boundary structure before the given element and returns its range.
466
+ * It could be either another sibling element or an opening tag of a parent.
467
+ *
468
+ * @param parent - Parent element.
469
+ * @param index - Current element index.
470
+ * @returns Anchor range.
471
+ */
472
+ function findStartAnchorRange(parent, index) {
473
+ const previousElement = parent.subElements[index - 1];
474
+ if (index === 0) {
475
+ return (0, xml_odata_annotation_converter_1.transformRange)(parent.syntax.openBody);
476
+ }
477
+ if (previousElement) {
478
+ return sourcePositionToRange(previousElement.position);
479
+ }
480
+ return undefined;
481
+ }
482
+ /**
483
+ * Find comment that is associated with the range.
484
+ * We consider comments right before an element to be associated.
485
+ *
486
+ * @param comments - Documents comments.
487
+ * @param range - Range to which the comment should be associated to.
488
+ * @returns Comment if it exists.
489
+ */
490
+ function findComment(comments, range) {
491
+ const previousLine = range.start.line - 1;
492
+ for (const comment of comments) {
493
+ if (comment.range.end.line === previousLine || comment.range.start.line === range.end.line) {
494
+ return comment;
495
+ }
496
+ }
497
+ return undefined;
498
+ }
499
+ function sourcePositionToRange(position) {
500
+ return odata_annotation_core_types_1.Range.create(position.startLine - 1, position.startColumn - 1, position.endLine - 1, position.endColumn);
501
+ }
502
+ function getIndentFromElement(element) {
503
+ if ((element === null || element === void 0 ? void 0 : element.type) === 'XMLElement') {
504
+ const openTagRange = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.openBody);
505
+ if (openTagRange) {
506
+ return (0, odata_annotation_core_1.getIndentLevel)(openTagRange.start.character, printOptions.tabWidth) + 1;
507
+ }
508
+ }
509
+ return 0;
510
+ }
511
+ function createElementRanges(document, pointers) {
512
+ const ranges = [];
513
+ const groups = pointers.reduce((acc, pointer) => {
514
+ const segments = pointer.split('/');
515
+ // remove /subElements/<index> suffix
516
+ const containerPath = segments.slice(0, -2).join('/');
517
+ const index = parseInt(segments.slice(-1)[0], 10);
518
+ const list = acc.get(containerPath);
519
+ if (list) {
520
+ list.push(index);
521
+ }
522
+ else {
523
+ acc.set(containerPath, [index]);
524
+ }
525
+ return acc;
526
+ }, new Map());
527
+ for (const [containerPath, indices] of groups) {
528
+ const parent = (0, pointer_1.getNodeFromPointer)(document, containerPath);
529
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'XMLElement') {
530
+ indices.sort((index1, index2) => index1 - index2);
531
+ for (let i = 1, start = indices[0], end = indices[0]; i <= indices.length; i++) {
532
+ const current = indices[i];
533
+ if (current === undefined) {
534
+ // end of collection
535
+ ranges.push({ parent, start, end });
536
+ }
537
+ else if (end + 1 === current) {
538
+ // indices are in sequence -> merge
539
+ end = current;
540
+ }
541
+ else {
542
+ // there is a gap between indices -> create a range
543
+ ranges.push({ parent, start, end });
544
+ start = end = current;
545
+ }
546
+ }
547
+ }
548
+ }
549
+ return ranges;
550
+ }
551
+ function getElementContent(element, comments) {
552
+ const range = (0, xml_odata_annotation_converter_1.transformRange)(element.position);
553
+ if (!range) {
554
+ return [];
555
+ }
556
+ const commentsInContent = comments.filter((comment) => isCommentInContent(range, comment, element));
557
+ const source = [...element.subElements, ...commentsInContent].sort(compareRange);
558
+ const content = [];
559
+ for (let i = 0; i < source.length; i++) {
560
+ const item = source[i];
561
+ if (item.type !== 'XMLElement') {
562
+ content.push(item);
563
+ continue;
564
+ }
565
+ const range = (0, xml_odata_annotation_converter_1.transformRange)(item.position);
566
+ if (!range) {
567
+ continue;
568
+ }
569
+ const element = {
570
+ type: 'element',
571
+ element: item,
572
+ elementRange: range,
573
+ range: (0, cds_annotation_parser_1.copyRange)(range)
574
+ };
575
+ const previousItem = content[content.length - 1];
576
+ const previousLine = element.range.start.line - 1;
577
+ if ((previousItem === null || previousItem === void 0 ? void 0 : previousItem.type) === 'comment' &&
578
+ (previousItem.range.end.line === previousLine || previousItem.range.end.line === element.range.start.line)) {
579
+ // typescript can't infer that content.pop() === previousItem
580
+ element.leadingComment = content.pop();
581
+ updatePosition(element.range.start, previousItem.range.start);
582
+ }
583
+ const nextItem = source[i + 1];
584
+ if ((nextItem === null || nextItem === void 0 ? void 0 : nextItem.type) === 'comment' && nextItem.range.start.line === range.end.line) {
585
+ element.trailingComment = nextItem;
586
+ updatePosition(element.range.end, nextItem.range.end);
587
+ i++;
588
+ }
589
+ content.push(element);
590
+ }
591
+ return content;
592
+ }
593
+ function isCommentInContent(range, comment, element) {
594
+ return ((0, odata_annotation_core_1.rangeContained)(range, comment.range) &&
595
+ !element.subElements.some((item) => {
596
+ const subElementRange = (0, xml_odata_annotation_converter_1.transformRange)(item.position);
597
+ if (!subElementRange) {
598
+ return false;
599
+ }
600
+ return (0, odata_annotation_core_1.rangeContained)(subElementRange, comment.range);
601
+ }));
602
+ }
603
+ function compareRange(a, b) {
604
+ var _a, _b, _c, _d, _e, _f, _g, _h;
605
+ const aRange = (_a = a.range) !== null && _a !== void 0 ? _a : (0, xml_odata_annotation_converter_1.transformRange)((_c = (_b = a.syntax) === null || _b === void 0 ? void 0 : _b.closeBody) !== null && _c !== void 0 ? _c : (_d = a.syntax) === null || _d === void 0 ? void 0 : _d.openBody);
606
+ const bRange = (_e = b.range) !== null && _e !== void 0 ? _e : (0, xml_odata_annotation_converter_1.transformRange)((_g = (_f = b.syntax) === null || _f === void 0 ? void 0 : _f.closeBody) !== null && _g !== void 0 ? _g : (_h = b.syntax) === null || _h === void 0 ? void 0 : _h.openBody);
607
+ if (!aRange) {
608
+ return 1;
609
+ }
610
+ if (!bRange) {
611
+ return -1;
612
+ }
613
+ if ((0, odata_annotation_core_1.isBefore)(aRange.start, bRange.start)) {
614
+ return -1;
615
+ }
616
+ else if ((0, odata_annotation_core_1.isBefore)(bRange.start, aRange.start)) {
617
+ return 1;
618
+ }
619
+ return 0;
620
+ }
621
+ function findContentIndices(start, end, content) {
622
+ let previousContentIndex = -1;
623
+ let startContentIndex = -1;
624
+ let endContentIndex = -1;
625
+ for (let index = 0, contentIndex = 0; index < content.length; index++) {
626
+ const element = content[index];
627
+ if (element.type === 'element') {
628
+ if (start - 1 === contentIndex) {
629
+ previousContentIndex = index;
630
+ }
631
+ if (start === contentIndex) {
632
+ startContentIndex = index;
633
+ }
634
+ if (end === contentIndex) {
635
+ endContentIndex = index;
636
+ break;
637
+ }
638
+ contentIndex++;
639
+ }
640
+ }
641
+ return {
642
+ previousContentIndex,
643
+ startContentIndex,
644
+ endContentIndex
645
+ };
646
+ }
647
+ function getRangeForMove(content, parent, start, end) {
648
+ var _a, _b;
649
+ const { previousContentIndex, startContentIndex, endContentIndex } = findContentIndices(start, end, content);
650
+ const endElement = content[endContentIndex];
651
+ let startPosition = (_a = getStartAnchor(content, parent, previousContentIndex, startContentIndex)) === null || _a === void 0 ? void 0 : _a.start;
652
+ let endPosition = (_b = endElement === null || endElement === void 0 ? void 0 : endElement.range) === null || _b === void 0 ? void 0 : _b.end;
653
+ if (startPosition) {
654
+ startPosition = (0, cds_annotation_parser_1.copyPosition)(startPosition);
655
+ }
656
+ if (endPosition) {
657
+ endPosition = (0, cds_annotation_parser_1.copyPosition)(endPosition);
658
+ }
659
+ if (!startPosition || !endElement) {
660
+ return undefined;
661
+ }
662
+ return odata_annotation_core_types_1.Range.create(startPosition, endPosition);
663
+ }
664
+ function getStartAnchor(content, parent, previous, index) {
665
+ var _a, _b;
666
+ const previousElement = content[previous];
667
+ let startPosition = index === 0 ? (_a = (0, xml_odata_annotation_converter_1.transformRange)(parent.syntax.openBody)) === null || _a === void 0 ? void 0 : _a.end : (_b = previousElement === null || previousElement === void 0 ? void 0 : previousElement.range) === null || _b === void 0 ? void 0 : _b.end;
668
+ const item = content[index];
669
+ if (startPosition) {
670
+ startPosition = (0, cds_annotation_parser_1.copyPosition)(startPosition);
671
+ }
672
+ if (!startPosition || !item) {
673
+ return undefined;
674
+ }
675
+ const previousItem = content[index - 1];
676
+ if ((previousItem === null || previousItem === void 0 ? void 0 : previousItem.type) === 'comment') {
677
+ // multiple comments between previous item and starting item -> ignore them
678
+ updatePosition(startPosition, previousItem.range.end);
679
+ }
680
+ return odata_annotation_core_types_1.Range.create(startPosition, (0, cds_annotation_parser_1.copyPosition)(item.range.end));
681
+ }
682
+ function updatePosition(a, b) {
683
+ a.line = b.line;
684
+ a.character = b.character;
685
+ }
686
+ function adjustRangeByComments(comments, range) {
687
+ if (!range) {
688
+ return;
689
+ }
690
+ // find inline comment after planned insert position
691
+ const inlineComments = comments.filter((comment) => comment.range.start.line === range.end.line && comment.range.start.character > range.end.character);
692
+ // search the right most inline comment, its end position should be the insertion position
693
+ if (inlineComments.length) {
694
+ let pos = range.end;
695
+ for (const comment of inlineComments) {
696
+ if (comment.range.start.character > pos.character) {
697
+ pos = comment.range.end;
698
+ }
699
+ }
700
+ range.end = pos;
701
+ }
702
+ }
703
+ function findInsertPositionForMove(index, element, comments) {
704
+ var _a, _b;
705
+ if (index === 0) {
706
+ const range = (0, xml_odata_annotation_converter_1.transformRange)(element.syntax.openBody);
707
+ return range === null || range === void 0 ? void 0 : range.end;
708
+ }
709
+ else if (index === undefined || index >= element.subElements.length) {
710
+ const child = element.subElements[element.subElements.length - 1];
711
+ if (!child) {
712
+ return undefined;
713
+ }
714
+ // self closed elements only have "openBody"
715
+ const range = (0, xml_odata_annotation_converter_1.transformRange)((_a = child.syntax.closeBody) !== null && _a !== void 0 ? _a : child.syntax.openBody);
716
+ adjustRangeByComments(comments, range);
717
+ return range === null || range === void 0 ? void 0 : range.end;
718
+ }
719
+ else if (index > 0) {
720
+ const child = element.subElements[index - 1];
721
+ // end of the previous element
722
+ // self closed elements only have "openBody"
723
+ const range = (0, xml_odata_annotation_converter_1.transformRange)((_b = child.syntax.closeBody) !== null && _b !== void 0 ? _b : child.syntax.openBody);
724
+ adjustRangeByComments(comments, range);
725
+ return range === null || range === void 0 ? void 0 : range.end;
726
+ }
727
+ return undefined;
728
+ }
729
+ function getNamespaceMap(parent) {
730
+ const map = {};
731
+ for (const alias of Object.keys(parent.namespaces)) {
732
+ if (alias === ast_1.DEFAULT_NS) {
733
+ continue;
734
+ }
735
+ const namespace = parent.namespaces[alias];
736
+ if (namespace === xml_odata_annotation_converter_1.EDMX_V4_NAMESPACE) {
737
+ map[odata_annotation_core_types_1.EDMX_NAMESPACE_ALIAS] = alias;
738
+ }
739
+ else if (namespace === xml_odata_annotation_converter_1.EDM_V4_NAMESPACE) {
740
+ map[odata_annotation_core_types_1.EDM_NAMESPACE_ALIAS] = alias;
741
+ }
742
+ }
743
+ return map;
744
+ }
745
+ function getNamespaceMapForNewRootNode(element) {
746
+ const map = {};
747
+ for (const attributeName of Object.keys(element.attributes)) {
748
+ if (!attributeName.startsWith('xmlns')) {
749
+ continue;
750
+ }
751
+ const { name, value: namespace } = element.attributes[attributeName];
752
+ const [, alias] = name.split(':');
753
+ if (alias === undefined) {
754
+ continue;
755
+ }
756
+ if (namespace === xml_odata_annotation_converter_1.EDMX_V4_NAMESPACE) {
757
+ map[odata_annotation_core_types_1.EDMX_NAMESPACE_ALIAS] = alias;
758
+ }
759
+ else if (namespace === xml_odata_annotation_converter_1.EDM_V4_NAMESPACE) {
760
+ map[odata_annotation_core_types_1.EDM_NAMESPACE_ALIAS] = alias;
761
+ }
762
+ }
763
+ return map;
764
+ }
765
+ function preprocessChanges(changes, document) {
766
+ let result = removeDuplicates(changes);
767
+ result = removeOverlappingDeletes(result);
768
+ result = combineInsertsWithDeletions(result, document);
769
+ return result;
770
+ }
771
+ function combineInsertsWithDeletions(changes, document) {
772
+ var _a;
773
+ const result = [];
774
+ const deletions = new Set();
775
+ const replacements = new Map();
776
+ // Inserts are usually merged together, so we need to replace the last insert of the batch for the same index
777
+ for (let i = changes.length - 1; i >= 0; i--) {
778
+ const change = changes[i];
779
+ if (change.type !== 'insert-element') {
780
+ continue;
781
+ }
782
+ // merge inserts and deletions
783
+ const element = (0, pointer_1.getNodeFromPointer)(document, change.pointer);
784
+ if ((element === null || element === void 0 ? void 0 : element.type) !== 'XMLElement') {
785
+ continue;
786
+ }
787
+ const index = (_a = change.index) !== null && _a !== void 0 ? _a : element.subElements.length - 1;
788
+ const pointer = `${change.pointer}/subElements/${index}`;
789
+ const deletionChangeIndex = changes.findIndex((c) => c.pointer === pointer && c.type === 'delete-element');
790
+ if (deletionChangeIndex !== -1 && !replacements.has(deletionChangeIndex)) {
791
+ replacements.set(deletionChangeIndex, {
792
+ type: 'replace-element',
793
+ pointer,
794
+ newElement: change.element
795
+ });
796
+ deletions.add(i);
797
+ }
798
+ }
799
+ for (let i = 0; i < changes.length; i++) {
800
+ const change = changes[i];
801
+ const replacement = replacements.get(i);
802
+ if (replacement) {
803
+ result.push(replacement);
804
+ }
805
+ else if (!deletions.has(i)) {
806
+ result.push(change);
807
+ }
808
+ }
809
+ return result;
810
+ }
811
+ function removeDuplicates(changes) {
812
+ const existingDeletions = [];
813
+ const result = [];
814
+ for (const change of changes) {
815
+ if (change.type === 'delete-element') {
816
+ if (existingDeletions.indexOf(change.pointer) === -1) {
817
+ existingDeletions.push(change.pointer);
818
+ result.push(change);
819
+ }
820
+ }
821
+ else {
822
+ result.push(change);
823
+ }
824
+ }
825
+ return result;
826
+ }
827
+ function removeOverlappingDeletes(changes) {
828
+ const result = [];
829
+ const deletions = new Set();
830
+ for (const change of changes) {
831
+ if (change.type === 'delete-element') {
832
+ const pointerLength = change.pointer.split('/').length;
833
+ for (let j = 0; j < changes.length; j++) {
834
+ const otherChange = changes[j];
835
+ const otherPointerLength = otherChange.pointer.split('/').length;
836
+ if ((otherChange.type === 'delete-element' || otherChange.type === 'delete-attribute') &&
837
+ otherChange.pointer.startsWith(change.pointer) &&
838
+ otherChange.pointer !== change.pointer &&
839
+ // startsWith can match siblings because indices are converted to string and compared as strings
840
+ // we need to avoid .../subElements/1 matching to .../subElements/10
841
+ otherPointerLength !== pointerLength) {
842
+ deletions.add(j);
843
+ }
844
+ }
845
+ }
846
+ }
847
+ for (let i = 0; i < changes.length; i++) {
848
+ const change = changes[i];
849
+ if (!deletions.has(i)) {
850
+ result.push(change);
851
+ }
852
+ }
853
+ return result;
854
+ }
855
+ //# sourceMappingURL=writer.js.map