@sap/cds-compiler 3.1.2 → 3.4.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 (117) hide show
  1. package/CHANGELOG.md +101 -3
  2. package/bin/cdsc.js +4 -2
  3. package/doc/CHANGELOG_BETA.md +35 -0
  4. package/lib/api/main.js +153 -29
  5. package/lib/api/validate.js +8 -3
  6. package/lib/base/dictionaries.js +6 -6
  7. package/lib/base/error.js +2 -2
  8. package/lib/base/keywords.js +106 -24
  9. package/lib/base/message-registry.js +177 -79
  10. package/lib/base/messages.js +78 -57
  11. package/lib/base/model.js +2 -1
  12. package/lib/checks/actionsFunctions.js +1 -1
  13. package/lib/checks/annotationsOData.js +2 -2
  14. package/lib/checks/arrayOfs.js +15 -7
  15. package/lib/checks/cdsPersistence.js +1 -1
  16. package/lib/checks/checkForTypes.js +53 -0
  17. package/lib/checks/defaultValues.js +4 -2
  18. package/lib/checks/elements.js +81 -6
  19. package/lib/checks/foreignKeys.js +12 -13
  20. package/lib/checks/invalidTarget.js +10 -11
  21. package/lib/checks/managedInType.js +21 -15
  22. package/lib/checks/nullableKeys.js +1 -1
  23. package/lib/checks/onConditions.js +9 -9
  24. package/lib/checks/parameters.js +23 -0
  25. package/lib/checks/queryNoDbArtifacts.js +1 -1
  26. package/lib/checks/selectItems.js +1 -1
  27. package/lib/checks/sql-snippets.js +12 -10
  28. package/lib/checks/types.js +2 -2
  29. package/lib/checks/utils.js +17 -7
  30. package/lib/checks/validator.js +36 -14
  31. package/lib/compiler/assert-consistency.js +21 -13
  32. package/lib/compiler/builtins.js +8 -0
  33. package/lib/compiler/checks.js +57 -40
  34. package/lib/compiler/define.js +139 -69
  35. package/lib/compiler/extend.js +319 -50
  36. package/lib/compiler/finalize-parse-cdl.js +14 -9
  37. package/lib/compiler/kick-start.js +2 -35
  38. package/lib/compiler/populate.js +111 -68
  39. package/lib/compiler/propagator.js +5 -3
  40. package/lib/compiler/resolve.js +71 -108
  41. package/lib/compiler/shared.js +82 -54
  42. package/lib/compiler/tweak-assocs.js +26 -14
  43. package/lib/compiler/utils.js +13 -2
  44. package/lib/edm/annotations/genericTranslation.js +10 -7
  45. package/lib/edm/csn2edm.js +11 -11
  46. package/lib/edm/edm.js +17 -9
  47. package/lib/edm/edmPreprocessor.js +53 -30
  48. package/lib/edm/edmUtils.js +7 -2
  49. package/lib/gen/Dictionary.json +14 -0
  50. package/lib/gen/language.checksum +1 -1
  51. package/lib/gen/language.interp +3 -2
  52. package/lib/gen/languageParser.js +4312 -4186
  53. package/lib/inspect/inspectModelStatistics.js +1 -1
  54. package/lib/inspect/inspectPropagation.js +23 -9
  55. package/lib/json/csnVersion.js +13 -13
  56. package/lib/json/from-csn.js +161 -172
  57. package/lib/json/to-csn.js +70 -10
  58. package/lib/language/.eslintrc.json +4 -0
  59. package/lib/language/antlrParser.js +8 -11
  60. package/lib/language/docCommentParser.js +1 -2
  61. package/lib/language/errorStrategy.js +54 -27
  62. package/lib/language/genericAntlrParser.js +140 -93
  63. package/lib/language/language.g4 +57 -33
  64. package/lib/language/multiLineStringParser.js +75 -63
  65. package/lib/main.d.ts +3 -6
  66. package/lib/main.js +1 -0
  67. package/lib/model/.eslintrc.json +13 -0
  68. package/lib/model/api.js +4 -2
  69. package/lib/model/csnRefs.js +78 -50
  70. package/lib/model/csnUtils.js +272 -222
  71. package/lib/model/enrichCsn.js +41 -31
  72. package/lib/model/revealInternalProperties.js +61 -57
  73. package/lib/model/sortViews.js +35 -31
  74. package/lib/modelCompare/compare.js +52 -18
  75. package/lib/modelCompare/filter.js +83 -0
  76. package/lib/optionProcessor.js +10 -1
  77. package/lib/render/manageConstraints.js +11 -7
  78. package/lib/render/toCdl.js +151 -106
  79. package/lib/render/toHdbcds.js +8 -6
  80. package/lib/render/toRename.js +4 -4
  81. package/lib/render/toSql.js +17 -7
  82. package/lib/render/utils/common.js +27 -9
  83. package/lib/render/utils/sql.js +5 -5
  84. package/lib/sql-identifier.js +7 -0
  85. package/lib/transform/db/applyTransformations.js +32 -3
  86. package/lib/transform/db/assertUnique.js +27 -38
  87. package/lib/transform/db/expansion.js +92 -41
  88. package/lib/transform/db/flattening.js +1 -1
  89. package/lib/transform/db/temporal.js +3 -1
  90. package/lib/transform/db/transformExists.js +8 -2
  91. package/lib/transform/db/views.js +42 -13
  92. package/lib/transform/draft/db.js +2 -2
  93. package/lib/transform/forOdataNew.js +10 -7
  94. package/lib/transform/{forHanaNew.js → forRelationalDB.js} +18 -12
  95. package/lib/transform/localized.js +29 -20
  96. package/lib/transform/odata/toFinalBaseType.js +8 -11
  97. package/lib/transform/odata/typesExposure.js +2 -1
  98. package/lib/transform/parseExpr.js +245 -0
  99. package/lib/transform/transformUtilsNew.js +122 -51
  100. package/lib/transform/translateAssocsToJoins.js +17 -16
  101. package/lib/utils/moduleResolve.js +5 -5
  102. package/lib/utils/objectUtils.js +3 -3
  103. package/lib/utils/term.js +5 -5
  104. package/package.json +2 -2
  105. package/share/messages/anno-duplicate-unrelated-layer.md +6 -6
  106. package/share/messages/check-proper-type-of.md +4 -4
  107. package/share/messages/check-proper-type.md +2 -2
  108. package/share/messages/duplicate-autoexposed.md +4 -4
  109. package/share/messages/extend-repeated-intralayer.md +4 -5
  110. package/share/messages/extend-unrelated-layer.md +4 -4
  111. package/share/messages/message-explanations.json +3 -1
  112. package/share/messages/redirected-to-ambiguous.md +7 -6
  113. package/share/messages/redirected-to-complex.md +63 -0
  114. package/share/messages/redirected-to-unrelated.md +6 -5
  115. package/share/messages/rewrite-not-supported.md +4 -4
  116. package/share/messages/{syntax-expected-integer.md → syntax-expecting-integer.md} +4 -4
  117. package/share/messages/wildcard-excluding-one.md +37 -0
