@sap/cds-compiler 5.1.2 → 5.3.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 (68) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/bin/cdsc.js +7 -2
  3. package/bin/cdshi.js +24 -17
  4. package/bin/cdsse.js +17 -18
  5. package/doc/CHANGELOG_BETA.md +9 -4
  6. package/lib/api/main.js +19 -2
  7. package/lib/api/options.js +4 -1
  8. package/lib/api/validate.js +5 -0
  9. package/lib/base/builtins.js +1 -0
  10. package/lib/base/message-registry.js +40 -3
  11. package/lib/base/messages.js +1 -1
  12. package/lib/base/model.js +0 -11
  13. package/lib/checks/actionsFunctions.js +0 -12
  14. package/lib/checks/structuredAnnoExpressions.js +10 -14
  15. package/lib/compiler/assert-consistency.js +21 -13
  16. package/lib/compiler/builtins.js +2 -2
  17. package/lib/compiler/checks.js +25 -6
  18. package/lib/compiler/define.js +27 -31
  19. package/lib/compiler/extend.js +16 -18
  20. package/lib/compiler/generate.js +3 -3
  21. package/lib/compiler/populate.js +22 -16
  22. package/lib/compiler/propagator.js +3 -2
  23. package/lib/compiler/resolve.js +87 -94
  24. package/lib/compiler/shared.js +12 -13
  25. package/lib/compiler/tweak-assocs.js +390 -86
  26. package/lib/compiler/utils.js +41 -33
  27. package/lib/compiler/xpr-rewrite.js +45 -58
  28. package/lib/edm/annotations/genericTranslation.js +17 -13
  29. package/lib/edm/csn2edm.js +28 -4
  30. package/lib/edm/edm.js +68 -28
  31. package/lib/edm/edmInboundChecks.js +5 -8
  32. package/lib/edm/edmPreprocessor.js +66 -40
  33. package/lib/edm/edmUtils.js +1 -1
  34. package/lib/gen/BaseParser.js +778 -0
  35. package/lib/gen/CdlParser.js +4477 -0
  36. package/lib/gen/language.checksum +1 -1
  37. package/lib/gen/language.interp +1 -1
  38. package/lib/gen/languageParser.js +4072 -4024
  39. package/lib/inspect/inspectPropagation.js +1 -1
  40. package/lib/json/from-csn.js +5 -3
  41. package/lib/json/to-csn.js +7 -10
  42. package/lib/language/antlrParser.js +96 -0
  43. package/lib/language/errorStrategy.js +1 -1
  44. package/lib/language/genericAntlrParser.js +32 -4
  45. package/lib/language/multiLineStringParser.js +1 -1
  46. package/lib/main.d.ts +23 -0
  47. package/lib/model/cloneCsn.js +22 -13
  48. package/lib/model/csnUtils.js +2 -0
  49. package/lib/model/revealInternalProperties.js +2 -0
  50. package/lib/modelCompare/utils/filter.js +70 -42
  51. package/lib/optionProcessor.js +16 -10
  52. package/lib/parsers/AstBuildingParser.js +1290 -0
  53. package/lib/parsers/CdlGrammar.g4 +2013 -0
  54. package/lib/parsers/Lexer.js +249 -0
  55. package/lib/render/toCdl.js +46 -45
  56. package/lib/render/toSql.js +5 -5
  57. package/lib/transform/addTenantFields.js +4 -4
  58. package/lib/transform/db/applyTransformations.js +54 -16
  59. package/lib/transform/draft/odata.js +10 -11
  60. package/lib/transform/effective/flattening.js +10 -14
  61. package/lib/transform/forRelationalDB.js +7 -6
  62. package/lib/transform/odata/flattening.js +42 -31
  63. package/lib/transform/odata/toFinalBaseType.js +7 -6
  64. package/lib/transform/universalCsn/universalCsnEnricher.js +1 -0
  65. package/lib/utils/moduleResolve.js +1 -1
  66. package/package.json +2 -2
  67. package/share/messages/redirected-to-ambiguous.md +5 -4
  68. package/share/messages/redirected-to-complex.md +6 -3
