@sap/cds-compiler 2.11.4 → 2.13.8

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 (133) hide show
  1. package/CHANGELOG.md +159 -1
  2. package/bin/cds_update_identifiers.js +7 -7
  3. package/bin/cdsc.js +22 -23
  4. package/bin/cdsse.js +2 -2
  5. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  6. package/doc/CHANGELOG_BETA.md +25 -6
  7. package/doc/CHANGELOG_DEPRECATED.md +22 -6
  8. package/doc/NameResolution.md +21 -16
  9. package/lib/api/main.js +30 -63
  10. package/lib/api/options.js +5 -5
  11. package/lib/api/validate.js +0 -5
  12. package/lib/backends.js +15 -23
  13. package/lib/base/dictionaries.js +0 -8
  14. package/lib/base/error.js +26 -0
  15. package/lib/base/keywords.js +7 -17
  16. package/lib/base/location.js +9 -4
  17. package/lib/base/message-registry.js +52 -2
  18. package/lib/base/messages.js +16 -26
  19. package/lib/base/model.js +2 -62
  20. package/lib/base/optionProcessorHelper.js +246 -183
  21. package/lib/checks/.eslintrc.json +2 -0
  22. package/lib/checks/actionsFunctions.js +2 -1
  23. package/lib/checks/annotationsOData.js +1 -1
  24. package/lib/checks/cdsPersistence.js +2 -1
  25. package/lib/checks/enricher.js +17 -1
  26. package/lib/checks/foreignKeys.js +4 -4
  27. package/lib/checks/invalidTarget.js +3 -1
  28. package/lib/checks/managedInType.js +4 -4
  29. package/lib/checks/managedWithoutKeys.js +3 -1
  30. package/lib/checks/queryNoDbArtifacts.js +1 -3
  31. package/lib/checks/selectItems.js +4 -4
  32. package/lib/checks/sql-snippets.js +94 -0
  33. package/lib/checks/types.js +1 -1
  34. package/lib/checks/validator.js +12 -7
  35. package/lib/compiler/assert-consistency.js +10 -6
  36. package/lib/compiler/base.js +0 -1
  37. package/lib/compiler/builtins.js +8 -6
  38. package/lib/compiler/checks.js +46 -12
  39. package/lib/compiler/cycle-detector.js +1 -1
  40. package/lib/compiler/define.js +1103 -0
  41. package/lib/compiler/extend.js +983 -0
  42. package/lib/compiler/finalize-parse-cdl.js +231 -0
  43. package/lib/compiler/index.js +33 -14
  44. package/lib/compiler/kick-start.js +190 -0
  45. package/lib/compiler/moduleLayers.js +4 -4
  46. package/lib/compiler/populate.js +1226 -0
  47. package/lib/compiler/propagator.js +113 -47
  48. package/lib/compiler/resolve.js +1433 -0
  49. package/lib/compiler/shared.js +76 -38
  50. package/lib/compiler/tweak-assocs.js +529 -0
  51. package/lib/compiler/utils.js +204 -33
  52. package/lib/edm/.eslintrc.json +5 -0
  53. package/lib/edm/annotations/genericTranslation.js +38 -25
  54. package/lib/edm/annotations/preprocessAnnotations.js +3 -3
  55. package/lib/edm/csn2edm.js +10 -9
  56. package/lib/edm/edm.js +19 -20
  57. package/lib/edm/edmPreprocessor.js +166 -95
  58. package/lib/edm/edmUtils.js +127 -34
  59. package/lib/gen/Dictionary.json +92 -43
  60. package/lib/gen/language.checksum +1 -1
  61. package/lib/gen/language.interp +11 -1
  62. package/lib/gen/language.tokens +86 -82
  63. package/lib/gen/languageLexer.interp +18 -1
  64. package/lib/gen/languageLexer.js +925 -847
  65. package/lib/gen/languageLexer.tokens +78 -74
  66. package/lib/gen/languageParser.js +5434 -4298
  67. package/lib/json/from-csn.js +59 -17
  68. package/lib/json/to-csn.js +143 -71
  69. package/lib/language/antlrParser.js +3 -3
  70. package/lib/language/docCommentParser.js +3 -3
  71. package/lib/language/genericAntlrParser.js +144 -54
  72. package/lib/language/language.g4 +424 -203
  73. package/lib/language/multiLineStringParser.js +536 -0
  74. package/lib/main.d.ts +472 -61
  75. package/lib/main.js +38 -11
  76. package/lib/model/api.js +3 -1
  77. package/lib/model/csnRefs.js +321 -204
  78. package/lib/model/csnUtils.js +224 -263
  79. package/lib/model/enrichCsn.js +97 -40
  80. package/lib/model/revealInternalProperties.js +27 -6
  81. package/lib/model/sortViews.js +2 -1
  82. package/lib/modelCompare/compare.js +17 -12
  83. package/lib/optionProcessor.js +7 -6
  84. package/lib/render/DuplicateChecker.js +1 -1
  85. package/lib/render/manageConstraints.js +36 -33
  86. package/lib/render/toCdl.js +174 -275
  87. package/lib/render/toHdbcds.js +201 -115
  88. package/lib/render/toRename.js +7 -10
  89. package/lib/render/toSql.js +149 -75
  90. package/lib/render/utils/common.js +22 -8
  91. package/lib/render/utils/sql.js +10 -7
  92. package/lib/render/utils/stringEscapes.js +111 -0
  93. package/lib/sql-identifier.js +1 -1
  94. package/lib/transform/.eslintrc.json +5 -0
  95. package/lib/transform/braceExpression.js +4 -2
  96. package/lib/transform/db/.eslintrc.json +2 -0
  97. package/lib/transform/db/applyTransformations.js +35 -12
  98. package/lib/transform/db/assertUnique.js +1 -1
  99. package/lib/transform/db/associations.js +187 -0
  100. package/lib/transform/db/cdsPersistence.js +150 -0
  101. package/lib/transform/db/constraints.js +61 -56
  102. package/lib/transform/db/expansion.js +50 -29
  103. package/lib/transform/db/flattening.js +552 -105
  104. package/lib/transform/db/groupByOrderBy.js +3 -1
  105. package/lib/transform/db/temporal.js +236 -0
  106. package/lib/transform/db/transformExists.js +94 -28
  107. package/lib/transform/db/views.js +5 -4
  108. package/lib/transform/draft/.eslintrc.json +38 -0
  109. package/lib/transform/{db/draft.js → draft/db.js} +9 -7
  110. package/lib/transform/draft/odata.js +227 -0
  111. package/lib/transform/forHanaNew.js +94 -801
  112. package/lib/transform/forOdataNew.js +22 -175
  113. package/lib/transform/localized.js +36 -32
  114. package/lib/transform/odata/generateForeignKeyElements.js +3 -3
  115. package/lib/transform/odata/referenceFlattener.js +95 -89
  116. package/lib/transform/odata/structureFlattener.js +1 -1
  117. package/lib/transform/odata/toFinalBaseType.js +86 -12
  118. package/lib/transform/odata/typesExposure.js +5 -5
  119. package/lib/transform/odata/utils.js +2 -2
  120. package/lib/transform/transformUtilsNew.js +47 -33
  121. package/lib/transform/translateAssocsToJoins.js +10 -27
  122. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  123. package/lib/transform/universalCsn/coreComputed.js +170 -0
  124. package/lib/transform/universalCsn/universalCsnEnricher.js +715 -0
  125. package/lib/transform/universalCsn/utils.js +63 -0
  126. package/lib/utils/file.js +2 -1
  127. package/lib/utils/objectUtils.js +30 -0
  128. package/lib/utils/timetrace.js +8 -2
  129. package/package.json +1 -1
  130. package/share/messages/README.md +26 -0
  131. package/lib/compiler/definer.js +0 -2340
  132. package/lib/compiler/resolver.js +0 -2988
  133. package/lib/transform/universalCsnEnricher.js +0 -67
