@sap/cds-compiler 6.7.3 → 6.9.0

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 (116) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/README.md +4 -0
  3. package/bin/cdsc.js +5 -5
  4. package/bin/cdshi.js +1 -0
  5. package/bin/cdsse.js +1 -1
  6. package/lib/api/main.js +17 -9
  7. package/lib/api/options.js +5 -2
  8. package/lib/api/validate.js +1 -1
  9. package/lib/base/builtins.js +13 -9
  10. package/lib/{model → base}/csnRefs.js +8 -10
  11. package/lib/base/error.js +2 -0
  12. package/lib/base/message-registry.js +68 -4
  13. package/lib/base/messages.js +4 -2
  14. package/lib/{optionProcessor.js → base/optionProcessor.js} +5 -3
  15. package/lib/base/{model.js → specialOptions.js} +16 -39
  16. package/lib/checks/arrayOfs.js +1 -1
  17. package/lib/checks/elements.js +1 -1
  18. package/lib/checks/enricher.js +2 -2
  19. package/lib/checks/featureFlags.js +54 -24
  20. package/lib/checks/foreignKeys.js +1 -1
  21. package/lib/checks/invalidTarget.js +1 -1
  22. package/lib/checks/managedInType.js +1 -1
  23. package/lib/checks/onConditions.js +1 -1
  24. package/lib/checks/queryNoDbArtifacts.js +1 -1
  25. package/lib/checks/validator.js +10 -14
  26. package/lib/compiler/assert-consistency.js +11 -9
  27. package/lib/compiler/base.js +5 -1
  28. package/lib/compiler/builtins.js +1 -1
  29. package/lib/compiler/checks.js +3 -3
  30. package/lib/compiler/define.js +6 -3
  31. package/lib/{base → compiler}/dictionaries.js +4 -3
  32. package/lib/compiler/extend.js +121 -21
  33. package/lib/compiler/generate.js +2 -2
  34. package/lib/compiler/index.js +11 -3
  35. package/lib/compiler/kick-start.js +1 -1
  36. package/lib/compiler/lsp-api.js +3 -3
  37. package/lib/compiler/populate.js +6 -7
  38. package/lib/compiler/resolve.js +53 -36
  39. package/lib/compiler/shared.js +68 -18
  40. package/lib/compiler/tweak-assocs.js +2 -2
  41. package/lib/compiler/utils.js +28 -27
  42. package/lib/compiler/xpr-rewrite.js +3 -3
  43. package/lib/edm/EdmPrimitiveTypeDefinitions.js +4 -1
  44. package/lib/edm/annotations/edmJson.js +2 -4
  45. package/lib/edm/annotations/genericTranslation.js +51 -7
  46. package/lib/edm/csn2edm.js +3 -2
  47. package/lib/edm/edmAnnoPreprocessor.js +1 -1
  48. package/lib/edm/edmInboundChecks.js +2 -1
  49. package/lib/edm/edmPreprocessor.js +3 -3
  50. package/lib/edm/edmUtils.js +2 -2
  51. package/lib/gen/BaseParser.js +59 -108
  52. package/lib/gen/CdlGrammar.checksum +1 -1
  53. package/lib/gen/CdlParser.js +2052 -1965
  54. package/lib/gen/Dictionary.json +67 -7
  55. package/lib/json/from-csn.js +14 -14
  56. package/lib/json/to-csn.js +77 -38
  57. package/lib/main.js +3 -3
  58. package/lib/model/csnUtils.js +2 -2
  59. package/lib/modelCompare/compare.js +1 -1
  60. package/lib/modelCompare/utils/filter.js +1 -0
  61. package/lib/parsers/AstBuildingParser.js +83 -33
  62. package/lib/parsers/index.js +1 -1
  63. package/lib/render/manageConstraints.js +1 -1
  64. package/lib/render/toCdl.js +49 -30
  65. package/lib/render/toHdbcds.js +2 -2
  66. package/lib/render/toSql.js +16 -7
  67. package/lib/render/utils/common.js +11 -3
  68. package/lib/render/utils/sql.js +14 -5
  69. package/lib/render/utils/standardDatabaseFunctions.js +108 -99
  70. package/lib/sql-identifier.js +9 -1
  71. package/lib/{model → tool-lib}/enrichCsn.js +3 -2
  72. package/lib/{model → tool-lib}/revealInternalProperties.js +2 -1
  73. package/lib/transform/addTenantFields.js +1 -1
  74. package/lib/transform/db/applyTransformations.js +1 -1
  75. package/lib/transform/db/assertUnique.js +1 -1
  76. package/lib/transform/db/assocsToQueries/transformExists.js +1 -1
  77. package/lib/transform/db/backlinks.js +2 -2
  78. package/lib/transform/db/expansion.js +2 -2
  79. package/lib/transform/db/flattening.js +3 -4
  80. package/lib/transform/db/killAnnotations.js +1 -0
  81. package/lib/transform/db/processSqlServices.js +2 -1
  82. package/lib/transform/db/rewriteCalculatedElements.js +2 -2
  83. package/lib/transform/db/temporal.js +30 -5
  84. package/lib/transform/db/views.js +16 -20
  85. package/lib/transform/draft/db.js +1 -2
  86. package/lib/transform/effective/associations.js +1 -1
  87. package/lib/transform/effective/flattening.js +6 -5
  88. package/lib/transform/effective/main.js +24 -4
  89. package/lib/transform/effective/types.js +1 -1
  90. package/lib/transform/{odata/fioriTreeViews.js → fioriTreeViews.js} +48 -25
  91. package/lib/transform/forOdata.js +25 -7
  92. package/lib/transform/forRelationalDB.js +48 -12
  93. package/lib/transform/localized.js +2 -2
  94. package/lib/transform/odata/createForeignKeys.js +1 -1
  95. package/lib/transform/odata/flattening.js +2 -2
  96. package/lib/transform/odata/toFinalBaseType.js +3 -2
  97. package/lib/transform/odata/typesExposure.js +3 -2
  98. package/lib/transform/transformUtils.js +2 -2
  99. package/lib/transform/translateAssocsToJoins.js +2 -1
  100. package/lib/transform/tupleExpansion.js +44 -4
  101. package/lib/transform/universalCsn/universalCsnEnricher.js +7 -3
  102. package/lib/transform/universalCsn/utils.js +1 -1
  103. package/lib/{base → utils}/lazyload.js +9 -0
  104. package/lib/{base → utils}/node-helpers.js +2 -0
  105. package/lib/utils/objectUtils.js +29 -6
  106. package/lib/{base → utils}/optionProcessorHelper.js +16 -6
  107. package/package.json +3 -40
  108. /package/lib/{model → base}/cloneCsn.js +0 -0
  109. /package/lib/{model/api.js → base/model-api.js} +0 -0
  110. /package/lib/{api → base}/trace.js +0 -0
  111. /package/lib/{model → base}/xprAsTree.js +0 -0
  112. /package/lib/{inspect → tool-lib}/index.js +0 -0
  113. /package/lib/{inspect → tool-lib}/inspectModelStatistics.js +0 -0
  114. /package/lib/{inspect → tool-lib}/inspectPropagation.js +0 -0
  115. /package/lib/{inspect → tool-lib}/inspectUtils.js +0 -0
  116. /package/lib/{base → utils}/shuffle.js +0 -0
