@sap/cds-compiler 2.12.0 → 2.13.6

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 (118) hide show
  1. package/CHANGELOG.md +110 -15
  2. package/bin/cdsc.js +13 -13
  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 +28 -63
  8. package/lib/api/options.js +3 -3
  9. package/lib/api/validate.js +0 -5
  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 +25 -4
  16. package/lib/base/messages.js +16 -26
  17. package/lib/base/model.js +2 -63
  18. package/lib/base/optionProcessorHelper.js +158 -123
  19. package/lib/checks/annotationsOData.js +1 -1
  20. package/lib/checks/cdsPersistence.js +2 -1
  21. package/lib/checks/enricher.js +17 -1
  22. package/lib/checks/invalidTarget.js +3 -1
  23. package/lib/checks/managedWithoutKeys.js +3 -1
  24. package/lib/checks/selectItems.js +4 -4
  25. package/lib/checks/sql-snippets.js +27 -26
  26. package/lib/checks/types.js +1 -1
  27. package/lib/checks/validator.js +4 -7
  28. package/lib/compiler/assert-consistency.js +5 -3
  29. package/lib/compiler/builtins.js +8 -6
  30. package/lib/compiler/checks.js +14 -3
  31. package/lib/compiler/cycle-detector.js +1 -1
  32. package/lib/compiler/define.js +1103 -0
  33. package/lib/compiler/extend.js +983 -0
  34. package/lib/compiler/finalize-parse-cdl.js +231 -0
  35. package/lib/compiler/index.js +32 -13
  36. package/lib/compiler/kick-start.js +190 -0
  37. package/lib/compiler/moduleLayers.js +4 -4
  38. package/lib/compiler/populate.js +1226 -0
  39. package/lib/compiler/propagator.js +111 -46
  40. package/lib/compiler/resolve.js +1433 -0
  41. package/lib/compiler/shared.js +64 -37
  42. package/lib/compiler/tweak-assocs.js +529 -0
  43. package/lib/compiler/utils.js +197 -33
  44. package/lib/edm/.eslintrc.json +5 -0
  45. package/lib/edm/annotations/genericTranslation.js +5 -9
  46. package/lib/edm/annotations/preprocessAnnotations.js +2 -2
  47. package/lib/edm/csn2edm.js +9 -8
  48. package/lib/edm/edm.js +11 -12
  49. package/lib/edm/edmPreprocessor.js +137 -73
  50. package/lib/edm/edmUtils.js +116 -22
  51. package/lib/gen/Dictionary.json +10 -3
  52. package/lib/gen/language.checksum +1 -1
  53. package/lib/gen/language.interp +9 -1
  54. package/lib/gen/language.tokens +86 -83
  55. package/lib/gen/languageLexer.interp +10 -1
  56. package/lib/gen/languageLexer.js +860 -833
  57. package/lib/gen/languageLexer.tokens +78 -75
  58. package/lib/gen/languageParser.js +5282 -4265
  59. package/lib/json/from-csn.js +12 -1
  60. package/lib/json/to-csn.js +126 -66
  61. package/lib/language/docCommentParser.js +2 -2
  62. package/lib/language/genericAntlrParser.js +76 -3
  63. package/lib/language/language.g4 +297 -130
  64. package/lib/language/multiLineStringParser.js +5 -5
  65. package/lib/main.d.ts +468 -59
  66. package/lib/main.js +35 -9
  67. package/lib/model/api.js +3 -1
  68. package/lib/model/csnRefs.js +225 -156
  69. package/lib/model/csnUtils.js +192 -223
  70. package/lib/model/enrichCsn.js +70 -29
  71. package/lib/model/revealInternalProperties.js +27 -6
  72. package/lib/model/sortViews.js +2 -1
  73. package/lib/modelCompare/compare.js +17 -12
  74. package/lib/optionProcessor.js +5 -4
  75. package/lib/render/manageConstraints.js +35 -32
  76. package/lib/render/toCdl.js +73 -288
  77. package/lib/render/toHdbcds.js +25 -23
  78. package/lib/render/toSql.js +98 -41
  79. package/lib/render/utils/common.js +5 -10
  80. package/lib/render/utils/sql.js +4 -3
  81. package/lib/render/utils/stringEscapes.js +111 -0
  82. package/lib/sql-identifier.js +1 -1
  83. package/lib/transform/.eslintrc.json +5 -0
  84. package/lib/transform/db/.eslintrc.json +2 -0
  85. package/lib/transform/db/applyTransformations.js +35 -12
  86. package/lib/transform/db/assertUnique.js +1 -1
  87. package/lib/transform/db/associations.js +103 -305
  88. package/lib/transform/db/cdsPersistence.js +2 -2
  89. package/lib/transform/db/constraints.js +55 -52
  90. package/lib/transform/db/expansion.js +46 -24
  91. package/lib/transform/db/flattening.js +553 -102
  92. package/lib/transform/db/groupByOrderBy.js +3 -1
  93. package/lib/transform/db/transformExists.js +59 -6
  94. package/lib/transform/db/views.js +5 -4
  95. package/lib/transform/draft/.eslintrc.json +38 -0
  96. package/lib/transform/{db/draft.js → draft/db.js} +6 -5
  97. package/lib/transform/draft/odata.js +227 -0
  98. package/lib/transform/forHanaNew.js +67 -183
  99. package/lib/transform/forOdataNew.js +17 -171
  100. package/lib/transform/localized.js +34 -19
  101. package/lib/transform/odata/generateForeignKeyElements.js +1 -1
  102. package/lib/transform/odata/referenceFlattener.js +95 -89
  103. package/lib/transform/odata/structureFlattener.js +1 -1
  104. package/lib/transform/odata/toFinalBaseType.js +86 -12
  105. package/lib/transform/odata/typesExposure.js +5 -5
  106. package/lib/transform/odata/utils.js +2 -2
  107. package/lib/transform/transformUtilsNew.js +36 -22
  108. package/lib/transform/translateAssocsToJoins.js +2 -19
  109. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  110. package/lib/transform/universalCsn/coreComputed.js +170 -0
  111. package/lib/transform/universalCsn/universalCsnEnricher.js +715 -0
  112. package/lib/transform/universalCsn/utils.js +63 -0
  113. package/lib/utils/objectUtils.js +30 -0
  114. package/package.json +1 -1
  115. package/share/messages/README.md +26 -0
  116. package/lib/compiler/definer.js +0 -2361
  117. package/lib/compiler/resolver.js +0 -3079
  118. 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 ) {
@@ -116,12 +124,13 @@ function propagate( model ) {
116
124
  }
117
125
  if (obj.items)
118
126
  run( obj.items );
119
- setProp( art, '_status', 'propagated' );
127
+ setLink( art, '_status', 'propagated' );
120
128
  }
