@sap/cds-compiler 3.4.2 → 3.4.4

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 (57) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/bin/cdsc.js +3 -4
  3. package/bin/cdshi.js +19 -6
  4. package/doc/CHANGELOG_ARCHIVE.md +1 -1
  5. package/lib/api/main.js +6 -3
  6. package/lib/base/message-registry.js +60 -37
  7. package/lib/base/messages.js +7 -3
  8. package/lib/checks/.eslintrc.json +2 -0
  9. package/lib/compiler/.eslintrc.json +4 -1
  10. package/lib/compiler/assert-consistency.js +8 -6
  11. package/lib/compiler/builtins.js +13 -13
  12. package/lib/compiler/checks.js +50 -33
  13. package/lib/compiler/define.js +9 -6
  14. package/lib/compiler/extend.js +71 -45
  15. package/lib/compiler/finalize-parse-cdl.js +3 -3
  16. package/lib/compiler/populate.js +16 -5
  17. package/lib/compiler/resolve.js +2 -15
  18. package/lib/compiler/shared.js +4 -4
  19. package/lib/compiler/utils.js +14 -0
  20. package/lib/edm/annotations/genericTranslation.js +68 -56
  21. package/lib/edm/csn2edm.js +214 -174
  22. package/lib/edm/edmAnnoPreprocessor.js +5 -5
  23. package/lib/edm/edmInboundChecks.js +2 -2
  24. package/lib/edm/edmPreprocessor.js +1 -1
  25. package/lib/edm/edmUtils.js +3 -3
  26. package/lib/gen/Dictionary.json +176 -8
  27. package/lib/gen/language.checksum +1 -1
  28. package/lib/gen/language.interp +2 -1
  29. package/lib/gen/languageParser.js +4776 -4513
  30. package/lib/json/from-csn.js +21 -16
  31. package/lib/json/to-csn.js +37 -41
  32. package/lib/language/.eslintrc.json +4 -1
  33. package/lib/language/antlrParser.js +5 -2
  34. package/lib/language/docCommentParser.js +6 -6
  35. package/lib/language/errorStrategy.js +43 -23
  36. package/lib/language/genericAntlrParser.js +54 -95
  37. package/lib/language/language.g4 +92 -66
  38. package/lib/language/multiLineStringParser.js +2 -2
  39. package/lib/language/textUtils.js +2 -2
  40. package/lib/model/csnRefs.js +5 -0
  41. package/lib/modelCompare/compare.js +2 -2
  42. package/lib/modelCompare/utils/.eslintrc.json +22 -0
  43. package/lib/modelCompare/utils/filter.js +99 -0
  44. package/lib/render/.eslintrc.json +1 -0
  45. package/lib/render/toCdl.js +96 -127
  46. package/lib/render/toHdbcds.js +38 -35
  47. package/lib/render/toSql.js +75 -161
  48. package/lib/render/utils/common.js +133 -83
  49. package/lib/render/utils/delta.js +227 -0
  50. package/lib/transform/db/.eslintrc.json +2 -0
  51. package/lib/transform/draft/.eslintrc.json +1 -35
  52. package/lib/transform/forOdataNew.js +26 -19
  53. package/lib/transform/localized.js +9 -8
  54. package/lib/transform/odata/typesExposure.js +26 -4
  55. package/lib/transform/transformUtilsNew.js +15 -8
  56. package/package.json +2 -3
  57. package/lib/modelCompare/filter.js +0 -83
@@ -30,7 +30,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
30
30
 
31
31
  // use original options for messages; cloned CSN for semantic location
32
32
  const messageFunctions = makeMessageFunction(csn, _options, 'to.edmx');
33
- const { info, warning, error, message, throwWithAnyError } = messageFunctions;
33
+ const { info, warning, error, message, throwWithError } = messageFunctions;
34
34
  checkCSNVersion(csn, _options);
35
35
 
36
36
  let rc = Object.create(null);
@@ -54,7 +54,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
54
54
 
55
55
  const v = options.v;
56
56
  if(Object.keys(allServices).length === 0) {
57
- info(null, null, `No Services in model`);
57
+ info(null, null, 'No Services in model');
58
58
  return rc;
59
59
  }
60
60
 
@@ -76,7 +76,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
76
76
  services[serviceCsn.name] = createEdm(serviceCsn);
77
77
  return services; }, rc);
78
78
  }
