@sap/cds-compiler 2.11.2 → 2.13.6

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 (140) hide show
  1. package/CHANGELOG.md +175 -2
  2. package/bin/.eslintrc.json +1 -2
  3. package/bin/cds_update_identifiers.js +10 -8
  4. package/bin/cdsc.js +23 -17
  5. package/bin/cdsse.js +2 -2
  6. package/bin/cdsv2m.js +3 -2
  7. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  8. package/doc/CHANGELOG_BETA.md +25 -6
  9. package/doc/CHANGELOG_DEPRECATED.md +22 -6
  10. package/doc/NameResolution.md +21 -16
  11. package/lib/api/main.js +32 -79
  12. package/lib/api/options.js +3 -2
  13. package/lib/api/validate.js +2 -1
  14. package/lib/backends.js +16 -26
  15. package/lib/base/dictionaries.js +0 -8
  16. package/lib/base/error.js +26 -0
  17. package/lib/base/keywords.js +10 -19
  18. package/lib/base/location.js +9 -4
  19. package/lib/base/message-registry.js +75 -9
  20. package/lib/base/messages.js +31 -35
  21. package/lib/base/model.js +2 -62
  22. package/lib/base/optionProcessorHelper.js +246 -183
  23. package/lib/checks/.eslintrc.json +2 -0
  24. package/lib/checks/actionsFunctions.js +2 -1
  25. package/lib/checks/annotationsOData.js +1 -1
  26. package/lib/checks/cdsPersistence.js +2 -1
  27. package/lib/checks/emptyOrOnlyVirtual.js +2 -2
  28. package/lib/checks/enricher.js +17 -1
  29. package/lib/checks/foreignKeys.js +4 -4
  30. package/lib/checks/invalidTarget.js +3 -1
  31. package/lib/checks/managedInType.js +4 -4
  32. package/lib/checks/managedWithoutKeys.js +3 -1
  33. package/lib/checks/queryNoDbArtifacts.js +1 -3
  34. package/lib/checks/selectItems.js +4 -4
  35. package/lib/checks/sql-snippets.js +94 -0
  36. package/lib/checks/types.js +1 -1
  37. package/lib/checks/unknownMagic.js +1 -1
  38. package/lib/checks/validator.js +12 -7
  39. package/lib/compiler/assert-consistency.js +12 -8
  40. package/lib/compiler/base.js +0 -1
  41. package/lib/compiler/builtins.js +42 -21
  42. package/lib/compiler/checks.js +46 -12
  43. package/lib/compiler/cycle-detector.js +1 -1
  44. package/lib/compiler/define.js +1103 -0
  45. package/lib/compiler/extend.js +983 -0
  46. package/lib/compiler/finalize-parse-cdl.js +231 -0
  47. package/lib/compiler/index.js +46 -39
  48. package/lib/compiler/kick-start.js +190 -0
  49. package/lib/compiler/moduleLayers.js +4 -4
  50. package/lib/compiler/populate.js +1226 -0
  51. package/lib/compiler/propagator.js +113 -47
  52. package/lib/compiler/resolve.js +1433 -0
  53. package/lib/compiler/shared.js +100 -65
  54. package/lib/compiler/tweak-assocs.js +529 -0
  55. package/lib/compiler/utils.js +215 -33
  56. package/lib/edm/.eslintrc.json +5 -0
  57. package/lib/edm/annotations/genericTranslation.js +38 -25
  58. package/lib/edm/annotations/preprocessAnnotations.js +3 -3
  59. package/lib/edm/csn2edm.js +10 -9
  60. package/lib/edm/edm.js +19 -20
  61. package/lib/edm/edmPreprocessor.js +166 -95
  62. package/lib/edm/edmUtils.js +127 -34
  63. package/lib/gen/Dictionary.json +92 -43
  64. package/lib/gen/language.checksum +1 -1
  65. package/lib/gen/language.interp +11 -1
  66. package/lib/gen/language.tokens +86 -82
  67. package/lib/gen/languageLexer.interp +18 -1
  68. package/lib/gen/languageLexer.js +925 -847
  69. package/lib/gen/languageLexer.tokens +78 -74
  70. package/lib/gen/languageParser.js +5434 -4298
  71. package/lib/json/from-csn.js +59 -17
  72. package/lib/json/to-csn.js +189 -71
  73. package/lib/language/antlrParser.js +3 -3
  74. package/lib/language/docCommentParser.js +3 -3
  75. package/lib/language/errorStrategy.js +26 -8
  76. package/lib/language/genericAntlrParser.js +144 -53
  77. package/lib/language/language.g4 +424 -200
  78. package/lib/language/multiLineStringParser.js +536 -0
  79. package/lib/main.d.ts +550 -61
  80. package/lib/main.js +38 -11
  81. package/lib/model/api.js +3 -1
  82. package/lib/model/csnRefs.js +322 -198
  83. package/lib/model/csnUtils.js +226 -370
  84. package/lib/model/enrichCsn.js +124 -69
  85. package/lib/model/revealInternalProperties.js +29 -7
  86. package/lib/model/sortViews.js +10 -2
  87. package/lib/modelCompare/compare.js +17 -12
  88. package/lib/optionProcessor.js +8 -3
  89. package/lib/render/.eslintrc.json +1 -2
  90. package/lib/render/DuplicateChecker.js +1 -1
  91. package/lib/render/manageConstraints.js +36 -33
  92. package/lib/render/toCdl.js +174 -275
  93. package/lib/render/toHdbcds.js +203 -122
  94. package/lib/render/toRename.js +7 -10
  95. package/lib/render/toSql.js +161 -82
  96. package/lib/render/utils/common.js +22 -8
  97. package/lib/render/utils/sql.js +10 -7
  98. package/lib/render/utils/stringEscapes.js +111 -0
  99. package/lib/sql-identifier.js +1 -1
  100. package/lib/transform/.eslintrc.json +5 -0
  101. package/lib/transform/braceExpression.js +4 -2
  102. package/lib/transform/db/.eslintrc.json +2 -0
  103. package/lib/transform/db/applyTransformations.js +212 -0
  104. package/lib/transform/db/assertUnique.js +1 -1
  105. package/lib/transform/db/associations.js +187 -0
  106. package/lib/transform/db/cdsPersistence.js +150 -0
  107. package/lib/transform/db/constraints.js +61 -56
  108. package/lib/transform/db/expansion.js +50 -29
  109. package/lib/transform/db/flattening.js +556 -106
  110. package/lib/transform/db/groupByOrderBy.js +3 -1
  111. package/lib/transform/db/temporal.js +236 -0
  112. package/lib/transform/db/transformExists.js +103 -28
  113. package/lib/transform/db/views.js +92 -44
  114. package/lib/transform/draft/.eslintrc.json +38 -0
  115. package/lib/transform/{db/draft.js → draft/db.js} +9 -7
  116. package/lib/transform/draft/odata.js +227 -0
  117. package/lib/transform/forHanaNew.js +98 -783
  118. package/lib/transform/forOdataNew.js +22 -175
  119. package/lib/transform/localized.js +36 -32
  120. package/lib/transform/odata/generateForeignKeyElements.js +3 -3
  121. package/lib/transform/odata/referenceFlattener.js +95 -89
  122. package/lib/transform/odata/structureFlattener.js +1 -1
  123. package/lib/transform/odata/toFinalBaseType.js +86 -12
  124. package/lib/transform/odata/typesExposure.js +5 -5
  125. package/lib/transform/odata/utils.js +2 -2
  126. package/lib/transform/transformUtilsNew.js +47 -33
  127. package/lib/transform/translateAssocsToJoins.js +13 -30
  128. package/lib/transform/universalCsn/.eslintrc.json +36 -0
  129. package/lib/transform/universalCsn/coreComputed.js +170 -0
  130. package/lib/transform/universalCsn/universalCsnEnricher.js +715 -0
  131. package/lib/transform/universalCsn/utils.js +63 -0
  132. package/lib/utils/file.js +8 -3
  133. package/lib/utils/objectUtils.js +30 -0
  134. package/lib/utils/timetrace.js +8 -2
  135. package/package.json +1 -1
  136. package/share/messages/README.md +26 -0
  137. package/lib/compiler/definer.js +0 -2349
  138. package/lib/compiler/resolver.js +0 -2922
  139. package/lib/transform/db/helpers.js +0 -58
  140. package/lib/transform/universalCsnEnricher.js +0 -67