@@ -1,15 +1,31 @@
1
- // Compiler phase "define": transform dictionary of AST-like CSNs into augmented CSN
1
+ // Compiler phase 1 = "define": transform dictionary of AST-like XSNs into XSN
2
2
 
3
- // AST-like CSN looks as follows:
4
- // { kind: 'source', env: <dictionary of artifact defs>, namespace: {}, ... }
3
+ // The 'define' phase (function 'define' below) is the first phase of the compile
4
+ // function. In it, the compiler
5
+ //
6
+ // - collects definitions and extensions from the XSN representation of CDL and
7
+ // CSN sources (“ASTs”) into _one_ XSN model,
8
+ // - sets “structural” links between XSN nodes and completes the “name”,
9
+ // some links and names inside `extensions` are set at a later stage
10
+ // - reports errors for: “late” syntax errors (when it is more convenient to do
11
+ // it here instead of doing it in both CDL and CSN parser), “structural” errors
12
+ // and “duplicate definition errors”
13
+
14
+ // The 'define' phase is the only compile() phase which is also called for
15
+ // parse.cdl. See file ./finalize-parse-cdl.js for details.
16
+
17
+ // --------- TODO: begin in extra markdown document -----------------------------
18
+
19
+ // An XSN for a source looks like
20
+ // { kind: 'source', artifacts: <dictionary of artifact defs>, namespace: {}, ... }
5
21
  //
