@sap/cds-compiler 3.8.0 → 3.8.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@
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 3.8.2 - 2023-03-30
11
+
12
+ ### Fixed
13
+
14
+ - parser: Identifiers that are keywords were not allowed in annotation values inside arrays
15
+ - compiler: Compatibility against cds-lsp was restored.
16
+ - to.sql/hdbcds/hdi/edm(x): Fix a crash for sub-queries inside nested expressions of on-conditions of JOINs.
17
+
10
18
  ## Version 3.8.0 - 2023-03-27
11
19
 
12
20
  ### Added
@@ -504,7 +504,7 @@ function assertConsistency( model, stage ) {
504
504
  ],
505
505
  },
506
506
  absolute: { test: isString },
507
- variant: { test: TODO }, // TODO: not set in CDL parser
507
+ variant: { requires: [ 'location', 'path' ] },
508
508
  element: { test: TODO }, // TODO: { test: isString },
509
509
  action: { test: isString },
510
510
  param: { test: TODO },
@@ -2,6 +2,8 @@
2
2
 
3
3
  'use strict';
4
4
 
5
+ const { CompilerAssertion } = require( '../base/error' );
6
+
5
7
  const dictKinds = {
6
8
  definitions: 'absolute',
7
9
  elements: 'element',
@@ -65,26 +67,26 @@ function propExists( prop, parent ) {
65
67
  }
66
68
 
67
69
  // Return the "old style" name structure with `absolute`, `action`, `param`,
68
- // `element`. Later we also need to add `select` and `alias`.
69
- // (Currently not needed, as only used for extend and annotate statements.)
70
+ // `element`. The following code makes use of the fact that only member extensions
71
+ // have a "sparse" name structure.
70
72
  function getArtifactName( art ) {
71
- if (!art.name || art.name.absolute)
73
+ if (!art.name || art.name.absolute) // no name or “old style”
72
74
  return art.name;
73
- // extend and annotate statement already have "sparse" names → calculate old one
74
- const link = art.name._artifact;
75
+ // extend and annotate statements as members already have "sparse" names → calculate old one
75
76
  const namePath = [];
76
- while (art._main && !art.name.absolute) { // until we hit an old-style name or the main artifact
77
- namePath.push( art );
78
- art = art._parent;
77
+ let parent = art;
78
+ while (parent._main) { // until we hit the main artifact
79
+ namePath.push( parent );
80
+ parent = parent._parent;
79
81
  }
80
82
  namePath.reverse();
81
- const name = { ...art.name };
83
+ // start with id/location of art.name, and absolute of art._main
84
+ const name = { id: art.name.id, location: art.name.location, absolute: parent.name.absolute };
82
85
  for (const np of namePath) {
83
86
  const prop = getMemberNameProp( np, np.kind );
84
87
  name[prop] = (name[prop]) ? `${ name[prop] }.${ np.name.id }` : np.name.id;
85
- name.id = np.name.id;
86
- name.location = np.name.location;
87
88
  }
89
+ const link = art.name._artifact;
88
90
  if (link !== undefined)
89
91
  Object.defineProperty( name, '_artifact', { value: link, configurable: true, writable: true } );
90
92
  return name;
@@ -103,7 +105,7 @@ function getMemberNameProp( elem, kind ) {
103
105
  obj = obj.items;
104
106
  if (obj.elements || obj.enum)
105
107
  return 'element';
106
- return 'id';
108
+ throw CompilerAssertion( `Member not found in parent properties ${ Object.keys( obj ).join('+') }` );
107
109
  }
108
110
 
109
111
  module.exports = {
@@ -188,6 +188,22 @@ function extend( model ) {
188
188
  model.extensions = Object.values( model.$lateExtensions );
189
189
  // TODO: testMode sort?
190
190
  model.extensions.forEach( createSuperAnnotate );
191
+ // set _artifact links for “main extensions” late as it would disturb the
192
+ // still existing old extend mechanism, see chooseAnnotationsInArtifact(),
193
+ // needed for LSP and friends:
194
+ Object.values( model.sources ).forEach( setArtifactLinkForExtensions );
195
+ Object.values( model.definitions ).forEach( setArtifactLinkForExtensions );
196
+ }
197
+
198
+ // TODO: delete again
199
+ function setArtifactLinkForExtensions( source ) {
200
+ if (!source.extensions)
201
+ return;
202
+ for (const ext of source.extensions ) {
203
+ const { name } = ext;
204
+ if (name?.absolute && name._artifact === undefined) // no link set yet
205
+ resolvePath( name, ext.kind, ext ); // for LSP
206
+ }
191
207
  }
192
208
 
193
209
  // For extendArtifactAfter(): -------------------------------------------------
@@ -1604,7 +1620,7 @@ function extend( model ) {
1604
1620
  delete model.$lateExtensions[absolute];
1605
1621
  // TODO: if the extension mechanism has been completed, we could uncomment:
1606
1622
  // art._extensions.forEach( ext => resolvePath( ext.name, ext.kind, ext )); // for LSP
1607
- // (if we do it now, the old extend functionality might think “already applied”)
1623
+ // for now, we do that at the end of lateExtensions()
1608
1624
  }
1609
1625
  }
1610
1626
  if (art._extensions) {
@@ -57,7 +57,8 @@ function fns( model ) {
57
57
  artItemsCount: Number.MAX_SAFE_INTEGER,
58
58
  undefinedDef: 'anno-undefined-def',
59
59
  undefinedArt: 'anno-undefined-art',
60
- allowAutoexposed: true,
60
+ allowAutoexposed: true, // TODO: think about Info/Warning
61
+ noMessageForLocalized: true, // TODO: should we issue a Debug message for code completion?
61
62
  },
62
63
  type: { // TODO: more detailed later (e.g. for enum base type?)
63
64
  envFn: artifactsEnv,
@@ -735,10 +736,12 @@ function fns( model ) {
735
736
  }
736
737
  else if (env.$frontend && env.$frontend !== 'cdl' || spec.global) {
737
738
  // IDE can inspect <model>.definitions - provide null for valid
738
- signalNotFound( spec.undefinedDef || 'ref-undefined-def', [ head.location, user ],
739
- valid, { art: head.id } );
739
+ if (!spec.noMessageForLocalized || !head.id.startsWith( 'localized.' )) {
740
+ signalNotFound( spec.undefinedDef || 'ref-undefined-def', [ head.location, user ],
741
+ valid, { art: head.id } );
742
+ }
740
743
  }
741
- else {
744
+ else if (!spec.noMessageForLocalized || head.id !== 'localized') {
742
745
  signalNotFound( spec.undefinedArt || 'ref-undefined-art', [ head.location, user ],
743
746
  valid, { name: head.id } );
744
747
  }
@@ -817,7 +820,7 @@ function fns( model ) {
817
820
  setTargetReferenceKey( orig.name.id, item );
818
821
  }
819
822
  art = sub;
820
- if (spec.envFn && (!artItemsCount || item === last) &&
823
+ if (spec.envFn && !spec.allowAutoexposed && (!artItemsCount || item === last) &&
821
824
  art && art.$inferred === 'autoexposed' && !user.$inferred) {
822
825
  // Depending on the processing sequence, the following could be a
823
826
  // simple 'ref-undefined-art'/'ref-undefined-def' - TODO: which we
@@ -1 +1 @@
1
- 371decdc6899d80e3420038878ed211c
1
+ 7b8ead4c652cf564b5ba45f94d2c45af