@sap/cds-compiler 2.12.0 → 2.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/CHANGELOG.md +221 -15
  2. package/bin/cdsc.js +125 -50
  3. package/bin/cdsse.js +2 -2
  4. package/doc/CHANGELOG_BETA.md +13 -6
  5. package/doc/CHANGELOG_DEPRECATED.md +22 -6
  6. package/doc/NameResolution.md +21 -16
  7. package/lib/api/main.js +47 -84
  8. package/lib/api/options.js +5 -6
  9. package/lib/api/validate.js +6 -11
  10. package/lib/backends.js +15 -23
  11. package/lib/base/dictionaries.js +0 -8
  12. package/lib/base/error.js +26 -0
  13. package/lib/base/keywords.js +7 -17
  14. package/lib/base/location.js +9 -4
  15. package/lib/base/message-registry.js +114 -18
  16. package/lib/base/messages.js +101 -90
  17. package/lib/base/model.js +2 -63
  18. package/lib/base/optionProcessorHelper.js +177 -123
  19. package/lib/checks/annotationsOData.js +12 -33
  20. package/lib/checks/arrayOfs.js +1 -34
  21. package/lib/checks/cdsPersistence.js +2 -1
  22. package/lib/checks/enricher.js +17 -1
  23. package/lib/checks/invalidTarget.js +3 -1
  24. package/lib/checks/managedWithoutKeys.js +3 -1
  25. package/lib/checks/selectItems.js +4 -4
  26. package/lib/checks/sql-snippets.js +27 -26
  27. package/lib/checks/types.js +1 -1
  28. package/lib/checks/validator.js +6 -11
  29. package/lib/compiler/assert-consistency.js +6 -3
  30. package/lib/compiler/base.js +1 -0
  31. package/lib/compiler/builtins.js +19 -6
  32. package/lib/compiler/checks.js +23 -60
  33. package/lib/compiler/cycle-detector.js +1 -1
  34. package/lib/compiler/define.js +1151 -0
  35. package/lib/compiler/extend.js +1000 -0
  36. package/lib/compiler/finalize-parse-cdl.js +237 -0
  37. package/lib/compiler/index.js +107 -39
  38. package/lib/compiler/kick-start.js +190 -0
  39. package/lib/compiler/moduleLayers.js +4 -4
  40. package/lib/compiler/populate.js +1227 -0
  41. package/lib/compiler/propagator.js +114 -46
  42. package/lib/compiler/resolve.js +1521 -0
  43. package/lib/compiler/shared.js +126 -65
  44. package/lib/compiler/tweak-assocs.js +535 -0
  45. package/lib/compiler/utils.js +197 -33
  46. package/lib/edm/.eslintrc.json +5 -0
  47. package/lib/edm/annotations/genericTranslation.js +38 -24
  48. package/lib/edm/annotations/preprocessAnnotations.js +2 -2
  49. package/lib/edm/csn2edm.js +219 -100
  50. package/lib/edm/edm.js +302 -230
  51. package/lib/edm/edmPreprocessor.js +554 -419
  52. package/lib/edm/edmUtils.js +138 -44
  53. package/lib/gen/Dictionary.json +100 -19
  54. package/lib/gen/language.checksum +1 -1
  55. package/lib/gen/language.interp +11 -1
  56. package/lib/gen/language.tokens +86 -83
  57. package/lib/gen/languageLexer.interp +10 -1
  58. package/lib/gen/languageLexer.js +860 -833
  59. package/lib/gen/languageLexer.tokens +78 -75
  60. package/lib/gen/languageParser.js +5765 -4480
  61. package/lib/json/csnVersion.js +10 -11
  62. package/lib/json/from-csn.js +15 -3
  63. package/lib/json/to-csn.js +126 -68
  64. package/lib/language/docCommentParser.js +4 -4
  65. package/lib/language/genericAntlrParser.js +123 -5
  66. package/lib/language/language.g4 +355 -156
  67. package/lib/language/multiLineStringParser.js +5 -5
  68. package/lib/main.d.ts +486 -59
  69. package/lib/main.js +41 -9
  70. package/lib/model/api.js +3 -1
  71. package/lib/model/csnRefs.js +252 -156
  72. package/lib/model/csnUtils.js +384 -297
  73. package/lib/model/enrichCsn.js +71 -29
  74. package/lib/model/revealInternalProperties.js +29 -8
  75. package/lib/model/sortViews.js +2 -1
  76. package/lib/modelCompare/compare.js +23 -18
  77. package/lib/optionProcessor.js +63 -26
  78. package/lib/render/manageConstraints.js +35 -32
  79. package/lib/render/toCdl.js +897 -947
  80. package/lib/render/toHdbcds.js +205 -257
  81. package/lib/render/toSql.js +264 -225
  82. package/lib/render/utils/common.js +136 -25
  83. package/lib/render/utils/sql.js +4 -3
  84. package/lib/render/utils/stringEscapes.js +111 -0
  85. package/lib/sql-identifier.js +1 -1
  86. package/lib/transform/.eslintrc.json +5 -0
  87. package/lib/transform/db/.eslintrc.json +3 -1
  88. package/lib/transform/db/applyTransformations.js +35 -12
  89. package/lib/transform/db/assertUnique.js +1 -1
  90. package/lib/transform/db/associations.js +104 -306
  91. package/lib/transform/db/cdsPersistence.js +2 -2
  92. package/lib/transform/db/constraints.js +58 -53
  93. package/lib/transform/db/expansion.js +60 -33
  94. package/lib/transform/db/flattening.js +582 -104
  95. package/lib/transform/db/groupByOrderBy.js +3 -1
  96. package/lib/transform/db/transformExists.js +66 -13
  97. package/lib/transform/db/views.js +11 -7
  98. package/lib/transform/draft/.eslintrc.json +38 -0
  99. package/lib/transform/{db/draft.js → draft/db.js} +6 -5
  100. package/lib/transform/draft/odata.js +227 -0
  101. package/lib/transform/forHanaNew.js +109 -208
  102. package/lib/transform/forOdataNew.js +59 -212
  103. package/lib/transform/localized.js +46 -26
  104. package/lib/transform/odata/toFinalBaseType.js +85 -11
  105. package/lib/transform/odata/typesExposure.js +147 -199
  106. package/lib/transform/odata/utils.js +2 -2
  107. package/lib/transform/transformUtilsNew.js +44 -33
  108. package/lib/transform/translateAssocsToJoins.js +3 -20
  109. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  110. package/lib/transform/universalCsn/coreComputed.js +172 -0
  111. package/lib/transform/universalCsn/universalCsnEnricher.js +737 -0
  112. package/lib/transform/universalCsn/utils.js +63 -0
  113. package/lib/utils/moduleResolve.js +13 -6
  114. package/lib/utils/objectUtils.js +30 -0
  115. package/package.json +1 -1
  116. package/share/messages/README.md +26 -0
  117. package/share/messages/message-explanations.json +2 -1
  118. package/share/messages/syntax-expected-integer.md +37 -0
  119. package/lib/compiler/definer.js +0 -2361
  120. package/lib/compiler/resolver.js +0 -3079
  121. package/lib/transform/odata/attachPath.js +0 -96
  122. package/lib/transform/odata/expandStructKeysInAssociations.js +0 -59
  123. package/lib/transform/odata/generateForeignKeyElements.js +0 -261
  124. package/lib/transform/odata/referenceFlattener.js +0 -290
  125. package/lib/transform/odata/sortByAssociationDependency.js +0 -105
  126. package/lib/transform/odata/structuralPath.js +0 -72
  127. package/lib/transform/odata/structureFlattener.js +0 -171
  128. package/lib/transform/universalCsnEnricher.js +0 -237