@@ -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,35 +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.append': never,
23
+ '@sql.prepend': never,
24
+ '@sql.replace': never,
22
25
  '@Analytics.hidden': never,
23
26
  '@Analytics.visible': never,
24
27
  '@cds.autoexpose': onlyViaArtifact,
25
28
  '@cds.autoexposed': never, // in case people set it themselves
26
29
  '@cds.redirection.target': never,
27
30
  '@fiori.draft.enabled': onlyViaArtifact,
28
- '@': withKind, // always except in 'returns' and 'items'
29
- 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'
30
33
  default: withKind, // always except in 'returns' and 'items'
31
- virtual: notViaType,
32
- notNull, // a variant of notViaType()
34
+ virtual,
35
+ notNull,
33
36
  targetElement: onlyViaParent, // in foreign keys
34
37
  value: onlyViaParent, // enum symbol value
35
38
  // masked: special = done in definer
36
39
  // key: special = done in resolver
37
40
  // actions: struct includes & primary source = in definer/resolver
38
- type: always,
41
+ type: notWithExpand,
39
42
  length: always,
40
43
  precision: always,
41
44
  scale: always,
42
45
  srid: always,
43
46
  localized: always,
44
- target: always,
45
- targetAspect: always,
46
- cardinality: always,
47
- on: ( prop, target, source ) => {
48
- target[prop] = source[prop];
49
- }, // TODO: get rid of this soon!
50
- 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
51
52
  items,
