@sap/cds-compiler 3.0.2 → 3.1.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 (72) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/bin/.eslintrc.json +2 -1
  3. package/bin/cdsc.js +19 -0
  4. package/doc/API.md +11 -0
  5. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  6. package/doc/CHANGELOG_BETA.md +24 -2
  7. package/doc/CHANGELOG_DEPRECATED.md +21 -1
  8. package/lib/api/main.js +7 -7
  9. package/lib/api/options.js +2 -3
  10. package/lib/base/message-registry.js +17 -5
  11. package/lib/base/messages.js +18 -39
  12. package/lib/base/model.js +2 -0
  13. package/lib/checks/actionsFunctions.js +8 -7
  14. package/lib/checks/selectItems.js +96 -14
  15. package/lib/checks/types.js +5 -8
  16. package/lib/checks/validator.js +1 -2
  17. package/lib/compiler/assert-consistency.js +64 -12
  18. package/lib/compiler/base.js +6 -4
  19. package/lib/compiler/builtins.js +58 -8
  20. package/lib/compiler/checks.js +1 -1
  21. package/lib/compiler/define.js +25 -22
  22. package/lib/compiler/extend.js +16 -10
  23. package/lib/compiler/finalize-parse-cdl.js +5 -9
  24. package/lib/compiler/index.js +2 -0
  25. package/lib/compiler/populate.js +34 -31
  26. package/lib/compiler/propagator.js +11 -6
  27. package/lib/compiler/resolve.js +14 -15
  28. package/lib/compiler/shared.js +53 -26
  29. package/lib/compiler/tweak-assocs.js +5 -11
  30. package/lib/compiler/utils.js +13 -4
  31. package/lib/edm/annotations/preprocessAnnotations.js +8 -4
  32. package/lib/edm/csn2edm.js +3 -3
  33. package/lib/edm/edm.js +9 -1
  34. package/lib/edm/edmAnnoPreprocessor.js +349 -0
  35. package/lib/edm/edmInboundChecks.js +85 -0
  36. package/lib/edm/edmPreprocessor.js +295 -638
  37. package/lib/edm/edmUtils.js +85 -5
  38. package/lib/gen/Dictionary.json +29 -9
  39. package/lib/gen/language.checksum +1 -1
  40. package/lib/gen/language.interp +1 -2
  41. package/lib/gen/languageLexer.js +3 -0
  42. package/lib/gen/languageParser.js +4344 -4530
  43. package/lib/inspect/.eslintrc.json +4 -0
  44. package/lib/inspect/index.js +14 -0
  45. package/lib/inspect/inspectModelStatistics.js +81 -0
  46. package/lib/inspect/inspectPropagation.js +189 -0
  47. package/lib/inspect/inspectUtils.js +44 -0
  48. package/lib/json/from-csn.js +3 -2
  49. package/lib/json/to-csn.js +8 -6
  50. package/lib/language/genericAntlrParser.js +121 -63
  51. package/lib/language/language.g4 +19 -57
  52. package/lib/main.d.ts +1 -0
  53. package/lib/model/api.js +1 -1
  54. package/lib/model/csnRefs.js +55 -29
  55. package/lib/model/csnUtils.js +11 -7
  56. package/lib/model/revealInternalProperties.js +2 -3
  57. package/lib/modelCompare/compare.js +3 -0
  58. package/lib/optionProcessor.js +27 -0
  59. package/lib/render/toCdl.js +57 -32
  60. package/lib/render/toSql.js +24 -8
  61. package/lib/render/utils/common.js +3 -4
  62. package/lib/transform/db/associations.js +43 -35
  63. package/lib/transform/db/cdsPersistence.js +0 -1
  64. package/lib/transform/db/flattening.js +3 -4
  65. package/lib/transform/db/transformExists.js +7 -5
  66. package/lib/transform/draft/db.js +1 -1
  67. package/lib/transform/forHanaNew.js +11 -2
  68. package/lib/transform/forOdataNew.js +1 -1
  69. package/lib/transform/odata/typesExposure.js +14 -5
  70. package/lib/utils/moduleResolve.js +0 -1
  71. package/package.json +2 -2
  72. package/lib/checks/unknownMagic.js +0 -41