79
- throwWithAnyError();
79
+ throwWithError();
80
80
  return rc;
81
81
 
82
82
  //--------------------------------------------------------------------------------
@@ -91,6 +91,8 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
91
91
  // let alias = serviceCsn.alias || baseName(baseName(serviceCsn.name, '::'), '.');
92
92
  // FIXME: UI5 cannot deal with spec conforming simpleid alias names
93
93
 
94
+ function markRendered(def) { setProp(def, '$isRendered', true); }
95
+
94
96
  const service = new Edm.DataServices(v);
95
97
  /** @type {object} */
96
98
  const edm = new Edm.Edm(v, service);
@@ -131,8 +133,19 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
131
133
  -----------------------------------------------*/
132
134
  let LeadSchema;
133
135
  const fqSchemaXRef = [serviceCsn.name];
134
- const whatsMySchemaName = function(n) {
135
- return fqSchemaXRef.reduce((rc, sn) => !rc && n && n.startsWith(sn + '.') ? sn : rc, undefined);
136
+ const whatsMySchemaName = function(n, arr=fqSchemaXRef) {
137
+ return arr.reduce((rc, sn) => !rc && n && n.startsWith(sn + '.') ? sn : rc, undefined);
138
+ }
139
+
140
+ let xServiceRefs = [];
141
+ const UsedTypes = {};
142
+ function collectUsedType(csn, typeName = (csn.items?.type || csn.type)) {
143
+ if(typeName) {
144
+ if(UsedTypes[typeName])
145
+ UsedTypes[typeName].push(csn)
146
+ else
147
+ UsedTypes[typeName] = [ csn ];
148
+ }
136
149
  }
137
150
 
138
151
  // create schema containers
@@ -175,20 +188,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
175
188
 
176
189
  // Fill the schemas and references, fqSchemaXRef must be complete
177
190
  populateSchemas(subSchemaDictionary);
178
- const xServiceRefs = populateXserviceRefs();
179
- /* TODO:
180
- const references = Object.entries(allSchemas).reduce((references, [fqName, art]) => {
181
- // add references
182
- if(fqName.startsWith(serviceCsn.name + '.') && art.kind === 'reference') {
183
- fqSchemaXRef.push(fqName);
184
- references.push(art);
185
- }
186
- return references;
187
- }, []);
188
- */
189
- // Add xrefs to full schema cross ref list for further usage
190
- fqSchemaXRef.push(...xServiceRefs);
191
- fqSchemaXRef.sort((a,b) => b.length-a.length);
191
+ xServiceRefs = populateXserviceRefs();
192
192
 
193
193
  // Bring the schemas in alphabetical order, service first, root last
194
194
  const sortedSchemaNames = Object.keys(subSchemaDictionary).filter(n => n !== fallBackSchemaName && n !== serviceCsn.name).sort();
@@ -223,13 +223,52 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
223
223
  service._children.forEach(c => {
224
224
  c._ec && Object.entries(c._ec._registry).forEach((([setName, arr]) => {
225
225
  if(arr.length > 1) {
226
- error(null, null, { name: c._edmAttributes.Namespace, id: setName },
227
- `Namespace $(NAME): Duplicate entries in EntityContainer with Name=$(ID) for ${arr.map(a =>a.getDuplicateMessage()).join(', ')} `);
226
+ error(null, null, {
227
+ name: c._edmAttributes.Namespace,
228
+ id: setName,
229
+ names: arr.map(a => a.getDuplicateMessage())
230
+ }, 'Namespace $(NAME): Duplicate entries in EntityContainer with Name=$(ID) for $(NAMES)');
228
231
  }
229
232
  }));
230
233
  });
231
234
  // Create annotations and distribute into Schemas
232
235
  addAnnotations();
236
+
237
+ // type cross check
238
+ const xServiceRefNames = xServiceRefs.map(r => r.name).sort((a,b)=>b.length-a.length);
239
+ for(let typeName in UsedTypes) {
240
+ if(!isBuiltinType(typeName)) {
241
+ let iTypeName = typeName;
242
+ /*
243
+ Report type ref, if the type is
244
+ - not a builtin,
245
+ - not included in required definitions (for this service)
246
+ - not a type clash (reported in type exposure),
247
+ - a @cds.external service member but can't be rendered
248
+ - and not a cross referenced type
249
+ */
250
+ if(!typeName.startsWith(serviceCsn.name + '.'))
251
+ iTypeName = serviceCsn.name + '.' + typeName;
252
+ const def = reqDefs.definitions[iTypeName];
253
+
254
+ const usages = UsedTypes[typeName].filter(u => !u.$NameClashReported);
255
+ if(usages.length > 0) {
256
+ if(def && !def.$isRendered && def['@cds.external'])
257
+ message('odata-spec-violation-type', usages[0].$location,
258
+ {
259
+ type: typeName,
260
+ anno: '@cds.external',
261
+ name: serviceCsn.name,
262
+ code: def.elements ? 'Edm.ComplexType' : 'Edm.TypeDefinition',
263
+ version: options.isV4() ? '4.0' : '2.0',
264
+ '#': 'external' } );
265
+ else if(!def && !whatsMySchemaName(typeName, xServiceRefNames))
266
+ message('odata-spec-violation-type', usages[0].$location,
267
+ { type: typeName, name: serviceCsn.name, '#': 'missing' } );
268
+ }
269
+ }
270
+ }
271
+
233
272
  return edm
234
273
 
235
274
  // Sort definitions into their schema container
@@ -290,7 +329,6 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
290
329
  return Object.entries(allSchemas).reduce((references, [fqName, art]) => {
291
330
  // add references
292
331
  if(art.kind === 'reference' && whatsMySchemaName(fqName) && serviceCsn.name === whatsMyServiceRootName(fqName, false)) {
293
- fqSchemaXRef.push(fqName);
294
332
  references.push(art);
295
333
  }
296
334
  return references;
@@ -331,17 +369,17 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
331
369
  */
332
370
  edmUtils.foreach(schemaCsn.definitions,
333
371
  a => a.kind === 'entity' && !a.abstract && a.name.startsWith(schemaNamePrefix),
334
- createEntityTypeAndSet
372
+ [createEntityTypeAndSet, markRendered]
335
373
  );
336
374
  // create unbound actions/functions
337
- edmUtils.foreach(schemaCsn.definitions,
375
+ edmUtils.foreach(schemaCsn.definitions,
338
376
  a => (a.kind === 'action' || a.kind === 'function') && a.name.startsWith(schemaNamePrefix),
339
- (options.isV4()) ? createActionV4 : createActionV2);
377
+ [(options.isV4()) ? createActionV4 : createActionV2, markRendered]);
340
378
 
341
379
  // create the complex types
342
380
  edmUtils.foreach(schemaCsn.definitions,
343
381
  a => edmUtils.isStructuredType(a) && a.name.startsWith(schemaNamePrefix),
344
- createComplexType);
382
+ [createComplexType, markRendered]);
345
383
 
346
384
  if(options.isV4())
347
385
  {
@@ -349,10 +387,10 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
349
387
  artifact => edmUtils.isDerivedType(artifact) &&
350
388
  !artifact.target &&
351
389
  artifact.name.startsWith(schemaNamePrefix),
352
- createTypeDefinition);
390
+ [createTypeDefinitionV4, markRendered]);
353
391
  }