@@ -7,10 +7,11 @@
7
7
  const { term } = require('../utils/term');
8
8
  const { locationString } = require('./location');
9
9
  const { isDeprecatedEnabled } = require('./model');
10
- const { centralMessages, centralMessageTexts } = require('./message-registry');
10
+ const { centralMessages, centralMessageTexts, oldMessageIds } = require('./message-registry');
11
11
  const { copyPropIfExist } = require('../utils/objectUtils');
12
12
  const _messageIdsWithExplanation = require('../../share/messages/message-explanations.json').messages;
13
13
  const { analyseCsnPath, traverseQuery } = require('../model/csnRefs');
14
+ const { CompilerAssertion } = require("./error");
14
15
 
15
16
  const fs = require('fs');
16
17
  const path = require('path');
@@ -24,7 +25,8 @@ let test$severities = null;
24
25
  let test$texts = null;
25
26
 
26
27
  /**
27
- * Returns true if at least one of the given messages is of severity "Error"
28
+ * Returns true if at least one of the given messages is of severity "Error".
29
+ *
28
30
  * @param {CSN.Message[]} messages
29
31
  * @returns {boolean}
30
32
  */
@@ -34,7 +36,8 @@ function hasErrors( messages ) {
34
36
 
35
37
  /**
36
38
  * Returns true if at least one of the given messages is of severity "Error"
37
- * and *cannot* be reclassified to a warning.
39
+ * and *cannot* be reclassified to a warning for the given module.
40
+ * Won't detect already downgraded messages.
38
41
  *
39
42
  * @param {CSN.Message[]} messages
40
43
  * @param {string} moduleName
@@ -122,9 +125,10 @@ class CompileMessage {
122
125
  * Creates an instance of CompileMessage.
123
126
  * @param {any} location Location of the message
124
127
  * @param {string} msg The message text
125
- * @param {CSN.MessageSeverity} [severity='Error'] Severity: Debug, Info, Warning, Error
128
+ * @param {MessageSeverity} [severity='Error'] Severity: Debug, Info, Warning, Error
126
129
  * @param {string} [id] The ID of the message - visible as property messageId
127
130
  * @param {any} [home]
131
+ * @param {string} [moduleName] Name of the module that created this message
128
132
  *
129
133
  * @memberOf CompileMessage
130
134
  */
@@ -140,7 +144,7 @@ class CompileMessage {
140
144
  Object.defineProperty( this, 'messageId', { value: id } );
141
145
  // this.messageId = id; // ids not yet finalized
142
146
  if (moduleName)
143
- Object.defineProperty( this, '$module', { value: moduleName } );
147
+ Object.defineProperty( this, '$module', { value: moduleName, configurable: true } );
144
148
  }
145
149
 
146
150
  toString() { // should have no argument...
@@ -175,22 +179,6 @@ function dollarLocation( location ) {
175
179
  return loc;
176
180
  }
177
181
 
178
- /**
179
- * Handle compiler messages, i.e. throw a compiler exception if there are errors.
180
- *
181
- * @param {object} model CSN or XSN
182
- * @param {CSN.Options} [options]
183
- * @deprecated Use throwWithError() from makeMessageFunction instead.
184
- */
185
- function handleMessages( model, options = {} ) {
186
- const messages = options.messages;
187
- if (messages && messages.length) {
188
- if (hasErrors( messages ))
189
- throw new CompilationError( messages, options.attachValidNames && model );
190
- }
191
- return model;
192
- }
193
-
194
182
  const severitySpecs = {
195
183
  error: { name: 'Error', level: 0 },
196
184
  warning: { name: 'Warning', level: 1 },
@@ -199,7 +187,7 @@ const severitySpecs = {
199
187
  };
200
188
 
201
189
  /**
202
- * Reclassify the given message's severity using:
190
+ * Get the reclassified severity of the given message using:
203
191
  *
204
192
  * 1. The specified severity: either centrally provided or via the input severity
205
193
  * - when generally specified as 'Error', immediately return 'Error'
@@ -210,17 +198,14 @@ const severitySpecs = {
210
198
  * been returned according to 1, return the severity according to the user wishes.
211
199
  * 3. Otherwise, use the specified severity.
212
200
  *
213
- * @param {string} id
214
- * @param {CSN.MessageSeverity} severity
215
- * @param {object} severities
201
+ * @param {object} msg The CompileMessage.
202
+ * @param {CSN.Options} options
216
203
  * @param {string} moduleName
217
- * @returns {CSN.MessageSeverity}
218
- *
219
- * TODO: we should pass options as usual
220
- * TODO: should be part of the returned function
204
+ * @param {boolean} deprecatedDowngradable
205
+ * @returns {MessageSeverity}
221
206
  */
222
- function reclassifiedSeverity( id, severity, severities, moduleName, deprecatedDowngradable ) {
223
- const spec = centralMessages[id] || { severity };
207
+ function reclassifiedSeverity(msg, options, moduleName, deprecatedDowngradable ) {
208
+ const spec = centralMessages[msg.messageId] || { severity: msg.severity, configurableFor: null, errorFor: null };
224
209
  if (spec.severity === 'Error') {
225
210
  const { configurableFor } = spec;
226
211
  if (!(Array.isArray( configurableFor )
@@ -233,7 +218,17 @@ function reclassifiedSeverity( id, severity, severities, moduleName, deprecatedD
233
218
  if (Array.isArray( errorFor ) && errorFor.includes( moduleName ))
234
219
  return 'Error';
235
220
  }
236
- return normalizedSeverity( severities[id] ) || spec.severity;
221
+
222
+ if (!options.severities)
223
+ return spec.severity;
224
+
225
+ let newSeverity = options.severities[msg.messageId];
226
+ // The user could have specified a severity through an old message ID.
227
+ if (!newSeverity && spec.oldNames) {
228
+ const oldName = spec.oldNames.find((name => options.severities[name]))
229
+ newSeverity = options.severities[oldName];
230
+ }
231
+ return normalizedSeverity( newSeverity ) || spec.severity;
237
232
  }
238
233
 
239
234
  function normalizedSeverity( severity ) {
@@ -243,24 +238,6 @@ function normalizedSeverity( severity ) {
243
238
  return s ? s.name : 'Error';
244
239
  }
245
240
 
246
- /**
247
- * Reclassifies all messages according to the current module.
248
- * This is required because if throwWithError() throws and the message's
249
- * severities has `errorFor` set, then the message may still appear to be a warning.
250
- *
251
- * TODO: this actually likely needs to be called by the backend module at the beginning!
252
- *
253
- * @param {CSN.Message[]} messages
254
- * @param {object} severities
255
- * @param {string} moduleName
256
- */
257
- function reclassifyMessagesForModule(messages, severities, moduleName, deprecatedDowngradable) {
258
- for (const msg of messages) {
259
- if (msg.messageId && msg.severity !== 'Error')
260
- msg.severity = reclassifiedSeverity(msg.messageId, msg.severity, severities, moduleName, deprecatedDowngradable);
261
- }
262
- }
263
-
264
241
  /**
265
242
  * Compare two severities. Returns 0 if they are the same, and <0 if
266
243
  * `a` has a lower `level` than `b` according to {@link severitySpecs},
@@ -268,8 +245,8 @@ function reclassifyMessagesForModule(messages, severities, moduleName, deprecate
268
245
  *
269
246
  * compareSeverities('Error', 'Info') => Error < Info => -1
270
247
  *
271
- * @param {CSN.MessageSeverity} a
272
- * @param {CSN.MessageSeverity} b
248
+ * @param {MessageSeverity} a
249
+ * @param {MessageSeverity} b
273
250
  * @see severitySpecs
274
251
  */
275
252
  function compareSeverities( a, b ) {
@@ -282,16 +259,16 @@ function compareSeverities( a, b ) {
282
259
  /**
283
260
  * @todo This was copied from somewhere just to make CSN paths work.
284
261
  * @param {CSN.Model} model
285
- * @param {CSN.Path} path
262
+ * @param {CSN.Path} csnPath
286
263
  */
287
- function searchForLocation( model, path ) {
264
+ function searchForLocation( model, csnPath ) {
288
265
  if (!model)
289
266
  return null;
290
267
  // Don't display a location if we cannot find one!
291
268
  let lastLocation = null;
292
269
  /** @type {object} */
293
270
  let currentStep = model;
294
- for (const step of path) {
271
+ for (const step of csnPath) {
295
272
  if (!currentStep)
296
273
  return lastLocation;
297
274
  currentStep = currentStep[step];
@@ -304,10 +281,9 @@ function searchForLocation( model, path ) {
304
281
 
305
282
  /**
306
283
  * Create the `message` functions to emit messages.
307
- * See internalDoc/ReportingMessages.md for detail
308
284
  *
309
285
  * @example
310
- * ```
286
+ * ```js
311
287
  * const { createMessageFunctions } = require(‘../base/messages’);
312
288
  * function module( …, options ) {
313
289
  * const { message, info, throwWithError } = createMessageFunctions( options, moduleName );
@@ -323,14 +299,14 @@ function searchForLocation( model, path ) {
323
299
  * @param {object} [model=null] the CSN or XSN model, used for convenience
324
300
  */
325
301
  function createMessageFunctions( options, moduleName, model = null ) {
326
- return makeMessageFunction( model, options, moduleName, true );
302
+ return makeMessageFunction( model, options, moduleName );
327
303
  }
328
304
 
329
305
  /**
330
306
  * Create the `message` function to emit messages.
331
307
  *
332
308
  * @example
333
- * ```
309
+ * ```js
334
310
  * const { makeMessageFunction } = require(‘../base/messages’);
335
311
  * function module( …, options ) {
336
312
  * const { message, info, throwWithError } = makeMessageFunction( model, options, moduleName );
@@ -344,15 +320,13 @@ function createMessageFunctions( options, moduleName, model = null ) {
344
320
  * @param {object} model
345
321
  * @param {CSN.Options} [options]
346
322
  * @param {string} [moduleName]
347
- * @param {boolean} [throwOnlyWithNew=false] behave like createMessageFunctions
348
323
  */
349
- function makeMessageFunction( model, options, moduleName = null, throwOnlyWithNew = false ) {
324
+ function makeMessageFunction( model, options, moduleName = null ) {
350
325
  // ensure message consistency during runtime with --test-mode
351
326
  if (options.testMode)
352
327
  _check$Init( options );
353
328
 
354
329
  const hasMessageArray = !!options.messages;
355
- const severities = options.severities || {};
356
330
  const deprecatedDowngradable = isDeprecatedEnabled( options, 'downgradableErrors' );
357
331
  /**
358
332
  * Array of collected compiler messages. Only use it for debugging. Will not
@@ -361,10 +335,17 @@ function makeMessageFunction( model, options, moduleName = null, throwOnlyWithNe
361
335
  * @type {CSN.Message[]}
362
336
  */
363
337
  let messages = options.messages || [];
338
+ /**
339
+ * Whether an error was emitted in the module. Also includes reclassified errors.
340
+ * @type {boolean}
341
+ */
364
342
  let hasNewError = false;
343
+
344
+ reclassifyMessagesForModule();
345
+
365
346
  return {
366
347
  message, error, warning, info, debug, messages,
367
- throwWithError: (throwOnlyWithNew ? throwWithError : throwWithAnyError),
348
+ throwWithError, throwWithAnyError,
368
349
  callTransparently, moduleName,
369
350
  };
370
351
 
@@ -376,11 +357,6 @@ function makeMessageFunction( model, options, moduleName = null, throwOnlyWithNe
376
357
  texts = { std: textOrArguments };
377
358
  textOrArguments = {};
378
359
  }
379
- if (id) {
380
- if (options.testMode && !options.$recompile)
381
- _check$Consistency( id, moduleName, severity, texts, options )
382
- severity = reclassifiedSeverity( id, severity, severities, moduleName, deprecatedDowngradable );
383
- }
384
360
 
385
361
  const [ fileLocation, semanticLocation, definition ] = _normalizeMessageLocation(location);
386
362
  const text = messageText( texts || centralMessageTexts[id], textOrArguments );
@@ -392,6 +368,12 @@ function makeMessageFunction( model, options, moduleName = null, throwOnlyWithNe
392
368
  if (definition)
393
369
  msg.$location.address = { definition };
394
370
 
371
+ if (id) {
372
+ if (options.testMode && !options.$recompile)
373
+ _check$Consistency( id, moduleName, severity, texts, options )
374
+ msg.severity = reclassifiedSeverity(msg, options, moduleName, deprecatedDowngradable );
375
+ }
376
+
395
377
  messages.push( msg );
396
378
  hasNewError = hasNewError || msg.severity === 'Error' &&
397
379
  !(options.testMode && msg.messageId && isDowngradable( msg.messageId, moduleName ));
@@ -421,7 +403,7 @@ function makeMessageFunction( model, options, moduleName = null, throwOnlyWithNe
421
403
 
422
404
  if (isShortSignature) {
423
405
  if (texts)
424
- throw new Error('No "texts" argument expected because text was already provided as third argument.');
406
+ throw new CompilerAssertion('No "texts" argument expected because text was already provided as third argument.');
425
407
  } else {
426
408
  if (textArguments !== undefined && typeof textArguments !== 'object')
427
409
  _expectedType('textArguments', textArguments, 'object')
@@ -430,7 +412,7 @@ function makeMessageFunction( model, options, moduleName = null, throwOnlyWithNe
430
412
  }
431
413
 
432
414
  function _expectedType(field, value, type) {
433
- throw new Error(`Invalid argument type for ${ field }! Expected ${ type } but got ${ typeof value }. Do you use the old function signature?`);
415
+ throw new CompilerAssertion(`Invalid argument type for ${ field }! Expected ${ type } but got ${ typeof value }. Do you use the old function signature?`);
434
416
  }
435
417
  }
436
418
 
@@ -485,9 +467,9 @@ function makeMessageFunction( model, options, moduleName = null, throwOnlyWithNe
485
467
  */
486
468
  function message(id, location, textArguments = null, texts = null) {
487
469
  if (!id)
488
- throw new Error('A message id is missing!');
470
+ throw new CompilerAssertion('A message id is missing!');
489
471
  if (!centralMessages[id])
490
- throw new Error(`Message id '${ id }' is missing an entry in the central message register!`);
472
+ throw new CompilerAssertion(`Message id '${ id }' is missing an entry in the central message register!`);
491
473
  return _message(id, location, textArguments, null, texts);
492
474
  }
493
475
 
@@ -539,12 +521,31 @@ function makeMessageFunction( model, options, moduleName = null, throwOnlyWithNe
539
521
  function throwWithAnyError() {
540
522
  if (!messages || !messages.length)
541
523
  return;
542
- reclassifyMessagesForModule( messages, severities, moduleName ); // TODO: no, at the beginning of the module
543
524
  const hasError = options.testMode ? hasNonDowngradableErrors : hasErrors;
544
525
  if (hasError( messages, moduleName ))
545
526
  throw new CompilationError( messages, options.attachValidNames && model );
546
527
  }
547
528
 
529
+ /**
530
+ * Reclassifies all messages according to the current module.
531
+ * This is required because if throwWithError() throws and the message's
532
+ * severities has `errorFor` set, then the message may still appear to be a warning.
533
+ */
534
+ function reclassifyMessagesForModule() {
535
+ for (const msg of messages) {
536
+ if (msg.messageId && msg.severity !== 'Error') {
537
+ const severity = reclassifiedSeverity(msg, options, moduleName, deprecatedDowngradable);
538
+ if (severity !== msg.severity) {
539
+ msg.severity = severity;
540
+ // Re-set the module regardless of severity, since we reclassified it.
541
+ Object.defineProperty( msg, '$module', { value: moduleName, configurable: true } );
542
+ hasNewError = hasNewError || severity === 'Error' &&
543
+ !(options.testMode && msg.messageId && isDowngradable( msg.messageId, moduleName ));
544
+ }
545
+ }
546
+ }
547
+ }
548
+
548
549
  /**
549
550
  * Collects all messages during the call of the callback function instead of
550
551
  * storing them in the model. Returns the collected messages.
@@ -580,7 +581,7 @@ function _check$Init( options ) {
580
581
 
581
582
  function _check$Consistency( id, moduleName, severity, texts, options ) {
582
583
  if (id.length > 30 && !centralMessages[id])
583
- throw new Error( `The message ID "${id}" has more than 30 chars and must be listed centrally` );
584
+ throw new CompilerAssertion( `The message ID "${id}" has more than 30 chars and must be listed centrally` );
584
585
  if (!options.severities)
585
586
  _check$Severities( id, moduleName || '?', severity );
586
587
  for (const [variant, text] of
@@ -597,20 +598,19 @@ function _check$Severities( id, moduleName, severity ) {
597
598
  if (!expected)
598
599
  test$severities[id] = severity;
599
600
  else if (expected !== severity)
600
- throw new Error( `Expecting severity "${expected}" from previous call, not "${severity}" for message ID "${id}"` );
601
+ throw new CompilerAssertion( `Expecting severity "${expected}" from previous call, not "${severity}" for message ID "${id}"` );
601
602
  return;
602
603
  }
603
604
  // now try whether the message could be something less than an Error in the module due to user wishes
604
- const user = reclassifiedSeverity( id, null, { [id]: 'Info' }, moduleName, false );
605
- if (user === 'Error') { // always an error in module
605
+ if (!isDowngradable( id, moduleName )) { // always an error in module
606
606
  if (severity !== 'Error')
607
- throw new Error( `Expecting severity "Error", not "${severity}" for message ID "${id}" in module "${moduleName}"` );
607
+ throw new CompilerAssertion( `Expecting severity "Error", not "${severity}" for message ID "${id}" in module "${moduleName}"` );
608
608
  }
609
609
  else if (spec.severity === 'Error') {
610
- throw new Error( `Expecting the use of function message() when message ID "${id}" is a configurable error in module "${moduleName}"` );
610
+ throw new CompilerAssertion( `Expecting the use of function message() when message ID "${id}" is a configurable error in module "${moduleName}"` );
611
611
  }
612
612
  else if (spec.severity !== severity) {
613
- throw new Error( `Expecting severity "${spec.severity}", not "${severity}" for message ID "${id}" in module "${moduleName}"` );
613
+ throw new CompilerAssertion( `Expecting severity "${spec.severity}", not "${severity}" for message ID "${id}" in module "${moduleName}"` );
614
614
  }
615
615
  }
616
616
 
@@ -621,7 +621,7 @@ function _check$Texts( id, prop, value ) {
621
621
  if (!expected)
622
622
  test$texts[id][prop] = value;
623
623
  else if (expected !== value)
624
- throw new Error( `Expecting text "${expected}", not "${value}" for message ID "${id}" and text variant "${prop}"`);
624
+ throw new CompilerAssertion( `Expecting text "${expected}", not "${value}" for message ID "${id}" and text variant "${prop}"`);
625
625
  }
626
626
 
627
627
  const quote = { // could be an option in the future
@@ -664,6 +664,7 @@ const paramsTransform = {
664
664
  expecting: transformManyWith( tokenSymbol ),
665
665
  // msg: m => m,
666
666
  $reviewed: ignoreTextTransform,
667
+ version: quote.meta,
667
668
  };
668
669
 
669
670
  function ignoreTextTransform() {
@@ -828,7 +829,7 @@ function messageString( err, normalizeFilename, noMessageId, noHome ) {
828
829
  return (err.$location && err.$location.file
829
830
  ? locationString( err.$location, normalizeFilename ) + ': '
830
831
  : '') +
831
- (err.severity||'Error') +
832
+ (err.severity || 'Error') +
832
833
  // TODO: use [message-id]
833
834
  (err.messageId && !noMessageId ? ' ' + err.messageId + ': ' : ': ') +
834
835
  err.message +
@@ -1101,13 +1102,15 @@ function artName( art, omit ) {
1101
1102
  r.push( (art.kind === 'extend' ? 'block:' : 'query:') + name.select ); // TODO: rename to 'select:1' and consider whether there are more selects
1102
1103
  if (name.action && omit !== 'action')
1103
1104
  r.push( memberActionName(art) + ':' + quoted( name.action ) );
1104
- if (name.alias)
1105
+ if (name.alias && art.kind !== '$self')
1105
1106
  r.push( (art.kind === 'mixin' ? 'mixin:' : 'alias:') + quoted( name.alias ) )
1106
1107
  if (name.param != null && omit !== 'param')
1107
1108
  r.push( name.param ? 'param:' + quoted( name.param ) : 'returns' ); // TODO: join
1108
1109
  if (name.element && omit !== 'element')
1109
1110
  // r.push( `${ art.kind }: ${ quoted( name.element )}` ); or even better element:"assoc"/key:"i" same with enum
1110
1111
  r.push( (art.kind === 'enum' ? 'enum:' : 'element:') + quoted( name.element ) );
1112
+ if (art.kind === '$self')
1113
+ r.push( 'alias:' + quoted( name.alias ) ) // should be late due to $self in anonymous aspect
1111
1114
  return r.join('/');
1112
1115
  }
1113
1116
 
@@ -1120,6 +1123,7 @@ function memberActionName( art ) {
1120
1123
  return 'action';
1121
1124
  }
1122
1125
 
1126
+ // TODO: XSN-specific things should probably move out
1123
1127
  function homeName( art, absoluteOnly ) {
1124
1128
  if (!art)
1125
1129
  return art;
@@ -1135,8 +1139,10 @@ function homeName( art, absoluteOnly ) {
1135
1139
  return homeName( art.name._artifact, absoluteOnly ); // use corresponding definition
1136
1140
  else if (absoluteOnly)
1137
1141
  return art.name.absolute;
1138
- else
1139
- return (art._main ? art._main.kind : art.kind) + ':' + artName( art );
1142
+ let main = art._main || art;
1143
+ while (main._outer) // anonymous aspect
1144
+ main = main._outer._main;
1145
+ return main.kind + ':' + artName( art );
1140
1146
  }
1141
1147
 
1142
1148
  // The "home" for extensions is handled differently because `_artifact` is not
@@ -1190,9 +1196,9 @@ function constructSemanticLocationFromCsnPath(csnPath, model) {
1190
1196
 
1191
1197
  // remove definitions
1192
1198
  csnPath.shift();
1193
- const artName = csnPath.shift();
1194
- let currentThing = model.definitions[artName];
1195
- let result = `${ (currentThing && currentThing.kind) ? currentThing.kind : 'artifact' }:${ _quoted(artName) }`;
1199
+ const artifactName = csnPath.shift();
1200
+ let currentThing = model.definitions[artifactName];
1201
+ let result = `${ (currentThing && currentThing.kind) ? currentThing.kind : 'artifact' }:${ _quoted(artifactName) }`;
1196
1202
 
1197
1203
  if (!currentThing)
1198
1204
  return result;
@@ -1405,6 +1411,7 @@ function _quoted( name ) {
1405
1411
 
1406
1412
  /**
1407
1413
  * Get the explanation string for the given message-id.
1414
+ * Ensure to have called hasMessageExplanation() before.
1408
1415
  *
1409
1416
  * @param {string} messageId
1410
1417
  * @returns {string}
@@ -1412,18 +1419,22 @@ function _quoted( name ) {
1412
1419
  * @see hasMessageExplanation()
1413
1420
  */
1414
1421
  function explainMessage(messageId) {
1422
+ messageId = oldMessageIds[messageId] || messageId;
1415
1423
  const filename = path.join(__dirname, '..', '..', 'share', 'messages', `${messageId}.md`);
1416
1424
  return fs.readFileSync(filename, 'utf8');
1417
1425
  }
1418
1426
 
1419
1427
  /**
1420
1428
  * Returns true if the given message has an explanation file.
1429
+ * Takes into account changed message ids, i.e. looks up if the new
1430
+ * message id has an explanation.
1421
1431
  *
1422
1432
  * @param {string} messageId
1423
1433
  * @returns {boolean}
1424
1434
  */
1425
1435
  function hasMessageExplanation(messageId) {
1426
- return messageId && _messageIdsWithExplanation.includes(messageId);
1436
+ const id = oldMessageIds[messageId] || messageId || false;
1437
+ return id && _messageIdsWithExplanation.includes(id);
1427
1438
  }
1428
1439
 
1429
1440
  /**
@@ -1444,12 +1455,12 @@ module.exports = {
1444
1455
  createMessageFunctions,
1445
1456
  makeMessageFunction,
1446
1457
  artName,
1447
- handleMessages,
1448
1458
  sortMessages: (m => m.sort(compareMessage)),
1449
1459
  sortMessagesSeverityAware: (m => m.sort(compareMessageSeverityAware)),
1450
1460
  deduplicateMessages,
1451
1461
  CompileMessage,
1452
1462
  CompilationError,
1463
+ isMessageDowngradable: isDowngradable,
1453
1464
  explainMessage,
1454
1465
  hasMessageExplanation,
1455
1466
  messageIdsWithExplanation,
package/lib/base/model.js CHANGED
@@ -27,7 +27,6 @@ const availableBetaFlags = {
27
27
  ignoreAssocPublishingInUnion: true,
28
28
  nestedProjections: true,
29
29
  enableUniversalCsn: true,
30
- sqlSnippets: true,
31
30
  // disabled by --beta-mode
32
31
  nestedServices: false,
33
32
  };
@@ -64,7 +63,7 @@ function isBetaEnabled( options, feature ) {
64
63
  */
65
64
  function isDeprecatedEnabled( options, feature = null ) {
66
65
  const { deprecated } = options;
67
- if(!feature)
66
+ if (!feature)
68
67
  return !!deprecated;
69
68
  return deprecated && typeof deprecated === 'object' && deprecated[feature];
70
69
  }
@@ -94,63 +93,6 @@ function forEachMember( construct, callback, target ) {
94
93
 
95
94
  }
96
95
 
97
- // Apply function `callback(member, memberName, prop)` to each member in
98
- // `construct`, recursively (i.e. also for sub-elements of elements).
99
- function forEachMemberRecursively( construct, callback ) {
100
- forEachMember( construct, ( member, memberName, prop ) => {
101
- callback( member, memberName, prop );
102
- // Descend into nested members, too
103
- forEachMemberRecursively( member, callback );
104
- });
105
- // If 'construct' has more than one query, descend into the elements of the remaining ones, too
106
- if (construct.$queries && construct.$queries.length > 1) {
107
- construct.$queries.slice(1).forEach(query => forEachMemberRecursively(query, callback));
108
- }
109
- }
110
-
111
- /**
112
- * Apply function `callback` to all members of object `obj` (main artifact or
113
- * parent member). Members are considered those in dictionaries `elements`,
114
- * `enum`, `actions` and `params` of `obj`, `elements` and `enums` are also
115
- * searched inside property `items` (array of). `$queries`, `mixin` and
116
- * `columns` are also visited in contrast to `forEachMember()`.
117
- * See function `forEachGeneric()` for details.
118
- *
119
- * @param {XSN.Artifact} construct
120
- * @param {(member: object, memberName: string, prop: string) => any} callback
121
- * @param {object} [target]
122
- */
123
- function forEachMemberWithQuery( construct, callback, target ) {
124
- let obj = construct.returns || construct; // why the extra `returns` for actions?
125
- obj = obj.items || obj;
126
- forEachGeneric( target || obj, 'elements', callback );
127
- forEachGeneric( obj, 'enum', callback );
128
- forEachGeneric( obj, 'foreignKeys', callback );
129
- forEachGeneric( construct, 'actions', callback );
130
- forEachGeneric( construct, 'params', callback );
131
- // For Queries
132
- forEachGeneric( construct, '$queries', callback );
133
- forEachGeneric( construct, 'mixin', callback );
134
- forEachGeneric( construct, 'columns', callback );
135
- }
136
-
137
- /**
138
- * Apply function `callback(member, memberName, prop)` to each member in
139
- * `construct`, recursively (i.e. also for sub-elements of elements).
140
- * In contrast to `forEachMemberRecursively()` this function also traverses
141
- * queries and mixins.
142
- *
143
- * @param {XSN.Artifact} construct
144
- * @param {(member: object, memberName: string, prop: string) => any} callback
145
- */
146
- function forEachMemberRecursivelyWithQuery( construct, callback ) {
147
- forEachMemberWithQuery( construct, ( member, memberName, prop ) => {
148
- callback( member, memberName, prop );
149
- // Descend into nested members, too
150
- forEachMemberRecursivelyWithQuery( member, callback );
151
- });
152
- }
153
-
154
96
  // Apply function `callback` to all objects in dictionary `dict`, including all
155
97
  // duplicates (found under the same name). Function `callback` is called with
156
98
  // the following arguments: the object, the name, and -if it is a duplicate-
@@ -158,7 +100,7 @@ function forEachMemberRecursivelyWithQuery( construct, callback ) {
158
100
  function forEachGeneric( obj, prop, callback ) {
159
101
  let dict = obj[prop];
160
102
  for (let name in dict) {
161
- let obj = dict[name];
103
+ obj = dict[name];
162
104
  callback( obj, name, prop );
163
105
  if (Array.isArray(obj.$duplicates)) // redefinitions
164
106
  obj.$duplicates.forEach( o => callback( o, name, prop ) )
@@ -190,9 +132,6 @@ module.exports = {
190
132
  queryOps,
191
133
  forEachDefinition,
192
134
  forEachMember,
193
- forEachMemberRecursively,
194
- forEachMemberWithQuery,
195
- forEachMemberRecursivelyWithQuery,
196
135
  forEachGeneric,
197
136
  forEachInOrder,
198
137
  setProp,