package/CHANGELOG.md CHANGED
@@ -7,6 +7,55 @@
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.1.0 - 2022-08-04
11
+
12
+ ### Added
13
+
14
+ - Extending an artifact with multiple includes in one extend statement is now possible:
15
+ `extend SomeEntity with FirstInclude, SecondInclude;`
16
+ - Aspects can now have actions and functions, similar to entities. Aspects can be extended by actions as well.
17
+ - `cdsc`:
18
+ - `toCsn` now supports `--with-locations` which adds a `$location` property to artifacts
19
+ - `toHana`/`toSql` now supports `--disable-hana-comments`, which disables rendering of doc-comments for HANA.
20
+ - to.hdi/sql/hdbcds: Support FK-access in `ORDER BY` and `GROUP BY`
21
+ - to.hdi.migration: Detect an implicit change from `not null` to `null` and render corresponding `ALTER`
22
+
23
+ ### Changed
24
+
25
+ - compiler: If an unknown file extension is used but the file starts with
26
+ an opening curly brace (`{`), it will be parsed as CSN.
27
+ - to.edm(x): In V4 containment mode, pull up `@Capabilities` annotations from the containees to the root container (set)
28
+ and translate them into corresponding `@Capabilities.NavigationRestrictions`. If a `NavigationRestriction` is already available
29
+ for that containment path, capabilities are merged into this path. Capability annotation value paths are prefixed with
30
+ the navigation restriction path.
31
+ The capability 'pull up' has an effect on entity annotations only. `@Capabilities` assignments on compositions are not pulled
32
+ up but rendered to the association type which is important to enable dynamic capabilities on 'to-many' relations and to avoid
33
+ ambiguities in entity set capabilities.
34
+ - Update OData vocabularies 'Analytics', 'Capabilities', 'Common', 'Core', 'DataIntegration', 'Graph', 'PersonalData', 'UI', 'Validation'.
35
+
36
+ ### Fixed
37
+
38
+ - Syntax of date/time literals are now checked against ISO 8601. If the format is invalid, a warning is emitted.
39
+ - The code completion directly after the `(` for functions with special syntax
40
+ now suggests all valid keywords, like for `extract` or `locate_regexpr`.
41
+ - compiler:
42
+ + `cast(elem as EnumType)` crashed the compiler.
43
+ + Annotations on sub-elements in query entities were lost during re-compilation.
44
+ + An association's cardinality was lost for associations published in projections.
45
+ + Annotations on indirect action parameters were lost in CSN flavor `gensrc`.
46
+ + If a file's content starts with `{` and if neither file extension is known nor
47
+ `fallbackParser` is set, assume the source is CSN.
48
+ - all backends: references in `order by` _expressions_ are correctly resolved.
49
+ - to.edm(x):
50
+ + Allow cross service references for unmanaged associations and improve warning message for muted associations.
51
+ + Nested `@UI.TextArrangement` has precedence over `@TextArrangement` shortcut annotation for `@Common.Text`.
52
+ - to.hdi.migration:
53
+ + Doc comments rendered the _full doc comment_ instead of only the first paragraph, as `to.hdi` does.
54
+ + Respect option `disableHanaComments` when rendering the `ALTER` statements
55
+ - to.hdi/sql/hdbcds:
56
+ + Check for invalid usages of `$self` and give helpful errors
57
+ + Correctly resolve association-steps in the from-clause in conjunction with `exists`
58
+
10
59
  ## Version 3.0.2 - 2022-07-05
11
60
 
12
61
  ### Fixed
@@ -59,6 +108,22 @@ The compiler behavior concerning `beta` features can change at any time without
59
108
  it is now only allowed for `count`, `min`, `max`, `sum`, `avg`, `stddev`, `var`.
60
109
  - All non-SNAPI options.
61
110
 
111
+ ## Version 2.15.8 - 2022-08-02
112
+
113
+ ### Fixed
114
+
115
+ - to.edm(x): Nested `@UI.TextArrangement` has precedence over `@TextArrangement` shortcut annotation for `@Common.Text`.
116
+ - to.hdi.migration:
117
+ + Respect option `disableHanaComments` when rendering the `ALTER` statements
118
+ + Doc comments rendered the _full doc comment_ instead of only the first paragraph, as `to.hdi` does.
119
+ - compiler: An association's cardinality was lost for associations published in projections.
120
+
121
+ ## Version 2.15.6 - 2022-07-26
122
+
123
+ ### Fixed
124
+
125
+ - Annotations on sub-elements were lost during re-compilation.
126
+
62
127
  ## Version 2.15.4 - 2022-06-09
63
128
 
64
129
  ### Fixed
@@ -11,6 +11,7 @@
11
11
  "no-process-exit": "off",
12
12
  "camelcase": "off",
13
13
  "radix": "off",
14
- "no-shadow": "warn"
14
+ "no-shadow": "warn",
15
+ "global-require": "off"
15
16
  }
16
17
  }
