@sap/cds-compiler 2.11.4 → 2.12.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 (80) hide show
  1. package/CHANGELOG.md +58 -1
  2. package/bin/cds_update_identifiers.js +7 -7
  3. package/bin/cdsc.js +9 -10
  4. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  5. package/doc/CHANGELOG_BETA.md +12 -0
  6. package/lib/api/main.js +2 -0
  7. package/lib/api/options.js +2 -2
  8. package/lib/base/message-registry.js +31 -2
  9. package/lib/base/model.js +1 -0
  10. package/lib/base/optionProcessorHelper.js +97 -69
  11. package/lib/checks/.eslintrc.json +2 -0
  12. package/lib/checks/actionsFunctions.js +2 -1
  13. package/lib/checks/foreignKeys.js +4 -4
  14. package/lib/checks/managedInType.js +4 -4
  15. package/lib/checks/queryNoDbArtifacts.js +1 -3
  16. package/lib/checks/sql-snippets.js +93 -0
  17. package/lib/checks/validator.js +8 -0
  18. package/lib/compiler/assert-consistency.js +5 -3
  19. package/lib/compiler/base.js +0 -1
  20. package/lib/compiler/checks.js +32 -9
  21. package/lib/compiler/definer.js +25 -4
  22. package/lib/compiler/index.js +1 -1
  23. package/lib/compiler/propagator.js +3 -2
  24. package/lib/compiler/resolver.js +97 -6
  25. package/lib/compiler/shared.js +12 -1
  26. package/lib/compiler/utils.js +7 -0
  27. package/lib/edm/annotations/genericTranslation.js +34 -17
  28. package/lib/edm/annotations/preprocessAnnotations.js +1 -1
  29. package/lib/edm/csn2edm.js +1 -1
  30. package/lib/edm/edm.js +8 -8
  31. package/lib/edm/edmPreprocessor.js +30 -23
  32. package/lib/edm/edmUtils.js +11 -12
  33. package/lib/gen/Dictionary.json +82 -40
  34. package/lib/gen/language.checksum +1 -1
  35. package/lib/gen/language.interp +3 -1
  36. package/lib/gen/language.tokens +15 -14
  37. package/lib/gen/languageLexer.interp +9 -1
  38. package/lib/gen/languageLexer.js +830 -779
  39. package/lib/gen/languageLexer.tokens +7 -6
  40. package/lib/gen/languageParser.js +2401 -2282
  41. package/lib/json/from-csn.js +47 -16
  42. package/lib/json/to-csn.js +17 -5
  43. package/lib/language/antlrParser.js +3 -3
  44. package/lib/language/docCommentParser.js +1 -1
  45. package/lib/language/genericAntlrParser.js +68 -51
  46. package/lib/language/language.g4 +128 -74
  47. package/lib/language/multiLineStringParser.js +536 -0
  48. package/lib/main.d.ts +5 -3
  49. package/lib/main.js +3 -2
  50. package/lib/model/csnRefs.js +116 -68
  51. package/lib/model/csnUtils.js +40 -48
  52. package/lib/model/enrichCsn.js +30 -14
  53. package/lib/optionProcessor.js +3 -3
  54. package/lib/render/DuplicateChecker.js +1 -1
  55. package/lib/render/manageConstraints.js +1 -1
  56. package/lib/render/toCdl.js +193 -79
  57. package/lib/render/toHdbcds.js +179 -95
  58. package/lib/render/toRename.js +7 -10
  59. package/lib/render/toSql.js +57 -40
  60. package/lib/render/utils/common.js +24 -5
  61. package/lib/render/utils/sql.js +6 -4
  62. package/lib/transform/braceExpression.js +4 -2
  63. package/lib/transform/db/associations.js +389 -0
  64. package/lib/transform/db/cdsPersistence.js +150 -0
  65. package/lib/transform/db/constraints.js +6 -4
  66. package/lib/transform/db/draft.js +3 -2
  67. package/lib/transform/db/expansion.js +4 -5
  68. package/lib/transform/db/flattening.js +5 -6
  69. package/lib/transform/db/temporal.js +236 -0
  70. package/lib/transform/db/transformExists.js +36 -23
  71. package/lib/transform/forHanaNew.js +35 -626
  72. package/lib/transform/forOdataNew.js +5 -4
  73. package/lib/transform/localized.js +3 -14
  74. package/lib/transform/odata/generateForeignKeyElements.js +2 -2
  75. package/lib/transform/transformUtilsNew.js +13 -13
  76. package/lib/transform/translateAssocsToJoins.js +8 -8
  77. package/lib/transform/universalCsnEnricher.js +217 -47
  78. package/lib/utils/file.js +2 -1
  79. package/lib/utils/timetrace.js +8 -2
  80. package/package.json +1 -1