@@ -1,15 +1,10 @@
1
- // module- and csn/XSN-independent definitions
1
+ // Definitions for beta and deprecated options
2
2
 
3
- // TODO: move XSN-specific things to lib/compiler/utils/
4
- // TODO: move CSN-specific things to ???
3
+ // Normal options are in ../base/optionProcessor.js (and some other files),
4
+ // unfortunately partly non-grep-able (option `fooBar` is defined via `--foo-bar`)
5
5
 
6
6
  'use strict';
7
7
 
8
- const { forEach } = require('../utils/objectUtils');
9
-
10
- // Normal options are in ../optionProcessor.js (and some other files),
11
- // unfortunately partly non-grep-able (option `fooBar` is defined via `--foo-bar`)
12
-
13
8
  /**
14
9
  * Object of all available beta flags that will be enabled/disabled by `--beta-mode`
15
10
  * through cdsc. Only intended for INTERNAL USE.
@@ -47,12 +42,12 @@ const availableDeprecatedFlags = {
47
42
  ignoreSpecifiedQueryElements: true,
48
43
  };
49
44
 
50
- // Deprecated flags that were removed in v5.
51
- const oldDeprecatedFlagsV5 = [
52
- 'includesNonShadowedFirst',
53
- 'eagerPersistenceForGeneratedEntities',
54
- 'noKeyPropagationWithExpansions',
55
- ];
45
+ // Deprecated flags that were removed in newer version and are complained about.
46
+ const oldDeprecatedFlags = {
47
+ includesNonShadowedFirst: true,
48
+ eagerPersistenceForGeneratedEntities: true,
49
+ noKeyPropagationWithExpansions: true,
50
+ };
56
51
 
57
52
  /**
58
53
  * Test for early-adaptor feature, stored in option `beta`(new-style) / `betaMode`(old-style)
@@ -98,48 +93,30 @@ function isDeprecatedEnabled( options, feature = null ) {
98
93
  }
99
94
 
100
95
  /**
101
- * In cds-compiler v3, we removed old v2 deprecated flags. That can lead to silent
96
+ * In the current cds-compiler, we might have removed old deprecated flags. That can lead to silent
102
97
  * errors such as entity/view names changing. To ensure that the user is forced
103
98
  * to change their code, emit an error if one of such removed flags was used.
104
99
  *
105
100
  * @param {CSN.Options} options
106
101
  * @param error Error message function returned by makeMessageFunction().
107
102
  */
