@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
@@ -8,31 +8,17 @@ function validateOptions(_options)
8
8
  {
9
9
  if(!_options.isV2 && !_options.isV4)
10
10
  {
11
- // csn2edm expects "version" to be a top-level property of options
11
+ // csn2edm expects "odataVersion" to be a top-level property of options
12
12
  // set to 'v4' as default, override with value from incoming options
13
- // (here version comes inside "toOdata")
14
- const options = Object.assign({ version: 'v4'}, _options);
15
- if (options.toOdata) {
16
- if(options.toOdata.version)
17
- options.version = options.toOdata.version;
18
- if(options.toOdata.odataFormat)
19
- options.odataFormat = options.toOdata.odataFormat;
20
- if(options.toOdata.odataContainment)
21
- options.odataContainment = options.toOdata.odataContainment;
22
- if(options.toOdata.odataForeignKeys)
23
- options.odataForeignKeys = options.toOdata.odataForeignKeys;
24
- if(options.toOdata.odataV2PartialConstr)
25
- options.odataV2PartialConstr = options.toOdata.odataV2PartialConstr;
26
- // global flag that indicates whether or not FKs shall be rendered in general
27
- // V2/V4 flat: yes
28
- // V4/struct: depending on odataForeignKeys
29
- options.renderForeignKeys =
30
- options.version === 'v4' ? options.odataFormat === 'structured' && !!options.odataForeignKeys : true;
13
+ const options = Object.assign({ odataVersion: 'v4'}, _options);
14
+ // global flag that indicates whether or not FKs shall be rendered in general
15
+ // V2/V4 flat: yes
16
+ // V4/struct: depending on odataForeignKeys
17
+ options.renderForeignKeys =
18
+ options.odataVersion === 'v4' ? options.odataFormat === 'structured' && !!options.odataForeignKeys : true;
31
19
 
32
- }
33
-
34
- const v2 = options.version.match(/v2/i) !== null;
35
- const v4 = options.version.match(/v4/i) !== null;
20
+ const v2 = options.odataVersion.match(/v2/i) !== null;
21
+ const v4 = options.odataVersion.match(/v4/i) !== null;
36
22
 
37
23
  options.v = [v2, v4];
38
24
  options.isStructFormat = options.odataFormat && options.odataFormat === 'structured';
@@ -41,8 +27,8 @@ function validateOptions(_options)
41
27
  if(options.v.filter(v=>v).length !== 1)
42
28
  throw Error(`Please debug me: EDM V2:${v2}, V4:${v4}`);
43
29
 
44
- options.isV2 = function() { return this.v[0]; }
45
- options.isV4 = function() { return this.v[1]; }
30
+ options.isV2 = () => v2;
31
+ options.isV4 = () => v4;
46
32
 
47
33
  options.pathDelimiter = options.isStructFormat ? '/' : '_';
48
34
 
@@ -70,22 +56,11 @@ function foreach(dictionary, filter, func) {
70
56
  });
71
57
  }
72
58
 
73
- // Call func(art, name) for each artifact 'art' with name 'name' in 'dictionary'
74
- function forAll(dictionary, func) {
75
- foreach(dictionary, ()=>true, func);
76
- }
77
-
78
59
  // true if _containerEntity is unequal to artifact name (non-recursive containment association)
79
60
  // or if artifact belongs to an artificial parameter entity
80
61
  function isContainee(artifact) {
81
- // if _containerEntity is present, it is guaranteed that it has at least one entry
82
- return (artifact._containerEntity && (artifact._containerEntity.length > 1 || artifact._containerEntity[0] != artifact.name));
83
- }
84
-
85
- // Return true if 'artifact' has an association type
86
- function isAssociation(artifact) {
87
- return (artifact.type === 'cds.Association' || artifact.type === 'Association') && artifact.target != undefined;
88
- //return artifact.target != undefined;
62
+ // if $containerNames is present, it is guaranteed that it has at least one entry
63
+ return (artifact.$containerNames && (artifact.$containerNames.length > 1 || artifact.$containerNames[0] != artifact.name));
89
64
  }
90
65
 
