@sap-ux/cds-annotation-parser 0.1.1

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 (55) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +74 -0
  3. package/dist/constants.d.ts +6 -0
  4. package/dist/constants.d.ts.map +1 -0
  5. package/dist/constants.js +10 -0
  6. package/dist/constants.js.map +1 -0
  7. package/dist/find-annotation-node.d.ts +40 -0
  8. package/dist/find-annotation-node.d.ts.map +1 -0
  9. package/dist/find-annotation-node.js +135 -0
  10. package/dist/find-annotation-node.js.map +1 -0
  11. package/dist/index.d.ts +7 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +52 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/parser/factory.d.ts +6 -0
  16. package/dist/parser/factory.d.ts.map +1 -0
  17. package/dist/parser/factory.js +13 -0
  18. package/dist/parser/factory.js.map +1 -0
  19. package/dist/parser/index.d.ts +11 -0
  20. package/dist/parser/index.d.ts.map +1 -0
  21. package/dist/parser/index.js +17 -0
  22. package/dist/parser/index.js.map +1 -0
  23. package/dist/parser/parser.d.ts +242 -0
  24. package/dist/parser/parser.d.ts.map +1 -0
  25. package/dist/parser/parser.js +385 -0
  26. package/dist/parser/parser.js.map +1 -0
  27. package/dist/parser/tokens.d.ts +103 -0
  28. package/dist/parser/tokens.d.ts.map +1 -0
  29. package/dist/parser/tokens.js +287 -0
  30. package/dist/parser/tokens.js.map +1 -0
  31. package/dist/transformer/annotation-ast-nodes.d.ts +178 -0
  32. package/dist/transformer/annotation-ast-nodes.d.ts.map +1 -0
  33. package/dist/transformer/annotation-ast-nodes.js +69 -0
  34. package/dist/transformer/annotation-ast-nodes.js.map +1 -0
  35. package/dist/transformer/ast.d.ts +6 -0
  36. package/dist/transformer/ast.d.ts.map +1 -0
  37. package/dist/transformer/ast.js +1227 -0
  38. package/dist/transformer/ast.js.map +1 -0
  39. package/dist/transformer/expressions.d.ts +87 -0
  40. package/dist/transformer/expressions.d.ts.map +1 -0
  41. package/dist/transformer/expressions.js +548 -0
  42. package/dist/transformer/expressions.js.map +1 -0
  43. package/dist/transformer/index.d.ts +5 -0
  44. package/dist/transformer/index.d.ts.map +1 -0
  45. package/dist/transformer/index.js +42 -0
  46. package/dist/transformer/index.js.map +1 -0
  47. package/dist/transformer/range.d.ts +20 -0
  48. package/dist/transformer/range.d.ts.map +1 -0
  49. package/dist/transformer/range.js +31 -0
  50. package/dist/transformer/range.js.map +1 -0
  51. package/dist/utils/index.d.ts +4 -0
  52. package/dist/utils/index.d.ts.map +1 -0
  53. package/dist/utils/index.js +17 -0
  54. package/dist/utils/index.js.map +1 -0
  55. package/package.json +38 -0