package/CHANGELOG.md CHANGED
@@ -7,12 +7,63 @@
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 5.3.0 - 2024-09-25
11
+
12
+ ### Added
13
+
14
+ - compiler:
15
+ - A warning is emitted if a string enum's values are longer than the specified length.
16
+ - ON-condition rewriting has been improved and now supports secondary associations.
17
+ - to.edm(x): Support optional action and function parameters in OData V4. The following rules apply:
18
+ + A parameter declared `not null` without default value is mandatory.
19
+ + A **function** parameter declared `null` without default value is mandatory.
20
+ + An **action** parameter declared `null` without default value is optional as it is equivalent to
21
+ `@Core.OptionalParameter { DefaultValue: null }`.
22
+ + A parameter with a default value is optional and the default value is rendered as
23
+ `@Core.OptionalParameter { DefaultValue: <value> }` regardless of its nullability.
24
+ + `@Core.OptionalParameter: true` can be used to turn a mandatory parameter into an optional parameter
25
+ (especially function parameters) and to signal an unspecified default value in the API if the parameter
26
+ has no default clause.
27
+ + `@Core.OptionalParameter: false` turns the creation of a `@Core.OptionalParameter: { Default: ... }`
28
+ annotation off.
29
+ + A default clause or `@Core.OptionalParameter: <bool>` have no effect on an explicit binding parameter.
30
+ + Mandatory and optional **action** parameters may appear in any order.
31
+ + Optional **function** parameters must not be followed by mandatory parameters.
32
+ - to.edm: Forward `@OpenAPI {...}` into EDM Json with option `--odata-openapi-hints`.
33
+ - cdsc: Option `--transitive-localized-views` was added.
34
+
35
+ ### Fixed
36
+
37
+ - CDL parser: Issue warning if annotation assignments have been written
38
+ at an invalid position inside a type expressions.
39
+ - CDL parser: Issue warning for arrayed parameter with default value.
40
+ - to.cdl: Arrayed parameters with default values were not rendered correctly.
41
+
42
+ ## Version 5.2.0 - 2024-08-27
43
+
44
+ ### Added
45
+
46
+ - to.edm(x): Add `@Core.Links { rel: 'author', href: 'https://cap.cloud.sap' };` as watermark to lead schema.
47
+ - to.sql.migration: Introduce option `script` to aid in generation of manual migration scripts by not aborting when encountering lossy changes.
48
+
49
+ ### Changed
50
+
51
+ - for.odata: No longer reject default values on action/function parameters.
52
+ - to.edm(x): Raise warning for default values on action/function parameters that they are ignored.
53
+
54
+ ### Fixed
55
+
56
+ - compiler: Fix extensions with bound actions using an explicit binding parameter in `parseCdl` CSN.
57
+ - for.odata, to.edm(x): Fix some issues with resolving annotation expressions in nested objects and
58
+ reliably replace value of `=` attribute with `true` after processing.
59
+
10
60
  ## Version 5.1.2 - 2024-08-05
11
61
 
12
62
  ### Fixed
13
63
 
14
64
  - compiler: In parseCdl mode, bound actions specifying the binding parameter with `$self` did not work.
15
65
 
66
+
16
67
  ## Version 5.1.0 - 2024-07-25
17
68
 
18
69
  ### Added
@@ -105,6 +156,13 @@ This is a preview version for the major release and contains breaking changes. I
105
156
  Use `to.edm(x)` instead.
106
157
 
107
158
 