121
129
 
122
130
  function step({ target, source }) {
123
- // console.log('PROPS:',source&&refString(source),'->',refString(target))
124
- 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');
125
134
  const keys = Object.keys( source );
126
135
  for (const prop of keys) {
127
136
  if (prop in target) // TODO: warning with competing props from multi-includes
@@ -130,8 +139,10 @@ function propagate( model ) {
130
139
  if (transformer)
131
140
  transformer( prop, target, source, viaType );
132
141
  }
133
- // propagate NOT NULL and VIRTUAL from sub elements:
134
- if (target.$inferred !== 'proxy' &&
142
+ // propagate NOT NULL and VIRTUAL from sub elements with
143
+ // 'deprecated.oldVirtualNotNullPropagation':
144
+ if (oldVirtualNotNullPropagation &&
145
+ target.$inferred !== 'proxy' &&
135
146
  target.kind === 'element' && source.kind === 'element') {
136
147
  let elem = source; // the outer element
137
148
  while (elem._parent.kind === 'element')
@@ -143,7 +154,7 @@ function propagate( model ) {
143
154
  props.virtual( 'virtual', target, elem );
144
155
  }
145
156
  }
146
- // setProp( target, '_status', 'shallow-propagated' );
157
+ // setLink( target, '_status', 'shallow-propagated' );
147
158
  }
148
159
 
149
160
  function never() { /* no-op: don't propagate */ }
@@ -154,12 +165,16 @@ function propagate( model ) {
154
165
  target[prop] = [ ...val ];
155
166
  target[prop].$inferred = 'prop';
156
167
  }
157
- else if ('_artifact' in val) {
158
- target[prop] = Object.assign( { $inferred: 'prop' }, val );
159
- setProp( target[prop], '_artifact', val._artifact );
160
- }
161
168
  else {
162
- 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 );
163
178
  }
164
179
  }