91
66
  function isComposition(artifact) {
@@ -93,16 +68,6 @@ function isComposition(artifact) {
93
68
  artifact.target != undefined;
94
69
  }
95
70
 
96
- function isAssociationOrComposition(artifact)
97
- {
98
- return isAssociation(artifact) || isComposition(artifact);
99
- }
100
-
101
- function isManagedAssociation(artifact)
102
- {
103
- return isAssociation(artifact) && artifact.on == undefined;
104
- }
105
-
106
71
  // Return true if the association 'assoc' has cardinality 'to-many'
107
72
  function isToMany(assoc) {
108
73
  if (!assoc.cardinality) {
@@ -122,13 +87,8 @@ function isSingleton(entityCsn) {
122
87
  return singleton || ((singleton === undefined || singleton === null) && hasNullable);
123
88
  }
124
89
 
125
- function isEntity(artifact)
126
- {
127
- return artifact.kind === 'entity';
128
- }
129
-
130
90
  function isParameterizedEntity(artifact) {
131
- return isEntity(artifact) && artifact.params;
91
+ return artifact.kind === 'entity' && artifact.params;
132
92
  }
133
93
 
134
94
  // Return true if 'artifact' is structured (i.e. has elements, like a structured type or an entity)
@@ -146,10 +106,6 @@ function isDerivedType(artifact) {
146
106
  return artifact.kind === 'type' && !isStructuredArtifact(artifact);
147
107
  }
148
108
 
149
- function isActionOrFunction(artifact) {
150
- return artifact.kind === 'action' || artifact.kind === 'function';
151
- }
152
-
153
109
  function resolveOnConditionAndPrepareConstraints(csn, assocCsn, messageFunctions) {
154
110
  if(!assocCsn._constraints)
155
111
  throw Error('Please debug me: need _constraints');
@@ -189,7 +145,7 @@ function resolveOnConditionAndPrepareConstraints(csn, assocCsn, messageFunctions
189
145
  info(null, ['definitions', parentName, 'elements', assocCsn.name],
190
146
  `"${originParentName}:${partnerPath.join('.')}" with target "${originAssocCsn._target.name}" is compared with $self which represents "${parentName}"`);
191
147
  }
192
- if(isAssociationOrComposition(originAssocCsn)) {
148
+ if(originAssocCsn.target) {
193
149
  // Mark this association as backlink if $self appears exactly once
194
150
  // to surpress edm:Association generation in V2 mode
195
151
  if(isBacklink) {
@@ -359,7 +315,7 @@ function finalizeReferentialConstraints(csn, assocCsn, options, info)
359
315
  // in structured mode only resolve top level element (path rewriting is done elsewhere)
360
316
  const depEltName = ( options.isFlatFormat ? c[0].join('_') : c[0][0] );
361
317
  const principalEltName = ( options.isFlatFormat ? c[1].join('_') : c[1][0] );
362
- const fk = (isEntity(dependentEntity) && dependentEntity.elements[ depEltName ]) ||
318
+ const fk = (dependentEntity.kind === 'entity' && dependentEntity.elements[ depEltName ]) ||
363
319
  (localDepEntity && localDepEntity.elements && localDepEntity.elements[ depEltName ]);
364
320
  const pk = principalEntity.$keys && principalEntity.$keys[ principalEltName ];
365
321
  if(isConstraintCandidate(fk) && isConstraintCandidate(pk)) {
@@ -797,24 +753,97 @@ function resolveOriginAssoc(csn, env, path) {
797
753
  return env;
798
754
  }
799
755
 
756
+ function mergeIntoNavPropRestrictions(annoPrefix, assocPath, props, navPropRestrictions) {
757
+ let navPropEntry;
758
+ let hasEntry = false;
759
+ let newEntry = false;
760
+ hasEntry = !!(navPropEntry = navPropRestrictions.find(p =>
761
+ p.NavigationProperty && p.NavigationProperty['='] === assocPath));
762
+
763
+ if(!hasEntry) {
764
+ navPropEntry = { NavigationProperty: { '=': assocPath } };
765
+ }
766
+
767
+ const prop = annoPrefix.split('.')[1];
768
+ // Filter properties with prefix and reduce them into a new dictionary
769
+ const o = props.filter(p => p[0].startsWith(annoPrefix+'.')).reduce((a,c) => {
770
+ a[c[0].replace(annoPrefix+'.', '')] = c[1];
771
+ return a;
772
+ }, { });
773
+ // don't overwrite existing restrictions
774
+ if(!navPropEntry[prop]) {
775
+ // if dictionary has entries, add them to navPropEnty
776
+ if(Object.keys(o).length) {
777
+ // ReadRestrictions may have sub type ReadByKeyRestrictions { Description, LongDescription }
778
+ // chop annotations into dictionaries
779
+ if(annoPrefix === '@Capabilities.ReadRestrictions' &&
780
+ Object.keys(o).some(k => k.startsWith('ReadByKeyRestrictions.'))) {
781
+ const no = {};
782
+ Object.entries(o).forEach(([k,v]) => {
783
+ const [head, ...tail] = k.split('.');
784
+ if(head === 'ReadByKeyRestrictions' && tail.length) {
785
+ if(!no['ReadByKeyRestrictions'])
786
+ no['ReadByKeyRestrictions'] = {};
787
+ // Don't try to add entry into non object
788
+ if(typeof no['ReadByKeyRestrictions'] === 'object')
789
+ no['ReadByKeyRestrictions'][tail.join('.')] = v;
790
+ }
791
+ else {
792
+ no[k] = v;
793
+ }
794
+ });
795
+ navPropEntry[prop] = no;
796
+ }
797
+ else {
798
+ navPropEntry[prop] = o;
799
+ }
800
+ newEntry = true;
801
+ }
802
+ }
803
+ else {
804
+ // merge but don't overwrite into existing navprop
805
+ Object.entries(o).forEach(([k,v]) => {
806
+ if(!navPropEntry[prop][k])
807
+ navPropEntry[prop][k] = v;
808
+ });
809
+ }
810
+ if(newEntry && !hasEntry) {
811
+ navPropRestrictions.push(navPropEntry);
812
+ }
813
+ }
814
+
815
+ // Assign but not overwrite annotation
816
+ function assignAnnotation(node, name, value) {
817
+ if(value !== undefined &&
818
+ name !== undefined && name[0] === '@' &&
819
+ (node[name] === undefined || node[name] === null)) {
820
+ node[name] = value;
821
+ }
822
+ }
823
+
824
+ // Set non enumerable property if it doesn't exist yet
825
+ function assignProp(obj, prop, value) {
826
+ if(obj[prop] === undefined) {
827
+ setProp(obj, prop, value);
828
+ }
829
+ }
830
+
831
+
832
+
800
833
  module.exports = {
834
+ assignAnnotation,
835
+ assignProp,
801
836
  validateOptions,
802
837
  intersect,
803
838
  foreach,
804
- forAll,
805
839
  isContainee,
806
- isAssociation,
807
- isManagedAssociation,
808
840
  isComposition,
809
- isAssociationOrComposition,
810
841
  isToMany,
811
842
  isSingleton,
812
- isEntity,
813
843
  isStructuredType,
814
844
  isStructuredArtifact,
815
845
  isParameterizedEntity,
816
846
  isDerivedType,
817
- isActionOrFunction,
818
847
  resolveOnConditionAndPrepareConstraints,
819
848
  finalizeReferentialConstraints,
820
849
  determineMultiplicity,
@@ -824,5 +853,6 @@ module.exports = {
824
853
  escapeStringForAttributeValue,
825
854
  escapeStringForText,
826
855
  getSchemaPrefix,
827
- getBaseName
856
+ getBaseName,
857
+ mergeIntoNavPropRestrictions
828
858
  }
@@ -989,8 +989,7 @@
989
989
  "NavigationProperty",
990
990
  "Action",
991
991
  "Function"
992
- ],
993
- "$experimental": true
992
+ ]
994
993
  },
995
994
  "Common.DerivedDefaultValue": {
996
995
  "Type": "Edm.String",
@@ -1424,6 +1423,13 @@
1424
1423
  "Type": "Graph.DetailsType",
1425
1424
  "$experimental": true
1426
1425
  },
1426
+ "Graph.CompositionRoot": {
1427
+ "Type": "Core.Tag",
1428
+ "AppliesTo": [
1429
+ "EntityType"
1430
+ ],
1431
+ "$experimental": true
1432
+ },
1427
1433
  "Hierarchy.RecursiveHierarchy": {
1428
1434
  "Type": "Hierarchy.RecursiveHierarchyType",
1429
1435
  "AppliesTo": [
@@ -2413,7 +2419,8 @@
2413
2419
  "CustomHeaders": "Collection(Capabilities.CustomParameter)",
2414
2420
  "CustomQueryOptions": "Collection(Capabilities.CustomParameter)",
2415
2421
  "Description": "Edm.String",
2416
- "LongDescription": "Edm.String"
2422
+ "LongDescription": "Edm.String",
2423
+ "ErrorResponses": "Collection(Capabilities.HttpResponse)"
2417
2424
  }
2418
2425
  },
2419
2426
  "Capabilities.PermissionType": {
@@ -2455,7 +2462,8 @@
2455
2462
  "CustomHeaders": "Collection(Capabilities.CustomParameter)",
2456
2463
  "CustomQueryOptions": "Collection(Capabilities.CustomParameter)",
2457
2464
  "Description": "Edm.String",
2458
- "LongDescription": "Edm.String"
2465
+ "LongDescription": "Edm.String",
2466
+ "ErrorResponses": "Collection(Capabilities.HttpResponse)"
2459
2467
  }
2460
2468
  },
2461
2469
  "Capabilities.DeepUpdateSupportType": {
@@ -2477,7 +2485,8 @@
2477
2485
  "CustomHeaders": "Collection(Capabilities.CustomParameter)",
2478
2486
  "CustomQueryOptions": "Collection(Capabilities.CustomParameter)",
2479
2487
  "Description": "Edm.String",
2480
- "LongDescription": "Edm.String"
2488
+ "LongDescription": "Edm.String",
2489
+ "ErrorResponses": "Collection(Capabilities.HttpResponse)"
2481
2490
  }
2482
2491
  },
2483
2492
  "Capabilities.CollectionPropertyRestrictionsType": {
@@ -2502,7 +2511,8 @@
2502
2511
  "FilterSegmentSupported": "Edm.Boolean",
2503
2512
  "Permissions": "Collection(Capabilities.PermissionType)",
2504
2513
  "CustomHeaders": "Collection(Capabilities.CustomParameter)",
2505
- "CustomQueryOptions": "Collection(Capabilities.CustomParameter)"
2514
+ "CustomQueryOptions": "Collection(Capabilities.CustomParameter)",
2515
+ "ErrorResponses": "Collection(Capabilities.HttpResponse)"
2506
2516
  }
2507
2517
  },
2508
2518
  "Capabilities.ModificationQueryOptionsType": {
@@ -2525,7 +2535,8 @@
2525
2535
  "CustomHeaders": "Collection(Capabilities.CustomParameter)",
2526
2536
  "CustomQueryOptions": "Collection(Capabilities.CustomParameter)",
2527
2537
  "Description": "Edm.String",
2528
- "LongDescription": "Edm.String"
2538
+ "LongDescription": "Edm.String",
2539
+ "ErrorResponses": "Collection(Capabilities.HttpResponse)"
2529
2540
  }
2530
2541
  },
2531
2542
  "Capabilities.ReadByKeyRestrictionsType": {
@@ -2537,7 +2548,8 @@
2537
2548
  "CustomHeaders": "Collection(Capabilities.CustomParameter)",
2538
2549
  "CustomQueryOptions": "Collection(Capabilities.CustomParameter)",
2539
2550
  "Description": "Edm.String",
2540
- "LongDescription": "Edm.String"
2551
+ "LongDescription": "Edm.String",
2552
+ "ErrorResponses": "Collection(Capabilities.HttpResponse)"
2541
2553
  }
2542
2554
  },
2543
2555
  "Capabilities.ReadRestrictionsType": {
@@ -2550,7 +2562,8 @@
2550
2562
  "CustomHeaders": "Collection(Capabilities.CustomParameter)",
2551
2563
  "CustomQueryOptions": "Collection(Capabilities.CustomParameter)",
2552
2564
  "Description": "Edm.String",
2553
- "LongDescription": "Edm.String"
2565
+ "LongDescription": "Edm.String",
2566
+ "ErrorResponses": "Collection(Capabilities.HttpResponse)"
2554
2567
  }
2555
2568
  },
2556
2569
  "Capabilities.CustomParameter": {
@@ -2563,6 +2576,13 @@
2563
2576
  "ExampleValues": "Collection(Core.PrimitiveExampleValue)"
2564
2577
  }
2565
2578
  },
2579
+ "Capabilities.HttpResponse": {
2580
+ "$kind": "ComplexType",
2581
+ "Properties": {
2582
+ "StatusCode": "Edm.String",
2583
+ "Description": "Edm.String"
2584
+ }
2585
+ },
2566
2586
  "Capabilities.FilterExpressionType": {
2567
2587
  "$kind": "TypeDefinition",
2568
2588
  "UnderlyingType": "Edm.String"
@@ -1 +1 @@
1
- 351a6ed427f91f2eef4d8e9a2e11dd17
1
+ 2067e213918678e2d85713a46e69d9cc