@sap/cds-compiler 2.15.8 → 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 (127) hide show
  1. package/CHANGELOG.md +102 -1590
  2. package/bin/.eslintrc.json +2 -1
  3. package/bin/cdsc.js +61 -46
  4. package/doc/API.md +11 -0
  5. package/doc/CHANGELOG_ARCHIVE.md +1592 -0
  6. package/doc/CHANGELOG_BETA.md +26 -5
  7. package/doc/CHANGELOG_DEPRECATED.md +55 -1
  8. package/doc/{DeprecatedOptions.md → DeprecatedOptions_v2.md} +3 -1
  9. package/doc/Versioning.md +20 -1
  10. package/lib/api/.eslintrc.json +2 -2
  11. package/lib/api/main.js +282 -156
  12. package/lib/api/options.js +17 -88
  13. package/lib/api/validate.js +6 -10
  14. package/lib/base/keywords.js +280 -110
  15. package/lib/base/message-registry.js +85 -25
  16. package/lib/base/messages.js +119 -89
  17. package/lib/base/model.js +46 -2
  18. package/lib/base/optionProcessorHelper.js +53 -21
  19. package/lib/checks/actionsFunctions.js +15 -12
  20. package/lib/checks/annotationsOData.js +1 -1
  21. package/lib/checks/cdsPersistence.js +1 -0
  22. package/lib/checks/elements.js +6 -6
  23. package/lib/checks/invalidTarget.js +1 -1
  24. package/lib/checks/nonexpandableStructured.js +1 -1
  25. package/lib/checks/queryNoDbArtifacts.js +2 -1
  26. package/lib/checks/selectItems.js +101 -15
  27. package/lib/checks/types.js +7 -8
  28. package/lib/checks/utils.js +2 -2
  29. package/lib/checks/validator.js +3 -3
  30. package/lib/compiler/assert-consistency.js +78 -21
  31. package/lib/compiler/base.js +6 -4
  32. package/lib/compiler/builtins.js +177 -10
  33. package/lib/compiler/checks.js +1 -1
  34. package/lib/compiler/define.js +28 -23
  35. package/lib/compiler/extend.js +75 -18
  36. package/lib/compiler/finalize-parse-cdl.js +25 -18
  37. package/lib/compiler/index.js +27 -11
  38. package/lib/compiler/moduleLayers.js +7 -0
  39. package/lib/compiler/populate.js +26 -39
  40. package/lib/compiler/propagator.js +12 -7
  41. package/lib/compiler/resolve.js +207 -236
  42. package/lib/compiler/shared.js +100 -93
  43. package/lib/compiler/tweak-assocs.js +13 -20
  44. package/lib/compiler/utils.js +20 -6
  45. package/lib/edm/annotations/preprocessAnnotations.js +12 -13
  46. package/lib/edm/csn2edm.js +35 -37
  47. package/lib/edm/edm.js +22 -13
  48. package/lib/edm/edmAnnoPreprocessor.js +349 -0
  49. package/lib/edm/edmInboundChecks.js +85 -0
  50. package/lib/edm/edmPreprocessor.js +338 -689
  51. package/lib/edm/edmUtils.js +97 -67
  52. package/lib/gen/Dictionary.json +29 -9
  53. package/lib/gen/language.checksum +1 -1
  54. package/lib/gen/language.interp +8 -31
  55. package/lib/gen/language.tokens +105 -114
  56. package/lib/gen/languageLexer.interp +1 -34
  57. package/lib/gen/languageLexer.js +892 -1007
  58. package/lib/gen/languageLexer.tokens +95 -106
  59. package/lib/gen/languageParser.js +20629 -22474
  60. package/lib/inspect/.eslintrc.json +4 -0
  61. package/lib/inspect/index.js +14 -0
  62. package/lib/inspect/inspectModelStatistics.js +81 -0
  63. package/lib/inspect/inspectPropagation.js +189 -0
  64. package/lib/inspect/inspectUtils.js +44 -0
  65. package/lib/json/from-csn.js +74 -69
  66. package/lib/json/to-csn.js +17 -14
  67. package/lib/language/antlrParser.js +2 -2
  68. package/lib/language/docCommentParser.js +61 -38
  69. package/lib/language/errorStrategy.js +52 -40
  70. package/lib/language/genericAntlrParser.js +424 -292
  71. package/lib/language/language.g4 +604 -687
  72. package/lib/language/multiLineStringParser.js +14 -42
  73. package/lib/language/textUtils.js +44 -0
  74. package/lib/main.d.ts +28 -42
  75. package/lib/main.js +104 -81
  76. package/lib/model/api.js +1 -1
  77. package/lib/model/csnRefs.js +57 -30
  78. package/lib/model/csnUtils.js +189 -287
  79. package/lib/model/revealInternalProperties.js +32 -10
  80. package/lib/model/sortViews.js +32 -31
  81. package/lib/modelCompare/compare.js +3 -0
  82. package/lib/optionProcessor.js +91 -57
  83. package/lib/render/.eslintrc.json +1 -1
  84. package/lib/render/DuplicateChecker.js +4 -7
  85. package/lib/render/manageConstraints.js +70 -2
  86. package/lib/render/toCdl.js +387 -367
  87. package/lib/render/toHdbcds.js +20 -16
  88. package/lib/render/toRename.js +44 -22
  89. package/lib/render/toSql.js +81 -59
  90. package/lib/render/utils/common.js +16 -3
  91. package/lib/render/utils/sql.js +20 -19
  92. package/lib/sql-identifier.js +6 -0
  93. package/lib/transform/db/.eslintrc.json +3 -2
  94. package/lib/transform/db/associations.js +43 -35
  95. package/lib/transform/db/cdsPersistence.js +5 -16
  96. package/lib/transform/db/constraints.js +1 -1
  97. package/lib/transform/db/expansion.js +7 -6
  98. package/lib/transform/db/flattening.js +16 -18
  99. package/lib/transform/db/transformExists.js +7 -5
  100. package/lib/transform/db/views.js +3 -3
  101. package/lib/transform/draft/.eslintrc.json +2 -2
  102. package/lib/transform/draft/db.js +6 -6
  103. package/lib/transform/draft/odata.js +6 -7
  104. package/lib/transform/forHanaNew.js +30 -24
  105. package/lib/transform/forOdataNew.js +14 -16
  106. package/lib/transform/localized.js +35 -25
  107. package/lib/transform/odata/toFinalBaseType.js +10 -10
  108. package/lib/transform/odata/typesExposure.js +17 -8
  109. package/lib/transform/odata/utils.js +1 -38
  110. package/lib/transform/transformUtilsNew.js +63 -77
  111. package/lib/transform/translateAssocsToJoins.js +2 -2
  112. package/lib/transform/universalCsn/.eslintrc.json +2 -2
  113. package/lib/transform/universalCsn/coreComputed.js +11 -6
  114. package/lib/transform/universalCsn/universalCsnEnricher.js +33 -5
  115. package/lib/utils/file.js +31 -21
  116. package/lib/utils/moduleResolve.js +0 -1
  117. package/lib/utils/timetrace.js +20 -21
  118. package/package.json +34 -4
  119. package/share/messages/syntax-expected-integer.md +9 -8
  120. package/doc/ApiMigration.md +0 -237
  121. package/doc/CommandLineMigration.md +0 -58
  122. package/doc/ErrorMessages.md +0 -175
  123. package/doc/FioriAnnotations.md +0 -94
  124. package/doc/ODataTransformation.md +0 -273
  125. package/lib/backends.js +0 -529
  126. package/lib/checks/unknownMagic.js +0 -41
  127. package/lib/fix_antlr4-8_warning.js +0 -56
