@sap/cds-compiler 2.12.0 → 2.15.2

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 (128) hide show
  1. package/CHANGELOG.md +221 -15
  2. package/bin/cdsc.js +125 -50
  3. package/bin/cdsse.js +2 -2
  4. package/doc/CHANGELOG_BETA.md +13 -6
  5. package/doc/CHANGELOG_DEPRECATED.md +22 -6
  6. package/doc/NameResolution.md +21 -16
  7. package/lib/api/main.js +47 -84
  8. package/lib/api/options.js +5 -6
  9. package/lib/api/validate.js +6 -11
  10. package/lib/backends.js +15 -23
  11. package/lib/base/dictionaries.js +0 -8
  12. package/lib/base/error.js +26 -0
  13. package/lib/base/keywords.js +7 -17
  14. package/lib/base/location.js +9 -4
  15. package/lib/base/message-registry.js +114 -18
  16. package/lib/base/messages.js +101 -90
  17. package/lib/base/model.js +2 -63
  18. package/lib/base/optionProcessorHelper.js +177 -123
  19. package/lib/checks/annotationsOData.js +12 -33
  20. package/lib/checks/arrayOfs.js +1 -34
  21. package/lib/checks/cdsPersistence.js +2 -1
  22. package/lib/checks/enricher.js +17 -1
  23. package/lib/checks/invalidTarget.js +3 -1
  24. package/lib/checks/managedWithoutKeys.js +3 -1
  25. package/lib/checks/selectItems.js +4 -4
  26. package/lib/checks/sql-snippets.js +27 -26
  27. package/lib/checks/types.js +1 -1
  28. package/lib/checks/validator.js +6 -11
  29. package/lib/compiler/assert-consistency.js +6 -3
  30. package/lib/compiler/base.js +1 -0
  31. package/lib/compiler/builtins.js +19 -6
  32. package/lib/compiler/checks.js +23 -60
  33. package/lib/compiler/cycle-detector.js +1 -1
  34. package/lib/compiler/define.js +1151 -0
  35. package/lib/compiler/extend.js +1000 -0
  36. package/lib/compiler/finalize-parse-cdl.js +237 -0
  37. package/lib/compiler/index.js +107 -39
  38. package/lib/compiler/kick-start.js +190 -0
  39. package/lib/compiler/moduleLayers.js +4 -4
  40. package/lib/compiler/populate.js +1227 -0
  41. package/lib/compiler/propagator.js +114 -46
  42. package/lib/compiler/resolve.js +1521 -0
  43. package/lib/compiler/shared.js +126 -65
  44. package/lib/compiler/tweak-assocs.js +535 -0
  45. package/lib/compiler/utils.js +197 -33
  46. package/lib/edm/.eslintrc.json +5 -0
  47. package/lib/edm/annotations/genericTranslation.js +38 -24
  48. package/lib/edm/annotations/preprocessAnnotations.js +2 -2
  49. package/lib/edm/csn2edm.js +219 -100
  50. package/lib/edm/edm.js +302 -230
  51. package/lib/edm/edmPreprocessor.js +554 -419
  52. package/lib/edm/edmUtils.js +138 -44
  53. package/lib/gen/Dictionary.json +100 -19
  54. package/lib/gen/language.checksum +1 -1
  55. package/lib/gen/language.interp +11 -1
  56. package/lib/gen/language.tokens +86 -83
  57. package/lib/gen/languageLexer.interp +10 -1
  58. package/lib/gen/languageLexer.js +860 -833
  59. package/lib/gen/languageLexer.tokens +78 -75
  60. package/lib/gen/languageParser.js +5765 -4480
  61. package/lib/json/csnVersion.js +10 -11
  62. package/lib/json/from-csn.js +15 -3
  63. package/lib/json/to-csn.js +126 -68
  64. package/lib/language/docCommentParser.js +4 -4
  65. package/lib/language/genericAntlrParser.js +123 -5
  66. package/lib/language/language.g4 +355 -156
  67. package/lib/language/multiLineStringParser.js +5 -5
  68. package/lib/main.d.ts +486 -59
  69. package/lib/main.js +41 -9
  70. package/lib/model/api.js +3 -1
  71. package/lib/model/csnRefs.js +252 -156
  72. package/lib/model/csnUtils.js +384 -297
  73. package/lib/model/enrichCsn.js +71 -29
  74. package/lib/model/revealInternalProperties.js +29 -8
  75. package/lib/model/sortViews.js +2 -1
  76. package/lib/modelCompare/compare.js +23 -18
  77. package/lib/optionProcessor.js +63 -26
  78. package/lib/render/manageConstraints.js +35 -32
  79. package/lib/render/toCdl.js +897 -947
  80. package/lib/render/toHdbcds.js +205 -257
  81. package/lib/render/toSql.js +264 -225
  82. package/lib/render/utils/common.js +136 -25
  83. package/lib/render/utils/sql.js +4 -3
  84. package/lib/render/utils/stringEscapes.js +111 -0
  85. package/lib/sql-identifier.js +1 -1
  86. package/lib/transform/.eslintrc.json +5 -0
  87. package/lib/transform/db/.eslintrc.json +3 -1
  88. package/lib/transform/db/applyTransformations.js +35 -12
  89. package/lib/transform/db/assertUnique.js +1 -1
  90. package/lib/transform/db/associations.js +104 -306
  91. package/lib/transform/db/cdsPersistence.js +2 -2
  92. package/lib/transform/db/constraints.js +58 -53
  93. package/lib/transform/db/expansion.js +60 -33
  94. package/lib/transform/db/flattening.js +582 -104
  95. package/lib/transform/db/groupByOrderBy.js +3 -1
  96. package/lib/transform/db/transformExists.js +66 -13
  97. package/lib/transform/db/views.js +11 -7
  98. package/lib/transform/draft/.eslintrc.json +38 -0
  99. package/lib/transform/{db/draft.js → draft/db.js} +6 -5
  100. package/lib/transform/draft/odata.js +227 -0
  101. package/lib/transform/forHanaNew.js +109 -208
  102. package/lib/transform/forOdataNew.js +59 -212
  103. package/lib/transform/localized.js +46 -26
  104. package/lib/transform/odata/toFinalBaseType.js +85 -11
  105. package/lib/transform/odata/typesExposure.js +147 -199
  106. package/lib/transform/odata/utils.js +2 -2
  107. package/lib/transform/transformUtilsNew.js +44 -33
  108. package/lib/transform/translateAssocsToJoins.js +3 -20
  109. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  110. package/lib/transform/universalCsn/coreComputed.js +172 -0
  111. package/lib/transform/universalCsn/universalCsnEnricher.js +737 -0
  112. package/lib/transform/universalCsn/utils.js +63 -0
  113. package/lib/utils/moduleResolve.js +13 -6
  114. package/lib/utils/objectUtils.js +30 -0
  115. package/package.json +1 -1
  116. package/share/messages/README.md +26 -0
  117. package/share/messages/message-explanations.json +2 -1
  118. package/share/messages/syntax-expected-integer.md +37 -0
  119. package/lib/compiler/definer.js +0 -2361
  120. package/lib/compiler/resolver.js +0 -3079
  121. package/lib/transform/odata/attachPath.js +0 -96
  122. package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
  123. package/lib/transform/odata/generateForeignKeyElements.js +0 -261
  124. package/lib/transform/odata/referenceFlattener.js +0 -290
  125. package/lib/transform/odata/sortByAssociationDependency.js +0 -105
  126. package/lib/transform/odata/structuralPath.js +0 -72
  127. package/lib/transform/odata/structureFlattener.js +0 -171
  128. package/lib/transform/universalCsnEnricher.js +0 -237
