@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
@@ -5,10 +5,10 @@
5
5
  const {
6
6
  forEachDefinition,
7
7
  forEachMember,
8
- setProp,
8
+ forEachGeneric,
9
9
  isDeprecatedEnabled,
10
10
  } = require( '../base/model');
11
- const { linkToOrigin, withAssociation } = require('./utils');
11
+ const { setLink, linkToOrigin, withAssociation } = require('./utils');
12
12
  // const { refString } = require( '../base/messages')
13
13
 
14
14
  function propagate( model ) {
@@ -19,37 +19,36 @@ function propagate( model ) {
19
19
  '@cds.persistence.calcview': never,
20
20
  '@cds.persistence.udf': never,
21
21
  '@cds.persistence.skip': notWithPersistenceTable,
22
- '@sql.prepend': never,
23
22
  '@sql.append': never,
23
+ '@sql.prepend': never,
24
+ '@sql.replace': never,
24
25
  '@Analytics.hidden': never,
25
26
  '@Analytics.visible': never,
26
27
  '@cds.autoexpose': onlyViaArtifact,
27
28
  '@cds.autoexposed': never, // in case people set it themselves
28
29
  '@cds.redirection.target': never,
29
30
  '@fiori.draft.enabled': onlyViaArtifact,
30
- '@': withKind, // always except in 'returns' and 'items'
31
- doc: withKind, // always except in 'returns' and 'items'
31
+ '@': annotation, // always except in 'returns' and 'items'
32
+ doc: annotation, // always except in 'returns' and 'items'
32
33
  default: withKind, // always except in 'returns' and 'items'
33
- virtual: notViaType,
34
- notNull, // a variant of notViaType()
34
+ virtual,
35
+ notNull,
35
36
  targetElement: onlyViaParent, // in foreign keys
36
37
  value: onlyViaParent, // enum symbol value
37
38
  // masked: special = done in definer
38
39
  // key: special = done in resolver
39
40
  // actions: struct includes & primary source = in definer/resolver
40
- type: always,
41
+ type: notWithExpand,
41
42
  length: always,
42
43
  precision: always,
43
44
  scale: always,
44
45
  srid: always,
45
46
  localized: always,
46
- target: always,
47
- targetAspect: always,
48
- cardinality: always,
49
- on: ( prop, target, source ) => {
50
- target[prop] = source[prop];
51
- }, // TODO: get rid of this soon!
52
- foreignKeys: expensive, // actually always, but dictionary copy
47
+ target: notWithExpand,
48
+ targetAspect: notWithExpand,
49
+ cardinality: notWithExpand,
50
+ on: notWithExpand,
51
+ foreignKeys: expensive, // includes "notWithExpand", dictionary copy
53
52
  items,
54
53
  elements: expensive,
55
54
  enum: expensive,
@@ -58,8 +57,17 @@ function propagate( model ) {
58
57
  };
59
58
  const { options } = model;
60
59
  const enableExpandElements = !isDeprecatedEnabled( options, 'noElementsExpansion' );
60
+ // eslint-disable-next-line max-len
61
+ const oldVirtualNotNullPropagation = isDeprecatedEnabled( options, 'oldVirtualNotNullPropagation' );
61
62
 
62
63
  forEachDefinition( model, run );
64
+
65
+ const { warning, throwWithError } = model.$messageFunctions;
66
+ // TODO: move 'virtual' handling/checks to resolver if
67
+ // 'deprecated.oldVirtualNotNullPropagation' is gone
68
+ if (!oldVirtualNotNullPropagation) // check would always be right, but to be ultra compatible…
69
+ forEachDefinition( model, checkVirtual );
70
+ throwWithError();
63
71
  return model;
64
72
 
65
73
  function run( art ) {
@@ -109,6 +117,9 @@ function propagate( model ) {
109
117
  function runMembers( art ) {
110
118
  // console.log('MEMBERS:',refString(art), art.elements ? Object.keys(art.elements) : 0)
111
119
  forEachMember( art, run ); // after propagation in parent!
120
+ // propagate to sub query elements even if not requested:
121
+ if (art.$queries)
122
+ art.$queries.forEach( run );
112
123
  let obj = art;
113
124
  if (art.returns) {
114
125
  obj = art.returns;
@@ -116,12 +127,13 @@ function propagate( model ) {
116
127
  }
117
128
  if (obj.items)
118
129
  run( obj.items );
119
- setProp( art, '_status', 'propagated' );
130
+ setLink( art, '_status', 'propagated' );
120
131
  }
121
132
 
122
133
  function step({ target, source }) {
123
- // console.log('PROPS:',source&&refString(source),'->',refString(target))
124
- const viaType = target.type && !target.type.$inferred;
134
+ // console.log('PROPS:',source&&source.name,'->',target.name)
135
+ const viaType = target.type && // TODO: falsy $inferred value instead 'cast'?
136
+ (!target.type.$inferred || target.type.$inferred === 'cast');
125
137
  const keys = Object.keys( source );
126
138
  for (const prop of keys) {
127
139
  if (prop in target) // TODO: warning with competing props from multi-includes
@@ -130,8 +142,10 @@ function propagate( model ) {
130
142
  if (transformer)
131
143
  transformer( prop, target, source, viaType );
132
144
  }
133
- // propagate NOT NULL and VIRTUAL from sub elements:
134
- if (target.$inferred !== 'proxy' &&
145
+ // propagate NOT NULL and VIRTUAL from sub elements with
146
+ // 'deprecated.oldVirtualNotNullPropagation':
147
+ if (oldVirtualNotNullPropagation &&
148
+ target.$inferred !== 'proxy' &&
135
149
  target.kind === 'element' && source.kind === 'element') {
136
150
  let elem = source; // the outer element
137
151
  while (elem._parent.kind === 'element')
@@ -143,7 +157,7 @@ function propagate( model ) {
143
157
  props.virtual( 'virtual', target, elem );
144
158
  }
145
159
  }
146
- // setProp( target, '_status', 'shallow-propagated' );
160
+ // setLink( target, '_status', 'shallow-propagated' );
147
161
  }
148
162
 
149
163
  function never() { /* no-op: don't propagate */ }
@@ -154,12 +168,16 @@ function propagate( model ) {
154
168
  target[prop] = [ ...val ];
155
169
  target[prop].$inferred = 'prop';
156
170
  }
157
- else if ('_artifact' in val) {
158
- target[prop] = Object.assign( { $inferred: 'prop' }, val );
159
- setProp( target[prop], '_artifact', val._artifact );
160
- }
161
171
  else {
162
- target[prop] = Object.assign( { $inferred: 'prop' }, val );
172
+ target[prop] = Object.assign( {}, val, { $inferred: 'prop' } );
173
+ if ('_artifact' in val)
174
+ setLink( target[prop], '_artifact', val._artifact );
175
+ if ('_outer' in val)
176
+ setLink( target[prop], '_outer', val._outer );
177
+ if ('_parent' in val)
178
+ setLink( target[prop], '_parent', val._parent );
179
+ if ('_main' in val)
180
+ setLink( target[prop], '_main', val._main );
163
181
  }
164
182
  }
165
183
 
@@ -178,10 +196,18 @@ function propagate( model ) {
178
196
 
179
197
  // Expensive properties are not really propagated if they can be directly
180
198
  // accessed at their type being a main artifact
199
+ // Expensive properties are also not propagated with `expand`:
200
+ // * `elements`: the compiler calculates its own `elements` for a structure
201
+ // ref with `expand`.
202
+ // * `params`: no element has parameters
203
+ // * `enum`: an enum cannot be used with `expand`
204
+ // * `keys`: should also not be propagated with `expand`
181
205
  function expensive( prop, target, source ) {
182
206
  // console.log(prop,source.name,'->',target.kind,target.name);
183
207
  if (source.kind === 'builtin')
184
208
  return;
209
+ if (target.expand) // do not propagate `keys` with expand
210
+ return;
185
211
  if (prop !== 'foreignKeys' && availableAtType( prop, target, source ))
186
212
  // foreignKeys must always be copied with target to avoid any confusion
187
213
  // whether we have to generated implicit keys
@@ -200,47 +226,88 @@ function propagate( model ) {
200
226
  }
201
227
  }
202
228
 
203
- function notViaType( prop, target, source, viaType ) {
204
- if (!viaType)
205
- always( prop, target, source );
206
- }
207
-
208
- function onlyViaArtifact( prop, target, source ) {
209
- if (target.kind) { // not in 'returns' and 'items'
210
- const from = target._from && target._from[0].path;
211
- if (!(from ? from[from.length - 1]._artifact : source)._main)
212
- always( prop, target, source );
213
- }
214
- }
215
-
216
229
  function onlyViaParent( prop, target, source ) {
217
230
  if (target.$inferred === 'proxy' || target.$inferred === 'expand-element')
218
231
  // assocs and enums do not have 'include'
219
232
  always( prop, target, source );
220
233
  }
221
234
 
235
+ function notWithExpand( prop, target, source ) {
236
+ if (!target.expand || prop === 'type' && source.elements)
237
+ always( prop, target, source );
238
+ }
239
+
222
240
  function notWithPersistenceTable( prop, target, source ) {
223
241
  const tableAnno = target['@cds.persistence.table'];
224
242
  if (!tableAnno || tableAnno.val === null)
243
+ annotation( prop, target, source );
244
+ }
245
+
246
+ function annotation( prop, target, source ) {
247
+ const anno = source[prop];
248
+ if (anno.val !== null)
225
249
  withKind( prop, target, source );
226
250
  }
227
251
 
252
+ function onlyViaArtifact( prop, target, source ) {
253
+ const from = target._from && target._from[0].path;
254
+ if (!(from ? from[from.length - 1]._artifact : source)._main)
255
+ annotation( prop, target, source );
256
+ }
257
+
228
258
  function withKind( prop, target, source ) {
229
259
  if (target.kind && (!target._parent || target._parent.returns !== target))
230
260
  always( prop, target, source ); // not in 'returns' and 'items'
231
261
  }
232
262
 
233
263
  function notNull( prop, target, source, viaType ) {
234
- if (!(viaType || target.value && withAssociation( target.value, targetMinZero )))
264
+ // Really "reset" NOT NULL when ref has assoc with cardinality min: 0 (TODO: Universal CSN)
265
+ if (oldVirtualNotNullPropagation && viaType)
266
+ return; // strange propagation not supported with Universal CSN
267
+ if (target.value && withAssociation( target.value, targetMinZero ))
268
+ target[prop] = { $inferred: 'NULL', val: undefined }; // set null value in Universal CSN
269
+ // $inferred: 'NULL' is only an issue for sub elements with a 'value' property;
270
+ // it only exists with nested projections, i.e. never with deprecated option enabled
271
+ else
272
+ always( prop, target, source );
273
+ }
274
+
275
+ function virtual( prop, target, source, viaType ) {
276
+ if (!viaType)
235
277
  always( prop, target, source );
278
+ else if (!oldVirtualNotNullPropagation) // NULL would block strange propagation to sub element
279
+ target[prop] = { $inferred: 'NULL', val: undefined }; // set null value in Univeral CSN
280
+ }
281
+
282
+ function checkVirtual( view ) {
283
+ if (view.query)
284
+ forEachGeneric( view, 'elements', checkNonVirtualElement );
285
+ }
286
+
287
+ function checkNonVirtualElement( elem ) {
288
+ // Not enough at all, but so are the current checks - a complete expression
289
+ // must be checked. Here we just check what might have worked before.
290
+ // TODO: Propagate 'virtual' in resolver if 'deprecated.oldVirtualNotNullPropagation' is gone.
291
+ const path = !elem.virtual && elem.value && elem.value.path;
292
+ if (!path || path.broken)
293
+ return;
294
+ for (const item of path) {
295
+ const art = item && item._artifact;
296
+ if (art && art.virtual && art.virtual.val) {
297
+ warning( 'def-missing-virtual', [ item.location, elem ], { art, keyword: 'virtual' },
298
+ // eslint-disable-next-line max-len
299
+ 'Prepend $(KEYWORD) to current select item - referred element $(ART) is virtual which is not inherited' );
300
+ return;
301
+ }
302
+ }
236
303
  }
237
304
 
238
305
  function returns( prop, target, source, ok ) {
239
306
  if (ok || target.$inferred === 'proxy' || target.$inferred === 'include' ) {
240
307
  target[prop] = { $inferred: 'proxy' };
241
308
  setEffectiveType( target[prop], source[prop] );
242
- setProp( target[prop], '_origin', source[prop] );
243
- setProp( target[prop], '_outer', target._outer || target ); // for setMemberParent
309
+ setLink( target[prop], '_origin', source[prop] );
310
+ setLink( target[prop], '_outer', target._outer || target ); // for setMemberParent
244
311
  }
245
312
  }
246
313
 
@@ -262,7 +329,8 @@ function targetMinZero( art ) {
262
329
 
263
330
  function getOrigin( art ) {
264
331
  if (art._origin)
265
- return !art.expand && art._origin;
332
+ // Do not consider _origin if due to expand of table alias ref
333
+ return (!art.expand || art._origin.kind === 'element') && art._origin;
266
334
  // Remark: a column with an 'inline' is never an element -> no need to check
267
335
  // art.inline
268
336
  if (art._from && art._from.length) { // query
@@ -273,7 +341,7 @@ function getOrigin( art ) {
273
341
  : tabref;
274
342
  }
275
343
 
276
- return (art.type && !art.type.$inferred)
344
+ return (art.type && (!art.type.$inferred || art.type.$inferred === 'cast'))
277
345
  ? art.type._artifact
278
346
  : art._origin;
279
347
  }
@@ -281,13 +349,13 @@ function getOrigin( art ) {
281
349
  function checkAndSetStatus( art ) {
282
350
  if (art._status === 'propagated' || art._status === 'propagating')
283
351
  return false;
284
- setProp( art, '_status', 'propagating' );
352
+ setLink( art, '_status', 'propagating' );
285
353
  return true;
286
354
  }
287
355
 
288
356
  function setEffectiveType( target, source ) {
289
357
  if ('_effectiveType' in source)
290
- setProp( target, '_effectiveType', source._effectiveType);
358
+ setLink( target, '_effectiveType', source._effectiveType);
291
359
  }
292
360
 
293
361
  module.exports = {