52
53
  elements: expensive,
53
54
  enum: expensive,
@@ -56,16 +57,24 @@ function propagate( model ) {
56
57
  };
57
58
  const { options } = model;
58
59
  const enableExpandElements = !isDeprecatedEnabled( options, 'noElementsExpansion' );
60
+ // eslint-disable-next-line max-len
61
+ const oldVirtualNotNullPropagation = isDeprecatedEnabled( options, 'oldVirtualNotNullPropagation' );
59
62
 
60
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();
61
71
  return model;
62
72
 
63
73
  function run( art ) {
64
74
  if (!art)
65
75
  return;
66
76
  if (!checkAndSetStatus( art )) {
67
- if ( art.status !== 'propagated')
68
- runMembers( art );
77
+ runMembers( art );
69
78
  return;
70
79
  }
71
80
  // console.log('RUN:', art.name, art.elements ? Object.keys(art.elements) : 0)
@@ -115,12 +124,13 @@ function propagate( model ) {
115
124
  }
116
125
  if (obj.items)
117
126
  run( obj.items );
118
- setProp( art, '_status', 'propagated' );
127
+ setLink( art, '_status', 'propagated' );
119
128
  }
120
129
 
121
130
  function step({ target, source }) {
122
- // console.log('PROPS:',source&&refString(source),'->',refString(target))
123
- const viaType = target.type && !target.type.$inferred;
131
+ // console.log('PROPS:',source&&source.name,'->',target.name)
132
+ const viaType = target.type && // TODO: falsy $inferred value instead 'cast'?
133
+ (!target.type.$inferred || target.type.$inferred === 'cast');
124
134
  const keys = Object.keys( source );
125
135
  for (const prop of keys) {
126
136
  if (prop in target) // TODO: warning with competing props from multi-includes
@@ -129,8 +139,10 @@ function propagate( model ) {
129
139
  if (transformer)
130
140
  transformer( prop, target, source, viaType );
131
141
  }
132
- // propagate NOT NULL and VIRTUAL from sub elements:
133
- if (target.$inferred !== 'proxy' &&
142
+ // propagate NOT NULL and VIRTUAL from sub elements with
143
+ // 'deprecated.oldVirtualNotNullPropagation':
144
+ if (oldVirtualNotNullPropagation &&
145
+ target.$inferred !== 'proxy' &&
134
146
  target.kind === 'element' && source.kind === 'element') {
135
147
  let elem = source; // the outer element
136
148
  while (elem._parent.kind === 'element')
@@ -142,7 +154,7 @@ function propagate( model ) {
142
154
  props.virtual( 'virtual', target, elem );
143
155
  }
144
156
  }
145
- // setProp( target, '_status', 'shallow-propagated' );
157
+ // setLink( target, '_status', 'shallow-propagated' );
146
158
  }
147
159
 
148
160
  function never() { /* no-op: don't propagate */ }
@@ -153,12 +165,16 @@ function propagate( model ) {
153
165
  target[prop] = [ ...val ];
154
166
  target[prop].$inferred = 'prop';
155
167
  }
156
- else if ('_artifact' in val) {
157
- target[prop] = Object.assign( { $inferred: 'prop' }, val );
158
- setProp( target[prop], '_artifact', val._artifact );
159
- }
160
168
  else {
161
- target[prop] = Object.assign( { $inferred: 'prop' }, val );
169
+ target[prop] = Object.assign( {}, val, { $inferred: 'prop' } );
170
+ if ('_artifact' in val)
171
+ setLink( target[prop], '_artifact', val._artifact );
172
+ if ('_outer' in val)
173
+ setLink( target[prop], '_outer', val._outer );
174
+ if ('_parent' in val)
175
+ setLink( target[prop], '_parent', val._parent );
176
+ if ('_main' in val)
177
+ setLink( target[prop], '_main', val._main );
162
178
  }
163
179
  }
164
180
 
@@ -177,10 +193,18 @@ function propagate( model ) {
177
193
 
178
194
  // Expensive properties are not really propagated if they can be directly
179
195
  // accessed at their type being a main artifact
196
+ // Expensive properties are also not propagated with `expand`:
197
+ // * `elements`: the compiler calculates its own `elements` for a structure
198
+ // ref with `expand`.
199
+ // * `params`: no element has parameters
200
+ // * `enum`: an enum cannot be used with `expand`
201
+ // * `keys`: should also not be propagated with `expand`
180
202
  function expensive( prop, target, source ) {
181
203
  // console.log(prop,source.name,'->',target.kind,target.name);
182
204
  if (source.kind === 'builtin')
183
205
  return;
206
+ if (target.expand) // do not propagate `keys` with expand
207
+ return;
184
208
  if (prop !== 'foreignKeys' && availableAtType( prop, target, source ))
185
209
  // foreignKeys must always be copied with target to avoid any confusion
186
210
  // whether we have to generated implicit keys
@@ -199,47 +223,88 @@ function propagate( model ) {
199
223
  }
200
224
  }
201
225
 
202
- function notViaType( prop, target, source, viaType ) {
203
- if (!viaType)
204
- always( prop, target, source );
205
- }
206
-
207
- function onlyViaArtifact( prop, target, source ) {
208
- if (target.kind) { // not in 'returns' and 'items'
209
- const from = target._from && target._from[0].path;
210
- if (!(from ? from[from.length - 1]._artifact : source)._main)
211
- always( prop, target, source );
212
- }
213
- }
214
-
215
226
  function onlyViaParent( prop, target, source ) {
216
227
  if (target.$inferred === 'proxy' || target.$inferred === 'expand-element')
217
228
  // assocs and enums do not have 'include'
218
229
  always( prop, target, source );
219
230
  }
220
231
 
232
+ function notWithExpand( prop, target, source ) {
233
+ if (!target.expand)
234
+ always( prop, target, source );
235
+ }
236
+
221
237
  function notWithPersistenceTable( prop, target, source ) {
222
238
  const tableAnno = target['@cds.persistence.table'];
223
239
  if (!tableAnno || tableAnno.val === null)
240
+ annotation( prop, target, source );
241
+ }
242
+
243
+ function annotation( prop, target, source ) {
244
+ const anno = source[prop];
245
+ if (anno.val !== null)
224
246
  withKind( prop, target, source );
225
247
  }
226
248
 
249
+ function onlyViaArtifact( prop, target, source ) {
250
+ const from = target._from && target._from[0].path;
251
+ if (!(from ? from[from.length - 1]._artifact : source)._main)
252
+ annotation( prop, target, source );
253
+ }
254
+
227
255
  function withKind( prop, target, source ) {
228
256
  if (target.kind && (!target._parent || target._parent.returns !== target))
229
257
  always( prop, target, source ); // not in 'returns' and 'items'
230
258
  }
231
259
 
232
260
  function notNull( prop, target, source, viaType ) {
233
- if (!(viaType || target.value && withAssociation( target.value, targetMinZero )))
261
+ // Really "reset" NOT NULL when ref has assoc with cardinality min: 0 (TODO: Universal CSN)
262
+ if (oldVirtualNotNullPropagation && viaType)
263
+ return; // strange propagation not supported with Universal CSN
264
+ if (target.value && withAssociation( target.value, targetMinZero ))
265
+ target[prop] = { $inferred: 'NULL', val: undefined }; // set null value in Universal CSN
266
+ // $inferred: 'NULL' is only an issue for sub elements with a 'value' property;
267
+ // it only exists with nested projections, i.e. never with deprecated option enabled
268
+ else
269
+ always( prop, target, source );
270
+ }
271
+
272
+ function virtual( prop, target, source, viaType ) {
273
+ if (!viaType)
234
274
  always( prop, target, source );
275
+ else if (!oldVirtualNotNullPropagation) // NULL would block strange propagation to sub element
276
+ target[prop] = { $inferred: 'NULL', val: undefined }; // set null value in Univeral CSN
277
+ }
278
+
279
+ function checkVirtual( view ) {
280
+ if (view.query)
281
+ forEachGeneric( view, 'elements', checkNonVirtualElement );
282
+ }
283
+
284
+ function checkNonVirtualElement( elem ) {
285
+ // Not enough at all, but so are the current checks - a complete expression
286
+ // must be checked. Here we just check what might have worked before.
287
+ // TODO: Propagate 'virtual' in resolver if 'deprecated.oldVirtualNotNullPropagation' is gone.
288
+ const path = !elem.virtual && elem.value && elem.value.path;
289
+ if (!path || path.broken)
290
+ return;
291
+ for (const item of path) {
292
+ const art = item && item._artifact;
293
+ if (art && art.virtual && art.virtual.val) {
294
+ warning( 'def-missing-virtual', [ item.location, elem ], { art, keyword: 'virtual' },
295
+ // eslint-disable-next-line max-len
296
+ 'Prepend $(KEYWORD) to current select item - referred element $(ART) is virtual which is not inherited' );
297
+ return;
298
+ }
299
+ }
235
300
  }
236
301
 
237
302
  function returns( prop, target, source, ok ) {
238
303
  if (ok || target.$inferred === 'proxy' || target.$inferred === 'include' ) {
239
304
  target[prop] = { $inferred: 'proxy' };
240
305
  setEffectiveType( target[prop], source[prop] );
241
- setProp( target[prop], '_origin', source[prop] );
242
- setProp( target[prop], '_outer', target._outer || target ); // for setMemberParent
306
+ setLink( target[prop], '_origin', source[prop] );
307
+ setLink( target[prop], '_outer', target._outer || target ); // for setMemberParent
243
308
  }
244
309
  }
245
310
 
@@ -261,7 +326,8 @@ function targetMinZero( art ) {
261
326
 
262
327
  function getOrigin( art ) {
263
328
  if (art._origin)
264
- return !art.expand && art._origin;
329
+ // Do not consider _origin if due to expand of table alias ref
330
+ return (!art.expand || art._origin.kind === 'element') && art._origin;
265
331
  // Remark: a column with an 'inline' is never an element -> no need to check
266
332
  // art.inline
267
333
  if (art._from && art._from.length) { // query
@@ -272,7 +338,7 @@ function getOrigin( art ) {
272
338
  : tabref;
273
339
  }
274
340
 
275
- return (art.type && !art.type.$inferred)
341
+ return (art.type && (!art.type.$inferred || art.type.$inferred === 'cast'))
276
342
  ? art.type._artifact
277
343
  : art._origin;
278
344
  }
@@ -280,13 +346,13 @@ function getOrigin( art ) {
280
346
  function checkAndSetStatus( art ) {
281
347
  if (art._status === 'propagated' || art._status === 'propagating')
282
348
  return false;
283
- setProp( art, '_status', 'propagating' );
349
+ setLink( art, '_status', 'propagating' );
284
350
  return true;
285
351
  }
286
352
 
287
353
  function setEffectiveType( target, source ) {
288
354
  if ('_effectiveType' in source)
289
- setProp( target, '_effectiveType', source._effectiveType);
355
+ setLink( target, '_effectiveType', source._effectiveType);
290
356
  }
291
357
 
292
358
  module.exports = {