@sap/cds-compiler 4.9.8 → 4.9.10

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 4.9.10 - 2025-04-29
11
+
12
+ ### Fixed
13
+
14
+ - Added option `allowMixinInProjectionExtension` which allows referring to mixins in `extend projection`.
15
+ This was forbidden in cds-compiler v4, but re-introduced in v5.5. Users wanting to migrate from cds-compiler
16
+ v3 to v4 can use this option for easier migration.
17
+
10
18
  ## Version 4.9.8 - 2024-07-29
11
19
 
12
20
  ### Fixed
@@ -975,6 +975,12 @@ const centralMessageTexts = {
975
975
  none: 'Ambiguous $(ID) requires an explicit table alias, but there are none: add table aliases to all sub-queries to disambiguate $(ID)',
976
976
  },
977
977
 
978
+ 'ref-special-in-extend': {
979
+ std: 'In an added column, $(ID) refers to the element of the projection source $(ART), not the table alias or mixin',
980
+ alias: 'In an added column, $(ID) refers to the element of the projection source $(ART), not the table alias',
981
+ mixin: 'In an added column, $(ID) refers to the element of the projection source $(ART), not the mixin',
982
+ },
983
+
978
984
  'type-managed-composition': {
979
985
  std: 'Managed compositions can\'t be used in types', // yet
980
986
  sub: 'Managed compositions can\'t be used in sub elements',
@@ -175,7 +175,9 @@ function fns( model ) {
175
175
  having: 'where',
176
176
  groupBy: 'where',
177
177
  column: {
178
- lexical: tableAliasesIfNotExtendAndSelf,
178
+ lexical: (!options.allowMixinInProjectionExtension
179
+ ? tableAliasesIfNotExtendAndSelf // default for v4
180
+ : tableAliasesAndSelf), // default for v5 or via option
179
181
  dollar: true,
180
182
  dynamic: combinedSourcesOrParentElements,
181
183
  notFound: undefinedSourceElement,
@@ -629,7 +631,6 @@ function fns( model ) {
629
631
  // simple 'ref-undefined-art'/'ref-undefined-def' - TODO: which we
630
632
  // could "change" to this message at the end of compile():
631
633
  error( 'ref-unexpected-autoexposed', [ item.location, user ], { art },
632
- // eslint-disable-next-line max-len
633
634
  'An auto-exposed entity can\'t be referred to - expose entity $(ART) explicitly' );
634
635
  return null; // continuation semantics: like “not found”
635
636
  }
@@ -693,16 +694,49 @@ function fns( model ) {
693
694
  return setArtifactLink( head, def ); // we do not want to see the using
694
695
  }
695
696
  case 'mixin': {
697
+ if (options.allowMixinInProjectionExtension) { // for v5 compatibility
698
+ // use a source element having that name if in `extend … with columns`:
699
+ const elem = (user._user || user).$extended &&
700
+ art._parent._combined[head.id];
701
+ if (elem) {
702
+ path.$prefix = elem._parent.name.id; // prepend alias name
703
+ info( 'ref-special-in-extend', [ head.location, user ],
704
+ { '#': 'mixin', id: head.id, art: elem._origin._main } );
705
+ setLink( head, '_navigation', elem );
706
+ return setArtifactLink( head, elem._origin );
707
+ }
708
+ }
696
709
  return setLink( head, '_navigation', art );
697
710
  }
698
711
  case '$navElement': {
699
- if (head.id === (user._user || user).$extended)
700
- path.$prefix = head.id;
712
+ if (!options.allowMixinInProjectionExtension) { // for v5 compatibility
713
+ if (head.id === (user._user || user).$extended)
714
+ path.$prefix = head.id;
715
+ }
701
716
  setLink( head, '_navigation', art );
702
717
  return setArtifactLink( head, art._origin );
703
718
  }
704
- case '$self': // TODO: remove $projection from CC
705
719
  case '$tableAlias': {
720
+ if (options.allowMixinInProjectionExtension) { // for v5 compatibility
721
+ // use a source element having that name if in `extend … with columns`:
722
+ const { $extended } = user._user || user;
723
+ const elem = $extended && art.elements[head.id];
724
+ if (elem) {
725
+ path.$prefix = art.name.id; // prepend alias name
726
+ info('ref-special-in-extend', [ head.location, user ],
727
+ { '#': 'alias', id: head.id, art: elem._origin._main });
728
+ setLink( head, '_navigation', elem );
729
+ return setArtifactLink( head, elem._origin );
730
+ }
731
+ else if ($extended) {
732
+ warning( 'ref-deprecated-in-extend', [ head.location, user ], { id: head.id },
733
+ // eslint-disable-next-line max-len
734
+ 'In an added column, do not use the table alias $(ID) to refer to source elements' );
735
+ }
736
+ }
737
+ }
738
+ /* FALLTHROUGH */
739
+ case '$self': { // TODO: remove $projection from CC
706
740
  setLink( head, '_navigation', art );
707
741
  setArtifactLink( head, art._origin ); // query source or leading query in FROM
708
742
  if (!art._origin)
@@ -1113,7 +1147,7 @@ function fns( model ) {
1113
1147
  // TODO: if it becomes non-configurable, we can omit this warning
1114
1148
  let id = pathName( path );
1115
1149
  let head = path[0]._artifact || { _parent: art };
1116
- // eslint-disable-next-line no-cond-assign
1150
+
1117
1151
  while ((head = head?._parent) && head.kind === 'builtin')
1118
1152
  id = `${ head.name.id }.${ id }`;
1119
1153
  const msgId = (art.$uncheckedElements) ? 'ref-unknown-var' : 'ref-undefined-var';
@@ -1635,7 +1669,7 @@ function fns( model ) {
1635
1669
  const txt = index >= path.length
1636
1670
  ? 'complete'
1637
1671
  : (isAssocToPrimaryKeys( assoc ) ? 'keys' : 'std');
1638
- // eslint-disable-next-line max-len
1672
+
1639
1673
  error( 'ref-invalid-navigation', [ last.location, user ], {
1640
1674
  '#': msgPrefix + txt, art: assoc, name: last.id, alias: '$self',
1641
1675
  }, {
@@ -1192,7 +1192,9 @@ function exprInternal( node, xprParens ) {
1192
1192
  }
1193
1193
  if (node.path) {
1194
1194
  const ref = node.path.map( pathItem );
1195
- if (node.path.$prefix) // auto-corrected ORDER BY refs without table alias
1195
+ // auto-corrected ORDER BY refs without table alias, or EXTEND … WITH COLUMN
1196
+ // refs to source element shadowed by alias name:
1197
+ if (node.path.$prefix)
1196
1198
  ref.unshift( node.path.$prefix );
1197
1199
  // we would need to consider node.global here if we introduce that
1198
1200
  return extra( { ref }, node );
package/lib/main.d.ts CHANGED
@@ -131,6 +131,15 @@ declare namespace compiler {
131
131
  * @since v2.8.0
132
132
  */
133
133
  addTextsLanguageAssoc?: boolean
134
+ /**
135
+ * Allow referring to mixins in `extend projection` clauses.
136
+ * This was allowed in cds-compiler v3, forbidden in v4, and allowed in v5.5 by default again.
137
+ *
138
+ * @default false
139
+ * @since v4.9.10
140
+ * @until v4.9.10
141
+ */
142
+ allowMixinInProjectionExtension?: boolean
134
143
  /**
135
144
  * An array of directory names that are used for CDS module lookups.
136
145
  * Lookup directory `node_modules/` is appended if not set explicitly.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "4.9.8",
3
+ "version": "4.9.10",
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)",