6
22
  // The property `artifacts` of a source contains the top-level definitions.
7
23
  // Definitions inside a context are not listed here (as opposed to
8
24
  // `definitions`, see below), but inside the property `artifacts` of that context.
9
25
 
10
- // The define phase (function 'define' below) enriches a dictionary of
11
- // (file names to) AST-like CSNs and restructure them a little bit, the result
12
- // is called "augmented CSN":
26
+ // The 'define' phase (function 'define' below) enriches a dictionary of
27
+ // (file names to) AST-like XSNs and restructure them a little bit, the result
28
+ // is called XSN ("augmented CSN"):
13
29
  // { sources: <dictionary of ASTs>, definitions: <dictionary of artifact defs> }
14
30
  //
15
31
  // The property `sources` is the input argument (dictionary of source ASTs).
@@ -20,14 +36,8 @@
20
36
  // objects as the definitions accessible via `sources` and `artifacts` of the
21
37
  // corresponding source/context.
22
38
  //
23
- // Because different sources could define artifacts with the same absolute
24
- // name, this compiler phase also put a property `messages` to the resulting
25
- // model, which is a vector of messages for the redefinitions. (Using the same
26
- // name for different definitions in one source is already recognized during
27
- // parsing.)
28
- //
29
39
  // You get the compact "official" CSN format by applying the function exported
30
- // by "../json/to-csn.js" to the augmented CSN.
40
+ // by "../json/to-csn.js" to the XSN.
31
41
 
32
42
  // Example 'file.cds':
33
43
  // namespace A;
@@ -54,7 +64,7 @@
54
64
  // An artifact definition looks as follows (example: context "A.B" above):
55
65
  // {
56
66
  // kind: 'context',
57
- // name: { id: 'B', absolute: 'A.B', location: { <for the id "B"> } },
67
+ // name: { path: [ { id: 'B'} ], absolute: 'A.B', location: { <for the id "B"> } },
58
68
  // artifacts: <for contexts, a dictionary of artifacts defined within>,
59
69
  // location: { <of the complete artifact definition> } },
60
70
  // _parent: <the parent artifact, here the source 'file.cds'>
@@ -74,11 +84,10 @@
74
84
  // location: { <of the complete element definition> } },
75
85
  // _parent: <the parent artifact, here the type "A.B.C">
76
86
  // }
77
- // References are resolved in the "resolve" phase of the compiler, see
78
- // './resolver.js'. We then get the properties `type.absolute` and `length`.
87
+ // --------- TODO: end in extra markdown document -------------------------------
79
88
 
80
89
  // Sub phase 1 (addXYZ) - only for main artifacts
81
- // - set _block links
90
+ // - set _block links for main definitions, vocabulary and extensions
82
91
  // - store definitions (including context extensions), NO duplicate check
83
92
  // - artifact name check
84
93
  // - Note: the only allow name resolving is resolveUncheckedPath(),
@@ -96,6 +105,7 @@
96
105
  // More sub phases...
97
106
 
98
107
  // The main difficulty is the correct behavior concerning duplicate definitions
108
+ // - For code completion, all duplicate definitions must be further checked.
99
109
  // - We need a unique object for the _subArtifacts dictionary.
100
110
  // - We must have a property at the artifact whether there are duplicates in order
101
111
  // to avoid consequential or repeated errors.
@@ -121,6 +131,7 @@ const {
121
131
  dependsOnSilent,
122
132
  pathName,
123
133
  splitIntoPath,
134
+ annotationHasEllipsis,
124
135
  } = require('./utils');
125
136
  const { compareLayer } = require('./moduleLayers');
126
137
  const { initBuiltins, isInReservedNamespace } = require('./builtins');