354
392
 
355
- // fetch all exising children names in a map
393
+ // fetch all existing child names in a map
356
394
  const NamesInSchemaXRef = Schema._children.reduce((acc, cur) => {
357
395
  const name = cur._edmAttributes.Name;
358
396
  if(acc[name] === undefined) {
@@ -370,15 +408,12 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
370
408
  np.addReferentialConstraintNodes();
371
409
  }
372
410
  else {
373
- addAssociation(np);
411
+ addAssociationV2(np);
374
412
  }
375
413
  });
376
414
 
377
- // remove EntityContainer if empty
378
- if(Schema._ec && Schema._ec._children.length === 0) {
379
- Schema._children.splice(Schema._children.indexOf(Schema._ec), 1);
380
- }
381
- if(Schema._children.length === 0) {
415
+ if(Schema._children.length === 0 ||
416
+ (Schema._children.length === 1 && Schema._children[0].kind === 'EntityContainer')) {
382
417
  // FIXME: Location for sub schemas?
383
418
  warning(null, ['definitions', Schema._edmAttributes.Namespace], { name: Schema._edmAttributes.Namespace }, 'Schema $(NAME) is empty');
384
419
  }
@@ -468,6 +503,134 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
468
503
  });
469
504
  }
470
505
 
506
+ function createComplexType(structuredTypeCsn)
507
+ {
508
+ // V4 attributes: Name, BaseType, Abstract, OpenType
509
+ const attributes = { Name: structuredTypeCsn.name.replace(schemaNamePrefix, '') };
510
+
511
+ const complexType = new Edm.ComplexType(v, attributes, structuredTypeCsn);
512
+ const elementsCsn = structuredTypeCsn.items || structuredTypeCsn;
513
+ const properties = createProperties(elementsCsn, structuredTypeCsn)[0];
514
+ const loc = ['definitions', structuredTypeCsn.name];
515
+
516
+ if(properties.length === 0) {
517
+ warning(null, loc, { name: structuredTypeCsn.name },
518
+ 'EDM ComplexType $(NAME) has no properties');
519
+ }
520
+ if(!edmUtils.isODataSimpleIdentifier(attributes.Name))
521
+ message('odata-spec-violation-id', loc, { id: attributes.Name });
522
+
523
+ properties.forEach(p => {
524
+ const pLoc = [ ...loc, ...(structuredTypeCsn.items ? ['items', 'elements'] : [ 'elements' ]), p._edmAttributes.Name ];
525
+ edmTypeCompatibilityCheck(p, pLoc);
526
+ if(p._edmAttributes.Name === complexType._edmAttributes.Name)
527
+ message('odata-spec-violation-property-name', pLoc, { kind: structuredTypeCsn.kind });
528
+
529
+ if(!edmUtils.isODataSimpleIdentifier(p._edmAttributes.Name))
530
+ message('odata-spec-violation-id', pLoc, { id: p._edmAttributes.Name });
531
+
532
+ if(options.isV2()) {
533
+ if(p._isCollection && !p._csn.target)
534
+ message('odata-spec-violation-array', pLoc, { version: '2.0' });
535
+
536
+ if(p._csn.target)
537
+ message('odata-spec-violation-assoc', pLoc, { version: '2.0' });
538
+ }
539
+ });
540
+
541
+
542
+ complexType.append(...(properties));
543
+
544
+ Schema.append(complexType);
545
+ }
546
+
547
+ /**
548
+ * @param {object} elementsCsn
549
+ * @param {object} edmParentCsn
550
+ * @returns {[object[], any]} Returns a [ [ Edm Properties ], boolean hasStream ]:
551
+ * array of Edm Properties
552
+ * hasStream : value of @Core.MediaType assignment
553
+ */
554
+ function createProperties(elementsCsn, edmParentCsn=elementsCsn)
555
+ {
556
+ const props = [];
557
+ let hasStream = false;
558
+ const streamProps = [];
559
+
560
+ elementsCsn.elements && Object.entries(elementsCsn.elements).forEach(([elementName, elementCsn]) =>
561
+ {
562
+ if(elementCsn._edmParentCsn == undefined)
563
+ setProp(elementCsn, '_edmParentCsn', edmParentCsn);
564
+
565
+ if(elementCsn.target) {
566
+ // Foreign keys are part of the generic elementCsn.elements property creation
567
+
568
+ // This is the V4 edmx:NavigationProperty
569
+ // gets rewritten for V2 in addAssociations()
570
+
571
+ // suppress navprop creation only if @odata.navigable:false is not annotated.
572
+ // (undefined !== false) still evaluates to true
573
+ if (!elementCsn._target.abstract && elementCsn['@odata.navigable'] !== false)
574
+ {
575
+ const navProp = new Edm.NavigationProperty(v, {
576
+ Name: elementName,
577
+ Type: elementCsn._target.name
578
+ }, elementCsn);
579
+ collectUsedType(elementCsn, elementCsn._target.name);
580
+ props.push(navProp);
581
+ // save the navProp in the global array for late constraint building
582
+ navigationProperties.push(navProp);
583
+ }
584
+ }
585
+ // render ordinary property if element is NOT ...
586
+ // 1) ... annotated @cds.api.ignore
587
+ // 2) ... annotated @odata.foreignKey4 and odataFormat: structured
588
+
589
+ else if(isEdmPropertyRendered(elementCsn, options))
590
+ {
591
+ // CDXCORE-CDXCORE-173
592
+ // V2: filter @Core.MediaType
593
+ if ( options.isV2() && elementCsn['@Core.MediaType']) {
594
+ hasStream = elementCsn['@Core.MediaType'];
595
+ delete elementCsn['@Core.MediaType'];
596
+ // CDXCORE-CDXCORE-177:
597
+ // V2: don't render element but add attribute 'm:HasStream="true' to EntityType
598
+ // V4: render property type 'Edm.Stream'
599
+ streamProps.push(elementName);
600
+
601
+ } else {
602
+ collectUsedType(elementCsn);
603
+ props.push(new Edm.Property(v, { Name: elementName }, elementCsn));
604
+ }
605
+ }
606
+
607
+ });
608
+ if(options.isV2()) {
609
+ if(streamProps.length > 1) { // TODO: why not mention 2.0 in text?
610
+ error(null, ['definitions', elementsCsn.name], { names: streamProps, version: '2.0', anno: '@Core.MediaType' },
611
+ 'Expected only one element to be annotated with $(ANNO) for OData $(VERSION) but found $(NAMES)');
612
+ }
613
+ else if(streamProps.length === 1) {
614
+ info(null, ['definitions', elementsCsn.name], { id: streamProps[0], version: '2.0', anno: '@Core.MediaType' },
615
+ 'Property $(ID) annotated with $(ANNO) is removed from EDM for OData $(VERSION)');
616
+ }
617
+ }
618
+ return [ props, hasStream ];
619
+ }
620
+
621
+ // V4 <TypeDefintion>
622
+ function createTypeDefinitionV4(typeCsn)
623
+ {
624
+ // derived types are already resolved to base types
625
+ const attributes = { Name: typeCsn.name.replace(schemaNamePrefix, '') };
626
+ if(!edmUtils.isODataSimpleIdentifier(attributes.Name))
627
+ message('odata-spec-violation-id', ['definitions', typeCsn.name], { id: attributes.Name });
628
+
629
+ const typeDef = new Edm.TypeDefinition(v, attributes, typeCsn );
630
+ edmTypeCompatibilityCheck(typeDef, [ 'definitions', typeCsn.name ]);
631
+ Schema.append(typeDef);
632
+ }
633
+
471
634
  // add bound/unbound actions/functions for V4
