@sap/cds-dk 4.5.0 → 4.6.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 (42) hide show
  1. package/CHANGELOG.md +65 -9
  2. package/bin/bind.js +124 -8
  3. package/bin/cds-ts.js +1 -1
  4. package/bin/cds.js +1 -0
  5. package/bin/deploy/index.js +2 -1
  6. package/bin/env.js +50 -9
  7. package/bin/help.js +2 -1
  8. package/bin/import.js +126 -24
  9. package/bin/watch.js +45 -9
  10. package/lib/bind/bindingResolver.js +138 -0
  11. package/lib/bind/cfKeyProvider.js +353 -0
  12. package/lib/bind/userCdsrcJsonStorageProvider.js +144 -0
  13. package/lib/client/auth_manager.js +4 -4
  14. package/lib/client/settings_manager.js +1 -1
  15. package/lib/import/common.js +33 -1
  16. package/lib/import/importapi.js +4 -3
  17. package/lib/import/index.js +49 -23
  18. package/lib/import/message.js +11 -6
  19. package/lib/import/utils/MetadataConverter.js +25 -4
  20. package/lib/import/utils/MetadataConverterFactory.js +1 -2
  21. package/lib/import/utils/MultiMap.js +26 -0
  22. package/lib/import/v2parser.js +142 -24
  23. package/lib/import/v4parser.js +222 -149
  24. package/lib/init/constants.js +1 -1
  25. package/lib/init/index.js +2 -0
  26. package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +36 -52
  27. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +15 -0
  28. package/lib/init/template/lint/index.js +14 -6
  29. package/lib/init/template/mta/files/mta.yaml.hbs +0 -7
  30. package/lib/init/template/mtx/files/xs-security.json.hbs +3 -1
  31. package/lib/init/template/mtx/package/dependencies.package.json +1 -1
  32. package/lib/init/template/nodejs/files/.gitignore.hbs +3 -0
  33. package/lib/init/util/commandUtil.js +5 -0
  34. package/lib/lint/Linter.js +31 -20
  35. package/lib/lint/checks.js +5 -1
  36. package/lib/lint/generators.js +1 -1
  37. package/lib/lint/io.js +59 -35
  38. package/lib/util/term.js +2 -0
  39. package/lib/watch/node-watch.js +38 -19
  40. package/npm-shrinkwrap.json +1276 -1102
  41. package/package.json +4 -3
  42. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/test.js +0 -10
@@ -15,8 +15,12 @@ let allAssociations = {};
15
15
  let allAssociationSets = {};
16
16
  let allComplexTypes = {};
17
17
  let allComplexTypeDocs = {};
18
+ let allComplexTypeNamespaces = {};
18
19
  let allInheritedComplexTypes = {};
20
+ let allowedNamespaces = [];
21
+ let allowAllNamespaces = false;
19
22
  let messages = require("./message").getMessages();
23
+ let common = require("./common");
20
24
  let versionInfo = require('../../package.json').version;
21
25
 
22
26
  let edmxncdsdatatype = {
@@ -56,9 +60,49 @@ function _initialize() {
56
60
  allAssociationSets = {};
57
61
  allComplexTypes = {};
58
62
  allComplexTypeDocs = {};
63
+ allComplexTypeNamespaces = {};
59
64
  allInheritedComplexTypes = {};
65
+ allowedNamespaces = [];
66
+ allowAllNamespaces = false;
60
67
  }
61
68
 
69
+ // Function to extract allowed namespace attributes from given set of attributes
70
+ function namespaceAttributeFilter(attributes) {
71
+ let namespaceAttributes = allowAllNamespaces
72
+ ? Object.keys(attributes).filter((attr) => attr.includes(':'))
73
+ : Object.keys(attributes).filter(
74
+ (attr) =>
75
+ attr.includes(':') &&
76
+ allowedNamespaces.includes(attr.split(':')[0]));
77
+
78
+
79
+ namespaceAttributes = namespaceAttributes.map(attribute => {
80
+ const index = attribute.indexOf(':');
81
+ let namespace = attribute.slice(0, index);
82
+ let name = attribute.slice(index + 1);
83
+
84
+ name = name.replace(/-/g, '.');
85
+
86
+ let formattedAttribute = {};
87
+ formattedAttribute[`${namespace}.${name}`] = _replaceSpecialCharacters(attributes[attribute]);
88
+ return formattedAttribute;
89
+ });
90
+
91
+ return namespaceAttributes;
92
+ }
93
+
94
+ //Function to generate CSN for namespace attributes
95
+ function _generateNamespaceAttributes(attributes, isBefore) {
96
+ let csn = "";
97
+ attributes.forEach((attr) => {
98
+ let key = Object.keys(attr)[0];
99
+ if (isBefore) csn = csn + ',\n';
100
+ csn = csn + `"@${key}":"${attr[key]}"`;
101
+ if (!isBefore) csn = csn + ',\n';
102
+ });
103
+
104
+ return csn;
105
+ }
62
106
  function _isValidEDMX(jsonObj) {
63
107
  let isValid = false;
64
108
  let edmx;
@@ -299,18 +343,20 @@ function _extractAllFunctionImports(functionImports, serviceNamespaceParam)
299
343
  }
300
344
  }