159
+ ## Version 4.9.8 - 2024-07-29
160
+
161
+ ### Fixed
162
+
163
+ - compiler: Fix extensions with bound actions using an explicit binding parameter in `parseCdl` CSN.
164
+ - to.edm(x): No `Nullable` attribute for `$ReturnType` of `Collection(<entity type>)` [OData V4 CSDL, section 12.8 Return Type](https://docs.oasis-open.org/odata/odata-csdl-xml/v4.01/odata-csdl-xml-v4.01.html#sec_ReturnType)
165
+
108
166
  ## Version 4.9.6 - 2024-07-15
109
167
 
110
168
  ### Fixed
package/bin/cdsc.js CHANGED
@@ -217,6 +217,11 @@ function cdsc_main() {
217
217
  if (cmdLine.options.stdin)
218
218
  cmdLine.options.fallbackParser ??= 'auto!';
219
219
 
220
+ if (cmdLine.options[cmdLine.command]?.transitiveLocalizedViews) {
221
+ cmdLine.options.fewerLocalizedViews = !cmdLine.options[cmdLine.command].transitiveLocalizedViews
222
+ delete cmdLine.options[cmdLine.command].transitiveLocalizedViews;
223
+ }
224
+
220
225
  parseSeverityOptions(cmdLine);
221
226
 
222
227
  // Do the work for the selected command
@@ -306,7 +311,7 @@ async function executeCommandLine( command, options, args ) {
306
311
  manageConstraints,
307
312
  toSql,
308
313
  inspect,
309
- toEffectiveCsn,
314
+ forEffective,
310
315
  forSeal,
311
316
  };
312
317
  const commandsWithoutCompilation = {
@@ -352,7 +357,7 @@ async function executeCommandLine( command, options, args ) {
352
357
  return model;
353
358
  }
354
359
 
355
- function toEffectiveCsn( model ) {
360
+ function forEffective( model ) {
356
361
  const features = [ 'resolveSimpleTypes', 'resolveProjections', 'remapOdataAnnotations', 'keepLocalized' ];
357
362
  for (const feature of features) {
358
363
  if (options[feature]) // map to boolean equivalent
package/bin/cdshi.js CHANGED
@@ -34,40 +34,47 @@ const categoryChars = { // default: first char of category name
34
34
  // ExtElement: 'E', // using the first letter is the default
35
35
  ExtBoundAction: 'B', // highlight like bound action definition
36
36
  ExtParam: 'P', // highlight like entity/action parameter definition
37
+ FromImplicit: 'W',
37
38
  Event: 'Y',
38
39
  KeyImplicit: 'r', // handle as normal ref
39
40
  // Remark: do not use `x`/`X` (hex literal `x'1e3d'`)
40
41
  };
41
42
 
43
+ const options = { newParser: true, attachTokens: true, messages: [] };
44
+
42
45
  function highlight( err, buf ) {
43
46
  if (err) {
44
47
  console.error( 'ERROR:', err.toString() );
45
48
  return;
46
49
  }
47
- const ts = compiler.parseX( buf, 'hi.cds', { attachTokens: true, messages: [] } ).tokenStream;
48
- if (!buf.length || !ts.tokens || !ts.tokens.length)
50
+ const { tokenStream } = compiler.parseX( buf, 'hi.cds', options );
51
+ const { tokens, lexer } = tokenStream;
52
+ if (!buf.length || !tokens || !tokens.length)
49
53
  return;
54
+
50
55
  const chars = [ ...buf ];
51
- for (const tok of ts.tokens) {
52
- if (tok.start < 0)
56
+ for (const tok of tokens) {
57
+ if (tok.type === 'Comment') // but interpret DocComment!
53
58
  continue;
54
- if (tok.$isSkipped) {
55
- if (tok.stop > tok.start) {
56
- chars[tok.start] = (tok.$isSkipped === true ? '\x0f' : '\x16'); // ^O / ^V
57
- chars[tok.stop] = '\x17'; // ^W
59
+ const { location, start } = tok;
60
+ if (start < 0)
61
+ continue;
62
+ const stop = lexer.characterPos( location.endLine, location.endCol ) - 1;
63
+ const cat = tok.parsedAs;
64
+ if (!cat) {
65
+ if (stop > start) {
66
+ chars[start] = (cat !== 0 ? '\x0f' : '\x16'); // ^O / ^V (ERROR)
67
+ chars[stop] = '\x17'; // ^W
58
68
  }
59
69
  else {
60
- chars[tok.start] = (tok.$isSkipped === true ? '\x0e' : '\x15'); // ^N / ^U
70
+ chars[start] = (cat !== 0 ? '\x0e' : '\x15'); // ^N / ^U (ERROR)
61
71
  }
62
72
  }
63
- else {
64
- const cat = tok.isIdentifier;
65
- if (cat) {
66
- if (cat !== 'ref' || chars[tok.start] !== '$')
67
- chars[tok.start] = categoryChars[cat] || cat.charAt(0);
68
- if (tok.stop > tok.start) // stop in ANTLR at last char, not behind
69
- chars[tok.start + 1] = '_';
70
- }
73
+ else if (cat !== 'keyword' && cat !== 'token') {
74
+ if (cat !== 'ref' || chars[start] !== '$')
75
+ chars[start] = categoryChars[cat] || cat.charAt(0);
76
+ if (stop > start)
77
+ chars[start + 1] = '_';
71
78
  }
72
79
  }
73
80
  for (const c of chars)
package/bin/cdsse.js CHANGED
@@ -7,8 +7,8 @@
7
7
  // corrupted, incomplete or erroneous CDL sources.
8
8
  //
9
9
  // The output could be used directly by some editors, e.g. Emacs. The
10
- // capabilities supported at the moments is: complete - work in progress.
11
- // Planned are: gotoDefinition, highlight (for syntax highlighting).
10
+ // capabilities supported at the moments is: complete, find, lint.
11
+ // Syntax highlighting is supported by ./cdshi.js.
12
12
 
13
13
  /* eslint no-console:off */
14
14
  // @ts-nocheck
@@ -52,6 +52,7 @@ function usage( err ) {
52
52
  }
53
53
 
54
54
  function complete( err, buf ) {
55
+ const messages = [];
55
56
  if (err)
56
57
  return usage( err );
57
58
  const off = offset( buf );
@@ -74,16 +75,13 @@ function complete( err, buf ) {
74
75
  const src = `${buf.substring( 0, off.prefix )}__NO_SUCH_ID__${buf.substring( off.cursor )}`;
75
76
  const fname = path.resolve( '', file );
76
77
  compiler.compileX( [ file ], '', {
77
- attachValidNames: true, lintMode: true, beta, messages: [],
78
- }, { [fname]: src } )
78
+ newParser: true, attachValidNames: true, lintMode: true, beta, messages }, { [fname]: src } )
79
79
  .then( ident, ident );
80
80
  }
81
81
  return true;
82
82
 
83
- function ident( xsnOrErr ) {
84
- if (!(xsnOrErr.messages || xsnOrErr.options && xsnOrErr.options.messages))
85
- return usage( xsnOrErr );
86
- const vn = messageAt( xsnOrErr, 'validNames', off.col ) || Object.create(null);
83
+ function ident() {
84
+ const vn = messageAt( messages, 'validNames', off.col ) || Object.create(null);
87
85
  // TODO: if there is no such message, use console.log( 'arbitrary identifier' )
88
86
  // if we want to avoid that the editor switches to fuzzy completion match
89
87
  // against the prefix (not yet done anyway)
@@ -107,18 +105,17 @@ function find( err, buf ) {
107
105
  return usage();
108
106
  if (off.prefix === off.cursor) // not at name
109
107
  return true;
108
+ const messages = [];
110
109
  const src = `${buf.substring( 0, off.prefix )}__NO_SUCH_ID__${buf.substring( off.cursor )}`;
111
110
  const fname = path.resolve( '', file );
112
111
  compiler.compileX( [ file ], '', {
113
- attachValidNames: true, lintMode: true, beta, messages: [],
112
+ newParser: true, attachValidNames: true, lintMode: true, beta, messages,
114
113
  }, { [fname]: src } )
115
114
  .then( show, show );
116
115
  return true;
117
116
 
118
- function show( xsnOrErr ) {
119
- if (!(xsnOrErr.messages || xsnOrErr.options && xsnOrErr.options.messages))
120
- return usage( xsnOrErr );
121
- const vn = messageAt( xsnOrErr, 'validNames', off.col ) || Object.create(null);
117
+ function show() {
118
+ const vn = messageAt( messages, 'validNames', off.col ) || Object.create(null);
122
119
  const art = vn[buf.substring( off.prefix, off.cursor )];
123
120
  if (art)
124
121
  console.log( `${locationString( art.name.location || art.location )}: Definition` );
@@ -129,13 +126,13 @@ function find( err, buf ) {
129
126
  function lint( err, buf ) {
130
127
  if (err)
131
128
  return usage( err );
129
+ const messages = [];
132
130
  const fname = path.resolve( '', file );
133
- compiler.compileX( [ file ], '', { lintMode: true, beta, messages: [] }, { [fname]: buf } )
131
+ compiler.compileX( [ file ], '', { newParser: true, lintMode: true, beta, messages }, { [fname]: buf } )
134
132
  .then( display, display );
135
133
  return true;
136
134
 
137
135
  function display( xsnOrErr ) {
138
- const messages = xsnOrErr.messages || xsnOrErr.options && xsnOrErr.options.messages;
139
136
  if (!messages)
140
137
  return usage( xsnOrErr );
141
138
  for (const msg of messages)
@@ -145,8 +142,10 @@ function lint( err, buf ) {
145
142
  }
146
143
 
147
144
  function tokensAt( buf, _offset, col, symbol ) {
145
+ const messages = [];
148
146
  const src = `${buf.substring( 0, _offset )}≠${buf.substring( _offset )}`;
149
- const et = messageAt( compiler.parseX( src, frel, { messages: [] } ), 'expectedTokens', col ) || [];
147
+ compiler.parseX( src, frel, { newParser: true, messages } );
148
+ const et = messageAt( messages, 'expectedTokens', col ) || [];
150
149
  for (const n of et) {
151
150
  if (typeof symbol === 'string') {
152
151
  if (n.length > 3 && n.charAt(0) === "'" && n.charAt(1) === symbol)
@@ -166,8 +165,8 @@ function tokensAt( buf, _offset, col, symbol ) {
166
165
  return et.includes( 'Identifier' );
167
166
  }
168
167
 
169
- function messageAt( model, prop, col ) {
170
- const msg = (model.messages || model.options && model.options.messages).find(
168
+ function messageAt( messages, prop, col ) {
169
+ const msg = messages.find(
171
170
  m => m[prop] && m.$location.line === line && m.$location.col === col && m.$location.file === frel
172
171
  );
173
172
  return msg && msg[prop];
@@ -8,6 +8,11 @@ Note: `beta` fixes, changes and features are listed in this ChangeLog just for i
8
8
  The compiler behavior concerning `beta` features can change at any time without notice.
9
9
  **Don't use `beta` fixes, changes and features in productive mode.**
10
10
 
11
+ ## Version 5.3.0 - 2024-09-25
12
+
13
+ ### Removed `optionalActionFunctionParameters`
14
+
15
+ It is now enabled by default.
11
16
 
12
17
  ## Version 5.0.0 - 2024-05-29
13
18
 
@@ -17,19 +22,19 @@ It is now enabled by default.
17
22
 
18
23
  ## Version 4.9.0 - 2024-04-25
19
24
 
20
- ## Removed `odataAnnotationExpressions`
25
+ ### Removed `odataAnnotationExpressions`
21
26
 
22
27
  It is now enabled by default.
23
28
 
24
- ## Removed `odataPathsInAnnotationExpressions`
29
+ ### Removed `odataPathsInAnnotationExpressions`
25
30
 
26
31
  It is now enabled by default.
27
32
 
28
- ## Removed `annotationExpressions`
33
+ ### Removed `annotationExpressions`
29
34
 
30
35
  It is now enabled by default.
31
36
 
32
- ## Added `temporalRawProjection`
37
+ ### Added `temporalRawProjection`
33
38
 
34
39
  Enables revocation of temporal where clause in projections of temporal entities if the
35
40
  `@cds.valid { from, to }` annotations on the projection elements have falsy values.
package/lib/api/main.js CHANGED
@@ -468,8 +468,19 @@ function remapName( key, csn, filter = () => true ) {
468
468
  */
469
469
  function sqlMigration( csn, options, messageFunctions, beforeImage ) {
470
470
  const internalOptions = prepareOptions.to.sql(options);
471
+
471
472
  messageFunctions.setOptions( internalOptions );
472
473
  handleTenantDiscriminator(options, internalOptions, messageFunctions);
474
+ if (!options.dry && internalOptions.script) {
475
+ messageFunctions.error('api-invalid-combination', null, { '#': 'dry-and-script', value: options.dry || 'undefined' });
476
+ messageFunctions.throwWithError();
477
+ }
478
+
479
+ if (internalOptions.script && !internalOptions.severities?.['type-unsupported-key-change']) {
480
+ internalOptions.severities ??= {};
481
+ internalOptions.severities['type-unsupported-key-change'] = 'warning';
482
+ }
483
+
473
484
  const { error, throwWithError } = messageFunctions;
474
485
 
475
486
  // Prepare after-image.
@@ -479,7 +490,7 @@ function sqlMigration( csn, options, messageFunctions, beforeImage ) {
479
490
  // Compare both images.
480
491
  const diff = modelCompare.compareModels(beforeImage || afterImage, afterImage, internalOptions);
481
492
  messageFunctions.setModel(diff);
482
- const diffFilterObj = diffFilter[internalOptions.sqlDialect];
493
+ const diffFilterObj = diffFilter.getFilter(internalOptions);
483
494
 
484
495
  if (diffFilterObj) {
485
496
  diff.extensions = diff.extensions.filter(ex => diffFilterObj.extension(ex, messageFunctions));
@@ -487,6 +498,9 @@ function sqlMigration( csn, options, messageFunctions, beforeImage ) {
487
498
  Object.entries(diff.deletions).forEach(entry => diffFilterObj.deletion(entry, error));
488
499
  diff.changedPrimaryKeys = diff.changedPrimaryKeys
489
500
  .filter(an => diffFilterObj.changedPrimaryKeys(an));
501
+
502
+ if (internalOptions.script && diffFilterObj.hasLossyChanges())
503
+ messageFunctions.warning('def-unsupported-changes', null, null, 'Found potentially lossy changes - check generated SQL statements');
490
504
  }
491
505
 
492
506
  const identifierUtils = sqlUtils.getIdentifierUtils(csn, internalOptions);
@@ -494,7 +508,10 @@ function sqlMigration( csn, options, messageFunctions, beforeImage ) {
494
508
  const drops = {
495
509
  creates: {},
496
510
  final: Object.entries(diff.deletions).reduce((previous, [ name, artifact ]) => {
497
- previous[name] = `DROP ${ (artifact.query || artifact.projection) ? 'VIEW' : 'TABLE' } ${ identifierUtils.renderArtifactName(name) };`;
511
+ if (artifact.query || artifact.projection)
512
+ previous[name] = `DROP VIEW ${ identifierUtils.renderArtifactName(name) };`;
513
+ else
514
+ previous[name] = `-- [WARNING] this statement is lossy\nDROP TABLE ${ identifierUtils.renderArtifactName(name) };`;
498
515
  return previous;
499
516
  }, {}),
500
517
  };
@@ -44,6 +44,7 @@ const publicOptionsNewAPI = [
44
44
  'odataXServiceRefs',
45
45
  'odataV2PartialConstr',
46
46
  'odataVocabularies',
47
+ 'odataNoCreator',
47
48
  'service',
48
49
  'serviceNames',
49
50
  //
@@ -53,6 +54,8 @@ const publicOptionsNewAPI = [
53
54
  'resolveProjections',
54
55
  'remapOdataAnnotations',
55
56
  'keepLocalized',
57
+ // to.sql.migration
58
+ 'script',
56
59
  ];
57
60
 
58
61
  // Internal options used for testing/debugging etc.
@@ -195,7 +198,7 @@ module.exports = {
195
198
  return translateOptions(options, defaultOptions, hardOptions, undefined, [ 'valid-structured' ], 'to.odata');
196
199
  },
197
200
  },
198
- for: { // TODO: Rename version to oDataVersion
201
+ for: {
199
202
  odata: (options) => {
200
203
  const hardOptions = { toOdata: true };
201
204
  const defaultOptions = { odataVersion: 'v4', odataFormat: 'flat' };
@@ -118,6 +118,11 @@ const validators = {
118
118
  expected: () => 'type boolean|number',
119
119
  found: val => `type ${ typeof val }`,
120
120
  },
121
+ withLocations: {
122
+ validate: val => typeof val === 'boolean' || val === 'withEndPosition',
123
+ expected: () => 'type boolean|"withEndPosition"',
124
+ found: val => `type ${ typeof val }`,
125
+ },
121
126
  dictionaryPrototype: {
122
127
  validate: () => true,
123
128
  },
@@ -17,6 +17,7 @@ const propagationRules = {
17
17
  '@cds.autoexpose': 'onlyViaArtifact',
18
18
  '@cds.autoexposed': 'never',
19
19
  '@cds.external': 'never',
20
+ '@cds.java.this.name': 'onlyViaParent',
20
21
  '@cds.persistence.calcview': 'never',
21
22
  '@cds.persistence.exists': 'never',
22
23
  '@cds.persistence.skip': 'notWithPersistenceTable',
@@ -157,6 +157,9 @@ const centralMessages = {
157
157
  'syntax-duplicate-equal-clause': { severity: 'Warning' },
158
158
  'syntax-invalid-name': { severity: 'Error', configurableFor: 'deprecated' },
159
159
  'syntax-missing-as': { severity: 'Error', configurableFor: true },
160
+ 'syntax-missing-proj-semicolon': { severity: 'Warning', errorFor: [ 'v6' ] },
161
+ 'syntax-unexpected-after': { severity: 'Warning', errorFor: [ 'v6' ] },
162
+ 'syntax-unexpected-many-one': { severity: 'Error', configurableFor: true }, // TODO: remove `configurableFor` soon, latest v6
160
163
  'syntax-unexpected-null': { severity: 'Error', configurableFor: true },
161
164
  'syntax-unexpected-reserved-word': { severity: 'Error', configurableFor: true },
162
165
  'syntax-unknown-escape': { severity: 'Error', configurableFor: true },
@@ -260,7 +263,8 @@ const centralMessageTexts = {
260
263
  std: 'Invalid option combination found: $(OPTION) and $(PROP)', // unused
261
264
  'valid-structured': 'Structured OData is only supported with OData version v4',
262
265
  'sql-dialect-and-naming': 'sqlDialect $(NAME) can\'t be combined with sqlMapping $(PROP)',
263
- 'tenant-and-naming': 'Option $(OPTION) can\'t be combined with sqlMapping $(PROP) - expected sqlMapping $(VALUE)'
266
+ 'tenant-and-naming': 'Option $(OPTION) can\'t be combined with sqlMapping $(PROP) - expected sqlMapping $(VALUE)',
267
+ 'dry-and-script': 'script:true must be combined with dry:true, found $(VALUE)',
264
268
  },
265
269
  'api-unexpected-combination': {
266
270
  std: 'Unexpected option combination: $(OPTION) and $(PROP)', // unused
@@ -356,6 +360,12 @@ const centralMessageTexts = {
356
360
  std: 'Annotations can\'t be used in a column with $(CODE)',
357
361
  doc: 'Doc comments can\'t be used in a column with $(CODE)',
358
362
  },
363
+ 'syntax-unexpected-after': {
364
+ std: 'Unexpected $(KEYWORD) after annotation assignment',
365
+ many: 'Unexpected $(KEYWORD) after array type',
366
+ enum: 'Unexpected annotation assignment after enum type',
367
+ },
368
+ 'syntax-unexpected-many-one': 'Replace $(CODE) with $(DELIMITED) to avoid an ambiguity with managed compositions of anonymous aspects',
359
369
  'syntax-invalid-name': {
360
370
  std: 'Identifier must consist of at least one character', // only via delimited id
361
371
  // as: 'String in property $(PROP) must not be empty', // expecting non-empty string is ok
@@ -694,8 +704,16 @@ const centralMessageTexts = {
694
704
  'annotation': 'Variable $(NAME) can only be used in annotation values',
695
705
  },
696
706
 
697
- // TODO: Better text ?
698
- 'rewrite-not-supported': 'The ON-condition is not rewritten here - provide an explicit ON-condition',
707
+ 'rewrite-not-supported': {
708
+ // TODO: Better text ?
709
+ std: 'The ON-condition is not rewritten here - provide an explicit ON-condition',
710
+ 'inline-expand': 'The ON-condition is not rewritten in nested projections - provide an explicit ON-condition',
711
+ 'secondary': 'The ON-condition is not rewritten due to multiple associations in this path - provide an explicit ON-condition',
712
+ },
713
+ 'rewrite-not-projected': {
714
+ std: 'Projected association $(NAME) uses non-projected element $(ELEMREF)',
715
+ element: 'Projected association $(NAME) uses non-projected element $(ELEMREF) of $(ART)',
716
+ },
699
717
  'type-unsupported-rewrite': {
700
718
  std: 'Rewriting the ON-condition not supported here', // unused: merge with 'rewrite-not-supported'
701
719
  'sub-element': 'Rewriting the ON-condition of unmanaged association in sub element is not supported'
@@ -745,6 +763,13 @@ const centralMessageTexts = {
745
763
  'onCond': 'Unexpected $(KEYWORD) on an association/composition with ON-condition; $(KEYWORD) requires exactly one foreign key',
746
764
  'targetAspect': 'Unexpected $(KEYWORD) on composition of aspect'
747
765
  },
766
+ 'type-expecting-service-target': {
767
+ std: 'Expecting service entity $(TARGET)',
768
+ ref: 'Expecting service entity $(TARGET); its element $(ID) referred to at line $(LINE), column $(COL) is not from an element with the same name in the provided model target',
769
+ key: 'Expecting service entity $(TARGET); its key element $(ID) is not from a key element with the same name in the provided model target',
770
+ missing: 'Expecting service entity $(TARGET); it does not have the key element $(ID) of the provided model target',
771
+ order: 'Expecting service entity $(TARGET); its key elements are in a different order than those of the provided model target',
772
+ },
748
773
 
749
774
  'anno-builtin': 'Builtin types should not be annotated nor extended. Use custom type instead',
750
775
  'ext-undefined-def': 'Artifact $(ART) has not been found',
@@ -980,6 +1005,13 @@ const centralMessageTexts = {
980
1005
  foreignKeys: 'Foreign key $(ID) does not result from the query',
981
1006
  },
982
1007
 
1008
+ // ID published! Used in stakeholder project; if renamed, add to oldMessageIds
1009
+ 'redirected-to-complex': {
1010
+ std: 'Redirection involves the complex view $(ART); add an explicit ON-condition/foreign keys to redirection',
1011
+ target: 'The redirected target $(ART) is a complex view; add an explicit ON-condition/foreign keys to redirection',
1012
+ targetOp: 'The redirected target $(ART) is a complex view with $(KEYWORD); add an explicit ON-condition/foreign keys to redirection',
1013
+ },
1014
+
983
1015
  'ref-sloppy-target': 'An entity or an aspect (not type) is expected here',
984
1016
 
985
1017
  'ref-ambiguous': {
@@ -1109,6 +1141,11 @@ const centralMessageTexts = {
1109
1141
  'odata-parameter-order': 'Unexpected mandatory after optional parameter',
1110
1142
  'odata-key-recursive': 'Unexpected recursive key $(NAME)',
1111
1143
  'odata-key-uuid-default-anno': 'Expected element of type $(TYPE) to be annotated with $(ANNO) when used as primary key in $(ID)',
1144
+ 'odata-ignoring-param-default': {
1145
+ 'std': 'Ignoring default value',
1146
+ 'xpr': 'Ignoring unexpected expression as default value',
1147
+ 'colitem': 'Ignoring unexpected default value for a structured or collection like parameter',
1148
+ },
1112
1149
  // -----------------------------------------------------------------------------------
1113
1150
  // All odata-anno MUST have a '$(ANNO)' parameter to indicate error location
1114
1151
  // -----------------------------------------------------------------------------------
@@ -908,7 +908,7 @@ function transformArg( arg, r, args, texts ) {
908
908
  return quoted( arg );
909
909
  if (arg._artifact)
910
910
  arg = arg._artifact;
911
- if (arg._outer)
911
+ while (arg._outer) // nested 'items'
912
912
  arg = arg._outer;
913
913
  if (args['#'] || args.member )
914
914
  return shortArtName( arg );
package/lib/base/model.js CHANGED
@@ -7,15 +7,6 @@
7
7
 
8
8
  const { forEach } = require('../utils/objectUtils');
9
9
 
10
- const queryOps = {
11
- query: 'select', // TODO: rename to SELECT
12
- union: 'union',
13
- intersect: 'union',
14
- except: 'union',
15
- minus: 'union',
16
- subquery: 'union', // for (subquery) with ORDER BY or LIMIT/OFFSET
17
- };
18
-
19
10
  /**
20
11
  * Object of all available beta flags that will be enabled/disabled by `--beta-mode`
21
12
  * through cdsc. Only intended for INTERNAL USE.
@@ -30,7 +21,6 @@ const availableBetaFlags = {
30
21
  mapAssocToJoinCardinality: true, // only SAP HANA HEX engine supports it
31
22
  enableUniversalCsn: true,
32
23
  odataTerms: true,
33
- optionalActionFunctionParameters: true, // not supported by runtime, yet.
34
24
  effectiveCsn: true,
35
25
  tenantVariable: true,
36
26
  calcAssoc: true,
@@ -224,7 +214,6 @@ module.exports = {
224
214
  availableBetaFlags,
225
215
  isDeprecatedEnabled,
226
216
  checkRemovedDeprecatedFlags,
227
- queryOps,
228
217
  forEachDefinition,
229
218
  forEachMember,
230
219
  forEachMemberRecursively,
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
3
  const { isBuiltinType } = require('../base/builtins');
4
- const { isBetaEnabled } = require('../base/model');
5
4
 
6
5
  // Only to be used with validator.js - a correct this value needs to be provided!
7
6
 
@@ -21,8 +20,6 @@ function checkActionOrFunction( art, artName, prop, path ) {
21
20
  // (this.options.odataProxies || this.options.odataXServiceRefs);
22
21
 
23
22
  const serviceName = this.csnUtils.getServiceName(artName);
24
- if (!serviceName && art.kind !== 'aspect')
25
- this.warning(null, path, {}, 'Functions and actions must be declared in a service');
26
23
 
27
24
  if (art.kind === 'entity') {
28
25
  for (const [ actName, act ] of Object.entries(art.actions)) {
@@ -71,15 +68,6 @@ function checkActionOrFunction( art, artName, prop, path ) {
71
68
  if (!paramType)
72
69
  return; // no type could be resolved
73
70
 
74
- // "default" is always propagated to params
75
- if (param.default && !isBetaEnabled(this.options, 'optionalActionFunctionParameters')) {
76
- this.message('param-default', currPath, { '#': actKind }, {
77
- std: 'Artifact parameters can\'t have a default value', // Not used
78
- action: 'Action parameters can\'t have a default value',
79
- function: 'Function parameters can\'t have a default value',
80
- });
81
- }
82
-
83
71
  if (param.type && this.csnUtils.isAssocOrComposition(param)) {
84
72
  this.error(null, currPath, { '#': actKind }, {
85
73
  std: 'An association is not allowed as this artifact\'s parameter type', // Not used
@@ -1,27 +1,23 @@
1
1
  'use strict';
2
2
 
3
3
  const { isBuiltinType } = require('../base/builtins');
4
- const { transformExpression, applyTransformationsOnNonDictionary } = require('../model/csnUtils');
4
+ const { transformAnnotationExpression } = require('../model/csnUtils');
5
5
  /**
6
6
  *
7
7
  * @param {object} member
8
8
  */
9
9
  function checkAnnotationExpression( member, _memberName, _prop, path ) {
10
10
  Object.keys(member).filter(pn => pn[0] === '@').forEach((anno) => {
11
- applyTransformationsOnNonDictionary(member, anno, {
12
- xpr: (parent, prop, _xpr, xprPath) => {
13
- transformExpression(parent, prop, {
14
- ref: (elemref, __prop, ref, refPath) => {
15
- const { art, scope } = this.csnUtils.inspectRef(refPath);
16
- if (scope !== '$magic' && art) {
17
- const ft = this.csnUtils.getFinalTypeInfo(art.type);
18
- if (!isBuiltinType(ft?.type))
19
- this.error('odata-anno-xpr-ref', refPath, { anno, elemref, '#': 'flatten_builtin_type' });
20
- }
21
- },
22
- }, xprPath);
11
+ transformAnnotationExpression(member, anno, {
12
+ ref: (elemref, __prop, _ref, refPath) => {
13
+ const { art, scope } = this.csnUtils.inspectRef(refPath);
14
+ if (scope !== '$magic' && art) {
15
+ const ft = this.csnUtils.getFinalTypeInfo(art.type);
16
+ if (!isBuiltinType(ft?.type))
17
+ this.error('odata-anno-xpr-ref', refPath, { anno, elemref, '#': 'flatten_builtin_type' });
18
+ }
23
19
  },
24
- }, {}, path);
20
+ }, path);
25
21
  });
26
22
  }
27
23