package/bin/cdsc.js CHANGED
@@ -262,6 +262,7 @@ function executeCommandLine(command, options, args) {
262
262
  toRename,
263
263
  manageConstraints,
264
264
  toSql,
265
+ inspect,
265
266
  };
266
267
  const commandsWithoutCompilation = {
267
268
  explain,
@@ -425,6 +426,24 @@ function executeCommandLine(command, options, args) {
425
426
  console.log(explainMessage(args.messageId));
426
427
  }
427
428
 
429
+ function inspect(model) {
430
+ const inspectModel = require('../lib/inspect');
431
+
432
+ if (options.statistics) {
433
+ const result = inspectModel.inspectModelStatistics(model, options);
434
+ if (result)
435
+ console.log(result);
436
+ }
437
+
438
+ if (options.propagation) {
439
+ const result = inspectModel.inspectPropagation(model, options, options.propagation);
440
+ if (result)
441
+ console.log(result);
442
+ }
443
+
444
+ return model;
445
+ }
446
+
428
447
  // Display error messages in `err` resulting from a compilation. Also set
429
448
  // process.exitCode - process.exit() will force the process to exit as quickly
430
449
  // as possible = is problematic, since console.error() might be asynchronous
package/doc/API.md ADDED
@@ -0,0 +1,11 @@
1
+ # CDS Compiler API Documentation
2
+
3
+ The API of `@sap/cds-compiler` is described in a TypeScript declaration file
4
+ [`main.d.ts`](../lib/main.d.ts).
5
+
6
+ Refer to that file for documentation on option names, API calls, and more.
7
+
8
+ You can use [TypeDoc] to render an HTML documentation from it.
9
+
10
+
11
+ [TypeDoc]: https://typedoc.org/
@@ -270,7 +270,7 @@ The compiler behaviour concerning `beta` features can change at any time without
270
270
  - to.sql/hdi/hdbcds:
271
271
  + Doc comments are translated into HANA comments (or into `@Comment` annotation for `to.hdbcds`).
272
272
  Such comments are possible on entities, views, elements of entities and `to.hdbcds` also supports comments on view columns.
273
- Generation can be disabled via option `disableHanaComments`. Entites/views (and their elements/columns)
273
+ Generation can be disabled via option `disableHanaComments`. Entities/views (and their elements/columns)
274
274
  annotated with `@cds.persistence.journal` for `to.hdi`/`to.sql` will not have comments rendered.
275
275
  + Generation of temporal `WHERE` clause can be suppressed by annotating the `validFrom`/`validTo` elements of the projection with `false` or `null`.
276
276
  - to.sql/hdi/hdbcds/edm(x)/for.odata: Structure/managed association comparisons (tuple comparisons) are now
@@ -8,7 +8,29 @@ 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 3.0.0 - 2022-XX-YY
11
+ ## Version 3.1.0 - 2022-08-04
12
+
13
+ ### Added `optionalActionFunctionParameters`
14
+
15
+ - to.edm(x): Annotate optional function/action parameters with `@Core.OptionalParameter` for OData V4.
16
+ An action/function parameter is optional if
17
+ 1) it is already annotated with `@Core.OptionalParameter` regardless of its definition.
18
+ 2) it has a default value (including null), regardless of it's nullability
19
+ 3) it has NO default value but is nullable (the implicit default value is null)
20
+
21
+ If a mandatory parameter (not null and no default value) appears after an optional
22
+ parameter, a warning is raised, Core.OptionalParameter requires that all optional
23
+ parameters appear rightmost.
24
+
25
+ ### Added `odataOpenType`
26
+
27
+ - to.edm(x): Support annotation `@open` on entity and structured type level to declare the corresponding entity/complex type to
28
+ be `OpenType=true`. If an open structured type is declared closed (with a falsy annotation value), the corresponding EDM type
29
+ is closed as well and suffixed with `_closed` (or `_open` vice versa).
30
+ No further checks are performed on possibly open foreign or primary key types nor on eventually bucket elements to store the
31
+ additional data.
32
+
33
+ ## Version 3.0.0 - 2022-06-23
12
34
 
13
35
  ### Removed `addTextsLanguageAssoc`
14
36
 
@@ -134,7 +156,7 @@ When the beta option `subElemRedirections` is set to true,
134
156
  _all_ array (new!) and structure types are expanded when referenced:
135
157
  managed associations (and compositions to entities) in that array are
136
158
  implicitly redirected when necessary.