@@ -207,7 +207,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
207
207
  // Note: we assume that all objects ly flat in the service, i.e. objName always
208
208
  // looks like <service name, can contain dots>.<id>
209
209
  forEachDefinition(csn, (object, objName) => {
210
- if(objName == serviceName || objName.startsWith(serviceName + '.')) {
210
+ if (objName === serviceName || objName.startsWith(serviceName + '.')) {
211
211
  if (object.kind === 'action' || object.kind === 'function') {
212
212
  handleAction(objName, object, null);
213
213
  }
@@ -505,8 +505,17 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
505
505
  let testToAlternativeEdmTarget = null; // if true, assign to alternative Edm Target
506
506
 
507
507
  if (carrier.kind === 'entity' || carrier.kind === 'view') {
508
- // If AppliesTo=[EntitySet/Singleton, EntityType], EntitySet/Singleton has precedence
509
- testToAlternativeEdmTarget = (x => x.includes('EntitySet') || x.includes('Singleton'));
508
+ // If AppliesTo=[EntitySet/Singleton/Collection, EntityType], EntitySet/Singleton/Collection has precedence
509
+ testToAlternativeEdmTarget = (x => {
510
+ if(options.isV2()) {
511
+ return ['Singleton', 'EntitySet', 'Collection'].some(y => x.includes(y));
512
+ }
513
+ else {
514
+ return edmUtils.isSingleton(carrier)
515
+ ? x.includes('Singleton')
516
+ : ['EntitySet', 'Collection'].some(y => x.includes(y));
517
+ }
518
+ });
510
519
  testToStandardEdmTarget = (x => x ? x.includes('EntityType') : true);
511
520
  // if carrier has an alternate 'entitySetName' use this instead of EdmTargetName
512
521
  // (see edmPreprocessor.initializeParameterizedEntityOrView(), where parameterized artifacts
@@ -534,15 +543,21 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
534
543
  alternativeEdmTargetName = edmTargetName;
535
544
  hasAlternativeCarrier = true; // EntityContainer is always available
536
545
  }
537
- //element => decide if navprop or normal property
546
+ //element => decide if navprop or normal property
538
547
  else if(!carrier.kind) {
539
- // if appliesTo is undefined, return true
548
+ // if appliesTo is undefined, return true
540
549
  if(carrier.target) {
541
- testToStandardEdmTarget = (x=> x ? x.includes('NavigationProperty') : true);
550
+ testToStandardEdmTarget = (x => x
551
+ ? x.includes('NavigationProperty') ||
552
+ carrier.cardinality && carrier.cardinality.max === '*' && x.includes('Collection')
553
+ : true);
542
554
  }
543
555
  else {
544
556
  // this might be more precise if handleAnnotation would know more about the carrier
545
- testToStandardEdmTarget = (x => x ? ['Parameter', 'Property'].some(y => x.includes(y)): true);
557
+ testToStandardEdmTarget = (x => x
558
+ ? ['Parameter', 'Property'].some(y => x.includes(y) ||
559
+ carrier._isCollection && x.includes('Collection'))
560
+ : true);
546
561
  }
547
562
  }
548
563
  return [
@@ -851,7 +866,6 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
851
866
  else if (!expectedType['Members'].includes(enumValue)) {
852
867
  message(warning, context, `enumeration type ${ dTypeName } has no value ${ enumValue }`);
853
868
  }
854
- return;
855
869
  }
856
870
 
857
871
  // cAnnoValue: array
@@ -865,8 +879,9 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
865
879
  }
866
880
 
867
881
  let index = 0;
868
- for (let e of cAnnoValue) {
869
- context.stack.push('[' + index++ + ']');
882
+ for (const e of cAnnoValue) {
883
+ context.stack.push('[' + index + ']');
884
+ index++;
870
885
  if (e['#']) {
871
886
  checkEnumValue(e['#'], dTypeName, context);
872
887
  }
@@ -901,7 +916,7 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
901
916
  }
902
917
  else {
903
918
  // replace all occurrences of '.' by '/' up to first '@'
904
- val = expr.split('@').map((o,i) => (i==0 ? o.replace(/\./g, '/') : o)).join('@');
919
+ val = expr.split('@').map((o,i) => (i === 0 ? o.replace(/\./g, '/') : o)).join('@');
905
920
  }
906
921
 
907
922
  return {
@@ -922,9 +937,10 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
922
937
  // caller already made sure that val is neither object nor array
923
938
  dTypeName = resolveType(dTypeName);
924
939
 
925
- if(isEnumType(dTypeName)) {
940
+ if (isEnumType(dTypeName)) {
926
941
  const type = getDictType(dTypeName);
927
- message(warning, context, `found non-enum value "${val}", expected ${type.Members.map(m=>`"#${m}"`).join(', ')} for ${dTypeName}`);
942
+ const expected = type.Members.map(m => `"#${m}"`).join(', ');
943
+ message(warning, context, `found non-enum value "${val}", expected ${expected} for ${dTypeName}`);
928
944
  }
929
945
 
930
946
  let typeName = 'String';
@@ -1154,8 +1170,9 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
1154
1170
  }
1155
1171
 
1156
1172
  let index = 0;
1157
- for (let value of annoValue) {
1158
- context.stack.push('[' + index++ + ']');
1173
+ for (const value of annoValue) {
1174
+ context.stack.push('[' + index + ']');
1175
+ index++
1159
1176
 
1160
1177
  // for dealing with the single array entries we unfortunately cannot call handleValue(),
1161
1178
  // as the values inside an array are represented differently from the values
@@ -1214,8 +1231,8 @@ function csn2annotationEdm(csn, serviceName, Edm = undefined, options=undefined,
1214
1231
  return edmNode;
1215
1232
  }
1216
1233
 
1217
- if(dynExprs.length === 0) {
1218
- if (typeof obj === 'object' && obj !== null && !Array.isArray(obj) && Object.keys(obj).length==1) {
1234
+ if (dynExprs.length === 0) {
1235
+ if (typeof obj === 'object' && obj !== null && !Array.isArray(obj) && Object.keys(obj).length === 1) {
1219
1236
  const k = Object.keys(obj)[0];
1220
1237
  const val = obj[k];
1221
1238
  edmNode = new Edm.ValueThing(v, k[0] === '$' ? k.slice(1) : k, val );
@@ -236,7 +236,7 @@ function preprocessAnnotations(csn, serviceName, options) {
236
236
  } else {
237
237
  let stringFields = Object.keys(vlEntity.elements).filter(
238
238
  x => !vlEntity.elements[x].key && vlEntity.elements[x].type === 'cds.String')
239
- if (stringFields.length == 1)
239
+ if (stringFields.length === 1)
240
240
  textField = stringFields[0];
241
241
  }
242
242
 
@@ -420,7 +420,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
420
420
  /** @type {object} */
421
421
  let containerEntry;
422
422
 
423
- if(edmUtils.isSingleton(entityCsn, options.isV4())) {
423
+ if(edmUtils.isSingleton(entityCsn) && options.isV4()) {
424
424
  containerEntry = new Edm.Singleton(v, { Name: EntitySetName, Type: fullQualified(EntityTypeName) }, entityCsn);
425
425
  if(entityCsn['@odata.singleton.nullable'])
426
426
  containerEntry.Nullable= true;
package/lib/edm/edm.js CHANGED
@@ -665,7 +665,7 @@ module.exports = function (options, error) {
665
665
  json['$'+this._typeName] = this._type;
666
666
 
667
667
  edmUtils.forAll(this, (v,p) => {
668
- if (p !== 'Name' && p != this._typeName
668
+ if (p !== 'Name' && p !== this._typeName
669
669
  // remove this line if Nullable=true becomes default
670
670
  && !(p === 'Nullable' && v == false))
671
671
  {
@@ -711,7 +711,7 @@ module.exports = function (options, error) {
711
711
  if(alias.length > 28) {
712
712
  alias = alias.substr(0, 13)+ '__' +alias.substr(alias.length-13, alias.length);
713
713
  }
714
- alias = alias+'_'+c.toString().padStart(3,0);
714
+ alias = alias+'_'+c.toString().padStart(3, '0');
715
715
  }
716
716
  else if(alias.length > 32) {
717
717
  alias = alias.substr(0, 15)+ '__' +alias.substr(alias.length-15, alias.length);
@@ -835,7 +835,7 @@ module.exports = function (options, error) {
835
835
  // Nullable=false is default for EDM JSON representation 4.01
836
836
  // When a key explicitly (!) has 'notNull = false', it stays nullable
837
837
  return (nodeCsn._NotNullCollection !== undefined ? nodeCsn._NotNullCollection :
838
- (nodeCsn.key && !(nodeCsn.notNull === false)) || nodeCsn.notNull === true);
838
+ (nodeCsn.key && nodeCsn.notNull !== false) || nodeCsn.notNull === true);
839
839
  }
840
840
 
841
841
  toJSONattributes(json)
@@ -1159,7 +1159,7 @@ module.exports = function (options, error) {
1159
1159
  /* short notation for Edm.Boolean, Edm.String and Edm.Float, see internal project:
1160
1160
  edmx2csn-npm/edm-converters/blob/835d92a1aa6b0be25c56cef85e260c9188187429/lib/edmxV40ToJsonV40/README.md
1161
1161
  */
1162
- case 'Edm.Boolean':
1162
+ case 'Edm.Boolean':
1163
1163
  v = (v=='true'?true:(v=='false'?false:v));
1164
1164
  // eslint-no-fallthrough
1165
1165
  case 'Edm.String':
@@ -1275,8 +1275,8 @@ module.exports = function (options, error) {
1275
1275
  if(this.Type)
1276
1276
  json['@type'] = this.Type;
1277
1277
  let keys = Object.keys(this).filter(k => k !== 'Type');
1278
- for(let i = 0; i < keys.length; i++)
1279
- json['$'+keys[i]] = this[keys[i]];
1278
+ for(const key of keys)
1279
+ json['$'+key] = this[key];
1280
1280
  }
1281
1281
 
1282
1282
  toJSONchildren(json)
@@ -1377,7 +1377,7 @@ module.exports = function (options, error) {
1377
1377
  }
1378
1378
 
1379
1379
  toJSON()
1380
- {
1380
+ {
1381
1381
  // toJSON: depending on number of children unary or n-ary expr
1382
1382
  const json = this.mergeJSONAnnotations();
1383
1383
  const e = this._children.filter(c=>c.kind !== 'Annotation');
@@ -1459,7 +1459,7 @@ module.exports = function (options, error) {
1459
1459
  return json;
1460
1460
  }
1461
1461
  }
1462
- // LabeledElementReference is a
1462
+ // LabeledElementReference is a
1463
1463
  class LabeledElementReference extends ValueThing {
1464
1464
  constructor(v, val) {
1465
1465
  super(v, 'LabeledElementReference', val);
@@ -39,7 +39,7 @@ function initializeModel(csn, _options, messageFunctions)
39
39
  if (!_options)
40
40
  throw Error('Please debug me: initializeModel must be invoked with options');
41
41
 
42
- const { info, warning, error, throwWithError } = messageFunctions;
42
+ const { info, warning, error, message, throwWithError } = messageFunctions;
43
43
 
44
44
  const csnUtils = getUtils(csn);
45
45
  const {
@@ -455,8 +455,8 @@ function initializeModel(csn, _options, messageFunctions)
455
455
  // propagate containment information, if containment is recursive, use parameterCsn.name as _containerEntity
456
456
  if(entityCsn._containerEntity) {
457
457
  setProp(parameterCsn, '_containerEntity', []);
458
- for(let c of entityCsn._containerEntity) {
459
- parameterCsn._containerEntity.push((c==entityCsn.name)?parameterCsn.name:c);
458
+ for(const c of entityCsn._containerEntity) {
459
+ parameterCsn._containerEntity.push((c === entityCsn.name) ? parameterCsn.name : c);
460
460
  }
461
461
  }
462
462
  entityCsn._containerEntity = [ parameterCsn ];
@@ -489,12 +489,18 @@ function initializeModel(csn, _options, messageFunctions)
489
489
  member.$path[1] = parameterEntityName;
490
490
  });
491
491
 
492
-
493
- csn.definitions[parameterCsn.name] = parameterCsn;
492
+ if(csn.definitions[parameterCsn.name])
493
+ error('odata-definition-exists', [ 'definitions', entityName ], { '#': 'std', name: parameterCsn.name });
494
+ else
495
+ csn.definitions[parameterCsn.name] = parameterCsn;
494
496
  // modify the original parameter entity with backlink and new name
495
- csn.definitions[originalEntityName] = entityCsn;
496
- delete csn.definitions[entityCsn.name];
497
- entityCsn.name = originalEntityName;
497
+ if(csn.definitions[originalEntityName])
498
+ error('odata-definition-exists', [ 'definitions', entityName ], { '#': 'std', name: originalEntityName });
499
+ else {
500
+ csn.definitions[originalEntityName] = entityCsn;
501
+ delete csn.definitions[entityCsn.name];
502
+ entityCsn.name = originalEntityName;
503
+ }
498
504
  setProp(entityCsn, '$entitySetName', originalEntitySetName);
499
505
  // add backlink association
500
506
  if(hasBacklink) {
@@ -546,6 +552,7 @@ function initializeModel(csn, _options, messageFunctions)
546
552
  // convert $path to path starting at main artifact
547
553
  function $path2path(p) {
548
554
  const path = [];
555
+ /** @type {object} */
549
556
  let env = csn;
550
557
  for (let i = 0; p && env && i < p.length; i++) {
551
558
  const ps = p[i];
@@ -769,7 +776,7 @@ function initializeModel(csn, _options, messageFunctions)
769
776
  if(element._constraints._partnerCsn.cardinality.src) {
770
777
  let srcMult = (element._constraints._partnerCsn.cardinality.src == 1) ? '0..1' : '*';
771
778
  let newMult = (element.cardinality.max > 1) ? '*' : '0..1';
772
- if(options.isV2() && srcMult != newMult) {
779
+ if(options.isV2() && srcMult !== newMult) {
773
780
  // Association 'E_toF': Multiplicity of Role='E' defined to '*', conflicting with target multiplicity '0..1' from
774
781
  warning(null, null, `Source cardinality "${element._constraints._partnerCsn.cardinality.src}" of "${element._constraints._partnerCsn._parent.name}/${element._constraints._partnerCsn.name}" conflicts with target cardinality "${element.cardinality.max}" of association "${element._parent.name}/${element.name}"`);
775
782
  }
@@ -1268,9 +1275,8 @@ function initializeModel(csn, _options, messageFunctions)
1268
1275
  }
1269
1276
  else if(alreadyRegistered && !alreadyRegistered.$proxy &&
1270
1277
  !['entity', 'view'].includes(alreadyRegistered.kind)) {
1271
- warning(null, ['definitions', element._parent.name, 'elements', element.name],
1272
- { name: fqProxyName, kind: alreadyRegistered.kind },
1273
- 'No proxy EDM entity type created due to name collision with $(NAME) of kind $(KIND)');
1278
+ warning('odata-definition-exists', ['definitions', element._parent.name, 'elements', element.name],
1279
+ { '#': 'proxy', name: fqProxyName, kind: alreadyRegistered.kind });
1274
1280
  return undefined;
1275
1281
  }
1276
1282
  }
@@ -1350,7 +1356,7 @@ function initializeModel(csn, _options, messageFunctions)
1350
1356
  // OData requires all elements along the path to be nullable: false (that is either key or notNull)
1351
1357
 
1352
1358
  const finalType = getFinalTypeDef(eltCsn.items && eltCsn.items.type || eltCsn.type);
1353
- const elements = eltCsn.elements || eltCsn.items && eltCsn.items.elements ||
1359
+ const elements = eltCsn.elements || eltCsn.items && eltCsn.items.elements ||
1354
1360
  (finalType && (finalType.elements || finalType.items && finalType.items.elements));
1355
1361
  if(elements) {
1356
1362
  Object.entries(elements).forEach(([eltName, elt]) => {
@@ -1415,7 +1421,7 @@ function initializeModel(csn, _options, messageFunctions)
1415
1421
  if(options.isV4() && type && !isAssociationOrComposition(type) && isBuiltinType(type.type)) {
1416
1422
  const edmType = edmUtils.mapCdsToEdmType(type);
1417
1423
  const legalEdmTypes = [
1418
- 'Edm.Boolean', 'Edm.Byte', 'Edm.Date', 'Edm.DateTimeOffset', 'Edm.Decimal', 'Edm.Duration',
1424
+ 'Edm.Boolean', 'Edm.Byte', 'Edm.Date', 'Edm.DateTimeOffset', 'Edm.Decimal', 'Edm.Duration',
1419
1425
  'Edm.Guid', 'Edm.Int16', 'Edm.Int32', 'Edm.Int64', 'Edm.SByte', 'Edm.String', 'Edm.TimeOfDay' ];
1420
1426
  if(!legalEdmTypes.includes(edmType)) {
1421
1427
  warning('odata-spec-violation-key-type', location,
@@ -1517,8 +1523,8 @@ function initializeModel(csn, _options, messageFunctions)
1517
1523
  // end point reached but must not be an external reference nor a proxy nor a composition itself
1518
1524
  // last assoc step must not be to-n and target a singleton
1519
1525
  let p = undefined;
1520
- if (!elt._target.$externalRef &&
1521
- !(edmUtils.isToMany(elt) && edmUtils.isSingleton(elt._target, options.isV4()))) {
1526
+ if (!elt._target.$externalRef &&
1527
+ !(edmUtils.isToMany(elt) && edmUtils.isSingleton(elt._target) && options.isV4())) {
1522
1528
  if(elt._target.$edmTgtPaths && elt._target.$edmTgtPaths.length) {
1523
1529
  p = elt._target.$edmTgtPaths.find(p => p[0] === edmUtils.getBaseName(struct.name)) || elt._target.$edmTgtPaths[0];
1524
1530
  }
@@ -1526,7 +1532,7 @@ function initializeModel(csn, _options, messageFunctions)
1526
1532
  const baseName = edmUtils.getBaseName(elt._target.$entitySetName || elt._target.name);
1527
1533
  // if own struct and target have a set they either are in the same $mySchemaName or not
1528
1534
  // if target is in another schema, target the full qualified entity set
1529
- p = (elt._target.$mySchemaName === struct.$mySchemaName) ?
1535
+ p = (elt._target.$mySchemaName === struct.$mySchemaName) ?
1530
1536
  [ baseName ] : [elt._target.$mySchemaName + '.EntityContainer', baseName];
1531
1537
  }
1532
1538
  if(p) {
@@ -1641,7 +1647,7 @@ function initializeModel(csn, _options, messageFunctions)
1641
1647
  !isBetaEnabled(options, 'nestedServices') && serviceRootNames.forEach(sn => {
1642
1648
  const parent = whatsMyServiceRootName(sn, false);
1643
1649
  if(parent && parent !== sn) {
1644
- error( 'service-nested-service', [ 'definitions', sn ], { art: parent },
1650
+ message( 'service-nested-service', [ 'definitions', sn ], { art: parent },
1645
1651
  'A service can\'t be nested within a service $(ART)' );
1646
1652
  }
1647
1653
  });
@@ -1650,7 +1656,7 @@ function initializeModel(csn, _options, messageFunctions)
1650
1656
  if(art.kind === 'context') {
1651
1657
  const parent = whatsMyServiceRootName(fqName);
1652
1658
  if(parent) {
1653
- error( 'service-nested-context', [ 'definitions', fqName ], { art: parent },
1659
+ message( 'service-nested-context', [ 'definitions', fqName ], { art: parent },
1654
1660
  'A context can\'t be nested within a service $(ART)' );
1655
1661
  }
1656
1662
  }
@@ -1788,8 +1794,8 @@ function initializeModel(csn, _options, messageFunctions)
1788
1794
  if(!navPropEntry[prop]) {
1789
1795
  // Filter properties with prefix and reduce them into a new dictionary
1790
1796
  const o = props.filter(p => p[0].startsWith(prefix+'.')).reduce((a,c) => {
1791
- a[c[0].replace(prefix+'.', '')] = c[1];
1792
- return a;
1797
+ a[c[0].replace(prefix+'.', '')] = c[1];
1798
+ return a;
1793
1799
  }, { });
1794
1800
  // if dictionary has entries, add them to navPropEnty
1795
1801
  if(Object.keys(o).length) {
@@ -1925,8 +1931,9 @@ function applyAppSpecificLateCsnTransformationOnElement(options, element, struct
1925
1931
  // nested functions begin
1926
1932
  function PDMSemantics()
1927
1933
  {
1928
- let dict = Object.create(null);
1929
1934
  /*
1935
+ let dict = Object.create(null);
1936
+
1930
1937
  dict['@PDM.xxx1'] = [ '@sap.pdm-semantics' ];
1931
1938
  dict['@PDM.xxx2'] = [ '@sap.pdm-propery' ];
1932
1939
  dict['@PDM.xxx3'] = [ '@sap.pdm-display-sq-no' ];
@@ -1940,7 +1947,7 @@ function applyAppSpecificLateCsnTransformationOnElement(options, element, struct
1940
1947
  // respect flattened annotation $value
1941
1948
  Object.keys(dict).forEach(k => dict[k+'.$value'] = dict[k]);
1942
1949
  */
1943
- return dict;
1950
+ return Object.create(null);
1944
1951
  }
1945
1952
 
1946
1953
  function AnalyticalAnnotations()
@@ -30,18 +30,18 @@ function validateOptions(_options)
30
30
 
31
31
  }
32
32
 
33
- const v2 = options.version.match(/v2/i) != undefined;
34
- const v4 = options.version.match(/v4/i) != undefined;
33
+ const v2 = options.version.match(/v2/i) !== null;
34
+ const v4 = options.version.match(/v4/i) !== null;
35
35
 
36
36
  options.v = [v2, v4];
37
37
  options.isStructFormat = options.odataFormat && options.odataFormat === 'structured';
38
38
  options.isFlatFormat = !options.isStructFormat;
39
39
 
40
- if(options.v.filter(v=>v).length != 1)
40
+ if(options.v.filter(v=>v).length !== 1)
41
41
  throw Error(`Please debug me: EDM V2:${v2}, V4:${v4}`);
42
42
 
43
- options.isV2 = function() { return this.v[0] == true; }
44
- options.isV4 = function() { return this.v[1] == true; }
43
+ options.isV2 = function() { return this.v[0]; }
44
+ options.isV4 = function() { return this.v[1]; }
45
45
 
46
46
  options.pathDelimiter = options.isStructFormat ? '/' : '_';
47
47
 
@@ -115,10 +115,10 @@ function isToMany(assoc) {
115
115
  return targetMax === '*' || Number(targetMax) > 1;
116
116
  }
117
117
 
118
- function isSingleton(entityCsn, v) {
118
+ function isSingleton(entityCsn) {
119
119
  const singleton = entityCsn['@odata.singleton'];
120
120
  const hasNullable = entityCsn['@odata.singleton.nullable'] !== undefined && entityCsn['@odata.singleton.nullable'] !== null;
121
- return v && singleton || ((singleton === undefined || singleton === null) && hasNullable);
121
+ return singleton || ((singleton === undefined || singleton === null) && hasNullable);
122
122
  }
123
123
 
124
124
  function isEntity(artifact)
@@ -358,7 +358,7 @@ function finalizeReferentialConstraints(csn, assocCsn, options, info)
358
358
  // in structured mode only resolve top level element (path rewriting is done elsewhere)
359
359
  const depEltName = ( options.isFlatFormat ? c[0].join('_') : c[0][0] );
360
360
  const principalEltName = ( options.isFlatFormat ? c[1].join('_') : c[1][0] );
361
- const fk = (isEntity(dependentEntity) && dependentEntity.elements[ depEltName ]) ||
361
+ const fk = (isEntity(dependentEntity) && dependentEntity.elements[ depEltName ]) ||
362
362
  (localDepEntity && localDepEntity.elements && localDepEntity.elements[ depEltName ]);
363
363
  const pk = principalEntity.$keys && principalEntity.$keys[ principalEltName ];
364
364
  if(isConstraintCandidate(fk) && isConstraintCandidate(pk)) {
@@ -463,12 +463,11 @@ function finalizeReferentialConstraints(csn, assocCsn, options, info)
463
463
  * The element must never be an association or composition and be renderable.
464
464
  */
465
465
  function isConstraintCandidate(elt) {
466
- let rc= (elt &&
466
+ return (elt &&
467
467
  elt.type &&
468
468
  (!options.isFlatFormat || options.isFlatFormat && isBuiltinType(elt.type)) &&
469
469
  !['cds.Association', 'cds.Composition'].includes(elt.type) &&
470
470
  isEdmPropertyRendered(elt, options));
471
- return rc;
472
471
  }
473
472
  }
474
473
 
@@ -694,10 +693,10 @@ function getBaseName(name) {
694
693
 
695
694
  // This is a poor mans path resolver for $self partner paths only
696
695
  function resolveOriginAssoc(csn, env, path) {
697
- for(let i = 0; i < path.length; i++) {
696
+ for(const segment of path) {
698
697
  let elements = (env.items && env.items.elements || env.elements);
699
698
  if(elements)
700
- env = env.elements[path[i]];
699
+ env = env.elements[segment];
701
700
  let type = (env.items && env.items.type || env.type);
702
701
  if(type && !isBuiltinType(type) && !(env.items && env.items.elements || env.elements))
703
702
  env = csn.definitions[env.type];