@sap/cds-compiler 4.4.0 → 4.4.4

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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@
7
7
  Note: `beta` fixes, changes and features are usually not listed in this ChangeLog but [here](doc/CHANGELOG_BETA.md).
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
 
10
+ ## Version 4.4.4 - 2023-11-24
11
+
12
+ ### Fixed
13
+
14
+ - to.hdi.migration: Changes in only `doc`-comments should not result in a drop-create of the primary key.
15
+
16
+ ## Version 4.4.2 - 2023-11-17
17
+
18
+ ### Fixed
19
+
20
+ - for.odata: Fix crash when using a projection with associations as action parameter type.
21
+ - to.edm(x): `Edm.AnyPropertyPath` is hard to `Edm.PropertyPath`. As there is no dynamic path evaluation,
22
+ `Edm.NavigationPropertyPath` must be enforced via `$edmJson`.
23
+ `Edm.AnyPropertyPath` has been used in `@Aggregation.ApplySupported.GroupableProperties` for the first
24
+ time after vocabulary update with [4.4.0](#version-440---2023-11-09).
25
+
10
26
  ## Version 4.4.0 - 2023-11-09
11
27
 
12
28
  ### Added
@@ -31,7 +31,22 @@ const $location = Symbol.for( 'cds.$location' );
31
31
  // attach stupid location - TODO: remove in v5
32
32
  const genLocation = new CsnLocation( '' );
33
33
 
34
- // Array.prototype.spread = 42; // prototype-polluted JS classes
34
+ const draftElements = [
35
+ 'IsActiveEntity',
36
+ 'HasActiveEntity',
37
+ 'HasDraftEntity',
38
+ 'DraftAdministrativeData',
39
+ 'SiblingEntity',
40
+ ];
41
+ const draftBoundActions = [
42
+ 'draftPrepare',
43
+ 'draftActivate',
44
+ 'draftEdit',
45
+ ];
46
+
47
+ function canBeDraftMember( name, parent, draftMembers ) {
48
+ return parent?.kind === 'entity' && parent._service && draftMembers.includes( name );
49
+ }
35
50
 
36
51
  function extend( model ) {
37
52
  // Get simplified "resolve" functionality and the message function:
@@ -718,7 +733,9 @@ function extend( model ) {
718
733
  'Parameters only exist for actions or functions' );
719
734
  break;
720
735
  case 'actions':
721
- // TODO: use extra text variant and location of dictionary
736
+ if (canBeDraftMember( name, parent, draftBoundActions ))
737
+ return true;
738
+ // TODO: use extra text variant and location of dictionary - no
722
739
  notFound( 'ext-undefined-action', ext.name.location, ext,
723
740
  { '#': 'action', art: parent, name } );
724
741
  break;
@@ -734,6 +751,8 @@ function extend( model ) {
734
751
  const art = inReturns || parent;
735
752
  switch (prop) {
736
753
  case 'elements':
754
+ if (canBeDraftMember( name, parent, draftElements ))
755
+ break;
737
756
  notFound( 'ext-undefined-element', ext.name.location, ext,
738
757
  { '#': (inReturns ? 'returns' : 'element'), art, name },
739
758
  parent.elements );
@@ -749,6 +768,8 @@ function extend( model ) {
749
768
  parent.params );
750
769
  break;
751
770
  case 'actions':
771
+ if (canBeDraftMember( name, parent, draftBoundActions ))
772
+ break;
752
773
  notFound( 'ext-undefined-action', ext.name.location, ext,
753
774
  { '#': 'action', art: parent, name },
754
775
  parent.actions );
@@ -934,14 +934,24 @@ function fns( model ) {
934
934
  // TODO: improve text, use text variant for: "or builtin" or "definitions" or none
935
935
  }
936
936
 
937
- function undefinedForAnnotate( user, item, valid, _dict, prev ) {
937
+ function undefinedForAnnotate( user, item, valid, _dict, prev, path ) {
938
938
  // in a CSN source, only one env was tested (valid.length 1):
939
939
  const art = (!prev) ? item.id : searchName( prev, item.id, 'absolute' );
940
+ if (!user.elements && !user.actions && !user.enum && !user.params &&
941
+ couldBeDraftsEntity( item.id, valid, prev, path ))
942
+ return;
940
943
  signalNotFound( (valid.length > 1 ? 'ext-undefined-art' : 'ext-undefined-def'),
941
944
  // TODO: ext-undefined-xyz
942
945
  [ item.location, user ], valid, { art } );
943
946
  }
944
947
 
948
+ function couldBeDraftsEntity( id, valid, prev, path ) {
949
+ const entity = prev
950
+ ? prev === path[path.length - 2]._artifact && prev
951
+ : path.length === 1 && id.endsWith( '.drafts' ) && model.definitions[id.slice( 0, -7 )];
952
+ return entity?.kind === 'entity' && !!entity._service;
953
+ }
954
+
945
955
  function undefinedParam( user, head, valid, _dict, _art, _path, semantics ) {
946
956
  // TODO: text variant if there are no parameters, or in artifactParameters()
947
957
  // TODO: use prepared message variants
@@ -246,7 +246,15 @@ const EdmPrimitiveTypeMap = {
246
246
  },
247
247
  // 'Edm.Untyped': { v4: true, desc: 'Abstract void type' },
248
248
  };
249
+ const EdmPathTypeMap = {
250
+ 'Edm.AnnotationPath': 1,
251
+ 'Edm.PropertyPath': 1,
252
+ 'Edm.NavigationPropertyPath': 1,
253
+ 'Edm.AnyPropertyPath': 1,
254
+ 'Edm.ModelElementPath': 1,
255
+ 'Edm.Path': 1,
256
+ };
249
257
 
250
258
  module.exports = {
251
- EdmTypeFacetMap, EdmTypeFacetNames, EdmPrimitiveTypeMap,
259
+ EdmTypeFacetMap, EdmTypeFacetNames, EdmPrimitiveTypeMap, EdmPathTypeMap,
252
260
  };
@@ -8,6 +8,7 @@ const { forEachDefinition } = require('../../model/csnUtils');
8
8
  const { isBetaEnabled, setProp } = require('../../base/model.js');
9
9
  const { xpr2edmJson, getEdmJsonHandler } = require('./edmJson.js');
10
10
  const { vocabularyDefinitions } = require('./vocabularyDefinitions.js');
11
+ const { EdmPathTypeMap } = require('../EdmPrimitiveTypeDefinitions.js');
11
12
 
12
13
  /** ************************************************************************************************
13
14
  * csn2annotationEdm
@@ -940,8 +941,12 @@ function csn2annotationEdm( reqDefs, csnVocabularies, serviceName,
940
941
  // note: expr can also be provided if an enum/complex type/collection is expected
941
942
  function handleExpression( value, dTypeName ) {
942
943
  let typeName = 'Path';
943
- if ( [ 'Edm.AnnotationPath', 'Edm.ModelElementPath', 'Edm.NavigationPropertyPath', 'Edm.PropertyPath', 'Edm.Path' ].includes(dTypeName) )
944
- typeName = dTypeName.split('.')[1];
944
+ if ( EdmPathTypeMap[dTypeName] ) {
945
+ if (dTypeName === 'Edm.AnyPropertyPath')
946
+ typeName = 'PropertyPath';
947
+ else
948
+ typeName = dTypeName.split('.')[1];
949
+ }
945
950
 
946
951
  if (value) {
947
952
  // replace all occurrences of '.' by '/' up to first '@'
@@ -190,7 +190,7 @@ function getExtensionAndMigrations(beforeModel, options, { extensions, migration
190
190
  migration.change = changedElements;
191
191
  if(!hasPrimaryKeyChange)
192
192
  forEach(changedElements, (_name, change) => {
193
- if((change.old.key || change.new.key) && !change.new.target && !change.old.target) {
193
+ if(!change.onlyDoc && (change.old.key || change.new.key) && !change.new.target && !change.old.target) {
194
194
  // For to.hdi.migration: Just drop-create (commented out), for to.sql.migration: Handle case where we add/remove "key" keyword, no drop-create otherwise
195
195
  if(options.sqlDialect === 'hana' && options.src === 'hdi' || (!change.old.key || !change.new.key)) {
196
196
  hasPrimaryKeyChange = true;
@@ -276,6 +276,8 @@ function getElementComparator(otherArtifact, addedElementsDict = null, changedEl
276
276
  element.$notNull = false; // Explicitly set notNull to the implicit default so we render the correct ALTER
277
277
  }
278
278
  changedElementsDict[name] = changedElement(element, otherElement);
279
+ } else if(docCommentChanged(element, otherElement)) {
280
+ changedElementsDict[name] = { ...changedElement(element, otherElement), onlyDoc: true };
279
281
  }
280
282
 
281
283
  return;
@@ -356,6 +358,9 @@ function deepEqual(a, b, include = () => true, depth = 0) {
356
358
  : a === b;
357
359
  }
358
360
 
361
+ function docCommentChanged(element, otherElement) {
362
+ return element.doc && !otherElement.doc || otherElement.doc && !element.doc || element.doc && element.doc !== otherElement.doc;
363
+ }
359
364
 
360
365
  const relevantProperties = {
361
366
  'doc': true,
@@ -364,7 +369,8 @@ const relevantProperties = {
364
369
  };
365
370
 
366
371
  /**
367
- * Returns whether any type parameters differ between two given elements. Ignores whether types themselves differ (`type` property).
372
+ * Returns whether any type parameters differ between two given elements. Ignores whether types themselves differ (`type` property) and ignores
373
+ * diff in doc comments.
368
374
  * @param element {object} an element
369
375
  * @param otherElement {object} another element
370
376
  * @returns {boolean}
@@ -373,7 +379,7 @@ function typeParametersChanged(element, otherElement) {
373
379
  const checked = new Set();
374
380
  for (const key in element) {
375
381
  if (Object.prototype.hasOwnProperty.call(element, key))
376
- if((!key.startsWith('@') || relevantProperties[key]) && key !== 'type') {
382
+ if((!key.startsWith('@') || relevantProperties[key]) && key !== 'type' && key !== 'doc') {
377
383
  checked.add(key);
378
384
  if(!deepEqual(element[key], otherElement[key]))
379
385
  return true;
@@ -382,7 +388,7 @@ function typeParametersChanged(element, otherElement) {
382
388
 
383
389
  for (const key in otherElement) {
384
390
  if (Object.prototype.hasOwnProperty.call(otherElement, key))
385
- if((!key.startsWith('@') || relevantProperties[key]) && key !== 'type' && !checked.has(key))
391
+ if((!key.startsWith('@') || relevantProperties[key]) && key !== 'type' && key !== 'doc' && !checked.has(key))
386
392
  return true;
387
393
  }
388
394
 
@@ -98,7 +98,9 @@ function transform4odataWithCsn(inputModel, options) {
98
98
  inspectRef,
99
99
  artifactRef,
100
100
  effectiveType,
101
- getFinalTypeInfo
101
+ getFinalTypeInfo,
102
+ dropDefinitionCache,
103
+ initDefinition,
102
104
  } = csnUtils;
103
105
 
104
106
  // are we working with structured OData or not
@@ -147,6 +149,8 @@ function transform4odataWithCsn(inputModel, options) {
147
149
  // TODO: handle artifact.projection instead of artifact.query correctly in future V2
148
150
  if (def.kind === 'entity' && def.projection) {
149
151
  def.query = { SELECT: def.projection };
152
+ dropDefinitionCache(def);
153
+ initDefinition(def);
150
154
  }
151
155
  }],
152
156
  { skipArtifact: isExternalServiceMember }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "4.4.0",
3
+ "version": "4.4.4",
4
4
  "description": "CDS (Core Data Services) compiler and backends",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "author": "SAP SE (https://www.sap.com)",