165
180
 
@@ -178,10 +193,18 @@ function propagate( model ) {
178
193
 
179
194
  // Expensive properties are not really propagated if they can be directly
180
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`
181
202
  function expensive( prop, target, source ) {
182
203
  // console.log(prop,source.name,'->',target.kind,target.name);
183
204
  if (source.kind === 'builtin')
184
205
  return;
206
+ if (target.expand) // do not propagate `keys` with expand
207
+ return;
185
208
  if (prop !== 'foreignKeys' && availableAtType( prop, target, source ))
186
209
  // foreignKeys must always be copied with target to avoid any confusion
187
210
  // whether we have to generated implicit keys
@@ -200,47 +223,88 @@ function propagate( model ) {
200
223
  }
201
224
  }
202
225
 
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
226
  function onlyViaParent( prop, target, source ) {
217
227
  if (target.$inferred === 'proxy' || target.$inferred === 'expand-element')
218
228
  // assocs and enums do not have 'include'
219
229
  always( prop, target, source );
220
230
  }
221
231
 
232
+ function notWithExpand( prop, target, source ) {
233
+ if (!target.expand)
234
+ always( prop, target, source );
235
+ }
236
+
222
237
  function notWithPersistenceTable( prop, target, source ) {
223
238
  const tableAnno = target['@cds.persistence.table'];
224
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)
225
246
  withKind( prop, target, source );
226
247
  }
227
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
+
228
255
  function withKind( prop, target, source ) {
229
256
  if (target.kind && (!target._parent || target._parent.returns !== target))
230
257
  always( prop, target, source ); // not in 'returns' and 'items'
231
258
  }
232
259
 
233
260
  function notNull( prop, target, source, viaType ) {
234
- 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)
235
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
+ }
236
300
  }
237
301
 
238
302
  function returns( prop, target, source, ok ) {
239
303
  if (ok || target.$inferred === 'proxy' || target.$inferred === 'include' ) {
240
304
  target[prop] = { $inferred: 'proxy' };
241
305
  setEffectiveType( target[prop], source[prop] );
242
- setProp( target[prop], '_origin', source[prop] );
243
- 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
244
308
  }
245
309
  }
246
310
 
@@ -262,7 +326,8 @@ function targetMinZero( art ) {
262
326
 
263
327
  function getOrigin( art ) {
264
328
  if (art._origin)
265
- 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;
266
331
  // Remark: a column with an 'inline' is never an element -> no need to check
267
332
  // art.inline
268
333
  if (art._from && art._from.length) { // query
@@ -273,7 +338,7 @@ function getOrigin( art ) {
273
338
  : tabref;
274
339
  }
275
340
 
276
- return (art.type && !art.type.$inferred)
341
+ return (art.type && (!art.type.$inferred || art.type.$inferred === 'cast'))
277
342
  ? art.type._artifact
278
343
  : art._origin;
279
344
  }
@@ -281,13 +346,13 @@ function getOrigin( art ) {
281
346
  function checkAndSetStatus( art ) {
282
347
  if (art._status === 'propagated' || art._status === 'propagating')
283
348
  return false;
284
- setProp( art, '_status', 'propagating' );
349
+ setLink( art, '_status', 'propagating' );
285
350
  return true;
286
351
  }
287
352
 
288
353
  function setEffectiveType( target, source ) {
289
354
  if ('_effectiveType' in source)
290
- setProp( target, '_effectiveType', source._effectiveType);
355
+ setLink( target, '_effectiveType', source._effectiveType);
291
356
  }
292
357
 
293
358
  module.exports = {