@@ -0,0 +1,1227 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAst = exports.locationToRange = void 0;
4
+ const vscode_languageserver_types_1 = require("vscode-languageserver-types");
5
+ const annotation_ast_nodes_1 = require("./annotation-ast-nodes");
6
+ const factory_1 = require("../parser/factory");
7
+ const expressions_1 = require("./expressions");
8
+ const odata_vocabularies_1 = require("@sap-ux/odata-vocabularies");
9
+ const tokens_1 = require("../parser/tokens");
10
+ const range_1 = require("./range");
11
+ const utils_1 = require("../utils");
12
+ /**
13
+ * Extracts qualifier part from term and adapt range and value for term.
14
+ *
15
+ * @param term Term node
16
+ * @returns Qualifier node
17
+ */
18
+ const createQualifier = (term) => {
19
+ var _a, _b;
20
+ const segment = term.segments.find((item) => item.value.includes('#'));
21
+ let qRange;
22
+ let qualifierValue = '';
23
+ if ((0, utils_1.isDefined)(segment)) {
24
+ const tokens = segment.value.split('#');
25
+ segment.value = (_a = tokens.shift()) !== null && _a !== void 0 ? _a : '';
26
+ qualifierValue = (_b = tokens.pop()) !== null && _b !== void 0 ? _b : '';
27
+ const len = qualifierValue.length;
28
+ if (segment.range) {
29
+ qRange = {
30
+ start: Object.assign(Object.assign({}, segment.range.end), { character: segment.range.end.character - len }),
31
+ end: Object.assign({}, segment.range.end)
32
+ };
33
+ segment.range.end.character = segment.range.end.character - len - 1;
34
+ }
35
+ }
36
+ return {
37
+ type: annotation_ast_nodes_1.QUALIFIER_TYPE,
38
+ value: qualifierValue,
39
+ range: qRange
40
+ };
41
+ };
42
+ const compareTokensByPosition = (a, b) => {
43
+ return a.startOffset - b.startOffset;
44
+ };
45
+ const adjustPosition = (position, offset) => vscode_languageserver_types_1.Position.create(position.line + offset.line, position.line === 0 ? position.character + offset.character : position.character);
46
+ const locationToRange = (location) => {
47
+ var _a, _b, _c;
48
+ return location
49
+ ? vscode_languageserver_types_1.Range.create(location.startLine - 1, ((_a = location.startColumn) !== null && _a !== void 0 ? _a : 0) - 1, ((_b = location.endLine) !== null && _b !== void 0 ? _b : 0) - 1, (_c = location.endColumn) !== null && _c !== void 0 ? _c : 0)
50
+ : undefined;
51
+ };
52
+ exports.locationToRange = locationToRange;
53
+ const existsAndNotRecovered = (nodes) => { var _a; return (0, utils_1.hasItems)(nodes) && !((_a = nodes[0]) === null || _a === void 0 ? void 0 : _a.isInsertedInRecovery); };
54
+ const vocabularyService = new odata_vocabularies_1.VocabularyService(true);
55
+ const vocabularyAliases = [...vocabularyService.getVocabularies().values()].map((vocabulary) => vocabulary.defaultAlias);
56
+ const supportedVocabularyAliases = new Set([...vocabularyAliases, ...vocabularyService.cdsVocabulary.groupNames]);
57
+ const findNextToken = (tokens, previousTokenEndOffset) => {
58
+ const prevTokenIdx = tokens.findIndex((token) => token.endOffset === previousTokenEndOffset);
59
+ return tokens[prevTokenIdx + 1];
60
+ };
61
+ /**
62
+ *
63
+ */
64
+ class CstToAstVisitor extends factory_1.Visitor {
65
+ constructor() {
66
+ super(...arguments);
67
+ this.tokenVector = [];
68
+ }
69
+ /**
70
+ * Main visitor entry.
71
+ *
72
+ * @param cstNode CST node
73
+ * @returns Result of the visitor call for the given cstNode
74
+ */
75
+ visit(cstNode) {
76
+ return super.visit(cstNode, cstNode.location);
77
+ }
78
+ /**
79
+ * Converts cst node location to range object.
80
+ *
81
+ * @param location CST node location
82
+ * @returns Range object
83
+ */
84
+ locationToRange(location) {
85
+ const range = (0, exports.locationToRange)(location);
86
+ if (this.startPosition && range) {
87
+ return vscode_languageserver_types_1.Range.create(adjustPosition(range.start, this.startPosition), adjustPosition(range.end, this.startPosition));
88
+ }
89
+ return range;
90
+ }
91
+ /**
92
+ * Converts given token to range object.
93
+ *
94
+ * @param token Token to convert
95
+ * @returns Range object
96
+ */
97
+ tokenToRange(token) {
98
+ var _a, _b, _c, _d, _e, _f;
99
+ const start = vscode_languageserver_types_1.Position.create(((_a = token.startLine) !== null && _a !== void 0 ? _a : 0) - 1, ((_b = token.startColumn) !== null && _b !== void 0 ? _b : 0) - 1);
100
+ const line = (0, utils_1.hasNaNOrUndefined)(token.endLine) ? ((_c = token.startLine) !== null && _c !== void 0 ? _c : 0) - 1 : ((_d = token.endLine) !== null && _d !== void 0 ? _d : 0) - 1;
101
+ const char = (0, utils_1.hasNaNOrUndefined)(token.endColumn)
102
+ ? ((_e = token.startColumn) !== null && _e !== void 0 ? _e : 0) - 1 + token.image.length
103
+ : (_f = token.endColumn) !== null && _f !== void 0 ? _f : 0;
104
+ const end = vscode_languageserver_types_1.Position.create(line, char);
105
+ if (this.startPosition) {
106
+ return vscode_languageserver_types_1.Range.create(adjustPosition(start, this.startPosition), adjustPosition(end, this.startPosition));
107
+ }
108
+ return vscode_languageserver_types_1.Range.create(start, end);
109
+ }
110
+ /**
111
+ * Converts CST token to AST token.
112
+ *
113
+ * @param token CST token
114
+ * @returns AST token
115
+ */
116
+ createToken(token) {
117
+ return {
118
+ type: annotation_ast_nodes_1.TOKEN_TYPE,
119
+ value: token.image,
120
+ range: this.tokenToRange(token)
121
+ };
122
+ }
123
+ /**
124
+ * Extracts qouted literal from the given cst token.
125
+ *
126
+ * @param context CST token
127
+ * @returns String literal (without quotes)
128
+ */
129
+ getQuotedLiteralValue(context) {
130
+ return context.image.split("'")[1];
131
+ }
132
+ /**
133
+ * Converts the given CST token to a path.
134
+ *
135
+ * @param identifier CST token
136
+ * @returns Path object
137
+ */
138
+ pathFromIdentifier(identifier) {
139
+ return {
140
+ type: annotation_ast_nodes_1.PATH_TYPE,
141
+ value: identifier.image,
142
+ segments: [
143
+ {
144
+ type: annotation_ast_nodes_1.IDENTIFIER_TYPE,
145
+ value: identifier.image,
146
+ range: this.tokenToRange(identifier)
147
+ }
148
+ ],
149
+ separators: [],
150
+ range: this.tokenToRange(identifier)
151
+ };
152
+ }
153
+ /**
154
+ * Converts given CST tokens to ast tokens. Used to convert comma tokens.
155
+ *
156
+ * @param parma Array of CST tokens
157
+ * @returns Array of AST tokens
158
+ */
159
+ getCommaToken(parma = []) {
160
+ return parma.map((item) => ({
161
+ type: annotation_ast_nodes_1.TOKEN_TYPE,
162
+ value: item.image,
163
+ range: this.tokenToRange(item)
164
+ }));
165
+ }
166
+ /**
167
+ * Extracts qualifier from the given annotation assignment.
168
+ *
169
+ * @param assignment Annotation assignment
170
+ * @returns Qualifier node or undefined if not found
171
+ */
172
+ getQualifier(assignment) {
173
+ if (!(0, utils_1.hasItems)(assignment.NumberSign)) {
174
+ return undefined;
175
+ }
176
+ const range = (0, utils_1.hasItems)(assignment.NumberSign) ? this.tokenToRange(assignment.NumberSign[0]) : undefined;
177
+ if (range) {
178
+ // We need position after # symbol
179
+ range.start.character++;
180
+ range.end.character++;
181
+ }
182
+ const qualifier = {
183
+ type: annotation_ast_nodes_1.QUALIFIER_TYPE,
184
+ value: '',
185
+ range: range
186
+ };
187
+ if ((0, utils_1.hasItems)(assignment.Identifier)) {
188
+ if (qualifier.range) {
189
+ qualifier.range.end = this.tokenToRange(assignment.Identifier[0]).end;
190
+ }
191
+ qualifier.value = assignment.Identifier[0].image;
192
+ }
193
+ return qualifier;
194
+ }
195
+ /**
196
+ * Converts given assignment to top level annotation group ast node.
197
+ *
198
+ * @param path First segment of the path is used as group name
199
+ * @param assignment Annotation assignment
200
+ * @param location cst location
201
+ * @returns Annotation group object
202
+ */
203
+ toTopLevelAnnotationPathGroup(path, assignment, location) {
204
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
205
+ const items = ((_c = (_b = (_a = assignment.children.value) === null || _a === void 0 ? void 0 : _a[0].children.struct) === null || _b === void 0 ? void 0 : _b[0].children.assignment) !== null && _c !== void 0 ? _c : []).map((childAssignment, index, childAssignments) => {
206
+ var _a, _b, _c, _d;
207
+ const annotation = this.visit(childAssignment);
208
+ // check for specific situation where current child has no value and separating comma to next child is missing
209
+ // then: current child value is represented by a path and next child path is empty
210
+ const nextChildAssignment = index < childAssignments.length - 1 ? childAssignments[index + 1] : null;
211
+ if (nextChildAssignment &&
212
+ !nextChildAssignment.children.path &&
213
+ nextChildAssignment.children.Colon &&
214
+ nextChildAssignment.children.value &&
215
+ childAssignment.children.value[0].children.path) {
216
+ // current child has no value (separating comma to next child is missing)
217
+ const start = this.tokenToRange(childAssignment.children.Colon[0]).end;
218
+ const end = (_d = (_c = this.locationToRange((_b = (_a = childAssignment.children.value) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.location)) === null || _c === void 0 ? void 0 : _c.start) !== null && _d !== void 0 ? _d : start;
219
+ annotation.value = {
220
+ type: annotation_ast_nodes_1.EMPTY_VALUE_TYPE,
221
+ range: vscode_languageserver_types_1.Range.create(start, end)
222
+ };
223
+ }
224
+ return annotation;
225
+ });
226
+ const commas = this.getCommaToken((_f = (_e = (_d = assignment.children.value) === null || _d === void 0 ? void 0 : _d[0].children) === null || _e === void 0 ? void 0 : _e.struct) === null || _f === void 0 ? void 0 : _f[0].children.Comma);
227
+ const ast = {
228
+ type: annotation_ast_nodes_1.ANNOTATION_GROUP_TYPE,
229
+ name: path.segments[0],
230
+ items: {
231
+ type: annotation_ast_nodes_1.ANNOTATION_GROUP_ITEMS_TYPE,
232
+ items,
233
+ range: this.locationToRange((_h = (_g = assignment.children.value) === null || _g === void 0 ? void 0 : _g[0]) === null || _h === void 0 ? void 0 : _h.location),
234
+ commas
235
+ },
236
+ range: this.locationToRange(location)
237
+ };
238
+ if ((_j = assignment.children.Colon) === null || _j === void 0 ? void 0 : _j.length) {
239
+ ast.colon = {
240
+ type: annotation_ast_nodes_1.TOKEN_TYPE,
241
+ value: assignment.children.Colon[0].image,
242
+ range: this.tokenToRange(assignment.children.Colon[0])
243
+ };
244
+ }
245
+ if ((_l = (_k = assignment.children.value) === null || _k === void 0 ? void 0 : _k[0]) === null || _l === void 0 ? void 0 : _l.children.struct) {
246
+ const struct = assignment.children.value[0].children.struct[0];
247
+ if (existsAndNotRecovered(struct.children.LCurly)) {
248
+ ast.items.openToken = this.createToken(struct.children.LCurly[0]);
249
+ }
250
+ if (existsAndNotRecovered(struct.children.RCurly)) {
251
+ ast.items.closeToken = this.createToken(struct.children.RCurly[0]);
252
+ }
253
+ }
254
+ return ast;
255
+ }
256
+ /**
257
+ * Creates colon token from the given assignment.
258
+ *
259
+ * @param assignment Assignment CST node
260
+ * @returns Colon ast token or undefined if not found
261
+ */
262
+ getColon(assignment) {
263
+ var _a;
264
+ if ((_a = assignment.children.Colon) === null || _a === void 0 ? void 0 : _a.length) {
265
+ return {
266
+ type: annotation_ast_nodes_1.TOKEN_TYPE,
267
+ range: this.tokenToRange(assignment.children.Colon[0]),
268
+ value: assignment.children.Colon[0].image
269
+ };
270
+ }
271
+ return undefined;
272
+ }
273
+ /**
274
+ * Converts given assignment to top level annotation path or annotation group path node.
275
+ *
276
+ * @param assignment Assignment to convert
277
+ * @param location CST location
278
+ * @returns Annotation or annotation group path node
279
+ */
280
+ toTopLevelAnnotationPath(assignment, location) {
281
+ const path = this.visit(assignment.children.path[0]);
282
+ if (path.segments.length !== 1 || (path.segments.length === 1 && !supportedVocabularyAliases.has(path.value))) {
283
+ const ast = {
284
+ type: annotation_ast_nodes_1.ANNOTATION_TYPE,
285
+ term: path,
286
+ range: this.locationToRange(location)
287
+ };
288
+ ast.colon = this.getColon(assignment);
289
+ const qualifier = this.getQualifier(assignment.children);
290
+ if (qualifier) {
291
+ ast.qualifier = qualifier;
292
+ }
293
+ // Flattened qualifier syntax handling
294
+ const qSegment = Math.min(supportedVocabularyAliases.has(path.segments[0].value) ? ast.term.segments.length - 1 : 0, 1);
295
+ if (!ast.qualifier && qSegment >= 0 && ast.term.segments[qSegment].value.includes('#')) {
296
+ ast.qualifier = createQualifier(ast.term);
297
+ }
298
+ if ((0, utils_1.hasItems)(assignment.children.value)) {
299
+ ast.value = this.visit(assignment.children.value[0]);
300
+ }
301
+ return ast;
302
+ }
303
+ else if (path.segments.length === 1 && supportedVocabularyAliases.has(path.value)) {
304
+ return this.toTopLevelAnnotationPathGroup(path, assignment, location);
305
+ }
306
+ return undefined;
307
+ }
308
+ /**
309
+ * Converts given assignment to top level annotation node.
310
+ *
311
+ * @param assignment Assignment to convert
312
+ * @param location CST location
313
+ * @returns Annotation ast node
314
+ */
315
+ toTopLevelAnnotation(assignment, location) {
316
+ var _a;
317
+ if ((0, utils_1.isDefined)(assignment.location) &&
318
+ isNaN(assignment.location.startOffset) &&
319
+ assignment.recoveredNode === true) {
320
+ return undefined;
321
+ }
322
+ if (assignment.children.path) {
323
+ return this.toTopLevelAnnotationPath(assignment, location);
324
+ }
325
+ if (assignment.children.value && assignment.children.Colon && !assignment.children.path) {
326
+ const end = this.tokenToRange(assignment.children.Colon[0]).start;
327
+ const start = (0, utils_1.isDefined)(this.startPosition)
328
+ ? { line: this.startPosition.line, character: this.startPosition.character }
329
+ : end;
330
+ const range = {
331
+ start,
332
+ end
333
+ };
334
+ const ast = {
335
+ type: annotation_ast_nodes_1.ANNOTATION_TYPE,
336
+ term: {
337
+ segments: [],
338
+ separators: [],
339
+ type: 'path',
340
+ value: '',
341
+ range
342
+ },
343
+ range: (0, range_1.copyRange)(range)
344
+ };
345
+ if ((_a = assignment.children.Colon) === null || _a === void 0 ? void 0 : _a.length) {
346
+ ast.colon = {
347
+ type: annotation_ast_nodes_1.TOKEN_TYPE,
348
+ range: this.tokenToRange(assignment.children.Colon[0]),
349
+ value: assignment.children.Colon[0].image
350
+ };
351
+ }
352
+ ast.qualifier = this.getQualifier(assignment.children);
353
+ if ((0, utils_1.hasItems)(assignment.children.value)) {
354
+ ast.value = this.visit(assignment.children.value[0]);
355
+ }
356
+ return ast;
357
+ }
358
+ return undefined;
359
+ }
360
+ /**
361
+ * Creates declaration node.
362
+ *
363
+ * @param context CST decrataion children
364
+ * @param location CST location of the given context
365
+ * @returns Declaration ast node or undefined if no items found in the context
366
+ */
367
+ declaration(context, location) {
368
+ if ((0, utils_1.hasItems)(context.assignment)) {
369
+ return this.toTopLevelAnnotation(context.assignment[0], location);
370
+ }
371
+ return undefined;
372
+ }
373
+ /**
374
+ * Converts number string image to number value.
375
+ *
376
+ * @param image String image of the number
377
+ * @returns Converted number value or the given image itself if conversion couldn't be done
378
+ */
379
+ numberValue(image) {
380
+ const num = Number.parseFloat(image || '0'); // not Number.parseInt() !
381
+ if (Number.isSafeInteger(num) || (!Number.isNaN(num) && Number.isFinite(num))) {
382
+ return num;
383
+ }
384
+ return image;
385
+ }
386
+ /**
387
+ * Converts collection value node.
388
+ *
389
+ * @param context CST collection children
390
+ * @param location CST location
391
+ * @returns Collection annotation value node
392
+ */
393
+ collectionValue(context, location) {
394
+ if (context.extendCollectionValue) {
395
+ return undefined;
396
+ }
397
+ return this.value(context, location);
398
+ }
399
+ /**
400
+ * Converts string value node.
401
+ *
402
+ * @param context CST value children
403
+ * @returns String or multiline string literal or undefined if no item found
404
+ */
405
+ stringValue(context) {
406
+ if ((0, utils_1.hasItems)(context.string)) {
407
+ return this.visit(context.string[0]);
408
+ }
409
+ if ((0, utils_1.hasItems)(context.multiLineStringStripIndent)) {
410
+ return this.visit(context.multiLineStringStripIndent[0]);
411
+ }
412
+ if ((0, utils_1.hasItems)(context.multiLineString)) {
413
+ return this.visit(context.multiLineString[0]);
414
+ }
415
+ return undefined;
416
+ }
417
+ /**
418
+ * Value converter subfunction which calls corresponding visitor for child element (if context permits).
419
+ *
420
+ * @param context Value children CST nodes
421
+ * @returns Object with visitor call result and flag indicating that the visitor call took place
422
+ */
423
+ valueNestedVisitor(context) {
424
+ if ((0, utils_1.hasItems)(context.enum)) {
425
+ return { done: true, result: this.visit(context.enum[0]) };
426
+ }
427
+ if ((0, utils_1.hasItems)(context.struct)) {
428
+ return { done: true, result: this.visit(context.struct[0]) };
429
+ }
430
+ if ((0, utils_1.hasItems)(context.collection)) {
431
+ return { done: true, result: this.visit(context.collection[0]) };
432
+ }
433
+ if ((0, utils_1.hasItems)(context.path)) {
434
+ return { done: true, result: this.visit(context.path[0]) };
435
+ }
436
+ if ((0, utils_1.hasItems)(context.expression)) {
437
+ return { done: true, result: this.visit(context.expression[0]) };
438
+ }
439
+ return { done: false };
440
+ }
441
+ /**
442
+ * Value converter subfunction which converts primitive value (if context permits).
443
+ *
444
+ * @param context Value children CST nodes
445
+ * @param location CST node location
446
+ * @returns Object with result of the conversion and a flag indicating that the conversion took place
447
+ */
448
+ primitiveValueConverter(context, location) {
449
+ if ((0, utils_1.hasItems)(context.string) ||
450
+ (0, utils_1.hasItems)(context.multiLineStringStripIndent) ||
451
+ (0, utils_1.hasItems)(context.multiLineString)) {
452
+ return { done: true, result: this.stringValue(context) };
453
+ }
454
+ if ((0, utils_1.hasItems)(context.Number)) {
455
+ return {
456
+ done: true,
457
+ result: {
458
+ type: annotation_ast_nodes_1.NUMBER_LITERAL_TYPE,
459
+ value: this.numberValue(context.Number[0].image),
460
+ range: this.locationToRange(location)
461
+ }
462
+ };
463
+ }
464
+ if ((0, utils_1.hasItems)(context.False)) {
465
+ return {
466
+ done: true,
467
+ result: {
468
+ type: annotation_ast_nodes_1.BOOLEAN_TYPE,
469
+ value: false,
470
+ range: this.locationToRange(location)
471
+ }
472
+ };
473
+ }
474
+ if ((0, utils_1.hasItems)(context.True)) {
475
+ return {
476
+ done: true,
477
+ result: {
478
+ type: annotation_ast_nodes_1.BOOLEAN_TYPE,
479
+ value: true,
480
+ range: this.locationToRange(location)
481
+ }
482
+ };
483
+ }
484
+ if ((0, utils_1.hasItems)(context.Null)) {
485
+ return {
486
+ done: true,
487
+ result: {
488
+ type: annotation_ast_nodes_1.TOKEN_TYPE,
489
+ value: context.Null[0].image.toLowerCase(),
490
+ range: this.locationToRange(location)
491
+ }
492
+ };
493
+ }
494
+ if ((0, utils_1.hasItems)(context.Binary)) {
495
+ return {
496
+ done: true,
497
+ result: {
498
+ type: annotation_ast_nodes_1.QUOTED_LITERAL_TYPE,
499
+ value: this.getQuotedLiteralValue(context.Binary[0]),
500
+ range: this.locationToRange(location),
501
+ kind: 'binary'
502
+ }
503
+ };
504
+ }
505
+ if ((0, utils_1.hasItems)(context.Date)) {
506
+ return {
507
+ done: true,
508
+ result: {
509
+ type: annotation_ast_nodes_1.QUOTED_LITERAL_TYPE,
510
+ value: this.getQuotedLiteralValue(context.Date[0]),
511
+ range: this.locationToRange(location),
512
+ kind: 'date'
513
+ }
514
+ };
515
+ }
516
+ if ((0, utils_1.hasItems)(context.Time)) {
517
+ return {
518
+ done: true,
519
+ result: {
520
+ type: annotation_ast_nodes_1.QUOTED_LITERAL_TYPE,
521
+ value: this.getQuotedLiteralValue(context.Time[0]),
522
+ range: this.locationToRange(location),
523
+ kind: 'time'
524
+ }
525
+ };
526
+ }
527
+ if ((0, utils_1.hasItems)(context.Timestamp)) {
528
+ return {
529
+ done: true,
530
+ result: {
531
+ type: annotation_ast_nodes_1.QUOTED_LITERAL_TYPE,
532
+ value: this.getQuotedLiteralValue(context.Timestamp[0]),
533
+ range: this.locationToRange(location),
534
+ kind: 'timestamp'
535
+ }
536
+ };
537
+ }
538
+ return { done: false };
539
+ }
540
+ /**
541
+ * Converts value children to value ast node.
542
+ *
543
+ * @param context CST value children
544
+ * @param location CST location
545
+ * @returns annotation value ast node or undefined if no items found
546
+ */
547
+ value(context, location) {
548
+ const nested = this.valueNestedVisitor(context);
549
+ if (nested.done) {
550
+ return nested.result;
551
+ }
552
+ const primitive = this.primitiveValueConverter(context, location);
553
+ if (primitive.done) {
554
+ return primitive.result;
555
+ }
556
+ if (!(0, utils_1.hasNaNOrUndefined)(location.endOffset)) {
557
+ // create empty value
558
+ return {
559
+ type: annotation_ast_nodes_1.EMPTY_VALUE_TYPE,
560
+ range: this.locationToRange(location)
561
+ };
562
+ }
563
+ return undefined;
564
+ }
565
+ /**
566
+ * Converts expression children to expression ast node.
567
+ *
568
+ * @param context CST expression children
569
+ * @param location CST location
570
+ * @returns Expression value ast node
571
+ */
572
+ expression(context, location) {
573
+ var _a, _b;
574
+ /**
575
+ * Builds operator.
576
+ *
577
+ * @param operatorToken Operator CST token
578
+ * @param range Token range
579
+ * @returns Operator node
580
+ */
581
+ function buildOperator(operatorToken, range) {
582
+ const operator = { type: annotation_ast_nodes_1.OPERATOR_TYPE, value: operatorToken.image, range };
583
+ return operator;
584
+ }
585
+ const openToken = existsAndNotRecovered(context.LParen) ? this.createToken(context.LParen[0]) : undefined;
586
+ const closeToken = existsAndNotRecovered(context.RParen) ? this.createToken(context.RParen[0]) : undefined;
587
+ const range = this.locationToRange(location);
588
+ const operators = ((_a = context.Operator) !== null && _a !== void 0 ? _a : []).map((token) => buildOperator(token, this.tokenToRange(token)));
589
+ const operands = ((_b = context.value) !== null && _b !== void 0 ? _b : []).map((token) => this.visit(token));
590
+ const expression = { operators, operands, openToken, closeToken, range };
591
+ const unsupportedOperator = operators.find((operator) => {
592
+ const operatorNames = expressions_1.operatorImageMap[operator.value.toUpperCase()];
593
+ return operatorNames.length && !operatorNames.some((operatorName) => expressions_1.operatorMap[operatorName].edmName);
594
+ });
595
+ if (unsupportedOperator || !range) {
596
+ const type = annotation_ast_nodes_1.UNSUPPORTED_OPERATOR_EXPRESSION_TYPE;
597
+ return Object.assign(Object.assign({}, expression), { type, unsupportedOperator });
598
+ }
599
+ try {
600
+ const protoExpression = (0, expressions_1.rebuildNumberSigns)({ operators, operands, range });
601
+ const expression = (0, expressions_1.buildExpression)(protoExpression);
602
+ if (range) {
603
+ expression.range = range;
604
+ }
605
+ if (openToken) {
606
+ expression.openToken = openToken;
607
+ }
608
+ if (closeToken) {
609
+ expression.closeToken = closeToken;
610
+ }
611
+ return expression;
612
+ }
613
+ catch (e) {
614
+ // expression did not follow grammar rules - return expression with empty operatorName
615
+ return Object.assign(Object.assign({}, expression), { type: annotation_ast_nodes_1.INCORRECT_EXPRESSION_TYPE, message: e.toString() });
616
+ }
617
+ }
618
+ /**
619
+ * Converts enum children to enum ast node.
620
+ *
621
+ * @param context CST enum children
622
+ * @param location CST location
623
+ * @returns Enum value ast node
624
+ */
625
+ enum(context, location) {
626
+ var _a;
627
+ const range = this.locationToRange(location);
628
+ if (range) {
629
+ range.start.character++;
630
+ }
631
+ const path = ((_a = context.path) === null || _a === void 0 ? void 0 : _a.length) === 1
632
+ ? this.visit(context.path[0])
633
+ : {
634
+ type: annotation_ast_nodes_1.PATH_TYPE,
635
+ value: '',
636
+ segments: [],
637
+ separators: [],
638
+ range
639
+ };
640
+ return {
641
+ type: annotation_ast_nodes_1.ENUM_TYPE,
642
+ path,
643
+ range: this.locationToRange(location)
644
+ };
645
+ }
646
+ /**
647
+ * Converts string children to string ast node.
648
+ *
649
+ * @param context CST string children
650
+ * @param location CST location
651
+ * @returns String literal ast node
652
+ */
653
+ string(context, location) {
654
+ var _a;
655
+ const range = this.locationToRange(location);
656
+ const value = ((_a = context.String) === null || _a === void 0 ? void 0 : _a.length) === 1 ? context.String[0].image : '';
657
+ const ast = {
658
+ type: annotation_ast_nodes_1.STRING_LITERAL_TYPE,
659
+ value,
660
+ range
661
+ };
662
+ if (existsAndNotRecovered(context.SingleQuote)) {
663
+ ast.openToken = this.createToken(context.SingleQuote[0]);
664
+ }
665
+ if (existsAndNotRecovered(context.StringExit)) {
666
+ ast.closeToken = this.createToken(context.StringExit[0]);
667
+ }
668
+ return ast;
669
+ }
670
+ /**
671
+ * Converts multi line string children to ast node.
672
+ *
673
+ * @param context CST multi line string children
674
+ * @param location CST location
675
+ * @returns Multi line string literal ast node
676
+ */
677
+ multiLineString(context, location) {
678
+ var _a;
679
+ const range = this.locationToRange(location);
680
+ const value = ((_a = context.MultiLineString) === null || _a === void 0 ? void 0 : _a.length) === 1 ? context.MultiLineString[0].image : '';
681
+ const ast = {
682
+ type: annotation_ast_nodes_1.MULTI_LINE_STRING_LITERAL_TYPE,
683
+ stripIndentation: false,
684
+ value,
685
+ range
686
+ };
687
+ if (existsAndNotRecovered(context.Backtick)) {
688
+ ast.openToken = this.createToken(context.Backtick[0]);
689
+ }
690
+ if (existsAndNotRecovered(context.MultiLineStringExit)) {
691
+ ast.closeToken = this.createToken(context.MultiLineStringExit[0]);
692
+ }
693
+ return ast;
694
+ }
695
+ /**
696
+ * Converts multi line strip indent children to ast node.
697
+ *
698
+ * @param context CST multi line strip indent children
699
+ * @param location CST location
700
+ * @returns Multi line string literal ast node
701
+ */
702
+ multiLineStringStripIndent(context, location) {
703
+ var _a;
704
+ const range = this.locationToRange(location);
705
+ const value = ((_a = context.MultiLineString) === null || _a === void 0 ? void 0 : _a.length) === 1 ? context.MultiLineString[0].image : '';
706
+ const ast = {
707
+ type: annotation_ast_nodes_1.MULTI_LINE_STRING_LITERAL_TYPE,
708
+ stripIndentation: true,
709
+ value,
710
+ range
711
+ };
712
+ if (existsAndNotRecovered(context.TripleBacktick)) {
713
+ ast.openToken = this.createToken(context.TripleBacktick[0]);
714
+ }
715
+ if (existsAndNotRecovered(context.MultiLineStringStripIndentExit)) {
716
+ ast.closeToken = this.createToken(context.MultiLineStringStripIndentExit[0]);
717
+ }
718
+ return ast;
719
+ }
720
+ /**
721
+ * Converts collection children to ast node.
722
+ *
723
+ * @param context CST collection children
724
+ * @param location CST location
725
+ * @returns Collection ast node
726
+ */
727
+ collection(context, location) {
728
+ const range = this.locationToRange(location);
729
+ const commas = this.getCommaToken(context === null || context === void 0 ? void 0 : context.Comma);
730
+ const ast = {
731
+ type: annotation_ast_nodes_1.COLLECTION_TYPE,
732
+ items: (0, utils_1.hasItems)(context.collectionValue)
733
+ ? context.collectionValue
734
+ .map((value) => this.visit(value))
735
+ .filter((item) => item !== undefined)
736
+ : [],
737
+ range,
738
+ commas
739
+ };
740
+ if (existsAndNotRecovered(context.LBracket)) {
741
+ ast.openToken = this.createToken(context.LBracket[0]);
742
+ }
743
+ if (existsAndNotRecovered(context.RBracket)) {
744
+ ast.closeToken = this.createToken(context.RBracket[0]);
745
+ }
746
+ return ast;
747
+ }
748
+ /**
749
+ * Converts cst token to identifier ast node.
750
+ *
751
+ * @param token CST token
752
+ * @param delimiter Quotation delimiter (none by default)
753
+ * @returns Identifier ast node
754
+ */
755
+ tokenToIdentifier(token, delimiter = annotation_ast_nodes_1.Delimiter.none) {
756
+ return {
757
+ type: annotation_ast_nodes_1.IDENTIFIER_TYPE,
758
+ value: token.image,
759
+ range: this.tokenToRange(token),
760
+ quoted: delimiter !== annotation_ast_nodes_1.Delimiter.none
761
+ };
762
+ }
763
+ /**
764
+ * Converts CST token to separator ast node.
765
+ *
766
+ * @param token CST token
767
+ * @param delimiter Escaped value delimiter (none by default)
768
+ * @returns Separator ast node
769
+ */
770
+ tokenToSeparator(token, delimiter = annotation_ast_nodes_1.Delimiter.none) {
771
+ return {
772
+ type: annotation_ast_nodes_1.SEPARATOR_TYPE,
773
+ value: token.image,
774
+ range: this.tokenToRange(token),
775
+ escaped: delimiter !== annotation_ast_nodes_1.Delimiter.none
776
+ };
777
+ }
778
+ /**
779
+ * Tries to recover identifier from one of given separator tokens (adjusts its range).
780
+ *
781
+ * @param identifier Identifier CST token
782
+ * @param index Index of separator token to recover
783
+ * @param separatorTokens Array with separator tokens
784
+ * @returns Recovered from separator identifier or original identifier
785
+ */
786
+ recoverIdentifiers(identifier, index, separatorTokens = []) {
787
+ const separator = separatorTokens[index - 1];
788
+ const fromErrorRecovery = identifier.isInsertedInRecovery && separator
789
+ ? // Adjust range so it is the next character after dot
790
+ this.identifierFromSeparatorToken(separator)
791
+ : undefined;
792
+ if (fromErrorRecovery) {
793
+ return fromErrorRecovery;
794
+ }
795
+ return identifier;
796
+ }
797
+ /**
798
+ * Converts separator CST token to identifier cst token.
799
+ *
800
+ * @param token Separator token
801
+ * @returns Identifier CST token with empty image nd adjusted range
802
+ */
803
+ identifierFromSeparatorToken(token) {
804
+ var _a, _b;
805
+ // Adjust range so it is the next character after separator
806
+ return {
807
+ image: '',
808
+ startOffset: token.startOffset + 1,
809
+ startLine: token.startLine,
810
+ startColumn: ((_a = token.startColumn) !== null && _a !== void 0 ? _a : 0) + 1,
811
+ endOffset: token.endOffset,
812
+ endLine: token.endLine,
813
+ endColumn: token.endColumn,
814
+ tokenType: tokens_1.tokenMap.Identifier,
815
+ isInsertedInRecovery: true,
816
+ tokenTypeIdx: (_b = tokens_1.tokenMap.Identifier.tokenTypeIdx) !== null && _b !== void 0 ? _b : -1
817
+ };
818
+ }
819
+ /**
820
+ * Creates empty identifier st token.
821
+ *
822
+ * @param start Start CST token
823
+ * @param end End CST token
824
+ * @returns Empty identifier CST token
825
+ */
826
+ createEmptyIdentifier(start, end) {
827
+ var _a, _b, _c, _d;
828
+ return {
829
+ image: '',
830
+ startOffset: ((_a = start.endOffset) !== null && _a !== void 0 ? _a : 0) + 1,
831
+ startLine: start.endLine,
832
+ startColumn: ((_b = start.endColumn) !== null && _b !== void 0 ? _b : 0) + 1,
833
+ endOffset: end.startOffset - 1,
834
+ endLine: end.startLine,
835
+ endColumn: ((_c = end.startColumn) !== null && _c !== void 0 ? _c : 0) - 1,
836
+ tokenType: tokens_1.tokenMap.Identifier,
837
+ isInsertedInRecovery: true,
838
+ tokenTypeIdx: (_d = tokens_1.tokenMap.Identifier.tokenTypeIdx) !== null && _d !== void 0 ? _d : -1
839
+ };
840
+ }
841
+ /**
842
+ * Extacts identifier tokens and delimiters from the given path segment cst node.
843
+ *
844
+ * @param segment Path segment node
845
+ * @returns Array of objects consisting of identifier token and delimiter
846
+ */
847
+ getIdentifierToken(segment) {
848
+ var _a;
849
+ if ((0, utils_1.hasItems)(segment.children.NumberSign)) {
850
+ if ((0, utils_1.hasItems)(segment.children.Identifier)) {
851
+ segment.children.Identifier[0].image += '#';
852
+ }
853
+ if ((0, utils_1.hasItems)(segment.children.Identifier) && segment.children.Identifier.length > 1) {
854
+ segment.children.Identifier[0].image += segment.children.Identifier[1].image;
855
+ segment = this.setNewRangeForIdentifier(segment, 1, 'Identifier');
856
+ }
857
+ else {
858
+ segment = this.setNewRangeForIdentifier(segment, 0, 'NumberSign');
859
+ }
860
+ if ((0, utils_1.hasItems)(segment.children.Identifier)) {
861
+ return [
862
+ {
863
+ token: segment.children.Identifier[0],
864
+ delimiter: annotation_ast_nodes_1.Delimiter.none
865
+ }
866
+ ];
867
+ }
868
+ }
869
+ else if ((0, utils_1.hasItems)(segment.children.Identifier, 2)) {
870
+ if (segment.children.Identifier[1].tokenTypeIdx === tokens_1.tokenMap.TermCastIdentifier.tokenTypeIdx) {
871
+ segment.children.Identifier[0].image += segment.children.Identifier[1].image;
872
+ segment = this.setNewRangeForIdentifier(segment, 1, 'Identifier');
873
+ }
874
+ if ((0, utils_1.hasItems)(segment.children.Identifier)) {
875
+ return [
876
+ {
877
+ token: segment.children.Identifier[0],
878
+ delimiter: annotation_ast_nodes_1.Delimiter.none
879
+ }
880
+ ];
881
+ }
882
+ }
883
+ return ((_a = segment.children.Identifier) !== null && _a !== void 0 ? _a : []).map((token) => ({
884
+ token,
885
+ delimiter: annotation_ast_nodes_1.Delimiter.none
886
+ }));
887
+ }
888
+ /**
889
+ * Sets new range end for the identifier in the given path segment.
890
+ *
891
+ * @param segment Path segment CST node
892
+ * @param index Index of an element within child grop to take range data from
893
+ * @param key Key of the children group
894
+ * @returns Updated path segment node
895
+ */
896
+ setNewRangeForIdentifier(segment, index, key) {
897
+ var _a, _b, _c;
898
+ if ((0, utils_1.hasItems)(segment.children.Identifier)) {
899
+ segment.children.Identifier[0].endColumn = (_a = segment.children[key]) === null || _a === void 0 ? void 0 : _a[index].endColumn;
900
+ segment.children.Identifier[0].endLine = (_b = segment.children[key]) === null || _b === void 0 ? void 0 : _b[index].endLine;
901
+ segment.children.Identifier[0].endOffset = (_c = segment.children[key]) === null || _c === void 0 ? void 0 : _c[index].endOffset;
902
+ }
903
+ return segment;
904
+ }
905
+ /**
906
+ * Joins segment identifiers by given separators.
907
+ *
908
+ * @param segments Array with identifier tokens
909
+ * @param separators Array with separator tokens
910
+ * @returns String result
911
+ */
912
+ joinSegments(segments, separators) {
913
+ let value = '';
914
+ const remainingSeparators = [...separators];
915
+ for (const segment of segments) {
916
+ value += segment.value;
917
+ const separator = remainingSeparators.shift();
918
+ if (separator) {
919
+ value += separator.value;
920
+ }
921
+ }
922
+ return value;
923
+ }
924
+ /**
925
+ * Converts path children to path ast node.
926
+ *
927
+ * @param context Path node children
928
+ * @param location CST location
929
+ * @returns Path AST node
930
+ */
931
+ path(context, location) {
932
+ var _a, _b, _c;
933
+ const segments = ((_a = context.pathSegment) !== null && _a !== void 0 ? _a : [])
934
+ .map((segment, i) => {
935
+ var _a, _b, _c, _d, _e;
936
+ const quotedIdentifiers = (_b = (_a = segment.children.quotedIdentifier) === null || _a === void 0 ? void 0 : _a.reduce((acc, quotedIdentifier) => {
937
+ return [
938
+ ...acc,
939
+ ...(quotedIdentifier.children.QuotedIdentifier || []).map((token, j) => {
940
+ var _a;
941
+ return ({
942
+ token: this.recoverIdentifiers(token, j, (_a = quotedIdentifier.children.PathSegmentSeparator) !== null && _a !== void 0 ? _a : []),
943
+ delimiter: annotation_ast_nodes_1.Delimiter.quoted
944
+ });
945
+ })
946
+ ];
947
+ }, [])) !== null && _b !== void 0 ? _b : [];
948
+ const delimitedIdentifiers = ((_d = (_c = segment.children.delimitedIdentifier) === null || _c === void 0 ? void 0 : _c.reduce((acc, delimitedIdentifier) => {
949
+ if (!delimitedIdentifier.children.DelimitedIdentifier) {
950
+ return [
951
+ ...acc,
952
+ {
953
+ token: this.createEmptyIdentifier(delimitedIdentifier.children.IdentifierStart[0], delimitedIdentifier.children.DelimitedIdentifierExit[0]),
954
+ delimiter: annotation_ast_nodes_1.Delimiter.exclamationSquareBrackets
955
+ }
956
+ ];
957
+ }
958
+ return [
959
+ ...acc,
960
+ ...(delimitedIdentifier.children.DelimitedIdentifier || []).map((token, j) => {
961
+ var _a;
962
+ return ({
963
+ token: this.recoverIdentifiers(token, j, (_a = delimitedIdentifier.children.PathSegmentSeparator) !== null && _a !== void 0 ? _a : []),
964
+ delimiter: annotation_ast_nodes_1.Delimiter.exclamationSquareBrackets
965
+ });
966
+ })
967
+ ];
968
+ }, [])) !== null && _d !== void 0 ? _d : []).map((identifier) => identifier);
969
+ const separator = ((_e = context.PathSegmentSeparator) !== null && _e !== void 0 ? _e : [])[i - 1];
970
+ const fromErrorRecovery = segment.recoveredNode && separator
971
+ ? [{ token: this.identifierFromSeparatorToken(separator), delimiter: annotation_ast_nodes_1.Delimiter.none }]
972
+ : [];
973
+ const identifiers = this.getIdentifierToken(segment);
974
+ return [...identifiers, ...quotedIdentifiers, ...delimitedIdentifiers, ...fromErrorRecovery];
975
+ })
976
+ .reduce((acc, allSegments) => [...acc, ...allSegments], [])
977
+ .sort((a, b) => compareTokensByPosition(a.token, b.token))
978
+ .map(({ token, delimiter }) => this.tokenToIdentifier(token, delimiter));
979
+ const separators = [
980
+ ...((_b = context.pathSegment) !== null && _b !== void 0 ? _b : []).map((segment) => {
981
+ var _a, _b, _c, _d;
982
+ const quotedIdentifiers = (_b = (_a = segment.children.quotedIdentifier) === null || _a === void 0 ? void 0 : _a.reduce((acc, quotedIdentifier) => {
983
+ var _a;
984
+ const childrenSeparators = (_a = quotedIdentifier.children.PathSegmentSeparator) !== null && _a !== void 0 ? _a : [];
985
+ return [
986
+ ...acc,
987
+ ...childrenSeparators.map((token) => ({
988
+ token,
989
+ delimiter: annotation_ast_nodes_1.Delimiter.quoted
990
+ }))
991
+ ];
992
+ }, [])) !== null && _b !== void 0 ? _b : [];
993
+ const delimitedIdentifiers = (_d = (_c = segment.children.delimitedIdentifier) === null || _c === void 0 ? void 0 : _c.reduce((acc, delimitedIdentifier) => {
994
+ var _a;
995
+ if (!delimitedIdentifier.children.DelimitedIdentifier) {
996
+ return [
997
+ ...acc,
998
+ {
999
+ token: this.createEmptyIdentifier(delimitedIdentifier.children.IdentifierStart[0], delimitedIdentifier.children.DelimitedIdentifierExit[0]),
1000
+ delimiter: annotation_ast_nodes_1.Delimiter.exclamationSquareBrackets
1001
+ }
1002
+ ];
1003
+ }
1004
+ const childrenSeparators = (_a = delimitedIdentifier.children.PathSegmentSeparator) !== null && _a !== void 0 ? _a : [];
1005
+ return [
1006
+ ...acc,
1007
+ ...childrenSeparators.map((token) => ({
1008
+ token,
1009
+ delimiter: annotation_ast_nodes_1.Delimiter.exclamationSquareBrackets
1010
+ }))
1011
+ ];
1012
+ }, [])) !== null && _d !== void 0 ? _d : [];
1013
+ return [...quotedIdentifiers, ...delimitedIdentifiers];
1014
+ }),
1015
+ ((_c = context.PathSegmentSeparator) !== null && _c !== void 0 ? _c : []).map((token) => ({
1016
+ token,
1017
+ delimiter: annotation_ast_nodes_1.Delimiter.none
1018
+ }))
1019
+ ]
1020
+ .reduce((acc, allSegments) => [...acc, ...allSegments], [])
1021
+ .sort((a, b) => compareTokensByPosition(a.token, b.token))
1022
+ .map(({ token, delimiter }) => this.tokenToSeparator(token, delimiter));
1023
+ const range = this.locationToRange(location);
1024
+ return {
1025
+ type: annotation_ast_nodes_1.PATH_TYPE,
1026
+ value: this.joinSegments(segments, separators),
1027
+ segments,
1028
+ separators,
1029
+ range
1030
+ };
1031
+ }
1032
+ /**
1033
+ * Extracts record property or embedded annotation from given record assignment.
1034
+ *
1035
+ * @param assignment Record assignment
1036
+ * @returns Property data
1037
+ */
1038
+ getRecordProperty(assignment) {
1039
+ const assignmentRange = this.locationToRange(assignment.location);
1040
+ const name = this.getAssignmentKey(assignment.children, assignmentRange);
1041
+ let property;
1042
+ if (name.value.startsWith('@')) {
1043
+ property = {
1044
+ type: annotation_ast_nodes_1.ANNOTATION_TYPE,
1045
+ term: name,
1046
+ value: (0, utils_1.hasItems)(assignment.children.value)
1047
+ ? this.visit(assignment.children.value[0])
1048
+ : undefined,
1049
+ range: assignmentRange
1050
+ };
1051
+ if (name.segments.length > 1 && name.segments[1].value.includes('#')) {
1052
+ property.qualifier = createQualifier(name);
1053
+ property.term.value = name.value.split('#')[0];
1054
+ }
1055
+ else if ((0, utils_1.hasItems)(assignment.children.NumberSign)) {
1056
+ property.qualifier = this.getQualifier(assignment.children);
1057
+ }
1058
+ return { property, kind: 'annotation' };
1059
+ }
1060
+ property = {
1061
+ type: annotation_ast_nodes_1.RECORD_PROPERTY_TYPE,
1062
+ name,
1063
+ value: (0, utils_1.hasItems)(assignment.children.value)
1064
+ ? this.visit(assignment.children.value[0])
1065
+ : undefined,
1066
+ range: assignmentRange
1067
+ };
1068
+ return { property, kind: 'property' };
1069
+ }
1070
+ /**
1071
+ * Converts structure children to ast record node.
1072
+ *
1073
+ * @param context CST structure children
1074
+ * @param location CST location
1075
+ * @returns AST record node
1076
+ */
1077
+ struct(context, location) {
1078
+ var _a;
1079
+ const range = this.locationToRange(location);
1080
+ const { properties: allProperties, annotations: allAnnotations } = ((_a = context.assignment) !== null && _a !== void 0 ? _a : [])
1081
+ .filter((assignment) => {
1082
+ return (0, utils_1.hasItems)(assignment.children.path) || (0, utils_1.hasItems)(assignment.children.value);
1083
+ })
1084
+ .reduce(({ annotations, properties }, assignment, assignmentIndex, assignments) => {
1085
+ var _a, _b, _c, _d, _e, _f, _g, _h;
1086
+ const { property, kind } = this.getRecordProperty(assignment);
1087
+ if (kind === 'annotation') {
1088
+ annotations.push(property);
1089
+ }
1090
+ else {
1091
+ properties.push(property);
1092
+ }
1093
+ if ((0, utils_1.hasItems)(assignment.children.Colon) &&
1094
+ (!(0, utils_1.hasItems)(assignment.children.value) ||
1095
+ (0, utils_1.hasNaNOrUndefined)((_b = (_a = assignment.children.value[0]) === null || _a === void 0 ? void 0 : _a.location) === null || _b === void 0 ? void 0 : _b.startOffset))) {
1096
+ this.recoverFromMissingValue(assignment.children.Colon[0], property);
1097
+ }
1098
+ else if (((_c = assignment.children) === null || _c === void 0 ? void 0 : _c.value) &&
1099
+ ((_d = assignment.children) === null || _d === void 0 ? void 0 : _d.value.length) &&
1100
+ ((_f = (_e = assignment.children.value[0]) === null || _e === void 0 ? void 0 : _e.children) === null || _f === void 0 ? void 0 : _f.path) &&
1101
+ assignments[assignmentIndex + 1] &&
1102
+ !((_g = assignments[assignmentIndex + 1].children) === null || _g === void 0 ? void 0 : _g.path)) {
1103
+ // missing value and comma: path for next property has been wrongly consumed as value for current property
1104
+ const start = this.tokenToRange(assignment.children.Colon[0]).end;
1105
+ const end = (_h = this.locationToRange(assignment.children.value[0].location)) === null || _h === void 0 ? void 0 : _h.start;
1106
+ property.value = {
1107
+ type: annotation_ast_nodes_1.EMPTY_VALUE_TYPE,
1108
+ range: vscode_languageserver_types_1.Range.create(start, end !== null && end !== void 0 ? end : start)
1109
+ };
1110
+ }
1111
+ property.colon = this.getColon(assignment);
1112
+ return { properties, annotations };
1113
+ }, { annotations: [], properties: [] });
1114
+ const commas = this.getCommaToken(context === null || context === void 0 ? void 0 : context.Comma);
1115
+ const ast = {
1116
+ type: annotation_ast_nodes_1.RECORD_TYPE,
1117
+ properties: allProperties,
1118
+ range,
1119
+ commas
1120
+ };
1121
+ if (allAnnotations.length) {
1122
+ ast.annotations = allAnnotations;
1123
+ }
1124
+ if (existsAndNotRecovered(context.LCurly)) {
1125
+ ast.openToken = this.createToken(context.LCurly[0]);
1126
+ }
1127
+ if (existsAndNotRecovered(context.RCurly)) {
1128
+ ast.closeToken = this.createToken(context.RCurly[0]);
1129
+ }
1130
+ return ast;
1131
+ }
1132
+ /**
1133
+ * Converts annotation assignment children to annotation ast node.
1134
+ *
1135
+ * @param context CST annotation assignment children
1136
+ * @param location CST location
1137
+ * @returns Annotation AST node
1138
+ */
1139
+ assignment(context, location) {
1140
+ var _a, _b, _c;
1141
+ const range = this.locationToRange(location);
1142
+ const ast = {
1143
+ type: annotation_ast_nodes_1.ANNOTATION_TYPE,
1144
+ term: this.getAssignmentKey(context, range),
1145
+ range
1146
+ };
1147
+ if ((_a = context.Colon) === null || _a === void 0 ? void 0 : _a.length) {
1148
+ ast.colon = {
1149
+ type: annotation_ast_nodes_1.TOKEN_TYPE,
1150
+ value: context.Colon[0].image,
1151
+ range: this.tokenToRange(context.Colon[0])
1152
+ };
1153
+ }
1154
+ if ((0, utils_1.hasItems)(context.NumberSign)) {
1155
+ ast.qualifier = this.getQualifier(context);
1156
+ }
1157
+ // Flattened qualifier syntax handling
1158
+ if (!ast.qualifier && ast.term.segments.length && ast.term.segments[0].value.includes('#')) {
1159
+ ast.qualifier = createQualifier(ast.term);
1160
+ }
1161
+ if ((0, utils_1.hasItems)(context.value) && !(0, utils_1.hasNaNOrUndefined)((_c = (_b = context.value[0]) === null || _b === void 0 ? void 0 : _b.location) === null || _c === void 0 ? void 0 : _c.startOffset)) {
1162
+ ast.value = this.visit(context.value[0]);
1163
+ }
1164
+ else if ((0, utils_1.hasItems)(context.Colon)) {
1165
+ this.recoverFromMissingValue(context.Colon[0], ast);
1166
+ }
1167
+ return ast;
1168
+ }
1169
+ /**
1170
+ * Extracts assignment key.
1171
+ *
1172
+ * @param context CST assignment children
1173
+ * @param range CST range
1174
+ * @returns Empty path AST node
1175
+ */
1176
+ getAssignmentKey(context, range) {
1177
+ if ((0, utils_1.hasItems)(context.path)) {
1178
+ return this.visit(context.path[0]);
1179
+ }
1180
+ const end = (0, utils_1.hasItems)(context.NumberSign)
1181
+ ? this.tokenToRange(context.NumberSign[0]).start
1182
+ : this.tokenToRange(context.Colon[0]).start;
1183
+ const start = range ? (0, range_1.copyPosition)(range.start) : end;
1184
+ return {
1185
+ type: annotation_ast_nodes_1.PATH_TYPE,
1186
+ segments: [],
1187
+ separators: [],
1188
+ value: '',
1189
+ range: vscode_languageserver_types_1.Range.create(start, end)
1190
+ };
1191
+ }
1192
+ /**
1193
+ * Recovers annotation or record property node when value is missng - sets up an empty value.
1194
+ *
1195
+ * @param colonToken Colon cst token
1196
+ * @param ast Annotation or property ast node
1197
+ */
1198
+ recoverFromMissingValue(colonToken, ast) {
1199
+ // adjust range
1200
+ const nextToken = findNextToken(this.tokenVector, colonToken.endOffset);
1201
+ if (((nextToken === null || nextToken === void 0 ? void 0 : nextToken.image) === ',' || (nextToken === null || nextToken === void 0 ? void 0 : nextToken.image) === '}') && (nextToken === null || nextToken === void 0 ? void 0 : nextToken.startColumn)) {
1202
+ if (ast.range) {
1203
+ // annotation range should end before comma
1204
+ ast.range.end = this.tokenToRange(nextToken).start;
1205
+ }
1206
+ // Error recovery, insert PATH node
1207
+ const colonRange = this.tokenToRange(colonToken);
1208
+ const nextTokenRange = this.tokenToRange(nextToken);
1209
+ ast.value = {
1210
+ type: annotation_ast_nodes_1.EMPTY_VALUE_TYPE,
1211
+ range: vscode_languageserver_types_1.Range.create(colonRange.end, nextTokenRange.start)
1212
+ };
1213
+ }
1214
+ }
1215
+ }
1216
+ const AstBuilder = new CstToAstVisitor();
1217
+ const buildAst = (cst, tokenVector, startPosition) => {
1218
+ AstBuilder.tokenVector = tokenVector;
1219
+ AstBuilder.startPosition = startPosition;
1220
+ const root = AstBuilder.visit(cst);
1221
+ if (root && (root.type === annotation_ast_nodes_1.ANNOTATION_TYPE || root.type === annotation_ast_nodes_1.ANNOTATION_GROUP_TYPE)) {
1222
+ return root;
1223
+ }
1224
+ return undefined;
1225
+ };
1226
+ exports.buildAst = buildAst;
1227
+ //# sourceMappingURL=ast.js.map