@@ -49,13 +49,13 @@ const { dictAdd } = require('../base/dictionaries');
49
49
  const { dictLocation } = require('../base/location');
50
50
  const { searchName, weakLocation } = require('../base/messages');
51
51
  const { combinedLocation } = require('../base/location');
52
- const { forEachValue } = require('../utils/objectUtils');
53
52
  const { typeParameters } = require('./builtins');
54
53
 
55
54
  const { kindProperties } = require('./base');
56
55
  const {
57
56
  setLink,
58
57
  setArtifactLink,
58
+ annotationHasEllipsis,
59
59
  pathName,
60
60
  linkToOrigin,
61
61
  setMemberParent,
@@ -73,9 +73,6 @@ const layers = require('./moduleLayers');
73
73
 
74
74
  const $location = Symbol.for('cds.$location');
75
75
 
76
- const annotationPriorities = {
77
- define: 1, extend: 2, annotate: 2, edmx: 3,
78
- };
79
76
  const $inferred = Symbol.for('cds.$inferred');
80
77
 
81
78
  // Export function of this file. Resolve type references in augmented CSN
@@ -90,6 +87,7 @@ function resolve( model ) {
90
87
  } = model.$messageFunctions;
91
88
  const {
92
89
  resolvePath,
90
+ checkAnnotate,
93
91
  defineAnnotations,
94
92
  attachAndEmitValidNames,
95
93
  lateExtensions,
@@ -106,11 +104,6 @@ function resolve( model ) {
106
104
 
107
105
  /** @type {any} may also be a boolean */
108
106
 
109
- // behavior depending on option `deprecated`:
110
- const enableExpandElements = !isDeprecatedEnabled( options, 'noElementsExpansion' );
111
- // TODO: we should get rid of noElementsExpansion soon; both
112
- // beta.nestedProjections and beta.universalCsn do not work with it.
113
-
114
107
  return doResolve();
115
108
 
116
109
  function doResolve() {
@@ -211,9 +204,9 @@ function resolve( model ) {
211
204
  info( 'query-from-many', [ toMany.location, query ], { art: toMany },
212
205
  {
213
206
  // eslint-disable-next-line max-len
214
- std: 'Selecting from to-many association $(ART) - key properties are not propagated',
207
+ std: 'Key properties are not propagated because a to-many association $(ART) is selected',
215
208
  // eslint-disable-next-line max-len
216
- element: 'Selecting from to-many association $(MEMBER) of $(ART) - key properties are not propagated',
209
+ element: 'Key properties are not propagated because a to-many association $(MEMBER) of $(ART) is selected',
217
210
  } );
218
211
  }
219
212
  // Check that all keys from the source are projected:
@@ -317,7 +310,7 @@ function resolve( model ) {
317
310
  if (obj.type) // TODO: && !obj.type.$inferred ?
318
311
  resolveTypeExpr( obj, art );
319
312
  const type = effectiveType( obj ); // make sure implicitly redirected target exists
320
- if (!obj.items && type && type.items && enableExpandElements) {
313
+ if (!obj.items && type && type.items) {
321
314
  // TODO: shouldn't be this part of populate.js ?
322
315
  const items = {
323
316
  location: weakLocation( (obj.type || obj).location ),
@@ -330,8 +323,7 @@ function resolve( model ) {
330
323
  }
331
324
  if (obj.items) { // TODO: make this a while in v2 (also items proxy)
332
325
  obj = obj.items || obj; // the object which has type properties
333
- if (enableExpandElements)
334
- effectiveType(obj);
326
+ effectiveType(obj);
335
327
  }
336
328
  if (obj.type) { // TODO: && !obj.type.$inferred ?
337
329
  if (obj !== (art.returns || art)) // not already checked
@@ -484,10 +476,7 @@ function resolve( model ) {
484
476
  if (ext.$extension) // extension for known artifact -> already applied
485
477
  return;
486
478
  annotateMembers( ext );
487
- for (const prop in ext) {
488
- if (prop.charAt(0) === '@')
489
- chooseAssignment( prop, ext );
490
- }
479
+ chooseAnnotationsInArtifact( ext );
491
480
  }
492
481
 
493
482
  /**
@@ -522,6 +511,8 @@ function resolve( model ) {
522
511
  setArtifactLink( ext.name, art );
523
512
 
524
513
  if (art) {
514
+ if (art.kind === 'annotate')
515
+ checkAnnotate( ext, art );
525
516
  defineAnnotations( ext, art, ext._block, ext.kind );
526
517
  // eslint-disable-next-line no-shadow
527
518
  forEachMember( ext, ( elem, name, prop ) => {
@@ -544,7 +535,7 @@ function resolve( model ) {
544
535
  }
545
536
  else if (prop === 'actions') {
546
537
  if (!feature) {
547
- warning( 'anno-unexpected-actions', [ ext.name.location, art ], {},
538
+ warning( 'anno-unexpected-actions', [ ext.name.location, art._parent || art ], {},
548
539
  'Actions and functions only exist top-level and for entities' );
549
540
  }
550
541
  else {
@@ -575,7 +566,7 @@ function resolve( model ) {
575
566
  // Currently(?), effectiveType() does not calculate the effective type of
576
567
  // its line item:
577
568
  effectiveType( obj );
578
- if (art._annotate.elements)
569
+ if (art._annotate.elements) // explicit $expand on aor needed
579
570
  setExpandStatusAnnotate( aor, 'annotate' );
580
571
  annotate( obj, 'element', 'elements', 'enum', art );
581
572
  annotate( art, 'action', 'actions' );
@@ -599,6 +590,8 @@ function resolve( model ) {
599
590
  // eslint-disable-next-line no-shadow
600
591
  function annotate( obj, kind, prop, altProp, parent = obj ) {
601
592
  const dict = art._annotate[prop];
593
+ if (dict && art._annotate[prop])
594
+ setExpandStatusAnnotate( art, 'annotate' );
602
595
  const env = obj[prop] || altProp && obj[altProp] || null;
603
596
  for (const n in dict)
604
597
  annotateMembers( env && env[n], dict[n], prop, n, parent, kind );
@@ -621,7 +614,7 @@ function resolve( model ) {
621
614
 
622
615
  function expandParameters( action ) {
623
616
  // see also expandElements()
624
- if (!enableExpandElements || !effectiveType( action ))
617
+ if (!effectiveType( action ))
625
618
  return;
626
619
  const chain = [];
627
620
  // Should we be able to consider params and returns separately?
@@ -714,241 +707,219 @@ function resolve( model ) {
714
707
  }
715
708
 
716
709
  function chooseAssignment( annoName, art ) {
717
- // TODO: getPath an all names
718
- const anno = art[annoName];
719
- if (!Array.isArray(anno)) { // just one assignment -> use it
720
- if (removeEllipsis( anno )) {
721
- error( 'anno-unexpected-ellipsis',
722
- [ anno.name.location, art ], { code: '...' } );
710
+ let anno = art[annoName];
711
+ if (!Array.isArray( anno )) { // just one assignment -> use it
712
+ if (!annotationHasEllipsis( anno ))
713
+ return;
714
+ anno = [ anno ];
715
+ }
716
+ // console.log('ASSIGN:',art.name.absolute,annoName)
717
+ const scheduledAssignments = [];
718
+ // sort assignment according to layer (define is bottom layer):
719
+ const layeredAnnos = layeredAssignments( anno );
720
+ let cont = true;
721
+ while (cont) {
722
+ const { assignments, issue } = assignmentsOfHighestLayers( layeredAnnos );
723
+ let index = assignments.length;
724
+ cont = !!index; // safety
725
+ while (--index >= 0) {
726
+ const a = assignments[index];
727
+ scheduledAssignments.push( a );
728
+ if (!annotationHasEllipsis( a )) {
729
+ cont = false;
730
+ break;
731
+ }
723
732
  }
724
- return;
725
- }
726
- // sort assignment according to layer
727
- const layerAnnos = Object.create(null);
728
- for (const a of anno) {
729
- const layer = layers.layer( a._block );
733
+ if (issue) {
734
+ // eslint-disable-next-line no-nested-ternary
735
+ const msg = (issue === true)
736
+ ? 'anno-duplicate'
737
+ : (index >= 0) ? 'anno-duplicate-unrelated-layer' : 'anno-unstable-array';
738
+ for (const a of assignments) {
739
+ if (!a.$errorReported)
740
+ message( msg, [ a.name.location, art ], { anno: annoName } );
741
+ }
742
+ }
743
+ // else if (index > 0) -- if we allow multiple assignments in one file - the last wins
744
+ }
745
+ // Now apply the assignments - all but the first have a '...'
746
+ let result = null;
747
+ scheduledAssignments.reverse();
748
+ for (const a of scheduledAssignments)
749
+ result = applyAssignment( result, a, art, annoName );
750
+ art[annoName] = result.name ? result
751
+ : Object.assign( {}, scheduledAssignments[scheduledAssignments.length - 1], result );
752
+ }
753
+
754
+ // Group assignments by their layers. An assignment provided with a definition
755
+ // is considered to be provided in a layer named '', the lowest layer.
756
+ // TODO: make this usable for extend (elements), too =
757
+ // do not use $priority, make assignments on define do not have own _block
758
+ function layeredAssignments( assignment ) {
759
+ const layered = Object.create(null);
760
+ for (const a of assignment) {
761
+ const layer = a.$priority && layers.layer( a );
762
+ // just consider layer if Extend/Annotate, not Define
730
763
  const name = (layer) ? layer.realname : '';
731
- const done = layerAnnos[name];
764
+ const done = layered[name];
732
765
  if (done)
733
- done.annos.push( a );
766
+ done.assignments.push( a );
734
767
  else
735
- layerAnnos[name] = { layer, annos: [ a ] };
768
+ layered[name] = { name, layer, assignments: [ a ] };
769
+ // TODO: file - if set: unique in layer
736
770
  }
737
- mergeArrayInSCCs();
738
- art[annoName] = mergeLayeredArrays( findLayerCandidate( ) );
739
- return;
771
+ return layered;
772
+ }
740
773
 
741
- // Merge annotations in each layer, i.e. multiple annotations in the same layer are
742
- // stored in an array and need to be merged before different layers can be merged.
743
- function mergeArrayInSCCs( ) {
744
- let pos = 0;
745
- forEachValue(layerAnnos, (layer) => {
746
- const mergeSource = layer.annos.find(v => (v.$priority === undefined ||
747
- annotationPriorities[v.$priority] === annotationPriorities.define));
748
- if (mergeSource) {
749
- // If the source annotation (at 'define' level) contains an ellipsis,
750
- // there is no base to apply to.
751
- if (removeEllipsis( mergeSource )) {
752
- error( 'anno-unexpected-ellipsis',
753
- [ mergeSource.name.location, art ], { code: '...' } );
754
- }
755
- // merge source into ellipsis array annotates
756
- layer.annos.forEach( (mergeTarget) => {
757
- if (mergeTarget.$priority &&
758
- annotationPriorities[mergeTarget.$priority] > annotationPriorities.define) {
759
- pos = findEllipsis( mergeTarget );
760
- if (pos > -1) {
761
- if (mergeSource.literal !== 'array') {
762
- error( 'anno-mismatched-ellipsis',
763
- [ mergeSource.name.location, art ], { code: '...' } );
764
- return;
765
- }
766
- mergeTarget.val = mergeArrayValues( mergeSource.val, mergeTarget.val );
767
- }
768
- }
769
- });
770
- }
771
- });
772
- }
773
-
774
- function mergeLayeredArrays( mergeTarget ) {
775
- if (mergeTarget.literal === 'array') {
776
- let layer = layers.layer( mergeTarget._block );
777
- delete layerAnnos[(layer) ? layer.realname : ''];
778
- let pos = findEllipsis( mergeTarget );
779
- let hasRun = false;
780
- while (pos > -1 && Object.keys( layerAnnos ).length ) {
781
- hasRun = true;
782
- const mergeSource = findLayerCandidate();
783
- if (mergeSource.literal !== 'array') {
784
- error( 'anno-mismatched-ellipsis',
785
- [ mergeSource.name.location, art ], { code: '...' } );
786
- return mergeTarget;
787
- }
788
- mergeTarget.val = mergeArrayValues( mergeSource.val, mergeTarget.val );
789
- layer = layers.layer( mergeSource._block );
790
- delete layerAnnos[(layer) ? layer.realname : ''];
791
- pos = findEllipsis( mergeTarget );
792
- }
793
- // All layers were processed. Remove excess ellipsis.
794
- if (removeEllipsis( mergeTarget, pos ) && hasRun) {
795
- // There shouldn't be any ellipsis or we don't have a base annotation.
796
- // But only if the loop above has run. Otherwise the in-layer merge
797
- // already warned about this case.
798
- message( 'anno-unexpected-ellipsis-layers',
799
- [ mergeTarget.name.location, art ], { code: '...' } );
800
- }
774
+ // Return assignments of the highest layers.
775
+ // Also return whether there could be an issue:
776
+ // - false: there is just one assignment
777
+ // - 'unrelated': there is just one assignment per layer
778
+ // - true: there is at least one layer with two or more assignments
779
+ // TODO: make this usable for extend (elements), too
780
+ function assignmentsOfHighestLayers( layeredAnnos ) {
781
+ const layerNames = Object.keys( layeredAnnos );
782
+ // console.log('HIB:',layerNames)
783
+ if (layerNames.length <= 1) {
784
+ const name = layerNames[0];
785
+ const { assignments } = layeredAnnos[name] || { assignments: [] };
786
+ delete layeredAnnos[name];
787
+ return { assignments, issue: assignments.length > 1 };
788
+ }
789
+
790
+ // collect all layers which are lower than another layer
791
+ const allExtends = Object.create(null);
792
+ allExtends[''] = {}; // the "Define" layer
793
+ for (const name of layerNames) {
794
+ if (name) // not the "Define" layer
795
+ Object.assign( allExtends, layeredAnnos[name].layer._layerExtends );
796
+ }
797
+ // console.log('HIE:',Object.keys(allExtends))
798
+ const assignments = [];
799
+ const highest = [];
800
+ for (const name of layerNames) {
801
+ if (!(name in allExtends)) {
802
+ const layer = layeredAnnos[name];
803
+ delete layeredAnnos[name];
804
+ highest.push( layer );
805
+ assignments.push( ...layer.assignments );
801
806
  }
802
- return mergeTarget;
803
807
  }
808
+ assignments.sort( compareAssignments );
809
+ const good = highest.every( layer => layer.assignments.length === 1 );
810
+ // TODO: use layer.file instead
811
+ const issue = !good || highest.length > 1 && 'unrelated';
812
+ // console.log('HI:',highest.map(l=>l.name),issue,issue&&assignments)
813
+ return { assignments, issue };
814
+ }
804
815
 
805
- function mergeArrayValues( previousValue, arraySpec ) {
806
- let prevPos = 0;
807
- const result = [];
808
- for (const item of arraySpec) {
809
- const ell = item && item.literal === 'token' && item.val === '...';
810
- if (!ell) {
811
- result.push( item );
812
- }
813
- else {
814
- let upToSpec = item.upTo && checkUpToSpec( item.upTo, true );
815
- while (prevPos < previousValue.length) {
816
- const prevItem = previousValue[prevPos++];
817
- result.push( prevItem );
818
- if (upToSpec && prevItem && equalUpTo( prevItem, item.upTo)) {
819
- upToSpec = false;
820
- break;
821
- }
822
- }
823
- if (upToSpec) { // non-matched UP TO
824
- warning( null, [ item.upTo.location, art ], { anno: annoName, code: '... up to' },
825
- 'The $(CODE) value does not match any item in the base annotation $(ANNO)' );
816
+ function compareAssignments( a, b ) {
817
+ const fileA = layers.realname( a._block );
818
+ const fileB = layers.realname( b._block );
819
+ if (fileA !== fileB)
820
+ return (fileA > fileB) ? 1 : -1;
821
+ return (a?.location?.line || 0) - (b?.location?.line || 0) ||
822
+ (a?.location?.col || 0) - (b?.location?.col || 0);
823
+ }
824
+
825
+ function applyAssignment( previousAnno, anno, art, annoName ) {
826
+ if (!previousAnno) {
827
+ if (!annotationHasEllipsis( anno ))
828
+ return anno;
829
+ if (anno.$priority) { // already complained about with Define
830
+ message( 'anno-unexpected-ellipsis-layers', // TODO: better location
831
+ [ anno.name.location, art ], { code: '...' } );
832
+ }
833
+ previousAnno = { val: [] };
834
+ }
835
+ else if (previousAnno.literal !== 'array') {
836
+ error( 'anno-mismatched-ellipsis', // TODO: better location
837
+ [ anno.name.location, art ], { code: '...' } );
838
+ previousAnno = { val: [] };
839
+ }
840
+ const previousValue = previousAnno.val;
841
+ let prevPos = 0;
842
+ const result = [];
843
+ for (const item of anno.val) {
844
+ const ell = item && item.literal === 'token' && item.val === '...';
845
+ if (!ell) {
846
+ result.push( item );
847
+ }
848
+ else {
849
+ let upToSpec = item.upTo && checkUpToSpec( item.upTo, art, annoName, true );
850
+ while (prevPos < previousValue.length) {
851
+ const prevItem = previousValue[prevPos++];
852
+ result.push( prevItem );
853
+ if (upToSpec && prevItem && equalUpTo( prevItem, item.upTo)) {
854
+ upToSpec = false;
855
+ break;
826
856
  }
827
857
  }
858
+ if (upToSpec) { // non-matched UP TO
859
+ warning( null, [ item.upTo.location, art ], { anno: annoName, code: '... up to' },
860
+ 'The $(CODE) value does not match any item in the base annotation $(ANNO)' );
861
+ }
828
862
  }
829
- return result;
830
863
  }
864
+ // console.log('TP:',previousValue.map(se),anno.val.map(se),'->',result.map(se))
865
+ return { val: result, literal: 'array' };
866
+ }
867
+ // function se(a) { return a.upTo ? [a.val,a.upTo.val] : a.val ; }
831
868
 
832
- function checkUpToSpec( upToSpec, trueIfFullUpTo ) {
833
- const { literal } = upToSpec;
834
- if (trueIfFullUpTo !== true) { // inside struct of UP TO
835
- if (literal !== 'struct' && literal !== 'array' )
836
- return true;
837
- }
838
- else if (literal === 'struct') {
839
- return Object.values( upToSpec.struct ).every( checkUpToSpec );
840
- }
841
- else if (literal !== 'array' && literal !== 'boolean' && literal !== 'null') {
869
+ function checkUpToSpec( upToSpec, art, annoName, isFullUpTo ) {
870
+ const { literal } = upToSpec;
871
+ if (!isFullUpTo) { // inside struct of UP TO
872
+ if (literal !== 'struct' && literal !== 'array' )
842
873
  return true;
843
- }
844
- error( null, [ upToSpec.location, art ],
845
- { anno: annoName, code: '... up to', '#': literal },
846
- {
847
- std: 'Unexpected $(CODE) value type in the assignment of $(ANNO)',
848
- array: 'Unexpected array as $(CODE) value in the assignment of $(ANNO)',
849
- // eslint-disable-next-line max-len
850
- struct: 'Unexpected structure as $(CODE) structure property value in the assignment of $(ANNO)',
851
- boolean: 'Unexpected boolean as $(CODE) value in the assignment of $(ANNO)',
852
- null: 'Unexpected null as $(CODE) value in the assignment of $(ANNO)',
853
- } );
854
- return false;
855
874
  }
875
+ else if (literal === 'struct') {
876
+ return Object.values( upToSpec.struct ).every( v => checkUpToSpec( v, art, annoName ) );
877
+ }
878
+ else if (literal !== 'array' && literal !== 'boolean' && literal !== 'null') {
879
+ return true;
880
+ }
881
+ error( null, [ upToSpec.location, art ],
882
+ { anno: annoName, code: '... up to', '#': literal },
883
+ {
884
+ std: 'Unexpected $(CODE) value type in the assignment of $(ANNO)',
885
+ array: 'Unexpected array as $(CODE) value in the assignment of $(ANNO)',
886
+ // eslint-disable-next-line max-len
887
+ struct: 'Unexpected structure as $(CODE) structure property value in the assignment of $(ANNO)',
888
+ boolean: 'Unexpected boolean as $(CODE) value in the assignment of $(ANNO)',
889
+ null: 'Unexpected null as $(CODE) value in the assignment of $(ANNO)',
890
+ } );
891
+ return false;
892
+ }
856
893
 
857
- function equalUpTo( previousItem, upToSpec ) {
858
- if (!previousItem)
859
- return false;
860
- if ('val' in upToSpec) {
861
- if (previousItem.val === upToSpec.val) // enum, struct and ref have no val
862
- return true;
863
- const typeUpTo = typeof upToSpec.val;
864
- const typePrev = typeof previousItem.val;
865
- if (typeUpTo === 'number')
866
- return typePrev === 'string' && previousItem.val === upToSpec.val.toString();
867
- if (typePrev === 'number')
868
- return typeUpTo === 'string' && upToSpec.val === previousItem.val.toString();
869
- }
870
- else if (upToSpec.path) {
871
- return previousItem.path && normalizeRef( previousItem ) === normalizeRef( upToSpec );
872
- }
873
- else if (upToSpec.sym) {
874
- return previousItem.sym && previousItem.sym.id === upToSpec.sym.id;
875
- }
876
- else if (upToSpec.struct && previousItem.struct) {
877
- return Object.entries( upToSpec.struct )
878
- .every( ([ n, v ]) => equalUpTo( previousItem.struct[n], v ) );
879
- }
894
+ function equalUpTo( previousItem, upToSpec ) {
895
+ if (!previousItem)
880
896
  return false;
897
+ if ('val' in upToSpec) {
898
+ if (previousItem.val === upToSpec.val) // enum, struct and ref have no val
899
+ return true;
900
+ const typeUpTo = typeof upToSpec.val;
901
+ const typePrev = typeof previousItem.val;
902
+ if (typeUpTo === 'number')
903
+ return typePrev === 'string' && previousItem.val === upToSpec.val.toString();
904
+ if (typePrev === 'number')
905
+ return typeUpTo === 'string' && upToSpec.val === previousItem.val.toString();
881
906
  }
882
-
883
- function normalizeRef( node ) { // see to-csn.js
884
- const ref = pathName( node.path );
885
- return node.variant ? `${ ref }#${ node.variant.id }` : ref;
886
- }
887
-
888
- function removeEllipsis(a, pos = findEllipsis( a )) {
889
- let count = 0;
890
- while (a.literal === 'array' && pos > -1) {
891
- count++;
892
- a.val.splice(pos, 1);
893
- pos = findEllipsis( a );
894
- }
895
- return count;
896
- }
897
-
898
- function findEllipsis(a) {
899
- return (a.literal === 'array' && a.val)
900
- ? a.val.findIndex(v => v.literal === 'token' && v.val === '...') : -1;
907
+ else if (upToSpec.path) {
908
+ return previousItem.path && normalizeRef( previousItem ) === normalizeRef( upToSpec );
901
909
  }
902
-
903
- function findLayerCandidate() {
904
- // collect assignments of upper layers (are in no _layerExtends)
905
- const exts = Object.keys( layerAnnos ).map( layerExtends );
906
- const allExtends = Object.assign( Object.create(null), ...exts );
907
- const collected = [];
908
- for (const name in layerAnnos) {
909
- if (!(name in allExtends))
910
- collected.push( prioritizedAnnos( layerAnnos[name].annos ) );
911
- }
912
- // inspect collected assignments - choose the one or signal error
913
- const justOnePerLayer = collected.every( annos => annos.length === 1);
914
- if (!justOnePerLayer || collected.length > 1) {
915
- for (const annos of collected) {
916
- for (const a of annos ) {
917
- // Only the message ID is different.
918
- if (justOnePerLayer) {
919
- message( 'anno-duplicate-unrelated-layer',
920
- [ a.name.location, art ], { anno: annoName },
921
- 'Duplicate assignment with $(ANNO)' );
922
- }
923
- else {
924
- message( 'anno-duplicate', [ a.name.location, art ], { anno: annoName } );
925
- }
926
- }
927
- }
928
- }
929
- return collected[0][0]; // just choose any one with error
910
+ else if (upToSpec.sym) {
911
+ return previousItem.sym && previousItem.sym.id === upToSpec.sym.id;
930
912
  }
931
-
932
- function layerExtends( name ) {
933
- const { layer } = layerAnnos[name];
934
- return layer && layer._layerExtends;
913
+ else if (upToSpec.struct && previousItem.struct) {
914
+ return Object.entries( upToSpec.struct )
915
+ .every( ([ n, v ]) => equalUpTo( previousItem.struct[n], v ) );
935
916
  }
917
+ return false;
936
918
  }
937
919
 
938
- function prioritizedAnnos( annos ) {
939
- let prio = 0;
940
- let r = [];
941
- for (const a of annos) {
942
- const p = annotationPriorities[a.$priority] || annotationPriorities.define;
943
- if (p === prio) {
944
- r.push(a);
945
- }
946
- else if (p > prio) {
947
- r = [ a ];
948
- prio = p;
949
- }
950
- }
951
- return r;
920
+ function normalizeRef( node ) { // see to-csn.js
921
+ const ref = pathName( node.path );
922
+ return node.variant ? `${ ref }#${ node.variant.id }` : ref;
952
923
  }
953
924
 
954
925
  // Phase 4 - queries and associations --------------------------------------
@@ -984,7 +955,7 @@ function resolve( model ) {
984
955
  resolveBy( query.$orderBy, 'order-by-union', query.elements, query._parent );
985
956
  if (query.orderBy) { // ORDER BY
986
957
  // search in `query.elements` after having checked table aliases of the current query
987
- resolveBy( query.orderBy, 'expr', query.elements );
958
+ resolveBy( query.orderBy, 'order-by', query.elements );
988
959
  // TODO: disallow resulting element ref if in expression!
989
960
  // Necessary to check it in the compiler as it might work with other semantics on DB!
990
961
  // (we could downgrade it to a warning if name is equal to unique source element name)
@@ -1292,7 +1263,7 @@ function resolve( model ) {
1292
1263
  const typeArt = resolveType( art.type, user );
1293
1264
  if (typeArt) {
1294
1265
  resolveTypeArgumentsUnchecked( art, typeArt, user );
1295
- checkTypeArguments( art );
1266
+ checkTypeArguments( art, typeArt );
1296
1267
  }
1297
1268
  }
1298
1269
 
@@ -1300,13 +1271,13 @@ function resolve( model ) {
1300
1271
  * Check the type arguments on `artWithType`.
1301
1272
  * If the effective type is an array or structured type, an error is emitted.
1302
1273
  */
1303
- function checkTypeArguments( artWithType ) {
1274
+ function checkTypeArguments( artWithType, typeArt ) {
1304
1275
  // Note: `_effectiveType` may point to `artWithType` itself, if the type is structured.
1305
1276
  // Also: For enums, it points to the enum type, which is why this trick is needed.
1306
1277
  // TODO(#8942): May not be necessary if effectiveType() is adapted. Furthermore, the enum
1307
1278
  // trick may be removed if effectiveType() does not stop at enums.
1308
1279
  const cyclic = new Set();
1309
- let effectiveTypeArt = effectiveType( artWithType );
1280
+ let effectiveTypeArt = effectiveType( typeArt );
1310
1281
  while (effectiveTypeArt && effectiveTypeArt.enum && !cyclic.has(effectiveTypeArt)) {
1311
1282
  cyclic.add(effectiveTypeArt);
1312
1283
  const underlyingEnumType = directType(effectiveTypeArt);