@@ -6,6 +6,8 @@
6
6
  // Please do not add functions “for completeness”, this is not an API file for
7
7
  // others but only by the core compiler.
8
8
 
9
+ // TODO: probably split this file into utils/….js
10
+
9
11
  'use strict';
10
12
 
11
13
  const { dictAdd, pushToDict } = require('../base/dictionaries');
@@ -31,6 +33,8 @@ function annotationIsFalse( anno ) { // falsy, but not null (u
31
33
  }
32
34
 
33
35
  /**
36
+ * Set compiler-calculated annotation value.
37
+ *
34
38
  * @param {XSN.Artifact} art
35
39
  * @param {string} anno
36
40
  * @param {XSN.Location} [location]
@@ -44,11 +48,11 @@ function annotateWith( art, anno, location = art.location, val = true, literal =
44
48
  name: { path: [ { id: anno.slice(1), location } ], location },
45
49
  val,
46
50
  literal,
51
+ $inferred: '$generated',
47
52
  location,
48
53
  };
49
54
  }
50
55
 
51
- // TODO: define setLink() like the current setProp(), we might have setArtifactLink()
52
56
  // Do not share this function with CSN processors!
53
57
 
54
58
  // The link (_artifact,_effectiveType,...) usually has the artifact as value.
@@ -57,28 +61,13 @@ function annotateWith( art, anno, location = art.location, val = true, literal =
57
61
  // - null: no valid reference, param:true if that is not allowed
58
62
  // - false (only complete ref): multiple definitions, rejected
59
63
  // - 0 (for _effectiveType only): circular reference
60
- function setLink( obj, value = null, prop = '_artifact' ) {
64
+ function setLink( obj, prop, value ) {
61
65
  Object.defineProperty( obj, prop, { value, configurable: true, writable: true } );
62
66
  return value;
63
67
  }
64
-
65
- /**
66
- * Like `obj.prop = value`, but not contained in JSON / CSN
67
- * It's important to set enumerable explicitly to false (although 'false' is the default),
68
- * as else, if the property already exists, it keeps the old setting for enumerable.
69
- *
70
- * @param {object} obj
71
- * @param {string} prop
72
- * @param {any} value
73
- */
74
- function setProp(obj, prop, value) {
75
- const descriptor = {
76
- value,
77
- configurable: true,
78
- writable: true,
79
- enumerable: false,
80
- };
81
- Object.defineProperty( obj, prop, descriptor );
68
+ // And a variant with the most common `prop`:
69
+ function setArtifactLink( obj, value ) {
70
+ Object.defineProperty( obj, '_artifact', { value, configurable: true, writable: true } );
82
71
  return value;
83
72
  }
84
73
 
@@ -92,7 +81,7 @@ function linkToOrigin( origin, name, parent, prop, location, silentDep ) {
92
81
  elem.name.$inferred = origin.name.$inferred;
93
82
  if (parent)
94
83
  setMemberParent( elem, name, parent, prop ); // TODO: redef in template
95
- setProp( elem, '_origin', origin );
84
+ setLink( elem, '_origin', origin );
96
85
  // TODO: should we use silent dependencies also for other things, like
97
86
  // included elements? (Currently for $inferred: 'expand-element' only)
98
87
  if (silentDep)
@@ -110,20 +99,21 @@ function setMemberParent( elem, name, parent, prop ) {
110
99
  p[prop] = Object.create(null);
111
100
  dictAdd( p[prop], name, elem );
112
101
  }
113
- if (parent._outer)
102
+ if (parent._outer && parent._outer.items) // TODO: remove for items, too
114
103
  parent = parent._outer;
115
- setProp( elem, '_parent', parent );
116
- setProp( elem, '_main', parent._main || parent );
117
- elem.name.absolute = elem._main.name.absolute;
104
+ setLink( elem, '_parent', parent );
105
+ setLink( elem, '_main', parent._main || parent );
106
+ const parentName = parent.name || parent._outer.name;
107
+ elem.name.absolute = parentName.absolute;
118
108
  if (name == null)
119
109
  return;
120
110
  const normalized = kindProperties[elem.kind].normalized || elem.kind;
121
111
  [ 'element', 'alias', 'select', 'param', 'action' ].forEach( ( kind ) => {
122
112
  if (normalized === kind)
123
- elem.name[kind] = (parent.name[kind] != null && kind !== 'select' && kind !== 'alias') ? `${ parent.name[kind] }.${ name }` : name;
113
+ elem.name[kind] = (parentName[kind] != null && kind !== 'select' && kind !== 'alias') ? `${ parentName[kind] }.${ name }` : name;
124
114
 
125
- else if (parent.name[kind] != null)
126
- elem.name[kind] = parent.name[kind];
115
+ else if (parentName[kind] != null)
116
+ elem.name[kind] = parentName[kind];
127
117
 
128
118
  else
129
119
  delete elem.name[kind];
@@ -140,7 +130,7 @@ function setMemberParent( elem, name, parent, prop ) {
140
130
  */
141
131
  function dependsOn( user, art, location ) {
142
132
  if (!user._deps)
143
- setProp( user, '_deps', [] );
133
+ setLink( user, '_deps', [] );
144
134
  user._deps.push( { art, location } );
145
135
  }
146
136
 
@@ -153,17 +143,17 @@ function dependsOn( user, art, location ) {
153
143
  */
154
144
  function dependsOnSilent( user, art ) {
155
145
  if (!user._deps)
156
- setProp( user, '_deps', [] );
146
+ setLink( user, '_deps', [] );
157
147
  user._deps.push( { art } );
158
148
  }
159
149
 
160
150
  function storeExtension( elem, name, prop, parent, block ) {
161
151
  if (prop === 'enum')
162
152
  prop = 'elements';
163
- setProp( elem, '_block', block );
153
+ setLink( elem, '_block', block );
164
154
  const kind = `_${ elem.kind }`; // _extend or _annotate
165
155
  if (!parent[kind])
166
- setProp( parent, kind, {} );
156
+ setLink( parent, kind, {} );
167
157
  // if (name === '' && prop === 'params') {
168
158
  // pushToDict( parent[kind], 'returns', elem ); // not really a dict
169
159
  // return;
@@ -218,6 +208,174 @@ function augmentPath( location, ...args ) {
218
208
  return { path: args.map( id => ({ id, location }) ), location };
219
209
  }
220
210
 
211
+ function copyExpr( expr, location, skipUnderscored, rewritePath ) {
212
+ if (!expr || typeof expr !== 'object')
213
+ return expr;
214
+ else if (Array.isArray(expr))
215
+ return expr.map( e => copyExpr( e, location, skipUnderscored, rewritePath ) );
216
+
217
+ const proto = Object.getPrototypeOf( expr );
218
+ if (proto && proto !== Object.prototype) // do not copy object from special classes
219
+ return expr;
220
+ const r = Object.create( proto );
221
+ for (const prop of Object.getOwnPropertyNames( expr )) {
222
+ const pd = Object.getOwnPropertyDescriptor( expr, prop );
223
+ if (!pd.enumerable) { // should include all properties starting with _
224
+ if (!skipUnderscored ||
225
+ prop === '_artifact' || prop === '_navigation' || prop === '_effectiveType')
226
+ Object.defineProperty( r, prop, pd );
227
+ }
228
+ else if (!proto) {
229
+ r[prop] = copyExpr( pd.value, location, skipUnderscored, rewritePath );
230
+ }
231
+ else if (prop === 'location') {
232
+ r[prop] = location || pd.value;
233
+ }
234
+ else if (prop.charAt(0) !== '$' || prop === '$inferred') {
235
+ r[prop] = copyExpr( pd.value, location, skipUnderscored, rewritePath );
236
+ }
237
+ else if (!skipUnderscored) { // skip $ properties
238
+ Object.defineProperty( r, prop, pd );
239
+ }
240
+ }
241
+ return r;
242
+ }
243
+
244
+ function testExpr( expr, pathTest, queryTest ) {
245
+ // TODO: also check path arguments/filters
246
+ if (!expr || typeof expr === 'string') { // parse error or keywords in {xpr:...}
247
+ return false;
248
+ }
249
+ else if (Array.isArray(expr)) {
250
+ return expr.some( e => testExpr( e, pathTest, queryTest ) );
251
+ }
252
+ else if (expr.path) {
253
+ return pathTest( expr );
254
+ }
255
+ else if (expr.query) {
256
+ return queryTest( expr.query );
257
+ }
258
+ else if (expr.op && expr.args) {
259
+ // unnamed args => array
260
+ if (Array.isArray(expr.args))
261
+ return expr.args.some( e => testExpr( e, pathTest, queryTest ) );
262
+ // named args => dictionary
263
+ for (const namedArg of Object.keys(expr.args)) {
264
+ if (testExpr(expr.args[namedArg], pathTest, queryTest))
265
+ return true;
266
+ }
267
+ }
268
+ return false;
269
+ }
270
+
271
+ // Return true if the path `item` with a final type `assoc` has a max target
272
+ // cardinality greater than one - either specified on the path item or assoc type.
273
+ function targetMaxNotOne( assoc, item ) {
274
+ // Semantics of associations without provided cardinality: [*,0..1]
275
+ const cardinality = item.cardinality || assoc.cardinality;
276
+ return cardinality && cardinality.targetMax && cardinality.targetMax.val !== 1;
277
+ }
278
+
279
+ // Query tree post-order traversal - called for everything which contributes to the query
280
+ // i.e. is necessary to calculate the elements of the query
281
+ // except "real ones": operands of UNION etc, JOIN with ON, and sub queries in FROM
282
+ // NOTE: does not run on non-referred sub queries! Consider using ‹main›.$queries instead!
283
+ function traverseQueryPost( query, simpleOnly, callback ) {
284
+ if (!query) // parser error
285
+ return;
286
+ if (!query.op) { // in FROM (not JOIN)
287
+ if (query.query) // subquery
288
+ traverseQueryPost( query.query, simpleOnly, callback );
289
+ return;
290
+ }
291
+ if (simpleOnly) {
292
+ const { from } = query;
293
+ if (!from || from.join) // parse error or join
294
+ return; // ok are: path or simple sub query (!)
295
+ }
296
+ if (query.from) { // SELECT
297
+ traverseQueryPost( query.from, simpleOnly, callback );
298
+ // console.log('FC:')
299
+ callback( query );
300
+ // console.log('FE:')
301
+ }
302
+ else if (query.args) { // JOIN, UNION, INTERSECT
303
+ if (!query.join && simpleOnly == null) {
304
+ // enough for elements: traverse only first args for UNION/INTERSECT
305
+ // TODO: we might use this also when we do not rewrite associations
306
+ // in non-referred sub queries
307
+ traverseQueryPost( query.args[0], simpleOnly, callback );
308
+ }
309
+ else {
310
+ for (const q of query.args)
311
+ traverseQueryPost( q, simpleOnly, callback );
312
+ // The ON condition has to be traversed extra, because it must be evaluated
313
+ // after the complete FROM has been traversed. It is also not necessary to
314
+ // evaluate it in populateQuery().
315
+ }
316
+ }
317
+ // else: with parse error (`select from <EOF>`, `select distinct from;`)
318
+ }
319
+
320
+ // Call callback on all queries in dependency order, i.e. starting with query Q
321
+ // 1. sub queries in FROM sources of Q
322
+ // 2. Q itself, except if non-referred query, but with right UNION parts
323
+ // 3. sub queries in ON in FROM of Q
324
+ // 4. sub queries in columns, WHERE, HAVING
325
+ function traverseQueryExtra( main, callback ) {
326
+ if (!main.$queries)
327
+ return;
328
+ // with a top-level UNION, $queries[0] is just the left
329
+ traverseQueryPost( main.query, false, (q) => { // also with right of UNION (to be compatible)
330
+ setLink( q, '_status', 'extra' );
331
+ callback( q );
332
+ } );
333
+ for (const query of main.$queries.slice(1)) {
334
+ if (query._status === 'extra' || query._parent.kind === '$tableAlias')
335
+ continue; // if parent is alias, query is FROM source -> run by traverseQueryPost
336
+ // we are now in the top-level (parent is entity) or a non-referred query (parent is query)
337
+ setLink( query, '_status', 'extra' ); // do not call callback() in non-referred query
338
+ // console.log( 'A:', query.name,query._status)
339
+ traverseQueryPost( query, null, (q) => {
340
+ if (q._status !== 'extra') {
341
+ // console.log( 'T:', q.name)
342
+ setLink( q, '_status', 'extra' );
343
+ callback( q );
344
+ }
345
+ // else console.log( 'E:', q.name)
346
+ } );
347
+ }
348
+ }
349
+
350
+ // About Helper property $expand for faster the XSN-to-CSN transformation
351
+ // - null/undefined: artifact, member, items does not contain expanded members
352
+ // - 'origin': all expanded (sub) elements have no new target/on and no new annotations
353
+ // that value is only on elements, types, and params -> no other members
354
+ // when set, only on elem/art with expanded elements
355
+ // - 'target': all expanded (sub) elements might only have new target/on, but
356
+ // no indivual annotations on any (sub) member
357
+ // when set, traverse all parents where the value has been 'origin' before
358
+ // - 'annotate': at least one inferred (sub) member has an individual annotation,
359
+ // not counting propagated ones; set up to the definition (main artifact)
360
+ // (only set with anno on $inferred elem), annotate “beats” target
361
+ // Usage according to CSN flavor:
362
+ // - gensrc: do not render inferred elements (including expanded elements),
363
+ // collect annotate statements with value 'annotate'
364
+ // - client: do not render expanded sub elements if artifact/member is no type, has a type,
365
+ // has $expand = 'origin', and all its _origin also have $expand = 'origin'
366
+ // (might sometimes render the elements unnecessarily, which is not wrong)
367
+ // - universal: do not render expanded sub elements if $expand = 'origin'
368
+ function setExpandStatus( elem, status ) {
369
+ // set on element
370
+ while (elem._main) {
371
+ elem = elem._parent;
372
+ if (status === 'annotate' ? elem.$expand === 'annotate' : elem.$expand !== 'origin')
373
+ return;
374
+ elem.$expand = status; // meaning: expanded, containing assocs
375
+ for (let line = elem.items; line; line = line.items)
376
+ line.$expand = status; // to-csn just uses the innermost $expand
377
+ }
378
+ }
221
379
 
222
380
  module.exports = {
223
381
  pushLink,
@@ -225,7 +383,7 @@ module.exports = {
225
383
  annotationIsFalse,
226
384
  annotateWith,
227
385
  setLink,
228
- setProp,
386
+ setArtifactLink,
229
387
  linkToOrigin,
230
388
  dependsOn,
231
389
  dependsOnSilent,
@@ -235,4 +393,10 @@ module.exports = {
235
393
  pathName,
236
394
  augmentPath,
237
395
  splitIntoPath,
396
+ copyExpr,
397
+ testExpr,
398
+ targetMaxNotOne,
399
+ traverseQueryPost,
400
+ traverseQueryExtra,
401
+ setExpandStatus,
238
402
  };
@@ -0,0 +1,5 @@
1
+ {
2
+ "rules": {
3
+ "no-shadow": "off"
4
+ }
5
+ }
@@ -4,15 +4,16 @@ const edmUtils = require('../edmUtils.js');
4
4
  const preprocessAnnotations = require('./preprocessAnnotations.js');
5
5
  const oDataDictionary = require('../../gen/Dictionary.json');
6
6
  const { forEachDefinition } = require('../../model/csnUtils');
7
+ const { forEach } = require("../../utils/objectUtils");
7
8
 
8
9
 
9
- /* Vocabulary overview as of January 2020:
10
-
10
+ /*
11
11
  OASIS: https://github.com/oasis-tcs/odata-vocabularies/tree/master/vocabularies
12
12
  Aggregation (published)
13
13
  Authorization (published)
14
14
  Capabilities (published)
15
15
  Core (published)
16
+ JSON (published)
16
17
  Measures (published)
17
18
  Repeatability (published)
18
19
  Temporal (not published, not yet finalized)
@@ -23,8 +24,9 @@ const { forEachDefinition } = require('../../model/csnUtils');
23
24
  CodeList (published)
24
25
  Common (pubished)
25
26
  Communication (published)
27
+ DataIntegration (published)
26
28
  Graph (published, experimental)
27
- Hierarchy (not published, still experimental)
29
+ Hierarchy (published, experimental)
28
30
  HTML5 (published, experimental)
29
31
  ODM (published, experimental)
30
32
  PersonalData (published)
@@ -73,16 +75,31 @@ const vocabularyDefinitions = {
73
75
  'inc': { Alias: 'Core', Namespace: 'Org.OData.Core.V1' },
74
76
  'int': { filename: 'Core.xml' }
75
77
  },
78
+ 'DataIntegration': {
79
+ 'ref': { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/DataIntegration.xml' },
80
+ 'inc': { Alias: 'DataIntegration', Namespace: 'com.sap.vocabularies.DataIntegration.v1' },
81
+ 'int': { filename: 'DataIntegration.xml' }
82
+ },
76
83
  'Graph': {
77
84
  'ref': { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Graph.xml' },
78
85
  'inc': { Alias: 'Graph', Namespace: 'com.sap.vocabularies.Graph.v1' },
79
86
  'int': { filename: 'Graph.xml' }
80
87
  },
88
+ 'Hierarchy': {
89
+ 'ref': { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Hierarchy.xml' },
90
+ 'inc': { Alias: 'Hierarchy', Namespace: 'com.sap.vocabularies.Hierarchy.v1' },
91
+ 'int': { filename: 'Hierarchy.xml' }
92
+ },
81
93
  'HTML5': {
82
94
  'ref': { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/HTML5.xml' },
83
95
  'inc': { Alias: 'HTML5', Namespace: 'com.sap.vocabularies.HTML5.v1' },
84
96
  'int': { filename: 'HTML5.xml' }
85
97
  },
98
+ 'JSON': {
99
+ 'ref': { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.JSON.V1.xml' },
100
+ 'inc': { Alias: 'JSON', Namespace: 'Org.OData.JSON.V1' },
101
+ 'int': { filename: 'JSON.xml' }
102
+ },
86
103
  'Measures': {
87
104
  'ref': { Uri: 'https://oasis-tcs.github.io/odata-vocabularies/vocabularies/Org.OData.Measures.V1.xml' },
88
105
  'inc': { Alias: 'Measures', Namespace: 'Org.OData.Measures.V1' },
@@ -414,7 +431,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
414
431
  // do nothing
415
432
 
416
433
  if(!isEdmPropertyRendered(carrier, options) ||
417
- (isV2() && (edmUtils.isDerivedType(carrier) || carrier['@Core.MediaType']))) {
434
+ (isV2() && (edmUtils.isDerivedType(carrier)))) {
418
435
  return;
419
436
  }
420
437
 
@@ -504,7 +521,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
504
521
  let hasAlternativeCarrier = false; // is the alternative annotation target available in the EDM?
505
522
  let testToAlternativeEdmTarget = null; // if true, assign to alternative Edm Target
506
523
 
507
- if (carrier.kind === 'entity' || carrier.kind === 'view') {
524
+ if (carrier.kind === 'entity') {
508
525
  // If AppliesTo=[EntitySet/Singleton/Collection, EntityType], EntitySet/Singleton/Collection has precedence
509
526
  testToAlternativeEdmTarget = (x => {
510
527
  if(options.isV2()) {
@@ -554,7 +571,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
554
571
  }
555
572
  else {
556
573
  // this might be more precise if handleAnnotation would know more about the carrier
557
- testToStandardEdmTarget = (x => x
574
+ testToStandardEdmTarget = (x => x
558
575
  ? ['Parameter', 'Property'].some(y => x.includes(y) ||
559
576
  carrier._isCollection && x.includes('Collection'))
560
577
  : true);
@@ -663,7 +680,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
663
680
  }
664
681
  mergePathStepsIntoPrefixTree(tree[name], pathSteps, index+1, carrier);
665
682
  }
666
- else {
683
+ else if(typeof tree === 'object' ){
667
684
  tree[name] = carrier['@' + pathSteps.join('.')];
668
685
  }
669
686
  }
@@ -714,9 +731,10 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
714
731
  * @type {object}
715
732
  * */
716
733
  let newAnno = undefined;
717
- const nullWhitelist = [ 'Core.OperationAvailable' ];
734
+ const omissions = { 'Aggregation.default':1 };
735
+ const nullList = { 'Core.OperationAvailable':1 };
718
736
  const voc = termName.slice(0, termName.indexOf('.'));
719
- if(vocabularyDefinitions[voc] && annoValue !== null || nullWhitelist.includes(termName)) {
737
+ if(vocabularyDefinitions[voc] && annoValue !== null && !omissions[termName]|| nullList[termName]) {
720
738
  newAnno = new Edm.Annotation(v, termName);
721
739
 
722
740
  // termName may contain a qualifier: @UI.FieldGroup#shippingStatus
@@ -729,8 +747,8 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
729
747
  message(error, context,
730
748
  `OData annotation qualifier "${ p[1] }" must start with a letter or underscore, followed by at most 127 letters, underscores or digits`);
731
749
  }
732
- newAnno.Term = termNameWithoutQualifiers;
733
- newAnno.Qualifier = p[1];
750
+ newAnno.setEdmAttribute('Term', termNameWithoutQualifiers);
751
+ newAnno.setEdmAttribute('Qualifier', p[1]);
734
752
  }
735
753
  if (p.length>2) {
736
754
  message(warning, context, `multiple qualifiers (${ p[1] },${ p[2] }${ p.length > 3 ? ',...' : '' })`);
@@ -948,7 +966,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
948
966
  if (typeof val === 'string') {
949
967
  if (dTypeName === 'Edm.Boolean') {
950
968
  typeName = 'Bool';
951
- if (!['true','false'].includes(val)) {
969
+ if (val !== 'true' && val !== 'false') {
952
970
  message(warning, context, `found String, but expected type ${ dTypeName }`);
953
971
  }
954
972
  }
@@ -1072,7 +1090,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
1072
1090
  // this type doesn't exist
1073
1091
  message(warning, context, `explicitly specified type '${ actualTypeName }' not found in vocabulary`);
1074
1092
  // explicitly mentioned type, render in XML and JSON
1075
- newRecord.Type = actualTypeName;
1093
+ newRecord.setEdmAttribute('Type', actualTypeName);
1076
1094
  }
1077
1095
  else if (dTypeName && !isDerivedFrom(actualTypeName, dTypeName)) {
1078
1096
  // this type doesn't fit the expected one
@@ -1080,7 +1098,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
1080
1098
  }' is not derived from expected type '${ dTypeName }'`);
1081
1099
  actualTypeName = dTypeName;
1082
1100
  // explicitly mentioned type, render in XML and JSON
1083
- newRecord.Type = actualTypeName;
1101
+ newRecord.setEdmAttribute('Type', actualTypeName);
1084
1102
  }
1085
1103
  else if (isAbstractType(actualTypeName)) {
1086
1104
  // this type is abstract
@@ -1088,7 +1106,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
1088
1106
  if(dTypeName)
1089
1107
  actualTypeName = dTypeName;
1090
1108
  // set to definition name and render in XML and JSON
1091
- newRecord.Type = actualTypeName;
1109
+ newRecord.setEdmAttribute('Type', actualTypeName);
1092
1110
  }
1093
1111
  else {
1094
1112
  // ok
@@ -1251,7 +1269,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
1251
1269
  const props = Object.create(null);
1252
1270
  Object.entries(obj).forEach(([k, val]) => {
1253
1271
  if(k === '@type') {
1254
- edmNode.Type = val;
1272
+ edmNode.setEdmAttribute('Type', val);
1255
1273
  }
1256
1274
  else {
1257
1275
  let child = undefined;
@@ -1284,14 +1302,10 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
1284
1302
  });
1285
1303
  }
1286
1304
  else { // literal
1287
- let escaped = obj;
1288
- if (typeof escaped === 'string') {
1289
- escaped = escaped.replace(/&/g, '&amp;')
1290
- }
1291
1305
  edmNode = new Edm.ValueThing(v,
1292
- exprDef && exprDef.valueThingName || getXmlTypeName(escaped), escaped);
1306
+ exprDef && exprDef.valueThingName || getXmlTypeName(obj), obj);
1293
1307
  // typename for static expression rendering
1294
- edmNode.setJSON( { [getJsonTypeName(escaped)]: escaped } );
1308
+ edmNode.setJSON( { [getJsonTypeName(obj)]: obj } );
1295
1309
  }
1296
1310
  }
1297
1311
  }
@@ -1301,14 +1315,14 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
1301
1315
  edmNode = exprDef.create(obj);
1302
1316
 
1303
1317
  // iterate over each obj.property and translate expression into EDM
1304
- Object.entries(obj).forEach(([name, val]) => {
1318
+ forEach(obj, (name, val) => {
1305
1319
  if(exprDef) {
1306
1320
  if(exprDef.anno && name[0] === '@') {
1307
1321
  edmNode.append(handleTerm(name.slice(1), val, context));
1308
1322
  }
1309
1323
  else if (exprDef.attr && exprDef.attr.includes(name)) {
1310
1324
  if (name[0] === '$') {
1311
- edmNode[name.slice(1)] = val;
1325
+ edmNode.setEdmAttribute(name.slice(1), val);
1312
1326
  }
1313
1327
  }
1314
1328
  else if (exprDef.jsonAttr && exprDef.jsonAttr.includes(name)) {
@@ -101,7 +101,7 @@ function preprocessAnnotations(csn, serviceName, options) {
101
101
 
102
102
  // inner functions
103
103
  function draftAnnotations(carrier, aName, aNameWithoutQualifier) {
104
- if ((carrier.kind === 'entity' || carrier.kind === 'view') &&
104
+ if ((carrier.kind === 'entity') &&
105
105
  (aNameWithoutQualifier === '@Common.DraftRoot.PreparationAction' ||
106
106
  aNameWithoutQualifier === '@Common.DraftRoot.ActivationAction' ||
107
107
  aNameWithoutQualifier === '@Common.DraftRoot.EditAction' ||
@@ -136,7 +136,7 @@ function preprocessAnnotations(csn, serviceName, options) {
136
136
  return false;
137
137
  }
138
138
 
139
- if (carrier.kind === 'entity' || carrier.kind === 'view') {
139
+ if (carrier.kind === 'entity') {
140
140
  warning(null, null, `annotation preprocessing/${aNameWithoutQualifier}: annotation must not be used for an entity, ${ctx}`);
141
141
  return false;
142
142
  }