@@ -42,11 +42,17 @@ const centralMessages = {
42
42
  'anno-definition': { severity: 'Warning' },
43
43
  'anno-duplicate': { severity: 'Error', configurableFor: true }, // does not hurt us
44
44
  'anno-duplicate-unrelated-layer': { severity: 'Error', configurableFor: true }, // does not hurt us
45
+ 'anno-invalid-sql-element': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
46
+ 'anno-invalid-sql-struct': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
47
+ 'anno-invalid-sql-kind': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
48
+ 'anno-invalid-sql-view': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
49
+ 'anno-invalid-sql-view-element': { severity: 'Error', configurableFor: true }, // @sql.prepend/append - configurable for "I know what I'm doing"
45
50
  'anno-undefined-action': { severity: 'Info' },
46
51
  'anno-undefined-art': { severity: 'Info' }, // for annotate statement (for CDL path root)
47
52
  'anno-undefined-def': { severity: 'Info' }, // for annotate statement (for CSN or CDL path cont)
48
53
  'anno-undefined-element': { severity: 'Info' },
49
54
  'anno-undefined-param': { severity: 'Info' },
55
+ 'anno-unexpected-ellipsis-layers': { severity: 'Error', configurableFor: true }, // TODO(v3): Merge with anno-unexpected-ellipsis and make non-configurable
50
56
 
51
57
  'args-expected-named': { severity: 'Error', configurableFor: 'deprecated' }, // future --sloppy
52
58
  'args-no-params': { severity: 'Error', configurableFor: 'deprecated' }, // future --sloppy
@@ -54,13 +60,14 @@ const centralMessages = {
54
60
 
55
61
  'assoc-in-array': { severity: 'Error', configurableFor: 'deprecated' }, // not supported yet
56
62
  'assoc-as-type': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: allow more, but not all
63
+ 'def-unexpected-paramview-assoc': { severity: 'Error' },
64
+ 'def-unexpected-calcview-assoc': { severity: 'Error' },
57
65
 
58
66
  'check-proper-type': { severity: 'Error', configurableFor: [ 'compile' ] },
59
67
  'check-proper-type-of': { severity: 'Info', errorFor: [ 'for.odata', 'to.edmx', 'to.hdbcds', 'to.sql', 'to.rename' ] },
60
68
 
61
69
  'expr-no-filter': { severity: 'Error', configurableFor: 'deprecated' },
62
70
 
63
- 'empty-entity': { severity: 'Info', errorFor: [ 'to.hdbcds', 'to.sql', 'to.rename' ] },
64
71
  'empty-type': { severity: 'Info' }, // only still an error in old transformers
65
72
 
66
73
  // Structured types were warned about but made CSN un-recompilable.
@@ -69,7 +76,7 @@ const centralMessages = {
69
76
  // TODO: rename to ref-expected-XYZ
70
77
  'expected-type': { severity: 'Error' },
71
78
  'ref-sloppy-type': { severity: 'Error' },
72
- 'ref-invalid-typeof': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: make it non-config
79
+ 'type-unexpected-typeof': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: make it non-config
73
80
  'expected-actionparam-type': { severity: 'Error' },
74
81
  'ref-sloppy-actionparam-type': { severity: 'Error' },
75
82
  'expected-event-type': { severity: 'Error' },
@@ -89,6 +96,7 @@ const centralMessages = {
89
96
  'query-undefined-element': { severity: 'Error' },
90
97
  'query-unexpected-assoc-hdbcds': { severity: 'Error' },
91
98
  'query-unexpected-structure-hdbcds': { severity: 'Error' },
99
+ 'query-ignoring-param-nullability': { severity: 'Info' },
92
100
 
93
101
  'recalculated-localized': { severity: 'Info' }, // KEEP: Downgrade in lib/transform/translateAssocsToJoins.js
94
102
  'redirected-implicitly-ambiguous': { severity: 'Error', configurableFor: true }, // does not hurt us - TODO: ref-ambiguous-target
@@ -99,6 +107,7 @@ const centralMessages = {
99
107
  'ref-undefined-def': { severity: 'Error' },
100
108
  'ref-undefined-var': { severity: 'Error' },
101
109
  'ref-undefined-element': { severity: 'Error' },
110
+ 'ref-unknown-var': { severity: 'Info' },
102
111
  'ref-obsolete-parameters': { severity: 'Error', configurableFor: true }, // does not hurt us
103
112
  'ref-undefined-param': { severity: 'Error' },
104
113
  'ref-rejected-on': { severity: 'Error' },
@@ -126,8 +135,17 @@ const centralMessages = {
126
135
  'syntax-fragile-alias': { severity: 'Error', configurableFor: true },
127
136
  'syntax-fragile-ident': { severity: 'Error', configurableFor: true },
128
137
 
138
+ 'syntax-invalid-extend': { severity: 'Error' },
139
+
140
+ 'syntax-invalid-text-block' : { severity: 'Error' },
141
+ 'syntax-unknown-escape': { severity: 'Error', configurableFor: true },
142
+ 'syntax-invalid-escape': { severity: 'Error' },
143
+ 'syntax-missing-escape': { severity: 'Error' },
144
+
129
145
  'type-managed-composition': { severity: 'Error', configurableFor: 'deprecated' }, // TODO: non-config
130
146
 
147
+ 'def-missing-element': { severity: 'Error' },
148
+
131
149
  'unexpected-keys-for-composition': { severity: 'Error' }, // TODO: more than 30 chars
132
150
  'unmanaged-as-key': { severity: 'Error', configurableFor: 'deprecated' }, // is confusing
133
151
  'composition-as-key': { severity: 'Error', configurableFor: 'deprecated' }, // is confusing and not supported
@@ -144,8 +162,10 @@ const centralMessages = {
144
162
 
145
163
  // For messageIds, where no text has been provided via code (central def)
146
164
  const centralMessageTexts = {
165
+ 'anno-duplicate': 'Duplicate assignment with $(ANNO)',
147
166
  'anno-mismatched-ellipsis': 'An array with $(CODE) can only be used if there is an assignment below with an array value',
148
- 'anno-unexpected-ellipsis': 'Unexpected $(CODE) in annotation assignment',
167
+ 'anno-unexpected-ellipsis': 'No base annotation available to apply $(CODE)',
168
+ 'anno-unexpected-ellipsis-layers': 'No base annotation available to apply $(CODE)',
149
169
  'missing-type-parameter': 'Missing value for type parameter $(NAME) in reference to type $(ID)',
150
170
  'syntax-csn-expected-object': 'Expected object for property $(PROP)',
151
171
  'syntax-csn-expected-column': 'Expected object or string \'*\' for property $(PROP)',
@@ -167,6 +187,23 @@ const centralMessageTexts = {
167
187
  one: 'Expected array in $(PROP) to have at least one item',
168
188
  suffix: 'With sibling property $(OTHERPROP), expected array in $(PROP) to have at least one item',
169
189
  },
190
+ 'syntax-invalid-extend': 'Can\'t extend an element with $(KIND)',
191
+ 'syntax-invalid-text-block': 'Missing newline in text block',
192
+ 'syntax-unknown-escape': 'Unknown escape sequence $(CODE)',
193
+ 'syntax-invalid-escape': {
194
+ std: 'Invalid escape sequence $(CODE)',
195
+ octal: 'Octal escape sequences are not supported. Use unicode escapes instead',
196
+ whitespace: 'Unknown escape sequence: Can\'t escape whitespace',
197
+ codepoint: 'Undefined code-point for $(CODE)',
198
+ 'unicode-hex': 'Expected hexadecimal numbers for unicode escape but found $(CODE)',
199
+ 'hex-count': 'Expected $(NUMBER) hexadecimal numbers for escape sequence but found $(CODE)',
200
+ 'unicode-brace': 'Missing closing brace for unicode escape sequence',
201
+ 'language-identifier': 'Escape sequences in text-block\'s language identifier are not allowed',
202
+ },
203
+ 'syntax-missing-escape': {
204
+ std: 'Missing escape. Replace $(CODE) with $(NEWCODE)',
205
+ placeholder: 'Placeholders are not supported. Replace $(CODE) with $(NEWCODE)',
206
+ },
170
207
  'ref-undefined-def': {
171
208
  std: 'Artifact $(ART) has not been found',
172
209
  // TODO: proposal 'No definition of $(NAME) found',
@@ -178,17 +215,21 @@ const centralMessageTexts = {
178
215
  std: 'Element $(ART) has not been found',
179
216
  element: 'Artifact $(ART) has no element $(MEMBER)'
180
217
  },
218
+ 'ref-unknown-var': {
219
+ std: 'Replacement $(ID) not found'
220
+ },
221
+ 'ref-unexpected-draft-enabled': 'Composition in draft-enabled entity can\'t lead to another entity with $(ANNO)',
181
222
  'ref-rejected-on': {
182
223
  std: 'Do not refer to a artefact like $(ID) in the explicit ON of a redirection', // Not used
183
224
  mixin: 'Do not refer to a mixin like $(ID) in the explicit ON of a redirection',
184
225
  alias: 'Do not refer to a source element (via table alias $(ID)) in the explicit ON of a redirection',
185
226
  },
186
- 'ref-invalid-typeof': {
187
- std: 'Do not use $(KEYWORD) for the type reference here',
188
- type: 'Do not use $(KEYWORD) for the type of a type',
189
- event: 'Do not use $(KEYWORD) for the type of an event',
190
- param: 'Do not use $(KEYWORD) for the type of a parameter',
191
- select: 'Do not use $(KEYWORD) for type references in queries',
227
+ 'type-unexpected-typeof': {
228
+ std: 'Unexpected $(KEYWORD) for the type reference here',
229
+ type: 'Unexpected $(KEYWORD) in type of a type definition',
230
+ event: 'Unexpected $(KEYWORD) for the type of an event',
231
+ param: 'Unexpected $(KEYWORD) for the type of a parameter definition',
232
+ select: 'Unexpected $(KEYWORD) for type references in queries',
192
233
  },
193
234
  'anno-builtin': 'Builtin types should not be annotated. Use custom type instead',
194
235
  'anno-undefined-def': 'Artifact $(ART) has not been found',
@@ -207,6 +248,22 @@ const centralMessageTexts = {
207
248
  param: 'Artifact $(ART) has no parameter $(MEMBER)'
208
249
  },
209
250
 
251
+ 'def-unexpected-paramview-assoc': {
252
+ std: 'SAP HANA does no support associations in/to parameterized entities',
253
+ view: 'SAP HANA does no support associations in parameterized entities',
254
+ target: 'SAP HANA does no support associations to parameterized entities',
255
+ },
256
+ 'def-unexpected-calcview-assoc': {
257
+ std: 'SAP HANA does not allow associations in/to entities annotated with $(ANNO)',
258
+ 'entity-persistence': 'SAP HANA does not allow associations in entities annotated with $(ANNO)',
259
+ 'target-persistence': 'SAP HANA does not allow associations pointing to entities annotated with $(ANNO)',
260
+ },
261
+
262
+ 'def-missing-element': {
263
+ std: 'Expecting entity to have at least one non-virtual element',
264
+ view: 'Expecting view to have at least one non-virtual element'
265
+ },
266
+
210
267
  'duplicate-definition': {
211
268
  std: 'Duplicate definition of $(NAME)',
212
269
  absolute: 'Duplicate definition of artifact $(NAME)',
@@ -235,6 +292,10 @@ const centralMessageTexts = {
235
292
 
236
293
  'query-unexpected-assoc-hdbcds': 'Publishing a managed association in a view is not possible for “hdbcds” naming mode',
237
294
  'query-unexpected-structure-hdbcds': 'Publishing a structured element in a view is not possible for “hdbcds” naming mode',
295
+ 'query-ignoring-param-nullability': {
296
+ std: 'Ignoring nullability constraint on parameter when generating SAP HANA CDS view',
297
+ sql: 'Ignoring nullability constraint on parameter when generating SQL view'
298
+ },
238
299
 
239
300
  'ref-sloppy-type': 'A type or an element is expected here',
240
301
  'ref-sloppy-actionparam-type': 'A type, an element, or a service entity is expected here',
@@ -273,6 +334,11 @@ const centralMessageTexts = {
273
334
  'odata-spec-violation-type': 'Expected element to have a type',
274
335
  'odata-spec-violation-property-name': 'Expected element name to be different from declaring $(KIND)',
275
336
  'odata-spec-violation-namespace': 'Expected service name not to be one of the reserved names $(NAMES)',
337
+ // Other odata/edm errors
338
+ 'odata-definition-exists': {
339
+ std: 'Entity can\'t be created due to name collision with existing definition $(NAME)',
340
+ proxy: 'No proxy entity created due to name collision with existing definition $(NAME) of kind $(KIND)'
341
+ }
276
342
  }
277
343
 
278
344
  /**
@@ -125,6 +125,7 @@ class CompileMessage {
125
125
  * @param {CSN.MessageSeverity} [severity='Error'] Severity: Debug, Info, Warning, Error
126
126
  * @param {string} [id] The ID of the message - visible as property messageId
127
127
  * @param {any} [home]
128
+ * @param {string} [moduleName] Name of the module that created this message
128
129
  *
129
130
  * @memberOf CompileMessage
130
131
  */
@@ -175,22 +176,6 @@ function dollarLocation( location ) {
175
176
  return loc;
176
177
  }
177
178
 
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
179
  const severitySpecs = {
195
180
  error: { name: 'Error', level: 0 },
196
181
  warning: { name: 'Warning', level: 1 },
@@ -282,16 +267,16 @@ function compareSeverities( a, b ) {
282
267
  /**
283
268
  * @todo This was copied from somewhere just to make CSN paths work.
284
269
  * @param {CSN.Model} model
285
- * @param {CSN.Path} path
270
+ * @param {CSN.Path} csnPath
286
271
  */
287
- function searchForLocation( model, path ) {
272
+ function searchForLocation( model, csnPath ) {
288
273
  if (!model)
289
274
  return null;
290
275
  // Don't display a location if we cannot find one!
291
276
  let lastLocation = null;
292
277
  /** @type {object} */
293
278
  let currentStep = model;
294
- for (const step of path) {
279
+ for (const step of csnPath) {
295
280
  if (!currentStep)
296
281
  return lastLocation;
297
282
  currentStep = currentStep[step];
@@ -672,13 +657,16 @@ function ignoreTextTransform() {
672
657
 
673
658
  function transformManyWith( t, sorted ) {
674
659
  return function transformMany( many, r, args, texts ) {
675
- const prop = ['none','one'][ many.length ];
676
- if (!prop || !texts[prop] || args['#'] ) {
677
- const names = many.map(t);
678
- return (sorted ? names.sort() : names).join(', ');
679
- }
660
+ const prop = ['none','one','two'][ many.length ];
661
+ const names = many.map(t);
662
+ if (sorted)
663
+ names.sort();
664
+ if (!prop || !texts[prop] || args['#'] )
665
+ return names.join(', ');
680
666
  r['#'] = prop; // text variant
681
- return many.length && t( many[0] );
667
+ if (many.length === 2)
668
+ r.second = names[1];
669
+ return many.length && names[0];
682
670
  };
683
671
  }
684
672
 
@@ -793,7 +781,7 @@ function replaceInString( text, params ) {
793
781
  start = pattern.lastIndex;
794
782
  }
795
783
  parts.push( text.substring( start ) );
796
- let remain = ('#' in params) ? [] : Object.keys( params ).filter( n => params[n] );
784
+ let remain = (params['#']) ? [] : Object.keys( params ).filter( n => params[n] );
797
785
  return (remain.length)
798
786
  ? parts.join('') + '; ' +
799
787
  remain.map( n => n.toUpperCase() + ' = ' + params[n] ).join(', ')
@@ -845,7 +833,10 @@ function messageHash(msg) {
845
833
  if(!msg.home)
846
834
  return messageString(msg);
847
835
  const copy = {...msg};
848
- copy.$location = undefined;
836
+ // Note: This is a hack. deduplicateMessages() would otherwise remove
837
+ // all but one message about duplicated artifacts.
838
+ if (!msg.messageId || !msg.messageId.includes('duplicate'))
839
+ copy.$location = undefined;
849
840
  return messageString(copy);
850
841
  }
851
842
 
@@ -1082,7 +1073,7 @@ function deduplicateMessages( messages ) {
1082
1073
 
1083
1074
  function shortArtName( art ) {
1084
1075
  const { name } = art;
1085
- if ([ 'select', 'action', 'alias', 'param' ].every( n => name[n] == null ) &&
1076
+ if ([ 'select', 'action', 'alias', 'param' ].every( n => name[n] == null || name[n] === 1 ) &&
1086
1077
  !name.absolute.includes(':'))
1087
1078
  return quote.name( name.element ? `${ name.absolute }:${ name.element }` : name.absolute );
1088
1079
  return artName( art );
@@ -1095,13 +1086,15 @@ function artName( art, omit ) {
1095
1086
  r.push( (art.kind === 'extend' ? 'block:' : 'query:') + name.select ); // TODO: rename to 'select:1' and consider whether there are more selects
1096
1087
  if (name.action && omit !== 'action')
1097
1088
  r.push( memberActionName(art) + ':' + quoted( name.action ) );
1098
- if (name.alias)
1089
+ if (name.alias && art.kind !== '$self')
1099
1090
  r.push( (art.kind === 'mixin' ? 'mixin:' : 'alias:') + quoted( name.alias ) )
1100
1091
  if (name.param != null && omit !== 'param')
1101
1092
  r.push( name.param ? 'param:' + quoted( name.param ) : 'returns' ); // TODO: join
1102
1093
  if (name.element && omit !== 'element')
1103
1094
  // r.push( `${ art.kind }: ${ quoted( name.element )}` ); or even better element:"assoc"/key:"i" same with enum
1104
1095
  r.push( (art.kind === 'enum' ? 'enum:' : 'element:') + quoted( name.element ) );
1096
+ if (art.kind === '$self')
1097
+ r.push( 'alias:' + quoted( name.alias ) ) // should be late due to $self in anonymous aspect
1105
1098
  return r.join('/');
1106
1099
  }
1107
1100
 
@@ -1114,6 +1107,7 @@ function memberActionName( art ) {
1114
1107
  return 'action';
1115
1108
  }
1116
1109
 
1110
+ // TODO: XSN-specific things should probably move out
1117
1111
  function homeName( art, absoluteOnly ) {
1118
1112
  if (!art)
1119
1113
  return art;
@@ -1129,8 +1123,10 @@ function homeName( art, absoluteOnly ) {
1129
1123
  return homeName( art.name._artifact, absoluteOnly ); // use corresponding definition
1130
1124
  else if (absoluteOnly)
1131
1125
  return art.name.absolute;
1132
- else
1133
- return (art._main ? art._main.kind : art.kind) + ':' + artName( art );
1126
+ let main = art._main || art;
1127
+ while (main._outer) // anonymous aspect
1128
+ main = main._outer._main;
1129
+ return main.kind + ':' + artName( art );
1134
1130
  }
1135
1131
 
1136
1132
  // The "home" for extensions is handled differently because `_artifact` is not
@@ -1184,9 +1180,9 @@ function constructSemanticLocationFromCsnPath(csnPath, model) {
1184
1180
 
1185
1181
  // remove definitions
1186
1182
  csnPath.shift();
1187
- const artName = csnPath.shift();
1188
- let currentThing = model.definitions[artName];
1189
- let result = `${ (currentThing && currentThing.kind) ? currentThing.kind : 'artifact' }:${ _quoted(artName) }`;
1183
+ const artifactName = csnPath.shift();
1184
+ let currentThing = model.definitions[artifactName];
1185
+ let result = `${ (currentThing && currentThing.kind) ? currentThing.kind : 'artifact' }:${ _quoted(artifactName) }`;
1190
1186
 
1191
1187
  if (!currentThing)
1192
1188
  return result;
@@ -1438,12 +1434,12 @@ module.exports = {
1438
1434
  createMessageFunctions,
1439
1435
  makeMessageFunction,
1440
1436
  artName,
1441
- handleMessages,
1442
1437
  sortMessages: (m => m.sort(compareMessage)),
1443
1438
  sortMessagesSeverityAware: (m => m.sort(compareMessageSeverityAware)),
1444
1439
  deduplicateMessages,
1445
1440
  CompileMessage,
1446
1441
  CompilationError,
1442
+ isMessageDowngradable: isDowngradable,
1447
1443
  explainMessage,
1448
1444
  hasMessageExplanation,
1449
1445
  messageIdsWithExplanation,
package/lib/base/model.js CHANGED
@@ -63,7 +63,7 @@ function isBetaEnabled( options, feature ) {
63
63
  */
64
64
  function isDeprecatedEnabled( options, feature = null ) {
65
65
  const { deprecated } = options;
66
- if(!feature)
66
+ if (!feature)
67
67
  return !!deprecated;
68
68
  return deprecated && typeof deprecated === 'object' && deprecated[feature];
69
69
  }
@@ -93,63 +93,6 @@ function forEachMember( construct, callback, target ) {
93
93
 
94
94
  }
95
95
 
96
- // Apply function `callback(member, memberName, prop)` to each member in
97
- // `construct`, recursively (i.e. also for sub-elements of elements).
98
- function forEachMemberRecursively( construct, callback ) {
99
- forEachMember( construct, ( member, memberName, prop ) => {
100
- callback( member, memberName, prop );
101
- // Descend into nested members, too
102
- forEachMemberRecursively( member, callback );
103
- });
104
- // If 'construct' has more than one query, descend into the elements of the remaining ones, too
105
- if (construct.$queries && construct.$queries.length > 1) {
106
- construct.$queries.slice(1).forEach(query => forEachMemberRecursively(query, callback));
107
- }
108
- }
109
-
110
- /**
111
- * Apply function `callback` to all members of object `obj` (main artifact or
112
- * parent member). Members are considered those in dictionaries `elements`,
113
- * `enum`, `actions` and `params` of `obj`, `elements` and `enums` are also
114
- * searched inside property `items` (array of). `$queries`, `mixin` and
115
- * `columns` are also visited in contrast to `forEachMember()`.
116
- * See function `forEachGeneric()` for details.
117
- *
118
- * @param {XSN.Artifact} construct
119
- * @param {(member: object, memberName: string, prop: string) => any} callback
120
- * @param {object} [target]
121
- */
122
- function forEachMemberWithQuery( construct, callback, target ) {
123
- let obj = construct.returns || construct; // why the extra `returns` for actions?
124
- obj = obj.items || obj;
125
- forEachGeneric( target || obj, 'elements', callback );
126
- forEachGeneric( obj, 'enum', callback );
127
- forEachGeneric( obj, 'foreignKeys', callback );
128
- forEachGeneric( construct, 'actions', callback );
129
- forEachGeneric( construct, 'params', callback );
130
- // For Queries
131
- forEachGeneric( construct, '$queries', callback );
132
- forEachGeneric( construct, 'mixin', callback );
133
- forEachGeneric( construct, 'columns', callback );
134
- }
135
-
136
- /**
137
- * Apply function `callback(member, memberName, prop)` to each member in
138
- * `construct`, recursively (i.e. also for sub-elements of elements).
139
- * In contrast to `forEachMemberRecursively()` this function also traverses
140
- * queries and mixins.
141
- *
142
- * @param {XSN.Artifact} construct
143
- * @param {(member: object, memberName: string, prop: string) => any} callback
144
- */
145
- function forEachMemberRecursivelyWithQuery( construct, callback ) {
146
- forEachMemberWithQuery( construct, ( member, memberName, prop ) => {
147
- callback( member, memberName, prop );
148
- // Descend into nested members, too
149
- forEachMemberRecursivelyWithQuery( member, callback );
150
- });
151
- }
152
-
153
96
  // Apply function `callback` to all objects in dictionary `dict`, including all
154
97
  // duplicates (found under the same name). Function `callback` is called with
155
98
  // the following arguments: the object, the name, and -if it is a duplicate-
@@ -157,7 +100,7 @@ function forEachMemberRecursivelyWithQuery( construct, callback ) {
157
100
  function forEachGeneric( obj, prop, callback ) {
158
101
  let dict = obj[prop];
159
102
  for (let name in dict) {
160
- let obj = dict[name];
103
+ obj = dict[name];
161
104
  callback( obj, name, prop );
162
105
  if (Array.isArray(obj.$duplicates)) // redefinitions
163
106
  obj.$duplicates.forEach( o => callback( o, name, prop ) )
@@ -189,9 +132,6 @@ module.exports = {
189
132
  queryOps,
190
133
  forEachDefinition,
191
134
  forEachMember,
192
- forEachMemberRecursively,
193
- forEachMemberWithQuery,
194
- forEachMemberRecursivelyWithQuery,
195
135
  forEachGeneric,
196
136
  forEachInOrder,
197
137
  setProp,