137
- See [below for details](#version-1300---20200612).
159
+ See [below for details](#version-1300---2020-06-12).
138
160
 
139
161
  Nested array types (without intermediate structure types) are not supported.
140
162
 
@@ -11,10 +11,28 @@ Note: `deprecated` features are listed in this ChangeLog just for information.
11
11
  **When the `deprecated` option is set, the `beta` option is ignored,
12
12
  and several new features are not available.**
13
13
 
14
- ## Version 3.0.0 - 2022-XX-YY
14
+ ## Version 3.1.0 - 2022-08-04
15
+
16
+ ### Added `autoCorrectOrderBySourceRefs`
17
+
18
+ When this option is set, calling `compile` auto-corrects direct `order by`
19
+ source element references without table alias for SELECT queries by adding the
20
+ table alias to the `ref`.
21
+
22
+ Using this option might lead to surprising results when elements are added to
23
+ existing models: `order by` specifications might change their semantics without
24
+ any extra messages.
25
+
26
+ ## Version 3.0.0 - 2022-06-23
15
27
 
16
28
  Version 3 of the cds-compiler removes all v2 deprecated flags.
17
29
 
30
+ ### Add `eagerPersistenceForGeneratedEntities`
31
+
32
+ If enabled, the old behavior regarding `@cds.persistence.skip` and `@cds.persistence.exists`
33
+ is restored, i.e. these annotations are not copied from parent to generated child entities, nor
34
+ is `@cds.persistence.exists` copied to localized convenience views.
35
+
18
36
  ### Removed `createLocalizedViews`
19
37
 
20
38
  ### Removed `downgradableErrors`
@@ -25,6 +43,8 @@ Version 3 of the cds-compiler removes all v2 deprecated flags.
25
43
 
26
44
  ### Removed `noElementsExpansion`
27
45
 
46
+ <!-- fully removed with 3.1.0 -->
47
+
28
48
  ### Removed `noInheritedAutoexposeViaComposition`
29
49
 
30
50
  ### Removed `noScopedRedirections`
package/lib/api/main.js CHANGED
@@ -408,10 +408,10 @@ function hdiMigration(csn, options, beforeImage) {
408
408
  }
409
409
 
410
410
  /**
411
- * From the given SQLs, create the the correct result structure.
411
+ * From the given SQLs, create the correct result structure.
412
412
  *
413
- * @param {object} hdbkinds
414
- * @param {CSN.Model} afterImage
413
+ * @param {object} hdbkinds Object of hdbkinds (such as `hdbindex`) mapped to dictionary of artifacts.
414
+ * @param {CSN.Model} afterImage CSN, used to create correct file names in result structure.
415
415
  * @returns {object[]} Array of objects, each having: name, suffix and sql
416
416
  */
417
417
  function createSqlDefinitions(hdbkinds, afterImage) {
@@ -430,8 +430,8 @@ function createSqlDefinitions(hdbkinds, afterImage) {
430
430
  /**
431
431
  * From the given deletions, create the correct result structure.
432
432
  *
433
- * @param {object} deletions
434
- * @param {CSN.Model} beforeImage
433
+ * @param {object} deletions Dictionary of deletions, only keys are used.
434
+ * @param {CSN.Model} beforeImage CSN used to create correct file names in result structure.
435
435
  * @returns {object[]} Array of objects, each having: name and suffix - only .hdbtable as suffix for now
436
436
  */
437
437
  function createSqlDeletions(deletions, beforeImage) {
@@ -442,8 +442,8 @@ function createSqlDeletions(deletions, beforeImage) {
442
442
  /**
443
443
  * From the given migrations, create the correct result structure.
444
444
  *
445
- * @param {object} migrations
446
- * @param {CSN.Model} afterImage
445
+ * @param {object} migrations Dictionary of changesets (migrations).
446
+ * @param {CSN.Model} afterImage CSN used to create correct file names in result structure.
447
447
  * @returns {object[]} Array of objects, each having: name, suffix and changeset.
448
448
  */
449
449
  function createSqlMigrations(migrations, afterImage) {
@@ -57,9 +57,7 @@ const privateOptions = [
57
57
  'noRecompile',
58
58
  'internalMsg',
59
59
  'disableHanaComments', // in case of issues with hana comment rendering
60
- 'dependentAutoexposed', // deprecated, no effect - TODO: safe to remove?
61
- 'longAutoexposed', // deprecated, no effect - TODO: safe to remove?
62
- 'localizedWithoutCoalesce', // deprecated version of 'localizedLanguageFallback',
60
+ 'localizedWithoutCoalesce', // deprecated version of 'localizedLanguageFallback', TODO(v4): Remove option
63
61
  ];
64
62
 
65
63
  const overallOptions = publicOptionsNewAPI.concat(privateOptions);
@@ -159,6 +157,7 @@ module.exports = {
159
157
  return translateOptions(options, defaultOptions, hardOptions, undefined, undefined, 'for.hana');
160
158
  },
161
159
  },
160
+ overallOptions, // exported for testing
162
161
  };
163
162
 
164
163
 
@@ -114,7 +114,7 @@ const centralMessages = {
114
114
  'ref-undefined-def': { severity: 'Error' },
115
115
  'ref-undefined-var': { severity: 'Error' },
116
116
  'ref-undefined-element': { severity: 'Error' },
117
- 'ref-unknown-var': { severity: 'Info' },
117
+ 'ref-unknown-var': { severity: 'Info', errorFor: [ 'to.hdbcds', 'to.sql', 'to.hdi', 'to.rename' ] },
118
118
  'ref-obsolete-parameters': { severity: 'Error', configurableFor: true }, // does not hurt us
119
119
  'ref-undefined-param': { severity: 'Error' },
120
120
  'ref-rejected-on': { severity: 'Error' },
@@ -131,6 +131,10 @@ const centralMessages = {
131
131
  'service-nested-context': { severity: 'Error', configurableFor: true }, // does not hurt compile, TODO
132
132
  'service-nested-service': { severity: 'Error', configurableFor: 'deprecated' }, // not supported yet
133
133
 
134
+ // 'syntax-duplicate-annotate' came late with v3 - make it configurable as
135
+ // fallback, but then parse.cdl is not supposed to work correctly (it can
136
+ // then either issue an error or produce a CSN missing some annotations):
137
+ 'syntax-duplicate-annotate': { severity: 'Error', configurableFor: true },
134
138
  'syntax-expected-cardinality': { severity: 'Error' },
135
139
  'syntax-expected-length': { severity: 'Error' },
136
140
  'syntax-expected-translation': { severity: 'Error' },
@@ -205,7 +209,7 @@ for (const oldName in oldMessageIds) {
205
209
  // For messageIds, where no text has been provided via code (central def)
206
210
  const centralMessageTexts = {
207
211
  'api-invalid-option': {
208
- std: 'Option $(NAME) is deprecated! Use SNAPI options instead',
212
+ std: 'Option $(NAME) is no longer supported! Use SNAPI options instead',
209
213
  magicVars: 'Option “magicVars” is no longer supported! Use “variableReplacements” instead. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
210
214
  user: 'Option “variableReplacements” expects “$user” instead of “user”. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
211
215
  locale: 'Option “variableReplacements” expects “$user.locale” instead of “locale”. See <https://cap.cloud.sap/docs/guides/databases#configuring-variables> for details',
@@ -228,6 +232,10 @@ const centralMessageTexts = {
228
232
  'flatten-fkey-exists': 'Generated foreign key element $(NAME) for association $(ART) conflicts with existing element',
229
233
  },
230
234
 
235
+ 'syntax-anno-ignored': {
236
+ std: 'Annotations can\'t be used at prefix references',
237
+ doc: 'Doc comments can\'t be used at prefix references',
238
+ },
231
239
  'syntax-unexpected-ellipsis': {
232
240
  std: 'Expected no more than one $(CODE)',
233
241
  'nested-array': 'Unexpected $(CODE) in nested array'
@@ -276,7 +284,7 @@ const centralMessageTexts = {
276
284
  unknown: 'Unknown argument $(CODE)',
277
285
  duplicate: 'Duplicate argument $(CODE)',
278
286
  },
279
- 'syntax-duplicate-annotate': 'You shouldn\'t refer to $(NAME) repeatedly in the same annotate statement',
287
+ 'syntax-duplicate-annotate': 'You can\'t refer to $(NAME) repeatedly with property $(PROP) in the same annotate statement',
280
288
  'syntax-duplicate-extend': {
281
289
  std: 'You can\'t define and refer to $(NAME) repeatedly in the same extend statement',
282
290
  define: 'You can\'t refer to $(NAME) in the same extend statement where it was defined',
@@ -309,7 +317,7 @@ const centralMessageTexts = {
309
317
  aspect: 'Element $(ID) has not been found in the anonymous target aspect'
310
318
  },
311
319
  'ref-unknown-var': {
312
- std: 'Replacement $(ID) not found'
320
+ std: 'No replacement found for special variable $(ID)'
313
321
  },
314
322
  'ref-unexpected-draft-enabled': 'Composition in draft-enabled entity can\'t lead to another entity with $(ANNO)',
315
323
  'ref-rejected-on': {
@@ -467,7 +475,11 @@ const centralMessageTexts = {
467
475
  std: 'Entity can\'t be created due to name collision with existing definition $(NAME)',
468
476
  proxy: 'No proxy entity created due to name collision with existing definition $(NAME) of kind $(KIND)'
469
477
  },
470
- 'odata-navigation': 'No OData navigation property generated, target $(TARGET) is outside of service $(SERVICE)'
478
+ 'odata-navigation': {
479
+ std: 'No OData navigation property generated, target $(TARGET) is outside of service $(SERVICE)',
480
+ oncond: 'No OData navigation property generated for association with arbitrary ON condition and target $(TARGET) outside of service $(SERVICE)'
481
+ },
482
+ 'odata-parameter-order': 'Unexpected mandatory after optional parameter',
471
483
  }
472
484
 
473
485
  /**
@@ -8,7 +8,6 @@ const { term } = require('../utils/term');
8
8
  const { locationString } = require('./location');
9
9
  const { isDeprecatedEnabled } = require('./model');
10
10
  const { centralMessages, centralMessageTexts, oldMessageIds } = require('./message-registry');
11
- const { copyPropIfExist } = require('../utils/objectUtils');
12
11
  const _messageIdsWithExplanation = require('../../share/messages/message-explanations.json').messages;
13
12
  const { analyseCsnPath, traverseQuery } = require('../model/csnRefs');
14
13
  const { CompilerAssertion } = require("./error");
@@ -135,7 +134,7 @@ class CompileMessage {
135
134
  constructor(location, msg, severity = 'Error', id = null, home = null, moduleName = null) {
136
135
  this.message = msg;
137
136
  this.location = location;
138
- this.$location = dollarLocation( this.location );
137
+ this.$location = { ...this.location, address: undefined };
139
138
  this.validNames = null;
140
139
  if (home) // semantic location, e.g. 'entity:"E"/element:"x"'
141
140
  this.home = home;
@@ -152,33 +151,6 @@ class CompileMessage {
152
151
  }
153
152
  }
154
153
 
155
- /**
156
- * Temporary v1 function to convert an "old-style" location to "new-style".
157
- *
158
- * @param {CSN.Location} location
159
- * @return {CSN.Location}
160
- * @todo Remove
161
- */
162
- function dollarLocation( location ) {
163
- const file = location && location.file || undefined;
164
- if (!file)
165
- return {};
166
- const loc = {
167
- file,
168
- line: location.line,
169
- col: location.col,
170
- address: undefined,
171
- };
172
- copyPropIfExist(location, 'endLine', loc);
173
- copyPropIfExist(location, 'endCol', loc);
174
- // TODO:
175
- // return {
176
- // ...location,
177
- // address: undefined,
178
- // };
179
- return loc;
180
- }
181
-
182
154
  const severitySpecs = {
183
155
  error: { name: 'Error', level: 0 },
184
156
  warning: { name: 'Warning', level: 1 },
@@ -257,14 +229,16 @@ function compareSeverities( a, b ) {
257
229
  }
258
230
 
259
231
  /**
260
- * @todo This was copied from somewhere just to make CSN paths work.
232
+ * Find the nearest $location for the given CSN path in the model.
233
+ * If the path does not exist, the parent is used, and so on.
234
+ *
261
235
  * @param {CSN.Model} model
262
236
  * @param {CSN.Path} csnPath
237
+ * @returns {CSN.Location | null}
263
238
  */
264
- function searchForLocation( model, csnPath ) {
239
+ function findNearestLocationForPath( model, csnPath ) {
265
240
  if (!model)
266
241
  return null;
267
- // Don't display a location if we cannot find one!
268
242
  let lastLocation = null;
269
243
  /** @type {object} */
270
244
  let currentStep = model;
@@ -438,7 +412,7 @@ function makeMessageFunction( model, options, moduleName = null ) {
438
412
  const isCsnPath = (typeof location[0] === 'string'); // could be `definitions`, `extensions`, ....
439
413
  if (isCsnPath) {
440
414
  return [
441
- searchForLocation( model, location ),
415
+ findNearestLocationForPath( model, location ),
442
416
  constructSemanticLocationFromCsnPath( location, model ),
443
417
  location[1] // location[0] is 'definitions'
444
418
  ];
@@ -1086,9 +1060,10 @@ function compareMessageSeverityAware( a, b ) {
1086
1060
  * @param {CompileMessage} msg
1087
1061
  */
1088
1062
  function homeSortName( { home, messageId } ) {
1089
- return (!home)
1090
- ? (messageId && /^(syntax|api)-/.test( messageId ) ? ' ' + messageId : '~')
1091
- : home.substring( home.indexOf(':') ); // i.e. starting with the ':', is always there
1063
+ if (!home)
1064
+ return (messageId && /^(syntax|api)-/.test( messageId ) ? ' ' + messageId : '~')
1065
+ else
1066
+ return home.substring( home.indexOf(':') ); // i.e. starting with the ':', is always there
1092
1067
  }
1093
1068
 
1094
1069
  /**
@@ -1192,8 +1167,8 @@ function homeNameForExtend( art ) {
1192
1167
  const kind = art.kind || 'extend';
1193
1168
  // TODO: fix the following - do like in collectArtifactExtensions() or
1194
1169
  // basically resolveUncheckedPath()
1195
- const absoluteName = art.name.id ? art.name.id :
1196
- (!art.name.element && art.name.absolute || art.name.path.map(s => s && s.id).join('.'));
1170
+ const absoluteName = art.name.id != null ? art.name.id :
1171
+ (!art.name.element && art.name.absolute || art.name.path && art.name.path.map(s => s && s.id).join('.'));
1197
1172
 
1198
1173
  // Surrounding parent may be another extension.
1199
1174
  const parent = art._parent;
@@ -1383,8 +1358,12 @@ function constructSemanticLocationFromCsnPath(csnPath, model) {
1383
1358
  if (typeof step === 'number') {
1384
1359
  if (currentThing.as)
1385
1360
  result += `:${ _quoted(currentThing.as) }`;
1361
+ else if (inRef)
1362
+ result += `:${ _quoted(currentThing) }`;
1363
+ else if (currentThing.ref)
1364
+ result += `:${ _quoted(currentThing.ref.map(r => r.id ? r.id : r).join('.')) }`;
1386
1365
  else
1387
- result += inRef ? `:${ _quoted(currentThing) }` : currentThing.ref ? `:${ _quoted(currentThing.ref.map(r => r.id ? r.id : r).join('.')) }` : '';
1366
+ return'';
1388
1367
 
1389
1368
  break;
1390
1369
  }
package/lib/base/model.js CHANGED
@@ -30,6 +30,8 @@ const availableBetaFlags = {
30
30
  enableUniversalCsn: true,
31
31
  // disabled by --beta-mode
32
32
  nestedServices: false,
33
+ odataOpenType: true,
34
+ optionalActionFunctionParameters: true,
33
35
  };
34
36
 
35
37
  /**
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const { isBuiltinType } = require('../model/csnUtils');
4
+ const { isBetaEnabled } = require('../base/model');
4
5
 
5
6
  // Only to be used with validator.js - a correct this value needs to be provided!
6
7
 
@@ -52,13 +53,13 @@ function checkActionOrFunction(art, artName, prop, path) {
52
53
  function checkActionOrFunctionParameter(param, currPath, actKind) {
53
54
  const paramType = param.type ? this.csnUtils.getFinalTypeDef(param.type) : param;
54
55
 
55
- if (param.default || paramType.default) {
56
- this.error('param-default', currPath, { '#': actKind },
57
- {
58
- std: 'Artifact parameters can\'t have a default value', // Not used
59
- action: 'Action parameters can\'t have a default value',
60
- function: 'Function parameters can\'t have a default value',
61
- });
56
+ if (!isBetaEnabled(this.options, 'optionalActionFunctionParameters') && (param.default || paramType.default)) {
57
+ this.message('param-default', currPath, { '#': actKind },
58
+ {
59
+ std: 'Artifact parameters can\'t have a default value', // Not used
60
+ action: 'Action parameters can\'t have a default value',
61
+ function: 'Function parameters can\'t have a default value',
62
+ });
62
63
  }
63
64
 
64
65
  if (paramType.type && this.csnUtils.isAssocOrComposition(param.type)) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const { forEachGeneric } = require('../model/csnUtils');
3
+ const { forEachGeneric, applyTransformationsOnNonDictionary } = require('../model/csnUtils');
4
4
 
5
5
  // Only to be used with validator.js - a correct this value needs to be provided!
6
6
 
@@ -17,21 +17,103 @@ function validateSelectItems(query) {
17
17
  const { SELECT } = query;
18
18
  if (!SELECT)
19
19
  return;
20
+ /**
21
+ * Check for a $self.<assoc> in columns etc. - since the $self.<assoc> references the "outside" view
22
+ * of the association, this is not allowed.
23
+ *
24
+ * @param {string} queryPart Part of the query that is being checked
25
+ * @returns {Function} Function as callback for applyTransformations
26
+ */
27
+ function checkRefForInvalid$Self(queryPart) {
28
+ const signalError = (error, parent, type) => {
29
+ if (queryPart === 'columns') {
30
+ error(null, parent.$path,
31
+ { name: parent.ref[0], type },
32
+ 'Select items starting with $(NAME) must not contain path steps of type $(TYPE)');
33
+ }
34
+ else if (queryPart === 'orderBy') {
35
+ error(null, parent.$path,
36
+ { id: queryPart, type },
37
+ 'Items of the $(ID)-clause must not contain path steps of type $(TYPE)');
38
+ }
39
+ else {
40
+ error(null, parent.$path,
41
+ { id: queryPart, name: parent.ref[0], type },
42
+ 'Items of the $(ID)-clause starting with $(NAME) must not contain path steps of type $(TYPE)');
43
+ }
44
+ };
45
+ return function checkForInvalid$SelfInRef(parent) {
46
+ if (parent.ref && (parent.$scope === '$self' || parent.$scope === '$query')) {
47
+ const { _links } = parent;
48
+ for (let j = parent.$scope === '$self' ? 1 : 0; j < _links.length - 1; j++) {
49
+ if (_links[j].art.target) {
50
+ if (_links[j].art.on) {
51
+ // It's an unmanaged association - traversal is always forbidden
52
+ signalError(this.error, parent, _links[j].art.type);
53
+ }
54
+ else {
55
+ // It's a managed association - access of the foreign keys is allowed
56
+ const nextRef = parent.ref[j + 1].id || parent.ref[j + 1];
57
+ if (!_links[j].art.keys.some(r => r.ref[0] === nextRef))
58
+ signalError(this.error, parent, _links[j].art.type);
59
+ }
60
+ }
61
+ }
62
+
63
+ const last = _links[_links.length - 1];
20
64
 
21
- forEachGeneric(SELECT, 'columns', (selectItem) => {
22
- if (selectItem.ref && (selectItem.ref[0] === '$self' || selectItem.ref[0] === '$projection')) {
23
- const pathStepWithTarget = selectItem._links.slice(1).find(link => link.art.target);
24
- if (pathStepWithTarget) {
25
- this.error(null, selectItem.$path,
26
- { name: selectItem.ref[0], type: pathStepWithTarget.art.type },
27
- 'Select items starting with $(NAME) must not contain path steps of type $(TYPE)');
65
+ if (last.art.target && last.art.on) {
66
+ // It's an unmanaged association - traversal is always forbidden
67
+ signalError(this.error, parent, last.art.type);
68
+ } // managed is okay, can be handled via tuple expansion
28
69
  }
29
- }
30
- else if (this.options.transformation === 'hdbcds' && selectItem.xpr && selectItem.func) {
31
- this.error(null, selectItem.$path,
32
- 'Window functions are not supported by SAP HANA CDS');
33
- }
34
- });
70
+ };
71
+ }
72
+
73
+ /**
74
+ * Check the given assoc filter for usage of $self - in an assoc-filter, you must only
75
+ * address things on the target side of the association, not from global scope.
76
+ *
77
+ * @param {object} parent
78
+ * @param {string} prop
79
+ * @param {Array} where
80
+ */
81
+ function checkFilterForInvalid$Self(parent, prop, where) {
82
+ where.forEach((whereStep) => {
83
+ if (whereStep.ref && ( whereStep.ref[0] === '$projection' || whereStep.ref[0] === '$self')) {
84
+ this.error('expr-where-unexpected-self', whereStep.$path,
85
+ { name: whereStep.ref[0] },
86
+ 'Path steps inside of filters must not start with $(NAME)');
87
+ }
88
+ });
89
+ }
90
+
91
+ const aTCB = (parent, prop) => {
92
+ applyTransformationsOnNonDictionary(parent, prop, {
93
+ ref: checkRefForInvalid$Self(prop).bind(this),
94
+ where: checkFilterForInvalid$Self.bind(this),
95
+ }, { skipStandard: { on: true }, drillRef: true });
96
+ };
97
+
98
+ const transformers = {
99
+ columns: aTCB,
100
+ groupBy: aTCB,
101
+ orderBy: aTCB,
102
+ having: aTCB,
103
+ where: aTCB,
104
+ };
105
+
106
+ if (this.options.transformation === 'hdbcds') {
107
+ transformers.xpr = (parent) => {
108
+ if (parent.func) {
109
+ this.error(null, parent.$path,
110
+ 'Window functions are not supported by SAP HANA CDS');
111
+ }
112
+ };
113
+ }
114
+
115
+ applyTransformationsOnNonDictionary(query, 'SELECT', transformers );
116
+
35
117
  // .call() with 'this' to ensure we have access to the options
36
118
  rejectManagedAssociationsAndStructuresForHdbcdsNames.call(this, SELECT, SELECT.$path);
37
119
  }