@@ -148,15 +159,15 @@ function define( model ) {
148
159
  const {
149
160
  resolveUncheckedPath,
150
161
  checkAnnotate,
151
- defineAnnotations,
152
162
  } = model.$functions;
153
163
 
154
164
  const extensionsDict = Object.create(null);
155
165
  Object.assign( model.$functions, {
156
166
  initArtifact,
157
167
  initMembers,
158
- extensionsDict, // a dictionary - TODO: remove
168
+ extensionsDict, // a dictionary - TODO: put directly into model?
159
169
  checkDefinitions,
170
+ initAnnotations,
160
171
  } );
161
172
  // During the definer, we can only resolve artifact references, i.e,
162
173
  // after a `.`, we only search in the `_subArtifacts` dictionary:
@@ -193,8 +204,9 @@ function define( model ) {
193
204
  initNamespaceAndUsing( model.sources[name] );
194
205
  dictForEach( model.definitions, initArtifact );
195
206
  dictForEach( model.vocabularies, initVocabulary );
207
+ dictForEach( extensionsDict, initExtension );
196
208
 
197
- mergeI18nBlocks( model );
209
+ mergeI18nBlocks();
198
210
  }
199
211
 
200
212
  // Phase 1: ----------------------------------------------------------------
@@ -213,9 +225,8 @@ function define( model ) {
213
225
  let namespace = src.namespace && src.namespace.path;
214
226
  let prefix = namespace ? `${ pathName( namespace ) }.` : '';
215
227
  if (isInReservedNamespace(prefix)) {
216
- error( 'reserved-namespace-cds', [ src.namespace.location, src.namespace ], {},
217
- // TODO: use $(NAME)
218
- 'The namespace "cds" is reserved for CDS builtins' );
228
+ error( 'reserved-namespace-cds', [ src.namespace.location, src.namespace ], { name: 'cds' },
229
+ 'The namespace $(NAME) is reserved for CDS builtins' );
219
230
  namespace = null;
220
231
  }
221
232
  if (src.$frontend !== 'json') { // CDL input
@@ -249,9 +260,8 @@ function define( model ) {
249
260
  const { absolute } = art.name;
250
261
  // TODO: check reserved, see checkName()/checkLocalizedObjects() of checks.js
251
262
  if (absolute === 'cds' || isInReservedNamespace(absolute)) {
252
- error( 'reserved-namespace-cds', [ art.name.location, art ], {},
253
- // TODO: use $(NAME)
254
- 'The namespace "cds" is reserved for CDS builtins' );
263
+ error( 'reserved-namespace-cds', [ art.name.location, art ], { name: 'cds' },
264
+ 'The namespace $(NAME) is reserved for CDS builtins' );
255
265
  const builtin = model.definitions[absolute];
256
266
  if (builtin && builtin.builtin) // if already a builtin...
257
267
  return;
@@ -259,8 +269,6 @@ function define( model ) {
259
269
  }
260
270
  else if (art.query && (absolute === 'localized' || absolute.startsWith( 'localized.' ))) {
261
271
  // Due to recompilation, we don't emit this info message for JSON frontend.
262
- // TODO: generalize this for $generated (definitions starting with
263
- // "localized" just have `$generated: true` as default)
264
272
  if (block.$frontend !== 'json') {
265
273
  info( 'ignored-localized-definition', [ art.name.location, art ], {},
266
274
  'This definition in the namespace "localized" is ignored' );
@@ -398,7 +406,7 @@ function define( model ) {
398
406
 
399
407
  // Phase 2 ("init") --------------------------------------------------------
400
408
  // Functions called from top-level: initNamespaceAndUsing(), initArtifact(),
401
- // initVocabulary()
409
+ // initVocabulary(), initExtension()
402
410
 
403
411
  function checkRedefinition( art ) {
404
412
  if (!art.$duplicates || art.$errorReported === 'syntax-duplicate-extend' ||
@@ -419,6 +427,8 @@ function define( model ) {
419
427
  }
420
428
 
421
429
  function initNamespaceAndUsing( src ) {
430
+ if (src.$frontend && src.$frontend !== 'cdl')
431
+ return;
422
432
  if (src.namespace) {
423
433
  const decl = src.namespace;
424
434
  const { path } = decl;
@@ -463,11 +473,11 @@ function define( model ) {
463
473
  initParentLink( art, model.definitions );
464
474
  const block = art._block;
465
475
  checkRedefinition( art );
466
- defineAnnotations( art, art, block );
476
+ initAnnotations( art, block );
467
477
  initMembers( art, art, block );
468
478
  initDollarSelf( art ); // $self
469
479
  if (art.params)
470
- initParams( art ); // $parameters
480
+ initDollarParameters( art );
471
481
  if (art.includes && !(art.name.absolute in extensionsDict)) // TODO: in next phase?
472
482
  extensionsDict[art.name.absolute] = []; // structure with includes must be "extended"
473
483
 
@@ -478,19 +488,23 @@ function define( model ) {
478
488
  if (!setLink( art, '_leadingQuery', initQueryExpression( art.query, art ) ) )
479
489
  return; // null or undefined in case of parse error
480
490
  setLink( art._leadingQuery, '_$next', art );
481
- // the following we be removed soon if we have:
491
+ // the following may be removed soon if we have:
482
492
  // view elements as proxies to elements of leading query
483
493
  if (art.elements) { // specified element via compilation of client-style CSN
484
494
  setLink( art, 'elements$', art.elements );
485
495
  delete art.elements;
486
496
  }
497
+ if (art.enum) { // specified enum via compilation of client-style CSN
498
+ setLink( art, 'enum$', art.enum );
499
+ delete art.enum;
500
+ }
487
501
  }
488
502
 
489
503
  function initVocabulary( art ) {
490
504
  initParentLink( art, model.vocabularies );
491
505
  checkRedefinition( art );
492
506
  const block = art._block;
493
- defineAnnotations( art, art, block );
507
+ initAnnotations( art, block );
494
508
  initMembers( art, art, block );
495
509
  }
496
510
 
@@ -516,6 +530,57 @@ function define( model ) {
516
530
  parent._subArtifacts[absolute.substring( dot + 1 )] = art; // not dictAdd()
517
531
  }
518
532
 
533
+ /** Initialize the extension `ext`.
534
+ *
535
+ * Currently:
536
+ *
537
+ * - initialize annotations (set _block, $priority, `...` check) on "main"
538
+ * extension and its columns do more later
539
+ * - for members in compile(): init annotations via extendMembers/annotateMembers
540
+ * - for members in parse.cdl(): init annotation via initMembers
541
+ *
542
+ * In the future:
543
+ *
544
+ * - also initialize members and member extensions/annotations here
545
+ * - we might also do other things, like calculating whether an `extend` is
546
+ * `annotate`-like, i.e. only contains name-resolution irrelevant extensions.
547
+ */
548
+ function initExtension( ext ) {
549
+ const block = ext._block;
550
+ initAnnotations( ext, block, ext.kind );
551
+ if (ext.columns) // the columns themselves are "definitions"
552
+ ext.columns.forEach( col => initAnnotations( col, block ) );
553
+ }
554
+
555
+ // Set _block links for annotations (necessary for layering) and do a late
556
+ // syntax check (`...` only with extensions, not definitions).
557
+ // extKind is either ext.kind (=art is extension) or false (=art is not an extension)
558
+ function initAnnotations( art, block, extKind = false ) {
559
+ // TODO: think of removing $priority, then
560
+ // no _block: define, _block: annotate/extend/edmx
561
+ // would fit with extending defs with props like length
562
+ for (const prop in art) {
563
+ if (prop.charAt(0) === '@') {
564
+ const anno = art[prop];
565
+ // TODO: make anno never be an array, see addAnnotation() in genericAntlrParser
566
+ if (Array.isArray( anno ))
567
+ anno.forEach( init );
568
+ else
569
+ init( anno );
570
+ }
571
+ }
572
+ return;
573
+
574
+ function init( anno ) {
575
+ setLink( anno, '_block', block );
576
+ anno.$priority = extKind;
577
+ if (!extKind && annotationHasEllipsis( anno )) {
578
+ error( 'anno-unexpected-ellipsis',
579
+ [ anno.name.location, art ], { code: '...' } );
580
+ }
581
+ }
582
+ }
583
+
519
584
  // From here til EOF, reexamine code ---------------------------------------
520
585
  // See populate:
521
586
  // - userQuery() or _query property?
@@ -541,7 +606,8 @@ function define( model ) {
541
606
  setLink( art, '_$next', model.$magicVariables );
542
607
  }
543
608
 
544
- function initParams( art ) {
609
+ function initDollarParameters( art ) {
610
+ // TODO: remove $parameters in v4?
545
611
  // TODO: use setMemberParent() ?
546
612
  const parameters = {
547
613
  name: { id: '$parameters', param: '$parameters', absolute: art.name.absolute },
@@ -604,16 +670,16 @@ function define( model ) {
604
670
  // Either expression (value), expand or new association (target && type)
605
671
  else if (col.value || col.expand || (col.target && col.type)) {
606
672
  setLink( col, '_block', parent._block );
607
- defineAnnotations( col, col, parent._block );
673
+ initAnnotations( col, parent._block );
608
674
  if (col.inline) { // `@anno elem.{ * }` does not work
609
675
  if (col.doc)
610
- warning( 'syntax-anno-ignored', [ col.doc.location, col ], { '#': 'doc' } );
676
+ warning( 'syntax-ignoring-anno', [ col.doc.location, col ], { '#': 'doc' } );
611
677
 
612
678
  // col.$annotations no available for CSN input, have to search.
613
679
  // Warning about first annotation should be enough to avoid spam.
614
680
  const firstAnno = Object.keys(col).find(key => key.startsWith('@'));
615
681
  if (firstAnno)
616
- warning( 'syntax-anno-ignored', [ col[firstAnno].name.location, col ] );
682
+ warning( 'syntax-ignoring-anno', [ col[firstAnno].name.location, col ] );
617
683
  }
618
684
  // TODO: allow sub queries? at least in top-level expand without parallel ref
619
685
  if (columns)
@@ -658,7 +724,7 @@ function define( model ) {
658
724
 
659
725
  /**
660
726
  * If we have a valid top-level exists, exists in filters of sub-expressions can be translated,
661
- * since we will have a top-level subquery after exists-processing in the forHanaNew.
727
+ * since we will have a top-level subquery after exists-processing in the forRelationalDB.
662
728
  *
663
729
  * Recursively drill down into:
664
730
  * - the .path
@@ -886,17 +952,21 @@ function define( model ) {
886
952
  /**
887
953
  * Set property `_parent` for all elements in `parent` to `parent` and do so
888
954
  * recursively for all sub elements.
955
+ *
956
+ * If not for extensions: construct === parent
889
957
  */
890
- // If not for extensions: construct === parent
891
958
  function initMembers( construct, parent, block, initExtensions = false ) {
892
959
  // TODO: split extend from init
893
960
  const isQueryExtension = kindProperties[construct.kind].isExtension &&
894
961
  (parent._main || parent).query;
895
962
  let obj = construct;
896
- if (obj.items) { // TODO: while
897
- setLink( obj.items, '_outer', obj );
898
- obj = obj.items; // TODO: probably set parent = obj (is so in csnRefs)
899
- setLink( obj, '_block', block );
963
+ let { items } = obj;
964
+ while (items) {
965
+ setLink( items, '_outer', obj );
966
+ setLink( items, '_parent', obj._parent );
967
+ setLink( items, '_block', block );
968
+ obj = items;
969
+ items = obj.items;
900
970
  }
901
971
  if (obj.target && targetIsTargetAspect( obj )) {
902
972
  obj.targetAspect = obj.target;
@@ -913,7 +983,7 @@ function define( model ) {
913
983
  if (obj.on && !obj.target) {
914
984
  error( 'unexpected-on-for-composition', [ obj.on.location, construct ],
915
985
  {},
916
- 'A managed aspect composition can\'t have a specified ON condition' );
986
+ 'A managed aspect composition can\'t have a specified ON-condition' );
917
987
  delete obj.on; // continuation semantics: not specified
918
988
  }
919
989
  if (targetAspect.elements) {
@@ -1017,9 +1087,9 @@ function define( model ) {
1017
1087
  setMemberParent( elem, name, parent, construct !== parent && prop );
1018
1088
  // console.log(message( null, elem.location, elem, {}, 'Info', 'INIT').toString())
1019
1089
  checkRedefinition( elem );
1020
- if (elem.kind === 'annotate')
1090
+ if (elem.kind === 'annotate' || elem.kind === 'extend')
1021
1091
  checkAnnotate( elem, elem );
1022
- defineAnnotations( elem, elem, bl );
1092
+ initAnnotations( elem, bl );
1023
1093
  initMembers( elem, elem, bl, initExtensions );
1024
1094
 
1025
1095
  // for a correct home path, setMemberParent needed to be called
@@ -1039,7 +1109,7 @@ function define( model ) {
1039
1109
  std: 'Elements can\'t have a value',
1040
1110
  entity: 'Entity elements can\'t have a value',
1041
1111
  type: 'Type elements can\'t have a value',
1042
- extend: 'Cannot extend type/entity elements with values',
1112
+ extend: 'Can\'t extend type/entity elements with values',
1043
1113
  });
1044
1114
  return;
1045
1115
  }
@@ -1072,8 +1142,11 @@ function define( model ) {
1072
1142
  'Actions and functions only exist top-level and for entities' );
1073
1143
  }
1074
1144
  else if (parent.kind === 'action' || parent.kind === 'function') {
1075
- error( 'extend-action', [ construct.location, construct ], {},
1076
- 'Actions and functions can\'t be extended, only annotated' );
1145
+ error( 'extend-action', [ construct.location, construct ], { '#': parent.kind }, {
1146
+ std: 'Actions and functions can\'t be extended, only annotated',
1147
+ action: 'Actions can\'t be extended, only annotated',
1148
+ function: 'Functions can\'t be extended, only annotated',
1149
+ } );
1077
1150
  }
1078
1151
  else if (prop === 'params') {
1079
1152
  if (!feature) {
@@ -1105,29 +1178,27 @@ function define( model ) {
1105
1178
  }
1106
1179
  return construct === parent;
1107
1180
  }
1108
- }
1109
1181
 
1110
- /**
1111
- * Merge (optional) translations into the XSN model.
1112
- *
1113
- * @param {XSN.Model} model
1114
- */
1115
- function mergeI18nBlocks( model ) {
1116
- const sortedSources = Object.keys(model.sources)
1117
- .filter(name => !!model.sources[name].i18n)
1118
- .sort( (a, b) => compareLayer( model.sources[a], model.sources[b] ) );
1182
+ /**
1183
+ * Merge (optional) translations into the XSN model.
1184
+ */
1185
+ function mergeI18nBlocks() {
1186
+ const sortedSources = Object.keys(model.sources)
1187
+ .filter(name => !!model.sources[name].i18n)
1188
+ .sort( (a, b) => compareLayer( model.sources[a], model.sources[b] ) );
1119
1189
 
1120
- if (sortedSources.length === 0)
1121
- return;
1190
+ if (sortedSources.length === 0)
1191
+ return;
1122
1192
 
1123
- if (!model.i18n)
1124
- model.i18n = Object.create( null );
1193
+ if (!model.i18n)
1194
+ model.i18n = Object.create( null );
1125
1195
 
1126
- for (const name of sortedSources)
1127
- initI18nFromSource( model.sources[name] );
1196
+ for (const name of sortedSources)
1197
+ initI18nFromSource( model.sources[name] );
1198
+ }
1128
1199
 
1129
1200
  /**
1130
- * Add the source's translations to the model. Warns if the sources translations
1201
+ * Add the source's translations to the model. Warns if the source's translations
1131
1202
  * do not match the ones from previous sources.
1132
1203
  *
1133
1204
  * @param {XSN.SourceAst} src
@@ -1144,9 +1215,8 @@ function mergeI18nBlocks( model ) {
1144
1215
  model.i18n[langKey][textKey] = sourceVal;
1145
1216
  }
1146
1217
  else if (modelVal.val !== sourceVal.val) {
1147
- // TODO: put mergeI18nBlocks() into main function instead
1148
- model.$messageFunctions.warning( 'i18n-different-value', sourceVal.location,
1149
- { prop: textKey, otherprop: langKey } );
1218
+ warning( 'i18n-different-value', sourceVal.location,
1219
+ { prop: textKey, otherprop: langKey } );
1150
1220
  }
1151
1221
  }
1152
1222
  }