108
- function checkRemovedDeprecatedFlags( options, { error } ) {
103
+ function checkRemovedDeprecatedFlags( { deprecated, messages }, { error } ) {
109
104
  // Assume that we emitted these errors once if a message with this ID was found.
110
- if (!options.deprecated || options.messages?.some(m => m.messageId === 'api-invalid-deprecated'))
105
+ if (!deprecated || messages?.some( m => m.messageId === 'api-invalid-deprecated' ))
111
106
  return;
112
107
 
113
- forEach(options.deprecated, (key, val) => {
114
- if (val && oldDeprecatedFlagsV5.includes(key)) {
115
- error('api-invalid-deprecated', null, { name: key },
116
- 'Deprecated flag $(NAME) has been removed in CDS compiler v6');
108
+ Object.keys( deprecated ).forEach( ( key ) => {
109
+ if (deprecated[key] && oldDeprecatedFlags[key]) { // why testing the value of the option?
110
+ error( 'api-invalid-deprecated', null, { name: key },
111
+ 'Deprecated flag $(NAME) has been removed in CDS compiler v6' );
117
112
  }
118
113
  });
119
114
  }
120
115
 
121
- /**
122
- * Like `obj.prop = value`, but not contained in JSON / CSN
123
- * It's important to set enumerable explicitly to false (although 'false' is the default),
124
- * as else, if the property already exists, it keeps the old setting for enumerable.
125
- *
126
- * @param {object} obj
127
- * @param {string} prop
128
- * @param {any} value
129
- */
130
- function setProp( obj, prop, value ) {
131
- const descriptor = {
132
- value, configurable: true, writable: true, enumerable: false,
133
- };
134
- Object.defineProperty( obj, prop, descriptor );
135
- return value;
136
- }
137
-
138
116
 
139
117
  module.exports = {
140
118
  isBetaEnabled,
141
119
  availableBetaFlags,
142
120
  isDeprecatedEnabled,
143
121
  checkRemovedDeprecatedFlags,
144
- setProp,
145
122
  };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { setProp } = require('../base/model');
3
+ const { setProp } = require('../utils/objectUtils');
4
4
 
5
5
  // Only to be used with validator.js - a correct `this` value needs to be provided!
6
6
 
@@ -8,7 +8,7 @@ const {
8
8
  } = require('../model/csnUtils');
9
9
  const { isBuiltinType } = require('../base/builtins');
10
10
  const { isGeoTypeName } = require('../compiler/builtins');
11
- const { setProp } = require('../base/model');
11
+ const { setProp } = require('../utils/objectUtils');
12
12
  // Only to be used with validator.js - a correct `this` value needs to be provided!
13
13
 
14
14
  /**
@@ -4,8 +4,8 @@
4
4
 
5
5
  'use strict';
6
6
 
7
- const { csnRefs } = require('../model/csnRefs');
8
- const { setProp } = require('../base/model');
7
+ const { csnRefs } = require('../base/csnRefs');
8
+ const { setProp } = require('../utils/objectUtils');
9
9
  const { isAnnotationExpression } = require('../base/builtins');
10
10
 
11
11
  /**
@@ -1,39 +1,69 @@
1
1
  'use strict';
2
2
 
3
- const { setProp } = require('../base/model');
3
+ const { setProp, forEachValue } = require('../utils/objectUtils');
4
4
  const { featureFlags } = require('../transform/featureFlags');
5
5
  const { isSqlService, isDummyService, isDataProductProductionService } = require('../transform/db/processSqlServices');
6
6
 
7
7
  /**
8
+ * Set a feature flag on the CSN model.
8
9
  *
9
- * @param {string} flag
10
+ * @param {CSN.Model} csn CSN model to set flag on
11
+ * @param {string} flag Flag name to set
12
+ */
13
+ function setFeatureFlag( csn, flag ) {
14
+ if (!csn.meta)
15
+ setProp(csn, 'meta', {});
16
+ if (!csn.meta[featureFlags])
17
+ csn.meta[featureFlags] = {};
18
+
19
+ csn.meta[featureFlags][flag] = true;
20
+ }
21
+
22
+ /**
23
+ * Get a function that detects and sets feature flags for expand/inline columns in a query.
10
24
  *
11
- * @returns {Function} Function to correctly set the given flag
25
+ * @param {CSN.Model} csn CSN model to set flags on
26
+ * @returns {Function} Function to call per query
12
27
  */
13
- function setFeatureFlag( flag ) {
14
- return function setFlag() {
15
- if (!this.csn.meta)
16
- setProp(this.csn, 'meta', {});
17
- if (!this.csn.meta[featureFlags])
18
- this.csn.meta[featureFlags] = {};
28
+ function getQueryFeatureFlagSetter( csn ) {
29
+ return function setQueryFeatureFlags(query) {
30
+ const queryProp = query.SELECT ? 'SELECT' : 'projection';
31
+ query[queryProp]?.columns?.forEach((column) => {
32
+ if (column.expand || column.inline)
33
+ setFeatureFlag(csn, '$expandInline');
34
+ });
35
+ };
36
+ }
19
37
 
20
- this.csn.meta[featureFlags][flag] = true;
38
+ /**
39
+ * Get a function that detects and sets feature flags for entity/service definitions.
40
+ * That are calculated elements and SQL services.
41
+ *
42
+ * @param {CSN.Model} csn CSN model to set flags on
43
+ * @param {CSN.Options} options Compiler options
44
+ * @returns {Function} Function to call per definition
45
+ */
46
+ function getDefinitionFeatureFlagSetter( csn, options ) {
47
+ return function setDefinitionFeatureFlags(def) {
48
+ if (def.kind === 'entity' && def.elements) {
49
+ forEachValue(def.elements, (element) => {
50
+ if (element.value)
51
+ setFeatureFlag(csn, '$calculatedElements');
52
+ });
53
+ }
54
+ else if (def.kind === 'service') {
55
+ if (isSqlService(def))
56
+ setFeatureFlag(csn, '$sqlService');
57
+ if (isDummyService(def, options))
58
+ setFeatureFlag(csn, '$dummyService');
59
+ if (isDataProductProductionService(def))
60
+ setFeatureFlag(csn, '$dataProductService');
61
+ }
21
62
  };
22
63
  }
23
64
 
24
- // Export a applyTransformations callback object that sets the feature flags if certain properties are present
65
+ // Export factory functions that create bound feature flag setters for use in transformation loops
25
66
  module.exports = {
26
- value: setFeatureFlag('$calculatedElements'),
27
- expand: setFeatureFlag('$expandInline'),
28
- inline: setFeatureFlag('$expandInline'),
29
- kind: function setFeatureFlagForSqlService( artifact ) {
30
- if (isSqlService(artifact))
31
- setFeatureFlag( '$sqlService' ).call(this);
32
-
33
- if (isDummyService(artifact, this.options))
34
- setFeatureFlag( '$dummyService' ).call(this);
35
-
36
- if (isDataProductProductionService(artifact, this.options))
37
- setFeatureFlag( '$dataProductService' ).call(this);
38
- },
67
+ getQueryFeatureFlagSetter,
68
+ getDefinitionFeatureFlagSetter,
39
69
  };
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { setProp } = require('../base/model');
3
+ const { setProp } = require('../utils/objectUtils');
4
4
 
5
5
  // Only to be used with validator.js - a correct this value needs to be provided!
6
6
 
@@ -3,7 +3,7 @@
3
3
  // Only to be used with validator.js - a correct this value needs to be provided!
4
4
 
5
5
  const { ModelError } = require('../base/error');
6
- const { setProp } = require('../base/model');
6
+ const { setProp } = require('../utils/objectUtils');
7
7
 
8
8
  /**
9
9
  * Assert that targets of associations and compositions are entities.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { setProp } = require('../base/model');
3
+ const { setProp } = require('../utils/objectUtils');
4
4
 
5
5
  // Only to be used with validator.js - a correct this value needs to be provided!
6
6
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { forEachGeneric } = require('../model/csnUtils');
4
4
  const { otherSideIsExpandableStructure, resolveArtifactType } = require('./utils');
5
- const { pathId } = require('../model/csnRefs');
5
+ const { pathId } = require('../base/csnRefs');
6
6
 
7
7
  // Only to be used with validator.js - a correct this value needs to be provided!
8
8
 
@@ -3,7 +3,7 @@
3
3
  const { isPersistedOnDatabase, applyTransformationsOnNonDictionary } = require('../model/csnUtils');
4
4
  const { isBuiltinType } = require('../base/builtins');
5
5
  const { requireForeignKeyAccess } = require('./onConditions');
6
- const { pathId } = require('../model/csnRefs');
6
+ const { pathId } = require('../base/csnRefs');
7
7
 
8
8
  const generalQueryProperties = [ 'from', 'columns', 'where', 'groupBy', 'orderBy', 'having', 'limit' ];
9
9
 
@@ -18,7 +18,6 @@ const validateHasPersistedElements = require('./hasPersistedElements');
18
18
  const checkForHanaTypes = require('./checkForTypes');
19
19
  const { checkAnnotationExpression } = require('./structuredAnnoExpressions');
20
20
  const checkForParams = require('./parameters');
21
- const checkAndRemoveEnums = require('./enums');
22
21
  // forOdata
23
22
  const { validateDefaultValues } = require('./defaultValues');
24
23
  const { checkActionOrFunction } = require('./actionsFunctions');
@@ -54,7 +53,6 @@ const {
54
53
  checkSqlAnnotationOnElement,
55
54
  } = require('./sql-snippets');
56
55
  const assertNoAssocUsageOutsideOfService = require('./assocOutsideService');
57
- const featureFlags = require('./featureFlags');
58
56
  const { timetrace } = require('../utils/timetrace');
59
57
 
60
58
  const forRelationalDBMemberValidators
@@ -94,7 +92,6 @@ const forRelationalDBCsnValidators = [
94
92
  navigationIntoMany,
95
93
  expandToMany,
96
94
  checkPathsInStoredCalcElement,
97
- featureFlags,
98
95
  ];
99
96
  /**
100
97
  * @type {Array<(query: CSN.Query, path: CSN.Path) => void>}
@@ -168,7 +165,7 @@ function _validate( csn, that,
168
165
  // TODO: Don't know if that's feasible? Do we really need to enrich annotations always?
169
166
  // const { cleanup } = enrich(csn, { processAnnotations: that.options.tranformation === 'odata' });
170
167
 
171
- applyTransformations(csn, mergeTransformers(csnValidators, that), [], { drillRef: true });
168
+ applyTransformations(csn, mergeTransformers(csnValidators, that), [], { drillRef: true, ...iterateOptions });
172
169
 
173
170
  forEachDefinition(csn, (artifact, artifactName, prop, path) => {
174
171
  artifactValidators.forEach((artifactValidator) => {
@@ -201,10 +198,8 @@ function _validate( csn, that,
201
198
  function getDBCsnValidators( options ) {
202
199
  const validations = [ ...forRelationalDBCsnValidators ];
203
200
 
204
- if (options.transformation !== 'effective') {
205
- validations.push(checkAndRemoveEnums);
201
+ if (options.transformation !== 'effective')
206
202
  validations.push(checkForParams.csnValidator);
207
- }
208
203
 
209
204
  if (options.sqlDialect === 'h2' || options.sqlDialect === 'postgres')
210
205
  validations.push(checkForHanaTypes);
@@ -221,7 +216,13 @@ function forRelationalDB( csn, that ) {
221
216
  const memberValidators = [ ...forRelationalDBMemberValidators, ...commonMemberValidators ];
222
217
  if (that.options.transformation === 'hdbcds')
223
218
  memberValidators.push(checkForParams.memberValidator);
224
-
219
+ // skip artifacts / elements which are not persisted on the database from being validated
220
+ const iterateOptions = {
221
+ skipArtifact: artifact => artifact.abstract ||
222
+ hasPersistenceSkipAnnotation(artifact) ||
223
+ artifact['@cds.persistence.exists'] ||
224
+ [ 'action', 'function', 'event' ].includes(artifact.kind),
225
+ };
225
226
  return _validate(csn, that,
226
227
  getDBCsnValidators(that.options),
227
228
  memberValidators,
@@ -246,12 +247,7 @@ function forRelationalDB( csn, that ) {
246
247
  }
247
248
  ),
248
249
  forRelationalDBQueryValidators.concat(commonQueryValidators),
249
- {
250
- skipArtifact: artifact => artifact.abstract ||
251
- hasPersistenceSkipAnnotation(artifact) ||
252
- artifact['@cds.persistence.exists'] ||
253
- [ 'action', 'function', 'event' ].includes(artifact.kind),
254
- });
250
+ iterateOptions);
255
251
  }
256
252
 
257
253
  /**
@@ -283,7 +283,7 @@ function assertConsistency( model, stage ) {
283
283
  'quantifier', 'orderBy', 'limit', 'name', '$parens', 'kind',
284
284
  '_origin', '$contains', // TODO tmp, see TODO in getOriginRaw()
285
285
  '_parent', '_main', '_leadingQuery', '_effectiveType', '$effectiveSeqNo', // in FROM
286
- '_$next', // parsing error: tableTerm with UNION on rhs.
286
+ '$expand', '_$next', // parsing error: tableTerm with UNION on rhs.
287
287
  ],
288
288
  },
289
289
  select: { // sub query
@@ -309,7 +309,7 @@ function assertConsistency( model, stage ) {
309
309
  'on', '$parens', 'cardinality',
310
310
  'kind', 'name', '_block', '_parent', '_main', '_user',
311
311
  '$tableAliases', '_combined', '_joinParent', '$joinArgsIndex',
312
- '_leadingQuery', '_$next', '_deps',
312
+ '_leadingQuery', '_$next', '_deps', '$expand',
313
313
  ],
314
314
  },
315
315
  ref: {
@@ -329,7 +329,7 @@ function assertConsistency( model, stage ) {
329
329
  '$parens',
330
330
  'kind', 'name', '_block', '_parent', '_main', 'elements',
331
331
  '_effectiveType', '$effectiveSeqNo', '_origin', '_joinParent', '$joinArgsIndex',
332
- '$duplicates', // duplicate query in FROM clause
332
+ '$expand', '$duplicates', // duplicate query in FROM clause
333
333
  ],
334
334
  },
335
335
  none: { optional: () => true }, // parse error
@@ -352,13 +352,13 @@ function assertConsistency( model, stage ) {
352
352
  requires: [ 'location', 'name' ],
353
353
  optional: [ '$duplicates' ],
354
354
  },
355
- orderBy: { inherits: 'value', test: isArray( expression ) },
355
+ orderBy: { kind: [ 'extend' ], inherits: 'value', test: isArray( expression ) },
356
356
  sort: { test: locationVal( isString ), enum: [ 'asc', 'desc' ] },
357
357
  nulls: { test: locationVal( isString ), enum: [ 'first', 'last' ] },
358
358
  $orderBy: { inherits: 'orderBy' },
359
- groupBy: { inherits: 'value', test: isArray( expression ) },
359
+ groupBy: { kind: [ 'extend' ], inherits: 'value', test: isArray( expression ) },
360
360
  $limit: { test: TODO },
361
- limit: { requires: [ 'rows' ], optional: [ 'offset', 'location' ] },
361
+ limit: { kind: [ 'extend' ], requires: [ 'rows' ], optional: [ 'offset', 'location' ] },
362
362
  rows: { inherits: 'value' },
363
363
  offset: { inherits: 'value' },
364
364
  _combined: { test: TODO },
@@ -438,6 +438,8 @@ function assertConsistency( model, stage ) {
438
438
  'location', '$inferred', 'sort', 'nulls',
439
439
  'param', 'scope', // for dynamic parameter '?'
440
440
  'args', 'op', 'func', 'suffix',
441
+ // needed for groupBy extensions - TODO: outside `value`:
442
+ '$extended', '_block', '_outer',
441
443
  // calculated elements on-write - TODO: outside `value`
442
444
  'stored',
443
445
  ],
@@ -512,8 +514,8 @@ function assertConsistency( model, stage ) {
512
514
  test: args,
513
515
  },
514
516
  on: { kind: true, inherits: 'value', test: expression },
515
- where: { inherits: 'value' },
516
- having: { inherits: 'value' },
517
+ where: { kind: [ 'extend' ], inherits: 'value' },
518
+ having: { kind: [ 'extend' ], inherits: 'value' },
517
519
  op: { test: locationVal( isString ) },
518
520
  join: { test: locationVal( isString ) },
519
521
  quantifier: { test: locationVal( isString ) },
@@ -736,7 +738,7 @@ function assertConsistency( model, stage ) {
736
738
  $expand: {
737
739
  kind: true,
738
740
  // See description of `setExpandStatus()` of in `lib/compiler/utils.js`.
739
- test: isOneOf( [ 'origin', 'annotate', 'target' ] ),
741
+ test: isOneOf( [ 'origin', 'target', 'annotate', 'extend' ] ),
740
742
  },
741
743
  $inCycle: { kind: true, test: isBoolean },
742
744
 
@@ -3,6 +3,7 @@
3
3
  'use strict';
4
4
 
5
5
  const { CompilerAssertion } = require( '../base/error' );
6
+ const $inferred = Symbol.for( 'cds.$inferred' );
6
7
 
7
8
  const dictKinds = {
8
9
  definitions: 'absolute',
@@ -67,7 +68,8 @@ const kindProperties = {
67
68
 
68
69
  function propExists( prop, parent ) {
69
70
  const obj = parent.returns || parent;
70
- return (obj.items || obj.targetAspect || obj)[prop];
71
+ const members = (obj.items || obj.targetAspect || obj)[prop];
72
+ return members && !members[$inferred];
71
73
  }
72
74
 
73
75
  /**
@@ -90,6 +92,8 @@ function getArtifactName( art ) {
90
92
  const namePath = [];
91
93
  let parent = art._outer || art;
92
94
  while (parent._main || parent.kind === 'builtin') { // until we hit the main artifact
95
+ if (!parent.name)
96
+ return '<error>';
93
97
  if (parent.name.$inferred !== '$internal' || parent.kind === '$inline')
94
98
  namePath.push( parent );
95
99
  if (parent.kind === 'select')
@@ -9,7 +9,7 @@
9
9
 
10
10
  const { builtinLocation } = require('../base/location');
11
11
  const { setLink } = require('./utils');
12
- const { isBetaEnabled } = require('../base/model');
12
+ const { isBetaEnabled } = require('../base/specialOptions');
13
13
 
14
14
  // TODO: make type parameters a dict
15
15
  const core = {
@@ -9,7 +9,7 @@
9
9
 
10
10
  'use strict';
11
11
 
12
- const { isDeprecatedEnabled } = require('../base/model');
12
+ const { isDeprecatedEnabled } = require('../base/specialOptions');
13
13
  const { propagationRules, acceptsExprValues } = require('../base/builtins');
14
14
  const { typeParameters } = require('./builtins');
15
15
  const {
@@ -132,8 +132,8 @@ function check( model ) {
132
132
  typeName === 'cds.Vector' ||
133
133
  typeName === 'cds.hana.CLOB' ||
134
134
  typeName === 'cds.LargeBinary') {
135
- warning( 'def-unsupported-key', [ elem.type?.location || elem.location, elem ],
136
- { '#': 'type', keyword: 'key', type: typeName } );
135
+ warning( 'type-invalid-for-key', [ elem.type?.location || elem.location, elem ],
136
+ { type: typeName } );
137
137
  }
138
138
  }
139
139
 
@@ -122,10 +122,10 @@
122
122
 
123
123
  const { weakLocation, builtinLocation } = require('../base/location');
124
124
 
125
- const shuffleGen = require('../base/shuffle');
125
+ const shuffleGen = require('../utils/shuffle');
126
126
  const {
127
127
  dictAdd, dictAddArray, dictForEach, pushToDict,
128
- } = require('../base/dictionaries');
128
+ } = require('./dictionaries');
129
129
  const { kindProperties } = require('./base');
130
130
  const {
131
131
  setLink,
@@ -724,6 +724,9 @@ function define( model ) {
724
724
  // ORDER BY and LIMIT to be evaluated in leading query
725
725
  }
726
726
  else { // with parse error (`select from <EOF>`, `select from E { *, ( select }`)
727
+ // TODO: call initQuery() anyway to avoid Error[expr-no-subquery] also for
728
+ // UNIONs (test3/Queries/DollarSelf/CorruptedSource.err.cds), see also
729
+ // resolveExprNode()
727
730
  return undefined;
728
731
  }
729
732
  return query._leadingQuery || query;
@@ -1004,7 +1007,7 @@ function define( model ) {
1004
1007
  }
1005
1008
  else if ((col.expand || col.value) &&
1006
1009
  !path && // no parse error (path without last item)
1007
- (insideExpand || query._parent.kind !== 'select')) { // not sub-selects
1010
+ (insideExpand || query._parent?.kind !== 'select')) { // not sub-selects
1008
1011
  error( 'query-req-name',
1009
1012
  // TODO: message function: `query` should work directly
1010
1013
  [ (col.value || col).location, (query.name ? query : query._parent ) ],
@@ -2,6 +2,8 @@
2
2
  //
3
3
  // Warning: this is Core-compiler only stuff
4
4
 
5
+ // TODO: probably move to some future lib/xsn/
6
+
5
7
  'use strict';
6
8
 
7
9
  // New-style duplicate representation - use the style below for artifacts and
@@ -84,9 +86,8 @@ function dictAddArray( dict, name, entry, messageCallback ) {
84
86
  function dictFirst( dict ) {
85
87
  if (!dict)
86
88
  return dict;
87
- for (const name in dict)
88
- return dict[name];
89
- return undefined;
89
+ const names = Object.keys( dict );
90
+ return names.length ? dict[names[0]] : null;
90
91
  }
91
92
 
92
93
  // Push `entry` to the array value with key `name` in the dictionary `dict`.