472
635
  function createActionV4(actionCsn, _name, entityCsn=undefined)
473
636
  {
@@ -528,7 +691,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
528
691
  const pLoc = [ ...loc, 'params', p._edmAttributes.Name ];
529
692
  if(!edmUtils.isODataSimpleIdentifier(parameterName))
530
693
  message('odata-spec-violation-id', pLoc, { id: parameterName });
531
-
694
+ collectUsedType(parameterCsn);
532
695
  edmTypeCompatibilityCheck(p, pLoc);
533
696
  actionNode.append(p);
534
697
  });
@@ -536,6 +699,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
536
699
  // return type if any
537
700
  if(actionCsn.returns) {
538
701
  actionNode._returnType = new Edm.ReturnType(v, actionCsn.returns);
702
+ collectUsedType(actionCsn.returns);
539
703
  edmTypeCompatibilityCheck(actionNode._returnType, [ ...loc, 'returns' ]);
540
704
  // if binding type matches return type add attribute EntitySetPath
541
705
  if(entityCsn != undefined && fullQualified(entityCsn.name) === actionNode._returnType._type) {
@@ -617,6 +781,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
617
781
  actionCsn.params && Object.entries(actionCsn.params).forEach(([parameterName, parameterCsn]) => {
618
782
  const pLoc = [...loc, 'params', parameterName];
619
783
  const param = new Edm.Parameter(v, { Name: parameterName }, parameterCsn, 'In' );
784
+ collectUsedType(parameterCsn);
620
785
  edmTypeCompatibilityCheck(param, pLoc);
621
786
  if(!edmUtils.isODataSimpleIdentifier(parameterName))
622
787
  message('odata-spec-violation-id', pLoc, { id: parameterName });
@@ -644,6 +809,7 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
644
809
  const returns = action.returns.items || action.returns;
645
810
  let type = returns.type;
646
811
  if (type) {
812
+ collectUsedType(action.returns);
647
813
  if (!isBuiltinType(type) && csn.definitions[type].kind !== 'entity' && csn.definitions[type].kind !== 'type') {
648
814
  message('odata-spec-violation-returns', returnsLoc, { kind: action.kind, version: '2.0' });
649
815
  }
@@ -671,147 +837,21 @@ function csn2edmAll(_csn, _options, serviceNames=undefined) {
671
837
  }
672
838
  }
673
839
 
674
- /**
675
- * @param {object} elementsCsn
676
- * @param {object} edmParentCsn
677
- * @returns {[object[], any]} Returns a [ [ Edm Properties ], boolean hasStream ]:
678
- * array of Edm Properties
679
- * hasStream : value of @Core.MediaType assignment
680
- */
681
- function createProperties(elementsCsn, edmParentCsn=elementsCsn)
682
- {
683
- const props = [];
684
- let hasStream = false;
685
- const streamProps = [];
686
-
687
- elementsCsn.elements && Object.entries(elementsCsn.elements).forEach(([elementName, elementCsn]) =>
688
- {
689
- if(elementCsn._edmParentCsn == undefined)
690
- setProp(elementCsn, '_edmParentCsn', edmParentCsn);
691
-
692
- if(elementCsn.target) {
693
- // Foreign keys are part of the generic elementCsn.elements property creation
694
-
695
- // This is the V4 edmx:NavigationProperty
696
- // gets rewritten for V2 in addAssociations()
697
-
698
- // suppress navprop creation only if @odata.navigable:false is not annotated.
699
- // (undefined !== false) still evaluates to true
700
- if (!elementCsn._target.abstract && elementCsn['@odata.navigable'] !== false)
701
- {
702
- const navProp = new Edm.NavigationProperty(v, {
703
- Name: elementName,
704
- Type: elementCsn._target.name
705
- }, elementCsn);
706
- props.push(navProp);
707
- // save the navProp in the global array for late constraint building
708
- navigationProperties.push(navProp);
709
- }
710
- }
711
- // render ordinary property if element is NOT ...
712
- // 1) ... annotated @cds.api.ignore
713
- // 2) ... annotated @odata.foreignKey4 and odataFormat: structured
714
-
715
- else if(isEdmPropertyRendered(elementCsn, options))
716
- {
717
- // CDXCORE-CDXCORE-173
718
- // V2: filter @Core.MediaType
719
- if ( options.isV2() && elementCsn['@Core.MediaType']) {
720
- hasStream = elementCsn['@Core.MediaType'];
721
- delete elementCsn['@Core.MediaType'];
722
- // CDXCORE-CDXCORE-177:
723
- // V2: don't render element but add attribute 'm:HasStream="true' to EntityType
724
- // V4: render property type 'Edm.Stream'
725
- streamProps.push(elementName);
726
-
727
- } else {
728
- props.push(new Edm.Property(v, { Name: elementName }, elementCsn));
729
- }
730
- }
731
-
732
- });
733
- if(options.isV2()) {
734
- if(streamProps.length > 1) { // TODO: why not mention 2.0 in text?
735
- error(null, ['definitions', elementsCsn.name], { names: streamProps, version: '2.0', anno: '@Core.MediaType' },
736
- `Expected only one element to be annotated with $(ANNO) for OData $(VERSION) but found $(NAMES)`);
737
- }
738
- else if(streamProps.length === 1) {
739
- info(null, ['definitions', elementsCsn.name], { id: streamProps[0], version: '2.0', anno: '@Core.MediaType' },
740
- 'Property $(ID) annotated with $(ANNO) is removed from EDM for OData $(VERSION)');
741
- }
742
- }
743
- return [ props, hasStream ];
744
- }
745
-
746
- function createComplexType(structuredTypeCsn)
747
- {
748
- // V4 attributes: Name, BaseType, Abstract, OpenType
749
- const attributes = { Name: structuredTypeCsn.name.replace(schemaNamePrefix, '') };
750
-
751
- const complexType = new Edm.ComplexType(v, attributes, structuredTypeCsn);
752
- const elementsCsn = structuredTypeCsn.items || structuredTypeCsn;
753
- const properties = createProperties(elementsCsn, structuredTypeCsn)[0];
754
- const loc = ['definitions', structuredTypeCsn.name];
755
-
756
- if(properties.length === 0) {
757
- warning(null, loc, { name: structuredTypeCsn.name },
758
- 'EDM ComplexType $(NAME) has no properties');
759
- }
760
- if(!edmUtils.isODataSimpleIdentifier(attributes.Name))
761
- message('odata-spec-violation-id', loc, { id: attributes.Name });
762
-
763
- properties.forEach(p => {
764
- const pLoc = [ ...loc, ...(structuredTypeCsn.items ? ['items', 'elements'] : [ 'elements' ]), p._edmAttributes.Name ];
765
- edmTypeCompatibilityCheck(p, pLoc);
766
- if(p._edmAttributes.Name === complexType._edmAttributes.Name)
767
- message('odata-spec-violation-property-name', pLoc, { kind: structuredTypeCsn.kind });
768
-
769
- if(!edmUtils.isODataSimpleIdentifier(p._edmAttributes.Name))
770
- message('odata-spec-violation-id', pLoc, { id: p._edmAttributes.Name });
771
-
772
- if(options.isV2()) {
773
- if(p._isCollection && !p._csn.target)
774
- message('odata-spec-violation-array', pLoc, { version: '2.0' });
775
-
776
- if(p._csn.target)
777
- message('odata-spec-violation-assoc', pLoc, { version: '2.0' });
778
- }
779
- });
780
-
781
-
782
- complexType.append(...(properties));
783
-
784
- Schema.append(complexType);
785
- }
786
-
787
- // V4 <TypeDefintion>
788
- function createTypeDefinition(typeCsn)
789
- {
790
- // derived types are already resolved to base types
791
- const attributes = { Name: typeCsn.name.replace(schemaNamePrefix, '') };
792
- if(!edmUtils.isODataSimpleIdentifier(attributes.Name))
793
- message('odata-spec-violation-id', ['definitions', typeCsn.name], { id: attributes.Name });
794
-
795
- const typeDef = new Edm.TypeDefinition(v, attributes, typeCsn );
796
- edmTypeCompatibilityCheck(typeDef, [ 'definitions', typeCsn.name ]);
797
- Schema.append(typeDef);
798
- }
799
-
800
840
  /*
801
- * addAssociation() constructs a V2 association.
802
- * In V4 all this has been simplified very much, the only thing actually left over is
803
- * <ReferentialConstriant> that is then a sub element to <NavigationProperty>.
804
- * However, referential constraints are substantially different to its V2 counterpart,
805
- * so it is better to reimplement proper V4 construction of<NavigationProperty> in a separate
806
- * function.
807
- *
808
- * This method does:
809
- * rewrite <NavigationProperty> attributes to be V2 compliant
810
- * add <Association> elements to the schema
811
- * add <End>, <ReferentialConstraint>, <Dependent> and <Principal> sub elements to <Association>
812
- * add <AssociationSet> to the EntityContainer for each <Association>
841
+ addAssociation() constructs a V2 association.
842
+ In V4 all this has been simplified very much, the only thing actually left over is
843
+ <ReferentialConstriant> that is then a sub element to <NavigationProperty>.
844
+ However, referential constraints are substantially different to its V2 counterpart,
845
+ so it is better to reimplement proper V4 construction of<NavigationProperty> in a separate
846
+ function.
847
+
848
+ This method does:
849
+ rewrite <NavigationProperty> attributes to be V2 compliant
850
+ add <Association> elements to the schema
851
+ add <End>, <ReferentialConstraint>, <Dependent> and <Principal> sub elements to <Association>
852
+ add <AssociationSet> to the EntityContainer for each <Association>
813
853
  */
814
- function addAssociation(navigationProperty)
854
+ function addAssociationV2(navigationProperty)
815
855
  {
816
856
  let constraints = navigationProperty._csn._constraints;
817
857
  let parentName = navigationProperty._csn._edmParentCsn.name.replace(schemaNamePrefix, '');
@@ -109,7 +109,7 @@ function applyAppSpecificLateCsnTransformationOnElement(options, element, struct
109
109
  if(!Array.isArray(CommonAttributes)) {
110
110
  error(null, ['definitions', struct.name, 'elements', element.name],
111
111
  { anno: '@Common.attribute', code: JSON.stringify(CommonAttributes) },
112
- `Expect array value for $(ANNOTATION): $(CODE)`);
112
+ 'Expect array value for $(ANNOTATION): $(CODE)');
113
113
  return;
114
114
  }
115
115
 
@@ -125,7 +125,7 @@ function applyAppSpecificLateCsnTransformationOnElement(options, element, struct
125
125
  if(!Array.isArray(ContextDefiningProperties)) {
126
126
  error(null, ['definitions', struct.name, 'elements', element.name],
127
127
  { anno: '@Aggregation.ContextDefiningProperties', code: JSON.stringify(ContextDefiningProperties) },
128
- `Expect array value for $(ANNOTATION): $(CODE)`);
128
+ 'Expect array value for $(ANNOTATION): $(CODE)');
129
129
  return;
130
130
  }
131
131
  if(ContextDefiningProperties.length > 0)
@@ -198,7 +198,7 @@ function applyAppSpecificLateCsnTransformationOnStructure(options, struct, error
198
198
  error(null, ['definitions', struct.name ],
199
199
  { anno: '@Capabilities.FilterRestrictions.FilterExpressionRestrictions',
200
200
  code: JSON.stringify(filterRestrictions) },
201
- `Expect array value for $(ANNOTATION): $(CODE)`);
201
+ 'Expect array value for $(ANNOTATION): $(CODE)');
202
202
  return;
203
203
  }
204
204
  filterRestrictions.forEach(v => {
@@ -215,7 +215,7 @@ function applyAppSpecificLateCsnTransformationOnStructure(options, struct, error
215
215
  error(null, ['definitions', struct.name],
216
216
  { anno: '@Capabilities.FilterRestrictions.RequiredProperties',
217
217
  code: JSON.stringify(requiredProperties) },
218
- `Expect array value for $(ANNOTATION): $(CODE)`);
218
+ 'Expect array value for $(ANNOTATION): $(CODE)');
219
219
  return;
220
220
  }
221
221
 
@@ -346,4 +346,4 @@ module.exports = {
346
346
  setSAPSpecificV2AnnotationsToEntityContainer,
347
347
  setSAPSpecificV2AnnotationsToEntitySet,
348
348
  setSAPSpecificV2AnnotationsToAssociation
349
- };
349
+ };
@@ -24,11 +24,11 @@ function resolveForeignKeyRefs(csn) {
24
24
  function inboundQualificationChecks(csn, options, messageFunctions,
25
25
  serviceRootNames, requestedServiceNames, isMyServiceRequested, whatsMyServiceRootName) {
26
26
  const csnUtils = getUtils(csn);
27
- const { message, throwWithAnyError } = messageFunctions;
27
+ const { message, throwWithError } = messageFunctions;
28
28
 
29
29
  forEachDefinition(csn, [ attach$path, checkChainedArray ]);
30
30
  checkNestedContextsAndServices();
31
- throwWithAnyError();
31
+ throwWithError();
32
32
 
33
33
  // attach $path to all
34
34
  function attach$path(def, defName) {
@@ -264,7 +264,7 @@ function initializeModel(csn, _options, messageFunctions, requestedServiceNames=
264
264
  const art = csn.definitions[newDefName];
265
265
  if(art !== undefined) {
266
266
  error(null, [ 'definitions', defName ], { name: newDefName },
267
- `Artifact name containing dots can't be mapped to an OData compliant name because it conflicts with existing definition $(NAME)`);
267
+ 'Artifact name containing dots can\'t be mapped to an OData compliant name because it conflicts with existing definition $(NAME)');
268
268
  }
269
269
  else {
270
270
  csn.definitions[newDefName] = def;
@@ -205,7 +205,7 @@ function resolveOnConditionAndPrepareConstraints(csn, assocCsn, messageFunctions
205
205
  function fillConstraints(arg, pos)
206
206
  {
207
207
  if(arg.xpr)
208
- arg.xpr.map(fillConstraints);
208
+ getExpressionArguments(arg.xpr);
209
209
  else if(pos > 0 && pos < expr.length)
210
210
  {
211
211
  let lhs = expr[pos-1];
@@ -485,7 +485,7 @@ function mapCdsToEdmType(csn, messageFunctions, isV2=false, isMediaType=false, l
485
485
  const { error } = messageFunctions || { error: ()=>true };
486
486
  let cdsType = csn.type;
487
487
  if(cdsType === undefined) {
488
- error(null, location, `no type found`);
488
+ error(null, location, 'no type found');
489
489
  return '<NOTYPE>';
490
490
  }
491
491
  if(!isBuiltinType(cdsType))
@@ -544,7 +544,7 @@ function mapCdsToEdmType(csn, messageFunctions, isV2=false, isMediaType=false, l
544
544
  */
545
545
  }[cdsType];
546
546
  if (edmType == undefined) {
547
- error(null, location, { type: cdsType }, `No EDM type available for $(TYPE)`);
547
+ error(null, location, { type: cdsType }, 'No EDM type available for $(TYPE)');
548
548
  }
549
549
  if(isV2)
550
550
  {