301
345
 
346
+ function _replaceSpecialCharacters(text) {
347
+ return text.replace(/(?:\\[rn]|[\r\n]+)+/gm, "\\n").replace(/\s+/g, ' ').replace(/"/g, """).trim();
348
+ }
349
+
302
350
  // to parse the documentation tag
303
351
  function _parseDocumentationTag(documentedContent) {
304
- let documentation = "", text = "";
352
+ let documentation = "";
305
353
  if (documentedContent.Summary && documentedContent.Summary._text) {
306
- text = documentedContent.Summary._text.replace(/(?:\\[rn]|[\r\n]+)+/gm, "\\n");
307
- documentation = text;
354
+ documentation = _replaceSpecialCharacters(documentedContent.Summary._text);
308
355
  }
309
356
  if (documentedContent.LongDescription && documentedContent.LongDescription._text) {
310
357
  if (documentedContent.Summary)
311
358
  documentation += "\\n\\n";
312
- text = documentedContent.LongDescription._text.replace(/(?:\\[rn]|[\r\n]+)+/gm, "\\n");
313
- documentation += text;
359
+ documentation += _replaceSpecialCharacters(documentedContent.LongDescription._text);
314
360
  }
315
361
  return documentation;
316
362
  }
@@ -319,10 +365,12 @@ function _extractComplexType(complexType, serviceNamespaceParam) {
319
365
  let complexTypeKey = "";
320
366
  let baseType = "";
321
367
  let properties;
368
+ let namespaceAttributes = {};
322
369
  Object.keys(complexType).forEach((key) => {
323
370
  if (key === "_attributes") {
324
371
  complexTypeKey =
325
372
  serviceNamespaceParam + "." + complexType[key].Name;
373
+ namespaceAttributes = namespaceAttributeFilter(complexType[key]);
326
374
  baseType = complexType[key].BaseType;
327
375
  } else if (key === "Property") {
328
376
  properties = complexType.Property;
@@ -334,6 +382,9 @@ function _extractComplexType(complexType, serviceNamespaceParam) {
334
382
  if (complexTypeKey && baseType) {
335
383
  allInheritedComplexTypes[complexTypeKey] = baseType;
336
384
  }
385
+ if (namespaceAttributes.length) {
386
+ allComplexTypeNamespaces[complexTypeKey] = namespaceAttributes;
387
+ }
337
388
  }
338
389
 
339
390
  function _extractAllComplexTypes(complexTypes, serviceNamespaceParam) {
@@ -358,7 +409,8 @@ function _getServiceEntityProperty(
358
409
  displayFormat,
359
410
  isKey,
360
411
  documentation,
361
- isCollection
412
+ isCollection,
413
+ allowedNamespaceAttributes = -1
362
414
  ) {
363
415
  let cdsDataType = null;
364
416
  let hasInvalidPrecision = false;
@@ -424,6 +476,10 @@ function _getServiceEntityProperty(
424
476
  propertyJson = propertyJson + ',\n"doc":"' + documentation + '"';
425
477
  }
426
478
 
479
+ if (allowedNamespaceAttributes !== -1) {
480
+ propertyJson += _generateNamespaceAttributes(allowedNamespaceAttributes, true);
481
+ }
482
+
427
483
  if(propertyName)
428
484
  propertyJson = propertyJson + "\n}";
429
485
  return propertyJson;
@@ -434,6 +490,9 @@ function _getServiceComplexType(complexTypeKey, complexType) {
434
490
  let complexTypeProperty;
435
491
  let i;
436
492
  complexTypeCSN = complexTypeCSN + '"kind": "type",\n';
493
+ if(allComplexTypeNamespaces[complexTypeKey]) {
494
+ complexTypeCSN += _generateNamespaceAttributes(allComplexTypeNamespaces[complexTypeKey], false);
495
+ }
437
496
  if (allComplexTypeDocs[complexTypeKey])
438
497
  complexTypeCSN = complexTypeCSN + '"doc":' + `"${allComplexTypeDocs[complexTypeKey]}",` + "\n";
439
498
  complexTypeCSN = complexTypeCSN + '"elements": {\n';
@@ -444,6 +503,10 @@ function _getServiceComplexType(complexTypeKey, complexType) {
444
503
  complexTypeProperty = complexType[i]._attributes;
445
504
  if(complexType[i].Documentation)
446
505
  complexTypeProperty.doc = _parseDocumentationTag(complexType[i].Documentation);
506
+
507
+ let namespaceAttributes = namespaceAttributeFilter(complexTypeProperty)
508
+ const complexTypePropertyNamespace = namespaceAttributes.length ? namespaceAttributes : -1
509
+
447
510
  complexTypeCSN =
448
511
  complexTypeCSN +
449
512
  _getServiceEntityProperty(
@@ -455,7 +518,8 @@ function _getServiceComplexType(complexTypeKey, complexType) {
455
518
  complexTypeProperty["sap:display-format"],
456
519
  false,
457
520
  complexTypeProperty.doc,
458
- -1
521
+ -1,
522
+ complexTypePropertyNamespace
459
523
  );
460
524
  if (i !== complexType.length - 1) {
461
525
  complexTypeCSN = complexTypeCSN + ",\n";
@@ -468,6 +532,10 @@ function _getServiceComplexType(complexTypeKey, complexType) {
468
532
  complexTypeProperty = complexType._attributes;
469
533
  if(complexType.Documentation)
470
534
  complexTypeProperty.doc = _parseDocumentationTag(complexType.Documentation);
535
+
536
+ let namespaceAttributes = namespaceAttributeFilter(complexTypeProperty);
537
+ const complexTypePropertyNamespace = namespaceAttributes.length ? namespaceAttributes : -1;
538
+
471
539
  complexTypeCSN =
472
540
  complexTypeCSN +
473
541
  _getServiceEntityProperty(
@@ -479,7 +547,8 @@ function _getServiceComplexType(complexTypeKey, complexType) {
479
547
  complexTypeProperty["sap:display-format"],
480
548
  false,
481
549
  complexTypeProperty.doc,
482
- -1
550
+ -1,
551
+ complexTypePropertyNamespace
483
552
  );
484
553
  }
485
554
  }
@@ -524,6 +593,10 @@ function _parseParameter(parameter)
524
593
  let isCollection = -1;
525
594
  if(parameter.Documentation)
526
595
  doc = _parseDocumentationTag(parameter.Documentation);
596
+
597
+ let namespaceAttributes = namespaceAttributeFilter(parameter._attributes);
598
+ const parameterNamespaceAttributes = namespaceAttributes.length ? namespaceAttributes : -1;
599
+
527
600
  let type = parameter["_attributes"].Type;
528
601
  if(type.substring(0,10) === 'Collection')
529
602
  {
@@ -538,7 +611,8 @@ function _parseParameter(parameter)
538
611
  parameter["_attributes"]["sap:display-format"],
539
612
  false,
540
613
  doc,
541
- isCollection);
614
+ isCollection,
615
+ parameterNamespaceAttributes);
542
616
  return csn;
543
617
  }
544
618
 
@@ -602,7 +676,7 @@ function _getFunctionImport(functionImport,isBounded) {
602
676
  }
603
677
  if(functionImport[4] !== -1)
604
678
  {
605
- csn = csn + ',\n "doc": "' + functionImport[4] + '"';
679
+ csn = csn + ',\n "doc": "' + _replaceSpecialCharacters(functionImport[4]) + '"';
606
680
  }
607
681
 
608
682
  csn = csn + "\n }";
@@ -637,6 +711,8 @@ function _parseEntityAttributes(attributes) {
637
711
  entityAttributes.Name = attributes.Name;
638
712
  entityAttributes.BaseType = attributes.BaseType;
639
713
  entityAttributes.Abstract = attributes.Abstract;
714
+ entityAttributes.allowedNamespaceAttributes = namespaceAttributeFilter(attributes);
715
+
640
716
  return entityAttributes;
641
717
  }
642
718
 
@@ -658,6 +734,9 @@ function _parseEntityKeys(keys) {
658
734
 
659
735
  function _getPropertyAttributes(propAttributes) {
660
736
  let propOthers = [];
737
+
738
+ let namespaceAttributes = namespaceAttributeFilter(propAttributes)
739
+
661
740
  propOthers.push(propAttributes.Type);
662
741
  if (propAttributes.MaxLength) {
663
742
  propOthers.push(propAttributes.MaxLength);
@@ -687,6 +766,13 @@ function _getPropertyAttributes(propAttributes) {
687
766
  }else{
688
767
  propOthers.push(-1);
689
768
  }
769
+
770
+ if (namespaceAttributes.length) {
771
+ propOthers.push(namespaceAttributes);
772
+ } else {
773
+ propOthers.push(-1);
774
+ }
775
+
690
776
  return propOthers;
691
777
  }
692
778
 
@@ -755,7 +841,8 @@ function _generateCSNEntityKeys(entityKeysList, entityPropertiesMap) {
755
841
  propAttributes[4],
756
842
  true,
757
843
  propAttributes[5],
758
- -1
844
+ -1,
845
+ propAttributes[6]
759
846
  );
760
847
  if (i !== entityKeysList.length - 1) {
761
848
  csnEntity = csnEntity + ",\n";
@@ -793,7 +880,8 @@ function _generateCSNEntityProperties(entityKeysList, entityPropertiesMap) {
793
880
  propAttributes[4],
794
881
  false,
795
882
  propAttributes[5],
796
- -1
883
+ -1,
884
+ propAttributes[6]
797
885
  );
798
886
  if (i !== entityProperties.length - 1) {
799
887
  csnEntity = csnEntity + ",\n";
@@ -1075,6 +1163,7 @@ function _getServiceEntityNavigationProperty(navPropAttributes, mockServerUc) {
1075
1163
  let navPropName;
1076
1164
  let relationshipName;
1077
1165
  let navPropDoc;
1166
+ let allowedNamespaceAttributes = namespaceAttributeFilter(navPropAttributes);
1078
1167
  // var fromRole;
1079
1168
  let toRole;
1080
1169
  if (!navPropAttributes) {
@@ -1087,18 +1176,28 @@ function _getServiceEntityNavigationProperty(navPropAttributes, mockServerUc) {
1087
1176
  navPropDoc = navPropAttributes.doc;
1088
1177
 
1089
1178
  csn = csn + '"' + navPropName + '": {\n';
1179
+ if(allowedNamespaceAttributes.length) {
1180
+ csn += _generateNamespaceAttributes(allowedNamespaceAttributes, false);
1181
+ }
1090
1182
  // if documentatin exists for navigation property
1091
- if(navPropDoc)
1092
- csn = csn + `"doc": "${navPropDoc}",` + "\n";
1183
+ if (navPropDoc) {
1184
+ csn = csn + '"doc":' + `"Please add an ON condition\\n${navPropDoc}",\n`;
1185
+ } else {
1186
+ csn = csn + '"doc": "Please add an ON condition", \n';
1187
+ }
1093
1188
  csn = csn + '"type": "cds.Association",\n';
1094
- csn =
1095
- csn +
1189
+ csn = csn +
1096
1190
  _getCSNAssociatedEntitySet(
1097
1191
  relationshipName,
1098
1192
  toRole,
1099
1193
  navPropName,
1100
1194
  mockServerUc
1101
1195
  );
1196
+ // Convert managed associations and compositions in unmanaged with empty key to avoid
1197
+ // "generation" of keys, that do not exist in the external service.
1198
+ if (common.checkForEmptyKeys(csn, "V2")) {
1199
+ csn = csn + ',\n"keys": []\n';
1200
+ }
1102
1201
  csn = csn + "}";
1103
1202
 
1104
1203
  return csn;
@@ -1156,8 +1255,8 @@ function _constructServiceEntity(
1156
1255
  let csnProperties;
1157
1256
  let hasProperties;
1158
1257
  csnEntity = csnEntity + '"kind": "entity",\n';
1159
- if (ignorePersistenceSkip === false) {
1160
- csnEntity = csnEntity + '"@cds.persistence.skip": true,\n';
1258
+ if (ignorePersistenceSkip === false) {
1259
+ csnEntity = csnEntity + '"@cds.persistence.skip": true,\n';
1161
1260
  }
1162
1261
  if (
1163
1262
  entityAttributes.Abstract &&
@@ -1165,6 +1264,11 @@ function _constructServiceEntity(
1165
1264
  ) {
1166
1265
  csnEntity = csnEntity + '"abstract": true,\n';
1167
1266
  }
1267
+
1268
+ if(entityAttributes.allowedNamespaceAttributes.length)
1269
+ {
1270
+ csnEntity += _generateNamespaceAttributes(entityAttributes.allowedNamespaceAttributes, false);
1271
+ }
1168
1272
  // if documentation exists for the entity
1169
1273
  if (documentation) {
1170
1274
  csnEntity = csnEntity + `"doc": "${documentation}",` + '\n';
@@ -1395,11 +1499,12 @@ function _generateEDMXJSON2CSN(
1395
1499
  const definitions = [];
1396
1500
 
1397
1501
  if (mockServerUc) {
1398
- let def = '"' + serviceNamespaceParam + '": {"kind": "service"';
1399
- let schemaDoc = jsonObj["edmx:Edmx"]["edmx:DataServices"].Schema.Documentation;
1400
- // if documentation exists for schema
1401
- if(schemaDoc)
1402
- def += ',\n' + `"doc": "${_parseDocumentationTag(schemaDoc)}"`;
1502
+ let def = '"' + serviceNamespaceParam + '": {"kind": "service"' + ',\n' + '"@cds.external": true';
1503
+
1504
+ let serviceDoc = jsonObj["edmx:Edmx"]["edmx:DataServices"]["Schema"].EntityContainer.Documentation;
1505
+ // if documentation exists for service
1506
+ if(serviceDoc)
1507
+ def += ',\n' + `"doc": "${_parseDocumentationTag(serviceDoc)}"`;
1403
1508
  def += "}";
1404
1509
  definitions.push(def);
1405
1510
  }
@@ -1437,14 +1542,27 @@ function _generateEDMXJSON2CSN(
1437
1542
  function getEdmxv2CSN(
1438
1543
  edmx2jsonModel,
1439
1544
  ignorePersistenceSkip,
1440
- mockServerUc
1545
+ mockServerUc,
1546
+ context
1441
1547
  ) {
1442
1548
  let csnDataModel;
1443
1549
  let isValid;
1444
1550
  _initialize();
1551
+ if (!context.include_all_namespaces && context.namespaces.length) {
1552
+ allowedNamespaces = allowedNamespaces.concat(context.namespaces)
1553
+ }
1554
+ else if(context.include_all_namespaces) {
1555
+ allowAllNamespaces = true;
1556
+ }
1557
+
1445
1558
  isValid = _validateEDMX(edmx2jsonModel);
1446
1559
  if (isValid) {
1447
1560
  serviceNamespace = _getServiceNameSpace(edmx2jsonModel);
1561
+ let namespaceAlias = edmx2jsonModel["edmx:Edmx"]["edmx:DataServices"].Schema._attributes.Alias;
1562
+ // replace the namespace alias value with original namespace value
1563
+ if (namespaceAlias) {
1564
+ edmx2jsonModel = common.replaceAliasValue(JSON.stringify(edmx2jsonModel), serviceNamespace, namespaceAlias);
1565
+ }
1448
1566
  csnDataModel = _generateEDMXJSON2CSN(
1449
1567
  edmx2jsonModel,
1450
1568
  serviceNamespace,